From ee3d0bae2109e374199b59f647129b86b0f0d109 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Apr 2024 09:53:06 +0200 Subject: [PATCH 001/173] Bump org.dhatim:fastexcel from 0.17.0 to 0.18.0 in /cnf (#2620) * Bump org.dhatim:fastexcel from 0.17.0 to 0.18.0 in /cnf Bumps [org.dhatim:fastexcel](https://github.com/dhatim/fastexcel) from 0.17.0 to 0.18.0. - [Release notes](https://github.com/dhatim/fastexcel/releases) - [Commits](https://github.com/dhatim/fastexcel/compare/0.17.0...0.18.0) --- updated-dependencies: - dependency-name: org.dhatim:fastexcel dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Update bnd --------- 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/bnd.bnd | 2 +- io.openems.wrapper/fastexcel.bnd | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cnf/pom.xml b/cnf/pom.xml index 7610fda907c..0b18242fc7d 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -260,7 +260,7 @@ org.dhatim fastexcel - 0.17.0 + 0.18.0 diff --git a/io.openems.wrapper/bnd.bnd b/io.openems.wrapper/bnd.bnd index a346e5ae840..a4088ac1113 100644 --- a/io.openems.wrapper/bnd.bnd +++ b/io.openems.wrapper/bnd.bnd @@ -24,6 +24,6 @@ Bundle-Description: This wraps external java libraries that do not have OSGi hea com.google.gson;version='2.10.1',\ de.bytefish:pgbulkinsert;version='8.1.3',\ fr.turri:aXMLRPC;version='1.13.0',\ - org.dhatim:fastexcel;version='0.17.0',\ + org.dhatim:fastexcel;version='0.18.0',\ org.eclipse.paho.mqttv5.client;version='1.2.5',\ org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm;version='1.7.3',\ diff --git a/io.openems.wrapper/fastexcel.bnd b/io.openems.wrapper/fastexcel.bnd index efe0ad1737b..ab7f758a06e 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.17.0 +Bundle-Version: 0.18.0 -Include-Resource: @fastexcel-0.17.0.jar +Include-Resource: @fastexcel-0.18.0.jar -dsannotations: * From 6adb74f2512ed99d50db1ed95ee79e67b4fc671f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Apr 2024 10:08:15 +0200 Subject: [PATCH 002/173] Bump org.apache.felix:org.apache.felix.webconsole from 5.0.0 to 5.0.2 in /cnf (#2619) * Bump org.apache.felix:org.apache.felix.webconsole in /cnf Bumps org.apache.felix:org.apache.felix.webconsole from 5.0.0 to 5.0.2. --- updated-dependencies: - dependency-name: org.apache.felix:org.apache.felix.webconsole 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 0b18242fc7d..85ce8d8a776 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -237,7 +237,7 @@ org.apache.felix org.apache.felix.webconsole - 5.0.0 + 5.0.2 diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index bc68a467e50..93014f953ba 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -109,7 +109,7 @@ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ org.apache.felix.scr;version='[2.2.10,2.2.11)',\ - org.apache.felix.webconsole;version='[5.0.0,5.0.1)',\ + org.apache.felix.webconsole;version='[5.0.2,5.0.3)',\ org.apache.felix.webconsole.plugins.ds;version='[2.3.0,2.3.1)',\ org.jetbrains.kotlin.osgi-bundle;version='[1.9.23,1.9.24)',\ org.jsr-305;version='[3.0.2,3.0.3)',\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index 09c9967dc78..f77b23df3a8 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -394,7 +394,7 @@ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ org.apache.felix.scr;version='[2.2.10,2.2.11)',\ - org.apache.felix.webconsole;version='[5.0.0,5.0.1)',\ + org.apache.felix.webconsole;version='[5.0.2,5.0.3)',\ org.apache.felix.webconsole.plugins.ds;version='[2.3.0,2.3.1)',\ org.eclipse.jetty.client;version='[9.4.28,9.4.29)',\ org.eclipse.jetty.http;version='[9.4.28,9.4.29)',\ From c78334d8810d2a291511a9fa3e1c6072c03da84a Mon Sep 17 00:00:00 2001 From: Hannes Date: Tue, 16 Apr 2024 22:07:09 +0200 Subject: [PATCH 003/173] Apply Eclipse Format & Organize Imports; fix resource leak (#2617) * Update OdooHandler.java: Just a Minor Update Fix * Apply Eclipse Format + Organize Imports on everything --------- Co-authored-by: Stefan Feilmeier --- .../alerting/handler/OfflineEdgeHandler.java | 6 +-- .../openems/backend/b2brest/RestHandler.java | 18 ++++---- .../openems/backend/common/metadata/User.java | 3 +- .../edgewebsocket/SystemLogHandler.java | 1 + .../backend/metadata/dummy/MetadataDummy.java | 4 +- .../backend/metadata/file/MetadataFile.java | 2 +- .../metadata/odoo/odoo/OdooHandler.java | 1 - .../io/openems/common/types/EdgeConfig.java | 2 +- .../websocket/AbstractWebsocketClient.java | 2 +- .../websocket/AbstractWebsocketServer.java | 2 +- .../bridge/modbus/BridgeModbusSerialImpl.java | 16 ++++--- .../edge/bridge/modbus/ConfigSerial.java | 6 +-- .../edge/bridge/modbus/MyConfigSerial.java | 8 ++-- .../edge/controller/api/rest/RestHandler.java | 18 ++++---- .../ess/timeofusetariff/optimizer/Utils.java | 2 +- .../timeofusetariff/optimizer/UtilsTest.java | 2 +- .../ControllerIoHeatingElementImpl.java | 3 +- .../io/openems/edge/app/evcs/DezonyEvcs.java | 3 +- .../openems/edge/app/evcs/IesKeywattEvcs.java | 3 +- .../io/openems/edge/app/evcs/KebaEvcs.java | 3 +- .../edge/app/evcs/WebastoNextEvcs.java | 3 +- .../edge/app/evcs/WebastoUniteEvcs.java | 3 +- .../appmanager/formly/JsonFormlyUtil.java | 4 +- .../core/appmanager/validator/Checkables.java | 2 +- .../integratedsystem/TestFeneconHome30.java | 6 ++- .../api/manager/PredictorManager.java | 5 ++- .../influxdb/TimedataInfluxDbImpl.java | 45 ++++++++++--------- .../awattar/TimeOfUseTariffAwattarImpl.java | 2 +- 28 files changed, 95 insertions(+), 80 deletions(-) diff --git a/io.openems.backend.alerting/src/io/openems/backend/alerting/handler/OfflineEdgeHandler.java b/io.openems.backend.alerting/src/io/openems/backend/alerting/handler/OfflineEdgeHandler.java index 7662a1badcb..dc5f5cf117d 100644 --- a/io.openems.backend.alerting/src/io/openems/backend/alerting/handler/OfflineEdgeHandler.java +++ b/io.openems.backend.alerting/src/io/openems/backend/alerting/handler/OfflineEdgeHandler.java @@ -30,7 +30,7 @@ public class OfflineEdgeHandler implements Handler { public static final int MAX_SIMULTANEOUS_MSGS = 500; public static final int MAX_SIMULTANEOUS_EDGES = 1000; public static final int EDGE_REBOOT_MINUTES = 5; - + private final Logger log = LoggerFactory.getLogger(OfflineEdgeHandler.class); private final int initialDelay; // in Minutes @@ -42,7 +42,7 @@ public class OfflineEdgeHandler implements Handler { private TimedTask initMetadata; private TimedExecutor timeService; - + public OfflineEdgeHandler(MessageSchedulerService mss, TimedExecutor timeService, Mailer mailer, Metadata metadata, int initialDelay) { this.mailer = mailer; @@ -256,7 +256,7 @@ public Consumer getEventHandler(String eventTopic) { yield this::handleOnSetOnline; case Metadata.Events.AFTER_IS_INITIALIZED: - yield this::handleMetadataAfterInitialize; + yield this::handleMetadataAfterInitialize; default: yield null; diff --git a/io.openems.backend.b2brest/src/io/openems/backend/b2brest/RestHandler.java b/io.openems.backend.b2brest/src/io/openems/backend/b2brest/RestHandler.java index 3fd2e3d5b1e..337da975af9 100644 --- a/io.openems.backend.b2brest/src/io/openems/backend/b2brest/RestHandler.java +++ b/io.openems.backend.b2brest/src/io/openems/backend/b2brest/RestHandler.java @@ -1,8 +1,9 @@ package io.openems.backend.b2brest; -import java.io.BufferedReader; +import static io.openems.common.utils.JsonUtils.parseToJsonObject; +import static java.util.stream.Collectors.joining; + import java.io.IOException; -import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.util.Arrays; import java.util.Base64; @@ -11,7 +12,6 @@ import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; -import java.util.stream.Collectors; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; @@ -19,7 +19,6 @@ import org.slf4j.LoggerFactory; import com.google.gson.JsonObject; -import com.google.gson.JsonParser; import io.openems.backend.common.metadata.User; import io.openems.common.exceptions.OpenemsError; @@ -145,11 +144,12 @@ private void sendErrorResponse(Request baseRequest, HttpServletResponse response */ private static JsonObject parseJson(Request baseRequest) throws OpenemsException { try { - return JsonParser.parseString(// - new BufferedReader(new InputStreamReader(baseRequest.getInputStream())) // - .lines() // - .collect(Collectors.joining("\n"))) // - .getAsJsonObject(); + try (var br = baseRequest.getReader()) { + return parseToJsonObject(br // + .lines() // + .collect(joining("\n"))); + } + } catch (Exception e) { throw new OpenemsException("Unable to parse: " + e.getMessage()); } diff --git a/io.openems.backend.common/src/io/openems/backend/common/metadata/User.java b/io.openems.backend.common/src/io/openems/backend/common/metadata/User.java index 93acdcdd235..2769e26f35a 100644 --- a/io.openems.backend.common/src/io/openems/backend/common/metadata/User.java +++ b/io.openems.backend.common/src/io/openems/backend/common/metadata/User.java @@ -3,10 +3,11 @@ import java.util.ArrayList; import java.util.List; import java.util.Map.Entry; -import com.google.gson.JsonObject; import java.util.NavigableMap; import java.util.TreeMap; +import com.google.gson.JsonObject; + import io.openems.common.channel.Level; import io.openems.common.exceptions.OpenemsError; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; diff --git a/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/SystemLogHandler.java b/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/SystemLogHandler.java index 33ad4d777ba..41bd8ce5961 100644 --- a/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/SystemLogHandler.java +++ b/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/SystemLogHandler.java @@ -10,6 +10,7 @@ import org.slf4j.LoggerFactory; import com.google.gson.JsonObject; + import io.openems.backend.common.metadata.User; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.jsonrpc.base.GenericJsonrpcResponseSuccess; diff --git a/io.openems.backend.metadata.dummy/src/io/openems/backend/metadata/dummy/MetadataDummy.java b/io.openems.backend.metadata.dummy/src/io/openems/backend/metadata/dummy/MetadataDummy.java index 2a3d132729a..899de4292de 100644 --- a/io.openems.backend.metadata.dummy/src/io/openems/backend/metadata/dummy/MetadataDummy.java +++ b/io.openems.backend.metadata.dummy/src/io/openems/backend/metadata/dummy/MetadataDummy.java @@ -276,7 +276,7 @@ public EdgeHandler edge() { public Optional getSerialNumberForEdge(Edge edge) { throw new UnsupportedOperationException("DummyMetadata.getSerialNumberForEdge() is not implemented"); } - + @Override public UserAlertingSettings getUserAlertingSettings(String edgeId, String userId) throws OpenemsException { throw new UnsupportedOperationException("DummyMetadata.getUserAlertingSettings() is not implemented"); @@ -369,7 +369,7 @@ public EdgeMetadata getEdgeMetadataForUser(User user, String edgeId) throws Open public Optional getSumState(String edgeId) { throw new UnsupportedOperationException("DummyMetadata.getSumState() is not implemented"); } - + @Override public void logGenericSystemLog(GenericSystemLog systemLog) { this.logInfo(this.log, diff --git a/io.openems.backend.metadata.file/src/io/openems/backend/metadata/file/MetadataFile.java b/io.openems.backend.metadata.file/src/io/openems/backend/metadata/file/MetadataFile.java index 6ec8f8bc2e4..e1fda5d7540 100644 --- a/io.openems.backend.metadata.file/src/io/openems/backend/metadata/file/MetadataFile.java +++ b/io.openems.backend.metadata.file/src/io/openems/backend/metadata/file/MetadataFile.java @@ -310,7 +310,7 @@ public Optional getSerialNumberForEdge(Edge edge) { public UserAlertingSettings getUserAlertingSettings(String edgeId, String userId) throws OpenemsException { throw new UnsupportedOperationException("FileMetadata.getUserAlertingSettings() is not implemented"); } - + @Override public List getUserAlertingSettings(String edgeId) { throw new UnsupportedOperationException("FileMetadata.getUserAlertingSettings() is not implemented"); diff --git a/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/odoo/OdooHandler.java b/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/odoo/OdooHandler.java index 625a990b6e7..faf69a04d76 100644 --- a/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/odoo/OdooHandler.java +++ b/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/odoo/OdooHandler.java @@ -57,7 +57,6 @@ import io.openems.common.jsonrpc.request.GetEdgesRequest.PaginationOptions; import io.openems.common.session.Language; import io.openems.common.session.Role; -import io.openems.common.utils.JsonUtils; import io.openems.common.utils.ObjectUtils; import io.openems.common.utils.PasswordUtils; diff --git a/io.openems.common/src/io/openems/common/types/EdgeConfig.java b/io.openems.common/src/io/openems/common/types/EdgeConfig.java index 1871fb826d7..232f2de63f0 100644 --- a/io.openems.common/src/io/openems/common/types/EdgeConfig.java +++ b/io.openems.common/src/io/openems/common/types/EdgeConfig.java @@ -1254,7 +1254,7 @@ public static EdgeConfig fromJson(JsonObject json) { private volatile JsonObject _json = null; /** - * Build from {@link ActualEdgeConfig} using a {@link Builder}. + * Build from {@link ActualEdgeConfig}. * * @param actual the {@link ActualEdgeConfig} */ diff --git a/io.openems.common/src/io/openems/common/websocket/AbstractWebsocketClient.java b/io.openems.common/src/io/openems/common/websocket/AbstractWebsocketClient.java index d5479756c79..79c805a69c3 100644 --- a/io.openems.common/src/io/openems/common/websocket/AbstractWebsocketClient.java +++ b/io.openems.common/src/io/openems/common/websocket/AbstractWebsocketClient.java @@ -9,8 +9,8 @@ import org.java_websocket.client.WebSocketClient; import org.java_websocket.drafts.Draft; import org.java_websocket.drafts.Draft_6455; -import org.java_websocket.extensions.permessage_deflate.PerMessageDeflateExtension; import org.java_websocket.exceptions.WebsocketNotConnectedException; +import org.java_websocket.extensions.permessage_deflate.PerMessageDeflateExtension; import org.java_websocket.framing.CloseFrame; import org.java_websocket.handshake.ServerHandshake; import org.slf4j.Logger; diff --git a/io.openems.common/src/io/openems/common/websocket/AbstractWebsocketServer.java b/io.openems.common/src/io/openems/common/websocket/AbstractWebsocketServer.java index acc9017532e..72880facf42 100644 --- a/io.openems.common/src/io/openems/common/websocket/AbstractWebsocketServer.java +++ b/io.openems.common/src/io/openems/common/websocket/AbstractWebsocketServer.java @@ -16,8 +16,8 @@ import org.java_websocket.WebSocket; import org.java_websocket.drafts.Draft; import org.java_websocket.drafts.Draft_6455; -import org.java_websocket.extensions.permessage_deflate.PerMessageDeflateExtension; import org.java_websocket.exceptions.WebsocketNotConnectedException; +import org.java_websocket.extensions.permessage_deflate.PerMessageDeflateExtension; import org.java_websocket.handshake.ClientHandshake; import org.java_websocket.server.WebSocketServer; import org.slf4j.Logger; diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/BridgeModbusSerialImpl.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/BridgeModbusSerialImpl.java index 4488593accc..d36835f41f8 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/BridgeModbusSerialImpl.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/BridgeModbusSerialImpl.java @@ -60,14 +60,20 @@ public class BridgeModbusSerialImpl extends AbstractModbusBridge /** The configured parity. */ private Parity parity; - + /** Enable internal bus termination. */ private boolean enableTermination; - - /** The configured delay between activating the transmitter and actually sending data in microseconds. */ + + /** + * The configured delay between activating the transmitter and actually sending + * data in microseconds. + */ private int delayBeforeTx; - - /** The configured delay between the end of transmitting data and deactivating transmitter in microseconds. */ + + /** + * The configured delay between the end of transmitting data and deactivating + * transmitter in microseconds. + */ private int delayAfterTx; public BridgeModbusSerialImpl() { diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/ConfigSerial.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/ConfigSerial.java index 5032b4f574c..0ae88b2bbdd 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/ConfigSerial.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/ConfigSerial.java @@ -35,13 +35,13 @@ @AttributeDefinition(name = "Parity", description = "The parity - 'none', 'even', 'odd', 'mark' or 'space'") Parity parity() default Parity.NONE; - + @AttributeDefinition(name = "Enable termination", description = "Sets whether the interface shall enable internal bus termination") boolean enableTermination() default true; - + @AttributeDefinition(name = "Delay before TX [μs]", description = "Sets the delay between activating the transmitter and actually sending data. There are devices in the field requiring such a delay for start bit detection.", min = "0") int delayBeforeTx() default 1000; - + @AttributeDefinition(name = "Delay after TX [μs]", description = "Sets the delay between the end of transmitting data and deactivating the transmitter.", min = "0") int delayAfterTx() default 0; diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/MyConfigSerial.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/MyConfigSerial.java index 5df6db2a1d2..fbb13ca6a46 100644 --- a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/MyConfigSerial.java +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/MyConfigSerial.java @@ -53,17 +53,17 @@ public Builder setParity(Parity parity) { this.parity = parity; return this; } - + public Builder setEnableTermination(boolean enableTermination) { this.enableTermination = enableTermination; return this; } - + public Builder setDelayBeforeTx(int delay) { this.delayBeforeTx = delay; return this; } - + public Builder setDelayAfterTx(int delay) { this.delayAfterTx = delay; return this; @@ -124,7 +124,7 @@ public Stopbit stopbits() { public Parity parity() { return this.builder.parity; } - + @Override public boolean enableTermination() { return this.builder.enableTermination; diff --git a/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/RestHandler.java b/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/RestHandler.java index b5650ea5fde..ea542953acb 100644 --- a/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/RestHandler.java +++ b/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/RestHandler.java @@ -1,8 +1,9 @@ package io.openems.edge.controller.api.rest; -import java.io.BufferedReader; +import static io.openems.common.utils.JsonUtils.parseToJsonObject; +import static java.util.stream.Collectors.joining; + import java.io.IOException; -import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.util.Arrays; import java.util.Base64; @@ -14,7 +15,6 @@ import java.util.concurrent.ExecutionException; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; -import java.util.stream.Collectors; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; @@ -24,7 +24,6 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import com.google.gson.JsonParser; import io.openems.common.channel.AccessMode; import io.openems.common.exceptions.OpenemsError; @@ -364,11 +363,12 @@ private boolean handlePost(User user, ChannelAddress channelAddress, Request bas */ private static JsonObject parseJson(Request baseRequest) throws OpenemsException { try { - return JsonParser.parseString(// - new BufferedReader(new InputStreamReader(baseRequest.getInputStream())) // - .lines() // - .collect(Collectors.joining("\n"))) // - .getAsJsonObject(); + try (var br = baseRequest.getReader()) { + return parseToJsonObject(br // + .lines() // + .collect(joining("\n"))); + } + } catch (Exception e) { throw new OpenemsException("Unable to parse: " + e.getMessage()); } diff --git a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/optimizer/Utils.java b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/optimizer/Utils.java index c3c07d1023a..3706433a290 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/optimizer/Utils.java +++ b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/optimizer/Utils.java @@ -399,7 +399,7 @@ public static GetScheduleResponse handleGetScheduleRequest(Optimizer optimizer, // Process past data final var fromDate = now.minusHours(3); final var toDate = now.minusMinutes(15); - + try { var queryResult = timedata.queryHistoricData(null, fromDate, toDate, // Set.of(channelQuarterlyPrices, channelStateMachine, // diff --git a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/optimizer/UtilsTest.java b/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/optimizer/UtilsTest.java index bd3309a40c5..58d02834e31 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/optimizer/UtilsTest.java +++ b/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/optimizer/UtilsTest.java @@ -207,7 +207,7 @@ public void testCalculateChargeGridPower() { .withGridActivePower(10_000), // /* maxChargePowerFromGrid */ 20_000, // /* limitChargePowerFor14aEnWG */ true).intValue()); - + assertEquals(-11000, calculateChargeGridPower(null, // new DummyManagedSymmetricEss("ess0") // .withCapacity(20_000) // diff --git a/io.openems.edge.controller.io.heatingelement/src/io/openems/edge/controller/io/heatingelement/ControllerIoHeatingElementImpl.java b/io.openems.edge.controller.io.heatingelement/src/io/openems/edge/controller/io/heatingelement/ControllerIoHeatingElementImpl.java index 11f32531716..3fddd82d2b0 100644 --- a/io.openems.edge.controller.io.heatingelement/src/io/openems/edge/controller/io/heatingelement/ControllerIoHeatingElementImpl.java +++ b/io.openems.edge.controller.io.heatingelement/src/io/openems/edge/controller/io/heatingelement/ControllerIoHeatingElementImpl.java @@ -219,8 +219,7 @@ protected Status modeAutomatic() throws IllegalArgumentException, OpenemsNamedEx targetLevel = this.applyHysteresis(targetLevel); Status runState; - runState = targetLevel.equals(Level.LEVEL_0) ? Status.INACTIVE - : Status.ACTIVE; + runState = targetLevel.equals(Level.LEVEL_0) ? Status.INACTIVE : Status.ACTIVE; var now = LocalTime.now(this.componentManager.getClock()); var configuredEndTime = DateUtils.parseLocalTimeOrError(this.config.endTime()); diff --git a/io.openems.edge.core/src/io/openems/edge/app/evcs/DezonyEvcs.java b/io.openems.edge.core/src/io/openems/edge/app/evcs/DezonyEvcs.java index acb60aef5e5..88bcc11c66e 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/evcs/DezonyEvcs.java +++ b/io.openems.edge.core/src/io/openems/edge/app/evcs/DezonyEvcs.java @@ -148,7 +148,8 @@ protected ThrowingTriFunction, L return AppConfiguration.create() // .addTask(Tasks.component(components)) // - .addTask(Tasks.schedulerByCentralOrder(new SchedulerComponent(ctrlEvcsId, "Controller.Evcs", this.getAppId()))) // + .addTask(Tasks.schedulerByCentralOrder( + new SchedulerComponent(ctrlEvcsId, "Controller.Evcs", this.getAppId()))) // .addDependencies(EvcsCluster.dependency(t, this.componentManager, this.componentUtil, maxHardwarePowerPerPhase, evcsId)) // .build(); diff --git a/io.openems.edge.core/src/io/openems/edge/app/evcs/IesKeywattEvcs.java b/io.openems.edge.core/src/io/openems/edge/app/evcs/IesKeywattEvcs.java index 9b339212730..95a1fab272a 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/evcs/IesKeywattEvcs.java +++ b/io.openems.edge.core/src/io/openems/edge/app/evcs/IesKeywattEvcs.java @@ -154,7 +154,8 @@ protected ThrowingTriFunction, L return AppConfiguration.create() // .addTask(Tasks.component(components)) // - .addTask(Tasks.schedulerByCentralOrder(new SchedulerComponent(ctrlEvcsId, "Controller.Evcs", this.getAppId()))) // + .addTask(Tasks.schedulerByCentralOrder( + new SchedulerComponent(ctrlEvcsId, "Controller.Evcs", this.getAppId()))) // .addDependencies(EvcsCluster.dependency(t, this.componentManager, this.componentUtil, maxHardwarePowerPerPhase, evcsId)) // .build(); diff --git a/io.openems.edge.core/src/io/openems/edge/app/evcs/KebaEvcs.java b/io.openems.edge.core/src/io/openems/edge/app/evcs/KebaEvcs.java index bf1344b7b9e..e9a680cb831 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/evcs/KebaEvcs.java +++ b/io.openems.edge.core/src/io/openems/edge/app/evcs/KebaEvcs.java @@ -141,7 +141,8 @@ protected ThrowingTriFunction, L return AppConfiguration.create() // .addTask(Tasks.component(components)) // - .addTask(Tasks.schedulerByCentralOrder(new SchedulerComponent(ctrlEvcsId, "Controller.Evcs", this.getAppId()))) // + .addTask(Tasks.schedulerByCentralOrder( + new SchedulerComponent(ctrlEvcsId, "Controller.Evcs", this.getAppId()))) // .throwingOnlyIf(ip.startsWith("192.168.25."), b -> b.addTask(Tasks.staticIp(new InterfaceConfiguration("eth0") // .addIp("Evcs", "192.168.25.10/24")))) // diff --git a/io.openems.edge.core/src/io/openems/edge/app/evcs/WebastoNextEvcs.java b/io.openems.edge.core/src/io/openems/edge/app/evcs/WebastoNextEvcs.java index 32044ba31d6..8530681aae6 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/evcs/WebastoNextEvcs.java +++ b/io.openems.edge.core/src/io/openems/edge/app/evcs/WebastoNextEvcs.java @@ -161,7 +161,8 @@ protected ThrowingTriFunction, L return AppConfiguration.create() // .addTask(Tasks.component(components)) // - .addTask(Tasks.schedulerByCentralOrder(new SchedulerComponent(ctrlEvcsId, "Controller.Evcs", this.getAppId()))) // + .addTask(Tasks.schedulerByCentralOrder( + new SchedulerComponent(ctrlEvcsId, "Controller.Evcs", this.getAppId()))) // .addDependencies(EvcsCluster.dependency(t, this.componentManager, this.componentUtil, maxHardwarePowerPerPhase, evcsId)) // .build(); diff --git a/io.openems.edge.core/src/io/openems/edge/app/evcs/WebastoUniteEvcs.java b/io.openems.edge.core/src/io/openems/edge/app/evcs/WebastoUniteEvcs.java index 8966672689a..9a3f9e9dff1 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/evcs/WebastoUniteEvcs.java +++ b/io.openems.edge.core/src/io/openems/edge/app/evcs/WebastoUniteEvcs.java @@ -161,7 +161,8 @@ protected ThrowingTriFunction, L return AppConfiguration.create() // .addTask(Tasks.component(components)) // - .addTask(Tasks.schedulerByCentralOrder(new SchedulerComponent(ctrlEvcsId, "Controller.Evcs", this.getAppId()))) // + .addTask(Tasks.schedulerByCentralOrder( + new SchedulerComponent(ctrlEvcsId, "Controller.Evcs", this.getAppId()))) // .addDependencies(EvcsCluster.dependency(t, this.componentManager, this.componentUtil, maxHardwarePowerPerPhase, evcsId)) // .build(); diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/formly/JsonFormlyUtil.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/formly/JsonFormlyUtil.java index 9b6dac90949..5c91ac7cefd 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/formly/JsonFormlyUtil.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/formly/JsonFormlyUtil.java @@ -146,7 +146,7 @@ public static > RangeBuilder buildRange(T property) { public static RangeBuilder buildRangeFromNameable(Nameable nameable) { return new RangeBuilder(nameable); } - + /** * Creates a JsonObject Formly DateTime Builder for the given enum. * @@ -156,7 +156,7 @@ public static RangeBuilder buildRangeFromNameable(Nameable nameable) { public static DateTimeBuilder buildDateTimeFromNameable(Nameable nameable) { return new DateTimeBuilder(nameable); } - + /** * Creates a JsonObject Formly Repeat Builder for the given enum. * diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/Checkables.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/Checkables.java index cbd23d84ab7..65b03fa36c4 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/Checkables.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/Checkables.java @@ -41,7 +41,7 @@ public static CheckableConfig checkRelayCount(String io, int count, InjectableCo * Creates a {@link CheckableConfig} which checks if any installed relay has at * least the given amount of ports available. * - * @param count the number of available ports + * @param count the number of available ports * @param filters additional relay filter * @return the {@link CheckableConfig} */ diff --git a/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome30.java b/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome30.java index 1a32aa6ffeb..0603064a596 100644 --- a/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome30.java +++ b/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome30.java @@ -139,7 +139,8 @@ public void testEnableEmergency() throws Exception { this.appManagerTestBundle.sut.handleUpdateAppInstanceRequest(DUMMY_ADMIN, new UpdateAppInstance.Request( homeInstance.instanceId, homeInstance.alias, fullSettingsWithoutEmergencyReserve())); - this.appManagerTestBundle.scheduler.assertExactSchedulerOrder("Update Home 30 to remove EmergencyReserve Controller", + this.appManagerTestBundle.scheduler.assertExactSchedulerOrder( + "Update Home 30 to remove EmergencyReserve Controller", // "ctrlPrepareBatteryExtension0", "ctrlGridOptimizedCharge0", "ctrlEssSurplusFeedToGrid0", "ctrlBalancing0"); } @@ -267,7 +268,8 @@ public static final OpenemsAppInstance createFullHome30(AppManagerTestBundle app assertNotNull(homeInstance); appManagerTestBundle.assertNoValidationErrors(); - appManagerTestBundle.scheduler.assertExactSchedulerOrder("Failed setting initial Home 30 Scheduler configuration", + appManagerTestBundle.scheduler.assertExactSchedulerOrder( + "Failed setting initial Home 30 Scheduler configuration", // "ctrlPrepareBatteryExtension0", "ctrlEmergencyCapacityReserve0", "ctrlGridOptimizedCharge0", "ctrlEssSurplusFeedToGrid0", "ctrlBalancing0"); return homeInstance; diff --git a/io.openems.edge.predictor.api/src/io/openems/edge/predictor/api/manager/PredictorManager.java b/io.openems.edge.predictor.api/src/io/openems/edge/predictor/api/manager/PredictorManager.java index b5c4499b7f0..dc9fdea5567 100644 --- a/io.openems.edge.predictor.api/src/io/openems/edge/predictor/api/manager/PredictorManager.java +++ b/io.openems.edge.predictor.api/src/io/openems/edge/predictor/api/manager/PredictorManager.java @@ -4,6 +4,7 @@ import io.openems.edge.common.channel.Doc; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.predictor.api.prediction.Prediction; +import io.openems.edge.predictor.api.prediction.Predictor; public interface PredictorManager extends OpenemsComponent { @@ -29,8 +30,8 @@ public Doc doc() { * given {@link ChannelAddress}. * * @param channelAddress the {@link ChannelAddress} - * @return the {@link Prediction}; {@link Prediction#EMPTY_PREDICTION} if no Predictor - * matches the Channel-Address + * @return the {@link Prediction}; {@link Prediction#EMPTY_PREDICTION} if no + * Predictor matches the Channel-Address */ public Prediction getPrediction(ChannelAddress channelAddress); } diff --git a/io.openems.edge.timedata.influxdb/src/io/openems/edge/timedata/influxdb/TimedataInfluxDbImpl.java b/io.openems.edge.timedata.influxdb/src/io/openems/edge/timedata/influxdb/TimedataInfluxDbImpl.java index d0b7c3f4b61..10517dc27a4 100644 --- a/io.openems.edge.timedata.influxdb/src/io/openems/edge/timedata/influxdb/TimedataInfluxDbImpl.java +++ b/io.openems.edge.timedata.influxdb/src/io/openems/edge/timedata/influxdb/TimedataInfluxDbImpl.java @@ -220,33 +220,34 @@ public SortedMap> queryResendData(Z // TODO implement this method return emptySortedMap(); } - + @Override public CompletableFuture> getLatestValue(ChannelAddress channelAddress) { - return CompletableFuture.supplyAsync(() -> { - try { - SortedMap sortedMap = this.influxConnector.queryLastData(Optional.empty(), channelAddress, this.config.measurement()); + return CompletableFuture.supplyAsync(() -> { + try { + SortedMap sortedMap = this.influxConnector.queryLastData(Optional.empty(), + channelAddress, this.config.measurement()); - if (sortedMap != null && !sortedMap.isEmpty() && sortedMap.containsKey(channelAddress)) { - JsonElement latestValue = sortedMap.get(channelAddress); + if (sortedMap != null && !sortedMap.isEmpty() && sortedMap.containsKey(channelAddress)) { + JsonElement latestValue = sortedMap.get(channelAddress); - // Check if it´s a number and can be converted to long - if (latestValue.isJsonPrimitive()) { - if (latestValue.getAsJsonPrimitive().isNumber()) { - return Optional.of(latestValue.getAsLong()); - } - } - } else { - // No data found - return Optional.empty(); - } - } catch (Exception e) { - this.log.error("Error getting latest value", e); - } - return Optional.empty(); - }); + // Check if it´s a number and can be converted to long + if (latestValue.isJsonPrimitive()) { + if (latestValue.getAsJsonPrimitive().isNumber()) { + return Optional.of(latestValue.getAsLong()); + } + } + } else { + // No data found + return Optional.empty(); + } + } catch (Exception e) { + this.log.error("Error getting latest value", e); + } + return Optional.empty(); + }); } - + @Override public Timeranges getResendTimeranges(ChannelAddress notSendChannel, long lastResendTimestamp) throws OpenemsNamedException { diff --git a/io.openems.edge.timeofusetariff.awattar/src/io/openems/edge/timeofusetariff/awattar/TimeOfUseTariffAwattarImpl.java b/io.openems.edge.timeofusetariff.awattar/src/io/openems/edge/timeofusetariff/awattar/TimeOfUseTariffAwattarImpl.java index 90955376748..21a489c625d 100644 --- a/io.openems.edge.timeofusetariff.awattar/src/io/openems/edge/timeofusetariff/awattar/TimeOfUseTariffAwattarImpl.java +++ b/io.openems.edge.timeofusetariff.awattar/src/io/openems/edge/timeofusetariff/awattar/TimeOfUseTariffAwattarImpl.java @@ -149,7 +149,7 @@ public static TimeOfUsePrices parsePrices(String jsonData) throws OpenemsNamedEx .ofInstant(Instant.ofEpochMilli(getAsLong(element, "start_timestamp")), // ZoneId.systemDefault()) .truncatedTo(ChronoUnit.HOURS); - + // Adding the values in the Map. result.put(startTimeStamp, marketPrice); result.put(startTimeStamp.plusMinutes(15), marketPrice); From 348f59d0a2f7857b26b5b1347743d8d6f29e4f36 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Sun, 28 Apr 2024 22:05:52 +0200 Subject: [PATCH 004/173] Refactor RPC handling (#2610) Removed endpoints from ControllerApiBackend (edge --> backend): - UpdateUserLanguage (Threw error NotImplemented) - UpdateUserSettings (Threw error NotImplemented) Added endpoint to RestApi: - queryHistoricTimeseriesEnergyPerPeriod - queryHistoricTimeseriesExportXlxs Reviewed-by: Hueseyin Sahutoglu <34771592+huseyinsaht@users.noreply.github.com> Co-authored-by: Michael Grill <59126309+michaelgrill@users.noreply.github.com> --- cnf/checkstyle.xml | 2 +- .../exceptions/OpenemsRuntimeException.java | 28 + .../jsonrpc/serialization/JsonArrayPath.java | 39 ++ .../serialization/JsonArrayPathActual.java | 36 ++ .../serialization/JsonArrayPathDummy.java | 38 ++ .../serialization/JsonElementPath.java | 48 ++ .../serialization/JsonElementPathActual.java | 32 + .../serialization/JsonElementPathDummy.java | 49 ++ .../jsonrpc/serialization/JsonObjectPath.java | 131 ++++ .../serialization/JsonObjectPathActual.java | 33 + .../serialization/JsonObjectPathDummy.java | 47 ++ .../jsonrpc/serialization/JsonPath.java | 5 + .../jsonrpc/serialization/JsonPathDummy.java | 14 + .../jsonrpc/serialization/JsonSerializer.java | 41 ++ .../serialization/JsonSerializerUtil.java | 157 +++++ .../serialization/SerializerDescriptor.java | 26 + .../jsonrpc/serialization/StringPath.java | 21 + .../serialization/StringPathActual.java | 32 + .../serialization/StringPathDummy.java | 28 + .../jsonrpc/serialization}/package-info.java | 2 +- .../onewire/impl/BridgeOnewireImpl.java | 20 +- .../common/component/ComponentManager.java | 37 +- .../openems/edge/common/host/DummyHost.java | 12 - .../src/io/openems/edge/common/host/Host.java | 3 +- .../io/openems/edge/common/jsonapi/Call.java | 102 +++ .../edge/common/jsonapi/ComponentJsonApi.java | 12 + .../edge/common/jsonapi/EdgeGuards.java | 46 ++ .../openems/edge/common/jsonapi/EdgeKeys.java | 14 + .../jsonapi/EndpointDefinitionBuilder.java | 133 ++++ .../EndpointRequestDefinitionBuilder.java | 78 +++ .../common/jsonapi/EndpointRequestType.java | 30 + .../EndpointResponseDefinitionBuilder.java | 83 +++ .../openems/edge/common/jsonapi/Example.java | 5 + .../openems/edge/common/jsonapi/JsonApi.java | 34 +- .../edge/common/jsonapi/JsonApiBuilder.java | 609 ++++++++++++++++++ .../edge/common/jsonapi/JsonApiEndpoint.java | 66 ++ .../JsonrpcBackendRoleEndpointGuard.java | 28 + .../common/jsonapi/JsonrpcEndpointGuard.java | 17 + .../jsonapi/JsonrpcRoleEndpointGuard.java | 44 ++ .../io/openems/edge/common/jsonapi/Key.java | 5 + .../common/jsonapi/MultipleJsonApiBinder.java | 78 +++ .../common/jsonapi/SingleJsonApiBinder.java | 102 +++ .../edge/common/jsonapi/Subrequest.java | 40 ++ .../io/openems/edge/common/jsonapi/Tag.java | 27 + .../common/test/DummyComponentManager.java | 101 ++- .../openems/edge/common/jsonapi/CallTest.java | 81 +++ .../edge/common/jsonapi/DummyJsonApi.java | 16 + .../edge/common/jsonapi/EmptyObject.java | 19 + .../EndpointRequestDefinitionBuilderTest.java | 48 ++ ...EndpointResponseDefinitionBuilderTest.java | 48 ++ .../common/jsonapi/JsonApiBuilderTest.java | 188 ++++++ .../jsonapi/JsonrpcRoleEndpointGuardTest.java | 48 ++ .../jsonapi/MultipleJsonApiBinderTest.java | 54 ++ .../jsonapi/SingleJsonApiBinderTest.java | 55 ++ .../api/backend/BackendOnRequest.java | 84 +++ .../api/backend/ControllerApiBackendImpl.java | 119 ++-- .../controller/api/backend/OnRequest.java | 292 --------- .../api/backend/WebsocketClient.java | 6 +- .../{ => api}/ControllerApiBackend.java | 23 +- .../api/backend/api/package-info.java | 3 + .../handler/AuthenticatedRequestHandler.java | 65 ++ .../BindingComponentConfigRequestHandler.java | 28 + .../BindingComponentRequestHandler.java | 28 + .../handler/BindingRoutesJsonApiHandler.java | 40 ++ .../backend/handler/RootRequestHandler.java | 52 ++ .../SubscribeSystemLogJsonApiHandler.java | 63 ++ .../backend/ControllerApiBackendImplTest.java | 1 + .../backend/DummyBackendOnRequestFactory.java | 41 ++ .../ComponentConfigRequestHandler.java | 87 +++ .../handler/ComponentRequestHandler.java | 145 +++++ .../common/handler/QueryRequestHandler.java | 73 +++ .../common/handler/RoutesJsonApiHandler.java | 134 ++++ .../api/common/handler/package-info.java | 3 + .../api/modbus/AbstractModbusTcpApi.java | 52 +- .../ControllerApiModbusTcpReadOnlyImpl.java | 4 +- .../ControllerApiModbusTcpReadWriteImpl.java | 4 +- .../controller/api/rest/AbstractRestApi.java | 22 +- .../api/rest/JsonRpcRestHandler.java | 109 ++++ .../edge/controller/api/rest/RestHandler.java | 206 +----- .../BindingComponentConfigRequestHandler.java | 34 + .../BindingComponentRequestHandler.java | 34 + .../handler/BindingQueryRequestHandler.java | 26 + .../handler/BindingRoutesJsonApiHandler.java | 42 ++ .../api/rest/handler/RootRequestHandler.java | 55 ++ .../ControllerApiRestReadOnlyImpl.java | 28 +- .../ControllerApiRestReadWriteImpl.java | 28 +- .../rest/DummyJsonRpcRestHandlerFactory.java | 47 ++ .../ControllerApiRestReadOnlyImplTest.java | 5 +- .../ControllerApiRestReadWriteImplTest.java | 33 +- .../edge/controller/api/websocket/Config.java | 3 + .../api/websocket/ControllerApiWebsocket.java | 3 +- .../websocket/ControllerApiWebsocketImpl.java | 91 +-- .../controller/api/websocket/OnRequest.java | 566 ++-------------- .../api/websocket/SystemLogHandler.java | 78 --- .../api/websocket/WebsocketServer.java | 4 +- .../edge/controller/api/websocket/WsData.java | 16 - .../handler/AuthenticationRequestHandler.java | 103 +++ .../BindingComponentConfigRequestHandler.java | 34 + .../BindingComponentRequestHandler.java | 34 + .../handler/BindingQueryRequestHandler.java | 26 + .../handler/BindingRoutesJsonApiHandler.java | 42 ++ .../websocket/handler/EdgeRequestHandler.java | 37 ++ .../handler/EdgeRpcRequestHandler.java | 65 ++ .../websocket/handler/RootRequestHandler.java | 48 ++ .../SubscribeChannelsRequestHandler.java | 24 + .../SubscribeSystemLogRequestHandler.java | 75 +++ .../ControllerApiWebsocketImplTest.java | 1 + .../api/websocket/DummyOnRequestFactory.java | 36 ++ .../controller/api/websocket/MyConfig.java | 12 + .../api/websocket/OnRequestTest.java | 37 +- .../TimeOfUseTariffControllerImpl.java | 34 +- .../ControllerEssBalancingSchedule.java | 3 +- .../ControllerEssBalancingScheduleImpl.java | 46 +- .../edge/core/appmanager/AppAssistant.java | 27 +- .../appmanager/AppCenterBackendUtilImpl.java | 4 +- .../edge/core/appmanager/AppDescriptor.java | 24 +- .../edge/core/appmanager/AppManager.java | 3 +- .../edge/core/appmanager/AppManagerImpl.java | 236 ++++--- .../core/appmanager/ComponentUtilImpl.java | 14 +- .../core/appmanager/OpenemsAppInstance.java | 46 +- .../core/appmanager/ResolveDependencies.java | 6 +- .../appmanager/dependency/Dependency.java | 19 + .../ComponentAggregateTaskImpl.java | 28 +- ...PersistencePredictorAggregateTaskImpl.java | 16 +- .../appmanager/jsonrpc/AddAppInstance.java | 136 ++-- .../appmanager/jsonrpc/DeleteAppInstance.java | 101 +-- .../edge/core/appmanager/jsonrpc/GetApp.java | 106 +-- .../appmanager/jsonrpc/GetAppAssistant.java | 94 ++- .../appmanager/jsonrpc/GetAppDescriptor.java | 94 ++- .../appmanager/jsonrpc/GetAppInstances.java | 102 ++- .../edge/core/appmanager/jsonrpc/GetApps.java | 101 +-- .../appmanager/jsonrpc/UpdateAppInstance.java | 122 ++-- .../ComponentManagerImpl.java | 154 ++--- .../DefaultConfigurationWorker.java | 21 +- .../io/openems/edge/core/host/HostImpl.java | 77 +-- .../edge/app/evcs/TestEvcsCluster.java | 59 +- .../edge/app/evcs/TestHardyBarthEvcs.java | 37 +- .../openems/edge/app/heat/TestHeatPump.java | 2 +- .../app/integratedsystem/TestFeneconHome.java | 14 +- .../integratedsystem/TestFeneconHome20.java | 9 +- .../integratedsystem/TestFeneconHome30.java | 19 +- .../TestFeneconHome30DefaultRelays.java | 2 +- .../TestFeneconHomeDefaultRelays.java | 2 +- .../edge/app/timeofusetariff/TestTibber.java | 33 +- .../AppManagerAppHelperImplTest.java | 22 +- .../AppManagerImpSynchronizationTest.java | 12 +- .../core/appmanager/AppManagerTestBundle.java | 8 +- .../core/appmanager/AppPermissionTest.java | 4 +- .../DummyPseudoComponentManager.java | 40 +- .../core/appmanager/InstallationTest.java | 27 +- .../appmanager/TestSettingComponentIds.java | 20 +- .../ComponentAggregateTaskImplTest.java | 2 + ...istencePredictorAggregateTaskImplTest.java | 2 + ...erByCentralOrderAggregateTaskImplTest.java | 12 +- .../aggregatetask/TestScheduler.java | 14 +- .../appmanager/validator/CheckHomeTest.java | 18 +- .../meter/discovergy/MeterDiscovergy.java | 3 +- .../meter/discovergy/MeterDiscovergyImpl.java | 57 +- .../edge/simulator/app/SimulatorApp.java | 4 +- .../edge/simulator/app/SimulatorAppImpl.java | 35 +- ui/src/app/app-routing.module.ts | 2 + .../settings/jsonrpctest/jsonrpctest.html | 191 ++++++ .../edge/settings/jsonrpctest/jsonrpctest.ts | 187 ++++++ .../edge/settings/jsonrpctest/permission.ts | 7 + .../app/edge/settings/settings.component.html | 14 + .../app/edge/settings/settings.component.ts | 5 + ui/src/app/edge/settings/settings.module.ts | 2 + 167 files changed, 6463 insertions(+), 2459 deletions(-) create mode 100644 io.openems.common/src/io/openems/common/exceptions/OpenemsRuntimeException.java create mode 100644 io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonArrayPath.java create mode 100644 io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonArrayPathActual.java create mode 100644 io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonArrayPathDummy.java create mode 100644 io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonElementPath.java create mode 100644 io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonElementPathActual.java create mode 100644 io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonElementPathDummy.java create mode 100644 io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonObjectPath.java create mode 100644 io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonObjectPathActual.java create mode 100644 io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonObjectPathDummy.java create mode 100644 io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonPath.java create mode 100644 io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonPathDummy.java create mode 100644 io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonSerializer.java create mode 100644 io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonSerializerUtil.java create mode 100644 io.openems.common/src/io/openems/common/jsonrpc/serialization/SerializerDescriptor.java create mode 100644 io.openems.common/src/io/openems/common/jsonrpc/serialization/StringPath.java create mode 100644 io.openems.common/src/io/openems/common/jsonrpc/serialization/StringPathActual.java create mode 100644 io.openems.common/src/io/openems/common/jsonrpc/serialization/StringPathDummy.java rename {io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend => io.openems.common/src/io/openems/common/jsonrpc/serialization}/package-info.java (63%) create mode 100644 io.openems.edge.common/src/io/openems/edge/common/jsonapi/Call.java create mode 100644 io.openems.edge.common/src/io/openems/edge/common/jsonapi/ComponentJsonApi.java create mode 100644 io.openems.edge.common/src/io/openems/edge/common/jsonapi/EdgeGuards.java create mode 100644 io.openems.edge.common/src/io/openems/edge/common/jsonapi/EdgeKeys.java create mode 100644 io.openems.edge.common/src/io/openems/edge/common/jsonapi/EndpointDefinitionBuilder.java create mode 100644 io.openems.edge.common/src/io/openems/edge/common/jsonapi/EndpointRequestDefinitionBuilder.java create mode 100644 io.openems.edge.common/src/io/openems/edge/common/jsonapi/EndpointRequestType.java create mode 100644 io.openems.edge.common/src/io/openems/edge/common/jsonapi/EndpointResponseDefinitionBuilder.java create mode 100644 io.openems.edge.common/src/io/openems/edge/common/jsonapi/Example.java create mode 100644 io.openems.edge.common/src/io/openems/edge/common/jsonapi/JsonApiBuilder.java create mode 100644 io.openems.edge.common/src/io/openems/edge/common/jsonapi/JsonApiEndpoint.java create mode 100644 io.openems.edge.common/src/io/openems/edge/common/jsonapi/JsonrpcBackendRoleEndpointGuard.java create mode 100644 io.openems.edge.common/src/io/openems/edge/common/jsonapi/JsonrpcEndpointGuard.java create mode 100644 io.openems.edge.common/src/io/openems/edge/common/jsonapi/JsonrpcRoleEndpointGuard.java create mode 100644 io.openems.edge.common/src/io/openems/edge/common/jsonapi/Key.java create mode 100644 io.openems.edge.common/src/io/openems/edge/common/jsonapi/MultipleJsonApiBinder.java create mode 100644 io.openems.edge.common/src/io/openems/edge/common/jsonapi/SingleJsonApiBinder.java create mode 100644 io.openems.edge.common/src/io/openems/edge/common/jsonapi/Subrequest.java create mode 100644 io.openems.edge.common/src/io/openems/edge/common/jsonapi/Tag.java create mode 100644 io.openems.edge.common/test/io/openems/edge/common/jsonapi/CallTest.java create mode 100644 io.openems.edge.common/test/io/openems/edge/common/jsonapi/DummyJsonApi.java create mode 100644 io.openems.edge.common/test/io/openems/edge/common/jsonapi/EmptyObject.java create mode 100644 io.openems.edge.common/test/io/openems/edge/common/jsonapi/EndpointRequestDefinitionBuilderTest.java create mode 100644 io.openems.edge.common/test/io/openems/edge/common/jsonapi/EndpointResponseDefinitionBuilderTest.java create mode 100644 io.openems.edge.common/test/io/openems/edge/common/jsonapi/JsonApiBuilderTest.java create mode 100644 io.openems.edge.common/test/io/openems/edge/common/jsonapi/JsonrpcRoleEndpointGuardTest.java create mode 100644 io.openems.edge.common/test/io/openems/edge/common/jsonapi/MultipleJsonApiBinderTest.java create mode 100644 io.openems.edge.common/test/io/openems/edge/common/jsonapi/SingleJsonApiBinderTest.java create mode 100644 io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/BackendOnRequest.java delete mode 100644 io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/OnRequest.java rename io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/{ => api}/ControllerApiBackend.java (73%) create mode 100644 io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/api/package-info.java create mode 100644 io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/handler/AuthenticatedRequestHandler.java create mode 100644 io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/handler/BindingComponentConfigRequestHandler.java create mode 100644 io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/handler/BindingComponentRequestHandler.java create mode 100644 io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/handler/BindingRoutesJsonApiHandler.java create mode 100644 io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/handler/RootRequestHandler.java create mode 100644 io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/handler/SubscribeSystemLogJsonApiHandler.java create mode 100644 io.openems.edge.controller.api.backend/test/io/openems/edge/controller/api/backend/DummyBackendOnRequestFactory.java create mode 100644 io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/handler/ComponentConfigRequestHandler.java create mode 100644 io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/handler/ComponentRequestHandler.java create mode 100644 io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/handler/QueryRequestHandler.java create mode 100644 io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/handler/RoutesJsonApiHandler.java create mode 100644 io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/handler/package-info.java create mode 100644 io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/JsonRpcRestHandler.java create mode 100644 io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/handler/BindingComponentConfigRequestHandler.java create mode 100644 io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/handler/BindingComponentRequestHandler.java create mode 100644 io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/handler/BindingQueryRequestHandler.java create mode 100644 io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/handler/BindingRoutesJsonApiHandler.java create mode 100644 io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/handler/RootRequestHandler.java create mode 100644 io.openems.edge.controller.api.rest/test/io/openems/edge/controller/api/rest/DummyJsonRpcRestHandlerFactory.java delete mode 100644 io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/SystemLogHandler.java create mode 100644 io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/AuthenticationRequestHandler.java create mode 100644 io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/BindingComponentConfigRequestHandler.java create mode 100644 io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/BindingComponentRequestHandler.java create mode 100644 io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/BindingQueryRequestHandler.java create mode 100644 io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/BindingRoutesJsonApiHandler.java create mode 100644 io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/EdgeRequestHandler.java create mode 100644 io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/EdgeRpcRequestHandler.java create mode 100644 io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/RootRequestHandler.java create mode 100644 io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/SubscribeChannelsRequestHandler.java create mode 100644 io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/SubscribeSystemLogRequestHandler.java create mode 100644 io.openems.edge.controller.api.websocket/test/io/openems/edge/controller/api/websocket/DummyOnRequestFactory.java create mode 100644 ui/src/app/edge/settings/jsonrpctest/jsonrpctest.html create mode 100644 ui/src/app/edge/settings/jsonrpctest/jsonrpctest.ts create mode 100644 ui/src/app/edge/settings/jsonrpctest/permission.ts diff --git a/cnf/checkstyle.xml b/cnf/checkstyle.xml index 7f0ec058035..ad22318becf 100644 --- a/cnf/checkstyle.xml +++ b/cnf/checkstyle.xml @@ -132,7 +132,7 @@ - + diff --git a/io.openems.common/src/io/openems/common/exceptions/OpenemsRuntimeException.java b/io.openems.common/src/io/openems/common/exceptions/OpenemsRuntimeException.java new file mode 100644 index 00000000000..d0a67297ec5 --- /dev/null +++ b/io.openems.common/src/io/openems/common/exceptions/OpenemsRuntimeException.java @@ -0,0 +1,28 @@ +package io.openems.common.exceptions; + +public class OpenemsRuntimeException extends RuntimeException { + + private static final long serialVersionUID = -4509666272212124910L; + + public OpenemsRuntimeException() { + super(); + } + + public OpenemsRuntimeException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + public OpenemsRuntimeException(String message, Throwable cause) { + super(message, cause); + } + + public OpenemsRuntimeException(String message) { + super(message); + } + + public OpenemsRuntimeException(Throwable cause) { + super(cause); + } + +} diff --git a/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonArrayPath.java b/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonArrayPath.java new file mode 100644 index 00000000000..99ad2a70858 --- /dev/null +++ b/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonArrayPath.java @@ -0,0 +1,39 @@ +package io.openems.common.jsonrpc.serialization; + +import java.util.List; +import java.util.function.Function; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +public interface JsonArrayPath extends JsonPath { + + /** + * Gets the elements as a list parsed to the object. + * + * @param the type of the objects + * @param mapper the {@link JsonElement} to object mapper + * @return the list with the parsed values + */ + public List getAsList(Function mapper); + + /** + * Gets the elements as a list parsed to the object. + * + * @param the type of the objects + * @param serializer the {@link JsonSerializer} to deserialize the elements + * @return the list with the parsed values + */ + public default List getAsList(JsonSerializer serializer) { + return this.getAsList(serializer::deserializePath); + } + + /** + * Gets the current element of the path. + * + * @return the {@link JsonObject} + */ + public JsonArray get(); + +} \ No newline at end of file diff --git a/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonArrayPathActual.java b/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonArrayPathActual.java new file mode 100644 index 00000000000..67ac20a1079 --- /dev/null +++ b/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonArrayPathActual.java @@ -0,0 +1,36 @@ +package io.openems.common.jsonrpc.serialization; + +import java.util.List; +import java.util.function.Function; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsRuntimeException; +import io.openems.common.utils.JsonUtils; + +public class JsonArrayPathActual implements JsonArrayPath { + + private final JsonArray object; + + public JsonArrayPathActual(JsonElement object) { + if (!object.isJsonArray()) { + throw new OpenemsRuntimeException(object + " is not a JsonArray!"); + } + this.object = object.getAsJsonArray(); + } + + @Override + public List getAsList(Function mapper) { + return JsonUtils.stream(this.object) // + .map(JsonElementPathActual::new) // + .map(mapper) // + .toList(); + } + + @Override + public JsonArray get() { + return this.object; + } + +} \ No newline at end of file diff --git a/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonArrayPathDummy.java b/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonArrayPathDummy.java new file mode 100644 index 00000000000..bc592b0eacf --- /dev/null +++ b/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonArrayPathDummy.java @@ -0,0 +1,38 @@ +package io.openems.common.jsonrpc.serialization; + +import static java.util.Collections.emptyList; + +import java.util.List; +import java.util.function.Function; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; + +import io.openems.common.utils.JsonUtils; + +public class JsonArrayPathDummy implements JsonArrayPath, JsonPathDummy { + + private JsonPathDummy elementType; + + @Override + public List getAsList(Function mapper) { + final var path = new JsonElementPathDummy(); + mapper.apply(path); + this.elementType = path; + return emptyList(); + } + + @Override + public JsonArray get() { + return new JsonArray(); + } + + @Override + public JsonElement buildPath() { + return JsonUtils.buildJsonObject() // + .addProperty("type", "array") // + .onlyIf(this.elementType != null, t -> t.add("elementType", this.elementType.buildPath())) // + .build(); + } + +} diff --git a/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonElementPath.java b/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonElementPath.java new file mode 100644 index 00000000000..043f8eb3779 --- /dev/null +++ b/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonElementPath.java @@ -0,0 +1,48 @@ +package io.openems.common.jsonrpc.serialization; + +import com.google.gson.JsonElement; + +public interface JsonElementPath extends JsonPath { + + /** + * Gets the current {@link JsonElementPath} as a {@link JsonObjectPath}. + * + * @return the current element as a {@link JsonObjectPath} + */ + public JsonObjectPath getAsJsonObjectPath(); + + /** + * Gets the current {@link JsonElementPath} as a {@link JsonArrayPath}. + * + * @return the current element as a {@link JsonArrayPath} + */ + public JsonArrayPath getAsJsonArrayPath(); + + /** + * Gets the current {@link JsonElementPath} as a {@link StringPath}. + * + * @return the current element as a {@link StringPath} + */ + public StringPath getAsStringPath(); + + /** + * Gets the current {@link JsonElementPath} as a {@link String}. + * + * @return the current element as a {@link String} + */ + public default String getAsString() { + return this.getAsStringPath().get(); + } + + /** + * Gets the current {@link JsonElementPath} as a Object serialized with the + * provided {@link JsonSerializer}. + * + * @param the type of the final object + * @param serializer the {@link JsonSerializer} to deserialize the + * {@link JsonElement} to the object + * @return the current element as a {@link StringPath} + */ + public O getAsObject(JsonSerializer serializer); + +} \ No newline at end of file diff --git a/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonElementPathActual.java b/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonElementPathActual.java new file mode 100644 index 00000000000..e0d955d1a60 --- /dev/null +++ b/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonElementPathActual.java @@ -0,0 +1,32 @@ +package io.openems.common.jsonrpc.serialization; + +import com.google.gson.JsonElement; + +public class JsonElementPathActual implements JsonElementPath { + private final JsonElement element; + + public JsonElementPathActual(JsonElement element) { + this.element = element; + } + + @Override + public JsonArrayPath getAsJsonArrayPath() { + return new JsonArrayPathActual(this.element); + } + + @Override + public JsonObjectPath getAsJsonObjectPath() { + return new JsonObjectPathActual(this.element); + } + + @Override + public StringPath getAsStringPath() { + return new StringPathActual(this.element); + } + + @Override + public O getAsObject(JsonSerializer deserializer) { + return deserializer.deserializePath(new JsonElementPathActual(this.element)); + } + +} diff --git a/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonElementPathDummy.java b/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonElementPathDummy.java new file mode 100644 index 00000000000..5d26b9bffb4 --- /dev/null +++ b/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonElementPathDummy.java @@ -0,0 +1,49 @@ +package io.openems.common.jsonrpc.serialization; + +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; + +public class JsonElementPathDummy implements JsonElementPath, JsonPathDummy { + + private JsonPathDummy dummyPath; + + @Override + public JsonArrayPath getAsJsonArrayPath() { + return this.withDummyPath(new JsonArrayPathDummy()); + } + + @Override + public JsonObjectPath getAsJsonObjectPath() { + return this.withDummyPath(new JsonObjectPathDummy()); + } + + @Override + public StringPath getAsStringPath() { + return this.withDummyPath(new StringPathDummy()); + } + + @Override + public O getAsObject(JsonSerializer deserializer) { + final var dummyPath = new JsonElementPathDummy(); + this.withDummyPath(dummyPath); + return deserializer.deserializePath(dummyPath); + } + + private T withDummyPath(T path) { + if (this.dummyPath != null) { + throw new RuntimeException("Path already set"); + } + this.dummyPath = path; + return path; + } + + public JsonPathDummy getDummyPath() { + return this.dummyPath; + } + + @Override + public JsonElement buildPath() { + return this.dummyPath == null ? JsonNull.INSTANCE : this.dummyPath.buildPath(); + } + +} diff --git a/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonObjectPath.java b/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonObjectPath.java new file mode 100644 index 00000000000..fbd925cec08 --- /dev/null +++ b/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonObjectPath.java @@ -0,0 +1,131 @@ +package io.openems.common.jsonrpc.serialization; + +import java.util.List; +import java.util.function.Function; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; + +public interface JsonObjectPath extends JsonPath { + + /** + * Gets the element associated with the member name from this object. + * + * @param member the name of the member + * @return the {@link JsonElementPath} of the member value + */ + public JsonElementPath getJsonElementPath(String member); + + /** + * Gets the element associated with the member name from this object as a + * {@link StringPath}. + * + * @param member the name of the member + * @return the {@link StringPath} of the member value + */ + public default StringPath getStringPath(String member) { + return this.getJsonElementPath(member).getAsStringPath(); + } + + /** + * Gets the element associated with the member name from this object as a + * {@link String}. + * + * @param member the name of the member + * @return the {@link String} of the member value + */ + public default String getString(String member) { + return this.getStringPath(member).get(); + } + + /** + * Gets the element associated with the member name from this object as a + * {@link JsonObjectPath}. + * + * @param member the name of the member + * @return the {@link JsonObjectPath} of the member value + */ + public default JsonObjectPath getJsonObjectPath(String member) { + return this.getJsonElementPath(member).getAsJsonObjectPath(); + } + + /** + * Gets the element associated with the member name from this object as a + * {@link JsonObject}. + * + * @param member the name of the member + * @return the {@link JsonObject} of the member value + */ + public default JsonObject getJsonObject(String member) { + return this.getJsonObjectPath(member).get(); + } + + /** + * Gets the element associated with the member name from this object as a + * {@link JsonArrayPath}. + * + * @param member the name of the member + * @return the {@link JsonArrayPath} of the member value + */ + public default JsonArrayPath getJsonArrayPath(String member) { + return this.getJsonElementPath(member).getAsJsonArrayPath(); + } + + /** + * Gets the element associated with the member name from this object as a + * {@link JsonArray}. + * + * @param member the name of the member + * @return the {@link JsonArray} of the member value + */ + public default JsonArray getJsonArray(String member) { + return this.getJsonArrayPath(member).get(); + } + + /** + * Gets the element associated with the member name from this object as a + * {@link List}. + * + * @param the type of the elements in the list + * @param member the name of the member + * @param mapper the mapper to deserialize the elements + * @return the {@link List} of the member value + */ + public default List getList(String member, Function mapper) { + return this.getJsonArrayPath(member).getAsList(mapper); + } + + /** + * Gets the element associated with the member name from this object as a + * {@link List}. + * + * @param the type of the elements in the list + * @param member the name of the member + * @param serializer the {@link JsonSerializer} to deserialize the elements + * @return the {@link List} of the member value + */ + public default List getList(String member, JsonSerializer serializer) { + return this.getJsonArrayPath(member).getAsList(serializer); + } + + /** + * Gets the element associated with the member name from this object as the + * generic object. + * + * @param the type of the element + * @param member the name of the member + * @param serializer the {@link JsonSerializer} to deserialize the element + * @return the object of the member value + */ + public default T getElement(String member, JsonSerializer serializer) { + return this.getJsonElementPath(member).getAsObject(serializer); + } + + /** + * Gets the current element of the path. + * + * @return the {@link JsonObject} + */ + public JsonObject get(); + +} \ No newline at end of file diff --git a/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonObjectPathActual.java b/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonObjectPathActual.java new file mode 100644 index 00000000000..7de86237260 --- /dev/null +++ b/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonObjectPathActual.java @@ -0,0 +1,33 @@ +package io.openems.common.jsonrpc.serialization; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import io.openems.common.exceptions.OpenemsRuntimeException; + +public class JsonObjectPathActual implements JsonObjectPath { + private final JsonObject object; + + public JsonObjectPathActual(JsonElement object) { + if (!object.isJsonObject()) { + throw new OpenemsRuntimeException(object + " is not a JsonObject!"); + } + this.object = object.getAsJsonObject(); + } + + @Override + public JsonElementPath getJsonElementPath(String member) { + return new JsonElementPathActual(this.object.get(member)); + } + + @Override + public JsonObjectPath getJsonObjectPath(String member) { + return new JsonObjectPathActual(this.object.get(member)); + } + + @Override + public JsonObject get() { + return this.object; + } + +} \ No newline at end of file diff --git a/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonObjectPathDummy.java b/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonObjectPathDummy.java new file mode 100644 index 00000000000..68639fee6b8 --- /dev/null +++ b/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonObjectPathDummy.java @@ -0,0 +1,47 @@ +package io.openems.common.jsonrpc.serialization; + +import static io.openems.common.utils.JsonUtils.toJsonObject; + +import java.util.Map; +import java.util.Map.Entry; +import java.util.TreeMap; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import io.openems.common.utils.JsonUtils; + +public class JsonObjectPathDummy implements JsonObjectPath, JsonPathDummy { + + private final Map paths = new TreeMap<>(); + + @Override + public JsonElementPath getJsonElementPath(String member) { + return this.withDummyPath(member, new JsonElementPathDummy()); + } + + @Override + public JsonObjectPath getJsonObjectPath(String member) { + return this.withDummyPath(member, new JsonObjectPathDummy()); + } + + @Override + public JsonObject get() { + return new JsonObject(); + } + + @Override + public JsonElement buildPath() { + return JsonUtils.buildJsonObject() // + .addProperty("type", "object") // + .add("properties", this.paths.entrySet().stream() // + .collect(toJsonObject(Entry::getKey, input -> input.getValue().buildPath()))) // + .build(); + } + + private final T withDummyPath(String member, T path) { + this.paths.put(member, path); + return path; + } + +} diff --git a/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonPath.java b/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonPath.java new file mode 100644 index 00000000000..4c9b0d82a59 --- /dev/null +++ b/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonPath.java @@ -0,0 +1,5 @@ +package io.openems.common.jsonrpc.serialization; + +public interface JsonPath { + +} diff --git a/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonPathDummy.java b/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonPathDummy.java new file mode 100644 index 00000000000..3148bab82e0 --- /dev/null +++ b/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonPathDummy.java @@ -0,0 +1,14 @@ +package io.openems.common.jsonrpc.serialization; + +import com.google.gson.JsonElement; + +public interface JsonPathDummy { + + /** + * Creates the description of the Path as a {@link JsonElement}. + * + * @return the created {@link JsonElement} + */ + public JsonElement buildPath(); + +} diff --git a/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonSerializer.java b/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonSerializer.java new file mode 100644 index 00000000000..2b8e52df570 --- /dev/null +++ b/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonSerializer.java @@ -0,0 +1,41 @@ +package io.openems.common.jsonrpc.serialization; + +import com.google.gson.JsonElement; + +public interface JsonSerializer { + + /** + * Gets the {@link SerializerDescriptor} of the object this serializer + * serializes. + * + * @return the {@link SerializerDescriptor} + */ + public SerializerDescriptor descriptor(); + + /** + * Serializes from a object to a {@link JsonElement}. + * + * @param obj the object to serialize + * @return the serialized object as a {@link JsonElement} + */ + public JsonElement serialize(T obj); + + /** + * Deserializes from a {@link JsonElement} to the object. + * + * @param json the {@link JsonElement} to deserialize into a object + * @return the deserialized object from the {@link JsonElement} + */ + public T deserializePath(JsonElementPath json); + + /** + * Deserializes from a {@link JsonElement} to the object. + * + * @param json the {@link JsonElement} to deserialize into a object + * @return the deserialized object from the {@link JsonElement} + */ + public default T deserialize(JsonElement json) { + return this.deserializePath(new JsonElementPathActual(json)); + } + +} diff --git a/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonSerializerUtil.java b/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonSerializerUtil.java new file mode 100644 index 00000000000..2052d35d0b8 --- /dev/null +++ b/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonSerializerUtil.java @@ -0,0 +1,157 @@ +package io.openems.common.jsonrpc.serialization; + +import java.util.function.Function; + +import com.google.common.base.Supplier; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +public final class JsonSerializerUtil { + + /** + * Creates a {@link JsonSerializer} for a empty {@link JsonObject}. + * + * @param the type of the object + * @param object the object supplier to create an empty instance of it + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer emptyObjectSerializer(// + Supplier object // + ) { + return jsonObjectSerializer(json -> object.get(), json -> new JsonObject()); + } + + /** + * Creates a {@link JsonSerializer} for the provided type. + * + * @param the type of the object to serialize and deserialize. + * @param clazz the {@link Class} of the object + * @param toObjMapper the deserializer from {@link JsonObject} to object + * @param toJsonMapper the serializer from object to {@link JsonElement} + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer jsonObjectSerializer(// + Class clazz, // + Function toObjMapper, // + Function toJsonMapper // + ) { + return jsonObjectSerializer(toObjMapper, toJsonMapper); + } + + /** + * Creates a {@link JsonSerializer} for the provided type. + * + * @param the type of the object to serialize and deserialize. + * @param toObjMapper the deserializer from {@link JsonObject} to object + * @param toJsonMapper the serializer from object to {@link JsonElement} + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer jsonObjectSerializer(// + Function toObjMapper, // + Function toJsonMapper // + ) { + return jsonSerializer(toObjMapper.compose(JsonElementPath::getAsJsonObjectPath), toJsonMapper); + } + + /** + * Creates a {@link JsonSerializer} for the provided type. + * + * @param the type of the object to serialize and deserialize. + * @param clazz the {@link Class} of the object + * @param toObjMapper the deserializer from {@link JsonArray} to object + * @param toJsonMapper the serializer from object to {@link JsonElement} + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer jsonArraySerializer(// + Class clazz, // + Function toObjMapper, // + Function toJsonMapper // + ) { + return jsonArraySerializer(toObjMapper, toJsonMapper); + } + + /** + * Creates a {@link JsonSerializer} for the provided type. + * + * @param the type of the object to serialize and deserialize. + * @param toObjMapper the deserializer from {@link JsonArray} to object + * @param toJsonMapper the serializer from object to {@link JsonElement} + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer jsonArraySerializer(// + Function toObjMapper, // + Function toJsonMapper // + ) { + return jsonSerializer(toObjMapper.compose(JsonElementPath::getAsJsonArrayPath), toJsonMapper); + } + + /** + * Creates a {@link JsonSerializer} for the provided type. + * + * @param the type of the object to serialize and deserialize. + * @param clazz the {@link Class} of the object + * @param toObjMapper the deserializer from {@link JsonElement} to object + * @param toJsonMapper the serializer from object ot {@link JsonElement} + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer jsonSerializer(// + Class clazz, // + Function toObjMapper, // + Function toJsonMapper // + ) { + return jsonSerializer(toObjMapper, toJsonMapper); + } + + /** + * Creates a {@link JsonSerializer} for the provided type. + * + * @param the type of the object to serialize and deserialize. + * @param toObjMapper the deserializer from {@link JsonElement} to object + * @param toJsonMapper the serializer from object to {@link JsonElement} + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer jsonSerializer(// + Function toObjMapper, // + Function toJsonMapper // + ) { + final var path = new JsonElementPathDummy(); + toObjMapper.apply(path); + return new SimpleJsonSerializer(new SerializerDescriptor(path), toJsonMapper, toObjMapper); + } + + private JsonSerializerUtil() { + } + + private static final class SimpleJsonSerializer implements JsonSerializer { + + private final SerializerDescriptor descriptor; + private final Function serialize; + private final Function deserialize; + + public SimpleJsonSerializer(SerializerDescriptor descriptor, Function serialize, + Function deserialize) { + super(); + this.descriptor = descriptor; + this.serialize = serialize; + this.deserialize = deserialize; + } + + @Override + public SerializerDescriptor descriptor() { + return this.descriptor; + } + + @Override + public JsonElement serialize(T a) { + return this.serialize.apply(a); + } + + @Override + public T deserializePath(JsonElementPath a) { + return this.deserialize.apply(a); + } + + } + +} diff --git a/io.openems.common/src/io/openems/common/jsonrpc/serialization/SerializerDescriptor.java b/io.openems.common/src/io/openems/common/jsonrpc/serialization/SerializerDescriptor.java new file mode 100644 index 00000000000..568cf1a2c09 --- /dev/null +++ b/io.openems.common/src/io/openems/common/jsonrpc/serialization/SerializerDescriptor.java @@ -0,0 +1,26 @@ +package io.openems.common.jsonrpc.serialization; + +import com.google.gson.JsonElement; + +public class SerializerDescriptor { + + private final JsonElementPathDummy obj; + + public SerializerDescriptor(JsonElementPathDummy obj) { + this.obj = obj; + } + + /** + * Creates a {@link JsonElement} of the object description. + * + * @return the created {@link JsonElementPath} + */ + public JsonElement toJson() { + return this.obj.buildPath(); + } + + public JsonElementPathDummy getObj() { + return this.obj; + } + +} diff --git a/io.openems.common/src/io/openems/common/jsonrpc/serialization/StringPath.java b/io.openems.common/src/io/openems/common/jsonrpc/serialization/StringPath.java new file mode 100644 index 00000000000..d32c4056eb0 --- /dev/null +++ b/io.openems.common/src/io/openems/common/jsonrpc/serialization/StringPath.java @@ -0,0 +1,21 @@ +package io.openems.common.jsonrpc.serialization; + +import java.util.UUID; + +public interface StringPath extends JsonPath { + + /** + * Gets the string value of the current path. + * + * @return the value + */ + public String get(); + + /** + * Gets the value as a {@link UUID}. + * + * @return the {@link UUID} + */ + public UUID getAsUuid(); + +} diff --git a/io.openems.common/src/io/openems/common/jsonrpc/serialization/StringPathActual.java b/io.openems.common/src/io/openems/common/jsonrpc/serialization/StringPathActual.java new file mode 100644 index 00000000000..d0f2e2799b1 --- /dev/null +++ b/io.openems.common/src/io/openems/common/jsonrpc/serialization/StringPathActual.java @@ -0,0 +1,32 @@ +package io.openems.common.jsonrpc.serialization; + +import java.util.UUID; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsRuntimeException; + +public class StringPathActual implements StringPath { + + private final String element; + + public StringPathActual(JsonElement element) throws OpenemsRuntimeException { + super(); + if (!element.isJsonPrimitive() // + || !element.getAsJsonPrimitive().isString()) { + throw new OpenemsRuntimeException(element + " is not a String!"); + } + this.element = element.getAsString(); + } + + @Override + public String get() { + return this.element; + } + + @Override + public UUID getAsUuid() { + return UUID.fromString(this.element); + } + +} diff --git a/io.openems.common/src/io/openems/common/jsonrpc/serialization/StringPathDummy.java b/io.openems.common/src/io/openems/common/jsonrpc/serialization/StringPathDummy.java new file mode 100644 index 00000000000..5cd61d65a25 --- /dev/null +++ b/io.openems.common/src/io/openems/common/jsonrpc/serialization/StringPathDummy.java @@ -0,0 +1,28 @@ +package io.openems.common.jsonrpc.serialization; + +import java.util.UUID; + +import com.google.gson.JsonElement; + +import io.openems.common.utils.JsonUtils; + +public class StringPathDummy implements StringPath, JsonPathDummy { + + @Override + public String get() { + return ""; + } + + @Override + public UUID getAsUuid() { + return UUID.randomUUID(); + } + + @Override + public JsonElement buildPath() { + return JsonUtils.buildJsonObject() // + .addProperty("type", "string") // + .build(); + } + +} diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/package-info.java b/io.openems.common/src/io/openems/common/jsonrpc/serialization/package-info.java similarity index 63% rename from io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/package-info.java rename to io.openems.common/src/io/openems/common/jsonrpc/serialization/package-info.java index cd7e2d65c23..5d8dc7bba5c 100644 --- a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/package-info.java +++ b/io.openems.common/src/io/openems/common/jsonrpc/serialization/package-info.java @@ -1,3 +1,3 @@ @org.osgi.annotation.versioning.Version("1.0.0") @org.osgi.annotation.bundle.Export -package io.openems.edge.controller.api.backend; +package io.openems.common.jsonrpc.serialization; diff --git a/io.openems.edge.bridge.onewire/src/io/openems/edge/bridge/onewire/impl/BridgeOnewireImpl.java b/io.openems.edge.bridge.onewire/src/io/openems/edge/bridge/onewire/impl/BridgeOnewireImpl.java index 95cadfee470..b03ef071bd0 100644 --- a/io.openems.edge.bridge.onewire/src/io/openems/edge/bridge/onewire/impl/BridgeOnewireImpl.java +++ b/io.openems.edge.bridge.onewire/src/io/openems/edge/bridge/onewire/impl/BridgeOnewireImpl.java @@ -1,6 +1,5 @@ package io.openems.edge.bridge.onewire.impl; -import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; import org.osgi.service.component.ComponentContext; @@ -14,16 +13,13 @@ import com.dalsemi.onewire.adapter.DSPortAdapter; -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.jsonrpc.base.JsonrpcRequest; -import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; import io.openems.edge.bridge.onewire.BridgeOnewire; import io.openems.edge.bridge.onewire.jsonrpc.GetDevicesRequest; import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.event.EdgeEventConstants; -import io.openems.edge.common.jsonapi.JsonApi; -import io.openems.edge.common.user.User; +import io.openems.edge.common.jsonapi.ComponentJsonApi; +import io.openems.edge.common.jsonapi.JsonApiBuilder; @Designate(ocd = Config.class, factory = true) @Component(// @@ -34,7 +30,8 @@ @EventTopics({ // EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE // }) -public class BridgeOnewireImpl extends AbstractOpenemsComponent implements BridgeOnewire, OpenemsComponent, JsonApi { +public class BridgeOnewireImpl extends AbstractOpenemsComponent + implements BridgeOnewire, OpenemsComponent, ComponentJsonApi { private OneWireTaskWorker taskWorker = null; @@ -84,13 +81,8 @@ protected void logError(Logger log, String message) { } @Override - public CompletableFuture handleJsonrpcRequest(User user, JsonrpcRequest message) - throws OpenemsNamedException { - switch (message.getMethod()) { - case GetDevicesRequest.METHOD: - return CompletableFuture.completedFuture(this.taskWorker.handleGetDevicesRequest(message)); - } - return null; + public void buildJsonApiRoutes(JsonApiBuilder builder) { + builder.handleRequest(GetDevicesRequest.METHOD, call -> this.taskWorker.handleGetDevicesRequest(call.getRequest())); } } \ No newline at end of file diff --git a/io.openems.edge.common/src/io/openems/edge/common/component/ComponentManager.java b/io.openems.edge.common/src/io/openems/edge/common/component/ComponentManager.java index f026cf8d3fd..ea444764b63 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/component/ComponentManager.java +++ b/io.openems.edge.common/src/io/openems/edge/common/component/ComponentManager.java @@ -7,18 +7,21 @@ import io.openems.common.channel.Level; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.jsonrpc.request.CreateComponentConfigRequest; +import io.openems.common.jsonrpc.request.DeleteComponentConfigRequest; +import io.openems.common.jsonrpc.request.UpdateComponentConfigRequest; import io.openems.common.types.ChannelAddress; import io.openems.common.types.EdgeConfig; import io.openems.edge.common.channel.Channel; import io.openems.edge.common.channel.Doc; import io.openems.edge.common.channel.StateChannel; import io.openems.edge.common.channel.value.Value; -import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.user.User; /** * A Service that provides access to OpenEMS-Components. */ -public interface ComponentManager extends OpenemsComponent, JsonApi, ClockProvider { +public interface ComponentManager extends OpenemsComponent, ClockProvider { public static final String SINGLETON_SERVICE_PID = "Core.ComponentManager"; public static final String SINGLETON_COMPONENT_ID = "_componentManager"; @@ -274,4 +277,34 @@ public default > T getChannel(ChannelAddress channelAddress */ public EdgeConfig getEdgeConfig(); + /** + * Handles a {@link CreateComponentConfigRequest}. + * + * @param user the user + * @param request the {@link CreateComponentConfigRequest} + * @throws OpenemsNamedException on error + */ + public void handleCreateComponentConfigRequest(User user, CreateComponentConfigRequest request) + throws OpenemsNamedException; + + /** + * Handles a {@link UpdateComponentConfigRequest}. + * + * @param user the user + * @param request the {@link UpdateComponentConfigRequest} + * @throws OpenemsNamedException on error + */ + public void handleUpdateComponentConfigRequest(User user, UpdateComponentConfigRequest request) + throws OpenemsNamedException; + + /** + * Handles a {@link DeleteComponentConfigRequest}. + * + * @param user the user + * @param request the {@link DeleteComponentConfigRequest} + * @throws OpenemsNamedException on error + */ + public void handleDeleteComponentConfigRequest(User user, DeleteComponentConfigRequest request) + throws OpenemsNamedException; + } \ No newline at end of file diff --git a/io.openems.edge.common/src/io/openems/edge/common/host/DummyHost.java b/io.openems.edge.common/src/io/openems/edge/common/host/DummyHost.java index 845c1dd479d..18378ccece7 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/host/DummyHost.java +++ b/io.openems.edge.common/src/io/openems/edge/common/host/DummyHost.java @@ -1,14 +1,8 @@ package io.openems.edge.common.host; -import java.util.concurrent.CompletableFuture; - -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.jsonrpc.base.JsonrpcRequest; -import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.test.AbstractDummyOpenemsComponent; import io.openems.edge.common.test.TestUtils; -import io.openems.edge.common.user.User; /** * Simulates a {@link Host} for the OpenEMS Component test framework. @@ -37,10 +31,4 @@ public DummyHost withHostname(String value) { return this; } - @Override - public CompletableFuture handleJsonrpcRequest(User user, JsonrpcRequest request) - throws OpenemsNamedException { - return null; - } - } \ No newline at end of file diff --git a/io.openems.edge.common/src/io/openems/edge/common/host/Host.java b/io.openems.edge.common/src/io/openems/edge/common/host/Host.java index da15ab467dc..27366c7d401 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/host/Host.java +++ b/io.openems.edge.common/src/io/openems/edge/common/host/Host.java @@ -7,9 +7,8 @@ import io.openems.edge.common.channel.StringReadChannel; import io.openems.edge.common.channel.value.Value; import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.common.jsonapi.JsonApi; -public interface Host extends OpenemsComponent, JsonApi { +public interface Host extends OpenemsComponent { public static final String SINGLETON_SERVICE_PID = "Core.Host"; public static final String SINGLETON_COMPONENT_ID = "_host"; diff --git a/io.openems.edge.common/src/io/openems/edge/common/jsonapi/Call.java b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/Call.java new file mode 100644 index 00000000000..f64376644a0 --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/Call.java @@ -0,0 +1,102 @@ +package io.openems.edge.common.jsonapi; + +import java.util.Map; +import java.util.TreeMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Call { + + private final Logger log = LoggerFactory.getLogger(Call.class); + + private final REQUEST request; + private RESPONSE response; + private Map properties; + + private Call(REQUEST request, Map properties) { + super(); + this.request = request; + this.properties = properties; + } + + public Call(REQUEST request) { + this(request, new TreeMap<>()); + } + + public void setResponse(RESPONSE response) { + if (this.response != null) { + this.log.info("Request[" + this.request + "] was already fulfilled!"); + } + this.response = response; + } + + /** + * Gets the value to which the specific key is mapped, or null if this map + * contains no mapping for the key. + * + *

+ * The properties may contain special information about the current {@link Call} + * e. g. which user did trigger this call. + * + * @param the type of value + * @param key the key whose associated value is to be returned + * @return the value to which the specified key is mapped, or null if this map + * contains no mapping for the key + * @see Call#put(Key, Object) + */ + @SuppressWarnings("unchecked") + public T get(Key key) { + return (T) this.properties.get(key.identifier()); + } + + /** + * Associates the specified value with the specified key in this map. If the map + * previously contained a mapping for the key, the old value is replaced by the + * specified value. + * + *

+ * With this values can be associated to the current call e. g. the user who + * triggered this call. + * + * @param the type of the value + * @param key key with which the specified value is to be associated + * @param value value to be associated with the specified key + */ + public void put(Key key, T value) { + this.properties.put(key.identifier(), value); + } + + /** + * Creates a new {@link Call} with the given request and applies all properties + * to the new {@link Call}. + * + * @param the type of the new request + * @param request the new request + * @return the new {@link Call} + */ + public Call mapRequest(REQ request) { + return new Call<>(request, this.properties); + } + + /** + * Creates a new {@link Call} with the type of the response mapped to a new + * type. The current request and the properties are applied to the new + * {@link Call}. + * + * @param the new type of the response + * @return the new {@link Call} + */ + public Call mapResponse() { + return new Call<>(this.request, this.properties); + } + + public REQUEST getRequest() { + return this.request; + } + + public RESPONSE getResponse() { + return this.response; + } + +} \ No newline at end of file diff --git a/io.openems.edge.common/src/io/openems/edge/common/jsonapi/ComponentJsonApi.java b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/ComponentJsonApi.java new file mode 100644 index 00000000000..e12c09553fa --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/ComponentJsonApi.java @@ -0,0 +1,12 @@ +package io.openems.edge.common.jsonapi; + +public interface ComponentJsonApi extends JsonApi { + + /** + * Returns a unique ID for this OpenEMS component. + * + * @return the unique ID + */ + public String id(); + +} diff --git a/io.openems.edge.common/src/io/openems/edge/common/jsonapi/EdgeGuards.java b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/EdgeGuards.java new file mode 100644 index 00000000000..43ce40ec96d --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/EdgeGuards.java @@ -0,0 +1,46 @@ +package io.openems.edge.common.jsonapi; + +import io.openems.common.session.Role; +import io.openems.edge.common.user.User; + +public final class EdgeGuards { + + /** + * Creates a {@link JsonrpcEndpointGuard} which checks if the {@link Role} of + * the current {@link User} is atleast the given {@link Role}. + * + * @param role the role which the user should atleast have + * @return the created {@link JsonrpcEndpointGuard} + */ + public static JsonrpcEndpointGuard roleIsAtleast(Role role) { + return new JsonrpcRoleEndpointGuard(role); + } + + /** + * Creates a {@link JsonrpcEndpointGuard} which checks if the request is NOT + * from the backend and if so checks if the {@link Role} of the current + * {@link User} is atleast the given {@link Role}. + * + * @param role the role which the user should atleast have + * @return the created {@link JsonrpcEndpointGuard} + */ + public static JsonrpcEndpointGuard roleIsAtleastNotFromBackend(Role role) { + return new JsonrpcBackendRoleEndpointGuard(role, false); + } + + /** + * Creates a {@link JsonrpcEndpointGuard} which checks if the request is from + * the backend and if so checks if the {@link Role} of the current {@link User} + * is atleast the given {@link Role}. + * + * @param role the role which the user should atleast have + * @return the created {@link JsonrpcEndpointGuard} + */ + public static JsonrpcEndpointGuard roleIsAtleastFromBackend(Role role) { + return new JsonrpcBackendRoleEndpointGuard(role, true); + } + + private EdgeGuards() { + } + +} diff --git a/io.openems.edge.common/src/io/openems/edge/common/jsonapi/EdgeKeys.java b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/EdgeKeys.java new file mode 100644 index 00000000000..cbfb6ef940d --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/EdgeKeys.java @@ -0,0 +1,14 @@ +package io.openems.edge.common.jsonapi; + +import io.openems.edge.common.user.User; + +public final class EdgeKeys { + + public static final Key USER_KEY = new Key<>("user", User.class); + + public static final Key IS_FROM_BACKEND_KEY = new Key<>("isFromBackend", Boolean.class); + + private EdgeKeys() { + } + +} diff --git a/io.openems.edge.common/src/io/openems/edge/common/jsonapi/EndpointDefinitionBuilder.java b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/EndpointDefinitionBuilder.java new file mode 100644 index 00000000000..e1072f534a0 --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/EndpointDefinitionBuilder.java @@ -0,0 +1,133 @@ +package io.openems.edge.common.jsonapi; + +import static java.util.Collections.emptyList; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +import io.openems.common.jsonrpc.serialization.JsonSerializer; + +public final class EndpointDefinitionBuilder { + private final EndpointRequestDefinitionBuilder endpointRequestBuilder = new EndpointRequestDefinitionBuilder<>(); + private final EndpointResponseDefinitionBuilder endpointResponseBuilder = new EndpointResponseDefinitionBuilder<>(); + private final List tags = new ArrayList<>(); + private String description; + private List guards = emptyList(); + + /** + * Sets the description for the current endpoint. + * + * @param description the description of the endpoint + * @return this + */ + public EndpointDefinitionBuilder setDescription(String description) { + this.description = description; + return this; + } + + /** + * Sets the {@link JsonrpcEndpointGuard JsonrpcEndpointGuards} for the current + * endpoint. + * + * @param guards the {@link JsonrpcEndpointGuard JsonrpcEndpointGuards} of the + * endpoint + * @return this + */ + public EndpointDefinitionBuilder setGuards(JsonrpcEndpointGuard... guards) { + this.guards = List.of(guards); + return this; + } + + /** + * Sets the {@link JsonSerializer} of the request. + * + * @param serializer the request {@link JsonSerializer} + * @return this + */ + public EndpointDefinitionBuilder setRequestSerializer(// + JsonSerializer serializer // + ) { + this.endpointRequestBuilder.setSerializer(serializer); + return this; + } + + /** + * Applies the request builder configuration of the consumer to the current + * request definition. + * + * @param builder the builder consumer + * @return this + */ + public EndpointDefinitionBuilder applyRequestBuilder(// + Consumer> builder // + ) { + builder.accept(this.endpointRequestBuilder); + return this; + } + + /** + * Sets the {@link JsonSerializer} of the request and applies the request + * builder configuration of the consumer to the current request definition. + * + * @param serializer the request {@link JsonSerializer} + * @param builder the builder consumer + * @return this + */ + public EndpointDefinitionBuilder applyRequestBuilderWithSerializer(// + JsonSerializer serializer, // + Consumer> builder // + ) { + this.setRequestSerializer(serializer); + this.applyRequestBuilder(builder); + return this; + } + + /** + * Sets the {@link JsonSerializer} of the response. + * + * @param serializer the response {@link JsonSerializer} + * @return this + */ + public EndpointDefinitionBuilder setResponseSerializer(// + JsonSerializer serializer // + ) { + this.endpointResponseBuilder.setSerializer(serializer); + return this; + } + + /** + * Applies the response builder configuration of the consumer to the current + * response definition. + * + * @param builder the builder consumer + * @return this + */ + public EndpointDefinitionBuilder applyResponseBuilder(// + Consumer> builder // + ) { + builder.accept(this.endpointResponseBuilder); + return this; + } + + public String getDescription() { + return this.description; + } + + public List getGuards() { + return this.guards; + } + + public EndpointRequestDefinitionBuilder getEndpointRequestBuilder() { + return this.endpointRequestBuilder; + } + + public EndpointResponseDefinitionBuilder getEndpointResponseBuilder() { + return this.endpointResponseBuilder; + } + + public List getTags() { + return this.tags; + } + +} \ No newline at end of file diff --git a/io.openems.edge.common/src/io/openems/edge/common/jsonapi/EndpointRequestDefinitionBuilder.java b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/EndpointRequestDefinitionBuilder.java new file mode 100644 index 00000000000..cde58c31b0b --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/EndpointRequestDefinitionBuilder.java @@ -0,0 +1,78 @@ +package io.openems.edge.common.jsonapi; + +import static io.openems.common.utils.JsonUtils.toJsonArray; + +import java.util.ArrayList; +import java.util.List; + +import com.google.gson.JsonArray; + +import io.openems.common.jsonrpc.serialization.JsonSerializer; +import io.openems.common.utils.JsonUtils; + +public final class EndpointRequestDefinitionBuilder { + + private JsonSerializer serializer; + private final List> examples = new ArrayList<>(); + + /** + * Sets the {@link JsonSerializer} of the request. + * + * @param serializer the request {@link JsonSerializer} + * @return this + */ + public EndpointRequestDefinitionBuilder setSerializer(// + JsonSerializer serializer // + ) { + this.serializer = serializer; + return this; + } + + /** + * Adds an example object to the current request definition associated to the + * given name. + * + * @param name the name of the example + * @param request the example object + * @return this + */ + public EndpointRequestDefinitionBuilder addExample(String name, REQUEST request) { + this.examples.add(new Example<>(name, request)); + return this; + } + + /** + * Adds an example object to the current request definition. + * + * @param request the example object + * @return this + */ + public EndpointRequestDefinitionBuilder addExample(REQUEST request) { + this.examples.add(new Example<>("<" + this.examples.size() + ">", request)); + return this; + } + + public JsonSerializer getSerializer() { + return this.serializer; + } + + public List> getExamples() { + return this.examples; + } + + /** + * Creates a {@link JsonArray} from the examples of the current request + * definition. + * + * @return the {@link JsonArray} with the examples + */ + public JsonArray createExampleArray() { + return this.examples.stream() // + .map(t -> JsonUtils.buildJsonObject() // + .addProperty("key", t.identifier()) // + .add("value", this.serializer.serialize(t.exampleObject())) // + .build()) // + .collect(toJsonArray()); + } + +} \ No newline at end of file diff --git a/io.openems.edge.common/src/io/openems/edge/common/jsonapi/EndpointRequestType.java b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/EndpointRequestType.java new file mode 100644 index 00000000000..21b1085395a --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/EndpointRequestType.java @@ -0,0 +1,30 @@ +package io.openems.edge.common.jsonapi; + +import io.openems.common.jsonrpc.serialization.JsonSerializer; + +public interface EndpointRequestType { + + /** + * Gets the name of the request method. + * + * @return the method name + */ + public abstract String getMethod(); + + /** + * Gets the {@link JsonSerializer} for the request. Used to convert the received + * json into a java object. + * + * @return the request {@link JsonSerializer} + */ + public abstract JsonSerializer getRequestSerializer(); + + /** + * Gets the {@link JsonSerializer} for the response. Used to convert the + * response java object into a json string. + * + * @return the response {@link JsonSerializer} + */ + public abstract JsonSerializer getResponseSerializer(); + +} \ No newline at end of file diff --git a/io.openems.edge.common/src/io/openems/edge/common/jsonapi/EndpointResponseDefinitionBuilder.java b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/EndpointResponseDefinitionBuilder.java new file mode 100644 index 00000000000..fc5a03a3389 --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/EndpointResponseDefinitionBuilder.java @@ -0,0 +1,83 @@ +package io.openems.edge.common.jsonapi; + +import static io.openems.common.utils.JsonUtils.toJsonArray; + +import java.util.ArrayList; +import java.util.List; + +import com.google.gson.JsonArray; + +import io.openems.common.jsonrpc.serialization.JsonSerializer; +import io.openems.common.utils.JsonUtils; + +public final class EndpointResponseDefinitionBuilder { + + private JsonSerializer serializer; + private final List> examples = new ArrayList<>(); + + /** + * Sets the {@link JsonSerializer} of the response. + * + * @param serializer the response {@link JsonSerializer} + * @return this + */ + public EndpointResponseDefinitionBuilder setSerializer(// + JsonSerializer serializer // + ) { + this.serializer = serializer; + return this; + } + + /** + * Adds an example object to the current response definition associated to the + * given name. + * + * @param name the name of the example + * @param response the example object + * @return this + */ + public EndpointResponseDefinitionBuilder addExample(// + String name, // + RESPONSE response // + ) { + this.examples.add(new Example<>(name, response)); + return this; + } + + /** + * Adds an example object to the current request definition. + * + * @param response the example object + * @return this + */ + public EndpointResponseDefinitionBuilder addExample(// + RESPONSE response // + ) { + this.examples.add(new Example<>("<" + this.examples.size() + ">", response)); + return this; + } + + public JsonSerializer getSerializer() { + return this.serializer; + } + + public List> getExamples() { + return this.examples; + } + + /** + * Creates a {@link JsonArray} from the examples of the current request + * definition. + * + * @return the {@link JsonArray} with the examples + */ + public JsonArray createExampleArray() { + return this.examples.stream() // + .map(t -> JsonUtils.buildJsonObject() // + .addProperty("key", t.identifier()) // + .add("value", this.serializer.serialize(t.exampleObject())) // + .build()) // + .collect(toJsonArray()); + } + +} \ No newline at end of file diff --git a/io.openems.edge.common/src/io/openems/edge/common/jsonapi/Example.java b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/Example.java new file mode 100644 index 00000000000..9ea4f2bd7bc --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/Example.java @@ -0,0 +1,5 @@ +package io.openems.edge.common.jsonapi; + +public record Example(String identifier, T exampleObject) { + +} \ No newline at end of file diff --git a/io.openems.edge.common/src/io/openems/edge/common/jsonapi/JsonApi.java b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/JsonApi.java index 370dbae51d9..1b78a9b7ba5 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/jsonapi/JsonApi.java +++ b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/JsonApi.java @@ -1,27 +1,27 @@ package io.openems.edge.common.jsonapi; -import java.util.concurrent.CompletableFuture; - -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.jsonrpc.base.JsonrpcRequest; -import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; -import io.openems.edge.common.user.User; - /** * Declares a class as being able to handle JSON-RPC Requests. */ public interface JsonApi { /** - * Handles a JSON-RPC Request. - * - * @param user the authenticated {@link User} - * @param request the JSON-RPC Request - * @return a Future JSON-RPC Success Response; null response results in a - * OpenemsError.JSONRPC_UNHANDLED_METHOD - * @throws OpenemsNamedException on error + * Specifies routes of the current component in the given builder. + * + *

+ * Example:
+ * + *

+	 * {@code @Override}
+	 * public void buildJsonApiRoutes(JsonApiBuilder builder) {
+	 *     builder.rpc("METHOD_NAME", call -> {
+	 *        // handle call...
+	 *     });
+	 * }
+	 * 
+ * + * @param builder the builder to add the routes */ - public CompletableFuture handleJsonrpcRequest(User user, JsonrpcRequest request) - throws OpenemsNamedException; + public void buildJsonApiRoutes(JsonApiBuilder builder); -} +} \ No newline at end of file diff --git a/io.openems.edge.common/src/io/openems/edge/common/jsonapi/JsonApiBuilder.java b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/JsonApiBuilder.java new file mode 100644 index 00000000000..e1c1cae8031 --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/JsonApiBuilder.java @@ -0,0 +1,609 @@ +package io.openems.edge.common.jsonapi; + +import static java.util.stream.Collectors.joining; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.IntStream; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableMap; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingConsumer; +import io.openems.common.function.ThrowingFunction; +import io.openems.common.jsonrpc.base.GenericJsonrpcResponseSuccess; +import io.openems.common.jsonrpc.base.JsonrpcRequest; +import io.openems.common.jsonrpc.base.JsonrpcResponse; +import io.openems.common.jsonrpc.base.JsonrpcResponseError; +import io.openems.common.jsonrpc.serialization.JsonSerializer; +import io.openems.common.utils.FunctionUtils; + +/** + * TODO route interceptor/observer/notifications. + */ +public class JsonApiBuilder { + + private final Logger log = LoggerFactory.getLogger(JsonApiBuilder.class); + + private boolean debug = false; + + private final Map endpoints = new TreeMap<>(); + + private final List builder = new ArrayList<>(); + private final List> endpointAddedListeners = new ArrayList<>(); + private final List> endpointRemovedListeners = new ArrayList<>(); + + private final Consumer endpointAddedListener = e -> { + this.endpoints.put(e.getMethod(), e); + }; + + private final Consumer endpointRemovedListener = e -> { + this.endpoints.remove(e.getMethod()); + }; + + /** + * Adds a rpc request handler to the current builder. + * + * @param method the method of the handled rpc request + * @param handler the handler of the request + * @return this + */ + public JsonApiBuilder handleRequest(// + final String method, // + final ThrowingFunction, JsonrpcResponse, Exception> handler // + ) { + return this.rpc(method, call -> { + call.setResponse(handler.apply(call)); + }); + } + + /** + * Adds a rpc request handler to the current builder. + * + * @param method the method of the handled rpc request + * @param defBuilder the builder for the {@link EndpointDefinitionBuilder} + * @param handler the handler of the request + * @return this + */ + public JsonApiBuilder handleRequest(// + final String method, // + final Consumer> defBuilder, // + final ThrowingFunction, JsonrpcResponse, Exception> handler // + ) { + return this.rpc(method, defBuilder, call -> { + call.setResponse(handler.apply(call)); + }); + } + + /** + * Adds a rpc request handler to the current builder. + * + * @param the type of the request + * @param the type of the response + * @param endpointType the {@link EndpointRequestType} of the handled rpc + * request + * @param defBuilder the builder for the {@link EndpointDefinitionBuilder} + * @param handler the handler of the request + * @return this + */ + public JsonApiBuilder handleRequest(// + final EndpointRequestType endpointType, // + final Consumer> defBuilder, // + final ThrowingFunction, RESPONSE, Exception> handler // + ) { + return this.rpc(endpointType.getMethod(), defBuilder, call -> { + call.setResponse(handler.apply(call)); + }, endpointType.getRequestSerializer(), endpointType.getResponseSerializer()); + } + + /** + * Adds a rpc handler to the current builder. + * + * @param method the method of the handled rpc request + * @param handler the handler of the request + * @return this + */ + public JsonApiBuilder rpc(// + final String method, // + final ThrowingConsumer, Exception> handler // + ) { + this.addEndpoint(new JsonApiEndpoint(method, (b, call) -> { + try { + handler.accept(call); + } catch (Exception e) { + call.setResponse(this.handleException(call, e)); + } + })); + return this; + } + + /** + * Adds a rpc handler to the current builder. + * + * @param method the method of the handled rpc request + * @param defBuilder the builder for the {@link EndpointDefinitionBuilder} + * @param handler the handler of the request + * @return this + */ + public JsonApiBuilder rpc(// + final String method, // + final Consumer> defBuilder, // + final ThrowingConsumer, Exception> handler // + ) { + final var endpointDef = new EndpointDefinitionBuilder(); + defBuilder.accept(endpointDef); + this.addEndpoint(new JsonApiEndpoint(method, (b, call) -> { + try { + for (var guard : endpointDef.getGuards()) { + guard.test(call); + } + handler.accept(call); + } catch (Exception e) { + call.setResponse(this.handleException(call, e)); + } + }, endpointDef)); + return this; + } + + /** + * Adds a rpc handler to the current builder. + * + * @param the type of the request + * @param the type of the response + * @param method the method of the handled rpc request + * @param defBuilder the builder for the + * {@link EndpointDefinitionBuilder} + * @param handler the handler of the request + * @param requestSerializer the {@link JsonSerializer} of the request + * @param responseSerializer the {@link JsonSerializer} of the response + * @return this + */ + public JsonApiBuilder rpc(// + final String method, // + final Consumer> defBuilder, // + final ThrowingConsumer, Exception> handler, // + final JsonSerializer requestSerializer, // + final JsonSerializer responseSerializer // + ) { + final var endpointDef = new EndpointDefinitionBuilder(); + endpointDef.setRequestSerializer(requestSerializer); + endpointDef.setResponseSerializer(responseSerializer); + defBuilder.accept(endpointDef); + + this.addEndpoint(new JsonApiEndpoint(method, (b, t) -> { + for (var guard : endpointDef.getGuards()) { + try { + guard.test(t); + } catch (Exception e) { + t.setResponse(this.handleException(t, e)); + return; + } + } + try { + final var mappedCall = t.mapRequest(requestSerializer.deserialize(t.getRequest().getParams())) // + .mapResponse(); + + handler.accept(mappedCall); + + t.setResponse(new GenericJsonrpcResponseSuccess(t.getRequest().getId(), + responseSerializer.serialize(mappedCall.getResponse()).getAsJsonObject())); + } catch (Exception e) { + t.setResponse(this.handleException(t, e)); + } + }, endpointDef)); + return this; + } + + /** + * Adds a rpc handler to the current builder. + * + * @param the type of the request + * @param method the method of the handled rpc request + * @param defBuilder the builder for the {@link EndpointDefinitionBuilder} + * @param subroutes the subroutes which can be reached with this handler + * @param handler the handler of the request + * @param serializer the {@link JsonSerializer} of the request + * @return this + */ + public JsonApiBuilder rpc(// + final String method, // + final Consumer> defBuilder, // + final Supplier> subroutes, // + final ThrowingConsumer, Exception> handler, // + final JsonSerializer serializer // + ) { + final var endpointDef = new EndpointDefinitionBuilder(); + endpointDef.setRequestSerializer(serializer); + defBuilder.accept(endpointDef); + + this.addEndpoint(new JsonApiEndpoint(method, (b, t) -> { + try { + for (var guard : endpointDef.getGuards()) { + guard.test(t); + } + + var call = t.mapRequest(serializer.deserialize(t.getRequest().getParams())); + handler.accept(call); + if (call.getResponse() != null) { + t.setResponse(call.getResponse()); + } + } catch (Exception e) { + t.setResponse(this.handleException(t, e)); + } + }, endpointDef, subroutes)); + return this; + } + + /** + * Adds a rpc handler to the current builder. + * + * @param method the method of the handled rpc request + * @param defBuilder the builder for the {@link EndpointDefinitionBuilder} + * @param subroutes the subroutes which can be reached with this handler + * @param handler the handler of the request + * @return this + */ + public JsonApiBuilder rpc(// + final String method, // + final Consumer> defBuilder, // + final Supplier> subroutes, // + final ThrowingConsumer, Exception> handler // + ) { + final var endpointDef = new EndpointDefinitionBuilder(); + defBuilder.accept(endpointDef); + + this.addEndpoint(new JsonApiEndpoint(method, (b, t) -> { + try { + for (var guard : endpointDef.getGuards()) { + guard.test(t); + } + + handler.accept(t); + } catch (Exception e) { + t.setResponse(this.handleException(t, e)); + } + }, endpointDef, subroutes)); + return this; + } + + /** + * Delegates the handled request to another endpoint. + * + * @param method the method of the handled rpc request + * @param defBuilder the builder for the {@link EndpointDefinitionBuilder} + * @param handler the handler of the request which returns the delegated + * request + * @param builder the path to the builder which handles the delegated + * request + * @param responseMapper the mapper of the response + * @param subroutes the subroutes which can be reached with this handler + * @return this + */ + public JsonApiBuilder delegate(// + final String method, // + final Consumer> defBuilder, // + final ThrowingFunction, JsonrpcRequest, Exception> handler, // + final Function builder, // + final Function responseMapper, // + final Supplier> subroutes // + ) { + final var endpointDef = new EndpointDefinitionBuilder(); + defBuilder.accept(endpointDef); + this.addEndpoint(new JsonApiEndpoint(method, (b, t) -> { + try { + final var call = t.mapRequest(handler.apply(t)); + builder.apply(b).handle(call); + if (call.getResponse() != null) { + t.setResponse(responseMapper.apply(call.getResponse())); + } + } catch (Exception e) { + this.handleException(t, e); + } + }, endpointDef, subroutes)); + return this; + } + + /** + * Delegates the handled request to another endpoint. + * + * @param method the method of the handled rpc request + * @param handler the handler of the request which returns the delegated + * request + * @param builder the path to the builder which handles the delegated request + * @param subroutes the subroutes which can be reached with this handler + * @return this + */ + public JsonApiBuilder delegate(// + final String method, // + final ThrowingFunction, JsonrpcRequest, Exception> handler, // + final Function builder, // + final Supplier> subroutes // + ) { + return this.delegate(method, FunctionUtils::doNothing, handler, builder, Function.identity(), subroutes); + } + + /** + * Delegates the handled request to another endpoint. + * + * @param method the method of the handled rpc request + * @param defBuilder the builder for the {@link EndpointDefinitionBuilder} + * @param handler the handler of the request which returns the delegated + * request + * @param builder the path to the builder which handles the delegated request + * @return this + */ + public JsonApiBuilder delegate(// + final String method, // + final Consumer> defBuilder, // + final ThrowingFunction, JsonrpcRequest, Exception> handler, // + final Function builder // + ) { + return this.delegate(method, defBuilder, handler, builder, Function.identity(), null); + } + + /** + * Delegates the handled request to another endpoint. + * + * @param method the method of the handled rpc request + * @param handler the handler of the request which returns the delegated request + * @param builder the path to the builder which handles the delegated request + * @return this + */ + public JsonApiBuilder delegate(// + final String method, // + final ThrowingFunction, JsonrpcRequest, Exception> handler, // + final Function builder // + ) { + return this.delegate(method, FunctionUtils::doNothing, handler, builder, Function.identity(), null); + } + + /** + * Delegates the handled request to another endpoint. + * + * @param method the method of the handled rpc request + * @param defBuilder the builder for the {@link EndpointDefinitionBuilder} + * @param handler the handler of the request which returns the delegated + * request + * @return this + */ + public JsonApiBuilder delegate(// + final String method, // + final Consumer> defBuilder, // + final ThrowingFunction, JsonrpcRequest, Exception> handler // + ) { + return this.delegate(method, defBuilder, handler, Function.identity()); + } + + /** + * Delegates the handled request to another endpoint. + * + * @param method the method of the handled rpc request + * @param handler the handler of the request which returns the delegated request + * @return this + */ + public JsonApiBuilder delegate(// + final String method, // + final ThrowingFunction, JsonrpcRequest, Exception> handler // + ) { + return this.delegate(method, FunctionUtils::doNothing, handler, Function.identity()); + } + + private void addEndpoint(JsonApiEndpoint endpoint) { + synchronized (this.endpoints) { + final var previous = this.endpoints.put(endpoint.getMethod(), endpoint); + if (previous != null) { + this.endpointRemovedListeners.forEach(t -> t.accept(previous)); + this.log.error("Duplicated endpoint defined for method '" + endpoint.getMethod() + + "'. Override with last defined endpoint"); + } + this.endpointAddedListeners.forEach(t -> t.accept(endpoint)); + + if (this.isDebug()) { + this.log.info("Added handler for method '" + endpoint.getMethod() + "'"); + } + } + } + + /** + * Removes an endpoint by its method. + * + * @param method the method of the endpoint to remove + * @return the endpoint which got removed or null if no endpoint with this + * method exists + */ + public JsonApiEndpoint removeEndpoint(String method) { + synchronized (this.endpoints) { + final var removedEndpoint = this.endpoints.remove(method); + if (removedEndpoint == null) { + return null; + } + this.endpointRemovedListeners.forEach(t -> t.accept(removedEndpoint)); + + if (this.isDebug()) { + this.log.info("Removed handler for method '" + method + "'"); + } + return removedEndpoint; + } + } + + /** + * Adds a {@link JsonApiBuilder} to the current builder. All methods are + * "copied" to this builder and available for both then. + * + * @param builder the {@link JsonApiBuilder} to add + * @see JsonApiBuilder#removeBuilder(JsonApiBuilder) + */ + public void addBuilder(JsonApiBuilder builder) { + synchronized (builder.endpoints) { + this.builder.add(builder); + builder.addEndpointAddedListener(this.endpointAddedListener); + builder.addEndpointRemovedListener(this.endpointRemovedListener); + builder.getEndpoints().forEach((t, u) -> this.addEndpoint(u)); + } + } + + /** + * Removes a {@link JsonApiBuilder} and all its methods from this builder. + * + * @param builder the {@link JsonApiBuilder} to remove + * @see JsonApiBuilder#addBuilder(JsonApiBuilder) + */ + public void removeBuilder(JsonApiBuilder builder) { + synchronized (builder.endpoints) { + this.builder.remove(builder); + builder.removeEndpointAddedListener(this.endpointAddedListener); + builder.removeEndpointRemovedListener(this.endpointRemovedListener); + builder.getEndpoints().forEach((t, u) -> this.removeEndpoint(t)); + } + } + + /** + * Adds a listener to call when a endpoint got added to the current builder. + * + * @param listener the listener to call when the event happened + */ + public void addEndpointAddedListener(Consumer listener) { + this.endpointAddedListeners.add(listener); + } + + /** + * Removes a listener which was subscribed to the endpoint added event. + * + * @param listener the listener to remove + */ + public void removeEndpointAddedListener(Consumer listener) { + this.endpointAddedListeners.remove(listener); + } + + /** + * Adds a listener to call when a endpoint got removed to the current builder. + * + * @param listener the listener to call when the event happened + */ + public void addEndpointRemovedListener(Consumer listener) { + this.endpointRemovedListeners.add(listener); + } + + /** + * Removes a listener which was subscribed to the endpoint removed event. + * + * @param listener the listener to remove + */ + public void removeEndpointRemovedListener(Consumer listener) { + this.endpointRemovedListeners.remove(listener); + } + + public Map getEndpoints() { + return ImmutableMap.copyOf(this.endpoints); + } + + public boolean isDebug() { + return this.debug; + } + + public void setDebug(boolean debug) { + this.debug = debug; + } + + /** + * Closes this builder. + * + *

+ * Removes all {@link JsonApiBuilder} from this builder. + */ + public void close() { + final var builderToRemove = new ArrayList<>(this.builder); + builderToRemove.forEach(this::removeBuilder); + } + + private JsonrpcResponseError handleException(Call call, Throwable t) { + if (this.isDebug()) { + this.log.error(t.getMessage(), t); + } + + // Get JSON-RPC Response Error + if (t instanceof OpenemsNamedException ex) { + return new JsonrpcResponseError(call.getRequest().getId(), ex); + } else { + return new JsonrpcResponseError(call.getRequest().getId(), t.getMessage()); + } + } + + private static final Key DEPTH = new Key("depth", Integer.class); + @SuppressWarnings({ "unchecked", "rawtypes" }) + private static final Key> TRACE = (Key>) new Key("trace", List.class); + + private static record JsonHandlerTrace(// + String method, // + boolean exists // + ) { + + } + + /** + * Handles a {@link Call}. + * + *

+ * A {@link Call} is usually created and passed to a builder when a request from + * an user is called in the UI or via code directly (BackendController, + * WebsocketController, RestApi, ...). + * + * @param call the call to handle + */ + public void handle(Call call) { + var depth = call.get(DEPTH); + final var trace = call.get(TRACE) != null ? call.get(TRACE) : new ArrayList(); + this.handle(// + depth == null ? 0 : depth, // + trace, // + call // + ); + + if (depth != null) { + return; + } + + if (!this.isDebug()) { + return; + } + this.log.info("Debug info for Request " + call.getRequest().getId() + "" + System.lineSeparator() // + + IntStream.range(0, trace.size()) // + .mapToObj(i -> { + var t = trace.get(i); + return Strings.repeat(" ", i) + "\\ " + t.method() + (t.exists() ? "" : " (missing)"); + }).collect(joining(System.lineSeparator())) // + + System.lineSeparator() + Strings.repeat(" ", trace.size()) + " -> "// + + (call.getResponse() == null ? "Missing Response" : call.getResponse().toJsonObject())); + } + + private void handle(// + final int depth, // + final List trace, // + Call call // + ) { + final var endpoint = this.endpoints.get(call.getRequest().getMethod()); + trace.add(new JsonHandlerTrace(call.getRequest().getMethod(), endpoint != null)); + call.put(DEPTH, depth + 1); + call.put(TRACE, trace); + + if (endpoint == null) { + // TODO later for notifications there should not be a response + call.setResponse(new JsonrpcResponseError(call.getRequest().getId(), + "Endpoint with method \"" + call.getRequest().getMethod() + "\" is not defined!")); + return; + } + + // handle request + endpoint.handle(this, call); + } + +} \ No newline at end of file diff --git a/io.openems.edge.common/src/io/openems/edge/common/jsonapi/JsonApiEndpoint.java b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/JsonApiEndpoint.java new file mode 100644 index 00000000000..aa3307423e9 --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/JsonApiEndpoint.java @@ -0,0 +1,66 @@ +package io.openems.edge.common.jsonapi; + +import java.util.List; +import java.util.function.BiConsumer; +import java.util.function.Supplier; + +import io.openems.common.jsonrpc.base.JsonrpcRequest; +import io.openems.common.jsonrpc.base.JsonrpcResponse; + +public class JsonApiEndpoint { + private final String method; + private final BiConsumer> handler; + private final EndpointDefinitionBuilder def; + private final Supplier> subroutes; + + public JsonApiEndpoint(// + String method, // + BiConsumer> handler, // + EndpointDefinitionBuilder def, // + Supplier> subroutes // + ) { + super(); + this.method = method; + this.handler = handler; + this.def = def; + this.subroutes = subroutes; + } + + public JsonApiEndpoint(// + String method, // + BiConsumer> handler, // + EndpointDefinitionBuilder def // + ) { + this(method, handler, def, null); + } + + public JsonApiEndpoint(// + String method, // + BiConsumer> handler // + ) { + this(method, handler, new EndpointDefinitionBuilder()); + } + + public String getMethod() { + return this.method; + } + + public Supplier> getSubroutes() { + return this.subroutes; + } + + public EndpointDefinitionBuilder getDef() { + return this.def; + } + + /** + * Handles the call with the current endpoint handler. + * + * @param builder the current root {@link JsonApiBuilder} + * @param call the {@link Call} to handle + */ + public void handle(JsonApiBuilder builder, Call call) { + this.handler.accept(builder, call); + } + +} \ No newline at end of file diff --git a/io.openems.edge.common/src/io/openems/edge/common/jsonapi/JsonrpcBackendRoleEndpointGuard.java b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/JsonrpcBackendRoleEndpointGuard.java new file mode 100644 index 00000000000..dc13f85a541 --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/JsonrpcBackendRoleEndpointGuard.java @@ -0,0 +1,28 @@ +package io.openems.edge.common.jsonapi; + +import io.openems.common.jsonrpc.base.JsonrpcRequest; +import io.openems.common.jsonrpc.base.JsonrpcResponse; +import io.openems.common.session.Role; + +public final class JsonrpcBackendRoleEndpointGuard implements JsonrpcEndpointGuard { + + private final JsonrpcEndpointGuard roleGuard; + private final boolean checkIfBackend; + + public JsonrpcBackendRoleEndpointGuard(Role role, boolean checkIfBackend) { + this.roleGuard = EdgeGuards.roleIsAtleast(role); + this.checkIfBackend = checkIfBackend; + } + + @Override + public void test(Call call) throws Exception { + final var isFromBackend = call.get(EdgeKeys.IS_FROM_BACKEND_KEY); + + if ((isFromBackend != null && isFromBackend) != this.checkIfBackend) { + return; + } + + this.roleGuard.test(call); + } + +} \ No newline at end of file diff --git a/io.openems.edge.common/src/io/openems/edge/common/jsonapi/JsonrpcEndpointGuard.java b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/JsonrpcEndpointGuard.java new file mode 100644 index 00000000000..128a5d150da --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/JsonrpcEndpointGuard.java @@ -0,0 +1,17 @@ +package io.openems.edge.common.jsonapi; + +import io.openems.common.jsonrpc.base.JsonrpcRequest; +import io.openems.common.jsonrpc.base.JsonrpcResponse; + +public interface JsonrpcEndpointGuard { + + /** + * Checks if the current call fulfills the required check. If not an + * {@link Exception} gets thrown. + * + * @param call the call to check + * @throws Exception on error + */ + public void test(Call call) throws Exception; + +} \ No newline at end of file diff --git a/io.openems.edge.common/src/io/openems/edge/common/jsonapi/JsonrpcRoleEndpointGuard.java b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/JsonrpcRoleEndpointGuard.java new file mode 100644 index 00000000000..a21d6df0994 --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/JsonrpcRoleEndpointGuard.java @@ -0,0 +1,44 @@ +package io.openems.edge.common.jsonapi; + +import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.jsonObjectSerializer; + +import io.openems.common.jsonrpc.base.JsonrpcRequest; +import io.openems.common.jsonrpc.base.JsonrpcResponse; +import io.openems.common.jsonrpc.serialization.JsonSerializer; +import io.openems.common.session.Role; +import io.openems.common.utils.JsonUtils; + +public final class JsonrpcRoleEndpointGuard implements JsonrpcEndpointGuard { + + private final Role role; + + public JsonrpcRoleEndpointGuard(Role role) { + this.role = role; + } + + @Override + public void test(Call call) throws Exception { + call.get(EdgeKeys.USER_KEY).getRole().assertIsAtLeast(call.getRequest().getMethod(), this.role); + } + + public Role getRole() { + return this.role; + } + + /** + * Returns a {@link JsonSerializer} for a {@link JsonrpcRoleEndpointGuard}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(JsonrpcRoleEndpointGuard.class, + t -> new JsonrpcRoleEndpointGuard(Role.getRole(t.getStringPath("role") // + .get())), + t -> JsonUtils.buildJsonObject() // + .addProperty("name", "role") // + .addProperty("description", "User-Role has to be at least " + t.getRole()) // + .addProperty("role", t.getRole()) // + .build()); + } + +} \ No newline at end of file diff --git a/io.openems.edge.common/src/io/openems/edge/common/jsonapi/Key.java b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/Key.java new file mode 100644 index 00000000000..1f3d4e877dc --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/Key.java @@ -0,0 +1,5 @@ +package io.openems.edge.common.jsonapi; + +public record Key(String identifier, Class type) { + +} \ No newline at end of file diff --git a/io.openems.edge.common/src/io/openems/edge/common/jsonapi/MultipleJsonApiBinder.java b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/MultipleJsonApiBinder.java new file mode 100644 index 00000000000..f051eaa18eb --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/MultipleJsonApiBinder.java @@ -0,0 +1,78 @@ +package io.openems.edge.common.jsonapi; + +import java.util.HashMap; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MultipleJsonApiBinder { + + private final Logger log = LoggerFactory.getLogger(MultipleJsonApiBinder.class); + + private final JsonApiBuilder jsonApiBuilder = new JsonApiBuilder(); + private final Map handler = new HashMap<>(); + + /** + * Binds the new handler and adds all its route paths. If the handler was + * already binded replaces the old {@link JsonApiBuilder} with a new one and + * logs a warning. + * + *

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

+	 * {@code @Reference}(//
+	 *      target = "(entry=" + ENTRY_POINT + ")", //
+	 *      policyOption = ReferencePolicyOption.GREEDY, //
+	 *      policy = ReferencePolicy.DYNAMIC, //
+	 *      cardinality = ReferenceCardinality.MULTIPLE //
+	 * )
+	 * protected void bindHandler(JsonApi2 handler) {
+	 *    this.binder.bindJsonApi(handler);
+	 * }
+	 * 
+ * + * @param handler the handler to bind + * @see MultipleJsonApiBinder#unbindJsonApi(JsonApi) + */ + public void bindJsonApi(JsonApi handler) { + final var newBuilder = new JsonApiBuilder(); + final var prevBuilder = this.handler.put(handler, newBuilder); + if (prevBuilder != null) { + this.log.warn("Builder for handler " + handler + " was already existing."); + } + handler.buildJsonApiRoutes(newBuilder); + this.jsonApiBuilder.addBuilder(newBuilder); + } + + /** + * Unbinds a handler and removes all its route paths. + * + *

+ * Commonly used like this with OSGi injection to unbind a {@link JsonApi}:
+ * + *

+	 * protected void unbindHandler(JsonApi2 handler) {
+	 * 	this.binder.unbindJsonApi(handler);
+	 * }
+	 * 
+ * + * @param handler the {@link JsonApi} to remove + * @see MultipleJsonApiBinder#bindJsonApi(JsonApi) + */ + public void unbindJsonApi(JsonApi handler) { + final var builder = this.handler.remove(handler); + if (builder == null) { + return; + } + builder.close(); + this.jsonApiBuilder.removeBuilder(builder); + } + + public JsonApiBuilder getJsonApiBuilder() { + return this.jsonApiBuilder; + } + +} diff --git a/io.openems.edge.common/src/io/openems/edge/common/jsonapi/SingleJsonApiBinder.java b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/SingleJsonApiBinder.java new file mode 100644 index 00000000000..e13e2838e9e --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/SingleJsonApiBinder.java @@ -0,0 +1,102 @@ +package io.openems.edge.common.jsonapi; + +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.exceptions.OpenemsException; +import io.openems.common.jsonrpc.base.GenericJsonrpcResponseSuccess; +import io.openems.common.jsonrpc.base.JsonrpcRequest; +import io.openems.common.jsonrpc.base.JsonrpcResponse; +import io.openems.common.jsonrpc.base.JsonrpcResponseError; +import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; +import io.openems.common.utils.FunctionUtils; + +public class SingleJsonApiBinder { + + private boolean debug = false; + + private JsonApi jsonApi; + private JsonApiBuilder builder; + + /** + * Binds the {@link JsonApi} as the current handler. + * + * @param jsonApi the {@link JsonApi} to bind + * @return the created {@link JsonApiBuilder} from the {@link JsonApi} + */ + public JsonApiBuilder bind(JsonApi jsonApi) { + this.jsonApi = jsonApi; + this.builder = new JsonApiBuilder(); + this.builder.setDebug(this.debug); + this.jsonApi.buildJsonApiRoutes(this.builder); + return this.builder; + } + + /** + * Unbinds the current active {@link JsonApi} and its created + * {@link JsonApiBuilder}. + */ + public void unbind() { + this.jsonApi = null; + this.builder.close(); + this.builder = null; + } + + /** + * Handles a {@link JsonrpcRequest}. + * + * @param request the request to handle + * @return the result future + * @throws OpenemsNamedException on error + */ + public CompletableFuture handleRequest(JsonrpcRequest request) + throws OpenemsNamedException { + return this.handleRequest(request, FunctionUtils::doNothing); + } + + /** + * Handles a {@link JsonrpcRequest}. + * + * @param request the request to handle + * @param callAction the action to execute before the call gets handle by an + * endpoint; can be used to provide additional call properties + * with {@link Call#put(Key, Object)} + * @return the result future + * @throws OpenemsNamedException on error + */ + public CompletableFuture handleRequest(// + JsonrpcRequest request, // + Consumer> callAction // + ) throws OpenemsNamedException { + final var builder = this.builder; + if (builder == null) { + throw new OpenemsException("Not ready"); + } + + final var call = new Call(request); + callAction.accept(call); + builder.handle(call); + + final var response = call.getResponse(); + if (response == null) { + throw new OpenemsException("No response"); + } + + if (response instanceof JsonrpcResponseSuccess success) { + return CompletableFuture + .completedFuture(new GenericJsonrpcResponseSuccess(request.getId(), success.getResult())); + } else if (response instanceof JsonrpcResponseError error) { + return CompletableFuture.failedFuture(error.getOpenemsError().exception(error.getParamsAsObjectArray())); + } + throw new OpenemsException("Unhandled response"); + } + + public void setDebug(boolean debug) { + this.debug = debug; + if (this.builder != null) { + this.builder.setDebug(debug); + } + } + +} diff --git a/io.openems.edge.common/src/io/openems/edge/common/jsonapi/Subrequest.java b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/Subrequest.java new file mode 100644 index 00000000000..8589d7af913 --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/Subrequest.java @@ -0,0 +1,40 @@ +package io.openems.edge.common.jsonapi; + +import java.util.ArrayList; +import java.util.List; + +import com.google.gson.JsonElement; + +public final class Subrequest { + + public record Subroute(String[] path, JsonApiBuilder builder) { + + } + + private final JsonElement baseRequest; + private final List subrouteToBuilder = new ArrayList<>(); + + public Subrequest(JsonElement baseRequest) { + this.baseRequest = baseRequest; + } + + /** + * Adds a {@link JsonApiBuilder} for the {@link Subrequest} associated to the + * provided path. + * + * @param builder the {@link JsonApiBuilder} to add at the path + * @param path the path which the builder gets associated to + */ + public void addRpcBuilderFor(JsonApiBuilder builder, String... path) { + this.subrouteToBuilder.add(new Subroute(path, builder)); + } + + public JsonElement getBaseRequest() { + return this.baseRequest; + } + + public List getSubrouteToBuilder() { + return this.subrouteToBuilder; + } + +} diff --git a/io.openems.edge.common/src/io/openems/edge/common/jsonapi/Tag.java b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/Tag.java new file mode 100644 index 00000000000..b52e88ef763 --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/Tag.java @@ -0,0 +1,27 @@ +package io.openems.edge.common.jsonapi; + +import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.jsonObjectSerializer; + +import io.openems.common.jsonrpc.serialization.JsonSerializer; +import io.openems.common.utils.JsonUtils; + +public record Tag(// + String name // +) { + + /** + * Returns a {@link JsonSerializer} for a {@link Tag}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(Tag.class, json -> { + return new Tag(json.getString("name")); + }, obj -> { + return JsonUtils.buildJsonObject() // + .addProperty("name", obj.name()) // + .build(); + }); + } + +} \ No newline at end of file diff --git a/io.openems.edge.common/src/io/openems/edge/common/test/DummyComponentManager.java b/io.openems.edge.common/src/io/openems/edge/common/test/DummyComponentManager.java index 1fee0432111..a3a43bbe07f 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/test/DummyComponentManager.java +++ b/io.openems.edge.common/src/io/openems/edge/common/test/DummyComponentManager.java @@ -7,7 +7,6 @@ import java.util.Collections; import java.util.Hashtable; import java.util.List; -import java.util.concurrent.CompletableFuture; import org.osgi.framework.InvalidSyntaxException; import org.osgi.service.cm.ConfigurationAdmin; @@ -20,25 +19,26 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; import io.openems.common.jsonrpc.base.GenericJsonrpcResponseSuccess; -import io.openems.common.jsonrpc.base.JsonrpcRequest; -import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; import io.openems.common.jsonrpc.request.CreateComponentConfigRequest; +import io.openems.common.jsonrpc.request.DeleteComponentConfigRequest; import io.openems.common.jsonrpc.request.GetEdgeConfigRequest; import io.openems.common.jsonrpc.request.UpdateComponentConfigRequest; import io.openems.common.jsonrpc.request.UpdateComponentConfigRequest.Property; import io.openems.common.jsonrpc.response.GetEdgeConfigResponse; -import io.openems.common.session.Role; import io.openems.common.types.EdgeConfig; import io.openems.common.utils.JsonUtils; import io.openems.edge.common.channel.Channel; import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.jsonapi.ComponentJsonApi; +import io.openems.edge.common.jsonapi.EdgeKeys; +import io.openems.edge.common.jsonapi.JsonApiBuilder; import io.openems.edge.common.user.User; /** * Simulates a ComponentManager for the OpenEMS Component test framework. */ -public class DummyComponentManager implements ComponentManager { +public class DummyComponentManager implements ComponentManager, ComponentJsonApi { private final List components = new ArrayList<>(); private final Clock clock; @@ -167,38 +167,29 @@ public Collection> channels() { } @Override - public CompletableFuture handleJsonrpcRequest(User user, JsonrpcRequest request) - throws OpenemsNamedException { - user.assertRoleIsAtLeast("handleJsonrpcRequest", Role.GUEST); + public void buildJsonApiRoutes(JsonApiBuilder builder) { + builder.handleRequest(GetEdgeConfigRequest.METHOD, call -> { + return new GetEdgeConfigResponse(call.getRequest().getId(), this.getEdgeConfig()); + }); - switch (request.getMethod()) { + builder.handleRequest(CreateComponentConfigRequest.METHOD, call -> { + final var request = CreateComponentConfigRequest.from(call.getRequest()); + this.handleCreateComponentConfigRequest(call.get(EdgeKeys.USER_KEY), request); - case GetEdgeConfigRequest.METHOD: - return this.handleGetEdgeConfigRequest(user, GetEdgeConfigRequest.from(request)); - case CreateComponentConfigRequest.METHOD: - return this.handleCreateComponentConfigRequest(user, CreateComponentConfigRequest.from(request)); - case UpdateComponentConfigRequest.METHOD: - return this.handleUpdateComponentConfigRequest(user, UpdateComponentConfigRequest.from(request)); + return new GenericJsonrpcResponseSuccess(request.getId()); + }); - default: - throw OpenemsError.JSONRPC_UNHANDLED_METHOD.exception(request.getMethod()); - } + builder.handleRequest(UpdateComponentConfigRequest.METHOD, call -> { + final var request = UpdateComponentConfigRequest.from(call.getRequest()); + this.handleUpdateComponentConfigRequest(call.get(EdgeKeys.USER_KEY), request); + + return new GenericJsonrpcResponseSuccess(request.getId()); + }); } - /** - * Handles a {@link CreateComponentConfigRequest}. - * - *

- * Only creates the Configuration with the given Properties. Does not actually - * add the component the the dummy component list. - * - * @param user the executing user - * @param request the {@link CreateComponentConfigRequest} - * @return the Future JSON-RPC Response - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleCreateComponentConfigRequest(User user, - CreateComponentConfigRequest request) throws OpenemsNamedException { + @Override + public void handleCreateComponentConfigRequest(User user, CreateComponentConfigRequest request) + throws OpenemsNamedException { if (this.configurationAdmin == null) { throw new OpenemsException("Can not create Component Config. ConfigurationAdmin is null!"); } @@ -218,27 +209,11 @@ private CompletableFuture handleCreateComponentConfigReq // TODO Auto-generated catch block e.printStackTrace(); } - - return CompletableFuture.completedFuture(new GenericJsonrpcResponseSuccess(request.getId())); - } - - /** - * Handles a {@link GetEdgeConfigRequest}. - * - * @param user the {@link User} - * @param request the {@link GetEdgeConfigRequest} - * @return the Future JSON-RPC Response - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleGetEdgeConfigRequest(User user, - GetEdgeConfigRequest request) throws OpenemsNamedException { - var config = this.getEdgeConfig(); - var response = new GetEdgeConfigResponse(request.getId(), config); - return CompletableFuture.completedFuture(response); } - private CompletableFuture handleUpdateComponentConfigRequest(User user, - UpdateComponentConfigRequest request) throws OpenemsNamedException { + @Override + public void handleUpdateComponentConfigRequest(User user, UpdateComponentConfigRequest request) + throws OpenemsNamedException { if (this.configurationAdmin == null) { throw new OpenemsException("Can not update Component Config. ConfigurationAdmin is null!"); } @@ -257,7 +232,29 @@ private CompletableFuture handleUpdateComponentConfigReq } configuration.update(properties); } - return CompletableFuture.completedFuture(new GenericJsonrpcResponseSuccess(request.getId())); + } catch (IOException | InvalidSyntaxException e) { + throw new OpenemsException("Can not update Component Config."); + } + } + + @Override + public void handleDeleteComponentConfigRequest(User user, DeleteComponentConfigRequest request) + throws OpenemsNamedException { + if (this.configurationAdmin == null) { + throw new OpenemsException("Can not delete Component Config. ConfigurationAdmin is null!"); + } + + try { + for (var configuration : this.configurationAdmin.listConfigurations(null)) { + final var props = configuration.getProperties(); + if (props == null) { + continue; + } + if (props.get("id") == null || !props.get("id").equals(request.getComponentId())) { + continue; + } + configuration.delete(); + } } catch (IOException | InvalidSyntaxException e) { throw new OpenemsException("Can not update Component Config."); } diff --git a/io.openems.edge.common/test/io/openems/edge/common/jsonapi/CallTest.java b/io.openems.edge.common/test/io/openems/edge/common/jsonapi/CallTest.java new file mode 100644 index 00000000000..56a1820b518 --- /dev/null +++ b/io.openems.edge.common/test/io/openems/edge/common/jsonapi/CallTest.java @@ -0,0 +1,81 @@ +package io.openems.edge.common.jsonapi; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import com.google.gson.JsonObject; + +import io.openems.common.jsonrpc.base.GenericJsonrpcRequest; +import io.openems.common.jsonrpc.base.GenericJsonrpcResponseSuccess; +import io.openems.common.jsonrpc.base.JsonrpcRequest; +import io.openems.common.jsonrpc.base.JsonrpcResponse; + +public class CallTest { + + @Test + public void testGetSetResponse() { + final var call = new Call( + new GenericJsonrpcRequest("method", new JsonObject())); + + final var exampleResponse = new GenericJsonrpcResponseSuccess(call.getRequest().getId()); + call.setResponse(exampleResponse); + + assertEquals(exampleResponse, call.getResponse()); + } + + @Test + public void testGetPutProperties() { + final var call = new Call( + new GenericJsonrpcRequest("method", new JsonObject())); + + final var dummyKey = new Key<>("dummy", String.class); + + final var dummyValue = "dummyValue"; + call.put(dummyKey, dummyValue); + assertEquals(dummyValue, call.get(dummyKey)); + } + + @Test + public void testMapRequest() { + final var originalRequest = new GenericJsonrpcRequest("method", new JsonObject()); + final var call = new Call(originalRequest); + class DummyRequestClass { + + } + + final var dummyRequest = new DummyRequestClass(); + final var newCall = call.mapRequest(dummyRequest); + + assertEquals(dummyRequest, newCall.getRequest()); + assertEquals(originalRequest, call.getRequest()); + } + + @Test + public void testMapResponse() { + final var call = new Call( + new GenericJsonrpcRequest("method", new JsonObject())); + class DummyResponseClass { + + } + + final var mappedCall = call.mapResponse(); + + final var originalResponse = new GenericJsonrpcResponseSuccess(call.getRequest().getId()); + call.setResponse(originalResponse); + final var mappedResponse = new DummyResponseClass(); + mappedCall.setResponse(mappedResponse); + + assertEquals(originalResponse, call.getResponse()); + assertEquals(mappedResponse, mappedCall.getResponse()); + } + + @Test + public void testGetRequest() { + final var exampleRequest = new GenericJsonrpcRequest("method", new JsonObject()); + final var call = new Call(exampleRequest); + + assertEquals(exampleRequest, call.getRequest()); + } + +} diff --git a/io.openems.edge.common/test/io/openems/edge/common/jsonapi/DummyJsonApi.java b/io.openems.edge.common/test/io/openems/edge/common/jsonapi/DummyJsonApi.java new file mode 100644 index 00000000000..c7ec9307f6f --- /dev/null +++ b/io.openems.edge.common/test/io/openems/edge/common/jsonapi/DummyJsonApi.java @@ -0,0 +1,16 @@ +package io.openems.edge.common.jsonapi; + +public final class DummyJsonApi implements JsonApi { + + private final JsonApiBuilder builder; + + public DummyJsonApi(JsonApiBuilder builder) { + this.builder = builder; + } + + @Override + public void buildJsonApiRoutes(JsonApiBuilder builder) { + builder.addBuilder(this.builder); + } + +} \ No newline at end of file diff --git a/io.openems.edge.common/test/io/openems/edge/common/jsonapi/EmptyObject.java b/io.openems.edge.common/test/io/openems/edge/common/jsonapi/EmptyObject.java new file mode 100644 index 00000000000..6c8d0cdc20f --- /dev/null +++ b/io.openems.edge.common/test/io/openems/edge/common/jsonapi/EmptyObject.java @@ -0,0 +1,19 @@ +package io.openems.edge.common.jsonapi; + +import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.emptyObjectSerializer; + +import io.openems.common.jsonrpc.serialization.JsonSerializer; + +public record EmptyObject() { + + /** + * Returns a {@link JsonSerializer} for a + * {@link JsonApiBuilderTest.EmptyObject}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return emptyObjectSerializer(EmptyObject::new); + } + +} \ No newline at end of file diff --git a/io.openems.edge.common/test/io/openems/edge/common/jsonapi/EndpointRequestDefinitionBuilderTest.java b/io.openems.edge.common/test/io/openems/edge/common/jsonapi/EndpointRequestDefinitionBuilderTest.java new file mode 100644 index 00000000000..2c6e46460c9 --- /dev/null +++ b/io.openems.edge.common/test/io/openems/edge/common/jsonapi/EndpointRequestDefinitionBuilderTest.java @@ -0,0 +1,48 @@ +package io.openems.edge.common.jsonapi; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; + +public class EndpointRequestDefinitionBuilderTest { + + @Test + public void testSetGetSerializer() { + final var defBuilder = new EndpointRequestDefinitionBuilder(); + defBuilder.setSerializer(EmptyObject.serializer()); + assertNotNull(defBuilder.getSerializer()); + } + + @Test + public void testAddExampleStringRequest() { + final var defBuilder = new EndpointRequestDefinitionBuilder(); + + final var exampleKey = "exampleKey"; + final var exampleObject = new EmptyObject(); + defBuilder.addExample(exampleKey, exampleObject); + assertEquals(1, defBuilder.getExamples().size()); + assertEquals(exampleKey, defBuilder.getExamples().get(0).identifier()); + assertEquals(exampleObject, defBuilder.getExamples().get(0).exampleObject()); + } + + @Test + public void testAddExampleRequest() { + final var defBuilder = new EndpointRequestDefinitionBuilder(); + + final var exampleObject = new EmptyObject(); + defBuilder.addExample(exampleObject); + assertEquals(1, defBuilder.getExamples().size()); + assertEquals(exampleObject, defBuilder.getExamples().get(0).exampleObject()); + } + + @Test + public void testCreateExampleArray() { + final var defBuilder = new EndpointRequestDefinitionBuilder(); + defBuilder.addExample(new EmptyObject()); + defBuilder.setSerializer(EmptyObject.serializer()); + + assertEquals(1, defBuilder.createExampleArray().size()); + } + +} diff --git a/io.openems.edge.common/test/io/openems/edge/common/jsonapi/EndpointResponseDefinitionBuilderTest.java b/io.openems.edge.common/test/io/openems/edge/common/jsonapi/EndpointResponseDefinitionBuilderTest.java new file mode 100644 index 00000000000..487d69b6937 --- /dev/null +++ b/io.openems.edge.common/test/io/openems/edge/common/jsonapi/EndpointResponseDefinitionBuilderTest.java @@ -0,0 +1,48 @@ +package io.openems.edge.common.jsonapi; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; + +public class EndpointResponseDefinitionBuilderTest { + + @Test + public void testSetGetSerializer() { + final var defBuilder = new EndpointResponseDefinitionBuilder(); + defBuilder.setSerializer(EmptyObject.serializer()); + assertNotNull(defBuilder.getSerializer()); + } + + @Test + public void testAddExampleStringResponse() { + final var defBuilder = new EndpointResponseDefinitionBuilder(); + + final var exampleKey = "exampleKey"; + final var exampleObject = new EmptyObject(); + defBuilder.addExample(exampleKey, exampleObject); + assertEquals(1, defBuilder.getExamples().size()); + assertEquals(exampleKey, defBuilder.getExamples().get(0).identifier()); + assertEquals(exampleObject, defBuilder.getExamples().get(0).exampleObject()); + } + + @Test + public void testAddExampleResponse() { + final var defBuilder = new EndpointResponseDefinitionBuilder(); + + final var exampleObject = new EmptyObject(); + defBuilder.addExample(exampleObject); + assertEquals(1, defBuilder.getExamples().size()); + assertEquals(exampleObject, defBuilder.getExamples().get(0).exampleObject()); + } + + @Test + public void testCreateExampleArray() { + final var defBuilder = new EndpointResponseDefinitionBuilder(); + defBuilder.addExample(new EmptyObject()); + defBuilder.setSerializer(EmptyObject.serializer()); + + assertEquals(1, defBuilder.createExampleArray().size()); + } + +} diff --git a/io.openems.edge.common/test/io/openems/edge/common/jsonapi/JsonApiBuilderTest.java b/io.openems.edge.common/test/io/openems/edge/common/jsonapi/JsonApiBuilderTest.java new file mode 100644 index 00000000000..290d565adbf --- /dev/null +++ b/io.openems.edge.common/test/io/openems/edge/common/jsonapi/JsonApiBuilderTest.java @@ -0,0 +1,188 @@ +package io.openems.edge.common.jsonapi; + +import static java.util.Collections.emptyList; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Function; + +import org.junit.Test; + +import com.google.gson.JsonObject; + +import io.openems.common.jsonrpc.base.GenericJsonrpcRequest; +import io.openems.common.jsonrpc.base.GenericJsonrpcResponseSuccess; +import io.openems.common.jsonrpc.base.JsonrpcRequest; +import io.openems.common.jsonrpc.base.JsonrpcResponse; +import io.openems.common.utils.FunctionUtils; + +public class JsonApiBuilderTest { + + @Test + public void testAddMethodHandler() { + final var builder = new JsonApiBuilder(); + + final var testMethod = "method"; + builder.handleRequest(testMethod, t -> null); + + assertEquals(1, builder.getEndpoints().size()); + final var addedEndpoint = builder.getEndpoints().get(testMethod); + assertNotNull(addedEndpoint); + } + + @Test + public void testAddMethodHandler2() { + final var builder = new JsonApiBuilder(); + + final var testMethod = "method"; + final var dummyDescription = "description"; + builder.rpc(testMethod, endpoint -> { + endpoint.setDescription(dummyDescription); + }, FunctionUtils::doNothing); + + assertEquals(1, builder.getEndpoints().size()); + final var addedEndpoint = builder.getEndpoints().get(testMethod); + assertNotNull(addedEndpoint); + assertEquals(dummyDescription, addedEndpoint.getDef().getDescription()); + } + + @Test + public void testAddMethodHandler3() { + final var builder = new JsonApiBuilder(); + + final var testMethod = "method"; + final var dummyDescription = "description"; + builder.rpc(testMethod, endpoint -> { + endpoint.setDescription(dummyDescription); + }, () -> List.of(new Subrequest(new JsonObject())), FunctionUtils::doNothing); + + assertEquals(1, builder.getEndpoints().size()); + final var addedEndpoint = builder.getEndpoints().get(testMethod); + assertNotNull(addedEndpoint); + assertEquals(dummyDescription, addedEndpoint.getDef().getDescription()); + final var subroutes = addedEndpoint.getSubroutes().get(); + assertEquals(1, subroutes.size()); + } + + @Test + public void testAddMethodHandler4() { + final var builder = new JsonApiBuilder(); + + final var testMethod = "method"; + final var dummyDescription = "description"; + builder.rpc(testMethod, endpoint -> { + endpoint.setDescription(dummyDescription); + }, () -> List.of(new Subrequest(new JsonObject())), FunctionUtils::doNothing, EmptyObject.serializer()); + + assertEquals(1, builder.getEndpoints().size()); + final var addedEndpoint = builder.getEndpoints().get(testMethod); + assertNotNull(addedEndpoint); + assertEquals(dummyDescription, addedEndpoint.getDef().getDescription()); + assertNotNull(addedEndpoint.getDef().getEndpointRequestBuilder().getSerializer()); + final var subroutes = addedEndpoint.getSubroutes().get(); + assertEquals(1, subroutes.size()); + } + + @Test + public void testAddMethodHandler5() { + final var builder = new JsonApiBuilder(); + + final var testMethod = "method"; + final var dummyDescription = "description"; + builder.rpc(testMethod, endpoint -> { + endpoint.setDescription(dummyDescription); + }, FunctionUtils::doNothing, EmptyObject.serializer(), EmptyObject.serializer()); + + assertEquals(1, builder.getEndpoints().size()); + final var addedEndpoint = builder.getEndpoints().get(testMethod); + assertNotNull(addedEndpoint); + assertEquals(dummyDescription, addedEndpoint.getDef().getDescription()); + assertNotNull(addedEndpoint.getDef().getEndpointRequestBuilder().getSerializer()); + assertNotNull(addedEndpoint.getDef().getEndpointResponseBuilder().getSerializer()); + } + + @Test + public void testDelegate() throws Exception { + final var builder = new JsonApiBuilder(); + + final var testMethod = "method"; + final var dummyDescription = "description"; + builder.delegate(testMethod, endpoint -> { + endpoint.setDescription(dummyDescription); + }, call -> { + return new GenericJsonrpcRequest("method2", new JsonObject()); + }, Function.identity(), Function.identity(), () -> emptyList()); + + final var isMethod2Called = new AtomicBoolean(false); + builder.handleRequest("method2", call -> { + isMethod2Called.set(true); + return null; + }); + + assertEquals(2, builder.getEndpoints().size()); + final var addedEndpoint = builder.getEndpoints().get(testMethod); + assertNotNull(addedEndpoint); + assertEquals(dummyDescription, addedEndpoint.getDef().getDescription()); + + final var testCall = new Call( + new GenericJsonrpcRequest(testMethod, new JsonObject())); + builder.handle(testCall); + assertTrue(isMethod2Called.get()); + } + + @Test + public void testCallEndpoint() { + final var builder = new JsonApiBuilder(); + + final var testMethod = "method"; + builder.handleRequest(testMethod, call -> { + return new GenericJsonrpcResponseSuccess(call.getRequest().getId()); + }); + + assertEquals(1, builder.getEndpoints().size()); + final var addedEndpoint = builder.getEndpoints().get(testMethod); + assertNotNull(addedEndpoint); + + final var testCall = new Call( + new GenericJsonrpcRequest(testMethod, new JsonObject())); + builder.handle(testCall); + + assertNotNull(testCall.getResponse()); + } + + @Test + public void testRemoveEndpoint() throws Exception { + final var builder = new JsonApiBuilder(); + + final var testMethod = "method"; + builder.handleRequest(testMethod, t -> null); + + assertEquals(1, builder.getEndpoints().size()); + + builder.removeEndpoint(testMethod); + assertEquals(0, builder.getEndpoints().size()); + } + + @Test + public void testAddBuilder() throws Exception { + final var builder = new JsonApiBuilder(); + final var subBuilder = new JsonApiBuilder(); + + builder.addBuilder(subBuilder); + + final var testMethod = "subMethod"; + subBuilder.handleRequest(testMethod, call -> { + return new GenericJsonrpcResponseSuccess(call.getRequest().getId()); + }); + + final var testCall = new Call( + new GenericJsonrpcRequest(testMethod, new JsonObject())); + builder.handle(testCall); + + assertNotNull(testCall.getResponse()); + } + +} diff --git a/io.openems.edge.common/test/io/openems/edge/common/jsonapi/JsonrpcRoleEndpointGuardTest.java b/io.openems.edge.common/test/io/openems/edge/common/jsonapi/JsonrpcRoleEndpointGuardTest.java new file mode 100644 index 00000000000..0e7cfc5eed6 --- /dev/null +++ b/io.openems.edge.common/test/io/openems/edge/common/jsonapi/JsonrpcRoleEndpointGuardTest.java @@ -0,0 +1,48 @@ +package io.openems.edge.common.jsonapi; + +import static io.openems.edge.common.test.DummyUser.DUMMY_ADMIN; +import static io.openems.edge.common.test.DummyUser.DUMMY_INSTALLER; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import com.google.gson.JsonObject; + +import io.openems.common.jsonrpc.base.GenericJsonrpcRequest; +import io.openems.common.jsonrpc.base.JsonrpcRequest; +import io.openems.common.jsonrpc.base.JsonrpcResponse; +import io.openems.common.session.Role; + +public class JsonrpcRoleEndpointGuardTest { + + @Test + public void testTest() throws Exception { + final var guard = new JsonrpcRoleEndpointGuard(Role.ADMIN); + + final var call = new Call( + new GenericJsonrpcRequest("method", new JsonObject())); + + call.put(EdgeKeys.USER_KEY, DUMMY_ADMIN); + guard.test(call); + } + + @Test(expected = Exception.class) + public void testTestException() throws Exception { + final var guard = new JsonrpcRoleEndpointGuard(Role.ADMIN); + + final var call = new Call( + new GenericJsonrpcRequest("method", new JsonObject())); + + call.put(EdgeKeys.USER_KEY, DUMMY_INSTALLER); + guard.test(call); + } + + @Test + public void testGetRole() { + final var role = Role.ADMIN; + final var guard = new JsonrpcRoleEndpointGuard(role); + + assertEquals(role, guard.getRole()); + } + +} diff --git a/io.openems.edge.common/test/io/openems/edge/common/jsonapi/MultipleJsonApiBinderTest.java b/io.openems.edge.common/test/io/openems/edge/common/jsonapi/MultipleJsonApiBinderTest.java new file mode 100644 index 00000000000..3788513ff83 --- /dev/null +++ b/io.openems.edge.common/test/io/openems/edge/common/jsonapi/MultipleJsonApiBinderTest.java @@ -0,0 +1,54 @@ +package io.openems.edge.common.jsonapi; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import io.openems.common.utils.FunctionUtils; + +public class MultipleJsonApiBinderTest { + + @Test + public void testBindJsonApi() { + final var binder = new MultipleJsonApiBinder(); + + binder.bindJsonApi(new DummyJsonApi(new JsonApiBuilder().rpc("method1", FunctionUtils::doNothing))); + binder.bindJsonApi(new DummyJsonApi(new JsonApiBuilder().rpc("method2", FunctionUtils::doNothing))); + + assertTrue(binder.getJsonApiBuilder().getEndpoints().containsKey("method1")); + assertTrue(binder.getJsonApiBuilder().getEndpoints().containsKey("method2")); + assertEquals(2, binder.getJsonApiBuilder().getEndpoints().size()); + + binder.bindJsonApi(new DummyJsonApi(new JsonApiBuilder().rpc("method3", FunctionUtils::doNothing))); + + assertTrue(binder.getJsonApiBuilder().getEndpoints().containsKey("method3")); + assertEquals(3, binder.getJsonApiBuilder().getEndpoints().size()); + } + + @Test + public void testUnbindJsonApi() { + final var binder = new MultipleJsonApiBinder(); + + final var dummyApi1 = new DummyJsonApi(new JsonApiBuilder().rpc("method1", FunctionUtils::doNothing)); + binder.bindJsonApi(dummyApi1); + final var dummyApi2 = new DummyJsonApi(new JsonApiBuilder().rpc("method2", FunctionUtils::doNothing)); + binder.bindJsonApi(dummyApi2); + + assertTrue(binder.getJsonApiBuilder().getEndpoints().containsKey("method1")); + assertTrue(binder.getJsonApiBuilder().getEndpoints().containsKey("method2")); + assertEquals(2, binder.getJsonApiBuilder().getEndpoints().size()); + + final var dummyApi3 = new DummyJsonApi(new JsonApiBuilder().rpc("method3", FunctionUtils::doNothing)); + binder.bindJsonApi(dummyApi3); + + assertTrue(binder.getJsonApiBuilder().getEndpoints().containsKey("method3")); + assertEquals(3, binder.getJsonApiBuilder().getEndpoints().size()); + + binder.unbindJsonApi(dummyApi2); + assertTrue(binder.getJsonApiBuilder().getEndpoints().containsKey("method1")); + assertTrue(binder.getJsonApiBuilder().getEndpoints().containsKey("method3")); + assertEquals(2, binder.getJsonApiBuilder().getEndpoints().size()); + } + +} diff --git a/io.openems.edge.common/test/io/openems/edge/common/jsonapi/SingleJsonApiBinderTest.java b/io.openems.edge.common/test/io/openems/edge/common/jsonapi/SingleJsonApiBinderTest.java new file mode 100644 index 00000000000..18a0b620eea --- /dev/null +++ b/io.openems.edge.common/test/io/openems/edge/common/jsonapi/SingleJsonApiBinderTest.java @@ -0,0 +1,55 @@ +package io.openems.edge.common.jsonapi; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.util.Optional; +import java.util.UUID; + +import org.junit.Test; + +import com.google.gson.JsonObject; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.jsonrpc.base.GenericJsonrpcRequest; +import io.openems.common.jsonrpc.base.GenericJsonrpcResponseSuccess; + +public class SingleJsonApiBinderTest { + + @Test + public void testBind() throws Exception { + final var binder = new SingleJsonApiBinder(); + + final var id = UUID.randomUUID(); + final var response = new GenericJsonrpcResponseSuccess(id); + binder.bind(new DummyJsonApi(new JsonApiBuilder().handleRequest("method", call -> response))); + + final var handledResponse = binder + .handleRequest(new GenericJsonrpcRequest(id, "method", new JsonObject(), Optional.empty())).get(); + assertEquals(response.getResult(), handledResponse.getResult()); + } + + @Test + public void testUnbind() throws Exception { + final var binder = new SingleJsonApiBinder(); + + final var id = UUID.randomUUID(); + final var response = new GenericJsonrpcResponseSuccess(id); + binder.bind(new DummyJsonApi(new JsonApiBuilder().handleRequest("method", call -> response))); + + final var handledResponse = binder + .handleRequest(new GenericJsonrpcRequest(id, "method", new JsonObject(), Optional.empty())).get(); + assertEquals(response.getResult(), handledResponse.getResult()); + + binder.unbind(); + + OpenemsNamedException exception = null; + try { + binder.handleRequest(new GenericJsonrpcRequest("method", new JsonObject())).get(); + } catch (OpenemsNamedException e) { + exception = e; + } + assertNotNull(exception); + } + +} diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/BackendOnRequest.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/BackendOnRequest.java new file mode 100644 index 00000000000..c3d38665a53 --- /dev/null +++ b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/BackendOnRequest.java @@ -0,0 +1,84 @@ +package io.openems.edge.controller.api.backend; + +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; + +import org.java_websocket.WebSocket; +import org.osgi.service.component.ComponentServiceObjects; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ServiceScope; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.jsonrpc.base.JsonrpcRequest; +import io.openems.common.jsonrpc.base.JsonrpcResponse; +import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; +import io.openems.common.utils.FunctionUtils; +import io.openems.common.websocket.OnRequest; +import io.openems.edge.common.jsonapi.Call; +import io.openems.edge.common.jsonapi.SingleJsonApiBinder; +import io.openems.edge.controller.api.backend.handler.RootRequestHandler; + +@Component(// + scope = ServiceScope.PROTOTYPE, // + service = { BackendOnRequest.class, OnRequest.class } // +) +public class BackendOnRequest implements OnRequest { + + @Component(service = BackendOnRequest.Factory.class) + public static class Factory { + + @Reference + private ComponentServiceObjects cso; + + /** + * Returns a new {@link BackendOnRequest} service object. + * + * @return the created {@link BackendOnRequest} object + * @see #unget(BackendOnRequest) + */ + public BackendOnRequest get() { + return this.cso.getService(); + } + + /** + * Releases the {@link BackendOnRequest} service object. + * + * @param service a {@link BackendOnRequest} provided by this factory + * @see #get() + */ + public void unget(BackendOnRequest service) { + if (service == null) { + return; + } + this.cso.ungetService(service); + } + + } + + private final SingleJsonApiBinder apiBinder = new SingleJsonApiBinder(); + private Consumer> onCall = FunctionUtils::doNothing; + + @Activate + public BackendOnRequest(@Reference RootRequestHandler handler) { + this.apiBinder.bind(handler); + } + + @Override + public CompletableFuture run(// + final WebSocket ws, // + final JsonrpcRequest request // + ) throws OpenemsNamedException { + return this.apiBinder.handleRequest(request, this.onCall); + } + + public void setOnCall(Consumer> callAction) { + this.onCall = callAction == null ? FunctionUtils::doNothing : callAction; + } + + public void setDebug(boolean debug) { + this.apiBinder.setDebug(debug); + } + +} diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/ControllerApiBackendImpl.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/ControllerApiBackendImpl.java index eefbc0b7be3..50f6109cba7 100644 --- a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/ControllerApiBackendImpl.java +++ b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/ControllerApiBackendImpl.java @@ -15,8 +15,6 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; -import org.ops4j.pax.logging.spi.PaxAppender; -import org.ops4j.pax.logging.spi.PaxLoggingEvent; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; @@ -36,7 +34,6 @@ import io.openems.common.jsonrpc.base.JsonrpcRequest; import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; import io.openems.common.jsonrpc.notification.EdgeConfigNotification; -import io.openems.common.jsonrpc.notification.SystemLogNotification; import io.openems.common.oem.OpenemsEdgeOem; import io.openems.common.types.EdgeConfig; import io.openems.common.utils.ThreadPoolUtils; @@ -46,29 +43,31 @@ import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.cycle.Cycle; import io.openems.edge.common.event.EdgeEventConstants; -import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.EdgeKeys; +import io.openems.edge.common.jsonapi.Key; import io.openems.edge.common.user.User; import io.openems.edge.controller.api.Controller; +import io.openems.edge.controller.api.backend.api.ControllerApiBackend; import io.openems.edge.controller.api.common.ApiWorker; +import io.openems.edge.controller.api.common.handler.ComponentConfigRequestHandler; @Designate(ocd = Config.class, factory = true) @Component(// name = "Controller.Api.Backend", // immediate = true, // - configurationPolicy = ConfigurationPolicy.REQUIRE, // - property = { // - "org.ops4j.pax.logging.appender.name=Controller.Api.Backend", // - } // + configurationPolicy = ConfigurationPolicy.REQUIRE // ) @EventTopics({ // EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE, // EdgeEventConstants.TOPIC_CONFIG_UPDATE // }) public class ControllerApiBackendImpl extends AbstractOpenemsComponent - implements ControllerApiBackend, Controller, JsonApi, OpenemsComponent, PaxAppender, EventHandler { + implements ControllerApiBackend, Controller, OpenemsComponent, EventHandler { protected static final String COMPONENT_NAME = "Controller.Api.Backend"; + public static final Key WEBSOCKET_CLIENT_KEY = new Key<>("websocketClient", WebsocketClient.class); + protected final SendChannelValuesWorker sendChannelValuesWorker = new SendChannelValuesWorker(this); protected final ApiWorker apiWorker = new ApiWorker(this); @@ -76,21 +75,22 @@ public class ControllerApiBackendImpl extends AbstractOpenemsComponent @Reference private OpenemsEdgeOem oem; + @Reference + protected ComponentManager componentManager; + @Reference + protected Cycle cycle; @Reference private ResendHistoricDataWorkerFactory resendHistoricDataWorkerFactory; protected ResendHistoricDataWorker resendHistoricDataWorker; @Reference - protected ComponentManager componentManager; - - @Reference - protected Cycle cycle; + private BackendOnRequest.Factory requestHandlerFactory; + protected BackendOnRequest requestHandler; protected WebsocketClient websocket = null; protected Config config; /** Used for SubscribeSystemLogRequests. */ - private boolean isSystemLogSubscribed = false; private ScheduledExecutorService executor; public ControllerApiBackendImpl() { @@ -99,20 +99,17 @@ public ControllerApiBackendImpl() { Controller.ChannelId.values(), // ControllerApiBackend.ChannelId.values() // ); - this.apiWorker.setLogChannel(this.getApiWorkerLogChannel()); } - /** - * Activation method. - * - * @param context the {@link ComponentContext} - * @param config the {@link Config} - */ @Activate private void activate(ComponentContext context, Config config) { this.config = config; super.activate(context, config.id(), config.alias(), config.enabled()); + this.apiWorker.setLogChannel(this.getApiWorkerLogChannel()); + this.resendHistoricDataWorker = this.resendHistoricDataWorkerFactory.get(); + this.requestHandler = this.requestHandlerFactory.get(); + if (!this.isEnabled()) { return; } @@ -159,11 +156,18 @@ private void activate(ComponentContext context, Config config) { t -> this.websocket.sendMessage(t) // )); this.resendHistoricDataWorker.activate(this.id(), false); + + this.requestHandler.setOnCall(call -> { + call.put(WEBSOCKET_CLIENT_KEY, this.websocket); + call.put(ComponentConfigRequestHandler.API_WORKER_KEY, this.apiWorker); + call.put(EdgeKeys.IS_FROM_BACKEND_KEY, true); + }); + this.requestHandler.setDebug(config.debugMode()); } @Override @Deactivate - protected void deactivate() { + protected synchronized void deactivate() { super.deactivate(); this.resendHistoricDataWorkerFactory.unget(this.resendHistoricDataWorker); this.resendHistoricDataWorker = null; @@ -194,55 +198,33 @@ protected void logError(Logger log, String message) { super.logError(log, message); } - /** - * Activates/deactivates subscription to System-Log. - * - *

- * If activated, all System-Log events are sent via - * {@link SystemLogNotification}s. - * - * @param isSystemLogSubscribed true to activate - */ - protected void setSystemLogSubscribed(boolean isSystemLogSubscribed) { - this.isSystemLogSubscribed = isSystemLogSubscribed; - } - - @Override - public void doAppend(PaxLoggingEvent event) { - if (!this.isSystemLogSubscribed) { - return; - } - var ws = this.websocket; - if (ws == null) { - return; - } - var notification = SystemLogNotification.fromPaxLoggingEvent(event); - ws.sendMessage(notification); - } - @Override public void handleEvent(Event event) { - if (!this.isEnabled()) { - return; - } - switch (event.getTopic()) { - case EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE: - this.sendChannelValuesWorker.collectData(); - break; - - case EdgeEventConstants.TOPIC_CONFIG_UPDATE: - // Send new EdgeConfig - var config = (EdgeConfig) event.getProperty(EdgeEventConstants.TOPIC_CONFIG_UPDATE_KEY); - var message = new EdgeConfigNotification(config); - var ws = this.websocket; - if (ws == null) { + try { + if (!this.isEnabled()) { return; } - ws.sendMessage(message); - - // Trigger sending of all channel values, because a Component might have - // disappeared - this.sendChannelValuesWorker.sendValuesOfAllChannelsOnce(); + switch (event.getTopic()) { + case EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE: + this.sendChannelValuesWorker.collectData(); + break; + + case EdgeEventConstants.TOPIC_CONFIG_UPDATE: + // Send new EdgeConfig + var config = (EdgeConfig) event.getProperty(EdgeEventConstants.TOPIC_CONFIG_UPDATE_KEY); + var message = new EdgeConfigNotification(config); + var ws = this.websocket; + if (ws == null) { + return; + } + ws.sendMessage(message); + + // Trigger sending of all channel values, because a Component might have + // disappeared + this.sendChannelValuesWorker.sendValuesOfAllChannelsOnce(); + } + } catch (Exception e) { + e.printStackTrace(); } } @@ -281,9 +263,8 @@ public ScheduledFuture scheduleWithFixedDelay(Runnable command, long initialD } @Override - public CompletableFuture handleJsonrpcRequest(User user, JsonrpcRequest request) + public CompletableFuture sendRequest(User user, JsonrpcRequest request) throws OpenemsNamedException { - // delegates request to actual backend return this.websocket.sendRequest(request); } diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/OnRequest.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/OnRequest.java deleted file mode 100644 index d49fcfbbd19..00000000000 --- a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/OnRequest.java +++ /dev/null @@ -1,292 +0,0 @@ -package io.openems.edge.controller.api.backend; - -import java.util.concurrent.CompletableFuture; - -import org.java_websocket.WebSocket; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.openems.common.exceptions.NotImplementedException; -import io.openems.common.exceptions.OpenemsError; -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.exceptions.OpenemsException; -import io.openems.common.jsonrpc.base.GenericJsonrpcResponseSuccess; -import io.openems.common.jsonrpc.base.JsonrpcRequest; -import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; -import io.openems.common.jsonrpc.request.AuthenticatedRpcRequest; -import io.openems.common.jsonrpc.request.ComponentJsonApiRequest; -import io.openems.common.jsonrpc.request.CreateComponentConfigRequest; -import io.openems.common.jsonrpc.request.DeleteComponentConfigRequest; -import io.openems.common.jsonrpc.request.GetEdgeConfigRequest; -import io.openems.common.jsonrpc.request.SetChannelValueRequest; -import io.openems.common.jsonrpc.request.SubscribeSystemLogRequest; -import io.openems.common.jsonrpc.request.UpdateComponentConfigRequest; -import io.openems.common.jsonrpc.request.UpdateUserLanguageRequest; -import io.openems.common.jsonrpc.request.UpdateUserSettingsRequest; -import io.openems.common.jsonrpc.response.AuthenticatedRpcResponse; -import io.openems.common.session.Role; -import io.openems.edge.common.component.ComponentManager; -import io.openems.edge.common.jsonapi.JsonApi; -import io.openems.edge.common.user.User; - -public class OnRequest implements io.openems.common.websocket.OnRequest { - - private final Logger log = LoggerFactory.getLogger(OnRequest.class); - private final ControllerApiBackendImpl parent; - - public OnRequest(ControllerApiBackendImpl parent) { - this.parent = parent; - } - - @Override - public CompletableFuture run(WebSocket ws, JsonrpcRequest request) - throws OpenemsException, OpenemsNamedException { - switch (request.getMethod()) { - - case AuthenticatedRpcRequest.METHOD: - return this.handleAuthenticatedRpcRequest(AuthenticatedRpcRequest.from(request, User::from)); - - default: - this.parent.logWarn(this.log, "Unhandled Request: " + request); - throw OpenemsError.JSONRPC_UNHANDLED_METHOD.exception(request.getMethod()); - } - } - - /** - * Handles a {@link AuthenticatedRpcRequest}. - * - * @param authenticatedRpcRequest the {@link AuthenticatedRpcRequest} - * @return the JSON-RPC Success Response Future - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleAuthenticatedRpcRequest( - AuthenticatedRpcRequest authenticatedRpcRequest) throws OpenemsNamedException { - var user = authenticatedRpcRequest.getUser(); - var request = authenticatedRpcRequest.getPayload(); - - final var resultFuture = switch (request.getMethod()) { - - case GetEdgeConfigRequest.METHOD -> // - this.handleGetEdgeConfigRequest(user, GetEdgeConfigRequest.from(request)); - - case CreateComponentConfigRequest.METHOD -> // - this.handleCreateComponentConfigRequest(user, CreateComponentConfigRequest.from(request)); - - case UpdateComponentConfigRequest.METHOD -> // - this.handleUpdateComponentConfigRequest(user, UpdateComponentConfigRequest.from(request)); - - case DeleteComponentConfigRequest.METHOD -> // - this.handleDeleteComponentConfigRequest(user, DeleteComponentConfigRequest.from(request)); - - case SetChannelValueRequest.METHOD -> // - this.handleSetChannelValueRequest(user, SetChannelValueRequest.from(request)); - - case ComponentJsonApiRequest.METHOD -> // - this.handleComponentJsonApiRequest(user, ComponentJsonApiRequest.from(request)); - - case SubscribeSystemLogRequest.METHOD -> // - this.handleSubscribeSystemLogRequest(user, SubscribeSystemLogRequest.from(request)); - - case UpdateUserLanguageRequest.METHOD -> // - this.handleUpdateUserLanguageRequest(user, UpdateUserLanguageRequest.from(request)); - - case UpdateUserSettingsRequest.METHOD -> // - this.handleUpdateUserSettingsRequest(user, UpdateUserSettingsRequest.from(request)); - - default -> { - this.parent.logWarn(this.log, "Unhandled Request: " + request); - throw OpenemsError.JSONRPC_UNHANDLED_METHOD.exception(request.getMethod()); - } - }; - - var result = new CompletableFuture(); - resultFuture.whenComplete((r, ex) -> { - if (ex != null) { - result.completeExceptionally(ex); - } else if (r != null) { - result.complete(new AuthenticatedRpcResponse(authenticatedRpcRequest.getId(), r)); - } else { - result.completeExceptionally( - new OpenemsNamedException(OpenemsError.JSONRPC_UNHANDLED_METHOD, request.getMethod())); - } - }); - return result; - } - - /** - * Handles a {@link GetEdgeConfigRequest}. - * - * @param user the {@link User} - * @param getEdgeConfigRequest the {@link GetEdgeConfigRequest} - * @return the JSON-RPC Success Response Future - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleGetEdgeConfigRequest(User user, - GetEdgeConfigRequest getEdgeConfigRequest) throws OpenemsNamedException { - // wrap original request inside ComponentJsonApiRequest - var request = new ComponentJsonApiRequest(ComponentManager.SINGLETON_COMPONENT_ID, getEdgeConfigRequest); - - return this.handleComponentJsonApiRequest(user, request); - } - - /** - * Handles a {@link CreateComponentConfigRequest}. - * - * @param user the {@link User} - * @param createComponentConfigRequest the {@link CreateComponentConfigRequest} - * @return the Future JSON-RPC Response - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleCreateComponentConfigRequest(User user, - CreateComponentConfigRequest createComponentConfigRequest) throws OpenemsNamedException { - user.assertRoleIsAtLeast(DeleteComponentConfigRequest.METHOD, Role.INSTALLER); - - // wrap original request inside ComponentJsonApiRequest - var request = new ComponentJsonApiRequest(ComponentManager.SINGLETON_COMPONENT_ID, - createComponentConfigRequest); - - return this.handleComponentJsonApiRequest(user, request); - } - - /** - * Handles a {@link UpdateComponentConfigRequest}. - * - * @param user the {@link User} - * @param updateComponentConfigRequest the {@link UpdateComponentConfigRequest} - * @return the Future JSON-RPC Response - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleUpdateComponentConfigRequest(User user, - UpdateComponentConfigRequest updateComponentConfigRequest) throws OpenemsNamedException { - user.assertRoleIsAtLeast(DeleteComponentConfigRequest.METHOD, Role.OWNER); - - // wrap original request inside ComponentJsonApiRequest - var request = new ComponentJsonApiRequest(ComponentManager.SINGLETON_COMPONENT_ID, - updateComponentConfigRequest); - - return this.handleComponentJsonApiRequest(user, request); - } - - /** - * Handles a {@link DeleteComponentConfigRequest}. - * - * @param user the {@link User} - * @param deleteComponentConfigRequest the {@link DeleteComponentConfigRequest} - * @return the Future JSON-RPC Response - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleDeleteComponentConfigRequest(User user, - DeleteComponentConfigRequest deleteComponentConfigRequest) throws OpenemsNamedException { - user.assertRoleIsAtLeast(DeleteComponentConfigRequest.METHOD, Role.INSTALLER); - - // wrap original request inside ComponentJsonApiRequest - var request = new ComponentJsonApiRequest(ComponentManager.SINGLETON_COMPONENT_ID, - deleteComponentConfigRequest); - - return this.handleComponentJsonApiRequest(user, request); - } - - /** - * Handles a {@link SetChannelValueRequest}. - * - * @param user the {@link User} - * @param request the {@link SetChannelValueRequest} - * @return the Future JSON-RPC Response - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleSetChannelValueRequest(User user, - SetChannelValueRequest request) throws OpenemsNamedException { - user.assertRoleIsAtLeast(SetChannelValueRequest.METHOD, Role.ADMIN); - - return this.parent.apiWorker.handleSetChannelValueRequest(this.parent.componentManager, user, request); - } - - /** - * Handles a {@link ComponentJsonApiRequest}. - * - * @param user the {@link User} - * @param request the {@link ComponentJsonApiRequest} - * @return the JSON-RPC Success Response Future - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleComponentJsonApiRequest(User user, - ComponentJsonApiRequest request) throws OpenemsNamedException { - // get Component - var componentId = request.getComponentId(); - var component = this.parent.componentManager.getComponent(componentId); - - if (component == null) { - throw new OpenemsException("Unable to find Component [" + componentId + "]"); - } - - if (!(component instanceof JsonApi)) { - throw new OpenemsException("Component [" + componentId + "] is no JsonApi"); - } - - // call JsonApi - var jsonApi = (JsonApi) component; - CompletableFuture responseFuture = jsonApi.handleJsonrpcRequest(user, - request.getPayload()); - - // handle null response - if (responseFuture == null) { - throw OpenemsError.JSONRPC_UNHANDLED_METHOD.exception(request.getPayload().getMethod()); - } - - // Wrap reply in EdgeRpcResponse - var edgeRpcResponse = new CompletableFuture(); - responseFuture.whenComplete((r, ex) -> { - if (ex != null) { - edgeRpcResponse.completeExceptionally(ex); - } else if (r != null) { - edgeRpcResponse.complete(new GenericJsonrpcResponseSuccess(request.getId(), r.getResult())); - } else { - edgeRpcResponse.completeExceptionally(new OpenemsNamedException(OpenemsError.JSONRPC_UNHANDLED_METHOD, - request.getPayload().getMethod())); - } - }); - - return edgeRpcResponse; - } - - /** - * Handles a {@link SubscribeSystemLogRequest}. - * - * @param user the {@link User} - * @param request the {@link SubscribeSystemLogRequest} - * @return the JSON-RPC Success Response Future - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleSubscribeSystemLogRequest(User user, - SubscribeSystemLogRequest request) throws OpenemsNamedException { - this.parent.setSystemLogSubscribed(request.isSubscribe()); - return CompletableFuture.completedFuture(new GenericJsonrpcResponseSuccess(request.getId())); - } - - /** - * Handles a {@link UpdateUserLanguageRequest}. - * - * @param user the {@link User} - * @param request the {@link UpdateUserLanguageRequest} - * @return the JSON-RPC Success Response Future - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleUpdateUserLanguageRequest(User user, - UpdateUserLanguageRequest request) throws OpenemsNamedException { - throw new NotImplementedException("Edge backend api update user language not implemented"); - } - - /** - * Handles a {@link UpdateUserSettingsRequest}. - * - * @param user the {@link User} - * @param request the {@link UpdateUserSettingsRequest} - * @return the JSON-RPC Success Response Future - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleUpdateUserSettingsRequest(User user, - UpdateUserSettingsRequest request) throws OpenemsNamedException { - throw new NotImplementedException("Edge backend api update user settings not implemented"); - } - -} diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/WebsocketClient.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/WebsocketClient.java index 45a9800a44b..9730473734e 100644 --- a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/WebsocketClient.java +++ b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/WebsocketClient.java @@ -19,7 +19,6 @@ public class WebsocketClient extends AbstractWebsocketClient { private final ControllerApiBackendImpl parent; private final OnOpen onOpen; - private final OnRequest onRequest; private final OnNotification onNotification; private final OnError onError; private final OnClose onClose; @@ -29,7 +28,6 @@ protected WebsocketClient(ControllerApiBackendImpl parent, String name, URI serv super(name, serverUri, httpHeaders, proxy); this.parent = parent; this.onOpen = new OnOpen(parent); - this.onRequest = new OnRequest(parent); this.onNotification = new OnNotification(parent); this.onError = new OnError(parent); this.onClose = (ws, code, reason, remote) -> { @@ -45,8 +43,8 @@ public OnOpen getOnOpen() { } @Override - public OnRequest getOnRequest() { - return this.onRequest; + public BackendOnRequest getOnRequest() { + return this.parent.requestHandler; } @Override diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/ControllerApiBackend.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/api/ControllerApiBackend.java similarity index 73% rename from io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/ControllerApiBackend.java rename to io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/api/ControllerApiBackend.java index 555420f97c8..90023b35f81 100644 --- a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/ControllerApiBackend.java +++ b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/api/ControllerApiBackend.java @@ -1,21 +1,25 @@ -package io.openems.edge.controller.api.backend; +package io.openems.edge.controller.api.backend.api; + +import java.util.concurrent.CompletableFuture; -import org.ops4j.pax.logging.spi.PaxAppender; import org.osgi.service.event.EventHandler; import io.openems.common.channel.Level; import io.openems.common.channel.PersistencePriority; import io.openems.common.channel.Unit; +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.jsonrpc.base.JsonrpcRequest; +import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; import io.openems.common.types.OpenemsType; import io.openems.edge.common.channel.Doc; import io.openems.edge.common.channel.LongReadChannel; import io.openems.edge.common.channel.StateChannel; import io.openems.edge.common.channel.StringReadChannel; import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.user.User; import io.openems.edge.controller.api.Controller; -public interface ControllerApiBackend extends Controller, JsonApi, OpenemsComponent, PaxAppender, EventHandler { +public interface ControllerApiBackend extends Controller, OpenemsComponent, EventHandler { public enum ChannelId implements io.openems.edge.common.channel.ChannelId { API_WORKER_LOG(Doc.of(OpenemsType.STRING) // @@ -76,4 +80,15 @@ public default LongReadChannel getLastSuccessFulResendChannel() { */ public boolean isConnected(); + /** + * Sends the request to the connected backend. + * + * @param user the user + * @param request the request to send + * @return the result future + * @throws OpenemsNamedException on error + */ + public CompletableFuture sendRequest(User user, JsonrpcRequest request) + throws OpenemsNamedException; + } diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/api/package-info.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/api/package-info.java new file mode 100644 index 00000000000..ad5a110d7cf --- /dev/null +++ b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/api/package-info.java @@ -0,0 +1,3 @@ +@org.osgi.annotation.versioning.Version("1.0.0") +@org.osgi.annotation.bundle.Export +package io.openems.edge.controller.api.backend.api; diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/handler/AuthenticatedRequestHandler.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/handler/AuthenticatedRequestHandler.java new file mode 100644 index 00000000000..e95c94ad568 --- /dev/null +++ b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/handler/AuthenticatedRequestHandler.java @@ -0,0 +1,65 @@ +package io.openems.edge.controller.api.backend.handler; + +import java.util.List; + +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; + +import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; +import io.openems.common.jsonrpc.request.AuthenticatedRpcRequest; +import io.openems.common.jsonrpc.response.AuthenticatedRpcResponse; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.common.jsonapi.EdgeKeys; +import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.JsonApiBuilder; +import io.openems.edge.common.jsonapi.MultipleJsonApiBinder; +import io.openems.edge.common.jsonapi.Subrequest; +import io.openems.edge.common.user.User; + +@Component(property = { "entry=" + RootRequestHandler.ENTRY_POINT }) +public class AuthenticatedRequestHandler implements JsonApi { + + public static final String ENTRY_POINT = "edge.backend.authenticated"; + + private final MultipleJsonApiBinder binder = new MultipleJsonApiBinder(); + + @Reference(// + target = "(entry=" + ENTRY_POINT + ")", // + bind = "bindHandler", unbind = "unbindHandler", // + policyOption = ReferencePolicyOption.GREEDY, // + policy = ReferencePolicy.DYNAMIC, // + cardinality = ReferenceCardinality.MULTIPLE // + ) + protected void bindHandler(JsonApi handler) { + this.binder.bindJsonApi(handler); + } + + protected void unbindHandler(JsonApi handler) { + this.binder.unbindJsonApi(handler); + } + + @Override + public void buildJsonApiRoutes(JsonApiBuilder b) { + b.delegate(AuthenticatedRpcRequest.METHOD, endpoint -> { + + }, t -> { + final var authenticatedRpcRequest = AuthenticatedRpcRequest.from(t.getRequest(), User::from); + t.put(EdgeKeys.USER_KEY, authenticatedRpcRequest.getUser()); + return authenticatedRpcRequest.getPayload(); + }, c -> this.binder.getJsonApiBuilder(), response -> { + // wrap response in a AuthenticatedRpcResponse if successful + if (response instanceof JsonrpcResponseSuccess success) { + return new AuthenticatedRpcResponse(response.getId(), success); + } + return response; + }, () -> { + final var subrequest = new Subrequest(JsonUtils.buildJsonObject().build()); + subrequest.addRpcBuilderFor(this.binder.getJsonApiBuilder(), "payload"); + return List.of(subrequest); + }); + } + +} diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/handler/BindingComponentConfigRequestHandler.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/handler/BindingComponentConfigRequestHandler.java new file mode 100644 index 00000000000..e726a07b404 --- /dev/null +++ b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/handler/BindingComponentConfigRequestHandler.java @@ -0,0 +1,28 @@ +package io.openems.edge.controller.api.backend.handler; + +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.JsonApiBuilder; +import io.openems.edge.controller.api.common.handler.ComponentConfigRequestHandler; + +@Component(property = { "entry=" + AuthenticatedRequestHandler.ENTRY_POINT }) +public class BindingComponentConfigRequestHandler implements JsonApi { + + private final ComponentConfigRequestHandler componentConfigRequestHandler; + + @Activate + public BindingComponentConfigRequestHandler(// + @Reference ComponentConfigRequestHandler componentConfigRequestHandler // + ) { + this.componentConfigRequestHandler = componentConfigRequestHandler; + } + + @Override + public void buildJsonApiRoutes(JsonApiBuilder builder) { + this.componentConfigRequestHandler.buildJsonApiRoutes(builder); + } + +} \ No newline at end of file diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/handler/BindingComponentRequestHandler.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/handler/BindingComponentRequestHandler.java new file mode 100644 index 00000000000..58b91fd51ca --- /dev/null +++ b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/handler/BindingComponentRequestHandler.java @@ -0,0 +1,28 @@ +package io.openems.edge.controller.api.backend.handler; + +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.JsonApiBuilder; +import io.openems.edge.controller.api.common.handler.ComponentRequestHandler; + +@Component(property = { "entry=" + AuthenticatedRequestHandler.ENTRY_POINT }) +public class BindingComponentRequestHandler implements JsonApi { + + private final ComponentRequestHandler componentRequestHandler; + + @Activate + public BindingComponentRequestHandler(// + @Reference ComponentRequestHandler componentRequestHandler // + ) { + this.componentRequestHandler = componentRequestHandler; + } + + @Override + public void buildJsonApiRoutes(JsonApiBuilder builder) { + this.componentRequestHandler.buildJsonApiRoutes(builder); + } + +} \ No newline at end of file diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/handler/BindingRoutesJsonApiHandler.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/handler/BindingRoutesJsonApiHandler.java new file mode 100644 index 00000000000..def81a37ab6 --- /dev/null +++ b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/handler/BindingRoutesJsonApiHandler.java @@ -0,0 +1,40 @@ +package io.openems.edge.controller.api.backend.handler; + +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceScope; + +import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.JsonApiBuilder; +import io.openems.edge.controller.api.common.handler.RoutesJsonApiHandler; + +@Component(// + property = { "entry=" + AuthenticatedRequestHandler.ENTRY_POINT }, // + service = { BindingRoutesJsonApiHandler.class, JsonApi.class } // +) +public class BindingRoutesJsonApiHandler implements JsonApi { + + private final RoutesJsonApiHandler jsonApiHandler; + + @Activate + public BindingRoutesJsonApiHandler(// + @Reference(scope = ReferenceScope.PROTOTYPE_REQUIRED) RoutesJsonApiHandler jsonApiHandler // + ) { + this.jsonApiHandler = jsonApiHandler; + } + + @Override + public void buildJsonApiRoutes(JsonApiBuilder builder) { + this.jsonApiHandler.buildJsonApiRoutes(builder); + } + + public JsonApiBuilder getBuilder() { + return this.jsonApiHandler.getBuilder(); + } + + public void setBuilder(JsonApiBuilder builder) { + this.jsonApiHandler.setBuilder(builder); + } + +} \ No newline at end of file diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/handler/RootRequestHandler.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/handler/RootRequestHandler.java new file mode 100644 index 00000000000..68f07c59e27 --- /dev/null +++ b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/handler/RootRequestHandler.java @@ -0,0 +1,52 @@ +package io.openems.edge.controller.api.backend.handler; + +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.component.annotations.ServiceScope; + +import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.JsonApiBuilder; +import io.openems.edge.common.jsonapi.MultipleJsonApiBinder; + +@Component(// + service = { RootRequestHandler.class, JsonApi.class }, // + scope = ServiceScope.SINGLETON // +) +public class RootRequestHandler implements JsonApi { + + public static final String ENTRY_POINT = "edge.backend.root"; + + private final MultipleJsonApiBinder binder = new MultipleJsonApiBinder(); + private final BindingRoutesJsonApiHandler routesHandler; + + @Reference(// + target = "(entry=" + ENTRY_POINT + ")", // + policyOption = ReferencePolicyOption.GREEDY, // + policy = ReferencePolicy.DYNAMIC, // + cardinality = ReferenceCardinality.MULTIPLE // + ) + protected void bindHandler(JsonApi handler) { + this.binder.bindJsonApi(handler); + this.routesHandler.setBuilder(this.binder.getJsonApiBuilder()); + } + + protected void unbindHandler(JsonApi handler) { + this.binder.unbindJsonApi(handler); + this.routesHandler.setBuilder(null); + } + + @Activate + public RootRequestHandler(@Reference BindingRoutesJsonApiHandler routesHandler) { + this.routesHandler = routesHandler; + } + + @Override + public void buildJsonApiRoutes(JsonApiBuilder builder) { + builder.addBuilder(this.binder.getJsonApiBuilder()); + } + +} diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/handler/SubscribeSystemLogJsonApiHandler.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/handler/SubscribeSystemLogJsonApiHandler.java new file mode 100644 index 00000000000..856bc85beaf --- /dev/null +++ b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/handler/SubscribeSystemLogJsonApiHandler.java @@ -0,0 +1,63 @@ +package io.openems.edge.controller.api.backend.handler; + +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.ops4j.pax.logging.spi.PaxAppender; +import org.ops4j.pax.logging.spi.PaxLoggingEvent; +import org.osgi.service.component.annotations.Component; + +import io.openems.common.exceptions.OpenemsException; +import io.openems.common.jsonrpc.base.GenericJsonrpcResponseSuccess; +import io.openems.common.jsonrpc.notification.SystemLogNotification; +import io.openems.common.jsonrpc.request.SubscribeSystemLogRequest; +import io.openems.common.jsonrpc.response.AuthenticatedRpcResponse; +import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.JsonApiBuilder; +import io.openems.edge.controller.api.backend.ControllerApiBackendImpl; +import io.openems.edge.controller.api.backend.WebsocketClient; + +@Component(property = { // + "entry=" + AuthenticatedRequestHandler.ENTRY_POINT, // + "org.ops4j.pax.logging.appender.name=Controller.Api.Backend", // +}) +public class SubscribeSystemLogJsonApiHandler implements JsonApi, PaxAppender { + + private final Set subscriber = ConcurrentHashMap.newKeySet(); + + @Override + public void buildJsonApiRoutes(JsonApiBuilder builder) { + builder.handleRequest(SubscribeSystemLogRequest.METHOD, call -> { + final var webSocket = call.get(ControllerApiBackendImpl.WEBSOCKET_CLIENT_KEY); + if (webSocket == null) { + throw new OpenemsException("Websocket is not defined."); + } + final var request = SubscribeSystemLogRequest.from(call.getRequest()); + if (request.isSubscribe()) { + this.subscriber.add(webSocket); + } else { + this.subscriber.remove(webSocket); + } + + return new AuthenticatedRpcResponse(call.getRequest().getId(), + new GenericJsonrpcResponseSuccess(request.getId())); + }); + } + + @Override + public void doAppend(PaxLoggingEvent event) { + if (this.subscriber.isEmpty()) { + return; + } + + final var notification = SystemLogNotification.fromPaxLoggingEvent(event); + final var iterator = this.subscriber.iterator(); + while (iterator.hasNext()) { + final var ws = iterator.next(); + if (!ws.sendMessage(notification)) { + iterator.remove(); + } + } + } + +} \ No newline at end of file diff --git a/io.openems.edge.controller.api.backend/test/io/openems/edge/controller/api/backend/ControllerApiBackendImplTest.java b/io.openems.edge.controller.api.backend/test/io/openems/edge/controller/api/backend/ControllerApiBackendImplTest.java index d5d49a61b28..9d594615157 100644 --- a/io.openems.edge.controller.api.backend/test/io/openems/edge/controller/api/backend/ControllerApiBackendImplTest.java +++ b/io.openems.edge.controller.api.backend/test/io/openems/edge/controller/api/backend/ControllerApiBackendImplTest.java @@ -40,6 +40,7 @@ public void test() throws Exception { .addReference("componentManager", new DummyComponentManager(clock)) // .addReference("cycle", new DummyCycle(1000)) // .addReference("resendHistoricDataWorkerFactory", new DummyResendHistoricDataWorkerFactory()) // + .addReference("requestHandlerFactory", new DummyBackendOnRequestFactory()) // .addReference("oem", new DummyOpenemsEdgeOem()) // .addComponent(new DummySum()) // .activate(MyConfig.create() // diff --git a/io.openems.edge.controller.api.backend/test/io/openems/edge/controller/api/backend/DummyBackendOnRequestFactory.java b/io.openems.edge.controller.api.backend/test/io/openems/edge/controller/api/backend/DummyBackendOnRequestFactory.java new file mode 100644 index 00000000000..05aed052db3 --- /dev/null +++ b/io.openems.edge.controller.api.backend/test/io/openems/edge/controller/api/backend/DummyBackendOnRequestFactory.java @@ -0,0 +1,41 @@ +package io.openems.edge.controller.api.backend; + +import java.lang.reflect.InvocationTargetException; + +import org.osgi.framework.ServiceReference; +import org.osgi.service.component.ComponentServiceObjects; + +import io.openems.common.utils.ReflectionUtils; +import io.openems.edge.controller.api.backend.handler.BindingRoutesJsonApiHandler; +import io.openems.edge.controller.api.backend.handler.RootRequestHandler; +import io.openems.edge.controller.api.common.handler.RoutesJsonApiHandler; + +public class DummyBackendOnRequestFactory extends BackendOnRequest.Factory { + + public DummyBackendOnRequestFactory() + throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { + super(); + ReflectionUtils.setAttribute(BackendOnRequest.Factory.class, this, "cso", new DummyBackendOnRequestCso()); + } + + private static class DummyBackendOnRequestCso implements ComponentServiceObjects { + + @Override + public BackendOnRequest getService() { + return new BackendOnRequest( + new RootRequestHandler(new BindingRoutesJsonApiHandler(new RoutesJsonApiHandler()))); + } + + @Override + public void ungetService(BackendOnRequest service) { + // empty for tests + } + + @Override + public ServiceReference getServiceReference() { + // empty for tests + return null; + } + } + +} diff --git a/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/handler/ComponentConfigRequestHandler.java b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/handler/ComponentConfigRequestHandler.java new file mode 100644 index 00000000000..1eb5cb4f331 --- /dev/null +++ b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/handler/ComponentConfigRequestHandler.java @@ -0,0 +1,87 @@ +package io.openems.edge.controller.api.common.handler; + +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ServiceScope; + +import io.openems.common.jsonrpc.request.ComponentJsonApiRequest; +import io.openems.common.jsonrpc.request.CreateComponentConfigRequest; +import io.openems.common.jsonrpc.request.DeleteComponentConfigRequest; +import io.openems.common.jsonrpc.request.GetEdgeConfigRequest; +import io.openems.common.jsonrpc.request.SetChannelValueRequest; +import io.openems.common.jsonrpc.request.UpdateComponentConfigRequest; +import io.openems.common.session.Role; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.common.jsonapi.EdgeGuards; +import io.openems.edge.common.jsonapi.EdgeKeys; +import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.JsonApiBuilder; +import io.openems.edge.common.jsonapi.Key; +import io.openems.edge.controller.api.common.ApiWorker; + +@Component(service = { ComponentConfigRequestHandler.class, JsonApi.class }, scope = ServiceScope.SINGLETON) +public class ComponentConfigRequestHandler implements JsonApi { + + public static final Key API_WORKER_KEY = new Key<>("apiWorker", ApiWorker.class); + + private final ComponentManager componentManager; + + @Activate + public ComponentConfigRequestHandler(@Reference ComponentManager componentManager) { + this.componentManager = componentManager; + } + + @Override + public void buildJsonApiRoutes(JsonApiBuilder builder) { + builder.delegate(GetEdgeConfigRequest.METHOD, endpoint -> { + endpoint.setDescription(""" + Handles a GetEdgeConfigRequest. + Delegates original request to a ComponentJsonApiRequest. + """); + }, call -> { + return new ComponentJsonApiRequest(ComponentManager.SINGLETON_COMPONENT_ID, + GetEdgeConfigRequest.from(call.getRequest())); + }); + + builder.delegate(CreateComponentConfigRequest.METHOD, endpoint -> { + endpoint.setDescription(""" + Handles a CreateComponentConfigRequest. + Delegates original request to a ComponentJsonApiRequest. + """); + }, call -> { + return new ComponentJsonApiRequest(ComponentManager.SINGLETON_COMPONENT_ID, + CreateComponentConfigRequest.from(call.getRequest())); + }); + + builder.delegate(UpdateComponentConfigRequest.METHOD, endpoint -> { + endpoint.setDescription(""" + Handles a UpdateComponentConfigRequest. + Delegates original request to a ComponentJsonApiRequest. + """); + }, call -> { + return new ComponentJsonApiRequest(ComponentManager.SINGLETON_COMPONENT_ID, + UpdateComponentConfigRequest.from(call.getRequest())); + }); + + builder.delegate(DeleteComponentConfigRequest.METHOD, endpoint -> { + endpoint.setDescription(""" + Handles a DeleteComponentConfigRequest. + Delegates original request to a ComponentJsonApiRequest. + """); + }, call -> { + return new ComponentJsonApiRequest(ComponentManager.SINGLETON_COMPONENT_ID, + DeleteComponentConfigRequest.from(call.getRequest())); + }); + + builder.handleRequest(SetChannelValueRequest.METHOD, endpoint -> { + endpoint.setDescription("Handles a SetChannelValueRequest") // + .setGuards(EdgeGuards.roleIsAtleast(Role.ADMIN)); + }, call -> { + final var apiWorker = call.get(API_WORKER_KEY); + return apiWorker.handleSetChannelValueRequest(this.componentManager, call.get(EdgeKeys.USER_KEY), + SetChannelValueRequest.from(call.getRequest())).get(); + }); + } + +} \ No newline at end of file diff --git a/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/handler/ComponentRequestHandler.java b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/handler/ComponentRequestHandler.java new file mode 100644 index 00000000000..bf04173b4c3 --- /dev/null +++ b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/handler/ComponentRequestHandler.java @@ -0,0 +1,145 @@ +package io.openems.edge.controller.api.common.handler; + +import java.util.Map; +import java.util.TreeMap; +import java.util.function.Consumer; + +import org.osgi.framework.Constants; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.component.annotations.ServiceScope; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.openems.common.jsonrpc.request.ComponentJsonApiRequest; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.common.jsonapi.ComponentJsonApi; +import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.JsonApiBuilder; +import io.openems.edge.common.jsonapi.JsonApiEndpoint; +import io.openems.edge.common.jsonapi.Subrequest; +import io.openems.edge.common.jsonapi.Tag; + +/** + * This class handles {@link ComponentJsonApiRequest} and delegates the request + * to their component. + */ +@Component(service = { ComponentRequestHandler.class, JsonApi.class }, scope = ServiceScope.SINGLETON) +public class ComponentRequestHandler implements JsonApi { + + private record BoundComponentJsonApi(// + long serviceId, // + JsonApiBuilder apiBuilder, // + Consumer endpointListener // + ) { + + public ComponentRequestHandler.BoundComponentJsonApi with(Consumer endpointListener) { + return new BoundComponentJsonApi(this.serviceId, this.apiBuilder, endpointListener); + } + + } + + private final Logger log = LoggerFactory.getLogger(ComponentRequestHandler.class); + + private final Map jsonApis = new TreeMap<>(); + + /** + * Binds a {@link ComponentJsonApi}. + * + * @param jsonApi the {@link ComponentJsonApi} to bind + * @param ref the OSGi component properties + */ + @Reference(// + policy = ReferencePolicy.DYNAMIC, // + bind = "bindJsonApi", unbind = "unbindJsonApi", // + updated = "updateJsonApi", // + policyOption = ReferencePolicyOption.GREEDY, // + cardinality = ReferenceCardinality.MULTIPLE // + ) + public void bindJsonApi(ComponentJsonApi jsonApi, Map ref) { + final var builder = new JsonApiBuilder(); + + final var boundComponent = new BoundComponentJsonApi(// + (Long) ref.get(Constants.SERVICE_ID), // + builder, // + t -> t.getDef().getTags().add(new Tag(jsonApi.id())) // + ); + + builder.addEndpointAddedListener(boundComponent.endpointListener()); + jsonApi.buildJsonApiRoutes(builder); + this.jsonApis.put(jsonApi.id(), boundComponent); + this.log.info("Added '" + jsonApi.id() + "' to Component Apis."); + + } + + /** + * Updates a {@link ComponentJsonApi} on configuration change. + * + * @param jsonApi the {@link ComponentJsonApi} to update + * @param ref the updated OSGi component properties + */ + public void updateJsonApi(ComponentJsonApi jsonApi, Map ref) { + final long servicePid = (Long) ref.get(Constants.SERVICE_ID); + for (var entry : this.jsonApis.entrySet()) { + if (entry.getValue().serviceId() != servicePid) { + continue; + } + final var previousComponentId = entry.getKey(); + final var prevBinding = this.jsonApis.remove(previousComponentId); + for (var endpoint : prevBinding.apiBuilder().getEndpoints().values()) { + endpoint.getDef().getTags().removeIf(t -> t.name().equals(previousComponentId)); + endpoint.getDef().getTags().add(new Tag(jsonApi.id())); + } + prevBinding.apiBuilder().removeEndpointAddedListener(prevBinding.endpointListener()); + final var newBinding = prevBinding.with(t -> t.getDef().getTags().add(new Tag(jsonApi.id()))); + prevBinding.apiBuilder().addEndpointAddedListener(newBinding.endpointListener()); + + this.jsonApis.put(jsonApi.id(), newBinding); + break; + } + this.log.info("Updated Component Api " + jsonApi.id()); + } + + /** + * Unbinds a {@link ComponentJsonApi}. + * + * @param jsonApi the {@link ComponentJsonApi} to remove + * @param ref the updated OSGi component properties + */ + public void unbindJsonApi(ComponentJsonApi jsonApi, Map ref) { + this.jsonApis.remove(jsonApi.id()); + this.log.info("Removed '" + jsonApi.id() + "' from Component Apis."); + } + + @Override + public void buildJsonApiRoutes(JsonApiBuilder builder) { + builder.rpc(ComponentJsonApiRequest.METHOD, endpoint -> { + endpoint.setDescription("Handles a ComponentJsonApiRequest."); + + }, () -> { + return this.jsonApis.entrySet().stream() // + .map(jsonApiEntry -> { + final var subrequest = new Subrequest(JsonUtils.buildJsonObject() // + .addProperty("componentId", jsonApiEntry.getKey()) // + .build()); + + subrequest.addRpcBuilderFor(jsonApiEntry.getValue().apiBuilder(), "payload"); + return subrequest; + }).toList(); + }, call -> { + final var request = ComponentJsonApiRequest.from(call.getRequest()); + final var component = this.jsonApis.get(request.getComponentId()); + if (component == null) { + throw new RuntimeException("Component with id '" + request.getComponentId() + "' was not found"); + } + var mapped = call.mapRequest(request.getPayload()); + component.apiBuilder().handle(mapped); + + call.setResponse(mapped.getResponse()); + }); + } + +} \ No newline at end of file diff --git a/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/handler/QueryRequestHandler.java b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/handler/QueryRequestHandler.java new file mode 100644 index 00000000000..9bed397860b --- /dev/null +++ b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/handler/QueryRequestHandler.java @@ -0,0 +1,73 @@ +package io.openems.edge.controller.api.common.handler; + +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; + +import io.openems.common.exceptions.OpenemsException; +import io.openems.common.jsonrpc.request.QueryHistoricTimeseriesDataRequest; +import io.openems.common.jsonrpc.request.QueryHistoricTimeseriesEnergyPerPeriodRequest; +import io.openems.common.jsonrpc.request.QueryHistoricTimeseriesEnergyRequest; +import io.openems.common.jsonrpc.request.QueryHistoricTimeseriesExportXlxsRequest; +import io.openems.common.jsonrpc.response.QueryHistoricTimeseriesDataResponse; +import io.openems.common.jsonrpc.response.QueryHistoricTimeseriesEnergyPerPeriodResponse; +import io.openems.common.jsonrpc.response.QueryHistoricTimeseriesEnergyResponse; +import io.openems.edge.common.jsonapi.EdgeKeys; +import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.JsonApiBuilder; +import io.openems.edge.timedata.api.Timedata; + +@Component(service = { QueryRequestHandler.class, JsonApi.class }) +public class QueryRequestHandler implements JsonApi { + + @Reference(// + policy = ReferencePolicy.DYNAMIC, // + policyOption = ReferencePolicyOption.GREEDY, // + cardinality = ReferenceCardinality.OPTIONAL // + ) + private volatile Timedata timedata; + + @Override + public void buildJsonApiRoutes(JsonApiBuilder builder) { + builder.handleRequest(QueryHistoricTimeseriesDataRequest.METHOD, call -> { + final var data = this.getTimedata().queryHistoricData(// + null, /* ignore Edge-ID */ + QueryHistoricTimeseriesDataRequest.from(call.getRequest())); + + return new QueryHistoricTimeseriesDataResponse(call.getRequest().getId(), data); + }); + + builder.handleRequest(QueryHistoricTimeseriesEnergyRequest.METHOD, call -> { + final var request = QueryHistoricTimeseriesEnergyRequest.from(call.getRequest()); + final var data = this.getTimedata().queryHistoricEnergy(// + null, /* ignore Edge-ID */ + request.getFromDate(), request.getToDate(), request.getChannels()); + return new QueryHistoricTimeseriesEnergyResponse(request.getId(), data); + }); + + builder.handleRequest(QueryHistoricTimeseriesEnergyPerPeriodRequest.METHOD, call -> { + final var request = QueryHistoricTimeseriesEnergyPerPeriodRequest.from(call.getRequest()); + var data = this.getTimedata().queryHistoricEnergyPerPeriod(// + null, /* ignore Edge-ID */ + request.getFromDate(), request.getToDate(), request.getChannels(), request.getResolution()); + return new QueryHistoricTimeseriesEnergyPerPeriodResponse(request.getId(), data); + }); + + builder.handleRequest(QueryHistoricTimeseriesExportXlxsRequest.METHOD, call -> { + final var request = QueryHistoricTimeseriesExportXlxsRequest.from(call.getRequest()); + return this.getTimedata().handleQueryHistoricTimeseriesExportXlxsRequest(null /* ignore Edge-ID */, request, + call.get(EdgeKeys.USER_KEY).getLanguage()); + }); + } + + private final Timedata getTimedata() throws OpenemsException { + final var currentTimedata = this.timedata; + if (currentTimedata == null) { + throw new OpenemsException("There is no Timedata-Service available!"); + } + return currentTimedata; + } + +} diff --git a/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/handler/RoutesJsonApiHandler.java b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/handler/RoutesJsonApiHandler.java new file mode 100644 index 00000000000..4cceb550d83 --- /dev/null +++ b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/handler/RoutesJsonApiHandler.java @@ -0,0 +1,134 @@ +package io.openems.edge.controller.api.common.handler; + +import static io.openems.common.utils.JsonUtils.toJsonArray; +import static java.util.Collections.emptyList; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.stream.Stream; + +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ServiceScope; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; + +import io.openems.common.exceptions.OpenemsException; +import io.openems.common.jsonrpc.base.GenericJsonrpcResponseSuccess; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.JsonApiBuilder; +import io.openems.edge.common.jsonapi.JsonApiEndpoint; +import io.openems.edge.common.jsonapi.JsonrpcRoleEndpointGuard; +import io.openems.edge.common.jsonapi.Subrequest; +import io.openems.edge.common.jsonapi.Tag; + +@Component(// + service = { RoutesJsonApiHandler.class, JsonApi.class }, // + scope = ServiceScope.PROTOTYPE // +) +public class RoutesJsonApiHandler implements JsonApi { + + private JsonApiBuilder builder; + + @Override + public void buildJsonApiRoutes(JsonApiBuilder builder) { + builder.handleRequest("routes", call -> { + final var b = this.getBuilder(); + if (b == null) { + throw new OpenemsException("Builder is not yet set."); + } + + final var result = getAllRequests(emptyList(), b); + + return new GenericJsonrpcResponseSuccess(call.getRequest().getId(), JsonUtils.buildJsonObject() // + .addProperty("version", "1") // + .add("endpoints", result.stream().collect(toJsonArray())) // + .build()); + }); + } + + public JsonApiBuilder getBuilder() { + return this.builder; + } + + public void setBuilder(JsonApiBuilder builder) { + this.builder = builder; + } + + private record EndpointParent(JsonApiEndpoint parentEndpoint, JsonElement baseRequest, String[] path) { + + } + + private static final List getAllRequests(List parent, JsonApiBuilder builder) { + final var result = new ArrayList(); + for (var entry : builder.getEndpoints().entrySet()) { + final var def = entry.getValue().getDef(); + + final var parentArray = parent.stream() // + .map(t -> JsonUtils.buildJsonObject() // + .addProperty("method", t.parentEndpoint().getMethod()) // + .add("request", JsonUtils.buildJsonObject() // + .add("base", t.baseRequest()) // + .add("pathToSubrequest", Stream.of(t.path()) // + .map(JsonPrimitive::new) // + .collect(toJsonArray())) // + .build()) + .build()) // + .collect(toJsonArray()); + + final var resultJson = JsonUtils.buildJsonObject() // + .addProperty("method", entry.getKey()) // + .addPropertyIfNotNull("description", def.getDescription()) // + .add("tags", def.getTags().stream() // + .map(Tag.serializer()::serialize) // + .collect(toJsonArray())) + .add("guards", def.getGuards().stream() // + .map(t -> { + if (t instanceof JsonrpcRoleEndpointGuard a) { + return JsonrpcRoleEndpointGuard.serializer().serialize(a); + } + return null; + }) // + .filter(Objects::nonNull) // + .collect(toJsonArray())) + .add("parent", parentArray); + + def.applyRequestBuilder(request -> { + resultJson.add("request", JsonUtils.buildJsonObject() // + .onlyIf(request.getSerializer() != null, t -> { + t.add("json", request.getSerializer().descriptor().toJson()) // + .add("examples", request.createExampleArray()); + }).build()); + }); + + def.applyResponseBuilder(response -> { + resultJson.add("response", JsonUtils.buildJsonObject() // + .onlyIf(response.getSerializer() != null, t -> { + t.add("json", response.getSerializer().descriptor().toJson()) // + .add("examples", response.createExampleArray()); + }).build()); + }); + + result.add(resultJson.build()); + + final List subroutes = entry.getValue().getSubroutes() != null + ? entry.getValue().getSubroutes().get() + : emptyList(); + + for (var subroute : subroutes) { + for (var b : subroute.getSubrouteToBuilder()) { + var currentParent = new EndpointParent(entry.getValue(), subroute.getBaseRequest(), b.path()); + final var subparents = new ArrayList<>(parent); + subparents.add(currentParent); + result.addAll(getAllRequests(subparents, b.builder())); + } + } + + } + return result; + } + +} \ No newline at end of file diff --git a/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/handler/package-info.java b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/handler/package-info.java new file mode 100644 index 00000000000..26261007ee9 --- /dev/null +++ b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/handler/package-info.java @@ -0,0 +1,3 @@ +@org.osgi.annotation.versioning.Version("1.0.0") +@org.osgi.annotation.bundle.Export +package io.openems.edge.controller.api.common.handler; diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusTcpApi.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusTcpApi.java index 63246fe38c2..d862b6c7177 100644 --- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusTcpApi.java +++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusTcpApi.java @@ -2,7 +2,6 @@ import java.util.List; import java.util.TreeMap; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.CopyOnWriteArrayList; import org.osgi.service.cm.ConfigurationAdmin; @@ -16,15 +15,15 @@ import io.openems.common.channel.AccessMode; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; -import io.openems.common.jsonrpc.base.JsonrpcRequest; -import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; import io.openems.common.utils.ConfigUtils; import io.openems.common.worker.AbstractWorker; import io.openems.edge.common.channel.Channel; import io.openems.edge.common.channel.WriteChannel; import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.ComponentJsonApi; +import io.openems.edge.common.jsonapi.JsonApiBuilder; +import io.openems.edge.common.jsonapi.JsonrpcEndpointGuard; import io.openems.edge.common.meta.Meta; import io.openems.edge.common.modbusslave.ModbusRecord; import io.openems.edge.common.modbusslave.ModbusRecordChannel; @@ -34,7 +33,6 @@ import io.openems.edge.common.modbusslave.ModbusRecordUint16Hash; import io.openems.edge.common.modbusslave.ModbusSlave; import io.openems.edge.common.modbusslave.ModbusSlaveNatureTable; -import io.openems.edge.common.user.User; import io.openems.edge.controller.api.Controller; import io.openems.edge.controller.api.common.ApiWorker; import io.openems.edge.controller.api.common.WritePojo; @@ -44,7 +42,7 @@ import io.openems.edge.controller.api.modbus.jsonrpc.GetModbusProtocolResponse; public abstract class AbstractModbusTcpApi extends AbstractOpenemsComponent - implements ModbusTcpApi, Controller, OpenemsComponent, JsonApi { + implements ModbusTcpApi, Controller, OpenemsComponent, ComponentJsonApi { public static final int UNIT_ID = 1; public static final int DEFAULT_PORT = 502; @@ -377,25 +375,33 @@ protected void logWarn(Logger log, String message) { } @Override - public CompletableFuture handleJsonrpcRequest(User user, JsonrpcRequest message) - throws OpenemsNamedException { - if (this.getComponentMissingFault().get() == Boolean.TRUE) { - throw new OpenemsException(this.getComponentMissingFaultChannel().channelDoc().getText()); - } - if (this.getComponentNoModbusApiFault().get() == Boolean.TRUE) { - throw new OpenemsException(this.getComponentNoModbusApiFaultChannel().channelDoc().getText()); - } - - switch (message.getMethod()) { - case GetModbusProtocolRequest.METHOD: - return CompletableFuture.completedFuture(new GetModbusProtocolResponse(message.getId(), this.records)); + public void buildJsonApiRoutes(JsonApiBuilder builder) { + builder.handleRequest(GetModbusProtocolRequest.METHOD, def -> { + def.setGuards(this.componentMissingGuard(), this.componentNoModbusApiGuard()); + }, call -> { + return new GetModbusProtocolResponse(call.getRequest().getId(), this.records); + }); + builder.handleRequest(GetModbusProtocolExportXlsxRequest.METHOD, def -> { + def.setGuards(this.componentMissingGuard(), this.componentNoModbusApiGuard()); + }, call -> { + return new GetModbusProtocolExportXlsxResponse(call.getRequest().getId(), this.components, this.records); + }); + } - case GetModbusProtocolExportXlsxRequest.METHOD: - return CompletableFuture.completedFuture( - new GetModbusProtocolExportXlsxResponse(message.getId(), this.components, this.records)); + private JsonrpcEndpointGuard componentMissingGuard() { + return call -> { + if (this.getComponentMissingFault().get() == Boolean.TRUE) { + throw new OpenemsException(this.getComponentMissingFaultChannel().channelDoc().getText()); + } + }; + } - } - return null; + private JsonrpcEndpointGuard componentNoModbusApiGuard() { + return call -> { + if (this.getComponentNoModbusApiFault().get() == Boolean.TRUE) { + throw new OpenemsException(this.getComponentNoModbusApiFaultChannel().channelDoc().getText()); + } + }; } /** diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/ControllerApiModbusTcpReadOnlyImpl.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/ControllerApiModbusTcpReadOnlyImpl.java index 187c6548c7d..b983cbd8df4 100644 --- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/ControllerApiModbusTcpReadOnlyImpl.java +++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/ControllerApiModbusTcpReadOnlyImpl.java @@ -17,7 +17,7 @@ import io.openems.common.channel.AccessMode; import io.openems.common.exceptions.OpenemsException; import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.ComponentJsonApi; import io.openems.edge.common.meta.Meta; import io.openems.edge.controller.api.Controller; import io.openems.edge.controller.api.modbus.AbstractModbusTcpApi; @@ -30,7 +30,7 @@ configurationPolicy = ConfigurationPolicy.REQUIRE // ) public class ControllerApiModbusTcpReadOnlyImpl extends AbstractModbusTcpApi - implements ControllerApiModbusTcpReadOnly, ModbusTcpApi, Controller, OpenemsComponent, JsonApi { + implements ControllerApiModbusTcpReadOnly, ModbusTcpApi, Controller, OpenemsComponent, ComponentJsonApi { @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) private Meta metaComponent = null; diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImpl.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImpl.java index a29416d1146..af51ee0b092 100644 --- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImpl.java +++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImpl.java @@ -17,7 +17,7 @@ import io.openems.common.channel.AccessMode; import io.openems.common.exceptions.OpenemsException; import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.ComponentJsonApi; import io.openems.edge.common.meta.Meta; import io.openems.edge.controller.api.Controller; import io.openems.edge.controller.api.modbus.AbstractModbusTcpApi; @@ -30,7 +30,7 @@ configurationPolicy = ConfigurationPolicy.REQUIRE // ) public class ControllerApiModbusTcpReadWriteImpl extends AbstractModbusTcpApi - implements ControllerApiModbusTcpReadWrite, ModbusTcpApi, Controller, OpenemsComponent, JsonApi { + implements ControllerApiModbusTcpReadWrite, ModbusTcpApi, Controller, OpenemsComponent, ComponentJsonApi { @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) private Meta metaComponent = null; diff --git a/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/AbstractRestApi.java b/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/AbstractRestApi.java index 6bdc7228e31..db1d16228f7 100644 --- a/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/AbstractRestApi.java +++ b/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/AbstractRestApi.java @@ -12,15 +12,14 @@ import io.openems.common.channel.AccessMode; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.exceptions.OpenemsException; import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.user.UserService; import io.openems.edge.controller.api.Controller; import io.openems.edge.controller.api.common.ApiWorker; +import io.openems.edge.controller.api.common.handler.ComponentConfigRequestHandler; import io.openems.edge.controller.api.rest.readonly.ControllerApiRestReadOnlyImpl; -import io.openems.edge.timedata.api.Timedata; public abstract class AbstractRestApi extends AbstractOpenemsComponent implements RestApi, Controller, OpenemsComponent { @@ -83,6 +82,10 @@ protected void activate(ComponentContext context, String id, String alias, boole "Unable to start " + this.implementationName + " on port [" + port + "]: " + e.getMessage()); this._setUnableToStart(true); } + + this.getRpcRestHandler().setOnCall(call -> { + call.put(ComponentConfigRequestHandler.API_WORKER_KEY, this.apiWorker); + }); } @Override @@ -122,14 +125,6 @@ protected boolean isDebugModeEnabled() { return this.isDebugModeEnabled; } - /** - * Gets the Timedata service. - * - * @return the service - * @throws OpenemsException if the timeservice is not available - */ - protected abstract Timedata getTimedata() throws OpenemsException; - /** * Gets the UserService. * @@ -144,6 +139,13 @@ protected boolean isDebugModeEnabled() { */ protected abstract ComponentManager getComponentManager(); + /** + * Gets the JsonRpcRestHandler. + * + * @return the service + */ + protected abstract JsonRpcRestHandler getRpcRestHandler(); + /** * Gets the AccessMode. * diff --git a/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/JsonRpcRestHandler.java b/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/JsonRpcRestHandler.java new file mode 100644 index 00000000000..0421bfa8a49 --- /dev/null +++ b/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/JsonRpcRestHandler.java @@ -0,0 +1,109 @@ +package io.openems.edge.controller.api.rest; + +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; + +import org.osgi.service.component.ComponentServiceObjects; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.component.annotations.ServiceScope; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.jsonrpc.base.JsonrpcRequest; +import io.openems.common.jsonrpc.base.JsonrpcResponse; +import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; +import io.openems.common.utils.FunctionUtils; +import io.openems.edge.common.jsonapi.Call; +import io.openems.edge.common.jsonapi.EdgeKeys; +import io.openems.edge.common.jsonapi.SingleJsonApiBinder; +import io.openems.edge.common.user.User; +import io.openems.edge.controller.api.rest.handler.RootRequestHandler; + +@Component(// + scope = ServiceScope.PROTOTYPE, // + service = JsonRpcRestHandler.class // +) +public class JsonRpcRestHandler { + + @Component(service = JsonRpcRestHandler.Factory.class) + public static class Factory { + + @Reference + private ComponentServiceObjects cso; + + /** + * Returns a new {@link JsonRpcRestHandler} service object. + * + * @return the created {@link JsonRpcRestHandler} object + * @see #unget(JsonRpcRestHandler) + */ + public JsonRpcRestHandler get() { + return this.cso.getService(); + } + + /** + * Releases the {@link JsonRpcRestHandler} service object. + * + * @param service a {@link JsonRpcRestHandler} provided by this factory + * @see #get() + */ + public void unget(JsonRpcRestHandler service) { + if (service == null) { + return; + } + this.cso.ungetService(service); + } + + } + + private final SingleJsonApiBinder apiBinder = new SingleJsonApiBinder(); + + private Consumer> onCall = FunctionUtils::doNothing; + + /** + * Binds the {@link RootRequestHandler}. + * + * @param rootHandler the handler + */ + @Reference(// + cardinality = ReferenceCardinality.OPTIONAL, // + policy = ReferencePolicy.DYNAMIC, // + policyOption = ReferencePolicyOption.GREEDY // + ) + public void bindRootHandler(RootRequestHandler rootHandler) { + this.apiBinder.bind(rootHandler); + } + + /** + * Unbinds the {@link RootRequestHandler}. + * + * @param rootHandler the handler + */ + public void unbindRootHandler(RootRequestHandler rootHandler) { + this.apiBinder.unbind(); + } + + /** + * Handles a rest request. + * + * @param user the user of the current request + * @param request the request to handle + * @return the result future + * @throws OpenemsNamedException on error + */ + public CompletableFuture handleRequest(User user, JsonrpcRequest request) + throws OpenemsNamedException { + return this.apiBinder.handleRequest(request, call -> { + call.put(EdgeKeys.USER_KEY, user); + this.onCall.accept(call); + }); + } + + public void setOnCall(Consumer> onCall) { + this.onCall = onCall == null ? FunctionUtils::doNothing : onCall; + } + +} diff --git a/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/RestHandler.java b/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/RestHandler.java index ea542953acb..1819afa7696 100644 --- a/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/RestHandler.java +++ b/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/RestHandler.java @@ -8,10 +8,8 @@ import java.util.Arrays; import java.util.Base64; import java.util.List; -import java.util.Map; import java.util.StringTokenizer; import java.util.UUID; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; @@ -29,30 +27,18 @@ import io.openems.common.exceptions.OpenemsError; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; -import io.openems.common.jsonrpc.base.GenericJsonrpcResponseSuccess; import io.openems.common.jsonrpc.base.JsonrpcMessage; import io.openems.common.jsonrpc.base.JsonrpcRequest; import io.openems.common.jsonrpc.base.JsonrpcResponseError; import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; -import io.openems.common.jsonrpc.request.ComponentJsonApiRequest; -import io.openems.common.jsonrpc.request.CreateComponentConfigRequest; -import io.openems.common.jsonrpc.request.DeleteComponentConfigRequest; -import io.openems.common.jsonrpc.request.GetEdgeConfigRequest; -import io.openems.common.jsonrpc.request.QueryHistoricTimeseriesDataRequest; -import io.openems.common.jsonrpc.request.QueryHistoricTimeseriesEnergyRequest; import io.openems.common.jsonrpc.request.SetChannelValueRequest; -import io.openems.common.jsonrpc.request.UpdateComponentConfigRequest; -import io.openems.common.jsonrpc.response.QueryHistoricTimeseriesDataResponse; -import io.openems.common.jsonrpc.response.QueryHistoricTimeseriesEnergyResponse; import io.openems.common.session.Role; import io.openems.common.types.ChannelAddress; import io.openems.common.utils.JsonUtils; import io.openems.common.utils.StringUtils; import io.openems.common.utils.UuidUtils; import io.openems.edge.common.channel.Channel; -import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.common.jsonapi.JsonApi; import io.openems.edge.common.user.User; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -432,7 +418,7 @@ private void handleJsonRpc(User user, Request baseRequest, HttpServletRequest ht requestId = request.getId(); // handle the request - var responseFuture = this.handleJsonRpcRequest(user, request); + var responseFuture = this.parent.getRpcRestHandler().handleRequest(user, request); // wait for response JsonrpcResponseSuccess response; @@ -453,194 +439,4 @@ private void handleJsonRpc(User user, Request baseRequest, HttpServletRequest ht } } - /** - * Handles an JSON-RPC Request. - * - * @param user the {@link User} - * @param request the {@link JsonrpcRequest} - * @return the JSON-RPC Success Response Future - * @throws OpenemsException on error - */ - private CompletableFuture handleJsonRpcRequest(User user, JsonrpcRequest request) - throws OpenemsException, OpenemsNamedException { - switch (request.getMethod()) { - - case QueryHistoricTimeseriesDataRequest.METHOD: - return this.handleQueryHistoricDataRequest(user, QueryHistoricTimeseriesDataRequest.from(request)); - - case QueryHistoricTimeseriesEnergyRequest.METHOD: - return this.handleQueryHistoricEnergyRequest(user, QueryHistoricTimeseriesEnergyRequest.from(request)); - - case GetEdgeConfigRequest.METHOD: - return this.handleGetEdgeConfigRequest(user, GetEdgeConfigRequest.from(request)); - - case CreateComponentConfigRequest.METHOD: - return this.handleCreateComponentConfigRequest(user, CreateComponentConfigRequest.from(request)); - - case UpdateComponentConfigRequest.METHOD: - return this.handleUpdateComponentConfigRequest(user, UpdateComponentConfigRequest.from(request)); - - case DeleteComponentConfigRequest.METHOD: - return this.handleDeleteComponentConfigRequest(user, DeleteComponentConfigRequest.from(request)); - - case ComponentJsonApiRequest.METHOD: - return this.handleComponentJsonApiRequest(user, ComponentJsonApiRequest.from(request)); - - default: - this.parent.logWarn(this.log, "Unhandled Request: " + request); - throw OpenemsError.JSONRPC_UNHANDLED_METHOD.exception(request.getMethod()); - } - } - - /** - * Handles a QueryHistoricDataRequest. - * - * @param user the {@link User} - * @param request the {@link QueryHistoricTimeseriesDataRequest} - * @return the Future JSON-RPC Response - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleQueryHistoricDataRequest(User user, - QueryHistoricTimeseriesDataRequest request) throws OpenemsNamedException { - var data = this.parent.getTimedata().queryHistoricData(// - null, /* ignore Edge-ID */ - request); - - // JSON-RPC response - return CompletableFuture.completedFuture(new QueryHistoricTimeseriesDataResponse(request.getId(), data)); - } - - /** - * Handles a QueryHistoricEnergyRequest. - * - * @param user the {@link User} - * @param request the {@link QueryHistoricTimeseriesEnergyRequest} - * @return the Future JSPN-RPC Response - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleQueryHistoricEnergyRequest(User user, - QueryHistoricTimeseriesEnergyRequest request) throws OpenemsNamedException { - Map data = this.parent.getTimedata().queryHistoricEnergy(// - null, /* ignore Edge-ID */ - request.getFromDate(), request.getToDate(), request.getChannels()); - - // JSON-RPC response - return CompletableFuture.completedFuture(new QueryHistoricTimeseriesEnergyResponse(request.getId(), data)); - } - - /** - * Handles a GetEdgeConfigRequest. - * - * @param user the {@link User} - * @param getEdgeConfigRequest the {@link GetEdgeConfigRequest} - * @return the JSON-RPC Success Response Future - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleGetEdgeConfigRequest(User user, - GetEdgeConfigRequest getEdgeConfigRequest) throws OpenemsNamedException { - // wrap original request inside ComponentJsonApiRequest - var request = new ComponentJsonApiRequest(ComponentManager.SINGLETON_COMPONENT_ID, getEdgeConfigRequest); - - return this.handleComponentJsonApiRequest(user, request); - } - - /** - * Handles a CreateComponentConfigRequest. - * - * @param user the {@link User} - * @param createComponentConfigRequest the {@link CreateComponentConfigRequest} - * @return the Future JSON-RPC Response - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleCreateComponentConfigRequest(User user, - CreateComponentConfigRequest createComponentConfigRequest) throws OpenemsNamedException { - // wrap original request inside ComponentJsonApiRequest - var request = new ComponentJsonApiRequest(ComponentManager.SINGLETON_COMPONENT_ID, - createComponentConfigRequest); - - return this.handleComponentJsonApiRequest(user, request); - } - - /** - * Handles a UpdateComponentConfigRequest. - * - * @param user the {@link User} - * @param updateComponentConfigRequest the {@link UpdateComponentConfigRequest} - * @return the Future JSON-RPC Response - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleUpdateComponentConfigRequest(User user, - UpdateComponentConfigRequest updateComponentConfigRequest) throws OpenemsNamedException { - // wrap original request inside ComponentJsonApiRequest - var request = new ComponentJsonApiRequest(ComponentManager.SINGLETON_COMPONENT_ID, - updateComponentConfigRequest); - - return this.handleComponentJsonApiRequest(user, request); - } - - /** - * Handles a DeleteComponentConfigRequest. - * - * @param user the User - * @param deleteComponentConfigRequest the DeleteComponentConfigRequest - * @return the Future JSON-RPC Response - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleDeleteComponentConfigRequest(User user, - DeleteComponentConfigRequest deleteComponentConfigRequest) throws OpenemsNamedException { - // wrap original request inside ComponentJsonApiRequest - var request = new ComponentJsonApiRequest(ComponentManager.SINGLETON_COMPONENT_ID, - deleteComponentConfigRequest); - - return this.handleComponentJsonApiRequest(user, request); - } - - /** - * Handles a ComponentJsonApiRequest. - * - * @param user the User - * @param request the ComponentJsonApiRequest - * @return the JSON-RPC Success Response Future - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleComponentJsonApiRequest(User user, - ComponentJsonApiRequest request) throws OpenemsNamedException { - // get Component - var componentId = request.getComponentId(); - var component = this.parent.getComponentManager().getComponent(componentId); - - if (component == null) { - throw new OpenemsException("Unable to find Component [" + componentId + "]"); - } - - if (!(component instanceof JsonApi)) { - throw new OpenemsException("Component [" + componentId + "] is no JsonApi"); - } - - // call JsonApi - var jsonApi = (JsonApi) component; - CompletableFuture responseFuture = jsonApi.handleJsonrpcRequest(user, - request.getPayload()); - - // handle null response - if (responseFuture == null) { - throw OpenemsError.JSONRPC_UNHANDLED_METHOD.exception(request.getPayload().getMethod()); - } - - // Wrap reply in EdgeRpcResponse - var edgeRpcResponse = new CompletableFuture(); - responseFuture.whenComplete((r, ex) -> { - if (ex != null) { - edgeRpcResponse.completeExceptionally(ex); - } else if (r != null) { - edgeRpcResponse.complete(new GenericJsonrpcResponseSuccess(request.getId(), r.getResult())); - } else { - edgeRpcResponse.completeExceptionally(new OpenemsNamedException(OpenemsError.JSONRPC_UNHANDLED_METHOD, - request.getPayload().getMethod())); - } - }); - - return edgeRpcResponse; - } - } diff --git a/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/handler/BindingComponentConfigRequestHandler.java b/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/handler/BindingComponentConfigRequestHandler.java new file mode 100644 index 00000000000..00c85ca9887 --- /dev/null +++ b/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/handler/BindingComponentConfigRequestHandler.java @@ -0,0 +1,34 @@ +package io.openems.edge.controller.api.rest.handler; + +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.JsonApiBuilder; +import io.openems.edge.controller.api.common.handler.ComponentConfigRequestHandler; + +/** + * This class makes it possible to request component update, delete, ... + * {@link ComponentConfigRequestHandler} in a websocket connection. It just + * "binds" the component which handles the request and provides their methods + * indirectly. + */ +@Component(property = "entry=" + RootRequestHandler.ENTRY_POINT) +public class BindingComponentConfigRequestHandler implements JsonApi { + + private final ComponentConfigRequestHandler componentConfigRequestHandler; + + @Activate + public BindingComponentConfigRequestHandler(// + @Reference ComponentConfigRequestHandler componentConfigRequestHandler // + ) { + this.componentConfigRequestHandler = componentConfigRequestHandler; + } + + @Override + public void buildJsonApiRoutes(JsonApiBuilder builder) { + this.componentConfigRequestHandler.buildJsonApiRoutes(builder); + } + +} \ No newline at end of file diff --git a/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/handler/BindingComponentRequestHandler.java b/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/handler/BindingComponentRequestHandler.java new file mode 100644 index 00000000000..318b0806154 --- /dev/null +++ b/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/handler/BindingComponentRequestHandler.java @@ -0,0 +1,34 @@ +package io.openems.edge.controller.api.rest.handler; + +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import io.openems.common.jsonrpc.request.ComponentJsonApiRequest; +import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.JsonApiBuilder; +import io.openems.edge.controller.api.common.handler.ComponentRequestHandler; + +/** + * This class makes it possible to request {@link ComponentJsonApiRequest} in a + * websocket connection. It just "binds" the component which handles the request + * and provides their methods indirectly. + */ +@Component(property = "entry=" + RootRequestHandler.ENTRY_POINT) +public class BindingComponentRequestHandler implements JsonApi { + + private final ComponentRequestHandler componentRequestHandler; + + @Activate + public BindingComponentRequestHandler(// + @Reference ComponentRequestHandler componentRequestHandler // + ) { + this.componentRequestHandler = componentRequestHandler; + } + + @Override + public void buildJsonApiRoutes(JsonApiBuilder builder) { + this.componentRequestHandler.buildJsonApiRoutes(builder); + } + +} \ No newline at end of file diff --git a/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/handler/BindingQueryRequestHandler.java b/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/handler/BindingQueryRequestHandler.java new file mode 100644 index 00000000000..6dc37c078ae --- /dev/null +++ b/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/handler/BindingQueryRequestHandler.java @@ -0,0 +1,26 @@ +package io.openems.edge.controller.api.rest.handler; + +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.JsonApiBuilder; +import io.openems.edge.controller.api.common.handler.QueryRequestHandler; + +@Component(property = "entry=" + RootRequestHandler.ENTRY_POINT) +public class BindingQueryRequestHandler implements JsonApi { + + private final QueryRequestHandler queryRequestHandler; + + @Activate + public BindingQueryRequestHandler(@Reference QueryRequestHandler handler) { + this.queryRequestHandler = handler; + } + + @Override + public void buildJsonApiRoutes(JsonApiBuilder builder) { + this.queryRequestHandler.buildJsonApiRoutes(builder); + } + +} diff --git a/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/handler/BindingRoutesJsonApiHandler.java b/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/handler/BindingRoutesJsonApiHandler.java new file mode 100644 index 00000000000..8d683db4614 --- /dev/null +++ b/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/handler/BindingRoutesJsonApiHandler.java @@ -0,0 +1,42 @@ +package io.openems.edge.controller.api.rest.handler; + +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceScope; +import org.osgi.service.component.annotations.ServiceScope; + +import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.JsonApiBuilder; +import io.openems.edge.controller.api.common.handler.RoutesJsonApiHandler; + +@Component(// + property = "entry=" + RootRequestHandler.ENTRY_POINT, // + service = { BindingRoutesJsonApiHandler.class, JsonApi.class }, // + scope = ServiceScope.SINGLETON // +) +public class BindingRoutesJsonApiHandler implements JsonApi { + + private final RoutesJsonApiHandler jsonApiHandler; + + @Activate + public BindingRoutesJsonApiHandler(// + @Reference(scope = ReferenceScope.PROTOTYPE_REQUIRED) RoutesJsonApiHandler jsonApiHandler // + ) { + this.jsonApiHandler = jsonApiHandler; + } + + @Override + public void buildJsonApiRoutes(JsonApiBuilder builder) { + this.jsonApiHandler.buildJsonApiRoutes(builder); + } + + public JsonApiBuilder getBuilder() { + return this.jsonApiHandler.getBuilder(); + } + + public void setBuilder(JsonApiBuilder builder) { + this.jsonApiHandler.setBuilder(builder); + } + +} \ No newline at end of file diff --git a/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/handler/RootRequestHandler.java b/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/handler/RootRequestHandler.java new file mode 100644 index 00000000000..33e3558af1f --- /dev/null +++ b/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/handler/RootRequestHandler.java @@ -0,0 +1,55 @@ +package io.openems.edge.controller.api.rest.handler; + +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; + +import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.JsonApiBuilder; +import io.openems.edge.common.jsonapi.MultipleJsonApiBinder; + +@Component(service = { RootRequestHandler.class, JsonApi.class }) +public class RootRequestHandler implements JsonApi { + + public static final String ENTRY_POINT = "edge.rest.root"; + + private final MultipleJsonApiBinder binder = new MultipleJsonApiBinder(); + + /** + * Binds a {@link JsonApi2}. + * + * @param jsonApi the {@link JsonApi2} to bind + */ + @Reference(// + target = "(entry=" + ENTRY_POINT + ")", // + cardinality = ReferenceCardinality.MULTIPLE, // + policy = ReferencePolicy.DYNAMIC, // + policyOption = ReferencePolicyOption.GREEDY // + ) + public void bindJsonApi(JsonApi jsonApi) { + this.binder.bindJsonApi(jsonApi); + } + + /** + * Unbinds a {@link JsonApi2}. + * + * @param jsonApi the {@link JsonApi2} to unbind + */ + public void unbindJsonApi(JsonApi jsonApi) { + this.binder.unbindJsonApi(jsonApi); + } + + @Activate + public RootRequestHandler(@Reference BindingRoutesJsonApiHandler routesJsonApiHandler) { + routesJsonApiHandler.setBuilder(this.binder.getJsonApiBuilder()); + } + + @Override + public void buildJsonApiRoutes(JsonApiBuilder builder) { + builder.addBuilder(this.binder.getJsonApiBuilder()); + } + +} diff --git a/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/readonly/ControllerApiRestReadOnlyImpl.java b/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/readonly/ControllerApiRestReadOnlyImpl.java index 4595f7f1f35..39841518748 100644 --- a/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/readonly/ControllerApiRestReadOnlyImpl.java +++ b/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/readonly/ControllerApiRestReadOnlyImpl.java @@ -6,9 +6,6 @@ import org.osgi.service.component.annotations.ConfigurationPolicy; import org.osgi.service.component.annotations.Deactivate; import org.osgi.service.component.annotations.Reference; -import org.osgi.service.component.annotations.ReferenceCardinality; -import org.osgi.service.component.annotations.ReferencePolicy; -import org.osgi.service.component.annotations.ReferencePolicyOption; import org.osgi.service.metatype.annotations.Designate; import io.openems.common.channel.AccessMode; @@ -18,8 +15,8 @@ import io.openems.edge.common.user.UserService; import io.openems.edge.controller.api.Controller; import io.openems.edge.controller.api.rest.AbstractRestApi; +import io.openems.edge.controller.api.rest.JsonRpcRestHandler; import io.openems.edge.controller.api.rest.RestApi; -import io.openems.edge.timedata.api.Timedata; @Designate(ocd = Config.class, factory = true) @Component(// @@ -30,15 +27,16 @@ public class ControllerApiRestReadOnlyImpl extends AbstractRestApi implements ControllerApiRestReadOnly, RestApi, Controller, OpenemsComponent { + @Reference + private JsonRpcRestHandler.Factory restHandlerFactory; + private JsonRpcRestHandler restHandler; + @Reference private ComponentManager componentManager; @Reference private UserService userService; - @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) - private volatile Timedata timedata = null; - public ControllerApiRestReadOnlyImpl() { super("REST-Api Read-Only", // OpenemsComponent.ChannelId.values(), // @@ -50,6 +48,8 @@ public ControllerApiRestReadOnlyImpl() { @Activate private void activate(ComponentContext context, Config config) throws OpenemsException { + this.restHandler = this.restHandlerFactory.get(); + super.activate(context, config.id(), config.alias(), config.enabled(), config.debugMode(), 0, /* no timeout */ config.port(), config.connectionlimit()); } @@ -58,14 +58,7 @@ private void activate(ComponentContext context, Config config) throws OpenemsExc @Deactivate protected void deactivate() { super.deactivate(); - } - - @Override - protected Timedata getTimedata() throws OpenemsException { - if (this.timedata != null) { - return this.timedata; - } - throw new OpenemsException("There is no Timedata-Service available!"); + this.restHandlerFactory.unget(this.restHandler); } @Override @@ -78,6 +71,11 @@ protected ComponentManager getComponentManager() { return this.componentManager; } + @Override + protected JsonRpcRestHandler getRpcRestHandler() { + return this.restHandler; + } + @Override protected AccessMode getAccessMode() { return AccessMode.READ_ONLY; diff --git a/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/readwrite/ControllerApiRestReadWriteImpl.java b/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/readwrite/ControllerApiRestReadWriteImpl.java index 9eed3c74014..2faef0d16a2 100644 --- a/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/readwrite/ControllerApiRestReadWriteImpl.java +++ b/io.openems.edge.controller.api.rest/src/io/openems/edge/controller/api/rest/readwrite/ControllerApiRestReadWriteImpl.java @@ -6,9 +6,6 @@ import org.osgi.service.component.annotations.ConfigurationPolicy; import org.osgi.service.component.annotations.Deactivate; import org.osgi.service.component.annotations.Reference; -import org.osgi.service.component.annotations.ReferenceCardinality; -import org.osgi.service.component.annotations.ReferencePolicy; -import org.osgi.service.component.annotations.ReferencePolicyOption; import org.osgi.service.metatype.annotations.Designate; import io.openems.common.channel.AccessMode; @@ -18,8 +15,8 @@ import io.openems.edge.common.user.UserService; import io.openems.edge.controller.api.Controller; import io.openems.edge.controller.api.rest.AbstractRestApi; +import io.openems.edge.controller.api.rest.JsonRpcRestHandler; import io.openems.edge.controller.api.rest.RestApi; -import io.openems.edge.timedata.api.Timedata; @Designate(ocd = Config.class, factory = true) @Component(// @@ -30,15 +27,16 @@ public class ControllerApiRestReadWriteImpl extends AbstractRestApi implements ControllerApiRestReadWrite, RestApi, Controller, OpenemsComponent { + @Reference + private JsonRpcRestHandler.Factory restHandlerFactory; + private JsonRpcRestHandler restHandler; + @Reference private ComponentManager componentManager; @Reference private UserService userService; - @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) - private volatile Timedata timedata = null; - public ControllerApiRestReadWriteImpl() { super("REST-Api Read-Write", // OpenemsComponent.ChannelId.values(), // @@ -51,6 +49,8 @@ public ControllerApiRestReadWriteImpl() { @Activate private void activate(ComponentContext context, Config config) throws OpenemsException { + this.restHandler = this.restHandlerFactory.get(); + super.activate(context, config.id(), config.alias(), config.enabled(), config.debugMode(), config.apiTimeout(), config.port(), config.connectionlimit()); } @@ -59,14 +59,7 @@ private void activate(ComponentContext context, Config config) throws OpenemsExc @Deactivate protected void deactivate() { super.deactivate(); - } - - @Override - protected Timedata getTimedata() throws OpenemsException { - if (this.timedata != null) { - return this.timedata; - } - throw new OpenemsException("There is no Timedata-Service available!"); + this.restHandlerFactory.unget(this.restHandler); } @Override @@ -79,6 +72,11 @@ protected ComponentManager getComponentManager() { return this.componentManager; } + @Override + protected JsonRpcRestHandler getRpcRestHandler() { + return this.restHandler; + } + @Override protected AccessMode getAccessMode() { return AccessMode.READ_WRITE; diff --git a/io.openems.edge.controller.api.rest/test/io/openems/edge/controller/api/rest/DummyJsonRpcRestHandlerFactory.java b/io.openems.edge.controller.api.rest/test/io/openems/edge/controller/api/rest/DummyJsonRpcRestHandlerFactory.java new file mode 100644 index 00000000000..2b99bdb06c3 --- /dev/null +++ b/io.openems.edge.controller.api.rest/test/io/openems/edge/controller/api/rest/DummyJsonRpcRestHandlerFactory.java @@ -0,0 +1,47 @@ +package io.openems.edge.controller.api.rest; + +import java.lang.reflect.InvocationTargetException; + +import org.osgi.framework.ServiceReference; +import org.osgi.service.component.ComponentServiceObjects; + +import com.google.common.base.Supplier; + +import io.openems.common.utils.ReflectionUtils; + +public class DummyJsonRpcRestHandlerFactory extends JsonRpcRestHandler.Factory { + + public DummyJsonRpcRestHandlerFactory(Supplier factoryMethod) + throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { + super(); + ReflectionUtils.setAttribute(JsonRpcRestHandler.Factory.class, this, "cso", + new DummyJsonRpcRestHandlerCso(factoryMethod)); + } + + private static class DummyJsonRpcRestHandlerCso implements ComponentServiceObjects { + + private final Supplier factoryMethod; + + public DummyJsonRpcRestHandlerCso(Supplier factoryMethod) { + super(); + this.factoryMethod = factoryMethod; + } + + @Override + public JsonRpcRestHandler getService() { + return this.factoryMethod.get(); + } + + @Override + public void ungetService(JsonRpcRestHandler service) { + // empty for tests + } + + @Override + public ServiceReference getServiceReference() { + // empty for tests + return null; + } + } + +} diff --git a/io.openems.edge.controller.api.rest/test/io/openems/edge/controller/api/rest/readonly/ControllerApiRestReadOnlyImplTest.java b/io.openems.edge.controller.api.rest/test/io/openems/edge/controller/api/rest/readonly/ControllerApiRestReadOnlyImplTest.java index 6b71381c73a..e7bc5a974ef 100644 --- a/io.openems.edge.controller.api.rest/test/io/openems/edge/controller/api/rest/readonly/ControllerApiRestReadOnlyImplTest.java +++ b/io.openems.edge.controller.api.rest/test/io/openems/edge/controller/api/rest/readonly/ControllerApiRestReadOnlyImplTest.java @@ -6,8 +6,9 @@ import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.common.test.DummyUserService; import io.openems.edge.common.test.TestUtils; +import io.openems.edge.controller.api.rest.DummyJsonRpcRestHandlerFactory; +import io.openems.edge.controller.api.rest.JsonRpcRestHandler; import io.openems.edge.controller.test.ControllerTest; -import io.openems.edge.timedata.test.DummyTimedata; public class ControllerApiRestReadOnlyImplTest { @@ -20,7 +21,7 @@ public void test() throws OpenemsException, Exception { new ControllerTest(new ControllerApiRestReadOnlyImpl()) // .addReference("componentManager", new DummyComponentManager()) // .addReference("userService", new DummyUserService()) // - .addReference("timedata", new DummyTimedata("timedata0")) // + .addReference("restHandlerFactory", new DummyJsonRpcRestHandlerFactory(JsonRpcRestHandler::new)) // .activate(MyConfig.create() // .setId(CTRL_ID) // .setEnabled(false) // do not actually start server diff --git a/io.openems.edge.controller.api.rest/test/io/openems/edge/controller/api/rest/readwrite/ControllerApiRestReadWriteImplTest.java b/io.openems.edge.controller.api.rest/test/io/openems/edge/controller/api/rest/readwrite/ControllerApiRestReadWriteImplTest.java index d118133f257..6baf712a911 100644 --- a/io.openems.edge.controller.api.rest/test/io/openems/edge/controller/api/rest/readwrite/ControllerApiRestReadWriteImplTest.java +++ b/io.openems.edge.controller.api.rest/test/io/openems/edge/controller/api/rest/readwrite/ControllerApiRestReadWriteImplTest.java @@ -15,7 +15,9 @@ import java.util.Base64; import org.junit.Test; +import org.osgi.framework.Constants; +import com.google.common.collect.ImmutableMap; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -36,8 +38,16 @@ import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.common.test.DummyUserService; import io.openems.edge.common.test.TestUtils; +import io.openems.edge.controller.api.common.handler.ComponentConfigRequestHandler; +import io.openems.edge.controller.api.common.handler.ComponentRequestHandler; +import io.openems.edge.controller.api.common.handler.RoutesJsonApiHandler; +import io.openems.edge.controller.api.rest.DummyJsonRpcRestHandlerFactory; +import io.openems.edge.controller.api.rest.JsonRpcRestHandler; +import io.openems.edge.controller.api.rest.handler.BindingComponentConfigRequestHandler; +import io.openems.edge.controller.api.rest.handler.BindingComponentRequestHandler; +import io.openems.edge.controller.api.rest.handler.BindingRoutesJsonApiHandler; +import io.openems.edge.controller.api.rest.handler.RootRequestHandler; import io.openems.edge.controller.test.ControllerTest; -import io.openems.edge.timedata.test.DummyTimedata; public class ControllerApiRestReadWriteImplTest { @@ -48,12 +58,29 @@ public class ControllerApiRestReadWriteImplTest { public void test() throws OpenemsException, Exception { final var port = TestUtils.findRandomOpenPortOnAllLocalInterfaces(); + final var componentManager = new DummyComponentManager(); + + final var rootHandler = new RootRequestHandler(new BindingRoutesJsonApiHandler(new RoutesJsonApiHandler())); + rootHandler.bindJsonApi( + new BindingComponentConfigRequestHandler(new ComponentConfigRequestHandler(componentManager))); + final var componentRequestHandler = new ComponentRequestHandler(); + componentRequestHandler.bindJsonApi(componentManager, ImmutableMap.builder() // + .put(Constants.SERVICE_ID, 0L) // + .build()); + rootHandler.bindJsonApi(new BindingComponentRequestHandler(componentRequestHandler)); + + final var factory = new DummyJsonRpcRestHandlerFactory(() -> { + final var restHandler = new JsonRpcRestHandler(); + restHandler.bindRootHandler(rootHandler); + return restHandler; + }); + var sut = new ControllerApiRestReadWriteImpl(); var test = new ControllerTest(sut) // - .addReference("componentManager", new DummyComponentManager()) // + .addReference("componentManager", componentManager) // .addReference("userService", new DummyUserService(// DUMMY_GUEST, DUMMY_OWNER, DUMMY_INSTALLER, DUMMY_ADMIN)) // - .addReference("timedata", new DummyTimedata("timedata0")) // + .addReference("restHandlerFactory", factory) // .addComponent(new DummyComponent(DUMMY_ID) // .withReadChannel(1234)) // .activate(MyConfig.create() // diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/Config.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/Config.java index cc861c598f6..40a10f7fd72 100644 --- a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/Config.java +++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/Config.java @@ -23,5 +23,8 @@ @AttributeDefinition(name = "Api-Timeout", description = "Sets the timeout in seconds for updates on Channels set by this Api.") int apiTimeout() default 60; + @AttributeDefinition(name = "Debug Mode", description = "Activates the debug mode") + boolean debugMode() default false; + String webconsole_configurationFactory_nameHint() default "Controller Api Websocket [{id}]"; } \ No newline at end of file diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/ControllerApiWebsocket.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/ControllerApiWebsocket.java index f8113b044dd..33d5eec61e8 100644 --- a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/ControllerApiWebsocket.java +++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/ControllerApiWebsocket.java @@ -1,6 +1,5 @@ package io.openems.edge.controller.api.websocket; -import org.ops4j.pax.logging.spi.PaxAppender; import org.osgi.service.event.EventHandler; import io.openems.common.channel.Level; @@ -8,7 +7,7 @@ import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.controller.api.Controller; -public interface ControllerApiWebsocket extends Controller, OpenemsComponent, PaxAppender, EventHandler { +public interface ControllerApiWebsocket extends Controller, OpenemsComponent, EventHandler { public static final String EDGE_ID = "0"; public static final String EDGE_COMMENT = ""; diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/ControllerApiWebsocketImpl.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/ControllerApiWebsocketImpl.java index fdb68329a49..f352756454f 100644 --- a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/ControllerApiWebsocketImpl.java +++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/ControllerApiWebsocketImpl.java @@ -1,22 +1,14 @@ package io.openems.edge.controller.api.websocket; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; -import org.java_websocket.WebSocket; -import org.ops4j.pax.logging.spi.PaxAppender; -import org.ops4j.pax.logging.spi.PaxLoggingEvent; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.ConfigurationPolicy; import org.osgi.service.component.annotations.Deactivate; import org.osgi.service.component.annotations.Reference; -import org.osgi.service.component.annotations.ReferenceCardinality; -import org.osgi.service.component.annotations.ReferencePolicy; -import org.osgi.service.component.annotations.ReferencePolicyOption; import org.osgi.service.event.Event; import org.osgi.service.event.EventHandler; import org.osgi.service.event.propertytypes.EventTopics; @@ -25,12 +17,9 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder; -import io.openems.common.exceptions.OpenemsError; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.exceptions.OpenemsException; import io.openems.common.jsonrpc.notification.EdgeConfigNotification; import io.openems.common.jsonrpc.notification.EdgeRpcNotification; -import io.openems.common.jsonrpc.request.SubscribeSystemLogRequest; import io.openems.common.types.EdgeConfig; import io.openems.common.utils.ThreadPoolUtils; import io.openems.common.websocket.AbstractWebsocketServer.DebugMode; @@ -38,55 +27,48 @@ import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.event.EdgeEventConstants; -import io.openems.edge.common.user.User; import io.openems.edge.common.user.UserService; import io.openems.edge.controller.api.Controller; import io.openems.edge.controller.api.common.ApiWorker; -import io.openems.edge.timedata.api.Timedata; +import io.openems.edge.controller.api.common.handler.ComponentConfigRequestHandler; @Designate(ocd = Config.class, factory = true) @Component(// name = "Controller.Api.Websocket", // immediate = true, // - configurationPolicy = ConfigurationPolicy.REQUIRE, // - property = { // - "org.ops4j.pax.logging.appender.name=Controller.Api.Websocket" // - }) + configurationPolicy = ConfigurationPolicy.REQUIRE // +) @EventTopics({ // EdgeEventConstants.TOPIC_CONFIG_UPDATE, // EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE // }) public class ControllerApiWebsocketImpl extends AbstractOpenemsComponent - implements ControllerApiWebsocket, Controller, OpenemsComponent, PaxAppender, EventHandler { + implements ControllerApiWebsocket, Controller, OpenemsComponent, EventHandler { private static final int POOL_SIZE = 10; - /** Stores valid session tokens for authentication via Cookie. */ - protected final Map sessionTokens = new ConcurrentHashMap<>(); protected final ApiWorker apiWorker = new ApiWorker(this); - private final SystemLogHandler systemLogHandler; - @Reference protected ComponentManager componentManager; @Reference protected UserService userService; - @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) - private volatile Timedata timedata = null; - protected WebsocketServer server = null; private ScheduledExecutorService executor; + @Reference + protected OnRequest.Factory onRequestFactory; + protected OnRequest onRequest; + public ControllerApiWebsocketImpl() { super(// OpenemsComponent.ChannelId.values(), // Controller.ChannelId.values(), // ControllerApiWebsocket.ChannelId.values() // ); - this.systemLogHandler = new SystemLogHandler(this); } @Activate @@ -103,7 +85,14 @@ private void activate(ComponentContext context, Config config) { new ThreadFactoryBuilder().setNameFormat(name + "-%d").build()); this.apiWorker.setTimeoutSeconds(config.apiTimeout()); + + this.onRequest = this.onRequestFactory.get(); + this.onRequest.setOnCall(call -> { + call.put(ComponentConfigRequestHandler.API_WORKER_KEY, this.apiWorker); + }); + this.onRequest.setDebug(config.debugMode()); this.startServer(config.port(), POOL_SIZE, DebugMode.OFF); + } @Override @@ -111,6 +100,7 @@ private void activate(ComponentContext context, Config config) { protected void deactivate() { super.deactivate(); this.stopServer(); + this.onRequestFactory.unget(this.onRequest); ThreadPoolUtils.shutdownAndAwaitTermination(this.executor, 5); } @@ -155,43 +145,6 @@ protected void logError(Logger log, String message) { super.logError(log, message); } - @Override - public void doAppend(PaxLoggingEvent event) { - this.systemLogHandler.handlePaxLoggingEvent(event); - } - - /** - * Gets the WebSocket connection attachment for a UI token. - * - * @param token the UI token - * @return the WsData - * @throws OpenemsNamedException if there is no connection with this token - */ - protected WsData getWsDataForTokenOrError(String token) throws OpenemsNamedException { - var connections = this.server.getConnections(); - for (WebSocket websocket : connections) { - WsData wsData = websocket.getAttachment(); - var thisToken = wsData.getSessionToken(); - if (thisToken != null && thisToken.equals(token)) { - return wsData; - } - } - throw OpenemsError.BACKEND_NO_UI_WITH_TOKEN.exception(token); - } - - /** - * Handles a SubscribeSystemLogRequest by forwarding it to the - * 'SystemLogHandler'. - * - * @param token the UI token - * @param request the SubscribeSystemLogRequest - * @throws OpenemsNamedException on error - */ - protected void handleSubscribeSystemLogRequest(String token, SubscribeSystemLogRequest request) - throws OpenemsNamedException { - this.systemLogHandler.handleSubscribeSystemLogRequest(token, request); - } - @Override public void handleEvent(Event event) { if (!this.isEnabled()) { @@ -217,16 +170,4 @@ public void handleEvent(Event event) { } } - /** - * Gets the Timedata service. - * - * @return the service - * @throws OpenemsException if the timeservice is not available - */ - public Timedata getTimedata() throws OpenemsException { - if (this.timedata != null) { - return this.timedata; - } - throw new OpenemsException("There is no Timedata-Service available!"); - } } diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnRequest.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnRequest.java index 7a398aa9bb5..66f4cd88d34 100644 --- a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnRequest.java +++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnRequest.java @@ -1,534 +1,100 @@ package io.openems.edge.controller.api.websocket; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.UUID; import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; import org.java_websocket.WebSocket; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.osgi.service.component.ComponentServiceObjects; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.component.annotations.ServiceScope; -import com.google.gson.JsonElement; - -import io.openems.common.exceptions.OpenemsError; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.exceptions.OpenemsException; -import io.openems.common.jsonrpc.base.GenericJsonrpcResponseSuccess; import io.openems.common.jsonrpc.base.JsonrpcRequest; +import io.openems.common.jsonrpc.base.JsonrpcResponse; import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; -import io.openems.common.jsonrpc.request.AuthenticateWithPasswordRequest; -import io.openems.common.jsonrpc.request.AuthenticateWithTokenRequest; -import io.openems.common.jsonrpc.request.ComponentJsonApiRequest; -import io.openems.common.jsonrpc.request.CreateComponentConfigRequest; -import io.openems.common.jsonrpc.request.DeleteComponentConfigRequest; -import io.openems.common.jsonrpc.request.EdgeRpcRequest; -import io.openems.common.jsonrpc.request.GetEdgeConfigRequest; -import io.openems.common.jsonrpc.request.GetEdgeRequest; -import io.openems.common.jsonrpc.request.GetEdgesRequest; -import io.openems.common.jsonrpc.request.LogoutRequest; -import io.openems.common.jsonrpc.request.QueryHistoricTimeseriesDataRequest; -import io.openems.common.jsonrpc.request.QueryHistoricTimeseriesEnergyPerPeriodRequest; -import io.openems.common.jsonrpc.request.QueryHistoricTimeseriesEnergyRequest; -import io.openems.common.jsonrpc.request.QueryHistoricTimeseriesExportXlxsRequest; -import io.openems.common.jsonrpc.request.SetChannelValueRequest; -import io.openems.common.jsonrpc.request.SubscribeChannelsRequest; -import io.openems.common.jsonrpc.request.SubscribeEdgesRequest; -import io.openems.common.jsonrpc.request.SubscribeSystemLogRequest; -import io.openems.common.jsonrpc.request.UpdateComponentConfigRequest; -import io.openems.common.jsonrpc.response.AuthenticateResponse; -import io.openems.common.jsonrpc.response.EdgeRpcResponse; -import io.openems.common.jsonrpc.response.GetEdgeResponse; -import io.openems.common.jsonrpc.response.GetEdgesResponse; -import io.openems.common.jsonrpc.response.QueryHistoricTimeseriesDataResponse; -import io.openems.common.jsonrpc.response.QueryHistoricTimeseriesEnergyPerPeriodResponse; -import io.openems.common.jsonrpc.response.QueryHistoricTimeseriesEnergyResponse; -import io.openems.common.session.Language; -import io.openems.common.session.Role; -import io.openems.common.types.ChannelAddress; -import io.openems.edge.common.component.ComponentManager; -import io.openems.edge.common.jsonapi.JsonApi; -import io.openems.edge.common.user.User; - +import io.openems.common.utils.FunctionUtils; +import io.openems.edge.common.jsonapi.Call; +import io.openems.edge.common.jsonapi.EdgeKeys; +import io.openems.edge.common.jsonapi.Key; +import io.openems.edge.common.jsonapi.SingleJsonApiBinder; +import io.openems.edge.controller.api.websocket.handler.RootRequestHandler; + +@Component(service = { OnRequest.class }, scope = ServiceScope.PROTOTYPE) public class OnRequest implements io.openems.common.websocket.OnRequest { - private final Logger log = LoggerFactory.getLogger(OnRequest.class); - private final ControllerApiWebsocketImpl parent; - - public OnRequest(ControllerApiWebsocketImpl parent) { - this.parent = parent; - } + @Component(service = OnRequest.Factory.class) + public static class Factory { - @Override - public CompletableFuture run(WebSocket ws, JsonrpcRequest request) - throws OpenemsException, OpenemsNamedException { - // get websocket attachment - WsData wsData = ws.getAttachment(); + @Reference + private ComponentServiceObjects cso; - // Start with authentication requests - switch (request.getMethod()) { - case AuthenticateWithTokenRequest.METHOD: - return this.handleAuthenticateWithTokenRequest(wsData, AuthenticateWithTokenRequest.from(request)); - - case AuthenticateWithPasswordRequest.METHOD: - return this.handleAuthenticateWithPasswordRequest(wsData, AuthenticateWithPasswordRequest.from(request)); + /** + * Returns a new {@link OnRequest} service object. + * + * @return the created {@link OnRequest} object + * @see #unget(OnRequest) + */ + public OnRequest get() { + return this.cso.getService(); } - // is user authenticated? - var user = wsData.assertUserIsAuthenticated(request.getMethod()); - user.assertRoleIsAtLeast(request.getMethod(), Role.GUEST); - - switch (request.getMethod()) { - case LogoutRequest.METHOD: - return this.handleLogoutRequest(wsData, user, LogoutRequest.from(request)); - - case EdgeRpcRequest.METHOD: - return this.handleEdgeRpcRequest(wsData, user, EdgeRpcRequest.from(request)); - - case GetEdgesRequest.METHOD: - return handleGetEdgesRequest(user, GetEdgesRequest.from(request)); - - case GetEdgeRequest.METHOD: - return handleGetEdgeRequest(user, GetEdgeRequest.from(request)); - - case SubscribeEdgesRequest.METHOD: - return this.handleSubscribeEdgesReqeust(user, SubscribeEdgesRequest.from(request)); - - default: - this.parent.logWarn(this.log, "Unhandled Request: " + request); - throw OpenemsError.JSONRPC_UNHANDLED_METHOD.exception(request.getMethod()); - } - } - - /** - * Handles a {@link LogoutRequest}. - * - * @param wsData the WebSocket attachment - * @param user the authenticated {@link User} - * @param request the {@link LogoutRequest} - * @return the JSON-RPC Success Response Future - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleLogoutRequest(WsData wsData, User user, - LogoutRequest request) throws OpenemsNamedException { - this.parent.sessionTokens.remove(wsData.getSessionToken(), user); - wsData.logout(); - return CompletableFuture.completedFuture(new GenericJsonrpcResponseSuccess(request.getId())); - } - - /** - * Handles a {@link EdgeRpcRequest}. - * - * @param wsData the WebSocket attachment - * @param edgeRpcRequest the EdgeRpcRequest - * @param user the {@link User} - * @return the JSON-RPC Success Response Future - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleEdgeRpcRequest(WsData wsData, User user, - EdgeRpcRequest edgeRpcRequest) throws OpenemsNamedException { - var request = edgeRpcRequest.getPayload(); - - CompletableFuture resultFuture; - switch (request.getMethod()) { - - case SubscribeChannelsRequest.METHOD: - resultFuture = this.handleSubscribeChannelsRequest(wsData, user, SubscribeChannelsRequest.from(request)); - break; - - case SubscribeSystemLogRequest.METHOD: - resultFuture = this.handleSubscribeSystemLogRequest(wsData, user, SubscribeSystemLogRequest.from(request)); - break; - - case QueryHistoricTimeseriesDataRequest.METHOD: - resultFuture = this.handleQueryHistoricDataRequest(user, QueryHistoricTimeseriesDataRequest.from(request)); - break; - - case QueryHistoricTimeseriesEnergyRequest.METHOD: - resultFuture = this.handleQueryHistoricEnergyRequest(QueryHistoricTimeseriesEnergyRequest.from(request)); - break; - - case QueryHistoricTimeseriesEnergyPerPeriodRequest.METHOD: - resultFuture = this.handleQueryHistoricEnergyPerPeriodRequest( - QueryHistoricTimeseriesEnergyPerPeriodRequest.from(request)); - break; - - case QueryHistoricTimeseriesExportXlxsRequest.METHOD: - resultFuture = this.handleQueryHistoricTimeseriesExportXlxsRequest(user, - QueryHistoricTimeseriesExportXlxsRequest.from(request)); - break; - - case CreateComponentConfigRequest.METHOD: - resultFuture = this.handleCreateComponentConfigRequest(user, CreateComponentConfigRequest.from(request)); - break; - - case UpdateComponentConfigRequest.METHOD: - resultFuture = this.handleUpdateComponentConfigRequest(user, UpdateComponentConfigRequest.from(request)); - break; - - case DeleteComponentConfigRequest.METHOD: - resultFuture = this.handleDeleteComponentConfigRequest(user, DeleteComponentConfigRequest.from(request)); - break; - - case GetEdgeConfigRequest.METHOD: - resultFuture = this.handleGetEdgeConfigRequest(user, GetEdgeConfigRequest.from(request)); - break; - - case SetChannelValueRequest.METHOD: - resultFuture = this.handleSetChannelValueRequest(user, SetChannelValueRequest.from(request)); - break; - - case ComponentJsonApiRequest.METHOD: - resultFuture = this.handleComponentJsonApiRequest(user, ComponentJsonApiRequest.from(request)); - break; - - // TODO: to be implemented: UI Logout - - default: - throw OpenemsError.JSONRPC_UNHANDLED_METHOD.exception(request.getMethod()); - } - - // Wrap reply in EdgeRpcResponse - var result = new CompletableFuture(); - resultFuture.whenComplete((r, ex) -> { - if (ex != null) { - result.completeExceptionally(ex); - } else if (r != null) { - result.complete(new EdgeRpcResponse(edgeRpcRequest.getId(), r)); - } else { - result.completeExceptionally( - new OpenemsNamedException(OpenemsError.JSONRPC_UNHANDLED_METHOD, request.getMethod())); + /** + * Releases the {@link OnRequest} service object. + * + * @param service a {@link OnRequest} provided by this factory + * @see #get() + */ + public void unget(OnRequest service) { + if (service == null) { + return; } - }); - return result; - } - - /** - * Handles a {@link AuthenticateWithTokenRequest}. - * - * @param wsData the WebSocket attachment - * @param request the {@link AuthenticateWithTokenRequest} - * @return the JSON-RPC Success Response Future - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleAuthenticateWithTokenRequest(WsData wsData, - AuthenticateWithTokenRequest request) throws OpenemsNamedException { - var token = request.getToken(); - return this.handleAuthentication(wsData, request.getId(), - Optional.ofNullable(this.parent.sessionTokens.get(token)), token); - } - - /** - * Handles a {@link AuthenticateWithPasswordRequest}. - * - * @param wsData the WebSocket attachment - * @param request the {@link AuthenticateWithPasswordRequest} - * @return the JSON-RPC Success Response Future - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleAuthenticateWithPasswordRequest(WsData wsData, - AuthenticateWithPasswordRequest request) throws OpenemsNamedException { - return this.handleAuthentication(wsData, request.getId(), - this.parent.userService.authenticate(request.password), UUID.randomUUID().toString()); - } - - /** - * Common handler for {@link AuthenticateWithTokenRequest} and - * {@link AuthenticateWithPasswordRequest}. - * - * @param wsData the WebSocket attachment - * @param requestId the ID of the original {@link JsonrpcRequest} - * @param userOpt the optional {@link User} - * @param token the existing or new token - * @return the JSON-RPC Success Response Future - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleAuthentication(WsData wsData, UUID requestId, - Optional userOpt, String token) throws OpenemsNamedException { - if (userOpt.isPresent()) { - var user = userOpt.get(); - wsData.setSessionToken(token); - wsData.setUser(user); - this.parent.sessionTokens.put(token, user); - this.parent.logInfo(this.log, "User [" + user.getId() + ":" + user.getName() + "] connected."); - - return CompletableFuture.completedFuture(new AuthenticateResponse(requestId, token, user, - List.of(Utils.getEdgeMetadata(user.getRole())), Language.DEFAULT)); + this.cso.ungetService(service); } - wsData.unsetUser(); - throw OpenemsError.COMMON_AUTHENTICATION_FAILED.exception(); - } - /** - * Handles a {@link SubscribeChannelsRequest}. - * - * @param wsData the WebSocket attachment - * @param user the {@link User} - * @param request the {@link SubscribeChannelsRequest} - * @return the JSON-RPC Success Response Future - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleSubscribeChannelsRequest(WsData wsData, User user, - SubscribeChannelsRequest request) throws OpenemsNamedException { - // Register subscription in WsData - wsData.handleSubscribeChannelsRequest(request); - - // JSON-RPC response - return CompletableFuture.completedFuture(new GenericJsonrpcResponseSuccess(request.getId())); } - /** - * Handles a {@link QueryHistoricTimeseriesDataRequest}. - * - * @param user the {@link User} - * @param request the {@link QueryHistoricTimeseriesDataRequest} - * @return the Future JSON-RPC Response - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleQueryHistoricDataRequest(User user, - QueryHistoricTimeseriesDataRequest request) throws OpenemsNamedException { - var data = this.parent.getTimedata().queryHistoricData(// - null, /* ignore Edge-ID */ - request); - - // JSON-RPC response - return CompletableFuture.completedFuture(new QueryHistoricTimeseriesDataResponse(request.getId(), data)); - } + public static final Key WS_DATA_KEY = new Key<>("wsData", WsData.class); + public static final Key WEBSOCKET_KEY = new Key<>("websocket", WebSocket.class); - /** - * Handles a QueryHistoricEnergyRequest. - * - * @param request the QueryHistoricEnergyRequest - * @return the Future JSPN-RPC Response - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleQueryHistoricEnergyRequest( - QueryHistoricTimeseriesEnergyRequest request) throws OpenemsNamedException { - Map data = this.parent.getTimedata().queryHistoricEnergy(// - null, /* ignore Edge-ID */ - request.getFromDate(), request.getToDate(), request.getChannels()); - - // JSON-RPC response - return CompletableFuture.completedFuture(new QueryHistoricTimeseriesEnergyResponse(request.getId(), data)); - } - - /** - * Handles a {@link QueryHistoricTimeseriesEnergyPerPeriodRequest}. - * - * @param request the {@link QueryHistoricTimeseriesEnergyPerPeriodRequest} - * @return the Future JSON-RPC Response - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleQueryHistoricEnergyPerPeriodRequest( - QueryHistoricTimeseriesEnergyPerPeriodRequest request) throws OpenemsNamedException { - var data = this.parent.getTimedata().queryHistoricEnergyPerPeriod(// - null, /* ignore Edge-ID */ - request.getFromDate(), request.getToDate(), request.getChannels(), request.getResolution()); - - return CompletableFuture - .completedFuture(new QueryHistoricTimeseriesEnergyPerPeriodResponse(request.getId(), data)); - } + private final SingleJsonApiBinder apiBinder = new SingleJsonApiBinder(); + private Consumer> onCall = FunctionUtils::doNothing; - /** - * Handles a {@link QueryHistoricTimeseriesExportXlxsRequest}. - * - * @param user the {@link User} - * @param request the {@link QueryHistoricTimeseriesExportXlxsRequest} - * @return the Future JSON-RPC Response - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleQueryHistoricTimeseriesExportXlxsRequest(User user, - QueryHistoricTimeseriesExportXlxsRequest request) throws OpenemsNamedException { - return CompletableFuture.completedFuture( - this.parent.getTimedata().handleQueryHistoricTimeseriesExportXlxsRequest(null /* ignore Edge-ID */, - request, user.getLanguage())); + @Reference(// + cardinality = ReferenceCardinality.OPTIONAL, // + policy = ReferencePolicy.DYNAMIC, // + policyOption = ReferencePolicyOption.GREEDY // + ) + protected void bindRootHandler(RootRequestHandler rootHandler) { + this.apiBinder.bind(rootHandler); } - /** - * Handles a {@link CreateComponentConfigRequest}. - * - * @param user the {@link User} - * @param createComponentConfigRequest the {@link CreateComponentConfigRequest} - * @return the Future JSON-RPC Response - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleCreateComponentConfigRequest(User user, - CreateComponentConfigRequest createComponentConfigRequest) throws OpenemsNamedException { - // wrap original request inside ComponentJsonApiRequest - var request = new ComponentJsonApiRequest(ComponentManager.SINGLETON_COMPONENT_ID, - createComponentConfigRequest); - - return this.handleComponentJsonApiRequest(user, request); - } - - /** - * Handles a {@link UpdateComponentConfigRequest}. - * - * @param user the {@link User} - * @param updateComponentConfigRequest the {@link UpdateComponentConfigRequest} - * @return the Future JSON-RPC Response - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleUpdateComponentConfigRequest(User user, - UpdateComponentConfigRequest updateComponentConfigRequest) throws OpenemsNamedException { - // wrap original request inside ComponentJsonApiRequest - var request = new ComponentJsonApiRequest(ComponentManager.SINGLETON_COMPONENT_ID, - updateComponentConfigRequest); - - return this.handleComponentJsonApiRequest(user, request); - } - - /** - * Handles a {@link DeleteComponentConfigRequest}. - * - * @param user the {@link User} - * @param deleteComponentConfigRequest the {@link DeleteComponentConfigRequest} - * @return the Future JSON-RPC Response - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleDeleteComponentConfigRequest(User user, - DeleteComponentConfigRequest deleteComponentConfigRequest) throws OpenemsNamedException { - // wrap original request inside ComponentJsonApiRequest - var request = new ComponentJsonApiRequest(ComponentManager.SINGLETON_COMPONENT_ID, - deleteComponentConfigRequest); - - return this.handleComponentJsonApiRequest(user, request); - } - - /** - * Handles a {@link GetEdgeConfigRequest}. - * - * @param user the {@link User} - * @param getEdgeConfigRequest the {@link GetEdgeConfigRequest} - * @return the Future JSON-RPC Response - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleGetEdgeConfigRequest(User user, - GetEdgeConfigRequest getEdgeConfigRequest) throws OpenemsNamedException { - // wrap original request inside ComponentJsonApiRequest - var request = new ComponentJsonApiRequest(ComponentManager.SINGLETON_COMPONENT_ID, getEdgeConfigRequest); - - return this.handleComponentJsonApiRequest(user, request); + protected void unbindRootHandler(RootRequestHandler rootHandler) { + this.apiBinder.unbind(); } - /** - * Handles a {@link SetChannelValueRequest}. - * - * @param user the User - * @param request the {@link SetChannelValueRequest} - * @return the Future JSON-RPC Response - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleSetChannelValueRequest(User user, - SetChannelValueRequest request) throws OpenemsNamedException { - user.assertRoleIsAtLeast(SetChannelValueRequest.METHOD, Role.ADMIN); - - return this.parent.apiWorker.handleSetChannelValueRequest(this.parent.componentManager, user, request); - } - - /** - * Handles a {@link ComponentJsonApiRequest}. - * - * @param user the User - * @param request the {@link ComponentJsonApiRequest} - * @return the Future JSON-RPC Response - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleComponentJsonApiRequest(User user, - ComponentJsonApiRequest request) throws OpenemsNamedException { - // get Component - var componentId = request.getComponentId(); - var component = this.parent.componentManager.getComponent(componentId); - - if (component == null) { - throw new OpenemsException("Unable to find Component [" + componentId + "]"); - } - - if (!(component instanceof JsonApi)) { - throw new OpenemsException("Component [" + componentId + "] is no JsonApi"); - } - - // call JsonApi - var jsonApi = (JsonApi) component; - CompletableFuture responseFuture = jsonApi.handleJsonrpcRequest(user, - request.getPayload()); - - // handle null response - if (responseFuture == null) { - throw OpenemsError.JSONRPC_UNHANDLED_METHOD.exception(request.getPayload().getMethod()); - } - - // Wrap reply in new JsonrpcResponseSuccess - var jsonrpcResponse = new CompletableFuture(); - responseFuture.whenComplete((r, ex) -> { - if (ex != null) { - jsonrpcResponse.completeExceptionally(ex); - } else if (r != null) { - jsonrpcResponse.complete(new GenericJsonrpcResponseSuccess(request.getId(), r.getResult())); - } else { - jsonrpcResponse.completeExceptionally(new OpenemsNamedException(OpenemsError.JSONRPC_UNHANDLED_METHOD, - request.getPayload().getMethod())); - } + @Override + public CompletableFuture run(WebSocket ws, JsonrpcRequest request) + throws OpenemsNamedException { + return this.apiBinder.handleRequest(request, call -> { + WsData wsData = ws.getAttachment(); + call.put(WS_DATA_KEY, wsData); + wsData.getUser().ifPresent(user -> { + call.put(EdgeKeys.USER_KEY, user); + }); + this.onCall.accept(call); }); - - return jsonrpcResponse; - } - - /** - * Handles a {@link SubscribeSystemLogRequest}. - * - * @param wsData the WebSocket attachment - * @param user the {@link User} - * @param request the {@link SubscribeSystemLogRequest} - * @return the JSON-RPC Success Response Future - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleSubscribeSystemLogRequest(WsData wsData, User user, - SubscribeSystemLogRequest request) throws OpenemsNamedException { - var token = wsData.getSessionToken(); - if (token == null) { - throw OpenemsError.BACKEND_UI_TOKEN_MISSING.exception(); - } - this.parent.handleSubscribeSystemLogRequest(token, request); - return CompletableFuture.completedFuture(new GenericJsonrpcResponseSuccess(request.getId())); - } - - /** - * Handles a {@link GetEdgesRequest}. - * - * @param user the {@link User} - * @param request the {@link GetEdgesRequest} - * @return the {@link GetEdgesResponse} Response Future - * @throws OpenemsNamedException on error - */ - protected static CompletableFuture handleGetEdgesRequest(User user, GetEdgesRequest request) { - return CompletableFuture.completedFuture(// - new GetEdgesResponse(request.getId(), List.of(Utils.getEdgeMetadata(user.getGlobalRole())))); } - /** - * Handles a {@link GetEdgeRequest}. - * - * @param user the {@link User} - * @param request the {@link GetEdgeRequest} - * @return the {@link GetEdgeResponse} Response Future - */ - protected static CompletableFuture handleGetEdgeRequest(User user, GetEdgeRequest request) { - return CompletableFuture.completedFuture(// - new GetEdgeResponse(request.id, Utils.getEdgeMetadata(user.getGlobalRole()))); + public void setOnCall(Consumer> callAction) { + this.onCall = callAction == null ? FunctionUtils::doNothing : callAction; } - /** - * Handles a {@link SubscribeEdgesRequest}. - * - * @param user the {@link User} - * @param request the {@link SubscribeEdgesRequest} - * @return the Response Future - */ - private CompletableFuture handleSubscribeEdgesReqeust(User user, - SubscribeEdgesRequest request) { - return CompletableFuture.completedFuture(new GenericJsonrpcResponseSuccess(request.getId())); + public void setDebug(boolean debug) { + this.apiBinder.setDebug(debug); } } diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/SystemLogHandler.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/SystemLogHandler.java deleted file mode 100644 index 2e8ae3379e1..00000000000 --- a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/SystemLogHandler.java +++ /dev/null @@ -1,78 +0,0 @@ -package io.openems.edge.controller.api.websocket; - -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.CompletableFuture; - -import org.ops4j.pax.logging.spi.PaxLoggingEvent; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.jsonrpc.base.GenericJsonrpcResponseSuccess; -import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; -import io.openems.common.jsonrpc.notification.EdgeRpcNotification; -import io.openems.common.jsonrpc.notification.SystemLogNotification; -import io.openems.common.jsonrpc.request.SubscribeSystemLogRequest; - -public class SystemLogHandler { - - private final Logger log = LoggerFactory.getLogger(SystemLogHandler.class); - private final ControllerApiWebsocketImpl parent; - private final Set subscriptions = new HashSet<>(); - - public SystemLogHandler(ControllerApiWebsocketImpl parent) { - this.parent = parent; - } - - /** - * Handles a {@link SubscribeSystemLogRequest}. - * - * @param token the UI session token - * @param request the {@link SubscribeSystemLogRequest} - * @return a reply - * @throws OpenemsNamedException on error - */ - public CompletableFuture handleSubscribeSystemLogRequest(String token, - SubscribeSystemLogRequest request) throws OpenemsNamedException { - if (request.isSubscribe()) { - /* - * Start subscription - */ - this.subscriptions.add(token); - - } else { - /* - * End subscription - */ - this.subscriptions.remove(token); - } - // announce success - return CompletableFuture.completedFuture(new GenericJsonrpcResponseSuccess(request.getId())); - } - - /** - * Handles a PaxLoggingEvent and sends a SystemLogNotification to all subscribed - * UI sessions. - * - * @param event the event - */ - public void handlePaxLoggingEvent(PaxLoggingEvent event) { - synchronized (this.subscriptions) { - if (this.subscriptions.isEmpty()) { - return; - } - var notification = new EdgeRpcNotification(ControllerApiWebsocket.EDGE_ID, - SystemLogNotification.fromPaxLoggingEvent(event)); - for (var iter = this.subscriptions.iterator(); iter.hasNext();) { - var token = iter.next(); - try { - this.parent.getWsDataForTokenOrError(token).send(notification); - } catch (OpenemsNamedException e) { - iter.remove(); - this.log.warn("Unable to handle PaxLoggingEvent: " + e.getMessage()); - } - } - } - } -} diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WebsocketServer.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WebsocketServer.java index 0744f152e2e..cc0c451279e 100644 --- a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WebsocketServer.java +++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WebsocketServer.java @@ -10,7 +10,6 @@ public class WebsocketServer extends AbstractWebsocketServer { private final ControllerApiWebsocketImpl parent; private final OnOpen onOpen; - private final OnRequest onRequest; private final OnNotification onNotification; private final OnError onError; private final OnClose onClose; @@ -20,7 +19,6 @@ public WebsocketServer(ControllerApiWebsocketImpl parent, String name, int port, super(name, port, poolSize, debugMode); this.parent = parent; this.onOpen = new OnOpen(parent); - this.onRequest = new OnRequest(parent); this.onNotification = new OnNotification(parent); this.onError = new OnError(parent); this.onClose = new OnClose(parent); @@ -38,7 +36,7 @@ protected OnOpen getOnOpen() { @Override protected OnRequest getOnRequest() { - return this.onRequest; + return this.parent.onRequest; } @Override diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WsData.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WsData.java index ed2f355872f..6a455a86972 100644 --- a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WsData.java +++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WsData.java @@ -13,7 +13,6 @@ import com.google.gson.JsonElement; import com.google.gson.JsonNull; -import io.openems.common.exceptions.OpenemsError; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; import io.openems.common.jsonrpc.notification.CurrentDataNotification; @@ -142,21 +141,6 @@ public Optional getUser() { return this.user; } - /** - * Throws an exception if the User is not authenticated. - * - * @param resource a resource identifier; used for the exception - * @return the current {@link User} - * @throws OpenemsNamedException if the current Role privileges are less - */ - public User assertUserIsAuthenticated(String resource) throws OpenemsNamedException { - if (this.getUser().isPresent()) { - return this.getUser().get(); - } - throw OpenemsError.COMMON_USER_NOT_AUTHENTICATED - .exception("Session [" + this.getSessionToken() + "]. Ignoring [" + resource + "]"); - } - @Override public String toString() { String tokenString; diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/AuthenticationRequestHandler.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/AuthenticationRequestHandler.java new file mode 100644 index 00000000000..e36b38e030d --- /dev/null +++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/AuthenticationRequestHandler.java @@ -0,0 +1,103 @@ +package io.openems.edge.controller.api.websocket.handler; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.openems.common.exceptions.OpenemsError; +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.jsonrpc.base.GenericJsonrpcResponseSuccess; +import io.openems.common.jsonrpc.base.JsonrpcRequest; +import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; +import io.openems.common.jsonrpc.request.AuthenticateWithPasswordRequest; +import io.openems.common.jsonrpc.request.AuthenticateWithTokenRequest; +import io.openems.common.jsonrpc.request.LogoutRequest; +import io.openems.common.jsonrpc.response.AuthenticateResponse; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.edge.common.jsonapi.EdgeGuards; +import io.openems.edge.common.jsonapi.EdgeKeys; +import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.JsonApiBuilder; +import io.openems.edge.common.user.User; +import io.openems.edge.common.user.UserService; +import io.openems.edge.controller.api.websocket.OnRequest; +import io.openems.edge.controller.api.websocket.Utils; +import io.openems.edge.controller.api.websocket.WsData; + +@Component(property = "entry=" + RootRequestHandler.ENTRY_POINT) +public class AuthenticationRequestHandler implements JsonApi { + + private final Logger log = LoggerFactory.getLogger(AuthenticationRequestHandler.class); + + private final Map sessionTokens = new ConcurrentHashMap<>(); + + @Reference + private UserService userService; + + @Override + public void buildJsonApiRoutes(JsonApiBuilder builder) { + builder.handleRequest(AuthenticateWithTokenRequest.METHOD, call -> { + final var request = AuthenticateWithTokenRequest.from(call.getRequest()); + var token = request.getToken(); + + return this.handleAuthentication(call.get(OnRequest.WS_DATA_KEY), request.getId(), + Optional.ofNullable(this.sessionTokens.get(token)), token); + }); + + builder.handleRequest(AuthenticateWithPasswordRequest.METHOD, call -> { + final var request = AuthenticateWithPasswordRequest.from(call.getRequest()); + + return this.handleAuthentication(call.get(OnRequest.WS_DATA_KEY), request.getId(), + this.userService.authenticate(request.password), UUID.randomUUID().toString()); + }); + + builder.handleRequest(LogoutRequest.METHOD, endpoint -> { + endpoint.setGuards(EdgeGuards.roleIsAtleast(Role.GUEST)); + }, call -> { + final var wsData = call.get(OnRequest.WS_DATA_KEY); + this.sessionTokens.remove(wsData.getSessionToken(), call.get(EdgeKeys.USER_KEY)); + wsData.logout(); + return new GenericJsonrpcResponseSuccess(call.getRequest().getId()); + }); + } + + /** + * Common handler for {@link AuthenticateWithTokenRequest} and + * {@link AuthenticateWithPasswordRequest}. + * + * @param wsData the WebSocket attachment + * @param requestId the ID of the original {@link JsonrpcRequest} + * @param userOpt the optional {@link User} + * @param token the existing or new token + * @return the JSON-RPC Success Response Future + * @throws OpenemsNamedException on error + */ + private JsonrpcResponseSuccess handleAuthentication(// + WsData wsData, // + UUID requestId, // + Optional userOpt, // + String token // + ) throws OpenemsNamedException { + if (userOpt.isEmpty()) { + wsData.unsetUser(); + throw OpenemsError.COMMON_AUTHENTICATION_FAILED.exception(); + } + final var user = userOpt.get(); + wsData.setSessionToken(token); + wsData.setUser(user); + this.sessionTokens.put(token, user); + this.log.info("User [" + user.getId() + ":" + user.getName() + "] connected."); + + return new AuthenticateResponse(requestId, token, user, List.of(Utils.getEdgeMetadata(user.getRole())), + Language.DEFAULT); + } + +} diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/BindingComponentConfigRequestHandler.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/BindingComponentConfigRequestHandler.java new file mode 100644 index 00000000000..95184e286ab --- /dev/null +++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/BindingComponentConfigRequestHandler.java @@ -0,0 +1,34 @@ +package io.openems.edge.controller.api.websocket.handler; + +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.JsonApiBuilder; +import io.openems.edge.controller.api.common.handler.ComponentConfigRequestHandler; + +/** + * This class makes it possible to request component update, delete, ... + * {@link ComponentConfigRequestHandler} in a websocket connection. It just + * "binds" the component which handles the request and provides their methods + * indirectly. + */ +@Component(property = "entry=" + EdgeRpcRequestHandler.ENTRY_POINT) +public class BindingComponentConfigRequestHandler implements JsonApi { + + private final ComponentConfigRequestHandler componentConfigRequestHandler; + + @Activate + public BindingComponentConfigRequestHandler(// + @Reference ComponentConfigRequestHandler componentConfigRequestHandler // + ) { + this.componentConfigRequestHandler = componentConfigRequestHandler; + } + + @Override + public void buildJsonApiRoutes(JsonApiBuilder builder) { + this.componentConfigRequestHandler.buildJsonApiRoutes(builder); + } + +} \ No newline at end of file diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/BindingComponentRequestHandler.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/BindingComponentRequestHandler.java new file mode 100644 index 00000000000..993629f3b93 --- /dev/null +++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/BindingComponentRequestHandler.java @@ -0,0 +1,34 @@ +package io.openems.edge.controller.api.websocket.handler; + +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import io.openems.common.jsonrpc.request.ComponentJsonApiRequest; +import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.JsonApiBuilder; +import io.openems.edge.controller.api.common.handler.ComponentRequestHandler; + +/** + * This class makes it possible to request {@link ComponentJsonApiRequest} in a + * websocket connection. It just "binds" the component which handles the request + * and provides their methods indirectly. + */ +@Component(property = "entry=" + EdgeRpcRequestHandler.ENTRY_POINT) +public class BindingComponentRequestHandler implements JsonApi { + + private final ComponentRequestHandler componentRequestHandler; + + @Activate + public BindingComponentRequestHandler(// + @Reference ComponentRequestHandler componentRequestHandler // + ) { + this.componentRequestHandler = componentRequestHandler; + } + + @Override + public void buildJsonApiRoutes(JsonApiBuilder builder) { + this.componentRequestHandler.buildJsonApiRoutes(builder); + } + +} \ No newline at end of file diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/BindingQueryRequestHandler.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/BindingQueryRequestHandler.java new file mode 100644 index 00000000000..7b5ef449e45 --- /dev/null +++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/BindingQueryRequestHandler.java @@ -0,0 +1,26 @@ +package io.openems.edge.controller.api.websocket.handler; + +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.JsonApiBuilder; +import io.openems.edge.controller.api.common.handler.QueryRequestHandler; + +@Component(property = "entry=" + EdgeRpcRequestHandler.ENTRY_POINT) +public class BindingQueryRequestHandler implements JsonApi { + + private final QueryRequestHandler queryRequestHandler; + + @Activate + public BindingQueryRequestHandler(@Reference QueryRequestHandler handler) { + this.queryRequestHandler = handler; + } + + @Override + public void buildJsonApiRoutes(JsonApiBuilder builder) { + this.queryRequestHandler.buildJsonApiRoutes(builder); + } + +} diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/BindingRoutesJsonApiHandler.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/BindingRoutesJsonApiHandler.java new file mode 100644 index 00000000000..93bcc016179 --- /dev/null +++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/BindingRoutesJsonApiHandler.java @@ -0,0 +1,42 @@ +package io.openems.edge.controller.api.websocket.handler; + +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceScope; +import org.osgi.service.component.annotations.ServiceScope; + +import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.JsonApiBuilder; +import io.openems.edge.controller.api.common.handler.RoutesJsonApiHandler; + +@Component(// + property = "entry=" + EdgeRpcRequestHandler.ENTRY_POINT, // + service = { BindingRoutesJsonApiHandler.class, JsonApi.class }, // + scope = ServiceScope.SINGLETON // +) +public class BindingRoutesJsonApiHandler implements JsonApi { + + private final RoutesJsonApiHandler jsonApiHandler; + + @Activate + public BindingRoutesJsonApiHandler(// + @Reference(scope = ReferenceScope.PROTOTYPE_REQUIRED) RoutesJsonApiHandler jsonApiHandler // + ) { + this.jsonApiHandler = jsonApiHandler; + } + + @Override + public void buildJsonApiRoutes(JsonApiBuilder builder) { + this.jsonApiHandler.buildJsonApiRoutes(builder); + } + + public JsonApiBuilder getBuilder() { + return this.jsonApiHandler.getBuilder(); + } + + public void setBuilder(JsonApiBuilder builder) { + this.jsonApiHandler.setBuilder(builder); + } + +} \ No newline at end of file diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/EdgeRequestHandler.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/EdgeRequestHandler.java new file mode 100644 index 00000000000..45234bfaa4f --- /dev/null +++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/EdgeRequestHandler.java @@ -0,0 +1,37 @@ +package io.openems.edge.controller.api.websocket.handler; + +import java.util.List; + +import org.osgi.service.component.annotations.Component; + +import io.openems.common.jsonrpc.base.GenericJsonrpcResponseSuccess; +import io.openems.common.jsonrpc.request.GetEdgeRequest; +import io.openems.common.jsonrpc.request.GetEdgesRequest; +import io.openems.common.jsonrpc.request.SubscribeEdgesRequest; +import io.openems.common.jsonrpc.response.GetEdgeResponse; +import io.openems.common.jsonrpc.response.GetEdgesResponse; +import io.openems.edge.common.jsonapi.EdgeKeys; +import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.JsonApiBuilder; +import io.openems.edge.controller.api.websocket.Utils; + +@Component(property = "entry=" + RootRequestHandler.ENTRY_POINT) +public class EdgeRequestHandler implements JsonApi { + + @Override + public void buildJsonApiRoutes(JsonApiBuilder builder) { + builder.handleRequest(GetEdgesRequest.METHOD, call -> { + final var user = call.get(EdgeKeys.USER_KEY); + return new GetEdgesResponse(call.getRequest().getId(), + List.of(Utils.getEdgeMetadata(user.getGlobalRole()))); + }); + + builder.handleRequest(GetEdgeRequest.METHOD, call -> { + final var user = call.get(EdgeKeys.USER_KEY); + return new GetEdgeResponse(call.getRequest().getId(), Utils.getEdgeMetadata(user.getGlobalRole())); + }); + + builder.handleRequest(SubscribeEdgesRequest.METHOD, call -> new GenericJsonrpcResponseSuccess(call.getRequest().getId())); + } + +} diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/EdgeRpcRequestHandler.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/EdgeRpcRequestHandler.java new file mode 100644 index 00000000000..8aa5e780c95 --- /dev/null +++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/EdgeRpcRequestHandler.java @@ -0,0 +1,65 @@ +package io.openems.edge.controller.api.websocket.handler; + +import java.util.List; + +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; + +import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; +import io.openems.common.jsonrpc.request.EdgeRpcRequest; +import io.openems.common.jsonrpc.response.EdgeRpcResponse; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.JsonApiBuilder; +import io.openems.edge.common.jsonapi.MultipleJsonApiBinder; +import io.openems.edge.common.jsonapi.Subrequest; +import io.openems.edge.controller.api.websocket.ControllerApiWebsocket; + +@Component(property = "entry=" + RootRequestHandler.ENTRY_POINT) +public class EdgeRpcRequestHandler implements JsonApi { + + public static final String ENTRY_POINT = "edge.websocket.edgeRpc"; + + private final MultipleJsonApiBinder binder = new MultipleJsonApiBinder(); + + @Reference(// + cardinality = ReferenceCardinality.MULTIPLE, // + policy = ReferencePolicy.DYNAMIC, // + policyOption = ReferencePolicyOption.GREEDY, // + target = "(entry=" + ENTRY_POINT + ")" // + ) + protected void bindJsonApi(JsonApi jsonApi) { + this.binder.bindJsonApi(jsonApi); + } + + protected void unbindJsonApi(JsonApi jsonApi) { + this.binder.unbindJsonApi(jsonApi); + } + + @Override + public void buildJsonApiRoutes(JsonApiBuilder builder) { + builder.delegate(EdgeRpcRequest.METHOD, endpoint -> { + + }, call -> { + return EdgeRpcRequest.from(call.getRequest()).getPayload(); + }, b -> { + return this.binder.getJsonApiBuilder(); + }, response -> { + // wrap response in a EdgeRpcResponse if successful + if (response instanceof JsonrpcResponseSuccess success) { + return new EdgeRpcResponse(response.getId(), success); + } + return response; + }, () -> { + final var subrequest = new Subrequest(JsonUtils.buildJsonObject() // + .addProperty("edgeId", ControllerApiWebsocket.EDGE_ID) // + .build()); + subrequest.addRpcBuilderFor(this.binder.getJsonApiBuilder(), "payload"); + return List.of(subrequest); + }); + } + +} diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/RootRequestHandler.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/RootRequestHandler.java new file mode 100644 index 00000000000..1080884c136 --- /dev/null +++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/RootRequestHandler.java @@ -0,0 +1,48 @@ +package io.openems.edge.controller.api.websocket.handler; + +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; + +import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.JsonApiBuilder; +import io.openems.edge.common.jsonapi.MultipleJsonApiBinder; + +@Component(service = { RootRequestHandler.class, JsonApi.class }) +public class RootRequestHandler implements JsonApi { + + public static final String ENTRY_POINT = "edge.websocket.root"; + + private final MultipleJsonApiBinder apiBinder = new MultipleJsonApiBinder(); + private final BindingRoutesJsonApiHandler routesJsonApiHandler; + + @Reference(// + cardinality = ReferenceCardinality.MULTIPLE, // + policy = ReferencePolicy.DYNAMIC, // + policyOption = ReferencePolicyOption.GREEDY, // + target = "(entry=" + ENTRY_POINT + ")" // + ) + protected void bindJsonApi(JsonApi jsonApi) { + this.apiBinder.bindJsonApi(jsonApi); + this.routesJsonApiHandler.setBuilder(this.apiBinder.getJsonApiBuilder()); + } + + protected void unbindJsonApi(JsonApi jsonApi) { + this.apiBinder.unbindJsonApi(jsonApi); + this.routesJsonApiHandler.setBuilder(null); + } + + @Activate + public RootRequestHandler(@Reference BindingRoutesJsonApiHandler routesJsonApiHandler) { + this.routesJsonApiHandler = routesJsonApiHandler; + } + + @Override + public void buildJsonApiRoutes(JsonApiBuilder builder) { + builder.addBuilder(this.apiBinder.getJsonApiBuilder()); + } + +} diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/SubscribeChannelsRequestHandler.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/SubscribeChannelsRequestHandler.java new file mode 100644 index 00000000000..dbf4e4c0a6d --- /dev/null +++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/SubscribeChannelsRequestHandler.java @@ -0,0 +1,24 @@ +package io.openems.edge.controller.api.websocket.handler; + +import org.osgi.service.component.annotations.Component; + +import io.openems.common.jsonrpc.base.GenericJsonrpcResponseSuccess; +import io.openems.common.jsonrpc.request.SubscribeChannelsRequest; +import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.JsonApiBuilder; +import io.openems.edge.controller.api.websocket.OnRequest; + +@Component(property = "entry=" + EdgeRpcRequestHandler.ENTRY_POINT) +public class SubscribeChannelsRequestHandler implements JsonApi { + + @Override + public void buildJsonApiRoutes(JsonApiBuilder builder) { + builder.handleRequest(SubscribeChannelsRequest.METHOD, call -> { + final var request = SubscribeChannelsRequest.from(call.getRequest()); + call.get(OnRequest.WS_DATA_KEY).handleSubscribeChannelsRequest(request); + + return new GenericJsonrpcResponseSuccess(request.getId()); + }); + } + +} diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/SubscribeSystemLogRequestHandler.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/SubscribeSystemLogRequestHandler.java new file mode 100644 index 00000000000..172251df193 --- /dev/null +++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/SubscribeSystemLogRequestHandler.java @@ -0,0 +1,75 @@ +package io.openems.edge.controller.api.websocket.handler; + +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.ops4j.pax.logging.spi.PaxAppender; +import org.ops4j.pax.logging.spi.PaxLoggingEvent; +import org.osgi.service.component.annotations.Component; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.openems.common.exceptions.OpenemsException; +import io.openems.common.jsonrpc.base.GenericJsonrpcResponseSuccess; +import io.openems.common.jsonrpc.notification.EdgeRpcNotification; +import io.openems.common.jsonrpc.notification.SystemLogNotification; +import io.openems.common.jsonrpc.request.SubscribeSystemLogRequest; +import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.JsonApiBuilder; +import io.openems.edge.controller.api.websocket.ControllerApiWebsocket; +import io.openems.edge.controller.api.websocket.OnRequest; +import io.openems.edge.controller.api.websocket.WsData; + +@Component(property = { // + "entry=" + EdgeRpcRequestHandler.ENTRY_POINT, // + "org.ops4j.pax.logging.appender.name=Controller.Api.Websocket" // +}) +public class SubscribeSystemLogRequestHandler implements JsonApi, PaxAppender { + + private final Logger log = LoggerFactory.getLogger(SubscribeSystemLogRequestHandler.class); + + private final Set subscribers = ConcurrentHashMap.newKeySet(); + + @Override + public void buildJsonApiRoutes(JsonApiBuilder builder) { + builder.handleRequest(SubscribeSystemLogRequest.METHOD, call -> { + final var request = SubscribeSystemLogRequest.from(call.getRequest()); + final var wsData = call.get(OnRequest.WS_DATA_KEY); + + if (request.isSubscribe()) { + this.subscribers.add(wsData); + } else { + this.subscribers.remove(wsData); + } + + return new GenericJsonrpcResponseSuccess(request.getId()); + }); + } + + @Override + public void doAppend(PaxLoggingEvent event) { + if (this.subscribers.isEmpty()) { + return; + } + + final var notification = new EdgeRpcNotification(ControllerApiWebsocket.EDGE_ID, + SystemLogNotification.fromPaxLoggingEvent(event)); + + final var iter = this.subscribers.iterator(); + while (iter.hasNext()) { + final var wsData = iter.next(); + + if (wsData.getWebsocket().isFlushAndClose()) { + iter.remove(); + continue; + } + try { + wsData.send(notification); + } catch (OpenemsException e) { + this.log.warn("Unable to handle PaxLoggingEvent", e); + iter.remove(); + } + } + } + +} diff --git a/io.openems.edge.controller.api.websocket/test/io/openems/edge/controller/api/websocket/ControllerApiWebsocketImplTest.java b/io.openems.edge.controller.api.websocket/test/io/openems/edge/controller/api/websocket/ControllerApiWebsocketImplTest.java index 058fa42d5f4..b37f1fb4929 100644 --- a/io.openems.edge.controller.api.websocket/test/io/openems/edge/controller/api/websocket/ControllerApiWebsocketImplTest.java +++ b/io.openems.edge.controller.api.websocket/test/io/openems/edge/controller/api/websocket/ControllerApiWebsocketImplTest.java @@ -14,6 +14,7 @@ public class ControllerApiWebsocketImplTest { public void test() throws Exception { new ControllerTest(new ControllerApiWebsocketImpl()) // .addReference("componentManager", new DummyComponentManager()) // + .addReference("onRequestFactory", new DummyOnRequestFactory()) // .activate(MyConfig.create() // .setId(CTRL_ID) // .setApiTimeout(60) // diff --git a/io.openems.edge.controller.api.websocket/test/io/openems/edge/controller/api/websocket/DummyOnRequestFactory.java b/io.openems.edge.controller.api.websocket/test/io/openems/edge/controller/api/websocket/DummyOnRequestFactory.java new file mode 100644 index 00000000000..a953b39803c --- /dev/null +++ b/io.openems.edge.controller.api.websocket/test/io/openems/edge/controller/api/websocket/DummyOnRequestFactory.java @@ -0,0 +1,36 @@ +package io.openems.edge.controller.api.websocket; + +import java.lang.reflect.InvocationTargetException; + +import org.osgi.framework.ServiceReference; +import org.osgi.service.component.ComponentServiceObjects; + +import io.openems.common.utils.ReflectionUtils; + +public class DummyOnRequestFactory extends OnRequest.Factory { + + public DummyOnRequestFactory() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { + super(); + ReflectionUtils.setAttribute(OnRequest.Factory.class, this, "cso", new DummyOnRequestCso()); + } + + private static class DummyOnRequestCso implements ComponentServiceObjects { + + @Override + public OnRequest getService() { + return new OnRequest(); + } + + @Override + public void ungetService(OnRequest service) { + // empty for tests + } + + @Override + public ServiceReference getServiceReference() { + // empty for tests + return null; + } + } + +} diff --git a/io.openems.edge.controller.api.websocket/test/io/openems/edge/controller/api/websocket/MyConfig.java b/io.openems.edge.controller.api.websocket/test/io/openems/edge/controller/api/websocket/MyConfig.java index d3a294ee563..f234dea0c9d 100644 --- a/io.openems.edge.controller.api.websocket/test/io/openems/edge/controller/api/websocket/MyConfig.java +++ b/io.openems.edge.controller.api.websocket/test/io/openems/edge/controller/api/websocket/MyConfig.java @@ -9,6 +9,7 @@ protected static class Builder { private String id; private int port; private int apiTimeout; + private boolean debugMode; private Builder() { } @@ -28,6 +29,11 @@ public Builder setPort(int port) { return this; } + public Builder setDebugMode(boolean debugMode) { + this.debugMode = debugMode; + return this; + } + public MyConfig build() { return new MyConfig(this); } @@ -58,4 +64,10 @@ public int port() { public int apiTimeout() { return this.builder.apiTimeout; } + + @Override + public boolean debugMode() { + return this.builder.debugMode; + } + } \ No newline at end of file diff --git a/io.openems.edge.controller.api.websocket/test/io/openems/edge/controller/api/websocket/OnRequestTest.java b/io.openems.edge.controller.api.websocket/test/io/openems/edge/controller/api/websocket/OnRequestTest.java index 514e7e363f3..34295fb43d4 100644 --- a/io.openems.edge.controller.api.websocket/test/io/openems/edge/controller/api/websocket/OnRequestTest.java +++ b/io.openems.edge.controller.api.websocket/test/io/openems/edge/controller/api/websocket/OnRequestTest.java @@ -5,24 +5,45 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import org.junit.Before; import org.junit.Test; import io.openems.common.OpenemsConstants; import io.openems.common.jsonrpc.base.GenericJsonrpcRequest; +import io.openems.common.jsonrpc.base.JsonrpcRequest; +import io.openems.common.jsonrpc.base.JsonrpcResponse; import io.openems.common.jsonrpc.request.GetEdgeRequest; import io.openems.common.jsonrpc.request.GetEdgesRequest; +import io.openems.common.jsonrpc.response.GetEdgeResponse; +import io.openems.common.jsonrpc.response.GetEdgesResponse; import io.openems.common.jsonrpc.response.GetEdgesResponse.EdgeMetadata; import io.openems.common.utils.JsonUtils; +import io.openems.edge.common.jsonapi.Call; +import io.openems.edge.common.jsonapi.EdgeKeys; +import io.openems.edge.common.jsonapi.JsonApiBuilder; +import io.openems.edge.controller.api.websocket.handler.EdgeRequestHandler; public class OnRequestTest { + private JsonApiBuilder api; + + @Before + public void before() { + this.api = new JsonApiBuilder(); + new EdgeRequestHandler().buildJsonApiRoutes(this.api); + } + @Test public void testHandleGetEdgesRequest() throws Exception { - final var response = OnRequest.handleGetEdgesRequest(DUMMY_ADMIN, + final var call = new Call( GetEdgesRequest.from(new GenericJsonrpcRequest(GetEdgesRequest.METHOD, JsonUtils.buildJsonObject() // .addProperty("page", 0) // - .build()))) - .get(); + .build()))); + call.put(EdgeKeys.USER_KEY, DUMMY_ADMIN); + + this.api.handle(call); + + final var response = (GetEdgesResponse) call.getResponse(); final var edges = response.edgeMetadata; assertEquals(1, edges.size()); @@ -32,11 +53,15 @@ public void testHandleGetEdgesRequest() throws Exception { @Test public void testHandleGetEdgeRequest() throws Exception { - final var response = OnRequest.handleGetEdgeRequest(DUMMY_ADMIN, + final var call = new Call( GetEdgeRequest.from(new GenericJsonrpcRequest(GetEdgeRequest.METHOD, JsonUtils.buildJsonObject() // .addProperty("edgeId", ControllerApiWebsocket.EDGE_ID) // - .build()))) - .get(); + .build()))); + call.put(EdgeKeys.USER_KEY, DUMMY_ADMIN); + + this.api.handle(call); + + final var response = (GetEdgeResponse) call.getResponse(); this.validateLocalEdgeMetadata(response.edgeMetadata); } diff --git a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImpl.java b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImpl.java index 2646728095b..3f30cb88d2e 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImpl.java +++ b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImpl.java @@ -10,7 +10,6 @@ import java.time.ZonedDateTime; import java.util.List; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.CopyOnWriteArrayList; import org.osgi.service.cm.ConfigurationAdmin; @@ -26,21 +25,20 @@ import org.osgi.service.component.annotations.ReferencePolicyOption; import org.osgi.service.metatype.annotations.Designate; -import io.openems.common.exceptions.OpenemsError; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.jsonrpc.base.JsonrpcRequest; -import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; -import io.openems.common.session.Role; import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.ComponentJsonApi; +import io.openems.edge.common.jsonapi.EdgeKeys; +import io.openems.edge.common.jsonapi.JsonApiBuilder; import io.openems.edge.common.sum.Sum; import io.openems.edge.common.user.User; import io.openems.edge.controller.api.Controller; import io.openems.edge.controller.ess.emergencycapacityreserve.ControllerEssEmergencyCapacityReserve; import io.openems.edge.controller.ess.limittotaldischarge.ControllerEssLimitTotalDischarge; import io.openems.edge.controller.ess.timeofusetariff.jsonrpc.GetScheduleRequest; +import io.openems.edge.controller.ess.timeofusetariff.jsonrpc.GetScheduleResponse; import io.openems.edge.controller.ess.timeofusetariff.optimizer.Context; import io.openems.edge.controller.ess.timeofusetariff.optimizer.Optimizer; import io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils; @@ -60,7 +58,7 @@ configurationPolicy = ConfigurationPolicy.REQUIRE // ) public class TimeOfUseTariffControllerImpl extends AbstractOpenemsComponent - implements TimeOfUseTariffController, Controller, OpenemsComponent, TimedataProvider, JsonApi { + implements TimeOfUseTariffController, Controller, OpenemsComponent, TimedataProvider, ComponentJsonApi { /** The hard working Worker. */ private final Optimizer optimizer; @@ -262,13 +260,13 @@ public Timedata getTimedata() { } @Override - public CompletableFuture handleJsonrpcRequest(User user, JsonrpcRequest request) - throws OpenemsNamedException { - user.assertRoleIsAtLeast("handleJsonrpcRequest", Role.GUEST); - return switch (request.getMethod()) { - case GetScheduleRequest.METHOD -> this.handleGetScheduleRequest(user, GetScheduleRequest.from(request)); - default -> throw OpenemsError.JSONRPC_UNHANDLED_METHOD.exception(request.getMethod()); - }; + public void buildJsonApiRoutes(JsonApiBuilder builder) { + builder.handleRequest(GetScheduleRequest.METHOD, call -> { + return this.handleGetScheduleRequest(// + call.get(EdgeKeys.USER_KEY), // + GetScheduleRequest.from(call.getRequest()) // + ); + }); } /** @@ -279,10 +277,10 @@ public CompletableFuture handleJsonrpcRequest( * @return the Future JSON-RPC Response * @throws OpenemsNamedException on error */ - private CompletableFuture handleGetScheduleRequest(User user, - GetScheduleRequest request) throws OpenemsNamedException { - return CompletableFuture.completedFuture(Utils.handleGetScheduleRequest(this.optimizer, request.getId(), - this.timedata, this.id(), ZonedDateTime.now(this.componentManager.getClock()))); + protected GetScheduleResponse handleGetScheduleRequest(User user, GetScheduleRequest request) + throws OpenemsNamedException { + return Utils.handleGetScheduleRequest(this.optimizer, request.getId(), this.timedata, this.id(), + ZonedDateTime.now(this.componentManager.getClock())); } @Override diff --git a/io.openems.edge.controller.symmetric.balancingschedule/src/io/openems/edge/controller/symmetric/balancingschedule/ControllerEssBalancingSchedule.java b/io.openems.edge.controller.symmetric.balancingschedule/src/io/openems/edge/controller/symmetric/balancingschedule/ControllerEssBalancingSchedule.java index c8fa907e10a..6fc7c43f953 100644 --- a/io.openems.edge.controller.symmetric.balancingschedule/src/io/openems/edge/controller/symmetric/balancingschedule/ControllerEssBalancingSchedule.java +++ b/io.openems.edge.controller.symmetric.balancingschedule/src/io/openems/edge/controller/symmetric/balancingschedule/ControllerEssBalancingSchedule.java @@ -9,10 +9,9 @@ import io.openems.edge.common.channel.StateChannel; import io.openems.edge.common.channel.value.Value; import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.common.jsonapi.JsonApi; import io.openems.edge.controller.api.Controller; -public interface ControllerEssBalancingSchedule extends Controller, OpenemsComponent, JsonApi { +public interface ControllerEssBalancingSchedule extends Controller, OpenemsComponent { public enum ChannelId implements io.openems.edge.common.channel.ChannelId { NO_ACTIVE_SETPOINT(Doc.of(Level.INFO) // diff --git a/io.openems.edge.controller.symmetric.balancingschedule/src/io/openems/edge/controller/symmetric/balancingschedule/ControllerEssBalancingScheduleImpl.java b/io.openems.edge.controller.symmetric.balancingschedule/src/io/openems/edge/controller/symmetric/balancingschedule/ControllerEssBalancingScheduleImpl.java index 02bcb5ef9e9..72a69f96798 100644 --- a/io.openems.edge.controller.symmetric.balancingschedule/src/io/openems/edge/controller/symmetric/balancingschedule/ControllerEssBalancingScheduleImpl.java +++ b/io.openems.edge.controller.symmetric.balancingschedule/src/io/openems/edge/controller/symmetric/balancingschedule/ControllerEssBalancingScheduleImpl.java @@ -3,7 +3,6 @@ import java.time.ZonedDateTime; import java.util.List; import java.util.Optional; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.CopyOnWriteArrayList; import org.osgi.service.cm.ConfigurationAdmin; @@ -21,14 +20,10 @@ import org.slf4j.LoggerFactory; import com.google.gson.JsonArray; -import com.google.gson.JsonObject; import io.openems.common.exceptions.InvalidValueException; -import io.openems.common.exceptions.OpenemsError; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.jsonrpc.base.GenericJsonrpcResponseSuccess; -import io.openems.common.jsonrpc.base.JsonrpcRequest; -import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; import io.openems.common.jsonrpc.request.SetGridConnScheduleRequest; import io.openems.common.jsonrpc.request.SetGridConnScheduleRequest.GridConnSchedule; import io.openems.common.session.Role; @@ -36,8 +31,9 @@ import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.common.jsonapi.JsonApi; -import io.openems.edge.common.user.User; +import io.openems.edge.common.jsonapi.ComponentJsonApi; +import io.openems.edge.common.jsonapi.EdgeGuards; +import io.openems.edge.common.jsonapi.JsonApiBuilder; import io.openems.edge.controller.api.Controller; import io.openems.edge.ess.api.ManagedSymmetricEss; import io.openems.edge.meter.api.ElectricityMeter; @@ -49,7 +45,7 @@ configurationPolicy = ConfigurationPolicy.REQUIRE // ) public class ControllerEssBalancingScheduleImpl extends AbstractOpenemsComponent - implements ControllerEssBalancingSchedule, Controller, OpenemsComponent, JsonApi { + implements ControllerEssBalancingSchedule, Controller, OpenemsComponent, ComponentJsonApi { private final Logger log = LoggerFactory.getLogger(ControllerEssBalancingScheduleImpl.class); @@ -163,32 +159,14 @@ public void run() throws OpenemsNamedException { } @Override - public CompletableFuture handleJsonrpcRequest(User user, JsonrpcRequest request) - throws OpenemsNamedException { - user.assertRoleIsAtLeast("handleJsonrpcRequest", Role.OWNER); - - switch (request.getMethod()) { - - case SetGridConnScheduleRequest.METHOD: - return this.handleSetGridConnScheduleRequest(user, SetGridConnScheduleRequest.from(request)); - - default: - throw OpenemsError.JSONRPC_UNHANDLED_METHOD.exception(request.getMethod()); - } - } - - /** - * Handles a SetGridConnScheduleRequest. - * - * @param user the User - * @param request the SetGridConnScheduleRequest - * @return the Future JSON-RPC Response - * @throws OpenemsNamedException on error - */ - private CompletableFuture handleSetGridConnScheduleRequest(User user, - SetGridConnScheduleRequest request) { - this.schedule = request.getSchedule(); - return CompletableFuture.completedFuture(new GenericJsonrpcResponseSuccess(request.getId(), new JsonObject())); + public void buildJsonApiRoutes(JsonApiBuilder builder) { + builder.handleRequest(SetGridConnScheduleRequest.METHOD, def -> { + def.setGuards(EdgeGuards.roleIsAtleast(Role.OWNER)); + }, call -> { + final var request = SetGridConnScheduleRequest.from(call.getRequest()); + this.schedule = request.getSchedule(); + return new GenericJsonrpcResponseSuccess(request.getId()); + }); } /** diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppAssistant.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppAssistant.java index ce001806fdd..6532e61a7be 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppAssistant.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppAssistant.java @@ -1,8 +1,10 @@ package io.openems.edge.core.appmanager; +import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.jsonObjectSerializer; + import com.google.gson.JsonArray; -import com.google.gson.JsonObject; +import io.openems.common.jsonrpc.serialization.JsonSerializer; import io.openems.common.utils.JsonUtils; public class AppAssistant { @@ -89,16 +91,21 @@ private AppAssistant(String name, String alias, JsonArray fields) { } /** - * Gets this {@link AppAssistant} as {@link JsonObject}. - * - * @return the {@link JsonObject} + * Returns a {@link JsonSerializer} for a {@link AppAssistant}. + * + * @return the created {@link JsonSerializer} */ - public JsonObject toJsonObject() { - return JsonUtils.buildJsonObject() // - .addProperty("name", this.name) // - .addProperty("alias", this.alias) // - .add("fields", this.fields) // - .build(); + public static JsonSerializer serializer() { + return jsonObjectSerializer(AppAssistant.class, // + json -> new AppAssistant(// + json.getString("name"), // + json.getString("alias"), // + json.getJsonArray("fields")), // + obj -> JsonUtils.buildJsonObject() // + .addProperty("name", obj.name) // + .addProperty("alias", obj.alias) // + .add("fields", obj.fields) // + .build()); } } diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppCenterBackendUtilImpl.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppCenterBackendUtilImpl.java index b01715345f1..d27333d5d14 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppCenterBackendUtilImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppCenterBackendUtilImpl.java @@ -33,7 +33,7 @@ import io.openems.common.jsonrpc.response.AppCenterIsKeyApplicableResponse; import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.user.User; -import io.openems.edge.controller.api.backend.ControllerApiBackend; +import io.openems.edge.controller.api.backend.api.ControllerApiBackend; @Component public class AppCenterBackendUtilImpl implements AppCenterBackendUtil { @@ -105,7 +105,7 @@ public boolean isConnected() { private final CompletableFuture handleRequestAsync(User user, JsonrpcRequest request) throws OpenemsNamedException { - return this.getBackendOrError().handleJsonrpcRequest(user, new AppCenterRequest(request)) // + return this.getBackendOrError().sendRequest(user, new AppCenterRequest(request)) // .orTimeout(30L, TimeUnit.SECONDS); } diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppDescriptor.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppDescriptor.java index 17d500fd1af..ff3e9a3525a 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppDescriptor.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppDescriptor.java @@ -1,9 +1,9 @@ package io.openems.edge.core.appmanager; +import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.jsonObjectSerializer; import static io.openems.common.utils.StringUtils.definedOrElse; -import com.google.gson.JsonObject; - +import io.openems.common.jsonrpc.serialization.JsonSerializer; import io.openems.common.utils.JsonUtils; public class AppDescriptor { @@ -46,14 +46,20 @@ public final String getWebsiteUrl() { } /** - * Builds a {@link JsonObject} out of this {@link AppDescriptor}. - * - * @return the {@link JsonObject} + * Returns a {@link JsonSerializer} for a {@link AppDescriptor}. + * + * @return the created {@link JsonSerializer} */ - public JsonObject toJsonObject() { - return JsonUtils.buildJsonObject() // - .addPropertyIfNotNull("websiteUrl", this.websiteUrl) // - .build(); + public static JsonSerializer serializer() { + return jsonObjectSerializer(AppDescriptor.class, json -> { + return new AppDescriptor(// + json.getString("websiteUrl") // + ); + }, obj -> { + return JsonUtils.buildJsonObject() // + .addPropertyIfNotNull("websiteUrl", obj.websiteUrl) // + .build(); + }); } } diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManager.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManager.java index 46bbe033d65..73749f40d64 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManager.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManager.java @@ -5,12 +5,11 @@ import io.openems.edge.common.channel.StateChannel; import io.openems.edge.common.channel.value.Value; import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.common.jsonapi.JsonApi; /** * A Service that manages OpenEMS Apps. */ -public interface AppManager extends OpenemsComponent, JsonApi { +public interface AppManager extends OpenemsComponent { public enum ChannelId implements io.openems.edge.common.channel.ChannelId { WRONG_APP_CONFIGURATION(Doc.of(Level.WARNING) // diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManagerImpl.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManagerImpl.java index 0784dfa08ab..e06ac96c3a3 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManagerImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManagerImpl.java @@ -1,5 +1,7 @@ package io.openems.edge.core.appmanager; +import static java.util.Collections.emptyList; + import java.util.AbstractMap; import java.util.ArrayList; import java.util.Arrays; @@ -35,16 +37,13 @@ import org.slf4j.LoggerFactory; import com.google.gson.JsonArray; +import com.google.gson.JsonObject; -import io.openems.common.exceptions.OpenemsError; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; import io.openems.common.function.ThrowingConsumer; import io.openems.common.function.ThrowingFunction; import io.openems.common.function.ThrowingSupplier; -import io.openems.common.jsonrpc.base.GenericJsonrpcResponseSuccess; -import io.openems.common.jsonrpc.base.JsonrpcRequest; -import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; import io.openems.common.jsonrpc.request.UpdateComponentConfigRequest; import io.openems.common.jsonrpc.request.UpdateComponentConfigRequest.Property; import io.openems.common.oem.OpenemsEdgeOem; @@ -54,7 +53,10 @@ import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.ComponentJsonApi; +import io.openems.edge.common.jsonapi.EdgeGuards; +import io.openems.edge.common.jsonapi.EdgeKeys; +import io.openems.edge.common.jsonapi.JsonApiBuilder; import io.openems.edge.common.user.User; import io.openems.edge.core.appmanager.dependency.AppManagerAppHelper; import io.openems.edge.core.appmanager.dependency.Dependency; @@ -68,7 +70,6 @@ import io.openems.edge.core.appmanager.jsonrpc.GetApps; import io.openems.edge.core.appmanager.jsonrpc.UpdateAppInstance; import io.openems.edge.core.appmanager.validator.Validator; -import io.openems.edge.core.componentmanager.ComponentManagerImpl; @Designate(ocd = Config.class, factory = false) @Component(// @@ -77,9 +78,9 @@ property = { // "enabled=true" // }) -public class AppManagerImpl extends AbstractOpenemsComponent implements AppManager, OpenemsComponent, JsonApi { +public class AppManagerImpl extends AbstractOpenemsComponent implements AppManager, OpenemsComponent, ComponentJsonApi { - private final Logger log = LoggerFactory.getLogger(this.getClass()); + private final Logger log = LoggerFactory.getLogger(AppManagerImpl.class); @Reference private AppValidateWorker appValidateWorker; @@ -508,31 +509,31 @@ private final OpenemsAppInstance createInstanceWithFilledProperties(// * @return the Future JSON-RPC Response * @throws OpenemsNamedException on error */ - public CompletableFuture handleAddAppInstanceRequest(// + public AddAppInstance.Response handleAddAppInstanceRequest(// final User user, // nullable final AddAppInstance.Request request, // final boolean ignoreBackend // ) throws OpenemsNamedException { // check if key is valid for this app - if (!ignoreBackend && !this.backendUtil.isKeyApplicable(user, request.key, request.appId)) { + if (!ignoreBackend && !this.backendUtil.isKeyApplicable(user, request.key(), request.appId())) { throw new OpenemsException("Key not applicable!"); } - final var openemsApp = this.findAppByIdOrError(request.appId); + final var openemsApp = this.findAppByIdOrError(request.appId()); return this.lockModifyingApps(() -> { // initial check if the app can even be installed final var language = user == null ? Language.DEFAULT : user.getLanguage(); - openemsApp.getAppConfiguration(ConfigurationTarget.ADD, request.properties, language); + openemsApp.getAppConfiguration(ConfigurationTarget.ADD, request.properties(), language); this.validator.checkStatus(openemsApp, language); List warnings = new ArrayList<>(); - var instance = new OpenemsAppInstance(openemsApp.getAppId(), request.alias, UUID.randomUUID(), - request.properties, null); + var instance = new OpenemsAppInstance(openemsApp.getAppId(), request.alias(), UUID.randomUUID(), + request.properties(), null); if (!ignoreBackend) { try { // try to send the backend the install request - this.backendUtil.addInstallAppInstanceHistory(user, request.key, request.appId, + this.backendUtil.addInstallAppInstanceHistory(user, request.key(), request.appId(), instance.instanceId); } catch (OpenemsNamedException e) { // if timeout happens but the backend registered the app as installed it may @@ -564,8 +565,7 @@ public CompletableFuture handleAddAppInstanceRequest(// this.instantiatedApps.add(instance); } var instanceWithFilledProperties = this.createInstanceWithFilledProperties(openemsApp, instance); - return new Pair<>(true, CompletableFuture.completedFuture(// - new AddAppInstance.Response(request.id, instanceWithFilledProperties, warnings))); + return new Pair<>(true, new AddAppInstance.Response(instanceWithFilledProperties, warnings)); }, (shouldUpdate) -> { if (shouldUpdate == null || !shouldUpdate) { return; @@ -590,8 +590,8 @@ public CompletableFuture handleAddAppInstanceRequest(// * @return the Future JSON-RPC Response * @throws OpenemsNamedException on error */ - public CompletableFuture handleAddAppInstanceRequest(User user, - AddAppInstance.Request request) throws OpenemsNamedException { + public AddAppInstance.Response handleAddAppInstanceRequest(User user, AddAppInstance.Request request) + throws OpenemsNamedException { return this.handleAddAppInstanceRequest(user, request, false); } @@ -603,10 +603,10 @@ public CompletableFuture handleAddAppInstanceRequest(Us * @return the request id * @throws OpenemsNamedException on error */ - public CompletableFuture handleDeleteAppInstanceRequest(User user, - DeleteAppInstance.Request request) throws OpenemsNamedException { + public DeleteAppInstance.Response handleDeleteAppInstanceRequest(User user, DeleteAppInstance.Request request) + throws OpenemsNamedException { final var updatedResultPair = this.>lockModifyingApps(() -> { - final var instance = this.findInstanceById(request.instanceId).orElse(null); + final var instance = this.findInstanceById(request.instanceId()).orElse(null); if (instance == null) { return new Pair<>(false, null); } @@ -626,12 +626,12 @@ public CompletableFuture handleDeleteAppInstan try { this.updateAppManagerConfiguration(user, this.instantiatedApps); } catch (OpenemsNamedException e) { - throw new OpenemsException("Unable to update App-Manager configuration for ID [" + request.instanceId + throw new OpenemsException("Unable to update App-Manager configuration for ID [" + request.instanceId() + "]: " + e.getMessage()); } }); if (updatedResultPair == null) { - return CompletableFuture.completedFuture(new GenericJsonrpcResponseSuccess(request.id)); + return new DeleteAppInstance.Response(emptyList()); } final var updatedResult = updatedResultPair.first; @@ -648,10 +648,9 @@ public CompletableFuture handleDeleteAppInstan this._setAppsNotSyncedWithBackend(true); }); if (updatedResult == null) { - return CompletableFuture.completedFuture(new GenericJsonrpcResponseSuccess(request.id)); + return new DeleteAppInstance.Response(emptyList()); } else { - return CompletableFuture - .completedFuture(new DeleteAppInstance.Response(request.id, updatedResult.warnings)); + return new DeleteAppInstance.Response(updatedResult.warnings); } } @@ -663,17 +662,12 @@ public CompletableFuture handleDeleteAppInstan * @return the Future JSON-RPC Response * @throws OpenemsNamedException on error */ - private CompletableFuture handleGetAppAssistantRequest(// + private GetAppAssistant.Response handleGetAppAssistantRequest(// final User user, // final GetAppAssistant.Request request // ) throws OpenemsNamedException { - for (var app : this.availableApps) { - if (request.appId.equals(app.getAppId())) { - return CompletableFuture - .completedFuture(new GetAppAssistant.Response(request.id, app.getAppAssistant(user))); - } - } - throw new OpenemsException("App-ID [" + request.appId + "] is unknown"); + final var app = this.findAppByIdOrError(request.appId()); + return new GetAppAssistant.Response(app.getAppAssistant(user)); } /** @@ -684,11 +678,10 @@ private CompletableFuture handleGetAppAssistantRequest(/ * @return the Future JSON-RPC Response * @throws OpenemsNamedException on error */ - private CompletableFuture handleGetAppDescriptorRequest(User user, - GetAppDescriptor.Request request) throws OpenemsNamedException { - final var app = this.findAppByIdOrError(request.appId); - return CompletableFuture - .completedFuture(new GetAppDescriptor.Response(request.id, app.getAppDescriptor(this.oem))); + private GetAppDescriptor.Response handleGetAppDescriptorRequest(User user, GetAppDescriptor.Request request) + throws OpenemsNamedException { + final var app = this.findAppByIdOrError(request.appId()); + return new GetAppDescriptor.Response(app.getAppDescriptor(this.oem)); } /** @@ -699,10 +692,10 @@ private CompletableFuture handleGetAppDescriptorRequest( * @return the Future JSON-RPC Response * @throws OpenemsNamedException on error */ - private CompletableFuture handleGetAppInstancesRequest(User user, - GetAppInstances.Request request) throws OpenemsNamedException { + private GetAppInstances.Response handleGetAppInstancesRequest(User user, GetAppInstances.Request request) + throws OpenemsNamedException { var instances = this.instantiatedApps.stream() // - .filter(i -> i.appId.equals(request.appId)) // + .filter(i -> i.appId.equals(request.appId())) // .map(t -> { final var app = this.findAppById(t.appId).orElse(null); var properties = t.properties; @@ -710,8 +703,9 @@ private CompletableFuture handleGetAppInstancesRequest(U properties = AbstractOpenemsApp.fillUpProperties(app, properties); } return new OpenemsAppInstance(t.appId, t.alias, t.instanceId, properties, t.dependencies); - }); - return CompletableFuture.completedFuture(new GetAppInstances.Response(request.id, instances)); + }) // + .toList(); + return new GetAppInstances.Response(instances); } /** @@ -722,13 +716,12 @@ private CompletableFuture handleGetAppInstancesRequest(U * @return the Future JSON-RPC Response * @throws OpenemsNamedException on error */ - private CompletableFuture handleGetAppRequest(User user, GetApp.Request request) - throws OpenemsNamedException { - var app = this.availableApps.stream().filter(t -> t.getAppId().equals(request.appId)).findFirst().get(); - var instances = this.instantiatedApps.stream().filter(t -> t.appId.equals(request.appId)) - .collect(Collectors.toList()); - return CompletableFuture - .completedFuture(new GetApp.Response(request.id, app, instances, user.getLanguage(), this.validator)); + private GetApp.Response handleGetAppRequest(User user, GetApp.Request request) throws OpenemsNamedException { + final var app = this.findAppByIdOrError(request.appId()); + var instances = this.instantiatedApps.stream() // + .filter(t -> t.appId.equals(request.appId())) // + .toList(); + return GetApp.Response.newInstance(app, instances, user.getLanguage(), this.validator); } /** @@ -739,46 +732,103 @@ private CompletableFuture handleGetAppRequest(User user, * @return the Future JSON-RPC Response * @throws OpenemsNamedException on error */ - private CompletableFuture handleGetAppsRequest(User user, GetApps.Request request) - throws OpenemsNamedException { - return CompletableFuture.completedFuture(new GetApps.Response(request.id, this.availableApps, - this.instantiatedApps, user.getRole(), user.getLanguage(), this.validator)); + private GetApps.Response handleGetAppsRequest(User user, GetApps.Request request) throws OpenemsNamedException { + return GetApps.Response.newInstance(this.availableApps, this.instantiatedApps, user.getRole(), + user.getLanguage(), this.validator); } @Override - public CompletableFuture handleJsonrpcRequest(User user, JsonrpcRequest request) - throws OpenemsNamedException { - user.assertRoleIsAtLeast("handleJsonrpcRequest", Role.OWNER); + public void buildJsonApiRoutes(JsonApiBuilder builder) { + builder.handleRequest(new GetApps(), endpoint -> { + endpoint.setDescription(""" + Gets all available apps on the current edge. + """.stripIndent()); + + endpoint.applyRequestBuilder(request -> { + request.addExample(new GetApps.Request()); + }); - switch (request.getMethod()) { + }, call -> this.handleGetAppsRequest(call.get(EdgeKeys.USER_KEY), call.getRequest())); - case GetApps.METHOD: - return this.handleGetAppsRequest(user, GetApps.Request.from(request)); + builder.handleRequest(new GetApp(), endpoint -> { + endpoint.setDescription(""" + Gets an app by its id. + """.stripIndent()); - case GetApp.METHOD: - return this.handleGetAppRequest(user, GetApp.Request.from(request)); + endpoint.applyRequestBuilder(request -> { + request.addExample("Get Keba app", new GetApp.Request("App.Evcs.Keba")); + }); - case GetAppAssistant.METHOD: - return this.handleGetAppAssistantRequest(user, GetAppAssistant.Request.from(request)); + }, call -> this.handleGetAppRequest(call.get(EdgeKeys.USER_KEY), call.getRequest())); - case GetAppDescriptor.METHOD: - return this.handleGetAppDescriptorRequest(user, GetAppDescriptor.Request.from(request)); + builder.handleRequest(new GetAppAssistant(), endpoint -> { + endpoint.setDescription(""" + Gets the AppAssistant for a app. + """.stripIndent()); - case GetAppInstances.METHOD: - return this.handleGetAppInstancesRequest(user, GetAppInstances.Request.from(request)); + endpoint.applyRequestBuilder(request -> { + request.addExample("Get the AppAssistant for Keba app", new GetAppAssistant.Request("App.Evcs.Keba")); + }); - case AddAppInstance.METHOD: - return this.handleAddAppInstanceRequest(user, AddAppInstance.Request.from(request), false); + }, call -> this.handleGetAppAssistantRequest(call.get(EdgeKeys.USER_KEY), call.getRequest())); - case UpdateAppInstance.METHOD: - return this.handleUpdateAppInstanceRequest(user, UpdateAppInstance.Request.from(request)); + builder.handleRequest(new GetAppDescriptor(), endpoint -> { + endpoint.setDescription(""" + Gets the AppDescriptor for a app. + """.stripIndent()); - case DeleteAppInstance.METHOD: - return this.handleDeleteAppInstanceRequest(user, DeleteAppInstance.Request.from(request)); + endpoint.applyRequestBuilder(request -> { + request.addExample("Get the AppDescriptor for Keba app", new GetAppDescriptor.Request("App.Evcs.Keba")); + }); - default: - throw OpenemsError.JSONRPC_UNHANDLED_METHOD.exception(request.getMethod()); - } + }, call -> this.handleGetAppDescriptorRequest(call.get(EdgeKeys.USER_KEY), call.getRequest())); + + builder.handleRequest(new GetAppInstances(), endpoint -> { + endpoint.setDescription(""" + Gets the AppInstances for a app. + """.stripIndent()); + + endpoint.applyRequestBuilder(request -> { + request.addExample("Get the instances of the Keba app", new GetAppInstances.Request("App.Evcs.Keba")); + }); + + }, call -> this.handleGetAppInstancesRequest(call.get(EdgeKeys.USER_KEY), call.getRequest())); + + builder.handleRequest(new UpdateAppInstance(), endpoint -> { + endpoint.setDescription(""" + Updates a AppInstance. + """.stripIndent()); + + endpoint.setGuards(EdgeGuards.roleIsAtleast(Role.OWNER)); + + }, call -> this.handleUpdateAppInstanceRequest(call.get(EdgeKeys.USER_KEY), call.getRequest())); + + builder.handleRequest(new DeleteAppInstance(), endpoint -> { + endpoint.setDescription(""" + Deletes a AppInstance. + """.stripIndent()) // + .setGuards(EdgeGuards.roleIsAtleast(Role.INSTALLER)); + + }, call -> this.handleDeleteAppInstanceRequest(call.get(EdgeKeys.USER_KEY), call.getRequest())); + + builder.handleRequest(new AddAppInstance(), endpoint -> { + endpoint.setDescription(""" + Handles a AddAppInstance Request. + """.stripIndent()); + endpoint.setGuards(EdgeGuards.roleIsAtleast(Role.OWNER)); + + endpoint.applyRequestBuilder(request -> { + request.addExample(new AddAppInstance.Request("0000-0000-0000-0000", "App.Id", "alias", + JsonUtils.buildJsonObject() // + .addProperty("key", "value") // + .build())); + }); + endpoint.applyResponseBuilder(response -> { + response.addExample(new AddAppInstance.Response( + new OpenemsAppInstance("App.Id", "alias", UUID.randomUUID(), new JsonObject(), emptyList()), + emptyList())); + }); + }, call -> this.handleAddAppInstanceRequest(call.get(EdgeKeys.USER_KEY), call.getRequest())); } /** @@ -789,15 +839,15 @@ public CompletableFuture handleJsonrpcRequest( * @return the Future JSON-RPC Response * @throws OpenemsNamedException on error */ - public CompletableFuture handleUpdateAppInstanceRequest(User user, - UpdateAppInstance.Request request) throws OpenemsNamedException { + public UpdateAppInstance.Response handleUpdateAppInstanceRequest(User user, UpdateAppInstance.Request request) + throws OpenemsNamedException { return this.lockModifyingApps(() -> { - final var oldApp = this.findInstanceByIdOrError(request.instanceId); + final var oldApp = this.findInstanceByIdOrError(request.instanceId()); final var app = this.findAppByIdOrError(oldApp.appId); - app.getAppConfiguration(ConfigurationTarget.UPDATE, request.properties, user.getLanguage()); + app.getAppConfiguration(ConfigurationTarget.UPDATE, request.properties(), user.getLanguage()); - final var updatedInstance = new OpenemsAppInstance(oldApp.appId, request.alias, oldApp.instanceId, - request.properties, oldApp.dependencies); + final var updatedInstance = new OpenemsAppInstance(oldApp.appId, request.alias(), oldApp.instanceId, + request.properties(), oldApp.dependencies); var result = this.lastUpdate = this.useAppManagerAppHelper(appHelper -> { return appHelper.updateApp(user, oldApp, updatedInstance, app); @@ -807,9 +857,9 @@ public CompletableFuture handleUpdateAppInstanceRequ // replace old instances with new ones this.instantiatedApps.removeAll(result.modifiedOrCreatedApps); this.instantiatedApps.addAll(result.modifiedOrCreatedApps); - return new Pair<>(true, CompletableFuture.completedFuture(// - new UpdateAppInstance.Response(request.id, // - this.createInstanceWithFilledProperties(app, result.rootInstance), result.warnings))); + + return new Pair<>(true, new UpdateAppInstance.Response( + this.createInstanceWithFilledProperties(app, result.rootInstance), result.warnings)); }, (shouldUpdate) -> { if (shouldUpdate == null || !shouldUpdate) { return; @@ -817,7 +867,7 @@ public CompletableFuture handleUpdateAppInstanceRequ try { this.updateAppManagerConfiguration(user, this.instantiatedApps); } catch (OpenemsNamedException e) { - throw new OpenemsException("Unable to update App-Manager configuration for ID [" + request.instanceId + throw new OpenemsException("Unable to update App-Manager configuration for ID [" + request.instanceId() + "]: " + e.getMessage()); } }); @@ -834,13 +884,9 @@ private void updateAppManagerConfiguration(User user, List a this.waitingForModified = true; AppManagerImpl.sortApps(apps); var p = new Property("apps", getJsonAppsString(apps)); - var updateRequest = new UpdateComponentConfigRequest(SINGLETON_COMPONENT_ID, Arrays.asList(p)); // user can be null using internal method - if (user == null) { - ((ComponentManagerImpl) this.componentManager).handleUpdateComponentConfigRequest(user, updateRequest); - } else { - this.componentManager.handleJsonrpcRequest(user, updateRequest); - } + this.componentManager.handleUpdateComponentConfigRequest(user, + new UpdateComponentConfigRequest(SINGLETON_COMPONENT_ID, Arrays.asList(p))); } private static void sortApps(List apps) { diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/ComponentUtilImpl.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/ComponentUtilImpl.java index 2cc1648bc68..46e6d79ebaa 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/ComponentUtilImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/ComponentUtilImpl.java @@ -41,9 +41,8 @@ import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.host.Host; -import io.openems.edge.common.jsonapi.JsonApi; import io.openems.edge.common.user.User; -import io.openems.edge.core.componentmanager.ComponentManagerImpl; +import io.openems.edge.core.host.HostImpl; import io.openems.edge.core.host.NetworkInterface; import io.openems.edge.core.host.jsonrpc.SetNetworkConfigRequest; import io.openems.edge.io.api.DigitalOutput; @@ -548,8 +547,8 @@ public String[] getPreferredRelays(// @Override public void updateInterfaces(User user, List> interfaces) throws OpenemsNamedException { - JsonApi host = this.componentManager.getComponent(Host.SINGLETON_COMPONENT_ID); - host.handleJsonrpcRequest(user, new SetNetworkConfigRequest(interfaces)); + HostImpl host = this.componentManager.getComponent(Host.SINGLETON_COMPONENT_ID); + host.handleSetNetworkConfigRequest(user, new SetNetworkConfigRequest(interfaces)); // wait until its updated do { @@ -628,12 +627,7 @@ public synchronized void setSchedulerComponentIds(// new UpdateComponentConfigRequest.Property("controllers.ids", ids) // )); - if (user != null) { - this.componentManager.handleJsonrpcRequest(user, request).get(); - return; - } - - ((ComponentManagerImpl) this.componentManager).handleUpdateComponentConfigRequest(user, request).get(); + this.componentManager.handleUpdateComponentConfigRequest(user, request); } catch (Exception e) { e.printStackTrace(); throw new OpenemsException("Could not update Scheduler!"); diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/OpenemsAppInstance.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/OpenemsAppInstance.java index 7240d9a6c67..45cc193805c 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/OpenemsAppInstance.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/OpenemsAppInstance.java @@ -1,11 +1,17 @@ package io.openems.edge.core.appmanager; +import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.jsonObjectSerializer; +import static io.openems.common.utils.JsonUtils.toJsonArray; +import static java.util.Collections.emptyList; + import java.util.List; import java.util.Objects; import java.util.UUID; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import io.openems.common.jsonrpc.serialization.JsonSerializer; import io.openems.common.utils.JsonUtils; import io.openems.edge.core.appmanager.dependency.Dependency; @@ -27,7 +33,7 @@ public OpenemsAppInstance(String appId, String alias, UUID instanceId, JsonObjec this.alias = alias; this.instanceId = Objects.requireNonNull(instanceId); this.properties = properties; - this.dependencies = dependencies; + this.dependencies = dependencies == null ? emptyList() : dependencies; } @Override @@ -47,21 +53,39 @@ public int hashCode() { return Objects.hash(this.instanceId); } + /** + * Returns a {@link JsonSerializer} for a {@link OpenemsAppInstance}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(OpenemsAppInstance.class, // + json -> new OpenemsAppInstance(// + json.getString("appId"), // + json.getString("alias"), // + json.getStringPath("instanceId").getAsUuid(), // + json.getJsonObject("properties"), // + // TODO add optional methods + json.getList("dependencies", Dependency.serializer())), // + obj -> JsonUtils.buildJsonObject() // + .addProperty("appId", obj.appId) // + .addProperty("alias", obj.alias != null ? obj.alias : "") // + .addProperty("instanceId", obj.instanceId.toString()) // + .add("properties", obj.properties == null ? new JsonObject() : obj.properties) // + .onlyIf(obj.dependencies != null && !obj.dependencies.isEmpty(), b -> b // + .add("dependencies", obj.dependencies.stream() // + .map(Dependency.serializer()::serialize) // + .collect(toJsonArray()))) // + .build()); + } + /** * Gets this {@link OpenemsAppInstance} as {@link JsonObject}. * * @return the {@link JsonObject} */ - public JsonObject toJsonObject() { - return JsonUtils.buildJsonObject() // - .addProperty("appId", this.appId) // - .addProperty("alias", this.alias != null ? this.alias : "") // - .addProperty("instanceId", this.instanceId.toString()) // - // TODO define if the field is editable - .add("properties", this.properties == null ? new JsonObject() : this.properties) // - .onlyIf(this.dependencies != null && !this.dependencies.isEmpty(), j -> j.add("dependencies", // - this.dependencies.stream().map(Dependency::toJsonObject).collect(JsonUtils.toJsonArray()))) - .build(); + public JsonElement toJsonObject() { + return serializer().serialize(this); } } diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/ResolveDependencies.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/ResolveDependencies.java index e7222904914..a14ae6a2bea 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/ResolveDependencies.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/ResolveDependencies.java @@ -1,7 +1,6 @@ package io.openems.edge.core.appmanager; import java.util.List; -import java.util.concurrent.ExecutionException; import org.osgi.framework.BundleContext; import org.slf4j.Logger; @@ -105,16 +104,15 @@ public static void resolveDependencies(User user, AppManagerImpl appManagerImpl, try { LOG.info(String.format("Resolving dependency with installing %s!", config.appId)); - var future = appManagerImpl.handleAddAppInstanceRequest(user, // + appManagerImpl.handleAddAppInstanceRequest(user, // new AddAppInstance.Request(// config.appId, "key", // config.alias, // config.initialProperties), true); - future.get(); resolveDependencies(user, appManagerImpl, appManagerUtil); return; - } catch (OpenemsNamedException | InterruptedException | ExecutionException e) { + } catch (OpenemsNamedException e) { e.printStackTrace(); } } diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/Dependency.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/Dependency.java index 71ed57c8aff..acb45b0508c 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/Dependency.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/Dependency.java @@ -1,9 +1,12 @@ package io.openems.edge.core.appmanager.dependency; +import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.jsonObjectSerializer; + import java.util.UUID; import com.google.gson.JsonObject; +import io.openems.common.jsonrpc.serialization.JsonSerializer; import io.openems.common.utils.JsonUtils; import io.openems.edge.core.appmanager.AppManager; @@ -35,4 +38,20 @@ public JsonObject toJsonObject() { .build(); } + /** + * Returns a {@link JsonSerializer} for a {@link Dependency}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(Dependency.class, // + json -> new Dependency(// + json.getString("key"), // + json.getStringPath("instanceId").getAsUuid()), // + obj -> JsonUtils.buildJsonObject() // + .addProperty("key", obj.key) // + .addProperty("instanceId", obj.instanceId.toString()) // + .build()); + } + } diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/ComponentAggregateTaskImpl.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/ComponentAggregateTaskImpl.java index 4ac9a8b6e3f..b7c8349e4ed 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/ComponentAggregateTaskImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/ComponentAggregateTaskImpl.java @@ -26,7 +26,6 @@ import io.openems.edge.core.appmanager.ComponentUtilImpl; import io.openems.edge.core.appmanager.TranslationUtil; import io.openems.edge.core.appmanager.dependency.AppManagerAppHelperImpl; -import io.openems.edge.core.componentmanager.ComponentManagerImpl; @Component(// service = { // @@ -180,13 +179,8 @@ public void delete(User user, List otherAppConfigurations) thr } try { - final var request = new DeleteComponentConfigRequest(comp.getId()); - if (user != null) { - this.componentManager.handleJsonrpcRequest(user, request); - } else { - // user can be null using internal method - ((ComponentManagerImpl) this.componentManager).handleDeleteComponentConfigRequest(user, request); - } + this.componentManager.handleDeleteComponentConfigRequest(user, + new DeleteComponentConfigRequest(comp.getId())); this.deletedComponents.add(comp.getId()); } catch (OpenemsNamedException e) { errors.add(e.toString()); @@ -247,13 +241,8 @@ private void createComponent(User user, EdgeConfig.Component comp) throws Openem properties.add(new Property("id", comp.getId())); properties.add(new Property("alias", comp.getAlias())); - var request = new CreateComponentConfigRequest(comp.getFactoryId(), properties); - if (user != null) { - this.componentManager.handleJsonrpcRequest(user, request); - return; - } - // user can be null using internal method - ((ComponentManagerImpl) this.componentManager).handleCreateComponentConfigRequest(user, request); + this.componentManager.handleCreateComponentConfigRequest(user, + new CreateComponentConfigRequest(comp.getFactoryId(), properties)); } /** @@ -276,14 +265,9 @@ private void reconfigure(User user, EdgeConfig.Component myComp, EdgeConfig.Comp .map(t -> new Property(t.getKey(), t.getValue())) // .collect(Collectors.toList()); properties.add(new Property("alias", myComp.getAlias())); - var updateRequest = new UpdateComponentConfigRequest(actualComp.getId(), properties); - if (user != null) { - this.componentManager.handleJsonrpcRequest(user, updateRequest); - return; - } - // user can be null using internal method - ((ComponentManagerImpl) this.componentManager).handleUpdateComponentConfigRequest(user, updateRequest); + this.componentManager.handleUpdateComponentConfigRequest(user, + new UpdateComponentConfigRequest(actualComp.getId(), properties)); } @Override diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/PersistencePredictorAggregateTaskImpl.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/PersistencePredictorAggregateTaskImpl.java index 6b4995c0aef..49bfb12f7ed 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/PersistencePredictorAggregateTaskImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/PersistencePredictorAggregateTaskImpl.java @@ -8,7 +8,6 @@ import java.util.List; import java.util.Optional; import java.util.Set; -import java.util.concurrent.ExecutionException; import java.util.stream.Stream; import org.osgi.service.component.annotations.Activate; @@ -144,15 +143,12 @@ private static void updatePredictor(// existingChannels.addAll(channelsToAdd); existingChannels.removeAll(channelsToRemove); - try { - componentManager.handleJsonrpcRequest(user, new UpdateComponentConfigRequest(predictor.id(), List.of(// - new UpdateComponentConfigRequest.Property("channelAddresses", existingChannels.stream() // - .map(JsonPrimitive::new) // - .collect(toJsonArray())) // - ))).get(); - } catch (InterruptedException | ExecutionException e) { - throw new OpenemsException("Unable to update Persistence Predictor", e); - } + componentManager.handleUpdateComponentConfigRequest(user, + new UpdateComponentConfigRequest(predictor.id(), List.of(// + new UpdateComponentConfigRequest.Property("channelAddresses", existingChannels.stream() // + .map(JsonPrimitive::new) // + .collect(toJsonArray())) // + ))); } private static Set getAllChannels(List otherAppConfigurations) { diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/AddAppInstance.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/AddAppInstance.java index 6eb47e5c592..17c21023811 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/AddAppInstance.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/AddAppInstance.java @@ -1,18 +1,20 @@ package io.openems.edge.core.appmanager.jsonrpc; +import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.jsonObjectSerializer; +import static io.openems.common.utils.JsonUtils.toJsonArray; + import java.util.List; -import java.util.Optional; -import java.util.UUID; -import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.jsonrpc.base.JsonrpcRequest; -import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; +import io.openems.common.jsonrpc.serialization.JsonElementPath; +import io.openems.common.jsonrpc.serialization.JsonSerializer; import io.openems.common.utils.JsonUtils; +import io.openems.edge.common.jsonapi.EndpointRequestType; import io.openems.edge.core.appmanager.OpenemsAppInstance; +import io.openems.edge.core.appmanager.jsonrpc.AddAppInstance.Request; +import io.openems.edge.core.appmanager.jsonrpc.AddAppInstance.Response; /** * Adds an {@link OpenemsAppInstance}. @@ -46,81 +48,73 @@ * } * */ -public class AddAppInstance { - - public static final String METHOD = "addAppInstance"; - - public static class Request extends JsonrpcRequest { +public class AddAppInstance implements EndpointRequestType { - /** - * Parses a generic {@link JsonrpcRequest} to a {@link AddAppInstance}. - * - * @param r the {@link JsonrpcRequest} - * @return the {@link AddAppInstance} Request - * @throws OpenemsNamedException on error - */ - public static Request from(JsonrpcRequest r) throws OpenemsNamedException { - var p = r.getParams(); - var key = JsonUtils.getAsString(p, "key"); - var appId = JsonUtils.getAsString(p, "appId"); - var alias = JsonUtils.getAsOptionalString(p, "alias").orElse(null); - var properties = JsonUtils.getAsJsonObject(p, "properties"); - return new Request(r, key, appId, alias, properties); - } + @Override + public String getMethod() { + return "addAppInstance"; + } - public final String key; + @Override + public JsonSerializer getRequestSerializer() { + return Request.serializer(); + } - public final String appId; - public final String alias; - public final JsonObject properties; + @Override + public JsonSerializer getResponseSerializer() { + return Response.serializer(); + } - private Request(JsonrpcRequest request, String key, String appId, String alias, JsonObject properties) { - super(request, METHOD); - this.key = key; - this.appId = appId; - this.alias = alias; - this.properties = properties; - } + public static record Request(// + String appId, // + String key, // + String alias, // + JsonObject properties // + ) { - public Request(String appId, String key, String alias, JsonObject properties) { - super(METHOD); - this.key = key; - this.appId = appId; - this.alias = alias; - this.properties = properties; + /** + * Returns a {@link JsonSerializer} for a {@link AddAppInstance.Request}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(Request.class, // + json -> new Request(// + json.getString("appId"), // + json.getString("key"), // + json.getString("alias"), // + json.getJsonObject("properties")), + obj -> JsonUtils.buildJsonObject() // + .addProperty("appId", obj.appId()) // + .addProperty("key", obj.key()) // + .addProperty("alias", obj.alias()) // + .add("properties", obj.properties()) // + .build()); } - @Override - public JsonObject getParams() { - return JsonUtils.buildJsonObject() // - .addProperty("appId", this.appId) // - .addPropertyIfNotNull("alias", this.alias) // - .add("properties", this.properties) // - .build(); - } } - public static class Response extends JsonrpcResponseSuccess { - - public final OpenemsAppInstance instance; - public final JsonArray warnings; + public record Response(// + OpenemsAppInstance instance, // + List warnings // + ) { - public Response(UUID id, OpenemsAppInstance instance, List warnings) { - super(id); - this.instance = instance; - this.warnings = Optional.ofNullable(warnings) // - .map(t -> t.stream() // - .map(JsonPrimitive::new) // - .collect(JsonUtils.toJsonArray())) - .orElse(new JsonArray()); - } - - @Override - public JsonObject getResult() { - return JsonUtils.buildJsonObject() // - .add("instance", this.instance.toJsonObject()) // - .add("warnings", this.warnings) // - .build(); + /** + * Returns a {@link JsonSerializer} for a {@link AddAppInstance.Response}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(Response.class, // + json -> new Response(// + json.getElement("instance", OpenemsAppInstance.serializer()), // + json.getList("warnings", JsonElementPath::getAsString)), // + obj -> JsonUtils.buildJsonObject() // + .add("instance", obj.instance.toJsonObject()) // + .add("warnings", obj.warnings.stream() // + .map(JsonPrimitive::new) // + .collect(toJsonArray())) // + .build()); } } diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/DeleteAppInstance.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/DeleteAppInstance.java index 3806cd6339a..f3023bb117b 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/DeleteAppInstance.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/DeleteAppInstance.java @@ -1,17 +1,20 @@ package io.openems.edge.core.appmanager.jsonrpc; +import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.jsonObjectSerializer; +import static io.openems.common.utils.JsonUtils.toJsonArray; + import java.util.List; import java.util.UUID; -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.jsonrpc.base.JsonrpcRequest; -import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; +import io.openems.common.jsonrpc.serialization.JsonElementPath; +import io.openems.common.jsonrpc.serialization.JsonSerializer; import io.openems.common.utils.JsonUtils; +import io.openems.edge.common.jsonapi.EndpointRequestType; import io.openems.edge.core.appmanager.OpenemsAppInstance; +import io.openems.edge.core.appmanager.jsonrpc.DeleteAppInstance.Request; +import io.openems.edge.core.appmanager.jsonrpc.DeleteAppInstance.Response; /** * Updates an {@link OpenemsAppInstance}.. @@ -43,61 +46,63 @@ * } * */ -public class DeleteAppInstance { - - public static final String METHOD = "deleteAppInstance"; +public final class DeleteAppInstance implements EndpointRequestType { - public static class Request extends JsonrpcRequest { + @Override + public String getMethod() { + return "deleteAppInstance"; + } - /** - * Parses a generic {@link JsonrpcRequest} to a {@link DeleteAppInstance}. - * - * @param r the {@link JsonrpcRequest} - * @return the {@link DeleteAppInstance} - * @throws OpenemsNamedException on error - */ - public static Request from(JsonrpcRequest r) throws OpenemsNamedException { - var p = r.getParams(); - var instanceId = JsonUtils.getAsUUID(p, "instanceId"); - return new Request(r, instanceId); - } + @Override + public JsonSerializer getRequestSerializer() { + return Request.serializer(); + } - public final UUID instanceId; + @Override + public JsonSerializer getResponseSerializer() { + return Response.serializer(); + } - private Request(JsonrpcRequest request, UUID instanceId) { - super(request, METHOD); - this.instanceId = instanceId; - } + public record Request(// + UUID instanceId // + ) { - public Request(UUID instanceId) { - super(METHOD); - this.instanceId = instanceId; + /** + * Returns a {@link JsonSerializer} for a {@link DeleteAppInstance.Request}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(DeleteAppInstance.Request.class, // + json -> new DeleteAppInstance.Request(// + json.getStringPath("instanceId").getAsUuid()), // + obj -> JsonUtils.buildJsonObject() // + .addProperty("instanceId", obj.instanceId().toString()) // + .build()); } - @Override - public JsonObject getParams() { - return JsonUtils.buildJsonObject() // - .addProperty("instanceId", this.instanceId.toString()) // - .build(); - } } - public static class Response extends JsonrpcResponseSuccess { + public record Response(// + List warnings // + ) { - private final JsonArray warnings; - - public Response(UUID id, List warnings) { - super(id); - this.warnings = warnings == null ? new JsonArray() - : warnings.stream().map(JsonPrimitive::new).collect(JsonUtils.toJsonArray()); + /** + * Returns a {@link JsonSerializer} for a {@link DeleteAppInstance.Response}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(DeleteAppInstance.Response.class, // + json -> new DeleteAppInstance.Response(// + json.getList("warnings", JsonElementPath::getAsString)), // + obj -> JsonUtils.buildJsonObject() // + .add("warnings", obj.warnings().stream() // + .map(JsonPrimitive::new) // + .collect(toJsonArray())) // + .build()); } - @Override - public JsonObject getResult() { - return JsonUtils.buildJsonObject() // - .add("warnings", this.warnings) // - .build(); - } } } diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/GetApp.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/GetApp.java index 4dfed6389ff..1263f5a5ed7 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/GetApp.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/GetApp.java @@ -1,8 +1,9 @@ package io.openems.edge.core.appmanager.jsonrpc; +import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.jsonObjectSerializer; + import java.util.Arrays; import java.util.List; -import java.util.UUID; import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -12,13 +13,15 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; -import io.openems.common.jsonrpc.base.JsonrpcRequest; -import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; +import io.openems.common.jsonrpc.serialization.JsonSerializer; import io.openems.common.session.Language; import io.openems.common.utils.JsonUtils; +import io.openems.edge.common.jsonapi.EndpointRequestType; import io.openems.edge.core.appmanager.OpenemsApp; import io.openems.edge.core.appmanager.OpenemsAppInstance; import io.openems.edge.core.appmanager.flag.Flag; +import io.openems.edge.core.appmanager.jsonrpc.GetApp.Request; +import io.openems.edge.core.appmanager.jsonrpc.GetApp.Response; import io.openems.edge.core.appmanager.validator.OpenemsAppStatus; import io.openems.edge.core.appmanager.validator.Validator; @@ -65,60 +68,77 @@ * } * */ -public class GetApp { - - public static final String METHOD = "getApp"; - - public static class Request extends JsonrpcRequest { +public class GetApp implements EndpointRequestType { - /** - * Parses a generic {@link JsonrpcRequest} to a {@link Request}. - * - * @param r the {@link JsonrpcRequest} - * @return the {@link GetAppsRequest} - * @throws OpenemsNamedException on error - */ - public static Request from(JsonrpcRequest r) throws OpenemsNamedException { - var p = r.getParams(); - var appId = JsonUtils.getAsString(p, "appId"); - return new Request(r, appId); - } + @Override + public String getMethod() { + return "getApp"; + } - public final String appId; + @Override + public JsonSerializer getRequestSerializer() { + return Request.serializer(); + } - private Request(JsonrpcRequest request, String appId) { - super(request, METHOD); - this.appId = appId; - } + @Override + public JsonSerializer getResponseSerializer() { + return Response.serializer(); + } - public Request(String appId) { - super(METHOD); - this.appId = appId; - } + public record Request(// + String appId // + ) { - @Override - public JsonObject getParams() { - return new JsonObject(); + /** + * Returns a {@link JsonSerializer} for a {@link GetApp.Request}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(GetApp.Request.class, // + json -> new GetApp.Request(// + json.getString("appId")), // + obj -> JsonUtils.buildJsonObject() // + .addProperty("appId", obj.appId()) // + .build()); } } - public static class Response extends JsonrpcResponseSuccess { - - private final JsonObject app; + public record Response(// + JsonObject app // + ) { - public Response(UUID id, OpenemsApp app, List instantiatedApps, Language language, + /** + * Creates a Response. + * + * @param app the app of the response + * @param instantiatedApps all created {@link OpenemsAppInstance} + * @param language the current language + * @param validator the {@link Validator} + * @return the created Response + * @throws OpenemsNamedException on error + */ + public static Response newInstance(OpenemsApp app, List instantiatedApps, Language language, Validator validator) throws OpenemsNamedException { - super(id); - this.app = createJsonObjectOf(app, validator, instantiatedApps, language); + return new Response(createJsonObjectOf(app, validator, instantiatedApps, language)); } - @Override - public JsonObject getResult() { - return JsonUtils.buildJsonObject() // - .add("app", this.app) // - .build(); + /** + * Returns a {@link JsonSerializer} for a {@link GetApp.Response}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(GetApp.Response.class, // + json -> new GetApp.Response(JsonUtils.buildJsonObject() // + .addProperty("appId", json.getString("appId")) // + .build()), // + obj -> JsonUtils.buildJsonObject() // + .add("app", obj.app()) // + .build()); } + } /** diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/GetAppAssistant.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/GetAppAssistant.java index 6532d89fd71..18f99677a19 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/GetAppAssistant.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/GetAppAssistant.java @@ -1,15 +1,15 @@ package io.openems.edge.core.appmanager.jsonrpc; -import java.util.UUID; +import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.jsonObjectSerializer; +import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.jsonSerializer; -import com.google.gson.JsonObject; - -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.jsonrpc.base.JsonrpcRequest; -import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; +import io.openems.common.jsonrpc.serialization.JsonSerializer; import io.openems.common.utils.JsonUtils; +import io.openems.edge.common.jsonapi.EndpointRequestType; import io.openems.edge.core.appmanager.AppAssistant; import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.jsonrpc.GetAppAssistant.Request; +import io.openems.edge.core.appmanager.jsonrpc.GetAppAssistant.Response; /** * Gets the App-Assistant for a {@link OpenemsApp}. @@ -36,63 +36,61 @@ * "jsonrpc": "2.0", * "id": "UUID", * "result": { - * ... {@link AppAssistant#toJsonObject()} + * ... {@link AppAssistant#serializer()} * } * } * */ -public class GetAppAssistant { +public class GetAppAssistant implements EndpointRequestType { + + @Override + public String getMethod() { + return "getAppAssistant"; + } - public static final String METHOD = "getAppAssistant"; + @Override + public JsonSerializer getRequestSerializer() { + return Request.serializer(); + } - public static class Request extends JsonrpcRequest { + @Override + public JsonSerializer getResponseSerializer() { + return Response.serializer(); + } + public record Request(// + String appId // + ) { /** - * Parses a generic {@link JsonrpcRequest} to a {@link GetAppAssistantRequest}. - * - * @param r the {@link JsonrpcRequest} - * @return the {@link GetAppAssistantRequest} - * @throws OpenemsNamedException on error + * Returns a {@link JsonSerializer} for a {@link GetAppAssistant.Request}. + * + * @return the created {@link JsonSerializer} */ - public static Request from(JsonrpcRequest r) throws OpenemsNamedException { - var p = r.getParams(); - var appId = JsonUtils.getAsString(p, "appId"); - return new Request(r, appId); - } - - public final String appId; - - public Request(JsonrpcRequest request, String appId) { - super(request, METHOD); - this.appId = appId; + public static JsonSerializer serializer() { + return jsonObjectSerializer(GetAppAssistant.Request.class, // + json -> new GetAppAssistant.Request(// + json.getString("appId")), + obj -> JsonUtils.buildJsonObject() // + .addProperty("appId", obj.appId()) // + .build()); } - public Request(String appId) { - super(METHOD); - this.appId = appId; - } - - @Override - public JsonObject getParams() { - return JsonUtils.buildJsonObject() // - .addProperty("appId", this.appId) // - .build(); - } } - public static class Response extends JsonrpcResponseSuccess { - - private final AppAssistant appAssistant; - - public Response(UUID id, AppAssistant appAssistant) { - super(id); - this.appAssistant = appAssistant; + public record Response(// + AppAssistant appAssistant // + ) { + /** + * Returns a {@link JsonSerializer} for a {@link GetAppAssistant.Response}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonSerializer(GetAppAssistant.Response.class, // + json -> new GetAppAssistant.Response(json.getAsObject(AppAssistant.serializer())), // + obj -> AppAssistant.serializer().serialize(obj.appAssistant())); } - @Override - public JsonObject getResult() { - return this.appAssistant.toJsonObject(); - } } } diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/GetAppDescriptor.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/GetAppDescriptor.java index 4c5a513bb71..97922ed1d28 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/GetAppDescriptor.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/GetAppDescriptor.java @@ -1,15 +1,15 @@ package io.openems.edge.core.appmanager.jsonrpc; -import java.util.UUID; +import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.jsonObjectSerializer; +import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.jsonSerializer; -import com.google.gson.JsonObject; - -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.jsonrpc.base.JsonrpcRequest; -import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; +import io.openems.common.jsonrpc.serialization.JsonSerializer; import io.openems.common.utils.JsonUtils; +import io.openems.edge.common.jsonapi.EndpointRequestType; import io.openems.edge.core.appmanager.AppDescriptor; import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.jsonrpc.GetAppDescriptor.Request; +import io.openems.edge.core.appmanager.jsonrpc.GetAppDescriptor.Response; /** * Gets the App-Descriptor for a {@link OpenemsApp}. @@ -36,63 +36,61 @@ * "jsonrpc": "2.0", * "id": "UUID", * "result": { - * ... {@link AppDescriptor#toJsonObject()} + * ... {@link AppDescriptor#serializer()} * } * } * */ -public class GetAppDescriptor { +public class GetAppDescriptor implements EndpointRequestType { + + @Override + public String getMethod() { + return "getAppDescriptor"; + } - public static final String METHOD = "getAppDescriptor"; + @Override + public JsonSerializer getRequestSerializer() { + return Request.serializer(); + } - public static class Request extends JsonrpcRequest { + @Override + public JsonSerializer getResponseSerializer() { + return Response.serializer(); + } + public record Request(// + String appId // + ) { /** - * Parses a generic {@link JsonrpcRequest} to a {@link GetAppAssistantRequest}. - * - * @param r the {@link JsonrpcRequest} - * @return the {@link GetAppAssistantRequest} - * @throws OpenemsNamedException on error + * Returns a {@link JsonSerializer} for a {@link GetAppDescriptor.Request}. + * + * @return the created {@link JsonSerializer} */ - public static Request from(JsonrpcRequest r) throws OpenemsNamedException { - var p = r.getParams(); - var appId = JsonUtils.getAsString(p, "appId"); - return new Request(r, appId); - } - - public final String appId; - - public Request(JsonrpcRequest request, String appId) { - super(request, METHOD); - this.appId = appId; + public static JsonSerializer serializer() { + return jsonObjectSerializer(GetAppDescriptor.Request.class, // + json -> new GetAppDescriptor.Request(// + json.getString("appId")), // + obj -> JsonUtils.buildJsonObject() // + .addProperty("appId", obj.appId()) // + .build()); } - public Request(String appId) { - super(METHOD); - this.appId = appId; - } - - @Override - public JsonObject getParams() { - return JsonUtils.buildJsonObject() // - .addProperty("appId", this.appId) // - .build(); - } } - public static class Response extends JsonrpcResponseSuccess { - - private final AppDescriptor appDescriptor; - - public Response(UUID id, AppDescriptor appDescriptor) { - super(id); - this.appDescriptor = appDescriptor; + public record Response(// + AppDescriptor appDescriptor // + ) { + /** + * Returns a {@link JsonSerializer} for a {@link GetAppDescriptor.Response}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonSerializer(GetAppDescriptor.Response.class, // + json -> new GetAppDescriptor.Response(json.getAsObject(AppDescriptor.serializer())), // + obj -> AppDescriptor.serializer().serialize(obj.appDescriptor())); } - @Override - public JsonObject getResult() { - return this.appDescriptor.toJsonObject(); - } } } diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/GetAppInstances.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/GetAppInstances.java index dea459eb9e9..1163db1bab0 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/GetAppInstances.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/GetAppInstances.java @@ -1,17 +1,17 @@ package io.openems.edge.core.appmanager.jsonrpc; -import java.util.UUID; -import java.util.stream.Stream; +import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.jsonObjectSerializer; +import static io.openems.common.utils.JsonUtils.toJsonArray; -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; +import java.util.List; -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.jsonrpc.base.JsonrpcRequest; -import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; +import io.openems.common.jsonrpc.serialization.JsonSerializer; import io.openems.common.utils.JsonUtils; +import io.openems.edge.common.jsonapi.EndpointRequestType; import io.openems.edge.core.appmanager.OpenemsApp; import io.openems.edge.core.appmanager.OpenemsAppInstance; +import io.openems.edge.core.appmanager.jsonrpc.GetAppInstances.Request; +import io.openems.edge.core.appmanager.jsonrpc.GetAppInstances.Response; /** * Gets the active instances of an {@link OpenemsApp}. @@ -43,61 +43,59 @@ * } * */ -public class GetAppInstances { +public class GetAppInstances implements EndpointRequestType { - public static final String METHOD = "getAppInstances"; + @Override + public String getMethod() { + return "getAppInstances"; + } + + @Override + public JsonSerializer getRequestSerializer() { + return Request.serializer(); + } - public static class Request extends JsonrpcRequest { + @Override + public JsonSerializer getResponseSerializer() { + return Response.serializer(); + } + public record Request(// + String appId // + ) { /** - * Parses a generic {@link JsonrpcRequest} to a {@link GetAppInstances}. - * - * @param r the {@link JsonrpcRequest} - * @return the {@link GetAppInstances} - * @throws OpenemsNamedException on error + * Returns a {@link JsonSerializer} for a {@link GetAppInstances.Request}. + * + * @return the created {@link JsonSerializer} */ - public static Request from(JsonrpcRequest r) throws OpenemsNamedException { - var p = r.getParams(); - var appId = JsonUtils.getAsString(p, "appId"); - return new Request(r, appId); - } - - public final String appId; - - private Request(JsonrpcRequest request, String appId) { - super(request, METHOD); - this.appId = appId; - } - - public Request(String appId) { - super(METHOD); - this.appId = appId; + public static JsonSerializer serializer() { + return jsonObjectSerializer(GetAppInstances.Request.class, // + json -> new GetAppInstances.Request(// + json.getString("appId")), // + obj -> JsonUtils.buildJsonObject() // + .addProperty("appId", obj.appId()) // + .build()); } - @Override - public JsonObject getParams() { - return JsonUtils.buildJsonObject() // - .addProperty("appId", this.appId) // - .build(); - } } - public static class Response extends JsonrpcResponseSuccess { - - private final JsonArray instances; - - public Response(UUID id, Stream instances) { - super(id); + public record Response(// + List instances // + ) { - this.instances = instances.map(OpenemsAppInstance::toJsonObject) // - .collect(JsonUtils.toJsonArray()); - } - - @Override - public JsonObject getResult() { - return JsonUtils.buildJsonObject() // - .add("instances", this.instances) // - .build(); // + /** + * Returns a {@link JsonSerializer} for a {@link GetAppInstances.Response}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(GetAppInstances.Response.class, // + json -> new GetAppInstances.Response(json.getList("instances", OpenemsAppInstance.serializer())), // + obj -> JsonUtils.buildJsonObject() // + .add("instances", obj.instances().stream() // + .map(OpenemsAppInstance.serializer()::serialize) // + .collect(toJsonArray())) // + .build()); } } diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/GetApps.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/GetApps.java index e5ee12319e4..b25eacfc46f 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/GetApps.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/GetApps.java @@ -1,21 +1,23 @@ package io.openems.edge.core.appmanager.jsonrpc; +import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.emptyObjectSerializer; +import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.jsonObjectSerializer; + import java.util.List; import java.util.Objects; -import java.util.UUID; import com.google.gson.JsonArray; -import com.google.gson.JsonObject; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.exceptions.OpenemsException; -import io.openems.common.jsonrpc.base.JsonrpcRequest; -import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; +import io.openems.common.jsonrpc.serialization.JsonSerializer; import io.openems.common.session.Language; import io.openems.common.session.Role; import io.openems.common.utils.JsonUtils; +import io.openems.edge.common.jsonapi.EndpointRequestType; import io.openems.edge.core.appmanager.OpenemsApp; import io.openems.edge.core.appmanager.OpenemsAppInstance; +import io.openems.edge.core.appmanager.jsonrpc.GetApps.Request; +import io.openems.edge.core.appmanager.jsonrpc.GetApps.Response; import io.openems.edge.core.appmanager.validator.Validator; /** @@ -61,39 +63,70 @@ * } * */ -public class GetApps { +public class GetApps implements EndpointRequestType { + + @Override + public String getMethod() { + return "getApps"; + } - public static final String METHOD = "getApps"; + @Override + public JsonSerializer getRequestSerializer() { + return Request.serializer(); + } + + @Override + public JsonSerializer getResponseSerializer() { + return Response.serializer(); + } - public static class Request extends JsonrpcRequest { + public record Request() { /** - * Parses a generic {@link JsonrpcRequest} to a {@link Request}. - * - * @param r the {@link JsonrpcRequest} - * @return the {@link GetAppsRequest} - * @throws OpenemsNamedException on error + * Returns a {@link JsonSerializer} for a {@link GetApps.Response}. + * + * @return the created {@link JsonSerializer} */ - public static Request from(JsonrpcRequest r) throws OpenemsException { - return new Request(r); + public static JsonSerializer serializer() { + return emptyObjectSerializer(Request::new); } - public Request() { - super(METHOD); - } + } - private Request(JsonrpcRequest request) { - super(request, METHOD); - } + public record Response(// + JsonArray apps // + ) { - @Override - public JsonObject getParams() { - return new JsonObject(); + /** + * Creates a new Response. + * + * @param availableApps all available app + * @param instantiatedApps all {@link OpenemsAppInstance} + * @param userRole the current {@link Role} of the user + * @param language the current {@link Language} of the user + * @param validator the {@link Validator} to validate the app + * @return the created Response + */ + public static Response newInstance(List availableApps, List instantiatedApps, + Role userRole, Language language, Validator validator) { + return new Response(createAppsArray(availableApps, instantiatedApps, userRole, language, validator)); } - } - - public static class Response extends JsonrpcResponseSuccess { + /** + * Returns a {@link JsonSerializer} for a {@link GetApps.Response}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(Response.class, json -> { + // TODO serialize whole apps not only JsonArray + return new Response(json.getJsonArray("apps")); + }, obj -> { + return JsonUtils.buildJsonObject() // + .add("apps", obj.apps()) // + .build(); + }); + } private static JsonArray createAppsArray(List availableApps, List instantiatedApps, Role userRole, Language language, Validator validator) { @@ -118,20 +151,6 @@ private static JsonArray createAppsArray(List availableApps, .collect(JsonUtils.toJsonArray()); } - private final JsonArray apps; - - public Response(UUID id, List availableApps, List instantiatedApps, - Role userRole, Language language, Validator validator) { - super(id); - this.apps = createAppsArray(availableApps, instantiatedApps, userRole, language, validator); - } - - @Override - public JsonObject getResult() { - return JsonUtils.buildJsonObject() // - .add("apps", this.apps) // - .build(); - } } } diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/UpdateAppInstance.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/UpdateAppInstance.java index a297b0c6b52..50facf512a4 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/UpdateAppInstance.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/UpdateAppInstance.java @@ -1,17 +1,21 @@ package io.openems.edge.core.appmanager.jsonrpc; +import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.jsonObjectSerializer; +import static io.openems.common.utils.JsonUtils.toJsonArray; + import java.util.List; import java.util.UUID; -import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.jsonrpc.base.JsonrpcRequest; -import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; +import io.openems.common.jsonrpc.serialization.JsonElementPath; +import io.openems.common.jsonrpc.serialization.JsonSerializer; import io.openems.common.utils.JsonUtils; +import io.openems.edge.common.jsonapi.EndpointRequestType; import io.openems.edge.core.appmanager.OpenemsAppInstance; +import io.openems.edge.core.appmanager.jsonrpc.UpdateAppInstance.Request; +import io.openems.edge.core.appmanager.jsonrpc.UpdateAppInstance.Response; /** * Updates an {@link OpenemsAppInstance}.. @@ -45,74 +49,72 @@ * } * */ -public class UpdateAppInstance { - - public static final String METHOD = "updateAppInstance"; +public class UpdateAppInstance implements EndpointRequestType { - public static class Request extends JsonrpcRequest { + @Override + public String getMethod() { + return "updateAppInstance"; + } - /** - * Parses a generic {@link JsonrpcRequest} to a {@link UpdateAppInstance}. - * - * @param r the {@link JsonrpcRequest} - * @return the {@link UpdateAppInstance} - * @throws OpenemsNamedException on error - */ - public static Request from(JsonrpcRequest r) throws OpenemsNamedException { - var p = r.getParams(); - var instanceId = JsonUtils.getAsUUID(p, "instanceId"); - var alias = JsonUtils.getAsString(p, "alias"); - var properties = JsonUtils.getAsJsonObject(p, "properties"); - return new Request(r, instanceId, alias, properties); - } + @Override + public JsonSerializer getRequestSerializer() { + return Request.serializer(); + } - public final UUID instanceId; - public final String alias; - public final JsonObject properties; + @Override + public JsonSerializer getResponseSerializer() { + return Response.serializer(); + } - private Request(JsonrpcRequest request, UUID instanceId, String alias, JsonObject properties) { - super(request, METHOD); - this.instanceId = instanceId; - this.alias = alias; - this.properties = properties; - } + public record Request(// + UUID instanceId, // + String alias, // + JsonObject properties // + ) { - public Request(UUID instanceId, String alias, JsonObject properties) { - super(METHOD); - this.instanceId = instanceId; - this.alias = alias; - this.properties = properties; + /** + * Returns a {@link JsonSerializer} for a {@link UpdateAppInstance.Request}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(UpdateAppInstance.Request.class, // + json -> new UpdateAppInstance.Request(// + json.getStringPath("instanceId").getAsUuid(), // + json.getString("alias"), // + json.getJsonObject("properties")), // + obj -> JsonUtils.buildJsonObject() // + .addProperty("instanceId", obj.instanceId().toString()) // + .addProperty("alias", obj.alias()) // + .add("properties", obj.properties()) // + .build()); } - @Override - public JsonObject getParams() { - return JsonUtils.buildJsonObject() // - .addProperty("instanceId", this.instanceId.toString()) // - .addProperty("alias", this.alias) // - .add("properties", this.properties) // - .build(); - } } - public static class Response extends JsonrpcResponseSuccess { + public record Response(// + OpenemsAppInstance instance, // + List warnings // + ) { - public final OpenemsAppInstance instance; - public final JsonArray warnings; - - public Response(UUID id, OpenemsAppInstance instance, List warnings) { - super(id); - this.instance = instance; - this.warnings = warnings == null ? new JsonArray() - : warnings.stream().map(JsonPrimitive::new).collect(JsonUtils.toJsonArray()); + /** + * Returns a {@link JsonSerializer} for a {@link UpdateAppInstance.Response}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(UpdateAppInstance.Response.class, // + json -> new UpdateAppInstance.Response(// + json.getElement("instance", OpenemsAppInstance.serializer()), // + json.getList("warnings", JsonElementPath::getAsString)), // + obj -> JsonUtils.buildJsonObject() // + .add("instance", OpenemsAppInstance.serializer().serialize(obj.instance())) // + .add("warnings", obj.warnings().stream() // + .map(JsonPrimitive::new) // + .collect(toJsonArray())) // + .build()); } - @Override - public JsonObject getResult() { - return JsonUtils.buildJsonObject() // - .add("instance", this.instance.toJsonObject()) // - .add("warnings", this.warnings) // - .build(); - } } } diff --git a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java index 79245de3195..1df00beb666 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java @@ -9,7 +9,6 @@ import java.util.Dictionary; import java.util.Hashtable; import java.util.List; -import java.util.concurrent.CompletableFuture; import org.osgi.framework.BundleContext; import org.osgi.framework.InvalidSyntaxException; @@ -37,8 +36,6 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; import io.openems.common.jsonrpc.base.GenericJsonrpcResponseSuccess; -import io.openems.common.jsonrpc.base.JsonrpcRequest; -import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; import io.openems.common.jsonrpc.request.CreateComponentConfigRequest; import io.openems.common.jsonrpc.request.DeleteComponentConfigRequest; import io.openems.common.jsonrpc.request.GetEdgeConfigRequest; @@ -52,7 +49,10 @@ import io.openems.edge.common.component.ClockProvider; import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.ComponentJsonApi; +import io.openems.edge.common.jsonapi.EdgeGuards; +import io.openems.edge.common.jsonapi.EdgeKeys; +import io.openems.edge.common.jsonapi.JsonApiBuilder; import io.openems.edge.common.user.User; import io.openems.edge.core.componentmanager.jsonrpc.ChannelExportXlsxRequest; import io.openems.edge.core.componentmanager.jsonrpc.ChannelExportXlsxResponse; @@ -65,7 +65,7 @@ "enabled=true" // }) public class ComponentManagerImpl extends AbstractOpenemsComponent - implements ComponentManager, OpenemsComponent, JsonApi, ConfigurationListener { + implements ComponentManager, OpenemsComponent, ConfigurationListener, ComponentJsonApi { private final List workers = new ArrayList<>(); private final EdgeConfigWorker edgeConfigWorker; @@ -215,6 +215,9 @@ private List getComponentsViaService(Class clazz, String filter) { // filter invalid e.printStackTrace(); return Collections.emptyList(); + } catch (RuntimeException e) { + e.printStackTrace(); + return Collections.emptyList(); } } @@ -282,30 +285,64 @@ protected void logError(Logger log, String message) { } @Override - public CompletableFuture handleJsonrpcRequest(User user, JsonrpcRequest request) - throws OpenemsNamedException { - user.assertRoleIsAtLeast("handleJsonrpcRequest", Role.GUEST); - - switch (request.getMethod()) { - - case GetEdgeConfigRequest.METHOD: - return this.handleGetEdgeConfigRequest(user, GetEdgeConfigRequest.from(request)); - - case CreateComponentConfigRequest.METHOD: - return this.handleCreateComponentConfigRequest(user, CreateComponentConfigRequest.from(request)); - - case UpdateComponentConfigRequest.METHOD: - return this.handleUpdateComponentConfigRequest(user, UpdateComponentConfigRequest.from(request)); - - case DeleteComponentConfigRequest.METHOD: - return this.handleDeleteComponentConfigRequest(user, DeleteComponentConfigRequest.from(request)); - - case ChannelExportXlsxRequest.METHOD: - return this.handleChannelExportXlsxRequest(user, ChannelExportXlsxRequest.from(request)); - - default: - throw OpenemsError.JSONRPC_UNHANDLED_METHOD.exception(request.getMethod()); - } + public void buildJsonApiRoutes(JsonApiBuilder builder) { + builder.handleRequest(GetEdgeConfigRequest.METHOD, endpoint -> { + endpoint.setDescription(""" + Handles a GetEdgeConfigRequest. + """) // + .setGuards(EdgeGuards.roleIsAtleast(Role.GUEST)); + }, t -> { + return this.handleGetEdgeConfigRequest(t.get(EdgeKeys.USER_KEY), // + GetEdgeConfigRequest.from(t.getRequest())); + }); + + builder.handleRequest(CreateComponentConfigRequest.METHOD, endpoint -> { + endpoint.setDescription(""" + Handles a CreateComponentConfigRequest. + """) // + .setGuards(EdgeGuards.roleIsAtleastFromBackend(Role.INSTALLER), // + EdgeGuards.roleIsAtleastNotFromBackend(Role.ADMIN)); + }, t -> { + this.handleCreateComponentConfigRequest(t.get(EdgeKeys.USER_KEY), // + CreateComponentConfigRequest.from(t.getRequest())); + + return new GenericJsonrpcResponseSuccess(t.getRequest().getId()); + }); + + builder.handleRequest(UpdateComponentConfigRequest.METHOD, endpoint -> { + endpoint.setDescription(""" + Handles a UpdateComponentConfigRequest. + """) // + .setGuards(EdgeGuards.roleIsAtleast(Role.OWNER)); + }, t -> { + this.handleUpdateComponentConfigRequest(t.get(EdgeKeys.USER_KEY), // + UpdateComponentConfigRequest.from(t.getRequest())); + + return new GenericJsonrpcResponseSuccess(t.getRequest().getId()); + }); + + builder.handleRequest(DeleteComponentConfigRequest.METHOD, endpoint -> { + endpoint.setDescription(""" + Handles a DeleteComponentConfigRequest. + """) // + .setGuards(EdgeGuards.roleIsAtleastFromBackend(Role.INSTALLER), // + EdgeGuards.roleIsAtleastNotFromBackend(Role.ADMIN)); + }, t -> { + this.handleDeleteComponentConfigRequest(t.get(EdgeKeys.USER_KEY), // + DeleteComponentConfigRequest.from(t.getRequest())); + + return new GenericJsonrpcResponseSuccess(t.getRequest().getId()); + }); + + builder.handleRequest(ChannelExportXlsxRequest.METHOD, endpoint -> { + endpoint.setDescription(""" + Handles a ChannelExportXlsxRequest. + """) // + .setGuards(EdgeGuards.roleIsAtleast(Role.ADMIN)); + }, t -> { + return this.handleChannelExportXlsxRequest(t.get(EdgeKeys.USER_KEY), // + ChannelExportXlsxRequest.from(t.getRequest())); + }); } /** @@ -316,23 +353,15 @@ public CompletableFuture handleJsonrpcRequest(User user, * @return the Future JSON-RPC Response * @throws OpenemsNamedException on error */ - private CompletableFuture handleGetEdgeConfigRequest(User user, - GetEdgeConfigRequest request) throws OpenemsNamedException { + private GetEdgeConfigResponse handleGetEdgeConfigRequest(User user, GetEdgeConfigRequest request) + throws OpenemsNamedException { var config = this.getEdgeConfig(); - var response = new GetEdgeConfigResponse(request.getId(), config); - return CompletableFuture.completedFuture(response); + return new GetEdgeConfigResponse(request.getId(), config); } - /** - * Handles a {@link CreateComponentConfigRequest}. - * - * @param user the {@link User} - * @param request the {@link CreateComponentConfigRequest} - * @return the Future JSON-RPC Response - * @throws OpenemsNamedException on error - */ - public CompletableFuture handleCreateComponentConfigRequest(User user, - CreateComponentConfigRequest request) throws OpenemsNamedException { + @Override + public void handleCreateComponentConfigRequest(User user, CreateComponentConfigRequest request) + throws OpenemsNamedException { // Get Component-ID from Request String componentId = null; for (Property property : request.getProperties()) { @@ -395,20 +424,11 @@ public CompletableFuture handleCreateComponentConfigRequ e.printStackTrace(); throw OpenemsError.EDGE_UNABLE_TO_CREATE_CONFIG.exception(request.getFactoryPid(), e.getMessage()); } - - return CompletableFuture.completedFuture(new GenericJsonrpcResponseSuccess(request.getId())); } - /** - * Handles a {@link UpdateComponentConfigRequest}. - * - * @param user the {@link User} - * @param request the {@link UpdateComponentConfigRequest} - * @return the Future JSON-RPC Response - * @throws OpenemsNamedException on error - */ - public CompletableFuture handleUpdateComponentConfigRequest(User user, - UpdateComponentConfigRequest request) throws OpenemsNamedException { + @Override + public void handleUpdateComponentConfigRequest(User user, UpdateComponentConfigRequest request) + throws OpenemsNamedException { var config = this.getExistingConfigForId(request.getComponentId()); // Create map with changed configuration attributes @@ -451,20 +471,11 @@ public CompletableFuture handleUpdateComponentConfigRequ e.printStackTrace(); throw OpenemsError.EDGE_UNABLE_TO_APPLY_CONFIG.exception(request.getComponentId(), e.getMessage()); } - - return CompletableFuture.completedFuture(new GenericJsonrpcResponseSuccess(request.getId())); } - /** - * Handles a {@link DeleteComponentConfigRequest}. - * - * @param user the {@link User} - * @param request the {@link DeleteComponentConfigRequest} - * @return the Future JSON-RPC Response - * @throws OpenemsNamedException on error - */ - public CompletableFuture handleDeleteComponentConfigRequest(User user, - DeleteComponentConfigRequest request) throws OpenemsNamedException { + @Override + public void handleDeleteComponentConfigRequest(User user, DeleteComponentConfigRequest request) + throws OpenemsNamedException { var config = this.getExistingConfigForId(request.getComponentId()); try { @@ -473,8 +484,6 @@ public CompletableFuture handleDeleteComponentConfigRequ e.printStackTrace(); throw OpenemsError.EDGE_UNABLE_TO_DELETE_CONFIG.exception(request.getComponentId(), e.getMessage()); } - - return CompletableFuture.completedFuture(new GenericJsonrpcResponseSuccess(request.getId())); } /** @@ -485,14 +494,13 @@ public CompletableFuture handleDeleteComponentConfigRequ * @return the Future JSON-RPC Response * @throws OpenemsNamedException on error */ - protected CompletableFuture handleChannelExportXlsxRequest(User user, - ChannelExportXlsxRequest request) throws OpenemsNamedException { - user.assertRoleIsAtLeast("ChannelExportXlsxRequest", Role.ADMIN); + protected ChannelExportXlsxResponse handleChannelExportXlsxRequest(User user, ChannelExportXlsxRequest request) + throws OpenemsNamedException { var component = this.getComponent(request.getComponentId()); if (component == null) { throw OpenemsError.EDGE_NO_COMPONENT_WITH_ID.exception(request.getComponentId()); } - return CompletableFuture.completedFuture(new ChannelExportXlsxResponse(request.getId(), component)); + return new ChannelExportXlsxResponse(request.getId(), component); } /** diff --git a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/DefaultConfigurationWorker.java b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/DefaultConfigurationWorker.java index 3131bc5fc76..c884719aea5 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/DefaultConfigurationWorker.java +++ b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/DefaultConfigurationWorker.java @@ -6,9 +6,6 @@ import java.util.Hashtable; import java.util.List; import java.util.Optional; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; @@ -180,11 +177,9 @@ protected void createConfiguration(AtomicBoolean defaultConfigurationFailed, Str "Creating Component configuration [" + factoryPid + "]: " + properties.stream() // .map(p -> p.getName() + ":" + p.getValue().toString()) // .collect(Collectors.joining(", "))); - var response = this.parent.handleCreateComponentConfigRequest(null /* no user */, + this.parent.handleCreateComponentConfigRequest(null /* no user */, new CreateComponentConfigRequest(factoryPid, properties)); - response.get(60, TimeUnit.SECONDS); - - } catch (OpenemsNamedException | InterruptedException | ExecutionException | TimeoutException e) { + } catch (OpenemsNamedException e) { this.parent.logError(this.log, "Unable to create Component configuration for Factory [" + factoryPid + "]: " + e.getMessage()); e.printStackTrace(); @@ -208,11 +203,9 @@ protected void updateConfiguration(AtomicBoolean defaultConfigurationFailed, Str .map(p -> p.getName() + ":" + p.getValue().toString()) // .collect(Collectors.joining(", "))); - var response = this.parent.handleUpdateComponentConfigRequest(null /* no user */, + this.parent.handleUpdateComponentConfigRequest(null /* no user */, new UpdateComponentConfigRequest(componentId, properties)); - response.get(60, TimeUnit.SECONDS); - - } catch (OpenemsNamedException | InterruptedException | ExecutionException | TimeoutException e) { + } catch (OpenemsNamedException e) { this.parent.logError(this.log, "Unable to update Component configuration for Component [" + componentId + "]: " + e.getMessage()); e.printStackTrace(); @@ -231,11 +224,9 @@ protected void deleteConfiguration(AtomicBoolean defaultConfigurationFailed, Str try { this.parent.logInfo(this.log, "Deleting Component [" + componentId + "]"); - var response = this.parent.handleDeleteComponentConfigRequest(null /* no user */, + this.parent.handleDeleteComponentConfigRequest(null /* no user */, new DeleteComponentConfigRequest(componentId)); - response.get(60, TimeUnit.SECONDS); - - } catch (OpenemsNamedException | InterruptedException | ExecutionException | TimeoutException e) { + } catch (OpenemsNamedException e) { this.parent.logError(this.log, "Unable to delete Component [" + componentId + "]: " + e.getMessage()); e.printStackTrace(); defaultConfigurationFailed.set(true); diff --git a/io.openems.edge.core/src/io/openems/edge/core/host/HostImpl.java b/io.openems.edge.core/src/io/openems/edge/core/host/HostImpl.java index fa89606796f..bc18b13fab4 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/host/HostImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/host/HostImpl.java @@ -17,18 +17,18 @@ import org.osgi.service.metatype.annotations.Designate; import org.slf4j.Logger; -import io.openems.common.exceptions.OpenemsError; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; import io.openems.common.jsonrpc.base.GenericJsonrpcResponseSuccess; -import io.openems.common.jsonrpc.base.JsonrpcRequest; import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; import io.openems.common.oem.OpenemsEdgeOem; import io.openems.common.session.Role; import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.host.Host; -import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.ComponentJsonApi; +import io.openems.edge.common.jsonapi.EdgeKeys; +import io.openems.edge.common.jsonapi.JsonApiBuilder; import io.openems.edge.common.user.User; import io.openems.edge.core.host.jsonrpc.ExecuteSystemCommandRequest; import io.openems.edge.core.host.jsonrpc.ExecuteSystemRestartRequest; @@ -48,7 +48,7 @@ property = { // "enabled=true" // }) -public class HostImpl extends AbstractOpenemsComponent implements Host, OpenemsComponent, JsonApi { +public class HostImpl extends AbstractOpenemsComponent implements Host, OpenemsComponent, ComponentJsonApi { protected final OperatingSystem operatingSystem; @@ -140,32 +140,36 @@ protected void deactivate() { } @Override - public CompletableFuture handleJsonrpcRequest(User user, JsonrpcRequest request) - throws OpenemsNamedException { - user.assertRoleIsAtLeast("handleJsonrpcRequest", Role.OWNER); - switch (request.getMethod()) { - - case GetNetworkConfigRequest.METHOD: - return this.handleGetNetworkConfigRequest(user, GetNetworkConfigRequest.from(request)); - - case SetNetworkConfigRequest.METHOD: - return this.handleSetNetworkConfigRequest(user, SetNetworkConfigRequest.from(request)); - - case GetSystemUpdateStateRequest.METHOD: - return this.handleGetSystemUpdateStateRequest(user, GetSystemUpdateStateRequest.from(request)); - - case ExecuteSystemUpdateRequest.METHOD: - return this.handleExecuteSystemUpdateRequest(user, ExecuteSystemUpdateRequest.from(request)); - - case ExecuteSystemCommandRequest.METHOD: - return this.handleExecuteCommandRequest(user, ExecuteSystemCommandRequest.from(request)); - - case ExecuteSystemRestartRequest.METHOD: - return this.handleExecuteSystemRestartRequest(user, ExecuteSystemRestartRequest.from(request)); - - default: - throw OpenemsError.JSONRPC_UNHANDLED_METHOD.exception(request.getMethod()); - } + public void buildJsonApiRoutes(JsonApiBuilder builder) { + builder.handleRequest(GetNetworkConfigRequest.METHOD, call -> { + return this.handleGetNetworkConfigRequest(call.get(EdgeKeys.USER_KEY), + GetNetworkConfigRequest.from(call.getRequest())); + }); + + builder.handleRequest(SetNetworkConfigRequest.METHOD, call -> { + return this.handleSetNetworkConfigRequest(call.get(EdgeKeys.USER_KEY), + SetNetworkConfigRequest.from(call.getRequest())); + }); + + builder.handleRequest(GetSystemUpdateStateRequest.METHOD, call -> { + return this.handleGetSystemUpdateStateRequest(call.get(EdgeKeys.USER_KEY), + GetSystemUpdateStateRequest.from(call.getRequest())).get(); + }); + + builder.handleRequest(ExecuteSystemUpdateRequest.METHOD, call -> { + return this.handleExecuteSystemUpdateRequest(call.get(EdgeKeys.USER_KEY), + ExecuteSystemUpdateRequest.from(call.getRequest())).get(); + }); + + builder.handleRequest(ExecuteSystemCommandRequest.METHOD, call -> { + return this.handleExecuteCommandRequest(call.get(EdgeKeys.USER_KEY), + ExecuteSystemCommandRequest.from(call.getRequest())).get(); + }); + + builder.handleRequest(ExecuteSystemRestartRequest.METHOD, call -> { + return this.handleExecuteSystemRestartRequest(call.get(EdgeKeys.USER_KEY), + ExecuteSystemRestartRequest.from(call.getRequest())).get(); + }); } /** @@ -176,12 +180,11 @@ public CompletableFuture handleJsonrpcRequest( * @return the Future JSON-RPC Response * @throws OpenemsNamedException on error */ - private CompletableFuture handleGetNetworkConfigRequest(User user, - GetNetworkConfigRequest request) throws OpenemsNamedException { + private GetNetworkConfigResponse handleGetNetworkConfigRequest(User user, GetNetworkConfigRequest request) + throws OpenemsNamedException { user.assertRoleIsAtLeast("handleGetNetworkConfigRequest", Role.OWNER); var config = this.operatingSystem.getNetworkConfiguration(); - var response = new GetNetworkConfigResponse(request.getId(), config); - return CompletableFuture.completedFuture(response); + return new GetNetworkConfigResponse(request.getId(), config); } /** @@ -192,8 +195,8 @@ private CompletableFuture handleGetNetworkConfigRequest( * @return the Future JSON-RPC Response * @throws OpenemsNamedException on error */ - private CompletableFuture handleSetNetworkConfigRequest(User user, - SetNetworkConfigRequest request) throws OpenemsNamedException { + public GenericJsonrpcResponseSuccess handleSetNetworkConfigRequest(User user, SetNetworkConfigRequest request) + throws OpenemsNamedException { user.assertRoleIsAtLeast("handleSetNetworkConfigRequest", Role.OWNER); var oldNetworkConfiguration = this.operatingSystem.getNetworkConfiguration(); this.operatingSystem.handleSetNetworkConfigRequest(user, oldNetworkConfiguration, request); @@ -201,7 +204,7 @@ private CompletableFuture handleSetNetworkConfigRequest( // Notify NetworkConfigurationWorker about the change this.networkConfigurationWorker.triggerNextRun(); - return CompletableFuture.completedFuture(new GenericJsonrpcResponseSuccess(request.getId())); + return new GenericJsonrpcResponseSuccess(request.getId()); } /** diff --git a/io.openems.edge.core/test/io/openems/edge/app/evcs/TestEvcsCluster.java b/io.openems.edge.core/test/io/openems/edge/app/evcs/TestEvcsCluster.java index c5d1dbd4297..06378d223fc 100644 --- a/io.openems.edge.core/test/io/openems/edge/app/evcs/TestEvcsCluster.java +++ b/io.openems.edge.core/test/io/openems/edge/app/evcs/TestEvcsCluster.java @@ -115,26 +115,26 @@ public void testReinstallationWhenMoreOrEqualOfTwoEvcsExist() throws Exception { assertEquals(2, this.appManagerTestBundle.sut.getInstantiatedApps().size()); - this.appManagerTestBundle.componentManger.handleJsonrpcRequest(DUMMY_ADMIN, + this.appManagerTestBundle.componentManger.handleCreateComponentConfigRequest(DUMMY_ADMIN, new CreateComponentConfigRequest("Evcs.Keba.KeContact", Lists.newArrayList(// new UpdateComponentConfigRequest.Property("id", "evcs0"), // new UpdateComponentConfigRequest.Property("ip", "1.1.1.1") // - ))).get(); - this.appManagerTestBundle.componentManger.handleJsonrpcRequest(DUMMY_ADMIN, + ))); + this.appManagerTestBundle.componentManger.handleCreateComponentConfigRequest(DUMMY_ADMIN, new CreateComponentConfigRequest("Controller.Evcs", Lists.newArrayList(// new UpdateComponentConfigRequest.Property("id", "ctrlEvcs0"), // new UpdateComponentConfigRequest.Property("evcs.id", "evcs0") // - ))).get(); - this.appManagerTestBundle.componentManger.handleJsonrpcRequest(DUMMY_ADMIN, + ))); + this.appManagerTestBundle.componentManger.handleCreateComponentConfigRequest(DUMMY_ADMIN, new CreateComponentConfigRequest("Evcs.Keba.KeContact", Lists.newArrayList(// new UpdateComponentConfigRequest.Property("id", "evcs1"), // new UpdateComponentConfigRequest.Property("ip", "1.1.1.2") // - ))).get(); - this.appManagerTestBundle.componentManger.handleJsonrpcRequest(DUMMY_ADMIN, + ))); + this.appManagerTestBundle.componentManger.handleCreateComponentConfigRequest(DUMMY_ADMIN, new CreateComponentConfigRequest("Controller.Evcs", Lists.newArrayList(// new UpdateComponentConfigRequest.Property("id", "ctrlEvcs1"), // new UpdateComponentConfigRequest.Property("evcs.id", "evcs1") // - ))).get(); + ))); ResolveDependencies.resolveDependencies(DUMMY_ADMIN, this.appManagerTestBundle.sut, this.appManagerTestBundle.appManagerUtil); @@ -167,7 +167,7 @@ public void testClusterWasAlreadyExisting() throws Exception { this.installKeba("1.1.1.1"); final var clusterId = "evcsCluster0"; - this.appManagerTestBundle.componentManger.handleJsonrpcRequest(DUMMY_ADMIN, + this.appManagerTestBundle.componentManger.handleCreateComponentConfigRequest(DUMMY_ADMIN, new CreateComponentConfigRequest("Evcs.Cluster.PeakShaving", Lists.newArrayList(// new UpdateComponentConfigRequest.Property("id", clusterId), // new UpdateComponentConfigRequest.Property("enabled", false), // @@ -175,7 +175,7 @@ public void testClusterWasAlreadyExisting() throws Exception { .add("evcs0") // .build()), // new UpdateComponentConfigRequest.Property("hardwarePowerLimitPerPhase", 1234) // - ))).get(); + ))); this.assertIdsGotAdded("evcs0"); @@ -198,13 +198,12 @@ public void testModifyDoubleToSingle() throws Exception { this.appManagerTestBundle.assertInstalledApps(3); this.appManagerTestBundle.sut.handleUpdateAppInstanceRequest(DUMMY_ADMIN, - new UpdateAppInstance.Request(response.instance.instanceId, "alias", JsonUtils.buildJsonObject() // + new UpdateAppInstance.Request(response.instance().instanceId, "alias", JsonUtils.buildJsonObject() // .addProperty(HardyBarthEvcs.Property.NUMBER_OF_CHARGING_STATIONS.name(), 1) // .addProperty(HardyBarthEvcs.SubPropertyFirstChargepoint.IP.name(), "2.1.1.1") // - .build())) - .get(); + .build())); - final var evcsId = response.instance.properties.get(HardyBarthEvcs.Property.EVCS_ID.name()).getAsString(); + final var evcsId = response.instance().properties.get(HardyBarthEvcs.Property.EVCS_ID.name()).getAsString(); this.assertIdsGotAdded("evcs0", evcsId); this.assertClusterHasOnlyValidProps(); @@ -219,8 +218,7 @@ public void setMaxHardwarePower() throws Exception { JsonUtils.buildJsonObject() // .addProperty(KebaEvcs.Property.IP.name(), "1.1.1.2") // .addProperty(KebaEvcs.Property.MAX_HARDWARE_POWER.name(), hardwarePower) // - .build())) - .get(); + .build())); final var clusterComponent = this.appManagerTestBundle.componentManger.getComponent("evcsCluster0"); final var hardwarePowerPerPhase = (int) clusterComponent.getComponentContext().getProperties() .get("hardwarePowerLimitPerPhase"); @@ -243,7 +241,7 @@ public void testRemoveClusterWhenEvcsBelowTwo() throws Exception { this.assertSingleClusterApp(); this.appManagerTestBundle.sut.handleDeleteAppInstanceRequest(DUMMY_ADMIN, - new DeleteAppInstance.Request(responseSecondEvcs.instance.instanceId)).get(); + new DeleteAppInstance.Request(responseSecondEvcs.instance().instanceId)); this.appManagerTestBundle.assertInstalledApps(1); } @@ -285,11 +283,10 @@ private AddAppInstance.Response installKeba(String ip) new AddAppInstance.Request(this.kebaEvcs.getAppId(), "key", "alias", // JsonUtils.buildJsonObject() // .addProperty(KebaEvcs.Property.IP.name(), ip) // - .build())) - .get(); + .build())); - final var evcsId = response.instance.properties.get(KebaEvcs.Property.EVCS_ID.name()).getAsString(); - final var evcsCtrlId = response.instance.properties.get(KebaEvcs.Property.CTRL_EVCS_ID.name()).getAsString(); + final var evcsId = response.instance().properties.get(KebaEvcs.Property.EVCS_ID.name()).getAsString(); + final var evcsCtrlId = response.instance().properties.get(KebaEvcs.Property.CTRL_EVCS_ID.name()).getAsString(); this.appManagerTestBundle.assertComponentsExist(// new EdgeConfig.Component(evcsId, null, "Evcs.Keba.KeContact", JsonUtils.buildJsonObject() // .addProperty("ip", ip) // @@ -315,11 +312,10 @@ private AddAppInstance.Response installHardyBarthDouble(String... ips) .onlyIf(count == 2, b -> b.addProperty(HardyBarthEvcs.SubPropertySecondChargepoint.IP_CP_2.name(), secondIp)) // - .build())) - .get(); + .build())); - final var evcsId = response.instance.properties.get(HardyBarthEvcs.Property.EVCS_ID.name()).getAsString(); - final var evcsCtrlId = response.instance.properties.get(HardyBarthEvcs.Property.CTRL_EVCS_ID.name()) + final var evcsId = response.instance().properties.get(HardyBarthEvcs.Property.EVCS_ID.name()).getAsString(); + final var evcsCtrlId = response.instance().properties.get(HardyBarthEvcs.Property.CTRL_EVCS_ID.name()) .getAsString(); this.appManagerTestBundle.assertComponentsExist(// new EdgeConfig.Component(evcsId, null, "Evcs.HardyBarth", JsonUtils.buildJsonObject() // @@ -329,10 +325,10 @@ private AddAppInstance.Response installHardyBarthDouble(String... ips) .build()) // ); if (count == 2) { - final var evcsIdCp2 = response.instance.properties.get(HardyBarthEvcs.Property.EVCS_ID_CP_2.name()) - .getAsString(); - final var evcsCtrlIdCp2 = response.instance.properties.get(HardyBarthEvcs.Property.CTRL_EVCS_ID_CP_2.name()) + final var evcsIdCp2 = response.instance().properties.get(HardyBarthEvcs.Property.EVCS_ID_CP_2.name()) .getAsString(); + final var evcsCtrlIdCp2 = response.instance().properties + .get(HardyBarthEvcs.Property.CTRL_EVCS_ID_CP_2.name()).getAsString(); this.appManagerTestBundle.assertComponentsExist(// new EdgeConfig.Component(evcsIdCp2, null, "Evcs.HardyBarth", JsonUtils.buildJsonObject() // .build()), // @@ -351,11 +347,10 @@ private AddAppInstance.Response installIesKeywatt() JsonUtils.buildJsonObject() // .addProperty(IesKeywattEvcs.Property.OCCP_CHARGE_POINT_IDENTIFIER.name(), "IES1") // .addProperty(IesKeywattEvcs.Property.OCCP_CONNECTOR_IDENTIFIER.name(), 1) // - .build())) - .get(); + .build())); - final var evcsId = response.instance.properties.get(IesKeywattEvcs.Property.EVCS_ID.name()).getAsString(); - final var evcsCtrlId = response.instance.properties.get(IesKeywattEvcs.Property.CTRL_EVCS_ID.name()) + final var evcsId = response.instance().properties.get(IesKeywattEvcs.Property.EVCS_ID.name()).getAsString(); + final var evcsCtrlId = response.instance().properties.get(IesKeywattEvcs.Property.CTRL_EVCS_ID.name()) .getAsString(); this.appManagerTestBundle.assertComponentsExist(// new EdgeConfig.Component(evcsId, null, "Evcs.Ocpp.IesKeywattSingle", JsonUtils.buildJsonObject() // diff --git a/io.openems.edge.core/test/io/openems/edge/app/evcs/TestHardyBarthEvcs.java b/io.openems.edge.core/test/io/openems/edge/app/evcs/TestHardyBarthEvcs.java index 9e0f1bb7ea3..435299ec387 100644 --- a/io.openems.edge.core/test/io/openems/edge/app/evcs/TestHardyBarthEvcs.java +++ b/io.openems.edge.core/test/io/openems/edge/app/evcs/TestHardyBarthEvcs.java @@ -38,13 +38,12 @@ public void testInstallationAndUpdate() throws Exception { new AddAppInstance.Request(this.hardyBarthEvcs.getAppId(), "key", "alias", JsonUtils.buildJsonObject() // .addProperty(HardyBarthEvcs.Property.NUMBER_OF_CHARGING_STATIONS.name(), 1) // .addProperty(HardyBarthEvcs.SubPropertyFirstChargepoint.IP.name(), "192.168.1.30") // - .build())) - .get(); + .build())); - final var installProps = installResponse.instance.properties; + final var installProps = installResponse.instance().properties; final var firstCreatedEvcsId = installProps.get(HardyBarthEvcs.Property.EVCS_ID.name()).getAsString(); final var firstCreatedCtrlEvcsId = installProps.get(HardyBarthEvcs.Property.CTRL_EVCS_ID.name()).getAsString(); - assertTrue(installResponse.warnings == null || installResponse.warnings.isEmpty()); + assertTrue(installResponse.warnings() == null || installResponse.warnings().isEmpty()); assertEquals(1, this.appManagerTestBundle.sut.getInstantiatedApps().size()); assertEquals("evcs0", firstCreatedEvcsId); assertEquals("ctrlEvcs0", firstCreatedCtrlEvcsId); @@ -54,21 +53,20 @@ public void testInstallationAndUpdate() throws Exception { assertFalse(installProps.has(HardyBarthEvcs.SubPropertySecondChargepoint.IP_CP_2.name())); final var updateToDoubleResponse = this.appManagerTestBundle.sut.handleUpdateAppInstanceRequest(DUMMY_ADMIN, - new UpdateAppInstance.Request(installResponse.instance.instanceId, "alias", // + new UpdateAppInstance.Request(installResponse.instance().instanceId, "alias", // JsonUtils.buildJsonObject() // .addProperty(HardyBarthEvcs.Property.NUMBER_OF_CHARGING_STATIONS.name(), 2) // .addProperty(HardyBarthEvcs.SubPropertyFirstChargepoint.IP.name(), "192.168.1.30") // .addProperty(HardyBarthEvcs.SubPropertySecondChargepoint.IP_CP_2.name(), "192.168.1.31") // .addProperty(HardyBarthEvcs.SubPropertySecondChargepoint.ALIAS_CP_2.name(), "alias 2") // - .build())) - .get(); + .build())); - final var updateDoubleProps = updateToDoubleResponse.instance.properties; + final var updateDoubleProps = updateToDoubleResponse.instance().properties; final var firstCreatedEvcsIdOfSecond = updateDoubleProps.get(HardyBarthEvcs.Property.EVCS_ID_CP_2.name()) .getAsString(); final var firstCreatedCtrlEvcsIdOfSecond = updateDoubleProps .get(HardyBarthEvcs.Property.CTRL_EVCS_ID_CP_2.name()).getAsString(); - assertTrue(updateToDoubleResponse.warnings == null || updateToDoubleResponse.warnings.isEmpty()); + assertTrue(updateToDoubleResponse.warnings() == null || updateToDoubleResponse.warnings().isEmpty()); assertEquals(1, this.appManagerTestBundle.sut.getInstantiatedApps().size()); assertEquals(firstCreatedEvcsId, updateDoubleProps.get(HardyBarthEvcs.Property.EVCS_ID.name()).getAsString()); assertEquals(firstCreatedCtrlEvcsId, @@ -83,14 +81,14 @@ public void testInstallationAndUpdate() throws Exception { assertTrue(updateDoubleProps.has(HardyBarthEvcs.SubPropertySecondChargepoint.IP_CP_2.name())); final var updateBackToSingleResponse = this.appManagerTestBundle.sut.handleUpdateAppInstanceRequest(DUMMY_ADMIN, - new UpdateAppInstance.Request(installResponse.instance.instanceId, "alias", JsonUtils.buildJsonObject() // - .addProperty(HardyBarthEvcs.Property.NUMBER_OF_CHARGING_STATIONS.name(), 1) // - .addProperty(HardyBarthEvcs.SubPropertyFirstChargepoint.IP.name(), "192.168.1.30") // - .build())) - .get(); + new UpdateAppInstance.Request(installResponse.instance().instanceId, "alias", + JsonUtils.buildJsonObject() // + .addProperty(HardyBarthEvcs.Property.NUMBER_OF_CHARGING_STATIONS.name(), 1) // + .addProperty(HardyBarthEvcs.SubPropertyFirstChargepoint.IP.name(), "192.168.1.30") // + .build())); - final var updateSingleProps = updateBackToSingleResponse.instance.properties; - assertTrue(updateBackToSingleResponse.warnings == null || updateBackToSingleResponse.warnings.isEmpty()); + final var updateSingleProps = updateBackToSingleResponse.instance().properties; + assertTrue(updateBackToSingleResponse.warnings() == null || updateBackToSingleResponse.warnings().isEmpty()); assertEquals(1, this.appManagerTestBundle.sut.getInstantiatedApps().size()); assertEquals(firstCreatedEvcsId, updateSingleProps.get(HardyBarthEvcs.Property.EVCS_ID.name()).getAsString()); assertEquals(firstCreatedEvcsId, updateSingleProps.get(HardyBarthEvcs.Property.EVCS_ID.name()).getAsString()); @@ -106,10 +104,9 @@ public void testInstallationDouble() throws Exception { .addProperty(HardyBarthEvcs.SubPropertyFirstChargepoint.IP.name(), "192.168.1.30") // .addProperty(HardyBarthEvcs.SubPropertySecondChargepoint.IP_CP_2.name(), "192.168.1.31") // .addProperty(HardyBarthEvcs.SubPropertySecondChargepoint.ALIAS_CP_2.name(), "alias 2") // - .build())) - .get(); - final var updateProps = installResponse.instance.properties; - assertTrue(installResponse.warnings == null || installResponse.warnings.isEmpty()); + .build())); + final var updateProps = installResponse.instance().properties; + assertTrue(installResponse.warnings() == null || installResponse.warnings().isEmpty()); assertEquals(1, this.appManagerTestBundle.sut.getInstantiatedApps().size()); assertTrue(updateProps.get(HardyBarthEvcs.Property.EVCS_ID.name()).getAsString().startsWith("evcs")); assertTrue(updateProps.get(HardyBarthEvcs.Property.CTRL_EVCS_ID.name()).getAsString().startsWith("ctrlEvcs")); diff --git a/io.openems.edge.core/test/io/openems/edge/app/heat/TestHeatPump.java b/io.openems.edge.core/test/io/openems/edge/app/heat/TestHeatPump.java index 07fb577c6fa..4831dc04896 100644 --- a/io.openems.edge.core/test/io/openems/edge/app/heat/TestHeatPump.java +++ b/io.openems.edge.core/test/io/openems/edge/app/heat/TestHeatPump.java @@ -86,7 +86,7 @@ public void testNotRemovingDependenciesFromRelay() throws Exception { assertEquals(3, home.dependencies.size()); // update heat pump - this.appManagerTestBundle.sut.handleJsonrpcRequest(DUMMY_ADMIN, new UpdateAppInstance.Request( + this.appManagerTestBundle.sut.handleUpdateAppInstanceRequest(DUMMY_ADMIN, new UpdateAppInstance.Request( heatPumpInstance.instanceId, "alias", JsonUtils.buildJsonObject().build())); // if exceptions occurs here heat pump also deleted dependencies from home diff --git a/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome.java b/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome.java index 73a51874649..f95d671afdf 100644 --- a/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome.java +++ b/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome.java @@ -64,7 +64,7 @@ public void testCreateAndUpdateHomeFullSettings() throws Exception { var homeInstance = this.createFullHome(); - this.appManagerTestBundle.sut.handleJsonrpcRequest(DUMMY_ADMIN, + this.appManagerTestBundle.sut.handleUpdateAppInstanceRequest(DUMMY_ADMIN, new UpdateAppInstance.Request(homeInstance.instanceId, "aliasrename", fullConfig)); // expect the same as before // make sure every dependency got installed @@ -119,7 +119,7 @@ public void testRemoveAcMeter() throws Exception { .addProperty("SHADOW_MANAGEMENT_DISABLED", false) // .build(); - this.appManagerTestBundle.sut.handleJsonrpcRequest(DUMMY_ADMIN, + this.appManagerTestBundle.sut.handleUpdateAppInstanceRequest(DUMMY_ADMIN, new UpdateAppInstance.Request(homeInstance.instanceId, "aliasrename", configNoMeter)); // expect the same as before // make sure every dependency got installed @@ -157,7 +157,7 @@ public void testFeedInTypeRippleControlReceiver() throws Exception { final var properties = fullSettings(); properties.addProperty("RIPPLE_CONTROL_RECEIVER_ACTIV", true); this.appManagerTestBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, - new AddAppInstance.Request("App.FENECON.Home", "key", "alias", properties)).get(); + new AddAppInstance.Request("App.FENECON.Home", "key", "alias", properties)); final var batteryInverterProps = this.appManagerTestBundle.componentManger.getComponent("batteryInverter0") .getComponentContext().getProperties(); @@ -171,7 +171,7 @@ public void testFeedInTypeDynamicLimitation() throws Exception { final var properties = fullSettings(); properties.addProperty("FEED_IN_TYPE", FeedInType.DYNAMIC_LIMITATION.name()); this.appManagerTestBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, - new AddAppInstance.Request("App.FENECON.Home", "key", "alias", properties)).get(); + new AddAppInstance.Request("App.FENECON.Home", "key", "alias", properties)); final var batteryInverterProps = this.appManagerTestBundle.componentManger.getComponent("batteryInverter0") .getComponentContext().getProperties(); @@ -185,7 +185,7 @@ public void testFeedInTypeNoLimitation() throws Exception { final var properties = fullSettings(); properties.addProperty("FEED_IN_TYPE", FeedInType.NO_LIMITATION.name()); this.appManagerTestBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, - new AddAppInstance.Request("App.FENECON.Home", "key", "alias", properties)).get(); + new AddAppInstance.Request("App.FENECON.Home", "key", "alias", properties)); final var batteryInverterProps = this.appManagerTestBundle.componentManger.getComponent("batteryInverter0") .getComponentContext().getProperties(); @@ -211,9 +211,9 @@ public static final OpenemsAppInstance createFullHome(AppManagerTestBundle appMa var fullConfig = fullSettings(); final var response = appManagerTestBundle.sut.handleAddAppInstanceRequest(user, - new AddAppInstance.Request("App.FENECON.Home", "key", "alias", fullConfig)).get(); + new AddAppInstance.Request("App.FENECON.Home", "key", "alias", fullConfig)); - assertEquals(4, response.instance.dependencies.size()); + assertEquals(4, response.instance().dependencies.size()); // make sure every dependency got installed assertEquals(appManagerTestBundle.sut.getInstantiatedApps().size(), 5); diff --git a/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome20.java b/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome20.java index 53bc17e0d65..f192548fe84 100644 --- a/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome20.java +++ b/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome20.java @@ -49,7 +49,7 @@ public void testCreateHomeFullSettings() throws Exception { public void testCreateAndUpdateHomeFullSettings() throws Exception { var homeInstance = this.createFullHome(); - this.appManagerTestBundle.sut.handleJsonrpcRequest(DUMMY_ADMIN, + this.appManagerTestBundle.sut.handleUpdateAppInstanceRequest(DUMMY_ADMIN, new UpdateAppInstance.Request(homeInstance.instanceId, "aliasrename", fullSettings())); // expect the same as before // make sure every dependency got installed @@ -96,7 +96,7 @@ public void testCheckPvs() throws Exception { settings.addProperty("HAS_PV_3", false); settings.addProperty("HAS_PV_4", false); - this.appManagerTestBundle.sut.handleJsonrpcRequest(DUMMY_ADMIN, + this.appManagerTestBundle.sut.handleUpdateAppInstanceRequest(DUMMY_ADMIN, new UpdateAppInstance.Request(homeInstance.instanceId, "aliasrename", settings)); for (int i = 0; i < 2; i++) { @@ -124,15 +124,14 @@ public void testShadowManagement() throws Exception { .addProperty("EMERGENCY_RESERVE_ENABLED", true) // .addProperty("EMERGENCY_RESERVE_SOC", 15) // .addProperty("SHADOW_MANAGEMENT_DISABLED", true) // - .build())) - .get(); + .build())); var batteryInverter = this.appManagerTestBundle.componentManger.getComponent("batteryInverter0"); assertEquals("DISABLE", (String) batteryInverter.getComponentContext().getProperties().get("mpptForShadowEnable")); this.appManagerTestBundle.sut.handleUpdateAppInstanceRequest(DUMMY_ADMIN, - new UpdateAppInstance.Request(response.instance.instanceId, "alias", JsonUtils.buildJsonObject() // + new UpdateAppInstance.Request(response.instance().instanceId, "alias", JsonUtils.buildJsonObject() // .addProperty("SAFETY_COUNTRY", "GERMANY") // .addProperty("FEED_IN_TYPE", FeedInType.DYNAMIC_LIMITATION) // .addProperty("MAX_FEED_IN_POWER", 1000) // diff --git a/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome30.java b/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome30.java index 0603064a596..ed6fd66154c 100644 --- a/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome30.java +++ b/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome30.java @@ -50,7 +50,7 @@ public void testCreateHomeFullSettings() throws Exception { public void testCreateAndUpdateHomeFullSettings() throws Exception { var homeInstance = this.createFullHome30(); - this.appManagerTestBundle.sut.handleJsonrpcRequest(DUMMY_ADMIN, + this.appManagerTestBundle.sut.handleUpdateAppInstanceRequest(DUMMY_ADMIN, new UpdateAppInstance.Request(homeInstance.instanceId, "aliasrename", fullSettings())); // expect the same as before // make sure every dependency got installed @@ -97,7 +97,7 @@ public void testCheckPvs() throws Exception { settings.addProperty("HAS_PV_3", false); settings.addProperty("HAS_PV_4", false); - this.appManagerTestBundle.sut.handleJsonrpcRequest(DUMMY_ADMIN, + this.appManagerTestBundle.sut.handleUpdateAppInstanceRequest(DUMMY_ADMIN, new UpdateAppInstance.Request(homeInstance.instanceId, "aliasrename", settings)); for (int i = 0; i < 2; i++) { @@ -157,15 +157,14 @@ public void testShadowManagement() throws Exception { .addProperty("EMERGENCY_RESERVE_ENABLED", true) // .addProperty("EMERGENCY_RESERVE_SOC", 15) // .addProperty("SHADOW_MANAGEMENT_DISABLED", true) // - .build())) - .get(); + .build())); var batteryInverter = this.appManagerTestBundle.componentManger.getComponent("batteryInverter0"); assertEquals("DISABLE", (String) batteryInverter.getComponentContext().getProperties().get("mpptForShadowEnable")); this.appManagerTestBundle.sut.handleUpdateAppInstanceRequest(DUMMY_ADMIN, - new UpdateAppInstance.Request(response.instance.instanceId, "alias", JsonUtils.buildJsonObject() // + new UpdateAppInstance.Request(response.instance().instanceId, "alias", JsonUtils.buildJsonObject() // .addProperty("SAFETY_COUNTRY", "GERMANY") // .addProperty("FEED_IN_TYPE", FeedInType.DYNAMIC_LIMITATION) // .addProperty("MAX_FEED_IN_POWER", 1000) // @@ -185,7 +184,7 @@ public void testFeedInTypeRippleControlReceiver() throws Exception { final var properties = fullSettings(); properties.addProperty("FEED_IN_TYPE", FeedInType.EXTERNAL_LIMITATION.name()); this.appManagerTestBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, - new AddAppInstance.Request("App.FENECON.Home.30", "key", "alias", properties)).get(); + new AddAppInstance.Request("App.FENECON.Home.30", "key", "alias", properties)); final var batteryInverterProps = this.appManagerTestBundle.componentManger.getComponent("batteryInverter0") .getComponentContext().getProperties(); @@ -199,7 +198,7 @@ public void testFeedInTypeDynamicLimitation() throws Exception { final var properties = fullSettings(); properties.addProperty("FEED_IN_TYPE", FeedInType.DYNAMIC_LIMITATION.name()); this.appManagerTestBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, - new AddAppInstance.Request("App.FENECON.Home.30", "key", "alias", properties)).get(); + new AddAppInstance.Request("App.FENECON.Home.30", "key", "alias", properties)); final var batteryInverterProps = this.appManagerTestBundle.componentManger.getComponent("batteryInverter0") .getComponentContext().getProperties(); @@ -213,7 +212,7 @@ public void testFeedInTypeNoLimitation() throws Exception { final var properties = fullSettings(); properties.addProperty("FEED_IN_TYPE", FeedInType.NO_LIMITATION.name()); this.appManagerTestBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, - new AddAppInstance.Request("App.FENECON.Home.30", "key", "alias", properties)).get(); + new AddAppInstance.Request("App.FENECON.Home.30", "key", "alias", properties)); final var batteryInverterProps = this.appManagerTestBundle.componentManger.getComponent("batteryInverter0") .getComponentContext().getProperties(); @@ -239,9 +238,9 @@ public static final OpenemsAppInstance createFullHome30(AppManagerTestBundle app var fullConfig = fullSettings(); final var response = appManagerTestBundle.sut.handleAddAppInstanceRequest(user, - new AddAppInstance.Request("App.FENECON.Home.30", "key", "alias", fullConfig)).get(); + new AddAppInstance.Request("App.FENECON.Home.30", "key", "alias", fullConfig)); - assertEquals(4, response.instance.dependencies.size()); + assertEquals(4, response.instance().dependencies.size()); // make sure every dependency got installed assertEquals(appManagerTestBundle.sut.getInstantiatedApps().size(), 5); diff --git a/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome30DefaultRelays.java b/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome30DefaultRelays.java index 0b96ddc28a3..699921aa573 100644 --- a/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome30DefaultRelays.java +++ b/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome30DefaultRelays.java @@ -94,7 +94,7 @@ public void testDefaultRelayValuesThresholdControl() throws Exception { private final OpenemsAppInstance createFullHomeWithDummyIo() throws Exception { final var instance = TestFeneconHome30.createFullHome30(this.appManagerTestBundle, DUMMY_ADMIN); - this.appManagerTestBundle.componentManger.handleJsonrpcRequest(DUMMY_ADMIN, + this.appManagerTestBundle.componentManger.handleDeleteComponentConfigRequest(DUMMY_ADMIN, new DeleteComponentConfigRequest("io0")); final var dummyRelay = new DummyInputOutput("io0", "RELAY", 1, 8); this.appManagerTestBundle.cm.getOrCreateEmptyConfiguration(dummyRelay.id()); diff --git a/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHomeDefaultRelays.java b/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHomeDefaultRelays.java index 294a053a360..983785d6092 100644 --- a/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHomeDefaultRelays.java +++ b/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHomeDefaultRelays.java @@ -90,7 +90,7 @@ public void testDefaultRelayValuesThresholdControl() throws Exception { private final OpenemsAppInstance createFullHomeWithDummyIo() throws Exception { final var instance = TestFeneconHome.createFullHome(this.appManagerTestBundle, DUMMY_ADMIN); - this.appManagerTestBundle.componentManger.handleJsonrpcRequest(DUMMY_ADMIN, + this.appManagerTestBundle.componentManger.handleDeleteComponentConfigRequest(DUMMY_ADMIN, new DeleteComponentConfigRequest("io0")); final var dummyRelay = new DummyInputOutput("io0", "RELAY", 1, 4); this.appManagerTestBundle.cm.getOrCreateEmptyConfiguration(dummyRelay.id()); diff --git a/io.openems.edge.core/test/io/openems/edge/app/timeofusetariff/TestTibber.java b/io.openems.edge.core/test/io/openems/edge/app/timeofusetariff/TestTibber.java index 63d398608c1..0a1bfcf3c8d 100644 --- a/io.openems.edge.core/test/io/openems/edge/app/timeofusetariff/TestTibber.java +++ b/io.openems.edge.core/test/io/openems/edge/app/timeofusetariff/TestTibber.java @@ -58,15 +58,15 @@ public void testRemoveAccessToken() throws Exception { .addProperty("ACCESS_TOKEN", "g78aw9ht2n112nb453") // .build(); var response = this.appManagerTestBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, - new AddAppInstance.Request(this.tibber.getAppId(), "key", "alias", properties)).get(); + new AddAppInstance.Request(this.tibber.getAppId(), "key", "alias", properties)); // in response its set because the access token in the component is not empty - assertEquals("xxx", response.instance.properties.get("ACCESS_TOKEN").getAsString()); + assertEquals("xxx", response.instance().properties.get("ACCESS_TOKEN").getAsString()); // in the actual instance there shouldn't be an access token, instead it should // only be taken directly from the component final var instance = this.appManagerTestBundle.appManagerUtil - .findInstanceByIdOrError(response.instance.instanceId); + .findInstanceByIdOrError(response.instance().instanceId); assertFalse(instance.properties.has("ACCESS_TOKEN")); final var apps = this.appManagerTestBundle.getAppsFromConfig(); @@ -89,7 +89,7 @@ public void testAddChannelToPredictor() throws Exception { .addProperty("ACCESS_TOKEN", "g78aw9ht2n112nb453") // .build(); this.appManagerTestBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, - new AddAppInstance.Request(this.tibber.getAppId(), "key", "alias", properties)).get(); + new AddAppInstance.Request(this.tibber.getAppId(), "key", "alias", properties)); this.assertChannelsInPredictor("_sum/UnmanagedConsumptionActivePower"); } @@ -100,7 +100,7 @@ public void testOnlyCompatibleWithHome() throws Exception { .addProperty("ACCESS_TOKEN", "g78aw9ht2n112nb453") // .build(); this.appManagerTestBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, - new AddAppInstance.Request(this.tibber.getAppId(), "key", "alias", properties)).get(); + new AddAppInstance.Request(this.tibber.getAppId(), "key", "alias", properties)); } @Test @@ -110,40 +110,37 @@ public void testSetTokenValue() throws Exception { .addProperty("ACCESS_TOKEN", "g78aw9ht2n112nb453") // .build(); final var response = this.appManagerTestBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, - new AddAppInstance.Request(this.tibber.getAppId(), "key", "alias", properties)).get(); + new AddAppInstance.Request(this.tibber.getAppId(), "key", "alias", properties)); final var accessTokenProp = Arrays.stream(this.tibber.getProperties()) // .filter(t -> t.name.equals(Tibber.Property.ACCESS_TOKEN.name())) // .findAny().orElse(null); - var value = accessTokenProp.bidirectionalValue.apply(response.instance.properties); + var value = accessTokenProp.bidirectionalValue.apply(response.instance().properties); assertEquals("xxx", value.getAsString()); - this.appManagerTestBundle.componentManger.handleJsonrpcRequest(DUMMY_ADMIN, - new UpdateComponentConfigRequest(response.instance.properties + this.appManagerTestBundle.componentManger.handleUpdateComponentConfigRequest(DUMMY_ADMIN, + new UpdateComponentConfigRequest(response.instance().properties .get(Tibber.Property.TIME_OF_USE_TARIFF_PROVIDER_ID.name()).getAsString(), - List.of(new UpdateComponentConfigRequest.Property("accessToken", "")))) - .get(); + List.of(new UpdateComponentConfigRequest.Property("accessToken", "")))); - value = accessTokenProp.bidirectionalValue.apply(response.instance.properties); + value = accessTokenProp.bidirectionalValue.apply(response.instance().properties); assertEquals(JsonNull.INSTANCE, value); } private void createPredictor() throws Exception { - this.appManagerTestBundle.componentManger.handleJsonrpcRequest(DUMMY_ADMIN, + this.appManagerTestBundle.componentManger.handleCreateComponentConfigRequest(DUMMY_ADMIN, new CreateComponentConfigRequest("Predictor.PersistenceModel", List.of(// new UpdateComponentConfigRequest.Property("id", "predictor0"), // new UpdateComponentConfigRequest.Property("channelAddresses", JsonUtils.buildJsonArray()// .build()) // - ))).get(); + ))); } private void installHome() throws InterruptedException, ExecutionException, OpenemsNamedException { - this.appManagerTestBundle.sut - .handleAddAppInstanceRequest(DUMMY_ADMIN, - new AddAppInstance.Request("App.FENECON.Home", "key", "alias", TestFeneconHome.minSettings())) - .get(); + this.appManagerTestBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, + new AddAppInstance.Request("App.FENECON.Home", "key", "alias", TestFeneconHome.minSettings())); } private void assertChannelsInPredictor(String... channels) throws OpenemsNamedException { diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerAppHelperImplTest.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerAppHelperImplTest.java index 22899557932..98637a96d29 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerAppHelperImplTest.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerAppHelperImplTest.java @@ -2,6 +2,7 @@ import static io.openems.edge.common.test.DummyUser.DUMMY_ADMIN; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.ArrayList; @@ -130,7 +131,7 @@ public void testUpdatePolicyNever() throws OpenemsNamedException { assertEquals(2, this.appManagerTestBundle.sut.getInstantiatedApps().size()); - this.appManagerTestBundle.sut.handleJsonrpcRequest(DUMMY_ADMIN, + this.appManagerTestBundle.sut.handleUpdateAppInstanceRequest(DUMMY_ADMIN, new UpdateAppInstance.Request(this.getAppByAppId(this.testAApp.getAppId()).instanceId, "", JsonUtils.buildJsonObject() // .addProperty("UPDATE_POLICY", DependencyDeclaration.UpdatePolicy.NEVER.name()) // @@ -160,7 +161,7 @@ public void testUpdatePolicyAlways() throws OpenemsNamedException { assertEquals(3, this.appManagerTestBundle.sut.getInstantiatedApps().size()); - this.appManagerTestBundle.sut.handleJsonrpcRequest(DUMMY_ADMIN, + this.appManagerTestBundle.sut.handleUpdateAppInstanceRequest(DUMMY_ADMIN, new UpdateAppInstance.Request(this.getAppByAppId(this.testAApp.getAppId()).instanceId, "", JsonUtils.buildJsonObject() // .addProperty("UPDATE_POLICY", DependencyDeclaration.UpdatePolicy.ALWAYS.name()) // @@ -184,7 +185,7 @@ public void testUpdatePolicyIfMine() throws OpenemsNamedException { assertEquals(2, this.appManagerTestBundle.sut.getInstantiatedApps().size()); - this.appManagerTestBundle.sut.handleJsonrpcRequest(DUMMY_ADMIN, + this.appManagerTestBundle.sut.handleUpdateAppInstanceRequest(DUMMY_ADMIN, new UpdateAppInstance.Request(this.getAppByAppId(this.testAApp.getAppId()).instanceId, "", JsonUtils.buildJsonObject() // .addProperty("UPDATE_POLICY", DependencyDeclaration.UpdatePolicy.IF_MINE.name()) // @@ -200,7 +201,7 @@ public void testUpdatePolicyIfMine() throws OpenemsNamedException { assertEquals(3, this.appManagerTestBundle.sut.getInstantiatedApps().size()); - this.appManagerTestBundle.sut.handleJsonrpcRequest(DUMMY_ADMIN, + this.appManagerTestBundle.sut.handleUpdateAppInstanceRequest(DUMMY_ADMIN, new UpdateAppInstance.Request(this.getAppByAppId(this.testAApp.getAppId()).instanceId, "", JsonUtils.buildJsonObject() // .addProperty("UPDATE_POLICY", DependencyDeclaration.UpdatePolicy.IF_MINE.name()) // @@ -334,14 +335,13 @@ public void testDependencyUpdatePolicyAllowAll() assertEquals(2, this.appManagerTestBundle.sut.getInstantiatedApps().size()); var newAlias = "newAppAlias"; - var completable = this.appManagerTestBundle.sut.handleJsonrpcRequest(DUMMY_ADMIN, + var result = this.appManagerTestBundle.sut.handleUpdateAppInstanceRequest(DUMMY_ADMIN, new UpdateAppInstance.Request(this.getAppByAppId(this.testCApp.getAppId()).instanceId, newAlias, JsonUtils.buildJsonObject() // .addProperty("NUMBER", 2) // .build())); - var result = completable.get().getResult(); - assertTrue(!result.has("warnings") || result.get("warnings").getAsJsonArray().size() == 0); + assertTrue(result.warnings().isEmpty()); var instance = this.getAppByAppId(this.testCApp.getAppId()); assertEquals(newAlias, instance.alias); @@ -364,7 +364,7 @@ public void testDependencyUpdatePolicyAllowNone() assertEquals(2, this.appManagerTestBundle.sut.getInstantiatedApps().size()); var newAlias = "newAppAlias"; - this.appManagerTestBundle.sut.handleJsonrpcRequest(DUMMY_ADMIN, + this.appManagerTestBundle.sut.handleUpdateAppInstanceRequest(DUMMY_ADMIN, new UpdateAppInstance.Request(this.getAppByAppId(this.testCApp.getAppId()).instanceId, newAlias, JsonUtils.buildJsonObject() // .addProperty("NUMBER", 2) // @@ -387,15 +387,13 @@ public void testDependencyUpdatePolicyAllowOnlyUnconfiguredProperties() assertEquals(2, this.appManagerTestBundle.sut.getInstantiatedApps().size()); var newAlias = "newAppAlias"; - var completable = this.appManagerTestBundle.sut.handleJsonrpcRequest(DUMMY_ADMIN, + var result = this.appManagerTestBundle.sut.handleUpdateAppInstanceRequest(DUMMY_ADMIN, new UpdateAppInstance.Request(this.getAppByAppId(this.testCApp.getAppId()).instanceId, newAlias, JsonUtils.buildJsonObject() // .addProperty("NUMBER", 2) // .build())); - var result = completable.get().getResult(); - assertTrue(result.has("warnings")); - assertTrue(result.get("warnings").getAsJsonArray().size() > 0); + assertFalse(result.warnings().isEmpty()); var instance = this.getAppByAppId(this.testCApp.getAppId()); assertEquals(newAlias, instance.alias); diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerImpSynchronizationTest.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerImpSynchronizationTest.java index 7bdc17916be..9b79d51b330 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerImpSynchronizationTest.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerImpSynchronizationTest.java @@ -6,7 +6,6 @@ import java.util.UUID; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import org.junit.Before; @@ -142,8 +141,7 @@ public void testRemoveOfNotAvailableInstance() throws Exception { public void testSimulateAfterInstallaion() throws Exception { this.appManager.handleAddAppInstanceRequest(DUMMY_ADMIN, new AddAppInstance.Request("App.PvInverter.SolarEdge", "key", "alias", JsonUtils.buildJsonObject() // - .build())) - .get(); + .build())); assertTrue(this.appManager.lockModifyingApps.tryLock()); assertTrue(this.appManager.waitingForModified); @@ -156,8 +154,7 @@ public void testSimulateAfterInstallaion() throws Exception { public void testSimulateLockWaitingForModification() throws Exception { this.appManager.handleAddAppInstanceRequest(DUMMY_ADMIN, new AddAppInstance.Request("App.PvInverter.SolarEdge", "key", "alias", JsonUtils.buildJsonObject() // - .build())) - .get(); + .build())); assertTrue(this.appManager.waitingForModified); @@ -166,9 +163,8 @@ public void testSimulateLockWaitingForModification() throws Exception { return this.appManager.handleAddAppInstanceRequest(DUMMY_ADMIN, new AddAppInstance.Request("App.PvInverter.SolarEdge", "key", "alias", JsonUtils.buildJsonObject() // - .build())) - .get(); - } catch (InterruptedException | ExecutionException | OpenemsNamedException e) { + .build())); + } catch (OpenemsNamedException e) { throw new RuntimeException(e); } }); diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerTestBundle.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerTestBundle.java index 97ca72d496d..abcc772227d 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerTestBundle.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerTestBundle.java @@ -8,7 +8,6 @@ import java.util.Dictionary; import java.util.Hashtable; import java.util.List; -import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; @@ -29,7 +28,6 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; -import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; import io.openems.common.types.EdgeConfig; import io.openems.common.utils.JsonUtils; import io.openems.common.utils.ReflectionUtils; @@ -181,7 +179,7 @@ protected void deactivate() { } @Override - public CompletableFuture handleAddAppInstanceRequest(User user, Request request, + public AddAppInstance.Response handleAddAppInstanceRequest(User user, Request request, boolean ignoreBackend) throws OpenemsNamedException { final var response = super.handleAddAppInstanceRequest(user, request, ignoreBackend); this.modifyWithCurrentConfig(); @@ -189,7 +187,7 @@ public CompletableFuture handleAddAppInstanceRequest(Us } @Override - public CompletableFuture handleDeleteAppInstanceRequest(User user, + public DeleteAppInstance.Response handleDeleteAppInstanceRequest(User user, DeleteAppInstance.Request request) throws OpenemsNamedException { final var response = super.handleDeleteAppInstanceRequest(user, request); this.modifyWithCurrentConfig(); @@ -197,7 +195,7 @@ public CompletableFuture handleDeleteAppInstan } @Override - public CompletableFuture handleUpdateAppInstanceRequest(User user, + public UpdateAppInstance.Response handleUpdateAppInstanceRequest(User user, UpdateAppInstance.Request request) throws OpenemsNamedException { final var response = super.handleUpdateAppInstanceRequest(user, request); this.modifyWithCurrentConfig(); diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppPermissionTest.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppPermissionTest.java index bb0be50560b..7156716fbd6 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppPermissionTest.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppPermissionTest.java @@ -61,11 +61,11 @@ private OpenemsAppInstance createDummyApp() throws Exception { return this.test.sut.handleAddAppInstanceRequest(DUMMY_INSTALLER, new AddAppInstance.Request("App.Dummy", "key", "alias", JsonUtils.buildJsonObject() // .build())) - .get().instance; + .instance(); } private void deleteDummyApp(OpenemsAppInstance instance, User user) throws Exception { - this.test.sut.handleDeleteAppInstanceRequest(user, new DeleteAppInstance.Request(instance.instanceId)).get(); + this.test.sut.handleDeleteAppInstanceRequest(user, new DeleteAppInstance.Request(instance.instanceId)); } } diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/DummyPseudoComponentManager.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/DummyPseudoComponentManager.java index 36f66c5f4ef..9aba2d766eb 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/DummyPseudoComponentManager.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/DummyPseudoComponentManager.java @@ -11,7 +11,6 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Vector; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; @@ -30,13 +29,9 @@ import io.openems.common.exceptions.OpenemsError; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; -import io.openems.common.jsonrpc.base.GenericJsonrpcResponseSuccess; -import io.openems.common.jsonrpc.base.JsonrpcRequest; -import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; import io.openems.common.jsonrpc.request.CreateComponentConfigRequest; import io.openems.common.jsonrpc.request.DeleteComponentConfigRequest; import io.openems.common.jsonrpc.request.UpdateComponentConfigRequest; -import io.openems.common.session.Role; import io.openems.common.types.EdgeConfig; import io.openems.common.types.EdgeConfig.ActualEdgeConfig; import io.openems.common.types.EdgeConfig.Component; @@ -157,27 +152,7 @@ public EdgeConfig getEdgeConfig() { } @Override - public CompletableFuture handleJsonrpcRequest(// - final User user, // - final JsonrpcRequest request // - ) throws OpenemsNamedException { - user.assertRoleIsAtLeast("handleJsonrpcRequest", Role.GUEST); - - switch (request.getMethod()) { - - case CreateComponentConfigRequest.METHOD: - return this.handleCreateComponentConfigRequest(user, CreateComponentConfigRequest.from(request)); - case UpdateComponentConfigRequest.METHOD: - return this.handleUpdateComponentConfigRequest(user, UpdateComponentConfigRequest.from(request)); - case DeleteComponentConfigRequest.METHOD: - return this.handleDeleteComponentConfigRequest(user, DeleteComponentConfigRequest.from(request)); - - default: - throw OpenemsError.JSONRPC_UNHANDLED_METHOD.exception(request.getMethod()); - } - } - - private CompletableFuture handleCreateComponentConfigRequest(// + public void handleCreateComponentConfigRequest(// final User user, // final CreateComponentConfigRequest request // ) throws OpenemsNamedException { @@ -189,11 +164,10 @@ private CompletableFuture handleCreateComponentConfigReq ); this.components.add(component); - - return CompletableFuture.completedFuture(new GenericJsonrpcResponseSuccess(request.getId())); } - private CompletableFuture handleUpdateComponentConfigRequest(// + @Override + public void handleUpdateComponentConfigRequest(// final User user, // final UpdateComponentConfigRequest request // ) throws OpenemsNamedException { @@ -207,7 +181,6 @@ private CompletableFuture handleUpdateComponentConfigReq ); this.components.removeIf(t -> t.id().equals(request.getComponentId())); this.components.add(component); - return CompletableFuture.completedFuture(new GenericJsonrpcResponseSuccess(request.getId())); } if (this.configurationAdmin == null) { throw new OpenemsException("Can not update Component Config. ConfigurationAdmin is null!"); @@ -227,18 +200,17 @@ private CompletableFuture handleUpdateComponentConfigReq } configuration.update(properties); } - return CompletableFuture.completedFuture(new GenericJsonrpcResponseSuccess(request.getId())); } catch (IOException | InvalidSyntaxException e) { throw new OpenemsException("Can not update Component Config."); } } - private CompletableFuture handleDeleteComponentConfigRequest(// + @Override + public void handleDeleteComponentConfigRequest(// final User user, // final DeleteComponentConfigRequest request // ) throws OpenemsNamedException { this.components.removeIf(t -> t.id().equals(request.getComponentId())); - return CompletableFuture.completedFuture(new GenericJsonrpcResponseSuccess(request.getId())); } /** @@ -417,4 +389,4 @@ public ServiceReference getServiceReference() { } -} \ No newline at end of file +} diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/InstallationTest.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/InstallationTest.java index abefe8a1024..6824b806e5e 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/InstallationTest.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/InstallationTest.java @@ -31,8 +31,7 @@ public void testIncompatibleAppInstallation() throws Exception { try { appManagerTestBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, new AddAppInstance.Request(app.getAppId(), "key", "alias", JsonUtils.buildJsonObject() // - .build())) - .get(); + .build())); } catch (OpenemsException e) { exception = e; } @@ -51,11 +50,10 @@ public void testCompatibleAppInstallation() throws Exception { singleAppTest(dummyApp, (appManagerTestBundle, app) -> { final var response = appManagerTestBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, new AddAppInstance.Request(app.getAppId(), "key", "alias", JsonUtils.buildJsonObject() // - .build())) - .get(); + .build())); assertNotNull(appManagerTestBundle.sut.getInstantiatedApps() - .get(appManagerTestBundle.sut.getInstantiatedApps().indexOf(response.instance))); + .get(appManagerTestBundle.sut.getInstantiatedApps().indexOf(response.instance()))); }); } @@ -70,8 +68,7 @@ public void testNotInstallableAppInstallation() throws Exception { try { appManagerTestBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, new AddAppInstance.Request(app.getAppId(), "key", "alias", JsonUtils.buildJsonObject() // - .build())) - .get(); + .build())); } catch (OpenemsException e) { exception = e; } @@ -90,11 +87,10 @@ public void testInstallableAppInstallation() throws Exception { singleAppTest(dummyApp, (appManagerTestBundle, app) -> { final var response = appManagerTestBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, new AddAppInstance.Request(app.getAppId(), "key", "alias", JsonUtils.buildJsonObject() // - .build())) - .get(); + .build())); assertNotNull(appManagerTestBundle.sut.getInstantiatedApps() - .get(appManagerTestBundle.sut.getInstantiatedApps().indexOf(response.instance))); + .get(appManagerTestBundle.sut.getInstantiatedApps().indexOf(response.instance()))); }); } @@ -110,8 +106,7 @@ public void testAppInstallationWithExceptionalConfiguration() throws Exception { try { appManagerTestBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, new AddAppInstance.Request(app.getAppId(), "key", "alias", JsonUtils.buildJsonObject() // - .build())) - .get(); + .build())); } catch (OpenemsException e) { exception = e; } @@ -133,11 +128,10 @@ public void testAppUpdateWithExceptionalConfiguration() throws Exception { singleAppTest(dummyApp, (appManagerTestBundle, app) -> { final var response = appManagerTestBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, new AddAppInstance.Request(app.getAppId(), "key", "alias", JsonUtils.buildJsonObject() // - .build())) - .get(); + .build())); final var instance = appManagerTestBundle.sut.getInstantiatedApps() - .get(appManagerTestBundle.sut.getInstantiatedApps().indexOf(response.instance)); + .get(appManagerTestBundle.sut.getInstantiatedApps().indexOf(response.instance())); assertNotNull(instance); @@ -145,8 +139,7 @@ public void testAppUpdateWithExceptionalConfiguration() throws Exception { try { appManagerTestBundle.sut.handleUpdateAppInstanceRequest(DUMMY_ADMIN, new UpdateAppInstance.Request(instance.instanceId, "alias", JsonUtils.buildJsonObject() // - .build())) - .get(); + .build())); } catch (OpenemsException e) { exception = e; } diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestSettingComponentIds.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestSettingComponentIds.java index 9e9df0f93e2..5538b1cb389 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestSettingComponentIds.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestSettingComponentIds.java @@ -36,7 +36,7 @@ public void beforeEach() throws Exception { public void testSettingInitially() throws Exception { final var installResponse = this.add(4); - final var installProps = installResponse.instance.properties; + final var installProps = installResponse.instance().properties; final var initId1 = JsonUtils.getAsString(installProps, TestMultipleIds.Property.ID_1.name()); final var initId2 = JsonUtils.getAsString(installProps, TestMultipleIds.Property.ID_2.name()); final var initId3 = JsonUtils.getAsString(installProps, TestMultipleIds.Property.ID_3.name()); @@ -49,14 +49,14 @@ public void testSettingInitially() throws Exception { public void testSettingOnUpdate() throws Exception { final var installResponse = this.add(2); - final var installProps = installResponse.instance.properties; + final var installProps = installResponse.instance().properties; final var initId1 = JsonUtils.getAsString(installProps, TestMultipleIds.Property.ID_1.name()); final var initId2 = JsonUtils.getAsString(installProps, TestMultipleIds.Property.ID_2.name()); assertEquals(2, Sets.newHashSet(initId1, initId2).size()); assertEquals(3, installProps.size()); - final var updateResponse = this.update(installResponse.instance.instanceId, 4); - final var updateProps = updateResponse.instance.properties; + final var updateResponse = this.update(installResponse.instance().instanceId, 4); + final var updateProps = updateResponse.instance().properties; final var updatedId1 = JsonUtils.getAsString(updateProps, TestMultipleIds.Property.ID_1.name()); final var updatedId2 = JsonUtils.getAsString(updateProps, TestMultipleIds.Property.ID_2.name()); final var initId3 = JsonUtils.getAsString(updateProps, TestMultipleIds.Property.ID_3.name()); @@ -72,7 +72,7 @@ public void testSettingOnUpdate() throws Exception { public void testRemoveIds() throws Exception { final var installResponse = this.add(4); - final var installProps = installResponse.instance.properties; + final var installProps = installResponse.instance().properties; final var initId1 = JsonUtils.getAsString(installProps, TestMultipleIds.Property.ID_1.name()); final var initId2 = JsonUtils.getAsString(installProps, TestMultipleIds.Property.ID_2.name()); final var initId3 = JsonUtils.getAsString(installProps, TestMultipleIds.Property.ID_3.name()); @@ -80,8 +80,8 @@ public void testRemoveIds() throws Exception { assertEquals(4, Sets.newHashSet(initId1, initId2, initId3, initId4).size()); - final var updateResponse = this.update(installResponse.instance.instanceId, 2); - final var updateProps = updateResponse.instance.properties; + final var updateResponse = this.update(installResponse.instance().instanceId, 2); + final var updateProps = updateResponse.instance().properties; final var updatedId1 = JsonUtils.getAsString(updateProps, TestMultipleIds.Property.ID_1.name()); final var updatedId2 = JsonUtils.getAsString(updateProps, TestMultipleIds.Property.ID_2.name()); @@ -95,16 +95,14 @@ private AddAppInstance.Response add(int setIds) throws Exception { return this.appManagerTestBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, new AddAppInstance.Request(this.testMultipleIds.getAppId(), "key", "alias", JsonUtils.buildJsonObject() // .addProperty(TestMultipleIds.Property.SET_IDS.name(), setIds) // - .build())) - .get(); + .build())); } private UpdateAppInstance.Response update(UUID instanceId, int setIds) throws Exception { return this.appManagerTestBundle.sut.handleUpdateAppInstanceRequest(DUMMY_ADMIN, new UpdateAppInstance.Request(instanceId, "alias", JsonUtils.buildJsonObject() // .addProperty(TestMultipleIds.Property.SET_IDS.name(), setIds) // - .build())) - .get(); + .build())); } } diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/dependency/aggregatetask/ComponentAggregateTaskImplTest.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/dependency/aggregatetask/ComponentAggregateTaskImplTest.java index d10837e575b..73543c97028 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/dependency/aggregatetask/ComponentAggregateTaskImplTest.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/dependency/aggregatetask/ComponentAggregateTaskImplTest.java @@ -17,6 +17,7 @@ import io.openems.common.session.Language; import io.openems.common.types.EdgeConfig; import io.openems.common.utils.JsonUtils; +import io.openems.edge.common.test.DummyConfigurationAdmin; import io.openems.edge.core.appmanager.AppConfiguration; import io.openems.edge.core.appmanager.DummyPseudoComponentManager; import io.openems.edge.core.appmanager.TranslationUtil; @@ -30,6 +31,7 @@ public class ComponentAggregateTaskImplTest { @Before public void setUp() throws Exception { this.componentManager = new DummyPseudoComponentManager(); + this.componentManager.setConfigurationAdmin(new DummyConfigurationAdmin()); this.task = new ComponentAggregateTaskImpl(this.componentManager); this.task.reset(); } diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/dependency/aggregatetask/PersistencePredictorAggregateTaskImplTest.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/dependency/aggregatetask/PersistencePredictorAggregateTaskImplTest.java index 05ec348ff7f..abd53f85834 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/dependency/aggregatetask/PersistencePredictorAggregateTaskImplTest.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/dependency/aggregatetask/PersistencePredictorAggregateTaskImplTest.java @@ -21,6 +21,7 @@ import io.openems.common.session.Language; import io.openems.common.types.EdgeConfig; import io.openems.common.utils.JsonUtils; +import io.openems.edge.common.test.DummyConfigurationAdmin; import io.openems.edge.core.appmanager.AppConfiguration; import io.openems.edge.core.appmanager.DummyPseudoComponentManager; import io.openems.edge.core.appmanager.TranslationUtil; @@ -34,6 +35,7 @@ public class PersistencePredictorAggregateTaskImplTest { @Before public void setUp() throws Exception { this.componentManager = new DummyPseudoComponentManager(); + this.componentManager.setConfigurationAdmin(new DummyConfigurationAdmin()); this.task = new PersistencePredictorAggregateTaskImpl(this.componentManager); this.task.reset(); } diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/dependency/aggregatetask/SchedulerByCentralOrderAggregateTaskImplTest.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/dependency/aggregatetask/SchedulerByCentralOrderAggregateTaskImplTest.java index b692317f4bf..d98e708f505 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/dependency/aggregatetask/SchedulerByCentralOrderAggregateTaskImplTest.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/dependency/aggregatetask/SchedulerByCentralOrderAggregateTaskImplTest.java @@ -274,7 +274,7 @@ public void testGetGeneralFailMessage() { @Test public void testValidate() throws Exception { this.testBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, - new AddAppInstance.Request("appId", "key", "alias", JsonUtils.buildJsonObject().build())).get(); + new AddAppInstance.Request("appId", "key", "alias", JsonUtils.buildJsonObject().build())); final var schedulerConfig = new SchedulerByCentralOrderConfiguration(// new SchedulerComponent("id0", "factoryId", "appId") // @@ -292,7 +292,7 @@ public void testValidate() throws Exception { @Test public void testValidateMissingIds() throws Exception { this.testBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, - new AddAppInstance.Request("appId", "key", "alias", JsonUtils.buildJsonObject().build())).get(); + new AddAppInstance.Request("appId", "key", "alias", JsonUtils.buildJsonObject().build())); // remove ids from scheduler this.testBundle.scheduler.setSchedulerIds(DUMMY_ADMIN); @@ -313,11 +313,9 @@ public void testValidateMissingIds() throws Exception { @Test public void testValidateWronglyConfiguredIds() throws Exception { this.testBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, - new AddAppInstance.Request("appId", "key", "alias", JsonUtils.buildJsonObject().build())).get(); - this.testBundle.sut - .handleAddAppInstanceRequest(DUMMY_ADMIN, - new AddAppInstance.Request("appId2", "key", "alias", JsonUtils.buildJsonObject().build())) - .get(); + new AddAppInstance.Request("appId", "key", "alias", JsonUtils.buildJsonObject().build())); + this.testBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, + new AddAppInstance.Request("appId2", "key", "alias", JsonUtils.buildJsonObject().build())); this.testBundle.scheduler.setSchedulerIds(DUMMY_ADMIN, "id1", "id0"); diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/dependency/aggregatetask/TestScheduler.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/dependency/aggregatetask/TestScheduler.java index 8ce40d13df9..05708d430bd 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/dependency/aggregatetask/TestScheduler.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/dependency/aggregatetask/TestScheduler.java @@ -81,13 +81,13 @@ public void setSchedulerIds(User user, List ids) this.setSchedulerIds(user, ids.toArray(String[]::new)); } - public void setSchedulerIds(User user, String... ids) - throws OpenemsNamedException, InterruptedException, ExecutionException { - this.componentManager.handleJsonrpcRequest(user, new UpdateComponentConfigRequest("scheduler0", List.of(// - new UpdateComponentConfigRequest.Property("controllers.ids", Arrays.stream(ids) // - .map(JsonPrimitive::new) // - .collect(toJsonArray())) // - ))).get(); + public void setSchedulerIds(User user, String... ids) throws OpenemsNamedException { + this.componentManager.handleUpdateComponentConfigRequest(user, + new UpdateComponentConfigRequest("scheduler0", List.of(// + new UpdateComponentConfigRequest.Property("controllers.ids", Arrays.stream(ids) // + .map(JsonPrimitive::new) // + .collect(toJsonArray())) // + ))); } } diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/validator/CheckHomeTest.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/validator/CheckHomeTest.java index 578d5281b31..6174b2d811d 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/validator/CheckHomeTest.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/validator/CheckHomeTest.java @@ -47,12 +47,10 @@ public void testCheck() { @Test public void testCheckWithInstalledHome10() throws Exception { - final var response = this.appManagerTestBundle.sut - .handleAddAppInstanceRequest(DUMMY_ADMIN, - new AddAppInstance.Request("App.FENECON.Home", "key", "alias", TestFeneconHome.fullSettings())) - .get(); + final var response = this.appManagerTestBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, + new AddAppInstance.Request("App.FENECON.Home", "key", "alias", TestFeneconHome.fullSettings())); - assertTrue(response.warnings.isEmpty()); + assertTrue(response.warnings().isEmpty()); assertTrue(this.checkHome.check()); assertTrue(PropsUtil.isHomeInstalled(this.appManagerTestBundle.appManagerUtil)); } @@ -60,10 +58,9 @@ public void testCheckWithInstalledHome10() throws Exception { @Test public void testCheckWithInstalledHome20() throws Exception { final var response = this.appManagerTestBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, - new AddAppInstance.Request("App.FENECON.Home.20", "key", "alias", TestFeneconHome20.fullSettings())) - .get(); + new AddAppInstance.Request("App.FENECON.Home.20", "key", "alias", TestFeneconHome20.fullSettings())); - assertTrue(response.warnings.isEmpty()); + assertTrue(response.warnings().isEmpty()); assertTrue(this.checkHome.check()); assertTrue(PropsUtil.isHomeInstalled(this.appManagerTestBundle.appManagerUtil)); } @@ -71,10 +68,9 @@ public void testCheckWithInstalledHome20() throws Exception { @Test public void testCheckWithInstalledHome30() throws Exception { final var response = this.appManagerTestBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, - new AddAppInstance.Request("App.FENECON.Home.30", "key", "alias", TestFeneconHome30.fullSettings())) - .get(); + new AddAppInstance.Request("App.FENECON.Home.30", "key", "alias", TestFeneconHome30.fullSettings())); - assertTrue(response.warnings.isEmpty()); + assertTrue(response.warnings().isEmpty()); assertTrue(this.checkHome.check()); assertTrue(PropsUtil.isHomeInstalled(this.appManagerTestBundle.appManagerUtil)); } diff --git a/io.openems.edge.meter.discovergy/src/io/openems/edge/meter/discovergy/MeterDiscovergy.java b/io.openems.edge.meter.discovergy/src/io/openems/edge/meter/discovergy/MeterDiscovergy.java index f99a6062584..80874dbc5e7 100644 --- a/io.openems.edge.meter.discovergy/src/io/openems/edge/meter/discovergy/MeterDiscovergy.java +++ b/io.openems.edge.meter.discovergy/src/io/openems/edge/meter/discovergy/MeterDiscovergy.java @@ -6,10 +6,9 @@ import io.openems.common.types.OpenemsType; import io.openems.edge.common.channel.Doc; import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.common.jsonapi.JsonApi; import io.openems.edge.meter.api.ElectricityMeter; -public interface MeterDiscovergy extends ElectricityMeter, OpenemsComponent, EventHandler, JsonApi { +public interface MeterDiscovergy extends ElectricityMeter, OpenemsComponent, EventHandler { public enum ChannelId implements io.openems.edge.common.channel.ChannelId { /* diff --git a/io.openems.edge.meter.discovergy/src/io/openems/edge/meter/discovergy/MeterDiscovergyImpl.java b/io.openems.edge.meter.discovergy/src/io/openems/edge/meter/discovergy/MeterDiscovergyImpl.java index 007eb33ca9b..24884b6d2d6 100644 --- a/io.openems.edge.meter.discovergy/src/io/openems/edge/meter/discovergy/MeterDiscovergyImpl.java +++ b/io.openems.edge.meter.discovergy/src/io/openems/edge/meter/discovergy/MeterDiscovergyImpl.java @@ -2,7 +2,6 @@ import java.util.HashSet; import java.util.Set; -import java.util.concurrent.CompletableFuture; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.annotations.Activate; @@ -17,16 +16,14 @@ import com.google.gson.JsonElement; -import io.openems.common.exceptions.OpenemsError; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.jsonrpc.base.JsonrpcRequest; -import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; -import io.openems.common.session.Role; import io.openems.common.utils.JsonUtils; import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.event.EdgeEventConstants; -import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.ComponentJsonApi; +import io.openems.edge.common.jsonapi.EdgeKeys; +import io.openems.edge.common.jsonapi.JsonApiBuilder; import io.openems.edge.common.user.User; import io.openems.edge.meter.api.ElectricityMeter; import io.openems.edge.meter.api.MeterType; @@ -46,7 +43,7 @@ EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE // }) public class MeterDiscovergyImpl extends AbstractOpenemsComponent - implements MeterDiscovergy, ElectricityMeter, OpenemsComponent, EventHandler, JsonApi { + implements MeterDiscovergy, ElectricityMeter, OpenemsComponent, EventHandler, ComponentJsonApi { private MeterType meterType = MeterType.PRODUCTION; private DiscovergyApiClient apiClient = null; @@ -118,21 +115,20 @@ protected void logError(Logger log, String message) { } @Override - public CompletableFuture handleJsonrpcRequest(User user, JsonrpcRequest request) - throws OpenemsNamedException { - user.assertRoleIsAtLeast("handleJsonrpcRequest", Role.GUEST); - - switch (request.getMethod()) { - - case GetMetersRequest.METHOD: - return this.handleGetMetersRequest(user, GetMetersRequest.from(request)); - - case GetFieldNamesRequest.METHOD: - return this.handleGetFieldNamesRequest(user, GetFieldNamesRequest.from(request)); - - default: - throw OpenemsError.JSONRPC_UNHANDLED_METHOD.exception(request.getMethod()); - } + public void buildJsonApiRoutes(JsonApiBuilder builder) { + builder.handleRequest(GetMetersRequest.METHOD, call -> { + return this.handleGetMetersRequest(// + call.get(EdgeKeys.USER_KEY), // + GetMetersRequest.from(call.getRequest()) // + ); + }); + + builder.handleRequest(GetFieldNamesRequest.METHOD, call -> { + return this.handleGetFieldNamesRequest(// + call.get(EdgeKeys.USER_KEY), // + GetFieldNamesRequest.from(call.getRequest()) // + ); + }); } /** @@ -143,14 +139,12 @@ public CompletableFuture handleJsonrpcRequest( * * @param user the User * @param request the GetMetersRequest - * @return the Future JSON-RPC Response + * @return the Response * @throws OpenemsNamedException on error */ - private CompletableFuture handleGetMetersRequest(User user, GetMetersRequest request) - throws OpenemsNamedException { + private GetMetersResponse handleGetMetersRequest(User user, GetMetersRequest request) throws OpenemsNamedException { var meters = this.apiClient.getMeters(); - var response = new GetMetersResponse(request.getId(), meters); - return CompletableFuture.completedFuture(response); + return new GetMetersResponse(request.getId(), meters); } /** @@ -161,17 +155,16 @@ private CompletableFuture handleGetMetersRequest(User us * * @param user the User * @param request the GetFieldNamesRequest - * @return the Future JSON-RPC Response + * @return the Response * @throws OpenemsNamedException on error */ - private CompletableFuture handleGetFieldNamesRequest(User user, - GetFieldNamesRequest request) throws OpenemsNamedException { + private GetFieldNamesResponse handleGetFieldNamesRequest(User user, GetFieldNamesRequest request) + throws OpenemsNamedException { var fieldNames = this.apiClient.getFieldNames(request.getMeterId()); Set fields = new HashSet<>(); for (JsonElement fieldNameElement : fieldNames) { fields.add(JsonUtils.getAsEnum(Field.class, fieldNameElement)); } - var response = new GetFieldNamesResponse(request.getId(), fields); - return CompletableFuture.completedFuture(response); + return new GetFieldNamesResponse(request.getId(), fields); } } diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/app/SimulatorApp.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/app/SimulatorApp.java index 6fbdd0d0d75..d3cbdc6051d 100644 --- a/io.openems.edge.simulator/src/io/openems/edge/simulator/app/SimulatorApp.java +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/app/SimulatorApp.java @@ -5,12 +5,10 @@ import io.openems.edge.common.channel.Doc; import io.openems.edge.common.component.ClockProvider; import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.common.jsonapi.JsonApi; import io.openems.edge.simulator.datasource.api.SimulatorDatasource; import io.openems.edge.timedata.api.Timedata; -public interface SimulatorApp - extends SimulatorDatasource, ClockProvider, OpenemsComponent, JsonApi, EventHandler, Timedata { +public interface SimulatorApp extends SimulatorDatasource, ClockProvider, OpenemsComponent, EventHandler, Timedata { public enum ChannelId implements io.openems.edge.common.channel.ChannelId { ; diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/app/SimulatorAppImpl.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/app/SimulatorAppImpl.java index ca6c1215434..8236fb6fa7b 100644 --- a/io.openems.edge.simulator/src/io/openems/edge/simulator/app/SimulatorAppImpl.java +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/app/SimulatorAppImpl.java @@ -39,11 +39,8 @@ import com.google.gson.JsonPrimitive; import io.openems.common.exceptions.NotImplementedException; -import io.openems.common.exceptions.OpenemsError; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; -import io.openems.common.jsonrpc.base.JsonrpcRequest; -import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; import io.openems.common.jsonrpc.request.CreateComponentConfigRequest; import io.openems.common.jsonrpc.request.DeleteComponentConfigRequest; import io.openems.common.jsonrpc.request.UpdateComponentConfigRequest.Property; @@ -61,7 +58,10 @@ import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.cycle.Cycle; import io.openems.edge.common.event.EdgeEventConstants; -import io.openems.edge.common.jsonapi.JsonApi; +import io.openems.edge.common.jsonapi.ComponentJsonApi; +import io.openems.edge.common.jsonapi.EdgeGuards; +import io.openems.edge.common.jsonapi.EdgeKeys; +import io.openems.edge.common.jsonapi.JsonApiBuilder; import io.openems.edge.common.type.TypeUtils; import io.openems.edge.common.user.User; import io.openems.edge.simulator.app.ExecuteSimulationRequest.Profile; @@ -79,8 +79,8 @@ EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE, // EdgeEventConstants.TOPIC_CYCLE_AFTER_WRITE // }) -public class SimulatorAppImpl extends AbstractOpenemsComponent - implements SimulatorApp, SimulatorDatasource, ClockProvider, OpenemsComponent, JsonApi, EventHandler, Timedata { +public class SimulatorAppImpl extends AbstractOpenemsComponent implements SimulatorApp, SimulatorDatasource, + ClockProvider, OpenemsComponent, EventHandler, Timedata, ComponentJsonApi { public static final String SINGLETON_SERVICE_PID = "Simulator.App"; public static final String SINGLETON_COMPONENT_ID = "_simulator"; @@ -157,18 +157,11 @@ protected void deactivate() { } @Override - public CompletableFuture handleJsonrpcRequest(User user, JsonrpcRequest request) - throws OpenemsNamedException { - user.assertRoleIsAtLeast("handleJsonrpcRequest", Role.ADMIN); - - switch (request.getMethod()) { - - case ExecuteSimulationRequest.METHOD: - return this.handleExecuteSimulationRequest(user, ExecuteSimulationRequest.from(request)); - - default: - throw OpenemsError.JSONRPC_UNHANDLED_METHOD.exception(request.getMethod()); - } + public void buildJsonApiRoutes(JsonApiBuilder builder) { + builder.handleRequest(ExecuteSimulationRequest.METHOD, def -> { + def.setGuards(EdgeGuards.roleIsAtleast(Role.ADMIN)); + }, call -> this.handleExecuteSimulationRequest(call.get(EdgeKeys.USER_KEY), + ExecuteSimulationRequest.from(call.getRequest())).get()); } /** @@ -189,7 +182,7 @@ private synchronized CompletableFuture handleExecuteS this.setCycleTime(AbstractWorker.ALWAYS_WAIT_FOR_TRIGGER_NEXT_RUN); // Create Ess.Power with disabled PID filter - this.componentManager.handleJsonrpcRequest(user, + this.componentManager.handleCreateComponentConfigRequest(user, new CreateComponentConfigRequest("Ess.Power", Arrays.asList(new Property("enablePid", false)))); // Create Components @@ -198,7 +191,7 @@ private synchronized CompletableFuture handleExecuteS this.logInfo(this.log, "Create Component [" + createRequest.getComponentId() + "] from [" + createRequest.getFactoryPid() + "]"); simulatorComponentIds.add(createRequest.getComponentId()); - this.componentManager.handleJsonrpcRequest(user, createRequest); + this.componentManager.handleCreateComponentConfigRequest(user, createRequest); } this.waitForComponentsToActivate(simulatorComponentIds); @@ -389,7 +382,7 @@ private void stopSimulation() { private void deleteComponent(User user, String componentId) throws OpenemsNamedException { this.logInfo(this.log, "Delete Component [" + componentId + "]"); var deleteComponentConfigRequest = new DeleteComponentConfigRequest(componentId); - this.componentManager.handleJsonrpcRequest(user, deleteComponentConfigRequest); + this.componentManager.handleDeleteComponentConfigRequest(user, deleteComponentConfigRequest); } /** diff --git a/ui/src/app/app-routing.module.ts b/ui/src/app/app-routing.module.ts index dfc0e25f4e5..e1f9f03e9b3 100644 --- a/ui/src/app/app-routing.module.ts +++ b/ui/src/app/app-routing.module.ts @@ -36,6 +36,7 @@ import { IndexComponent as EdgeSettingsComponentInstallIndexComponentComponent } import { ComponentInstallComponent as EdgeSettingsComponentInstallComponentComponent } from './edge/settings/component/install/install.component'; import { IndexComponent as EdgeSettingsComponentUpdateIndexComponentComponent } from './edge/settings/component/update/index.component'; import { ComponentUpdateComponent as EdgeSettingsComponentUpdateComponentComponent } from './edge/settings/component/update/update.component'; +import { JsonrpcTestComponent } from './edge/settings/jsonrpctest/jsonrpctest'; import { NetworkComponent as EdgeSettingsNetworkComponent } from './edge/settings/network/network.component'; import { AliasUpdateComponent } from './edge/settings/profile/aliasupdate.component'; import { ProfileComponent as EdgeSettingsProfileComponent } from './edge/settings/profile/profile.component'; @@ -116,6 +117,7 @@ const routes: Routes = [ { path: 'settings/app/update/:appId', component: EdgeSettingsAppUpdate }, { path: 'settings/app/single/:appId', component: EdgeSettingsAppSingle }, { path: 'settings/alerting', component: EdgeSettingsAlerting }, + { path: 'settings/jsonrpctest', component: JsonrpcTestComponent }, ], }, diff --git a/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.html b/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.html new file mode 100644 index 00000000000..d10ae978751 --- /dev/null +++ b/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.html @@ -0,0 +1,191 @@ + + + + + + { +
+
+ + +   + + "{{item.key}}": + , +
+ + +   + + } + + + string + + + + [] + + +
+ +

+ + + + + + + + + + + + {{parent.method}} ➔ + + {{ endpoint.method }} + + {{tag.name}} + + + + + + + +
+
+
+
+ + + {{guard.name}} {{guard.description}} + + + + +
+ Request +
+ + +
+ +
+ Response +
+ + +
+
+ + + Examples + + + + + + {{example.key}} + + + +
+
+
{{example.value | json}}
+
+
+
+ + + + + {{example.key}} + + + +
+
+
{{example.value | json}}
+
+
+
+
+ + + + Try + now! + + + +
+ + Request + + + + + + Raw + + + Form + + + + + + +
+ + + +
+
+ Form +
+
+
+ + + + + Run! + + + + + + Response + + + + +
{{endpoint.fetch?.response}}
+
+
+
+
+
+
+
+ +
+
+
+
+
diff --git a/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.ts b/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.ts new file mode 100644 index 00000000000..9fe0119358c --- /dev/null +++ b/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.ts @@ -0,0 +1,187 @@ +import { Component, OnInit } from '@angular/core'; +import { FormGroup } from '@angular/forms'; +import { ActivatedRoute } from '@angular/router'; +import { JsonrpcRequest } from 'src/app/shared/jsonrpc/base'; +import { Edge, Service, Websocket } from 'src/app/shared/shared'; +import { environment } from 'src/environments'; + +@Component({ + selector: JsonrpcTestComponent.SELECTOR, + templateUrl: './jsonrpctest.html', +}) +export class JsonrpcTestComponent implements OnInit { + + private static readonly SELECTOR = "jsonrpcTest"; + + private edge: Edge | undefined; + protected endpoints: Endpoint[] = []; + + constructor( + private route: ActivatedRoute, + private service: Service, + private websocket: Websocket, + ) { + + } + + public ngOnInit(): void { + this.service.setCurrentComponent('Jsonrpc Test', this.route).then(edge => { + this.edge = edge; + edge.sendRequest(this.websocket, new JsonrpcRequest("routes", {})).then(response => { + this.endpoints = (response.result['endpoints'] as EndpointResponse[]).map(endpoint => { + return { + method: endpoint.method, + description: endpoint.description ? endpoint.description.replace('\n', '
') : null, + tags: endpoint.tags, + guards: endpoint.guards, + request: endpoint.request, // JSON.stringify(endpoint.request.json, null, 2), + response: endpoint.response, + parent: endpoint.parent, + requestMethod: 'raw', + form: new FormGroup({}), + model: {}, + modelRaw: JSON.stringify(createDummyRequest(endpoint.request.json), null, 2), + }; + }); + }); + }).catch(e => { + this.service.toast(e, 'danger'); + }); + } + + protected request(endpoint: Endpoint): void { + console.log("Run!", endpoint); + if (!endpoint.fetch) { + endpoint.fetch = {}; + } + endpoint.fetch.loading = true; + this.service.startSpinnerTransparentBackground(endpoint.method); + + let request: JsonrpcRequest = new JsonrpcRequest( + endpoint.method, + endpoint.modelRaw ? JSON.parse(endpoint.modelRaw) : {}, + ); + for (let i = endpoint.parent.length - 1; i >= 0; i--) { + const parent = endpoint.parent[i]; + if (environment.backend === 'OpenEMS Backend') { + if (parent.method === 'authenticatedRpc') { + break; + } + } + + const lastRequest = request; + request = new JsonrpcRequest( + parent.method, { + ...parent.request.base, + }, + ); + const lastObj = request.params; + for (let j = 0; j < parent.request.pathToSubrequest.length; j++) { + const path = parent.request.pathToSubrequest[j]; + if (j === parent.request.pathToSubrequest.length - 1) { + lastObj[path] = lastRequest; + } else { + lastObj[path] = {}; + } + } + } + + + (environment.backend === 'OpenEMS Edge' + ? this.websocket.sendRequest(request) + : this.edge.sendRequest(this.websocket, request)) + .then(response => { + endpoint.fetch.response = JSON.stringify(response, null, 2); + }).catch(error => { + endpoint.fetch.response = JSON.stringify(error, null, 2); + }).finally(() => { + endpoint.fetch.loading = false; + this.service.stopSpinner(endpoint.method); + }); + } + +} + +function createDummyRequest(endpointType?: EndpointType) { + if (!endpointType) { + return undefined; + } + switch (endpointType.type) { + case 'object': { + const obj = {}; + for (const [key, value] of Object.entries(endpointType.properties)) { + obj[key] = createDummyRequest(value); + } + return obj; + } + case 'string': { + return 'string'; + } + } +} + +type EndpointResponse = { + method: string, + description: string, + tags: Tag[], + guards: Guard[], + request: { + json: EndpointType, + examples: RequestExample[] + }, + response: { + json: EndpointType, + examples: RequestExample[] + }, + parent: { method: string, request: { base: any, pathToSubrequest: string[] } }[], +} + +type Tag = { + name: string +} + +type Guard = { + name: string, + description: string +} + +type RequestExample = { + key: string, + value: {} +} + +type EndpointType = + { + type: 'object', + properties: { [key: string]: EndpointType } + } + | { + type: 'string', + constraints: string[] + } + +type Endpoint = { + method: string, + description: string, + tags: Tag[], + guards: Guard[], + request: { + json: EndpointType, + examples: RequestExample[], + selectedExample?: string, + }, + response: { + json: EndpointType, + examples: RequestExample[], + }, + parent: { method: string, request: { base: any, pathToSubrequest: string[] } }[], + tryRequest?: boolean, + requestMethod: string, + form: FormGroup; + model: any; + modelRaw: string; + fetch?: { + loading?: boolean, + response?: string; + } +} diff --git a/ui/src/app/edge/settings/jsonrpctest/permission.ts b/ui/src/app/edge/settings/jsonrpctest/permission.ts new file mode 100644 index 00000000000..38b82cf42eb --- /dev/null +++ b/ui/src/app/edge/settings/jsonrpctest/permission.ts @@ -0,0 +1,7 @@ +import { Edge } from "src/app/shared/edge/edge"; +import { User } from "src/app/shared/jsonrpc/shared"; + +export function canSeeJsonrpcTest(user: User, edge: Edge): boolean { + // TODO check for certain users + return true; +} diff --git a/ui/src/app/edge/settings/settings.component.html b/ui/src/app/edge/settings/settings.component.html index 51c5353aaec..dcc60d91df9 100644 --- a/ui/src/app/edge/settings/settings.component.html +++ b/ui/src/app/edge/settings/settings.component.html @@ -88,6 +88,20 @@ + + + + + + Jsonrpc test + + + + + + + + diff --git a/ui/src/app/edge/settings/settings.component.ts b/ui/src/app/edge/settings/settings.component.ts index 5076ca530a8..5f5d0ac7d90 100644 --- a/ui/src/app/edge/settings/settings.component.ts +++ b/ui/src/app/edge/settings/settings.component.ts @@ -3,6 +3,7 @@ import { ActivatedRoute } from '@angular/router'; import { environment } from 'src/environments'; import { Edge, Service, Utils } from '../../shared/shared'; import { canSeeAppCenter } from './app/permissions'; +import { canSeeJsonrpcTest } from './jsonrpctest/permission'; @Component({ selector: 'settings', @@ -14,6 +15,8 @@ export class SettingsComponent implements OnInit { public environment = environment; public canSeeAppCenter: boolean | undefined; + public canSeeJsonrpcTest: boolean | undefined; + protected isEdgeBackend: boolean = environment.backend === 'OpenEMS Edge'; constructor( @@ -26,7 +29,9 @@ export class SettingsComponent implements OnInit { public ngOnInit() { this.service.getCurrentEdge().then(edge => { this.edge = edge; + const user = this.service.metadata?.value?.user; this.canSeeAppCenter = canSeeAppCenter(this.edge); + this.canSeeJsonrpcTest = canSeeJsonrpcTest(user, edge); }); } } diff --git a/ui/src/app/edge/settings/settings.module.ts b/ui/src/app/edge/settings/settings.module.ts index 4c5b3920c50..05f8222e512 100644 --- a/ui/src/app/edge/settings/settings.module.ts +++ b/ui/src/app/edge/settings/settings.module.ts @@ -9,6 +9,7 @@ import { IndexComponent as ComponentInstallIndexComponent } from './component/in import { ComponentInstallComponent } from './component/install/install.component'; import { IndexComponent as ComponentUpdateIndexComponent } from './component/update/index.component'; import { ComponentUpdateComponent } from './component/update/update.component'; +import { JsonrpcTestComponent } from './jsonrpctest/jsonrpctest'; import { NetworkComponent } from './network/network.component'; import { AliasUpdateComponent } from './profile/aliasupdate.component'; import { ProfileComponent } from './profile/profile.component'; @@ -32,6 +33,7 @@ import { SystemExecuteComponent } from './systemexecute/systemexecute.component' ComponentInstallIndexComponent, ComponentUpdateComponent, ComponentUpdateIndexComponent, + JsonrpcTestComponent, MaintenanceComponent, NetworkComponent, OeSystemUpdateComponent, From 6bb25c77d7c3db47e88e5998eac647346c6dd2a6 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Mon, 29 Apr 2024 10:54:09 +0200 Subject: [PATCH 005/173] FEMS Backports 2023-04 (#2623) - Backend - Add API for Simulation-Engine Component - In future this should be used for scenario simulations, like what would have been the benefit of using an additional battery module - Common - Change Unit `EUROS_PER_MEGAWATT_HOUR` to `MONEY_PER_MEGAWATT_HOUR` - Prepare-commit: add UI build+test to script - "Coding Guidelines" should also cover UI development (https://openems.github.io/openems.io/openems/latest/contribute/coding-guidelines.html#_openems_edge_backend) - CI: Update node to v20 LTS - Edge - Modbus-Bridge: - Improve SunSpec handling for SMA PV-Inverter: certain versions do not provide END_OF_MAP but throw ILLEGAL_ADDRESS_EXCEPTION instead, causing the previous SunSpec implementation to get stuck while parsing - Remove unnecessary `throws OpenemsException` and `try...catch` in certain places (`defineModbusProtocol()`, `new ModbusProtocol()`, `addTask()`,...) - Optionally provide `ExecuteState` of an entire ModbusTask; this allows for more fine-grained evaluation of read errors - Switch to updated `readElementOnce` and/or improve brevity of `CompletableFuture` by using `thenCompose` instead of `thenAccept` in... - RRD4j: correctly postprocess queried data - fix querying data with different resolution than 5 Minutes - Time-of-Use: split Optimizer and Controller - Introduce new Bundles for `Energy` and `Energy API` - Time-of-Use-Controller and EnergyScheduler are still tightly coupled for now, as this is an ongoing refactoring. Eventually they should only communicate via `EnergySchedulable` - Move Optimizer (i.e. all Jenetics related code) to `Energy` - New Channel `_sum/GridBuyPrice` - UI: show data in [kW] and cleanup code - Tibber: Homes-Filter could not be unset - KACO Blueplanet Gridsave BatteryInverter: state-machine improvement - Update Kaco Blueplanet Gridsave state-machine - Add grid disconnection failure state channel - Replace `MAX_START_ATTEMPTS` with `MAX_START_TIMEOUT` - GoodWe - Optionally show values per MPPT; not per String - GoodWeChargerTwoStringImpl was used to represent one string from a GoodWe MPPT tracker that is responsible for two strings (GoodWe ET-Systems). - Possible values given by GoodWe are: MPPT Current, MPPT Power, String Current, String Voltage - As the current values of one string are incorrect (so far DSP-Version 12, ARM-Version 27) the power cannot be calculated as expected. - A new Component GoodWeChargerMpptTwoStringImpl is mirroring the GoodWe values to get the important values from: MPPT Current, MPPT Power, String Voltage (One of the two strings) - Update BMS Registers ChargeMaxVoltage & DischargeMinVoltage - Set ChargeMaxVoltage & DischargeMinVoltage - Handle inverter specific behaviour on empty/full battery - UI - Add optional strict mode - Another step towards *strict mode* in UI - Add `typescript-strict-plugin` -> https://github.com/allegro/typescript-strict-plugin - Add `tsc` and `tsc-strict` to CI build - Add `// @ts-strict-ignore` comment in non-compliant code files - Update to Angular Version 16. - Replacing [kekeh/angular-mydatepicker](https://github.com/kekeh/angular-mydatepicker) with its fork [nodro7/angular-mydatepicker](https://github.com/nodro7/angular-mydatepicker) - Revert calculating stepSize for charts - Removing stepSize calculation due to chartjs breaking style in some circumstances - keeping max ticks limit at 6 - Change resolution from 20 to 15 minutes - Remove dead link from ChpSoc (BHKW) Widget in history - Settings|Channels: fix Persistence Priority warning - Warning for persistencePriority lower than backends global priority, was also shown for equals - Hide FooterComponent for [history Children](https://git.intranet.fenecon.de/FENECON/fems/src/commit/9d4006ba912bf7653c300321aec56b10ced2faec/ui/src/app/app-routing.module.ts#L87) due to overlapping on different heights - [Footercomponent overlapping content](https://forum.ionicframework.com/t/ion-footer-overlap-content/109487/6). - [Chartjs -> responsive charts](https://www.chartjs.org/docs/latest/configuration/responsive.html#important-note) approach of setting fixed height is causing the problem, `onZoom` event doesnt resize the charts canvas and chart canvas gets moved down into the footer - Footer: fix esLint autofix mistake; hide for history detail views - Revert adding detail navigation to production history (this is a planned feature that was accidentially merged) - Fix Page count of edges pagination on initial search --- .github/workflows/build.yml | 2 +- .github/workflows/release.yml | 2 +- .../common/jsonrpc/SimulationEngine.java | 24 + .../jsonrpc/request/SimulationRequest.java | 68 + .../backend/uiwebsocket/impl/OnRequest.java | 23 + .../uiwebsocket/impl/UiWebsocketImpl.java | 6 + .../src/io/openems/common/channel/Unit.java | 7 +- io.openems.edge.application/EdgeApp.bndrun | 3 + .../edge/battery/bmw/BmwBatteryImpl.java | 5 +- .../BydBatteryBoxCommercialC130Impl.java | 65 +- .../BatteryFeneconCommercialImpl.java | 2 +- .../fenecon/home/BatteryFeneconHomeImpl.java | 5 +- .../BatterySoltaroClusterVersionBImpl.java | 2 +- .../BatterySoltaroClusterVersionCImpl.java | 459 +- .../BatterySoltaroSingleRackVersionAImpl.java | 2 +- .../BatterySoltaroSingleRackVersionBImpl.java | 78 +- .../BatterySoltaroSingleRackVersionCImpl.java | 29 +- .../doc/statemachine.md | 32 +- ...BatteryInverterKacoBlueplanetGridsave.java | 143 +- ...eryInverterKacoBlueplanetGridsaveImpl.java | 116 +- .../blueplanetgridsave/KacoSunSpecModel.java | 4 +- .../statemachine/Context.java | 18 +- .../statemachine/ErrorHandler.java | 45 +- .../statemachine/GoRunningHandler.java | 69 +- .../statemachine/GoStoppedHandler.java | 64 +- .../statemachine/RunningHandler.java | 34 +- .../statemachine/StateMachine.java | 23 +- .../statemachine/StoppedHandler.java | 14 +- .../statemachine/UndefinedHandler.java | 34 +- ...nverterKacoBlueplanetGridsaveImplTest.java | 3 +- .../BatteryInverterRefuStore88kImpl.java | 2 +- .../sinexcel/BatteryInverterSinexcelImpl.java | 2 +- .../AbstractSunSpecBatteryInverter.java | 2 +- .../api/AbstractOpenemsModbusComponent.java | 4 +- .../bridge/modbus/api/ModbusProtocol.java | 10 +- .../edge/bridge/modbus/api/ModbusUtils.java | 205 +- .../task/AbstractReadDigitalInputsTask.java | 7 +- .../api/task/AbstractReadRegistersTask.java | 7 +- .../modbus/api/task/AbstractReadTask.java | 20 +- .../bridge/modbus/api/task/AbstractTask.java | 8 +- .../modbus/api/task/AbstractWriteTask.java | 22 +- .../api/task/FC16WriteRegistersTask.java | 23 +- .../modbus/api/task/FC1ReadCoilsTask.java | 10 +- .../modbus/api/task/FC2ReadInputsTask.java | 10 +- .../modbus/api/task/FC3ReadRegistersTask.java | 11 +- .../api/task/FC4ReadInputRegistersTask.java | 9 +- .../modbus/api/task/FC5WriteCoilTask.java | 9 +- .../modbus/api/task/FC6WriteRegisterTask.java | 10 +- .../edge/bridge/modbus/api/task/Task.java | 23 +- .../modbus/api/worker/ModbusWorker.java | 16 +- .../AbstractOpenemsSunSpecComponent.java | 157 +- .../bridge/modbus/test/DummyModbusBridge.java | 10 +- .../modbus/BridgeModbusTcpImplTest.java | 7 +- .../bridge/modbus/DummyModbusComponent.java | 4 +- .../edge/bridge/modbus/MyConfigTcp.java | 2 +- .../bridge/modbus/api/ConversionTest.java | 19 - .../bridge/modbus/api/ModbusUtilsTest.java | 47 + .../modbus/api/worker/AbstractDummyTask.java | 40 +- .../modbus/api/worker/DummyReadTask.java | 2 +- .../modbus/api/worker/DummyWriteTask.java | 2 +- .../AbstractOpenemsSunSpecComponentTest.java | 141 +- .../modbus/sunspec/DummySunSpecComponent.java | 11 +- .../bridge/modbus/sunspec/dummy/Config.java | 19 + .../bridge/modbus/sunspec/dummy/MyConfig.java | 90 + .../sunspec/dummy/MySunSpecComponentImpl.java | 77 + .../channel/calculate/CalculateAverage.java | 13 +- .../src/io/openems/edge/common/sum/Sum.java | 43 + .../io/openems/edge/common/type/Tuple.java | 14 + .../bnd.bnd | 3 +- .../TimeOfUseTariffController.java | 2 +- .../TimeOfUseTariffControllerImpl.java | 203 +- .../controller/ess/timeofusetariff/Utils.java | 247 + .../jsonrpc/GetScheduleResponse.java | 55 - .../timeofusetariff/optimizer/Context.java | 172 - .../ess/timeofusetariff/package-info.java | 3 + .../TimeOfUseTariffControllerImplTest.java | 65 +- .../ess/timeofusetariff/UtilsTest.java | 215 + .../jsonrpc/ScheduleDatasTest.java | 134 - .../optimizer/OptimizerTest.java | 22 - .../timeofusetariff/optimizer/UtilsTest.java | 558 - io.openems.edge.core/bnd.bnd | 1 + .../app/integratedsystem/FeneconHome20.java | 67 +- .../app/integratedsystem/FeneconHome30.java | 68 +- .../FeneconHomeComponents.java | 27 +- .../edge/app/timeofusetariff/Tibber.java | 11 +- .../core/appmanager/translation_de.properties | 5 +- .../core/appmanager/translation_en.properties | 5 +- .../PredictorManagerImpl.java | 2 +- .../src/io/openems/edge/core/sum/SumImpl.java | 10 + .../edge/app/timeofusetariff/TestTibber.java | 32 + .../edge2edge/common/AbstractEdge2Edge.java | 202 +- .../edge/edge2edge/ess/Edge2EdgeEssImpl.java | 2 +- io.openems.edge.energy.api/.classpath | 12 + io.openems.edge.energy.api/.gitignore | 3 + io.openems.edge.energy.api/.project | 23 + .../org.eclipse.core.resources.prefs | 2 + io.openems.edge.energy.api/bnd.bnd | 15 + io.openems.edge.energy.api/readme.adoc | 5 + .../edge/energy/api/EnergySchedulable.java | 13 + .../energy/api/EnergyScheduleHandler.java | 76 + .../edge/energy/api/EnergyScheduler.java | 29 + .../openems/edge/energy/api/package-info.java | 3 + io.openems.edge.energy.api/test/.gitignore | 0 io.openems.edge.energy/.classpath | 12 + io.openems.edge.energy/.gitignore | 3 + io.openems.edge.energy/.project | 23 + .../org.eclipse.core.resources.prefs | 2 + io.openems.edge.energy/bnd.bnd | 22 + io.openems.edge.energy/readme.adoc | 5 + .../src/io/openems/edge/energy/Config.java | 15 + .../edge/energy/EnergySchedulerImpl.java | 149 + .../energy}/jsonrpc/GetScheduleRequest.java | 2 +- .../energy/jsonrpc/GetScheduleResponse.java | 73 + .../edge/energy}/optimizer/EnergyFlow.java | 4 +- .../edge/energy/optimizer/GlobalContext.java | 103 + .../optimizer/InitialPopulationUtils.java | 8 +- .../edge/energy}/optimizer/Optimizer.java | 70 +- .../edge/energy}/optimizer/Params.java | 6 +- .../edge/energy}/optimizer/ParamsUtils.java | 10 +- .../edge/energy/optimizer}/ScheduleDatas.java | 112 +- .../edge/energy}/optimizer/Simulator.java | 24 +- .../openems/edge/energy}/optimizer/Utils.java | 285 +- io.openems.edge.energy/test/.gitignore | 0 .../edge/energy/EnergySchedulerImplTest.java | 126 + .../test/io/openems/edge/energy/MyConfig.java | 74 + .../io/openems/edge/energy}/TestData.java | 4 +- .../jsonrpc/GetScheduleResponseTest.java | 34 +- .../energy}/optimizer/EnergyFlowTest.java | 34 +- .../optimizer/InitialPopulationUtilsTest.java | 18 +- .../energy}/optimizer/IntegrationTests.java | 15 +- .../edge/energy/optimizer/OptimizerTest.java | 21 + .../energy}/optimizer/ParamsUtilsTest.java | 6 +- .../optimizer/RunOptimizerFromLogApp.java | 10 +- .../energy/optimizer/ScheduleDatasTest.java | 183 + .../edge/energy}/optimizer/SimulatorTest.java | 18 +- .../edge/energy/optimizer/UtilsTest.java | 337 + .../adstec/storaxe/EssAdstecStoraxeImpl.java | 2 +- .../container/EssFeneconBydContainerImpl.java | 6 +- .../EssFeneconCommercial40Impl.java | 2 +- .../AbstractEssFeneconCommercial40Pv.java | 3 +- .../edge/ess/mr/gridcon/GridconPcsImpl.java | 3 +- .../sunnyisland/EssSmaSunnyIslandImpl.java | 2 +- .../EvcsAlpitronicHyperchargerImpl.java | 2 +- .../smart/EvcsSpelsbergSmartImpl.java | 2 +- .../webasto/next/EvcsWebastoNextImpl.java | 2 +- .../webasto/unite/EvcsWebastoUniteImpl.java | 2 +- .../charger/AbstractFeneconDessCharger.java | 3 +- .../fenecon/dess/ess/FeneconDessEssImpl.java | 2 +- .../gridmeter/FeneconDessGridMeterImpl.java | 2 +- .../dess/pvmeter/FeneconDessPvMeterImpl.java | 2 +- .../fenecon/mini/ess/FeneconMiniEssImpl.java | 2 +- .../gridmeter/FeneconMiniGridMeterImpl.java | 2 +- .../mini/pvmeter/FeneconMiniPvMeterImpl.java | 2 +- .../fenecon/pro/ess/FeneconProEssImpl.java | 2 +- .../pro/pvmeter/FeneconProPvMeterImpl.java | 2 +- .../GoodWeBatteryInverterImpl.java | 44 +- .../charger/AbstractGoodWeEtCharger.java | 3 +- .../goodwe/charger/mppt/twostring/Config.java | 30 + .../GoodWeChargerMpptTwoStringImpl.java | 247 + .../charger/mppt/twostring/MpptPort.java | 24 + .../edge/goodwe/charger/twostring/Config.java | 1 + .../twostring/GoodWeChargerTwoString.java | 1 + .../twostring/GoodWeChargerTwoStringImpl.java | 16 + .../edge/goodwe/charger/twostring/PvPort.java | 25 +- .../edge/goodwe/common/AbstractGoodWe.java | 62 +- .../io/openems/edge/goodwe/common/GoodWe.java | 14 +- .../GoodWeEmergencyPowerMeterImpl.java | 2 +- .../goodwe/gridmeter/GoodWeGridMeterImpl.java | 25 +- .../GoodWeBatteryInverterImplTest.java | 87 +- .../edge/goodwe/batteryinverter/MyConfig.java | 2 +- .../GoodWeChargerMpptTwoStringImplTest.java | 190 + .../charger/mppt/twostring/MyConfig.java | 72 + .../charger/mppt/twostring/TestStatic.java | 28 + .../GoodWeChargerTwoStringImplTest.java | 1 + .../charger/twostring/RuleOfThreeTest.java | 1 + .../analog/mr/IoFilipowskiMrAo1Impl.java | 2 +- .../eight/IoKmtronicRelay8PortImpl.java | 2 +- .../four/IoKmtronicRelay4PortImpl.java | 2 +- .../src/io/openems/edge/wago/IoWagoImpl.java | 2 +- .../io/weidmueller/IoWeidmuellerUr20Impl.java | 37 +- .../artemes/am2/MeterArtemesAM2Impl.java | 2 +- .../em300/MeterBControlEM300Impl.java | 2 +- .../bgetech/MeterBgeTechDrt428M2Impl.java | 2 +- .../aplus/MeterCamillebauerAplusImpl.java | 2 +- .../em300/MeterCarloGavazziEm300Impl.java | 2 +- .../umg511/MeterJanitzaUmg511Impl.java | 2 +- .../umg604/MeterJanitzaUmg604Impl.java | 2 +- .../umg96rme/MeterJanitzaUmg96rmeImpl.java | 2 +- .../meter/kdk/puct2/MeterKdk2puctImpl.java | 2 +- .../sdm630/MeterMicrocareSdm630Impl.java | 2 +- .../PhoenixContactMeterImpl.java | 2 +- .../plexlog/MeterPlexlogDataloggerImpl.java | 2 +- .../pqplus/umd96/MeterPqplusUmd96Impl.java | 2 +- .../pqplus/umd97/MeterPqplusUmd97Impl.java | 2 +- .../MeterSchneiderActi9SmartlinkImpl.java | 2 +- .../pac1600/MeterSiemensPac1600Impl.java | 2 +- .../pac2200/MeterSiemensPac2200Impl.java | 3 +- .../meter/sma/shm20/MeterSmaShm20Impl.java | 2 +- .../meter/socomec/AbstractSocomecMeter.java | 42 +- .../MeterSocomecSinglephaseImpl.java | 2 +- .../MeterSocomecThreephaseImpl.java | 2 +- .../meter/sunspec/AbstractSunSpecMeter.java | 2 +- .../weidmueller/MeterWeidmueller525Impl.java | 2 +- .../efr4001ip/MeterZiehlEfr4001IpImpl.java | 2 +- .../fronius/PvInverterFroniusImpl.java | 2 +- .../PvInverterKacoBlueplanetImpl.java | 2 +- .../kostal/PvInverterKostalImpl.java | 2 +- .../sma/PvInverterSmaSunnyTripowerImpl.java | 2 +- .../solarlog/PvInverterSolarlogImpl.java | 2 +- .../sunspec/AbstractSunSpecPvInverter.java | 7 +- .../gridmeter/SolarEdgeGridMeterImpl.java | 2 +- .../pvinverter/SolarEdgePvInverterImpl.java | 2 +- .../openems/edge/timedata/api/Timedata.java | 18 + .../api/utils/CalculateEnergyFromPower.java | 13 + .../edge/timedata/rrd4j/Rrd4jReadHandler.java | 43 + .../edge/timedata/rrd4j/Rrd4jSupplier.java | 46 +- .../timedata/rrd4j/TimedataRrd4jImpl.java | 7 + .../rrd4j/version/VersionHandler.java | 14 +- .../timedata/rrd4j/Rrd4jReadHandlerTest.java | 188 +- .../timedata/rrd4j/TimedataRrd4jImplTest.java | 6 +- tools/prepare-commit.sh | 12 + ui/.vscode/settings.json | 11 +- ui/package-lock.json | 36391 ++++++++-------- ui/package.json | 151 +- ui/src/app/app.component.html | 2 +- ui/src/app/app.component.ts | 25 +- ui/src/app/app.module.ts | 6 +- ui/src/app/edge/edge.component.ts | 1 + .../channelThreshold.module.ts | 3 - .../chart/totalchart.component.ts | 1 + .../Controller/ChannelThreshold/flat/flat.ts | 1 + .../Ess/TimeOfUseTariff/chart/chart.ts | 8 +- .../Ess/TimeOfUseTariff/flat/flat.ts | 1 + .../TimeOfUseTariff/timeOfUseTariff.module.ts | 3 - .../app/edge/history/abstracthistorychart.ts | 5 +- .../app/edge/history/abstracthistorywidget.ts | 1 + .../edge/history/chpsoc/chart.component.ts | 1 + .../chpsocchartoverview.component.ts | 1 + .../edge/history/chpsoc/widget.component.html | 4 +- .../edge/history/chpsoc/widget.component.ts | 1 + .../edge/history/common/autarchy/Autarchy.ts | 3 - .../history/common/autarchy/chart/chart.ts | 1 + .../edge/history/common/autarchy/flat/flat.ts | 1 + .../history/common/consumption/Consumption.ts | 3 - .../common/consumption/chart/chart.spec.ts | 18 +- .../history/common/consumption/chart/chart.ts | 1 + .../history/common/consumption/flat/flat.ts | 1 + .../common/energy/chart/channels.spec.ts | 12 +- .../history/common/energy/chart/chart.spec.ts | 28 +- .../edge/history/common/energy/chart/chart.ts | 1 + .../app/edge/history/common/energy/energy.ts | 4 - .../edge/history/common/energy/flat/flat.ts | 1 + .../history/common/grid/chart/chart.spec.ts | 19 +- .../edge/history/common/grid/chart/chart.ts | 1 + ui/src/app/edge/history/common/grid/grid.ts | 3 - .../common/production/chart/chargerChart.ts | 1 + .../production/chart/productionMeterChart.ts | 1 + .../common/production/chart/totalAcChart.ts | 1 + .../common/production/chart/totalChart.ts | 1 + .../common/production/chart/totalDcChart.ts | 1 + .../common/production/overview/overview.html | 2 +- .../history/common/production/production.ts | 9 - .../common/selfconsumption/SelfConsumption.ts | 3 - .../selfconsumption/chart/chart.component.ts | 1 + .../common/selfconsumption/flat/flat.ts | 1 + .../delayedselltogrid/chart.component.ts | 1 + ...elayedselltogridchartoverview.component.ts | 1 + .../delayedselltogrid/widget.component.ts | 1 + ...fixdigitaloutputchartoverview.component.ts | 1 + .../fixdigitaloutput/singlechart.component.ts | 1 + .../fixdigitaloutput/totalchart.component.ts | 1 + .../fixdigitaloutput/widget.component.ts | 1 + .../app/edge/history/grid/chart.component.ts | 1 + .../gridoptimizedcharge/chart.component.ts | 17 +- ...doptimizedchargechartoverview.component.ts | 1 + .../sellToGridLimitChart.component.ts | 1 + .../gridoptimizedcharge/widget.component.ts | 1 + .../history/heatingelement/chart.component.ts | 1 + .../heatingelementchartoverview.component.ts | 1 + .../heatingelement/widget.component.ts | 1 + .../edge/history/heatpump/chart.component.ts | 1 + .../heatpumpchartoverview.component.ts | 1 + .../edge/history/heatpump/widget.component.ts | 1 + ui/src/app/edge/history/history.component.ts | 1 + ui/src/app/edge/history/historydataservice.ts | 1 + ...etricpeakshavingchartoverview.component.ts | 1 + .../peakshaving/asymmetric/chart.component.ts | 1 + .../asymmetric/widget.component.ts | 1 + .../peakshaving/symmetric/chart.component.ts | 1 + ...etricpeakshavingchartoverview.component.ts | 1 + .../peakshaving/symmetric/widget.component.ts | 1 + .../peakshaving/timeslot/chart.component.ts | 1 + ...eslotpeakshavingchartoverview.component.ts | 1 + .../peakshaving/timeslot/widget.component.ts | 1 + ui/src/app/edge/history/shared.ts | 3 +- .../singlethreshold/chart.component.ts | 1 + .../singlethresholdchartoverview.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 + .../storagechartoverview.component.ts | 1 + .../history/storage/totalchart.component.ts | 1 + .../edge/history/storage/widget.component.ts | 1 + .../Channelthreshold/Channelthreshold.ts | 1 + .../app/edge/live/Controller/ChpSoc/ChpSoc.ts | 1 + .../ChpSoc/modal/modal.component.ts | 1 + .../Ess/FixActivePower/Ess_FixActivePower.ts | 4 - .../Ess/FixActivePower/flat/flat.ts | 1 + .../Ess/FixActivePower/modal/modal.ts | 1 + .../Ess_GridOptimizedCharge.ts | 5 - .../Ess/GridOptimizedCharge/flat/flat.ts | 1 + .../Ess/GridOptimizedCharge/modal/modal.ts | 1 + .../modal/predictionChart.ts | 1 + .../TimeOfUseTariff/Ess_TimeOfUseTariff.ts | 148 +- .../Ess/TimeOfUseTariff/modal/modal.ts | 10 +- .../TimeOfUseTariff/modal/powerSocChart.ts | 38 +- .../TimeOfUseTariff/modal/statePriceChart.ts | 9 +- ui/src/app/edge/live/Controller/Evcs/Evcs.ts | 5 - .../administration.component.ts | 1 + .../edge/live/Controller/Evcs/flat/flat.ts | 1 + .../edge/live/Controller/Evcs/modal/modal.ts | 1 + .../live/Controller/Evcs/popover/popover.ts | 1 + .../Io_ChannelSingleThreshold.ts | 1 + .../modal/modal.component.ts | 1 + .../FixDigitalOutput/Io_FixDigitalOutput.ts | 1 + .../FixDigitalOutput/modal/modal.component.ts | 1 + .../Io/HeatingElement/Io_HeatingElement.ts | 4 - .../Controller/Io/HeatingElement/flat/flat.ts | 1 + .../Io/HeatingElement/modal/modal.ts | 1 + .../Controller/Io/Heatpump/Io_Heatpump.ts | 1 + .../Io/Heatpump/modal/modal.component.ts | 1 + .../PeakShaving/Asymmetric/Asymmetric.ts | 1 + .../Asymmetric/modal/modal.component.ts | 1 + .../PeakShaving/Symmetric/Symmetric.ts | 1 + .../Symmetric/modal/modal.component.ts | 1 + .../Symmetric_TimeSlot/Symmetric_TimeSlot.ts | 1 + .../modal/modal.component.ts | 1 + .../Api_DigitalInput/Io_Api_DigitalInput.ts | 1 + .../Api_DigitalInput/modal/modal.component.ts | 1 + .../Evcs_Api_Cluster/Evcs_Api_Cluster.ts | 1 + .../modal/evcs-chart/evcs.chart.ts | 1 + .../modal/evcsCluster-modal.page.ts | 1 + .../live/common/autarchy/Common_Autarchy.ts | 4 - .../edge/live/common/autarchy/flat/flat.ts | 1 + .../common/consumption/Common_Consumption.ts | 4 - .../edge/live/common/consumption/flat/flat.ts | 1 + .../common/consumption/modal/modal.spec.ts | 1 + .../app/edge/live/common/grid/Common_Grid.ts | 4 - ui/src/app/edge/live/common/grid/flat/flat.ts | 1 + .../common/production/Common_Production.ts | 4 - .../selfconsumption/Common_Selfconsumption.ts | 4 - .../live/common/selfconsumption/flat/flat.ts | 1 + .../common/storage/modal/modal.component.ts | 1 + .../live/common/storage/storage.component.ts | 1 + .../delayedselltogrid.component.ts | 1 + .../modal/modal.component.ts | 1 + .../energymonitor/chart/chart.component.ts | 1 + .../section/abstractsection.component.ts | 1 + .../chart/section/consumption.component.ts | 1 + .../chart/section/grid.component.ts | 1 + .../chart/section/production.component.ts | 1 + .../chart/section/storage.component.ts | 1 + .../energymonitor/energymonitor.component.ts | 1 + ui/src/app/edge/live/live.component.ts | 1 + ui/src/app/edge/live/live.module.ts | 18 - ui/src/app/edge/live/livedataservice.ts | 1 + .../settings/alerting/alerting.component.ts | 11 +- ui/src/app/edge/settings/app/app.module.ts | 1 + .../formly-option-group-picker.component.ts | 1 + .../formly-reorder-array.component.ts | 1 + .../formly-safe-input-modal.component.ts | 1 + .../safe-input/formly-safe-input.extended.ts | 1 + .../app/edge/settings/app/index.component.ts | 1 + .../edge/settings/app/install.component.ts | 1 + .../app/jsonrpc/getAppAssistant.spec.ts | 1 + .../settings/app/jsonrpc/getAppAssistant.ts | 1 + .../settings/app/keypopup/modal.component.ts | 1 + .../app/edge/settings/app/single.component.ts | 1 + .../app/edge/settings/app/update.component.ts | 1 + .../settings/channels/channels.component.ts | 3 +- .../component/install/index.component.ts | 1 + .../component/install/install.component.ts | 1 + .../component/update/index.component.ts | 1 + .../component/update/update.component.ts | 1 + .../edge/settings/jsonrpctest/jsonrpctest.ts | 1 + .../settings/network/network.component.ts | 1 + .../settings/profile/aliasupdate.component.ts | 1 + .../modbusapi/getModbusProtocolResponse.ts | 4 +- .../settings/profile/profile.component.ts | 1 + .../app/edge/settings/settings.component.ts | 1 + ui/src/app/edge/settings/settings.module.ts | 2 - .../settings/system/executeSystemUpdate.ts | 1 + .../system/executesystemupdate.component.ts | 1 + .../system/maintenance/maintenance.ts | 1 + .../system/oe-system-update.component.ts | 1 + .../edge/settings/system/system.component.ts | 1 + .../systemexecute/systemexecute.component.ts | 1 + .../settings/systemlog/systemlog.component.ts | 1 + ui/src/app/index/filter/filter.component.ts | 1 + ui/src/app/index/login.component.ts | 1 + ui/src/app/index/login.spec.ts | 1 + .../app/index/overview/overview.component.ts | 2 +- .../app/registration/modal/modal.component.ts | 1 + .../chartoptions/chartoptions.component.ts | 1 + ui/src/app/shared/directive/directive.ts | 3 - ui/src/app/shared/edge/currentdata.ts | 1 + ui/src/app/shared/edge/edge.ts | 1 + ui/src/app/shared/edge/edgeconfig.spec.ts | 14 +- ui/src/app/shared/edge/edgeconfig.ts | 12 +- .../edge/meter/esscharger/modal.component.ts | 1 + ui/src/app/shared/edge/meter/meter.module.ts | 2 - ui/src/app/shared/footer/footer.html | 2 +- ui/src/app/shared/footer/footer.ts | 45 +- .../form-field-checkbox-hyperlink.wrapper.ts | 1 + .../form-field-default-cases.wrapper.ts | 1 + .../formly-field-checkbox-with-image.html | 10 +- .../formly-select-field-modal.component.ts | 1 + .../shared/formly/formly-skeleton-wrapper.ts | 1 + .../abstracthistorywidget.ts | 1 + .../chart/abstractHistoryChartOverview.ts | 1 + .../chart/abstracthistorychart.ts | 16 +- .../chart/chart.constants.spec.ts | 1 + .../chart/chart.constants.ts | 1 + .../shared/genericComponents/chart/chart.ts | 1 + .../flat/abstract-flat-widget-line.ts | 1 + .../flat/abstract-flat-widget.ts | 1 + .../flat/flat-widget-line/flat-widget-line.ts | 1 + .../app/shared/genericComponents/flat/flat.ts | 1 + .../genericComponents/genericComponents.ts | 16 - .../modal/abstract-modal-line.ts | 1 + .../genericComponents/modal/abstractModal.ts | 1 + .../modal/help-button/help-button.ts | 1 + .../modal/modal-button/modal-button.ts | 1 + .../modal/modal-info-line/modal-info-line.ts | 1 + .../modal/modal-line/modal-line.ts | 1 + .../modal-value-line/modal-value-line.ts | 1 + .../shared/genericComponents/modal/modal.ts | 1 + .../modal-horizontal-line.ts | 1 + .../genericComponents/shared/converter.ts | 1 + .../genericComponents/shared/dataservice.ts | 1 + .../shared/genericComponents/shared/filter.ts | 1 + .../shared/testing/common.ts | 8 +- .../shared/testing/tester.ts | 3 +- ui/src/app/shared/header/header.component.ts | 1 + .../shared/history-data-error.component.ts | 1 + .../queryHistoricTimeseriesDataRequest.ts | 1 + ...istoricTimeseriesEnergyPerPeriodRequest.ts | 1 + .../queryHistoricTimeseriesEnergyRequest.ts | 1 + .../queryHistoricTimeseriesExportXlxs.ts | 1 + .../request/setEmergencyReserveRequest.ts | 2 +- .../request/subscribeChannelsRequest.ts | 1 + .../jsonrpc/response/edgeRpcResponse.ts | 2 +- .../percentagebar/percentagebar.component.ts | 1 + .../app/shared/pickdate/pickdate.component.ts | 1 + .../pickdate/popover/popover.component.ts | 3 +- .../shared/pipe/classname/classname.pipe.ts | 1 + ui/src/app/shared/pipe/keys/keys.pipe.ts | 1 + ui/src/app/shared/pipe/pipe.ts | 10 - ui/src/app/shared/pipe/sign/sign.pipe.ts | 1 + ui/src/app/shared/service/abstractservice.ts | 1 + ui/src/app/shared/service/defaulttypes.ts | 1 + .../service/globalRouteChangeHandler.ts | 1 + ui/src/app/shared/service/pagination.ts | 1 + ui/src/app/shared/service/service.ts | 1 + ui/src/app/shared/service/utils.spec.ts | 1 + ui/src/app/shared/service/utils.ts | 142 +- ui/src/app/shared/service/websocket.ts | 1 + .../app/shared/service/websocketInterface.ts | 1 + ui/src/app/shared/service/wsdata.ts | 1 + ui/src/app/shared/shared.module.ts | 1 + ui/src/app/shared/shared.spec.ts | 1 + ui/src/app/shared/shared.ts | 1 + .../shared/status/single/status.component.ts | 1 + ui/src/app/shared/translate.extension.ts | 1 + ui/src/app/shared/type/language.spec.ts | 1 + ui/src/app/shared/type/widget.ts | 1 + .../shared/utils/array/array.utils.spec.ts | 1 + .../shared/utils/color/color.utils.spec.ts | 1 + ui/src/app/shared/utils/color/color.utils.ts | 1 + .../app/shared/utils/date/dateutils.spec.ts | 1 + .../shared/utils/datetime/datetime-utils.ts | 1 + .../app/shared/utils/time/timeutils.spec.ts | 1 + ui/src/app/shared/utils/time/timeutils.ts | 1 + ui/src/app/user/user.component.ts | 1 + ui/src/assets/i18n/de.json | 19 +- ui/src/assets/i18n/en.json | 21 +- ui/src/assets/img/home-mppt/Home_20_MPPT1.png | Bin 0 -> 297385 bytes ui/src/assets/img/home-mppt/Home_20_MPPT2.png | Bin 0 -> 297872 bytes ui/src/assets/img/home-mppt/Home_30_MPPT1.png | Bin 0 -> 304512 bytes ui/src/assets/img/home-mppt/Home_30_MPPT2.png | Bin 0 -> 455661 bytes ui/src/assets/img/home-mppt/Home_30_MPPT3.png | Bin 0 -> 454797 bytes ui/src/index.html | 4 +- .../openems/environments/backend-dev.ts | 1 + .../openems/environments/backend-docker.ts | 1 + .../openems/environments/backend-prod.ts | 1 + .../themes/openems/environments/edge-dev.ts | 1 + .../openems/environments/edge-docker.ts | 1 + .../themes/openems/environments/edge-prod.ts | 1 + ui/src/themes/openems/environments/gitpod.ts | 1 + ui/tsconfig.json | 8 +- 502 files changed, 25083 insertions(+), 20499 deletions(-) create mode 100644 io.openems.backend.common/src/io/openems/backend/common/jsonrpc/SimulationEngine.java create mode 100644 io.openems.backend.common/src/io/openems/backend/common/jsonrpc/request/SimulationRequest.java create mode 100644 io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/ModbusUtilsTest.java create mode 100644 io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/dummy/Config.java create mode 100644 io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/dummy/MyConfig.java create mode 100644 io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/dummy/MySunSpecComponentImpl.java create mode 100644 io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/Utils.java delete mode 100644 io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/GetScheduleResponse.java delete mode 100644 io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/optimizer/Context.java create mode 100644 io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/package-info.java create mode 100644 io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/UtilsTest.java delete mode 100644 io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/ScheduleDatasTest.java delete mode 100644 io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/optimizer/OptimizerTest.java delete mode 100644 io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/optimizer/UtilsTest.java create mode 100644 io.openems.edge.energy.api/.classpath create mode 100644 io.openems.edge.energy.api/.gitignore create mode 100644 io.openems.edge.energy.api/.project create mode 100644 io.openems.edge.energy.api/.settings/org.eclipse.core.resources.prefs create mode 100644 io.openems.edge.energy.api/bnd.bnd create mode 100644 io.openems.edge.energy.api/readme.adoc create mode 100644 io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergySchedulable.java create mode 100644 io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergyScheduleHandler.java create mode 100644 io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergyScheduler.java create mode 100644 io.openems.edge.energy.api/src/io/openems/edge/energy/api/package-info.java create mode 100644 io.openems.edge.energy.api/test/.gitignore create mode 100644 io.openems.edge.energy/.classpath create mode 100644 io.openems.edge.energy/.gitignore create mode 100644 io.openems.edge.energy/.project create mode 100644 io.openems.edge.energy/.settings/org.eclipse.core.resources.prefs create mode 100644 io.openems.edge.energy/bnd.bnd create mode 100644 io.openems.edge.energy/readme.adoc create mode 100644 io.openems.edge.energy/src/io/openems/edge/energy/Config.java create mode 100644 io.openems.edge.energy/src/io/openems/edge/energy/EnergySchedulerImpl.java rename {io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff => io.openems.edge.energy/src/io/openems/edge/energy}/jsonrpc/GetScheduleRequest.java (94%) create mode 100644 io.openems.edge.energy/src/io/openems/edge/energy/jsonrpc/GetScheduleResponse.java rename {io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff => io.openems.edge.energy/src/io/openems/edge/energy}/optimizer/EnergyFlow.java (96%) create mode 100644 io.openems.edge.energy/src/io/openems/edge/energy/optimizer/GlobalContext.java rename {io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff => io.openems.edge.energy/src/io/openems/edge/energy}/optimizer/InitialPopulationUtils.java (92%) rename {io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff => io.openems.edge.energy/src/io/openems/edge/energy}/optimizer/Optimizer.java (58%) rename {io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff => io.openems.edge.energy/src/io/openems/edge/energy}/optimizer/Params.java (96%) rename {io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff => io.openems.edge.energy/src/io/openems/edge/energy}/optimizer/ParamsUtils.java (88%) rename {io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/jsonrpc => io.openems.edge.energy/src/io/openems/edge/energy/optimizer}/ScheduleDatas.java (78%) rename {io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff => io.openems.edge.energy/src/io/openems/edge/energy}/optimizer/Simulator.java (88%) rename {io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff => io.openems.edge.energy/src/io/openems/edge/energy}/optimizer/Utils.java (66%) create mode 100644 io.openems.edge.energy/test/.gitignore create mode 100644 io.openems.edge.energy/test/io/openems/edge/energy/EnergySchedulerImplTest.java create mode 100644 io.openems.edge.energy/test/io/openems/edge/energy/MyConfig.java rename {io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff => io.openems.edge.energy/test/io/openems/edge/energy}/TestData.java (98%) rename {io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff => io.openems.edge.energy/test/io/openems/edge/energy}/jsonrpc/GetScheduleResponseTest.java (53%) rename {io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff => io.openems.edge.energy/test/io/openems/edge/energy}/optimizer/EnergyFlowTest.java (87%) rename {io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff => io.openems.edge.energy/test/io/openems/edge/energy}/optimizer/InitialPopulationUtilsTest.java (82%) rename {io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff => io.openems.edge.energy/test/io/openems/edge/energy}/optimizer/IntegrationTests.java (79%) create mode 100644 io.openems.edge.energy/test/io/openems/edge/energy/optimizer/OptimizerTest.java rename {io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff => io.openems.edge.energy/test/io/openems/edge/energy}/optimizer/ParamsUtilsTest.java (83%) rename {io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff => io.openems.edge.energy/test/io/openems/edge/energy}/optimizer/RunOptimizerFromLogApp.java (72%) create mode 100644 io.openems.edge.energy/test/io/openems/edge/energy/optimizer/ScheduleDatasTest.java rename {io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff => io.openems.edge.energy/test/io/openems/edge/energy}/optimizer/SimulatorTest.java (90%) create mode 100644 io.openems.edge.energy/test/io/openems/edge/energy/optimizer/UtilsTest.java create mode 100644 io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/mppt/twostring/Config.java create mode 100644 io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/mppt/twostring/GoodWeChargerMpptTwoStringImpl.java create mode 100644 io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/mppt/twostring/MpptPort.java create mode 100644 io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/mppt/twostring/GoodWeChargerMpptTwoStringImplTest.java create mode 100644 io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/mppt/twostring/MyConfig.java create mode 100644 io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/mppt/twostring/TestStatic.java create mode 100644 ui/src/assets/img/home-mppt/Home_20_MPPT1.png create mode 100644 ui/src/assets/img/home-mppt/Home_20_MPPT2.png create mode 100644 ui/src/assets/img/home-mppt/Home_30_MPPT1.png create mode 100644 ui/src/assets/img/home-mppt/Home_30_MPPT2.png create mode 100644 ui/src/assets/img/home-mppt/Home_30_MPPT3.png diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7b04defeffe..74fa7fb6190 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -78,7 +78,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: '16' + node-version: '20' - name: Setup Cache for Node.js uses: actions/cache@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 841b65015f4..8acfebfebf7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -51,7 +51,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: '16' + node-version: '20' - name: Setup Cache for Node.js uses: actions/cache@v4 diff --git a/io.openems.backend.common/src/io/openems/backend/common/jsonrpc/SimulationEngine.java b/io.openems.backend.common/src/io/openems/backend/common/jsonrpc/SimulationEngine.java new file mode 100644 index 00000000000..975f1d00ea6 --- /dev/null +++ b/io.openems.backend.common/src/io/openems/backend/common/jsonrpc/SimulationEngine.java @@ -0,0 +1,24 @@ +package io.openems.backend.common.jsonrpc; + +import java.util.concurrent.CompletableFuture; + +import io.openems.backend.common.jsonrpc.request.SimulationRequest; +import io.openems.backend.common.metadata.User; +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; + +public interface SimulationEngine { + + /** + * Handles a JSON-RPC Request. + * + * @param edgeId the Edge-ID + * @param user the authenticated {@link User} + * @param request the {@link JsonrpcRequest} + * @return the JSON-RPC Success Response Future + * @throws OpenemsNamedException on error + */ + public CompletableFuture handleRequest(String edgeId, User user, SimulationRequest request) + throws OpenemsNamedException; + +} \ No newline at end of file diff --git a/io.openems.backend.common/src/io/openems/backend/common/jsonrpc/request/SimulationRequest.java b/io.openems.backend.common/src/io/openems/backend/common/jsonrpc/request/SimulationRequest.java new file mode 100644 index 00000000000..37d2422e8b4 --- /dev/null +++ b/io.openems.backend.common/src/io/openems/backend/common/jsonrpc/request/SimulationRequest.java @@ -0,0 +1,68 @@ +package io.openems.backend.common.jsonrpc.request; + +import com.google.gson.JsonObject; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.jsonrpc.base.GenericJsonrpcRequest; +import io.openems.common.jsonrpc.base.JsonrpcRequest; +import io.openems.common.utils.JsonUtils; + +/** + * Represents a JSON-RPC Request for 'SimulationRequest'. + * + *
+ * {
+ *   "jsonrpc": "2.0",
+ *   "id": "UUID",
+ *   "method": "simulation",
+ *   "params": {
+ *     "payload": {@link JsonrpcRequest},
+ *   }
+ * }
+ * 
+ */ +public class SimulationRequest extends JsonrpcRequest { + + public static final String METHOD = "simulation"; + + /** + * Create {@link SimulationRequest} from a template {@link JsonrpcRequest}. + * + * @param r the template {@link JsonrpcRequest} + * @return the {@link SimulationRequest} + * @throws OpenemsNamedException on parse error + */ + public static SimulationRequest from(JsonrpcRequest r) throws OpenemsNamedException { + var p = r.getParams(); + JsonrpcRequest payload = GenericJsonrpcRequest.from(JsonUtils.getAsJsonObject(p, "payload")); + return new SimulationRequest(r, payload); + } + + private final JsonrpcRequest payload; + + public SimulationRequest(JsonrpcRequest payload) { + super(SimulationRequest.METHOD, payload.getTimeout() /* inherit timeout from payload */); + this.payload = payload; + } + + public SimulationRequest(JsonrpcRequest request, JsonrpcRequest payload) { + super(request, SimulationRequest.METHOD); + this.payload = payload; + } + + /** + * Gets the Payload {@link JsonrpcRequest}. + * + * @return Payload + */ + public JsonrpcRequest getPayload() { + return this.payload; + } + + @Override + public JsonObject getParams() { + return JsonUtils.buildJsonObject() // + .add("payload", this.payload.toJsonObject()) // + .build(); + } +} diff --git a/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnRequest.java b/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnRequest.java index 7464ba22feb..cc4b697ccbb 100644 --- a/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnRequest.java +++ b/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnRequest.java @@ -20,6 +20,7 @@ import io.openems.backend.common.jsonrpc.request.RegisterUserRequest; import io.openems.backend.common.jsonrpc.request.SetUserAlertingConfigsRequest; import io.openems.backend.common.jsonrpc.request.SetUserInformationRequest; +import io.openems.backend.common.jsonrpc.request.SimulationRequest; import io.openems.backend.common.jsonrpc.request.SubmitSetupProtocolRequest; import io.openems.backend.common.jsonrpc.request.SubscribeEdgesRequest; import io.openems.backend.common.jsonrpc.response.AddEdgeToUserResponse; @@ -224,6 +225,9 @@ private CompletableFuture handleEdgeRpcRequest(WsData wsData, U this.handleSubscribeChannelsRequest(wsData, edgeId, user, SubscribeChannelsRequest.from(request)); case SubscribeSystemLogRequest.METHOD -> this.handleSubscribeSystemLogRequest(wsData, edgeId, user, SubscribeSystemLogRequest.from(request)); + case SimulationRequest.METHOD -> + this.handleSimulationRequest(edgeId, user, SimulationRequest.from(request)); + case ComponentJsonApiRequest.METHOD -> { final var componentRequest = ComponentJsonApiRequest.from(request); if (!"_host".equals(componentRequest.getComponentId())) { @@ -280,6 +284,25 @@ private CompletableFuture handleEdgeRpcRequest(WsData wsData, U return result; } + /** + * Handles a {@link GetSimulationRequest}. + * + * @param edgeId the Edge-ID + * @param user the {@link User} - no specific level required + * @param request the {@link GetSimulationRequest} + * @return the JSON-RPC Success Response Future + * @throws OpenemsNamedException on error + */ + private CompletableFuture handleSimulationRequest(String edgeId, User user, SimulationRequest request) throws OpenemsNamedException { + + final var simulation = this.parent.simulation; + if (simulation == null) { + throw new OpenemsException("simulation unavailable"); + } + + return simulation.handleRequest(edgeId, user, request); + } + private record LogSystemExecuteCommend(// String edgeId, // non-null User user, // non-null diff --git a/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/UiWebsocketImpl.java b/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/UiWebsocketImpl.java index 24d90076040..98fe60fb108 100644 --- a/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/UiWebsocketImpl.java +++ b/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/UiWebsocketImpl.java @@ -13,6 +13,8 @@ import org.osgi.service.component.annotations.ConfigurationPolicy; import org.osgi.service.component.annotations.Deactivate; import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; import org.osgi.service.event.Event; import org.osgi.service.event.EventHandler; import org.osgi.service.event.propertytypes.EventTopics; @@ -27,6 +29,7 @@ import io.openems.backend.common.edgewebsocket.EdgeCache; import io.openems.backend.common.edgewebsocket.EdgeWebsocket; import io.openems.backend.common.jsonrpc.JsonRpcRequestHandler; +import io.openems.backend.common.jsonrpc.SimulationEngine; import io.openems.backend.common.metadata.Metadata; import io.openems.backend.common.metadata.User; import io.openems.backend.common.timedata.TimedataManager; @@ -66,6 +69,9 @@ public class UiWebsocketImpl extends AbstractOpenemsBackendComponent @Reference protected volatile TimedataManager timedataManager; + + @Reference(policy = ReferencePolicy.DYNAMIC, cardinality = ReferenceCardinality.OPTIONAL) + protected volatile SimulationEngine simulation; public UiWebsocketImpl() { super("Ui.Websocket"); 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 8ad4a2ced40..466ea4fbef6 100644 --- a/io.openems.common/src/io/openems/common/channel/Unit.java +++ b/io.openems.common/src/io/openems/common/channel/Unit.java @@ -187,9 +187,10 @@ public enum Unit { // ########## /** - * Unit of Energy Price [€/MWh]. + * Unit of Energy Price, e.g. [€/MWh]. (see Meta.ChannelId#CURRENCY). */ - EUROS_PER_MEGAWATT_HOUR("€/MWh"), + // TODO symbol should incorporate actual Currency + MONEY_PER_MEGAWATT_HOUR("€/MWh"), // ########## // Frequency @@ -357,7 +358,7 @@ public String format(Object value, OpenemsType type) { case NONE -> // value.toString(); - case AMPERE, DEGREE_CELSIUS, DEZIDEGREE_CELSIUS, EUROS_PER_MEGAWATT_HOUR, HERTZ, MILLIAMPERE, MICROAMPERE, + case AMPERE, DEGREE_CELSIUS, DEZIDEGREE_CELSIUS, MONEY_PER_MEGAWATT_HOUR, HERTZ, MILLIAMPERE, MICROAMPERE, MILLIHERTZ, MILLIVOLT, MICROVOLT, PERCENT, VOLT, VOLT_AMPERE, VOLT_AMPERE_REACTIVE, WATT, KILOWATT, MILLIWATT, WATT_HOURS, OHM, KILOOHM, SECONDS, AMPERE_HOURS, HOUR, CUMULATED_SECONDS, KILOAMPERE_HOURS, KILOVOLT_AMPERE, KILOVOLT_AMPERE_REACTIVE, KILOVOLT_AMPERE_REACTIVE_HOURS, KILOWATT_HOURS, MICROOHM, diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index f77b23df3a8..4eea8ce4531 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -106,6 +106,7 @@ bnd.identity;id='io.openems.edge.core',\ bnd.identity;id='io.openems.edge.edge2edge',\ bnd.identity;id='io.openems.edge.ess.adstec.storaxe',\ + bnd.identity;id='io.openems.edge.energy',\ bnd.identity;id='io.openems.edge.ess.byd.container',\ bnd.identity;id='io.openems.edge.ess.cluster',\ bnd.identity;id='io.openems.edge.ess.core',\ @@ -271,6 +272,8 @@ io.openems.edge.core;version=snapshot,\ io.openems.edge.edge2edge;version=snapshot,\ io.openems.edge.ess.adstec.storaxe;version=snapshot,\ + io.openems.edge.energy;version=snapshot,\ + io.openems.edge.energy.api;version=snapshot,\ io.openems.edge.ess.api;version=snapshot,\ io.openems.edge.ess.byd.container;version=snapshot,\ io.openems.edge.ess.cluster;version=snapshot,\ diff --git a/io.openems.edge.battery.bmw/src/io/openems/edge/battery/bmw/BmwBatteryImpl.java b/io.openems.edge.battery.bmw/src/io/openems/edge/battery/bmw/BmwBatteryImpl.java index 20737cf8ab3..7c660f82094 100644 --- a/io.openems.edge.battery.bmw/src/io/openems/edge/battery/bmw/BmwBatteryImpl.java +++ b/io.openems.edge.battery.bmw/src/io/openems/edge/battery/bmw/BmwBatteryImpl.java @@ -27,7 +27,6 @@ import io.openems.common.channel.AccessMode; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.exceptions.OpenemsException; import io.openems.edge.battery.api.Battery; import io.openems.edge.battery.bmw.enums.BmsState; import io.openems.edge.battery.bmw.enums.State; @@ -342,10 +341,8 @@ private void setStateMachineState(State state) { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { - + protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this, // - new FC16WriteRegistersTask(1399, // m(BmwBattery.ChannelId.HEART_BEAT, new UnsignedWordElement(1399)), // m(BmwBattery.ChannelId.BMS_STATE_COMMAND, new UnsignedWordElement(1400)), // 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 c9ee669d9f7..0dae16c2fcd 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 @@ -3,6 +3,7 @@ import static io.openems.edge.bridge.modbus.api.ElementToChannelConverter.DIRECT_1_TO_1; import static io.openems.edge.bridge.modbus.api.ElementToChannelConverter.SCALE_FACTOR_2; import static io.openems.edge.bridge.modbus.api.ElementToChannelConverter.SCALE_FACTOR_MINUS_1; +import static io.openems.edge.bridge.modbus.api.ModbusUtils.readElementOnce; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; @@ -26,7 +27,6 @@ import io.openems.common.channel.AccessMode; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.exceptions.OpenemsException; import io.openems.edge.battery.api.Battery; import io.openems.edge.battery.bydcommercial.statemachine.Context; import io.openems.edge.battery.bydcommercial.statemachine.StateMachine; @@ -176,7 +176,7 @@ public String debugLog() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this, // new FC3ReadRegistersTask(0x2010, Priority.HIGH, // m(BydBatteryBoxCommercialC130.ChannelId.POWER_CIRCUIT_CONTROL, new UnsignedWordElement(0x2010)) // @@ -964,43 +964,30 @@ public StartStop getStartStopTarget() { BydBatteryBoxCommercialC130Impl.this.isModbusProtocolInitialized = true; // Try to read MODULE_QTY Register - try { - ModbusUtils.readELementOnce(this.getModbusProtocol(), new UnsignedWordElement(0x210D), false) - .thenAccept(moduleQtyValue -> { - if (moduleQtyValue != null) { - // Register is available -> add Registers for current hardware to protocol - try { - this.getModbusProtocol().addTasks(// - new FC3ReadRegistersTask(0x210D, Priority.LOW, // - m(BydBatteryBoxCommercialC130.ChannelId.MODULE_QTY, - new UnsignedWordElement(0x210D)), // - m(BydBatteryBoxCommercialC130.ChannelId.TOTAL_VOLTAGE_OF_SINGLE_MODULE, - new UnsignedWordElement(0x210E))), // - new FC3ReadRegistersTask(0x216E, Priority.LOW, // - m(Battery.ChannelId.CHARGE_MAX_VOLTAGE, new UnsignedWordElement(0x216E), // - SCALE_FACTOR_MINUS_1), // - m(Battery.ChannelId.DISCHARGE_MIN_VOLTAGE, - new UnsignedWordElement(0x216F), // - SCALE_FACTOR_MINUS_1) // - )); - } catch (OpenemsException e) { - BydBatteryBoxCommercialC130Impl.this.logError(BydBatteryBoxCommercialC130Impl.this.log, - "Unable to add registers for detected hardware version: " + e.getMessage()); - e.printStackTrace(); - } // - } else { - BydBatteryBoxCommercialC130Impl.this.logInfo(BydBatteryBoxCommercialC130Impl.this.log, - "Detected old hardware version. Registers are not available. Setting default values."); - - this._setChargeMaxVoltage(OLD_VERSION_DEFAULT_CHARGE_MAX_VOLTAGE); - this._setDischargeMinVoltage(OLD_VERSION_DEFAULT_DISCHARGE_MIN_VOLTAGE); - } - }); - } catch (OpenemsException e) { - BydBatteryBoxCommercialC130Impl.this.logError(BydBatteryBoxCommercialC130Impl.this.log, - "Unable to detect hardware version: " + e.getMessage()); - e.printStackTrace(); - } + readElementOnce(this.getModbusProtocol(), ModbusUtils::doNotRetry, new UnsignedWordElement(0x210D)) + .thenAccept(moduleQtyValue -> { + if (moduleQtyValue != null) { + // Register is available -> add Registers for current hardware to protocol + this.getModbusProtocol().addTasks(// + new FC3ReadRegistersTask(0x210D, Priority.LOW, // + m(BydBatteryBoxCommercialC130.ChannelId.MODULE_QTY, + new UnsignedWordElement(0x210D)), // + m(BydBatteryBoxCommercialC130.ChannelId.TOTAL_VOLTAGE_OF_SINGLE_MODULE, + new UnsignedWordElement(0x210E))), // + new FC3ReadRegistersTask(0x216E, Priority.LOW, // + m(Battery.ChannelId.CHARGE_MAX_VOLTAGE, new UnsignedWordElement(0x216E), // + SCALE_FACTOR_MINUS_1), // + m(Battery.ChannelId.DISCHARGE_MIN_VOLTAGE, new UnsignedWordElement(0x216F), // + SCALE_FACTOR_MINUS_1) // + )); + } else { + BydBatteryBoxCommercialC130Impl.this.logInfo(BydBatteryBoxCommercialC130Impl.this.log, + "Detected old hardware version. Registers are not available. Setting default values."); + + this._setChargeMaxVoltage(OLD_VERSION_DEFAULT_CHARGE_MAX_VOLTAGE); + this._setDischargeMinVoltage(OLD_VERSION_DEFAULT_DISCHARGE_MIN_VOLTAGE); + } + }); }; } 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 d04da464d2d..869077dbe64 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 @@ -181,7 +181,7 @@ protected void deactivate() { }); @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this, // // Versions new FC3ReadRegistersTask(0, Priority.LOW, // 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 d45e42a80b6..01748d00999 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 @@ -2,6 +2,7 @@ import static io.openems.edge.bridge.modbus.api.AbstractOpenemsModbusComponent.BitConverter.INVERT; import static io.openems.edge.bridge.modbus.api.ElementToChannelConverter.SCALE_FACTOR_MINUS_1; +import static io.openems.edge.bridge.modbus.api.ModbusUtils.readElementOnce; import java.util.List; import java.util.Objects; @@ -186,7 +187,7 @@ private void handleStateMachine() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this, // new FC3ReadRegistersTask(500, Priority.LOW, // m(new BitsWordElement(500, this) // @@ -345,7 +346,7 @@ protected ModbusProtocol defineModbusProtocol() throws OpenemsException { */ private void detectHardwareType() throws OpenemsException { // Set Battery-Protection - ModbusUtils.readELementOnce(this.getModbusProtocol(), new UnsignedWordElement(10019), true) // + readElementOnce(this.getModbusProtocol(), ModbusUtils::retryOnNull, new UnsignedWordElement(10019)) .thenAccept(value -> { if (value == null) { return; diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionb/BatterySoltaroClusterVersionBImpl.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionb/BatterySoltaroClusterVersionBImpl.java index 102b6e8481a..771573775ef 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionb/BatterySoltaroClusterVersionBImpl.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionb/BatterySoltaroClusterVersionBImpl.java @@ -509,7 +509,7 @@ public void setStateMachineState(State state) { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { var protocol = new ModbusProtocol(this, // -------- control registers of master -------------------------------------- new FC16WriteRegistersTask(0x1004, // 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 d51be44a2c3..56c3d916474 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 @@ -2,6 +2,7 @@ import static io.openems.edge.bridge.modbus.api.ElementToChannelConverter.SCALE_FACTOR_2; import static io.openems.edge.bridge.modbus.api.ElementToChannelConverter.SCALE_FACTOR_MINUS_1; +import static io.openems.edge.bridge.modbus.api.ModbusUtils.readElementOnce; import java.util.LinkedList; import java.util.Optional; @@ -10,6 +11,7 @@ import java.util.TreeSet; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.BiPredicate; import java.util.function.Consumer; import org.osgi.service.cm.ConfigurationAdmin; @@ -57,6 +59,7 @@ import io.openems.edge.bridge.modbus.api.task.FC16WriteRegistersTask; import io.openems.edge.bridge.modbus.api.task.FC3ReadRegistersTask; import io.openems.edge.bridge.modbus.api.task.FC6WriteRegisterTask; +import io.openems.edge.bridge.modbus.api.task.Task.ExecuteState; import io.openems.edge.common.channel.Channel; import io.openems.edge.common.channel.EnumReadChannel; import io.openems.edge.common.channel.IntegerReadChannel; @@ -185,198 +188,191 @@ protected void deactivate() { private void updateRackChannels(Integer numberOfModules, TreeSet racks) throws OpenemsException { for (Rack r : racks) { - try { - this.getModbusProtocol().addTasks(// - - new FC3ReadRegistersTask(r.offset + 0x000B, Priority.LOW, // - m(this.createChannelId(r, RackChannel.EMS_ADDRESS), - new UnsignedWordElement(r.offset + 0x000B)), // - m(this.createChannelId(r, RackChannel.EMS_BAUDRATE), - new UnsignedWordElement(r.offset + 0x000C)), // - new DummyRegisterElement(r.offset + 0x000D, r.offset + 0x000F), - m(this.createChannelId(r, RackChannel.PRE_CHARGE_CONTROL), - new UnsignedWordElement(r.offset + 0x0010)), // - new DummyRegisterElement(r.offset + 0x0011, r.offset + 0x0014), - m(this.createChannelId(r, RackChannel.SET_SUB_MASTER_ADDRESS), - new UnsignedWordElement(r.offset + 0x0015)) // - ), // - new FC3ReadRegistersTask(r.offset + 0x00F4, Priority.LOW, // - m(this.createChannelId(r, RackChannel.EMS_COMMUNICATION_TIMEOUT), - new UnsignedWordElement(r.offset + 0x00F4)) // - ), - - // Single Cluster Control Registers (running without Master BMS) - new FC6WriteRegisterTask(r.offset + 0x0010, // - m(this.createChannelId(r, RackChannel.PRE_CHARGE_CONTROL), - new UnsignedWordElement(r.offset + 0x0010)) // - ), // - new FC6WriteRegisterTask(r.offset + 0x00F4, // - m(this.createChannelId(r, RackChannel.EMS_COMMUNICATION_TIMEOUT), - new UnsignedWordElement(r.offset + 0x00F4)) // - ), // - new FC16WriteRegistersTask(r.offset + 0x000B, // - m(this.createChannelId(r, RackChannel.EMS_ADDRESS), - new UnsignedWordElement(r.offset + 0x000B)), // - m(this.createChannelId(r, RackChannel.EMS_BAUDRATE), - new UnsignedWordElement(r.offset + 0x000C)) // - ), // - - // Single Cluster Control Registers (General) - new FC6WriteRegisterTask(r.offset + 0x00CC, // - m(this.createChannelId(r, RackChannel.SYSTEM_TOTAL_CAPACITY), - new UnsignedWordElement(r.offset + 0x00CC)) // - ), // - new FC6WriteRegisterTask(r.offset + 0x0015, // - m(this.createChannelId(r, RackChannel.SET_SUB_MASTER_ADDRESS), - new UnsignedWordElement(r.offset + 0x0015)) // - ), // - new FC6WriteRegisterTask(r.offset + 0x00F3, // - m(this.createChannelId(r, RackChannel.VOLTAGE_LOW_PROTECTION), - new UnsignedWordElement(r.offset + 0x00F3)) // - ), // - new FC3ReadRegistersTask(r.offset + 0x00CC, Priority.LOW, // - m(this.createChannelId(r, RackChannel.SYSTEM_TOTAL_CAPACITY), - new UnsignedWordElement(r.offset + 0x00CC)) // - ), - - // Single Cluster Status Registers - new FC3ReadRegistersTask(r.offset + 0x100, Priority.HIGH, // - m(this.createChannelId(r, RackChannel.VOLTAGE), - new UnsignedWordElement(r.offset + 0x100), SCALE_FACTOR_2), - m(this.createChannelId(r, RackChannel.CURRENT), new SignedWordElement(r.offset + 0x101), - SCALE_FACTOR_2), - m(this.createChannelId(r, RackChannel.CHARGE_INDICATION), - new UnsignedWordElement(r.offset + 0x102)), - m(this.createChannelId(r, RackChannel.SOC), new UnsignedWordElement(r.offset + 0x103)), - m(this.createChannelId(r, RackChannel.SOH), new UnsignedWordElement(r.offset + 0x104)), - m(this.createChannelId(r, RackChannel.MAX_CELL_VOLTAGE_ID), - new UnsignedWordElement(r.offset + 0x105)), - m(this.createChannelId(r, RackChannel.MAX_CELL_VOLTAGE), - new UnsignedWordElement(r.offset + 0x106)), - m(this.createChannelId(r, RackChannel.MIN_CELL_VOLTAGE_ID), - new UnsignedWordElement(r.offset + 0x107)), - m(this.createChannelId(r, RackChannel.MIN_CELL_VOLTAGE), - new UnsignedWordElement(r.offset + 0x108)), - m(this.createChannelId(r, RackChannel.MAX_CELL_TEMPERATURE_ID), - new UnsignedWordElement(r.offset + 0x109)), - m(this.createChannelId(r, RackChannel.MAX_CELL_TEMPERATURE), - new SignedWordElement(r.offset + 0x10A), SCALE_FACTOR_MINUS_1), - m(this.createChannelId(r, RackChannel.MIN_CELL_TEMPERATURE_ID), - new UnsignedWordElement(r.offset + 0x10B)), - m(this.createChannelId(r, RackChannel.MIN_CELL_TEMPERATURE), - new SignedWordElement(r.offset + 0x10C), SCALE_FACTOR_MINUS_1), - m(this.createChannelId(r, RackChannel.AVERAGE_VOLTAGE), - new UnsignedWordElement(r.offset + 0x10D)), - m(this.createChannelId(r, RackChannel.SYSTEM_INSULATION), - new UnsignedWordElement(r.offset + 0x10E)), - m(this.createChannelId(r, RackChannel.SYSTEM_MAX_CHARGE_CURRENT), - new UnsignedWordElement(r.offset + 0x10F), SCALE_FACTOR_2), - m(this.createChannelId(r, RackChannel.SYSTEM_MAX_DISCHARGE_CURRENT), - new UnsignedWordElement(r.offset + 0x110), SCALE_FACTOR_2), - m(this.createChannelId(r, RackChannel.POSITIVE_INSULATION), - new UnsignedWordElement(r.offset + 0x111)), - m(this.createChannelId(r, RackChannel.NEGATIVE_INSULATION), - new UnsignedWordElement(r.offset + 0x112)), - m(this.createChannelId(r, RackChannel.CLUSTER_RUN_STATE), - new UnsignedWordElement(r.offset + 0x113)), - m(this.createChannelId(r, RackChannel.AVG_TEMPERATURE), - new SignedWordElement(r.offset + 0x114))), - new FC3ReadRegistersTask(r.offset + 0x18b, Priority.LOW, - m(this.createChannelId(r, RackChannel.PROJECT_ID), - new UnsignedWordElement(r.offset + 0x18b)), - m(this.createChannelId(r, RackChannel.VERSION_MAJOR), - new UnsignedWordElement(r.offset + 0x18c)), - m(this.createChannelId(r, RackChannel.VERSION_SUB), - new UnsignedWordElement(r.offset + 0x18d)), - m(this.createChannelId(r, RackChannel.VERSION_MODIFY), - new UnsignedWordElement(r.offset + 0x18e))), - - // System Warning/Shut Down Status Registers - new FC3ReadRegistersTask(r.offset + 0x140, Priority.LOW, - // Level 2 Alarm: BMS Self-protect, main contactor shut down - m(new BitsWordElement(r.offset + 0x140, this) // - .bit(0, this.createChannelId(r, RackChannel.LEVEL2_CELL_VOLTAGE_HIGH)) // - .bit(1, this.createChannelId(r, RackChannel.LEVEL2_TOTAL_VOLTAGE_HIGH)) // - .bit(2, this.createChannelId(r, RackChannel.LEVEL2_CHARGE_CURRENT_HIGH)) // - .bit(3, this.createChannelId(r, RackChannel.LEVEL2_CELL_VOLTAGE_LOW)) // - .bit(4, this.createChannelId(r, RackChannel.LEVEL2_TOTAL_VOLTAGE_LOW)) // - .bit(5, this.createChannelId(r, RackChannel.LEVEL2_DISCHARGE_CURRENT_HIGH)) // - .bit(6, this.createChannelId(r, RackChannel.LEVEL2_CHARGE_TEMP_HIGH)) // - .bit(7, this.createChannelId(r, RackChannel.LEVEL2_CHARGE_TEMP_LOW)) // - // 8 -> Reserved - // 9 -> Reserved - .bit(10, this.createChannelId(r, RackChannel.LEVEL2_POWER_POLE_TEMP_HIGH)) // - // 11 -> Reserved - .bit(12, this.createChannelId(r, RackChannel.LEVEL2_INSULATION_VALUE)) // - // 13 -> Reserved - .bit(14, this.createChannelId(r, RackChannel.LEVEL2_DISCHARGE_TEMP_HIGH)) // - .bit(15, this.createChannelId(r, RackChannel.LEVEL2_DISCHARGE_TEMP_LOW)) // - ), - // Level 1 Alarm: EMS Control to stop charge, discharge, charge&discharge - m(new BitsWordElement(r.offset + 0x141, this) // - .bit(1, this.createChannelId(r, RackChannel.LEVEL1_TOTAL_VOLTAGE_HIGH)) // - .bit(2, this.createChannelId(r, RackChannel.LEVEL1_CHARGE_CURRENT_HIGH)) // - .bit(4, this.createChannelId(r, RackChannel.LEVEL1_TOTAL_VOLTAGE_LOW)) // - .bit(5, this.createChannelId(r, RackChannel.LEVEL1_DISCHARGE_CURRENT_HIGH)) // - .bit(6, this.createChannelId(r, RackChannel.LEVEL1_CHARGE_TEMP_HIGH)) // - .bit(7, this.createChannelId(r, RackChannel.LEVEL1_CHARGE_TEMP_LOW)) // - .bit(8, this.createChannelId(r, RackChannel.LEVEL1_SOC_LOW)) // - .bit(9, this.createChannelId(r, RackChannel.LEVEL1_TEMP_DIFF_TOO_BIG)) // - .bit(10, this.createChannelId(r, RackChannel.LEVEL1_POWER_POLE_TEMP_HIGH)) // - .bit(11, this.createChannelId(r, RackChannel.LEVEL1_CELL_VOLTAGE_DIFF_TOO_BIG)) // - .bit(12, this.createChannelId(r, RackChannel.LEVEL1_INSULATION_VALUE)) // - .bit(13, this.createChannelId(r, RackChannel.LEVEL1_TOTAL_VOLTAGE_DIFF_TOO_BIG)) // - .bit(14, this.createChannelId(r, RackChannel.LEVEL1_DISCHARGE_TEMP_HIGH)) // - .bit(15, this.createChannelId(r, RackChannel.LEVEL1_DISCHARGE_TEMP_LOW)) // - ), - // Pre-Alarm: Temperature Alarm will active current limication - m(new BitsWordElement(r.offset + 0x142, this) // - .bit(2, this.createChannelId(r, RackChannel.PRE_ALARM_CHARGE_CURRENT_HIGH)) // - .bit(4, this.createChannelId(r, RackChannel.PRE_ALARM_TOTAL_VOLTAGE_LOW)) // - .bit(5, this.createChannelId(r, RackChannel.PRE_ALARM_DISCHARGE_CURRENT_HIGH)) // - .bit(6, this.createChannelId(r, RackChannel.PRE_ALARM_CHARGE_TEMP_HIGH)) // - .bit(7, this.createChannelId(r, RackChannel.PRE_ALARM_CHARGE_TEMP_LOW)) // - .bit(10, this.createChannelId(r, RackChannel.PRE_ALARM_POWER_POLE_HIGH))// - .bit(11, this.createChannelId(r, - RackChannel.PRE_ALARM_CELL_VOLTAGE_DIFF_TOO_BIG)) // - .bit(12, this.createChannelId(r, RackChannel.PRE_ALARM_INSULATION_FAIL)) // - .bit(13, this.createChannelId(r, - RackChannel.PRE_ALARM_TOTAL_VOLTAGE_DIFF_TOO_BIG)) // - .bit(14, this.createChannelId(r, RackChannel.PRE_ALARM_DISCHARGE_TEMP_HIGH)) // - .bit(15, this.createChannelId(r, RackChannel.PRE_ALARM_DISCHARGE_TEMP_LOW)) // - ) // - ), - // Other Alarm Info - new FC3ReadRegistersTask(r.offset + 0x1A5, Priority.LOW, // - m(new BitsWordElement(r.offset + 0x1A5, this) // - .bit(0, this.createChannelId(r, RackChannel.ALARM_COMMUNICATION_TO_MASTER_BMS)) // - .bit(1, this.createChannelId(r, RackChannel.ALARM_COMMUNICATION_TO_SLAVE_BMS)) // - .bit(2, this.createChannelId(r, - RackChannel.ALARM_COMMUNICATION_SLAVE_BMS_TO_TEMP_SENSORS)) // - .bit(3, this.createChannelId(r, RackChannel.ALARM_SLAVE_BMS_HARDWARE)) // - )), - // Slave BMS Fault Message Registers - new FC3ReadRegistersTask(r.offset + 0x185, Priority.LOW, // - m(new BitsWordElement(r.offset + 0x185, this) // - .bit(0, this.createChannelId(r, RackChannel.SLAVE_BMS_VOLTAGE_SENSOR_CABLES)) // - .bit(1, this.createChannelId(r, RackChannel.SLAVE_BMS_POWER_CABLE)) // - .bit(2, this.createChannelId(r, RackChannel.SLAVE_BMS_LTC6803)) // - .bit(3, this.createChannelId(r, RackChannel.SLAVE_BMS_VOLTAGE_SENSORS)) // - .bit(4, this.createChannelId(r, RackChannel.SLAVE_BMS_TEMP_SENSOR_CABLES)) // - .bit(5, this.createChannelId(r, RackChannel.SLAVE_BMS_TEMP_SENSORS)) // - .bit(6, this.createChannelId(r, RackChannel.SLAVE_BMS_POWER_POLE_TEMP_SENSOR)) // - .bit(7, this.createChannelId(r, RackChannel.SLAVE_BMS_TEMP_BOARD_COM)) // - .bit(8, this.createChannelId(r, RackChannel.SLAVE_BMS_BALANCE_MODULE)) // - .bit(9, this.createChannelId(r, RackChannel.SLAVE_BMS_TEMP_SENSORS2)) // - .bit(10, this.createChannelId(r, RackChannel.SLAVE_BMS_INTERNAL_COM)) // - .bit(11, this.createChannelId(r, RackChannel.SLAVE_BMS_EEPROM)) // - .bit(12, this.createChannelId(r, RackChannel.SLAVE_BMS_INIT)) // - )) // - ); - } catch (OpenemsException e) { - this.logError(this.log, "Error while creating modbus tasks: " + e.getMessage()); - e.printStackTrace(); - } // + this.getModbusProtocol().addTasks(// + + new FC3ReadRegistersTask(r.offset + 0x000B, Priority.LOW, // + m(this.createChannelId(r, RackChannel.EMS_ADDRESS), + new UnsignedWordElement(r.offset + 0x000B)), // + m(this.createChannelId(r, RackChannel.EMS_BAUDRATE), + new UnsignedWordElement(r.offset + 0x000C)), // + new DummyRegisterElement(r.offset + 0x000D, r.offset + 0x000F), + m(this.createChannelId(r, RackChannel.PRE_CHARGE_CONTROL), + new UnsignedWordElement(r.offset + 0x0010)), // + new DummyRegisterElement(r.offset + 0x0011, r.offset + 0x0014), + m(this.createChannelId(r, RackChannel.SET_SUB_MASTER_ADDRESS), + new UnsignedWordElement(r.offset + 0x0015)) // + ), // + new FC3ReadRegistersTask(r.offset + 0x00F4, Priority.LOW, // + m(this.createChannelId(r, RackChannel.EMS_COMMUNICATION_TIMEOUT), + new UnsignedWordElement(r.offset + 0x00F4)) // + ), + + // Single Cluster Control Registers (running without Master BMS) + new FC6WriteRegisterTask(r.offset + 0x0010, // + m(this.createChannelId(r, RackChannel.PRE_CHARGE_CONTROL), + new UnsignedWordElement(r.offset + 0x0010)) // + ), // + new FC6WriteRegisterTask(r.offset + 0x00F4, // + m(this.createChannelId(r, RackChannel.EMS_COMMUNICATION_TIMEOUT), + new UnsignedWordElement(r.offset + 0x00F4)) // + ), // + new FC16WriteRegistersTask(r.offset + 0x000B, // + m(this.createChannelId(r, RackChannel.EMS_ADDRESS), + new UnsignedWordElement(r.offset + 0x000B)), // + m(this.createChannelId(r, RackChannel.EMS_BAUDRATE), + new UnsignedWordElement(r.offset + 0x000C)) // + ), // + + // Single Cluster Control Registers (General) + new FC6WriteRegisterTask(r.offset + 0x00CC, // + m(this.createChannelId(r, RackChannel.SYSTEM_TOTAL_CAPACITY), + new UnsignedWordElement(r.offset + 0x00CC)) // + ), // + new FC6WriteRegisterTask(r.offset + 0x0015, // + m(this.createChannelId(r, RackChannel.SET_SUB_MASTER_ADDRESS), + new UnsignedWordElement(r.offset + 0x0015)) // + ), // + new FC6WriteRegisterTask(r.offset + 0x00F3, // + m(this.createChannelId(r, RackChannel.VOLTAGE_LOW_PROTECTION), + new UnsignedWordElement(r.offset + 0x00F3)) // + ), // + new FC3ReadRegistersTask(r.offset + 0x00CC, Priority.LOW, // + m(this.createChannelId(r, RackChannel.SYSTEM_TOTAL_CAPACITY), + new UnsignedWordElement(r.offset + 0x00CC)) // + ), + + // Single Cluster Status Registers + new FC3ReadRegistersTask(r.offset + 0x100, Priority.HIGH, // + m(this.createChannelId(r, RackChannel.VOLTAGE), new UnsignedWordElement(r.offset + 0x100), + SCALE_FACTOR_2), + m(this.createChannelId(r, RackChannel.CURRENT), new SignedWordElement(r.offset + 0x101), + SCALE_FACTOR_2), + m(this.createChannelId(r, RackChannel.CHARGE_INDICATION), + new UnsignedWordElement(r.offset + 0x102)), + m(this.createChannelId(r, RackChannel.SOC), new UnsignedWordElement(r.offset + 0x103)), + m(this.createChannelId(r, RackChannel.SOH), new UnsignedWordElement(r.offset + 0x104)), + m(this.createChannelId(r, RackChannel.MAX_CELL_VOLTAGE_ID), + new UnsignedWordElement(r.offset + 0x105)), + m(this.createChannelId(r, RackChannel.MAX_CELL_VOLTAGE), + new UnsignedWordElement(r.offset + 0x106)), + m(this.createChannelId(r, RackChannel.MIN_CELL_VOLTAGE_ID), + new UnsignedWordElement(r.offset + 0x107)), + m(this.createChannelId(r, RackChannel.MIN_CELL_VOLTAGE), + new UnsignedWordElement(r.offset + 0x108)), + m(this.createChannelId(r, RackChannel.MAX_CELL_TEMPERATURE_ID), + new UnsignedWordElement(r.offset + 0x109)), + m(this.createChannelId(r, RackChannel.MAX_CELL_TEMPERATURE), + new SignedWordElement(r.offset + 0x10A), SCALE_FACTOR_MINUS_1), + m(this.createChannelId(r, RackChannel.MIN_CELL_TEMPERATURE_ID), + new UnsignedWordElement(r.offset + 0x10B)), + m(this.createChannelId(r, RackChannel.MIN_CELL_TEMPERATURE), + new SignedWordElement(r.offset + 0x10C), SCALE_FACTOR_MINUS_1), + m(this.createChannelId(r, RackChannel.AVERAGE_VOLTAGE), + new UnsignedWordElement(r.offset + 0x10D)), + m(this.createChannelId(r, RackChannel.SYSTEM_INSULATION), + new UnsignedWordElement(r.offset + 0x10E)), + m(this.createChannelId(r, RackChannel.SYSTEM_MAX_CHARGE_CURRENT), + new UnsignedWordElement(r.offset + 0x10F), SCALE_FACTOR_2), + m(this.createChannelId(r, RackChannel.SYSTEM_MAX_DISCHARGE_CURRENT), + new UnsignedWordElement(r.offset + 0x110), SCALE_FACTOR_2), + m(this.createChannelId(r, RackChannel.POSITIVE_INSULATION), + new UnsignedWordElement(r.offset + 0x111)), + m(this.createChannelId(r, RackChannel.NEGATIVE_INSULATION), + new UnsignedWordElement(r.offset + 0x112)), + m(this.createChannelId(r, RackChannel.CLUSTER_RUN_STATE), + new UnsignedWordElement(r.offset + 0x113)), + m(this.createChannelId(r, RackChannel.AVG_TEMPERATURE), + new SignedWordElement(r.offset + 0x114))), + new FC3ReadRegistersTask(r.offset + 0x18b, Priority.LOW, + m(this.createChannelId(r, RackChannel.PROJECT_ID), + new UnsignedWordElement(r.offset + 0x18b)), + m(this.createChannelId(r, RackChannel.VERSION_MAJOR), + new UnsignedWordElement(r.offset + 0x18c)), + m(this.createChannelId(r, RackChannel.VERSION_SUB), + new UnsignedWordElement(r.offset + 0x18d)), + m(this.createChannelId(r, RackChannel.VERSION_MODIFY), + new UnsignedWordElement(r.offset + 0x18e))), + + // System Warning/Shut Down Status Registers + new FC3ReadRegistersTask(r.offset + 0x140, Priority.LOW, + // Level 2 Alarm: BMS Self-protect, main contactor shut down + m(new BitsWordElement(r.offset + 0x140, this) // + .bit(0, this.createChannelId(r, RackChannel.LEVEL2_CELL_VOLTAGE_HIGH)) // + .bit(1, this.createChannelId(r, RackChannel.LEVEL2_TOTAL_VOLTAGE_HIGH)) // + .bit(2, this.createChannelId(r, RackChannel.LEVEL2_CHARGE_CURRENT_HIGH)) // + .bit(3, this.createChannelId(r, RackChannel.LEVEL2_CELL_VOLTAGE_LOW)) // + .bit(4, this.createChannelId(r, RackChannel.LEVEL2_TOTAL_VOLTAGE_LOW)) // + .bit(5, this.createChannelId(r, RackChannel.LEVEL2_DISCHARGE_CURRENT_HIGH)) // + .bit(6, this.createChannelId(r, RackChannel.LEVEL2_CHARGE_TEMP_HIGH)) // + .bit(7, this.createChannelId(r, RackChannel.LEVEL2_CHARGE_TEMP_LOW)) // + // 8 -> Reserved + // 9 -> Reserved + .bit(10, this.createChannelId(r, RackChannel.LEVEL2_POWER_POLE_TEMP_HIGH)) // + // 11 -> Reserved + .bit(12, this.createChannelId(r, RackChannel.LEVEL2_INSULATION_VALUE)) // + // 13 -> Reserved + .bit(14, this.createChannelId(r, RackChannel.LEVEL2_DISCHARGE_TEMP_HIGH)) // + .bit(15, this.createChannelId(r, RackChannel.LEVEL2_DISCHARGE_TEMP_LOW)) // + ), + // Level 1 Alarm: EMS Control to stop charge, discharge, charge&discharge + m(new BitsWordElement(r.offset + 0x141, this) // + .bit(1, this.createChannelId(r, RackChannel.LEVEL1_TOTAL_VOLTAGE_HIGH)) // + .bit(2, this.createChannelId(r, RackChannel.LEVEL1_CHARGE_CURRENT_HIGH)) // + .bit(4, this.createChannelId(r, RackChannel.LEVEL1_TOTAL_VOLTAGE_LOW)) // + .bit(5, this.createChannelId(r, RackChannel.LEVEL1_DISCHARGE_CURRENT_HIGH)) // + .bit(6, this.createChannelId(r, RackChannel.LEVEL1_CHARGE_TEMP_HIGH)) // + .bit(7, this.createChannelId(r, RackChannel.LEVEL1_CHARGE_TEMP_LOW)) // + .bit(8, this.createChannelId(r, RackChannel.LEVEL1_SOC_LOW)) // + .bit(9, this.createChannelId(r, RackChannel.LEVEL1_TEMP_DIFF_TOO_BIG)) // + .bit(10, this.createChannelId(r, RackChannel.LEVEL1_POWER_POLE_TEMP_HIGH)) // + .bit(11, this.createChannelId(r, RackChannel.LEVEL1_CELL_VOLTAGE_DIFF_TOO_BIG)) // + .bit(12, this.createChannelId(r, RackChannel.LEVEL1_INSULATION_VALUE)) // + .bit(13, this.createChannelId(r, RackChannel.LEVEL1_TOTAL_VOLTAGE_DIFF_TOO_BIG)) // + .bit(14, this.createChannelId(r, RackChannel.LEVEL1_DISCHARGE_TEMP_HIGH)) // + .bit(15, this.createChannelId(r, RackChannel.LEVEL1_DISCHARGE_TEMP_LOW)) // + ), + // Pre-Alarm: Temperature Alarm will active current limication + m(new BitsWordElement(r.offset + 0x142, this) // + .bit(2, this.createChannelId(r, RackChannel.PRE_ALARM_CHARGE_CURRENT_HIGH)) // + .bit(4, this.createChannelId(r, RackChannel.PRE_ALARM_TOTAL_VOLTAGE_LOW)) // + .bit(5, this.createChannelId(r, RackChannel.PRE_ALARM_DISCHARGE_CURRENT_HIGH)) // + .bit(6, this.createChannelId(r, RackChannel.PRE_ALARM_CHARGE_TEMP_HIGH)) // + .bit(7, this.createChannelId(r, RackChannel.PRE_ALARM_CHARGE_TEMP_LOW)) // + .bit(10, this.createChannelId(r, RackChannel.PRE_ALARM_POWER_POLE_HIGH))// + .bit(11, this.createChannelId(r, RackChannel.PRE_ALARM_CELL_VOLTAGE_DIFF_TOO_BIG)) // + .bit(12, this.createChannelId(r, RackChannel.PRE_ALARM_INSULATION_FAIL)) // + .bit(13, this.createChannelId(r, RackChannel.PRE_ALARM_TOTAL_VOLTAGE_DIFF_TOO_BIG)) // + .bit(14, this.createChannelId(r, RackChannel.PRE_ALARM_DISCHARGE_TEMP_HIGH)) // + .bit(15, this.createChannelId(r, RackChannel.PRE_ALARM_DISCHARGE_TEMP_LOW)) // + ) // + ), + // Other Alarm Info + new FC3ReadRegistersTask(r.offset + 0x1A5, Priority.LOW, // + m(new BitsWordElement(r.offset + 0x1A5, this) // + .bit(0, this.createChannelId(r, RackChannel.ALARM_COMMUNICATION_TO_MASTER_BMS)) // + .bit(1, this.createChannelId(r, RackChannel.ALARM_COMMUNICATION_TO_SLAVE_BMS)) // + .bit(2, this.createChannelId(r, + RackChannel.ALARM_COMMUNICATION_SLAVE_BMS_TO_TEMP_SENSORS)) // + .bit(3, this.createChannelId(r, RackChannel.ALARM_SLAVE_BMS_HARDWARE)) // + )), + // Slave BMS Fault Message Registers + new FC3ReadRegistersTask(r.offset + 0x185, Priority.LOW, // + m(new BitsWordElement(r.offset + 0x185, this) // + .bit(0, this.createChannelId(r, RackChannel.SLAVE_BMS_VOLTAGE_SENSOR_CABLES)) // + .bit(1, this.createChannelId(r, RackChannel.SLAVE_BMS_POWER_CABLE)) // + .bit(2, this.createChannelId(r, RackChannel.SLAVE_BMS_LTC6803)) // + .bit(3, this.createChannelId(r, RackChannel.SLAVE_BMS_VOLTAGE_SENSORS)) // + .bit(4, this.createChannelId(r, RackChannel.SLAVE_BMS_TEMP_SENSOR_CABLES)) // + .bit(5, this.createChannelId(r, RackChannel.SLAVE_BMS_TEMP_SENSORS)) // + .bit(6, this.createChannelId(r, RackChannel.SLAVE_BMS_POWER_POLE_TEMP_SENSOR)) // + .bit(7, this.createChannelId(r, RackChannel.SLAVE_BMS_TEMP_BOARD_COM)) // + .bit(8, this.createChannelId(r, RackChannel.SLAVE_BMS_BALANCE_MODULE)) // + .bit(9, this.createChannelId(r, RackChannel.SLAVE_BMS_TEMP_SENSORS2)) // + .bit(10, this.createChannelId(r, RackChannel.SLAVE_BMS_INTERNAL_COM)) // + .bit(11, this.createChannelId(r, RackChannel.SLAVE_BMS_EEPROM)) // + .bit(12, this.createChannelId(r, RackChannel.SLAVE_BMS_INIT)) // + )) // + ); Consumer addCellChannels = type -> { for (var i = 0; i < numberOfModules; i++) { var elements = new ModbusElement[type.getSensorsPerModule()]; @@ -389,14 +385,9 @@ private void updateRackChannels(Integer numberOfModules, TreeSet racks) th elements[j] = m(channelId, new UnsignedWordElement(r.offset + type.getOffset() + sensorIndex)); } // Add a Modbus read task for this module - try { - this.getModbusProtocol().addTasks(// - new FC3ReadRegistersTask(r.offset + type.getOffset() + i * type.getSensorsPerModule(), - Priority.LOW, elements)); - } catch (OpenemsException e) { - this.logError(this.log, "Error while creating modbus tasks: " + e.getMessage()); - e.printStackTrace(); - } + this.getModbusProtocol().addTasks(// + new FC3ReadRegistersTask(r.offset + type.getOffset() + i * type.getSensorsPerModule(), + Priority.LOW, elements)); } }; addCellChannels.accept(CellChannelFactory.Type.VOLTAGE_CLUSTER); @@ -657,38 +648,24 @@ private void calculateCapacity(int numberOfTowers, int numberOfModules) { * @throws OpenemsException on error */ private CompletableFuture getNumberOfModules() { - final var result = new CompletableFuture(); - - try { - ModbusUtils - .readELementOnce(this.getModbusProtocol(), - new UnsignedWordElement(0x20C1 /* No of modules for 1st tower */), true) - .thenAccept(numberOfModules -> { - if (numberOfModules == null) { - return; - } - result.complete(numberOfModules); - }); - } catch (OpenemsException e) { - result.completeExceptionally(e); - } - - return result; + return readElementOnce(this.getModbusProtocol(), ModbusUtils::retryOnNull, + new UnsignedWordElement(0x20C1 /* No of modules for 1st tower */)); } /** * Recursively reads the 'No of modules' register of each tower. Eventually * completes the {@link CompletableFuture}. * + * @param retryPredicate yield true to retry reading values; false + * otherwise. Parameters are the {@link ExecuteState} + * of the entire task and the individual element + * value * @param result the {@link CompletableFuture} * @param totalNumberOfTowers the recursively incremented total number of towers * @param addresses Queue with the remaining 'No of modules' registers - * @param tryAgainOnError if true, tries to read till it receives a value; - * if false, stops after first try and possibly - * return null */ - private void checkNumberOfTowers(CompletableFuture result, int totalNumberOfTowers, - final Queue addresses, boolean tryAgainOnError) { + private void checkNumberOfTowers(BiPredicate retryPredicate, + CompletableFuture result, int totalNumberOfTowers, final Queue addresses) { final var address = addresses.poll(); if (address == null) { @@ -697,28 +674,18 @@ private void checkNumberOfTowers(CompletableFuture result, int totalNum return; } - try { - // Read next address in Queue - ModbusUtils.readELementOnce(this.getModbusProtocol(), new UnsignedWordElement(address), tryAgainOnError) - .thenAccept(numberOfModules -> { - if (numberOfModules == null) { - if (tryAgainOnError) { - // Try again - return; - } - // Read error -> this tower does not exist. Stop here. - result.complete(totalNumberOfTowers); - return; - } - - // Read successful -> try to read next tower - this.checkNumberOfTowers(result, totalNumberOfTowers + 1, addresses, false); - }); - } catch (OpenemsException e) { - e.printStackTrace(); - result.completeExceptionally(e); - return; - } + // Read next address in Queue + readElementOnce(this.getModbusProtocol(), retryPredicate, new UnsignedWordElement(address)) + .thenAccept(numberOfModules -> { + if (numberOfModules == null) { + // Read error -> this tower does not exist. Stop here. + result.complete(totalNumberOfTowers); + return; + } + + // Read successful -> try to read next tower + this.checkNumberOfTowers(ModbusUtils::doNotRetry, result, totalNumberOfTowers + 1, addresses); + }); } private CompletableFuture getNumberOfTowers() throws OpenemsException { @@ -731,7 +698,7 @@ private CompletableFuture getNumberOfTowers() throws OpenemsException { addresses.add(0x50C1 /* No of modules for 4th tower */); addresses.add(0x60C1 /* No of modules for 5th tower */); - this.checkNumberOfTowers(result, 0, addresses, true); + this.checkNumberOfTowers(ModbusUtils::retryOnNull, result, 0, addresses); return result; } @@ -786,7 +753,7 @@ public String debugLog() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this, /* * BMS Control Registers diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versiona/BatterySoltaroSingleRackVersionAImpl.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versiona/BatterySoltaroSingleRackVersionAImpl.java index 125aba6961e..92bf44d0a43 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versiona/BatterySoltaroSingleRackVersionAImpl.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versiona/BatterySoltaroSingleRackVersionAImpl.java @@ -435,7 +435,7 @@ private void stopSystem() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this, // new FC6WriteRegisterTask(0x2010, // m(BatterySoltaroSingleRackVersionA.ChannelId.BMS_CONTACTOR_CONTROL, 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 28a0e5f4268..2bc1e0c7db0 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 @@ -4,6 +4,7 @@ import static io.openems.edge.bridge.modbus.api.ElementToChannelConverter.SCALE_FACTOR_1; import static io.openems.edge.bridge.modbus.api.ElementToChannelConverter.SCALE_FACTOR_2; import static io.openems.edge.bridge.modbus.api.ElementToChannelConverter.SCALE_FACTOR_MINUS_1; +import static io.openems.edge.bridge.modbus.api.ModbusUtils.readElementOnce; import java.util.Optional; import java.util.concurrent.CompletableFuture; @@ -230,7 +231,7 @@ public String debugLog() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { var protocol = new ModbusProtocol(this, // // Main switch @@ -914,22 +915,9 @@ protected ModbusProtocol defineModbusProtocol() throws OpenemsException { * Gets the Number of Modules. * * @return the Number of Modules as a {@link CompletableFuture}. - * @throws OpenemsException on error */ private CompletableFuture getNumberOfModules() { - final var result = new CompletableFuture(); - try { - ModbusUtils.readELementOnce(this.getModbusProtocol(), new UnsignedWordElement(0x20C1), true) - .thenAccept(numberOfModules -> { - if (numberOfModules == null) { - return; - } - result.complete(numberOfModules); - }); - } catch (OpenemsException e) { - result.completeExceptionally(e); - } - return result; + return readElementOnce(this.getModbusProtocol(), ModbusUtils::retryOnNull, new UnsignedWordElement(0x20C1)); } /** @@ -955,41 +943,35 @@ private void calculateCapacity(Integer numberOfModules) { * @param numberOfModules the number of battery modules */ private void createDynamicChannels(int numberOfModules) { - try { - for (var i = 0; i < numberOfModules; i++) { - var ameVolt = new ModbusElement[SENSORS_PER_MODULE]; - var ameTemp = new ModbusElement[SENSORS_PER_MODULE]; - for (var j = 0; j < SENSORS_PER_MODULE; j++) { - var sensor = i * SENSORS_PER_MODULE + j; - { - // Create Voltage Channel - var channelId = new ChannelIdImpl( - "CLUSTER_1_BATTERY_" + String.format("%03d", sensor) + "_VOLTAGE", - Doc.of(OpenemsType.INTEGER).unit(Unit.MILLIVOLT)); - this.addChannel(channelId); - // Create Modbus-Mapping for Voltages - var uwe = new UnsignedWordElement(VOLTAGE_ADDRESS_OFFSET + sensor); - ameVolt[j] = m(channelId, uwe); - } - { - // Create Temperature Channel - var channelId = new ChannelIdImpl( - "CLUSTER_1_BATTERY_" + String.format("%03d", sensor) + "_TEMPERATURE", - Doc.of(OpenemsType.INTEGER).unit(Unit.DEZIDEGREE_CELSIUS)); - this.addChannel(channelId); - // Create Modbus-Mapping for Temperatures - var uwe = new UnsignedWordElement(TEMPERATURE_ADDRESS_OFFSET + sensor); - ameTemp[j] = m(channelId, uwe); - } + for (var i = 0; i < numberOfModules; i++) { + var ameVolt = new ModbusElement[SENSORS_PER_MODULE]; + var ameTemp = new ModbusElement[SENSORS_PER_MODULE]; + for (var j = 0; j < SENSORS_PER_MODULE; j++) { + var sensor = i * SENSORS_PER_MODULE + j; + { + // Create Voltage Channel + var channelId = new ChannelIdImpl("CLUSTER_1_BATTERY_" + String.format("%03d", sensor) + "_VOLTAGE", + Doc.of(OpenemsType.INTEGER).unit(Unit.MILLIVOLT)); + this.addChannel(channelId); + // Create Modbus-Mapping for Voltages + var uwe = new UnsignedWordElement(VOLTAGE_ADDRESS_OFFSET + sensor); + ameVolt[j] = m(channelId, uwe); + } + { + // Create Temperature Channel + var channelId = new ChannelIdImpl( + "CLUSTER_1_BATTERY_" + String.format("%03d", sensor) + "_TEMPERATURE", + Doc.of(OpenemsType.INTEGER).unit(Unit.DEZIDEGREE_CELSIUS)); + this.addChannel(channelId); + // Create Modbus-Mapping for Temperatures + var uwe = new UnsignedWordElement(TEMPERATURE_ADDRESS_OFFSET + sensor); + ameTemp[j] = m(channelId, uwe); } - this.getModbusProtocol().addTasks(// - new FC3ReadRegistersTask(VOLTAGE_ADDRESS_OFFSET + i * SENSORS_PER_MODULE, Priority.LOW, - ameVolt), // - new FC3ReadRegistersTask(TEMPERATURE_ADDRESS_OFFSET + i * SENSORS_PER_MODULE, Priority.LOW, - ameTemp)); } - } catch (OpenemsException e) { - e.printStackTrace(); + this.getModbusProtocol().addTasks(// + new FC3ReadRegistersTask(VOLTAGE_ADDRESS_OFFSET + i * SENSORS_PER_MODULE, Priority.LOW, ameVolt), // + new FC3ReadRegistersTask(TEMPERATURE_ADDRESS_OFFSET + i * SENSORS_PER_MODULE, Priority.LOW, + ameTemp)); } } } 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 4d1246d3c20..69feb15eeaa 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 @@ -3,6 +3,7 @@ import static io.openems.edge.bridge.modbus.api.ElementToChannelConverter.DIRECT_1_TO_1; import static io.openems.edge.bridge.modbus.api.ElementToChannelConverter.SCALE_FACTOR_2; import static io.openems.edge.bridge.modbus.api.ElementToChannelConverter.SCALE_FACTOR_MINUS_1; +import static io.openems.edge.bridge.modbus.api.ModbusUtils.readElementOnce; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicReference; @@ -27,7 +28,6 @@ import io.openems.common.channel.AccessMode; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.exceptions.OpenemsException; import io.openems.edge.battery.api.Battery; import io.openems.edge.battery.protection.BatteryProtection; import io.openems.edge.battery.soltaro.common.batteryprotection.BatteryProtectionDefinitionSoltaro3500Wh; @@ -152,22 +152,9 @@ private void calculateCapacity(Integer numberOfModules) { * Gets the Number of Modules. * * @return the Number of Modules as a {@link CompletableFuture}. - * @throws OpenemsException on error */ private CompletableFuture getNumberOfModules() { - final var result = new CompletableFuture(); - try { - ModbusUtils.readELementOnce(this.getModbusProtocol(), new UnsignedWordElement(0x20C1), true) - .thenAccept(numberOfModules -> { - if (numberOfModules == null) { - return; - } - result.complete(numberOfModules); - }); - } catch (OpenemsException e) { - result.completeExceptionally(e); - } - return result; + return readElementOnce(this.getModbusProtocol(), ModbusUtils::retryOnNull, new UnsignedWordElement(0x20C1)); } @Override @@ -219,7 +206,7 @@ public String debugLog() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { var protocol = new ModbusProtocol(this, // new FC6WriteRegisterTask(0x2004, // m(BatterySoltaroSingleRackVersionC.ChannelId.SYSTEM_RESET, new UnsignedWordElement(0x2004)) // @@ -731,14 +718,8 @@ void createCellVoltageAndTemperatureChannels(int numberOfModules) { } // Add a Modbus read task for this module var startAddress = type.getOffset() + i * type.getSensorsPerModule(); - try { - this.getModbusProtocol().addTask(// - new FC3ReadRegistersTask(startAddress, Priority.LOW, elements)); - } catch (OpenemsException e) { - this.logWarn(this.log, "Error while adding Modbus task for slave [" + i + "] starting at [" - + startAddress + "]: " + e.getMessage()); - e.printStackTrace(); - } + this.getModbusProtocol().addTask(// + new FC3ReadRegistersTask(startAddress, Priority.LOW, elements)); } }; addCellChannels.accept(CellChannelFactory.Type.VOLTAGE_SINGLE); diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/doc/statemachine.md b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/doc/statemachine.md index 1e8ee842279..2ba632a58d8 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/doc/statemachine.md +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/doc/statemachine.md @@ -2,26 +2,28 @@ ```mermaid graph LR -Undefined -->|target START| GoRunning +Undefined --> |hasFault| Error +Undefined --> |isStarted or Grid Connected| Running +Undefined --> |isStopped or Off, Standby, Pre-charge| Stopped +Undefined --> |else| Go_Stopped -GoRunning -->|not timeout| GoRunning -GoRunning -->|isRunning| Running -GoRunning -->|timeout| Undefined +Go_Stopped --> |Off or Standby or Pre-charge| Stopped +Go_Stopped --> |hasFault or timeout| Error +Go_Stopped --> |try for 240 second| Go_Stopped -Running -->|isRunning && everythingOk| Running -Running -->|otherwise| Undefined +Stopped --> |targetStart| Go_Running +Stopped --> |hasFault| Error -Undefined -->|target STOP| GoStopped -GoStopped -->|isStopped| Stopped -GoStopped -->|not timeout| GoStopped -GoStopped -->|timeout| Undefined +Go_Running --> |targetStop| Go_Stopped +Go_Running --> |hasFault or timeout| Error +Go_Running --> |try for 240 second| Go_Running +Go_Running --> |Grid Connected or Throttled| Running -Stopped -->|isStopped && everythingOk| Stopped -Stopped -->|otherwise| Undefined +Running --> |hasFault| Error +Running --> |targetStop| Go_Stopped -Undefined -->|hasFault| ErrorHandling -ErrorHandling -->|not timeout| ErrorHandling -ErrorHandling -->|eventually| Undefined +Error --> |!hasFault| Stopped +Error --> |hasFault| Error ``` View using Mermaid, e.g. https://mermaid-js.github.io/mermaid-live-editor \ No newline at end of file diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsave.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsave.java index 1e83c03b677..193b3dbd1d7 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsave.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsave.java @@ -8,6 +8,7 @@ import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.KacoSunSpecModel.S64201.S64201CurrentState; import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.KacoSunSpecModel.S64201.S64201RequestedState; import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.statemachine.StateMachine.State; +import io.openems.edge.bridge.modbus.api.ModbusComponent; import io.openems.edge.bridge.modbus.sunspec.SunSpecPoint; import io.openems.edge.common.channel.Channel; import io.openems.edge.common.channel.Doc; @@ -18,8 +19,8 @@ import io.openems.edge.common.startstop.StartStop; import io.openems.edge.common.startstop.StartStoppable; -public interface BatteryInverterKacoBlueplanetGridsave - extends ManagedSymmetricBatteryInverter, SymmetricBatteryInverter, OpenemsComponent, StartStoppable { +public interface BatteryInverterKacoBlueplanetGridsave extends ManagedSymmetricBatteryInverter, + SymmetricBatteryInverter, ModbusComponent, OpenemsComponent, StartStoppable { /** * Sets the KACO watchdog timeout to 60 seconds. @@ -31,28 +32,19 @@ public interface BatteryInverterKacoBlueplanetGridsave */ public static final int WATCHDOG_TRIGGER_SECONDS = 10; - /** - * Retry set-command after x Seconds, e.g. for starting battery or - * battery-inverter. - */ - public static int RETRY_COMMAND_SECONDS = 30; - - /** - * Retry x attempts for set-command. - */ - public static int RETRY_COMMAND_MAX_ATTEMPTS = 30; - public enum ChannelId implements io.openems.edge.common.channel.ChannelId { STATE_MACHINE(Doc.of(State.values()) // .text("Current State of State-Machine")), // RUN_FAILED(Doc.of(Level.FAULT) // .text("Running the Logic failed")), // - MAX_START_ATTEMPTS(Doc.of(Level.FAULT) // - .text("The maximum number of start attempts failed")), // - MAX_STOP_ATTEMPTS(Doc.of(Level.FAULT) // - .text("The maximum number of stop attempts failed")), // + MAX_START_TIMEOUT(Doc.of(Level.FAULT) // + .text("Max start time is exceeded")), // + MAX_STOP_TIMEOUT(Doc.of(Level.FAULT) // + .text("Max stop time is exceeded")), // INVERTER_CURRENT_STATE_FAULT(Doc.of(Level.FAULT) // .text("The 'CurrentState' is invalid")), // + GRID_DISCONNECTION(Doc.of(Level.FAULT) // + .text("External grid protection disconnection (17)")), // ; private final Doc doc; @@ -92,59 +84,59 @@ public Doc doc() { public S64201CurrentState getCurrentState(); /** - * Gets the Channel for {@link ChannelId#MAX_START_ATTEMPTS}. + * Gets the Channel for {@link ChannelId#MAX_START_TIMEOUT}. * * @return the Channel */ - public default StateChannel getMaxStartAttemptsChannel() { - return this.channel(ChannelId.MAX_START_ATTEMPTS); + public default StateChannel getMaxStartTimeoutChannel() { + return this.channel(ChannelId.MAX_START_TIMEOUT); } /** - * Gets the {@link StateChannel} for {@link ChannelId#MAX_START_ATTEMPTS}. + * Gets the {@link StateChannel} for {@link ChannelId#MAX_START_TIMEOUT}. * * @return the Channel {@link Value} */ - public default Value getMaxStartAttempts() { - return this.getMaxStartAttemptsChannel().value(); + public default Value getMaxStartTimeout() { + return this.getMaxStartTimeoutChannel().value(); } /** - * Internal method to set the 'nextValue' on - * {@link ChannelId#MAX_START_ATTEMPTS} Channel. + * Internal method to set the 'nextValue' on {@link ChannelId#MAX_START_TIMEOUT} + * Channel. * * @param value the next value */ - public default void _setMaxStartAttempts(Boolean value) { - this.getMaxStartAttemptsChannel().setNextValue(value); + public default void _setMaxStartTimeout(boolean value) { + this.getMaxStartTimeoutChannel().setNextValue(value); } /** - * Gets the Channel for {@link ChannelId#MAX_STOP_ATTEMPTS}. + * Gets the Channel for {@link ChannelId#MAX_STOP_TIMEOUT}. * * @return the Channel */ - public default StateChannel getMaxStopAttemptsChannel() { - return this.channel(ChannelId.MAX_STOP_ATTEMPTS); + public default StateChannel getMaxStopTimeoutChannel() { + return this.channel(ChannelId.MAX_STOP_TIMEOUT); } /** - * Gets the {@link StateChannel} for {@link ChannelId#MAX_STOP_ATTEMPTS}. + * Gets the {@link StateChannel} for {@link ChannelId#MAX_STOP_TIMEOUT}. * * @return the Channel {@link Value} */ - public default Value getMaxStopAttempts() { - return this.getMaxStopAttemptsChannel().value(); + public default Value getMaxStopTimeout() { + return this.getMaxStopTimeoutChannel().value(); } /** - * Internal method to set the 'nextValue' on {@link ChannelId#MAX_STOP_ATTEMPTS} + * Internal method to set the 'nextValue' on {@link ChannelId#MAX_STOP_TIMEOUT} * Channel. * * @param value the next value */ - public default void _setMaxStopAttempts(Boolean value) { - this.getMaxStopAttemptsChannel().setNextValue(value); + public default void _setMaxStopTimeout(boolean value) { + this.getMaxStopTimeoutChannel().setNextValue(value); } /** @@ -166,4 +158,83 @@ public default WriteChannel getRequestedStateChannel() thr public default void setRequestedState(S64201RequestedState value) throws OpenemsNamedException { this.getRequestedStateChannel().setNextWriteValue(value); } + + /** + * Gets the Channel for ChannelId.INVERTER_CURRENT_STATE_FAULT. + * + * @return the Channel + */ + public default Channel getInverterCurrentStateFaultChannel() { + return this.channel(ChannelId.INVERTER_CURRENT_STATE_FAULT); + } + + /** + * Writes the value to the ChannelId.INVERTER_CURRENT_STATE_FAULT. + * + * @param value the next value + */ + public default void _setInverterCurrentStateFault(boolean value) { + this.getInverterCurrentStateFaultChannel().setNextValue(value); + } + + /** + * Gets the Channel for ChannelId.RUN_FAILED. + * + * @return the Channel + */ + public default Channel getRunFailedChannel() { + return this.channel(ChannelId.RUN_FAILED); + } + + /** + * Writes the value to the ChannelId.RUN_FAILED. + * + * @param value the next value + */ + public default void _setRunFailed(boolean value) { + this.getRunFailedChannel().setNextValue(value); + } + + /** + * Gets the Channel for ChannelId.GRID_DISCONNECTION. + * + * @return the Channel + */ + public default Channel getGridDisconnectionChannel() { + return this.channel(ChannelId.GRID_DISCONNECTION); + } + + /** + * Writes the value to the ChannelId.GRID_DISCONNECTION. + * + * @param value the next value + */ + public default void _setGridDisconnection(boolean value) { + this.getGridDisconnectionChannel().setNextValue(value); + } + + /** + * Checks if the system is in a running state. This method retrieves the + * system's global state and determines whether the system is in a running + * state. + * + * @return true if the system is in a running state, false otherwise. + */ + public boolean isRunning(); + + /** + * Checks if the system is in a stop state. This method retrieves the system's + * global state and determines whether the system is in a stop state. + * + * @return true if the system is in a stop state, false otherwise. + */ + public boolean isShutdown(); + + /** + * Checks if the system is in a fault state. This method retrieves the system's + * global state and determines whether the system is in a fault state. + * + * @return true if the system is in a fault state, false otherwise. + */ + public boolean hasFailure(); } 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 95979bdc2d0..976d430e141 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 @@ -6,7 +6,6 @@ import java.time.Instant; import java.util.Map; import java.util.Optional; -import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import org.osgi.service.cm.ConfigurationAdmin; @@ -33,6 +32,7 @@ import io.openems.edge.batteryinverter.api.ManagedSymmetricBatteryInverter; import io.openems.edge.batteryinverter.api.SymmetricBatteryInverter; import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.KacoSunSpecModel.S64201.S64201CurrentState; +import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.KacoSunSpecModel.S64201.S64201StVnd; import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.KacoSunSpecModel.S64202.S64202EnLimit; import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.statemachine.Context; import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.statemachine.StateMachine; @@ -49,7 +49,6 @@ import io.openems.edge.common.channel.FloatWriteChannel; import io.openems.edge.common.channel.IntegerReadChannel; import io.openems.edge.common.channel.IntegerWriteChannel; -import io.openems.edge.common.channel.StateChannel; import io.openems.edge.common.channel.value.Value; import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.component.OpenemsComponent; @@ -106,6 +105,7 @@ protected void setModbus(BridgeModbus modbus) { * Kaco 92 does not have model 64203. */ private boolean hasSunSpecModel64203 = false; + private StartStop startStopTarget = StartStop.UNDEFINED; /** * Active SunSpec models for KACO blueplanet gridsave. Commented models are @@ -113,7 +113,7 @@ protected void setModbus(BridgeModbus modbus) { */ private static final Map ACTIVE_MODELS = ImmutableMap.builder() .put(DefaultSunSpecModel.S_1, Priority.LOW) // - .put(DefaultSunSpecModel.S_103, Priority.LOW) // + .put(DefaultSunSpecModel.S_103, Priority.HIGH) // .put(DefaultSunSpecModel.S_121, Priority.LOW) // .put(KacoSunSpecModel.S_64201, Priority.HIGH) // .put(KacoSunSpecModel.S_64202, Priority.LOW) // @@ -135,7 +135,7 @@ protected void setModbus(BridgeModbus modbus) { // .put(SunSpecModel.S_160, Priority.LOW) // @Activate - public BatteryInverterKacoBlueplanetGridsaveImpl() throws OpenemsException { + public BatteryInverterKacoBlueplanetGridsaveImpl() { super(// ACTIVE_MODELS, // OpenemsComponent.ChannelId.values(), // @@ -194,6 +194,9 @@ public void run(Battery battery, int setActivePower, int setReactivePower) throw // Set Battery Limits this.setBatteryLimits(battery); + // Set if there is grid disconnection failure + this.setGridDisconnectionFailure(); + // Calculate the Energy values from ActivePower. this.calculateEnergy(); @@ -202,24 +205,32 @@ public void run(Battery battery, int setActivePower, int setReactivePower) throw this.triggerWatchdog(); } - // Set State-Channels - this.setStateChannels(); - // Prepare Context - var context = new Context(this, battery, this.config, setActivePower, setReactivePower); + var context = new Context(this, // + battery, // + setActivePower, // + setReactivePower, // + this.componentManager.getClock()); // Call the StateMachine try { this.stateMachine.run(context); - - this.channel(BatteryInverterKacoBlueplanetGridsave.ChannelId.RUN_FAILED).setNextValue(false); - + this._setRunFailed(false); } catch (OpenemsNamedException e) { - this.channel(BatteryInverterKacoBlueplanetGridsave.ChannelId.RUN_FAILED).setNextValue(true); + this._setRunFailed(true); this.logError(this.log, "StateMachine failed: " + e.getMessage()); } } + private void setGridDisconnectionFailure() throws OpenemsException { + Channel stVndChannel = this.getSunSpecChannelOrError(KacoSunSpecModel.S64201.ST_VND); + Value stVnd = stVndChannel.value(); + if (!stVnd.isDefined()) { + return; + } + this._setGridDisconnection(stVnd.asEnum() == S64201StVnd.POWADORPROTECT_DISCONNECTION); + } + @Override public BatteryInverterConstraint[] getStaticConstraints() throws OpenemsException { if (this.stateMachine.getCurrentState() == State.RUNNING) { @@ -313,38 +324,6 @@ private void triggerWatchdog() throws OpenemsNamedException { } } - /** - * Sets the State-Channels, e.g. Warnings and Faults. - * - * @throws OpenemsNamedException on error - */ - private void setStateChannels() throws OpenemsNamedException { - /* - * INVERTER_CURRENT_STATE_FAULT - */ - StateChannel inverterCurrentStateChannel = this - .channel(BatteryInverterKacoBlueplanetGridsave.ChannelId.INVERTER_CURRENT_STATE_FAULT); - switch (this.getCurrentState()) { - case FAULT: - case UNDEFINED: - case NO_ERROR_PENDING: - inverterCurrentStateChannel.setNextValue(true); - break; - case GRID_CONNECTED: - case GRID_PRE_CONNECTED: - case MPPT: - case OFF: - case PRECHARGE: - case SHUTTING_DOWN: - case SLEEPING: - case STANDBY: - case STARTING: - case THROTTLED: - inverterCurrentStateChannel.setNextValue(false); - break; - } - } - /** * Mark SunSpec initialization completed; this takes some time at startup. */ @@ -405,34 +384,18 @@ public String debugLog() { .toString(); } - private final AtomicReference startStopTarget = new AtomicReference<>(StartStop.UNDEFINED); - @Override public void setStartStop(StartStop value) { - if (this.startStopTarget.getAndSet(value) != value) { - // Set only if value changed - this.stateMachine.forceNextState(State.UNDEFINED); - } + this.startStopTarget = value; } @Override public StartStop getStartStopTarget() { - switch (this.config.startStop()) { - case AUTO: - // read StartStop-Channel - return this.startStopTarget.get(); - - case START: - // force START - return StartStop.START; - - case STOP: - // force STOP - return StartStop.STOP; - } - - assert false; - return StartStop.UNDEFINED; // can never happen + return switch (this.config.startStop()) { + case AUTO -> this.startStopTarget; + case START -> StartStop.START; + case STOP -> StartStop.STOP; + }; } /** @@ -485,7 +448,7 @@ public Timedata getTimedata() { } @Override - protected void addBlock(int startAddress, SunSpecModel model, Priority priority) throws OpenemsException { + protected void addBlock(int startAddress, SunSpecModel model, Priority priority) { super.addBlock(startAddress, model, priority); // Mark S_64203 as available @@ -493,4 +456,23 @@ protected void addBlock(int startAddress, SunSpecModel model, Priority priority) this.hasSunSpecModel64203 = true; } } + + @Override + public boolean isRunning() { + return this.getCurrentState() == S64201CurrentState.GRID_CONNECTED// + || this.getCurrentState() == S64201CurrentState.THROTTLED; + } + + @Override + public boolean isShutdown() { + return this.getCurrentState() == S64201CurrentState.OFF // + || this.getCurrentState() == S64201CurrentState.STANDBY // + || this.getCurrentState() == S64201CurrentState.PRECHARGE// + || this.getCurrentState() == S64201CurrentState.SHUTTING_DOWN; + } + + @Override + public boolean hasFailure() { + return this.hasFaults() || this.getCurrentState() == S64201CurrentState.FAULT; + } } diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/KacoSunSpecModel.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/KacoSunSpecModel.java index 9f548478ea4..139f38ba225 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/KacoSunSpecModel.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/KacoSunSpecModel.java @@ -341,8 +341,8 @@ public static enum S64201 implements SunSpecPoint { PointType.INT16, // true, // AccessMode.READ_ONLY, // - Unit.HERTZ, // - "HZ_SF", // + Unit.MILLIHERTZ, // + "mHZ_SF", // new OptionsEnum[0])), // RESERVED_36(new ReservedPointImpl("S64201_RESERVED_36")), // RESERVED_37(new ReservedPointImpl("S64201_RESERVED_37")), // diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/Context.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/Context.java index 555e823f8be..9620e98ffba 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/Context.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/Context.java @@ -1,23 +1,31 @@ package io.openems.edge.batteryinverter.kaco.blueplanetgridsave.statemachine; +import java.time.Clock; +import java.time.Instant; + import io.openems.edge.battery.api.Battery; import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.BatteryInverterKacoBlueplanetGridsave; -import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.Config; import io.openems.edge.common.statemachine.AbstractContext; public class Context extends AbstractContext { protected final Battery battery; - protected final Config config; protected final int setActivePower; protected final int setReactivePower; + protected final Clock clock; + + private static final int TIMEOUT = 240; // [s] - public Context(BatteryInverterKacoBlueplanetGridsave parent, Battery battery, Config config, int setActivePower, - int setReactivePower) { + public Context(BatteryInverterKacoBlueplanetGridsave parent, Battery battery, int setActivePower, + int setReactivePower, Clock clock) { super(parent); this.battery = battery; - this.config = config; this.setActivePower = setActivePower; this.setReactivePower = setReactivePower; + this.clock = clock; + } + + protected boolean isTimeout(Instant now, Instant entryAt) { + return now.minusSeconds(TIMEOUT).isAfter(entryAt); } } \ No newline at end of file diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/ErrorHandler.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/ErrorHandler.java index 5000e50caa6..8dc242a57b6 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/ErrorHandler.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/ErrorHandler.java @@ -1,8 +1,5 @@ package io.openems.edge.batteryinverter.kaco.blueplanetgridsave.statemachine; -import java.time.Duration; -import java.time.Instant; - import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.KacoSunSpecModel.S64201.S64201RequestedState; import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.statemachine.StateMachine.State; @@ -10,50 +7,18 @@ public class ErrorHandler extends StateHandler { - private static final int WAIT_SECONDS = 120; - - private Instant entryAt = Instant.MIN; - @Override protected void onEntry(Context context) throws OpenemsNamedException { - this.entryAt = Instant.now(); + final var inverter = context.getParent(); + inverter.setRequestedState(S64201RequestedState.OFF); } @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - var inverter = context.getParent(); - switch (inverter.getCurrentState()) { - case STANDBY: - case GRID_CONNECTED: - case GRID_PRE_CONNECTED: - case THROTTLED: - case PRECHARGE: - case MPPT: - case STARTING: - case OFF: - case SHUTTING_DOWN: - case SLEEPING: - // no more error pending - return State.UNDEFINED; - case UNDEFINED: - // TODO - break; - case FAULT: - case NO_ERROR_PENDING: - /* - * According to Manual: to more errors to be acknowledged - try to turn OFF - */ - // TODO this should not be set all the time - inverter.setRequestedState(S64201RequestedState.OFF); - break; + final var inverter = context.getParent(); + if (!inverter.hasFailure()) { + return State.GO_STOPPED; } - - if (Duration.between(this.entryAt, Instant.now()).getSeconds() > WAIT_SECONDS) { - // Try again - return State.UNDEFINED; - } - return State.ERROR; } - } diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/GoRunningHandler.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/GoRunningHandler.java index 1779232b7ac..9ca5d58e034 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/GoRunningHandler.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/GoRunningHandler.java @@ -1,78 +1,47 @@ package io.openems.edge.batteryinverter.kaco.blueplanetgridsave.statemachine; -import java.time.Duration; import java.time.Instant; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.BatteryInverterKacoBlueplanetGridsave; import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.KacoSunSpecModel.S64201.S64201RequestedState; import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.statemachine.StateMachine.State; +import io.openems.edge.common.startstop.StartStop; import io.openems.edge.common.statemachine.StateHandler; public class GoRunningHandler extends StateHandler { - private Instant lastAttempt = Instant.MIN; - private int attemptCounter = 0; + private Instant entryAt = Instant.MIN; @Override - protected void onEntry(Context context) throws OpenemsNamedException { - this.lastAttempt = Instant.MIN; - this.attemptCounter = 0; - var inverter = context.getParent(); - inverter._setMaxStartAttempts(false); + protected void onEntry(Context context) { + this.entryAt = Instant.now(context.clock); } @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - var inverter = context.getParent(); - - // Has Faults -> abort - if (inverter.hasFaults()) { - return State.UNDEFINED; + final var inverter = context.getParent(); + if (inverter.hasFailure()) { + return State.ERROR; } - switch (inverter.getCurrentState()) { - case GRID_CONNECTED: - // All Good - - case THROTTLED: - // if inverter is throttled, full power is not available, but the device - // is still working - return State.RUNNING; + final var now = Instant.now(context.clock); + if (context.isTimeout(now, this.entryAt)) { + inverter._setMaxStartTimeout(true); + return State.ERROR; + } - case FAULT: - case GRID_PRE_CONNECTED: - case MPPT: - case NO_ERROR_PENDING: - case OFF: - case PRECHARGE: - case SHUTTING_DOWN: - case SLEEPING: - case STANDBY: - case STARTING: - case UNDEFINED: - // Not yet running... + if (inverter.getStartStopTarget() == StartStop.STOP) { + return State.GO_STOPPED; } - var isMaxStartTimePassed = Duration.between(this.lastAttempt, Instant.now()) - .getSeconds() > BatteryInverterKacoBlueplanetGridsave.RETRY_COMMAND_SECONDS; - if (!isMaxStartTimePassed) { - // Still waiting... - return State.GO_RUNNING; + if (inverter.isRunning()) { + return State.RUNNING; } - if (this.attemptCounter > BatteryInverterKacoBlueplanetGridsave.RETRY_COMMAND_MAX_ATTEMPTS) { - // Too many tries - inverter._setMaxStartAttempts(true); - return State.UNDEFINED; - } else { - // Trying to switch on - inverter.setRequestedState(S64201RequestedState.GRID_CONNECTED); - this.lastAttempt = Instant.now(); - this.attemptCounter++; - return State.GO_RUNNING; + // Trying to switch on + inverter.setRequestedState(S64201RequestedState.GRID_CONNECTED); + return State.GO_RUNNING; - } } } diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/GoStoppedHandler.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/GoStoppedHandler.java index d793a6dfea7..c28f540555d 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/GoStoppedHandler.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/GoStoppedHandler.java @@ -1,68 +1,46 @@ package io.openems.edge.batteryinverter.kaco.blueplanetgridsave.statemachine; -import java.time.Duration; import java.time.Instant; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.BatteryInverterKacoBlueplanetGridsave; import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.KacoSunSpecModel.S64201.S64201RequestedState; import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.statemachine.StateMachine.State; import io.openems.edge.common.statemachine.StateHandler; public class GoStoppedHandler extends StateHandler { - private Instant lastAttempt = Instant.MIN; - private int attemptCounter = 0; + private Instant entryAt = Instant.MIN; @Override protected void onEntry(Context context) { - this.lastAttempt = Instant.MIN; - this.attemptCounter = 0; + this.entryAt = Instant.now(context.clock); } @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - var inverter = context.getParent(); - - switch (inverter.getCurrentState()) { - case OFF: - case STANDBY: - // All Good - return State.STOPPED; - - case GRID_CONNECTED: - case THROTTLED: - case FAULT: - case GRID_PRE_CONNECTED: - case MPPT: - case NO_ERROR_PENDING: - case PRECHARGE: - case SHUTTING_DOWN: - case SLEEPING: - case STARTING: - case UNDEFINED: - // Not yet running... + final var inverter = context.getParent(); + + // Due to the low battery DC voltage, the inverter receives a battery low + // voltage error in the stop process and goes into a fault state that can be + // ignored during this time. Due to this situation, hasFault is preferred + // instead of hasFailure. + if (inverter.hasFaults()) { + inverter._setInverterCurrentStateFault(true); + return State.ERROR; } - var isMaxStartTimePassed = Duration.between(this.lastAttempt, Instant.now()) - .getSeconds() > BatteryInverterKacoBlueplanetGridsave.RETRY_COMMAND_SECONDS; - if (!isMaxStartTimePassed) { - // Still waiting... - return State.GO_STOPPED; + final var now = Instant.now(context.clock); + if (context.isTimeout(now, this.entryAt)) { + inverter._setMaxStartTimeout(true); + return State.ERROR; } - if (this.attemptCounter > BatteryInverterKacoBlueplanetGridsave.RETRY_COMMAND_MAX_ATTEMPTS) { - // Too many tries - inverter._setMaxStopAttempts(true); - return State.UNDEFINED; - - } else { - // Trying to switch off - inverter.setRequestedState(S64201RequestedState.OFF); - this.lastAttempt = Instant.now(); - this.attemptCounter++; - return State.GO_STOPPED; + if (inverter.isShutdown()) { + return State.STOPPED; } - } + // Trying to switch off + inverter.setRequestedState(S64201RequestedState.OFF); + return State.GO_STOPPED; + } } diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/RunningHandler.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/RunningHandler.java index 76301531cb8..986127e902e 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/RunningHandler.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/RunningHandler.java @@ -15,39 +15,16 @@ public class RunningHandler extends StateHandler { @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { var inverter = context.getParent(); - - if (inverter.hasFaults()) { - return State.UNDEFINED; + if (inverter.hasFailure() || !inverter.isRunning()) { + return State.ERROR; } - switch (inverter.getCurrentState()) { - case FAULT: - case GRID_PRE_CONNECTED: - case MPPT: - case NO_ERROR_PENDING: - case OFF: - case PRECHARGE: - case SHUTTING_DOWN: - case SLEEPING: - case STANDBY: - case STARTING: - case UNDEFINED: - return State.UNDEFINED; - - case GRID_CONNECTED: - // All Good - - case THROTTLED: - // if inverter is throttled, full power is not available, but the device - // is still working + if (inverter.getStartStopTarget() == StartStop.STOP) { + return State.GO_STOPPED; } - // Mark as started - inverter._setStartStop(StartStop.START); - - // Apply Active and Reactive Power Set-Points this.applyPower(context); - + inverter._setStartStop(StartStop.START); return State.RUNNING; } @@ -75,5 +52,4 @@ private void applyPower(Context context) throws OpenemsNamedException { var varSetPct = context.setReactivePower * 100F / maxApparentPower; varSetPctChannel.setNextWriteValue(varSetPct); } - } diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/StateMachine.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/StateMachine.java index 743dca4fe1a..ab70913b54d 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/StateMachine.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/StateMachine.java @@ -51,20 +51,13 @@ public StateMachine(State initialState) { @Override public StateHandler getStateHandler(State state) { - switch (state) { - case UNDEFINED: - return new UndefinedHandler(); - case GO_RUNNING: - return new GoRunningHandler(); - case RUNNING: - return new RunningHandler(); - case GO_STOPPED: - return new GoStoppedHandler(); - case STOPPED: - return new StoppedHandler(); - case ERROR: - return new ErrorHandler(); - } - throw new IllegalArgumentException("Unknown State [" + state + "]"); + return switch (state) { + case UNDEFINED -> new UndefinedHandler(); + case GO_RUNNING -> new GoRunningHandler(); + case RUNNING -> new RunningHandler(); + case GO_STOPPED -> new GoStoppedHandler(); + case STOPPED -> new StoppedHandler(); + case ERROR -> new ErrorHandler(); + }; } } diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/StoppedHandler.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/StoppedHandler.java index 75a415711ed..c2a6b23cca2 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/StoppedHandler.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/StoppedHandler.java @@ -8,11 +8,17 @@ public class StoppedHandler extends StateHandler { @Override public State runAndGetNextState(Context context) { - // Mark as stopped - var inverter = context.getParent(); - inverter._setStartStop(StartStop.STOP); + final var inverter = context.getParent(); + + if (inverter.hasFaults()) { + return State.ERROR; + } + + if (inverter.getStartStopTarget() == StartStop.START) { + return State.GO_RUNNING; + } + inverter._setStartStop(StartStop.STOP); return State.STOPPED; } - } diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/UndefinedHandler.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/UndefinedHandler.java index bd6b4927bac..c177bd4538a 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/UndefinedHandler.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/UndefinedHandler.java @@ -7,30 +7,24 @@ public class UndefinedHandler extends StateHandler { @Override public State runAndGetNextState(Context context) { - var inverter = context.getParent(); + final var inverter = context.getParent(); - switch (inverter.getStartStopTarget()) { - case UNDEFINED: - // Stuck in UNDEFINED State + if (inverter.getCurrentState().isUndefined()) { return State.UNDEFINED; + } - case START: - // force START - if (inverter.hasFaults()) { - // Has Faults -> error handling - return State.ERROR; - } else { - // No Faults -> start - return State.GO_RUNNING; - } - - case STOP: - // force STOP - return State.GO_STOPPED; + if (inverter.hasFailure()) { + return State.ERROR; } - assert false; - return State.UNDEFINED; // can never happen - } + if (inverter.isRunning()) { + return State.RUNNING; + } + if (inverter.isShutdown()) { + return State.STOPPED; + } + + return State.GO_STOPPED; + } } diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/test/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsaveImplTest.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/test/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsaveImplTest.java index 7a17c2a68a0..d4d2c215065 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/test/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsaveImplTest.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/test/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsaveImplTest.java @@ -90,6 +90,7 @@ public void prepareTest() throws Exception { addChannel.invoke(sut, KacoSunSpecModel.S64201.WATCHDOG.getChannelId()); addChannel.invoke(sut, KacoSunSpecModel.S64201.W_SET_PCT.getChannelId()); addChannel.invoke(sut, KacoSunSpecModel.S64201.WPARAM_RMP_TMS.getChannelId()); + addChannel.invoke(sut, KacoSunSpecModel.S64201.ST_VND.getChannelId()); test.activate(MyConfig.create() // .setId(BATTERY_INVERTER_ID) // @@ -108,7 +109,7 @@ public void testStart() throws Exception { .output(STATE_MACHINE, State.UNDEFINED)) // .next(new TestCase() // .timeleap(clock, 4, ChronoUnit.SECONDS) // - .output(STATE_MACHINE, State.GO_RUNNING)) // + .output(STATE_MACHINE, State.STOPPED)) // .next(new TestCase() // .timeleap(clock, 1, ChronoUnit.SECONDS) // .input(CURRENT_STATE, S64201CurrentState.GRID_CONNECTED) // 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 d311907ea13..a63d14f76fd 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 @@ -220,7 +220,7 @@ public int getPowerPrecision() { private static final int SUNSPEC_64800 = 40225; // MESA-PCS Extensions @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { // Register + protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this, // new FC3ReadRegistersTask(SUNSPEC_1, Priority.LOW, // m(BatteryInverterRefuStore88k.ChannelId.ID_1, new UnsignedWordElement(SUNSPEC_1)), // 40002 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 b41b9e77a2c..5a65149220b 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 @@ -391,7 +391,7 @@ public ModbusSlaveTable getModbusSlaveTable(AccessMode accessMode) { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this, // new FC3ReadRegistersTask(1, Priority.HIGH, // m(BatteryInverterSinexcel.ChannelId.MANUFACTURER_AND_MODEL_NUMBER, // diff --git a/io.openems.edge.batteryinverter.sunspec/src/io/openems/edge/batteryinverter/sunspec/AbstractSunSpecBatteryInverter.java b/io.openems.edge.batteryinverter.sunspec/src/io/openems/edge/batteryinverter/sunspec/AbstractSunSpecBatteryInverter.java index 646ca7f453b..6e4d8e8a637 100644 --- a/io.openems.edge.batteryinverter.sunspec/src/io/openems/edge/batteryinverter/sunspec/AbstractSunSpecBatteryInverter.java +++ b/io.openems.edge.batteryinverter.sunspec/src/io/openems/edge/batteryinverter/sunspec/AbstractSunSpecBatteryInverter.java @@ -23,7 +23,7 @@ public abstract class AbstractSunSpecBatteryInverter extends AbstractOpenemsSunS public AbstractSunSpecBatteryInverter(Map activeModels, io.openems.edge.common.channel.ChannelId[] firstInitialChannelIds, - io.openems.edge.common.channel.ChannelId[]... furtherInitialChannelIds) throws OpenemsException { + io.openems.edge.common.channel.ChannelId[]... furtherInitialChannelIds) { super(activeModels, firstInitialChannelIds, furtherInitialChannelIds); } diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/AbstractOpenemsModbusComponent.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/AbstractOpenemsModbusComponent.java index b429a7177cb..7bf6e9e249d 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/AbstractOpenemsModbusComponent.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/AbstractOpenemsModbusComponent.java @@ -230,7 +230,7 @@ public BridgeModbus getBridgeModbus() { * @return the {@link ModbusProtocol} * @throws OpenemsException on error */ - protected ModbusProtocol getModbusProtocol() throws OpenemsException { + protected ModbusProtocol getModbusProtocol() { var protocol = this.protocol; if (protocol != null) { return protocol; @@ -251,7 +251,7 @@ public void retryModbusCommunication() { * @return the ModbusProtocol * @throws OpenemsException on error */ - protected abstract ModbusProtocol defineModbusProtocol() throws OpenemsException; + protected abstract ModbusProtocol defineModbusProtocol(); /** * Maps an Element to one or more ModbusChannels using converters, that convert diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/ModbusProtocol.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/ModbusProtocol.java index e4e922aead0..3b6cac58e6c 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/ModbusProtocol.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/ModbusProtocol.java @@ -1,6 +1,5 @@ package io.openems.edge.bridge.modbus.api; -import io.openems.common.exceptions.OpenemsException; import io.openems.edge.bridge.modbus.api.task.Task; import io.openems.edge.common.taskmanager.TasksManager; @@ -21,9 +20,8 @@ public class ModbusProtocol { * * @param parent the {@link AbstractOpenemsModbusComponent} parent * @param tasks the {@link Task}s - * @throws OpenemsException on error */ - public ModbusProtocol(AbstractOpenemsModbusComponent parent, Task... tasks) throws OpenemsException { + public ModbusProtocol(AbstractOpenemsModbusComponent parent, Task... tasks) { this.parent = parent; this.addTasks(tasks); } @@ -32,9 +30,8 @@ public ModbusProtocol(AbstractOpenemsModbusComponent parent, Task... tasks) thro * Adds Tasks to the Protocol. * * @param tasks the tasks - * @throws OpenemsException on error */ - public synchronized void addTasks(Task... tasks) throws OpenemsException { + public synchronized void addTasks(Task... tasks) { for (Task task : tasks) { this.addTask(task); } @@ -44,9 +41,8 @@ public synchronized void addTasks(Task... tasks) throws OpenemsException { * Adds a Task to the Protocol. * * @param task the task - * @throws OpenemsException on plausibility error */ - public synchronized void addTask(Task task) throws OpenemsException { + public synchronized void addTask(Task task) { // add the the parent to the Task task.setParent(this.parent); // fill taskManager diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/ModbusUtils.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/ModbusUtils.java index e2ebb682479..48dc3a52b99 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/ModbusUtils.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/ModbusUtils.java @@ -1,166 +1,133 @@ package io.openems.edge.bridge.modbus.api; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.ArrayList; +import static io.openems.edge.bridge.modbus.api.task.Task.ExecuteState.NO_OP; +import static java.util.Collections.emptyList; +import static java.util.concurrent.CompletableFuture.completedFuture; + import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.BiPredicate; import java.util.function.Function; import java.util.stream.Collectors; -import java.util.stream.IntStream; +import java.util.stream.Stream; import com.ghgande.j2mod.modbus.procimg.InputRegister; import com.ghgande.j2mod.modbus.procimg.Register; -import io.openems.common.exceptions.OpenemsException; import io.openems.edge.bridge.modbus.api.element.ModbusRegisterElement; import io.openems.edge.bridge.modbus.api.task.FC3ReadRegistersTask; import io.openems.edge.bridge.modbus.api.task.Task; +import io.openems.edge.bridge.modbus.api.task.Task.ExecuteState; import io.openems.edge.common.taskmanager.Priority; public class ModbusUtils { + /** + * Predefined `retryPredicate` that triggers a retry whenever `value` is null, + * i.e. on any error. + * + * @param the Type of the element + * @param executeState the Task {@link ExecuteState} + * @param value the value + * @return true for retry + */ + public static boolean retryOnNull(ExecuteState executeState, T value) { + return value == null; + } + + /** + * Predefined `retryPredicate` that never retries. + * + * @param the Type of the element + * @param executeState the Task {@link ExecuteState} + * @param value the value + * @return always false + */ + public static boolean doNotRetry(ExecuteState executeState, T value) { + return false; + } + /** * Reads given Element once from Modbus. * - * @param the Type of the element - * @param modbusProtocol the {@link ModbusProtocol}, that is linked with a - * {@link BridgeModbus} - * @param element the {@link ModbusRegisterElement} - * @param tryAgainOnError if true, tries to read till it receives a value; if - * false, stops after first try and possibly return null + * @param the Type of the element + * @param modbusProtocol the {@link ModbusProtocol}, that is linked with a + * {@link BridgeModbus} + * @param retryPredicate yield true to retry reading values; false otherwise. + * Parameters are the {@link ExecuteState} of the entire + * task and the individual element value + * @param element the {@link ModbusRegisterElement} * @return a future value, e.g. a Integer or null (if tryAgainOnError is false) - * @throws OpenemsException on error with the {@link ModbusProtocol} object */ - public static CompletableFuture readELementOnce(ModbusProtocol modbusProtocol, - ModbusRegisterElement element, boolean tryAgainOnError) throws OpenemsException { - // Prepare result - final var result = new CompletableFuture(); - - // Activate task - final Task task = new FC3ReadRegistersTask(element.startAddress, Priority.HIGH, element); - modbusProtocol.addTask(task); - - // Register listener for element - element.onUpdateCallback(value -> { - if (value == null) { - if (tryAgainOnError) { - return; - } - result.complete(null); - } - // do not try again - modbusProtocol.removeTask(task); - result.complete(value); - }); - - return result; + @SuppressWarnings("unchecked") + public static CompletableFuture readElementOnce(ModbusProtocol modbusProtocol, + BiPredicate retryPredicate, ModbusRegisterElement element) { + return readElementsOnce(modbusProtocol, retryPredicate, // + new ModbusRegisterElement[] { element }) // + .thenApply(rsr -> ((ReadElementsResult) rsr).values().get(0)); } /** * Reads given Elements once from Modbus. * - * @param the Type of the elements - * @param modbusProtocol the {@link ModbusProtocol}, that is linked with a - * {@link BridgeModbus} - * @param elements the {@link ModbusRegisterElement}s - * @param tryAgainOnError if true, tries to read till it receives a value on - * first register; if false, stops after first try and - * possibly return null - * @return a future array of values, e.g. Integer[] or null (if tryAgainOnError - * is false). If an array is returned, it is guaranteed to have the same - * length as `elements` - * @throws OpenemsException on error with the {@link ModbusProtocol} object + * @param the Type of the elements + * @param modbusProtocol the {@link ModbusProtocol}, that is linked with a + * {@link BridgeModbus} + * @param retryPredicate yield true to retry reading values. Parameters are the + * Task success state and individual element value + * @param elements the {@link ModbusRegisterElement}s + * @return a future array of values, e.g. Integer[] or null. If an array is + * returned, it is guaranteed to have the same length as `elements` */ - public static CompletableFuture> readELementsOnce(ModbusProtocol modbusProtocol, - ModbusRegisterElement[] elements, boolean tryAgainOnError) throws OpenemsException { + @SafeVarargs + public static CompletableFuture> readElementsOnce(ModbusProtocol modbusProtocol, + BiPredicate retryPredicate, ModbusRegisterElement... elements) { if (elements.length == 0) { - return CompletableFuture.completedFuture(Collections.emptyList()); + return completedFuture(new ReadElementsResult<>(NO_OP, emptyList())); } - // Prepare result - final var result = new CompletableFuture>(); + // Register listener for each element + final var executeState = new AtomicReference(ExecuteState.NO_OP); // Activate task - final Task task = new FC3ReadRegistersTask(elements[0].startAddress, Priority.HIGH, elements); + final Task task = new FC3ReadRegistersTask(executeState::set, // + elements[0].startAddress, Priority.HIGH, elements); modbusProtocol.addTask(task); - // Register listener for each element - final var subResults = new ArrayList>(); - { + @SuppressWarnings("unchecked") + final var subResults = (CompletableFuture[]) new CompletableFuture[elements.length]; + for (var i = 0; i < elements.length; i++) { var subResult = new CompletableFuture(); - subResults.add(subResult); - elements[0].onUpdateCallback(value -> { - if (value == null) { - if (tryAgainOnError) { - // try again - return; - } else { - result.complete(null); - } - } - - // do not try again - modbusProtocol.removeTask(task); - subResult.complete(value); - }); - } - - for (var i = 1; i < elements.length; i++) { - var subResult = new CompletableFuture(); - subResults.add(subResult); + subResults[i] = subResult; elements[i].onUpdateCallback(value -> { - modbusProtocol.removeTask(task); - subResult.complete(value); + if (retryPredicate.test(executeState.get(), value)) { + // try again + return; + } else { + // do not try again + subResult.complete(value); + } }); } - CompletableFuture // - .allOf(subResults.toArray(new CompletableFuture[subResults.size()])) // - .thenAccept(ignored -> result.complete(// - subResults.stream() // - .map(CompletableFuture::join) // - .toList())); - - return result; + return CompletableFuture // + .allOf(subResults) // + .thenApply(ignore -> { + // remove task + modbusProtocol.removeTask(task); + + // return combined future + return new ReadElementsResult<>(executeState.get(), // + Stream.of(subResults) // + .map(CompletableFuture::join) // + .toList()); + }); } - /** - * Converts upper/lower bytes to Short. - * - * @param value the int value - * @param upperBytes 1 = upper two bytes, 0 = lower two bytes - * @return the Short - */ - public static Short convert(int value, int upperBytes) { - var b = ByteBuffer.allocate(4); - b.order(ByteOrder.LITTLE_ENDIAN); - b.putInt(value); - - var byte0 = b.get(upperBytes * 2); - var byte1 = b.get(upperBytes * 2 + 1); - - var shortBuf = ByteBuffer.allocate(2); - shortBuf.order(ByteOrder.LITTLE_ENDIAN); - shortBuf.put(0, byte0); - shortBuf.put(1, byte1); + public static record ReadElementsResult(ExecuteState executeState, List values) { - return shortBuf.getShort(); - } - - /** - * Converts a byte array to a String in the form "00C1 00B2". - * - * @param data byte array - * @return string - */ - public static String byteArrayToHexString(byte[] data) { - return IntStream.range(0, data.length / 2) // - .mapToObj(i -> String.format("%2s%2s", // - Integer.toHexString(data[i]), Integer.toHexString(data[i + 1])).replace(' ', '0')) - .collect(Collectors.joining(" ")); } /** diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractReadDigitalInputsTask.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractReadDigitalInputsTask.java index a7a6cec7edc..5a918fe1d5c 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractReadDigitalInputsTask.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractReadDigitalInputsTask.java @@ -1,5 +1,6 @@ package io.openems.edge.bridge.modbus.api.task; +import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -17,9 +18,9 @@ public abstract class AbstractReadDigitalInputsTask // extends AbstractReadTask { - public AbstractReadDigitalInputsTask(String name, Class responseClazz, int startAddress, - Priority priority, CoilElement... elements) { - super(name, responseClazz, CoilElement.class, startAddress, priority, elements); + public AbstractReadDigitalInputsTask(String name, Consumer onExecute, Class responseClazz, + int startAddress, Priority priority, CoilElement... elements) { + super(name, onExecute, responseClazz, CoilElement.class, startAddress, priority, elements); } @Override diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractReadRegistersTask.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractReadRegistersTask.java index 936971a7464..24f691d6c1e 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractReadRegistersTask.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractReadRegistersTask.java @@ -1,6 +1,7 @@ package io.openems.edge.bridge.modbus.api.task; import java.util.Arrays; +import java.util.function.Consumer; import com.ghgande.j2mod.modbus.msg.ModbusRequest; import com.ghgande.j2mod.modbus.msg.ModbusResponse; @@ -17,9 +18,9 @@ public abstract class AbstractReadRegistersTask // extends AbstractReadTask { - public AbstractReadRegistersTask(String name, Class responseClazz, int startAddress, Priority priority, - ModbusElement... elements) { - super(name, responseClazz, ModbusRegisterElement.class, startAddress, priority, elements); + public AbstractReadRegistersTask(String name, Consumer onExecute, Class responseClazz, + int startAddress, Priority priority, ModbusElement... elements) { + super(name, onExecute, responseClazz, ModbusRegisterElement.class, startAddress, priority, elements); } @SuppressWarnings("unchecked") diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractReadTask.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractReadTask.java index 66c104f6fe8..ef5c010c268 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractReadTask.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractReadTask.java @@ -2,6 +2,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.function.Consumer; import java.util.stream.Stream; import org.slf4j.Logger; @@ -33,9 +34,9 @@ public abstract class AbstractReadTask elementClazz; - public AbstractReadTask(String name, Class responseClazz, Class elementClazz, int startAddress, - Priority priority, ModbusElement... elements) { - super(name, responseClazz, startAddress, elements); + public AbstractReadTask(String name, Consumer onExecute, Class responseClazz, + Class elementClazz, int startAddress, Priority priority, ModbusElement... elements) { + super(name, onExecute, responseClazz, startAddress, elements); this.elementClazz = elementClazz; this.priority = priority; } @@ -49,19 +50,26 @@ public ExecuteState execute(AbstractModbusBridge bridge) { try { var result = this.parseResponse(response); validateResponse(result, this.length); + + // NOTE: onExecute has to be called before filling elements; but OK could be + // wrong if fillElements throws an exception. + this.onExecute.accept(ExecuteState.OK); this.fillElements(result); + return ExecuteState.OK; + } catch (OpenemsException e1) { logError(this.log, e1, "Parsing Response failed."); throw e1; } - return ExecuteState.OK; } catch (Exception e) { + var executeState = new ExecuteState.Error(e); + this.onExecute.accept(executeState); + // Invalidate Elements Stream.of(this.elements).forEach(el -> el.invalidate(bridge)); - - return ExecuteState.ERROR; + return executeState; } } diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractTask.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractTask.java index 60ac8520114..35c419f539e 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractTask.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractTask.java @@ -3,6 +3,7 @@ import java.util.Arrays; import java.util.concurrent.TimeUnit; import java.util.function.BiConsumer; +import java.util.function.Consumer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,6 +31,7 @@ public abstract non-sealed class AbstractTask implements Task { protected final String name; + protected final Consumer onExecute; protected final Class responseClazz; protected final int startAddress; protected final int length; @@ -39,8 +41,10 @@ public abstract non-sealed class AbstractTask responseClazz, int startAddress, ModbusElement... elements) { + public AbstractTask(String name, Consumer onExecute, Class responseClazz, int startAddress, + ModbusElement... elements) { this.name = name; + this.onExecute = onExecute; this.responseClazz = responseClazz; this.startAddress = startAddress; this.elements = elements; @@ -87,7 +91,7 @@ public AbstractOpenemsModbusComponent getParent() { * WriteTask. * * @param bridge the Modbus-Bridge - * @return the number of executed Sub-Tasks + * @return the {@link ExecuteState} */ public abstract ExecuteState execute(AbstractModbusBridge bridge); diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractWriteTask.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractWriteTask.java index 40460ca1f75..e8d2335c259 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractWriteTask.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractWriteTask.java @@ -1,5 +1,7 @@ package io.openems.edge.bridge.modbus.api.task; +import java.util.function.Consumer; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -16,8 +18,9 @@ public abstract class AbstractWriteTask // extends AbstractTask implements WriteTask { - public AbstractWriteTask(String name, Class responseClazz, int startAddress, ModbusElement... elements) { - super(name, responseClazz, startAddress, elements); + public AbstractWriteTask(String name, Consumer onExecute, Class responseClazz, + int startAddress, ModbusElement... elements) { + super(name, onExecute, responseClazz, startAddress, elements); } /** @@ -45,19 +48,26 @@ public abstract static class Single responseClazz, int startAddress, ELEMENT element) { - super(name, responseClazz, startAddress, element); + public Single(String name, Consumer onExecute, Class responseClazz, int startAddress, + ELEMENT element) { + super(name, onExecute, responseClazz, startAddress, element); this.element = element; } @Override public final ExecuteState execute(AbstractModbusBridge bridge) { + var result = this._execute(bridge); + this.onExecute.accept(result); + return result; + } + + private ExecuteState _execute(AbstractModbusBridge bridge) { final REQUEST request; try { request = this.createModbusRequest(); } catch (OpenemsException e) { logError(this.log, e, "Creating Modbus Request failed."); - return ExecuteState.ERROR; + return new ExecuteState.Error(e); } if (request == null) { @@ -70,7 +80,7 @@ public final ExecuteState execute(AbstractModbusBridge bridge) { } catch (Exception e) { // On error a log message has already been logged - return ExecuteState.ERROR; + return new ExecuteState.Error(e); } } diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC16WriteRegistersTask.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC16WriteRegistersTask.java index 0c16e83e897..7767f54674b 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC16WriteRegistersTask.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC16WriteRegistersTask.java @@ -13,6 +13,7 @@ import com.ghgande.j2mod.modbus.msg.WriteMultipleRegistersResponse; import com.ghgande.j2mod.modbus.procimg.Register; +import io.openems.common.utils.FunctionUtils; import io.openems.edge.bridge.modbus.api.AbstractModbusBridge; import io.openems.edge.bridge.modbus.api.LogVerbosity; import io.openems.edge.bridge.modbus.api.ModbusUtils; @@ -29,11 +30,21 @@ public class FC16WriteRegistersTask private final Logger log = LoggerFactory.getLogger(FC16WriteRegistersTask.class); public FC16WriteRegistersTask(int startAddress, ModbusElement... elements) { - super("FC16WriteRegisters", WriteMultipleRegistersResponse.class, startAddress, elements); + this(FunctionUtils::doNothing, startAddress, elements); + } + + public FC16WriteRegistersTask(Consumer onExecute, int startAddress, ModbusElement... elements) { + super("FC16WriteRegisters", onExecute, WriteMultipleRegistersResponse.class, startAddress, elements); } @Override - public ExecuteState execute(AbstractModbusBridge bridge) { + public final ExecuteState execute(AbstractModbusBridge bridge) { + var result = this._execute(bridge); + this.onExecute.accept(result); + return result; + } + + private ExecuteState _execute(AbstractModbusBridge bridge) { var requests = mergeWriteRegisters(this.elements, message -> this.log.warn(message)).stream() // .map(e -> new WriteMultipleRegistersRequest(e.startAddress(), e.getRegisters())) // .toList(); @@ -42,7 +53,7 @@ public ExecuteState execute(AbstractModbusBridge bridge) { return ExecuteState.NO_OP; } - boolean hasError = false; + Exception lastError = null; for (var request : requests) { try { this.executeRequest(bridge, request); @@ -52,12 +63,12 @@ public ExecuteState execute(AbstractModbusBridge bridge) { // Invalidate Elements Stream.of(this.elements).forEach(el -> el.invalidate(bridge)); - hasError = true; + lastError = e; } } - if (hasError) { - return ExecuteState.ERROR; + if (lastError != null) { + return new ExecuteState.Error(lastError); } else { return ExecuteState.OK; } diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC1ReadCoilsTask.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC1ReadCoilsTask.java index 859db8748aa..0c546569033 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC1ReadCoilsTask.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC1ReadCoilsTask.java @@ -1,9 +1,12 @@ package io.openems.edge.bridge.modbus.api.task; +import java.util.function.Consumer; + import com.ghgande.j2mod.modbus.msg.ReadCoilsRequest; import com.ghgande.j2mod.modbus.msg.ReadCoilsResponse; import com.ghgande.j2mod.modbus.util.BitVector; +import io.openems.common.utils.FunctionUtils; import io.openems.edge.bridge.modbus.api.element.CoilElement; import io.openems.edge.common.taskmanager.Priority; @@ -14,7 +17,12 @@ public class FC1ReadCoilsTask extends AbstractReadDigitalInputsTask { public FC1ReadCoilsTask(int startAddress, Priority priority, CoilElement... elements) { - super("FC1ReadCoils", ReadCoilsResponse.class, startAddress, priority, elements); + this(FunctionUtils::doNothing, startAddress, priority, elements); + } + + public FC1ReadCoilsTask(Consumer onExecute, int startAddress, Priority priority, + CoilElement... elements) { + super("FC1ReadCoils", onExecute, ReadCoilsResponse.class, startAddress, priority, elements); } @Override diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC2ReadInputsTask.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC2ReadInputsTask.java index bd42892fa01..462dad3b5d0 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC2ReadInputsTask.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC2ReadInputsTask.java @@ -1,9 +1,12 @@ package io.openems.edge.bridge.modbus.api.task; +import java.util.function.Consumer; + import com.ghgande.j2mod.modbus.msg.ReadInputDiscretesRequest; import com.ghgande.j2mod.modbus.msg.ReadInputDiscretesResponse; import com.ghgande.j2mod.modbus.util.BitVector; +import io.openems.common.utils.FunctionUtils; import io.openems.edge.bridge.modbus.api.element.CoilElement; import io.openems.edge.common.taskmanager.Priority; @@ -15,7 +18,12 @@ public class FC2ReadInputsTask extends AbstractReadDigitalInputsTask { public FC2ReadInputsTask(int startAddress, Priority priority, CoilElement... elements) { - super("FC2ReadCoils", ReadInputDiscretesResponse.class, startAddress, priority, elements); + this(FunctionUtils::doNothing, startAddress, priority, elements); + } + + public FC2ReadInputsTask(Consumer onExecute, int startAddress, Priority priority, + CoilElement... elements) { + super("FC2ReadCoils", onExecute, ReadInputDiscretesResponse.class, startAddress, priority, elements); } @Override diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC3ReadRegistersTask.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC3ReadRegistersTask.java index d1d104a28fd..420c406e0c7 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC3ReadRegistersTask.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC3ReadRegistersTask.java @@ -1,10 +1,13 @@ package io.openems.edge.bridge.modbus.api.task; +import java.util.function.Consumer; + import com.ghgande.j2mod.modbus.msg.ReadMultipleRegistersRequest; import com.ghgande.j2mod.modbus.msg.ReadMultipleRegistersResponse; import com.ghgande.j2mod.modbus.procimg.Register; import io.openems.common.exceptions.OpenemsException; +import io.openems.common.utils.FunctionUtils; import io.openems.edge.bridge.modbus.api.ModbusUtils; import io.openems.edge.bridge.modbus.api.element.ModbusElement; import io.openems.edge.common.taskmanager.Priority; @@ -17,7 +20,13 @@ public class FC3ReadRegistersTask extends AbstractReadRegistersTask { public FC3ReadRegistersTask(int startAddress, Priority priority, ModbusElement... elements) { - super("FC3ReadHoldingRegisters", ReadMultipleRegistersResponse.class, startAddress, priority, elements); + this(FunctionUtils::doNothing, startAddress, priority, elements); + } + + public FC3ReadRegistersTask(Consumer onExecute, int startAddress, Priority priority, + ModbusElement... elements) { + super("FC3ReadHoldingRegisters", onExecute, ReadMultipleRegistersResponse.class, startAddress, priority, + elements); } @Override diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC4ReadInputRegistersTask.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC4ReadInputRegistersTask.java index e05190fd759..96d383e7859 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC4ReadInputRegistersTask.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC4ReadInputRegistersTask.java @@ -1,5 +1,6 @@ package io.openems.edge.bridge.modbus.api.task; +import java.util.function.Consumer; import java.util.stream.Stream; import com.ghgande.j2mod.modbus.msg.ReadInputRegistersRequest; @@ -8,6 +9,7 @@ import com.ghgande.j2mod.modbus.procimg.SimpleRegister; import io.openems.common.exceptions.OpenemsException; +import io.openems.common.utils.FunctionUtils; import io.openems.edge.bridge.modbus.api.ModbusUtils; import io.openems.edge.bridge.modbus.api.element.ModbusElement; import io.openems.edge.common.taskmanager.Priority; @@ -20,7 +22,12 @@ public class FC4ReadInputRegistersTask extends AbstractReadRegistersTask { public FC4ReadInputRegistersTask(int startAddress, Priority priority, ModbusElement... elements) { - super("FC4ReadInputRegisters", ReadInputRegistersResponse.class, startAddress, priority, elements); + this(FunctionUtils::doNothing, startAddress, priority, elements); + } + + public FC4ReadInputRegistersTask(Consumer onExecute, int startAddress, Priority priority, + ModbusElement... elements) { + super("FC4ReadInputRegisters", onExecute, ReadInputRegistersResponse.class, startAddress, priority, elements); } @Override diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC5WriteCoilTask.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC5WriteCoilTask.java index 25c3d3de17a..5f42a0069af 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC5WriteCoilTask.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC5WriteCoilTask.java @@ -1,9 +1,12 @@ package io.openems.edge.bridge.modbus.api.task; +import java.util.function.Consumer; + import com.ghgande.j2mod.modbus.msg.WriteCoilRequest; import com.ghgande.j2mod.modbus.msg.WriteCoilResponse; import io.openems.common.exceptions.OpenemsException; +import io.openems.common.utils.FunctionUtils; import io.openems.edge.bridge.modbus.api.element.CoilElement; /** @@ -13,7 +16,11 @@ public class FC5WriteCoilTask extends AbstractWriteTask.Single { public FC5WriteCoilTask(int startAddress, CoilElement element) { - super("FC5WriteCoil", WriteCoilResponse.class, startAddress, element); + this(FunctionUtils::doNothing, startAddress, element); + } + + public FC5WriteCoilTask(Consumer onExecute, int startAddress, CoilElement element) { + super("FC5WriteCoil", onExecute, WriteCoilResponse.class, startAddress, element); } @Override diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC6WriteRegisterTask.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC6WriteRegisterTask.java index c116f3907ab..ceff91159bd 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC6WriteRegisterTask.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC6WriteRegisterTask.java @@ -1,9 +1,12 @@ package io.openems.edge.bridge.modbus.api.task; +import java.util.function.Consumer; + import com.ghgande.j2mod.modbus.msg.WriteSingleRegisterRequest; import com.ghgande.j2mod.modbus.msg.WriteSingleRegisterResponse; import io.openems.common.exceptions.OpenemsException; +import io.openems.common.utils.FunctionUtils; import io.openems.edge.bridge.modbus.api.ModbusUtils; import io.openems.edge.bridge.modbus.api.element.AbstractSingleWordElement; @@ -11,7 +14,12 @@ public class FC6WriteRegisterTask extends AbstractWriteTask.Single> { public FC6WriteRegisterTask(int startAddress, AbstractSingleWordElement element) { - super("FC6WriteRegister", WriteSingleRegisterResponse.class, startAddress, element); + this(FunctionUtils::doNothing, startAddress, element); + } + + public FC6WriteRegisterTask(Consumer onExecute, int startAddress, + AbstractSingleWordElement element) { + super("FC6WriteRegister", onExecute, WriteSingleRegisterResponse.class, startAddress, element); } @Override diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/Task.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/Task.java index f810b548f94..2862df554ab 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/Task.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/Task.java @@ -58,12 +58,27 @@ public sealed interface Task extends ManagedTask permits AbstractTask, ReadTask, */ public ExecuteState execute(AbstractModbusBridge bridge); - public static enum ExecuteState { + public static sealed interface ExecuteState { + + public static final class Ok implements ExecuteState { + private Ok() { + } + } + /** Successfully executed request(s). */ - OK, + public static final ExecuteState.Ok OK = new ExecuteState.Ok(); + + public static final class NoOp implements ExecuteState { + private NoOp() { + } + } + /** No available requests -> no operation. */ - NO_OP, + public static final ExecuteState.NoOp NO_OP = new ExecuteState.NoOp(); + /** Executing request(s) failed. */ - ERROR; + public static final record Error(Exception exception) implements ExecuteState { + } + } } \ No newline at end of file diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/worker/ModbusWorker.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/worker/ModbusWorker.java index f51191f8631..68aed664b5d 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/worker/ModbusWorker.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/worker/ModbusWorker.java @@ -73,23 +73,21 @@ protected void forever() throws InterruptedException { // execute the task var result = this.execute.apply(task); - switch (result) { - case OK -> { + // NOTE: with Java 21 LTS this can be refactored to a pattern matching switch + // statement + if (result instanceof ExecuteState.Ok) { // no exception & at least one sub-task executed this.markComponentAsDefective(task.getParent(), false); - } - case ERROR -> { + } else if (result instanceof ExecuteState.NoOp) { + // did not execute anything + + } else if (result instanceof ExecuteState.Error) { this.markComponentAsDefective(task.getParent(), true); // invalidate elements of this task this.invalidate.accept(task.getElements()); } - - case NO_OP -> { - } - } - } /** diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/AbstractOpenemsSunSpecComponent.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/AbstractOpenemsSunSpecComponent.java index 5dafbd32b4d..1f95e69272b 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/AbstractOpenemsSunSpecComponent.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/AbstractOpenemsSunSpecComponent.java @@ -1,5 +1,10 @@ package io.openems.edge.bridge.modbus.sunspec; +import static com.ghgande.j2mod.modbus.Modbus.ILLEGAL_ADDRESS_EXCEPTION; +import static io.openems.edge.bridge.modbus.api.ModbusUtils.readElementOnce; +import static io.openems.edge.bridge.modbus.api.ModbusUtils.readElementsOnce; +import static java.util.concurrent.CompletableFuture.completedFuture; + import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -15,6 +20,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.ghgande.j2mod.modbus.ModbusSlaveException; import com.google.common.collect.Lists; import io.openems.common.exceptions.OpenemsException; @@ -25,13 +31,12 @@ import io.openems.edge.bridge.modbus.api.ModbusUtils; import io.openems.edge.bridge.modbus.api.element.DummyRegisterElement; import io.openems.edge.bridge.modbus.api.element.ModbusElement; -import io.openems.edge.bridge.modbus.api.element.ModbusRegisterElement; import io.openems.edge.bridge.modbus.api.element.UnsignedDoublewordElement; import io.openems.edge.bridge.modbus.api.element.UnsignedWordElement; 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.FC3ReadRegistersTask; -import io.openems.edge.bridge.modbus.api.task.Task; +import io.openems.edge.bridge.modbus.api.task.Task.ExecuteState; import io.openems.edge.common.channel.Channel; import io.openems.edge.common.taskmanager.Priority; @@ -70,7 +75,7 @@ public abstract class AbstractOpenemsSunSpecComponent extends AbstractOpenemsMod */ public AbstractOpenemsSunSpecComponent(Map activeModels, io.openems.edge.common.channel.ChannelId[] firstInitialChannelIds, - io.openems.edge.common.channel.ChannelId[]... furtherInitialChannelIds) throws OpenemsException { + io.openems.edge.common.channel.ChannelId[]... furtherInitialChannelIds) { super(firstInitialChannelIds, furtherInitialChannelIds); this.activeModels = activeModels; this.modbusProtocol = new ModbusProtocol(this); @@ -97,18 +102,10 @@ protected boolean activate(ComponentContext context, String id, String alias, bo throw new IllegalArgumentException("This modbus device is not SunSpec!"); } - try { - this.readNextBlock(40_002, expectedBlocks).thenRun(() -> { - this.isSunSpecInitializationCompleted = true; - this.onSunSpecInitializationCompleted(); - }); - - } catch (OpenemsException e) { - this.logWarn(this.log, "Error while reading SunSpec identifier block: " + e.getMessage()); - e.printStackTrace(); + this.readNextBlock(40_002, expectedBlocks).thenRun(() -> { this.isSunSpecInitializationCompleted = true; this.onSunSpecInitializationCompleted(); - } + }); }); return super.activate(context, id, alias, enabled, unitId, cm, modbusReference, modbusId); } @@ -128,16 +125,8 @@ protected final ModbusProtocol defineModbusProtocol() { * @throws OpenemsException on error */ private CompletableFuture isSunSpec() throws OpenemsException { - final var result = new CompletableFuture(); - ModbusUtils.readELementOnce(this.modbusProtocol, new UnsignedDoublewordElement(40_000), true) - .thenAccept(value -> { - if (value == 0x53756e53) { - result.complete(true); - } else { - result.complete(false); - } - }); - return result; + return readElementOnce(this.modbusProtocol, ModbusUtils::retryOnNull, new UnsignedDoublewordElement(40_000)) // + .thenApply(v -> v == 0x53756e53); } /** @@ -148,31 +137,47 @@ private CompletableFuture isSunSpec() throws OpenemsException { * @return a future that completes once reading the block finished * @throws OpenemsException on error */ - private CompletableFuture readNextBlock(int startAddress, Set remainingBlocks) - throws OpenemsException { - final var finished = new CompletableFuture(); - + private CompletableFuture readNextBlock(int startAddress, Set remainingBlocks) { // Finish if all expected Blocks have been read if (remainingBlocks.isEmpty()) { - finished.complete(null); + return completedFuture(null); } /* * Try to read block by block until all required blocks have been read or an - * END_OF_MAP register has been found. + * END_OF_MAP register has been found or reading fails permanently. * * It may still happen that a device does not have a valid END_OF_MAP register * and that some blocks are not read - especially when one component is used for * multiple devices like single and three phase inverter. */ - this.readElementsOnceTyped(new UnsignedWordElement(startAddress), new UnsignedWordElement(startAddress + 1)) - .thenAccept(values -> { - int blockId = values.get(0); + return readElementsOnce(this.modbusProtocol, // + // Retry if value is null and error is not "Illegal Data Address". + // Background: some SMA inverters do not provide an END_OF_MAP register. + (executeState, value) -> { + if (executeState instanceof ExecuteState.Error s) { + if (s.exception() instanceof ModbusSlaveException mse) { + if (mse.isType(ILLEGAL_ADDRESS_EXCEPTION)) { + return false; // do not retry + } + } + } + if (value != null) { + return false; // do not retry + } + return true; + }, // + + new UnsignedWordElement(startAddress), // Block-ID + new UnsignedWordElement(startAddress + 1)) // Length of Block + + .thenCompose(rer -> { + var values = rer.values(); + var blockId = values.get(0); // END_OF_MAP - if (blockId == 0xFFFF) { - finished.complete(null); - return; + if (blockId == null || blockId == 0xFFFF) { + return completedFuture(null); } // Handle SunSpec Block @@ -190,46 +195,23 @@ private CompletableFuture readNextBlock(int startAddress, Set rem if (activeEntry != null) { var sunSpecModel = activeEntry.getKey(); var priority = activeEntry.getValue(); - try { - this.addBlock(startAddress, sunSpecModel, priority); - remainingBlocks.remove(activeEntry.getKey().getBlockId()); - } catch (OpenemsException e) { - this.logWarn(this.log, "Error while adding SunSpec-Model [" + blockId - + "] starting at [" + startAddress + "]: " + e.getMessage()); - e.printStackTrace(); - } + this.addBlock(startAddress, sunSpecModel, priority); + remainingBlocks.remove(activeEntry.getKey().getBlockId()); } else { // This block is not considered, because the Model is not active this.logInfo(this.log, "Ignoring SunSpec-Model [" + blockId + "] starting at [" + startAddress + "]"); } - } - // Stop reading if all expectedBlocks have been read - if (remainingBlocks.isEmpty()) { - finished.complete(null); - return; } // Read next block recursively var nextBlockStartAddress = startAddress + 2 + values.get(1); - try { - - final var readNextBlockFuture = this.readNextBlock(nextBlockStartAddress, remainingBlocks); - // Announce finished when next block (recursively) is finished - readNextBlockFuture.thenRun(() -> { - finished.complete(null); - }); - } catch (OpenemsException e) { - this.logWarn(this.log, "Error while adding SunSpec-Model [" + blockId + "] starting at [" - + startAddress + "]: " + e.getMessage()); - e.printStackTrace(); - finished.complete(null); // announce finish immediately to not get stuck - } + // Announce finished when next block (recursively) is finished + return this.readNextBlock(nextBlockStartAddress, remainingBlocks); }); - return finished; } /** @@ -286,9 +268,8 @@ public boolean isSunSpecInitializationCompleted() { * @param startAddress the address to start reading from * @param model the SunSpecModel * @param priority the reading priority - * @throws OpenemsException on error */ - protected void addBlock(int startAddress, SunSpecModel model, Priority priority) throws OpenemsException { + protected void addBlock(int startAddress, SunSpecModel model, Priority priority) { this.logInfo(this.log, "Adding SunSpec-Model [" + model.getBlockId() + ":" + model.label() + "] starting at [" + startAddress + "]"); var readElements = new ArrayList(); @@ -424,54 +405,6 @@ protected ElementToChannelConverter generateElementToChannelConverter(SunSpecMod } } - /** - * Reads given Elements once from Modbus. - * - * @param the Type of the elements - * @param elements the elements - * @return a future list with the values, e.g. a list of integers - * @throws OpenemsException on error - */ - @SafeVarargs - private final CompletableFuture> readElementsOnceTyped(ModbusRegisterElement... elements) - throws OpenemsException { - // Register listeners for elements - @SuppressWarnings("unchecked") - final var subResults = (CompletableFuture[]) new CompletableFuture[elements.length]; - for (var i = 0; i < elements.length; i++) { - var subResult = new CompletableFuture(); - subResults[i] = subResult; - - var element = elements[i]; - element.onUpdateCallback(value -> { - if (value == null) { - // try again - return; - } - subResult.complete(value); - }); - } - - // Activate task - final Task task = new FC3ReadRegistersTask(elements[0].startAddress, Priority.HIGH, elements); - this.modbusProtocol.addTask(task); - - // Prepare result - final var result = new CompletableFuture>(); - CompletableFuture.allOf(subResults).thenRun(() -> { - // do not try again - this.modbusProtocol.removeTask(task); - - // get all results and complete result - List values = Stream.of(subResults) // - .map(CompletableFuture::join) // - .collect(Collectors.toCollection(ArrayList::new)); - result.complete(values); - }); - - return result; - } - /** * Get the Channel for the given Point. * 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 cd031cfb4cb..1d508bb9363 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 @@ -23,6 +23,10 @@ public class DummyModbusBridge extends AbstractModbusBridge implements BridgeMod private InetAddress ipAddress = null; public DummyModbusBridge(String id) { + this(id, LogVerbosity.NONE); + } + + public DummyModbusBridge(String id, LogVerbosity logVerbosity) { super(// OpenemsComponent.ChannelId.values(), // BridgeModbus.ChannelId.values(), // @@ -31,7 +35,7 @@ public DummyModbusBridge(String id) { for (Channel channel : this.channels()) { channel.nextProcessImage(); } - super.activate(null, id, "", true, LogVerbosity.NONE, 2); + super.activate(null, id, "", true, logVerbosity, 2); } /** @@ -66,12 +70,12 @@ public InetAddress getIpAddress() { @Override public ModbusTransaction getNewModbusTransaction() throws OpenemsException { - throw new UnsupportedOperationException("Unsupported by Dummy Class"); + throw new UnsupportedOperationException("getNewModbusTransaction() Unsupported by Dummy Class"); } @Override public void closeModbusConnection() { - throw new UnsupportedOperationException("Unsupported by Dummy Class"); + throw new UnsupportedOperationException("closeModbusConnection() Unsupported by Dummy Class"); } } diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/BridgeModbusTcpImplTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/BridgeModbusTcpImplTest.java index ca9a516b620..276dc8dcce6 100644 --- a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/BridgeModbusTcpImplTest.java +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/BridgeModbusTcpImplTest.java @@ -22,7 +22,6 @@ import io.openems.edge.common.taskmanager.Priority; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; -import io.openems.edge.common.test.DummyCycle; import io.openems.edge.common.test.TestUtils; public class BridgeModbusTcpImplTest { @@ -61,7 +60,6 @@ public void test() throws Exception { var device = new MyModbusComponent(DEVICE_ID, sut, UNIT_ID); var test = new ComponentTest(sut) // .addComponent(device) // - .addReference("cycle", new DummyCycle(CYCLE_TIME)) // .activate(MyConfigTcp.create() // .setId(MODBUS_ID) // .setIp("127.0.0.1") // @@ -135,11 +133,10 @@ public Doc doc() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this, // new FC3ReadRegistersTask(100, Priority.HIGH, // - m(ChannelId.REGISTER_100, new UnsignedWordElement(100) // - ))); // + m(ChannelId.REGISTER_100, new UnsignedWordElement(100)))); // } } 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 f0b8ee7d3e6..a4f3dc43db3 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 @@ -50,12 +50,12 @@ public DummyModbusComponent(String id, AbstractModbusBridge bridge, int unitId, super.activate(context, id, "", true, unitId, cm, "Modbus", bridge.id()); } - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this); } @Override - public ModbusProtocol getModbusProtocol() throws OpenemsException { + public ModbusProtocol getModbusProtocol() { return super.getModbusProtocol(); } diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/MyConfigTcp.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/MyConfigTcp.java index 18a2114d244..1f74849a5ce 100644 --- a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/MyConfigTcp.java +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/MyConfigTcp.java @@ -6,7 +6,7 @@ @SuppressWarnings("all") public class MyConfigTcp extends AbstractComponentConfig implements ConfigTcp { - protected static class Builder { + public static class Builder { private String id; private String ip; private int port; diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/ConversionTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/ConversionTest.java index 0e502a04d72..5e5b5777c16 100644 --- a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/ConversionTest.java +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/ConversionTest.java @@ -10,25 +10,6 @@ public class ConversionTest { - @Test - public void testShortConversions() { - - var v1 = 0; - var result = ModbusUtils.convert(v1, 0); - Short expected = 0; - assertEquals(expected, result); - - v1 = 1; - result = ModbusUtils.convert(v1, 0); - expected = 1; - assertEquals(expected, result); - - v1 = 65536; - result = ModbusUtils.convert(v1, 1); - expected = 1; - assertEquals(expected, result); - } - @Test public void multiplyTest() { var value = 10; diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/ModbusUtilsTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/ModbusUtilsTest.java new file mode 100644 index 00000000000..afca83ff9b3 --- /dev/null +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/ModbusUtilsTest.java @@ -0,0 +1,47 @@ +package io.openems.edge.bridge.modbus.api; + +import static io.openems.edge.bridge.modbus.api.ModbusUtils.doNotRetry; +import static io.openems.edge.bridge.modbus.api.ModbusUtils.intToHexString; +import static io.openems.edge.bridge.modbus.api.ModbusUtils.registersToHexString; +import static io.openems.edge.bridge.modbus.api.ModbusUtils.retryOnNull; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import com.ghgande.j2mod.modbus.procimg.SimpleInputRegister; +import com.ghgande.j2mod.modbus.procimg.SimpleRegister; + +import io.openems.edge.bridge.modbus.api.task.Task.ExecuteState; + +public class ModbusUtilsTest { + + @Test + public void testRetryOnNull() { + assertTrue(retryOnNull(ExecuteState.OK, null)); + assertFalse(retryOnNull(ExecuteState.OK, 123)); + } + + @Test + public void testDoNotRetry() { + assertFalse(doNotRetry(ExecuteState.OK, null)); + assertFalse(doNotRetry(ExecuteState.OK, 123)); + } + + @Test + public void testIntToHexString() { + assertEquals("00af", intToHexString(0xAF)); + } + + @Test + public void testRegistersToHexString() { + assertEquals("00aa 00ff", registersToHexString(new SimpleRegister(0xAA), new SimpleRegister(0xFF))); + } + + @Test + public void testInputRegistersToHexString() { + assertEquals("00aa 00ff", registersToHexString(new SimpleInputRegister(0xAA), new SimpleInputRegister(0xFF))); + } + +} diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/AbstractDummyTask.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/AbstractDummyTask.java index b834c62cb6c..5a61d27e0b4 100644 --- a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/AbstractDummyTask.java +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/AbstractDummyTask.java @@ -1,11 +1,14 @@ package io.openems.edge.bridge.modbus.api.worker; +import java.util.function.Consumer; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.ghgande.j2mod.modbus.msg.ModbusRequest; import com.ghgande.j2mod.modbus.msg.ModbusResponse; +import io.openems.common.utils.FunctionUtils; import io.openems.edge.bridge.modbus.api.AbstractModbusBridge; import io.openems.edge.bridge.modbus.api.task.AbstractTask; @@ -15,22 +18,28 @@ public abstract class AbstractDummyTask extends AbstractTask onExecute, long delay) { + super(name, onExecute, ModbusResponse.class, 0); this.name = name; this.delay = delay; } - public void setDefective(boolean isDefective, long delay) { - this.isDefective = isDefective; + public void setDefective(Exception defect, long delay) { + this.defect = defect; this.delay = delay; } + protected long getDelay() { + return this.delay; + } + @Override protected String payloadToString(ModbusRequest request) { return ""; @@ -41,29 +50,16 @@ protected String payloadToString(ModbusResponse response) { return ""; } - /** - * Callback on Execute. - * - * @param onExecuteCallback the callback {@link Runnable} - */ - public void onExecute(Runnable onExecuteCallback) { - this.onExecuteCallback = onExecuteCallback; - } - @Override public ExecuteState execute(AbstractModbusBridge bridge) { - if (this.onExecuteCallback != null) { - this.onExecuteCallback.run(); - } - try { Thread.sleep(this.delay); } catch (InterruptedException e) { this.log.warn(e.getMessage()); } - if (this.isDefective) { - return ExecuteState.ERROR; + if (this.defect != null) { + return new ExecuteState.Error(this.defect); } return ExecuteState.OK; } diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/DummyReadTask.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/DummyReadTask.java index 63357905cfb..d8b3284429c 100644 --- a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/DummyReadTask.java +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/DummyReadTask.java @@ -14,7 +14,7 @@ public DummyReadTask(String name, long delay, Priority priority) { @Override public String toString() { - return "DummyReadTask [name=" + this.name + ", delay=" + this.delay + ", priority=" + this.priority + "]"; + return "DummyReadTask [name=" + this.name + ", delay=" + this.getDelay() + ", priority=" + this.priority + "]"; } @Override diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/DummyWriteTask.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/DummyWriteTask.java index c219e0a6295..f7ff37d8c51 100644 --- a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/DummyWriteTask.java +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/DummyWriteTask.java @@ -11,7 +11,7 @@ public DummyWriteTask(String name, long delay) { @Override public String toString() { - return "DummyWriteTask [name=" + this.name + ", delay=" + this.delay + "]"; + return "DummyWriteTask [name=" + this.name + ", delay=" + this.getDelay() + "]"; } @Override diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/AbstractOpenemsSunSpecComponentTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/AbstractOpenemsSunSpecComponentTest.java index ed2041643b3..a4526ef63dd 100644 --- a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/AbstractOpenemsSunSpecComponentTest.java +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/AbstractOpenemsSunSpecComponentTest.java @@ -1,14 +1,35 @@ package io.openems.edge.bridge.modbus.sunspec; +import static io.openems.edge.bridge.modbus.sunspec.AbstractOpenemsSunSpecComponent.preprocessModbusElements; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import java.util.ArrayList; +import java.util.stream.IntStream; +import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; +import com.ghgande.j2mod.modbus.procimg.SimpleProcessImage; +import com.ghgande.j2mod.modbus.procimg.SimpleRegister; +import com.ghgande.j2mod.modbus.slave.ModbusSlave; +import com.ghgande.j2mod.modbus.slave.ModbusSlaveFactory; +import com.google.common.collect.ImmutableSortedMap; + import io.openems.common.exceptions.OpenemsException; +import io.openems.edge.bridge.modbus.BridgeModbusTcpImpl; +import io.openems.edge.bridge.modbus.MyConfigTcp; +import io.openems.edge.bridge.modbus.api.LogVerbosity; import io.openems.edge.bridge.modbus.api.element.ModbusElement; import io.openems.edge.bridge.modbus.api.element.StringWordElement; +import io.openems.edge.bridge.modbus.sunspec.dummy.MyConfig; +import io.openems.edge.bridge.modbus.sunspec.dummy.MySunSpecComponentImpl; +import io.openems.edge.common.test.AbstractComponentTest.TestCase; +import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.common.test.DummyConfigurationAdmin; +import io.openems.edge.common.test.TestUtils; public class AbstractOpenemsSunSpecComponentTest { @@ -22,11 +43,129 @@ public void testPreprocessModbusElements() throws OpenemsException { elements.add(element); } - var sut = AbstractOpenemsSunSpecComponent.preprocessModbusElements(elements); + var sut = preprocessModbusElements(elements); assertEquals(2, sut.size()); // two sublists assertEquals(69, sut.get(0).size()); // first task assertEquals(1, sut.get(1).size()); // second task assertEquals(StringWordElement.class, sut.get(1).get(0).getClass()); // second task } + private static final int UNIT_ID = 1; + + @Before + public void changeLogLevel() { + java.lang.System.setProperty("org.ops4j.pax.logging.DefaultServiceLog.level", "INFO"); + } + + private static ImmutableSortedMap.Builder generateSunSpec() { + var b = ImmutableSortedMap.naturalOrder() // + .put(40000, 0x5375) // SunSpec identifier + .put(40001, 0x6e53) // SunSpec identifier + + .put(40002, 1) // SunSpec Block-ID + .put(40003, 66); // Length of the SunSpec Block + IntStream.range(40004, 40070).forEach(i -> b.put(i, 0)); + b // + .put(40070, 123) // SunSpec Block-ID + .put(40071, 24); // Length of the SunSpec Block + IntStream.range(40072, 40096).forEach(i -> b.put(i, 0)); + b // + .put(40096, 999) // SunSpec Block-ID + .put(40097, 10) // Length of the SunSpec Block + + .put(40108, 702) // SunSpec Block-ID + .put(40109, 50); // Length of the SunSpec Block + IntStream.range(40110, 40160).forEach(i -> b.put(i, 0)); + return b; + } + + // Disabled because of timing issues in CI + @Ignore + @Test + public void test() throws Exception { + var port = TestUtils.findRandomOpenPortOnAllLocalInterfaces(); + ModbusSlave slave = null; + try { + /* + * Open Modbus/TCP Slave + */ + slave = ModbusSlaveFactory.createTCPSlave(port, 1); + slave.open(); + + /* + * Instantiate Modbus-Bridge + */ + var bridge = new BridgeModbusTcpImpl(); + var testBridge = new ComponentTest(bridge) // + .activate(MyConfigTcp.create() // + .setId("modbus0") // + .setIp("127.0.0.1") // + .setPort(port) // + .setInvalidateElementsAfterReadErrors(1) // + .setLogVerbosity(LogVerbosity.READS_AND_WRITES_VERBOSE) // + .build()); + + var cmp = new MySunSpecComponentImpl(); + var testCmp = new ComponentTest(cmp) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("setModbus", bridge) // + .activate(MyConfig.create() // + .setId("cmp0") // + .setModbusId("modbus0") // + .setModbusUnitId(UNIT_ID) // + .setReadFromModbusBlock(1) // + .build()); + + testWithEndOfMap(slave, bridge, testBridge, cmp, testCmp); + testWithIllegalAddress(slave, bridge, testBridge, cmp, testCmp); + + assertFalse(cmp.getSunSpecChannel(DefaultSunSpecModel.S103.APH_A).isPresent()); + assertNotNull(cmp.getSunSpecChannelOrError(DefaultSunSpecModel.S702.W_MAX_RTG)); + + } finally { + if (slave != null) { + slave.close(); + } + } + } + + private static void cycle(ComponentTest testBridge, ComponentTest testCmp, int count, int sleep) throws Exception { + for (var i = 0; i < count; i++) { + testBridge.next(new TestCase()); + testCmp.next(new TestCase()); + Thread.sleep(sleep); // TODO required? + } + } + + private static void testWithEndOfMap(ModbusSlave slave, BridgeModbusTcpImpl bridge, ComponentTest testBridge, + MySunSpecComponentImpl cmp, ComponentTest testCmp) throws Exception { + var processImage = new SimpleProcessImage(UNIT_ID); + generateSunSpec() // + .put(40160, 0xFFFF) // END_OF_MAP + .put(40161, 0)// Behind the end + .build() // + .entrySet().stream() // + .forEach(e -> processImage.addRegister(e.getKey(), new SimpleRegister(e.getValue()))); + slave.addProcessImage(UNIT_ID, processImage); + + cycle(testBridge, testCmp, 5, 100); + + assertEquals(58, cmp.channels().size()); + } + + private static void testWithIllegalAddress(ModbusSlave slave, BridgeModbusTcpImpl bridge, ComponentTest testBridge, + MySunSpecComponentImpl cmp, ComponentTest testCmp) throws Exception { + var processImage = new SimpleProcessImage(UNIT_ID); + generateSunSpec() // + .build() // + .entrySet().stream() // + .forEach(e -> processImage.addRegister(e.getKey(), new SimpleRegister(e.getValue()))); + slave.addProcessImage(UNIT_ID, processImage); + + cycle(testBridge, testCmp, 2, 100); + cycle(testBridge, testCmp, 1, 2000); // wait for defective component + cycle(testBridge, testCmp, 2, 100); + + assertEquals(58, cmp.channels().size()); + } } diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/DummySunSpecComponent.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/DummySunSpecComponent.java index adbb4e21c59..3a6d52f2fc4 100644 --- a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/DummySunSpecComponent.java +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/DummySunSpecComponent.java @@ -16,17 +16,20 @@ public class DummySunSpecComponent extends AbstractOpenemsSunSpecComponent { /** * All models are active with low priority. */ - private static final Map ACTIVE_MODELS = Stream.of(DefaultSunSpecModel.values()) - .collect(Collectors.toMap(model -> model, model -> Priority.LOW, (a, b) -> a, TreeMap::new)); + private static final Map ACTIVE_MODELS = Stream.of(DefaultSunSpecModel.values()) // + .collect(Collectors.toMap(// + model -> model, // + model -> Priority.LOW, // + (a, b) -> a, TreeMap::new)); - public DummySunSpecComponent() throws OpenemsException { + public DummySunSpecComponent() { super(ACTIVE_MODELS, // OpenemsComponent.ChannelId.values(), // ModbusComponent.ChannelId.values()); // this.addBlocks(); } - private void addBlocks() throws OpenemsException { + private void addBlocks() { var startAddress = 40000; for (var entry : ACTIVE_MODELS.keySet()) { this.addBlock(startAddress, entry, ACTIVE_MODELS.get(entry)); diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/dummy/Config.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/dummy/Config.java new file mode 100644 index 00000000000..24169ea7b76 --- /dev/null +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/dummy/Config.java @@ -0,0 +1,19 @@ +package io.openems.edge.bridge.modbus.sunspec.dummy; + +@interface Config { + String id(); + + String alias(); + + boolean enabled(); + + boolean readOnly(); + + String modbus_id(); + + int modbusUnitId(); + + int readFromModbusBlock(); + + String Modbus_target(); +} \ No newline at end of file diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/dummy/MyConfig.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/dummy/MyConfig.java new file mode 100644 index 00000000000..665e48e73be --- /dev/null +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/dummy/MyConfig.java @@ -0,0 +1,90 @@ +package io.openems.edge.bridge.modbus.sunspec.dummy; + +import io.openems.common.test.AbstractComponentConfig; +import io.openems.common.utils.ConfigUtils; + +@SuppressWarnings("all") +public class MyConfig extends AbstractComponentConfig implements Config { + + public static class Builder { + private String id = null; + private boolean readOnly; + private String modbusId = null; + private int modbusUnitId; + private int readFromModbusBlock; + + private Builder() { + } + + public Builder setId(String id) { + this.id = id; + return this; + } + + public Builder setReadOnly(boolean readOnly) { + this.readOnly = readOnly; + return this; + } + + public Builder setModbusId(String modbusId) { + this.modbusId = modbusId; + return this; + } + + public Builder setModbusUnitId(int modbusUnitId) { + this.modbusUnitId = modbusUnitId; + return this; + } + + public Builder setReadFromModbusBlock(int readFromModbusBlock) { + this.readFromModbusBlock = readFromModbusBlock; + return this; + } + + public MyConfig build() { + return new MyConfig(this); + } + } + + /** + * Create a Config builder. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new Builder(); + } + + private final Builder builder; + + private MyConfig(Builder builder) { + super(Config.class, builder.id); + this.builder = builder; + } + + @Override + public boolean readOnly() { + return this.builder.readOnly; + } + + @Override + public String modbus_id() { + return this.builder.modbusId; + } + + @Override + public int readFromModbusBlock() { + return this.builder.readFromModbusBlock; + } + + @Override + public String Modbus_target() { + return ConfigUtils.generateReferenceTargetFilter(this.id(), this.modbus_id()); + } + + @Override + public int modbusUnitId() { + return this.builder.modbusUnitId; + } + +} \ No newline at end of file diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/dummy/MySunSpecComponentImpl.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/dummy/MySunSpecComponentImpl.java new file mode 100644 index 00000000000..119adf1cf99 --- /dev/null +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/dummy/MySunSpecComponentImpl.java @@ -0,0 +1,77 @@ +package io.openems.edge.bridge.modbus.sunspec.dummy; + +import java.util.Map; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; + +import com.google.common.collect.ImmutableMap; + +import io.openems.common.exceptions.OpenemsException; +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.sunspec.AbstractOpenemsSunSpecComponent; +import io.openems.edge.bridge.modbus.sunspec.DefaultSunSpecModel; +import io.openems.edge.bridge.modbus.sunspec.SunSpecModel; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.taskmanager.Priority; + +public class MySunSpecComponentImpl extends AbstractOpenemsSunSpecComponent + implements ModbusComponent, OpenemsComponent { + + private static final Map ACTIVE_MODELS = ImmutableMap.builder() + .put(DefaultSunSpecModel.S_1, Priority.LOW) // + .put(DefaultSunSpecModel.S_101, Priority.LOW) // + .put(DefaultSunSpecModel.S_103, Priority.HIGH) // + .put(DefaultSunSpecModel.S_701, Priority.HIGH) // + .put(DefaultSunSpecModel.S_702, Priority.LOW) // + .build(); + + @Reference + private ConfigurationAdmin cm; + + @Override + @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) + protected void setModbus(BridgeModbus modbus) { + super.setModbus(modbus); + } + + public MySunSpecComponentImpl() { + super(// + ACTIVE_MODELS, // + OpenemsComponent.ChannelId.values(), // + ModbusComponent.ChannelId.values() // + ); + } + + @Activate + private void activate(ComponentContext context, Config config) throws OpenemsException { + if (super.activate(context, config.id(), config.alias(), true, config.modbusUnitId(), this.cm, "Modbus", + config.modbus_id(), config.readFromModbusBlock())) { + return; + } + } + + @Override + public ModbusProtocol getModbusProtocol() { + return super.getModbusProtocol(); + } + + @Override + @Deactivate + protected void deactivate() { + super.deactivate(); + } + + @Override + protected void onSunSpecInitializationCompleted() { + } + +} diff --git a/io.openems.edge.common/src/io/openems/edge/common/channel/calculate/CalculateAverage.java b/io.openems.edge.common/src/io/openems/edge/common/channel/calculate/CalculateAverage.java index f6e44d207cd..e6d8ef2dc0d 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/channel/calculate/CalculateAverage.java +++ b/io.openems.edge.common/src/io/openems/edge/common/channel/calculate/CalculateAverage.java @@ -26,7 +26,7 @@ public void addValue(Channel channel) { var value = channel.value().asOptional(); if (value.isPresent()) { try { - this.values.add(value.get().doubleValue()); + this.addValue(value.get()); } catch (Exception e) { this.log.error("Adding Channel [" + channel.address() + "] value [" + value + "] failed. " + e.getClass().getSimpleName() + ": " + e.getMessage()); @@ -35,6 +35,17 @@ public void addValue(Channel channel) { } } + /** + * Adds a Value. + * + * @param value the value + */ + public void addValue(Number value) { + if (value != null) { + this.values.add(value.doubleValue()); + } + } + /** * Calculates the average. * diff --git a/io.openems.edge.common/src/io/openems/edge/common/sum/Sum.java b/io.openems.edge.common/src/io/openems/edge/common/sum/Sum.java index f37d089dce1..28d5b71e4bb 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/sum/Sum.java +++ b/io.openems.edge.common/src/io/openems/edge/common/sum/Sum.java @@ -7,11 +7,13 @@ import io.openems.common.types.OpenemsType; import io.openems.edge.common.channel.Channel; import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.channel.DoubleReadChannel; import io.openems.edge.common.channel.IntegerReadChannel; import io.openems.edge.common.channel.LongReadChannel; import io.openems.edge.common.channel.StateChannel; import io.openems.edge.common.channel.value.Value; import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.meta.Meta; import io.openems.edge.common.modbusslave.ModbusSlaveNatureTable; import io.openems.edge.common.modbusslave.ModbusType; @@ -273,6 +275,18 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { GRID_MAX_ACTIVE_POWER(Doc.of(OpenemsType.INTEGER) // .unit(Unit.WATT) // .persistencePriority(PersistencePriority.VERY_HIGH)), + /** + * Grid: Price for Buy-from-Grid. + * + *
    + *
  • Interface: Sum (origin: TimeOfUseTariff) + *
  • Type: Integer + *
  • Unit: Currency (see {@link Meta.ChannelId#CURRENCY}) per MWh + *
+ */ + GRID_BUY_PRICE(Doc.of(OpenemsType.DOUBLE) // + .unit(Unit.MONEY_PER_MEGAWATT_HOUR) // + .persistencePriority(PersistencePriority.VERY_HIGH)), /** * Production: Active Power. * @@ -1192,6 +1206,35 @@ public default void _setGridActivePowerL3(int value) { this.getGridActivePowerL3Channel().setNextValue(value); } + /** + * Gets the Channel for {@link ChannelId#GRID_BUY_PRICE}. + * + * @return the Channel + */ + public default DoubleReadChannel getGridBuyPriceChannel() { + return this.channel(ChannelId.GRID_BUY_PRICE); + } + + /** + * Gets the Buy-from-Grid price [Currency/MWh]. See + * {@link ChannelId#GRID_BUY_PRICE}. + * + * @return the Channel {@link Value} + */ + public default Value getGridBuyPrice() { + return this.getGridBuyPriceChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#GRID_BUY_PRICE} + * Channel. + * + * @param value the next value + */ + public default void _setGridBuyPrice(Double value) { + this.getGridBuyPriceChannel().setNextValue(value); + } + /** * Gets the Channel for {@link ChannelId#GRID_MIN_ACTIVE_POWER}. * diff --git a/io.openems.edge.common/src/io/openems/edge/common/type/Tuple.java b/io.openems.edge.common/src/io/openems/edge/common/type/Tuple.java index 5621c1a6509..04d3292ed7b 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/type/Tuple.java +++ b/io.openems.edge.common/src/io/openems/edge/common/type/Tuple.java @@ -1,4 +1,18 @@ package io.openems.edge.common.type; public record Tuple(A a, B b) { + + /** + * Factory for a {@link Tuple}. + * + * @param Type of a + * @param Type of b + * @param a value a + * @param b value b + * @return a new Tuple + */ + public static Tuple of(A a, B b) { + return new Tuple<>(a, b); + } + } diff --git a/io.openems.edge.controller.ess.timeofusetariff/bnd.bnd b/io.openems.edge.controller.ess.timeofusetariff/bnd.bnd index 8f894150414..d45bd8553ce 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/bnd.bnd +++ b/io.openems.edge.controller.ess.timeofusetariff/bnd.bnd @@ -10,11 +10,10 @@ Bundle-Version: 1.0.0.${tstamp} io.openems.edge.controller.api,\ io.openems.edge.controller.ess.emergencycapacityreserve,\ io.openems.edge.controller.ess.limittotaldischarge,\ + io.openems.edge.energy.api,\ io.openems.edge.ess.api,\ - io.openems.edge.predictor.api,\ io.openems.edge.timedata.api,\ io.openems.edge.timeofusetariff.api,\ - io.openems.wrapper.jenetics,\ -testpath: \ ${testpath},\ diff --git a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffController.java b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffController.java index 7950bdbb387..9876f79201e 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffController.java +++ b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffController.java @@ -22,7 +22,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { .text("Current state of the Controller")), QUARTERLY_PRICES(Doc.of(OpenemsType.DOUBLE) // - .unit(Unit.EUROS_PER_MEGAWATT_HOUR) // + .unit(Unit.MONEY_PER_MEGAWATT_HOUR) // .text("Price of the electricity for the current Hour")// .persistencePriority(PersistencePriority.HIGH)), // diff --git a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImpl.java b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImpl.java index 3f30cb88d2e..5ae75684899 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImpl.java +++ b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImpl.java @@ -3,12 +3,8 @@ import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.BALANCING; import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.CHARGE_GRID; import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.DELAY_DISCHARGE; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.calculateChargeGridPower; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.calculateDelayDischargePower; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.getEssMinSocPercentage; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.postprocessRunState; +import static io.openems.edge.controller.ess.timeofusetariff.Utils.calculateAutomaticMode; -import java.time.ZonedDateTime; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @@ -30,22 +26,19 @@ import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.jsonapi.ComponentJsonApi; -import io.openems.edge.common.jsonapi.EdgeKeys; import io.openems.edge.common.jsonapi.JsonApiBuilder; import io.openems.edge.common.sum.Sum; -import io.openems.edge.common.user.User; import io.openems.edge.controller.api.Controller; import io.openems.edge.controller.ess.emergencycapacityreserve.ControllerEssEmergencyCapacityReserve; import io.openems.edge.controller.ess.limittotaldischarge.ControllerEssLimitTotalDischarge; -import io.openems.edge.controller.ess.timeofusetariff.jsonrpc.GetScheduleRequest; -import io.openems.edge.controller.ess.timeofusetariff.jsonrpc.GetScheduleResponse; -import io.openems.edge.controller.ess.timeofusetariff.optimizer.Context; -import io.openems.edge.controller.ess.timeofusetariff.optimizer.Optimizer; -import io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils; +import io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImpl.Context; +import io.openems.edge.controller.ess.timeofusetariff.Utils.ApplyState; +import io.openems.edge.energy.api.EnergySchedulable; +import io.openems.edge.energy.api.EnergyScheduleHandler; +import io.openems.edge.energy.api.EnergyScheduler; import io.openems.edge.ess.api.ManagedSymmetricEss; import io.openems.edge.ess.power.api.Phase; import io.openems.edge.ess.power.api.Pwr; -import io.openems.edge.predictor.api.manager.PredictorManager; import io.openems.edge.timedata.api.Timedata; import io.openems.edge.timedata.api.TimedataProvider; import io.openems.edge.timedata.api.utils.CalculateActiveTime; @@ -57,12 +50,15 @@ immediate = true, // configurationPolicy = ConfigurationPolicy.REQUIRE // ) -public class TimeOfUseTariffControllerImpl extends AbstractOpenemsComponent - implements TimeOfUseTariffController, Controller, OpenemsComponent, TimedataProvider, ComponentJsonApi { +public class TimeOfUseTariffControllerImpl extends AbstractOpenemsComponent implements TimeOfUseTariffController, + EnergySchedulable, Controller, OpenemsComponent, TimedataProvider, ComponentJsonApi { - /** The hard working Worker. */ - private final Optimizer optimizer; + public static record Context(List ctrlEmergencyCapacityReserves, + List ctrlLimitTotalDischarges, ManagedSymmetricEss ess, + ControlMode controlMode, int maxChargePowerFromGrid, boolean limitChargePowerFor14aEnWG) { + } + private final EnergyScheduleHandler energyScheduleHandler; private final CalculateActiveTime calculateDelayedTime = new CalculateActiveTime(this, TimeOfUseTariffController.ChannelId.DELAYED_TIME); private final CalculateActiveTime calculateChargedTime = new CalculateActiveTime(this, @@ -75,14 +71,12 @@ public class TimeOfUseTariffControllerImpl extends AbstractOpenemsComponent private ComponentManager componentManager; @Reference - private PredictorManager predictorManager; + private Sum sum; + // This is only required to get the current price for UI chart @Reference private TimeOfUseTariff timeOfUseTariff; - @Reference - private Sum sum; - @Reference(policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) private volatile Timedata timedata; @@ -99,6 +93,9 @@ public class TimeOfUseTariffControllerImpl extends AbstractOpenemsComponent @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) private ManagedSymmetricEss ess; + @Reference + private EnergyScheduler energyScheduler; + private Config config = null; public TimeOfUseTariffControllerImpl() { @@ -107,153 +104,69 @@ public TimeOfUseTariffControllerImpl() { Controller.ChannelId.values(), // TimeOfUseTariffController.ChannelId.values() // ); - - // Prepare Optimizer and Context - this.optimizer = new Optimizer(() -> Context.create() // - .setClock(this.componentManager.getClock()) // - .setSum(this.sum) // - .setPredictorManager(this.predictorManager) // - .setTimeOfUseTariff(this.timeOfUseTariff) // - .setEss(this.ess) // - .setCtrlEmergencyCapacityReserves(this.ctrlEmergencyCapacityReserves) // - .setCtrlLimitTotalDischarges(this.ctrlLimitTotalDischarges) // - .setControlMode(this.config.controlMode()) // - .setMaxChargePowerFromGrid(this.config.maxChargePowerFromGrid()) // - .setLimitChargePowerFor14aEnWG(this.config.limitChargePowerFor14aEnWG()) // - .build()); + this.energyScheduleHandler = new EnergyScheduleHandler<>(// + () -> this.config.controlMode().states, // + () -> new Context(this.ctrlEmergencyCapacityReserves, this.ctrlLimitTotalDischarges, this.ess, + this.config.controlMode(), this.config.maxChargePowerFromGrid(), + this.config.limitChargePowerFor14aEnWG())); } @Activate private void activate(ComponentContext context, Config config) { super.activate(context, config.id(), config.alias(), config.enabled()); - if (this.applyConfig(config)) { - this.optimizer.activate(this.id()); - } + this.applyConfig(config); } @Modified private void modified(ComponentContext context, Config config) { super.modified(context, config.id(), config.alias(), config.enabled()); - if (this.applyConfig(config)) { - this.optimizer.modified(this.id()); - } + this.applyConfig(config); } - private synchronized boolean applyConfig(Config config) { + private synchronized void applyConfig(Config config) { this.config = config; // update filter for 'ess' - if (OpenemsComponent.updateReferenceFilter(this.cm, this.servicePid(), "ess", config.ess_id())) { - return false; - } - - if (!config.enabled()) { - this.optimizer.deactivate(); - return false; - } - - return true; + OpenemsComponent.updateReferenceFilter(this.cm, this.servicePid(), "ess", config.ess_id()); } @Override @Deactivate protected void deactivate() { - this.optimizer.deactivate(); super.deactivate(); } @Override public void run() throws OpenemsNamedException { // Mode given from the configuration. - switch (this.config.mode()) { - case AUTOMATIC -> this.modeAutomatic(); - case OFF -> this.modeOff(); - } + var as = switch (this.config.mode()) { + case AUTOMATIC -> calculateAutomaticMode(this.sum, this.ess, + this.energyScheduleHandler.getCurrentEssChargeInChargeGrid(), this.config.maxChargePowerFromGrid(), + this.config.limitChargePowerFor14aEnWG(), this.getCurrentPeriodState()); + case OFF -> new ApplyState(StateMachine.BALANCING, null); + }; - this.updateVisualizationChannels(); - } + // Update Channels + this._setStateMachine(as.actualState()); + this.calculateChargedTime.update(as.actualState() == CHARGE_GRID); + this.calculateDelayedTime.update(as.actualState() == DELAY_DISCHARGE); + this._setQuarterlyPrices(this.timeOfUseTariff.getPrices().getFirst()); - private StateMachine getCurrentStateMachine() { - return this.optimizer.getCurrentStateMachine(); + // Apply ActivePower set-point + if (as.setPoint() != null) { + this.ess.setActivePowerLessOrEquals(this.ess.getPower().fitValueIntoMinMaxPower(this.id(), this.ess, + Phase.ALL, Pwr.ACTIVE, as.setPoint())); + } } private StateMachine getCurrentPeriodState() { - var state = this.getCurrentStateMachine(); + var state = this.energyScheduleHandler.getCurrentState(); if (state != null) { return state; } return BALANCING; // Default Fallback } - /** - * Apply the Schedule. - * - * @throws OpenemsNamedException on error - */ - private void modeAutomatic() throws OpenemsNamedException { - // Evaluate current state - final var state = postprocessRunState( - getEssMinSocPercentage(this.ctrlLimitTotalDischarges, this.ctrlEmergencyCapacityReserves), // - this.ess.getSoc().get(), // - this.sum.getProductionActivePower().orElse(0), // - this.getCurrentPeriodState()); - this._setStateMachine(state); - - // Update the timer. - this.calculateChargedTime.update(state == CHARGE_GRID); - this.calculateDelayedTime.update(state == DELAY_DISCHARGE); - - // Get and apply ActivePower Less-or-Equals Set-Point - var activePower = switch (state) { - case CHARGE_GRID -> calculateChargeGridPower(this.optimizer.getParams(), this.ess, this.sum, - this.config.maxChargePowerFromGrid(), this.config.limitChargePowerFor14aEnWG()); - case DELAY_DISCHARGE -> calculateDelayDischargePower(this.ess); - case BALANCING -> null; - }; - - if (activePower != null) { - this.ess.setActivePowerLessOrEquals(this.ess.getPower().fitValueIntoMinMaxPower(this.id(), this.ess, - Phase.ALL, Pwr.ACTIVE, activePower)); - } - } - - /** - * Apply the mode OFF logic. Sets the Default values to the channels, if the - * Mode is 'OFF'. - */ - private void modeOff() { - // Update the timer. - this.calculateChargedTime.update(false); - this.calculateDelayedTime.update(false); - - // Default State Machine. - this._setStateMachine(BALANCING); - } - - /** - * This is only to visualize data for better debugging. - */ - private void updateVisualizationChannels() { - final Double quarterlyPrice; - var period = this.getCurrentStateMachine(); - if (period == null) { - // Values are not available. - quarterlyPrice = this.timeOfUseTariff.getPrices().getFirst(); - - } else { - var params = this.optimizer.getParams(); - if (params != null) { - // First period is always the current period. - quarterlyPrice = params.optimizePeriods().get(0).price(); - } else { - quarterlyPrice = null; - } - } - - // Set the channels - this._setQuarterlyPrices(quarterlyPrice); - } - @Override public Timedata getTimedata() { return this.timedata; @@ -261,35 +174,21 @@ public Timedata getTimedata() { @Override public void buildJsonApiRoutes(JsonApiBuilder builder) { - builder.handleRequest(GetScheduleRequest.METHOD, call -> { - return this.handleGetScheduleRequest(// - call.get(EdgeKeys.USER_KEY), // - GetScheduleRequest.from(call.getRequest()) // - ); - }); - } - - /** - * Handles a {@link GetScheduleRequest}. - * - * @param user the User - * @param request the GetScheduleRequest - * @return the Future JSON-RPC Response - * @throws OpenemsNamedException on error - */ - protected GetScheduleResponse handleGetScheduleRequest(User user, GetScheduleRequest request) - throws OpenemsNamedException { - return Utils.handleGetScheduleRequest(this.optimizer, request.getId(), this.timedata, this.id(), - ZonedDateTime.now(this.componentManager.getClock())); + this.energyScheduler.buildJsonApiRoutes(builder); } @Override public String debugLog() { var b = new StringBuilder() // .append(this.getStateMachine()); // - if (this.getCurrentStateMachine() == null) { + if (this.getCurrentPeriodState() == null) { b.append("|No Schedule available"); } return b.toString(); } + + @Override + public EnergyScheduleHandler getEnergyScheduleHandler() { + return this.energyScheduleHandler; + } } diff --git a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/Utils.java b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/Utils.java new file mode 100644 index 00000000000..6543f9b24c1 --- /dev/null +++ b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/Utils.java @@ -0,0 +1,247 @@ +package io.openems.edge.controller.ess.timeofusetariff; + +import static io.openems.edge.common.type.TypeUtils.multiply; +import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.BALANCING; +import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.CHARGE_GRID; +import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.DELAY_DISCHARGE; +import static io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffController.PERIODS_PER_HOUR; +import static java.lang.Math.max; +import static java.lang.Math.min; +import static java.lang.Math.round; +import static java.util.stream.IntStream.concat; + +import java.util.List; +import java.util.Objects; + +import io.openems.common.types.ChannelAddress; +import io.openems.edge.common.sum.Sum; +import io.openems.edge.controller.api.Controller; +import io.openems.edge.controller.ess.emergencycapacityreserve.ControllerEssEmergencyCapacityReserve; +import io.openems.edge.controller.ess.limittotaldischarge.ControllerEssLimitTotalDischarge; +import io.openems.edge.ess.api.HybridEss; +import io.openems.edge.ess.api.ManagedSymmetricEss; + +/** + * Utils for {@link TimeOfUseTariffController}. + * + *

+ * All energy values are in [Wh] and positive, unless stated differently. + */ +public final class Utils { + + private Utils() { + } + + /** Keep some buffer to avoid scheduling errors because of bad predictions. */ + public static final float ESS_MAX_SOC = 90F; + + /** Limit Charge Power for §14a EnWG. */ + public static final int ESS_LIMIT_14A_ENWG = -4200; + + /** + * C-Rate (capacity divided by time) during {@link StateMachine#CHARGE_GRID}. + * With a C-Rate of 0.5 the battery gets fully charged within 2 hours. + */ + public static final float ESS_CHARGE_C_RATE = 0.5F; + + public static final ChannelAddress SUM_PRODUCTION = new ChannelAddress("_sum", "ProductionActivePower"); + public static final ChannelAddress SUM_CONSUMPTION = new ChannelAddress("_sum", "ConsumptionActivePower"); + public static final ChannelAddress SUM_GRID = new ChannelAddress("_sum", "GridActivePower"); + public static final ChannelAddress SUM_UNMANAGED_CONSUMPTION = new ChannelAddress("_sum", + "UnmanagedConsumptionActivePower"); + public static final ChannelAddress SUM_ESS_DISCHARGE_POWER = new ChannelAddress("_sum", "EssDischargePower"); + public static final ChannelAddress SUM_ESS_SOC = new ChannelAddress("_sum", "EssSoc"); + + /** + * Returns the configured minimum SoC, or zero. + * + * @param ctrlLimitTotalDischarges the list of + * {@link ControllerEssLimitTotalDischarge} + * @param ctrlEmergencyCapacityReserves the list of + * {@link ControllerEssEmergencyCapacityReserve} + * @return the value in [%] + */ + public static int getEssMinSocPercentage(List ctrlLimitTotalDischarges, + List ctrlEmergencyCapacityReserves) { + return concat(// + ctrlLimitTotalDischarges.stream() // + .map(ctrl -> ctrl.getMinSoc().get()) // + .filter(Objects::nonNull) // + .mapToInt(v -> max(0, v)), // only positives + ctrlEmergencyCapacityReserves.stream() // + .map(ctrl -> ctrl.getActualReserveSoc().get()) // + .filter(Objects::nonNull) // + .mapToInt(v -> max(0, v))) // only positives + .max().orElse(0); + } + + public static record ApplyState(StateMachine actualState, Integer setPoint) { + } + + /** + * Calculate Automatic Mode. + * + * @param sum the {@link Sum} + * @param ess the {@link ManagedSymmetricEss} + * @param essChargeInChargeGrid ESS Charge Energy in CHARGE_GRID State [Wh] + * @param maxChargePowerFromGrid the configured max charge from grid power + * @param limitChargePowerFor14aEnWG Limit Charge Power for §14a EnWG + * @param targetState the scheduled target {@link StateMachine} + * @return {@link ApplyState} + */ + public static ApplyState calculateAutomaticMode(Sum sum, ManagedSymmetricEss ess, Integer essChargeInChargeGrid, + int maxChargePowerFromGrid, boolean limitChargePowerFor14aEnWG, StateMachine targetState) { + final StateMachine actualState; + final Integer setPoint; + + var gridActivePower = sum.getGridActivePower().get(); // current buy-from/sell-to grid + var essActivePower = ess.getActivePower().get(); // current charge/discharge ESS + if (gridActivePower == null || essActivePower == null) { + // undefined state + return new ApplyState(BALANCING, null); + } + + // Post-process and get actual state + final var pwrBalancing = gridActivePower + essActivePower; + final var pwrDelayDischarge = calculateDelayDischargePower(ess); + final var pwrChargeGrid = calculateChargeGridPower(essChargeInChargeGrid, ess, essActivePower, gridActivePower, + maxChargePowerFromGrid, limitChargePowerFor14aEnWG); + actualState = postprocessRunState(targetState, pwrBalancing, pwrDelayDischarge, pwrChargeGrid); + + // Get and apply ActivePower Less-or-Equals Set-Point + setPoint = switch (actualState) { + case BALANCING -> null; // delegate to next priority Controller + case DELAY_DISCHARGE -> pwrDelayDischarge; + case CHARGE_GRID -> pwrChargeGrid; + }; + + return new ApplyState(actualState, setPoint); + } + + /** + * Post-Process a state during {@link Controller#run()}, i.e. replace with + * 'better' state if appropriate. + * + *

+ * NOTE: this can be useful, if live operation deviates from predicted + * operation, e.g. because predictions were wrong. + * + * @param state the initial state + * @param pwrBalancing the power set-point as it would be in + * {@link StateMachine#BALANCING} + * @param pwrDelayDischarge the power set-point as it would be in + * {@link StateMachine#DELAY_DISCHARGE} + * @param pwrChargeGrid the power set-point as it would be in + * {@link StateMachine#CHARGE_GRID} + * @return the new state + */ + public static StateMachine postprocessRunState(StateMachine state, int pwrBalancing, int pwrDelayDischarge, + int pwrChargeGrid) { + if (state == CHARGE_GRID) { + // CHARGE_GRID,... + if (pwrChargeGrid >= pwrDelayDischarge) { + // but battery charge/discharge is the same as DELAY_DISCHARGE + state = DELAY_DISCHARGE; + } + } + + if (state == DELAY_DISCHARGE) { + // CHARGE_GRID,... + if (pwrDelayDischarge >= pwrBalancing) { + // but battery charge/discharge is the same as DELAY_DISCHARGE + state = BALANCING; + } + } + + return state; + } + + protected static int calculateEssChargeInChargeGridPowerFromParams(Integer essChargeInChargeGrid, + ManagedSymmetricEss ess) { + if (essChargeInChargeGrid != null) { + return toPower(essChargeInChargeGrid); + } + var capacity = ess.getCapacity(); + if (capacity.isDefined()) { + return round(capacity.get() * ESS_CHARGE_C_RATE); + } + var maxApparentPower = ess.getMaxApparentPower(); + if (maxApparentPower.isDefined()) { + return maxApparentPower.get() / 4; + } + return 0; + } + + /** + * Calculates the Max-ActivePower constraint for + * {@link StateMachine#CHARGE_GRID}. + * + * @param essChargeInChargeGrid ESS Charge Energy in CHARGE_GRID State [Wh] + * @param ess the {@link ManagedSymmetricEss} + * @param essActivePower the ESS ActivePower + * @param gridActivePower the Grid ActivePower + * @param maxChargePowerFromGrid the configured max charge from grid power + * @param limitChargePowerFor14aEnWG Limit Charge Power for §14a EnWG + * @return the set-point or null + */ + public static int calculateChargeGridPower(Integer essChargeInChargeGrid, ManagedSymmetricEss ess, + int essActivePower, int gridActivePower, int maxChargePowerFromGrid, boolean limitChargePowerFor14aEnWG) { + var realGridPower = gridActivePower + essActivePower; // 'real', without current ESS charge/discharge + var targetChargePower = calculateEssChargeInChargeGridPowerFromParams(essChargeInChargeGrid, ess) // + + min(0, realGridPower) * -1; // add excess production + var effectiveGridBuyPower = max(0, realGridPower) + targetChargePower; + var chargePower = max(0, targetChargePower - max(0, effectiveGridBuyPower - maxChargePowerFromGrid)); + + // Invert to negative for CHARGE + chargePower *= -1; + + // Apply §14a EnWG limit + if (limitChargePowerFor14aEnWG) { + chargePower = max(ESS_LIMIT_14A_ENWG, chargePower); + } + + return chargePower; + } + + /** + * Calculates the Max-ActivePower constraint for + * {@link StateMachine#CHARGE_PRODUCTION}. + * + * @param sum the {@link Sum} + * @return the set-point + */ + public static Integer calculateMaxChargeProductionPower(Sum sum) { + var productionAcActivePower = sum.getProductionAcActivePower().get(); + if (productionAcActivePower == null || productionAcActivePower < 0) { + return 0; // unknown AC production -> do not charge + } + return -productionAcActivePower; + } + + /** + * Calculates the ActivePower constraint for + * {@link StateMachine#DELAY_DISCHARGE}. + * + * @param ess the {@link ManagedSymmetricEss} + * @return the set-point + */ + public static int calculateDelayDischargePower(ManagedSymmetricEss ess) { + if (ess instanceof HybridEss e) { + // Limit discharge to DC-PV power + return max(0, ess.getActivePower().orElse(0) - e.getDcDischargePower().orElse(0)); + } else { + // Limit discharge to 0 + return 0; + } + } + + /** + * Converts energy [Wh/15 min] to power [W]. + * + * @param energy the energy value + * @return the power value + */ + private static Integer toPower(Integer energy) { + return multiply(energy, PERIODS_PER_HOUR); + } +} diff --git a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/GetScheduleResponse.java b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/GetScheduleResponse.java deleted file mode 100644 index 4464d3548d4..00000000000 --- a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/GetScheduleResponse.java +++ /dev/null @@ -1,55 +0,0 @@ -package io.openems.edge.controller.ess.timeofusetariff.jsonrpc; - -import java.time.ZonedDateTime; -import java.util.UUID; - -import com.google.gson.JsonObject; - -import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; -import io.openems.common.utils.JsonUtils; - -/** - * Represents a JSON-RPC Response for 'getMeters'. - * - *

- * {
- *   "jsonrpc": "2.0",
- *   "id": "UUID",
- *   "result": {
- *     'schedule': [{
- *      'timestamp':...,
- *      'price':...,
- *      'state':...,
- *      'grid':...,
- *      'production':...,
- *      'consumption':...,
- *      'ess':...,
- *      'soc':...,
- *     }]
- *   }
- * }
- * 
- */ -public class GetScheduleResponse extends JsonrpcResponseSuccess { - - private final ZonedDateTime fromDate; - private final ScheduleDatas scheduleDatas; - - public GetScheduleResponse(ZonedDateTime fromDate, ScheduleDatas scheduleDatas) { - this(UUID.randomUUID(), fromDate, scheduleDatas); - } - - public GetScheduleResponse(UUID id, ZonedDateTime fromDate, ScheduleDatas scheduleDatas) { - super(id); - this.scheduleDatas = scheduleDatas; - this.fromDate = fromDate; - } - - @Override - public JsonObject getResult() { - return JsonUtils.buildJsonObject() // - .add("schedule", this.scheduleDatas.toJsonArray(this.fromDate)) // - .build(); - } - -} diff --git a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/optimizer/Context.java b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/optimizer/Context.java deleted file mode 100644 index d7d5dd8724c..00000000000 --- a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/optimizer/Context.java +++ /dev/null @@ -1,172 +0,0 @@ -package io.openems.edge.controller.ess.timeofusetariff.optimizer; - -import java.time.Clock; -import java.util.List; - -import io.openems.edge.common.sum.Sum; -import io.openems.edge.controller.ess.emergencycapacityreserve.ControllerEssEmergencyCapacityReserve; -import io.openems.edge.controller.ess.limittotaldischarge.ControllerEssLimitTotalDischarge; -import io.openems.edge.controller.ess.timeofusetariff.ControlMode; -import io.openems.edge.ess.api.ManagedSymmetricEss; -import io.openems.edge.predictor.api.manager.PredictorManager; -import io.openems.edge.timeofusetariff.api.TimeOfUseTariff; - -public record Context(// - Clock clock, // - Sum sum, // - PredictorManager predictorManager, // - TimeOfUseTariff timeOfUseTariff, // - ManagedSymmetricEss ess, // - List ctrlEmergencyCapacityReserves, // - List ctrlLimitTotalDischarges, // - ControlMode controlMode, // - int maxChargePowerFromGrid, // - boolean limitChargePowerFor14aEnWG) { - - public static class Builder { - private Clock clock; - private Sum sum; - private PredictorManager predictorManager; - private TimeOfUseTariff timeOfUseTariff; - private ManagedSymmetricEss ess; - private List ctrlEmergencyCapacityReserves; - private List ctrlLimitTotalDischarges; - private ControlMode controlMode; - private int maxChargePowerFromGrid; - private boolean limitChargePowerFor14aEnWG; - - /** - * The {@link Clock}. - * - * @param clock the {@link Clock} - * @return myself - */ - public Builder setClock(Clock clock) { - this.clock = clock; - return this; - } - - /** - * The {@link Sum}. - * - * @param sum the {@link Sum} - * @return myself - */ - public Builder setSum(Sum sum) { - this.sum = sum; - return this; - } - - /** - * The {@link PredictorManager}. - * - * @param predictorManager the {@link PredictorManager} - * @return myself - */ - public Builder setPredictorManager(PredictorManager predictorManager) { - this.predictorManager = predictorManager; - return this; - } - - /** - * The {@link TimeOfUseTariff}. - * - * @param timeOfUseTariff the {@link TimeOfUseTariff} - * @return myself - */ - public Builder setTimeOfUseTariff(TimeOfUseTariff timeOfUseTariff) { - this.timeOfUseTariff = timeOfUseTariff; - return this; - } - - /** - * The {@link ManagedSymmetricEss}. - * - * @param ess the {@link ManagedSymmetricEss} - * @return myself - */ - public Builder setEss(ManagedSymmetricEss ess) { - this.ess = ess; - return this; - } - - /** - * The list of {@link ControllerEssEmergencyCapacityReserve}. - * - * @param ctrlEmergencyCapacityReserves the list of - * {@link ControllerEssEmergencyCapacityReserve} - * @return myself - */ - public Builder setCtrlEmergencyCapacityReserves( - List ctrlEmergencyCapacityReserves) { - this.ctrlEmergencyCapacityReserves = ctrlEmergencyCapacityReserves; - return this; - } - - /** - * The list of {@link ControllerEssLimitTotalDischarge}. - * - * @param ctrlLimitTotalDischarges the list of - * {@link ControllerEssLimitTotalDischarge} - * @return myself - */ - public Builder setCtrlLimitTotalDischarges(List ctrlLimitTotalDischarges) { - this.ctrlLimitTotalDischarges = ctrlLimitTotalDischarges; - return this; - } - - /** - * The {@link ControlMode}. - * - * @param controlMode the {@link ControlMode} - * @return myself - */ - public Builder setControlMode(ControlMode controlMode) { - this.controlMode = controlMode; - return this; - } - - /** - * The maxChargePowerFromGrid. - * - * @param maxChargePowerFromGrid the maxChargePowerFromGrid - * @return myself - */ - public Builder setMaxChargePowerFromGrid(int maxChargePowerFromGrid) { - this.maxChargePowerFromGrid = maxChargePowerFromGrid; - return this; - } - - /** - * Always apply 14a EnWG limit of 4.2 kW. - * - * @param limitChargePowerFor14aEnWG boolean - * @return myself - */ - public Builder setLimitChargePowerFor14aEnWG(boolean limitChargePowerFor14aEnWG) { - this.limitChargePowerFor14aEnWG = limitChargePowerFor14aEnWG; - return this; - } - - /** - * Builds the {@link Context}. - * - * @return the {@link Context} record - */ - public Context build() { - return new Context(this.clock, this.sum, this.predictorManager, this.timeOfUseTariff, this.ess, - this.ctrlEmergencyCapacityReserves, this.ctrlLimitTotalDischarges, this.controlMode, - this.maxChargePowerFromGrid, this.limitChargePowerFor14aEnWG); - } - } - - /** - * Create a {@link Context} {@link Builder}. - * - * @return a {@link Builder} - */ - public static Builder create() { - return new Context.Builder(); - } - -} diff --git a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/package-info.java b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/package-info.java new file mode 100644 index 00000000000..7b31142b53d --- /dev/null +++ b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/package-info.java @@ -0,0 +1,3 @@ +@org.osgi.annotation.versioning.Version("1.0.0") +@org.osgi.annotation.bundle.Export +package io.openems.edge.controller.ess.timeofusetariff; diff --git a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImplTest.java b/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImplTest.java index f7d4af753f2..d3f32289678 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImplTest.java +++ b/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImplTest.java @@ -1,20 +1,12 @@ package io.openems.edge.controller.ess.timeofusetariff; -import static io.openems.common.utils.DateUtils.roundDownToQuarter; import static io.openems.edge.controller.ess.timeofusetariff.ControlMode.CHARGE_CONSUMPTION; import static io.openems.edge.controller.ess.timeofusetariff.Mode.AUTOMATIC; import static io.openems.edge.controller.ess.timeofusetariff.RiskLevel.MEDIUM; -import static io.openems.edge.controller.ess.timeofusetariff.TestData.CONSUMPTION_PREDICTION_QUARTERLY; -import static io.openems.edge.controller.ess.timeofusetariff.TestData.PRODUCTION_PREDICTION_QUARTERLY; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.SUM_CONSUMPTION; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.SUM_PRODUCTION; -import static java.time.temporal.ChronoUnit.DAYS; import java.time.Clock; import java.time.Instant; import java.time.ZoneOffset; -import java.time.ZonedDateTime; -import java.util.function.Supplier; import org.junit.Test; @@ -23,13 +15,8 @@ import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.controller.ess.timeofusetariff.optimizer.Context; -import io.openems.edge.controller.ess.timeofusetariff.optimizer.Optimizer; import io.openems.edge.controller.test.ControllerTest; import io.openems.edge.ess.test.DummyManagedSymmetricEss; -import io.openems.edge.predictor.api.prediction.Prediction; -import io.openems.edge.predictor.api.test.DummyPredictor; -import io.openems.edge.predictor.api.test.DummyPredictorManager; import io.openems.edge.timedata.test.DummyTimedata; import io.openems.edge.timeofusetariff.test.DummyTimeOfUseTariffProvider; @@ -45,28 +32,21 @@ public void test() throws Exception { } /** - * Creates a {@link TimeOfUseTariffControllerImplTest} instance. + * Creates a {@link TimeOfUseTariffControllerImpl} instance. * * @param clock a {@link Clock} * @return the object * @throws Exception on error */ public static TimeOfUseTariffControllerImpl create(Clock clock) throws Exception { - var now = roundDownToQuarter(ZonedDateTime.now(clock)); - final var midnight = now.truncatedTo(DAYS); var componentManager = new DummyComponentManager(clock); var sum = new DummySum(); - var predictor0 = new DummyPredictor("predictor0", componentManager, - Prediction.from(sum, SUM_PRODUCTION, midnight, PRODUCTION_PREDICTION_QUARTERLY), SUM_PRODUCTION); - var predictor1 = new DummyPredictor("predictor0", componentManager, - Prediction.from(sum, SUM_CONSUMPTION, midnight, CONSUMPTION_PREDICTION_QUARTERLY), SUM_CONSUMPTION); - var timeOfUseTariff = DummyTimeOfUseTariffProvider.fromHourlyPrices(clock, TestData.HOURLY_PRICES_SUMMER); + var timeOfUseTariff = DummyTimeOfUseTariffProvider.empty(clock); var sut = new TimeOfUseTariffControllerImpl(); new ControllerTest(sut) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", componentManager) // - .addReference("predictorManager", new DummyPredictorManager(predictor0, predictor1)) // .addReference("timedata", new DummyTimedata("timedata0")) // .addReference("timeOfUseTariff", timeOfUseTariff) // .addReference("sum", sum) // @@ -87,45 +67,4 @@ public static TimeOfUseTariffControllerImpl create(Clock clock) throws Exception .next(new TestCase()); return sut; } - - /** - * Gets the {@link Optimizer} via Java Reflection. - * - * @param ctrl the {@link TimeOfUseTariffControllerImplTest} - * @return the object - * @throws Exception on error - */ - public static Optimizer getOptimizer(TimeOfUseTariffControllerImpl ctrl) throws Exception { - var field = TimeOfUseTariffControllerImpl.class.getDeclaredField("optimizer"); - field.setAccessible(true); - return (Optimizer) field.get(ctrl); - } - - /** - * Calls the 'createParams()' method in the {@link Optimizer} via Java - * Reflection. - * - * @param optimizer the {@link Optimizer} - * @throws Exception on error - */ - public static void callCreateParams(Optimizer optimizer) throws Exception { - var method = Optimizer.class.getDeclaredMethod("createParams"); - method.setAccessible(true); - method.invoke(optimizer); - } - - /** - * Gets the {@link Context} via Java Reflection. - * - * @param ctrl the {@link TimeOfUseTariffControllerImplTest} - * @return the object - * @throws Exception on error - */ - @SuppressWarnings("unchecked") - public static Context getContext(TimeOfUseTariffControllerImpl ctrl) throws Exception { - var optimizer = getOptimizer(ctrl); - var field = Optimizer.class.getDeclaredField("context"); - field.setAccessible(true); - return ((Supplier) field.get(optimizer)).get(); - } } diff --git a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/UtilsTest.java b/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/UtilsTest.java new file mode 100644 index 00000000000..c7a104c3419 --- /dev/null +++ b/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/UtilsTest.java @@ -0,0 +1,215 @@ +package io.openems.edge.controller.ess.timeofusetariff; + +import static io.openems.edge.common.test.TestUtils.withValue; +import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.BALANCING; +import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.CHARGE_GRID; +import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.DELAY_DISCHARGE; +import static io.openems.edge.controller.ess.timeofusetariff.Utils.calculateAutomaticMode; +import static io.openems.edge.controller.ess.timeofusetariff.Utils.calculateChargeGridPower; +import static io.openems.edge.controller.ess.timeofusetariff.Utils.calculateDelayDischargePower; +import static io.openems.edge.controller.ess.timeofusetariff.Utils.calculateEssChargeInChargeGridPowerFromParams; +import static io.openems.edge.controller.ess.timeofusetariff.Utils.calculateMaxChargeProductionPower; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import io.openems.edge.common.sum.DummySum; +import io.openems.edge.controller.ess.timeofusetariff.Utils.ApplyState; +import io.openems.edge.ess.api.SymmetricEss; +import io.openems.edge.ess.test.DummyHybridEss; +import io.openems.edge.ess.test.DummyManagedSymmetricEss; + +public class UtilsTest { + + @Test + public void testCalculateChargeGridPower() { + assertEquals(-10000, calculateChargeGridPower(null, // + new DummyManagedSymmetricEss("ess0") // + .withCapacity(20000), // + /* essActivePower */ -6000, // + /* gridActivePower */ 10000, // + /* maxChargePowerFromGrid */ 20000, // + /* limitChargePowerFor14aEnWG */ false)); + + assertEquals(-4200, calculateChargeGridPower(null, // + new DummyManagedSymmetricEss("ess0") // + .withCapacity(20000), // + /* essActivePower */ -6000, // + /* gridActivePower */ 10000, // + /* maxChargePowerFromGrid */ 20000, // + /* limitChargePowerFor14aEnWG */ true)); + + assertEquals(-11000, calculateChargeGridPower(null, // + new DummyManagedSymmetricEss("ess0") // + .withCapacity(20000), // + /* essActivePower */ -6000, // + /* gridActivePower */ 5000, // + /* maxChargePowerFromGrid */ 20000, // + /* limitChargePowerFor14aEnWG */ false)); + + assertEquals(-5860, calculateChargeGridPower(1340, // + new DummyManagedSymmetricEss("ess0"), // + /* essActivePower */ -1000, // + /* gridActivePower */ 500, // + /* maxChargePowerFromGrid */ 24000, // + /* limitChargePowerFor14aEnWG */ false)); + + // Would be -3584, but limited to 5000 which is already surpassed + // TODO if this should actually serve as blackout-protection, a positive value + // would have to be returned + assertEquals(0, calculateChargeGridPower(1000, // + new DummyManagedSymmetricEss("ess0"), // + /* essActivePower */ 1000, // + /* gridActivePower */ 9000, // + /* maxChargePowerFromGrid */ 5000, // + /* limitChargePowerFor14aEnWG */ false)); + + assertEquals(-8360, calculateChargeGridPower(1340, // + new DummyHybridEss("ess0") // + .withDcDischargePower(-1500), // + /* essActivePower */ -1000, // + /* gridActivePower */ -2000, // + /* maxChargePowerFromGrid */ 24000, // + /* limitChargePowerFor14aEnWG */ false)); + } + + @Test + public void testCalculateChargeProduction() { + assertEquals(-500, calculateMaxChargeProductionPower(// + new DummySum() // + .withProductionAcActivePower(500)) // + .intValue()); + + assertEquals(0, calculateMaxChargeProductionPower(// + new DummySum()) // + .intValue()); + + assertEquals(0, calculateMaxChargeProductionPower(// + new DummySum() // + .withProductionAcActivePower(-100 /* wrong */)) // + .intValue()); + } + + @Test + public void testCalculateDelayDischarge() { + // DC-PV + assertEquals(500, calculateDelayDischargePower(// + new DummyHybridEss("ess0") // + .withActivePower(-500) // + .withDcDischargePower(-1000))); + + // Never negative + assertEquals(0, calculateDelayDischargePower(// + new DummyHybridEss("ess0") // + .withActivePower(-1500) // + .withDcDischargePower(-1000))); + + // AC-PV + assertEquals(0, calculateDelayDischargePower(// + new DummyManagedSymmetricEss("ess0") // + .withActivePower(-1500))); + } + + @Test + public void testCalculateMaxChargeGridPowerFromParams() { + final var ess = new DummyManagedSymmetricEss("ess0"); + + // No params, initial ESS + assertEquals(0, calculateEssChargeInChargeGridPowerFromParams(null, ess)); + + // No params, ESS with MaxApparentPower + withValue(ess, SymmetricEss.ChannelId.MAX_APPARENT_POWER, 1000); + assertEquals(250, calculateEssChargeInChargeGridPowerFromParams(null, ess)); + + // No params, ESS with Capacity + withValue(ess, SymmetricEss.ChannelId.CAPACITY, 15000); + assertEquals(7500, calculateEssChargeInChargeGridPowerFromParams(null, ess)); + + // With params (22 kWh; but few Consumption) + assertEquals(5360, calculateEssChargeInChargeGridPowerFromParams(1340, ess)); + } + + @Test + public void testCalculateAutomaticMode() { + assertEquals("Null-Check", new ApplyState(BALANCING, null), // + calculateAutomaticMode(// + new DummySum(), // + new DummyManagedSymmetricEss("ess0"), // + /* essChargeInChargeGrid */ 1000, // + /* maxChargePowerFromGrid */ 2000, // + /* limitChargePowerFor14aEnWG */ true, // + BALANCING)); + assertEquals("Null-Check", new ApplyState(BALANCING, null), // + calculateAutomaticMode(// + new DummySum() // + .withGridActivePower(100), // + new DummyManagedSymmetricEss("ess0"), // + /* essChargeInChargeGrid */ 1000, // + /* maxChargePowerFromGrid */ 2000, // + /* limitChargePowerFor14aEnWG */ true, // + BALANCING)); + + assertEquals("BALANCING", new ApplyState(BALANCING, null), // + calculateAutomaticMode(// + new DummySum() // + .withGridActivePower(100), // + new DummyManagedSymmetricEss("ess0") // + .withActivePower(500), // + /* essChargeInChargeGrid */ 1000, // + /* maxChargePowerFromGrid */ 2000, // + /* limitChargePowerFor14aEnWG */ true, // + BALANCING)); + + assertEquals("DELAY_DISCHARGE stays DELAY_DISCHARGE", new ApplyState(DELAY_DISCHARGE, 0), // + calculateAutomaticMode(// + new DummySum() // + .withGridActivePower(100), // + new DummyManagedSymmetricEss("ess0") // + .withActivePower(500), // + /* essChargeInChargeGrid */ 1000, // + /* maxChargePowerFromGrid */ 2000, // + /* limitChargePowerFor14aEnWG */ true, // + DELAY_DISCHARGE)); + assertEquals("DELAY_DISCHARGE to BALANCING", new ApplyState(BALANCING, null), // + calculateAutomaticMode(// + new DummySum() // + .withGridActivePower(-500), // + new DummyManagedSymmetricEss("ess0") // + .withActivePower(500), // + /* essChargeInChargeGrid */ 1000, // + /* maxChargePowerFromGrid */ 2000, // + /* limitChargePowerFor14aEnWG */ true, // + DELAY_DISCHARGE)); + + assertEquals("CHARGE_GRID stays CHARGE_GRID", new ApplyState(CHARGE_GRID, -1400), // + calculateAutomaticMode(// + new DummySum() // + .withGridActivePower(100), // + new DummyManagedSymmetricEss("ess0") // + .withActivePower(500), // + /* essChargeInChargeGrid */ 1000, // + /* maxChargePowerFromGrid */ 2000, // + /* limitChargePowerFor14aEnWG */ true, // + CHARGE_GRID)); + assertEquals("CHARGE_GRID to DELAY_DISCHARGE", new ApplyState(DELAY_DISCHARGE, 0), // + calculateAutomaticMode(// + new DummySum() // + .withGridActivePower(100), // + new DummyManagedSymmetricEss("ess0") // + .withActivePower(500), // + /* essChargeInChargeGrid */ 1000, // + /* maxChargePowerFromGrid */ 400, // + /* limitChargePowerFor14aEnWG */ true, // + CHARGE_GRID)); + assertEquals("CHARGE_GRID to BALANCING", new ApplyState(BALANCING, null), // + calculateAutomaticMode(// + new DummySum() // + .withGridActivePower(-500), // + new DummyManagedSymmetricEss("ess0") // + .withActivePower(500), // + /* essChargeInChargeGrid */ 1000, // + /* maxChargePowerFromGrid */ 0, // + /* limitChargePowerFor14aEnWG */ true, // + CHARGE_GRID)); + } +} diff --git a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/ScheduleDatasTest.java b/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/ScheduleDatasTest.java deleted file mode 100644 index 0ee6b1f3b95..00000000000 --- a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/ScheduleDatasTest.java +++ /dev/null @@ -1,134 +0,0 @@ -package io.openems.edge.controller.ess.timeofusetariff.jsonrpc; - -import static io.openems.common.utils.JsonUtils.prettyToString; -import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.CHARGE_GRID; -import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.DELAY_DISCHARGE; -import static io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImplTest.CLOCK; -import static io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImplTest.callCreateParams; -import static io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImplTest.getOptimizer; -import static io.openems.edge.controller.ess.timeofusetariff.jsonrpc.ScheduleDatas.fromLogString; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.time.ZoneId; -import java.time.ZonedDateTime; - -import org.junit.Test; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSortedMap; - -import io.openems.edge.controller.ess.timeofusetariff.StateMachine; -import io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImplTest; -import io.openems.edge.controller.ess.timeofusetariff.jsonrpc.ScheduleDatas.ScheduleData; -import io.openems.edge.controller.ess.timeofusetariff.optimizer.EnergyFlow; -import io.openems.edge.controller.ess.timeofusetariff.optimizer.Params.Length; -import io.openems.edge.controller.ess.timeofusetariff.optimizer.Params.OptimizePeriod; -import io.openems.edge.controller.ess.timeofusetariff.optimizer.Params.QuarterPeriod; -import io.openems.edge.controller.ess.timeofusetariff.optimizer.Simulator; - -public class ScheduleDatasTest { - - protected static final ZonedDateTime TIME = ZonedDateTime.of(2000, 1, 1, 0, 15, 0, 0, ZoneId.of("UTC")); - - protected static final ScheduleDatas SCHEDULE_DATAS = new ScheduleDatas(22_000, ImmutableList.of(// - new ScheduleData(TIME, null, 100, 200, 300, 1234, 222, 333, 78.9, DELAY_DISCHARGE, 987, 654), - new ScheduleData(TIME.plusMinutes(15), null, 100, 200, 300, 4567, 444, 333, 12.3, CHARGE_GRID, 987, 654))); - - @Test - public void testIsEmpty() { - assertFalse(SCHEDULE_DATAS.isEmpty()); - assertTrue(new ScheduleDatas(22_000, ImmutableList.of()).isEmpty()); - } - - @Test - public void testStream() { - assertEquals(2, SCHEDULE_DATAS.stream().count()); - } - - @Test - public void testToLogString() { - assertEquals( - """ - OPTIMIZER Time OptimizeBy EssMaxChargeEnergy EssMaxDischargeEnergy MaxBuyFromGrid EssInitial Production Consumption Price State EssChargeDischarge Grid - OPTIMIZER 00:15 - 100 200 300 1234 222 333 78.90 DELAY_DISCHARGE 987 654 - OPTIMIZER 00:30 - 100 200 300 4567 444 333 12.30 CHARGE_GRID 987 654 - """, - SCHEDULE_DATAS.toLogString("OPTIMIZER ")); - } - - @Test - public void testToJsonArray() { - assertEquals(""" - [ - { - "timestamp": "2000-01-01T00:00:00Z", - "soc": null, - "production": null, - "consumption": null, - "state": null, - "price": null, - "ess": null, - "grid": null - }, - { - "timestamp": "2000-01-01T00:15:00Z", - "soc": 6, - "production": 222, - "consumption": 333, - "state": 0, - "price": 78.9, - "ess": 987, - "grid": 654 - }, - { - "timestamp": "2000-01-01T00:30:00Z", - "soc": 21, - "production": 444, - "consumption": 333, - "state": 3, - "price": 12.3, - "ess": 987, - "grid": 654 - } - ]""", prettyToString(SCHEDULE_DATAS.toJsonArray(TIME.minusMinutes(15)))); - } - - @Test - public void testFromLogString() { - var log = SCHEDULE_DATAS.toLogString(""); - assertEquals(log, fromLogString(22_000, log).toLogString("")); - } - - @Test - public void testFromSchedule1() throws Exception { - var optimizer = getOptimizer(TimeOfUseTariffControllerImplTest.create(CLOCK)); - callCreateParams(optimizer); - var sds = ScheduleDatas.fromSchedule(optimizer); - assertEquals( - """ - Time OptimizeBy EssMaxChargeEnergy EssMaxDischargeEnergy MaxBuyFromGrid EssInitial Production Consumption Price State EssChargeDischarge Grid - """, - sds.toLogString("")); - } - - @Test - public void testFromSchedule2() throws Exception { - var sds = ScheduleDatas.fromSchedule(22_000, ImmutableSortedMap.of(// - TIME, // - new Simulator.Period(// - new OptimizePeriod(TIME, Length.QUARTER, 1, 2, 3, 4, 5, 6, 7., ImmutableList.of(// - new QuarterPeriod(TIME, 1, 2, 3, 4, 5, 6, 7))), - StateMachine.BALANCING, 10_000, - new EnergyFlow(0, 0, 1000 /* ess */, 500 /* grid */, 0, 0, 0, 0, 0, 0)) // - )); - assertEquals( - """ - OPTIMIZER Time OptimizeBy EssMaxChargeEnergy EssMaxDischargeEnergy MaxBuyFromGrid EssInitial Production Consumption Price State EssChargeDischarge Grid - OPTIMIZER 00:15 QUARTER 1 2 4 10000 5 6 7.00 BALANCING 1000 500 - """, - sds.toLogString("OPTIMIZER ")); - } - -} diff --git a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/optimizer/OptimizerTest.java b/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/optimizer/OptimizerTest.java deleted file mode 100644 index 310c8f74fc8..00000000000 --- a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/optimizer/OptimizerTest.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.openems.edge.controller.ess.timeofusetariff.optimizer; - -import static io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImplTest.CLOCK; -import static io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImplTest.getOptimizer; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -import io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImplTest; - -public class OptimizerTest { - - @Test - public void testEmpty() throws Exception { - var sut = getOptimizer(TimeOfUseTariffControllerImplTest.create(CLOCK)); - assertNull(sut.getParams()); - assertNull(sut.getCurrentStateMachine()); - assertTrue(sut.getSchedule().isEmpty()); - } - -} diff --git a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/optimizer/UtilsTest.java b/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/optimizer/UtilsTest.java deleted file mode 100644 index 58d02834e31..00000000000 --- a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/optimizer/UtilsTest.java +++ /dev/null @@ -1,558 +0,0 @@ -package io.openems.edge.controller.ess.timeofusetariff.optimizer; - -import static io.openems.common.utils.DateUtils.roundDownToQuarter; -import static io.openems.common.utils.JsonUtils.getAsFloat; -import static io.openems.common.utils.JsonUtils.getAsInt; -import static io.openems.common.utils.JsonUtils.getAsJsonArray; -import static io.openems.common.utils.JsonUtils.getAsJsonObject; -import static io.openems.common.utils.UuidUtils.getNilUuid; -import static io.openems.edge.common.test.TestUtils.withValue; -import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.BALANCING; -import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.CHARGE_GRID; -import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.DELAY_DISCHARGE; -import static io.openems.edge.controller.ess.timeofusetariff.TestData.CONSUMPTION_PREDICTION_QUARTERLY; -import static io.openems.edge.controller.ess.timeofusetariff.TestData.PAST_HOURLY_PRICES; -import static io.openems.edge.controller.ess.timeofusetariff.TestData.PAST_SOC; -import static io.openems.edge.controller.ess.timeofusetariff.TestData.PAST_STATES; -import static io.openems.edge.controller.ess.timeofusetariff.TestData.PRODUCTION_888_20231106; -import static io.openems.edge.controller.ess.timeofusetariff.TestData.PRODUCTION_PREDICTION_QUARTERLY; -import static io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImplTest.CLOCK; -import static io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImplTest.callCreateParams; -import static io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImplTest.getContext; -import static io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImplTest.getOptimizer; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.EnergyFlowTest.NO_FLOW; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.SimulatorTest.TIME; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.SimulatorTest.createParams888d20231106; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.ESS_MAX_SOC; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.SUM_CONSUMPTION; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.SUM_ESS_DISCHARGE_POWER; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.SUM_ESS_SOC; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.SUM_GRID; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.SUM_PRODUCTION; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.calculateChargeGridPower; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.calculateDelayDischargePower; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.calculateEssChargeInChargeGridPowerFromParams; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.calculateExecutionLimitSeconds; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.calculateMaxChargeProductionPower; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.createSimulatorParams; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.findFirstPeakIndex; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.findFirstValleyIndex; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.generateProductionPrediction; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.getEssMinSocEnergy; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.handleGetScheduleRequest; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.interpolateArray; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.joinConsumptionPredictions; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.paramsAreValid; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.postprocessRunState; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.postprocessSimulatorState; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.toEnergy; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.toPower; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.updateSchedule; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import java.time.Duration; -import java.time.Instant; -import java.time.ZoneId; -import java.time.ZoneOffset; -import java.time.ZonedDateTime; -import java.time.temporal.ChronoUnit; -import java.util.List; -import java.util.TreeMap; -import java.util.stream.IntStream; - -import org.junit.Test; - -import com.google.common.collect.ImmutableSortedMap; - -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.test.TimeLeapClock; -import io.openems.common.types.ChannelAddress; -import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.common.sum.DummySum; -import io.openems.edge.common.test.AbstractDummyOpenemsComponent; -import io.openems.edge.controller.ess.emergencycapacityreserve.ControllerEssEmergencyCapacityReserve; -import io.openems.edge.controller.ess.limittotaldischarge.ControllerEssLimitTotalDischarge; -import io.openems.edge.controller.ess.timeofusetariff.ControlMode; -import io.openems.edge.controller.ess.timeofusetariff.StateMachine; -import io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImplTest; -import io.openems.edge.controller.ess.timeofusetariff.optimizer.Simulator.Period; -import io.openems.edge.ess.api.SymmetricEss; -import io.openems.edge.ess.test.DummyHybridEss; -import io.openems.edge.ess.test.DummyManagedSymmetricEss; -import io.openems.edge.timedata.test.DummyTimedata; - -public class UtilsTest { - - protected static ImmutableSortedMap prepareExistingSchedule(ZonedDateTime fromDate, - StateMachine... existingSchedule) { - return IntStream.range(0, existingSchedule.length) // - .mapToObj(Integer::valueOf) // - .collect(ImmutableSortedMap.toImmutableSortedMap( - ZonedDateTime::compareTo, // - i -> fromDate.plusMinutes(i * 15), // - i -> existingSchedule[i])); - } - - @Test - public void testCreateSimulatorParams() throws Exception { - final var context = getContext(TimeOfUseTariffControllerImplTest.create(CLOCK)); - final var p = createSimulatorParams(context, ImmutableSortedMap.of()); - final var op = p.optimizePeriods().get(0); - assertEquals(4, p.optimizePeriods().size()); - assertEquals(10000, p.essTotalEnergy()); - assertEquals(0, p.essMinSocEnergy()); - assertEquals(250, op.essMaxChargeEnergy()); - assertEquals(250, op.essMaxDischargeEnergy()); - assertEquals(6000, p.essInitialEnergy()); - assertEquals(434, op.essChargeInChargeGrid()); - assertEquals(2500, op.maxBuyFromGrid()); - assertArrayEquals(ControlMode.CHARGE_CONSUMPTION.states, p.states()); - } - - @Test - public void testInterpolateArrayFloat() { - assertArrayEquals(new double[] { 123, 123, 234, 234, 345 }, // - interpolateArray(new Double[] { null, 123., 234., null, 345., null }), // - 0.0001F); - - assertArrayEquals(new double[] {}, // - interpolateArray(new Double[] { null }), // - 0.0001F); - } - - @Test - public void testInterpolateArrayInteger() { - assertArrayEquals(new int[] { 123, 123, 234, 234, 345 }, // - interpolateArray(new Integer[] { null, 123, 234, null, 345, null })); - - assertArrayEquals(new int[] {}, // - interpolateArray(new Integer[] { null })); - - assertArrayEquals(new int[] { 123, 123 }, // - interpolateArray(new Integer[] { null, 123 })); - - assertArrayEquals(new int[] { 123 }, // - interpolateArray(new Integer[] { 123, null })); - } - - @Test - public void testToPower() { - assertEquals(2000, (int) toPower(500)); - assertNull(toPower(null)); - } - - @Test - public void testGenerateProductionPrediction() { - final var arr = new Integer[] { 1, 2, 3 }; - assertArrayEquals(arr, generateProductionPrediction(arr, 2)); - assertArrayEquals(new Integer[] { 1, 2, 3, 0 }, generateProductionPrediction(arr, 4)); - } - - @Test - public void testJoinConsumptionPredictions() { - assertArrayEquals(// - new Integer[] { 1, 2, 3, 4, 55, 66, 77, 88, 99 }, // - joinConsumptionPredictions(4, // - new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, // - new Integer[] { 11, 22, 33, 44, 55, 66, 77, 88, 99 })); - } - - @Test - public void testFindFirstPeakIndex() { - assertEquals(0, findFirstPeakIndex(0, new double[0])); - assertEquals(0, findFirstPeakIndex(0, new double[] { 1 })); - assertEquals(0, findFirstPeakIndex(0, new double[] { 1, 0 })); - assertEquals(1, findFirstPeakIndex(0, new double[] { 0, 1, 0 })); - assertEquals(1, findFirstPeakIndex(0, new double[] { 0, 1, 0, 1 })); - assertEquals(5, findFirstPeakIndex(5, new double[0])); - } - - @Test - public void testFindFirstValleyIndex() { - assertEquals(0, findFirstValleyIndex(0, new double[0])); - assertEquals(0, findFirstValleyIndex(0, new double[] { 1 })); - assertEquals(1, findFirstValleyIndex(0, new double[] { 1, 0 })); - assertEquals(0, findFirstValleyIndex(0, new double[] { 0, 1, 0 })); - assertEquals(2, findFirstValleyIndex(1, new double[] { 0, 1, 0, 1 })); - assertEquals(5, findFirstValleyIndex(5, new double[0])); - } - - @Test - public void testCalculateChargeGridPower() { - var params = createParams888d20231106(ControlMode.CHARGE_CONSUMPTION.states); - assertNull(calculateChargeGridPower(params, // - new DummyManagedSymmetricEss("ess0"), // - new DummySum(), // - /* maxChargePowerFromGrid */ 24_000, // - /* limitChargePowerFor14aEnWG */ false)); - - assertEquals(-10000, calculateChargeGridPower(null, // - new DummyManagedSymmetricEss("ess0") // - .withCapacity(20_000) // - .withActivePower(-6_000), // - new DummySum() // - .withGridActivePower(10_000), // - /* maxChargePowerFromGrid */ 20_000, // - /* limitChargePowerFor14aEnWG */ false).intValue()); - - assertEquals(-4200, calculateChargeGridPower(null, // - new DummyManagedSymmetricEss("ess0") // - .withCapacity(20_000) // - .withActivePower(-6_000), // - new DummySum() // - .withGridActivePower(10_000), // - /* maxChargePowerFromGrid */ 20_000, // - /* limitChargePowerFor14aEnWG */ true).intValue()); - - assertEquals(-11000, calculateChargeGridPower(null, // - new DummyManagedSymmetricEss("ess0") // - .withCapacity(20_000) // - .withActivePower(-6_000), // - new DummySum() // - .withGridActivePower(5_000), // - /* maxChargePowerFromGrid */ 20_000, // - /* limitChargePowerFor14aEnWG */ false).intValue()); - - assertEquals(-5860, calculateChargeGridPower(params, // - new DummyManagedSymmetricEss("ess0") // - .withActivePower(-1000), // - new DummySum() // - .withGridActivePower(500), // - /* maxChargePowerFromGrid */ 24_000, // - /* limitChargePowerFor14aEnWG */ false).intValue()); - - // Would be -3584, but limited to 5000 which is already surpassed - // TODO if this should actually serve as blackout-protection, a positive value - // would have to be returned - assertEquals(0, calculateChargeGridPower(params, // - new DummyManagedSymmetricEss("ess0") // - .withActivePower(1000), // - new DummySum() // - .withGridActivePower(9000), // - /* maxChargePowerFromGrid */ 5_000, // - /* limitChargePowerFor14aEnWG */ false).intValue()); - - assertEquals(-8360, calculateChargeGridPower(params, // - new DummyHybridEss("ess0") // - .withActivePower(-1000) // - .withDcDischargePower(-1500), // - new DummySum() // - .withGridActivePower(-2000), // - /* maxChargePowerFromGrid */ 24_000, // - /* limitChargePowerFor14aEnWG */ false).intValue()); - } - - @Test - public void testCalculateChargeProduction() { - assertEquals(-500, calculateMaxChargeProductionPower(// - new DummySum() // - .withProductionAcActivePower(500)) // - .intValue()); - - assertEquals(0, calculateMaxChargeProductionPower(// - new DummySum()) // - .intValue()); - - assertEquals(0, calculateMaxChargeProductionPower(// - new DummySum() // - .withProductionAcActivePower(-100 /* wrong */)) // - .intValue()); - } - - @Test - public void testCalculateDelayDischarge() { - // DC-PV - assertEquals(500, calculateDelayDischargePower(// - new DummyHybridEss("ess0") // - .withActivePower(-500) // - .withDcDischargePower(-1000)) - .intValue()); - - // Never negative - assertEquals(0, calculateDelayDischargePower(// - new DummyHybridEss("ess0") // - .withActivePower(-1500) // - .withDcDischargePower(-1000)) - .intValue()); - - // AC-PV - assertEquals(0, calculateDelayDischargePower(// - new DummyManagedSymmetricEss("ess0") // - .withActivePower(-1500)) // - .intValue()); - } - - @Test - public void testParamsAreValid() throws Exception { - var builder = Params.create() // - .setTime(TIME) // - .setEssInitialEnergy(0) // - .setEssTotalEnergy(22000) // - .setEssMinSocEnergy(2_000) // - .setEssMaxSocEnergy(20_000) // - .seMaxBuyFromGrid(toEnergy(24_000)) // - .seMaxBuyFromGrid(0) // - .setStates(new StateMachine[0]); - - // No periods are available - assertFalse(paramsAreValid(builder // - .setProductions() // - .setConsumptions() // - .setPrices() // - .build())); - - // Production and Consumption predictions are all zero - assertFalse(paramsAreValid(builder // - .setProductions(0, 0, 0) // - .setConsumptions(0, 0) // - .setPrices(123F) // - .build())); - - // Prices are all the same - assertFalse(paramsAreValid(builder // - .setProductions(0, 1, 3) // - .setConsumptions(0, 2) // - .setPrices(123F, 123F) // - .build())); - - // Finally got it right... - assertTrue(paramsAreValid(builder // - .setProductions(0, 1, 3) // - .setConsumptions(0, 2) // - .setPrices(123F, 124F) // - .build())); - assertEquals(2, builder.build().optimizePeriods().size()); - } - - private static class MyControllerEssLimitTotalDischarge - extends AbstractDummyOpenemsComponent - implements ControllerEssLimitTotalDischarge { - - protected MyControllerEssLimitTotalDischarge(Integer minSoc) { - super("ctrl0", // - OpenemsComponent.ChannelId.values(), // - ControllerEssLimitTotalDischarge.ChannelId.values() // - ); - withValue(this.getMinSocChannel(), minSoc); - } - - @Override - public void run() throws OpenemsNamedException { - } - - @Override - protected MyControllerEssLimitTotalDischarge self() { - return this; - } - } - - private static class MyControllerEssEmergencyCapacityReserve - extends AbstractDummyOpenemsComponent - implements ControllerEssEmergencyCapacityReserve { - - protected MyControllerEssEmergencyCapacityReserve(Integer reserveSoc) { - super("ctrl0", // - OpenemsComponent.ChannelId.values(), // - ControllerEssEmergencyCapacityReserve.ChannelId.values() // - ); - withValue(this.getActualReserveSocChannel(), reserveSoc); - } - - @Override - public void run() throws OpenemsNamedException { - } - - @Override - protected MyControllerEssEmergencyCapacityReserve self() { - return this; - } - } - - @Test - public void testGetEssMinSocEnergy() { - var t1 = new MyControllerEssLimitTotalDischarge(50); - var t2 = new MyControllerEssLimitTotalDischarge(null); - var t3 = new MyControllerEssEmergencyCapacityReserve(30); - assertEquals(5000, getEssMinSocEnergy(new Context(// - null, null, null, null, null, // - List.of(t3), List.of(t1, t2), // - null, 0, false), // - 10000)); - } - - @Test - public void testHandleScheduleRequest() throws Exception { - final var clock = new TimeLeapClock(Instant.parse("2020-03-04T14:19:00.00Z"), ZoneOffset.UTC); - final var ctrl = TimeOfUseTariffControllerImplTest.create(clock); - - // Simulate historic data - var now = roundDownToQuarter(ZonedDateTime.now(clock)); - final var fromDate = now.minusHours(3); - var timedata = new DummyTimedata("timedata0"); - for (var i = 0; i < 12; i++) { - var quarter = fromDate.plusMinutes(i * 15); - timedata.add(quarter, new ChannelAddress("ctrl0", "QuarterlyPrices"), PAST_HOURLY_PRICES[i]); - timedata.add(quarter, new ChannelAddress("ctrl0", "StateMachine"), PAST_STATES[i]); - timedata.add(quarter, SUM_PRODUCTION, PRODUCTION_PREDICTION_QUARTERLY[i]); - timedata.add(quarter, SUM_CONSUMPTION, CONSUMPTION_PREDICTION_QUARTERLY[i]); - timedata.add(quarter, SUM_ESS_SOC, PAST_SOC[i]); - timedata.add(quarter, SUM_ESS_DISCHARGE_POWER, PRODUCTION_888_20231106[i]); - timedata.add(quarter, SUM_GRID, PRODUCTION_888_20231106[i]); - } - - var optimizer = getOptimizer(ctrl); - callCreateParams(optimizer); - - // Testing only past data. For full data, optimizer has to be created as well. - var result = handleGetScheduleRequest(optimizer, getNilUuid(), timedata, "ctrl0", clock.now()).getResult(); - - // JsonUtils.prettyPrint(result); - - var schedule = getAsJsonArray(result, "schedule"); - assertEquals(11, schedule.size()); - { - var period = getAsJsonObject(schedule.get(0)); - assertEquals(PAST_HOURLY_PRICES[0], getAsFloat(period, "price"), 0.00F); - assertEquals(PRODUCTION_PREDICTION_QUARTERLY[0] / 4, getAsInt(period, "production")); - } - } - - @Test - public void testPostprocessPeriodState() { - var p = Params.create() // - .setTime(TIME) // - .setEssInitialEnergy(0) // - .setEssTotalEnergy(22000) // - .setEssMinSocEnergy(2_000) // - .setEssMaxSocEnergy(20_000) // - .setEssMaxChargeEnergy(0) // - .setEssMaxDischargeEnergy(0) // - .seMaxBuyFromGrid(toEnergy(24_000)) // - .setProductions() // - .setConsumptions() // - .setPrices(new double[] { 123 }) // - .setStates(new StateMachine[0]) // - .build(); - - assertEquals("BALANCING stays BALANCING", // - BALANCING, postprocessSimulatorState(p, 0, BALANCING, NO_FLOW)); - - assertEquals("DELAY_DISCHARGE but battery is empty", // - BALANCING, postprocessSimulatorState(p, 2000, DELAY_DISCHARGE, NO_FLOW)); - - assertEquals("DELAY_DISCHARGE and would discharge in balancing", // - DELAY_DISCHARGE, postprocessSimulatorState(p, 2001, DELAY_DISCHARGE, NO_FLOW)); - assertEquals("DELAY_DISCHARGE and would charge from PV in balancing", // - BALANCING, postprocessSimulatorState(p, 2001, DELAY_DISCHARGE, - new EnergyFlow(0, 0, 0, 0, 0, 0, 1 /* productionToEss */, 0, 0, 0))); - - assertEquals("CHARGE_GRID actually from grid", // - CHARGE_GRID, postprocessSimulatorState(p, 0, CHARGE_GRID, - new EnergyFlow(0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /* gridToEss */))); - assertEquals("CHARGE_GRID but actually not charging", // - BALANCING, postprocessSimulatorState(p, 0, CHARGE_GRID, NO_FLOW)); - assertEquals("CHARGE_GRID but battery is full", // - DELAY_DISCHARGE, postprocessSimulatorState(p, 20_001, CHARGE_GRID, - new EnergyFlow(0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /* gridToEss */))); - } - - @Test - public void testPostprocessRunState() { - // SoC undefined -> all stay - assertEquals(BALANCING, postprocessRunState(0, null, 0, BALANCING)); - assertEquals(DELAY_DISCHARGE, postprocessRunState(0, null, 0, DELAY_DISCHARGE)); - assertEquals(CHARGE_GRID, postprocessRunState(0, null, 0, CHARGE_GRID)); - - assertEquals("BALANCING stays BALANCING", // - BALANCING, postprocessRunState(10, 10, 0, BALANCING)); - - assertEquals("DELAY_DISCHARGE but SoC is at Min-SoC", // - BALANCING, postprocessRunState(10, 10, 0, DELAY_DISCHARGE)); - assertEquals("DELAY_DISCHARGE and SoC is above Min-SoC", // - DELAY_DISCHARGE, postprocessRunState(10, 11, 0, DELAY_DISCHARGE)); - - assertEquals("CHARGE_GRID but SoC is at Max-SoC", // - DELAY_DISCHARGE, postprocessRunState((int) ESS_MAX_SOC, (int) ESS_MAX_SOC + 1, 0, CHARGE_GRID)); - assertEquals("CHARGE_GRID and SoC is below or equal Max-SoC", // - CHARGE_GRID, postprocessRunState((int) ESS_MAX_SOC, (int) ESS_MAX_SOC, 0, CHARGE_GRID)); - } - - @Test - public void testCalculateExecutionLimitSeconds() { - final var clock = new TimeLeapClock(Instant.parse("2022-01-01T00:00:00.00Z"), ZoneOffset.UTC); - assertEquals(Duration.ofMinutes(14).plusSeconds(30).toSeconds(), calculateExecutionLimitSeconds(clock)); - - clock.leap(11, ChronoUnit.MINUTES); - assertEquals(Duration.ofMinutes(3).plusSeconds(30).toSeconds(), calculateExecutionLimitSeconds(clock)); - - clock.leap(150, ChronoUnit.SECONDS); - assertEquals(60, calculateExecutionLimitSeconds(clock)); - - clock.leap(1, ChronoUnit.SECONDS); - assertEquals(Duration.ofMinutes(15).plusSeconds(59).toSeconds(), calculateExecutionLimitSeconds(clock)); - } - - @Test - public void testCalculateMaxChargeGridPowerFromParams() { - final var params = createParams888d20231106(ControlMode.CHARGE_CONSUMPTION.states); - final var ess = new DummyManagedSymmetricEss("ess0"); - - // No params, initial ESS - assertEquals(0, calculateEssChargeInChargeGridPowerFromParams(null, ess)); - - // No params, ESS with MaxApparentPower - withValue(ess, SymmetricEss.ChannelId.MAX_APPARENT_POWER, 1000); - assertEquals(250, calculateEssChargeInChargeGridPowerFromParams(null, ess)); - - // No params, ESS with Capacity - withValue(ess, SymmetricEss.ChannelId.CAPACITY, 15000); - assertEquals(7500, calculateEssChargeInChargeGridPowerFromParams(null, ess)); - - // With params (22 kWh; but few Consumption) - assertEquals(5360, calculateEssChargeInChargeGridPowerFromParams(params, ess)); - } - - @Test - public void testUpdateSchedule() { - final ZonedDateTime t = ZonedDateTime.of(2000, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC")); - final Period pOld = new Period(null, DELAY_DISCHARGE, 0, NO_FLOW); - final Period pNew = new Period(null, BALANCING, 0, NO_FLOW); - - var schedule = new TreeMap(); - schedule.put(t.minusMinutes(15), pOld); // old entry is removed - schedule.put(t, pOld); // current entry stays - schedule.put(t.plusMinutes(15), pOld); // is overridden - schedule.put(t.plusMinutes(30), pOld); // is overridden - schedule.put(t.plusMinutes(45), pOld); // timestamp is missing in new Schedule -> remove - - var newSchedule = ImmutableSortedMap.naturalOrder() // - .put(t, pNew) // - .put(t.plusMinutes(15), pNew) // - .put(t.plusMinutes(30), pNew) // - .build(); - - updateSchedule(t, schedule, newSchedule); - - // One old entry - assertEquals(1, schedule.values().stream().filter(v -> v == pOld).count()); - - // Two new entries - assertEquals(2, schedule.values().stream().filter(v -> v == pNew).count()); - - // No old entry - assertEquals(0, schedule.keySet().stream().filter(tz -> tz.isBefore(t)).count()); - - // Details - assertEquals(pOld, schedule.get(t)); - assertEquals(pNew, schedule.get(t.plusMinutes(15))); - assertEquals(pNew, schedule.get(t.plusMinutes(30))); - - // No current entry -> handle null - schedule.remove(t); - updateSchedule(t, schedule, newSchedule); - } -} diff --git a/io.openems.edge.core/bnd.bnd b/io.openems.edge.core/bnd.bnd index 670793f4591..58ebb64e861 100644 --- a/io.openems.edge.core/bnd.bnd +++ b/io.openems.edge.core/bnd.bnd @@ -16,6 +16,7 @@ Bundle-Version: 1.0.0.${tstamp} io.openems.edge.predictor.api,\ io.openems.edge.scheduler.api,\ io.openems.edge.timedata.api,\ + io.openems.edge.timeofusetariff.api,\ io.openems.wrapper.fastexcel,\ io.openems.wrapper.okhttp,\ io.openems.wrapper.sdnotify,\ diff --git a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome20.java b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome20.java index c5fa2b7406e..083bd11673b 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome20.java +++ b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome20.java @@ -5,6 +5,7 @@ import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.battery; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.batteryInverter; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.charger; +import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.chargerOld; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.ctrlEmergencyCapacityReserve; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.ctrlEssSurplusFeedToGrid; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.emergencyMeter; @@ -78,6 +79,7 @@ import io.openems.edge.core.appmanager.dependency.aggregatetask.SchedulerByCentralOrderConfiguration.SchedulerComponent; import io.openems.edge.core.appmanager.formly.Exp; import io.openems.edge.core.appmanager.formly.JsonFormlyUtil; +import io.openems.edge.core.appmanager.formly.expression.BooleanExpression; /** * Describes a FENECON Home 20 energy storage system. @@ -97,8 +99,10 @@ "CT_RATIO_FIRST": 200, "HAS_AC_METER": false, "AC_METER_TYPE": {@link AcMeterType}, - "HAS_PV_[1-4]":true, - "PV_ALIAS_[1-4]":"PV [1-4]", + "HAS_PV_[1-4]":true, // deprecated + "PV_ALIAS_[1-4]":"PV [1-4]", // deprecated + "HAS_MPPT_[1-2]":true, + "MPPT_ALIAS_[1-2]":"MPPT [1-2]", "HAS_EMERGENCY_RESERVE":true, "EMERGENCY_RESERVE_ENABLED":true, "EMERGENCY_RESERVE_SOC":20, @@ -178,9 +182,17 @@ public Type self() { } + @Deprecated private static final int MAX_NUMBER_OF_PV = 4; + @Deprecated private static final IntFunction HAS_PV = value -> "HAS_PV_" + (value + 1); + @Deprecated private static final IntFunction PV_ALIAS = value -> "ALIAS_PV_" + (value + 1); + + private static final int MAX_NUMBER_OF_MPPT = 2; + private static final IntFunction HAS_MPPT = value -> "HAS_MPPT_" + (value + 1); + private static final IntFunction MPPT_ALIAS = value -> "ALIAS_MPPT_" + (value + 1); + private final Map pvDefs = new TreeMap<>(); @Activate @@ -192,21 +204,55 @@ public FeneconHome20(// ) { super(componentManager, componentContext, cm, componentUtil); + BooleanExpression anyOldPvSelected = null; for (int i = 0; i < MAX_NUMBER_OF_PV; i++) { final var oneBased = i + 1; final var hasPv = new ParentPropertyImpl(HAS_PV.apply(i), AppDef.copyOfGeneric(defaultDef(), def -> def // .setTranslatedLabel("App.IntegratedSystem.hasPv.label", oneBased, (oneBased + 1) / 2) // .setDefaultValue(false) // - .setField(JsonFormlyUtil::buildCheckboxFromNameable) // )); + hasPv.def().setField(t -> JsonFormlyUtil.buildCheckboxFromNameable(t), + (app, property, l, parameter, field) -> { + field.onlyShowIf(Exp.currentModelValue(hasPv).notNull()); + }); + + if (anyOldPvSelected == null) { + anyOldPvSelected = Exp.currentModelValue(hasPv).isNull(); + } else { + anyOldPvSelected = anyOldPvSelected.and(Exp.currentModelValue(hasPv).isNull()); + } + final var pvAlias = new ParentPropertyImpl(PV_ALIAS.apply(i), AppDef.copyOfGeneric(defaultDef(), def -> def // .setTranslatedLabel("App.IntegratedSystem.pvAlias.label", oneBased) // .setDefaultValueString((app, property, l, parameter) -> TranslationUtil .getTranslation(parameter.bundle(), "App.IntegratedSystem.pvAlias.alias", oneBased)) // .setField(JsonFormlyUtil::buildInputFromNameable, (app, property, l, parameter, field) -> { field.onlyShowIf(Exp.currentModelValue(hasPv).notNull()); + }))); + + this.pvDefs.put(hasPv.name(), hasPv); + this.pvDefs.put(pvAlias.name(), pvAlias); + } + final var tempAnyOldPvSelected = anyOldPvSelected; + + for (int i = 0; i < MAX_NUMBER_OF_MPPT; i++) { + final var oneBased = i + 1; + final var hasPv = new ParentPropertyImpl(HAS_MPPT.apply(i), AppDef.copyOfGeneric(defaultDef(), def -> def // + .setTranslatedLabel("App.IntegratedSystem.hasMppt.label", oneBased) // + .setDefaultValue(false) // + .setField(JsonFormlyUtil::buildCheckboxFromNameable, (app, property, l, parameter, field) -> { + field.onlyShowIf(tempAnyOldPvSelected); }) // )); + final var pvAlias = new ParentPropertyImpl(MPPT_ALIAS.apply(i), + AppDef.copyOfGeneric(defaultDef(), def -> def // + .setTranslatedLabel("App.IntegratedSystem.mpptAlias.label", oneBased) // + .setDefaultValueString((app, property, l, parameter) -> TranslationUtil.getTranslation( + parameter.bundle(), "App.IntegratedSystem.mpptAlias.alias", oneBased)) // + .setField(JsonFormlyUtil::buildInputFromNameable, (app, property, l, parameter, field) -> { + field.onlyShowIf(Exp.currentModelValue(hasPv).notNull()); + }) // + )); this.pvDefs.put(hasPv.name(), hasPv); this.pvDefs.put(pvAlias.name(), pvAlias); @@ -279,6 +325,16 @@ protected ThrowingTriFunction self() { } + @Deprecated private static final int MAX_NUMBER_OF_PV = 6; + @Deprecated private static final IntFunction HAS_PV = value -> "HAS_PV_" + (value + 1); + @Deprecated private static final IntFunction PV_ALIAS = value -> "ALIAS_PV_" + (value + 1); + + private static final int MAX_NUMBER_OF_MPPT = 3; + private static final IntFunction HAS_MPPT = value -> "HAS_MPPT_" + (value + 1); + private static final IntFunction MPPT_ALIAS = value -> "ALIAS_MPPT_" + (value + 1); + private final Map pvDefs = new TreeMap<>(); @Activate @@ -192,13 +204,24 @@ public FeneconHome30(// ) { super(componentManager, componentContext, cm, componentUtil); + BooleanExpression anyOldPvSelected = null; for (int i = 0; i < MAX_NUMBER_OF_PV; i++) { final var oneBased = i + 1; final var hasPv = new ParentPropertyImpl(HAS_PV.apply(i), AppDef.copyOfGeneric(defaultDef(), def -> def // .setTranslatedLabel("App.IntegratedSystem.hasPv.label", oneBased, (oneBased + 1) / 2) // .setDefaultValue(false) // - .setField(JsonFormlyUtil::buildCheckboxFromNameable) // )); + hasPv.def().setField(t -> JsonFormlyUtil.buildCheckboxFromNameable(t), + (app, property, l, parameter, field) -> { + field.onlyShowIf(Exp.currentModelValue(hasPv).notNull()); + }); + + if (anyOldPvSelected == null) { + anyOldPvSelected = Exp.currentModelValue(hasPv).isNull(); + } else { + anyOldPvSelected = anyOldPvSelected.and(Exp.currentModelValue(hasPv).isNull()); + } + final var pvAlias = new ParentPropertyImpl(PV_ALIAS.apply(i), AppDef.copyOfGeneric(defaultDef(), def -> def // .setTranslatedLabel("App.IntegratedSystem.pvAlias.label", oneBased) // .setDefaultValueString((app, property, l, parameter) -> TranslationUtil @@ -208,6 +231,30 @@ public FeneconHome30(// }) // )); + this.pvDefs.put(hasPv.name(), hasPv); + this.pvDefs.put(pvAlias.name(), pvAlias); + } + final var tempAnyOldPvSelected = anyOldPvSelected; + + for (int i = 0; i < MAX_NUMBER_OF_MPPT; i++) { + final var oneBased = i + 1; + final var hasPv = new ParentPropertyImpl(HAS_MPPT.apply(i), AppDef.copyOfGeneric(defaultDef(), def -> def // + .setTranslatedLabel("App.IntegratedSystem.hasMppt.label", oneBased) // + .setDefaultValue(false) // + .setField(JsonFormlyUtil::buildCheckboxFromNameable, (app, property, l, parameter, field) -> { + field.onlyShowIf(tempAnyOldPvSelected); + }) // + )); + final var pvAlias = new ParentPropertyImpl(MPPT_ALIAS.apply(i), + AppDef.copyOfGeneric(defaultDef(), def -> def // + .setTranslatedLabel("App.IntegratedSystem.mpptAlias.label", oneBased) // + .setDefaultValueString((app, property, l, parameter) -> TranslationUtil.getTranslation( + parameter.bundle(), "App.IntegratedSystem.mpptAlias.alias", oneBased)) // + .setField(JsonFormlyUtil::buildInputFromNameable, (app, property, l, parameter, field) -> { + field.onlyShowIf(Exp.currentModelValue(hasPv).notNull()); + }) // + )); + this.pvDefs.put(hasPv.name(), hasPv); this.pvDefs.put(pvAlias.name(), pvAlias); } @@ -279,6 +326,16 @@ protected ThrowingTriFunction def// .setTranslatedLabelWithAppPrefix(".filterForHome.label") // .setTranslatedDescriptionWithAppPrefix(".filterForHome.description") // - .setDefaultValue((app, property, l, parameter) -> JsonNull.INSTANCE) + .setDefaultValue("") // .setField(JsonFormlyUtil::buildInputFromNameable, (app, property, l, parameter, field) -> { - field.onlyShowIf(Exp.currentModelValue(MULTIPLE_HOMES_CHECK).notNull() - .or(Exp.currentModelValue(property).notNull())); + field.onlyShowIf(Exp.currentModelValue(MULTIPLE_HOMES_CHECK).notNull()); }) // .bidirectional(TIME_OF_USE_TARIFF_PROVIDER_ID, "filter", ComponentManagerSupplier::getComponentManager))); @@ -146,7 +144,8 @@ protected ThrowingTriFunction, L final var alias = this.getString(p, l, Property.ALIAS); final var accessToken = this.getValueOrDefault(p, Property.ACCESS_TOKEN, null); - final var filter = this.getValueOrDefault(p, Property.FILTER, null); + final var multipleHomesCheck = this.getBoolean(p, Property.MULTIPLE_HOMES_CHECK); + final var filter = multipleHomesCheck ? this.getString(p, Property.FILTER) : ""; final var components = Lists.newArrayList(// new EdgeConfig.Component(ctrlEssTimeOfUseTariffId, alias, "Controller.Ess.Time-Of-Use-Tariff", @@ -158,7 +157,7 @@ protected ThrowingTriFunction, L .onlyIf(accessToken != null && !accessToken.equals("xxx"), b -> { b.addProperty("accessToken", accessToken); }) // - .addPropertyIfNotNull("filter", filter) // + .addProperty("filter", filter) // .build())// ); diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties index 43f56722dfc..d0e0f07245e 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties @@ -214,9 +214,12 @@ App.IntegratedSystem.predictor0.alias = Prognose App.IntegratedSystem.ctrlEssSurplusFeedToGrid0.alias = Überschusseinspeisung App.IntegratedSystem.emergencyMeter.alias = Notstromverbraucher App.IntegratedSystem.ctrlEmergencyCapacityReserve0.alias = Ansteuerung der Notstromreserve -App.IntegratedSystem.hasPv.label = Hat DC-PV {0} (MPPT {1}) +App.IntegratedSystem.hasPv.label = Hat DC-PV {0} (MPPT {1}) (Nicht mehr unterstützt) +App.IntegratedSystem.hasMppt.label = Hat MPPT {0} App.IntegratedSystem.pvAlias.label = PV {0} Alias App.IntegratedSystem.pvAlias.alias = PV {0} +App.IntegratedSystem.mpptAlias.label = MPPT {0} Alias +App.IntegratedSystem.mpptAlias.alias = MPPT {0} App.IntegratedSystem.hasAcMeter.label = Hat AC-Zähler App.IntegratedSystem.acMeterType.label = AC-Zähler Typ diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties index 53bbdfccfc7..75b69cbbf27 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties @@ -214,9 +214,12 @@ App.IntegratedSystem.predictor0.alias = Forecast App.IntegratedSystem.ctrlEssSurplusFeedToGrid0.alias = Excess feed-in App.IntegratedSystem.emergencyMeter.alias = Emergency power consumers App.IntegratedSystem.ctrlEmergencyCapacityReserve0.alias = Control of the emergency power reserve -App.IntegratedSystem.hasPv.label = Has DC-PV {0} (MPPT {1}) +App.IntegratedSystem.hasPv.label = Has DC-PV {0} (MPPT {1}) (No longer supported) +App.IntegratedSystem.hasMppt.label = Hat MPPT {0} App.IntegratedSystem.pvAlias.label = PV {0} Alias App.IntegratedSystem.pvAlias.alias = PV {0} +App.IntegratedSystem.mpptAlias.label = MPPT {0} Alias +App.IntegratedSystem.mpptAlias.alias = MPPT {0} App.IntegratedSystem.hasAcMeter.label = Has AC meter App.IntegratedSystem.acMeterType.label = AC-Meter Type diff --git a/io.openems.edge.core/src/io/openems/edge/core/predictormanager/PredictorManagerImpl.java b/io.openems.edge.core/src/io/openems/edge/core/predictormanager/PredictorManagerImpl.java index c2393659ebf..5e820a73686 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/predictormanager/PredictorManagerImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/predictormanager/PredictorManagerImpl.java @@ -127,7 +127,7 @@ private Prediction getPredictionSum(Sum.ChannelId channelId) { ESS_DISCHARGE_POWER, ESS_MIN_DISCHARGE_POWER, ESS_MAX_DISCHARGE_POWER, ESS_MAX_APPARENT_POWER, ESS_REACTIVE_POWER, ESS_SOC, // - GRID_ACTIVE_POWER, GRID_ACTIVE_POWER_L1, GRID_ACTIVE_POWER_L2, GRID_ACTIVE_POWER_L3, + GRID_ACTIVE_POWER, GRID_ACTIVE_POWER_L1, GRID_ACTIVE_POWER_L2, GRID_ACTIVE_POWER_L3, GRID_BUY_PRICE, GRID_BUY_ACTIVE_ENERGY, GRID_MAX_ACTIVE_POWER, GRID_MIN_ACTIVE_POWER, GRID_MODE, GRID_SELL_ACTIVE_ENERGY, // diff --git a/io.openems.edge.core/src/io/openems/edge/core/sum/SumImpl.java b/io.openems.edge.core/src/io/openems/edge/core/sum/SumImpl.java index 4901c486e17..c7aca7017cc 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/sum/SumImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/sum/SumImpl.java @@ -21,6 +21,7 @@ import io.openems.common.channel.AccessMode; import io.openems.common.channel.Level; +import io.openems.edge.common.channel.calculate.CalculateAverage; import io.openems.edge.common.channel.calculate.CalculateIntegerSum; import io.openems.edge.common.channel.calculate.CalculateLongSum; import io.openems.edge.common.component.AbstractOpenemsComponent; @@ -42,6 +43,7 @@ import io.openems.edge.meter.api.ElectricityMeter; import io.openems.edge.meter.api.VirtualMeter; import io.openems.edge.timedata.api.Timedata; +import io.openems.edge.timeofusetariff.api.TimeOfUseTariff; @Designate(ocd = Config.class, factory = false) @Component(// @@ -170,6 +172,7 @@ private void calculateChannelValues() { final var gridActivePowerL1 = new CalculateIntegerSum(); final var gridActivePowerL2 = new CalculateIntegerSum(); final var gridActivePowerL3 = new CalculateIntegerSum(); + final var gridBuyPrice = new CalculateAverage(); final var gridBuyActiveEnergy = new CalculateLongSum(); final var gridSellActiveEnergy = new CalculateLongSum(); @@ -302,6 +305,12 @@ private void calculateChannelValues() { } managedConsumptionActivePower.addValue(evcs.getChargePowerChannel()); + + } else if (component instanceof TimeOfUseTariff tou) { + /* + * Time-of-Use-Tariff + */ + gridBuyPrice.addValue(tou.getPrices().getFirst()); } } @@ -348,6 +357,7 @@ private void calculateChannelValues() { this._setGridActivePowerL2(gridActivePowerL2Sum); var gridActivePowerL3Sum = gridActivePowerL3.calculate(); this._setGridActivePowerL3(gridActivePowerL3Sum); + this._setGridBuyPrice(gridBuyPrice.calculate()); var gridBuyActiveEnergySum = gridBuyActiveEnergy.calculate(); gridBuyActiveEnergySum = this.energyValuesHandler.setValue(Sum.ChannelId.GRID_BUY_ACTIVE_ENERGY, diff --git a/io.openems.edge.core/test/io/openems/edge/app/timeofusetariff/TestTibber.java b/io.openems.edge.core/test/io/openems/edge/app/timeofusetariff/TestTibber.java index 0a1bfcf3c8d..da9a0d9deec 100644 --- a/io.openems.edge.core/test/io/openems/edge/app/timeofusetariff/TestTibber.java +++ b/io.openems.edge.core/test/io/openems/edge/app/timeofusetariff/TestTibber.java @@ -129,6 +129,38 @@ public void testSetTokenValue() throws Exception { assertEquals(JsonNull.INSTANCE, value); } + @Test + public void testUnsetFilterValue() throws Exception { + this.installHome(); + final var properties = JsonUtils.buildJsonObject() // + .addProperty(Tibber.Property.ACCESS_TOKEN.name(), "g78aw9ht2n112nb453") // + .addProperty(Tibber.Property.MULTIPLE_HOMES_CHECK.name(), true) // + .addProperty(Tibber.Property.FILTER.name(), "randomInitialFilter") // + .build(); + final var response = this.appManagerTestBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, + new AddAppInstance.Request(this.tibber.getAppId(), "key", "alias", properties)); + + final var filterProp = Arrays.stream(this.tibber.getProperties()) // + .filter(t -> t.name.equals(Tibber.Property.FILTER.name())) // + .findAny().orElseThrow(); + var value = filterProp.bidirectionalValue.apply(response.instance().properties); + + assertEquals("randomInitialFilter", value.getAsString()); + + this.appManagerTestBundle.componentManger.handleUpdateComponentConfigRequest(DUMMY_ADMIN, + new UpdateComponentConfigRequest( + response.instance().properties.get(Tibber.Property.TIME_OF_USE_TARIFF_PROVIDER_ID.name()) + .getAsString(), + List.of(new UpdateComponentConfigRequest.Property(Tibber.Property.ACCESS_TOKEN.name(), + "g78aw9ht2n112nb453")))); + + value = filterProp.bidirectionalValue.apply(response.instance().properties); + + assertTrue(value.isJsonPrimitive()); + assertTrue(value.getAsJsonPrimitive().isString()); + assertEquals("", value.getAsString()); + } + private void createPredictor() throws Exception { this.appManagerTestBundle.componentManger.handleCreateComponentConfigRequest(DUMMY_ADMIN, new CreateComponentConfigRequest("Predictor.PersistenceModel", List.of(// diff --git a/io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/common/AbstractEdge2Edge.java b/io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/common/AbstractEdge2Edge.java index e3a922e5a58..9dae53bdbeb 100644 --- a/io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/common/AbstractEdge2Edge.java +++ b/io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/common/AbstractEdge2Edge.java @@ -1,5 +1,8 @@ package io.openems.edge.edge2edge.common; +import static io.openems.edge.bridge.modbus.api.ModbusUtils.readElementOnce; +import static java.util.concurrent.CompletableFuture.completedFuture; + import java.util.ArrayDeque; import java.util.Deque; import java.util.List; @@ -50,7 +53,7 @@ public abstract class AbstractEdge2Edge extends AbstractOpenemsModbusComponent protected AbstractEdge2Edge(List> modbusSlaveNatureTableMethods, io.openems.edge.common.channel.ChannelId[] firstInitialChannelIds, - io.openems.edge.common.channel.ChannelId[]... furtherInitialChannelIds) throws OpenemsException { + io.openems.edge.common.channel.ChannelId[]... furtherInitialChannelIds) { super(firstInitialChannelIds, furtherInitialChannelIds); this.modbusSlaveNatureTableMethods = modbusSlaveNatureTableMethods; this.modbusProtocol = new ModbusProtocol(this); @@ -76,37 +79,33 @@ protected boolean activate(ComponentContext context, String id, String alias, bo return; } - try { - ModbusUtils.readELementOnce(this.modbusProtocol, new UnsignedWordElement(1), true).thenAccept(value -> { - if (value == null) { - return; - } - this.findComponentBlock(remoteComponentId, 1 + value) // - .whenComplete((startAddress, e1) -> { - if (e1 != null) { - this._setMappingRemoteProtocolFault(true); - e1.printStackTrace(); - return; - } - - // Found Component Block -> read each nature block - this.readNatureBlocks(startAddress).whenComplete((ignore, e2) -> { - if (e2 != null) { + readElementOnce(this.modbusProtocol, ModbusUtils::retryOnNull, new UnsignedWordElement(1)) + .thenAccept(value -> { + if (value == null) { + return; + } + this.findComponentBlock(remoteComponentId, 1 + value) // + .whenComplete((startAddress, e1) -> { + if (e1 != null) { this._setMappingRemoteProtocolFault(true); - // TODO restart with timeout finding the component block on exception - e2.printStackTrace(); + e1.printStackTrace(); return; } - this._setMappingRemoteProtocolFault(false); - this.logInfo(this.log, "Finished reading remote Modbus/TCP protocol"); - }); - }); - }); + // Found Component Block -> read each nature block + this.readNatureBlocks(startAddress).whenComplete((ignore, e2) -> { + if (e2 != null) { + this._setMappingRemoteProtocolFault(true); + // TODO restart with timeout finding the component block on exception + e2.printStackTrace(); + return; + } - } catch (OpenemsException e) { - this._setMappingRemoteProtocolFault(true); - } + this._setMappingRemoteProtocolFault(false); + this.logInfo(this.log, "Finished reading remote Modbus/TCP protocol"); + }); + }); + }); }); return false; } @@ -123,14 +122,10 @@ protected void deactivate() { * Tests if first register is 0x6201 ("OpenEMS"). * * @return a future true if it is OpenEMS; otherwise false - * @throws OpenemsException on error */ - private CompletableFuture isOpenems() throws OpenemsException { - final var result = new CompletableFuture(); - ModbusUtils.readELementOnce(this.modbusProtocol, new UnsignedWordElement(0), true).thenAccept(value -> { - result.complete(isHashEqual(value, "OpenEMS")); - }); - return result; + private CompletableFuture isOpenems() { + return readElementOnce(this.modbusProtocol, ModbusUtils::retryOnNull, new UnsignedWordElement(0)) // + .thenCompose(value -> completedFuture(isHashEqual(value, "OpenEMS"))); } /** @@ -166,55 +161,41 @@ private CompletableFuture findComponentBlock(String componentId, int st } private void _findComponentBlock(CompletableFuture result, String componentId, int startAddress) { - try { - ModbusUtils.readELementOnce(this.modbusProtocol, new StringWordElement(startAddress, 16), false) - .thenAccept(remoteComponentId -> { - if (remoteComponentId == null) { - result.completeExceptionally( - new OpenemsException("Unable to find remote Component with ID " + componentId)); - } - if (remoteComponentId.equals(componentId)) { - this.logInfo(this.log, - "Found Remote-Component '" + componentId + "' on address " + startAddress); - result.complete(startAddress); - return; - } - try { - ModbusUtils.readELementOnce(this.modbusProtocol, new UnsignedWordElement(startAddress + 16), - false).thenAccept(lengthOfBlock -> { - this._findComponentBlock(result, componentId, startAddress + lengthOfBlock); - }); - } catch (OpenemsException e) { - result.completeExceptionally(e); - } - }); - } catch (OpenemsException e) { - result.completeExceptionally(e); - } + readElementOnce(this.modbusProtocol, ModbusUtils::retryOnNull, new StringWordElement(startAddress, 16)) // + .thenAccept(remoteComponentId -> { + if (remoteComponentId == null) { + result.completeExceptionally( + new OpenemsException("Unable to find remote Component with ID " + componentId)); + } + if (remoteComponentId.equals(componentId)) { + this.logInfo(this.log, + "Found Remote-Component '" + componentId + "' on address " + startAddress); + result.complete(startAddress); + return; + } + readElementOnce(this.modbusProtocol, ModbusUtils::retryOnNull, + new UnsignedWordElement(startAddress + 16)) // + .thenAccept(lengthOfBlock -> { + this._findComponentBlock(result, componentId, startAddress + lengthOfBlock); + }); + }); } private CompletableFuture readNatureBlocks(int startAddress) { - final var result = new CompletableFuture(); - try { - ModbusUtils.readELementOnce(this.modbusProtocol, new UnsignedWordElement(startAddress + 16), false) - .thenAccept(lengthOfComponentBlock -> { - var lastAddress = startAddress + lengthOfComponentBlock + 20; - // TODO fix length of last component blocks in Slave Modbus/TCP-Api - this.readNatureStartAddresses(startAddress + 20, lastAddress) - .thenAccept(natureStartAddresses -> { - try { - this.mapRemoteChannels(natureStartAddresses); - result.complete(null); - - } catch (OpenemsException e) { - result.completeExceptionally(e); - } - }); - }); - } catch (OpenemsException e) { - result.completeExceptionally(e); - } - return result; + return readElementOnce(this.modbusProtocol, ModbusUtils::doNotRetry, new UnsignedWordElement(startAddress + 16)) + .thenCompose(lengthOfComponentBlock -> + // TODO fix length of last component blocks in Slave Modbus/TCP-Api + this.readNatureStartAddresses(startAddress + 20, + startAddress + lengthOfComponentBlock + 20 /* last address */) + .thenCompose(natureStartAddresses -> { + try { + this.mapRemoteChannels(natureStartAddresses); + return completedFuture(null); + + } catch (OpenemsException e) { + return CompletableFuture.failedFuture(e); + } + })); } /** @@ -438,40 +419,31 @@ private CompletableFuture> readNatureStartAddresses(int private void _readNatureStartAddresses(CompletableFuture> result, int startAddress, int lastAddress, final TreeMap natureStartAddresses) { - try { - ModbusUtils.readELementOnce(this.modbusProtocol, new UnsignedWordElement(startAddress), false) - .thenAccept(rawHash -> { - if (rawHash == null) { - result.completeExceptionally( - new OpenemsException("Unable to read hash at " + startAddress)); - return; - } - var hash = (short) (int) rawHash; - - try { - ModbusUtils.readELementOnce(this.modbusProtocol, new UnsignedWordElement(startAddress + 1), - false).thenAccept(lengthOfNatureBlock -> { - this.logInfo(this.log, "Found Remote-Nature '0x" - + Integer.toHexString(hash & 0xffff) + "' on address " + startAddress); - // TODO get Remote-Nature name from this.modbusSlaveNatureTableMethods - natureStartAddresses.put(startAddress, hash); - - var nextStartAddress = startAddress + lengthOfNatureBlock; - if (nextStartAddress >= lastAddress) { - result.complete(natureStartAddresses); - - } else { - // recursive call of _readNatureStartAddresses - this._readNatureStartAddresses(result, nextStartAddress, lastAddress, - natureStartAddresses); - } - }); - } catch (OpenemsException e) { - result.completeExceptionally(e); - } - }); - } catch (OpenemsException e) { - result.completeExceptionally(e); - } + readElementOnce(this.modbusProtocol, ModbusUtils::retryOnNull, new UnsignedWordElement(startAddress)) + .thenAccept(rawHash -> { + if (rawHash == null) { + result.completeExceptionally(new OpenemsException("Unable to read hash at " + startAddress)); + return; + } + var hash = (short) (int) rawHash; + + readElementOnce(this.modbusProtocol, ModbusUtils::doNotRetry, + new UnsignedWordElement(startAddress + 1)).thenAccept(lengthOfNatureBlock -> { + this.logInfo(this.log, "Found Remote-Nature '0x" + Integer.toHexString(hash & 0xffff) + + "' on address " + startAddress); + // TODO get Remote-Nature name from this.modbusSlaveNatureTableMethods + natureStartAddresses.put(startAddress, hash); + + var nextStartAddress = startAddress + lengthOfNatureBlock; + if (nextStartAddress >= lastAddress) { + result.complete(natureStartAddresses); + + } else { + // recursive call of _readNatureStartAddresses + this._readNatureStartAddresses(result, nextStartAddress, lastAddress, + natureStartAddresses); + } + }); + }); } } diff --git a/io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/ess/Edge2EdgeEssImpl.java b/io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/ess/Edge2EdgeEssImpl.java index 5c816d12c97..3273b2127fd 100644 --- a/io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/ess/Edge2EdgeEssImpl.java +++ b/io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/ess/Edge2EdgeEssImpl.java @@ -54,7 +54,7 @@ protected void setModbus(BridgeModbus modbus) { super.setModbus(modbus); } - public Edge2EdgeEssImpl() throws OpenemsException { + public Edge2EdgeEssImpl() { super(// Lists.newArrayList(// OpenemsComponent::getModbusSlaveNatureTable, // diff --git a/io.openems.edge.energy.api/.classpath b/io.openems.edge.energy.api/.classpath new file mode 100644 index 00000000000..bbfbdbe40e7 --- /dev/null +++ b/io.openems.edge.energy.api/.classpath @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/io.openems.edge.energy.api/.gitignore b/io.openems.edge.energy.api/.gitignore new file mode 100644 index 00000000000..90dde36e4ac --- /dev/null +++ b/io.openems.edge.energy.api/.gitignore @@ -0,0 +1,3 @@ +/bin/ +/bin_test/ +/generated/ diff --git a/io.openems.edge.energy.api/.project b/io.openems.edge.energy.api/.project new file mode 100644 index 00000000000..edc8917776f --- /dev/null +++ b/io.openems.edge.energy.api/.project @@ -0,0 +1,23 @@ + + + io.openems.edge.energy.api + + + + + + org.eclipse.jdt.core.javabuilder + + + + + bndtools.core.bndbuilder + + + + + + org.eclipse.jdt.core.javanature + bndtools.core.bndnature + + diff --git a/io.openems.edge.energy.api/.settings/org.eclipse.core.resources.prefs b/io.openems.edge.energy.api/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 00000000000..99f26c0203a --- /dev/null +++ b/io.openems.edge.energy.api/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/io.openems.edge.energy.api/bnd.bnd b/io.openems.edge.energy.api/bnd.bnd new file mode 100644 index 00000000000..49a30e8f94b --- /dev/null +++ b/io.openems.edge.energy.api/bnd.bnd @@ -0,0 +1,15 @@ +Bundle-Name: OpenEMS Edge Energy Api +Bundle-Vendor: FENECON GmbH +Bundle-License: https://opensource.org/licenses/EPL-2.0 +Bundle-Version: 1.0.0.${tstamp} + +-buildpath: \ + ${buildpath},\ + io.openems.common,\ + io.openems.edge.common,\ + io.openems.edge.controller.api,\ + io.openems.edge.predictor.api,\ + io.openems.edge.timeofusetariff.api,\ + +-testpath: \ + ${testpath},\ diff --git a/io.openems.edge.energy.api/readme.adoc b/io.openems.edge.energy.api/readme.adoc new file mode 100644 index 00000000000..48c7bd7b577 --- /dev/null +++ b/io.openems.edge.energy.api/readme.adoc @@ -0,0 +1,5 @@ += OpenEMS Energy API + +The API for OpenEMS Energy Schedules. + +https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.energy.api[Source Code icon:github[]] \ No newline at end of file diff --git a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergySchedulable.java b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergySchedulable.java new file mode 100644 index 00000000000..cf2f7e66e0d --- /dev/null +++ b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergySchedulable.java @@ -0,0 +1,13 @@ +package io.openems.edge.energy.api; + +import io.openems.edge.controller.api.Controller; + +public interface EnergySchedulable extends Controller { + + /** + * Get the {@link EnergyScheduleHandler}. + * + * @return {@link EnergyScheduleHandler} + */ + public EnergyScheduleHandler getEnergyScheduleHandler(); +} diff --git a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergyScheduleHandler.java b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergyScheduleHandler.java new file mode 100644 index 00000000000..ca5ca2ebc45 --- /dev/null +++ b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergyScheduleHandler.java @@ -0,0 +1,76 @@ +package io.openems.edge.energy.api; + +import static io.openems.common.utils.DateUtils.roundDownToQuarter; + +import java.time.ZonedDateTime; +import java.util.Optional; +import java.util.function.Supplier; + +import com.google.common.collect.ImmutableMap; + +public class EnergyScheduleHandler { + + private final Supplier availableStates; + private final Supplier context; + + private ImmutableMap> schedule = ImmutableMap.of(); + + public EnergyScheduleHandler(Supplier availableStates, Supplier context) { + this.availableStates = availableStates; + this.context = context; + } + + /** + * Gets the available States. + * + * @return an Array of States + */ + public STATE[] getAvailableStates() { + return this.availableStates.get(); + } + + /** + * Gets the Context. + * + * @return the Context + */ + public CONTEXT getContext() { + return this.context.get(); + } + + public static record Period(STATE state, Integer essChargeInChargeGrid) { + } + + /** + * Sets the Schedule. Called by Optimizer. + * + * @param schedule the Schedule + */ + public synchronized void setSchedule(ImmutableMap> schedule) { + this.schedule = schedule; + } + + /** + * Gets the current State or null. + * + * @return the State or null + */ + public synchronized STATE getCurrentState() { + return Optional.ofNullable(this.schedule.get(roundDownToQuarter(ZonedDateTime.now()))) // + .map(Period::state) // + .orElse(null); + } + + // TODO hacky... find a better way! + /** + * Gets the current essChargeInChargeGrid or null. + * + * @return the essChargeInChargeGrid or null + */ + public synchronized Integer getCurrentEssChargeInChargeGrid() { + return Optional.ofNullable(this.schedule.get(roundDownToQuarter(ZonedDateTime.now()))) // + .map(Period::essChargeInChargeGrid) // + .orElse(null); + } + +} diff --git a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergyScheduler.java b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergyScheduler.java new file mode 100644 index 00000000000..7d58264b26b --- /dev/null +++ b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergyScheduler.java @@ -0,0 +1,29 @@ +package io.openems.edge.energy.api; + +import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.jsonapi.ComponentJsonApi; + +/** + * The global Energy Schedule optimizer singleton. + */ +public interface EnergyScheduler extends OpenemsComponent, ComponentJsonApi { + + public static final String SINGLETON_SERVICE_PID = "Core.Energy"; + public static final String SINGLETON_COMPONENT_ID = "_energy"; + + public enum ChannelId implements io.openems.edge.common.channel.ChannelId { + ; + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } +} diff --git a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/package-info.java b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/package-info.java new file mode 100644 index 00000000000..a842873a538 --- /dev/null +++ b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/package-info.java @@ -0,0 +1,3 @@ +@org.osgi.annotation.versioning.Version("1.0.0") +@org.osgi.annotation.bundle.Export +package io.openems.edge.energy.api; diff --git a/io.openems.edge.energy.api/test/.gitignore b/io.openems.edge.energy.api/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.energy/.classpath b/io.openems.edge.energy/.classpath new file mode 100644 index 00000000000..bbfbdbe40e7 --- /dev/null +++ b/io.openems.edge.energy/.classpath @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/io.openems.edge.energy/.gitignore b/io.openems.edge.energy/.gitignore new file mode 100644 index 00000000000..90dde36e4ac --- /dev/null +++ b/io.openems.edge.energy/.gitignore @@ -0,0 +1,3 @@ +/bin/ +/bin_test/ +/generated/ diff --git a/io.openems.edge.energy/.project b/io.openems.edge.energy/.project new file mode 100644 index 00000000000..6126f1ae321 --- /dev/null +++ b/io.openems.edge.energy/.project @@ -0,0 +1,23 @@ + + + io.openems.edge.energy + + + + + + org.eclipse.jdt.core.javabuilder + + + + + bndtools.core.bndbuilder + + + + + + org.eclipse.jdt.core.javanature + bndtools.core.bndnature + + diff --git a/io.openems.edge.energy/.settings/org.eclipse.core.resources.prefs b/io.openems.edge.energy/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 00000000000..99f26c0203a --- /dev/null +++ b/io.openems.edge.energy/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/io.openems.edge.energy/bnd.bnd b/io.openems.edge.energy/bnd.bnd new file mode 100644 index 00000000000..7df50f07c5e --- /dev/null +++ b/io.openems.edge.energy/bnd.bnd @@ -0,0 +1,22 @@ +Bundle-Name: OpenEMS Edge Energy +Bundle-Vendor: FENECON GmbH +Bundle-License: https://opensource.org/licenses/EPL-2.0 +Bundle-Version: 1.0.0.${tstamp} + +-buildpath: \ + ${buildpath},\ + io.openems.common,\ + io.openems.edge.common,\ + io.openems.edge.controller.api,\ + io.openems.edge.controller.ess.emergencycapacityreserve,\ + io.openems.edge.controller.ess.limittotaldischarge,\ + io.openems.edge.controller.ess.timeofusetariff,\ + io.openems.edge.energy.api,\ + io.openems.edge.ess.api,\ + io.openems.edge.predictor.api,\ + io.openems.edge.timedata.api,\ + io.openems.edge.timeofusetariff.api,\ + io.openems.wrapper.jenetics,\ + +-testpath: \ + ${testpath} \ No newline at end of file diff --git a/io.openems.edge.energy/readme.adoc b/io.openems.edge.energy/readme.adoc new file mode 100644 index 00000000000..e0c1789dd4d --- /dev/null +++ b/io.openems.edge.energy/readme.adoc @@ -0,0 +1,5 @@ += OpenEMS Energy + +Implementations and Services for OpenEMS Energy Schedules. + +https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.energy[Source Code icon:github[]] \ No newline at end of file diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/Config.java b/io.openems.edge.energy/src/io/openems/edge/energy/Config.java new file mode 100644 index 00000000000..5b1344d5a72 --- /dev/null +++ b/io.openems.edge.energy/src/io/openems/edge/energy/Config.java @@ -0,0 +1,15 @@ +package io.openems.edge.energy; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +@ObjectClassDefinition(// + name = "Core Energy Scheduler", // + description = "The global Energy Scheduler.") +@interface Config { + + @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?") + boolean enabled() default true; + + String webconsole_configurationFactory_nameHint() default "Core Energy Scheduler"; +} \ No newline at end of file diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/EnergySchedulerImpl.java b/io.openems.edge.energy/src/io/openems/edge/energy/EnergySchedulerImpl.java new file mode 100644 index 00000000000..1f0e892b447 --- /dev/null +++ b/io.openems.edge.energy/src/io/openems/edge/energy/EnergySchedulerImpl.java @@ -0,0 +1,149 @@ +package io.openems.edge.energy; + +import static io.openems.edge.energy.optimizer.Utils.handleGetScheduleRequest; + +import java.time.ZonedDateTime; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Modified; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.metatype.annotations.Designate; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.exceptions.OpenemsException; +import io.openems.edge.common.component.AbstractOpenemsComponent; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.jsonapi.ComponentJsonApi; +import io.openems.edge.common.jsonapi.JsonApiBuilder; +import io.openems.edge.common.sum.Sum; +import io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImpl; +import io.openems.edge.energy.api.EnergySchedulable; +import io.openems.edge.energy.api.EnergyScheduler; +import io.openems.edge.energy.jsonrpc.GetScheduleRequest; +import io.openems.edge.energy.optimizer.GlobalContext; +import io.openems.edge.energy.optimizer.Optimizer; +import io.openems.edge.predictor.api.manager.PredictorManager; +import io.openems.edge.timedata.api.Timedata; +import io.openems.edge.timeofusetariff.api.TimeOfUseTariff; + +@Designate(ocd = Config.class, factory = false) +@Component(// + name = EnergyScheduler.SINGLETON_SERVICE_PID, // + immediate = true, // + configurationPolicy = ConfigurationPolicy.OPTIONAL // +) +public class EnergySchedulerImpl extends AbstractOpenemsComponent + implements OpenemsComponent, EnergyScheduler, ComponentJsonApi { + + /** The hard working Optimizer. */ + private final Optimizer optimizer; + + @Reference + private ConfigurationAdmin cm; + + @Reference + private ComponentManager componentManager; + + @Reference + private PredictorManager predictorManager; + + @Reference(policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) + private volatile TimeOfUseTariff timeOfUseTariff; + + @Reference + private Sum sum; + + @Reference(policyOption = ReferencePolicyOption.GREEDY, // + cardinality = ReferenceCardinality.MULTIPLE, // + policy = ReferencePolicy.DYNAMIC, // + target = "(enabled=true)") + private volatile List> schedulables = new CopyOnWriteArrayList<>(); + + @Reference(policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) + private volatile Timedata timedata; + + public EnergySchedulerImpl() { + super(// + OpenemsComponent.ChannelId.values(), // + EnergyScheduler.ChannelId.values() // + ); + // Prepare Optimizer and Context + this.optimizer = new Optimizer(() -> { + if (this.timeOfUseTariff == null) { + throw new OpenemsException("TimeOfUseTariff is not available"); + } + var ctrl = this.schedulables.stream() // + .filter(TimeOfUseTariffControllerImpl.class::isInstance) // + .map(TimeOfUseTariffControllerImpl.class::cast) // + .findFirst().orElse(null); + if (ctrl == null) { + throw new OpenemsException("TimeOfUseTariffController is not available"); + } + var esh = ctrl.getEnergyScheduleHandler(); + // NOTE: This is a workaround while we refactor TimeOfUseTariffController + // This code assumes that the `EnergySchedulable` is a + // `TimeOfUseTariffController` + return GlobalContext.create() // + .setClock(this.componentManager.getClock()) // + .setEnergyScheduleHandler(esh) // + .setSum(this.sum) // + .setPredictorManager(this.predictorManager) // + .setTimeOfUseTariff(this.timeOfUseTariff) // + .build(); + }); + } + + @Activate + private void activate(ComponentContext context, Config config) throws OpenemsException { + super.activate(context, SINGLETON_COMPONENT_ID, SINGLETON_SERVICE_PID, true); + if (this.applyConfig(config)) { + this.optimizer.activate(this.id()); + } + } + + @Modified + private void modified(ComponentContext context, Config config) throws OpenemsNamedException { + super.modified(context, SINGLETON_COMPONENT_ID, SINGLETON_SERVICE_PID, true); + if (this.applyConfig(config)) { + this.optimizer.modified(this.id()); + } + } + + private synchronized boolean applyConfig(Config config) { + if (OpenemsComponent.validateSingleton(this.cm, SINGLETON_SERVICE_PID, SINGLETON_COMPONENT_ID)) { + return false; + } + + if (!config.enabled()) { + this.optimizer.deactivate(); + return false; + } + + return true; + } + + @Override + @Deactivate + protected void deactivate() { + this.optimizer.deactivate(); + super.deactivate(); + } + + @Override + public void buildJsonApiRoutes(JsonApiBuilder builder) { + builder.handleRequest(GetScheduleRequest.METHOD, call -> handleGetScheduleRequest(// + this.optimizer, call.getRequest().getId(), this.timedata, this.timeOfUseTariff, + "ctrlEssTimeOfUseTariff0", ZonedDateTime.now(this.componentManager.getClock()))); + } +} diff --git a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/GetScheduleRequest.java b/io.openems.edge.energy/src/io/openems/edge/energy/jsonrpc/GetScheduleRequest.java similarity index 94% rename from io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/GetScheduleRequest.java rename to io.openems.edge.energy/src/io/openems/edge/energy/jsonrpc/GetScheduleRequest.java index ff357bfd827..1dbdb0dc7d8 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/GetScheduleRequest.java +++ b/io.openems.edge.energy/src/io/openems/edge/energy/jsonrpc/GetScheduleRequest.java @@ -1,4 +1,4 @@ -package io.openems.edge.controller.ess.timeofusetariff.jsonrpc; +package io.openems.edge.energy.jsonrpc; import com.google.gson.JsonObject; diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/jsonrpc/GetScheduleResponse.java b/io.openems.edge.energy/src/io/openems/edge/energy/jsonrpc/GetScheduleResponse.java new file mode 100644 index 00000000000..e27461abc45 --- /dev/null +++ b/io.openems.edge.energy/src/io/openems/edge/energy/jsonrpc/GetScheduleResponse.java @@ -0,0 +1,73 @@ +package io.openems.edge.energy.jsonrpc; + +import java.time.ZonedDateTime; +import java.util.Map.Entry; +import java.util.TreeMap; +import java.util.UUID; + +import com.google.gson.JsonObject; + +import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.energy.optimizer.ScheduleDatas; +import io.openems.edge.energy.optimizer.ScheduleDatas.ScheduleData; + +/** + * Represents a JSON-RPC Response for 'getMeters'. + * + *
+ * {
+ *   "jsonrpc": "2.0",
+ *   "id": "UUID",
+ *   "result": {
+ *     'schedule': [{
+ *      'timestamp':...,
+ *      'price':...,
+ *      'state':...,
+ *      'grid':...,
+ *      'production':...,
+ *      'consumption':...,
+ *      'ess':...,
+ *      'soc':...,
+ *     }]
+ *   }
+ * }
+ * 
+ */ +public class GetScheduleResponse extends JsonrpcResponseSuccess { + + private final ZonedDateTime fromDate; + private final ZonedDateTime toDate; + private final ScheduleDatas scheduleDatas; + + public GetScheduleResponse(ZonedDateTime fromDate, ZonedDateTime toDate, ScheduleDatas scheduleDatas) { + this(UUID.randomUUID(), fromDate, toDate, scheduleDatas); + } + + public GetScheduleResponse(UUID id, ZonedDateTime fromDate, ZonedDateTime toDate, ScheduleDatas scheduleDatas) { + super(id); + this.fromDate = fromDate; + this.toDate = toDate; + this.scheduleDatas = scheduleDatas; + } + + @Override + public JsonObject getResult() { + var s = new TreeMap(); + var t = this.fromDate; + // Prefill with empty objects + while (!t.isAfter(this.toDate)) { + s.put(t, ScheduleData.emptyJsonObject(t)); + t = t.plusMinutes(15); + } + // Replace with actual data + s.putAll(this.scheduleDatas.toJsonObjects()); + + return JsonUtils.buildJsonObject() // + .add("schedule", s.entrySet().stream() // + .map(Entry::getValue) // + .collect(JsonUtils.toJsonArray())) // + .build(); + } + +} diff --git a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/optimizer/EnergyFlow.java b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/EnergyFlow.java similarity index 96% rename from io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/optimizer/EnergyFlow.java rename to io.openems.edge.energy/src/io/openems/edge/energy/optimizer/EnergyFlow.java index 0f43d3cca58..bf108379c74 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/optimizer/EnergyFlow.java +++ b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/EnergyFlow.java @@ -1,11 +1,11 @@ -package io.openems.edge.controller.ess.timeofusetariff.optimizer; +package io.openems.edge.energy.optimizer; import static io.openems.edge.common.type.TypeUtils.fitWithin; import static java.lang.Math.max; import static java.lang.Math.min; import io.openems.edge.controller.ess.timeofusetariff.StateMachine; -import io.openems.edge.controller.ess.timeofusetariff.optimizer.Params.OptimizePeriod; +import io.openems.edge.energy.optimizer.Params.OptimizePeriod; /** * Simulates a detailed Energy-Flow. diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/GlobalContext.java b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/GlobalContext.java new file mode 100644 index 00000000000..c7b889a6eff --- /dev/null +++ b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/GlobalContext.java @@ -0,0 +1,103 @@ +package io.openems.edge.energy.optimizer; + +import java.time.Clock; + +import io.openems.edge.common.sum.Sum; +import io.openems.edge.controller.ess.timeofusetariff.StateMachine; +import io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffController; +import io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImpl; +import io.openems.edge.energy.api.EnergyScheduleHandler; +import io.openems.edge.predictor.api.manager.PredictorManager; +import io.openems.edge.timeofusetariff.api.TimeOfUseTariff; + +public record GlobalContext(// + Clock clock, // + EnergyScheduleHandler energyScheduleHandler, // + Sum sum, // + PredictorManager predictorManager, // + TimeOfUseTariff timeOfUseTariff) { + + public static class Builder { + private Clock clock; + private EnergyScheduleHandler energyScheduleHandler; + private Sum sum; + private PredictorManager predictorManager; + private TimeOfUseTariff timeOfUseTariff; + + /** + * The {@link Clock}. + * + * @param clock the {@link Clock} + * @return myself + */ + public Builder setClock(Clock clock) { + this.clock = clock; + return this; + } + + /** + * The {@link EnergyScheduleHandler} of the {@link TimeOfUseTariffController}. + * + * @param energyScheduleHandler the {@link EnergyScheduleHandler} + * @return myself + */ + public Builder setEnergyScheduleHandler( + EnergyScheduleHandler energyScheduleHandler) { + this.energyScheduleHandler = energyScheduleHandler; + return this; + } + + /** + * The {@link Sum}. + * + * @param sum the {@link Sum} + * @return myself + */ + public Builder setSum(Sum sum) { + this.sum = sum; + return this; + } + + /** + * The {@link PredictorManager}. + * + * @param predictorManager the {@link PredictorManager} + * @return myself + */ + public Builder setPredictorManager(PredictorManager predictorManager) { + this.predictorManager = predictorManager; + return this; + } + + /** + * The {@link TimeOfUseTariff}. + * + * @param timeOfUseTariff the {@link TimeOfUseTariff} + * @return myself + */ + public Builder setTimeOfUseTariff(TimeOfUseTariff timeOfUseTariff) { + this.timeOfUseTariff = timeOfUseTariff; + return this; + } + + /** + * Builds the {@link GlobalContext}. + * + * @return the {@link GlobalContext} record + */ + public GlobalContext build() { + return new GlobalContext(this.clock, this.energyScheduleHandler, this.sum, this.predictorManager, + this.timeOfUseTariff); + } + } + + /** + * Create a {@link GlobalContext} {@link Builder}. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new GlobalContext.Builder(); + } + +} diff --git a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/optimizer/InitialPopulationUtils.java b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/InitialPopulationUtils.java similarity index 92% rename from io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/optimizer/InitialPopulationUtils.java rename to io.openems.edge.energy/src/io/openems/edge/energy/optimizer/InitialPopulationUtils.java index 40a7dbc0901..b09e3e3036c 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/optimizer/InitialPopulationUtils.java +++ b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/InitialPopulationUtils.java @@ -1,10 +1,10 @@ -package io.openems.edge.controller.ess.timeofusetariff.optimizer; +package io.openems.edge.energy.optimizer; import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.BALANCING; import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.CHARGE_GRID; import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.DELAY_DISCHARGE; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.findFirstPeakIndex; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.findFirstValleyIndex; +import static io.openems.edge.energy.optimizer.Utils.findFirstPeakIndex; +import static io.openems.edge.energy.optimizer.Utils.findFirstValleyIndex; import java.util.Arrays; import java.util.List; @@ -19,7 +19,7 @@ import io.jenetics.IntegerChromosome; import io.jenetics.IntegerGene; import io.openems.edge.controller.ess.timeofusetariff.StateMachine; -import io.openems.edge.controller.ess.timeofusetariff.optimizer.Params.OptimizePeriod; +import io.openems.edge.energy.optimizer.Params.OptimizePeriod; public class InitialPopulationUtils { diff --git a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/optimizer/Optimizer.java b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Optimizer.java similarity index 58% rename from io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/optimizer/Optimizer.java rename to io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Optimizer.java index 693f11a82a6..030b0c3e4dc 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/optimizer/Optimizer.java +++ b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Optimizer.java @@ -1,13 +1,13 @@ -package io.openems.edge.controller.ess.timeofusetariff.optimizer; +package io.openems.edge.energy.optimizer; +import static com.google.common.collect.ImmutableMap.toImmutableMap; import static com.google.common.collect.ImmutableSortedMap.toImmutableSortedMap; -import static io.openems.common.utils.DateUtils.roundDownToQuarter; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Simulator.simulate; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.calculateExecutionLimitSeconds; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.createSimulatorParams; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.initializeRandomRegistryForProduction; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.logSchedule; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.updateSchedule; +import static io.openems.edge.energy.optimizer.Simulator.simulate; +import static io.openems.edge.energy.optimizer.Utils.calculateExecutionLimitSeconds; +import static io.openems.edge.energy.optimizer.Utils.createSimulatorParams; +import static io.openems.edge.energy.optimizer.Utils.initializeRandomRegistryForProduction; +import static io.openems.edge.energy.optimizer.Utils.logSchedule; +import static io.openems.edge.energy.optimizer.Utils.updateSchedule; import static java.lang.Thread.sleep; import java.time.Duration; @@ -15,18 +15,18 @@ import java.time.ZonedDateTime; import java.util.Map.Entry; import java.util.TreeMap; -import java.util.function.Supplier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.ImmutableSortedMap; -import io.openems.common.exceptions.InvalidValueException; +import io.openems.common.exceptions.OpenemsException; +import io.openems.common.function.ThrowingSupplier; import io.openems.common.test.TimeLeapClock; import io.openems.common.worker.AbstractImmediateWorker; -import io.openems.edge.controller.ess.timeofusetariff.StateMachine; -import io.openems.edge.controller.ess.timeofusetariff.optimizer.Simulator.Period; +import io.openems.edge.energy.api.EnergyScheduleHandler; +import io.openems.edge.energy.optimizer.Simulator.Period; /** * This task is executed once in the beginning and afterwards every full 15 @@ -36,13 +36,13 @@ public class Optimizer extends AbstractImmediateWorker { private final Logger log = LoggerFactory.getLogger(Optimizer.class); - private final Supplier context; + private final ThrowingSupplier globalContext; private final TreeMap schedule = new TreeMap<>(); private Params params = null; - public Optimizer(Supplier context) { - this.context = context; + public Optimizer(ThrowingSupplier globalContext) { + this.globalContext = globalContext; initializeRandomRegistryForProduction(); // Run Optimizer thread in LOW PRIORITY @@ -50,18 +50,18 @@ public Optimizer(Supplier context) { } @Override - public void forever() throws InterruptedException { + public void forever() throws InterruptedException, OpenemsException { this.log.info("# Start next run of Optimizer"); this.createParams(); // this possibly takes forever - final var context = this.context.get(); - final var start = Instant.now(context.clock()); + final var globalContext = this.globalContext.get(); + final var start = Instant.now(globalContext.clock()); long executionLimitSeconds; // Calculate max execution time till next quarter (with buffer) - executionLimitSeconds = calculateExecutionLimitSeconds(context.clock()); + executionLimitSeconds = calculateExecutionLimitSeconds(globalContext.clock()); // Find best Schedule var schedule = Simulator.getBestSchedule(this.params, executionLimitSeconds); @@ -74,13 +74,20 @@ public void forever() throws InterruptedException { // Update Schedule from newly simulated Schedule synchronized (this.schedule) { - updateSchedule(ZonedDateTime.now(context.clock()), this.schedule, newSchedule); + updateSchedule(ZonedDateTime.now(globalContext.clock()), this.schedule, newSchedule); } + // Send Schedule to Controller + globalContext.energyScheduleHandler().setSchedule(this.schedule.entrySet().stream()// + .collect(toImmutableMap(// + Entry::getKey, // + e -> new EnergyScheduleHandler.Period<>(e.getValue().state(), + e.getValue().op().essChargeInChargeGrid())))); + // Sleep remaining time - if (!(context.clock() instanceof TimeLeapClock)) { + if (!(globalContext.clock() instanceof TimeLeapClock)) { var remainingExecutionLimit = Duration - .between(Instant.now(context.clock()), start.plusSeconds(executionLimitSeconds)).getSeconds(); + .between(Instant.now(globalContext.clock()), start.plusSeconds(executionLimitSeconds)).getSeconds(); if (remainingExecutionLimit > 0) { this.log.info("Sleep [" + remainingExecutionLimit + "s] till next run of Optimizer"); sleep(remainingExecutionLimit * 1000); @@ -97,7 +104,7 @@ private void createParams() throws InterruptedException { while (true) { try { synchronized (this.schedule) { - this.params = createSimulatorParams(this.context.get(), // + this.params = createSimulatorParams(this.globalContext.get(), // this.schedule.entrySet().stream() // .collect(toImmutableSortedMap(// ZonedDateTime::compareTo, // @@ -105,7 +112,7 @@ private void createParams() throws InterruptedException { return; } - } catch (InvalidValueException e) { + } catch (OpenemsException e) { this.log.info("# Stuck trying to get Params. " + e.getMessage()); this.params = null; synchronized (this.schedule) { @@ -125,21 +132,6 @@ public Params getParams() { return this.params; } - /** - * Gets the current {@link StateMachine} or null. - * - * @return {@link StateMachine} or null - */ - public StateMachine getCurrentStateMachine() { - synchronized (this.schedule) { - var period = this.schedule.get(roundDownToQuarter(ZonedDateTime.now())); - if (period != null) { - return period.state(); - } - } - return null; - } - /** * Gets a copy of the Schedule. * diff --git a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/optimizer/Params.java b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Params.java similarity index 96% rename from io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/optimizer/Params.java rename to io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Params.java index 1513c1e44a7..b13de0b8546 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/optimizer/Params.java +++ b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Params.java @@ -1,8 +1,8 @@ -package io.openems.edge.controller.ess.timeofusetariff.optimizer; +package io.openems.edge.energy.optimizer; import static com.google.common.collect.ImmutableList.toImmutableList; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.ParamsUtils.calculateChargeEnergyInChargeGrid; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.ParamsUtils.calculatePeriodLengthHourFromIndex; +import static io.openems.edge.energy.optimizer.ParamsUtils.calculateChargeEnergyInChargeGrid; +import static io.openems.edge.energy.optimizer.ParamsUtils.calculatePeriodLengthHourFromIndex; import static java.lang.Math.min; import java.time.ZonedDateTime; diff --git a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/optimizer/ParamsUtils.java b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/ParamsUtils.java similarity index 88% rename from io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/optimizer/ParamsUtils.java rename to io.openems.edge.energy/src/io/openems/edge/energy/optimizer/ParamsUtils.java index b99381c6794..f350cf2ab44 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/optimizer/ParamsUtils.java +++ b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/ParamsUtils.java @@ -1,10 +1,10 @@ -package io.openems.edge.controller.ess.timeofusetariff.optimizer; +package io.openems.edge.energy.optimizer; import static com.google.common.math.Quantiles.percentiles; import static io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffController.PERIODS_PER_HOUR; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.ESS_CHARGE_C_RATE; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.findFirstPeakIndex; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.findFirstValleyIndex; +import static io.openems.edge.energy.optimizer.Utils.ESS_CHARGE_C_RATE; +import static io.openems.edge.energy.optimizer.Utils.findFirstPeakIndex; +import static io.openems.edge.energy.optimizer.Utils.findFirstValleyIndex; import static java.lang.Math.max; import static java.lang.Math.min; import static java.lang.Math.round; @@ -16,7 +16,7 @@ import com.google.common.primitives.ImmutableIntArray; import io.openems.edge.controller.ess.timeofusetariff.StateMachine; -import io.openems.edge.controller.ess.timeofusetariff.optimizer.Simulator.Period; +import io.openems.edge.energy.optimizer.Simulator.Period; public class ParamsUtils { diff --git a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/ScheduleDatas.java b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/ScheduleDatas.java similarity index 78% rename from io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/ScheduleDatas.java rename to io.openems.edge.energy/src/io/openems/edge/energy/optimizer/ScheduleDatas.java index d2251fa011b..053dac39d13 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/ScheduleDatas.java +++ b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/ScheduleDatas.java @@ -1,16 +1,19 @@ -package io.openems.edge.controller.ess.timeofusetariff.jsonrpc; +package io.openems.edge.energy.optimizer; import static com.google.common.collect.ImmutableList.toImmutableList; +import static com.google.common.collect.ImmutableSortedMap.toImmutableSortedMap; import static io.openems.common.types.OptionsEnum.getOption; +import static io.openems.common.utils.JsonUtils.buildJsonObject; import static io.openems.common.utils.JsonUtils.getAsDouble; import static io.openems.common.utils.JsonUtils.getAsInt; import static io.openems.common.utils.JsonUtils.toJson; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.SUM_CONSUMPTION; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.SUM_ESS_DISCHARGE_POWER; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.SUM_ESS_SOC; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.SUM_GRID; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.SUM_PRODUCTION; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.toEnergy; +import static io.openems.edge.energy.optimizer.Utils.SUM_CONSUMPTION; +import static io.openems.edge.energy.optimizer.Utils.SUM_ESS_DISCHARGE_POWER; +import static io.openems.edge.energy.optimizer.Utils.SUM_ESS_SOC; +import static io.openems.edge.energy.optimizer.Utils.SUM_GRID; +import static io.openems.edge.energy.optimizer.Utils.SUM_PRODUCTION; +import static io.openems.edge.energy.optimizer.Utils.toEnergy; +import static io.openems.edge.energy.optimizer.Utils.toPower; import static java.lang.Double.parseDouble; import static java.lang.Integer.parseInt; import static java.lang.Math.round; @@ -32,18 +35,16 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSortedMap; -import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonNull; +import com.google.gson.JsonObject; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; import io.openems.common.types.ChannelAddress; -import io.openems.common.utils.JsonUtils; import io.openems.edge.controller.ess.timeofusetariff.StateMachine; -import io.openems.edge.controller.ess.timeofusetariff.optimizer.Optimizer; -import io.openems.edge.controller.ess.timeofusetariff.optimizer.Params.Length; -import io.openems.edge.controller.ess.timeofusetariff.optimizer.Simulator.Period; +import io.openems.edge.energy.optimizer.Params.Length; +import io.openems.edge.energy.optimizer.Simulator.Period; /** * Data for JSONRPC-Response. Values are in [W]. @@ -162,46 +163,16 @@ public String toLogString(String prefix) { } /** - * Builds a {@link JsonArray} of this {@link ScheduleDatas}. + * Builds a Map of {@link JsonObject}s of this {@link ScheduleDatas}. * - * @param fromDate the From-Date - * @return {@link JsonArray} + * @return a Map */ - public JsonArray toJsonArray(ZonedDateTime fromDate) { - var result = JsonUtils.buildJsonArray(); - var nextTime = fromDate; - - // Create the JSON object for each ScheduleData and add it to the schedule array - for (var e : this.entries) { - while (nextTime.isBefore(e.time())) { - // Add empty object for gaps - result.add(JsonUtils.buildJsonObject() // - .addProperty("timestamp", nextTime) // - .add("soc", JsonNull.INSTANCE) // - .add("production", JsonNull.INSTANCE) // - .add("consumption", JsonNull.INSTANCE) // - .add("state", JsonNull.INSTANCE) // - .add("price", JsonNull.INSTANCE) // - .add("ess", JsonNull.INSTANCE) // - .add("grid", JsonNull.INSTANCE) // - .build()); - nextTime = nextTime.plusMinutes(15); - } - - result.add(JsonUtils.buildJsonObject() // - .addProperty("timestamp", e.time()) // - .add("soc", toJson(round((e.essInitial() * 100) / (float) this.essTotalEnergy()))) // - .add("production", toJson(e.production())) // - .add("consumption", toJson(e.consumption())) // - .add("state", toJson(e.state.getValue())) // - .add("price", toJson(e.price())) // - .add("ess", toJson(e.essChargeDischarge())) // - .add("grid", toJson(e.grid())) // - .build()); - nextTime = e.time().plusMinutes(15); - } - - return result.build(); + public ImmutableSortedMap toJsonObjects() { + return this.entries().stream() // + .collect(toImmutableSortedMap(ZonedDateTime::compareTo, // + ScheduleData::time, // + sd -> sd.toJsonObject(this.essTotalEnergy()), // + (a, b) -> b)); } public record ScheduleData(// @@ -278,10 +249,47 @@ public static Stream fromHistoricDataQuery(int essTotalEnergy, } /** - * Creates a Stream of {@link ScheduleData}. + * Convert this {@link ScheduleData} to a {@link JsonObject}. * * @param essTotalEnergy ESS Total Energy (Capacity) [Wh] - * @param period the {@link Period} + * @return a JsonObject + */ + public JsonObject toJsonObject(int essTotalEnergy) { + return buildJsonObject() // + .addProperty("timestamp", this.time()) // + .add("soc", toJson(round((this.essInitial() * 100) / (float) essTotalEnergy))) // + .add("production", toJson(toPower(this.production()))) // + .add("consumption", toJson(toPower(this.consumption()))) // + .add("state", toJson(this.state.getValue())) // + .add("price", toJson(this.price())) // + .add("ess", toJson(toPower(this.essChargeDischarge()))) // + .add("grid", toJson(toPower(this.grid()))) // + .build(); + } + + /** + * Convert this {@link ScheduleData} to a {@link JsonObject}. + * + * @param essTotalEnergy ESS Total Energy (Capacity) [Wh] + * @return a JsonObject + */ + public static JsonObject emptyJsonObject(ZonedDateTime timestamp) { + return buildJsonObject() // + .addProperty("timestamp", timestamp) // + .add("soc", JsonNull.INSTANCE) // + .add("production", JsonNull.INSTANCE) // + .add("consumption", JsonNull.INSTANCE) // + .add("state", JsonNull.INSTANCE) // + .add("price", JsonNull.INSTANCE) // + .add("ess", JsonNull.INSTANCE) // + .add("grid", JsonNull.INSTANCE) // + .build(); + } + + /** + * Creates a Stream of {@link ScheduleData}. + * + * @param period the {@link Period} * @return a Stream of {@link ScheduleData} */ public static Stream fromPeriod(Period period) { diff --git a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/optimizer/Simulator.java b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Simulator.java similarity index 88% rename from io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/optimizer/Simulator.java rename to io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Simulator.java index 849e7cd3a11..0b79a5f6cc2 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/optimizer/Simulator.java +++ b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Simulator.java @@ -1,10 +1,10 @@ -package io.openems.edge.controller.ess.timeofusetariff.optimizer; +package io.openems.edge.energy.optimizer; import static io.jenetics.engine.EvolutionResult.toBestGenotype; import static io.jenetics.engine.Limits.byExecutionTime; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.InitialPopulationUtils.buildInitialPopulation; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.paramsAreValid; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.postprocessSimulatorState; +import static io.openems.edge.energy.optimizer.InitialPopulationUtils.buildInitialPopulation; +import static io.openems.edge.energy.optimizer.Utils.paramsAreValid; +import static io.openems.edge.energy.optimizer.Utils.postprocessSimulatorState; import static java.lang.Math.max; import static java.time.Duration.ofSeconds; @@ -24,8 +24,8 @@ import io.jenetics.engine.Engine; import io.jenetics.engine.EvolutionResult; import io.openems.edge.controller.ess.timeofusetariff.StateMachine; -import io.openems.edge.controller.ess.timeofusetariff.optimizer.Params.Length; -import io.openems.edge.controller.ess.timeofusetariff.optimizer.Params.OptimizePeriod; +import io.openems.edge.energy.optimizer.Params.Length; +import io.openems.edge.energy.optimizer.Params.OptimizePeriod; public class Simulator { @@ -105,17 +105,23 @@ protected static double simulatePeriod(Params p, OptimizePeriod op, StateMachine // Calculate Cost double cost; if (ef.grid() > 0) { + // Filter negative prices + var price = max(0, op.price()); + cost = // Cost for direct Consumption - ef.gridToConsumption() * op.price() + ef.gridToConsumption() * price // Cost for future Consumption after storage - + ef.gridToEss() * op.price() * EFFICIENCY_FACTOR; + + ef.gridToEss() * price * EFFICIENCY_FACTOR; } else { // Sell-to-Grid cost = 0.; } if (collect != null) { - var postprocessedState = postprocessSimulatorState(p, essInitial, state, ef); + var postprocessedState = postprocessSimulatorState(state, // + EnergyFlow.withBalancing(p, op, essInitial), // + EnergyFlow.withDelayDischarge(p, op, essInitial), // + EnergyFlow.withChargeGrid(p, op, essInitial)); collect.accept(new Period(op, postprocessedState, essInitial, ef)); } return cost; diff --git a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/optimizer/Utils.java b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Utils.java similarity index 66% rename from io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/optimizer/Utils.java rename to io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Utils.java index 3706433a290..4bc3d97858c 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/optimizer/Utils.java +++ b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Utils.java @@ -1,16 +1,16 @@ -package io.openems.edge.controller.ess.timeofusetariff.optimizer; +package io.openems.edge.energy.optimizer; +import static com.google.common.collect.Streams.concat; import static io.openems.common.utils.DateUtils.roundDownToQuarter; import static io.openems.edge.common.type.TypeUtils.multiply; import static io.openems.edge.common.type.TypeUtils.orElse; import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.BALANCING; +import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.CHARGE_GRID; import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.DELAY_DISCHARGE; import static io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffController.PERIODS_PER_HOUR; import static java.lang.Math.max; -import static java.lang.Math.min; import static java.lang.Math.round; import static java.util.Arrays.stream; -import static java.util.stream.IntStream.concat; import java.time.Clock; import java.time.Duration; @@ -34,23 +34,19 @@ import io.jenetics.util.RandomRegistry; import io.openems.common.exceptions.InvalidValueException; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.exceptions.OpenemsException; import io.openems.common.timedata.Resolution; import io.openems.common.types.ChannelAddress; -import io.openems.edge.common.sum.Sum; -import io.openems.edge.controller.api.Controller; import io.openems.edge.controller.ess.emergencycapacityreserve.ControllerEssEmergencyCapacityReserve; import io.openems.edge.controller.ess.limittotaldischarge.ControllerEssLimitTotalDischarge; import io.openems.edge.controller.ess.timeofusetariff.StateMachine; import io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffController; -import io.openems.edge.controller.ess.timeofusetariff.jsonrpc.GetScheduleResponse; -import io.openems.edge.controller.ess.timeofusetariff.jsonrpc.ScheduleDatas; -import io.openems.edge.controller.ess.timeofusetariff.jsonrpc.ScheduleDatas.ScheduleData; -import io.openems.edge.controller.ess.timeofusetariff.optimizer.Simulator.Period; -import io.openems.edge.ess.api.HybridEss; -import io.openems.edge.ess.api.ManagedSymmetricEss; +import io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImpl; +import io.openems.edge.energy.jsonrpc.GetScheduleResponse; +import io.openems.edge.energy.optimizer.ScheduleDatas.ScheduleData; +import io.openems.edge.energy.optimizer.Simulator.Period; import io.openems.edge.ess.api.SymmetricEss; import io.openems.edge.timedata.api.Timedata; +import io.openems.edge.timeofusetariff.api.TimeOfUseTariff; /** * Utils for {@link TimeOfUseTariffController}. @@ -127,28 +123,29 @@ private static void initializeRandomRegistry(boolean isUnitTest) { /** * Create {@link Params} for {@link Simulator}. * - * @param context the {@link Context} object + * @param globalContext the {@link GlobalContext} object * @param existingSchedule the existing schedule, i.e. result of previous * optimization * @return {@link Params} * @throws InvalidValueException on error */ - public static Params createSimulatorParams(Context context, + public static Params createSimulatorParams(GlobalContext globalContext, ImmutableSortedMap existingSchedule) throws InvalidValueException { final var time = roundDownToQuarter(ZonedDateTime.now()); // Prediction values final var predictionConsumption = joinConsumptionPredictions(4, // - context.predictorManager().getPrediction(SUM_CONSUMPTION).asArray(), // - context.predictorManager().getPrediction(SUM_UNMANAGED_CONSUMPTION).asArray()); + globalContext.predictorManager().getPrediction(SUM_CONSUMPTION).asArray(), // + globalContext.predictorManager().getPrediction(SUM_UNMANAGED_CONSUMPTION).asArray()); final var predictionProduction = generateProductionPrediction(// - context.predictorManager().getPrediction(SUM_PRODUCTION).asArray(), // + globalContext.predictorManager().getPrediction(SUM_PRODUCTION).asArray(), // predictionConsumption.length); // Prices contains the price values and the time it is retrieved. - final var prices = context.timeOfUseTariff().getPrices(); + final var prices = globalContext.timeOfUseTariff().getPrices(); // Ess information. + TimeOfUseTariffControllerImpl.Context context = globalContext.energyScheduleHandler().getContext(); final var essTotalEnergy = context.ess().getCapacity().getOrError(); final var essMinSocEnergy = getEssMinSocEnergy(context, essTotalEnergy); final var essMaxSocEnergy = round(ESS_MAX_SOC / 100F * essTotalEnergy); @@ -156,8 +153,8 @@ public static Params createSimulatorParams(Context context, final var essSocEnergy = essTotalEnergy /* [Wh] */ / 100 * essSoc; // Power Values for scheduling battery for individual periods. - var maxDischargePower = context.sum().getEssMaxDischargePower().orElse(1000 /* at least 1000 */); - var maxChargePower = context.sum().getEssMaxDischargePower().orElse(-1000 /* at least 1000 */); + var maxDischargePower = globalContext.sum().getEssMaxDischargePower().orElse(1000 /* at least 1000 */); + var maxChargePower = globalContext.sum().getEssMaxDischargePower().orElse(-1000 /* at least 1000 */); if (context.limitChargePowerFor14aEnWG()) { maxChargePower = max(ESS_LIMIT_14A_ENWG, maxChargePower); // Apply §14a EnWG limit } @@ -234,11 +231,11 @@ protected static boolean paramsAreValid(Params p) { * Returns the amount of energy that is not available for scheduling because of * a configured minimum SoC. * - * @param context the {@link Context} + * @param context the {@link TimeOfUseTariffControllerImpl.Context} * @param essCapacity net {@link SymmetricEss.ChannelId#CAPACITY} * @return the value in [Wh] */ - protected static int getEssMinSocEnergy(Context context, int essCapacity) { + protected static int getEssMinSocEnergy(TimeOfUseTariffControllerImpl.Context context, int essCapacity) { return essCapacity /* [Wh] */ / 100 // * getEssMinSocPercentage(// context.ctrlLimitTotalDischarges(), // @@ -371,53 +368,61 @@ protected static int findFirstValleyIndex(int fromIndex, double[] values) { * from the {@link Optimizer} provided, then concatenates them to generate a * 24-hour {@link GetScheduleResponse}. * - * @param optimizer the {@link Optimizer} - * @param requestId the JSON-RPC request-id - * @param timedata the{@link Timedata} - * @param componentId the Component-ID - * @param now the current {@link ZonedDateTime} (will get rounded down - * to 15 minutes) + * @param optimizer the {@link Optimizer} + * @param requestId the JSON-RPC request-id + * @param timedata the{@link Timedata} + * @param timeOfUseTariff the {@link TimeOfUseTariff} + * @param componentId the Component-ID + * @param now the current {@link ZonedDateTime} (will get rounded + * down to 15 minutes) * @return the {@link GetScheduleResponse} * @throws OpenemsNamedException on error */ public static GetScheduleResponse handleGetScheduleRequest(Optimizer optimizer, UUID requestId, Timedata timedata, - String componentId, ZonedDateTime now) throws OpenemsNamedException { + TimeOfUseTariff timeOfUseTariff, String componentId, ZonedDateTime now) { + final var b = ImmutableList.builder(); now = roundDownToQuarter(now); + final var fromTime = now.minusHours(3); - final var schedule = optimizer.getSchedule(); - if (schedule == null) { - throw new OpenemsException("Has no Schedule"); - } final var params = optimizer.getParams(); - if (params == null) { - throw new OpenemsException("Has no Params"); - } - final var channelQuarterlyPrices = new ChannelAddress(componentId, "QuarterlyPrices"); - final var channelStateMachine = new ChannelAddress(componentId, "StateMachine"); - final var b = ImmutableList.builder(); - - // Process past data - final var fromDate = now.minusHours(3); - final var toDate = now.minusMinutes(15); - - try { - var queryResult = timedata.queryHistoricData(null, fromDate, toDate, // - Set.of(channelQuarterlyPrices, channelStateMachine, // - SUM_GRID, SUM_PRODUCTION, SUM_CONSUMPTION, SUM_ESS_DISCHARGE_POWER, SUM_ESS_SOC), - new Resolution(15, ChronoUnit.MINUTES)); - ScheduleData.fromHistoricDataQuery(// - params.essTotalEnergy(), channelQuarterlyPrices, channelStateMachine, queryResult) // - .forEach(b::add); - } catch (Exception e) { - LOG.warn("Unable to read historic data: " + e.getMessage()); + if (params != null) { + // Process last three hours of historic data + final var channelQuarterlyPrices = new ChannelAddress(componentId, "QuarterlyPrices"); + final var channelStateMachine = new ChannelAddress(componentId, "StateMachine"); + try { + var queryResult = timedata.queryHistoricData(null, fromTime, now, // + Set.of(channelQuarterlyPrices, channelStateMachine, // + SUM_GRID, SUM_PRODUCTION, SUM_CONSUMPTION, SUM_ESS_DISCHARGE_POWER, SUM_ESS_SOC), + new Resolution(15, ChronoUnit.MINUTES)); + ScheduleData.fromHistoricDataQuery(// + params.essTotalEnergy(), channelQuarterlyPrices, channelStateMachine, queryResult) // + .forEach(b::add); + } catch (Exception e) { + LOG.warn("Unable to read historic data: " + e.getMessage()); + } } // Process future schedule + final var schedule = optimizer.getSchedule(); optimizer.getSchedule().values().stream() // .flatMap(ScheduleData::fromPeriod) // .forEach(b::add); - return new GetScheduleResponse(requestId, fromDate, new ScheduleDatas(params.essTotalEnergy(), b.build())); + // Find 'toTime' of result + final ZonedDateTime toTime; + if (!schedule.isEmpty()) { + toTime = schedule.lastKey(); + } else { + var pricesPerQuarter = timeOfUseTariff.getPrices().pricePerQuarter; + if (!pricesPerQuarter.isEmpty()) { + toTime = pricesPerQuarter.lastKey(); + } else { + toTime = fromTime; + } + } + + return new GetScheduleResponse(requestId, fromTime, toTime, + new ScheduleDatas(params.essTotalEnergy(), b.build())); } /** @@ -445,170 +450,34 @@ public static long calculateExecutionLimitSeconds(Clock clock) { * NOTE: heavy computation is ok here, because this method is called only at the * end with the best Schedule. * - * @param p the {@link Params} - * @param essInitialEnergy the initial ESS energy in this period * @param state the initial state - * @param ef the {@link EnergyFlow} + * @param efBalancing the {@link EnergyFlow} as it would be in + * {@link StateMachine#BALANCING} + * @param efDelayDischarge the {@link EnergyFlow} as it would be in + * {@link StateMachine#DELAY_DISCHARGE} + * @param efChargeGrid the {@link EnergyFlow} as it would be in + * {@link StateMachine#CHARGE_GRID} * @return the new state */ - public static StateMachine postprocessSimulatorState(Params p, int essInitialEnergy, StateMachine state, - EnergyFlow ef) { - return switch (state) { - case BALANCING -> state; - - case DELAY_DISCHARGE -> { - // DELAY_DISCHARGE,... - if (essInitialEnergy <= p.essMinSocEnergy()) { - // but battery is already empty (at Min-Soc) - yield BALANCING; - } else if (ef.productionToEss() > 0) { - // but actually charging -> could have been BALANCING - yield BALANCING; - } - yield state; - } - - case CHARGE_GRID -> { + public static StateMachine postprocessSimulatorState(StateMachine state, EnergyFlow efBalancing, + EnergyFlow efDelayDischarge, EnergyFlow efChargeGrid) { + if (state == CHARGE_GRID) { // CHARGE_GRID,... - if (ef.gridToEss() == 0) { - // but actually not charging - yield BALANCING; - } else if (essInitialEnergy > p.essMaxSocEnergy()) { - // but battery is above limit - yield DELAY_DISCHARGE; + if (efChargeGrid.ess() >= efDelayDischarge.ess()) { + // but battery charge/discharge is the same as DELAY_DISCHARGE + state = DELAY_DISCHARGE; } - yield state; } - }; - } - /** - * Post-Process a state during {@link Controller#run()}, i.e. replace with - * 'better' state if appropriate. - * - *

- * NOTE: this can be useful, if live operation deviates from predicted - * operation, e.g. because predictions were wrong. - * - * @param minSoc the configured Minimum-SoC, or zero - * @param soc the current {@link SymmetricEss.ChannelId#SOC} - * @param production the current {@link Sum.ChannelId#PRODUCTION_ACTIVE_POWER}, - * or zero - * @param state the initial state - * @return the new state - */ - public static StateMachine postprocessRunState(int minSoc, Integer soc, int production, StateMachine state) { - if (soc == null) { - return state; - } - - return switch (state) { - case BALANCING -> state; - - case DELAY_DISCHARGE -> { + if (state == DELAY_DISCHARGE) { // DELAY_DISCHARGE,... - if (soc <= minSoc) { - // but SoC is at Min-SoC -> could have been BALANCING - yield BALANCING; - } - yield state; - } - - case CHARGE_GRID -> { - // CHARGE_GRID,... - if (soc > ESS_MAX_SOC) { - // but surpassed Max-SoC -> stop charge; no discharge - yield DELAY_DISCHARGE; - } - yield state; - } - }; - } - - protected static int calculateEssChargeInChargeGridPowerFromParams(Params params, ManagedSymmetricEss ess) { - if (params != null) { - for (var period : params.optimizePeriods()) { - return toPower(period.essChargeInChargeGrid()); // take first period + if (efDelayDischarge.ess() >= efBalancing.ess()) { + // but battery charge/discharge is the same as BALANCING + state = BALANCING; } } - var capacity = ess.getCapacity(); - if (capacity.isDefined()) { - return round(capacity.get() * ESS_CHARGE_C_RATE); - } - var maxApparentPower = ess.getMaxApparentPower(); - if (maxApparentPower.isDefined()) { - return maxApparentPower.get() / 4; - } - return 0; - } - - /** - * Calculates the Max-ActivePower constraint for - * {@link StateMachine#CHARGE_GRID}. - * - * @param params the {@link Params} - * @param ess the {@link ManagedSymmetricEss} - * @param sum the {@link Sum} - * @param maxChargePowerFromGrid the configured max charge from grid power - * @param limitChargePowerFor14aEnWG Limit Charge Power for §14a EnWG - * @return the set-point or null - */ - public static Integer calculateChargeGridPower(Params params, ManagedSymmetricEss ess, Sum sum, - int maxChargePowerFromGrid, boolean limitChargePowerFor14aEnWG) { - // TODO limitChargePowerFor14aEnWG - var gridActivePower = sum.getGridActivePower().get(); // current buy-from/sell-to grid - var essActivePower = ess.getActivePower().get(); // current charge/discharge ESS - if (gridActivePower == null || essActivePower == null) { - return null; // undefined state - } - - var realGridPower = gridActivePower + essActivePower; // 'real', without current ESS charge/discharge - var targetChargePower = calculateEssChargeInChargeGridPowerFromParams(params, ess) // - + min(0, realGridPower) * -1; // add excess production - var effectiveGridBuyPower = max(0, realGridPower) + targetChargePower; - var chargePower = max(0, targetChargePower - max(0, effectiveGridBuyPower - maxChargePowerFromGrid)); - - // Invert to negative for CHARGE - chargePower *= -1; - // Apply §14a EnWG limit - if (limitChargePowerFor14aEnWG) { - chargePower = max(ESS_LIMIT_14A_ENWG, chargePower); - } - - return chargePower; - } - - /** - * Calculates the Max-ActivePower constraint for - * {@link StateMachine#CHARGE_PRODUCTION}. - * - * @param sum the {@link Sum} - * @return the set-point - */ - public static Integer calculateMaxChargeProductionPower(Sum sum) { - var productionAcActivePower = sum.getProductionAcActivePower().get(); - if (productionAcActivePower == null || productionAcActivePower < 0) { - return 0; // unknown AC production -> do not charge - } - return -productionAcActivePower; - } - - /** - * Calculates the ActivePower constraint for - * {@link StateMachine#DELAY_DISCHARGE}. - * - * @param ess the {@link ManagedSymmetricEss} - * @return the set-point - */ - public static Integer calculateDelayDischargePower(ManagedSymmetricEss ess) { - if (ess instanceof HybridEss) { - // Limit discharge to DC-PV power - return max(0, ess.getActivePower().orElse(0) - ((HybridEss) ess).getDcDischargePower().orElse(0)); - } else { - // Limit discharge to 0 - return 0; - } + return state; } /** diff --git a/io.openems.edge.energy/test/.gitignore b/io.openems.edge.energy/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.energy/test/io/openems/edge/energy/EnergySchedulerImplTest.java b/io.openems.edge.energy/test/io/openems/edge/energy/EnergySchedulerImplTest.java new file mode 100644 index 00000000000..10331208f63 --- /dev/null +++ b/io.openems.edge.energy/test/io/openems/edge/energy/EnergySchedulerImplTest.java @@ -0,0 +1,126 @@ +package io.openems.edge.energy; + +import static io.openems.common.utils.DateUtils.roundDownToQuarter; +import static io.openems.edge.energy.TestData.CONSUMPTION_PREDICTION_QUARTERLY; +import static io.openems.edge.energy.TestData.HOURLY_PRICES_SUMMER; +import static io.openems.edge.energy.TestData.PRODUCTION_PREDICTION_QUARTERLY; +import static io.openems.edge.energy.optimizer.Utils.SUM_CONSUMPTION; +import static io.openems.edge.energy.optimizer.Utils.SUM_PRODUCTION; +import static java.time.temporal.ChronoUnit.DAYS; + +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.util.List; +import java.util.function.Supplier; + +import org.junit.Test; + +import io.openems.common.test.TimeLeapClock; +import io.openems.edge.common.sum.DummySum; +import io.openems.edge.common.test.AbstractComponentTest.TestCase; +import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.common.test.DummyComponentManager; +import io.openems.edge.common.test.DummyConfigurationAdmin; +import io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImpl; +import io.openems.edge.energy.optimizer.GlobalContext; +import io.openems.edge.energy.optimizer.Optimizer; +import io.openems.edge.predictor.api.prediction.Prediction; +import io.openems.edge.predictor.api.test.DummyPredictor; +import io.openems.edge.predictor.api.test.DummyPredictorManager; +import io.openems.edge.timedata.test.DummyTimedata; +import io.openems.edge.timeofusetariff.test.DummyTimeOfUseTariffProvider; + +public class EnergySchedulerImplTest { + + public static final Clock CLOCK = new TimeLeapClock(Instant.parse("2020-03-04T14:19:00.00Z"), ZoneOffset.UTC); + + private static final String CTRL_ID = "ctrl0"; + + @Test + public void test() throws Exception { + create(CLOCK); + } + + /** + * Creates a {@link EnergySchedulerImplTest} instance. + * + * @param clock a {@link Clock} + * @return the object + * @throws Exception on error + */ + public static EnergySchedulerImpl create(Clock clock) throws Exception { + var now = roundDownToQuarter(ZonedDateTime.now(clock)); + final var midnight = now.truncatedTo(DAYS); + var componentManager = new DummyComponentManager(clock); + var sum = new DummySum(); + var predictor0 = new DummyPredictor("predictor0", componentManager, + Prediction.from(sum, SUM_PRODUCTION, midnight, PRODUCTION_PREDICTION_QUARTERLY), SUM_PRODUCTION); + var predictor1 = new DummyPredictor("predictor0", componentManager, + Prediction.from(sum, SUM_CONSUMPTION, midnight, CONSUMPTION_PREDICTION_QUARTERLY), SUM_CONSUMPTION); + var timeOfUseTariff = DummyTimeOfUseTariffProvider.fromHourlyPrices(clock, HOURLY_PRICES_SUMMER); + var ctrl = new TimeOfUseTariffControllerImpl(); // this is not fully activated; config is null + + var sut = new EnergySchedulerImpl(); + new ComponentTest(sut) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("componentManager", componentManager) // + .addReference("predictorManager", new DummyPredictorManager(predictor0, predictor1)) // + .addReference("timedata", new DummyTimedata("timedata0")) // + .addReference("timeOfUseTariff", timeOfUseTariff) // + .addReference("schedulables", List.of(ctrl)) // + .addReference("sum", sum) // + .activate(MyConfig.create() // + .setId(CTRL_ID) // + .setEnabled(false) // + .setEssId("ess0") // + .setEssMaxChargePower(5000) // + .setMaxChargePowerFromGrid(10000) // + .setLimitChargePowerFor14aEnWG(false) // + .build()) // + .next(new TestCase()); + return sut; + } + + /** + * Gets the {@link Optimizer} via Java Reflection. + * + * @param energyScheduler the {@link EnergySchedulerImpl} + * @return the object + * @throws Exception on error + */ + public static Optimizer getOptimizer(EnergySchedulerImpl energyScheduler) throws Exception { + var field = EnergySchedulerImpl.class.getDeclaredField("optimizer"); + field.setAccessible(true); + return (Optimizer) field.get(energyScheduler); + } + + /** + * Calls the 'createParams()' method in the {@link Optimizer} via Java + * Reflection. + * + * @param optimizer the {@link Optimizer} + * @throws Exception on error + */ + public static void callCreateParams(Optimizer optimizer) throws Exception { + var method = Optimizer.class.getDeclaredMethod("createParams"); + method.setAccessible(true); + method.invoke(optimizer); + } + + /** + * Gets the {@link GlobalContext} via Java Reflection. + * + * @param energyScheduler the {@link EnergySchedulerImpl} + * @return the object + * @throws Exception on error + */ + @SuppressWarnings("unchecked") + public static GlobalContext getGlobalContext(EnergySchedulerImpl energyScheduler) throws Exception { + var optimizer = getOptimizer(energyScheduler); + var field = Optimizer.class.getDeclaredField("globalContext"); + field.setAccessible(true); + return ((Supplier) field.get(optimizer)).get(); + } +} diff --git a/io.openems.edge.energy/test/io/openems/edge/energy/MyConfig.java b/io.openems.edge.energy/test/io/openems/edge/energy/MyConfig.java new file mode 100644 index 00000000000..2aeb9dc7bd3 --- /dev/null +++ b/io.openems.edge.energy/test/io/openems/edge/energy/MyConfig.java @@ -0,0 +1,74 @@ +package io.openems.edge.energy; + +import io.openems.common.test.AbstractComponentConfig; + +@SuppressWarnings("all") +public class MyConfig extends AbstractComponentConfig implements Config { + + protected static class Builder { + private String id; + private boolean enabled; + private String essId; + private int essMaxChargePower; + private int maxChargePowerFromGrid; + private boolean limitChargePowerFor14aEnWG; + + private Builder() { + } + + public Builder setId(String id) { + this.id = id; + return this; + } + + public Builder setEnabled(boolean enabled) { + this.enabled = enabled; + return this; + } + + public Builder setEssId(String essId) { + this.essId = essId; + return this; + } + + public Builder setEssMaxChargePower(int essMaxChargePower) { + this.essMaxChargePower = essMaxChargePower; + return this; + } + + public Builder setMaxChargePowerFromGrid(int maxChargePowerFromGrid) { + this.maxChargePowerFromGrid = maxChargePowerFromGrid; + return this; + } + + public Builder setLimitChargePowerFor14aEnWG(boolean limitChargePowerFor14aEnWG) { + this.limitChargePowerFor14aEnWG = limitChargePowerFor14aEnWG; + return this; + } + + public MyConfig build() { + return new MyConfig(this); + } + } + + /** + * Create a Config builder. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new Builder(); + } + + private final Builder builder; + + private MyConfig(Builder builder) { + super(Config.class, builder.id); + this.builder = builder; + } + + @Override + public boolean enabled() { + return this.builder.enabled; + } +} \ No newline at end of file diff --git a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/TestData.java b/io.openems.edge.energy/test/io/openems/edge/energy/TestData.java similarity index 98% rename from io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/TestData.java rename to io.openems.edge.energy/test/io/openems/edge/energy/TestData.java index 664f3b0d705..c89873819e7 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/TestData.java +++ b/io.openems.edge.energy/test/io/openems/edge/energy/TestData.java @@ -1,8 +1,10 @@ -package io.openems.edge.controller.ess.timeofusetariff; +package io.openems.edge.energy; import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.BALANCING; import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.DELAY_DISCHARGE; +import io.openems.edge.controller.ess.timeofusetariff.StateMachine; + public class TestData { // Edge 888; 06.11.2023 diff --git a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/GetScheduleResponseTest.java b/io.openems.edge.energy/test/io/openems/edge/energy/jsonrpc/GetScheduleResponseTest.java similarity index 53% rename from io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/GetScheduleResponseTest.java rename to io.openems.edge.energy/test/io/openems/edge/energy/jsonrpc/GetScheduleResponseTest.java index a5d6d3df718..780b77f7b9d 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/GetScheduleResponseTest.java +++ b/io.openems.edge.energy/test/io/openems/edge/energy/jsonrpc/GetScheduleResponseTest.java @@ -1,9 +1,9 @@ -package io.openems.edge.controller.ess.timeofusetariff.jsonrpc; +package io.openems.edge.energy.jsonrpc; import static io.openems.common.utils.JsonUtils.prettyToString; import static io.openems.common.utils.UuidUtils.getNilUuid; -import static io.openems.edge.controller.ess.timeofusetariff.jsonrpc.ScheduleDatasTest.SCHEDULE_DATAS; -import static io.openems.edge.controller.ess.timeofusetariff.jsonrpc.ScheduleDatasTest.TIME; +import static io.openems.edge.energy.optimizer.ScheduleDatasTest.SCHEDULE_DATAS; +import static io.openems.edge.energy.optimizer.SimulatorTest.TIME; import static org.junit.Assert.assertEquals; import org.junit.Test; @@ -14,7 +14,7 @@ public class GetScheduleResponseTest { @Test public void testToJsonObject() throws OpenemsNamedException { - var response = new GetScheduleResponse(getNilUuid(), TIME, SCHEDULE_DATAS); + var response = new GetScheduleResponse(getNilUuid(), TIME, TIME.plusMinutes(30), SCHEDULE_DATAS); assertEquals(""" { @@ -22,25 +22,35 @@ public void testToJsonObject() throws OpenemsNamedException { "id": "00000000-0000-0000-0000-000000000000", "result": { "schedule": [ + { + "timestamp": "2000-01-01T00:00:00Z", + "soc": null, + "production": null, + "consumption": null, + "state": null, + "price": null, + "ess": null, + "grid": null + }, { "timestamp": "2000-01-01T00:15:00Z", "soc": 6, - "production": 222, - "consumption": 333, + "production": 888, + "consumption": 1332, "state": 0, "price": 78.9, - "ess": 987, - "grid": 654 + "ess": 3948, + "grid": 2616 }, { "timestamp": "2000-01-01T00:30:00Z", "soc": 21, - "production": 444, - "consumption": 333, + "production": 1776, + "consumption": 1332, "state": 3, "price": 12.3, - "ess": 987, - "grid": 654 + "ess": 3948, + "grid": 2616 } ] } diff --git a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/optimizer/EnergyFlowTest.java b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/EnergyFlowTest.java similarity index 87% rename from io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/optimizer/EnergyFlowTest.java rename to io.openems.edge.energy/test/io/openems/edge/energy/optimizer/EnergyFlowTest.java index a9d8b9eec7b..d58ae40fc1d 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/optimizer/EnergyFlowTest.java +++ b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/EnergyFlowTest.java @@ -1,5 +1,9 @@ -package io.openems.edge.controller.ess.timeofusetariff.optimizer; +package io.openems.edge.energy.optimizer; +import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.BALANCING; +import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.CHARGE_GRID; +import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.DELAY_DISCHARGE; +import static io.openems.edge.energy.optimizer.Utils.postprocessSimulatorState; import static java.lang.Math.max; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -11,7 +15,7 @@ import org.junit.Test; import io.openems.common.function.TriFunction; -import io.openems.edge.controller.ess.timeofusetariff.optimizer.Params.OptimizePeriod; +import io.openems.edge.energy.optimizer.Params.OptimizePeriod; public class EnergyFlowTest { @@ -257,6 +261,7 @@ public void testChargeGridAndAboveGridMaxEnergy() { /* * DISCHARGE GRID - just for completeness */ + private static EnergyFlow withDischargeGrid(Params p, OptimizePeriod op, int essInitial) { // This is just for completeness; not actually used yet return EnergyFlow.create(p, op, essInitial, // @@ -275,4 +280,29 @@ public void testDischargeGridAndCharge() { assertEquals(500, e.productionToConsumption()); assertEquals(2000, e.productionToGrid()); } + + /* + * Utils + */ + + @Test + public void testUtilsPostprocessPeriodState() { + assertEquals("BALANCING stays BALANCING", // + BALANCING, postprocessSimulatorState(BALANCING, // + NO_FLOW, NO_FLOW, NO_FLOW)); + + assertEquals("DELAY_DISCHARGE stays DELAY_DISCHARGE", // + DELAY_DISCHARGE, postprocessSimulatorState(DELAY_DISCHARGE, // + NO_FLOW, charge(EnergyFlow::withDelayDischarge), NO_FLOW)); + assertEquals("DELAY_DISCHARGE to BALANCING", // + BALANCING, postprocessSimulatorState(DELAY_DISCHARGE, // + NO_FLOW, NO_FLOW, NO_FLOW)); + + assertEquals("CHARGE_GRID stays CHARGE_GRID", // + CHARGE_GRID, postprocessSimulatorState(CHARGE_GRID, // + NO_FLOW, NO_FLOW, charge(EnergyFlow::withChargeGrid))); + assertEquals("CHARGE_GRID to BALANCING", // + BALANCING, postprocessSimulatorState(CHARGE_GRID, // + NO_FLOW, NO_FLOW, NO_FLOW)); + } } diff --git a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/optimizer/InitialPopulationUtilsTest.java b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/InitialPopulationUtilsTest.java similarity index 82% rename from io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/optimizer/InitialPopulationUtilsTest.java rename to io.openems.edge.energy/test/io/openems/edge/energy/optimizer/InitialPopulationUtilsTest.java index 31c101e741e..ee7c8c1d448 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/optimizer/InitialPopulationUtilsTest.java +++ b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/InitialPopulationUtilsTest.java @@ -1,16 +1,16 @@ -package io.openems.edge.controller.ess.timeofusetariff.optimizer; +package io.openems.edge.energy.optimizer; import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.BALANCING; import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.CHARGE_GRID; import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.DELAY_DISCHARGE; -import static io.openems.edge.controller.ess.timeofusetariff.TestData.CONSUMPTION_888_20231106; -import static io.openems.edge.controller.ess.timeofusetariff.TestData.PRICES_888_20231106; -import static io.openems.edge.controller.ess.timeofusetariff.TestData.PRODUCTION_888_20231106; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.InitialPopulationUtils.buildInitialPopulation; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.SimulatorTest.hourlyToQuarterly; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.interpolateArray; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.toEnergy; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.UtilsTest.prepareExistingSchedule; +import static io.openems.edge.energy.TestData.CONSUMPTION_888_20231106; +import static io.openems.edge.energy.TestData.PRICES_888_20231106; +import static io.openems.edge.energy.TestData.PRODUCTION_888_20231106; +import static io.openems.edge.energy.optimizer.InitialPopulationUtils.buildInitialPopulation; +import static io.openems.edge.energy.optimizer.SimulatorTest.hourlyToQuarterly; +import static io.openems.edge.energy.optimizer.Utils.interpolateArray; +import static io.openems.edge.energy.optimizer.Utils.toEnergy; +import static io.openems.edge.energy.optimizer.UtilsTest.prepareExistingSchedule; import static java.util.Arrays.stream; import static org.junit.Assert.assertEquals; diff --git a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/optimizer/IntegrationTests.java b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/IntegrationTests.java similarity index 79% rename from io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/optimizer/IntegrationTests.java rename to io.openems.edge.energy/test/io/openems/edge/energy/optimizer/IntegrationTests.java index 8869a26d10a..f5b0ebbc544 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/optimizer/IntegrationTests.java +++ b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/IntegrationTests.java @@ -1,11 +1,11 @@ -package io.openems.edge.controller.ess.timeofusetariff.optimizer; +package io.openems.edge.energy.optimizer; import static io.openems.common.utils.DateUtils.parseZonedDateTimeOrError; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Params.PARAMS_PATTERN; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Simulator.calculateCost; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Simulator.getBestSchedule; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.SimulatorTest.logSchedule; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.initializeRandomRegistryForUnitTest; +import static io.openems.edge.energy.optimizer.Params.PARAMS_PATTERN; +import static io.openems.edge.energy.optimizer.Simulator.calculateCost; +import static io.openems.edge.energy.optimizer.Simulator.getBestSchedule; +import static io.openems.edge.energy.optimizer.SimulatorTest.logSchedule; +import static io.openems.edge.energy.optimizer.Utils.initializeRandomRegistryForUnitTest; import static java.lang.Integer.parseInt; import static org.junit.Assert.assertEquals; @@ -20,8 +20,7 @@ import io.openems.common.exceptions.OpenemsException; import io.openems.edge.controller.ess.timeofusetariff.StateMachine; -import io.openems.edge.controller.ess.timeofusetariff.jsonrpc.ScheduleDatas; -import io.openems.edge.controller.ess.timeofusetariff.jsonrpc.ScheduleDatas.ScheduleData; +import io.openems.edge.energy.optimizer.ScheduleDatas.ScheduleData; public class IntegrationTests { diff --git a/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/OptimizerTest.java b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/OptimizerTest.java new file mode 100644 index 00000000000..1ab693e4e03 --- /dev/null +++ b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/OptimizerTest.java @@ -0,0 +1,21 @@ +package io.openems.edge.energy.optimizer; + +import static io.openems.edge.energy.EnergySchedulerImplTest.CLOCK; +import static io.openems.edge.energy.EnergySchedulerImplTest.getOptimizer; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import io.openems.edge.energy.EnergySchedulerImplTest; + +public class OptimizerTest { + + @Test + public void testEmpty() throws Exception { + var sut = getOptimizer(EnergySchedulerImplTest.create(CLOCK)); + assertNull(sut.getParams()); + assertTrue(sut.getSchedule().isEmpty()); + } + +} diff --git a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/optimizer/ParamsUtilsTest.java b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/ParamsUtilsTest.java similarity index 83% rename from io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/optimizer/ParamsUtilsTest.java rename to io.openems.edge.energy/test/io/openems/edge/energy/optimizer/ParamsUtilsTest.java index 61fa54d6c1f..68fb733131c 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/optimizer/ParamsUtilsTest.java +++ b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/ParamsUtilsTest.java @@ -1,7 +1,7 @@ -package io.openems.edge.controller.ess.timeofusetariff.optimizer; +package io.openems.edge.energy.optimizer; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.ParamsUtils.calculateChargeEnergyInChargeGrid; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.ParamsUtils.calculatePeriodLengthHourFromIndex; +import static io.openems.edge.energy.optimizer.ParamsUtils.calculateChargeEnergyInChargeGrid; +import static io.openems.edge.energy.optimizer.ParamsUtils.calculatePeriodLengthHourFromIndex; import static org.junit.Assert.assertEquals; import java.time.ZonedDateTime; diff --git a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/optimizer/RunOptimizerFromLogApp.java b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/RunOptimizerFromLogApp.java similarity index 72% rename from io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/optimizer/RunOptimizerFromLogApp.java rename to io.openems.edge.energy/test/io/openems/edge/energy/optimizer/RunOptimizerFromLogApp.java index 935d969fc10..1c468f22028 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/optimizer/RunOptimizerFromLogApp.java +++ b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/RunOptimizerFromLogApp.java @@ -1,7 +1,8 @@ -package io.openems.edge.controller.ess.timeofusetariff.optimizer; +package io.openems.edge.energy.optimizer; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Simulator.getBestSchedule; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.SimulatorTest.logSchedule; +import static io.openems.edge.energy.optimizer.Simulator.getBestSchedule; +import static io.openems.edge.energy.optimizer.Simulator.simulate; +import static io.openems.edge.energy.optimizer.Utils.logSchedule; /** * This little application allows running the Optimizer from an existing log. @@ -34,7 +35,8 @@ public class RunOptimizerFromLogApp { public static void main(String[] args) throws Exception { var params = IntegrationTests.parseParams(LOG); var schedule = getBestSchedule(params, EXECUTION_LIMIT_SECONDS); + var periods = simulate(params, schedule); - logSchedule(params, schedule); + logSchedule(params, periods); } } \ No newline at end of file diff --git a/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/ScheduleDatasTest.java b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/ScheduleDatasTest.java new file mode 100644 index 00000000000..33cc5327106 --- /dev/null +++ b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/ScheduleDatasTest.java @@ -0,0 +1,183 @@ +package io.openems.edge.energy.optimizer; + +import static io.openems.common.utils.JsonUtils.getAsInt; +import static io.openems.common.utils.JsonUtils.prettyToString; +import static io.openems.common.utils.JsonUtils.toJson; +import static io.openems.common.utils.JsonUtils.toJsonArray; +import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.CHARGE_GRID; +import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.DELAY_DISCHARGE; +import static io.openems.edge.energy.EnergySchedulerImplTest.CLOCK; +import static io.openems.edge.energy.EnergySchedulerImplTest.getOptimizer; +import static io.openems.edge.energy.optimizer.ScheduleDatas.fromLogString; +import static io.openems.edge.energy.optimizer.ScheduleDatas.ScheduleData.fromHistoricDataQuery; +import static io.openems.edge.energy.optimizer.Utils.SUM_CONSUMPTION; +import static io.openems.edge.energy.optimizer.Utils.SUM_ESS_DISCHARGE_POWER; +import static io.openems.edge.energy.optimizer.Utils.SUM_ESS_SOC; +import static io.openems.edge.energy.optimizer.Utils.SUM_GRID; +import static io.openems.edge.energy.optimizer.Utils.SUM_PRODUCTION; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.SortedMap; + +import org.junit.Test; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSortedMap; +import com.google.gson.JsonElement; + +import io.openems.common.types.ChannelAddress; +import io.openems.common.utils.DateUtils; +import io.openems.edge.controller.ess.timeofusetariff.StateMachine; +import io.openems.edge.energy.EnergySchedulerImplTest; +import io.openems.edge.energy.optimizer.Params.Length; +import io.openems.edge.energy.optimizer.Params.OptimizePeriod; +import io.openems.edge.energy.optimizer.Params.QuarterPeriod; +import io.openems.edge.energy.optimizer.ScheduleDatas.ScheduleData; + +public class ScheduleDatasTest { + + protected static final ZonedDateTime TIME = ZonedDateTime.of(2000, 1, 1, 0, 15, 0, 0, ZoneId.of("UTC")); + + public static final ScheduleDatas SCHEDULE_DATAS = new ScheduleDatas(22_000, ImmutableList.of(// + new ScheduleData(TIME, null, 100, 200, 300, 1234, 222, 333, 78.9, DELAY_DISCHARGE, 987, 654), + new ScheduleData(TIME.plusMinutes(15), null, 100, 200, 300, 4567, 444, 333, 12.3, CHARGE_GRID, 987, 654))); + + @Test + public void testIsEmpty() { + assertFalse(SCHEDULE_DATAS.isEmpty()); + assertTrue(new ScheduleDatas(22_000, ImmutableList.of()).isEmpty()); + } + + @Test + public void testStream() { + assertEquals(2, SCHEDULE_DATAS.stream().count()); + } + + @Test + public void testToLogString() { + assertEquals( + """ + OPTIMIZER Time OptimizeBy EssMaxChargeEnergy EssMaxDischargeEnergy MaxBuyFromGrid EssInitial Production Consumption Price State EssChargeDischarge Grid + OPTIMIZER 00:15 - 100 200 300 1234 222 333 78.90 DELAY_DISCHARGE 987 654 + OPTIMIZER 00:30 - 100 200 300 4567 444 333 12.30 CHARGE_GRID 987 654 + """, + SCHEDULE_DATAS.toLogString("OPTIMIZER ")); + } + + @Test + public void testToJsonArray() { + assertEquals(""" + [ + { + "timestamp": "2000-01-01T00:15:00Z", + "soc": 6, + "production": 888, + "consumption": 1332, + "state": 0, + "price": 78.9, + "ess": 3948, + "grid": 2616 + }, + { + "timestamp": "2000-01-01T00:30:00Z", + "soc": 21, + "production": 1776, + "consumption": 1332, + "state": 3, + "price": 12.3, + "ess": 3948, + "grid": 2616 + } + ]""", prettyToString(SCHEDULE_DATAS.toJsonObjects().values().stream().collect(toJsonArray()))); + } + + @Test + public void testFromLogString() { + var log = SCHEDULE_DATAS.toLogString(""); + assertEquals(log, fromLogString(22_000, log).toLogString("")); + } + + @Test + public void testFromSchedule1() throws Exception { + var optimizer = getOptimizer(EnergySchedulerImplTest.create(CLOCK)); + var p = optimizer.getParams(); + var s = optimizer.getSchedule(); + + assertNull(p); + assertTrue(s.isEmpty()); + } + + @Test + public void testFromSchedule2() throws Exception { + var sds = ScheduleDatas.fromSchedule(22_000, ImmutableSortedMap.of(// + TIME, // + new Simulator.Period(// + new OptimizePeriod(TIME, Length.QUARTER, 1, 2, 3, 4, 5, 6, 7., ImmutableList.of(// + new QuarterPeriod(TIME, 1, 2, 3, 4, 5, 6, 7))), + StateMachine.BALANCING, 10_000, + new EnergyFlow(0, 0, 1000 /* ess */, 500 /* grid */, 0, 0, 0, 0, 0, 0)) // + )); + assertEquals( + """ + OPTIMIZER Time OptimizeBy EssMaxChargeEnergy EssMaxDischargeEnergy MaxBuyFromGrid EssInitial Production Consumption Price State EssChargeDischarge Grid + OPTIMIZER 00:15 QUARTER 1 2 4 10000 5 6 7.00 BALANCING 1000 500 + """, + sds.toLogString("OPTIMIZER ")); + } + + @Test + public void testFromHistoricDataQuery() throws Exception { + final var price = ChannelAddress.fromString("_sum/GridBuyPrice"); + final var state = ChannelAddress.fromString("ctrl0/StateMachine"); + final var time = DateUtils.roundDownToQuarter(ZonedDateTime.now()); + + var sd = fromHistoricDataQuery(10000 /* [Wh] */, price, state, + ImmutableSortedMap.>naturalOrder() // + .put(time, ImmutableSortedMap.naturalOrder() // + .put(SUM_ESS_SOC, toJson(50)) // + .put(SUM_PRODUCTION, toJson(123)) // + .put(SUM_CONSUMPTION, toJson(234)) // + .put(price, toJson(100)) // + .put(state, toJson(CHARGE_GRID.getValue())) // + .put(SUM_ESS_DISCHARGE_POWER, toJson(345)) // + .put(SUM_GRID, toJson(456)) // + .build()) // + .build()) // + .findFirst().get(); + + assertEquals(5000, sd.essInitial()); + assertEquals(123 / 4, sd.production()); + assertEquals(234 / 4, sd.consumption()); + assertEquals(100., sd.price(), 0.001); + assertEquals(CHARGE_GRID, sd.state()); + assertEquals(345 / 4, sd.essChargeDischarge()); + assertEquals(456 / 4, sd.grid()); + + var j = sd.toJsonObject(10000); + + assertEquals(50, getAsInt(j, "soc")); + assertEquals(120 /* rounding */, getAsInt(j, "production")); + assertEquals(232, getAsInt(j, "consumption")); + assertEquals(CHARGE_GRID.getValue(), getAsInt(j, "state")); + assertEquals(100., getAsInt(j, "price"), 0.001); + assertEquals(344 /* rounding */, getAsInt(j, "ess")); + assertEquals(456, getAsInt(j, "grid")); + } + + @Test + public void testToJsonObjects() throws Exception { + // Simulate duplicated timestamp + var sds = new ScheduleDatas(SCHEDULE_DATAS.essTotalEnergy(), ImmutableList.builder() // + .addAll(SCHEDULE_DATAS.entries()) // + .add(SCHEDULE_DATAS.entries().get(0)) // + .build()); + var j = sds.toJsonObjects(); + assertEquals(2, j.size()); + } + +} diff --git a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/optimizer/SimulatorTest.java b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/SimulatorTest.java similarity index 90% rename from io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/optimizer/SimulatorTest.java rename to io.openems.edge.energy/test/io/openems/edge/energy/optimizer/SimulatorTest.java index 6f34a0141b1..73cae4f79cb 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/optimizer/SimulatorTest.java +++ b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/SimulatorTest.java @@ -1,15 +1,15 @@ -package io.openems.edge.controller.ess.timeofusetariff.optimizer; +package io.openems.edge.energy.optimizer; import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.BALANCING; import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.CHARGE_GRID; import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.DELAY_DISCHARGE; -import static io.openems.edge.controller.ess.timeofusetariff.TestData.CONSUMPTION_888_20231106; -import static io.openems.edge.controller.ess.timeofusetariff.TestData.PRICES_888_20231106; -import static io.openems.edge.controller.ess.timeofusetariff.TestData.PRODUCTION_888_20231106; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Simulator.getBestSchedule; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Simulator.simulate; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.interpolateArray; -import static io.openems.edge.controller.ess.timeofusetariff.optimizer.Utils.toEnergy; +import static io.openems.edge.energy.TestData.CONSUMPTION_888_20231106; +import static io.openems.edge.energy.TestData.PRICES_888_20231106; +import static io.openems.edge.energy.TestData.PRODUCTION_888_20231106; +import static io.openems.edge.energy.optimizer.Simulator.getBestSchedule; +import static io.openems.edge.energy.optimizer.Simulator.simulate; +import static io.openems.edge.energy.optimizer.Utils.interpolateArray; +import static io.openems.edge.energy.optimizer.Utils.toEnergy; import static java.util.Arrays.stream; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -30,7 +30,7 @@ import io.jenetics.util.RandomRegistry; import io.openems.edge.controller.ess.timeofusetariff.ControlMode; import io.openems.edge.controller.ess.timeofusetariff.StateMachine; -import io.openems.edge.controller.ess.timeofusetariff.optimizer.Simulator.Period; +import io.openems.edge.energy.optimizer.Simulator.Period; public class SimulatorTest { diff --git a/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/UtilsTest.java b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/UtilsTest.java new file mode 100644 index 00000000000..a2b82ad90a9 --- /dev/null +++ b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/UtilsTest.java @@ -0,0 +1,337 @@ +package io.openems.edge.energy.optimizer; + +import static io.openems.common.utils.DateUtils.roundDownToQuarter; +import static io.openems.edge.common.test.TestUtils.withValue; +import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.BALANCING; +import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.DELAY_DISCHARGE; +import static io.openems.edge.energy.EnergySchedulerImplTest.getOptimizer; +import static io.openems.edge.energy.TestData.CONSUMPTION_PREDICTION_QUARTERLY; +import static io.openems.edge.energy.TestData.PAST_HOURLY_PRICES; +import static io.openems.edge.energy.TestData.PAST_SOC; +import static io.openems.edge.energy.TestData.PAST_STATES; +import static io.openems.edge.energy.TestData.PRODUCTION_888_20231106; +import static io.openems.edge.energy.TestData.PRODUCTION_PREDICTION_QUARTERLY; +import static io.openems.edge.energy.optimizer.EnergyFlowTest.NO_FLOW; +import static io.openems.edge.energy.optimizer.SimulatorTest.TIME; +import static io.openems.edge.energy.optimizer.Utils.SUM_CONSUMPTION; +import static io.openems.edge.energy.optimizer.Utils.SUM_ESS_DISCHARGE_POWER; +import static io.openems.edge.energy.optimizer.Utils.SUM_ESS_SOC; +import static io.openems.edge.energy.optimizer.Utils.SUM_GRID; +import static io.openems.edge.energy.optimizer.Utils.SUM_PRODUCTION; +import static io.openems.edge.energy.optimizer.Utils.calculateExecutionLimitSeconds; +import static io.openems.edge.energy.optimizer.Utils.findFirstPeakIndex; +import static io.openems.edge.energy.optimizer.Utils.findFirstValleyIndex; +import static io.openems.edge.energy.optimizer.Utils.generateProductionPrediction; +import static io.openems.edge.energy.optimizer.Utils.getEssMinSocEnergy; +import static io.openems.edge.energy.optimizer.Utils.interpolateArray; +import static io.openems.edge.energy.optimizer.Utils.joinConsumptionPredictions; +import static io.openems.edge.energy.optimizer.Utils.paramsAreValid; +import static io.openems.edge.energy.optimizer.Utils.toEnergy; +import static io.openems.edge.energy.optimizer.Utils.toPower; +import static io.openems.edge.energy.optimizer.Utils.updateSchedule; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.time.Duration; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; +import java.util.List; +import java.util.TreeMap; +import java.util.stream.IntStream; + +import org.junit.Test; + +import com.google.common.collect.ImmutableSortedMap; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.test.TimeLeapClock; +import io.openems.common.types.ChannelAddress; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.test.AbstractDummyOpenemsComponent; +import io.openems.edge.controller.ess.emergencycapacityreserve.ControllerEssEmergencyCapacityReserve; +import io.openems.edge.controller.ess.limittotaldischarge.ControllerEssLimitTotalDischarge; +import io.openems.edge.controller.ess.timeofusetariff.StateMachine; +import io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImpl; +import io.openems.edge.energy.EnergySchedulerImplTest; +import io.openems.edge.energy.optimizer.Simulator.Period; +import io.openems.edge.timedata.test.DummyTimedata; + +public class UtilsTest { + + protected static ImmutableSortedMap prepareExistingSchedule(ZonedDateTime fromDate, + StateMachine... existingSchedule) { + return IntStream.range(0, existingSchedule.length) // + .mapToObj(Integer::valueOf) // + .collect(ImmutableSortedMap.toImmutableSortedMap( + ZonedDateTime::compareTo, // + i -> fromDate.plusMinutes(i * 15), // + i -> existingSchedule[i])); + } + + @Test + public void testInterpolateArrayFloat() { + assertArrayEquals(new double[] { 123, 123, 234, 234, 345 }, // + interpolateArray(new Double[] { null, 123., 234., null, 345., null }), // + 0.0001F); + + assertArrayEquals(new double[] {}, // + interpolateArray(new Double[] { null }), // + 0.0001F); + } + + @Test + public void testInterpolateArrayInteger() { + assertArrayEquals(new int[] { 123, 123, 234, 234, 345 }, // + interpolateArray(new Integer[] { null, 123, 234, null, 345, null })); + + assertArrayEquals(new int[] {}, // + interpolateArray(new Integer[] { null })); + + assertArrayEquals(new int[] { 123, 123 }, // + interpolateArray(new Integer[] { null, 123 })); + + assertArrayEquals(new int[] { 123 }, // + interpolateArray(new Integer[] { 123, null })); + } + + @Test + public void testToPower() { + assertEquals(2000, (int) toPower(500)); + assertNull(toPower(null)); + } + + @Test + public void testGenerateProductionPrediction() { + final var arr = new Integer[] { 1, 2, 3 }; + assertArrayEquals(arr, generateProductionPrediction(arr, 2)); + assertArrayEquals(new Integer[] { 1, 2, 3, 0 }, generateProductionPrediction(arr, 4)); + } + + @Test + public void testJoinConsumptionPredictions() { + assertArrayEquals(// + new Integer[] { 1, 2, 3, 4, 55, 66, 77, 88, 99 }, // + joinConsumptionPredictions(4, // + new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, // + new Integer[] { 11, 22, 33, 44, 55, 66, 77, 88, 99 })); + } + + @Test + public void testFindFirstPeakIndex() { + assertEquals(0, findFirstPeakIndex(0, new double[0])); + assertEquals(0, findFirstPeakIndex(0, new double[] { 1 })); + assertEquals(0, findFirstPeakIndex(0, new double[] { 1, 0 })); + assertEquals(1, findFirstPeakIndex(0, new double[] { 0, 1, 0 })); + assertEquals(1, findFirstPeakIndex(0, new double[] { 0, 1, 0, 1 })); + assertEquals(5, findFirstPeakIndex(5, new double[0])); + } + + @Test + public void testFindFirstValleyIndex() { + assertEquals(0, findFirstValleyIndex(0, new double[0])); + assertEquals(0, findFirstValleyIndex(0, new double[] { 1 })); + assertEquals(1, findFirstValleyIndex(0, new double[] { 1, 0 })); + assertEquals(0, findFirstValleyIndex(0, new double[] { 0, 1, 0 })); + assertEquals(2, findFirstValleyIndex(1, new double[] { 0, 1, 0, 1 })); + assertEquals(5, findFirstValleyIndex(5, new double[0])); + } + + @Test + public void testParamsAreValid() throws Exception { + var builder = Params.create() // + .setTime(TIME) // + .setEssInitialEnergy(0) // + .setEssTotalEnergy(22000) // + .setEssMinSocEnergy(2_000) // + .setEssMaxSocEnergy(20_000) // + .seMaxBuyFromGrid(toEnergy(24_000)) // + .seMaxBuyFromGrid(0) // + .setStates(new StateMachine[0]); + + // No periods are available + assertFalse(paramsAreValid(builder // + .setProductions() // + .setConsumptions() // + .setPrices() // + .build())); + + // Production and Consumption predictions are all zero + assertFalse(paramsAreValid(builder // + .setProductions(0, 0, 0) // + .setConsumptions(0, 0) // + .setPrices(123F) // + .build())); + + // Prices are all the same + assertFalse(paramsAreValid(builder // + .setProductions(0, 1, 3) // + .setConsumptions(0, 2) // + .setPrices(123F, 123F) // + .build())); + + // Finally got it right... + assertTrue(paramsAreValid(builder // + .setProductions(0, 1, 3) // + .setConsumptions(0, 2) // + .setPrices(123F, 124F) // + .build())); + assertEquals(2, builder.build().optimizePeriods().size()); + } + + private static class MyControllerEssLimitTotalDischarge + extends AbstractDummyOpenemsComponent + implements ControllerEssLimitTotalDischarge { + + protected MyControllerEssLimitTotalDischarge(Integer minSoc) { + super("ctrl0", // + OpenemsComponent.ChannelId.values(), // + ControllerEssLimitTotalDischarge.ChannelId.values() // + ); + withValue(this.getMinSocChannel(), minSoc); + } + + @Override + public void run() throws OpenemsNamedException { + } + + @Override + protected MyControllerEssLimitTotalDischarge self() { + return this; + } + } + + private static class MyControllerEssEmergencyCapacityReserve + extends AbstractDummyOpenemsComponent + implements ControllerEssEmergencyCapacityReserve { + + protected MyControllerEssEmergencyCapacityReserve(Integer reserveSoc) { + super("ctrl0", // + OpenemsComponent.ChannelId.values(), // + ControllerEssEmergencyCapacityReserve.ChannelId.values() // + ); + withValue(this.getActualReserveSocChannel(), reserveSoc); + } + + @Override + public void run() throws OpenemsNamedException { + } + + @Override + protected MyControllerEssEmergencyCapacityReserve self() { + return this; + } + } + + @Test + public void testGetEssMinSocEnergy() { + var t1 = new MyControllerEssLimitTotalDischarge(50); + var t2 = new MyControllerEssLimitTotalDischarge(null); + var t3 = new MyControllerEssEmergencyCapacityReserve(30); + assertEquals(5000, getEssMinSocEnergy( + new TimeOfUseTariffControllerImpl.Context(List.of(t3), List.of(t1, t2), null, null, 10000, false), + 10000)); + } + + @Test + public void testHandleScheduleRequest() throws Exception { + final var clock = new TimeLeapClock(Instant.parse("2020-03-04T14:19:00.00Z"), ZoneOffset.UTC); + final var energyScheduler = EnergySchedulerImplTest.create(clock); + + // Simulate historic data + var now = roundDownToQuarter(ZonedDateTime.now(clock)); + final var fromDate = now.minusHours(3); + var timedata = new DummyTimedata("timedata0"); + for (var i = 0; i < 12; i++) { + var quarter = fromDate.plusMinutes(i * 15); + timedata.add(quarter, new ChannelAddress("ctrl0", "QuarterlyPrices"), PAST_HOURLY_PRICES[i]); + timedata.add(quarter, new ChannelAddress("ctrl0", "StateMachine"), PAST_STATES[i]); + timedata.add(quarter, SUM_PRODUCTION, PRODUCTION_PREDICTION_QUARTERLY[i]); + timedata.add(quarter, SUM_CONSUMPTION, CONSUMPTION_PREDICTION_QUARTERLY[i]); + timedata.add(quarter, SUM_ESS_SOC, PAST_SOC[i]); + timedata.add(quarter, SUM_ESS_DISCHARGE_POWER, PRODUCTION_888_20231106[i]); + timedata.add(quarter, SUM_GRID, PRODUCTION_888_20231106[i]); + } + + var optimizer = getOptimizer(energyScheduler); + System.out.println(optimizer); + // TODO this requires a fully configured TimeOfUseTariffControllerImpl + // callCreateParams(optimizer); + // + // // Testing only past data. For full data, optimizer has to be created as + // well. + // var result = handleGetScheduleRequest(optimizer, getNilUuid(), timedata, + // "ctrl0", clock.now()).getResult(); + // + // // JsonUtils.prettyPrint(result); + // + // var schedule = getAsJsonArray(result, "schedule"); + // assertEquals(11, schedule.size()); + // { + // var period = getAsJsonObject(schedule.get(0)); + // assertEquals(PAST_HOURLY_PRICES[0], getAsFloat(period, "price"), 0.00F); + // assertEquals(PRODUCTION_PREDICTION_QUARTERLY[0] / 4, getAsInt(period, + // "production")); + // } + } + + @Test + public void testCalculateExecutionLimitSeconds() { + final var clock = new TimeLeapClock(Instant.parse("2022-01-01T00:00:00.00Z"), ZoneOffset.UTC); + assertEquals(Duration.ofMinutes(14).plusSeconds(30).toSeconds(), calculateExecutionLimitSeconds(clock)); + + clock.leap(11, ChronoUnit.MINUTES); + assertEquals(Duration.ofMinutes(3).plusSeconds(30).toSeconds(), calculateExecutionLimitSeconds(clock)); + + clock.leap(150, ChronoUnit.SECONDS); + assertEquals(60, calculateExecutionLimitSeconds(clock)); + + clock.leap(1, ChronoUnit.SECONDS); + assertEquals(Duration.ofMinutes(15).plusSeconds(59).toSeconds(), calculateExecutionLimitSeconds(clock)); + } + + @Test + public void testUpdateSchedule() { + final ZonedDateTime t = ZonedDateTime.of(2000, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC")); + final Period pOld = new Period(null, DELAY_DISCHARGE, 0, NO_FLOW); + final Period pNew = new Period(null, BALANCING, 0, NO_FLOW); + + var schedule = new TreeMap(); + schedule.put(t.minusMinutes(15), pOld); // old entry is removed + schedule.put(t, pOld); // current entry stays + schedule.put(t.plusMinutes(15), pOld); // is overridden + schedule.put(t.plusMinutes(30), pOld); // is overridden + schedule.put(t.plusMinutes(45), pOld); // timestamp is missing in new Schedule -> remove + + var newSchedule = ImmutableSortedMap.naturalOrder() // + .put(t, pNew) // + .put(t.plusMinutes(15), pNew) // + .put(t.plusMinutes(30), pNew) // + .build(); + + updateSchedule(t, schedule, newSchedule); + + // One old entry + assertEquals(1, schedule.values().stream().filter(v -> v == pOld).count()); + + // Two new entries + assertEquals(2, schedule.values().stream().filter(v -> v == pNew).count()); + + // No old entry + assertEquals(0, schedule.keySet().stream().filter(tz -> tz.isBefore(t)).count()); + + // Details + assertEquals(pOld, schedule.get(t)); + assertEquals(pNew, schedule.get(t.plusMinutes(15))); + assertEquals(pNew, schedule.get(t.plusMinutes(30))); + + // No current entry -> handle null + schedule.remove(t); + updateSchedule(t, schedule, newSchedule); + } +} diff --git a/io.openems.edge.ess.adstec.storaxe/src/io/openems/edge/ess/adstec/storaxe/EssAdstecStoraxeImpl.java b/io.openems.edge.ess.adstec.storaxe/src/io/openems/edge/ess/adstec/storaxe/EssAdstecStoraxeImpl.java index 9ad0862dfd1..6a045d2e415 100644 --- a/io.openems.edge.ess.adstec.storaxe/src/io/openems/edge/ess/adstec/storaxe/EssAdstecStoraxeImpl.java +++ b/io.openems.edge.ess.adstec.storaxe/src/io/openems/edge/ess/adstec/storaxe/EssAdstecStoraxeImpl.java @@ -80,7 +80,7 @@ protected void deactivate() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { final var offset = -1; // The Modbus library seems to use 0 offsets. // We need to override because the ess returns neg for capacitative, pos for diff --git a/io.openems.edge.ess.byd.container/src/io/openems/edge/ess/byd/container/EssFeneconBydContainerImpl.java b/io.openems.edge.ess.byd.container/src/io/openems/edge/ess/byd/container/EssFeneconBydContainerImpl.java index 58dee2ba3aa..621bbca994a 100644 --- a/io.openems.edge.ess.byd.container/src/io/openems/edge/ess/byd/container/EssFeneconBydContainerImpl.java +++ b/io.openems.edge.ess.byd.container/src/io/openems/edge/ess/byd/container/EssFeneconBydContainerImpl.java @@ -220,7 +220,7 @@ public Constraint[] getStaticConstraints() throws OpenemsNamedException { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this, new FC3ReadRegistersTask(0x1001, Priority.LOW, // TODO check each channels id's for scaling factor m(EssFeneconBydContainer.ChannelId.PCS_SYSTEM_WORKSTATE, new UnsignedWordElement(0x1001)), @@ -496,7 +496,7 @@ protected ModbusProtocol defineModbusProtocol() throws OpenemsException { ))); } - private ModbusProtocol defineModbus1Protocol() throws OpenemsException { + private ModbusProtocol defineModbus1Protocol() { return new ModbusProtocol(this, new FC3ReadRegistersTask(0x3410, Priority.LOW, m(EssFeneconBydContainer.ChannelId.CONTAINER_IMMERSION_STATE, new UnsignedWordElement(0x3410)), @@ -570,7 +570,7 @@ private ModbusProtocol defineModbus1Protocol() throws OpenemsException { ))); } - protected ModbusProtocol defineModbus2Protocol() throws OpenemsException { + protected ModbusProtocol defineModbus2Protocol() { return new ModbusProtocol(this, new FC3ReadRegistersTask(0x38A0, Priority.LOW, // // RTU registers m(EssFeneconBydContainer.ChannelId.SYSTEM_WORKSTATE, new UnsignedWordElement(0x38A0)), diff --git a/io.openems.edge.ess.fenecon.commercial40/src/io/openems/edge/ess/fenecon/commercial40/EssFeneconCommercial40Impl.java b/io.openems.edge.ess.fenecon.commercial40/src/io/openems/edge/ess/fenecon/commercial40/EssFeneconCommercial40Impl.java index 6db503707f7..e4582a1474a 100644 --- a/io.openems.edge.ess.fenecon.commercial40/src/io/openems/edge/ess/fenecon/commercial40/EssFeneconCommercial40Impl.java +++ b/io.openems.edge.ess.fenecon.commercial40/src/io/openems/edge/ess/fenecon/commercial40/EssFeneconCommercial40Impl.java @@ -166,7 +166,7 @@ public String getModbusBridgeId() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this, // new FC3ReadRegistersTask(0x0101, Priority.LOW, // m(EssFeneconCommercial40.ChannelId.SYSTEM_STATE, new UnsignedWordElement(0x0101)), diff --git a/io.openems.edge.ess.fenecon.commercial40/src/io/openems/edge/ess/fenecon/commercial40/charger/AbstractEssFeneconCommercial40Pv.java b/io.openems.edge.ess.fenecon.commercial40/src/io/openems/edge/ess/fenecon/commercial40/charger/AbstractEssFeneconCommercial40Pv.java index 01efbb553d7..b55b0b549ca 100644 --- a/io.openems.edge.ess.fenecon.commercial40/src/io/openems/edge/ess/fenecon/commercial40/charger/AbstractEssFeneconCommercial40Pv.java +++ b/io.openems.edge.ess.fenecon.commercial40/src/io/openems/edge/ess/fenecon/commercial40/charger/AbstractEssFeneconCommercial40Pv.java @@ -6,7 +6,6 @@ import org.osgi.service.event.EventHandler; import io.openems.common.channel.AccessMode; -import io.openems.common.exceptions.OpenemsException; import io.openems.edge.bridge.modbus.api.AbstractOpenemsModbusComponent; import io.openems.edge.bridge.modbus.api.ModbusComponent; import io.openems.edge.bridge.modbus.api.ModbusProtocol; @@ -52,7 +51,7 @@ public AbstractEssFeneconCommercial40Pv() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { var protocol = new ModbusProtocol(this, // new FC16WriteRegistersTask(0x0503, // m(EssFeneconCommercial40Pv.ChannelId.SET_PV_POWER_LIMIT, new UnsignedWordElement(0x0503), diff --git a/io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/GridconPcsImpl.java b/io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/GridconPcsImpl.java index e70b13d4ba9..22a1f17994b 100644 --- a/io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/GridconPcsImpl.java +++ b/io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/GridconPcsImpl.java @@ -22,7 +22,6 @@ import org.slf4j.LoggerFactory; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.exceptions.OpenemsException; import io.openems.edge.bridge.modbus.api.AbstractOpenemsModbusComponent; import io.openems.edge.bridge.modbus.api.BridgeModbus; import io.openems.edge.bridge.modbus.api.ModbusComponent; @@ -382,7 +381,7 @@ protected void writeDcDcControlCommandWord() throws IllegalArgumentException, Op } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { int inverterCount = this.inverterCount.getCount(); ModbusProtocol result = new ModbusProtocol(this, // diff --git a/io.openems.edge.ess.sma/src/io/openems/edge/sma/sunnyisland/EssSmaSunnyIslandImpl.java b/io.openems.edge.ess.sma/src/io/openems/edge/sma/sunnyisland/EssSmaSunnyIslandImpl.java index feca1e58f8a..49513f81dc0 100644 --- a/io.openems.edge.ess.sma/src/io/openems/edge/sma/sunnyisland/EssSmaSunnyIslandImpl.java +++ b/io.openems.edge.ess.sma/src/io/openems/edge/sma/sunnyisland/EssSmaSunnyIslandImpl.java @@ -153,7 +153,7 @@ public void applyPower(int activePowerL1, int reactivePowerL1, int activePowerL2 } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this, // new FC3ReadRegistersTask(30051, Priority.LOW, // m(EssSmaSunnyIsland.ChannelId.DEVICE_CLASS, new UnsignedDoublewordElement(30051)), // diff --git a/io.openems.edge.evcs.alpitronic.hypercharger/src/io/openems/edge/evcs/hypercharger/EvcsAlpitronicHyperchargerImpl.java b/io.openems.edge.evcs.alpitronic.hypercharger/src/io/openems/edge/evcs/hypercharger/EvcsAlpitronicHyperchargerImpl.java index c3442232ad9..0dec8b68dad 100644 --- a/io.openems.edge.evcs.alpitronic.hypercharger/src/io/openems/edge/evcs/hypercharger/EvcsAlpitronicHyperchargerImpl.java +++ b/io.openems.edge.evcs.alpitronic.hypercharger/src/io/openems/edge/evcs/hypercharger/EvcsAlpitronicHyperchargerImpl.java @@ -170,7 +170,7 @@ public void handleEvent(Event event) { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { var modbusProtocol = new ModbusProtocol(this, new FC3ReadRegistersTask(this.offset.apply(0), Priority.LOW, diff --git a/io.openems.edge.evcs.spelsberg/src/io/openems/edge/evcs/spelsberg/smart/EvcsSpelsbergSmartImpl.java b/io.openems.edge.evcs.spelsberg/src/io/openems/edge/evcs/spelsberg/smart/EvcsSpelsbergSmartImpl.java index aad3dc375e8..71e6df3342a 100644 --- a/io.openems.edge.evcs.spelsberg/src/io/openems/edge/evcs/spelsberg/smart/EvcsSpelsbergSmartImpl.java +++ b/io.openems.edge.evcs.spelsberg/src/io/openems/edge/evcs/spelsberg/smart/EvcsSpelsbergSmartImpl.java @@ -116,7 +116,7 @@ protected void deactivate() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { final var modbusProtocol = new ModbusProtocol(this, new FC3ReadRegistersTask(1000, Priority.HIGH, m(EvcsSpelsbergSmart.ChannelId.CHARGE_POINT_STATE, new UnsignedWordElement(1000)), diff --git a/io.openems.edge.evcs.webasto.next/src/io/openems/edge/evcs/webasto/next/EvcsWebastoNextImpl.java b/io.openems.edge.evcs.webasto.next/src/io/openems/edge/evcs/webasto/next/EvcsWebastoNextImpl.java index fb56b811741..d57c72553c9 100644 --- a/io.openems.edge.evcs.webasto.next/src/io/openems/edge/evcs/webasto/next/EvcsWebastoNextImpl.java +++ b/io.openems.edge.evcs.webasto.next/src/io/openems/edge/evcs/webasto/next/EvcsWebastoNextImpl.java @@ -139,7 +139,7 @@ private void applyConfig(ComponentContext context, Config config) { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { // Cannot read the gaps, therefore there are so many tasks var modbusProtocol = new ModbusProtocol(this, // new FC3ReadRegistersTask(1000, Priority.HIGH, diff --git a/io.openems.edge.evcs.webasto.unite/src/io/openems/edge/evcs/webasto/unite/EvcsWebastoUniteImpl.java b/io.openems.edge.evcs.webasto.unite/src/io/openems/edge/evcs/webasto/unite/EvcsWebastoUniteImpl.java index 3a144fd5797..8c0d5a821f6 100644 --- a/io.openems.edge.evcs.webasto.unite/src/io/openems/edge/evcs/webasto/unite/EvcsWebastoUniteImpl.java +++ b/io.openems.edge.evcs.webasto.unite/src/io/openems/edge/evcs/webasto/unite/EvcsWebastoUniteImpl.java @@ -114,7 +114,7 @@ protected void setModbus(BridgeModbus modbus) { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { /* * The Webasto Unite does not support reading Multiple Registers in one task * with "gaps" in between. Therefore, this modbus protocol consists of many diff --git a/io.openems.edge.fenecon.dess/src/io/openems/edge/fenecon/dess/charger/AbstractFeneconDessCharger.java b/io.openems.edge.fenecon.dess/src/io/openems/edge/fenecon/dess/charger/AbstractFeneconDessCharger.java index cf21f3796e3..638976fc8f3 100644 --- a/io.openems.edge.fenecon.dess/src/io/openems/edge/fenecon/dess/charger/AbstractFeneconDessCharger.java +++ b/io.openems.edge.fenecon.dess/src/io/openems/edge/fenecon/dess/charger/AbstractFeneconDessCharger.java @@ -6,7 +6,6 @@ import org.osgi.service.event.EventHandler; import io.openems.common.channel.AccessMode; -import io.openems.common.exceptions.OpenemsException; import io.openems.edge.bridge.modbus.api.AbstractOpenemsModbusComponent; import io.openems.edge.bridge.modbus.api.ModbusComponent; import io.openems.edge.bridge.modbus.api.ModbusProtocol; @@ -41,7 +40,7 @@ public AbstractFeneconDessCharger() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { final var offset = this.getOffset(); return new ModbusProtocol(this, // new FC3ReadRegistersTask(offset + 2, Priority.LOW, // diff --git a/io.openems.edge.fenecon.dess/src/io/openems/edge/fenecon/dess/ess/FeneconDessEssImpl.java b/io.openems.edge.fenecon.dess/src/io/openems/edge/fenecon/dess/ess/FeneconDessEssImpl.java index e6ff71b8885..cfe3251c770 100644 --- a/io.openems.edge.fenecon.dess/src/io/openems/edge/fenecon/dess/ess/FeneconDessEssImpl.java +++ b/io.openems.edge.fenecon.dess/src/io/openems/edge/fenecon/dess/ess/FeneconDessEssImpl.java @@ -115,7 +115,7 @@ protected void deactivate() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this, // new FC3ReadRegistersTask(10000, Priority.LOW, // m(FeneconDessEss.ChannelId.SYSTEM_STATE, new UnsignedWordElement(10000)), // diff --git a/io.openems.edge.fenecon.dess/src/io/openems/edge/fenecon/dess/gridmeter/FeneconDessGridMeterImpl.java b/io.openems.edge.fenecon.dess/src/io/openems/edge/fenecon/dess/gridmeter/FeneconDessGridMeterImpl.java index 5e0a1ff2cc5..39580294e38 100644 --- a/io.openems.edge.fenecon.dess/src/io/openems/edge/fenecon/dess/gridmeter/FeneconDessGridMeterImpl.java +++ b/io.openems.edge.fenecon.dess/src/io/openems/edge/fenecon/dess/gridmeter/FeneconDessGridMeterImpl.java @@ -98,7 +98,7 @@ protected void deactivate() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this, // new FC3ReadRegistersTask(11109, Priority.LOW, // m(FeneconDessGridMeter.ChannelId.ORIGINAL_ACTIVE_CONSUMPTION_ENERGY, diff --git a/io.openems.edge.fenecon.dess/src/io/openems/edge/fenecon/dess/pvmeter/FeneconDessPvMeterImpl.java b/io.openems.edge.fenecon.dess/src/io/openems/edge/fenecon/dess/pvmeter/FeneconDessPvMeterImpl.java index 676206cac33..e9fc1e27ddf 100644 --- a/io.openems.edge.fenecon.dess/src/io/openems/edge/fenecon/dess/pvmeter/FeneconDessPvMeterImpl.java +++ b/io.openems.edge.fenecon.dess/src/io/openems/edge/fenecon/dess/pvmeter/FeneconDessPvMeterImpl.java @@ -89,7 +89,7 @@ protected void deactivate() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this, // new FC3ReadRegistersTask(11144, Priority.HIGH, // m(ElectricityMeter.ChannelId.ACTIVE_POWER_L1, new UnsignedWordElement(11144), DELTA_10000)), // 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 29075f57aa6..397b253f49d 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 @@ -170,7 +170,7 @@ public SinglePhase getPhase() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this, // new FC3ReadRegistersTask(100, Priority.LOW, // m(FeneconMiniEss.ChannelId.SYSTEM_STATE, new UnsignedWordElement(100)), // diff --git a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/gridmeter/FeneconMiniGridMeterImpl.java b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/gridmeter/FeneconMiniGridMeterImpl.java index 33852c82a7e..9968e9c6e59 100644 --- a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/gridmeter/FeneconMiniGridMeterImpl.java +++ b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/gridmeter/FeneconMiniGridMeterImpl.java @@ -92,7 +92,7 @@ protected void deactivate() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this, // new FC3ReadRegistersTask(4004, Priority.HIGH, // m(ElectricityMeter.ChannelId.ACTIVE_POWER, new SignedWordElement(4004), diff --git a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/pvmeter/FeneconMiniPvMeterImpl.java b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/pvmeter/FeneconMiniPvMeterImpl.java index d382325cb7e..009311b915e 100644 --- a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/pvmeter/FeneconMiniPvMeterImpl.java +++ b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/pvmeter/FeneconMiniPvMeterImpl.java @@ -88,7 +88,7 @@ protected void deactivate() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this, // new FC3ReadRegistersTask(4006, Priority.HIGH, // m(ElectricityMeter.ChannelId.ACTIVE_POWER, new UnsignedWordElement(4006)))); diff --git a/io.openems.edge.fenecon.pro/src/io/openems/edge/fenecon/pro/ess/FeneconProEssImpl.java b/io.openems.edge.fenecon.pro/src/io/openems/edge/fenecon/pro/ess/FeneconProEssImpl.java index 66bd61011ea..7b49c117c15 100644 --- a/io.openems.edge.fenecon.pro/src/io/openems/edge/fenecon/pro/ess/FeneconProEssImpl.java +++ b/io.openems.edge.fenecon.pro/src/io/openems/edge/fenecon/pro/ess/FeneconProEssImpl.java @@ -135,7 +135,7 @@ public String getModbusBridgeId() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this, // new FC3ReadRegistersTask(100, Priority.HIGH, // m(FeneconProEss.ChannelId.SYSTEM_STATE, new UnsignedWordElement(100)), // diff --git a/io.openems.edge.fenecon.pro/src/io/openems/edge/fenecon/pro/pvmeter/FeneconProPvMeterImpl.java b/io.openems.edge.fenecon.pro/src/io/openems/edge/fenecon/pro/pvmeter/FeneconProPvMeterImpl.java index 61837c0e395..896686de264 100644 --- a/io.openems.edge.fenecon.pro/src/io/openems/edge/fenecon/pro/pvmeter/FeneconProPvMeterImpl.java +++ b/io.openems.edge.fenecon.pro/src/io/openems/edge/fenecon/pro/pvmeter/FeneconProPvMeterImpl.java @@ -92,7 +92,7 @@ public String getModbusBridgeId() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this, // new FC3ReadRegistersTask(121, Priority.LOW, // m(ElectricityMeter.ChannelId.VOLTAGE_L1, new UnsignedWordElement(121), SCALE_FACTOR_2), // diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverterImpl.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverterImpl.java index c20446244e5..8dec660e38a 100644 --- a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverterImpl.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverterImpl.java @@ -312,8 +312,8 @@ private void setBatteryLimits(Battery battery) throws OpenemsNamedException { var setBatteryStrings = TypeUtils.divide(battery.getDischargeMinVoltage().get(), MODULE_MIN_VOLTAGE); var setChargeMaxCurrent = this.getGoodweType().maxDcCurrent; var setDischargeMaxCurrent = this.getGoodweType().maxDcCurrent; - var setChargeMaxVoltage = battery.getChargeMaxVoltage().orElse(0); - var setDischargeMinVoltage = battery.getDischargeMinVoltage().orElse(0); + var setChargeMaxVoltage = battery.getChargeMaxVoltage().orElse(210); + var setDischargeMinVoltage = battery.getDischargeMinVoltage().orElse(210); Integer setSocUnderMin = 0; // [0-100]; 0 MinSoc = 100 DoD Integer setOfflineSocUnderMin = 0; // [0-100]; 0 MinSoc = 100 DoD @@ -336,6 +336,9 @@ private void setBatteryLimits(Battery battery) throws OpenemsNamedException { } } + /* + * Check correct BMS register values. Goodwe recommends setting the values once + */ if (bmsChargeMaxCurrent.isDefined() && !Objects.equals(bmsChargeMaxCurrent.get(), setChargeMaxCurrent) || bmsDischargeMaxCurrent.isDefined() && !Objects.equals(bmsDischargeMaxCurrent.get(), setDischargeMaxCurrent) @@ -365,6 +368,24 @@ private void setBatteryLimits(Battery battery) throws OpenemsNamedException { this.writeToChannel(GoodWe.ChannelId.BMS_OFFLINE_SOC_UNDER_MIN, setOfflineSocUnderMin); } + /* + * Check correct BMS register value for voltage. Handled separately to avoid + * sending other values multiple times if the voltage registers are not written + * immediately + */ + if (doSetBmsVoltage(battery, bmsChargeMaxVoltage, setChargeMaxVoltage, bmsDischargeMinVoltage, + setDischargeMinVoltage)) { + // Update is required + this.logInfo(this.log, "Update for BMS Registers." // + + " Voltages" // + + " [Discharge " + bmsDischargeMinVoltage.get() + " -> " + setDischargeMinVoltage + "]" // + + " [Charge " + bmsChargeMaxVoltage.get() + " -> " + setChargeMaxVoltage + + "]. This can take up to 10 minutes."); + + this.writeToChannel(GoodWe.ChannelId.BMS_CHARGE_MAX_VOLTAGE, setChargeMaxVoltage); + this.writeToChannel(GoodWe.ChannelId.BMS_DISCHARGE_MIN_VOLTAGE, setDischargeMinVoltage); + } + /* * Regularly write all WBMS Channels. */ @@ -398,6 +419,25 @@ private void setBatteryLimits(Battery battery) throws OpenemsNamedException { this.writeToChannel(GoodWe.ChannelId.WBMS_DISABLE_TIMEOUT_DETECTION, 0); } + protected static boolean doSetBmsVoltage(Battery battery, Value bmsChargeMaxVoltage, + Integer setChargeMaxVoltage, Value bmsDischargeMinVoltage, Integer setDischargeMinVoltage) { + if (!battery.getChargeMaxCurrent().isDefined() || !battery.getDischargeMaxCurrent().isDefined() + || !bmsChargeMaxVoltage.isDefined() || !bmsChargeMaxVoltage.isDefined()) { + // Do not set channels if input data is missing/not yet available + return false; + } + if (battery.getChargeMaxCurrent().get() == 0 || battery.getDischargeMaxCurrent().get() == 0) { + // Exclude times with full or empty battery, due to inverter mis-behaviour + return false; + } + if (Objects.equals(bmsChargeMaxVoltage.get(), setChargeMaxVoltage) + && Objects.equals(bmsDischargeMinVoltage.get(), setDischargeMinVoltage)) { + // Values are already set + return false; + } + return true; + } + /** * Set general values. * diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/AbstractGoodWeEtCharger.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/AbstractGoodWeEtCharger.java index 9d04b476aad..cf6d669406e 100644 --- a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/AbstractGoodWeEtCharger.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/AbstractGoodWeEtCharger.java @@ -6,7 +6,6 @@ import org.osgi.service.event.EventHandler; import io.openems.common.channel.AccessMode; -import io.openems.common.exceptions.OpenemsException; import io.openems.edge.bridge.modbus.api.AbstractOpenemsModbusComponent; import io.openems.edge.bridge.modbus.api.ModbusComponent; import io.openems.edge.bridge.modbus.api.ModbusProtocol; @@ -47,7 +46,7 @@ protected AbstractGoodWeEtCharger(io.openems.edge.common.channel.ChannelId[] fir } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { final var startAddress = this.getStartAddress(); return new ModbusProtocol(this, // new FC3ReadRegistersTask(startAddress, Priority.HIGH, // diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/mppt/twostring/Config.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/mppt/twostring/Config.java new file mode 100644 index 00000000000..08ab8878666 --- /dev/null +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/mppt/twostring/Config.java @@ -0,0 +1,30 @@ +package io.openems.edge.goodwe.charger.mppt.twostring; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +@ObjectClassDefinition(// + name = "GoodWe Charger MPPT Two-String", // + description = "Implements the GoodWe-ET MPPT with two strings as one Charger.") + +@interface Config { + @AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component") + String id() default "charger0"; + + @AttributeDefinition(name = "Alias", description = "Human-readable name of this Component; defaults to Component-ID") + String alias() default ""; + + @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?") + boolean enabled() default true; + + @AttributeDefinition(name = "Used MPPT", description = "MPPT port that is used with one or two strings") + MpptPort mpptPort() default MpptPort.MPPT_1; + + @AttributeDefinition(name = "GoodWe ESS or Battery-Inverter", description = "ID of GoodWe Energy Storage System or Battery-Inverter.") + String essOrBatteryInverter_id() default "batteryInverter0"; + + @AttributeDefinition(name = "GoodWe ESS or Battery-Inverter target filter", description = "This is auto-generated by 'GoodWe ESS or Battery-Inverter'.") + String essOrBatteryInverter_target() default "(enabled=true)"; + + String webconsole_configurationFactory_nameHint() default "GoodWe Charger MPPT Two-String [{id}]"; +} diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/mppt/twostring/GoodWeChargerMpptTwoStringImpl.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/mppt/twostring/GoodWeChargerMpptTwoStringImpl.java new file mode 100644 index 00000000000..b6efa0f10c0 --- /dev/null +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/mppt/twostring/GoodWeChargerMpptTwoStringImpl.java @@ -0,0 +1,247 @@ +package io.openems.edge.goodwe.charger.mppt.twostring; + +import java.util.Optional; +import java.util.function.Consumer; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventHandler; +import org.osgi.service.event.propertytypes.EventTopics; +import org.osgi.service.metatype.annotations.Designate; + +import io.openems.common.channel.AccessMode; +import io.openems.common.exceptions.OpenemsException; +import io.openems.common.types.ChannelAddress; +import io.openems.common.types.OpenemsType; +import io.openems.edge.bridge.modbus.api.ModbusComponent; +import io.openems.edge.common.channel.IntegerReadChannel; +import io.openems.edge.common.channel.value.Value; +import io.openems.edge.common.component.AbstractOpenemsComponent; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.event.EdgeEventConstants; +import io.openems.edge.common.modbusslave.ModbusSlave; +import io.openems.edge.common.modbusslave.ModbusSlaveTable; +import io.openems.edge.common.type.TypeUtils; +import io.openems.edge.ess.dccharger.api.EssDcCharger; +import io.openems.edge.goodwe.charger.GoodWeCharger; +import io.openems.edge.goodwe.common.GoodWe; +import io.openems.edge.timedata.api.Timedata; +import io.openems.edge.timedata.api.TimedataProvider; +import io.openems.edge.timedata.api.utils.CalculateEnergyFromPower; + +@Designate(ocd = Config.class, factory = true) +@Component(// + name = "GoodWe.Charger.Mppt.Two-String", // + immediate = true, // + configurationPolicy = ConfigurationPolicy.REQUIRE // +) +@EventTopics({ // + EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE // +}) +public class GoodWeChargerMpptTwoStringImpl extends AbstractOpenemsComponent + implements EssDcCharger, GoodWeCharger, OpenemsComponent, EventHandler, TimedataProvider, ModbusSlave { + + private final CalculateEnergyFromPower calculateActualEnergy = new CalculateEnergyFromPower(this, + EssDcCharger.ChannelId.ACTUAL_ENERGY); + + private GoodWeListener currentListener; + private GoodWeListener powerListener; + private GoodWeListener voltageListener; + private Config config; + private boolean timedataQueryIsRunning = false; + + @Reference + private ConfigurationAdmin cm; + + @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) + private GoodWe essOrBatteryInverter; + + @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) + private volatile Timedata timedata = null; + + public GoodWeChargerMpptTwoStringImpl() { + super(// + OpenemsComponent.ChannelId.values(), // + ModbusComponent.ChannelId.values(), // + EssDcCharger.ChannelId.values(), // + GoodWeCharger.ChannelId.values() // + ); + } + + @Activate + private void activate(ComponentContext context, Config config) throws OpenemsException { + super.activate(context, config.id(), config.alias(), config.enabled()); + this.config = config; + + this.currentListener = new GoodWeListener(this, this.essOrBatteryInverter, + config.mpptPort().mpptCurrentChannelId, EssDcCharger.ChannelId.CURRENT); + this.powerListener = new GoodWeListener(this, this.essOrBatteryInverter, config.mpptPort().mpptPowerChannelId, + EssDcCharger.ChannelId.ACTUAL_POWER); + this.voltageListener = new GoodWeListener(this, this.essOrBatteryInverter, + config.mpptPort().mpptVoltageChannelId, EssDcCharger.ChannelId.VOLTAGE); + + this.essOrBatteryInverter.addCharger(this); + + if (OpenemsComponent.updateReferenceFilter(this.cm, this.servicePid(), "essOrBatteryInverter", + config.essOrBatteryInverter_id())) { + return; + } + } + + @Override + @Deactivate + protected void deactivate() { + this.essOrBatteryInverter.removeCharger(this); + this.currentListener.deactivate(); + this.powerListener.deactivate(); + this.voltageListener.deactivate(); + super.deactivate(); + } + + @Override + public void handleEvent(Event event) { + switch (event.getTopic()) { + case EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE: + this.calculateEnergy(); + break; + } + } + + @Override + public ModbusSlaveTable getModbusSlaveTable(AccessMode accessMode) { + return new ModbusSlaveTable(// + OpenemsComponent.getModbusSlaveNatureTable(accessMode), // + EssDcCharger.getModbusSlaveNatureTable(accessMode)); + } + + @Override + public Timedata getTimedata() { + return this.timedata; + } + + /** + * Calculate the Energy values from ActivePower. + */ + private void calculateEnergy() { + + if (!this.getActualEnergy().isDefined()) { + this.initializeCumulatedEnergyFromTimedata(); + return; + } + + var actualPower = this.getActualPower().get(); + if (actualPower == null) { + // Not available + this.calculateActualEnergy.update(null); + } else if (actualPower > 0) { + this.calculateActualEnergy.update(actualPower); + } else { + this.calculateActualEnergy.update(0); + } + } + + /** + * Initialize cumulated energy value from from Timedata service. + */ + private void initializeCumulatedEnergyFromTimedata() { + + final var actualEnergyChannel = EssDcCharger.ChannelId.ACTUAL_ENERGY; + var timedata = this.getTimedata(); + + if (timedata == null || this.timedataQueryIsRunning) { + return; + } + + this.timedataQueryIsRunning = true; + timedata.getLatestValue(new ChannelAddress(this.id(), actualEnergyChannel.id())).thenAccept(currentEnergy -> { + + if (currentEnergy.isEmpty()) { + + final String[] stringIds = switch (this.config.mpptPort()) { + case MPPT_1 -> new String[] { "charger0", "charger1" }; + case MPPT_2 -> new String[] { "charger2", "charger3" }; + case MPPT_3 -> new String[] { "charger4", "charger5" }; + }; + + /* + * Calculate total base energy from separate string energy values + */ + timedata.getLatestValueOfNotExistingChannel(new ChannelAddress(stringIds[0], actualEnergyChannel.id()), + actualEnergyChannel.doc().getUnit()) + .thenCombine(timedata.getLatestValueOfNotExistingChannel( + new ChannelAddress(stringIds[1], actualEnergyChannel.id()), + actualEnergyChannel.doc().getUnit()), (energyString1, energyString2) -> { + return caculateEnergyFromTwoStrings(energyString1, energyString2); + }) + .thenAccept(combinedEnergy -> { + this.channel(actualEnergyChannel).setNextValue(combinedEnergy); + this.calculateActualEnergy.setBaseEnergyManually(combinedEnergy); + }); + } else { + this.channel(actualEnergyChannel) + .setNextValue(TypeUtils.getAsType(OpenemsType.LONG, currentEnergy.get())); + } + }); + } + + /** + * Calculate energy from two given strings. + * + * @param energyString1Opt energy of string 1 + * @param energyString2Opt energy of string 2 + * @return total energy + */ + public static Long caculateEnergyFromTwoStrings(Optional energyString1Opt, + Optional energyString2Opt) { + long energyString1; + long energyString2; + + try { + energyString1 = TypeUtils.getAsType(OpenemsType.LONG, energyString1Opt.get()); + } catch (Exception e) { + energyString1 = 0L; + } + try { + energyString2 = TypeUtils.getAsType(OpenemsType.LONG, energyString2Opt.get()); + } catch (Exception e) { + energyString2 = 0L; + } + return TypeUtils.sum(energyString1, energyString2); + } + + @Override + public final String debugLog() { + return "L:" + this.getActualPower().asString(); + } + + private static class GoodWeListener implements Consumer> { + + private final IntegerReadChannel goodWeChannel; + private final IntegerReadChannel mirrorChannel; + + public GoodWeListener(GoodWeChargerMpptTwoStringImpl parent, GoodWe essOrBatteryInverter, + GoodWe.ChannelId goodWeChannel, io.openems.edge.common.channel.ChannelId mirrorChannel) { + this.goodWeChannel = essOrBatteryInverter.channel(goodWeChannel); + this.mirrorChannel = parent.channel(mirrorChannel); + this.goodWeChannel.onSetNextValue(this); + } + + public void deactivate() { + this.goodWeChannel.removeOnSetNextValueCallback(this); + } + + @Override + public void accept(Value t) { + this.mirrorChannel.setNextValue(t); + } + } +} diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/mppt/twostring/MpptPort.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/mppt/twostring/MpptPort.java new file mode 100644 index 00000000000..e61c6dbc63d --- /dev/null +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/mppt/twostring/MpptPort.java @@ -0,0 +1,24 @@ +package io.openems.edge.goodwe.charger.mppt.twostring; + +import io.openems.edge.goodwe.common.GoodWe; + +/** + * Defines the GoodWe MPPT with two Strings. + */ +public enum MpptPort { + + MPPT_1(GoodWe.ChannelId.MPPT1_P, GoodWe.ChannelId.MPPT1_I, GoodWe.ChannelId.TWO_S_PV1_V), // + MPPT_2(GoodWe.ChannelId.MPPT2_P, GoodWe.ChannelId.MPPT2_I, GoodWe.ChannelId.TWO_S_PV3_V), // + MPPT_3(GoodWe.ChannelId.MPPT3_P, GoodWe.ChannelId.MPPT3_I, GoodWe.ChannelId.TWO_S_PV5_V); // + + public final GoodWe.ChannelId mpptPowerChannelId; + public final GoodWe.ChannelId mpptCurrentChannelId; + public final GoodWe.ChannelId mpptVoltageChannelId; + + private MpptPort(GoodWe.ChannelId mpptPowerChannelId, GoodWe.ChannelId mpptCurrentChannelId, + GoodWe.ChannelId mpptVoltageChannelId) { + this.mpptPowerChannelId = mpptPowerChannelId; + this.mpptCurrentChannelId = mpptCurrentChannelId; + this.mpptVoltageChannelId = mpptVoltageChannelId; + } +} diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/twostring/Config.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/twostring/Config.java index 14288206959..941e35ba015 100644 --- a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/twostring/Config.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/twostring/Config.java @@ -7,6 +7,7 @@ name = "GoodWe Charger Two-String", // description = "Implements a GoodWe PV string (for an MPPT of two strings).") +@Deprecated @interface Config { @AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component") String id() default "charger0"; diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/twostring/GoodWeChargerTwoString.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/twostring/GoodWeChargerTwoString.java index adf81bff1cf..00e958794e8 100644 --- a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/twostring/GoodWeChargerTwoString.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/twostring/GoodWeChargerTwoString.java @@ -8,6 +8,7 @@ import io.openems.edge.ess.dccharger.api.EssDcCharger; import io.openems.edge.goodwe.charger.GoodWeCharger; +@Deprecated public interface GoodWeChargerTwoString extends OpenemsComponent, EssDcCharger, GoodWeCharger { public enum ChannelId implements io.openems.edge.common.channel.ChannelId { diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/twostring/GoodWeChargerTwoStringImpl.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/twostring/GoodWeChargerTwoStringImpl.java index 99d8632e405..3da7eca9664 100644 --- a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/twostring/GoodWeChargerTwoStringImpl.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/twostring/GoodWeChargerTwoStringImpl.java @@ -31,6 +31,21 @@ import io.openems.edge.timedata.api.TimedataProvider; import io.openems.edge.timedata.api.utils.CalculateEnergyFromPower; +/** + * {@link GoodWeChargerTwoStringImpl} was used to represent one string from a + * GoodWe MPPT tracker that is responsible for two strings (GoodWe ET-Systems). + * + *

+ * Possible values are: + *

  • MPPT Current + *
  • MPPT Power + *
  • String Current + *
  • String Voltage + * + *

    + * As the current values of one string are incorrect (so far DSP-Version 12, + * ARM-Version 27) the power cannot be calculated. + */ @Designate(ocd = Config.class, factory = true) @Component(// name = "GoodWe.Charger.Two-String", // @@ -40,6 +55,7 @@ @EventTopics({ // EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE // }) +@Deprecated public class GoodWeChargerTwoStringImpl extends AbstractOpenemsComponent implements GoodWeChargerTwoString, EssDcCharger, GoodWeCharger, OpenemsComponent, EventHandler, TimedataProvider, ModbusSlave { diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/twostring/PvPort.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/twostring/PvPort.java index 36edaca2fcc..e5c4f5e192c 100644 --- a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/twostring/PvPort.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/twostring/PvPort.java @@ -5,20 +5,21 @@ /** * Defines the PV-Port of a GoodWe Charger Two-String. */ +@Deprecated public enum PvPort { - PV_1(GoodWe.ChannelId.TWO_S_MPPT1_P, GoodWe.ChannelId.TWO_S_MPPT1_I, GoodWe.ChannelId.TWO_S_PV1_I, - GoodWe.ChannelId.TWO_S_PV2_I, GoodWe.ChannelId.TWO_S_PV1_V), - PV_2(GoodWe.ChannelId.TWO_S_MPPT1_P, GoodWe.ChannelId.TWO_S_MPPT1_I, GoodWe.ChannelId.TWO_S_PV2_I, - GoodWe.ChannelId.TWO_S_PV1_I, GoodWe.ChannelId.TWO_S_PV2_V), // - PV_3(GoodWe.ChannelId.TWO_S_MPPT2_P, GoodWe.ChannelId.TWO_S_MPPT2_I, GoodWe.ChannelId.TWO_S_PV3_I, - GoodWe.ChannelId.TWO_S_PV4_I, GoodWe.ChannelId.TWO_S_PV3_V), // - PV_4(GoodWe.ChannelId.TWO_S_MPPT2_P, GoodWe.ChannelId.TWO_S_MPPT2_I, GoodWe.ChannelId.TWO_S_PV4_I, - GoodWe.ChannelId.TWO_S_PV5_I, GoodWe.ChannelId.TWO_S_PV4_V), // - PV_5(GoodWe.ChannelId.TWO_S_MPPT3_P, GoodWe.ChannelId.TWO_S_MPPT3_I, GoodWe.ChannelId.TWO_S_PV5_I, - GoodWe.ChannelId.TWO_S_PV6_I, GoodWe.ChannelId.TWO_S_PV5_V), // - PV_6(GoodWe.ChannelId.TWO_S_MPPT3_P, GoodWe.ChannelId.TWO_S_MPPT3_I, GoodWe.ChannelId.TWO_S_PV6_I, - GoodWe.ChannelId.TWO_S_PV5_I, GoodWe.ChannelId.TWO_S_PV6_V); // + PV_1(GoodWe.ChannelId.MPPT1_P, GoodWe.ChannelId.MPPT1_I, GoodWe.ChannelId.TWO_S_PV1_I, GoodWe.ChannelId.TWO_S_PV2_I, + GoodWe.ChannelId.TWO_S_PV1_V), + PV_2(GoodWe.ChannelId.MPPT1_P, GoodWe.ChannelId.MPPT1_I, GoodWe.ChannelId.TWO_S_PV2_I, GoodWe.ChannelId.TWO_S_PV1_I, + GoodWe.ChannelId.TWO_S_PV2_V), // + PV_3(GoodWe.ChannelId.MPPT2_P, GoodWe.ChannelId.MPPT2_I, GoodWe.ChannelId.TWO_S_PV3_I, GoodWe.ChannelId.TWO_S_PV4_I, + GoodWe.ChannelId.TWO_S_PV3_V), // + PV_4(GoodWe.ChannelId.MPPT2_P, GoodWe.ChannelId.MPPT2_I, GoodWe.ChannelId.TWO_S_PV4_I, GoodWe.ChannelId.TWO_S_PV5_I, + GoodWe.ChannelId.TWO_S_PV4_V), // + PV_5(GoodWe.ChannelId.MPPT3_P, GoodWe.ChannelId.MPPT3_I, GoodWe.ChannelId.TWO_S_PV5_I, GoodWe.ChannelId.TWO_S_PV6_I, + GoodWe.ChannelId.TWO_S_PV5_V), // + PV_6(GoodWe.ChannelId.MPPT3_P, GoodWe.ChannelId.MPPT3_I, GoodWe.ChannelId.TWO_S_PV6_I, GoodWe.ChannelId.TWO_S_PV5_I, + GoodWe.ChannelId.TWO_S_PV6_V); // public final GoodWe.ChannelId mpptPowerChannelId; public final GoodWe.ChannelId mpptCurrentChannelId; diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/AbstractGoodWe.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/AbstractGoodWe.java index 7b0df783129..a35ad484323 100644 --- a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/AbstractGoodWe.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/AbstractGoodWe.java @@ -4,6 +4,7 @@ import static io.openems.edge.bridge.modbus.api.ElementToChannelConverter.SCALE_FACTOR_2; import static io.openems.edge.bridge.modbus.api.ElementToChannelConverter.SCALE_FACTOR_MINUS_1; import static io.openems.edge.bridge.modbus.api.ElementToChannelConverter.SCALE_FACTOR_MINUS_2; +import static io.openems.edge.bridge.modbus.api.ModbusUtils.readElementOnce; import java.util.HashSet; import java.util.Map; @@ -17,11 +18,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.openems.common.exceptions.NotImplementedException; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; import io.openems.common.types.OpenemsType; -import io.openems.edge.batteryinverter.api.HybridManagedSymmetricBatteryInverter; import io.openems.edge.bridge.modbus.api.AbstractOpenemsModbusComponent; import io.openems.edge.bridge.modbus.api.ChannelMetaInfoReadAndWrite; import io.openems.edge.bridge.modbus.api.ElementToChannelConverter; @@ -55,6 +54,7 @@ import io.openems.edge.timedata.api.TimedataProvider; import io.openems.edge.timedata.api.utils.CalculateEnergyFromPower; +@SuppressWarnings("deprecation") public abstract class AbstractGoodWe extends AbstractOpenemsModbusComponent implements GoodWe, OpenemsComponent, TimedataProvider, EventHandler { @@ -100,7 +100,7 @@ protected AbstractGoodWe(// } @Override - protected final ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected final ModbusProtocol defineModbusProtocol() { var protocol = new ModbusProtocol(this, // new FC3ReadRegistersTask(35001, Priority.LOW, // @@ -1183,7 +1183,7 @@ protected final ModbusProtocol defineModbusProtocol() throws OpenemsException { * Register 35011: GoodWeType as String (Not supported for GoodWe 20 & 30) * Register 35003: Serial number as String (Fallback for GoodWe 20 & 30) */ - ModbusUtils.readELementOnce(protocol, new StringWordElement(35011, 5), true) // + readElementOnce(protocol, ModbusUtils::retryOnNull, new StringWordElement(35011, 5)) // .thenAccept(value -> { /* @@ -1201,29 +1201,24 @@ protected final ModbusProtocol defineModbusProtocol() throws OpenemsException { /* * Evaluate GoodweType from serial number */ - try { - ModbusUtils.readELementOnce(protocol, new StringWordElement(35003, 8), true) // - .thenAccept(serialNr -> { - final var hardwareType = getGoodWeTypeFromSerialNr(serialNr); - try { - this._setGoodweType(hardwareType); - if (hardwareType == GoodWeType.FENECON_FHI_20_DAH - || hardwareType == GoodWeType.FENECON_FHI_29_9_DAH) { - this.handleMultipleStringChargers(protocol); - } - - } catch (OpenemsException e) { - this.logError(this.log, "Unable to add charger tasks for modbus protocol"); + readElementOnce(protocol, ModbusUtils::retryOnNull, new StringWordElement(35003, 8)) // + .thenAccept(serialNr -> { + final var hardwareType = getGoodWeTypeFromSerialNr(serialNr); + try { + this._setGoodweType(hardwareType); + if (hardwareType == GoodWeType.FENECON_FHI_20_DAH + || hardwareType == GoodWeType.FENECON_FHI_29_9_DAH) { + this.handleMultipleStringChargers(protocol); } - }); - } catch (OpenemsException e) { - this.logError(this.log, "Unable to read element for serial number"); - e.printStackTrace(); - } + + } catch (OpenemsException e) { + this.logError(this.log, "Unable to add charger tasks for modbus protocol"); + } + }); }); // Handles different DSP versions - ModbusUtils.readELementOnce(protocol, new UnsignedWordElement(35016), true) // + readElementOnce(protocol, ModbusUtils::retryOnNull, new UnsignedWordElement(35016)) // .thenAccept(dspVersion -> { try { @@ -1375,19 +1370,20 @@ private void handleMultipleStringChargers(ModbusProtocol protocol) throws Openem m(GoodWe.ChannelId.TWO_S_PV6_I, new UnsignedWordElement(35307), ElementToChannelConverter.SCALE_FACTOR_2), // new DummyRegisterElement(35308, 35336), - m(GoodWe.ChannelId.TWO_S_MPPT1_P, new UnsignedWordElement(35337)), - m(GoodWe.ChannelId.TWO_S_MPPT2_P, new UnsignedWordElement(35338)), - m(GoodWe.ChannelId.TWO_S_MPPT3_P, new UnsignedWordElement(35339)), + m(GoodWe.ChannelId.MPPT1_P, new UnsignedWordElement(35337)), + m(GoodWe.ChannelId.MPPT2_P, new UnsignedWordElement(35338)), + m(GoodWe.ChannelId.MPPT3_P, new UnsignedWordElement(35339)), new DummyRegisterElement(35340, 35344), // Power MPPT4 - MPPT8 - m(GoodWe.ChannelId.TWO_S_MPPT1_I, new UnsignedWordElement(35345), // + m(GoodWe.ChannelId.MPPT1_I, new UnsignedWordElement(35345), // ElementToChannelConverter.SCALE_FACTOR_2), - m(GoodWe.ChannelId.TWO_S_MPPT2_I, new UnsignedWordElement(35346), // + m(GoodWe.ChannelId.MPPT2_I, new UnsignedWordElement(35346), // ElementToChannelConverter.SCALE_FACTOR_2), - m(GoodWe.ChannelId.TWO_S_MPPT3_I, new UnsignedWordElement(35347), // + m(GoodWe.ChannelId.MPPT3_I, new UnsignedWordElement(35347), // ElementToChannelConverter.SCALE_FACTOR_2)) // ); } + // TODO: Can be removed when GoodWeChargerTwoStringImpl has been deleted private void setMultipleStringChannels() { this.chargers.stream() // @@ -1907,7 +1903,7 @@ private void handleDspVersion5(ModbusProtocol protocol) throws OpenemsException ); } - protected ModbusElement getSocModbusElement(int address) throws NotImplementedException { + protected ModbusElement getSocModbusElement(int address) { if (this instanceof HybridEss) { return m(SymmetricEss.ChannelId.SOC, new UnsignedWordElement(address), new ElementToChannelConverter( // element -> channel @@ -1923,11 +1919,9 @@ protected ModbusElement getSocModbusElement(int address) throws NotImplementedEx }, // channel -> element value -> value)); - } - if (this instanceof HybridManagedSymmetricBatteryInverter) { - return new DummyRegisterElement(address); + } else { - throw new NotImplementedException("Wrong implementation of AbstractGoodWe"); + return new DummyRegisterElement(address); } } diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/GoodWe.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/GoodWe.java index b4f33d3c86d..e5fff122fc3 100644 --- a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/GoodWe.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/GoodWe.java @@ -105,9 +105,9 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId * * MPPT1 */ - TWO_S_MPPT1_P(Doc.of(OpenemsType.INTEGER) // + MPPT1_P(Doc.of(OpenemsType.INTEGER) // .unit(Unit.WATT)), - TWO_S_MPPT1_I(Doc.of(OpenemsType.INTEGER) // + MPPT1_I(Doc.of(OpenemsType.INTEGER) // .unit(Unit.MILLIAMPERE)), // TWO_S_PV1_V(Doc.of(OpenemsType.INTEGER) // .unit(Unit.VOLT)), // @@ -120,9 +120,9 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId /* * MPPT2 */ - TWO_S_MPPT2_P(Doc.of(OpenemsType.INTEGER) // + MPPT2_P(Doc.of(OpenemsType.INTEGER) // .unit(Unit.WATT)), - TWO_S_MPPT2_I(Doc.of(OpenemsType.INTEGER) // + MPPT2_I(Doc.of(OpenemsType.INTEGER) // .unit(Unit.MILLIAMPERE)), // TWO_S_PV3_V(Doc.of(OpenemsType.INTEGER) // .unit(Unit.VOLT)), // @@ -135,9 +135,9 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId /* * MPPT3 */ - TWO_S_MPPT3_P(Doc.of(OpenemsType.INTEGER) // + MPPT3_P(Doc.of(OpenemsType.INTEGER) // .unit(Unit.WATT)), - TWO_S_MPPT3_I(Doc.of(OpenemsType.INTEGER) // + MPPT3_I(Doc.of(OpenemsType.INTEGER) // .unit(Unit.MILLIAMPERE)), // TWO_S_PV5_V(Doc.of(OpenemsType.INTEGER) // .unit(Unit.VOLT)), // @@ -194,7 +194,7 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId V_BATTERY1(Doc.of(OpenemsType.INTEGER) // .unit(Unit.VOLT)), // I_BATTERY1(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT)), // + .unit(Unit.AMPERE)), // P_BATTERY1(Doc.of(OpenemsType.INTEGER) // .unit(Unit.WATT)), // BATTERY_MODE(Doc.of(BatteryMode.values())), // diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/emergencypowermeter/GoodWeEmergencyPowerMeterImpl.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/emergencypowermeter/GoodWeEmergencyPowerMeterImpl.java index 9f0f6ed30f9..a9643334fc1 100644 --- a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/emergencypowermeter/GoodWeEmergencyPowerMeterImpl.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/emergencypowermeter/GoodWeEmergencyPowerMeterImpl.java @@ -100,7 +100,7 @@ protected void deactivate() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this, // // Power of each backup up phase diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/gridmeter/GoodWeGridMeterImpl.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/gridmeter/GoodWeGridMeterImpl.java index 67a2a6accf3..3cb9157b12e 100644 --- a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/gridmeter/GoodWeGridMeterImpl.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/gridmeter/GoodWeGridMeterImpl.java @@ -4,6 +4,7 @@ import static io.openems.edge.bridge.modbus.api.ElementToChannelConverter.SCALE_FACTOR_1; import static io.openems.edge.bridge.modbus.api.ElementToChannelConverter.SCALE_FACTOR_2; import static io.openems.edge.bridge.modbus.api.ElementToChannelConverter.SCALE_FACTOR_MINUS_2; +import static io.openems.edge.bridge.modbus.api.ModbusUtils.readElementOnce; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentContext; @@ -124,7 +125,7 @@ protected void deactivate() { private final ElementToChannelConverter ignoreZeroAndInvert = IgnoreZeroConverter.from(this, INVERT); @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { var protocol = new ModbusProtocol(this, // // States @@ -175,18 +176,11 @@ protected ModbusProtocol defineModbusProtocol() throws OpenemsException { this.ignoreZeroAndScaleFactor1))); // Handles different DSP versions - ModbusUtils.readELementOnce(protocol, new UnsignedWordElement(35016), true) // - .thenAccept(dspVersion -> { - try { - if (dspVersion >= 4 || dspVersion == 0) { - this.handleDspVersion4(protocol); - } - - } catch (OpenemsException e) { - this.logError(this.log, "Unable to add task for modbus protocol"); - e.printStackTrace(); - } - }); + readElementOnce(protocol, ModbusUtils::retryOnNull, new UnsignedWordElement(35016)).thenAccept(dspVersion -> { + if (dspVersion >= 4 || dspVersion == 0) { + this.handleDspVersion4(protocol); + } + }); switch (this.config.goodWeMeterCategory()) { case COMMERCIAL_METER -> this.handleExternalMeter(protocol); @@ -201,9 +195,8 @@ protected ModbusProtocol defineModbusProtocol() throws OpenemsException { * Adds Registers that are available from DSP version 4. * * @param protocol the {@link ModbusProtocol} - * @throws OpenemsException on error */ - private void handleDspVersion4(ModbusProtocol protocol) throws OpenemsException { + private void handleDspVersion4(ModbusProtocol protocol) { protocol.addTask(// new FC3ReadRegistersTask(36052, Priority.LOW, // m(ElectricityMeter.ChannelId.VOLTAGE_L1, new UnsignedWordElement(36052), @@ -220,7 +213,7 @@ private void handleDspVersion4(ModbusProtocol protocol) throws OpenemsException this.ignoreZeroAndScaleFactor2))); // } - private void handleExternalMeter(ModbusProtocol protocol) throws OpenemsException { + private void handleExternalMeter(ModbusProtocol protocol) { protocol.addTask(// new FC6WriteRegisterTask(47456, diff --git a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverterImplTest.java b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverterImplTest.java index 9aeacc78673..b9ddd6130e6 100644 --- a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverterImplTest.java +++ b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverterImplTest.java @@ -1,11 +1,16 @@ package io.openems.edge.goodwe.batteryinverter; +import static io.openems.edge.goodwe.batteryinverter.GoodWeBatteryInverterImpl.doSetBmsVoltage; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + import org.junit.Test; import io.openems.common.types.ChannelAddress; import io.openems.edge.battery.api.Battery; import io.openems.edge.battery.test.DummyBattery; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; +import io.openems.edge.common.channel.value.Value; import io.openems.edge.common.sum.DummySum; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; @@ -22,6 +27,7 @@ import io.openems.edge.goodwe.common.enums.MeterCommunicateStatus; import io.openems.edge.goodwe.common.enums.SafetyCountry; +@SuppressWarnings("deprecation") public class GoodWeBatteryInverterImplTest { private static final String MODBUS_ID = "modbus0"; @@ -73,12 +79,12 @@ public class GoodWeBatteryInverterImplTest { private static final ChannelAddress CHARGER_6_VOLTAGE = new ChannelAddress(CHARGER_6_ID, "Voltage"); private static final ChannelAddress CHARGER_6_CURRENT = new ChannelAddress(CHARGER_6_ID, "Current"); - private static final ChannelAddress TWO_S_MPPT1_P = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSMppt1P"); - private static final ChannelAddress TWO_S_MPPT1_I = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSMppt1I"); - private static final ChannelAddress TWO_S_MPPT2_P = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSMppt2P"); - private static final ChannelAddress TWO_S_MPPT2_I = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSMppt2I"); - private static final ChannelAddress TWO_S_MPPT3_P = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSMppt3P"); - private static final ChannelAddress TWO_S_MPPT3_I = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSMppt3I"); + private static final ChannelAddress MPPT1_P = new ChannelAddress(BATTERY_INVERTER_ID, "Mppt1P"); + private static final ChannelAddress MPPT1_I = new ChannelAddress(BATTERY_INVERTER_ID, "Mppt1I"); + private static final ChannelAddress MPPT2_P = new ChannelAddress(BATTERY_INVERTER_ID, "Mppt2P"); + private static final ChannelAddress MPPT2_I = new ChannelAddress(BATTERY_INVERTER_ID, "Mppt2I"); + private static final ChannelAddress MPPT3_P = new ChannelAddress(BATTERY_INVERTER_ID, "Mppt3P"); + private static final ChannelAddress MPPT3_I = new ChannelAddress(BATTERY_INVERTER_ID, "Mppt3I"); private static final ChannelAddress TWO_S_PV1_I = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv1I"); private static final ChannelAddress TWO_S_PV1_V = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv1V"); private static final ChannelAddress TWO_S_PV2_I = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv2I"); @@ -516,8 +522,8 @@ public void testTwoStringCharger() throws Exception { .setControlMode(ControlMode.SMART) // .build()) // .next(new TestCase() // - .input(TWO_S_MPPT1_I, 20) // - .input(TWO_S_MPPT1_P, 2000) // + .input(MPPT1_I, 20) // + .input(MPPT1_P, 2000) // .input(TWO_S_PV1_I, 10) // .input(TWO_S_PV2_I, 10) // .input(TWO_S_PV1_V, 240) // @@ -540,8 +546,8 @@ public void testTwoStringCharger() throws Exception { // Chargers with different current values .next(new TestCase() // - .input(TWO_S_MPPT1_I, 20) // - .input(TWO_S_MPPT1_P, 2000) // + .input(MPPT1_I, 20) // + .input(MPPT1_P, 2000) // .input(TWO_S_PV1_I, 5) // .input(TWO_S_PV2_I, 15) // .output(CHARGER_ACTUAL_POWER, 1000) // @@ -551,8 +557,8 @@ public void testTwoStringCharger() throws Exception { .output(CHARGER_2_ACTUAL_POWER, 1500)) // .next(new TestCase() // - .input(TWO_S_MPPT1_I, 20) // - .input(TWO_S_MPPT1_P, 2000) // + .input(MPPT1_I, 20) // + .input(MPPT1_P, 2000) // .input(TWO_S_PV1_I, 20) // .input(TWO_S_PV2_I, 0) // .output(CHARGER_ACTUAL_POWER, 500) // @@ -588,8 +594,8 @@ public void testTwoStringCharger() throws Exception { .setControlMode(ControlMode.SMART) // .build()) // .next(new TestCase() // - .input(TWO_S_MPPT2_I, 20) // - .input(TWO_S_MPPT2_P, 2000) // + .input(MPPT2_I, 20) // + .input(MPPT2_P, 2000) // .input(TWO_S_PV3_I, 10) // .input(TWO_S_PV4_I, 10) // .input(TWO_S_PV3_V, 240) // @@ -612,8 +618,8 @@ public void testTwoStringCharger() throws Exception { // Chargers with different current values .next(new TestCase() // - .input(TWO_S_MPPT2_I, 20) // - .input(TWO_S_MPPT2_P, 2000) // + .input(MPPT2_I, 20) // + .input(MPPT2_P, 2000) // .input(TWO_S_PV3_I, 5) // .input(TWO_S_PV4_I, 15) // .output(CHARGER_3_ACTUAL_POWER, 1000) // @@ -623,8 +629,8 @@ public void testTwoStringCharger() throws Exception { .output(CHARGER_4_ACTUAL_POWER, 1500)) // .next(new TestCase() // - .input(TWO_S_MPPT2_I, 20) // - .input(TWO_S_MPPT2_P, 2000) // + .input(MPPT2_I, 20) // + .input(MPPT2_P, 2000) // .input(TWO_S_PV3_I, 20) // .input(TWO_S_PV4_I, 0) // .output(CHARGER_3_ACTUAL_POWER, 500) // @@ -660,8 +666,8 @@ public void testTwoStringCharger() throws Exception { .setControlMode(ControlMode.SMART) // .build()) // .next(new TestCase() // - .input(TWO_S_MPPT3_I, 20) // - .input(TWO_S_MPPT3_P, 2000) // + .input(MPPT3_I, 20) // + .input(MPPT3_P, 2000) // .input(TWO_S_PV5_I, 10) // .input(TWO_S_PV6_I, 10) // .input(TWO_S_PV5_V, 240) // @@ -684,8 +690,8 @@ public void testTwoStringCharger() throws Exception { // Chargers with different current values .next(new TestCase() // - .input(TWO_S_MPPT3_I, 20) // - .input(TWO_S_MPPT3_P, 2000) // + .input(MPPT3_I, 20) // + .input(MPPT3_P, 2000) // .input(TWO_S_PV5_I, 5) // .input(TWO_S_PV6_I, 15) // .output(CHARGER_5_ACTUAL_POWER, 1000) // @@ -695,8 +701,8 @@ public void testTwoStringCharger() throws Exception { .output(CHARGER_6_ACTUAL_POWER, 1500)) // .next(new TestCase() // - .input(TWO_S_MPPT3_I, 20) // - .input(TWO_S_MPPT3_P, 2000) // + .input(MPPT3_I, 20) // + .input(MPPT3_P, 2000) // .input(TWO_S_PV5_I, 20) // .input(TWO_S_PV6_I, 0) // .output(CHARGER_5_ACTUAL_POWER, 500) // @@ -706,4 +712,37 @@ public void testTwoStringCharger() throws Exception { .output(CHARGER_6_ACTUAL_POWER, 0) // ); } + + @Test + public void testDoSetBmsVoltage() { + final var battery = new DummyBattery("battery0"); + final var bmsChargeMaxVoltage = new Value(null, 123); + final var bmsDischargeMinVoltage = new Value(null, 456); + + // No battery values + assertFalse(doSetBmsVoltage(battery, bmsChargeMaxVoltage, 1, bmsDischargeMinVoltage, 1)); + battery // + .withChargeMaxCurrent(234) // + .withDischargeMaxCurrent(234); + + // Battery full + battery // + .withChargeMaxCurrent(0); // + assertFalse(doSetBmsVoltage(battery, bmsChargeMaxVoltage, 1, bmsDischargeMinVoltage, 1)); + + // Battery empty + battery // + .withDischargeMaxCurrent(0); // + assertFalse(doSetBmsVoltage(battery, bmsChargeMaxVoltage, 1, bmsDischargeMinVoltage, 1)); + + // Values are already set + battery // + .withChargeMaxCurrent(234) // + .withDischargeMaxCurrent(234); + assertFalse(doSetBmsVoltage(battery, bmsChargeMaxVoltage, 123, bmsDischargeMinVoltage, 456)); + + // Values should be updated + assertTrue(doSetBmsVoltage(battery, bmsChargeMaxVoltage, 1, bmsDischargeMinVoltage, 456)); + assertTrue(doSetBmsVoltage(battery, bmsChargeMaxVoltage, 123, bmsDischargeMinVoltage, 1)); + } } diff --git a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/batteryinverter/MyConfig.java b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/batteryinverter/MyConfig.java index 35f50b2dda5..5d5a2db41ee 100644 --- a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/batteryinverter/MyConfig.java +++ b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/batteryinverter/MyConfig.java @@ -10,7 +10,7 @@ @SuppressWarnings("all") public class MyConfig extends AbstractComponentConfig implements Config { - protected static class Builder { + public static class Builder { private String id; private ControlMode controlMode; private String modbusId; diff --git a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/mppt/twostring/GoodWeChargerMpptTwoStringImplTest.java b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/mppt/twostring/GoodWeChargerMpptTwoStringImplTest.java new file mode 100644 index 00000000000..9ba2a25098a --- /dev/null +++ b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/mppt/twostring/GoodWeChargerMpptTwoStringImplTest.java @@ -0,0 +1,190 @@ +package io.openems.edge.goodwe.charger.mppt.twostring; + +import org.junit.Test; + +import io.openems.common.types.ChannelAddress; +import io.openems.edge.battery.api.Battery; +import io.openems.edge.battery.test.DummyBattery; +import io.openems.edge.bridge.modbus.test.DummyModbusBridge; +import io.openems.edge.common.sum.DummySum; +import io.openems.edge.common.test.AbstractComponentTest.TestCase; +import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.common.test.DummyConfigurationAdmin; +import io.openems.edge.ess.test.DummyPower; +import io.openems.edge.goodwe.GoodWeConstants; +import io.openems.edge.goodwe.batteryinverter.GoodWeBatteryInverterImpl; +import io.openems.edge.goodwe.common.enums.ControlMode; +import io.openems.edge.goodwe.common.enums.EnableDisable; +import io.openems.edge.goodwe.common.enums.FeedInPowerSettings; +import io.openems.edge.goodwe.common.enums.SafetyCountry; + +public class GoodWeChargerMpptTwoStringImplTest { + + private static final String MODBUS_ID = "modbus0"; + private static final String BATTERY_ID = "battery0"; + private static final String CHARGER_1_ID = "charger0"; + private static final String CHARGER_2_ID = "charger1"; + private static final String CHARGER_3_ID = "charger2"; + private static final String BATTERY_INVERTER_ID = "batteryInverter0"; + + private static final Battery BATTERY = new DummyBattery(BATTERY_ID); + + private static final ChannelAddress MPPT1_P = new ChannelAddress(BATTERY_INVERTER_ID, "Mppt1P"); + private static final ChannelAddress MPPT1_I = new ChannelAddress(BATTERY_INVERTER_ID, "Mppt1I"); + private static final ChannelAddress MPPT2_P = new ChannelAddress(BATTERY_INVERTER_ID, "Mppt2P"); + private static final ChannelAddress MPPT2_I = new ChannelAddress(BATTERY_INVERTER_ID, "Mppt2I"); + private static final ChannelAddress MPPT3_P = new ChannelAddress(BATTERY_INVERTER_ID, "Mppt3P"); + private static final ChannelAddress MPPT3_I = new ChannelAddress(BATTERY_INVERTER_ID, "Mppt3I"); + private static final ChannelAddress TWO_S_PV1_I = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv1I"); + private static final ChannelAddress TWO_S_PV1_V = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv1V"); + private static final ChannelAddress TWO_S_PV2_I = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv2I"); + private static final ChannelAddress TWO_S_PV2_V = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv2V"); + private static final ChannelAddress TWO_S_PV3_I = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv3I"); + private static final ChannelAddress TWO_S_PV3_V = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv3V"); + private static final ChannelAddress TWO_S_PV4_I = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv4I"); + private static final ChannelAddress TWO_S_PV4_V = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv4V"); + private static final ChannelAddress TWO_S_PV5_I = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv5I"); + private static final ChannelAddress TWO_S_PV5_V = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv5V"); + private static final ChannelAddress TWO_S_PV6_I = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv6I"); + private static final ChannelAddress TWO_S_PV6_V = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv6V"); + private static final ChannelAddress CHARGER_1_ACTUAL_POWER = new ChannelAddress(CHARGER_1_ID, "ActualPower"); + private static final ChannelAddress CHARGER_1_VOLTAGE = new ChannelAddress(CHARGER_1_ID, "Voltage"); + private static final ChannelAddress CHARGER_1_CURRENT = new ChannelAddress(CHARGER_1_ID, "Current"); + private static final ChannelAddress CHARGER_2_ACTUAL_POWER = new ChannelAddress(CHARGER_2_ID, "ActualPower"); + private static final ChannelAddress CHARGER_2_VOLTAGE = new ChannelAddress(CHARGER_2_ID, "Voltage"); + private static final ChannelAddress CHARGER_2_CURRENT = new ChannelAddress(CHARGER_2_ID, "Current"); + private static final ChannelAddress CHARGER_3_ACTUAL_POWER = new ChannelAddress(CHARGER_3_ID, "ActualPower"); + private static final ChannelAddress CHARGER_3_VOLTAGE = new ChannelAddress(CHARGER_3_ID, "Voltage"); + private static final ChannelAddress CHARGER_3_CURRENT = new ChannelAddress(CHARGER_3_ID, "Current"); + + @Test + public void test() throws Exception { + var ess = new GoodWeBatteryInverterImpl(); + var charger1 = new GoodWeChargerMpptTwoStringImpl(); + var charger2 = new GoodWeChargerMpptTwoStringImpl(); + var charger3 = new GoodWeChargerMpptTwoStringImpl(); + + new ComponentTest(charger1) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("essOrBatteryInverter", ess) // + .activate(MyConfig.create() // + .setId(CHARGER_1_ID) // + .setBatteryInverterId(BATTERY_INVERTER_ID) // + .setMpptPort(MpptPort.MPPT_1) // + .build()); + + new ComponentTest(charger2) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("essOrBatteryInverter", ess) // + .activate(MyConfig.create() // + .setId(CHARGER_2_ID) // + .setBatteryInverterId(BATTERY_INVERTER_ID) // + .setMpptPort(MpptPort.MPPT_2) // + .build()); + + new ComponentTest(charger3) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("essOrBatteryInverter", ess) // + .activate(MyConfig.create() // + .setId(CHARGER_3_ID) // + .setBatteryInverterId(BATTERY_INVERTER_ID) // + .setMpptPort(MpptPort.MPPT_3) // + .build()); + + ess.addCharger(charger1); + ess.addCharger(charger2); + ess.addCharger(charger3); + + new ComponentTest(ess) // + .addReference("power", new DummyPower()) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("sum", new DummySum()) // + .addComponent(charger1) // + .addComponent(charger2) // + .addComponent(charger3) // + .addComponent(BATTERY) // + .activate(io.openems.edge.goodwe.batteryinverter.MyConfig.create() // + .setId(BATTERY_INVERTER_ID) // + .setModbusId(MODBUS_ID) // + .setModbusUnitId(GoodWeConstants.DEFAULT_UNIT_ID) // + .setSafetyCountry(SafetyCountry.GERMANY) // + .setMpptForShadowEnable(EnableDisable.ENABLE) // + .setBackupEnable(EnableDisable.ENABLE) // + .setFeedPowerEnable(EnableDisable.ENABLE) // + .setFeedPowerPara(3000) // + .setFeedInPowerSettings(FeedInPowerSettings.PU_ENABLE_CURVE) // + .setControlMode(ControlMode.SMART) // + .build()) // + .next(new TestCase() // + .input(MPPT1_I, 20) // + .input(MPPT1_P, 2000) // + .input(TWO_S_PV1_I, 10) // + .input(TWO_S_PV2_I, 10) // + .input(TWO_S_PV1_V, 240) // + .input(TWO_S_PV2_V, 240)) // + // Values applied in the next cycle + .next(new TestCase() // + .output(CHARGER_1_ACTUAL_POWER, 2000) // + .output(CHARGER_1_CURRENT, 20) // + .output(CHARGER_1_VOLTAGE, 240) // + .output(CHARGER_2_ACTUAL_POWER, null) // + .output(CHARGER_2_CURRENT, null) // + .output(CHARGER_2_VOLTAGE, null) // + .output(CHARGER_3_ACTUAL_POWER, null) // + .output(CHARGER_3_CURRENT, null) // + .output(CHARGER_3_VOLTAGE, null) // + ) // + + // Chargers with different current values + .next(new TestCase() // + .input(MPPT1_I, 20) // + .input(MPPT1_P, 3000) // + .input(TWO_S_PV1_I, 5) // + .input(TWO_S_PV2_I, 15) // + .input(TWO_S_PV1_V, 250) // + .input(TWO_S_PV2_V, 250)) // + .next(new TestCase() // + .output(CHARGER_1_ACTUAL_POWER, 3000) // + .output(CHARGER_1_CURRENT, 20) // + .output(CHARGER_1_VOLTAGE, 250) // + .output(CHARGER_2_ACTUAL_POWER, null) // + .output(CHARGER_2_CURRENT, null) // + .output(CHARGER_2_VOLTAGE, null). // + output(CHARGER_3_ACTUAL_POWER, null) // + .output(CHARGER_3_CURRENT, null) // + .output(CHARGER_3_VOLTAGE, null) // + ) + + .next(new TestCase() // + .input(MPPT1_I, 20) // + .input(MPPT1_P, 2000) // + .input(MPPT2_I, 30) // + .input(MPPT2_P, 3000) // + .input(MPPT3_I, 40) // + .input(MPPT3_P, 4000) // + .input(TWO_S_PV1_I, 10) // + .input(TWO_S_PV1_V, 250) // + .input(TWO_S_PV2_I, 10) // + .input(TWO_S_PV2_V, 250) // + .input(TWO_S_PV3_I, 15) // + .input(TWO_S_PV3_V, 280) // + .input(TWO_S_PV4_I, 15) // + .input(TWO_S_PV4_V, 280) // + .input(TWO_S_PV5_I, 20) // + .input(TWO_S_PV5_V, 299) // + .input(TWO_S_PV6_I, 20) // + .input(TWO_S_PV6_V, 299)) // + .next(new TestCase() // + .output(CHARGER_1_ACTUAL_POWER, 2000) // + .output(CHARGER_1_CURRENT, 20) // + .output(CHARGER_1_VOLTAGE, 250) // + .output(CHARGER_2_ACTUAL_POWER, 3000) // + .output(CHARGER_2_CURRENT, 30) // + .output(CHARGER_2_VOLTAGE, 280). // + output(CHARGER_3_ACTUAL_POWER, 4000) // + .output(CHARGER_3_CURRENT, 40) // + .output(CHARGER_3_VOLTAGE, 299) // + ); + } +} diff --git a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/mppt/twostring/MyConfig.java b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/mppt/twostring/MyConfig.java new file mode 100644 index 00000000000..79d7f0b1623 --- /dev/null +++ b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/mppt/twostring/MyConfig.java @@ -0,0 +1,72 @@ +package io.openems.edge.goodwe.charger.mppt.twostring; + +import io.openems.common.test.AbstractComponentConfig; +import io.openems.common.utils.ConfigUtils; + +@SuppressWarnings("all") +public class MyConfig extends AbstractComponentConfig implements Config { + + public static class Builder { + private String id; + private MpptPort mpptPort; + private String essOrBatteryInverter; + + private Builder() { + } + + public Builder setId(String id) { + this.id = id; + return this; + } + + public Builder setBatteryInverterId(String essOrBatteryInverter) { + this.essOrBatteryInverter = essOrBatteryInverter; + return this; + } + + public Builder setMpptPort(MpptPort mpptPort) { + this.mpptPort = mpptPort; + return this; + } + + /** + * Builds the Config. + * + * @return the Config + */ + public MyConfig build() { + return new MyConfig(this); + } + } + + /** + * Create a Config builder. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new Builder(); + } + + private final Builder builder; + + private MyConfig(Builder builder) { + super(Config.class, builder.id); + this.builder = builder; + } + + @Override + public String essOrBatteryInverter_id() { + return this.builder.essOrBatteryInverter; + } + + @Override + public String essOrBatteryInverter_target() { + return ConfigUtils.generateReferenceTargetFilter(this.id(), this.essOrBatteryInverter_id()); + } + + @Override + public MpptPort mpptPort() { + return this.builder.mpptPort; + } +} diff --git a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/mppt/twostring/TestStatic.java b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/mppt/twostring/TestStatic.java new file mode 100644 index 00000000000..b1149ad7c64 --- /dev/null +++ b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/mppt/twostring/TestStatic.java @@ -0,0 +1,28 @@ +package io.openems.edge.goodwe.charger.mppt.twostring; + +import static org.junit.Assert.assertEquals; + +import java.util.Optional; + +import org.junit.Test; + +public class TestStatic { + + @Test + public void testCaculateEnergyFromTwoStrings() { + Optional string1 = Optional.of(40_000L); + Optional string2 = Optional.of(90_000L); + Optional string3 = Optional.empty(); + Optional string4 = Optional.of(0); + + var result = GoodWeChargerMpptTwoStringImpl.caculateEnergyFromTwoStrings(string1, string2); + assertEquals((long) result, 130_000L); + + var result2 = GoodWeChargerMpptTwoStringImpl.caculateEnergyFromTwoStrings(string3, string4); + assertEquals((long) result2, 0); + + var result3 = GoodWeChargerMpptTwoStringImpl.caculateEnergyFromTwoStrings(string1, string3); + assertEquals((long) result3, 40_000L); + } + +} diff --git a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/twostring/GoodWeChargerTwoStringImplTest.java b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/twostring/GoodWeChargerTwoStringImplTest.java index 75841a8ca30..3d2e5340e78 100644 --- a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/twostring/GoodWeChargerTwoStringImplTest.java +++ b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/twostring/GoodWeChargerTwoStringImplTest.java @@ -11,6 +11,7 @@ public class GoodWeChargerTwoStringImplTest { private static final String ESS_ID = "ess0"; private static final String CHARGER_ID = "charger0"; + @SuppressWarnings("deprecation") @Test public void test() throws Exception { new ComponentTest(new GoodWeChargerTwoStringImpl()) // diff --git a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/twostring/RuleOfThreeTest.java b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/twostring/RuleOfThreeTest.java index 5298ac5f23b..cfe59e9bb6a 100644 --- a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/twostring/RuleOfThreeTest.java +++ b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/twostring/RuleOfThreeTest.java @@ -7,6 +7,7 @@ import org.junit.Test; +@SuppressWarnings("deprecation") public class RuleOfThreeTest { @Test diff --git a/io.openems.edge.io.filipowski/src/io/openems/edge/io/filipowski/analog/mr/IoFilipowskiMrAo1Impl.java b/io.openems.edge.io.filipowski/src/io/openems/edge/io/filipowski/analog/mr/IoFilipowskiMrAo1Impl.java index ea29a1b0e6a..6f6a08401a4 100644 --- a/io.openems.edge.io.filipowski/src/io/openems/edge/io/filipowski/analog/mr/IoFilipowskiMrAo1Impl.java +++ b/io.openems.edge.io.filipowski/src/io/openems/edge/io/filipowski/analog/mr/IoFilipowskiMrAo1Impl.java @@ -79,7 +79,7 @@ protected void deactivate() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { final var address = this.config.analogOutput().startAddress; return new ModbusProtocol(this, // diff --git a/io.openems.edge.io.kmtronic/src/io/openems/edge/io/kmtronic/eight/IoKmtronicRelay8PortImpl.java b/io.openems.edge.io.kmtronic/src/io/openems/edge/io/kmtronic/eight/IoKmtronicRelay8PortImpl.java index f6d0994bd0b..74d57edee6c 100644 --- a/io.openems.edge.io.kmtronic/src/io/openems/edge/io/kmtronic/eight/IoKmtronicRelay8PortImpl.java +++ b/io.openems.edge.io.kmtronic/src/io/openems/edge/io/kmtronic/eight/IoKmtronicRelay8PortImpl.java @@ -66,7 +66,7 @@ protected void deactivate() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this, // /* * For Read: Read Coils diff --git a/io.openems.edge.io.kmtronic/src/io/openems/edge/io/kmtronic/four/IoKmtronicRelay4PortImpl.java b/io.openems.edge.io.kmtronic/src/io/openems/edge/io/kmtronic/four/IoKmtronicRelay4PortImpl.java index 63f142ffac9..431ba55d1b4 100644 --- a/io.openems.edge.io.kmtronic/src/io/openems/edge/io/kmtronic/four/IoKmtronicRelay4PortImpl.java +++ b/io.openems.edge.io.kmtronic/src/io/openems/edge/io/kmtronic/four/IoKmtronicRelay4PortImpl.java @@ -66,7 +66,7 @@ protected void deactivate() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this, // /* * For Read: Read Coils diff --git a/io.openems.edge.io.wago/src/io/openems/edge/wago/IoWagoImpl.java b/io.openems.edge.io.wago/src/io/openems/edge/wago/IoWagoImpl.java index 250029d4998..d00fe280ee6 100644 --- a/io.openems.edge.io.wago/src/io/openems/edge/wago/IoWagoImpl.java +++ b/io.openems.edge.io.wago/src/io/openems/edge/wago/IoWagoImpl.java @@ -270,7 +270,7 @@ protected CoilElement createModbusCoilElement(io.openems.edge.common.channel.Cha } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { if (this.protocol == null) { this.protocol = new ModbusProtocol(this); } diff --git a/io.openems.edge.io.weidmueller/src/io/openems/edge/io/weidmueller/IoWeidmuellerUr20Impl.java b/io.openems.edge.io.weidmueller/src/io/openems/edge/io/weidmueller/IoWeidmuellerUr20Impl.java index 288bc173545..fdceb8c3564 100644 --- a/io.openems.edge.io.weidmueller/src/io/openems/edge/io/weidmueller/IoWeidmuellerUr20Impl.java +++ b/io.openems.edge.io.weidmueller/src/io/openems/edge/io/weidmueller/IoWeidmuellerUr20Impl.java @@ -1,5 +1,8 @@ package io.openems.edge.io.weidmueller; +import static io.openems.edge.bridge.modbus.api.ModbusUtils.readElementOnce; +import static io.openems.edge.bridge.modbus.api.ModbusUtils.readElementsOnce; + import java.util.ArrayList; import java.util.List; import java.util.TreeMap; @@ -29,6 +32,7 @@ import io.openems.edge.bridge.modbus.api.ModbusUtils; import io.openems.edge.bridge.modbus.api.element.BitsWordElement; import io.openems.edge.bridge.modbus.api.element.CoilElement; +import io.openems.edge.bridge.modbus.api.element.ModbusRegisterElement; import io.openems.edge.bridge.modbus.api.element.UnsignedDoublewordElement; import io.openems.edge.bridge.modbus.api.element.UnsignedWordElement; import io.openems.edge.bridge.modbus.api.task.FC3ReadRegistersTask; @@ -72,7 +76,7 @@ protected void setModbus(BridgeModbus modbus) { private BooleanReadChannel[] digitalInputChannels; private BooleanWriteChannel[] digitalOutputChannels; - public IoWeidmuellerUr20Impl() throws OpenemsException { + public IoWeidmuellerUr20Impl() { super(// OpenemsComponent.ChannelId.values(), // ModbusComponent.ChannelId.values(), // @@ -154,15 +158,7 @@ private void activate(ComponentContext context, Config config) throws OpenemsExc return; } - try { - this.modbusProtocol.addTasks(tasks); - - } catch (OpenemsException e) { - this.logError(this.log, "Unable to add Modbus-Task for U-Remote-Module #" + moduleCount // - + " [" + module.name() + "]: " + e.getMessage()); - e.printStackTrace(); - return; - } + this.modbusProtocol.addTasks(tasks); this.digitalInputChannels = this.modules.values().stream() // .flatMap(cs -> cs.stream()) // @@ -182,7 +178,7 @@ protected void deactivate() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { return this.modbusProtocol; } @@ -226,27 +222,16 @@ public String debugLog() { } private CompletableFuture readNumberOfEntriesInTheCurrentModuleList() { - try { - return ModbusUtils.readELementOnce(this.modbusProtocol, new UnsignedWordElement(0x27FE), true); - - } catch (OpenemsException e) { - this.logWarn(this.log, "Unable to readNumberOfEntriesInTheCurrentModuleList: " + e.getMessage()); - return CompletableFuture.failedFuture(e); - } + return readElementOnce(this.modbusProtocol, ModbusUtils::retryOnNull, new UnsignedWordElement(0x27FE)); } + @SuppressWarnings("unchecked") private CompletableFuture> readCurrentModuleList(int numberOfEntries) { var elements = IntStream.range(0, numberOfEntries) // .map(index -> 0x2A00 + index * 2) // .mapToObj(address -> new UnsignedDoublewordElement(address)) // - .toArray(UnsignedDoublewordElement[]::new); - try { - return ModbusUtils.readELementsOnce(this.modbusProtocol, elements, true); - - } catch (OpenemsException e) { - this.logWarn(this.log, "Unable to readCurrentModuleList: " + e.getMessage()); - return CompletableFuture.failedFuture(e); - } + .toArray(ModbusRegisterElement[]::new); + return readElementsOnce(this.modbusProtocol, ModbusUtils::retryOnNull, elements); } } diff --git a/io.openems.edge.meter.artemes.am2/src/io/openems/edge/meter/artemes/am2/MeterArtemesAM2Impl.java b/io.openems.edge.meter.artemes.am2/src/io/openems/edge/meter/artemes/am2/MeterArtemesAM2Impl.java index 4682151c3c1..52db9a3acd0 100644 --- a/io.openems.edge.meter.artemes.am2/src/io/openems/edge/meter/artemes/am2/MeterArtemesAM2Impl.java +++ b/io.openems.edge.meter.artemes.am2/src/io/openems/edge/meter/artemes/am2/MeterArtemesAM2Impl.java @@ -85,7 +85,7 @@ public MeterType getMeterType() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this, new FC4ReadInputRegistersTask(0x0000, Priority.HIGH, m(ElectricityMeter.ChannelId.VOLTAGE_L1, new UnsignedDoublewordElement(0x0000)), diff --git a/io.openems.edge.meter.bcontrol.em300/src/io/openems/edge/meter/bcontrol/em300/MeterBControlEM300Impl.java b/io.openems.edge.meter.bcontrol.em300/src/io/openems/edge/meter/bcontrol/em300/MeterBControlEM300Impl.java index 44339f8512d..3cd11ad580e 100644 --- a/io.openems.edge.meter.bcontrol.em300/src/io/openems/edge/meter/bcontrol/em300/MeterBControlEM300Impl.java +++ b/io.openems.edge.meter.bcontrol.em300/src/io/openems/edge/meter/bcontrol/em300/MeterBControlEM300Impl.java @@ -92,7 +92,7 @@ public MeterType getMeterType() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { var modbusProtocol = new ModbusProtocol(this, // new FC3ReadRegistersTask(0, Priority.HIGH, // m(MeterBControlEM300.ChannelId.ACTIVE_POWER_POS, new UnsignedDoublewordElement(0), diff --git a/io.openems.edge.meter.bgetech/src/io/openems/edge/meter/bgetech/MeterBgeTechDrt428M2Impl.java b/io.openems.edge.meter.bgetech/src/io/openems/edge/meter/bgetech/MeterBgeTechDrt428M2Impl.java index fa0546c7c10..39b7909110c 100644 --- a/io.openems.edge.meter.bgetech/src/io/openems/edge/meter/bgetech/MeterBgeTechDrt428M2Impl.java +++ b/io.openems.edge.meter.bgetech/src/io/openems/edge/meter/bgetech/MeterBgeTechDrt428M2Impl.java @@ -85,7 +85,7 @@ public MeterType getMeterType() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { ModbusProtocol modbusProtocol = new ModbusProtocol(this, // new FC3ReadRegistersTask(14, Priority.HIGH, // m(ElectricityMeter.ChannelId.VOLTAGE_L1, new FloatDoublewordElement(14), SCALE_FACTOR_3), // diff --git a/io.openems.edge.meter.camillebauer.aplus/src/io/openems/edge/meter/camillebauer/aplus/MeterCamillebauerAplusImpl.java b/io.openems.edge.meter.camillebauer.aplus/src/io/openems/edge/meter/camillebauer/aplus/MeterCamillebauerAplusImpl.java index e519ac0fd59..77bd4a98c39 100644 --- a/io.openems.edge.meter.camillebauer.aplus/src/io/openems/edge/meter/camillebauer/aplus/MeterCamillebauerAplusImpl.java +++ b/io.openems.edge.meter.camillebauer.aplus/src/io/openems/edge/meter/camillebauer/aplus/MeterCamillebauerAplusImpl.java @@ -110,7 +110,7 @@ protected void deactivate() { * in 99. */ @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this, // new FC3ReadRegistersTask(99, Priority.HIGH, // m(ElectricityMeter.ChannelId.VOLTAGE, // diff --git a/io.openems.edge.meter.carlo.gavazzi.em300/src/io/openems/edge/meter/carlo/gavazzi/em300/MeterCarloGavazziEm300Impl.java b/io.openems.edge.meter.carlo.gavazzi.em300/src/io/openems/edge/meter/carlo/gavazzi/em300/MeterCarloGavazziEm300Impl.java index da837045d71..d5aea0a4d23 100644 --- a/io.openems.edge.meter.carlo.gavazzi.em300/src/io/openems/edge/meter/carlo/gavazzi/em300/MeterCarloGavazziEm300Impl.java +++ b/io.openems.edge.meter.carlo.gavazzi.em300/src/io/openems/edge/meter/carlo/gavazzi/em300/MeterCarloGavazziEm300Impl.java @@ -85,7 +85,7 @@ public MeterType getMeterType() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { final var offset = 300000 + 1; /** * See Modbus definition PDF-file in doc directory and diff --git a/io.openems.edge.meter.janitza/src/io/openems/edge/meter/janitza/umg511/MeterJanitzaUmg511Impl.java b/io.openems.edge.meter.janitza/src/io/openems/edge/meter/janitza/umg511/MeterJanitzaUmg511Impl.java index 5b9b915ba6c..b4ad5712068 100644 --- a/io.openems.edge.meter.janitza/src/io/openems/edge/meter/janitza/umg511/MeterJanitzaUmg511Impl.java +++ b/io.openems.edge.meter.janitza/src/io/openems/edge/meter/janitza/umg511/MeterJanitzaUmg511Impl.java @@ -95,7 +95,7 @@ public MeterType getMeterType() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { var modbusProtocol = new ModbusProtocol(this, // new FC3ReadRegistersTask(3845, Priority.HIGH, // m(ElectricityMeter.ChannelId.VOLTAGE_L1, new FloatDoublewordElement(3845), SCALE_FACTOR_3), // diff --git a/io.openems.edge.meter.janitza/src/io/openems/edge/meter/janitza/umg604/MeterJanitzaUmg604Impl.java b/io.openems.edge.meter.janitza/src/io/openems/edge/meter/janitza/umg604/MeterJanitzaUmg604Impl.java index 69f35ae04ec..95fa44bd68f 100644 --- a/io.openems.edge.meter.janitza/src/io/openems/edge/meter/janitza/umg604/MeterJanitzaUmg604Impl.java +++ b/io.openems.edge.meter.janitza/src/io/openems/edge/meter/janitza/umg604/MeterJanitzaUmg604Impl.java @@ -95,7 +95,7 @@ public MeterType getMeterType() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { var modbusProtocol = new ModbusProtocol(this, // new FC3ReadRegistersTask(1317, Priority.HIGH, // m(ElectricityMeter.ChannelId.VOLTAGE_L1, new FloatDoublewordElement(1317), // diff --git a/io.openems.edge.meter.janitza/src/io/openems/edge/meter/janitza/umg96rme/MeterJanitzaUmg96rmeImpl.java b/io.openems.edge.meter.janitza/src/io/openems/edge/meter/janitza/umg96rme/MeterJanitzaUmg96rmeImpl.java index b2f916b4ce3..7b9f91291a4 100644 --- a/io.openems.edge.meter.janitza/src/io/openems/edge/meter/janitza/umg96rme/MeterJanitzaUmg96rmeImpl.java +++ b/io.openems.edge.meter.janitza/src/io/openems/edge/meter/janitza/umg96rme/MeterJanitzaUmg96rmeImpl.java @@ -94,7 +94,7 @@ public MeterType getMeterType() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { /* * We are using the FLOAT registers from the modbus table, because they are all * reachable within one ReadMultipleRegistersRequest. diff --git a/io.openems.edge.meter.kdk/src/io/openems/edge/meter/kdk/puct2/MeterKdk2puctImpl.java b/io.openems.edge.meter.kdk/src/io/openems/edge/meter/kdk/puct2/MeterKdk2puctImpl.java index 2a4e65abc20..a8e380226d3 100755 --- a/io.openems.edge.meter.kdk/src/io/openems/edge/meter/kdk/puct2/MeterKdk2puctImpl.java +++ b/io.openems.edge.meter.kdk/src/io/openems/edge/meter/kdk/puct2/MeterKdk2puctImpl.java @@ -100,7 +100,7 @@ public ModbusSlaveTable getModbusSlaveTable(AccessMode accessMode) { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { var modbusProtocol = new ModbusProtocol(this, // new FC3ReadRegistersTask(0x4007, Priority.LOW, // m(MeterKdk2puct.ChannelId.SOFTWARE_VERSION, new FloatDoublewordElement(0x4007))), diff --git a/io.openems.edge.meter.microcare.sdm630/src/io/openems/edge/meter/microcare/sdm630/MeterMicrocareSdm630Impl.java b/io.openems.edge.meter.microcare.sdm630/src/io/openems/edge/meter/microcare/sdm630/MeterMicrocareSdm630Impl.java index 8ab87bab921..b0d8cf50337 100644 --- a/io.openems.edge.meter.microcare.sdm630/src/io/openems/edge/meter/microcare/sdm630/MeterMicrocareSdm630Impl.java +++ b/io.openems.edge.meter.microcare.sdm630/src/io/openems/edge/meter/microcare/sdm630/MeterMicrocareSdm630Impl.java @@ -105,7 +105,7 @@ public MeterType getMeterType() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { final var offset = 30001; return new ModbusProtocol(this, // new FC4ReadInputRegistersTask(30001 - offset, Priority.HIGH, diff --git a/io.openems.edge.meter.phoenixcontact/src/io/openems/edge/meter/phoenixcontact/PhoenixContactMeterImpl.java b/io.openems.edge.meter.phoenixcontact/src/io/openems/edge/meter/phoenixcontact/PhoenixContactMeterImpl.java index 5645a4f13a1..146005b63ff 100644 --- a/io.openems.edge.meter.phoenixcontact/src/io/openems/edge/meter/phoenixcontact/PhoenixContactMeterImpl.java +++ b/io.openems.edge.meter.phoenixcontact/src/io/openems/edge/meter/phoenixcontact/PhoenixContactMeterImpl.java @@ -78,7 +78,7 @@ protected void deactivate() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { final var modbusProtocol = new ModbusProtocol(this, // new FC3ReadRegistersTask(0x8006, Priority.HIGH, // m(ElectricityMeter.ChannelId.VOLTAGE_L1, new FloatDoublewordElement(0x8006) // diff --git a/io.openems.edge.meter.plexlog/src/io/openems/edge/meter/plexlog/MeterPlexlogDataloggerImpl.java b/io.openems.edge.meter.plexlog/src/io/openems/edge/meter/plexlog/MeterPlexlogDataloggerImpl.java index c317670fd32..50bf5fa08f8 100644 --- a/io.openems.edge.meter.plexlog/src/io/openems/edge/meter/plexlog/MeterPlexlogDataloggerImpl.java +++ b/io.openems.edge.meter.plexlog/src/io/openems/edge/meter/plexlog/MeterPlexlogDataloggerImpl.java @@ -75,7 +75,7 @@ public String debugLog() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { final var modbusProtocol = new ModbusProtocol(this, // new FC4ReadInputRegistersTask(0, Priority.HIGH, // this.m(ElectricityMeter.ChannelId.ACTIVE_POWER, new SignedDoublewordElement(0)), // diff --git a/io.openems.edge.meter.pqplus/src/io/openems/edge/meter/pqplus/umd96/MeterPqplusUmd96Impl.java b/io.openems.edge.meter.pqplus/src/io/openems/edge/meter/pqplus/umd96/MeterPqplusUmd96Impl.java index a8064457fcb..248c2c30784 100644 --- a/io.openems.edge.meter.pqplus/src/io/openems/edge/meter/pqplus/umd96/MeterPqplusUmd96Impl.java +++ b/io.openems.edge.meter.pqplus/src/io/openems/edge/meter/pqplus/umd96/MeterPqplusUmd96Impl.java @@ -90,7 +90,7 @@ public MeterType getMeterType() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this, // // Frequency new FC3ReadRegistersTask(0x1004, Priority.LOW, // diff --git a/io.openems.edge.meter.pqplus/src/io/openems/edge/meter/pqplus/umd97/MeterPqplusUmd97Impl.java b/io.openems.edge.meter.pqplus/src/io/openems/edge/meter/pqplus/umd97/MeterPqplusUmd97Impl.java index ddda6519f0b..72accb117fb 100644 --- a/io.openems.edge.meter.pqplus/src/io/openems/edge/meter/pqplus/umd97/MeterPqplusUmd97Impl.java +++ b/io.openems.edge.meter.pqplus/src/io/openems/edge/meter/pqplus/umd97/MeterPqplusUmd97Impl.java @@ -87,7 +87,7 @@ public MeterType getMeterType() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this, // new FC3ReadRegistersTask(19000, Priority.HIGH, // m(ElectricityMeter.ChannelId.VOLTAGE_L1, new FloatDoublewordElement(19000), SCALE_FACTOR_3), diff --git a/io.openems.edge.meter.schneider.acti9.smartlink/src/io/openems/edge/meter/schneider/acti9/smartlink/MeterSchneiderActi9SmartlinkImpl.java b/io.openems.edge.meter.schneider.acti9.smartlink/src/io/openems/edge/meter/schneider/acti9/smartlink/MeterSchneiderActi9SmartlinkImpl.java index 23d3b54cbb2..f2d9c28e77c 100644 --- a/io.openems.edge.meter.schneider.acti9.smartlink/src/io/openems/edge/meter/schneider/acti9/smartlink/MeterSchneiderActi9SmartlinkImpl.java +++ b/io.openems.edge.meter.schneider.acti9.smartlink/src/io/openems/edge/meter/schneider/acti9/smartlink/MeterSchneiderActi9SmartlinkImpl.java @@ -85,7 +85,7 @@ public MeterType getMeterType() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { final var offset = 1; /** * See Datasheet PDF-file in doc directory. diff --git a/io.openems.edge.meter.siemens/src/io/openems/edge/meter/siemens/pac1600/MeterSiemensPac1600Impl.java b/io.openems.edge.meter.siemens/src/io/openems/edge/meter/siemens/pac1600/MeterSiemensPac1600Impl.java index 610f120c2eb..dbe1c463ce1 100644 --- a/io.openems.edge.meter.siemens/src/io/openems/edge/meter/siemens/pac1600/MeterSiemensPac1600Impl.java +++ b/io.openems.edge.meter.siemens/src/io/openems/edge/meter/siemens/pac1600/MeterSiemensPac1600Impl.java @@ -81,7 +81,7 @@ public MeterType getMeterType() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this, // new FC3ReadRegistersTask(1, Priority.HIGH, // m(ElectricityMeter.ChannelId.VOLTAGE_L1, new UnsignedDoublewordElement(1), diff --git a/io.openems.edge.meter.siemens/src/io/openems/edge/meter/siemens/pac2200/MeterSiemensPac2200Impl.java b/io.openems.edge.meter.siemens/src/io/openems/edge/meter/siemens/pac2200/MeterSiemensPac2200Impl.java index 4a71484d27a..3c2e8f5d7fa 100644 --- a/io.openems.edge.meter.siemens/src/io/openems/edge/meter/siemens/pac2200/MeterSiemensPac2200Impl.java +++ b/io.openems.edge.meter.siemens/src/io/openems/edge/meter/siemens/pac2200/MeterSiemensPac2200Impl.java @@ -95,8 +95,7 @@ public MeterType getMeterType() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { - + protected ModbusProtocol defineModbusProtocol() { var modbusProtocol = new ModbusProtocol(this, // new FC3ReadRegistersTask(1, Priority.HIGH, // m(ElectricityMeter.ChannelId.VOLTAGE_L1, new FloatDoublewordElement(1), SCALE_FACTOR_3), diff --git a/io.openems.edge.meter.sma.shm20/src/io/openems/edge/meter/sma/shm20/MeterSmaShm20Impl.java b/io.openems.edge.meter.sma.shm20/src/io/openems/edge/meter/sma/shm20/MeterSmaShm20Impl.java index 4aaf78ae43f..7e31503d6e9 100644 --- a/io.openems.edge.meter.sma.shm20/src/io/openems/edge/meter/sma/shm20/MeterSmaShm20Impl.java +++ b/io.openems.edge.meter.sma.shm20/src/io/openems/edge/meter/sma/shm20/MeterSmaShm20Impl.java @@ -85,7 +85,7 @@ public MeterType getMeterType() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { var modbusProtocol = new ModbusProtocol(this, // Consumption and Production Energy new FC3ReadRegistersTask(30581, Priority.HIGH, // diff --git a/io.openems.edge.meter.socomec/src/io/openems/edge/meter/socomec/AbstractSocomecMeter.java b/io.openems.edge.meter.socomec/src/io/openems/edge/meter/socomec/AbstractSocomecMeter.java index b3f9643e4c9..eaa80b7399f 100644 --- a/io.openems.edge.meter.socomec/src/io/openems/edge/meter/socomec/AbstractSocomecMeter.java +++ b/io.openems.edge.meter.socomec/src/io/openems/edge/meter/socomec/AbstractSocomecMeter.java @@ -1,5 +1,7 @@ package io.openems.edge.meter.socomec; +import static io.openems.edge.bridge.modbus.api.ModbusUtils.readElementOnce; + import java.util.concurrent.CompletableFuture; import org.slf4j.Logger; @@ -23,7 +25,7 @@ public abstract class AbstractSocomecMeter extends AbstractOpenemsModbusComponen protected final ModbusProtocol modbusProtocol; protected AbstractSocomecMeter(io.openems.edge.common.channel.ChannelId[] firstInitialChannelIds, - io.openems.edge.common.channel.ChannelId[]... furtherInitialChannelIds) throws OpenemsException { + io.openems.edge.common.channel.ChannelId[]... furtherInitialChannelIds) { super(firstInitialChannelIds, furtherInitialChannelIds); this.modbusProtocol = new ModbusProtocol(this); } @@ -145,32 +147,18 @@ private CompletableFuture getSocomecIdentifier() { final var result = new CompletableFuture(); // Search for Socomec identifier register. Needs to be "SOCO". - try { - ModbusUtils.readELementOnce(this.modbusProtocol, new UnsignedQuadruplewordElement(0xC350), true) - .thenAccept(value -> { - if (value != 0x0053004F0043004FL /* SOCO */) { - this.channel(SocomecMeter.ChannelId.NO_SOCOMEC_METER).setNextValue(true); - return; - } - // Found Socomec meter - try { - ModbusUtils.readELementOnce(this.modbusProtocol, new StringWordElement(0xC38A, 8), true) - .thenAccept(name -> { - result.complete(name.toLowerCase()); - }); - - } catch (OpenemsException e) { - this.logWarn(this.log, "Error while trying to identify Socomec meter: " + e.getMessage()); - e.printStackTrace(); - result.complete(""); - } - }); - - } catch (OpenemsException e) { - this.logWarn(this.log, "Error while trying to identify Socomec meter: " + e.getMessage()); - e.printStackTrace(); - result.complete(""); - } + readElementOnce(this.modbusProtocol, ModbusUtils::retryOnNull, new UnsignedQuadruplewordElement(0xC350)) + .thenAccept(value -> { + if (value != 0x0053004F0043004FL /* SOCO */) { + this.channel(SocomecMeter.ChannelId.NO_SOCOMEC_METER).setNextValue(true); + // Complete result with Long value + result.complete(String.valueOf(value)); + } + readElementOnce(this.modbusProtocol, ModbusUtils::retryOnNull, new StringWordElement(0xC38A, 8)) + .thenAccept(name -> { + result.complete(name.toLowerCase()); + }); + }); return result; } diff --git a/io.openems.edge.meter.socomec/src/io/openems/edge/meter/socomec/singlephase/MeterSocomecSinglephaseImpl.java b/io.openems.edge.meter.socomec/src/io/openems/edge/meter/socomec/singlephase/MeterSocomecSinglephaseImpl.java index 36138cea305..04317f76ce8 100644 --- a/io.openems.edge.meter.socomec/src/io/openems/edge/meter/socomec/singlephase/MeterSocomecSinglephaseImpl.java +++ b/io.openems.edge.meter.socomec/src/io/openems/edge/meter/socomec/singlephase/MeterSocomecSinglephaseImpl.java @@ -60,7 +60,7 @@ protected void setModbus(BridgeModbus modbus) { private Config config; - public MeterSocomecSinglephaseImpl() throws OpenemsException { + public MeterSocomecSinglephaseImpl() { super(// OpenemsComponent.ChannelId.values(), // ModbusComponent.ChannelId.values(), // diff --git a/io.openems.edge.meter.socomec/src/io/openems/edge/meter/socomec/threephase/MeterSocomecThreephaseImpl.java b/io.openems.edge.meter.socomec/src/io/openems/edge/meter/socomec/threephase/MeterSocomecThreephaseImpl.java index 2116d69b3bb..5152fbde0a0 100644 --- a/io.openems.edge.meter.socomec/src/io/openems/edge/meter/socomec/threephase/MeterSocomecThreephaseImpl.java +++ b/io.openems.edge.meter.socomec/src/io/openems/edge/meter/socomec/threephase/MeterSocomecThreephaseImpl.java @@ -58,7 +58,7 @@ protected void setModbus(BridgeModbus modbus) { private Config config; - public MeterSocomecThreephaseImpl() throws OpenemsException { + public MeterSocomecThreephaseImpl() { super(// OpenemsComponent.ChannelId.values(), // ModbusComponent.ChannelId.values(), // diff --git a/io.openems.edge.meter.sunspec/src/io/openems/edge/meter/sunspec/AbstractSunSpecMeter.java b/io.openems.edge.meter.sunspec/src/io/openems/edge/meter/sunspec/AbstractSunSpecMeter.java index f188d986c06..e5c8c0e8365 100644 --- a/io.openems.edge.meter.sunspec/src/io/openems/edge/meter/sunspec/AbstractSunSpecMeter.java +++ b/io.openems.edge.meter.sunspec/src/io/openems/edge/meter/sunspec/AbstractSunSpecMeter.java @@ -33,7 +33,7 @@ public abstract class AbstractSunSpecMeter extends AbstractOpenemsSunSpecCompone public AbstractSunSpecMeter(Map activeModels, io.openems.edge.common.channel.ChannelId[] firstInitialChannelIds, - io.openems.edge.common.channel.ChannelId[]... furtherInitialChannelIds) throws OpenemsException { + io.openems.edge.common.channel.ChannelId[]... furtherInitialChannelIds) { super(activeModels, firstInitialChannelIds, furtherInitialChannelIds); } diff --git a/io.openems.edge.meter.weidmueller/src/io/openems/edge/meter/weidmueller/MeterWeidmueller525Impl.java b/io.openems.edge.meter.weidmueller/src/io/openems/edge/meter/weidmueller/MeterWeidmueller525Impl.java index 0dfbec080a0..4dd38b5e0a3 100644 --- a/io.openems.edge.meter.weidmueller/src/io/openems/edge/meter/weidmueller/MeterWeidmueller525Impl.java +++ b/io.openems.edge.meter.weidmueller/src/io/openems/edge/meter/weidmueller/MeterWeidmueller525Impl.java @@ -81,7 +81,7 @@ public MeterType getMeterType() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this, // new FC3ReadRegistersTask(19000, Priority.HIGH, // m(ElectricityMeter.ChannelId.VOLTAGE_L1, new FloatDoublewordElement(19000)), // diff --git a/io.openems.edge.meter.ziehl/src/io/openems/edge/meter/ziehl/efr4001ip/MeterZiehlEfr4001IpImpl.java b/io.openems.edge.meter.ziehl/src/io/openems/edge/meter/ziehl/efr4001ip/MeterZiehlEfr4001IpImpl.java index c4d4e7c398c..e6d852fcd0d 100644 --- a/io.openems.edge.meter.ziehl/src/io/openems/edge/meter/ziehl/efr4001ip/MeterZiehlEfr4001IpImpl.java +++ b/io.openems.edge.meter.ziehl/src/io/openems/edge/meter/ziehl/efr4001ip/MeterZiehlEfr4001IpImpl.java @@ -83,7 +83,7 @@ protected void deactivate() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { final var startingRegister = 0x00B0; // 0x0000 for EFR4000IP final var startingRegisterFeedIn = 0x0156; // 0x0084 for EFR4000IP var modbusProtocol = new ModbusProtocol(this, // diff --git a/io.openems.edge.pvinverter.fronius/src/io/openems/edge/pvinverter/fronius/PvInverterFroniusImpl.java b/io.openems.edge.pvinverter.fronius/src/io/openems/edge/pvinverter/fronius/PvInverterFroniusImpl.java index aaa2e9c45ee..1973b591a74 100644 --- a/io.openems.edge.pvinverter.fronius/src/io/openems/edge/pvinverter/fronius/PvInverterFroniusImpl.java +++ b/io.openems.edge.pvinverter.fronius/src/io/openems/edge/pvinverter/fronius/PvInverterFroniusImpl.java @@ -71,7 +71,7 @@ protected void setModbus(BridgeModbus modbus) { super.setModbus(modbus); } - public PvInverterFroniusImpl() throws OpenemsException { + public PvInverterFroniusImpl() { super(// ACTIVE_MODELS, // OpenemsComponent.ChannelId.values(), // diff --git a/io.openems.edge.pvinverter.kaco.blueplanet/src/io/openems/edge/pvinverter/kaco/blueplanet/PvInverterKacoBlueplanetImpl.java b/io.openems.edge.pvinverter.kaco.blueplanet/src/io/openems/edge/pvinverter/kaco/blueplanet/PvInverterKacoBlueplanetImpl.java index 68959240db1..da46c61fa7a 100644 --- a/io.openems.edge.pvinverter.kaco.blueplanet/src/io/openems/edge/pvinverter/kaco/blueplanet/PvInverterKacoBlueplanetImpl.java +++ b/io.openems.edge.pvinverter.kaco.blueplanet/src/io/openems/edge/pvinverter/kaco/blueplanet/PvInverterKacoBlueplanetImpl.java @@ -92,7 +92,7 @@ protected void setModbus(BridgeModbus modbus) { super.setModbus(modbus); } - public PvInverterKacoBlueplanetImpl() throws OpenemsException { + public PvInverterKacoBlueplanetImpl() { super(// ACTIVE_MODELS, // true /* enable manuel calculation of ActiveProductionEnergy */, // diff --git a/io.openems.edge.pvinverter.kostal/src/io/openems/edge/pvinverter/kostal/PvInverterKostalImpl.java b/io.openems.edge.pvinverter.kostal/src/io/openems/edge/pvinverter/kostal/PvInverterKostalImpl.java index 382e2dd37d7..e066097a383 100644 --- a/io.openems.edge.pvinverter.kostal/src/io/openems/edge/pvinverter/kostal/PvInverterKostalImpl.java +++ b/io.openems.edge.pvinverter.kostal/src/io/openems/edge/pvinverter/kostal/PvInverterKostalImpl.java @@ -73,7 +73,7 @@ protected void setModbus(BridgeModbus modbus) { super.setModbus(modbus); } - public PvInverterKostalImpl() throws OpenemsException { + public PvInverterKostalImpl() { super(// ACTIVE_MODELS, // OpenemsComponent.ChannelId.values(), // diff --git a/io.openems.edge.pvinverter.sma/src/io/openems/edge/pvinverter/sma/PvInverterSmaSunnyTripowerImpl.java b/io.openems.edge.pvinverter.sma/src/io/openems/edge/pvinverter/sma/PvInverterSmaSunnyTripowerImpl.java index aa0bf81cc43..1f08127e275 100644 --- a/io.openems.edge.pvinverter.sma/src/io/openems/edge/pvinverter/sma/PvInverterSmaSunnyTripowerImpl.java +++ b/io.openems.edge.pvinverter.sma/src/io/openems/edge/pvinverter/sma/PvInverterSmaSunnyTripowerImpl.java @@ -100,7 +100,7 @@ protected void setModbus(BridgeModbus modbus) { super.setModbus(modbus); } - public PvInverterSmaSunnyTripowerImpl() throws OpenemsException { + public PvInverterSmaSunnyTripowerImpl() { super(// ACTIVE_MODELS, // OpenemsComponent.ChannelId.values(), // diff --git a/io.openems.edge.pvinverter.solarlog/src/io/openems/edge/pvinverter/solarlog/PvInverterSolarlogImpl.java b/io.openems.edge.pvinverter.solarlog/src/io/openems/edge/pvinverter/solarlog/PvInverterSolarlogImpl.java index b8a9e29c21b..cf8c62c0da1 100644 --- a/io.openems.edge.pvinverter.solarlog/src/io/openems/edge/pvinverter/solarlog/PvInverterSolarlogImpl.java +++ b/io.openems.edge.pvinverter.solarlog/src/io/openems/edge/pvinverter/solarlog/PvInverterSolarlogImpl.java @@ -114,7 +114,7 @@ protected void deactivate() { } @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this, // new FC4ReadInputRegistersTask(3500, Priority.HIGH, m(PvInverterSolarlog.ChannelId.LAST_UPDATE_TIME, diff --git a/io.openems.edge.pvinverter.sunspec/src/io/openems/edge/pvinverter/sunspec/AbstractSunSpecPvInverter.java b/io.openems.edge.pvinverter.sunspec/src/io/openems/edge/pvinverter/sunspec/AbstractSunSpecPvInverter.java index b35a1e10f49..34ff14dc35d 100644 --- a/io.openems.edge.pvinverter.sunspec/src/io/openems/edge/pvinverter/sunspec/AbstractSunSpecPvInverter.java +++ b/io.openems.edge.pvinverter.sunspec/src/io/openems/edge/pvinverter/sunspec/AbstractSunSpecPvInverter.java @@ -57,6 +57,7 @@ private static enum InverterType { SINGLE_PHASE(S_101, S_111), // SPLIT_PHASE(S_102, S_112), // THREE_PHASE(S_103, S_113); + // TODO evaluate S701_ACType if block 701 is used private final List blocks; @@ -75,14 +76,14 @@ private InverterType(DefaultSunSpecModel... blocks) { public AbstractSunSpecPvInverter(Map activeModels, io.openems.edge.common.channel.ChannelId[] firstInitialChannelIds, - io.openems.edge.common.channel.ChannelId[]... furtherInitialChannelIds) throws OpenemsException { + io.openems.edge.common.channel.ChannelId[]... furtherInitialChannelIds) { this(activeModels, false, firstInitialChannelIds, furtherInitialChannelIds); } public AbstractSunSpecPvInverter(Map activeModels, boolean calculateActiveProductionEnergyManually, io.openems.edge.common.channel.ChannelId[] firstInitialChannelIds, - io.openems.edge.common.channel.ChannelId[]... furtherInitialChannelIds) throws OpenemsException { + io.openems.edge.common.channel.ChannelId[]... furtherInitialChannelIds) { super(activeModels, firstInitialChannelIds, furtherInitialChannelIds); this.calculateActiveProductionEnergyManually = calculateActiveProductionEnergyManually; this._setActiveConsumptionEnergy(0); @@ -322,7 +323,7 @@ protected void onSunSpecInitializationCompleted() { } @Override - protected void addBlock(int startAddress, SunSpecModel model, Priority priority) throws OpenemsException { + protected void addBlock(int startAddress, SunSpecModel model, Priority priority) { super.addBlock(startAddress, model, priority); // Can we evaluate the InverterType from this Block? diff --git a/io.openems.edge.solaredge/src/io/openems/edge/solaredge/gridmeter/SolarEdgeGridMeterImpl.java b/io.openems.edge.solaredge/src/io/openems/edge/solaredge/gridmeter/SolarEdgeGridMeterImpl.java index 0fb0dc646ca..fdb83a0ae8f 100644 --- a/io.openems.edge.solaredge/src/io/openems/edge/solaredge/gridmeter/SolarEdgeGridMeterImpl.java +++ b/io.openems.edge.solaredge/src/io/openems/edge/solaredge/gridmeter/SolarEdgeGridMeterImpl.java @@ -64,7 +64,7 @@ protected void setModbus(BridgeModbus modbus) { private Config config; - public SolarEdgeGridMeterImpl() throws OpenemsException { + public SolarEdgeGridMeterImpl() { super(// ACTIVE_MODELS, // OpenemsComponent.ChannelId.values(), // diff --git a/io.openems.edge.solaredge/src/io/openems/edge/solaredge/pvinverter/SolarEdgePvInverterImpl.java b/io.openems.edge.solaredge/src/io/openems/edge/solaredge/pvinverter/SolarEdgePvInverterImpl.java index 721120a5fdf..b8712b27a04 100644 --- a/io.openems.edge.solaredge/src/io/openems/edge/solaredge/pvinverter/SolarEdgePvInverterImpl.java +++ b/io.openems.edge.solaredge/src/io/openems/edge/solaredge/pvinverter/SolarEdgePvInverterImpl.java @@ -81,7 +81,7 @@ protected void setModbus(BridgeModbus modbus) { super.setModbus(modbus); } - public SolarEdgePvInverterImpl() throws OpenemsException { + public SolarEdgePvInverterImpl() { super(// ACTIVE_MODELS, // OpenemsComponent.ChannelId.values(), // diff --git a/io.openems.edge.timedata.api/src/io/openems/edge/timedata/api/Timedata.java b/io.openems.edge.timedata.api/src/io/openems/edge/timedata/api/Timedata.java index 36fe7b9595e..e581eb800a4 100644 --- a/io.openems.edge.timedata.api/src/io/openems/edge/timedata/api/Timedata.java +++ b/io.openems.edge.timedata.api/src/io/openems/edge/timedata/api/Timedata.java @@ -10,6 +10,7 @@ import com.google.gson.JsonElement; +import io.openems.common.channel.Unit; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.timedata.CommonTimedataService; import io.openems.common.types.ChannelAddress; @@ -41,6 +42,23 @@ public Doc doc() { */ public CompletableFuture> getLatestValue(ChannelAddress channelAddress); + /** + * Gets the latest known value for the given {@link ChannelAddress} of a not + * existing channel. + * + *

    + * Gets the latest known value even if the ChannelAddress is not longer + * existing. + * + * @param channelAddress the ChannelAddress to be queried + * @param unit unit + * @return the latest known value or Empty + */ + public default CompletableFuture> getLatestValueOfNotExistingChannel(ChannelAddress channelAddress, + Unit unit) { + return CompletableFuture.completedFuture(Optional.empty()); + } + /** * Gets the {@link Timeranges} to data which got not send. The not send data * gets determined with the notSendChannel and the lastResendTimestamp. diff --git a/io.openems.edge.timedata.api/src/io/openems/edge/timedata/api/utils/CalculateEnergyFromPower.java b/io.openems.edge.timedata.api/src/io/openems/edge/timedata/api/utils/CalculateEnergyFromPower.java index 1a38462b260..49d0100f04b 100644 --- a/io.openems.edge.timedata.api/src/io/openems/edge/timedata/api/utils/CalculateEnergyFromPower.java +++ b/io.openems.edge.timedata.api/src/io/openems/edge/timedata/api/utils/CalculateEnergyFromPower.java @@ -190,4 +190,17 @@ private void calculateEnergy() { // update 'cumulatedEnergy' this.component.channel(this.channelId).setNextValue(this.baseCumulatedEnergy); } + + /** + * Set baseEnergy manually. + * + *

    + * Set baseEnergy manually & go to CALCULATE_ENERGY_OPERATION + * + * @param baseCumulatedEnergy baseCumulatedEnergy + */ + public void setBaseEnergyManually(long baseCumulatedEnergy) { + this.baseCumulatedEnergy = baseCumulatedEnergy; + this.state = State.CALCULATE_ENERGY_OPERATION; + } } diff --git a/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/Rrd4jReadHandler.java b/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/Rrd4jReadHandler.java index abba6d9c364..6747b3b96d9 100644 --- a/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/Rrd4jReadHandler.java +++ b/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/Rrd4jReadHandler.java @@ -28,6 +28,7 @@ import com.google.gson.JsonNull; import com.google.gson.JsonPrimitive; +import io.openems.common.channel.Unit; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; import io.openems.common.timedata.Resolution; @@ -565,6 +566,48 @@ public CompletableFuture> getLatestValue(// }); } + /** + * Gets the latest known value for the given {@link ChannelAddress} of a not + * existing channel. + * + *

    + * Gets the latest known value even if the ChannelAddress is not longer + * existing. + * + * @param rrdDbId the id of the rrdb + * @param channelAddress the ChannelAddress to be queried + * @param unit unit + * @return the latest known value or Empty + */ + public CompletableFuture> getLatestValueOfNotExistingChannel(// + final String rrdDbId, // + final ChannelAddress channelAddress, // + final Unit unit // + ) { + return CompletableFuture.supplyAsync(() -> { + + try (var database = this.rrd4jSupplier.getExistingUpdatedRrdDb(rrdDbId, channelAddress, unit)) { + if (database == null) { + return Optional.empty(); + } + + // search for last value in robin + final var robin = database.getArchive(0).getRobin(0); + for (int i = robin.getSize() - 1; i >= 0; i--) { + final var value = robin.getValue(i); + if (Double.isNaN(value)) { + continue; + } + return Optional.of(value); + } + + return Optional.empty(); + } catch (Exception e) { + return Optional.empty(); + } + }); + } + private static double getFirstValueBefore(RrdDb database, long endTimestamp) throws IOException { final var archive = database.getArchive(0); if (archive.getStartTime() > endTimestamp) { diff --git a/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/Rrd4jSupplier.java b/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/Rrd4jSupplier.java index 8efc38568d3..fc0d4f2b50b 100644 --- a/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/Rrd4jSupplier.java +++ b/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/Rrd4jSupplier.java @@ -10,6 +10,7 @@ import java.util.Arrays; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.function.BiFunction; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; @@ -40,7 +41,7 @@ ) public class Rrd4jSupplier { - private final Logger log = LoggerFactory.getLogger(this.getClass()); + private final Logger log = LoggerFactory.getLogger(Rrd4jSupplier.class); @Reference private VersionHandler versionHandler; @@ -48,15 +49,29 @@ public class Rrd4jSupplier { private final KeyLock keyLock = new KeyLock(); private final RrdBackendFactory factory; + // channelAddress, rrdDbId => file path + private final BiFunction fileValidator; + protected Rrd4jSupplier(// - final RrdBackendFactory factory // + final RrdBackendFactory factory, // + final BiFunction fileValidator // ) { this.factory = factory; + this.fileValidator = fileValidator; } @Activate public Rrd4jSupplier() { - this(new RrdRandomAccessFileBackendFactory()); + this(// + new RrdRandomAccessFileBackendFactory(), // + (t, u) -> { + final var file = getDbFile(t, u); + if (!file.exists()) { + return null; + } + return file.toURI().toString(); + } // + ); } /** @@ -123,7 +138,7 @@ public RrdDb getExistingUpdatedRrdDb(// */ public static ChannelDef getDsDefForChannel(final Unit channelUnit) { return switch (channelUnit) { - case AMPERE, AMPERE_HOURS, DEGREE_CELSIUS, DEZIDEGREE_CELSIUS, EUROS_PER_MEGAWATT_HOUR, HERTZ, HOUR, + case AMPERE, AMPERE_HOURS, DEGREE_CELSIUS, DEZIDEGREE_CELSIUS, MONEY_PER_MEGAWATT_HOUR, HERTZ, HOUR, KILOAMPERE_HOURS, KILOOHM, KILOVOLT_AMPERE, KILOVOLT_AMPERE_REACTIVE, KILOWATT, MICROOHM, MICROAMPERE, MICROVOLT, MILLIAMPERE_HOURS, MILLIAMPERE, MILLIHERTZ, MILLIOHM, MILLISECONDS, MILLIVOLT, MILLIWATT, MINUTE, NONE, WATT, VOLT, VOLT_AMPERE, VOLT_AMPERE_REACTIVE, WATT_HOURS_BY_WATT_PEAK, OHM, SECONDS, @@ -148,8 +163,8 @@ private RrdDb getExistingRrdDb(// final ChannelAddress channelAddress, // final String rrdDbId // ) { - var file = getDbFile(channelAddress, rrdDbId); - if (!file.exists()) { + final var filePath = this.fileValidator.apply(channelAddress, rrdDbId); + if (filePath == null) { return null; } try { @@ -158,7 +173,7 @@ private RrdDb getExistingRrdDb(// // .setPool(RrdDbPool.getInstance()) // // ^^ is not used anymore because of caching // problems when overwriting the old database file - .setPath(file.toURI()) // + .setPath(filePath) // .build(); } catch (IOException e) { this.log.error("Unable to open existing RrdDb", e); @@ -334,24 +349,19 @@ public static double[] postProcessData(FetchData data, long resolution) "Requested resolution [" + resolution + "] is not dividable by RRD4j Step [" + step + "]"); } var merge = (int) (resolution / step); - var buffer = new double[merge]; - for (var i = 1; i < input.length; i += merge) { + for (int i = 0; i < result.length; i++) { + var buffer = new double[merge]; for (var j = 0; j < merge; j++) { - if (i + j < input.length) { - buffer[j] = input[i + j]; + final var inputIndex = (i * merge) + j; + if (inputIndex < input.length) { + buffer[j] = input[inputIndex]; } else { buffer[j] = Double.NaN; } } - // put in result; avoid index rounding error - var resultIndex = (i - 1) / merge; - if (resultIndex >= result.length) { - break; - } - result[resultIndex] = TypeUtils.average(buffer); + result[i] = TypeUtils.average(buffer); } - } else if (step > resolution) { // Split each entry to multiple values var resultTimestamp = 0; diff --git a/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/TimedataRrd4jImpl.java b/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/TimedataRrd4jImpl.java index e1d6898bcfd..81fd3d0e9e6 100644 --- a/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/TimedataRrd4jImpl.java +++ b/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/TimedataRrd4jImpl.java @@ -19,6 +19,7 @@ import com.google.gson.JsonElement; +import io.openems.common.channel.Unit; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.timedata.Resolution; import io.openems.common.types.ChannelAddress; @@ -138,6 +139,12 @@ public CompletableFuture> getLatestValue(ChannelAddress channel return this.readHandler.getLatestValue(this.id(), channelAddress); } + @Override + public CompletableFuture> getLatestValueOfNotExistingChannel(ChannelAddress channelAddress, + Unit unit) { + return this.readHandler.getLatestValueOfNotExistingChannel(this.id(), channelAddress, unit); + } + @Override public void handleEvent(Event event) { if (!this.isEnabled()) { diff --git a/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/version/VersionHandler.java b/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/version/VersionHandler.java index f06ad16ad66..c6c598ead39 100644 --- a/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/version/VersionHandler.java +++ b/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/version/VersionHandler.java @@ -44,12 +44,17 @@ public static int getVersion(RrdDb db) throws IOException { private final List versions = new ArrayList<>(); + /** + * Binds a {@link Version} to this current handler. + * + * @param version the {@link Version} to bind + */ @Reference(// policy = ReferencePolicy.DYNAMIC, // cardinality = ReferenceCardinality.MULTIPLE, // bind = "bindVersion", unbind = "unbindVersion" // ) - protected void bindVersion(Version version) { + public void bindVersion(Version version) { // make sure the versions list is sorted by the version number ascending final var insertIndex = Collections.binarySearch(this.versions, version, Version.numberComparator()); if (insertIndex < 0) { @@ -57,7 +62,12 @@ protected void bindVersion(Version version) { } } - protected void unbindVersion(Version version) { + /** + * Unbinds a {@link Version} from this current handler. + * + * @param version the {@link Version} to unbind + */ + public void unbindVersion(Version version) { this.versions.remove(version); } diff --git a/io.openems.edge.timedata.rrd4j/test/io/openems/edge/timedata/rrd4j/Rrd4jReadHandlerTest.java b/io.openems.edge.timedata.rrd4j/test/io/openems/edge/timedata/rrd4j/Rrd4jReadHandlerTest.java index c94a79f0583..635a3035742 100644 --- a/io.openems.edge.timedata.rrd4j/test/io/openems/edge/timedata/rrd4j/Rrd4jReadHandlerTest.java +++ b/io.openems.edge.timedata.rrd4j/test/io/openems/edge/timedata/rrd4j/Rrd4jReadHandlerTest.java @@ -1,43 +1,94 @@ package io.openems.edge.timedata.rrd4j; +import static java.util.stream.Collectors.toMap; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; +import java.util.Arrays; +import java.util.Set; +import java.util.SortedMap; +import java.util.TreeMap; import org.junit.Before; import org.junit.Test; import org.rrd4j.core.RrdBackendFactory; +import org.rrd4j.core.RrdDb; import org.rrd4j.core.RrdMemoryBackendFactory; +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; + import io.openems.common.channel.Unit; +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.timedata.Resolution; +import io.openems.common.types.ChannelAddress; +import io.openems.common.types.OpenemsType; +import io.openems.common.utils.ReflectionUtils; +import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.test.AbstractDummyOpenemsComponent; +import io.openems.edge.common.test.DummyComponentManager; +import io.openems.edge.common.type.Tuple; import io.openems.edge.timedata.rrd4j.version.Version.CreateDatabaseConfig; import io.openems.edge.timedata.rrd4j.version.Version3Test; +import io.openems.edge.timedata.rrd4j.version.VersionHandler; public class Rrd4jReadHandlerTest { // starts at 1. January 2020 00:00:00 private static final Instant START = Instant.ofEpochSecond(1577836800L); + private final String rrdbId = "rrdbId"; private RrdBackendFactory factory; + private RrdDb db; + private Rrd4jReadHandler readHandler; + private DummyComponent dummyComponent; @Before public void setUp() throws Exception { this.factory = new RrdMemoryBackendFactory(); - } - - @Test - public void testGetArchivesSortedByArcStep() throws Exception { final var version3 = Version3Test.createDummyVersion3(); - final var db = version3.createNewDb(new CreateDatabaseConfig(// - "rrdbId", // - Unit.WATT_HOURS, // - "path", // - START.getEpochSecond(), // + this.db = version3.createNewDb(new CreateDatabaseConfig(// + this.rrdbId, // + Unit.WATT, // + "comp0/DummyChannel", // + START.getEpochSecond() - 1, // this.factory, // null // )); - final var sorted = Rrd4jReadHandler.getArchivesSortedByArcStep(db); + final var robin = this.db.getArchive(0).getRobin(0); + for (int i = 0; i < robin.getSize(); i++) { + final var value = i * 100; + this.db.createSample(START.plus(5 * i, ChronoUnit.MINUTES).getEpochSecond()) // + .setValues(value) // + .update(); + } + + this.readHandler = new Rrd4jReadHandler(); + final var dcm = new DummyComponentManager(); + this.dummyComponent = new DummyComponent("comp0"); + dcm.addComponent(this.dummyComponent); + final var rrd4jSupplier = new Rrd4jSupplier(this.factory, (t, u) -> { + return t.toString(); + }); + + final var versionHandler = new VersionHandler(); + versionHandler.bindVersion(version3); + + ReflectionUtils.setAttribute(Rrd4jReadHandler.class, this.readHandler, "componentManager", dcm); + ReflectionUtils.setAttribute(Rrd4jReadHandler.class, this.readHandler, "rrd4jSupplier", rrd4jSupplier); + ReflectionUtils.setAttribute(Rrd4jSupplier.class, rrd4jSupplier, "versionHandler", versionHandler); + + } + + @Test + public void testGetArchivesSortedByArcStep() throws Exception { + final var sorted = Rrd4jReadHandler.getArchivesSortedByArcStep(this.db); long lastStepSize = 0L; for (var archive : sorted) { assertTrue("The last step size should be lower than the next step size.", @@ -47,4 +98,121 @@ public void testGetArchivesSortedByArcStep() throws Exception { } + @Test + public void testQueryHistoricDataWithResolution1minutes() throws Exception { + assertEquals(values(// + Tuple.of(START.plus(0, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 0), // + Tuple.of(START.plus(1, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 0), // + Tuple.of(START.plus(2, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 0), // + Tuple.of(START.plus(3, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 0), // + Tuple.of(START.plus(4, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 0), // + Tuple.of(START.plus(5, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 100), // + Tuple.of(START.plus(6, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 100), // + Tuple.of(START.plus(7, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 100), // + Tuple.of(START.plus(8, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 100), // + Tuple.of(START.plus(9, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 100), // + Tuple.of(START.plus(10, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 200), // + Tuple.of(START.plus(11, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 200), // + Tuple.of(START.plus(12, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 200), // + Tuple.of(START.plus(13, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 200), // + Tuple.of(START.plus(14, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 200), // + Tuple.of(START.plus(15, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 300), // + Tuple.of(START.plus(16, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 300), // + Tuple.of(START.plus(17, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 300), // + Tuple.of(START.plus(18, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 300), // + Tuple.of(START.plus(19, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 300), // + Tuple.of(START.plus(20, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 400), // + Tuple.of(START.plus(21, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 400), // + Tuple.of(START.plus(22, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 400), // + Tuple.of(START.plus(23, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 400), // + Tuple.of(START.plus(24, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 400), // + Tuple.of(START.plus(25, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 500), // + Tuple.of(START.plus(26, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 500), // + Tuple.of(START.plus(27, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 500), // + Tuple.of(START.plus(28, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 500), // + Tuple.of(START.plus(29, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 500) // + ), this.query(new Resolution(1, ChronoUnit.MINUTES))); + } + + @Test + public void testQueryHistoricDataWithResolution5minutes() throws Exception { + assertEquals(values(// + Tuple.of(START.plus(0, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 0), // + Tuple.of(START.plus(5, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 100), // + Tuple.of(START.plus(10, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 200), // + Tuple.of(START.plus(15, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 300), // + Tuple.of(START.plus(20, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 400), // + Tuple.of(START.plus(25, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 500) // + ), this.query(new Resolution(5, ChronoUnit.MINUTES))); + } + + @Test + public void testQueryHistoricDataWithResolution10minutes() throws Exception { + assertEquals(values(// + Tuple.of(START.plus(0, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 50), // + Tuple.of(START.plus(10, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 250), // + Tuple.of(START.plus(20, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 450) // + ), this.query(new Resolution(10, ChronoUnit.MINUTES))); + } + + @Test + public void testQueryHistoricDataWithResolution15minutes() throws Exception { + assertEquals(values(// + Tuple.of(START.plus(0, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 100), // + Tuple.of(START.plus(15, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), 400) // + ), this.query(new Resolution(15, ChronoUnit.MINUTES))); + } + + private SortedMap> query(Resolution resolution) + throws IllegalArgumentException, OpenemsNamedException { + return this.readHandler.queryHistoricData(this.rrdbId, // + START.atZone(ZoneId.of("UTC")), // + START.plus(30, ChronoUnit.MINUTES).atZone(ZoneId.of("UTC")), // + Set.of(this.dummyComponent.channel(DummyComponent.ChannelId.DUMMY_CHANNEL).address()), // + resolution, false); + } + + @SafeVarargs + private SortedMap> values( + Tuple... values) { + return Arrays.stream(values) // + .collect(toMap(Tuple::a, t -> { + final var valueMap = new TreeMap(); + valueMap.put(this.dummyComponent.channel(DummyComponent.ChannelId.DUMMY_CHANNEL).address(), + new JsonPrimitive(t.b())); + return valueMap; + }, (t, u) -> u, TreeMap::new)); + } + + private class DummyComponent extends AbstractDummyOpenemsComponent implements OpenemsComponent { + + public enum ChannelId implements io.openems.edge.common.channel.ChannelId { + DUMMY_CHANNEL(Doc.of(OpenemsType.INTEGER)); // + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } + + public DummyComponent(String id) { + super(id, // + OpenemsComponent.ChannelId.values(), // + ChannelId.values() // + ); + } + + @Override + protected DummyComponent self() { + return this; + } + + } + } diff --git a/io.openems.edge.timedata.rrd4j/test/io/openems/edge/timedata/rrd4j/TimedataRrd4jImplTest.java b/io.openems.edge.timedata.rrd4j/test/io/openems/edge/timedata/rrd4j/TimedataRrd4jImplTest.java index 52a2c9d45ee..980994dfb48 100644 --- a/io.openems.edge.timedata.rrd4j/test/io/openems/edge/timedata/rrd4j/TimedataRrd4jImplTest.java +++ b/io.openems.edge.timedata.rrd4j/test/io/openems/edge/timedata/rrd4j/TimedataRrd4jImplTest.java @@ -87,9 +87,9 @@ public void testMerge() throws IOException, URISyntaxException { database.close(); assertEquals(12, result.length); // 3 hours * 4 entries/per hour (15 minutes) = 12 - assertEquals(8.0, result[0], 0.1); - assertEquals(23.0, result[1], 0.1); - assertEquals(38.0, result[2], 0.1); + assertEquals((0 + 3 + 8) / 3.0, result[0], 0.1); + assertEquals((13 + 18 + 23) / 3.0, result[1], 0.1); + assertEquals((28 + 33 + 38) / 3.0, result[2], 0.1); } /** diff --git a/tools/prepare-commit.sh b/tools/prepare-commit.sh index 2f09b2e951b..62e4a91d8ed 100755 --- a/tools/prepare-commit.sh +++ b/tools/prepare-commit.sh @@ -194,3 +194,15 @@ head -n $(grep -n '\-runbundles:' "$bndrun.new" | grep -Eo '^[^:]+' | head -n1) rm "$bndrun.new" ./gradlew resolve.BackendApp +# Build + test UI +cd ui +npm install +node_modules/.bin/ng lint --fix +node_modules/.bin/tsc +node_modules/.bin/tsc-strict +node_modules/.bin/ng build -c "fenecon,fenecon-backend-prod,prod" +npm run test -- --no-watch --no-progress --browsers=ChromeHeadlessCI +cd .. + +echo +echo "Finished" \ No newline at end of file diff --git a/ui/.vscode/settings.json b/ui/.vscode/settings.json index c854b790a8b..ca17a9ba2dd 100644 --- a/ui/.vscode/settings.json +++ b/ui/.vscode/settings.json @@ -22,5 +22,14 @@ "files.eol": "\n", "files.insertFinalNewline": true, "editor.defaultFormatter": "dbaeumer.vscode-eslint", - "eslint.format.enable": true + "eslint.format.enable": true, + "[typescript]": { + "editor.defaultFormatter": "vscode.typescript-language-features" + }, + "[jsonc]": { + "editor.defaultFormatter": "vscode.json-language-features" + }, + "[json]": { + "editor.defaultFormatter": "vscode.json-language-features" + } } diff --git a/ui/package-lock.json b/ui/package-lock.json index 0627e3411ec..85710afd431 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1,17026 +1,19373 @@ { - "name": "openems-ui", - "version": "2024.5.0-SNAPSHOT", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "openems-ui", - "version": "2024.5.0-SNAPSHOT", - "license": "AGPL-3.0", - "dependencies": { - "@angular/animations": "~15.2.9", - "@angular/cdk": "~15.2.9", - "@angular/common": "~15.2.9", - "@angular/core": "~15.2.9", - "@angular/forms": "~15.2.9", - "@angular/platform-browser": "~15.2.9", - "@angular/platform-browser-dynamic": "~15.2.9", - "@angular/router": "~15.2.9", - "@angular/service-worker": "~15.2.9", - "@ionic/angular": "^6.7.4", - "@ngx-formly/core": "^6.1.7", - "@ngx-formly/ionic": "^6.1.7", - "@ngx-formly/schematics": "^6.1.7", - "@ngx-translate/core": "^14.0.0", - "angular-mydatepicker": "^0.11.5", - "chart.js": "^4.4.0", - "chartjs-adapter-date-fns": "^3.0.0", - "chartjs-plugin-zoom": "^2.0.1", - "classlist.js": "^1.1.20150312", - "compare-versions": "^6.1.0", - "d3": "^7.9.0", - "date-fns": "^2.30.0", - "file-saver-es": "^2.0.5", - "ng2-charts": "4.1.1", - "ngx-cookie-service": "^15.0.0", - "ngx-spinner": "^15.0.1", - "roboto-fontface": "^0.10.0", - "rxjs": "~6.6.7", - "tslib": "^2.5.0", - "uuid": "^9.0.0", - "zone.js": "~0.13.0" - }, - "devDependencies": { - "@angular-devkit/build-angular": "^15.2.8", - "@angular-eslint/builder": "~15.2.1", - "@angular-eslint/eslint-plugin": "~15.2.1", - "@angular-eslint/eslint-plugin-template": "~15.2.1", - "@angular-eslint/template-parser": "~15.2.1", - "@angular/cli": "~15.2.8", - "@angular/compiler": "~15.2.9", - "@angular/compiler-cli": "~15.2.9", - "@angular/language-service": "~15.2.9", - "@ionic/angular-toolkit": "^7.0.0", - "@types/jasmine": "~4.3.2", - "@types/jasminewd2": "~2.0.10", - "@types/node": "^20.2.5", - "@types/uuid": "^9.0.2", - "@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": "^3.1.0", - "jasmine-core": "~4.5.0", - "jasmine-spec-reporter": "~7.0.0", - "karma": "~6.4.2", - "karma-chrome-launcher": "~3.2.0", - "karma-coverage": "~2.2.0", - "karma-coverage-istanbul-reporter": "~3.0.3", - "karma-jasmine": "~5.1.0", - "karma-jasmine-html-reporter": "^2.0.0", - "protractor": "~7.0.0", - "ts-node": "~10.9.1", - "typescript": "~4.9.5" - } - }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@angular-devkit/architect": { - "version": "0.1502.9", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1502.9.tgz", - "integrity": "sha512-CFn+LbtYeLG7WqO+BBSjogl764StHpwgfJnNAXQ/3UouUktZ92z4lxhUm0PwIPb5k0lILsf81ubcS1vzwoXEEg==", - "dev": true, - "dependencies": { - "@angular-devkit/core": "15.2.9", - "rxjs": "6.6.7" - }, - "engines": { - "node": "^14.20.0 || ^16.13.0 || >=18.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@angular-devkit/build-angular": { - "version": "15.2.9", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-15.2.9.tgz", - "integrity": "sha512-djOo2Q22zLrxPccSbINz93hD+pES/nNPoze4Ys/0IdtMlLmxO/YGsA+FG5eNeNAf2jK/JRoNydaYOh7XpGoCzA==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "2.2.0", - "@angular-devkit/architect": "0.1502.9", - "@angular-devkit/build-webpack": "0.1502.9", - "@angular-devkit/core": "15.2.9", - "@babel/core": "7.20.12", - "@babel/generator": "7.20.14", - "@babel/helper-annotate-as-pure": "7.18.6", - "@babel/helper-split-export-declaration": "7.18.6", - "@babel/plugin-proposal-async-generator-functions": "7.20.7", - "@babel/plugin-transform-async-to-generator": "7.20.7", - "@babel/plugin-transform-runtime": "7.19.6", - "@babel/preset-env": "7.20.2", - "@babel/runtime": "7.20.13", - "@babel/template": "7.20.7", - "@discoveryjs/json-ext": "0.5.7", - "@ngtools/webpack": "15.2.9", - "ansi-colors": "4.1.3", - "autoprefixer": "10.4.13", - "babel-loader": "9.1.2", - "babel-plugin-istanbul": "6.1.1", - "browserslist": "4.21.5", - "cacache": "17.0.4", - "chokidar": "3.5.3", - "copy-webpack-plugin": "11.0.0", - "critters": "0.0.16", - "css-loader": "6.7.3", - "esbuild-wasm": "0.17.8", - "glob": "8.1.0", - "https-proxy-agent": "5.0.1", - "inquirer": "8.2.4", - "jsonc-parser": "3.2.0", - "karma-source-map-support": "1.4.0", - "less": "4.1.3", - "less-loader": "11.1.0", - "license-webpack-plugin": "4.0.2", - "loader-utils": "3.2.1", - "magic-string": "0.29.0", - "mini-css-extract-plugin": "2.7.2", - "open": "8.4.1", - "ora": "5.4.1", - "parse5-html-rewriting-stream": "7.0.0", - "piscina": "3.2.0", - "postcss": "8.4.21", - "postcss-loader": "7.0.2", - "resolve-url-loader": "5.0.0", - "rxjs": "6.6.7", - "sass": "1.58.1", - "sass-loader": "13.2.0", - "semver": "7.5.3", - "source-map-loader": "4.0.1", - "source-map-support": "0.5.21", - "terser": "5.16.3", - "text-table": "0.2.0", - "tree-kill": "1.2.2", - "tslib": "2.5.0", - "webpack": "5.76.1", - "webpack-dev-middleware": "6.0.1", - "webpack-dev-server": "4.11.1", - "webpack-merge": "5.8.0", - "webpack-subresource-integrity": "5.1.0" - }, - "engines": { - "node": "^14.20.0 || ^16.13.0 || >=18.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "optionalDependencies": { - "esbuild": "0.17.8" - }, - "peerDependencies": { - "@angular/compiler-cli": "^15.0.0", - "@angular/localize": "^15.0.0", - "@angular/platform-server": "^15.0.0", - "@angular/service-worker": "^15.0.0", - "karma": "^6.3.0", - "ng-packagr": "^15.0.0", - "protractor": "^7.0.0", - "tailwindcss": "^2.0.0 || ^3.0.0", - "typescript": ">=4.8.2 <5.0" - }, - "peerDependenciesMeta": { - "@angular/localize": { - "optional": true - }, - "@angular/platform-server": { - "optional": true - }, - "@angular/service-worker": { - "optional": true - }, - "karma": { - "optional": true - }, - "ng-packagr": { - "optional": true - }, - "protractor": { - "optional": true - }, - "tailwindcss": { - "optional": true - } - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/esbuild": { - "version": "0.17.8", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.8.tgz", - "integrity": "sha512-g24ybC3fWhZddZK6R3uD2iF/RIPnRpwJAqLov6ouX3hMbY4+tKolP0VMF3zuIYCaXun+yHwS5IPQ91N2BT191g==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/android-arm": "0.17.8", - "@esbuild/android-arm64": "0.17.8", - "@esbuild/android-x64": "0.17.8", - "@esbuild/darwin-arm64": "0.17.8", - "@esbuild/darwin-x64": "0.17.8", - "@esbuild/freebsd-arm64": "0.17.8", - "@esbuild/freebsd-x64": "0.17.8", - "@esbuild/linux-arm": "0.17.8", - "@esbuild/linux-arm64": "0.17.8", - "@esbuild/linux-ia32": "0.17.8", - "@esbuild/linux-loong64": "0.17.8", - "@esbuild/linux-mips64el": "0.17.8", - "@esbuild/linux-ppc64": "0.17.8", - "@esbuild/linux-riscv64": "0.17.8", - "@esbuild/linux-s390x": "0.17.8", - "@esbuild/linux-x64": "0.17.8", - "@esbuild/netbsd-x64": "0.17.8", - "@esbuild/openbsd-x64": "0.17.8", - "@esbuild/sunos-x64": "0.17.8", - "@esbuild/win32-arm64": "0.17.8", - "@esbuild/win32-ia32": "0.17.8", - "@esbuild/win32-x64": "0.17.8" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - }, - "node_modules/@angular-devkit/build-webpack": { - "version": "0.1502.9", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1502.9.tgz", - "integrity": "sha512-VzMXoZjrbL1XlcSegqpZCBDbVvKFGPs3cKp4bXDD5ht95jcCyJPk5FA/wrh0pGGwbOF8ae/XOWFcPRzctC35iA==", - "dev": true, - "dependencies": { - "@angular-devkit/architect": "0.1502.9", - "rxjs": "6.6.7" - }, - "engines": { - "node": "^14.20.0 || ^16.13.0 || >=18.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "webpack": "^5.30.0", - "webpack-dev-server": "^4.0.0" - } - }, - "node_modules/@angular-devkit/core": { - "version": "15.2.9", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-15.2.9.tgz", - "integrity": "sha512-6u44YJ9tEG2hiWITL1rwA9yP6ot4a3cyN/UOMRkYSa/XO2Gz5/dM3U74E2kwg+P1NcxLXffBWl0rz8/Y/lSZyQ==", - "dev": true, - "dependencies": { - "ajv": "8.12.0", - "ajv-formats": "2.1.1", - "jsonc-parser": "3.2.0", - "rxjs": "6.6.7", - "source-map": "0.7.4" - }, - "engines": { - "node": "^14.20.0 || ^16.13.0 || >=18.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^3.5.2" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/@angular-devkit/core/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@angular-devkit/core/node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - }, - "node_modules/@angular-devkit/schematics": { - "version": "15.2.9", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-15.2.9.tgz", - "integrity": "sha512-o08nE8sTpfq/Fknrr1rzBsM8vY36BDox+8dOo9Zc/KqcVPwDy94YKRzHb+xxVaU9jy1VYeCjy63mkyELy7Z3zQ==", - "dev": true, - "dependencies": { - "@angular-devkit/core": "15.2.9", - "jsonc-parser": "3.2.0", - "magic-string": "0.29.0", - "ora": "5.4.1", - "rxjs": "6.6.7" - }, - "engines": { - "node": "^14.20.0 || ^16.13.0 || >=18.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@angular-devkit/schematics/node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - }, - "node_modules/@angular-eslint/builder": { - "version": "15.2.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-15.2.1.tgz", - "integrity": "sha512-7x2DANebLRl997Mj4DhZrnz5+vnSjavGGveJ0mBuU7CEsL0ZYLftdRqL0e0HtU3ksseS7xpchD6OM08nkNgySw==", - "dev": true, - "peerDependencies": { - "eslint": "^7.20.0 || ^8.0.0", - "typescript": "*" - } - }, - "node_modules/@angular-eslint/bundled-angular-compiler": { - "version": "15.2.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-15.2.1.tgz", - "integrity": "sha512-LO7Am8eVCr7oh6a0VmKSL7K03CnQEQhFO7Wt/YtbfYOxVjrbwmYLwJn+wZPOT7A02t/BttOD/WXuDrOWtSMQ/Q==", - "dev": true - }, - "node_modules/@angular-eslint/eslint-plugin": { - "version": "15.2.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-15.2.1.tgz", - "integrity": "sha512-OM7b1kS4E4CkXjkaWN+lEzawh4VxY6l7FO1Cuk4s7iv3/YpZG3rJxIZBqnFLTixwrBuqw8y4FNBzF3eDgmFAUw==", - "dev": true, - "dependencies": { - "@angular-eslint/utils": "15.2.1", - "@typescript-eslint/utils": "5.48.2" - }, - "peerDependencies": { - "eslint": "^7.20.0 || ^8.0.0", - "typescript": "*" - } - }, - "node_modules/@angular-eslint/eslint-plugin-template": { - "version": "15.2.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-15.2.1.tgz", - "integrity": "sha512-IeiSLk6YxapFdH2z5o/O3R7VwtBd2T6fWmhLFPwDYMDknrwegnOjwswCdBplOccpUp0wqlCeGUx7LTsuzwaz7w==", - "dev": true, - "dependencies": { - "@angular-eslint/bundled-angular-compiler": "15.2.1", - "@angular-eslint/utils": "15.2.1", - "@typescript-eslint/type-utils": "5.48.2", - "@typescript-eslint/utils": "5.48.2", - "aria-query": "5.1.3", - "axobject-query": "3.1.1" - }, - "peerDependencies": { - "eslint": "^7.20.0 || ^8.0.0", - "typescript": "*" - } - }, - "node_modules/@angular-eslint/template-parser": { - "version": "15.2.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-15.2.1.tgz", - "integrity": "sha512-ViCi79gC2aKJecmYLkOT+QlT5WMRNXeYz0Dr9Pr8qXzIbY0oAWE7nOT5jkXwQ9oUk+ybtGCWHma5JVJWVJsIog==", - "dev": true, - "dependencies": { - "@angular-eslint/bundled-angular-compiler": "15.2.1", - "eslint-scope": "^7.0.0" - }, - "peerDependencies": { - "eslint": "^7.20.0 || ^8.0.0", - "typescript": "*" - } - }, - "node_modules/@angular-eslint/template-parser/node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@angular-eslint/template-parser/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/@angular-eslint/utils": { - "version": "15.2.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-15.2.1.tgz", - "integrity": "sha512-++FneAJHxJqcSu0igVN6uOkSoHxlzgLoMBswuovYJy3UKwm33/T6WFku8++753Ca/JucIoR1gdUfO7SoSspMDg==", - "dev": true, - "dependencies": { - "@angular-eslint/bundled-angular-compiler": "15.2.1", - "@typescript-eslint/utils": "5.48.2" - }, - "peerDependencies": { - "eslint": "^7.20.0 || ^8.0.0", - "typescript": "*" - } - }, - "node_modules/@angular/animations": { - "version": "15.2.9", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-15.2.9.tgz", - "integrity": "sha512-GQujLhI0cQFcl4Q8y0oSYKSRnW23GIeSL+Arl4eFufziJ9hGAAQNuesaNs/7i+9UlTHDMkPH3kd5ScXuYYz6wg==", - "dependencies": { - "tslib": "^2.3.0" - }, - "engines": { - "node": "^14.20.0 || ^16.13.0 || >=18.10.0" - }, - "peerDependencies": { - "@angular/core": "15.2.9" - } - }, - "node_modules/@angular/cdk": { - "version": "15.2.9", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-15.2.9.tgz", - "integrity": "sha512-koaM07N1AIQ5oHU27l0/FoQSSoYAwlAYwVZ4Di3bYrJsTBNCN2Xsby7wI8gZxdepMnV4Fe9si382BDBov+oO4Q==", - "dependencies": { - "tslib": "^2.3.0" - }, - "optionalDependencies": { - "parse5": "^7.1.2" - }, - "peerDependencies": { - "@angular/common": "^15.0.0 || ^16.0.0", - "@angular/core": "^15.0.0 || ^16.0.0", - "rxjs": "^6.5.3 || ^7.4.0" - } - }, - "node_modules/@angular/cdk/node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "optional": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/@angular/cdk/node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "optional": true, - "dependencies": { - "entities": "^4.4.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/@angular/cli": { - "version": "15.2.9", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-15.2.9.tgz", - "integrity": "sha512-mI6hkGyIJDKd8MRiBl3p5chsUhgnluwmpsq3g1FFPw+wv+eXsPYgCiHqXS/OsK+shFxii9XMxoZQO28bJ4NAOQ==", - "dev": true, - "dependencies": { - "@angular-devkit/architect": "0.1502.9", - "@angular-devkit/core": "15.2.9", - "@angular-devkit/schematics": "15.2.9", - "@schematics/angular": "15.2.9", - "@yarnpkg/lockfile": "1.1.0", - "ansi-colors": "4.1.3", - "ini": "3.0.1", - "inquirer": "8.2.4", - "jsonc-parser": "3.2.0", - "npm-package-arg": "10.1.0", - "npm-pick-manifest": "8.0.1", - "open": "8.4.1", - "ora": "5.4.1", - "pacote": "15.1.0", - "resolve": "1.22.1", - "semver": "7.5.3", - "symbol-observable": "4.0.0", - "yargs": "17.6.2" - }, - "bin": { - "ng": "bin/ng.js" - }, - "engines": { - "node": "^14.20.0 || ^16.13.0 || >=18.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@angular/cli/node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - }, - "node_modules/@angular/cli/node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/@angular/common": { - "version": "15.2.9", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-15.2.9.tgz", - "integrity": "sha512-LM9/UHG2dRrOzlu2KovrFwWIziFMjRxHzSP3Igw6Symw/wIl0kXGq8Fn6RpFP78zmLqnv+IQOoRiby9MCXsI4g==", - "dependencies": { - "tslib": "^2.3.0" - }, - "engines": { - "node": "^14.20.0 || ^16.13.0 || >=18.10.0" - }, - "peerDependencies": { - "@angular/core": "15.2.9", - "rxjs": "^6.5.3 || ^7.4.0" - } - }, - "node_modules/@angular/compiler": { - "version": "15.2.9", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-15.2.9.tgz", - "integrity": "sha512-MoKugbjk+E0wRBj12uvIyDLELlVLonnqjA2+XiF+7FxALIeyds3/qQeEoMmYIqAbN3NnTT5pV92RxWwG4tHFwA==", - "dependencies": { - "tslib": "^2.3.0" - }, - "engines": { - "node": "^14.20.0 || ^16.13.0 || >=18.10.0" - }, - "peerDependencies": { - "@angular/core": "15.2.9" - }, - "peerDependenciesMeta": { - "@angular/core": { - "optional": true - } - } - }, - "node_modules/@angular/compiler-cli": { - "version": "15.2.9", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-15.2.9.tgz", - "integrity": "sha512-zsbI8G2xHOeYWI0hjFzrI//ZhZV9il/uQW5dAimfwJp06KZDeXZ3PdwY9JQslf6F+saLwOObxy6QMrIVvfjy9w==", - "dev": true, - "dependencies": { - "@babel/core": "7.19.3", - "@jridgewell/sourcemap-codec": "^1.4.14", - "chokidar": "^3.0.0", - "convert-source-map": "^1.5.1", - "dependency-graph": "^0.11.0", - "magic-string": "^0.27.0", - "reflect-metadata": "^0.1.2", - "semver": "^7.0.0", - "tslib": "^2.3.0", - "yargs": "^17.2.1" - }, - "bin": { - "ng-xi18n": "bundles/src/bin/ng_xi18n.js", - "ngc": "bundles/src/bin/ngc.js", - "ngcc": "bundles/ngcc/main-ngcc.js" - }, - "engines": { - "node": "^14.20.0 || ^16.13.0 || >=18.10.0" - }, - "peerDependencies": { - "@angular/compiler": "15.2.9", - "typescript": ">=4.8.2 <5.0" - } - }, - "node_modules/@angular/compiler-cli/node_modules/@babel/core": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.3.tgz", - "integrity": "sha512-WneDJxdsjEvyKtXKsaBGbDeiyOjR5vYq4HcShxnIbG0qixpoHjI3MqeZM9NDvsojNCEBItQE4juOo/bU6e72gQ==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.3", - "@babel/helper-compilation-targets": "^7.19.3", - "@babel/helper-module-transforms": "^7.19.0", - "@babel/helpers": "^7.19.0", - "@babel/parser": "^7.19.3", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.3", - "@babel/types": "^7.19.3", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/semver": { - "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" - } - }, - "node_modules/@angular/compiler-cli/node_modules/magic-string": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", - "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", - "dev": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.13" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@angular/core": { - "version": "15.2.9", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-15.2.9.tgz", - "integrity": "sha512-w46Z1yUXCQfKV7XfnamOoLA2VD0MVUUYVrUjO73mHSskDXSXxfZAEHO9kfUS71Cj35PvhP3mbkqWscpea2WeYg==", - "dependencies": { - "tslib": "^2.3.0" - }, - "engines": { - "node": "^14.20.0 || ^16.13.0 || >=18.10.0" - }, - "peerDependencies": { - "rxjs": "^6.5.3 || ^7.4.0", - "zone.js": "~0.11.4 || ~0.12.0 || ~0.13.0" - } - }, - "node_modules/@angular/forms": { - "version": "15.2.9", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-15.2.9.tgz", - "integrity": "sha512-sk0pC2EFi2Ohg5J0q0NYptbT+2WOkoiERSMYA39ncDvlSZBWsNlxpkbGUSck7NIxjK2QfcVN1ldGbHlZTFvtqg==", - "dependencies": { - "tslib": "^2.3.0" - }, - "engines": { - "node": "^14.20.0 || ^16.13.0 || >=18.10.0" - }, - "peerDependencies": { - "@angular/common": "15.2.9", - "@angular/core": "15.2.9", - "@angular/platform-browser": "15.2.9", - "rxjs": "^6.5.3 || ^7.4.0" - } - }, - "node_modules/@angular/language-service": { - "version": "15.2.9", - "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-15.2.9.tgz", - "integrity": "sha512-B7lP4q/eHge2lZezOXS96EYzVf4stMCWfOnz7+pUUi0HbF+A5QCV65SWQddS/M+NM2jj8N2L/j+6UCH8lJjTQA==", - "dev": true, - "engines": { - "node": "^14.20.0 || ^16.13.0 || >=18.10.0" - } - }, - "node_modules/@angular/platform-browser": { - "version": "15.2.9", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-15.2.9.tgz", - "integrity": "sha512-ufCHeSX+U6d43YOMkn3igwfqtlozoCXADcbyfUEG8m2y9XASobqmCKvdSk/zfl62oyiA8msntWBJVBE2l4xKXg==", - "dependencies": { - "tslib": "^2.3.0" - }, - "engines": { - "node": "^14.20.0 || ^16.13.0 || >=18.10.0" - }, - "peerDependencies": { - "@angular/animations": "15.2.9", - "@angular/common": "15.2.9", - "@angular/core": "15.2.9" - }, - "peerDependenciesMeta": { - "@angular/animations": { - "optional": true - } - } - }, - "node_modules/@angular/platform-browser-dynamic": { - "version": "15.2.9", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-15.2.9.tgz", - "integrity": "sha512-ZIYDM6MShblb8OyV1m4+18lJJ2LCeICmeg2uSbpFYptYBSOClrTiYOOFVDJvn7HLvNzljLs16XPrgyaYVqNpcw==", - "dependencies": { - "tslib": "^2.3.0" - }, - "engines": { - "node": "^14.20.0 || ^16.13.0 || >=18.10.0" - }, - "peerDependencies": { - "@angular/common": "15.2.9", - "@angular/compiler": "15.2.9", - "@angular/core": "15.2.9", - "@angular/platform-browser": "15.2.9" - } - }, - "node_modules/@angular/router": { - "version": "15.2.9", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-15.2.9.tgz", - "integrity": "sha512-UCbh5DLSDhybv0xKYT7kGQMfOVdyhHIHOZz5EYVebbhste6S+W1LE57vTHq7QtxJsyKBa/WSkaUkCLXD6ntCAg==", - "dependencies": { - "tslib": "^2.3.0" - }, - "engines": { - "node": "^14.20.0 || ^16.13.0 || >=18.10.0" - }, - "peerDependencies": { - "@angular/common": "15.2.9", - "@angular/core": "15.2.9", - "@angular/platform-browser": "15.2.9", - "rxjs": "^6.5.3 || ^7.4.0" - } - }, - "node_modules/@angular/service-worker": { - "version": "15.2.9", - "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-15.2.9.tgz", - "integrity": "sha512-qM/lcrjaxIfpKj174mMWedtGfLNgLl5m7p9mPNODFjqp5lQj3fTTS643ix5Pr0onwbvbNbXu4g67/WXJqap0eA==", - "dependencies": { - "tslib": "^2.3.0" - }, - "bin": { - "ngsw-config": "ngsw-config.js" - }, - "engines": { - "node": "^14.20.0 || ^16.13.0 || >=18.10.0" - }, - "peerDependencies": { - "@angular/common": "15.2.9", - "@angular/core": "15.2.9" - } - }, - "node_modules/@assemblyscript/loader": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.10.1.tgz", - "integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==", - "dev": true - }, - "node_modules/@babel/code-frame": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", - "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.23.4", - "chalk": "^2.4.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", - "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.20.12", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz", - "integrity": "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.7", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-module-transforms": "^7.20.11", - "@babel/helpers": "^7.20.7", - "@babel/parser": "^7.20.7", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.12", - "@babel/types": "^7.20.7", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/semver": { - "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" - } - }, - "node_modules/@babel/generator": { - "version": "7.20.14", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz", - "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.20.7", - "@jridgewell/gen-mapping": "^0.3.2", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", - "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", - "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", - "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.23.5", - "@babel/helper-validator-option": "^7.23.5", - "browserslist": "^4.22.2", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/browserslist": { - "version": "4.22.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", - "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001565", - "electron-to-chromium": "^1.4.601", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "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" - } - }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.7.tgz", - "integrity": "sha512-xCoqR/8+BoNnXOY7RVSgv6X+o7pmT5q1d+gGcRlXYkI+9B31glE4jeejhKVpA04O1AtzOt7OSQ6VYKP5FcRl9g==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-member-expression-to-functions": "^7.23.0", - "@babel/helper-optimise-call-expression": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.20", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/helper-annotate-as-pure": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", - "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { - "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" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", - "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "regexpu-core": "^5.3.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/@babel/helper-annotate-as-pure": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", - "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { - "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" - } - }, - "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", - "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", - "dev": true, - "dependencies": { - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-plugin-utils": "^7.16.7", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - }, - "peerDependencies": { - "@babel/core": "^7.4.0-0" - } - }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": { - "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" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "dev": true, - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name/node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", - "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.23.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", - "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.20" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-module-transforms/node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", - "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", - "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-wrap-function": "^7.22.20" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-remap-async-to-generator/node_modules/@babel/helper-annotate-as-pure": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", - "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", - "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-member-expression-to-functions": "^7.22.15", - "@babel/helper-optimise-call-expression": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", - "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", - "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", - "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", - "dev": true, - "dependencies": { - "@babel/helper-function-name": "^7.22.5", - "@babel/template": "^7.22.15", - "@babel/types": "^7.22.19" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-wrap-function/node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.23.8", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.8.tgz", - "integrity": "sha512-KDqYz4PiOWvDFrdHLPhKtCThtIcKVy6avWD2oG4GEvyQ+XDZwHD4YQd+H2vNMnq2rkdxsDkU82T+Vk8U/WXHRQ==", - "dev": true, - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.7", - "@babel/types": "^7.23.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers/node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", - "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.23.3.tgz", - "integrity": "sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.23.3.tgz", - "integrity": "sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/plugin-transform-optional-chaining": "^7.23.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.13.0" - } - }, - "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz", - "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-async-generator-functions instead.", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-remap-async-to-generator": "^7.18.9", - "@babel/plugin-syntax-async-generators": "^7.8.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", - "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-class-static-block": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.21.0.tgz", - "integrity": "sha512-XP5G9MWNUskFuP30IfFSEFB0Z6HzLIUcjYM4bYOPHXl7eiJ9HFv8tWj6TXTN5QODiEhDZAeI4hLok2iHFFV4hw==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-static-block instead.", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.21.0", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" - } - }, - "node_modules/@babel/plugin-proposal-dynamic-import": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", - "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-dynamic-import instead.", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-export-namespace-from": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", - "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-export-namespace-from instead.", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-json-strings": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", - "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-json-strings instead.", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-json-strings": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz", - "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-logical-assignment-operators instead.", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", - "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead.", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-numeric-separator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", - "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-numeric-separator instead.", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", - "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead.", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-catch-binding": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", - "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-catch-binding instead.", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", - "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead.", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-private-methods": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", - "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-methods instead.", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.11.tgz", - "integrity": "sha512-0QZ8qP/3RLDVBwBFoWAwCtgcDZJVwA5LUJRZU8x2YFfKNuFq161wK3cuGrALu5yiPu+vzwTAg/sMWVNeWeNyaw==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-property-in-object instead.", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-create-class-features-plugin": "^7.21.0", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-unicode-property-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", - "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-unicode-property-regex instead.", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.23.3.tgz", - "integrity": "sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.23.3.tgz", - "integrity": "sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz", - "integrity": "sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-remap-async-to-generator": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.23.3.tgz", - "integrity": "sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.4.tgz", - "integrity": "sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.23.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.8.tgz", - "integrity": "sha512-yAYslGsY1bX6Knmg46RjiCiNSwJKv2IUC8qOdYKqMMr0491SXFhcHqOdRDeCRohOOIzwN/90C6mQ9qAKgrP7dg==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.20", - "@babel/helper-split-export-declaration": "^7.22.6", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-classes/node_modules/@babel/helper-annotate-as-pure": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", - "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/plugin-transform-classes/node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.23.3.tgz", - "integrity": "sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/template": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-computed-properties/node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.3.tgz", - "integrity": "sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.23.3.tgz", - "integrity": "sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.23.3.tgz", - "integrity": "sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.23.3.tgz", - "integrity": "sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==", - "dev": true, - "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.23.6.tgz", - "integrity": "sha512-aYH4ytZ0qSuBbpfhuofbg/e96oQ7U2w1Aw/UQmKT+1l39uEhUPoFS3fHevDc1G0OvewyDudfMKY1OulczHzWIw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.23.3.tgz", - "integrity": "sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==", - "dev": true, - "dependencies": { - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.23.3.tgz", - "integrity": "sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.23.3.tgz", - "integrity": "sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.3.tgz", - "integrity": "sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz", - "integrity": "sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-simple-access": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.3.tgz", - "integrity": "sha512-ZxyKGTkF9xT9YJuKQRo19ewf3pXpopuYQd8cDXqNzc3mUNbOME0RKMoZxviQk74hwzfQsEe66dE92MaZbdHKNQ==", - "dev": true, - "dependencies": { - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.23.3.tgz", - "integrity": "sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", - "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-new-target": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.23.3.tgz", - "integrity": "sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.23.3.tgz", - "integrity": "sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.20" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.4.tgz", - "integrity": "sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz", - "integrity": "sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.23.3.tgz", - "integrity": "sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.23.3.tgz", - "integrity": "sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "regenerator-transform": "^0.15.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.23.3.tgz", - "integrity": "sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-runtime": { - "version": "7.19.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.6.tgz", - "integrity": "sha512-PRH37lz4JU156lYFW1p8OxE5i7d6Sl/zV58ooyr+q1J1lnQPyg5tIiXlIwNVhJaY4W3TmOtdc8jqdXQcB1v5Yw==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.19.0", - "babel-plugin-polyfill-corejs2": "^0.3.3", - "babel-plugin-polyfill-corejs3": "^0.6.0", - "babel-plugin-polyfill-regenerator": "^0.4.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { - "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" - } - }, - "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.23.3.tgz", - "integrity": "sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-spread": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.23.3.tgz", - "integrity": "sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.23.3.tgz", - "integrity": "sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.23.3.tgz", - "integrity": "sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.23.3.tgz", - "integrity": "sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.23.3.tgz", - "integrity": "sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.23.3.tgz", - "integrity": "sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.20.2.tgz", - "integrity": "sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.20.1", - "@babel/helper-compilation-targets": "^7.20.0", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-validator-option": "^7.18.6", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", - "@babel/plugin-proposal-async-generator-functions": "^7.20.1", - "@babel/plugin-proposal-class-properties": "^7.18.6", - "@babel/plugin-proposal-class-static-block": "^7.18.6", - "@babel/plugin-proposal-dynamic-import": "^7.18.6", - "@babel/plugin-proposal-export-namespace-from": "^7.18.9", - "@babel/plugin-proposal-json-strings": "^7.18.6", - "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", - "@babel/plugin-proposal-numeric-separator": "^7.18.6", - "@babel/plugin-proposal-object-rest-spread": "^7.20.2", - "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", - "@babel/plugin-proposal-optional-chaining": "^7.18.9", - "@babel/plugin-proposal-private-methods": "^7.18.6", - "@babel/plugin-proposal-private-property-in-object": "^7.18.6", - "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.20.0", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.18.6", - "@babel/plugin-transform-async-to-generator": "^7.18.6", - "@babel/plugin-transform-block-scoped-functions": "^7.18.6", - "@babel/plugin-transform-block-scoping": "^7.20.2", - "@babel/plugin-transform-classes": "^7.20.2", - "@babel/plugin-transform-computed-properties": "^7.18.9", - "@babel/plugin-transform-destructuring": "^7.20.2", - "@babel/plugin-transform-dotall-regex": "^7.18.6", - "@babel/plugin-transform-duplicate-keys": "^7.18.9", - "@babel/plugin-transform-exponentiation-operator": "^7.18.6", - "@babel/plugin-transform-for-of": "^7.18.8", - "@babel/plugin-transform-function-name": "^7.18.9", - "@babel/plugin-transform-literals": "^7.18.9", - "@babel/plugin-transform-member-expression-literals": "^7.18.6", - "@babel/plugin-transform-modules-amd": "^7.19.6", - "@babel/plugin-transform-modules-commonjs": "^7.19.6", - "@babel/plugin-transform-modules-systemjs": "^7.19.6", - "@babel/plugin-transform-modules-umd": "^7.18.6", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1", - "@babel/plugin-transform-new-target": "^7.18.6", - "@babel/plugin-transform-object-super": "^7.18.6", - "@babel/plugin-transform-parameters": "^7.20.1", - "@babel/plugin-transform-property-literals": "^7.18.6", - "@babel/plugin-transform-regenerator": "^7.18.6", - "@babel/plugin-transform-reserved-words": "^7.18.6", - "@babel/plugin-transform-shorthand-properties": "^7.18.6", - "@babel/plugin-transform-spread": "^7.19.0", - "@babel/plugin-transform-sticky-regex": "^7.18.6", - "@babel/plugin-transform-template-literals": "^7.18.9", - "@babel/plugin-transform-typeof-symbol": "^7.18.9", - "@babel/plugin-transform-unicode-escapes": "^7.18.10", - "@babel/plugin-transform-unicode-regex": "^7.18.6", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.20.2", - "babel-plugin-polyfill-corejs2": "^0.3.3", - "babel-plugin-polyfill-corejs3": "^0.6.0", - "babel-plugin-polyfill-regenerator": "^0.4.1", - "core-js-compat": "^3.25.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/semver": { - "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" - } - }, - "node_modules/@babel/preset-modules": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6.tgz", - "integrity": "sha512-ID2yj6K/4lKfhuU3+EX4UvNbIt7eACFbHmNUjzA+ep+B5971CknnA/9DEWKbRokfbbtblxxxXFJJrH47UEAMVg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@babel/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", - "dev": true - }, - "node_modules/@babel/runtime": { - "version": "7.20.13", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz", - "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==", - "dev": true, - "dependencies": { - "regenerator-runtime": "^0.13.11" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.7.tgz", - "integrity": "sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.6", - "@babel/types": "^7.23.6", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/@babel/generator": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", - "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.23.6", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/types": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", - "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "dev": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@discoveryjs/json-ext": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", - "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", - "dev": true, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/@es-joy/jsdoccomment": { - "version": "0.39.4", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.39.4.tgz", - "integrity": "sha512-Jvw915fjqQct445+yron7Dufix9A+m9j1fCJYlCo1FWlRvTxa3pjJelxdSTdaLWcTwRU6vbL+NYjO4YuNIS5Qg==", - "dev": true, - "dependencies": { - "comment-parser": "1.3.1", - "esquery": "^1.5.0", - "jsdoc-type-pratt-parser": "~4.0.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.17.8", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.8.tgz", - "integrity": "sha512-ghAbV3ia2zybEefXRRm7+lx8J/rnupZT0gp9CaGy/3iolEXkJ6LYRq4IpQVI9zR97ID80KJVoUlo3LSeA/sMAg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@eslint/eslintrc/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/eslintrc/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/@eslint/eslintrc/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/js": { - "version": "8.51.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz", - "integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@gar/promisify": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", - "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", - "dev": true - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", - "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", - "dev": true - }, - "node_modules/@ionic/angular": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@ionic/angular/-/angular-6.7.4.tgz", - "integrity": "sha512-E41OEAXZFe7rhtseD0R+cEsE2qOxMBGeCGwNNdnoiWtU35+I60YM0M1NaXUd8iiSCUX6v794CETQQeazBxSORg==", - "dependencies": { - "@ionic/core": "6.7.4", - "ionicons": "^6.1.3", - "jsonc-parser": "^3.0.0", - "tslib": "^2.0.0" - }, - "peerDependencies": { - "@angular/core": ">=12.0.0", - "@angular/forms": ">=12.0.0", - "@angular/router": ">=12.0.0", - "rxjs": ">=6.6.0", - "zone.js": ">=0.11.0" - } - }, - "node_modules/@ionic/angular-toolkit": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@ionic/angular-toolkit/-/angular-toolkit-7.0.0.tgz", - "integrity": "sha512-9nVeGuGRO3sUYSVzcHmddPd9+C+XDW2BpRSxCqMK1MKLlfnnpVMP1TTf/IDQhBj+koHwBAQBj6voBSsFUzTKBg==", - "dev": true, - "dependencies": { - "@angular-devkit/core": "^14.0.0", - "@angular-devkit/schematics": "^14.0.0", - "@schematics/angular": "^14.0.0" - } - }, - "node_modules/@ionic/angular-toolkit/node_modules/@angular-devkit/core": { - "version": "14.2.13", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.2.13.tgz", - "integrity": "sha512-aIefeZcbjghQg/V6U9CTLtyB5fXDJ63KwYqVYkWP+i0XriS5A9puFgq2u/OVsWxAfYvqpDqp5AdQ0g0bi3CAsA==", - "dev": true, - "dependencies": { - "ajv": "8.11.0", - "ajv-formats": "2.1.1", - "jsonc-parser": "3.1.0", - "rxjs": "6.6.7", - "source-map": "0.7.4" - }, - "engines": { - "node": "^14.15.0 || >=16.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^3.5.2" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/@ionic/angular-toolkit/node_modules/@angular-devkit/schematics": { - "version": "14.2.13", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-14.2.13.tgz", - "integrity": "sha512-2zczyeNzeBcrT2HOysv52X9SH3tZoHfWJvVf6H0SIa74rfDKEl7hFpKNXnh3x8sIMLj5mZn05n5RCqGxCczcIg==", - "dev": true, - "dependencies": { - "@angular-devkit/core": "14.2.13", - "jsonc-parser": "3.1.0", - "magic-string": "0.26.2", - "ora": "5.4.1", - "rxjs": "6.6.7" - }, - "engines": { - "node": "^14.15.0 || >=16.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@ionic/angular-toolkit/node_modules/@schematics/angular": { - "version": "14.2.13", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-14.2.13.tgz", - "integrity": "sha512-MLxTpTU3E8QACQ/5c0sENMR2gRiMXpGaKeD5IHY+3wyU2fUSJVB0QPU/l1WhoyZbX8N9ospBgf5UEG7taVF9rg==", - "dev": true, - "dependencies": { - "@angular-devkit/core": "14.2.13", - "@angular-devkit/schematics": "14.2.13", - "jsonc-parser": "3.1.0" - }, - "engines": { - "node": "^14.15.0 || >=16.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@ionic/angular-toolkit/node_modules/magic-string": { - "version": "0.26.2", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.2.tgz", - "integrity": "sha512-NzzlXpclt5zAbmo6h6jNc8zl2gNRGHvmsZW4IvZhTC4W7k4OlLP+S5YLussa/r3ixNT66KOQfNORlXHSOy/X4A==", - "dev": true, - "dependencies": { - "sourcemap-codec": "^1.4.8" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@ionic/core": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-6.7.4.tgz", - "integrity": "sha512-IG6vQtt4xrJdas6k1CwqahD/BWsYK6Gi/BAIN8TumBmtfNMu38iOG6Dh05q4hCQzmDm2xDS/BVD3Qz7AmOKArA==", - "dependencies": { - "@stencil/core": "^2.18.0", - "ionicons": "^6.1.3", - "tslib": "^2.1.0" - } - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@isaacs/cliui/node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "node_modules/@isaacs/cliui/node_modules/string-width-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@isaacs/cliui/node_modules/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/@isaacs/cliui/node_modules/string-width-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi-cjs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", - "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@kurkle/color": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz", - "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==" - }, - "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", - "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", - "dev": true - }, - "node_modules/@ngtools/webpack": { - "version": "15.2.9", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-15.2.9.tgz", - "integrity": "sha512-nOXUGqKkAEMlCcrhkDwWDzcVdKNH7MNRUXfNzsFc9zdeR/5p3qt6SVMN7OOE3NREyI7P6nzARc3S+6QDBjf3Jg==", - "dev": true, - "engines": { - "node": "^14.20.0 || ^16.13.0 || >=18.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "@angular/compiler-cli": "^15.0.0", - "typescript": ">=4.8.2 <5.0", - "webpack": "^5.54.0" - } - }, - "node_modules/@ngx-formly/core": { - "version": "6.1.7", - "resolved": "https://registry.npmjs.org/@ngx-formly/core/-/core-6.1.7.tgz", - "integrity": "sha512-hFale+MISRuRznbi4Q7HQaXDICl6wtMneJcnQGmYv8yjeaOYjBsogpD4cOeDf3GibrHYk7Ggh4mamGaLdCL65A==", - "dependencies": { - "tslib": "^2.0.0" - }, - "peerDependencies": { - "@angular/forms": ">=13.2.0", - "rxjs": "^6.5.3 || ^7.0.0" - } - }, - "node_modules/@ngx-formly/ionic": { - "version": "6.1.7", - "resolved": "https://registry.npmjs.org/@ngx-formly/ionic/-/ionic-6.1.7.tgz", - "integrity": "sha512-T1rXjM2L8LvbtE2xdeyStECHjipy7ZqmixI7uVJ/2+7i4frD30UisAW25+Kg1E3Bq2SpQ+De+tEg/B1kOGclWA==", - "dependencies": { - "tslib": "^2.0.0" - }, - "peerDependencies": { - "@ionic/angular": "^6.0.0", - "@ngx-formly/core": "6.1.7" - } - }, - "node_modules/@ngx-formly/schematics": { - "version": "6.1.7", - "resolved": "https://registry.npmjs.org/@ngx-formly/schematics/-/schematics-6.1.7.tgz", - "integrity": "sha512-My7Caz9zNS8NQKtAQTF21YIZnJZ9KZTlh1GPjydlYRpLp2zkfsEiu7nUDBFZV6e0/pLLnlPuaeEkXEuK8SPCZw==", - "dependencies": { - "@angular-devkit/core": "^13.0.3", - "@angular-devkit/schematics": "^13.0.3", - "@schematics/angular": "^13.0.3" - } - }, - "node_modules/@ngx-formly/schematics/node_modules/@angular-devkit/core": { - "version": "13.3.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-13.3.11.tgz", - "integrity": "sha512-rfqoLMRYhlz0wzKlHx7FfyIyQq8dKTsmbCoIVU1cEIH0gyTMVY7PbVzwRRcO6xp5waY+0hA+0Brriujpuhkm4w==", - "dependencies": { - "ajv": "8.9.0", - "ajv-formats": "2.1.1", - "fast-json-stable-stringify": "2.1.0", - "magic-string": "0.25.7", - "rxjs": "6.6.7", - "source-map": "0.7.3" - }, - "engines": { - "node": "^12.20.0 || ^14.15.0 || >=16.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^3.5.2" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/@ngx-formly/schematics/node_modules/@angular-devkit/schematics": { - "version": "13.3.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-13.3.11.tgz", - "integrity": "sha512-ben+EGXpCrClnIVAAnEQmhQdKmnnqFhMp5BqMxgOslSYBAmCutLA6rBu5vsc8kZcGian1wt+lueF7G1Uk5cGBg==", - "dependencies": { - "@angular-devkit/core": "13.3.11", - "jsonc-parser": "3.0.0", - "magic-string": "0.25.7", - "ora": "5.4.1", - "rxjs": "6.6.7" - }, - "engines": { - "node": "^12.20.0 || ^14.15.0 || >=16.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@ngx-formly/schematics/node_modules/@schematics/angular": { - "version": "13.3.11", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-13.3.11.tgz", - "integrity": "sha512-imKBnKYEse0SBVELZO/753nkpt3eEgpjrYkB+AFWF9YfO/4RGnYXDHoH8CFkzxPH9QQCgNrmsVFNiYGS+P/S1A==", - "dependencies": { - "@angular-devkit/core": "13.3.11", - "@angular-devkit/schematics": "13.3.11", - "jsonc-parser": "3.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.15.0 || >=16.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@ngx-formly/schematics/node_modules/ajv": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.9.0.tgz", - "integrity": "sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@ngx-formly/schematics/node_modules/jsonc-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", - "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==" - }, - "node_modules/@ngx-formly/schematics/node_modules/magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", - "dependencies": { - "sourcemap-codec": "^1.4.4" - } - }, - "node_modules/@ngx-formly/schematics/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@ngx-translate/core": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-14.0.0.tgz", - "integrity": "sha512-UevdwNCXMRCdJv//0kC8h2eSfmi02r29xeE8E9gJ1Al4D4jEJ7eiLPdjslTMc21oJNGguqqWeEVjf64SFtvw2w==", - "dependencies": { - "tslib": "^2.3.0" - }, - "peerDependencies": { - "@angular/core": ">=13.0.0", - "rxjs": "^6.5.3 || ^7.4.0" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@npmcli/fs": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", - "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", - "dev": true, - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/git": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-4.1.0.tgz", - "integrity": "sha512-9hwoB3gStVfa0N31ymBmrX+GuDGdVA/QWShZVqE0HK2Af+7QGGrCTbZia/SW0ImUTjTne7SP91qxDmtXvDHRPQ==", - "dev": true, - "dependencies": { - "@npmcli/promise-spawn": "^6.0.0", - "lru-cache": "^7.4.4", - "npm-pick-manifest": "^8.0.0", - "proc-log": "^3.0.0", - "promise-inflight": "^1.0.1", - "promise-retry": "^2.0.1", - "semver": "^7.3.5", - "which": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/git/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/@npmcli/git/node_modules/which": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", - "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/installed-package-contents": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz", - "integrity": "sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==", - "dev": true, - "dependencies": { - "npm-bundled": "^3.0.0", - "npm-normalize-package-bin": "^3.0.0" - }, - "bin": { - "installed-package-contents": "lib/index.js" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/move-file": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", - "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", - "deprecated": "This functionality has been moved to @npmcli/fs", - "dev": true, - "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/@npmcli/node-gyp": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", - "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/promise-spawn": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-6.0.2.tgz", - "integrity": "sha512-gGq0NJkIGSwdbUt4yhdF8ZrmkGKVz9vAdVzpOfnom+V8PLSmSOVhZwbNvZZS1EYcJN5hzzKBxmmVVAInM6HQLg==", - "dev": true, - "dependencies": { - "which": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/promise-spawn/node_modules/which": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", - "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/run-script": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-6.0.2.tgz", - "integrity": "sha512-NCcr1uQo1k5U+SYlnIrbAh3cxy+OQT1VtqiAbxdymSlptbzBb62AjH2xXgjNCoP073hoa1CfCAcwoZ8k96C4nA==", - "dev": true, - "dependencies": { - "@npmcli/node-gyp": "^3.0.0", - "@npmcli/promise-spawn": "^6.0.0", - "node-gyp": "^9.0.0", - "read-package-json-fast": "^3.0.0", - "which": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/run-script/node_modules/which": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", - "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@schematics/angular": { - "version": "15.2.9", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-15.2.9.tgz", - "integrity": "sha512-0Lit6TLNUwcAYiEkXgZp3vY9xAO1cnZCBXuUcp+6v+Ddnrt2w/YOiGe74p21cYe0StkTpTljsqsKBTiX7TMjQg==", - "dev": true, - "dependencies": { - "@angular-devkit/core": "15.2.9", - "@angular-devkit/schematics": "15.2.9", - "jsonc-parser": "3.2.0" - }, - "engines": { - "node": "^14.20.0 || ^16.13.0 || >=18.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@schematics/angular/node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - }, - "node_modules/@sigstore/bundle": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-1.1.0.tgz", - "integrity": "sha512-PFutXEy0SmQxYI4texPw3dd2KewuNqv7OuK1ZFtY2fM754yhvG2KdgwIhRnoEE2uHdtdGNQ8s0lb94dW9sELog==", - "dev": true, - "dependencies": { - "@sigstore/protobuf-specs": "^0.2.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@sigstore/protobuf-specs": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.2.1.tgz", - "integrity": "sha512-XTWVxnWJu+c1oCshMLwnKvz8ZQJJDVOlciMfgpJBQbThVjKTCG8dwyhgLngBD2KN0ap9F/gOV8rFDEx8uh7R2A==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@sigstore/sign": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-1.0.0.tgz", - "integrity": "sha512-INxFVNQteLtcfGmcoldzV6Je0sbbfh9I16DM4yJPw3j5+TFP8X6uIiA18mvpEa9yyeycAKgPmOA3X9hVdVTPUA==", - "dev": true, - "dependencies": { - "@sigstore/bundle": "^1.1.0", - "@sigstore/protobuf-specs": "^0.2.0", - "make-fetch-happen": "^11.0.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@sigstore/sign/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/@sigstore/sign/node_modules/make-fetch-happen": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", - "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", - "dev": true, - "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^17.0.0", - "http-cache-semantics": "^4.1.1", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^5.0.0", - "minipass-fetch": "^3.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^10.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@sigstore/sign/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@sigstore/sign/node_modules/minipass-fetch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", - "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", - "dev": true, - "dependencies": { - "minipass": "^7.0.3", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/@sigstore/sign/node_modules/minipass-fetch/node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", - "dev": true, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/@sigstore/tuf": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-1.0.3.tgz", - "integrity": "sha512-2bRovzs0nJZFlCN3rXirE4gwxCn97JNjMmwpecqlbgV9WcxX7WRuIrgzx/X7Ib7MYRbyUTpBYE0s2x6AmZXnlg==", - "dev": true, - "dependencies": { - "@sigstore/protobuf-specs": "^0.2.0", - "tuf-js": "^1.1.7" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@socket.io/component-emitter": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", - "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", - "dev": true - }, - "node_modules/@stencil/core": { - "version": "2.22.3", - "resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.22.3.tgz", - "integrity": "sha512-kmVA0M/HojwsfkeHsifvHVIYe4l5tin7J5+DLgtl8h6WWfiMClND5K3ifCXXI2ETDNKiEk21p6jql3Fx9o2rng==", - "bin": { - "stencil": "bin/stencil" - }, - "engines": { - "node": ">=12.10.0", - "npm": ">=6.0.0" - } - }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true - }, - "node_modules/@tufjs/canonical-json": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-1.0.0.tgz", - "integrity": "sha512-QTnf++uxunWvG2z3UFNzAoQPHxnSXOwtaI3iJ+AohhV+5vONuArPjJE7aPXPVXfXJsqrVbZBu9b81AJoSd09IQ==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@tufjs/models": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-1.0.4.tgz", - "integrity": "sha512-qaGV9ltJP0EO25YfFUPhxRVK0evXFIAGicsVXuRim4Ed9cjPxYhNnNJ49SFmbeLgtxpslIkX317IgpfcHPVj/A==", - "dev": true, - "dependencies": { - "@tufjs/canonical-json": "1.0.0", - "minimatch": "^9.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@tufjs/models/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@tufjs/models/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@types/body-parser": { - "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", - "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", - "dev": true, - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/bonjour": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", - "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/connect-history-api-fallback": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", - "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", - "dev": true, - "dependencies": { - "@types/express-serve-static-core": "*", - "@types/node": "*" - } - }, - "node_modules/@types/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", - "dev": true - }, - "node_modules/@types/cors": { - "version": "2.8.17", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", - "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/eslint": { - "version": "8.56.2", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.2.tgz", - "integrity": "sha512-uQDwm1wFHmbBbCZCqAlq6Do9LYwByNZHWzXppSnay9SuwJ+VRbjkbLABer54kcPnMSlG6Fdiy2yaFXm/z9Z5gw==", - "dev": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "dev": true, - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "node_modules/@types/estree": { - "version": "0.0.51", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", - "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", - "dev": true - }, - "node_modules/@types/express": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", - "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", - "dev": true, - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "4.17.41", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz", - "integrity": "sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==", - "dev": true, - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, - "node_modules/@types/http-errors": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", - "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true - }, - "node_modules/@types/http-proxy": { - "version": "1.17.14", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", - "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/jasmine": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-4.3.2.tgz", - "integrity": "sha512-lKkWBcbxEZX/7nxPqEtv/OjPLaBa2j0o+hmv5Yn83b/+11C1kfBAkgvmrb13WDkmizUJ3B+jYrWh4M0YRtrzEQ==", - "dev": true - }, - "node_modules/@types/jasminewd2": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@types/jasminewd2/-/jasminewd2-2.0.10.tgz", - "integrity": "sha512-J7mDz7ovjwjc+Y9rR9rY53hFWKATcIkrr9DwQWmOas4/pnIPJTXawnzjwpHm3RSxz/e3ZVUvQ7cRbd5UQLo10g==", - "dev": true, - "dependencies": { - "@types/jasmine": "*" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true - }, - "node_modules/@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true - }, - "node_modules/@types/node": { - "version": "20.2.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.5.tgz", - "integrity": "sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ==", - "dev": true - }, - "node_modules/@types/node-forge": { - "version": "1.3.11", - "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", - "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/parse-json": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", - "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", - "dev": true - }, - "node_modules/@types/q": { - "version": "0.0.32", - "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", - "integrity": "sha512-qYi3YV9inU/REEfxwVcGZzbS3KG/Xs90lv0Pr+lDtuVjBPGd1A+eciXzVSaRvLify132BfcvhvEjeVahrUl0Ug==", - "dev": true - }, - "node_modules/@types/qs": { - "version": "6.9.11", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz", - "integrity": "sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==", - "dev": true - }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true - }, - "node_modules/@types/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", - "dev": true - }, - "node_modules/@types/selenium-webdriver": { - "version": "3.0.26", - "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.26.tgz", - "integrity": "sha512-dyIGFKXfUFiwkMfNGn1+F6b80ZjR3uSYv1j6xVJSDlft5waZ2cwkHW4e7zNzvq7hiEackcgvBpmnXZrI1GltPg==", - "dev": true - }, - "node_modules/@types/semver": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", - "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", - "dev": true - }, - "node_modules/@types/send": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", - "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", - "dev": true, - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "node_modules/@types/serve-index": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", - "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", - "dev": true, - "dependencies": { - "@types/express": "*" - } - }, - "node_modules/@types/serve-static": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", - "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", - "dev": true, - "dependencies": { - "@types/http-errors": "*", - "@types/mime": "*", - "@types/node": "*" - } - }, - "node_modules/@types/sockjs": { - "version": "0.3.36", - "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", - "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/uuid": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.2.tgz", - "integrity": "sha512-kNnC1GFBLuhImSnV7w4njQkUiJi0ZXUycu1rUaouPqiKlXkh77JKgdRnTAp1x5eBwcIwbtI+3otwzuIDEuDoxQ==", - "dev": true - }, - "node_modules/@types/ws": { - "version": "8.5.10", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", - "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "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.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", - "graphemer": "^1.4.0", - "ignore": "^5.2.4", - "natural-compare": "^1.4.0", - "natural-compare-lite": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { - "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": "6.2.0", - "@typescript-eslint/visitor-keys": "6.2.0" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { - "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": "6.2.0", - "@typescript-eslint/utils": "6.2.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { - "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": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { - "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": "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.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "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.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": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { - "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": "6.2.0", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "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/eslint-plugin/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/@typescript-eslint/parser": { - "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": "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": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { - "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": "6.2.0", - "@typescript-eslint/visitor-keys": "6.2.0" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { - "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": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { - "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": "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.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { - "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": "6.2.0", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/parser/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/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.2.tgz", - "integrity": "sha512-zEUFfonQid5KRDKoI3O+uP1GnrFd4tIHlvs+sTJXiWuypUWMuDaottkJuR612wQfOkjYbsaskSIURV9xo4f+Fw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.48.2", - "@typescript-eslint/visitor-keys": "5.48.2" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.2.tgz", - "integrity": "sha512-QVWx7J5sPMRiOMJp5dYshPxABRoZV1xbRirqSk8yuIIsu0nvMTZesKErEA3Oix1k+uvsk8Cs8TGJ6kQ0ndAcew==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "5.48.2", - "@typescript-eslint/utils": "5.48.2", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.2.tgz", - "integrity": "sha512-hE7dA77xxu7ByBc6KCzikgfRyBCTst6dZQpwaTy25iMYOnbNljDT4hjhrGEJJ0QoMjrfqrx+j1l1B9/LtKeuqA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.2.tgz", - "integrity": "sha512-bibvD3z6ilnoVxUBFEgkO0k0aFvUc4Cttt0dAreEr+nrAHhWzkO83PEVVuieK3DqcgL6VAK5dkzK8XUVja5Zcg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.48.2", - "@typescript-eslint/visitor-keys": "5.48.2", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.2.tgz", - "integrity": "sha512-2h18c0d7jgkw6tdKTlNaM7wyopbLRBiit8oAxoP89YnuBOzCZ8g8aBCaCqq7h208qUTroL7Whgzam7UY3HVLow==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.48.2", - "@typescript-eslint/types": "5.48.2", - "@typescript-eslint/typescript-estree": "5.48.2", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0", - "semver": "^7.3.7" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.2.tgz", - "integrity": "sha512-z9njZLSkwmjFWUelGEwEbdf4NwKvfHxvGC0OcGN1Hp/XNDIcJ7D5DpPNPv6x6/mFvc1tQHsaWmpD/a4gOvvCJQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.48.2", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", - "dev": true, - "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" - } - }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", - "dev": true, - "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" - } - }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", - "dev": true, - "dependencies": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", - "dev": true, - "dependencies": { - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", - "dev": true - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true - }, - "node_modules/@yarnpkg/lockfile": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", - "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", - "dev": true - }, - "node_modules/abab": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", - "deprecated": "Use your platform's native atob() and btoa() methods instead", - "dev": true - }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dev": true, - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-import-assertions": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", - "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", - "dev": true, - "peerDependencies": { - "acorn": "^8" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.1.tgz", - "integrity": "sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/adjust-sourcemap-loader": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", - "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", - "dev": true, - "dependencies": { - "loader-utils": "^2.0.0", - "regex-parser": "^2.2.11" - }, - "engines": { - "node": ">=8.9" - } - }, - "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "dev": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, - "node_modules/adm-zip": { - "version": "0.5.10", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.10.tgz", - "integrity": "sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==", - "dev": true, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/agentkeepalive": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", - "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", - "dev": true, - "dependencies": { - "humanize-ms": "^1.2.1" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ajv": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", - "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/angular-mydatepicker": { - "version": "0.11.5", - "resolved": "https://registry.npmjs.org/angular-mydatepicker/-/angular-mydatepicker-0.11.5.tgz", - "integrity": "sha512-nKXUA3NhzMJ02jX+AiqpEr0kl2lCS3tGaFeHcyBFhwlDao9BO9i3403NXaFliOCeN2M4VvUNQs8pggLE7DECIA==", - "dependencies": { - "tslib": "^1.9.0" - } - }, - "node_modules/angular-mydatepicker/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-html-community": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", - "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", - "dev": true, - "engines": [ - "node >= 0.8.0" - ], - "bin": { - "ansi-html": "bin/ansi-html" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "devOptional": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/aproba": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "dev": true - }, - "node_modules/are-docs-informative": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", - "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", - "dev": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/are-we-there-yet": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", - "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", - "dev": true, - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/aria-query": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", - "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", - "dev": true, - "dependencies": { - "deep-equal": "^2.0.5" - } - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "dev": true - }, - "node_modules/array-includes": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", - "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", - "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", - "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", - "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-array-buffer": "^3.0.2", - "is-shared-array-buffer": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true - }, - "node_modules/autoprefixer": { - "version": "10.4.13", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz", - "integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - } - ], - "dependencies": { - "browserslist": "^4.21.4", - "caniuse-lite": "^1.0.30001426", - "fraction.js": "^4.2.0", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/aws4": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", - "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", - "dev": true - }, - "node_modules/axobject-query": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", - "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==", - "dev": true, - "dependencies": { - "deep-equal": "^2.0.5" - } - }, - "node_modules/babel-loader": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.2.tgz", - "integrity": "sha512-mN14niXW43tddohGl8HPu5yfQq70iUThvFL/4QzESA7GcZoC0eVOhvWdQ8+3UlSjaDE9MVtsW9mxDY07W7VpVA==", - "dev": true, - "dependencies": { - "find-cache-dir": "^3.3.2", - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 14.15.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0", - "webpack": ">=5" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", - "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.17.7", - "@babel/helper-define-polyfill-provider": "^0.3.3", - "semver": "^6.1.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { - "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" - } - }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", - "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", - "dev": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.3", - "core-js-compat": "^3.25.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", - "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", - "dev": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/base64id": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", - "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", - "dev": true, - "engines": { - "node": "^4.5.0 || >= 5.9" - } - }, - "node_modules/batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", - "dev": true - }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "dev": true, - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, - "node_modules/big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "devOptional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/blocking-proxy": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-1.0.1.tgz", - "integrity": "sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "blocking-proxy": "built/lib/bin.js" - }, - "engines": { - "node": ">=6.9.x" - } - }, - "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", - "dev": true, - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/body-parser/node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/bonjour-service": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", - "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "multicast-dns": "^7.2.5" - } - }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "devOptional": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/browserstack": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.6.1.tgz", - "integrity": "sha512-GxtFjpIaKdbAyzHfFDKixKO8IBT7wR3NjbzrGc78nNs/Ciys9wU3/nBtsqsWv5nDSrdI5tz0peKuzCPuNXNUiw==", - "dev": true, - "dependencies": { - "https-proxy-agent": "^2.2.1" - } - }, - "node_modules/browserstack/node_modules/agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", - "dev": true, - "dependencies": { - "es6-promisify": "^5.0.0" - }, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/browserstack/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/browserstack/node_modules/https-proxy-agent": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", - "dev": true, - "dependencies": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - }, - "engines": { - "node": ">= 4.5.0" - } - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/builtins": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", - "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", - "dev": true, - "dependencies": { - "semver": "^7.0.0" - } - }, - "node_modules/bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/cacache": { - "version": "17.0.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.0.4.tgz", - "integrity": "sha512-Z/nL3gU+zTUjz5pCA5vVjYM8pmaw2kxM7JEiE0fv3w77Wj+sFbi70CrBruUWH0uNcEdvLDixFpgA2JM4F4DBjA==", - "dev": true, - "dependencies": { - "@npmcli/fs": "^3.1.0", - "fs-minipass": "^3.0.0", - "glob": "^8.0.1", - "lru-cache": "^7.7.1", - "minipass": "^4.0.0", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "ssri": "^10.0.0", - "tar": "^6.1.11", - "unique-filename": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/cacache/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/call-bind": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", - "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.1", - "set-function-length": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001576", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001576.tgz", - "integrity": "sha512-ff5BdakGe2P3SQsMsiqmt1Lc8221NR1VzHj5jXN5vBny9A6fpze94HiVV/n7XRosOlsShJcvMv5mdnpjOGCEgg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, - "node_modules/chart.js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.1.tgz", - "integrity": "sha512-C74QN1bxwV1v2PEujhmKjOZ7iUM4w6BWs23Md/6aOZZSlwMzeCIDGuZay++rBgChYru7/+QFeoQW0fQoP534Dg==", - "dependencies": { - "@kurkle/color": "^0.3.0" - }, - "engines": { - "pnpm": ">=7" - } - }, - "node_modules/chartjs-adapter-date-fns": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chartjs-adapter-date-fns/-/chartjs-adapter-date-fns-3.0.0.tgz", - "integrity": "sha512-Rs3iEB3Q5pJ973J93OBTpnP7qoGwvq3nUnoMdtxO+9aoJof7UFcRbWcIDteXuYd1fgAvct/32T9qaLyLuZVwCg==", - "peerDependencies": { - "chart.js": ">=2.8.0", - "date-fns": ">=2.0.0" - } - }, - "node_modules/chartjs-plugin-zoom": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/chartjs-plugin-zoom/-/chartjs-plugin-zoom-2.0.1.tgz", - "integrity": "sha512-ogOmLu6e+Q7E1XWOCOz9YwybMslz9qNfGV2a+qjfmqJYpsw5ZMoRHZBUyW+NGhkpQ5PwwPA/+rikHpBZb7PZuA==", - "dependencies": { - "hammerjs": "^2.0.8" - }, - "peerDependencies": { - "chart.js": ">=3.2.0" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "devOptional": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", - "dev": true, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/classlist.js": { - "version": "1.1.20150312", - "resolved": "https://registry.npmjs.org/classlist.js/-/classlist.js-1.1.20150312.tgz", - "integrity": "sha512-eR8yB970+yGslcTnJnROX2icsMa8v/KVLv/sgv3NhSvZSHgam64XNSF2TyJnKIfsnTFJBcTdrIneYqUIrvxLpg==" - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dependencies": { - "restore-cursor": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-spinners": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", - "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-convert/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true, - "bin": { - "color-support": "bin.js" - } - }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true - }, - "node_modules/colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "engines": { - "node": ">= 10" - } - }, - "node_modules/comment-parser": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.3.1.tgz", - "integrity": "sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA==", - "dev": true, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", - "dev": true - }, - "node_modules/compare-versions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.0.tgz", - "integrity": "sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg==" - }, - "node_modules/compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "dev": true, - "dependencies": { - "mime-db": ">= 1.43.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", - "dev": true, - "dependencies": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", - "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/compression/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/compression/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/compression/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/connect": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", - "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", - "dev": true, - "dependencies": { - "debug": "2.6.9", - "finalhandler": "1.1.2", - "parseurl": "~1.3.3", - "utils-merge": "1.0.1" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/connect-history-api-fallback": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", - "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/connect/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/connect/node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "dev": true, - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/connect/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/connect/node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", - "dev": true, - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/connect/node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "dev": true - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dev": true, - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "dev": true - }, - "node_modules/copy-anything": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", - "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", - "dev": true, - "dependencies": { - "is-what": "^3.14.1" - }, - "funding": { - "url": "https://github.com/sponsors/mesqueeb" - } - }, - "node_modules/copy-webpack-plugin": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", - "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", - "dev": true, - "dependencies": { - "fast-glob": "^3.2.11", - "glob-parent": "^6.0.1", - "globby": "^13.1.1", - "normalize-path": "^3.0.0", - "schema-utils": "^4.0.0", - "serialize-javascript": "^6.0.0" - }, - "engines": { - "node": ">= 14.15.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - } - }, - "node_modules/copy-webpack-plugin/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/core-js-compat": { - "version": "3.35.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.35.0.tgz", - "integrity": "sha512-5blwFAddknKeNgsjBzilkdQ0+YK8L1PfqPYq40NOYMYFSS38qj+hpTcLLWwpIwA2A5bje/x5jmVn2tzUMg9IVw==", - "dev": true, - "dependencies": { - "browserslist": "^4.22.2" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/core-js-compat/node_modules/browserslist": { - "version": "4.22.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", - "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001565", - "electron-to-chromium": "^1.4.601", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "dev": true, - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", - "dev": true, - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "node_modules/critters": { - "version": "0.0.16", - "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.16.tgz", - "integrity": "sha512-JwjgmO6i3y6RWtLYmXwO5jMd+maZt8Tnfu7VVISmEWyQqfLpB8soBswf8/2bu6SBXxtKA68Al3c+qIG1ApT68A==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "css-select": "^4.2.0", - "parse5": "^6.0.1", - "parse5-htmlparser2-tree-adapter": "^6.0.1", - "postcss": "^8.3.7", - "pretty-bytes": "^5.3.0" - } - }, - "node_modules/critters/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/critters/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/critters/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/critters/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/critters/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/css-loader": { - "version": "6.7.3", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.3.tgz", - "integrity": "sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ==", - "dev": true, - "dependencies": { - "icss-utils": "^5.1.0", - "postcss": "^8.4.19", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.0", - "postcss-modules-scope": "^3.0.0", - "postcss-modules-values": "^4.0.0", - "postcss-value-parser": "^4.2.0", - "semver": "^7.3.8" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - } - }, - "node_modules/css-select": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", - "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.0.1", - "domhandler": "^4.3.1", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", - "dev": true, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/custom-event": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", - "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", - "dev": true - }, - "node_modules/d3": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", - "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", - "dependencies": { - "d3-array": "3", - "d3-axis": "3", - "d3-brush": "3", - "d3-chord": "3", - "d3-color": "3", - "d3-contour": "4", - "d3-delaunay": "6", - "d3-dispatch": "3", - "d3-drag": "3", - "d3-dsv": "3", - "d3-ease": "3", - "d3-fetch": "3", - "d3-force": "3", - "d3-format": "3", - "d3-geo": "3", - "d3-hierarchy": "3", - "d3-interpolate": "3", - "d3-path": "3", - "d3-polygon": "3", - "d3-quadtree": "3", - "d3-random": "3", - "d3-scale": "4", - "d3-scale-chromatic": "3", - "d3-selection": "3", - "d3-shape": "3", - "d3-time": "3", - "d3-time-format": "4", - "d3-timer": "3", - "d3-transition": "3", - "d3-zoom": "3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-array": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", - "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", - "dependencies": { - "internmap": "1 - 2" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-axis": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", - "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-brush": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", - "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-drag": "2 - 3", - "d3-interpolate": "1 - 3", - "d3-selection": "3", - "d3-transition": "3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-chord": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", - "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", - "dependencies": { - "d3-path": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-color": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", - "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-contour": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", - "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", - "dependencies": { - "d3-array": "^3.2.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-delaunay": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", - "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", - "dependencies": { - "delaunator": "5" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-dispatch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", - "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-drag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", - "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-selection": "3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-dsv": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", - "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", - "dependencies": { - "commander": "7", - "iconv-lite": "0.6", - "rw": "1" - }, - "bin": { - "csv2json": "bin/dsv2json.js", - "csv2tsv": "bin/dsv2dsv.js", - "dsv2dsv": "bin/dsv2dsv.js", - "dsv2json": "bin/dsv2json.js", - "json2csv": "bin/json2dsv.js", - "json2dsv": "bin/json2dsv.js", - "json2tsv": "bin/json2dsv.js", - "tsv2csv": "bin/dsv2dsv.js", - "tsv2json": "bin/dsv2json.js" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-ease": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", - "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-fetch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", - "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", - "dependencies": { - "d3-dsv": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-force": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", - "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-quadtree": "1 - 3", - "d3-timer": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-format": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", - "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-geo": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.0.tgz", - "integrity": "sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA==", - "dependencies": { - "d3-array": "2.5.0 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-hierarchy": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", - "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-interpolate": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", - "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", - "dependencies": { - "d3-color": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-path": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", - "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-polygon": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", - "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-quadtree": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", - "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-random": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", - "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-scale": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", - "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", - "dependencies": { - "d3-array": "2.10.0 - 3", - "d3-format": "1 - 3", - "d3-interpolate": "1.2.0 - 3", - "d3-time": "2.1.1 - 3", - "d3-time-format": "2 - 4" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-scale-chromatic": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", - "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==", - "dependencies": { - "d3-color": "1 - 3", - "d3-interpolate": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-selection": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", - "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-shape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", - "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", - "dependencies": { - "d3-path": "^3.1.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-time": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", - "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", - "dependencies": { - "d3-array": "2 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-time-format": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", - "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", - "dependencies": { - "d3-time": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-timer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", - "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-transition": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", - "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", - "dependencies": { - "d3-color": "1 - 3", - "d3-dispatch": "1 - 3", - "d3-ease": "1 - 3", - "d3-interpolate": "1 - 3", - "d3-timer": "1 - 3" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "d3-selection": "2 - 3" - } - }, - "node_modules/d3-zoom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", - "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-drag": "2 - 3", - "d3-interpolate": "1 - 3", - "d3-selection": "2 - 3", - "d3-transition": "2 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/date-fns": { - "version": "2.30.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", - "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", - "dependencies": { - "@babel/runtime": "^7.21.0" - }, - "engines": { - "node": ">=0.11" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/date-fns" - } - }, - "node_modules/date-fns/node_modules/@babel/runtime": { - "version": "7.23.8", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.8.tgz", - "integrity": "sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/date-fns/node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" - }, - "node_modules/date-format": { - "version": "4.0.14", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", - "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/deep-equal": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", - "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.5", - "es-get-iterator": "^1.1.3", - "get-intrinsic": "^1.2.2", - "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.2", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "isarray": "^2.0.5", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "side-channel": "^1.0.4", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/deep-equal/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/default-gateway": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", - "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", - "dev": true, - "dependencies": { - "execa": "^5.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/defaults": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", - "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", - "dependencies": { - "clone": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/define-data-property": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", - "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/del": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", - "integrity": "sha512-Z4fzpbIRjOu7lO5jCETSWoqUDVe0IPOlfugBsF6suen2LKDlVb4QZpKEM9P+buNJ4KI1eN7I083w/pbKUpsrWQ==", - "dev": true, - "dependencies": { - "globby": "^5.0.0", - "is-path-cwd": "^1.0.0", - "is-path-in-cwd": "^1.0.0", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "rimraf": "^2.2.8" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/del/node_modules/array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", - "dev": true, - "dependencies": { - "array-uniq": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/del/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/del/node_modules/globby": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", - "integrity": "sha512-HJRTIH2EeH44ka+LWig+EqT2ONSYpVlNfx6pyd592/VF1TbfljJ7elwie7oSwcViLGqOdWocSdu2txwBF9bjmQ==", - "dev": true, - "dependencies": { - "array-union": "^1.0.1", - "arrify": "^1.0.0", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/del/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/del/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/delaunator": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz", - "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==", - "dependencies": { - "robust-predicates": "^3.0.0" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "dev": true - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/dependency-graph": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", - "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", - "dev": true, - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "dev": true, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true - }, - "node_modules/di": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", - "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", - "dev": true - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dns-packet": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", - "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", - "dev": true, - "dependencies": { - "@leichtgewicht/ip-codec": "^2.0.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dom-serialize": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", - "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", - "dev": true, - "dependencies": { - "custom-event": "~1.0.0", - "ent": "~2.2.0", - "extend": "^3.0.0", - "void-elements": "^2.0.0" - } - }, - "node_modules/dom-serializer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", - "dev": true, - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", - "dev": true, - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dev": true, - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true - }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "dev": true, - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true - }, - "node_modules/electron-to-chromium": { - "version": "1.4.628", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.628.tgz", - "integrity": "sha512-2k7t5PHvLsufpP6Zwk0nof62yLOsCf032wZx7/q0mv8gwlXjhcxI3lz6f0jBr0GrnWKcm3burXzI3t5IrcdUxw==", - "dev": true - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, - "node_modules/engine.io": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz", - "integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==", - "dev": true, - "dependencies": { - "@types/cookie": "^0.4.1", - "@types/cors": "^2.8.12", - "@types/node": ">=10.0.0", - "accepts": "~1.3.4", - "base64id": "2.0.0", - "cookie": "~0.4.1", - "cors": "~2.8.5", - "debug": "~4.3.1", - "engine.io-parser": "~5.2.1", - "ws": "~8.11.0" - }, - "engines": { - "node": ">=10.2.0" - } - }, - "node_modules/engine.io-parser": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz", - "integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==", - "dev": true, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/engine.io/node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/engine.io/node_modules/ws": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", - "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/enhanced-resolve": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", - "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/ent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", - "dev": true - }, - "node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "dev": true, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "dev": true - }, - "node_modules/errno": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", - "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", - "dev": true, - "optional": true, - "dependencies": { - "prr": "~1.0.1" - }, - "bin": { - "errno": "cli.js" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.22.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", - "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "arraybuffer.prototype.slice": "^1.0.2", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.5", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.2", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.12", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "safe-array-concat": "^1.0.1", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.0", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-get-iterator": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", - "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "is-arguments": "^1.1.1", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.7", - "isarray": "^2.0.5", - "stop-iteration-iterator": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-get-iterator/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "node_modules/es-module-lexer": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", - "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", - "dev": true - }, - "node_modules/es-set-tostringtag": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", - "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.2", - "has-tostringtag": "^1.0.0", - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", - "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.0" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", - "dev": true - }, - "node_modules/es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", - "dev": true, - "dependencies": { - "es6-promise": "^4.0.3" - } - }, - "node_modules/esbuild-wasm": { - "version": "0.17.8", - "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.17.8.tgz", - "integrity": "sha512-zCmpxv95E0FuCmvdw1K836UHnj4EdiQnFfjTby35y3LAjRPtXMj3sbHDRHjbD8Mqg5lTwq3knacr/1qIFU51CQ==", - "dev": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "dev": true - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/eslint": { - "version": "8.51.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.51.0.tgz", - "integrity": "sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.51.0", - "@humanwhocodes/config-array": "^0.11.11", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-module-utils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", - "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", - "dev": true, - "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.27.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", - "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "array.prototype.flatmap": "^1.3.1", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.7", - "eslint-module-utils": "^2.7.4", - "has": "^1.0.3", - "is-core-module": "^2.11.0", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.values": "^1.1.6", - "resolve": "^1.22.1", - "semver": "^6.3.0", - "tsconfig-paths": "^3.14.1" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/semver": { - "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" - } - }, - "node_modules/eslint-plugin-jsdoc": { - "version": "45.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-45.0.0.tgz", - "integrity": "sha512-l2+Jcs/Ps7oFA+SWY+0sweU/e5LgricnEl6EsDlyRTF5y0+NWL1y9Qwz9PHwHAxtdJq6lxPjEQWmYLMkvhzD4g==", - "dev": true, - "dependencies": { - "@es-joy/jsdoccomment": "~0.39.4", - "are-docs-informative": "^0.0.2", - "comment-parser": "1.3.1", - "debug": "^4.3.4", - "escape-string-regexp": "^4.0.0", - "esquery": "^1.5.0", - "semver": "^7.5.1", - "spdx-expression-parse": "^3.0.1" - }, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - } - }, - "node_modules/eslint-plugin-jsdoc/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint-plugin-prefer-arrow": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-prefer-arrow/-/eslint-plugin-prefer-arrow-1.2.3.tgz", - "integrity": "sha512-J9I5PKCOJretVuiZRGvPQxCbllxGAV/viI20JO3LYblAodofBxyMnZAJ+WGeClHgANnSJberTNoFWWjrWKBuXQ==", - "dev": true, - "peerDependencies": { - "eslint": ">=2.0.0" - } - }, - "node_modules/eslint-plugin-unused-imports": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-3.1.0.tgz", - "integrity": "sha512-9l1YFCzXKkw1qtAru1RWUtG2EVDZY0a0eChKXcL+EZ5jitG7qxdctu4RnvhOJHv4xfmUf7h+JJPINlVpGhZMrw==", - "dev": true, - "dependencies": { - "eslint-rule-composer": "^0.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "@typescript-eslint/eslint-plugin": "6 - 7", - "eslint": "8" - }, - "peerDependenciesMeta": { - "@typescript-eslint/eslint-plugin": { - "optional": true - } - } - }, - "node_modules/eslint-rule-composer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", - "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/eslint/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/eslint/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/eslint/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/eslint/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/eslint/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/eslint/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eventemitter-asyncresource": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz", - "integrity": "sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==", - "dev": true - }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/exponential-backoff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", - "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", - "dev": true - }, - "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", - "dev": true, - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.2", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.6.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.11.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/external-editor/node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", - "dev": true, - "engines": [ - "node >=0.6.0" - ] - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", - "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", - "dev": true, - "dependencies": { - "websocket-driver": ">=0.5.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/file-saver-es": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/file-saver-es/-/file-saver-es-2.0.5.tgz", - "integrity": "sha512-Kg0lt+is9nOyi/VDms9miScNGot25jVFbjFccXuCL/shd2Q+rt70MALxHVkXllsX83JEBLiHQNjDPGd/6FIOoQ==" - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "devOptional": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "dev": true, - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", - "dev": true, - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", - "dev": true - }, - "node_modules/follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fraction.js": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", - "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", - "dev": true, - "engines": { - "node": "*" - }, - "funding": { - "type": "patreon", - "url": "https://github.com/sponsors/rawify" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/fs-minipass": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", - "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", - "dev": true, - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/fs-minipass/node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", - "dev": true, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/fs-monkey": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz", - "integrity": "sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==", - "dev": true - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gauge": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", - "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", - "dev": true, - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", - "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - } - }, - "node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "devOptional": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/globby": { - "version": "13.2.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", - "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", - "dev": true, - "dependencies": { - "dir-glob": "^3.0.1", - "fast-glob": "^3.3.0", - "ignore": "^5.2.4", - "merge2": "^1.4.1", - "slash": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/hammerjs": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz", - "integrity": "sha512-tSQXBXS/MWQOn/RKckawJ61vvsDpCom87JgxiYdGwHdOa0ht0vzUWDlfioofFCRU0L+6NGDt6XzbgoJvZkMeRQ==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/handle-thing": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true - }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", - "dev": true, - "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/har-validator/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/har-validator/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", - "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-ansi/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", - "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "dev": true - }, - "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hdr-histogram-js": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz", - "integrity": "sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g==", - "dev": true, - "dependencies": { - "@assemblyscript/loader": "^0.10.1", - "base64-js": "^1.2.0", - "pako": "^1.0.3" - } - }, - "node_modules/hdr-histogram-percentiles-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz", - "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==", - "dev": true - }, - "node_modules/hosted-git-info": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", - "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", - "dev": true, - "dependencies": { - "lru-cache": "^7.5.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/hosted-git-info/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - } - }, - "node_modules/hpack.js/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/hpack.js/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/hpack.js/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/html-entities": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz", - "integrity": "sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/mdevils" - }, - { - "type": "patreon", - "url": "https://patreon.com/mdevils" - } - ] - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "dev": true - }, - "node_modules/http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", - "dev": true - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dev": true, - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-parser-js": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", - "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", - "dev": true - }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dev": true, - "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/http-proxy-middleware": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", - "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", - "dev": true, - "dependencies": { - "@types/http-proxy": "^1.17.8", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.1", - "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "@types/express": "^4.17.13" - }, - "peerDependenciesMeta": { - "@types/express": { - "optional": true - } - } - }, - "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - }, - "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "dev": true, - "dependencies": { - "ms": "^2.0.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/icss-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ignore": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/ignore-walk": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.4.tgz", - "integrity": "sha512-t7sv42WkwFkyKbivUCglsQW5YWMskWtbEf4MNKX5u/CCWHKSPzN4FtBQGsQZgCLbxOzpVlcbWVK5KB3auIOjSw==", - "dev": true, - "dependencies": { - "minimatch": "^9.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/ignore-walk/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/ignore-walk/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/image-size": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", - "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", - "dev": true, - "optional": true, - "bin": { - "image-size": "bin/image-size.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", - "dev": true - }, - "node_modules/immutable": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", - "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==", - "dev": true - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "dev": true - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ini": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.1.tgz", - "integrity": "sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ==", - "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/inquirer": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", - "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.1", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.21", - "mute-stream": "0.0.8", - "ora": "^5.4.1", - "run-async": "^2.4.0", - "rxjs": "^7.5.5", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/inquirer/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/inquirer/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/inquirer/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/inquirer/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/inquirer/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/inquirer/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/internal-slot": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", - "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.2", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/internmap": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", - "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", - "engines": { - "node": ">=12" - } - }, - "node_modules/ionicons": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/ionicons/-/ionicons-6.1.3.tgz", - "integrity": "sha512-ptzz38dd/Yq+PgjhXegh7yhb/SLIk1bvL9vQDtLv1aoSc7alO6mX2DIMgcKYzt9vrNWkRu1f9Jr78zIFFyOXqw==", - "dependencies": { - "@stencil/core": "^2.18.0" - } - }, - "node_modules/ip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", - "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==", - "dev": true - }, - "node_modules/ipaddr.js": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", - "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "devOptional": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "devOptional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "devOptional": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-lambda": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "dev": true - }, - "node_modules/is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "devOptional": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-path-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "integrity": "sha512-cnS56eR9SPAscL77ik76ATVqoPARTqPIVkMDVxRaWH06zT+6+CzIroYRJ0VVvm0Z1zfAvxvz9i/D3Ppjaqt5Nw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-path-in-cwd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", - "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", - "dev": true, - "dependencies": { - "is-path-inside": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-path-in-cwd/node_modules/is-path-inside": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha512-qhsCR/Esx4U4hg/9I19OVUAJkGWtjRYHMRgUMZE2TDdj+Ag+kttZanLupfddNyglzz50cUlmWzUaI37GDfNx/g==", - "dev": true, - "dependencies": { - "path-is-inside": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", - "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", - "dev": true, - "dependencies": { - "which-typed-array": "^1.1.11" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-weakmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-what": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", - "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", - "dev": true - }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true - }, - "node_modules/isbinaryfile": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", - "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", - "dev": true, - "engines": { - "node": ">= 8.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/gjtorikian/" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "dev": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "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" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-report/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report/node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/istanbul-lib-report/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", - "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jackspeak": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", - "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", - "dev": true, - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/jasmine": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz", - "integrity": "sha512-KbdGQTf5jbZgltoHs31XGiChAPumMSY64OZMWLNYnEnMfG5uwGBhffePwuskexjT+/Jea/gU3qAU8344hNohSw==", - "dev": true, - "dependencies": { - "exit": "^0.1.2", - "glob": "^7.0.6", - "jasmine-core": "~2.8.0" - }, - "bin": { - "jasmine": "bin/jasmine.js" - } - }, - "node_modules/jasmine-core": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.5.0.tgz", - "integrity": "sha512-9PMzyvhtocxb3aXJVOPqBDswdgyAeSB81QnLop4npOpbqnheaTEwPc9ZloQeVswugPManznQBjD8kWDTjlnHuw==", - "dev": true - }, - "node_modules/jasmine-spec-reporter": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-7.0.0.tgz", - "integrity": "sha512-OtC7JRasiTcjsaCBPtMO0Tl8glCejM4J4/dNuOJdA8lBjz4PmWjYQ6pzb0uzpBNAWJMDudYuj9OdXJWqM2QTJg==", - "dev": true, - "dependencies": { - "colors": "1.4.0" - } - }, - "node_modules/jasmine/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/jasmine/node_modules/jasmine-core": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz", - "integrity": "sha512-SNkOkS+/jMZvLhuSx1fjhcNWUC/KG6oVyFUGkSBEr9n1axSNduWU8GlI7suaHXr4yxjet6KjrUZxUTE5WzzWwQ==", - "dev": true - }, - "node_modules/jasminewd2": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.2.0.tgz", - "integrity": "sha512-Rn0nZe4rfDhzA63Al3ZGh0E+JTmM6ESZYXJGKuqKGZObsAB9fwXPD03GjtIEvJBDOhN94T5MzbwZSqzFHSQPzg==", - "dev": true, - "engines": { - "node": ">= 6.9.x" - } - }, - "node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/jest-worker/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true - }, - "node_modules/jsdoc-type-pratt-parser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", - "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", - "dev": true, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonc-parser": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.1.0.tgz", - "integrity": "sha512-DRf0QjnNeCUds3xTjKlQQ3DpJD51GvDjJfnxUVWg6PZTo2otSm+slzNAxU/35hF8/oJIKoG9slq30JYOsF2azg==" - }, - "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", - "dev": true, - "engines": [ - "node >= 0.2.0" - ] - }, - "node_modules/jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "dev": true, - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/jszip": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", - "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", - "dev": true, - "dependencies": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "setimmediate": "^1.0.5" - } - }, - "node_modules/jszip/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/jszip/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/jszip/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/karma": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.2.tgz", - "integrity": "sha512-C6SU/53LB31BEgRg+omznBEMY4SjHU3ricV6zBcAe1EeILKkeScr+fZXtaI5WyDbkVowJxxAI6h73NcFPmXolQ==", - "dev": true, - "dependencies": { - "@colors/colors": "1.5.0", - "body-parser": "^1.19.0", - "braces": "^3.0.2", - "chokidar": "^3.5.1", - "connect": "^3.7.0", - "di": "^0.0.1", - "dom-serialize": "^2.2.1", - "glob": "^7.1.7", - "graceful-fs": "^4.2.6", - "http-proxy": "^1.18.1", - "isbinaryfile": "^4.0.8", - "lodash": "^4.17.21", - "log4js": "^6.4.1", - "mime": "^2.5.2", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.5", - "qjobs": "^1.2.0", - "range-parser": "^1.2.1", - "rimraf": "^3.0.2", - "socket.io": "^4.4.1", - "source-map": "^0.6.1", - "tmp": "^0.2.1", - "ua-parser-js": "^0.7.30", - "yargs": "^16.1.1" - }, - "bin": { - "karma": "bin/karma" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/karma-chrome-launcher": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.2.0.tgz", - "integrity": "sha512-rE9RkUPI7I9mAxByQWkGJFXfFD6lE4gC5nPuZdobf/QdTEJI6EU4yIay/cfU/xV4ZxlM5JiTv7zWYgA64NpS5Q==", - "dev": true, - "dependencies": { - "which": "^1.2.1" - } - }, - "node_modules/karma-chrome-launcher/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/karma-coverage": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-2.2.1.tgz", - "integrity": "sha512-yj7hbequkQP2qOSb20GuNSIyE//PgJWHwC2IydLE6XRtsnaflv+/OSGNssPjobYUlhVVagy99TQpqUt3vAUG7A==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.2.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.1", - "istanbul-reports": "^3.0.5", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/karma-coverage-istanbul-reporter": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-3.0.3.tgz", - "integrity": "sha512-wE4VFhG/QZv2Y4CdAYWDbMmcAHeS926ZIji4z+FkB2aF/EposRb6DP6G5ncT/wXhqUfAb/d7kZrNKPonbvsATw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^3.0.6", - "istanbul-reports": "^3.0.2", - "minimatch": "^3.0.4" - }, - "funding": { - "url": "https://github.com/sponsors/mattlewis92" - } - }, - "node_modules/karma-coverage-istanbul-reporter/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/karma-coverage-istanbul-reporter/node_modules/istanbul-lib-source-maps": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", - "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "rimraf": "^2.6.3", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/karma-coverage-istanbul-reporter/node_modules/istanbul-lib-source-maps/node_modules/istanbul-lib-coverage": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", - "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/karma-coverage-istanbul-reporter/node_modules/make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "dependencies": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/karma-coverage-istanbul-reporter/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/karma-coverage-istanbul-reporter/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/karma-coverage-istanbul-reporter/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/karma-jasmine": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-5.1.0.tgz", - "integrity": "sha512-i/zQLFrfEpRyQoJF9fsCdTMOF5c2dK7C7OmsuKg2D0YSsuZSfQDiLuaiktbuio6F2wiCsZSnSnieIQ0ant/uzQ==", - "dev": true, - "dependencies": { - "jasmine-core": "^4.1.0" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "karma": "^6.0.0" - } - }, - "node_modules/karma-jasmine-html-reporter": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-2.0.0.tgz", - "integrity": "sha512-SB8HNNiazAHXM1vGEzf8/tSyEhkfxuDdhYdPBX2Mwgzt0OuF2gicApQ+uvXLID/gXyJQgvrM9+1/2SxZFUUDIA==", - "dev": true, - "peerDependencies": { - "jasmine-core": "^4.0.0", - "karma": "^6.0.0", - "karma-jasmine": "^5.0.0" - } - }, - "node_modules/karma-source-map-support": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", - "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", - "dev": true, - "dependencies": { - "source-map-support": "^0.5.5" - } - }, - "node_modules/karma/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/karma/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/karma/node_modules/mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", - "dev": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/karma/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/karma/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/karma/node_modules/tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "dev": true, - "dependencies": { - "rimraf": "^3.0.0" - }, - "engines": { - "node": ">=8.17.0" - } - }, - "node_modules/karma/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/karma/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/klona": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", - "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/less": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/less/-/less-4.1.3.tgz", - "integrity": "sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==", - "dev": true, - "dependencies": { - "copy-anything": "^2.0.1", - "parse-node-version": "^1.0.1", - "tslib": "^2.3.0" - }, - "bin": { - "lessc": "bin/lessc" - }, - "engines": { - "node": ">=6" - }, - "optionalDependencies": { - "errno": "^0.1.1", - "graceful-fs": "^4.1.2", - "image-size": "~0.5.0", - "make-dir": "^2.1.0", - "mime": "^1.4.1", - "needle": "^3.1.0", - "source-map": "~0.6.0" - } - }, - "node_modules/less-loader": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.1.0.tgz", - "integrity": "sha512-C+uDBV7kS7W5fJlUjq5mPBeBVhYpTIm5gB09APT9o3n/ILeaXVsiSFTbZpTJCJwQ/Crczfn3DmfQFwxYusWFug==", - "dev": true, - "dependencies": { - "klona": "^2.0.4" - }, - "engines": { - "node": ">= 14.15.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "less": "^3.5.0 || ^4.0.0", - "webpack": "^5.0.0" - } - }, - "node_modules/less/node_modules/make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "optional": true, - "dependencies": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/less/node_modules/semver": { - "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": { - "semver": "bin/semver" - } - }, - "node_modules/less/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/license-webpack-plugin": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", - "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==", - "dev": true, - "dependencies": { - "webpack-sources": "^3.0.0" - }, - "peerDependenciesMeta": { - "webpack": { - "optional": true - }, - "webpack-sources": { - "optional": true - } - } - }, - "node_modules/lie": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "dev": true, - "dependencies": { - "immediate": "~3.0.5" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "node_modules/loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", - "dev": true, - "engines": { - "node": ">=6.11.5" - } - }, - "node_modules/loader-utils": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", - "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", - "dev": true, - "engines": { - "node": ">= 12.13.0" - } - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-symbols/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/log-symbols/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/log-symbols/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/log-symbols/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/log4js": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.9.1.tgz", - "integrity": "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==", - "dev": true, - "dependencies": { - "date-format": "^4.0.14", - "debug": "^4.3.4", - "flatted": "^3.2.7", - "rfdc": "^1.3.0", - "streamroller": "^3.1.5" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/magic-string": { - "version": "0.29.0", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.29.0.tgz", - "integrity": "sha512-WcfidHrDjMY+eLjlU+8OvwREqHwpgCeKVBUpQ3OhYYuvfaYCUgcbuBzappNzZvg/v8onU3oQj+BYpkOJe9Iw4Q==", - "dev": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.13" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "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" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/make-fetch-happen": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", - "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", - "dev": true, - "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^16.1.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^2.0.3", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^9.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/@npmcli/fs": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", - "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", - "dev": true, - "dependencies": { - "@gar/promisify": "^1.1.3", - "semver": "^7.3.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/cacache": { - "version": "16.1.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", - "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", - "dev": true, - "dependencies": { - "@npmcli/fs": "^2.1.0", - "@npmcli/move-file": "^2.0.0", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "glob": "^8.0.1", - "infer-owner": "^1.0.4", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "mkdirp": "^1.0.4", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^9.0.0", - "tar": "^6.1.11", - "unique-filename": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/make-fetch-happen/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/make-fetch-happen/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/make-fetch-happen/node_modules/ssri": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", - "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", - "dev": true, - "dependencies": { - "minipass": "^3.1.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/unique-filename": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", - "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", - "dev": true, - "dependencies": { - "unique-slug": "^3.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/unique-slug": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", - "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/memfs": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", - "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", - "dev": true, - "dependencies": { - "fs-monkey": "^1.0.4" - }, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", - "dev": true - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/mini-css-extract-plugin": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.2.tgz", - "integrity": "sha512-EdlUizq13o0Pd+uCp+WO/JpkLvHRVGt97RqfeGhXqAcorYo1ypJSpkV+WDT0vY/kmh/p7wRdJNJtuyK540PXDw==", - "dev": true, - "dependencies": { - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minipass": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", - "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-collect/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-collect/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/minipass-fetch": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", - "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", - "dev": true, - "dependencies": { - "minipass": "^3.1.6", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/minipass-fetch/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-fetch/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-flush/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-flush/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/minipass-json-stream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", - "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", - "dev": true, - "dependencies": { - "jsonparse": "^1.3.1", - "minipass": "^3.0.0" - } - }, - "node_modules/minipass-json-stream/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-json-stream/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-pipeline/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-pipeline/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minizlib/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/multicast-dns": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", - "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", - "dev": true, - "dependencies": { - "dns-packet": "^5.2.2", - "thunky": "^1.0.2" - }, - "bin": { - "multicast-dns": "cli.js" - } - }, - "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, - "node_modules/needle": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/needle/-/needle-3.3.1.tgz", - "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", - "dev": true, - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.3", - "sax": "^1.2.4" - }, - "bin": { - "needle": "bin/needle" - }, - "engines": { - "node": ">= 4.4.x" - } - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "node_modules/ng2-charts": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ng2-charts/-/ng2-charts-4.1.1.tgz", - "integrity": "sha512-iHwXDbmX86lfeH8VRcsaW2tJATsuAZo4kvvC/Yk2l35zOHjevja1qBvO6BAibiDazi9r9aS6ZRJOqWPsz1pP2w==", - "dependencies": { - "lodash-es": "^4.17.15", - "tslib": "^2.3.0" - }, - "peerDependencies": { - "@angular/cdk": ">=14.0.0", - "@angular/common": ">=14.0.0", - "@angular/core": ">=14.0.0", - "chart.js": "^3.4.0 || ^4.0.0", - "rxjs": "^6.5.3 || ^7.4.0" - } - }, - "node_modules/ngx-cookie-service": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/ngx-cookie-service/-/ngx-cookie-service-15.0.0.tgz", - "integrity": "sha512-KU1JCjfpDTvD6L0FhHN9W/oP3Sue8yMAAK6XY3h/MEhrPS7vx6t3+h0ulY8l8R/9d1cmlQVyTHn1Jd1Jdf5K+g==", - "dependencies": { - "tslib": "^2.0.0" - }, - "peerDependencies": { - "@angular/common": "^15.0.0", - "@angular/core": "^15.0.0" - } - }, - "node_modules/ngx-spinner": { - "version": "15.0.1", - "resolved": "https://registry.npmjs.org/ngx-spinner/-/ngx-spinner-15.0.1.tgz", - "integrity": "sha512-7DjETmBpuXTwI68ad1xMKpwt4Cyz1eyu8E7AJcFiKa+8JAnbo0k1qfvWur0aemncRNxDxHoyl6jw42MsnE/B+g==", - "dependencies": { - "tslib": "^2.3.0" - }, - "peerDependencies": { - "@angular/common": "^15.0.0", - "@angular/core": "^15.0.0" - } - }, - "node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", - "dev": true, - "engines": { - "node": ">= 6.13.0" - } - }, - "node_modules/node-gyp": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.1.tgz", - "integrity": "sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==", - "dev": true, - "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^10.0.3", - "nopt": "^6.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": "^12.13 || ^14.13 || >=16" - } - }, - "node_modules/node-gyp/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", - "dev": true - }, - "node_modules/nopt": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", - "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", - "dev": true, - "dependencies": { - "abbrev": "^1.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/normalize-package-data": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-5.0.0.tgz", - "integrity": "sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q==", - "dev": true, - "dependencies": { - "hosted-git-info": "^6.0.0", - "is-core-module": "^2.8.1", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "devOptional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-bundled": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.0.tgz", - "integrity": "sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ==", - "dev": true, - "dependencies": { - "npm-normalize-package-bin": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-install-checks": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz", - "integrity": "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==", - "dev": true, - "dependencies": { - "semver": "^7.1.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-normalize-package-bin": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", - "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-package-arg": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz", - "integrity": "sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^6.0.0", - "proc-log": "^3.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^5.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-packlist": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-7.0.4.tgz", - "integrity": "sha512-d6RGEuRrNS5/N84iglPivjaJPxhDbZmlbTwTDX2IbcRHG5bZCdtysYMhwiPvcF4GisXHGn7xsxv+GQ7T/02M5Q==", - "dev": true, - "dependencies": { - "ignore-walk": "^6.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-pick-manifest": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-8.0.1.tgz", - "integrity": "sha512-mRtvlBjTsJvfCCdmPtiu2bdlx8d/KXtF7yNXNWe7G0Z36qWA9Ny5zXsI2PfBZEv7SXgoxTmNaTzGSbbzDZChoA==", - "dev": true, - "dependencies": { - "npm-install-checks": "^6.0.0", - "npm-normalize-package-bin": "^3.0.0", - "npm-package-arg": "^10.0.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-registry-fetch": { - "version": "14.0.5", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-14.0.5.tgz", - "integrity": "sha512-kIDMIo4aBm6xg7jOttupWZamsZRkAqMqwqqbVXnUqstY5+tapvv6bkH/qMR76jdgV+YljEUCyWx3hRYMrJiAgA==", - "dev": true, - "dependencies": { - "make-fetch-happen": "^11.0.0", - "minipass": "^5.0.0", - "minipass-fetch": "^3.0.0", - "minipass-json-stream": "^1.0.1", - "minizlib": "^2.1.2", - "npm-package-arg": "^10.0.0", - "proc-log": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-registry-fetch/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/npm-registry-fetch/node_modules/make-fetch-happen": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", - "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", - "dev": true, - "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^17.0.0", - "http-cache-semantics": "^4.1.1", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^5.0.0", - "minipass-fetch": "^3.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^10.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-registry-fetch/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm-registry-fetch/node_modules/minipass-fetch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", - "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", - "dev": true, - "dependencies": { - "minipass": "^7.0.3", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/npm-registry-fetch/node_modules/minipass-fetch/node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", - "dev": true, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npmlog": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", - "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", - "dev": true, - "dependencies": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", - "set-blocking": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.values": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", - "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dev": true, - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/open": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.1.tgz", - "integrity": "sha512-/4b7qZNhv6Uhd7jjnREh1NjnPxlTq+XNWPG88Ydkj5AILcA5m3ajvcg57pB24EQjKv0dK62XnDqk9c/hkIG5Kg==", - "dev": true, - "dependencies": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", - "dev": true, - "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "dependencies": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/ora/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/ora/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/ora/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/ora/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-retry": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", - "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", - "dev": true, - "dependencies": { - "@types/retry": "0.12.0", - "retry": "^0.13.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pacote": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.1.0.tgz", - "integrity": "sha512-FFcjtIl+BQNfeliSm7MZz5cpdohvUV1yjGnqgVM4UnVF7JslRY0ImXAygdaCDV0jjUADEWu4y5xsDV8brtrTLg==", - "dev": true, - "dependencies": { - "@npmcli/git": "^4.0.0", - "@npmcli/installed-package-contents": "^2.0.1", - "@npmcli/promise-spawn": "^6.0.1", - "@npmcli/run-script": "^6.0.0", - "cacache": "^17.0.0", - "fs-minipass": "^3.0.0", - "minipass": "^4.0.0", - "npm-package-arg": "^10.0.0", - "npm-packlist": "^7.0.0", - "npm-pick-manifest": "^8.0.0", - "npm-registry-fetch": "^14.0.0", - "proc-log": "^3.0.0", - "promise-retry": "^2.0.1", - "read-package-json": "^6.0.0", - "read-package-json-fast": "^3.0.0", - "sigstore": "^1.0.0", - "ssri": "^10.0.0", - "tar": "^6.1.11" - }, - "bin": { - "pacote": "lib/bin.js" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parse-node-version": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", - "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, - "node_modules/parse5-html-rewriting-stream": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-7.0.0.tgz", - "integrity": "sha512-mazCyGWkmCRWDI15Zp+UiCqMp/0dgEmkZRvhlsqqKYr4SsVm/TvnSpD9fCvqCA2zoWJcfRym846ejWBBHRiYEg==", - "dev": true, - "dependencies": { - "entities": "^4.3.0", - "parse5": "^7.0.0", - "parse5-sax-parser": "^7.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parse5-html-rewriting-stream/node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/parse5-html-rewriting-stream/node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "dev": true, - "dependencies": { - "entities": "^4.4.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parse5-htmlparser2-tree-adapter": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", - "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", - "dev": true, - "dependencies": { - "parse5": "^6.0.1" - } - }, - "node_modules/parse5-sax-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-7.0.0.tgz", - "integrity": "sha512-5A+v2SNsq8T6/mG3ahcz8ZtQ0OUFTatxPbeidoMB7tkJSGDY3tdfl4MHovtLQHkEn5CGxijNWRQHhRQ6IRpXKg==", - "dev": true, - "dependencies": { - "parse5": "^7.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parse5-sax-parser/node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/parse5-sax-parser/node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "dev": true, - "dependencies": { - "entities": "^4.4.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", - "dev": true - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-scurry": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", - "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", - "dev": true, - "dependencies": { - "lru-cache": "^9.1.1 || ^10.0.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", - "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", - "dev": true, - "engines": { - "node": "14 || >=16.14" - } - }, - "node_modules/path-scurry/node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", - "dev": true, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", - "dev": true - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "devOptional": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", - "dev": true, - "dependencies": { - "pinkie": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/piscina": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/piscina/-/piscina-3.2.0.tgz", - "integrity": "sha512-yn/jMdHRw+q2ZJhFhyqsmANcbF6V2QwmD84c6xRau+QpQOmtrBCoRGdvTfeuFDYXB5W2m6MfLkjkvQa9lUSmIA==", - "dev": true, - "dependencies": { - "eventemitter-asyncresource": "^1.0.0", - "hdr-histogram-js": "^2.0.1", - "hdr-histogram-percentiles-obj": "^3.0.0" - }, - "optionalDependencies": { - "nice-napi": "^1.0.2" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/postcss": { - "version": "8.4.21", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", - "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - } - ], - "dependencies": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-loader": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.0.2.tgz", - "integrity": "sha512-fUJzV/QH7NXUAqV8dWJ9Lg4aTkDCezpTS5HgJ2DvqznexTbSTxgi/dTECvTZ15BwKTtk8G/bqI/QTu2HPd3ZCg==", - "dev": true, - "dependencies": { - "cosmiconfig": "^7.0.0", - "klona": "^2.0.5", - "semver": "^7.3.8" - }, - "engines": { - "node": ">= 14.15.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "postcss": "^7.0.0 || ^8.0.1", - "webpack": "^5.0.0" - } - }, - "node_modules/postcss-modules-extract-imports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-local-by-default": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz", - "integrity": "sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==", - "dev": true, - "dependencies": { - "icss-utils": "^5.0.0", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.1.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-scope": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.1.0.tgz", - "integrity": "sha512-SaIbK8XW+MZbd0xHPf7kdfA/3eOt7vxJ72IRecn3EzuZVLr1r0orzf0MX/pN8m+NMDoo6X/SQd8oeKqGZd8PXg==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.4" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-values": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", - "dev": true, - "dependencies": { - "icss-utils": "^5.0.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.0.15", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz", - "integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==", - "dev": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/pretty-bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/proc-log": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", - "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "node_modules/promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "dev": true - }, - "node_modules/promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "dev": true, - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/promise-retry/node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/protractor": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/protractor/-/protractor-7.0.0.tgz", - "integrity": "sha512-UqkFjivi4GcvUQYzqGYNe0mLzfn5jiLmO8w9nMhQoJRLhy2grJonpga2IWhI6yJO30LibWXJJtA4MOIZD2GgZw==", - "deprecated": "We have news to share - Protractor is deprecated and will reach end-of-life by Summer 2023. To learn more and find out about other options please refer to this post on the Angular blog. Thank you for using and contributing to Protractor. https://goo.gle/state-of-e2e-in-angular", - "dev": true, - "dependencies": { - "@types/q": "^0.0.32", - "@types/selenium-webdriver": "^3.0.0", - "blocking-proxy": "^1.0.0", - "browserstack": "^1.5.1", - "chalk": "^1.1.3", - "glob": "^7.0.3", - "jasmine": "2.8.0", - "jasminewd2": "^2.1.0", - "q": "1.4.1", - "saucelabs": "^1.5.0", - "selenium-webdriver": "3.6.0", - "source-map-support": "~0.4.0", - "webdriver-js-extender": "2.1.0", - "webdriver-manager": "^12.1.7", - "yargs": "^15.3.1" - }, - "bin": { - "protractor": "bin/protractor", - "webdriver-manager": "bin/webdriver-manager" - }, - "engines": { - "node": ">=10.13.x" - } - }, - "node_modules/protractor/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/protractor/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/protractor/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", - "dev": true, - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/protractor/node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/protractor/node_modules/cliui/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/protractor/node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/protractor/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/protractor/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/protractor/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/protractor/node_modules/source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "dev": true, - "dependencies": { - "source-map": "^0.5.6" - } - }, - "node_modules/protractor/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/protractor/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/protractor/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/protractor/node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/protractor/node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/protractor/node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/protractor/node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, - "node_modules/protractor/node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/protractor/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dev": true, - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxy-addr/node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", - "dev": true, - "optional": true - }, - "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "engines": { - "node": ">=6" - } - }, - "node_modules/q": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", - "integrity": "sha512-/CdEdaw49VZVmyIDGUQKDDT53c7qBkO6g5CefWz91Ae+l4+cRtcDYwMTXh6me4O8TMldeGHG3N2Bl84V78Ywbg==", - "dev": true, - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, - "node_modules/qjobs": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", - "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", - "dev": true, - "engines": { - "node": ">=0.9" - } - }, - "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "dev": true, - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/raw-body/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/raw-body/node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/read-package-json": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-6.0.4.tgz", - "integrity": "sha512-AEtWXYfopBj2z5N5PbkAOeNHRPUg5q+Nen7QLxV8M2zJq1ym6/lCz3fYNTCXe19puu2d06jfHhrP7v/S2PtMMw==", - "dev": true, - "dependencies": { - "glob": "^10.2.2", - "json-parse-even-better-errors": "^3.0.0", - "normalize-package-data": "^5.0.0", - "npm-normalize-package-bin": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/read-package-json-fast": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", - "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", - "dev": true, - "dependencies": { - "json-parse-even-better-errors": "^3.0.0", - "npm-normalize-package-bin": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/read-package-json-fast/node_modules/json-parse-even-better-errors": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", - "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/read-package-json/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/read-package-json/node_modules/glob": { - "version": "10.3.10", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", - "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", - "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", - "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/read-package-json/node_modules/json-parse-even-better-errors": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", - "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/read-package-json/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/read-package-json/node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", - "dev": true, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "devOptional": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/reflect-metadata": { - "version": "0.1.14", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz", - "integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==", - "dev": true - }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true - }, - "node_modules/regenerate-unicode-properties": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", - "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", - "dev": true, - "dependencies": { - "regenerate": "^1.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", - "dev": true - }, - "node_modules/regenerator-transform": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", - "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.8.4" - } - }, - "node_modules/regex-parser": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.3.0.tgz", - "integrity": "sha512-TVILVSz2jY5D47F4mA4MppkBrafEaiUWJO/TcZHEIuI13AqoZMkK1WMA4Om1YkYbTx+9Ki1/tSUXbceyr9saRg==", - "dev": true - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", - "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "set-function-name": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexpu-core": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", - "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", - "dev": true, - "dependencies": { - "@babel/regjsgen": "^0.8.0", - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsparser": "^0.9.1", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regjsparser": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", - "dev": true, - "dependencies": { - "jsesc": "~0.5.0" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - } - }, - "node_modules/request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", - "dev": true, - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/request/node_modules/qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/request/node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "dev": true, - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true - }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-url-loader": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", - "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", - "dev": true, - "dependencies": { - "adjust-sourcemap-loader": "^4.0.0", - "convert-source-map": "^1.7.0", - "loader-utils": "^2.0.0", - "postcss": "^8.2.14", - "source-map": "0.6.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/resolve-url-loader/node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "dev": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, - "node_modules/resolve-url-loader/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rfdc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", - "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", - "dev": true - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/roboto-fontface": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/roboto-fontface/-/roboto-fontface-0.10.0.tgz", - "integrity": "sha512-OlwfYEgA2RdboZohpldlvJ1xngOins5d7ejqnIBWr9KaMxsnBqotpptRXTyfNRLnFpqzX6sTDt+X+a+6udnU8g==" - }, - "node_modules/robust-predicates": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", - "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" - }, - "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/rw": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" - }, - "node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, - "node_modules/rxjs/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/safe-array-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", - "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-array-concat/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safe-regex-test": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.1.tgz", - "integrity": "sha512-Y5NejJTTliTyY4H7sipGqY+RX5P87i3F7c4Rcepy72nq+mNLhIsD0W4c7kEmduMDQCSqtPsXPlSTsFhh2LQv+g==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "get-intrinsic": "^1.2.2", - "is-regex": "^1.1.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/sass": { - "version": "1.58.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.58.1.tgz", - "integrity": "sha512-bnINi6nPXbP1XNRaranMFEBZWUfdW/AF16Ql5+ypRxfTvCRTTKrLsMIakyDcayUt2t/RZotmL4kgJwNH5xO+bg==", - "dev": true, - "dependencies": { - "chokidar": ">=3.0.0 <4.0.0", - "immutable": "^4.0.0", - "source-map-js": ">=0.6.2 <2.0.0" - }, - "bin": { - "sass": "sass.js" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/sass-loader": { - "version": "13.2.0", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.2.0.tgz", - "integrity": "sha512-JWEp48djQA4nbZxmgC02/Wh0eroSUutulROUusYJO9P9zltRbNN80JCBHqRGzjd4cmZCa/r88xgfkjGD0TXsHg==", - "dev": true, - "dependencies": { - "klona": "^2.0.4", - "neo-async": "^2.6.2" - }, - "engines": { - "node": ">= 14.15.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "fibers": ">= 3.1.0", - "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", - "sass": "^1.3.0", - "sass-embedded": "*", - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "fibers": { - "optional": true - }, - "node-sass": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - } - } - }, - "node_modules/saucelabs": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.5.0.tgz", - "integrity": "sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ==", - "dev": true, - "dependencies": { - "https-proxy-agent": "^2.2.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/saucelabs/node_modules/agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", - "dev": true, - "dependencies": { - "es6-promisify": "^5.0.0" - }, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/saucelabs/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/saucelabs/node_modules/https-proxy-agent": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", - "dev": true, - "dependencies": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - }, - "engines": { - "node": ">= 4.5.0" - } - }, - "node_modules/sax": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", - "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==", - "dev": true - }, - "node_modules/schema-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", - "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", - "dev": true - }, - "node_modules/selenium-webdriver": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz", - "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==", - "dev": true, - "dependencies": { - "jszip": "^3.1.3", - "rimraf": "^2.5.4", - "tmp": "0.0.30", - "xml2js": "^0.4.17" - }, - "engines": { - "node": ">= 6.9.0" - } - }, - "node_modules/selenium-webdriver/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/selenium-webdriver/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/selenium-webdriver/node_modules/tmp": { - "version": "0.0.30", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", - "integrity": "sha512-HXdTB7lvMwcb55XFfrTM8CPr/IYREk4hVBFaQ4b/6nInrluSL86hfHm7vu0luYKCfyBZp2trCjpc8caC3vVM3w==", - "dev": true, - "dependencies": { - "os-tmpdir": "~1.0.1" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/selfsigned": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", - "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", - "dev": true, - "dependencies": { - "@types/node-forge": "^1.3.0", - "node-forge": "^1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "dev": true, - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", - "dev": true, - "dependencies": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/serve-index/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/serve-index/node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-index/node_modules/http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", - "dev": true, - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-index/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true - }, - "node_modules/serve-index/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/serve-index/node_modules/setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true - }, - "node_modules/serve-index/node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "dev": true, - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true - }, - "node_modules/set-function-length": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", - "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", - "dev": true, - "dependencies": { - "define-data-property": "^1.1.1", - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-function-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", - "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", - "dev": true, - "dependencies": { - "define-data-property": "^1.0.1", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "dev": true - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true - }, - "node_modules/shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - }, - "node_modules/sigstore": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-1.9.0.tgz", - "integrity": "sha512-0Zjz0oe37d08VeOtBIuB6cRriqXse2e8w+7yIy2XSXjshRKxbc2KkhXjL229jXSxEm7UbcjS76wcJDGQddVI9A==", - "dev": true, - "dependencies": { - "@sigstore/bundle": "^1.1.0", - "@sigstore/protobuf-specs": "^0.2.0", - "@sigstore/sign": "^1.0.0", - "@sigstore/tuf": "^1.0.3", - "make-fetch-happen": "^11.0.1" - }, - "bin": { - "sigstore": "bin/sigstore.js" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/sigstore/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/sigstore/node_modules/make-fetch-happen": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", - "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", - "dev": true, - "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^17.0.0", - "http-cache-semantics": "^4.1.1", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^5.0.0", - "minipass-fetch": "^3.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^10.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/sigstore/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/sigstore/node_modules/minipass-fetch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", - "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", - "dev": true, - "dependencies": { - "minipass": "^7.0.3", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/sigstore/node_modules/minipass-fetch/node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", - "dev": true, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "dev": true, - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socket.io": { - "version": "4.7.3", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.3.tgz", - "integrity": "sha512-SE+UIQXBQE+GPG2oszWMlsEmWtHVqw/h1VrYJGK5/MC7CH5p58N448HwIrtREcvR4jfdOJAY4ieQfxMr55qbbw==", - "dev": true, - "dependencies": { - "accepts": "~1.3.4", - "base64id": "~2.0.0", - "cors": "~2.8.5", - "debug": "~4.3.2", - "engine.io": "~6.5.2", - "socket.io-adapter": "~2.5.2", - "socket.io-parser": "~4.2.4" - }, - "engines": { - "node": ">=10.2.0" - } - }, - "node_modules/socket.io-adapter": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz", - "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==", - "dev": true, - "dependencies": { - "ws": "~8.11.0" - } - }, - "node_modules/socket.io-adapter/node_modules/ws": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", - "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/socket.io-parser": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", - "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", - "dev": true, - "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/sockjs": { - "version": "0.3.24", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", - "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", - "dev": true, - "dependencies": { - "faye-websocket": "^0.11.3", - "uuid": "^8.3.2", - "websocket-driver": "^0.7.4" - } - }, - "node_modules/sockjs/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/socks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", - "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", - "dev": true, - "dependencies": { - "ip": "^2.0.0", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.13.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", - "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", - "dev": true, - "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-loader": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-4.0.1.tgz", - "integrity": "sha512-oqXpzDIByKONVY8g1NUPOTQhe0UTU5bWUl32GSkqK2LjJj0HmwTMVKxcUip0RgAYhY1mqgOxjbQM48a0mmeNfA==", - "dev": true, - "dependencies": { - "abab": "^2.0.6", - "iconv-lite": "^0.6.3", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": ">= 14.15.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.72.1" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "deprecated": "Please use @jridgewell/sourcemap-codec instead" - }, - "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.16", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", - "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", - "dev": true - }, - "node_modules/spdy": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", - "dev": true, - "dependencies": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/spdy-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", - "dev": true, - "dependencies": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "node_modules/sshpk": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", - "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", - "dev": true, - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ssri": { - "version": "10.0.5", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", - "integrity": "sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==", - "dev": true, - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/ssri/node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", - "dev": true, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/stop-iteration-iterator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", - "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", - "dev": true, - "dependencies": { - "internal-slot": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/streamroller": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", - "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==", - "dev": true, - "dependencies": { - "date-format": "^4.0.14", - "debug": "^4.3.4", - "fs-extra": "^8.1.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/symbol-observable": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", - "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/tar": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", - "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", - "dev": true, - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/tar/node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tar/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/tar/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/terser": { - "version": "5.16.3", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.3.tgz", - "integrity": "sha512-v8wWLaS/xt3nE9dgKEWhNUFP6q4kngO5B8eYFUuebsu7Dw/UNAnpUod6UHo04jSSkv8TzKHjZDSd7EXdDQAl8Q==", - "dev": true, - "dependencies": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser-webpack-plugin": { - "version": "5.3.10", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", - "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.20", - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.1", - "terser": "^5.26.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "uglify-js": { - "optional": true - } - } - }, - "node_modules/terser-webpack-plugin/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/terser-webpack-plugin/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/terser-webpack-plugin/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/terser-webpack-plugin/node_modules/terser": { - "version": "5.26.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.26.0.tgz", - "integrity": "sha512-dytTGoE2oHgbNV9nTzgBEPaqAWvcJNl66VZ0BkJqlvp71IjO8CxdBx/ykCNb47cLnCmCvRZ6ZR0tLkqvZCdVBQ==", - "dev": true, - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/test-exclude/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, - "node_modules/thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true - }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "devOptional": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true, - "bin": { - "tree-kill": "cli.js" - } - }, - "node_modules/ts-api-utils": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", - "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", - "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", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "dev": true, - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/tsconfig-paths": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", - "dev": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/tsutils/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tuf-js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-1.1.7.tgz", - "integrity": "sha512-i3P9Kgw3ytjELUfpuKVDNBJvk4u5bXL6gskv572mcevPbSKCV3zt3djhmlEQ65yERjIbOSncy7U4cQJaB1CBCg==", - "dev": true, - "dependencies": { - "@tufjs/models": "1.0.4", - "debug": "^4.3.4", - "make-fetch-happen": "^11.1.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/tuf-js/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/tuf-js/node_modules/make-fetch-happen": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", - "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", - "dev": true, - "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^17.0.0", - "http-cache-semantics": "^4.1.1", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^5.0.0", - "minipass-fetch": "^3.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^10.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/tuf-js/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/tuf-js/node_modules/minipass-fetch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", - "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", - "dev": true, - "dependencies": { - "minipass": "^7.0.3", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/tuf-js/node_modules/minipass-fetch/node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", - "dev": true, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dev": true, - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typed-array-buffer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", - "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", - "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", - "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-assert": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", - "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", - "dev": true - }, - "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/ua-parser-js": { - "version": "0.7.37", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.37.tgz", - "integrity": "sha512-xV8kqRKM+jhMvcHWUKthV9fNebIzrNy//2O9ZwWcfiBFR5f25XVZPLlEajk/sf3Ra15V92isyQqnIEXRDaZWEA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/ua-parser-js" - }, - { - "type": "paypal", - "url": "https://paypal.me/faisalman" - }, - { - "type": "github", - "url": "https://github.com/sponsors/faisalman" - } - ], - "engines": { - "node": "*" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "dev": true, - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", - "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unique-filename": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", - "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", - "dev": true, - "dependencies": { - "unique-slug": "^4.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/unique-slug": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", - "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/validate-npm-package-name": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", - "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", - "dev": true, - "dependencies": { - "builtins": "^5.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "node_modules/verror/node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true - }, - "node_modules/void-elements": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", - "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", - "dev": true, - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", - "dev": true, - "dependencies": { - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "dependencies": { - "defaults": "^1.0.3" - } - }, - "node_modules/webdriver-js-extender": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz", - "integrity": "sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ==", - "dev": true, - "dependencies": { - "@types/selenium-webdriver": "^3.0.0", - "selenium-webdriver": "^3.0.1" - }, - "engines": { - "node": ">=6.9.x" - } - }, - "node_modules/webdriver-manager": { - "version": "12.1.9", - "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.1.9.tgz", - "integrity": "sha512-Yl113uKm8z4m/KMUVWHq1Sjtla2uxEBtx2Ue3AmIlnlPAKloDn/Lvmy6pqWCUersVISpdMeVpAaGbNnvMuT2LQ==", - "dev": true, - "dependencies": { - "adm-zip": "^0.5.2", - "chalk": "^1.1.1", - "del": "^2.2.0", - "glob": "^7.0.3", - "ini": "^1.3.4", - "minimist": "^1.2.0", - "q": "^1.4.1", - "request": "^2.87.0", - "rimraf": "^2.5.2", - "semver": "^5.3.0", - "xml2js": "^0.4.17" - }, - "bin": { - "webdriver-manager": "bin/webdriver-manager" - }, - "engines": { - "node": ">=6.9.x" - } - }, - "node_modules/webdriver-manager/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webdriver-manager/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webdriver-manager/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", - "dev": true, - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webdriver-manager/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/webdriver-manager/node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "node_modules/webdriver-manager/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/webdriver-manager/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/webdriver-manager/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webdriver-manager/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/webpack": { - "version": "5.76.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz", - "integrity": "sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==", - "dev": true, - "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^0.0.51", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.7.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.10.0", - "es-module-lexer": "^0.9.0", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.4.0", - "webpack-sources": "^3.2.3" - }, - "bin": { - "webpack": "bin/webpack.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-dev-middleware": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.0.1.tgz", - "integrity": "sha512-PZPZ6jFinmqVPJZbisfggDiC+2EeGZ1ZByyMP5sOFJcPPWSexalISz+cvm+j+oYPT7FIJyxT76esjnw9DhE5sw==", - "dev": true, - "dependencies": { - "colorette": "^2.0.10", - "memfs": "^3.4.12", - "mime-types": "^2.1.31", - "range-parser": "^1.2.1", - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 14.15.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - } - }, - "node_modules/webpack-dev-server": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.11.1.tgz", - "integrity": "sha512-lILVz9tAUy1zGFwieuaQtYiadImb5M3d+H+L1zDYalYoDl0cksAB1UNyuE5MMWJrG6zR1tXkCP2fitl7yoUJiw==", - "dev": true, - "dependencies": { - "@types/bonjour": "^3.5.9", - "@types/connect-history-api-fallback": "^1.3.5", - "@types/express": "^4.17.13", - "@types/serve-index": "^1.9.1", - "@types/serve-static": "^1.13.10", - "@types/sockjs": "^0.3.33", - "@types/ws": "^8.5.1", - "ansi-html-community": "^0.0.8", - "bonjour-service": "^1.0.11", - "chokidar": "^3.5.3", - "colorette": "^2.0.10", - "compression": "^1.7.4", - "connect-history-api-fallback": "^2.0.0", - "default-gateway": "^6.0.3", - "express": "^4.17.3", - "graceful-fs": "^4.2.6", - "html-entities": "^2.3.2", - "http-proxy-middleware": "^2.0.3", - "ipaddr.js": "^2.0.1", - "open": "^8.0.9", - "p-retry": "^4.5.0", - "rimraf": "^3.0.2", - "schema-utils": "^4.0.0", - "selfsigned": "^2.1.1", - "serve-index": "^1.9.1", - "sockjs": "^0.3.24", - "spdy": "^4.0.2", - "webpack-dev-middleware": "^5.3.1", - "ws": "^8.4.2" - }, - "bin": { - "webpack-dev-server": "bin/webpack-dev-server.js" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.37.0 || ^5.0.0" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-dev-server/node_modules/webpack-dev-middleware": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", - "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", - "dev": true, - "dependencies": { - "colorette": "^2.0.10", - "memfs": "^3.4.3", - "mime-types": "^2.1.31", - "range-parser": "^1.2.1", - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" - } - }, - "node_modules/webpack-merge": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", - "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", - "dev": true, - "dependencies": { - "clone-deep": "^4.0.1", - "wildcard": "^2.0.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "dev": true, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack-subresource-integrity": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz", - "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==", - "dev": true, - "dependencies": { - "typed-assert": "^1.0.8" - }, - "engines": { - "node": ">= 12" - }, - "peerDependencies": { - "html-webpack-plugin": ">= 5.0.0-beta.1 < 6", - "webpack": "^5.12.0" - }, - "peerDependenciesMeta": { - "html-webpack-plugin": { - "optional": true - } - } - }, - "node_modules/webpack/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/webpack/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/webpack/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", - "dev": true, - "dependencies": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", - "dev": true, - "dependencies": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-module": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", - "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", - "dev": true - }, - "node_modules/which-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", - "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.4", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dev": true, - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "node_modules/wildcard": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", - "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", - "dev": true - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/ws": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", - "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "dev": true, - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/yargs": { - "version": "17.6.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", - "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", - "dev": true, - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zone.js": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.13.0.tgz", - "integrity": "sha512-7m3hNNyswsdoDobCkYNAy5WiUulkMd3+fWaGT9ij6iq3Zr/IwJo4RMCYPSDjT+r7tnPErmY9sZpKhWQ8S5k6XQ==", - "dependencies": { - "tslib": "^2.3.0" - } + "name": "openems-ui", + "version": "2024.5.0-SNAPSHOT", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "openems-ui", + "version": "2024.5.0-SNAPSHOT", + "license": "AGPL-3.0", + "dependencies": { + "@angular/animations": "~16.2.12", + "@angular/common": "~16.2.12", + "@angular/core": "~16.2.12", + "@angular/forms": "~16.2.12", + "@angular/platform-browser": "~16.2.12", + "@angular/platform-browser-dynamic": "~16.2.12", + "@angular/router": "~16.2.12", + "@angular/service-worker": "~16.2.12", + "@ionic/angular": "^6.7.5", + "@ngx-formly/core": "^6.3.0", + "@ngx-formly/ionic": "^6.3.0", + "@ngx-formly/schematics": "^6.3.0", + "@ngx-translate/core": "^14.0.0", + "@nodro7/angular-mydatepicker": "^0.14.0", + "chart.js": "^4.4.2", + "chartjs-adapter-date-fns": "^3.0.0", + "chartjs-plugin-zoom": "^2.0.1", + "classlist.js": "^1.1.20150312", + "compare-versions": "^6.1.0", + "d3": "^7.9.0", + "date-fns": "^2.30.0", + "file-saver-es": "^2.0.5", + "ng2-charts": "4.1.1", + "ngx-cookie-service": "^16.1.0", + "ngx-spinner": "^16.0.2", + "roboto-fontface": "^0.10.0", + "rxjs": "~6.6.7", + "swiper": "11.1.1", + "tslib": "^2.6.2", + "uuid": "^9.0.1", + "zone.js": "~0.13.3" + }, + "devDependencies": { + "@angular-devkit/build-angular": "^16.2.13", + "@angular-eslint/builder": "^16.3.1", + "@angular-eslint/eslint-plugin": "^16.3.1", + "@angular-eslint/eslint-plugin-template": "^16.3.1", + "@angular-eslint/template-parser": "^16.3.1", + "@angular/cli": "^16.2.13", + "@angular/compiler": "^16.2.12", + "@angular/compiler-cli": "^16.2.12", + "@angular/language-service": "^16.2.12", + "@ionic/angular-toolkit": "^11.0.1", + "@types/jasmine": "~4.3.6", + "@types/jasminewd2": "~2.0.13", + "@types/node": "^20.12.6", + "@types/uuid": "^9.0.8", + "@typescript-eslint/eslint-plugin": "^6.21.0", + "@typescript-eslint/parser": "^6.21.0", + "eslint": "^8.57.0", + "eslint-plugin-import": "2.29.1", + "eslint-plugin-jsdoc": "48.2.3", + "eslint-plugin-prefer-arrow": "1.2.3", + "eslint-plugin-unused-imports": "^3.1.0", + "jasmine-core": "~4.5.0", + "jasmine-spec-reporter": "~7.0.0", + "karma": "~6.4.2", + "karma-chrome-launcher": "~3.2.0", + "karma-coverage": "~2.2.1", + "karma-coverage-istanbul-reporter": "~3.0.3", + "karma-jasmine": "~5.1.0", + "karma-jasmine-html-reporter": "^2.1.0", + "protractor": "~7.0.0", + "ts-node": "^10.9.2", + "typescript": "~4.9.5", + "typescript-strict-plugin": "^2.4.1" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@angular-devkit/architect": { + "version": "0.1602.13", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.13.tgz", + "integrity": "sha512-ejrOYoXgbhDYjdaW4B2SyWeb6AqR8vqqzMyvCq2JX7fo08IhLnVu1fcl0fwr161l37TuzgPNWrHSciOzzmZDkw==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "16.2.13", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/architect/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@angular-devkit/build-angular": { + "version": "16.2.13", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-16.2.13.tgz", + "integrity": "sha512-2G8gnBpBKcu+/jJH5DJZyMgn2RwDFPgiNSkcLKFg5DdqVFVT3CCoZAobfpAEMndrysfMmoUPGuAmsgCfdczQjg==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "2.2.1", + "@angular-devkit/architect": "0.1602.13", + "@angular-devkit/build-webpack": "0.1602.13", + "@angular-devkit/core": "16.2.13", + "@babel/core": "7.22.9", + "@babel/generator": "7.22.9", + "@babel/helper-annotate-as-pure": "7.22.5", + "@babel/helper-split-export-declaration": "7.22.6", + "@babel/plugin-proposal-async-generator-functions": "7.20.7", + "@babel/plugin-transform-async-to-generator": "7.22.5", + "@babel/plugin-transform-runtime": "7.22.9", + "@babel/preset-env": "7.22.9", + "@babel/runtime": "7.22.6", + "@babel/template": "7.22.5", + "@discoveryjs/json-ext": "0.5.7", + "@ngtools/webpack": "16.2.13", + "@vitejs/plugin-basic-ssl": "1.0.1", + "ansi-colors": "4.1.3", + "autoprefixer": "10.4.14", + "babel-loader": "9.1.3", + "babel-plugin-istanbul": "6.1.1", + "browserslist": "^4.21.5", + "chokidar": "3.5.3", + "copy-webpack-plugin": "11.0.0", + "critters": "0.0.20", + "css-loader": "6.8.1", + "esbuild-wasm": "0.18.17", + "fast-glob": "3.3.1", + "guess-parser": "0.4.22", + "https-proxy-agent": "5.0.1", + "inquirer": "8.2.4", + "jsonc-parser": "3.2.0", + "karma-source-map-support": "1.4.0", + "less": "4.1.3", + "less-loader": "11.1.0", + "license-webpack-plugin": "4.0.2", + "loader-utils": "3.2.1", + "magic-string": "0.30.1", + "mini-css-extract-plugin": "2.7.6", + "mrmime": "1.0.1", + "open": "8.4.2", + "ora": "5.4.1", + "parse5-html-rewriting-stream": "7.0.0", + "picomatch": "2.3.1", + "piscina": "4.0.0", + "postcss": "8.4.31", + "postcss-loader": "7.3.3", + "resolve-url-loader": "5.0.0", + "rxjs": "7.8.1", + "sass": "1.64.1", + "sass-loader": "13.3.2", + "semver": "7.5.4", + "source-map-loader": "4.0.1", + "source-map-support": "0.5.21", + "terser": "5.19.2", + "text-table": "0.2.0", + "tree-kill": "1.2.2", + "tslib": "2.6.1", + "vite": "4.5.2", + "webpack": "5.88.2", + "webpack-dev-middleware": "6.1.2", + "webpack-dev-server": "4.15.1", + "webpack-merge": "5.9.0", + "webpack-subresource-integrity": "5.1.0" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "optionalDependencies": { + "esbuild": "0.18.17" + }, + "peerDependencies": { + "@angular/compiler-cli": "^16.0.0", + "@angular/localize": "^16.0.0", + "@angular/platform-server": "^16.0.0", + "@angular/service-worker": "^16.0.0", + "jest": "^29.5.0", + "jest-environment-jsdom": "^29.5.0", + "karma": "^6.3.0", + "ng-packagr": "^16.0.0", + "protractor": "^7.0.0", + "tailwindcss": "^2.0.0 || ^3.0.0", + "typescript": ">=4.9.3 <5.2" + }, + "peerDependenciesMeta": { + "@angular/localize": { + "optional": true + }, + "@angular/platform-server": { + "optional": true + }, + "@angular/service-worker": { + "optional": true + }, + "jest": { + "optional": true + }, + "jest-environment-jsdom": { + "optional": true + }, + "karma": { + "optional": true + }, + "ng-packagr": { + "optional": true + }, + "protractor": { + "optional": true + }, + "tailwindcss": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@babel/core": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.9.tgz", + "integrity": "sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.9", + "@babel/helper-compilation-targets": "^7.22.9", + "@babel/helper-module-transforms": "^7.22.9", + "@babel/helpers": "^7.22.6", + "@babel/parser": "^7.22.7", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.8", + "@babel/types": "^7.22.5", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.2", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@babel/core/node_modules/semver": { + "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" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@babel/runtime": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.6.tgz", + "integrity": "sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.13.11" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@babel/template": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", + "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/@angular-devkit/build-angular/node_modules/fast-glob": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/@angular-devkit/build-angular/node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, + "node_modules/@angular-devkit/build-angular/node_modules/less": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/less/-/less-4.1.3.tgz", + "integrity": "sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==", + "dev": true, + "dependencies": { + "copy-anything": "^2.0.1", + "parse-node-version": "^1.0.1", + "tslib": "^2.3.0" + }, + "bin": { + "lessc": "bin/lessc" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "source-map": "~0.6.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "dev": true + }, + "node_modules/@angular-devkit/build-angular/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/@angular-devkit/build-angular/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/@angular-devkit/build-angular/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/terser": { + "version": "5.19.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.19.2.tgz", + "integrity": "sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/tslib": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", + "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==", + "dev": true + }, + "node_modules/@angular-devkit/build-angular/node_modules/webpack": { + "version": "5.88.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz", + "integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.7", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@angular-devkit/build-webpack": { + "version": "0.1602.13", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1602.13.tgz", + "integrity": "sha512-H7CqnC0kvWR0Q45ZXsCO3M9lGd4dOajEmkCVmq7vVptU3nJRbCqJ0ZScj9bH5YSlcdO0jPbOdcTELWyEZ3BMFQ==", + "dev": true, + "dependencies": { + "@angular-devkit/architect": "0.1602.13", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "webpack": "^5.30.0", + "webpack-dev-server": "^4.0.0" + } + }, + "node_modules/@angular-devkit/build-webpack/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@angular-devkit/core": { + "version": "16.2.13", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.13.tgz", + "integrity": "sha512-6jTlYOIeYsOF/Vw/hBNusjoCmKJBByoyGS1Fu2Yav8ltxYK04aDtI73l9JJB/5Cpzhc4YELrMqBMH7in5Vowaw==", + "dev": true, + "dependencies": { + "ajv": "8.12.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.2.0", + "picomatch": "2.3.1", + "rxjs": "7.8.1", + "source-map": "0.7.4" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/core/node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, + "node_modules/@angular-devkit/core/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@angular-devkit/schematics": { + "version": "16.2.13", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-16.2.13.tgz", + "integrity": "sha512-uhhJZpppaeuT/2V6RiCheJKzS4bAZADL+Gw59VJaojqS8ssdG1UzvqRJokIzFzP7+MhHWylZBWUvWLQxuUvtsA==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "16.2.13", + "jsonc-parser": "3.2.0", + "magic-string": "0.30.1", + "ora": "5.4.1", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/schematics/node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, + "node_modules/@angular-devkit/schematics/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@angular-eslint/builder": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-16.3.1.tgz", + "integrity": "sha512-PmIOnRwqdOW1bvZtpTGBTDcOq/Czm3D+IPC/k90yIMs1VsAtcxqUmUtELje+ylJeb2LPeEZavekSnEpcatM4HQ==", + "dev": true, + "dependencies": { + "@nx/devkit": "16.5.1", + "nx": "16.5.1" + }, + "peerDependencies": { + "eslint": "^7.20.0 || ^8.0.0", + "typescript": "*" + } + }, + "node_modules/@angular-eslint/bundled-angular-compiler": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-16.3.1.tgz", + "integrity": "sha512-m4WP1xwS9XLcC/3n6lIcG5HZoai/5eb5W3xm48GVcv//0qE2p7S96RSgKPgGHvif5pF8O9xAqEWs3gDEG45+7A==", + "dev": true + }, + "node_modules/@angular-eslint/eslint-plugin": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-16.3.1.tgz", + "integrity": "sha512-kSc8ESfoy8TUSthbq0Lpq9e17I+3Smy4rHoNpKCFEGuJgPs0+OssZMxB6a5EawGbv2EKTPEtrxzFm1WsLR0U9Q==", + "dev": true, + "dependencies": { + "@angular-eslint/utils": "16.3.1", + "@typescript-eslint/utils": "5.62.0" + }, + "peerDependencies": { + "eslint": "^7.20.0 || ^8.0.0", + "typescript": "*" + } + }, + "node_modules/@angular-eslint/eslint-plugin-template": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-16.3.1.tgz", + "integrity": "sha512-+RcFEWqNiRt3+5jXvmlIDlXtP9+vjdmgmVL6tt8yDbqdjBOewtyMu4pE4YaR4sFboyxgME9PbO2WrOyPXh6xjg==", + "dev": true, + "dependencies": { + "@angular-eslint/bundled-angular-compiler": "16.3.1", + "@angular-eslint/utils": "16.3.1", + "@typescript-eslint/type-utils": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "aria-query": "5.3.0", + "axobject-query": "4.0.0" + }, + "peerDependencies": { + "eslint": "^7.20.0 || ^8.0.0", + "typescript": "*" + } + }, + "node_modules/@angular-eslint/template-parser": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-16.3.1.tgz", + "integrity": "sha512-9+SxUtxB2iOnm0ldS2ow0stMxe02rB/TxeMIe8fxsLFHZdw8RQvs/p3HLvVHXzv6gUblMHebIb/ubUmwEVb2SA==", + "dev": true, + "dependencies": { + "@angular-eslint/bundled-angular-compiler": "16.3.1", + "eslint-scope": "^7.0.0" + }, + "peerDependencies": { + "eslint": "^7.20.0 || ^8.0.0", + "typescript": "*" + } + }, + "node_modules/@angular-eslint/template-parser/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@angular-eslint/template-parser/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@angular-eslint/utils": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-16.3.1.tgz", + "integrity": "sha512-tEBcce0rG+DmcPO8jhRffUFDioGw3G4cUAE15XlRctY1J3QzOBH9HdUOTDt0mMjBgpWCzh0YVT1Moh2bPXU9Xg==", + "dev": true, + "dependencies": { + "@angular-eslint/bundled-angular-compiler": "16.3.1", + "@typescript-eslint/utils": "5.62.0" + }, + "peerDependencies": { + "eslint": "^7.20.0 || ^8.0.0", + "typescript": "*" + } + }, + "node_modules/@angular/animations": { + "version": "16.2.12", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-16.2.12.tgz", + "integrity": "sha512-MD0ElviEfAJY8qMOd6/jjSSvtqER2RDAi0lxe6EtUacC1DHCYkaPrKW4vLqY+tmZBg1yf+6n+uS77pXcHHcA3w==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0" + }, + "peerDependencies": { + "@angular/core": "16.2.12" + } + }, + "node_modules/@angular/cdk": { + "version": "15.2.9", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-15.2.9.tgz", + "integrity": "sha512-koaM07N1AIQ5oHU27l0/FoQSSoYAwlAYwVZ4Di3bYrJsTBNCN2Xsby7wI8gZxdepMnV4Fe9si382BDBov+oO4Q==", + "peer": true, + "dependencies": { + "tslib": "^2.3.0" + }, + "optionalDependencies": { + "parse5": "^7.1.2" + }, + "peerDependencies": { + "@angular/common": "^15.0.0 || ^16.0.0", + "@angular/core": "^15.0.0 || ^16.0.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/cdk/node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "optional": true, + "peer": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/@angular/cli": { + "version": "16.2.13", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-16.2.13.tgz", + "integrity": "sha512-Zs/IHV0qeQBlRYp3XTJP96KKMFrOVd4gFWEXyt8xVbma9W7UCWr/0C6D8HRFjheiT40TSa2Suwpk6Hppm+9ESA==", + "dev": true, + "dependencies": { + "@angular-devkit/architect": "0.1602.13", + "@angular-devkit/core": "16.2.13", + "@angular-devkit/schematics": "16.2.13", + "@schematics/angular": "16.2.13", + "@yarnpkg/lockfile": "1.1.0", + "ansi-colors": "4.1.3", + "ini": "4.1.1", + "inquirer": "8.2.4", + "jsonc-parser": "3.2.0", + "npm-package-arg": "10.1.0", + "npm-pick-manifest": "8.0.1", + "open": "8.4.2", + "ora": "5.4.1", + "pacote": "15.2.0", + "resolve": "1.22.2", + "semver": "7.5.4", + "symbol-observable": "4.0.0", + "yargs": "17.7.2" + }, + "bin": { + "ng": "bin/ng.js" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/cli/node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, + "node_modules/@angular/cli/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@angular/cli/node_modules/resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "dev": true, + "dependencies": { + "is-core-module": "^2.11.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@angular/cli/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/@angular/cli/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@angular/common": { + "version": "16.2.12", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-16.2.12.tgz", + "integrity": "sha512-B+WY/cT2VgEaz9HfJitBmgdk4I333XG/ybC98CMC4Wz8E49T8yzivmmxXB3OD6qvjcOB6ftuicl6WBqLbZNg2w==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0" + }, + "peerDependencies": { + "@angular/core": "16.2.12", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/compiler": { + "version": "16.2.12", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-16.2.12.tgz", + "integrity": "sha512-6SMXUgSVekGM7R6l1Z9rCtUGtlg58GFmgbpMCsGf+VXxP468Njw8rjT2YZkf5aEPxEuRpSHhDYjqz7n14cwCXQ==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0" + }, + "peerDependencies": { + "@angular/core": "16.2.12" + }, + "peerDependenciesMeta": { + "@angular/core": { + "optional": true + } + } + }, + "node_modules/@angular/compiler-cli": { + "version": "16.2.12", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-16.2.12.tgz", + "integrity": "sha512-pWSrr152562ujh6lsFZR8NfNc5Ljj+zSTQO44DsuB0tZjwEpnRcjJEgzuhGXr+CoiBf+jTSPZKemtSktDk5aaA==", + "dev": true, + "dependencies": { + "@babel/core": "7.23.2", + "@jridgewell/sourcemap-codec": "^1.4.14", + "chokidar": "^3.0.0", + "convert-source-map": "^1.5.1", + "reflect-metadata": "^0.1.2", + "semver": "^7.0.0", + "tslib": "^2.3.0", + "yargs": "^17.2.1" + }, + "bin": { + "ng-xi18n": "bundles/src/bin/ng_xi18n.js", + "ngc": "bundles/src/bin/ngc.js", + "ngcc": "bundles/ngcc/index.js" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0" + }, + "peerDependencies": { + "@angular/compiler": "16.2.12", + "typescript": ">=4.9.3 <5.2" + } + }, + "node_modules/@angular/core": { + "version": "16.2.12", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-16.2.12.tgz", + "integrity": "sha512-GLLlDeke/NjroaLYOks0uyzFVo6HyLl7VOm0K1QpLXnYvW63W9Ql/T3yguRZa7tRkOAeFZ3jw+1wnBD4O8MoUA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0" + }, + "peerDependencies": { + "rxjs": "^6.5.3 || ^7.4.0", + "zone.js": "~0.13.0" + } + }, + "node_modules/@angular/forms": { + "version": "16.2.12", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-16.2.12.tgz", + "integrity": "sha512-1Eao89hlBgLR3v8tU91vccn21BBKL06WWxl7zLpQmG6Hun+2jrThgOE4Pf3os4fkkbH4Apj0tWL2fNIWe/blbw==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0" + }, + "peerDependencies": { + "@angular/common": "16.2.12", + "@angular/core": "16.2.12", + "@angular/platform-browser": "16.2.12", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/language-service": { + "version": "16.2.12", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-16.2.12.tgz", + "integrity": "sha512-sZwB+ZEjChx9EYcqPaS4OnhC/q5RcedZjIdM9mCxuU/MtseURRYRI/8Hnm1RHo9qyc5PmsQpg7p9Vp/5hXLUjw==", + "dev": true, + "engines": { + "node": "^16.14.0 || >=18.10.0" + } + }, + "node_modules/@angular/platform-browser": { + "version": "16.2.12", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-16.2.12.tgz", + "integrity": "sha512-NnH7ju1iirmVEsUq432DTm0nZBGQsBrU40M3ZeVHMQ2subnGiyUs3QyzDz8+VWLL/T5xTxWLt9BkDn65vgzlIQ==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0" + }, + "peerDependencies": { + "@angular/animations": "16.2.12", + "@angular/common": "16.2.12", + "@angular/core": "16.2.12" + }, + "peerDependenciesMeta": { + "@angular/animations": { + "optional": true + } + } + }, + "node_modules/@angular/platform-browser-dynamic": { + "version": "16.2.12", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-16.2.12.tgz", + "integrity": "sha512-ya54jerNgreCVAR278wZavwjrUWImMr2F8yM5n9HBvsMBbFaAQ83anwbOEiHEF2BlR+gJiEBLfpuPRMw20pHqw==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0" + }, + "peerDependencies": { + "@angular/common": "16.2.12", + "@angular/compiler": "16.2.12", + "@angular/core": "16.2.12", + "@angular/platform-browser": "16.2.12" + } + }, + "node_modules/@angular/router": { + "version": "16.2.12", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-16.2.12.tgz", + "integrity": "sha512-aU6QnYSza005V9P3W6PpkieL56O0IHps96DjqI1RS8yOJUl3THmokqYN4Fm5+HXy4f390FN9i6ftadYQDKeWmA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0" + }, + "peerDependencies": { + "@angular/common": "16.2.12", + "@angular/core": "16.2.12", + "@angular/platform-browser": "16.2.12", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/service-worker": { + "version": "16.2.12", + "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-16.2.12.tgz", + "integrity": "sha512-o0z0s4c76NmRASa+mUHn/q6vUKQNa06mGmLBDKm84vRQ1sQ2TJv+R1p8K9WkiM5mGy6tjQCDOgaz13TcxMFWOQ==", + "dependencies": { + "tslib": "^2.3.0" + }, + "bin": { + "ngsw-config": "ngsw-config.js" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0" + }, + "peerDependencies": { + "@angular/common": "16.2.12", + "@angular/core": "16.2.12" + } + }, + "node_modules/@assemblyscript/loader": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.10.1.tgz", + "integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==", + "dev": true + }, + "node_modules/@babel/code-frame": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz", + "integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-module-transforms": "^7.23.0", + "@babel/helpers": "^7.23.2", + "@babel/parser": "^7.23.0", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.2", + "@babel/types": "^7.23.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/@babel/generator": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz", + "integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/@babel/core/node_modules/semver": { + "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" + } + }, + "node_modules/@babel/generator": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.9.tgz", + "integrity": "sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", + "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "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" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.4.tgz", + "integrity": "sha512-lG75yeuUSVu0pIcbhiYMXBXANHrpUPaOfu7ryAzskCgKUHuAxRQI5ssrtmF0X9UXldPlvT0XM/A4F44OXRt6iQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.24.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "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" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", + "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "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" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.1.tgz", + "integrity": "sha512-o7SDgTJuvx5vLKD6SFvkydkSMBvahDKGiNJzG22IZYXhiqoe9efY7zocICBgzHV4IRg5wdgl2nEL/tulKIEIbA==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", + "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", + "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", + "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.1.tgz", + "integrity": "sha512-QCR1UqC9BzG5vZl8BMicmZ28RuUBnHhAMddD8yHFHDRH9lLTZ9uUPehX8ctVPT8l0TKblJidqcgUUKGVrePleQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", + "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.19" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz", + "integrity": "sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", + "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", + "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.1.tgz", + "integrity": "sha512-y4HqEnkelJIOQGd+3g1bTeKsA5c6qM7eOn7VggGVbBc0y8MLSKHacwcIE2PplNlQSj0PqS9rrXL/nkPVK+kUNg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.1.tgz", + "integrity": "sha512-Hj791Ii4ci8HqnaKHAlLNs+zaLXb0EzSDhiAWp5VNlyvCNymYfacs64pxTxbH1znW/NcArSmwpmG9IKE/TUVVQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.24.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-proposal-async-generator-functions": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz", + "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-async-generator-functions instead.", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-remap-async-to-generator": "^7.18.9", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-unicode-property-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", + "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-unicode-property-regex instead.", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.1.tgz", + "integrity": "sha512-IuwnI5XnuF189t91XbxmXeCDz3qs6iDRO7GJ++wcfgeXNs/8FmIlKcpDSXNVyuLQxlwvskmI3Ct73wUODkJBlQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.1.tgz", + "integrity": "sha512-zhQTMH0X2nVLnb04tz+s7AMuasX8U0FnpE+nHTOhSOINjWMnopoZTxtIKsd45n4GQ/HIZLyfIpoul8e2m0DnRA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.1.tgz", + "integrity": "sha512-ngT/3NkRhsaep9ck9uj2Xhv9+xB1zShY3tM3g6om4xxCELwCDN4g4Aq5dRn48+0hasAql7s2hdBOysCfNpr4fw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.3.tgz", + "integrity": "sha512-Qe26CMYVjpQxJ8zxM1340JFNjZaF+ISWpr1Kt/jGo+ZTUzKkfw/pphEWbRCb+lmSM6k/TOgfYLvmbHkUQ0asIg==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-remap-async-to-generator": "^7.22.20", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.22.5.tgz", + "integrity": "sha512-b1A8D8ZzE/VhNDoV1MSJTnpKkCG5bJo+19R4o4oy03zM7ws8yEMK755j61Dc3EyvdysbqH5BOOTquJ7ZX9C6vQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.1.tgz", + "integrity": "sha512-TWWC18OShZutrv9C6mye1xwtam+uNi2bnTOCBUd5sZxyHOiWbU6ztSROofIMrK84uweEZC219POICK/sTYwfgg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.4.tgz", + "integrity": "sha512-nIFUZIpGKDf9O9ttyRXpHFpKC+X3Y5mtshZONuEUYBomAKoM4y029Jr+uB1bHGPhNmK8YXHevDtKDOLmtRrp6g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.1.tgz", + "integrity": "sha512-OMLCXi0NqvJfORTaPQBwqLXHhb93wkBKZ4aNwMl6WtehO7ar+cmp+89iPEQPqxAnxsOKTaMcs3POz3rKayJ72g==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.4.tgz", + "integrity": "sha512-B8q7Pz870Hz/q9UgP8InNpY01CSLDSCyqX7zcRuv3FcPl87A2G17lASroHWaCtbdIcbYzOZ7kWmXFKbijMSmFg==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.4", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.1.tgz", + "integrity": "sha512-ZTIe3W7UejJd3/3R4p7ScyyOoafetUShSf4kCqV0O7F/RiHxVj/wRaRnQlrGwflvcehNA8M42HkAiEDYZu2F1Q==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-replace-supers": "^7.24.1", + "@babel/helper-split-export-declaration": "^7.22.6", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.1.tgz", + "integrity": "sha512-5pJGVIUfJpOS+pAqBQd+QMaTD2vCL/HcePooON6pDpHgRp4gNRmzyHTPIkXntwKsq3ayUFVfJaIKPw2pOkOcTw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/template": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.1.tgz", + "integrity": "sha512-ow8jciWqNxR3RYbSNVuF4U2Jx130nwnBnhRw6N6h1bOejNkABmcI5X5oz29K4alWX7vf1C+o6gtKXikzRKkVdw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.1.tgz", + "integrity": "sha512-p7uUxgSoZwZ2lPNMzUkqCts3xlp8n+o05ikjy7gbtFJSt9gdU88jAmtfmOxHM14noQXBxfgzf2yRWECiNVhTCw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.1.tgz", + "integrity": "sha512-msyzuUnvsjsaSaocV6L7ErfNsa5nDWL1XKNnDePLgmz+WdU4w/J8+AxBMrWfi9m4IxfL5sZQKUPQKDQeeAT6lA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.1.tgz", + "integrity": "sha512-av2gdSTyXcJVdI+8aFZsCAtR29xJt0S5tas+Ef8NvBNmD1a+N/3ecMLeMBgfcK+xzsjdLDT6oHt+DFPyeqUbDA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.1.tgz", + "integrity": "sha512-U1yX13dVBSwS23DEAqU+Z/PkwE9/m7QQy8Y9/+Tdb8UWYaGNDYwTLi19wqIAiROr8sXVum9A/rtiH5H0boUcTw==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.1.tgz", + "integrity": "sha512-Ft38m/KFOyzKw2UaJFkWG9QnHPG/Q/2SkOrRk4pNBPg5IPZ+dOxcmkK5IyuBcxiNPyyYowPGUReyBvrvZs7IlQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.1.tgz", + "integrity": "sha512-OxBdcnF04bpdQdR3i4giHZNZQn7cm8RQKcSwA17wAAqEELo1ZOwp5FFgeptWUQXFyT9kwHo10aqqauYkRZPCAg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.1.tgz", + "integrity": "sha512-BXmDZpPlh7jwicKArQASrj8n22/w6iymRnvHYYd2zO30DbE277JO20/7yXJT3QxDPtiQiOxQBbZH4TpivNXIxA==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.1.tgz", + "integrity": "sha512-U7RMFmRvoasscrIFy5xA4gIp8iWnWubnKkKuUGJjsuOH7GfbMkB+XZzeslx2kLdEGdOJDamEmCqOks6e8nv8DQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.1.tgz", + "integrity": "sha512-zn9pwz8U7nCqOYIiBaOxoQOtYmMODXTJnkxG4AtX8fPmnCRYWBOHD0qcpwS9e2VDSp1zNJYpdnFMIKb8jmwu6g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.1.tgz", + "integrity": "sha512-OhN6J4Bpz+hIBqItTeWJujDOfNP+unqv/NJgyhlpSqgBTPm37KkMmZV6SYcOj+pnDbdcl1qRGV/ZiIjX9Iy34w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.1.tgz", + "integrity": "sha512-4ojai0KysTWXzHseJKa1XPNXKRbuUrhkOPY4rEGeR+7ChlJVKxFa3H3Bz+7tWaGKgJAXUWKOGmltN+u9B3+CVg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.1.tgz", + "integrity": "sha512-lAxNHi4HVtjnHd5Rxg3D5t99Xm6H7b04hUS7EHIXcUl2EV4yl1gWdqZrNzXnSrHveL9qMdbODlLF55mvgjAfaQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.1.tgz", + "integrity": "sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-simple-access": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.1.tgz", + "integrity": "sha512-mqQ3Zh9vFO1Tpmlt8QPnbwGHzNz3lpNEMxQb1kAemn/erstyqw1r9KeOlOfo3y6xAnFEcOv2tSyrXfmMk+/YZA==", + "dev": true, + "dependencies": { + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.1.tgz", + "integrity": "sha512-tuA3lpPj+5ITfcCluy6nWonSL7RvaG0AOTeAuvXqEKS34lnLzXpDb0dcP6K8jD0zWZFNDVly90AGFJPnm4fOYg==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.1.tgz", + "integrity": "sha512-/rurytBM34hYy0HKZQyA0nHbQgQNFm4Q/BOc9Hflxi2X3twRof7NaE5W46j4kQitm7SvACVRXsa6N/tSZxvPug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.1.tgz", + "integrity": "sha512-iQ+caew8wRrhCikO5DrUYx0mrmdhkaELgFa+7baMcVuhxIkN7oxt06CZ51D65ugIb1UWRQ8oQe+HXAVM6qHFjw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.1.tgz", + "integrity": "sha512-7GAsGlK4cNL2OExJH1DzmDeKnRv/LXq0eLUSvudrehVA5Rgg4bIrqEUW29FbKMBRT0ztSqisv7kjP+XIC4ZMNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.1.tgz", + "integrity": "sha512-XjD5f0YqOtebto4HGISLNfiNMTTs6tbkFf2TOqJlYKYmbo+mN9Dnpl4SRoofiziuOWMIyq3sZEUqLo3hLITFEA==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.24.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.1.tgz", + "integrity": "sha512-oKJqR3TeI5hSLRxudMjFQ9re9fBVUU0GICqM3J1mi8MqlhVr6hC/ZN4ttAyMuQR6EZZIY6h/exe5swqGNNIkWQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-replace-supers": "^7.24.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.1.tgz", + "integrity": "sha512-oBTH7oURV4Y+3EUrf6cWn1OHio3qG/PVwO5J03iSJmBg6m2EhKjkAu/xuaXaYwWW9miYtvbWv4LNf0AmR43LUA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.1.tgz", + "integrity": "sha512-n03wmDt+987qXwAgcBlnUUivrZBPZ8z1plL0YvgQalLm+ZE5BMhGm94jhxXtA1wzv1Cu2aaOv1BM9vbVttrzSg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.1.tgz", + "integrity": "sha512-8Jl6V24g+Uw5OGPeWNKrKqXPDw2YDjLc53ojwfMcKwlEoETKU9rU0mHUtcg9JntWI/QYzGAXNWEcVHZ+fR+XXg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.1.tgz", + "integrity": "sha512-tGvisebwBO5em4PaYNqt4fkw56K2VALsAbAakY0FjTYqJp7gfdrgr7YX76Or8/cpik0W6+tj3rZ0uHU9Oil4tw==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.1.tgz", + "integrity": "sha512-pTHxDVa0BpUbvAgX3Gat+7cSciXqUcY9j2VZKTbSB6+VQGpNgNO9ailxTGHSXlqOnX1Hcx1Enme2+yv7VqP9bg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.1.tgz", + "integrity": "sha512-LetvD7CrHmEx0G442gOomRr66d7q8HzzGGr4PMHGr+5YIm6++Yke+jxj246rpvsbyhJwCLxcTn6zW1P1BSenqA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.1.tgz", + "integrity": "sha512-sJwZBCzIBE4t+5Q4IGLaaun5ExVMRY0lYwos/jNecjMrVCygCdph3IKv0tkP5Fc87e/1+bebAmEAGBfnRD+cnw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.1.tgz", + "integrity": "sha512-JAclqStUfIwKN15HrsQADFgeZt+wexNQ0uLhuqvqAUFoqPMjEcFCYZBhq0LUdz6dZK/mD+rErhW71fbx8RYElg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.22.9.tgz", + "integrity": "sha512-9KjBH61AGJetCPYp/IEyLEp47SyybZb0nDRpBvmtEkm+rUIwxdlKpyNHI1TmsGkeuLclJdleQHRZ8XLBnnh8CQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "babel-plugin-polyfill-corejs2": "^0.4.4", + "babel-plugin-polyfill-corejs3": "^0.8.2", + "babel-plugin-polyfill-regenerator": "^0.5.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "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" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.1.tgz", + "integrity": "sha512-LyjVB1nsJ6gTTUKRjRWx9C1s9hE7dLfP/knKdrfeH9UPtAGjYGgxIbFfx7xyLIEWs7Xe1Gnf8EWiUqfjLhInZA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.1.tgz", + "integrity": "sha512-KjmcIM+fxgY+KxPVbjelJC6hrH1CgtPmTvdXAfn3/a9CnWGSTY7nH4zm5+cjmWJybdcPSsD0++QssDsjcpe47g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.1.tgz", + "integrity": "sha512-9v0f1bRXgPVcPrngOQvLXeGNNVLc8UjMVfebo9ka0WF3/7+aVUHmaJVT3sa0XCzEFioPfPHZiOcYG9qOsH63cw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.1.tgz", + "integrity": "sha512-WRkhROsNzriarqECASCNu/nojeXCDTE/F2HmRgOzi7NGvyfYGq1NEjKBK3ckLfRgGc6/lPAqP0vDOSw3YtG34g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.1.tgz", + "integrity": "sha512-CBfU4l/A+KruSUoW+vTQthwcAdwuqbpRNB8HQKlZABwHRhsdHZ9fezp4Sn18PeAlYxTNiLMlx4xUBV3AWfg1BA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.1.tgz", + "integrity": "sha512-RlkVIcWT4TLI96zM660S877E7beKlQw7Ig+wqkKBiWfj0zH5Q4h50q6er4wzZKRNSYpfo6ILJ+hrJAGSX2qcNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.1.tgz", + "integrity": "sha512-Ss4VvlfYV5huWApFsF8/Sq0oXnGO+jB+rijFEFugTd3cwSObUSnUi88djgR5528Csl0uKlrI331kRqe56Ov2Ng==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.1.tgz", + "integrity": "sha512-2A/94wgZgxfTsiLaQ2E36XAOdcZmGAaEEgVmxQWwZXWkGhvoHbaqXcKnU8zny4ycpu3vNqg0L/PcCiYtHtA13g==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.1.tgz", + "integrity": "sha512-fqj4WuzzS+ukpgerpAoOnMfQXwUHFxXUZUE84oL2Kao2N8uSlvcpnAidKASgsNgzZHBsHWvcm8s9FPWUhAb8fA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.9.tgz", + "integrity": "sha512-wNi5H/Emkhll/bqPjsjQorSykrlfY5OWakd6AulLvMEytpKasMVUpVy8RL4qBIBs5Ac6/5i0/Rv0b/Fg6Eag/g==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-compilation-targets": "^7.22.9", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.5", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.22.5", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.22.5", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.22.5", + "@babel/plugin-syntax-import-attributes": "^7.22.5", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.22.5", + "@babel/plugin-transform-async-generator-functions": "^7.22.7", + "@babel/plugin-transform-async-to-generator": "^7.22.5", + "@babel/plugin-transform-block-scoped-functions": "^7.22.5", + "@babel/plugin-transform-block-scoping": "^7.22.5", + "@babel/plugin-transform-class-properties": "^7.22.5", + "@babel/plugin-transform-class-static-block": "^7.22.5", + "@babel/plugin-transform-classes": "^7.22.6", + "@babel/plugin-transform-computed-properties": "^7.22.5", + "@babel/plugin-transform-destructuring": "^7.22.5", + "@babel/plugin-transform-dotall-regex": "^7.22.5", + "@babel/plugin-transform-duplicate-keys": "^7.22.5", + "@babel/plugin-transform-dynamic-import": "^7.22.5", + "@babel/plugin-transform-exponentiation-operator": "^7.22.5", + "@babel/plugin-transform-export-namespace-from": "^7.22.5", + "@babel/plugin-transform-for-of": "^7.22.5", + "@babel/plugin-transform-function-name": "^7.22.5", + "@babel/plugin-transform-json-strings": "^7.22.5", + "@babel/plugin-transform-literals": "^7.22.5", + "@babel/plugin-transform-logical-assignment-operators": "^7.22.5", + "@babel/plugin-transform-member-expression-literals": "^7.22.5", + "@babel/plugin-transform-modules-amd": "^7.22.5", + "@babel/plugin-transform-modules-commonjs": "^7.22.5", + "@babel/plugin-transform-modules-systemjs": "^7.22.5", + "@babel/plugin-transform-modules-umd": "^7.22.5", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.22.5", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.22.5", + "@babel/plugin-transform-numeric-separator": "^7.22.5", + "@babel/plugin-transform-object-rest-spread": "^7.22.5", + "@babel/plugin-transform-object-super": "^7.22.5", + "@babel/plugin-transform-optional-catch-binding": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.22.6", + "@babel/plugin-transform-parameters": "^7.22.5", + "@babel/plugin-transform-private-methods": "^7.22.5", + "@babel/plugin-transform-private-property-in-object": "^7.22.5", + "@babel/plugin-transform-property-literals": "^7.22.5", + "@babel/plugin-transform-regenerator": "^7.22.5", + "@babel/plugin-transform-reserved-words": "^7.22.5", + "@babel/plugin-transform-shorthand-properties": "^7.22.5", + "@babel/plugin-transform-spread": "^7.22.5", + "@babel/plugin-transform-sticky-regex": "^7.22.5", + "@babel/plugin-transform-template-literals": "^7.22.5", + "@babel/plugin-transform-typeof-symbol": "^7.22.5", + "@babel/plugin-transform-unicode-escapes": "^7.22.5", + "@babel/plugin-transform-unicode-property-regex": "^7.22.5", + "@babel/plugin-transform-unicode-regex": "^7.22.5", + "@babel/plugin-transform-unicode-sets-regex": "^7.22.5", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.22.5", + "babel-plugin-polyfill-corejs2": "^0.4.4", + "babel-plugin-polyfill-corejs3": "^0.8.2", + "babel-plugin-polyfill-regenerator": "^0.5.1", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "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" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6.tgz", + "integrity": "sha512-ID2yj6K/4lKfhuU3+EX4UvNbIt7eACFbHmNUjzA+ep+B5971CknnA/9DEWKbRokfbbtblxxxXFJJrH47UEAMVg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", + "dev": true + }, + "node_modules/@babel/runtime": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz", + "integrity": "sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", + "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.24.1", + "@babel/generator": "^7.24.1", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.24.1", + "@babel/types": "^7.24.0", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/generator": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz", + "integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@es-joy/jsdoccomment": { + "version": "0.42.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.42.0.tgz", + "integrity": "sha512-R1w57YlVA6+YE01wch3GPYn6bCsrOV3YW/5oGGE2tmX6JcL9Nr+b5IikrjMPF+v9CV3ay+obImEdsDhovhJrzw==", + "dev": true, + "dependencies": { + "comment-parser": "1.4.1", + "esquery": "^1.5.0", + "jsdoc-type-pratt-parser": "~4.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.17.tgz", + "integrity": "sha512-wHsmJG/dnL3OkpAcwbgoBTTMHVi4Uyou3F5mf58ZtmUyIKfcdA7TROav/6tCzET4A3QW2Q2FC+eFneMU+iyOxg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.17.tgz", + "integrity": "sha512-9np+YYdNDed5+Jgr1TdWBsozZ85U1Oa3xW0c7TWqH0y2aGghXtZsuT8nYRbzOMcl0bXZXjOGbksoTtVOlWrRZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.17.tgz", + "integrity": "sha512-O+FeWB/+xya0aLg23hHEM2E3hbfwZzjqumKMSIqcHbNvDa+dza2D0yLuymRBQQnC34CWrsJUXyH2MG5VnLd6uw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.17.tgz", + "integrity": "sha512-M9uJ9VSB1oli2BE/dJs3zVr9kcCBBsE883prage1NWz6pBS++1oNn/7soPNS3+1DGj0FrkSvnED4Bmlu1VAE9g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.17.tgz", + "integrity": "sha512-XDre+J5YeIJDMfp3n0279DFNrGCXlxOuGsWIkRb1NThMZ0BsrWXoTg23Jer7fEXQ9Ye5QjrvXpxnhzl3bHtk0g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.17.tgz", + "integrity": "sha512-cjTzGa3QlNfERa0+ptykyxs5A6FEUQQF0MuilYXYBGdBxD3vxJcKnzDlhDCa1VAJCmAxed6mYhA2KaJIbtiNuQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.17.tgz", + "integrity": "sha512-sOxEvR8d7V7Kw8QqzxWc7bFfnWnGdaFBut1dRUYtu+EIRXefBc/eIsiUiShnW0hM3FmQ5Zf27suDuHsKgZ5QrA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.17.tgz", + "integrity": "sha512-2d3Lw6wkwgSLC2fIvXKoMNGVaeY8qdN0IC3rfuVxJp89CRfA3e3VqWifGDfuakPmp90+ZirmTfye1n4ncjv2lg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.17.tgz", + "integrity": "sha512-c9w3tE7qA3CYWjT+M3BMbwMt+0JYOp3vCMKgVBrCl1nwjAlOMYzEo+gG7QaZ9AtqZFj5MbUc885wuBBmu6aADQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.17.tgz", + "integrity": "sha512-1DS9F966pn5pPnqXYz16dQqWIB0dmDfAQZd6jSSpiT9eX1NzKh07J6VKR3AoXXXEk6CqZMojiVDSZi1SlmKVdg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.17.tgz", + "integrity": "sha512-EvLsxCk6ZF0fpCB6w6eOI2Fc8KW5N6sHlIovNe8uOFObL2O+Mr0bflPHyHwLT6rwMg9r77WOAWb2FqCQrVnwFg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.17.tgz", + "integrity": "sha512-e0bIdHA5p6l+lwqTE36NAW5hHtw2tNRmHlGBygZC14QObsA3bD4C6sXLJjvnDIjSKhW1/0S3eDy+QmX/uZWEYQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.17.tgz", + "integrity": "sha512-BAAilJ0M5O2uMxHYGjFKn4nJKF6fNCdP1E0o5t5fvMYYzeIqy2JdAP88Az5LHt9qBoUa4tDaRpfWt21ep5/WqQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.17.tgz", + "integrity": "sha512-Wh/HW2MPnC3b8BqRSIme/9Zhab36PPH+3zam5pqGRH4pE+4xTrVLx2+XdGp6fVS3L2x+DrsIcsbMleex8fbE6g==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.17.tgz", + "integrity": "sha512-j/34jAl3ul3PNcK3pfI0NSlBANduT2UO5kZ7FCaK33XFv3chDhICLY8wJJWIhiQ+YNdQ9dxqQctRg2bvrMlYgg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.17.tgz", + "integrity": "sha512-QM50vJ/y+8I60qEmFxMoxIx4de03pGo2HwxdBeFd4nMh364X6TIBZ6VQ5UQmPbQWUVWHWws5MmJXlHAXvJEmpQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.17.tgz", + "integrity": "sha512-/jGlhWR7Sj9JPZHzXyyMZ1RFMkNPjC6QIAan0sDOtIo2TYk3tZn5UDrkE0XgsTQCxWTTOcMPf9p6Rh2hXtl5TQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.17.tgz", + "integrity": "sha512-rSEeYaGgyGGf4qZM2NonMhMOP/5EHp4u9ehFiBrg7stH6BYEEjlkVREuDEcQ0LfIl53OXLxNbfuIj7mr5m29TA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.17.tgz", + "integrity": "sha512-Y7ZBbkLqlSgn4+zot4KUNYst0bFoO68tRgI6mY2FIM+b7ZbyNVtNbDP5y8qlu4/knZZ73fgJDlXID+ohY5zt5g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.17.tgz", + "integrity": "sha512-bwPmTJsEQcbZk26oYpc4c/8PvTY3J5/QK8jM19DVlEsAB41M39aWovWoHtNm78sd6ip6prilxeHosPADXtEJFw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.17.tgz", + "integrity": "sha512-H/XaPtPKli2MhW+3CQueo6Ni3Avggi6hP/YvgkEe1aSaxw+AeO8MFjq8DlgfTd9Iz4Yih3QCZI6YLMoyccnPRg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.17.tgz", + "integrity": "sha512-fGEb8f2BSA3CW7riJVurug65ACLuQAzKq0SSqkY2b2yHHH0MzDfbLyKIGzHwOI/gkHcxM/leuSW6D5w/LMNitA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "dev": true + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", + "dev": true + }, + "node_modules/@ionic/angular": { + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@ionic/angular/-/angular-6.7.5.tgz", + "integrity": "sha512-nV8HP7RedjYkIAT8nVr5ifHNT0D3XzA74RPG3/WCCFJKunERNJ9SBiNkCTWhUpSkqsYYwEB4+SOOHz+R5NLk/w==", + "dependencies": { + "@ionic/core": "6.7.5", + "ionicons": "^6.1.3", + "jsonc-parser": "^3.0.0", + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/core": ">=12.0.0", + "@angular/forms": ">=12.0.0", + "@angular/router": ">=12.0.0", + "rxjs": ">=6.6.0", + "zone.js": ">=0.11.0" + } + }, + "node_modules/@ionic/angular-toolkit": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/@ionic/angular-toolkit/-/angular-toolkit-11.0.1.tgz", + "integrity": "sha512-dxx2RDbxDYM2nWRPIirKMJySHtqJ1u02T25PGbNb99W2Wlcmu1cza3+2/PQ8ga18yMz/dQqaGyEmPDf3ZSVO0w==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "^17.0.0", + "@angular-devkit/schematics": "^17.0.0", + "@schematics/angular": "^17.0.0" + } + }, + "node_modules/@ionic/angular-toolkit/node_modules/@angular-devkit/core": { + "version": "17.3.3", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-17.3.3.tgz", + "integrity": "sha512-J22Sh3M7rj8Ar3iEs20ko5wgC3DE7vWfYZNdimt2IJiS4J7BEX8R3Awf+TRt+6AN3NFm3/xe1Sz4yvDh3FvNFg==", + "dev": true, + "dependencies": { + "ajv": "8.12.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.2.1", + "picomatch": "4.0.1", + "rxjs": "7.8.1", + "source-map": "0.7.4" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@ionic/angular-toolkit/node_modules/@angular-devkit/schematics": { + "version": "17.3.3", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-17.3.3.tgz", + "integrity": "sha512-SABqTtj2im4PJhQjNaAsSypbNkpZFW8YozJ3P748tlh5a9XoHpgiqXv5JhRbyKElLDAyk5i9fe2++JmSudPG/Q==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "17.3.3", + "jsonc-parser": "3.2.1", + "magic-string": "0.30.8", + "ora": "5.4.1", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@ionic/angular-toolkit/node_modules/@schematics/angular": { + "version": "17.3.3", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-17.3.3.tgz", + "integrity": "sha512-kNlyjIKTBhfi8Jab3MCkxNRbbpErbzdu0lZNSL8Nidmqs6Tk23Dc1bZe4t/gPNOCkCvQlwYa6X88SjC/ntyVng==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "17.3.3", + "@angular-devkit/schematics": "17.3.3", + "jsonc-parser": "3.2.1" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@ionic/angular-toolkit/node_modules/magic-string": { + "version": "0.30.8", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", + "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@ionic/angular-toolkit/node_modules/picomatch": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.1.tgz", + "integrity": "sha512-xUXwsxNjwTQ8K3GnT4pCJm+xq3RUPQbmkYJTP5aFIfNIvbcc/4MUxgBaaRSZJ6yGJZiGSyYlM6MzwTsRk8SYCg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@ionic/angular-toolkit/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@ionic/core": { + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-6.7.5.tgz", + "integrity": "sha512-zRkRn+h/Vs3xt/EVgBdShMKDyeGOM4RU31NPF2icfu3CUTH+VrMV569MUnNjYvd1Lu2xK90pYy4TaicSWmC1Pw==", + "dependencies": { + "@stencil/core": "^2.18.0", + "ionicons": "^6.1.3", + "tslib": "^2.1.0" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@kurkle/color": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz", + "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==" + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "dev": true + }, + "node_modules/@ngtools/webpack": { + "version": "16.2.13", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-16.2.13.tgz", + "integrity": "sha512-P5OiVp9MeMwVxihtC9NB4mx1Zlbup2DLMAWYAl8/kcFdRrRW+1YDQn93tlFToQDHGpPxkqW7cnFUPnA+QwQMYA==", + "dev": true, + "engines": { + "node": "^16.14.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "@angular/compiler-cli": "^16.0.0", + "typescript": ">=4.9.3 <5.2", + "webpack": "^5.54.0" + } + }, + "node_modules/@ngx-formly/core": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@ngx-formly/core/-/core-6.3.0.tgz", + "integrity": "sha512-9qCoPdLLVShoruzXeJUjMdIhfIlHCI+TggA3Wc01ISHTK2vXx1gNIFLuS+hez3JEzu8nIDRuA/nWqj4j8fJCNg==", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/forms": ">=13.2.0", + "rxjs": "^6.5.3 || ^7.0.0" + } + }, + "node_modules/@ngx-formly/ionic": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@ngx-formly/ionic/-/ionic-6.3.0.tgz", + "integrity": "sha512-oiJB0iwmTVro7zDev3NS5lMvpgMINzCqr4Xm2h17882r4qrkGVIyN3IMQErNZY4iPYaKu0M3RiAvgEkDgVGigw==", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@ionic/angular": "^6.0.0 || ^7.0.0", + "@ngx-formly/core": "6.3.0" + } + }, + "node_modules/@ngx-formly/schematics": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@ngx-formly/schematics/-/schematics-6.3.0.tgz", + "integrity": "sha512-XSzOvrZ1NoUhmd733bcgUFkl+26pSw8eyXChi9LwrS26nEPweR8RA/JxN+lFvIb92MWzLShLd1DY2oBz/0r0ZQ==", + "dependencies": { + "@angular-devkit/core": "^13.0.3", + "@angular-devkit/schematics": "^13.0.3", + "@schematics/angular": "^13.0.3" + } + }, + "node_modules/@ngx-formly/schematics/node_modules/@angular-devkit/core": { + "version": "13.3.11", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-13.3.11.tgz", + "integrity": "sha512-rfqoLMRYhlz0wzKlHx7FfyIyQq8dKTsmbCoIVU1cEIH0gyTMVY7PbVzwRRcO6xp5waY+0hA+0Brriujpuhkm4w==", + "dependencies": { + "ajv": "8.9.0", + "ajv-formats": "2.1.1", + "fast-json-stable-stringify": "2.1.0", + "magic-string": "0.25.7", + "rxjs": "6.6.7", + "source-map": "0.7.3" + }, + "engines": { + "node": "^12.20.0 || ^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@ngx-formly/schematics/node_modules/@angular-devkit/schematics": { + "version": "13.3.11", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-13.3.11.tgz", + "integrity": "sha512-ben+EGXpCrClnIVAAnEQmhQdKmnnqFhMp5BqMxgOslSYBAmCutLA6rBu5vsc8kZcGian1wt+lueF7G1Uk5cGBg==", + "dependencies": { + "@angular-devkit/core": "13.3.11", + "jsonc-parser": "3.0.0", + "magic-string": "0.25.7", + "ora": "5.4.1", + "rxjs": "6.6.7" + }, + "engines": { + "node": "^12.20.0 || ^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@ngx-formly/schematics/node_modules/@schematics/angular": { + "version": "13.3.11", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-13.3.11.tgz", + "integrity": "sha512-imKBnKYEse0SBVELZO/753nkpt3eEgpjrYkB+AFWF9YfO/4RGnYXDHoH8CFkzxPH9QQCgNrmsVFNiYGS+P/S1A==", + "dependencies": { + "@angular-devkit/core": "13.3.11", + "@angular-devkit/schematics": "13.3.11", + "jsonc-parser": "3.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@ngx-formly/schematics/node_modules/ajv": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.9.0.tgz", + "integrity": "sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@ngx-formly/schematics/node_modules/jsonc-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", + "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==" + }, + "node_modules/@ngx-formly/schematics/node_modules/magic-string": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", + "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "dependencies": { + "sourcemap-codec": "^1.4.4" + } + }, + "node_modules/@ngx-formly/schematics/node_modules/source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@ngx-translate/core": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-14.0.0.tgz", + "integrity": "sha512-UevdwNCXMRCdJv//0kC8h2eSfmi02r29xeE8E9gJ1Al4D4jEJ7eiLPdjslTMc21oJNGguqqWeEVjf64SFtvw2w==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/core": ">=13.0.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodro7/angular-mydatepicker": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@nodro7/angular-mydatepicker/-/angular-mydatepicker-0.14.0.tgz", + "integrity": "sha512-NLUqU2Hpy3OQn/2xp5FDIqBlb87o9LCYRShnA9tfbQIPQIKay4sSexK6XPswZ3ccXkvrgRMhFDZpv10JURqahA==", + "dependencies": { + "tslib": "^2.0.0" + } + }, + "node_modules/@npmcli/fs": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", + "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-4.1.0.tgz", + "integrity": "sha512-9hwoB3gStVfa0N31ymBmrX+GuDGdVA/QWShZVqE0HK2Af+7QGGrCTbZia/SW0ImUTjTne7SP91qxDmtXvDHRPQ==", + "dev": true, + "dependencies": { + "@npmcli/promise-spawn": "^6.0.0", + "lru-cache": "^7.4.4", + "npm-pick-manifest": "^8.0.0", + "proc-log": "^3.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@npmcli/git/node_modules/which": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", + "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/installed-package-contents": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz", + "integrity": "sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==", + "dev": true, + "dependencies": { + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "bin": { + "installed-package-contents": "lib/index.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/move-file": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", + "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", + "deprecated": "This functionality has been moved to @npmcli/fs", + "dev": true, + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/node-gyp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", + "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/promise-spawn": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-6.0.2.tgz", + "integrity": "sha512-gGq0NJkIGSwdbUt4yhdF8ZrmkGKVz9vAdVzpOfnom+V8PLSmSOVhZwbNvZZS1EYcJN5hzzKBxmmVVAInM6HQLg==", + "dev": true, + "dependencies": { + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/which": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", + "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-6.0.2.tgz", + "integrity": "sha512-NCcr1uQo1k5U+SYlnIrbAh3cxy+OQT1VtqiAbxdymSlptbzBb62AjH2xXgjNCoP073hoa1CfCAcwoZ8k96C4nA==", + "dev": true, + "dependencies": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/promise-spawn": "^6.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^3.0.0", + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script/node_modules/which": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", + "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@nrwl/devkit": { + "version": "16.5.1", + "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-16.5.1.tgz", + "integrity": "sha512-NB+DE/+AFJ7lKH/WBFyatJEhcZGj25F24ncDkwjZ6MzEiSOGOJS0LaV/R+VUsmS5EHTPXYOpn3zHWWAcJhyOmA==", + "dev": true, + "dependencies": { + "@nx/devkit": "16.5.1" + } + }, + "node_modules/@nrwl/tao": { + "version": "16.5.1", + "resolved": "https://registry.npmjs.org/@nrwl/tao/-/tao-16.5.1.tgz", + "integrity": "sha512-x+gi/fKdM6uQNIti9exFlm3V5LBP3Y8vOEziO42HdOigyrXa0S0HD2WMpccmp6PclYKhwEDUjKJ39xh5sdh4Ig==", + "dev": true, + "dependencies": { + "nx": "16.5.1" + }, + "bin": { + "tao": "index.js" + } + }, + "node_modules/@nx/devkit": { + "version": "16.5.1", + "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-16.5.1.tgz", + "integrity": "sha512-T1acZrVVmJw/sJ4PIGidCBYBiBqlg/jT9e8nIGXLSDS20xcLvfo4zBQf8UZLrmHglnwwpDpOWuVJCp2rYA5aDg==", + "dev": true, + "dependencies": { + "@nrwl/devkit": "16.5.1", + "ejs": "^3.1.7", + "ignore": "^5.0.4", + "semver": "7.5.3", + "tmp": "~0.2.1", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "nx": ">= 15 <= 17" + } + }, + "node_modules/@nx/devkit/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@nx/devkit/node_modules/semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@nx/devkit/node_modules/tmp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "dev": true, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@nx/devkit/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@nx/nx-darwin-arm64": { + "version": "16.5.1", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-16.5.1.tgz", + "integrity": "sha512-q98TFI4B/9N9PmKUr1jcbtD4yAFs1HfYd9jUXXTQOlfO9SbDjnrYJgZ4Fp9rMNfrBhgIQ4x1qx0AukZccKmH9Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nx/nx-darwin-x64": { + "version": "16.5.1", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-16.5.1.tgz", + "integrity": "sha512-j9HmL1l8k7EVJ3eOM5y8COF93gqrydpxCDoz23ZEtsY+JHY77VAiRQsmqBgEx9GGA2dXi9VEdS67B0+1vKariw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nx/nx-freebsd-x64": { + "version": "16.5.1", + "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-16.5.1.tgz", + "integrity": "sha512-CXSPT01aVS869tvCCF2tZ7LnCa8l41wJ3mTVtWBkjmRde68E5Up093hklRMyXb3kfiDYlfIKWGwrV4r0eH6x1A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nx/nx-linux-arm-gnueabihf": { + "version": "16.5.1", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-16.5.1.tgz", + "integrity": "sha512-BhrumqJSZCWFfLFUKl4CAUwR0Y0G2H5EfFVGKivVecEQbb+INAek1aa6c89evg2/OvetQYsJ+51QknskwqvLsA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nx/nx-linux-arm64-gnu": { + "version": "16.5.1", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-16.5.1.tgz", + "integrity": "sha512-x7MsSG0W+X43WVv7JhiSq2eKvH2suNKdlUHEG09Yt0vm3z0bhtym1UCMUg3IUAK7jy9hhLeDaFVFkC6zo+H/XQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nx/nx-linux-arm64-musl": { + "version": "16.5.1", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-16.5.1.tgz", + "integrity": "sha512-J+/v/mFjOm74I0PNtH5Ka+fDd+/dWbKhpcZ2R1/6b9agzZk+Ff/SrwJcSYFXXWKbPX+uQ4RcJoytT06Zs3s0ow==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nx/nx-linux-x64-gnu": { + "version": "16.5.1", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-16.5.1.tgz", + "integrity": "sha512-igooWJ5YxQ94Zft7IqgL+Lw0qHaY15Btw4gfK756g/YTYLZEt4tTvR1y6RnK/wdpE3sa68bFTLVBNCGTyiTiDQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nx/nx-linux-x64-musl": { + "version": "16.5.1", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-16.5.1.tgz", + "integrity": "sha512-zF/exnPqFYbrLAduGhTmZ7zNEyADid2bzNQiIjJkh8Y6NpDwrQIwVIyvIxqynsjMrIs51kBH+8TUjKjj2Jgf5A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nx/nx-win32-arm64-msvc": { + "version": "16.5.1", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-16.5.1.tgz", + "integrity": "sha512-qtqiLS9Y9TYyAbbpq58kRoOroko4ZXg5oWVqIWFHoxc5bGPweQSJCROEqd1AOl2ZDC6BxfuVHfhDDop1kK05WA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nx/nx-win32-x64-msvc": { + "version": "16.5.1", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-16.5.1.tgz", + "integrity": "sha512-kUJBLakK7iyA9WfsGGQBVennA4jwf5XIgm0lu35oMOphtZIluvzItMt0EYBmylEROpmpEIhHq0P6J9FA+WH0Rg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.0.4.tgz", + "integrity": "sha512-cTDi+FUDBIUOBKEtj+nhiJ71AZVlkAsQFuGQTun5tV9mwQBQgZvhCzG+URPQc8myeN32yRVZEfVAPCs1RW+Jvg==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "node-addon-api": "^3.2.1", + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@schematics/angular": { + "version": "16.2.13", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-16.2.13.tgz", + "integrity": "sha512-SFE9e7X/CEtzwGEqHUqXriAm4J4uTjcfoRXslc7BuqOKABM8RXPphGQsVG4xOt3n25kXXGkFO2dvDRHuLTP1fQ==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "16.2.13", + "@angular-devkit/schematics": "16.2.13", + "jsonc-parser": "3.2.0" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@schematics/angular/node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, + "node_modules/@sigstore/bundle": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-1.1.0.tgz", + "integrity": "sha512-PFutXEy0SmQxYI4texPw3dd2KewuNqv7OuK1ZFtY2fM754yhvG2KdgwIhRnoEE2uHdtdGNQ8s0lb94dW9sELog==", + "dev": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.2.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/protobuf-specs": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.2.1.tgz", + "integrity": "sha512-XTWVxnWJu+c1oCshMLwnKvz8ZQJJDVOlciMfgpJBQbThVjKTCG8dwyhgLngBD2KN0ap9F/gOV8rFDEx8uh7R2A==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/sign": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-1.0.0.tgz", + "integrity": "sha512-INxFVNQteLtcfGmcoldzV6Je0sbbfh9I16DM4yJPw3j5+TFP8X6uIiA18mvpEa9yyeycAKgPmOA3X9hVdVTPUA==", + "dev": true, + "dependencies": { + "@sigstore/bundle": "^1.1.0", + "@sigstore/protobuf-specs": "^0.2.0", + "make-fetch-happen": "^11.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/sign/node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@sigstore/sign/node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@sigstore/sign/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@sigstore/sign/node_modules/make-fetch-happen": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", + "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^5.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/sign/node_modules/minipass-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/@sigstore/sign/node_modules/minipass-fetch/node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/@sigstore/tuf": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-1.0.3.tgz", + "integrity": "sha512-2bRovzs0nJZFlCN3rXirE4gwxCn97JNjMmwpecqlbgV9WcxX7WRuIrgzx/X7Ib7MYRbyUTpBYE0s2x6AmZXnlg==", + "dev": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.2.0", + "tuf-js": "^1.1.7" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", + "dev": true + }, + "node_modules/@stencil/core": { + "version": "2.22.3", + "resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.22.3.tgz", + "integrity": "sha512-kmVA0M/HojwsfkeHsifvHVIYe4l5tin7J5+DLgtl8h6WWfiMClND5K3ifCXXI2ETDNKiEk21p6jql3Fx9o2rng==", + "bin": { + "stencil": "bin/stencil" + }, + "engines": { + "node": ">=12.10.0", + "npm": ">=6.0.0" + } + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "node_modules/@tufjs/canonical-json": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-1.0.0.tgz", + "integrity": "sha512-QTnf++uxunWvG2z3UFNzAoQPHxnSXOwtaI3iJ+AohhV+5vONuArPjJE7aPXPVXfXJsqrVbZBu9b81AJoSd09IQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-1.0.4.tgz", + "integrity": "sha512-qaGV9ltJP0EO25YfFUPhxRVK0evXFIAGicsVXuRim4Ed9cjPxYhNnNJ49SFmbeLgtxpslIkX317IgpfcHPVj/A==", + "dev": true, + "dependencies": { + "@tufjs/canonical-json": "1.0.0", + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@tufjs/models/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "dev": true, + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", + "dev": true + }, + "node_modules/@types/cors": { + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/eslint": { + "version": "8.56.2", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.2.tgz", + "integrity": "sha512-uQDwm1wFHmbBbCZCqAlq6Do9LYwByNZHWzXppSnay9SuwJ+VRbjkbLABer54kcPnMSlG6Fdiy2yaFXm/z9Z5gw==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz", + "integrity": "sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, + "node_modules/@types/http-proxy": { + "version": "1.17.14", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", + "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/jasmine": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-4.3.6.tgz", + "integrity": "sha512-3N0FpQTeiWjm+Oo1WUYWguUS7E6JLceiGTriFrG8k5PU7zRLJCzLcWURU3wjMbZGS//a2/LgjsnO3QxIlwxt9g==", + "dev": true + }, + "node_modules/@types/jasminewd2": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@types/jasminewd2/-/jasminewd2-2.0.13.tgz", + "integrity": "sha512-aJ3wj8tXMpBrzQ5ghIaqMisD8C3FIrcO6sDKHqFbuqAsI7yOxj0fA7MrRCPLZHIVUjERIwsMmGn/vB0UQ9u0Hg==", + "dev": true, + "dependencies": { + "@types/jasmine": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.12.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", + "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/q": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", + "integrity": "sha512-qYi3YV9inU/REEfxwVcGZzbS3KG/Xs90lv0Pr+lDtuVjBPGd1A+eciXzVSaRvLify132BfcvhvEjeVahrUl0Ug==", + "dev": true + }, + "node_modules/@types/qs": { + "version": "6.9.14", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.14.tgz", + "integrity": "sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true + }, + "node_modules/@types/selenium-webdriver": { + "version": "3.0.26", + "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.26.tgz", + "integrity": "sha512-dyIGFKXfUFiwkMfNGn1+F6b80ZjR3uSYv1j6xVJSDlft5waZ2cwkHW4e7zNzvq7hiEackcgvBpmnXZrI1GltPg==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/uuid": { + "version": "9.0.8", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", + "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", + "dev": true + }, + "node_modules/@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", + "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/type-utils": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", + "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", + "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", + "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", + "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "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.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/@vitejs/plugin-basic-ssl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.0.1.tgz", + "integrity": "sha512-pcub+YbFtFhaGRTo1832FQHQSHvMrlb43974e2eS8EKleR3p1cDdkJFPci1UhwkEf1J9Bz+wKBSzqpKp7nNj2A==", + "dev": true, + "engines": { + "node": ">=14.6.0" + }, + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@wessberg/ts-evaluator": { + "version": "0.0.27", + "resolved": "https://registry.npmjs.org/@wessberg/ts-evaluator/-/ts-evaluator-0.0.27.tgz", + "integrity": "sha512-7gOpVm3yYojUp/Yn7F4ZybJRxyqfMNf0LXK5KJiawbPfL0XTsJV+0mgrEDjOIR6Bi0OYk2Cyg4tjFu1r8MCZaA==", + "deprecated": "this package has been renamed to ts-evaluator. Please install ts-evaluator instead", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "jsdom": "^16.4.0", + "object-path": "^0.11.5", + "tslib": "^2.0.3" + }, + "engines": { + "node": ">=10.1.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/wessberg/ts-evaluator?sponsor=1" + }, + "peerDependencies": { + "typescript": ">=3.2.x || >= 4.x" + } + }, + "node_modules/@wessberg/ts-evaluator/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@wessberg/ts-evaluator/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@wessberg/ts-evaluator/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@wessberg/ts-evaluator/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wessberg/ts-evaluator/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true + }, + "node_modules/@yarnpkg/parsers": { + "version": "3.0.0-rc.46", + "resolved": "https://registry.npmjs.org/@yarnpkg/parsers/-/parsers-3.0.0-rc.46.tgz", + "integrity": "sha512-aiATs7pSutzda/rq8fnuPwTglyVwjM22bNnK2ZgjrpAjQHSSl3lztd2f9evst1W/qnC58DRz7T7QndUDumAR4Q==", + "dev": true, + "dependencies": { + "js-yaml": "^3.10.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=14.15.0" + } + }, + "node_modules/@zkochan/js-yaml": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@zkochan/js-yaml/-/js-yaml-0.0.6.tgz", + "integrity": "sha512-nzvgl3VfhcELQ8LyVrYOru+UtAy1nrygk2+AGbTm8a5YcO6o8lSjAT+pfg3vJWxIoZKOUhrK6UU7xW/+00kQrg==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@zkochan/js-yaml/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "deprecated": "Use your platform's native atob() and btoa() methods instead", + "dev": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dev": true, + "dependencies": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, + "node_modules/acorn-globals/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals/node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.1.tgz", + "integrity": "sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/adjust-sourcemap-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", + "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/adm-zip": { + "version": "0.5.12", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.12.tgz", + "integrity": "sha512-6TVU49mK6KZb4qG6xWaaM4C7sA/sgUMLy/JYMOzkcp3BvVLpW0fXDFQiIzAuxFCt/2+xD7fNIiPFAoLZPhVNLQ==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agentkeepalive": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "dev": true, + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "devOptional": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true + }, + "node_modules/are-docs-informative": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "dev": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/array-includes": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", + "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/autoprefixer": { + "version": "10.4.14", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", + "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + } + ], + "dependencies": { + "browserslist": "^4.21.5", + "caniuse-lite": "^1.0.30001464", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", + "dev": true + }, + "node_modules/axios": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", + "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "dev": true, + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/axobject-query": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.0.0.tgz", + "integrity": "sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==", + "dev": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/babel-loader": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", + "integrity": "sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==", + "dev": true, + "dependencies": { + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0", + "webpack": ">=5" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.10.tgz", + "integrity": "sha512-rpIuu//y5OX6jVU+a5BCn1R5RSZYWAl2Nar76iwaOdycqb6JPxediskWFMMl7stfwNJR4b7eiQvh5fB5TEQJTQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.1", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "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" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.7.tgz", + "integrity": "sha512-KyDvZYxAzkC0Aj2dAPyDzi2Ym15e5JKZSK+maI7NAwSqofvuFglbSsxE7wUOvTg9oFVnHMzVzBKcqEb4PJgtOA==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.4.4", + "core-js-compat": "^3.33.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3/node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.4.tgz", + "integrity": "sha512-QcJMILQCu2jm5TFPGA3lCpJJTeEP+mqeXooG/NZbg/h5FTFi6V0+99ahlRsW8/kRLyb24LZVCCiclDedhLKcBA==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.5.tgz", + "integrity": "sha512-OJGYZlhLqBh2DDHeqAxWB1XIvr49CxiJ2gIt61/PU55CQK4Z58OzMqjDe1zwQdQk+rBYsRc+1rJmdajM3gimHg==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.5.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator/node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz", + "integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "dev": true, + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dev": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "devOptional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/blocking-proxy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-1.0.1.tgz", + "integrity": "sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "blocking-proxy": "built/lib/bin.js" + }, + "engines": { + "node": ">=6.9.x" + } + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/bonjour-service": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", + "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "devOptional": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "dev": true + }, + "node_modules/browserslist": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/browserstack": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.6.1.tgz", + "integrity": "sha512-GxtFjpIaKdbAyzHfFDKixKO8IBT7wR3NjbzrGc78nNs/Ciys9wU3/nBtsqsWv5nDSrdI5tz0peKuzCPuNXNUiw==", + "dev": true, + "dependencies": { + "https-proxy-agent": "^2.2.1" + } + }, + "node_modules/browserstack/node_modules/agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "dev": true, + "dependencies": { + "es6-promisify": "^5.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/browserstack/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/browserstack/node_modules/https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "dev": true, + "dependencies": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacache": { + "version": "17.1.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.1.4.tgz", + "integrity": "sha512-/aJwG2l3ZMJ1xNAnqbMpA40of9dj/pIH3QfiuQSqjfPJF747VR0J/bHn+/KdNnHKc6XQcWt/AfRSBft82W1d2A==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^7.7.1", + "minipass": "^7.0.3", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/cacache/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/cacache/node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001606", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001606.tgz", + "integrity": "sha512-LPbwnW4vfpJId225pwjZJOgX1m9sGfbw/RKJvw/t0QhYOOaTXHvkjVGFGPpvwEzufrjvTlsULnVTxdy4/6cqkg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "dev": true + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "node_modules/chart.js": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.2.tgz", + "integrity": "sha512-6GD7iKwFpP5kbSD4MeRRRlTnQvxfQREy36uEtm1hzHzcOqwWx0YEHuspuoNlslu+nciLIB7fjjsHkUv/FzFcOg==", + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=8" + } + }, + "node_modules/chartjs-adapter-date-fns": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chartjs-adapter-date-fns/-/chartjs-adapter-date-fns-3.0.0.tgz", + "integrity": "sha512-Rs3iEB3Q5pJ973J93OBTpnP7qoGwvq3nUnoMdtxO+9aoJof7UFcRbWcIDteXuYd1fgAvct/32T9qaLyLuZVwCg==", + "peerDependencies": { + "chart.js": ">=2.8.0", + "date-fns": ">=2.0.0" + } + }, + "node_modules/chartjs-plugin-zoom": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/chartjs-plugin-zoom/-/chartjs-plugin-zoom-2.0.1.tgz", + "integrity": "sha512-ogOmLu6e+Q7E1XWOCOz9YwybMslz9qNfGV2a+qjfmqJYpsw5ZMoRHZBUyW+NGhkpQ5PwwPA/+rikHpBZb7PZuA==", + "dependencies": { + "hammerjs": "^2.0.8" + }, + "peerDependencies": { + "chart.js": ">=3.2.0" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "devOptional": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/classlist.js": { + "version": "1.1.20150312", + "resolved": "https://registry.npmjs.org/classlist.js/-/classlist.js-1.1.20150312.tgz", + "integrity": "sha512-eR8yB970+yGslcTnJnROX2icsMa8v/KVLv/sgv3NhSvZSHgam64XNSF2TyJnKIfsnTFJBcTdrIneYqUIrvxLpg==" + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-convert/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/comment-parser": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", + "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", + "dev": true, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", + "dev": true + }, + "node_modules/compare-versions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.0.tgz", + "integrity": "sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg==" + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/connect/node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/connect/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/connect/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "dev": true + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "node_modules/copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dev": true, + "dependencies": { + "is-what": "^3.14.1" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "dev": true, + "dependencies": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/core-js-compat": { + "version": "3.36.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.1.tgz", + "integrity": "sha512-Dk997v9ZCt3X/npqzyGdTlq6t7lDBhZwGvV94PKzDArjp7BTRm7WlDAXYd/OWdeFHO8OChQYRJNJvUCqCbrtKA==", + "dev": true, + "dependencies": { + "browserslist": "^4.23.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dev": true, + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cosmiconfig/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/cosmiconfig/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/critters": { + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.20.tgz", + "integrity": "sha512-CImNRorKOl5d8TWcnAz5n5izQ6HFsvz29k327/ELy6UFcmbiZNOsinaKvzv16WZR0P6etfSWYzE47C4/56B3Uw==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "css-select": "^5.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.2", + "htmlparser2": "^8.0.2", + "postcss": "^8.4.23", + "pretty-bytes": "^5.3.0" + } + }, + "node_modules/critters/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/critters/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/critters/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/critters/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/critters/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-loader": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.8.1.tgz", + "integrity": "sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g==", + "dev": true, + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.21", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.3", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.8" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "dev": true + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + }, + "node_modules/custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", + "dev": true + }, + "node_modules/d3": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", + "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", + "dependencies": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "dependencies": { + "d3-array": "^3.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA==", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", + "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dev": true, + "dependencies": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, + "node_modules/date-format": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", + "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "dev": true + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha512-Z4fzpbIRjOu7lO5jCETSWoqUDVe0IPOlfugBsF6suen2LKDlVb4QZpKEM9P+buNJ4KI1eN7I083w/pbKUpsrWQ==", + "dev": true, + "dependencies": { + "globby": "^5.0.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "rimraf": "^2.2.8" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/del/node_modules/array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", + "dev": true, + "dependencies": { + "array-uniq": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/del/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/del/node_modules/globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha512-HJRTIH2EeH44ka+LWig+EqT2ONSYpVlNfx6pyd592/VF1TbfljJ7elwie7oSwcViLGqOdWocSdu2txwBF9bjmQ==", + "dev": true, + "dependencies": { + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/del/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/del/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/delaunator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz", + "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==", + "dependencies": { + "robust-predicates": "^3.0.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true + }, + "node_modules/di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", + "dev": true + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dev": true, + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", + "dev": true, + "dependencies": { + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "dependencies": { + "webidl-conversions": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/domexception/node_modules/webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dev": true, + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dev": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "node_modules/ejs": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz", + "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==", + "dev": true, + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.728", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.728.tgz", + "integrity": "sha512-Ud1v7hJJYIqehlUJGqR6PF1Ek8l80zWwxA6nGxigBsGJ9f9M2fciHyrIiNMerSHSH3p+0/Ia7jIlnDkt41h5cw==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/engine.io": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz", + "integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==", + "dev": true, + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz", + "integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/enhanced-resolve": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", + "dev": true + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "devOptional": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "optional": true, + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.3", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.0.tgz", + "integrity": "sha512-pqrTKmwEIgafsYZAGw9kszYzmagcE/n4dbgwGWLEXg7J4QFJVQRBld8j3Q3GNez79jzxZshq0bcT962QHOghjw==", + "dev": true + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + }, + "node_modules/es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", + "dev": true, + "dependencies": { + "es6-promise": "^4.0.3" + } + }, + "node_modules/esbuild": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.17.tgz", + "integrity": "sha512-1GJtYnUxsJreHYA0Y+iQz2UEykonY66HNWOb0yXYZi9/kNrORUEHVg87eQsCtqh59PEJ5YVZJO98JHznMJSWjg==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.17", + "@esbuild/android-arm64": "0.18.17", + "@esbuild/android-x64": "0.18.17", + "@esbuild/darwin-arm64": "0.18.17", + "@esbuild/darwin-x64": "0.18.17", + "@esbuild/freebsd-arm64": "0.18.17", + "@esbuild/freebsd-x64": "0.18.17", + "@esbuild/linux-arm": "0.18.17", + "@esbuild/linux-arm64": "0.18.17", + "@esbuild/linux-ia32": "0.18.17", + "@esbuild/linux-loong64": "0.18.17", + "@esbuild/linux-mips64el": "0.18.17", + "@esbuild/linux-ppc64": "0.18.17", + "@esbuild/linux-riscv64": "0.18.17", + "@esbuild/linux-s390x": "0.18.17", + "@esbuild/linux-x64": "0.18.17", + "@esbuild/netbsd-x64": "0.18.17", + "@esbuild/openbsd-x64": "0.18.17", + "@esbuild/sunos-x64": "0.18.17", + "@esbuild/win32-arm64": "0.18.17", + "@esbuild/win32-ia32": "0.18.17", + "@esbuild/win32-x64": "0.18.17" + } + }, + "node_modules/esbuild-wasm": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.18.17.tgz", + "integrity": "sha512-9OHGcuRzy+I8ziF9FzjfKLWAPbvi0e/metACVg9k6bK+SI4FFxeV6PcZsz8RIVaMD4YNehw+qj6UMR3+qj/EuQ==", + "dev": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "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" + } + }, + "node_modules/eslint-plugin-jsdoc": { + "version": "48.2.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.2.3.tgz", + "integrity": "sha512-r9DMAmFs66VNvNqRLLjHejdnJtILrt3xGi+Qx0op0oRfFGVpOR1Hb3BC++MacseHx93d8SKYPhyrC9BS7Os2QA==", + "dev": true, + "dependencies": { + "@es-joy/jsdoccomment": "~0.42.0", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.4.1", + "debug": "^4.3.4", + "escape-string-regexp": "^4.0.0", + "esquery": "^1.5.0", + "is-builtin-module": "^3.2.1", + "semver": "^7.6.0", + "spdx-expression-parse": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/spdx-expression-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/eslint-plugin-prefer-arrow": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prefer-arrow/-/eslint-plugin-prefer-arrow-1.2.3.tgz", + "integrity": "sha512-J9I5PKCOJretVuiZRGvPQxCbllxGAV/viI20JO3LYblAodofBxyMnZAJ+WGeClHgANnSJberTNoFWWjrWKBuXQ==", + "dev": true, + "peerDependencies": { + "eslint": ">=2.0.0" + } + }, + "node_modules/eslint-plugin-unused-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-3.1.0.tgz", + "integrity": "sha512-9l1YFCzXKkw1qtAru1RWUtG2EVDZY0a0eChKXcL+EZ5jitG7qxdctu4RnvhOJHv4xfmUf7h+JJPINlVpGhZMrw==", + "dev": true, + "dependencies": { + "eslint-rule-composer": "^0.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "6 - 7", + "eslint": "8" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + } + } + }, + "node_modules/eslint-rule-composer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", + "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter-asyncresource": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz", + "integrity": "sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==", + "dev": true + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "dev": true + }, + "node_modules/express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/external-editor/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "dev": true, + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", + "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/file-saver-es": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/file-saver-es/-/file-saver-es-2.0.5.tgz", + "integrity": "sha512-Kg0lt+is9nOyi/VDms9miScNGot25jVFbjFccXuCL/shd2Q+rt70MALxHVkXllsX83JEBLiHQNjDPGd/6FIOoQ==" + }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dev": true, + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "devOptional": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/find-cache-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", + "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", + "dev": true, + "dependencies": { + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs-minipass": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz", + "integrity": "sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "dev": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/glob": { + "version": "10.3.12", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", + "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.6", + "minimatch": "^9.0.1", + "minipass": "^7.0.4", + "path-scurry": "^1.10.2" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "devOptional": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob/node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", + "dev": true, + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/guess-parser": { + "version": "0.4.22", + "resolved": "https://registry.npmjs.org/guess-parser/-/guess-parser-0.4.22.tgz", + "integrity": "sha512-KcUWZ5ACGaBM69SbqwVIuWGoSAgD+9iJnchR9j/IarVI1jHVeXv+bUXBIMeqVMSKt3zrn0Dgf9UpcOEpPBLbSg==", + "dev": true, + "dependencies": { + "@wessberg/ts-evaluator": "0.0.27" + }, + "peerDependencies": { + "typescript": ">=3.7.5" + } + }, + "node_modules/hammerjs": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz", + "integrity": "sha512-tSQXBXS/MWQOn/RKckawJ61vvsDpCom87JgxiYdGwHdOa0ht0vzUWDlfioofFCRU0L+6NGDt6XzbgoJvZkMeRQ==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dev": true, + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/har-validator/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/har-validator/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hdr-histogram-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz", + "integrity": "sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g==", + "dev": true, + "dependencies": { + "@assemblyscript/loader": "^0.10.1", + "base64-js": "^1.2.0", + "pako": "^1.0.3" + } + }, + "node_modules/hdr-histogram-percentiles-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz", + "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==", + "dev": true + }, + "node_modules/hosted-git-info": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", + "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", + "dev": true, + "dependencies": { + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "dev": true, + "dependencies": { + "whatwg-encoding": "^1.0.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/html-entities": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", + "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dev": true, + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-walk": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.4.tgz", + "integrity": "sha512-t7sv42WkwFkyKbivUCglsQW5YWMskWtbEf4MNKX5u/CCWHKSPzN4FtBQGsQZgCLbxOzpVlcbWVK5KB3auIOjSw==", + "dev": true, + "dependencies": { + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/ignore-walk/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/ignore-walk/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "dev": true, + "optional": true, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "dev": true + }, + "node_modules/immutable": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", + "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/inquirer": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", + "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/inquirer/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/inquirer/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/inquirer/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/inquirer/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/inquirer/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/ionicons": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/ionicons/-/ionicons-6.1.3.tgz", + "integrity": "sha512-ptzz38dd/Yq+PgjhXegh7yhb/SLIk1bvL9vQDtLv1aoSc7alO6mX2DIMgcKYzt9vrNWkRu1f9Jr78zIFFyOXqw==", + "dependencies": { + "@stencil/core": "^2.18.0" + } + }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dev": true, + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ip-address/node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "dev": true + }, + "node_modules/ip-address/node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true + }, + "node_modules/ipaddr.js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", + "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "devOptional": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dev": true, + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "devOptional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "devOptional": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "devOptional": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha512-cnS56eR9SPAscL77ik76ATVqoPARTqPIVkMDVxRaWH06zT+6+CzIroYRJ0VVvm0Z1zfAvxvz9i/D3Ppjaqt5Nw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-in-cwd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", + "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", + "dev": true, + "dependencies": { + "is-path-inside": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-in-cwd/node_modules/is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha512-qhsCR/Esx4U4hg/9I19OVUAJkGWtjRYHMRgUMZE2TDdj+Ag+kttZanLupfddNyglzz50cUlmWzUaI37GDfNx/g==", + "dev": true, + "dependencies": { + "path-is-inside": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", + "dev": true + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/isbinaryfile": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", + "dev": true, + "engines": { + "node": ">= 8.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "dev": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "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" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", + "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jake": { + "version": "10.8.7", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz", + "integrity": "sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==", + "dev": true, + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jake/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jake/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jake/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jake/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jake/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jasmine": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz", + "integrity": "sha512-KbdGQTf5jbZgltoHs31XGiChAPumMSY64OZMWLNYnEnMfG5uwGBhffePwuskexjT+/Jea/gU3qAU8344hNohSw==", + "dev": true, + "dependencies": { + "exit": "^0.1.2", + "glob": "^7.0.6", + "jasmine-core": "~2.8.0" + }, + "bin": { + "jasmine": "bin/jasmine.js" + } + }, + "node_modules/jasmine-core": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.5.0.tgz", + "integrity": "sha512-9PMzyvhtocxb3aXJVOPqBDswdgyAeSB81QnLop4npOpbqnheaTEwPc9ZloQeVswugPManznQBjD8kWDTjlnHuw==", + "dev": true + }, + "node_modules/jasmine-spec-reporter": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-7.0.0.tgz", + "integrity": "sha512-OtC7JRasiTcjsaCBPtMO0Tl8glCejM4J4/dNuOJdA8lBjz4PmWjYQ6pzb0uzpBNAWJMDudYuj9OdXJWqM2QTJg==", + "dev": true, + "dependencies": { + "colors": "1.4.0" + } + }, + "node_modules/jasmine/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jasmine/node_modules/jasmine-core": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz", + "integrity": "sha512-SNkOkS+/jMZvLhuSx1fjhcNWUC/KG6oVyFUGkSBEr9n1axSNduWU8GlI7suaHXr4yxjet6KjrUZxUTE5WzzWwQ==", + "dev": true + }, + "node_modules/jasminewd2": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.2.0.tgz", + "integrity": "sha512-Rn0nZe4rfDhzA63Al3ZGh0E+JTmM6ESZYXJGKuqKGZObsAB9fwXPD03GjtIEvJBDOhN94T5MzbwZSqzFHSQPzg==", + "dev": true, + "engines": { + "node": ">= 6.9.x" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jiti": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "dev": true, + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true + }, + "node_modules/jsdoc-type-pratt-parser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", + "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "dev": true, + "dependencies": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==" + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dev": true, + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "dev": true, + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jszip/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/jszip/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/jszip/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/karma": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.2.tgz", + "integrity": "sha512-C6SU/53LB31BEgRg+omznBEMY4SjHU3ricV6zBcAe1EeILKkeScr+fZXtaI5WyDbkVowJxxAI6h73NcFPmXolQ==", + "dev": true, + "dependencies": { + "@colors/colors": "1.5.0", + "body-parser": "^1.19.0", + "braces": "^3.0.2", + "chokidar": "^3.5.1", + "connect": "^3.7.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.1", + "glob": "^7.1.7", + "graceful-fs": "^4.2.6", + "http-proxy": "^1.18.1", + "isbinaryfile": "^4.0.8", + "lodash": "^4.17.21", + "log4js": "^6.4.1", + "mime": "^2.5.2", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.5", + "qjobs": "^1.2.0", + "range-parser": "^1.2.1", + "rimraf": "^3.0.2", + "socket.io": "^4.4.1", + "source-map": "^0.6.1", + "tmp": "^0.2.1", + "ua-parser-js": "^0.7.30", + "yargs": "^16.1.1" + }, + "bin": { + "karma": "bin/karma" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/karma-chrome-launcher": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.2.0.tgz", + "integrity": "sha512-rE9RkUPI7I9mAxByQWkGJFXfFD6lE4gC5nPuZdobf/QdTEJI6EU4yIay/cfU/xV4ZxlM5JiTv7zWYgA64NpS5Q==", + "dev": true, + "dependencies": { + "which": "^1.2.1" + } + }, + "node_modules/karma-chrome-launcher/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/karma-coverage": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-2.2.1.tgz", + "integrity": "sha512-yj7hbequkQP2qOSb20GuNSIyE//PgJWHwC2IydLE6XRtsnaflv+/OSGNssPjobYUlhVVagy99TQpqUt3vAUG7A==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.1", + "istanbul-reports": "^3.0.5", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/karma-coverage-istanbul-reporter": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-3.0.3.tgz", + "integrity": "sha512-wE4VFhG/QZv2Y4CdAYWDbMmcAHeS926ZIji4z+FkB2aF/EposRb6DP6G5ncT/wXhqUfAb/d7kZrNKPonbvsATw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^3.0.6", + "istanbul-reports": "^3.0.2", + "minimatch": "^3.0.4" + }, + "funding": { + "url": "https://github.com/sponsors/mattlewis92" + } + }, + "node_modules/karma-coverage-istanbul-reporter/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/karma-coverage-istanbul-reporter/node_modules/istanbul-lib-source-maps": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", + "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "rimraf": "^2.6.3", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/karma-coverage-istanbul-reporter/node_modules/istanbul-lib-source-maps/node_modules/istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/karma-coverage-istanbul-reporter/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/karma-coverage-istanbul-reporter/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/karma-jasmine": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-5.1.0.tgz", + "integrity": "sha512-i/zQLFrfEpRyQoJF9fsCdTMOF5c2dK7C7OmsuKg2D0YSsuZSfQDiLuaiktbuio6F2wiCsZSnSnieIQ0ant/uzQ==", + "dev": true, + "dependencies": { + "jasmine-core": "^4.1.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "karma": "^6.0.0" + } + }, + "node_modules/karma-jasmine-html-reporter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-2.1.0.tgz", + "integrity": "sha512-sPQE1+nlsn6Hwb5t+HHwyy0A1FNCVKuL1192b+XNauMYWThz2kweiBVW1DqloRpVvZIJkIoHVB7XRpK78n1xbQ==", + "dev": true, + "peerDependencies": { + "jasmine-core": "^4.0.0 || ^5.0.0", + "karma": "^6.0.0", + "karma-jasmine": "^5.0.0" + } + }, + "node_modules/karma-source-map-support": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", + "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", + "dev": true, + "dependencies": { + "source-map-support": "^0.5.5" + } + }, + "node_modules/karma/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/karma/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/karma/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/karma/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/karma/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/karma/node_modules/tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dev": true, + "dependencies": { + "rimraf": "^3.0.0" + }, + "engines": { + "node": ">=8.17.0" + } + }, + "node_modules/karma/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/karma/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/launch-editor": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.1.tgz", + "integrity": "sha512-eB/uXmFVpY4zezmGp5XtU21kwo7GBbKB+EQ+UZeWtGb9yAM5xt/Evk+lYH3eRNAtId+ej4u7TYPFZ07w4s7rRw==", + "dev": true, + "dependencies": { + "picocolors": "^1.0.0", + "shell-quote": "^1.8.1" + } + }, + "node_modules/less": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/less/-/less-4.2.0.tgz", + "integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==", + "dev": true, + "peer": true, + "dependencies": { + "copy-anything": "^2.0.1", + "parse-node-version": "^1.0.1", + "tslib": "^2.3.0" + }, + "bin": { + "lessc": "bin/lessc" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "source-map": "~0.6.0" + } + }, + "node_modules/less-loader": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.1.0.tgz", + "integrity": "sha512-C+uDBV7kS7W5fJlUjq5mPBeBVhYpTIm5gB09APT9o3n/ILeaXVsiSFTbZpTJCJwQ/Crczfn3DmfQFwxYusWFug==", + "dev": true, + "dependencies": { + "klona": "^2.0.4" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "less": "^3.5.0 || ^4.0.0", + "webpack": "^5.0.0" + } + }, + "node_modules/less/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/license-webpack-plugin": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", + "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==", + "dev": true, + "dependencies": { + "webpack-sources": "^3.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-sources": { + "optional": true + } + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", + "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", + "dev": true, + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/log4js": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.9.1.tgz", + "integrity": "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==", + "dev": true, + "dependencies": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "flatted": "^3.2.7", + "rfdc": "^1.3.0", + "streamroller": "^3.1.5" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.1.tgz", + "integrity": "sha512-mbVKXPmS0z0G4XqFDCTllmDQ6coZzn94aMlb0o/A4HEHJCKcanlDZwYJgwnkmgD3jyWhUgj9VsPrfd972yPffA==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/make-fetch-happen": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", + "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^16.1.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^2.0.3", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^9.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/@npmcli/fs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", + "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", + "dev": true, + "dependencies": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/make-fetch-happen/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/cacache": { + "version": "16.1.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", + "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/make-fetch-happen/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/make-fetch-happen/node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/make-fetch-happen/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/make-fetch-happen/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-fetch-happen/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/make-fetch-happen/node_modules/ssri": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", + "dev": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/unique-filename": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", + "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", + "dev": true, + "dependencies": { + "unique-slug": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/unique-slug": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", + "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.7.6", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.6.tgz", + "integrity": "sha512-Qk7HcgaPkGG6eD77mLvZS1nmxlao3j+9PkrT9Uc7HAE1id3F41+DdBRYRYkbyfNRGzm8/YWtzhw7nVPmwhqTQw==", + "dev": true, + "dependencies": { + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-collect/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/minipass-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", + "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "dev": true, + "dependencies": { + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/minipass-fetch/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-fetch/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-flush/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "dev": true, + "dependencies": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "node_modules/minipass-json-stream/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-json-stream/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mrmime": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", + "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/needle": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.3.1.tgz", + "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", + "dev": true, + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/ng2-charts": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ng2-charts/-/ng2-charts-4.1.1.tgz", + "integrity": "sha512-iHwXDbmX86lfeH8VRcsaW2tJATsuAZo4kvvC/Yk2l35zOHjevja1qBvO6BAibiDazi9r9aS6ZRJOqWPsz1pP2w==", + "dependencies": { + "lodash-es": "^4.17.15", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/cdk": ">=14.0.0", + "@angular/common": ">=14.0.0", + "@angular/core": ">=14.0.0", + "chart.js": "^3.4.0 || ^4.0.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/ngx-cookie-service": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/ngx-cookie-service/-/ngx-cookie-service-16.1.0.tgz", + "integrity": "sha512-FrzMjsGCHZCd2sEucigMaGyzImBL0l6gwWn6jmLBhcNVx0D7P8Yvtgk9aUptlqBrVKy4c2upglSa3Ogv3679bw==", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/common": "^16.0.0", + "@angular/core": "^16.0.0" + } + }, + "node_modules/ngx-spinner": { + "version": "16.0.2", + "resolved": "https://registry.npmjs.org/ngx-spinner/-/ngx-spinner-16.0.2.tgz", + "integrity": "sha512-MZpOHb3dvSqD6xiEdR+EtOfPY2r1kfA7t5Hv5IVwi7gkbTwVgnqxDWdOYJ/HW1pSZ5iEGhqlJqWg6CysLmNfHQ==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/animations": ">=15.0.0", + "@angular/common": ">=15.0.0", + "@angular/core": ">=15.0.0" + } + }, + "node_modules/nice-napi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", + "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "!win32" + ], + "dependencies": { + "node-addon-api": "^3.0.0", + "node-gyp-build": "^4.2.2" + } + }, + "node_modules/node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "dev": true + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-gyp": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.1.tgz", + "integrity": "sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^10.0.3", + "nopt": "^6.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^12.13 || ^14.13 || >=16" + } + }, + "node_modules/node-gyp-build": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.0.tgz", + "integrity": "sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==", + "dev": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-gyp/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, + "node_modules/nopt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", + "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "dev": true, + "dependencies": { + "abbrev": "^1.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/normalize-package-data": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-5.0.0.tgz", + "integrity": "sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q==", + "dev": true, + "dependencies": { + "hosted-git-info": "^6.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "devOptional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-bundled": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.0.tgz", + "integrity": "sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ==", + "dev": true, + "dependencies": { + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-install-checks": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz", + "integrity": "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==", + "dev": true, + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-package-arg": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz", + "integrity": "sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^6.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-packlist": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-7.0.4.tgz", + "integrity": "sha512-d6RGEuRrNS5/N84iglPivjaJPxhDbZmlbTwTDX2IbcRHG5bZCdtysYMhwiPvcF4GisXHGn7xsxv+GQ7T/02M5Q==", + "dev": true, + "dependencies": { + "ignore-walk": "^6.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-pick-manifest": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-8.0.1.tgz", + "integrity": "sha512-mRtvlBjTsJvfCCdmPtiu2bdlx8d/KXtF7yNXNWe7G0Z36qWA9Ny5zXsI2PfBZEv7SXgoxTmNaTzGSbbzDZChoA==", + "dev": true, + "dependencies": { + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^10.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-registry-fetch": { + "version": "14.0.5", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-14.0.5.tgz", + "integrity": "sha512-kIDMIo4aBm6xg7jOttupWZamsZRkAqMqwqqbVXnUqstY5+tapvv6bkH/qMR76jdgV+YljEUCyWx3hRYMrJiAgA==", + "dev": true, + "dependencies": { + "make-fetch-happen": "^11.0.0", + "minipass": "^5.0.0", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^10.0.0", + "proc-log": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-registry-fetch/node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/npm-registry-fetch/node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/npm-registry-fetch/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/npm-registry-fetch/node_modules/make-fetch-happen": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", + "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^5.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-registry-fetch/node_modules/minipass-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/npm-registry-fetch/node_modules/minipass-fetch/node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "dev": true, + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/nwsapi": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", + "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==", + "dev": true + }, + "node_modules/nx": { + "version": "16.5.1", + "resolved": "https://registry.npmjs.org/nx/-/nx-16.5.1.tgz", + "integrity": "sha512-I3hJRE4hG7JWAtncWwDEO3GVeGPpN0TtM8xH5ArZXyDuVeTth/i3TtJzdDzqXO1HHtIoAQN0xeq4n9cLuMil5g==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@nrwl/tao": "16.5.1", + "@parcel/watcher": "2.0.4", + "@yarnpkg/lockfile": "^1.1.0", + "@yarnpkg/parsers": "3.0.0-rc.46", + "@zkochan/js-yaml": "0.0.6", + "axios": "^1.0.0", + "chalk": "^4.1.0", + "cli-cursor": "3.1.0", + "cli-spinners": "2.6.1", + "cliui": "^7.0.2", + "dotenv": "~10.0.0", + "enquirer": "~2.3.6", + "fast-glob": "3.2.7", + "figures": "3.2.0", + "flat": "^5.0.2", + "fs-extra": "^11.1.0", + "glob": "7.1.4", + "ignore": "^5.0.4", + "js-yaml": "4.1.0", + "jsonc-parser": "3.2.0", + "lines-and-columns": "~2.0.3", + "minimatch": "3.0.5", + "npm-run-path": "^4.0.1", + "open": "^8.4.0", + "semver": "7.5.3", + "string-width": "^4.2.3", + "strong-log-transformer": "^2.1.0", + "tar-stream": "~2.2.0", + "tmp": "~0.2.1", + "tsconfig-paths": "^4.1.2", + "tslib": "^2.3.0", + "v8-compile-cache": "2.3.0", + "yargs": "^17.6.2", + "yargs-parser": "21.1.1" + }, + "bin": { + "nx": "bin/nx.js" + }, + "optionalDependencies": { + "@nx/nx-darwin-arm64": "16.5.1", + "@nx/nx-darwin-x64": "16.5.1", + "@nx/nx-freebsd-x64": "16.5.1", + "@nx/nx-linux-arm-gnueabihf": "16.5.1", + "@nx/nx-linux-arm64-gnu": "16.5.1", + "@nx/nx-linux-arm64-musl": "16.5.1", + "@nx/nx-linux-x64-gnu": "16.5.1", + "@nx/nx-linux-x64-musl": "16.5.1", + "@nx/nx-win32-arm64-msvc": "16.5.1", + "@nx/nx-win32-x64-msvc": "16.5.1" + }, + "peerDependencies": { + "@swc-node/register": "^1.4.2", + "@swc/core": "^1.2.173" + }, + "peerDependenciesMeta": { + "@swc-node/register": { + "optional": true + }, + "@swc/core": { + "optional": true + } + } + }, + "node_modules/nx/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/nx/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/nx/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/nx/node_modules/cli-spinners": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", + "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nx/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/nx/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/nx/node_modules/fast-glob": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", + "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nx/node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/nx/node_modules/glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/nx/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/nx/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/nx/node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, + "node_modules/nx/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/nx/node_modules/lines-and-columns": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.4.tgz", + "integrity": "sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/nx/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/nx/node_modules/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/nx/node_modules/semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/nx/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nx/node_modules/tmp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "dev": true, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/nx/node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dev": true, + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/nx/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/nx/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object-path": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.11.8.tgz", + "integrity": "sha512-YJjNZrlXJFM42wTBn6zgOJVar9KFJvzx6sTWDte8sWZF//cnjl0BxHNpfZx+ZffXX63A9q0b1zsFiBX4g4X5KA==", + "dev": true, + "engines": { + "node": ">= 10.12.0" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", + "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ora/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/ora/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ora/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-retry/node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pacote": { + "version": "15.2.0", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.2.0.tgz", + "integrity": "sha512-rJVZeIwHTUta23sIZgEIM62WYwbmGbThdbnkt81ravBplQv+HjyroqnLRNH2+sLJHcGZmLRmhPwACqhfTcOmnA==", + "dev": true, + "dependencies": { + "@npmcli/git": "^4.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^6.0.1", + "@npmcli/run-script": "^6.0.0", + "cacache": "^17.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^5.0.0", + "npm-package-arg": "^10.0.0", + "npm-packlist": "^7.0.0", + "npm-pick-manifest": "^8.0.0", + "npm-registry-fetch": "^14.0.0", + "proc-log": "^3.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^6.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^1.3.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "node_modules/parse5-html-rewriting-stream": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-7.0.0.tgz", + "integrity": "sha512-mazCyGWkmCRWDI15Zp+UiCqMp/0dgEmkZRvhlsqqKYr4SsVm/TvnSpD9fCvqCA2zoWJcfRym846ejWBBHRiYEg==", + "dev": true, + "dependencies": { + "entities": "^4.3.0", + "parse5": "^7.0.0", + "parse5-sax-parser": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-html-rewriting-stream/node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-sax-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-7.0.0.tgz", + "integrity": "sha512-5A+v2SNsq8T6/mG3ahcz8ZtQ0OUFTatxPbeidoMB7tkJSGDY3tdfl4MHovtLQHkEn5CGxijNWRQHhRQ6IRpXKg==", + "dev": true, + "dependencies": { + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-sax-parser/node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", + "dev": true + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-scurry": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", + "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "devOptional": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "dev": true, + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/piscina": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.0.0.tgz", + "integrity": "sha512-641nAmJS4k4iqpNUqfggqUBUMmlw0ZoM5VZKdQkV2e970Inn3Tk9kroCc1wpsYLD07vCwpys5iY0d3xI/9WkTg==", + "dev": true, + "dependencies": { + "eventemitter-asyncresource": "^1.0.0", + "hdr-histogram-js": "^2.0.1", + "hdr-histogram-percentiles-obj": "^3.0.0" + }, + "optionalDependencies": { + "nice-napi": "^1.0.2" + } + }, + "node_modules/pkg-dir": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", + "dev": true, + "dependencies": { + "find-up": "^6.3.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "dev": true, + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dev": true, + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dev": true, + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/pkg-dir/node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.4.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", + "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-loader": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.3.3.tgz", + "integrity": "sha512-YgO/yhtevGO/vJePCQmTxiaEwER94LABZN0ZMT4A0vsak9TpO+RvKRs7EmJ8peIlB9xfXCsS7M8LjqncsUZ5HA==", + "dev": true, + "dependencies": { + "cosmiconfig": "^8.2.0", + "jiti": "^1.18.2", + "semver": "^7.3.8" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", + "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", + "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.16", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz", + "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/protractor": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/protractor/-/protractor-7.0.0.tgz", + "integrity": "sha512-UqkFjivi4GcvUQYzqGYNe0mLzfn5jiLmO8w9nMhQoJRLhy2grJonpga2IWhI6yJO30LibWXJJtA4MOIZD2GgZw==", + "deprecated": "We have news to share - Protractor is deprecated and will reach end-of-life by Summer 2023. To learn more and find out about other options please refer to this post on the Angular blog. Thank you for using and contributing to Protractor. https://goo.gle/state-of-e2e-in-angular", + "dev": true, + "dependencies": { + "@types/q": "^0.0.32", + "@types/selenium-webdriver": "^3.0.0", + "blocking-proxy": "^1.0.0", + "browserstack": "^1.5.1", + "chalk": "^1.1.3", + "glob": "^7.0.3", + "jasmine": "2.8.0", + "jasminewd2": "^2.1.0", + "q": "1.4.1", + "saucelabs": "^1.5.0", + "selenium-webdriver": "3.6.0", + "source-map-support": "~0.4.0", + "webdriver-js-extender": "2.1.0", + "webdriver-manager": "^12.1.7", + "yargs": "^15.3.1" + }, + "bin": { + "protractor": "bin/protractor", + "webdriver-manager": "bin/webdriver-manager" + }, + "engines": { + "node": ">=10.13.x" + } + }, + "node_modules/protractor/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/protractor/node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/protractor/node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/protractor/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/protractor/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/protractor/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "dependencies": { + "source-map": "^0.5.6" + } + }, + "node_modules/protractor/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/protractor/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/protractor/node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/protractor/node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/protractor/node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/protractor/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/protractor/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/protractor/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "dev": true, + "optional": true + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/q": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", + "integrity": "sha512-/CdEdaw49VZVmyIDGUQKDDT53c7qBkO6g5CefWz91Ae+l4+cRtcDYwMTXh6me4O8TMldeGHG3N2Bl84V78Ywbg==", + "dev": true, + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "dev": true, + "engines": { + "node": ">=0.9" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-package-json": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-6.0.4.tgz", + "integrity": "sha512-AEtWXYfopBj2z5N5PbkAOeNHRPUg5q+Nen7QLxV8M2zJq1ym6/lCz3fYNTCXe19puu2d06jfHhrP7v/S2PtMMw==", + "dev": true, + "dependencies": { + "glob": "^10.2.2", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^5.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-package-json-fast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", + "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", + "dev": true, + "dependencies": { + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-package-json-fast/node_modules/json-parse-even-better-errors": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", + "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-package-json/node_modules/json-parse-even-better-errors": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", + "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "devOptional": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/reflect-metadata": { + "version": "0.1.14", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz", + "integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==", + "dev": true + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regex-parser": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.3.0.tgz", + "integrity": "sha512-TVILVSz2jY5D47F4mA4MppkBrafEaiUWJO/TcZHEIuI13AqoZMkK1WMA4Om1YkYbTx+9Ki1/tSUXbceyr9saRg==", + "dev": true + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dev": true, + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dev": true, + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request/node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/request/node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/request/node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/request/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-url-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", + "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", + "dev": true, + "dependencies": { + "adjust-sourcemap-loader": "^4.0.0", + "convert-source-map": "^1.7.0", + "loader-utils": "^2.0.0", + "postcss": "^8.2.14", + "source-map": "0.6.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/resolve-url-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/resolve-url-loader/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "dev": true + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/roboto-fontface": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/roboto-fontface/-/roboto-fontface-0.10.0.tgz", + "integrity": "sha512-OlwfYEgA2RdboZohpldlvJ1xngOins5d7ejqnIBWr9KaMxsnBqotpptRXTyfNRLnFpqzX6sTDt+X+a+6udnU8g==" + }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" + }, + "node_modules/rollup": { + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" + }, + "node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/rxjs/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sass": { + "version": "1.64.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.64.1.tgz", + "integrity": "sha512-16rRACSOFEE8VN7SCgBu1MpYCyN7urj9At898tyzdXFhC+a+yOX5dXwAR7L8/IdPJ1NB8OYoXmD55DM30B2kEQ==", + "dev": true, + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-loader": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.2.tgz", + "integrity": "sha512-CQbKl57kdEv+KDLquhC+gE3pXt74LEAzm+tzywcA0/aHZuub8wTErbjAoNI57rPUWRYRNC5WUnNl8eGJNbDdwg==", + "dev": true, + "dependencies": { + "neo-async": "^2.6.2" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "fibers": ">= 3.1.0", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "fibers": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + } + } + }, + "node_modules/saucelabs": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.5.0.tgz", + "integrity": "sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ==", + "dev": true, + "dependencies": { + "https-proxy-agent": "^2.2.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/saucelabs/node_modules/agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "dev": true, + "dependencies": { + "es6-promisify": "^5.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/saucelabs/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/saucelabs/node_modules/https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "dev": true, + "dependencies": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/sax": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", + "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==", + "dev": true + }, + "node_modules/saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dev": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, + "node_modules/selenium-webdriver": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz", + "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==", + "dev": true, + "dependencies": { + "jszip": "^3.1.3", + "rimraf": "^2.5.4", + "tmp": "0.0.30", + "xml2js": "^0.4.17" + }, + "engines": { + "node": ">= 6.9.0" + } + }, + "node_modules/selenium-webdriver/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/selenium-webdriver/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/selenium-webdriver/node_modules/tmp": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", + "integrity": "sha512-HXdTB7lvMwcb55XFfrTM8CPr/IYREk4hVBFaQ4b/6nInrluSL86hfHm7vu0luYKCfyBZp2trCjpc8caC3vVM3w==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.1" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dev": true, + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/sigstore": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-1.9.0.tgz", + "integrity": "sha512-0Zjz0oe37d08VeOtBIuB6cRriqXse2e8w+7yIy2XSXjshRKxbc2KkhXjL229jXSxEm7UbcjS76wcJDGQddVI9A==", + "dev": true, + "dependencies": { + "@sigstore/bundle": "^1.1.0", + "@sigstore/protobuf-specs": "^0.2.0", + "@sigstore/sign": "^1.0.0", + "@sigstore/tuf": "^1.0.3", + "make-fetch-happen": "^11.0.1" + }, + "bin": { + "sigstore": "bin/sigstore.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/sigstore/node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/sigstore/node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/sigstore/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/sigstore/node_modules/make-fetch-happen": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", + "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^5.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/sigstore/node_modules/minipass-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/sigstore/node_modules/minipass-fetch/node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socket.io": { + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.3.tgz", + "integrity": "sha512-SE+UIQXBQE+GPG2oszWMlsEmWtHVqw/h1VrYJGK5/MC7CH5p58N448HwIrtREcvR4jfdOJAY4ieQfxMr55qbbw==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.5.2", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz", + "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==", + "dev": true, + "dependencies": { + "ws": "~8.11.0" + } + }, + "node_modules/socket.io-adapter/node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dev": true, + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/sockjs/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/socks": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.1.tgz", + "integrity": "sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ==", + "dev": true, + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "dev": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-4.0.1.tgz", + "integrity": "sha512-oqXpzDIByKONVY8g1NUPOTQhe0UTU5bWUl32GSkqK2LjJj0HmwTMVKxcUip0RgAYhY1mqgOxjbQM48a0mmeNfA==", + "dev": true, + "dependencies": { + "abab": "^2.0.6", + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.72.1" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "deprecated": "Please use @jridgewell/sourcemap-codec instead" + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", + "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", + "dev": true + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/sshpk": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", + "dev": true, + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ssri": { + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", + "integrity": "sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/ssri/node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/streamroller": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", + "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==", + "dev": true, + "dependencies": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strong-log-transformer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz", + "integrity": "sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA==", + "dev": true, + "dependencies": { + "duplexer": "^0.1.1", + "minimist": "^1.2.0", + "through": "^2.3.4" + }, + "bin": { + "sl-log-transformer": "bin/sl-log-transformer.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/swiper": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.1.1.tgz", + "integrity": "sha512-jGmEA/fNz1lACIcY4/40ggm1Gcyv+EUivmgV/Jd2WFPsEJhbWXnRAwzZR8OPjkBLtDxmzcoYG/iiAMWfRs0YKQ==", + "funding": [ + { + "type": "patreon", + "url": "https://www.patreon.com/swiperjs" + }, + { + "type": "open_collective", + "url": "http://opencollective.com/swiper" + } + ], + "engines": { + "node": ">= 4.7.0" + } + }, + "node_modules/symbol-observable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", + "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/terser": { + "version": "5.29.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.29.1.tgz", + "integrity": "sha512-lZQ/fyaIGxsbGxApKmoPTODIzELy3++mXhS5hOqaAWZjQtpq/hFHAc+rm29NND1rYRxRWKcjuARNwULNXa5RtQ==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "devOptional": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "dev": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/ts-api-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", + "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "dev": true, + "engines": { + "node": ">=16.13.0" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tuf-js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-1.1.7.tgz", + "integrity": "sha512-i3P9Kgw3ytjELUfpuKVDNBJvk4u5bXL6gskv572mcevPbSKCV3zt3djhmlEQ65yERjIbOSncy7U4cQJaB1CBCg==", + "dev": true, + "dependencies": { + "@tufjs/models": "1.0.4", + "debug": "^4.3.4", + "make-fetch-happen": "^11.1.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/tuf-js/node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/tuf-js/node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/tuf-js/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/tuf-js/node_modules/make-fetch-happen": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", + "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^5.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/tuf-js/node_modules/minipass-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/tuf-js/node_modules/minipass-fetch/node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-assert": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", + "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", + "dev": true + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/typescript-strict-plugin": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/typescript-strict-plugin/-/typescript-strict-plugin-2.4.1.tgz", + "integrity": "sha512-LYjh7JLcxAzGQQEmoxzSbJvBSqRvQaFfz984s08tdYCwxrso0HWeeUZto1umu9juousVMmiUBR/dvQMik4ffiw==", + "dev": true, + "dependencies": { + "chalk": "^3.0.0", + "execa": "^4.0.0", + "minimatch": "^9.0.3", + "ora": "^5.4.1", + "yargs": "^16.2.0" + }, + "bin": { + "tsc-strict": "dist/cli/tsc-strict/index.js", + "update-strict-comments": "dist/cli/update-strict-comments/index.js" + } + }, + "node_modules/typescript-strict-plugin/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/typescript-strict-plugin/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/typescript-strict-plugin/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/typescript-strict-plugin/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/typescript-strict-plugin/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/typescript-strict-plugin/node_modules/execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/typescript-strict-plugin/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript-strict-plugin/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/typescript-strict-plugin/node_modules/human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true, + "engines": { + "node": ">=8.12.0" + } + }, + "node_modules/typescript-strict-plugin/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/typescript-strict-plugin/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/typescript-strict-plugin/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/typescript-strict-plugin/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ua-parser-js": { + "version": "0.7.37", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.37.tgz", + "integrity": "sha512-xV8kqRKM+jhMvcHWUKthV9fNebIzrNy//2O9ZwWcfiBFR5f25XVZPLlEajk/sf3Ra15V92isyQqnIEXRDaZWEA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "engines": { + "node": "*" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "dev": true, + "dependencies": { + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", + "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", + "dev": true, + "dependencies": { + "builtins": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/vite": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz", + "integrity": "sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==", + "dev": true, + "dependencies": { + "esbuild": "^0.18.10", + "postcss": "^8.4.27", + "rollup": "^3.27.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "deprecated": "Use your platform's native performance.now() and performance.timeOrigin.", + "dev": true, + "dependencies": { + "browser-process-hrtime": "^1.0.0" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "dev": true, + "dependencies": { + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/webdriver-js-extender": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz", + "integrity": "sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ==", + "dev": true, + "dependencies": { + "@types/selenium-webdriver": "^3.0.0", + "selenium-webdriver": "^3.0.1" + }, + "engines": { + "node": ">=6.9.x" + } + }, + "node_modules/webdriver-manager": { + "version": "12.1.9", + "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.1.9.tgz", + "integrity": "sha512-Yl113uKm8z4m/KMUVWHq1Sjtla2uxEBtx2Ue3AmIlnlPAKloDn/Lvmy6pqWCUersVISpdMeVpAaGbNnvMuT2LQ==", + "dev": true, + "dependencies": { + "adm-zip": "^0.5.2", + "chalk": "^1.1.1", + "del": "^2.2.0", + "glob": "^7.0.3", + "ini": "^1.3.4", + "minimist": "^1.2.0", + "q": "^1.4.1", + "request": "^2.87.0", + "rimraf": "^2.5.2", + "semver": "^5.3.0", + "xml2js": "^0.4.17" + }, + "bin": { + "webdriver-manager": "bin/webdriver-manager" + }, + "engines": { + "node": ">=6.9.x" + } + }, + "node_modules/webdriver-manager/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webdriver-manager/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webdriver-manager/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webdriver-manager/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/webdriver-manager/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/webdriver-manager/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/webdriver-manager/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/webdriver-manager/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webdriver-manager/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true, + "engines": { + "node": ">=10.4" + } + }, + "node_modules/webpack": { + "version": "5.90.3", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.3.tgz", + "integrity": "sha512-h6uDYlWCctQRuXBs1oYpVe6sFcWedl0dpcVaTf/YF67J9bKvwJajFulMVSYKHrksMB3I/pIagRzDxwxkebuzKA==", + "dev": true, + "peer": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.21.10", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-middleware": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.1.2.tgz", + "integrity": "sha512-Wu+EHmX326YPYUpQLKmKbTyZZJIB8/n6R09pTmB03kJmnMsVPTo9COzHZFr01txwaCAuZvfBJE4ZCHRcKs5JaQ==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.12", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server": { + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", + "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", + "dev": true, + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.5", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.13.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/webpack-dev-middleware": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-server/node_modules/ws": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", + "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/webpack-merge": { + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.9.0.tgz", + "integrity": "sha512-6NbRQw4+Sy50vYNTw7EyOn41OZItPiXB8GNv3INSoe3PSFaHJEz3SHTrYVaRm2LilNGnFUzh0FAwqPEmU/CwDg==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-subresource-integrity": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz", + "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==", + "dev": true, + "dependencies": { + "typed-assert": "^1.0.8" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "html-webpack-plugin": ">= 5.0.0-beta.1 < 6", + "webpack": "^5.12.0" + }, + "peerDependenciesMeta": { + "html-webpack-plugin": { + "optional": true + } + } + }, + "node_modules/webpack/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peer": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/webpack/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "peer": true + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "peer": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "dependencies": { + "iconv-lite": "0.4.24" + } + }, + "node_modules/whatwg-encoding/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "dev": true, + "dependencies": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "dev": true + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true } + } + }, + "node_modules/xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, + "node_modules/xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dev": true, + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zone.js": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.13.3.tgz", + "integrity": "sha512-MKPbmZie6fASC/ps4dkmIhaT5eonHkEt6eAy80K42tAm0G2W+AahLJjbfi6X9NPdciOE9GRFTTM8u2IiF6O3ww==", + "dependencies": { + "tslib": "^2.3.0" + } } + } } diff --git a/ui/package.json b/ui/package.json index 9111de9179c..9bceb0ddfaf 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,77 +1,78 @@ { - "name": "openems-ui", - "version": "2024.5.0-SNAPSHOT", - "license": "AGPL-3.0", - "private": true, - "dependencies": { - "@angular/animations": "~15.2.9", - "@angular/cdk": "~15.2.9", - "@angular/common": "~15.2.9", - "@angular/core": "~15.2.9", - "@angular/forms": "~15.2.9", - "@angular/platform-browser": "~15.2.9", - "@angular/platform-browser-dynamic": "~15.2.9", - "@angular/router": "~15.2.9", - "@angular/service-worker": "~15.2.9", - "@ionic/angular": "^6.7.4", - "@ngx-formly/core": "^6.1.7", - "@ngx-formly/ionic": "^6.1.7", - "@ngx-formly/schematics": "^6.1.7", - "@ngx-translate/core": "^14.0.0", - "angular-mydatepicker": "^0.11.5", - "chart.js": "^4.4.0", - "chartjs-adapter-date-fns": "^3.0.0", - "chartjs-plugin-zoom": "^2.0.1", - "classlist.js": "^1.1.20150312", - "compare-versions": "^6.1.0", - "d3": "^7.9.0", - "date-fns": "^2.30.0", - "file-saver-es": "^2.0.5", - "ng2-charts": "4.1.1", - "ngx-cookie-service": "^15.0.0", - "ngx-spinner": "^15.0.1", - "roboto-fontface": "^0.10.0", - "rxjs": "~6.6.7", - "tslib": "^2.5.0", - "uuid": "^9.0.0", - "zone.js": "~0.13.0" - }, - "devDependencies": { - "@angular-devkit/build-angular": "^15.2.8", - "@angular-eslint/builder": "~15.2.1", - "@angular-eslint/eslint-plugin": "~15.2.1", - "@angular-eslint/eslint-plugin-template": "~15.2.1", - "@angular-eslint/template-parser": "~15.2.1", - "@angular/cli": "~15.2.8", - "@angular/compiler": "~15.2.9", - "@angular/compiler-cli": "~15.2.9", - "@angular/language-service": "~15.2.9", - "@ionic/angular-toolkit": "^7.0.0", - "@types/jasmine": "~4.3.2", - "@types/jasminewd2": "~2.0.10", - "@types/node": "^20.2.5", - "@types/uuid": "^9.0.2", - "@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": "^3.1.0", - "jasmine-core": "~4.5.0", - "jasmine-spec-reporter": "~7.0.0", - "karma": "~6.4.2", - "karma-chrome-launcher": "~3.2.0", - "karma-coverage": "~2.2.0", - "karma-coverage-istanbul-reporter": "~3.0.3", - "karma-jasmine": "~5.1.0", - "karma-jasmine-html-reporter": "^2.0.0", - "protractor": "~7.0.0", - "ts-node": "~10.9.1", - "typescript": "~4.9.5" - }, - "scripts": { - "lint": "ng lint", - "test": "ng test" - } + "name": "openems-ui", + "version": "2024.5.0-SNAPSHOT", + "license": "AGPL-3.0", + "private": true, + "dependencies": { + "@angular/animations": "~16.2.12", + "@angular/common": "~16.2.12", + "@angular/core": "~16.2.12", + "@angular/forms": "~16.2.12", + "@angular/platform-browser": "~16.2.12", + "@angular/platform-browser-dynamic": "~16.2.12", + "@angular/router": "~16.2.12", + "@angular/service-worker": "~16.2.12", + "@ionic/angular": "^6.7.5", + "@ngx-formly/core": "^6.3.0", + "@ngx-formly/ionic": "^6.3.0", + "@ngx-formly/schematics": "^6.3.0", + "@ngx-translate/core": "^14.0.0", + "@nodro7/angular-mydatepicker": "^0.14.0", + "chart.js": "^4.4.2", + "chartjs-adapter-date-fns": "^3.0.0", + "chartjs-plugin-zoom": "^2.0.1", + "classlist.js": "^1.1.20150312", + "compare-versions": "^6.1.0", + "d3": "^7.9.0", + "date-fns": "^2.30.0", + "file-saver-es": "^2.0.5", + "ng2-charts": "4.1.1", + "ngx-cookie-service": "^16.1.0", + "ngx-spinner": "^16.0.2", + "roboto-fontface": "^0.10.0", + "rxjs": "~6.6.7", + "swiper": "11.1.1", + "tslib": "^2.6.2", + "uuid": "^9.0.1", + "zone.js": "~0.13.3" + }, + "devDependencies": { + "@angular-devkit/build-angular": "^16.2.13", + "@angular-eslint/builder": "^16.3.1", + "@angular-eslint/eslint-plugin": "^16.3.1", + "@angular-eslint/eslint-plugin-template": "^16.3.1", + "@angular-eslint/template-parser": "^16.3.1", + "@angular/cli": "^16.2.13", + "@angular/compiler": "^16.2.12", + "@angular/compiler-cli": "^16.2.12", + "@angular/language-service": "^16.2.12", + "@ionic/angular-toolkit": "^11.0.1", + "@types/jasmine": "~4.3.6", + "@types/jasminewd2": "~2.0.13", + "@types/node": "^20.12.6", + "@types/uuid": "^9.0.8", + "@typescript-eslint/eslint-plugin": "^6.21.0", + "@typescript-eslint/parser": "^6.21.0", + "eslint": "^8.57.0", + "eslint-plugin-import": "2.29.1", + "eslint-plugin-jsdoc": "48.2.3", + "eslint-plugin-prefer-arrow": "1.2.3", + "eslint-plugin-unused-imports": "^3.1.0", + "jasmine-core": "~4.5.0", + "jasmine-spec-reporter": "~7.0.0", + "karma": "~6.4.2", + "karma-chrome-launcher": "~3.2.0", + "karma-coverage": "~2.2.1", + "karma-coverage-istanbul-reporter": "~3.0.3", + "karma-jasmine": "~5.1.0", + "karma-jasmine-html-reporter": "^2.1.0", + "protractor": "~7.0.0", + "ts-node": "^10.9.2", + "typescript": "~4.9.5", + "typescript-strict-plugin": "^2.4.1" + }, + "scripts": { + "lint": "ng lint", + "test": "ng test" + } } diff --git a/ui/src/app/app.component.html b/ui/src/app/app.component.html index 0fed6720b56..80c7aa7d2a0 100644 --- a/ui/src/app/app.component.html +++ b/ui/src/app/app.component.html @@ -78,5 +78,5 @@

    Index.connectionFailed

    - + diff --git a/ui/src/app/app.component.ts b/ui/src/app/app.component.ts index db0bc53c50d..bcf853fe001 100644 --- a/ui/src/app/app.component.ts +++ b/ui/src/app/app.component.ts @@ -1,7 +1,8 @@ +// @ts-strict-ignore import { Component, OnDestroy, OnInit } from '@angular/core'; -import { Router } from '@angular/router'; +import { NavigationEnd, Router } from '@angular/router'; import { MenuController, ModalController, Platform, ToastController } from '@ionic/angular'; -import { Subject } from 'rxjs'; +import { Subject, Subscription } from 'rxjs'; import { filter, takeUntil } from 'rxjs/operators'; import { Meta } from '@angular/platform-browser'; @@ -21,9 +22,11 @@ export class AppComponent implements OnInit, OnDestroy { public enableSideMenu: boolean; public isSystemLogEnabled: boolean = false; private ngUnsubscribe: Subject = new Subject(); + private subscription: Subscription = new Subscription(); protected isUserAllowedToSeeOverview: boolean = false; protected isUserAllowedToSeeFooter: boolean = false; + protected isHistoryDetailView: boolean = false; constructor( private platform: Platform, @@ -38,10 +41,19 @@ export class AppComponent implements OnInit, OnDestroy { ) { service.setLang(Language.getByKey(localStorage.LANGUAGE) ?? Language.getByBrowserLang(navigator.language)); - this.service.metadata.pipe(filter(metadata => !!metadata)).subscribe(metadata => { - this.isUserAllowedToSeeOverview = UserPermission.isUserAllowedToSeeOverview(metadata.user); - this.isUserAllowedToSeeFooter = UserPermission.isUserAllowedToSeeFooter(metadata.user); - }); + + this.subscription.add( + this.service.metadata.pipe(filter(metadata => !!metadata)).subscribe(metadata => { + this.isUserAllowedToSeeOverview = UserPermission.isUserAllowedToSeeOverview(metadata.user); + this.isUserAllowedToSeeFooter = UserPermission.isUserAllowedToSeeFooter(metadata.user); + })); + + this.subscription.add( + this.router.events.pipe(filter(event => event instanceof NavigationEnd)).subscribe((e: NavigationEnd) => { + // Hide footer for history detail views + const segments = e.url.split('/'); + this.isHistoryDetailView = segments.slice(0, -1).includes('history'); + })); } ngOnInit() { @@ -107,5 +119,6 @@ export class AppComponent implements OnInit, OnDestroy { ngOnDestroy() { this.ngUnsubscribe.next(); this.ngUnsubscribe.complete(); + this.subscription.unsubscribe(); } } diff --git a/ui/src/app/app.module.ts b/ui/src/app/app.module.ts index 7113abdf1f7..97e37811918 100644 --- a/ui/src/app/app.module.ts +++ b/ui/src/app/app.module.ts @@ -8,7 +8,6 @@ import { RouteReuseStrategy } from '@angular/router'; 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 { AppRoutingModule } from './app-routing.module'; @@ -29,6 +28,7 @@ import { StatusSingleComponent } from './shared/status/single/status.component'; import { registerTranslateExtension } from './shared/translate.extension'; import { Language, MyTranslateLoader } from './shared/type/language'; import { UserModule } from './user/user.module'; +import { AngularMyDatePickerModule } from '@nodro7/angular-mydatepicker'; @NgModule({ declarations: [ @@ -38,10 +38,6 @@ import { UserModule } from './user/user.module'; StatusSingleComponent, SystemLogComponent, ], - entryComponents: [ - ChartOptionsPopoverComponent, - PickDatePopoverComponent, - ], imports: [ AngularMyDatePickerModule, AppRoutingModule, diff --git a/ui/src/app/edge/edge.component.ts b/ui/src/app/edge/edge.component.ts index 90d88be7e0a..9e4d158846c 100644 --- a/ui/src/app/edge/edge.component.ts +++ b/ui/src/app/edge/edge.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnDestroy, OnInit } from "@angular/core"; import { ActivatedRoute, Router } from "@angular/router"; import { SubscribeEdgesRequest } from "src/app/shared/jsonrpc/request/subscribeEdgesRequest"; diff --git a/ui/src/app/edge/history/Controller/ChannelThreshold/channelThreshold.module.ts b/ui/src/app/edge/history/Controller/ChannelThreshold/channelThreshold.module.ts index 91953858eff..bf6f9d53acf 100644 --- a/ui/src/app/edge/history/Controller/ChannelThreshold/channelThreshold.module.ts +++ b/ui/src/app/edge/history/Controller/ChannelThreshold/channelThreshold.module.ts @@ -10,9 +10,6 @@ import { OverviewComponent } from "./overview/overview"; BrowserModule, SharedModule, ], - entryComponents: [ - FlatComponent, - ], declarations: [ FlatComponent, TotalChartComponent, diff --git a/ui/src/app/edge/history/Controller/ChannelThreshold/chart/totalchart.component.ts b/ui/src/app/edge/history/Controller/ChannelThreshold/chart/totalchart.component.ts index 711bf37fb0c..14d525d0c37 100644 --- a/ui/src/app/edge/history/Controller/ChannelThreshold/chart/totalchart.component.ts +++ b/ui/src/app/edge/history/Controller/ChannelThreshold/chart/totalchart.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { AbstractHistoryChart } from 'src/app/shared/genericComponents/chart/abstracthistorychart'; import { QueryHistoricTimeseriesEnergyResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; diff --git a/ui/src/app/edge/history/Controller/ChannelThreshold/flat/flat.ts b/ui/src/app/edge/history/Controller/ChannelThreshold/flat/flat.ts index a6d91689197..d46cae5a51f 100644 --- a/ui/src/app/edge/history/Controller/ChannelThreshold/flat/flat.ts +++ b/ui/src/app/edge/history/Controller/ChannelThreshold/flat/flat.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; diff --git a/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/chart/chart.ts b/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/chart/chart.ts index e51d62b69b9..84ad2eb878e 100644 --- a/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/chart/chart.ts +++ b/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/chart/chart.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input } from '@angular/core'; import * as Chart from 'chart.js'; import { calculateResolution, ChronoUnit, Resolution } from 'src/app/edge/history/shared'; @@ -14,7 +15,6 @@ export class ChartComponent extends AbstractHistoryChart { @Input() public override component: EdgeConfig.Component; - private TimeOfUseTariffState = TimeOfUseTariffUtils.TimeOfUseTariffState; private currencyLabel: Currency.Label; // Default protected override getChartData(): HistoryUtils.ChartData { @@ -49,21 +49,21 @@ export class ChartComponent extends AbstractHistoryChart { output: (data: HistoryUtils.ChannelData) => { return [{ name: this.translate.instant('Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.BALANCING'), - converter: () => this.getDataset(data, this.TimeOfUseTariffState.Balancing), + converter: () => this.getDataset(data, TimeOfUseTariffUtils.State.Balancing), color: 'rgb(51,102,0)', stack: 1, order: 1, }, { name: this.translate.instant('Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.CHARGE_GRID'), - converter: () => this.getDataset(data, this.TimeOfUseTariffState.ChargeGrid), + converter: () => this.getDataset(data, TimeOfUseTariffUtils.State.ChargeGrid), color: 'rgb(0, 204, 204)', stack: 1, order: 1, }, { name: this.translate.instant('Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.DELAY_DISCHARGE'), - converter: () => this.getDataset(data, this.TimeOfUseTariffState.DelayDischarge), + converter: () => this.getDataset(data, TimeOfUseTariffUtils.State.DelayDischarge), color: 'rgb(0,0,0)', stack: 1, order: 1, diff --git a/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/flat/flat.ts b/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/flat/flat.ts index ea86a49ea0b..eeb4fb4fab2 100644 --- a/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/flat/flat.ts +++ b/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/flat/flat.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input } from '@angular/core'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; diff --git a/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/timeOfUseTariff.module.ts b/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/timeOfUseTariff.module.ts index 6ad0ccbfb00..16ac1004777 100644 --- a/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/timeOfUseTariff.module.ts +++ b/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/timeOfUseTariff.module.ts @@ -10,9 +10,6 @@ import { ChartComponent } from "./chart/chart"; BrowserModule, SharedModule, ], - entryComponents: [ - FlatComponent, - ], declarations: [ FlatComponent, OverviewComponent, diff --git a/ui/src/app/edge/history/abstracthistorychart.ts b/ui/src/app/edge/history/abstracthistorychart.ts index d0b96867714..b225e292d7c 100644 --- a/ui/src/app/edge/history/abstracthistorychart.ts +++ b/ui/src/app/edge/history/abstracthistorychart.ts @@ -1,7 +1,7 @@ +// @ts-strict-ignore import { TranslateService } from '@ngx-translate/core'; import * as Chart from 'chart.js'; import { AbstractHistoryChart as NewAbstractHistoryChart } from 'src/app/shared/genericComponents/chart/abstracthistorychart'; -import { ChartConstants } from 'src/app/shared/genericComponents/chart/chart.constants'; import { JsonrpcResponseError } from 'src/app/shared/jsonrpc/base'; import { QueryHistoricTimeseriesDataRequest } from "src/app/shared/jsonrpc/request/queryHistoricTimeseriesDataRequest"; import { QueryHistoricTimeseriesEnergyPerPeriodRequest } from 'src/app/shared/jsonrpc/request/queryHistoricTimeseriesEnergyPerPeriodRequest'; @@ -412,9 +412,8 @@ export abstract class AbstractHistoryChart { break; } - const scaleOptions: { min: number, max: number, stepSize: number } | null = ChartConstants.getScaleOptions(this.datasets, yAxis); // Only one yAxis defined - options = NewAbstractHistoryChart.getYAxisOptions(options, yAxis, this.translate, 'line', locale, false, scaleOptions); + options = NewAbstractHistoryChart.getYAxisOptions(options, yAxis, this.translate, 'line', locale, false); options.scales.x['stacked'] = true; options.scales[ChartAxis.LEFT]['stacked'] = false; diff --git a/ui/src/app/edge/history/abstracthistorywidget.ts b/ui/src/app/edge/history/abstracthistorywidget.ts index 84b241264cd..8a0e419c4c4 100644 --- a/ui/src/app/edge/history/abstracthistorywidget.ts +++ b/ui/src/app/edge/history/abstracthistorywidget.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { JsonrpcResponseError } from 'src/app/shared/jsonrpc/base'; import { QueryHistoricTimeseriesDataRequest } from 'src/app/shared/jsonrpc/request/queryHistoricTimeseriesDataRequest'; import { QueryHistoricTimeseriesDataResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesDataResponse'; diff --git a/ui/src/app/edge/history/chpsoc/chart.component.ts b/ui/src/app/edge/history/chpsoc/chart.component.ts index b825b5d31f0..aa37afaee2f 100644 --- a/ui/src/app/edge/history/chpsoc/chart.component.ts +++ b/ui/src/app/edge/history/chpsoc/chart.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; diff --git a/ui/src/app/edge/history/chpsoc/chpsocchartoverview/chpsocchartoverview.component.ts b/ui/src/app/edge/history/chpsoc/chpsocchartoverview/chpsocchartoverview.component.ts index c55484dfa5f..e5b740eccec 100644 --- a/ui/src/app/edge/history/chpsoc/chpsocchartoverview/chpsocchartoverview.component.ts +++ b/ui/src/app/edge/history/chpsoc/chpsocchartoverview/chpsocchartoverview.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Edge, EdgeConfig, Service } from '../../../../shared/shared'; diff --git a/ui/src/app/edge/history/chpsoc/widget.component.html b/ui/src/app/edge/history/chpsoc/widget.component.html index 52a74471a19..5c3e6d94f61 100644 --- a/ui/src/app/edge/history/chpsoc/widget.component.html +++ b/ui/src/app/edge/history/chpsoc/widget.component.html @@ -1,4 +1,4 @@ - + {{ component.alias }} @@ -14,4 +14,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/history/chpsoc/widget.component.ts b/ui/src/app/edge/history/chpsoc/widget.component.ts index 45bdc7a995e..090b3ed1da8 100644 --- a/ui/src/app/edge/history/chpsoc/widget.component.ts +++ b/ui/src/app/edge/history/chpsoc/widget.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { QueryHistoricTimeseriesDataResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesDataResponse'; diff --git a/ui/src/app/edge/history/common/autarchy/Autarchy.ts b/ui/src/app/edge/history/common/autarchy/Autarchy.ts index 03506c4004d..1407ff291e6 100644 --- a/ui/src/app/edge/history/common/autarchy/Autarchy.ts +++ b/ui/src/app/edge/history/common/autarchy/Autarchy.ts @@ -10,9 +10,6 @@ import { OverviewComponent } from './overview/overview'; BrowserModule, SharedModule, ], - entryComponents: [ - FlatComponent, - ], declarations: [ FlatComponent, ChartComponent, 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 be1dc505d14..d6896069cee 100644 --- a/ui/src/app/edge/history/common/autarchy/chart/chart.ts +++ b/ui/src/app/edge/history/common/autarchy/chart/chart.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { AbstractHistoryChart } from 'src/app/shared/genericComponents/chart/abstracthistorychart'; import { QueryHistoricTimeseriesEnergyResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; diff --git a/ui/src/app/edge/history/common/autarchy/flat/flat.ts b/ui/src/app/edge/history/common/autarchy/flat/flat.ts index 8d167e1ef34..2cfb7757b8e 100644 --- a/ui/src/app/edge/history/common/autarchy/flat/flat.ts +++ b/ui/src/app/edge/history/common/autarchy/flat/flat.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; import { ChannelAddress, CurrentData, Utils } from '../../../../../shared/shared'; diff --git a/ui/src/app/edge/history/common/consumption/Consumption.ts b/ui/src/app/edge/history/common/consumption/Consumption.ts index f98ecbae967..bc0ccaadea4 100644 --- a/ui/src/app/edge/history/common/consumption/Consumption.ts +++ b/ui/src/app/edge/history/common/consumption/Consumption.ts @@ -11,9 +11,6 @@ import { OverviewComponent } from './overview/overview'; BrowserModule, SharedModule, ], - entryComponents: [ - FlatComponent, - ], declarations: [ FlatComponent, ChartComponent, diff --git a/ui/src/app/edge/history/common/consumption/chart/chart.spec.ts b/ui/src/app/edge/history/common/consumption/chart/chart.spec.ts index db26031999e..9e124f57aed 100644 --- a/ui/src/app/edge/history/common/consumption/chart/chart.spec.ts +++ b/ui/src/app/edge/history/common/consumption/chart/chart.spec.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { DummyConfig } from "src/app/shared/edge/edgeconfig.spec"; import { OeTester } from "src/app/shared/genericComponents/shared/testing/common"; @@ -31,9 +32,8 @@ describe('History Consumption', () => { DATA('Sonstiger: 63,3 kWh', [null, null, null, 0.5658045977011494, 0.3871815181518151, 0.561425925925926, 0.5732169811320755, 0.5658080808080809, 0.5879803921568627, 0.5842389380530973, 0.6074818181818182, 0.6050275229357799, 0.5956407766990292, 0.6025294117647059, 0.5781684210526317, 0.5816813186813187, 0.6495166666666666, 0.5602999999999999, 0.56703738317757, 0.6297672413793104, 0.5688613861386138, 0.5896039603960396, 0.5245090909090909, 0.5093300330033004, 0.6177196261682243, 0.608122641509434, 0.60278, 0.6508155339805825, 0.6058877551020408, 0.5943904761904762, 0.57636, 0.5650660377358491, 0.587495145631068, 0.626375, 0.6819428571428572, 0.6504629629629629, 0.6313738317757009, 0.68725, 0.5602452830188679, 0.5278952380952382, 0.6202222222222221, 0.4016355140186916, 0.5878130841121496, 0.604, 0.616295918367347, 0.5789405940594059, 0.5943396226415094, 0.6481078431372549, null, null, null, 0.5652183908045977, 0.5736481481481481, 0.5365462962962964, 0.558081081081081, 0.5747543859649124, 0.5743557692307693, 0.5969047619047619, 0.6540720720720721, 0.5018766666666667, 0.6128045977011494, 0.6361100000000001, 0.6137948717948718, 0.5388857142857142, 0.5371157894736842, 0.5511634615384615, 0.5588809523809524, 0.5591222222222223, 0.6185576923076923, 0.6543287671232877, 0.6160574712643678, 0.5889056603773585, 0.5787096774193549, 0.583036036036036, 0.572570093457944, 0.5952631578947368, 0.7450888888888888, 0.7073990610328639, -1.452950549450549, 2.233161450571287, 1.1458434343434352, 1.2180771929824568, 0.9178416666666669, 0.9020510752688171, 1.3458171717171723, 1.1460410714285718, 0.9853455165691996, 1.189936077481839, -1.4153224202237875, 0.6774427860696518, 0.9827305699481865, 0.8582012987012987, 0.7678924050632912, 0.761950495049505, 0.6821319796954315, 0.5954198473282443, 0.7021286549707602, 0.7309484536082475, 0.739, 0.730572864321608, 0.7547467532467532, 0.657373417721519, 0.6409480519480519, 0.6698156424581005, 0.7876280991735537, 2.931229357798165, 1.9542808988764044, 0.7775346534653466, 1.098538860103627, 1.2441524390243903, 2.9194913793103447, 2.9874188034188034, 3.4140294117647056, 1.2151999999999998, 2.7142824427480914, 2.6578703703703703, 2.8738923076923077, 4.013462078651685, 3.791560606060606, 2.845578947368421, 1.7741875, 0.89646, 1.2468691588785048, 1.0760386740331491, 0.8393491124260355, 1.194960199004975, 1.0562878787878787, 3.133, 3.78845625, 1.288096153846154, 3.4541666666666666, 2.0936967871485943, 2.384391025641026, 1.6707888888888887, 1.5589767441860465, 2.8620799999999997, 2.3241241379310345, 1.9640169491525423, 1.8084, 3.4660503597122303, 2.2974397590361444, 2.5300493827160495, 2.439358490566038, 2.0079060773480664, 1.7515, 1.4163181818181818, 1.4292298850574712, 1.4520298507462688, 1.4897204301075269, 1.6330952380952382, 1.8262928571428572, 1.6101904761904762, 1.680929292929293, 2.881743119266055, 3.5851634615384613, 3.6891666666666665, 3.6573402777777777, 3.6435348837209305, 3.7148645833333336, 3.731375, 3.74479, 3.6362363636363635, 4.273113924050633, 3.4461999999999997, 3.5387142857142857, 3.7906065573770493, 3.5276750000000003, 3.4676712328767123, 3.5595, 3.7982, 5.460666666666667, 1.3094406779661016, 1.5357454545454545, 3.4238260869565216, 3.3823636363636367, 3.4006315789473684, 2.95075, 3.386731707317073, 2.506, 1.4471666666666667, 1.4425999999999999, 0.946, 0.9425789473684211, 0.9507142857142856, 0.947, 0.9762857142857143, 1.7862857142857143, 1.5135777777777777, 1.4995625, 1.338, 1.3278125, 1.2739175257731958, 1.4387457627118645, 1.2484186046511627, 1.2866693548387098, 1.2848934911242604, 1.2237952755905512, 0.74809375, 0.8717684210526315, 0.8445338983050847, 0.7916749999999999, 0.8041932773109244, 0.7303737373737375, 0.7055024390243902, 0.6872407407407407, 0.6909939759036144, 0.751, 0.765139344262295, 0.686871794871795, 0.6697434210526315, 1.7678091603053436, 0.7246764705882353, 0.7482772277227723, 0.9401142857142858, 0.750368, 1.3660232558139536, 0.7274137931034482, 0.710719512195122, 0.6898555555555557, 0.739453488372093, 0.817875, 0.7304303797468354, 0.7355890410958904, 0.738225806451613, 1.906921739130435, 2.290785714285714, 1.2075072463768115, 1.1675890410958905, 1.2290208333333332, 1.1923777777777778, 1.2088717948717949, 1.367715909090909, 1.284223300970874, 1.1631739130434782, 1.15253, 1.1614545454545455, 1.2195681818181818, 1.183752808988764, 1.197778947368421, 1.2338888888888888, 1.275070588235294, 1.235554054054054, 1.20783908045977, 1.2416184210526318, 1.159042735042735, 1.1382948717948718, 1.1069915966386554, 1.1714504504504506, 1.223822429906542, 1.1221696428571428, 1.018892857142857, 0.9818285714285714, 0.9988363636363636, 0.8434776785714284, 1.4379482009925546, 1.4043499341238475, 1.7165029190992493, 1.781351488095238, 1.8585528255528247, 3.6707709585574175, 4.427144379844961, 4.301046195652174, 4.194778846153845, 4.150229357798166, 4.055816642120766, 3.976974967061925, 2.711485714285714, 1.0600519480519486, 0.954382608695652, 0.7914855072463762, 0.9272300420168067, 0.28519157088122604, 0.8123142857142857, 0.8095892857142857, 0.8664786324786324, 0.8778319327731092, 0.8108141592920354, 0.8157121212121212, 0.7706470588235294, 0.7633157894736842, 0.7815151515151515, 0.8075833333333333, 0.824743119266055, 0.8762151898734176, 0.882424, 0.7502213114754098, 0.675954954954955, 0.6371222222222223]), ], labels: LABELS(History.DAY.dataChannelWithValues.result.timestamps), - options: OeTester.ChartOptions.LINE_CHART_OPTIONS('hour', 'line', { - ["left"]: { scale: { min: -2, max: 11 }, ticks: { stepSize: 3.25 } }, - }), + options: OeTester.ChartOptions.LINE_CHART_OPTIONS('hour', 'line', {}, + ), }, }); } @@ -50,9 +50,7 @@ describe('History Consumption', () => { DATA('Sonstiger: 97,1 kWh', [0.6360308446701046, 0.9095864441102458, 0.7335808811402847, 0.5718131699718612, 0.9616446485934361, 0.6381720132750589, 1.02619037791046, 1.0145027809280902, 0.6390464755453447, 0.7096512022948386, 0.819995628581571, 0.935642813016216, 0.5254472085206601, 1.8851739940941776, 0.863444783197832, 1.1921009009810684, 0.5202376219567795, 0.7444045122530605, 0.901856453684574, 0.8104459244359407, 1.0830737950562592, 0.8714288985355628, 0.7780086316183336, 0.9590122781645534, 0.58627825521263, 0.8413148987905428, 0.8796668002158831, 0.6461976914860288, 0.8006733468796897, 0.8250297170962498, 0.825867009418173, 0.8407590098644301, 1.2782520162083928, 0.9299547986301717, 1.100431849409396, 0.881695115377627, -3.0801277220264014, 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]), ], labels: LABELS(History.WEEK.dataChannelWithValues.result.timestamps), - options: OeTester.ChartOptions.LINE_CHART_OPTIONS('day', 'line', { - ["left"]: { scale: { min: -4, max: 5 }, ticks: { stepSize: 2.25 } }, - }), + options: OeTester.ChartOptions.LINE_CHART_OPTIONS('day', 'line', {}), }, }); } @@ -69,9 +67,7 @@ describe('History Consumption', () => { DATA('Sonstiger: 683,3 kWh', [1.1707523832922395, 0.941219247423001, 0.9813072961027226, 0.9147731344893865, 0.9179723719850451, 1.0221279641612842, 0.966452725206484, 0.9473972354717355, 0.9621558239123786, 1.0389565290773752, 0.719602808727641, 0.7164739453418082, 0.8312551527306125, 1.0513294309882544, 1.0642356695090618, 1.064549904209455, 0.8827148020023398, 1.0886724659066331, 0.9617007570391821, 1.2024244259088868, 1.4752269957477093, 1.149323439144603, 1.2039544333297325, 1.0275239776315197, 0.9588534351033258, 1.0445672257542986, 1.1028960998629487, 0.9010854319660326, 0.8581094263176695, null, null]), ], labels: LABELS(History.MONTH.energyPerPeriodChannelWithValues.result.timestamps), - options: OeTester.ChartOptions.BAR_CHART_OPTIONS('day', 'bar', { - ["left"]: { scale: { min: 0, max: 3 }, ticks: { stepSize: 0.75 } }, - }), + options: OeTester.ChartOptions.BAR_CHART_OPTIONS('day', 'bar', {}), }, }); } @@ -88,9 +84,7 @@ describe('History Consumption', () => { DATA('Sonstiger: 10.883,9 kWh', [1275.767, 1390.6460000000002, 1480.519, 1565.359, 1387.424, 1027.67, 1412.9189999999999, 1344.913, 0, 0, 0, 0]), ], labels: LABELS(History.YEAR.energyPerPeriodChannelWithValues.result.timestamps), - options: OeTester.ChartOptions.BAR_CHART_OPTIONS('month', 'bar', { - ["left"]: { scale: { min: 0, max: 2307 }, ticks: { stepSize: 576.75 } }, - }), + options: OeTester.ChartOptions.BAR_CHART_OPTIONS('month', 'bar', {}), }, }); } diff --git a/ui/src/app/edge/history/common/consumption/chart/chart.ts b/ui/src/app/edge/history/common/consumption/chart/chart.ts index e40ad5ff702..13e21ec841c 100644 --- a/ui/src/app/edge/history/common/consumption/chart/chart.ts +++ b/ui/src/app/edge/history/common/consumption/chart/chart.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { AbstractHistoryChart } from 'src/app/shared/genericComponents/chart/abstracthistorychart'; diff --git a/ui/src/app/edge/history/common/consumption/flat/flat.ts b/ui/src/app/edge/history/common/consumption/flat/flat.ts index ddfde940df7..947b0c7c2c8 100644 --- a/ui/src/app/edge/history/common/consumption/flat/flat.ts +++ b/ui/src/app/edge/history/common/consumption/flat/flat.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; import { ChannelAddress, CurrentData, EdgeConfig } from '../../../../../shared/shared'; 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 9d76eb3cc97..632d08a1291 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 @@ -14,13 +14,13 @@ export namespace History { "responsive": true, "maintainAspectRatio": false, "elements": { "point": { "radius": 0, "hitRadius": 0, "hoverRadius": 0 }, "line": { "stepped": false, "fill": true } }, "datasets": { "bar": {}, "line": {} }, "plugins": { "colors": { "enabled": false }, "legend": { "display": true, "position": "bottom", "labels": { "color": '' } }, "tooltip": { "intersect": false, "mode": "index", "callbacks": {} } }, "scales": { "x": { "stacked": true, "offset": false, "type": "time", "ticks": { "source": "auto", "maxTicksLimit": 31 }, "bounds": "ticks", "adapters": { "date": { "locale": { "code": "de", "formatLong": {}, "localize": {}, "match": {}, "options": { "weekStartsOn": 1, "firstWeekContainsDate": 4 } } } }, "time": { "unit": period as TimeUnit, "displayFormats": { "datetime": "yyyy-MM-dd HH:mm:ss", "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" } } }, "left": { - ...options["left"].scale, ...(chartType === 'line' ? { stacked: false } : {}), "title": { "text": "kW", "display": true, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, - "ticks": { ...options["left"].ticks, "color": '', "padding": 5, "maxTicksLimit": ChartConstants.NUMBER_OF_Y_AXIS_TICKS }, + ...options["left"]?.scale, ...(chartType === 'line' ? { stacked: false } : {}), "title": { "text": "kW", "display": true, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, + "ticks": { ...options["left"]?.ticks, "color": '', "padding": 5, "maxTicksLimit": ChartConstants.NUMBER_OF_Y_AXIS_TICKS }, }, "right": { - ...options["right"].scale, ...(chartType === 'line' ? { stacked: false } : {}), "beginAtZero": true, "max": 100, "min": 0, "type": "linear", "title": { "text": "%", "display": true, "font": { "size": 11 }, "padding": 5 }, "position": "right", "grid": { "display": false }, + ...options["right"]?.scale, ...(chartType === 'line' ? { stacked: false } : {}), "beginAtZero": true, "max": 100, "min": 0, "type": "linear", "title": { "text": "%", "display": true, "font": { "size": 11 }, "padding": 5 }, "position": "right", "grid": { "display": false }, "ticks": { - ...options["right"].ticks, + ...options["right"]?.ticks, "color": '', "padding": 5, "maxTicksLimit": ChartConstants.NUMBER_OF_Y_AXIS_TICKS, @@ -35,9 +35,9 @@ export namespace History { "responsive": true, "maintainAspectRatio": false, "elements": { "point": { "radius": 0, "hitRadius": 0, "hoverRadius": 0 }, "line": { "stepped": false, "fill": true } }, "datasets": { "bar": { "barPercentage": 1 }, "line": {} }, "plugins": { "colors": { "enabled": false }, "legend": { "display": true, "position": "bottom", "labels": { "color": '' } }, "tooltip": { "intersect": false, "mode": "x", "callbacks": {} } }, "scales": { "x": { "stacked": true, "offset": true, "type": "time", "ticks": { "source": "auto", "maxTicksLimit": 31 }, "bounds": "ticks", "adapters": { "date": { "locale": { "code": "de", "formatLong": {}, "localize": {}, "match": {}, "options": { "weekStartsOn": 1, "firstWeekContainsDate": 4 } } } }, "time": { "unit": period as TimeUnit, "displayFormats": { "datetime": "yyyy-MM-dd HH:mm:ss", "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" } } }, "left": { - ...options["left"].scale, ...(chartType === 'line' ? { stacked: false } : {}), "title": { "text": "kWh", "display": true, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, + ...options["left"]?.scale, ...(chartType === 'line' ? { stacked: false } : {}), "title": { "text": "kWh", "display": true, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, "ticks": { - ...options["left"].ticks, + ...options["left"]?.ticks, "color": '', "padding": 5, "maxTicksLimit": ChartConstants.NUMBER_OF_Y_AXIS_TICKS, 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 f2fde360c3e..6520137afc5 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,3 +1,4 @@ +// @ts-strict-ignore import { History } from "src/app/edge/history/common/energy/chart/channels.spec"; import { DummyConfig } from "src/app/shared/edge/edgeconfig.spec"; @@ -33,7 +34,7 @@ describe('History EnergyMonitor', () => { ], labels: LABELS(History.DAY.dataChannelWithValues.result.timestamps), options: History.LINE_CHART_OPTIONS('hour', 'line', { - ["left"]: { scale: { min: 0, max: 7 }, ticks: { stepSize: 1.75 } }, ["right"]: { scale: { min: 0, max: 1003 }, ticks: { stepSize: 25 } }, + ['right']: { ticks: { stepSize: 20 }, scale: null }, }), }, }); @@ -54,9 +55,7 @@ describe('History EnergyMonitor', () => { DATA('Ladezustand', History.WEEK.dataChannelWithValues.result.data['_sum/EssSoc']), ], labels: LABELS(History.WEEK.dataChannelWithValues.result.timestamps), - options: History.LINE_CHART_OPTIONS('day', 'line', { - ["left"]: { scale: { min: 0, max: 9 }, ticks: { stepSize: 2.25 } }, ["right"]: { scale: { min: 0, max: 1003 }, ticks: { stepSize: 25 } }, - }), + options: History.LINE_CHART_OPTIONS('day', 'line', { ['right']: { ticks: { stepSize: 20 }, scale: null } }), }, }); } @@ -79,9 +78,7 @@ describe('History EnergyMonitor', () => { 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', { - ["left"]: { scale: { min: 0, max: 1579 }, ticks: { stepSize: 394.75 } }, - }), + options: History.BAR_CHART_OPTIONS('day', 'bar', {}), }, }); } @@ -104,9 +101,7 @@ describe('History EnergyMonitor', () => { 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', { - ["left"]: { scale: { min: 0, max: 22491 }, ticks: { stepSize: 5622.75 } }, - }), + options: History.BAR_CHART_OPTIONS('month', 'bar', {}), }, }); } @@ -119,7 +114,6 @@ describe('History EnergyMonitor', () => { data: [], labels: LABELS(History.YEAR.energyPerPeriodChannelWithValues.result.timestamps), options: History.BAR_CHART_OPTIONS('month', 'bar', { - ["left"]: { scale: {}, ticks: {} }, }), }, }); @@ -143,9 +137,7 @@ describe('History EnergyMonitor', () => { 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', { - ["left"]: { scale: { min: 0, max: 12839 }, ticks: { stepSize: 3209.75 } }, ["right"]: { scale: { min: 0, max: 1003 }, ticks: { stepSize: 25 } }, - }), + options: History.BAR_CHART_OPTIONS('month', 'bar', {}), }, }); } @@ -165,9 +157,7 @@ describe('History EnergyMonitor', () => { 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', { - ["left"]: { scale: { min: 0, max: 12839 }, ticks: { stepSize: 3209.75 } }, - }), + options: History.BAR_CHART_OPTIONS('month', 'bar', {}), }, }); } @@ -187,9 +177,7 @@ describe('History EnergyMonitor', () => { 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', { - ["left"]: { scale: { min: 0, max: 11635 }, ticks: { stepSize: 2908.75 } }, - }), + options: History.BAR_CHART_OPTIONS('month', 'bar', {}), }, }); } 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 2e3a22cc496..8e65cb0a53f 100644 --- a/ui/src/app/edge/history/common/energy/chart/chart.ts +++ b/ui/src/app/edge/history/common/energy/chart/chart.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { AbstractHistoryChart } from 'src/app/shared/genericComponents/chart/abstracthistorychart'; diff --git a/ui/src/app/edge/history/common/energy/energy.ts b/ui/src/app/edge/history/common/energy/energy.ts index 6b7704256e2..fe07c430784 100644 --- a/ui/src/app/edge/history/common/energy/energy.ts +++ b/ui/src/app/edge/history/common/energy/energy.ts @@ -10,10 +10,6 @@ import { FlatComponent } from './flat/flat'; BrowserModule, SharedModule, ], - entryComponents: [ - FlatComponent, - ChartComponent, - ], declarations: [ FlatComponent, ChartComponent, diff --git a/ui/src/app/edge/history/common/energy/flat/flat.ts b/ui/src/app/edge/history/common/energy/flat/flat.ts index 2ff36ee1489..f69ce558271 100644 --- a/ui/src/app/edge/history/common/energy/flat/flat.ts +++ b/ui/src/app/edge/history/common/energy/flat/flat.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; import { ChannelAddress, CurrentData, Utils } from '../../../../../shared/shared'; diff --git a/ui/src/app/edge/history/common/grid/chart/chart.spec.ts b/ui/src/app/edge/history/common/grid/chart/chart.spec.ts index e44f5fc6a5c..d0af9ae56dd 100644 --- a/ui/src/app/edge/history/common/grid/chart/chart.spec.ts +++ b/ui/src/app/edge/history/common/grid/chart/chart.spec.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { History } from "src/app/edge/history/common/energy/chart/channels.spec"; import { DummyConfig } from "src/app/shared/edge/edgeconfig.spec"; import { OeTester } from "src/app/shared/genericComponents/shared/testing/common"; @@ -27,10 +28,7 @@ describe('History Grid', () => { DATA('Bezug: 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]), ], labels: LABELS(History.DAY.dataChannelWithValues.result.timestamps), - options: OeTester.ChartOptions.LINE_CHART_OPTIONS('hour', 'line', { - ["left"]: { scale: { min: 0, max: 7 }, ticks: { stepSize: 1.75 } }, - }, - ), + options: OeTester.ChartOptions.LINE_CHART_OPTIONS('hour', 'line', {}), }, }, false); } @@ -44,11 +42,8 @@ describe('History Grid', () => { DATA('Bezug: 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]), ], labels: LABELS(History.WEEK.dataChannelWithValues.result.timestamps), - options: OeTester.ChartOptions.LINE_CHART_OPTIONS('day', 'line', { - ["left"]: { scale: { min: 0, max: 7 }, ticks: { stepSize: 1.75 } }, - }), + options: OeTester.ChartOptions.LINE_CHART_OPTIONS('day', 'line', {}), }, - }, false); } { @@ -61,9 +56,7 @@ describe('History Grid', () => { DATA('Bezug: 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]), ], labels: LABELS(History.MONTH.energyPerPeriodChannelWithValues.result.timestamps), - options: OeTester.ChartOptions.BAR_CHART_OPTIONS('day', 'bar', { - ["left"]: { scale: { min: 0, max: 1003 }, ticks: { stepSize: 250.75 } }, - }), + options: OeTester.ChartOptions.BAR_CHART_OPTIONS('day', 'bar', {}), }, }, false); @@ -78,9 +71,7 @@ describe('History Grid', () => { DATA('Bezug: 23.209 kWh', [9829, 4812, 2915, 2036, 2712, 773, 94, null, null, null, null, null]), ], labels: LABELS(History.YEAR.energyPerPeriodChannelWithValues.result.timestamps), - options: OeTester.ChartOptions.BAR_CHART_OPTIONS('month', 'bar', { - ["left"]: { scale: { min: 0, max: 12839 }, ticks: { stepSize: 3209.75 } }, - }), + options: OeTester.ChartOptions.BAR_CHART_OPTIONS('month', 'bar', {}), }, }, false); } diff --git a/ui/src/app/edge/history/common/grid/chart/chart.ts b/ui/src/app/edge/history/common/grid/chart/chart.ts index fd5507e76a7..c8e5fc00b15 100644 --- a/ui/src/app/edge/history/common/grid/chart/chart.ts +++ b/ui/src/app/edge/history/common/grid/chart/chart.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { AbstractHistoryChart } from 'src/app/shared/genericComponents/chart/abstracthistorychart'; diff --git a/ui/src/app/edge/history/common/grid/grid.ts b/ui/src/app/edge/history/common/grid/grid.ts index 8971a15d9f0..85814e76c9f 100644 --- a/ui/src/app/edge/history/common/grid/grid.ts +++ b/ui/src/app/edge/history/common/grid/grid.ts @@ -11,9 +11,6 @@ import { OverviewComponent } from './overview/overview'; BrowserModule, SharedModule, ], - entryComponents: [ - FlatComponent, - ], declarations: [ FlatComponent, ChartComponent, 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 83f1b903235..593e4d4bc19 100644 --- a/ui/src/app/edge/history/common/production/chart/chargerChart.ts +++ b/ui/src/app/edge/history/common/production/chart/chargerChart.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { AbstractHistoryChart } from 'src/app/shared/genericComponents/chart/abstracthistorychart'; import { QueryHistoricTimeseriesEnergyResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; 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 798f886c6c4..baf66d6a040 100644 --- a/ui/src/app/edge/history/common/production/chart/productionMeterChart.ts +++ b/ui/src/app/edge/history/common/production/chart/productionMeterChart.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { AbstractHistoryChart } from 'src/app/shared/genericComponents/chart/abstracthistorychart'; import { QueryHistoricTimeseriesEnergyResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; 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 af06fd9527c..c788ebf8964 100644 --- a/ui/src/app/edge/history/common/production/chart/totalAcChart.ts +++ b/ui/src/app/edge/history/common/production/chart/totalAcChart.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { AbstractHistoryChart } from 'src/app/shared/genericComponents/chart/abstracthistorychart'; import { QueryHistoricTimeseriesEnergyResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; 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 2cb1514eb6a..0f2deef3cc5 100644 --- a/ui/src/app/edge/history/common/production/chart/totalChart.ts +++ b/ui/src/app/edge/history/common/production/chart/totalChart.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { AbstractHistoryChart } from 'src/app/shared/genericComponents/chart/abstracthistorychart'; import { QueryHistoricTimeseriesEnergyResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; 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 7e6a6764159..a9b87962b9a 100644 --- a/ui/src/app/edge/history/common/production/chart/totalDcChart.ts +++ b/ui/src/app/edge/history/common/production/chart/totalDcChart.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { AbstractHistoryChart } from 'src/app/shared/genericComponents/chart/abstracthistorychart'; import { QueryHistoricTimeseriesEnergyResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; diff --git a/ui/src/app/edge/history/common/production/overview/overview.html b/ui/src/app/edge/history/common/production/overview/overview.html index 36b566df443..c4706da4aaf 100644 --- a/ui/src/app/edge/history/common/production/overview/overview.html +++ b/ui/src/app/edge/history/common/production/overview/overview.html @@ -33,4 +33,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/history/common/production/production.ts b/ui/src/app/edge/history/common/production/production.ts index 038dc44c818..890070a3e15 100644 --- a/ui/src/app/edge/history/common/production/production.ts +++ b/ui/src/app/edge/history/common/production/production.ts @@ -15,15 +15,6 @@ import { OverviewComponent } from './overview/overview'; BrowserModule, SharedModule, ], - entryComponents: [ - FlatComponent, - OverviewComponent, - ProductionMeterChartComponent, - TotalDcChartComponent, - TotalAcChartComponent, - TotalChartComponent, - ChargerChartComponent, - ], declarations: [ FlatComponent, OverviewComponent, diff --git a/ui/src/app/edge/history/common/selfconsumption/SelfConsumption.ts b/ui/src/app/edge/history/common/selfconsumption/SelfConsumption.ts index 49ece21cfab..e67a47ad931 100644 --- a/ui/src/app/edge/history/common/selfconsumption/SelfConsumption.ts +++ b/ui/src/app/edge/history/common/selfconsumption/SelfConsumption.ts @@ -10,9 +10,6 @@ import { OverviewComponent } from "./overview/overview"; BrowserModule, SharedModule, ], - entryComponents: [ - FlatComponent, - ], declarations: [ FlatComponent, ChartComponent, 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 af0c382d9ed..0974e5f5bfe 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,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { AbstractHistoryChart } from 'src/app/shared/genericComponents/chart/abstracthistorychart'; import { QueryHistoricTimeseriesEnergyResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; diff --git a/ui/src/app/edge/history/common/selfconsumption/flat/flat.ts b/ui/src/app/edge/history/common/selfconsumption/flat/flat.ts index 91598222c82..4bcd1ba6b0b 100644 --- a/ui/src/app/edge/history/common/selfconsumption/flat/flat.ts +++ b/ui/src/app/edge/history/common/selfconsumption/flat/flat.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; import { CurrentData, Utils, ChannelAddress } from 'src/app/shared/shared'; diff --git a/ui/src/app/edge/history/delayedselltogrid/chart.component.ts b/ui/src/app/edge/history/delayedselltogrid/chart.component.ts index e6f40fe98a9..e51dd2b147c 100644 --- a/ui/src/app/edge/history/delayedselltogrid/chart.component.ts +++ b/ui/src/app/edge/history/delayedselltogrid/chart.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; diff --git a/ui/src/app/edge/history/delayedselltogrid/symmetricpeakshavingchartoverview/delayedselltogridchartoverview.component.ts b/ui/src/app/edge/history/delayedselltogrid/symmetricpeakshavingchartoverview/delayedselltogridchartoverview.component.ts index 715208abce1..fa597ea5577 100644 --- a/ui/src/app/edge/history/delayedselltogrid/symmetricpeakshavingchartoverview/delayedselltogridchartoverview.component.ts +++ b/ui/src/app/edge/history/delayedselltogrid/symmetricpeakshavingchartoverview/delayedselltogridchartoverview.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Edge, EdgeConfig, Service } from '../../../../shared/shared'; diff --git a/ui/src/app/edge/history/delayedselltogrid/widget.component.ts b/ui/src/app/edge/history/delayedselltogrid/widget.component.ts index 7e56e114434..3b4e3442ca5 100644 --- a/ui/src/app/edge/history/delayedselltogrid/widget.component.ts +++ b/ui/src/app/edge/history/delayedselltogrid/widget.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { ActivatedRoute } from '@angular/router'; import { Component, Input, OnInit } from '@angular/core'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; diff --git a/ui/src/app/edge/history/fixdigitaloutput/fixdigitaloutputchartoverview/fixdigitaloutputchartoverview.component.ts b/ui/src/app/edge/history/fixdigitaloutput/fixdigitaloutputchartoverview/fixdigitaloutputchartoverview.component.ts index 623410cef2e..d62eb1766cd 100644 --- a/ui/src/app/edge/history/fixdigitaloutput/fixdigitaloutputchartoverview/fixdigitaloutputchartoverview.component.ts +++ b/ui/src/app/edge/history/fixdigitaloutput/fixdigitaloutputchartoverview/fixdigitaloutputchartoverview.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Edge, EdgeConfig, Service, Utils } from '../../../../shared/shared'; diff --git a/ui/src/app/edge/history/fixdigitaloutput/singlechart.component.ts b/ui/src/app/edge/history/fixdigitaloutput/singlechart.component.ts index 136004e5499..7dba882fa89 100644 --- a/ui/src/app/edge/history/fixdigitaloutput/singlechart.component.ts +++ b/ui/src/app/edge/history/fixdigitaloutput/singlechart.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; diff --git a/ui/src/app/edge/history/fixdigitaloutput/totalchart.component.ts b/ui/src/app/edge/history/fixdigitaloutput/totalchart.component.ts index 3f678bf5ccc..ede98a6e38b 100644 --- a/ui/src/app/edge/history/fixdigitaloutput/totalchart.component.ts +++ b/ui/src/app/edge/history/fixdigitaloutput/totalchart.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; diff --git a/ui/src/app/edge/history/fixdigitaloutput/widget.component.ts b/ui/src/app/edge/history/fixdigitaloutput/widget.component.ts index 8716004c0fb..f4990c751fb 100644 --- a/ui/src/app/edge/history/fixdigitaloutput/widget.component.ts +++ b/ui/src/app/edge/history/fixdigitaloutput/widget.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { QueryHistoricTimeseriesDataResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesDataResponse'; diff --git a/ui/src/app/edge/history/grid/chart.component.ts b/ui/src/app/edge/history/grid/chart.component.ts index 43cc204ee76..285c8d4961e 100644 --- a/ui/src/app/edge/history/grid/chart.component.ts +++ b/ui/src/app/edge/history/grid/chart.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { formatNumber } from '@angular/common'; import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; diff --git a/ui/src/app/edge/history/gridoptimizedcharge/chart.component.ts b/ui/src/app/edge/history/gridoptimizedcharge/chart.component.ts index 06743192d12..828617a2266 100644 --- a/ui/src/app/edge/history/gridoptimizedcharge/chart.component.ts +++ b/ui/src/app/edge/history/gridoptimizedcharge/chart.component.ts @@ -1,7 +1,7 @@ +// @ts-strict-ignore import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; -import { ChartConstants } from 'src/app/shared/genericComponents/chart/chart.constants'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; import { ChartAxis, HistoryUtils, YAxisTitle } from 'src/app/shared/service/utils'; @@ -159,9 +159,10 @@ export class GridOptimizedChargeChartComponent extends AbstractHistoryChart impl label: this.translate.instant('General.soc'), data: socData, hidden: false, - yAxisID: 'yAxis2', + yAxisID: ChartAxis.RIGHT, position: 'right', borderDash: [10, 10], + unit: YAxisTitle.PERCENTAGE, }); this.colors.push({ backgroundColor: 'rgba(189, 195, 199,0.05)', @@ -190,20 +191,14 @@ export class GridOptimizedChargeChartComponent extends AbstractHistoryChart impl } private applyControllerSpecificOptions() { - const yAxisRight: HistoryUtils.yAxes = { - unit: YAxisTitle.PERCENTAGE, - position: 'right', - yAxisId: ChartAxis.RIGHT, - displayGrid: false, - }; + const yAxisRight: HistoryUtils.yAxes = { unit: YAxisTitle.PERCENTAGE, position: 'right', yAxisId: ChartAxis.RIGHT, displayGrid: false }; + const yAxisLeft: HistoryUtils.yAxes = { position: 'left', unit: YAxisTitle.ENERGY, yAxisId: ChartAxis.LEFT }; const locale = this.service.translate.currentLang; const showYAxisTitle = true; - const yAxisLeft: HistoryUtils.yAxes = { position: 'left', unit: YAxisTitle.ENERGY, yAxisId: ChartAxis.LEFT }; [yAxisRight, yAxisLeft].forEach(yAxis => { - const scaleOptions = ChartConstants.getScaleOptions(this.datasets, yAxis); - this.options = NewAbstractHistoryChart.getYAxisOptions(this.options, yAxis, this.translate, 'line', locale, showYAxisTitle, scaleOptions); + this.options = NewAbstractHistoryChart.getYAxisOptions(this.options, yAxis, this.translate, 'line', locale, showYAxisTitle); }); this.datasets = this.datasets.map((el, index, arr) => { diff --git a/ui/src/app/edge/history/gridoptimizedcharge/gridoptimizedchargechartoverview/gridoptimizedchargechartoverview.component.ts b/ui/src/app/edge/history/gridoptimizedcharge/gridoptimizedchargechartoverview/gridoptimizedchargechartoverview.component.ts index 081dbb9895c..0f2dc33a6aa 100644 --- a/ui/src/app/edge/history/gridoptimizedcharge/gridoptimizedchargechartoverview/gridoptimizedchargechartoverview.component.ts +++ b/ui/src/app/edge/history/gridoptimizedcharge/gridoptimizedchargechartoverview/gridoptimizedchargechartoverview.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Edge, EdgeConfig, Service } from '../../../../shared/shared'; diff --git a/ui/src/app/edge/history/gridoptimizedcharge/sellToGridLimitChart.component.ts b/ui/src/app/edge/history/gridoptimizedcharge/sellToGridLimitChart.component.ts index fca488700f2..0c556547ae4 100644 --- a/ui/src/app/edge/history/gridoptimizedcharge/sellToGridLimitChart.component.ts +++ b/ui/src/app/edge/history/gridoptimizedcharge/sellToGridLimitChart.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; diff --git a/ui/src/app/edge/history/gridoptimizedcharge/widget.component.ts b/ui/src/app/edge/history/gridoptimizedcharge/widget.component.ts index 122ef28ec7a..fd5361b5b33 100644 --- a/ui/src/app/edge/history/gridoptimizedcharge/widget.component.ts +++ b/ui/src/app/edge/history/gridoptimizedcharge/widget.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; diff --git a/ui/src/app/edge/history/heatingelement/chart.component.ts b/ui/src/app/edge/history/heatingelement/chart.component.ts index 3d933402698..d2647126584 100644 --- a/ui/src/app/edge/history/heatingelement/chart.component.ts +++ b/ui/src/app/edge/history/heatingelement/chart.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; diff --git a/ui/src/app/edge/history/heatingelement/heatingelementchartoverview/heatingelementchartoverview.component.ts b/ui/src/app/edge/history/heatingelement/heatingelementchartoverview/heatingelementchartoverview.component.ts index 8feb42315f4..795f4503b0f 100644 --- a/ui/src/app/edge/history/heatingelement/heatingelementchartoverview/heatingelementchartoverview.component.ts +++ b/ui/src/app/edge/history/heatingelement/heatingelementchartoverview/heatingelementchartoverview.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Edge, EdgeConfig, Service } from '../../../../shared/shared'; diff --git a/ui/src/app/edge/history/heatingelement/widget.component.ts b/ui/src/app/edge/history/heatingelement/widget.component.ts index 0f8c2a62e16..54c59de124b 100644 --- a/ui/src/app/edge/history/heatingelement/widget.component.ts +++ b/ui/src/app/edge/history/heatingelement/widget.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { QueryHistoricTimeseriesDataResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesDataResponse'; diff --git a/ui/src/app/edge/history/heatpump/chart.component.ts b/ui/src/app/edge/history/heatpump/chart.component.ts index 5350e669af1..a026c2e3d71 100644 --- a/ui/src/app/edge/history/heatpump/chart.component.ts +++ b/ui/src/app/edge/history/heatpump/chart.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; diff --git a/ui/src/app/edge/history/heatpump/heatpumpchartoverview/heatpumpchartoverview.component.ts b/ui/src/app/edge/history/heatpump/heatpumpchartoverview/heatpumpchartoverview.component.ts index a4c248c80e1..93e94726d5e 100644 --- a/ui/src/app/edge/history/heatpump/heatpumpchartoverview/heatpumpchartoverview.component.ts +++ b/ui/src/app/edge/history/heatpump/heatpumpchartoverview/heatpumpchartoverview.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { ModalController } from '@ionic/angular'; diff --git a/ui/src/app/edge/history/heatpump/widget.component.ts b/ui/src/app/edge/history/heatpump/widget.component.ts index e8e42316c5b..14ef01243f7 100644 --- a/ui/src/app/edge/history/heatpump/widget.component.ts +++ b/ui/src/app/edge/history/heatpump/widget.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { ModalController } from '@ionic/angular'; diff --git a/ui/src/app/edge/history/history.component.ts b/ui/src/app/edge/history/history.component.ts index 0441bc8823d..61166b75f5d 100644 --- a/ui/src/app/edge/history/history.component.ts +++ b/ui/src/app/edge/history/history.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; diff --git a/ui/src/app/edge/history/historydataservice.ts b/ui/src/app/edge/history/historydataservice.ts index 60efc278739..51e5a033ab5 100644 --- a/ui/src/app/edge/history/historydataservice.ts +++ b/ui/src/app/edge/history/historydataservice.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Inject, Injectable } from "@angular/core"; import { DataService } from "../../shared/genericComponents/shared/dataservice"; diff --git a/ui/src/app/edge/history/peakshaving/asymmetric/asymmetricpeakshavingchartoverview/asymmetricpeakshavingchartoverview.component.ts b/ui/src/app/edge/history/peakshaving/asymmetric/asymmetricpeakshavingchartoverview/asymmetricpeakshavingchartoverview.component.ts index 7d5cca39ae8..9e012f13202 100644 --- a/ui/src/app/edge/history/peakshaving/asymmetric/asymmetricpeakshavingchartoverview/asymmetricpeakshavingchartoverview.component.ts +++ b/ui/src/app/edge/history/peakshaving/asymmetric/asymmetricpeakshavingchartoverview/asymmetricpeakshavingchartoverview.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Edge, EdgeConfig, Service } from '../../../../../shared/shared'; 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 14c7fc670fa..158d68ca676 100644 --- a/ui/src/app/edge/history/peakshaving/asymmetric/chart.component.ts +++ b/ui/src/app/edge/history/peakshaving/asymmetric/chart.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; diff --git a/ui/src/app/edge/history/peakshaving/asymmetric/widget.component.ts b/ui/src/app/edge/history/peakshaving/asymmetric/widget.component.ts index dfa54214f11..daf215d6681 100644 --- a/ui/src/app/edge/history/peakshaving/asymmetric/widget.component.ts +++ b/ui/src/app/edge/history/peakshaving/asymmetric/widget.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { ActivatedRoute } from '@angular/router'; import { Component, Input, OnInit } from '@angular/core'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; 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 11d986d8b25..8cd625e16b9 100644 --- a/ui/src/app/edge/history/peakshaving/symmetric/chart.component.ts +++ b/ui/src/app/edge/history/peakshaving/symmetric/chart.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; diff --git a/ui/src/app/edge/history/peakshaving/symmetric/symmetricpeakshavingchartoverview/symmetricpeakshavingchartoverview.component.ts b/ui/src/app/edge/history/peakshaving/symmetric/symmetricpeakshavingchartoverview/symmetricpeakshavingchartoverview.component.ts index 452bd2b603b..9da6f44c1bc 100644 --- a/ui/src/app/edge/history/peakshaving/symmetric/symmetricpeakshavingchartoverview/symmetricpeakshavingchartoverview.component.ts +++ b/ui/src/app/edge/history/peakshaving/symmetric/symmetricpeakshavingchartoverview/symmetricpeakshavingchartoverview.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Edge, EdgeConfig, Service } from '../../../../../shared/shared'; diff --git a/ui/src/app/edge/history/peakshaving/symmetric/widget.component.ts b/ui/src/app/edge/history/peakshaving/symmetric/widget.component.ts index 923c2e27646..179d46e5e31 100644 --- a/ui/src/app/edge/history/peakshaving/symmetric/widget.component.ts +++ b/ui/src/app/edge/history/peakshaving/symmetric/widget.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; 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 f933fec6d96..1e65baae7f0 100644 --- a/ui/src/app/edge/history/peakshaving/timeslot/chart.component.ts +++ b/ui/src/app/edge/history/peakshaving/timeslot/chart.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; diff --git a/ui/src/app/edge/history/peakshaving/timeslot/timeslotpeakshavingchartoverview/timeslotpeakshavingchartoverview.component.ts b/ui/src/app/edge/history/peakshaving/timeslot/timeslotpeakshavingchartoverview/timeslotpeakshavingchartoverview.component.ts index f49c60691b1..79375034f28 100644 --- a/ui/src/app/edge/history/peakshaving/timeslot/timeslotpeakshavingchartoverview/timeslotpeakshavingchartoverview.component.ts +++ b/ui/src/app/edge/history/peakshaving/timeslot/timeslotpeakshavingchartoverview/timeslotpeakshavingchartoverview.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Edge, EdgeConfig, Service } from '../../../../../shared/shared'; diff --git a/ui/src/app/edge/history/peakshaving/timeslot/widget.component.ts b/ui/src/app/edge/history/peakshaving/timeslot/widget.component.ts index c01df3e9348..ab34310c2a0 100644 --- a/ui/src/app/edge/history/peakshaving/timeslot/widget.component.ts +++ b/ui/src/app/edge/history/peakshaving/timeslot/widget.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; diff --git a/ui/src/app/edge/history/shared.ts b/ui/src/app/edge/history/shared.ts index 9c9cddc5bf8..506dce92d5d 100644 --- a/ui/src/app/edge/history/shared.ts +++ b/ui/src/app/edge/history/shared.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import * as Chart from 'chart.js'; import { differenceInDays, differenceInMinutes, startOfDay } from 'date-fns'; import { de } from 'date-fns/locale'; @@ -318,7 +319,7 @@ export function calculateResolution(service: Service, fromDate: Date, toDate: Da if (days <= 1) { if (service.isSmartphoneResolution) { - result = { resolution: { value: 20, unit: ChronoUnit.Type.MINUTES }, timeFormat: 'hour' }; // 1 Day + result = { resolution: { value: 15, unit: ChronoUnit.Type.MINUTES }, timeFormat: 'hour' }; // 1 Day } else { result = { resolution: { value: 5, unit: ChronoUnit.Type.MINUTES }, timeFormat: 'hour' }; // 5 Minutes } diff --git a/ui/src/app/edge/history/singlethreshold/chart.component.ts b/ui/src/app/edge/history/singlethreshold/chart.component.ts index 32be29b928f..df56ee64199 100644 --- a/ui/src/app/edge/history/singlethreshold/chart.component.ts +++ b/ui/src/app/edge/history/singlethreshold/chart.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { formatNumber } from '@angular/common'; import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; diff --git a/ui/src/app/edge/history/singlethreshold/singlethresholdchartoverview/singlethresholdchartoverview.component.ts b/ui/src/app/edge/history/singlethreshold/singlethresholdchartoverview/singlethresholdchartoverview.component.ts index 16ff4faef04..0c9fae32c4f 100644 --- a/ui/src/app/edge/history/singlethreshold/singlethresholdchartoverview/singlethresholdchartoverview.component.ts +++ b/ui/src/app/edge/history/singlethreshold/singlethresholdchartoverview/singlethresholdchartoverview.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Edge, EdgeConfig, Service, Utils } from '../../../../shared/shared'; diff --git a/ui/src/app/edge/history/singlethreshold/widget.component.ts b/ui/src/app/edge/history/singlethreshold/widget.component.ts index 5a5b46ec2f1..5af56a066b8 100644 --- a/ui/src/app/edge/history/singlethreshold/widget.component.ts +++ b/ui/src/app/edge/history/singlethreshold/widget.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { QueryHistoricTimeseriesDataResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesDataResponse'; diff --git a/ui/src/app/edge/history/storage/chargerchart.component.ts b/ui/src/app/edge/history/storage/chargerchart.component.ts index 8b37ac0cb02..354e37e2aec 100644 --- a/ui/src/app/edge/history/storage/chargerchart.component.ts +++ b/ui/src/app/edge/history/storage/chargerchart.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; diff --git a/ui/src/app/edge/history/storage/esschart.component.ts b/ui/src/app/edge/history/storage/esschart.component.ts index 0ad2c4f52b0..507377c51dd 100644 --- a/ui/src/app/edge/history/storage/esschart.component.ts +++ b/ui/src/app/edge/history/storage/esschart.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; diff --git a/ui/src/app/edge/history/storage/singlechart.component.ts b/ui/src/app/edge/history/storage/singlechart.component.ts index e3ec04397ed..44bebe80fff 100644 --- a/ui/src/app/edge/history/storage/singlechart.component.ts +++ b/ui/src/app/edge/history/storage/singlechart.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { formatNumber } from '@angular/common'; import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; diff --git a/ui/src/app/edge/history/storage/socchart.component.ts b/ui/src/app/edge/history/storage/socchart.component.ts index 55fac0feecb..b6e67531da2 100644 --- a/ui/src/app/edge/history/storage/socchart.component.ts +++ b/ui/src/app/edge/history/storage/socchart.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; diff --git a/ui/src/app/edge/history/storage/storagechartoverview/storagechartoverview.component.ts b/ui/src/app/edge/history/storage/storagechartoverview/storagechartoverview.component.ts index 85eecd04639..1030838ca9c 100644 --- a/ui/src/app/edge/history/storage/storagechartoverview/storagechartoverview.component.ts +++ b/ui/src/app/edge/history/storage/storagechartoverview/storagechartoverview.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Edge, EdgeConfig, Service, Utils } from '../../../../shared/shared'; diff --git a/ui/src/app/edge/history/storage/totalchart.component.ts b/ui/src/app/edge/history/storage/totalchart.component.ts index 0e7f761a8bc..36cfb326953 100644 --- a/ui/src/app/edge/history/storage/totalchart.component.ts +++ b/ui/src/app/edge/history/storage/totalchart.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; diff --git a/ui/src/app/edge/history/storage/widget.component.ts b/ui/src/app/edge/history/storage/widget.component.ts index 3dcdcdcfed7..1673230f739 100644 --- a/ui/src/app/edge/history/storage/widget.component.ts +++ b/ui/src/app/edge/history/storage/widget.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Cumulated } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; diff --git a/ui/src/app/edge/live/Controller/Channelthreshold/Channelthreshold.ts b/ui/src/app/edge/live/Controller/Channelthreshold/Channelthreshold.ts index 10b64329b18..fe75017e03d 100644 --- a/ui/src/app/edge/live/Controller/Channelthreshold/Channelthreshold.ts +++ b/ui/src/app/edge/live/Controller/Channelthreshold/Channelthreshold.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; import { Icon } from 'src/app/shared/type/widget'; diff --git a/ui/src/app/edge/live/Controller/ChpSoc/ChpSoc.ts b/ui/src/app/edge/live/Controller/ChpSoc/ChpSoc.ts index b7fa89871de..76f7fc04222 100644 --- a/ui/src/app/edge/live/Controller/ChpSoc/ChpSoc.ts +++ b/ui/src/app/edge/live/Controller/ChpSoc/ChpSoc.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; import { Icon } from 'src/app/shared/type/widget'; diff --git a/ui/src/app/edge/live/Controller/ChpSoc/modal/modal.component.ts b/ui/src/app/edge/live/Controller/ChpSoc/modal/modal.component.ts index d84bc2e422d..3a4ab019f79 100644 --- a/ui/src/app/edge/live/Controller/ChpSoc/modal/modal.component.ts +++ b/ui/src/app/edge/live/Controller/ChpSoc/modal/modal.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { ModalController } from '@ionic/angular'; diff --git a/ui/src/app/edge/live/Controller/Ess/FixActivePower/Ess_FixActivePower.ts b/ui/src/app/edge/live/Controller/Ess/FixActivePower/Ess_FixActivePower.ts index 61c72138ad6..471d2ee863d 100644 --- a/ui/src/app/edge/live/Controller/Ess/FixActivePower/Ess_FixActivePower.ts +++ b/ui/src/app/edge/live/Controller/Ess/FixActivePower/Ess_FixActivePower.ts @@ -9,10 +9,6 @@ import { ModalComponent } from './modal/modal'; BrowserModule, SharedModule, ], - entryComponents: [ - FlatComponent, - ModalComponent, - ], declarations: [ FlatComponent, ModalComponent, 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 44af2e7d70d..114bb581a71 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 @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; diff --git a/ui/src/app/edge/live/Controller/Ess/FixActivePower/modal/modal.ts b/ui/src/app/edge/live/Controller/Ess/FixActivePower/modal/modal.ts index cd23b31bd62..82b9e73d33e 100644 --- a/ui/src/app/edge/live/Controller/Ess/FixActivePower/modal/modal.ts +++ b/ui/src/app/edge/live/Controller/Ess/FixActivePower/modal/modal.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { FormControl, FormGroup } from '@angular/forms'; import { AbstractModal } from 'src/app/shared/genericComponents/modal/abstractModal'; diff --git a/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/Ess_GridOptimizedCharge.ts b/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/Ess_GridOptimizedCharge.ts index 72b7aaa5e06..90c1bb531b7 100644 --- a/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/Ess_GridOptimizedCharge.ts +++ b/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/Ess_GridOptimizedCharge.ts @@ -10,11 +10,6 @@ import { PredictionChartComponent } from './modal/predictionChart'; BrowserModule, SharedModule, ], - entryComponents: [ - FlatComponent, - ModalComponent, - PredictionChartComponent, - ], declarations: [ FlatComponent, ModalComponent, 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 3248cc5dc65..daf5c9530ab 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 @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; import { ChannelAddress, CurrentData, EdgeConfig, Utils } from 'src/app/shared/shared'; diff --git a/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/modal/modal.ts b/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/modal/modal.ts index 0184f951da7..703dc533b0e 100644 --- a/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/modal/modal.ts +++ b/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/modal/modal.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { ChangeDetectionStrategy, Component } from '@angular/core'; import { FormControl, FormGroup, Validators } from '@angular/forms'; import { AbstractModal } from 'src/app/shared/genericComponents/modal/abstractModal'; 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 3c21c751a26..e785684e2b0 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 @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; diff --git a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/Ess_TimeOfUseTariff.ts b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/Ess_TimeOfUseTariff.ts index 2baf5db81e0..3e068cbf248 100644 --- a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/Ess_TimeOfUseTariff.ts +++ b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/Ess_TimeOfUseTariff.ts @@ -1,5 +1,10 @@ +// @ts-strict-ignore import { NgModule } from "@angular/core"; import { BrowserModule } from "@angular/platform-browser"; +import { TranslateService } from "@ngx-translate/core"; +import { ChartDataset } from "chart.js"; +import { ChartAxis, TimeOfUseTariffUtils } from "src/app/shared/service/utils"; +import { Utils } from "src/app/shared/shared"; import { SharedModule } from "src/app/shared/shared.module"; import { FlatComponent } from "./flat/flat"; import { ModalComponent } from "./modal/modal"; @@ -11,12 +16,6 @@ import { ScheduleStateAndPriceChartComponent } from "./modal/statePriceChart"; BrowserModule, SharedModule, ], - entryComponents: [ - FlatComponent, - ModalComponent, - ScheduleStateAndPriceChartComponent, - SchedulePowerAndSocChartComponent, - ], declarations: [ FlatComponent, ModalComponent, @@ -28,4 +27,141 @@ import { ScheduleStateAndPriceChartComponent } from "./modal/statePriceChart"; ], }) export class Controller_Ess_TimeOfUseTariff { + + /** + * Gets the schedule chart data containing datasets, colors and labels. + * + * @param size The length of the dataset + * @param prices The Time-of-Use-Tariff quarterly price array + * @param states The Time-of-Use-Tariff state array + * @param timestamps The Time-of-Use-Tariff timestamps array + * @param gridBuy The Time-of-Use-Tariff gridBuy array + * @param socArray The Time-of0Use-Tariff soc Array. + * @param translate The Translate service + * @param controlMode The Control mode of the controller. + * @returns The ScheduleChartData. + */ + public static getScheduleChartData(size: number, prices: number[], states: number[], timestamps: string[], + gridBuy: number[], socArray: number[], translate: TranslateService, + controlMode: Controller_Ess_TimeOfUseTariff.ControlMode): Controller_Ess_TimeOfUseTariff.ScheduleChartData { + + const datasets: ChartDataset[] = []; + const colors: any[] = []; + const labels: Date[] = []; + + // Initializing States. + const barChargeGrid = Array(size).fill(null); + const barBalancing = Array(size).fill(null); + const barDelayDischarge = Array(size).fill(null); + + for (let index = 0; index < size; index++) { + const quarterlyPrice = TimeOfUseTariffUtils.formatPrice(prices[index]); + const state = states[index]; + labels.push(new Date(timestamps[index])); + + if (state !== null) { + switch (state) { + case TimeOfUseTariffUtils.State.DelayDischarge: + barDelayDischarge[index] = quarterlyPrice; + break; + case TimeOfUseTariffUtils.State.Balancing: + barBalancing[index] = quarterlyPrice; + break; + case TimeOfUseTariffUtils.State.ChargeGrid: + barChargeGrid[index] = quarterlyPrice; + break; + } + } + } + + // Set datasets + datasets.push({ + type: 'bar', + label: translate.instant('Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.BALANCING'), + data: barBalancing, + order: 1, + }); + colors.push({ + // Dark Green + backgroundColor: 'rgba(51,102,0,0.8)', + borderColor: 'rgba(51,102,0,1)', + }); + + // Set dataset for ChargeGrid. + if (!barChargeGrid.every(v => v === null) || controlMode == Controller_Ess_TimeOfUseTariff.ControlMode.CHARGE_CONSUMPTION) { + datasets.push({ + type: 'bar', + label: translate.instant('Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.CHARGE_GRID'), + data: barChargeGrid, + order: 1, + }); + colors.push({ + // Sky blue + backgroundColor: 'rgba(0, 204, 204,0.5)', + borderColor: 'rgba(0, 204, 204,0.7)', + }); + } + + // Set dataset for buy from grid + datasets.push({ + type: 'bar', + label: translate.instant('Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.DELAY_DISCHARGE'), + data: barDelayDischarge, + order: 1, + }); + colors.push({ + // Black + backgroundColor: 'rgba(0,0,0,0.8)', + borderColor: 'rgba(0,0,0,0.9)', + }); + + // State of charge data + datasets.push({ + type: 'line', + label: translate.instant('General.soc'), + data: socArray, + hidden: false, + yAxisID: ChartAxis.RIGHT, + borderDash: [10, 10], + order: 0, + }); + colors.push({ + backgroundColor: 'rgba(189, 195, 199,0.2)', + borderColor: 'rgba(189, 195, 199,1)', + }); + + datasets.push({ + type: 'line', + label: translate.instant('General.gridBuy'), + data: gridBuy.map(v => Utils.divideSafely(v, 1000)), // [W] to [kW] + hidden: true, + yAxisID: ChartAxis.RIGHT_2, + order: 2, + }); + colors.push({ + backgroundColor: 'rgba(0,0,0, 0.2)', + borderColor: 'rgba(0,0,0, 1)', + }); + + const scheduleChartData: Controller_Ess_TimeOfUseTariff.ScheduleChartData = { + colors: colors, + datasets: datasets, + labels: labels, + }; + + return scheduleChartData; + } +} + +export namespace Controller_Ess_TimeOfUseTariff { + export type ScheduleChartData = { + datasets: ChartDataset[], + colors: any[], + labels: Date[] + }; + + export enum ControlMode { + CHARGE_CONSUMPTION = 'CHARGE_CONSUMPTION', + DELAY_DISCHARGE = 'DELAY_DISCHARGE' + } } diff --git a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/modal.ts b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/modal.ts index 5c5ba73e90a..368003307d2 100644 --- a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/modal.ts +++ b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/modal.ts @@ -1,8 +1,9 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { FormControl, FormGroup } from '@angular/forms'; import { AbstractModal } from 'src/app/shared/genericComponents/modal/abstractModal'; -import { TimeOfUseTariffUtils } from 'src/app/shared/service/utils'; import { ChannelAddress, Currency, CurrentData } from 'src/app/shared/shared'; +import { Controller_Ess_TimeOfUseTariff } from '../Ess_TimeOfUseTariff'; @Component({ templateUrl: './modal.html', @@ -11,13 +12,12 @@ export class ModalComponent extends AbstractModal { protected readonly CONVERT_TIME_OF_USE_TARIFF_STATE = this.Utils.CONVERT_TIME_OF_USE_TARIFF_STATE(this.translate); protected priceWithCurrency: any; - protected controlMode = TimeOfUseTariffUtils.ControlMode; protected override getFormGroup(): FormGroup { return this.formBuilder.group({ mode: new FormControl(this.component.properties.mode), controlMode: new FormControl(this.component.properties.controlMode), - chargeConsumptionIsActive: new FormControl(this.component.properties.controlMode === this.controlMode.CHARGE_CONSUMPTION ? true : false), + chargeConsumptionIsActive: new FormControl(this.component.properties.controlMode === Controller_Ess_TimeOfUseTariff.ControlMode.CHARGE_CONSUMPTION ? true : false), }); } @@ -32,7 +32,9 @@ export class ModalComponent extends AbstractModal { this.formGroup?.get('chargeConsumptionIsActive') .valueChanges .subscribe(isActive => { - const controlMode: TimeOfUseTariffUtils.ControlMode = isActive ? this.controlMode.CHARGE_CONSUMPTION : this.controlMode.DELAY_DISCHARGE; + const controlMode: Controller_Ess_TimeOfUseTariff.ControlMode = isActive + ? Controller_Ess_TimeOfUseTariff.ControlMode.CHARGE_CONSUMPTION + : Controller_Ess_TimeOfUseTariff.ControlMode.DELAY_DISCHARGE; this.formGroup.controls['controlMode'].setValue(controlMode); this.formGroup.controls['controlMode'].markAsDirty(); })); diff --git a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/powerSocChart.ts b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/powerSocChart.ts index cf839777858..562a139ceae 100644 --- a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/powerSocChart.ts +++ b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/powerSocChart.ts @@ -1,12 +1,12 @@ +// @ts-strict-ignore import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import * as Chart from 'chart.js'; import { AbstractHistoryChart } from 'src/app/edge/history/abstracthistorychart'; import { AbstractHistoryChart as NewAbstractHistoryChart } from 'src/app/shared/genericComponents/chart/abstracthistorychart'; -import { ChartConstants } from 'src/app/shared/genericComponents/chart/chart.constants'; import { ComponentJsonApiRequest } from 'src/app/shared/jsonrpc/request/componentJsonApiRequest'; -import { ChartAxis, HistoryUtils, TimeOfUseTariffUtils, YAxisTitle } from 'src/app/shared/service/utils'; +import { ChartAxis, HistoryUtils, TimeOfUseTariffUtils, Utils, YAxisTitle } from 'src/app/shared/service/utils'; import { ChannelAddress, Edge, EdgeConfig, Service, Websocket } from 'src/app/shared/shared'; import { GetScheduleRequest } from '../../../../../../shared/jsonrpc/request/getScheduleRequest'; @@ -60,12 +60,12 @@ export class SchedulePowerAndSocChartComponent extends AbstractHistoryChart impl // Extracting prices and states from the schedule array const { gridBuyArray, gridSellArray, productionArray, consumptionArray, essDischargeArray, essChargeArray, socArray, labels } = { - gridBuyArray: schedule.map(entry => HistoryUtils.ValueConverter.NEGATIVE_AS_ZERO(entry.grid)), - gridSellArray: schedule.map(entry => HistoryUtils.ValueConverter.POSITIVE_AS_ZERO_AND_INVERT_NEGATIVE(entry.grid)), - productionArray: schedule.map(entry => entry.production), - consumptionArray: schedule.map(entry => entry.consumption), - essDischargeArray: schedule.map(entry => HistoryUtils.ValueConverter.NEGATIVE_AS_ZERO(entry.ess)), - essChargeArray: schedule.map(entry => HistoryUtils.ValueConverter.POSITIVE_AS_ZERO_AND_INVERT_NEGATIVE(entry.ess)), + gridBuyArray: schedule.map(entry => HistoryUtils.ValueConverter.NEGATIVE_AS_ZERO(entry.grid), 1000), + gridSellArray: schedule.map(entry => HistoryUtils.ValueConverter.POSITIVE_AS_ZERO_AND_INVERT_NEGATIVE(entry.grid), 1000), + productionArray: schedule.map(entry => entry.production, 1000), + consumptionArray: schedule.map(entry => entry.consumption, 1000), + essDischargeArray: schedule.map(entry => HistoryUtils.ValueConverter.NEGATIVE_AS_ZERO(entry.ess), 1000), + essChargeArray: schedule.map(entry => HistoryUtils.ValueConverter.POSITIVE_AS_ZERO_AND_INVERT_NEGATIVE(entry.ess), 1000), socArray: schedule.map(entry => entry.soc), labels: schedule.map(entry => new Date(entry.timestamp)), }; @@ -73,7 +73,7 @@ export class SchedulePowerAndSocChartComponent extends AbstractHistoryChart impl datasets.push({ type: 'line', label: this.translate.instant('General.gridBuy'), - data: gridBuyArray, + data: gridBuyArray.map(v => Utils.divideSafely(v, 1000)), // [W] to [kW] hidden: true, order: 1, }); @@ -85,7 +85,7 @@ export class SchedulePowerAndSocChartComponent extends AbstractHistoryChart impl datasets.push({ type: 'line', label: this.translate.instant('General.gridSell'), - data: gridSellArray, + data: gridSellArray.map(v => Utils.divideSafely(v, 1000)), // [W] to [kW] hidden: true, order: 1, }); @@ -97,7 +97,7 @@ export class SchedulePowerAndSocChartComponent extends AbstractHistoryChart impl datasets.push({ type: 'line', label: this.translate.instant('General.production'), - data: productionArray, + data: productionArray.map(v => Utils.divideSafely(v, 1000)), // [W] to [kW] hidden: false, order: 1, }); @@ -109,7 +109,7 @@ export class SchedulePowerAndSocChartComponent extends AbstractHistoryChart impl datasets.push({ type: 'line', label: this.translate.instant('General.consumption'), - data: consumptionArray, + data: consumptionArray.map(v => Utils.divideSafely(v, 1000)), // [W] to [kW] hidden: false, order: 1, }); @@ -121,9 +121,10 @@ export class SchedulePowerAndSocChartComponent extends AbstractHistoryChart impl datasets.push({ type: 'line', label: this.translate.instant('General.chargePower'), - data: essChargeArray, + data: essChargeArray.map(v => Utils.divideSafely(v, 1000)), // [W] to [kW] hidden: true, order: 1, + unit: YAxisTitle.POWER, }); this.colors.push({ backgroundColor: 'rgba(0,223,0, 0.2)', @@ -133,9 +134,10 @@ export class SchedulePowerAndSocChartComponent extends AbstractHistoryChart impl datasets.push({ type: 'line', label: this.translate.instant('General.dischargePower'), - data: essDischargeArray, + data: essDischargeArray.map(v => Utils.divideSafely(v, 1000)), // [W] to [kW] hidden: true, order: 1, + unit: YAxisTitle.POWER, }); this.colors.push({ backgroundColor: 'rgba(200,0,0, 0.2)', @@ -168,7 +170,6 @@ export class SchedulePowerAndSocChartComponent extends AbstractHistoryChart impl this.initializeChart(); return; }).finally(async () => { - this.unit = YAxisTitle.POWER; await this.setOptions(this.options); this.applyControllerSpecificOptions(); }); @@ -176,11 +177,10 @@ export class SchedulePowerAndSocChartComponent extends AbstractHistoryChart impl private applyControllerSpecificOptions() { const rightYAxis: HistoryUtils.yAxes = { position: 'right', unit: YAxisTitle.PERCENTAGE, yAxisId: ChartAxis.RIGHT }; - const leftYAxis: HistoryUtils.yAxes = { position: 'left', unit: YAxisTitle.ENERGY, yAxisId: ChartAxis.LEFT }; + const leftYAxis: HistoryUtils.yAxes = { position: 'left', unit: YAxisTitle.POWER, yAxisId: ChartAxis.LEFT }; const locale = this.service.translate.currentLang; - const scaleOptionsLeft = ChartConstants.getScaleOptions(this.datasets, leftYAxis); - this.options = NewAbstractHistoryChart.getYAxisOptions(this.options, rightYAxis, this.translate, 'line', locale, true, scaleOptionsLeft); + this.options = NewAbstractHistoryChart.getYAxisOptions(this.options, rightYAxis, this.translate, 'line', locale, true); this.options = NewAbstractHistoryChart.getYAxisOptions(this.options, leftYAxis, this.translate, 'line', locale, true); this.datasets = this.datasets.map((el: Chart.ChartDataset) => { @@ -201,6 +201,8 @@ export class SchedulePowerAndSocChartComponent extends AbstractHistoryChart impl }; this.options.scales[ChartAxis.RIGHT].grid.display = false; + this.options.scales[ChartAxis.LEFT].suggestedMin = 0; + this.options.scales[ChartAxis.LEFT].suggestedMax = 1; } protected setLabel() { diff --git a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/statePriceChart.ts b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/statePriceChart.ts index 3edc5233d72..cb6fc333a81 100644 --- a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/statePriceChart.ts +++ b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/statePriceChart.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; @@ -12,6 +13,7 @@ import { calculateResolution } from 'src/app/edge/history/shared'; import { ColorUtils } from 'src/app/shared/utils/color/color.utils'; import { GetScheduleRequest } from '../../../../../../shared/jsonrpc/request/getScheduleRequest'; import { GetScheduleResponse } from '../../../../../../shared/jsonrpc/response/getScheduleResponse'; +import { Controller_Ess_TimeOfUseTariff } from '../Ess_TimeOfUseTariff'; @Component({ selector: 'statePriceChart', @@ -69,7 +71,8 @@ export class ScheduleStateAndPriceChartComponent extends AbstractHistoryChart im socArray: schedule.map(entry => entry.soc), }; - const scheduleChartData = TimeOfUseTariffUtils.getScheduleChartData(schedule.length, priceArray, stateArray, timestampArray, gridBuyArray, socArray, this.translate, this.component.properties.controlMode); + const scheduleChartData = Controller_Ess_TimeOfUseTariff.getScheduleChartData(schedule.length, priceArray, + stateArray, timestampArray, gridBuyArray, socArray, this.translate, this.component.properties.controlMode); this.colors = scheduleChartData.colors; this.labels = scheduleChartData.labels; @@ -78,10 +81,12 @@ export class ScheduleStateAndPriceChartComponent extends AbstractHistoryChart im this.loading = false; this.setLabel(); this.stopSpinner(); + }).catch((reason) => { console.error(reason); this.initializeChart(); return; + }).finally(async () => { this.unit = YAxisTitle.CURRENCY; await this.setOptions(this.options); @@ -152,6 +157,8 @@ export class ScheduleStateAndPriceChartComponent extends AbstractHistoryChart im this.options.scales[ChartAxis.LEFT]['title'].text = this.currencyLabel; this.options.scales[ChartAxis.RIGHT].grid.display = false; + this.options.scales[ChartAxis.RIGHT_2].suggestedMin = 0; + this.options.scales[ChartAxis.RIGHT_2].suggestedMax = 1; this.options.scales[ChartAxis.RIGHT_2].grid.display = false; this.options['animation'] = false; } diff --git a/ui/src/app/edge/live/Controller/Evcs/Evcs.ts b/ui/src/app/edge/live/Controller/Evcs/Evcs.ts index 21dec28b819..6a2568a03c5 100644 --- a/ui/src/app/edge/live/Controller/Evcs/Evcs.ts +++ b/ui/src/app/edge/live/Controller/Evcs/Evcs.ts @@ -10,11 +10,6 @@ import { PopoverComponent } from './popover/popover'; BrowserModule, SharedModule, ], - entryComponents: [ - FlatComponent, - ModalComponent, - PopoverComponent, - ], declarations: [ FlatComponent, ModalComponent, diff --git a/ui/src/app/edge/live/Controller/Evcs/administration/administration.component.ts b/ui/src/app/edge/live/Controller/Evcs/administration/administration.component.ts index e1ffd2103e3..bc9fb3b4fef 100644 --- a/ui/src/app/edge/live/Controller/Evcs/administration/administration.component.ts +++ b/ui/src/app/edge/live/Controller/Evcs/administration/administration.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { ModalController } from '@ionic/angular'; diff --git a/ui/src/app/edge/live/Controller/Evcs/flat/flat.ts b/ui/src/app/edge/live/Controller/Evcs/flat/flat.ts index ff43a24e529..50cb8fede3e 100644 --- a/ui/src/app/edge/live/Controller/Evcs/flat/flat.ts +++ b/ui/src/app/edge/live/Controller/Evcs/flat/flat.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; diff --git a/ui/src/app/edge/live/Controller/Evcs/modal/modal.ts b/ui/src/app/edge/live/Controller/Evcs/modal/modal.ts index 2a394e903e1..3971ecd4e94 100644 --- a/ui/src/app/edge/live/Controller/Evcs/modal/modal.ts +++ b/ui/src/app/edge/live/Controller/Evcs/modal/modal.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { ChangeDetectorRef, Component, Inject } from '@angular/core'; import { FormBuilder, FormControl, FormGroup } from '@angular/forms'; import { ActivatedRoute } from '@angular/router'; diff --git a/ui/src/app/edge/live/Controller/Evcs/popover/popover.ts b/ui/src/app/edge/live/Controller/Evcs/popover/popover.ts index c2272df7af1..94f6f39109a 100644 --- a/ui/src/app/edge/live/Controller/Evcs/popover/popover.ts +++ b/ui/src/app/edge/live/Controller/Evcs/popover/popover.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { AbstractModal } from 'src/app/shared/genericComponents/modal/abstractModal'; 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 450cd89fc59..df989ea5c05 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,3 +1,4 @@ +// @ts-strict-ignore 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'; diff --git a/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/modal/modal.component.ts b/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/modal/modal.component.ts index 05f2e79bb9c..68a871803e4 100644 --- a/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/modal/modal.component.ts +++ b/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/modal/modal.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnInit } from '@angular/core'; import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import { ModalController } from '@ionic/angular'; 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 fdaf6d1e271..80c7c667c3f 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,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; import { ChannelAddress, CurrentData } from 'src/app/shared/shared'; diff --git a/ui/src/app/edge/live/Controller/Io/FixDigitalOutput/modal/modal.component.ts b/ui/src/app/edge/live/Controller/Io/FixDigitalOutput/modal/modal.component.ts index aa8c5ece5fd..3a6111ccab2 100644 --- a/ui/src/app/edge/live/Controller/Io/FixDigitalOutput/modal/modal.component.ts +++ b/ui/src/app/edge/live/Controller/Io/FixDigitalOutput/modal/modal.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input } from '@angular/core'; import { Router } from '@angular/router'; import { ModalController } from '@ionic/angular'; diff --git a/ui/src/app/edge/live/Controller/Io/HeatingElement/Io_HeatingElement.ts b/ui/src/app/edge/live/Controller/Io/HeatingElement/Io_HeatingElement.ts index 7c4f9b30984..d390623b36b 100644 --- a/ui/src/app/edge/live/Controller/Io/HeatingElement/Io_HeatingElement.ts +++ b/ui/src/app/edge/live/Controller/Io/HeatingElement/Io_HeatingElement.ts @@ -9,10 +9,6 @@ import { ModalComponent } from "./modal/modal"; BrowserModule, SharedModule, ], - entryComponents: [ - FlatComponent, - ModalComponent, - ], declarations: [ FlatComponent, ModalComponent, 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 afc1d046a05..ac081a96468 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 @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; diff --git a/ui/src/app/edge/live/Controller/Io/HeatingElement/modal/modal.ts b/ui/src/app/edge/live/Controller/Io/HeatingElement/modal/modal.ts index 35a0e239d55..c440f01a45e 100644 --- a/ui/src/app/edge/live/Controller/Io/HeatingElement/modal/modal.ts +++ b/ui/src/app/edge/live/Controller/Io/HeatingElement/modal/modal.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnInit } from '@angular/core'; import { FormControl, FormGroup } from '@angular/forms'; import { BehaviorSubject } from 'rxjs'; 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 a9487152f25..7fbbc30b59d 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,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; diff --git a/ui/src/app/edge/live/Controller/Io/Heatpump/modal/modal.component.ts b/ui/src/app/edge/live/Controller/Io/Heatpump/modal/modal.component.ts index 5d7e1874d9a..367e192854f 100644 --- a/ui/src/app/edge/live/Controller/Io/Heatpump/modal/modal.component.ts +++ b/ui/src/app/edge/live/Controller/Io/Heatpump/modal/modal.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnInit } from '@angular/core'; import { FormBuilder, FormControl, FormGroup } from '@angular/forms'; import { ModalController } from '@ionic/angular'; 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 08c2f7cfc1c..c1afbe5d598 100644 --- a/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/Asymmetric.ts +++ b/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/Asymmetric.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; diff --git a/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/modal/modal.component.ts b/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/modal/modal.component.ts index 68988b5cf20..751df3e54b1 100644 --- a/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/modal/modal.component.ts +++ b/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/modal/modal.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnInit } from '@angular/core'; import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import { ModalController } from '@ionic/angular'; 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 36b337fdc48..1d25869f2bd 100644 --- a/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/Symmetric.ts +++ b/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/Symmetric.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; diff --git a/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/modal/modal.component.ts b/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/modal/modal.component.ts index e53c0cc60c5..2f1c86eed96 100644 --- a/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/modal/modal.component.ts +++ b/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/modal/modal.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnInit } from '@angular/core'; import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import { ModalController } from '@ionic/angular'; 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 d702d4bf962..e8d9e356b7b 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,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; diff --git a/ui/src/app/edge/live/Controller/PeakShaving/Symmetric_TimeSlot/modal/modal.component.ts b/ui/src/app/edge/live/Controller/PeakShaving/Symmetric_TimeSlot/modal/modal.component.ts index ce717a33a0b..a424dd6df36 100644 --- a/ui/src/app/edge/live/Controller/PeakShaving/Symmetric_TimeSlot/modal/modal.component.ts +++ b/ui/src/app/edge/live/Controller/PeakShaving/Symmetric_TimeSlot/modal/modal.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnInit } from '@angular/core'; import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import { ModalController } from '@ionic/angular'; 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 c0980557c66..0fdc12f4202 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,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; import { ChannelAddress, EdgeConfig } from 'src/app/shared/shared'; diff --git a/ui/src/app/edge/live/Io/Api_DigitalInput/modal/modal.component.ts b/ui/src/app/edge/live/Io/Api_DigitalInput/modal/modal.component.ts index eef0fc31745..2402bb3ea24 100644 --- a/ui/src/app/edge/live/Io/Api_DigitalInput/modal/modal.component.ts +++ b/ui/src/app/edge/live/Io/Api_DigitalInput/modal/modal.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input } from '@angular/core'; import { Edge, Service, EdgeConfig } from '../../../../../shared/shared'; import { ModalController } from '@ionic/angular'; 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 4b4bfa0d57f..43f8fe3fe25 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,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; diff --git a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcs-chart/evcs.chart.ts b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcs-chart/evcs.chart.ts index ad1ce0727d7..e78268eda98 100644 --- a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcs-chart/evcs.chart.ts +++ b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcs-chart/evcs.chart.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import * as Chart from 'chart.js'; import { Component, Input, OnInit, OnChanges } from '@angular/core'; import { CurrentData } from 'src/app/shared/edge/currentdata'; diff --git a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcsCluster-modal.page.ts b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcsCluster-modal.page.ts index 2ae12fc26fe..f1f6edc62d6 100644 --- a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcsCluster-modal.page.ts +++ b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcsCluster-modal.page.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { ActivatedRoute, Router } from '@angular/router'; import { Component, Input, OnInit, ViewChild } from '@angular/core'; import { Edge, EdgeConfig, Service, Websocket } from 'src/app/shared/shared'; diff --git a/ui/src/app/edge/live/common/autarchy/Common_Autarchy.ts b/ui/src/app/edge/live/common/autarchy/Common_Autarchy.ts index 3360cef6144..8aa0d3022b4 100644 --- a/ui/src/app/edge/live/common/autarchy/Common_Autarchy.ts +++ b/ui/src/app/edge/live/common/autarchy/Common_Autarchy.ts @@ -9,10 +9,6 @@ import { ModalComponent } from './modal/modal'; BrowserModule, SharedModule, ], - entryComponents: [ - FlatComponent, - ModalComponent, - ], declarations: [ FlatComponent, ModalComponent, diff --git a/ui/src/app/edge/live/common/autarchy/flat/flat.ts b/ui/src/app/edge/live/common/autarchy/flat/flat.ts index baa38c8bfce..cc161dbc2d9 100644 --- a/ui/src/app/edge/live/common/autarchy/flat/flat.ts +++ b/ui/src/app/edge/live/common/autarchy/flat/flat.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore 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'; diff --git a/ui/src/app/edge/live/common/consumption/Common_Consumption.ts b/ui/src/app/edge/live/common/consumption/Common_Consumption.ts index 5059a7e0ce8..f685ef859cf 100644 --- a/ui/src/app/edge/live/common/consumption/Common_Consumption.ts +++ b/ui/src/app/edge/live/common/consumption/Common_Consumption.ts @@ -9,10 +9,6 @@ import { ModalComponent } from './modal/modal'; BrowserModule, SharedModule, ], - entryComponents: [ - FlatComponent, - ModalComponent, - ], declarations: [ FlatComponent, ModalComponent, 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 8170a24be7d..34f7f9f16a8 100644 --- a/ui/src/app/edge/live/common/consumption/flat/flat.ts +++ b/ui/src/app/edge/live/common/consumption/flat/flat.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; import { ChannelAddress, CurrentData, EdgeConfig, Utils } from 'src/app/shared/shared'; diff --git a/ui/src/app/edge/live/common/consumption/modal/modal.spec.ts b/ui/src/app/edge/live/common/consumption/modal/modal.spec.ts index a93aed2185b..eb9eae845eb 100644 --- a/ui/src/app/edge/live/common/consumption/modal/modal.spec.ts +++ b/ui/src/app/edge/live/common/consumption/modal/modal.spec.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { CHANNEL_LINE, DummyConfig, LINE_HORIZONTAL, LINE_INFO_PHASES_DE, VALUE_FROM_CHANNELS_LINE } from "src/app/shared/edge/edgeconfig.spec"; import { TextIndentation } from "src/app/shared/genericComponents/modal/modal-line/modal-line"; import { OeFormlyViewTester } from "src/app/shared/genericComponents/shared/testing/tester"; diff --git a/ui/src/app/edge/live/common/grid/Common_Grid.ts b/ui/src/app/edge/live/common/grid/Common_Grid.ts index f18c9384061..b560e4725d4 100644 --- a/ui/src/app/edge/live/common/grid/Common_Grid.ts +++ b/ui/src/app/edge/live/common/grid/Common_Grid.ts @@ -9,10 +9,6 @@ import { ModalComponent } from './modal/modal'; BrowserModule, SharedModule, ], - entryComponents: [ - FlatComponent, - ModalComponent, - ], declarations: [ FlatComponent, ModalComponent, diff --git a/ui/src/app/edge/live/common/grid/flat/flat.ts b/ui/src/app/edge/live/common/grid/flat/flat.ts index c1a86e14098..047830f4b9f 100644 --- a/ui/src/app/edge/live/common/grid/flat/flat.ts +++ b/ui/src/app/edge/live/common/grid/flat/flat.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { ChannelAddress, CurrentData, GridMode, Utils } from 'src/app/shared/shared'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; diff --git a/ui/src/app/edge/live/common/production/Common_Production.ts b/ui/src/app/edge/live/common/production/Common_Production.ts index 944697e272d..ab5942cf712 100644 --- a/ui/src/app/edge/live/common/production/Common_Production.ts +++ b/ui/src/app/edge/live/common/production/Common_Production.ts @@ -9,10 +9,6 @@ import { ModalComponent } from './modal/modal'; BrowserModule, SharedModule, ], - entryComponents: [ - FlatComponent, - ModalComponent, - ], declarations: [ FlatComponent, ModalComponent, diff --git a/ui/src/app/edge/live/common/selfconsumption/Common_Selfconsumption.ts b/ui/src/app/edge/live/common/selfconsumption/Common_Selfconsumption.ts index 846a5e07e49..6c49f7603a4 100644 --- a/ui/src/app/edge/live/common/selfconsumption/Common_Selfconsumption.ts +++ b/ui/src/app/edge/live/common/selfconsumption/Common_Selfconsumption.ts @@ -9,10 +9,6 @@ import { ModalComponent } from './modal/modal'; BrowserModule, SharedModule, ], - entryComponents: [ - FlatComponent, - ModalComponent, - ], declarations: [ FlatComponent, ModalComponent, 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 8a7223e3bff..73f504b17de 100644 --- a/ui/src/app/edge/live/common/selfconsumption/flat/flat.ts +++ b/ui/src/app/edge/live/common/selfconsumption/flat/flat.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore 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'; diff --git a/ui/src/app/edge/live/common/storage/modal/modal.component.ts b/ui/src/app/edge/live/common/storage/modal/modal.component.ts index 035eb139a8d..8fc10a04131 100644 --- a/ui/src/app/edge/live/common/storage/modal/modal.component.ts +++ b/ui/src/app/edge/live/common/storage/modal/modal.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { FormBuilder, FormControl, FormGroup } from '@angular/forms'; import { ModalController } from '@ionic/angular'; 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 f0ee2852496..f5558444284 100644 --- a/ui/src/app/edge/live/common/storage/storage.component.ts +++ b/ui/src/app/edge/live/common/storage/storage.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { formatNumber } from '@angular/common'; import { Component } from '@angular/core'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; diff --git a/ui/src/app/edge/live/delayedselltogrid/delayedselltogrid.component.ts b/ui/src/app/edge/live/delayedselltogrid/delayedselltogrid.component.ts index 166b0fbc080..5f14f0149a4 100644 --- a/ui/src/app/edge/live/delayedselltogrid/delayedselltogrid.component.ts +++ b/ui/src/app/edge/live/delayedselltogrid/delayedselltogrid.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { ModalController } from '@ionic/angular'; diff --git a/ui/src/app/edge/live/delayedselltogrid/modal/modal.component.ts b/ui/src/app/edge/live/delayedselltogrid/modal/modal.component.ts index b03668fc30c..c9a4efbb5b5 100644 --- a/ui/src/app/edge/live/delayedselltogrid/modal/modal.component.ts +++ b/ui/src/app/edge/live/delayedselltogrid/modal/modal.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnInit } from '@angular/core'; import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import { ModalController } from '@ionic/angular'; diff --git a/ui/src/app/edge/live/energymonitor/chart/chart.component.ts b/ui/src/app/edge/live/energymonitor/chart/chart.component.ts index 25ad7177fab..be5fe2c85d0 100644 --- a/ui/src/app/edge/live/energymonitor/chart/chart.component.ts +++ b/ui/src/app/edge/live/energymonitor/chart/chart.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, ElementRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { fromEvent, Subject } from 'rxjs'; import { debounceTime, delay, takeUntil } from 'rxjs/operators'; diff --git a/ui/src/app/edge/live/energymonitor/chart/section/abstractsection.component.ts b/ui/src/app/edge/live/energymonitor/chart/section/abstractsection.component.ts index 3625b51d42b..95045c5cd53 100644 --- a/ui/src/app/edge/live/energymonitor/chart/section/abstractsection.component.ts +++ b/ui/src/app/edge/live/energymonitor/chart/section/abstractsection.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { DefaultTypes } from '../../../../../shared/service/defaulttypes'; import { Service } from 'src/app/shared/shared'; import { TranslateService } from '@ngx-translate/core'; diff --git a/ui/src/app/edge/live/energymonitor/chart/section/consumption.component.ts b/ui/src/app/edge/live/energymonitor/chart/section/consumption.component.ts index f437f59fb88..5fc5be23e8c 100644 --- a/ui/src/app/edge/live/energymonitor/chart/section/consumption.component.ts +++ b/ui/src/app/edge/live/energymonitor/chart/section/consumption.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { animate, state, style, transition, trigger } from '@angular/animations'; import { Component, OnDestroy, OnInit } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; diff --git a/ui/src/app/edge/live/energymonitor/chart/section/grid.component.ts b/ui/src/app/edge/live/energymonitor/chart/section/grid.component.ts index f02cef40162..a4ddb265ebc 100644 --- a/ui/src/app/edge/live/energymonitor/chart/section/grid.component.ts +++ b/ui/src/app/edge/live/energymonitor/chart/section/grid.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { animate, state, style, transition, trigger } from '@angular/animations'; import { Component, OnDestroy, OnInit } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; diff --git a/ui/src/app/edge/live/energymonitor/chart/section/production.component.ts b/ui/src/app/edge/live/energymonitor/chart/section/production.component.ts index becd9c8b94a..655204788d6 100644 --- a/ui/src/app/edge/live/energymonitor/chart/section/production.component.ts +++ b/ui/src/app/edge/live/energymonitor/chart/section/production.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { animate, state, style, transition, trigger } from '@angular/animations'; import { Component, OnDestroy, OnInit } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; diff --git a/ui/src/app/edge/live/energymonitor/chart/section/storage.component.ts b/ui/src/app/edge/live/energymonitor/chart/section/storage.component.ts index 12e8f547495..0391ff3990e 100644 --- a/ui/src/app/edge/live/energymonitor/chart/section/storage.component.ts +++ b/ui/src/app/edge/live/energymonitor/chart/section/storage.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { animate, state, style, transition, trigger } from '@angular/animations'; import { Component, OnDestroy, OnInit } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; diff --git a/ui/src/app/edge/live/energymonitor/energymonitor.component.ts b/ui/src/app/edge/live/energymonitor/energymonitor.component.ts index 65521679073..ef8122fb281 100644 --- a/ui/src/app/edge/live/energymonitor/energymonitor.component.ts +++ b/ui/src/app/edge/live/energymonitor/energymonitor.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { ChannelAddress, Edge, Service, Websocket } from '../../../shared/shared'; diff --git a/ui/src/app/edge/live/live.component.ts b/ui/src/app/edge/live/live.component.ts index 15c1ccafd52..8f36b79cb9f 100644 --- a/ui/src/app/edge/live/live.component.ts +++ b/ui/src/app/edge/live/live.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Subject } from 'rxjs'; diff --git a/ui/src/app/edge/live/live.module.ts b/ui/src/app/edge/live/live.module.ts index d07a7dec8d8..62c2a8b672e 100644 --- a/ui/src/app/edge/live/live.module.ts +++ b/ui/src/app/edge/live/live.module.ts @@ -61,24 +61,6 @@ import { Controller_Evcs } from './Controller/Evcs/Evcs'; Controller_Evcs, Controller_Ess_TimeOfUseTariff, ], - entryComponents: [ - AdministrationComponent, - Controller_Asymmetric_PeakShavingModalComponent, - Controller_ChpSocComponent, - Controller_ChpSocModalComponent, - Controller_Io_ChannelSingleThresholdComponent, - Controller_Io_ChannelSingleThresholdModalComponent, - Controller_Io_FixDigitalOutputComponent, - Controller_Io_FixDigitalOutputModalComponent, - Controller_Io_HeatpumpModalComponent, - Controller_Symmetric_PeakShavingComponent, - Controller_Symmetric_TimeSlot_PeakShavingModalComponent, - DelayedSellToGridModalComponent, - Evcs_Api_ClusterModalComponent, - Io_Api_DigitalInput_ModalComponent, - Io_Api_DigitalInputComponent, - StorageModalComponent, - ], declarations: [ AdministrationComponent, Controller_Asymmetric_PeakShavingComponent, diff --git a/ui/src/app/edge/live/livedataservice.ts b/ui/src/app/edge/live/livedataservice.ts index 82f9578245b..6dd0c30ddbe 100644 --- a/ui/src/app/edge/live/livedataservice.ts +++ b/ui/src/app/edge/live/livedataservice.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Directive, Inject, OnDestroy } from "@angular/core"; import { takeUntil } from "rxjs/operators"; import { v4 as uuidv4 } from 'uuid'; diff --git a/ui/src/app/edge/settings/alerting/alerting.component.ts b/ui/src/app/edge/settings/alerting/alerting.component.ts index 62b1a96f77c..cf41c78d8a5 100644 --- a/ui/src/app/edge/settings/alerting/alerting.component.ts +++ b/ui/src/app/edge/settings/alerting/alerting.component.ts @@ -1,11 +1,11 @@ -import { User } from 'src/app/shared/jsonrpc/shared'; +// @ts-strict-ignore import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormControl, FormGroup } from '@angular/forms'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; -import { SetUserAlertingConfigsRequest, UserSettingRequest } from 'src/app/shared/jsonrpc/request/setUserAlertingConfigsRequest'; import { GetUserAlertingConfigsRequest } from 'src/app/shared/jsonrpc/request/getUserAlertingConfigsRequest'; -import { GetUserAlertingConfigsResponse, AlertingSettingResponse } from 'src/app/shared/jsonrpc/response/getUserAlertingConfigsResponse'; +import { SetUserAlertingConfigsRequest, UserSettingRequest } from 'src/app/shared/jsonrpc/request/setUserAlertingConfigsRequest'; +import { AlertingSettingResponse, GetUserAlertingConfigsResponse } from 'src/app/shared/jsonrpc/response/getUserAlertingConfigsResponse'; import { Edge, Service, Utils, Websocket } from 'src/app/shared/shared'; export enum AlertingType { @@ -32,7 +32,6 @@ export class AlertingComponent implements OnInit { protected readonly defaultValues: DefaultValues; protected edge: Edge; - protected user: User; protected error: Error; protected currentUserInformation: DetailedAlertingSetting; @@ -60,10 +59,6 @@ export class AlertingComponent implements OnInit { this.service.setCurrentComponent({ languageKey: 'Edge.Config.Index.alerting' }, this.route).then(edge => { this.edge = edge; - this.service.metadata.subscribe(metadata => { - this.user = metadata.user; - }); - const request = new GetUserAlertingConfigsRequest({ edgeId: this.edge.id }); this.sendRequest(request).then(response => { diff --git a/ui/src/app/edge/settings/app/app.module.ts b/ui/src/app/edge/settings/app/app.module.ts index 0a46bb809d3..3b12184a7ed 100644 --- a/ui/src/app/edge/settings/app/app.module.ts +++ b/ui/src/app/edge/settings/app/app.module.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { NgModule } from '@angular/core'; import { SharedModule } from 'src/app/shared/shared.module'; import { InstallAppComponent } from './install.component'; diff --git a/ui/src/app/edge/settings/app/formly/option-group-picker/formly-option-group-picker.component.ts b/ui/src/app/edge/settings/app/formly/option-group-picker/formly-option-group-picker.component.ts index ca942bdc65c..0141269e76d 100644 --- a/ui/src/app/edge/settings/app/formly/option-group-picker/formly-option-group-picker.component.ts +++ b/ui/src/app/edge/settings/app/formly/option-group-picker/formly-option-group-picker.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnInit } from "@angular/core"; import { FieldType, FieldTypeConfig, FormlyFieldConfig } from "@ngx-formly/core"; import { OptionGroup, OptionGroupConfig, Option, getTitleFromOptionConfig } from "./optionGroupPickerConfiguration"; diff --git a/ui/src/app/edge/settings/app/formly/reorder-select/formly-reorder-array.component.ts b/ui/src/app/edge/settings/app/formly/reorder-select/formly-reorder-array.component.ts index fd328a69a62..04cb6f3138b 100644 --- a/ui/src/app/edge/settings/app/formly/reorder-select/formly-reorder-array.component.ts +++ b/ui/src/app/edge/settings/app/formly/reorder-select/formly-reorder-array.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnInit } from "@angular/core"; import { ItemReorderEventDetail } from "@ionic/angular"; import { FieldType, FieldTypeConfig, FormlyFieldConfig, FormlyFieldProps } from "@ngx-formly/core"; diff --git a/ui/src/app/edge/settings/app/formly/safe-input/formly-safe-input-modal.component.ts b/ui/src/app/edge/settings/app/formly/safe-input/formly-safe-input-modal.component.ts index b1396ed9d1c..745dcf43183 100644 --- a/ui/src/app/edge/settings/app/formly/safe-input/formly-safe-input-modal.component.ts +++ b/ui/src/app/edge/settings/app/formly/safe-input/formly-safe-input-modal.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnInit } from "@angular/core"; import { FormGroup } from "@angular/forms"; import { ModalController } from "@ionic/angular"; diff --git a/ui/src/app/edge/settings/app/formly/safe-input/formly-safe-input.extended.ts b/ui/src/app/edge/settings/app/formly/safe-input/formly-safe-input.extended.ts index af18e0ba539..4470534d432 100644 --- a/ui/src/app/edge/settings/app/formly/safe-input/formly-safe-input.extended.ts +++ b/ui/src/app/edge/settings/app/formly/safe-input/formly-safe-input.extended.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnInit } from "@angular/core"; import { ModalController } from "@ionic/angular"; import { FieldWrapper, FormlyFieldConfig } from "@ngx-formly/core"; diff --git a/ui/src/app/edge/settings/app/index.component.ts b/ui/src/app/edge/settings/app/index.component.ts index e66a84813d1..b29368b81af 100644 --- a/ui/src/app/edge/settings/app/index.component.ts +++ b/ui/src/app/edge/settings/app/index.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { IonPopover, ModalController } from '@ionic/angular'; diff --git a/ui/src/app/edge/settings/app/install.component.ts b/ui/src/app/edge/settings/app/install.component.ts index 6734b5ead43..53a719c8218 100644 --- a/ui/src/app/edge/settings/app/install.component.ts +++ b/ui/src/app/edge/settings/app/install.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnDestroy, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; diff --git a/ui/src/app/edge/settings/app/jsonrpc/getAppAssistant.spec.ts b/ui/src/app/edge/settings/app/jsonrpc/getAppAssistant.spec.ts index 6f008936224..5e76d319812 100644 --- a/ui/src/app/edge/settings/app/jsonrpc/getAppAssistant.spec.ts +++ b/ui/src/app/edge/settings/app/jsonrpc/getAppAssistant.spec.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { GetAppAssistant } from "./getAppAssistant"; import { FormlyFieldConfig } from "@ngx-formly/core"; diff --git a/ui/src/app/edge/settings/app/jsonrpc/getAppAssistant.ts b/ui/src/app/edge/settings/app/jsonrpc/getAppAssistant.ts index d3c6e1777ff..1e8088be0b9 100644 --- a/ui/src/app/edge/settings/app/jsonrpc/getAppAssistant.ts +++ b/ui/src/app/edge/settings/app/jsonrpc/getAppAssistant.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { AbstractControl } from "@angular/forms"; import { FormlyFieldConfig } from "@ngx-formly/core"; 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 e79bed2646d..d94779ef5c8 100644 --- a/ui/src/app/edge/settings/app/keypopup/modal.component.ts +++ b/ui/src/app/edge/settings/app/keypopup/modal.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { Router } from '@angular/router'; diff --git a/ui/src/app/edge/settings/app/single.component.ts b/ui/src/app/edge/settings/app/single.component.ts index 0f6ffb92983..bacbbf39ceb 100644 --- a/ui/src/app/edge/settings/app/single.component.ts +++ b/ui/src/app/edge/settings/app/single.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, HostListener, OnDestroy, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { DomSanitizer } from '@angular/platform-browser'; diff --git a/ui/src/app/edge/settings/app/update.component.ts b/ui/src/app/edge/settings/app/update.component.ts index 82c1817b320..f097862c3ba 100644 --- a/ui/src/app/edge/settings/app/update.component.ts +++ b/ui/src/app/edge/settings/app/update.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; diff --git a/ui/src/app/edge/settings/channels/channels.component.ts b/ui/src/app/edge/settings/channels/channels.component.ts index 436173cd76a..2709b475a2e 100644 --- a/ui/src/app/edge/settings/channels/channels.component.ts +++ b/ui/src/app/edge/settings/channels/channels.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; @@ -77,7 +78,7 @@ export class ChannelsComponent { return; } - if (PersistencePriority.isAtLeast(channelConfig.persistencePriority, globalPersistencePriority)) { + if (PersistencePriority.isLessThan(channelConfig.persistencePriority, globalPersistencePriority)) { this.componentChannelConfig.set(address.toString(), { ...this.config.getChannel(address), ...{ showPersistencePriority: true } }); } } diff --git a/ui/src/app/edge/settings/component/install/index.component.ts b/ui/src/app/edge/settings/component/install/index.component.ts index e15b516c35a..147379b3235 100644 --- a/ui/src/app/edge/settings/component/install/index.component.ts +++ b/ui/src/app/edge/settings/component/install/index.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { ActivatedRoute } from '@angular/router'; import { CategorizedFactories } from 'src/app/shared/edge/edgeconfig'; import { Component, OnInit } from '@angular/core'; diff --git a/ui/src/app/edge/settings/component/install/install.component.ts b/ui/src/app/edge/settings/component/install/install.component.ts index 40ede1a058a..89ad5585219 100644 --- a/ui/src/app/edge/settings/component/install/install.component.ts +++ b/ui/src/app/edge/settings/component/install/install.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { ActivatedRoute } from '@angular/router'; import { Component, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; diff --git a/ui/src/app/edge/settings/component/update/index.component.ts b/ui/src/app/edge/settings/component/update/index.component.ts index c8eb4efa668..fcec4e80b41 100644 --- a/ui/src/app/edge/settings/component/update/index.component.ts +++ b/ui/src/app/edge/settings/component/update/index.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { CategorizedComponents } from 'src/app/shared/edge/edgeconfig'; diff --git a/ui/src/app/edge/settings/component/update/update.component.ts b/ui/src/app/edge/settings/component/update/update.component.ts index 4e7cb09fc02..e4e0f1b7f5b 100644 --- a/ui/src/app/edge/settings/component/update/update.component.ts +++ b/ui/src/app/edge/settings/component/update/update.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { ActivatedRoute } from '@angular/router'; import { Component, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; diff --git a/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.ts b/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.ts index 9fe0119358c..ce87c5b6db7 100644 --- a/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.ts +++ b/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { ActivatedRoute } from '@angular/router'; diff --git a/ui/src/app/edge/settings/network/network.component.ts b/ui/src/app/edge/settings/network/network.component.ts index 3be20a409e9..6d56284c258 100644 --- a/ui/src/app/edge/settings/network/network.component.ts +++ b/ui/src/app/edge/settings/network/network.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { ActivatedRoute } from '@angular/router'; diff --git a/ui/src/app/edge/settings/profile/aliasupdate.component.ts b/ui/src/app/edge/settings/profile/aliasupdate.component.ts index d916b716704..43c62955fbe 100644 --- a/ui/src/app/edge/settings/profile/aliasupdate.component.ts +++ b/ui/src/app/edge/settings/profile/aliasupdate.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormControl, FormGroup } from '@angular/forms'; import { ActivatedRoute } from '@angular/router'; diff --git a/ui/src/app/edge/settings/profile/modbusapi/getModbusProtocolResponse.ts b/ui/src/app/edge/settings/profile/modbusapi/getModbusProtocolResponse.ts index d1bbe48e7c7..cc25ca0bbb9 100644 --- a/ui/src/app/edge/settings/profile/modbusapi/getModbusProtocolResponse.ts +++ b/ui/src/app/edge/settings/profile/modbusapi/getModbusProtocolResponse.ts @@ -22,8 +22,8 @@ import { JsonrpcResponseSuccess } from '../../../../shared/jsonrpc/base'; export class GetModbusProtocolResponse extends JsonrpcResponseSuccess { public constructor( - public readonly id: string, - public readonly result: { + public override readonly id: string, + public override readonly result: { table: [{ ref: number, name: string, diff --git a/ui/src/app/edge/settings/profile/profile.component.ts b/ui/src/app/edge/settings/profile/profile.component.ts index baba0377806..73b75bfab1d 100644 --- a/ui/src/app/edge/settings/profile/profile.component.ts +++ b/ui/src/app/edge/settings/profile/profile.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { PopoverController } from '@ionic/angular'; diff --git a/ui/src/app/edge/settings/settings.component.ts b/ui/src/app/edge/settings/settings.component.ts index 5f5d0ac7d90..04bc4542cc9 100644 --- a/ui/src/app/edge/settings/settings.component.ts +++ b/ui/src/app/edge/settings/settings.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { environment } from 'src/environments'; diff --git a/ui/src/app/edge/settings/settings.module.ts b/ui/src/app/edge/settings/settings.module.ts index 05f8222e512..a98f0f24b3d 100644 --- a/ui/src/app/edge/settings/settings.module.ts +++ b/ui/src/app/edge/settings/settings.module.ts @@ -42,8 +42,6 @@ import { SystemExecuteComponent } from './systemexecute/systemexecute.component' SystemComponent, SystemExecuteComponent, ], - entryComponents: [ - ], exports: [ OeSystemUpdateComponent, ], diff --git a/ui/src/app/edge/settings/system/executeSystemUpdate.ts b/ui/src/app/edge/settings/system/executeSystemUpdate.ts index b237ec5149b..00b806ce07c 100644 --- a/ui/src/app/edge/settings/system/executeSystemUpdate.ts +++ b/ui/src/app/edge/settings/system/executeSystemUpdate.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Subject, timer } from "rxjs"; import { takeUntil } from "rxjs/operators"; import { ComponentJsonApiRequest } from "src/app/shared/jsonrpc/request/componentJsonApiRequest"; diff --git a/ui/src/app/edge/settings/system/executesystemupdate.component.ts b/ui/src/app/edge/settings/system/executesystemupdate.component.ts index b2f8c2e35af..8ec0694b34e 100644 --- a/ui/src/app/edge/settings/system/executesystemupdate.component.ts +++ b/ui/src/app/edge/settings/system/executesystemupdate.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'; import { Edge, Service, Websocket } from 'src/app/shared/shared'; import { environment } from 'src/environments'; diff --git a/ui/src/app/edge/settings/system/maintenance/maintenance.ts b/ui/src/app/edge/settings/system/maintenance/maintenance.ts index 9f74a0846b0..34e27d47c15 100644 --- a/ui/src/app/edge/settings/system/maintenance/maintenance.ts +++ b/ui/src/app/edge/settings/system/maintenance/maintenance.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnInit } from '@angular/core'; import { AlertController } from '@ionic/angular'; import { TranslateService } from '@ngx-translate/core'; diff --git a/ui/src/app/edge/settings/system/oe-system-update.component.ts b/ui/src/app/edge/settings/system/oe-system-update.component.ts index d08c16bc6ff..fe7847136fc 100644 --- a/ui/src/app/edge/settings/system/oe-system-update.component.ts +++ b/ui/src/app/edge/settings/system/oe-system-update.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'; import { Edge, Service, Websocket } from 'src/app/shared/shared'; import { environment } from 'src/environments'; diff --git a/ui/src/app/edge/settings/system/system.component.ts b/ui/src/app/edge/settings/system/system.component.ts index c88f08fb295..11c23429957 100644 --- a/ui/src/app/edge/settings/system/system.component.ts +++ b/ui/src/app/edge/settings/system/system.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { environment } from 'src/environments'; diff --git a/ui/src/app/edge/settings/systemexecute/systemexecute.component.ts b/ui/src/app/edge/settings/systemexecute/systemexecute.component.ts index abbf8083096..00db9a6ec92 100644 --- a/ui/src/app/edge/settings/systemexecute/systemexecute.component.ts +++ b/ui/src/app/edge/settings/systemexecute/systemexecute.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormControl, FormGroup } from '@angular/forms'; import { ActivatedRoute } from '@angular/router'; diff --git a/ui/src/app/edge/settings/systemlog/systemlog.component.ts b/ui/src/app/edge/settings/systemlog/systemlog.component.ts index 1eac0d407fc..2785a1df4b7 100644 --- a/ui/src/app/edge/settings/systemlog/systemlog.component.ts +++ b/ui/src/app/edge/settings/systemlog/systemlog.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { ActivatedRoute } from '@angular/router'; import { Component, OnDestroy, OnInit } from '@angular/core'; import { parse } from 'date-fns'; diff --git a/ui/src/app/index/filter/filter.component.ts b/ui/src/app/index/filter/filter.component.ts index 9015a779216..a7598c9c8e2 100644 --- a/ui/src/app/index/filter/filter.component.ts +++ b/ui/src/app/index/filter/filter.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, EventEmitter, Output } from "@angular/core"; import { TranslateService } from "@ngx-translate/core"; import { TKeyValue } from "src/app/shared/service/defaulttypes"; diff --git a/ui/src/app/index/login.component.ts b/ui/src/app/index/login.component.ts index b6f489c6562..4cb1c9ff054 100644 --- a/ui/src/app/index/login.component.ts +++ b/ui/src/app/index/login.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { AfterContentChecked, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; diff --git a/ui/src/app/index/login.spec.ts b/ui/src/app/index/login.spec.ts index c41303affae..47f64346695 100644 --- a/ui/src/app/index/login.spec.ts +++ b/ui/src/app/index/login.spec.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { LoginComponent } from "./login.component"; describe('Login', () => { diff --git a/ui/src/app/index/overview/overview.component.ts b/ui/src/app/index/overview/overview.component.ts index 5e8139ce097..cdd0eecbf7f 100644 --- a/ui/src/app/index/overview/overview.component.ts +++ b/ui/src/app/index/overview/overview.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnDestroy, OnInit } from "@angular/core"; import { FormGroup } from "@angular/forms"; import { ActivatedRoute, Router } from "@angular/router"; @@ -82,7 +83,6 @@ export class OverViewComponent implements OnInit, OnDestroy { this.loadNextPage().then((edges) => { this.filteredEdges = edges; - this.page++; }); } diff --git a/ui/src/app/registration/modal/modal.component.ts b/ui/src/app/registration/modal/modal.component.ts index 4589f3f6d5a..a52284aa166 100644 --- a/ui/src/app/registration/modal/modal.component.ts +++ b/ui/src/app/registration/modal/modal.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import { ModalController } from '@ionic/angular'; diff --git a/ui/src/app/shared/chartoptions/chartoptions.component.ts b/ui/src/app/shared/chartoptions/chartoptions.component.ts index 713a05edf1f..d7cefe3fd04 100644 --- a/ui/src/app/shared/chartoptions/chartoptions.component.ts +++ b/ui/src/app/shared/chartoptions/chartoptions.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { ChartOptionsPopoverComponent } from './popover/popover.component'; import { Component, EventEmitter, Input, Output } from '@angular/core'; import { PopoverController } from '@ionic/angular'; diff --git a/ui/src/app/shared/directive/directive.ts b/ui/src/app/shared/directive/directive.ts index 4e7a62bcafb..ae075455c1a 100644 --- a/ui/src/app/shared/directive/directive.ts +++ b/ui/src/app/shared/directive/directive.ts @@ -6,9 +6,6 @@ import { VarDirective } from './ngvar'; imports: [ BrowserModule, ], - entryComponents: [ - VarDirective, - ], declarations: [ VarDirective, ], diff --git a/ui/src/app/shared/edge/currentdata.ts b/ui/src/app/shared/edge/currentdata.ts index fb71949ab7b..82b9ae647d7 100644 --- a/ui/src/app/shared/edge/currentdata.ts +++ b/ui/src/app/shared/edge/currentdata.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { DefaultTypes } from "../service/defaulttypes"; import { Utils } from "../service/utils"; diff --git a/ui/src/app/shared/edge/edge.ts b/ui/src/app/shared/edge/edge.ts index 3d4640e5419..6be4ef0e4da 100644 --- a/ui/src/app/shared/edge/edge.ts +++ b/ui/src/app/shared/edge/edge.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { compareVersions } from 'compare-versions'; import { BehaviorSubject, Subject } from 'rxjs'; import { SumState } from 'src/app/index/shared/sumState'; diff --git a/ui/src/app/shared/edge/edgeconfig.spec.ts b/ui/src/app/shared/edge/edgeconfig.spec.ts index 38233fe962b..9b6a9bb0b99 100644 --- a/ui/src/app/shared/edge/edgeconfig.spec.ts +++ b/ui/src/app/shared/edge/edgeconfig.spec.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { TimeUnit } from "chart.js"; import { SumState } from "src/app/index/shared/sumState"; @@ -5,7 +6,7 @@ import { TextIndentation } from "../genericComponents/modal/modal-line/modal-lin import { OeChartTester, OeFormlyViewTester } from "../genericComponents/shared/testing/tester"; import { Role } from "../type/role"; import { Edge } from "./edge"; -import { EdgeConfig } from "./edgeconfig"; +import { EdgeConfig, PersistencePriority } from "./edgeconfig"; export namespace DummyConfig { @@ -301,3 +302,14 @@ export namespace ChartConfig { }, }); } + +describe('PersistencePriority', () => { + it('#isLessThan', () => { + expect(PersistencePriority.isLessThan(PersistencePriority.LOW, PersistencePriority.HIGH)).toBe(true); + expect(PersistencePriority.isLessThan(PersistencePriority.VERY_HIGH, PersistencePriority.HIGH)).toBe(false); + expect(PersistencePriority.isLessThan(PersistencePriority.HIGH, PersistencePriority.HIGH)).toBe(false); + expect(PersistencePriority.isLessThan(null, PersistencePriority.HIGH)).toBe(false); + expect(PersistencePriority.isLessThan(undefined, PersistencePriority.HIGH)).toBe(false); + expect(PersistencePriority.isLessThan(undefined, null)).toBe(false); + }); +}); diff --git a/ui/src/app/shared/edge/edgeconfig.ts b/ui/src/app/shared/edge/edgeconfig.ts index 67084f8d382..ebeec7e0231 100644 --- a/ui/src/app/shared/edge/edgeconfig.ts +++ b/ui/src/app/shared/edge/edgeconfig.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { ChannelAddress } from '../type/channeladdress'; import { Widgets } from '../type/widget'; import { Edge } from './edge'; @@ -635,11 +636,18 @@ export namespace PersistencePriority { export const DEFAULT_CHANNEL_PRIORITY: string = PersistencePriority.VERY_LOW; export const DEFAULT_GLOBAL_PRIORITY: string = PersistencePriority.HIGH; - export function isAtLeast(prio1: string, prio2: string) { + /** + * Checks if given prio1 is less than prio2 + * + * @param prio1 the prio that will be compared + * @param prio2 the prio to compare it to + * @returns true if prio1 is less than prio2 + */ + export function isLessThan(prio1: string, prio2: string): boolean { if (typeof prio1 !== 'string' || typeof prio2 !== 'string') { return false; } - return Object.keys(PersistencePriority).indexOf(prio1) <= Object.keys(PersistencePriority).indexOf(prio2); + return Object.keys(PersistencePriority).indexOf(prio1) < Object.keys(PersistencePriority).indexOf(prio2); } } diff --git a/ui/src/app/shared/edge/meter/esscharger/modal.component.ts b/ui/src/app/shared/edge/meter/esscharger/modal.component.ts index 2af44c5b692..594394991e8 100644 --- a/ui/src/app/shared/edge/meter/esscharger/modal.component.ts +++ b/ui/src/app/shared/edge/meter/esscharger/modal.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input } from '@angular/core'; import { Converter } from 'src/app/shared/genericComponents/shared/converter'; import { Utils } from 'src/app/shared/shared'; diff --git a/ui/src/app/shared/edge/meter/meter.module.ts b/ui/src/app/shared/edge/meter/meter.module.ts index f4a3e900bbb..5ecef0c6bd7 100644 --- a/ui/src/app/shared/edge/meter/meter.module.ts +++ b/ui/src/app/shared/edge/meter/meter.module.ts @@ -14,8 +14,6 @@ import { EssChargerComponent } from "./esscharger/modal.component"; PipeModule, Generic_ComponentsModule, ], - entryComponents: [ - ], declarations: [ ElectricityMeterComponent, EssChargerComponent, diff --git a/ui/src/app/shared/footer/footer.html b/ui/src/app/shared/footer/footer.html index 44f7cf74119..1ff1460ea74 100644 --- a/ui/src/app/shared/footer/footer.html +++ b/ui/src/app/shared/footer/footer.html @@ -3,7 +3,7 @@ - + {{displayValues.comment}} | diff --git a/ui/src/app/shared/footer/footer.ts b/ui/src/app/shared/footer/footer.ts index a2445cd05b1..38539365640 100644 --- a/ui/src/app/shared/footer/footer.ts +++ b/ui/src/app/shared/footer/footer.ts @@ -10,6 +10,7 @@ import { Role } from "../type/role"; @Component({ selector: 'oe-footer', styles: [` + :host[data-isSmartPhone=true] { position: relative; } @@ -18,16 +19,16 @@ import { Role } from "../type/role"; position: sticky; bottom: 0; width: 100%; - font-size: 14px !important; - } - ion-row { - text-align: center; - } + font-size: 14px !important; + ion-row { + text-align: center; + } - ion-item { - --min-height: initial !important; - font-size: inherit; + ion-item { + --min-height: initial !important; + font-size: inherit; + } } `], templateUrl: 'footer.html', @@ -36,7 +37,7 @@ export class FooterComponent implements OnInit { protected user: User | null = null; protected edge: Edge | null = null; - protected displayValues: { version: string, id: string, comment: string } | null = null; + protected displayValues: { comment: string, id: string, version: string } | null = null; protected isAtLeastOwner: boolean | null = null; @HostBinding('attr.data-isSmartPhone') @@ -56,7 +57,7 @@ export class FooterComponent implements OnInit { let title = environment.edgeShortName; if (edge) { - this.displayValues = FooterComponent.getDisplayValues(edge); + this.displayValues = FooterComponent.getDisplayValues(this.user, edge); if (this.user.hasMultipleEdges) { title += " | " + edge.id; @@ -64,16 +65,30 @@ export class FooterComponent implements OnInit { } this.title.setTitle(title); - this.isAtLeastOwner = Role.isAtLeast(this.user.globalRole, Role.OWNER); }); }); } - private static getDisplayValues(edge: Edge): { version: string; id: string; comment: string; } { - return { - comment: edge?.comment, - id: edge.id, + private static getDisplayValues(user: User, edge: Edge): { comment: string, id: string, version: string } { + const result = { + comment: "", + id: "", version: edge.version, }; + + switch (environment.backend) { + case "OpenEMS Backend": + if (Role.isAtLeast(user.globalRole, Role.OWNER) && user.hasMultipleEdges) { + result.comment = edge?.comment; + } + result.id = edge.id; + break; + + case "OpenEMS Edge": + result.id = environment.edgeShortName; + break; + } + + return result; } } diff --git a/ui/src/app/shared/formly/form-field-checkbox-hyperlink/form-field-checkbox-hyperlink.wrapper.ts b/ui/src/app/shared/formly/form-field-checkbox-hyperlink/form-field-checkbox-hyperlink.wrapper.ts index 0270cd13836..c923b6718f3 100644 --- a/ui/src/app/shared/formly/form-field-checkbox-hyperlink/form-field-checkbox-hyperlink.wrapper.ts +++ b/ui/src/app/shared/formly/form-field-checkbox-hyperlink/form-field-checkbox-hyperlink.wrapper.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, ChangeDetectionStrategy, OnInit } from '@angular/core'; import { FieldWrapper } from '@ngx-formly/core'; diff --git a/ui/src/app/shared/formly/form-field-default-cases.wrapper.ts b/ui/src/app/shared/formly/form-field-default-cases.wrapper.ts index e99cb765b1e..0b649c05ac8 100644 --- a/ui/src/app/shared/formly/form-field-default-cases.wrapper.ts +++ b/ui/src/app/shared/formly/form-field-default-cases.wrapper.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnInit } from '@angular/core'; import { AbstractControl } from '@angular/forms'; import { FieldWrapper } from '@ngx-formly/core'; diff --git a/ui/src/app/shared/formly/formly-field-checkbox-image/formly-field-checkbox-with-image.html b/ui/src/app/shared/formly/formly-field-checkbox-image/formly-field-checkbox-with-image.html index 4cd06e749bb..e48b0e25839 100644 --- a/ui/src/app/shared/formly/formly-field-checkbox-image/formly-field-checkbox-with-image.html +++ b/ui/src/app/shared/formly/formly-field-checkbox-image/formly-field-checkbox-with-image.html @@ -10,12 +10,10 @@ - - - - + + + - - \ No newline at end of file + diff --git a/ui/src/app/shared/formly/formly-select-field-modal.component.ts b/ui/src/app/shared/formly/formly-select-field-modal.component.ts index 97128d2f62b..d2a72af4576 100644 --- a/ui/src/app/shared/formly/formly-select-field-modal.component.ts +++ b/ui/src/app/shared/formly/formly-select-field-modal.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnInit } from "@angular/core"; import { ModalController } from "@ionic/angular"; diff --git a/ui/src/app/shared/formly/formly-skeleton-wrapper.ts b/ui/src/app/shared/formly/formly-skeleton-wrapper.ts index b7e953ac752..fdc339aebae 100644 --- a/ui/src/app/shared/formly/formly-skeleton-wrapper.ts +++ b/ui/src/app/shared/formly/formly-skeleton-wrapper.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { FormlyFieldConfig } from '@ngx-formly/core'; diff --git a/ui/src/app/shared/genericComponents/abstracthistorywidget.ts b/ui/src/app/shared/genericComponents/abstracthistorywidget.ts index fef3a8d65a0..6786e3e0417 100644 --- a/ui/src/app/shared/genericComponents/abstracthistorywidget.ts +++ b/ui/src/app/shared/genericComponents/abstracthistorywidget.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Directive, Inject, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { ModalController } from '@ionic/angular'; diff --git a/ui/src/app/shared/genericComponents/chart/abstractHistoryChartOverview.ts b/ui/src/app/shared/genericComponents/chart/abstractHistoryChartOverview.ts index 420d25601c5..ed4e296eb30 100644 --- a/ui/src/app/shared/genericComponents/chart/abstractHistoryChartOverview.ts +++ b/ui/src/app/shared/genericComponents/chart/abstractHistoryChartOverview.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Directive, OnChanges, OnDestroy, OnInit } from "@angular/core"; import { ActivatedRoute } from "@angular/router"; import { ModalController } from "@ionic/angular"; diff --git a/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts b/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts index 811ccaa256b..c64b512460b 100644 --- a/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts +++ b/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { DecimalPipe, formatNumber } from '@angular/common'; import { ChangeDetectorRef, Directive, Input, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; @@ -544,7 +545,7 @@ export abstract class AbstractHistoryChart implements OnInit { * @returns options */ public static getOptions(chartObject: HistoryUtils.ChartData, chartType: 'line' | 'bar', service: Service, - translate: TranslateService, legendOptions: { label: string, strokeThroughHidingStyle: boolean }[], channelData: { data: { [name: string]: number[] } }, locale: string, config: EdgeConfig, datasets: Chart.ChartDataset[]): Chart.ChartOptions { + translate: TranslateService, legendOptions: { label: string, strokeThroughHidingStyle: boolean }[], channelData: { data: { [name: string]: number[] } }, locale: string, config: EdgeConfig): Chart.ChartOptions { let tooltipsLabel: string | null = null; let options: Chart.ChartOptions = Utils.deepCopy(Utils.deepCopy(DEFAULT_TIME_CHART_OPTIONS)); @@ -552,8 +553,7 @@ export abstract class AbstractHistoryChart implements OnInit { const showYAxisTitle: boolean = chartObject.yAxes.length > 1; chartObject.yAxes.forEach((element) => { - const scaleOptions: { min: number, max: number, stepSize: number } | null = ChartConstants.getScaleOptions(datasets, element); - options = AbstractHistoryChart.getYAxisOptions(options, element, translate, chartType, locale, showYAxisTitle, scaleOptions); + options = AbstractHistoryChart.getYAxisOptions(options, element, translate, chartType, locale, showYAxisTitle); }); options.plugins.tooltip.callbacks.title = (tooltipItems: Chart.TooltipItem[]): string => { @@ -697,7 +697,7 @@ export abstract class AbstractHistoryChart implements OnInit { * @param locale the current locale * @returns the chart options {@link Chart.ChartOptions} */ - public static getYAxisOptions(options: Chart.ChartOptions, element: HistoryUtils.yAxes, translate: TranslateService, chartType: 'line' | 'bar', locale: string, showYAxisTitle?: boolean, data?: { min: number, max: number, stepSize: number }): Chart.ChartOptions { + public static getYAxisOptions(options: Chart.ChartOptions, element: HistoryUtils.yAxes, translate: TranslateService, chartType: 'line' | 'bar', locale: string, showYAxisTitle?: boolean): Chart.ChartOptions { const baseConfig = { title: { @@ -712,14 +712,10 @@ export abstract class AbstractHistoryChart implements OnInit { grid: { display: element.displayGrid ?? true, }, - ...(data?.min != null && { min: data.min }), - ...(data?.max != null && { max: data.max }), - ticks: { color: getComputedStyle(document.documentElement).getPropertyValue('--ion-color-text'), padding: 5, maxTicksLimit: ChartConstants.NUMBER_OF_Y_AXIS_TICKS, - ...(data?.stepSize && { stepSize: data.stepSize }), }, }; @@ -773,7 +769,7 @@ export abstract class AbstractHistoryChart implements OnInit { ticks: { ...baseConfig.ticks, padding: 5, - stepSize: 25, + stepSize: 20, }, }; break; @@ -818,7 +814,7 @@ export abstract class AbstractHistoryChart implements OnInit { */ protected setChartLabel() { const locale = this.service.translate.currentLang; - this.options = AbstractHistoryChart.getOptions(this.chartObject, this.chartType, this.service, this.translate, this.legendOptions, this.channelData, locale, this.config, this.datasets); + this.options = AbstractHistoryChart.getOptions(this.chartObject, this.chartType, this.service, this.translate, this.legendOptions, this.channelData, locale, this.config); this.loading = false; this.stopSpinner(); } diff --git a/ui/src/app/shared/genericComponents/chart/chart.constants.spec.ts b/ui/src/app/shared/genericComponents/chart/chart.constants.spec.ts index 7024335ee16..275330f89a6 100644 --- a/ui/src/app/shared/genericComponents/chart/chart.constants.spec.ts +++ b/ui/src/app/shared/genericComponents/chart/chart.constants.spec.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { ChartDataset } from "chart.js"; import { History } from "src/app/edge/history/common/energy/chart/channels.spec"; diff --git a/ui/src/app/shared/genericComponents/chart/chart.constants.ts b/ui/src/app/shared/genericComponents/chart/chart.constants.ts index f239cbaf399..ebc7711ee78 100644 --- a/ui/src/app/shared/genericComponents/chart/chart.constants.ts +++ b/ui/src/app/shared/genericComponents/chart/chart.constants.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { ChartDataset } from "chart.js"; import { ArrayUtils } from "../../utils/array/array.utils"; diff --git a/ui/src/app/shared/genericComponents/chart/chart.ts b/ui/src/app/shared/genericComponents/chart/chart.ts index 0927c4f0409..35436b36467 100644 --- a/ui/src/app/shared/genericComponents/chart/chart.ts +++ b/ui/src/app/shared/genericComponents/chart/chart.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, OnInit, Output } from "@angular/core"; import { ActivatedRoute } from "@angular/router"; import { ModalController, PopoverController } from "@ionic/angular"; diff --git a/ui/src/app/shared/genericComponents/flat/abstract-flat-widget-line.ts b/ui/src/app/shared/genericComponents/flat/abstract-flat-widget-line.ts index e3929bd9860..c390e2f6459 100644 --- a/ui/src/app/shared/genericComponents/flat/abstract-flat-widget-line.ts +++ b/ui/src/app/shared/genericComponents/flat/abstract-flat-widget-line.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Directive, Inject, Input, OnChanges, OnDestroy } from "@angular/core"; import { ActivatedRoute } from "@angular/router"; import { ModalController } from "@ionic/angular"; 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 c4b1adcc878..e57ef8c9c83 100644 --- a/ui/src/app/shared/genericComponents/flat/abstract-flat-widget.ts +++ b/ui/src/app/shared/genericComponents/flat/abstract-flat-widget.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Directive, Inject, Input, OnDestroy, OnInit } from "@angular/core"; import { ActivatedRoute } from "@angular/router"; import { ModalController } from "@ionic/angular"; 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 8a6ae6e99b6..7ce3eab9718 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,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input } from "@angular/core"; import { AbstractFlatWidgetLine } from "../abstract-flat-widget-line"; diff --git a/ui/src/app/shared/genericComponents/flat/flat.ts b/ui/src/app/shared/genericComponents/flat/flat.ts index c06ab9b9ee0..c15744a15ed 100644 --- a/ui/src/app/shared/genericComponents/flat/flat.ts +++ b/ui/src/app/shared/genericComponents/flat/flat.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input } from '@angular/core'; import { Icon } from 'src/app/shared/type/widget'; diff --git a/ui/src/app/shared/genericComponents/genericComponents.ts b/ui/src/app/shared/genericComponents/genericComponents.ts index fa0f62b4656..417ac36b721 100644 --- a/ui/src/app/shared/genericComponents/genericComponents.ts +++ b/ui/src/app/shared/genericComponents/genericComponents.ts @@ -33,22 +33,6 @@ import { NotificationComponent } from './shared/notification/notification'; RouterModule, TranslateModule, ], - entryComponents: [ - PickDateComponent, - FlatWidgetComponent, - FlatWidgetLineComponent, - FlatWidgetHorizontalLineComponent, - FlatWidgetPercentagebarComponent, - FlatWidgetLineItemComponent, - ModalButtonsComponent, - ModalInfoLineComponent, - ModalLineComponent, - ModalHorizontalLineComponent, - ModalComponent, - ModalLineItemComponent, - ModalPhasesComponent, - ModalValueLineComponent, - ], declarations: [ // Flat 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 11437da9071..5381137990c 100644 --- a/ui/src/app/shared/genericComponents/modal/abstract-modal-line.ts +++ b/ui/src/app/shared/genericComponents/modal/abstract-modal-line.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { ChangeDetectorRef, Directive, Inject, Input, OnChanges, OnDestroy, OnInit } from "@angular/core"; import { FormBuilder, FormGroup } from "@angular/forms"; import { ActivatedRoute } from "@angular/router"; diff --git a/ui/src/app/shared/genericComponents/modal/abstractModal.ts b/ui/src/app/shared/genericComponents/modal/abstractModal.ts index e1540757482..c9daf5850f5 100644 --- a/ui/src/app/shared/genericComponents/modal/abstractModal.ts +++ b/ui/src/app/shared/genericComponents/modal/abstractModal.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { ChangeDetectorRef, Directive, Inject, Input, OnDestroy, OnInit } from "@angular/core"; import { FormBuilder, FormGroup } from "@angular/forms"; import { ActivatedRoute } from "@angular/router"; diff --git a/ui/src/app/shared/genericComponents/modal/help-button/help-button.ts b/ui/src/app/shared/genericComponents/modal/help-button/help-button.ts index fe1fd90e48c..38d4a5025e6 100644 --- a/ui/src/app/shared/genericComponents/modal/help-button/help-button.ts +++ b/ui/src/app/shared/genericComponents/modal/help-button/help-button.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input } from "@angular/core"; import { Service } from "src/app/shared/shared"; import { environment } from 'src/environments'; diff --git a/ui/src/app/shared/genericComponents/modal/modal-button/modal-button.ts b/ui/src/app/shared/genericComponents/modal/modal-button/modal-button.ts index a29ea8940b4..f1b50ef6328 100644 --- a/ui/src/app/shared/genericComponents/modal/modal-button/modal-button.ts +++ b/ui/src/app/shared/genericComponents/modal/modal-button/modal-button.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input } from "@angular/core"; import { Icon } from "src/app/shared/type/widget"; import { AbstractModalLine } from "../abstract-modal-line"; diff --git a/ui/src/app/shared/genericComponents/modal/modal-info-line/modal-info-line.ts b/ui/src/app/shared/genericComponents/modal/modal-info-line/modal-info-line.ts index d33fddc59db..ec2b7ff70d1 100644 --- a/ui/src/app/shared/genericComponents/modal/modal-info-line/modal-info-line.ts +++ b/ui/src/app/shared/genericComponents/modal/modal-info-line/modal-info-line.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input } from "@angular/core"; import { Icon } from "src/app/shared/type/widget"; 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 4cf7619299c..57e97e2e0af 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,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input } from "@angular/core"; import { AbstractModalLine } from "../abstract-modal-line"; import { ButtonLabel } from "../modal-button/modal-button"; diff --git a/ui/src/app/shared/genericComponents/modal/modal-value-line/modal-value-line.ts b/ui/src/app/shared/genericComponents/modal/modal-value-line/modal-value-line.ts index fa507440f63..6857fdf23dd 100644 --- a/ui/src/app/shared/genericComponents/modal/modal-value-line/modal-value-line.ts +++ b/ui/src/app/shared/genericComponents/modal/modal-value-line/modal-value-line.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input } from "@angular/core"; import { ChannelAddress, CurrentData } from "src/app/shared/shared"; diff --git a/ui/src/app/shared/genericComponents/modal/modal.ts b/ui/src/app/shared/genericComponents/modal/modal.ts index c4f9d5f4ab7..10481fb647a 100644 --- a/ui/src/app/shared/genericComponents/modal/modal.ts +++ b/ui/src/app/shared/genericComponents/modal/modal.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input } from "@angular/core"; import { FormGroup } from "@angular/forms"; import { ModalController } from "@ionic/angular"; diff --git a/ui/src/app/shared/genericComponents/modal/model-horizontal-line/modal-horizontal-line.ts b/ui/src/app/shared/genericComponents/modal/model-horizontal-line/modal-horizontal-line.ts index 7309a5a7e59..03214110464 100644 --- a/ui/src/app/shared/genericComponents/modal/model-horizontal-line/modal-horizontal-line.ts +++ b/ui/src/app/shared/genericComponents/modal/model-horizontal-line/modal-horizontal-line.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input } from "@angular/core"; /** diff --git a/ui/src/app/shared/genericComponents/shared/converter.ts b/ui/src/app/shared/genericComponents/shared/converter.ts index d6aa1d8fe99..12458d38a0e 100644 --- a/ui/src/app/shared/genericComponents/shared/converter.ts +++ b/ui/src/app/shared/genericComponents/shared/converter.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { TranslateService } from "@ngx-translate/core"; import { CurrentData, EdgeConfig, Utils } from "../../shared"; diff --git a/ui/src/app/shared/genericComponents/shared/dataservice.ts b/ui/src/app/shared/genericComponents/shared/dataservice.ts index 2cc9b167d2a..7af1ff7bb55 100644 --- a/ui/src/app/shared/genericComponents/shared/dataservice.ts +++ b/ui/src/app/shared/genericComponents/shared/dataservice.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Injectable } from "@angular/core"; import { BehaviorSubject, Subject } from "rxjs"; diff --git a/ui/src/app/shared/genericComponents/shared/filter.ts b/ui/src/app/shared/genericComponents/shared/filter.ts index 4203954819f..b1ab407ec79 100644 --- a/ui/src/app/shared/genericComponents/shared/filter.ts +++ b/ui/src/app/shared/genericComponents/shared/filter.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { GridMode } from "../../shared"; export type Filter = (value: number | string | null) => boolean; diff --git a/ui/src/app/shared/genericComponents/shared/testing/common.ts b/ui/src/app/shared/genericComponents/shared/testing/common.ts index a05d77e00ad..06ecc495617 100644 --- a/ui/src/app/shared/genericComponents/shared/testing/common.ts +++ b/ui/src/app/shared/genericComponents/shared/testing/common.ts @@ -27,9 +27,9 @@ export namespace OeTester { options: { "responsive": true, "maintainAspectRatio": false, "elements": { "point": { "radius": 0, "hitRadius": 0, "hoverRadius": 0 }, "line": { "stepped": false, "fill": true } }, "datasets": { "bar": {}, "line": {} }, "plugins": { "colors": { "enabled": false }, "legend": { "display": true, "position": "bottom", "labels": { "color": '' } }, "tooltip": { "intersect": false, "mode": "index", "callbacks": {} } }, "scales": { "x": { "stacked": true, "offset": false, "type": "time", "ticks": { "source": "auto", "maxTicksLimit": 31 }, "bounds": "ticks", "adapters": { "date": { "locale": { "code": "de", "formatLong": {}, "localize": {}, "match": {}, "options": { "weekStartsOn": 1, "firstWeekContainsDate": 4 } } } }, "time": { "unit": period as TimeUnit, "displayFormats": { "datetime": "yyyy-MM-dd HH:mm:ss", "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" } } }, "left": { - ...options["left"].scale, ...(chartType === 'line' ? { stacked: false } : {}), "title": { "text": "kW", "display": false, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, + ...options["left"]?.scale, ...(chartType === 'line' ? { stacked: false } : {}), "title": { "text": "kW", "display": false, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, "ticks": { - ...options["left"].ticks, + ...options["left"]?.ticks, "color": '', "padding": 5, "maxTicksLimit": ChartConstants.NUMBER_OF_Y_AXIS_TICKS, @@ -44,9 +44,9 @@ export namespace OeTester { "responsive": true, "maintainAspectRatio": false, "elements": { "point": { "radius": 0, "hitRadius": 0, "hoverRadius": 0 }, "line": { "stepped": false, "fill": true } }, "datasets": { "bar": { "barPercentage": 1 }, "line": {} }, "plugins": { "colors": { "enabled": false }, "legend": { "display": true, "position": "bottom", "labels": { "color": '' } }, "tooltip": { "intersect": false, "mode": "x", "callbacks": {} } }, "scales": { "x": { "stacked": true, "offset": true, "type": "time", "ticks": { "source": "auto", "maxTicksLimit": 31 }, "bounds": "ticks", "adapters": { "date": { "locale": { "code": "de", "formatLong": {}, "localize": {}, "match": {}, "options": { "weekStartsOn": 1, "firstWeekContainsDate": 4 } } } }, "time": { "unit": period as TimeUnit, "displayFormats": { "datetime": "yyyy-MM-dd HH:mm:ss", "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" } } }, "left": { - ...options["left"].scale, ...(chartType === 'line' ? { stacked: false } : {}), "title": { "text": "kWh", "display": false, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, + ...options["left"]?.scale, ...(chartType === 'line' ? { stacked: false } : {}), "title": { "text": "kWh", "display": false, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, "ticks": { - ...options["left"].ticks, + ...options["left"]?.ticks, "color": '', "padding": 5, "maxTicksLimit": ChartConstants.NUMBER_OF_Y_AXIS_TICKS, diff --git a/ui/src/app/shared/genericComponents/shared/testing/tester.ts b/ui/src/app/shared/genericComponents/shared/testing/tester.ts index ad4bd140916..96559478cc7 100644 --- a/ui/src/app/shared/genericComponents/shared/testing/tester.ts +++ b/ui/src/app/shared/genericComponents/shared/testing/tester.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import * as Chart from "chart.js"; import { ChartDataset } from "chart.js"; import { QueryHistoricTimeseriesDataResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesDataResponse"; @@ -305,7 +306,7 @@ export class OeChartTester { return { type: 'option', - options: AbstractHistoryChart.getOptions(chartData, chartType, testContext.service, testContext.translate, legendOptions, channelData.result, locale, config, datasets), + options: AbstractHistoryChart.getOptions(chartData, chartType, testContext.service, testContext.translate, legendOptions, channelData.result, locale, config), }; } diff --git a/ui/src/app/shared/header/header.component.ts b/ui/src/app/shared/header/header.component.ts index efd940d50a0..a1b4d2b76a7 100644 --- a/ui/src/app/shared/header/header.component.ts +++ b/ui/src/app/shared/header/header.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { AfterViewChecked, ChangeDetectorRef, Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'; import { MenuController, ModalController } from '@ionic/angular'; diff --git a/ui/src/app/shared/history-data-error.component.ts b/ui/src/app/shared/history-data-error.component.ts index d3874ce0576..74df053ac50 100644 --- a/ui/src/app/shared/history-data-error.component.ts +++ b/ui/src/app/shared/history-data-error.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input } from "@angular/core"; import { JsonrpcResponseError } from "src/app/shared/jsonrpc/base"; diff --git a/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesDataRequest.ts b/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesDataRequest.ts index 7253f7d2340..77146413230 100644 --- a/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesDataRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesDataRequest.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { ChannelAddress } from "../../../shared/type/channeladdress"; import { format } from 'date-fns'; import { JsonrpcRequest } from "../base"; diff --git a/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesEnergyPerPeriodRequest.ts b/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesEnergyPerPeriodRequest.ts index 23c68ecbf3f..c81fd430687 100644 --- a/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesEnergyPerPeriodRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesEnergyPerPeriodRequest.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { ChannelAddress } from "../../type/channeladdress"; import { format } from 'date-fns'; import { JsonrpcRequest } from "../base"; diff --git a/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesEnergyRequest.ts b/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesEnergyRequest.ts index ec0ec292f68..cd44298b563 100644 --- a/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesEnergyRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesEnergyRequest.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { ChannelAddress } from "../../type/channeladdress"; import { format } from 'date-fns'; import { JsonrpcRequest } from "../base"; diff --git a/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesExportXlxs.ts b/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesExportXlxs.ts index a15f8cd76d4..eb67e868a7a 100644 --- a/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesExportXlxs.ts +++ b/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesExportXlxs.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { format } from 'date-fns'; import { JsonrpcRequest } from '../base'; diff --git a/ui/src/app/shared/jsonrpc/request/setEmergencyReserveRequest.ts b/ui/src/app/shared/jsonrpc/request/setEmergencyReserveRequest.ts index d8b3865b865..d360e4e16a8 100644 --- a/ui/src/app/shared/jsonrpc/request/setEmergencyReserveRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/setEmergencyReserveRequest.ts @@ -19,7 +19,7 @@ export class SetEmergencyReserveRequest extends JsonrpcRequest { private static METHOD: string = "setEmergencyReserve"; public constructor( - public readonly params: { + public override readonly params: { value: number }, ) { diff --git a/ui/src/app/shared/jsonrpc/request/subscribeChannelsRequest.ts b/ui/src/app/shared/jsonrpc/request/subscribeChannelsRequest.ts index 441ba33ea3b..34a2897aea4 100644 --- a/ui/src/app/shared/jsonrpc/request/subscribeChannelsRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/subscribeChannelsRequest.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { ChannelAddress } from "../../../shared/type/channeladdress"; import { JsonrpcRequest } from "../base"; import { JsonRpcUtils } from "../jsonrpcutils"; diff --git a/ui/src/app/shared/jsonrpc/response/edgeRpcResponse.ts b/ui/src/app/shared/jsonrpc/response/edgeRpcResponse.ts index 6d3729db020..8e80ced8991 100644 --- a/ui/src/app/shared/jsonrpc/response/edgeRpcResponse.ts +++ b/ui/src/app/shared/jsonrpc/response/edgeRpcResponse.ts @@ -16,7 +16,7 @@ import { JsonrpcRequest, JsonrpcResponseSuccess } from "../base"; export class EdgeRpcResponse extends JsonrpcResponseSuccess { public constructor( - public readonly id: string, + public override readonly id: string, public readonly params: { payload: JsonrpcRequest }, diff --git a/ui/src/app/shared/percentagebar/percentagebar.component.ts b/ui/src/app/shared/percentagebar/percentagebar.component.ts index f916bdda31b..dfa6da83147 100644 --- a/ui/src/app/shared/percentagebar/percentagebar.component.ts +++ b/ui/src/app/shared/percentagebar/percentagebar.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input } from '@angular/core'; @Component({ diff --git a/ui/src/app/shared/pickdate/pickdate.component.ts b/ui/src/app/shared/pickdate/pickdate.component.ts index 5445b50b0eb..950e0eedf13 100644 --- a/ui/src/app/shared/pickdate/pickdate.component.ts +++ b/ui/src/app/shared/pickdate/pickdate.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { PopoverController } from '@ionic/angular'; import { TranslateService } from '@ngx-translate/core'; diff --git a/ui/src/app/shared/pickdate/popover/popover.component.ts b/ui/src/app/shared/pickdate/popover/popover.component.ts index 5bbb076d201..ad430f4dd75 100644 --- a/ui/src/app/shared/pickdate/popover/popover.component.ts +++ b/ui/src/app/shared/pickdate/popover/popover.component.ts @@ -1,13 +1,14 @@ +// @ts-strict-ignore import { Component, Input, OnInit } from '@angular/core'; import { PopoverController } from '@ionic/angular'; 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 { EdgePermission, Service, Utils } from '../../shared'; +import { CalAnimation, IAngularMyDpOptions, IMyDate, IMyDateRangeModel } from '@nodro7/angular-mydatepicker'; @Component({ selector: 'pickdatepopover', diff --git a/ui/src/app/shared/pipe/classname/classname.pipe.ts b/ui/src/app/shared/pipe/classname/classname.pipe.ts index 386c9241826..7b966b8add5 100644 --- a/ui/src/app/shared/pipe/classname/classname.pipe.ts +++ b/ui/src/app/shared/pipe/classname/classname.pipe.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ diff --git a/ui/src/app/shared/pipe/keys/keys.pipe.ts b/ui/src/app/shared/pipe/keys/keys.pipe.ts index 7098244b582..3d4eb68073d 100644 --- a/ui/src/app/shared/pipe/keys/keys.pipe.ts +++ b/ui/src/app/shared/pipe/keys/keys.pipe.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ diff --git a/ui/src/app/shared/pipe/pipe.ts b/ui/src/app/shared/pipe/pipe.ts index 85b06b08628..e2fef054ecf 100644 --- a/ui/src/app/shared/pipe/pipe.ts +++ b/ui/src/app/shared/pipe/pipe.ts @@ -14,16 +14,6 @@ import { VersionPipe } from './version/version.pipe'; imports: [ BrowserModule, ], - entryComponents: [ - UnitvaluePipe, - SignPipe, - FormatSecondsToDurationPipe, - KeysPipe, - IsclassPipe, - ClassnamePipe, - VersionPipe, - TypeofPipe, - ], declarations: [ UnitvaluePipe, SignPipe, diff --git a/ui/src/app/shared/pipe/sign/sign.pipe.ts b/ui/src/app/shared/pipe/sign/sign.pipe.ts index dafe66279b7..614ff7c928b 100644 --- a/ui/src/app/shared/pipe/sign/sign.pipe.ts +++ b/ui/src/app/shared/pipe/sign/sign.pipe.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ diff --git a/ui/src/app/shared/service/abstractservice.ts b/ui/src/app/shared/service/abstractservice.ts index 51cb2ffb876..02143b36ac0 100644 --- a/ui/src/app/shared/service/abstractservice.ts +++ b/ui/src/app/shared/service/abstractservice.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { ErrorHandler } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { BehaviorSubject } from 'rxjs'; diff --git a/ui/src/app/shared/service/defaulttypes.ts b/ui/src/app/shared/service/defaulttypes.ts index e9762bda4f4..98527a673a6 100644 --- a/ui/src/app/shared/service/defaulttypes.ts +++ b/ui/src/app/shared/service/defaulttypes.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { TranslateService } from '@ngx-translate/core'; import { endOfMonth, endOfYear, format, getDay, getMonth, getYear, isSameDay, isSameMonth, isSameYear, startOfMonth, startOfYear, subDays } from 'date-fns'; diff --git a/ui/src/app/shared/service/globalRouteChangeHandler.ts b/ui/src/app/shared/service/globalRouteChangeHandler.ts index 17495ca8d69..af6db888e34 100644 --- a/ui/src/app/shared/service/globalRouteChangeHandler.ts +++ b/ui/src/app/shared/service/globalRouteChangeHandler.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Injectable } from "@angular/core"; import { Router, RoutesRecognized } from "@angular/router"; import { TranslateService } from "@ngx-translate/core"; diff --git a/ui/src/app/shared/service/pagination.ts b/ui/src/app/shared/service/pagination.ts index 96956983461..61d1f1aea1c 100644 --- a/ui/src/app/shared/service/pagination.ts +++ b/ui/src/app/shared/service/pagination.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Directive } from '@angular/core'; import { Router } from '@angular/router'; import { SubscribeEdgesRequest } from '../jsonrpc/request/subscribeEdgesRequest'; diff --git a/ui/src/app/shared/service/service.ts b/ui/src/app/shared/service/service.ts index 5a724cb6fe8..771b140ab6e 100644 --- a/ui/src/app/shared/service/service.ts +++ b/ui/src/app/shared/service/service.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { registerLocaleData } from '@angular/common'; import { Injectable } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; diff --git a/ui/src/app/shared/service/utils.spec.ts b/ui/src/app/shared/service/utils.spec.ts index 816379415c1..49a2ae3d31a 100644 --- a/ui/src/app/shared/service/utils.spec.ts +++ b/ui/src/app/shared/service/utils.spec.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Utils } from "./utils"; describe('Utils', () => { diff --git a/ui/src/app/shared/service/utils.ts b/ui/src/app/shared/service/utils.ts index 9d1792028c5..d3f9652c6e5 100644 --- a/ui/src/app/shared/service/utils.ts +++ b/ui/src/app/shared/service/utils.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { formatNumber } from '@angular/common'; import { TranslateService } from '@ngx-translate/core'; import { ChartDataset } from 'chart.js'; @@ -773,24 +774,12 @@ export namespace HistoryUtils { export namespace TimeOfUseTariffUtils { - export type ScheduleChartData = { - datasets: ChartDataset[], - colors: any[], - labels: Date[] - } - - export enum TimeOfUseTariffState { + export enum State { DelayDischarge = 0, Balancing = 1, - ChargeProduction = 2, ChargeGrid = 3, } - export enum ControlMode { - CHARGE_CONSUMPTION = 'CHARGE_CONSUMPTION', - DELAY_DISCHARGE = 'DELAY_DISCHARGE' - } - /** * Converts a value in €/MWh to €Ct./kWh. * @@ -808,127 +797,6 @@ export namespace TimeOfUseTariffUtils { } } - /** - * Gets the schedule chart data containing datasets, colors and labels. - * - * @param size The length of the dataset - * @param prices The Time-of-Use-Tariff quarterly price array - * @param states The Time-of-Use-Tariff state array - * @param timestamps The Time-of-Use-Tariff timestamps array - * @param gridBuy The Time-of-Use-Tariff gridBuy array - * @param socArray The Time-of0Use-Tariff soc Array. - * @param translate The Translate service - * @param controlMode The Control mode of the controller. - * @returns The ScheduleChartData. - */ - export function getScheduleChartData(size: number, prices: number[], states: number[], timestamps: string[], gridBuy: number[], socArray: number[], translate: TranslateService, controlMode: ControlMode): ScheduleChartData { - const datasets: ChartDataset[] = []; - const colors: any[] = []; - const labels: Date[] = []; - - // Initializing States. - const barChargeGrid = Array(size).fill(null); - const barBalancing = Array(size).fill(null); - const barDelayDischarge = Array(size).fill(null); - - for (let index = 0; index < size; index++) { - const quarterlyPrice = formatPrice(prices[index]); - const state = states[index]; - labels.push(new Date(timestamps[index])); - - if (state !== null) { - switch (state) { - case TimeOfUseTariffState.DelayDischarge: - barDelayDischarge[index] = quarterlyPrice; - break; - case TimeOfUseTariffState.Balancing: - barBalancing[index] = quarterlyPrice; - break; - case TimeOfUseTariffState.ChargeGrid: - barChargeGrid[index] = quarterlyPrice; - break; - } - } - } - - // Set datasets - datasets.push({ - type: 'bar', - label: translate.instant('Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.BALANCING'), - data: barBalancing, - order: 1, - }); - colors.push({ - // Dark Green - backgroundColor: 'rgba(51,102,0,0.8)', - borderColor: 'rgba(51,102,0,1)', - }); - - // Set dataset for ChargeGrid. - if (!barChargeGrid.every(v => v === null) || controlMode == ControlMode.CHARGE_CONSUMPTION) { - datasets.push({ - type: 'bar', - label: translate.instant('Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.CHARGE_GRID'), - data: barChargeGrid, - order: 1, - }); - colors.push({ - // Sky blue - backgroundColor: 'rgba(0, 204, 204,0.5)', - borderColor: 'rgba(0, 204, 204,0.7)', - }); - } - - // Set dataset for buy from grid - datasets.push({ - type: 'bar', - label: translate.instant('Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.DELAY_DISCHARGE'), - data: barDelayDischarge, - order: 1, - }); - colors.push({ - // Black - backgroundColor: 'rgba(0,0,0,0.8)', - borderColor: 'rgba(0,0,0,0.9)', - }); - - // State of charge data - datasets.push({ - type: 'line', - label: translate.instant('General.soc'), - data: socArray, - hidden: false, - yAxisID: ChartAxis.RIGHT, - borderDash: [10, 10], - order: 0, - }); - colors.push({ - backgroundColor: 'rgba(189, 195, 199,0.2)', - borderColor: 'rgba(189, 195, 199,1)', - }); - - datasets.push({ - type: 'line', - label: translate.instant('General.gridBuy'), - data: gridBuy, - hidden: true, - yAxisID: ChartAxis.RIGHT_2, - order: 2, - }); - colors.push({ - backgroundColor: 'rgba(0,0,0, 0.2)', - borderColor: 'rgba(0,0,0, 1)', - }); - - const scheduleChartData: ScheduleChartData = { - colors: colors, - datasets: datasets, - labels: labels, - }; - - return scheduleChartData; - } - /** * Retrieves a formatted label based on the provided value and label type. * @@ -962,12 +830,10 @@ export namespace TimeOfUseTariffUtils { // Show floating point number for values between 0 and 1 return label + ": " + formatNumber(value, 'de', '1.0-4') + " " + currencyLabel; - case gridBuyLabel: - return label + ": " + formatNumber(value, 'de', '1.0-0') + " kW"; - default: + case gridBuyLabel: // Power values - return label + ": " + formatNumber(value, 'de', '1.0-0') + ' ' + 'W'; + return label + ": " + formatNumber(value, 'de', '1.0-2') + " kW"; } } diff --git a/ui/src/app/shared/service/websocket.ts b/ui/src/app/shared/service/websocket.ts index 65c6e196d99..429879edf00 100644 --- a/ui/src/app/shared/service/websocket.ts +++ b/ui/src/app/shared/service/websocket.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Injectable } from '@angular/core'; import { Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; diff --git a/ui/src/app/shared/service/websocketInterface.ts b/ui/src/app/shared/service/websocketInterface.ts index 0d5b2b36261..517799b1eb9 100644 --- a/ui/src/app/shared/service/websocketInterface.ts +++ b/ui/src/app/shared/service/websocketInterface.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { JsonrpcNotification, JsonrpcRequest, JsonrpcResponseSuccess } from '../jsonrpc/base'; import { AuthenticateWithPasswordRequest } from '../jsonrpc/request/authenticateWithPasswordRequest'; import { AuthenticateWithTokenRequest } from '../jsonrpc/request/authenticateWithTokenRequest'; diff --git a/ui/src/app/shared/service/wsdata.ts b/ui/src/app/shared/service/wsdata.ts index a0f8511fa45..ea2a0a2b71d 100644 --- a/ui/src/app/shared/service/wsdata.ts +++ b/ui/src/app/shared/service/wsdata.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { WebSocketSubject } from "rxjs/webSocket"; import { environment } from "src/environments"; import { JsonrpcNotification, JsonrpcRequest, JsonrpcResponse, JsonrpcResponseError, JsonrpcResponseSuccess } from "../jsonrpc/base"; diff --git a/ui/src/app/shared/shared.module.ts b/ui/src/app/shared/shared.module.ts index 0f7b7fdeef8..3ea0d81b6cd 100644 --- a/ui/src/app/shared/shared.module.ts +++ b/ui/src/app/shared/shared.module.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { CommonModule } from '@angular/common'; import { Injector, NgModule } from '@angular/core'; import { FormControl, FormsModule, ReactiveFormsModule, ValidationErrors } from '@angular/forms'; diff --git a/ui/src/app/shared/shared.spec.ts b/ui/src/app/shared/shared.spec.ts index 33611a2cf17..82662b2ea1f 100644 --- a/ui/src/app/shared/shared.spec.ts +++ b/ui/src/app/shared/shared.spec.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { SumState } from "../index/shared/sumState"; import { Edge, EdgePermission } from "./shared"; import { Role } from "./type/role"; diff --git a/ui/src/app/shared/shared.ts b/ui/src/app/shared/shared.ts index 2653ae81df8..90b7b4ca963 100644 --- a/ui/src/app/shared/shared.ts +++ b/ui/src/app/shared/shared.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore export { Edge } from "./edge/edge"; export { EdgeConfig } from "./edge/edgeconfig"; export { Logger } from "./service/logger"; diff --git a/ui/src/app/shared/status/single/status.component.ts b/ui/src/app/shared/status/single/status.component.ts index 4355d6dba50..bcc032a56ae 100644 --- a/ui/src/app/shared/status/single/status.component.ts +++ b/ui/src/app/shared/status/single/status.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnDestroy, OnInit } from '@angular/core'; import { ModalController } from '@ionic/angular'; import { Subject } from 'rxjs'; diff --git a/ui/src/app/shared/translate.extension.ts b/ui/src/app/shared/translate.extension.ts index d740e46c5d5..e0d7675b9af 100644 --- a/ui/src/app/shared/translate.extension.ts +++ b/ui/src/app/shared/translate.extension.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { FormlyExtension, FormlyFieldConfig } from '@ngx-formly/core'; import { TranslateService } from '@ngx-translate/core'; diff --git a/ui/src/app/shared/type/language.spec.ts b/ui/src/app/shared/type/language.spec.ts index e4fdefcec4c..d3b078be851 100644 --- a/ui/src/app/shared/type/language.spec.ts +++ b/ui/src/app/shared/type/language.spec.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Language } from "./language"; describe('Language', () => { diff --git a/ui/src/app/shared/type/widget.ts b/ui/src/app/shared/type/widget.ts index 474955e1efe..44370393bed 100644 --- a/ui/src/app/shared/type/widget.ts +++ b/ui/src/app/shared/type/widget.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Edge } from '../edge/edge'; import { EdgeConfig } from '../edge/edgeconfig'; diff --git a/ui/src/app/shared/utils/array/array.utils.spec.ts b/ui/src/app/shared/utils/array/array.utils.spec.ts index 47984ef938f..aab90e1edaa 100644 --- a/ui/src/app/shared/utils/array/array.utils.spec.ts +++ b/ui/src/app/shared/utils/array/array.utils.spec.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { ArrayUtils } from "./array.utils"; describe('Array-Utils', () => { diff --git a/ui/src/app/shared/utils/color/color.utils.spec.ts b/ui/src/app/shared/utils/color/color.utils.spec.ts index 3e2c43ad324..d9ee75dd2a8 100644 --- a/ui/src/app/shared/utils/color/color.utils.spec.ts +++ b/ui/src/app/shared/utils/color/color.utils.spec.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { ColorUtils } from "./color.utils"; describe('Color-Utils', () => { diff --git a/ui/src/app/shared/utils/color/color.utils.ts b/ui/src/app/shared/utils/color/color.utils.ts index c2041facddf..e8408861359 100644 --- a/ui/src/app/shared/utils/color/color.utils.ts +++ b/ui/src/app/shared/utils/color/color.utils.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore export namespace ColorUtils { /** diff --git a/ui/src/app/shared/utils/date/dateutils.spec.ts b/ui/src/app/shared/utils/date/dateutils.spec.ts index 266c73d0c29..91af5e6dfb2 100644 --- a/ui/src/app/shared/utils/date/dateutils.spec.ts +++ b/ui/src/app/shared/utils/date/dateutils.spec.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { DateUtils } from "./dateutils"; describe('DateUtils', () => { diff --git a/ui/src/app/shared/utils/datetime/datetime-utils.ts b/ui/src/app/shared/utils/datetime/datetime-utils.ts index 76af3902b26..aec8bad6a21 100644 --- a/ui/src/app/shared/utils/datetime/datetime-utils.ts +++ b/ui/src/app/shared/utils/datetime/datetime-utils.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { format, startOfMonth, startOfYear } from "date-fns"; import { de } from "date-fns/locale"; import { ChronoUnit } from "src/app/edge/history/shared"; diff --git a/ui/src/app/shared/utils/time/timeutils.spec.ts b/ui/src/app/shared/utils/time/timeutils.spec.ts index 03abf88d4f3..0916acd4b76 100644 --- a/ui/src/app/shared/utils/time/timeutils.spec.ts +++ b/ui/src/app/shared/utils/time/timeutils.spec.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { TimeUtils } from "./timeutils"; describe('TimeUtils', () => { diff --git a/ui/src/app/shared/utils/time/timeutils.ts b/ui/src/app/shared/utils/time/timeutils.ts index d53491fbc34..905f2128402 100644 --- a/ui/src/app/shared/utils/time/timeutils.ts +++ b/ui/src/app/shared/utils/time/timeutils.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { DecimalPipe } from "@angular/common"; import { Language } from "../../type/language"; diff --git a/ui/src/app/user/user.component.ts b/ui/src/app/user/user.component.ts index 35d71138e2e..4be869cd4ea 100644 --- a/ui/src/app/user/user.component.ts +++ b/ui/src/app/user/user.component.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Component, OnInit } from '@angular/core'; import { FormGroup, Validators } from '@angular/forms'; import { ActivatedRoute } from '@angular/router'; diff --git a/ui/src/assets/i18n/de.json b/ui/src/assets/i18n/de.json index 0b5f4c8cd9e..e1fd38cc65a 100644 --- a/ui/src/assets/i18n/de.json +++ b/ui/src/assets/i18n/de.json @@ -669,11 +669,12 @@ "TIME_OF_INSTALLATION": "Zeitpunkt der Installation", "WARRANTY_TERMS": "Garantiebedingungen", "ACCEPT": "akzeptieren", - "ALIAS_WITH_LABEL_HOME_DC": "Alias MPPT{{mppt}} PV{{pv}}", - "VALUE_WITH_LABEL_HOME_DC": "Wert MPPT{{ mppt }} PV{{ pv }} {{ symbol }}", - "ORIENTATION_WITH_LABEL_HOME_DC": "Ausrichtung MPPT{{ mppt }} PV{{ pv }}", - "MODULE_TYPE_WITH_LABEL_HOME_DC": "Modultyp MPPT{{ mppt }} PV{{ pv }}", - "NUMBER_OF_MODULES_WITH_LABEL_HOME_DC": "Anzahl PV-Module MPPT{{ mppt }} PV{{ pv }}", + "ALIAS_WITH_LABEL_HOME_DC": "Alias MPPT{{mppt}}", + "VALUE_WITH_LABEL_HOME_DC": "Wert MPPT{{ mppt }} {{ symbol }}", + "ORIENTATION_WITH_LABEL_HOME_DC": "Ausrichtung MPPT{{ mppt }}", + "MODULE_TYPE_WITH_LABEL_HOME_DC": "Modultyp MPPT{{ mppt }}", + "NUMBER_OF_MODULES_WITH_LABEL_HOME_DC": "Anzahl PV-Module MPPT{{ mppt }}", + "BOTH_SELECTED_LABEL": "Beide Anschlüsse (\"PV{{ pv1 }}\" und \"PV{{ pv2 }}\") belegt", "DEVICE_CONNECTION_CHECKED": "Das Stromspeichersystem ist an das Stromnetz angeschlossen", "ENERGY_FLOW_METER": { "LABEL": "Installierter Netzzähler" @@ -757,13 +758,16 @@ "SOUTH": "Sued", "WEST": "West" }, - "INSTALLED_POWER": "Installierte leistung [Wₚ]", + "INSTALLED_POWER": "Installierte Leistung [Wₚ]", + "INSTALLED_POWER_PER_STRING": "Installierte Leistung pro String [Wₚ]", "MARKED_AS": " MPPT {{ mppt }} (beschriftet mit \"PV{{ pv }}\")", + "MARKED_AS_BOTH_STRINGS": " MPPT {{ mppt }} (beschriftet mit \"PV{{ pv1 }}\" & \"PV{{ pv2 }}\")", "MODULE_TYPE_DESCRIPTION": "z. B. Hersteller und Leistung", "MODULE_TYPE_WITH_LABEL": "Modultyp {{ label }}{{ number }}", "MODULE_TYPE": "Modultyp", "NUMBER_OF_MODULES_WITH_LABEL": "Anzahl PV-Module {{ label }}{{ number }}", "NUMBER_OF_MODULES": "Anzahl PV-Module", + "NUMBER_OF_MODULES_PER_STRING": "Anzahl PV-Module pro String", "OPEN_MANUAL": "Anleitung öffnen", "ORIENTATION_WITH_LABEL": "Ausrichtung {{ label }}{{ number }}", "ORIENTATION": "Ausrichtung", @@ -771,7 +775,8 @@ "SHADE_MANAGEMENT_DESCRIPTION": "Nur wenn Optimierer verbaut sind, muss das Schattenmanagement deaktiviert werden", "TITLE_PV": "DC-PV Installation (Wechselrichtereingänge)", "TITLE_DC": "DC-PV-Installation", - "DUPLICATE": " MPPT {{ mppt }} doppelt belegt (beschriftet mit \"PV{{ pv }}\")" + "DUPLICATE": " MPPT {{ mppt }} doppelt belegt (beschriftet mit \"PV{{ pv }}\")", + "BOTH_SELECTED_LABEL": "Sind beide Anschlüsse (\"PV{{ pv1 }}\" und \"PV{{ pv2 }}\") belegt?" }, "PROTOCOL_SERIAL_NUMBERS": { "BATTERY_MODULE": "Batteriemodul ", diff --git a/ui/src/assets/i18n/en.json b/ui/src/assets/i18n/en.json index fa02d57c5e8..96a04d721fd 100644 --- a/ui/src/assets/i18n/en.json +++ b/ui/src/assets/i18n/en.json @@ -671,11 +671,12 @@ "TIME_OF_INSTALLATION": "Time of the installation", "WARRANTY_TERMS": "Warranty terms", "ACCEPT": "acceptation", - "ALIAS_WITH_LABEL_HOME_DC": "Alias MPPT{{mppt}} PV{{pv}}", - "VALUE_WITH_LABEL_HOME_DC": "Value MPPT{{ mppt }} PV{{ pv }} {{ symbol }}", - "ORIENTATION_WITH_LABEL_HOME_DC": "MPPT{{ mppt }} PV{{ pv }} Orientation", - "MODULE_TYPE_WITH_LABEL_HOME_DC": "Type of modules MPPT{{ mppt }} PV{{ pv }}", - "NUMBER_OF_MODULES_WITH_LABEL_HOME_DC": "Numnber of PV modules MPPT{{ mppt }} PV{{ pv }}", + "ALIAS_WITH_LABEL_HOME_DC": "Alias MPPT{{mppt}}", + "VALUE_WITH_LABEL_HOME_DC": "Value MPPT{{ mppt }} {{ symbol }}", + "ORIENTATION_WITH_LABEL_HOME_DC": "MPPT{{ mppt }} Orientation", + "MODULE_TYPE_WITH_LABEL_HOME_DC": "Type of modules MPPT{{ mppt }}", + "NUMBER_OF_MODULES_WITH_LABEL_HOME_DC": "Numnber of PV modules MPPT{{ mppt }}", + "BOTH_SELECTED_LABEL": "Both pv-ports (\"PV{{ pv1 }}\" and \"PV{{ pv2 }}\") connected", "DEVICE_CONNECTION_CHECKED": "The energy storage system is connected to the power grid", "ENERGY_FLOW_METER": { "LABEL": "Installed Grid-Meter" @@ -759,13 +760,16 @@ "SOUTH": "South", "WEST": "West" }, - "INSTALLED_POWER": "Installed power[Wₚ]", + "INSTALLED_POWER": "Installed power [Wₚ]", + "INSTALLED_POWER_PER_STRING": "Installed power per string [Wₚ]", "MARKED_AS": " MPPT {{ mppt }} (marked as \"PV{{ pv }}\")", + "MARKED_AS_BOTH_STRINGS": " MPPT {{ mppt }} (marked as \"PV{{ pv1 }}\" & \"PV{{ pv2 }}\")", "MODULE_TYPE_DESCRIPTION": "e.g. Manufuturer and Power", "MODULE_TYPE_WITH_LABEL": "Type of modules {{ label }}{{ number }}", "MODULE_TYPE": "Type of modules", "NUMBER_OF_MODULES_WITH_LABEL": "Number of PV module {{ label }}{{ number }}", - "NUMBER_OF_MODULES": "Number of PV module", + "NUMBER_OF_MODULES": "Number of PV module per string", + "NUMBER_OF_MODULES_PER_STRING": "Number of PV module", "OPEN_MANUAL": "Open manual", "ORIENTATION_WITH_LABEL": "{{ label }}{{ number }} Orientation", "ORIENTATION": "Orientation", @@ -773,7 +777,8 @@ "SHADE_MANAGEMENT_DESCRIPTION": "The shade management has to be disabled, only if optimizers are installed.", "TITLE_PV": "DC-PV installation (Inverter inputs)", "TITLE_DC": "DC-PV-Installation", - "DUPLICATE": " MPPT {{ mppt }} double occupied (marked as \"PV{{ pv }}\")" + "DUPLICATE": " MPPT {{ mppt }} double occupied (marked as \"PV{{ pv }}\")", + "BOTH_SELECTED_LABEL": "Are both ports (\"PV{{ pv1 }}\" & \"PV{{ pv2 }}\") connected?" }, "PROTOCOL_SERIAL_NUMBERS": { "BATTERY_MODULE": "Battery module ", diff --git a/ui/src/assets/img/home-mppt/Home_20_MPPT1.png b/ui/src/assets/img/home-mppt/Home_20_MPPT1.png new file mode 100644 index 0000000000000000000000000000000000000000..77bb0695527cad091b5d58d3999bb88a541cc157 GIT binary patch literal 297385 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

    yFUT8o0{fHT`5%!aa=T0(D#R8mu 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

    ^RN5 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 N6$MTCYFV@3{|AZE0$l(A literal 0 HcmV?d00001 diff --git a/ui/src/assets/img/home-mppt/Home_20_MPPT2.png b/ui/src/assets/img/home-mppt/Home_20_MPPT2.png new file mode 100644 index 0000000000000000000000000000000000000000..401db52ee894775cab03bd7dea91b582bc122c11 GIT binary patch literal 297872 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 z

    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�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�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

    ~j2b2LZE$R(HQ0F~XWO<~(s{2fR~& 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

    yH0YvUSJS(%L9*o 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 literal 0 HcmV?d00001 diff --git a/ui/src/assets/img/home-mppt/Home_30_MPPT1.png b/ui/src/assets/img/home-mppt/Home_30_MPPT1.png new file mode 100644 index 0000000000000000000000000000000000000000..2efb461103cba805472b218aefddf145b6bf1324 GIT binary patch literal 304512 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

    !m|l#x(Ml#k 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 ^8BFDHRVaT>tLw*=$n)m*4eG$5#e_3*84ogdmt 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 aG&c=jK5gwbZAz?H0C9%k=~Ckyn*KX}VRBOd literal 0 HcmV?d00001 diff --git a/ui/src/assets/img/home-mppt/Home_30_MPPT2.png b/ui/src/assets/img/home-mppt/Home_30_MPPT2.png new file mode 100644 index 0000000000000000000000000000000000000000..aceeb5735bfbe2131d7f6b6afed70974001276f7 GIT binary patch literal 455661 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�s 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


    Ksh4*3mWVTaUye&we3+Fr`z#9E*VdL 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≪_|je`4bbIHc+XLqG{MTSYc_QEosAd_i$Jk?p(}ql4qK7B$PZA76pqR z2aWmt#?{|m#G|AK93;zyU@F;^_kjLYb|D?lq{p}r!$w71lp6Psub7i)bLHaW-o8`B{RKFM|L6Pb~*vf!YjnC(=Efm)kAEpY^ z;iw@^*L8g|l~3^Mfk-$}AU{x3M?mcW{b+PaGZCu|spV+Fbywdl$n$I~p2c`qzM&R+ ztzM@5>yry-?ZxWwClr#7iw8TWAN$<)<9~tlpRyhjx}*83 z*f<8wFCbj$uSgeCKOWo`Y!RpTEymv=Fe`IhGZ$eio~mxLno~?Yu@Qnfz74UXa8`PUsKp(aTm^eePlD#Sy@{%APeeI=^^kaE2koM*yGqtReNv7j z!o%q5+H2hT=*H68`_X8CfS%co*(sr5f7R4htMzoIy=_I^4QxhrSPIF@1#{G){3Y6D z?Zcr49Bv>_gT=kyctNt!z5~wjpm_~>u=TFT7lYT#)@BGh;I~fct@$i2saN%FM!VbF z%S6{%BUab_qiIT_2+nq?yU+P4R?d zX=6Y5G|M9p)XV(5$%H+#_S^pFFt# zCq|WJ7UpcW&4%<>`lln#4NNMTH2P>NnW&%n_-a6#$eqE&g<>I{g1c_}YlY?{rFG0a zF0mXPmvsH_HZ>4>Cb}Z+(sD*RHnS}R^12>l%XY(^9N`Iy+>iuQy}m=p_Hz3Tv4!HZ zqu=B#hYcr3d_<;9+F4Z^ni-!7hs3BbefiTW@B^aw+^T*B&ynNeAz)V=I3G;Knr3F8 z2ZcL2_s7ziv7Uw-RBEL^DuVd-2sVf&d!#oP563G9ko)P`w{K)eqpQ=8A-LVSa$iM#g1~d2I@srTZ{;1ffL(t#%-ql8};fsO+cS za(mw-$~*)_gcgp{X|r|HfWX_tXnka@p(OT0`hsff`FRf1;X}GX4X;d6urf$AAkDWx zVPyiihb#u|Fn4>o=~fTST9Ao$AK&KNWPCoeZW9|&miuhvPCCx%QMpnWm=$TSX>lot zs}}4jPW+*0p)ziHCxv3E!L`P*q}CZ9Uvw9K0LUvztahp#lW?@EZ6axua{66Yyr}d% z&jLewyqOcpbMc1Br6 z5q`FVFnnXytA9IAL}CIEN37P}E_cVyFGjLV7H{ocB6E1(LGhS)#`D86YvN@!aG(VZ z3;W}U`5298zNJp0<)*qMA;Q$%5jBsESx0mLXaVu9 zf8Hb!FIZ#r&xwl$p;RTp)QYuf{NYfeK#N#f?2$`kx=6?Ddb&Tg*p3aN z9%dCY%a62oy*dq-p>5dw9c_?XN`Z3TI}ok++E-iXWNr}bk72a7S*J^R@|^^Gdchi{ zR)U*7AIYWV(!Dba$dCjM@6fP0Zne{zzf#cmxc*t{!_#9%hXhRU6g!hE#*~9M%(7z9 z8*Iu$oo!u0+&!(?*F;5AUo4o+q|#mH^IWE#o=+cj9;HH>JvPzYAobCF8+`p85x8RR zl5OD@)+U(UB1>D`;H zc>hDYZy1OtewHPfb7x7QJ$exd58eJ{fTLBgc(#DE^quD5sVDg|v^h&mY{I!8UT_IVH8pKPiZwdBo zOju9GL2_4~-5Ra7_NWdI0w+l|B0bI>@@705F;D+bs>^ajqub9lJfm%QJCPTlu`&l? z$tQ{5y9;Ix0H>a1wa^Wi#0(*^2=7Niq3~&w$o!?38@dxr$k5pC<-69_k5`x1(V#{% zyrK6d^RkAJn7zyq23Z0%0D@Ni#_eU!57tW*rA08$01~6Nx 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

    h%IwBbu**oSX|jn? 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

    Zm>NiyZLxw^l? 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

    V>~(D)D~Xob|cx}(^-w3 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 z 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 z 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 - + @@ -30,4 +30,4 @@ - \ No newline at end of file + diff --git a/ui/src/themes/openems/environments/backend-dev.ts b/ui/src/themes/openems/environments/backend-dev.ts index f48b00c5e42..0f93f985f5d 100644 --- a/ui/src/themes/openems/environments/backend-dev.ts +++ b/ui/src/themes/openems/environments/backend-dev.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Environment } from "src/environments"; import { theme } from "./theme"; diff --git a/ui/src/themes/openems/environments/backend-docker.ts b/ui/src/themes/openems/environments/backend-docker.ts index 386f296c86d..5ca08fb74f8 100644 --- a/ui/src/themes/openems/environments/backend-docker.ts +++ b/ui/src/themes/openems/environments/backend-docker.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Environment } from "src/environments"; import { theme } from "./theme"; diff --git a/ui/src/themes/openems/environments/backend-prod.ts b/ui/src/themes/openems/environments/backend-prod.ts index ae5bb5eb32f..114c43274f1 100644 --- a/ui/src/themes/openems/environments/backend-prod.ts +++ b/ui/src/themes/openems/environments/backend-prod.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Environment } from "src/environments"; import { theme } from "./theme"; diff --git a/ui/src/themes/openems/environments/edge-dev.ts b/ui/src/themes/openems/environments/edge-dev.ts index 164dd04f34e..a6fd796b39e 100644 --- a/ui/src/themes/openems/environments/edge-dev.ts +++ b/ui/src/themes/openems/environments/edge-dev.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Environment } from "src/environments"; import { theme } from "./theme"; diff --git a/ui/src/themes/openems/environments/edge-docker.ts b/ui/src/themes/openems/environments/edge-docker.ts index d174226e837..80ed1d80a99 100644 --- a/ui/src/themes/openems/environments/edge-docker.ts +++ b/ui/src/themes/openems/environments/edge-docker.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Environment } from "src/environments"; import { theme } from "./theme"; diff --git a/ui/src/themes/openems/environments/edge-prod.ts b/ui/src/themes/openems/environments/edge-prod.ts index bcaf40f6901..4f023294025 100644 --- a/ui/src/themes/openems/environments/edge-prod.ts +++ b/ui/src/themes/openems/environments/edge-prod.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Environment } from "src/environments"; import { theme } from "./theme"; diff --git a/ui/src/themes/openems/environments/gitpod.ts b/ui/src/themes/openems/environments/gitpod.ts index 1ef2f8ca499..4b8f7f22ead 100644 --- a/ui/src/themes/openems/environments/gitpod.ts +++ b/ui/src/themes/openems/environments/gitpod.ts @@ -1,3 +1,4 @@ +// @ts-strict-ignore import { Environment } from "src/environments"; import { theme } from "./theme"; diff --git a/ui/tsconfig.json b/ui/tsconfig.json index 79f74f6da18..997c7208b30 100644 --- a/ui/tsconfig.json +++ b/ui/tsconfig.json @@ -9,7 +9,13 @@ "downlevelIteration": true, "experimentalDecorators": true, "moduleResolution": "node", + "plugins": [ + { + "name": "typescript-strict-plugin" + } + ], "importHelpers": true, + "strict": false, "target": "ES2022", "module": "es2020", "noImplicitOverride": true, @@ -27,4 +33,4 @@ "strictInputAccessModifiers": true, "strictTemplates": false } -} \ No newline at end of file +} From 3f420338b6d9ad0a69fe11441f422f6e4bf50f1d Mon Sep 17 00:00:00 2001 From: Thomas Sicking <91258335+tsicking@users.noreply.github.com> Date: Mon, 29 Apr 2024 15:29:55 +0200 Subject: [PATCH 006/173] Modbus SunSpec: synchronize Channel values (#2609) * onUpdate() replaced by onSetNextValue() in mapFirstPointToChannel() * Fix prepare-commit script --- io.openems.edge.application/EdgeApp.bndrun | 4 +- .../AbstractOpenemsSunSpecComponent.java | 2 +- tools/prepare-commit.sh | 4 +- ui/package-lock.json | 5517 ++++++----------- 4 files changed, 1761 insertions(+), 3766 deletions(-) diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index 4eea8ce4531..d79a89639bc 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -105,8 +105,8 @@ bnd.identity;id='io.openems.edge.controller.symmetric.timeslotpeakshaving',\ bnd.identity;id='io.openems.edge.core',\ bnd.identity;id='io.openems.edge.edge2edge',\ - bnd.identity;id='io.openems.edge.ess.adstec.storaxe',\ bnd.identity;id='io.openems.edge.energy',\ + bnd.identity;id='io.openems.edge.ess.adstec.storaxe',\ bnd.identity;id='io.openems.edge.ess.byd.container',\ bnd.identity;id='io.openems.edge.ess.cluster',\ bnd.identity;id='io.openems.edge.ess.core',\ @@ -271,9 +271,9 @@ io.openems.edge.controller.symmetric.timeslotpeakshaving;version=snapshot,\ io.openems.edge.core;version=snapshot,\ io.openems.edge.edge2edge;version=snapshot,\ - io.openems.edge.ess.adstec.storaxe;version=snapshot,\ io.openems.edge.energy;version=snapshot,\ io.openems.edge.energy.api;version=snapshot,\ + io.openems.edge.ess.adstec.storaxe;version=snapshot,\ io.openems.edge.ess.api;version=snapshot,\ io.openems.edge.ess.byd.container;version=snapshot,\ io.openems.edge.ess.cluster;version=snapshot,\ diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/AbstractOpenemsSunSpecComponent.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/AbstractOpenemsSunSpecComponent.java index 1f95e69272b..a45c8251a35 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/AbstractOpenemsSunSpecComponent.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/AbstractOpenemsSunSpecComponent.java @@ -457,7 +457,7 @@ protected void mapFirstPointToChannel(io.openems.edge.common.channel.ChannelId t for (SunSpecPoint point : points) { Optional> c = this.getSunSpecChannel(point); if (c.isPresent()) { - c.get().onUpdate(value -> { + c.get().onSetNextValue(value -> { this.channel(targetChannel).setNextValue(converter.elementToChannel(value.get())); }); return; diff --git a/tools/prepare-commit.sh b/tools/prepare-commit.sh index 62e4a91d8ed..2f7db41cca9 100755 --- a/tools/prepare-commit.sh +++ b/tools/prepare-commit.sh @@ -200,9 +200,9 @@ npm install node_modules/.bin/ng lint --fix node_modules/.bin/tsc node_modules/.bin/tsc-strict -node_modules/.bin/ng build -c "fenecon,fenecon-backend-prod,prod" +node_modules/.bin/ng build -c "openems,openems-backend-prod,prod" npm run test -- --no-watch --no-progress --browsers=ChromeHeadlessCI cd .. echo -echo "Finished" \ No newline at end of file +echo "Finished" diff --git a/ui/package-lock.json b/ui/package-lock.json index 85710afd431..90fc27fd10a 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -79,18 +79,16 @@ }, "node_modules/@aashutoshrathi/word-wrap": { "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/@ampproject/remapping": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" @@ -101,9 +99,8 @@ }, "node_modules/@angular-devkit/architect": { "version": "0.1602.13", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.13.tgz", - "integrity": "sha512-ejrOYoXgbhDYjdaW4B2SyWeb6AqR8vqqzMyvCq2JX7fo08IhLnVu1fcl0fwr161l37TuzgPNWrHSciOzzmZDkw==", "dev": true, + "license": "MIT", "dependencies": { "@angular-devkit/core": "16.2.13", "rxjs": "7.8.1" @@ -116,18 +113,16 @@ }, "node_modules/@angular-devkit/architect/node_modules/rxjs": { "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@angular-devkit/build-angular": { "version": "16.2.13", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-16.2.13.tgz", - "integrity": "sha512-2G8gnBpBKcu+/jJH5DJZyMgn2RwDFPgiNSkcLKFg5DdqVFVT3CCoZAobfpAEMndrysfMmoUPGuAmsgCfdczQjg==", "dev": true, + "license": "MIT", "dependencies": { "@ampproject/remapping": "2.2.1", "@angular-devkit/architect": "0.1602.13", @@ -247,9 +242,8 @@ }, "node_modules/@angular-devkit/build-angular/node_modules/@ampproject/remapping": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.3.0", "@jridgewell/trace-mapping": "^0.3.9" @@ -260,9 +254,8 @@ }, "node_modules/@angular-devkit/build-angular/node_modules/@babel/core": { "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.9.tgz", - "integrity": "sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w==", "dev": true, + "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.22.5", @@ -290,18 +283,16 @@ }, "node_modules/@angular-devkit/build-angular/node_modules/@babel/core/node_modules/semver": { "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" } }, "node_modules/@angular-devkit/build-angular/node_modules/@babel/runtime": { "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.6.tgz", - "integrity": "sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==", "dev": true, + "license": "MIT", "dependencies": { "regenerator-runtime": "^0.13.11" }, @@ -311,9 +302,8 @@ }, "node_modules/@angular-devkit/build-angular/node_modules/@babel/template": { "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", - "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.22.5", "@babel/parser": "^7.22.5", @@ -325,9 +315,8 @@ }, "node_modules/@angular-devkit/build-angular/node_modules/ajv": { "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -341,24 +330,21 @@ }, "node_modules/@angular-devkit/build-angular/node_modules/ajv-keywords": { "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", "dev": true, + "license": "MIT", "peerDependencies": { "ajv": "^6.9.1" } }, "node_modules/@angular-devkit/build-angular/node_modules/commander": { "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@angular-devkit/build-angular/node_modules/fast-glob": { "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -372,21 +358,18 @@ }, "node_modules/@angular-devkit/build-angular/node_modules/json-schema-traverse": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@angular-devkit/build-angular/node_modules/jsonc-parser": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@angular-devkit/build-angular/node_modules/less": { "version": "4.1.3", - "resolved": "https://registry.npmjs.org/less/-/less-4.1.3.tgz", - "integrity": "sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "copy-anything": "^2.0.1", "parse-node-version": "^1.0.1", @@ -410,9 +393,8 @@ }, "node_modules/@angular-devkit/build-angular/node_modules/lru-cache": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -422,8 +404,6 @@ }, "node_modules/@angular-devkit/build-angular/node_modules/postcss": { "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "dev": true, "funding": [ { @@ -439,6 +419,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", @@ -450,24 +431,21 @@ }, "node_modules/@angular-devkit/build-angular/node_modules/regenerator-runtime": { "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@angular-devkit/build-angular/node_modules/rxjs": { "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@angular-devkit/build-angular/node_modules/schema-utils": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dev": true, + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -483,9 +461,8 @@ }, "node_modules/@angular-devkit/build-angular/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, + "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -498,9 +475,8 @@ }, "node_modules/@angular-devkit/build-angular/node_modules/source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "optional": true, "engines": { "node": ">=0.10.0" @@ -508,9 +484,8 @@ }, "node_modules/@angular-devkit/build-angular/node_modules/terser": { "version": "5.19.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.19.2.tgz", - "integrity": "sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -526,15 +501,13 @@ }, "node_modules/@angular-devkit/build-angular/node_modules/tslib": { "version": "2.6.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", - "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==", - "dev": true + "dev": true, + "license": "0BSD" }, "node_modules/@angular-devkit/build-angular/node_modules/webpack": { "version": "5.88.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz", - "integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.0", @@ -579,15 +552,13 @@ }, "node_modules/@angular-devkit/build-angular/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/@angular-devkit/build-webpack": { "version": "0.1602.13", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1602.13.tgz", - "integrity": "sha512-H7CqnC0kvWR0Q45ZXsCO3M9lGd4dOajEmkCVmq7vVptU3nJRbCqJ0ZScj9bH5YSlcdO0jPbOdcTELWyEZ3BMFQ==", "dev": true, + "license": "MIT", "dependencies": { "@angular-devkit/architect": "0.1602.13", "rxjs": "7.8.1" @@ -604,18 +575,16 @@ }, "node_modules/@angular-devkit/build-webpack/node_modules/rxjs": { "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@angular-devkit/core": { "version": "16.2.13", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.13.tgz", - "integrity": "sha512-6jTlYOIeYsOF/Vw/hBNusjoCmKJBByoyGS1Fu2Yav8ltxYK04aDtI73l9JJB/5Cpzhc4YELrMqBMH7in5Vowaw==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "8.12.0", "ajv-formats": "2.1.1", @@ -640,24 +609,21 @@ }, "node_modules/@angular-devkit/core/node_modules/jsonc-parser": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@angular-devkit/core/node_modules/rxjs": { "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@angular-devkit/schematics": { "version": "16.2.13", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-16.2.13.tgz", - "integrity": "sha512-uhhJZpppaeuT/2V6RiCheJKzS4bAZADL+Gw59VJaojqS8ssdG1UzvqRJokIzFzP7+MhHWylZBWUvWLQxuUvtsA==", "dev": true, + "license": "MIT", "dependencies": { "@angular-devkit/core": "16.2.13", "jsonc-parser": "3.2.0", @@ -673,24 +639,21 @@ }, "node_modules/@angular-devkit/schematics/node_modules/jsonc-parser": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@angular-devkit/schematics/node_modules/rxjs": { "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@angular-eslint/builder": { "version": "16.3.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-16.3.1.tgz", - "integrity": "sha512-PmIOnRwqdOW1bvZtpTGBTDcOq/Czm3D+IPC/k90yIMs1VsAtcxqUmUtELje+ylJeb2LPeEZavekSnEpcatM4HQ==", "dev": true, + "license": "MIT", "dependencies": { "@nx/devkit": "16.5.1", "nx": "16.5.1" @@ -702,15 +665,13 @@ }, "node_modules/@angular-eslint/bundled-angular-compiler": { "version": "16.3.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-16.3.1.tgz", - "integrity": "sha512-m4WP1xwS9XLcC/3n6lIcG5HZoai/5eb5W3xm48GVcv//0qE2p7S96RSgKPgGHvif5pF8O9xAqEWs3gDEG45+7A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@angular-eslint/eslint-plugin": { "version": "16.3.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-16.3.1.tgz", - "integrity": "sha512-kSc8ESfoy8TUSthbq0Lpq9e17I+3Smy4rHoNpKCFEGuJgPs0+OssZMxB6a5EawGbv2EKTPEtrxzFm1WsLR0U9Q==", "dev": true, + "license": "MIT", "dependencies": { "@angular-eslint/utils": "16.3.1", "@typescript-eslint/utils": "5.62.0" @@ -722,9 +683,8 @@ }, "node_modules/@angular-eslint/eslint-plugin-template": { "version": "16.3.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-16.3.1.tgz", - "integrity": "sha512-+RcFEWqNiRt3+5jXvmlIDlXtP9+vjdmgmVL6tt8yDbqdjBOewtyMu4pE4YaR4sFboyxgME9PbO2WrOyPXh6xjg==", "dev": true, + "license": "MIT", "dependencies": { "@angular-eslint/bundled-angular-compiler": "16.3.1", "@angular-eslint/utils": "16.3.1", @@ -740,9 +700,8 @@ }, "node_modules/@angular-eslint/template-parser": { "version": "16.3.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-16.3.1.tgz", - "integrity": "sha512-9+SxUtxB2iOnm0ldS2ow0stMxe02rB/TxeMIe8fxsLFHZdw8RQvs/p3HLvVHXzv6gUblMHebIb/ubUmwEVb2SA==", "dev": true, + "license": "MIT", "dependencies": { "@angular-eslint/bundled-angular-compiler": "16.3.1", "eslint-scope": "^7.0.0" @@ -754,9 +713,8 @@ }, "node_modules/@angular-eslint/template-parser/node_modules/eslint-scope": { "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -770,18 +728,16 @@ }, "node_modules/@angular-eslint/template-parser/node_modules/estraverse": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } }, "node_modules/@angular-eslint/utils": { "version": "16.3.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-16.3.1.tgz", - "integrity": "sha512-tEBcce0rG+DmcPO8jhRffUFDioGw3G4cUAE15XlRctY1J3QzOBH9HdUOTDt0mMjBgpWCzh0YVT1Moh2bPXU9Xg==", "dev": true, + "license": "MIT", "dependencies": { "@angular-eslint/bundled-angular-compiler": "16.3.1", "@typescript-eslint/utils": "5.62.0" @@ -793,8 +749,7 @@ }, "node_modules/@angular/animations": { "version": "16.2.12", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-16.2.12.tgz", - "integrity": "sha512-MD0ElviEfAJY8qMOd6/jjSSvtqER2RDAi0lxe6EtUacC1DHCYkaPrKW4vLqY+tmZBg1yf+6n+uS77pXcHHcA3w==", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, @@ -807,8 +762,7 @@ }, "node_modules/@angular/cdk": { "version": "15.2.9", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-15.2.9.tgz", - "integrity": "sha512-koaM07N1AIQ5oHU27l0/FoQSSoYAwlAYwVZ4Di3bYrJsTBNCN2Xsby7wI8gZxdepMnV4Fe9si382BDBov+oO4Q==", + "license": "MIT", "peer": true, "dependencies": { "tslib": "^2.3.0" @@ -824,8 +778,7 @@ }, "node_modules/@angular/cdk/node_modules/parse5": { "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "license": "MIT", "optional": true, "peer": true, "dependencies": { @@ -837,9 +790,8 @@ }, "node_modules/@angular/cli": { "version": "16.2.13", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-16.2.13.tgz", - "integrity": "sha512-Zs/IHV0qeQBlRYp3XTJP96KKMFrOVd4gFWEXyt8xVbma9W7UCWr/0C6D8HRFjheiT40TSa2Suwpk6Hppm+9ESA==", "dev": true, + "license": "MIT", "dependencies": { "@angular-devkit/architect": "0.1602.13", "@angular-devkit/core": "16.2.13", @@ -871,15 +823,13 @@ }, "node_modules/@angular/cli/node_modules/jsonc-parser": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@angular/cli/node_modules/lru-cache": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -889,9 +839,8 @@ }, "node_modules/@angular/cli/node_modules/resolve": { "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", "dev": true, + "license": "MIT", "dependencies": { "is-core-module": "^2.11.0", "path-parse": "^1.0.7", @@ -906,9 +855,8 @@ }, "node_modules/@angular/cli/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, + "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -921,14 +869,12 @@ }, "node_modules/@angular/cli/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/@angular/common": { "version": "16.2.12", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-16.2.12.tgz", - "integrity": "sha512-B+WY/cT2VgEaz9HfJitBmgdk4I333XG/ybC98CMC4Wz8E49T8yzivmmxXB3OD6qvjcOB6ftuicl6WBqLbZNg2w==", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, @@ -942,8 +888,7 @@ }, "node_modules/@angular/compiler": { "version": "16.2.12", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-16.2.12.tgz", - "integrity": "sha512-6SMXUgSVekGM7R6l1Z9rCtUGtlg58GFmgbpMCsGf+VXxP468Njw8rjT2YZkf5aEPxEuRpSHhDYjqz7n14cwCXQ==", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, @@ -961,9 +906,8 @@ }, "node_modules/@angular/compiler-cli": { "version": "16.2.12", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-16.2.12.tgz", - "integrity": "sha512-pWSrr152562ujh6lsFZR8NfNc5Ljj+zSTQO44DsuB0tZjwEpnRcjJEgzuhGXr+CoiBf+jTSPZKemtSktDk5aaA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/core": "7.23.2", "@jridgewell/sourcemap-codec": "^1.4.14", @@ -989,8 +933,7 @@ }, "node_modules/@angular/core": { "version": "16.2.12", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-16.2.12.tgz", - "integrity": "sha512-GLLlDeke/NjroaLYOks0uyzFVo6HyLl7VOm0K1QpLXnYvW63W9Ql/T3yguRZa7tRkOAeFZ3jw+1wnBD4O8MoUA==", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, @@ -1004,8 +947,7 @@ }, "node_modules/@angular/forms": { "version": "16.2.12", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-16.2.12.tgz", - "integrity": "sha512-1Eao89hlBgLR3v8tU91vccn21BBKL06WWxl7zLpQmG6Hun+2jrThgOE4Pf3os4fkkbH4Apj0tWL2fNIWe/blbw==", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, @@ -1021,17 +963,15 @@ }, "node_modules/@angular/language-service": { "version": "16.2.12", - "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-16.2.12.tgz", - "integrity": "sha512-sZwB+ZEjChx9EYcqPaS4OnhC/q5RcedZjIdM9mCxuU/MtseURRYRI/8Hnm1RHo9qyc5PmsQpg7p9Vp/5hXLUjw==", "dev": true, + "license": "MIT", "engines": { "node": "^16.14.0 || >=18.10.0" } }, "node_modules/@angular/platform-browser": { "version": "16.2.12", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-16.2.12.tgz", - "integrity": "sha512-NnH7ju1iirmVEsUq432DTm0nZBGQsBrU40M3ZeVHMQ2subnGiyUs3QyzDz8+VWLL/T5xTxWLt9BkDn65vgzlIQ==", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, @@ -1051,8 +991,7 @@ }, "node_modules/@angular/platform-browser-dynamic": { "version": "16.2.12", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-16.2.12.tgz", - "integrity": "sha512-ya54jerNgreCVAR278wZavwjrUWImMr2F8yM5n9HBvsMBbFaAQ83anwbOEiHEF2BlR+gJiEBLfpuPRMw20pHqw==", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, @@ -1068,8 +1007,7 @@ }, "node_modules/@angular/router": { "version": "16.2.12", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-16.2.12.tgz", - "integrity": "sha512-aU6QnYSza005V9P3W6PpkieL56O0IHps96DjqI1RS8yOJUl3THmokqYN4Fm5+HXy4f390FN9i6ftadYQDKeWmA==", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, @@ -1085,8 +1023,7 @@ }, "node_modules/@angular/service-worker": { "version": "16.2.12", - "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-16.2.12.tgz", - "integrity": "sha512-o0z0s4c76NmRASa+mUHn/q6vUKQNa06mGmLBDKm84vRQ1sQ2TJv+R1p8K9WkiM5mGy6tjQCDOgaz13TcxMFWOQ==", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, @@ -1103,15 +1040,13 @@ }, "node_modules/@assemblyscript/loader": { "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.10.1.tgz", - "integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/@babel/code-frame": { "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", - "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/highlight": "^7.24.2", "picocolors": "^1.0.0" @@ -1122,18 +1057,16 @@ }, "node_modules/@babel/compat-data": { "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", - "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz", - "integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==", "dev": true, + "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.22.13", @@ -1161,9 +1094,8 @@ }, "node_modules/@babel/core/node_modules/@babel/generator": { "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz", - "integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.24.0", "@jridgewell/gen-mapping": "^0.3.5", @@ -1176,24 +1108,21 @@ }, "node_modules/@babel/core/node_modules/convert-source-map": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@babel/core/node_modules/semver": { "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" } }, "node_modules/@babel/generator": { "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.9.tgz", - "integrity": "sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.22.5", "@jridgewell/gen-mapping": "^0.3.2", @@ -1206,9 +1135,8 @@ }, "node_modules/@babel/helper-annotate-as-pure": { "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", - "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.22.5" }, @@ -1218,9 +1146,8 @@ }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", - "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.22.15" }, @@ -1230,9 +1157,8 @@ }, "node_modules/@babel/helper-compilation-targets": { "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", - "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/compat-data": "^7.23.5", "@babel/helper-validator-option": "^7.23.5", @@ -1246,18 +1172,16 @@ }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { "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" } }, "node_modules/@babel/helper-create-class-features-plugin": { "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.4.tgz", - "integrity": "sha512-lG75yeuUSVu0pIcbhiYMXBXANHrpUPaOfu7ryAzskCgKUHuAxRQI5ssrtmF0X9UXldPlvT0XM/A4F44OXRt6iQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-environment-visitor": "^7.22.20", @@ -1278,18 +1202,16 @@ }, "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { "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" } }, "node_modules/@babel/helper-create-regexp-features-plugin": { "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", - "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "regexpu-core": "^5.3.1", @@ -1304,18 +1226,16 @@ }, "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { "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" } }, "node_modules/@babel/helper-define-polyfill-provider": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.1.tgz", - "integrity": "sha512-o7SDgTJuvx5vLKD6SFvkydkSMBvahDKGiNJzG22IZYXhiqoe9efY7zocICBgzHV4IRg5wdgl2nEL/tulKIEIbA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", @@ -1329,18 +1249,16 @@ }, "node_modules/@babel/helper-environment-visitor": { "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/template": "^7.22.15", "@babel/types": "^7.23.0" @@ -1351,9 +1269,8 @@ }, "node_modules/@babel/helper-hoist-variables": { "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.22.5" }, @@ -1363,9 +1280,8 @@ }, "node_modules/@babel/helper-member-expression-to-functions": { "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", - "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.23.0" }, @@ -1375,9 +1291,8 @@ }, "node_modules/@babel/helper-module-imports": { "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.22.15" }, @@ -1387,9 +1302,8 @@ }, "node_modules/@babel/helper-module-transforms": { "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", - "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-module-imports": "^7.22.15", @@ -1406,9 +1320,8 @@ }, "node_modules/@babel/helper-optimise-call-expression": { "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", - "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.22.5" }, @@ -1418,18 +1331,16 @@ }, "node_modules/@babel/helper-plugin-utils": { "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", - "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", - "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-environment-visitor": "^7.22.20", @@ -1444,9 +1355,8 @@ }, "node_modules/@babel/helper-replace-supers": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.1.tgz", - "integrity": "sha512-QCR1UqC9BzG5vZl8BMicmZ28RuUBnHhAMddD8yHFHDRH9lLTZ9uUPehX8ctVPT8l0TKblJidqcgUUKGVrePleQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-member-expression-to-functions": "^7.23.0", @@ -1461,9 +1371,8 @@ }, "node_modules/@babel/helper-simple-access": { "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.22.5" }, @@ -1473,9 +1382,8 @@ }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", - "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.22.5" }, @@ -1485,9 +1393,8 @@ }, "node_modules/@babel/helper-split-export-declaration": { "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.22.5" }, @@ -1497,36 +1404,32 @@ }, "node_modules/@babel/helper-string-parser": { "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", - "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-wrap-function": { "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", - "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-function-name": "^7.22.5", "@babel/template": "^7.22.15", @@ -1538,9 +1441,8 @@ }, "node_modules/@babel/helpers": { "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz", - "integrity": "sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/template": "^7.24.0", "@babel/traverse": "^7.24.1", @@ -1552,9 +1454,8 @@ }, "node_modules/@babel/highlight": { "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", - "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", @@ -1567,9 +1468,8 @@ }, "node_modules/@babel/parser": { "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", - "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==", "dev": true, + "license": "MIT", "bin": { "parser": "bin/babel-parser.js" }, @@ -1579,9 +1479,8 @@ }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.1.tgz", - "integrity": "sha512-y4HqEnkelJIOQGd+3g1bTeKsA5c6qM7eOn7VggGVbBc0y8MLSKHacwcIE2PplNlQSj0PqS9rrXL/nkPVK+kUNg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -1594,9 +1493,8 @@ }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.1.tgz", - "integrity": "sha512-Hj791Ii4ci8HqnaKHAlLNs+zaLXb0EzSDhiAWp5VNlyvCNymYfacs64pxTxbH1znW/NcArSmwpmG9IKE/TUVVQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0", "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", @@ -1611,10 +1509,8 @@ }, "node_modules/@babel/plugin-proposal-async-generator-functions": { "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz", - "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-async-generator-functions instead.", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-plugin-utils": "^7.20.2", @@ -1630,9 +1526,8 @@ }, "node_modules/@babel/plugin-proposal-private-property-in-object": { "version": "7.21.0-placeholder-for-preset-env.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", - "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" }, @@ -1642,10 +1537,8 @@ }, "node_modules/@babel/plugin-proposal-unicode-property-regex": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", - "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-unicode-property-regex instead.", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" @@ -1659,9 +1552,8 @@ }, "node_modules/@babel/plugin-syntax-async-generators": { "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1671,9 +1563,8 @@ }, "node_modules/@babel/plugin-syntax-class-properties": { "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.12.13" }, @@ -1683,9 +1574,8 @@ }, "node_modules/@babel/plugin-syntax-class-static-block": { "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -1698,9 +1588,8 @@ }, "node_modules/@babel/plugin-syntax-dynamic-import": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1710,9 +1599,8 @@ }, "node_modules/@babel/plugin-syntax-export-namespace-from": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.3" }, @@ -1722,9 +1610,8 @@ }, "node_modules/@babel/plugin-syntax-import-assertions": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.1.tgz", - "integrity": "sha512-IuwnI5XnuF189t91XbxmXeCDz3qs6iDRO7GJ++wcfgeXNs/8FmIlKcpDSXNVyuLQxlwvskmI3Ct73wUODkJBlQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -1737,9 +1624,8 @@ }, "node_modules/@babel/plugin-syntax-import-attributes": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.1.tgz", - "integrity": "sha512-zhQTMH0X2nVLnb04tz+s7AMuasX8U0FnpE+nHTOhSOINjWMnopoZTxtIKsd45n4GQ/HIZLyfIpoul8e2m0DnRA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -1752,9 +1638,8 @@ }, "node_modules/@babel/plugin-syntax-import-meta": { "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -1764,9 +1649,8 @@ }, "node_modules/@babel/plugin-syntax-json-strings": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1776,9 +1660,8 @@ }, "node_modules/@babel/plugin-syntax-logical-assignment-operators": { "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -1788,9 +1671,8 @@ }, "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1800,9 +1682,8 @@ }, "node_modules/@babel/plugin-syntax-numeric-separator": { "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -1812,9 +1693,8 @@ }, "node_modules/@babel/plugin-syntax-object-rest-spread": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1824,9 +1704,8 @@ }, "node_modules/@babel/plugin-syntax-optional-catch-binding": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1836,9 +1715,8 @@ }, "node_modules/@babel/plugin-syntax-optional-chaining": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1848,9 +1726,8 @@ }, "node_modules/@babel/plugin-syntax-private-property-in-object": { "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -1863,9 +1740,8 @@ }, "node_modules/@babel/plugin-syntax-top-level-await": { "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -1878,9 +1754,8 @@ }, "node_modules/@babel/plugin-syntax-unicode-sets-regex": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", - "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" @@ -1894,9 +1769,8 @@ }, "node_modules/@babel/plugin-transform-arrow-functions": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.1.tgz", - "integrity": "sha512-ngT/3NkRhsaep9ck9uj2Xhv9+xB1zShY3tM3g6om4xxCELwCDN4g4Aq5dRn48+0hasAql7s2hdBOysCfNpr4fw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -1909,9 +1783,8 @@ }, "node_modules/@babel/plugin-transform-async-generator-functions": { "version": "7.24.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.3.tgz", - "integrity": "sha512-Qe26CMYVjpQxJ8zxM1340JFNjZaF+ISWpr1Kt/jGo+ZTUzKkfw/pphEWbRCb+lmSM6k/TOgfYLvmbHkUQ0asIg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-plugin-utils": "^7.24.0", @@ -1927,9 +1800,8 @@ }, "node_modules/@babel/plugin-transform-async-to-generator": { "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.22.5.tgz", - "integrity": "sha512-b1A8D8ZzE/VhNDoV1MSJTnpKkCG5bJo+19R4o4oy03zM7ws8yEMK755j61Dc3EyvdysbqH5BOOTquJ7ZX9C6vQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.22.5", "@babel/helper-plugin-utils": "^7.22.5", @@ -1944,9 +1816,8 @@ }, "node_modules/@babel/plugin-transform-block-scoped-functions": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.1.tgz", - "integrity": "sha512-TWWC18OShZutrv9C6mye1xwtam+uNi2bnTOCBUd5sZxyHOiWbU6ztSROofIMrK84uweEZC219POICK/sTYwfgg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -1959,9 +1830,8 @@ }, "node_modules/@babel/plugin-transform-block-scoping": { "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.4.tgz", - "integrity": "sha512-nIFUZIpGKDf9O9ttyRXpHFpKC+X3Y5mtshZONuEUYBomAKoM4y029Jr+uB1bHGPhNmK8YXHevDtKDOLmtRrp6g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -1974,9 +1844,8 @@ }, "node_modules/@babel/plugin-transform-class-properties": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.1.tgz", - "integrity": "sha512-OMLCXi0NqvJfORTaPQBwqLXHhb93wkBKZ4aNwMl6WtehO7ar+cmp+89iPEQPqxAnxsOKTaMcs3POz3rKayJ72g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.24.1", "@babel/helper-plugin-utils": "^7.24.0" @@ -1990,9 +1859,8 @@ }, "node_modules/@babel/plugin-transform-class-static-block": { "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.4.tgz", - "integrity": "sha512-B8q7Pz870Hz/q9UgP8InNpY01CSLDSCyqX7zcRuv3FcPl87A2G17lASroHWaCtbdIcbYzOZ7kWmXFKbijMSmFg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.24.4", "@babel/helper-plugin-utils": "^7.24.0", @@ -2007,9 +1875,8 @@ }, "node_modules/@babel/plugin-transform-classes": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.1.tgz", - "integrity": "sha512-ZTIe3W7UejJd3/3R4p7ScyyOoafetUShSf4kCqV0O7F/RiHxVj/wRaRnQlrGwflvcehNA8M42HkAiEDYZu2F1Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-compilation-targets": "^7.23.6", @@ -2029,9 +1896,8 @@ }, "node_modules/@babel/plugin-transform-computed-properties": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.1.tgz", - "integrity": "sha512-5pJGVIUfJpOS+pAqBQd+QMaTD2vCL/HcePooON6pDpHgRp4gNRmzyHTPIkXntwKsq3ayUFVfJaIKPw2pOkOcTw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0", "@babel/template": "^7.24.0" @@ -2045,9 +1911,8 @@ }, "node_modules/@babel/plugin-transform-destructuring": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.1.tgz", - "integrity": "sha512-ow8jciWqNxR3RYbSNVuF4U2Jx130nwnBnhRw6N6h1bOejNkABmcI5X5oz29K4alWX7vf1C+o6gtKXikzRKkVdw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -2060,9 +1925,8 @@ }, "node_modules/@babel/plugin-transform-dotall-regex": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.1.tgz", - "integrity": "sha512-p7uUxgSoZwZ2lPNMzUkqCts3xlp8n+o05ikjy7gbtFJSt9gdU88jAmtfmOxHM14noQXBxfgzf2yRWECiNVhTCw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.22.15", "@babel/helper-plugin-utils": "^7.24.0" @@ -2076,9 +1940,8 @@ }, "node_modules/@babel/plugin-transform-duplicate-keys": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.1.tgz", - "integrity": "sha512-msyzuUnvsjsaSaocV6L7ErfNsa5nDWL1XKNnDePLgmz+WdU4w/J8+AxBMrWfi9m4IxfL5sZQKUPQKDQeeAT6lA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -2091,9 +1954,8 @@ }, "node_modules/@babel/plugin-transform-dynamic-import": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.1.tgz", - "integrity": "sha512-av2gdSTyXcJVdI+8aFZsCAtR29xJt0S5tas+Ef8NvBNmD1a+N/3ecMLeMBgfcK+xzsjdLDT6oHt+DFPyeqUbDA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-dynamic-import": "^7.8.3" @@ -2107,9 +1969,8 @@ }, "node_modules/@babel/plugin-transform-exponentiation-operator": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.1.tgz", - "integrity": "sha512-U1yX13dVBSwS23DEAqU+Z/PkwE9/m7QQy8Y9/+Tdb8UWYaGNDYwTLi19wqIAiROr8sXVum9A/rtiH5H0boUcTw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", "@babel/helper-plugin-utils": "^7.24.0" @@ -2123,9 +1984,8 @@ }, "node_modules/@babel/plugin-transform-export-namespace-from": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.1.tgz", - "integrity": "sha512-Ft38m/KFOyzKw2UaJFkWG9QnHPG/Q/2SkOrRk4pNBPg5IPZ+dOxcmkK5IyuBcxiNPyyYowPGUReyBvrvZs7IlQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" @@ -2139,9 +1999,8 @@ }, "node_modules/@babel/plugin-transform-for-of": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.1.tgz", - "integrity": "sha512-OxBdcnF04bpdQdR3i4giHZNZQn7cm8RQKcSwA17wAAqEELo1ZOwp5FFgeptWUQXFyT9kwHo10aqqauYkRZPCAg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0", "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" @@ -2155,9 +2014,8 @@ }, "node_modules/@babel/plugin-transform-function-name": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.1.tgz", - "integrity": "sha512-BXmDZpPlh7jwicKArQASrj8n22/w6iymRnvHYYd2zO30DbE277JO20/7yXJT3QxDPtiQiOxQBbZH4TpivNXIxA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-function-name": "^7.23.0", @@ -2172,9 +2030,8 @@ }, "node_modules/@babel/plugin-transform-json-strings": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.1.tgz", - "integrity": "sha512-U7RMFmRvoasscrIFy5xA4gIp8iWnWubnKkKuUGJjsuOH7GfbMkB+XZzeslx2kLdEGdOJDamEmCqOks6e8nv8DQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-json-strings": "^7.8.3" @@ -2188,9 +2045,8 @@ }, "node_modules/@babel/plugin-transform-literals": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.1.tgz", - "integrity": "sha512-zn9pwz8U7nCqOYIiBaOxoQOtYmMODXTJnkxG4AtX8fPmnCRYWBOHD0qcpwS9e2VDSp1zNJYpdnFMIKb8jmwu6g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -2203,9 +2059,8 @@ }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.1.tgz", - "integrity": "sha512-OhN6J4Bpz+hIBqItTeWJujDOfNP+unqv/NJgyhlpSqgBTPm37KkMmZV6SYcOj+pnDbdcl1qRGV/ZiIjX9Iy34w==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" @@ -2219,9 +2074,8 @@ }, "node_modules/@babel/plugin-transform-member-expression-literals": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.1.tgz", - "integrity": "sha512-4ojai0KysTWXzHseJKa1XPNXKRbuUrhkOPY4rEGeR+7ChlJVKxFa3H3Bz+7tWaGKgJAXUWKOGmltN+u9B3+CVg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -2234,9 +2088,8 @@ }, "node_modules/@babel/plugin-transform-modules-amd": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.1.tgz", - "integrity": "sha512-lAxNHi4HVtjnHd5Rxg3D5t99Xm6H7b04hUS7EHIXcUl2EV4yl1gWdqZrNzXnSrHveL9qMdbODlLF55mvgjAfaQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.23.3", "@babel/helper-plugin-utils": "^7.24.0" @@ -2250,9 +2103,8 @@ }, "node_modules/@babel/plugin-transform-modules-commonjs": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.1.tgz", - "integrity": "sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.23.3", "@babel/helper-plugin-utils": "^7.24.0", @@ -2267,9 +2119,8 @@ }, "node_modules/@babel/plugin-transform-modules-systemjs": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.1.tgz", - "integrity": "sha512-mqQ3Zh9vFO1Tpmlt8QPnbwGHzNz3lpNEMxQb1kAemn/erstyqw1r9KeOlOfo3y6xAnFEcOv2tSyrXfmMk+/YZA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-module-transforms": "^7.23.3", @@ -2285,9 +2136,8 @@ }, "node_modules/@babel/plugin-transform-modules-umd": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.1.tgz", - "integrity": "sha512-tuA3lpPj+5ITfcCluy6nWonSL7RvaG0AOTeAuvXqEKS34lnLzXpDb0dcP6K8jD0zWZFNDVly90AGFJPnm4fOYg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.23.3", "@babel/helper-plugin-utils": "^7.24.0" @@ -2301,9 +2151,8 @@ }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", - "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.22.5", "@babel/helper-plugin-utils": "^7.22.5" @@ -2317,9 +2166,8 @@ }, "node_modules/@babel/plugin-transform-new-target": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.1.tgz", - "integrity": "sha512-/rurytBM34hYy0HKZQyA0nHbQgQNFm4Q/BOc9Hflxi2X3twRof7NaE5W46j4kQitm7SvACVRXsa6N/tSZxvPug==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -2332,9 +2180,8 @@ }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.1.tgz", - "integrity": "sha512-iQ+caew8wRrhCikO5DrUYx0mrmdhkaELgFa+7baMcVuhxIkN7oxt06CZ51D65ugIb1UWRQ8oQe+HXAVM6qHFjw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" @@ -2348,9 +2195,8 @@ }, "node_modules/@babel/plugin-transform-numeric-separator": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.1.tgz", - "integrity": "sha512-7GAsGlK4cNL2OExJH1DzmDeKnRv/LXq0eLUSvudrehVA5Rgg4bIrqEUW29FbKMBRT0ztSqisv7kjP+XIC4ZMNw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-numeric-separator": "^7.10.4" @@ -2364,9 +2210,8 @@ }, "node_modules/@babel/plugin-transform-object-rest-spread": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.1.tgz", - "integrity": "sha512-XjD5f0YqOtebto4HGISLNfiNMTTs6tbkFf2TOqJlYKYmbo+mN9Dnpl4SRoofiziuOWMIyq3sZEUqLo3hLITFEA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-plugin-utils": "^7.24.0", @@ -2382,9 +2227,8 @@ }, "node_modules/@babel/plugin-transform-object-super": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.1.tgz", - "integrity": "sha512-oKJqR3TeI5hSLRxudMjFQ9re9fBVUU0GICqM3J1mi8MqlhVr6hC/ZN4ttAyMuQR6EZZIY6h/exe5swqGNNIkWQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0", "@babel/helper-replace-supers": "^7.24.1" @@ -2398,9 +2242,8 @@ }, "node_modules/@babel/plugin-transform-optional-catch-binding": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.1.tgz", - "integrity": "sha512-oBTH7oURV4Y+3EUrf6cWn1OHio3qG/PVwO5J03iSJmBg6m2EhKjkAu/xuaXaYwWW9miYtvbWv4LNf0AmR43LUA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" @@ -2414,9 +2257,8 @@ }, "node_modules/@babel/plugin-transform-optional-chaining": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.1.tgz", - "integrity": "sha512-n03wmDt+987qXwAgcBlnUUivrZBPZ8z1plL0YvgQalLm+ZE5BMhGm94jhxXtA1wzv1Cu2aaOv1BM9vbVttrzSg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0", "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", @@ -2431,9 +2273,8 @@ }, "node_modules/@babel/plugin-transform-parameters": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.1.tgz", - "integrity": "sha512-8Jl6V24g+Uw5OGPeWNKrKqXPDw2YDjLc53ojwfMcKwlEoETKU9rU0mHUtcg9JntWI/QYzGAXNWEcVHZ+fR+XXg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -2446,9 +2287,8 @@ }, "node_modules/@babel/plugin-transform-private-methods": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.1.tgz", - "integrity": "sha512-tGvisebwBO5em4PaYNqt4fkw56K2VALsAbAakY0FjTYqJp7gfdrgr7YX76Or8/cpik0W6+tj3rZ0uHU9Oil4tw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.24.1", "@babel/helper-plugin-utils": "^7.24.0" @@ -2462,9 +2302,8 @@ }, "node_modules/@babel/plugin-transform-private-property-in-object": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.1.tgz", - "integrity": "sha512-pTHxDVa0BpUbvAgX3Gat+7cSciXqUcY9j2VZKTbSB6+VQGpNgNO9ailxTGHSXlqOnX1Hcx1Enme2+yv7VqP9bg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-create-class-features-plugin": "^7.24.1", @@ -2480,9 +2319,8 @@ }, "node_modules/@babel/plugin-transform-property-literals": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.1.tgz", - "integrity": "sha512-LetvD7CrHmEx0G442gOomRr66d7q8HzzGGr4PMHGr+5YIm6++Yke+jxj246rpvsbyhJwCLxcTn6zW1P1BSenqA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -2495,9 +2333,8 @@ }, "node_modules/@babel/plugin-transform-regenerator": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.1.tgz", - "integrity": "sha512-sJwZBCzIBE4t+5Q4IGLaaun5ExVMRY0lYwos/jNecjMrVCygCdph3IKv0tkP5Fc87e/1+bebAmEAGBfnRD+cnw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0", "regenerator-transform": "^0.15.2" @@ -2511,9 +2348,8 @@ }, "node_modules/@babel/plugin-transform-reserved-words": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.1.tgz", - "integrity": "sha512-JAclqStUfIwKN15HrsQADFgeZt+wexNQ0uLhuqvqAUFoqPMjEcFCYZBhq0LUdz6dZK/mD+rErhW71fbx8RYElg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -2526,9 +2362,8 @@ }, "node_modules/@babel/plugin-transform-runtime": { "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.22.9.tgz", - "integrity": "sha512-9KjBH61AGJetCPYp/IEyLEp47SyybZb0nDRpBvmtEkm+rUIwxdlKpyNHI1TmsGkeuLclJdleQHRZ8XLBnnh8CQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.22.5", "@babel/helper-plugin-utils": "^7.22.5", @@ -2546,18 +2381,16 @@ }, "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { "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" } }, "node_modules/@babel/plugin-transform-shorthand-properties": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.1.tgz", - "integrity": "sha512-LyjVB1nsJ6gTTUKRjRWx9C1s9hE7dLfP/knKdrfeH9UPtAGjYGgxIbFfx7xyLIEWs7Xe1Gnf8EWiUqfjLhInZA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -2570,9 +2403,8 @@ }, "node_modules/@babel/plugin-transform-spread": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.1.tgz", - "integrity": "sha512-KjmcIM+fxgY+KxPVbjelJC6hrH1CgtPmTvdXAfn3/a9CnWGSTY7nH4zm5+cjmWJybdcPSsD0++QssDsjcpe47g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0", "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" @@ -2586,9 +2418,8 @@ }, "node_modules/@babel/plugin-transform-sticky-regex": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.1.tgz", - "integrity": "sha512-9v0f1bRXgPVcPrngOQvLXeGNNVLc8UjMVfebo9ka0WF3/7+aVUHmaJVT3sa0XCzEFioPfPHZiOcYG9qOsH63cw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -2601,9 +2432,8 @@ }, "node_modules/@babel/plugin-transform-template-literals": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.1.tgz", - "integrity": "sha512-WRkhROsNzriarqECASCNu/nojeXCDTE/F2HmRgOzi7NGvyfYGq1NEjKBK3ckLfRgGc6/lPAqP0vDOSw3YtG34g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -2616,9 +2446,8 @@ }, "node_modules/@babel/plugin-transform-typeof-symbol": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.1.tgz", - "integrity": "sha512-CBfU4l/A+KruSUoW+vTQthwcAdwuqbpRNB8HQKlZABwHRhsdHZ9fezp4Sn18PeAlYxTNiLMlx4xUBV3AWfg1BA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -2631,9 +2460,8 @@ }, "node_modules/@babel/plugin-transform-unicode-escapes": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.1.tgz", - "integrity": "sha512-RlkVIcWT4TLI96zM660S877E7beKlQw7Ig+wqkKBiWfj0zH5Q4h50q6er4wzZKRNSYpfo6ILJ+hrJAGSX2qcNw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -2646,9 +2474,8 @@ }, "node_modules/@babel/plugin-transform-unicode-property-regex": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.1.tgz", - "integrity": "sha512-Ss4VvlfYV5huWApFsF8/Sq0oXnGO+jB+rijFEFugTd3cwSObUSnUi88djgR5528Csl0uKlrI331kRqe56Ov2Ng==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.22.15", "@babel/helper-plugin-utils": "^7.24.0" @@ -2662,9 +2489,8 @@ }, "node_modules/@babel/plugin-transform-unicode-regex": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.1.tgz", - "integrity": "sha512-2A/94wgZgxfTsiLaQ2E36XAOdcZmGAaEEgVmxQWwZXWkGhvoHbaqXcKnU8zny4ycpu3vNqg0L/PcCiYtHtA13g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.22.15", "@babel/helper-plugin-utils": "^7.24.0" @@ -2678,9 +2504,8 @@ }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.1.tgz", - "integrity": "sha512-fqj4WuzzS+ukpgerpAoOnMfQXwUHFxXUZUE84oL2Kao2N8uSlvcpnAidKASgsNgzZHBsHWvcm8s9FPWUhAb8fA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.22.15", "@babel/helper-plugin-utils": "^7.24.0" @@ -2694,9 +2519,8 @@ }, "node_modules/@babel/preset-env": { "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.9.tgz", - "integrity": "sha512-wNi5H/Emkhll/bqPjsjQorSykrlfY5OWakd6AulLvMEytpKasMVUpVy8RL4qBIBs5Ac6/5i0/Rv0b/Fg6Eag/g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/compat-data": "^7.22.9", "@babel/helper-compilation-targets": "^7.22.9", @@ -2788,18 +2612,16 @@ }, "node_modules/@babel/preset-env/node_modules/semver": { "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" } }, "node_modules/@babel/preset-modules": { "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6.tgz", - "integrity": "sha512-ID2yj6K/4lKfhuU3+EX4UvNbIt7eACFbHmNUjzA+ep+B5971CknnA/9DEWKbRokfbbtblxxxXFJJrH47UEAMVg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", @@ -2813,14 +2635,12 @@ }, "node_modules/@babel/regjsgen": { "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@babel/runtime": { "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz", - "integrity": "sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==", + "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -2830,9 +2650,8 @@ }, "node_modules/@babel/template": { "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", - "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.23.5", "@babel/parser": "^7.24.0", @@ -2844,9 +2663,8 @@ }, "node_modules/@babel/traverse": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", - "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.24.1", "@babel/generator": "^7.24.1", @@ -2865,9 +2683,8 @@ }, "node_modules/@babel/traverse/node_modules/@babel/generator": { "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz", - "integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.24.0", "@jridgewell/gen-mapping": "^0.3.5", @@ -2880,9 +2697,8 @@ }, "node_modules/@babel/types": { "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", - "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.23.4", "@babel/helper-validator-identifier": "^7.22.20", @@ -2894,18 +2710,16 @@ }, "node_modules/@colors/colors": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.1.90" } }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -2915,9 +2729,8 @@ }, "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -2925,18 +2738,16 @@ }, "node_modules/@discoveryjs/json-ext": { "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", - "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" } }, "node_modules/@es-joy/jsdoccomment": { "version": "0.42.0", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.42.0.tgz", - "integrity": "sha512-R1w57YlVA6+YE01wch3GPYn6bCsrOV3YW/5oGGE2tmX6JcL9Nr+b5IikrjMPF+v9CV3ay+obImEdsDhovhJrzw==", "dev": true, + "license": "MIT", "dependencies": { "comment-parser": "1.4.1", "esquery": "^1.5.0", @@ -2946,254 +2757,13 @@ "node": ">=16" } }, - "node_modules/@esbuild/android-arm": { - "version": "0.18.17", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.17.tgz", - "integrity": "sha512-wHsmJG/dnL3OkpAcwbgoBTTMHVi4Uyou3F5mf58ZtmUyIKfcdA7TROav/6tCzET4A3QW2Q2FC+eFneMU+iyOxg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.18.17", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.17.tgz", - "integrity": "sha512-9np+YYdNDed5+Jgr1TdWBsozZ85U1Oa3xW0c7TWqH0y2aGghXtZsuT8nYRbzOMcl0bXZXjOGbksoTtVOlWrRZg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.18.17", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.17.tgz", - "integrity": "sha512-O+FeWB/+xya0aLg23hHEM2E3hbfwZzjqumKMSIqcHbNvDa+dza2D0yLuymRBQQnC34CWrsJUXyH2MG5VnLd6uw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.18.17", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.17.tgz", - "integrity": "sha512-M9uJ9VSB1oli2BE/dJs3zVr9kcCBBsE883prage1NWz6pBS++1oNn/7soPNS3+1DGj0FrkSvnED4Bmlu1VAE9g==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.18.17", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.17.tgz", - "integrity": "sha512-XDre+J5YeIJDMfp3n0279DFNrGCXlxOuGsWIkRb1NThMZ0BsrWXoTg23Jer7fEXQ9Ye5QjrvXpxnhzl3bHtk0g==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.18.17", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.17.tgz", - "integrity": "sha512-cjTzGa3QlNfERa0+ptykyxs5A6FEUQQF0MuilYXYBGdBxD3vxJcKnzDlhDCa1VAJCmAxed6mYhA2KaJIbtiNuQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.18.17", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.17.tgz", - "integrity": "sha512-sOxEvR8d7V7Kw8QqzxWc7bFfnWnGdaFBut1dRUYtu+EIRXefBc/eIsiUiShnW0hM3FmQ5Zf27suDuHsKgZ5QrA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.18.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.17.tgz", - "integrity": "sha512-2d3Lw6wkwgSLC2fIvXKoMNGVaeY8qdN0IC3rfuVxJp89CRfA3e3VqWifGDfuakPmp90+ZirmTfye1n4ncjv2lg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.18.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.17.tgz", - "integrity": "sha512-c9w3tE7qA3CYWjT+M3BMbwMt+0JYOp3vCMKgVBrCl1nwjAlOMYzEo+gG7QaZ9AtqZFj5MbUc885wuBBmu6aADQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.18.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.17.tgz", - "integrity": "sha512-1DS9F966pn5pPnqXYz16dQqWIB0dmDfAQZd6jSSpiT9eX1NzKh07J6VKR3AoXXXEk6CqZMojiVDSZi1SlmKVdg==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.18.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.17.tgz", - "integrity": "sha512-EvLsxCk6ZF0fpCB6w6eOI2Fc8KW5N6sHlIovNe8uOFObL2O+Mr0bflPHyHwLT6rwMg9r77WOAWb2FqCQrVnwFg==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.18.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.17.tgz", - "integrity": "sha512-e0bIdHA5p6l+lwqTE36NAW5hHtw2tNRmHlGBygZC14QObsA3bD4C6sXLJjvnDIjSKhW1/0S3eDy+QmX/uZWEYQ==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.18.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.17.tgz", - "integrity": "sha512-BAAilJ0M5O2uMxHYGjFKn4nJKF6fNCdP1E0o5t5fvMYYzeIqy2JdAP88Az5LHt9qBoUa4tDaRpfWt21ep5/WqQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.18.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.17.tgz", - "integrity": "sha512-Wh/HW2MPnC3b8BqRSIme/9Zhab36PPH+3zam5pqGRH4pE+4xTrVLx2+XdGp6fVS3L2x+DrsIcsbMleex8fbE6g==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.18.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.17.tgz", - "integrity": "sha512-j/34jAl3ul3PNcK3pfI0NSlBANduT2UO5kZ7FCaK33XFv3chDhICLY8wJJWIhiQ+YNdQ9dxqQctRg2bvrMlYgg==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@esbuild/linux-x64": { "version": "0.18.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.17.tgz", - "integrity": "sha512-QM50vJ/y+8I60qEmFxMoxIx4de03pGo2HwxdBeFd4nMh364X6TIBZ6VQ5UQmPbQWUVWHWws5MmJXlHAXvJEmpQ==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -3202,107 +2772,10 @@ "node": ">=12" } }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.18.17", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.17.tgz", - "integrity": "sha512-/jGlhWR7Sj9JPZHzXyyMZ1RFMkNPjC6QIAan0sDOtIo2TYk3tZn5UDrkE0XgsTQCxWTTOcMPf9p6Rh2hXtl5TQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.18.17", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.17.tgz", - "integrity": "sha512-rSEeYaGgyGGf4qZM2NonMhMOP/5EHp4u9ehFiBrg7stH6BYEEjlkVREuDEcQ0LfIl53OXLxNbfuIj7mr5m29TA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.18.17", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.17.tgz", - "integrity": "sha512-Y7ZBbkLqlSgn4+zot4KUNYst0bFoO68tRgI6mY2FIM+b7ZbyNVtNbDP5y8qlu4/knZZ73fgJDlXID+ohY5zt5g==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.18.17", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.17.tgz", - "integrity": "sha512-bwPmTJsEQcbZk26oYpc4c/8PvTY3J5/QK8jM19DVlEsAB41M39aWovWoHtNm78sd6ip6prilxeHosPADXtEJFw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.18.17", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.17.tgz", - "integrity": "sha512-H/XaPtPKli2MhW+3CQueo6Ni3Avggi6hP/YvgkEe1aSaxw+AeO8MFjq8DlgfTd9Iz4Yih3QCZI6YLMoyccnPRg==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.18.17", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.17.tgz", - "integrity": "sha512-fGEb8f2BSA3CW7riJVurug65ACLuQAzKq0SSqkY2b2yHHH0MzDfbLyKIGzHwOI/gkHcxM/leuSW6D5w/LMNitA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", "dev": true, + "license": "MIT", "dependencies": { "eslint-visitor-keys": "^3.3.0" }, @@ -3315,18 +2788,16 @@ }, "node_modules/@eslint-community/regexpp": { "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", "dev": true, + "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -3347,9 +2818,8 @@ }, "node_modules/@eslint/eslintrc/node_modules/ajv": { "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -3363,15 +2833,13 @@ }, "node_modules/@eslint/eslintrc/node_modules/argparse": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "dev": true, + "license": "Python-2.0" }, "node_modules/@eslint/eslintrc/node_modules/globals": { "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^0.20.2" }, @@ -3384,9 +2852,8 @@ }, "node_modules/@eslint/eslintrc/node_modules/js-yaml": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -3396,15 +2863,13 @@ }, "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@eslint/eslintrc/node_modules/type-fest": { "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -3414,24 +2879,21 @@ }, "node_modules/@eslint/js": { "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", "dev": true, + "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@gar/promisify": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", - "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@humanwhocodes/object-schema": "^2.0.2", "debug": "^4.3.1", @@ -3443,9 +2905,8 @@ }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=12.22" }, @@ -3456,14 +2917,12 @@ }, "node_modules/@humanwhocodes/object-schema": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", - "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/@ionic/angular": { "version": "6.7.5", - "resolved": "https://registry.npmjs.org/@ionic/angular/-/angular-6.7.5.tgz", - "integrity": "sha512-nV8HP7RedjYkIAT8nVr5ifHNT0D3XzA74RPG3/WCCFJKunERNJ9SBiNkCTWhUpSkqsYYwEB4+SOOHz+R5NLk/w==", + "license": "MIT", "dependencies": { "@ionic/core": "6.7.5", "ionicons": "^6.1.3", @@ -3480,9 +2939,8 @@ }, "node_modules/@ionic/angular-toolkit": { "version": "11.0.1", - "resolved": "https://registry.npmjs.org/@ionic/angular-toolkit/-/angular-toolkit-11.0.1.tgz", - "integrity": "sha512-dxx2RDbxDYM2nWRPIirKMJySHtqJ1u02T25PGbNb99W2Wlcmu1cza3+2/PQ8ga18yMz/dQqaGyEmPDf3ZSVO0w==", "dev": true, + "license": "MIT", "dependencies": { "@angular-devkit/core": "^17.0.0", "@angular-devkit/schematics": "^17.0.0", @@ -3491,9 +2949,8 @@ }, "node_modules/@ionic/angular-toolkit/node_modules/@angular-devkit/core": { "version": "17.3.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-17.3.3.tgz", - "integrity": "sha512-J22Sh3M7rj8Ar3iEs20ko5wgC3DE7vWfYZNdimt2IJiS4J7BEX8R3Awf+TRt+6AN3NFm3/xe1Sz4yvDh3FvNFg==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "8.12.0", "ajv-formats": "2.1.1", @@ -3518,9 +2975,8 @@ }, "node_modules/@ionic/angular-toolkit/node_modules/@angular-devkit/schematics": { "version": "17.3.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-17.3.3.tgz", - "integrity": "sha512-SABqTtj2im4PJhQjNaAsSypbNkpZFW8YozJ3P748tlh5a9XoHpgiqXv5JhRbyKElLDAyk5i9fe2++JmSudPG/Q==", "dev": true, + "license": "MIT", "dependencies": { "@angular-devkit/core": "17.3.3", "jsonc-parser": "3.2.1", @@ -3536,9 +2992,8 @@ }, "node_modules/@ionic/angular-toolkit/node_modules/@schematics/angular": { "version": "17.3.3", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-17.3.3.tgz", - "integrity": "sha512-kNlyjIKTBhfi8Jab3MCkxNRbbpErbzdu0lZNSL8Nidmqs6Tk23Dc1bZe4t/gPNOCkCvQlwYa6X88SjC/ntyVng==", "dev": true, + "license": "MIT", "dependencies": { "@angular-devkit/core": "17.3.3", "@angular-devkit/schematics": "17.3.3", @@ -3552,9 +3007,8 @@ }, "node_modules/@ionic/angular-toolkit/node_modules/magic-string": { "version": "0.30.8", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", - "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" }, @@ -3564,9 +3018,8 @@ }, "node_modules/@ionic/angular-toolkit/node_modules/picomatch": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.1.tgz", - "integrity": "sha512-xUXwsxNjwTQ8K3GnT4pCJm+xq3RUPQbmkYJTP5aFIfNIvbcc/4MUxgBaaRSZJ6yGJZiGSyYlM6MzwTsRk8SYCg==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -3576,17 +3029,15 @@ }, "node_modules/@ionic/angular-toolkit/node_modules/rxjs": { "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@ionic/core": { "version": "6.7.5", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-6.7.5.tgz", - "integrity": "sha512-zRkRn+h/Vs3xt/EVgBdShMKDyeGOM4RU31NPF2icfu3CUTH+VrMV569MUnNjYvd1Lu2xK90pYy4TaicSWmC1Pw==", + "license": "MIT", "dependencies": { "@stencil/core": "^2.18.0", "ionicons": "^6.1.3", @@ -3595,9 +3046,8 @@ }, "node_modules/@isaacs/cliui": { "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -3612,9 +3062,8 @@ }, "node_modules/@isaacs/cliui/node_modules/ansi-regex": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -3624,9 +3073,8 @@ }, "node_modules/@isaacs/cliui/node_modules/ansi-styles": { "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -3636,15 +3084,13 @@ }, "node_modules/@isaacs/cliui/node_modules/emoji-regex": { "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, + "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -3659,9 +3105,8 @@ }, "node_modules/@isaacs/cliui/node_modules/strip-ansi": { "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -3674,9 +3119,8 @@ }, "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -3691,9 +3135,8 @@ }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, + "license": "ISC", "dependencies": { "camelcase": "^5.3.1", "find-up": "^4.1.0", @@ -3707,18 +3150,16 @@ }, "node_modules/@istanbuljs/schema": { "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -3730,27 +3171,24 @@ }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/set-array": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/source-map": { "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", - "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.0", "@jridgewell/trace-mapping": "^0.3.9" @@ -3758,15 +3196,13 @@ }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -3774,20 +3210,17 @@ }, "node_modules/@kurkle/color": { "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz", - "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==" + "license": "MIT" }, "node_modules/@leichtgewicht/ip-codec": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", - "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@ngtools/webpack": { "version": "16.2.13", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-16.2.13.tgz", - "integrity": "sha512-P5OiVp9MeMwVxihtC9NB4mx1Zlbup2DLMAWYAl8/kcFdRrRW+1YDQn93tlFToQDHGpPxkqW7cnFUPnA+QwQMYA==", "dev": true, + "license": "MIT", "engines": { "node": "^16.14.0 || >=18.10.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", @@ -3801,8 +3234,7 @@ }, "node_modules/@ngx-formly/core": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@ngx-formly/core/-/core-6.3.0.tgz", - "integrity": "sha512-9qCoPdLLVShoruzXeJUjMdIhfIlHCI+TggA3Wc01ISHTK2vXx1gNIFLuS+hez3JEzu8nIDRuA/nWqj4j8fJCNg==", + "license": "MIT", "dependencies": { "tslib": "^2.0.0" }, @@ -3813,8 +3245,7 @@ }, "node_modules/@ngx-formly/ionic": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@ngx-formly/ionic/-/ionic-6.3.0.tgz", - "integrity": "sha512-oiJB0iwmTVro7zDev3NS5lMvpgMINzCqr4Xm2h17882r4qrkGVIyN3IMQErNZY4iPYaKu0M3RiAvgEkDgVGigw==", + "license": "MIT", "dependencies": { "tslib": "^2.0.0" }, @@ -3825,8 +3256,7 @@ }, "node_modules/@ngx-formly/schematics": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@ngx-formly/schematics/-/schematics-6.3.0.tgz", - "integrity": "sha512-XSzOvrZ1NoUhmd733bcgUFkl+26pSw8eyXChi9LwrS26nEPweR8RA/JxN+lFvIb92MWzLShLd1DY2oBz/0r0ZQ==", + "license": "MIT", "dependencies": { "@angular-devkit/core": "^13.0.3", "@angular-devkit/schematics": "^13.0.3", @@ -3835,8 +3265,7 @@ }, "node_modules/@ngx-formly/schematics/node_modules/@angular-devkit/core": { "version": "13.3.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-13.3.11.tgz", - "integrity": "sha512-rfqoLMRYhlz0wzKlHx7FfyIyQq8dKTsmbCoIVU1cEIH0gyTMVY7PbVzwRRcO6xp5waY+0hA+0Brriujpuhkm4w==", + "license": "MIT", "dependencies": { "ajv": "8.9.0", "ajv-formats": "2.1.1", @@ -3861,8 +3290,7 @@ }, "node_modules/@ngx-formly/schematics/node_modules/@angular-devkit/schematics": { "version": "13.3.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-13.3.11.tgz", - "integrity": "sha512-ben+EGXpCrClnIVAAnEQmhQdKmnnqFhMp5BqMxgOslSYBAmCutLA6rBu5vsc8kZcGian1wt+lueF7G1Uk5cGBg==", + "license": "MIT", "dependencies": { "@angular-devkit/core": "13.3.11", "jsonc-parser": "3.0.0", @@ -3878,8 +3306,7 @@ }, "node_modules/@ngx-formly/schematics/node_modules/@schematics/angular": { "version": "13.3.11", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-13.3.11.tgz", - "integrity": "sha512-imKBnKYEse0SBVELZO/753nkpt3eEgpjrYkB+AFWF9YfO/4RGnYXDHoH8CFkzxPH9QQCgNrmsVFNiYGS+P/S1A==", + "license": "MIT", "dependencies": { "@angular-devkit/core": "13.3.11", "@angular-devkit/schematics": "13.3.11", @@ -3893,8 +3320,7 @@ }, "node_modules/@ngx-formly/schematics/node_modules/ajv": { "version": "8.9.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.9.0.tgz", - "integrity": "sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ==", + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -3908,29 +3334,25 @@ }, "node_modules/@ngx-formly/schematics/node_modules/jsonc-parser": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", - "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==" + "license": "MIT" }, "node_modules/@ngx-formly/schematics/node_modules/magic-string": { "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "license": "MIT", "dependencies": { "sourcemap-codec": "^1.4.4" } }, "node_modules/@ngx-formly/schematics/node_modules/source-map": { "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "license": "BSD-3-Clause", "engines": { "node": ">= 8" } }, "node_modules/@ngx-translate/core": { "version": "14.0.0", - "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-14.0.0.tgz", - "integrity": "sha512-UevdwNCXMRCdJv//0kC8h2eSfmi02r29xeE8E9gJ1Al4D4jEJ7eiLPdjslTMc21oJNGguqqWeEVjf64SFtvw2w==", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, @@ -3941,9 +3363,8 @@ }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -3954,18 +3375,16 @@ }, "node_modules/@nodelib/fs.stat": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/@nodelib/fs.walk": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -3976,17 +3395,15 @@ }, "node_modules/@nodro7/angular-mydatepicker": { "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@nodro7/angular-mydatepicker/-/angular-mydatepicker-0.14.0.tgz", - "integrity": "sha512-NLUqU2Hpy3OQn/2xp5FDIqBlb87o9LCYRShnA9tfbQIPQIKay4sSexK6XPswZ3ccXkvrgRMhFDZpv10JURqahA==", + "license": "MIT", "dependencies": { "tslib": "^2.0.0" } }, "node_modules/@npmcli/fs": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", - "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", "dev": true, + "license": "ISC", "dependencies": { "semver": "^7.3.5" }, @@ -3996,9 +3413,8 @@ }, "node_modules/@npmcli/git": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-4.1.0.tgz", - "integrity": "sha512-9hwoB3gStVfa0N31ymBmrX+GuDGdVA/QWShZVqE0HK2Af+7QGGrCTbZia/SW0ImUTjTne7SP91qxDmtXvDHRPQ==", "dev": true, + "license": "ISC", "dependencies": { "@npmcli/promise-spawn": "^6.0.0", "lru-cache": "^7.4.4", @@ -4015,18 +3431,16 @@ }, "node_modules/@npmcli/git/node_modules/lru-cache": { "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "dev": true, + "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/@npmcli/git/node_modules/which": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", - "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -4039,9 +3453,8 @@ }, "node_modules/@npmcli/installed-package-contents": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz", - "integrity": "sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==", "dev": true, + "license": "ISC", "dependencies": { "npm-bundled": "^3.0.0", "npm-normalize-package-bin": "^3.0.0" @@ -4055,10 +3468,8 @@ }, "node_modules/@npmcli/move-file": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", - "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", - "deprecated": "This functionality has been moved to @npmcli/fs", "dev": true, + "license": "MIT", "dependencies": { "mkdirp": "^1.0.4", "rimraf": "^3.0.2" @@ -4069,18 +3480,16 @@ }, "node_modules/@npmcli/node-gyp": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", - "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", "dev": true, + "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/@npmcli/promise-spawn": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-6.0.2.tgz", - "integrity": "sha512-gGq0NJkIGSwdbUt4yhdF8ZrmkGKVz9vAdVzpOfnom+V8PLSmSOVhZwbNvZZS1EYcJN5hzzKBxmmVVAInM6HQLg==", "dev": true, + "license": "ISC", "dependencies": { "which": "^3.0.0" }, @@ -4090,9 +3499,8 @@ }, "node_modules/@npmcli/promise-spawn/node_modules/which": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", - "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -4105,9 +3513,8 @@ }, "node_modules/@npmcli/run-script": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-6.0.2.tgz", - "integrity": "sha512-NCcr1uQo1k5U+SYlnIrbAh3cxy+OQT1VtqiAbxdymSlptbzBb62AjH2xXgjNCoP073hoa1CfCAcwoZ8k96C4nA==", "dev": true, + "license": "ISC", "dependencies": { "@npmcli/node-gyp": "^3.0.0", "@npmcli/promise-spawn": "^6.0.0", @@ -4121,9 +3528,8 @@ }, "node_modules/@npmcli/run-script/node_modules/which": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", - "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -4136,18 +3542,16 @@ }, "node_modules/@nrwl/devkit": { "version": "16.5.1", - "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-16.5.1.tgz", - "integrity": "sha512-NB+DE/+AFJ7lKH/WBFyatJEhcZGj25F24ncDkwjZ6MzEiSOGOJS0LaV/R+VUsmS5EHTPXYOpn3zHWWAcJhyOmA==", "dev": true, + "license": "MIT", "dependencies": { "@nx/devkit": "16.5.1" } }, "node_modules/@nrwl/tao": { "version": "16.5.1", - "resolved": "https://registry.npmjs.org/@nrwl/tao/-/tao-16.5.1.tgz", - "integrity": "sha512-x+gi/fKdM6uQNIti9exFlm3V5LBP3Y8vOEziO42HdOigyrXa0S0HD2WMpccmp6PclYKhwEDUjKJ39xh5sdh4Ig==", "dev": true, + "license": "MIT", "dependencies": { "nx": "16.5.1" }, @@ -4157,9 +3561,8 @@ }, "node_modules/@nx/devkit": { "version": "16.5.1", - "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-16.5.1.tgz", - "integrity": "sha512-T1acZrVVmJw/sJ4PIGidCBYBiBqlg/jT9e8nIGXLSDS20xcLvfo4zBQf8UZLrmHglnwwpDpOWuVJCp2rYA5aDg==", "dev": true, + "license": "MIT", "dependencies": { "@nrwl/devkit": "16.5.1", "ejs": "^3.1.7", @@ -4174,9 +3577,8 @@ }, "node_modules/@nx/devkit/node_modules/lru-cache": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -4186,9 +3588,8 @@ }, "node_modules/@nx/devkit/node_modules/semver": { "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", "dev": true, + "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -4199,176 +3600,44 @@ "node": ">=10" } }, - "node_modules/@nx/devkit/node_modules/tmp": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", - "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", - "dev": true, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/@nx/devkit/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/@nx/nx-darwin-arm64": { - "version": "16.5.1", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-16.5.1.tgz", - "integrity": "sha512-q98TFI4B/9N9PmKUr1jcbtD4yAFs1HfYd9jUXXTQOlfO9SbDjnrYJgZ4Fp9rMNfrBhgIQ4x1qx0AukZccKmH9Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nx/nx-darwin-x64": { - "version": "16.5.1", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-16.5.1.tgz", - "integrity": "sha512-j9HmL1l8k7EVJ3eOM5y8COF93gqrydpxCDoz23ZEtsY+JHY77VAiRQsmqBgEx9GGA2dXi9VEdS67B0+1vKariw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nx/nx-freebsd-x64": { - "version": "16.5.1", - "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-16.5.1.tgz", - "integrity": "sha512-CXSPT01aVS869tvCCF2tZ7LnCa8l41wJ3mTVtWBkjmRde68E5Up093hklRMyXb3kfiDYlfIKWGwrV4r0eH6x1A==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nx/nx-linux-arm-gnueabihf": { - "version": "16.5.1", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-16.5.1.tgz", - "integrity": "sha512-BhrumqJSZCWFfLFUKl4CAUwR0Y0G2H5EfFVGKivVecEQbb+INAek1aa6c89evg2/OvetQYsJ+51QknskwqvLsA==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nx/nx-linux-arm64-gnu": { - "version": "16.5.1", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-16.5.1.tgz", - "integrity": "sha512-x7MsSG0W+X43WVv7JhiSq2eKvH2suNKdlUHEG09Yt0vm3z0bhtym1UCMUg3IUAK7jy9hhLeDaFVFkC6zo+H/XQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nx/nx-linux-arm64-musl": { - "version": "16.5.1", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-16.5.1.tgz", - "integrity": "sha512-J+/v/mFjOm74I0PNtH5Ka+fDd+/dWbKhpcZ2R1/6b9agzZk+Ff/SrwJcSYFXXWKbPX+uQ4RcJoytT06Zs3s0ow==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nx/nx-linux-x64-gnu": { - "version": "16.5.1", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-16.5.1.tgz", - "integrity": "sha512-igooWJ5YxQ94Zft7IqgL+Lw0qHaY15Btw4gfK756g/YTYLZEt4tTvR1y6RnK/wdpE3sa68bFTLVBNCGTyiTiDQ==", - "cpu": [ - "x64" - ], + "node_modules/@nx/devkit/node_modules/tmp": { + "version": "0.2.3", "dev": true, - "optional": true, - "os": [ - "linux" - ], + "license": "MIT", "engines": { - "node": ">= 10" + "node": ">=14.14" } }, - "node_modules/@nx/nx-linux-x64-musl": { - "version": "16.5.1", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-16.5.1.tgz", - "integrity": "sha512-zF/exnPqFYbrLAduGhTmZ7zNEyADid2bzNQiIjJkh8Y6NpDwrQIwVIyvIxqynsjMrIs51kBH+8TUjKjj2Jgf5A==", - "cpu": [ - "x64" - ], + "node_modules/@nx/devkit/node_modules/yallist": { + "version": "4.0.0", "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } + "license": "ISC" }, - "node_modules/@nx/nx-win32-arm64-msvc": { + "node_modules/@nx/nx-linux-x64-gnu": { "version": "16.5.1", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-16.5.1.tgz", - "integrity": "sha512-qtqiLS9Y9TYyAbbpq58kRoOroko4ZXg5oWVqIWFHoxc5bGPweQSJCROEqd1AOl2ZDC6BxfuVHfhDDop1kK05WA==", "cpu": [ - "arm64" + "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ - "win32" + "linux" ], "engines": { "node": ">= 10" } }, - "node_modules/@nx/nx-win32-x64-msvc": { + "node_modules/@nx/nx-linux-x64-musl": { "version": "16.5.1", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-16.5.1.tgz", - "integrity": "sha512-kUJBLakK7iyA9WfsGGQBVennA4jwf5XIgm0lu35oMOphtZIluvzItMt0EYBmylEROpmpEIhHq0P6J9FA+WH0Rg==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ - "win32" + "linux" ], "engines": { "node": ">= 10" @@ -4376,10 +3645,9 @@ }, "node_modules/@parcel/watcher": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.0.4.tgz", - "integrity": "sha512-cTDi+FUDBIUOBKEtj+nhiJ71AZVlkAsQFuGQTun5tV9mwQBQgZvhCzG+URPQc8myeN32yRVZEfVAPCs1RW+Jvg==", "dev": true, "hasInstallScript": true, + "license": "MIT", "dependencies": { "node-addon-api": "^3.2.1", "node-gyp-build": "^4.3.0" @@ -4394,9 +3662,8 @@ }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, + "license": "MIT", "optional": true, "engines": { "node": ">=14" @@ -4404,9 +3671,8 @@ }, "node_modules/@schematics/angular": { "version": "16.2.13", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-16.2.13.tgz", - "integrity": "sha512-SFE9e7X/CEtzwGEqHUqXriAm4J4uTjcfoRXslc7BuqOKABM8RXPphGQsVG4xOt3n25kXXGkFO2dvDRHuLTP1fQ==", "dev": true, + "license": "MIT", "dependencies": { "@angular-devkit/core": "16.2.13", "@angular-devkit/schematics": "16.2.13", @@ -4420,15 +3686,13 @@ }, "node_modules/@schematics/angular/node_modules/jsonc-parser": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@sigstore/bundle": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-1.1.0.tgz", - "integrity": "sha512-PFutXEy0SmQxYI4texPw3dd2KewuNqv7OuK1ZFtY2fM754yhvG2KdgwIhRnoEE2uHdtdGNQ8s0lb94dW9sELog==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@sigstore/protobuf-specs": "^0.2.0" }, @@ -4438,18 +3702,16 @@ }, "node_modules/@sigstore/protobuf-specs": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.2.1.tgz", - "integrity": "sha512-XTWVxnWJu+c1oCshMLwnKvz8ZQJJDVOlciMfgpJBQbThVjKTCG8dwyhgLngBD2KN0ap9F/gOV8rFDEx8uh7R2A==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/@sigstore/sign": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-1.0.0.tgz", - "integrity": "sha512-INxFVNQteLtcfGmcoldzV6Je0sbbfh9I16DM4yJPw3j5+TFP8X6uIiA18mvpEa9yyeycAKgPmOA3X9hVdVTPUA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@sigstore/bundle": "^1.1.0", "@sigstore/protobuf-specs": "^0.2.0", @@ -4461,18 +3723,16 @@ }, "node_modules/@sigstore/sign/node_modules/@tootallnate/once": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10" } }, "node_modules/@sigstore/sign/node_modules/http-proxy-agent": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", "dev": true, + "license": "MIT", "dependencies": { "@tootallnate/once": "2", "agent-base": "6", @@ -4484,18 +3744,16 @@ }, "node_modules/@sigstore/sign/node_modules/lru-cache": { "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "dev": true, + "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/@sigstore/sign/node_modules/make-fetch-happen": { "version": "11.1.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", - "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", "dev": true, + "license": "ISC", "dependencies": { "agentkeepalive": "^4.2.1", "cacache": "^17.0.0", @@ -4519,9 +3777,8 @@ }, "node_modules/@sigstore/sign/node_modules/minipass-fetch": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", - "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", "dev": true, + "license": "MIT", "dependencies": { "minipass": "^7.0.3", "minipass-sized": "^1.0.3", @@ -4536,18 +3793,16 @@ }, "node_modules/@sigstore/sign/node_modules/minipass-fetch/node_modules/minipass": { "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", "dev": true, + "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } }, "node_modules/@sigstore/tuf": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-1.0.3.tgz", - "integrity": "sha512-2bRovzs0nJZFlCN3rXirE4gwxCn97JNjMmwpecqlbgV9WcxX7WRuIrgzx/X7Ib7MYRbyUTpBYE0s2x6AmZXnlg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@sigstore/protobuf-specs": "^0.2.0", "tuf-js": "^1.1.7" @@ -4558,14 +3813,12 @@ }, "node_modules/@socket.io/component-emitter": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", - "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@stencil/core": { "version": "2.22.3", - "resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.22.3.tgz", - "integrity": "sha512-kmVA0M/HojwsfkeHsifvHVIYe4l5tin7J5+DLgtl8h6WWfiMClND5K3ifCXXI2ETDNKiEk21p6jql3Fx9o2rng==", + "license": "MIT", "bin": { "stencil": "bin/stencil" }, @@ -4576,51 +3829,44 @@ }, "node_modules/@tootallnate/once": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } }, "node_modules/@tsconfig/node10": { "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@tufjs/canonical-json": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-1.0.0.tgz", - "integrity": "sha512-QTnf++uxunWvG2z3UFNzAoQPHxnSXOwtaI3iJ+AohhV+5vONuArPjJE7aPXPVXfXJsqrVbZBu9b81AJoSd09IQ==", "dev": true, + "license": "MIT", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/@tufjs/models": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-1.0.4.tgz", - "integrity": "sha512-qaGV9ltJP0EO25YfFUPhxRVK0evXFIAGicsVXuRim4Ed9cjPxYhNnNJ49SFmbeLgtxpslIkX317IgpfcHPVj/A==", "dev": true, + "license": "MIT", "dependencies": { "@tufjs/canonical-json": "1.0.0", "minimatch": "^9.0.0" @@ -4631,18 +3877,16 @@ }, "node_modules/@tufjs/models/node_modules/brace-expansion": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/@tufjs/models/node_modules/minimatch": { "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -4655,9 +3899,8 @@ }, "node_modules/@types/body-parser": { "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", - "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", "dev": true, + "license": "MIT", "dependencies": { "@types/connect": "*", "@types/node": "*" @@ -4665,27 +3908,24 @@ }, "node_modules/@types/bonjour": { "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", - "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/connect": { "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/connect-history-api-fallback": { "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", - "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", "dev": true, + "license": "MIT", "dependencies": { "@types/express-serve-static-core": "*", "@types/node": "*" @@ -4693,24 +3933,21 @@ }, "node_modules/@types/cookie": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/cors": { "version": "2.8.17", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", - "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/eslint": { "version": "8.56.2", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.2.tgz", - "integrity": "sha512-uQDwm1wFHmbBbCZCqAlq6Do9LYwByNZHWzXppSnay9SuwJ+VRbjkbLABer54kcPnMSlG6Fdiy2yaFXm/z9Z5gw==", "dev": true, + "license": "MIT", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -4718,9 +3955,8 @@ }, "node_modules/@types/eslint-scope": { "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", "dev": true, + "license": "MIT", "dependencies": { "@types/eslint": "*", "@types/estree": "*" @@ -4728,15 +3964,13 @@ }, "node_modules/@types/estree": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/express": { "version": "4.17.21", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", - "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", @@ -4746,9 +3980,8 @@ }, "node_modules/@types/express-serve-static-core": { "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz", - "integrity": "sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -4758,111 +3991,95 @@ }, "node_modules/@types/http-errors": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", - "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/http-proxy": { "version": "1.17.14", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", - "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/jasmine": { "version": "4.3.6", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-4.3.6.tgz", - "integrity": "sha512-3N0FpQTeiWjm+Oo1WUYWguUS7E6JLceiGTriFrG8k5PU7zRLJCzLcWURU3wjMbZGS//a2/LgjsnO3QxIlwxt9g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/jasminewd2": { "version": "2.0.13", - "resolved": "https://registry.npmjs.org/@types/jasminewd2/-/jasminewd2-2.0.13.tgz", - "integrity": "sha512-aJ3wj8tXMpBrzQ5ghIaqMisD8C3FIrcO6sDKHqFbuqAsI7yOxj0fA7MrRCPLZHIVUjERIwsMmGn/vB0UQ9u0Hg==", "dev": true, + "license": "MIT", "dependencies": { "@types/jasmine": "*" } }, "node_modules/@types/json-schema": { "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/json5": { "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/mime": { "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/node": { "version": "20.12.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", - "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", "dev": true, + "license": "MIT", "dependencies": { "undici-types": "~5.26.4" } }, "node_modules/@types/node-forge": { "version": "1.3.11", - "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", - "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/q": { "version": "0.0.32", - "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", - "integrity": "sha512-qYi3YV9inU/REEfxwVcGZzbS3KG/Xs90lv0Pr+lDtuVjBPGd1A+eciXzVSaRvLify132BfcvhvEjeVahrUl0Ug==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/qs": { "version": "6.9.14", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.14.tgz", - "integrity": "sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/range-parser": { "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/retry": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/selenium-webdriver": { "version": "3.0.26", - "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.26.tgz", - "integrity": "sha512-dyIGFKXfUFiwkMfNGn1+F6b80ZjR3uSYv1j6xVJSDlft5waZ2cwkHW4e7zNzvq7hiEackcgvBpmnXZrI1GltPg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/semver": { "version": "7.5.8", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/send": { "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", - "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", "dev": true, + "license": "MIT", "dependencies": { "@types/mime": "^1", "@types/node": "*" @@ -4870,18 +4087,16 @@ }, "node_modules/@types/serve-index": { "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", - "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", "dev": true, + "license": "MIT", "dependencies": { "@types/express": "*" } }, "node_modules/@types/serve-static": { "version": "1.15.7", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", - "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", "dev": true, + "license": "MIT", "dependencies": { "@types/http-errors": "*", "@types/node": "*", @@ -4890,33 +4105,29 @@ }, "node_modules/@types/sockjs": { "version": "0.3.36", - "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", - "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/uuid": { "version": "9.0.8", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", - "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/ws": { "version": "8.5.10", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", - "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", - "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.5.1", "@typescript-eslint/scope-manager": "6.21.0", @@ -4949,9 +4160,8 @@ }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", - "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/typescript-estree": "6.21.0", "@typescript-eslint/utils": "6.21.0", @@ -4976,9 +4186,8 @@ }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", - "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", @@ -5001,9 +4210,8 @@ }, "node_modules/@typescript-eslint/parser": { "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", - "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/scope-manager": "6.21.0", "@typescript-eslint/types": "6.21.0", @@ -5029,9 +4237,8 @@ }, "node_modules/@typescript-eslint/scope-manager": { "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", - "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/types": "6.21.0", "@typescript-eslint/visitor-keys": "6.21.0" @@ -5046,9 +4253,8 @@ }, "node_modules/@typescript-eslint/type-utils": { "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", - "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/typescript-estree": "5.62.0", "@typescript-eslint/utils": "5.62.0", @@ -5073,9 +4279,8 @@ }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", - "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", "dev": true, + "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -5086,9 +4291,8 @@ }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", - "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/types": "5.62.0", "@typescript-eslint/visitor-keys": "5.62.0", @@ -5113,9 +4317,8 @@ }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", - "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/types": "5.62.0", "eslint-visitor-keys": "^3.3.0" @@ -5130,9 +4333,8 @@ }, "node_modules/@typescript-eslint/type-utils/node_modules/globby": { "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, + "license": "MIT", "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -5150,18 +4352,16 @@ }, "node_modules/@typescript-eslint/type-utils/node_modules/slash": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@typescript-eslint/types": { "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", - "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", "dev": true, + "license": "MIT", "engines": { "node": "^16.0.0 || >=18.0.0" }, @@ -5172,9 +4372,8 @@ }, "node_modules/@typescript-eslint/typescript-estree": { "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", - "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/types": "6.21.0", "@typescript-eslint/visitor-keys": "6.21.0", @@ -5200,18 +4399,16 @@ }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/globby": { "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, + "license": "MIT", "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -5229,9 +4426,8 @@ }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -5244,18 +4440,16 @@ }, "node_modules/@typescript-eslint/typescript-estree/node_modules/slash": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@typescript-eslint/utils": { "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", - "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@types/json-schema": "^7.0.9", @@ -5279,9 +4473,8 @@ }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", - "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/types": "5.62.0", "@typescript-eslint/visitor-keys": "5.62.0" @@ -5296,9 +4489,8 @@ }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", - "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", "dev": true, + "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -5309,9 +4501,8 @@ }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", - "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/types": "5.62.0", "@typescript-eslint/visitor-keys": "5.62.0", @@ -5336,9 +4527,8 @@ }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", - "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/types": "5.62.0", "eslint-visitor-keys": "^3.3.0" @@ -5353,9 +4543,8 @@ }, "node_modules/@typescript-eslint/utils/node_modules/globby": { "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, + "license": "MIT", "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -5373,18 +4562,16 @@ }, "node_modules/@typescript-eslint/utils/node_modules/slash": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@typescript-eslint/visitor-keys": { "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", - "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/types": "6.21.0", "eslint-visitor-keys": "^3.4.1" @@ -5399,15 +4586,13 @@ }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/@vitejs/plugin-basic-ssl": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.0.1.tgz", - "integrity": "sha512-pcub+YbFtFhaGRTo1832FQHQSHvMrlb43974e2eS8EKleR3p1cDdkJFPci1UhwkEf1J9Bz+wKBSzqpKp7nNj2A==", "dev": true, + "license": "MIT", "engines": { "node": ">=14.6.0" }, @@ -5417,9 +4602,8 @@ }, "node_modules/@webassemblyjs/ast": { "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", - "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/helper-numbers": "1.11.6", "@webassemblyjs/helper-wasm-bytecode": "1.11.6" @@ -5427,27 +4611,23 @@ }, "node_modules/@webassemblyjs/floating-point-hex-parser": { "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", - "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-api-error": { "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", - "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-buffer": { "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", - "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-numbers": { "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", - "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.11.6", "@webassemblyjs/helper-api-error": "1.11.6", @@ -5456,15 +4636,13 @@ }, "node_modules/@webassemblyjs/helper-wasm-bytecode": { "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", - "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-wasm-section": { "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", - "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-buffer": "1.12.1", @@ -5474,33 +4652,29 @@ }, "node_modules/@webassemblyjs/ieee754": { "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", - "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", "dev": true, + "license": "MIT", "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, "node_modules/@webassemblyjs/leb128": { "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", - "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/utf8": { "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", - "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/wasm-edit": { "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", - "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-buffer": "1.12.1", @@ -5514,9 +4688,8 @@ }, "node_modules/@webassemblyjs/wasm-gen": { "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", - "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", @@ -5527,9 +4700,8 @@ }, "node_modules/@webassemblyjs/wasm-opt": { "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", - "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-buffer": "1.12.1", @@ -5539,9 +4711,8 @@ }, "node_modules/@webassemblyjs/wasm-parser": { "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", - "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-api-error": "1.11.6", @@ -5553,9 +4724,8 @@ }, "node_modules/@webassemblyjs/wast-printer": { "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", - "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.12.1", "@xtuc/long": "4.2.2" @@ -5563,10 +4733,8 @@ }, "node_modules/@wessberg/ts-evaluator": { "version": "0.0.27", - "resolved": "https://registry.npmjs.org/@wessberg/ts-evaluator/-/ts-evaluator-0.0.27.tgz", - "integrity": "sha512-7gOpVm3yYojUp/Yn7F4ZybJRxyqfMNf0LXK5KJiawbPfL0XTsJV+0mgrEDjOIR6Bi0OYk2Cyg4tjFu1r8MCZaA==", - "deprecated": "this package has been renamed to ts-evaluator. Please install ts-evaluator instead", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.1.0", "jsdom": "^16.4.0", @@ -5586,9 +4754,8 @@ }, "node_modules/@wessberg/ts-evaluator/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -5601,9 +4768,8 @@ }, "node_modules/@wessberg/ts-evaluator/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -5617,9 +4783,8 @@ }, "node_modules/@wessberg/ts-evaluator/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -5629,18 +4794,16 @@ }, "node_modules/@wessberg/ts-evaluator/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@wessberg/ts-evaluator/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -5650,27 +4813,23 @@ }, "node_modules/@xtuc/ieee754": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/@xtuc/long": { "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/@yarnpkg/lockfile": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", - "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", - "dev": true + "dev": true, + "license": "BSD-2-Clause" }, "node_modules/@yarnpkg/parsers": { "version": "3.0.0-rc.46", - "resolved": "https://registry.npmjs.org/@yarnpkg/parsers/-/parsers-3.0.0-rc.46.tgz", - "integrity": "sha512-aiATs7pSutzda/rq8fnuPwTglyVwjM22bNnK2ZgjrpAjQHSSl3lztd2f9evst1W/qnC58DRz7T7QndUDumAR4Q==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "js-yaml": "^3.10.0", "tslib": "^2.4.0" @@ -5681,9 +4840,8 @@ }, "node_modules/@zkochan/js-yaml": { "version": "0.0.6", - "resolved": "https://registry.npmjs.org/@zkochan/js-yaml/-/js-yaml-0.0.6.tgz", - "integrity": "sha512-nzvgl3VfhcELQ8LyVrYOru+UtAy1nrygk2+AGbTm8a5YcO6o8lSjAT+pfg3vJWxIoZKOUhrK6UU7xW/+00kQrg==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -5693,28 +4851,23 @@ }, "node_modules/@zkochan/js-yaml/node_modules/argparse": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "dev": true, + "license": "Python-2.0" }, "node_modules/abab": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", - "deprecated": "Use your platform's native atob() and btoa() methods instead", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/abbrev": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/accepts": { "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dev": true, + "license": "MIT", "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" @@ -5725,9 +4878,8 @@ }, "node_modules/acorn": { "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -5737,9 +4889,8 @@ }, "node_modules/acorn-globals": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", "dev": true, + "license": "MIT", "dependencies": { "acorn": "^7.1.1", "acorn-walk": "^7.1.1" @@ -5747,9 +4898,8 @@ }, "node_modules/acorn-globals/node_modules/acorn": { "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -5759,45 +4909,40 @@ }, "node_modules/acorn-globals/node_modules/acorn-walk": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.4.0" } }, "node_modules/acorn-import-assertions": { "version": "1.9.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", - "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^8" } }, "node_modules/acorn-jsx": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "node_modules/acorn-walk": { "version": "8.3.1", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.1.tgz", - "integrity": "sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.4.0" } }, "node_modules/adjust-sourcemap-loader": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", - "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", "dev": true, + "license": "MIT", "dependencies": { "loader-utils": "^2.0.0", "regex-parser": "^2.2.11" @@ -5808,9 +4953,8 @@ }, "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, + "license": "MIT", "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -5822,18 +4966,16 @@ }, "node_modules/adm-zip": { "version": "0.5.12", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.12.tgz", - "integrity": "sha512-6TVU49mK6KZb4qG6xWaaM4C7sA/sgUMLy/JYMOzkcp3BvVLpW0fXDFQiIzAuxFCt/2+xD7fNIiPFAoLZPhVNLQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0" } }, "node_modules/agent-base": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "dev": true, + "license": "MIT", "dependencies": { "debug": "4" }, @@ -5843,9 +4985,8 @@ }, "node_modules/agentkeepalive": { "version": "4.5.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", - "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", "dev": true, + "license": "MIT", "dependencies": { "humanize-ms": "^1.2.1" }, @@ -5855,9 +4996,8 @@ }, "node_modules/aggregate-error": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", "dev": true, + "license": "MIT", "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" @@ -5868,8 +5008,7 @@ }, "node_modules/ajv": { "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -5883,8 +5022,7 @@ }, "node_modules/ajv-formats": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "license": "MIT", "dependencies": { "ajv": "^8.0.0" }, @@ -5899,9 +5037,8 @@ }, "node_modules/ajv-keywords": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3" }, @@ -5911,18 +5048,16 @@ }, "node_modules/ansi-colors": { "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/ansi-escapes": { "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^0.21.3" }, @@ -5935,29 +5070,26 @@ }, "node_modules/ansi-html-community": { "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", - "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", "dev": true, "engines": [ "node >= 0.8.0" ], + "license": "Apache-2.0", "bin": { "ansi-html": "bin/ansi-html" } }, "node_modules/ansi-regex": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/ansi-styles": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^1.9.0" }, @@ -5967,9 +5099,8 @@ }, "node_modules/anymatch": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "devOptional": true, + "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -5980,24 +5111,21 @@ }, "node_modules/aproba": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/are-docs-informative": { "version": "0.0.2", - "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", - "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", "dev": true, + "license": "MIT", "engines": { "node": ">=14" } }, "node_modules/are-we-there-yet": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", - "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", "dev": true, + "license": "ISC", "dependencies": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" @@ -6008,33 +5136,29 @@ }, "node_modules/arg": { "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/argparse": { "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, + "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" } }, "node_modules/aria-query": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", - "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", "dev": true, + "license": "Apache-2.0", "dependencies": { "dequal": "^2.0.3" } }, "node_modules/array-buffer-byte-length": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", - "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.5", "is-array-buffer": "^3.0.4" @@ -6048,15 +5172,13 @@ }, "node_modules/array-flatten": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/array-includes": { "version": "3.1.7", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", - "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -6073,27 +5195,24 @@ }, "node_modules/array-union": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/array-uniq": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/array.prototype.findlastindex": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", - "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -6111,9 +5230,8 @@ }, "node_modules/array.prototype.flat": { "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", - "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -6129,9 +5247,8 @@ }, "node_modules/array.prototype.flatmap": { "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", - "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -6147,9 +5264,8 @@ }, "node_modules/arraybuffer.prototype.slice": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", - "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", "dev": true, + "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.1", "call-bind": "^1.0.5", @@ -6169,47 +5285,40 @@ }, "node_modules/arrify": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/asn1": { "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", "dev": true, + "license": "MIT", "dependencies": { "safer-buffer": "~2.1.0" } }, "node_modules/assert-plus": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8" } }, "node_modules/async": { "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/asynckit": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/autoprefixer": { "version": "10.4.14", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", - "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", "dev": true, "funding": [ { @@ -6221,6 +5330,7 @@ "url": "https://tidelift.com/funding/github/npm/autoprefixer" } ], + "license": "MIT", "dependencies": { "browserslist": "^4.21.5", "caniuse-lite": "^1.0.30001464", @@ -6241,9 +5351,8 @@ }, "node_modules/available-typed-arrays": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "dev": true, + "license": "MIT", "dependencies": { "possible-typed-array-names": "^1.0.0" }, @@ -6256,24 +5365,21 @@ }, "node_modules/aws-sign2": { "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "*" } }, "node_modules/aws4": { "version": "1.12.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", - "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/axios": { "version": "1.6.8", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", - "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", "dev": true, + "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -6282,9 +5388,8 @@ }, "node_modules/axios/node_modules/form-data": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", "dev": true, + "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -6296,18 +5401,16 @@ }, "node_modules/axobject-query": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.0.0.tgz", - "integrity": "sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "dequal": "^2.0.3" } }, "node_modules/babel-loader": { "version": "9.1.3", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", - "integrity": "sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==", "dev": true, + "license": "MIT", "dependencies": { "find-cache-dir": "^4.0.0", "schema-utils": "^4.0.0" @@ -6322,9 +5425,8 @@ }, "node_modules/babel-plugin-istanbul": { "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", @@ -6338,9 +5440,8 @@ }, "node_modules/babel-plugin-polyfill-corejs2": { "version": "0.4.10", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.10.tgz", - "integrity": "sha512-rpIuu//y5OX6jVU+a5BCn1R5RSZYWAl2Nar76iwaOdycqb6JPxediskWFMMl7stfwNJR4b7eiQvh5fB5TEQJTQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/compat-data": "^7.22.6", "@babel/helper-define-polyfill-provider": "^0.6.1", @@ -6352,18 +5453,16 @@ }, "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { "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" } }, "node_modules/babel-plugin-polyfill-corejs3": { "version": "0.8.7", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.7.tgz", - "integrity": "sha512-KyDvZYxAzkC0Aj2dAPyDzi2Ym15e5JKZSK+maI7NAwSqofvuFglbSsxE7wUOvTg9oFVnHMzVzBKcqEb4PJgtOA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-define-polyfill-provider": "^0.4.4", "core-js-compat": "^3.33.1" @@ -6374,9 +5473,8 @@ }, "node_modules/babel-plugin-polyfill-corejs3/node_modules/@babel/helper-define-polyfill-provider": { "version": "0.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.4.tgz", - "integrity": "sha512-QcJMILQCu2jm5TFPGA3lCpJJTeEP+mqeXooG/NZbg/h5FTFi6V0+99ahlRsW8/kRLyb24LZVCCiclDedhLKcBA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", @@ -6390,9 +5488,8 @@ }, "node_modules/babel-plugin-polyfill-regenerator": { "version": "0.5.5", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.5.tgz", - "integrity": "sha512-OJGYZlhLqBh2DDHeqAxWB1XIvr49CxiJ2gIt61/PU55CQK4Z58OzMqjDe1zwQdQk+rBYsRc+1rJmdajM3gimHg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-define-polyfill-provider": "^0.5.0" }, @@ -6402,9 +5499,8 @@ }, "node_modules/babel-plugin-polyfill-regenerator/node_modules/@babel/helper-define-polyfill-provider": { "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz", - "integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", @@ -6418,14 +5514,11 @@ }, "node_modules/balanced-match": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/base64-js": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "funding": [ { "type": "github", @@ -6439,54 +5532,49 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/base64id": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", - "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", "dev": true, + "license": "MIT", "engines": { "node": "^4.5.0 || >= 5.9" } }, "node_modules/batch": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/bcrypt-pbkdf": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "tweetnacl": "^0.14.3" } }, "node_modules/big.js": { "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", "dev": true, + "license": "MIT", "engines": { "node": "*" } }, "node_modules/binary-extensions": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "devOptional": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/bl": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "license": "MIT", "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -6495,9 +5583,8 @@ }, "node_modules/blocking-proxy": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-1.0.1.tgz", - "integrity": "sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA==", "dev": true, + "license": "MIT", "dependencies": { "minimist": "^1.2.0" }, @@ -6510,9 +5597,8 @@ }, "node_modules/body-parser": { "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "dev": true, + "license": "MIT", "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", @@ -6534,27 +5620,24 @@ }, "node_modules/body-parser/node_modules/bytes": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/body-parser/node_modules/debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/body-parser/node_modules/iconv-lite": { "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -6564,15 +5647,13 @@ }, "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/bonjour-service": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", - "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "multicast-dns": "^7.2.5" @@ -6580,15 +5661,13 @@ }, "node_modules/boolbase": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -6596,9 +5675,8 @@ }, "node_modules/braces": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "devOptional": true, + "license": "MIT", "dependencies": { "fill-range": "^7.0.1" }, @@ -6608,14 +5686,11 @@ }, "node_modules/browser-process-hrtime": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true + "dev": true, + "license": "BSD-2-Clause" }, "node_modules/browserslist": { "version": "4.23.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", - "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", "dev": true, "funding": [ { @@ -6631,6 +5706,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "caniuse-lite": "^1.0.30001587", "electron-to-chromium": "^1.4.668", @@ -6646,18 +5722,16 @@ }, "node_modules/browserstack": { "version": "1.6.1", - "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.6.1.tgz", - "integrity": "sha512-GxtFjpIaKdbAyzHfFDKixKO8IBT7wR3NjbzrGc78nNs/Ciys9wU3/nBtsqsWv5nDSrdI5tz0peKuzCPuNXNUiw==", "dev": true, + "license": "MIT", "dependencies": { "https-proxy-agent": "^2.2.1" } }, "node_modules/browserstack/node_modules/agent-base": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", "dev": true, + "license": "MIT", "dependencies": { "es6-promisify": "^5.0.0" }, @@ -6667,18 +5741,16 @@ }, "node_modules/browserstack/node_modules/debug": { "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.1" } }, "node_modules/browserstack/node_modules/https-proxy-agent": { "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", "dev": true, + "license": "MIT", "dependencies": { "agent-base": "^4.3.0", "debug": "^3.1.0" @@ -6689,8 +5761,6 @@ }, "node_modules/buffer": { "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "funding": [ { "type": "github", @@ -6705,6 +5775,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -6712,15 +5783,13 @@ }, "node_modules/buffer-from": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/builtin-modules": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", - "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" }, @@ -6730,27 +5799,24 @@ }, "node_modules/builtins": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", - "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", "dev": true, + "license": "MIT", "dependencies": { "semver": "^7.0.0" } }, "node_modules/bytes": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/cacache": { "version": "17.1.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.1.4.tgz", - "integrity": "sha512-/aJwG2l3ZMJ1xNAnqbMpA40of9dj/pIH3QfiuQSqjfPJF747VR0J/bHn+/KdNnHKc6XQcWt/AfRSBft82W1d2A==", "dev": true, + "license": "ISC", "dependencies": { "@npmcli/fs": "^3.1.0", "fs-minipass": "^3.0.0", @@ -6771,27 +5837,24 @@ }, "node_modules/cacache/node_modules/lru-cache": { "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "dev": true, + "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/cacache/node_modules/minipass": { "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", "dev": true, + "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } }, "node_modules/call-bind": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dev": true, + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -6808,26 +5871,22 @@ }, "node_modules/callsites": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/camelcase": { "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/caniuse-lite": { "version": "1.0.30001606", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001606.tgz", - "integrity": "sha512-LPbwnW4vfpJId225pwjZJOgX1m9sGfbw/RKJvw/t0QhYOOaTXHvkjVGFGPpvwEzufrjvTlsULnVTxdy4/6cqkg==", "dev": true, "funding": [ { @@ -6842,19 +5901,18 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/caseless": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/chalk": { "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -6866,14 +5924,12 @@ }, "node_modules/chardet": { "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/chart.js": { "version": "4.4.2", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.2.tgz", - "integrity": "sha512-6GD7iKwFpP5kbSD4MeRRRlTnQvxfQREy36uEtm1hzHzcOqwWx0YEHuspuoNlslu+nciLIB7fjjsHkUv/FzFcOg==", + "license": "MIT", "dependencies": { "@kurkle/color": "^0.3.0" }, @@ -6883,8 +5939,7 @@ }, "node_modules/chartjs-adapter-date-fns": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chartjs-adapter-date-fns/-/chartjs-adapter-date-fns-3.0.0.tgz", - "integrity": "sha512-Rs3iEB3Q5pJ973J93OBTpnP7qoGwvq3nUnoMdtxO+9aoJof7UFcRbWcIDteXuYd1fgAvct/32T9qaLyLuZVwCg==", + "license": "MIT", "peerDependencies": { "chart.js": ">=2.8.0", "date-fns": ">=2.0.0" @@ -6892,8 +5947,7 @@ }, "node_modules/chartjs-plugin-zoom": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/chartjs-plugin-zoom/-/chartjs-plugin-zoom-2.0.1.tgz", - "integrity": "sha512-ogOmLu6e+Q7E1XWOCOz9YwybMslz9qNfGV2a+qjfmqJYpsw5ZMoRHZBUyW+NGhkpQ5PwwPA/+rikHpBZb7PZuA==", + "license": "MIT", "dependencies": { "hammerjs": "^2.0.8" }, @@ -6903,8 +5957,6 @@ }, "node_modules/chokidar": { "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "devOptional": true, "funding": [ { @@ -6912,6 +5964,7 @@ "url": "https://paulmillr.com/funding/" } ], + "license": "MIT", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -6930,40 +5983,35 @@ }, "node_modules/chownr": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } }, "node_modules/chrome-trace-event": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0" } }, "node_modules/classlist.js": { "version": "1.1.20150312", - "resolved": "https://registry.npmjs.org/classlist.js/-/classlist.js-1.1.20150312.tgz", - "integrity": "sha512-eR8yB970+yGslcTnJnROX2icsMa8v/KVLv/sgv3NhSvZSHgam64XNSF2TyJnKIfsnTFJBcTdrIneYqUIrvxLpg==" + "license": "Dedicated to the public domain" }, "node_modules/clean-stack": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/cli-cursor": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "license": "MIT", "dependencies": { "restore-cursor": "^3.1.0" }, @@ -6973,8 +6021,7 @@ }, "node_modules/cli-spinners": { "version": "2.9.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", - "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "license": "MIT", "engines": { "node": ">=6" }, @@ -6984,18 +6031,16 @@ }, "node_modules/cli-width": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", "dev": true, + "license": "ISC", "engines": { "node": ">= 10" } }, "node_modules/cliui": { "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -7007,17 +6052,15 @@ }, "node_modules/clone": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "license": "MIT", "engines": { "node": ">=0.8" } }, "node_modules/clone-deep": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", "dev": true, + "license": "MIT", "dependencies": { "is-plain-object": "^2.0.4", "kind-of": "^6.0.2", @@ -7029,53 +6072,46 @@ }, "node_modules/color-convert": { "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "1.1.3" } }, "node_modules/color-convert/node_modules/color-name": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "license": "MIT" }, "node_modules/color-support": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", "dev": true, + "license": "ISC", "bin": { "color-support": "bin.js" } }, "node_modules/colorette": { "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/colors": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.1.90" } }, "node_modules/combined-stream": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, + "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" }, @@ -7085,37 +6121,32 @@ }, "node_modules/commander": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", "engines": { "node": ">= 10" } }, "node_modules/comment-parser": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", - "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 12.0.0" } }, "node_modules/common-path-prefix": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", - "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/compare-versions": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.0.tgz", - "integrity": "sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg==" + "license": "MIT" }, "node_modules/compressible": { "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", "dev": true, + "license": "MIT", "dependencies": { "mime-db": ">= 1.43.0 < 2" }, @@ -7125,9 +6156,8 @@ }, "node_modules/compression": { "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", "dev": true, + "license": "MIT", "dependencies": { "accepts": "~1.3.5", "bytes": "3.0.0", @@ -7143,36 +6173,31 @@ }, "node_modules/compression/node_modules/debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/compression/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/compression/node_modules/safe-buffer": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/connect": { "version": "3.7.0", - "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", - "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", "dev": true, + "license": "MIT", "dependencies": { "debug": "2.6.9", "finalhandler": "1.1.2", @@ -7185,27 +6210,24 @@ }, "node_modules/connect-history-api-fallback": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", - "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8" } }, "node_modules/connect/node_modules/debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/connect/node_modules/finalhandler": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", "dev": true, + "license": "MIT", "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", @@ -7221,15 +6243,13 @@ }, "node_modules/connect/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/connect/node_modules/on-finished": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", "dev": true, + "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -7239,24 +6259,21 @@ }, "node_modules/connect/node_modules/statuses": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/console-control-strings": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/content-disposition": { "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" }, @@ -7266,39 +6283,34 @@ }, "node_modules/content-type": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/convert-source-map": { "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cookie": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/cookie-signature": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/copy-anything": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", - "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", "dev": true, + "license": "MIT", "dependencies": { "is-what": "^3.14.1" }, @@ -7308,9 +6320,8 @@ }, "node_modules/copy-webpack-plugin": { "version": "11.0.0", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", - "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", "dev": true, + "license": "MIT", "dependencies": { "fast-glob": "^3.2.11", "glob-parent": "^6.0.1", @@ -7332,9 +6343,8 @@ }, "node_modules/copy-webpack-plugin/node_modules/glob-parent": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.3" }, @@ -7344,9 +6354,8 @@ }, "node_modules/core-js-compat": { "version": "3.36.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.1.tgz", - "integrity": "sha512-Dk997v9ZCt3X/npqzyGdTlq6t7lDBhZwGvV94PKzDArjp7BTRm7WlDAXYd/OWdeFHO8OChQYRJNJvUCqCbrtKA==", "dev": true, + "license": "MIT", "dependencies": { "browserslist": "^4.23.0" }, @@ -7357,15 +6366,13 @@ }, "node_modules/core-util-is": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cors": { "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", "dev": true, + "license": "MIT", "dependencies": { "object-assign": "^4", "vary": "^1" @@ -7376,9 +6383,8 @@ }, "node_modules/cosmiconfig": { "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", "dev": true, + "license": "MIT", "dependencies": { "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", @@ -7402,15 +6408,13 @@ }, "node_modules/cosmiconfig/node_modules/argparse": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "dev": true, + "license": "Python-2.0" }, "node_modules/cosmiconfig/node_modules/js-yaml": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -7420,15 +6424,13 @@ }, "node_modules/create-require": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/critters": { "version": "0.0.20", - "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.20.tgz", - "integrity": "sha512-CImNRorKOl5d8TWcnAz5n5izQ6HFsvz29k327/ELy6UFcmbiZNOsinaKvzv16WZR0P6etfSWYzE47C4/56B3Uw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "chalk": "^4.1.0", "css-select": "^5.1.0", @@ -7441,9 +6443,8 @@ }, "node_modules/critters/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -7456,9 +6457,8 @@ }, "node_modules/critters/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -7472,9 +6472,8 @@ }, "node_modules/critters/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -7484,18 +6483,16 @@ }, "node_modules/critters/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/critters/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -7505,9 +6502,8 @@ }, "node_modules/cross-spawn": { "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -7519,9 +6515,8 @@ }, "node_modules/css-loader": { "version": "6.8.1", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.8.1.tgz", - "integrity": "sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g==", "dev": true, + "license": "MIT", "dependencies": { "icss-utils": "^5.1.0", "postcss": "^8.4.21", @@ -7545,9 +6540,8 @@ }, "node_modules/css-select": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", @@ -7561,9 +6555,8 @@ }, "node_modules/css-what": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">= 6" }, @@ -7573,9 +6566,8 @@ }, "node_modules/cssesc": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true, + "license": "MIT", "bin": { "cssesc": "bin/cssesc" }, @@ -7585,15 +6577,13 @@ }, "node_modules/cssom": { "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cssstyle": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", "dev": true, + "license": "MIT", "dependencies": { "cssom": "~0.3.6" }, @@ -7603,20 +6593,17 @@ }, "node_modules/cssstyle/node_modules/cssom": { "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/custom-event": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", - "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/d3": { "version": "7.9.0", - "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", - "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", + "license": "ISC", "dependencies": { "d3-array": "3", "d3-axis": "3", @@ -7655,8 +6642,7 @@ }, "node_modules/d3-array": { "version": "3.2.4", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", - "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", "dependencies": { "internmap": "1 - 2" }, @@ -7666,16 +6652,14 @@ }, "node_modules/d3-axis": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", - "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/d3-brush": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", - "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "license": "ISC", "dependencies": { "d3-dispatch": "1 - 3", "d3-drag": "2 - 3", @@ -7689,8 +6673,7 @@ }, "node_modules/d3-chord": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", - "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "license": "ISC", "dependencies": { "d3-path": "1 - 3" }, @@ -7700,16 +6683,14 @@ }, "node_modules/d3-color": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", - "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/d3-contour": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", - "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "license": "ISC", "dependencies": { "d3-array": "^3.2.0" }, @@ -7719,8 +6700,7 @@ }, "node_modules/d3-delaunay": { "version": "6.0.4", - "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", - "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "license": "ISC", "dependencies": { "delaunator": "5" }, @@ -7730,16 +6710,14 @@ }, "node_modules/d3-dispatch": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", - "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/d3-drag": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", - "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "license": "ISC", "dependencies": { "d3-dispatch": "1 - 3", "d3-selection": "3" @@ -7750,8 +6728,7 @@ }, "node_modules/d3-dsv": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", - "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "license": "ISC", "dependencies": { "commander": "7", "iconv-lite": "0.6", @@ -7774,16 +6751,14 @@ }, "node_modules/d3-ease": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", - "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", "engines": { "node": ">=12" } }, "node_modules/d3-fetch": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", - "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "license": "ISC", "dependencies": { "d3-dsv": "1 - 3" }, @@ -7793,8 +6768,7 @@ }, "node_modules/d3-force": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", - "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "license": "ISC", "dependencies": { "d3-dispatch": "1 - 3", "d3-quadtree": "1 - 3", @@ -7806,16 +6780,14 @@ }, "node_modules/d3-format": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", - "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/d3-geo": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.0.tgz", - "integrity": "sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA==", + "license": "ISC", "dependencies": { "d3-array": "2.5.0 - 3" }, @@ -7825,16 +6797,14 @@ }, "node_modules/d3-hierarchy": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", - "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/d3-interpolate": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", - "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", "dependencies": { "d3-color": "1 - 3" }, @@ -7844,40 +6814,35 @@ }, "node_modules/d3-path": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", - "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/d3-polygon": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", - "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/d3-quadtree": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", - "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/d3-random": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", - "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/d3-scale": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", - "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", "dependencies": { "d3-array": "2.10.0 - 3", "d3-format": "1 - 3", @@ -7891,8 +6856,7 @@ }, "node_modules/d3-scale-chromatic": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", - "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==", + "license": "ISC", "dependencies": { "d3-color": "1 - 3", "d3-interpolate": "1 - 3" @@ -7903,16 +6867,14 @@ }, "node_modules/d3-selection": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", - "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/d3-shape": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", - "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", "dependencies": { "d3-path": "^3.1.0" }, @@ -7922,8 +6884,7 @@ }, "node_modules/d3-time": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", - "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", "dependencies": { "d3-array": "2 - 3" }, @@ -7933,8 +6894,7 @@ }, "node_modules/d3-time-format": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", - "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", "dependencies": { "d3-time": "1 - 3" }, @@ -7944,16 +6904,14 @@ }, "node_modules/d3-timer": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", - "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/d3-transition": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", - "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "license": "ISC", "dependencies": { "d3-color": "1 - 3", "d3-dispatch": "1 - 3", @@ -7970,8 +6928,7 @@ }, "node_modules/d3-zoom": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", - "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "license": "ISC", "dependencies": { "d3-dispatch": "1 - 3", "d3-drag": "2 - 3", @@ -7985,9 +6942,8 @@ }, "node_modules/dashdash": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", "dev": true, + "license": "MIT", "dependencies": { "assert-plus": "^1.0.0" }, @@ -7997,9 +6953,8 @@ }, "node_modules/data-urls": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", "dev": true, + "license": "MIT", "dependencies": { "abab": "^2.0.3", "whatwg-mimetype": "^2.3.0", @@ -8011,9 +6966,8 @@ }, "node_modules/data-view-buffer": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", - "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.6", "es-errors": "^1.3.0", @@ -8028,9 +6982,8 @@ }, "node_modules/data-view-byte-length": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", - "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "es-errors": "^1.3.0", @@ -8045,9 +6998,8 @@ }, "node_modules/data-view-byte-offset": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", - "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.6", "es-errors": "^1.3.0", @@ -8062,8 +7014,7 @@ }, "node_modules/date-fns": { "version": "2.30.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", - "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.21.0" }, @@ -8077,18 +7028,16 @@ }, "node_modules/date-format": { "version": "4.0.14", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", - "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", "dev": true, + "license": "MIT", "engines": { "node": ">=4.0" } }, "node_modules/debug": { "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -8103,30 +7052,26 @@ }, "node_modules/decamelize": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/decimal.js": { "version": "10.4.3", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", - "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/deep-is": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/default-gateway": { "version": "6.0.3", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", - "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "execa": "^5.0.0" }, @@ -8136,8 +7081,7 @@ }, "node_modules/defaults": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", - "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "license": "MIT", "dependencies": { "clone": "^1.0.2" }, @@ -8147,9 +7091,8 @@ }, "node_modules/define-data-property": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dev": true, + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -8164,18 +7107,16 @@ }, "node_modules/define-lazy-prop": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/define-properties": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, + "license": "MIT", "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", @@ -8190,9 +7131,8 @@ }, "node_modules/del": { "version": "2.2.2", - "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", - "integrity": "sha512-Z4fzpbIRjOu7lO5jCETSWoqUDVe0IPOlfugBsF6suen2LKDlVb4QZpKEM9P+buNJ4KI1eN7I083w/pbKUpsrWQ==", "dev": true, + "license": "MIT", "dependencies": { "globby": "^5.0.0", "is-path-cwd": "^1.0.0", @@ -8208,9 +7148,8 @@ }, "node_modules/del/node_modules/array-union": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", "dev": true, + "license": "MIT", "dependencies": { "array-uniq": "^1.0.1" }, @@ -8220,9 +7159,8 @@ }, "node_modules/del/node_modules/glob": { "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -8240,9 +7178,8 @@ }, "node_modules/del/node_modules/globby": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", - "integrity": "sha512-HJRTIH2EeH44ka+LWig+EqT2ONSYpVlNfx6pyd592/VF1TbfljJ7elwie7oSwcViLGqOdWocSdu2txwBF9bjmQ==", "dev": true, + "license": "MIT", "dependencies": { "array-union": "^1.0.1", "arrify": "^1.0.0", @@ -8257,18 +7194,16 @@ }, "node_modules/del/node_modules/pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/del/node_modules/rimraf": { "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "dev": true, + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -8278,50 +7213,44 @@ }, "node_modules/delaunator": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz", - "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==", + "license": "ISC", "dependencies": { "robust-predicates": "^3.0.0" } }, "node_modules/delayed-stream": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.4.0" } }, "node_modules/delegates": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/depd": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/dequal": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/destroy": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" @@ -8329,30 +7258,26 @@ }, "node_modules/detect-node": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/di": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", - "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/diff": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } }, "node_modules/dir-glob": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, + "license": "MIT", "dependencies": { "path-type": "^4.0.0" }, @@ -8362,9 +7287,8 @@ }, "node_modules/dns-packet": { "version": "5.6.1", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", - "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", "dev": true, + "license": "MIT", "dependencies": { "@leichtgewicht/ip-codec": "^2.0.1" }, @@ -8374,9 +7298,8 @@ }, "node_modules/doctrine": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, + "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -8386,9 +7309,8 @@ }, "node_modules/dom-serialize": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", - "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", "dev": true, + "license": "MIT", "dependencies": { "custom-event": "~1.0.0", "ent": "~2.2.0", @@ -8398,9 +7320,8 @@ }, "node_modules/dom-serializer": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "dev": true, + "license": "MIT", "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", @@ -8412,22 +7333,19 @@ }, "node_modules/domelementtype": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", "dev": true, "funding": [ { "type": "github", "url": "https://github.com/sponsors/fb55" } - ] + ], + "license": "BSD-2-Clause" }, "node_modules/domexception": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", - "deprecated": "Use your platform's native DOMException instead", "dev": true, + "license": "MIT", "dependencies": { "webidl-conversions": "^5.0.0" }, @@ -8437,18 +7355,16 @@ }, "node_modules/domexception/node_modules/webidl-conversions": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=8" } }, "node_modules/domhandler": { "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "domelementtype": "^2.3.0" }, @@ -8461,9 +7377,8 @@ }, "node_modules/domutils": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", @@ -8475,30 +7390,26 @@ }, "node_modules/dotenv": { "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=10" } }, "node_modules/duplexer": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/eastasianwidth": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/ecc-jsbn": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", "dev": true, + "license": "MIT", "dependencies": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" @@ -8506,15 +7417,13 @@ }, "node_modules/ee-first": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/ejs": { "version": "3.1.9", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz", - "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "jake": "^10.8.5" }, @@ -8527,39 +7436,34 @@ }, "node_modules/electron-to-chromium": { "version": "1.4.728", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.728.tgz", - "integrity": "sha512-Ud1v7hJJYIqehlUJGqR6PF1Ek8l80zWwxA6nGxigBsGJ9f9M2fciHyrIiNMerSHSH3p+0/Ia7jIlnDkt41h5cw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/emoji-regex": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/emojis-list": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } }, "node_modules/encodeurl": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/encoding": { "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "iconv-lite": "^0.6.2" @@ -8567,18 +7471,16 @@ }, "node_modules/end-of-stream": { "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, + "license": "MIT", "dependencies": { "once": "^1.4.0" } }, "node_modules/engine.io": { "version": "6.5.4", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz", - "integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==", "dev": true, + "license": "MIT", "dependencies": { "@types/cookie": "^0.4.1", "@types/cors": "^2.8.12", @@ -8597,27 +7499,24 @@ }, "node_modules/engine.io-parser": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz", - "integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" } }, "node_modules/engine.io/node_modules/cookie": { "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/engine.io/node_modules/ws": { "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", - "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -8636,9 +7535,8 @@ }, "node_modules/enhanced-resolve": { "version": "5.15.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", - "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", "dev": true, + "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -8649,9 +7547,8 @@ }, "node_modules/enquirer": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", "dev": true, + "license": "MIT", "dependencies": { "ansi-colors": "^4.1.1" }, @@ -8661,15 +7558,13 @@ }, "node_modules/ent": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/entities": { "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "devOptional": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.12" }, @@ -8679,24 +7574,21 @@ }, "node_modules/env-paths": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/err-code": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/errno": { "version": "0.1.8", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", - "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "prr": "~1.0.1" @@ -8707,18 +7599,16 @@ }, "node_modules/error-ex": { "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, + "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" } }, "node_modules/es-abstract": { "version": "1.23.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", - "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", "dev": true, + "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.1", "arraybuffer.prototype.slice": "^1.0.3", @@ -8776,9 +7666,8 @@ }, "node_modules/es-define-property": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", "dev": true, + "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.4" }, @@ -8788,24 +7677,21 @@ }, "node_modules/es-errors": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/es-module-lexer": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.0.tgz", - "integrity": "sha512-pqrTKmwEIgafsYZAGw9kszYzmagcE/n4dbgwGWLEXg7J4QFJVQRBld8j3Q3GNez79jzxZshq0bcT962QHOghjw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/es-object-atoms": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", - "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", "dev": true, + "license": "MIT", "dependencies": { "es-errors": "^1.3.0" }, @@ -8815,9 +7701,8 @@ }, "node_modules/es-set-tostringtag": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", - "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", "dev": true, + "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.4", "has-tostringtag": "^1.0.2", @@ -8829,18 +7714,16 @@ }, "node_modules/es-shim-unscopables": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", - "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", "dev": true, + "license": "MIT", "dependencies": { "hasown": "^2.0.0" } }, "node_modules/es-to-primitive": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "dev": true, + "license": "MIT", "dependencies": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -8855,25 +7738,22 @@ }, "node_modules/es6-promise": { "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/es6-promisify": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", "dev": true, + "license": "MIT", "dependencies": { "es6-promise": "^4.0.3" } }, "node_modules/esbuild": { "version": "0.18.17", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.17.tgz", - "integrity": "sha512-1GJtYnUxsJreHYA0Y+iQz2UEykonY66HNWOb0yXYZi9/kNrORUEHVg87eQsCtqh59PEJ5YVZJO98JHznMJSWjg==", "dev": true, "hasInstallScript": true, + "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -8907,9 +7787,8 @@ }, "node_modules/esbuild-wasm": { "version": "0.18.17", - "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.18.17.tgz", - "integrity": "sha512-9OHGcuRzy+I8ziF9FzjfKLWAPbvi0e/metACVg9k6bK+SI4FFxeV6PcZsz8RIVaMD4YNehw+qj6UMR3+qj/EuQ==", "dev": true, + "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -8919,33 +7798,29 @@ }, "node_modules/escalade": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/escape-html": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/escape-string-regexp": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.0" } }, "node_modules/escodegen": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", - "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esprima": "^4.0.1", "estraverse": "^5.2.0", @@ -8964,18 +7839,16 @@ }, "node_modules/escodegen/node_modules/estraverse": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } }, "node_modules/escodegen/node_modules/source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "optional": true, "engines": { "node": ">=0.10.0" @@ -8983,9 +7856,8 @@ }, "node_modules/eslint": { "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -9038,9 +7910,8 @@ }, "node_modules/eslint-import-resolver-node": { "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^3.2.7", "is-core-module": "^2.13.0", @@ -9049,18 +7920,16 @@ }, "node_modules/eslint-import-resolver-node/node_modules/debug": { "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.1" } }, "node_modules/eslint-module-utils": { "version": "2.8.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", - "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^3.2.7" }, @@ -9075,18 +7944,16 @@ }, "node_modules/eslint-module-utils/node_modules/debug": { "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.1" } }, "node_modules/eslint-plugin-import": { "version": "2.29.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", - "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", "dev": true, + "license": "MIT", "dependencies": { "array-includes": "^3.1.7", "array.prototype.findlastindex": "^1.2.3", @@ -9115,18 +7982,16 @@ }, "node_modules/eslint-plugin-import/node_modules/debug": { "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.1" } }, "node_modules/eslint-plugin-import/node_modules/doctrine": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -9136,18 +8001,16 @@ }, "node_modules/eslint-plugin-import/node_modules/semver": { "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" } }, "node_modules/eslint-plugin-jsdoc": { "version": "48.2.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.2.3.tgz", - "integrity": "sha512-r9DMAmFs66VNvNqRLLjHejdnJtILrt3xGi+Qx0op0oRfFGVpOR1Hb3BC++MacseHx93d8SKYPhyrC9BS7Os2QA==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@es-joy/jsdoccomment": "~0.42.0", "are-docs-informative": "^0.0.2", @@ -9168,9 +8031,8 @@ }, "node_modules/eslint-plugin-jsdoc/node_modules/escape-string-regexp": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -9180,9 +8042,8 @@ }, "node_modules/eslint-plugin-jsdoc/node_modules/spdx-expression-parse": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", - "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", "dev": true, + "license": "MIT", "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -9190,18 +8051,16 @@ }, "node_modules/eslint-plugin-prefer-arrow": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-prefer-arrow/-/eslint-plugin-prefer-arrow-1.2.3.tgz", - "integrity": "sha512-J9I5PKCOJretVuiZRGvPQxCbllxGAV/viI20JO3LYblAodofBxyMnZAJ+WGeClHgANnSJberTNoFWWjrWKBuXQ==", "dev": true, + "license": "MIT", "peerDependencies": { "eslint": ">=2.0.0" } }, "node_modules/eslint-plugin-unused-imports": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-3.1.0.tgz", - "integrity": "sha512-9l1YFCzXKkw1qtAru1RWUtG2EVDZY0a0eChKXcL+EZ5jitG7qxdctu4RnvhOJHv4xfmUf7h+JJPINlVpGhZMrw==", "dev": true, + "license": "MIT", "dependencies": { "eslint-rule-composer": "^0.3.0" }, @@ -9220,18 +8079,16 @@ }, "node_modules/eslint-rule-composer": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", - "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", "dev": true, + "license": "MIT", "engines": { "node": ">=4.0.0" } }, "node_modules/eslint-scope": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -9242,9 +8099,8 @@ }, "node_modules/eslint-visitor-keys": { "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -9254,9 +8110,8 @@ }, "node_modules/eslint/node_modules/ajv": { "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -9270,9 +8125,8 @@ }, "node_modules/eslint/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -9285,15 +8139,13 @@ }, "node_modules/eslint/node_modules/argparse": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "dev": true, + "license": "Python-2.0" }, "node_modules/eslint/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -9307,9 +8159,8 @@ }, "node_modules/eslint/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -9319,9 +8170,8 @@ }, "node_modules/eslint/node_modules/escape-string-regexp": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -9331,9 +8181,8 @@ }, "node_modules/eslint/node_modules/eslint-scope": { "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -9347,18 +8196,16 @@ }, "node_modules/eslint/node_modules/estraverse": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } }, "node_modules/eslint/node_modules/find-up": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -9372,9 +8219,8 @@ }, "node_modules/eslint/node_modules/glob-parent": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.3" }, @@ -9384,9 +8230,8 @@ }, "node_modules/eslint/node_modules/globals": { "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^0.20.2" }, @@ -9399,18 +8244,16 @@ }, "node_modules/eslint/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/eslint/node_modules/js-yaml": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -9420,15 +8263,13 @@ }, "node_modules/eslint/node_modules/json-schema-traverse": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/eslint/node_modules/locate-path": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^5.0.0" }, @@ -9441,9 +8282,8 @@ }, "node_modules/eslint/node_modules/p-limit": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" }, @@ -9456,9 +8296,8 @@ }, "node_modules/eslint/node_modules/p-locate": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^3.0.2" }, @@ -9471,9 +8310,8 @@ }, "node_modules/eslint/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -9483,9 +8321,8 @@ }, "node_modules/eslint/node_modules/type-fest": { "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -9495,9 +8332,8 @@ }, "node_modules/espree": { "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", @@ -9512,9 +8348,8 @@ }, "node_modules/esprima": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true, + "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -9525,9 +8360,8 @@ }, "node_modules/esquery": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -9537,18 +8371,16 @@ }, "node_modules/esquery/node_modules/estraverse": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } }, "node_modules/esrecurse": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -9558,66 +8390,58 @@ }, "node_modules/esrecurse/node_modules/estraverse": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } }, "node_modules/estraverse": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } }, "node_modules/esutils": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/etag": { "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/eventemitter-asyncresource": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz", - "integrity": "sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/eventemitter3": { "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/events": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.x" } }, "node_modules/execa": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, + "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -9638,8 +8462,6 @@ }, "node_modules/exit": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", "dev": true, "engines": { "node": ">= 0.8.0" @@ -9647,15 +8469,13 @@ }, "node_modules/exponential-backoff": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", - "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/express": { "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "dev": true, + "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", @@ -9695,30 +8515,26 @@ }, "node_modules/express/node_modules/debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/express/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/extend": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/external-editor": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", "dev": true, + "license": "MIT", "dependencies": { "chardet": "^0.7.0", "iconv-lite": "^0.4.24", @@ -9730,9 +8546,8 @@ }, "node_modules/external-editor/node_modules/iconv-lite": { "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -9742,23 +8557,20 @@ }, "node_modules/extsprintf": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", "dev": true, "engines": [ "node >=0.6.0" - ] + ], + "license": "MIT" }, "node_modules/fast-deep-equal": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "license": "MIT" }, "node_modules/fast-glob": { "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -9772,29 +8584,25 @@ }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fastq": { "version": "1.16.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", - "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", "dev": true, + "license": "ISC", "dependencies": { "reusify": "^1.0.4" } }, "node_modules/faye-websocket": { "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", "dev": true, + "license": "Apache-2.0", "dependencies": { "websocket-driver": ">=0.5.1" }, @@ -9804,9 +8612,8 @@ }, "node_modules/figures": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", "dev": true, + "license": "MIT", "dependencies": { "escape-string-regexp": "^1.0.5" }, @@ -9819,9 +8626,8 @@ }, "node_modules/file-entry-cache": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, + "license": "MIT", "dependencies": { "flat-cache": "^3.0.4" }, @@ -9831,32 +8637,28 @@ }, "node_modules/file-saver-es": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/file-saver-es/-/file-saver-es-2.0.5.tgz", - "integrity": "sha512-Kg0lt+is9nOyi/VDms9miScNGot25jVFbjFccXuCL/shd2Q+rt70MALxHVkXllsX83JEBLiHQNjDPGd/6FIOoQ==" + "license": "MIT" }, "node_modules/filelist": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", - "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", "dev": true, + "license": "Apache-2.0", "dependencies": { "minimatch": "^5.0.1" } }, "node_modules/filelist/node_modules/brace-expansion": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/filelist/node_modules/minimatch": { "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -9866,9 +8668,8 @@ }, "node_modules/fill-range": { "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "devOptional": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -9878,9 +8679,8 @@ }, "node_modules/finalhandler": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", "dev": true, + "license": "MIT", "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", @@ -9896,24 +8696,21 @@ }, "node_modules/finalhandler/node_modules/debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/finalhandler/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/find-cache-dir": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", - "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", "dev": true, + "license": "MIT", "dependencies": { "common-path-prefix": "^3.0.0", "pkg-dir": "^7.0.0" @@ -9927,9 +8724,8 @@ }, "node_modules/find-up": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -9940,18 +8736,16 @@ }, "node_modules/flat": { "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", "dev": true, + "license": "BSD-3-Clause", "bin": { "flat": "cli.js" } }, "node_modules/flat-cache": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, + "license": "MIT", "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.3", @@ -9963,14 +8757,11 @@ }, "node_modules/flatted": { "version": "3.2.9", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/follow-redirects": { "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "dev": true, "funding": [ { @@ -9978,6 +8769,7 @@ "url": "https://github.com/sponsors/RubenVerborgh" } ], + "license": "MIT", "engines": { "node": ">=4.0" }, @@ -9989,18 +8781,16 @@ }, "node_modules/for-each": { "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", "dev": true, + "license": "MIT", "dependencies": { "is-callable": "^1.1.3" } }, "node_modules/foreground-child": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", "dev": true, + "license": "ISC", "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -10014,9 +8804,8 @@ }, "node_modules/foreground-child/node_modules/signal-exit": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, + "license": "ISC", "engines": { "node": ">=14" }, @@ -10026,18 +8815,16 @@ }, "node_modules/forever-agent": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "*" } }, "node_modules/form-data": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", "dev": true, + "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -10049,18 +8836,16 @@ }, "node_modules/forwarded": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/fraction.js": { "version": "4.3.7", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", - "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", "dev": true, + "license": "MIT", "engines": { "node": "*" }, @@ -10071,24 +8856,21 @@ }, "node_modules/fresh": { "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/fs-constants": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fs-extra": { "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "dev": true, + "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", @@ -10100,9 +8882,8 @@ }, "node_modules/fs-minipass": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", - "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", "dev": true, + "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, @@ -10112,53 +8893,34 @@ }, "node_modules/fs-minipass/node_modules/minipass": { "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", "dev": true, + "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } }, "node_modules/fs-monkey": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz", - "integrity": "sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==", - "dev": true + "dev": true, + "license": "Unlicense" }, "node_modules/fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } + "license": "ISC" }, "node_modules/function-bind": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/function.prototype.name": { "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -10174,18 +8936,16 @@ }, "node_modules/functions-have-names": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/gauge": { "version": "4.0.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", - "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", "dev": true, + "license": "ISC", "dependencies": { "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.3", @@ -10202,27 +8962,24 @@ }, "node_modules/gensync": { "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/get-caller-file": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, + "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } }, "node_modules/get-intrinsic": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dev": true, + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2", @@ -10239,18 +8996,16 @@ }, "node_modules/get-package-type": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.0.0" } }, "node_modules/get-stream": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -10260,9 +9015,8 @@ }, "node_modules/get-symbol-description": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", - "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.5", "es-errors": "^1.3.0", @@ -10277,18 +9031,16 @@ }, "node_modules/getpass": { "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", "dev": true, + "license": "MIT", "dependencies": { "assert-plus": "^1.0.0" } }, "node_modules/glob": { "version": "10.3.12", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", - "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", "dev": true, + "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^2.3.6", @@ -10308,9 +9060,8 @@ }, "node_modules/glob-parent": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "devOptional": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -10320,24 +9071,21 @@ }, "node_modules/glob-to-regexp": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true + "dev": true, + "license": "BSD-2-Clause" }, "node_modules/glob/node_modules/brace-expansion": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/glob/node_modules/minimatch": { "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -10350,27 +9098,24 @@ }, "node_modules/glob/node_modules/minipass": { "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", "dev": true, + "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } }, "node_modules/globals": { "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/globalthis": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", "dev": true, + "license": "MIT", "dependencies": { "define-properties": "^1.1.3" }, @@ -10383,9 +9128,8 @@ }, "node_modules/globby": { "version": "13.2.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", - "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", "dev": true, + "license": "MIT", "dependencies": { "dir-glob": "^3.0.1", "fast-glob": "^3.3.0", @@ -10402,9 +9146,8 @@ }, "node_modules/gopd": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", "dev": true, + "license": "MIT", "dependencies": { "get-intrinsic": "^1.1.3" }, @@ -10414,21 +9157,18 @@ }, "node_modules/graceful-fs": { "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/graphemer": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/guess-parser": { "version": "0.4.22", - "resolved": "https://registry.npmjs.org/guess-parser/-/guess-parser-0.4.22.tgz", - "integrity": "sha512-KcUWZ5ACGaBM69SbqwVIuWGoSAgD+9iJnchR9j/IarVI1jHVeXv+bUXBIMeqVMSKt3zrn0Dgf9UpcOEpPBLbSg==", "dev": true, + "license": "MIT", "dependencies": { "@wessberg/ts-evaluator": "0.0.27" }, @@ -10438,33 +9178,28 @@ }, "node_modules/hammerjs": { "version": "2.0.8", - "resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz", - "integrity": "sha512-tSQXBXS/MWQOn/RKckawJ61vvsDpCom87JgxiYdGwHdOa0ht0vzUWDlfioofFCRU0L+6NGDt6XzbgoJvZkMeRQ==", + "license": "MIT", "engines": { "node": ">=0.8.0" } }, "node_modules/handle-thing": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/har-schema": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", "dev": true, + "license": "ISC", "engines": { "node": ">=4" } }, "node_modules/har-validator": { "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^6.12.3", "har-schema": "^2.0.0" @@ -10475,9 +9210,8 @@ }, "node_modules/har-validator/node_modules/ajv": { "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -10491,15 +9225,13 @@ }, "node_modules/har-validator/node_modules/json-schema-traverse": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/has-ansi": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^2.0.0" }, @@ -10509,36 +9241,32 @@ }, "node_modules/has-ansi/node_modules/ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/has-bigints": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-flag": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/has-property-descriptors": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" }, @@ -10548,9 +9276,8 @@ }, "node_modules/has-proto": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -10560,9 +9287,8 @@ }, "node_modules/has-symbols": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -10572,9 +9298,8 @@ }, "node_modules/has-tostringtag": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, + "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" }, @@ -10587,15 +9312,13 @@ }, "node_modules/has-unicode": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/hasown": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -10605,9 +9328,8 @@ }, "node_modules/hdr-histogram-js": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz", - "integrity": "sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g==", "dev": true, + "license": "BSD", "dependencies": { "@assemblyscript/loader": "^0.10.1", "base64-js": "^1.2.0", @@ -10616,15 +9338,13 @@ }, "node_modules/hdr-histogram-percentiles-obj": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz", - "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/hosted-git-info": { "version": "6.1.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", - "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", "dev": true, + "license": "ISC", "dependencies": { "lru-cache": "^7.5.1" }, @@ -10634,18 +9354,16 @@ }, "node_modules/hosted-git-info/node_modules/lru-cache": { "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "dev": true, + "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/hpack.js": { "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", "dev": true, + "license": "MIT", "dependencies": { "inherits": "^2.0.1", "obuf": "^1.0.0", @@ -10655,9 +9373,8 @@ }, "node_modules/hpack.js/node_modules/readable-stream": { "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, + "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -10670,24 +9387,21 @@ }, "node_modules/hpack.js/node_modules/safe-buffer": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/hpack.js/node_modules/string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" } }, "node_modules/html-encoding-sniffer": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", "dev": true, + "license": "MIT", "dependencies": { "whatwg-encoding": "^1.0.5" }, @@ -10697,8 +9411,6 @@ }, "node_modules/html-entities": { "version": "2.5.2", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", - "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", "dev": true, "funding": [ { @@ -10709,18 +9421,16 @@ "type": "patreon", "url": "https://patreon.com/mdevils" } - ] + ], + "license": "MIT" }, "node_modules/html-escaper": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/htmlparser2": { "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", "dev": true, "funding": [ "https://github.com/fb55/htmlparser2?sponsor=1", @@ -10729,6 +9439,7 @@ "url": "https://github.com/sponsors/fb55" } ], + "license": "MIT", "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", @@ -10738,21 +9449,18 @@ }, "node_modules/http-cache-semantics": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "dev": true + "dev": true, + "license": "BSD-2-Clause" }, "node_modules/http-deceiver": { "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/http-errors": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "dev": true, + "license": "MIT", "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", @@ -10766,15 +9474,13 @@ }, "node_modules/http-parser-js": { "version": "0.5.8", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", - "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/http-proxy": { "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "dev": true, + "license": "MIT", "dependencies": { "eventemitter3": "^4.0.0", "follow-redirects": "^1.0.0", @@ -10786,9 +9492,8 @@ }, "node_modules/http-proxy-agent": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", "dev": true, + "license": "MIT", "dependencies": { "@tootallnate/once": "1", "agent-base": "6", @@ -10800,9 +9505,8 @@ }, "node_modules/http-proxy-middleware": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", - "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", "dev": true, + "license": "MIT", "dependencies": { "@types/http-proxy": "^1.17.8", "http-proxy": "^1.18.1", @@ -10824,9 +9528,8 @@ }, "node_modules/http-signature": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", "dev": true, + "license": "MIT", "dependencies": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", @@ -10839,9 +9542,8 @@ }, "node_modules/https-proxy-agent": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", "dev": true, + "license": "MIT", "dependencies": { "agent-base": "6", "debug": "4" @@ -10852,26 +9554,23 @@ }, "node_modules/human-signals": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=10.17.0" } }, "node_modules/humanize-ms": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.0.0" } }, "node_modules/iconv-lite": { "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -10881,9 +9580,8 @@ }, "node_modules/icss-utils": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", "dev": true, + "license": "ISC", "engines": { "node": "^10 || ^12 || >= 14" }, @@ -10893,8 +9591,6 @@ }, "node_modules/ieee754": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", "funding": [ { "type": "github", @@ -10908,22 +9604,21 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "BSD-3-Clause" }, "node_modules/ignore": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } }, "node_modules/ignore-walk": { "version": "6.0.4", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.4.tgz", - "integrity": "sha512-t7sv42WkwFkyKbivUCglsQW5YWMskWtbEf4MNKX5u/CCWHKSPzN4FtBQGsQZgCLbxOzpVlcbWVK5KB3auIOjSw==", "dev": true, + "license": "ISC", "dependencies": { "minimatch": "^9.0.0" }, @@ -10933,18 +9628,16 @@ }, "node_modules/ignore-walk/node_modules/brace-expansion": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/ignore-walk/node_modules/minimatch": { "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -10957,9 +9650,8 @@ }, "node_modules/image-size": { "version": "0.5.5", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", - "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", "dev": true, + "license": "MIT", "optional": true, "bin": { "image-size": "bin/image-size.js" @@ -10970,21 +9662,18 @@ }, "node_modules/immediate": { "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/immutable": { "version": "4.3.5", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", - "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/import-fresh": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, + "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -10998,42 +9687,37 @@ }, "node_modules/import-fresh/node_modules/resolve-from": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/imurmurhash": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.19" } }, "node_modules/indent-string": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/infer-owner": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/inflight": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "dev": true, + "license": "ISC", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -11041,23 +9725,20 @@ }, "node_modules/inherits": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "license": "ISC" }, "node_modules/ini": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", - "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", "dev": true, + "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/inquirer": { "version": "8.2.4", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", - "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", "dev": true, + "license": "MIT", "dependencies": { "ansi-escapes": "^4.2.1", "chalk": "^4.1.1", @@ -11081,9 +9762,8 @@ }, "node_modules/inquirer/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -11096,9 +9776,8 @@ }, "node_modules/inquirer/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -11112,9 +9791,8 @@ }, "node_modules/inquirer/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -11124,27 +9802,24 @@ }, "node_modules/inquirer/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/inquirer/node_modules/rxjs": { "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/inquirer/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -11154,9 +9829,8 @@ }, "node_modules/internal-slot": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", - "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", "dev": true, + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.0", @@ -11168,25 +9842,22 @@ }, "node_modules/internmap": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", - "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/ionicons": { "version": "6.1.3", - "resolved": "https://registry.npmjs.org/ionicons/-/ionicons-6.1.3.tgz", - "integrity": "sha512-ptzz38dd/Yq+PgjhXegh7yhb/SLIk1bvL9vQDtLv1aoSc7alO6mX2DIMgcKYzt9vrNWkRu1f9Jr78zIFFyOXqw==", + "license": "MIT", "dependencies": { "@stencil/core": "^2.18.0" } }, "node_modules/ip-address": { "version": "9.0.5", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", - "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", "dev": true, + "license": "MIT", "dependencies": { "jsbn": "1.1.0", "sprintf-js": "^1.1.3" @@ -11197,30 +9868,26 @@ }, "node_modules/ip-address/node_modules/jsbn": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", - "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/ip-address/node_modules/sprintf-js": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/ipaddr.js": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", - "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10" } }, "node_modules/is-array-buffer": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", - "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.2.1" @@ -11234,15 +9901,13 @@ }, "node_modules/is-arrayish": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/is-bigint": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", "dev": true, + "license": "MIT", "dependencies": { "has-bigints": "^1.0.1" }, @@ -11252,9 +9917,8 @@ }, "node_modules/is-binary-path": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "devOptional": true, + "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" }, @@ -11264,9 +9928,8 @@ }, "node_modules/is-boolean-object": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -11280,9 +9943,8 @@ }, "node_modules/is-builtin-module": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", - "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", "dev": true, + "license": "MIT", "dependencies": { "builtin-modules": "^3.3.0" }, @@ -11295,9 +9957,8 @@ }, "node_modules/is-callable": { "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -11307,9 +9968,8 @@ }, "node_modules/is-core-module": { "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dev": true, + "license": "MIT", "dependencies": { "hasown": "^2.0.0" }, @@ -11319,9 +9979,8 @@ }, "node_modules/is-data-view": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", - "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", "dev": true, + "license": "MIT", "dependencies": { "is-typed-array": "^1.1.13" }, @@ -11334,9 +9993,8 @@ }, "node_modules/is-date-object": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", "dev": true, + "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -11349,9 +10007,8 @@ }, "node_modules/is-docker": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "dev": true, + "license": "MIT", "bin": { "is-docker": "cli.js" }, @@ -11364,27 +10021,24 @@ }, "node_modules/is-extglob": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "devOptional": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/is-glob": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "devOptional": true, + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -11394,23 +10048,20 @@ }, "node_modules/is-interactive": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/is-lambda": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/is-negative-zero": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -11420,18 +10071,16 @@ }, "node_modules/is-number": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "devOptional": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } }, "node_modules/is-number-object": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "dev": true, + "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -11444,18 +10093,16 @@ }, "node_modules/is-path-cwd": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "integrity": "sha512-cnS56eR9SPAscL77ik76ATVqoPARTqPIVkMDVxRaWH06zT+6+CzIroYRJ0VVvm0Z1zfAvxvz9i/D3Ppjaqt5Nw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/is-path-in-cwd": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", - "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", "dev": true, + "license": "MIT", "dependencies": { "is-path-inside": "^1.0.0" }, @@ -11465,9 +10112,8 @@ }, "node_modules/is-path-in-cwd/node_modules/is-path-inside": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha512-qhsCR/Esx4U4hg/9I19OVUAJkGWtjRYHMRgUMZE2TDdj+Ag+kttZanLupfddNyglzz50cUlmWzUaI37GDfNx/g==", "dev": true, + "license": "MIT", "dependencies": { "path-is-inside": "^1.0.1" }, @@ -11477,18 +10123,16 @@ }, "node_modules/is-path-inside": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/is-plain-obj": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -11498,9 +10142,8 @@ }, "node_modules/is-plain-object": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, + "license": "MIT", "dependencies": { "isobject": "^3.0.1" }, @@ -11510,15 +10153,13 @@ }, "node_modules/is-potential-custom-element-name": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/is-regex": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -11532,9 +10173,8 @@ }, "node_modules/is-shared-array-buffer": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", - "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7" }, @@ -11547,9 +10187,8 @@ }, "node_modules/is-stream": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -11559,9 +10198,8 @@ }, "node_modules/is-string": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", "dev": true, + "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -11574,9 +10212,8 @@ }, "node_modules/is-symbol": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "dev": true, + "license": "MIT", "dependencies": { "has-symbols": "^1.0.2" }, @@ -11589,9 +10226,8 @@ }, "node_modules/is-typed-array": { "version": "1.1.13", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", - "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", "dev": true, + "license": "MIT", "dependencies": { "which-typed-array": "^1.1.14" }, @@ -11604,14 +10240,12 @@ }, "node_modules/is-typedarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/is-unicode-supported": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "license": "MIT", "engines": { "node": ">=10" }, @@ -11621,9 +10255,8 @@ }, "node_modules/is-weakref": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2" }, @@ -11633,15 +10266,13 @@ }, "node_modules/is-what": { "version": "3.14.1", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", - "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/is-wsl": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "dev": true, + "license": "MIT", "dependencies": { "is-docker": "^2.0.0" }, @@ -11651,15 +10282,13 @@ }, "node_modules/isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/isbinaryfile": { "version": "4.0.10", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", - "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8.0.0" }, @@ -11669,39 +10298,34 @@ }, "node_modules/isexe": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/isobject": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/isstream": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=8" } }, "node_modules/istanbul-lib-instrument": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", @@ -11715,18 +10339,16 @@ }, "node_modules/istanbul-lib-instrument/node_modules/semver": { "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" } }, "node_modules/istanbul-lib-report": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^4.0.0", @@ -11738,18 +10360,16 @@ }, "node_modules/istanbul-lib-report/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/istanbul-lib-report/node_modules/make-dir": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, + "license": "MIT", "dependencies": { "semver": "^7.5.3" }, @@ -11762,9 +10382,8 @@ }, "node_modules/istanbul-lib-report/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -11774,9 +10393,8 @@ }, "node_modules/istanbul-lib-source-maps": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "debug": "^4.1.1", "istanbul-lib-coverage": "^3.0.0", @@ -11788,18 +10406,16 @@ }, "node_modules/istanbul-lib-source-maps/node_modules/source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/istanbul-reports": { "version": "3.1.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", - "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" @@ -11810,9 +10426,8 @@ }, "node_modules/jackspeak": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", - "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -11828,9 +10443,8 @@ }, "node_modules/jake": { "version": "10.8.7", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz", - "integrity": "sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==", "dev": true, + "license": "Apache-2.0", "dependencies": { "async": "^3.2.3", "chalk": "^4.0.2", @@ -11846,9 +10460,8 @@ }, "node_modules/jake/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -11861,9 +10474,8 @@ }, "node_modules/jake/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -11877,9 +10489,8 @@ }, "node_modules/jake/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -11889,18 +10500,16 @@ }, "node_modules/jake/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jake/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -11910,9 +10519,8 @@ }, "node_modules/jasmine": { "version": "2.8.0", - "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz", - "integrity": "sha512-KbdGQTf5jbZgltoHs31XGiChAPumMSY64OZMWLNYnEnMfG5uwGBhffePwuskexjT+/Jea/gU3qAU8344hNohSw==", "dev": true, + "license": "MIT", "dependencies": { "exit": "^0.1.2", "glob": "^7.0.6", @@ -11924,24 +10532,21 @@ }, "node_modules/jasmine-core": { "version": "4.5.0", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.5.0.tgz", - "integrity": "sha512-9PMzyvhtocxb3aXJVOPqBDswdgyAeSB81QnLop4npOpbqnheaTEwPc9ZloQeVswugPManznQBjD8kWDTjlnHuw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jasmine-spec-reporter": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-7.0.0.tgz", - "integrity": "sha512-OtC7JRasiTcjsaCBPtMO0Tl8glCejM4J4/dNuOJdA8lBjz4PmWjYQ6pzb0uzpBNAWJMDudYuj9OdXJWqM2QTJg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "colors": "1.4.0" } }, "node_modules/jasmine/node_modules/glob": { "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -11959,24 +10564,21 @@ }, "node_modules/jasmine/node_modules/jasmine-core": { "version": "2.8.0", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz", - "integrity": "sha512-SNkOkS+/jMZvLhuSx1fjhcNWUC/KG6oVyFUGkSBEr9n1axSNduWU8GlI7suaHXr4yxjet6KjrUZxUTE5WzzWwQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jasminewd2": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.2.0.tgz", - "integrity": "sha512-Rn0nZe4rfDhzA63Al3ZGh0E+JTmM6ESZYXJGKuqKGZObsAB9fwXPD03GjtIEvJBDOhN94T5MzbwZSqzFHSQPzg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6.9.x" } }, "node_modules/jest-worker": { "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", @@ -11988,18 +10590,16 @@ }, "node_modules/jest-worker/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-worker/node_modules/supports-color": { "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -12012,24 +10612,21 @@ }, "node_modules/jiti": { "version": "1.21.0", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", - "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", "dev": true, + "license": "MIT", "bin": { "jiti": "bin/jiti.js" } }, "node_modules/js-tokens": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/js-yaml": { "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -12040,24 +10637,21 @@ }, "node_modules/jsbn": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jsdoc-type-pratt-parser": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", - "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=12.0.0" } }, "node_modules/jsdom": { "version": "16.7.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", - "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", "dev": true, + "license": "MIT", "dependencies": { "abab": "^2.0.5", "acorn": "^8.2.4", @@ -12101,9 +10695,8 @@ }, "node_modules/jsesc": { "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true, + "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, @@ -12113,44 +10706,37 @@ }, "node_modules/json-buffer": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-schema": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true + "dev": true, + "license": "(AFL-2.1 OR BSD-3-Clause)" }, "node_modules/json-schema-traverse": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stringify-safe": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/json5": { "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, + "license": "MIT", "bin": { "json5": "lib/cli.js" }, @@ -12160,32 +10746,28 @@ }, "node_modules/jsonc-parser": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", - "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==" + "license": "MIT" }, "node_modules/jsonfile": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "dev": true, + "license": "MIT", "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "node_modules/jsonparse": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", "dev": true, "engines": [ "node >= 0.2.0" - ] + ], + "license": "MIT" }, "node_modules/jsprim": { "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", "dev": true, + "license": "MIT", "dependencies": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", @@ -12198,9 +10780,8 @@ }, "node_modules/jszip": { "version": "3.10.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", - "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", "dev": true, + "license": "(MIT OR GPL-3.0-or-later)", "dependencies": { "lie": "~3.3.0", "pako": "~1.0.2", @@ -12210,9 +10791,8 @@ }, "node_modules/jszip/node_modules/readable-stream": { "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, + "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -12225,24 +10805,21 @@ }, "node_modules/jszip/node_modules/safe-buffer": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jszip/node_modules/string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" } }, "node_modules/karma": { "version": "6.4.2", - "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.2.tgz", - "integrity": "sha512-C6SU/53LB31BEgRg+omznBEMY4SjHU3ricV6zBcAe1EeILKkeScr+fZXtaI5WyDbkVowJxxAI6h73NcFPmXolQ==", "dev": true, + "license": "MIT", "dependencies": { "@colors/colors": "1.5.0", "body-parser": "^1.19.0", @@ -12278,18 +10855,16 @@ }, "node_modules/karma-chrome-launcher": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.2.0.tgz", - "integrity": "sha512-rE9RkUPI7I9mAxByQWkGJFXfFD6lE4gC5nPuZdobf/QdTEJI6EU4yIay/cfU/xV4ZxlM5JiTv7zWYgA64NpS5Q==", "dev": true, + "license": "MIT", "dependencies": { "which": "^1.2.1" } }, "node_modules/karma-chrome-launcher/node_modules/which": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -12299,9 +10874,8 @@ }, "node_modules/karma-coverage": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-2.2.1.tgz", - "integrity": "sha512-yj7hbequkQP2qOSb20GuNSIyE//PgJWHwC2IydLE6XRtsnaflv+/OSGNssPjobYUlhVVagy99TQpqUt3vAUG7A==", "dev": true, + "license": "MIT", "dependencies": { "istanbul-lib-coverage": "^3.2.0", "istanbul-lib-instrument": "^5.1.0", @@ -12316,9 +10890,8 @@ }, "node_modules/karma-coverage-istanbul-reporter": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-3.0.3.tgz", - "integrity": "sha512-wE4VFhG/QZv2Y4CdAYWDbMmcAHeS926ZIji4z+FkB2aF/EposRb6DP6G5ncT/wXhqUfAb/d7kZrNKPonbvsATw==", "dev": true, + "license": "MIT", "dependencies": { "istanbul-lib-coverage": "^3.0.0", "istanbul-lib-report": "^3.0.0", @@ -12332,9 +10905,8 @@ }, "node_modules/karma-coverage-istanbul-reporter/node_modules/glob": { "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -12352,9 +10924,8 @@ }, "node_modules/karma-coverage-istanbul-reporter/node_modules/istanbul-lib-source-maps": { "version": "3.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", - "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "debug": "^4.1.1", "istanbul-lib-coverage": "^2.0.5", @@ -12368,18 +10939,16 @@ }, "node_modules/karma-coverage-istanbul-reporter/node_modules/istanbul-lib-source-maps/node_modules/istanbul-lib-coverage": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", - "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=6" } }, "node_modules/karma-coverage-istanbul-reporter/node_modules/rimraf": { "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "dev": true, + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -12389,18 +10958,16 @@ }, "node_modules/karma-coverage-istanbul-reporter/node_modules/source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/karma-jasmine": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-5.1.0.tgz", - "integrity": "sha512-i/zQLFrfEpRyQoJF9fsCdTMOF5c2dK7C7OmsuKg2D0YSsuZSfQDiLuaiktbuio6F2wiCsZSnSnieIQ0ant/uzQ==", "dev": true, + "license": "MIT", "dependencies": { "jasmine-core": "^4.1.0" }, @@ -12413,9 +10980,8 @@ }, "node_modules/karma-jasmine-html-reporter": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-2.1.0.tgz", - "integrity": "sha512-sPQE1+nlsn6Hwb5t+HHwyy0A1FNCVKuL1192b+XNauMYWThz2kweiBVW1DqloRpVvZIJkIoHVB7XRpK78n1xbQ==", "dev": true, + "license": "MIT", "peerDependencies": { "jasmine-core": "^4.0.0 || ^5.0.0", "karma": "^6.0.0", @@ -12424,18 +10990,16 @@ }, "node_modules/karma-source-map-support": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", - "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", "dev": true, + "license": "MIT", "dependencies": { "source-map-support": "^0.5.5" } }, "node_modules/karma/node_modules/cliui": { "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", @@ -12444,9 +11008,8 @@ }, "node_modules/karma/node_modules/glob": { "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -12464,9 +11027,8 @@ }, "node_modules/karma/node_modules/mime": { "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", "dev": true, + "license": "MIT", "bin": { "mime": "cli.js" }, @@ -12476,9 +11038,8 @@ }, "node_modules/karma/node_modules/mkdirp": { "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, + "license": "MIT", "dependencies": { "minimist": "^1.2.6" }, @@ -12488,18 +11049,16 @@ }, "node_modules/karma/node_modules/source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/karma/node_modules/tmp": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", "dev": true, + "license": "MIT", "dependencies": { "rimraf": "^3.0.0" }, @@ -12509,9 +11068,8 @@ }, "node_modules/karma/node_modules/yargs": { "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, + "license": "MIT", "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", @@ -12527,45 +11085,40 @@ }, "node_modules/karma/node_modules/yargs-parser": { "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } }, "node_modules/keyv": { "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, + "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } }, "node_modules/kind-of": { "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/klona": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", - "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/launch-editor": { "version": "2.6.1", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.1.tgz", - "integrity": "sha512-eB/uXmFVpY4zezmGp5XtU21kwo7GBbKB+EQ+UZeWtGb9yAM5xt/Evk+lYH3eRNAtId+ej4u7TYPFZ07w4s7rRw==", "dev": true, + "license": "MIT", "dependencies": { "picocolors": "^1.0.0", "shell-quote": "^1.8.1" @@ -12573,9 +11126,8 @@ }, "node_modules/less": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/less/-/less-4.2.0.tgz", - "integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==", "dev": true, + "license": "Apache-2.0", "peer": true, "dependencies": { "copy-anything": "^2.0.1", @@ -12600,9 +11152,8 @@ }, "node_modules/less-loader": { "version": "11.1.0", - "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.1.0.tgz", - "integrity": "sha512-C+uDBV7kS7W5fJlUjq5mPBeBVhYpTIm5gB09APT9o3n/ILeaXVsiSFTbZpTJCJwQ/Crczfn3DmfQFwxYusWFug==", "dev": true, + "license": "MIT", "dependencies": { "klona": "^2.0.4" }, @@ -12620,9 +11171,8 @@ }, "node_modules/less/node_modules/source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "optional": true, "peer": true, "engines": { @@ -12631,9 +11181,8 @@ }, "node_modules/levn": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -12644,9 +11193,8 @@ }, "node_modules/license-webpack-plugin": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", - "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==", "dev": true, + "license": "ISC", "dependencies": { "webpack-sources": "^3.0.0" }, @@ -12661,42 +11209,37 @@ }, "node_modules/lie": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", "dev": true, + "license": "MIT", "dependencies": { "immediate": "~3.0.5" } }, "node_modules/lines-and-columns": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/loader-runner": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.11.5" } }, "node_modules/loader-utils": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", - "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 12.13.0" } }, "node_modules/locate-path": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -12706,31 +11249,26 @@ }, "node_modules/lodash": { "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash-es": { "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + "license": "MIT" }, "node_modules/lodash.debounce": { "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.merge": { "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/log-symbols": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "license": "MIT", "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" @@ -12744,8 +11282,7 @@ }, "node_modules/log-symbols/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -12758,8 +11295,7 @@ }, "node_modules/log-symbols/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -12773,8 +11309,7 @@ }, "node_modules/log-symbols/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -12784,16 +11319,14 @@ }, "node_modules/log-symbols/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/log-symbols/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -12803,9 +11336,8 @@ }, "node_modules/log4js": { "version": "6.9.1", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.9.1.tgz", - "integrity": "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==", "dev": true, + "license": "Apache-2.0", "dependencies": { "date-format": "^4.0.14", "debug": "^4.3.4", @@ -12819,18 +11351,16 @@ }, "node_modules/lru-cache": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^3.0.2" } }, "node_modules/magic-string": { "version": "0.30.1", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.1.tgz", - "integrity": "sha512-mbVKXPmS0z0G4XqFDCTllmDQ6coZzn94aMlb0o/A4HEHJCKcanlDZwYJgwnkmgD3jyWhUgj9VsPrfd972yPffA==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" }, @@ -12840,9 +11370,8 @@ }, "node_modules/make-dir": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", "dev": true, + "license": "MIT", "dependencies": { "pify": "^4.0.1", "semver": "^5.6.0" @@ -12853,24 +11382,21 @@ }, "node_modules/make-dir/node_modules/semver": { "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" } }, "node_modules/make-error": { "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/make-fetch-happen": { "version": "10.2.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", - "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", "dev": true, + "license": "ISC", "dependencies": { "agentkeepalive": "^4.2.1", "cacache": "^16.1.0", @@ -12895,9 +11421,8 @@ }, "node_modules/make-fetch-happen/node_modules/@npmcli/fs": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", - "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", "dev": true, + "license": "ISC", "dependencies": { "@gar/promisify": "^1.1.3", "semver": "^7.3.5" @@ -12908,27 +11433,24 @@ }, "node_modules/make-fetch-happen/node_modules/@tootallnate/once": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10" } }, "node_modules/make-fetch-happen/node_modules/brace-expansion": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/make-fetch-happen/node_modules/cacache": { "version": "16.1.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", - "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", "dev": true, + "license": "ISC", "dependencies": { "@npmcli/fs": "^2.1.0", "@npmcli/move-file": "^2.0.0", @@ -12955,9 +11477,8 @@ }, "node_modules/make-fetch-happen/node_modules/fs-minipass": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", "dev": true, + "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -12967,9 +11488,8 @@ }, "node_modules/make-fetch-happen/node_modules/glob": { "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -12986,9 +11506,8 @@ }, "node_modules/make-fetch-happen/node_modules/http-proxy-agent": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", "dev": true, + "license": "MIT", "dependencies": { "@tootallnate/once": "2", "agent-base": "6", @@ -13000,18 +11519,16 @@ }, "node_modules/make-fetch-happen/node_modules/lru-cache": { "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "dev": true, + "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/make-fetch-happen/node_modules/minimatch": { "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -13021,9 +11538,8 @@ }, "node_modules/make-fetch-happen/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -13033,9 +11549,8 @@ }, "node_modules/make-fetch-happen/node_modules/ssri": { "version": "9.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", - "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", "dev": true, + "license": "ISC", "dependencies": { "minipass": "^3.1.1" }, @@ -13045,9 +11560,8 @@ }, "node_modules/make-fetch-happen/node_modules/unique-filename": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", - "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", "dev": true, + "license": "ISC", "dependencies": { "unique-slug": "^3.0.0" }, @@ -13057,9 +11571,8 @@ }, "node_modules/make-fetch-happen/node_modules/unique-slug": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", - "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", "dev": true, + "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4" }, @@ -13069,24 +11582,21 @@ }, "node_modules/make-fetch-happen/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/media-typer": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/memfs": { "version": "3.5.3", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", - "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", "dev": true, + "license": "Unlicense", "dependencies": { "fs-monkey": "^1.0.4" }, @@ -13096,39 +11606,34 @@ }, "node_modules/merge-descriptors": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/merge-stream": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/merge2": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/methods": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/micromatch": { "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, + "license": "MIT", "dependencies": { "braces": "^3.0.2", "picomatch": "^2.3.1" @@ -13139,9 +11644,8 @@ }, "node_modules/mime": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, + "license": "MIT", "bin": { "mime": "cli.js" }, @@ -13151,18 +11655,16 @@ }, "node_modules/mime-db": { "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, + "license": "MIT", "dependencies": { "mime-db": "1.52.0" }, @@ -13172,17 +11674,15 @@ }, "node_modules/mimic-fn": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/mini-css-extract-plugin": { "version": "2.7.6", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.6.tgz", - "integrity": "sha512-Qk7HcgaPkGG6eD77mLvZS1nmxlao3j+9PkrT9Uc7HAE1id3F41+DdBRYRYkbyfNRGzm8/YWtzhw7nVPmwhqTQw==", "dev": true, + "license": "MIT", "dependencies": { "schema-utils": "^4.0.0" }, @@ -13199,15 +11699,13 @@ }, "node_modules/minimalistic-assert": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/minimatch": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -13217,27 +11715,24 @@ }, "node_modules/minimist": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/minipass": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "dev": true, + "license": "ISC", "engines": { "node": ">=8" } }, "node_modules/minipass-collect": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", "dev": true, + "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -13247,9 +11742,8 @@ }, "node_modules/minipass-collect/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -13259,15 +11753,13 @@ }, "node_modules/minipass-collect/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/minipass-fetch": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", - "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", "dev": true, + "license": "MIT", "dependencies": { "minipass": "^3.1.6", "minipass-sized": "^1.0.3", @@ -13282,9 +11774,8 @@ }, "node_modules/minipass-fetch/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -13294,15 +11785,13 @@ }, "node_modules/minipass-fetch/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/minipass-flush": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", "dev": true, + "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -13312,9 +11801,8 @@ }, "node_modules/minipass-flush/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -13324,15 +11812,13 @@ }, "node_modules/minipass-flush/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/minipass-json-stream": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", - "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", "dev": true, + "license": "MIT", "dependencies": { "jsonparse": "^1.3.1", "minipass": "^3.0.0" @@ -13340,9 +11826,8 @@ }, "node_modules/minipass-json-stream/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -13352,15 +11837,13 @@ }, "node_modules/minipass-json-stream/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/minipass-pipeline": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", "dev": true, + "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -13370,9 +11853,8 @@ }, "node_modules/minipass-pipeline/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -13382,15 +11864,13 @@ }, "node_modules/minipass-pipeline/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/minipass-sized": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", "dev": true, + "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -13400,9 +11880,8 @@ }, "node_modules/minipass-sized/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -13412,15 +11891,13 @@ }, "node_modules/minipass-sized/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/minizlib": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", "dev": true, + "license": "MIT", "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" @@ -13431,9 +11908,8 @@ }, "node_modules/minizlib/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -13443,15 +11919,13 @@ }, "node_modules/minizlib/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/mkdirp": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true, + "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" }, @@ -13461,24 +11935,21 @@ }, "node_modules/mrmime": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", - "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" } }, "node_modules/ms": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/multicast-dns": { "version": "7.2.5", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", - "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", "dev": true, + "license": "MIT", "dependencies": { "dns-packet": "^5.2.2", "thunky": "^1.0.2" @@ -13489,14 +11960,11 @@ }, "node_modules/mute-stream": { "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/nanoid": { "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "dev": true, "funding": [ { @@ -13504,6 +11972,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -13513,15 +11982,13 @@ }, "node_modules/natural-compare": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/needle": { "version": "3.3.1", - "resolved": "https://registry.npmjs.org/needle/-/needle-3.3.1.tgz", - "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "iconv-lite": "^0.6.3", @@ -13536,23 +12003,20 @@ }, "node_modules/negotiator": { "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/neo-async": { "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/ng2-charts": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ng2-charts/-/ng2-charts-4.1.1.tgz", - "integrity": "sha512-iHwXDbmX86lfeH8VRcsaW2tJATsuAZo4kvvC/Yk2l35zOHjevja1qBvO6BAibiDazi9r9aS6ZRJOqWPsz1pP2w==", + "license": "ISC", "dependencies": { "lodash-es": "^4.17.15", "tslib": "^2.3.0" @@ -13567,8 +12031,7 @@ }, "node_modules/ngx-cookie-service": { "version": "16.1.0", - "resolved": "https://registry.npmjs.org/ngx-cookie-service/-/ngx-cookie-service-16.1.0.tgz", - "integrity": "sha512-FrzMjsGCHZCd2sEucigMaGyzImBL0l6gwWn6jmLBhcNVx0D7P8Yvtgk9aUptlqBrVKy4c2upglSa3Ogv3679bw==", + "license": "MIT", "dependencies": { "tslib": "^2.0.0" }, @@ -13579,8 +12042,7 @@ }, "node_modules/ngx-spinner": { "version": "16.0.2", - "resolved": "https://registry.npmjs.org/ngx-spinner/-/ngx-spinner-16.0.2.tgz", - "integrity": "sha512-MZpOHb3dvSqD6xiEdR+EtOfPY2r1kfA7t5Hv5IVwi7gkbTwVgnqxDWdOYJ/HW1pSZ5iEGhqlJqWg6CysLmNfHQ==", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, @@ -13592,10 +12054,9 @@ }, "node_modules/nice-napi": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", - "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "!win32" @@ -13607,24 +12068,21 @@ }, "node_modules/node-addon-api": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", - "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/node-forge": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", "dev": true, + "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { "node": ">= 6.13.0" } }, "node_modules/node-gyp": { "version": "9.4.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.1.tgz", - "integrity": "sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==", "dev": true, + "license": "MIT", "dependencies": { "env-paths": "^2.2.0", "exponential-backoff": "^3.1.1", @@ -13647,9 +12105,8 @@ }, "node_modules/node-gyp-build": { "version": "4.8.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.0.tgz", - "integrity": "sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==", "dev": true, + "license": "MIT", "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", @@ -13658,9 +12115,8 @@ }, "node_modules/node-gyp/node_modules/glob": { "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -13678,15 +12134,13 @@ }, "node_modules/node-releases": { "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/nopt": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", - "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", "dev": true, + "license": "ISC", "dependencies": { "abbrev": "^1.0.0" }, @@ -13699,9 +12153,8 @@ }, "node_modules/normalize-package-data": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-5.0.0.tgz", - "integrity": "sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "hosted-git-info": "^6.0.0", "is-core-module": "^2.8.1", @@ -13714,27 +12167,24 @@ }, "node_modules/normalize-path": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "devOptional": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/normalize-range": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/npm-bundled": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.0.tgz", - "integrity": "sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ==", "dev": true, + "license": "ISC", "dependencies": { "npm-normalize-package-bin": "^3.0.0" }, @@ -13744,9 +12194,8 @@ }, "node_modules/npm-install-checks": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz", - "integrity": "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "semver": "^7.1.1" }, @@ -13756,18 +12205,16 @@ }, "node_modules/npm-normalize-package-bin": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", - "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", "dev": true, + "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm-package-arg": { "version": "10.1.0", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz", - "integrity": "sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==", "dev": true, + "license": "ISC", "dependencies": { "hosted-git-info": "^6.0.0", "proc-log": "^3.0.0", @@ -13780,9 +12227,8 @@ }, "node_modules/npm-packlist": { "version": "7.0.4", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-7.0.4.tgz", - "integrity": "sha512-d6RGEuRrNS5/N84iglPivjaJPxhDbZmlbTwTDX2IbcRHG5bZCdtysYMhwiPvcF4GisXHGn7xsxv+GQ7T/02M5Q==", "dev": true, + "license": "ISC", "dependencies": { "ignore-walk": "^6.0.0" }, @@ -13792,9 +12238,8 @@ }, "node_modules/npm-pick-manifest": { "version": "8.0.1", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-8.0.1.tgz", - "integrity": "sha512-mRtvlBjTsJvfCCdmPtiu2bdlx8d/KXtF7yNXNWe7G0Z36qWA9Ny5zXsI2PfBZEv7SXgoxTmNaTzGSbbzDZChoA==", "dev": true, + "license": "ISC", "dependencies": { "npm-install-checks": "^6.0.0", "npm-normalize-package-bin": "^3.0.0", @@ -13807,9 +12252,8 @@ }, "node_modules/npm-registry-fetch": { "version": "14.0.5", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-14.0.5.tgz", - "integrity": "sha512-kIDMIo4aBm6xg7jOttupWZamsZRkAqMqwqqbVXnUqstY5+tapvv6bkH/qMR76jdgV+YljEUCyWx3hRYMrJiAgA==", "dev": true, + "license": "ISC", "dependencies": { "make-fetch-happen": "^11.0.0", "minipass": "^5.0.0", @@ -13825,18 +12269,16 @@ }, "node_modules/npm-registry-fetch/node_modules/@tootallnate/once": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10" } }, "node_modules/npm-registry-fetch/node_modules/http-proxy-agent": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", "dev": true, + "license": "MIT", "dependencies": { "@tootallnate/once": "2", "agent-base": "6", @@ -13848,18 +12290,16 @@ }, "node_modules/npm-registry-fetch/node_modules/lru-cache": { "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "dev": true, + "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/npm-registry-fetch/node_modules/make-fetch-happen": { "version": "11.1.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", - "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", "dev": true, + "license": "ISC", "dependencies": { "agentkeepalive": "^4.2.1", "cacache": "^17.0.0", @@ -13883,9 +12323,8 @@ }, "node_modules/npm-registry-fetch/node_modules/minipass-fetch": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", - "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", "dev": true, + "license": "MIT", "dependencies": { "minipass": "^7.0.3", "minipass-sized": "^1.0.3", @@ -13900,18 +12339,16 @@ }, "node_modules/npm-registry-fetch/node_modules/minipass-fetch/node_modules/minipass": { "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", "dev": true, + "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } }, "node_modules/npm-run-path": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.0.0" }, @@ -13921,9 +12358,8 @@ }, "node_modules/npmlog": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", - "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", "dev": true, + "license": "ISC", "dependencies": { "are-we-there-yet": "^3.0.0", "console-control-strings": "^1.1.0", @@ -13936,9 +12372,8 @@ }, "node_modules/nth-check": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0" }, @@ -13948,16 +12383,14 @@ }, "node_modules/nwsapi": { "version": "2.2.7", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", - "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/nx": { "version": "16.5.1", - "resolved": "https://registry.npmjs.org/nx/-/nx-16.5.1.tgz", - "integrity": "sha512-I3hJRE4hG7JWAtncWwDEO3GVeGPpN0TtM8xH5ArZXyDuVeTth/i3TtJzdDzqXO1HHtIoAQN0xeq4n9cLuMil5g==", "dev": true, "hasInstallScript": true, + "license": "MIT", "dependencies": { "@nrwl/tao": "16.5.1", "@parcel/watcher": "2.0.4", @@ -14024,9 +12457,8 @@ }, "node_modules/nx/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -14039,15 +12471,13 @@ }, "node_modules/nx/node_modules/argparse": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "dev": true, + "license": "Python-2.0" }, "node_modules/nx/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -14061,9 +12491,8 @@ }, "node_modules/nx/node_modules/cli-spinners": { "version": "2.6.1", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", - "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" }, @@ -14073,9 +12502,8 @@ }, "node_modules/nx/node_modules/cliui": { "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", @@ -14084,9 +12512,8 @@ }, "node_modules/nx/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -14096,9 +12523,8 @@ }, "node_modules/nx/node_modules/fast-glob": { "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -14112,9 +12538,8 @@ }, "node_modules/nx/node_modules/fs-extra": { "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", "dev": true, + "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -14126,9 +12551,8 @@ }, "node_modules/nx/node_modules/glob": { "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -14143,18 +12567,16 @@ }, "node_modules/nx/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/nx/node_modules/js-yaml": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -14164,15 +12586,13 @@ }, "node_modules/nx/node_modules/jsonc-parser": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/nx/node_modules/jsonfile": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, + "license": "MIT", "dependencies": { "universalify": "^2.0.0" }, @@ -14182,18 +12602,16 @@ }, "node_modules/nx/node_modules/lines-and-columns": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.4.tgz", - "integrity": "sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==", "dev": true, + "license": "MIT", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, "node_modules/nx/node_modules/lru-cache": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -14203,9 +12621,8 @@ }, "node_modules/nx/node_modules/minimatch": { "version": "3.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -14215,9 +12632,8 @@ }, "node_modules/nx/node_modules/semver": { "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", "dev": true, + "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -14230,9 +12646,8 @@ }, "node_modules/nx/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -14242,18 +12657,16 @@ }, "node_modules/nx/node_modules/tmp": { "version": "0.2.3", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", - "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", "dev": true, + "license": "MIT", "engines": { "node": ">=14.14" } }, "node_modules/nx/node_modules/tsconfig-paths": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", - "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", "dev": true, + "license": "MIT", "dependencies": { "json5": "^2.2.2", "minimist": "^1.2.6", @@ -14265,69 +12678,61 @@ }, "node_modules/nx/node_modules/universalify": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10.0.0" } }, "node_modules/nx/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/oauth-sign": { "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "*" } }, "node_modules/object-assign": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/object-inspect": { "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/object-keys": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/object-path": { "version": "0.11.8", - "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.11.8.tgz", - "integrity": "sha512-YJjNZrlXJFM42wTBn6zgOJVar9KFJvzx6sTWDte8sWZF//cnjl0BxHNpfZx+ZffXX63A9q0b1zsFiBX4g4X5KA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10.12.0" } }, "node_modules/object.assign": { "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.5", "define-properties": "^1.2.1", @@ -14343,9 +12748,8 @@ }, "node_modules/object.fromentries": { "version": "2.0.8", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", - "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -14361,9 +12765,8 @@ }, "node_modules/object.groupby": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", - "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -14375,9 +12778,8 @@ }, "node_modules/object.values": { "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", - "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -14392,15 +12794,13 @@ }, "node_modules/obuf": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/on-finished": { "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dev": true, + "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -14410,26 +12810,23 @@ }, "node_modules/on-headers": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, + "license": "ISC", "dependencies": { "wrappy": "1" } }, "node_modules/onetime": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" }, @@ -14442,9 +12839,8 @@ }, "node_modules/open": { "version": "8.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", - "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", "dev": true, + "license": "MIT", "dependencies": { "define-lazy-prop": "^2.0.0", "is-docker": "^2.1.1", @@ -14459,9 +12855,8 @@ }, "node_modules/optionator": { "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dev": true, + "license": "MIT", "dependencies": { "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", @@ -14476,8 +12871,7 @@ }, "node_modules/ora": { "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "license": "MIT", "dependencies": { "bl": "^4.1.0", "chalk": "^4.1.0", @@ -14498,8 +12892,7 @@ }, "node_modules/ora/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -14512,8 +12905,7 @@ }, "node_modules/ora/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -14527,8 +12919,7 @@ }, "node_modules/ora/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -14538,16 +12929,14 @@ }, "node_modules/ora/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/ora/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -14557,18 +12946,16 @@ }, "node_modules/os-tmpdir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/p-limit": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, + "license": "MIT", "dependencies": { "p-try": "^2.0.0" }, @@ -14581,9 +12968,8 @@ }, "node_modules/p-locate": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, @@ -14593,9 +12979,8 @@ }, "node_modules/p-map": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", "dev": true, + "license": "MIT", "dependencies": { "aggregate-error": "^3.0.0" }, @@ -14608,9 +12993,8 @@ }, "node_modules/p-retry": { "version": "4.6.2", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", - "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/retry": "0.12.0", "retry": "^0.13.1" @@ -14621,27 +13005,24 @@ }, "node_modules/p-retry/node_modules/retry": { "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } }, "node_modules/p-try": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/pacote": { "version": "15.2.0", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.2.0.tgz", - "integrity": "sha512-rJVZeIwHTUta23sIZgEIM62WYwbmGbThdbnkt81ravBplQv+HjyroqnLRNH2+sLJHcGZmLRmhPwACqhfTcOmnA==", "dev": true, + "license": "ISC", "dependencies": { "@npmcli/git": "^4.0.0", "@npmcli/installed-package-contents": "^2.0.1", @@ -14671,15 +13052,13 @@ }, "node_modules/pako": { "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true + "dev": true, + "license": "(MIT AND Zlib)" }, "node_modules/parent-module": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -14689,9 +13068,8 @@ }, "node_modules/parse-json": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -14707,24 +13085,21 @@ }, "node_modules/parse-node-version": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", - "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.10" } }, "node_modules/parse5": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/parse5-html-rewriting-stream": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-7.0.0.tgz", - "integrity": "sha512-mazCyGWkmCRWDI15Zp+UiCqMp/0dgEmkZRvhlsqqKYr4SsVm/TvnSpD9fCvqCA2zoWJcfRym846ejWBBHRiYEg==", "dev": true, + "license": "MIT", "dependencies": { "entities": "^4.3.0", "parse5": "^7.0.0", @@ -14736,9 +13111,8 @@ }, "node_modules/parse5-html-rewriting-stream/node_modules/parse5": { "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", "dev": true, + "license": "MIT", "dependencies": { "entities": "^4.4.0" }, @@ -14748,9 +13122,8 @@ }, "node_modules/parse5-sax-parser": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-7.0.0.tgz", - "integrity": "sha512-5A+v2SNsq8T6/mG3ahcz8ZtQ0OUFTatxPbeidoMB7tkJSGDY3tdfl4MHovtLQHkEn5CGxijNWRQHhRQ6IRpXKg==", "dev": true, + "license": "MIT", "dependencies": { "parse5": "^7.0.0" }, @@ -14760,9 +13133,8 @@ }, "node_modules/parse5-sax-parser/node_modules/parse5": { "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", "dev": true, + "license": "MIT", "dependencies": { "entities": "^4.4.0" }, @@ -14772,57 +13144,50 @@ }, "node_modules/parseurl": { "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/path-exists": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/path-is-inside": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", - "dev": true + "dev": true, + "license": "(WTFPL OR MIT)" }, "node_modules/path-key": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/path-parse": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/path-scurry": { "version": "1.10.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", - "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -14836,45 +13201,39 @@ }, "node_modules/path-scurry/node_modules/lru-cache": { "version": "10.2.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", - "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", "dev": true, + "license": "ISC", "engines": { "node": "14 || >=16.14" } }, "node_modules/path-to-regexp": { "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/path-type": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/performance-now": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/picocolors": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "devOptional": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -14884,27 +13243,24 @@ }, "node_modules/pify": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/pinkie": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/pinkie-promise": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", "dev": true, + "license": "MIT", "dependencies": { "pinkie": "^2.0.0" }, @@ -14914,9 +13270,8 @@ }, "node_modules/piscina": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.0.0.tgz", - "integrity": "sha512-641nAmJS4k4iqpNUqfggqUBUMmlw0ZoM5VZKdQkV2e970Inn3Tk9kroCc1wpsYLD07vCwpys5iY0d3xI/9WkTg==", "dev": true, + "license": "MIT", "dependencies": { "eventemitter-asyncresource": "^1.0.0", "hdr-histogram-js": "^2.0.1", @@ -14928,9 +13283,8 @@ }, "node_modules/pkg-dir": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", - "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", "dev": true, + "license": "MIT", "dependencies": { "find-up": "^6.3.0" }, @@ -14943,9 +13297,8 @@ }, "node_modules/pkg-dir/node_modules/find-up": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", - "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^7.1.0", "path-exists": "^5.0.0" @@ -14959,9 +13312,8 @@ }, "node_modules/pkg-dir/node_modules/locate-path": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", - "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^6.0.0" }, @@ -14974,9 +13326,8 @@ }, "node_modules/pkg-dir/node_modules/p-limit": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", - "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", "dev": true, + "license": "MIT", "dependencies": { "yocto-queue": "^1.0.0" }, @@ -14989,9 +13340,8 @@ }, "node_modules/pkg-dir/node_modules/p-locate": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", - "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^4.0.0" }, @@ -15004,18 +13354,16 @@ }, "node_modules/pkg-dir/node_modules/path-exists": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", - "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", "dev": true, + "license": "MIT", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, "node_modules/pkg-dir/node_modules/yocto-queue": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", - "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", "dev": true, + "license": "MIT", "engines": { "node": ">=12.20" }, @@ -15025,17 +13373,14 @@ }, "node_modules/possible-typed-array-names": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", - "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/postcss": { "version": "8.4.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", - "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", "dev": true, "funding": [ { @@ -15051,6 +13396,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.0.0", @@ -15062,9 +13408,8 @@ }, "node_modules/postcss-loader": { "version": "7.3.3", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.3.3.tgz", - "integrity": "sha512-YgO/yhtevGO/vJePCQmTxiaEwER94LABZN0ZMT4A0vsak9TpO+RvKRs7EmJ8peIlB9xfXCsS7M8LjqncsUZ5HA==", "dev": true, + "license": "MIT", "dependencies": { "cosmiconfig": "^8.2.0", "jiti": "^1.18.2", @@ -15084,9 +13429,8 @@ }, "node_modules/postcss-modules-extract-imports": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", - "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", "dev": true, + "license": "ISC", "engines": { "node": "^10 || ^12 || >= 14" }, @@ -15096,9 +13440,8 @@ }, "node_modules/postcss-modules-local-by-default": { "version": "4.0.5", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", - "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", "dev": true, + "license": "MIT", "dependencies": { "icss-utils": "^5.0.0", "postcss-selector-parser": "^6.0.2", @@ -15113,9 +13456,8 @@ }, "node_modules/postcss-modules-scope": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", - "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", "dev": true, + "license": "ISC", "dependencies": { "postcss-selector-parser": "^6.0.4" }, @@ -15128,9 +13470,8 @@ }, "node_modules/postcss-modules-values": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", "dev": true, + "license": "ISC", "dependencies": { "icss-utils": "^5.0.0" }, @@ -15143,9 +13484,8 @@ }, "node_modules/postcss-selector-parser": { "version": "6.0.16", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz", - "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==", "dev": true, + "license": "MIT", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -15156,24 +13496,21 @@ }, "node_modules/postcss-value-parser": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/prelude-ls": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8.0" } }, "node_modules/pretty-bytes": { "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" }, @@ -15183,30 +13520,26 @@ }, "node_modules/proc-log": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", - "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", "dev": true, + "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/process-nextick-args": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/promise-inflight": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/promise-retry": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", "dev": true, + "license": "MIT", "dependencies": { "err-code": "^2.0.2", "retry": "^0.12.0" @@ -15217,10 +13550,8 @@ }, "node_modules/protractor": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/protractor/-/protractor-7.0.0.tgz", - "integrity": "sha512-UqkFjivi4GcvUQYzqGYNe0mLzfn5jiLmO8w9nMhQoJRLhy2grJonpga2IWhI6yJO30LibWXJJtA4MOIZD2GgZw==", - "deprecated": "We have news to share - Protractor is deprecated and will reach end-of-life by Summer 2023. To learn more and find out about other options please refer to this post on the Angular blog. Thank you for using and contributing to Protractor. https://goo.gle/state-of-e2e-in-angular", "dev": true, + "license": "MIT", "dependencies": { "@types/q": "^0.0.32", "@types/selenium-webdriver": "^3.0.0", @@ -15248,27 +13579,24 @@ }, "node_modules/protractor/node_modules/ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/protractor/node_modules/ansi-styles": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/protractor/node_modules/chalk": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", @@ -15282,9 +13610,8 @@ }, "node_modules/protractor/node_modules/cliui": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", @@ -15293,18 +13620,16 @@ }, "node_modules/protractor/node_modules/cliui/node_modules/ansi-regex": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/protractor/node_modules/cliui/node_modules/strip-ansi": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -15314,9 +13639,8 @@ }, "node_modules/protractor/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -15326,9 +13650,8 @@ }, "node_modules/protractor/node_modules/glob": { "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -15346,27 +13669,24 @@ }, "node_modules/protractor/node_modules/source-map": { "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/protractor/node_modules/source-map-support": { "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", "dev": true, + "license": "MIT", "dependencies": { "source-map": "^0.5.6" } }, "node_modules/protractor/node_modules/strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^2.0.0" }, @@ -15376,18 +13696,16 @@ }, "node_modules/protractor/node_modules/supports-color": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.0" } }, "node_modules/protractor/node_modules/wrap-ansi": { "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -15399,18 +13717,16 @@ }, "node_modules/protractor/node_modules/wrap-ansi/node_modules/ansi-regex": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/protractor/node_modules/wrap-ansi/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -15423,9 +13739,8 @@ }, "node_modules/protractor/node_modules/wrap-ansi/node_modules/strip-ansi": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -15435,15 +13750,13 @@ }, "node_modules/protractor/node_modules/y18n": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/protractor/node_modules/yargs": { "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "dev": true, + "license": "MIT", "dependencies": { "cliui": "^6.0.0", "decamelize": "^1.2.0", @@ -15463,9 +13776,8 @@ }, "node_modules/protractor/node_modules/yargs-parser": { "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "dev": true, + "license": "ISC", "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" @@ -15476,9 +13788,8 @@ }, "node_modules/proxy-addr": { "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "dev": true, + "license": "MIT", "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -15489,37 +13800,32 @@ }, "node_modules/proxy-addr/node_modules/ipaddr.js": { "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.10" } }, "node_modules/proxy-from-env": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/prr": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", "dev": true, + "license": "MIT", "optional": true }, "node_modules/psl": { "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/pump": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, + "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -15527,17 +13833,15 @@ }, "node_modules/punycode": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/q": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", - "integrity": "sha512-/CdEdaw49VZVmyIDGUQKDDT53c7qBkO6g5CefWz91Ae+l4+cRtcDYwMTXh6me4O8TMldeGHG3N2Bl84V78Ywbg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.6.0", "teleport": ">=0.2.0" @@ -15545,18 +13849,16 @@ }, "node_modules/qjobs": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", - "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.9" } }, "node_modules/qs": { "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.0.4" }, @@ -15569,14 +13871,11 @@ }, "node_modules/querystringify": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/queue-microtask": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true, "funding": [ { @@ -15591,31 +13890,29 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/randombytes": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "^5.1.0" } }, "node_modules/range-parser": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/raw-body": { "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dev": true, + "license": "MIT", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -15628,18 +13925,16 @@ }, "node_modules/raw-body/node_modules/bytes": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/raw-body/node_modules/iconv-lite": { "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -15649,9 +13944,8 @@ }, "node_modules/read-package-json": { "version": "6.0.4", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-6.0.4.tgz", - "integrity": "sha512-AEtWXYfopBj2z5N5PbkAOeNHRPUg5q+Nen7QLxV8M2zJq1ym6/lCz3fYNTCXe19puu2d06jfHhrP7v/S2PtMMw==", "dev": true, + "license": "ISC", "dependencies": { "glob": "^10.2.2", "json-parse-even-better-errors": "^3.0.0", @@ -15664,9 +13958,8 @@ }, "node_modules/read-package-json-fast": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", - "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", "dev": true, + "license": "ISC", "dependencies": { "json-parse-even-better-errors": "^3.0.0", "npm-normalize-package-bin": "^3.0.0" @@ -15677,26 +13970,23 @@ }, "node_modules/read-package-json-fast/node_modules/json-parse-even-better-errors": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", - "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", "dev": true, + "license": "MIT", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/read-package-json/node_modules/json-parse-even-better-errors": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", - "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", "dev": true, + "license": "MIT", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/readable-stream": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -15708,9 +13998,8 @@ }, "node_modules/readdirp": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "devOptional": true, + "license": "MIT", "dependencies": { "picomatch": "^2.2.1" }, @@ -15720,21 +14009,18 @@ }, "node_modules/reflect-metadata": { "version": "0.1.14", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz", - "integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/regenerate": { "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/regenerate-unicode-properties": { "version": "10.1.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", - "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", "dev": true, + "license": "MIT", "dependencies": { "regenerate": "^1.4.2" }, @@ -15744,29 +14030,25 @@ }, "node_modules/regenerator-runtime": { "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + "license": "MIT" }, "node_modules/regenerator-transform": { "version": "0.15.2", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", - "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/runtime": "^7.8.4" } }, "node_modules/regex-parser": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.3.0.tgz", - "integrity": "sha512-TVILVSz2jY5D47F4mA4MppkBrafEaiUWJO/TcZHEIuI13AqoZMkK1WMA4Om1YkYbTx+9Ki1/tSUXbceyr9saRg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/regexp.prototype.flags": { "version": "1.5.2", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", - "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.6", "define-properties": "^1.2.1", @@ -15782,9 +14064,8 @@ }, "node_modules/regexpu-core": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", - "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/regjsgen": "^0.8.0", "regenerate": "^1.4.2", @@ -15799,9 +14080,8 @@ }, "node_modules/regjsparser": { "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "jsesc": "~0.5.0" }, @@ -15811,8 +14091,6 @@ }, "node_modules/regjsparser/node_modules/jsesc": { "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", "dev": true, "bin": { "jsesc": "bin/jsesc" @@ -15820,10 +14098,8 @@ }, "node_modules/request": { "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", "dev": true, + "license": "Apache-2.0", "dependencies": { "aws-sign2": "~0.7.0", "aws4": "^1.8.0", @@ -15852,9 +14128,8 @@ }, "node_modules/request/node_modules/form-data": { "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "dev": true, + "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", @@ -15866,18 +14141,16 @@ }, "node_modules/request/node_modules/qs": { "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.6" } }, "node_modules/request/node_modules/tough-cookie": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "psl": "^1.1.28", "punycode": "^2.1.1" @@ -15888,48 +14161,41 @@ }, "node_modules/request/node_modules/uuid": { "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", "dev": true, + "license": "MIT", "bin": { "uuid": "bin/uuid" } }, "node_modules/require-directory": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/require-from-string": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/require-main-filename": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/requires-port": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/resolve": { "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, + "license": "MIT", "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -15944,18 +14210,16 @@ }, "node_modules/resolve-from": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/resolve-url-loader": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", - "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", "dev": true, + "license": "MIT", "dependencies": { "adjust-sourcemap-loader": "^4.0.0", "convert-source-map": "^1.7.0", @@ -15969,9 +14233,8 @@ }, "node_modules/resolve-url-loader/node_modules/loader-utils": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, + "license": "MIT", "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -15983,17 +14246,15 @@ }, "node_modules/resolve-url-loader/node_modules/source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/restore-cursor": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "license": "MIT", "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" @@ -16004,18 +14265,16 @@ }, "node_modules/retry": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } }, "node_modules/reusify": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true, + "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -16023,15 +14282,13 @@ }, "node_modules/rfdc": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", - "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/rimraf": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -16044,9 +14301,8 @@ }, "node_modules/rimraf/node_modules/glob": { "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -16064,19 +14320,16 @@ }, "node_modules/roboto-fontface": { "version": "0.10.0", - "resolved": "https://registry.npmjs.org/roboto-fontface/-/roboto-fontface-0.10.0.tgz", - "integrity": "sha512-OlwfYEgA2RdboZohpldlvJ1xngOins5d7ejqnIBWr9KaMxsnBqotpptRXTyfNRLnFpqzX6sTDt+X+a+6udnU8g==" + "license": "Apache-2.0" }, "node_modules/robust-predicates": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", - "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" + "license": "Unlicense" }, "node_modules/rollup": { "version": "3.29.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", - "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", "dev": true, + "license": "MIT", "bin": { "rollup": "dist/bin/rollup" }, @@ -16090,17 +14343,14 @@ }, "node_modules/run-async": { "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } }, "node_modules/run-parallel": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, "funding": [ { @@ -16116,19 +14366,18 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } }, "node_modules/rw": { "version": "1.3.3", - "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" + "license": "BSD-3-Clause" }, "node_modules/rxjs": { "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "license": "Apache-2.0", "dependencies": { "tslib": "^1.9.0" }, @@ -16138,14 +14387,12 @@ }, "node_modules/rxjs/node_modules/tslib": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + "license": "0BSD" }, "node_modules/safe-array-concat": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", - "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "get-intrinsic": "^1.2.4", @@ -16161,14 +14408,11 @@ }, "node_modules/safe-array-concat/node_modules/isarray": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/safe-buffer": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "funding": [ { "type": "github", @@ -16182,13 +14426,13 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/safe-regex-test": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", - "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.6", "es-errors": "^1.3.0", @@ -16203,14 +14447,12 @@ }, "node_modules/safer-buffer": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "license": "MIT" }, "node_modules/sass": { "version": "1.64.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.64.1.tgz", - "integrity": "sha512-16rRACSOFEE8VN7SCgBu1MpYCyN7urj9At898tyzdXFhC+a+yOX5dXwAR7L8/IdPJ1NB8OYoXmD55DM30B2kEQ==", "dev": true, + "license": "MIT", "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -16225,9 +14467,8 @@ }, "node_modules/sass-loader": { "version": "13.3.2", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.2.tgz", - "integrity": "sha512-CQbKl57kdEv+KDLquhC+gE3pXt74LEAzm+tzywcA0/aHZuub8wTErbjAoNI57rPUWRYRNC5WUnNl8eGJNbDdwg==", "dev": true, + "license": "MIT", "dependencies": { "neo-async": "^2.6.2" }, @@ -16262,8 +14503,6 @@ }, "node_modules/saucelabs": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.5.0.tgz", - "integrity": "sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ==", "dev": true, "dependencies": { "https-proxy-agent": "^2.2.1" @@ -16274,9 +14513,8 @@ }, "node_modules/saucelabs/node_modules/agent-base": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", "dev": true, + "license": "MIT", "dependencies": { "es6-promisify": "^5.0.0" }, @@ -16286,18 +14524,16 @@ }, "node_modules/saucelabs/node_modules/debug": { "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.1" } }, "node_modules/saucelabs/node_modules/https-proxy-agent": { "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", "dev": true, + "license": "MIT", "dependencies": { "agent-base": "^4.3.0", "debug": "^3.1.0" @@ -16308,15 +14544,13 @@ }, "node_modules/sax": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", - "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/saxes": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", "dev": true, + "license": "ISC", "dependencies": { "xmlchars": "^2.2.0" }, @@ -16326,9 +14560,8 @@ }, "node_modules/schema-utils": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", - "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", "dev": true, + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.9", "ajv": "^8.9.0", @@ -16345,15 +14578,13 @@ }, "node_modules/select-hose": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/selenium-webdriver": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz", - "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==", "dev": true, + "license": "Apache-2.0", "dependencies": { "jszip": "^3.1.3", "rimraf": "^2.5.4", @@ -16366,9 +14597,8 @@ }, "node_modules/selenium-webdriver/node_modules/glob": { "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -16386,9 +14616,8 @@ }, "node_modules/selenium-webdriver/node_modules/rimraf": { "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "dev": true, + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -16398,9 +14627,8 @@ }, "node_modules/selenium-webdriver/node_modules/tmp": { "version": "0.0.30", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", - "integrity": "sha512-HXdTB7lvMwcb55XFfrTM8CPr/IYREk4hVBFaQ4b/6nInrluSL86hfHm7vu0luYKCfyBZp2trCjpc8caC3vVM3w==", "dev": true, + "license": "MIT", "dependencies": { "os-tmpdir": "~1.0.1" }, @@ -16410,9 +14638,8 @@ }, "node_modules/selfsigned": { "version": "2.4.1", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", - "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", "dev": true, + "license": "MIT", "dependencies": { "@types/node-forge": "^1.3.0", "node-forge": "^1" @@ -16423,9 +14650,8 @@ }, "node_modules/semver": { "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "dev": true, + "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -16438,9 +14664,8 @@ }, "node_modules/semver/node_modules/lru-cache": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -16450,15 +14675,13 @@ }, "node_modules/semver/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/send": { "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "dev": true, + "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -16480,39 +14703,34 @@ }, "node_modules/send/node_modules/debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/send/node_modules/debug/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/send/node_modules/ms": { "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/serialize-javascript": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "randombytes": "^2.1.0" } }, "node_modules/serve-index": { "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", "dev": true, + "license": "MIT", "dependencies": { "accepts": "~1.3.4", "batch": "0.6.1", @@ -16528,27 +14746,24 @@ }, "node_modules/serve-index/node_modules/debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/serve-index/node_modules/depd": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/serve-index/node_modules/http-errors": { "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", "dev": true, + "license": "MIT", "dependencies": { "depd": "~1.1.2", "inherits": "2.0.3", @@ -16561,36 +14776,31 @@ }, "node_modules/serve-index/node_modules/inherits": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/serve-index/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/serve-index/node_modules/setprototypeof": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/serve-index/node_modules/statuses": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/serve-static": { "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "dev": true, + "license": "MIT", "dependencies": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", @@ -16603,15 +14813,13 @@ }, "node_modules/set-blocking": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/set-function-length": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dev": true, + "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -16626,9 +14834,8 @@ }, "node_modules/set-function-name": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "dev": true, + "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -16641,21 +14848,18 @@ }, "node_modules/setimmediate": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/setprototypeof": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/shallow-clone": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", "dev": true, + "license": "MIT", "dependencies": { "kind-of": "^6.0.2" }, @@ -16665,9 +14869,8 @@ }, "node_modules/shebang-command": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -16677,27 +14880,24 @@ }, "node_modules/shebang-regex": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/shell-quote": { "version": "1.8.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", - "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/side-channel": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -16709,14 +14909,12 @@ }, "node_modules/signal-exit": { "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + "license": "ISC" }, "node_modules/sigstore": { "version": "1.9.0", - "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-1.9.0.tgz", - "integrity": "sha512-0Zjz0oe37d08VeOtBIuB6cRriqXse2e8w+7yIy2XSXjshRKxbc2KkhXjL229jXSxEm7UbcjS76wcJDGQddVI9A==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@sigstore/bundle": "^1.1.0", "@sigstore/protobuf-specs": "^0.2.0", @@ -16733,18 +14931,16 @@ }, "node_modules/sigstore/node_modules/@tootallnate/once": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10" } }, "node_modules/sigstore/node_modules/http-proxy-agent": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", "dev": true, + "license": "MIT", "dependencies": { "@tootallnate/once": "2", "agent-base": "6", @@ -16756,18 +14952,16 @@ }, "node_modules/sigstore/node_modules/lru-cache": { "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "dev": true, + "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/sigstore/node_modules/make-fetch-happen": { "version": "11.1.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", - "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", "dev": true, + "license": "ISC", "dependencies": { "agentkeepalive": "^4.2.1", "cacache": "^17.0.0", @@ -16791,9 +14985,8 @@ }, "node_modules/sigstore/node_modules/minipass-fetch": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", - "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", "dev": true, + "license": "MIT", "dependencies": { "minipass": "^7.0.3", "minipass-sized": "^1.0.3", @@ -16808,18 +15001,16 @@ }, "node_modules/sigstore/node_modules/minipass-fetch/node_modules/minipass": { "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", "dev": true, + "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } }, "node_modules/slash": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -16829,9 +15020,8 @@ }, "node_modules/smart-buffer": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6.0.0", "npm": ">= 3.0.0" @@ -16839,9 +15029,8 @@ }, "node_modules/socket.io": { "version": "4.7.3", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.3.tgz", - "integrity": "sha512-SE+UIQXBQE+GPG2oszWMlsEmWtHVqw/h1VrYJGK5/MC7CH5p58N448HwIrtREcvR4jfdOJAY4ieQfxMr55qbbw==", "dev": true, + "license": "MIT", "dependencies": { "accepts": "~1.3.4", "base64id": "~2.0.0", @@ -16857,18 +15046,16 @@ }, "node_modules/socket.io-adapter": { "version": "2.5.2", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz", - "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==", "dev": true, + "license": "MIT", "dependencies": { "ws": "~8.11.0" } }, "node_modules/socket.io-adapter/node_modules/ws": { "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", - "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -16887,9 +15074,8 @@ }, "node_modules/socket.io-parser": { "version": "4.2.4", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", - "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", "dev": true, + "license": "MIT", "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" @@ -16900,9 +15086,8 @@ }, "node_modules/sockjs": { "version": "0.3.24", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", - "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", "dev": true, + "license": "MIT", "dependencies": { "faye-websocket": "^0.11.3", "uuid": "^8.3.2", @@ -16911,18 +15096,16 @@ }, "node_modules/sockjs/node_modules/uuid": { "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true, + "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } }, "node_modules/socks": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.1.tgz", - "integrity": "sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ==", "dev": true, + "license": "MIT", "dependencies": { "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" @@ -16934,9 +15117,8 @@ }, "node_modules/socks-proxy-agent": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", - "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", "dev": true, + "license": "MIT", "dependencies": { "agent-base": "^6.0.2", "debug": "^4.3.3", @@ -16948,27 +15130,24 @@ }, "node_modules/source-map": { "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">= 8" } }, "node_modules/source-map-js": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/source-map-loader": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-4.0.1.tgz", - "integrity": "sha512-oqXpzDIByKONVY8g1NUPOTQhe0UTU5bWUl32GSkqK2LjJj0HmwTMVKxcUip0RgAYhY1mqgOxjbQM48a0mmeNfA==", "dev": true, + "license": "MIT", "dependencies": { "abab": "^2.0.6", "iconv-lite": "^0.6.3", @@ -16987,9 +15166,8 @@ }, "node_modules/source-map-support": { "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -16997,24 +15175,20 @@ }, "node_modules/source-map-support/node_modules/source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/sourcemap-codec": { "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "deprecated": "Please use @jridgewell/sourcemap-codec instead" + "license": "MIT" }, "node_modules/spdx-correct": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" @@ -17022,15 +15196,13 @@ }, "node_modules/spdx-exceptions": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true + "dev": true, + "license": "CC-BY-3.0" }, "node_modules/spdx-expression-parse": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, + "license": "MIT", "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -17038,15 +15210,13 @@ }, "node_modules/spdx-license-ids": { "version": "3.0.16", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", - "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", - "dev": true + "dev": true, + "license": "CC0-1.0" }, "node_modules/spdy": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^4.1.0", "handle-thing": "^2.0.0", @@ -17060,9 +15230,8 @@ }, "node_modules/spdy-transport": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^4.1.0", "detect-node": "^2.0.4", @@ -17074,15 +15243,13 @@ }, "node_modules/sprintf-js": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/sshpk": { "version": "1.18.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", - "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", "dev": true, + "license": "MIT", "dependencies": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -17105,9 +15272,8 @@ }, "node_modules/ssri": { "version": "10.0.5", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", - "integrity": "sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==", "dev": true, + "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, @@ -17117,27 +15283,24 @@ }, "node_modules/ssri/node_modules/minipass": { "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", "dev": true, + "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } }, "node_modules/statuses": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/streamroller": { "version": "3.1.5", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", - "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==", "dev": true, + "license": "MIT", "dependencies": { "date-format": "^4.0.14", "debug": "^4.3.4", @@ -17149,17 +15312,15 @@ }, "node_modules/string_decoder": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" } }, "node_modules/string-width": { "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -17172,9 +15333,8 @@ "node_modules/string-width-cjs": { "name": "string-width", "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -17186,9 +15346,8 @@ }, "node_modules/string.prototype.trim": { "version": "1.2.9", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", - "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -17204,9 +15363,8 @@ }, "node_modules/string.prototype.trimend": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", - "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -17218,9 +15376,8 @@ }, "node_modules/string.prototype.trimstart": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", - "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -17235,8 +15392,7 @@ }, "node_modules/strip-ansi": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -17247,9 +15403,8 @@ "node_modules/strip-ansi-cjs": { "name": "strip-ansi", "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -17259,27 +15414,24 @@ }, "node_modules/strip-bom": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/strip-final-newline": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/strip-json-comments": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -17289,9 +15441,8 @@ }, "node_modules/strong-log-transformer": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz", - "integrity": "sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "duplexer": "^0.1.1", "minimist": "^1.2.0", @@ -17306,9 +15457,8 @@ }, "node_modules/supports-color": { "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -17318,9 +15468,8 @@ }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -17330,8 +15479,6 @@ }, "node_modules/swiper": { "version": "11.1.1", - "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.1.1.tgz", - "integrity": "sha512-jGmEA/fNz1lACIcY4/40ggm1Gcyv+EUivmgV/Jd2WFPsEJhbWXnRAwzZR8OPjkBLtDxmzcoYG/iiAMWfRs0YKQ==", "funding": [ { "type": "patreon", @@ -17342,39 +15489,36 @@ "url": "http://opencollective.com/swiper" } ], + "license": "MIT", "engines": { "node": ">= 4.7.0" } }, "node_modules/symbol-observable": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", - "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10" } }, "node_modules/symbol-tree": { "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/tapable": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/tar": { "version": "6.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", "dev": true, + "license": "ISC", "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -17389,9 +15533,8 @@ }, "node_modules/tar-stream": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "dev": true, + "license": "MIT", "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", @@ -17405,9 +15548,8 @@ }, "node_modules/tar/node_modules/fs-minipass": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", "dev": true, + "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -17417,9 +15559,8 @@ }, "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -17429,15 +15570,13 @@ }, "node_modules/tar/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/terser": { "version": "5.29.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.29.1.tgz", - "integrity": "sha512-lZQ/fyaIGxsbGxApKmoPTODIzELy3++mXhS5hOqaAWZjQtpq/hFHAc+rm29NND1rYRxRWKcjuARNwULNXa5RtQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -17453,9 +15592,8 @@ }, "node_modules/terser-webpack-plugin": { "version": "5.3.10", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", - "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.20", "jest-worker": "^27.4.5", @@ -17487,9 +15625,8 @@ }, "node_modules/terser-webpack-plugin/node_modules/ajv": { "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -17503,24 +15640,21 @@ }, "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", "dev": true, + "license": "MIT", "peerDependencies": { "ajv": "^6.9.1" } }, "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/terser-webpack-plugin/node_modules/schema-utils": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dev": true, + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -17536,15 +15670,13 @@ }, "node_modules/terser/node_modules/commander": { "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/test-exclude": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dev": true, + "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", @@ -17556,9 +15688,8 @@ }, "node_modules/test-exclude/node_modules/glob": { "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -17576,27 +15707,23 @@ }, "node_modules/text-table": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/through": { "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/thunky": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/tmp": { "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, + "license": "MIT", "dependencies": { "os-tmpdir": "~1.0.2" }, @@ -17606,18 +15733,16 @@ }, "node_modules/to-fast-properties": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/to-regex-range": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "devOptional": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -17627,18 +15752,16 @@ }, "node_modules/toidentifier": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.6" } }, "node_modules/tough-cookie": { "version": "4.1.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", - "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "psl": "^1.1.33", "punycode": "^2.1.1", @@ -17651,18 +15774,16 @@ }, "node_modules/tough-cookie/node_modules/universalify": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4.0.0" } }, "node_modules/tr46": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", "dev": true, + "license": "MIT", "dependencies": { "punycode": "^2.1.1" }, @@ -17672,18 +15793,16 @@ }, "node_modules/tree-kill": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "dev": true, + "license": "MIT", "bin": { "tree-kill": "cli.js" } }, "node_modules/ts-api-utils": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", - "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", "dev": true, + "license": "MIT", "engines": { "node": ">=16.13.0" }, @@ -17693,9 +15812,8 @@ }, "node_modules/ts-node": { "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, + "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -17736,9 +15854,8 @@ }, "node_modules/tsconfig-paths": { "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, + "license": "MIT", "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", @@ -17748,9 +15865,8 @@ }, "node_modules/tsconfig-paths/node_modules/json5": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, + "license": "MIT", "dependencies": { "minimist": "^1.2.0" }, @@ -17760,14 +15876,12 @@ }, "node_modules/tslib": { "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + "license": "0BSD" }, "node_modules/tsutils": { "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^1.8.1" }, @@ -17780,15 +15894,13 @@ }, "node_modules/tsutils/node_modules/tslib": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "dev": true, + "license": "0BSD" }, "node_modules/tuf-js": { "version": "1.1.7", - "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-1.1.7.tgz", - "integrity": "sha512-i3P9Kgw3ytjELUfpuKVDNBJvk4u5bXL6gskv572mcevPbSKCV3zt3djhmlEQ65yERjIbOSncy7U4cQJaB1CBCg==", "dev": true, + "license": "MIT", "dependencies": { "@tufjs/models": "1.0.4", "debug": "^4.3.4", @@ -17800,18 +15912,16 @@ }, "node_modules/tuf-js/node_modules/@tootallnate/once": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10" } }, "node_modules/tuf-js/node_modules/http-proxy-agent": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", "dev": true, + "license": "MIT", "dependencies": { "@tootallnate/once": "2", "agent-base": "6", @@ -17823,18 +15933,16 @@ }, "node_modules/tuf-js/node_modules/lru-cache": { "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "dev": true, + "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/tuf-js/node_modules/make-fetch-happen": { "version": "11.1.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", - "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", "dev": true, + "license": "ISC", "dependencies": { "agentkeepalive": "^4.2.1", "cacache": "^17.0.0", @@ -17858,9 +15966,8 @@ }, "node_modules/tuf-js/node_modules/minipass-fetch": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", - "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", "dev": true, + "license": "MIT", "dependencies": { "minipass": "^7.0.3", "minipass-sized": "^1.0.3", @@ -17875,18 +15982,16 @@ }, "node_modules/tuf-js/node_modules/minipass-fetch/node_modules/minipass": { "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", "dev": true, + "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } }, "node_modules/tunnel-agent": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, + "license": "Apache-2.0", "dependencies": { "safe-buffer": "^5.0.1" }, @@ -17896,15 +16001,13 @@ }, "node_modules/tweetnacl": { "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true + "dev": true, + "license": "Unlicense" }, "node_modules/type-check": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" }, @@ -17914,9 +16017,8 @@ }, "node_modules/type-fest": { "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -17926,9 +16028,8 @@ }, "node_modules/type-is": { "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "dev": true, + "license": "MIT", "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" @@ -17939,9 +16040,8 @@ }, "node_modules/typed-array-buffer": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", - "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "es-errors": "^1.3.0", @@ -17953,9 +16053,8 @@ }, "node_modules/typed-array-byte-length": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", - "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", @@ -17972,9 +16071,8 @@ }, "node_modules/typed-array-byte-offset": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", - "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", "dev": true, + "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.7", @@ -17992,9 +16090,8 @@ }, "node_modules/typed-array-length": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", - "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", @@ -18012,15 +16109,13 @@ }, "node_modules/typed-assert": { "version": "1.0.9", - "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", - "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/typescript": { "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -18031,9 +16126,8 @@ }, "node_modules/typescript-strict-plugin": { "version": "2.4.1", - "resolved": "https://registry.npmjs.org/typescript-strict-plugin/-/typescript-strict-plugin-2.4.1.tgz", - "integrity": "sha512-LYjh7JLcxAzGQQEmoxzSbJvBSqRvQaFfz984s08tdYCwxrso0HWeeUZto1umu9juousVMmiUBR/dvQMik4ffiw==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^3.0.0", "execa": "^4.0.0", @@ -18048,9 +16142,8 @@ }, "node_modules/typescript-strict-plugin/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -18063,18 +16156,16 @@ }, "node_modules/typescript-strict-plugin/node_modules/brace-expansion": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/typescript-strict-plugin/node_modules/chalk": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -18085,9 +16176,8 @@ }, "node_modules/typescript-strict-plugin/node_modules/cliui": { "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", @@ -18096,9 +16186,8 @@ }, "node_modules/typescript-strict-plugin/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -18108,9 +16197,8 @@ }, "node_modules/typescript-strict-plugin/node_modules/execa": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", "dev": true, + "license": "MIT", "dependencies": { "cross-spawn": "^7.0.0", "get-stream": "^5.0.0", @@ -18131,9 +16219,8 @@ }, "node_modules/typescript-strict-plugin/node_modules/get-stream": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", "dev": true, + "license": "MIT", "dependencies": { "pump": "^3.0.0" }, @@ -18146,27 +16233,24 @@ }, "node_modules/typescript-strict-plugin/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/typescript-strict-plugin/node_modules/human-signals": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=8.12.0" } }, "node_modules/typescript-strict-plugin/node_modules/minimatch": { "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -18179,9 +16263,8 @@ }, "node_modules/typescript-strict-plugin/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -18191,9 +16274,8 @@ }, "node_modules/typescript-strict-plugin/node_modules/yargs": { "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, + "license": "MIT", "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", @@ -18209,17 +16291,14 @@ }, "node_modules/typescript-strict-plugin/node_modules/yargs-parser": { "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } }, "node_modules/ua-parser-js": { "version": "0.7.37", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.37.tgz", - "integrity": "sha512-xV8kqRKM+jhMvcHWUKthV9fNebIzrNy//2O9ZwWcfiBFR5f25XVZPLlEajk/sf3Ra15V92isyQqnIEXRDaZWEA==", "dev": true, "funding": [ { @@ -18235,15 +16314,15 @@ "url": "https://github.com/sponsors/faisalman" } ], + "license": "MIT", "engines": { "node": "*" } }, "node_modules/unbox-primitive": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "has-bigints": "^1.0.2", @@ -18256,24 +16335,21 @@ }, "node_modules/undici-types": { "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/unicode-match-property-ecmascript": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "dev": true, + "license": "MIT", "dependencies": { "unicode-canonical-property-names-ecmascript": "^2.0.0", "unicode-property-aliases-ecmascript": "^2.0.0" @@ -18284,27 +16360,24 @@ }, "node_modules/unicode-match-property-value-ecmascript": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/unicode-property-aliases-ecmascript": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", - "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/unique-filename": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", - "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", "dev": true, + "license": "ISC", "dependencies": { "unique-slug": "^4.0.0" }, @@ -18314,9 +16387,8 @@ }, "node_modules/unique-slug": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", - "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", "dev": true, + "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4" }, @@ -18326,26 +16398,22 @@ }, "node_modules/universalify": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4.0.0" } }, "node_modules/unpipe": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/update-browserslist-db": { "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", "dev": true, "funding": [ { @@ -18361,6 +16429,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "escalade": "^3.1.1", "picocolors": "^1.0.0" @@ -18374,17 +16443,15 @@ }, "node_modules/uri-js": { "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } }, "node_modules/url-parse": { "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "dev": true, + "license": "MIT", "dependencies": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" @@ -18392,47 +16459,41 @@ }, "node_modules/util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + "license": "MIT" }, "node_modules/utils-merge": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4.0" } }, "node_modules/uuid": { "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], + "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } }, "node_modules/v8-compile-cache": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/validate-npm-package-license": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, + "license": "Apache-2.0", "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" @@ -18440,9 +16501,8 @@ }, "node_modules/validate-npm-package-name": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", - "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", "dev": true, + "license": "ISC", "dependencies": { "builtins": "^5.0.0" }, @@ -18452,21 +16512,19 @@ }, "node_modules/vary": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/verror": { "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", "dev": true, "engines": [ "node >=0.6.0" ], + "license": "MIT", "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", @@ -18475,9 +16533,8 @@ }, "node_modules/vite": { "version": "4.5.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz", - "integrity": "sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==", "dev": true, + "license": "MIT", "dependencies": { "esbuild": "^0.18.10", "postcss": "^8.4.27", @@ -18530,28 +16587,24 @@ }, "node_modules/void-elements": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", - "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/w3c-hr-time": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "deprecated": "Use your platform's native performance.now() and performance.timeOrigin.", "dev": true, + "license": "MIT", "dependencies": { "browser-process-hrtime": "^1.0.0" } }, "node_modules/w3c-xmlserializer": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", "dev": true, + "license": "MIT", "dependencies": { "xml-name-validator": "^3.0.0" }, @@ -18561,9 +16614,8 @@ }, "node_modules/watchpack": { "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", "dev": true, + "license": "MIT", "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" @@ -18574,26 +16626,23 @@ }, "node_modules/wbuf": { "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", "dev": true, + "license": "MIT", "dependencies": { "minimalistic-assert": "^1.0.0" } }, "node_modules/wcwidth": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "license": "MIT", "dependencies": { "defaults": "^1.0.3" } }, "node_modules/webdriver-js-extender": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz", - "integrity": "sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/selenium-webdriver": "^3.0.0", "selenium-webdriver": "^3.0.1" @@ -18604,9 +16653,8 @@ }, "node_modules/webdriver-manager": { "version": "12.1.9", - "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.1.9.tgz", - "integrity": "sha512-Yl113uKm8z4m/KMUVWHq1Sjtla2uxEBtx2Ue3AmIlnlPAKloDn/Lvmy6pqWCUersVISpdMeVpAaGbNnvMuT2LQ==", "dev": true, + "license": "MIT", "dependencies": { "adm-zip": "^0.5.2", "chalk": "^1.1.1", @@ -18629,27 +16677,24 @@ }, "node_modules/webdriver-manager/node_modules/ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/webdriver-manager/node_modules/ansi-styles": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/webdriver-manager/node_modules/chalk": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", @@ -18663,9 +16708,8 @@ }, "node_modules/webdriver-manager/node_modules/glob": { "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -18683,15 +16727,13 @@ }, "node_modules/webdriver-manager/node_modules/ini": { "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/webdriver-manager/node_modules/rimraf": { "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "dev": true, + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -18701,18 +16743,16 @@ }, "node_modules/webdriver-manager/node_modules/semver": { "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" } }, "node_modules/webdriver-manager/node_modules/strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^2.0.0" }, @@ -18722,27 +16762,24 @@ }, "node_modules/webdriver-manager/node_modules/supports-color": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.0" } }, "node_modules/webidl-conversions": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=10.4" } }, "node_modules/webpack": { "version": "5.90.3", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.3.tgz", - "integrity": "sha512-h6uDYlWCctQRuXBs1oYpVe6sFcWedl0dpcVaTf/YF67J9bKvwJajFulMVSYKHrksMB3I/pIagRzDxwxkebuzKA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.3", @@ -18788,9 +16825,8 @@ }, "node_modules/webpack-dev-middleware": { "version": "6.1.2", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.1.2.tgz", - "integrity": "sha512-Wu+EHmX326YPYUpQLKmKbTyZZJIB8/n6R09pTmB03kJmnMsVPTo9COzHZFr01txwaCAuZvfBJE4ZCHRcKs5JaQ==", "dev": true, + "license": "MIT", "dependencies": { "colorette": "^2.0.10", "memfs": "^3.4.12", @@ -18816,9 +16852,8 @@ }, "node_modules/webpack-dev-server": { "version": "4.15.1", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", - "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", "dev": true, + "license": "MIT", "dependencies": { "@types/bonjour": "^3.5.9", "@types/connect-history-api-fallback": "^1.3.5", @@ -18875,9 +16910,8 @@ }, "node_modules/webpack-dev-server/node_modules/webpack-dev-middleware": { "version": "5.3.4", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", - "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", "dev": true, + "license": "MIT", "dependencies": { "colorette": "^2.0.10", "memfs": "^3.4.3", @@ -18898,9 +16932,8 @@ }, "node_modules/webpack-dev-server/node_modules/ws": { "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", - "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -18919,9 +16952,8 @@ }, "node_modules/webpack-merge": { "version": "5.9.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.9.0.tgz", - "integrity": "sha512-6NbRQw4+Sy50vYNTw7EyOn41OZItPiXB8GNv3INSoe3PSFaHJEz3SHTrYVaRm2LilNGnFUzh0FAwqPEmU/CwDg==", "dev": true, + "license": "MIT", "dependencies": { "clone-deep": "^4.0.1", "wildcard": "^2.0.0" @@ -18932,18 +16964,16 @@ }, "node_modules/webpack-sources": { "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.13.0" } }, "node_modules/webpack-subresource-integrity": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz", - "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==", "dev": true, + "license": "MIT", "dependencies": { "typed-assert": "^1.0.8" }, @@ -18962,9 +16992,8 @@ }, "node_modules/webpack/node_modules/ajv": { "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", @@ -18979,9 +17008,8 @@ }, "node_modules/webpack/node_modules/ajv-keywords": { "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", "dev": true, + "license": "MIT", "peer": true, "peerDependencies": { "ajv": "^6.9.1" @@ -18989,16 +17017,14 @@ }, "node_modules/webpack/node_modules/json-schema-traverse": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/webpack/node_modules/schema-utils": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "@types/json-schema": "^7.0.8", @@ -19015,9 +17041,8 @@ }, "node_modules/websocket-driver": { "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", @@ -19029,27 +17054,24 @@ }, "node_modules/websocket-extensions": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=0.8.0" } }, "node_modules/whatwg-encoding": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", "dev": true, + "license": "MIT", "dependencies": { "iconv-lite": "0.4.24" } }, "node_modules/whatwg-encoding/node_modules/iconv-lite": { "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -19059,15 +17081,13 @@ }, "node_modules/whatwg-mimetype": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/whatwg-url": { "version": "8.7.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", "dev": true, + "license": "MIT", "dependencies": { "lodash": "^4.7.0", "tr46": "^2.1.0", @@ -19079,9 +17099,8 @@ }, "node_modules/which": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -19094,9 +17113,8 @@ }, "node_modules/which-boxed-primitive": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", "dev": true, + "license": "MIT", "dependencies": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", @@ -19110,15 +17128,13 @@ }, "node_modules/which-module": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", - "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/which-typed-array": { "version": "1.1.15", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", - "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", "dev": true, + "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.7", @@ -19135,24 +17151,21 @@ }, "node_modules/wide-align": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" } }, "node_modules/wildcard": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", - "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/wrap-ansi": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -19168,9 +17181,8 @@ "node_modules/wrap-ansi-cjs": { "name": "wrap-ansi", "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -19185,9 +17197,8 @@ }, "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -19200,9 +17211,8 @@ }, "node_modules/wrap-ansi-cjs/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -19212,9 +17222,8 @@ }, "node_modules/wrap-ansi/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -19227,9 +17236,8 @@ }, "node_modules/wrap-ansi/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -19239,15 +17247,13 @@ }, "node_modules/wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/ws": { "version": "7.5.9", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.3.0" }, @@ -19266,15 +17272,13 @@ }, "node_modules/xml-name-validator": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/xml2js": { "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", "dev": true, + "license": "MIT", "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" @@ -19285,39 +17289,34 @@ }, "node_modules/xmlbuilder": { "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4.0" } }, "node_modules/xmlchars": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/y18n": { "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } }, "node_modules/yallist": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/yargs": { "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, + "license": "MIT", "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -19333,27 +17332,24 @@ }, "node_modules/yargs-parser": { "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, + "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/yn": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/yocto-queue": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -19363,8 +17359,7 @@ }, "node_modules/zone.js": { "version": "0.13.3", - "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.13.3.tgz", - "integrity": "sha512-MKPbmZie6fASC/ps4dkmIhaT5eonHkEt6eAy80K42tAm0G2W+AahLJjbfi6X9NPdciOE9GRFTTM8u2IiF6O3ww==", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" } From 021e67494933fe69c3eeddb88030c84509c05f26 Mon Sep 17 00:00:00 2001 From: Hannes Date: Mon, 29 Apr 2024 23:52:49 +0200 Subject: [PATCH 007/173] Implement new Shelly Plus Plug S (#2529) --- .../bridge/http/dummy/DummyBridgeHttp.java | 37 ++- .../http/dummy/DummyBridgeHttpFactory.java | 13 +- .../common/test/AbstractComponentTest.java | 11 + io.openems.edge.io.shelly/readme.adoc | 9 +- .../openems/edge/io/shelly/common/Utils.java | 29 +++ .../io/shelly/shelly25/IoShelly25Impl.java | 1 - .../{common => shelly25}/ShellyApi.java | 3 +- .../io/shelly/shelly3em/IoShelly3EmImpl.java | 13 +- .../shelly/shellyplug/IoShellyPlugImpl.java | 13 +- .../io/shelly/shellyplusplugs/Config.java | 33 +++ .../shellyplusplugs/IoShellyPlusPlugs.java | 144 +++++++++++ .../IoShellyPlusPlugsImpl.java | 237 ++++++++++++++++++ .../shellyplusplugs/IoShellyPlugImplTest.java | 88 +++++++ .../io/shelly/shellyplusplugs/MyConfig.java | 75 ++++++ .../edge/meter/api/SinglePhaseMeter.java | 84 +++++++ 15 files changed, 754 insertions(+), 36 deletions(-) create mode 100644 io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/common/Utils.java rename io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/{common => shelly25}/ShellyApi.java (97%) create mode 100644 io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplusplugs/Config.java create mode 100644 io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlusPlugs.java create mode 100644 io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlusPlugsImpl.java create mode 100644 io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlugImplTest.java create mode 100644 io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplusplugs/MyConfig.java diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttp.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttp.java index 7a5e3af2b5c..5abccd97132 100644 --- a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttp.java +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttp.java @@ -1,27 +1,52 @@ package io.openems.edge.bridge.http.dummy; +import static java.util.concurrent.CompletableFuture.completedFuture; + +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.CompletableFuture; import io.openems.edge.bridge.http.api.BridgeHttp; public class DummyBridgeHttp implements BridgeHttp { + public final List cycleEndpoints = new ArrayList<>(); + public final List timeEndpoints = new ArrayList<>(); + + private String nextRequestResult = null; + @Override public void subscribeCycle(CycleEndpoint endpoint) { - // TODO Auto-generated method stub - + this.cycleEndpoints.add(endpoint); } @Override public void subscribeTime(TimeEndpoint endpoint) { - // TODO Auto-generated method stub - + this.timeEndpoints.add(endpoint); } @Override public CompletableFuture request(Endpoint endpoint) { - // TODO Auto-generated method stub - return null; + return completedFuture(this.nextRequestResult); + } + + /** + * Mocks a result for all {@link CycleEndpoint}s. + * + * @param result the mocked read result + */ + public void mockCycleResult(String result) { + this.cycleEndpoints.forEach(// + e -> e.result().accept(result)); + } + + /** + * Mocks a result for simple request {@link Endpoint}. + * + * @param nextRequestResult the mocked read result + */ + public void mockRequestResult(String nextRequestResult) { + this.nextRequestResult = nextRequestResult; } } diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpFactory.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpFactory.java index d8a4d19c59a..f19ec95eca8 100644 --- a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpFactory.java +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpFactory.java @@ -11,16 +11,25 @@ public class DummyBridgeHttpFactory extends BridgeHttpFactory { + public final DummyBridgeHttp bridge = new DummyBridgeHttp(); + public DummyBridgeHttpFactory() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { super(); - ReflectionUtils.setAttribute(BridgeHttpFactory.class, this, "csoBridgeHttp", new DummyBridgeHttpCso()); + ReflectionUtils.setAttribute(BridgeHttpFactory.class, this, "csoBridgeHttp", + new DummyBridgeHttpCso(this.bridge)); } private static class DummyBridgeHttpCso implements ComponentServiceObjects { + private final DummyBridgeHttp bridge; + + public DummyBridgeHttpCso(DummyBridgeHttp bridge) { + this.bridge = bridge; + } + @Override public BridgeHttp getService() { - return new DummyBridgeHttp(); + return this.bridge; } @Override diff --git a/io.openems.edge.common/src/io/openems/edge/common/test/AbstractComponentTest.java b/io.openems.edge.common/src/io/openems/edge/common/test/AbstractComponentTest.java index 03bccc75aa1..df40330b7c2 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/test/AbstractComponentTest.java +++ b/io.openems.edge.common/src/io/openems/edge/common/test/AbstractComponentTest.java @@ -528,6 +528,17 @@ public SELF activate(AbstractComponentConfig config) throws Exception { return this.self(); } + /** + * Calls the 'deactivate()' method of the 'system-under-test'. + * + * @return itself, to use as a builder + * @throws Exception on error + */ + public SELF deactivate() throws Exception { + this.callDeactivate(); + return this.self(); + } + private int getConfigChangeCount() throws IOException, InvalidSyntaxException { var result = 0; for (Object object : this.references) { diff --git a/io.openems.edge.io.shelly/readme.adoc b/io.openems.edge.io.shelly/readme.adoc index 69c6b6c7d64..16eed94af93 100644 --- a/io.openems.edge.io.shelly/readme.adoc +++ b/io.openems.edge.io.shelly/readme.adoc @@ -3,10 +3,9 @@ This bundle implements Shelly WiFi Relay Switches. Compatible with -- https://shelly.cloud/products/shelly-25-smart-home-automation-relay/[Shelly 2.5] -- https://shelly.cloud/products/shelly-plug-s-smart-home-automation-device/[Shelly Plug S] - -Implemented Natures -- DigitalOutput +- https://www.shelly.com/de/products/shop/1xs25[Shelly 2.5] +- https://www.shelly.com/en/products/shop/shelly-3-em[Shelly 3EM] +- Shelly Plug S +- https://www.shelly.com/de/products/shop/shelly-plus-plug-s-1[Shelly Plus Plug S] https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.io.shelly[Source Code icon:github[]] \ No newline at end of file diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/common/Utils.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/common/Utils.java new file mode 100644 index 00000000000..14595f04ea6 --- /dev/null +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/common/Utils.java @@ -0,0 +1,29 @@ +package io.openems.edge.io.shelly.common; + +import io.openems.edge.common.channel.Channel; +import io.openems.edge.common.component.OpenemsComponent; + +public class Utils { + + private Utils() { + } + + /** + * Generates a standard Debug-Log string for Shellys with one relay and power + * meter. + * + * @param relayChannel the Relay-Channel + * @param activePowerChannel the ActivePower-Channel + * @return suitable for {@link OpenemsComponent#debugLog()} + */ + public static String generateDebugLog(Channel relayChannel, Channel activePowerChannel) { + var b = new StringBuilder(); + relayChannel.value().asOptional().ifPresentOrElse(// + v -> b.append(v ? "On" : "Off"), // + () -> b.append("Unknown")); + b.append("|"); + b.append(activePowerChannel.value().asString()); + return b.toString(); + } + +} diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java index d802358f7db..aad007289db 100644 --- a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java @@ -22,7 +22,6 @@ import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.event.EdgeEventConstants; import io.openems.edge.io.api.DigitalOutput; -import io.openems.edge.io.shelly.common.ShellyApi; @Designate(ocd = Config.class, factory = true) @Component(// diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/common/ShellyApi.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/ShellyApi.java similarity index 97% rename from io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/common/ShellyApi.java rename to io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/ShellyApi.java index 7c24c80703e..6b3b8a3db6f 100644 --- a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/common/ShellyApi.java +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/ShellyApi.java @@ -1,4 +1,4 @@ -package io.openems.edge.io.shelly.common; +package io.openems.edge.io.shelly.shelly25; import java.io.BufferedReader; import java.io.IOException; @@ -13,6 +13,7 @@ import io.openems.common.exceptions.OpenemsException; import io.openems.common.utils.JsonUtils; +// TODO replace with HttpBridge /** * Implements the local Shelly REST Api. * diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly3em/IoShelly3EmImpl.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly3em/IoShelly3EmImpl.java index 5d899b8faba..1cb2c8d1f1e 100644 --- a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly3em/IoShelly3EmImpl.java +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly3em/IoShelly3EmImpl.java @@ -4,6 +4,7 @@ import static io.openems.common.utils.JsonUtils.getAsFloat; import static io.openems.common.utils.JsonUtils.getAsJsonArray; import static io.openems.common.utils.JsonUtils.getAsJsonObject; +import static io.openems.edge.io.shelly.common.Utils.generateDebugLog; import static java.lang.Math.round; import java.util.Objects; @@ -109,17 +110,7 @@ public BooleanWriteChannel[] digitalOutputChannels() { @Override public String debugLog() { - var b = new StringBuilder(); - var valueOpt = this.getRelayChannel().value().asOptional(); - b.append(valueOpt.isPresent() // - ? (valueOpt.get() // - ? "ON" // - : "OFF") // - : "Unknown"); - b.append("|"); - b.append(this.getActivePowerChannel().value().asString()); - - return b.toString(); + return generateDebugLog(this.getRelayChannel(), this.getActivePowerChannel()); } @Override diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplug/IoShellyPlugImpl.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplug/IoShellyPlugImpl.java index 03bbb6a9982..a883becf42c 100644 --- a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplug/IoShellyPlugImpl.java +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplug/IoShellyPlugImpl.java @@ -1,5 +1,7 @@ package io.openems.edge.io.shelly.shellyplug; +import static io.openems.edge.io.shelly.common.Utils.generateDebugLog; + import java.util.Objects; import org.osgi.service.component.ComponentContext; @@ -99,16 +101,7 @@ public BooleanWriteChannel[] digitalOutputChannels() { @Override public String debugLog() { - var b = new StringBuilder(); - var valueOpt = this.getRelayChannel().value().asOptional(); - if (valueOpt.isPresent()) { - b.append(valueOpt.get() ? "On" : "Off"); - } else { - b.append("Unknown"); - } - b.append("|"); - b.append(this.getActivePowerChannel().value().asString()); - return b.toString(); + return generateDebugLog(this.getRelayChannel(), this.getActivePowerChannel()); } @Override diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplusplugs/Config.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplusplugs/Config.java new file mode 100644 index 00000000000..39904456e3f --- /dev/null +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplusplugs/Config.java @@ -0,0 +1,33 @@ +package io.openems.edge.io.shelly.shellyplusplugs; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +import io.openems.edge.meter.api.MeterType; +import io.openems.edge.meter.api.SinglePhase; + +@ObjectClassDefinition(// + name = "IO Shelly Plus Plug S", // + description = "Implements the Shelly Plus Plug S") +@interface Config { + + @AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component") + String id() default "io0"; + + @AttributeDefinition(name = "Alias", description = "Human-readable name of this Component; defaults to Component-ID") + String alias() default ""; + + @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?") + boolean enabled() default true; + + @AttributeDefinition(name = "Phase", description = "Which Phase is this Shelly Plug connected to?") + SinglePhase phase() default SinglePhase.L1; + + @AttributeDefinition(name = "IP-Address", description = "The IP address of the Shelly device.") + String ip(); + + @AttributeDefinition(name = "Meter-Type", description = "What is measured by this Meter?") + MeterType type() default MeterType.CONSUMPTION_METERED; + + String webconsole_configurationFactory_nameHint() default "IO Shelly Plus Plug S [{id}]"; +} \ No newline at end of file diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlusPlugs.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlusPlugs.java new file mode 100644 index 00000000000..d0224d1e99c --- /dev/null +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlusPlugs.java @@ -0,0 +1,144 @@ +package io.openems.edge.io.shelly.shellyplusplugs; + +import org.osgi.service.event.EventHandler; + +import io.openems.common.channel.AccessMode; +import io.openems.common.channel.Level; +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.BooleanDoc; +import io.openems.edge.common.channel.BooleanWriteChannel; +import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.channel.StateChannel; +import io.openems.edge.common.channel.value.Value; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.io.api.DigitalOutput; +import io.openems.edge.meter.api.ElectricityMeter; +import io.openems.edge.meter.api.SinglePhaseMeter; + +public interface IoShellyPlusPlugs + extends DigitalOutput, SinglePhaseMeter, ElectricityMeter, OpenemsComponent, EventHandler { + + public static enum ChannelId implements io.openems.edge.common.channel.ChannelId { + /** + * Holds writes to Relay Output for debugging. + * + *

    + */ + DEBUG_RELAY(Doc.of(OpenemsType.BOOLEAN)), // + /** + * Relay Output. + * + *
      + *
    • Interface: ShellyPlug + *
    • Type: Boolean + *
    • Range: On/Off + *
    + */ + RELAY(new BooleanDoc() // + .accessMode(AccessMode.READ_WRITE) // + .onChannelSetNextWriteMirrorToDebugChannel(ChannelId.DEBUG_RELAY)), + /** + * Indicates if an update is available. + * + *
      + *
    • Interface: ShellyPlug + *
    • Type: Boolean + *
    • Level: INFO + *
    + */ + HAS_UPDATE(Doc.of(Level.INFO) // + .text("A new Firmware Update is available.")), + /** + * Slave Communication Failed Fault. + * + *
      + *
    • Interface: ShellyPlug + *
    • Type: State + *
    + */ + SLAVE_COMMUNICATION_FAILED(Doc.of(Level.FAULT)); // + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } + + /** + * Gets the Channel for {@link ChannelId#RELAY}. + * + * @return the Channel + */ + public default BooleanWriteChannel getRelayChannel() { + return this.channel(ChannelId.RELAY); + } + + /** + * Gets the Relay Output 1. See {@link ChannelId#RELAY}. + * + * @return the Channel {@link Value} + */ + public default Value getRelay() { + return this.getRelayChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#RELAY} Channel. + * + * @param value the next value + */ + public default void _setRelay(Boolean value) { + this.getRelayChannel().setNextValue(value); + } + + /** + * Sets the Relay Output. See {@link ChannelId#RELAY}. + * + * @param value the next write value + * @throws OpenemsNamedException on error + */ + public default void setRelay(boolean value) throws OpenemsNamedException { + this.getRelayChannel().setNextWriteValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#SLAVE_COMMUNICATION_FAILED}. + * + * @return the Channel + */ + public default StateChannel getSlaveCommunicationFailedChannel() { + return this.channel(ChannelId.SLAVE_COMMUNICATION_FAILED); + } + + /** + * Gets the Slave Communication Failed State. See + * {@link ChannelId#SLAVE_COMMUNICATION_FAILED}. + * + * @return the Channel {@link Value} + */ + public default Value getSlaveCommunicationFailed() { + return this.getSlaveCommunicationFailedChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on + * {@link ChannelId#SLAVE_COMMUNICATION_FAILED} Channel. + * + * @param value the next value + */ + public default void _setSlaveCommunicationFailed(boolean value) { + this.getSlaveCommunicationFailedChannel().setNextValue(value); + } + +} \ No newline at end of file diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlusPlugsImpl.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlusPlugsImpl.java new file mode 100644 index 00000000000..fd441091fa7 --- /dev/null +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlusPlugsImpl.java @@ -0,0 +1,237 @@ +package io.openems.edge.io.shelly.shellyplusplugs; + +import static io.openems.common.utils.JsonUtils.getAsBoolean; +import static io.openems.common.utils.JsonUtils.getAsFloat; +import static io.openems.common.utils.JsonUtils.getAsJsonObject; +import static io.openems.edge.io.shelly.common.Utils.generateDebugLog; +import static java.lang.Math.round; + +import java.util.Objects; + +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventHandler; +import org.osgi.service.event.propertytypes.EventTopics; +import org.osgi.service.metatype.annotations.Designate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonElement; + +import io.openems.edge.bridge.http.api.BridgeHttp; +import io.openems.edge.bridge.http.api.BridgeHttpFactory; +import io.openems.edge.common.channel.BooleanWriteChannel; +import io.openems.edge.common.component.AbstractOpenemsComponent; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.event.EdgeEventConstants; +import io.openems.edge.io.api.DigitalOutput; +import io.openems.edge.meter.api.ElectricityMeter; +import io.openems.edge.meter.api.MeterType; +import io.openems.edge.meter.api.SinglePhase; +import io.openems.edge.meter.api.SinglePhaseMeter; +import io.openems.edge.timedata.api.Timedata; +import io.openems.edge.timedata.api.TimedataProvider; +import io.openems.edge.timedata.api.utils.CalculateEnergyFromPower; + +@Designate(ocd = Config.class, factory = true) +@Component(// + name = "IO.Shelly.Plus.PlugS", // + immediate = true, // + configurationPolicy = ConfigurationPolicy.REQUIRE// +) +@EventTopics({ // + EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE, // + EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE // +}) +public class IoShellyPlusPlugsImpl extends AbstractOpenemsComponent implements IoShellyPlusPlugs, DigitalOutput, + SinglePhaseMeter, ElectricityMeter, OpenemsComponent, TimedataProvider, EventHandler { + + private final CalculateEnergyFromPower calculateProductionEnergy = new CalculateEnergyFromPower(this, + ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY); + private final CalculateEnergyFromPower calculateConsumptionEnergy = new CalculateEnergyFromPower(this, + ElectricityMeter.ChannelId.ACTIVE_CONSUMPTION_ENERGY); + + private final Logger log = LoggerFactory.getLogger(IoShellyPlusPlugsImpl.class); + private final BooleanWriteChannel[] digitalOutputChannels; + + private MeterType meterType = null; + private SinglePhase phase = null; + private String baseUrl; + + @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) + private volatile Timedata timedata; + + @Reference(cardinality = ReferenceCardinality.MANDATORY) + private BridgeHttpFactory httpBridgeFactory; + private BridgeHttp httpBridge; + + public IoShellyPlusPlugsImpl() { + super(// + OpenemsComponent.ChannelId.values(), // + ElectricityMeter.ChannelId.values(), // + DigitalOutput.ChannelId.values(), // + IoShellyPlusPlugs.ChannelId.values() // + ); + this.digitalOutputChannels = new BooleanWriteChannel[] { // + this.channel(IoShellyPlusPlugs.ChannelId.RELAY) // + }; + + SinglePhaseMeter.calculateSinglePhaseFromActivePower(this); + SinglePhaseMeter.calculateSinglePhaseFromCurrent(this); + SinglePhaseMeter.calculateSinglePhaseFromVoltage(this); + } + + @Activate + protected void activate(ComponentContext context, Config config) { + super.activate(context, config.id(), config.alias(), config.enabled()); + this.meterType = config.type(); + this.phase = config.phase(); + this.baseUrl = "http://" + config.ip(); + this.httpBridge = this.httpBridgeFactory.get(); + + if (!this.isEnabled()) { + return; + } + + this.httpBridge.subscribeJsonEveryCycle(this.baseUrl + "/rpc/Shelly.GetStatus", this::processHttpResult); + } + + @Override + @Deactivate + protected void deactivate() { + if (this.httpBridge != null) { + this.httpBridgeFactory.unget(this.httpBridge); + this.httpBridge = null; + } + super.deactivate(); + } + + @Override + public BooleanWriteChannel[] digitalOutputChannels() { + return this.digitalOutputChannels; + } + + @Override + public String debugLog() { + return generateDebugLog(this.getRelayChannel(), this.getActivePowerChannel()); + } + + @Override + public void handleEvent(Event event) { + if (!this.isEnabled()) { + return; + } + + switch (event.getTopic()) { + case EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE // + -> this.calculateEnergy(); + case EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE // + -> this.executeWrite(); + } + } + + private void processHttpResult(JsonElement result, Throwable error) { + this._setSlaveCommunicationFailed(result == null); + + Boolean relayStatus = null; + Boolean updatesAvailable = false; + Integer activePower = null; + Integer current = null; + Integer voltage = null; + + if (error != null) { + this.logWarn(this.log, error.getMessage()); + + } else { + try { + var response = getAsJsonObject(result); + var sysInfo = getAsJsonObject(response, "sys"); + var update = getAsJsonObject(sysInfo, "available_updates"); + updatesAvailable = update != null && !update.entrySet().isEmpty(); + + var relays = getAsJsonObject(response, "switch:0"); + activePower = round(getAsFloat(relays, "apower")); + current = round(getAsFloat(relays, "current") * 1000); + voltage = round(getAsFloat(relays, "voltage") * 1000); + relayStatus = getAsBoolean(relays, "output"); + + } catch (Exception e) { + this.logWarn(this.log, e.getMessage()); + } + } + + this._setRelay(relayStatus); + this._setActivePower(activePower); + this._setCurrent(current); + this._setVoltage(voltage); + this.channel(IoShellyPlusPlugs.ChannelId.HAS_UPDATE).setNextValue(updatesAvailable); + } + + /** + * Execute on Cycle Event "Execute Write". + */ + private void executeWrite() { + var channel = this.getRelayChannel(); + var readValue = channel.value().get(); + var writeValue = channel.getNextWriteValueAndReset(); + if (writeValue.isEmpty()) { + return; + } + if (Objects.equals(readValue, writeValue.get())) { + return; + } + var index = 0; + final var url = this.baseUrl + "/relay/" + index + "?turn=" + (writeValue.get() ? "on" : "off"); + + this.httpBridge.get(url).whenComplete((t, e) -> { + this._setSlaveCommunicationFailed(e != null); + if (e == null) { + this.logDebug(this.log, "Executed write successfully for URL: " + url); + } else { + this.logError(this.log, "Failed to execute write for URL: " + url + "; Error: " + e.getMessage()); + } + }); + } + + /** + * Calculate the Energy values from ActivePower. + */ + private void calculateEnergy() { + // Calculate Energy + final var activePower = this.getActivePower().get(); + if (activePower == null) { + this.calculateProductionEnergy.update(null); + this.calculateConsumptionEnergy.update(null); + } else if (activePower >= 0) { + this.calculateProductionEnergy.update(activePower); + this.calculateConsumptionEnergy.update(0); + } else { + this.calculateProductionEnergy.update(0); + this.calculateConsumptionEnergy.update(-activePower); + } + } + + @Override + public MeterType getMeterType() { + return this.meterType; + } + + @Override + public SinglePhase getPhase() { + return this.phase; + } + + @Override + public Timedata getTimedata() { + return this.timedata; + } + +} diff --git a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlugImplTest.java b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlugImplTest.java new file mode 100644 index 00000000000..88da88fe9ff --- /dev/null +++ b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlugImplTest.java @@ -0,0 +1,88 @@ +package io.openems.edge.io.shelly.shellyplusplugs; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import io.openems.common.types.ChannelAddress; +import io.openems.edge.bridge.http.dummy.DummyBridgeHttpFactory; +import io.openems.edge.common.test.AbstractComponentTest.TestCase; +import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.meter.api.MeterType; +import io.openems.edge.meter.api.SinglePhase; +import io.openems.edge.timedata.test.DummyTimedata; + +public class IoShellyPlugImplTest { + + private static final String COMPONENT_ID = "io0"; + + private static final ChannelAddress ACTIVE_POWER = new ChannelAddress(COMPONENT_ID, "ActivePower"); + private static final ChannelAddress ACTIVE_POWER_L1 = new ChannelAddress(COMPONENT_ID, "ActivePowerL1"); + private static final ChannelAddress ACTIVE_POWER_L2 = new ChannelAddress(COMPONENT_ID, "ActivePowerL2"); + private static final ChannelAddress CURRENT = new ChannelAddress(COMPONENT_ID, "Current"); + private static final ChannelAddress VOLTAGE = new ChannelAddress(COMPONENT_ID, "Voltage"); + private static final ChannelAddress PRODUCTION_ENERGY = new ChannelAddress(COMPONENT_ID, "ActiveProductionEnergy"); + private static final ChannelAddress CONSUMPTION_ENERGY = new ChannelAddress(COMPONENT_ID, + "ActiveConsumptionEnergy"); + + @Test + public void test() throws Exception { + final var bridgeFactory = new DummyBridgeHttpFactory(); + final var bridge = bridgeFactory.bridge; + final var sut = new IoShellyPlusPlugsImpl(); + new ComponentTest(sut) // + .addReference("httpBridgeFactory", bridgeFactory) // + .addReference("timedata", new DummyTimedata("timedata0")) // + .activate(MyConfig.create() // + .setId(COMPONENT_ID) // + .setPhase(SinglePhase.L1) // + .setIp("127.0.0.1") // + .setType(MeterType.PRODUCTION) // + .build()) // + + .next(new TestCase("Successfull read response") // + .onBeforeControllersCallbacks(() -> bridge.mockCycleResult(""" + { + "sys": { + "available_updates": { + "foo": "bar" + } + }, + "switch:0": { + "current": 1.234, + "voltage": 231.5, + "output": false, + "apower": 789.1 + } + } + """)) // + .output(ACTIVE_POWER, 789) // + .output(ACTIVE_POWER_L1, 789) // + .output(ACTIVE_POWER_L2, null) // + .output(CURRENT, 1234) // + .output(VOLTAGE, 231500)) // + + .next(new TestCase("Invalid read response") // + .onBeforeControllersCallbacks(() -> assertEquals("Off|789 W", sut.debugLog())) + + .onBeforeControllersCallbacks(() -> bridge.mockCycleResult("failed")) // + .output(ACTIVE_POWER, null) // + .output(ACTIVE_POWER_L1, null) // + .output(ACTIVE_POWER_L2, null) // + .output(CURRENT, null) // + .output(VOLTAGE, null) // + + .output(PRODUCTION_ENERGY, 0L) // + .output(CONSUMPTION_ENERGY, 0L)) // + + .next(new TestCase("Write") // + .onBeforeControllersCallbacks(() -> assertEquals("Unknown|UNDEFINED", sut.debugLog())) + + .onBeforeControllersCallbacks(() -> { + sut.setRelay(true); + bridge.mockRequestResult("FOO-BAR"); + })) // + + .deactivate(); + } +} diff --git a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplusplugs/MyConfig.java b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplusplugs/MyConfig.java new file mode 100644 index 00000000000..81fe32540f0 --- /dev/null +++ b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplusplugs/MyConfig.java @@ -0,0 +1,75 @@ +package io.openems.edge.io.shelly.shellyplusplugs; + +import io.openems.common.test.AbstractComponentConfig; +import io.openems.edge.io.shelly.shellyplusplugs.Config; +import io.openems.edge.meter.api.MeterType; +import io.openems.edge.meter.api.SinglePhase; + +@SuppressWarnings("all") +public class MyConfig extends AbstractComponentConfig implements Config { + + protected static class Builder { + private String id; + private String ip; + private MeterType type; + private SinglePhase phase; + + private Builder() { + } + + public Builder setId(String id) { + this.id = id; + return this; + } + + public Builder setPhase(SinglePhase phase) { + this.phase = phase; + return this; + } + + public Builder setIp(String ip) { + this.ip = ip; + return this; + } + + public Builder setType(MeterType type) { + this.type = type; + return this; + } + + public MyConfig build() { + return new MyConfig(this); + } + } + + /** + * Create a Config builder. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new Builder(); + } + + private final Builder builder; + + private MyConfig(Builder builder) { + super(Config.class, builder.id); + this.builder = builder; + } + + @Override + public SinglePhase phase() { + return this.builder.phase; + } + + @Override + public String ip() { + return this.builder.ip; + } + + @Override + public MeterType type() { + return this.builder.type; + } +} \ No newline at end of file diff --git a/io.openems.edge.meter.api/src/io/openems/edge/meter/api/SinglePhaseMeter.java b/io.openems.edge.meter.api/src/io/openems/edge/meter/api/SinglePhaseMeter.java index 07ccff0bc23..bb9264c8f99 100644 --- a/io.openems.edge.meter.api/src/io/openems/edge/meter/api/SinglePhaseMeter.java +++ b/io.openems.edge.meter.api/src/io/openems/edge/meter/api/SinglePhaseMeter.java @@ -76,6 +76,90 @@ public static void calculateSinglePhaseFromActi }); } + /** + * Initializes Channel listeners for a {@link SinglePhaseMeter}. + * + *

    + * Sets the correct value for {@link ChannelId#CURRENT_L1}, + * {@link ChannelId#CURRENT_L2} or {@link ChannelId#CURRENT_L3} from + * {@link ChannelId#CURRENT} by evaluating the configured {@link SinglePhase} + * via {@link SinglePhaseMeter#getPhase()}. + * + * @param meter the {@link SinglePhaseMeter} + */ + public static void calculateSinglePhaseFromCurrent(SinglePhaseMeter meter) { + SinglePhaseMeter.calculateSinglePhaseFromCurrent(meter, SinglePhaseMeter::getPhase); + } + + /** + * Initializes Channel listeners for a {@link SinglePhaseMeter}. + * + *

    + * Use this method if it is not known at compile time, that the + * {@link ElectricityMeter} is a {@link SinglePhaseMeter}, i.e. it is not + * implementing {@link SinglePhaseMeter}. + * + *

    + * Sets the correct value for {@link ChannelId#CURRENT_L1}, + * {@link ChannelId#CURRENT_L2} or {@link ChannelId#CURRENT_L3} from + * {@link ChannelId#CURRENT} by evaluating the provided {@link SinglePhase}. + * + * @param type that extends {@link ElectricityMeter} + * @param meter a {@link ElectricityMeter} + * @param phaseProvider a provider for {@link SinglePhase} + */ + public static void calculateSinglePhaseFromCurrent(METER meter, + Function phaseProvider) { + meter.getCurrentChannel().onSetNextValue(value -> { + var phase = phaseProvider.apply(meter); + meter.getCurrentL1Channel().setNextValue(phase == SinglePhase.L1 ? value : null); + meter.getCurrentL2Channel().setNextValue(phase == SinglePhase.L2 ? value : null); + meter.getCurrentL3Channel().setNextValue(phase == SinglePhase.L3 ? value : null); + }); + } + + /** + * Initializes Channel listeners for a {@link SinglePhaseMeter}. + * + *

    + * Sets the correct value for {@link ChannelId#VOLTAGE_L1}, + * {@link ChannelId#VOLTAGE_L2} or {@link ChannelId#VOLTAGE_L3} from + * {@link ChannelId#VOLTAGE} by evaluating the configured {@link SinglePhase} + * via {@link SinglePhaseMeter#getPhase()}. + * + * @param meter the {@link SinglePhaseMeter} + */ + public static void calculateSinglePhaseFromVoltage(SinglePhaseMeter meter) { + SinglePhaseMeter.calculateSinglePhaseFromVoltage(meter, SinglePhaseMeter::getPhase); + } + + /** + * Initializes Channel listeners for a {@link SinglePhaseMeter}. + * + *

    + * Use this method if it is not known at compile time, that the + * {@link ElectricityMeter} is a {@link SinglePhaseMeter}, i.e. it is not + * implementing {@link SinglePhaseMeter}. + * + *

    + * Sets the correct value for {@link ChannelId#VOLTAGE_L1}, + * {@link ChannelId#VOLTAGE_L2} or {@link ChannelId#VOLTAGE_L3} from + * {@link ChannelId#VOLTAGE} by evaluating the provided {@link SinglePhase}. + * + * @param type that extends {@link ElectricityMeter} + * @param meter a {@link ElectricityMeter} + * @param phaseProvider a provider for {@link SinglePhase} + */ + public static void calculateSinglePhaseFromVoltage(METER meter, + Function phaseProvider) { + meter.getVoltageChannel().onSetNextValue(value -> { + var phase = phaseProvider.apply(meter); + meter.getVoltageL1Channel().setNextValue(phase == SinglePhase.L1 ? value : null); + meter.getVoltageL2Channel().setNextValue(phase == SinglePhase.L2 ? value : null); + meter.getVoltageL3Channel().setNextValue(phase == SinglePhase.L3 ? value : null); + }); + } + /** * Used for Modbus/TCP Api Controller. Provides a Modbus table for the Channels * of this Component. From 49c8e94aa4a022b74b74e76ba613282c9ff3bfed Mon Sep 17 00:00:00 2001 From: Hannes Date: Tue, 30 Apr 2024 17:33:51 +0200 Subject: [PATCH 008/173] Implement Eastron SDM120 meter & update existing SDM360 (#2554) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Hans Krämer <158505461+fanass-dev@users.noreply.github.com> Co-authored-by: Stefan Feilmeier <3515268+sfeilmeier@users.noreply.github.com> --- io.openems.edge.application/EdgeApp.bndrun | 4 +- .../edge/meter/api/SinglePhaseMeter.java | 71 +++++-- .../.classpath | 0 .../.gitignore | 0 .../.project | 2 +- .../org.eclipse.core.resources.prefs | 0 .../bnd.bnd | 2 +- .../doc/SDM120-MODBUS_Protocol.pdf | Bin 0 -> 238378 bytes .../doc/SDM630Register1-5.pdf | Bin .../readme.adoc | 9 +- .../edge/meter/eastron/sdm120/Config.java | 41 ++++ .../eastron/sdm120/MeterEastronSdm120.java | 32 +++ .../sdm120/MeterEastronSdm120Impl.java | 185 ++++++++++++++++++ .../edge/meter/eastron}/sdm630/Config.java | 8 +- .../eastron/sdm630/MeterEastronSdm630.java | 4 +- .../sdm630/MeterEastronSdm630Impl.java | 13 +- .../test/.gitignore | 0 .../sdm120/MeterEastronSdm120ImplTest.java | 29 +++ .../edge/meter/eastron/sdm120/MyConfig.java | 98 ++++++++++ .../sdm630/MeterEastronSdm630ImplTest.java | 6 +- .../edge/meter/eastron}/sdm630/MyConfig.java | 2 +- 21 files changed, 471 insertions(+), 35 deletions(-) rename {io.openems.edge.meter.microcare.sdm630 => io.openems.edge.meter.eastron}/.classpath (100%) rename {io.openems.edge.meter.microcare.sdm630 => io.openems.edge.meter.eastron}/.gitignore (100%) rename {io.openems.edge.meter.microcare.sdm630 => io.openems.edge.meter.eastron}/.project (90%) rename {io.openems.edge.meter.microcare.sdm630 => io.openems.edge.meter.eastron}/.settings/org.eclipse.core.resources.prefs (100%) rename {io.openems.edge.meter.microcare.sdm630 => io.openems.edge.meter.eastron}/bnd.bnd (84%) create mode 100644 io.openems.edge.meter.eastron/doc/SDM120-MODBUS_Protocol.pdf rename {io.openems.edge.meter.microcare.sdm630 => io.openems.edge.meter.eastron}/doc/SDM630Register1-5.pdf (100%) rename {io.openems.edge.meter.microcare.sdm630 => io.openems.edge.meter.eastron}/readme.adoc (55%) create mode 100644 io.openems.edge.meter.eastron/src/io/openems/edge/meter/eastron/sdm120/Config.java create mode 100644 io.openems.edge.meter.eastron/src/io/openems/edge/meter/eastron/sdm120/MeterEastronSdm120.java create mode 100644 io.openems.edge.meter.eastron/src/io/openems/edge/meter/eastron/sdm120/MeterEastronSdm120Impl.java rename {io.openems.edge.meter.microcare.sdm630/src/io/openems/edge/meter/microcare => io.openems.edge.meter.eastron/src/io/openems/edge/meter/eastron}/sdm630/Config.java (86%) rename io.openems.edge.meter.microcare.sdm630/src/io/openems/edge/meter/microcare/sdm630/MeterMicrocareSdm630.java => io.openems.edge.meter.eastron/src/io/openems/edge/meter/eastron/sdm630/MeterEastronSdm630.java (83%) rename io.openems.edge.meter.microcare.sdm630/src/io/openems/edge/meter/microcare/sdm630/MeterMicrocareSdm630Impl.java => io.openems.edge.meter.eastron/src/io/openems/edge/meter/eastron/sdm630/MeterEastronSdm630Impl.java (95%) rename {io.openems.edge.meter.microcare.sdm630 => io.openems.edge.meter.eastron}/test/.gitignore (100%) create mode 100644 io.openems.edge.meter.eastron/test/io/openems/edge/meter/eastron/sdm120/MeterEastronSdm120ImplTest.java create mode 100644 io.openems.edge.meter.eastron/test/io/openems/edge/meter/eastron/sdm120/MyConfig.java rename io.openems.edge.meter.microcare.sdm630/test/io/openems/edge/meter/microcare/sdm630/MeterMicrocareSdm630ImplTest.java => io.openems.edge.meter.eastron/test/io/openems/edge/meter/eastron/sdm630/MeterEastronSdm630ImplTest.java (82%) rename {io.openems.edge.meter.microcare.sdm630/test/io/openems/edge/meter/microcare => io.openems.edge.meter.eastron/test/io/openems/edge/meter/eastron}/sdm630/MyConfig.java (96%) diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index d79a89639bc..0e5c289c8f1 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -150,9 +150,9 @@ bnd.identity;id='io.openems.edge.meter.camillebauer.aplus',\ bnd.identity;id='io.openems.edge.meter.carlo.gavazzi.em300',\ bnd.identity;id='io.openems.edge.meter.discovergy',\ + bnd.identity;id='io.openems.edge.meter.eastron',\ bnd.identity;id='io.openems.edge.meter.janitza',\ bnd.identity;id='io.openems.edge.meter.kdk',\ - bnd.identity;id='io.openems.edge.meter.microcare.sdm630',\ bnd.identity;id='io.openems.edge.meter.phoenixcontact',\ bnd.identity;id='io.openems.edge.meter.plexlog',\ bnd.identity;id='io.openems.edge.meter.pqplus',\ @@ -321,9 +321,9 @@ io.openems.edge.meter.camillebauer.aplus;version=snapshot,\ io.openems.edge.meter.carlo.gavazzi.em300;version=snapshot,\ io.openems.edge.meter.discovergy;version=snapshot,\ + io.openems.edge.meter.eastron;version=snapshot,\ io.openems.edge.meter.janitza;version=snapshot,\ io.openems.edge.meter.kdk;version=snapshot,\ - io.openems.edge.meter.microcare.sdm630;version=snapshot,\ io.openems.edge.meter.phoenixcontact;version=snapshot,\ io.openems.edge.meter.plexlog;version=snapshot,\ io.openems.edge.meter.pqplus;version=snapshot,\ diff --git a/io.openems.edge.meter.api/src/io/openems/edge/meter/api/SinglePhaseMeter.java b/io.openems.edge.meter.api/src/io/openems/edge/meter/api/SinglePhaseMeter.java index bb9264c8f99..206766eaa16 100644 --- a/io.openems.edge.meter.api/src/io/openems/edge/meter/api/SinglePhaseMeter.java +++ b/io.openems.edge.meter.api/src/io/openems/edge/meter/api/SinglePhaseMeter.java @@ -1,5 +1,9 @@ package io.openems.edge.meter.api; +import static io.openems.edge.meter.api.SinglePhase.L1; +import static io.openems.edge.meter.api.SinglePhase.L2; +import static io.openems.edge.meter.api.SinglePhase.L3; + import java.util.function.Function; import org.osgi.annotation.versioning.ProviderType; @@ -45,7 +49,7 @@ public Doc doc() { * @param meter the {@link SinglePhaseMeter} */ public static void calculateSinglePhaseFromActivePower(SinglePhaseMeter meter) { - SinglePhaseMeter.calculateSinglePhaseFromActivePower(meter, SinglePhaseMeter::getPhase); + calculateSinglePhaseFromActivePower(meter, SinglePhaseMeter::getPhase); } /** @@ -70,9 +74,52 @@ public static void calculateSinglePhaseFromActi Function phaseProvider) { meter.getActivePowerChannel().onSetNextValue(value -> { var phase = phaseProvider.apply(meter); - meter.getActivePowerL1Channel().setNextValue(phase == SinglePhase.L1 ? value : null); - meter.getActivePowerL2Channel().setNextValue(phase == SinglePhase.L2 ? value : null); - meter.getActivePowerL3Channel().setNextValue(phase == SinglePhase.L3 ? value : null); + meter.getActivePowerL1Channel().setNextValue(phase == L1 ? value : null); + meter.getActivePowerL2Channel().setNextValue(phase == L2 ? value : null); + meter.getActivePowerL3Channel().setNextValue(phase == L3 ? value : null); + }); + } + + /** + * Initializes Channel listeners for a {@link SinglePhaseMeter}. + * + *

    + * Sets the correct value for {@link ChannelId#REACTIVE_POWER_L1}, + * {@link ChannelId#REACTIVE_POWER_L2} or {@link ChannelId#REACTIVE_POWER_L3} + * from {@link ChannelId#REACTIVE_POWER} by evaluating the configured + * {@link SinglePhase} via {@link SinglePhaseMeter#getPhase()}. + * + * @param meter the {@link SinglePhaseMeter} + */ + public static void calculateSinglePhaseFromReactivePower(SinglePhaseMeter meter) { + calculateSinglePhaseFromReactivePower(meter, SinglePhaseMeter::getPhase); + } + + /** + * Initializes Channel listeners for a {@link SinglePhaseMeter}. + * + *

    + * Use this method if it is not known at compile time, that the + * {@link ElectricityMeter} is a {@link SinglePhaseMeter}, i.e. it is not + * implementing {@link SinglePhaseMeter}. + * + *

    + * Sets the correct value for {@link ChannelId#REACTIVE_POWER_L1}, + * {@link ChannelId#REACTIVE_POWER_L2} or {@link ChannelId#REACTIVE_POWER_L3} + * from {@link ChannelId#REACTIVE_POWER} by evaluating the provided + * {@link SinglePhase}. + * + * @param type that extends {@link ElectricityMeter} + * @param meter a {@link ElectricityMeter} + * @param phaseProvider a provider for {@link SinglePhase} + */ + public static void calculateSinglePhaseFromReactivePower(METER meter, + Function phaseProvider) { + meter.getReactivePowerChannel().onSetNextValue(value -> { + var phase = phaseProvider.apply(meter); + meter.getReactivePowerL1Channel().setNextValue(phase == L1 ? value : null); + meter.getReactivePowerL2Channel().setNextValue(phase == L2 ? value : null); + meter.getReactivePowerL3Channel().setNextValue(phase == L3 ? value : null); }); } @@ -88,7 +135,7 @@ public static void calculateSinglePhaseFromActi * @param meter the {@link SinglePhaseMeter} */ public static void calculateSinglePhaseFromCurrent(SinglePhaseMeter meter) { - SinglePhaseMeter.calculateSinglePhaseFromCurrent(meter, SinglePhaseMeter::getPhase); + calculateSinglePhaseFromCurrent(meter, SinglePhaseMeter::getPhase); } /** @@ -112,9 +159,9 @@ public static void calculateSinglePhaseFromCurr Function phaseProvider) { meter.getCurrentChannel().onSetNextValue(value -> { var phase = phaseProvider.apply(meter); - meter.getCurrentL1Channel().setNextValue(phase == SinglePhase.L1 ? value : null); - meter.getCurrentL2Channel().setNextValue(phase == SinglePhase.L2 ? value : null); - meter.getCurrentL3Channel().setNextValue(phase == SinglePhase.L3 ? value : null); + meter.getCurrentL1Channel().setNextValue(phase == L1 ? value : null); + meter.getCurrentL2Channel().setNextValue(phase == L2 ? value : null); + meter.getCurrentL3Channel().setNextValue(phase == L3 ? value : null); }); } @@ -130,7 +177,7 @@ public static void calculateSinglePhaseFromCurr * @param meter the {@link SinglePhaseMeter} */ public static void calculateSinglePhaseFromVoltage(SinglePhaseMeter meter) { - SinglePhaseMeter.calculateSinglePhaseFromVoltage(meter, SinglePhaseMeter::getPhase); + calculateSinglePhaseFromVoltage(meter, SinglePhaseMeter::getPhase); } /** @@ -154,9 +201,9 @@ public static void calculateSinglePhaseFromVolt Function phaseProvider) { meter.getVoltageChannel().onSetNextValue(value -> { var phase = phaseProvider.apply(meter); - meter.getVoltageL1Channel().setNextValue(phase == SinglePhase.L1 ? value : null); - meter.getVoltageL2Channel().setNextValue(phase == SinglePhase.L2 ? value : null); - meter.getVoltageL3Channel().setNextValue(phase == SinglePhase.L3 ? value : null); + meter.getVoltageL1Channel().setNextValue(phase == L1 ? value : null); + meter.getVoltageL2Channel().setNextValue(phase == L2 ? value : null); + meter.getVoltageL3Channel().setNextValue(phase == L3 ? value : null); }); } diff --git a/io.openems.edge.meter.microcare.sdm630/.classpath b/io.openems.edge.meter.eastron/.classpath similarity index 100% rename from io.openems.edge.meter.microcare.sdm630/.classpath rename to io.openems.edge.meter.eastron/.classpath diff --git a/io.openems.edge.meter.microcare.sdm630/.gitignore b/io.openems.edge.meter.eastron/.gitignore similarity index 100% rename from io.openems.edge.meter.microcare.sdm630/.gitignore rename to io.openems.edge.meter.eastron/.gitignore diff --git a/io.openems.edge.meter.microcare.sdm630/.project b/io.openems.edge.meter.eastron/.project similarity index 90% rename from io.openems.edge.meter.microcare.sdm630/.project rename to io.openems.edge.meter.eastron/.project index 3694691cf2b..15128f1ed59 100644 --- a/io.openems.edge.meter.microcare.sdm630/.project +++ b/io.openems.edge.meter.eastron/.project @@ -1,6 +1,6 @@ - io.openems.edge.meter.microcare.sdm630 + io.openems.edge.meter.eastron diff --git a/io.openems.edge.meter.microcare.sdm630/.settings/org.eclipse.core.resources.prefs b/io.openems.edge.meter.eastron/.settings/org.eclipse.core.resources.prefs similarity index 100% rename from io.openems.edge.meter.microcare.sdm630/.settings/org.eclipse.core.resources.prefs rename to io.openems.edge.meter.eastron/.settings/org.eclipse.core.resources.prefs diff --git a/io.openems.edge.meter.microcare.sdm630/bnd.bnd b/io.openems.edge.meter.eastron/bnd.bnd similarity index 84% rename from io.openems.edge.meter.microcare.sdm630/bnd.bnd rename to io.openems.edge.meter.eastron/bnd.bnd index 39fb3f2b3fc..ba1e48e8ad4 100644 --- a/io.openems.edge.meter.microcare.sdm630/bnd.bnd +++ b/io.openems.edge.meter.eastron/bnd.bnd @@ -1,4 +1,4 @@ -Bundle-Name: OpenEMS Edge Meter Microcare SDM 630 Smart Meter +Bundle-Name: OpenEMS Edge Meter Eastron SDM 630 Smart Meter Bundle-Vendor: Microcare (Destrier Electronics Pty Ltd) Bundle-Version: 1.0.0.${tstamp} Bundle-License: Proprietary (for now) diff --git a/io.openems.edge.meter.eastron/doc/SDM120-MODBUS_Protocol.pdf b/io.openems.edge.meter.eastron/doc/SDM120-MODBUS_Protocol.pdf new file mode 100644 index 0000000000000000000000000000000000000000..825241433689db2e85b3ab2af47931ae3a3f9ef7 GIT binary patch literal 238378 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 z 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 z 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ð%#nta{vlf5mQtZo_MXYnx3xYX|oe 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 KbS^%$<^K&)n~%r< literal 0 HcmV?d00001 diff --git a/io.openems.edge.meter.microcare.sdm630/doc/SDM630Register1-5.pdf b/io.openems.edge.meter.eastron/doc/SDM630Register1-5.pdf similarity index 100% rename from io.openems.edge.meter.microcare.sdm630/doc/SDM630Register1-5.pdf rename to io.openems.edge.meter.eastron/doc/SDM630Register1-5.pdf diff --git a/io.openems.edge.meter.microcare.sdm630/readme.adoc b/io.openems.edge.meter.eastron/readme.adoc similarity index 55% rename from io.openems.edge.meter.microcare.sdm630/readme.adoc rename to io.openems.edge.meter.eastron/readme.adoc index f4e64498a14..d8ccfd5ef52 100644 --- a/io.openems.edge.meter.microcare.sdm630/readme.adoc +++ b/io.openems.edge.meter.eastron/readme.adoc @@ -1,8 +1,11 @@ -= Microcare SDM 630 Meter += Eastron/Microcare SDM 630 and 120 Meter -This implementation is functionally compatible with a number of energy meters with the name "SDM 630". +This implementation is functionally compatible with a number of energy meters with the names: + +- SDM 630 and +- SDM 120 Implemented Natures: - ElectricityMeter -https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.meter.microcare.sdm630[Source Code icon:github[]] \ No newline at end of file +https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.meter.eastron[Source Code icon:github[]] \ No newline at end of file diff --git a/io.openems.edge.meter.eastron/src/io/openems/edge/meter/eastron/sdm120/Config.java b/io.openems.edge.meter.eastron/src/io/openems/edge/meter/eastron/sdm120/Config.java new file mode 100644 index 00000000000..1800860d9c5 --- /dev/null +++ b/io.openems.edge.meter.eastron/src/io/openems/edge/meter/eastron/sdm120/Config.java @@ -0,0 +1,41 @@ +package io.openems.edge.meter.eastron.sdm120; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +import io.openems.edge.meter.api.MeterType; +import io.openems.edge.meter.api.SinglePhase; + +@ObjectClassDefinition(name = "Meter Eastron SDM 120", // + description = "Implements the Eastron SDM120 meter.") +@interface Config { + + @AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component") + String id() default "meter0"; + + @AttributeDefinition(name = "Alias", description = "Human-readable name of this Component; defaults to Component-ID") + String alias() default ""; + + @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?") + boolean enabled() default true; + + @AttributeDefinition(name = "Meter-Type", description = "Grid (default), Production, Consumption") + MeterType type() default MeterType.GRID; + + @AttributeDefinition(name = "Modbus-ID", description = "ID of Modbus bridge.") + String modbus_id() default "modbus0"; + + @AttributeDefinition(name = "Modbus Unit-ID", description = "The Unit-ID of the Modbus device.") + int modbusUnitId() default 1; + + @AttributeDefinition(name = "Invert Power", description = "Inverts ALL Power values, inverts current values, swaps production and consumption energy, i.e. Power is multiplied with -1.") + boolean invert() default false; + + @AttributeDefinition(name = "Phase", description = "Which Phase is this Meter connected to?") + SinglePhase phase() default SinglePhase.L1; + + @AttributeDefinition(name = "Modbus target filter", description = "This is auto-generated by 'Modbus-ID'.") + String Modbus_target() default "(enabled=true)"; + + String webconsole_configurationFactory_nameHint() default "Meter Eastron SDM 120 [{id}]"; +} \ No newline at end of file diff --git a/io.openems.edge.meter.eastron/src/io/openems/edge/meter/eastron/sdm120/MeterEastronSdm120.java b/io.openems.edge.meter.eastron/src/io/openems/edge/meter/eastron/sdm120/MeterEastronSdm120.java new file mode 100644 index 00000000000..3fa5e9d2b44 --- /dev/null +++ b/io.openems.edge.meter.eastron/src/io/openems/edge/meter/eastron/sdm120/MeterEastronSdm120.java @@ -0,0 +1,32 @@ +package io.openems.edge.meter.eastron.sdm120; + +import io.openems.common.channel.Unit; +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.modbusslave.ModbusSlave; +import io.openems.edge.meter.api.ElectricityMeter; +import io.openems.edge.meter.api.SinglePhaseMeter; + +public interface MeterEastronSdm120 extends SinglePhaseMeter, ElectricityMeter, OpenemsComponent, ModbusSlave { + + public enum ChannelId implements io.openems.edge.common.channel.ChannelId { + REACTIVE_PRODUCTION_ENERGY(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT_AMPERE_REACTIVE_HOURS)), // + REACTIVE_CONSUMPTION_ENERGY(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT_AMPERE_REACTIVE_HOURS)), // + ; + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } + +} diff --git a/io.openems.edge.meter.eastron/src/io/openems/edge/meter/eastron/sdm120/MeterEastronSdm120Impl.java b/io.openems.edge.meter.eastron/src/io/openems/edge/meter/eastron/sdm120/MeterEastronSdm120Impl.java new file mode 100644 index 00000000000..3667375bb8b --- /dev/null +++ b/io.openems.edge.meter.eastron/src/io/openems/edge/meter/eastron/sdm120/MeterEastronSdm120Impl.java @@ -0,0 +1,185 @@ +package io.openems.edge.meter.eastron.sdm120; + +import static io.openems.edge.bridge.modbus.api.ElementToChannelConverter.INVERT_IF_TRUE; +import static io.openems.edge.bridge.modbus.api.ElementToChannelConverter.SCALE_FACTOR_3; +import static io.openems.edge.bridge.modbus.api.ElementToChannelConverter.chain; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventHandler; +import org.osgi.service.event.propertytypes.EventTopics; +import org.osgi.service.metatype.annotations.Designate; + +import io.openems.common.channel.AccessMode; +import io.openems.common.exceptions.OpenemsException; +import io.openems.edge.bridge.modbus.api.AbstractOpenemsModbusComponent; +import io.openems.edge.bridge.modbus.api.BridgeModbus; +import io.openems.edge.bridge.modbus.api.ModbusComponent; +import io.openems.edge.bridge.modbus.api.ModbusProtocol; +import io.openems.edge.bridge.modbus.api.element.DummyRegisterElement; +import io.openems.edge.bridge.modbus.api.element.FloatDoublewordElement; +import io.openems.edge.bridge.modbus.api.task.FC4ReadInputRegistersTask; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.event.EdgeEventConstants; +import io.openems.edge.common.modbusslave.ModbusSlave; +import io.openems.edge.common.modbusslave.ModbusSlaveTable; +import io.openems.edge.common.taskmanager.Priority; +import io.openems.edge.meter.api.ElectricityMeter; +import io.openems.edge.meter.api.MeterType; +import io.openems.edge.meter.api.SinglePhase; +import io.openems.edge.meter.api.SinglePhaseMeter; +import io.openems.edge.timedata.api.Timedata; +import io.openems.edge.timedata.api.TimedataProvider; +import io.openems.edge.timedata.api.utils.CalculateEnergyFromPower; + +@Designate(ocd = Config.class, factory = true) +@Component(// + name = "Meter.Eastron.SDM120", // + immediate = true, // + configurationPolicy = ConfigurationPolicy.REQUIRE // +) +@EventTopics({ // + EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE // +}) +public class MeterEastronSdm120Impl extends AbstractOpenemsModbusComponent + implements MeterEastronSdm120, SinglePhaseMeter, ElectricityMeter, ModbusComponent, OpenemsComponent, + ModbusSlave, TimedataProvider, EventHandler { + + private final CalculateEnergyFromPower calculateProductionEnergy = new CalculateEnergyFromPower(this, + ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY); + private final CalculateEnergyFromPower calculateConsumptionEnergy = new CalculateEnergyFromPower(this, + ElectricityMeter.ChannelId.ACTIVE_CONSUMPTION_ENERGY); + + @Reference + private ConfigurationAdmin cm; + + @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) + private volatile Timedata timedata; + + @Override + @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) + protected void setModbus(BridgeModbus modbus) { + super.setModbus(modbus); + } + + private Config config; + + public MeterEastronSdm120Impl() { + super(// + OpenemsComponent.ChannelId.values(), // + ModbusComponent.ChannelId.values(), // + ElectricityMeter.ChannelId.values(), // + SinglePhaseMeter.ChannelId.values(), // + MeterEastronSdm120.ChannelId.values() // + ); + + SinglePhaseMeter.calculateSinglePhaseFromActivePower(this); + SinglePhaseMeter.calculateSinglePhaseFromReactivePower(this); + SinglePhaseMeter.calculateSinglePhaseFromCurrent(this); + SinglePhaseMeter.calculateSinglePhaseFromVoltage(this); + } + + @Activate + private void activate(ComponentContext context, Config config) throws OpenemsException { + this.config = config; + if (super.activate(context, config.id(), config.alias(), config.enabled(), config.modbusUnitId(), this.cm, + "Modbus", config.modbus_id())) { + return; + } + } + + @Override + @Deactivate + protected void deactivate() { + super.deactivate(); + } + + @Override + public MeterType getMeterType() { + return this.config.type(); + } + + @Override + protected ModbusProtocol defineModbusProtocol() { + final var offset = 30001; + final var invert = this.config.invert(); + + return new ModbusProtocol(this, // + new FC4ReadInputRegistersTask(30001 - offset, Priority.HIGH, // + m(ElectricityMeter.ChannelId.VOLTAGE, new FloatDoublewordElement(30001 - offset), + SCALE_FACTOR_3), // + new DummyRegisterElement(30003 - offset, 30006 - offset), // + m(ElectricityMeter.ChannelId.CURRENT, new FloatDoublewordElement(30007 - offset), + chain(SCALE_FACTOR_3, INVERT_IF_TRUE(invert))), // + new DummyRegisterElement(30009 - offset, 30012 - offset), // + m(ElectricityMeter.ChannelId.ACTIVE_POWER, new FloatDoublewordElement(30013 - offset), + INVERT_IF_TRUE(invert)), // + new DummyRegisterElement(30015 - offset, 30024 - offset), // + m(ElectricityMeter.ChannelId.REACTIVE_POWER, new FloatDoublewordElement(30025 - offset), + INVERT_IF_TRUE(invert)), // + new DummyRegisterElement(30027 - offset, 30070 - offset), // + m(ElectricityMeter.ChannelId.FREQUENCY, new FloatDoublewordElement(30071 - offset), + SCALE_FACTOR_3))); + } + + @Override + public String debugLog() { + return "L:" + this.getActivePower().asString(); + } + + @Override + public ModbusSlaveTable getModbusSlaveTable(AccessMode accessMode) { + return new ModbusSlaveTable(// + OpenemsComponent.getModbusSlaveNatureTable(accessMode), // + ElectricityMeter.getModbusSlaveNatureTable(accessMode), // + SinglePhaseMeter.getModbusSlaveNatureTable(accessMode) // + ); + } + + @Override + public Timedata getTimedata() { + return this.timedata; + } + + @Override + public void handleEvent(Event event) { + if (!this.isEnabled()) { + return; + } + switch (event.getTopic()) { + case EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE -> this.calculateEnergy(); + } + } + + /** + * Calculate the Energy values from ActivePower. + */ + private void calculateEnergy() { + // Calculate Energy + final var activePower = this.getActivePower().get(); + if (activePower == null) { + this.calculateProductionEnergy.update(null); + this.calculateConsumptionEnergy.update(null); + } else if (activePower >= 0) { + this.calculateProductionEnergy.update(activePower); + this.calculateConsumptionEnergy.update(0); + } else { + this.calculateProductionEnergy.update(0); + this.calculateConsumptionEnergy.update(-activePower); + } + } + + @Override + public SinglePhase getPhase() { + return this.config.phase(); + } +} diff --git a/io.openems.edge.meter.microcare.sdm630/src/io/openems/edge/meter/microcare/sdm630/Config.java b/io.openems.edge.meter.eastron/src/io/openems/edge/meter/eastron/sdm630/Config.java similarity index 86% rename from io.openems.edge.meter.microcare.sdm630/src/io/openems/edge/meter/microcare/sdm630/Config.java rename to io.openems.edge.meter.eastron/src/io/openems/edge/meter/eastron/sdm630/Config.java index 2d663d771b8..072294858f1 100644 --- a/io.openems.edge.meter.microcare.sdm630/src/io/openems/edge/meter/microcare/sdm630/Config.java +++ b/io.openems.edge.meter.eastron/src/io/openems/edge/meter/eastron/sdm630/Config.java @@ -1,12 +1,12 @@ -package io.openems.edge.meter.microcare.sdm630; +package io.openems.edge.meter.eastron.sdm630; import org.osgi.service.metatype.annotations.AttributeDefinition; import org.osgi.service.metatype.annotations.ObjectClassDefinition; import io.openems.edge.meter.api.MeterType; -@ObjectClassDefinition(name = "Meter Microcare SDM 630", // - description = "Implements the Microcare SDM630 meter.") +@ObjectClassDefinition(name = "Meter Eastron SDM 630", // + description = "Implements the Eastron SDM630 meter.") @interface Config { @AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component") @@ -30,5 +30,5 @@ @AttributeDefinition(name = "Modbus target filter", description = "This is auto-generated by 'Modbus-ID'.") String Modbus_target() default "(enabled=true)"; - String webconsole_configurationFactory_nameHint() default "Meter Microcare SDM 630 [{id}]"; + String webconsole_configurationFactory_nameHint() default "Meter Eastron SDM 630 [{id}]"; } \ No newline at end of file diff --git a/io.openems.edge.meter.microcare.sdm630/src/io/openems/edge/meter/microcare/sdm630/MeterMicrocareSdm630.java b/io.openems.edge.meter.eastron/src/io/openems/edge/meter/eastron/sdm630/MeterEastronSdm630.java similarity index 83% rename from io.openems.edge.meter.microcare.sdm630/src/io/openems/edge/meter/microcare/sdm630/MeterMicrocareSdm630.java rename to io.openems.edge.meter.eastron/src/io/openems/edge/meter/eastron/sdm630/MeterEastronSdm630.java index 269595affb5..344f1703832 100644 --- a/io.openems.edge.meter.microcare.sdm630/src/io/openems/edge/meter/microcare/sdm630/MeterMicrocareSdm630.java +++ b/io.openems.edge.meter.eastron/src/io/openems/edge/meter/eastron/sdm630/MeterEastronSdm630.java @@ -1,4 +1,4 @@ -package io.openems.edge.meter.microcare.sdm630; +package io.openems.edge.meter.eastron.sdm630; import io.openems.common.channel.Unit; import io.openems.common.types.OpenemsType; @@ -7,7 +7,7 @@ import io.openems.edge.common.modbusslave.ModbusSlave; import io.openems.edge.meter.api.ElectricityMeter; -public interface MeterMicrocareSdm630 extends ElectricityMeter, OpenemsComponent, ModbusSlave { +public interface MeterEastronSdm630 extends ElectricityMeter, OpenemsComponent, ModbusSlave { public enum ChannelId implements io.openems.edge.common.channel.ChannelId { REACTIVE_PRODUCTION_ENERGY(Doc.of(OpenemsType.INTEGER) // diff --git a/io.openems.edge.meter.microcare.sdm630/src/io/openems/edge/meter/microcare/sdm630/MeterMicrocareSdm630Impl.java b/io.openems.edge.meter.eastron/src/io/openems/edge/meter/eastron/sdm630/MeterEastronSdm630Impl.java similarity index 95% rename from io.openems.edge.meter.microcare.sdm630/src/io/openems/edge/meter/microcare/sdm630/MeterMicrocareSdm630Impl.java rename to io.openems.edge.meter.eastron/src/io/openems/edge/meter/eastron/sdm630/MeterEastronSdm630Impl.java index b0d8cf50337..b636a7f42da 100644 --- a/io.openems.edge.meter.microcare.sdm630/src/io/openems/edge/meter/microcare/sdm630/MeterMicrocareSdm630Impl.java +++ b/io.openems.edge.meter.eastron/src/io/openems/edge/meter/eastron/sdm630/MeterEastronSdm630Impl.java @@ -1,4 +1,4 @@ -package io.openems.edge.meter.microcare.sdm630; +package io.openems.edge.meter.eastron.sdm630; import static io.openems.edge.bridge.modbus.api.ElementToChannelConverter.DIRECT_1_TO_1; import static io.openems.edge.bridge.modbus.api.ElementToChannelConverter.SCALE_FACTOR_3; @@ -41,6 +41,7 @@ import io.openems.edge.timedata.api.TimedataProvider; import io.openems.edge.timedata.api.utils.CalculateEnergyFromPower; +// NOTE: we stick with the name `Meter.Microcare.SDM630` for backwards compatibility @Designate(ocd = Config.class, factory = true) @Component(// name = "Meter.Microcare.SDM630", // @@ -50,7 +51,7 @@ @EventTopics({ // EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE // }) -public class MeterMicrocareSdm630Impl extends AbstractOpenemsModbusComponent implements MeterMicrocareSdm630, +public class MeterEastronSdm630Impl extends AbstractOpenemsModbusComponent implements MeterEastronSdm630, ElectricityMeter, ModbusComponent, OpenemsComponent, ModbusSlave, TimedataProvider, EventHandler { private final CalculateEnergyFromPower calculateProductionEnergy = new CalculateEnergyFromPower(this, @@ -72,12 +73,12 @@ protected void setModbus(BridgeModbus modbus) { super.setModbus(modbus); } - public MeterMicrocareSdm630Impl() { + public MeterEastronSdm630Impl() { super(// OpenemsComponent.ChannelId.values(), // ModbusComponent.ChannelId.values(), // ElectricityMeter.ChannelId.values(), // - MeterMicrocareSdm630.ChannelId.values() // + MeterEastronSdm630.ChannelId.values() // ); // Automatically calculate sum values from L1/L2/L3 @@ -179,11 +180,11 @@ protected ModbusProtocol defineModbusProtocol() { .byteOrder(ByteOrder.BIG_ENDIAN), DIRECT_1_TO_1), new DummyRegisterElement(30073 - offset, 30076 - offset), // - m(MeterMicrocareSdm630.ChannelId.REACTIVE_PRODUCTION_ENERGY, + m(MeterEastronSdm630.ChannelId.REACTIVE_PRODUCTION_ENERGY, new FloatDoublewordElement(30077 - offset).wordOrder(WordOrder.MSWLSW) .byteOrder(ByteOrder.BIG_ENDIAN), SCALE_FACTOR_3), - m(MeterMicrocareSdm630.ChannelId.REACTIVE_CONSUMPTION_ENERGY, + m(MeterEastronSdm630.ChannelId.REACTIVE_CONSUMPTION_ENERGY, new FloatDoublewordElement(30079 - offset).wordOrder(WordOrder.MSWLSW) .byteOrder(ByteOrder.BIG_ENDIAN), SCALE_FACTOR_3))); diff --git a/io.openems.edge.meter.microcare.sdm630/test/.gitignore b/io.openems.edge.meter.eastron/test/.gitignore similarity index 100% rename from io.openems.edge.meter.microcare.sdm630/test/.gitignore rename to io.openems.edge.meter.eastron/test/.gitignore diff --git a/io.openems.edge.meter.eastron/test/io/openems/edge/meter/eastron/sdm120/MeterEastronSdm120ImplTest.java b/io.openems.edge.meter.eastron/test/io/openems/edge/meter/eastron/sdm120/MeterEastronSdm120ImplTest.java new file mode 100644 index 00000000000..169778c8b20 --- /dev/null +++ b/io.openems.edge.meter.eastron/test/io/openems/edge/meter/eastron/sdm120/MeterEastronSdm120ImplTest.java @@ -0,0 +1,29 @@ +package io.openems.edge.meter.eastron.sdm120; + +import org.junit.Test; + +import io.openems.edge.bridge.modbus.test.DummyModbusBridge; +import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.common.test.DummyConfigurationAdmin; +import io.openems.edge.meter.api.MeterType; +import io.openems.edge.meter.api.SinglePhase; + +public class MeterEastronSdm120ImplTest { + + private static final String METER_ID = "meter0"; + private static final String MODBUS_ID = "modbus0"; + + @Test + public void test() throws Exception { + new ComponentTest(new MeterEastronSdm120Impl()) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .activate(MyConfig.create() // + .setId(METER_ID) // + .setModbusId(MODBUS_ID) // + .setType(MeterType.GRID) // + .setPhase(SinglePhase.L1) // + .build()) // + ; + } +} \ No newline at end of file diff --git a/io.openems.edge.meter.eastron/test/io/openems/edge/meter/eastron/sdm120/MyConfig.java b/io.openems.edge.meter.eastron/test/io/openems/edge/meter/eastron/sdm120/MyConfig.java new file mode 100644 index 00000000000..f1e83072c87 --- /dev/null +++ b/io.openems.edge.meter.eastron/test/io/openems/edge/meter/eastron/sdm120/MyConfig.java @@ -0,0 +1,98 @@ +package io.openems.edge.meter.eastron.sdm120; + +import io.openems.common.test.AbstractComponentConfig; +import io.openems.common.utils.ConfigUtils; +import io.openems.edge.meter.api.MeterType; +import io.openems.edge.meter.api.SinglePhase; + +@SuppressWarnings("all") +public class MyConfig extends AbstractComponentConfig implements Config { + + protected static class Builder { + private String id; + private String modbusId; + private int modbusUnitId; + private MeterType type; + private SinglePhase phase; + private boolean invert; + + private Builder() { + } + + public Builder setId(String id) { + this.id = id; + return this; + } + + public Builder setModbusId(String modbusId) { + this.modbusId = modbusId; + return this; + } + + public Builder setType(MeterType type) { + this.type = type; + return this; + } + + public Builder setPhase(SinglePhase phase) { + this.phase = phase; + return this; + } + + public Builder setInvert(boolean invert) { + this.invert = invert; + return this; + } + + public MyConfig build() { + return new MyConfig(this); + } + } + + /** + * Create a Config builder. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new Builder(); + } + + private final Builder builder; + + private MyConfig(Builder builder) { + super(Config.class, builder.id); + this.builder = builder; + } + + @Override + public String modbus_id() { + return this.builder.modbusId; + } + + @Override + public String Modbus_target() { + return ConfigUtils.generateReferenceTargetFilter(this.id(), this.modbus_id()); + } + + @Override + public int modbusUnitId() { + return this.builder.modbusUnitId; + } + + @Override + public MeterType type() { + return this.builder.type; + } + + @Override + public boolean invert() { + return this.builder.invert; + } + + @Override + public SinglePhase phase() { + return this.builder.phase; + } + +} \ No newline at end of file diff --git a/io.openems.edge.meter.microcare.sdm630/test/io/openems/edge/meter/microcare/sdm630/MeterMicrocareSdm630ImplTest.java b/io.openems.edge.meter.eastron/test/io/openems/edge/meter/eastron/sdm630/MeterEastronSdm630ImplTest.java similarity index 82% rename from io.openems.edge.meter.microcare.sdm630/test/io/openems/edge/meter/microcare/sdm630/MeterMicrocareSdm630ImplTest.java rename to io.openems.edge.meter.eastron/test/io/openems/edge/meter/eastron/sdm630/MeterEastronSdm630ImplTest.java index 64b02b4862b..d79ef87a631 100644 --- a/io.openems.edge.meter.microcare.sdm630/test/io/openems/edge/meter/microcare/sdm630/MeterMicrocareSdm630ImplTest.java +++ b/io.openems.edge.meter.eastron/test/io/openems/edge/meter/eastron/sdm630/MeterEastronSdm630ImplTest.java @@ -1,4 +1,4 @@ -package io.openems.edge.meter.microcare.sdm630; +package io.openems.edge.meter.eastron.sdm630; import org.junit.Test; @@ -7,14 +7,14 @@ import io.openems.edge.common.test.DummyConfigurationAdmin; import io.openems.edge.meter.api.MeterType; -public class MeterMicrocareSdm630ImplTest { +public class MeterEastronSdm630ImplTest { private static final String METER_ID = "meter0"; private static final String MODBUS_ID = "modbus0"; @Test public void test() throws Exception { - new ComponentTest(new MeterMicrocareSdm630Impl()) // + new ComponentTest(new MeterEastronSdm630Impl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // .activate(MyConfig.create() // diff --git a/io.openems.edge.meter.microcare.sdm630/test/io/openems/edge/meter/microcare/sdm630/MyConfig.java b/io.openems.edge.meter.eastron/test/io/openems/edge/meter/eastron/sdm630/MyConfig.java similarity index 96% rename from io.openems.edge.meter.microcare.sdm630/test/io/openems/edge/meter/microcare/sdm630/MyConfig.java rename to io.openems.edge.meter.eastron/test/io/openems/edge/meter/eastron/sdm630/MyConfig.java index 918f6b2339b..d686ca017c8 100644 --- a/io.openems.edge.meter.microcare.sdm630/test/io/openems/edge/meter/microcare/sdm630/MyConfig.java +++ b/io.openems.edge.meter.eastron/test/io/openems/edge/meter/eastron/sdm630/MyConfig.java @@ -1,4 +1,4 @@ -package io.openems.edge.meter.microcare.sdm630; +package io.openems.edge.meter.eastron.sdm630; import io.openems.common.test.AbstractComponentConfig; import io.openems.common.utils.ConfigUtils; From 5d1a04fa5ab81d05ba7a189a71fe2d27baaa45bb Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Thu, 2 May 2024 12:10:53 +0200 Subject: [PATCH 009/173] Push version to 2024.5.0 --- io.openems.common/src/io/openems/common/OpenemsConstants.java | 2 +- tools/common.sh | 4 ++-- ui/package-lock.json | 4 ++-- ui/package.json | 2 +- ui/src/app/changelog/view/component/changelog.constants.ts | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/io.openems.common/src/io/openems/common/OpenemsConstants.java b/io.openems.common/src/io/openems/common/OpenemsConstants.java index 407317327cc..4597a187f45 100644 --- a/io.openems.common/src/io/openems/common/OpenemsConstants.java +++ b/io.openems.common/src/io/openems/common/OpenemsConstants.java @@ -36,7 +36,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/tools/common.sh b/tools/common.sh index f3f937fa62a..598a8341fb5 100644 --- a/tools/common.sh +++ b/tools/common.sh @@ -53,10 +53,10 @@ common_update_version_in_code() { sed --in-place "s#\(VERSION_DEV_BUILD_TIME = \)\"\(.*\)\";#\1\"$VERSION_DEV_BUILD_TIME\";#" $SRC_OPENEMS_CONSTANTS echo "## Update $SRC_PACKAGE_JSON" - sed --in-place "s#^\( \"version\": \"\).*\(\".*$\)#\1$VERSION\2#" $SRC_PACKAGE_JSON + sed --in-place "s#^\( \"version\": \"\).*\(\".*$\)#\1$VERSION\2#" $SRC_PACKAGE_JSON echo "## Update $SRC_PACKAGE_LOCK_JSON" - sed --in-place "s#^\( \"version\": \"\).*\(\".*$\)#\1$VERSION\2#" $SRC_PACKAGE_LOCK_JSON + sed --in-place "s#^\( \"version\": \"\).*\(\".*$\)#\1$VERSION\2#" $SRC_PACKAGE_LOCK_JSON echo "## Update $SRC_CHANGELOG_CONSTANTS" sed --in-place "s#\(UI_VERSION = \"\).*\(\";\)#\1$VERSION\2#" $SRC_CHANGELOG_CONSTANTS diff --git a/ui/package-lock.json b/ui/package-lock.json index 90fc27fd10a..4b739a860c4 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "openems-ui", - "version": "2024.5.0-SNAPSHOT", + "version": "2024.5.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "openems-ui", - "version": "2024.5.0-SNAPSHOT", + "version": "2024.5.0", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "~16.2.12", diff --git a/ui/package.json b/ui/package.json index 9bceb0ddfaf..6d98a3e50e9 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,6 +1,6 @@ { "name": "openems-ui", - "version": "2024.5.0-SNAPSHOT", + "version": "2024.5.0", "license": "AGPL-3.0", "private": true, "dependencies": { diff --git a/ui/src/app/changelog/view/component/changelog.constants.ts b/ui/src/app/changelog/view/component/changelog.constants.ts index 3966ef1c06e..fd9fa77b986 100644 --- a/ui/src/app/changelog/view/component/changelog.constants.ts +++ b/ui/src/app/changelog/view/component/changelog.constants.ts @@ -2,7 +2,7 @@ import { Role } from "src/app/shared/type/role"; export class Changelog { - public static readonly UI_VERSION = "2024.5.0-SNAPSHOT"; + public static readonly UI_VERSION = "2024.5.0"; public static product(...products: Product[]) { return products.map(product => Changelog.link(product.name, product.url)).join(", ") + '. '; From 35b69e53d636e7b221accdd3833a6e75bc844ba5 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Thu, 2 May 2024 12:14:02 +0200 Subject: [PATCH 010/173] Start development of version 2024.6.0-SNAPSHOT --- io.openems.common/src/io/openems/common/OpenemsConstants.java | 4 ++-- ui/package-lock.json | 4 ++-- ui/package.json | 2 +- ui/src/app/changelog/view/component/changelog.constants.ts | 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 4597a187f45..b016110bb8c 100644 --- a/io.openems.common/src/io/openems/common/OpenemsConstants.java +++ b/io.openems.common/src/io/openems/common/OpenemsConstants.java @@ -22,7 +22,7 @@ public class OpenemsConstants { *

    * This is the month of the release. */ - public static final short VERSION_MINOR = 5; + public static final short VERSION_MINOR = 6; /** * The patch version of OpenEMS. @@ -36,7 +36,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 4b739a860c4..dc5afee6e67 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "openems-ui", - "version": "2024.5.0", + "version": "2024.6.0-SNAPSHOT", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "openems-ui", - "version": "2024.5.0", + "version": "2024.6.0-SNAPSHOT", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "~16.2.12", diff --git a/ui/package.json b/ui/package.json index 6d98a3e50e9..74e887f0f23 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,6 +1,6 @@ { "name": "openems-ui", - "version": "2024.5.0", + "version": "2024.6.0-SNAPSHOT", "license": "AGPL-3.0", "private": true, "dependencies": { diff --git a/ui/src/app/changelog/view/component/changelog.constants.ts b/ui/src/app/changelog/view/component/changelog.constants.ts index fd9fa77b986..a41211bc7ca 100644 --- a/ui/src/app/changelog/view/component/changelog.constants.ts +++ b/ui/src/app/changelog/view/component/changelog.constants.ts @@ -2,7 +2,7 @@ import { Role } from "src/app/shared/type/role"; export class Changelog { - public static readonly UI_VERSION = "2024.5.0"; + public static readonly UI_VERSION = "2024.6.0-SNAPSHOT"; public static product(...products: Product[]) { return products.map(product => Changelog.link(product.name, product.url)).join(", ") + '. '; From 3edf920f9115fc925c7d89f4c075fa3c8f48daad Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 May 2024 09:49:28 +0200 Subject: [PATCH 011/173] Bump com.google.guava:guava from 33.1.0-jre to 33.2.0-jre in /cnf (#2632) * Bump com.google.guava:guava from 33.1.0-jre to 33.2.0-jre in /cnf Bumps [com.google.guava:guava](https://github.com/google/guava) from 33.1.0-jre to 33.2.0-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-minor ... Signed-off-by: dependabot[bot] * Update bnd+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 | 2 +- cnf/pom.xml | 2 +- io.openems.backend.application/BackendApp.bndrun | 2 +- io.openems.edge.application/EdgeApp.bndrun | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cnf/build.bnd b/cnf/build.bnd index f2e77d03885..3c42895f80c 100644 --- a/cnf/build.bnd +++ b/cnf/build.bnd @@ -40,7 +40,7 @@ buildpath: \ org.osgi.service.metatype;version='1.4.1',\ org.osgi.service.metatype.annotations;version='1.4.1',\ org.osgi.util.promise;version='1.2.0',\ - com.google.guava;version='33.1.0.jre',\ + com.google.guava;version='33.2.0.jre',\ com.google.gson;version='2.10.1',\ testpath: \ diff --git a/cnf/pom.xml b/cnf/pom.xml index 85ce8d8a776..cea309899fd 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -38,7 +38,7 @@ com.google.guava guava - 33.1.0-jre + 33.2.0-jre com.google.guava diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index 93014f953ba..4f46a16cab0 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -61,7 +61,7 @@ -runbundles: \ Java-WebSocket;version='[1.5.4,1.5.5)',\ com.google.gson;version='[2.10.1,2.10.2)',\ - com.google.guava;version='[33.1.0,33.1.1)',\ + com.google.guava;version='[33.2.0,33.2.1)',\ com.google.guava.failureaccess;version='[1.0.2,1.0.3)',\ com.squareup.okio;version='[3.9.0,3.9.1)',\ com.zaxxer.HikariCP;version='[5.1.0,5.1.1)',\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index 0e5c289c8f1..d067945f4e0 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -195,7 +195,7 @@ com.fazecast.jSerialComm;version='[2.10.4,2.10.5)',\ com.ghgande.j2mod;version='[3.2.1,3.2.2)',\ com.google.gson;version='[2.10.1,2.10.2)',\ - com.google.guava;version='[33.1.0,33.1.1)',\ + com.google.guava;version='[33.2.0,33.2.1)',\ com.google.guava.failureaccess;version='[1.0.2,1.0.3)',\ com.squareup.okio;version='[3.9.0,3.9.1)',\ com.sun.jna;version='[5.14.0,5.14.1)',\ From 1bf531fcb0f9bffc4b2d3218b9738d3eed2c53b9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 May 2024 13:12:51 +0200 Subject: [PATCH 012/173] Bump org.apache.felix:org.apache.felix.http.jetty from 5.1.10 to 5.1.12 in /cnf (#2631) * Bump org.apache.felix:org.apache.felix.http.jetty in /cnf Bumps org.apache.felix:org.apache.felix.http.jetty from 5.1.10 to 5.1.12. --- updated-dependencies: - dependency-name: org.apache.felix:org.apache.felix.http.jetty 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 cea309899fd..69d37dd48f0 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -203,7 +203,7 @@ org.apache.felix org.apache.felix.http.jetty - 5.1.10 + 5.1.12 diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index 4f46a16cab0..ff19a98eb97 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -104,7 +104,7 @@ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ org.apache.felix.eventadmin;version='[1.6.4,1.6.5)',\ org.apache.felix.fileinstall;version='[3.7.4,3.7.5)',\ - org.apache.felix.http.jetty;version='[5.1.10,5.1.11)',\ + org.apache.felix.http.jetty;version='[5.1.12,5.1.13)',\ org.apache.felix.http.servlet-api;version='[3.0.0,3.0.1)',\ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index d067945f4e0..ed67e7b0e75 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -392,7 +392,7 @@ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ org.apache.felix.eventadmin;version='[1.6.4,1.6.5)',\ org.apache.felix.fileinstall;version='[3.7.4,3.7.5)',\ - org.apache.felix.http.jetty;version='[5.1.10,5.1.11)',\ + org.apache.felix.http.jetty;version='[5.1.12,5.1.13)',\ org.apache.felix.http.servlet-api;version='[3.0.0,3.0.1)',\ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ From a74e9024645f4c687b17d2f61329c9a377eeada1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 May 2024 13:34:13 +0200 Subject: [PATCH 013/173] Bump @ngx-translate/core from 14.0.0 to 15.0.0 in /ui (#2626) Bumps [@ngx-translate/core](https://github.com/ngx-translate/core) from 14.0.0 to 15.0.0. - [Release notes](https://github.com/ngx-translate/core/releases) - [Commits](https://github.com/ngx-translate/core/compare/v14.0.0...v15.0.0) --- updated-dependencies: - dependency-name: "@ngx-translate/core" dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 16 +++++++++------- ui/package.json | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index dc5afee6e67..6c34cece401 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -21,7 +21,7 @@ "@ngx-formly/core": "^6.3.0", "@ngx-formly/ionic": "^6.3.0", "@ngx-formly/schematics": "^6.3.0", - "@ngx-translate/core": "^14.0.0", + "@ngx-translate/core": "^15.0.0", "@nodro7/angular-mydatepicker": "^0.14.0", "chart.js": "^4.4.2", "chartjs-adapter-date-fns": "^3.0.0", @@ -3351,14 +3351,16 @@ } }, "node_modules/@ngx-translate/core": { - "version": "14.0.0", - "license": "MIT", - "dependencies": { - "tslib": "^2.3.0" + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-15.0.0.tgz", + "integrity": "sha512-Am5uiuR0bOOxyoercDnAA3rJVizo4RRqJHo8N3RqJ+XfzVP/I845yEnMADykOHvM6HkVm4SZSnJBOiz0Anx5BA==", + "engines": { + "node": "^16.13.0 || >=18.10.0" }, "peerDependencies": { - "@angular/core": ">=13.0.0", - "rxjs": "^6.5.3 || ^7.4.0" + "@angular/common": ">=16.0.0", + "@angular/core": ">=16.0.0", + "rxjs": "^6.5.5 || ^7.4.0" } }, "node_modules/@nodelib/fs.scandir": { diff --git a/ui/package.json b/ui/package.json index 74e887f0f23..2061085f7d6 100644 --- a/ui/package.json +++ b/ui/package.json @@ -16,7 +16,7 @@ "@ngx-formly/core": "^6.3.0", "@ngx-formly/ionic": "^6.3.0", "@ngx-formly/schematics": "^6.3.0", - "@ngx-translate/core": "^14.0.0", + "@ngx-translate/core": "^15.0.0", "@nodro7/angular-mydatepicker": "^0.14.0", "chart.js": "^4.4.2", "chartjs-adapter-date-fns": "^3.0.0", From a64e975debd38765bb9ffc2d3c0d61ed9874191d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 May 2024 13:48:05 +0200 Subject: [PATCH 014/173] Bump typescript-strict-plugin from 2.4.1 to 2.4.3 in /ui (#2634) Bumps [typescript-strict-plugin](https://github.com/allegro/typescript-strict-plugin) from 2.4.1 to 2.4.3. - [Release notes](https://github.com/allegro/typescript-strict-plugin/releases) - [Changelog](https://github.com/allegro/typescript-strict-plugin/blob/master/CHANGELOG.md) - [Commits](https://github.com/allegro/typescript-strict-plugin/commits) --- updated-dependencies: - dependency-name: typescript-strict-plugin dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 7 ++++--- ui/package.json | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 6c34cece401..7e553bcddb9 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -74,7 +74,7 @@ "protractor": "~7.0.0", "ts-node": "^10.9.2", "typescript": "~4.9.5", - "typescript-strict-plugin": "^2.4.1" + "typescript-strict-plugin": "^2.4.3" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -16127,9 +16127,10 @@ } }, "node_modules/typescript-strict-plugin": { - "version": "2.4.1", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/typescript-strict-plugin/-/typescript-strict-plugin-2.4.3.tgz", + "integrity": "sha512-xKdyZGKg3Sy4tPU+b0U1DuxsDoCpMbu41iQvibTPiVjdZJvtG7Ou04a9NpEWuV/Dho8Xo3c34WmROtkHZe0pkg==", "dev": true, - "license": "MIT", "dependencies": { "chalk": "^3.0.0", "execa": "^4.0.0", diff --git a/ui/package.json b/ui/package.json index 2061085f7d6..6a92624d243 100644 --- a/ui/package.json +++ b/ui/package.json @@ -69,7 +69,7 @@ "protractor": "~7.0.0", "ts-node": "^10.9.2", "typescript": "~4.9.5", - "typescript-strict-plugin": "^2.4.1" + "typescript-strict-plugin": "^2.4.3" }, "scripts": { "lint": "ng lint", From 4c6904c44e8d57d11dbbfc842611f8f81625e176 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 May 2024 13:54:01 +0200 Subject: [PATCH 015/173] Bump ejs from 3.1.9 to 3.1.10 in /ui (#2629) Bumps [ejs](https://github.com/mde/ejs) from 3.1.9 to 3.1.10. - [Release notes](https://github.com/mde/ejs/releases) - [Commits](https://github.com/mde/ejs/compare/v3.1.9...v3.1.10) --- updated-dependencies: - dependency-name: ejs dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 7e553bcddb9..7de2b74e6c4 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -7423,9 +7423,10 @@ "license": "MIT" }, "node_modules/ejs": { - "version": "3.1.9", + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", "dev": true, - "license": "Apache-2.0", "dependencies": { "jake": "^10.8.5" }, From 802eb3967518f087db756acee81d4d2783600d07 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 May 2024 14:23:10 +0200 Subject: [PATCH 016/173] Bump vite and @angular-devkit/build-angular in /ui (#2624) Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) to 4.5.3 and updates ancestor dependency [@angular-devkit/build-angular](https://github.com/angular/angular-cli). These dependencies need to be updated together. Updates `vite` from 4.5.2 to 4.5.3 - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/v4.5.3/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v4.5.3/packages/vite) Updates `@angular-devkit/build-angular` from 16.2.13 to 16.2.14 - [Release notes](https://github.com/angular/angular-cli/releases) - [Changelog](https://github.com/angular/angular-cli/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular-cli/compare/16.2.13...16.2.14) --- updated-dependencies: - dependency-name: vite dependency-type: indirect - dependency-name: "@angular-devkit/build-angular" dependency-type: direct:development ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 538 +++++++++++++++++++++++++++++++------------ ui/package.json | 2 +- 2 files changed, 390 insertions(+), 150 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 7de2b74e6c4..d830901e711 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -42,7 +42,7 @@ "zone.js": "~0.13.3" }, "devDependencies": { - "@angular-devkit/build-angular": "^16.2.13", + "@angular-devkit/build-angular": "^16.2.14", "@angular-eslint/builder": "^16.3.1", "@angular-eslint/eslint-plugin": "^16.3.1", "@angular-eslint/eslint-plugin-template": "^16.3.1", @@ -120,14 +120,15 @@ } }, "node_modules/@angular-devkit/build-angular": { - "version": "16.2.13", + "version": "16.2.14", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-16.2.14.tgz", + "integrity": "sha512-bXQ6i7QPhwmYHuh+DSNkBhjTIHQF0C6fqZEg2ApJA3NmnzE98oQnmJ9AnGnAkdf1Mjn3xi2gxoZWPDDxGEINMw==", "dev": true, - "license": "MIT", "dependencies": { "@ampproject/remapping": "2.2.1", - "@angular-devkit/architect": "0.1602.13", - "@angular-devkit/build-webpack": "0.1602.13", - "@angular-devkit/core": "16.2.13", + "@angular-devkit/architect": "0.1602.14", + "@angular-devkit/build-webpack": "0.1602.14", + "@angular-devkit/core": "16.2.14", "@babel/core": "7.22.9", "@babel/generator": "7.22.9", "@babel/helper-annotate-as-pure": "7.22.5", @@ -139,7 +140,7 @@ "@babel/runtime": "7.22.6", "@babel/template": "7.22.5", "@discoveryjs/json-ext": "0.5.7", - "@ngtools/webpack": "16.2.13", + "@ngtools/webpack": "16.2.14", "@vitejs/plugin-basic-ssl": "1.0.1", "ansi-colors": "4.1.3", "autoprefixer": "10.4.14", @@ -182,7 +183,7 @@ "text-table": "0.2.0", "tree-kill": "1.2.2", "tslib": "2.6.1", - "vite": "4.5.2", + "vite": "4.5.3", "webpack": "5.88.2", "webpack-dev-middleware": "6.1.2", "webpack-dev-server": "4.15.1", @@ -252,6 +253,79 @@ "node": ">=6.0.0" } }, + "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/architect": { + "version": "0.1602.14", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.14.tgz", + "integrity": "sha512-eSdONEV5dbtLNiOMBy9Ue9DdJ1ct6dH9RdZfYiedq6VZn0lejePAjY36MYVXgq2jTE+v/uIiaNy7caea5pt55A==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "16.2.14", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core": { + "version": "16.2.14", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.14.tgz", + "integrity": "sha512-Ui14/d2+p7lnmXlK/AX2ieQEGInBV75lonNtPQgwrYgskF8ufCuN0DyVZQUy9fJDkC+xQxbJyYrby/BS0R0e7w==", + "dev": true, + "dependencies": { + "ajv": "8.12.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.2.0", + "picomatch": "2.3.1", + "rxjs": "7.8.1", + "source-map": "0.7.4" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/@angular-devkit/build-angular/node_modules/@babel/core": { "version": "7.22.9", "dev": true, @@ -556,11 +630,12 @@ "license": "ISC" }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.1602.13", + "version": "0.1602.14", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1602.14.tgz", + "integrity": "sha512-f+ZTCjOoA1SCQEaX3L/63ubqr/vlHkwDXAtKjBsQgyz6srnETcjy96Us5k/LoK7/hPc85zFneqLinfqOMVWHJQ==", "dev": true, - "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.1602.13", + "@angular-devkit/architect": "0.1602.14", "rxjs": "7.8.1" }, "engines": { @@ -573,10 +648,59 @@ "webpack-dev-server": "^4.0.0" } }, + "node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/architect": { + "version": "0.1602.14", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.14.tgz", + "integrity": "sha512-eSdONEV5dbtLNiOMBy9Ue9DdJ1ct6dH9RdZfYiedq6VZn0lejePAjY36MYVXgq2jTE+v/uIiaNy7caea5pt55A==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "16.2.14", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/core": { + "version": "16.2.14", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.14.tgz", + "integrity": "sha512-Ui14/d2+p7lnmXlK/AX2ieQEGInBV75lonNtPQgwrYgskF8ufCuN0DyVZQUy9fJDkC+xQxbJyYrby/BS0R0e7w==", + "dev": true, + "dependencies": { + "ajv": "8.12.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.2.0", + "picomatch": "2.3.1", + "rxjs": "7.8.1", + "source-map": "0.7.4" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-webpack/node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, "node_modules/@angular-devkit/build-webpack/node_modules/rxjs": { "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, - "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -3214,13 +3338,15 @@ }, "node_modules/@leichtgewicht/ip-codec": { "version": "2.0.5", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "dev": true }, "node_modules/@ngtools/webpack": { - "version": "16.2.13", + "version": "16.2.14", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-16.2.14.tgz", + "integrity": "sha512-3+zPP3Wir46qrZ3FEiTz5/emSoVHYUCH+WgBmJ57mZCx1qBOYh2VgllnPr/Yusl1sc/jUZjdwq/es/9ZNw+zDQ==", "dev": true, - "license": "MIT", "engines": { "node": "^16.14.0 || >=18.10.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", @@ -3901,8 +4027,9 @@ }, "node_modules/@types/body-parser": { "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", "dev": true, - "license": "MIT", "dependencies": { "@types/connect": "*", "@types/node": "*" @@ -3910,24 +4037,27 @@ }, "node_modules/@types/bonjour": { "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/connect": { "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/connect-history-api-fallback": { "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", "dev": true, - "license": "MIT", "dependencies": { "@types/express-serve-static-core": "*", "@types/node": "*" @@ -3971,8 +4101,9 @@ }, "node_modules/@types/express": { "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", @@ -3982,8 +4113,9 @@ }, "node_modules/@types/express-serve-static-core": { "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz", + "integrity": "sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -3993,13 +4125,15 @@ }, "node_modules/@types/http-errors": { "version": "2.0.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true }, "node_modules/@types/http-proxy": { "version": "1.17.14", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", + "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -4029,8 +4163,9 @@ }, "node_modules/@types/mime": { "version": "1.3.5", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true }, "node_modules/@types/node": { "version": "20.12.7", @@ -4042,8 +4177,9 @@ }, "node_modules/@types/node-forge": { "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -4054,19 +4190,22 @@ "license": "MIT" }, "node_modules/@types/qs": { - "version": "6.9.14", - "dev": true, - "license": "MIT" + "version": "6.9.15", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", + "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", + "dev": true }, "node_modules/@types/range-parser": { "version": "1.2.7", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true }, "node_modules/@types/retry": { "version": "0.12.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true }, "node_modules/@types/selenium-webdriver": { "version": "3.0.26", @@ -4080,8 +4219,9 @@ }, "node_modules/@types/send": { "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", "dev": true, - "license": "MIT", "dependencies": { "@types/mime": "^1", "@types/node": "*" @@ -4089,16 +4229,18 @@ }, "node_modules/@types/serve-index": { "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", "dev": true, - "license": "MIT", "dependencies": { "@types/express": "*" } }, "node_modules/@types/serve-static": { "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", "dev": true, - "license": "MIT", "dependencies": { "@types/http-errors": "*", "@types/node": "*", @@ -4107,8 +4249,9 @@ }, "node_modules/@types/sockjs": { "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -4120,8 +4263,9 @@ }, "node_modules/@types/ws": { "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -5072,11 +5216,12 @@ }, "node_modules/ansi-html-community": { "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", "dev": true, "engines": [ "node >= 0.8.0" ], - "license": "Apache-2.0", "bin": { "ansi-html": "bin/ansi-html" } @@ -5174,8 +5319,9 @@ }, "node_modules/array-flatten": { "version": "1.1.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true }, "node_modules/array-includes": { "version": "3.1.7", @@ -5547,8 +5693,9 @@ }, "node_modules/batch": { "version": "0.6.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true }, "node_modules/bcrypt-pbkdf": { "version": "1.0.2", @@ -5654,8 +5801,9 @@ }, "node_modules/bonjour-service": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", + "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", "dev": true, - "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "multicast-dns": "^7.2.5" @@ -5809,8 +5957,9 @@ }, "node_modules/bytes": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -6147,8 +6296,9 @@ }, "node_modules/compressible": { "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", "dev": true, - "license": "MIT", "dependencies": { "mime-db": ">= 1.43.0 < 2" }, @@ -6158,8 +6308,9 @@ }, "node_modules/compression": { "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", "dev": true, - "license": "MIT", "dependencies": { "accepts": "~1.3.5", "bytes": "3.0.0", @@ -6175,21 +6326,24 @@ }, "node_modules/compression/node_modules/debug": { "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/compression/node_modules/ms": { "version": "2.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true }, "node_modules/compression/node_modules/safe-buffer": { "version": "5.1.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true }, "node_modules/concat-map": { "version": "0.0.1", @@ -6212,8 +6366,9 @@ }, "node_modules/connect-history-api-fallback": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.8" } @@ -6274,8 +6429,9 @@ }, "node_modules/content-disposition": { "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "dev": true, - "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" }, @@ -6298,16 +6454,18 @@ }, "node_modules/cookie": { "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/cookie-signature": { "version": "1.0.6", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true }, "node_modules/copy-anything": { "version": "2.0.6", @@ -7072,8 +7230,9 @@ }, "node_modules/default-gateway": { "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "execa": "^5.0.0" }, @@ -7260,8 +7419,9 @@ }, "node_modules/detect-node": { "version": "2.1.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true }, "node_modules/di": { "version": "0.0.1", @@ -7289,8 +7449,9 @@ }, "node_modules/dns-packet": { "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", "dev": true, - "license": "MIT", "dependencies": { "@leichtgewicht/ip-codec": "^2.0.1" }, @@ -8417,8 +8578,9 @@ }, "node_modules/etag": { "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -8443,8 +8605,9 @@ }, "node_modules/execa": { "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, - "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -8477,8 +8640,9 @@ }, "node_modules/express": { "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "dev": true, - "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", @@ -8518,16 +8682,18 @@ }, "node_modules/express/node_modules/debug": { "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/express/node_modules/ms": { "version": "2.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true }, "node_modules/extend": { "version": "3.0.2", @@ -8604,8 +8770,9 @@ }, "node_modules/faye-websocket": { "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", "dev": true, - "license": "Apache-2.0", "dependencies": { "websocket-driver": ">=0.5.1" }, @@ -8682,8 +8849,9 @@ }, "node_modules/finalhandler": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", "dev": true, - "license": "MIT", "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", @@ -8699,16 +8867,18 @@ }, "node_modules/finalhandler/node_modules/debug": { "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/finalhandler/node_modules/ms": { "version": "2.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true }, "node_modules/find-cache-dir": { "version": "4.0.0", @@ -8839,8 +9009,9 @@ }, "node_modules/forwarded": { "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -8859,8 +9030,9 @@ }, "node_modules/fresh": { "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -8912,6 +9084,20 @@ "dev": true, "license": "ISC" }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "dev": true, @@ -9007,8 +9193,9 @@ }, "node_modules/get-stream": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" }, @@ -9188,8 +9375,9 @@ }, "node_modules/handle-thing": { "version": "2.0.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true }, "node_modules/har-schema": { "version": "2.0.0", @@ -9365,8 +9553,9 @@ }, "node_modules/hpack.js": { "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", "dev": true, - "license": "MIT", "dependencies": { "inherits": "^2.0.1", "obuf": "^1.0.0", @@ -9376,8 +9565,9 @@ }, "node_modules/hpack.js/node_modules/readable-stream": { "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, - "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -9390,13 +9580,15 @@ }, "node_modules/hpack.js/node_modules/safe-buffer": { "version": "5.1.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true }, "node_modules/hpack.js/node_modules/string_decoder": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" } @@ -9414,6 +9606,8 @@ }, "node_modules/html-entities": { "version": "2.5.2", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", + "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", "dev": true, "funding": [ { @@ -9424,8 +9618,7 @@ "type": "patreon", "url": "https://patreon.com/mdevils" } - ], - "license": "MIT" + ] }, "node_modules/html-escaper": { "version": "2.0.2", @@ -9457,8 +9650,9 @@ }, "node_modules/http-deceiver": { "version": "1.2.7", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true }, "node_modules/http-errors": { "version": "2.0.0", @@ -9477,8 +9671,9 @@ }, "node_modules/http-parser-js": { "version": "0.5.8", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true }, "node_modules/http-proxy": { "version": "1.18.1", @@ -9508,8 +9703,9 @@ }, "node_modules/http-proxy-middleware": { "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", "dev": true, - "license": "MIT", "dependencies": { "@types/http-proxy": "^1.17.8", "http-proxy": "^1.18.1", @@ -9557,8 +9753,9 @@ }, "node_modules/human-signals": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=10.17.0" } @@ -9880,9 +10077,10 @@ "license": "BSD-3-Clause" }, "node_modules/ipaddr.js": { - "version": "2.1.0", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 10" } @@ -10134,8 +10332,9 @@ }, "node_modules/is-plain-obj": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" }, @@ -11120,8 +11319,9 @@ }, "node_modules/launch-editor": { "version": "2.6.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.1.tgz", + "integrity": "sha512-eB/uXmFVpY4zezmGp5XtU21kwo7GBbKB+EQ+UZeWtGb9yAM5xt/Evk+lYH3eRNAtId+ej4u7TYPFZ07w4s7rRw==", "dev": true, - "license": "MIT", "dependencies": { "picocolors": "^1.0.0", "shell-quote": "^1.8.1" @@ -11609,8 +11809,9 @@ }, "node_modules/merge-descriptors": { "version": "1.0.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true }, "node_modules/merge-stream": { "version": "2.0.0", @@ -11627,8 +11828,9 @@ }, "node_modules/methods": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -11702,8 +11904,9 @@ }, "node_modules/minimalistic-assert": { "version": "1.0.1", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true }, "node_modules/minimatch": { "version": "3.1.2", @@ -11951,8 +12154,9 @@ }, "node_modules/multicast-dns": { "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", "dev": true, - "license": "MIT", "dependencies": { "dns-packet": "^5.2.2", "thunky": "^1.0.2" @@ -12076,8 +12280,9 @@ }, "node_modules/node-forge": { "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", "dev": true, - "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { "node": ">= 6.13.0" } @@ -12797,8 +13002,9 @@ }, "node_modules/obuf": { "version": "1.1.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true }, "node_modules/on-finished": { "version": "2.4.1", @@ -12813,8 +13019,9 @@ }, "node_modules/on-headers": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -12996,8 +13203,9 @@ }, "node_modules/p-retry": { "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/retry": "0.12.0", "retry": "^0.13.1" @@ -13008,8 +13216,9 @@ }, "node_modules/p-retry/node_modules/retry": { "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 4" } @@ -13212,8 +13421,9 @@ }, "node_modules/path-to-regexp": { "version": "0.1.7", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true }, "node_modules/path-type": { "version": "4.0.0", @@ -13791,8 +14001,9 @@ }, "node_modules/proxy-addr": { "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "dev": true, - "license": "MIT", "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -13803,8 +14014,9 @@ }, "node_modules/proxy-addr/node_modules/ipaddr.js": { "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.10" } @@ -14581,8 +14793,9 @@ }, "node_modules/select-hose": { "version": "2.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true }, "node_modules/selenium-webdriver": { "version": "3.6.0", @@ -14641,8 +14854,9 @@ }, "node_modules/selfsigned": { "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", "dev": true, - "license": "MIT", "dependencies": { "@types/node-forge": "^1.3.0", "node-forge": "^1" @@ -14683,8 +14897,9 @@ }, "node_modules/send": { "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "dev": true, - "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -14706,21 +14921,24 @@ }, "node_modules/send/node_modules/debug": { "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/send/node_modules/debug/node_modules/ms": { "version": "2.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true }, "node_modules/send/node_modules/ms": { "version": "2.1.3", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true }, "node_modules/serialize-javascript": { "version": "6.0.2", @@ -14732,8 +14950,9 @@ }, "node_modules/serve-index": { "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", "dev": true, - "license": "MIT", "dependencies": { "accepts": "~1.3.4", "batch": "0.6.1", @@ -14749,24 +14968,27 @@ }, "node_modules/serve-index/node_modules/debug": { "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/serve-index/node_modules/depd": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/serve-index/node_modules/http-errors": { "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", "dev": true, - "license": "MIT", "dependencies": { "depd": "~1.1.2", "inherits": "2.0.3", @@ -14779,31 +15001,36 @@ }, "node_modules/serve-index/node_modules/inherits": { "version": "2.0.3", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true }, "node_modules/serve-index/node_modules/ms": { "version": "2.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true }, "node_modules/serve-index/node_modules/setprototypeof": { "version": "1.1.0", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true }, "node_modules/serve-index/node_modules/statuses": { "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/serve-static": { "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "dev": true, - "license": "MIT", "dependencies": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", @@ -14891,8 +15118,9 @@ }, "node_modules/shell-quote": { "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", "dev": true, - "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -15089,8 +15317,9 @@ }, "node_modules/sockjs": { "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", "dev": true, - "license": "MIT", "dependencies": { "faye-websocket": "^0.11.3", "uuid": "^8.3.2", @@ -15099,8 +15328,9 @@ }, "node_modules/sockjs/node_modules/uuid": { "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true, - "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } @@ -15218,8 +15448,9 @@ }, "node_modules/spdy": { "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", "dev": true, - "license": "MIT", "dependencies": { "debug": "^4.1.0", "handle-thing": "^2.0.0", @@ -15233,8 +15464,9 @@ }, "node_modules/spdy-transport": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", "dev": true, - "license": "MIT", "dependencies": { "debug": "^4.1.0", "detect-node": "^2.0.4", @@ -15720,8 +15952,9 @@ }, "node_modules/thunky": { "version": "1.1.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true }, "node_modules/tmp": { "version": "0.0.33", @@ -16536,9 +16769,10 @@ } }, "node_modules/vite": { - "version": "4.5.2", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.3.tgz", + "integrity": "sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==", "dev": true, - "license": "MIT", "dependencies": { "esbuild": "^0.18.10", "postcss": "^8.4.27", @@ -16630,8 +16864,9 @@ }, "node_modules/wbuf": { "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", "dev": true, - "license": "MIT", "dependencies": { "minimalistic-assert": "^1.0.0" } @@ -16856,8 +17091,9 @@ }, "node_modules/webpack-dev-server": { "version": "4.15.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", + "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", "dev": true, - "license": "MIT", "dependencies": { "@types/bonjour": "^3.5.9", "@types/connect-history-api-fallback": "^1.3.5", @@ -16914,8 +17150,9 @@ }, "node_modules/webpack-dev-server/node_modules/webpack-dev-middleware": { "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", "dev": true, - "license": "MIT", "dependencies": { "colorette": "^2.0.10", "memfs": "^3.4.3", @@ -16935,9 +17172,10 @@ } }, "node_modules/webpack-dev-server/node_modules/ws": { - "version": "8.16.0", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz", + "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==", "dev": true, - "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -17045,8 +17283,9 @@ }, "node_modules/websocket-driver": { "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", "dev": true, - "license": "Apache-2.0", "dependencies": { "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", @@ -17058,8 +17297,9 @@ }, "node_modules/websocket-extensions": { "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=0.8.0" } diff --git a/ui/package.json b/ui/package.json index 6a92624d243..5399ae2ae24 100644 --- a/ui/package.json +++ b/ui/package.json @@ -37,7 +37,7 @@ "zone.js": "~0.13.3" }, "devDependencies": { - "@angular-devkit/build-angular": "^16.2.13", + "@angular-devkit/build-angular": "^16.2.14", "@angular-eslint/builder": "^16.3.1", "@angular-eslint/eslint-plugin": "^16.3.1", "@angular-eslint/eslint-plugin-template": "^16.3.1", From 254f1ca87728f2c8f1b5250818778439bfd22f52 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 May 2024 22:35:17 +0200 Subject: [PATCH 017/173] Bump eslint-plugin-unused-imports from 3.1.0 to 3.2.0 in /ui (#2633) Bumps [eslint-plugin-unused-imports](https://github.com/sweepline/eslint-plugin-unused-imports) from 3.1.0 to 3.2.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-minor ... 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 | 7 ++++--- ui/package.json | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index d830901e711..958a26c12c8 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -62,7 +62,7 @@ "eslint-plugin-import": "2.29.1", "eslint-plugin-jsdoc": "48.2.3", "eslint-plugin-prefer-arrow": "1.2.3", - "eslint-plugin-unused-imports": "^3.1.0", + "eslint-plugin-unused-imports": "^3.2.0", "jasmine-core": "~4.5.0", "jasmine-spec-reporter": "~7.0.0", "karma": "~6.4.2", @@ -8222,9 +8222,10 @@ } }, "node_modules/eslint-plugin-unused-imports": { - "version": "3.1.0", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-3.2.0.tgz", + "integrity": "sha512-6uXyn6xdINEpxE1MtDjxQsyXB37lfyO2yKGVVgtD7WEWQGORSOZjgrD6hBhvGv4/SO+TOlS+UnC6JppRqbuwGQ==", "dev": true, - "license": "MIT", "dependencies": { "eslint-rule-composer": "^0.3.0" }, diff --git a/ui/package.json b/ui/package.json index 5399ae2ae24..a36b43361c9 100644 --- a/ui/package.json +++ b/ui/package.json @@ -57,7 +57,7 @@ "eslint-plugin-import": "2.29.1", "eslint-plugin-jsdoc": "48.2.3", "eslint-plugin-prefer-arrow": "1.2.3", - "eslint-plugin-unused-imports": "^3.1.0", + "eslint-plugin-unused-imports": "^3.2.0", "jasmine-core": "~4.5.0", "jasmine-spec-reporter": "~7.0.0", "karma": "~6.4.2", From 54514b5da3416b5e52a0b6c47bb5ebd97ed09332 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 May 2024 17:19:09 +0200 Subject: [PATCH 018/173] Update dependencies: influx, kotlin, gson (#2647) - Bump com.influxdb:influxdb-client-utils from 7.0.0 to 7.1.0 in /cnf #2648 - Bump com.influxdb:influxdb-client-java from 7.0.0 to 7.1.0 in /cnf #2649 - Bump com.influxdb:flux-dsl from 7.0.0 to 7.1.0 in /cnf #2646 - Bump com.google.code.gson:gson from 2.10.1 to 2.11.0 in /cnf #2645 - Bump org.jetbrains.kotlin:kotlin-osgi-bundle from 1.9.23 to 1.9.24 in /cnf #2640 - Bump org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm from 1.8.0 to 1.8.1 in /cnf #2639 --- cnf/build.bnd | 2 +- cnf/pom.xml | 14 +++++++------- io.openems.backend.application/BackendApp.bndrun | 4 ++-- io.openems.edge.application/EdgeApp.bndrun | 4 ++-- 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 ++-- io.openems.wrapper/kotlinx-coroutines-core-jvm.bnd | 4 ++-- 9 files changed, 22 insertions(+), 22 deletions(-) diff --git a/cnf/build.bnd b/cnf/build.bnd index 3c42895f80c..c0bce03e8c1 100644 --- a/cnf/build.bnd +++ b/cnf/build.bnd @@ -41,7 +41,7 @@ buildpath: \ org.osgi.service.metatype.annotations;version='1.4.1',\ org.osgi.util.promise;version='1.2.0',\ com.google.guava;version='33.2.0.jre',\ - com.google.gson;version='2.10.1',\ + com.google.gson;version='2.11.0',\ testpath: \ slf4j.simple,\ diff --git a/cnf/pom.xml b/cnf/pom.xml index 69d37dd48f0..2ebbc2688ea 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -33,7 +33,7 @@ com.google.code.gson gson - 2.10.1 + 2.11.0 com.google.guava @@ -271,22 +271,22 @@ com.influxdb influxdb-client-java - 7.0.0 + 7.1.0 com.influxdb influxdb-client-core - 7.0.0 + 7.1.0 com.influxdb influxdb-client-utils - 7.0.0 + 7.1.0 com.influxdb flux-dsl - 7.0.0 + 7.1.0 org.java-websocket @@ -296,12 +296,12 @@ org.jetbrains.kotlin kotlin-osgi-bundle - 1.9.23 + 1.9.24 org.jetbrains.kotlinx kotlinx-coroutines-core-jvm - 1.8.0 + 1.8.1 diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index ff19a98eb97..4c4283c9e71 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -60,7 +60,7 @@ -runbundles: \ Java-WebSocket;version='[1.5.4,1.5.5)',\ - com.google.gson;version='[2.10.1,2.10.2)',\ + com.google.gson;version='[2.11.0,2.11.1)',\ com.google.guava;version='[33.2.0,33.2.1)',\ com.google.guava.failureaccess;version='[1.0.2,1.0.3)',\ com.squareup.okio;version='[3.9.0,3.9.1)',\ @@ -111,7 +111,7 @@ org.apache.felix.scr;version='[2.2.10,2.2.11)',\ org.apache.felix.webconsole;version='[5.0.2,5.0.3)',\ org.apache.felix.webconsole.plugins.ds;version='[2.3.0,2.3.1)',\ - org.jetbrains.kotlin.osgi-bundle;version='[1.9.23,1.9.24)',\ + org.jetbrains.kotlin.osgi-bundle;version='[1.9.24,1.9.25)',\ 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 ed67e7b0e75..5bee66c6b24 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -194,7 +194,7 @@ bcutil;version='[1.70.0,1.70.1)',\ com.fazecast.jSerialComm;version='[2.10.4,2.10.5)',\ com.ghgande.j2mod;version='[3.2.1,3.2.2)',\ - com.google.gson;version='[2.10.1,2.10.2)',\ + com.google.gson;version='[2.11.0,2.11.1)',\ com.google.guava;version='[33.2.0,33.2.1)',\ com.google.guava.failureaccess;version='[1.0.2,1.0.3)',\ com.squareup.okio;version='[3.9.0,3.9.1)',\ @@ -404,7 +404,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.9.23,1.9.24)',\ + org.jetbrains.kotlin.osgi-bundle;version='[1.9.24,1.9.25)',\ org.jsoup;version='[1.17.2,1.17.3)',\ org.jsr-305;version='[3.0.2,3.0.3)',\ org.openmuc.jmbus;version='[3.3.0,3.3.1)',\ diff --git a/io.openems.wrapper/influxdb-client-core.bnd b/io.openems.wrapper/influxdb-client-core.bnd index 393a0f73745..7798c9f3287 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: 7.0.0 +Bundle-Version: 7.1.0 Include-Resource: \ - @influxdb-client-core-7.0.0.jar,\ + @influxdb-client-core-7.1.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 7c862ce2e4c..d104a2e8891 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: 7.0.0 +Bundle-Version: 7.1.0 Include-Resource: \ - @influxdb-client-java-7.0.0.jar,\ + @influxdb-client-java-7.1.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 3fe9e8fd05e..32ffc20d813 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: 7.0.0 +Bundle-Version: 7.1.0 Include-Resource: \ - @influxdb-client-utils-7.0.0.jar,\ + @influxdb-client-utils-7.1.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 f731585750e..d7c95c16634 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: 7.0.0 +Bundle-Version: 7.1.0 Include-Resource: \ - @flux-dsl-7.0.0.jar,\ + @flux-dsl-7.1.0.jar,\ Export-Package: \ com.influxdb.query,\ diff --git a/io.openems.wrapper/kotlinx-coroutines-core-jvm.bnd b/io.openems.wrapper/kotlinx-coroutines-core-jvm.bnd index ad36e0c51f6..eaafb47be8d 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.8.0 +Bundle-Version: 1.8.1 Include-Resource: \ - @kotlinx-coroutines-core-jvm-1.8.0.jar,\ + @kotlinx-coroutines-core-jvm-1.8.1.jar,\ Export-Package: \ kotlinx.coroutines,\ From 9a76f7a5ff9e4f391469eb12dfa47ae59cf71496 Mon Sep 17 00:00:00 2001 From: parapluplu Date: Mon, 27 May 2024 17:35:18 +0200 Subject: [PATCH 019/173] CI: generate jacoco xml report (#2652) For some build processes the xml file is better integrated (e.g. if you need to transform the jacoco report to a cobertura report). So far only the csv report was generated. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index f44c073c365..36f3eea152d 100644 --- a/build.gradle +++ b/build.gradle @@ -55,7 +55,7 @@ subprojects { jacocoTestReport { reports { - xml.required = false + xml.required = true csv.required = true html.required = false } From 03a409147837bb97517a9561e300d47f4d4c3128 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 May 2024 23:15:13 +0200 Subject: [PATCH 020/173] Bump org.apache.felix:org.apache.felix.http.jetty from 5.1.12 to 5.1.14 in /cnf (#2654) * Bump org.apache.felix:org.apache.felix.http.jetty in /cnf Bumps org.apache.felix:org.apache.felix.http.jetty from 5.1.12 to 5.1.14. --- updated-dependencies: - dependency-name: org.apache.felix:org.apache.felix.http.jetty 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 2ebbc2688ea..81189f0fcc8 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -203,7 +203,7 @@ org.apache.felix org.apache.felix.http.jetty - 5.1.12 + 5.1.14 diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index 4c4283c9e71..db4273fda7d 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -104,7 +104,7 @@ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ org.apache.felix.eventadmin;version='[1.6.4,1.6.5)',\ org.apache.felix.fileinstall;version='[3.7.4,3.7.5)',\ - org.apache.felix.http.jetty;version='[5.1.12,5.1.13)',\ + org.apache.felix.http.jetty;version='[5.1.14,5.1.15)',\ org.apache.felix.http.servlet-api;version='[3.0.0,3.0.1)',\ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index 5bee66c6b24..c1fd1f3f7c1 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -392,7 +392,7 @@ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ org.apache.felix.eventadmin;version='[1.6.4,1.6.5)',\ org.apache.felix.fileinstall;version='[3.7.4,3.7.5)',\ - org.apache.felix.http.jetty;version='[5.1.12,5.1.13)',\ + org.apache.felix.http.jetty;version='[5.1.14,5.1.15)',\ org.apache.felix.http.servlet-api;version='[3.0.0,3.0.1)',\ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ From 81b68161ebfad265e09d55512234b0dacb37dd0e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 May 2024 23:22:10 +0200 Subject: [PATCH 021/173] Bump org.jetbrains.kotlin:kotlin-osgi-bundle from 1.9.24 to 2.0.0 in /cnf (#2653) * Bump org.jetbrains.kotlin:kotlin-osgi-bundle in /cnf Bumps org.jetbrains.kotlin:kotlin-osgi-bundle from 1.9.24 to 2.0.0. --- updated-dependencies: - dependency-name: org.jetbrains.kotlin:kotlin-osgi-bundle dependency-type: direct:production update-type: version-update:semver-major ... 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 81189f0fcc8..93688eb6428 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -296,7 +296,7 @@ org.jetbrains.kotlin kotlin-osgi-bundle - 1.9.24 + 2.0.0 org.jetbrains.kotlinx diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index db4273fda7d..4b2a142e8e8 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -111,7 +111,7 @@ org.apache.felix.scr;version='[2.2.10,2.2.11)',\ org.apache.felix.webconsole;version='[5.0.2,5.0.3)',\ org.apache.felix.webconsole.plugins.ds;version='[2.3.0,2.3.1)',\ - org.jetbrains.kotlin.osgi-bundle;version='[1.9.24,1.9.25)',\ + org.jetbrains.kotlin.osgi-bundle;version='[2.0.0,2.0.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 c1fd1f3f7c1..f1d467a7c92 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -404,7 +404,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.9.24,1.9.25)',\ + org.jetbrains.kotlin.osgi-bundle;version='[2.0.0,2.0.1)',\ org.jsoup;version='[1.17.2,1.17.3)',\ org.jsr-305;version='[3.0.2,3.0.3)',\ org.openmuc.jmbus;version='[3.3.0,3.3.1)',\ From 68186f13ced1dbe19527e830cad59e10526d9bcd Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Sat, 1 Jun 2024 17:18:07 +0200 Subject: [PATCH 022/173] FEMS Backports 2023-05 (#2656) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - UI: add notification infrastructure - Battery improvements - Adds `DC_MIN_VOLTAGE` and `DC_MAX_VOLTAGE` to BatteryInverter; implemented in KACO. - Adds ESS-Protection on Generic-ESS - Adds Voltage Regulation in ESS - Modbus/SunSpec: implement BitWords - Refactor SunSpecCodeGenerator - Handle `BITFIELD16` and `BITFIELD32` properly - Allow overriding BITFIELD mapping, e.g. for "Vendor defined events" - ESS Power Solver: improve KEEPING_ALL_EQUAL strategy - Add `OPTIMIZE_BY_KEEPING_ALL_NEAR_EQUAL` strategy; automatically applied as fallback to `OPTIMIZE_BY_KEEPING_ALL_EQUAL`. - Systemd-Networkd: parse [Gateway] in [Route] block - Backend: Send ON_SET_SUM_STATE Event only on change (#1195) - GoodWe: fix sorting of diagnostic bit registers - UI: add warning for systemupdate - Confirmation alert for systemupdate - Standardizing alert for update and EMS restart - UI: adjust translations of alert - Adjust translations of confirmation alert of system update - Adding fix messages for retrofit bnd - Backend b2bwebsocket: fix tests - Gradle builds end with a warning: `Deprecated Gradle features were used in this build, making it incompatible with Gradle 9.0.` - This is due to this error ``` > Task :io.openems.backend.b2bwebsocket:test No test executed. This behavior has been deprecated. This will fail with an error in Gradle 9.0. There are test sources present but no test was executed. Please check your test configuration. Consult the upgrading giude for further information: https://docs.gradle.org/8.7/userguide/upgrading_version_8.html#test_task_fail_on_no_test_executed ``` - UI: improve systemLog - Adding searchbar to be able to filter systemlog (case-insensitive) - Adding debug level filter - Enable Copying of systemlog - Improved filter for Non condensed output -> splitting debugLog string if line-breaks provided - add toggle to reconfigure [condensedOutput](https://github.com/OpenEMS/openems/blob/develop/io.openems.edge.controller.debug.log/src/io/openems/edge/controller/debuglog/Config.java#L23-L24) - Power Solver: OPTIMIZE_BY_KEEPING_ALL_NEAR_EQUAL - GoodWe: fix impossible high Battery Power values - FENECON Home Battery add stop functionality - STOP Home battery on very low cell voltage. Adds Channels: - LOW_MIN_VOLTAGE_WARNING: Low min voltage warning | Niedriger Ladezustand der Batterie, da die Batterie nicht durch den Wechselrichter beladen werden kann. Ohne Beladung schaltet sich die Batterie demnächst ab, um sich selbst zu schützen - LOW_MIN_VOLTAGE_FAULT: Low min voltage fault | Niedriger Ladezustand. Die Batterie schaltet sich demnächst ab, um sich selbst zu schützen - LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED: Low min voltage fault - Battery stopped | Batterie wurde wegen zu niedrigem Ladezustand abgeschaltet. Bitte kontaktieren Sie Ihren Installateur - Backend Alerting: fix NPE, general improvements - make local variables final - remove `public` from interface methods - add null check to `Message.compareTo` - Update Debian settings - Do not install man-pages, locales, docs - Weidmüller IO: fix reading of CurrentModuleList - Fixed hidden ClassCastException in `readCurrentModuleList()` - CI: Improve gradle scripts - UI: fix duplicate legend item generation for same aliases - UI: Extend Eslint - Extend EsLint to make implementing lifecycle interfaces mandatory - UI: Hide Menu in login page - TimeOfUseTariff rabot.charge implementation --------- Co-authored-by: Sebastian Asen <47855186+sebastianasen@users.noreply.github.com> Co-authored-by: Lukas Rieger <73471197+lukasrgr@users.noreply.github.com> Co-authored-by: Stefan Feilmeier <3515268+sfeilmeier@users.noreply.github.com> Co-authored-by: Hueseyin Sahutoglu <34771592+huseyinsaht@users.noreply.github.com> Co-authored-by: Bishal Ghimire <71323741+Bishalghimire1997@users.noreply.github.com> Co-authored-by: Pooran Chandrashekaraiah <46567310+pooran-c@users.noreply.github.com> Co-authored-by: Sagar Venu <32655208+venu-sagar@users.noreply.github.com> Co-authored-by: Kai Jeschek <99220919+da-Kai@users.noreply.github.com> Co-authored-by: Manoj-Kumar Varikela <20610573+manojniit@users.noreply.github.com> Co-authored-by: Saeid Nikoubin Boroujeni <118315460+saeedniko@users.noreply.github.com> --- build.gradle | 24 +- .../io/openems/backend/alerting/Alerting.java | 6 +- .../io/openems/backend/alerting/Handler.java | 8 +- .../io/openems/backend/alerting/Message.java | 2 +- .../alerting/handler/OfflineEdgeHandler.java | 75 +- .../alerting/handler/SumStateHandler.java | 45 +- .../alerting/message/OfflineEdgeMessage.java | 6 +- .../alerting/message/SumStateMessage.java | 6 +- .../alerting/scheduler/MessageScheduler.java | 2 +- .../scheduler/MessageSchedulerService.java | 4 +- .../alerting/scheduler/MinuteTimer.java | 22 +- .../alerting/scheduler/MinuteTimerAsync.java | 7 +- .../backend/alerting/scheduler/Scheduler.java | 2 +- .../alerting/scheduler/TimedExecutor.java | 7 +- .../io/openems/backend/alerting/Dummy.java | 6 +- .../openems/backend/alerting/MessageTest.java | 6 +- .../b2bwebsocket/B2bWebsocketTest.java | 32 +- .../openems/backend/common/metadata/Edge.java | 30 +- .../backend/edgewebsocket/OnNotification.java | 5 +- .../openems/common/function/TriConsumer.java | 26 + .../common/oem/DummyOpenemsEdgeOem.java | 3 +- io.openems.edge.application/EdgeApp.bndrun | 2 + .../io/openems/edge/battery/api/Battery.java | 55 +- .../battery/protection/BatteryProtection.java | 12 + .../AbstractMaxCurrentHandler.java | 2 + .../battery/test/AbstractDummyBattery.java | 11 + .../fenecon/home/BatteryFeneconHome.java | 100 +- .../fenecon/home/BatteryFeneconHomeImpl.java | 80 +- .../battery/fenecon/home/ModbusHelper.java | 24 + .../home/statemachine/ErrorHandler.java | 25 +- .../home/statemachine/GoStoppedHandler.java | 42 +- .../home/statemachine/RunningHandler.java | 2 +- .../home/statemachine/StateMachine.java | 22 +- .../home/statemachine/StoppedHandler.java | 33 + .../home/statemachine/UndefinedHandler.java | 4 +- .../home/BatteryFeneconHomeImplTest.java | 192 + .../edge/battery/fenecon/home/TestStatic.java | 24 + .../api/SymmetricBatteryInverter.java | 105 + .../DummyManagedSymmetricBatteryInverter.java | 22 + ...eryInverterKacoBlueplanetGridsaveImpl.java | 8 +- .../blueplanetgridsave/KacoSunSpecModel.java | 964 +- .../ElementToChannelScaleFactorConverter.java | 4 +- .../worker/internal/TasksSupplierImpl.java | 1 + .../AbstractOpenemsSunSpecComponent.java | 131 +- .../modbus/sunspec/DefaultSunSpecModel.java | 18123 +++------------- .../edge/bridge/modbus/sunspec/Point.java | 418 + .../modbus/sunspec/SunSpecCodeGenerator.java | 787 - .../modbus/sunspec/SunSpecModelType.java | 24 +- .../bridge/modbus/sunspec/SunSpecPoint.java | 198 +- .../modbus/sunspec/SunSpecPointCategory.java | 5 + .../edge/bridge/modbus/sunspec/Utils.java | 50 + .../AbstractOpenemsSunSpecComponentTest.java | 19 +- .../edge/bridge/modbus/sunspec/UtilsTest.java | 21 + .../sunspec/generator/FluentWriter.java | 131 + .../modbus/sunspec/generator/Model.java | 74 + .../modbus/sunspec/generator/Point.java | 193 + .../generator/SunSpecCodeGenerator.java | 505 + .../openems/edge/common/channel/EnumDoc.java | 4 +- .../openems/edge/common/filter/Pt1filter.java | 31 +- .../app/integratedsystem/FeneconHome20.java | 1 + .../app/integratedsystem/FeneconHome30.java | 1 + .../app/timeofusetariff/AwattarHourly.java | 4 +- .../edge/app/timeofusetariff/EntsoE.java | 3 +- .../edge/app/timeofusetariff/RabotCharge.java | 188 + .../timeofusetariff/StromdaoCorrently.java | 3 +- .../edge/app/timeofusetariff/Tibber.java | 3 +- .../core/appmanager/translation_de.properties | 4 + .../core/appmanager/translation_en.properties | 4 + .../edge/core/host/NetworkInterface.java | 165 +- .../host/OperatingSystemDebianSystemd.java | 86 +- .../host/jsonrpc/SetNetworkConfigRequest.java | 1 + .../io/openems/edge/core/appmanager/Apps.java | 11 + .../core/appmanager/ComponentUtilTest.java | 9 +- .../core/appmanager/TestTranslations.java | 3 + .../OperatingSystemDebianSystemdTest.java | 176 +- .../edge/ess/power/api/SolverStrategy.java | 3 +- .../openems/edge/ess/core/power/Solver.java | 9 +- .../power/optimizers/KeepAllNearEqual.java | 251 + .../solver/nearequal/ConstraintWrapper.java | 120 + .../solver/nearequal/SolveNearEqual.java | 121 + .../ess/core/power/NearEqualSolverTest.java | 25 + .../ess/core/power/PowerComponentTest.java | 119 + .../ess/core/power/PowerComponentTest2.java | 205 + ...AbstractAllowedChargeDischargeHandler.java | 178 +- .../common/AbstractChannelManager.java | 34 +- .../common/AbstractGenericManagedEss.java | 2 +- .../ess/generic/common/CycleProvider.java | 11 + .../offgrid/EssGenericOffGridImpl.java | 29 +- .../AllowedChargeDischargeHandler.java | 5 +- .../symmetric/EssGenericManagedSymmetric.java | 3 +- .../EssGenericManagedSymmetricImpl.java | 23 +- .../ess/generic/symmetric/EssProtection.java | 148 + .../generic/symmetric/EssProtectionTest.java | 469 + .../ess/mr/gridcon/helper/DummyBattery.java | 2 + .../edge/goodwe/batteryinverter/Config.java | 4 + .../GoodWeBatteryInverter.java | 13 +- .../GoodWeBatteryInverterImpl.java | 66 +- .../batteryinverter/statemachine/Context.java | 16 + .../statemachine/ErrorHandler.java | 32 + .../statemachine/GoRunningHandler.java | 13 + .../statemachine/GoStoppedHandler.java | 13 + .../statemachine/RunningHandler.java | 15 + .../statemachine/StateMachine.java | 63 + .../statemachine/StoppedHandler.java | 15 + .../statemachine/UndefinedHandler.java | 17 + .../edge/goodwe/common/AbstractGoodWe.java | 80 +- .../io/openems/edge/goodwe/common/GoodWe.java | 4 +- .../ess/AllowedChargeDischargeHandler.java | 4 +- .../edge/goodwe/ess/GoodWeEssImpl.java | 14 +- .../GoodWeBatteryInverterImplTest.java | 28 + .../edge/goodwe/batteryinverter/MyConfig.java | 12 + .../GoodWeChargerMpptTwoStringImplTest.java | 4 + .../edge/goodwe/common/TestStatic.java | 64 + .../io/weidmueller/IoWeidmuellerUr20Impl.java | 4 +- .../.classpath | 12 + .../.gitignore | 2 + .../.project | 23 + .../org.eclipse.core.resources.prefs | 2 + .../bnd.bnd | 14 + .../readme.adoc | 5 + .../timeofusetariff/rabotcharge/Config.java | 25 + .../TimeOfUseTariffRabotCharge.java | 26 + .../TimeOfUseTariffRabotChargeImpl.java | 212 + .../test/.gitignore | 0 .../timeofusetariff/rabotcharge/MyConfig.java | 51 + .../TimeOfUseTariffRabotChargeImplTest.java | 126 + io.openems.wrapper/retrofit2.bnd | 2 + tools/common.sh | 13 + tools/debian/etc/apt/apt.conf.d/99nodoc | 8 + tools/debian/etc/dpkg/dpkg.cfg.d/01nodoc | 9 + ui/.eslintrc.json | 3 + ui/src/app/app-routing.module.ts | 2 +- ui/src/app/app.module.ts | 4 +- ui/src/app/edge/edge.component.ts | 9 + .../system/maintenance/maintenance.ts | 17 +- .../system/oe-system-update.component.html | 2 +- .../system/oe-system-update.component.ts | 26 +- .../systemlog/systemlog.component.html | 55 +- .../settings/systemlog/systemlog.component.ts | 148 +- .../chart/abstracthistorychart.ts | 20 +- .../shared/notification/notification.ts | 1 - ui/src/app/shared/header/header.component.ts | 2 +- ui/src/app/shared/shared.ts | 35 + .../app/shared/utils/date/dateutils.spec.ts | 9 + ui/src/app/shared/utils/date/dateutils.ts | 15 + ui/src/assets/i18n/de.json | 9 +- ui/src/assets/i18n/en.json | 9 +- ui/src/global.scss | 5 - 148 files changed, 9605 insertions(+), 16968 deletions(-) create mode 100644 io.openems.common/src/io/openems/common/function/TriConsumer.java create mode 100644 io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/ModbusHelper.java create mode 100644 io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/StoppedHandler.java create mode 100644 io.openems.edge.battery.fenecon.home/test/io/openems/edge/battery/fenecon/home/TestStatic.java create mode 100644 io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/Point.java delete mode 100644 io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/SunSpecCodeGenerator.java create mode 100644 io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/SunSpecPointCategory.java create mode 100644 io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/Utils.java create mode 100644 io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/UtilsTest.java create mode 100644 io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/generator/FluentWriter.java create mode 100644 io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/generator/Model.java create mode 100644 io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/generator/Point.java create mode 100644 io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/generator/SunSpecCodeGenerator.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/RabotCharge.java create mode 100644 io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/optimizers/KeepAllNearEqual.java create mode 100644 io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/solver/nearequal/ConstraintWrapper.java create mode 100644 io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/solver/nearequal/SolveNearEqual.java create mode 100644 io.openems.edge.ess.core/test/io/openems/edge/ess/core/power/NearEqualSolverTest.java create mode 100644 io.openems.edge.ess.core/test/io/openems/edge/ess/core/power/PowerComponentTest2.java create mode 100644 io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/CycleProvider.java create mode 100644 io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/EssProtection.java create mode 100644 io.openems.edge.ess.generic/test/io/openems/edge/ess/generic/symmetric/EssProtectionTest.java create mode 100644 io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/Context.java create mode 100644 io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/ErrorHandler.java create mode 100644 io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/GoRunningHandler.java create mode 100644 io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/GoStoppedHandler.java create mode 100644 io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/RunningHandler.java create mode 100644 io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/StateMachine.java create mode 100644 io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/StoppedHandler.java create mode 100644 io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/UndefinedHandler.java create mode 100644 io.openems.edge.timeofusetariff.rabotcharge/.classpath create mode 100644 io.openems.edge.timeofusetariff.rabotcharge/.gitignore create mode 100644 io.openems.edge.timeofusetariff.rabotcharge/.project create mode 100644 io.openems.edge.timeofusetariff.rabotcharge/.settings/org.eclipse.core.resources.prefs create mode 100644 io.openems.edge.timeofusetariff.rabotcharge/bnd.bnd create mode 100644 io.openems.edge.timeofusetariff.rabotcharge/readme.adoc create mode 100644 io.openems.edge.timeofusetariff.rabotcharge/src/io/openems/edge/timeofusetariff/rabotcharge/Config.java create mode 100644 io.openems.edge.timeofusetariff.rabotcharge/src/io/openems/edge/timeofusetariff/rabotcharge/TimeOfUseTariffRabotCharge.java create mode 100644 io.openems.edge.timeofusetariff.rabotcharge/src/io/openems/edge/timeofusetariff/rabotcharge/TimeOfUseTariffRabotChargeImpl.java create mode 100644 io.openems.edge.timeofusetariff.rabotcharge/test/.gitignore create mode 100644 io.openems.edge.timeofusetariff.rabotcharge/test/io/openems/edge/timeofusetariff/rabotcharge/MyConfig.java create mode 100644 io.openems.edge.timeofusetariff.rabotcharge/test/io/openems/edge/timeofusetariff/rabotcharge/TimeOfUseTariffRabotChargeImplTest.java create mode 100644 tools/debian/etc/apt/apt.conf.d/99nodoc create mode 100644 tools/debian/etc/dpkg/dpkg.cfg.d/01nodoc diff --git a/build.gradle b/build.gradle index 36f3eea152d..1b669653067 100644 --- a/build.gradle +++ b/build.gradle @@ -191,12 +191,16 @@ task buildEdge() { outputs.upToDateWhen { false } doLast { - file("${buildDir}/openems-edge.jar").delete() + def source = file("io.openems.edge.application/generated/distributions/executable/EdgeApp.jar") + def output = file(System.getenv('OEMS_EDGE_OUTPUT') ?: "${buildDir}/openems-edge.jar") + + output.delete() copy { - from file("io.openems.edge.application/generated/distributions/executable/EdgeApp.jar") - into file("${buildDir}") - rename ("EdgeApp.jar", "openems-edge.jar") + from source + into output.getParentFile() + rename (source.getName(), output.getName()) } + println("Built ${output}!") } } @@ -220,12 +224,16 @@ task buildBackend() { outputs.upToDateWhen { false } doLast { - file("${buildDir}/openems-backend.jar").delete() + def source = file("io.openems.backend.application/generated/distributions/executable/BackendApp.jar") + def output = file(System.getenv('OEMS_BACKEND_OUTPUT') ?: "${buildDir}/openems-backend.jar") + + output.delete() copy { - from file("io.openems.backend.application/generated/distributions/executable/BackendApp.jar") - into file("${buildDir}") - rename ("BackendApp.jar", "openems-backend.jar") + from source + into output.getParentFile() + rename (source.getName(), output.getName()) } + println("Built ${output}!") } } diff --git a/io.openems.backend.alerting/src/io/openems/backend/alerting/Alerting.java b/io.openems.backend.alerting/src/io/openems/backend/alerting/Alerting.java index 18a93a70acd..3260526018b 100644 --- a/io.openems.backend.alerting/src/io/openems/backend/alerting/Alerting.java +++ b/io.openems.backend.alerting/src/io/openems/backend/alerting/Alerting.java @@ -107,9 +107,9 @@ protected void deactivate() { @Override public void handleEvent(Event event) { - var reader = new EventReader(event); + final var reader = new EventReader(event); for (var h : this.handler) { - var task = h.getEventHandler(reader.getTopic()); + final var task = h.getEventHandler(reader.getTopic()); if (task != null) { this.execute(task, reader); } @@ -122,7 +122,7 @@ private void execute(Consumer consumer, EventReader reader) { @Override public String debugLog() { - int queueSize = this.executor.getQueue().size(); + final int queueSize = this.executor.getQueue().size(); if (queueSize >= THREAD_QUEUE_WARNING_THRESHOLD) { return "%d tasks in the EventHandlerQueue!".formatted(queueSize); } else { diff --git a/io.openems.backend.alerting/src/io/openems/backend/alerting/Handler.java b/io.openems.backend.alerting/src/io/openems/backend/alerting/Handler.java index 2cb06971150..c3a8902eb05 100644 --- a/io.openems.backend.alerting/src/io/openems/backend/alerting/Handler.java +++ b/io.openems.backend.alerting/src/io/openems/backend/alerting/Handler.java @@ -11,7 +11,7 @@ public interface Handler { /** * Stop the Handler. */ - public void stop(); + void stop(); /** * Send the messages. @@ -19,14 +19,14 @@ public interface Handler { * @param sentAt TimeStamp at with sending was initiated * @param messages which to send */ - public void send(ZonedDateTime sentAt, List messages); + void send(ZonedDateTime sentAt, List messages); /** * Return generic type of handler as Class object. * * @return GenericType of handler */ - public Class getGeneric(); + Class getGeneric(); /** * Handle given event. @@ -34,5 +34,5 @@ public interface Handler { * @param eventTopic to handle * @return {@link Consumer} to be scheduled in executor */ - public Consumer getEventHandler(String eventTopic); + Consumer getEventHandler(String eventTopic); } diff --git a/io.openems.backend.alerting/src/io/openems/backend/alerting/Message.java b/io.openems.backend.alerting/src/io/openems/backend/alerting/Message.java index 5525c1fcaa7..d477b56ef49 100644 --- a/io.openems.backend.alerting/src/io/openems/backend/alerting/Message.java +++ b/io.openems.backend.alerting/src/io/openems/backend/alerting/Message.java @@ -57,7 +57,7 @@ public boolean equals(Object obj) { @Override public int compareTo(Message o) { if (o == null) { - return -1; + return 1; } return this.getNotifyStamp().compareTo(o.getNotifyStamp()); } diff --git a/io.openems.backend.alerting/src/io/openems/backend/alerting/handler/OfflineEdgeHandler.java b/io.openems.backend.alerting/src/io/openems/backend/alerting/handler/OfflineEdgeHandler.java index dc5f5cf117d..d93c67b32b8 100644 --- a/io.openems.backend.alerting/src/io/openems/backend/alerting/handler/OfflineEdgeHandler.java +++ b/io.openems.backend.alerting/src/io/openems/backend/alerting/handler/OfflineEdgeHandler.java @@ -41,7 +41,7 @@ public class OfflineEdgeHandler implements Handler { private MessageScheduler msgScheduler; private TimedTask initMetadata; - private TimedExecutor timeService; + private final TimedExecutor timeService; public OfflineEdgeHandler(MessageSchedulerService mss, TimedExecutor timeService, Mailer mailer, Metadata metadata, int initialDelay) { @@ -74,16 +74,16 @@ public void send(ZonedDateTime sentAt, List pack) { return; } - var params = JsonUtils.generateJsonArray(pack, OfflineEdgeMessage::getParams); + final var params = JsonUtils.generateJsonArray(pack, OfflineEdgeMessage::getParams); this.mailer.sendMail(sentAt, OfflineEdgeMessage.TEMPLATE, params); - var logStr = new StringBuilder(pack.size() * 64); + final var logStr = new StringBuilder(pack.size() * 64); pack.forEach(msg -> { logStr.append(msg).append(", "); this.tryReschedule(msg); }); - this.log.info("Sent OfflineEdgeMsg: " + logStr.substring(0, logStr.length() - 2)); + this.log.info("Sent OfflineEdgeMsg: {}", logStr.substring(0, logStr.length() - 2)); } private void tryReschedule(OfflineEdgeMessage msg) { @@ -93,38 +93,37 @@ private void tryReschedule(OfflineEdgeMessage msg) { } private boolean isEdgeOffline(String edgeId) { - var edge = this.metadata.getEdge(edgeId); - if (edge.isPresent()) { - return edge.get().isOffline(); - } - return false; + final var edge = this.metadata.getEdge(edgeId); + return edge.map(Edge::isOffline).orElse(false); } private void checkMetadata() { this.log.info("[OfflineEdgeHandler] check Metadata for Offline Edges"); - var msgs = new LinkedList(); - var count = new AtomicInteger(); - var validOfflineEges = this.metadata.getAllOfflineEdges().stream() // + final var msgs = new LinkedList(); + final var count = new AtomicInteger(); + final var validOfflineEges = this.metadata.getAllOfflineEdges().stream() // .filter(this::isValidEdge) // .toList(); if (validOfflineEges.size() > OfflineEdgeHandler.MAX_SIMULTANEOUS_EDGES) { - this.log.error("[OfflineEdgeHandler] Canceled checkMetadata(); tried to schedule msgs for " - + OfflineEdgeHandler.MAX_SIMULTANEOUS_EDGES + " Offline-Edges at once!!"); + this.log.error( + "[OfflineEdgeHandler] Canceled checkMetadata(); tried to schedule msgs for {} Offline-Edges at once!!", + OfflineEdgeHandler.MAX_SIMULTANEOUS_EDGES); return; } for (var edge : validOfflineEges) { - var msg = this.getEdgeMessage(edge); + final var msg = this.getEdgeMessage(edge); if (msg == null) { continue; } - var completeCnt = count.addAndGet(msg.getMessageCount()); + final var completeCnt = count.addAndGet(msg.getMessageCount()); if (completeCnt > OfflineEdgeHandler.MAX_SIMULTANEOUS_MSGS) { - this.log.error("[OfflineEdgeHandler] Canceled checkMetadata(); tried to schedule over " - + OfflineEdgeHandler.MAX_SIMULTANEOUS_MSGS + " EdgeOffline Messages at once!!"); + this.log.error( + "[OfflineEdgeHandler] Canceled checkMetadata(); tried to schedule over {} EdgeOffline Messages at once!!", + OfflineEdgeHandler.MAX_SIMULTANEOUS_MSGS); return; } @@ -141,7 +140,7 @@ private void checkMetadata() { * @return true if valid */ private boolean isValidEdge(Edge edge) { - var invalid = edge.getLastmessage() == null // was never online + final var invalid = edge.getLastmessage() == null // was never online || edge.getLastmessage() // .isBefore(this.timeService.now().minusWeeks(1)); // already offline for a week return !invalid; @@ -155,16 +154,15 @@ private boolean isValidEdge(Edge edge) { */ protected OfflineEdgeMessage getEdgeMessage(Edge edge) { if (edge == null || edge.getId() == null) { - this.log.warn("Called method getEdgeMessage with " // - + (edge == null ? "Edge{null}" : "Edge{id=null}")); + this.log.warn("Called method getEdgeMessage with {}", (edge == null ? "Edge{null}" : "Edge{id=null}")); return null; } try { - var alertingSettings = this.metadata.getEdgeOfflineAlertingSettings(edge.getId()); + final var alertingSettings = this.metadata.getEdgeOfflineAlertingSettings(edge.getId()); if (alertingSettings == null || alertingSettings.isEmpty()) { return null; } - var message = new OfflineEdgeMessage(edge.getId(), edge.getLastmessage()); + final var message = new OfflineEdgeMessage(edge.getId(), edge.getLastmessage()); for (var setting : alertingSettings) { if (setting.delay() > 0 && this.shouldReceiveMail(edge, setting)) { message.addRecipient(setting); @@ -174,7 +172,7 @@ protected OfflineEdgeMessage getEdgeMessage(Edge edge) { return message; } } catch (OpenemsException e) { - this.log.warn("Could not get alerting settings for " + edge.getId(), e); + this.log.warn("Could not get alerting settings for {}", edge.getId(), e); } return null; } @@ -184,10 +182,10 @@ private boolean shouldReceiveMail(Edge edge, OfflineEdgeAlertingSetting setting) final var edgeOfflineSince = edge.getLastmessage(); var hasNotRecievedMailYet = true; - var neverRecievedAnyMail = lastMailRecievedAt == null; + final var neverRecievedAnyMail = lastMailRecievedAt == null; if (!neverRecievedAnyMail) { - var nextMailRecieveAt = edgeOfflineSince.plus(setting.delay(), ChronoUnit.MINUTES); + final var nextMailRecieveAt = edgeOfflineSince.plus(setting.delay(), ChronoUnit.MINUTES); hasNotRecievedMailYet = nextMailRecieveAt.isAfter(lastMailRecievedAt); } @@ -199,12 +197,13 @@ protected void tryRemoveEdge(Edge edge) { } protected void tryAddEdge(Edge edge) { - if (this.isValidEdge(edge)) { - var msg = this.getEdgeMessage(edge); - var msgScheduler = this.msgScheduler; - if (msg != null && msgScheduler != null) { - this.msgScheduler.schedule(msg); - } + if (!this.isValidEdge(edge)) { + return; + } + final var msg = this.getEdgeMessage(edge); + final var msgScheduler = this.msgScheduler; + if (msg != null && msgScheduler != null) { + this.msgScheduler.schedule(msg); } } @@ -218,7 +217,7 @@ private void handleMetadataAfterInitialize(EventReader event) { if (this.initialDelay <= 0) { this.checkMetadata(); } else { - var executeAt = this.timeService.now().plusMinutes(OfflineEdgeHandler.this.initialDelay); + final var executeAt = this.timeService.now().plusMinutes(OfflineEdgeHandler.this.initialDelay); this.initMetadata = this.timeService.schedule(executeAt, (now) -> { this.checkMetadata(); }); @@ -226,12 +225,12 @@ private void handleMetadataAfterInitialize(EventReader event) { } private void handleOnSetOnline(EventReader event) { - var edgeId = event.getString(Edge.Events.OnSetOnline.EDGE_ID); - var isOnline = event.getBoolean(Edge.Events.OnSetOnline.IS_ONLINE); + final var edgeId = event.getString(Edge.Events.OnSetOnline.EDGE_ID); + final var isOnline = event.getBoolean(Edge.Events.OnSetOnline.IS_ONLINE); - var edgeOpt = this.metadata.getEdge(edgeId); + final var edgeOpt = this.metadata.getEdge(edgeId); if (edgeOpt.isPresent()) { - var edge = edgeOpt.get(); + final var edge = edgeOpt.get(); /* Ensure that the online-state has not changed */ if (edge.isOnline() == isOnline) { if (isOnline) { @@ -245,7 +244,7 @@ private void handleOnSetOnline(EventReader event) { } } } else { - this.log.warn("Edge with id: " + edgeId + " not found"); + this.log.warn("Edge with id: {} not found", edgeId); } } diff --git a/io.openems.backend.alerting/src/io/openems/backend/alerting/handler/SumStateHandler.java b/io.openems.backend.alerting/src/io/openems/backend/alerting/handler/SumStateHandler.java index d61fca0c8ba..39260dd6798 100644 --- a/io.openems.backend.alerting/src/io/openems/backend/alerting/handler/SumStateHandler.java +++ b/io.openems.backend.alerting/src/io/openems/backend/alerting/handler/SumStateHandler.java @@ -36,7 +36,7 @@ public class SumStateHandler implements Handler { private MessageScheduler msgScheduler; private TimedTask initMetadata; - private TimedExecutor timeService; + private final TimedExecutor timeService; public SumStateHandler(MessageSchedulerService mss, TimedExecutor timeService, Mailer mailer, Metadata metadata, int initialDelay) { @@ -62,19 +62,23 @@ public void send(ZonedDateTime sentAt, List pack) { // Ensure Edge is still in error state before sending mail. pack.removeIf((msg) -> !this.isEdgeError(msg.getEdgeId())); - var params = JsonUtils.generateJsonArray(pack.stream().map(SumStateMessage::getParams).toList()); + if (pack.isEmpty()) { + return; + } + + final var params = JsonUtils.generateJsonArray(pack.stream().map(SumStateMessage::getParams).toList()); if (!params.isEmpty()) { this.mailer.sendMail(sentAt, SumStateMessage.TEMPLATE, params); } - var logStrBuilder = new StringBuilder(pack.size() * 64); + final var logStrBuilder = new StringBuilder(pack.size() * 64); pack.forEach(msg -> { logStrBuilder.append(msg).append(", "); this.tryReschedule(msg); }); - var logStr = logStrBuilder.toString(); + final var logStr = logStrBuilder.toString(); if (!logStr.isBlank()) { - this.log.info("Sent ErrorEdgeMsg: " + logStr); + this.log.info("Sent ErrorEdgeMsg: {}", logStr); } } @@ -85,12 +89,8 @@ private void tryReschedule(SumStateMessage msg) { } private boolean isEdgeError(String edgeId) { - var sumState = this.metadata.getSumState(edgeId); - if (sumState.isPresent()) { - return this.isSevere(sumState.get()); - } else { - return false; - } + final var sumState = this.metadata.getEdge(edgeId).map(Edge::getSumState); + return sumState.map(this::isSevere).orElse(false); } private boolean isSevere(Level level) { @@ -107,8 +107,8 @@ private boolean isSevere(Level level) { */ protected SumStateMessage getEdgeMessage(Edge edge, Level sumState) throws OpenemsException { if (edge == null || edge.getId() == null) { - this.log.warn("Called method SumStateHandler.getEdgeMessage with " // - + (edge == null ? "Edge{null}" : "Edge{id=null}")); + this.log.warn("Called method SumStateHandler.getEdgeMessage with {}", + (edge == null ? "Edge{null}" : "Edge{id=null}")); return null; } else if (edge.isOffline()) { this.log.warn("Called method SumStateHandler.getEdgeMessage with offline" // @@ -116,9 +116,8 @@ protected SumStateMessage getEdgeMessage(Edge edge, Level sumState) throws Opene return null; } try { - var sumStateSettings = this.metadata.getSumStateAlertingSettings(edge.getId()); - var message = new SumStateMessage(edge.getId(), sumState, this.timeService.now(), sumStateSettings); - return message; + final var sumStateSettings = this.metadata.getSumStateAlertingSettings(edge.getId()); + return new SumStateMessage(edge.getId(), sumState, this.timeService.now(), sumStateSettings); } catch (OpenemsException e) { throw new OpenemsException("Could not get alerting settings for " + edge.getId(), e); } @@ -129,14 +128,14 @@ protected void tryRemoveEdge(String edgeId) { } protected void addOrUpdate(Edge edge, Level sumState) { - var oldMsg = this.msgScheduler.remove(edge.getId()); + final var oldMsg = this.msgScheduler.remove(edge.getId()); if (oldMsg == null) { if (this.faultSince.containsKey(edge.getId())) { return; } try { - var newMsg = this.getEdgeMessage(edge, sumState); + final var newMsg = this.getEdgeMessage(edge, sumState); if (newMsg != null && !newMsg.isEmpty()) { this.msgScheduler.schedule(newMsg); } @@ -168,12 +167,12 @@ private void handleEdgeOnSetSumState(EventReader event) { if (this.isSevere(level)) { final var edgeOpt = this.metadata.getEdge(edgeId); - if (edgeOpt.isEmpty()) { - this.log.warn("Edge with id '" + edgeId + "' was not found!"); + if (edgeOpt.isPresent()) { + this.addOrUpdate(edgeOpt.get(), level); + this.faultSince.putIfAbsent(edgeId, this.timeService.now()); + } else { + this.log.warn("Edge with id '{}' was not found!", edgeId); } - this.addOrUpdate(edgeOpt.get(), level); - - this.faultSince.putIfAbsent(edgeId, this.timeService.now()); } else { this.tryRemoveEdge(edgeId); diff --git a/io.openems.backend.alerting/src/io/openems/backend/alerting/message/OfflineEdgeMessage.java b/io.openems.backend.alerting/src/io/openems/backend/alerting/message/OfflineEdgeMessage.java index 949cffa2712..6521716bae8 100644 --- a/io.openems.backend.alerting/src/io/openems/backend/alerting/message/OfflineEdgeMessage.java +++ b/io.openems.backend.alerting/src/io/openems/backend/alerting/message/OfflineEdgeMessage.java @@ -33,7 +33,7 @@ public OfflineEdgeMessage(String edgeId, ZonedDateTime offlineAt) { @Override public ZonedDateTime getNotifyStamp() { - var minutes = this.recipients.isEmpty() ? 0 : this.recipients.firstKey(); + final var minutes = this.recipients.isEmpty() ? 0 : this.recipients.firstKey(); return this.offlineAt.plusMinutes(minutes); } @@ -44,7 +44,7 @@ public ZonedDateTime getNotifyStamp() { */ public void addRecipient(OfflineEdgeAlertingSetting setting) { this.recipients.putIfAbsent(setting.delay(), new ArrayList<>()); - var settings = this.recipients.get(setting.delay()); + final var settings = this.recipients.get(setting.delay()); settings.add(setting); } @@ -85,7 +85,7 @@ public JsonObject getParams() { @Override public String toString() { - var rec = this.getCurrentRecipients().stream() // + final var rec = this.getCurrentRecipients().stream() // .map(s -> String.valueOf(s.userLogin())) // .collect(Collectors.joining(",")); return OfflineEdgeMessage.class.getSimpleName() + "{for=" + this.getEdgeId() + ", to=[" + rec + "], at=" diff --git a/io.openems.backend.alerting/src/io/openems/backend/alerting/message/SumStateMessage.java b/io.openems.backend.alerting/src/io/openems/backend/alerting/message/SumStateMessage.java index a7b5863234a..c41ee938b11 100644 --- a/io.openems.backend.alerting/src/io/openems/backend/alerting/message/SumStateMessage.java +++ b/io.openems.backend.alerting/src/io/openems/backend/alerting/message/SumStateMessage.java @@ -90,10 +90,10 @@ public JsonObject getParams() { @Override public String toString() { - var localNotify = this.getNotifyStamp().withZoneSameInstant(ZoneId.systemDefault()).toString(); - var localSince = this.getStateSince().withZoneSameInstant(ZoneId.systemDefault()).toString(); + final var localNotify = this.getNotifyStamp().withZoneSameInstant(ZoneId.systemDefault()).toString(); + final var localSince = this.getStateSince().withZoneSameInstant(ZoneId.systemDefault()).toString(); - var rec = this.getCurrentRecipients().stream() // + final var rec = this.getCurrentRecipients().stream() // .map(s -> String.valueOf(s.userLogin())) // .collect(Collectors.joining(",")); diff --git a/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/MessageScheduler.java b/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/MessageScheduler.java index 7f0598cabfe..7585adf772c 100644 --- a/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/MessageScheduler.java +++ b/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/MessageScheduler.java @@ -121,7 +121,7 @@ private boolean hasTimeElapsed(ZonedDateTime now, T msg) { private T poll() { synchronized (this) { - var msg = this.queue.poll(); + final var msg = this.queue.poll(); if (msg != null) { this.messageForId.remove(msg.getId()); } diff --git a/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/MessageSchedulerService.java b/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/MessageSchedulerService.java index eeaca43f9da..3ac6985e32a 100644 --- a/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/MessageSchedulerService.java +++ b/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/MessageSchedulerService.java @@ -17,7 +17,7 @@ public interface MessageSchedulerService { * @param handler to register * @return new MessageScheduler for handler to schedule messages with */ - public MessageScheduler register(Handler handler); + MessageScheduler register(Handler handler); /** * Unregister handler for message scheduling and remove MessageScheduler. @@ -25,6 +25,6 @@ public interface MessageSchedulerService { * @param type of message * @param handler to unregister */ - public void unregister(Handler handler); + void unregister(Handler handler); } diff --git a/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/MinuteTimer.java b/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/MinuteTimer.java index b21357bb0d9..5668e4e0821 100644 --- a/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/MinuteTimer.java +++ b/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/MinuteTimer.java @@ -4,7 +4,7 @@ import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.List; -import java.util.PriorityQueue; +import java.util.concurrent.PriorityBlockingQueue; import java.util.function.Consumer; import org.slf4j.Logger; @@ -21,7 +21,7 @@ public class MinuteTimer implements TimedExecutor { private final Logger log = LoggerFactory.getLogger(MinuteTimer.class); private final List> subscriber = new ArrayList<>(); - private final PriorityQueue singleTasks = new PriorityQueue<>(); + private final PriorityBlockingQueue singleTasks = new PriorityBlockingQueue<>(); private final Clock clock; private long cycleCount = 0; @@ -73,7 +73,7 @@ public void unsubscribe(Consumer sub) { */ @Override public TimedTask schedule(ZonedDateTime at, Consumer task) { - var singleTask = new TimedTask(at, task); + final var singleTask = new TimedTask(at, task); this.singleTasks.add(singleTask); return singleTask; } @@ -95,10 +95,11 @@ private synchronized boolean empty() { } protected synchronized void start() { - if (!this.isRunning) { - this.log.debug("START"); - this.isRunning = true; + if (this.isRunning) { + return; } + this.log.debug("START"); + this.isRunning = true; } private void logDebugInfos() { @@ -115,7 +116,7 @@ protected synchronized void cycle() { this.cycleCount++; this.logDebugInfos(); - var now = this.now(); + final var now = this.now(); this.callSubscriber(now); this.callSingleTasks(now); @@ -147,10 +148,11 @@ private void callSingleTasks(ZonedDateTime now) { } protected synchronized void stop() { - if (this.isRunning) { - this.log.debug("STOP"); - this.isRunning = false; + if (!this.isRunning) { + return; } + this.log.debug("STOP"); + this.isRunning = false; } public int getSubscriberCount() { diff --git a/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/MinuteTimerAsync.java b/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/MinuteTimerAsync.java index bb73b81e4c1..121b3e954e4 100644 --- a/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/MinuteTimerAsync.java +++ b/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/MinuteTimerAsync.java @@ -53,9 +53,10 @@ public void unsubscribe(Consumer sub) { @Override protected void stop() { super.stop(); - if (this.scheduler != null) { - this.scheduler.shutdownNow(); - this.scheduler = null; + if (this.scheduler == null) { + return; } + this.scheduler.shutdownNow(); + this.scheduler = null; } } diff --git a/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/Scheduler.java b/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/Scheduler.java index cc6930f132d..ac069f6839b 100644 --- a/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/Scheduler.java +++ b/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/Scheduler.java @@ -33,7 +33,7 @@ public Scheduler() { @Override public MessageScheduler register(Handler handler) { - var msgSch = new MessageScheduler<>(handler); + final var msgSch = new MessageScheduler<>(handler); this.msgScheduler.add(msgSch); return msgSch; } diff --git a/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/TimedExecutor.java b/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/TimedExecutor.java index fc37e9beee6..debb78c6cbf 100644 --- a/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/TimedExecutor.java +++ b/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/TimedExecutor.java @@ -15,8 +15,11 @@ public TimedTask(ZonedDateTime executeAt, Consumer task) { } @Override - public int compareTo(TimedTask o) { - return this.executeAt.compareTo(o.executeAt); + public int compareTo(TimedTask other) { + if (other == null || other.executeAt == null) { + return 1; + } + return this.executeAt.compareTo(other.executeAt); } } diff --git a/io.openems.backend.alerting/test/io/openems/backend/alerting/Dummy.java b/io.openems.backend.alerting/test/io/openems/backend/alerting/Dummy.java index 2d87c796bdb..84d406508e8 100644 --- a/io.openems.backend.alerting/test/io/openems/backend/alerting/Dummy.java +++ b/io.openems.backend.alerting/test/io/openems/backend/alerting/Dummy.java @@ -6,7 +6,6 @@ import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -104,7 +103,6 @@ public static class AlertingMetadataImpl extends SimpleMetadataImpl { private Collection edges; private Map> offlineSettings; private Map> sumStateSettings; - private Map sumStates = new HashMap<>(10); /** * Initialize Metadata with test data for Offline-Alerting. @@ -157,11 +155,11 @@ public List getSumStateAlertingSettings(String edgeId) @Override public Optional getSumState(String edgeId) { - return Optional.ofNullable(this.sumStates.get(edgeId)); + return this.getEdge(edgeId).map(Edge::getSumState); } public void setSumState(String edgeId, Level sumState) { - this.sumStates.put(edgeId, sumState); + this.getEdge(edgeId).ifPresent(e -> e.setSumState(sumState)); } public Collection getEdges() { diff --git a/io.openems.backend.alerting/test/io/openems/backend/alerting/MessageTest.java b/io.openems.backend.alerting/test/io/openems/backend/alerting/MessageTest.java index 95b9588877c..d1e2296f3c2 100644 --- a/io.openems.backend.alerting/test/io/openems/backend/alerting/MessageTest.java +++ b/io.openems.backend.alerting/test/io/openems/backend/alerting/MessageTest.java @@ -33,8 +33,10 @@ public void testMessage() { assertNotEquals(msg10.hashCode(), msg20.hashCode()); assertNotEquals(msg10.hashCode(), null); - assertTrue("", msg10.compareTo(msg11) > 0); - assertTrue("", msg10.compareTo(msg20) < 0); + assertTrue("msg10 should be greater than msg11", msg10.compareTo(msg11) > 0); + assertTrue("msg10 should be lower than msg20", msg10.compareTo(msg20) < 0); + + assertTrue("msg10 should be greater than null", msg10.compareTo(null) > 0); } /* *********************************************** */ diff --git a/io.openems.backend.b2bwebsocket/test/io/openems/backend/b2bwebsocket/B2bWebsocketTest.java b/io.openems.backend.b2bwebsocket/test/io/openems/backend/b2bwebsocket/B2bWebsocketTest.java index b53a401b2a2..b56f303d50c 100644 --- a/io.openems.backend.b2bwebsocket/test/io/openems/backend/b2bwebsocket/B2bWebsocketTest.java +++ b/io.openems.backend.b2bwebsocket/test/io/openems/backend/b2bwebsocket/B2bWebsocketTest.java @@ -8,6 +8,8 @@ import java.util.Map; import java.util.concurrent.ExecutionException; +import org.junit.Test; + import io.openems.backend.b2bwebsocket.jsonrpc.request.SubscribeEdgesChannelsRequest; import io.openems.backend.common.jsonrpc.request.GetEdgesChannelsValuesRequest; import io.openems.backend.common.jsonrpc.request.GetEdgesStatusRequest; @@ -30,20 +32,6 @@ public class B2bWebsocketTest { private static final String USERNAME = "user"; private static final String PASSWORD = "password"; - /** - * Main. - * - * @param args the args - * @throws Exception on error - */ - public static void main(String[] args) throws Exception { - getEdgesStatusRequest(); - getEdgeConfigRequest(); - getEdgesChannelsValuesRequest(); - subscribeEdgesChannelsRequest(); - setGridConnSchedule(); - } - private static TestClient prepareTestClient() throws URISyntaxException, InterruptedException { Map httpHeaders = new HashMap<>(); var auth = new String( @@ -55,7 +43,8 @@ private static TestClient prepareTestClient() throws URISyntaxException, Interru return client; } - private static void getEdgesStatusRequest() throws Exception { + @Test + public void getEdgesStatusRequest() throws Exception { var client = B2bWebsocketTest.prepareTestClient(); var request = new GetEdgesStatusRequest("edge0"); @@ -68,7 +57,8 @@ private static void getEdgesStatusRequest() throws Exception { client.stop(); } - private static void getEdgeConfigRequest() throws Exception { + @Test + public void getEdgeConfigRequest() throws Exception { var client = B2bWebsocketTest.prepareTestClient(); var request = new EdgeRpcRequest("edge0", new GetEdgeConfigRequest()); @@ -81,7 +71,8 @@ private static void getEdgeConfigRequest() throws Exception { client.stop(); } - private static void getEdgesChannelsValuesRequest() throws Exception { + @Test + public void getEdgesChannelsValuesRequest() throws Exception { var client = B2bWebsocketTest.prepareTestClient(); var request = new GetEdgesChannelsValuesRequest(); @@ -97,7 +88,8 @@ private static void getEdgesChannelsValuesRequest() throws Exception { client.stop(); } - private static void subscribeEdgesChannelsRequest() throws Exception { + @Test + public void subscribeEdgesChannelsRequest() throws Exception { var client = B2bWebsocketTest.prepareTestClient(); client.setOnNotification((ws, notification) -> { System.out.println(notification.toString()); @@ -114,11 +106,11 @@ private static void subscribeEdgesChannelsRequest() throws Exception { System.out.println(e.getMessage()); } - Thread.sleep(10000); client.stop(); } - private static void setGridConnSchedule() throws Exception { + @Test + public void setGridConnSchedule() throws Exception { var client = B2bWebsocketTest.prepareTestClient(); var request = new SetGridConnScheduleRequest("edge0"); diff --git a/io.openems.backend.common/src/io/openems/backend/common/metadata/Edge.java b/io.openems.backend.common/src/io/openems/backend/common/metadata/Edge.java index b5940b7d971..c5879b522d6 100644 --- a/io.openems.backend.common/src/io/openems/backend/common/metadata/Edge.java +++ b/io.openems.backend.common/src/io/openems/backend/common/metadata/Edge.java @@ -13,6 +13,7 @@ import com.google.gson.JsonObject; import io.openems.backend.common.event.BackendEventConstants; +import io.openems.common.channel.Level; import io.openems.common.event.EventBuilder; import io.openems.common.types.SemanticVersion; import io.openems.common.utils.JsonUtils; @@ -28,6 +29,7 @@ public class Edge { private final AtomicReference producttype = new AtomicReference<>(""); private final AtomicReference lastmessage = new AtomicReference<>(null); private boolean isOnline = false; + private final AtomicReference sumState = new AtomicReference<>(null); private final List user; @@ -72,6 +74,7 @@ public JsonObject toJsonObject() { .addProperty("version", this.version.get().toString()) // .addProperty("producttype", this.producttype.get()) // .addProperty("online", this.isOnline) // + .addProperty("sumState", this.sumState.get()) // .addPropertyIfNotNull("lastmessage", this.lastmessage.get()) // .build(); } @@ -84,7 +87,8 @@ public String toString() { + "version=" + this.version + ", " // + "producttype=" + this.producttype + ", " // + "lastmessage=" + this.lastmessage + ", " // - + "isOnline=" + this.isOnline // + + "isOnline=" + this.isOnline + ", " // + + "sumState=" + this.sumState // + "]"; } @@ -234,6 +238,29 @@ public List getUser() { return this.user; } + /* + * SumState + */ + public Level getSumState() { + return this.sumState.get(); + } + + /** + * Sets the sumState and emits a ON_SET_SUM_STATE event. + * + * @param sumState the sumState + */ + public void setSumState(Level sumState) { + Level oldState = this.sumState.getAndSet(sumState); + if (!Objects.equal(oldState, sumState)) { // on change + EventBuilder.from(this.parent.getEventAdmin(), Events.ON_SET_SUM_STATE) // + .addArg(Events.OnSetSumState.EDGE_ID, this.id) // + .addArg(Events.OnSetSumState.OLD_SUM_STATE, oldState) // + .addArg(Events.OnSetSumState.SUM_STATE, sumState) // + .send(); + } + } + /** * Defines all Events an Edge can throw. */ @@ -271,6 +298,7 @@ public static final class OnSetProducttype { public static final class OnSetSumState { public static final String EDGE_ID = "EdgeId:String"; + public static final String OLD_SUM_STATE = "OldSumState:Level"; public static final String SUM_STATE = "SumState:Level"; } diff --git a/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/OnNotification.java b/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/OnNotification.java index 7254b84e0f3..3f6c0498372 100644 --- a/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/OnNotification.java +++ b/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/OnNotification.java @@ -145,10 +145,7 @@ private void handleDataNotification(AbstractDataNotification message, WsData wsD // set specific Edge values if (d.has("_sum/State") && d.get("_sum/State").isJsonPrimitive()) { var sumState = Level.fromJson(d, "_sum/State").orElse(Level.FAULT); - EventBuilder.from(this.parent.eventAdmin, Events.ON_SET_SUM_STATE) - .addArg(Events.OnSetSumState.EDGE_ID, edgeId) // - .addArg(Events.OnSetSumState.SUM_STATE, sumState) // - .send(); + edge.setSumState(sumState); } if (d.has("_meta/Version") && d.get("_meta/Version").isJsonPrimitive()) { diff --git a/io.openems.common/src/io/openems/common/function/TriConsumer.java b/io.openems.common/src/io/openems/common/function/TriConsumer.java new file mode 100644 index 00000000000..f5cb703c4a2 --- /dev/null +++ b/io.openems.common/src/io/openems/common/function/TriConsumer.java @@ -0,0 +1,26 @@ +package io.openems.common.function; + +import java.util.function.BiConsumer; + +/** + * This interface is similar to the java.util interface {@link BiConsumer}. + * Difference is, that it allows to pass to the apply() method one more + * parameter. + * + * @param the apply methods first argument type + * @param the apply methods second argument type + * @param the apply methods third argument type + */ +@FunctionalInterface +public interface TriConsumer { + + /** + * Applies this function to the given arguments. + * + * @param t the first function argument + * @param u the second function argument + * @param v the third function argument + */ + public void accept(T t, U u, V v); + +} diff --git a/io.openems.common/src/io/openems/common/oem/DummyOpenemsEdgeOem.java b/io.openems.common/src/io/openems/common/oem/DummyOpenemsEdgeOem.java index 270154f1318..63558ed64b3 100644 --- a/io.openems.common/src/io/openems/common/oem/DummyOpenemsEdgeOem.java +++ b/io.openems.common/src/io/openems/common/oem/DummyOpenemsEdgeOem.java @@ -65,6 +65,7 @@ public SystemUpdateParams getSystemUpdateParams() { .put("App.FENECON.Industrial.S.ISK011", "https://fenecon.de/fenecon-industrial-s/") // .put("App.TimeOfUseTariff.Awattar", "") // .put("App.TimeOfUseTariff.ENTSO-E", "") // + .put("App.TimeOfUseTariff.RabotCharge", "") // .put("App.TimeOfUseTariff.Stromdao", "") // .put("App.TimeOfUseTariff.Tibber", "") // .put("App.Api.ModbusTcp.ReadOnly", "") // @@ -125,4 +126,4 @@ public static void assertAllWebsiteUrlsSet(OpenemsEdgeOem oem) throws OpenemsExc throw new OpenemsException("Missing Website-URLs in Edge-OEM for [" + String.join(", ", missing) + "]"); } } -} \ No newline at end of file +} diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index f1d467a7c92..1ca35b83f67 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -185,6 +185,7 @@ bnd.identity;id='io.openems.edge.timeofusetariff.awattar',\ bnd.identity;id='io.openems.edge.timeofusetariff.corrently',\ bnd.identity;id='io.openems.edge.timeofusetariff.entsoe',\ + bnd.identity;id='io.openems.edge.timeofusetariff.rabotcharge',\ bnd.identity;id='io.openems.edge.timeofusetariff.tibber',\ -runbundles: \ @@ -362,6 +363,7 @@ io.openems.edge.timeofusetariff.awattar;version=snapshot,\ io.openems.edge.timeofusetariff.corrently;version=snapshot,\ io.openems.edge.timeofusetariff.entsoe;version=snapshot,\ + io.openems.edge.timeofusetariff.rabotcharge;version=snapshot,\ io.openems.edge.timeofusetariff.tibber;version=snapshot,\ io.openems.oem.openems;version=snapshot,\ io.openems.shared.influxdb;version=snapshot,\ diff --git a/io.openems.edge.battery.api/src/io/openems/edge/battery/api/Battery.java b/io.openems.edge.battery.api/src/io/openems/edge/battery/api/Battery.java index c8cfdaf41e9..a0ccf59f1fe 100644 --- a/io.openems.edge.battery.api/src/io/openems/edge/battery/api/Battery.java +++ b/io.openems.edge.battery.api/src/io/openems/edge/battery/api/Battery.java @@ -207,7 +207,21 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ MAX_CELL_VOLTAGE(Doc.of(OpenemsType.INTEGER) // .unit(Unit.MILLIVOLT) // - .persistencePriority(PersistencePriority.HIGH)); + .persistencePriority(PersistencePriority.HIGH)), // + + /** + * Battery Inner Resistance. + * + *

      + *
    • Interface: Battery + *
    • Type: Integer + *
    • Unit: mOhm + *
    + */ + INNER_RESISTANCE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.MILLIOHM) // + .persistencePriority(PersistencePriority.MEDIUM)), // + ; private final Doc doc; @@ -243,6 +257,7 @@ public static ModbusSlaveNatureTable getModbusSlaveNatureTable(AccessMode access .channel(18, ChannelId.MAX_CELL_TEMPERATURE, ModbusType.FLOAT32) // .channel(20, ChannelId.MIN_CELL_VOLTAGE, ModbusType.FLOAT32) // .channel(22, ChannelId.MAX_CELL_VOLTAGE, ModbusType.FLOAT32) // + .channel(24, ChannelId.INNER_RESISTANCE, ModbusType.FLOAT32) // .build(); } @@ -736,6 +751,44 @@ public default void _setMaxCellVoltage(int value) { this.getMaxCellVoltageChannel().setNextValue(value); } + /** + * Gets the Channel for {@link ChannelId#INNER_RESISTANCE}. + * + * @return the Channel + */ + public default IntegerReadChannel getInnerResistanceChannel() { + return this.channel(ChannelId.INNER_RESISTANCE); + } + + /** + * Gets the Inner Resistance [mOhm]. See {@link ChannelId#INNER_RESISTANCE}. + * + * @return the Channel {@link Value} + */ + public default Value getInnerResistance() { + return this.getInnerResistanceChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#INNER_RESISTANCE} + * Channel. + * + * @param value the next value + */ + public default void _setInnerResistance(Integer value) { + this.getInnerResistanceChannel().setNextValue(value); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#INNER_RESISTANCE} + * Channel. + * + * @param value the next value + */ + public default void _setInnerResistance(int value) { + this.getInnerResistanceChannel().setNextValue(value); + } + /** * Generates a default DebugLog message for {@link Battery} implementations with * a State-Machine. diff --git a/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/BatteryProtection.java b/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/BatteryProtection.java index 51d94b397d2..44cf766ce8b 100644 --- a/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/BatteryProtection.java +++ b/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/BatteryProtection.java @@ -192,6 +192,18 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ BP_FORCE_CHARGE(Doc.of(AbstractForceChargeDischarge.State.values()) // .persistencePriority(PersistencePriority.MEDIUM)), // + + /** + * Battery Max Ever Current. + * + *
      + *
    • Interface: BatteryProtection + *
    + */ + BP_MAX_EVER_CURRENT(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.AMPERE) // + .persistencePriority(PersistencePriority.MEDIUM)), // + ; private final Doc doc; diff --git a/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/currenthandler/AbstractMaxCurrentHandler.java b/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/currenthandler/AbstractMaxCurrentHandler.java index fc472e48f7c..83c84e4d6a1 100644 --- a/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/currenthandler/AbstractMaxCurrentHandler.java +++ b/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/currenthandler/AbstractMaxCurrentHandler.java @@ -6,6 +6,7 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.edge.battery.api.Battery; +import io.openems.edge.battery.protection.BatteryProtection; import io.openems.edge.battery.protection.BatteryProtection.ChannelId; import io.openems.edge.battery.protection.force.AbstractForceChargeDischarge; import io.openems.edge.common.channel.IntegerReadChannel; @@ -234,6 +235,7 @@ public synchronized int calculateCurrentLimit(Battery battery) { /* * Store limits in Channels. If value is 'null', store the bmsMaxEverCurrent */ + battery.channel(BatteryProtection.ChannelId.BP_MAX_EVER_CURRENT).setNextValue(this.bmsMaxEverCurrent); battery.channel(this.getBpMinVoltageChannelId()) .setNextValue(TypeUtils.orElse(minCellVoltageLimit, this.bmsMaxEverCurrent)); battery.channel(this.getBpMaxVoltageChannelId()) diff --git a/io.openems.edge.battery.api/src/io/openems/edge/battery/test/AbstractDummyBattery.java b/io.openems.edge.battery.api/src/io/openems/edge/battery/test/AbstractDummyBattery.java index 0533af8c760..cf0252cf904 100644 --- a/io.openems.edge.battery.api/src/io/openems/edge/battery/test/AbstractDummyBattery.java +++ b/io.openems.edge.battery.api/src/io/openems/edge/battery/test/AbstractDummyBattery.java @@ -174,4 +174,15 @@ public final SELF withMaxCellTemperature(int value) { return this.self(); } + /** + * Set {@link Battery.ChannelId#INNER_RESISTANCE}. + * + * @param value the value + * @return myself + */ + public final SELF withInnerResistence(int value) { + TestUtils.withValue(this, Battery.ChannelId.INNER_RESISTANCE, value); + return this.self(); + } + } diff --git a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/BatteryFeneconHome.java b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/BatteryFeneconHome.java index f362fe3dea4..9de0fccbd03 100644 --- a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/BatteryFeneconHome.java +++ b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/BatteryFeneconHome.java @@ -12,12 +12,13 @@ import io.openems.edge.common.channel.Doc; import io.openems.edge.common.channel.IntegerDoc; 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; import io.openems.edge.common.startstop.StartStop; import io.openems.edge.common.startstop.StartStoppable; -public interface BatteryFeneconHome extends Battery, ModbusComponent, OpenemsComponent, StartStoppable { +public interface BatteryFeneconHome extends Battery, ModbusComponent, OpenemsComponent, StartStoppable, ModbusHelper { /** * Gets the Channel for {@link ChannelId#BMS_CONTROL}. @@ -673,6 +674,16 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId .text("Current State of State-Machine")), // RUN_FAILED(Doc.of(Level.FAULT) // .text("Running the Logic failed")), // + LOW_MIN_VOLTAGE_WARNING(Doc.of(Level.WARNING) // + .text("Low min voltage warning " + + "| Niedriger Ladezustand der Batterie, da die Batterie nicht durch den Wechselrichter beladen werden kann. Ohne Beladung schaltet sich die Batterie demnächst ab, um sich selbst zu schützen")), + LOW_MIN_VOLTAGE_FAULT(Doc.of(Level.FAULT) // + .text("Low min voltage fault " + + "| Niedriger Ladezustand. Die Batterie schaltet sich demnächst ab, um sich selbst zu schützen")), + LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED(Doc.of(Level.FAULT) // + .text("Low min voltage fault - Battery stopped " + + "| Batterie wurde wegen zu niedrigem Ladezustand abgeschaltet. Bitte kontaktieren Sie Ihren Installateur")), + ; private final Doc doc; @@ -686,4 +697,91 @@ public Doc doc() { return this.doc; } } + + /** + * Gets the Channel for {@link ChannelId#LOW_MIN_VOLTAGE_WARNING}. + * + * @return the Channel + */ + public default StateChannel getLowMinVoltageWarningChannel() { + return this.channel(ChannelId.LOW_MIN_VOLTAGE_WARNING); + } + + /** + * Gets the Warning state channel for a low minimum voltage. See + * {@link ChannelId#LOW_MIN_VOLTAGE_WARNING}. + * + * @return the Channel {@link Value} + */ + public default Value getLowMinVoltageWarning() { + return this.getLowMinVoltageWarningChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on + * {@link ChannelId#LOW_MIN_VOLTAGE_WARNING} Channel. + * + * @param value the next value + */ + public default void _setLowMinVoltageWarning(boolean value) { + this.getLowMinVoltageWarningChannel().setNextValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#LOW_MIN_VOLTAGE_FAULT}. + * + * @return the Channel + */ + public default StateChannel getLowMinVoltageFaultChannel() { + return this.channel(ChannelId.LOW_MIN_VOLTAGE_FAULT); + } + + /** + * Gets the fault state channel for a low minimum voltage. See + * {@link ChannelId#LOW_MIN_VOLTAGE_FAULT}. + * + * @return the Channel {@link Value} + */ + public default Value getLowMinVoltage() { + return this.getLowMinVoltageFaultChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on + * {@link ChannelId#LOW_MIN_VOLTAGE_FAULT} Channel. + * + * @param value the next value + */ + public default void _setLowMinVoltageFault(boolean value) { + this.getLowMinVoltageFaultChannel().setNextValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED}. + * + * @return the Channel + */ + public default StateChannel getLowMinVoltageFaultBatteryStoppedChannel() { + return this.channel(ChannelId.LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED); + } + + /** + * Gets the fault state channel for a low minimum voltage when battery is + * stopped. See {@link ChannelId#LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED}. + * + * @return the Channel {@link Value} + */ + public default Value getLowMinVoltageFaultBatteryStopped() { + return this.getLowMinVoltageFaultBatteryStoppedChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on + * {@link ChannelId#LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED} Channel. + * + * @param value the next value + */ + public default void _setLowMinVoltageFaultBatteryStopped(boolean value) { + this.getLowMinVoltageFaultBatteryStoppedChannel().setNextValue(value); + } } 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 01748d00999..51dad2bc072 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 @@ -4,6 +4,7 @@ import static io.openems.edge.bridge.modbus.api.ElementToChannelConverter.SCALE_FACTOR_MINUS_1; import static io.openems.edge.bridge.modbus.api.ModbusUtils.readElementOnce; +import java.time.Instant; import java.util.List; import java.util.Objects; import java.util.concurrent.atomic.AtomicReference; @@ -81,7 +82,11 @@ EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE // }) public class BatteryFeneconHomeImpl extends AbstractOpenemsModbusComponent implements ModbusComponent, OpenemsComponent, - Battery, EventHandler, ModbusSlave, StartStoppable, BatteryFeneconHome { + Battery, EventHandler, ModbusSlave, StartStoppable, BatteryFeneconHome, ModbusHelper { + + public static final int DEFAULT_CRITICAL_MIN_VOLTAGE = 2800; + protected static final int TIMEOUT = 600; // [10 minutes in seconds] + private Instant timeCriticalMinVoltage; protected final StateMachine stateMachine = new StateMachine(State.UNDEFINED); @@ -148,6 +153,7 @@ public void handleEvent(Event event) { this.batteryProtection.apply(); break; case EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE: + this.checkCriticalMinVoltage(); this.handleStateMachine(); break; } @@ -172,7 +178,6 @@ private void handleStateMachine() { this.getBmsControl(), // this.getModbusCommunicationFailed(), // () -> this.retryModbusCommunication()); - // Call the StateMachine try { @@ -1046,4 +1051,75 @@ public static String generateTempBalancingChannelName(int tower, int module, int private static String generateSingleCellPrefix(int tower, int module, int num) { return "TOWER_" + tower + "_MODULE_" + module + "_CELL_" + String.format("%03d", num); } + + @Override + public BridgeModbus getModbus() { + return this.getBridgeModbus(); + } + + @Override + public ModbusProtocol getDefinedModbusProtocol() throws OpenemsException { + return this.getModbusProtocol(); + } + + private void checkCriticalMinVoltage() { + + final var subState = getMinVoltageSubState(DEFAULT_CRITICAL_MIN_VOLTAGE, + this.getMinCellVoltage().orElse(Integer.MAX_VALUE), this.getCurrent().orElse(0)); + var now = Instant.now(this.componentManager.getClock()); + + switch (subState) { + case ABOVE_LIMIT -> { + this._setLowMinVoltageFault(false); + this._setLowMinVoltageWarning(false); + this._setLowMinVoltageFaultBatteryStopped(false); + this.timeCriticalMinVoltage = null; + } + case BELOW_LIMIT -> { + + if (this.stateMachine.getCurrentState() == StateMachine.State.STOPPED) { + this._setLowMinVoltageFaultBatteryStopped(true); + this._setLowMinVoltageFault(false); + this._setLowMinVoltageWarning(false); + return; + } + + this._setLowMinVoltageFaultBatteryStopped(false); + + if (this.timeCriticalMinVoltage == null) { + this.timeCriticalMinVoltage = now; + } + + if (this.timeCriticalMinVoltage.isBefore(now.minusSeconds(TIMEOUT))) { + this._setLowMinVoltageFault(true); + this._setLowMinVoltageWarning(false); + return; + } + this._setLowMinVoltageWarning(true); + this._setLowMinVoltageFault(false); + } + case BELOW_LIMIT_CHARGING -> { + this._setLowMinVoltageFaultBatteryStopped(false); + this._setLowMinVoltageWarning(true); + this._setLowMinVoltageFault(false); + this.timeCriticalMinVoltage = null; + } + } + } + + protected static MinVoltageSubState getMinVoltageSubState(int minVoltageLimit, int currentMinVoltage, int current) { + if (currentMinVoltage > minVoltageLimit) { + return MinVoltageSubState.ABOVE_LIMIT; + } + if (current < 0) { + return MinVoltageSubState.BELOW_LIMIT_CHARGING; + } + return MinVoltageSubState.BELOW_LIMIT; + } + + protected static enum MinVoltageSubState { + ABOVE_LIMIT, // + BELOW_LIMIT, // + BELOW_LIMIT_CHARGING; // + } } diff --git a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/ModbusHelper.java b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/ModbusHelper.java new file mode 100644 index 00000000000..b072d1ebdc4 --- /dev/null +++ b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/ModbusHelper.java @@ -0,0 +1,24 @@ +package io.openems.edge.battery.fenecon.home; + +import io.openems.common.exceptions.OpenemsException; +import io.openems.edge.bridge.modbus.api.BridgeModbus; +import io.openems.edge.bridge.modbus.api.ModbusProtocol; + +public interface ModbusHelper { + + /** + * Get modbus bridge. + * + * @return modbus bridge. + */ + public BridgeModbus getModbus(); + + /** + * Get defined modbus protocol. + * + * @return modbus protocol + * @throws OpenemsException on error + */ + public ModbusProtocol getDefinedModbusProtocol() throws OpenemsException; + +} diff --git a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/ErrorHandler.java b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/ErrorHandler.java index f44234e32c1..0353dcada1b 100644 --- a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/ErrorHandler.java +++ b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/ErrorHandler.java @@ -1,31 +1,22 @@ package io.openems.edge.battery.fenecon.home.statemachine; -import java.time.Duration; -import java.time.Instant; - -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.edge.battery.fenecon.home.statemachine.StateMachine.State; import io.openems.edge.common.statemachine.StateHandler; public class ErrorHandler extends StateHandler { - private static final int WAIT_IN_ERROR_STATE_SECONDS = 120; - - private Instant entryAt = Instant.MIN; - - @Override - protected void onEntry(Context context) throws OpenemsNamedException { - this.entryAt = Instant.now(); - } - @Override public State runAndGetNextState(Context context) { - if (Duration.between(this.entryAt, Instant.now()).getSeconds() > WAIT_IN_ERROR_STATE_SECONDS) { - // Try again - return State.UNDEFINED; + + if (context.getParent().getLowMinVoltage().orElse(false)) { + return State.GO_STOPPED; } - return State.ERROR; + if (context.getParent().hasFaults()) { + return State.ERROR; + } else { + return State.UNDEFINED; + } } } diff --git a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/GoStoppedHandler.java b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/GoStoppedHandler.java index 983fc889aa2..a41a0bf4837 100644 --- a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/GoStoppedHandler.java +++ b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/GoStoppedHandler.java @@ -1,19 +1,51 @@ package io.openems.edge.battery.fenecon.home.statemachine; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.time.Duration; +import java.time.Instant; +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.exceptions.OpenemsException; import io.openems.edge.battery.fenecon.home.statemachine.StateMachine.State; import io.openems.edge.common.statemachine.StateHandler; public class GoStoppedHandler extends StateHandler { - private final Logger log = LoggerFactory.getLogger(GoStoppedHandler.class); + private static int TIMEOUT = 2100; // [35 minutes in seconds] + private Instant timeAtEntry = Instant.MIN; + private boolean didProtocolAdd = false; @Override - public State runAndGetNextState(Context context) { - context.logWarn(this.log, "Stopping a FENECON Home Battery is not supported"); + protected void onEntry(Context context) throws OpenemsNamedException { + final var battery = context.getParent(); + final var modbus = battery.getModbus(); + modbus.removeProtocol(battery.id()); + this.didProtocolAdd = false; + this.timeAtEntry = Instant.now(context.clock); + } + + @Override + public State runAndGetNextState(Context context) throws OpenemsException { + final var battery = context.getParent(); + var now = Instant.now(context.clock); + if (Duration.between(this.timeAtEntry, now).getSeconds() > TIMEOUT && !this.didProtocolAdd) { + this.addAndRetryModbusProtocol(context); + return State.GO_STOPPED; + } + + if (battery.getModbusCommunicationFailed()) { + return State.STOPPED; + } + + // TODO if battery is not off return State.GO_STOPPED; } + private void addAndRetryModbusProtocol(Context context) throws OpenemsException { + final var battery = context.getParent(); + final var modbus = battery.getModbus(); + modbus.addProtocol(battery.id(), battery.getDefinedModbusProtocol()); + modbus.retryModbusCommunication(battery.id()); + this.didProtocolAdd = true; + } + } diff --git a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/RunningHandler.java b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/RunningHandler.java index 36cbde803ab..af6bc9c316d 100644 --- a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/RunningHandler.java +++ b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/RunningHandler.java @@ -11,7 +11,7 @@ public State runAndGetNextState(Context context) { var battery = context.getParent(); if (battery.hasFaults()) { - return State.UNDEFINED; + return State.ERROR; } // Is Battery still started? diff --git a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/StateMachine.java b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/StateMachine.java index 4e73243f460..bf9624a2cd9 100644 --- a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/StateMachine.java +++ b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/StateMachine.java @@ -13,6 +13,7 @@ public enum State implements io.openems.edge.common.statemachine.State, O RUNNING(11), // GO_STOPPED(20), // + STOPPED(21), // ERROR(30), // ; @@ -50,18 +51,13 @@ public StateMachine(State initialState) { @Override public StateHandler getStateHandler(State state) { - switch (state) { - case UNDEFINED: - return new UndefinedHandler(); - case GO_RUNNING: - return new GoRunningHandler(); - case RUNNING: - return new RunningHandler(); - case GO_STOPPED: - return new GoStoppedHandler(); - case ERROR: - return new ErrorHandler(); - } - throw new IllegalArgumentException("Unknown State [" + state + "]"); + return switch (state) { + case UNDEFINED -> new UndefinedHandler(); + case GO_RUNNING -> new GoRunningHandler(); + case RUNNING -> new RunningHandler(); + case GO_STOPPED -> new GoStoppedHandler(); + case STOPPED -> new StoppedHandler(); + case ERROR -> new ErrorHandler(); + }; } } \ No newline at end of file diff --git a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/StoppedHandler.java b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/StoppedHandler.java new file mode 100644 index 00000000000..050ac7c9583 --- /dev/null +++ b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/StoppedHandler.java @@ -0,0 +1,33 @@ +package io.openems.edge.battery.fenecon.home.statemachine; + +import io.openems.edge.battery.fenecon.home.BatteryFeneconHomeImpl; +import io.openems.edge.battery.fenecon.home.statemachine.StateMachine.State; +import io.openems.edge.common.startstop.StartStop; +import io.openems.edge.common.statemachine.StateHandler; + +public class StoppedHandler extends StateHandler { + + @Override + public State runAndGetNextState(Context context) { + final var battery = context.getParent(); + + final int currentMinVoltage; + if (battery.getMinCellVoltage().isDefined()) { + currentMinVoltage = battery.getMinCellVoltage().get(); + } else { + currentMinVoltage = battery.getMinCellVoltageChannel().getPastValues().lastEntry().getValue() + .orElse(Integer.MAX_VALUE); + } + + if (currentMinVoltage < BatteryFeneconHomeImpl.DEFAULT_CRITICAL_MIN_VOLTAGE) { + battery._setLowMinVoltageFaultBatteryStopped(true); + } else { + battery._setLowMinVoltageFaultBatteryStopped(false); + } + + // Mark as started + battery._setStartStop(StartStop.STOP); + return State.STOPPED; + } + +} diff --git a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/UndefinedHandler.java b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/UndefinedHandler.java index e5485be00c3..49b32ea48b5 100644 --- a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/UndefinedHandler.java +++ b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/UndefinedHandler.java @@ -19,7 +19,9 @@ public State runAndGetNextState(Context context) { if (battery.getModbusCommunicationFailed()) { // Modbus Communication Failed -> try to start yield State.GO_RUNNING; + } else if (battery.hasFaults()) { + // Has Faults -> error handling yield State.ERROR; } else { @@ -29,7 +31,7 @@ public State runAndGetNextState(Context context) { } case STOP -> - // STOP is impossible -> stuck in GO_STOPPED State + // force STOP State.GO_STOPPED; }; } diff --git a/io.openems.edge.battery.fenecon.home/test/io/openems/edge/battery/fenecon/home/BatteryFeneconHomeImplTest.java b/io.openems.edge.battery.fenecon.home/test/io/openems/edge/battery/fenecon/home/BatteryFeneconHomeImplTest.java index 1faf9d74e77..9327aaa91cc 100644 --- a/io.openems.edge.battery.fenecon.home/test/io/openems/edge/battery/fenecon/home/BatteryFeneconHomeImplTest.java +++ b/io.openems.edge.battery.fenecon.home/test/io/openems/edge/battery/fenecon/home/BatteryFeneconHomeImplTest.java @@ -32,6 +32,12 @@ public class BatteryFeneconHomeImplTest { private static final ChannelAddress STATE_MACHINE = new ChannelAddress(BATTERY_ID, BatteryFeneconHome.ChannelId.STATE_MACHINE.id()); + private static final ChannelAddress LOW_MIN_VOLTAGE_WARNING = new ChannelAddress(BATTERY_ID, + BatteryFeneconHome.ChannelId.LOW_MIN_VOLTAGE_WARNING.id()); + private static final ChannelAddress LOW_MIN_VOLTAGE_FAULT = new ChannelAddress(BATTERY_ID, + BatteryFeneconHome.ChannelId.LOW_MIN_VOLTAGE_FAULT.id()); + private static final ChannelAddress LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED = new ChannelAddress(BATTERY_ID, + BatteryFeneconHome.ChannelId.LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED.id()); private static final ChannelAddress MODBUS_COMMUNICATION_FAILED = new ChannelAddress(BATTERY_ID, ModbusComponent.ChannelId.MODBUS_COMMUNICATION_FAILED.id()); private static final ChannelAddress BMS_CONTROL = new ChannelAddress(BATTERY_ID, @@ -42,6 +48,10 @@ public class BatteryFeneconHomeImplTest { Battery.ChannelId.MAX_CELL_VOLTAGE.id()); private static final ChannelAddress CHARGE_MAX_CURRENT = new ChannelAddress(BATTERY_ID, Battery.ChannelId.CHARGE_MAX_CURRENT.id()); + private static final ChannelAddress CURRENT = new ChannelAddress(BATTERY_ID, Battery.ChannelId.CURRENT.id()); + private static final ChannelAddress MIN_CELL_VOLTAGE = new ChannelAddress(BATTERY_ID, + Battery.ChannelId.MIN_CELL_VOLTAGE.id()); + private static final ChannelAddress BATTERY_RELAY = new ChannelAddress(IO_ID, "InputOutput4"); private static ThrowingRunnable assertLog(BatteryFeneconHomeImpl sut, String message) { @@ -304,4 +314,186 @@ public void testGetHardwareTypeFromRegisterValue() { BatteryFeneconHomeImpl.parseHardwareTypeFromRegisterValue(640)); } + + @Test + public void testMinVoltageGoStopped() throws Exception { + final var clock = new TimeLeapClock(Instant.parse("2020-01-01T01:00:00.00Z"), ZoneOffset.UTC); + var sut = new BatteryFeneconHomeImpl(); + new ComponentTest(sut) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("componentManager", new DummyComponentManager(clock)) // + .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addComponent(new DummyInputOutput(IO_ID)) // + .activate(MyConfig.create() // + .setId(BATTERY_ID) // + .setModbusId(MODBUS_ID) // + .setModbusUnitId(0) // + .setStartStop(StartStopConfig.START) // + .setBatteryStartUpRelay("io0/InputOutput4")// + .build())// + + .next(new TestCase() // + .input(BATTERY_RELAY, false) // + .input(BMS_CONTROL, true) // Switched On + .output(STATE_MACHINE, StateMachine.State.UNDEFINED))// + .next(new TestCase() // + .onBeforeProcessImage(assertLog(sut, "GoRunning-Undefined")) // + .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .next(new TestCase() // + .onBeforeProcessImage(assertLog(sut, "GoRunning-StartUpRelayOff")) // + .output(STATE_MACHINE, StateMachine.State.GO_RUNNING))// + .next(new TestCase() // + .onBeforeProcessImage(assertLog(sut, "GoRunning-RetryModbusCommunication")) // + .output(STATE_MACHINE, StateMachine.State.GO_RUNNING))// + .next(new TestCase() // + .onBeforeProcessImage(assertLog(sut, "GoRunning-WaitForBmsControl")) // + .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .next(new TestCase() // + .onBeforeProcessImage(assertLog(sut, "GoRunning-WaitForModbusCommunication")) // + .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .next(new TestCase() // + .output(STATE_MACHINE, StateMachine.State.RUNNING)) + + /* + * Critical min voltage + */ + .next(new TestCase("MinCellVoltage below critical value") // + .input(MIN_CELL_VOLTAGE, (BatteryFeneconHomeImpl.DEFAULT_CRITICAL_MIN_VOLTAGE - 100)) // + .input(CURRENT, 0) // + .output(LOW_MIN_VOLTAGE_WARNING, true) // + .output(LOW_MIN_VOLTAGE_FAULT, false) // + .output(STATE_MACHINE, StateMachine.State.RUNNING) // + .output(LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED, false) // + .onAfterControllersCallbacks( + () -> clock.leap(BatteryFeneconHomeImpl.TIMEOUT - 10, ChronoUnit.SECONDS))) // + .next(new TestCase("MinCellVoltage below critical value - charging resets time") // + .input(MIN_CELL_VOLTAGE, (BatteryFeneconHomeImpl.DEFAULT_CRITICAL_MIN_VOLTAGE - 100)) // + .input(CURRENT, -300) // + .output(LOW_MIN_VOLTAGE_WARNING, true) // + .output(LOW_MIN_VOLTAGE_FAULT, false) // + .output(LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED, false)) // + .next(new TestCase("MinCellVoltage below critical value - timer starts again") // + .input(CURRENT, 0) // + .input(MIN_CELL_VOLTAGE, (BatteryFeneconHomeImpl.DEFAULT_CRITICAL_MIN_VOLTAGE - 100)) // + .output(LOW_MIN_VOLTAGE_WARNING, true) // + .output(LOW_MIN_VOLTAGE_FAULT, false) // + .output(LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED, false) // + .onAfterControllersCallbacks( + () -> clock.leap(BatteryFeneconHomeImpl.TIMEOUT - 10, ChronoUnit.SECONDS))) // + .next(new TestCase("MinCellVoltage below critical value - time not passed") // + .input(CURRENT, 0) // + .input(MIN_CELL_VOLTAGE, (BatteryFeneconHomeImpl.DEFAULT_CRITICAL_MIN_VOLTAGE - 100)) // + .output(LOW_MIN_VOLTAGE_WARNING, true) // + .output(LOW_MIN_VOLTAGE_FAULT, false) // + .output(LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED, false) // + .onAfterControllersCallbacks(() -> clock.leap(15, ChronoUnit.SECONDS))) // + .next(new TestCase("MinCellVoltage below critical value - time passed") // + .input(CURRENT, 0) // + .input(MIN_CELL_VOLTAGE, (BatteryFeneconHomeImpl.DEFAULT_CRITICAL_MIN_VOLTAGE - 100)) // + .output(LOW_MIN_VOLTAGE_FAULT, true) // + .output(LOW_MIN_VOLTAGE_WARNING, false) // + .output(LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED, false) // + .output(STATE_MACHINE, StateMachine.State.RUNNING)) // + .next(new TestCase("MinCellVoltage below critical value - error") // + .input(LOW_MIN_VOLTAGE_FAULT, true) // + .input(CURRENT, 0) // + .input(MIN_CELL_VOLTAGE, (BatteryFeneconHomeImpl.DEFAULT_CRITICAL_MIN_VOLTAGE - 100)) // + .output(LOW_MIN_VOLTAGE_FAULT, true) // + .output(LOW_MIN_VOLTAGE_WARNING, false) // + .output(LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED, false)) // + .next(new TestCase() // + .output(STATE_MACHINE, StateMachine.State.ERROR)) // + .next(new TestCase("MinCellVoltage below critical value - go stopped") // + .input(LOW_MIN_VOLTAGE_FAULT, true) // + .input(CURRENT, 0) // + + // MinCellVoltage would be null, but there is not DummyTimedata for not to test + // "getPastValues" + .input(MIN_CELL_VOLTAGE, (BatteryFeneconHomeImpl.DEFAULT_CRITICAL_MIN_VOLTAGE - 100)) // + .output(LOW_MIN_VOLTAGE_FAULT, true) // + .output(LOW_MIN_VOLTAGE_WARNING, false) // + .output(LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED, false) // + .output(STATE_MACHINE, StateMachine.State.GO_STOPPED) // + .onAfterControllersCallbacks(() -> clock.leap(2_100, ChronoUnit.SECONDS))) // 35 minutes + .next(new TestCase() // + .input(MODBUS_COMMUNICATION_FAILED, true) // + ) // + .next(new TestCase("MinCellVoltage below critical value - stopped") // + .input(CURRENT, 0) // + .input(MODBUS_COMMUNICATION_FAILED, true) // + .input(MIN_CELL_VOLTAGE, (BatteryFeneconHomeImpl.DEFAULT_CRITICAL_MIN_VOLTAGE - 100)) // + .output(LOW_MIN_VOLTAGE_WARNING, false) // + .output(LOW_MIN_VOLTAGE_FAULT, false) // + .output(LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED, true) // + .output(STATE_MACHINE, StateMachine.State.STOPPED) // + ); + } + + @Test + public void testMinVoltageCharging() throws Exception { + final var clock = new TimeLeapClock(Instant.parse("2020-01-01T01:00:00.00Z"), ZoneOffset.UTC); + var sut = new BatteryFeneconHomeImpl(); + new ComponentTest(sut) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("componentManager", new DummyComponentManager(clock)) // + .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addComponent(new DummyInputOutput(IO_ID)) // + .activate(MyConfig.create() // + .setId(BATTERY_ID) // + .setModbusId(MODBUS_ID) // + .setModbusUnitId(0) // + .setStartStop(StartStopConfig.START) // + .setBatteryStartUpRelay("io0/InputOutput4")// + .build())// + + .next(new TestCase() // + .input(BATTERY_RELAY, false) // + .input(BMS_CONTROL, true) // Switched On + .output(STATE_MACHINE, StateMachine.State.UNDEFINED))// + .next(new TestCase() // + .onBeforeProcessImage(assertLog(sut, "GoRunning-Undefined")) // + .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .next(new TestCase() // + .onBeforeProcessImage(assertLog(sut, "GoRunning-StartUpRelayOff")) // + .output(STATE_MACHINE, StateMachine.State.GO_RUNNING))// + .next(new TestCase() // + .onBeforeProcessImage(assertLog(sut, "GoRunning-RetryModbusCommunication")) // + .output(STATE_MACHINE, StateMachine.State.GO_RUNNING))// + .next(new TestCase() // + .onBeforeProcessImage(assertLog(sut, "GoRunning-WaitForBmsControl")) // + .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .next(new TestCase() // + .onBeforeProcessImage(assertLog(sut, "GoRunning-WaitForModbusCommunication")) // + .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .next(new TestCase() // + .output(STATE_MACHINE, StateMachine.State.RUNNING)) + + /* + * Critical min voltage + */ + .next(new TestCase("MinCellVoltage below critical value") // + .input(MIN_CELL_VOLTAGE, (BatteryFeneconHomeImpl.DEFAULT_CRITICAL_MIN_VOLTAGE - 100)) // + .input(CURRENT, 0) // + .output(LOW_MIN_VOLTAGE_WARNING, true) // + .output(LOW_MIN_VOLTAGE_FAULT, false) // + .output(STATE_MACHINE, StateMachine.State.RUNNING) // + .output(LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED, false) // + .onAfterControllersCallbacks( + () -> clock.leap(BatteryFeneconHomeImpl.TIMEOUT - 10, ChronoUnit.SECONDS))) // + .next(new TestCase("MinCellVoltage below critical value - charging resets time") // + .input(MIN_CELL_VOLTAGE, (BatteryFeneconHomeImpl.DEFAULT_CRITICAL_MIN_VOLTAGE - 100)) // + .input(CURRENT, -300) // + .output(LOW_MIN_VOLTAGE_WARNING, true) // + .output(LOW_MIN_VOLTAGE_FAULT, false) // + .output(STATE_MACHINE, StateMachine.State.RUNNING) // + .output(LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED, false)) // + .next(new TestCase("MinCellVoltage below critical value - charging") // + .input(CURRENT, -2000) // + .input(MIN_CELL_VOLTAGE, (BatteryFeneconHomeImpl.DEFAULT_CRITICAL_MIN_VOLTAGE + 50)) // + .output(LOW_MIN_VOLTAGE_WARNING, false) // + .output(LOW_MIN_VOLTAGE_FAULT, false) // + .output(STATE_MACHINE, StateMachine.State.RUNNING) // + .output(LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED, false) // + ); + } } diff --git a/io.openems.edge.battery.fenecon.home/test/io/openems/edge/battery/fenecon/home/TestStatic.java b/io.openems.edge.battery.fenecon.home/test/io/openems/edge/battery/fenecon/home/TestStatic.java new file mode 100644 index 00000000000..3c8d218c3f4 --- /dev/null +++ b/io.openems.edge.battery.fenecon.home/test/io/openems/edge/battery/fenecon/home/TestStatic.java @@ -0,0 +1,24 @@ +package io.openems.edge.battery.fenecon.home; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import io.openems.edge.battery.fenecon.home.BatteryFeneconHomeImpl.MinVoltageSubState; + +public class TestStatic { + + @Test + public void testGetMinVoltageSubState() { + + assertEquals(MinVoltageSubState.BELOW_LIMIT_CHARGING, + BatteryFeneconHomeImpl.getMinVoltageSubState(2800, 2700, -2000)); + + assertEquals(MinVoltageSubState.BELOW_LIMIT, BatteryFeneconHomeImpl.getMinVoltageSubState(2800, 2600, 0)); + assertEquals(MinVoltageSubState.BELOW_LIMIT, BatteryFeneconHomeImpl.getMinVoltageSubState(2800, 2600, 2000)); + + assertEquals(MinVoltageSubState.ABOVE_LIMIT, + BatteryFeneconHomeImpl.getMinVoltageSubState(2800, Integer.MAX_VALUE, 0)); + assertEquals(MinVoltageSubState.ABOVE_LIMIT, BatteryFeneconHomeImpl.getMinVoltageSubState(2800, 2900, 1000)); + } +} diff --git a/io.openems.edge.batteryinverter.api/src/io/openems/edge/batteryinverter/api/SymmetricBatteryInverter.java b/io.openems.edge.batteryinverter.api/src/io/openems/edge/batteryinverter/api/SymmetricBatteryInverter.java index 3e74c1bef9a..32aa035b4f1 100644 --- a/io.openems.edge.batteryinverter.api/src/io/openems/edge/batteryinverter/api/SymmetricBatteryInverter.java +++ b/io.openems.edge.batteryinverter.api/src/io/openems/edge/batteryinverter/api/SymmetricBatteryInverter.java @@ -106,6 +106,34 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ ACTIVE_DISCHARGE_ENERGY(Doc.of(OpenemsType.LONG) // .unit(Unit.CUMULATED_WATT_HOURS) // + .persistencePriority(PersistencePriority.HIGH)// + ), // + + /** + * Inverter DC Minimum Voltage. + * + *
      + *
    • Interface: SymmetricBatteryInverter + *
    • Type: Integer + *
    • Unit: V + *
    + */ + DC_MIN_VOLTAGE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT) // + .persistencePriority(PersistencePriority.HIGH)// + ), // + + /** + * Inverter DC Max Voltage. + * + *
      + *
    • Interface: SymmetricBatteryInverter + *
    • Type: Integer + *
    • Unit: V + *
    + */ + DC_MAX_VOLTAGE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT) // .persistencePriority(PersistencePriority.HIGH) // ); @@ -358,4 +386,81 @@ public default void _setActiveDischargeEnergy(long value) { this.getActiveDischargeEnergyChannel().setNextValue(value); } + /** + * Gets the Channel for {@link ChannelId#DC_MIN_VOLTAGE}. + * + * @return the Channel + */ + public default IntegerReadChannel getDcMinVoltageChannel() { + return this.channel(ChannelId.DC_MIN_VOLTAGE); + } + + /** + * Gets the Minimum Inverter DC Voltage in [V]. See + * {@link ChannelId#DC_MIN_VOLTAGE}. + * + * @return the Channel {@link Value} + */ + public default Value getDcMinVoltage() { + return this.getDcMinVoltageChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#DC_MIN_VOLTAGE} + * Channel. + * + * @param value the next value + */ + public default void _setDcMinVoltage(Integer value) { + this.getDcMinVoltageChannel().setNextValue(value); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#DC_MIN_VOLTAGE} + * Channel. + * + * @param value the next value + */ + public default void _setDcMinVoltage(int value) { + this.getDcMinVoltageChannel().setNextValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#DC_MAX_VOLTAGE}. + * + * @return the Channel + */ + public default IntegerReadChannel getDcMaxVoltageChannel() { + return this.channel(ChannelId.DC_MAX_VOLTAGE); + } + + /** + * Gets the Maximum Inverter DC Voltage in [V]. See + * {@link ChannelId#DC_MAX_VOLTAGE}. + * + * @return the Channel {@link Value} + */ + public default Value getDcMaxVoltage() { + return this.getDcMaxVoltageChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#DC_MAX_VOLTAGE} + * Channel. + * + * @param value the next value + */ + public default void _setDcMaxVoltage(Integer value) { + this.getDcMaxVoltageChannel().setNextValue(value); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#DC_MAX_VOLTAGE} + * Channel. + * + * @param value the next value + */ + public default void _setDcMaxVoltage(int value) { + this.getDcMaxVoltageChannel().setNextValue(value); + } } diff --git a/io.openems.edge.batteryinverter.api/src/io/openems/edge/batteryinverter/test/DummyManagedSymmetricBatteryInverter.java b/io.openems.edge.batteryinverter.api/src/io/openems/edge/batteryinverter/test/DummyManagedSymmetricBatteryInverter.java index c108b9466ec..6e9554e74e1 100644 --- a/io.openems.edge.batteryinverter.api/src/io/openems/edge/batteryinverter/test/DummyManagedSymmetricBatteryInverter.java +++ b/io.openems.edge.batteryinverter.api/src/io/openems/edge/batteryinverter/test/DummyManagedSymmetricBatteryInverter.java @@ -65,6 +65,28 @@ public DummyManagedSymmetricBatteryInverter withMaxApparentPower(int value) { return this; } + /** + * Set {@link SymmetricBatteryInverter.ChannelId#DC_MIN_VOLTAGE}. + * + * @param value the value + * @return myself + */ + public DummyManagedSymmetricBatteryInverter withDcMinVoltage(int value) { + TestUtils.withValue(this, SymmetricBatteryInverter.ChannelId.DC_MIN_VOLTAGE, value); + return this; + } + + /** + * Set {@link SymmetricBatteryInverter.ChannelId#DC_MAX_VOLTAGE}. + * + * @param value the value + * @return myself + */ + public DummyManagedSymmetricBatteryInverter withDcMaxVoltage(int value) { + TestUtils.withValue(this, SymmetricBatteryInverter.ChannelId.DC_MAX_VOLTAGE, value); + return this; + } + @Override public void run(Battery battery, int setActivePower, int setReactivePower) throws OpenemsNamedException { this._setActivePower(setActivePower); 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 976d430e141..80774e5c800 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 @@ -1,6 +1,7 @@ package io.openems.edge.batteryinverter.kaco.blueplanetgridsave; import static io.openems.edge.common.channel.ChannelUtils.setWriteValueIfNotRead; +import static io.openems.edge.common.sum.GridMode.ON_GRID; import java.time.Duration; import java.time.Instant; @@ -54,7 +55,6 @@ import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.startstop.StartStop; import io.openems.edge.common.startstop.StartStoppable; -import io.openems.edge.common.sum.GridMode; import io.openems.edge.common.taskmanager.Priority; import io.openems.edge.ess.power.api.Phase; import io.openems.edge.ess.power.api.Pwr; @@ -75,6 +75,8 @@ public class BatteryInverterKacoBlueplanetGridsaveImpl extends AbstractSunSpecBa private static final int UNIT_ID = 1; private static final int READ_FROM_MODBUS_BLOCK = 1; + private static final int DC_MIN_VOLTAGE_LIMIT = 650; + private static final int DC_MAX_VOLTAGE_LIMIT = 1315; private final Logger log = LoggerFactory.getLogger(BatteryInverterKacoBlueplanetGridsaveImpl.class); private final StateMachine stateMachine = new StateMachine(State.UNDEFINED); @@ -145,7 +147,9 @@ public BatteryInverterKacoBlueplanetGridsaveImpl() { StartStoppable.ChannelId.values(), // BatteryInverterKacoBlueplanetGridsave.ChannelId.values() // ); - this._setGridMode(GridMode.ON_GRID); + this._setGridMode(ON_GRID); + this._setDcMinVoltage(DC_MIN_VOLTAGE_LIMIT); + this._setDcMaxVoltage(DC_MAX_VOLTAGE_LIMIT); } @Activate diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/KacoSunSpecModel.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/KacoSunSpecModel.java index 139f38ba225..2757dbf6616 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/KacoSunSpecModel.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/KacoSunSpecModel.java @@ -3,444 +3,129 @@ import io.openems.common.channel.AccessMode; import io.openems.common.channel.Unit; import io.openems.common.types.OptionsEnum; +import io.openems.edge.bridge.modbus.sunspec.Point; +import io.openems.edge.bridge.modbus.sunspec.Point.EnumPoint; +import io.openems.edge.bridge.modbus.sunspec.Point.ScaleFactorPoint; +import io.openems.edge.bridge.modbus.sunspec.Point.ScaledValuePoint; +import io.openems.edge.bridge.modbus.sunspec.Point.ValuePoint; import io.openems.edge.bridge.modbus.sunspec.SunSpecModel; import io.openems.edge.bridge.modbus.sunspec.SunSpecModelType; import io.openems.edge.bridge.modbus.sunspec.SunSpecPoint; -import io.openems.edge.bridge.modbus.sunspec.SunSpecPoint.PointImpl; -import io.openems.edge.bridge.modbus.sunspec.SunSpecPoint.PointType; public enum KacoSunSpecModel implements SunSpecModel { - S_64201(// - "Bidirectional inverter control", // + S_64201("Bidirectional inverter control", // "Bidirectional inverter control backend", // - "", // - 52, // - KacoSunSpecModel.S64201.values(), // - SunSpecModelType.VENDOR_SPECIFIC), // - S_64202(// - "Battery Charge Discharge Characteristic", // + 52 /* length */, KacoSunSpecModel.S64201.values(), SunSpecModelType.VENDOR_SPECIFIC), // + S_64202("Battery Charge Discharge Characteristic", // "Bidirectional inverter battery charge discharge characteristic", // - "", // - 14, // - KacoSunSpecModel.S64202.values(), // - SunSpecModelType.VENDOR_SPECIFIC), // - S_64203(// - "Batterysystem Information", // + 14 /* length */, KacoSunSpecModel.S64202.values(), SunSpecModelType.VENDOR_SPECIFIC), // + S_64203("Batterysystem Information", // "Batterysystem Information Frontend", // - "", // - 26, // - KacoSunSpecModel.S64203.values(), // - SunSpecModelType.VENDOR_SPECIFIC), // - S_64204(// - "Q(U) extended", // + 26 /* length */, KacoSunSpecModel.S64203.values(), SunSpecModelType.VENDOR_SPECIFIC), // + S_64204("Q(U) extended", // "Q(U) offset extension", // - "", // - 8, // - KacoSunSpecModel.S64204.values(), // - SunSpecModelType.VENDOR_SPECIFIC // - ); // + 8 /* length */, KacoSunSpecModel.S64204.values(), SunSpecModelType.VENDOR_SPECIFIC // + ); public static enum S64201 implements SunSpecPoint { - VERSION_MAJOR(new PointImpl(// - "S64201_VERSION_MAJOR", // - "Version", // - "Major Version of model", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - VERSION_MINOR(new PointImpl(// - "S64201_VERSION_MINOR", // - "VerMinor", // - "Minor Version of model", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - REQUESTED_STATE(new PointImpl(// - "S64201_REQUESTED_STATE", // - "RequestedState", // - "Enumerated value. Control operating state", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S64201RequestedState.values())), // - CURRENT_STATE(new PointImpl(// - "S64201_CURRENT_STATE", // - "CurrentState", // - "Enumerated value. Operating State", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S64201CurrentState.values())), - CONTROL_MODE(new PointImpl(// - "S64201_CONTROL_MODE", // - "ControlMode", // - "Power Control mode", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S64201ControlMode.values())), - RESERVED_5(new ReservedPointImpl("S64201_RESERVED_5")), // - WATCHDOG(new PointImpl(// - "S64201_WATCHDOG", // - "Watchdog", // - "Enable Watchdog", // - """ - Register must be written with the desired watchdog timeout in seconds. \ - Watchdog timer is reset on every write access to the value written \ - to the register. 0 means watchdog is disabled. It is recommended to \ - re-write the register at least once before half of the watchdog timeout \ - has elapsed.""", // - PointType.UINT16, // - true, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - W_SET_PCT(new PointImpl(// - "S64201_W_SET_PCT", // - "WSetPct", // - "Active power output setpoint (in percent of WMax)", // + VERSION_MAJOR(new ValuePoint("S64201_VERSION_MAJOR", "Major Version of model", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + VERSION_MINOR(new ValuePoint("S64201_VERSION_MINOR", "Minor Version of model", "", // + ValuePoint.Type.UINT16, true, AccessMode.READ_ONLY, Unit.NONE)), + REQUESTED_STATE(new EnumPoint("S64201_REQUESTED_STATE", "Enumerated value. Control operating state", "", // + EnumPoint.Type.ENUM16, true, AccessMode.READ_WRITE, S64201RequestedState.values())), // + CURRENT_STATE(new EnumPoint("S64201_CURRENT_STATE", "Enumerated value. Operating State", "", // + EnumPoint.Type.ENUM16, true, AccessMode.READ_ONLY, S64201CurrentState.values())), + CONTROL_MODE(new EnumPoint("S64201_CONTROL_MODE", "Power Control mode", "", // + EnumPoint.Type.ENUM16, true, AccessMode.READ_WRITE, S64201ControlMode.values())), + RESERVED_5(new ReservedPoint("S64201_RESERVED_5")), // + WATCHDOG(new ValuePoint("S64201_WATCHDOG", "Enable Watchdog", """ + Register must be written with the desired watchdog timeout in seconds. \ + Watchdog timer is reset on every write access to the value written \ + to the register. 0 means watchdog is disabled. It is recommended to \ + re-write the register at least once before half of the watchdog timeout \ + has elapsed.""", // + ValuePoint.Type.UINT16, true, AccessMode.READ_WRITE, Unit.SECONDS)), + W_SET_PCT(new ScaledValuePoint("S64201_W_SET_PCT", "Active power output setpoint (in percent of WMax)", // "negative values mean charge", // - PointType.INT16, // - true, // - AccessMode.READ_WRITE, // - Unit.PERCENT, // - "W_SET_PCT_SF", // - new OptionsEnum[0])), // - VAR_SET_PCT(new PointImpl(// - "S64201_VAR_SET_PCT", // - "VarSetPct", // - "Reactive power output setpoint (in percent of VAMax)", // + ValuePoint.Type.INT16, true, AccessMode.READ_WRITE, Unit.PERCENT, "W_SET_PCT_SF")), // + VAR_SET_PCT(new ScaledValuePoint("S64201_VAR_SET_PCT", "Reactive power output setpoint (in percent of VAMax)", // "negative values mean charge", // - PointType.INT16, // - true, // - AccessMode.READ_WRITE, // - Unit.PERCENT, // - "VAR_SET_PCT_SF", // - new OptionsEnum[0])), // - RESERVED_9(new ReservedPointImpl("S64201_RESERVED_9")), // - RESERVED_10(new ReservedPointImpl("S64201_RESERVED_10")), // - RESERVED_11(new ReservedPointImpl("S64201_RESERVED_11")), // - RESERVED_12(new ReservedPointImpl("S64201_RESERVED_12")), // - RESERVED_13(new ReservedPointImpl("S64201_RESERVED_13")), // - ST_VND(new PointImpl(// - "S64201_ST_VND", // - "StVnd", // - "PrologState", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S64201StVnd.values())), - ST_PU(new PointImpl(// - "S64201_ST_PU", // - "StPu", // - "Power Unit State (DSP)", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S64201StPu.values())), - ST_PCU(new PointImpl(// - "S64201_ST_PCU", // - "StPcu", // - "Precharge unit state", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S64201StPcu.values())), - ERR_PCU(new PointImpl(// - "S64201_ERR_PCU", // - "ErrPcu", // - "Precharge unit error", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S64201ErrPcu.values())), - WPARAM_RMP_TMS(new PointImpl(// - "S64201_WPARAM_RMP_TMS", // - "WparamRmpTms", // + ValuePoint.Type.INT16, true, AccessMode.READ_WRITE, Unit.PERCENT, "VAR_SET_PCT_SF")), // + RESERVED_9(new ReservedPoint("S64201_RESERVED_9")), // + RESERVED_10(new ReservedPoint("S64201_RESERVED_10")), // + RESERVED_11(new ReservedPoint("S64201_RESERVED_11")), // + RESERVED_12(new ReservedPoint("S64201_RESERVED_12")), // + RESERVED_13(new ReservedPoint("S64201_RESERVED_13")), // + ST_VND(new EnumPoint("S64201_ST_VND", "PrologState", "", // + EnumPoint.Type.ENUM16, false, AccessMode.READ_ONLY, S64201StVnd.values())), + ST_PU(new EnumPoint("S64201_ST_PU", "Power Unit State (DSP)", "", // + EnumPoint.Type.ENUM16, true, AccessMode.READ_ONLY, S64201StPu.values())), + ST_PCU(new EnumPoint("S64201_ST_PCU", "Precharge unit state", "", // + EnumPoint.Type.ENUM16, false, AccessMode.READ_ONLY, S64201StPcu.values())), + ERR_PCU(new EnumPoint("S64201_ERR_PCU", "Precharge unit error", "", // + EnumPoint.Type.ENUM16, false, AccessMode.READ_ONLY, S64201ErrPcu.values())), + WPARAM_RMP_TMS(new ValuePoint("S64201_WPARAM_RMP_TMS", "WparamRmpDecTmm", // "The time of the PT1 in seconds (time to accomplish a change of 99,3% which means 5tau)" + " for active power (W) in response to changes of WSetPct.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_WRITE, // - Unit.MILLISECONDS, // - null, // - new OptionsEnum[0])), // - WPARAM_RMP_DEC_TMM(new PointImpl(// - "S64201_WPARAM_RMP_DEC_TMM", // - "WparamRmpDecTmm", // + ValuePoint.Type.UINT16, true, AccessMode.READ_WRITE, Unit.MILLISECONDS)), // + WPARAM_RMP_DEC_TMM(new ScaledValuePoint("S64201_WPARAM_RMP_DEC_TMM", "WparamRmpDecTmm", // "The maximum rate at which the active power (W) value may be decreased in response to changes of WSetPct", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_WRITE, // - Unit.PERCENT, // - "RMP_INC_DEC_SF", // - new OptionsEnum[0])), // - WPARAM_RMP_INC_TMM(new PointImpl(// - "S64201_WPARAM_RMP_INC_TMM", // - "WparamRmpIncTmm", // + ValuePoint.Type.UINT16, true, AccessMode.READ_WRITE, Unit.PERCENT, "RMP_INC_DEC_SF")), // + WPARAM_RMP_INC_TMM(new ScaledValuePoint("S64201_WPARAM_RMP_INC_TMM", "WparamRmpIncTmm", // "The maximum rate at which the active power (W) value may be increased in response to changes of WSetPct", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_WRITE, // - Unit.PERCENT, // - "RMP_INC_DEC_SF", // - new OptionsEnum[0])), // - RESERVED_21(new ReservedPointImpl("S64201_RESERVED_21")), // - RESERVED_22(new ReservedPointImpl("S64201_RESERVED_22")), // - W_PARAM_ENA(new PointImpl(// - "S64201_W_PARAM_ENA", // - "WParamEna", // + ValuePoint.Type.UINT16, true, AccessMode.READ_WRITE, Unit.PERCENT, "RMP_INC_DEC_SF")), // + RESERVED_21(new ReservedPoint("S64201_RESERVED_21")), // + RESERVED_22(new ReservedPoint("S64201_RESERVED_22")), // + W_PARAM_ENA(new EnumPoint("S64201_W_PARAM_ENA", "WSet_Ena control", // "Enumerated value. Enable filter and ramp rate parameters for active power setpoint (W)", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S64201WParamEna.values())), // - VAR_PARAM_RMP_TMS(new PointImpl(// - "S64201_VAR_PARAM_RMP_TMS", // - "VarParamRmpTms", // + EnumPoint.Type.ENUM16, true, AccessMode.READ_WRITE, S64201WParamEna.values())), // + VAR_PARAM_RMP_TMS(new ScaledValuePoint("S64201_VAR_PARAM_RMP_TMS", "VarParamRmpTms", // "The time of the PT1 in seconds (time to accomplish a change of 99,3% which means 5tau) " + "for reactive power (var) in response to changes of VarSetPct.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - "RMP_TMS_SF", // - new OptionsEnum[0])), // - VAR_PARAM_RMP_DEC_TMM(new PointImpl(// - "S64201_VAR_PARAM_RMP_DEC_TMM", // - "VarParamRmpDecTmm", // + ValuePoint.Type.UINT16, true, AccessMode.READ_WRITE, Unit.SECONDS, "RMP_TMS_SF")), // + VAR_PARAM_RMP_DEC_TMM(new ScaledValuePoint("S64201_VAR_PARAM_RMP_DEC_TMM", "VarParamRmpDecTmm", // "The maximum rate at which the reactive power (var) may be decreased in response to changes of VarSetPct.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_WRITE, // - Unit.PERCENT, // - "RMP_INC_DEC_SF", // - new OptionsEnum[0])), // - VAR_PARAM_RMP_INC_TMM(new PointImpl(// - "S64201_VAR_PARAM_RMP_INC_TMM", // - "VarParamRmpDecTmm", // + ValuePoint.Type.UINT16, true, AccessMode.READ_WRITE, Unit.PERCENT, "RMP_INC_DEC_SF")), // + VAR_PARAM_RMP_INC_TMM(new ScaledValuePoint("S64201_VAR_PARAM_RMP_INC_TMM", "VarParamRmpIncTmm", // "The maximum rate at which the reactive power (var) may be increased in response to changes of VarSetPct.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_WRITE, // - Unit.PERCENT, // - "RMP_INC_DEC_SF", // - new OptionsEnum[0])), // - RESERVED_27(new ReservedPointImpl("S64201_RESERVED_27")), // - RESERVED_28(new ReservedPointImpl("S64201_RESERVED_28")), // - VAR_PARAM_ENA(new PointImpl(// - "S64201_VAR_PARAM_ENA", // - "VarParamEna", // + ValuePoint.Type.UINT16, true, AccessMode.READ_WRITE, Unit.PERCENT, "RMP_INC_DEC_SF")), // + RESERVED_27(new ReservedPoint("S64201_RESERVED_27")), // + RESERVED_28(new ReservedPoint("S64201_RESERVED_28")), // + VAR_PARAM_ENA(new EnumPoint("S64201_VAR_PARAM_ENA", "VarParam_Ena", // "Enumerated value. Enable filter and ramp rate parameters for reactive power setpoint (var)", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S64201VarParamEna.values())), // - PH_VPH_A(new PointImpl(// - "S64201_PH_VPH_A", // - "Phase Voltage AN", // - "Phase Voltage AN", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_B(new PointImpl(// - "S64201_PH_VPH_B", // - "Phase Voltage BN", // - "Phase Voltage BN", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_C(new PointImpl(// - "S64201_PH_VPH_C", // - "Phase Voltage CN", // - "Phase Voltage CN", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - W(new PointImpl(// - "S64201_W", // - "Watts", // - "AC Power", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - V_AR(new PointImpl(// - "S64201_V_AR", // - "VAr", // - "AC Reactive Power", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "V_AR_SF", // - new OptionsEnum[0])), // - HZ(new PointImpl(// - "S64201_HZ", // - "Hz", // - "Line Frequency", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.MILLIHERTZ, // - "mHZ_SF", // - new OptionsEnum[0])), // - RESERVED_36(new ReservedPointImpl("S64201_RESERVED_36")), // - RESERVED_37(new ReservedPointImpl("S64201_RESERVED_37")), // - RESERVED_38(new ReservedPointImpl("S64201_RESERVED_38")), // - RESERVED_39(new ReservedPointImpl("S64201_RESERVED_39")), // - RESERVED_40(new ReservedPointImpl("S64201_RESERVED_40")), // - RESERVED_41(new ReservedPointImpl("S64201_RESERVED_41")), // - RESERVED_42(new ReservedPointImpl("S64201_RESERVED_42")), // - RESERVED_43(new ReservedPointImpl("S64201_RESERVED_43")), // - W_SET_PCT_SF(new PointImpl(// - "S64201_W_SET_PCT_SF", // - "WSetPct_SF", // - "Scale factor for active power setpoint (% WMax)", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - VAR_SET_PCT_SF(new PointImpl(// - "S64201_VAR_SET_PCT_SF", // - "VarSetPct_SF", // - "Scale factor for reactive power setpoint (% VAMax)", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - RMP_TMS_SF(new PointImpl(// - "S64201_RMP_TMS_SF", // - "RmpTms_SF", // - "Scale factor for PT1", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - RMP_INC_DEC_SF(new PointImpl(// - "S64201_RMP_INC_DEC_SF", // - "RmpIncDec_SF", // - "Scale factor for increment and decrement ramps.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - V_SF(new PointImpl(// - "S64201_V_SF", // - "V_SF", // - "Scale factor for voltage measurements", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - W_SF(new PointImpl(// - "S64201_W_SF", // - "W_SF", // - "Scale factor for active power measurement", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - V_AR_SF(new PointImpl(// - "S64201_V_AR_SF", // - "VAr_SF", // - "Scale factor for reactive power measurement", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - HZ_SF(new PointImpl(// - "S64201_HZ_SF", // - "Hz_SF", // - "Scale factor for frequency measurement", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - ; // + EnumPoint.Type.ENUM16, true, AccessMode.READ_WRITE, S64201VarParamEna.values())), // + PH_VPH_A(new ScaledValuePoint("S64201_PH_VPH_A", "Phase Voltage AN", "", // + ValuePoint.Type.UINT16, true, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_B(new ScaledValuePoint("S64201_PH_VPH_B", "Phase Voltage BN", "", // + ValuePoint.Type.UINT16, true, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_C(new ScaledValuePoint("S64201_PH_VPH_C", "Phase Voltage CN", "", // + ValuePoint.Type.UINT16, true, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + W(new ScaledValuePoint("S64201_W", "AC Power", "", // + ValuePoint.Type.INT16, true, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + V_AR(new ScaledValuePoint("S64201_V_AR", "AC Reactive Power", "", // + ValuePoint.Type.INT16, true, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "V_AR_SF")), // + HZ(new ScaledValuePoint("S64201_HZ", "Line Frequency", "", // + ValuePoint.Type.INT16, true, AccessMode.READ_ONLY, Unit.MILLIHERTZ, "mHZ_SF")), // + RESERVED_36(new ReservedPoint("S64201_RESERVED_36")), // + RESERVED_37(new ReservedPoint("S64201_RESERVED_37")), // + RESERVED_38(new ReservedPoint("S64201_RESERVED_38")), // + RESERVED_39(new ReservedPoint("S64201_RESERVED_39")), // + RESERVED_40(new ReservedPoint("S64201_RESERVED_40")), // + RESERVED_41(new ReservedPoint("S64201_RESERVED_41")), // + RESERVED_42(new ReservedPoint("S64201_RESERVED_42")), // + RESERVED_43(new ReservedPoint("S64201_RESERVED_43")), // + W_SET_PCT_SF( + new ScaleFactorPoint("S64201_W_SET_PCT_SF", "Scale factor for active power setpoint (% WMax)", "")), // + VAR_SET_PCT_SF(new ScaleFactorPoint("S64201_VAR_SET_PCT_SF", + "Scale factor for reactive power setpoint (% VAMax)", "")), // + RMP_TMS_SF(new ScaleFactorPoint("S64201_RMP_TMS_SF", "Scale factor for PT1", "")), // + RMP_INC_DEC_SF( + new ScaleFactorPoint("S64201_RMP_INC_DEC_SF", "Scale factor for increment and decrement ramps.", "")), // + V_SF(new ScaleFactorPoint("S64201_V_SF", "Scale factor for voltage measurements", "")), // + W_SF(new ScaleFactorPoint("S64201_W_SF", "Scale factor for active power measurement", "")), // + V_AR_SF(new ScaleFactorPoint("S64201_V_AR_SF", "Scale factor for reactive power measurement", "")), // + HZ_SF(new ScaleFactorPoint("S64201_HZ_SF", "Scale factor for frequency measurement", "")); public static enum S64201RequestedState implements OptionsEnum { UNDEFINED(-1, "Undefined"), // @@ -854,145 +539,46 @@ public OptionsEnum getUndefined() { } } - protected final PointImpl impl; + protected final Point impl; - private S64201(PointImpl impl) { + private S64201(Point impl) { this.impl = impl; } @Override - public PointImpl get() { + public Point get() { return this.impl; } } // TODO Registers DIS_MIN_V to EN_LIMIT are repeated blocks public static enum S64202 implements SunSpecPoint { - VERSION_MAJOR(new PointImpl(// - "S64202_VERSION_MAJOR", // - "Version", // - "Major Version of model", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - VERSION_MINOR(new PointImpl(// - "S64202_VERSION_MINOR", // - "VerMinor", // - "Minor Version of model", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - RESERVED_2(new ReservedPointImpl("S64202_RESERVED_2")), // - RESERVED_3(new ReservedPointImpl("S64202_RESERVED_3")), // - V_SF(new PointImpl(// - "S64202_V_SF", // - "V_SF", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - A_SF(new PointImpl(// - "S64202_A_SF", // - "A_SF", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - DIS_MIN_V_0(new PointImpl(// - "S64202_DIS_MIN_V_0", // - "min. discharge voltage", // - "min. discharge voltage", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_WRITE, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - DIS_MAX_A_0(new PointImpl(// - "S64202_DIS_MAX_A_0", // - "max. discharge current", // - "max. discharge current", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_WRITE, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - DIS_CUTOFF_A_0(new PointImpl(// - "S64202_DIS_CUTOFF_A_0", // - "discharge cutoff current", // - "Disconnect if discharge current lower than DisCutoffA", // - "no auto disconnect if value is 0", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - CHA_MAX_V_0(new PointImpl(// - "S64202_CHA_MAX_V_0", // - "max. charge voltage", // - "max. charge voltage", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_WRITE, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - CHA_MAX_A_0(new PointImpl(// - "S64202_CHA_MAX_A_0", // - "max. charge current", // - "max. charge current", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_WRITE, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - CHA_CUTOFF_A_0(new PointImpl(// - "S64202_CHA_CUTOFF_A_0", // - "charge cutoff current", // - "Disconnect if charge current lower than ChaCutoffA", // - "no auto disconnect if value is 0", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - RESERVED_0(new ReservedPointImpl("S64202_RESERVED_0")), // - EN_LIMIT_0(new PointImpl(// - "S64202_EN_LIMIT_0", // - "EnLimit", // - "new battery limits are activated when EnLimit is 1", // - "must be 0 or 1", // - PointType.UINT16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S64202EnLimit.values())), // - ; // + VERSION_MAJOR(new ValuePoint("S64202_VERSION_MAJOR", "Major Version of model", "", // + ValuePoint.Type.UINT16, true, AccessMode.READ_ONLY, Unit.NONE)), // + VERSION_MINOR(new ValuePoint("S64202_VERSION_MINOR", "Minor Version of model", "", // + ValuePoint.Type.UINT16, true, AccessMode.READ_ONLY, Unit.NONE)), // + RESERVED_2(new ReservedPoint("S64202_RESERVED_2")), // + RESERVED_3(new ReservedPoint("S64202_RESERVED_3")), // + V_SF(new ScaleFactorPoint("S64202_V_SF", "", "")), // + A_SF(new ScaleFactorPoint("S64202_A_SF", "", "")), // + DIS_MIN_V_0(new ScaledValuePoint("S64202_DIS_MIN_V_0", "min. discharge voltage", "", // + ValuePoint.Type.UINT16, true, AccessMode.READ_WRITE, Unit.VOLT, "V_SF")), // + DIS_MAX_A_0(new ScaledValuePoint("S64202_DIS_MAX_A_0", "max. discharge current", "", // + ValuePoint.Type.UINT16, true, AccessMode.READ_WRITE, Unit.AMPERE, "A_SF")), // + DIS_CUTOFF_A_0(new ScaledValuePoint("S64202_DIS_CUTOFF_A_0", "discharge cutoff current", // + "Disconnect if discharge current lower than DisCutoffA. No auto disconnect if value is 0", // + ValuePoint.Type.UINT16, false, AccessMode.READ_WRITE, Unit.AMPERE, "A_SF")), // + CHA_MAX_V_0(new ScaledValuePoint("S64202_CHA_MAX_V_0", "max. charge voltage", "", // + ValuePoint.Type.UINT16, true, AccessMode.READ_WRITE, Unit.VOLT, "V_SF")), // + CHA_MAX_A_0(new ScaledValuePoint("S64202_CHA_MAX_A_0", "max. charge current", "", // + ValuePoint.Type.UINT16, true, AccessMode.READ_WRITE, Unit.AMPERE, "A_SF")), // + CHA_CUTOFF_A_0(new ScaledValuePoint("S64202_CHA_CUTOFF_A_0", "charge cutoff current", // + "Disconnect if charge current lower than ChaCutoffA. No auto disconnect if value is 0", // + ValuePoint.Type.UINT16, false, AccessMode.READ_WRITE, Unit.AMPERE, "A_SF")), // + RESERVED_0(new ReservedPoint("S64202_RESERVED_0")), // + EN_LIMIT_0(new EnumPoint("S64202_EN_LIMIT_0", "EnLimit", // + "new battery limits are activated when EnLimit is 1. Must be 0 or 1", // + EnumPoint.Type.ENUM16, true, AccessMode.READ_WRITE, S64202EnLimit.values())); public static enum S64202EnLimit implements OptionsEnum { UNDEFINED(-1, "Undefined"), // @@ -1023,152 +609,44 @@ public OptionsEnum getUndefined() { } } - protected final PointImpl impl; + protected final Point impl; - private S64202(PointImpl impl) { + private S64202(Point impl) { this.impl = impl; } @Override - public PointImpl get() { + public Point get() { return this.impl; } } // TODO Registers BAT_ID to BAT_SW_SUM are repeated blocks public static enum S64203 implements SunSpecPoint { - VERSION_MAJOR(new PointImpl(// - "S64203_VERSION_MAJOR", // - "Version", // - "Major Version of model", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - VERSION_MINOR(new PointImpl(// - "S64203_VERSION_MINOR", // - "VerMinor", // - "Minor Version of model", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - E_M_S_ERR_CODE(new PointImpl(// - "S64203_E_M_S_ERR_CODE", // - "Errorcode from EMS", // - "Minor Version of model", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S64203EmsErrCode.values())), - SOC_SF(new PointImpl(// - "S64203_SOC_SF", // - "SoC_SF", // - "SoC scale factor", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - SOH_SF(new PointImpl(// - "S64203_SOH_SF", // - "SoH_SF", // - "SoH scale factor", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TEMP_SF(new PointImpl(// - "S64203_TEMP_SF", // - "Temp_SF", // - "temperature scale factor", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - BAT_ID_0(new PointImpl(// - "S64203_BAT_ID_0", // - "Battery ID / Serial number", // - "Battery ID or Serial number", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.VOLT, // - null, // - new OptionsEnum[0])), // - BAT_SOC_0(new PointImpl(// - "S64203_BAT_SOC_0", // - "SoC of battery", // - "SoC of battery", // + VERSION_MAJOR(new ValuePoint("S64203_VERSION_MAJOR", "Major Version of model", "", // + ValuePoint.Type.UINT16, true, AccessMode.READ_ONLY, Unit.NONE)), // + VERSION_MINOR(new ValuePoint("S64203_VERSION_MINOR", "Minor Version of model", "", // + ValuePoint.Type.UINT16, true, AccessMode.READ_ONLY, Unit.NONE)), // + EMS_ERR_CODE(new EnumPoint("S64203_EMS_ERR_CODE", "Errorcode from EMS", "", // + EnumPoint.Type.ENUM16, false, AccessMode.READ_WRITE, S64203EmsErrCode.values())), + SOC_SF(new ScaleFactorPoint("S64203_SOC_SF", "SoC scale factor", "")), // + SOH_SF(new ScaleFactorPoint("S64203_SOH_SF", "SoH scale factor", "")), // + TEMP_SF(new ScaleFactorPoint("S64203_TEMP_SF", "temperature scale factor", "")), // + BAT_ID_0(new ValuePoint("S64203_BAT_ID_0", "Battery ID or Serial number", "", // + ValuePoint.Type.UINT16, false, AccessMode.READ_WRITE, Unit.VOLT)), // + BAT_SOC_0(new ScaledValuePoint("S64203_BAT_SOC_0", "SoC of battery", // "valid range is from 0 to 100", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.PERCENT, // - "SOC_SF", // - new OptionsEnum[0])), // - BAT_SOH_0(new PointImpl(// - "S64203_BAT_SOH_0", // - "SoH of battery", // - "SoH of battery", // + ValuePoint.Type.UINT16, false, AccessMode.READ_WRITE, Unit.PERCENT, "SOC_SF")), // + BAT_SOH_0(new ScaledValuePoint("S64203_BAT_SOH_0", "SoH of battery", // "valid range is from 0 to 100", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.PERCENT, // - "SOH_SF", // - new OptionsEnum[0])), // - BAT_TEMP_0(new PointImpl(// - "S64203_BAT_TEMP_0", // - "Avg. temperature of battery", // - "Avg. temperature of battery", // + ValuePoint.Type.UINT16, false, AccessMode.READ_WRITE, Unit.PERCENT, "SOH_SF")), // + BAT_TEMP_0(new ScaledValuePoint("S64203_BAT_TEMP_0", "Avg. temperature of battery", "valid range is from -50 to 100", // - PointType.INT16, // - false, // - AccessMode.READ_WRITE, // - Unit.DEGREE_CELSIUS, // - "TEMP_SF", // - new OptionsEnum[0])), // - BAT_SW_VER_0(new PointImpl(// - "S64203_BAT_SW_VER_0", // - "Softwareversion of battery", // - "Softwareversion of battery", // - "", // - PointType.STRING4, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - BAT_SW_SUM_0(new PointImpl(// - "S64203_BAT_SW_SUM_0", // - "Software checksum of battery", // - "Software checksum of battery", // - "", // - PointType.STRING4, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // + ValuePoint.Type.INT16, false, AccessMode.READ_WRITE, Unit.DEGREE_CELSIUS, "TEMP_SF")), // + BAT_SW_VER_0(new ValuePoint("S64203_BAT_SW_VER_0", "Softwareversion of battery", "", // + ValuePoint.Type.STRING4, false, AccessMode.READ_WRITE, Unit.NONE)), // + BAT_SW_SUM_0(new ValuePoint("S64203_BAT_SW_SUM_0", "Software checksum of battery", "", // + ValuePoint.Type.STRING4, false, AccessMode.READ_WRITE, Unit.NONE)), // ; // public static enum S64203EmsErrCode implements OptionsEnum { @@ -1198,109 +676,34 @@ public OptionsEnum getUndefined() { } } - protected final PointImpl impl; + protected final Point impl; - private S64203(PointImpl impl) { + private S64203(Point impl) { this.impl = impl; } @Override - public PointImpl get() { + public Point get() { return this.impl; } } public static enum S64204 implements SunSpecPoint { - VERSION_MAJOR(new PointImpl(// - "S64204_VERSION_MAJOR", // - "Version", // - "Major Version of model", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - VERSION_MINOR(new PointImpl(// - "S64204_VERSION_MINOR", // - "VerMinor", // - "Minor Version of model", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - V_OFF_PCT(new PointImpl(// - "S64204_V_OFF_PCT", // - "VOffPct", // - "Q(U) grid voltage offset", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_WRITE, // - Unit.PERCENT, // - "V_OFF_PCT_SF", // - new OptionsEnum[0])), // - VAR_OFF_PCT(new PointImpl(// - "S64204_VAR_OFF_PCT", // - "VArOffPct", // - "Q(U) reactive power offset (The depending reference is configured in model 126. " - + "%refVal is %Wmax, %VArMax or %VArAval depending on value of DeptRef in model 126)", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_WRITE, // - Unit.PERCENT, // - "VAR_OFF_PCT_SF", // - new OptionsEnum[0])), // - RVRT_TMS(new PointImpl(// - "S64204_RVRT_TMS", // - "RvrtTms", // - "Timeout period for volt-VAR curve selection", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - OFFSET_ENA(new PointImpl(// - "S64204_OFFSET_ENA", // - "OffsetEna", // - "Q(U) dynamic Q/U offset enable", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S64204OffsetEna.values())), // - V_OFF_PCT_SF(new PointImpl(// - "S64204_V_OFF_PCT_SF", // - "VOffPct_SF", // - "Scale factor for offset voltage", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - VAR_OFF_PCT_SF(new PointImpl(// - "S64204_VAR_OFF_PCT_SF", // - "VarOffPct_SF", // - "Scale factor for reactive power offset", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])) // - ; // + VERSION_MAJOR(new ValuePoint("S64204_VERSION_MAJOR", "Major Version of model", "", // + ValuePoint.Type.UINT16, true, AccessMode.READ_ONLY, Unit.NONE)), // + VERSION_MINOR(new ValuePoint("S64204_VERSION_MINOR", "Minor Version of model", "", // + ValuePoint.Type.UINT16, true, AccessMode.READ_ONLY, Unit.NONE)), // + V_OFF_PCT(new ScaledValuePoint("S64204_V_OFF_PCT", "Q(U) grid voltage offset", "", // + ValuePoint.Type.INT16, true, AccessMode.READ_WRITE, Unit.PERCENT, "V_OFF_PCT_SF")), // + VAR_OFF_PCT(new ScaledValuePoint("S64204_VAR_OFF_PCT", "VArOffPct", // + "Q(U) reactive power offset (The depending reference is configured in model 126. %refVal is %Wmax, %VArMax or %VArAval depending on value of DeptRef in model 126)", // + ValuePoint.Type.INT16, true, AccessMode.READ_WRITE, Unit.PERCENT, "VAR_OFF_PCT_SF")), // + RVRT_TMS(new ValuePoint("S64204_RVRT_TMS", "Timeout period for volt-VAR curve selection", "", // + ValuePoint.Type.UINT16, true, AccessMode.READ_WRITE, Unit.SECONDS)), // + OFFSET_ENA(new EnumPoint("S64204_OFFSET_ENA", "Q(U) dynamic Q/U offset enable", "", // + EnumPoint.Type.ENUM16, true, AccessMode.READ_WRITE, S64204OffsetEna.values())), // + V_OFF_PCT_SF(new ScaleFactorPoint("S64204_V_OFF_PCT_SF", "Scale factor for offset voltage", "")), // + VAR_OFF_PCT_SF(new ScaleFactorPoint("S64204_VAR_OFF_PCT_SF", "Scale factor for reactive power offset", "")); public static enum S64204OffsetEna implements OptionsEnum { UNDEFINED(-1, "Undefined"), // @@ -1331,30 +734,28 @@ public OptionsEnum getUndefined() { } } - protected final PointImpl impl; + protected final Point impl; - private S64204(PointImpl impl) { + private S64204(Point impl) { this.impl = impl; } @Override - public PointImpl get() { + public Point get() { return this.impl; } } public final String label; public final String description; - public final String notes; public final int length; public final SunSpecPoint[] points; public final SunSpecModelType modelType; - private KacoSunSpecModel(String label, String description, String notes, int length, SunSpecPoint[] points, + private KacoSunSpecModel(String label, String description, int length, SunSpecPoint[] points, SunSpecModelType modelType) { this.label = label; this.description = description; - this.notes = notes; this.length = length; this.points = points; this.modelType = modelType; @@ -1370,18 +771,9 @@ public String label() { return this.label; } - private static class ReservedPointImpl extends PointImpl { - protected ReservedPointImpl(String channelId) { - super(channelId, // - "Reserved", // - "", // - "", // - PointType.PAD, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0]); + private static class ReservedPoint extends ValuePoint { + protected ReservedPoint(String channelId) { + super(channelId, "Reserved", "", ValuePoint.Type.PAD, false, AccessMode.READ_ONLY, Unit.NONE); } } diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/ElementToChannelScaleFactorConverter.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/ElementToChannelScaleFactorConverter.java index 75698cb16c2..cf558a53d99 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/ElementToChannelScaleFactorConverter.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/ElementToChannelScaleFactorConverter.java @@ -1,7 +1,7 @@ package io.openems.edge.bridge.modbus.api; import io.openems.common.exceptions.InvalidValueException; -import io.openems.edge.bridge.modbus.sunspec.SunSpecPoint; +import io.openems.edge.bridge.modbus.sunspec.Point.ScaledValuePoint; import io.openems.edge.common.channel.ChannelId; import io.openems.edge.common.channel.IntegerReadChannel; import io.openems.edge.common.component.OpenemsComponent; @@ -28,7 +28,7 @@ private static int getValueOrError(OpenemsComponent component, ChannelId channel return channel.value().getOrError(); } - public ElementToChannelScaleFactorConverter(OpenemsComponent component, SunSpecPoint point, + public ElementToChannelScaleFactorConverter(OpenemsComponent component, ScaledValuePoint point, ChannelId scaleFactorChannel) { super(// // element -> channel diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/worker/internal/TasksSupplierImpl.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/worker/internal/TasksSupplierImpl.java index f583b94b284..e7c6a4bcb02 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/worker/internal/TasksSupplierImpl.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/worker/internal/TasksSupplierImpl.java @@ -47,6 +47,7 @@ public synchronized void addProtocol(String sourceId, ModbusProtocol protocol) { */ public synchronized void removeProtocol(String sourceId) { this.taskManagers.remove(sourceId); + this.nextLowPriorityTasks.removeIf(t -> t.a() == sourceId); } @Override diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/AbstractOpenemsSunSpecComponent.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/AbstractOpenemsSunSpecComponent.java index a45c8251a35..3b01f8ce0da 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/AbstractOpenemsSunSpecComponent.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/AbstractOpenemsSunSpecComponent.java @@ -3,6 +3,7 @@ import static com.ghgande.j2mod.modbus.Modbus.ILLEGAL_ADDRESS_EXCEPTION; import static io.openems.edge.bridge.modbus.api.ModbusUtils.readElementOnce; import static io.openems.edge.bridge.modbus.api.ModbusUtils.readElementsOnce; +import static io.openems.edge.bridge.modbus.sunspec.Utils.toUpperUnderscore; import static java.util.concurrent.CompletableFuture.completedFuture; import java.util.ArrayList; @@ -37,6 +38,12 @@ import io.openems.edge.bridge.modbus.api.task.FC16WriteRegistersTask; import io.openems.edge.bridge.modbus.api.task.FC3ReadRegistersTask; import io.openems.edge.bridge.modbus.api.task.Task.ExecuteState; +import io.openems.edge.bridge.modbus.sunspec.Point.BitFieldPoint; +import io.openems.edge.bridge.modbus.sunspec.Point.BitFieldPoint.SunSpecBitPoint; +import io.openems.edge.bridge.modbus.sunspec.Point.ChannelIdPoint; +import io.openems.edge.bridge.modbus.sunspec.Point.ModbusElementPoint; +import io.openems.edge.bridge.modbus.sunspec.Point.ScaleFactorPoint; +import io.openems.edge.bridge.modbus.sunspec.Point.ScaledValuePoint; import io.openems.edge.common.channel.Channel; import io.openems.edge.common.taskmanager.Priority; @@ -231,7 +238,7 @@ private Entry getActiveModelForId(int blockId) { } /** - * Overwrite to provide custom SunSpecModel. + * Override to provide custom {@link SunSpecModel}. * * @param blockId the Block-Id * @return the {@link SunSpecModel} @@ -241,6 +248,21 @@ protected SunSpecModel getSunSpecModel(int blockId) throws IllegalArgumentExcept return null; } + /** + * Override to provide custom {@link SunSpecBitPoint}s. + * + *

    + * Use this to create a different mapping for SunSpec BitFields, e.g. Model 103 + * "Vendor defined events". + * + * @param bfp the {@link BitFieldPoint} + * @return array of {@link SunSpecBitPoint}s; null or empty uses defaults from + * {@link DefaultSunSpecModel}. + */ + protected SunSpecBitPoint[] getBitPoints(BitFieldPoint bfp) { + return null; + } + /** * Is the SunSpec initialization completed?. * @@ -277,27 +299,25 @@ protected void addBlock(int startAddress, SunSpecModel model, Priority priority) startAddress += 2; for (var i = 0; i < model.points().length; i++) { var point = model.points()[i]; - final var element = point.get().generateModbusElement(startAddress); + var elements = this.addModbusElementAndChannels(startAddress, model, point); + var length = elements.stream().mapToInt(e -> e.length).sum(); // Handle AccessMode switch (point.get().accessMode) { case READ_ONLY -> { - readElements.add(element); + readElements.addAll(elements); } case READ_WRITE -> { - readElements.add(element); - writeElements.add(element); + readElements.addAll(elements); + writeElements.addAll(elements); } case WRITE_ONLY -> { - readElements.add(new DummyRegisterElement(element.startAddress, element.length)); - writeElements.add(element); + readElements.add(new DummyRegisterElement(startAddress, length)); + writeElements.addAll(elements); } } - startAddress += element.length; - var channelId = point.getChannelId(); - this.addChannel(channelId); - this.m(channelId, element, this.generateElementToChannelConverter(model, point)); + startAddress += length; } // Create Tasks and add them to the ModbusProtocol @@ -313,6 +333,38 @@ protected void addBlock(int startAddress, SunSpecModel model, Priority priority) } } + /** + * Adds an Element of the block starting from startAddress and maps it to + * Channel(s). + * + * @param startAddress the address to start reading from + * @param model the {@link SunSpecModel} + * @param ssp the {@link SunSpecPoint} + * @return the added {@link ModbusElement}s + */ + protected List addModbusElementAndChannels(int startAddress, SunSpecModel model, SunSpecPoint ssp) { + final var p = ssp.get(); + // TODO migrate to Java 21 Switch Pattern Matching + if (p instanceof BitFieldPoint bfp) { + // Channels are added and mapped internally + var alternativeBitPoints = this.getBitPoints(bfp); + return bfp.generateModbusElements(this, channelId -> this.addChannel(channelId), startAddress, + alternativeBitPoints); + } + + if (p instanceof ModbusElementPoint mep) { + final var element = mep.generateModbusElement(startAddress); + if (p instanceof ChannelIdPoint cp) { + var channelId = cp.channelId; + this.addChannel(channelId); + this.m(channelId, element, this.generateElementToChannelConverter(model, p)); + } + return List.of(element); + } + + return List.of(); + } + /** * Converts a list of {@link ModbusElement}s to sublists, prepared for Modbus * {@link AbstractTask}s. @@ -368,7 +420,7 @@ protected static List> preprocessModbusElements(List Channel */ value -> point.isDefined(value) ? value : null, @@ -376,23 +428,26 @@ protected ElementToChannelConverter generateElementToChannelConverter(SunSpecMod // Generate Scale-Factor converter (possibly null) ElementToChannelConverter scaleFactorConverter = null; - if (point.get().scaleFactor.isPresent()) { - final var scaleFactor = point.get().scaleFactor.get(); - final var scaleFactorName = SunSpecCodeGenerator.toUpperUnderscore(scaleFactor); + + if (point instanceof ScaledValuePoint svp) { + final var scaleFactorName = toUpperUnderscore(svp.scaleFactor); scaleFactorConverter = Stream.of(model.points()) // .filter(p -> p.name().equals(scaleFactorName)) // - .map(sfp -> new ElementToChannelScaleFactorConverter(this, point, sfp.getChannelId())) // - // Found matching Scale-Factor Point in SunSpec Modal + .map(SunSpecPoint::get) // + .filter(ScaleFactorPoint.class::isInstance) // + .map(ScaleFactorPoint.class::cast) // + .map(sfp -> new ElementToChannelScaleFactorConverter(this, svp, sfp.channelId)) // + // Found matching Scale-Factor Point in SunSpec Model .findFirst() // Else: try to parse constant Scale-Factor .orElseGet(() -> { try { - return new ElementToChannelScaleFactorConverter(Integer.parseInt(scaleFactor)); + return new ElementToChannelScaleFactorConverter(Integer.parseInt(svp.scaleFactor)); } catch (NumberFormatException e) { // Unable to parse Scale-Factor to static value - this.logError(this.log, "Unable to parse Scale-Factor [" + scaleFactor + "] for Point [" - + point.name() + "]"); + this.logError(this.log, "Unable to parse Scale-Factor [" + svp.scaleFactor + "] for Point [" + + point.name + "]"); return null; } }); // @@ -408,32 +463,38 @@ protected ElementToChannelConverter generateElementToChannelConverter(SunSpecMod /** * Get the Channel for the given Point. * - * @param the Channel type - * @param point the SunSpec Point - * @return the optional Channel + * @param the Channel type + * @param ssp the {@link SunSpecPoint} + * @return the optional {@link Channel} */ - protected > Optional getSunSpecChannel(SunSpecPoint point) { - try { - return Optional.ofNullable(this.channel(point.getChannelId())); - } catch (IllegalArgumentException e) { - return Optional.empty(); + protected > Optional getSunSpecChannel(SunSpecPoint ssp) { + var point = ssp.get(); + if (point instanceof ChannelIdPoint cp) { + try { + return Optional.ofNullable(this.channel(cp.channelId)); + } catch (IllegalArgumentException e) { + // Ignore + } + } else { + // Ignore } + return Optional.empty(); } /** * Get the Channel for the given Point or throw an error if it is not available. * - * @param the Channel type - * @param point the SunSpec Point - * @return the optional Channel + * @param the Channel type + * @param ssp the {@link SunSpecPoint} + * @return the optional {@link Channel} * @throws OpenemsException if Channel is not available */ @SuppressWarnings("unchecked") - protected > T getSunSpecChannelOrError(SunSpecPoint point) throws OpenemsException { - Optional> channelOpt = this.getSunSpecChannel(point); + protected > T getSunSpecChannelOrError(SunSpecPoint ssp) throws OpenemsException { + Optional> channelOpt = this.getSunSpecChannel(ssp); if (!channelOpt.isPresent()) { - throw new OpenemsException("SunSpec Channel for Point [" + point.getClass().getSimpleName() + "." - + point.name() + "] is not available"); + throw new OpenemsException("SunSpec Channel for Point [" + ssp.getClass().getSimpleName() + "." + ssp.name() + + "] is not available"); } return (T) channelOpt.get(); } diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/DefaultSunSpecModel.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/DefaultSunSpecModel.java index f40ce5a9b4e..8911c6ee34e 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/DefaultSunSpecModel.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/DefaultSunSpecModel.java @@ -3,618 +3,242 @@ package io.openems.edge.bridge.modbus.sunspec; import io.openems.common.channel.AccessMode; +import io.openems.common.channel.Level; import io.openems.common.channel.Unit; import io.openems.common.types.OptionsEnum; +import io.openems.edge.bridge.modbus.sunspec.Point.BitFieldPoint; +import io.openems.edge.bridge.modbus.sunspec.Point.BitFieldPoint.SunSpecBitPoint; +import io.openems.edge.bridge.modbus.sunspec.Point.BitPoint; +import io.openems.edge.bridge.modbus.sunspec.Point.EnumPoint; +import io.openems.edge.bridge.modbus.sunspec.Point.ScaleFactorPoint; +import io.openems.edge.bridge.modbus.sunspec.Point.ScaledValuePoint; +import io.openems.edge.bridge.modbus.sunspec.Point.ValuePoint; /** * Do not touch this file. It is auto-generated by SunSpecCodeGenerator. */ public enum DefaultSunSpecModel implements SunSpecModel { - S_1(// - "Common", // + S_1("Common", // "All SunSpec compliant devices must include this as the first model", // - "", // - 66, // - DefaultSunSpecModel.S1.values(), // - SunSpecModelType.COMMON // - ), // - S_2(// - "Basic Aggregator", // + 66 /* length */, DefaultSunSpecModel.S1.values(), SunSpecModelType.COMMON), // + S_2("Basic Aggregator", // "Aggregates a collection of models for a given model id", // - "", // - 14, // - DefaultSunSpecModel.S2.values(), // - SunSpecModelType.AGGREGATOR // - ), // - S_15(// - "Interface Counters Model", // + 14 /* length */, DefaultSunSpecModel.S2.values(), SunSpecModelType.AGGREGATOR), // + S_15("Interface Counters Model", // "Interface counters", // - "", // - 24, // - DefaultSunSpecModel.S15.values(), // - SunSpecModelType.NETWORK_CONFIGURATION // - ), // - S_18(// - "Cellular Link", // + 24 /* length */, DefaultSunSpecModel.S15.values(), SunSpecModelType.NETWORK_CONFIGURATION), // + S_18("Cellular Link", // "Include this model to support a cellular interface link", // - "", // - 22, // - DefaultSunSpecModel.S18.values(), // - SunSpecModelType.NETWORK_CONFIGURATION // - ), // - S_101(// - "Inverter (Single Phase)", // + 22 /* length */, DefaultSunSpecModel.S18.values(), SunSpecModelType.NETWORK_CONFIGURATION), // + S_101("Inverter (Single Phase)", // "Include this model for single phase inverter monitoring", // - "", // - 50, // - DefaultSunSpecModel.S101.values(), // - SunSpecModelType.INVERTER // - ), // - S_102(// - "Inverter (Split-Phase)", // + 50 /* length */, DefaultSunSpecModel.S101.values(), SunSpecModelType.INVERTER), // + S_102("Inverter (Split-Phase)", // "Include this model for split phase inverter monitoring", // - "", // - 50, // - DefaultSunSpecModel.S102.values(), // - SunSpecModelType.INVERTER // - ), // - S_103(// - "Inverter (Three Phase)", // + 50 /* length */, DefaultSunSpecModel.S102.values(), SunSpecModelType.INVERTER), // + S_103("Inverter (Three Phase)", // "Include this model for three phase inverter monitoring", // - "", // - 50, // - DefaultSunSpecModel.S103.values(), // - SunSpecModelType.INVERTER // - ), // - S_111(// - "Inverter (Single Phase) FLOAT", // + 50 /* length */, DefaultSunSpecModel.S103.values(), SunSpecModelType.INVERTER), // + S_111("Inverter (Single Phase) FLOAT", // "Include this model for single phase inverter monitoring using float values", // - "", // - 60, // - DefaultSunSpecModel.S111.values(), // - SunSpecModelType.INVERTER // - ), // - S_112(// - "Inverter (Split Phase) FLOAT", // + 60 /* length */, DefaultSunSpecModel.S111.values(), SunSpecModelType.INVERTER), // + S_112("Inverter (Split Phase) FLOAT", // "Include this model for split phase inverter monitoring using float values", // - "", // - 60, // - DefaultSunSpecModel.S112.values(), // - SunSpecModelType.INVERTER // - ), // - S_113(// - "Inverter (Three Phase) FLOAT", // + 60 /* length */, DefaultSunSpecModel.S112.values(), SunSpecModelType.INVERTER), // + S_113("Inverter (Three Phase) FLOAT", // "Include this model for three phase inverter monitoring using float values", // - "", // - 60, // - DefaultSunSpecModel.S113.values(), // - SunSpecModelType.INVERTER // - ), // - S_120(// - "Nameplate", // + 60 /* length */, DefaultSunSpecModel.S113.values(), SunSpecModelType.INVERTER), // + S_120("Nameplate", // "Inverter Controls Nameplate Ratings", // - "", // - 26, // - DefaultSunSpecModel.S120.values(), // - SunSpecModelType.INVERTER // - ), // - S_121(// - "Basic Settings", // + 26 /* length */, DefaultSunSpecModel.S120.values(), SunSpecModelType.INVERTER), // + S_121("Basic Settings", // "Inverter Controls Basic Settings", // - "", // - 30, // - DefaultSunSpecModel.S121.values(), // - SunSpecModelType.INVERTER // - ), // - S_122(// - "Measurements_Status", // + 30 /* length */, DefaultSunSpecModel.S121.values(), SunSpecModelType.INVERTER), // + S_122("Measurements_Status", // "Inverter Controls Extended Measurements and Status", // - "", // - 44, // - DefaultSunSpecModel.S122.values(), // - SunSpecModelType.INVERTER // - ), // - S_123(// - "Immediate Controls", // + 44 /* length */, DefaultSunSpecModel.S122.values(), SunSpecModelType.INVERTER), // + S_123("Immediate Controls", // "Immediate Inverter Controls", // - "", // - 24, // - DefaultSunSpecModel.S123.values(), // - SunSpecModelType.INVERTER // - ), // - S_124(// - "Storage", // + 24 /* length */, DefaultSunSpecModel.S123.values(), SunSpecModelType.INVERTER), // + S_124("Storage", // "Basic Storage Controls", // - "", // - 24, // - DefaultSunSpecModel.S124.values(), // - SunSpecModelType.INVERTER // - ), // - S_125(// - "Pricing", // + 24 /* length */, DefaultSunSpecModel.S124.values(), SunSpecModelType.INVERTER), // + S_125("Pricing", // "Pricing Signal", // - "", // - 8, // - DefaultSunSpecModel.S125.values(), // - SunSpecModelType.INVERTER // - ), // - S_127(// - "Freq-Watt Param", // + 8 /* length */, DefaultSunSpecModel.S125.values(), SunSpecModelType.INVERTER), // + S_127("Freq-Watt Param", // "Parameterized Frequency-Watt", // - "", // - 10, // - DefaultSunSpecModel.S127.values(), // - SunSpecModelType.INVERTER // - ), // - S_128(// - "Dynamic Reactive Current", // + 10 /* length */, DefaultSunSpecModel.S127.values(), SunSpecModelType.INVERTER), // + S_128("Dynamic Reactive Current", // "Dynamic Reactive Current", // - "", // - 14, // - DefaultSunSpecModel.S128.values(), // - SunSpecModelType.INVERTER // - ), // - S_145(// - "Extended Settings", // + 14 /* length */, DefaultSunSpecModel.S128.values(), SunSpecModelType.INVERTER), // + S_145("Extended Settings", // "Inverter controls extended settings", // - "", // - 8, // - DefaultSunSpecModel.S145.values(), // - SunSpecModelType.INVERTER // - ), // - S_201(// - "Meter (Single Phase)single phase (AN or AB) meter", // + 8 /* length */, DefaultSunSpecModel.S145.values(), SunSpecModelType.INVERTER), // + S_201("Meter (Single Phase)single phase (AN or AB) meter", // "Include this model for single phase (AN or AB) metering", // + 105 /* length */, DefaultSunSpecModel.S201.values(), SunSpecModelType.METER), // + S_202("split single phase (ABN) meter", // "", // - 105, // - DefaultSunSpecModel.S201.values(), // - SunSpecModelType.METER // - ), // - S_202(// - "split single phase (ABN) meter", // - "", // - "", // - 105, // - DefaultSunSpecModel.S202.values(), // - SunSpecModelType.METER // - ), // - S_203(// - "wye-connect three phase (abcn) meter", // - "", // - "", // - 105, // - DefaultSunSpecModel.S203.values(), // - SunSpecModelType.METER // - ), // - S_204(// - "delta-connect three phase (abc) meter", // + 105 /* length */, DefaultSunSpecModel.S202.values(), SunSpecModelType.METER), // + S_203("wye-connect three phase (abcn) meter", // "", // + 105 /* length */, DefaultSunSpecModel.S203.values(), SunSpecModelType.METER), // + S_204("delta-connect three phase (abc) meter", // "", // - 105, // - DefaultSunSpecModel.S204.values(), // - SunSpecModelType.METER // - ), // - S_305(// - "GPS", // + 105 /* length */, DefaultSunSpecModel.S204.values(), SunSpecModelType.METER), // + S_305("GPS", // "Include to support location measurements", // - "", // - 36, // - DefaultSunSpecModel.S305.values(), // - SunSpecModelType.ENVIRONMENTAL // - ), // - S_306(// - "Reference Point Model", // + 36 /* length */, DefaultSunSpecModel.S305.values(), SunSpecModelType.ENVIRONMENTAL), // + S_306("Reference Point Model", // "Include to support a standard reference point", // - "", // - 4, // - DefaultSunSpecModel.S306.values(), // - SunSpecModelType.ENVIRONMENTAL // - ), // - S_307(// - "Base Met", // + 4 /* length */, DefaultSunSpecModel.S306.values(), SunSpecModelType.ENVIRONMENTAL), // + S_307("Base Met", // "Base Meteorological Model", // - "", // - 11, // - DefaultSunSpecModel.S307.values(), // - SunSpecModelType.ENVIRONMENTAL // - ), // - S_308(// - "Mini Met Model", // + 11 /* length */, DefaultSunSpecModel.S307.values(), SunSpecModelType.ENVIRONMENTAL), // + S_308("Mini Met Model", // "Include to support a few basic measurements", // - "", // - 4, // - DefaultSunSpecModel.S308.values(), // - SunSpecModelType.ENVIRONMENTAL // - ), // - S_701(// - "DER AC Measurement", // + 4 /* length */, DefaultSunSpecModel.S308.values(), SunSpecModelType.ENVIRONMENTAL), // + S_701("DER AC Measurement", // "DER AC measurement model.", // - "", // - 153, // - DefaultSunSpecModel.S701.values(), // - SunSpecModelType.RESERVED_1 // - ), // - S_702(// - "DER Capacity", // + 153 /* length */, DefaultSunSpecModel.S701.values(), SunSpecModelType.RESERVED_1), // + S_702("DER Capacity", // "DER capacity model.", // - "", // - 50, // - DefaultSunSpecModel.S702.values(), // - SunSpecModelType.RESERVED_1 // - ), // - S_703(// - "Enter Service", // + 50 /* length */, DefaultSunSpecModel.S702.values(), SunSpecModelType.RESERVED_1), // + S_703("Enter Service", // "Enter service model.", // - "", // - 17, // - DefaultSunSpecModel.S703.values(), // - SunSpecModelType.RESERVED_1 // - ), // - S_704(// - "DER AC Controls", // + 17 /* length */, DefaultSunSpecModel.S703.values(), SunSpecModelType.RESERVED_1), // + S_704("DER AC Controls", // "DER AC controls model.", // - "", // - 57, // - DefaultSunSpecModel.S704.values(), // - SunSpecModelType.RESERVED_1 // - ), // - S_705(// - "DER Volt-Var", // + 57 /* length */, DefaultSunSpecModel.S704.values(), SunSpecModelType.RESERVED_1), // + S_705("DER Volt-Var", // "DER Volt-Var model.", // - "", // - 13, // - DefaultSunSpecModel.S705.values(), // - SunSpecModelType.RESERVED_1 // - ), // - S_706(// - "DER Volt-Watt", // + 13 /* length */, DefaultSunSpecModel.S705.values(), SunSpecModelType.RESERVED_1), // + S_706("DER Volt-Watt", // "DER Volt-Watt model.", // - "", // - 13, // - DefaultSunSpecModel.S706.values(), // - SunSpecModelType.RESERVED_1 // - ), // - S_707(// - "DER Trip LV", // + 13 /* length */, DefaultSunSpecModel.S706.values(), SunSpecModelType.RESERVED_1), // + S_707("DER Trip LV", // "DER low voltage trip model.", // - "", // - 7, // - DefaultSunSpecModel.S707.values(), // - SunSpecModelType.RESERVED_1 // - ), // - S_708(// - "DER Trip HV", // + 7 /* length */, DefaultSunSpecModel.S707.values(), SunSpecModelType.RESERVED_1), // + S_708("DER Trip HV", // "DER high voltage trip model.", // - "", // - 7, // - DefaultSunSpecModel.S708.values(), // - SunSpecModelType.RESERVED_1 // - ), // - S_709(// - "DER Trip LF", // + 7 /* length */, DefaultSunSpecModel.S708.values(), SunSpecModelType.RESERVED_1), // + S_709("DER Trip LF", // "DER low frequency trip model.", // - "", // - 7, // - DefaultSunSpecModel.S709.values(), // - SunSpecModelType.RESERVED_1 // - ), // - S_710(// - "DER Trip HF", // + 7 /* length */, DefaultSunSpecModel.S709.values(), SunSpecModelType.RESERVED_1), // + S_710("DER Trip HF", // "DER high frequency trip model.", // - "", // - 7, // - DefaultSunSpecModel.S710.values(), // - SunSpecModelType.RESERVED_1 // - ), // - S_711(// - "DER Frequency Droop", // + 7 /* length */, DefaultSunSpecModel.S710.values(), SunSpecModelType.RESERVED_1), // + S_711("DER Frequency Droop", // "DER Frequency Droop model.", // - "", // - 12, // - DefaultSunSpecModel.S711.values(), // - SunSpecModelType.RESERVED_1 // - ), // - S_712(// - "DER Watt-Var", // + 12 /* length */, DefaultSunSpecModel.S711.values(), SunSpecModelType.RESERVED_1), // + S_712("DER Watt-Var", // "DER Watt-Var model.", // - "", // - 12, // - DefaultSunSpecModel.S712.values(), // - SunSpecModelType.RESERVED_1 // - ), // - S_713(// - "DER Storage Capacity", // + 12 /* length */, DefaultSunSpecModel.S712.values(), SunSpecModelType.RESERVED_1), // + S_713("DER Storage Capacity", // "DER storage capacity.", // - "", // - 7, // - DefaultSunSpecModel.S713.values(), // - SunSpecModelType.RESERVED_1 // - ), // - S_714(// - "DER DC Measurement", // + 7 /* length */, DefaultSunSpecModel.S713.values(), SunSpecModelType.RESERVED_1), // + S_714("DER DC Measurement", // "DER DC measurement.", // - "", // - 18, // - DefaultSunSpecModel.S714.values(), // - SunSpecModelType.RESERVED_1 // - ), // - S_715(// - "DERCtl", // + 18 /* length */, DefaultSunSpecModel.S714.values(), SunSpecModelType.RESERVED_1), // + S_715("DERCtl", // "DER Control", // - "", // - 7, // - DefaultSunSpecModel.S715.values(), // - SunSpecModelType.RESERVED_1 // - ), // - S_801(// - "Energy Storage Base Model (DEPRECATED)", // + 7 /* length */, DefaultSunSpecModel.S715.values(), SunSpecModelType.RESERVED_1), // + S_801("Energy Storage Base Model (DEPRECATED)", // "This model has been deprecated.", // + 1 /* length */, DefaultSunSpecModel.S801.values(), SunSpecModelType.STORAGE), // + S_802("Battery Base Model", // "", // - 1, // - DefaultSunSpecModel.S801.values(), // - SunSpecModelType.STORAGE // - ), // - S_802(// - "Battery Base Model", // - "", // - "", // - 62, // - DefaultSunSpecModel.S802.values(), // - SunSpecModelType.STORAGE // - ), // - S_64001(// - "Veris Status and Configuration", // - "", // - "", // - 71, // - DefaultSunSpecModel.S64001.values(), // - SunSpecModelType.VENDOR_SPECIFIC // - ), // - S_64101(// - "Eltek Inverter Extension", // - "", // + 62 /* length */, DefaultSunSpecModel.S802.values(), SunSpecModelType.STORAGE), // + S_64001("Veris Status and Configuration", // "", // - 7, // - DefaultSunSpecModel.S64101.values(), // - SunSpecModelType.VENDOR_SPECIFIC // - ), // - S_64110(// - "OutBack AXS device", // + 71 /* length */, DefaultSunSpecModel.S64001.values(), SunSpecModelType.VENDOR_SPECIFIC), // + S_64101("Eltek Inverter Extension", // "", // + 7 /* length */, DefaultSunSpecModel.S64101.values(), SunSpecModelType.VENDOR_SPECIFIC), // + S_64111("Basic Charge Controller", // "", // - 282, // - DefaultSunSpecModel.S64110.values(), // - SunSpecModelType.VENDOR_SPECIFIC // - ), // - S_64111(// - "Basic Charge Controller", // + 23 /* length */, DefaultSunSpecModel.S64111.values(), SunSpecModelType.VENDOR_SPECIFIC), // + S_64112("OutBack FM Charge Controller", // "", // - "", // - 23, // - DefaultSunSpecModel.S64111.values(), // - SunSpecModelType.VENDOR_SPECIFIC // - ), // - S_64112(// - "OutBack FM Charge Controller", // - "", // - "", // - 64, // - DefaultSunSpecModel.S64112.values(), // - SunSpecModelType.VENDOR_SPECIFIC // - ); // + 64 /* length */, DefaultSunSpecModel.S64112.values(), SunSpecModelType.VENDOR_SPECIFIC); // public static enum S1 implements SunSpecPoint { - MN(new PointImpl(// - "S1_MN", // - "Manufacturer", // + MN(new ValuePoint("S1_MN", "Manufacturer", // "Well known value registered with SunSpec for compliance", // - "", // - PointType.STRING16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - MD(new PointImpl(// - "S1_MD", // - "Model", // + ValuePoint.Type.STRING16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + MD(new ValuePoint("S1_MD", "Model", // "Manufacturer specific value (32 chars)", // - "", // - PointType.STRING16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - OPT(new PointImpl(// - "S1_OPT", // - "Options", // + ValuePoint.Type.STRING16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + OPT(new ValuePoint("S1_OPT", "Options", // "Manufacturer specific value (16 chars)", // - "", // - PointType.STRING8, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - VR(new PointImpl(// - "S1_VR", // - "Version", // + ValuePoint.Type.STRING8, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + VR(new ValuePoint("S1_VR", "Version", // "Manufacturer specific value (16 chars)", // - "", // - PointType.STRING8, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - SN(new PointImpl(// - "S1_SN", // - "Serial Number", // + ValuePoint.Type.STRING8, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + SN(new ValuePoint("S1_SN", "Serial Number", // "Manufacturer specific value (32 chars)", // - "", // - PointType.STRING16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - DA(new PointImpl(// - "S1_DA", // - "Device Address", // + ValuePoint.Type.STRING16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + DA(new ValuePoint("S1_DA", "Device Address", // "Modbus device address", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - PAD(new PointImpl(// - "S1_PAD", // - "", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + PAD(new ValuePoint("S1_PAD", "", // "Force even alignment", // - "", // - PointType.PAD, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // + ValuePoint.Type.PAD, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)); - protected final PointImpl impl; + private final Point point; - private S1(PointImpl impl) { - this.impl = impl; + private S1(Point point) { + this.point = point; } @Override - public PointImpl get() { - return this.impl; + public Point get() { + return this.point; } } public static enum S2 implements SunSpecPoint { - AID(new PointImpl(// - "S2_AID", // - "AID", // + AID(new ValuePoint("S2_AID", "AID", // "Aggregated model id", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - N(new PointImpl(// - "S2_N", // - "N", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + N(new ValuePoint("S2_N", "N", // "Number of aggregated models", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - UN(new PointImpl(// - "S2_UN", // - "UN", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UN(new ValuePoint("S2_UN", "UN", // "Update Number. Incrementing number each time the mapping is changed. If the number is not changed from the last reading the direct access to a specific offset will result in reading the same logical model as before. Otherwise the entire model must be read to refresh the changes", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - ST(new PointImpl(// - "S2_ST", // - "Status", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + ST(new EnumPoint("S2_ST", "Status", // "Enumerated status code", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S2_St.values())), // - ST_VND(new PointImpl(// - "S2_ST_VND", // - "Vendor Status", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S2_St.values())), // + ST_VND(new EnumPoint("S2_ST_VND", "Vendor Status", // "Vendor specific status code", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT(new PointImpl(// - "S2_EVT", // - "Event Code", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, new OptionsEnum[0])), // + EVT(new BitFieldPoint("S2_EVT", "Event Code", // "Bitmask event code", // - "", // - PointType.BITFIELD32, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S2_Evt.values())), // - EVT_VND(new PointImpl(// - "S2_EVT_VND", // - "Vendor Event Code", // + BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, S2_Evt.values())), // + EVT_VND(new BitFieldPoint("S2_EVT_VND", "Vendor Event Code", // "Vendor specific event code", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - CTL(new PointImpl(// - "S2_CTL", // - "Control", // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + CTL(new EnumPoint("S2_CTL", "Control", // "Control register for all aggregated devices", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S2_Ctl.values())), // - CTL_VND(new PointImpl(// - "S2_CTL_VND", // - "Vendor Control", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, S2_Ctl.values())), // + CTL_VND(new EnumPoint("S2_CTL_VND", "Vendor Control", // "Vendor control register for all aggregated devices", // - "", // - PointType.ENUM32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - CTL_VL(new PointImpl(// - "S2_CTL_VL", // - "Control Value", // + EnumPoint.Type.ENUM32, false /* mandatory? */, AccessMode.READ_ONLY, new OptionsEnum[0])), // + CTL_VL(new EnumPoint("S2_CTL_VL", "Control Value", // "Numerical value used as a parameter to the control", // - "", // - PointType.ENUM32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // + EnumPoint.Type.ENUM32, false /* mandatory? */, AccessMode.READ_ONLY, new OptionsEnum[0])); - protected final PointImpl impl; + private final Point point; - private S2(PointImpl impl) { - this.impl = impl; + private S2(Point point) { + this.point = point; } @Override - public PointImpl get() { - return this.impl; + public Point get() { + return this.point; } } @@ -623,7 +247,7 @@ public static enum S2_St implements OptionsEnum { OFF(1, "OFF"), // ON(2, "ON"), // FULL(3, "FULL"), // - FAULT(4, "FAULT"); // + FAULT(4, "FAULT"); private final int value; private final String name; @@ -649,51 +273,38 @@ public OptionsEnum getUndefined() { } } - public static enum S2_Evt implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - GROUND_FAULT(0, "GROUND_FAULT"), // - INPUT_OVER_VOLTAGE(1, "INPUT_OVER_VOLTAGE"), // - RESERVED_2(2, "RESERVED_2"), // - DC_DISCONNECT(3, "DC_DISCONNECT"), // - RESERVED_4(4, "RESERVED_4"), // - RESERVED_5(5, "RESERVED_5"), // - MANUAL_SHUTDOWN(6, "MANUAL_SHUTDOWN"), // - OVER_TEMPERATURE(7, "OVER_TEMPERATURE"), // - RESERVED_8(8, "RESERVED_8"), // - RESERVED_9(9, "RESERVED_9"), // - RESERVED_10(10, "RESERVED_10"), // - RESERVED_11(11, "RESERVED_11"), // - BLOWN_FUSE(12, "BLOWN_FUSE"), // - UNDER_TEMPERATURE(13, "UNDER_TEMPERATURE"), // - MEMORY_LOSS(14, "MEMORY_LOSS"), // - ARC_DETECTION(15, "ARC_DETECTION"), // - THEFT_DETECTION(16, "THEFT_DETECTION"), // - OUTPUT_OVER_CURRENT(17, "OUTPUT_OVER_CURRENT"), // - OUTPUT_OVER_VOLTAGE(18, "OUTPUT_OVER_VOLTAGE"), // - OUTPUT_UNDER_VOLTAGE(19, "OUTPUT_UNDER_VOLTAGE"), // - TEST_FAILED(20, "TEST_FAILED"); // - - private final int value; - private final String name; - - private S2_Evt(int value, String name) { - this.value = value; - this.name = name; - } + public static enum S2_Evt implements SunSpecBitPoint { + GROUND_FAULT(new BitPoint(0, "S2_EVT_GROUND_FAULT", "Ground Fault", Level.INFO)), // + INPUT_OVER_VOLTAGE(new BitPoint(1, "S2_EVT_INPUT_OVER_VOLTAGE", "Input Over Voltage", Level.INFO)), // + RESERVED_2(new BitPoint(2, "S2_EVT_RESERVED_2", "Reserved 2")), // + DC_DISCONNECT(new BitPoint(3, "S2_EVT_DC_DISCONNECT", "DC Disconnect", Level.INFO)), // + RESERVED_4(new BitPoint(4, "S2_EVT_RESERVED_4", "Reserved 4")), // + RESERVED_5(new BitPoint(5, "S2_EVT_RESERVED_5", "Reserved 5")), // + MANUAL_SHUTDOWN(new BitPoint(6, "S2_EVT_MANUAL_SHUTDOWN", "Manual Shutdown", Level.INFO)), // + OVER_TEMPERATURE(new BitPoint(7, "S2_EVT_OVER_TEMPERATURE", "Over Temperature", Level.INFO)), // + RESERVED_8(new BitPoint(8, "S2_EVT_RESERVED_8", "Reserved 8")), // + RESERVED_9(new BitPoint(9, "S2_EVT_RESERVED_9", "Reserved 9")), // + RESERVED_10(new BitPoint(10, "S2_EVT_RESERVED_10", "Reserved 10")), // + RESERVED_11(new BitPoint(11, "S2_EVT_RESERVED_11", "Reserved 11")), // + BLOWN_FUSE(new BitPoint(12, "S2_EVT_BLOWN_FUSE", "Blown Fuse", Level.INFO)), // + UNDER_TEMPERATURE(new BitPoint(13, "S2_EVT_UNDER_TEMPERATURE", "Under Temperature", Level.INFO)), // + MEMORY_LOSS(new BitPoint(14, "S2_EVT_MEMORY_LOSS", "Memory Loss", Level.INFO)), // + ARC_DETECTION(new BitPoint(15, "S2_EVT_ARC_DETECTION", "Arc Detection", Level.INFO)), // + THEFT_DETECTION(new BitPoint(16, "S2_EVT_THEFT_DETECTION", "Theft Detection", Level.INFO)), // + OUTPUT_OVER_CURRENT(new BitPoint(17, "S2_EVT_OUTPUT_OVER_CURRENT", "Output Over Current", Level.INFO)), // + OUTPUT_OVER_VOLTAGE(new BitPoint(18, "S2_EVT_OUTPUT_OVER_VOLTAGE", "Output Over Voltage", Level.INFO)), // + OUTPUT_UNDER_VOLTAGE(new BitPoint(19, "S2_EVT_OUTPUT_UNDER_VOLTAGE", "Output Under Voltage", Level.INFO)), // + TEST_FAILED(new BitPoint(20, "S2_EVT_TEST_FAILED", "Test Failed", Level.INFO)); - @Override - public int getValue() { - return this.value; - } + private final BitPoint point; - @Override - public String getName() { - return this.name; + private S2_Evt(BitPoint point) { + this.point = point; } @Override - public OptionsEnum getUndefined() { - return UNDEFINED; + public BitPoint get() { + return this.point; } } @@ -703,7 +314,7 @@ public static enum S2_Ctl implements OptionsEnum { AUTOMATIC(1, "AUTOMATIC"), // FORCE_OFF(2, "FORCE_OFF"), // TEST(3, "TEST"), // - THROTTLE(4, "THROTTLE"); // + THROTTLE(4, "THROTTLE"); private final int value; private final String name; @@ -730,715 +341,202 @@ public OptionsEnum getUndefined() { } public static enum S15 implements SunSpecPoint { - CLR(new PointImpl(// - "S15_CLR", // - "Clear", // + CLR(new ValuePoint("S15_CLR", "Clear", // "Write a \"1\" to clear all counters", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - IN_CNT(new PointImpl(// - "S15_IN_CNT", // - "Input Count", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + IN_CNT(new ValuePoint("S15_IN_CNT", "Input Count", // "Number of bytes received", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - IN_UC_CNT(new PointImpl(// - "S15_IN_UC_CNT", // - "Input Unicast Count", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + IN_UC_CNT(new ValuePoint("S15_IN_UC_CNT", "Input Unicast Count", // "Number of Unicast packets received", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - IN_N_UC_CNT(new PointImpl(// - "S15_IN_N_UC_CNT", // - "Input Non-Unicast Count", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + IN_N_UC_CNT(new ValuePoint("S15_IN_N_UC_CNT", "Input Non-Unicast Count", // "Number of non-Unicast packets received", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - IN_DSC_CNT(new PointImpl(// - "S15_IN_DSC_CNT", // - "Input Discarded Count", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + IN_DSC_CNT(new ValuePoint("S15_IN_DSC_CNT", "Input Discarded Count", // "Number of inbound packets received on the interface but discarded", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - IN_ERR_CNT(new PointImpl(// - "S15_IN_ERR_CNT", // - "Input Error Count", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + IN_ERR_CNT(new ValuePoint("S15_IN_ERR_CNT", "Input Error Count", // "Number of inbound packets that contain errors (excluding discards)", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - IN_UNK_CNT(new PointImpl(// - "S15_IN_UNK_CNT", // - "Input Unknown Count", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + IN_UNK_CNT(new ValuePoint("S15_IN_UNK_CNT", "Input Unknown Count", // "Number of inbound packets with unknown protocol", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - OUT_CNT(new PointImpl(// - "S15_OUT_CNT", // - "Output Count", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + OUT_CNT(new ValuePoint("S15_OUT_CNT", "Output Count", // "Total number of bytes transmitted on this interface", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - OUT_UC_CNT(new PointImpl(// - "S15_OUT_UC_CNT", // - "Output Unicast Count", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + OUT_UC_CNT(new ValuePoint("S15_OUT_UC_CNT", "Output Unicast Count", // "Number of Unicast packets transmitted", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - OUT_N_UC_CNT(new PointImpl(// - "S15_OUT_N_UC_CNT", // - "Output Non-Unicast Count", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + OUT_N_UC_CNT(new ValuePoint("S15_OUT_N_UC_CNT", "Output Non-Unicast Count", // "Number of Non-Unicast packets transmitted", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - OUT_DSC_CNT(new PointImpl(// - "S15_OUT_DSC_CNT", // - "Output Discarded Count", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + OUT_DSC_CNT(new ValuePoint("S15_OUT_DSC_CNT", "Output Discarded Count", // "Number of Discarded output packets", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - OUT_ERR_CNT(new PointImpl(// - "S15_OUT_ERR_CNT", // - "Output Error Count", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + OUT_ERR_CNT(new ValuePoint("S15_OUT_ERR_CNT", "Output Error Count", // "Number of outbound error packets", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - PAD(new PointImpl(// - "S15_PAD", // - "", // - "", // - "", // - PointType.PAD, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // - - protected final PointImpl impl; - - private S15(PointImpl impl) { - this.impl = impl; - } - - @Override - public PointImpl get() { - return this.impl; + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + PAD(new ValuePoint("S15_PAD", "", "", // + ValuePoint.Type.PAD, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)); + + private final Point point; + + private S15(Point point) { + this.point = point; + } + + @Override + public Point get() { + return this.point; } } public static enum S18 implements SunSpecPoint { - NAM(new PointImpl(// - "S18_NAM", // - "Name", // + NAM(new ValuePoint("S18_NAM", "Name", // "Interface name", // - "", // - PointType.STRING4, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - IMEI(new PointImpl(// - "S18_IMEI", // - "IMEI", // + ValuePoint.Type.STRING4, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + IMEI(new ValuePoint("S18_IMEI", "IMEI", // "International Mobile Equipment Identifier for the interface", // - "", // - PointType.UINT32, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - APN(new PointImpl(// - "S18_APN", // - "APN", // + ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + APN(new ValuePoint("S18_APN", "APN", // "Access Point Name for the interface", // - "", // - PointType.STRING4, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - NUM(new PointImpl(// - "S18_NUM", // - "Number", // + ValuePoint.Type.STRING4, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + NUM(new ValuePoint("S18_NUM", "Number", // "Phone number for the interface", // - "", // - PointType.STRING6, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - PIN(new PointImpl(// - "S18_PIN", // - "PIN", // + ValuePoint.Type.STRING6, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + PIN(new ValuePoint("S18_PIN", "PIN", // "Personal Identification Number for the interface", // - "", // - PointType.STRING6, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // + ValuePoint.Type.STRING6, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)); - protected final PointImpl impl; + private final Point point; - private S18(PointImpl impl) { - this.impl = impl; + private S18(Point point) { + this.point = point; } @Override - public PointImpl get() { - return this.impl; + public Point get() { + return this.point; } } public static enum S101 implements SunSpecPoint { - A(new PointImpl(// - "S101_A", // - "Amps", // + A(new ScaledValuePoint("S101_A", "Amps", // "AC Current", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - APH_A(new PointImpl(// - "S101_APH_A", // - "Amps PhaseA", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + APH_A(new ScaledValuePoint("S101_APH_A", "Amps PhaseA", // "Phase A Current", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - APH_B(new PointImpl(// - "S101_APH_B", // - "Amps PhaseB", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + APH_B(new ScaledValuePoint("S101_APH_B", "Amps PhaseB", // "Phase B Current", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - APH_C(new PointImpl(// - "S101_APH_C", // - "Amps PhaseC", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + APH_C(new ScaledValuePoint("S101_APH_C", "Amps PhaseC", // "Phase C Current", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - A_SF(new PointImpl(// - "S101_A_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - P_P_VPH_A_B(new PointImpl(// - "S101_P_P_VPH_A_B", // - "Phase Voltage AB", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + A_SF(new ScaleFactorPoint("S101_A_SF", "", "")), // + P_P_VPH_A_B(new ScaledValuePoint("S101_P_P_VPH_A_B", "Phase Voltage AB", // "Phase Voltage AB", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - P_P_VPH_B_C(new PointImpl(// - "S101_P_P_VPH_B_C", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + P_P_VPH_B_C(new ScaledValuePoint("S101_P_P_VPH_B_C", "Phase Voltage BC", // "Phase Voltage BC", // - "Phase Voltage BC", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - P_P_VPH_C_A(new PointImpl(// - "S101_P_P_VPH_C_A", // - "Phase Voltage CA", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + P_P_VPH_C_A(new ScaledValuePoint("S101_P_P_VPH_C_A", "Phase Voltage CA", // "Phase Voltage CA", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_A(new PointImpl(// - "S101_PH_VPH_A", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_A(new ScaledValuePoint("S101_PH_VPH_A", "Phase Voltage AN", // "Phase Voltage AN", // - "Phase Voltage AN", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_B(new PointImpl(// - "S101_PH_VPH_B", // - "Phase Voltage BN", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_B(new ScaledValuePoint("S101_PH_VPH_B", "Phase Voltage BN", // "Phase Voltage BN", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_C(new PointImpl(// - "S101_PH_VPH_C", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_C(new ScaledValuePoint("S101_PH_VPH_C", "Phase Voltage CN", // "Phase Voltage CN", // - "Phase Voltage CN", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - V_SF(new PointImpl(// - "S101_V_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - W(new PointImpl(// - "S101_W", // - "Watts", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + V_SF(new ScaleFactorPoint("S101_V_SF", "", "")), // + W(new ScaledValuePoint("S101_W", "Watts", // "AC Power", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - W_SF(new PointImpl(// - "S101_W_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - HZ(new PointImpl(// - "S101_HZ", // - "Hz", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + W_SF(new ScaleFactorPoint("S101_W_SF", "", "")), // + HZ(new ScaledValuePoint("S101_HZ", "Hz", // "Line Frequency", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.HERTZ, // - "Hz_SF", // - new OptionsEnum[0])), // - HZ_S_F(new PointImpl(// - "S101_HZ_S_F", // - "", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - VA(new PointImpl(// - "S101_VA", // - "VA", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.HERTZ, "Hz_SF")), // + HZ_S_F(new ScaleFactorPoint("S101_HZ_S_F", "", "")), // + VA(new ScaledValuePoint("S101_VA", "VA", // "AC Apparent Power", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE, // - "VA_SF", // - new OptionsEnum[0])), // - VA_SF(new PointImpl(// - "S101_VA_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - V_AR(new PointImpl(// - "S101_V_AR", // - "VAr", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + VA_SF(new ScaleFactorPoint("S101_VA_SF", "", "")), // + V_AR(new ScaledValuePoint("S101_V_AR", "VAr", // "AC Reactive Power", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "VAr_SF", // - new OptionsEnum[0])), // - V_AR_S_F(new PointImpl(// - "S101_V_AR_S_F", // - "", // - "", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - PF(new PointImpl(// - "S101_PF", // - "PF", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAr_SF")), // + V_AR_S_F(new ScaleFactorPoint("S101_V_AR_S_F", "", "")), // + PF(new ScaledValuePoint("S101_PF", "PF", // "AC Power Factor", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "PF_SF", // - new OptionsEnum[0])), // - PF_SF(new PointImpl(// - "S101_PF_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - WH(new PointImpl(// - "S101_WH", // - "WattHours", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + PF_SF(new ScaleFactorPoint("S101_PF_SF", "", "")), // + WH(new ScaledValuePoint("S101_WH", "WattHours", // "AC Energy", // - "", // - PointType.ACC32, // - true, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "WH_SF", // - new OptionsEnum[0])), // - WH_SF(new PointImpl(// - "S101_WH_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - DCA(new PointImpl(// - "S101_DCA", // - "DC Amps", // + ValuePoint.Type.ACC32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "WH_SF")), // + WH_SF(new ScaleFactorPoint("S101_WH_SF", "", "")), // + DCA(new ScaledValuePoint("S101_DCA", "DC Amps", // "DC Current", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "DCA_SF", // - new OptionsEnum[0])), // - DCA_SF(new PointImpl(// - "S101_DCA_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - DCV(new PointImpl(// - "S101_DCV", // - "DC Voltage", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "DCA_SF")), // + DCA_SF(new ScaleFactorPoint("S101_DCA_SF", "", "")), // + DCV(new ScaledValuePoint("S101_DCV", "DC Voltage", // "DC Voltage", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "DCV_SF", // - new OptionsEnum[0])), // - DCV_SF(new PointImpl(// - "S101_DCV_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - DCW(new PointImpl(// - "S101_DCW", // - "DC Watts", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "DCV_SF")), // + DCV_SF(new ScaleFactorPoint("S101_DCV_SF", "", "")), // + DCW(new ScaledValuePoint("S101_DCW", "DC Watts", // "DC Power", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "DCW_SF", // - new OptionsEnum[0])), // - DCW_SF(new PointImpl(// - "S101_DCW_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TMP_CAB(new PointImpl(// - "S101_TMP_CAB", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "DCW_SF")), // + DCW_SF(new ScaleFactorPoint("S101_DCW_SF", "", "")), // + TMP_CAB(new ScaledValuePoint("S101_TMP_CAB", "Cabinet Temperature", // "Cabinet Temperature", // - "Cabinet Temperature", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - "Tmp_SF", // - new OptionsEnum[0])), // - TMP_SNK(new PointImpl(// - "S101_TMP_SNK", // - "Heat Sink Temperature", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + TMP_SNK(new ScaledValuePoint("S101_TMP_SNK", "Heat Sink Temperature", // "Heat Sink Temperature", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - "Tmp_SF", // - new OptionsEnum[0])), // - TMP_TRNS(new PointImpl(// - "S101_TMP_TRNS", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + TMP_TRNS(new ScaledValuePoint("S101_TMP_TRNS", "Transformer Temperature", // "Transformer Temperature", // - "Transformer Temperature", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - "Tmp_SF", // - new OptionsEnum[0])), // - TMP_OT(new PointImpl(// - "S101_TMP_OT", // - "Other Temperature", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + TMP_OT(new ScaledValuePoint("S101_TMP_OT", "Other Temperature", // "Other Temperature", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - "Tmp_SF", // - new OptionsEnum[0])), // - TMP_S_F(new PointImpl(// - "S101_TMP_S_F", // - "", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - ST(new PointImpl(// - "S101_ST", // - "Operating State", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + TMP_S_F(new ScaleFactorPoint("S101_TMP_S_F", "", "")), // + ST(new EnumPoint("S101_ST", "Operating State", // "Enumerated value. Operating state", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S101_St.values())), // - ST_VND(new PointImpl(// - "S101_ST_VND", // - "Vendor Operating State", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S101_St.values())), // + ST_VND(new EnumPoint("S101_ST_VND", "Vendor Operating State", // "Vendor specific operating state code", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT1(new PointImpl(// - "S101_EVT1", // - "Event1", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, new OptionsEnum[0])), // + EVT1(new BitFieldPoint("S101_EVT1", "Event1", // "Bitmask value. Event fields", // - "", // - PointType.BITFIELD32, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S101_Evt1.values())), // - EVT2(new PointImpl(// - "S101_EVT2", // - "Event Bitfield 2", // + BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, S101_Evt1.values())), // + EVT2(new BitFieldPoint("S101_EVT2", "Event Bitfield 2", // "Reserved for future use", // - "", // - PointType.BITFIELD32, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT_VND1(new PointImpl(// - "S101_EVT_VND1", // - "Vendor Event Bitfield 1", // + BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + EVT_VND1(new BitFieldPoint("S101_EVT_VND1", "Vendor Event Bitfield 1", // "Vendor defined events", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT_VND2(new PointImpl(// - "S101_EVT_VND2", // - "Vendor Event Bitfield 2", // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + EVT_VND2(new BitFieldPoint("S101_EVT_VND2", "Vendor Event Bitfield 2", // "Vendor defined events", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT_VND3(new PointImpl(// - "S101_EVT_VND3", // - "Vendor Event Bitfield 3", // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + EVT_VND3(new BitFieldPoint("S101_EVT_VND3", "Vendor Event Bitfield 3", // "Vendor defined events", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT_VND4(new PointImpl(// - "S101_EVT_VND4", // - "Vendor Event Bitfield 4", // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + EVT_VND4(new BitFieldPoint("S101_EVT_VND4", "Vendor Event Bitfield 4", // "Vendor defined events", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])); - protected final PointImpl impl; + private final Point point; - private S101(PointImpl impl) { - this.impl = impl; + private S101(Point point) { + this.point = point; } @Override - public PointImpl get() { - return this.impl; + public Point get() { + return this.point; } } @@ -1451,7 +549,7 @@ public static enum S101_St implements OptionsEnum { THROTTLED(5, "THROTTLED"), // SHUTTING_DOWN(6, "SHUTTING_DOWN"), // FAULT(7, "FAULT"), // - STANDBY(8, "STANDBY"); // + STANDBY(8, "STANDBY"); private final int value; private final String name; @@ -1477,533 +575,152 @@ public OptionsEnum getUndefined() { } } - public static enum S101_Evt1 implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - GROUND_FAULT(0, "GROUND_FAULT"), // - DC_OVER_VOLT(1, "DC_OVER_VOLT"), // - AC_DISCONNECT(2, "AC_DISCONNECT"), // - DC_DISCONNECT(3, "DC_DISCONNECT"), // - GRID_DISCONNECT(4, "GRID_DISCONNECT"), // - CABINET_OPEN(5, "CABINET_OPEN"), // - MANUAL_SHUTDOWN(6, "MANUAL_SHUTDOWN"), // - OVER_TEMP(7, "OVER_TEMP"), // - OVER_FREQUENCY(8, "OVER_FREQUENCY"), // - UNDER_FREQUENCY(9, "UNDER_FREQUENCY"), // - AC_OVER_VOLT(10, "AC_OVER_VOLT"), // - AC_UNDER_VOLT(11, "AC_UNDER_VOLT"), // - BLOWN_STRING_FUSE(12, "BLOWN_STRING_FUSE"), // - UNDER_TEMP(13, "UNDER_TEMP"), // - MEMORY_LOSS(14, "MEMORY_LOSS"), // - HW_TEST_FAILURE(15, "HW_TEST_FAILURE"); // - - private final int value; - private final String name; - - private S101_Evt1(int value, String name) { - this.value = value; - this.name = name; - } + public static enum S101_Evt1 implements SunSpecBitPoint { + GROUND_FAULT(new BitPoint(0, "S101_EVT1_GROUND_FAULT", "Ground Fault", Level.INFO)), // + DC_OVER_VOLT(new BitPoint(1, "S101_EVT1_DC_OVER_VOLT", "DC Over Volt", Level.INFO)), // + AC_DISCONNECT(new BitPoint(2, "S101_EVT1_AC_DISCONNECT", "AC Disconnect", Level.INFO)), // + DC_DISCONNECT(new BitPoint(3, "S101_EVT1_DC_DISCONNECT", "DC Disconnect", Level.INFO)), // + GRID_DISCONNECT(new BitPoint(4, "S101_EVT1_GRID_DISCONNECT", "Grid Disconnect", Level.INFO)), // + CABINET_OPEN(new BitPoint(5, "S101_EVT1_CABINET_OPEN", "Cabinet Open", Level.INFO)), // + MANUAL_SHUTDOWN(new BitPoint(6, "S101_EVT1_MANUAL_SHUTDOWN", "Manual Shutdown", Level.INFO)), // + OVER_TEMP(new BitPoint(7, "S101_EVT1_OVER_TEMP", "Over Temp", Level.INFO)), // + OVER_FREQUENCY(new BitPoint(8, "S101_EVT1_OVER_FREQUENCY", "Over Frequency", Level.INFO)), // + UNDER_FREQUENCY(new BitPoint(9, "S101_EVT1_UNDER_FREQUENCY", "Under Frequency", Level.INFO)), // + AC_OVER_VOLT(new BitPoint(10, "S101_EVT1_AC_OVER_VOLT", "AC Over Volt", Level.INFO)), // + AC_UNDER_VOLT(new BitPoint(11, "S101_EVT1_AC_UNDER_VOLT", "AC Under Volt", Level.INFO)), // + BLOWN_STRING_FUSE(new BitPoint(12, "S101_EVT1_BLOWN_STRING_FUSE", "Blown String Fuse", Level.INFO)), // + UNDER_TEMP(new BitPoint(13, "S101_EVT1_UNDER_TEMP", "Under Temp", Level.INFO)), // + MEMORY_LOSS(new BitPoint(14, "S101_EVT1_MEMORY_LOSS", "Memory Loss", Level.INFO)), // + HW_TEST_FAILURE(new BitPoint(15, "S101_EVT1_HW_TEST_FAILURE", "HW Test Failure", Level.INFO)); - @Override - public int getValue() { - return this.value; - } + private final BitPoint point; - @Override - public String getName() { - return this.name; + private S101_Evt1(BitPoint point) { + this.point = point; } @Override - public OptionsEnum getUndefined() { - return UNDEFINED; + public BitPoint get() { + return this.point; } } public static enum S102 implements SunSpecPoint { - A(new PointImpl(// - "S102_A", // - "Amps", // + A(new ScaledValuePoint("S102_A", "Amps", // "AC Current", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - APH_A(new PointImpl(// - "S102_APH_A", // - "Amps PhaseA", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + APH_A(new ScaledValuePoint("S102_APH_A", "Amps PhaseA", // "Phase A Current", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - APH_B(new PointImpl(// - "S102_APH_B", // - "Amps PhaseB", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + APH_B(new ScaledValuePoint("S102_APH_B", "Amps PhaseB", // "Phase B Current", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - APH_C(new PointImpl(// - "S102_APH_C", // - "Amps PhaseC", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + APH_C(new ScaledValuePoint("S102_APH_C", "Amps PhaseC", // "Phase C Current", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - A_SF(new PointImpl(// - "S102_A_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - P_P_VPH_A_B(new PointImpl(// - "S102_P_P_VPH_A_B", // - "Phase Voltage AB", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + A_SF(new ScaleFactorPoint("S102_A_SF", "", "")), // + P_P_VPH_A_B(new ScaledValuePoint("S102_P_P_VPH_A_B", "Phase Voltage AB", // "Phase Voltage AB", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - P_P_VPH_B_C(new PointImpl(// - "S102_P_P_VPH_B_C", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + P_P_VPH_B_C(new ScaledValuePoint("S102_P_P_VPH_B_C", "Phase Voltage BC", // "Phase Voltage BC", // - "Phase Voltage BC", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - P_P_VPH_C_A(new PointImpl(// - "S102_P_P_VPH_C_A", // - "Phase Voltage CA", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + P_P_VPH_C_A(new ScaledValuePoint("S102_P_P_VPH_C_A", "Phase Voltage CA", // "Phase Voltage CA", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_A(new PointImpl(// - "S102_PH_VPH_A", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_A(new ScaledValuePoint("S102_PH_VPH_A", "Phase Voltage AN", // "Phase Voltage AN", // - "Phase Voltage AN", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_B(new PointImpl(// - "S102_PH_VPH_B", // - "Phase Voltage BN", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_B(new ScaledValuePoint("S102_PH_VPH_B", "Phase Voltage BN", // "Phase Voltage BN", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_C(new PointImpl(// - "S102_PH_VPH_C", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_C(new ScaledValuePoint("S102_PH_VPH_C", "Phase Voltage CN", // "Phase Voltage CN", // - "Phase Voltage CN", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - V_SF(new PointImpl(// - "S102_V_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - W(new PointImpl(// - "S102_W", // - "Watts", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + V_SF(new ScaleFactorPoint("S102_V_SF", "", "")), // + W(new ScaledValuePoint("S102_W", "Watts", // "AC Power", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - W_SF(new PointImpl(// - "S102_W_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - HZ(new PointImpl(// - "S102_HZ", // - "Hz", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + W_SF(new ScaleFactorPoint("S102_W_SF", "", "")), // + HZ(new ScaledValuePoint("S102_HZ", "Hz", // "Line Frequency", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.HERTZ, // - "Hz_SF", // - new OptionsEnum[0])), // - HZ_S_F(new PointImpl(// - "S102_HZ_S_F", // - "", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - VA(new PointImpl(// - "S102_VA", // - "VA", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.HERTZ, "Hz_SF")), // + HZ_S_F(new ScaleFactorPoint("S102_HZ_S_F", "", "")), // + VA(new ScaledValuePoint("S102_VA", "VA", // "AC Apparent Power", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE, // - "VA_SF", // - new OptionsEnum[0])), // - VA_SF(new PointImpl(// - "S102_VA_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - V_AR(new PointImpl(// - "S102_V_AR", // - "VAr", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + VA_SF(new ScaleFactorPoint("S102_VA_SF", "", "")), // + V_AR(new ScaledValuePoint("S102_V_AR", "VAr", // "AC Reactive Power", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "VAr_SF", // - new OptionsEnum[0])), // - V_AR_S_F(new PointImpl(// - "S102_V_AR_S_F", // - "", // - "", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - PF(new PointImpl(// - "S102_PF", // - "PF", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAr_SF")), // + V_AR_S_F(new ScaleFactorPoint("S102_V_AR_S_F", "", "")), // + PF(new ScaledValuePoint("S102_PF", "PF", // "AC Power Factor", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "PF_SF", // - new OptionsEnum[0])), // - PF_SF(new PointImpl(// - "S102_PF_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - WH(new PointImpl(// - "S102_WH", // - "WattHours", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + PF_SF(new ScaleFactorPoint("S102_PF_SF", "", "")), // + WH(new ScaledValuePoint("S102_WH", "WattHours", // "AC Energy", // - "", // - PointType.ACC32, // - true, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "WH_SF", // - new OptionsEnum[0])), // - WH_SF(new PointImpl(// - "S102_WH_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - DCA(new PointImpl(// - "S102_DCA", // - "DC Amps", // + ValuePoint.Type.ACC32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "WH_SF")), // + WH_SF(new ScaleFactorPoint("S102_WH_SF", "", "")), // + DCA(new ScaledValuePoint("S102_DCA", "DC Amps", // "DC Current", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "DCA_SF", // - new OptionsEnum[0])), // - DCA_SF(new PointImpl(// - "S102_DCA_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - DCV(new PointImpl(// - "S102_DCV", // - "DC Voltage", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "DCA_SF")), // + DCA_SF(new ScaleFactorPoint("S102_DCA_SF", "", "")), // + DCV(new ScaledValuePoint("S102_DCV", "DC Voltage", // "DC Voltage", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "DCV_SF", // - new OptionsEnum[0])), // - DCV_SF(new PointImpl(// - "S102_DCV_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - DCW(new PointImpl(// - "S102_DCW", // - "DC Watts", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "DCV_SF")), // + DCV_SF(new ScaleFactorPoint("S102_DCV_SF", "", "")), // + DCW(new ScaledValuePoint("S102_DCW", "DC Watts", // "DC Power", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "DCW_SF", // - new OptionsEnum[0])), // - DCW_SF(new PointImpl(// - "S102_DCW_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TMP_CAB(new PointImpl(// - "S102_TMP_CAB", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "DCW_SF")), // + DCW_SF(new ScaleFactorPoint("S102_DCW_SF", "", "")), // + TMP_CAB(new ScaledValuePoint("S102_TMP_CAB", "Cabinet Temperature", // "Cabinet Temperature", // - "Cabinet Temperature", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - "Tmp_SF", // - new OptionsEnum[0])), // - TMP_SNK(new PointImpl(// - "S102_TMP_SNK", // - "Heat Sink Temperature", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + TMP_SNK(new ScaledValuePoint("S102_TMP_SNK", "Heat Sink Temperature", // "Heat Sink Temperature", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - "Tmp_SF", // - new OptionsEnum[0])), // - TMP_TRNS(new PointImpl(// - "S102_TMP_TRNS", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + TMP_TRNS(new ScaledValuePoint("S102_TMP_TRNS", "Transformer Temperature", // "Transformer Temperature", // - "Transformer Temperature", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - "Tmp_SF", // - new OptionsEnum[0])), // - TMP_OT(new PointImpl(// - "S102_TMP_OT", // - "Other Temperature", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + TMP_OT(new ScaledValuePoint("S102_TMP_OT", "Other Temperature", // "Other Temperature", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - "Tmp_SF", // - new OptionsEnum[0])), // - TMP_S_F(new PointImpl(// - "S102_TMP_S_F", // - "", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - ST(new PointImpl(// - "S102_ST", // - "Operating State", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + TMP_S_F(new ScaleFactorPoint("S102_TMP_S_F", "", "")), // + ST(new EnumPoint("S102_ST", "Operating State", // "Enumerated value. Operating state", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S102_St.values())), // - ST_VND(new PointImpl(// - "S102_ST_VND", // - "Vendor Operating State", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S102_St.values())), // + ST_VND(new EnumPoint("S102_ST_VND", "Vendor Operating State", // "Vendor specific operating state code", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT1(new PointImpl(// - "S102_EVT1", // - "Event1", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, new OptionsEnum[0])), // + EVT1(new BitFieldPoint("S102_EVT1", "Event1", // "Bitmask value. Event fields", // - "", // - PointType.BITFIELD32, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S102_Evt1.values())), // - EVT2(new PointImpl(// - "S102_EVT2", // - "Event Bitfield 2", // + BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, S102_Evt1.values())), // + EVT2(new BitFieldPoint("S102_EVT2", "Event Bitfield 2", // "Reserved for future use", // - "", // - PointType.BITFIELD32, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT_VND1(new PointImpl(// - "S102_EVT_VND1", // - "Vendor Event Bitfield 1", // + BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + EVT_VND1(new BitFieldPoint("S102_EVT_VND1", "Vendor Event Bitfield 1", // "Vendor defined events", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT_VND2(new PointImpl(// - "S102_EVT_VND2", // - "Vendor Event Bitfield 2", // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + EVT_VND2(new BitFieldPoint("S102_EVT_VND2", "Vendor Event Bitfield 2", // "Vendor defined events", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT_VND3(new PointImpl(// - "S102_EVT_VND3", // - "Vendor Event Bitfield 3", // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + EVT_VND3(new BitFieldPoint("S102_EVT_VND3", "Vendor Event Bitfield 3", // "Vendor defined events", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT_VND4(new PointImpl(// - "S102_EVT_VND4", // - "Vendor Event Bitfield 4", // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + EVT_VND4(new BitFieldPoint("S102_EVT_VND4", "Vendor Event Bitfield 4", // "Vendor defined events", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])); - protected final PointImpl impl; + private final Point point; - private S102(PointImpl impl) { - this.impl = impl; + private S102(Point point) { + this.point = point; } @Override - public PointImpl get() { - return this.impl; + public Point get() { + return this.point; } } @@ -2016,7 +733,7 @@ public static enum S102_St implements OptionsEnum { THROTTLED(5, "THROTTLED"), // SHUTTING_DOWN(6, "SHUTTING_DOWN"), // FAULT(7, "FAULT"), // - STANDBY(8, "STANDBY"); // + STANDBY(8, "STANDBY"); private final int value; private final String name; @@ -2042,533 +759,152 @@ public OptionsEnum getUndefined() { } } - public static enum S102_Evt1 implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - GROUND_FAULT(0, "GROUND_FAULT"), // - DC_OVER_VOLT(1, "DC_OVER_VOLT"), // - AC_DISCONNECT(2, "AC_DISCONNECT"), // - DC_DISCONNECT(3, "DC_DISCONNECT"), // - GRID_DISCONNECT(4, "GRID_DISCONNECT"), // - CABINET_OPEN(5, "CABINET_OPEN"), // - MANUAL_SHUTDOWN(6, "MANUAL_SHUTDOWN"), // - OVER_TEMP(7, "OVER_TEMP"), // - OVER_FREQUENCY(8, "OVER_FREQUENCY"), // - UNDER_FREQUENCY(9, "UNDER_FREQUENCY"), // - AC_OVER_VOLT(10, "AC_OVER_VOLT"), // - AC_UNDER_VOLT(11, "AC_UNDER_VOLT"), // - BLOWN_STRING_FUSE(12, "BLOWN_STRING_FUSE"), // - UNDER_TEMP(13, "UNDER_TEMP"), // - MEMORY_LOSS(14, "MEMORY_LOSS"), // - HW_TEST_FAILURE(15, "HW_TEST_FAILURE"); // - - private final int value; - private final String name; - - private S102_Evt1(int value, String name) { - this.value = value; - this.name = name; - } + public static enum S102_Evt1 implements SunSpecBitPoint { + GROUND_FAULT(new BitPoint(0, "S102_EVT1_GROUND_FAULT", "Ground Fault", Level.INFO)), // + DC_OVER_VOLT(new BitPoint(1, "S102_EVT1_DC_OVER_VOLT", "DC Over Volt", Level.INFO)), // + AC_DISCONNECT(new BitPoint(2, "S102_EVT1_AC_DISCONNECT", "AC Disconnect", Level.INFO)), // + DC_DISCONNECT(new BitPoint(3, "S102_EVT1_DC_DISCONNECT", "DC Disconnect", Level.INFO)), // + GRID_DISCONNECT(new BitPoint(4, "S102_EVT1_GRID_DISCONNECT", "Grid Disconnect", Level.INFO)), // + CABINET_OPEN(new BitPoint(5, "S102_EVT1_CABINET_OPEN", "Cabinet Open", Level.INFO)), // + MANUAL_SHUTDOWN(new BitPoint(6, "S102_EVT1_MANUAL_SHUTDOWN", "Manual Shutdown", Level.INFO)), // + OVER_TEMP(new BitPoint(7, "S102_EVT1_OVER_TEMP", "Over Temp", Level.INFO)), // + OVER_FREQUENCY(new BitPoint(8, "S102_EVT1_OVER_FREQUENCY", "Over Frequency", Level.INFO)), // + UNDER_FREQUENCY(new BitPoint(9, "S102_EVT1_UNDER_FREQUENCY", "Under Frequency", Level.INFO)), // + AC_OVER_VOLT(new BitPoint(10, "S102_EVT1_AC_OVER_VOLT", "AC Over Volt", Level.INFO)), // + AC_UNDER_VOLT(new BitPoint(11, "S102_EVT1_AC_UNDER_VOLT", "AC Under Volt", Level.INFO)), // + BLOWN_STRING_FUSE(new BitPoint(12, "S102_EVT1_BLOWN_STRING_FUSE", "Blown String Fuse", Level.INFO)), // + UNDER_TEMP(new BitPoint(13, "S102_EVT1_UNDER_TEMP", "Under Temp", Level.INFO)), // + MEMORY_LOSS(new BitPoint(14, "S102_EVT1_MEMORY_LOSS", "Memory Loss", Level.INFO)), // + HW_TEST_FAILURE(new BitPoint(15, "S102_EVT1_HW_TEST_FAILURE", "HW Test Failure", Level.INFO)); - @Override - public int getValue() { - return this.value; - } + private final BitPoint point; - @Override - public String getName() { - return this.name; + private S102_Evt1(BitPoint point) { + this.point = point; } @Override - public OptionsEnum getUndefined() { - return UNDEFINED; + public BitPoint get() { + return this.point; } } public static enum S103 implements SunSpecPoint { - A(new PointImpl(// - "S103_A", // - "Amps", // + A(new ScaledValuePoint("S103_A", "Amps", // "AC Current", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - APH_A(new PointImpl(// - "S103_APH_A", // - "Amps PhaseA", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + APH_A(new ScaledValuePoint("S103_APH_A", "Amps PhaseA", // "Phase A Current", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - APH_B(new PointImpl(// - "S103_APH_B", // - "Amps PhaseB", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + APH_B(new ScaledValuePoint("S103_APH_B", "Amps PhaseB", // "Phase B Current", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - APH_C(new PointImpl(// - "S103_APH_C", // - "Amps PhaseC", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + APH_C(new ScaledValuePoint("S103_APH_C", "Amps PhaseC", // "Phase C Current", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - A_SF(new PointImpl(// - "S103_A_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - P_P_VPH_A_B(new PointImpl(// - "S103_P_P_VPH_A_B", // - "Phase Voltage AB", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + A_SF(new ScaleFactorPoint("S103_A_SF", "", "")), // + P_P_VPH_A_B(new ScaledValuePoint("S103_P_P_VPH_A_B", "Phase Voltage AB", // "Phase Voltage AB", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - P_P_VPH_B_C(new PointImpl(// - "S103_P_P_VPH_B_C", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + P_P_VPH_B_C(new ScaledValuePoint("S103_P_P_VPH_B_C", "Phase Voltage BC", // "Phase Voltage BC", // - "Phase Voltage BC", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - P_P_VPH_C_A(new PointImpl(// - "S103_P_P_VPH_C_A", // - "Phase Voltage CA", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + P_P_VPH_C_A(new ScaledValuePoint("S103_P_P_VPH_C_A", "Phase Voltage CA", // "Phase Voltage CA", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_A(new PointImpl(// - "S103_PH_VPH_A", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_A(new ScaledValuePoint("S103_PH_VPH_A", "Phase Voltage AN", // "Phase Voltage AN", // - "Phase Voltage AN", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_B(new PointImpl(// - "S103_PH_VPH_B", // - "Phase Voltage BN", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_B(new ScaledValuePoint("S103_PH_VPH_B", "Phase Voltage BN", // "Phase Voltage BN", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_C(new PointImpl(// - "S103_PH_VPH_C", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_C(new ScaledValuePoint("S103_PH_VPH_C", "Phase Voltage CN", // "Phase Voltage CN", // - "Phase Voltage CN", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - V_SF(new PointImpl(// - "S103_V_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - W(new PointImpl(// - "S103_W", // - "Watts", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + V_SF(new ScaleFactorPoint("S103_V_SF", "", "")), // + W(new ScaledValuePoint("S103_W", "Watts", // "AC Power", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - W_SF(new PointImpl(// - "S103_W_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - HZ(new PointImpl(// - "S103_HZ", // - "Hz", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + W_SF(new ScaleFactorPoint("S103_W_SF", "", "")), // + HZ(new ScaledValuePoint("S103_HZ", "Hz", // "Line Frequency", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.HERTZ, // - "Hz_SF", // - new OptionsEnum[0])), // - HZ_S_F(new PointImpl(// - "S103_HZ_S_F", // - "", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - VA(new PointImpl(// - "S103_VA", // - "VA", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.HERTZ, "Hz_SF")), // + HZ_S_F(new ScaleFactorPoint("S103_HZ_S_F", "", "")), // + VA(new ScaledValuePoint("S103_VA", "VA", // "AC Apparent Power", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE, // - "VA_SF", // - new OptionsEnum[0])), // - VA_SF(new PointImpl(// - "S103_VA_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - V_AR(new PointImpl(// - "S103_V_AR", // - "VAr", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + VA_SF(new ScaleFactorPoint("S103_VA_SF", "", "")), // + V_AR(new ScaledValuePoint("S103_V_AR", "VAr", // "AC Reactive Power", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "VAr_SF", // - new OptionsEnum[0])), // - V_AR_S_F(new PointImpl(// - "S103_V_AR_S_F", // - "", // - "", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - PF(new PointImpl(// - "S103_PF", // - "PF", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAr_SF")), // + V_AR_S_F(new ScaleFactorPoint("S103_V_AR_S_F", "", "")), // + PF(new ScaledValuePoint("S103_PF", "PF", // "AC Power Factor", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "PF_SF", // - new OptionsEnum[0])), // - PF_SF(new PointImpl(// - "S103_PF_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - WH(new PointImpl(// - "S103_WH", // - "WattHours", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + PF_SF(new ScaleFactorPoint("S103_PF_SF", "", "")), // + WH(new ScaledValuePoint("S103_WH", "WattHours", // "AC Energy", // - "", // - PointType.ACC32, // - true, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "WH_SF", // - new OptionsEnum[0])), // - WH_SF(new PointImpl(// - "S103_WH_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - DCA(new PointImpl(// - "S103_DCA", // - "DC Amps", // + ValuePoint.Type.ACC32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "WH_SF")), // + WH_SF(new ScaleFactorPoint("S103_WH_SF", "", "")), // + DCA(new ScaledValuePoint("S103_DCA", "DC Amps", // "DC Current", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "DCA_SF", // - new OptionsEnum[0])), // - DCA_SF(new PointImpl(// - "S103_DCA_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - DCV(new PointImpl(// - "S103_DCV", // - "DC Voltage", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "DCA_SF")), // + DCA_SF(new ScaleFactorPoint("S103_DCA_SF", "", "")), // + DCV(new ScaledValuePoint("S103_DCV", "DC Voltage", // "DC Voltage", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "DCV_SF", // - new OptionsEnum[0])), // - DCV_SF(new PointImpl(// - "S103_DCV_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - DCW(new PointImpl(// - "S103_DCW", // - "DC Watts", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "DCV_SF")), // + DCV_SF(new ScaleFactorPoint("S103_DCV_SF", "", "")), // + DCW(new ScaledValuePoint("S103_DCW", "DC Watts", // "DC Power", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "DCW_SF", // - new OptionsEnum[0])), // - DCW_SF(new PointImpl(// - "S103_DCW_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TMP_CAB(new PointImpl(// - "S103_TMP_CAB", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "DCW_SF")), // + DCW_SF(new ScaleFactorPoint("S103_DCW_SF", "", "")), // + TMP_CAB(new ScaledValuePoint("S103_TMP_CAB", "Cabinet Temperature", // "Cabinet Temperature", // - "Cabinet Temperature", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - "Tmp_SF", // - new OptionsEnum[0])), // - TMP_SNK(new PointImpl(// - "S103_TMP_SNK", // - "Heat Sink Temperature", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + TMP_SNK(new ScaledValuePoint("S103_TMP_SNK", "Heat Sink Temperature", // "Heat Sink Temperature", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - "Tmp_SF", // - new OptionsEnum[0])), // - TMP_TRNS(new PointImpl(// - "S103_TMP_TRNS", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + TMP_TRNS(new ScaledValuePoint("S103_TMP_TRNS", "Transformer Temperature", // "Transformer Temperature", // - "Transformer Temperature", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - "Tmp_SF", // - new OptionsEnum[0])), // - TMP_OT(new PointImpl(// - "S103_TMP_OT", // - "Other Temperature", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + TMP_OT(new ScaledValuePoint("S103_TMP_OT", "Other Temperature", // "Other Temperature", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - "Tmp_SF", // - new OptionsEnum[0])), // - TMP_S_F(new PointImpl(// - "S103_TMP_S_F", // - "", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - ST(new PointImpl(// - "S103_ST", // - "Operating State", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + TMP_S_F(new ScaleFactorPoint("S103_TMP_S_F", "", "")), // + ST(new EnumPoint("S103_ST", "Operating State", // "Enumerated value. Operating state", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S103_St.values())), // - ST_VND(new PointImpl(// - "S103_ST_VND", // - "Vendor Operating State", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S103_St.values())), // + ST_VND(new EnumPoint("S103_ST_VND", "Vendor Operating State", // "Vendor specific operating state code", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT1(new PointImpl(// - "S103_EVT1", // - "Event1", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, new OptionsEnum[0])), // + EVT1(new BitFieldPoint("S103_EVT1", "Event1", // "Bitmask value. Event fields", // - "", // - PointType.BITFIELD32, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S103_Evt1.values())), // - EVT2(new PointImpl(// - "S103_EVT2", // - "Event Bitfield 2", // + BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, S103_Evt1.values())), // + EVT2(new BitFieldPoint("S103_EVT2", "Event Bitfield 2", // "Reserved for future use", // - "", // - PointType.BITFIELD32, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT_VND1(new PointImpl(// - "S103_EVT_VND1", // - "Vendor Event Bitfield 1", // + BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + EVT_VND1(new BitFieldPoint("S103_EVT_VND1", "Vendor Event Bitfield 1", // "Vendor defined events", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT_VND2(new PointImpl(// - "S103_EVT_VND2", // - "Vendor Event Bitfield 2", // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + EVT_VND2(new BitFieldPoint("S103_EVT_VND2", "Vendor Event Bitfield 2", // "Vendor defined events", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT_VND3(new PointImpl(// - "S103_EVT_VND3", // - "Vendor Event Bitfield 3", // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + EVT_VND3(new BitFieldPoint("S103_EVT_VND3", "Vendor Event Bitfield 3", // "Vendor defined events", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT_VND4(new PointImpl(// - "S103_EVT_VND4", // - "Vendor Event Bitfield 4", // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + EVT_VND4(new BitFieldPoint("S103_EVT_VND4", "Vendor Event Bitfield 4", // "Vendor defined events", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])); - protected final PointImpl impl; + private final Point point; - private S103(PointImpl impl) { - this.impl = impl; + private S103(Point point) { + this.point = point; } @Override - public PointImpl get() { - return this.impl; + public Point get() { + return this.point; } } @@ -2581,7 +917,7 @@ public static enum S103_St implements OptionsEnum { THROTTLED(5, "THROTTLED"), // SHUTTING_DOWN(6, "SHUTTING_DOWN"), // FAULT(7, "FAULT"), // - STANDBY(8, "STANDBY"); // + STANDBY(8, "STANDBY"); private final int value; private final String name; @@ -2607,401 +943,140 @@ public OptionsEnum getUndefined() { } } - public static enum S103_Evt1 implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - GROUND_FAULT(0, "GROUND_FAULT"), // - DC_OVER_VOLT(1, "DC_OVER_VOLT"), // - AC_DISCONNECT(2, "AC_DISCONNECT"), // - DC_DISCONNECT(3, "DC_DISCONNECT"), // - GRID_DISCONNECT(4, "GRID_DISCONNECT"), // - CABINET_OPEN(5, "CABINET_OPEN"), // - MANUAL_SHUTDOWN(6, "MANUAL_SHUTDOWN"), // - OVER_TEMP(7, "OVER_TEMP"), // - OVER_FREQUENCY(8, "OVER_FREQUENCY"), // - UNDER_FREQUENCY(9, "UNDER_FREQUENCY"), // - AC_OVER_VOLT(10, "AC_OVER_VOLT"), // - AC_UNDER_VOLT(11, "AC_UNDER_VOLT"), // - BLOWN_STRING_FUSE(12, "BLOWN_STRING_FUSE"), // - UNDER_TEMP(13, "UNDER_TEMP"), // - MEMORY_LOSS(14, "MEMORY_LOSS"), // - HW_TEST_FAILURE(15, "HW_TEST_FAILURE"); // - - private final int value; - private final String name; - - private S103_Evt1(int value, String name) { - this.value = value; - this.name = name; - } + public static enum S103_Evt1 implements SunSpecBitPoint { + GROUND_FAULT(new BitPoint(0, "S103_EVT1_GROUND_FAULT", "Ground Fault", Level.INFO)), // + DC_OVER_VOLT(new BitPoint(1, "S103_EVT1_DC_OVER_VOLT", "DC Over Volt", Level.INFO)), // + AC_DISCONNECT(new BitPoint(2, "S103_EVT1_AC_DISCONNECT", "AC Disconnect", Level.INFO)), // + DC_DISCONNECT(new BitPoint(3, "S103_EVT1_DC_DISCONNECT", "DC Disconnect", Level.INFO)), // + GRID_DISCONNECT(new BitPoint(4, "S103_EVT1_GRID_DISCONNECT", "Grid Disconnect", Level.INFO)), // + CABINET_OPEN(new BitPoint(5, "S103_EVT1_CABINET_OPEN", "Cabinet Open", Level.INFO)), // + MANUAL_SHUTDOWN(new BitPoint(6, "S103_EVT1_MANUAL_SHUTDOWN", "Manual Shutdown", Level.INFO)), // + OVER_TEMP(new BitPoint(7, "S103_EVT1_OVER_TEMP", "Over Temp", Level.INFO)), // + OVER_FREQUENCY(new BitPoint(8, "S103_EVT1_OVER_FREQUENCY", "Over Frequency", Level.INFO)), // + UNDER_FREQUENCY(new BitPoint(9, "S103_EVT1_UNDER_FREQUENCY", "Under Frequency", Level.INFO)), // + AC_OVER_VOLT(new BitPoint(10, "S103_EVT1_AC_OVER_VOLT", "AC Over Volt", Level.INFO)), // + AC_UNDER_VOLT(new BitPoint(11, "S103_EVT1_AC_UNDER_VOLT", "AC Under Volt", Level.INFO)), // + BLOWN_STRING_FUSE(new BitPoint(12, "S103_EVT1_BLOWN_STRING_FUSE", "Blown String Fuse", Level.INFO)), // + UNDER_TEMP(new BitPoint(13, "S103_EVT1_UNDER_TEMP", "Under Temp", Level.INFO)), // + MEMORY_LOSS(new BitPoint(14, "S103_EVT1_MEMORY_LOSS", "Memory Loss", Level.INFO)), // + HW_TEST_FAILURE(new BitPoint(15, "S103_EVT1_HW_TEST_FAILURE", "HW Test Failure", Level.INFO)); - @Override - public int getValue() { - return this.value; - } + private final BitPoint point; - @Override - public String getName() { - return this.name; + private S103_Evt1(BitPoint point) { + this.point = point; } @Override - public OptionsEnum getUndefined() { - return UNDEFINED; + public BitPoint get() { + return this.point; } } public static enum S111 implements SunSpecPoint { - A(new PointImpl(// - "S111_A", // - "Amps", // + A(new ValuePoint("S111_A", "Amps", // "AC Current", // - "", // - PointType.FLOAT32, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - null, // - new OptionsEnum[0])), // - APH_A(new PointImpl(// - "S111_APH_A", // - "Amps PhaseA", // + ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE)), // + APH_A(new ValuePoint("S111_APH_A", "Amps PhaseA", // "Phase A Current", // - "", // - PointType.FLOAT32, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - null, // - new OptionsEnum[0])), // - APH_B(new PointImpl(// - "S111_APH_B", // - "Amps PhaseB", // + ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE)), // + APH_B(new ValuePoint("S111_APH_B", "Amps PhaseB", // "Phase B Current", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - null, // - new OptionsEnum[0])), // - APH_C(new PointImpl(// - "S111_APH_C", // - "Amps PhaseC", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE)), // + APH_C(new ValuePoint("S111_APH_C", "Amps PhaseC", // "Phase C Current", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - null, // - new OptionsEnum[0])), // - P_P_VPH_A_B(new PointImpl(// - "S111_P_P_VPH_A_B", // - "Phase Voltage AB", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE)), // + P_P_VPH_A_B(new ValuePoint("S111_P_P_VPH_A_B", "Phase Voltage AB", // "Phase Voltage AB", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - null, // - new OptionsEnum[0])), // - P_P_VPH_B_C(new PointImpl(// - "S111_P_P_VPH_B_C", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + P_P_VPH_B_C(new ValuePoint("S111_P_P_VPH_B_C", "Phase Voltage BC", // "Phase Voltage BC", // - "Phase Voltage BC", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - null, // - new OptionsEnum[0])), // - P_P_VPH_C_A(new PointImpl(// - "S111_P_P_VPH_C_A", // - "Phase Voltage CA", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + P_P_VPH_C_A(new ValuePoint("S111_P_P_VPH_C_A", "Phase Voltage CA", // "Phase Voltage CA", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - null, // - new OptionsEnum[0])), // - PH_VPH_A(new PointImpl(// - "S111_PH_VPH_A", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + PH_VPH_A(new ValuePoint("S111_PH_VPH_A", "Phase Voltage AN", // "Phase Voltage AN", // - "Phase Voltage AN", // - "", // - PointType.FLOAT32, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - null, // - new OptionsEnum[0])), // - PH_VPH_B(new PointImpl(// - "S111_PH_VPH_B", // - "Phase Voltage BN", // + ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + PH_VPH_B(new ValuePoint("S111_PH_VPH_B", "Phase Voltage BN", // "Phase Voltage BN", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - null, // - new OptionsEnum[0])), // - PH_VPH_C(new PointImpl(// - "S111_PH_VPH_C", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + PH_VPH_C(new ValuePoint("S111_PH_VPH_C", "Phase Voltage CN", // "Phase Voltage CN", // - "Phase Voltage CN", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - null, // - new OptionsEnum[0])), // - W(new PointImpl(// - "S111_W", // - "Watts", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + W(new ValuePoint("S111_W", "Watts", // "AC Power", // - "", // - PointType.FLOAT32, // - true, // - AccessMode.READ_ONLY, // - Unit.WATT, // - null, // - new OptionsEnum[0])), // - HZ(new PointImpl(// - "S111_HZ", // - "Hz", // + ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT)), // + HZ(new ValuePoint("S111_HZ", "Hz", // "Line Frequency", // - "", // - PointType.FLOAT32, // - true, // - AccessMode.READ_ONLY, // - Unit.HERTZ, // - null, // - new OptionsEnum[0])), // - VA(new PointImpl(// - "S111_VA", // - "VA", // + ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.HERTZ)), // + VA(new ValuePoint("S111_VA", "VA", // "AC Apparent Power", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE, // - null, // - new OptionsEnum[0])), // - V_AR(new PointImpl(// - "S111_V_AR", // - "VAr", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE)), // + V_AR(new ValuePoint("S111_V_AR", "VAr", // "AC Reactive Power", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - null, // - new OptionsEnum[0])), // - PF(new PointImpl(// - "S111_PF", // - "PF", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE)), // + PF(new ValuePoint("S111_PF", "PF", // "AC Power Factor", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - WH(new PointImpl(// - "S111_WH", // - "WattHours", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + WH(new ValuePoint("S111_WH", "WattHours", // "AC Energy", // - "", // - PointType.FLOAT32, // - true, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - null, // - new OptionsEnum[0])), // - DCA(new PointImpl(// - "S111_DCA", // - "DC Amps", // + ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS)), // + DCA(new ValuePoint("S111_DCA", "DC Amps", // "DC Current", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - null, // - new OptionsEnum[0])), // - DCV(new PointImpl(// - "S111_DCV", // - "DC Voltage", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE)), // + DCV(new ValuePoint("S111_DCV", "DC Voltage", // "DC Voltage", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - null, // - new OptionsEnum[0])), // - DCW(new PointImpl(// - "S111_DCW", // - "DC Watts", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + DCW(new ValuePoint("S111_DCW", "DC Watts", // "DC Power", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.WATT, // - null, // - new OptionsEnum[0])), // - TMP_CAB(new PointImpl(// - "S111_TMP_CAB", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT)), // + TMP_CAB(new ValuePoint("S111_TMP_CAB", "Cabinet Temperature", // "Cabinet Temperature", // - "Cabinet Temperature", // - "", // - PointType.FLOAT32, // - true, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - null, // - new OptionsEnum[0])), // - TMP_SNK(new PointImpl(// - "S111_TMP_SNK", // - "Heat Sink Temperature", // + ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS)), // + TMP_SNK(new ValuePoint("S111_TMP_SNK", "Heat Sink Temperature", // "Heat Sink Temperature", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - null, // - new OptionsEnum[0])), // - TMP_TRNS(new PointImpl(// - "S111_TMP_TRNS", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS)), // + TMP_TRNS(new ValuePoint("S111_TMP_TRNS", "Transformer Temperature", // "Transformer Temperature", // - "Transformer Temperature", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - null, // - new OptionsEnum[0])), // - TMP_OT(new PointImpl(// - "S111_TMP_OT", // - "Other Temperature", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS)), // + TMP_OT(new ValuePoint("S111_TMP_OT", "Other Temperature", // "Other Temperature", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - null, // - new OptionsEnum[0])), // - ST(new PointImpl(// - "S111_ST", // - "Operating State", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS)), // + ST(new EnumPoint("S111_ST", "Operating State", // "Enumerated value. Operating state", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S111_St.values())), // - ST_VND(new PointImpl(// - "S111_ST_VND", // - "Vendor Operating State", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S111_St.values())), // + ST_VND(new EnumPoint("S111_ST_VND", "Vendor Operating State", // "Vendor specific operating state code", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT1(new PointImpl(// - "S111_EVT1", // - "Event1", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, new OptionsEnum[0])), // + EVT1(new BitFieldPoint("S111_EVT1", "Event1", // "Bitmask value. Event fields", // - "", // - PointType.BITFIELD32, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S111_Evt1.values())), // - EVT2(new PointImpl(// - "S111_EVT2", // - "Event Bitfield 2", // + BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, S111_Evt1.values())), // + EVT2(new BitFieldPoint("S111_EVT2", "Event Bitfield 2", // "Reserved for future use", // - "", // - PointType.BITFIELD32, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT_VND1(new PointImpl(// - "S111_EVT_VND1", // - "Vendor Event Bitfield 1", // + BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + EVT_VND1(new BitFieldPoint("S111_EVT_VND1", "Vendor Event Bitfield 1", // "Vendor defined events", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT_VND2(new PointImpl(// - "S111_EVT_VND2", // - "Vendor Event Bitfield 2", // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + EVT_VND2(new BitFieldPoint("S111_EVT_VND2", "Vendor Event Bitfield 2", // "Vendor defined events", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT_VND3(new PointImpl(// - "S111_EVT_VND3", // - "Vendor Event Bitfield 3", // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + EVT_VND3(new BitFieldPoint("S111_EVT_VND3", "Vendor Event Bitfield 3", // "Vendor defined events", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT_VND4(new PointImpl(// - "S111_EVT_VND4", // - "Vendor Event Bitfield 4", // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + EVT_VND4(new BitFieldPoint("S111_EVT_VND4", "Vendor Event Bitfield 4", // "Vendor defined events", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])); - protected final PointImpl impl; + private final Point point; - private S111(PointImpl impl) { - this.impl = impl; + private S111(Point point) { + this.point = point; } @Override - public PointImpl get() { - return this.impl; + public Point get() { + return this.point; } } @@ -3014,7 +1089,7 @@ public static enum S111_St implements OptionsEnum { THROTTLED(5, "THROTTLED"), // SHUTTING_DOWN(6, "SHUTTING_DOWN"), // FAULT(7, "FAULT"), // - STANDBY(8, "STANDBY"); // + STANDBY(8, "STANDBY"); private final int value; private final String name; @@ -3040,401 +1115,140 @@ public OptionsEnum getUndefined() { } } - public static enum S111_Evt1 implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - GROUND_FAULT(0, "GROUND_FAULT"), // - DC_OVER_VOLT(1, "DC_OVER_VOLT"), // - AC_DISCONNECT(2, "AC_DISCONNECT"), // - DC_DISCONNECT(3, "DC_DISCONNECT"), // - GRID_DISCONNECT(4, "GRID_DISCONNECT"), // - CABINET_OPEN(5, "CABINET_OPEN"), // - MANUAL_SHUTDOWN(6, "MANUAL_SHUTDOWN"), // - OVER_TEMP(7, "OVER_TEMP"), // - OVER_FREQUENCY(8, "OVER_FREQUENCY"), // - UNDER_FREQUENCY(9, "UNDER_FREQUENCY"), // - AC_OVER_VOLT(10, "AC_OVER_VOLT"), // - AC_UNDER_VOLT(11, "AC_UNDER_VOLT"), // - BLOWN_STRING_FUSE(12, "BLOWN_STRING_FUSE"), // - UNDER_TEMP(13, "UNDER_TEMP"), // - MEMORY_LOSS(14, "MEMORY_LOSS"), // - HW_TEST_FAILURE(15, "HW_TEST_FAILURE"); // - - private final int value; - private final String name; - - private S111_Evt1(int value, String name) { - this.value = value; - this.name = name; - } + public static enum S111_Evt1 implements SunSpecBitPoint { + GROUND_FAULT(new BitPoint(0, "S111_EVT1_GROUND_FAULT", "Ground Fault", Level.INFO)), // + DC_OVER_VOLT(new BitPoint(1, "S111_EVT1_DC_OVER_VOLT", "DC Over Volt", Level.INFO)), // + AC_DISCONNECT(new BitPoint(2, "S111_EVT1_AC_DISCONNECT", "AC Disconnect", Level.INFO)), // + DC_DISCONNECT(new BitPoint(3, "S111_EVT1_DC_DISCONNECT", "DC Disconnect", Level.INFO)), // + GRID_DISCONNECT(new BitPoint(4, "S111_EVT1_GRID_DISCONNECT", "Grid Disconnect", Level.INFO)), // + CABINET_OPEN(new BitPoint(5, "S111_EVT1_CABINET_OPEN", "Cabinet Open", Level.INFO)), // + MANUAL_SHUTDOWN(new BitPoint(6, "S111_EVT1_MANUAL_SHUTDOWN", "Manual Shutdown", Level.INFO)), // + OVER_TEMP(new BitPoint(7, "S111_EVT1_OVER_TEMP", "Over Temp", Level.INFO)), // + OVER_FREQUENCY(new BitPoint(8, "S111_EVT1_OVER_FREQUENCY", "Over Frequency", Level.INFO)), // + UNDER_FREQUENCY(new BitPoint(9, "S111_EVT1_UNDER_FREQUENCY", "Under Frequency", Level.INFO)), // + AC_OVER_VOLT(new BitPoint(10, "S111_EVT1_AC_OVER_VOLT", "AC Over Volt", Level.INFO)), // + AC_UNDER_VOLT(new BitPoint(11, "S111_EVT1_AC_UNDER_VOLT", "AC Under Volt", Level.INFO)), // + BLOWN_STRING_FUSE(new BitPoint(12, "S111_EVT1_BLOWN_STRING_FUSE", "Blown String Fuse", Level.INFO)), // + UNDER_TEMP(new BitPoint(13, "S111_EVT1_UNDER_TEMP", "Under Temp", Level.INFO)), // + MEMORY_LOSS(new BitPoint(14, "S111_EVT1_MEMORY_LOSS", "Memory Loss", Level.INFO)), // + HW_TEST_FAILURE(new BitPoint(15, "S111_EVT1_HW_TEST_FAILURE", "HW Test Failure", Level.INFO)); - @Override - public int getValue() { - return this.value; - } + private final BitPoint point; - @Override - public String getName() { - return this.name; + private S111_Evt1(BitPoint point) { + this.point = point; } @Override - public OptionsEnum getUndefined() { - return UNDEFINED; + public BitPoint get() { + return this.point; } } public static enum S112 implements SunSpecPoint { - A(new PointImpl(// - "S112_A", // - "Amps", // + A(new ValuePoint("S112_A", "Amps", // "AC Current", // - "", // - PointType.FLOAT32, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - null, // - new OptionsEnum[0])), // - APH_A(new PointImpl(// - "S112_APH_A", // - "Amps PhaseA", // + ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE)), // + APH_A(new ValuePoint("S112_APH_A", "Amps PhaseA", // "Phase A Current", // - "", // - PointType.FLOAT32, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - null, // - new OptionsEnum[0])), // - APH_B(new PointImpl(// - "S112_APH_B", // - "Amps PhaseB", // + ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE)), // + APH_B(new ValuePoint("S112_APH_B", "Amps PhaseB", // "Phase B Current", // - "", // - PointType.FLOAT32, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - null, // - new OptionsEnum[0])), // - APH_C(new PointImpl(// - "S112_APH_C", // - "Amps PhaseC", // + ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE)), // + APH_C(new ValuePoint("S112_APH_C", "Amps PhaseC", // "Phase C Current", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - null, // - new OptionsEnum[0])), // - P_P_VPH_A_B(new PointImpl(// - "S112_P_P_VPH_A_B", // - "Phase Voltage AB", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE)), // + P_P_VPH_A_B(new ValuePoint("S112_P_P_VPH_A_B", "Phase Voltage AB", // "Phase Voltage AB", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - null, // - new OptionsEnum[0])), // - P_P_VPH_B_C(new PointImpl(// - "S112_P_P_VPH_B_C", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + P_P_VPH_B_C(new ValuePoint("S112_P_P_VPH_B_C", "Phase Voltage BC", // "Phase Voltage BC", // - "Phase Voltage BC", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - null, // - new OptionsEnum[0])), // - P_P_VPH_C_A(new PointImpl(// - "S112_P_P_VPH_C_A", // - "Phase Voltage CA", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + P_P_VPH_C_A(new ValuePoint("S112_P_P_VPH_C_A", "Phase Voltage CA", // "Phase Voltage CA", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - null, // - new OptionsEnum[0])), // - PH_VPH_A(new PointImpl(// - "S112_PH_VPH_A", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + PH_VPH_A(new ValuePoint("S112_PH_VPH_A", "Phase Voltage AN", // "Phase Voltage AN", // - "Phase Voltage AN", // - "", // - PointType.FLOAT32, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - null, // - new OptionsEnum[0])), // - PH_VPH_B(new PointImpl(// - "S112_PH_VPH_B", // - "Phase Voltage BN", // + ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + PH_VPH_B(new ValuePoint("S112_PH_VPH_B", "Phase Voltage BN", // "Phase Voltage BN", // - "", // - PointType.FLOAT32, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - null, // - new OptionsEnum[0])), // - PH_VPH_C(new PointImpl(// - "S112_PH_VPH_C", // + ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + PH_VPH_C(new ValuePoint("S112_PH_VPH_C", "Phase Voltage CN", // "Phase Voltage CN", // - "Phase Voltage CN", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - null, // - new OptionsEnum[0])), // - W(new PointImpl(// - "S112_W", // - "Watts", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + W(new ValuePoint("S112_W", "Watts", // "AC Power", // - "", // - PointType.FLOAT32, // - true, // - AccessMode.READ_ONLY, // - Unit.WATT, // - null, // - new OptionsEnum[0])), // - HZ(new PointImpl(// - "S112_HZ", // - "Hz", // + ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT)), // + HZ(new ValuePoint("S112_HZ", "Hz", // "Line Frequency", // - "", // - PointType.FLOAT32, // - true, // - AccessMode.READ_ONLY, // - Unit.HERTZ, // - null, // - new OptionsEnum[0])), // - VA(new PointImpl(// - "S112_VA", // - "VA", // + ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.HERTZ)), // + VA(new ValuePoint("S112_VA", "VA", // "AC Apparent Power", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE, // - null, // - new OptionsEnum[0])), // - V_AR(new PointImpl(// - "S112_V_AR", // - "VAr", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE)), // + V_AR(new ValuePoint("S112_V_AR", "VAr", // "AC Reactive Power", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - null, // - new OptionsEnum[0])), // - PF(new PointImpl(// - "S112_PF", // - "PF", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE)), // + PF(new ValuePoint("S112_PF", "PF", // "AC Power Factor", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - WH(new PointImpl(// - "S112_WH", // - "WattHours", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + WH(new ValuePoint("S112_WH", "WattHours", // "AC Energy", // - "", // - PointType.FLOAT32, // - true, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - null, // - new OptionsEnum[0])), // - DCA(new PointImpl(// - "S112_DCA", // - "DC Amps", // + ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS)), // + DCA(new ValuePoint("S112_DCA", "DC Amps", // "DC Current", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - null, // - new OptionsEnum[0])), // - DCV(new PointImpl(// - "S112_DCV", // - "DC Voltage", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE)), // + DCV(new ValuePoint("S112_DCV", "DC Voltage", // "DC Voltage", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - null, // - new OptionsEnum[0])), // - DCW(new PointImpl(// - "S112_DCW", // - "DC Watts", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + DCW(new ValuePoint("S112_DCW", "DC Watts", // "DC Power", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.WATT, // - null, // - new OptionsEnum[0])), // - TMP_CAB(new PointImpl(// - "S112_TMP_CAB", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT)), // + TMP_CAB(new ValuePoint("S112_TMP_CAB", "Cabinet Temperature", // "Cabinet Temperature", // - "Cabinet Temperature", // - "", // - PointType.FLOAT32, // - true, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - null, // - new OptionsEnum[0])), // - TMP_SNK(new PointImpl(// - "S112_TMP_SNK", // - "Heat Sink Temperature", // + ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS)), // + TMP_SNK(new ValuePoint("S112_TMP_SNK", "Heat Sink Temperature", // "Heat Sink Temperature", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - null, // - new OptionsEnum[0])), // - TMP_TRNS(new PointImpl(// - "S112_TMP_TRNS", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS)), // + TMP_TRNS(new ValuePoint("S112_TMP_TRNS", "Transformer Temperature", // "Transformer Temperature", // - "Transformer Temperature", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - null, // - new OptionsEnum[0])), // - TMP_OT(new PointImpl(// - "S112_TMP_OT", // - "Other Temperature", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS)), // + TMP_OT(new ValuePoint("S112_TMP_OT", "Other Temperature", // "Other Temperature", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - null, // - new OptionsEnum[0])), // - ST(new PointImpl(// - "S112_ST", // - "Operating State", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS)), // + ST(new EnumPoint("S112_ST", "Operating State", // "Enumerated value. Operating state", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S112_St.values())), // - ST_VND(new PointImpl(// - "S112_ST_VND", // - "Vendor Operating State", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S112_St.values())), // + ST_VND(new EnumPoint("S112_ST_VND", "Vendor Operating State", // "Vendor specific operating state code", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT1(new PointImpl(// - "S112_EVT1", // - "Event1", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, new OptionsEnum[0])), // + EVT1(new BitFieldPoint("S112_EVT1", "Event1", // "Bitmask value. Event fields", // - "", // - PointType.BITFIELD32, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S112_Evt1.values())), // - EVT2(new PointImpl(// - "S112_EVT2", // - "Event Bitfield 2", // + BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, S112_Evt1.values())), // + EVT2(new BitFieldPoint("S112_EVT2", "Event Bitfield 2", // "Reserved for future use", // - "", // - PointType.BITFIELD32, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT_VND1(new PointImpl(// - "S112_EVT_VND1", // - "Vendor Event Bitfield 1", // + BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + EVT_VND1(new BitFieldPoint("S112_EVT_VND1", "Vendor Event Bitfield 1", // "Vendor defined events", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT_VND2(new PointImpl(// - "S112_EVT_VND2", // - "Vendor Event Bitfield 2", // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + EVT_VND2(new BitFieldPoint("S112_EVT_VND2", "Vendor Event Bitfield 2", // "Vendor defined events", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT_VND3(new PointImpl(// - "S112_EVT_VND3", // - "Vendor Event Bitfield 3", // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + EVT_VND3(new BitFieldPoint("S112_EVT_VND3", "Vendor Event Bitfield 3", // "Vendor defined events", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT_VND4(new PointImpl(// - "S112_EVT_VND4", // - "Vendor Event Bitfield 4", // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + EVT_VND4(new BitFieldPoint("S112_EVT_VND4", "Vendor Event Bitfield 4", // "Vendor defined events", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])); - protected final PointImpl impl; + private final Point point; - private S112(PointImpl impl) { - this.impl = impl; + private S112(Point point) { + this.point = point; } @Override - public PointImpl get() { - return this.impl; + public Point get() { + return this.point; } } @@ -3447,7 +1261,7 @@ public static enum S112_St implements OptionsEnum { THROTTLED(5, "THROTTLED"), // SHUTTING_DOWN(6, "SHUTTING_DOWN"), // FAULT(7, "FAULT"), // - STANDBY(8, "STANDBY"); // + STANDBY(8, "STANDBY"); private final int value; private final String name; @@ -3473,401 +1287,140 @@ public OptionsEnum getUndefined() { } } - public static enum S112_Evt1 implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - GROUND_FAULT(0, "GROUND_FAULT"), // - DC_OVER_VOLT(1, "DC_OVER_VOLT"), // - AC_DISCONNECT(2, "AC_DISCONNECT"), // - DC_DISCONNECT(3, "DC_DISCONNECT"), // - GRID_DISCONNECT(4, "GRID_DISCONNECT"), // - CABINET_OPEN(5, "CABINET_OPEN"), // - MANUAL_SHUTDOWN(6, "MANUAL_SHUTDOWN"), // - OVER_TEMP(7, "OVER_TEMP"), // - OVER_FREQUENCY(8, "OVER_FREQUENCY"), // - UNDER_FREQUENCY(9, "UNDER_FREQUENCY"), // - AC_OVER_VOLT(10, "AC_OVER_VOLT"), // - AC_UNDER_VOLT(11, "AC_UNDER_VOLT"), // - BLOWN_STRING_FUSE(12, "BLOWN_STRING_FUSE"), // - UNDER_TEMP(13, "UNDER_TEMP"), // - MEMORY_LOSS(14, "MEMORY_LOSS"), // - HW_TEST_FAILURE(15, "HW_TEST_FAILURE"); // - - private final int value; - private final String name; - - private S112_Evt1(int value, String name) { - this.value = value; - this.name = name; - } + public static enum S112_Evt1 implements SunSpecBitPoint { + GROUND_FAULT(new BitPoint(0, "S112_EVT1_GROUND_FAULT", "Ground Fault", Level.INFO)), // + DC_OVER_VOLT(new BitPoint(1, "S112_EVT1_DC_OVER_VOLT", "DC Over Volt", Level.INFO)), // + AC_DISCONNECT(new BitPoint(2, "S112_EVT1_AC_DISCONNECT", "AC Disconnect", Level.INFO)), // + DC_DISCONNECT(new BitPoint(3, "S112_EVT1_DC_DISCONNECT", "DC Disconnect", Level.INFO)), // + GRID_DISCONNECT(new BitPoint(4, "S112_EVT1_GRID_DISCONNECT", "Grid Disconnect", Level.INFO)), // + CABINET_OPEN(new BitPoint(5, "S112_EVT1_CABINET_OPEN", "Cabinet Open", Level.INFO)), // + MANUAL_SHUTDOWN(new BitPoint(6, "S112_EVT1_MANUAL_SHUTDOWN", "Manual Shutdown", Level.INFO)), // + OVER_TEMP(new BitPoint(7, "S112_EVT1_OVER_TEMP", "Over Temp", Level.INFO)), // + OVER_FREQUENCY(new BitPoint(8, "S112_EVT1_OVER_FREQUENCY", "Over Frequency", Level.INFO)), // + UNDER_FREQUENCY(new BitPoint(9, "S112_EVT1_UNDER_FREQUENCY", "Under Frequency", Level.INFO)), // + AC_OVER_VOLT(new BitPoint(10, "S112_EVT1_AC_OVER_VOLT", "AC Over Volt", Level.INFO)), // + AC_UNDER_VOLT(new BitPoint(11, "S112_EVT1_AC_UNDER_VOLT", "AC Under Volt", Level.INFO)), // + BLOWN_STRING_FUSE(new BitPoint(12, "S112_EVT1_BLOWN_STRING_FUSE", "Blown String Fuse", Level.INFO)), // + UNDER_TEMP(new BitPoint(13, "S112_EVT1_UNDER_TEMP", "Under Temp", Level.INFO)), // + MEMORY_LOSS(new BitPoint(14, "S112_EVT1_MEMORY_LOSS", "Memory Loss", Level.INFO)), // + HW_TEST_FAILURE(new BitPoint(15, "S112_EVT1_HW_TEST_FAILURE", "HW Test Failure", Level.INFO)); - @Override - public int getValue() { - return this.value; - } + private final BitPoint point; - @Override - public String getName() { - return this.name; + private S112_Evt1(BitPoint point) { + this.point = point; } @Override - public OptionsEnum getUndefined() { - return UNDEFINED; + public BitPoint get() { + return this.point; } } public static enum S113 implements SunSpecPoint { - A(new PointImpl(// - "S113_A", // - "Amps", // + A(new ValuePoint("S113_A", "Amps", // "AC Current", // - "", // - PointType.FLOAT32, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - null, // - new OptionsEnum[0])), // - APH_A(new PointImpl(// - "S113_APH_A", // - "Amps PhaseA", // + ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE)), // + APH_A(new ValuePoint("S113_APH_A", "Amps PhaseA", // "Phase A Current", // - "", // - PointType.FLOAT32, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - null, // - new OptionsEnum[0])), // - APH_B(new PointImpl(// - "S113_APH_B", // - "Amps PhaseB", // + ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE)), // + APH_B(new ValuePoint("S113_APH_B", "Amps PhaseB", // "Phase B Current", // - "", // - PointType.FLOAT32, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - null, // - new OptionsEnum[0])), // - APH_C(new PointImpl(// - "S113_APH_C", // - "Amps PhaseC", // + ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE)), // + APH_C(new ValuePoint("S113_APH_C", "Amps PhaseC", // "Phase C Current", // - "", // - PointType.FLOAT32, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - null, // - new OptionsEnum[0])), // - P_P_VPH_A_B(new PointImpl(// - "S113_P_P_VPH_A_B", // - "Phase Voltage AB", // + ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE)), // + P_P_VPH_A_B(new ValuePoint("S113_P_P_VPH_A_B", "Phase Voltage AB", // "Phase Voltage AB", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - null, // - new OptionsEnum[0])), // - P_P_VPH_B_C(new PointImpl(// - "S113_P_P_VPH_B_C", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + P_P_VPH_B_C(new ValuePoint("S113_P_P_VPH_B_C", "Phase Voltage BC", // "Phase Voltage BC", // - "Phase Voltage BC", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - null, // - new OptionsEnum[0])), // - P_P_VPH_C_A(new PointImpl(// - "S113_P_P_VPH_C_A", // - "Phase Voltage CA", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + P_P_VPH_C_A(new ValuePoint("S113_P_P_VPH_C_A", "Phase Voltage CA", // "Phase Voltage CA", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - null, // - new OptionsEnum[0])), // - PH_VPH_A(new PointImpl(// - "S113_PH_VPH_A", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + PH_VPH_A(new ValuePoint("S113_PH_VPH_A", "Phase Voltage AN", // "Phase Voltage AN", // - "Phase Voltage AN", // - "", // - PointType.FLOAT32, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - null, // - new OptionsEnum[0])), // - PH_VPH_B(new PointImpl(// - "S113_PH_VPH_B", // - "Phase Voltage BN", // + ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + PH_VPH_B(new ValuePoint("S113_PH_VPH_B", "Phase Voltage BN", // "Phase Voltage BN", // - "", // - PointType.FLOAT32, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - null, // - new OptionsEnum[0])), // - PH_VPH_C(new PointImpl(// - "S113_PH_VPH_C", // + ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + PH_VPH_C(new ValuePoint("S113_PH_VPH_C", "Phase Voltage CN", // "Phase Voltage CN", // - "Phase Voltage CN", // - "", // - PointType.FLOAT32, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - null, // - new OptionsEnum[0])), // - W(new PointImpl(// - "S113_W", // - "Watts", // + ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + W(new ValuePoint("S113_W", "Watts", // "AC Power", // - "", // - PointType.FLOAT32, // - true, // - AccessMode.READ_ONLY, // - Unit.WATT, // - null, // - new OptionsEnum[0])), // - HZ(new PointImpl(// - "S113_HZ", // - "Hz", // + ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT)), // + HZ(new ValuePoint("S113_HZ", "Hz", // "Line Frequency", // - "", // - PointType.FLOAT32, // - true, // - AccessMode.READ_ONLY, // - Unit.HERTZ, // - null, // - new OptionsEnum[0])), // - VA(new PointImpl(// - "S113_VA", // - "VA", // + ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.HERTZ)), // + VA(new ValuePoint("S113_VA", "VA", // "AC Apparent Power", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE, // - null, // - new OptionsEnum[0])), // - V_AR(new PointImpl(// - "S113_V_AR", // - "VAr", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE)), // + V_AR(new ValuePoint("S113_V_AR", "VAr", // "AC Reactive Power", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - null, // - new OptionsEnum[0])), // - PF(new PointImpl(// - "S113_PF", // - "PF", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE)), // + PF(new ValuePoint("S113_PF", "PF", // "AC Power Factor", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - WH(new PointImpl(// - "S113_WH", // - "WattHours", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + WH(new ValuePoint("S113_WH", "WattHours", // "AC Energy", // - "", // - PointType.FLOAT32, // - true, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - null, // - new OptionsEnum[0])), // - DCA(new PointImpl(// - "S113_DCA", // - "DC Amps", // + ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS)), // + DCA(new ValuePoint("S113_DCA", "DC Amps", // "DC Current", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - null, // - new OptionsEnum[0])), // - DCV(new PointImpl(// - "S113_DCV", // - "DC Voltage", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE)), // + DCV(new ValuePoint("S113_DCV", "DC Voltage", // "DC Voltage", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - null, // - new OptionsEnum[0])), // - DCW(new PointImpl(// - "S113_DCW", // - "DC Watts", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + DCW(new ValuePoint("S113_DCW", "DC Watts", // "DC Power", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.WATT, // - null, // - new OptionsEnum[0])), // - TMP_CAB(new PointImpl(// - "S113_TMP_CAB", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT)), // + TMP_CAB(new ValuePoint("S113_TMP_CAB", "Cabinet Temperature", // "Cabinet Temperature", // - "Cabinet Temperature", // - "", // - PointType.FLOAT32, // - true, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - null, // - new OptionsEnum[0])), // - TMP_SNK(new PointImpl(// - "S113_TMP_SNK", // - "Heat Sink Temperature", // + ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS)), // + TMP_SNK(new ValuePoint("S113_TMP_SNK", "Heat Sink Temperature", // "Heat Sink Temperature", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - null, // - new OptionsEnum[0])), // - TMP_TRNS(new PointImpl(// - "S113_TMP_TRNS", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS)), // + TMP_TRNS(new ValuePoint("S113_TMP_TRNS", "Transformer Temperature", // "Transformer Temperature", // - "Transformer Temperature", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - null, // - new OptionsEnum[0])), // - TMP_OT(new PointImpl(// - "S113_TMP_OT", // - "Other Temperature", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS)), // + TMP_OT(new ValuePoint("S113_TMP_OT", "Other Temperature", // "Other Temperature", // - "", // - PointType.FLOAT32, // - false, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - null, // - new OptionsEnum[0])), // - ST(new PointImpl(// - "S113_ST", // - "Operating State", // + ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS)), // + ST(new EnumPoint("S113_ST", "Operating State", // "Enumerated value. Operating state", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S113_St.values())), // - ST_VND(new PointImpl(// - "S113_ST_VND", // - "Vendor Operating State", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S113_St.values())), // + ST_VND(new EnumPoint("S113_ST_VND", "Vendor Operating State", // "Vendor specific operating state code", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT1(new PointImpl(// - "S113_EVT1", // - "Event1", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, new OptionsEnum[0])), // + EVT1(new BitFieldPoint("S113_EVT1", "Event1", // "Bitmask value. Event fields", // - "", // - PointType.BITFIELD32, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S113_Evt1.values())), // - EVT2(new PointImpl(// - "S113_EVT2", // - "Event Bitfield 2", // + BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, S113_Evt1.values())), // + EVT2(new BitFieldPoint("S113_EVT2", "Event Bitfield 2", // "Reserved for future use", // - "", // - PointType.BITFIELD32, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT_VND1(new PointImpl(// - "S113_EVT_VND1", // - "Vendor Event Bitfield 1", // + BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + EVT_VND1(new BitFieldPoint("S113_EVT_VND1", "Vendor Event Bitfield 1", // "Vendor defined events", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT_VND2(new PointImpl(// - "S113_EVT_VND2", // - "Vendor Event Bitfield 2", // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + EVT_VND2(new BitFieldPoint("S113_EVT_VND2", "Vendor Event Bitfield 2", // "Vendor defined events", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT_VND3(new PointImpl(// - "S113_EVT_VND3", // - "Vendor Event Bitfield 3", // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + EVT_VND3(new BitFieldPoint("S113_EVT_VND3", "Vendor Event Bitfield 3", // "Vendor defined events", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT_VND4(new PointImpl(// - "S113_EVT_VND4", // - "Vendor Event Bitfield 4", // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + EVT_VND4(new BitFieldPoint("S113_EVT_VND4", "Vendor Event Bitfield 4", // "Vendor defined events", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])); - protected final PointImpl impl; + private final Point point; - private S113(PointImpl impl) { - this.impl = impl; + private S113(Point point) { + this.point = point; } @Override - public PointImpl get() { - return this.impl; + public Point get() { + return this.point; } } @@ -3880,7 +1433,7 @@ public static enum S113_St implements OptionsEnum { THROTTLED(5, "THROTTLED"), // SHUTTING_DOWN(6, "SHUTTING_DOWN"), // FAULT(7, "FAULT"), // - STANDBY(8, "STANDBY"); // + STANDBY(8, "STANDBY"); private final int value; private final String name; @@ -3906,353 +1459,123 @@ public OptionsEnum getUndefined() { } } - public static enum S113_Evt1 implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - GROUND_FAULT(0, "GROUND_FAULT"), // - DC_OVER_VOLT(1, "DC_OVER_VOLT"), // - AC_DISCONNECT(2, "AC_DISCONNECT"), // - DC_DISCONNECT(3, "DC_DISCONNECT"), // - GRID_DISCONNECT(4, "GRID_DISCONNECT"), // - CABINET_OPEN(5, "CABINET_OPEN"), // - MANUAL_SHUTDOWN(6, "MANUAL_SHUTDOWN"), // - OVER_TEMP(7, "OVER_TEMP"), // - OVER_FREQUENCY(8, "OVER_FREQUENCY"), // - UNDER_FREQUENCY(9, "UNDER_FREQUENCY"), // - AC_OVER_VOLT(10, "AC_OVER_VOLT"), // - AC_UNDER_VOLT(11, "AC_UNDER_VOLT"), // - BLOWN_STRING_FUSE(12, "BLOWN_STRING_FUSE"), // - UNDER_TEMP(13, "UNDER_TEMP"), // - MEMORY_LOSS(14, "MEMORY_LOSS"), // - HW_TEST_FAILURE(15, "HW_TEST_FAILURE"); // - - private final int value; - private final String name; - - private S113_Evt1(int value, String name) { - this.value = value; - this.name = name; - } + public static enum S113_Evt1 implements SunSpecBitPoint { + GROUND_FAULT(new BitPoint(0, "S113_EVT1_GROUND_FAULT", "Ground Fault", Level.INFO)), // + DC_OVER_VOLT(new BitPoint(1, "S113_EVT1_DC_OVER_VOLT", "DC Over Volt", Level.INFO)), // + AC_DISCONNECT(new BitPoint(2, "S113_EVT1_AC_DISCONNECT", "AC Disconnect", Level.INFO)), // + DC_DISCONNECT(new BitPoint(3, "S113_EVT1_DC_DISCONNECT", "DC Disconnect", Level.INFO)), // + GRID_DISCONNECT(new BitPoint(4, "S113_EVT1_GRID_DISCONNECT", "Grid Disconnect", Level.INFO)), // + CABINET_OPEN(new BitPoint(5, "S113_EVT1_CABINET_OPEN", "Cabinet Open", Level.INFO)), // + MANUAL_SHUTDOWN(new BitPoint(6, "S113_EVT1_MANUAL_SHUTDOWN", "Manual Shutdown", Level.INFO)), // + OVER_TEMP(new BitPoint(7, "S113_EVT1_OVER_TEMP", "Over Temp", Level.INFO)), // + OVER_FREQUENCY(new BitPoint(8, "S113_EVT1_OVER_FREQUENCY", "Over Frequency", Level.INFO)), // + UNDER_FREQUENCY(new BitPoint(9, "S113_EVT1_UNDER_FREQUENCY", "Under Frequency", Level.INFO)), // + AC_OVER_VOLT(new BitPoint(10, "S113_EVT1_AC_OVER_VOLT", "AC Over Volt", Level.INFO)), // + AC_UNDER_VOLT(new BitPoint(11, "S113_EVT1_AC_UNDER_VOLT", "AC Under Volt", Level.INFO)), // + BLOWN_STRING_FUSE(new BitPoint(12, "S113_EVT1_BLOWN_STRING_FUSE", "Blown String Fuse", Level.INFO)), // + UNDER_TEMP(new BitPoint(13, "S113_EVT1_UNDER_TEMP", "Under Temp", Level.INFO)), // + MEMORY_LOSS(new BitPoint(14, "S113_EVT1_MEMORY_LOSS", "Memory Loss", Level.INFO)), // + HW_TEST_FAILURE(new BitPoint(15, "S113_EVT1_HW_TEST_FAILURE", "HW Test Failure", Level.INFO)); - @Override - public int getValue() { - return this.value; - } + private final BitPoint point; - @Override - public String getName() { - return this.name; + private S113_Evt1(BitPoint point) { + this.point = point; } @Override - public OptionsEnum getUndefined() { - return UNDEFINED; + public BitPoint get() { + return this.point; } } public static enum S120 implements SunSpecPoint { - D_E_R_TYP(new PointImpl(// - "S120_D_E_R_TYP", // - "DERTyp", // + D_E_R_TYP(new EnumPoint("S120_D_E_R_TYP", "DERTyp", // "Type of DER device. Default value is 4 to indicate PV device.", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S120_DERTyp.values())), // - W_RTG(new PointImpl(// - "S120_W_RTG", // - "WRtg", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S120_DERTyp.values())), // + W_RTG(new ScaledValuePoint("S120_W_RTG", "WRtg", // "Continuous power output capability of the inverter.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "WRtg_SF", // - new OptionsEnum[0])), // - W_RTG_S_F(new PointImpl(// - "S120_W_RTG_S_F", // - "WRtg_SF", // - "Scale factor", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - V_A_RTG(new PointImpl(// - "S120_V_A_RTG", // - "VARtg", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "WRtg_SF")), // + W_RTG_S_F(new ScaleFactorPoint("S120_W_RTG_S_F", "WRtg_SF", // + "Scale factor")), // + V_A_RTG(new ScaledValuePoint("S120_V_A_RTG", "VARtg", // "Continuous Volt-Ampere capability of the inverter.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE, // - "VARtg_SF", // - new OptionsEnum[0])), // - V_A_RTG_S_F(new PointImpl(// - "S120_V_A_RTG_S_F", // - "VARtg_SF", // - "Scale factor", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - V_AR_RTG_Q1(new PointImpl(// - "S120_V_AR_RTG_Q1", // - "VArRtgQ1", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VARtg_SF")), // + V_A_RTG_S_F(new ScaleFactorPoint("S120_V_A_RTG_S_F", "VARtg_SF", // + "Scale factor")), // + V_AR_RTG_Q1(new ScaledValuePoint("S120_V_AR_RTG_Q1", "VArRtgQ1", // "Continuous VAR capability of the inverter in quadrant 1.", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "VArRtg_SF", // - new OptionsEnum[0])), // - V_AR_RTG_Q2(new PointImpl(// - "S120_V_AR_RTG_Q2", // - "VArRtgQ2", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VArRtg_SF")), // + V_AR_RTG_Q2(new ScaledValuePoint("S120_V_AR_RTG_Q2", "VArRtgQ2", // "Continuous VAR capability of the inverter in quadrant 2.", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "VArRtg_SF", // - new OptionsEnum[0])), // - V_AR_RTG_Q3(new PointImpl(// - "S120_V_AR_RTG_Q3", // - "VArRtgQ3", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VArRtg_SF")), // + V_AR_RTG_Q3(new ScaledValuePoint("S120_V_AR_RTG_Q3", "VArRtgQ3", // "Continuous VAR capability of the inverter in quadrant 3.", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "VArRtg_SF", // - new OptionsEnum[0])), // - V_AR_RTG_Q4(new PointImpl(// - "S120_V_AR_RTG_Q4", // - "VArRtgQ4", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VArRtg_SF")), // + V_AR_RTG_Q4(new ScaledValuePoint("S120_V_AR_RTG_Q4", "VArRtgQ4", // "Continuous VAR capability of the inverter in quadrant 4.", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "VArRtg_SF", // - new OptionsEnum[0])), // - V_AR_RTG_S_F(new PointImpl(// - "S120_V_AR_RTG_S_F", // - "VArRtg_SF", // - "Scale factor", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - A_RTG(new PointImpl(// - "S120_A_RTG", // - "ARtg", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VArRtg_SF")), // + V_AR_RTG_S_F(new ScaleFactorPoint("S120_V_AR_RTG_S_F", "VArRtg_SF", // + "Scale factor")), // + A_RTG(new ScaledValuePoint("S120_A_RTG", "ARtg", // "Maximum RMS AC current level capability of the inverter.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "ARtg_SF", // - new OptionsEnum[0])), // - A_RTG_S_F(new PointImpl(// - "S120_A_RTG_S_F", // - "ARtg_SF", // - "Scale factor", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - P_F_RTG_Q1(new PointImpl(// - "S120_P_F_RTG_Q1", // - "PFRtgQ1", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "ARtg_SF")), // + A_RTG_S_F(new ScaleFactorPoint("S120_A_RTG_S_F", "ARtg_SF", // + "Scale factor")), // + P_F_RTG_Q1(new ScaledValuePoint("S120_P_F_RTG_Q1", "PFRtgQ1", // "Minimum power factor capability of the inverter in quadrant 1.", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "PFRtg_SF", // - new OptionsEnum[0])), // - P_F_RTG_Q2(new PointImpl(// - "S120_P_F_RTG_Q2", // - "PFRtgQ2", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PFRtg_SF")), // + P_F_RTG_Q2(new ScaledValuePoint("S120_P_F_RTG_Q2", "PFRtgQ2", // "Minimum power factor capability of the inverter in quadrant 2.", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "PFRtg_SF", // - new OptionsEnum[0])), // - P_F_RTG_Q3(new PointImpl(// - "S120_P_F_RTG_Q3", // - "PFRtgQ3", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PFRtg_SF")), // + P_F_RTG_Q3(new ScaledValuePoint("S120_P_F_RTG_Q3", "PFRtgQ3", // "Minimum power factor capability of the inverter in quadrant 3.", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "PFRtg_SF", // - new OptionsEnum[0])), // - P_F_RTG_Q4(new PointImpl(// - "S120_P_F_RTG_Q4", // - "PFRtgQ4", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PFRtg_SF")), // + P_F_RTG_Q4(new ScaledValuePoint("S120_P_F_RTG_Q4", "PFRtgQ4", // "Minimum power factor capability of the inverter in quadrant 4.", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "PFRtg_SF", // - new OptionsEnum[0])), // - P_F_RTG_S_F(new PointImpl(// - "S120_P_F_RTG_S_F", // - "PFRtg_SF", // - "Scale factor", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - W_H_RTG(new PointImpl(// - "S120_W_H_RTG", // - "WHRtg", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PFRtg_SF")), // + P_F_RTG_S_F(new ScaleFactorPoint("S120_P_F_RTG_S_F", "PFRtg_SF", // + "Scale factor")), // + W_H_RTG(new ScaledValuePoint("S120_W_H_RTG", "WHRtg", // "Nominal energy rating of storage device.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "WHRtg_SF", // - new OptionsEnum[0])), // - W_H_RTG_S_F(new PointImpl(// - "S120_W_H_RTG_S_F", // - "WHRtg_SF", // - "Scale factor", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - AHR_RTG(new PointImpl(// - "S120_AHR_RTG", // - "AhrRtg", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "WHRtg_SF")), // + W_H_RTG_S_F(new ScaleFactorPoint("S120_W_H_RTG_S_F", "WHRtg_SF", // + "Scale factor")), // + AHR_RTG(new ScaledValuePoint("S120_AHR_RTG", "AhrRtg", // "The usable capacity of the battery. Maximum charge minus minimum charge from a technology capability perspective (Amp-hour capacity rating).", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.AMPERE_HOURS, // - "AhrRtg_SF", // - new OptionsEnum[0])), // - AHR_RTG_S_F(new PointImpl(// - "S120_AHR_RTG_S_F", // - "AhrRtg_SF", // - "Scale factor for amp-hour rating.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - MAX_CHA_RTE(new PointImpl(// - "S120_MAX_CHA_RTE", // - "MaxChaRte", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE_HOURS, "AhrRtg_SF")), // + AHR_RTG_S_F(new ScaleFactorPoint("S120_AHR_RTG_S_F", "AhrRtg_SF", // + "Scale factor for amp-hour rating.")), // + MAX_CHA_RTE(new ScaledValuePoint("S120_MAX_CHA_RTE", "MaxChaRte", // "Maximum rate of energy transfer into the storage device.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "MaxChaRte_SF", // - new OptionsEnum[0])), // - MAX_CHA_RTE_S_F(new PointImpl(// - "S120_MAX_CHA_RTE_S_F", // - "MaxChaRte_SF", // - "Scale factor", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - MAX_DIS_CHA_RTE(new PointImpl(// - "S120_MAX_DIS_CHA_RTE", // - "MaxDisChaRte", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "MaxChaRte_SF")), // + MAX_CHA_RTE_S_F(new ScaleFactorPoint("S120_MAX_CHA_RTE_S_F", "MaxChaRte_SF", // + "Scale factor")), // + MAX_DIS_CHA_RTE(new ScaledValuePoint("S120_MAX_DIS_CHA_RTE", "MaxDisChaRte", // "Maximum rate of energy transfer out of the storage device.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "MaxDisChaRte_SF", // - new OptionsEnum[0])), // - MAX_DIS_CHA_RTE_S_F(new PointImpl(// - "S120_MAX_DIS_CHA_RTE_S_F", // - "MaxDisChaRte_SF", // - "Scale factor", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - PAD(new PointImpl(// - "S120_PAD", // - "Pad", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "MaxDisChaRte_SF")), // + MAX_DIS_CHA_RTE_S_F(new ScaleFactorPoint("S120_MAX_DIS_CHA_RTE_S_F", "MaxDisChaRte_SF", // + "Scale factor")), // + PAD(new ValuePoint("S120_PAD", "Pad", // "Pad register.", // - "", // - PointType.PAD, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // + ValuePoint.Type.PAD, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)); - protected final PointImpl impl; + private final Point point; - private S120(PointImpl impl) { - this.impl = impl; + private S120(Point point) { + this.point = point; } @Override - public PointImpl get() { - return this.impl; + public Point get() { + return this.point; } } public static enum S120_DERTyp implements OptionsEnum { UNDEFINED(-1, "Undefined"), // PV(4, "PV"), // - PV_STOR(82, "PV_STOR"); // + PV_STOR(82, "PV_STOR"); private final int value; private final String name; @@ -4279,353 +1602,103 @@ public OptionsEnum getUndefined() { } public static enum S121 implements SunSpecPoint { - W_MAX(new PointImpl(// - "S121_W_MAX", // - "WMax", // + W_MAX(new ScaledValuePoint("S121_W_MAX", "WMax", // "Setting for maximum power output. Default to WRtg.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_WRITE, // - Unit.WATT, // - "WMax_SF", // - new OptionsEnum[0])), // - V_REF(new PointImpl(// - "S121_V_REF", // - "VRef", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.WATT, "WMax_SF")), // + V_REF(new ScaledValuePoint("S121_V_REF", "VRef", // "Voltage at the PCC.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_WRITE, // - Unit.VOLT, // - "VRef_SF", // - new OptionsEnum[0])), // - V_REF_OFS(new PointImpl(// - "S121_V_REF_OFS", // - "VRefOfs", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT, "VRef_SF")), // + V_REF_OFS(new ScaledValuePoint("S121_V_REF_OFS", "VRefOfs", // "Offset from PCC to inverter.", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_WRITE, // - Unit.VOLT, // - "VRefOfs_SF", // - new OptionsEnum[0])), // - V_MAX(new PointImpl(// - "S121_V_MAX", // - "VMax", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT, "VRefOfs_SF")), // + V_MAX(new ScaledValuePoint("S121_V_MAX", "VMax", // "Setpoint for maximum voltage.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.VOLT, // - "VMinMax_SF", // - new OptionsEnum[0])), // - V_MIN(new PointImpl(// - "S121_V_MIN", // - "VMin", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT, "VMinMax_SF")), // + V_MIN(new ScaledValuePoint("S121_V_MIN", "VMin", // "Setpoint for minimum voltage.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.VOLT, // - "VMinMax_SF", // - new OptionsEnum[0])), // - V_A_MAX(new PointImpl(// - "S121_V_A_MAX", // - "VAMax", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT, "VMinMax_SF")), // + V_A_MAX(new ScaledValuePoint("S121_V_A_MAX", "VAMax", // "Setpoint for maximum apparent power. Default to VARtg.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.VOLT_AMPERE, // - "VAMax_SF", // - new OptionsEnum[0])), // - V_AR_MAX_Q1(new PointImpl(// - "S121_V_AR_MAX_Q1", // - "VArMaxQ1", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT_AMPERE, "VAMax_SF")), // + V_AR_MAX_Q1(new ScaledValuePoint("S121_V_AR_MAX_Q1", "VArMaxQ1", // "Setting for maximum reactive power in quadrant 1. Default to VArRtgQ1.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_WRITE, // - Unit.VOLT_AMPERE_REACTIVE, // - "VArMax_SF", // - new OptionsEnum[0])), // - V_AR_MAX_Q2(new PointImpl(// - "S121_V_AR_MAX_Q2", // - "VArMaxQ2", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT_AMPERE_REACTIVE, "VArMax_SF")), // + V_AR_MAX_Q2(new ScaledValuePoint("S121_V_AR_MAX_Q2", "VArMaxQ2", // "Setting for maximum reactive power in quadrant 2. Default to VArRtgQ2.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_WRITE, // - Unit.VOLT_AMPERE_REACTIVE, // - "VArMax_SF", // - new OptionsEnum[0])), // - V_AR_MAX_Q3(new PointImpl(// - "S121_V_AR_MAX_Q3", // - "VArMaxQ3", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT_AMPERE_REACTIVE, "VArMax_SF")), // + V_AR_MAX_Q3(new ScaledValuePoint("S121_V_AR_MAX_Q3", "VArMaxQ3", // "Setting for maximum reactive power in quadrant 3. Default to VArRtgQ3.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_WRITE, // - Unit.VOLT_AMPERE_REACTIVE, // - "VArMax_SF", // - new OptionsEnum[0])), // - V_AR_MAX_Q4(new PointImpl(// - "S121_V_AR_MAX_Q4", // - "VArMaxQ4", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT_AMPERE_REACTIVE, "VArMax_SF")), // + V_AR_MAX_Q4(new ScaledValuePoint("S121_V_AR_MAX_Q4", "VArMaxQ4", // "Setting for maximum reactive power in quadrant 4. Default to VArRtgQ4.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_WRITE, // - Unit.VOLT_AMPERE_REACTIVE, // - "VArMax_SF", // - new OptionsEnum[0])), // - W_GRA(new PointImpl(// - "S121_W_GRA", // - "WGra", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT_AMPERE_REACTIVE, "VArMax_SF")), // + W_GRA(new ScaledValuePoint("S121_W_GRA", "WGra", // "Default ramp rate of change of active power due to command or internal action.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.PERCENT, // - "WGra_SF", // - new OptionsEnum[0])), // - P_F_MIN_Q1(new PointImpl(// - "S121_P_F_MIN_Q1", // - "PFMinQ1", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "WGra_SF")), // + P_F_MIN_Q1(new ScaledValuePoint("S121_P_F_MIN_Q1", "PFMinQ1", // "Setpoint for minimum power factor value in quadrant 1. Default to PFRtgQ1.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - "PFMin_SF", // - new OptionsEnum[0])), // - P_F_MIN_Q2(new PointImpl(// - "S121_P_F_MIN_Q2", // - "PFMinQ2", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "PFMin_SF")), // + P_F_MIN_Q2(new ScaledValuePoint("S121_P_F_MIN_Q2", "PFMinQ2", // "Setpoint for minimum power factor value in quadrant 2. Default to PFRtgQ2.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - "PFMin_SF", // - new OptionsEnum[0])), // - P_F_MIN_Q3(new PointImpl(// - "S121_P_F_MIN_Q3", // - "PFMinQ3", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "PFMin_SF")), // + P_F_MIN_Q3(new ScaledValuePoint("S121_P_F_MIN_Q3", "PFMinQ3", // "Setpoint for minimum power factor value in quadrant 3. Default to PFRtgQ3.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - "PFMin_SF", // - new OptionsEnum[0])), // - P_F_MIN_Q4(new PointImpl(// - "S121_P_F_MIN_Q4", // - "PFMinQ4", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "PFMin_SF")), // + P_F_MIN_Q4(new ScaledValuePoint("S121_P_F_MIN_Q4", "PFMinQ4", // "Setpoint for minimum power factor value in quadrant 4. Default to PFRtgQ4.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - "PFMin_SF", // - new OptionsEnum[0])), // - V_AR_ACT(new PointImpl(// - "S121_V_AR_ACT", // - "VArAct", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "PFMin_SF")), // + V_AR_ACT(new EnumPoint("S121_V_AR_ACT", "VArAct", // "VAR action on change between charging and discharging: 1=switch 2=maintain VAR characterization.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S121_VArAct.values())), // - CLC_TOT_V_A(new PointImpl(// - "S121_CLC_TOT_V_A", // - "ClcTotVA", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S121_VArAct.values())), // + CLC_TOT_V_A(new EnumPoint("S121_CLC_TOT_V_A", "ClcTotVA", // "Calculation method for total apparent power. 1=vector 2=arithmetic.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S121_ClcTotVA.values())), // - MAX_RMP_RTE(new PointImpl(// - "S121_MAX_RMP_RTE", // - "MaxRmpRte", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S121_ClcTotVA.values())), // + MAX_RMP_RTE(new ScaledValuePoint("S121_MAX_RMP_RTE", "MaxRmpRte", // "Setpoint for maximum ramp rate as percentage of nominal maximum ramp rate. This setting will limit the rate that watts delivery to the grid can increase or decrease in response to intermittent PV generation.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.PERCENT, // - "MaxRmpRte_SF", // - new OptionsEnum[0])), // - E_C_P_NOM_HZ(new PointImpl(// - "S121_E_C_P_NOM_HZ", // - "ECPNomHz", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "MaxRmpRte_SF")), // + E_C_P_NOM_HZ(new ScaledValuePoint("S121_E_C_P_NOM_HZ", "ECPNomHz", // "Setpoint for nominal frequency at the ECP.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.HERTZ, // - "ECPNomHz_SF", // - new OptionsEnum[0])), // - CONN_PH(new PointImpl(// - "S121_CONN_PH", // - "ConnPh", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.HERTZ, "ECPNomHz_SF")), // + CONN_PH(new EnumPoint("S121_CONN_PH", "ConnPh", // "Identity of connected phase for single phase inverters. A=1 B=2 C=3.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S121_ConnPh.values())), // - W_MAX_S_F(new PointImpl(// - "S121_W_MAX_S_F", // - "WMax_SF", // - "Scale factor for real power.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - V_REF_S_F(new PointImpl(// - "S121_V_REF_S_F", // - "VRef_SF", // - "Scale factor for voltage at the PCC.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - V_REF_OFS_S_F(new PointImpl(// - "S121_V_REF_OFS_S_F", // - "VRefOfs_SF", // - "Scale factor for offset voltage.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - V_MIN_MAX_S_F(new PointImpl(// - "S121_V_MIN_MAX_S_F", // - "VMinMax_SF", // - "Scale factor for min/max voltages.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - V_A_MAX_S_F(new PointImpl(// - "S121_V_A_MAX_S_F", // - "VAMax_SF", // - "Scale factor for apparent power.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - V_AR_MAX_S_F(new PointImpl(// - "S121_V_AR_MAX_S_F", // - "VArMax_SF", // - "Scale factor for reactive power.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - W_GRA_S_F(new PointImpl(// - "S121_W_GRA_S_F", // - "WGra_SF", // - "Scale factor for default ramp rate.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - P_F_MIN_S_F(new PointImpl(// - "S121_P_F_MIN_S_F", // - "PFMin_SF", // - "Scale factor for minimum power factor.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - MAX_RMP_RTE_S_F(new PointImpl(// - "S121_MAX_RMP_RTE_S_F", // - "MaxRmpRte_SF", // - "Scale factor for maximum ramp percentage.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - E_C_P_NOM_HZ_S_F(new PointImpl(// - "S121_E_C_P_NOM_HZ_S_F", // - "ECPNomHz_SF", // - "Scale factor for nominal frequency.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // - - protected final PointImpl impl; - - private S121(PointImpl impl) { - this.impl = impl; - } - - @Override - public PointImpl get() { - return this.impl; + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S121_ConnPh.values())), // + W_MAX_S_F(new ScaleFactorPoint("S121_W_MAX_S_F", "WMax_SF", // + "Scale factor for real power.")), // + V_REF_S_F(new ScaleFactorPoint("S121_V_REF_S_F", "VRef_SF", // + "Scale factor for voltage at the PCC.")), // + V_REF_OFS_S_F(new ScaleFactorPoint("S121_V_REF_OFS_S_F", "VRefOfs_SF", // + "Scale factor for offset voltage.")), // + V_MIN_MAX_S_F(new ScaleFactorPoint("S121_V_MIN_MAX_S_F", "VMinMax_SF", // + "Scale factor for min/max voltages.")), // + V_A_MAX_S_F(new ScaleFactorPoint("S121_V_A_MAX_S_F", "VAMax_SF", // + "Scale factor for apparent power.")), // + V_AR_MAX_S_F(new ScaleFactorPoint("S121_V_AR_MAX_S_F", "VArMax_SF", // + "Scale factor for reactive power.")), // + W_GRA_S_F(new ScaleFactorPoint("S121_W_GRA_S_F", "WGra_SF", // + "Scale factor for default ramp rate.")), // + P_F_MIN_S_F(new ScaleFactorPoint("S121_P_F_MIN_S_F", "PFMin_SF", // + "Scale factor for minimum power factor.")), // + MAX_RMP_RTE_S_F(new ScaleFactorPoint("S121_MAX_RMP_RTE_S_F", "MaxRmpRte_SF", // + "Scale factor for maximum ramp percentage.")), // + E_C_P_NOM_HZ_S_F(new ScaleFactorPoint("S121_E_C_P_NOM_HZ_S_F", "ECPNomHz_SF", // + "Scale factor for nominal frequency.")); + + private final Point point; + + private S121(Point point) { + this.point = point; + } + + @Override + public Point get() { + return this.point; } } public static enum S121_VArAct implements OptionsEnum { UNDEFINED(-1, "Undefined"), // SWITCH(1, "SWITCH"), // - MAINTAIN(2, "MAINTAIN"); // + MAINTAIN(2, "MAINTAIN"); private final int value; private final String name; @@ -4654,7 +1727,7 @@ public OptionsEnum getUndefined() { public static enum S121_ClcTotVA implements OptionsEnum { UNDEFINED(-1, "Undefined"), // VECTOR(1, "VECTOR"), // - ARITHMETIC(2, "ARITHMETIC"); // + ARITHMETIC(2, "ARITHMETIC"); private final int value; private final String name; @@ -4684,7 +1757,7 @@ public static enum S121_ConnPh implements OptionsEnum { UNDEFINED(-1, "Undefined"), // A(1, "A"), // B(2, "B"), // - C(3, "C"); // + C(3, "C"); private final int value; private final String name; @@ -4711,721 +1784,285 @@ public OptionsEnum getUndefined() { } public static enum S122 implements SunSpecPoint { - P_V_CONN(new PointImpl(// - "S122_P_V_CONN", // - "PVConn", // + P_V_CONN(new BitFieldPoint("S122_P_V_CONN", "PVConn", // "PV inverter present/available status. Enumerated value.", // - "", // - PointType.BITFIELD16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S122_PVConn.values())), // - STOR_CONN(new PointImpl(// - "S122_STOR_CONN", // - "StorConn", // + BitFieldPoint.Type.BITFIELD16, true /* mandatory? */, AccessMode.READ_ONLY, S122_PVConn.values())), // + STOR_CONN(new BitFieldPoint("S122_STOR_CONN", "StorConn", // "Storage inverter present/available status. Enumerated value.", // - "", // - PointType.BITFIELD16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S122_StorConn.values())), // - E_C_P_CONN(new PointImpl(// - "S122_E_C_P_CONN", // - "ECPConn", // + BitFieldPoint.Type.BITFIELD16, true /* mandatory? */, AccessMode.READ_ONLY, S122_StorConn.values())), // + E_C_P_CONN(new BitFieldPoint("S122_E_C_P_CONN", "ECPConn", // "ECP connection status: disconnected=0 connected=1.", // - "", // - PointType.BITFIELD16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S122_ECPConn.values())), // - ACT_WH(new PointImpl(// - "S122_ACT_WH", // - "ActWh", // + BitFieldPoint.Type.BITFIELD16, true /* mandatory? */, AccessMode.READ_ONLY, S122_ECPConn.values())), // + ACT_WH(new ValuePoint("S122_ACT_WH", "ActWh", // "AC lifetime active (real) energy output.", // - "", // - PointType.ACC64, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - null, // - new OptionsEnum[0])), // - ACT_V_AH(new PointImpl(// - "S122_ACT_V_AH", // - "ActVAh", // + ValuePoint.Type.ACC64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS)), // + ACT_V_AH(new ValuePoint("S122_ACT_V_AH", "ActVAh", // "AC lifetime apparent energy output.", // - "", // - PointType.ACC64, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - null, // - new OptionsEnum[0])), // - ACT_V_ARH_Q1(new PointImpl(// - "S122_ACT_V_ARH_Q1", // - "ActVArhQ1", // + ValuePoint.Type.ACC64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS)), // + ACT_V_ARH_Q1(new ValuePoint("S122_ACT_V_ARH_Q1", "ActVArhQ1", // "AC lifetime reactive energy output in quadrant 1.", // - "", // - PointType.ACC64, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - null, // - new OptionsEnum[0])), // - ACT_V_ARH_Q2(new PointImpl(// - "S122_ACT_V_ARH_Q2", // - "ActVArhQ2", // + ValuePoint.Type.ACC64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS)), // + ACT_V_ARH_Q2(new ValuePoint("S122_ACT_V_ARH_Q2", "ActVArhQ2", // "AC lifetime reactive energy output in quadrant 2.", // - "", // - PointType.ACC64, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - null, // - new OptionsEnum[0])), // - ACT_V_ARH_Q3(new PointImpl(// - "S122_ACT_V_ARH_Q3", // - "ActVArhQ3", // + ValuePoint.Type.ACC64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS)), // + ACT_V_ARH_Q3(new ValuePoint("S122_ACT_V_ARH_Q3", "ActVArhQ3", // "AC lifetime negative energy output in quadrant 3.", // - "", // - PointType.ACC64, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - null, // - new OptionsEnum[0])), // - ACT_V_ARH_Q4(new PointImpl(// - "S122_ACT_V_ARH_Q4", // - "ActVArhQ4", // + ValuePoint.Type.ACC64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS)), // + ACT_V_ARH_Q4(new ValuePoint("S122_ACT_V_ARH_Q4", "ActVArhQ4", // "AC lifetime reactive energy output in quadrant 4.", // - "", // - PointType.ACC64, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - null, // - new OptionsEnum[0])), // - V_AR_AVAL(new PointImpl(// - "S122_V_AR_AVAL", // - "VArAval", // + ValuePoint.Type.ACC64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS)), // + V_AR_AVAL(new ScaledValuePoint("S122_V_AR_AVAL", "VArAval", // "Amount of VARs available without impacting watts output.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "VArAval_SF", // - new OptionsEnum[0])), // - V_AR_AVAL_S_F(new PointImpl(// - "S122_V_AR_AVAL_S_F", // - "VArAval_SF", // - "Scale factor for available VARs.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - W_AVAL(new PointImpl(// - "S122_W_AVAL", // - "WAval", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VArAval_SF")), // + V_AR_AVAL_S_F(new ScaleFactorPoint("S122_V_AR_AVAL_S_F", "VArAval_SF", // + "Scale factor for available VARs.")), // + W_AVAL(new ScaledValuePoint("S122_W_AVAL", "WAval", // "Amount of Watts available.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "WAval_SF", // - new OptionsEnum[0])), // - W_AVAL_S_F(new PointImpl(// - "S122_W_AVAL_S_F", // - "WAval_SF", // - "Scale factor for available Watts.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - ST_SET_LIM_MSK(new PointImpl(// - "S122_ST_SET_LIM_MSK", // - "StSetLimMsk", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "WAval_SF")), // + W_AVAL_S_F(new ScaleFactorPoint("S122_W_AVAL_S_F", "WAval_SF", // + "Scale factor for available Watts.")), // + ST_SET_LIM_MSK(new BitFieldPoint("S122_ST_SET_LIM_MSK", "StSetLimMsk", // "Bit Mask indicating setpoint limit(s) reached.", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S122_StSetLimMsk.values())), // - ST_ACT_CTL(new PointImpl(// - "S122_ST_ACT_CTL", // - "StActCtl", // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, S122_StSetLimMsk.values())), // + ST_ACT_CTL(new BitFieldPoint("S122_ST_ACT_CTL", "StActCtl", // "Bit Mask indicating which inverter controls are currently active.", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S122_StActCtl.values())), // - TM_SRC(new PointImpl(// - "S122_TM_SRC", // - "TmSrc", // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, S122_StActCtl.values())), // + TM_SRC(new ValuePoint("S122_TM_SRC", "TmSrc", // "Source of time synchronization.", // - "", // - PointType.STRING4, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TMS(new PointImpl(// - "S122_TMS", // - "Tms", // + ValuePoint.Type.STRING4, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + TMS(new ValuePoint("S122_TMS", "Tms", // "Seconds since 01-01-2000 00:00 UTC", // - "", // - PointType.UINT32, // - false, // - AccessMode.READ_ONLY, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - RT_ST(new PointImpl(// - "S122_RT_ST", // - "RtSt", // + ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.SECONDS)), // + RT_ST(new BitFieldPoint("S122_RT_ST", "RtSt", // "Bit Mask indicating active ride-through status.", // - "", // - PointType.BITFIELD16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S122_RtSt.values())), // - RIS(new PointImpl(// - "S122_RIS", // - "Ris", // + BitFieldPoint.Type.BITFIELD16, false /* mandatory? */, AccessMode.READ_ONLY, S122_RtSt.values())), // + RIS(new ScaledValuePoint("S122_RIS", "Ris", // "Isolation resistance.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "Ris_SF", // - new OptionsEnum[0])), // - RIS_S_F(new PointImpl(// - "S122_RIS_S_F", // - "Ris_SF", // - "Scale factor for isolation resistance.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // - - protected final PointImpl impl; - - private S122(PointImpl impl) { - this.impl = impl; - } - - @Override - public PointImpl get() { - return this.impl; + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "Ris_SF")), // + RIS_S_F(new ScaleFactorPoint("S122_RIS_S_F", "Ris_SF", // + "Scale factor for isolation resistance.")); + + private final Point point; + + private S122(Point point) { + this.point = point; + } + + @Override + public Point get() { + return this.point; } } - public static enum S122_PVConn implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - CONNECTED(0, "CONNECTED"), // - AVAILABLE(1, "AVAILABLE"), // - OPERATING(2, "OPERATING"), // - TEST(3, "TEST"); // + public static enum S122_PVConn implements SunSpecBitPoint { + CONNECTED(new BitPoint(0, "S122_P_V_CONN_CONNECTED", "CONNECTED")), // + AVAILABLE(new BitPoint(1, "S122_P_V_CONN_AVAILABLE", "AVAILABLE")), // + OPERATING(new BitPoint(2, "S122_P_V_CONN_OPERATING", "OPERATING")), // + TEST(new BitPoint(3, "S122_P_V_CONN_TEST", "TEST")); - private final int value; - private final String name; + private final BitPoint point; - private S122_PVConn(int value, String name) { - this.value = value; - this.name = name; + private S122_PVConn(BitPoint point) { + this.point = point; } @Override - public int getValue() { - return this.value; - } - - @Override - public String getName() { - return this.name; - } - - @Override - public OptionsEnum getUndefined() { - return UNDEFINED; + public BitPoint get() { + return this.point; } } - public static enum S122_StorConn implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - CONNECTED(0, "CONNECTED"), // - AVAILABLE(1, "AVAILABLE"), // - OPERATING(2, "OPERATING"), // - TEST(3, "TEST"); // - - private final int value; - private final String name; + public static enum S122_StorConn implements SunSpecBitPoint { + CONNECTED(new BitPoint(0, "S122_STOR_CONN_CONNECTED", "CONNECTED")), // + AVAILABLE(new BitPoint(1, "S122_STOR_CONN_AVAILABLE", "AVAILABLE")), // + OPERATING(new BitPoint(2, "S122_STOR_CONN_OPERATING", "OPERATING")), // + TEST(new BitPoint(3, "S122_STOR_CONN_TEST", "TEST")); - private S122_StorConn(int value, String name) { - this.value = value; - this.name = name; - } - - @Override - public int getValue() { - return this.value; - } + private final BitPoint point; - @Override - public String getName() { - return this.name; + private S122_StorConn(BitPoint point) { + this.point = point; } @Override - public OptionsEnum getUndefined() { - return UNDEFINED; + public BitPoint get() { + return this.point; } } - public static enum S122_ECPConn implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - CONNECTED(0, "CONNECTED"); // + public static enum S122_ECPConn implements SunSpecBitPoint { + CONNECTED(new BitPoint(0, "S122_E_C_P_CONN_CONNECTED", "CONNECTED")); - private final int value; - private final String name; + private final BitPoint point; - private S122_ECPConn(int value, String name) { - this.value = value; - this.name = name; + private S122_ECPConn(BitPoint point) { + this.point = point; } @Override - public int getValue() { - return this.value; - } - - @Override - public String getName() { - return this.name; - } - - @Override - public OptionsEnum getUndefined() { - return UNDEFINED; + public BitPoint get() { + return this.point; } } - public static enum S122_StSetLimMsk implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - W_MAX(0, "W_MAX"), // - V_A_MAX(1, "V_A_MAX"), // - V_AR_AVAL(2, "V_AR_AVAL"), // - V_AR_MAX_Q1(3, "V_AR_MAX_Q1"), // - V_AR_MAX_Q2(4, "V_AR_MAX_Q2"), // - V_AR_MAX_Q3(5, "V_AR_MAX_Q3"), // - V_AR_MAX_Q4(6, "V_AR_MAX_Q4"), // - P_F_MIN_Q1(7, "P_F_MIN_Q1"), // - P_F_MIN_Q2(8, "P_F_MIN_Q2"), // - P_F_MIN_Q3(9, "P_F_MIN_Q3"), // - P_F_MIN_Q4(10, "P_F_MIN_Q4"); // - - private final int value; - private final String name; + public static enum S122_StSetLimMsk implements SunSpecBitPoint { + W_MAX(new BitPoint(0, "S122_ST_SET_LIM_MSK_W_MAX", "WMax")), // + V_A_MAX(new BitPoint(1, "S122_ST_SET_LIM_MSK_V_A_MAX", "VAMax")), // + V_AR_AVAL(new BitPoint(2, "S122_ST_SET_LIM_MSK_V_AR_AVAL", "VArAval")), // + V_AR_MAX_Q1(new BitPoint(3, "S122_ST_SET_LIM_MSK_V_AR_MAX_Q1", "VArMaxQ1")), // + V_AR_MAX_Q2(new BitPoint(4, "S122_ST_SET_LIM_MSK_V_AR_MAX_Q2", "VArMaxQ2")), // + V_AR_MAX_Q3(new BitPoint(5, "S122_ST_SET_LIM_MSK_V_AR_MAX_Q3", "VArMaxQ3")), // + V_AR_MAX_Q4(new BitPoint(6, "S122_ST_SET_LIM_MSK_V_AR_MAX_Q4", "VArMaxQ4")), // + P_F_MIN_Q1(new BitPoint(7, "S122_ST_SET_LIM_MSK_P_F_MIN_Q1", "PFMinQ1")), // + P_F_MIN_Q2(new BitPoint(8, "S122_ST_SET_LIM_MSK_P_F_MIN_Q2", "PFMinQ2")), // + P_F_MIN_Q3(new BitPoint(9, "S122_ST_SET_LIM_MSK_P_F_MIN_Q3", "PFMinQ3")), // + P_F_MIN_Q4(new BitPoint(10, "S122_ST_SET_LIM_MSK_P_F_MIN_Q4", "PFMinQ4")); - private S122_StSetLimMsk(int value, String name) { - this.value = value; - this.name = name; - } + private final BitPoint point; - @Override - public int getValue() { - return this.value; + private S122_StSetLimMsk(BitPoint point) { + this.point = point; } @Override - public String getName() { - return this.name; - } - - @Override - public OptionsEnum getUndefined() { - return UNDEFINED; + public BitPoint get() { + return this.point; } } - public static enum S122_StActCtl implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - FIXED_W(0, "FIXED_W"), // - FIXED_V_A_R(1, "FIXED_V_A_R"), // - FIXED_P_F(2, "FIXED_P_F"), // - VOLT_V_AR(3, "VOLT_V_AR"), // - FREQ_WATT_PARAM(4, "FREQ_WATT_PARAM"), // - FREQ_WATT_CURVE(5, "FREQ_WATT_CURVE"), // - DYN_REACTIVE_CURRENT(6, "DYN_REACTIVE_CURRENT"), // - LVRT(7, "LVRT"), // - HVRT(8, "HVRT"), // - WATT_P_F(9, "WATT_P_F"), // - VOLT_WATT(10, "VOLT_WATT"), // - SCHEDULED(12, "SCHEDULED"), // - LFRT(13, "LFRT"), // - HFRT(14, "HFRT"); // + public static enum S122_StActCtl implements SunSpecBitPoint { + FIXED_W(new BitPoint(0, "S122_ST_ACT_CTL_FIXED_W", "FixedW")), // + FIXED_V_A_R(new BitPoint(1, "S122_ST_ACT_CTL_FIXED_V_A_R", "FixedVAR")), // + FIXED_P_F(new BitPoint(2, "S122_ST_ACT_CTL_FIXED_P_F", "FixedPF")), // + VOLT_V_AR(new BitPoint(3, "S122_ST_ACT_CTL_VOLT_V_AR", "Volt-VAr")), // + FREQ_WATT_PARAM(new BitPoint(4, "S122_ST_ACT_CTL_FREQ_WATT_PARAM", "Freq-Watt-Param")), // + FREQ_WATT_CURVE(new BitPoint(5, "S122_ST_ACT_CTL_FREQ_WATT_CURVE", "Freq-Watt-Curve")), // + DYN_REACTIVE_CURRENT(new BitPoint(6, "S122_ST_ACT_CTL_DYN_REACTIVE_CURRENT", "Dyn-Reactive-Current")), // + LVRT(new BitPoint(7, "S122_ST_ACT_CTL_LVRT", "LVRT")), // + HVRT(new BitPoint(8, "S122_ST_ACT_CTL_HVRT", "HVRT")), // + WATT_P_F(new BitPoint(9, "S122_ST_ACT_CTL_WATT_P_F", "Watt-PF")), // + VOLT_WATT(new BitPoint(10, "S122_ST_ACT_CTL_VOLT_WATT", "Volt-Watt")), // + SCHEDULED(new BitPoint(12, "S122_ST_ACT_CTL_SCHEDULED", "Scheduled")), // + LFRT(new BitPoint(13, "S122_ST_ACT_CTL_LFRT", "LFRT")), // + HFRT(new BitPoint(14, "S122_ST_ACT_CTL_HFRT", "HFRT")); - private final int value; - private final String name; + private final BitPoint point; - private S122_StActCtl(int value, String name) { - this.value = value; - this.name = name; + private S122_StActCtl(BitPoint point) { + this.point = point; } @Override - public int getValue() { - return this.value; - } - - @Override - public String getName() { - return this.name; - } - - @Override - public OptionsEnum getUndefined() { - return UNDEFINED; + public BitPoint get() { + return this.point; } } - public static enum S122_RtSt implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - LVRT_ACTIVE(0, "LVRT_ACTIVE"), // - HVRT_ACTIVE(1, "HVRT_ACTIVE"), // - LFRT_ACTIVE(2, "LFRT_ACTIVE"), // - HFRT_ACTIVE(3, "HFRT_ACTIVE"); // + public static enum S122_RtSt implements SunSpecBitPoint { + LVRT_ACTIVE(new BitPoint(0, "S122_RT_ST_LVRT_ACTIVE", "Lvrt Active")), // + HVRT_ACTIVE(new BitPoint(1, "S122_RT_ST_HVRT_ACTIVE", "Hvrt Active")), // + LFRT_ACTIVE(new BitPoint(2, "S122_RT_ST_LFRT_ACTIVE", "Lfrt Active")), // + HFRT_ACTIVE(new BitPoint(3, "S122_RT_ST_HFRT_ACTIVE", "Hfrt Active")); - private final int value; - private final String name; + private final BitPoint point; - private S122_RtSt(int value, String name) { - this.value = value; - this.name = name; + private S122_RtSt(BitPoint point) { + this.point = point; } @Override - public int getValue() { - return this.value; - } - - @Override - public String getName() { - return this.name; - } - - @Override - public OptionsEnum getUndefined() { - return UNDEFINED; + public BitPoint get() { + return this.point; } } public static enum S123 implements SunSpecPoint { - CONN_WIN_TMS(new PointImpl(// - "S123_CONN_WIN_TMS", // - "Conn_WinTms", // + CONN_WIN_TMS(new ValuePoint("S123_CONN_WIN_TMS", "Conn_WinTms", // "Time window for connect/disconnect.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - CONN_RVRT_TMS(new PointImpl(// - "S123_CONN_RVRT_TMS", // - "Conn_RvrtTms", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + CONN_RVRT_TMS(new ValuePoint("S123_CONN_RVRT_TMS", "Conn_RvrtTms", // "Timeout period for connect/disconnect.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - CONN(new PointImpl(// - "S123_CONN", // - "Conn", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + CONN(new EnumPoint("S123_CONN", "Conn", // "Enumerated valued. Connection control.", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S123_Conn.values())), // - W_MAX_LIM_PCT(new PointImpl(// - "S123_W_MAX_LIM_PCT", // - "WMaxLimPct", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_WRITE, S123_Conn.values())), // + W_MAX_LIM_PCT(new ScaledValuePoint("S123_W_MAX_LIM_PCT", "WMaxLimPct", // "Set power output to specified level.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_WRITE, // - Unit.PERCENT, // - "WMaxLimPct_SF", // - new OptionsEnum[0])), // - W_MAX_LIM_PCT_WIN_TMS(new PointImpl(// - "S123_W_MAX_LIM_PCT_WIN_TMS", // - "WMaxLimPct_WinTms", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "WMaxLimPct_SF")), // + W_MAX_LIM_PCT_WIN_TMS(new ValuePoint("S123_W_MAX_LIM_PCT_WIN_TMS", "WMaxLimPct_WinTms", // "Time window for power limit change.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - W_MAX_LIM_PCT_RVRT_TMS(new PointImpl(// - "S123_W_MAX_LIM_PCT_RVRT_TMS", // - "WMaxLimPct_RvrtTms", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + W_MAX_LIM_PCT_RVRT_TMS(new ValuePoint("S123_W_MAX_LIM_PCT_RVRT_TMS", "WMaxLimPct_RvrtTms", // "Timeout period for power limit.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - W_MAX_LIM_PCT_RMP_TMS(new PointImpl(// - "S123_W_MAX_LIM_PCT_RMP_TMS", // - "WMaxLimPct_RmpTms", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + W_MAX_LIM_PCT_RMP_TMS(new ValuePoint("S123_W_MAX_LIM_PCT_RMP_TMS", "WMaxLimPct_RmpTms", // "Ramp time for moving from current setpoint to new setpoint.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - W_MAX_LIM_ENA(new PointImpl(// - "S123_W_MAX_LIM_ENA", // - "WMaxLim_Ena", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + W_MAX_LIM_ENA(new EnumPoint("S123_W_MAX_LIM_ENA", "WMaxLim_Ena", // "Enumerated valued. Throttle enable/disable control.", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S123_WMaxLim_Ena.values())), // - OUT_P_F_SET(new PointImpl(// - "S123_OUT_P_F_SET", // - "OutPFSet", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_WRITE, S123_WMaxLim_Ena.values())), // + OUT_P_F_SET(new ScaledValuePoint("S123_OUT_P_F_SET", "OutPFSet", // "Set power factor to specific value - cosine of angle.", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - "OutPFSet_SF", // - new OptionsEnum[0])), // - OUT_P_F_SET_WIN_TMS(new PointImpl(// - "S123_OUT_P_F_SET_WIN_TMS", // - "OutPFSet_WinTms", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "OutPFSet_SF")), // + OUT_P_F_SET_WIN_TMS(new ValuePoint("S123_OUT_P_F_SET_WIN_TMS", "OutPFSet_WinTms", // "Time window for power factor change.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - OUT_P_F_SET_RVRT_TMS(new PointImpl(// - "S123_OUT_P_F_SET_RVRT_TMS", // - "OutPFSet_RvrtTms", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + OUT_P_F_SET_RVRT_TMS(new ValuePoint("S123_OUT_P_F_SET_RVRT_TMS", "OutPFSet_RvrtTms", // "Timeout period for power factor.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - OUT_P_F_SET_RMP_TMS(new PointImpl(// - "S123_OUT_P_F_SET_RMP_TMS", // - "OutPFSet_RmpTms", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + OUT_P_F_SET_RMP_TMS(new ValuePoint("S123_OUT_P_F_SET_RMP_TMS", "OutPFSet_RmpTms", // "Ramp time for moving from current setpoint to new setpoint.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - OUT_P_F_SET_ENA(new PointImpl(// - "S123_OUT_P_F_SET_ENA", // - "OutPFSet_Ena", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + OUT_P_F_SET_ENA(new EnumPoint("S123_OUT_P_F_SET_ENA", "OutPFSet_Ena", // "Enumerated valued. Fixed power factor enable/disable control.", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S123_OutPFSet_Ena.values())), // - V_AR_W_MAX_PCT(new PointImpl(// - "S123_V_AR_W_MAX_PCT", // - "VArWMaxPct", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_WRITE, S123_OutPFSet_Ena.values())), // + V_AR_W_MAX_PCT(new ScaledValuePoint("S123_V_AR_W_MAX_PCT", "VArWMaxPct", // "Reactive power in percent of WMax.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_WRITE, // - Unit.PERCENT, // - "VArPct_SF", // - new OptionsEnum[0])), // - V_AR_MAX_PCT(new PointImpl(// - "S123_V_AR_MAX_PCT", // - "VArMaxPct", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "VArPct_SF")), // + V_AR_MAX_PCT(new ScaledValuePoint("S123_V_AR_MAX_PCT", "VArMaxPct", // "Reactive power in percent of VArMax.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_WRITE, // - Unit.PERCENT, // - "VArPct_SF", // - new OptionsEnum[0])), // - V_AR_AVAL_PCT(new PointImpl(// - "S123_V_AR_AVAL_PCT", // - "VArAvalPct", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "VArPct_SF")), // + V_AR_AVAL_PCT(new ScaledValuePoint("S123_V_AR_AVAL_PCT", "VArAvalPct", // "Reactive power in percent of VArAval.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_WRITE, // - Unit.PERCENT, // - "VArPct_SF", // - new OptionsEnum[0])), // - V_AR_PCT_WIN_TMS(new PointImpl(// - "S123_V_AR_PCT_WIN_TMS", // - "VArPct_WinTms", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "VArPct_SF")), // + V_AR_PCT_WIN_TMS(new ValuePoint("S123_V_AR_PCT_WIN_TMS", "VArPct_WinTms", // "Time window for VAR limit change.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - V_AR_PCT_RVRT_TMS(new PointImpl(// - "S123_V_AR_PCT_RVRT_TMS", // - "VArPct_RvrtTms", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + V_AR_PCT_RVRT_TMS(new ValuePoint("S123_V_AR_PCT_RVRT_TMS", "VArPct_RvrtTms", // "Timeout period for VAR limit.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - V_AR_PCT_RMP_TMS(new PointImpl(// - "S123_V_AR_PCT_RMP_TMS", // - "VArPct_RmpTms", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + V_AR_PCT_RMP_TMS(new ValuePoint("S123_V_AR_PCT_RMP_TMS", "VArPct_RmpTms", // "Ramp time for moving from current setpoint to new setpoint.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - V_AR_PCT_MOD(new PointImpl(// - "S123_V_AR_PCT_MOD", // - "VArPct_Mod", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + V_AR_PCT_MOD(new EnumPoint("S123_V_AR_PCT_MOD", "VArPct_Mod", // "Enumerated value. VAR percent limit mode.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S123_VArPct_Mod.values())), // - V_AR_PCT_ENA(new PointImpl(// - "S123_V_AR_PCT_ENA", // - "VArPct_Ena", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S123_VArPct_Mod.values())), // + V_AR_PCT_ENA(new EnumPoint("S123_V_AR_PCT_ENA", "VArPct_Ena", // "Enumerated valued. Percent limit VAr enable/disable control.", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S123_VArPct_Ena.values())), // - W_MAX_LIM_PCT_S_F(new PointImpl(// - "S123_W_MAX_LIM_PCT_S_F", // - "WMaxLimPct_SF", // - "Scale factor for power output percent.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - OUT_P_F_SET_S_F(new PointImpl(// - "S123_OUT_P_F_SET_S_F", // - "OutPFSet_SF", // - "Scale factor for power factor.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - V_AR_PCT_S_F(new PointImpl(// - "S123_V_AR_PCT_S_F", // - "VArPct_SF", // - "Scale factor for reactive power percent.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // - - protected final PointImpl impl; - - private S123(PointImpl impl) { - this.impl = impl; - } - - @Override - public PointImpl get() { - return this.impl; + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_WRITE, S123_VArPct_Ena.values())), // + W_MAX_LIM_PCT_S_F(new ScaleFactorPoint("S123_W_MAX_LIM_PCT_S_F", "WMaxLimPct_SF", // + "Scale factor for power output percent.")), // + OUT_P_F_SET_S_F(new ScaleFactorPoint("S123_OUT_P_F_SET_S_F", "OutPFSet_SF", // + "Scale factor for power factor.")), // + V_AR_PCT_S_F(new ScaleFactorPoint("S123_V_AR_PCT_S_F", "VArPct_SF", // + "Scale factor for reactive power percent.")); + + private final Point point; + + private S123(Point point) { + this.point = point; + } + + @Override + public Point get() { + return this.point; } } public static enum S123_Conn implements OptionsEnum { UNDEFINED(-1, "Undefined"), // DISCONNECT(0, "DISCONNECT"), // - CONNECT(1, "CONNECT"); // + CONNECT(1, "CONNECT"); private final int value; private final String name; @@ -5454,7 +2091,7 @@ public OptionsEnum getUndefined() { public static enum S123_WMaxLim_Ena implements OptionsEnum { UNDEFINED(-1, "Undefined"), // DISABLED(0, "DISABLED"), // - ENABLED(1, "ENABLED"); // + ENABLED(1, "ENABLED"); private final int value; private final String name; @@ -5483,7 +2120,7 @@ public OptionsEnum getUndefined() { public static enum S123_OutPFSet_Ena implements OptionsEnum { UNDEFINED(-1, "Undefined"), // DISABLED(0, "DISABLED"), // - ENABLED(1, "ENABLED"); // + ENABLED(1, "ENABLED"); private final int value; private final String name; @@ -5514,7 +2151,7 @@ public static enum S123_VArPct_Mod implements OptionsEnum { NONE(0, "NONE"), // W_MAX(1, "W_MAX"), // V_AR_MAX(2, "V_AR_MAX"), // - V_AR_AVAL(3, "V_AR_AVAL"); // + V_AR_AVAL(3, "V_AR_AVAL"); private final int value; private final String name; @@ -5543,7 +2180,7 @@ public OptionsEnum getUndefined() { public static enum S123_VArPct_Ena implements OptionsEnum { UNDEFINED(-1, "Undefined"), // DISABLED(0, "DISABLED"), // - ENABLED(1, "ENABLED"); // + ENABLED(1, "ENABLED"); private final int value; private final String name; @@ -5570,309 +2207,95 @@ public OptionsEnum getUndefined() { } public static enum S124 implements SunSpecPoint { - W_CHA_MAX(new PointImpl(// - "S124_W_CHA_MAX", // - "WChaMax", // + W_CHA_MAX(new ScaledValuePoint("S124_W_CHA_MAX", "WChaMax", // "Setpoint for maximum charge.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_WRITE, // - Unit.WATT, // - "WChaMax_SF", // - new OptionsEnum[0])), // - W_CHA_GRA(new PointImpl(// - "S124_W_CHA_GRA", // - "WChaGra", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.WATT, "WChaMax_SF")), // + W_CHA_GRA(new ScaledValuePoint("S124_W_CHA_GRA", "WChaGra", // "Setpoint for maximum charging rate. Default is MaxChaRte.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_WRITE, // - Unit.PERCENT, // - "WChaDisChaGra_SF", // - new OptionsEnum[0])), // - W_DIS_CHA_GRA(new PointImpl(// - "S124_W_DIS_CHA_GRA", // - "WDisChaGra", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "WChaDisChaGra_SF")), // + W_DIS_CHA_GRA(new ScaledValuePoint("S124_W_DIS_CHA_GRA", "WDisChaGra", // "Setpoint for maximum discharge rate. Default is MaxDisChaRte.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_WRITE, // - Unit.PERCENT, // - "WChaDisChaGra_SF", // - new OptionsEnum[0])), // - STOR_CTL_MOD(new PointImpl(// - "S124_STOR_CTL_MOD", // - "StorCtl_Mod", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "WChaDisChaGra_SF")), // + STOR_CTL_MOD(new BitFieldPoint("S124_STOR_CTL_MOD", "StorCtl_Mod", // "Activate hold/discharge/charge storage control mode. Bitfield value.", // - "", // - PointType.BITFIELD16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S124_StorCtl_Mod.values())), // - V_A_CHA_MAX(new PointImpl(// - "S124_V_A_CHA_MAX", // - "VAChaMax", // + BitFieldPoint.Type.BITFIELD16, true /* mandatory? */, AccessMode.READ_WRITE, S124_StorCtl_Mod.values())), // + V_A_CHA_MAX(new ScaledValuePoint("S124_V_A_CHA_MAX", "VAChaMax", // "Setpoint for maximum charging VA.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.VOLT_AMPERE, // - "VAChaMax_SF", // - new OptionsEnum[0])), // - MIN_RSV_PCT(new PointImpl(// - "S124_MIN_RSV_PCT", // - "MinRsvPct", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT_AMPERE, "VAChaMax_SF")), // + MIN_RSV_PCT(new ScaledValuePoint("S124_MIN_RSV_PCT", "MinRsvPct", // "Setpoint for minimum reserve for storage as a percentage of the nominal maximum storage.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.PERCENT, // - "MinRsvPct_SF", // - new OptionsEnum[0])), // - CHA_STATE(new PointImpl(// - "S124_CHA_STATE", // - "ChaState", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "MinRsvPct_SF")), // + CHA_STATE(new ScaledValuePoint("S124_CHA_STATE", "ChaState", // "Currently available energy as a percent of the capacity rating.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.PERCENT, // - "ChaState_SF", // - new OptionsEnum[0])), // - STOR_AVAL(new PointImpl(// - "S124_STOR_AVAL", // - "StorAval", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.PERCENT, "ChaState_SF")), // + STOR_AVAL(new ScaledValuePoint("S124_STOR_AVAL", "StorAval", // "State of charge (ChaState) minus storage reserve (MinRsvPct) times capacity rating (AhrRtg).", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.AMPERE_HOURS, // - "StorAval_SF", // - new OptionsEnum[0])), // - IN_BAT_V(new PointImpl(// - "S124_IN_BAT_V", // - "InBatV", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE_HOURS, "StorAval_SF")), // + IN_BAT_V(new ScaledValuePoint("S124_IN_BAT_V", "InBatV", // "Internal battery voltage.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "InBatV_SF", // - new OptionsEnum[0])), // - CHA_ST(new PointImpl(// - "S124_CHA_ST", // - "ChaSt", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "InBatV_SF")), // + CHA_ST(new EnumPoint("S124_CHA_ST", "ChaSt", // "Charge status of storage device. Enumerated value.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S124_ChaSt.values())), // - OUT_W_RTE(new PointImpl(// - "S124_OUT_W_RTE", // - "OutWRte", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, S124_ChaSt.values())), // + OUT_W_RTE(new ScaledValuePoint("S124_OUT_W_RTE", "OutWRte", // "Percent of max discharge rate.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_WRITE, // - Unit.PERCENT, // - "InOutWRte_SF", // - new OptionsEnum[0])), // - IN_W_RTE(new PointImpl(// - "S124_IN_W_RTE", // - "InWRte", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "InOutWRte_SF")), // + IN_W_RTE(new ScaledValuePoint("S124_IN_W_RTE", "InWRte", // "Percent of max charging rate.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_WRITE, // - Unit.PERCENT, // - "InOutWRte_SF", // - new OptionsEnum[0])), // - IN_OUT_W_RTE_WIN_TMS(new PointImpl(// - "S124_IN_OUT_W_RTE_WIN_TMS", // - "InOutWRte_WinTms", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "InOutWRte_SF")), // + IN_OUT_W_RTE_WIN_TMS(new ValuePoint("S124_IN_OUT_W_RTE_WIN_TMS", "InOutWRte_WinTms", // "Time window for charge/discharge rate change.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - IN_OUT_W_RTE_RVRT_TMS(new PointImpl(// - "S124_IN_OUT_W_RTE_RVRT_TMS", // - "InOutWRte_RvrtTms", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + IN_OUT_W_RTE_RVRT_TMS(new ValuePoint("S124_IN_OUT_W_RTE_RVRT_TMS", "InOutWRte_RvrtTms", // "Timeout period for charge/discharge rate.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - IN_OUT_W_RTE_RMP_TMS(new PointImpl(// - "S124_IN_OUT_W_RTE_RMP_TMS", // - "InOutWRte_RmpTms", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + IN_OUT_W_RTE_RMP_TMS(new ValuePoint("S124_IN_OUT_W_RTE_RMP_TMS", "InOutWRte_RmpTms", // "Ramp time for moving from current setpoint to new setpoint.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - CHA_GRI_SET(new PointImpl(// - "S124_CHA_GRI_SET", // - "", // - "", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S124_ChaGriSet.values())), // - W_CHA_MAX_S_F(new PointImpl(// - "S124_W_CHA_MAX_S_F", // - "WChaMax_SF", // - "Scale factor for maximum charge.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - W_CHA_DIS_CHA_GRA_S_F(new PointImpl(// - "S124_W_CHA_DIS_CHA_GRA_S_F", // - "WChaDisChaGra_SF", // - "Scale factor for maximum charge and discharge rate.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - V_A_CHA_MAX_S_F(new PointImpl(// - "S124_V_A_CHA_MAX_S_F", // - "VAChaMax_SF", // - "Scale factor for maximum charging VA.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - MIN_RSV_PCT_S_F(new PointImpl(// - "S124_MIN_RSV_PCT_S_F", // - "MinRsvPct_SF", // - "Scale factor for minimum reserve percentage.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - CHA_STATE_S_F(new PointImpl(// - "S124_CHA_STATE_S_F", // - "ChaState_SF", // - "Scale factor for available energy percent.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - STOR_AVAL_S_F(new PointImpl(// - "S124_STOR_AVAL_S_F", // - "StorAval_SF", // - "Scale factor for state of charge.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - IN_BAT_V_S_F(new PointImpl(// - "S124_IN_BAT_V_S_F", // - "InBatV_SF", // - "Scale factor for battery voltage.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - IN_OUT_W_RTE_S_F(new PointImpl(// - "S124_IN_OUT_W_RTE_S_F", // - "InOutWRte_SF", // - "Scale factor for percent charge/discharge rate.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // - - protected final PointImpl impl; - - private S124(PointImpl impl) { - this.impl = impl; - } - - @Override - public PointImpl get() { - return this.impl; - } - } - - public static enum S124_StorCtl_Mod implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - CHARGE(0, "CHARGE"), // - DI_S_C_H_A_R_G_E(1, "DI_S_C_H_A_R_G_E"); // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + CHA_GRI_SET(new EnumPoint("S124_CHA_GRI_SET", "", "", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S124_ChaGriSet.values())), // + W_CHA_MAX_S_F(new ScaleFactorPoint("S124_W_CHA_MAX_S_F", "WChaMax_SF", // + "Scale factor for maximum charge.")), // + W_CHA_DIS_CHA_GRA_S_F(new ScaleFactorPoint("S124_W_CHA_DIS_CHA_GRA_S_F", "WChaDisChaGra_SF", // + "Scale factor for maximum charge and discharge rate.")), // + V_A_CHA_MAX_S_F(new ScaleFactorPoint("S124_V_A_CHA_MAX_S_F", "VAChaMax_SF", // + "Scale factor for maximum charging VA.")), // + MIN_RSV_PCT_S_F(new ScaleFactorPoint("S124_MIN_RSV_PCT_S_F", "MinRsvPct_SF", // + "Scale factor for minimum reserve percentage.")), // + CHA_STATE_S_F(new ScaleFactorPoint("S124_CHA_STATE_S_F", "ChaState_SF", // + "Scale factor for available energy percent.")), // + STOR_AVAL_S_F(new ScaleFactorPoint("S124_STOR_AVAL_S_F", "StorAval_SF", // + "Scale factor for state of charge.")), // + IN_BAT_V_S_F(new ScaleFactorPoint("S124_IN_BAT_V_S_F", "InBatV_SF", // + "Scale factor for battery voltage.")), // + IN_OUT_W_RTE_S_F(new ScaleFactorPoint("S124_IN_OUT_W_RTE_S_F", "InOutWRte_SF", // + "Scale factor for percent charge/discharge rate.")); - private final int value; - private final String name; + private final Point point; - private S124_StorCtl_Mod(int value, String name) { - this.value = value; - this.name = name; + private S124(Point point) { + this.point = point; } @Override - public int getValue() { - return this.value; + public Point get() { + return this.point; } + } - @Override - public String getName() { - return this.name; + public static enum S124_StorCtl_Mod implements SunSpecBitPoint { + CHARGE(new BitPoint(0, "S124_STOR_CTL_MOD_CHARGE", "CHARGE")), // + DISCHARGE(new BitPoint(1, "S124_STOR_CTL_MOD_DISCHARGE", "DISCHARGE")); + + private final BitPoint point; + + private S124_StorCtl_Mod(BitPoint point) { + this.point = point; } @Override - public OptionsEnum getUndefined() { - return UNDEFINED; + public BitPoint get() { + return this.point; } } @@ -5884,7 +2307,7 @@ public static enum S124_ChaSt implements OptionsEnum { CHARGING(4, "CHARGING"), // FULL(5, "FULL"), // HOLDING(6, "HOLDING"), // - TESTING(7, "TESTING"); // + TESTING(7, "TESTING"); private final int value; private final String name; @@ -5913,7 +2336,7 @@ public OptionsEnum getUndefined() { public static enum S124_ChaGriSet implements OptionsEnum { UNDEFINED(-1, "Undefined"), // PV(0, "PV"), // - GRID(1, "GRID"); // + GRID(1, "GRID"); private final int value; private final String name; @@ -5940,132 +2363,53 @@ public OptionsEnum getUndefined() { } public static enum S125 implements SunSpecPoint { - MOD_ENA(new PointImpl(// - "S125_MOD_ENA", // - "ModEna", // + MOD_ENA(new BitFieldPoint("S125_MOD_ENA", "ModEna", // "Is price-based charge/discharge mode active?", // - "", // - PointType.BITFIELD16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S125_ModEna.values())), // - SIG_TYPE(new PointImpl(// - "S125_SIG_TYPE", // - "SigType", // + BitFieldPoint.Type.BITFIELD16, true /* mandatory? */, AccessMode.READ_WRITE, S125_ModEna.values())), // + SIG_TYPE(new EnumPoint("S125_SIG_TYPE", "SigType", // "Meaning of the pricing signal. When a Price schedule is used, type must match the schedule range variable description.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S125_SigType.values())), // - SIG(new PointImpl(// - "S125_SIG", // - "Sig", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S125_SigType.values())), // + SIG(new ScaledValuePoint("S125_SIG", "Sig", // "Utility/ESP specific pricing signal. Content depends on pricing signal type. When H/M/L type is specified. Low=0; Med=1; High=2.", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - "Sig_SF", // - new OptionsEnum[0])), // - WIN_TMS(new PointImpl(// - "S125_WIN_TMS", // - "WinTms", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "Sig_SF")), // + WIN_TMS(new ValuePoint("S125_WIN_TMS", "WinTms", // "Time window for charge/discharge pricing change.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - RVT_TMS(new PointImpl(// - "S125_RVT_TMS", // - "RvtTms", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + RVT_TMS(new ValuePoint("S125_RVT_TMS", "RvtTms", // "Timeout period for charge/discharge pricing change.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - RMP_TMS(new PointImpl(// - "S125_RMP_TMS", // - "RmpTms", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + RMP_TMS(new ValuePoint("S125_RMP_TMS", "RmpTms", // "Ramp time for moving from current charge or discharge level to new level.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - SIG_S_F(new PointImpl(// - "S125_SIG_S_F", // - "Sig_SF", // - "Pricing signal scale factor.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - PAD(new PointImpl(// - "S125_PAD", // - "", // - "", // - "", // - PointType.PAD, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // - - protected final PointImpl impl; - - private S125(PointImpl impl) { - this.impl = impl; - } - - @Override - public PointImpl get() { - return this.impl; - } - } + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + SIG_S_F(new ScaleFactorPoint("S125_SIG_S_F", "Sig_SF", // + "Pricing signal scale factor.")), // + PAD(new ValuePoint("S125_PAD", "", "", // + ValuePoint.Type.PAD, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)); - public static enum S125_ModEna implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - ENABLE(0, "ENABLE"); // - - private final int value; - private final String name; + private final Point point; - private S125_ModEna(int value, String name) { - this.value = value; - this.name = name; + private S125(Point point) { + this.point = point; } @Override - public int getValue() { - return this.value; + public Point get() { + return this.point; } + } - @Override - public String getName() { - return this.name; + public static enum S125_ModEna implements SunSpecBitPoint { + ENABLE(new BitPoint(0, "S125_MOD_ENA_ENABLE", "ENABLE")); + + private final BitPoint point; + + private S125_ModEna(BitPoint point) { + this.point = point; } @Override - public OptionsEnum getUndefined() { - return UNDEFINED; + public BitPoint get() { + return this.point; } } @@ -6075,7 +2419,7 @@ public static enum S125_SigType implements OptionsEnum { ABSOLUTE(1, "ABSOLUTE"), // RELATIVE(2, "RELATIVE"), // MULTIPLIER(3, "MULTIPLIER"), // - LEVEL(4, "LEVEL"); // + LEVEL(4, "LEVEL"); private final int value; private final String name; @@ -6102,357 +2446,132 @@ public OptionsEnum getUndefined() { } public static enum S127 implements SunSpecPoint { - W_GRA(new PointImpl(// - "S127_W_GRA", // - "WGra", // + W_GRA(new ScaledValuePoint("S127_W_GRA", "WGra", // "The slope of the reduction in the maximum allowed watts output as a function of frequency.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_WRITE, // - Unit.PERCENT, // - "WGra_SF", // - new OptionsEnum[0])), // - HZ_STR(new PointImpl(// - "S127_HZ_STR", // - "HzStr", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "WGra_SF")), // + HZ_STR(new ScaledValuePoint("S127_HZ_STR", "HzStr", // "The frequency deviation from nominal frequency (ECPNomHz) at which a snapshot of the instantaneous power output is taken to act as the CAPPED power level (PM) and above which reduction in power output occurs.", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_WRITE, // - Unit.HERTZ, // - "HzStrStop_SF", // - new OptionsEnum[0])), // - HZ_STOP(new PointImpl(// - "S127_HZ_STOP", // - "HzStop", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.HERTZ, "HzStrStop_SF")), // + HZ_STOP(new ScaledValuePoint("S127_HZ_STOP", "HzStop", // "The frequency deviation from nominal frequency (ECPNomHz) at which curtailed power output may return to normal and the cap on the power level value is removed.", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_WRITE, // - Unit.HERTZ, // - "HzStrStop_SF", // - new OptionsEnum[0])), // - HYS_ENA(new PointImpl(// - "S127_HYS_ENA", // - "HysEna", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.HERTZ, "HzStrStop_SF")), // + HYS_ENA(new BitFieldPoint("S127_HYS_ENA", "HysEna", // "Enable hysteresis", // - "", // - PointType.BITFIELD16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S127_HysEna.values())), // - MOD_ENA(new PointImpl(// - "S127_MOD_ENA", // - "ModEna", // + BitFieldPoint.Type.BITFIELD16, true /* mandatory? */, AccessMode.READ_WRITE, S127_HysEna.values())), // + MOD_ENA(new BitFieldPoint("S127_MOD_ENA", "ModEna", // "Is Parameterized Frequency-Watt control active.", // - "", // - PointType.BITFIELD16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S127_ModEna.values())), // - HZ_STOP_W_GRA(new PointImpl(// - "S127_HZ_STOP_W_GRA", // - "HzStopWGra", // + BitFieldPoint.Type.BITFIELD16, true /* mandatory? */, AccessMode.READ_WRITE, S127_ModEna.values())), // + HZ_STOP_W_GRA(new ScaledValuePoint("S127_HZ_STOP_W_GRA", "HzStopWGra", // "The maximum time-based rate of change at which power output returns to normal after having been capped by an over frequency event.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.PERCENT, // - "RmpIncDec_SF", // - new OptionsEnum[0])), // - W_GRA_S_F(new PointImpl(// - "S127_W_GRA_S_F", // - "WGra_SF", // - "Scale factor for output gradient.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - HZ_STR_STOP_S_F(new PointImpl(// - "S127_HZ_STR_STOP_S_F", // - "HzStrStop_SF", // - "Scale factor for frequency deviations.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - RMP_INC_DEC_S_F(new PointImpl(// - "S127_RMP_INC_DEC_S_F", // - "RmpIncDec_SF", // - "Scale factor for increment and decrement ramps.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - PAD(new PointImpl(// - "S127_PAD", // - "", // - "", // - "", // - PointType.PAD, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // - - protected final PointImpl impl; - - private S127(PointImpl impl) { - this.impl = impl; - } - - @Override - public PointImpl get() { - return this.impl; - } - } - - public static enum S127_HysEna implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - ENABLED(0, "ENABLED"); // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "RmpIncDec_SF")), // + W_GRA_S_F(new ScaleFactorPoint("S127_W_GRA_S_F", "WGra_SF", // + "Scale factor for output gradient.")), // + HZ_STR_STOP_S_F(new ScaleFactorPoint("S127_HZ_STR_STOP_S_F", "HzStrStop_SF", // + "Scale factor for frequency deviations.")), // + RMP_INC_DEC_S_F(new ScaleFactorPoint("S127_RMP_INC_DEC_S_F", "RmpIncDec_SF", // + "Scale factor for increment and decrement ramps.")), // + PAD(new ValuePoint("S127_PAD", "", "", // + ValuePoint.Type.PAD, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)); - private final int value; - private final String name; + private final Point point; - private S127_HysEna(int value, String name) { - this.value = value; - this.name = name; + private S127(Point point) { + this.point = point; } @Override - public int getValue() { - return this.value; - } - - @Override - public String getName() { - return this.name; - } - - @Override - public OptionsEnum getUndefined() { - return UNDEFINED; + public Point get() { + return this.point; } } - public static enum S127_ModEna implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - ENABLED(0, "ENABLED"); // + public static enum S127_HysEna implements SunSpecBitPoint { + ENABLED(new BitPoint(0, "S127_HYS_ENA_ENABLED", "ENABLED")); - private final int value; - private final String name; + private final BitPoint point; - private S127_ModEna(int value, String name) { - this.value = value; - this.name = name; + private S127_HysEna(BitPoint point) { + this.point = point; } @Override - public int getValue() { - return this.value; + public BitPoint get() { + return this.point; } + } - @Override - public String getName() { - return this.name; + public static enum S127_ModEna implements SunSpecBitPoint { + ENABLED(new BitPoint(0, "S127_MOD_ENA_ENABLED", "ENABLED")); + + private final BitPoint point; + + private S127_ModEna(BitPoint point) { + this.point = point; } @Override - public OptionsEnum getUndefined() { - return UNDEFINED; + public BitPoint get() { + return this.point; } } public static enum S128 implements SunSpecPoint { - AR_GRA_MOD(new PointImpl(// - "S128_AR_GRA_MOD", // - "ArGraMod", // + AR_GRA_MOD(new EnumPoint("S128_AR_GRA_MOD", "ArGraMod", // "Indicates if gradients trend toward zero at the edges of the deadband or trend toward zero at the center of the deadband.", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S128_ArGraMod.values())), // - AR_GRA_SAG(new PointImpl(// - "S128_AR_GRA_SAG", // - "ArGraSag", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_WRITE, S128_ArGraMod.values())), // + AR_GRA_SAG(new ScaledValuePoint("S128_AR_GRA_SAG", "ArGraSag", // "The gradient used to increase capacitive dynamic current. A value of 0 indicates no additional reactive current support.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - "ArGra_SF", // - new OptionsEnum[0])), // - AR_GRA_SWELL(new PointImpl(// - "S128_AR_GRA_SWELL", // - "ArGraSwell", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "ArGra_SF")), // + AR_GRA_SWELL(new ScaledValuePoint("S128_AR_GRA_SWELL", "ArGraSwell", // "The gradient used to increase inductive dynamic current. A value of 0 indicates no additional reactive current support.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - "ArGra_SF", // - new OptionsEnum[0])), // - MOD_ENA(new PointImpl(// - "S128_MOD_ENA", // - "ModEna", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "ArGra_SF")), // + MOD_ENA(new BitFieldPoint("S128_MOD_ENA", "ModEna", // "Activate dynamic reactive current model", // - "", // - PointType.BITFIELD16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S128_ModEna.values())), // - FIL_TMS(new PointImpl(// - "S128_FIL_TMS", // - "FilTms", // + BitFieldPoint.Type.BITFIELD16, true /* mandatory? */, AccessMode.READ_WRITE, S128_ModEna.values())), // + FIL_TMS(new ValuePoint("S128_FIL_TMS", "FilTms", // "The time window used to calculate the moving average voltage.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - DB_V_MIN(new PointImpl(// - "S128_DB_V_MIN", // - "DbVMin", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + DB_V_MIN(new ScaledValuePoint("S128_DB_V_MIN", "DbVMin", // "The lower delta voltage limit for which negative voltage deviations less than this value no dynamic vars are produced.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.PERCENT, // - "VRefPct_SF", // - new OptionsEnum[0])), // - DB_V_MAX(new PointImpl(// - "S128_DB_V_MAX", // - "DbVMax", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "VRefPct_SF")), // + DB_V_MAX(new ScaledValuePoint("S128_DB_V_MAX", "DbVMax", // "The upper delta voltage limit for which positive voltage deviations less than this value no dynamic current produced.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.PERCENT, // - "VRefPct_SF", // - new OptionsEnum[0])), // - BLK_ZN_V(new PointImpl(// - "S128_BLK_ZN_V", // - "BlkZnV", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "VRefPct_SF")), // + BLK_ZN_V(new ScaledValuePoint("S128_BLK_ZN_V", "BlkZnV", // "Block zone voltage which defines a lower voltage boundary below which no dynamic current is produced.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.PERCENT, // - "VRefPct_SF", // - new OptionsEnum[0])), // - HYS_BLK_ZN_V(new PointImpl(// - "S128_HYS_BLK_ZN_V", // - "HysBlkZnV", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "VRefPct_SF")), // + HYS_BLK_ZN_V(new ScaledValuePoint("S128_HYS_BLK_ZN_V", "HysBlkZnV", // "Hysteresis voltage used with BlkZnV.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.PERCENT, // - "VRefPct_SF", // - new OptionsEnum[0])), // - BLK_ZN_TMMS(new PointImpl(// - "S128_BLK_ZN_TMMS", // - "BlkZnTmms", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "VRefPct_SF")), // + BLK_ZN_TMMS(new ValuePoint("S128_BLK_ZN_TMMS", "BlkZnTmms", // "Block zone time the time before which reactive current support remains active regardless of how low the voltage drops.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.MILLISECONDS, // - null, // - new OptionsEnum[0])), // - HOLD_TMMS(new PointImpl(// - "S128_HOLD_TMMS", // - "HoldTmms", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.MILLISECONDS)), // + HOLD_TMMS(new ValuePoint("S128_HOLD_TMMS", "HoldTmms", // "Hold time during which reactive current support continues after the average voltage has entered the dead zone.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.MILLISECONDS, // - null, // - new OptionsEnum[0])), // - AR_GRA_S_F(new PointImpl(// - "S128_AR_GRA_S_F", // - "ArGra_SF", // - "Scale factor for the gradients.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - V_REF_PCT_S_F(new PointImpl(// - "S128_V_REF_PCT_S_F", // - "VRefPct_SF", // - "Scale factor for the voltage zone and limit settings.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - PAD(new PointImpl(// - "S128_PAD", // - "", // - "", // - "", // - PointType.PAD, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // - - protected final PointImpl impl; - - private S128(PointImpl impl) { - this.impl = impl; - } - - @Override - public PointImpl get() { - return this.impl; + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.MILLISECONDS)), // + AR_GRA_S_F(new ScaleFactorPoint("S128_AR_GRA_S_F", "ArGra_SF", // + "Scale factor for the gradients.")), // + V_REF_PCT_S_F(new ScaleFactorPoint("S128_V_REF_PCT_S_F", "VRefPct_SF", // + "Scale factor for the voltage zone and limit settings.")), // + PAD(new ValuePoint("S128_PAD", "", "", // + ValuePoint.Type.PAD, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)); + + private final Point point; + + private S128(Point point) { + this.point = point; + } + + @Override + public Point get() { + return this.point; } } public static enum S128_ArGraMod implements OptionsEnum { UNDEFINED(-1, "Undefined"), // EDGE(0, "EDGE"), // - CENTER(1, "CENTER"); // + CENTER(1, "CENTER"); private final int value; private final String name; @@ -6478,4688 +2597,1288 @@ public OptionsEnum getUndefined() { } } - public static enum S128_ModEna implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - ENABLED(0, "ENABLED"); // - - private final int value; - private final String name; - - private S128_ModEna(int value, String name) { - this.value = value; - this.name = name; - } + public static enum S128_ModEna implements SunSpecBitPoint { + ENABLED(new BitPoint(0, "S128_MOD_ENA_ENABLED", "ENABLED")); - @Override - public int getValue() { - return this.value; - } + private final BitPoint point; - @Override - public String getName() { - return this.name; + private S128_ModEna(BitPoint point) { + this.point = point; } @Override - public OptionsEnum getUndefined() { - return UNDEFINED; + public BitPoint get() { + return this.point; } } public static enum S145 implements SunSpecPoint { - NOM_RMP_UP_RTE(new PointImpl(// - "S145_NOM_RMP_UP_RTE", // - "Ramp Up Rate", // + NOM_RMP_UP_RTE(new ScaledValuePoint("S145_NOM_RMP_UP_RTE", "Ramp Up Rate", // "Ramp up rate as a percentage of max current.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - "Rmp_SF", // - new OptionsEnum[0])), // - NOM_RMP_DN_RTE(new PointImpl(// - "S145_NOM_RMP_DN_RTE", // - "NomRmpDnRte", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "Rmp_SF")), // + NOM_RMP_DN_RTE(new ScaledValuePoint("S145_NOM_RMP_DN_RTE", "NomRmpDnRte", // "Ramp down rate as a percentage of max current.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - "Rmp_SF", // - new OptionsEnum[0])), // - EMG_RMP_UP_RTE(new PointImpl(// - "S145_EMG_RMP_UP_RTE", // - "Emergency Ramp Up Rate", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "Rmp_SF")), // + EMG_RMP_UP_RTE(new ScaledValuePoint("S145_EMG_RMP_UP_RTE", "Emergency Ramp Up Rate", // "Emergency ramp up rate as a percentage of max current.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - "Rmp_SF", // - new OptionsEnum[0])), // - EMG_RMP_DN_RTE(new PointImpl(// - "S145_EMG_RMP_DN_RTE", // - "Emergency Ramp Down Rate", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "Rmp_SF")), // + EMG_RMP_DN_RTE(new ScaledValuePoint("S145_EMG_RMP_DN_RTE", "Emergency Ramp Down Rate", // "Emergency ramp down rate as a percentage of max current.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - "Rmp_SF", // - new OptionsEnum[0])), // - CONN_RMP_UP_RTE(new PointImpl(// - "S145_CONN_RMP_UP_RTE", // - "Connect Ramp Up Rate", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "Rmp_SF")), // + CONN_RMP_UP_RTE(new ScaledValuePoint("S145_CONN_RMP_UP_RTE", "Connect Ramp Up Rate", // "Connect ramp up rate as a percentage of max current.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - "Rmp_SF", // - new OptionsEnum[0])), // - CONN_RMP_DN_RTE(new PointImpl(// - "S145_CONN_RMP_DN_RTE", // - "Connect Ramp Down Rate", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "Rmp_SF")), // + CONN_RMP_DN_RTE(new ScaledValuePoint("S145_CONN_RMP_DN_RTE", "Connect Ramp Down Rate", // "Connect ramp down rate as a percentage of max current.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - "Rmp_SF", // - new OptionsEnum[0])), // - A_GRA(new PointImpl(// - "S145_A_GRA", // - "Default Ramp Rate", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "Rmp_SF")), // + A_GRA(new ScaledValuePoint("S145_A_GRA", "Default Ramp Rate", // "Ramp rate specified in percent of max current.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - "Rmp_SF", // - new OptionsEnum[0])), // - RMP_S_F(new PointImpl(// - "S145_RMP_S_F", // - "Ramp Rate Scale Factor", // - "Ramp Rate Scale Factor", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // - - protected final PointImpl impl; - - private S145(PointImpl impl) { - this.impl = impl; - } - - @Override - public PointImpl get() { - return this.impl; + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "Rmp_SF")), // + RMP_S_F(new ScaleFactorPoint("S145_RMP_S_F", "Ramp Rate Scale Factor", // + "Ramp Rate Scale Factor")); + + private final Point point; + + private S145(Point point) { + this.point = point; + } + + @Override + public Point get() { + return this.point; } } public static enum S201 implements SunSpecPoint { - A(new PointImpl(// - "S201_A", // - "Amps", // + A(new ScaledValuePoint("S201_A", "Amps", // "Total AC Current", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - APH_A(new PointImpl(// - "S201_APH_A", // - "Amps PhaseA", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + APH_A(new ScaledValuePoint("S201_APH_A", "Amps PhaseA", // "Phase A Current", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - APH_B(new PointImpl(// - "S201_APH_B", // - "Amps PhaseB", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + APH_B(new ScaledValuePoint("S201_APH_B", "Amps PhaseB", // "Phase B Current", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - APH_C(new PointImpl(// - "S201_APH_C", // - "Amps PhaseC", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + APH_C(new ScaledValuePoint("S201_APH_C", "Amps PhaseC", // "Phase C Current", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - A_SF(new PointImpl(// - "S201_A_SF", // - "", // - "Current scale factor", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - PH_V(new PointImpl(// - "S201_PH_V", // - "Voltage LN", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + A_SF(new ScaleFactorPoint("S201_A_SF", "", // + "Current scale factor")), // + PH_V(new ScaledValuePoint("S201_PH_V", "Voltage LN", // "Line to Neutral AC Voltage (average of active phases)", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_A(new PointImpl(// - "S201_PH_VPH_A", // - "Phase Voltage AN", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_A(new ScaledValuePoint("S201_PH_VPH_A", "Phase Voltage AN", // "Phase Voltage AN", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_B(new PointImpl(// - "S201_PH_VPH_B", // - "Phase Voltage BN", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_B(new ScaledValuePoint("S201_PH_VPH_B", "Phase Voltage BN", // "Phase Voltage BN", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_C(new PointImpl(// - "S201_PH_VPH_C", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_C(new ScaledValuePoint("S201_PH_VPH_C", "Phase Voltage CN", // "Phase Voltage CN", // - "Phase Voltage CN", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PPV(new PointImpl(// - "S201_PPV", // - "Voltage LL", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PPV(new ScaledValuePoint("S201_PPV", "Voltage LL", // "Line to Line AC Voltage (average of active phases)", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - P_P_VPH_A_B(new PointImpl(// - "S201_P_P_VPH_A_B", // - "Phase Voltage AB", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + P_P_VPH_A_B(new ScaledValuePoint("S201_P_P_VPH_A_B", "Phase Voltage AB", // "Phase Voltage AB", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - P_P_VPH_B_C(new PointImpl(// - "S201_P_P_VPH_B_C", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + P_P_VPH_B_C(new ScaledValuePoint("S201_P_P_VPH_B_C", "Phase Voltage BC", // "Phase Voltage BC", // - "Phase Voltage BC", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - P_P_VPH_C_A(new PointImpl(// - "S201_P_P_VPH_C_A", // - "Phase Voltage CA", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + P_P_VPH_C_A(new ScaledValuePoint("S201_P_P_VPH_C_A", "Phase Voltage CA", // "Phase Voltage CA", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - V_SF(new PointImpl(// - "S201_V_SF", // - "", // - "Voltage scale factor", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - HZ(new PointImpl(// - "S201_HZ", // - "Hz", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + V_SF(new ScaleFactorPoint("S201_V_SF", "", // + "Voltage scale factor")), // + HZ(new ScaledValuePoint("S201_HZ", "Hz", // "Frequency", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.HERTZ, // - "Hz_SF", // - new OptionsEnum[0])), // - HZ_S_F(new PointImpl(// - "S201_HZ_S_F", // - "", // - "Frequency scale factor", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - W(new PointImpl(// - "S201_W", // - "Watts", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.HERTZ, "Hz_SF")), // + HZ_S_F(new ScaleFactorPoint("S201_HZ_S_F", "", // + "Frequency scale factor")), // + W(new ScaledValuePoint("S201_W", "Watts", // "Total Real Power", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - WPH_A(new PointImpl(// - "S201_WPH_A", // - "Watts phase A", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - WPH_B(new PointImpl(// - "S201_WPH_B", // - "Watts phase B", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - WPH_C(new PointImpl(// - "S201_WPH_C", // - "Watts phase C", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - W_SF(new PointImpl(// - "S201_W_SF", // - "", // - "Real Power scale factor", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - VA(new PointImpl(// - "S201_VA", // - "VA", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + WPH_A(new ScaledValuePoint("S201_WPH_A", "Watts phase A", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + WPH_B(new ScaledValuePoint("S201_WPH_B", "Watts phase B", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + WPH_C(new ScaledValuePoint("S201_WPH_C", "Watts phase C", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + W_SF(new ScaleFactorPoint("S201_W_SF", "", // + "Real Power scale factor")), // + VA(new ScaledValuePoint("S201_VA", "VA", // "AC Apparent Power", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE, // - "VA_SF", // - new OptionsEnum[0])), // - V_APH_A(new PointImpl(// - "S201_V_APH_A", // - "VA phase A", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE, // - "VA_SF", // - new OptionsEnum[0])), // - V_APH_B(new PointImpl(// - "S201_V_APH_B", // - "VA phase B", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE, // - "VA_SF", // - new OptionsEnum[0])), // - V_APH_C(new PointImpl(// - "S201_V_APH_C", // - "VA phase C", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE, // - "VA_SF", // - new OptionsEnum[0])), // - VA_SF(new PointImpl(// - "S201_VA_SF", // - "", // - "Apparent Power scale factor", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - VAR(new PointImpl(// - "S201_VAR", // - "VAR", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + V_APH_A(new ScaledValuePoint("S201_V_APH_A", "VA phase A", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + V_APH_B(new ScaledValuePoint("S201_V_APH_B", "VA phase B", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + V_APH_C(new ScaledValuePoint("S201_V_APH_C", "VA phase C", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + VA_SF(new ScaleFactorPoint("S201_VA_SF", "", // + "Apparent Power scale factor")), // + VAR(new ScaledValuePoint("S201_VAR", "VAR", // "Reactive Power", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "VAR_SF", // - new OptionsEnum[0])), // - V_A_RPH_A(new PointImpl(// - "S201_V_A_RPH_A", // - "VAR phase A", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "VAR_SF", // - new OptionsEnum[0])), // - V_A_RPH_B(new PointImpl(// - "S201_V_A_RPH_B", // - "VAR phase B", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "VAR_SF", // - new OptionsEnum[0])), // - V_A_RPH_C(new PointImpl(// - "S201_V_A_RPH_C", // - "VAR phase C", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "VAR_SF", // - new OptionsEnum[0])), // - VAR_SF(new PointImpl(// - "S201_VAR_SF", // - "", // - "Reactive Power scale factor", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - PF(new PointImpl(// - "S201_PF", // - "PF", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + V_A_RPH_A(new ScaledValuePoint("S201_V_A_RPH_A", "VAR phase A", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + V_A_RPH_B(new ScaledValuePoint("S201_V_A_RPH_B", "VAR phase B", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + V_A_RPH_C(new ScaledValuePoint("S201_V_A_RPH_C", "VAR phase C", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + VAR_SF(new ScaleFactorPoint("S201_VAR_SF", "", // + "Reactive Power scale factor")), // + PF(new ScaledValuePoint("S201_PF", "PF", // "Power Factor", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "PF_SF", // - new OptionsEnum[0])), // - P_FPH_A(new PointImpl(// - "S201_P_FPH_A", // - "PF phase A", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "PF_SF", // - new OptionsEnum[0])), // - P_FPH_B(new PointImpl(// - "S201_P_FPH_B", // - "PF phase B", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "PF_SF", // - new OptionsEnum[0])), // - P_FPH_C(new PointImpl(// - "S201_P_FPH_C", // - "PF phase C", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "PF_SF", // - new OptionsEnum[0])), // - PF_SF(new PointImpl(// - "S201_PF_SF", // - "", // - "Power Factor scale factor", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TOT_WH_EXP(new PointImpl(// - "S201_TOT_WH_EXP", // - "Total Watt-hours Exported", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + P_FPH_A(new ScaledValuePoint("S201_P_FPH_A", "PF phase A", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + P_FPH_B(new ScaledValuePoint("S201_P_FPH_B", "PF phase B", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + P_FPH_C(new ScaledValuePoint("S201_P_FPH_C", "PF phase C", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + PF_SF(new ScaleFactorPoint("S201_PF_SF", "", // + "Power Factor scale factor")), // + TOT_WH_EXP(new ScaledValuePoint("S201_TOT_WH_EXP", "Total Watt-hours Exported", // "Total Real Energy Exported", // - "", // - PointType.ACC32, // - true, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_EXP_PH_A(new PointImpl(// - "S201_TOT_WH_EXP_PH_A", // - "Total Watt-hours Exported phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_EXP_PH_B(new PointImpl(// - "S201_TOT_WH_EXP_PH_B", // - "Total Watt-hours Exported phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_EXP_PH_C(new PointImpl(// - "S201_TOT_WH_EXP_PH_C", // - "Total Watt-hours Exported phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_IMP(new PointImpl(// - "S201_TOT_WH_IMP", // - "Total Watt-hours Imported", // + ValuePoint.Type.ACC32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_EXP_PH_A(new ScaledValuePoint("S201_TOT_WH_EXP_PH_A", "Total Watt-hours Exported phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_EXP_PH_B(new ScaledValuePoint("S201_TOT_WH_EXP_PH_B", "Total Watt-hours Exported phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_EXP_PH_C(new ScaledValuePoint("S201_TOT_WH_EXP_PH_C", "Total Watt-hours Exported phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_IMP(new ScaledValuePoint("S201_TOT_WH_IMP", "Total Watt-hours Imported", // "Total Real Energy Imported", // - "", // - PointType.ACC32, // - true, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_IMP_PH_A(new PointImpl(// - "S201_TOT_WH_IMP_PH_A", // - "Total Watt-hours Imported phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_IMP_PH_B(new PointImpl(// - "S201_TOT_WH_IMP_PH_B", // - "Total Watt-hours Imported phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_IMP_PH_C(new PointImpl(// - "S201_TOT_WH_IMP_PH_C", // - "Total Watt-hours Imported phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_S_F(new PointImpl(// - "S201_TOT_WH_S_F", // - "", // - "Real Energy scale factor", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TOT_V_AH_EXP(new PointImpl(// - "S201_TOT_V_AH_EXP", // - "Total VA-hours Exported", // + ValuePoint.Type.ACC32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_IMP_PH_A(new ScaledValuePoint("S201_TOT_WH_IMP_PH_A", "Total Watt-hours Imported phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_IMP_PH_B(new ScaledValuePoint("S201_TOT_WH_IMP_PH_B", "Total Watt-hours Imported phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_IMP_PH_C(new ScaledValuePoint("S201_TOT_WH_IMP_PH_C", "Total Watt-hours Imported phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_S_F(new ScaleFactorPoint("S201_TOT_WH_S_F", "", // + "Real Energy scale factor")), // + TOT_V_AH_EXP(new ScaledValuePoint("S201_TOT_V_AH_EXP", "Total VA-hours Exported", // "Total Apparent Energy Exported", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_EXP_PH_A(new PointImpl(// - "S201_TOT_V_AH_EXP_PH_A", // - "Total VA-hours Exported phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_EXP_PH_B(new PointImpl(// - "S201_TOT_V_AH_EXP_PH_B", // - "Total VA-hours Exported phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_EXP_PH_C(new PointImpl(// - "S201_TOT_V_AH_EXP_PH_C", // - "Total VA-hours Exported phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_IMP(new PointImpl(// - "S201_TOT_V_AH_IMP", // - "Total VA-hours Imported", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_EXP_PH_A(new ScaledValuePoint("S201_TOT_V_AH_EXP_PH_A", "Total VA-hours Exported phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_EXP_PH_B(new ScaledValuePoint("S201_TOT_V_AH_EXP_PH_B", "Total VA-hours Exported phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_EXP_PH_C(new ScaledValuePoint("S201_TOT_V_AH_EXP_PH_C", "Total VA-hours Exported phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_IMP(new ScaledValuePoint("S201_TOT_V_AH_IMP", "Total VA-hours Imported", // "Total Apparent Energy Imported", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_IMP_PH_A(new PointImpl(// - "S201_TOT_V_AH_IMP_PH_A", // - "Total VA-hours Imported phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_IMP_PH_B(new PointImpl(// - "S201_TOT_V_AH_IMP_PH_B", // - "Total VA-hours Imported phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_IMP_PH_C(new PointImpl(// - "S201_TOT_V_AH_IMP_PH_C", // - "Total VA-hours Imported phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_S_F(new PointImpl(// - "S201_TOT_V_AH_S_F", // - "", // - "Apparent Energy scale factor", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q1(new PointImpl(// - "S201_TOT_V_ARH_IMP_Q1", // - "Total VAR-hours Imported Q1", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_IMP_PH_A(new ScaledValuePoint("S201_TOT_V_AH_IMP_PH_A", "Total VA-hours Imported phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_IMP_PH_B(new ScaledValuePoint("S201_TOT_V_AH_IMP_PH_B", "Total VA-hours Imported phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_IMP_PH_C(new ScaledValuePoint("S201_TOT_V_AH_IMP_PH_C", "Total VA-hours Imported phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_S_F(new ScaleFactorPoint("S201_TOT_V_AH_S_F", "", // + "Apparent Energy scale factor")), // + TOT_V_ARH_IMP_Q1(new ScaledValuePoint("S201_TOT_V_ARH_IMP_Q1", "Total VAR-hours Imported Q1", // "Total Reactive Energy Imported Quadrant 1", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q1_PH_A(new PointImpl(// - "S201_TOT_V_ARH_IMP_Q1_PH_A", // - "Total VAr-hours Imported Q1 phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q1_PH_B(new PointImpl(// - "S201_TOT_V_ARH_IMP_Q1_PH_B", // - "Total VAr-hours Imported Q1 phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q1_PH_C(new PointImpl(// - "S201_TOT_V_ARH_IMP_Q1_PH_C", // - "Total VAr-hours Imported Q1 phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q2(new PointImpl(// - "S201_TOT_V_ARH_IMP_Q2", // - "Total VAr-hours Imported Q2", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q1_PH_A(new ScaledValuePoint("S201_TOT_V_ARH_IMP_Q1_PH_A", "Total VAr-hours Imported Q1 phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q1_PH_B(new ScaledValuePoint("S201_TOT_V_ARH_IMP_Q1_PH_B", "Total VAr-hours Imported Q1 phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q1_PH_C(new ScaledValuePoint("S201_TOT_V_ARH_IMP_Q1_PH_C", "Total VAr-hours Imported Q1 phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q2(new ScaledValuePoint("S201_TOT_V_ARH_IMP_Q2", "Total VAr-hours Imported Q2", // "Total Reactive Power Imported Quadrant 2", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q2_PH_A(new PointImpl(// - "S201_TOT_V_ARH_IMP_Q2_PH_A", // - "Total VAr-hours Imported Q2 phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q2_PH_B(new PointImpl(// - "S201_TOT_V_ARH_IMP_Q2_PH_B", // - "Total VAr-hours Imported Q2 phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q2_PH_C(new PointImpl(// - "S201_TOT_V_ARH_IMP_Q2_PH_C", // - "Total VAr-hours Imported Q2 phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q3(new PointImpl(// - "S201_TOT_V_ARH_EXP_Q3", // - "Total VAr-hours Exported Q3", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q2_PH_A(new ScaledValuePoint("S201_TOT_V_ARH_IMP_Q2_PH_A", "Total VAr-hours Imported Q2 phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q2_PH_B(new ScaledValuePoint("S201_TOT_V_ARH_IMP_Q2_PH_B", "Total VAr-hours Imported Q2 phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q2_PH_C(new ScaledValuePoint("S201_TOT_V_ARH_IMP_Q2_PH_C", "Total VAr-hours Imported Q2 phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q3(new ScaledValuePoint("S201_TOT_V_ARH_EXP_Q3", "Total VAr-hours Exported Q3", // "Total Reactive Power Exported Quadrant 3", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q3_PH_A(new PointImpl(// - "S201_TOT_V_ARH_EXP_Q3_PH_A", // - "Total VAr-hours Exported Q3 phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q3_PH_B(new PointImpl(// - "S201_TOT_V_ARH_EXP_Q3_PH_B", // - "Total VAr-hours Exported Q3 phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q3_PH_C(new PointImpl(// - "S201_TOT_V_ARH_EXP_Q3_PH_C", // - "Total VAr-hours Exported Q3 phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q4(new PointImpl(// - "S201_TOT_V_ARH_EXP_Q4", // - "Total VAr-hours Exported Q4", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q3_PH_A(new ScaledValuePoint("S201_TOT_V_ARH_EXP_Q3_PH_A", "Total VAr-hours Exported Q3 phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q3_PH_B(new ScaledValuePoint("S201_TOT_V_ARH_EXP_Q3_PH_B", "Total VAr-hours Exported Q3 phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q3_PH_C(new ScaledValuePoint("S201_TOT_V_ARH_EXP_Q3_PH_C", "Total VAr-hours Exported Q3 phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q4(new ScaledValuePoint("S201_TOT_V_ARH_EXP_Q4", "Total VAr-hours Exported Q4", // "Total Reactive Power Exported Quadrant 4", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q4_PH_A(new PointImpl(// - "S201_TOT_V_ARH_EXP_Q4_PH_A", // - "Total VAr-hours Exported Q4 Imported phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q4_PH_B(new PointImpl(// - "S201_TOT_V_ARH_EXP_Q4_PH_B", // - "Total VAr-hours Exported Q4 Imported phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q4_PH_C(new PointImpl(// - "S201_TOT_V_ARH_EXP_Q4_PH_C", // - "Total VAr-hours Exported Q4 Imported phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_S_F(new PointImpl(// - "S201_TOT_V_ARH_S_F", // - "", // - "Reactive Energy scale factor", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT(new PointImpl(// - "S201_EVT", // - "Events", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q4_PH_A(new ScaledValuePoint("S201_TOT_V_ARH_EXP_Q4_PH_A", "Total VAr-hours Exported Q4 Imported phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q4_PH_B(new ScaledValuePoint("S201_TOT_V_ARH_EXP_Q4_PH_B", "Total VAr-hours Exported Q4 Imported phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q4_PH_C(new ScaledValuePoint("S201_TOT_V_ARH_EXP_Q4_PH_C", "Total VAr-hours Exported Q4 Imported phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_S_F(new ScaleFactorPoint("S201_TOT_V_ARH_S_F", "", // + "Reactive Energy scale factor")), // + EVT(new BitFieldPoint("S201_EVT", "Events", // "Meter Event Flags", // - "", // - PointType.BITFIELD32, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S201_Evt.values())); // + BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, S201_Evt.values())); - protected final PointImpl impl; + private final Point point; - private S201(PointImpl impl) { - this.impl = impl; + private S201(Point point) { + this.point = point; } @Override - public PointImpl get() { - return this.impl; + public Point get() { + return this.point; } } - public static enum S201_Evt implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - POWER_FAILURE(2, "POWER_FAILURE"), // - UNDER_VOLTAGE(3, "UNDER_VOLTAGE"), // - LOW_P_F(4, "LOW_P_F"), // - OVER_CURRENT(5, "OVER_CURRENT"), // - OVER_VOLTAGE(6, "OVER_VOLTAGE"), // - MISSING_SENSOR(7, "MISSING_SENSOR"), // - OEM01(16, "OEM01"), // - OEM02(17, "OEM02"), // - OEM03(18, "OEM03"), // - OEM04(19, "OEM04"), // - OEM05(20, "OEM05"), // - OEM06(21, "OEM06"), // - OEM07(22, "OEM07"), // - OEM08(23, "OEM08"), // - OEM09(24, "OEM09"), // - OEM10(25, "OEM10"), // - OEM11(26, "OEM11"), // - OEM12(27, "OEM12"), // - OEM13(28, "OEM13"), // - OEM14(29, "OEM14"), // - OEM15(30, "OEM15"); // + public static enum S201_Evt implements SunSpecBitPoint { + POWER_FAILURE(new BitPoint(2, "S201_EVT_POWER_FAILURE", "Power_Failure")), // + UNDER_VOLTAGE(new BitPoint(3, "S201_EVT_UNDER_VOLTAGE", "Under_Voltage")), // + LOW_P_F(new BitPoint(4, "S201_EVT_LOW_P_F", "Low_PF")), // + OVER_CURRENT(new BitPoint(5, "S201_EVT_OVER_CURRENT", "Over_Current")), // + OVER_VOLTAGE(new BitPoint(6, "S201_EVT_OVER_VOLTAGE", "Over_Voltage")), // + MISSING_SENSOR(new BitPoint(7, "S201_EVT_MISSING_SENSOR", "Missing_Sensor")), // + OEM01(new BitPoint(16, "S201_EVT_OEM01", "OEM01")), // + OEM02(new BitPoint(17, "S201_EVT_OEM02", "OEM02")), // + OEM03(new BitPoint(18, "S201_EVT_OEM03", "OEM03")), // + OEM04(new BitPoint(19, "S201_EVT_OEM04", "OEM04")), // + OEM05(new BitPoint(20, "S201_EVT_OEM05", "OEM05")), // + OEM06(new BitPoint(21, "S201_EVT_OEM06", "OEM06")), // + OEM07(new BitPoint(22, "S201_EVT_OEM07", "OEM07")), // + OEM08(new BitPoint(23, "S201_EVT_OEM08", "OEM08")), // + OEM09(new BitPoint(24, "S201_EVT_OEM09", "OEM09")), // + OEM10(new BitPoint(25, "S201_EVT_OEM10", "OEM10")), // + OEM11(new BitPoint(26, "S201_EVT_OEM11", "OEM11")), // + OEM12(new BitPoint(27, "S201_EVT_OEM12", "OEM12")), // + OEM13(new BitPoint(28, "S201_EVT_OEM13", "OEM13")), // + OEM14(new BitPoint(29, "S201_EVT_OEM14", "OEM14")), // + OEM15(new BitPoint(30, "S201_EVT_OEM15", "OEM15")); - private final int value; - private final String name; + private final BitPoint point; - private S201_Evt(int value, String name) { - this.value = value; - this.name = name; + private S201_Evt(BitPoint point) { + this.point = point; } @Override - public int getValue() { - return this.value; - } - - @Override - public String getName() { - return this.name; - } - - @Override - public OptionsEnum getUndefined() { - return UNDEFINED; + public BitPoint get() { + return this.point; } } public static enum S202 implements SunSpecPoint { - A(new PointImpl(// - "S202_A", // - "Amps", // + A(new ScaledValuePoint("S202_A", "Amps", // "Total AC Current", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - APH_A(new PointImpl(// - "S202_APH_A", // - "Amps PhaseA", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + APH_A(new ScaledValuePoint("S202_APH_A", "Amps PhaseA", // "Phase A Current", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - APH_B(new PointImpl(// - "S202_APH_B", // - "Amps PhaseB", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + APH_B(new ScaledValuePoint("S202_APH_B", "Amps PhaseB", // "Phase B Current", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - APH_C(new PointImpl(// - "S202_APH_C", // - "Amps PhaseC", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + APH_C(new ScaledValuePoint("S202_APH_C", "Amps PhaseC", // "Phase C Current", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - A_SF(new PointImpl(// - "S202_A_SF", // - "", // - "Current scale factor", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - PH_V(new PointImpl(// - "S202_PH_V", // - "Voltage LN", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + A_SF(new ScaleFactorPoint("S202_A_SF", "", // + "Current scale factor")), // + PH_V(new ScaledValuePoint("S202_PH_V", "Voltage LN", // "Line to Neutral AC Voltage (average of active phases)", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_A(new PointImpl(// - "S202_PH_VPH_A", // - "Phase Voltage AN", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_A(new ScaledValuePoint("S202_PH_VPH_A", "Phase Voltage AN", // "Phase Voltage AN", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_B(new PointImpl(// - "S202_PH_VPH_B", // - "Phase Voltage BN", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_B(new ScaledValuePoint("S202_PH_VPH_B", "Phase Voltage BN", // "Phase Voltage BN", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_C(new PointImpl(// - "S202_PH_VPH_C", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_C(new ScaledValuePoint("S202_PH_VPH_C", "Phase Voltage CN", // "Phase Voltage CN", // - "Phase Voltage CN", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PPV(new PointImpl(// - "S202_PPV", // - "Voltage LL", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PPV(new ScaledValuePoint("S202_PPV", "Voltage LL", // "Line to Line AC Voltage (average of active phases)", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_A_B(new PointImpl(// - "S202_PH_VPH_A_B", // - "Phase Voltage AB", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_A_B(new ScaledValuePoint("S202_PH_VPH_A_B", "Phase Voltage AB", // "Phase Voltage AB", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_B_C(new PointImpl(// - "S202_PH_VPH_B_C", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_B_C(new ScaledValuePoint("S202_PH_VPH_B_C", "Phase Voltage BC", // "Phase Voltage BC", // - "Phase Voltage BC", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_C_A(new PointImpl(// - "S202_PH_VPH_C_A", // - "Phase Voltage CA", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_C_A(new ScaledValuePoint("S202_PH_VPH_C_A", "Phase Voltage CA", // "Phase Voltage CA", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - V_SF(new PointImpl(// - "S202_V_SF", // - "", // - "Voltage scale factor", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - HZ(new PointImpl(// - "S202_HZ", // - "Hz", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + V_SF(new ScaleFactorPoint("S202_V_SF", "", // + "Voltage scale factor")), // + HZ(new ScaledValuePoint("S202_HZ", "Hz", // "Frequency", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.HERTZ, // - "Hz_SF", // - new OptionsEnum[0])), // - HZ_S_F(new PointImpl(// - "S202_HZ_S_F", // - "", // - "Frequency scale factor", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - W(new PointImpl(// - "S202_W", // - "Watts", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.HERTZ, "Hz_SF")), // + HZ_S_F(new ScaleFactorPoint("S202_HZ_S_F", "", // + "Frequency scale factor")), // + W(new ScaledValuePoint("S202_W", "Watts", // "Total Real Power", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - WPH_A(new PointImpl(// - "S202_WPH_A", // - "Watts phase A", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - WPH_B(new PointImpl(// - "S202_WPH_B", // - "Watts phase B", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - WPH_C(new PointImpl(// - "S202_WPH_C", // - "Watts phase C", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - W_SF(new PointImpl(// - "S202_W_SF", // - "", // - "Real Power scale factor", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - VA(new PointImpl(// - "S202_VA", // - "VA", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + WPH_A(new ScaledValuePoint("S202_WPH_A", "Watts phase A", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + WPH_B(new ScaledValuePoint("S202_WPH_B", "Watts phase B", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + WPH_C(new ScaledValuePoint("S202_WPH_C", "Watts phase C", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + W_SF(new ScaleFactorPoint("S202_W_SF", "", // + "Real Power scale factor")), // + VA(new ScaledValuePoint("S202_VA", "VA", // "AC Apparent Power", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE, // - "VA_SF", // - new OptionsEnum[0])), // - V_APH_A(new PointImpl(// - "S202_V_APH_A", // - "VA phase A", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE, // - "VA_SF", // - new OptionsEnum[0])), // - V_APH_B(new PointImpl(// - "S202_V_APH_B", // - "VA phase B", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE, // - "VA_SF", // - new OptionsEnum[0])), // - V_APH_C(new PointImpl(// - "S202_V_APH_C", // - "VA phase C", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE, // - "VA_SF", // - new OptionsEnum[0])), // - VA_SF(new PointImpl(// - "S202_VA_SF", // - "", // - "Apparent Power scale factor", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - VAR(new PointImpl(// - "S202_VAR", // - "VAR", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + V_APH_A(new ScaledValuePoint("S202_V_APH_A", "VA phase A", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + V_APH_B(new ScaledValuePoint("S202_V_APH_B", "VA phase B", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + V_APH_C(new ScaledValuePoint("S202_V_APH_C", "VA phase C", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + VA_SF(new ScaleFactorPoint("S202_VA_SF", "", // + "Apparent Power scale factor")), // + VAR(new ScaledValuePoint("S202_VAR", "VAR", // "Reactive Power", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "VAR_SF", // - new OptionsEnum[0])), // - V_A_RPH_A(new PointImpl(// - "S202_V_A_RPH_A", // - "VAR phase A", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "VAR_SF", // - new OptionsEnum[0])), // - V_A_RPH_B(new PointImpl(// - "S202_V_A_RPH_B", // - "VAR phase B", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "VAR_SF", // - new OptionsEnum[0])), // - V_A_RPH_C(new PointImpl(// - "S202_V_A_RPH_C", // - "VAR phase C", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "VAR_SF", // - new OptionsEnum[0])), // - VAR_SF(new PointImpl(// - "S202_VAR_SF", // - "", // - "Reactive Power scale factor", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - PF(new PointImpl(// - "S202_PF", // - "PF", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + V_A_RPH_A(new ScaledValuePoint("S202_V_A_RPH_A", "VAR phase A", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + V_A_RPH_B(new ScaledValuePoint("S202_V_A_RPH_B", "VAR phase B", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + V_A_RPH_C(new ScaledValuePoint("S202_V_A_RPH_C", "VAR phase C", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + VAR_SF(new ScaleFactorPoint("S202_VAR_SF", "", // + "Reactive Power scale factor")), // + PF(new ScaledValuePoint("S202_PF", "PF", // "Power Factor", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "PF_SF", // - new OptionsEnum[0])), // - P_FPH_A(new PointImpl(// - "S202_P_FPH_A", // - "PF phase A", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "PF_SF", // - new OptionsEnum[0])), // - P_FPH_B(new PointImpl(// - "S202_P_FPH_B", // - "PF phase B", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "PF_SF", // - new OptionsEnum[0])), // - P_FPH_C(new PointImpl(// - "S202_P_FPH_C", // - "PF phase C", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "PF_SF", // - new OptionsEnum[0])), // - PF_SF(new PointImpl(// - "S202_PF_SF", // - "", // - "Power Factor scale factor", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TOT_WH_EXP(new PointImpl(// - "S202_TOT_WH_EXP", // - "Total Watt-hours Exported", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + P_FPH_A(new ScaledValuePoint("S202_P_FPH_A", "PF phase A", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + P_FPH_B(new ScaledValuePoint("S202_P_FPH_B", "PF phase B", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + P_FPH_C(new ScaledValuePoint("S202_P_FPH_C", "PF phase C", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + PF_SF(new ScaleFactorPoint("S202_PF_SF", "", // + "Power Factor scale factor")), // + TOT_WH_EXP(new ScaledValuePoint("S202_TOT_WH_EXP", "Total Watt-hours Exported", // "Total Real Energy Exported", // - "", // - PointType.ACC32, // - true, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_EXP_PH_A(new PointImpl(// - "S202_TOT_WH_EXP_PH_A", // - "Total Watt-hours Exported phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_EXP_PH_B(new PointImpl(// - "S202_TOT_WH_EXP_PH_B", // - "Total Watt-hours Exported phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_EXP_PH_C(new PointImpl(// - "S202_TOT_WH_EXP_PH_C", // - "Total Watt-hours Exported phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_IMP(new PointImpl(// - "S202_TOT_WH_IMP", // - "Total Watt-hours Imported", // + ValuePoint.Type.ACC32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_EXP_PH_A(new ScaledValuePoint("S202_TOT_WH_EXP_PH_A", "Total Watt-hours Exported phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_EXP_PH_B(new ScaledValuePoint("S202_TOT_WH_EXP_PH_B", "Total Watt-hours Exported phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_EXP_PH_C(new ScaledValuePoint("S202_TOT_WH_EXP_PH_C", "Total Watt-hours Exported phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_IMP(new ScaledValuePoint("S202_TOT_WH_IMP", "Total Watt-hours Imported", // "Total Real Energy Imported", // - "", // - PointType.ACC32, // - true, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_IMP_PH_A(new PointImpl(// - "S202_TOT_WH_IMP_PH_A", // - "Total Watt-hours Imported phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_IMP_PH_B(new PointImpl(// - "S202_TOT_WH_IMP_PH_B", // - "Total Watt-hours Imported phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_IMP_PH_C(new PointImpl(// - "S202_TOT_WH_IMP_PH_C", // - "Total Watt-hours Imported phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_S_F(new PointImpl(// - "S202_TOT_WH_S_F", // - "", // - "Real Energy scale factor", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TOT_V_AH_EXP(new PointImpl(// - "S202_TOT_V_AH_EXP", // - "Total VA-hours Exported", // + ValuePoint.Type.ACC32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_IMP_PH_A(new ScaledValuePoint("S202_TOT_WH_IMP_PH_A", "Total Watt-hours Imported phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_IMP_PH_B(new ScaledValuePoint("S202_TOT_WH_IMP_PH_B", "Total Watt-hours Imported phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_IMP_PH_C(new ScaledValuePoint("S202_TOT_WH_IMP_PH_C", "Total Watt-hours Imported phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_S_F(new ScaleFactorPoint("S202_TOT_WH_S_F", "", // + "Real Energy scale factor")), // + TOT_V_AH_EXP(new ScaledValuePoint("S202_TOT_V_AH_EXP", "Total VA-hours Exported", // "Total Apparent Energy Exported", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_EXP_PH_A(new PointImpl(// - "S202_TOT_V_AH_EXP_PH_A", // - "Total VA-hours Exported phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_EXP_PH_B(new PointImpl(// - "S202_TOT_V_AH_EXP_PH_B", // - "Total VA-hours Exported phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_EXP_PH_C(new PointImpl(// - "S202_TOT_V_AH_EXP_PH_C", // - "Total VA-hours Exported phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_IMP(new PointImpl(// - "S202_TOT_V_AH_IMP", // - "Total VA-hours Imported", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_EXP_PH_A(new ScaledValuePoint("S202_TOT_V_AH_EXP_PH_A", "Total VA-hours Exported phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_EXP_PH_B(new ScaledValuePoint("S202_TOT_V_AH_EXP_PH_B", "Total VA-hours Exported phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_EXP_PH_C(new ScaledValuePoint("S202_TOT_V_AH_EXP_PH_C", "Total VA-hours Exported phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_IMP(new ScaledValuePoint("S202_TOT_V_AH_IMP", "Total VA-hours Imported", // "Total Apparent Energy Imported", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_IMP_PH_A(new PointImpl(// - "S202_TOT_V_AH_IMP_PH_A", // - "Total VA-hours Imported phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_IMP_PH_B(new PointImpl(// - "S202_TOT_V_AH_IMP_PH_B", // - "Total VA-hours Imported phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_IMP_PH_C(new PointImpl(// - "S202_TOT_V_AH_IMP_PH_C", // - "Total VA-hours Imported phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_S_F(new PointImpl(// - "S202_TOT_V_AH_S_F", // - "", // - "Apparent Energy scale factor", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q1(new PointImpl(// - "S202_TOT_V_ARH_IMP_Q1", // - "Total VAR-hours Imported Q1", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_IMP_PH_A(new ScaledValuePoint("S202_TOT_V_AH_IMP_PH_A", "Total VA-hours Imported phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_IMP_PH_B(new ScaledValuePoint("S202_TOT_V_AH_IMP_PH_B", "Total VA-hours Imported phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_IMP_PH_C(new ScaledValuePoint("S202_TOT_V_AH_IMP_PH_C", "Total VA-hours Imported phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_S_F(new ScaleFactorPoint("S202_TOT_V_AH_S_F", "", // + "Apparent Energy scale factor")), // + TOT_V_ARH_IMP_Q1(new ScaledValuePoint("S202_TOT_V_ARH_IMP_Q1", "Total VAR-hours Imported Q1", // "Total Reactive Energy Imported Quadrant 1", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q1_PH_A(new PointImpl(// - "S202_TOT_V_ARH_IMP_Q1_PH_A", // - "Total VAr-hours Imported Q1 phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q1_PH_B(new PointImpl(// - "S202_TOT_V_ARH_IMP_Q1_PH_B", // - "Total VAr-hours Imported Q1 phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q1_PH_C(new PointImpl(// - "S202_TOT_V_ARH_IMP_Q1_PH_C", // - "Total VAr-hours Imported Q1 phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q2(new PointImpl(// - "S202_TOT_V_ARH_IMP_Q2", // - "Total VAr-hours Imported Q2", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q1_PH_A(new ScaledValuePoint("S202_TOT_V_ARH_IMP_Q1_PH_A", "Total VAr-hours Imported Q1 phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q1_PH_B(new ScaledValuePoint("S202_TOT_V_ARH_IMP_Q1_PH_B", "Total VAr-hours Imported Q1 phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q1_PH_C(new ScaledValuePoint("S202_TOT_V_ARH_IMP_Q1_PH_C", "Total VAr-hours Imported Q1 phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q2(new ScaledValuePoint("S202_TOT_V_ARH_IMP_Q2", "Total VAr-hours Imported Q2", // "Total Reactive Power Imported Quadrant 2", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q2_PH_A(new PointImpl(// - "S202_TOT_V_ARH_IMP_Q2_PH_A", // - "Total VAr-hours Imported Q2 phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q2_PH_B(new PointImpl(// - "S202_TOT_V_ARH_IMP_Q2_PH_B", // - "Total VAr-hours Imported Q2 phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q2_PH_C(new PointImpl(// - "S202_TOT_V_ARH_IMP_Q2_PH_C", // - "Total VAr-hours Imported Q2 phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q3(new PointImpl(// - "S202_TOT_V_ARH_EXP_Q3", // - "Total VAr-hours Exported Q3", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q2_PH_A(new ScaledValuePoint("S202_TOT_V_ARH_IMP_Q2_PH_A", "Total VAr-hours Imported Q2 phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q2_PH_B(new ScaledValuePoint("S202_TOT_V_ARH_IMP_Q2_PH_B", "Total VAr-hours Imported Q2 phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q2_PH_C(new ScaledValuePoint("S202_TOT_V_ARH_IMP_Q2_PH_C", "Total VAr-hours Imported Q2 phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q3(new ScaledValuePoint("S202_TOT_V_ARH_EXP_Q3", "Total VAr-hours Exported Q3", // "Total Reactive Power Exported Quadrant 3", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q3_PH_A(new PointImpl(// - "S202_TOT_V_ARH_EXP_Q3_PH_A", // - "Total VAr-hours Exported Q3 phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q3_PH_B(new PointImpl(// - "S202_TOT_V_ARH_EXP_Q3_PH_B", // - "Total VAr-hours Exported Q3 phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q3_PH_C(new PointImpl(// - "S202_TOT_V_ARH_EXP_Q3_PH_C", // - "Total VAr-hours Exported Q3 phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q4(new PointImpl(// - "S202_TOT_V_ARH_EXP_Q4", // - "Total VAr-hours Exported Q4", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q3_PH_A(new ScaledValuePoint("S202_TOT_V_ARH_EXP_Q3_PH_A", "Total VAr-hours Exported Q3 phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q3_PH_B(new ScaledValuePoint("S202_TOT_V_ARH_EXP_Q3_PH_B", "Total VAr-hours Exported Q3 phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q3_PH_C(new ScaledValuePoint("S202_TOT_V_ARH_EXP_Q3_PH_C", "Total VAr-hours Exported Q3 phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q4(new ScaledValuePoint("S202_TOT_V_ARH_EXP_Q4", "Total VAr-hours Exported Q4", // "Total Reactive Power Exported Quadrant 4", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q4_PH_A(new PointImpl(// - "S202_TOT_V_ARH_EXP_Q4_PH_A", // - "Total VAr-hours Exported Q4 Imported phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q4_PH_B(new PointImpl(// - "S202_TOT_V_ARH_EXP_Q4_PH_B", // - "Total VAr-hours Exported Q4 Imported phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q4_PH_C(new PointImpl(// - "S202_TOT_V_ARH_EXP_Q4_PH_C", // - "Total VAr-hours Exported Q4 Imported phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_S_F(new PointImpl(// - "S202_TOT_V_ARH_S_F", // - "", // - "Reactive Energy scale factor", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT(new PointImpl(// - "S202_EVT", // - "Events", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q4_PH_A(new ScaledValuePoint("S202_TOT_V_ARH_EXP_Q4_PH_A", "Total VAr-hours Exported Q4 Imported phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q4_PH_B(new ScaledValuePoint("S202_TOT_V_ARH_EXP_Q4_PH_B", "Total VAr-hours Exported Q4 Imported phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q4_PH_C(new ScaledValuePoint("S202_TOT_V_ARH_EXP_Q4_PH_C", "Total VAr-hours Exported Q4 Imported phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_S_F(new ScaleFactorPoint("S202_TOT_V_ARH_S_F", "", // + "Reactive Energy scale factor")), // + EVT(new BitFieldPoint("S202_EVT", "Events", // "Meter Event Flags", // - "", // - PointType.BITFIELD32, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S202_Evt.values())); // + BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, S202_Evt.values())); - protected final PointImpl impl; + private final Point point; - private S202(PointImpl impl) { - this.impl = impl; + private S202(Point point) { + this.point = point; } @Override - public PointImpl get() { - return this.impl; + public Point get() { + return this.point; } } - public static enum S202_Evt implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - POWER_FAILURE(2, "POWER_FAILURE"), // - UNDER_VOLTAGE(3, "UNDER_VOLTAGE"), // - LOW_P_F(4, "LOW_P_F"), // - OVER_CURRENT(5, "OVER_CURRENT"), // - OVER_VOLTAGE(6, "OVER_VOLTAGE"), // - MISSING_SENSOR(7, "MISSING_SENSOR"), // - RESERVED1(8, "RESERVED1"), // - RESERVED2(9, "RESERVED2"), // - RESERVED3(10, "RESERVED3"), // - RESERVED4(11, "RESERVED4"), // - RESERVED5(12, "RESERVED5"), // - RESERVED6(13, "RESERVED6"), // - RESERVED7(14, "RESERVED7"), // - RESERVED8(15, "RESERVED8"), // - OEM01(16, "OEM01"), // - OEM02(17, "OEM02"), // - OEM03(18, "OEM03"), // - OEM04(19, "OEM04"), // - OEM05(20, "OEM05"), // - OEM06(21, "OEM06"), // - OEM07(22, "OEM07"), // - OEM08(23, "OEM08"), // - OEM09(24, "OEM09"), // - OEM10(25, "OEM10"), // - OEM11(26, "OEM11"), // - OEM12(27, "OEM12"), // - OEM13(28, "OEM13"), // - OEM14(29, "OEM14"), // - OEM15(30, "OEM15"); // + public static enum S202_Evt implements SunSpecBitPoint { + POWER_FAILURE(new BitPoint(2, "S202_EVT_POWER_FAILURE", "Power_Failure")), // + UNDER_VOLTAGE(new BitPoint(3, "S202_EVT_UNDER_VOLTAGE", "Under_Voltage")), // + LOW_P_F(new BitPoint(4, "S202_EVT_LOW_P_F", "Low_PF")), // + OVER_CURRENT(new BitPoint(5, "S202_EVT_OVER_CURRENT", "Over_Current")), // + OVER_VOLTAGE(new BitPoint(6, "S202_EVT_OVER_VOLTAGE", "Over_Voltage")), // + MISSING_SENSOR(new BitPoint(7, "S202_EVT_MISSING_SENSOR", "Missing_Sensor")), // + RESERVED1(new BitPoint(8, "S202_EVT_RESERVED1", "Reserved1")), // + RESERVED2(new BitPoint(9, "S202_EVT_RESERVED2", "Reserved2")), // + RESERVED3(new BitPoint(10, "S202_EVT_RESERVED3", "Reserved3")), // + RESERVED4(new BitPoint(11, "S202_EVT_RESERVED4", "Reserved4")), // + RESERVED5(new BitPoint(12, "S202_EVT_RESERVED5", "Reserved5")), // + RESERVED6(new BitPoint(13, "S202_EVT_RESERVED6", "Reserved6")), // + RESERVED7(new BitPoint(14, "S202_EVT_RESERVED7", "Reserved7")), // + RESERVED8(new BitPoint(15, "S202_EVT_RESERVED8", "Reserved8")), // + OEM01(new BitPoint(16, "S202_EVT_OEM01", "OEM01")), // + OEM02(new BitPoint(17, "S202_EVT_OEM02", "OEM02")), // + OEM03(new BitPoint(18, "S202_EVT_OEM03", "OEM03")), // + OEM04(new BitPoint(19, "S202_EVT_OEM04", "OEM04")), // + OEM05(new BitPoint(20, "S202_EVT_OEM05", "OEM05")), // + OEM06(new BitPoint(21, "S202_EVT_OEM06", "OEM06")), // + OEM07(new BitPoint(22, "S202_EVT_OEM07", "OEM07")), // + OEM08(new BitPoint(23, "S202_EVT_OEM08", "OEM08")), // + OEM09(new BitPoint(24, "S202_EVT_OEM09", "OEM09")), // + OEM10(new BitPoint(25, "S202_EVT_OEM10", "OEM10")), // + OEM11(new BitPoint(26, "S202_EVT_OEM11", "OEM11")), // + OEM12(new BitPoint(27, "S202_EVT_OEM12", "OEM12")), // + OEM13(new BitPoint(28, "S202_EVT_OEM13", "OEM13")), // + OEM14(new BitPoint(29, "S202_EVT_OEM14", "OEM14")), // + OEM15(new BitPoint(30, "S202_EVT_OEM15", "OEM15")); - private final int value; - private final String name; + private final BitPoint point; - private S202_Evt(int value, String name) { - this.value = value; - this.name = name; + private S202_Evt(BitPoint point) { + this.point = point; } @Override - public int getValue() { - return this.value; - } - - @Override - public String getName() { - return this.name; - } - - @Override - public OptionsEnum getUndefined() { - return UNDEFINED; + public BitPoint get() { + return this.point; } } public static enum S203 implements SunSpecPoint { - A(new PointImpl(// - "S203_A", // - "Amps", // + A(new ScaledValuePoint("S203_A", "Amps", // "Total AC Current", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - APH_A(new PointImpl(// - "S203_APH_A", // - "Amps PhaseA", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + APH_A(new ScaledValuePoint("S203_APH_A", "Amps PhaseA", // "Phase A Current", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - APH_B(new PointImpl(// - "S203_APH_B", // - "Amps PhaseB", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + APH_B(new ScaledValuePoint("S203_APH_B", "Amps PhaseB", // "Phase B Current", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - APH_C(new PointImpl(// - "S203_APH_C", // - "Amps PhaseC", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + APH_C(new ScaledValuePoint("S203_APH_C", "Amps PhaseC", // "Phase C Current", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - A_SF(new PointImpl(// - "S203_A_SF", // - "", // - "Current scale factor", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - PH_V(new PointImpl(// - "S203_PH_V", // - "Voltage LN", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + A_SF(new ScaleFactorPoint("S203_A_SF", "", // + "Current scale factor")), // + PH_V(new ScaledValuePoint("S203_PH_V", "Voltage LN", // "Line to Neutral AC Voltage (average of active phases)", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_A(new PointImpl(// - "S203_PH_VPH_A", // - "Phase Voltage AN", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_A(new ScaledValuePoint("S203_PH_VPH_A", "Phase Voltage AN", // "Phase Voltage AN", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_B(new PointImpl(// - "S203_PH_VPH_B", // - "Phase Voltage BN", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_B(new ScaledValuePoint("S203_PH_VPH_B", "Phase Voltage BN", // "Phase Voltage BN", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_C(new PointImpl(// - "S203_PH_VPH_C", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_C(new ScaledValuePoint("S203_PH_VPH_C", "Phase Voltage CN", // "Phase Voltage CN", // - "Phase Voltage CN", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PPV(new PointImpl(// - "S203_PPV", // - "Voltage LL", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PPV(new ScaledValuePoint("S203_PPV", "Voltage LL", // "Line to Line AC Voltage (average of active phases)", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_A_B(new PointImpl(// - "S203_PH_VPH_A_B", // - "Phase Voltage AB", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_A_B(new ScaledValuePoint("S203_PH_VPH_A_B", "Phase Voltage AB", // "Phase Voltage AB", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_B_C(new PointImpl(// - "S203_PH_VPH_B_C", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_B_C(new ScaledValuePoint("S203_PH_VPH_B_C", "Phase Voltage BC", // "Phase Voltage BC", // - "Phase Voltage BC", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_C_A(new PointImpl(// - "S203_PH_VPH_C_A", // - "Phase Voltage CA", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_C_A(new ScaledValuePoint("S203_PH_VPH_C_A", "Phase Voltage CA", // "Phase Voltage CA", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - V_SF(new PointImpl(// - "S203_V_SF", // - "", // - "Voltage scale factor", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - HZ(new PointImpl(// - "S203_HZ", // - "Hz", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + V_SF(new ScaleFactorPoint("S203_V_SF", "", // + "Voltage scale factor")), // + HZ(new ScaledValuePoint("S203_HZ", "Hz", // "Frequency", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.HERTZ, // - "Hz_SF", // - new OptionsEnum[0])), // - HZ_S_F(new PointImpl(// - "S203_HZ_S_F", // - "", // - "Frequency scale factor", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - W(new PointImpl(// - "S203_W", // - "Watts", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.HERTZ, "Hz_SF")), // + HZ_S_F(new ScaleFactorPoint("S203_HZ_S_F", "", // + "Frequency scale factor")), // + W(new ScaledValuePoint("S203_W", "Watts", // "Total Real Power", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - WPH_A(new PointImpl(// - "S203_WPH_A", // - "Watts phase A", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - WPH_B(new PointImpl(// - "S203_WPH_B", // - "Watts phase B", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - WPH_C(new PointImpl(// - "S203_WPH_C", // - "Watts phase C", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - W_SF(new PointImpl(// - "S203_W_SF", // - "", // - "Real Power scale factor", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - VA(new PointImpl(// - "S203_VA", // - "VA", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + WPH_A(new ScaledValuePoint("S203_WPH_A", "Watts phase A", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + WPH_B(new ScaledValuePoint("S203_WPH_B", "Watts phase B", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + WPH_C(new ScaledValuePoint("S203_WPH_C", "Watts phase C", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + W_SF(new ScaleFactorPoint("S203_W_SF", "", // + "Real Power scale factor")), // + VA(new ScaledValuePoint("S203_VA", "VA", // "AC Apparent Power", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE, // - "VA_SF", // - new OptionsEnum[0])), // - V_APH_A(new PointImpl(// - "S203_V_APH_A", // - "VA phase A", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE, // - "VA_SF", // - new OptionsEnum[0])), // - V_APH_B(new PointImpl(// - "S203_V_APH_B", // - "VA phase B", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE, // - "VA_SF", // - new OptionsEnum[0])), // - V_APH_C(new PointImpl(// - "S203_V_APH_C", // - "VA phase C", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE, // - "VA_SF", // - new OptionsEnum[0])), // - VA_SF(new PointImpl(// - "S203_VA_SF", // - "", // - "Apparent Power scale factor", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - VAR(new PointImpl(// - "S203_VAR", // - "VAR", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + V_APH_A(new ScaledValuePoint("S203_V_APH_A", "VA phase A", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + V_APH_B(new ScaledValuePoint("S203_V_APH_B", "VA phase B", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + V_APH_C(new ScaledValuePoint("S203_V_APH_C", "VA phase C", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + VA_SF(new ScaleFactorPoint("S203_VA_SF", "", // + "Apparent Power scale factor")), // + VAR(new ScaledValuePoint("S203_VAR", "VAR", // "Reactive Power", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "VAR_SF", // - new OptionsEnum[0])), // - V_A_RPH_A(new PointImpl(// - "S203_V_A_RPH_A", // - "VAR phase A", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "VAR_SF", // - new OptionsEnum[0])), // - V_A_RPH_B(new PointImpl(// - "S203_V_A_RPH_B", // - "VAR phase B", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "VAR_SF", // - new OptionsEnum[0])), // - V_A_RPH_C(new PointImpl(// - "S203_V_A_RPH_C", // - "VAR phase C", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "VAR_SF", // - new OptionsEnum[0])), // - VAR_SF(new PointImpl(// - "S203_VAR_SF", // - "", // - "Reactive Power scale factor", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - PF(new PointImpl(// - "S203_PF", // - "PF", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + V_A_RPH_A(new ScaledValuePoint("S203_V_A_RPH_A", "VAR phase A", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + V_A_RPH_B(new ScaledValuePoint("S203_V_A_RPH_B", "VAR phase B", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + V_A_RPH_C(new ScaledValuePoint("S203_V_A_RPH_C", "VAR phase C", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + VAR_SF(new ScaleFactorPoint("S203_VAR_SF", "", // + "Reactive Power scale factor")), // + PF(new ScaledValuePoint("S203_PF", "PF", // "Power Factor", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "PF_SF", // - new OptionsEnum[0])), // - P_FPH_A(new PointImpl(// - "S203_P_FPH_A", // - "PF phase A", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "PF_SF", // - new OptionsEnum[0])), // - P_FPH_B(new PointImpl(// - "S203_P_FPH_B", // - "PF phase B", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "PF_SF", // - new OptionsEnum[0])), // - P_FPH_C(new PointImpl(// - "S203_P_FPH_C", // - "PF phase C", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "PF_SF", // - new OptionsEnum[0])), // - PF_SF(new PointImpl(// - "S203_PF_SF", // - "", // - "Power Factor scale factor", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TOT_WH_EXP(new PointImpl(// - "S203_TOT_WH_EXP", // - "Total Watt-hours Exported", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + P_FPH_A(new ScaledValuePoint("S203_P_FPH_A", "PF phase A", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + P_FPH_B(new ScaledValuePoint("S203_P_FPH_B", "PF phase B", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + P_FPH_C(new ScaledValuePoint("S203_P_FPH_C", "PF phase C", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + PF_SF(new ScaleFactorPoint("S203_PF_SF", "", // + "Power Factor scale factor")), // + TOT_WH_EXP(new ScaledValuePoint("S203_TOT_WH_EXP", "Total Watt-hours Exported", // "Total Real Energy Exported", // - "", // - PointType.ACC32, // - true, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_EXP_PH_A(new PointImpl(// - "S203_TOT_WH_EXP_PH_A", // - "Total Watt-hours Exported phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_EXP_PH_B(new PointImpl(// - "S203_TOT_WH_EXP_PH_B", // - "Total Watt-hours Exported phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_EXP_PH_C(new PointImpl(// - "S203_TOT_WH_EXP_PH_C", // - "Total Watt-hours Exported phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_IMP(new PointImpl(// - "S203_TOT_WH_IMP", // - "Total Watt-hours Imported", // + ValuePoint.Type.ACC32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_EXP_PH_A(new ScaledValuePoint("S203_TOT_WH_EXP_PH_A", "Total Watt-hours Exported phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_EXP_PH_B(new ScaledValuePoint("S203_TOT_WH_EXP_PH_B", "Total Watt-hours Exported phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_EXP_PH_C(new ScaledValuePoint("S203_TOT_WH_EXP_PH_C", "Total Watt-hours Exported phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_IMP(new ScaledValuePoint("S203_TOT_WH_IMP", "Total Watt-hours Imported", // "Total Real Energy Imported", // - "", // - PointType.ACC32, // - true, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_IMP_PH_A(new PointImpl(// - "S203_TOT_WH_IMP_PH_A", // - "Total Watt-hours Imported phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_IMP_PH_B(new PointImpl(// - "S203_TOT_WH_IMP_PH_B", // - "Total Watt-hours Imported phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_IMP_PH_C(new PointImpl(// - "S203_TOT_WH_IMP_PH_C", // - "Total Watt-hours Imported phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_S_F(new PointImpl(// - "S203_TOT_WH_S_F", // - "", // - "Real Energy scale factor", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TOT_V_AH_EXP(new PointImpl(// - "S203_TOT_V_AH_EXP", // - "Total VA-hours Exported", // + ValuePoint.Type.ACC32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_IMP_PH_A(new ScaledValuePoint("S203_TOT_WH_IMP_PH_A", "Total Watt-hours Imported phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_IMP_PH_B(new ScaledValuePoint("S203_TOT_WH_IMP_PH_B", "Total Watt-hours Imported phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_IMP_PH_C(new ScaledValuePoint("S203_TOT_WH_IMP_PH_C", "Total Watt-hours Imported phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_S_F(new ScaleFactorPoint("S203_TOT_WH_S_F", "", // + "Real Energy scale factor")), // + TOT_V_AH_EXP(new ScaledValuePoint("S203_TOT_V_AH_EXP", "Total VA-hours Exported", // "Total Apparent Energy Exported", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_EXP_PH_A(new PointImpl(// - "S203_TOT_V_AH_EXP_PH_A", // - "Total VA-hours Exported phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_EXP_PH_B(new PointImpl(// - "S203_TOT_V_AH_EXP_PH_B", // - "Total VA-hours Exported phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_EXP_PH_C(new PointImpl(// - "S203_TOT_V_AH_EXP_PH_C", // - "Total VA-hours Exported phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_IMP(new PointImpl(// - "S203_TOT_V_AH_IMP", // - "Total VA-hours Imported", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_EXP_PH_A(new ScaledValuePoint("S203_TOT_V_AH_EXP_PH_A", "Total VA-hours Exported phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_EXP_PH_B(new ScaledValuePoint("S203_TOT_V_AH_EXP_PH_B", "Total VA-hours Exported phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_EXP_PH_C(new ScaledValuePoint("S203_TOT_V_AH_EXP_PH_C", "Total VA-hours Exported phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_IMP(new ScaledValuePoint("S203_TOT_V_AH_IMP", "Total VA-hours Imported", // "Total Apparent Energy Imported", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_IMP_PH_A(new PointImpl(// - "S203_TOT_V_AH_IMP_PH_A", // - "Total VA-hours Imported phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_IMP_PH_B(new PointImpl(// - "S203_TOT_V_AH_IMP_PH_B", // - "Total VA-hours Imported phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_IMP_PH_C(new PointImpl(// - "S203_TOT_V_AH_IMP_PH_C", // - "Total VA-hours Imported phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_S_F(new PointImpl(// - "S203_TOT_V_AH_S_F", // - "", // - "Apparent Energy scale factor", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q1(new PointImpl(// - "S203_TOT_V_ARH_IMP_Q1", // - "Total VAR-hours Imported Q1", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_IMP_PH_A(new ScaledValuePoint("S203_TOT_V_AH_IMP_PH_A", "Total VA-hours Imported phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_IMP_PH_B(new ScaledValuePoint("S203_TOT_V_AH_IMP_PH_B", "Total VA-hours Imported phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_IMP_PH_C(new ScaledValuePoint("S203_TOT_V_AH_IMP_PH_C", "Total VA-hours Imported phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_S_F(new ScaleFactorPoint("S203_TOT_V_AH_S_F", "", // + "Apparent Energy scale factor")), // + TOT_V_ARH_IMP_Q1(new ScaledValuePoint("S203_TOT_V_ARH_IMP_Q1", "Total VAR-hours Imported Q1", // "Total Reactive Energy Imported Quadrant 1", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q1_PH_A(new PointImpl(// - "S203_TOT_V_ARH_IMP_Q1_PH_A", // - "Total VAr-hours Imported Q1 phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q1_PH_B(new PointImpl(// - "S203_TOT_V_ARH_IMP_Q1_PH_B", // - "Total VAr-hours Imported Q1 phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q1_PH_C(new PointImpl(// - "S203_TOT_V_ARH_IMP_Q1_PH_C", // - "Total VAr-hours Imported Q1 phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q2(new PointImpl(// - "S203_TOT_V_ARH_IMP_Q2", // - "Total VAr-hours Imported Q2", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q1_PH_A(new ScaledValuePoint("S203_TOT_V_ARH_IMP_Q1_PH_A", "Total VAr-hours Imported Q1 phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q1_PH_B(new ScaledValuePoint("S203_TOT_V_ARH_IMP_Q1_PH_B", "Total VAr-hours Imported Q1 phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q1_PH_C(new ScaledValuePoint("S203_TOT_V_ARH_IMP_Q1_PH_C", "Total VAr-hours Imported Q1 phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q2(new ScaledValuePoint("S203_TOT_V_ARH_IMP_Q2", "Total VAr-hours Imported Q2", // "Total Reactive Power Imported Quadrant 2", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q2_PH_A(new PointImpl(// - "S203_TOT_V_ARH_IMP_Q2_PH_A", // - "Total VAr-hours Imported Q2 phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q2_PH_B(new PointImpl(// - "S203_TOT_V_ARH_IMP_Q2_PH_B", // - "Total VAr-hours Imported Q2 phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q2_PH_C(new PointImpl(// - "S203_TOT_V_ARH_IMP_Q2_PH_C", // - "Total VAr-hours Imported Q2 phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q3(new PointImpl(// - "S203_TOT_V_ARH_EXP_Q3", // - "Total VAr-hours Exported Q3", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q2_PH_A(new ScaledValuePoint("S203_TOT_V_ARH_IMP_Q2_PH_A", "Total VAr-hours Imported Q2 phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q2_PH_B(new ScaledValuePoint("S203_TOT_V_ARH_IMP_Q2_PH_B", "Total VAr-hours Imported Q2 phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q2_PH_C(new ScaledValuePoint("S203_TOT_V_ARH_IMP_Q2_PH_C", "Total VAr-hours Imported Q2 phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q3(new ScaledValuePoint("S203_TOT_V_ARH_EXP_Q3", "Total VAr-hours Exported Q3", // "Total Reactive Power Exported Quadrant 3", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q3_PH_A(new PointImpl(// - "S203_TOT_V_ARH_EXP_Q3_PH_A", // - "Total VAr-hours Exported Q3 phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q3_PH_B(new PointImpl(// - "S203_TOT_V_ARH_EXP_Q3_PH_B", // - "Total VAr-hours Exported Q3 phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q3_PH_C(new PointImpl(// - "S203_TOT_V_ARH_EXP_Q3_PH_C", // - "Total VAr-hours Exported Q3 phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q4(new PointImpl(// - "S203_TOT_V_ARH_EXP_Q4", // - "Total VAr-hours Exported Q4", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q3_PH_A(new ScaledValuePoint("S203_TOT_V_ARH_EXP_Q3_PH_A", "Total VAr-hours Exported Q3 phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q3_PH_B(new ScaledValuePoint("S203_TOT_V_ARH_EXP_Q3_PH_B", "Total VAr-hours Exported Q3 phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q3_PH_C(new ScaledValuePoint("S203_TOT_V_ARH_EXP_Q3_PH_C", "Total VAr-hours Exported Q3 phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q4(new ScaledValuePoint("S203_TOT_V_ARH_EXP_Q4", "Total VAr-hours Exported Q4", // "Total Reactive Power Exported Quadrant 4", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q4_PH_A(new PointImpl(// - "S203_TOT_V_ARH_EXP_Q4_PH_A", // - "Total VAr-hours Exported Q4 Imported phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q4_PH_B(new PointImpl(// - "S203_TOT_V_ARH_EXP_Q4_PH_B", // - "Total VAr-hours Exported Q4 Imported phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q4_PH_C(new PointImpl(// - "S203_TOT_V_ARH_EXP_Q4_PH_C", // - "Total VAr-hours Exported Q4 Imported phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_S_F(new PointImpl(// - "S203_TOT_V_ARH_S_F", // - "", // - "Reactive Energy scale factor", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT(new PointImpl(// - "S203_EVT", // - "Events", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q4_PH_A(new ScaledValuePoint("S203_TOT_V_ARH_EXP_Q4_PH_A", "Total VAr-hours Exported Q4 Imported phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q4_PH_B(new ScaledValuePoint("S203_TOT_V_ARH_EXP_Q4_PH_B", "Total VAr-hours Exported Q4 Imported phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q4_PH_C(new ScaledValuePoint("S203_TOT_V_ARH_EXP_Q4_PH_C", "Total VAr-hours Exported Q4 Imported phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_S_F(new ScaleFactorPoint("S203_TOT_V_ARH_S_F", "", // + "Reactive Energy scale factor")), // + EVT(new BitFieldPoint("S203_EVT", "Events", // "Meter Event Flags", // - "", // - PointType.BITFIELD32, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S203_Evt.values())); // + BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, S203_Evt.values())); - protected final PointImpl impl; + private final Point point; - private S203(PointImpl impl) { - this.impl = impl; + private S203(Point point) { + this.point = point; } @Override - public PointImpl get() { - return this.impl; + public Point get() { + return this.point; } } - public static enum S203_Evt implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - POWER_FAILURE(2, "POWER_FAILURE"), // - UNDER_VOLTAGE(3, "UNDER_VOLTAGE"), // - LOW_P_F(4, "LOW_P_F"), // - OVER_CURRENT(5, "OVER_CURRENT"), // - OVER_VOLTAGE(6, "OVER_VOLTAGE"), // - MISSING_SENSOR(7, "MISSING_SENSOR"), // - RESERVED1(8, "RESERVED1"), // - RESERVED2(9, "RESERVED2"), // - RESERVED3(10, "RESERVED3"), // - RESERVED4(11, "RESERVED4"), // - RESERVED5(12, "RESERVED5"), // - RESERVED6(13, "RESERVED6"), // - RESERVED7(14, "RESERVED7"), // - RESERVED8(15, "RESERVED8"), // - OEM01(16, "OEM01"), // - OEM02(17, "OEM02"), // - OEM03(18, "OEM03"), // - OEM04(19, "OEM04"), // - OEM05(20, "OEM05"), // - OEM06(21, "OEM06"), // - OEM07(22, "OEM07"), // - OEM08(23, "OEM08"), // - OEM09(24, "OEM09"), // - OEM10(25, "OEM10"), // - OEM11(26, "OEM11"), // - OEM12(27, "OEM12"), // - OEM13(28, "OEM13"), // - OEM14(29, "OEM14"), // - OEM15(30, "OEM15"); // - - private final int value; - private final String name; + public static enum S203_Evt implements SunSpecBitPoint { + POWER_FAILURE(new BitPoint(2, "S203_EVT_POWER_FAILURE", "Power_Failure")), // + UNDER_VOLTAGE(new BitPoint(3, "S203_EVT_UNDER_VOLTAGE", "Under_Voltage")), // + LOW_P_F(new BitPoint(4, "S203_EVT_LOW_P_F", "Low_PF")), // + OVER_CURRENT(new BitPoint(5, "S203_EVT_OVER_CURRENT", "Over_Current")), // + OVER_VOLTAGE(new BitPoint(6, "S203_EVT_OVER_VOLTAGE", "Over_Voltage")), // + MISSING_SENSOR(new BitPoint(7, "S203_EVT_MISSING_SENSOR", "Missing_Sensor")), // + RESERVED1(new BitPoint(8, "S203_EVT_RESERVED1", "Reserved1")), // + RESERVED2(new BitPoint(9, "S203_EVT_RESERVED2", "Reserved2")), // + RESERVED3(new BitPoint(10, "S203_EVT_RESERVED3", "Reserved3")), // + RESERVED4(new BitPoint(11, "S203_EVT_RESERVED4", "Reserved4")), // + RESERVED5(new BitPoint(12, "S203_EVT_RESERVED5", "Reserved5")), // + RESERVED6(new BitPoint(13, "S203_EVT_RESERVED6", "Reserved6")), // + RESERVED7(new BitPoint(14, "S203_EVT_RESERVED7", "Reserved7")), // + RESERVED8(new BitPoint(15, "S203_EVT_RESERVED8", "Reserved8")), // + OEM01(new BitPoint(16, "S203_EVT_OEM01", "OEM01")), // + OEM02(new BitPoint(17, "S203_EVT_OEM02", "OEM02")), // + OEM03(new BitPoint(18, "S203_EVT_OEM03", "OEM03")), // + OEM04(new BitPoint(19, "S203_EVT_OEM04", "OEM04")), // + OEM05(new BitPoint(20, "S203_EVT_OEM05", "OEM05")), // + OEM06(new BitPoint(21, "S203_EVT_OEM06", "OEM06")), // + OEM07(new BitPoint(22, "S203_EVT_OEM07", "OEM07")), // + OEM08(new BitPoint(23, "S203_EVT_OEM08", "OEM08")), // + OEM09(new BitPoint(24, "S203_EVT_OEM09", "OEM09")), // + OEM10(new BitPoint(25, "S203_EVT_OEM10", "OEM10")), // + OEM11(new BitPoint(26, "S203_EVT_OEM11", "OEM11")), // + OEM12(new BitPoint(27, "S203_EVT_OEM12", "OEM12")), // + OEM13(new BitPoint(28, "S203_EVT_OEM13", "OEM13")), // + OEM14(new BitPoint(29, "S203_EVT_OEM14", "OEM14")), // + OEM15(new BitPoint(30, "S203_EVT_OEM15", "OEM15")); - private S203_Evt(int value, String name) { - this.value = value; - this.name = name; - } - - @Override - public int getValue() { - return this.value; - } + private final BitPoint point; - @Override - public String getName() { - return this.name; + private S203_Evt(BitPoint point) { + this.point = point; } @Override - public OptionsEnum getUndefined() { - return UNDEFINED; + public BitPoint get() { + return this.point; } } public static enum S204 implements SunSpecPoint { - A(new PointImpl(// - "S204_A", // - "Amps", // + A(new ScaledValuePoint("S204_A", "Amps", // "Total AC Current", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - APH_A(new PointImpl(// - "S204_APH_A", // - "Amps PhaseA", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + APH_A(new ScaledValuePoint("S204_APH_A", "Amps PhaseA", // "Phase A Current", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - APH_B(new PointImpl(// - "S204_APH_B", // - "Amps PhaseB", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + APH_B(new ScaledValuePoint("S204_APH_B", "Amps PhaseB", // "Phase B Current", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - APH_C(new PointImpl(// - "S204_APH_C", // - "Amps PhaseC", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + APH_C(new ScaledValuePoint("S204_APH_C", "Amps PhaseC", // "Phase C Current", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - A_SF(new PointImpl(// - "S204_A_SF", // - "", // - "Current scale factor", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - PH_V(new PointImpl(// - "S204_PH_V", // - "Voltage LN", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + A_SF(new ScaleFactorPoint("S204_A_SF", "", // + "Current scale factor")), // + PH_V(new ScaledValuePoint("S204_PH_V", "Voltage LN", // "Line to Neutral AC Voltage (average of active phases)", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_A(new PointImpl(// - "S204_PH_VPH_A", // - "Phase Voltage AN", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_A(new ScaledValuePoint("S204_PH_VPH_A", "Phase Voltage AN", // "Phase Voltage AN", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_B(new PointImpl(// - "S204_PH_VPH_B", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_B(new ScaledValuePoint("S204_PH_VPH_B", "Phase Voltage BN", // "Phase Voltage BN", // - "Phase Voltage BN", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_C(new PointImpl(// - "S204_PH_VPH_C", // - "Phase Voltage CN", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_C(new ScaledValuePoint("S204_PH_VPH_C", "Phase Voltage CN", // "Phase Voltage CN", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PPV(new PointImpl(// - "S204_PPV", // - "Voltage LL", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PPV(new ScaledValuePoint("S204_PPV", "Voltage LL", // "Line to Line AC Voltage (average of active phases)", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_A_B(new PointImpl(// - "S204_PH_VPH_A_B", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_A_B(new ScaledValuePoint("S204_PH_VPH_A_B", "Phase Voltage AB", // "Phase Voltage AB", // - "Phase Voltage AB", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_B_C(new PointImpl(// - "S204_PH_VPH_B_C", // - "Phase Voltage BC", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_B_C(new ScaledValuePoint("S204_PH_VPH_B_C", "Phase Voltage BC", // "Phase Voltage BC", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - PH_VPH_C_A(new PointImpl(// - "S204_PH_VPH_C_A", // - "Phase Voltage CA", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + PH_VPH_C_A(new ScaledValuePoint("S204_PH_VPH_C_A", "Phase Voltage CA", // "Phase Voltage CA", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - V_SF(new PointImpl(// - "S204_V_SF", // - "", // - "Voltage scale factor", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - HZ(new PointImpl(// - "S204_HZ", // - "Hz", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + V_SF(new ScaleFactorPoint("S204_V_SF", "", // + "Voltage scale factor")), // + HZ(new ScaledValuePoint("S204_HZ", "Hz", // "Frequency", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.HERTZ, // - "Hz_SF", // - new OptionsEnum[0])), // - HZ_S_F(new PointImpl(// - "S204_HZ_S_F", // - "", // - "Frequency scale factor", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - W(new PointImpl(// - "S204_W", // - "Watts", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.HERTZ, "Hz_SF")), // + HZ_S_F(new ScaleFactorPoint("S204_HZ_S_F", "", // + "Frequency scale factor")), // + W(new ScaledValuePoint("S204_W", "Watts", // "Total Real Power", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - WPH_A(new PointImpl(// - "S204_WPH_A", // - "Watts phase A", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - WPH_B(new PointImpl(// - "S204_WPH_B", // - "Watts phase B", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - WPH_C(new PointImpl(// - "S204_WPH_C", // - "Watts phase C", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - W_SF(new PointImpl(// - "S204_W_SF", // - "", // - "Real Power scale factor", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - VA(new PointImpl(// - "S204_VA", // - "VA", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + WPH_A(new ScaledValuePoint("S204_WPH_A", "Watts phase A", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + WPH_B(new ScaledValuePoint("S204_WPH_B", "Watts phase B", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + WPH_C(new ScaledValuePoint("S204_WPH_C", "Watts phase C", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + W_SF(new ScaleFactorPoint("S204_W_SF", "", // + "Real Power scale factor")), // + VA(new ScaledValuePoint("S204_VA", "VA", // "AC Apparent Power", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE, // - "VA_SF", // - new OptionsEnum[0])), // - V_APH_A(new PointImpl(// - "S204_V_APH_A", // - "VA phase A", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE, // - "VA_SF", // - new OptionsEnum[0])), // - V_APH_B(new PointImpl(// - "S204_V_APH_B", // - "VA phase B", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE, // - "VA_SF", // - new OptionsEnum[0])), // - V_APH_C(new PointImpl(// - "S204_V_APH_C", // - "VA phase C", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE, // - "VA_SF", // - new OptionsEnum[0])), // - VA_SF(new PointImpl(// - "S204_VA_SF", // - "", // - "Apparent Power scale factor", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - VAR(new PointImpl(// - "S204_VAR", // - "VAR", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + V_APH_A(new ScaledValuePoint("S204_V_APH_A", "VA phase A", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + V_APH_B(new ScaledValuePoint("S204_V_APH_B", "VA phase B", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + V_APH_C(new ScaledValuePoint("S204_V_APH_C", "VA phase C", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + VA_SF(new ScaleFactorPoint("S204_VA_SF", "", // + "Apparent Power scale factor")), // + VAR(new ScaledValuePoint("S204_VAR", "VAR", // "Reactive Power", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "VAR_SF", // - new OptionsEnum[0])), // - V_A_RPH_A(new PointImpl(// - "S204_V_A_RPH_A", // - "VAR phase A", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "VAR_SF", // - new OptionsEnum[0])), // - V_A_RPH_B(new PointImpl(// - "S204_V_A_RPH_B", // - "VAR phase B", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "VAR_SF", // - new OptionsEnum[0])), // - V_A_RPH_C(new PointImpl(// - "S204_V_A_RPH_C", // - "VAR phase C", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "VAR_SF", // - new OptionsEnum[0])), // - VAR_SF(new PointImpl(// - "S204_VAR_SF", // - "", // - "Reactive Power scale factor", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - PF(new PointImpl(// - "S204_PF", // - "PF", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + V_A_RPH_A(new ScaledValuePoint("S204_V_A_RPH_A", "VAR phase A", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + V_A_RPH_B(new ScaledValuePoint("S204_V_A_RPH_B", "VAR phase B", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + V_A_RPH_C(new ScaledValuePoint("S204_V_A_RPH_C", "VAR phase C", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + VAR_SF(new ScaleFactorPoint("S204_VAR_SF", "", // + "Reactive Power scale factor")), // + PF(new ScaledValuePoint("S204_PF", "PF", // "Power Factor", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "PF_SF", // - new OptionsEnum[0])), // - P_FPH_A(new PointImpl(// - "S204_P_FPH_A", // - "PF phase A", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "PF_SF", // - new OptionsEnum[0])), // - P_FPH_B(new PointImpl(// - "S204_P_FPH_B", // - "PF phase B", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "PF_SF", // - new OptionsEnum[0])), // - P_FPH_C(new PointImpl(// - "S204_P_FPH_C", // - "PF phase C", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "PF_SF", // - new OptionsEnum[0])), // - PF_SF(new PointImpl(// - "S204_PF_SF", // - "", // - "Power Factor scale factor", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TOT_WH_EXP(new PointImpl(// - "S204_TOT_WH_EXP", // - "Total Watt-hours Exported", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + P_FPH_A(new ScaledValuePoint("S204_P_FPH_A", "PF phase A", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + P_FPH_B(new ScaledValuePoint("S204_P_FPH_B", "PF phase B", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + P_FPH_C(new ScaledValuePoint("S204_P_FPH_C", "PF phase C", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + PF_SF(new ScaleFactorPoint("S204_PF_SF", "", // + "Power Factor scale factor")), // + TOT_WH_EXP(new ScaledValuePoint("S204_TOT_WH_EXP", "Total Watt-hours Exported", // "Total Real Energy Exported", // - "", // - PointType.ACC32, // - true, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_EXP_PH_A(new PointImpl(// - "S204_TOT_WH_EXP_PH_A", // - "Total Watt-hours Exported phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_EXP_PH_B(new PointImpl(// - "S204_TOT_WH_EXP_PH_B", // - "Total Watt-hours Exported phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_EXP_PH_C(new PointImpl(// - "S204_TOT_WH_EXP_PH_C", // - "Total Watt-hours Exported phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_IMP(new PointImpl(// - "S204_TOT_WH_IMP", // - "Total Watt-hours Imported", // + ValuePoint.Type.ACC32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_EXP_PH_A(new ScaledValuePoint("S204_TOT_WH_EXP_PH_A", "Total Watt-hours Exported phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_EXP_PH_B(new ScaledValuePoint("S204_TOT_WH_EXP_PH_B", "Total Watt-hours Exported phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_EXP_PH_C(new ScaledValuePoint("S204_TOT_WH_EXP_PH_C", "Total Watt-hours Exported phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_IMP(new ScaledValuePoint("S204_TOT_WH_IMP", "Total Watt-hours Imported", // "Total Real Energy Imported", // - "", // - PointType.ACC32, // - true, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_IMP_PH_A(new PointImpl(// - "S204_TOT_WH_IMP_PH_A", // - "Total Watt-hours Imported phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_IMP_PH_B(new PointImpl(// - "S204_TOT_WH_IMP_PH_B", // - "Total Watt-hours Imported phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_IMP_PH_C(new PointImpl(// - "S204_TOT_WH_IMP_PH_C", // - "Total Watt-hours Imported phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_S_F(new PointImpl(// - "S204_TOT_WH_S_F", // - "", // - "Real Energy scale factor", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TOT_V_AH_EXP(new PointImpl(// - "S204_TOT_V_AH_EXP", // - "Total VA-hours Exported", // + ValuePoint.Type.ACC32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_IMP_PH_A(new ScaledValuePoint("S204_TOT_WH_IMP_PH_A", "Total Watt-hours Imported phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_IMP_PH_B(new ScaledValuePoint("S204_TOT_WH_IMP_PH_B", "Total Watt-hours Imported phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_IMP_PH_C(new ScaledValuePoint("S204_TOT_WH_IMP_PH_C", "Total Watt-hours Imported phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_S_F(new ScaleFactorPoint("S204_TOT_WH_S_F", "", // + "Real Energy scale factor")), // + TOT_V_AH_EXP(new ScaledValuePoint("S204_TOT_V_AH_EXP", "Total VA-hours Exported", // "Total Apparent Energy Exported", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_EXP_PH_A(new PointImpl(// - "S204_TOT_V_AH_EXP_PH_A", // - "Total VA-hours Exported phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_EXP_PH_B(new PointImpl(// - "S204_TOT_V_AH_EXP_PH_B", // - "Total VA-hours Exported phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_EXP_PH_C(new PointImpl(// - "S204_TOT_V_AH_EXP_PH_C", // - "Total VA-hours Exported phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_IMP(new PointImpl(// - "S204_TOT_V_AH_IMP", // - "Total VA-hours Imported", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_EXP_PH_A(new ScaledValuePoint("S204_TOT_V_AH_EXP_PH_A", "Total VA-hours Exported phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_EXP_PH_B(new ScaledValuePoint("S204_TOT_V_AH_EXP_PH_B", "Total VA-hours Exported phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_EXP_PH_C(new ScaledValuePoint("S204_TOT_V_AH_EXP_PH_C", "Total VA-hours Exported phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_IMP(new ScaledValuePoint("S204_TOT_V_AH_IMP", "Total VA-hours Imported", // "Total Apparent Energy Imported", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_IMP_PH_A(new PointImpl(// - "S204_TOT_V_AH_IMP_PH_A", // - "Total VA-hours Imported phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_IMP_PH_B(new PointImpl(// - "S204_TOT_V_AH_IMP_PH_B", // - "Total VA-hours Imported phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_IMP_PH_C(new PointImpl(// - "S204_TOT_V_AH_IMP_PH_C", // - "Total VA-hours Imported phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_HOURS, // - "TotVAh_SF", // - new OptionsEnum[0])), // - TOT_V_AH_S_F(new PointImpl(// - "S204_TOT_V_AH_S_F", // - "", // - "Apparent Energy scale factor", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q1(new PointImpl(// - "S204_TOT_V_ARH_IMP_Q1", // - "Total VAR-hours Imported Q1", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_IMP_PH_A(new ScaledValuePoint("S204_TOT_V_AH_IMP_PH_A", "Total VA-hours Imported phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_IMP_PH_B(new ScaledValuePoint("S204_TOT_V_AH_IMP_PH_B", "Total VA-hours Imported phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_IMP_PH_C(new ScaledValuePoint("S204_TOT_V_AH_IMP_PH_C", "Total VA-hours Imported phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + TOT_V_AH_S_F(new ScaleFactorPoint("S204_TOT_V_AH_S_F", "", // + "Apparent Energy scale factor")), // + TOT_V_ARH_IMP_Q1(new ScaledValuePoint("S204_TOT_V_ARH_IMP_Q1", "Total VAR-hours Imported Q1", // "Total Reactive Energy Imported Quadrant 1", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q1_PH_A(new PointImpl(// - "S204_TOT_V_ARH_IMP_Q1_PH_A", // - "Total VAr-hours Imported Q1 phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q1_PH_B(new PointImpl(// - "S204_TOT_V_ARH_IMP_Q1_PH_B", // - "Total VAr-hours Imported Q1 phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q1_PH_C(new PointImpl(// - "S204_TOT_V_ARH_IMP_Q1_PH_C", // - "Total VAr-hours Imported Q1 phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q2(new PointImpl(// - "S204_TOT_V_ARH_IMP_Q2", // - "Total VAr-hours Imported Q2", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q1_PH_A(new ScaledValuePoint("S204_TOT_V_ARH_IMP_Q1_PH_A", "Total VAr-hours Imported Q1 phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q1_PH_B(new ScaledValuePoint("S204_TOT_V_ARH_IMP_Q1_PH_B", "Total VAr-hours Imported Q1 phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q1_PH_C(new ScaledValuePoint("S204_TOT_V_ARH_IMP_Q1_PH_C", "Total VAr-hours Imported Q1 phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q2(new ScaledValuePoint("S204_TOT_V_ARH_IMP_Q2", "Total VAr-hours Imported Q2", // "Total Reactive Power Imported Quadrant 2", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q2_PH_A(new PointImpl(// - "S204_TOT_V_ARH_IMP_Q2_PH_A", // - "Total VAr-hours Imported Q2 phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q2_PH_B(new PointImpl(// - "S204_TOT_V_ARH_IMP_Q2_PH_B", // - "Total VAr-hours Imported Q2 phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_IMP_Q2_PH_C(new PointImpl(// - "S204_TOT_V_ARH_IMP_Q2_PH_C", // - "Total VAr-hours Imported Q2 phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q3(new PointImpl(// - "S204_TOT_V_ARH_EXP_Q3", // - "Total VAr-hours Exported Q3", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q2_PH_A(new ScaledValuePoint("S204_TOT_V_ARH_IMP_Q2_PH_A", "Total VAr-hours Imported Q2 phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q2_PH_B(new ScaledValuePoint("S204_TOT_V_ARH_IMP_Q2_PH_B", "Total VAr-hours Imported Q2 phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q2_PH_C(new ScaledValuePoint("S204_TOT_V_ARH_IMP_Q2_PH_C", "Total VAr-hours Imported Q2 phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q3(new ScaledValuePoint("S204_TOT_V_ARH_EXP_Q3", "Total VAr-hours Exported Q3", // "Total Reactive Power Exported Quadrant 3", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q3_PH_A(new PointImpl(// - "S204_TOT_V_ARH_EXP_Q3_PH_A", // - "Total VAr-hours Exported Q3 phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q3_PH_B(new PointImpl(// - "S204_TOT_V_ARH_EXP_Q3_PH_B", // - "Total VAr-hours Exported Q3 phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q3_PH_C(new PointImpl(// - "S204_TOT_V_ARH_EXP_Q3_PH_C", // - "Total VAr-hours Exported Q3 phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q4(new PointImpl(// - "S204_TOT_V_ARH_EXP_Q4", // - "Total VAr-hours Exported Q4", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q3_PH_A(new ScaledValuePoint("S204_TOT_V_ARH_EXP_Q3_PH_A", "Total VAr-hours Exported Q3 phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q3_PH_B(new ScaledValuePoint("S204_TOT_V_ARH_EXP_Q3_PH_B", "Total VAr-hours Exported Q3 phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q3_PH_C(new ScaledValuePoint("S204_TOT_V_ARH_EXP_Q3_PH_C", "Total VAr-hours Exported Q3 phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q4(new ScaledValuePoint("S204_TOT_V_ARH_EXP_Q4", "Total VAr-hours Exported Q4", // "Total Reactive Power Exported Quadrant 4", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q4_PH_A(new PointImpl(// - "S204_TOT_V_ARH_EXP_Q4_PH_A", // - "Total VAr-hours Exported Q4 Imported phase A", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q4_PH_B(new PointImpl(// - "S204_TOT_V_ARH_EXP_Q4_PH_B", // - "Total VAr-hours Exported Q4 Imported phase B", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_EXP_Q4_PH_C(new PointImpl(// - "S204_TOT_V_ARH_EXP_Q4_PH_C", // - "Total VAr-hours Exported Q4 Imported phase C", // - "", // - "", // - PointType.ACC32, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVArh_SF", // - new OptionsEnum[0])), // - TOT_V_ARH_S_F(new PointImpl(// - "S204_TOT_V_ARH_S_F", // - "", // - "Reactive Energy scale factor", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT(new PointImpl(// - "S204_EVT", // - "Events", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q4_PH_A(new ScaledValuePoint("S204_TOT_V_ARH_EXP_Q4_PH_A", "Total VAr-hours Exported Q4 Imported phase A", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q4_PH_B(new ScaledValuePoint("S204_TOT_V_ARH_EXP_Q4_PH_B", "Total VAr-hours Exported Q4 Imported phase B", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q4_PH_C(new ScaledValuePoint("S204_TOT_V_ARH_EXP_Q4_PH_C", "Total VAr-hours Exported Q4 Imported phase C", "", // + ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_S_F(new ScaleFactorPoint("S204_TOT_V_ARH_S_F", "", // + "Reactive Energy scale factor")), // + EVT(new BitFieldPoint("S204_EVT", "Events", // "Meter Event Flags", // - "", // - PointType.BITFIELD32, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S204_Evt.values())); // + BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, S204_Evt.values())); - protected final PointImpl impl; + private final Point point; - private S204(PointImpl impl) { - this.impl = impl; + private S204(Point point) { + this.point = point; } @Override - public PointImpl get() { - return this.impl; + public Point get() { + return this.point; } } - public static enum S204_Evt implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - POWER_FAILURE(2, "POWER_FAILURE"), // - UNDER_VOLTAGE(3, "UNDER_VOLTAGE"), // - LOW_P_F(4, "LOW_P_F"), // - OVER_CURRENT(5, "OVER_CURRENT"), // - OVER_VOLTAGE(6, "OVER_VOLTAGE"), // - MISSING_SENSOR(7, "MISSING_SENSOR"), // - RESERVED1(8, "RESERVED1"), // - RESERVED2(9, "RESERVED2"), // - RESERVED3(10, "RESERVED3"), // - RESERVED4(11, "RESERVED4"), // - RESERVED5(12, "RESERVED5"), // - RESERVED6(13, "RESERVED6"), // - RESERVED7(14, "RESERVED7"), // - RESERVED8(15, "RESERVED8"), // - OEM01(16, "OEM01"), // - OEM02(17, "OEM02"), // - OEM03(18, "OEM03"), // - OEM04(19, "OEM04"), // - OEM05(20, "OEM05"), // - OEM06(21, "OEM06"), // - OEM07(22, "OEM07"), // - OEM08(23, "OEM08"), // - OEM09(24, "OEM09"), // - OEM10(25, "OEM10"), // - OEM11(26, "OEM11"), // - OEM12(27, "OEM12"), // - OEM13(28, "OEM13"), // - OEM14(29, "OEM14"), // - OEM15(30, "OEM15"); // + public static enum S204_Evt implements SunSpecBitPoint { + POWER_FAILURE(new BitPoint(2, "S204_EVT_POWER_FAILURE", "Power_Failure")), // + UNDER_VOLTAGE(new BitPoint(3, "S204_EVT_UNDER_VOLTAGE", "Under_Voltage")), // + LOW_P_F(new BitPoint(4, "S204_EVT_LOW_P_F", "Low_PF")), // + OVER_CURRENT(new BitPoint(5, "S204_EVT_OVER_CURRENT", "Over_Current")), // + OVER_VOLTAGE(new BitPoint(6, "S204_EVT_OVER_VOLTAGE", "Over_Voltage")), // + MISSING_SENSOR(new BitPoint(7, "S204_EVT_MISSING_SENSOR", "Missing_Sensor")), // + RESERVED1(new BitPoint(8, "S204_EVT_RESERVED1", "Reserved1")), // + RESERVED2(new BitPoint(9, "S204_EVT_RESERVED2", "Reserved2")), // + RESERVED3(new BitPoint(10, "S204_EVT_RESERVED3", "Reserved3")), // + RESERVED4(new BitPoint(11, "S204_EVT_RESERVED4", "Reserved4")), // + RESERVED5(new BitPoint(12, "S204_EVT_RESERVED5", "Reserved5")), // + RESERVED6(new BitPoint(13, "S204_EVT_RESERVED6", "Reserved6")), // + RESERVED7(new BitPoint(14, "S204_EVT_RESERVED7", "Reserved7")), // + RESERVED8(new BitPoint(15, "S204_EVT_RESERVED8", "Reserved8")), // + OEM01(new BitPoint(16, "S204_EVT_OEM01", "OEM01")), // + OEM02(new BitPoint(17, "S204_EVT_OEM02", "OEM02")), // + OEM03(new BitPoint(18, "S204_EVT_OEM03", "OEM03")), // + OEM04(new BitPoint(19, "S204_EVT_OEM04", "OEM04")), // + OEM05(new BitPoint(20, "S204_EVT_OEM05", "OEM05")), // + OEM06(new BitPoint(21, "S204_EVT_OEM06", "OEM06")), // + OEM07(new BitPoint(22, "S204_EVT_OEM07", "OEM07")), // + OEM08(new BitPoint(23, "S204_EVT_OEM08", "OEM08")), // + OEM09(new BitPoint(24, "S204_EVT_OEM09", "OEM09")), // + OEM10(new BitPoint(25, "S204_EVT_OEM10", "OEM10")), // + OEM11(new BitPoint(26, "S204_EVT_OEM11", "OEM11")), // + OEM12(new BitPoint(27, "S204_EVT_OEM12", "OEM12")), // + OEM13(new BitPoint(28, "S204_EVT_OEM13", "OEM13")), // + OEM14(new BitPoint(29, "S204_EVT_OEM14", "OEM14")), // + OEM15(new BitPoint(30, "S204_EVT_OEM15", "OEM15")); - private final int value; - private final String name; + private final BitPoint point; - private S204_Evt(int value, String name) { - this.value = value; - this.name = name; + private S204_Evt(BitPoint point) { + this.point = point; } @Override - public int getValue() { - return this.value; - } - - @Override - public String getName() { - return this.name; - } - - @Override - public OptionsEnum getUndefined() { - return UNDEFINED; + public BitPoint get() { + return this.point; } } public static enum S305 implements SunSpecPoint { - TM(new PointImpl(// - "S305_TM", // - "Tm", // + TM(new ValuePoint("S305_TM", "Tm", // "UTC 24 hour time stamp to millisecond hhmmss.sssZ format", // - "", // - PointType.STRING6, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - DATE(new PointImpl(// - "S305_DATE", // - "Date", // + ValuePoint.Type.STRING6, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + DATE(new ValuePoint("S305_DATE", "Date", // "UTC Date string YYYYMMDD format", // - "", // - PointType.STRING4, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - LOC(new PointImpl(// - "S305_LOC", // - "Location", // + ValuePoint.Type.STRING4, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + LOC(new ValuePoint("S305_LOC", "Location", // "Location string (40 chars max)", // - "", // - PointType.STRING20, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - LAT(new PointImpl(// - "S305_LAT", // - "Lat", // + ValuePoint.Type.STRING20, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + LAT(new ScaledValuePoint("S305_LAT", "Lat", // "Latitude with seven degrees of precision", // - "", // - PointType.INT32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "-7", // - new OptionsEnum[0])), // - LONG(new PointImpl(// - "S305_LONG", // - "Long", // + ValuePoint.Type.INT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "-7")), // + LONG(new ScaledValuePoint("S305_LONG", "Long", // "Longitude with seven degrees of precision", // - "", // - PointType.INT32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "-7", // - new OptionsEnum[0])), // - ALT(new PointImpl(// - "S305_ALT", // - "Altitude", // + ValuePoint.Type.INT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "-7")), // + ALT(new ValuePoint("S305_ALT", "Altitude", // "Altitude measurement in meters", // - "", // - PointType.INT32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // + ValuePoint.Type.INT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)); - protected final PointImpl impl; + private final Point point; - private S305(PointImpl impl) { - this.impl = impl; + private S305(Point point) { + this.point = point; } @Override - public PointImpl get() { - return this.impl; + public Point get() { + return this.point; } } public static enum S306 implements SunSpecPoint { - GHI(new PointImpl(// - "S306_GHI", // - "GHI", // + GHI(new ValuePoint("S306_GHI", "GHI", // "Global Horizontal Irradiance", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - A(new PointImpl(// - "S306_A", // - "Amps", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + A(new ValuePoint("S306_A", "Amps", // "Current measurement at reference point", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - V(new PointImpl(// - "S306_V", // - "Voltage", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + V(new ValuePoint("S306_V", "Voltage", // "Voltage measurement at reference point", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TMP(new PointImpl(// - "S306_TMP", // - "Temperature", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + TMP(new ValuePoint("S306_TMP", "Temperature", // "Temperature measurement at reference point", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)); - protected final PointImpl impl; + private final Point point; - private S306(PointImpl impl) { - this.impl = impl; + private S306(Point point) { + this.point = point; } @Override - public PointImpl get() { - return this.impl; + public Point get() { + return this.point; } } public static enum S307 implements SunSpecPoint { - TMP_AMB(new PointImpl(// - "S307_TMP_AMB", // - "Ambient Temperature", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - "-1", // - new OptionsEnum[0])), // - RH(new PointImpl(// - "S307_RH", // - "Relative Humidity", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - PRES(new PointImpl(// - "S307_PRES", // - "Barometric Pressure", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - WND_SPD(new PointImpl(// - "S307_WND_SPD", // - "Wind Speed", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - WND_DIR(new PointImpl(// - "S307_WND_DIR", // - "Wind Direction", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - RAIN(new PointImpl(// - "S307_RAIN", // - "Rainfall", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - SNW(new PointImpl(// - "S307_SNW", // - "Snow Depth", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - PPT(new PointImpl(// - "S307_PPT", // - "Precipitation Type", // + TMP_AMB(new ScaledValuePoint("S307_TMP_AMB", "Ambient Temperature", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "-1")), // + RH(new ValuePoint("S307_RH", "Relative Humidity", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + PRES(new ValuePoint("S307_PRES", "Barometric Pressure", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + WND_SPD(new ValuePoint("S307_WND_SPD", "Wind Speed", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + WND_DIR(new ValuePoint("S307_WND_DIR", "Wind Direction", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + RAIN(new ValuePoint("S307_RAIN", "Rainfall", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + SNW(new ValuePoint("S307_SNW", "Snow Depth", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + PPT(new ValuePoint("S307_PPT", "Precipitation Type", // "Precipitation Type (WMO 4680 SYNOP code reference)", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - ELEC_FLD(new PointImpl(// - "S307_ELEC_FLD", // - "Electric Field", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - SUR_WET(new PointImpl(// - "S307_SUR_WET", // - "Surface Wetness", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - SOIL_WET(new PointImpl(// - "S307_SOIL_WET", // - "Soil Wetness", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // - - protected final PointImpl impl; - - private S307(PointImpl impl) { - this.impl = impl; - } - - @Override - public PointImpl get() { - return this.impl; + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + ELEC_FLD(new ValuePoint("S307_ELEC_FLD", "Electric Field", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + SUR_WET(new ValuePoint("S307_SUR_WET", "Surface Wetness", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + SOIL_WET(new ValuePoint("S307_SOIL_WET", "Soil Wetness", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)); + + private final Point point; + + private S307(Point point) { + this.point = point; + } + + @Override + public Point get() { + return this.point; } } public static enum S308 implements SunSpecPoint { - GHI(new PointImpl(// - "S308_GHI", // - "GHI", // + GHI(new ValuePoint("S308_GHI", "GHI", // "Global Horizontal Irradiance", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TMP_B_O_M(new PointImpl(// - "S308_TMP_B_O_M", // - "Temp", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + TMP_B_O_M(new ScaledValuePoint("S308_TMP_B_O_M", "Temp", // "Back of module temperature measurement", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - "-1", // - new OptionsEnum[0])), // - TMP_AMB(new PointImpl(// - "S308_TMP_AMB", // - "Ambient Temperature", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - "-1", // - new OptionsEnum[0])), // - WND_SPD(new PointImpl(// - "S308_WND_SPD", // - "Wind Speed", // - "", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // - - protected final PointImpl impl; - - private S308(PointImpl impl) { - this.impl = impl; - } - - @Override - public PointImpl get() { - return this.impl; + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "-1")), // + TMP_AMB(new ScaledValuePoint("S308_TMP_AMB", "Ambient Temperature", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "-1")), // + WND_SPD(new ValuePoint("S308_WND_SPD", "Wind Speed", "", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)); + + private final Point point; + + private S308(Point point) { + this.point = point; + } + + @Override + public Point get() { + return this.point; } } public static enum S701 implements SunSpecPoint { - A_C_TYPE(new PointImpl(// - "S701_A_C_TYPE", // - "AC Wiring Type", // + A_C_TYPE(new EnumPoint("S701_A_C_TYPE", "AC Wiring Type", // "AC wiring type.", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S701_ACType.values())), // - ST(new PointImpl(// - "S701_ST", // - "Operating State", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S701_ACType.values())), // + ST(new EnumPoint("S701_ST", "Operating State", // "Operating state of the DER.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S701_St.values())), // - INV_ST(new PointImpl(// - "S701_INV_ST", // - "Inverter State", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, S701_St.values())), // + INV_ST(new EnumPoint("S701_INV_ST", "Inverter State", // "Enumerated value. Inverter state.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S701_InvSt.values())), // - CONN_ST(new PointImpl(// - "S701_CONN_ST", // - "Grid Connection State", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, S701_InvSt.values())), // + CONN_ST(new EnumPoint("S701_CONN_ST", "Grid Connection State", // "Grid connection state of the DER.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S701_ConnSt.values())), // - ALRM(new PointImpl(// - "S701_ALRM", // - "Alarm Bitfield", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, S701_ConnSt.values())), // + ALRM(new BitFieldPoint("S701_ALRM", "Alarm Bitfield", // "Active alarms for the DER.", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S701_Alrm.values())), // - D_E_R_MODE(new PointImpl(// - "S701_D_E_R_MODE", // - "DER Operational Characteristics", // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, S701_Alrm.values())), // + D_E_R_MODE(new BitFieldPoint("S701_D_E_R_MODE", "DER Operational Characteristics", // "Current operational characteristics of the DER.", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S701_DERMode.values())), // - W(new PointImpl(// - "S701_W", // - "Active Power", // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, S701_DERMode.values())), // + W(new ScaledValuePoint("S701_W", "Active Power", // "Total active power. Active power is positive for DER generation and negative for absorption.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - VA(new PointImpl(// - "S701_VA", // - "Apparent Power", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + VA(new ScaledValuePoint("S701_VA", "Apparent Power", // "Total apparent power.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE, // - "VA_SF", // - new OptionsEnum[0])), // - VAR(new PointImpl(// - "S701_VAR", // - "Reactive Power", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + VAR(new ScaledValuePoint("S701_VAR", "Reactive Power", // "Total reactive power.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "Var_SF", // - new OptionsEnum[0])), // - PF(new PointImpl(// - "S701_PF", // - "Power Factor", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "Var_SF")), // + PF(new ScaledValuePoint("S701_PF", "Power Factor", // "Power factor. The sign of power factor should be the sign of active power.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "PF_SF", // - new OptionsEnum[0])), // - A(new PointImpl(// - "S701_A", // - "Total AC Current", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + A(new ScaledValuePoint("S701_A", "Total AC Current", // "Total AC current.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - LLV(new PointImpl(// - "S701_LLV", // - "Voltage LL", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + LLV(new ScaledValuePoint("S701_LLV", "Voltage LL", // "Line to line AC voltage as an average of active phases.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - LNV(new PointImpl(// - "S701_LNV", // - "Voltage LN", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + LNV(new ScaledValuePoint("S701_LNV", "Voltage LN", // "Line to neutral AC voltage as an average of active phases.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - HZ(new PointImpl(// - "S701_HZ", // - "Frequency", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + HZ(new ScaledValuePoint("S701_HZ", "Frequency", // "AC frequency.", // - "", // - PointType.UINT32, // - false, // - AccessMode.READ_ONLY, // - Unit.HERTZ, // - "Hz_SF", // - new OptionsEnum[0])), // - TOT_WH_INJ(new PointImpl(// - "S701_TOT_WH_INJ", // - "Total Energy Injected", // + ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.HERTZ, "Hz_SF")), // + TOT_WH_INJ(new ScaledValuePoint("S701_TOT_WH_INJ", "Total Energy Injected", // "Total active energy injected (Quadrants 1 & 4).", // - "", // - PointType.UINT64, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_ABS(new PointImpl(// - "S701_TOT_WH_ABS", // - "Total Energy Absorbed", // + ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_ABS(new ScaledValuePoint("S701_TOT_WH_ABS", "Total Energy Absorbed", // "Total active energy absorbed (Quadrants 2 & 3).", // - "", // - PointType.UINT64, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_VARH_INJ(new PointImpl(// - "S701_TOT_VARH_INJ", // - "Total Reactive Energy Inj", // + ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_VARH_INJ(new ScaledValuePoint("S701_TOT_VARH_INJ", "Total Reactive Energy Inj", // "Total reactive energy injected (Quadrants 1 & 2).", // - "", // - PointType.UINT64, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVarh_SF", // - new OptionsEnum[0])), // - TOT_VARH_ABS(new PointImpl(// - "S701_TOT_VARH_ABS", // - "Total Reactive Energy Abs", // + ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVarh_SF")), // + TOT_VARH_ABS(new ScaledValuePoint("S701_TOT_VARH_ABS", "Total Reactive Energy Abs", // "Total reactive energy absorbed (Quadrants 3 & 4).", // - "", // - PointType.UINT64, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVarh_SF", // - new OptionsEnum[0])), // - TMP_AMB(new PointImpl(// - "S701_TMP_AMB", // - "Ambient Temperature", // + ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVarh_SF")), // + TMP_AMB(new ScaledValuePoint("S701_TMP_AMB", "Ambient Temperature", // "Ambient temperature.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - "Tmp_SF", // - new OptionsEnum[0])), // - TMP_CAB(new PointImpl(// - "S701_TMP_CAB", // - "Cabinet Temperature", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + TMP_CAB(new ScaledValuePoint("S701_TMP_CAB", "Cabinet Temperature", // "Cabinet temperature.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - "Tmp_SF", // - new OptionsEnum[0])), // - TMP_SNK(new PointImpl(// - "S701_TMP_SNK", // - "Heat Sink Temperature", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + TMP_SNK(new ScaledValuePoint("S701_TMP_SNK", "Heat Sink Temperature", // "Heat sink temperature.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - "Tmp_SF", // - new OptionsEnum[0])), // - TMP_TRNS(new PointImpl(// - "S701_TMP_TRNS", // - "Transformer Temperature", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + TMP_TRNS(new ScaledValuePoint("S701_TMP_TRNS", "Transformer Temperature", // "Transformer temperature.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - "Tmp_SF", // - new OptionsEnum[0])), // - TMP_SW(new PointImpl(// - "S701_TMP_SW", // - "IGBT/MOSFET Temperature", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + TMP_SW(new ScaledValuePoint("S701_TMP_SW", "IGBT/MOSFET Temperature", // "IGBT/MOSFET temperature.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - "Tmp_SF", // - new OptionsEnum[0])), // - TMP_OT(new PointImpl(// - "S701_TMP_OT", // - "Other Temperature", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + TMP_OT(new ScaledValuePoint("S701_TMP_OT", "Other Temperature", // "Other temperature.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - "Tmp_SF", // - new OptionsEnum[0])), // - WL1(new PointImpl(// - "S701_WL1", // - "Watts L1", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + WL1(new ScaledValuePoint("S701_WL1", "Watts L1", // "Active power L1.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - VAL1(new PointImpl(// - "S701_VAL1", // - "VA L1", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + VAL1(new ScaledValuePoint("S701_VAL1", "VA L1", // "Apparent power L1.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE, // - "VA_SF", // - new OptionsEnum[0])), // - VAR_L1(new PointImpl(// - "S701_VAR_L1", // - "Var L1", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + VAR_L1(new ScaledValuePoint("S701_VAR_L1", "Var L1", // "Reactive power L1.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "Var_SF", // - new OptionsEnum[0])), // - PFL1(new PointImpl(// - "S701_PFL1", // - "PF L1", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "Var_SF")), // + PFL1(new ScaledValuePoint("S701_PFL1", "PF L1", // "Power factor phase L1.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "PF_SF", // - new OptionsEnum[0])), // - AL1(new PointImpl(// - "S701_AL1", // - "Amps L1", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + AL1(new ScaledValuePoint("S701_AL1", "Amps L1", // "Current phase L1.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - VL1L2(new PointImpl(// - "S701_VL1L2", // - "Phase Voltage L1-L2", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + VL1L2(new ScaledValuePoint("S701_VL1L2", "Phase Voltage L1-L2", // "Phase voltage L1-L2.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - VL1(new PointImpl(// - "S701_VL1", // - "Phase Voltage L1-N", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + VL1(new ScaledValuePoint("S701_VL1", "Phase Voltage L1-N", // "Phase voltage L1-N.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - TOT_WH_INJ_L1(new PointImpl(// - "S701_TOT_WH_INJ_L1", // - "Total Watt-Hours Inj L1", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + TOT_WH_INJ_L1(new ScaledValuePoint("S701_TOT_WH_INJ_L1", "Total Watt-Hours Inj L1", // "Total active energy injected L1.", // - "", // - PointType.UINT64, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_ABS_L1(new PointImpl(// - "S701_TOT_WH_ABS_L1", // - "Total Watt-Hours Abs L1", // + ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_ABS_L1(new ScaledValuePoint("S701_TOT_WH_ABS_L1", "Total Watt-Hours Abs L1", // "Total active energy absorbed L1.", // - "", // - PointType.UINT64, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_VARH_INJ_L1(new PointImpl(// - "S701_TOT_VARH_INJ_L1", // - "Total Var-Hours Inj L1", // + ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_VARH_INJ_L1(new ScaledValuePoint("S701_TOT_VARH_INJ_L1", "Total Var-Hours Inj L1", // "Total reactive energy injected L1.", // - "", // - PointType.UINT64, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVarh_SF", // - new OptionsEnum[0])), // - TOT_VARH_ABS_L1(new PointImpl(// - "S701_TOT_VARH_ABS_L1", // - "Total Var-Hours Abs L1", // + ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVarh_SF")), // + TOT_VARH_ABS_L1(new ScaledValuePoint("S701_TOT_VARH_ABS_L1", "Total Var-Hours Abs L1", // "Total reactive energy absorbed L1.", // - "", // - PointType.UINT64, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVarh_SF", // - new OptionsEnum[0])), // - WL2(new PointImpl(// - "S701_WL2", // - "Watts L2", // + ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVarh_SF")), // + WL2(new ScaledValuePoint("S701_WL2", "Watts L2", // "Active power L2.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - VAL2(new PointImpl(// - "S701_VAL2", // - "VA L2", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + VAL2(new ScaledValuePoint("S701_VAL2", "VA L2", // "Apparent power L2.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE, // - "VA_SF", // - new OptionsEnum[0])), // - VAR_L2(new PointImpl(// - "S701_VAR_L2", // - "Var L2", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + VAR_L2(new ScaledValuePoint("S701_VAR_L2", "Var L2", // "Reactive power L2.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "Var_SF", // - new OptionsEnum[0])), // - PFL2(new PointImpl(// - "S701_PFL2", // - "PF L2", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "Var_SF")), // + PFL2(new ScaledValuePoint("S701_PFL2", "PF L2", // "Power factor L2.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "PF_SF", // - new OptionsEnum[0])), // - AL2(new PointImpl(// - "S701_AL2", // - "Amps L2", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + AL2(new ScaledValuePoint("S701_AL2", "Amps L2", // "Current L2.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - VL2L3(new PointImpl(// - "S701_VL2L3", // - "Phase Voltage L2-L3", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + VL2L3(new ScaledValuePoint("S701_VL2L3", "Phase Voltage L2-L3", // "Phase voltage L2-L3.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - VL2(new PointImpl(// - "S701_VL2", // - "Phase Voltage L2-N", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + VL2(new ScaledValuePoint("S701_VL2", "Phase Voltage L2-N", // "Phase voltage L2-N.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - TOT_WH_INJ_L2(new PointImpl(// - "S701_TOT_WH_INJ_L2", // - "Total Watt-Hours Inj L2", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + TOT_WH_INJ_L2(new ScaledValuePoint("S701_TOT_WH_INJ_L2", "Total Watt-Hours Inj L2", // "Total active energy injected L2.", // - "", // - PointType.UINT64, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_ABS_L2(new PointImpl(// - "S701_TOT_WH_ABS_L2", // - "Total Watt-Hours Abs L2", // + ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_ABS_L2(new ScaledValuePoint("S701_TOT_WH_ABS_L2", "Total Watt-Hours Abs L2", // "Total active energy absorbed L2.", // - "", // - PointType.UINT64, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_VARH_INJ_L2(new PointImpl(// - "S701_TOT_VARH_INJ_L2", // - "Total Var-Hours Inj L2", // + ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_VARH_INJ_L2(new ScaledValuePoint("S701_TOT_VARH_INJ_L2", "Total Var-Hours Inj L2", // "Total reactive energy injected L2.", // - "", // - PointType.UINT64, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVarh_SF", // - new OptionsEnum[0])), // - TOT_VARH_ABS_L2(new PointImpl(// - "S701_TOT_VARH_ABS_L2", // - "Total Var-Hours Abs L2", // + ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVarh_SF")), // + TOT_VARH_ABS_L2(new ScaledValuePoint("S701_TOT_VARH_ABS_L2", "Total Var-Hours Abs L2", // "Total reactive energy absorbed L2.", // - "", // - PointType.UINT64, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVarh_SF", // - new OptionsEnum[0])), // - WL3(new PointImpl(// - "S701_WL3", // - "Watts L3", // + ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVarh_SF")), // + WL3(new ScaledValuePoint("S701_WL3", "Watts L3", // "Active power L3.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - VAL3(new PointImpl(// - "S701_VAL3", // - "VA L3", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + VAL3(new ScaledValuePoint("S701_VAL3", "VA L3", // "Apparent power L3.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE, // - "VA_SF", // - new OptionsEnum[0])), // - VAR_L3(new PointImpl(// - "S701_VAR_L3", // - "Var L3", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + VAR_L3(new ScaledValuePoint("S701_VAR_L3", "Var L3", // "Reactive power L3.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "Var_SF", // - new OptionsEnum[0])), // - PFL3(new PointImpl(// - "S701_PFL3", // - "PF L3", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "Var_SF")), // + PFL3(new ScaledValuePoint("S701_PFL3", "PF L3", // "Power factor L3.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "PF_SF", // - new OptionsEnum[0])), // - AL3(new PointImpl(// - "S701_AL3", // - "Amps L3", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + AL3(new ScaledValuePoint("S701_AL3", "Amps L3", // "Current L3.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - VL3L1(new PointImpl(// - "S701_VL3L1", // - "Phase Voltage L3-L1", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + VL3L1(new ScaledValuePoint("S701_VL3L1", "Phase Voltage L3-L1", // "Phase voltage L3-L1.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - VL3(new PointImpl(// - "S701_VL3", // - "Phase Voltage L3-N", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + VL3(new ScaledValuePoint("S701_VL3", "Phase Voltage L3-N", // "Phase voltage L3-N.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - TOT_WH_INJ_L3(new PointImpl(// - "S701_TOT_WH_INJ_L3", // - "Total Watt-Hours Inj L3", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + TOT_WH_INJ_L3(new ScaledValuePoint("S701_TOT_WH_INJ_L3", "Total Watt-Hours Inj L3", // "Total active energy injected L3.", // - "", // - PointType.UINT64, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_WH_ABS_L3(new PointImpl(// - "S701_TOT_WH_ABS_L3", // - "Total Watt-Hours Abs L3", // + ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_WH_ABS_L3(new ScaledValuePoint("S701_TOT_WH_ABS_L3", "Total Watt-Hours Abs L3", // "Total active energy absorbed L3.", // - "", // - PointType.UINT64, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "TotWh_SF", // - new OptionsEnum[0])), // - TOT_VARH_INJ_L3(new PointImpl(// - "S701_TOT_VARH_INJ_L3", // - "Total Var-Hours Inj L3", // + ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + TOT_VARH_INJ_L3(new ScaledValuePoint("S701_TOT_VARH_INJ_L3", "Total Var-Hours Inj L3", // "Total reactive energy injected L3.", // - "", // - PointType.UINT64, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVarh_SF", // - new OptionsEnum[0])), // - TOT_VARH_ABS_L3(new PointImpl(// - "S701_TOT_VARH_ABS_L3", // - "Total Var-Hours Abs L3", // + ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVarh_SF")), // + TOT_VARH_ABS_L3(new ScaledValuePoint("S701_TOT_VARH_ABS_L3", "Total Var-Hours Abs L3", // "Total reactive energy absorbed L3.", // - "", // - PointType.UINT64, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE_HOURS, // - "TotVarh_SF", // - new OptionsEnum[0])), // - THROT_PCT(new PointImpl(// - "S701_THROT_PCT", // - "Throttling In Pct", // + ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVarh_SF")), // + THROT_PCT(new ValuePoint("S701_THROT_PCT", "Throttling In Pct", // "Throttling in pct of maximum active power.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - THROT_SRC(new PointImpl(// - "S701_THROT_SRC", // - "Throttle Source Information", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + THROT_SRC(new BitFieldPoint("S701_THROT_SRC", "Throttle Source Information", // "Active throttling source.", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S701_ThrotSrc.values())), // - A_SF(new PointImpl(// - "S701_A_SF", // - "Current Scale Factor", // - "Current scale factor.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - V_SF(new PointImpl(// - "S701_V_SF", // - "Voltage Scale Factor", // - "Voltage scale factor.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - HZ_S_F(new PointImpl(// - "S701_HZ_S_F", // - "Frequency Scale Factor", // - "Frequency scale factor.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - W_SF(new PointImpl(// - "S701_W_SF", // - "Active Power Scale Factor", // - "Active power scale factor.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - PF_SF(new PointImpl(// - "S701_PF_SF", // - "Power Factor Scale Factor", // - "Power factor scale factor.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - VA_SF(new PointImpl(// - "S701_VA_SF", // - "Apparent Power Scale Factor", // - "Apparent power scale factor.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - VAR_S_F(new PointImpl(// - "S701_VAR_S_F", // - "Reactive Power Scale Factor", // - "Reactive power scale factor.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TOT_WH_S_F(new PointImpl(// - "S701_TOT_WH_S_F", // - "Active Energy Scale Factor", // - "Active energy scale factor.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TOT_VARH_S_F(new PointImpl(// - "S701_TOT_VARH_S_F", // - "Reactive Energy Scale Factor", // - "Reactive energy scale factor.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TMP_S_F(new PointImpl(// - "S701_TMP_S_F", // - "Temperature Scale Factor", // - "Temperature scale factor.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - MN_ALRM_INFO(new PointImpl(// - "S701_MN_ALRM_INFO", // - "Manufacturer Alarm Info", // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, S701_ThrotSrc.values())), // + A_SF(new ScaleFactorPoint("S701_A_SF", "Current Scale Factor", // + "Current scale factor.")), // + V_SF(new ScaleFactorPoint("S701_V_SF", "Voltage Scale Factor", // + "Voltage scale factor.")), // + HZ_S_F(new ScaleFactorPoint("S701_HZ_S_F", "Frequency Scale Factor", // + "Frequency scale factor.")), // + W_SF(new ScaleFactorPoint("S701_W_SF", "Active Power Scale Factor", // + "Active power scale factor.")), // + PF_SF(new ScaleFactorPoint("S701_PF_SF", "Power Factor Scale Factor", // + "Power factor scale factor.")), // + VA_SF(new ScaleFactorPoint("S701_VA_SF", "Apparent Power Scale Factor", // + "Apparent power scale factor.")), // + VAR_S_F(new ScaleFactorPoint("S701_VAR_S_F", "Reactive Power Scale Factor", // + "Reactive power scale factor.")), // + TOT_WH_S_F(new ScaleFactorPoint("S701_TOT_WH_S_F", "Active Energy Scale Factor", // + "Active energy scale factor.")), // + TOT_VARH_S_F(new ScaleFactorPoint("S701_TOT_VARH_S_F", "Reactive Energy Scale Factor", // + "Reactive energy scale factor.")), // + TMP_S_F(new ScaleFactorPoint("S701_TMP_S_F", "Temperature Scale Factor", // + "Temperature scale factor.")), // + MN_ALRM_INFO(new ValuePoint("S701_MN_ALRM_INFO", "Manufacturer Alarm Info", // "Manufacturer alarm information. Valid if MANUFACTURER_ALRM indication is active.", // - "", // - PointType.STRING32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // + ValuePoint.Type.STRING32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)); - protected final PointImpl impl; + private final Point point; - private S701(PointImpl impl) { - this.impl = impl; + private S701(Point point) { + this.point = point; } @Override - public PointImpl get() { - return this.impl; + public Point get() { + return this.point; } } @@ -11167,7 +3886,7 @@ public static enum S701_ACType implements OptionsEnum { UNDEFINED(-1, "Undefined"), // SINGLE_PHASE(0, "SINGLE_PHASE"), // SPLIT_PHASE(1, "SPLIT_PHASE"), // - THREE_PHASE(2, "THREE_PHASE"); // + THREE_PHASE(2, "THREE_PHASE"); private final int value; private final String name; @@ -11196,7 +3915,7 @@ public OptionsEnum getUndefined() { public static enum S701_St implements OptionsEnum { UNDEFINED(-1, "Undefined"), // OFF(0, "OFF"), // - ON(1, "ON"); // + ON(1, "ON"); private final int value; private final String name; @@ -11231,7 +3950,7 @@ public static enum S701_InvSt implements OptionsEnum { THROTTLED(4, "THROTTLED"), // SHUTTING_DOWN(5, "SHUTTING_DOWN"), // FAULT(6, "FAULT"), // - STANDBY(7, "STANDBY"); // + STANDBY(7, "STANDBY"); private final int value; private final String name; @@ -11259,87 +3978,13 @@ public OptionsEnum getUndefined() { public static enum S701_ConnSt implements OptionsEnum { UNDEFINED(-1, "Undefined"), // - DISCONNECTED(0, "DISCONNECTED"), // - CONNECTED(1, "CONNECTED"); // - - private final int value; - private final String name; - - private S701_ConnSt(int value, String name) { - this.value = value; - this.name = name; - } - - @Override - public int getValue() { - return this.value; - } - - @Override - public String getName() { - return this.name; - } - - @Override - public OptionsEnum getUndefined() { - return UNDEFINED; - } - } - - public static enum S701_Alrm implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - GROUND_FAULT(0, "GROUND_FAULT"), // - DC_OVER_VOLT(1, "DC_OVER_VOLT"), // - AC_DISCONNECT(2, "AC_DISCONNECT"), // - DC_DISCONNECT(3, "DC_DISCONNECT"), // - GRID_DISCONNECT(4, "GRID_DISCONNECT"), // - CABINET_OPEN(5, "CABINET_OPEN"), // - MANUAL_SHUTDOWN(6, "MANUAL_SHUTDOWN"), // - OVER_TEMP(7, "OVER_TEMP"), // - OVER_FREQUENCY(8, "OVER_FREQUENCY"), // - UNDER_FREQUENCY(9, "UNDER_FREQUENCY"), // - AC_OVER_VOLT(10, "AC_OVER_VOLT"), // - AC_UNDER_VOLT(11, "AC_UNDER_VOLT"), // - BLOWN_STRING_FUSE(12, "BLOWN_STRING_FUSE"), // - UNDER_TEMP(13, "UNDER_TEMP"), // - MEMORY_LOSS(14, "MEMORY_LOSS"), // - HW_TEST_FAILURE(15, "HW_TEST_FAILURE"), // - MANUFACTURER_ALRM(16, "MANUFACTURER_ALRM"); // - - private final int value; - private final String name; - - private S701_Alrm(int value, String name) { - this.value = value; - this.name = name; - } - - @Override - public int getValue() { - return this.value; - } - - @Override - public String getName() { - return this.name; - } - - @Override - public OptionsEnum getUndefined() { - return UNDEFINED; - } - } - - public static enum S701_DERMode implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - GRID_FOLLOWING(0, "GRID_FOLLOWING"), // - GRID_FORMING(1, "GRID_FORMING"), // - PV_CLIPPED(2, "PV_CLIPPED"); // + DISCONNECTED(0, "DISCONNECTED"), // + CONNECTED(1, "CONNECTED"); private final int value; private final String name; - private S701_DERMode(int value, String name) { + private S701_ConnSt(int value, String name) { this.value = value; this.name = name; } @@ -11360,605 +4005,241 @@ public OptionsEnum getUndefined() { } } - public static enum S701_ThrotSrc implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - MAX_W(0, "MAX_W"), // - FIXED_W(1, "FIXED_W"), // - FIXED_VAR(2, "FIXED_VAR"), // - FIXED_PF(3, "FIXED_PF"), // - VOLT_VAR(4, "VOLT_VAR"), // - FREQ_WATT(5, "FREQ_WATT"), // - DYN_REACT_CURR(6, "DYN_REACT_CURR"), // - LVRT(7, "LVRT"), // - HVRT(8, "HVRT"), // - WATT_VAR(9, "WATT_VAR"), // - VOLT_WATT(10, "VOLT_WATT"), // - SCHEDULED(11, "SCHEDULED"), // - LFRT(12, "LFRT"), // - HFRT(13, "HFRT"), // - DERATED(14, "DERATED"); // + public static enum S701_Alrm implements SunSpecBitPoint { + GROUND_FAULT(new BitPoint(0, "S701_ALRM_GROUND_FAULT", "Ground Fault")), // + DC_OVER_VOLT(new BitPoint(1, "S701_ALRM_DC_OVER_VOLT", "DC Over Volt")), // + AC_DISCONNECT(new BitPoint(2, "S701_ALRM_AC_DISCONNECT", "AC Disconnect")), // + DC_DISCONNECT(new BitPoint(3, "S701_ALRM_DC_DISCONNECT", "DC Disconnect")), // + GRID_DISCONNECT(new BitPoint(4, "S701_ALRM_GRID_DISCONNECT", "Grid Disconnect")), // + CABINET_OPEN(new BitPoint(5, "S701_ALRM_CABINET_OPEN", "Cabinet Open")), // + MANUAL_SHUTDOWN(new BitPoint(6, "S701_ALRM_MANUAL_SHUTDOWN", "Manual Shutdown")), // + OVER_TEMP(new BitPoint(7, "S701_ALRM_OVER_TEMP", "Over Temp")), // + OVER_FREQUENCY(new BitPoint(8, "S701_ALRM_OVER_FREQUENCY", "Over Frequency")), // + UNDER_FREQUENCY(new BitPoint(9, "S701_ALRM_UNDER_FREQUENCY", "Under Frequency")), // + AC_OVER_VOLT(new BitPoint(10, "S701_ALRM_AC_OVER_VOLT", "AC Over Volt")), // + AC_UNDER_VOLT(new BitPoint(11, "S701_ALRM_AC_UNDER_VOLT", "AC Under Volt")), // + BLOWN_STRING_FUSE(new BitPoint(12, "S701_ALRM_BLOWN_STRING_FUSE", "Blown String Fuse")), // + UNDER_TEMP(new BitPoint(13, "S701_ALRM_UNDER_TEMP", "Under Temp")), // + MEMORY_LOSS(new BitPoint(14, "S701_ALRM_MEMORY_LOSS", "Memory Loss")), // + HW_TEST_FAILURE(new BitPoint(15, "S701_ALRM_HW_TEST_FAILURE", "HW Test Failure")), // + MANUFACTURER_ALRM(new BitPoint(16, "S701_ALRM_MANUFACTURER_ALRM", "Manufacturer Alrm")); - private final int value; - private final String name; + private final BitPoint point; - private S701_ThrotSrc(int value, String name) { - this.value = value; - this.name = name; + private S701_Alrm(BitPoint point) { + this.point = point; } @Override - public int getValue() { - return this.value; + public BitPoint get() { + return this.point; + } + } + + public static enum S701_DERMode implements SunSpecBitPoint { + GRID_FOLLOWING(new BitPoint(0, "S701_D_E_R_MODE_GRID_FOLLOWING", "Grid Following")), // + GRID_FORMING(new BitPoint(1, "S701_D_E_R_MODE_GRID_FORMING", "Grid Forming")), // + PV_CLIPPED(new BitPoint(2, "S701_D_E_R_MODE_PV_CLIPPED", "Pv Clipped")); + + private final BitPoint point; + + private S701_DERMode(BitPoint point) { + this.point = point; } @Override - public String getName() { - return this.name; + public BitPoint get() { + return this.point; + } + } + + public static enum S701_ThrotSrc implements SunSpecBitPoint { + MAX_W(new BitPoint(0, "S701_THROT_SRC_MAX_W", "Max W")), // + FIXED_W(new BitPoint(1, "S701_THROT_SRC_FIXED_W", "Fixed W")), // + FIXED_VAR(new BitPoint(2, "S701_THROT_SRC_FIXED_VAR", "Fixed Var")), // + FIXED_PF(new BitPoint(3, "S701_THROT_SRC_FIXED_PF", "Fixed Pf")), // + VOLT_VAR(new BitPoint(4, "S701_THROT_SRC_VOLT_VAR", "Volt Var")), // + FREQ_WATT(new BitPoint(5, "S701_THROT_SRC_FREQ_WATT", "Freq Watt")), // + DYN_REACT_CURR(new BitPoint(6, "S701_THROT_SRC_DYN_REACT_CURR", "Dyn React Curr")), // + LVRT(new BitPoint(7, "S701_THROT_SRC_LVRT", "LVRT")), // + HVRT(new BitPoint(8, "S701_THROT_SRC_HVRT", "HVRT")), // + WATT_VAR(new BitPoint(9, "S701_THROT_SRC_WATT_VAR", "Watt Var")), // + VOLT_WATT(new BitPoint(10, "S701_THROT_SRC_VOLT_WATT", "Volt Watt")), // + SCHEDULED(new BitPoint(11, "S701_THROT_SRC_SCHEDULED", "SCHEDULED")), // + LFRT(new BitPoint(12, "S701_THROT_SRC_LFRT", "LFRT")), // + HFRT(new BitPoint(13, "S701_THROT_SRC_HFRT", "HFRT")), // + DERATED(new BitPoint(14, "S701_THROT_SRC_DERATED", "DERATED")); + + private final BitPoint point; + + private S701_ThrotSrc(BitPoint point) { + this.point = point; } @Override - public OptionsEnum getUndefined() { - return UNDEFINED; + public BitPoint get() { + return this.point; } } public static enum S702 implements SunSpecPoint { - W_MAX_RTG(new PointImpl(// - "S702_W_MAX_RTG", // - "Active Power Max Rating", // + W_MAX_RTG(new ScaledValuePoint("S702_W_MAX_RTG", "Active Power Max Rating", // "Maximum active power rating at unity power factor in watts.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - W_OVR_EXT_RTG(new PointImpl(// - "S702_W_OVR_EXT_RTG", // - "Active Power (Over-Excited) Rating", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + W_OVR_EXT_RTG(new ScaledValuePoint("S702_W_OVR_EXT_RTG", "Active Power (Over-Excited) Rating", // "Active power rating at specified over-excited power factor in watts.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - W_OVR_EXT_RTG_P_F(new PointImpl(// - "S702_W_OVR_EXT_RTG_P_F", // - "Specified Over-Excited PF", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + W_OVR_EXT_RTG_P_F(new ScaledValuePoint("S702_W_OVR_EXT_RTG_P_F", "Specified Over-Excited PF", // "Specified over-excited power factor.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "PF_SF", // - new OptionsEnum[0])), // - W_UND_EXT_RTG(new PointImpl(// - "S702_W_UND_EXT_RTG", // - "Active Power (Under-Excited) Rating", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + W_UND_EXT_RTG(new ScaledValuePoint("S702_W_UND_EXT_RTG", "Active Power (Under-Excited) Rating", // "Active power rating at specified under-excited power factor in watts.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - W_UND_EXT_RTG_P_F(new PointImpl(// - "S702_W_UND_EXT_RTG_P_F", // - "Specified Under-Excited PF", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + W_UND_EXT_RTG_P_F(new ScaledValuePoint("S702_W_UND_EXT_RTG_P_F", "Specified Under-Excited PF", // "Specified under-excited power factor.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "PF_SF", // - new OptionsEnum[0])), // - V_A_MAX_RTG(new PointImpl(// - "S702_V_A_MAX_RTG", // - "Apparent Power Max Rating", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + V_A_MAX_RTG(new ScaledValuePoint("S702_V_A_MAX_RTG", "Apparent Power Max Rating", // "Maximum apparent power rating in voltamperes.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE, // - "VA_SF", // - new OptionsEnum[0])), // - VAR_MAX_INJ_RTG(new PointImpl(// - "S702_VAR_MAX_INJ_RTG", // - "Reactive Power Injected Rating", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + VAR_MAX_INJ_RTG(new ScaledValuePoint("S702_VAR_MAX_INJ_RTG", "Reactive Power Injected Rating", // "Maximum injected reactive power rating in vars.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "Var_SF", // - new OptionsEnum[0])), // - VAR_MAX_ABS_RTG(new PointImpl(// - "S702_VAR_MAX_ABS_RTG", // - "Reactive Power Absorbed Rating", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "Var_SF")), // + VAR_MAX_ABS_RTG(new ScaledValuePoint("S702_VAR_MAX_ABS_RTG", "Reactive Power Absorbed Rating", // "Maximum absorbed reactive power rating in vars.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE_REACTIVE, // - "Var_SF", // - new OptionsEnum[0])), // - W_CHA_RTE_MAX_RTG(new PointImpl(// - "S702_W_CHA_RTE_MAX_RTG", // - "Charge Rate Max Rating", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "Var_SF")), // + W_CHA_RTE_MAX_RTG(new ScaledValuePoint("S702_W_CHA_RTE_MAX_RTG", "Charge Rate Max Rating", // "Maximum active power charge rate in watts.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - W_DIS_CHA_RTE_MAX_RTG(new PointImpl(// - "S702_W_DIS_CHA_RTE_MAX_RTG", // - "Discharge Rate Max Rating", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + W_DIS_CHA_RTE_MAX_RTG(new ScaledValuePoint("S702_W_DIS_CHA_RTE_MAX_RTG", "Discharge Rate Max Rating", // "Maximum active power discharge rate in watts.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - V_A_CHA_RTE_MAX_RTG(new PointImpl(// - "S702_V_A_CHA_RTE_MAX_RTG", // - "Charge Rate Max VA Rating", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + V_A_CHA_RTE_MAX_RTG(new ScaledValuePoint("S702_V_A_CHA_RTE_MAX_RTG", "Charge Rate Max VA Rating", // "Maximum apparent power charge rate in voltamperes.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE, // - "VA_SF", // - new OptionsEnum[0])), // - V_A_DIS_CHA_RTE_MAX_RTG(new PointImpl(// - "S702_V_A_DIS_CHA_RTE_MAX_RTG", // - "Discharge Rate Max VA Rating", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + V_A_DIS_CHA_RTE_MAX_RTG(new ScaledValuePoint("S702_V_A_DIS_CHA_RTE_MAX_RTG", "Discharge Rate Max VA Rating", // "Maximum apparent power discharge rate in voltamperes.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT_AMPERE, // - "VA_SF", // - new OptionsEnum[0])), // - V_NOM_RTG(new PointImpl(// - "S702_V_NOM_RTG", // - "AC Voltage Nominal Rating", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + V_NOM_RTG(new ScaledValuePoint("S702_V_NOM_RTG", "AC Voltage Nominal Rating", // "AC voltage nominal rating.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - V_MAX_RTG(new PointImpl(// - "S702_V_MAX_RTG", // - "AC Voltage Max Rating", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + V_MAX_RTG(new ScaledValuePoint("S702_V_MAX_RTG", "AC Voltage Max Rating", // "AC voltage maximum rating.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - V_MIN_RTG(new PointImpl(// - "S702_V_MIN_RTG", // - "AC Voltage Min Rating", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + V_MIN_RTG(new ScaledValuePoint("S702_V_MIN_RTG", "AC Voltage Min Rating", // "AC voltage minimum rating.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - A_MAX_RTG(new PointImpl(// - "S702_A_MAX_RTG", // - "AC Current Max Rating", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + A_MAX_RTG(new ScaledValuePoint("S702_A_MAX_RTG", "AC Current Max Rating", // "AC current maximum rating in amps.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - P_F_OVR_EXT_RTG(new PointImpl(// - "S702_P_F_OVR_EXT_RTG", // - "PF Over-Excited Rating", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + P_F_OVR_EXT_RTG(new ScaledValuePoint("S702_P_F_OVR_EXT_RTG", "PF Over-Excited Rating", // "Power factor over-excited rating.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "PF_SF", // - new OptionsEnum[0])), // - P_F_UND_EXT_RTG(new PointImpl(// - "S702_P_F_UND_EXT_RTG", // - "PF Under-Excited Rating", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + P_F_UND_EXT_RTG(new ScaledValuePoint("S702_P_F_UND_EXT_RTG", "PF Under-Excited Rating", // "Power factor under-excited rating.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "PF_SF", // - new OptionsEnum[0])), // - REACT_SUSCEPT_RTG(new PointImpl(// - "S702_REACT_SUSCEPT_RTG", // - "Reactive Susceptance", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + REACT_SUSCEPT_RTG(new ScaledValuePoint("S702_REACT_SUSCEPT_RTG", "Reactive Susceptance", // "Reactive susceptance that remains connected to the Area EPS in the cease to energize and trip state.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "S_SF", // - new OptionsEnum[0])), // - NOR_OP_CAT_RTG(new PointImpl(// - "S702_NOR_OP_CAT_RTG", // - "Normal Operating Category", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "S_SF")), // + NOR_OP_CAT_RTG(new EnumPoint("S702_NOR_OP_CAT_RTG", "Normal Operating Category", // "Normal operating performance category as specified in IEEE 1547-2018.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S702_NorOpCatRtg.values())), // - ABN_OP_CAT_RTG(new PointImpl(// - "S702_ABN_OP_CAT_RTG", // - "Abnormal Operating Category", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, S702_NorOpCatRtg.values())), // + ABN_OP_CAT_RTG(new EnumPoint("S702_ABN_OP_CAT_RTG", "Abnormal Operating Category", // "Abnormal operating performance category as specified in IEEE 1547-2018.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S702_AbnOpCatRtg.values())), // - CTRL_MODES(new PointImpl(// - "S702_CTRL_MODES", // - "Supported Control Modes", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, S702_AbnOpCatRtg.values())), // + CTRL_MODES(new BitFieldPoint("S702_CTRL_MODES", "Supported Control Modes", // "Supported control mode functions.", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S702_CtrlModes.values())), // - INT_ISLAND_CAT_RTG(new PointImpl(// - "S702_INT_ISLAND_CAT_RTG", // - "Intentional Island Categories", // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, S702_CtrlModes.values())), // + INT_ISLAND_CAT_RTG(new BitFieldPoint("S702_INT_ISLAND_CAT_RTG", "Intentional Island Categories", // "Intentional island categories.", // - "", // - PointType.BITFIELD16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S702_IntIslandCatRtg.values())), // - W_MAX(new PointImpl(// - "S702_W_MAX", // - "Active Power Max Setting", // + BitFieldPoint.Type.BITFIELD16, false /* mandatory? */, AccessMode.READ_ONLY, S702_IntIslandCatRtg.values())), // + W_MAX(new ScaledValuePoint("S702_W_MAX", "Active Power Max Setting", // "Maximum active power setting used to adjust maximum active power setting.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - W_MAX_OVR_EXT(new PointImpl(// - "S702_W_MAX_OVR_EXT", // - "Active Power (Over-Excited) Setting", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.WATT, "W_SF")), // + W_MAX_OVR_EXT(new ScaledValuePoint("S702_W_MAX_OVR_EXT", "Active Power (Over-Excited) Setting", // "Active power setting at specified over-excited power factor in watts.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - W_OVR_EXT_P_F(new PointImpl(// - "S702_W_OVR_EXT_P_F", // - "Specified Over-Excited PF", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.WATT, "W_SF")), // + W_OVR_EXT_P_F(new ScaledValuePoint("S702_W_OVR_EXT_P_F", "Specified Over-Excited PF", // "Specified over-excited power factor.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - "PF_SF", // - new OptionsEnum[0])), // - W_MAX_UND_EXT(new PointImpl(// - "S702_W_MAX_UND_EXT", // - "Active Power (Under-Excited) Setting", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "PF_SF")), // + W_MAX_UND_EXT(new ScaledValuePoint("S702_W_MAX_UND_EXT", "Active Power (Under-Excited) Setting", // "Active power setting at specified under-excited power factor in watts.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - W_UND_EXT_P_F(new PointImpl(// - "S702_W_UND_EXT_P_F", // - "Specified Under-Excited PF", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.WATT, "W_SF")), // + W_UND_EXT_P_F(new ScaledValuePoint("S702_W_UND_EXT_P_F", "Specified Under-Excited PF", // "Specified under-excited power factor.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - "PF_SF", // - new OptionsEnum[0])), // - V_A_MAX(new PointImpl(// - "S702_V_A_MAX", // - "Apparent Power Max Setting", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "PF_SF")), // + V_A_MAX(new ScaledValuePoint("S702_V_A_MAX", "Apparent Power Max Setting", // "Maximum apparent power setting used to adjust maximum apparent power rating.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.VOLT_AMPERE, // - "VA_SF", // - new OptionsEnum[0])), // - VAR_MAX_INJ(new PointImpl(// - "S702_VAR_MAX_INJ", // - "Reactive Power Injected Setting", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT_AMPERE, "VA_SF")), // + VAR_MAX_INJ(new ScaledValuePoint("S702_VAR_MAX_INJ", "Reactive Power Injected Setting", // "Maximum injected reactive power setting used to adjust maximum injected reactive power rating.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.VOLT_AMPERE_REACTIVE, // - "Var_SF", // - new OptionsEnum[0])), // - VAR_MAX_ABS(new PointImpl(// - "S702_VAR_MAX_ABS", // - "Reactive Power Absorbed Setting", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT_AMPERE_REACTIVE, "Var_SF")), // + VAR_MAX_ABS(new ScaledValuePoint("S702_VAR_MAX_ABS", "Reactive Power Absorbed Setting", // "Maximum absorbed reactive power setting used to adjust maximum absorbed reactive power rating.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.VOLT_AMPERE_REACTIVE, // - "Var_SF", // - new OptionsEnum[0])), // - W_CHA_RTE_MAX(new PointImpl(// - "S702_W_CHA_RTE_MAX", // - "Charge Rate Max Setting", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT_AMPERE_REACTIVE, "Var_SF")), // + W_CHA_RTE_MAX(new ScaledValuePoint("S702_W_CHA_RTE_MAX", "Charge Rate Max Setting", // "Maximum active power charge rate setting used to adjust maximum active power charge rate rating.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - W_DIS_CHA_RTE_MAX(new PointImpl(// - "S702_W_DIS_CHA_RTE_MAX", // - "Discharge Rate Max Setting", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.WATT, "W_SF")), // + W_DIS_CHA_RTE_MAX(new ScaledValuePoint("S702_W_DIS_CHA_RTE_MAX", "Discharge Rate Max Setting", // "Maximum active power discharge rate setting used to adjust maximum active power discharge rate rating.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - V_A_CHA_RTE_MAX(new PointImpl(// - "S702_V_A_CHA_RTE_MAX", // - "Charge Rate Max VA Setting", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.WATT, "W_SF")), // + V_A_CHA_RTE_MAX(new ScaledValuePoint("S702_V_A_CHA_RTE_MAX", "Charge Rate Max VA Setting", // "Maximum apparent power charge rate setting used to adjust maximum apparent power charge rate rating.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.VOLT_AMPERE, // - "VA_SF", // - new OptionsEnum[0])), // - V_A_DIS_CHA_RTE_MAX(new PointImpl(// - "S702_V_A_DIS_CHA_RTE_MAX", // - "Discharge Rate Max VA Setting", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT_AMPERE, "VA_SF")), // + V_A_DIS_CHA_RTE_MAX(new ScaledValuePoint("S702_V_A_DIS_CHA_RTE_MAX", "Discharge Rate Max VA Setting", // "Maximum apparent power discharge rate setting used to adjust maximum apparent power discharge rate rating.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.VOLT_AMPERE, // - "VA_SF", // - new OptionsEnum[0])), // - V_NOM(new PointImpl(// - "S702_V_NOM", // - "Nominal AC Voltage Setting", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT_AMPERE, "VA_SF")), // + V_NOM(new ScaledValuePoint("S702_V_NOM", "Nominal AC Voltage Setting", // "Nominal AC voltage setting.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - V_MAX(new PointImpl(// - "S702_V_MAX", // - "AC Voltage Max Setting", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT, "V_SF")), // + V_MAX(new ScaledValuePoint("S702_V_MAX", "AC Voltage Max Setting", // "AC voltage maximum setting used to adjust AC voltage maximum rating.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - V_MIN(new PointImpl(// - "S702_V_MIN", // - "AC Voltage Min Setting", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT, "V_SF")), // + V_MIN(new ScaledValuePoint("S702_V_MIN", "AC Voltage Min Setting", // "AC voltage minimum setting used to adjust AC voltage minimum rating.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - A_MAX(new PointImpl(// - "S702_A_MAX", // - "AC Current Max Setting", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT, "V_SF")), // + A_MAX(new ScaledValuePoint("S702_A_MAX", "AC Current Max Setting", // "Maximum AC current setting used to adjust maximum AC current rating.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - P_F_OVR_EXT(new PointImpl(// - "S702_P_F_OVR_EXT", // - "PF Over-Excited Setting", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.AMPERE, "A_SF")), // + P_F_OVR_EXT(new ScaledValuePoint("S702_P_F_OVR_EXT", "PF Over-Excited Setting", // "Power factor over-excited setting.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - "PF_SF", // - new OptionsEnum[0])), // - P_F_UND_EXT(new PointImpl(// - "S702_P_F_UND_EXT", // - "PF Under-Excited Setting", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "PF_SF")), // + P_F_UND_EXT(new ScaledValuePoint("S702_P_F_UND_EXT", "PF Under-Excited Setting", // "Power factor under-excited setting.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - "PF_SF", // - new OptionsEnum[0])), // - INT_ISLAND_CAT(new PointImpl(// - "S702_INT_ISLAND_CAT", // - "Intentional Island Categories", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "PF_SF")), // + INT_ISLAND_CAT(new BitFieldPoint("S702_INT_ISLAND_CAT", "Intentional Island Categories", // "Intentional island categories.", // - "", // - PointType.BITFIELD16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S702_IntIslandCat.values())), // - W_SF(new PointImpl(// - "S702_W_SF", // - "Active Power Scale Factor", // - "Active power scale factor.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - PF_SF(new PointImpl(// - "S702_PF_SF", // - "Power Factor Scale Factor", // - "Power factor scale factor.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - VA_SF(new PointImpl(// - "S702_VA_SF", // - "Apparent Power Scale Factor", // - "Apparent power scale factor.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - VAR_S_F(new PointImpl(// - "S702_VAR_S_F", // - "Reactive Power Scale Factor", // - "Reactive power scale factor.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - V_SF(new PointImpl(// - "S702_V_SF", // - "Voltage Scale Factor", // - "Voltage scale factor.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - A_SF(new PointImpl(// - "S702_A_SF", // - "Current Scale Factor", // - "Current scale factor.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - S_SF(new PointImpl(// - "S702_S_SF", // - "Susceptance Scale Factor", // - "Susceptance scale factor.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // - - protected final PointImpl impl; - - private S702(PointImpl impl) { - this.impl = impl; - } - - @Override - public PointImpl get() { - return this.impl; + BitFieldPoint.Type.BITFIELD16, false /* mandatory? */, AccessMode.READ_WRITE, S702_IntIslandCat.values())), // + W_SF(new ScaleFactorPoint("S702_W_SF", "Active Power Scale Factor", // + "Active power scale factor.")), // + PF_SF(new ScaleFactorPoint("S702_PF_SF", "Power Factor Scale Factor", // + "Power factor scale factor.")), // + VA_SF(new ScaleFactorPoint("S702_VA_SF", "Apparent Power Scale Factor", // + "Apparent power scale factor.")), // + VAR_S_F(new ScaleFactorPoint("S702_VAR_S_F", "Reactive Power Scale Factor", // + "Reactive power scale factor.")), // + V_SF(new ScaleFactorPoint("S702_V_SF", "Voltage Scale Factor", // + "Voltage scale factor.")), // + A_SF(new ScaleFactorPoint("S702_A_SF", "Current Scale Factor", // + "Current scale factor.")), // + S_SF(new ScaleFactorPoint("S702_S_SF", "Susceptance Scale Factor", // + "Susceptance scale factor.")); + + private final Point point; + + private S702(Point point) { + this.point = point; + } + + @Override + public Point get() { + return this.point; } } public static enum S702_NorOpCatRtg implements OptionsEnum { UNDEFINED(-1, "Undefined"), // CAT_A(0, "CAT_A"), // - CAT_B(1, "CAT_B"); // + CAT_B(1, "CAT_B"); private final int value; private final String name; @@ -11988,7 +4269,7 @@ public static enum S702_AbnOpCatRtg implements OptionsEnum { UNDEFINED(-1, "Undefined"), // CAT_1(0, "CAT_1"), // CAT_2(1, "CAT_2"), // - CAT_3(2, "CAT_3"); // + CAT_3(2, "CAT_3"); private final int value; private final String name; @@ -12014,248 +4295,119 @@ public OptionsEnum getUndefined() { } } - public static enum S702_CtrlModes implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - MAX_W(0, "MAX_W"), // - FIXED_W(1, "FIXED_W"), // - FIXED_VAR(2, "FIXED_VAR"), // - FIXED_PF(3, "FIXED_PF"), // - VOLT_VAR(4, "VOLT_VAR"), // - FREQ_WATT(5, "FREQ_WATT"), // - DYN_REACT_CURR(6, "DYN_REACT_CURR"), // - LV_TRIP(7, "LV_TRIP"), // - HV_TRIP(8, "HV_TRIP"), // - WATT_VAR(9, "WATT_VAR"), // - VOLT_WATT(10, "VOLT_WATT"), // - SCHEDULED(11, "SCHEDULED"), // - LF_TRIP(12, "LF_TRIP"), // - HF_TRIP(13, "HF_TRIP"); // - - private final int value; - private final String name; - - private S702_CtrlModes(int value, String name) { - this.value = value; - this.name = name; - } + public static enum S702_CtrlModes implements SunSpecBitPoint { + MAX_W(new BitPoint(0, "S702_CTRL_MODES_MAX_W", "Max W")), // + FIXED_W(new BitPoint(1, "S702_CTRL_MODES_FIXED_W", "Fixed W")), // + FIXED_VAR(new BitPoint(2, "S702_CTRL_MODES_FIXED_VAR", "Fixed Var")), // + FIXED_PF(new BitPoint(3, "S702_CTRL_MODES_FIXED_PF", "Fixed Pf")), // + VOLT_VAR(new BitPoint(4, "S702_CTRL_MODES_VOLT_VAR", "Volt Var")), // + FREQ_WATT(new BitPoint(5, "S702_CTRL_MODES_FREQ_WATT", "Freq Watt")), // + DYN_REACT_CURR(new BitPoint(6, "S702_CTRL_MODES_DYN_REACT_CURR", "Dyn React Curr")), // + LV_TRIP(new BitPoint(7, "S702_CTRL_MODES_LV_TRIP", "Lv Trip")), // + HV_TRIP(new BitPoint(8, "S702_CTRL_MODES_HV_TRIP", "Hv Trip")), // + WATT_VAR(new BitPoint(9, "S702_CTRL_MODES_WATT_VAR", "Watt Var")), // + VOLT_WATT(new BitPoint(10, "S702_CTRL_MODES_VOLT_WATT", "Volt Watt")), // + SCHEDULED(new BitPoint(11, "S702_CTRL_MODES_SCHEDULED", "SCHEDULED")), // + LF_TRIP(new BitPoint(12, "S702_CTRL_MODES_LF_TRIP", "Lf Trip")), // + HF_TRIP(new BitPoint(13, "S702_CTRL_MODES_HF_TRIP", "Hf Trip")); - @Override - public int getValue() { - return this.value; - } + private final BitPoint point; - @Override - public String getName() { - return this.name; + private S702_CtrlModes(BitPoint point) { + this.point = point; } @Override - public OptionsEnum getUndefined() { - return UNDEFINED; + public BitPoint get() { + return this.point; } } - public static enum S702_IntIslandCatRtg implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - UNCATEGORIZED(0, "UNCATEGORIZED"), // - INT_ISL_CAPABLE(1, "INT_ISL_CAPABLE"), // - BLACK_START_CAPABLE(2, "BLACK_START_CAPABLE"), // - ISOCH_CAPABLE(3, "ISOCH_CAPABLE"); // - - private final int value; - private final String name; - - private S702_IntIslandCatRtg(int value, String name) { - this.value = value; - this.name = name; - } + public static enum S702_IntIslandCatRtg implements SunSpecBitPoint { + UNCATEGORIZED(new BitPoint(0, "S702_INT_ISLAND_CAT_RTG_UNCATEGORIZED", "UNCATEGORIZED")), // + INT_ISL_CAPABLE(new BitPoint(1, "S702_INT_ISLAND_CAT_RTG_INT_ISL_CAPABLE", "Int Isl Capable")), // + BLACK_START_CAPABLE(new BitPoint(2, "S702_INT_ISLAND_CAT_RTG_BLACK_START_CAPABLE", "Black Start Capable")), // + ISOCH_CAPABLE(new BitPoint(3, "S702_INT_ISLAND_CAT_RTG_ISOCH_CAPABLE", "Isoch Capable")); - @Override - public int getValue() { - return this.value; - } + private final BitPoint point; - @Override - public String getName() { - return this.name; + private S702_IntIslandCatRtg(BitPoint point) { + this.point = point; } @Override - public OptionsEnum getUndefined() { - return UNDEFINED; + public BitPoint get() { + return this.point; } } - public static enum S702_IntIslandCat implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - UNCATEGORIZED(0, "UNCATEGORIZED"), // - INT_ISL_CAPABLE(1, "INT_ISL_CAPABLE"), // - BLACK_START_CAPABLE(2, "BLACK_START_CAPABLE"), // - ISOCH_CAPABLE(3, "ISOCH_CAPABLE"); // - - private final int value; - private final String name; - - private S702_IntIslandCat(int value, String name) { - this.value = value; - this.name = name; - } + public static enum S702_IntIslandCat implements SunSpecBitPoint { + UNCATEGORIZED(new BitPoint(0, "S702_INT_ISLAND_CAT_UNCATEGORIZED", "UNCATEGORIZED")), // + INT_ISL_CAPABLE(new BitPoint(1, "S702_INT_ISLAND_CAT_INT_ISL_CAPABLE", "Int Isl Capable")), // + BLACK_START_CAPABLE(new BitPoint(2, "S702_INT_ISLAND_CAT_BLACK_START_CAPABLE", "Black Start Capable")), // + ISOCH_CAPABLE(new BitPoint(3, "S702_INT_ISLAND_CAT_ISOCH_CAPABLE", "Isoch Capable")); - @Override - public int getValue() { - return this.value; - } + private final BitPoint point; - @Override - public String getName() { - return this.name; + private S702_IntIslandCat(BitPoint point) { + this.point = point; } @Override - public OptionsEnum getUndefined() { - return UNDEFINED; + public BitPoint get() { + return this.point; } } public static enum S703 implements SunSpecPoint { - ES(new PointImpl(// - "S703_ES", // - "Permit Enter Service", // + ES(new EnumPoint("S703_ES", "Permit Enter Service", // "Permit enter service.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S703_ES.values())), // - E_S_V_HI(new PointImpl(// - "S703_E_S_V_HI", // - "Enter Service Voltage High", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S703_ES.values())), // + E_S_V_HI(new ScaledValuePoint("S703_E_S_V_HI", "Enter Service Voltage High", // "Enter service voltage high threshold as percent of normal voltage.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - "V_SF", // - new OptionsEnum[0])), // - E_S_V_LO(new PointImpl(// - "S703_E_S_V_LO", // - "Enter Service Voltage Low", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "V_SF")), // + E_S_V_LO(new ScaledValuePoint("S703_E_S_V_LO", "Enter Service Voltage Low", // "Enter service voltage low threshold as percent of normal voltage.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - "V_SF", // - new OptionsEnum[0])), // - E_S_HZ_HI(new PointImpl(// - "S703_E_S_HZ_HI", // - "Enter Service Frequency High", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "V_SF")), // + E_S_HZ_HI(new ScaledValuePoint("S703_E_S_HZ_HI", "Enter Service Frequency High", // "Enter service frequency high threshold.", // - "", // - PointType.UINT32, // - false, // - AccessMode.READ_WRITE, // - Unit.HERTZ, // - "Hz_SF", // - new OptionsEnum[0])), // - E_S_HZ_LO(new PointImpl(// - "S703_E_S_HZ_LO", // - "Enter Service Frequency Low", // + ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.HERTZ, "Hz_SF")), // + E_S_HZ_LO(new ScaledValuePoint("S703_E_S_HZ_LO", "Enter Service Frequency Low", // "Enter service frequency low threshold.", // - "", // - PointType.UINT32, // - false, // - AccessMode.READ_WRITE, // - Unit.HERTZ, // - "Hz_SF", // - new OptionsEnum[0])), // - E_S_DLY_TMS(new PointImpl(// - "S703_E_S_DLY_TMS", // - "Enter Service Delay Time", // + ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.HERTZ, "Hz_SF")), // + E_S_DLY_TMS(new ValuePoint("S703_E_S_DLY_TMS", "Enter Service Delay Time", // "Enter service delay time in seconds.", // - "", // - PointType.UINT32, // - false, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - E_S_RND_TMS(new PointImpl(// - "S703_E_S_RND_TMS", // - "Enter Service Random Delay", // + ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + E_S_RND_TMS(new ValuePoint("S703_E_S_RND_TMS", "Enter Service Random Delay", // "Enter service random delay in seconds.", // - "", // - PointType.UINT32, // - false, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - E_S_RMP_TMS(new PointImpl(// - "S703_E_S_RMP_TMS", // - "Enter Service Ramp Time", // + ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + E_S_RMP_TMS(new ValuePoint("S703_E_S_RMP_TMS", "Enter Service Ramp Time", // "Enter service ramp time in seconds.", // - "", // - PointType.UINT32, // - false, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - E_S_DLY_REM_TMS(new PointImpl(// - "S703_E_S_DLY_REM_TMS", // - "Enter Service Delay Remaining", // + ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + E_S_DLY_REM_TMS(new ValuePoint("S703_E_S_DLY_REM_TMS", "Enter Service Delay Remaining", // "Enter service delay time remaining in seconds.", // - "", // - PointType.UINT32, // - false, // - AccessMode.READ_ONLY, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - V_SF(new PointImpl(// - "S703_V_SF", // - "Voltage Scale Factor", // - "Voltage percentage scale factor.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - HZ_S_F(new PointImpl(// - "S703_HZ_S_F", // - "Frequency Scale Factor", // - "Frequency scale factor.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // - - protected final PointImpl impl; - - private S703(PointImpl impl) { - this.impl = impl; - } - - @Override - public PointImpl get() { - return this.impl; + ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.SECONDS)), // + V_SF(new ScaleFactorPoint("S703_V_SF", "Voltage Scale Factor", // + "Voltage percentage scale factor.")), // + HZ_S_F(new ScaleFactorPoint("S703_HZ_S_F", "Frequency Scale Factor", // + "Frequency scale factor.")); + + private final Point point; + + private S703(Point point) { + this.point = point; + } + + @Override + public Point get() { + return this.point; } } public static enum S703_ES implements OptionsEnum { UNDEFINED(-1, "Undefined"), // DISABLED(0, "DISABLED"), // - ENABLED(1, "ENABLED"); // + ENABLED(1, "ENABLED"); private final int value; private final String name; @@ -12282,496 +4434,146 @@ public OptionsEnum getUndefined() { } public static enum S704 implements SunSpecPoint { - P_F_W_INJ_ENA(new PointImpl(// - "S704_P_F_W_INJ_ENA", // - "Power Factor Enable (W Inj) Enable", // + P_F_W_INJ_ENA(new EnumPoint("S704_P_F_W_INJ_ENA", "Power Factor Enable (W Inj) Enable", // "Power factor enable when injecting active power.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S704_PFWInjEna.values())), // - P_F_W_INJ_ENA_RVRT(new PointImpl(// - "S704_P_F_W_INJ_ENA_RVRT", // - "Power Factor Reversion Enable (W Inj)", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S704_PFWInjEna.values())), // + P_F_W_INJ_ENA_RVRT(new EnumPoint("S704_P_F_W_INJ_ENA_RVRT", "Power Factor Reversion Enable (W Inj)", // "Power factor reversion timer when injecting active power enable.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S704_PFWInjEnaRvrt.values())), // - P_F_W_INJ_RVRT_TMS(new PointImpl(// - "S704_P_F_W_INJ_RVRT_TMS", // - "PF Reversion Time (W Inj)", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S704_PFWInjEnaRvrt.values())), // + P_F_W_INJ_RVRT_TMS(new ValuePoint("S704_P_F_W_INJ_RVRT_TMS", "PF Reversion Time (W Inj)", // "Power factor reversion timer when injecting active power.", // - "", // - PointType.UINT32, // - false, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - P_F_W_INJ_RVRT_REM(new PointImpl(// - "S704_P_F_W_INJ_RVRT_REM", // - "PF Reversion Time Rem (W Inj)", // + ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + P_F_W_INJ_RVRT_REM(new ValuePoint("S704_P_F_W_INJ_RVRT_REM", "PF Reversion Time Rem (W Inj)", // "Power factor reversion time remaining when injecting active power.", // - "", // - PointType.UINT32, // - false, // - AccessMode.READ_ONLY, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - P_F_W_ABS_ENA(new PointImpl(// - "S704_P_F_W_ABS_ENA", // - "Power Factor Enable (W Abs) Enable", // + ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.SECONDS)), // + P_F_W_ABS_ENA(new EnumPoint("S704_P_F_W_ABS_ENA", "Power Factor Enable (W Abs) Enable", // "Power factor enable when absorbing active power.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S704_PFWAbsEna.values())), // - P_F_W_ABS_ENA_RVRT(new PointImpl(// - "S704_P_F_W_ABS_ENA_RVRT", // - "Power Factor Reversion Enable (W Abs)", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S704_PFWAbsEna.values())), // + P_F_W_ABS_ENA_RVRT(new EnumPoint("S704_P_F_W_ABS_ENA_RVRT", "Power Factor Reversion Enable (W Abs)", // "Power factor reversion timer when absorbing active power enable.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S704_PFWAbsEnaRvrt.values())), // - P_F_W_ABS_RVRT_TMS(new PointImpl(// - "S704_P_F_W_ABS_RVRT_TMS", // - "PF Reversion Time (W Abs)", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S704_PFWAbsEnaRvrt.values())), // + P_F_W_ABS_RVRT_TMS(new ValuePoint("S704_P_F_W_ABS_RVRT_TMS", "PF Reversion Time (W Abs)", // "Power factor reversion timer when absorbing active power.", // - "", // - PointType.UINT32, // - false, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - P_F_W_ABS_RVRT_REM(new PointImpl(// - "S704_P_F_W_ABS_RVRT_REM", // - "PF Reversion Time Rem (W Abs)", // + ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + P_F_W_ABS_RVRT_REM(new ValuePoint("S704_P_F_W_ABS_RVRT_REM", "PF Reversion Time Rem (W Abs)", // "Power factor reversion time remaining when absorbing active power.", // - "", // - PointType.UINT32, // - false, // - AccessMode.READ_ONLY, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - W_MAX_LIM_PCT_ENA(new PointImpl(// - "S704_W_MAX_LIM_PCT_ENA", // - "Limit Max Power Pct Enable", // + ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.SECONDS)), // + W_MAX_LIM_PCT_ENA(new EnumPoint("S704_W_MAX_LIM_PCT_ENA", "Limit Max Power Pct Enable", // "Limit maximum active power percent enable.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S704_WMaxLimPctEna.values())), // - W_MAX_LIM_PCT(new PointImpl(// - "S704_W_MAX_LIM_PCT", // - "Limit Max Power Pct Setpoint", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S704_WMaxLimPctEna.values())), // + W_MAX_LIM_PCT(new ScaledValuePoint("S704_W_MAX_LIM_PCT", "Limit Max Power Pct Setpoint", // "Limit maximum active power percent value.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - "WMaxLimPct_SF", // - new OptionsEnum[0])), // - W_MAX_LIM_PCT_RVRT(new PointImpl(// - "S704_W_MAX_LIM_PCT_RVRT", // - "Reversion Limit Max Power Pct", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "WMaxLimPct_SF")), // + W_MAX_LIM_PCT_RVRT(new ScaledValuePoint("S704_W_MAX_LIM_PCT_RVRT", "Reversion Limit Max Power Pct", // "Reversion limit maximum active power percent value.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - "WMaxLimPct_SF", // - new OptionsEnum[0])), // - W_MAX_LIM_PCT_ENA_RVRT(new PointImpl(// - "S704_W_MAX_LIM_PCT_ENA_RVRT", // - "Reversion Limit Max Power Pct Enable", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "WMaxLimPct_SF")), // + W_MAX_LIM_PCT_ENA_RVRT(new EnumPoint("S704_W_MAX_LIM_PCT_ENA_RVRT", "Reversion Limit Max Power Pct Enable", // "Reversion limit maximum active power percent value enable.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S704_WMaxLimPctEnaRvrt.values())), // - W_MAX_LIM_PCT_RVRT_TMS(new PointImpl(// - "S704_W_MAX_LIM_PCT_RVRT_TMS", // - "Limit Max Power Pct Reversion Time", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S704_WMaxLimPctEnaRvrt.values())), // + W_MAX_LIM_PCT_RVRT_TMS(new ValuePoint("S704_W_MAX_LIM_PCT_RVRT_TMS", "Limit Max Power Pct Reversion Time", // "Limit maximum active power percent reversion time.", // - "", // - PointType.UINT32, // - false, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - W_MAX_LIM_PCT_RVRT_REM(new PointImpl(// - "S704_W_MAX_LIM_PCT_RVRT_REM", // - "Limit Max Power Pct Rev Time Rem", // + ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + W_MAX_LIM_PCT_RVRT_REM(new ValuePoint("S704_W_MAX_LIM_PCT_RVRT_REM", "Limit Max Power Pct Rev Time Rem", // "Limit maximum active power percent reversion time remaining.", // - "", // - PointType.UINT32, // - false, // - AccessMode.READ_ONLY, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - W_SET_ENA(new PointImpl(// - "S704_W_SET_ENA", // - "Set Active Power Enable", // + ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.SECONDS)), // + W_SET_ENA(new EnumPoint("S704_W_SET_ENA", "Set Active Power Enable", // "Set active power enable.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S704_WSetEna.values())), // - W_SET_MOD(new PointImpl(// - "S704_W_SET_MOD", // - "Set Active Power Mode", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S704_WSetEna.values())), // + W_SET_MOD(new EnumPoint("S704_W_SET_MOD", "Set Active Power Mode", // "Set active power mode.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S704_WSetMod.values())), // - W_SET(new PointImpl(// - "S704_W_SET", // - "Active Power Setpoint (W)", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S704_WSetMod.values())), // + W_SET(new ScaledValuePoint("S704_W_SET", "Active Power Setpoint (W)", // "Active power setting value in watts.", // - "", // - PointType.INT32, // - false, // - AccessMode.READ_WRITE, // - Unit.WATT, // - "WSet_SF", // - new OptionsEnum[0])), // - W_SET_RVRT(new PointImpl(// - "S704_W_SET_RVRT", // - "Reversion Active Power (W)", // + ValuePoint.Type.INT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.WATT, "WSet_SF")), // + W_SET_RVRT(new ScaledValuePoint("S704_W_SET_RVRT", "Reversion Active Power (W)", // "Reversion active power setting value in watts.", // - "", // - PointType.INT32, // - false, // - AccessMode.READ_WRITE, // - Unit.WATT, // - "WSet_SF", // - new OptionsEnum[0])), // - W_SET_PCT(new PointImpl(// - "S704_W_SET_PCT", // - "Active Power Setpoint (Pct)", // + ValuePoint.Type.INT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.WATT, "WSet_SF")), // + W_SET_PCT(new ScaledValuePoint("S704_W_SET_PCT", "Active Power Setpoint (Pct)", // "Active power setting value as percent.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - "WSetPct_SF", // - new OptionsEnum[0])), // - W_SET_PCT_RVRT(new PointImpl(// - "S704_W_SET_PCT_RVRT", // - "Reversion Active Power (Pct)", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "WSetPct_SF")), // + W_SET_PCT_RVRT(new ScaledValuePoint("S704_W_SET_PCT_RVRT", "Reversion Active Power (Pct)", // "Reversion active power setting value as percent.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - "WSetPct_SF", // - new OptionsEnum[0])), // - W_SET_ENA_RVRT(new PointImpl(// - "S704_W_SET_ENA_RVRT", // - "Reversion Active Power Enable", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "WSetPct_SF")), // + W_SET_ENA_RVRT(new EnumPoint("S704_W_SET_ENA_RVRT", "Reversion Active Power Enable", // "Reversion active power function enable.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S704_WSetEnaRvrt.values())), // - W_SET_RVRT_TMS(new PointImpl(// - "S704_W_SET_RVRT_TMS", // - "Active Power Reversion Time", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S704_WSetEnaRvrt.values())), // + W_SET_RVRT_TMS(new ValuePoint("S704_W_SET_RVRT_TMS", "Active Power Reversion Time", // "Set active power reversion time.", // - "", // - PointType.UINT32, // - false, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - W_SET_RVRT_REM(new PointImpl(// - "S704_W_SET_RVRT_REM", // - "Active Power Rev Time Rem", // + ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + W_SET_RVRT_REM(new ValuePoint("S704_W_SET_RVRT_REM", "Active Power Rev Time Rem", // "Set active power reversion time remaining.", // - "", // - PointType.UINT32, // - false, // - AccessMode.READ_ONLY, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - VAR_SET_ENA(new PointImpl(// - "S704_VAR_SET_ENA", // - "Set Reactive Power Enable", // + ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.SECONDS)), // + VAR_SET_ENA(new EnumPoint("S704_VAR_SET_ENA", "Set Reactive Power Enable", // "Set reactive power enable.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S704_VarSetEna.values())), // - VAR_SET_MOD(new PointImpl(// - "S704_VAR_SET_MOD", // - "Set Reactive Power Mode", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S704_VarSetEna.values())), // + VAR_SET_MOD(new EnumPoint("S704_VAR_SET_MOD", "Set Reactive Power Mode", // "Set reactive power mode.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S704_VarSetMod.values())), // - VAR_SET_PRI(new PointImpl(// - "S704_VAR_SET_PRI", // - "Reactive Power Priority", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S704_VarSetMod.values())), // + VAR_SET_PRI(new EnumPoint("S704_VAR_SET_PRI", "Reactive Power Priority", // "Reactive power priority.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S704_VarSetPri.values())), // - VAR_SET(new PointImpl(// - "S704_VAR_SET", // - "Reactive Power Setpoint (Vars)", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S704_VarSetPri.values())), // + VAR_SET(new ScaledValuePoint("S704_VAR_SET", "Reactive Power Setpoint (Vars)", // "Reactive power setting value in vars.", // - "", // - PointType.INT32, // - false, // - AccessMode.READ_WRITE, // - Unit.VOLT_AMPERE_REACTIVE, // - "VarSet_SF", // - new OptionsEnum[0])), // - VAR_SET_RVRT(new PointImpl(// - "S704_VAR_SET_RVRT", // - "Reversion Reactive Power (Vars)", // + ValuePoint.Type.INT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT_AMPERE_REACTIVE, "VarSet_SF")), // + VAR_SET_RVRT(new ScaledValuePoint("S704_VAR_SET_RVRT", "Reversion Reactive Power (Vars)", // "Reversion reactive power setting value in vars.", // - "", // - PointType.INT32, // - false, // - AccessMode.READ_WRITE, // - Unit.VOLT_AMPERE_REACTIVE, // - "VarSet_SF", // - new OptionsEnum[0])), // - VAR_SET_PCT(new PointImpl(// - "S704_VAR_SET_PCT", // - "Reactive Power Setpoint (Pct)", // + ValuePoint.Type.INT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT_AMPERE_REACTIVE, "VarSet_SF")), // + VAR_SET_PCT(new ScaledValuePoint("S704_VAR_SET_PCT", "Reactive Power Setpoint (Pct)", // "Reactive power setting value as percent.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - "VarSetPct_SF", // - new OptionsEnum[0])), // - VAR_SET_PCT_RVRT(new PointImpl(// - "S704_VAR_SET_PCT_RVRT", // - "Reversion Reactive Power (Pct)", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "VarSetPct_SF")), // + VAR_SET_PCT_RVRT(new ScaledValuePoint("S704_VAR_SET_PCT_RVRT", "Reversion Reactive Power (Pct)", // "Reversion reactive power setting value as percent.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - "VarSetPct_SF", // - new OptionsEnum[0])), // - VAR_SET_ENA_RVRT(new PointImpl(// - "S704_VAR_SET_ENA_RVRT", // - "Reversion Reactive Power Enable", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "VarSetPct_SF")), // + VAR_SET_ENA_RVRT(new EnumPoint("S704_VAR_SET_ENA_RVRT", "Reversion Reactive Power Enable", // "Reversion reactive power function enable.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S704_VarSetEnaRvrt.values())), // - VAR_SET_RVRT_TMS(new PointImpl(// - "S704_VAR_SET_RVRT_TMS", // - "Reactive Power Reversion Time", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S704_VarSetEnaRvrt.values())), // + VAR_SET_RVRT_TMS(new ValuePoint("S704_VAR_SET_RVRT_TMS", "Reactive Power Reversion Time", // "Set reactive power reversion time.", // - "", // - PointType.UINT32, // - false, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - VAR_SET_RVRT_REM(new PointImpl(// - "S704_VAR_SET_RVRT_REM", // - "Reactive Power Rev Time Rem", // + ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + VAR_SET_RVRT_REM(new ValuePoint("S704_VAR_SET_RVRT_REM", "Reactive Power Rev Time Rem", // "Set reactive power reversion time remaining.", // - "", // - PointType.UINT32, // - false, // - AccessMode.READ_ONLY, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - W_RMP(new PointImpl(// - "S704_W_RMP", // - "Normal Ramp Rate", // + ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.SECONDS)), // + W_RMP(new ValuePoint("S704_W_RMP", "Normal Ramp Rate", // "Ramp rate for increases in active power during normal generation.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - W_RMP_REF(new PointImpl(// - "S704_W_RMP_REF", // - "Normal Ramp Rate Reference", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + W_RMP_REF(new EnumPoint("S704_W_RMP_REF", "Normal Ramp Rate Reference", // "Ramp rate reference unit for increases in active power or current during normal generation.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S704_WRmpRef.values())), // - VAR_RMP(new PointImpl(// - "S704_VAR_RMP", // - "Reactive Power Ramp Rate", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S704_WRmpRef.values())), // + VAR_RMP(new ValuePoint("S704_VAR_RMP", "Reactive Power Ramp Rate", // "Ramp rate based on max reactive power per second.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - ANTI_ISL_ENA(new PointImpl(// - "S704_ANTI_ISL_ENA", // - "Anti-Islanding Enable", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + ANTI_ISL_ENA(new EnumPoint("S704_ANTI_ISL_ENA", "Anti-Islanding Enable", // "Anti-islanding enable.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S704_AntiIslEna.values())), // - PF_SF(new PointImpl(// - "S704_PF_SF", // - "Power Factor Scale Factor", // - "Power factor scale factor.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - W_MAX_LIM_PCT_S_F(new PointImpl(// - "S704_W_MAX_LIM_PCT_S_F", // - "Limit Max Power Scale Factor", // - "Limit maximum power scale factor.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - W_SET_S_F(new PointImpl(// - "S704_W_SET_S_F", // - "Active Power Scale Factor", // - "Active power scale factor.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - W_SET_PCT_S_F(new PointImpl(// - "S704_W_SET_PCT_S_F", // - "Active Power Pct Scale Factor", // - "Active power pct scale factor.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - VAR_SET_S_F(new PointImpl(// - "S704_VAR_SET_S_F", // - "Reactive Power Scale Factor", // - "Reactive power scale factor.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - VAR_SET_PCT_S_F(new PointImpl(// - "S704_VAR_SET_PCT_S_F", // - "Reactive Power Pct Scale Factor", // - "Reactive power pct scale factor.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // - - protected final PointImpl impl; - - private S704(PointImpl impl) { - this.impl = impl; - } - - @Override - public PointImpl get() { - return this.impl; + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S704_AntiIslEna.values())), // + PF_SF(new ScaleFactorPoint("S704_PF_SF", "Power Factor Scale Factor", // + "Power factor scale factor.")), // + W_MAX_LIM_PCT_S_F(new ScaleFactorPoint("S704_W_MAX_LIM_PCT_S_F", "Limit Max Power Scale Factor", // + "Limit maximum power scale factor.")), // + W_SET_S_F(new ScaleFactorPoint("S704_W_SET_S_F", "Active Power Scale Factor", // + "Active power scale factor.")), // + W_SET_PCT_S_F(new ScaleFactorPoint("S704_W_SET_PCT_S_F", "Active Power Pct Scale Factor", // + "Active power pct scale factor.")), // + VAR_SET_S_F(new ScaleFactorPoint("S704_VAR_SET_S_F", "Reactive Power Scale Factor", // + "Reactive power scale factor.")), // + VAR_SET_PCT_S_F(new ScaleFactorPoint("S704_VAR_SET_PCT_S_F", "Reactive Power Pct Scale Factor", // + "Reactive power pct scale factor.")); + + private final Point point; + + private S704(Point point) { + this.point = point; + } + + @Override + public Point get() { + return this.point; } } public static enum S704_PFWInjEna implements OptionsEnum { UNDEFINED(-1, "Undefined"), // DISABLED(0, "DISABLED"), // - ENABLED(1, "ENABLED"); // + ENABLED(1, "ENABLED"); private final int value; private final String name; @@ -12800,7 +4602,7 @@ public OptionsEnum getUndefined() { public static enum S704_PFWInjEnaRvrt implements OptionsEnum { UNDEFINED(-1, "Undefined"), // DISABLED(0, "DISABLED"), // - ENABLED(1, "ENABLED"); // + ENABLED(1, "ENABLED"); private final int value; private final String name; @@ -12829,7 +4631,7 @@ public OptionsEnum getUndefined() { public static enum S704_PFWAbsEna implements OptionsEnum { UNDEFINED(-1, "Undefined"), // DISABLED(0, "DISABLED"), // - ENABLED(1, "ENABLED"); // + ENABLED(1, "ENABLED"); private final int value; private final String name; @@ -12858,7 +4660,7 @@ public OptionsEnum getUndefined() { public static enum S704_PFWAbsEnaRvrt implements OptionsEnum { UNDEFINED(-1, "Undefined"), // DISABLED(0, "DISABLED"), // - ENABLED(1, "ENABLED"); // + ENABLED(1, "ENABLED"); private final int value; private final String name; @@ -12887,7 +4689,7 @@ public OptionsEnum getUndefined() { public static enum S704_WMaxLimPctEna implements OptionsEnum { UNDEFINED(-1, "Undefined"), // DISABLED(0, "DISABLED"), // - ENABLED(1, "ENABLED"); // + ENABLED(1, "ENABLED"); private final int value; private final String name; @@ -12916,7 +4718,7 @@ public OptionsEnum getUndefined() { public static enum S704_WMaxLimPctEnaRvrt implements OptionsEnum { UNDEFINED(-1, "Undefined"), // DISABLED(0, "DISABLED"), // - ENABLED(1, "ENABLED"); // + ENABLED(1, "ENABLED"); private final int value; private final String name; @@ -12945,7 +4747,7 @@ public OptionsEnum getUndefined() { public static enum S704_WSetEna implements OptionsEnum { UNDEFINED(-1, "Undefined"), // DISABLED(0, "DISABLED"), // - ENABLED(1, "ENABLED"); // + ENABLED(1, "ENABLED"); private final int value; private final String name; @@ -12974,7 +4776,7 @@ public OptionsEnum getUndefined() { public static enum S704_WSetMod implements OptionsEnum { UNDEFINED(-1, "Undefined"), // W_MAX_PCT(0, "W_MAX_PCT"), // - WATTS(1, "WATTS"); // + WATTS(1, "WATTS"); private final int value; private final String name; @@ -13003,7 +4805,7 @@ public OptionsEnum getUndefined() { public static enum S704_WSetEnaRvrt implements OptionsEnum { UNDEFINED(-1, "Undefined"), // DISABLED(0, "DISABLED"), // - ENABLED(1, "ENABLED"); // + ENABLED(1, "ENABLED"); private final int value; private final String name; @@ -13032,7 +4834,7 @@ public OptionsEnum getUndefined() { public static enum S704_VarSetEna implements OptionsEnum { UNDEFINED(-1, "Undefined"), // DISABLED(0, "DISABLED"), // - ENABLED(1, "ENABLED"); // + ENABLED(1, "ENABLED"); private final int value; private final String name; @@ -13064,7 +4866,7 @@ public static enum S704_VarSetMod implements OptionsEnum { VAR_MAX_PCT(1, "VAR_MAX_PCT"), // VAR_AVAIL_PCT(2, "VAR_AVAIL_PCT"), // VA_MAX_PCT(3, "VA_MAX_PCT"), // - VARS(4, "VARS"); // + VARS(4, "VARS"); private final int value; private final String name; @@ -13094,7 +4896,7 @@ public static enum S704_VarSetPri implements OptionsEnum { UNDEFINED(-1, "Undefined"), // ACTIVE(0, "ACTIVE"), // REACTIVE(1, "REACTIVE"), // - VENDOR(2, "VENDOR"); // + VENDOR(2, "VENDOR"); private final int value; private final String name; @@ -13123,7 +4925,7 @@ public OptionsEnum getUndefined() { public static enum S704_VarSetEnaRvrt implements OptionsEnum { UNDEFINED(-1, "Undefined"), // DISABLED(0, "DISABLED"), // - ENABLED(1, "ENABLED"); // + ENABLED(1, "ENABLED"); private final int value; private final String name; @@ -13152,7 +4954,7 @@ public OptionsEnum getUndefined() { public static enum S704_WRmpRef implements OptionsEnum { UNDEFINED(-1, "Undefined"), // A_MAX(0, "A_MAX"), // - W_MAX(1, "W_MAX"); // + W_MAX(1, "W_MAX"); private final int value; private final String name; @@ -13181,7 +4983,7 @@ public OptionsEnum getUndefined() { public static enum S704_AntiIslEna implements OptionsEnum { UNDEFINED(-1, "Undefined"), // DISABLED(0, "DISABLED"), // - ENABLED(1, "ENABLED"); // + ENABLED(1, "ENABLED"); private final int value; private final String name; @@ -13208,144 +5010,53 @@ public OptionsEnum getUndefined() { } public static enum S705 implements SunSpecPoint { - ENA(new PointImpl(// - "S705_ENA", // - "DER Volt-Var Module Enable", // + ENA(new EnumPoint("S705_ENA", "DER Volt-Var Module Enable", // "Volt-Var control enable.", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S705_Ena.values())), // - ADPT_CRV_REQ(new PointImpl(// - "S705_ADPT_CRV_REQ", // - "Adopt Curve Request", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_WRITE, S705_Ena.values())), // + ADPT_CRV_REQ(new ValuePoint("S705_ADPT_CRV_REQ", "Adopt Curve Request", // "Index of curve points to adopt. First curve index is 1.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - ADPT_CRV_RSLT(new PointImpl(// - "S705_ADPT_CRV_RSLT", // - "Adopt Curve Result", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + ADPT_CRV_RSLT(new EnumPoint("S705_ADPT_CRV_RSLT", "Adopt Curve Result", // "Result of last adopt curve operation.", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S705_AdptCrvRslt.values())), // - N_PT(new PointImpl(// - "S705_N_PT", // - "Number Of Points", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S705_AdptCrvRslt.values())), // + N_PT(new ValuePoint("S705_N_PT", "Number Of Points", // "Number of curve points supported.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - N_CRV(new PointImpl(// - "S705_N_CRV", // - "Stored Curve Count", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + N_CRV(new ValuePoint("S705_N_CRV", "Stored Curve Count", // "Number of stored curves supported.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - RVRT_TMS(new PointImpl(// - "S705_RVRT_TMS", // - "Reversion Timeout", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + RVRT_TMS(new ValuePoint("S705_RVRT_TMS", "Reversion Timeout", // "Reversion time in seconds. 0 = No reversion time.", // - "", // - PointType.UINT32, // - false, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - RVRT_REM(new PointImpl(// - "S705_RVRT_REM", // - "Reversion Time Remaining", // + ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + RVRT_REM(new ValuePoint("S705_RVRT_REM", "Reversion Time Remaining", // "Reversion time remaining in seconds.", // - "", // - PointType.UINT32, // - false, // - AccessMode.READ_ONLY, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - RVRT_CRV(new PointImpl(// - "S705_RVRT_CRV", // - "Reversion Curve", // + ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.SECONDS)), // + RVRT_CRV(new ValuePoint("S705_RVRT_CRV", "Reversion Curve", // "Default curve after reversion timeout.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - V_SF(new PointImpl(// - "S705_V_SF", // - "Voltage Scale Factor", // - "Scale factor for curve voltage points.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - DEPT_REF_S_F(new PointImpl(// - "S705_DEPT_REF_S_F", // - "Var Scale Factor", // - "Scale factor for curve var points.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - RSP_TMS_S_F(new PointImpl(// - "S705_RSP_TMS_S_F", // - "Open-Loop Scale Factor", // - "Open loop response time scale factor.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // - - protected final PointImpl impl; - - private S705(PointImpl impl) { - this.impl = impl; - } - - @Override - public PointImpl get() { - return this.impl; + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + V_SF(new ScaleFactorPoint("S705_V_SF", "Voltage Scale Factor", // + "Scale factor for curve voltage points.")), // + DEPT_REF_S_F(new ScaleFactorPoint("S705_DEPT_REF_S_F", "Var Scale Factor", // + "Scale factor for curve var points.")), // + RSP_TMS_S_F(new ScaleFactorPoint("S705_RSP_TMS_S_F", "Open-Loop Scale Factor", // + "Open loop response time scale factor.")); + + private final Point point; + + private S705(Point point) { + this.point = point; + } + + @Override + public Point get() { + return this.point; } } public static enum S705_Ena implements OptionsEnum { UNDEFINED(-1, "Undefined"), // DISABLED(0, "DISABLED"), // - ENABLED(1, "ENABLED"); // + ENABLED(1, "ENABLED"); private final int value; private final String name; @@ -13375,7 +5086,7 @@ public static enum S705_AdptCrvRslt implements OptionsEnum { UNDEFINED(-1, "Undefined"), // IN_PROGRESS(0, "IN_PROGRESS"), // COMPLETED(1, "COMPLETED"), // - FAILED(2, "FAILED"); // + FAILED(2, "FAILED"); private final int value; private final String name; @@ -13402,144 +5113,53 @@ public OptionsEnum getUndefined() { } public static enum S706 implements SunSpecPoint { - ENA(new PointImpl(// - "S706_ENA", // - "DER Volt-Watt Module Enable", // + ENA(new EnumPoint("S706_ENA", "DER Volt-Watt Module Enable", // "Volt-Watt control enable.", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S706_Ena.values())), // - ADPT_CRV_REQ(new PointImpl(// - "S706_ADPT_CRV_REQ", // - "Adopt Curve Request", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_WRITE, S706_Ena.values())), // + ADPT_CRV_REQ(new ValuePoint("S706_ADPT_CRV_REQ", "Adopt Curve Request", // "Index of curve points to adopt. First curve index is 1.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - ADPT_CRV_RSLT(new PointImpl(// - "S706_ADPT_CRV_RSLT", // - "Adopt Curve Result", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + ADPT_CRV_RSLT(new EnumPoint("S706_ADPT_CRV_RSLT", "Adopt Curve Result", // "Result of last adopt curve operation.", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S706_AdptCrvRslt.values())), // - N_PT(new PointImpl(// - "S706_N_PT", // - "Number Of Points", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S706_AdptCrvRslt.values())), // + N_PT(new ValuePoint("S706_N_PT", "Number Of Points", // "Number of curve points supported.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - N_CRV(new PointImpl(// - "S706_N_CRV", // - "Stored Curve Count", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + N_CRV(new ValuePoint("S706_N_CRV", "Stored Curve Count", // "Number of stored curves supported.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - RVRT_TMS(new PointImpl(// - "S706_RVRT_TMS", // - "Reversion Timeout", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + RVRT_TMS(new ValuePoint("S706_RVRT_TMS", "Reversion Timeout", // "Reversion time in seconds. 0 = No reversion time.", // - "", // - PointType.UINT32, // - false, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - RVRT_REM(new PointImpl(// - "S706_RVRT_REM", // - "Reversion Time Remaining", // + ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + RVRT_REM(new ValuePoint("S706_RVRT_REM", "Reversion Time Remaining", // "Reversion time remaining in seconds.", // - "", // - PointType.UINT32, // - false, // - AccessMode.READ_ONLY, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - RVRT_CRV(new PointImpl(// - "S706_RVRT_CRV", // - "Reversion Curve", // + ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.SECONDS)), // + RVRT_CRV(new ValuePoint("S706_RVRT_CRV", "Reversion Curve", // "Default curve after reversion timeout.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - V_SF(new PointImpl(// - "S706_V_SF", // - "Voltage Scale Factor", // - "Scale factor for curve voltage points.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - DEPT_REF_S_F(new PointImpl(// - "S706_DEPT_REF_S_F", // - "Watt Scale Factor", // - "Scale factor for curve watt points.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - RSP_TMS_S_F(new PointImpl(// - "S706_RSP_TMS_S_F", // - "Open-Loop Scale Factor", // - "Open loop response time scale factor.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // - - protected final PointImpl impl; - - private S706(PointImpl impl) { - this.impl = impl; - } - - @Override - public PointImpl get() { - return this.impl; + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + V_SF(new ScaleFactorPoint("S706_V_SF", "Voltage Scale Factor", // + "Scale factor for curve voltage points.")), // + DEPT_REF_S_F(new ScaleFactorPoint("S706_DEPT_REF_S_F", "Watt Scale Factor", // + "Scale factor for curve watt points.")), // + RSP_TMS_S_F(new ScaleFactorPoint("S706_RSP_TMS_S_F", "Open-Loop Scale Factor", // + "Open loop response time scale factor.")); + + private final Point point; + + private S706(Point point) { + this.point = point; + } + + @Override + public Point get() { + return this.point; } } public static enum S706_Ena implements OptionsEnum { UNDEFINED(-1, "Undefined"), // DISABLED(0, "DISABLED"), // - ENABLED(1, "ENABLED"); // + ENABLED(1, "ENABLED"); private final int value; private final String name; @@ -13569,7 +5189,7 @@ public static enum S706_AdptCrvRslt implements OptionsEnum { UNDEFINED(-1, "Undefined"), // IN_PROGRESS(0, "IN_PROGRESS"), // COMPLETED(1, "COMPLETED"), // - FAILED(2, "FAILED"); // + FAILED(2, "FAILED"); private final int value; private final String name; @@ -13596,100 +5216,42 @@ public OptionsEnum getUndefined() { } public static enum S707 implements SunSpecPoint { - ENA(new PointImpl(// - "S707_ENA", // - "DER Trip LV Module Enable", // + ENA(new EnumPoint("S707_ENA", "DER Trip LV Module Enable", // "DER low voltage trip control enable.", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S707_Ena.values())), // - ADPT_CRV_REQ(new PointImpl(// - "S707_ADPT_CRV_REQ", // - "Adopt Curve Request", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_WRITE, S707_Ena.values())), // + ADPT_CRV_REQ(new ValuePoint("S707_ADPT_CRV_REQ", "Adopt Curve Request", // "Index of curve points to adopt. First curve index is 1.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - ADPT_CRV_RSLT(new PointImpl(// - "S707_ADPT_CRV_RSLT", // - "Adopt Curve Result", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + ADPT_CRV_RSLT(new EnumPoint("S707_ADPT_CRV_RSLT", "Adopt Curve Result", // "Result of last adopt curve operation.", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S707_AdptCrvRslt.values())), // - N_PT(new PointImpl(// - "S707_N_PT", // - "Number Of Points", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S707_AdptCrvRslt.values())), // + N_PT(new ValuePoint("S707_N_PT", "Number Of Points", // "Number of curve points supported.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - N_CRV_SET(new PointImpl(// - "S707_N_CRV_SET", // - "Stored Curve Count", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + N_CRV_SET(new ValuePoint("S707_N_CRV_SET", "Stored Curve Count", // "Number of stored curves supported.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - V_SF(new PointImpl(// - "S707_V_SF", // - "Voltage Scale Factor", // - "Scale factor for curve voltage points.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TMS_S_F(new PointImpl(// - "S707_TMS_S_F", // - "Time Point Scale Factor", // - "Scale factor for curve time points.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // - - protected final PointImpl impl; - - private S707(PointImpl impl) { - this.impl = impl; - } - - @Override - public PointImpl get() { - return this.impl; + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + V_SF(new ScaleFactorPoint("S707_V_SF", "Voltage Scale Factor", // + "Scale factor for curve voltage points.")), // + TMS_S_F(new ScaleFactorPoint("S707_TMS_S_F", "Time Point Scale Factor", // + "Scale factor for curve time points.")); + + private final Point point; + + private S707(Point point) { + this.point = point; + } + + @Override + public Point get() { + return this.point; } } public static enum S707_Ena implements OptionsEnum { UNDEFINED(-1, "Undefined"), // DISABLED(0, "DISABLED"), // - ENABLED(1, "ENABLED"); // + ENABLED(1, "ENABLED"); private final int value; private final String name; @@ -13719,7 +5281,7 @@ public static enum S707_AdptCrvRslt implements OptionsEnum { UNDEFINED(-1, "Undefined"), // IN_PROGRESS(0, "IN_PROGRESS"), // COMPLETED(1, "COMPLETED"), // - FAILED(2, "FAILED"); // + FAILED(2, "FAILED"); private final int value; private final String name; @@ -13746,100 +5308,42 @@ public OptionsEnum getUndefined() { } public static enum S708 implements SunSpecPoint { - ENA(new PointImpl(// - "S708_ENA", // - "DER Trip HV Module Enable", // + ENA(new EnumPoint("S708_ENA", "DER Trip HV Module Enable", // "DER high voltage trip control enable.", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S708_Ena.values())), // - ADPT_CRV_REQ(new PointImpl(// - "S708_ADPT_CRV_REQ", // - "Adopt Curve Request", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_WRITE, S708_Ena.values())), // + ADPT_CRV_REQ(new ValuePoint("S708_ADPT_CRV_REQ", "Adopt Curve Request", // "Index of curve points to adopt. First curve index is 1.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - ADPT_CRV_RSLT(new PointImpl(// - "S708_ADPT_CRV_RSLT", // - "Adopt Curve Result", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + ADPT_CRV_RSLT(new EnumPoint("S708_ADPT_CRV_RSLT", "Adopt Curve Result", // "Result of last adopt curve operation.", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S708_AdptCrvRslt.values())), // - N_PT(new PointImpl(// - "S708_N_PT", // - "Number Of Points", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S708_AdptCrvRslt.values())), // + N_PT(new ValuePoint("S708_N_PT", "Number Of Points", // "Number of curve points supported.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - N_CRV_SET(new PointImpl(// - "S708_N_CRV_SET", // - "Stored Curve Count", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + N_CRV_SET(new ValuePoint("S708_N_CRV_SET", "Stored Curve Count", // "Number of stored curves supported.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - V_SF(new PointImpl(// - "S708_V_SF", // - "Voltage Scale Factor", // - "Scale factor for curve voltage points.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TMS_S_F(new PointImpl(// - "S708_TMS_S_F", // - "Time Point Scale Factor", // - "Scale factor for curve time points.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // - - protected final PointImpl impl; - - private S708(PointImpl impl) { - this.impl = impl; - } - - @Override - public PointImpl get() { - return this.impl; + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + V_SF(new ScaleFactorPoint("S708_V_SF", "Voltage Scale Factor", // + "Scale factor for curve voltage points.")), // + TMS_S_F(new ScaleFactorPoint("S708_TMS_S_F", "Time Point Scale Factor", // + "Scale factor for curve time points.")); + + private final Point point; + + private S708(Point point) { + this.point = point; + } + + @Override + public Point get() { + return this.point; } } public static enum S708_Ena implements OptionsEnum { UNDEFINED(-1, "Undefined"), // DISABLED(0, "DISABLED"), // - ENABLED(1, "ENABLED"); // + ENABLED(1, "ENABLED"); private final int value; private final String name; @@ -13869,7 +5373,7 @@ public static enum S708_AdptCrvRslt implements OptionsEnum { UNDEFINED(-1, "Undefined"), // IN_PROGRESS(0, "IN_PROGRESS"), // COMPLETED(1, "COMPLETED"), // - FAILED(2, "FAILED"); // + FAILED(2, "FAILED"); private final int value; private final String name; @@ -13896,100 +5400,42 @@ public OptionsEnum getUndefined() { } public static enum S709 implements SunSpecPoint { - ENA(new PointImpl(// - "S709_ENA", // - "DER Trip LF Module Enable", // + ENA(new EnumPoint("S709_ENA", "DER Trip LF Module Enable", // "DER low frequency trip control enable.", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S709_Ena.values())), // - ADPT_CRV_REQ(new PointImpl(// - "S709_ADPT_CRV_REQ", // - "Adopt Curve Request", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_WRITE, S709_Ena.values())), // + ADPT_CRV_REQ(new ValuePoint("S709_ADPT_CRV_REQ", "Adopt Curve Request", // "Index of curve points to adopt. First curve index is 1.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - ADPT_CRV_RSLT(new PointImpl(// - "S709_ADPT_CRV_RSLT", // - "Adopt Curve Result", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + ADPT_CRV_RSLT(new EnumPoint("S709_ADPT_CRV_RSLT", "Adopt Curve Result", // "Result of last adopt curve operation.", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S709_AdptCrvRslt.values())), // - N_PT(new PointImpl(// - "S709_N_PT", // - "Number Of Points", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S709_AdptCrvRslt.values())), // + N_PT(new ValuePoint("S709_N_PT", "Number Of Points", // "Number of curve points supported.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - N_CRV_SET(new PointImpl(// - "S709_N_CRV_SET", // - "Stored Curve Count", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + N_CRV_SET(new ValuePoint("S709_N_CRV_SET", "Stored Curve Count", // "Number of stored curves supported.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - HZ_S_F(new PointImpl(// - "S709_HZ_S_F", // - "Frequency Scale Factor", // - "Scale factor for curve frequency points.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TMS_S_F(new PointImpl(// - "S709_TMS_S_F", // - "Time Point Scale Factor", // - "Scale factor for curve time points.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // - - protected final PointImpl impl; - - private S709(PointImpl impl) { - this.impl = impl; - } - - @Override - public PointImpl get() { - return this.impl; + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + HZ_S_F(new ScaleFactorPoint("S709_HZ_S_F", "Frequency Scale Factor", // + "Scale factor for curve frequency points.")), // + TMS_S_F(new ScaleFactorPoint("S709_TMS_S_F", "Time Point Scale Factor", // + "Scale factor for curve time points.")); + + private final Point point; + + private S709(Point point) { + this.point = point; + } + + @Override + public Point get() { + return this.point; } } public static enum S709_Ena implements OptionsEnum { UNDEFINED(-1, "Undefined"), // DISABLED(0, "DISABLED"), // - ENABLED(1, "ENABLED"); // + ENABLED(1, "ENABLED"); private final int value; private final String name; @@ -14019,7 +5465,7 @@ public static enum S709_AdptCrvRslt implements OptionsEnum { UNDEFINED(-1, "Undefined"), // IN_PROGRESS(0, "IN_PROGRESS"), // COMPLETED(1, "COMPLETED"), // - FAILED(2, "FAILED"); // + FAILED(2, "FAILED"); private final int value; private final String name; @@ -14046,100 +5492,42 @@ public OptionsEnum getUndefined() { } public static enum S710 implements SunSpecPoint { - ENA(new PointImpl(// - "S710_ENA", // - "DER Trip HF Module Enable", // + ENA(new EnumPoint("S710_ENA", "DER Trip HF Module Enable", // "DER high frequency trip control enable.", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S710_Ena.values())), // - ADPT_CRV_REQ(new PointImpl(// - "S710_ADPT_CRV_REQ", // - "Adopt Curve Request", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_WRITE, S710_Ena.values())), // + ADPT_CRV_REQ(new ValuePoint("S710_ADPT_CRV_REQ", "Adopt Curve Request", // "Index of curve points to adopt. First curve index is 1.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - ADPT_CRV_RSLT(new PointImpl(// - "S710_ADPT_CRV_RSLT", // - "Adopt Curve Result", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + ADPT_CRV_RSLT(new EnumPoint("S710_ADPT_CRV_RSLT", "Adopt Curve Result", // "Result of last adopt curve operation.", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S710_AdptCrvRslt.values())), // - N_PT(new PointImpl(// - "S710_N_PT", // - "Number Of Points", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S710_AdptCrvRslt.values())), // + N_PT(new ValuePoint("S710_N_PT", "Number Of Points", // "Number of curve points supported.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - N_CRV_SET(new PointImpl(// - "S710_N_CRV_SET", // - "Stored Curve Count", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + N_CRV_SET(new ValuePoint("S710_N_CRV_SET", "Stored Curve Count", // "Number of stored curves supported.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - HZ_S_F(new PointImpl(// - "S710_HZ_S_F", // - "Frequency Scale Factor", // - "Scale factor for curve frequency points.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TMS_S_F(new PointImpl(// - "S710_TMS_S_F", // - "Time Point Scale Factor", // - "Scale factor for curve time points.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // - - protected final PointImpl impl; - - private S710(PointImpl impl) { - this.impl = impl; - } - - @Override - public PointImpl get() { - return this.impl; + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + HZ_S_F(new ScaleFactorPoint("S710_HZ_S_F", "Frequency Scale Factor", // + "Scale factor for curve frequency points.")), // + TMS_S_F(new ScaleFactorPoint("S710_TMS_S_F", "Time Point Scale Factor", // + "Scale factor for curve time points.")); + + private final Point point; + + private S710(Point point) { + this.point = point; + } + + @Override + public Point get() { + return this.point; } } public static enum S710_Ena implements OptionsEnum { UNDEFINED(-1, "Undefined"), // DISABLED(0, "DISABLED"), // - ENABLED(1, "ENABLED"); // + ENABLED(1, "ENABLED"); private final int value; private final String name; @@ -14169,7 +5557,7 @@ public static enum S710_AdptCrvRslt implements OptionsEnum { UNDEFINED(-1, "Undefined"), // IN_PROGRESS(0, "IN_PROGRESS"), // COMPLETED(1, "COMPLETED"), // - FAILED(2, "FAILED"); // + FAILED(2, "FAILED"); private final int value; private final String name; @@ -14196,133 +5584,50 @@ public OptionsEnum getUndefined() { } public static enum S711 implements SunSpecPoint { - ENA(new PointImpl(// - "S711_ENA", // - "DER Frequency Droop Module Enable", // + ENA(new EnumPoint("S711_ENA", "DER Frequency Droop Module Enable", // "DER Frequency-Watt (Frequency-Droop) control enable.", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S711_Ena.values())), // - ADPT_CTL_REQ(new PointImpl(// - "S711_ADPT_CTL_REQ", // - "Set Active Control Request", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_WRITE, S711_Ena.values())), // + ADPT_CTL_REQ(new ValuePoint("S711_ADPT_CTL_REQ", "Set Active Control Request", // "Set active control. 0 = No active control.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - ADPT_CTL_RSLT(new PointImpl(// - "S711_ADPT_CTL_RSLT", // - "Set Active Control Result", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + ADPT_CTL_RSLT(new EnumPoint("S711_ADPT_CTL_RSLT", "Set Active Control Result", // "Result of last set active control operation.", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S711_AdptCtlRslt.values())), // - N_CTL(new PointImpl(// - "S711_N_CTL", // - "Stored Control Count", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S711_AdptCtlRslt.values())), // + N_CTL(new ValuePoint("S711_N_CTL", "Stored Control Count", // "Number of stored controls supported.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - RVRT_TMS(new PointImpl(// - "S711_RVRT_TMS", // - "Reversion Timeout", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + RVRT_TMS(new ValuePoint("S711_RVRT_TMS", "Reversion Timeout", // "Reversion time in seconds. 0 = No reversion time.", // - "", // - PointType.UINT32, // - false, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - RVRT_REM(new PointImpl(// - "S711_RVRT_REM", // - "Reversion Time Left", // + ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + RVRT_REM(new ValuePoint("S711_RVRT_REM", "Reversion Time Left", // "Reversion time remaining in seconds.", // - "", // - PointType.UINT32, // - false, // - AccessMode.READ_ONLY, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - RVRT_CTL(new PointImpl(// - "S711_RVRT_CTL", // - "Reversion Control", // + ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.SECONDS)), // + RVRT_CTL(new ValuePoint("S711_RVRT_CTL", "Reversion Control", // "Default control after reversion timeout.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - DB_S_F(new PointImpl(// - "S711_DB_S_F", // - "Deadband Scale Factor", // - "Deadband scale factor.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - K_SF(new PointImpl(// - "S711_K_SF", // - "Frequency Change Scale Factor", // - "Frequency change scale factor.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - RSP_TMS_S_F(new PointImpl(// - "S711_RSP_TMS_S_F", // - "Open-Loop Scale Factor", // - "Open loop response time scale factor.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // - - protected final PointImpl impl; - - private S711(PointImpl impl) { - this.impl = impl; - } - - @Override - public PointImpl get() { - return this.impl; + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + DB_S_F(new ScaleFactorPoint("S711_DB_S_F", "Deadband Scale Factor", // + "Deadband scale factor.")), // + K_SF(new ScaleFactorPoint("S711_K_SF", "Frequency Change Scale Factor", // + "Frequency change scale factor.")), // + RSP_TMS_S_F(new ScaleFactorPoint("S711_RSP_TMS_S_F", "Open-Loop Scale Factor", // + "Open loop response time scale factor.")); + + private final Point point; + + private S711(Point point) { + this.point = point; + } + + @Override + public Point get() { + return this.point; } } public static enum S711_Ena implements OptionsEnum { UNDEFINED(-1, "Undefined"), // DISABLED(0, "DISABLED"), // - ENABLED(1, "ENABLED"); // + ENABLED(1, "ENABLED"); private final int value; private final String name; @@ -14352,7 +5657,7 @@ public static enum S711_AdptCtlRslt implements OptionsEnum { UNDEFINED(-1, "Undefined"), // IN_PROGRESS(0, "IN_PROGRESS"), // COMPLETED(1, "COMPLETED"), // - FAILED(2, "FAILED"); // + FAILED(2, "FAILED"); private final int value; private final String name; @@ -14379,133 +5684,51 @@ public OptionsEnum getUndefined() { } public static enum S712 implements SunSpecPoint { - ENA(new PointImpl(// - "S712_ENA", // - "DER Watt-Var Module Enable", // + ENA(new EnumPoint("S712_ENA", "DER Watt-Var Module Enable", // "DER Watt-Var control enable.", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S712_Ena.values())), // - ADPT_CRV_REQ(new PointImpl(// - "S712_ADPT_CRV_REQ", // - "Set Active Curve Request", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_WRITE, S712_Ena.values())), // + ADPT_CRV_REQ(new ValuePoint("S712_ADPT_CRV_REQ", "Set Active Curve Request", // "Set active curve. 0 = No active curve.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - ADPT_CRV_RSLT(new PointImpl(// - "S712_ADPT_CRV_RSLT", // - "Set Active Curve Result", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + ADPT_CRV_RSLT(new EnumPoint("S712_ADPT_CRV_RSLT", "Set Active Curve Result", // "Result of last set active curve operation.", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S712_AdptCrvRslt.values())), // - N_PT(new PointImpl(// - "S712_N_PT", // - "Number Of Points", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S712_AdptCrvRslt.values())), // + N_PT(new ValuePoint("S712_N_PT", "Number Of Points", // "Number of curve points supported.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - N_CRV(new PointImpl(// - "S712_N_CRV", // - "Stored Curve Count", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + N_CRV(new ValuePoint("S712_N_CRV", "Stored Curve Count", // "Number of stored curves supported.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - RVRT_TMS(new PointImpl(// - "S712_RVRT_TMS", // - "Reversion Timeout", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + RVRT_TMS(new ValuePoint("S712_RVRT_TMS", "Reversion Timeout", // "Reversion time in seconds. 0 = No reversion time.", // - "", // - PointType.UINT32, // - false, // - AccessMode.READ_WRITE, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - RVRT_REM(new PointImpl(// - "S712_RVRT_REM", // - "Reversion Time Left", // + ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + RVRT_REM(new ValuePoint("S712_RVRT_REM", "Reversion Time Left", // "Reversion time remaining in seconds.", // - "", // - PointType.UINT32, // - false, // - AccessMode.READ_ONLY, // - Unit.SECONDS, // - null, // - new OptionsEnum[0])), // - RVRT_CRV(new PointImpl(// - "S712_RVRT_CRV", // - "Reversion Curve", // + ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.SECONDS)), // + RVRT_CRV(new ValuePoint("S712_RVRT_CRV", "Reversion Curve", // "Default curve after reversion timeout.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - W_SF(new PointImpl(// - "S712_W_SF", // - "Active Power Scale Factor", // - "Scale factor for curve active power points.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - DEPT_REF_S_F(new PointImpl(// - "S712_DEPT_REF_S_F", // - "Var Scale Factor", // - "Scale factor for curve var points.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // - - protected final PointImpl impl; - - private S712(PointImpl impl) { - this.impl = impl; - } - - @Override - public PointImpl get() { - return this.impl; + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + W_SF(new ScaleFactorPoint("S712_W_SF", "Active Power Scale Factor", // + "Scale factor for curve active power points.")), // + DEPT_REF_S_F(new ScaleFactorPoint("S712_DEPT_REF_S_F", "Var Scale Factor", // + "Scale factor for curve var points.")); + + private final Point point; + + private S712(Point point) { + this.point = point; + } + + @Override + public Point get() { + return this.point; } } public static enum S712_Ena implements OptionsEnum { UNDEFINED(-1, "Undefined"), // DISABLED(0, "DISABLED"), // - ENABLED(1, "ENABLED"); // + ENABLED(1, "ENABLED"); private final int value; private final String name; @@ -14535,7 +5758,7 @@ public static enum S712_AdptCrvRslt implements OptionsEnum { UNDEFINED(-1, "Undefined"), // IN_PROGRESS(0, "IN_PROGRESS"), // COMPLETED(1, "COMPLETED"), // - FAILED(2, "FAILED"); // + FAILED(2, "FAILED"); private final int value; private final String name; @@ -14562,93 +5785,35 @@ public OptionsEnum getUndefined() { } public static enum S713 implements SunSpecPoint { - W_H_RTG(new PointImpl(// - "S713_W_H_RTG", // - "Energy Rating", // + W_H_RTG(new ScaledValuePoint("S713_W_H_RTG", "Energy Rating", // "Energy rating of the DER storage.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "WH_SF", // - new OptionsEnum[0])), // - W_H_AVAIL(new PointImpl(// - "S713_W_H_AVAIL", // - "Energy Available", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "WH_SF")), // + W_H_AVAIL(new ScaledValuePoint("S713_W_H_AVAIL", "Energy Available", // "Energy available of the DER storage (WHAvail = WHRtg * SoC * SoH)", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "WH_SF", // - new OptionsEnum[0])), // - SO_C(new PointImpl(// - "S713_SO_C", // - "State of Charge", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "WH_SF")), // + SO_C(new ScaledValuePoint("S713_SO_C", "State of Charge", // "State of charge of the DER storage.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "Pct_SF", // - new OptionsEnum[0])), // - SO_H(new PointImpl(// - "S713_SO_H", // - "State of Health", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "Pct_SF")), // + SO_H(new ScaledValuePoint("S713_SO_H", "State of Health", // "State of health of the DER storage.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "Pct_SF", // - new OptionsEnum[0])), // - STA(new PointImpl(// - "S713_STA", // - "Status", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "Pct_SF")), // + STA(new EnumPoint("S713_STA", "Status", // "Storage status.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S713_Sta.values())), // - WH_SF(new PointImpl(// - "S713_WH_SF", // - "Energy Scale Factor", // - "Scale factor for energy capacity.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - PCT_S_F(new PointImpl(// - "S713_PCT_S_F", // - "Percent Scale Factor", // - "Scale factor for percentage.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // - - protected final PointImpl impl; - - private S713(PointImpl impl) { - this.impl = impl; - } - - @Override - public PointImpl get() { - return this.impl; + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, S713_Sta.values())), // + WH_SF(new ScaleFactorPoint("S713_WH_SF", "Energy Scale Factor", // + "Scale factor for energy capacity.")), // + PCT_S_F(new ScaleFactorPoint("S713_PCT_S_F", "Percent Scale Factor", // + "Scale factor for percentage.")); + + private final Point point; + + private S713(Point point) { + this.point = point; + } + + @Override + public Point get() { + return this.point; } } @@ -14656,7 +5821,7 @@ public static enum S713_Sta implements OptionsEnum { UNDEFINED(-1, "Undefined"), // OK(0, "OK"), // WARNING(1, "WARNING"), // - ERROR(2, "ERROR"); // + ERROR(2, "ERROR"); private final int value; private final String name; @@ -14683,213 +5848,80 @@ public OptionsEnum getUndefined() { } public static enum S714 implements SunSpecPoint { - PRT_ALRMS(new PointImpl(// - "S714_PRT_ALRMS", // - "Port Alarms", // + PRT_ALRMS(new BitFieldPoint("S714_PRT_ALRMS", "Port Alarms", // "Bitfield of ports with active alarms. Bit is 1 if port has an active alarm. Bit 0 is first port.", // - "", // - PointType.BITFIELD32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - N_PRT(new PointImpl(// - "S714_N_PRT", // - "Number Of Ports", // + BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + N_PRT(new ValuePoint("S714_N_PRT", "Number Of Ports", // "Number of DC ports.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - DCA(new PointImpl(// - "S714_DCA", // - "DC Current", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + DCA(new ScaledValuePoint("S714_DCA", "DC Current", // "Total DC current for all ports.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "DCA_SF", // - new OptionsEnum[0])), // - DCW(new PointImpl(// - "S714_DCW", // - "DC Power", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "DCA_SF")), // + DCW(new ScaledValuePoint("S714_DCW", "DC Power", // "Total DC power for all ports.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "DCW_SF", // - new OptionsEnum[0])), // - D_C_WH_INJ(new PointImpl(// - "S714_D_C_WH_INJ", // - "DC Energy Injected", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "DCW_SF")), // + D_C_WH_INJ(new ScaledValuePoint("S714_D_C_WH_INJ", "DC Energy Injected", // "Total cumulative DC energy injected for all ports.", // - "", // - PointType.UINT64, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "DCWH_SF", // - new OptionsEnum[0])), // - D_C_WH_ABS(new PointImpl(// - "S714_D_C_WH_ABS", // - "DC Energy Absorbed", // + ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "DCWH_SF")), // + D_C_WH_ABS(new ScaledValuePoint("S714_D_C_WH_ABS", "DC Energy Absorbed", // "Total cumulative DC energy absorbed for all ports.", // - "", // - PointType.UINT64, // - false, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "DCWH_SF", // - new OptionsEnum[0])), // - DCA_SF(new PointImpl(// - "S714_DCA_SF", // - "DC Current Scale Factor", // - "DC current scale factor.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - DCV_SF(new PointImpl(// - "S714_DCV_SF", // - "DC Voltage Scale Factor", // - "DC voltage scale factor.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - DCW_SF(new PointImpl(// - "S714_DCW_SF", // - "DC Power Scale Factor", // - "DC power scale factor.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - DCWH_SF(new PointImpl(// - "S714_DCWH_SF", // - "DC Energy Scale Factor", // - "DC energy scale factor.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TMP_S_F(new PointImpl(// - "S714_TMP_S_F", // - "Temperature Scale Factor", // - "Temperature Scale Factor.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // - - protected final PointImpl impl; - - private S714(PointImpl impl) { - this.impl = impl; - } - - @Override - public PointImpl get() { - return this.impl; + ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "DCWH_SF")), // + DCA_SF(new ScaleFactorPoint("S714_DCA_SF", "DC Current Scale Factor", // + "DC current scale factor.")), // + DCV_SF(new ScaleFactorPoint("S714_DCV_SF", "DC Voltage Scale Factor", // + "DC voltage scale factor.")), // + DCW_SF(new ScaleFactorPoint("S714_DCW_SF", "DC Power Scale Factor", // + "DC power scale factor.")), // + DCWH_SF(new ScaleFactorPoint("S714_DCWH_SF", "DC Energy Scale Factor", // + "DC energy scale factor.")), // + TMP_S_F(new ScaleFactorPoint("S714_TMP_S_F", "Temperature Scale Factor", // + "Temperature Scale Factor.")); + + private final Point point; + + private S714(Point point) { + this.point = point; + } + + @Override + public Point get() { + return this.point; } } public static enum S715 implements SunSpecPoint { - LOC_REM_CTL(new PointImpl(// - "S715_LOC_REM_CTL", // - "Control Mode", // + LOC_REM_CTL(new EnumPoint("S715_LOC_REM_CTL", "Control Mode", // "DER control mode. Enumeration.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S715_LocRemCtl.values())), // - D_E_R_HB(new PointImpl(// - "S715_D_E_R_HB", // - "DER Heartbeat", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, S715_LocRemCtl.values())), // + D_E_R_HB(new ValuePoint("S715_D_E_R_HB", "DER Heartbeat", // "Value is incremented every second by the DER with periodic resets to zero.", // - "", // - PointType.UINT32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - CONTROLLER_HB(new PointImpl(// - "S715_CONTROLLER_HB", // - "Controller Heartbeat", // + ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + CONTROLLER_HB(new ValuePoint("S715_CONTROLLER_HB", "Controller Heartbeat", // "Value is incremented every second by the controller with periodic resets to zero.", // - "", // - PointType.UINT32, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - ALARM_RESET(new PointImpl(// - "S715_ALARM_RESET", // - "Alarm Reset", // + ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + ALARM_RESET(new ValuePoint("S715_ALARM_RESET", "Alarm Reset", // "Used to reset any latched alarms. 1 = Reset.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - OP_CTL(new PointImpl(// - "S715_OP_CTL", // - "Set Operation", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + OP_CTL(new EnumPoint("S715_OP_CTL", "Set Operation", // "Commands to PCS. Enumerated value.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S715_OpCtl.values())); // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S715_OpCtl.values())); - protected final PointImpl impl; + private final Point point; - private S715(PointImpl impl) { - this.impl = impl; + private S715(Point point) { + this.point = point; } @Override - public PointImpl get() { - return this.impl; + public Point get() { + return this.point; } } public static enum S715_LocRemCtl implements OptionsEnum { UNDEFINED(-1, "Undefined"), // REMOTE(0, "REMOTE"), // - LOCAL(1, "LOCAL"); // + LOCAL(1, "LOCAL"); private final int value; private final String name; @@ -14920,7 +5952,7 @@ public static enum S715_OpCtl implements OptionsEnum { STOP(0, "STOP"), // START(1, "START"), // ENTER_STANDBY(2, "ENTER_STANDBY"), // - EXIT_STANDBY(3, "EXIT_STANDBY"); // + EXIT_STANDBY(3, "EXIT_STANDBY"); private final int value; private final String name; @@ -14947,657 +5979,189 @@ public OptionsEnum getUndefined() { } public static enum S801 implements SunSpecPoint { - DEPRECATED(new PointImpl(// - "S801_DEPRECATED", // - "Deprecated Model", // + DEPRECATED(new EnumPoint("S801_DEPRECATED", "Deprecated Model", // "This model has been deprecated.", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, new OptionsEnum[0])); - protected final PointImpl impl; + private final Point point; - private S801(PointImpl impl) { - this.impl = impl; + private S801(Point point) { + this.point = point; } @Override - public PointImpl get() { - return this.impl; + public Point get() { + return this.point; } } public static enum S802 implements SunSpecPoint { - A_H_RTG(new PointImpl(// - "S802_A_H_RTG", // - "Nameplate Charge Capacity", // + A_H_RTG(new ScaledValuePoint("S802_A_H_RTG", "Nameplate Charge Capacity", // "Nameplate charge capacity in amp-hours.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE_HOURS, // - "AHRtg_SF", // - new OptionsEnum[0])), // - W_H_RTG(new PointImpl(// - "S802_W_H_RTG", // - "Nameplate Energy Capacity", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE_HOURS, "AHRtg_SF")), // + W_H_RTG(new ScaledValuePoint("S802_W_H_RTG", "Nameplate Energy Capacity", // "Nameplate energy capacity in DC watt-hours.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.CUMULATED_WATT_HOURS, // - "WHRtg_SF", // - new OptionsEnum[0])), // - W_CHA_RTE_MAX(new PointImpl(// - "S802_W_CHA_RTE_MAX", // - "Nameplate Max Charge Rate", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "WHRtg_SF")), // + W_CHA_RTE_MAX(new ScaledValuePoint("S802_W_CHA_RTE_MAX", "Nameplate Max Charge Rate", // "Maximum rate of energy transfer into the storage device in DC watts.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "WChaDisChaMax_SF", // - new OptionsEnum[0])), // - W_DIS_CHA_RTE_MAX(new PointImpl(// - "S802_W_DIS_CHA_RTE_MAX", // - "Nameplate Max Discharge Rate", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "WChaDisChaMax_SF")), // + W_DIS_CHA_RTE_MAX(new ScaledValuePoint("S802_W_DIS_CHA_RTE_MAX", "Nameplate Max Discharge Rate", // "Maximum rate of energy transfer out of the storage device in DC watts.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "WChaDisChaMax_SF", // - new OptionsEnum[0])), // - DIS_CHA_RTE(new PointImpl(// - "S802_DIS_CHA_RTE", // - "Self Discharge Rate", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "WChaDisChaMax_SF")), // + DIS_CHA_RTE(new ScaledValuePoint("S802_DIS_CHA_RTE", "Self Discharge Rate", // "Self discharge rate. Percentage of capacity (WHRtg) discharged per day.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.PERCENT, // - "DisChaRte_SF", // - new OptionsEnum[0])), // - SO_C_MAX(new PointImpl(// - "S802_SO_C_MAX", // - "Nameplate Max SoC", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.PERCENT, "DisChaRte_SF")), // + SO_C_MAX(new ScaledValuePoint("S802_SO_C_MAX", "Nameplate Max SoC", // "Manufacturer maximum state of charge, expressed as a percentage.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.PERCENT, // - "SoC_SF", // - new OptionsEnum[0])), // - SO_C_MIN(new PointImpl(// - "S802_SO_C_MIN", // - "Nameplate Min SoC", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.PERCENT, "SoC_SF")), // + SO_C_MIN(new ScaledValuePoint("S802_SO_C_MIN", "Nameplate Min SoC", // "Manufacturer minimum state of charge, expressed as a percentage.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.PERCENT, // - "SoC_SF", // - new OptionsEnum[0])), // - SOC_RSV_MAX(new PointImpl(// - "S802_SOC_RSV_MAX", // - "Max Reserve Percent", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.PERCENT, "SoC_SF")), // + SOC_RSV_MAX(new ScaledValuePoint("S802_SOC_RSV_MAX", "Max Reserve Percent", // "Setpoint for maximum reserve for storage as a percentage of the nominal maximum storage.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.PERCENT, // - "SoC_SF", // - new OptionsEnum[0])), // - SO_C_RSV_MIN(new PointImpl(// - "S802_SO_C_RSV_MIN", // - "Min Reserve Percent", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "SoC_SF")), // + SO_C_RSV_MIN(new ScaledValuePoint("S802_SO_C_RSV_MIN", "Min Reserve Percent", // "Setpoint for minimum reserve for storage as a percentage of the nominal maximum storage.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.PERCENT, // - "SoC_SF", // - new OptionsEnum[0])), // - SO_C(new PointImpl(// - "S802_SO_C", // - "State of Charge", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "SoC_SF")), // + SO_C(new ScaledValuePoint("S802_SO_C", "State of Charge", // "State of charge, expressed as a percentage.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.PERCENT, // - "SoC_SF", // - new OptionsEnum[0])), // - DO_D(new PointImpl(// - "S802_DO_D", // - "Depth of Discharge", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.PERCENT, "SoC_SF")), // + DO_D(new ScaledValuePoint("S802_DO_D", "Depth of Discharge", // "Depth of discharge, expressed as a percentage.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.PERCENT, // - "DoD_SF", // - new OptionsEnum[0])), // - SO_H(new PointImpl(// - "S802_SO_H", // - "State of Health", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.PERCENT, "DoD_SF")), // + SO_H(new ScaledValuePoint("S802_SO_H", "State of Health", // "Percentage of battery life remaining.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.PERCENT, // - "SoH_SF", // - new OptionsEnum[0])), // - N_CYC(new PointImpl(// - "S802_N_CYC", // - "Cycle Count", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.PERCENT, "SoH_SF")), // + N_CYC(new ValuePoint("S802_N_CYC", "Cycle Count", // "Number of cycles executed in the battery.", // - "", // - PointType.UINT32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - CHA_ST(new PointImpl(// - "S802_CHA_ST", // - "Charge Status", // + ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + CHA_ST(new EnumPoint("S802_CHA_ST", "Charge Status", // "Charge status of storage device. Enumeration.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S802_ChaSt.values())), // - LOC_REM_CTL(new PointImpl(// - "S802_LOC_REM_CTL", // - "Control Mode", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, S802_ChaSt.values())), // + LOC_REM_CTL(new EnumPoint("S802_LOC_REM_CTL", "Control Mode", // "Battery control mode. Enumeration.", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S802_LocRemCtl.values())), // - HB(new PointImpl(// - "S802_HB", // - "Battery Heartbeat", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S802_LocRemCtl.values())), // + HB(new ValuePoint("S802_HB", "Battery Heartbeat", // "Value is incremented every second with periodic resets to zero.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - CTRL_HB(new PointImpl(// - "S802_CTRL_HB", // - "Controller Heartbeat", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + CTRL_HB(new ValuePoint("S802_CTRL_HB", "Controller Heartbeat", // "Value is incremented every second with periodic resets to zero.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - ALM_RST(new PointImpl(// - "S802_ALM_RST", // - "Alarm Reset", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + ALM_RST(new ValuePoint("S802_ALM_RST", "Alarm Reset", // "Used to reset any latched alarms. 1 = Reset.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TYP(new PointImpl(// - "S802_TYP", // - "Battery Type", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + TYP(new EnumPoint("S802_TYP", "Battery Type", // "Type of battery. Enumeration.", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S802_Typ.values())), // - STATE(new PointImpl(// - "S802_STATE", // - "State of the Battery Bank", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S802_Typ.values())), // + STATE(new EnumPoint("S802_STATE", "State of the Battery Bank", // "State of the battery bank. Enumeration.", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S802_State.values())), // - STATE_VND(new PointImpl(// - "S802_STATE_VND", // - "Vendor Battery Bank State", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S802_State.values())), // + STATE_VND(new EnumPoint("S802_STATE_VND", "Vendor Battery Bank State", // "Vendor specific battery bank state. Enumeration.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - WARR_DT(new PointImpl(// - "S802_WARR_DT", // - "Warranty Date", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, new OptionsEnum[0])), // + WARR_DT(new ValuePoint("S802_WARR_DT", "Warranty Date", // "Date the device warranty expires.", // - "", // - PointType.UINT32, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT1(new PointImpl(// - "S802_EVT1", // - "Battery Event 1 Bitfield", // + ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + EVT1(new BitFieldPoint("S802_EVT1", "Battery Event 1 Bitfield", // "Alarms and warnings. Bit flags.", // - "", // - PointType.BITFIELD32, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S802_Evt1.values())), // - EVT2(new PointImpl(// - "S802_EVT2", // - "Battery Event 2 Bitfield", // + BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, S802_Evt1.values())), // + EVT2(new BitFieldPoint("S802_EVT2", "Battery Event 2 Bitfield", // "Alarms and warnings. Bit flags.", // - "", // - PointType.BITFIELD32, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT_VND1(new PointImpl(// - "S802_EVT_VND1", // - "Vendor Event Bitfield 1", // + BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + EVT_VND1(new BitFieldPoint("S802_EVT_VND1", "Vendor Event Bitfield 1", // "Vendor defined events.", // - "", // - PointType.BITFIELD32, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - EVT_VND2(new PointImpl(// - "S802_EVT_VND2", // - "Vendor Event Bitfield 2", // + BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + EVT_VND2(new BitFieldPoint("S802_EVT_VND2", "Vendor Event Bitfield 2", // "Vendor defined events.", // - "", // - PointType.BITFIELD32, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - V(new PointImpl(// - "S802_V", // - "External Battery Voltage", // + BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + V(new ScaledValuePoint("S802_V", "External Battery Voltage", // "DC Bus Voltage.", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - V_MAX(new PointImpl(// - "S802_V_MAX", // - "Max Battery Voltage", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + V_MAX(new ScaledValuePoint("S802_V_MAX", "Max Battery Voltage", // "Instantaneous maximum battery voltage.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - V_MIN(new PointImpl(// - "S802_V_MIN", // - "Min Battery Voltage", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + V_MIN(new ScaledValuePoint("S802_V_MIN", "Min Battery Voltage", // "Instantaneous minimum battery voltage.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - CELL_V_MAX(new PointImpl(// - "S802_CELL_V_MAX", // - "Max Cell Voltage", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + CELL_V_MAX(new ScaledValuePoint("S802_CELL_V_MAX", "Max Cell Voltage", // "Maximum voltage for all cells in the bank.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "CellV_SF", // - new OptionsEnum[0])), // - CELL_V_MAX_STR(new PointImpl(// - "S802_CELL_V_MAX_STR", // - "Max Cell Voltage String", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "CellV_SF")), // + CELL_V_MAX_STR(new ValuePoint("S802_CELL_V_MAX_STR", "Max Cell Voltage String", // "String containing the cell with maximum voltage.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - CELL_V_MAX_MOD(new PointImpl(// - "S802_CELL_V_MAX_MOD", // - "Max Cell Voltage Module", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + CELL_V_MAX_MOD(new ValuePoint("S802_CELL_V_MAX_MOD", "Max Cell Voltage Module", // "Module containing the cell with maximum voltage.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - CELL_V_MIN(new PointImpl(// - "S802_CELL_V_MIN", // - "Min Cell Voltage", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + CELL_V_MIN(new ScaledValuePoint("S802_CELL_V_MIN", "Min Cell Voltage", // "Minimum voltage for all cells in the bank.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "CellV_SF", // - new OptionsEnum[0])), // - CELL_V_MIN_STR(new PointImpl(// - "S802_CELL_V_MIN_STR", // - "Min Cell Voltage String", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "CellV_SF")), // + CELL_V_MIN_STR(new ValuePoint("S802_CELL_V_MIN_STR", "Min Cell Voltage String", // "String containing the cell with minimum voltage.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - CELL_V_MIN_MOD(new PointImpl(// - "S802_CELL_V_MIN_MOD", // - "Min Cell Voltage Module", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + CELL_V_MIN_MOD(new ValuePoint("S802_CELL_V_MIN_MOD", "Min Cell Voltage Module", // "Module containing the cell with minimum voltage.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - CELL_V_AVG(new PointImpl(// - "S802_CELL_V_AVG", // - "Average Cell Voltage", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + CELL_V_AVG(new ScaledValuePoint("S802_CELL_V_AVG", "Average Cell Voltage", // "Average cell voltage for all cells in the bank.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "CellV_SF", // - new OptionsEnum[0])), // - A(new PointImpl(// - "S802_A", // - "Total DC Current", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "CellV_SF")), // + A(new ScaledValuePoint("S802_A", "Total DC Current", // "Total DC current flowing to/from the battery bank.", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - A_CHA_MAX(new PointImpl(// - "S802_A_CHA_MAX", // - "Max Charge Current", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + A_CHA_MAX(new ScaledValuePoint("S802_A_CHA_MAX", "Max Charge Current", // "Instantaneous maximum DC charge current.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "AMax_SF", // - new OptionsEnum[0])), // - A_DIS_CHA_MAX(new PointImpl(// - "S802_A_DIS_CHA_MAX", // - "Max Discharge Current", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "AMax_SF")), // + A_DIS_CHA_MAX(new ScaledValuePoint("S802_A_DIS_CHA_MAX", "Max Discharge Current", // "Instantaneous maximum DC discharge current.", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "AMax_SF", // - new OptionsEnum[0])), // - W(new PointImpl(// - "S802_W", // - "Total Power", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "AMax_SF")), // + W(new ScaledValuePoint("S802_W", "Total Power", // "Total power flowing to/from the battery bank.", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - REQ_INV_STATE(new PointImpl(// - "S802_REQ_INV_STATE", // - "Inverter State Request", // + ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + REQ_INV_STATE(new EnumPoint("S802_REQ_INV_STATE", "Inverter State Request", // "Request from battery to start or stop the inverter. Enumeration.", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S802_ReqInvState.values())), // - REQ_W(new PointImpl(// - "S802_REQ_W", // - "Battery Power Request", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, S802_ReqInvState.values())), // + REQ_W(new ScaledValuePoint("S802_REQ_W", "Battery Power Request", // "AC Power requested by battery.", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "W_SF", // - new OptionsEnum[0])), // - SET_OP(new PointImpl(// - "S802_SET_OP", // - "Set Operation", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + SET_OP(new EnumPoint("S802_SET_OP", "Set Operation", // "Instruct the battery bank to perform an operation such as connecting. Enumeration.", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S802_SetOp.values())), // - SET_INV_STATE(new PointImpl(// - "S802_SET_INV_STATE", // - "Set Inverter State", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_WRITE, S802_SetOp.values())), // + SET_INV_STATE(new EnumPoint("S802_SET_INV_STATE", "Set Inverter State", // "Set the current state of the inverter.", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - S802_SetInvState.values())), // - A_H_RTG_S_F(new PointImpl(// - "S802_A_H_RTG_S_F", // - "", // - "Scale factor for charge capacity.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - W_H_RTG_S_F(new PointImpl(// - "S802_W_H_RTG_S_F", // - "", // - "Scale factor for energy capacity.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - W_CHA_DIS_CHA_MAX_S_F(new PointImpl(// - "S802_W_CHA_DIS_CHA_MAX_S_F", // - "", // - "Scale factor for maximum charge and discharge rate.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - DIS_CHA_RTE_S_F(new PointImpl(// - "S802_DIS_CHA_RTE_S_F", // - "", // - "Scale factor for self discharge rate.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - SO_C_S_F(new PointImpl(// - "S802_SO_C_S_F", // - "", // - "Scale factor for state of charge values.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - DO_D_S_F(new PointImpl(// - "S802_DO_D_S_F", // - "", // - "Scale factor for depth of discharge.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - SO_H_S_F(new PointImpl(// - "S802_SO_H_S_F", // - "", // - "Scale factor for state of health.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - V_SF(new PointImpl(// - "S802_V_SF", // - "", // - "Scale factor for DC bus voltage.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - CELL_V_S_F(new PointImpl(// - "S802_CELL_V_S_F", // - "", // - "Scale factor for cell voltage.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - A_SF(new PointImpl(// - "S802_A_SF", // - "", // - "Scale factor for DC current.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - A_MAX_S_F(new PointImpl(// - "S802_A_MAX_S_F", // - "", // - "Scale factor for instantaneous DC charge/discharge current.", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - W_SF(new PointImpl(// - "S802_W_SF", // - "", // - "Scale factor for AC power request.", // - "", // - PointType.SUNSSF, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // - - protected final PointImpl impl; - - private S802(PointImpl impl) { - this.impl = impl; - } - - @Override - public PointImpl get() { - return this.impl; + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_WRITE, S802_SetInvState.values())), // + A_H_RTG_S_F(new ScaleFactorPoint("S802_A_H_RTG_S_F", "", // + "Scale factor for charge capacity.")), // + W_H_RTG_S_F(new ScaleFactorPoint("S802_W_H_RTG_S_F", "", // + "Scale factor for energy capacity.")), // + W_CHA_DIS_CHA_MAX_S_F(new ScaleFactorPoint("S802_W_CHA_DIS_CHA_MAX_S_F", "", // + "Scale factor for maximum charge and discharge rate.")), // + DIS_CHA_RTE_S_F(new ScaleFactorPoint("S802_DIS_CHA_RTE_S_F", "", // + "Scale factor for self discharge rate.")), // + SO_C_S_F(new ScaleFactorPoint("S802_SO_C_S_F", "", // + "Scale factor for state of charge values.")), // + DO_D_S_F(new ScaleFactorPoint("S802_DO_D_S_F", "", // + "Scale factor for depth of discharge.")), // + SO_H_S_F(new ScaleFactorPoint("S802_SO_H_S_F", "", // + "Scale factor for state of health.")), // + V_SF(new ScaleFactorPoint("S802_V_SF", "", // + "Scale factor for DC bus voltage.")), // + CELL_V_S_F(new ScaleFactorPoint("S802_CELL_V_S_F", "", // + "Scale factor for cell voltage.")), // + A_SF(new ScaleFactorPoint("S802_A_SF", "", // + "Scale factor for DC current.")), // + A_MAX_S_F(new ScaleFactorPoint("S802_A_MAX_S_F", "", // + "Scale factor for instantaneous DC charge/discharge current.")), // + W_SF(new ScaleFactorPoint("S802_W_SF", "", // + "Scale factor for AC power request.")); + + private final Point point; + + private S802(Point point) { + this.point = point; + } + + @Override + public Point get() { + return this.point; } } @@ -15609,7 +6173,7 @@ public static enum S802_ChaSt implements OptionsEnum { CHARGING(4, "CHARGING"), // FULL(5, "FULL"), // HOLDING(6, "HOLDING"), // - TESTING(7, "TESTING"); // + TESTING(7, "TESTING"); private final int value; private final String name; @@ -15638,7 +6202,7 @@ public OptionsEnum getUndefined() { public static enum S802_LocRemCtl implements OptionsEnum { UNDEFINED(-1, "Undefined"), // REMOTE(0, "REMOTE"), // - LOCAL(1, "LOCAL"); // + LOCAL(1, "LOCAL"); private final int value; private final String name; @@ -15677,7 +6241,7 @@ public static enum S802_Typ implements OptionsEnum { RECHARGEABLE_ALKALINE(8, "RECHARGEABLE_ALKALINE"), // SODIUM_SULFUR(9, "SODIUM_SULFUR"), // FLOW(10, "FLOW"), // - OTHER(99, "OTHER"); // + OTHER(99, "OTHER"); private final int value; private final String name; @@ -15711,7 +6275,7 @@ public static enum S802_State implements OptionsEnum { STANDBY(4, "STANDBY"), // SOC_PROTECTION(5, "SOC_PROTECTION"), // SUSPENDING(6, "SUSPENDING"), // - FAULT(99, "FAULT"); // + FAULT(99, "FAULT"); private final int value; private final String name; @@ -15737,60 +6301,47 @@ public OptionsEnum getUndefined() { } } - public static enum S802_Evt1 implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - COMMUNICATION_ERROR(0, "COMMUNICATION_ERROR"), // - OVER_TEMP_ALARM(1, "OVER_TEMP_ALARM"), // - OVER_TEMP_WARNING(2, "OVER_TEMP_WARNING"), // - UNDER_TEMP_ALARM(3, "UNDER_TEMP_ALARM"), // - UNDER_TEMP_WARNING(4, "UNDER_TEMP_WARNING"), // - OVER_CHARGE_CURRENT_ALARM(5, "OVER_CHARGE_CURRENT_ALARM"), // - OVER_CHARGE_CURRENT_WARNING(6, "OVER_CHARGE_CURRENT_WARNING"), // - OVER_DISCHARGE_CURRENT_ALARM(7, "OVER_DISCHARGE_CURRENT_ALARM"), // - OVER_DISCHARGE_CURRENT_WARNING(8, "OVER_DISCHARGE_CURRENT_WARNING"), // - OVER_VOLT_ALARM(9, "OVER_VOLT_ALARM"), // - OVER_VOLT_WARNING(10, "OVER_VOLT_WARNING"), // - UNDER_VOLT_ALARM(11, "UNDER_VOLT_ALARM"), // - UNDER_VOLT_WARNING(12, "UNDER_VOLT_WARNING"), // - UNDER_SOC_MIN_ALARM(13, "UNDER_SOC_MIN_ALARM"), // - UNDER_SOC_MIN_WARNING(14, "UNDER_SOC_MIN_WARNING"), // - OVER_SOC_MAX_ALARM(15, "OVER_SOC_MAX_ALARM"), // - OVER_SOC_MAX_WARNING(16, "OVER_SOC_MAX_WARNING"), // - VOLTAGE_IMBALANCE_WARNING(17, "VOLTAGE_IMBALANCE_WARNING"), // - TEMPERATURE_IMBALANCE_ALARM(18, "TEMPERATURE_IMBALANCE_ALARM"), // - TEMPERATURE_IMBALANCE_WARNING(19, "TEMPERATURE_IMBALANCE_WARNING"), // - CONTACTOR_ERROR(20, "CONTACTOR_ERROR"), // - FAN_ERROR(21, "FAN_ERROR"), // - GROUND_FAULT(22, "GROUND_FAULT"), // - OPEN_DOOR_ERROR(23, "OPEN_DOOR_ERROR"), // - CURRENT_IMBALANCE_WARNING(24, "CURRENT_IMBALANCE_WARNING"), // - OTHER_ALARM(25, "OTHER_ALARM"), // - OTHER_WARNING(26, "OTHER_WARNING"), // - RESERVED_1(27, "RESERVED_1"), // - CONFIGURATION_ALARM(28, "CONFIGURATION_ALARM"), // - CONFIGURATION_WARNING(29, "CONFIGURATION_WARNING"); // - - private final int value; - private final String name; - - private S802_Evt1(int value, String name) { - this.value = value; - this.name = name; - } + public static enum S802_Evt1 implements SunSpecBitPoint { + COMMUNICATION_ERROR(new BitPoint(0, "S802_EVT1_COMMUNICATION_ERROR", "Communication Error")), // + OVER_TEMP_ALARM(new BitPoint(1, "S802_EVT1_OVER_TEMP_ALARM", "Over Temp Alarm")), // + OVER_TEMP_WARNING(new BitPoint(2, "S802_EVT1_OVER_TEMP_WARNING", "Over Temp Warning")), // + UNDER_TEMP_ALARM(new BitPoint(3, "S802_EVT1_UNDER_TEMP_ALARM", "Under Temp Alarm")), // + UNDER_TEMP_WARNING(new BitPoint(4, "S802_EVT1_UNDER_TEMP_WARNING", "Under Temp Warning")), // + OVER_CHARGE_CURRENT_ALARM(new BitPoint(5, "S802_EVT1_OVER_CHARGE_CURRENT_ALARM", "Over Charge Current Alarm")), // + OVER_CHARGE_CURRENT_WARNING(new BitPoint(6, "S802_EVT1_OVER_CHARGE_CURRENT_WARNING", "Over Charge Current Warning")), // + OVER_DISCHARGE_CURRENT_ALARM(new BitPoint(7, "S802_EVT1_OVER_DISCHARGE_CURRENT_ALARM", "Over Discharge Current Alarm")), // + OVER_DISCHARGE_CURRENT_WARNING(new BitPoint(8, "S802_EVT1_OVER_DISCHARGE_CURRENT_WARNING", "Over Discharge Current Warning")), // + OVER_VOLT_ALARM(new BitPoint(9, "S802_EVT1_OVER_VOLT_ALARM", "Over Volt Alarm")), // + OVER_VOLT_WARNING(new BitPoint(10, "S802_EVT1_OVER_VOLT_WARNING", "Over Volt Warning")), // + UNDER_VOLT_ALARM(new BitPoint(11, "S802_EVT1_UNDER_VOLT_ALARM", "Under Volt Alarm")), // + UNDER_VOLT_WARNING(new BitPoint(12, "S802_EVT1_UNDER_VOLT_WARNING", "Under Volt Warning")), // + UNDER_SOC_MIN_ALARM(new BitPoint(13, "S802_EVT1_UNDER_SOC_MIN_ALARM", "Under Soc Min Alarm")), // + UNDER_SOC_MIN_WARNING(new BitPoint(14, "S802_EVT1_UNDER_SOC_MIN_WARNING", "Under Soc Min Warning")), // + OVER_SOC_MAX_ALARM(new BitPoint(15, "S802_EVT1_OVER_SOC_MAX_ALARM", "Over Soc Max Alarm")), // + OVER_SOC_MAX_WARNING(new BitPoint(16, "S802_EVT1_OVER_SOC_MAX_WARNING", "Over Soc Max Warning")), // + VOLTAGE_IMBALANCE_WARNING(new BitPoint(17, "S802_EVT1_VOLTAGE_IMBALANCE_WARNING", "Voltage Imbalance Warning")), // + TEMPERATURE_IMBALANCE_ALARM(new BitPoint(18, "S802_EVT1_TEMPERATURE_IMBALANCE_ALARM", "Temperature Imbalance Alarm")), // + TEMPERATURE_IMBALANCE_WARNING(new BitPoint(19, "S802_EVT1_TEMPERATURE_IMBALANCE_WARNING", "Temperature Imbalance Warning")), // + CONTACTOR_ERROR(new BitPoint(20, "S802_EVT1_CONTACTOR_ERROR", "Contactor Error")), // + FAN_ERROR(new BitPoint(21, "S802_EVT1_FAN_ERROR", "Fan Error")), // + GROUND_FAULT(new BitPoint(22, "S802_EVT1_GROUND_FAULT", "Ground Fault")), // + OPEN_DOOR_ERROR(new BitPoint(23, "S802_EVT1_OPEN_DOOR_ERROR", "Open Door Error")), // + CURRENT_IMBALANCE_WARNING(new BitPoint(24, "S802_EVT1_CURRENT_IMBALANCE_WARNING", "Current Imbalance Warning")), // + OTHER_ALARM(new BitPoint(25, "S802_EVT1_OTHER_ALARM", "Other Alarm")), // + OTHER_WARNING(new BitPoint(26, "S802_EVT1_OTHER_WARNING", "Other Warning")), // + RESERVED_1(new BitPoint(27, "S802_EVT1_RESERVED_1", "Reserved 1")), // + CONFIGURATION_ALARM(new BitPoint(28, "S802_EVT1_CONFIGURATION_ALARM", "Configuration Alarm")), // + CONFIGURATION_WARNING(new BitPoint(29, "S802_EVT1_CONFIGURATION_WARNING", "Configuration Warning")); - @Override - public int getValue() { - return this.value; - } + private final BitPoint point; - @Override - public String getName() { - return this.name; + private S802_Evt1(BitPoint point) { + this.point = point; } @Override - public OptionsEnum getUndefined() { - return UNDEFINED; + public BitPoint get() { + return this.point; } } @@ -15798,7 +6349,7 @@ public static enum S802_ReqInvState implements OptionsEnum { UNDEFINED(-1, "Undefined"), // NO_REQUEST(0, "NO_REQUEST"), // START(1, "START"), // - STOP(2, "STOP"); // + STOP(2, "STOP"); private final int value; private final String name; @@ -15827,7 +6378,7 @@ public OptionsEnum getUndefined() { public static enum S802_SetOp implements OptionsEnum { UNDEFINED(-1, "Undefined"), // CONNECT(1, "CONNECT"), // - DISCONNECT(2, "DISCONNECT"); // + DISCONNECT(2, "DISCONNECT"); private final int value; private final String name; @@ -15857,7 +6408,7 @@ public static enum S802_SetInvState implements OptionsEnum { UNDEFINED(-1, "Undefined"), // INVERTER_STOPPED(1, "INVERTER_STOPPED"), // INVERTER_STANDBY(2, "INVERTER_STANDBY"), // - INVERTER_STARTED(3, "INVERTER_STARTED"); // + INVERTER_STARTED(3, "INVERTER_STARTED"); private final int value; private final String name; @@ -15884,1407 +6435,169 @@ public OptionsEnum getUndefined() { } public static enum S64001 implements SunSpecPoint { - CMD(new PointImpl(// - "S64001_CMD", // - "Command Code", // - "", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_WRITE, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - H_W_REV(new PointImpl(// - "S64001_H_W_REV", // - "Hardware Revision", // - "", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - R_S_F_W_REV(new PointImpl(// - "S64001_R_S_F_W_REV", // - "RS FW Revision", // - "", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - O_S_F_W_REV(new PointImpl(// - "S64001_O_S_F_W_REV", // - "OS FW Revision", // - "", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - PROD_REV(new PointImpl(// - "S64001_PROD_REV", // - "Product Revision", // - "", // - "", // - PointType.STRING2, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - BOOTS(new PointImpl(// - "S64001_BOOTS", // - "Boot Count", // - "", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - SWITCH(new PointImpl(// - "S64001_SWITCH", // - "DIP Switches", // - "", // - "", // - PointType.BITFIELD16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - SENSORS(new PointImpl(// - "S64001_SENSORS", // - "Num Detected Sensors", // - "", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TALKING(new PointImpl(// - "S64001_TALKING", // - "Num Communicating Sensors", // - "", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - STATUS(new PointImpl(// - "S64001_STATUS", // - "System Status", // - "", // - "", // - PointType.BITFIELD16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - CONFIG(new PointImpl(// - "S64001_CONFIG", // - "System Configuration", // - "", // - "", // - PointType.BITFIELD16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - L_E_DBLINK(new PointImpl(// - "S64001_L_E_DBLINK", // - "LED Blink Threshold", // - "", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - L_E_DON(new PointImpl(// - "S64001_L_E_DON", // - "LED On Threshold", // - "", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - RESERVED(new PointImpl(// - "S64001_RESERVED", // - "", // - "", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - LOC(new PointImpl(// - "S64001_LOC", // - "Location String", // - "", // - "", // - PointType.STRING16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - S1ID(new PointImpl(// - "S64001_S1ID", // - "Sensor 1 Unit ID", // - "", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - S1_ADDR(new PointImpl(// - "S64001_S1_ADDR", // - "Sensor 1 Address", // - "", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - S1_O_S_VER(new PointImpl(// - "S64001_S1_O_S_VER", // - "Sensor 1 OS Version", // - "", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - S1_VER(new PointImpl(// - "S64001_S1_VER", // - "Sensor 1 Product Version", // - "", // - "", // - PointType.STRING2, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - S1_SERIAL(new PointImpl(// - "S64001_S1_SERIAL", // - "Sensor 1 Serial Num", // - "", // - "", // - PointType.STRING5, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - S2ID(new PointImpl(// - "S64001_S2ID", // - "Sensor 2 Unit ID", // - "", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - S2_ADDR(new PointImpl(// - "S64001_S2_ADDR", // - "Sensor 2 Address", // - "", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - S2_O_S_VER(new PointImpl(// - "S64001_S2_O_S_VER", // - "Sensor 2 OS Version", // - "", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - S2_VER(new PointImpl(// - "S64001_S2_VER", // - "Sensor 2 Product Version", // - "", // - "", // - PointType.STRING2, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - S2_SERIAL(new PointImpl(// - "S64001_S2_SERIAL", // - "Sensor 2 Serial Num", // - "", // - "", // - PointType.STRING5, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - S3ID(new PointImpl(// - "S64001_S3ID", // - "Sensor 3 Unit ID", // - "", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - S3_ADDR(new PointImpl(// - "S64001_S3_ADDR", // - "Sensor 3 Address", // - "", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - S3_O_S_VER(new PointImpl(// - "S64001_S3_O_S_VER", // - "Sensor 3 OS Version", // - "", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - S3_VER(new PointImpl(// - "S64001_S3_VER", // - "Sensor 3 Product Version", // - "", // - "", // - PointType.STRING2, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - S3_SERIAL(new PointImpl(// - "S64001_S3_SERIAL", // - "Sensor 3 Serial Num", // - "", // - "", // - PointType.STRING5, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - S4ID(new PointImpl(// - "S64001_S4ID", // - "Sensor 4 Unit ID", // - "", // - "", // - PointType.ENUM16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - S4_ADDR(new PointImpl(// - "S64001_S4_ADDR", // - "Sensor 4 Address", // - "", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - S4_O_S_VER(new PointImpl(// - "S64001_S4_O_S_VER", // - "Sensor 4 OS Version", // - "", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - S4_VER(new PointImpl(// - "S64001_S4_VER", // - "Sensor 4 Product Version", // - "", // - "", // - PointType.STRING2, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - S4_SERIAL(new PointImpl(// - "S64001_S4_SERIAL", // - "Sensor 4 Serial Num", // - "", // - "", // - PointType.STRING5, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // - - protected final PointImpl impl; - - private S64001(PointImpl impl) { - this.impl = impl; - } - - @Override - public PointImpl get() { - return this.impl; + CMD(new EnumPoint("S64001_CMD", "Command Code", "", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, new OptionsEnum[0])), // + H_W_REV(new ValuePoint("S64001_H_W_REV", "Hardware Revision", "", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + R_S_F_W_REV(new ValuePoint("S64001_R_S_F_W_REV", "RS FW Revision", "", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + O_S_F_W_REV(new ValuePoint("S64001_O_S_F_W_REV", "OS FW Revision", "", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + PROD_REV(new ValuePoint("S64001_PROD_REV", "Product Revision", "", // + ValuePoint.Type.STRING2, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + BOOTS(new ValuePoint("S64001_BOOTS", "Boot Count", "", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + SWITCH(new BitFieldPoint("S64001_SWITCH", "DIP Switches", "", // + BitFieldPoint.Type.BITFIELD16, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + SENSORS(new ValuePoint("S64001_SENSORS", "Num Detected Sensors", "", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + TALKING(new ValuePoint("S64001_TALKING", "Num Communicating Sensors", "", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + STATUS(new BitFieldPoint("S64001_STATUS", "System Status", "", // + BitFieldPoint.Type.BITFIELD16, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + CONFIG(new BitFieldPoint("S64001_CONFIG", "System Configuration", "", // + BitFieldPoint.Type.BITFIELD16, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + L_E_DBLINK(new ValuePoint("S64001_L_E_DBLINK", "LED Blink Threshold", "", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + L_E_DON(new ValuePoint("S64001_L_E_DON", "LED On Threshold", "", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + RESERVED(new ValuePoint("S64001_RESERVED", "", "", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + LOC(new ValuePoint("S64001_LOC", "Location String", "", // + ValuePoint.Type.STRING16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + S1ID(new EnumPoint("S64001_S1ID", "Sensor 1 Unit ID", "", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, new OptionsEnum[0])), // + S1_ADDR(new ValuePoint("S64001_S1_ADDR", "Sensor 1 Address", "", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + S1_O_S_VER(new ValuePoint("S64001_S1_O_S_VER", "Sensor 1 OS Version", "", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + S1_VER(new ValuePoint("S64001_S1_VER", "Sensor 1 Product Version", "", // + ValuePoint.Type.STRING2, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + S1_SERIAL(new ValuePoint("S64001_S1_SERIAL", "Sensor 1 Serial Num", "", // + ValuePoint.Type.STRING5, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + S2ID(new EnumPoint("S64001_S2ID", "Sensor 2 Unit ID", "", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, new OptionsEnum[0])), // + S2_ADDR(new ValuePoint("S64001_S2_ADDR", "Sensor 2 Address", "", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + S2_O_S_VER(new ValuePoint("S64001_S2_O_S_VER", "Sensor 2 OS Version", "", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + S2_VER(new ValuePoint("S64001_S2_VER", "Sensor 2 Product Version", "", // + ValuePoint.Type.STRING2, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + S2_SERIAL(new ValuePoint("S64001_S2_SERIAL", "Sensor 2 Serial Num", "", // + ValuePoint.Type.STRING5, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + S3ID(new EnumPoint("S64001_S3ID", "Sensor 3 Unit ID", "", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, new OptionsEnum[0])), // + S3_ADDR(new ValuePoint("S64001_S3_ADDR", "Sensor 3 Address", "", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + S3_O_S_VER(new ValuePoint("S64001_S3_O_S_VER", "Sensor 3 OS Version", "", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + S3_VER(new ValuePoint("S64001_S3_VER", "Sensor 3 Product Version", "", // + ValuePoint.Type.STRING2, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + S3_SERIAL(new ValuePoint("S64001_S3_SERIAL", "Sensor 3 Serial Num", "", // + ValuePoint.Type.STRING5, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + S4ID(new EnumPoint("S64001_S4ID", "Sensor 4 Unit ID", "", // + EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, new OptionsEnum[0])), // + S4_ADDR(new ValuePoint("S64001_S4_ADDR", "Sensor 4 Address", "", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + S4_O_S_VER(new ValuePoint("S64001_S4_O_S_VER", "Sensor 4 OS Version", "", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + S4_VER(new ValuePoint("S64001_S4_VER", "Sensor 4 Product Version", "", // + ValuePoint.Type.STRING2, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + S4_SERIAL(new ValuePoint("S64001_S4_SERIAL", "Sensor 4 Serial Num", "", // + ValuePoint.Type.STRING5, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)); + + private final Point point; + + private S64001(Point point) { + this.point = point; + } + + @Override + public Point get() { + return this.point; } } public static enum S64101 implements SunSpecPoint { - ELTEK_COUNTRY_CODE(new PointImpl(// - "S64101_ELTEK_COUNTRY_CODE", // - "", // - "", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - ELTEK_FEEDING_PHASE(new PointImpl(// - "S64101_ELTEK_FEEDING_PHASE", // - "", // - "", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - ELTEK_A_P_D_METHOD(new PointImpl(// - "S64101_ELTEK_A_P_D_METHOD", // - "", // - "", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - ELTEK_A_P_D_POWER_REF(new PointImpl(// - "S64101_ELTEK_A_P_D_POWER_REF", // - "", // - "", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - ELTEK_R_P_S_METHOD(new PointImpl(// - "S64101_ELTEK_R_P_S_METHOD", // - "", // - "", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - ELTEK_R_P_S_Q_REF(new PointImpl(// - "S64101_ELTEK_R_P_S_Q_REF", // - "", // - "", // - "", // - PointType.UINT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - ELTEK_R_P_S_COS_PHI_REF(new PointImpl(// - "S64101_ELTEK_R_P_S_COS_PHI_REF", // - "", // - "", // - "", // - PointType.INT16, // - false, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // - - protected final PointImpl impl; - - private S64101(PointImpl impl) { - this.impl = impl; - } - - @Override - public PointImpl get() { - return this.impl; - } - } - - public static enum S64110 implements SunSpecPoint { - MAJOR_F_W_REV(new PointImpl(// - "S64110_MAJOR_F_W_REV", // - "AXS Major Firmware Number", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - MID_F_W_REV(new PointImpl(// - "S64110_MID_F_W_REV", // - "AXS Mid Firmware Number", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - MINOR_F_W_REV(new PointImpl(// - "S64110_MINOR_F_W_REV", // - "AXS Minor Firmware Number", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - ENCRYP_KEY(new PointImpl(// - "S64110_ENCRYP_KEY", // - "Encryption Key", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - M_A_C_ADDRESS(new PointImpl(// - "S64110_M_A_C_ADDRESS", // - "MAC Address", // - "", // - "", // - PointType.STRING7, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - WRITE_PASSWORD(new PointImpl(// - "S64110_WRITE_PASSWORD", // - "Write Password", // - "", // - "", // - PointType.STRING8, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - ENABLE_D_H_C_P(new PointImpl(// - "S64110_ENABLE_D_H_C_P", // - "Enable DHCP", // - "", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - T_C_P_I_P_ADDRESS(new PointImpl(// - "S64110_T_C_P_I_P_ADDRESS", // - "TCPIP Address", // - "", // - "", // - PointType.IPADDR, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - GATEWAY_ADDRESS(new PointImpl(// - "S64110_GATEWAY_ADDRESS", // - "TCPIP Gateway", // - "", // - "", // - PointType.IPADDR, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - T_C_P_I_P_NETMASK(new PointImpl(// - "S64110_T_C_P_I_P_NETMASK", // - "TCPIP Netmask", // - "", // - "", // - PointType.IPADDR, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - D_N_S1_ADDRESS(new PointImpl(// - "S64110_D_N_S1_ADDRESS", // - "TCPIP DNS1", // - "", // - "", // - PointType.IPADDR, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - D_N_S2_ADDRESS(new PointImpl(// - "S64110_D_N_S2_ADDRESS", // - "TCPIP DNS2", // - "", // - "", // - PointType.IPADDR, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - MODBUS_PORT(new PointImpl(// - "S64110_MODBUS_PORT", // - "ModBus Port", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - S_M_T_P_SERVER_NM(new PointImpl(// - "S64110_S_M_T_P_SERVER_NM", // - "SMTP Server Name", // - "", // - "", // - PointType.STRING20, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - S_M_T_P_ACCOUNT_NM(new PointImpl(// - "S64110_S_M_T_P_ACCOUNT_NM", // - "SMTP Account Name", // - "", // - "", // - PointType.STRING16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - S_M_T_P_ENABLE_S_S_L(new PointImpl(// - "S64110_S_M_T_P_ENABLE_S_S_L", // - "Enable SMTP SSL", // - "", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S64110_SMTP_enable_SSL.values())), // - S_M_T_P_PASSWORD(new PointImpl(// - "S64110_S_M_T_P_PASSWORD", // - "SMTP Password", // - "", // - "", // - PointType.STRING8, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - S_M_T_P_USER_NM(new PointImpl(// - "S64110_S_M_T_P_USER_NM", // - "SMTP User Name", // - "", // - "", // - PointType.STRING20, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - STAT_EMAIL_INT(new PointImpl(// - "S64110_STAT_EMAIL_INT", // - "Status Email Interval", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - STAT_START_H_R(new PointImpl(// - "S64110_STAT_START_H_R", // - "Status Email Start Hour", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - STAT_EMAIL_SUB(new PointImpl(// - "S64110_STAT_EMAIL_SUB", // - "Status Email Subject", // - "", // - "", // - PointType.STRING25, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - STAT_EMAIL_ADDR1(new PointImpl(// - "S64110_STAT_EMAIL_ADDR1", // - "Status Email to Address 1", // - "", // - "", // - PointType.STRING20, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - STAT_EMAIL_ADDR2(new PointImpl(// - "S64110_STAT_EMAIL_ADDR2", // - "Status Email to Address 2", // - "", // - "", // - PointType.STRING20, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - ALARM_EMAIL_EN(new PointImpl(// - "S64110_ALARM_EMAIL_EN", // - "Enable Alarm Email", // - "", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S64110_Alarm_email_en.values())), // - ALARM_EMAIL_SUB(new PointImpl(// - "S64110_ALARM_EMAIL_SUB", // - "Alarm Email Subject", // - "", // - "", // - PointType.STRING25, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - ALARM_EMAIL_ADDR1(new PointImpl(// - "S64110_ALARM_EMAIL_ADDR1", // - "Alarm Email to Address 1", // - "", // - "", // - PointType.STRING20, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - ALARM_EMAIL_ADDR2(new PointImpl(// - "S64110_ALARM_EMAIL_ADDR2", // - "Alarm Email to Address 2", // - "", // - "", // - PointType.STRING20, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - F_T_P_PASSWORD(new PointImpl(// - "S64110_F_T_P_PASSWORD", // - "FTP Password", // - "", // - "", // - PointType.STRING8, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - T_E_L_N_E_T_PASSWORD(new PointImpl(// - "S64110_T_E_L_N_E_T_PASSWORD", // - "Telnet Password", // - "", // - "", // - PointType.STRING8, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - LOG_WRITE_INT(new PointImpl(// - "S64110_LOG_WRITE_INT", // - "SD-Card Datalog Write Interval", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - LOG_RETAIN(new PointImpl(// - "S64110_LOG_RETAIN", // - "SD-Card Datalog Retain", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - LOG_MODE(new PointImpl(// - "S64110_LOG_MODE", // - "SD-Card Datalog Mode", // - "", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S64110_Log_mode.values())), // - N_T_P_SERVER_NM(new PointImpl(// - "S64110_N_T_P_SERVER_NM", // - "NTP Timer Server Name", // - "", // - "", // - PointType.STRING20, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - N_T_P_ENABLE(new PointImpl(// - "S64110_N_T_P_ENABLE", // - "Enable Network Time", // - "", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S64110_NTP_enable.values())), // - TIME_ZONE(new PointImpl(// - "S64110_TIME_ZONE", // - "Time Zone", // - "", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - DATE_YEAR(new PointImpl(// - "S64110_DATE_YEAR", // - "Year", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - DATE_MONTH(new PointImpl(// - "S64110_DATE_MONTH", // - "Month", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - DATE_DAY(new PointImpl(// - "S64110_DATE_DAY", // - "Day", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TIME_HOUR(new PointImpl(// - "S64110_TIME_HOUR", // - "Hour", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TIME_MINUTE(new PointImpl(// - "S64110_TIME_MINUTE", // - "Minute", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - TIME_SECOND(new PointImpl(// - "S64110_TIME_SECOND", // - "Second", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - BATTERY_TEMP(new PointImpl(// - "S64110_BATTERY_TEMP", // - "Battery Temperature", // - "", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - "Temp_SF", // - new OptionsEnum[0])), // - AMBIENT_TEMP(new PointImpl(// - "S64110_AMBIENT_TEMP", // - "Ambient Temperature", // - "", // - "", // - PointType.INT16, // - true, // - AccessMode.READ_ONLY, // - Unit.DEGREE_CELSIUS, // - "Temp_SF", // - new OptionsEnum[0])), // - TEMP_S_F(new PointImpl(// - "S64110_TEMP_S_F", // - "", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - A_X_S_ERROR(new PointImpl(// - "S64110_A_X_S_ERROR", // - "AXS Error", // - "", // - "", // - PointType.BITFIELD16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - A_X_S_STATUS(new PointImpl(// - "S64110_A_X_S_STATUS", // - "AXS Status", // - "", // - "", // - PointType.BITFIELD16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - A_X_S_SPARE(new PointImpl(// - "S64110_A_X_S_SPARE", // - "Spare", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // - - protected final PointImpl impl; - - private S64110(PointImpl impl) { - this.impl = impl; - } - - @Override - public PointImpl get() { - return this.impl; - } - } - - public static enum S64110_SMTP_enable_SSL implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - ASX_DISABLED(0, "ASX_DISABLED"), // - ASX_ENABLED(1, "ASX_ENABLED"); // - - private final int value; - private final String name; - - private S64110_SMTP_enable_SSL(int value, String name) { - this.value = value; - this.name = name; - } - - @Override - public int getValue() { - return this.value; - } - - @Override - public String getName() { - return this.name; - } - - @Override - public OptionsEnum getUndefined() { - return UNDEFINED; - } - } - - public static enum S64110_Alarm_email_en implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - ASX_DISABLED(0, "ASX_DISABLED"), // - ASX_ENABLED(1, "ASX_ENABLED"); // - - private final int value; - private final String name; - - private S64110_Alarm_email_en(int value, String name) { - this.value = value; - this.name = name; - } - - @Override - public int getValue() { - return this.value; - } - - @Override - public String getName() { - return this.name; - } - - @Override - public OptionsEnum getUndefined() { - return UNDEFINED; - } - } - - public static enum S64110_Log_mode implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - LOG_DISABLED(0, "LOG_DISABLED"), // - LOG_EXCEL(1, "LOG_EXCEL"), // - LOG_COMPACT(2, "LOG_COMPACT"); // - - private final int value; - private final String name; - - private S64110_Log_mode(int value, String name) { - this.value = value; - this.name = name; - } - - @Override - public int getValue() { - return this.value; - } - - @Override - public String getName() { - return this.name; - } - - @Override - public OptionsEnum getUndefined() { - return UNDEFINED; - } - } - - public static enum S64110_NTP_enable implements OptionsEnum { - UNDEFINED(-1, "Undefined"), // - ASX_DISABLED(0, "ASX_DISABLED"), // - ASX_ENABLED(1, "ASX_ENABLED"); // + ELTEK_COUNTRY_CODE(new ValuePoint("S64101_ELTEK_COUNTRY_CODE", "", "", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + ELTEK_FEEDING_PHASE(new ValuePoint("S64101_ELTEK_FEEDING_PHASE", "", "", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + ELTEK_A_P_D_METHOD(new ValuePoint("S64101_ELTEK_A_P_D_METHOD", "", "", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + ELTEK_A_P_D_POWER_REF(new ValuePoint("S64101_ELTEK_A_P_D_POWER_REF", "", "", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + ELTEK_R_P_S_METHOD(new ValuePoint("S64101_ELTEK_R_P_S_METHOD", "", "", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + ELTEK_R_P_S_Q_REF(new ValuePoint("S64101_ELTEK_R_P_S_Q_REF", "", "", // + ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + ELTEK_R_P_S_COS_PHI_REF(new ValuePoint("S64101_ELTEK_R_P_S_COS_PHI_REF", "", "", // + ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)); - private final int value; - private final String name; - - private S64110_NTP_enable(int value, String name) { - this.value = value; - this.name = name; - } - - @Override - public int getValue() { - return this.value; - } + private final Point point; - @Override - public String getName() { - return this.name; + private S64101(Point point) { + this.point = point; } @Override - public OptionsEnum getUndefined() { - return UNDEFINED; + public Point get() { + return this.point; } } public static enum S64111 implements SunSpecPoint { - PORT(new PointImpl(// - "S64111_PORT", // - "Port Number", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - V_SF(new PointImpl(// - "S64111_V_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - A_SF(new PointImpl(// - "S64111_A_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - P_SF(new PointImpl(// - "S64111_P_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - AH_SF(new PointImpl(// - "S64111_AH_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - KWH_SF(new PointImpl(// - "S64111_KWH_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - BATT_V(new PointImpl(// - "S64111_BATT_V", // - "Battery Voltage", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - ARRAY_V(new PointImpl(// - "S64111_ARRAY_V", // - "Array Voltage", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - OUTPUT_A(new PointImpl(// - "S64111_OUTPUT_A", // - "Output Current", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "A_SF", // - new OptionsEnum[0])), // - INPUT_A(new PointImpl(// - "S64111_INPUT_A", // - "Array Current", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "P_SF", // - new OptionsEnum[0])), // - CHARGER_ST(new PointImpl(// - "S64111_CHARGER_ST", // - "Operating State", // - "", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S64111_ChargerSt.values())), // - OUTPUT_W(new PointImpl(// - "S64111_OUTPUT_W", // - "Output Wattage", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "P_SF", // - new OptionsEnum[0])), // - TODAY_MIN_BAT_V(new PointImpl(// - "S64111_TODAY_MIN_BAT_V", // - "Today's Minimum Battery Voltage", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - TODAY_MAX_BAT_V(new PointImpl(// - "S64111_TODAY_MAX_BAT_V", // - "Today's Maximum Battery Voltage", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - VOCV(new PointImpl(// - "S64111_VOCV", // - "VOC", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - TODAY_MAX_V_O_C(new PointImpl(// - "S64111_TODAY_MAX_V_O_C", // - "Today's Maximum VOC", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - TODAYK_WH_OUTPUT(new PointImpl(// - "S64111_TODAYK_WH_OUTPUT", // - "Today's kWh", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.KILOWATT_HOURS, // - "KWH_SF", // - new OptionsEnum[0])), // - TODAY_A_H_OUTPUT(new PointImpl(// - "S64111_TODAY_A_H_OUTPUT", // - "Today's AH", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE_HOURS, // - "AH_SF", // - new OptionsEnum[0])), // - LIFE_TIME_K_W_H_OUT(new PointImpl(// - "S64111_LIFE_TIME_K_W_H_OUT", // - "Lifetime kWh", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.KILOWATT_HOURS, // - "P_SF", // - new OptionsEnum[0])), // - LIFE_TIME_A_H_OUT(new PointImpl(// - "S64111_LIFE_TIME_A_H_OUT", // - "Lifetime kAH", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.KILOAMPERE_HOURS, // - "KWH_SF", // - new OptionsEnum[0])), // - LIFE_TIME_MAX_OUT(new PointImpl(// - "S64111_LIFE_TIME_MAX_OUT", // - "Lifetime Maximum Output Wattage", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "P_SF", // - new OptionsEnum[0])), // - LIFE_TIME_MAX_BATT(new PointImpl(// - "S64111_LIFE_TIME_MAX_BATT", // - "Lifetime Maximum Battery Voltage", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - LIFE_TIME_MAX_V_O_C(new PointImpl(// - "S64111_LIFE_TIME_MAX_V_O_C", // - "Lifetime Maximum VOC Voltage", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])); // - - protected final PointImpl impl; - - private S64111(PointImpl impl) { - this.impl = impl; - } - - @Override - public PointImpl get() { - return this.impl; + PORT(new ValuePoint("S64111_PORT", "Port Number", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + V_SF(new ScaleFactorPoint("S64111_V_SF", "", "")), // + A_SF(new ScaleFactorPoint("S64111_A_SF", "", "")), // + P_SF(new ScaleFactorPoint("S64111_P_SF", "", "")), // + AH_SF(new ScaleFactorPoint("S64111_AH_SF", "", "")), // + KWH_SF(new ScaleFactorPoint("S64111_KWH_SF", "", "")), // + BATT_V(new ScaledValuePoint("S64111_BATT_V", "Battery Voltage", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + ARRAY_V(new ScaledValuePoint("S64111_ARRAY_V", "Array Voltage", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + OUTPUT_A(new ScaledValuePoint("S64111_OUTPUT_A", "Output Current", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + INPUT_A(new ScaledValuePoint("S64111_INPUT_A", "Array Current", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "P_SF")), // + CHARGER_ST(new EnumPoint("S64111_CHARGER_ST", "Operating State", "", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S64111_ChargerSt.values())), // + OUTPUT_W(new ScaledValuePoint("S64111_OUTPUT_W", "Output Wattage", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "P_SF")), // + TODAY_MIN_BAT_V(new ScaledValuePoint("S64111_TODAY_MIN_BAT_V", "Today's Minimum Battery Voltage", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + TODAY_MAX_BAT_V(new ScaledValuePoint("S64111_TODAY_MAX_BAT_V", "Today's Maximum Battery Voltage", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + VOCV(new ScaledValuePoint("S64111_VOCV", "VOC", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + TODAY_MAX_V_O_C(new ScaledValuePoint("S64111_TODAY_MAX_V_O_C", "Today's Maximum VOC", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + TODAYK_WH_OUTPUT(new ScaledValuePoint("S64111_TODAYK_WH_OUTPUT", "Today's kWh", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.KILOWATT_HOURS, "KWH_SF")), // + TODAY_A_H_OUTPUT(new ScaledValuePoint("S64111_TODAY_A_H_OUTPUT", "Today's AH", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE_HOURS, "AH_SF")), // + LIFE_TIME_K_W_H_OUT(new ScaledValuePoint("S64111_LIFE_TIME_K_W_H_OUT", "Lifetime kWh", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.KILOWATT_HOURS, "P_SF")), // + LIFE_TIME_A_H_OUT(new ScaledValuePoint("S64111_LIFE_TIME_A_H_OUT", "Lifetime kAH", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.KILOAMPERE_HOURS, "KWH_SF")), // + LIFE_TIME_MAX_OUT(new ScaledValuePoint("S64111_LIFE_TIME_MAX_OUT", "Lifetime Maximum Output Wattage", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "P_SF")), // + LIFE_TIME_MAX_BATT(new ScaledValuePoint("S64111_LIFE_TIME_MAX_BATT", "Lifetime Maximum Battery Voltage", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + LIFE_TIME_MAX_V_O_C(new ScaledValuePoint("S64111_LIFE_TIME_MAX_V_O_C", "Lifetime Maximum VOC Voltage", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")); + + private final Point point; + + private S64111(Point point) { + this.point = point; + } + + @Override + public Point get() { + return this.point; } } @@ -17294,7 +6607,7 @@ public static enum S64111_ChargerSt implements OptionsEnum { FLOAT(1, "FLOAT"), // BULK(2, "BULK"), // ABSORB(3, "ABSORB"), // - EQ(4, "EQ"); // + EQ(4, "EQ"); private final int value; private final String name; @@ -17321,720 +6634,138 @@ public OptionsEnum getUndefined() { } public static enum S64112 implements SunSpecPoint { - PORT(new PointImpl(// - "S64112_PORT", // - "Port Number", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - V_SF(new PointImpl(// - "S64112_V_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - C_SF(new PointImpl(// - "S64112_C_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - H_SF(new PointImpl(// - "S64112_H_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - P_SF(new PointImpl(// - "S64112_P_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - AH_SF(new PointImpl(// - "S64112_AH_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - KWH_SF(new PointImpl(// - "S64112_KWH_SF", // - "", // - "", // - "", // - PointType.SUNSSF, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - C_C_CONFIG_FAULT(new PointImpl(// - "S64112_C_C_CONFIG_FAULT", // - "Faults", // - "", // - "", // - PointType.BITFIELD16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - C_C_CONFIG_ABSORB_V(new PointImpl(// - "S64112_C_C_CONFIG_ABSORB_V", // - "Absorb", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - C_C_CONFIG_ABSORB_HR(new PointImpl(// - "S64112_C_C_CONFIG_ABSORB_HR", // - "Absorb Time", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "H_SF", // - new OptionsEnum[0])), // - C_C_CONFIG_ABSORB_END_A(new PointImpl(// - "S64112_C_C_CONFIG_ABSORB_END_A", // - "Absorb End", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "V_SF", // - new OptionsEnum[0])), // - C_C_CONFIG_REBULK_V(new PointImpl(// - "S64112_C_C_CONFIG_REBULK_V", // - "Rebulk", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - C_C_CONFIG_FLOAT_V(new PointImpl(// - "S64112_C_C_CONFIG_FLOAT_V", // - "Float", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - C_C_CONFIG_MAX_CHG_A(new PointImpl(// - "S64112_C_C_CONFIG_MAX_CHG_A", // - "Maximum Charge", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "V_SF", // - new OptionsEnum[0])), // - C_C_CONFIG_EQUALIZE_V(new PointImpl(// - "S64112_C_C_CONFIG_EQUALIZE_V", // - "Equalize", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - C_C_CONFIG_EQUALIZE_HR(new PointImpl(// - "S64112_C_C_CONFIG_EQUALIZE_HR", // - "Equalize Time", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - C_C_CONFIG_AUTO_EQUALIZE(new PointImpl(// - "S64112_C_C_CONFIG_AUTO_EQUALIZE", // - "Auto Equalize Interval", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - C_C_CONFIG_M_P_P_T_MODE(new PointImpl(// - "S64112_C_C_CONFIG_M_P_P_T_MODE", // - "MPPT mode", // - "", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S64112_CC_Config_MPPT_mode.values())), // - C_C_CONFIG_SWEEP_WIDTH(new PointImpl(// - "S64112_C_C_CONFIG_SWEEP_WIDTH", // - "Sweep Width", // - "", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S64112_CC_Config_sweep_width.values())), // - C_C_CONFIG_SWEEP_MAX(new PointImpl(// - "S64112_C_C_CONFIG_SWEEP_MAX", // - "Sweep Maximum", // - "", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S64112_CC_Config_sweep_max.values())), // - C_C_CONFIG_U_PICK_DUTY_CYC(new PointImpl(// - "S64112_C_C_CONFIG_U_PICK_DUTY_CYC", // - "U-Pick PWM Duty Cycle", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "V_SF", // - new OptionsEnum[0])), // - C_C_CONFIG_GRID_TIE(new PointImpl(// - "S64112_C_C_CONFIG_GRID_TIE", // - "Grid Tie Mode", // - "", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S64112_CC_Config_grid_tie.values())), // - C_C_CONFIG_TEMP_COMP(new PointImpl(// - "S64112_C_C_CONFIG_TEMP_COMP", // - "Temp Comp Mode", // - "", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S64112_CC_Config_temp_comp.values())), // - C_C_CONFIG_TEMP_COMP_LLIMT(new PointImpl(// - "S64112_C_C_CONFIG_TEMP_COMP_LLIMT", // - "Temp Comp Lower Limit", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - C_C_CONFIG_TEMP_COMP_HLIMT(new PointImpl(// - "S64112_C_C_CONFIG_TEMP_COMP_HLIMT", // - "Temp Comp Upper Limit", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - C_C_CONFIG_AUTO_RESTART(new PointImpl(// - "S64112_C_C_CONFIG_AUTO_RESTART", // - "Auto Restart Mode", // - "", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S64112_CC_Config_auto_restart.values())), // - C_C_CONFIG_WAKEUP_V_O_C(new PointImpl(// - "S64112_C_C_CONFIG_WAKEUP_V_O_C", // - "Wakeup VOC Change", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - C_C_CONFIG_SNOOZE_MODE_A(new PointImpl(// - "S64112_C_C_CONFIG_SNOOZE_MODE_A", // - "Snooze Mode", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "V_SF", // - new OptionsEnum[0])), // - C_C_CONFIG_WAKEUP_INTERVAL(new PointImpl(// - "S64112_C_C_CONFIG_WAKEUP_INTERVAL", // - "Wakeup Interval", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - C_C_CONFIG_A_U_X_MODE(new PointImpl(// - "S64112_C_C_CONFIG_A_U_X_MODE", // - "AUX Output Mode", // - "", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S64112_CC_Config_AUX_mode.values())), // - C_C_CONFIG_A_U_X_CONTROL(new PointImpl(// - "S64112_C_C_CONFIG_A_U_X_CONTROL", // - "AUX Output Control", // - "", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S64112_CC_Config_AUX_control.values())), // - C_C_CONFIG_A_U_X_STATE(new PointImpl(// - "S64112_C_C_CONFIG_A_U_X_STATE", // - "AUX Output State", // - "", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S64112_CC_Config_AUX_state.values())), // - C_C_CONFIG_A_U_X_POLARITY(new PointImpl(// - "S64112_C_C_CONFIG_A_U_X_POLARITY", // - "AUX Output Polarity", // - "", // - "", // - PointType.ENUM16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - S64112_CC_Config_AUX_polarity.values())), // - C_C_CONFIG_A_U_X_L_BATT_DISC(new PointImpl(// - "S64112_C_C_CONFIG_A_U_X_L_BATT_DISC", // - "AUX Low Battery Disconnect", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - C_C_CONFIG_A_U_X_L_BATT_RCON(new PointImpl(// - "S64112_C_C_CONFIG_A_U_X_L_BATT_RCON", // - "AUX Low Battery Reconnect", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - C_C_CONFIG_A_U_X_L_BATT_DLY(new PointImpl(// - "S64112_C_C_CONFIG_A_U_X_L_BATT_DLY", // - "AUX Low Battery Disconnect Delay", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - C_C_CONFIG_A_U_X_VENT_FAN_V(new PointImpl(// - "S64112_C_C_CONFIG_A_U_X_VENT_FAN_V", // - "AUX Vent Fan", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - C_C_CONFIG_A_U_X_P_V_TRIGGER_V(new PointImpl(// - "S64112_C_C_CONFIG_A_U_X_P_V_TRIGGER_V", // - "AUX PV Trigger", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - C_C_CONFIG_A_U_X_P_V_TRG_H_TM(new PointImpl(// - "S64112_C_C_CONFIG_A_U_X_P_V_TRG_H_TM", // - "AUX PV Trigger Hold Time", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - C_C_CONFIG_A_U_X_NLITE_THRS_V(new PointImpl(// - "S64112_C_C_CONFIG_A_U_X_NLITE_THRS_V", // - "AUX Night Light Threshold", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - C_C_CONFIG_A_U_X_NLITE_ON_TM(new PointImpl(// - "S64112_C_C_CONFIG_A_U_X_NLITE_ON_TM", // - "AUX Night Light On Time", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "H_SF", // - new OptionsEnum[0])), // - C_C_CONFIG_A_U_X_NLITE_ON_HIST(new PointImpl(// - "S64112_C_C_CONFIG_A_U_X_NLITE_ON_HIST", // - "AUX Night Light On Hysteresis", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - C_C_CONFIG_A_U_X_NLITE_OFF_HIST(new PointImpl(// - "S64112_C_C_CONFIG_A_U_X_NLITE_OFF_HIST", // - "AUX Night Light Off Hysteresis", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - C_C_CONFIG_A_U_X_ERROR_BATT_V(new PointImpl(// - "S64112_C_C_CONFIG_A_U_X_ERROR_BATT_V", // - "AUX Error Output Low Battery", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - C_C_CONFIG_A_U_X_DIVERT_H_TIME(new PointImpl(// - "S64112_C_C_CONFIG_A_U_X_DIVERT_H_TIME", // - "AUX Divert Hold Time", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - "V_SF", // - new OptionsEnum[0])), // - C_C_CONFIG_A_U_X_DIVERT_DLY_TIME(new PointImpl(// - "S64112_C_C_CONFIG_A_U_X_DIVERT_DLY_TIME", // - "AUX Divert Delay Time", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - C_C_CONFIG_A_U_X_DIVERT_REL_V(new PointImpl(// - "S64112_C_C_CONFIG_A_U_X_DIVERT_REL_V", // - "AUX Divert Relative", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - C_C_CONFIG_A_U_X_DIVERT_HYST_V(new PointImpl(// - "S64112_C_C_CONFIG_A_U_X_DIVERT_HYST_V", // - "AUX Divert Hysteresis", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - C_C_CONFIG_MAJOR_F_W_REV(new PointImpl(// - "S64112_C_C_CONFIG_MAJOR_F_W_REV", // - "FM CC Major Firmware Number", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - C_C_CONFIG_MID_F_W_REV(new PointImpl(// - "S64112_C_C_CONFIG_MID_F_W_REV", // - "FM CC Mid Firmware Number", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - C_C_CONFIG_MINOR_F_W_REV(new PointImpl(// - "S64112_C_C_CONFIG_MINOR_F_W_REV", // - "FM CC Minor Firmware Number", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - C_C_CONFIG_DATA_LOG_DAY_OFFSET(new PointImpl(// - "S64112_C_C_CONFIG_DATA_LOG_DAY_OFFSET", // - "Set Data Log Day Offset", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - C_C_CONFIG_DATA_LOG_CUR_DAY_OFF(new PointImpl(// - "S64112_C_C_CONFIG_DATA_LOG_CUR_DAY_OFF", // - "Current Data Log Day Offset", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - C_C_CONFIG_DATA_LOG_DAILY_A_H(new PointImpl(// - "S64112_C_C_CONFIG_DATA_LOG_DAILY_A_H", // - "Data Log Daily (Ah)", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE_HOURS, // - null, // - new OptionsEnum[0])), // - C_C_CONFIG_DATA_LOG_DAILY_K_W_H(new PointImpl(// - "S64112_C_C_CONFIG_DATA_LOG_DAILY_K_W_H", // - "Data Log Daily (kWh)", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.KILOWATT_HOURS, // - "KWH_SF", // - new OptionsEnum[0])), // - C_C_CONFIG_DATA_LOG_MAX_OUT_A(new PointImpl(// - "S64112_C_C_CONFIG_DATA_LOG_MAX_OUT_A", // - "Data Log Daily Maximum Output (A)", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.AMPERE, // - "V_SF", // - new OptionsEnum[0])), // - C_C_CONFIG_DATA_LOG_MAX_OUT_W(new PointImpl(// - "S64112_C_C_CONFIG_DATA_LOG_MAX_OUT_W", // - "Data Log Daily Maximum Output (W)", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.WATT, // - "V_SF", // - new OptionsEnum[0])), // - C_C_CONFIG_DATA_LOG_ABSORB_T(new PointImpl(// - "S64112_C_C_CONFIG_DATA_LOG_ABSORB_T", // - "Data Log Daily Absorb Time", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - C_C_CONFIG_DATA_LOG_FLOAT_T(new PointImpl(// - "S64112_C_C_CONFIG_DATA_LOG_FLOAT_T", // - "Data Log Daily Float Time", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - C_C_CONFIG_DATA_LOG_MIN_BATT_V(new PointImpl(// - "S64112_C_C_CONFIG_DATA_LOG_MIN_BATT_V", // - "Data Log Daily Minimum Battery", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - C_C_CONFIG_DATA_LOG_MAX_BATT_V(new PointImpl(// - "S64112_C_C_CONFIG_DATA_LOG_MAX_BATT_V", // - "Data Log Daily Maximum Battery", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - C_C_CONFIG_DATA_LOG_MAX_INPUT_V(new PointImpl(// - "S64112_C_C_CONFIG_DATA_LOG_MAX_INPUT_V", // - "Data Log Daily Maximum Input", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.VOLT, // - "V_SF", // - new OptionsEnum[0])), // - C_C_CONFIG_DATA_LOG_CLEAR(new PointImpl(// - "S64112_C_C_CONFIG_DATA_LOG_CLEAR", // - "Data Log Clear", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])), // - C_C_CONFIG_DATA_LOG_CLR_COMP(new PointImpl(// - "S64112_C_C_CONFIG_DATA_LOG_CLR_COMP", // - "Data Log Clear Complement", // - "", // - "", // - PointType.UINT16, // - true, // - AccessMode.READ_ONLY, // - Unit.NONE, // - null, // - new OptionsEnum[0])); // - - protected final PointImpl impl; - - private S64112(PointImpl impl) { - this.impl = impl; - } - - @Override - public PointImpl get() { - return this.impl; + PORT(new ValuePoint("S64112_PORT", "Port Number", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + V_SF(new ScaleFactorPoint("S64112_V_SF", "", "")), // + C_SF(new ScaleFactorPoint("S64112_C_SF", "", "")), // + H_SF(new ScaleFactorPoint("S64112_H_SF", "", "")), // + P_SF(new ScaleFactorPoint("S64112_P_SF", "", "")), // + AH_SF(new ScaleFactorPoint("S64112_AH_SF", "", "")), // + KWH_SF(new ScaleFactorPoint("S64112_KWH_SF", "", "")), // + C_C_CONFIG_FAULT(new BitFieldPoint("S64112_C_C_CONFIG_FAULT", "Faults", "", // + BitFieldPoint.Type.BITFIELD16, true /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + C_C_CONFIG_ABSORB_V(new ScaledValuePoint("S64112_C_C_CONFIG_ABSORB_V", "Absorb", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + C_C_CONFIG_ABSORB_HR(new ScaledValuePoint("S64112_C_C_CONFIG_ABSORB_HR", "Absorb Time", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "H_SF")), // + C_C_CONFIG_ABSORB_END_A(new ScaledValuePoint("S64112_C_C_CONFIG_ABSORB_END_A", "Absorb End", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "V_SF")), // + C_C_CONFIG_REBULK_V(new ScaledValuePoint("S64112_C_C_CONFIG_REBULK_V", "Rebulk", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + C_C_CONFIG_FLOAT_V(new ScaledValuePoint("S64112_C_C_CONFIG_FLOAT_V", "Float", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + C_C_CONFIG_MAX_CHG_A(new ScaledValuePoint("S64112_C_C_CONFIG_MAX_CHG_A", "Maximum Charge", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "V_SF")), // + C_C_CONFIG_EQUALIZE_V(new ScaledValuePoint("S64112_C_C_CONFIG_EQUALIZE_V", "Equalize", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + C_C_CONFIG_EQUALIZE_HR(new ValuePoint("S64112_C_C_CONFIG_EQUALIZE_HR", "Equalize Time", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + C_C_CONFIG_AUTO_EQUALIZE(new ValuePoint("S64112_C_C_CONFIG_AUTO_EQUALIZE", "Auto Equalize Interval", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + C_C_CONFIG_M_P_P_T_MODE(new EnumPoint("S64112_C_C_CONFIG_M_P_P_T_MODE", "MPPT mode", "", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S64112_CC_Config_MPPT_mode.values())), // + C_C_CONFIG_SWEEP_WIDTH(new EnumPoint("S64112_C_C_CONFIG_SWEEP_WIDTH", "Sweep Width", "", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S64112_CC_Config_sweep_width.values())), // + C_C_CONFIG_SWEEP_MAX(new EnumPoint("S64112_C_C_CONFIG_SWEEP_MAX", "Sweep Maximum", "", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S64112_CC_Config_sweep_max.values())), // + C_C_CONFIG_U_PICK_DUTY_CYC(new ScaledValuePoint("S64112_C_C_CONFIG_U_PICK_DUTY_CYC", "U-Pick PWM Duty Cycle", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "V_SF")), // + C_C_CONFIG_GRID_TIE(new EnumPoint("S64112_C_C_CONFIG_GRID_TIE", "Grid Tie Mode", "", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S64112_CC_Config_grid_tie.values())), // + C_C_CONFIG_TEMP_COMP(new EnumPoint("S64112_C_C_CONFIG_TEMP_COMP", "Temp Comp Mode", "", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S64112_CC_Config_temp_comp.values())), // + C_C_CONFIG_TEMP_COMP_LLIMT(new ScaledValuePoint("S64112_C_C_CONFIG_TEMP_COMP_LLIMT", "Temp Comp Lower Limit", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + C_C_CONFIG_TEMP_COMP_HLIMT(new ScaledValuePoint("S64112_C_C_CONFIG_TEMP_COMP_HLIMT", "Temp Comp Upper Limit", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + C_C_CONFIG_AUTO_RESTART(new EnumPoint("S64112_C_C_CONFIG_AUTO_RESTART", "Auto Restart Mode", "", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S64112_CC_Config_auto_restart.values())), // + C_C_CONFIG_WAKEUP_V_O_C(new ScaledValuePoint("S64112_C_C_CONFIG_WAKEUP_V_O_C", "Wakeup VOC Change", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + C_C_CONFIG_SNOOZE_MODE_A(new ScaledValuePoint("S64112_C_C_CONFIG_SNOOZE_MODE_A", "Snooze Mode", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "V_SF")), // + C_C_CONFIG_WAKEUP_INTERVAL(new ValuePoint("S64112_C_C_CONFIG_WAKEUP_INTERVAL", "Wakeup Interval", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + C_C_CONFIG_A_U_X_MODE(new EnumPoint("S64112_C_C_CONFIG_A_U_X_MODE", "AUX Output Mode", "", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S64112_CC_Config_AUX_mode.values())), // + C_C_CONFIG_A_U_X_CONTROL(new EnumPoint("S64112_C_C_CONFIG_A_U_X_CONTROL", "AUX Output Control", "", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S64112_CC_Config_AUX_control.values())), // + C_C_CONFIG_A_U_X_STATE(new EnumPoint("S64112_C_C_CONFIG_A_U_X_STATE", "AUX Output State", "", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S64112_CC_Config_AUX_state.values())), // + C_C_CONFIG_A_U_X_POLARITY(new EnumPoint("S64112_C_C_CONFIG_A_U_X_POLARITY", "AUX Output Polarity", "", // + EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S64112_CC_Config_AUX_polarity.values())), // + C_C_CONFIG_A_U_X_L_BATT_DISC(new ScaledValuePoint("S64112_C_C_CONFIG_A_U_X_L_BATT_DISC", "AUX Low Battery Disconnect", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + C_C_CONFIG_A_U_X_L_BATT_RCON(new ScaledValuePoint("S64112_C_C_CONFIG_A_U_X_L_BATT_RCON", "AUX Low Battery Reconnect", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + C_C_CONFIG_A_U_X_L_BATT_DLY(new ValuePoint("S64112_C_C_CONFIG_A_U_X_L_BATT_DLY", "AUX Low Battery Disconnect Delay", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + C_C_CONFIG_A_U_X_VENT_FAN_V(new ScaledValuePoint("S64112_C_C_CONFIG_A_U_X_VENT_FAN_V", "AUX Vent Fan", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + C_C_CONFIG_A_U_X_P_V_TRIGGER_V(new ScaledValuePoint("S64112_C_C_CONFIG_A_U_X_P_V_TRIGGER_V", "AUX PV Trigger", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + C_C_CONFIG_A_U_X_P_V_TRG_H_TM(new ValuePoint("S64112_C_C_CONFIG_A_U_X_P_V_TRG_H_TM", "AUX PV Trigger Hold Time", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + C_C_CONFIG_A_U_X_NLITE_THRS_V(new ScaledValuePoint("S64112_C_C_CONFIG_A_U_X_NLITE_THRS_V", "AUX Night Light Threshold", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + C_C_CONFIG_A_U_X_NLITE_ON_TM(new ScaledValuePoint("S64112_C_C_CONFIG_A_U_X_NLITE_ON_TM", "AUX Night Light On Time", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "H_SF")), // + C_C_CONFIG_A_U_X_NLITE_ON_HIST(new ValuePoint("S64112_C_C_CONFIG_A_U_X_NLITE_ON_HIST", "AUX Night Light On Hysteresis", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + C_C_CONFIG_A_U_X_NLITE_OFF_HIST(new ValuePoint("S64112_C_C_CONFIG_A_U_X_NLITE_OFF_HIST", "AUX Night Light Off Hysteresis", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + C_C_CONFIG_A_U_X_ERROR_BATT_V(new ScaledValuePoint("S64112_C_C_CONFIG_A_U_X_ERROR_BATT_V", "AUX Error Output Low Battery", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + C_C_CONFIG_A_U_X_DIVERT_H_TIME(new ScaledValuePoint("S64112_C_C_CONFIG_A_U_X_DIVERT_H_TIME", "AUX Divert Hold Time", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "V_SF")), // + C_C_CONFIG_A_U_X_DIVERT_DLY_TIME(new ValuePoint("S64112_C_C_CONFIG_A_U_X_DIVERT_DLY_TIME", "AUX Divert Delay Time", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + C_C_CONFIG_A_U_X_DIVERT_REL_V(new ScaledValuePoint("S64112_C_C_CONFIG_A_U_X_DIVERT_REL_V", "AUX Divert Relative", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + C_C_CONFIG_A_U_X_DIVERT_HYST_V(new ScaledValuePoint("S64112_C_C_CONFIG_A_U_X_DIVERT_HYST_V", "AUX Divert Hysteresis", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + C_C_CONFIG_MAJOR_F_W_REV(new ValuePoint("S64112_C_C_CONFIG_MAJOR_F_W_REV", "FM CC Major Firmware Number", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + C_C_CONFIG_MID_F_W_REV(new ValuePoint("S64112_C_C_CONFIG_MID_F_W_REV", "FM CC Mid Firmware Number", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + C_C_CONFIG_MINOR_F_W_REV(new ValuePoint("S64112_C_C_CONFIG_MINOR_F_W_REV", "FM CC Minor Firmware Number", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + C_C_CONFIG_DATA_LOG_DAY_OFFSET(new ValuePoint("S64112_C_C_CONFIG_DATA_LOG_DAY_OFFSET", "Set Data Log Day Offset", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + C_C_CONFIG_DATA_LOG_CUR_DAY_OFF(new ValuePoint("S64112_C_C_CONFIG_DATA_LOG_CUR_DAY_OFF", "Current Data Log Day Offset", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + C_C_CONFIG_DATA_LOG_DAILY_A_H(new ValuePoint("S64112_C_C_CONFIG_DATA_LOG_DAILY_A_H", "Data Log Daily (Ah)", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE_HOURS)), // + C_C_CONFIG_DATA_LOG_DAILY_K_W_H(new ScaledValuePoint("S64112_C_C_CONFIG_DATA_LOG_DAILY_K_W_H", "Data Log Daily (kWh)", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.KILOWATT_HOURS, "KWH_SF")), // + C_C_CONFIG_DATA_LOG_MAX_OUT_A(new ScaledValuePoint("S64112_C_C_CONFIG_DATA_LOG_MAX_OUT_A", "Data Log Daily Maximum Output (A)", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "V_SF")), // + C_C_CONFIG_DATA_LOG_MAX_OUT_W(new ScaledValuePoint("S64112_C_C_CONFIG_DATA_LOG_MAX_OUT_W", "Data Log Daily Maximum Output (W)", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "V_SF")), // + C_C_CONFIG_DATA_LOG_ABSORB_T(new ValuePoint("S64112_C_C_CONFIG_DATA_LOG_ABSORB_T", "Data Log Daily Absorb Time", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + C_C_CONFIG_DATA_LOG_FLOAT_T(new ValuePoint("S64112_C_C_CONFIG_DATA_LOG_FLOAT_T", "Data Log Daily Float Time", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + C_C_CONFIG_DATA_LOG_MIN_BATT_V(new ScaledValuePoint("S64112_C_C_CONFIG_DATA_LOG_MIN_BATT_V", "Data Log Daily Minimum Battery", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + C_C_CONFIG_DATA_LOG_MAX_BATT_V(new ScaledValuePoint("S64112_C_C_CONFIG_DATA_LOG_MAX_BATT_V", "Data Log Daily Maximum Battery", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + C_C_CONFIG_DATA_LOG_MAX_INPUT_V(new ScaledValuePoint("S64112_C_C_CONFIG_DATA_LOG_MAX_INPUT_V", "Data Log Daily Maximum Input", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + C_C_CONFIG_DATA_LOG_CLEAR(new ValuePoint("S64112_C_C_CONFIG_DATA_LOG_CLEAR", "Data Log Clear", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + C_C_CONFIG_DATA_LOG_CLR_COMP(new ValuePoint("S64112_C_C_CONFIG_DATA_LOG_CLR_COMP", "Data Log Clear Complement", "", // + ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)); + + private final Point point; + + private S64112(Point point) { + this.point = point; + } + + @Override + public Point get() { + return this.point; } } @@ -18042,7 +6773,7 @@ public static enum S64112_CC_Config_MPPT_mode implements OptionsEnum { UNDEFINED(-1, "Undefined"), // AUTO(0, "AUTO"), // U_PICK(1, "U_PICK"), // - WIND(2, "WIND"); // + WIND(2, "WIND"); private final int value; private final String name; @@ -18071,7 +6802,7 @@ public OptionsEnum getUndefined() { public static enum S64112_CC_Config_sweep_width implements OptionsEnum { UNDEFINED(-1, "Undefined"), // HALF(0, "HALF"), // - FULL(1, "FULL"); // + FULL(1, "FULL"); private final int value; private final String name; @@ -18102,7 +6833,7 @@ public static enum S64112_CC_Config_sweep_max implements OptionsEnum { EIGHTY_PERCENT(0, "EIGHTY_PERCENT"), // EIGHTY_FIVE_PERCENT(1, "EIGHTY_FIVE_PERCENT"), // NINTY_PERCENT(2, "NINTY_PERCENT"), // - NINTY_NINE_PERCENT(3, "NINTY_NINE_PERCENT"); // + NINTY_NINE_PERCENT(3, "NINTY_NINE_PERCENT"); private final int value; private final String name; @@ -18131,7 +6862,7 @@ public OptionsEnum getUndefined() { public static enum S64112_CC_Config_grid_tie implements OptionsEnum { UNDEFINED(-1, "Undefined"), // DISABLED(0, "DISABLED"), // - ENABLED(1, "ENABLED"); // + ENABLED(1, "ENABLED"); private final int value; private final String name; @@ -18160,7 +6891,7 @@ public OptionsEnum getUndefined() { public static enum S64112_CC_Config_temp_comp implements OptionsEnum { UNDEFINED(-1, "Undefined"), // WIDE(0, "WIDE"), // - LIMITED(1, "LIMITED"); // + LIMITED(1, "LIMITED"); private final int value; private final String name; @@ -18190,7 +6921,7 @@ public static enum S64112_CC_Config_auto_restart implements OptionsEnum { UNDEFINED(-1, "Undefined"), // OFF(0, "OFF"), // EVERY_90_MINUTES(1, "EVERY_90_MINUTES"), // - EVERY_90_MINUTES_IF_ABSORB_OR_FLOAT(2, "EVERY_90_MINUTES_IF_ABSORB_OR_FLOAT"); // + EVERY_90_MINUTES_IF_ABSORB_OR_FLOAT(2, "EVERY_90_MINUTES_IF_ABSORB_OR_FLOAT"); private final int value; private final String name; @@ -18226,7 +6957,7 @@ public static enum S64112_CC_Config_AUX_mode implements OptionsEnum { VENT_FAN(5, "VENT_FAN"), // P_V_TRIGGER(6, "P_V_TRIGGER"), // ERROR_OUTPUT(7, "ERROR_OUTPUT"), // - NIGHT_LIGHT(8, "NIGHT_LIGHT"); // + NIGHT_LIGHT(8, "NIGHT_LIGHT"); private final int value; private final String name; @@ -18256,7 +6987,7 @@ public static enum S64112_CC_Config_AUX_control implements OptionsEnum { UNDEFINED(-1, "Undefined"), // OFF(0, "OFF"), // AUTO(1, "AUTO"), // - ON(2, "ON"); // + ON(2, "ON"); private final int value; private final String name; @@ -18285,7 +7016,7 @@ public OptionsEnum getUndefined() { public static enum S64112_CC_Config_AUX_state implements OptionsEnum { UNDEFINED(-1, "Undefined"), // DISABLED(0, "DISABLED"), // - ENABLED(1, "ENABLED"); // + ENABLED(1, "ENABLED"); private final int value; private final String name; @@ -18314,7 +7045,7 @@ public OptionsEnum getUndefined() { public static enum S64112_CC_Config_AUX_polarity implements OptionsEnum { UNDEFINED(-1, "Undefined"), // LOW(0, "LOW"), // - HIGH(1, "HIGH"); // + HIGH(1, "HIGH"); private final int value; private final String name; @@ -18342,16 +7073,14 @@ public OptionsEnum getUndefined() { public final String label; public final String description; - public final String notes; public final int length; public final SunSpecPoint[] points; public final SunSpecModelType modelType; - private DefaultSunSpecModel(String label, String description, String notes, int length, SunSpecPoint[] points, + private DefaultSunSpecModel(String label, String description, int length, SunSpecPoint[] points, SunSpecModelType modelType) { this.label = label; this.description = description; - this.notes = notes; this.length = length; this.points = points; this.modelType = modelType; diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/Point.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/Point.java new file mode 100644 index 00000000000..3ea9dc3bbdd --- /dev/null +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/Point.java @@ -0,0 +1,418 @@ +package io.openems.edge.bridge.modbus.sunspec; + +import static io.openems.common.channel.AccessMode.READ_ONLY; +import static io.openems.edge.bridge.modbus.api.element.AbstractModbusElement.FillElementsPriority.HIGH; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Consumer; + +import io.openems.common.channel.AccessMode; +import io.openems.common.channel.Level; +import io.openems.common.channel.Unit; +import io.openems.common.types.OpenemsType; +import io.openems.common.types.OptionsEnum; +import io.openems.edge.bridge.modbus.api.element.BitsWordElement; +import io.openems.edge.bridge.modbus.api.element.DummyRegisterElement; +import io.openems.edge.bridge.modbus.api.element.FloatDoublewordElement; +import io.openems.edge.bridge.modbus.api.element.FloatQuadruplewordElement; +import io.openems.edge.bridge.modbus.api.element.ModbusElement; +import io.openems.edge.bridge.modbus.api.element.SignedDoublewordElement; +import io.openems.edge.bridge.modbus.api.element.SignedQuadruplewordElement; +import io.openems.edge.bridge.modbus.api.element.SignedWordElement; +import io.openems.edge.bridge.modbus.api.element.StringWordElement; +import io.openems.edge.bridge.modbus.api.element.UnsignedDoublewordElement; +import io.openems.edge.bridge.modbus.api.element.UnsignedQuadruplewordElement; +import io.openems.edge.bridge.modbus.api.element.UnsignedWordElement; +import io.openems.edge.common.channel.ChannelId; +import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.channel.internal.AbstractDoc; +import io.openems.edge.common.channel.internal.OpenemsTypeDoc; + +/** + * The internal PointImpl object for easier handling in Enums. + */ +public abstract sealed class Point { + + /** + * A Point that relates to a {@link ModbusElement}. + */ + protected static sealed interface ModbusElementPoint { + + /** + * Generates the {@link ModbusElement}. + * + * @param startAddress the start-address + * @return the {@link ModbusElement} + */ + public ModbusElement generateModbusElement(int startAddress); + } + + public static sealed interface Type { + + public static final short UNDEFINED_8 = Short.MIN_VALUE /* -32768 */; + public static final int UNDEFINED_16 = 65535; + public static final long UNDEFINED_32 = 4294967295L; + + /** + * Returns true if the value represents a 'defined' value in SunSpec. + * + * @param value the value; never null + * @return true for defined values + */ + public boolean isDefined(Object value); + } + + public final String name; + public final String description; + public final Point.Type type; + public final boolean mandatory; + public final AccessMode accessMode; + + public Point(String name, String label, String description, Point.Type type, boolean mandatory, + AccessMode accessMode) { + this.name = name; + this.description = description; + this.type = type; + this.mandatory = mandatory; + this.accessMode = accessMode; + } + + /** + * Returns true if the value represents a 'defined' value in SunSpec. + * + * @param value the value + * @return true for defined values + */ + public boolean isDefined(Object value) { + if (this.type != null && value != null) { + return this.type.isDefined(value); + } + return false; + } + + /** + * Represents a Point with a ChannelId. + */ + public abstract static sealed class ChannelIdPoint extends Point + permits Point.ValuePoint, Point.EnumPoint, Point.ScaleFactorPoint, Point.BitPoint { + + public final ChannelId channelId; + + private ChannelIdPoint(String name, String label, String description, Point.Type type, boolean mandatory, + AccessMode accessMode, AbstractDoc doc) { + super(name, label, description, type, mandatory, accessMode); + if (!label.isBlank() && !description.isBlank()) { + doc.text(label + ". " + description); + } else if (!label.isBlank()) { + doc.text(label); + } else { + doc.text(description); + } + doc.accessMode(accessMode); + this.channelId = new SunSChannelId<>(name, doc); + } + + } + + /** + * Represents a Point with a discrete value. + */ + public static non-sealed class ValuePoint extends Point.ChannelIdPoint implements ModbusElementPoint { + + public static enum Type implements Point.Type { + INT16(1), UINT16(1), COUNT(1), ACC16(1), INT32(2), UINT32(2), FLOAT32(2), ACC32(2), INT64(4), UINT64(4), + FLOAT64(4), ACC64(4), STRING2(2), STRING4(4), STRING5(5), STRING6(6), STRING7(7), STRING8(8), STRING12(12), + STRING16(16), STRING20(20), STRING25(25), STRING32(32), + /* use PAD for reserved points */ + PAD(1), IPADDR(1), IPV6ADDR(16), EUI48(6); + + public final int length; + + private Type(int length) { + this.length = length; + } + + @Override + public boolean isDefined(Object value) { + return switch (this) { + case INT16 -> !value.equals(UNDEFINED_8); + case UINT16, COUNT -> !value.equals(UNDEFINED_16); + case ACC16, ACC32, IPADDR, ACC64, IPV6ADDR -> !value.equals(0); + case INT32 -> !value.equals(0x80000000); // TODO correct? + case UINT32 -> !value.equals(UNDEFINED_32); + case INT64 -> !value.equals(0x8000000000000000L); // TODO correct? + case UINT64 -> !value.equals(0xFFFFFFFFFFFFFFFFL); // TODO correct? + case FLOAT32 -> !value.equals(Float.NaN); + case FLOAT64 -> false; // TODO not implemented + case PAD // This point is never needed/reserved + -> false; + case STRING12, STRING16, STRING2, STRING20, STRING25, STRING32, STRING4, STRING5, STRING6, STRING7, + STRING8 -> + !"".equals(value); + case EUI48 -> false; // TODO not implemented + }; + } + } + + private final Type type; + + private ValuePoint(String name, String label, String description, ValuePoint.Type type, boolean mandatory, + AccessMode accessMode, Unit unit, OpenemsTypeDoc doc) { + super(name, label, description, type, mandatory, accessMode, doc.unit(unit)); + this.type = type; + } + + public ValuePoint(String name, String label, String description, ValuePoint.Type type, boolean mandatory, + AccessMode accessMode, Unit unit) { + this(name, label, description, type, mandatory, accessMode, unit, // + Doc.of(// + switch (type) { + case UINT16, ACC16, INT16, COUNT, INT32, PAD, // ignore + EUI48, FLOAT32 // avoid floating point numbers; FLOAT32 might not fit in INTEGER + -> OpenemsType.INTEGER; + case ACC32, IPADDR, UINT32, UINT64, ACC64, INT64, IPV6ADDR, // + FLOAT64 // avoid floating point numbers + -> OpenemsType.LONG; + case STRING2, STRING4, STRING5, STRING6, STRING7, STRING8, STRING12, STRING16, STRING20, + STRING25, STRING32 // + -> OpenemsType.STRING; + })); + } + + @Override + public ModbusElement generateModbusElement(int startAddress) { + return switch (this.type) { + case UINT16, ACC16 // + -> new UnsignedWordElement(startAddress); + case INT16, COUNT // + -> new SignedWordElement(startAddress); + case UINT32, ACC32, IPADDR // + -> new UnsignedDoublewordElement(startAddress); + case INT32 // + -> new SignedDoublewordElement(startAddress); + case UINT64, ACC64 // + -> new UnsignedQuadruplewordElement(startAddress); + case INT64 // + -> new SignedQuadruplewordElement(startAddress); + case FLOAT32 // + -> new FloatDoublewordElement(startAddress); + case PAD // + -> new DummyRegisterElement(startAddress); + case FLOAT64 // + -> new FloatQuadruplewordElement(startAddress); + case EUI48, IPV6ADDR // this would be UINT128 + -> null; + case STRING2 -> new StringWordElement(startAddress, 2); + case STRING4 -> new StringWordElement(startAddress, 4); + case STRING5 -> new StringWordElement(startAddress, 5); + case STRING6 -> new StringWordElement(startAddress, 6); + case STRING7 -> new StringWordElement(startAddress, 7); + case STRING8 -> new StringWordElement(startAddress, 8); + case STRING12 -> new StringWordElement(startAddress, 12); + case STRING16 -> new StringWordElement(startAddress, 16); + case STRING20 -> new StringWordElement(startAddress, 20); + case STRING25 -> new StringWordElement(startAddress, 25); + case STRING32 -> new StringWordElement(startAddress, 32); + }; + } + } + + /** + * Represents a Point with a defined Scale-Factor. + */ + public static final class ScaledValuePoint extends Point.ValuePoint { + public final String scaleFactor; + + public ScaledValuePoint(String name, String label, String description, ValuePoint.Type type, boolean mandatory, + AccessMode accessMode, Unit unit, String scaleFactor) { + super(name, label, description, type, mandatory, accessMode, unit, Doc.of(OpenemsType.FLOAT)); + this.scaleFactor = scaleFactor; + } + } + + /** + * Represents a Scale-Factor Point. + */ + public static final class ScaleFactorPoint extends Point.ChannelIdPoint implements ModbusElementPoint { + + public static enum Type implements Point.Type { + SUNSSF(1); + + public final int length; + + private Type(int length) { + this.length = length; + } + + @Override + public boolean isDefined(Object value) { + return switch (this) { + case SUNSSF -> !value.equals(UNDEFINED_8); + }; + } + } + + public ScaleFactorPoint(String name, String label, String description) { + super(name, label, description, Type.SUNSSF, true, READ_ONLY, Doc.of(OpenemsType.INTEGER)); + } + + @Override + public ModbusElement generateModbusElement(int startAddress) { + return new SignedWordElement(startAddress) // + .fillElementsPriority(HIGH); + } + } + + /** + * Represents a Point with an Enum value. + */ + public static final class EnumPoint extends Point.ChannelIdPoint implements ModbusElementPoint { + + public static enum Type implements Point.Type { + ENUM16(1), ENUM32(2); + + public final int length; + + private Type(int length) { + this.length = length; + } + + @Override + public boolean isDefined(Object value) { + return switch (this) { + case ENUM16 -> !value.equals(UNDEFINED_16); + case ENUM32 -> !value.equals(UNDEFINED_32); + }; + } + } + + private final Type type; + + public EnumPoint(String name, String label, String description, EnumPoint.Type type, boolean mandatory, + AccessMode accessMode, OptionsEnum[] options) { + super(name, label, description, type, mandatory, accessMode, Doc.of(options)); + this.type = type; + } + + @Override + public ModbusElement generateModbusElement(int startAddress) { + return switch (this.type) { + case ENUM16 // + -> new UnsignedWordElement(startAddress); + case ENUM32 // + -> new UnsignedDoublewordElement(startAddress); + }; + } + + } + + /** + * Represents a Point with BitField values. + */ + public static final class BitFieldPoint extends Point { + + public interface SunSpecBitPoint extends SunSpecPoint { + @Override + public BitPoint get(); + } + + public static enum Type implements Point.Type { + BITFIELD16(1), BITFIELD32(2); + + public final int length; + + private Type(int length) { + this.length = length; + } + + @Override + public boolean isDefined(Object value) { + return switch (this) { + case BITFIELD16 -> !value.equals(UNDEFINED_16); + case BITFIELD32 -> !value.equals(UNDEFINED_32); + }; + } + } + + public final SunSpecBitPoint[] points; + public final BitFieldPoint.Type type; + + public BitFieldPoint(String name, String label, String description, BitFieldPoint.Type type, boolean mandatory, + AccessMode accessMode, SunSpecBitPoint[] points) { + super(name, label, description, type, mandatory, accessMode); // + this.points = points; + this.type = type; + } + + /** + * Generates the {@link ModbusElement}s. + * + * @param parent the parent + * {@link AbstractOpenemsSunSpecComponent} + * @param addChannel callback to add a Channel to parent (because the + * method is protected) + * @param startAddress the start-address + * @param alternativeBitPoints alternative {@link SunSpecBitPoint}s + * @return the {@link ModbusElement}s + */ + public List generateModbusElements(AbstractOpenemsSunSpecComponent parent, + Consumer addChannel, int startAddress, SunSpecBitPoint[] alternativeBitPoints) { + final SunSpecBitPoint[] points; + if (alternativeBitPoints != null && alternativeBitPoints.length > 0) { + points = alternativeBitPoints; + } else { + points = this.points; + } + + return switch (this.type) { + case BITFIELD16 -> { + var bwe = new BitsWordElement(startAddress, parent); + Arrays.stream(points).forEach(ssbp -> { + var bit = ssbp.get().bit; + var channelId = ssbp.get().channelId; + addChannel.accept(channelId); + bwe.bit(bit, channelId); + }); + yield List.of(bwe); + } + case BITFIELD32 -> { + var bwe0 = new BitsWordElement(startAddress, parent); + var bwe1 = new BitsWordElement(startAddress + 1, parent); + Arrays.stream(points).forEach(ssbp -> { + var bit = ssbp.get().bit; + var channelId = ssbp.get().channelId; + addChannel.accept(channelId); + if (bit > 15) { + bwe1.bit(bit - 16, channelId); + } else { + bwe0.bit(bit, channelId); + } + }); + yield List.of(bwe0, bwe1); + } + }; + } + } + + /** + * Represents one Bit within a BitFieldPoint. + */ + public static final class BitPoint extends Point.ChannelIdPoint { + + public final int bit; + + private BitPoint(int bit, String name, String label, AbstractDoc doc) { + super(name, label, "", null /* point type */, false, AccessMode.READ_ONLY, doc); + this.bit = bit; + } + + public BitPoint(int bit, String name, String label) { + this(bit, name, label, Doc.of(OpenemsType.BOOLEAN)); + } + + public BitPoint(int bit, String name, String label, Level level) { + this(bit, name, label, Doc.of(level)); + } + } +} \ No newline at end of file diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/SunSpecCodeGenerator.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/SunSpecCodeGenerator.java deleted file mode 100644 index a9827f5ce18..00000000000 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/SunSpecCodeGenerator.java +++ /dev/null @@ -1,787 +0,0 @@ -package io.openems.edge.bridge.modbus.sunspec; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.function.Function; - -import com.google.common.base.CaseFormat; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; - -import io.openems.common.channel.AccessMode; -import io.openems.common.channel.Unit; -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.exceptions.OpenemsException; -import io.openems.common.function.ThrowingFunction; -import io.openems.common.utils.JsonUtils; -import io.openems.edge.bridge.modbus.sunspec.SunSpecPoint.PointCategory; -import io.openems.edge.bridge.modbus.sunspec.SunSpecPoint.PointType; - -/** - * This tool converts SunSpec Json definitions to Java code suitable for the - * OpenEMS SunSpec implementation. - * - *

    - * Download Json files from https://github.com/sunspec/models. - */ -public class SunSpecCodeGenerator { - - /** - * Path to the SunSpec model Json files; download them from - * https://github.com/sunspec/models. - */ - private static final String SUNSPEC_JSON_PATH = System.getProperty("user.home") + "\\git\\sunspec\\json\\"; - /** - * Path to the generated output file. - */ - private static final String OUT_FILE_PATH = System.getProperty("user.dir") - + "\\src\\io\\openems\\edge\\bridge\\modbus\\sunspec\\DefaultSunSpecModel.java"; - - /** - * Json files that should be ignored; mainly because certain features are not - * implemented yet. - */ - private static final Set IGNORE_FILES = new HashSet<>(Arrays.asList(// - "model_3.json", // - "model_4.json", // - "model_5.json", // - "model_6.json", // - "model_7.json", // - "model_8.json", // - "model_9.json", // - "model_10.json", // - "model_11.json", // - "model_12.json", // - "model_13.json", // - "model_14.json", // - "model_16.json", // - "model_17.json", // - "model_19.json", // - "model_126.json", // - "model_129.json", // - "model_130.json", // - "model_131.json", // - "model_132.json", // - "model_133.json", // - "model_134.json", // - "model_135.json", // - "model_136.json", // - "model_137.json", // - "model_138.json", // - "model_139.json", // - "model_140.json", // - "model_141.json", // - "model_142.json", // - "model_143.json", // - "model_144.json", // - "model_160.json", // - "model_211.json", // - "model_212.json", // - "model_213.json", // - "model_214.json", // - "model_220.json", // - "model_302.json", // - "model_303.json", // - "model_304.json", // - "model_401.json", // - "model_402.json", // - "model_403.json", // - "model_404.json", // - "model_501.json", // - "model_502.json", // - "model_601.json", // - "model_803.json", // - "model_804.json", // - "model_805.json", // - "model_806.json", // - "model_807.json", // - "model_808.json", // - "model_809.json", // - "model_63001.json", // - "model_63002.json", // - "model_64020.json" // - )); - - /** - * Run this method to start the code generator. - * - * @param args not supported - * @throws Exception on error - */ - public static void main(String[] args) throws Exception { - System.out.println(SUNSPEC_JSON_PATH); - var generator = new SunSpecCodeGenerator(); - var models = generator.parseSunSpecFiles(); - generator.writeSunSpecModelJavaFile(models); - } - - /** - * Parses all SunSpec Json files in a directory. - * - * @return a list of Models - * @throws Exception on error - */ - private List parseSunSpecFiles() throws Exception { - List result = new ArrayList<>(); - for (File file : new File(SUNSPEC_JSON_PATH).listFiles(file -> // - file.getName().startsWith("model") // - && file.getName().endsWith(".json") // - && !IGNORE_FILES.contains(file.getName()))) { - try { - var model = this.parseSunSpecFile(Files.readString(file.toPath())); - result.add(model); - - } catch (Exception e) { - throw new Exception("Error while reading from " + file, e); - } - } - // Sort by model ids to have an ordered output - result.sort(new Comparator() { - @Override - public int compare(Model m1, Model m2) { - return m1.id - m2.id; - } - }); - - return result; - } - - /** - * Parses a SunSpec Json file. - * - * @param file the SunSpec Json file handler - * @return the Model - * @throws Exception on error - */ - private Model parseSunSpecFile(String file) throws Exception { - var json = JsonUtils.parseToJsonObject(file); - - var generator = new SunSpecCodeGenerator(); - return generator.parseSunSpecModels(json); - } - - /** - * Parses the element sunSpecModels. - * - *

    -	 *   <sunSpecModels v="1">
    -	 * 
    - * - *
      - *
    • xs:attribute name="v" type="xs:string" default="1" - *
    - * - * @param sunSpecModels the 'sunSpecModels' json - * @return the Model - * @throws OpenemsNamedException on error - * @throws JSONException on json error - */ - private Model parseSunSpecModels(JsonObject sunSpecModels) throws OpenemsNamedException { - return new Model(sunSpecModels); - } - - /** - * Writes the SunSpecModel.java file. - * - * @param models a list of Models - * @throws IOException on error - */ - private void writeSunSpecModelJavaFile(List models) throws IOException { - try (var w = Files.newBufferedWriter(Paths.get(OUT_FILE_PATH))) { - w.write("// CHECKSTYLE:OFF"); - w.newLine(); - w.newLine(); - w.write("package io.openems.edge.bridge.modbus.sunspec;"); - w.newLine(); - w.newLine(); - w.write("import io.openems.common.channel.AccessMode;"); - w.newLine(); - w.write("import io.openems.common.channel.Unit;"); - w.newLine(); - w.write("import io.openems.common.types.OptionsEnum;"); - w.newLine(); - w.newLine(); - w.write("/**"); - w.newLine(); - w.write(" * Do not touch this file. It is auto-generated by SunSpecCodeGenerator."); - w.newLine(); - w.write(" */"); - w.newLine(); - w.write("public enum DefaultSunSpecModel implements SunSpecModel {"); - w.newLine(); - - /* - * Write main Model enum - */ - for (var i = 0; i < models.size(); i++) { - var model = models.get(i); - w.write(" S_" + model.id + "(//"); - w.newLine(); - w.write(" \"" + esc(model.label) + "\", //"); - w.newLine(); - w.write(" \"" + esc(model.description) + "\", //"); - w.newLine(); - w.write(" \"" + esc(model.notes) + "\", //"); - w.newLine(); - w.write(" " + model.len + ", //"); - w.newLine(); - w.write(" DefaultSunSpecModel.S" + model.id + ".values(), //"); - w.newLine(); - w.write(" SunSpecModelType." + model.modelType + " //"); - w.newLine(); - w.write(" )"); - if (i == models.size() - 1) { - w.write("; //"); - } else { - w.write(", //"); - } - w.newLine(); - } - w.newLine(); - - /* - * For each Model write enum with SunSpecPoints - */ - for (Model model : models) { - w.write(" public static enum S" + model.id + " implements SunSpecPoint {"); - w.newLine(); - for (var i = 0; i < model.points.size(); i++) { - var point = model.points.get(i); - var pointUpperId = toUpperUnderscore(point.id); - w.write(" " + pointUpperId + "(new PointImpl(//"); - w.newLine(); - w.write(" \"S" + model.id + "_" + pointUpperId + "\", //"); - w.newLine(); - w.write(" \"" + esc(point.label) + "\", //"); - w.newLine(); - w.write(" \"" + esc(point.description) + "\", //"); - w.newLine(); - w.write(" \"" + esc(point.notes) + "\", //"); - w.newLine(); - w.write(" PointType." + point.type.name() + ", //"); - w.newLine(); - w.write(" " + point.mandatory + ", //"); - w.newLine(); - w.write(" AccessMode." + point.accessMode.name() + ", //"); - w.newLine(); - w.write(" Unit." + point.unit.name() + ", //"); - w.newLine(); - w.write(" " - + (point.scaleFactor.isPresent() ? "\"" + point.scaleFactor.get() + "\"" : null) + ", //"); - w.newLine(); - if (point.symbols.length == 0) { - w.write(" new OptionsEnum[0]))"); - } else { - w.write(" S" + model.id + "_" + point.id + ".values()))"); - } - - if (i == model.points.size() - 1) { - w.write("; //"); - } else { - w.write(", //"); - } - w.newLine(); - } - w.newLine(); - w.write(" protected final PointImpl impl;"); - w.newLine(); - w.newLine(); - w.write(" private S" + model.id + "(PointImpl impl) {"); - w.newLine(); - w.write(" this.impl = impl;"); - w.newLine(); - w.write(" }"); - w.newLine(); - w.newLine(); - w.write(" @Override"); - w.newLine(); - w.write(" public PointImpl get() {"); - w.newLine(); - w.write(" return this.impl;"); - w.newLine(); - w.write(" }"); - w.newLine(); - w.write(" }"); - w.newLine(); - w.newLine(); - - /* - * For SunSpecPoints with Symbols write OpenEMS OptionsEnum - */ - for (Point point : model.points) { - if (point.symbols.length == 0) { - continue; - } - - w.write(" public static enum S" + model.id + "_" + point.id + " implements OptionsEnum {"); - w.newLine(); - w.write(" UNDEFINED(-1, \"Undefined\"), //"); - w.newLine(); - for (var i = 0; i < point.symbols.length; i++) { - var symbol = point.symbols[i]; - var symbolId = symbol.id; - symbolId = toUpperUnderscore(symbolId); - - switch (symbolId) { - case "RESERVED": - symbolId = symbolId + "_" + symbol.value; // avoid duplicated "RESERVED" ids. - break; - } - - w.write(" " + symbolId + "(" + symbol.value + ", \"" + symbolId + "\")"); - if (i == point.symbols.length - 1) { - w.write("; //"); - } else { - w.write(", //"); - } - w.newLine(); - } - w.newLine(); - w.write(" private final int value;"); - w.newLine(); - w.write(" private final String name;"); - w.newLine(); - w.newLine(); - w.write(" private S" + model.id + "_" + point.id + "(int value, String name) {"); - w.newLine(); - w.write(" this.value = value;"); - w.newLine(); - w.write(" this.name = name;"); - w.newLine(); - w.write(" }"); - w.newLine(); - w.newLine(); - w.write(" @Override"); - w.newLine(); - w.write(" public int getValue() {"); - w.newLine(); - w.write(" return this.value;"); - w.newLine(); - w.write(" }"); - w.newLine(); - w.newLine(); - w.write(" @Override"); - w.newLine(); - w.write(" public String getName() {"); - w.newLine(); - w.write(" return this.name;"); - w.newLine(); - w.write(" }"); - w.newLine(); - w.newLine(); - w.write(" @Override"); - w.newLine(); - w.write(" public OptionsEnum getUndefined() {"); - w.newLine(); - w.write(" return UNDEFINED;"); - w.newLine(); - w.write(" }"); - w.newLine(); - w.write(" }"); - w.newLine(); - w.newLine(); - } - } - - w.write(" public final String label;"); - w.newLine(); - w.write(" public final String description;"); - w.newLine(); - w.write(" public final String notes;"); - w.newLine(); - w.write(" public final int length;"); - w.newLine(); - w.write(" public final SunSpecPoint[] points;"); - w.newLine(); - w.write(" public final SunSpecModelType modelType;"); - w.newLine(); - w.newLine(); - w.write(" private DefaultSunSpecModel(String label, String description, String notes, int length, SunSpecPoint[] points,"); - w.newLine(); - w.write(" SunSpecModelType modelType) {"); - w.newLine(); - w.write(" this.label = label;"); - w.newLine(); - w.write(" this.description = description;"); - w.newLine(); - w.write(" this.notes = notes;"); - w.newLine(); - w.write(" this.length = length;"); - w.newLine(); - w.write(" this.points = points;"); - w.newLine(); - w.write(" this.modelType = modelType;"); - w.newLine(); - w.write(" }"); - w.newLine(); - w.newLine(); - w.write(" @Override"); - w.newLine(); - w.write(" public SunSpecPoint[] points() {"); - w.newLine(); - w.write(" return this.points;"); - w.newLine(); - w.write(" }"); - w.newLine(); - w.newLine(); - w.write(" @Override"); - w.newLine(); - w.write(" public String label() {"); - w.newLine(); - w.write(" return this.label;"); - w.newLine(); - w.write(" }"); - w.newLine(); - w.write("}"); - w.newLine(); - w.write("// CHECKSTYLE:ON"); - w.newLine(); - } - } - - /** - * Helper method to escape a string. - * - * @param string original string - * @return escaped string - */ - private static final String esc(String string) { - if (string == null) { - return ""; - } - return string // - .replaceAll("[^\\x00-\\x7F]", "") // non-ascii chars - .replace("\"", "\\\"") // escape backslash - .trim(); - } - - /** - * POJO container for a SunSpec Model. - */ - public static class Model { - protected final int id; - protected final int len; - protected final String name; - protected final List points; - protected final SunSpecModelType modelType; - - protected String label = ""; - protected String description = ""; - protected String notes = ""; - - public Model(JsonObject model) throws OpenemsNamedException { - this.id = JsonUtils.getAsInt(model, "id"); - var group = model.get("group").getAsJsonObject(); - this.name = JsonUtils.getAsString(group, "name"); - this.label = JsonUtils.getAsStringOrElse(group, "label", ""); - this.description = JsonUtils.getAsStringOrElse(group, "desc", ""); - var points = JsonUtils.getAsJsonArray(group, "points"); - - var list = new ArrayList(); - var offset = 0; - for (var i = 0; i < points.size(); i++) { - var p = new Point(points.get(i).getAsJsonObject(), offset); - // ID and length not to be considered as points - if (!p.id.equals("ID") && !p.id.equals("L")) { - list.add(p); - } - offset += p.len; - } - this.points = list; - this.len = this.points.stream().map(p -> p.len).reduce(0, (t, p) -> t + p); - this.modelType = SunSpecModelType.getModelType(this.id); - } - - /** - * Gets the Point with the given Id. - * - * @param id the Point-ID - * @return the Point - * @throws OpenemsException on error - */ - public Point getPoint(String id) throws OpenemsException { - for (Point point : this.points) { - if (point.id.equals(id)) { - return point; - } - } - throw new OpenemsException("Unable to find Point with ID " + id); - } - - @Override - public String toString() { - return "Model [id=" + this.id + ", name=" + this.name + ", points=" + this.points + ", label=" + this.label - + ", description=" + this.description + ", notes=" + this.notes + "]"; - } - - } - - /** - * POJO container for a SunSpec Point. - */ - public static class Point { - - protected final String id; - protected final int len; - protected final int offset; - protected final PointType type; - protected final Optional scaleFactor; - protected final Unit unit; - protected final AccessMode accessMode; - protected final boolean mandatory; - protected final PointCategory category; - protected final Symbol[] symbols; - - protected String label; - protected String description; - protected String notes; - - public Point(JsonObject point, int offset) throws OpenemsNamedException { - this.id = JsonUtils.getAsString(point, "name"); - this.len = JsonUtils.getAsInt(point, "size"); - this.label = JsonUtils.getAsStringOrElse(point, "label", ""); - this.description = JsonUtils.getAsStringOrElse(point, "desc", ""); - this.offset = offset; - var t = JsonUtils.getAsString(point, "type"); - if (t.equals("string")) { - this.type = PointType.valueOf("STRING" + this.len); - } else { - this.type = PointType.valueOf(t.toUpperCase()); - } - var sf = JsonUtils.getAsOptionalPrimitive(point, "sf"); - if (sf.isPresent()) { - this.scaleFactor = Optional.of(sf.get().getAsString()); - } else { - this.scaleFactor = Optional.empty(); - } - this.unit = toUnit(JsonUtils.getAsStringOrElse(point, "units", "")); - var access = JsonUtils.getAsStringOrElse(point, "access", "r"); - switch (access.toLowerCase()) { - case "wo": - this.accessMode = AccessMode.WRITE_ONLY; - break; - case "rw": - this.accessMode = AccessMode.READ_WRITE; - break; - case "r": - case "ro": - default: - this.accessMode = AccessMode.READ_ONLY; - break; - } - this.mandatory = JsonUtils.getAsOptionalString(point, "mandatory").isPresent(); - this.category = PointCategory.MEASUREMENT; - - var symbolsJsonOpt = JsonUtils.getAsOptionalJsonArray(point, "symbols"); - Symbol[] symbols; - if (symbolsJsonOpt.isPresent()) { - var symbolsJson = symbolsJsonOpt.get(); - symbols = new Symbol[symbolsJson.size()]; - for (var i = 0; i < symbolsJson.size(); i++) { - var symbol = symbolsJson.get(i); - symbols[i] = new Symbol(symbol); - } - } else { - symbols = new Symbol[0]; - } - this.symbols = symbols; - - } - - static Unit toUnit(String unit) throws OpenemsNamedException { - final ThrowingFunction toUnit = s -> { - s = s.trim(); - if (s.contains(" ")) { - s = s.substring(0, s.indexOf(" ")); - } - switch (s) { - case "": - case "%ARtg/%dV": - case "bps": // not available in OpenEMS - case "cos()": // not available in OpenEMS - case "deg": // not available in OpenEMS - case "Degrees": // not available in OpenEMS - case "hhmmss": // not available in OpenEMS - case "hhmmss.sssZ": // not available in OpenEMS - case "HPa": // not available in OpenEMS - case "kO": // not available in OpenEMS - case "Mbps": // not available in OpenEMS - case "meters": // not available in OpenEMS - case "mm": // not available in OpenEMS - case "mps": // not available in OpenEMS - case "m/s": // not available in OpenEMS - case "ohms": // not available in OpenEMS - case "Pct": // not available in OpenEMS - case "PF": // not available in OpenEMS - case "SF": // not available in OpenEMS - case "text": // not available in OpenEMS - case "Tmd": // not available in OpenEMS - case "Tmh": // not available in OpenEMS - case "Tms": // not available in OpenEMS - case "Various": // not available in OpenEMS - case "Vm": // not available in OpenEMS - case "W/m2": // not available in OpenEMS - case "YYYYMMDD": // not available in OpenEMS - case "S": // not available in OpenEMS - case "%Max/Sec": // not available in OpenEMS - return Unit.NONE; - case "%": - case "%WHRtg": - return Unit.PERCENT; - case "A": - return Unit.AMPERE; - case "Ah": - case "AH": - return Unit.AMPERE_HOURS; - case "C": - return Unit.DEGREE_CELSIUS; - case "Hz": - return Unit.HERTZ; - case "kAH": - return Unit.KILOAMPERE_HOURS; - case "kWh": - return Unit.KILOWATT_HOURS; - case "mSecs": - return Unit.MILLISECONDS; - case "Secs": - return Unit.SECONDS; - case "V": - return Unit.VOLT; - case "VA": - return Unit.VOLT_AMPERE; - case "VAh": - return Unit.VOLT_AMPERE_HOURS; - case "var": - case "Var": - return Unit.VOLT_AMPERE_REACTIVE; - case "varh": - case "Varh": - return Unit.VOLT_AMPERE_REACTIVE_HOURS; - case "W": - return Unit.WATT; - case "Wh": - case "WH": - // Validate manually: OpenEMS distinguishes CUMULATED and DISCRETE Watt-Hours. - return Unit.CUMULATED_WATT_HOURS; - } - throw new OpenemsException("Unhandled unit [" + s + "]"); - }; - return toUnit.apply(unit); - } - - /** - * Gets the Symbol with the given Id. - * - * @param id the Symbol-Id - * @return the Symbol - * @throws OpenemsException on error - */ - public Symbol getSymbol(String id) throws OpenemsException { - for (Symbol symbol : this.symbols) { - if (symbol.id.equals(id)) { - return symbol; - } - } - throw new OpenemsException("Unable to find Symbol with ID " + id); - } - - @Override - public String toString() { - return "Point [id=" + this.id + ", len=" + this.len + ", offset=" + this.offset + ", type=" + this.type - + ", scaleFactor=" + this.scaleFactor.orElse("") + ", unit=" + this.unit + ", access=" - + this.accessMode + ", mandatory=" + this.mandatory + ", category=" + this.category + ", symbols=" - + Arrays.toString(this.symbols) + ", label=" + this.label + ", description=" + this.description - + ", notes=" + this.notes + "]"; - } - - /** - * POJO container for a SunSpec Point Symbol. - */ - public static class Symbol { - protected final String id; - protected final int value; - - protected String label; - protected String description; - protected String notes; - - private static Function idCleaner = id -> { - switch (id) { - case "ggOFF": - case "ggSLEEPING": - case "ggSTARTING": - case "ggTHROTTLED": - case "ggSHUTTING_DOWN": - case "ggFAULT": - case "ggSTANDBY": - // Special handling for ID 111 point "Operating State" - // TODO: create pull-request to fix Json file upstream - return id.substring(2); - case "M_EVENT_Power_Failure": - case "M_EVENT_Under_Voltage": - case "M_EVENT_Low_PF": - case "M_EVENT_Over_Current": - case "M_EVENT_Over_Voltage": - case "M_EVENT_Missing_Sensor": - case "M_EVENT_Reserved1": - case "M_EVENT_Reserved2": - case "M_EVENT_Reserved3": - case "M_EVENT_Reserved4": - case "M_EVENT_Reserved5": - case "M_EVENT_Reserved6": - case "M_EVENT_Reserved7": - case "M_EVENT_Reserved8": - case "M_EVENT_OEM01": - case "M_EVENT_OEM02": - case "M_EVENT_OEM03": - case "M_EVENT_OEM04": - case "M_EVENT_OEM05": - case "M_EVENT_OEM06": - case "M_EVENT_OEM07": - case "M_EVENT_OEM08": - case "M_EVENT_OEM09": - case "M_EVENT_OEM10": - case "M_EVENT_OEM11": - case "M_EVENT_OEM12": - case "M_EVENT_OEM13": - case "M_EVENT_OEM14": - case "M_EVENT_OEM15": - // Special handling for ID 202 point "Events" - return id.substring(8); - default: - return id; - } - }; - - protected Symbol(String id, int value) { - this.id = idCleaner.apply(id); - this.value = value; - } - - public Symbol(JsonElement symbol) throws OpenemsNamedException { - this(JsonUtils.getAsString(symbol, "name"), JsonUtils.getAsInt(symbol, "value")); - this.label = JsonUtils.getAsStringOrElse(symbol, "label", ""); - } - } - } - - protected static String toUpperUnderscore(String string) { - string = string // - .replace("-", "_") // - .replace(" ", "_"); - if (!string.toUpperCase().equals(string)) { - string = CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, string); - } - return string.replace("__", "_"); - } - -} diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/SunSpecModelType.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/SunSpecModelType.java index 903de11fe4d..283172c97b9 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/SunSpecModelType.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/SunSpecModelType.java @@ -1,5 +1,7 @@ package io.openems.edge.bridge.modbus.sunspec; +import java.util.Arrays; + /** * This is taken from the first sheet inside the SunSpec excel file. */ @@ -18,20 +20,24 @@ public enum SunSpecModelType { RESERVED_2(900, 63000), // VENDOR_SPECIFIC(64000, 65535); - protected final int startId; - protected final int endId; + private final int startId; + private final int endId; private SunSpecModelType(int startId, int endId) { this.startId = startId; this.endId = endId; } - protected static SunSpecModelType getModelType(int id) { - for (SunSpecModelType type : SunSpecModelType.values()) { - if (type.startId <= id && type.endId >= id) { - return type; - } - } - throw new IllegalArgumentException("There is no SunSpec Model-Type for ID " + id); + /** + * Get a {@link SunSpecModelType} by its id. + * + * @param id the id + * @return The {@link SunSpecModelType} + */ + public static SunSpecModelType getModelType(int id) { + return Arrays.stream(SunSpecModelType.values()) // + .filter(t -> t.startId <= id && t.endId >= id) // + .findFirst() // + .orElseThrow(() -> new IllegalArgumentException("There is no SunSpec Model-Type for ID " + id)); } } \ No newline at end of file diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/SunSpecPoint.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/SunSpecPoint.java index 0cc555f62d8..601a580817b 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/SunSpecPoint.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/SunSpecPoint.java @@ -1,27 +1,7 @@ package io.openems.edge.bridge.modbus.sunspec; -import static io.openems.edge.bridge.modbus.api.element.AbstractModbusElement.FillElementsPriority.HIGH; - -import java.util.Optional; - -import io.openems.common.channel.AccessMode; -import io.openems.common.channel.Unit; -import io.openems.common.types.OpenemsType; -import io.openems.common.types.OptionsEnum; -import io.openems.edge.bridge.modbus.api.element.DummyRegisterElement; -import io.openems.edge.bridge.modbus.api.element.FloatDoublewordElement; -import io.openems.edge.bridge.modbus.api.element.FloatQuadruplewordElement; -import io.openems.edge.bridge.modbus.api.element.ModbusElement; -import io.openems.edge.bridge.modbus.api.element.SignedDoublewordElement; -import io.openems.edge.bridge.modbus.api.element.SignedQuadruplewordElement; -import io.openems.edge.bridge.modbus.api.element.SignedWordElement; -import io.openems.edge.bridge.modbus.api.element.StringWordElement; -import io.openems.edge.bridge.modbus.api.element.UnsignedDoublewordElement; -import io.openems.edge.bridge.modbus.api.element.UnsignedQuadruplewordElement; -import io.openems.edge.bridge.modbus.api.element.UnsignedWordElement; +import io.openems.edge.bridge.modbus.sunspec.Point.ChannelIdPoint; import io.openems.edge.common.channel.ChannelId; -import io.openems.edge.common.channel.Doc; -import io.openems.edge.common.channel.EnumDoc; /** * Holds one "Point" or "Register" within a SunSpec "Model" or "Block". @@ -39,184 +19,22 @@ public interface SunSpecPoint { public String name(); /** - * The internal PointImpl object for easier handling in Enums. + * The internal {@link Point} object for easier handling in Enums. * * @return the internal PointImpl */ - public PointImpl get(); - - /** - * Returns true if the value represents a 'defined' value in SunSpec. - * - * @param value the value - * @return true for defined values - */ - public default boolean isDefined(Object value) { - return PointType.isDefined(this.get().type, value); - } + public Point get(); /** * Gets the {@link ChannelId} for this Point. * * @return the ChannelId. */ - public default SunSChannelId getChannelId() { - return this.get().channelId; - } - - /** - * The internal PointImpl object for easier handling in Enums. - */ - public static class PointImpl { - public final String label; - public final String description; - public final String notes; - public final PointType type; - public final boolean mandatory; - public final AccessMode accessMode; - public final Unit unit; - public final SunSChannelId channelId; - public final Optional scaleFactor; - public final OptionsEnum[] options; - - public PointImpl(String channelId, String label, String description, String notes, PointType type, - boolean mandatory, AccessMode accessMode, Unit unit, String scaleFactor, OptionsEnum[] options) { - this.label = label; - this.description = description; - this.notes = notes; - this.type = type; - this.mandatory = mandatory; - this.accessMode = accessMode; - this.unit = unit; - this.scaleFactor = Optional.ofNullable(scaleFactor); - if (options.length == 0) { - this.channelId = new SunSChannelId<>(channelId, // - Doc.of(this.getMatchingOpenemsType(this.scaleFactor.isPresent())) // - .unit(unit) // - .accessMode(accessMode)); - } else { - this.channelId = new SunSChannelId<>(channelId, // - new EnumDoc(options) // - .accessMode(accessMode)); - } - this.options = options; - } - - /** - * Generates a Modbus Element for the given point + startAddress. - * - * @param startAddress the startAddress of the Point - * @return a new Modbus Element - */ - public final ModbusElement generateModbusElement(Integer startAddress) { - return switch (this.type) { - case UINT16, ACC16, ENUM16, BITFIELD16 -> new UnsignedWordElement(startAddress); - case SUNSSF -> new SignedWordElement(startAddress)// - .fillElementsPriority(HIGH); - case INT16, COUNT -> new SignedWordElement(startAddress); - case UINT32, ACC32, ENUM32, BITFIELD32, IPADDR -> new UnsignedDoublewordElement(startAddress); - case INT32 -> new SignedDoublewordElement(startAddress); - case UINT64, ACC64 -> new UnsignedQuadruplewordElement(startAddress); - case INT64 -> new SignedQuadruplewordElement(startAddress); - case FLOAT32 -> new FloatDoublewordElement(startAddress); - case PAD -> new DummyRegisterElement(startAddress); - case FLOAT64 -> new FloatQuadruplewordElement(startAddress); - case EUI48 -> null; - case IPV6ADDR // TODO this would be UINT128 - -> null; - case STRING2 -> new StringWordElement(startAddress, 2); - case STRING4 -> new StringWordElement(startAddress, 4); - case STRING5 -> new StringWordElement(startAddress, 5); - case STRING6 -> new StringWordElement(startAddress, 6); - case STRING7 -> new StringWordElement(startAddress, 7); - case STRING8 -> new StringWordElement(startAddress, 8); - case STRING12 -> new StringWordElement(startAddress, 12); - case STRING16 -> new StringWordElement(startAddress, 16); - case STRING20 -> new StringWordElement(startAddress, 20); - case STRING25 -> new StringWordElement(startAddress, 25); - case STRING32 -> new StringWordElement(startAddress, 32); - default -> throw new IllegalArgumentException( - "Point [" + this.label + "]: Type [" + this.type + "] is not supported!"); - }; + public default ChannelId getChannelId() { + var p = this.get(); + if (p instanceof ChannelIdPoint cp) { + return cp.channelId; } - - /** - * Gets the {@link OpenemsType} that matches this SunSpec-Type. - * - * @param hasScaleFactor true if this Point has a ScaleFactor. If true, a - * floating point type is applied to avoid rounding - * errors. - * @return the {@link OpenemsType} - */ - public final OpenemsType getMatchingOpenemsType(boolean hasScaleFactor) { - if (hasScaleFactor) { - return OpenemsType.FLOAT; - } - - // TODO: map to floating point OpenemsType when appropriate - return switch (this.type) { - case UINT16, ACC16, ENUM16, BITFIELD16, INT16, SUNSSF, COUNT, INT32, PAD, // ignore - EUI48, FLOAT32 // avoid floating point numbers; FLOAT32 might not fit in INTEGER - -> OpenemsType.INTEGER; - case ACC32, BITFIELD32, ENUM32, IPADDR, UINT32, UINT64, ACC64, INT64, IPV6ADDR, // - FLOAT64 // avoid floating point numbers - -> OpenemsType.LONG; - case STRING2, STRING4, STRING5, STRING6, STRING7, STRING8, STRING12, STRING16, STRING20, STRING25, - STRING32 -> - OpenemsType.STRING; - default -> throw new IllegalArgumentException("Unable to get matching OpenemsType for " + this.type); - - }; - } - } - - public static enum PointType { - INT16(1), UINT16(1), COUNT(1), ACC16(1), INT32(2), UINT32(2), FLOAT32(2), ACC32(2), INT64(4), UINT64(4), - FLOAT64(4), ACC64(4), ENUM16(1), ENUM32(2), BITFIELD16(1), BITFIELD32(2), SUNSSF(1), STRING2(2), STRING4(4), - STRING5(5), STRING6(6), STRING7(7), STRING8(8), STRING12(12), STRING16(16), STRING20(20), STRING25(25), - STRING32(32), - /* use PAD for reserved points */ - PAD(1), IPADDR(1), IPV6ADDR(16), EUI48(6); - - public final int length; - - private PointType(int length) { - this.length = length; - } - - /** - * Returns true if the value represents a 'defined' value in SunSpec. - * - * @param type the PointType - * @param value the value - * @return true for defined values - */ - public static boolean isDefined(PointType type, Object value) { - if (value == null) { - return false; - } - return switch (type) { - case INT16, SUNSSF -> !value.equals(Short.MIN_VALUE /* -32768 */); - case UINT16, ENUM16, BITFIELD16, COUNT -> !value.equals(65535); - case ACC16, ACC32, IPADDR, ACC64, IPV6ADDR -> !value.equals(0); - case INT32 -> !value.equals(0x80000000); // TODO correct? - case UINT32, ENUM32, BITFIELD32 -> !value.equals(4294967295L); - case INT64 -> !value.equals(0x8000000000000000L); // TODO correct? - case UINT64 -> !value.equals(0xFFFFFFFFFFFFFFFFL); // TODO correct? - case FLOAT32 -> !value.equals(Float.NaN); - case FLOAT64 -> false; // TODO not implemented - case PAD // This point is never needed/reserved - -> false; - case STRING12, STRING16, STRING2, STRING20, STRING25, STRING32, STRING4, STRING5, STRING6, STRING7, - STRING8 -> - !"".equals(value); - case EUI48 -> false; // TODO not implemented - default -> false; - }; - } - } - - public static enum PointCategory { - NONE, MEASUREMENT, METERED, STATUS, EVENT, SETTING, CONTROL; + throw new IllegalAccessError("SunSpecPoint [" + this.name() + "] has no Channel-ID"); } } \ No newline at end of file diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/SunSpecPointCategory.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/SunSpecPointCategory.java new file mode 100644 index 00000000000..6788e0a651b --- /dev/null +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/SunSpecPointCategory.java @@ -0,0 +1,5 @@ +package io.openems.edge.bridge.modbus.sunspec; + +public enum SunSpecPointCategory { + NONE, MEASUREMENT, METERED, STATUS, EVENT, SETTING, CONTROL; +} \ No newline at end of file diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/Utils.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/Utils.java new file mode 100644 index 00000000000..34208137fa4 --- /dev/null +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/Utils.java @@ -0,0 +1,50 @@ +package io.openems.edge.bridge.modbus.sunspec; + +import static java.util.stream.Collectors.joining; + +import java.util.stream.Stream; + +import com.google.common.base.CaseFormat; + +public class Utils { + + private Utils() { + } + + /** + * Converts a String ID to UPPER_UNDERSCORE. + * + * @param string the source string + * @return the converted string + */ + public static String toUpperUnderscore(String string) { + string = string // + .replace("-", "_") // + .replace(" ", "_"); + if (!string.toUpperCase().equals(string)) { + string = CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, string); + } + return string.replace("__", "_"); + } + + /** + * Converts a String ID to a human readable label. + * + * @param string the source string + * @return the converted string + */ + public static String toLabel(String string) { + if (string.toUpperCase() != string || !string.contains("_")) { + // Directly return non-uppercase strings + return string; + } + // Taken from https://stackoverflow.com/a/28560959/4137113 + return Stream.of(string.trim().split("\\s|_")) // + .filter(word -> word.length() > 0) // + .map(word -> switch (word) { + case "AC", "DC", "HW" -> word; + default -> word.substring(0, 1).toUpperCase() + word.substring(1).toLowerCase(); // + }) // + .collect(joining(" ")); + } +} diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/AbstractOpenemsSunSpecComponentTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/AbstractOpenemsSunSpecComponentTest.java index a4526ef63dd..2ce0c196ec0 100644 --- a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/AbstractOpenemsSunSpecComponentTest.java +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/AbstractOpenemsSunSpecComponentTest.java @@ -24,6 +24,7 @@ import io.openems.edge.bridge.modbus.api.LogVerbosity; import io.openems.edge.bridge.modbus.api.element.ModbusElement; import io.openems.edge.bridge.modbus.api.element.StringWordElement; +import io.openems.edge.bridge.modbus.sunspec.Point.ModbusElementPoint; import io.openems.edge.bridge.modbus.sunspec.dummy.MyConfig; import io.openems.edge.bridge.modbus.sunspec.dummy.MySunSpecComponentImpl; import io.openems.edge.common.test.AbstractComponentTest.TestCase; @@ -38,14 +39,16 @@ public void testPreprocessModbusElements() throws OpenemsException { var elements = new ArrayList(); var startAddress = 0; for (var point : DefaultSunSpecModel.S_701.points()) { - var element = point.get().generateModbusElement(startAddress); - startAddress += element.length; - elements.add(element); + if (point.get() instanceof ModbusElementPoint mep) { // without BitFieldPoints + var element = mep.generateModbusElement(startAddress); + startAddress += element.length; + elements.add(element); + } } var sut = preprocessModbusElements(elements); assertEquals(2, sut.size()); // two sublists - assertEquals(69, sut.get(0).size()); // first task + assertEquals(66, sut.get(0).size()); // first task assertEquals(1, sut.get(1).size()); // second task assertEquals(StringWordElement.class, sut.get(1).get(0).getClass()); // second task } @@ -66,7 +69,7 @@ private static ImmutableSortedMap.Builder generateSunSpec() { .put(40003, 66); // Length of the SunSpec Block IntStream.range(40004, 40070).forEach(i -> b.put(i, 0)); b // - .put(40070, 123) // SunSpec Block-ID + .put(40070, 103) // SunSpec Block-ID .put(40071, 24); // Length of the SunSpec Block IntStream.range(40072, 40096).forEach(i -> b.put(i, 0)); b // @@ -119,7 +122,7 @@ public void test() throws Exception { testWithEndOfMap(slave, bridge, testBridge, cmp, testCmp); testWithIllegalAddress(slave, bridge, testBridge, cmp, testCmp); - assertFalse(cmp.getSunSpecChannel(DefaultSunSpecModel.S103.APH_A).isPresent()); + assertFalse(cmp.getSunSpecChannel(DefaultSunSpecModel.S101.APH_A).isPresent()); assertNotNull(cmp.getSunSpecChannelOrError(DefaultSunSpecModel.S702.W_MAX_RTG)); } finally { @@ -150,7 +153,7 @@ private static void testWithEndOfMap(ModbusSlave slave, BridgeModbusTcpImpl brid cycle(testBridge, testCmp, 5, 100); - assertEquals(58, cmp.channels().size()); + assertEquals(101, cmp.channels().size()); } private static void testWithIllegalAddress(ModbusSlave slave, BridgeModbusTcpImpl bridge, ComponentTest testBridge, @@ -166,6 +169,6 @@ private static void testWithIllegalAddress(ModbusSlave slave, BridgeModbusTcpImp cycle(testBridge, testCmp, 1, 2000); // wait for defective component cycle(testBridge, testCmp, 2, 100); - assertEquals(58, cmp.channels().size()); + assertEquals(101, cmp.channels().size()); } } diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/UtilsTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/UtilsTest.java new file mode 100644 index 00000000000..f11b02dae9b --- /dev/null +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/UtilsTest.java @@ -0,0 +1,21 @@ +package io.openems.edge.bridge.modbus.sunspec; + +import static io.openems.edge.bridge.modbus.sunspec.Utils.toLabel; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class UtilsTest { + + @Test + public void testToLabel() { + assertEquals("Not Configured", toLabel("NOT_CONFIGURED")); + assertEquals("Reserved 8", toLabel("RESERVED_8")); + assertEquals("FixedPF", toLabel("FixedPF")); + assertEquals("Volt-VAr", toLabel("Volt-VAr")); + assertEquals("Freq-Watt-Param", toLabel("Freq-Watt-Param")); + assertEquals("LVRT", toLabel("LVRT")); + assertEquals("DC Over Volt", toLabel("DC_OVER_VOLT")); + } + +} diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/generator/FluentWriter.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/generator/FluentWriter.java new file mode 100644 index 00000000000..c38354b35c2 --- /dev/null +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/generator/FluentWriter.java @@ -0,0 +1,131 @@ +package io.openems.edge.bridge.modbus.sunspec.generator; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.function.Supplier; + +public class FluentWriter implements AutoCloseable { + + private final BufferedWriter w; + + /** + * Builds a {@link FluentWriter}. + * + * @param path the path + * @return a {@link FluentWriter} + * @throws IOException on error + */ + public static FluentWriter to(String path) throws IOException { + return new FluentWriter(Paths.get(path)); + } + + private FluentWriter(Path path) throws IOException { + this.w = Files.newBufferedWriter(path); + } + + /** + * Writes line without final newLine. + * + * @param line the line + * @return myself + * @throws IOException on error + */ + public FluentWriter write(String line) throws IOException { + this.w.write(line); + return this; + } + + /** + * Writes text without final newLine if predicate is true. + * + * @param predicate the predicate; if true write text + * @param text the text Supplier + * @return myself + * @throws IOException on error + */ + public FluentWriter writeIf(boolean predicate, Supplier text) throws IOException { + if (predicate) { + this.write(text.get()); + } + return this; + } + + /** + * Writes true- or false-text without final newLine. + * + * @param predicate the predicate; if true write true-line; if false write + * false-line + * @param trueText the true-text + * @param falseText the false-text + * @return myself + * @throws IOException on error + */ + public FluentWriter writeIf(boolean predicate, String trueText, String falseText) throws IOException { + return predicate // + ? this.write(trueText) // + : this.write(falseText); + } + + /** + * Writes line with final newLine. + * + * @param line the line + * @return myself + * @throws IOException on error + */ + public FluentWriter writeln(String line) throws IOException { + this.w.write(line); + this.w.newLine(); + return this; + } + + /** + * Writes line if predicate is true. + * + * @param predicate the predicate; if true write line + * @param line the line + * @return myself + * @throws IOException on error + */ + public FluentWriter writelnIf(boolean predicate, String line) throws IOException { + if (predicate) { + this.writeln(line); + } + return this; + } + + /** + * Writes true- or false-line without final newLine. + * + * @param predicate the predicate; if true write true-line; if false write + * false-line + * @param trueLine the true-line + * @param falseLine the false-line + * @return myself + * @throws IOException on error + */ + public FluentWriter writelnIf(boolean predicate, String trueLine, String falseLine) throws IOException { + return predicate // + ? this.writeln(trueLine) // + : this.writeln(falseLine); + } + + /** + * Writes an empty newLine. + * + * @return myself + * @throws IOException on error + */ + public FluentWriter blank() throws IOException { + this.w.newLine(); + return this; + } + + @Override + public void close() throws IOException { + this.w.close(); + } +} \ No newline at end of file diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/generator/Model.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/generator/Model.java new file mode 100644 index 00000000000..3c7e716fed5 --- /dev/null +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/generator/Model.java @@ -0,0 +1,74 @@ +package io.openems.edge.bridge.modbus.sunspec.generator; + +import static io.openems.common.utils.JsonUtils.getAsInt; +import static io.openems.common.utils.JsonUtils.getAsJsonArray; +import static io.openems.common.utils.JsonUtils.getAsJsonObject; +import static io.openems.common.utils.JsonUtils.getAsString; +import static io.openems.common.utils.JsonUtils.getAsStringOrElse; + +import com.google.common.collect.ImmutableList; +import com.google.gson.JsonObject; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.exceptions.OpenemsException; +import io.openems.edge.bridge.modbus.sunspec.SunSpecModelType; + +/** + * POJO container for a SunSpec Model. + */ +public record Model(int id, int len, String name, String label, String description, ImmutableList points, + SunSpecModelType modelType) { + + /** + * Builds a {@link Model} from a {@link JsonObject}. + * + * @param model the {@link JsonObject} + * @return a {@link Model} + * @throws OpenemsNamedException on error + */ + public static Model fromJson(JsonObject model) throws OpenemsNamedException { + var id = getAsInt(model, "id"); + var group = model.get("group").getAsJsonObject(); + var name = getAsString(group, "name"); + var label = getAsStringOrElse(group, "label", ""); + var description = getAsStringOrElse(group, "desc", ""); + + var offset = 0; + final var list = ImmutableList.builder(); + for (var point : getAsJsonArray(group, "points")) { + var p = Point.fromJson(getAsJsonObject(point), offset); + // ID and length not to be considered as points + if (!p.id().equals("ID") && !p.id().equals("L")) { + list.add(p); + } + offset += p.len(); + } + var points = list.build(); + var len = points.stream() // + .map(Point::len) // + .reduce(0, (t, p) -> t + p); + var modelType = SunSpecModelType.getModelType(id); + return new Model(id, len, name, label, description, points, modelType); + } + + /** + * Gets the Point with the given Id. + * + * @param id the Point-ID + * @return the Point + * @throws OpenemsException on error + */ + public Point getPoint(String id) throws OpenemsException { + return this.points.stream() // + .filter(p -> p.id() == id) // + .findFirst() // + .orElseThrow(() -> new OpenemsException("Unable to find Point with ID " + id)); + } + + @Override + public String toString() { + return "Model [id=" + this.id + ", name=" + this.name + ", points=" + this.points + ", label=" + this.label + + ", description=" + this.description + "]"; + } + +} \ No newline at end of file diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/generator/Point.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/generator/Point.java new file mode 100644 index 00000000000..4f0c17e5eb5 --- /dev/null +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/generator/Point.java @@ -0,0 +1,193 @@ +package io.openems.edge.bridge.modbus.sunspec.generator; + +import static io.openems.common.utils.JsonUtils.getAsInt; +import static io.openems.common.utils.JsonUtils.getAsOptionalJsonArray; +import static io.openems.common.utils.JsonUtils.getAsOptionalPrimitive; +import static io.openems.common.utils.JsonUtils.getAsOptionalString; +import static io.openems.common.utils.JsonUtils.getAsString; +import static io.openems.common.utils.JsonUtils.getAsStringOrElse; + +import java.util.Arrays; +import java.util.Optional; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import io.openems.common.channel.AccessMode; +import io.openems.common.channel.Unit; +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.exceptions.OpenemsException; +import io.openems.common.function.ThrowingFunction; +import io.openems.edge.bridge.modbus.sunspec.SunSpecPointCategory; + +/** + * POJO container for a SunSpec Point. + */ +public record Point(String id, int len, int offset, String type, Optional scaleFactor, Unit unit, + AccessMode accessMode, boolean mandatory, SunSpecPointCategory category, Point.Symbol[] symbols, String label, + String description) { + + /** + * Builds a {@link Point} from a {@link JsonObject}. + * + * @param point the {@link JsonObject} + * @param offset the address offset + * @return a {@link Point} + * @throws OpenemsNamedException on error + */ + public static Point fromJson(JsonObject point, int offset) throws OpenemsNamedException { + var id = getAsString(point, "name"); + var len = getAsInt(point, "size"); + var label = getAsStringOrElse(point, "label", ""); + var description = getAsStringOrElse(point, "desc", ""); + final String type; + var t = getAsString(point, "type"); + if (t.equals("string")) { + type = "STRING" + len; + } else { + type = t.toUpperCase(); + } + var scaleFactor = getAsOptionalPrimitive(point, "sf").map(sf -> sf.getAsString()); + var unit = toUnit(getAsStringOrElse(point, "units", "")); + var accessMode = switch (getAsStringOrElse(point, "access", "r").toLowerCase()) { + case "wo" // + -> AccessMode.WRITE_ONLY; + case "rw" // + -> AccessMode.READ_WRITE; + default // "r", "ro" + -> AccessMode.READ_ONLY; + }; + var mandatory = getAsOptionalString(point, "mandatory").isPresent(); + var category = SunSpecPointCategory.MEASUREMENT; + + var symbolsJsonOpt = getAsOptionalJsonArray(point, "symbols"); + final Point.Symbol[] symbols; + if (symbolsJsonOpt.isPresent()) { + var symbolsJson = symbolsJsonOpt.get(); + symbols = new Point.Symbol[symbolsJson.size()]; + for (var i = 0; i < symbolsJson.size(); i++) { + var symbol = symbolsJson.get(i); + symbols[i] = Symbol.fromJson(symbol); + } + } else { + symbols = new Point.Symbol[0]; + } + return new Point(id, len, offset, type, scaleFactor, unit, accessMode, mandatory, category, symbols, label, + description); + } + + private static Unit toUnit(String unit) throws OpenemsNamedException { + final ThrowingFunction toUnit = s -> { + s = s.trim(); + if (s.contains(" ")) { + s = s.substring(0, s.indexOf(" ")); + } + return switch (s) { + case "", "%ARtg/%dV", "bps", "cos()", "deg", "Degrees", "hhmmss", "hhmmss.sssZ", "HPa", "kO", "Mbps", + "meters", "mm", "mps", "m/s", "ohms", "Pct", "PF", "SF", "text", "Tmd", "Tmh", "Tms", "Various", + "Vm", "W/m2", "YYYYMMDD", "S", "%Max/Sec" -> + Unit.NONE; + case "%", "%WHRtg" // + -> Unit.PERCENT; + case "A" // + -> Unit.AMPERE; + case "Ah", "AH" // + -> Unit.AMPERE_HOURS; + case "C" // + -> Unit.DEGREE_CELSIUS; + case "Hz" // + -> Unit.HERTZ; + case "kAH" // + -> Unit.KILOAMPERE_HOURS; + case "kWh" // + -> Unit.KILOWATT_HOURS; + case "mSecs" // + -> Unit.MILLISECONDS; + case "Secs" // + -> Unit.SECONDS; + case "V" // + -> Unit.VOLT; + case "VA" // + -> Unit.VOLT_AMPERE; + case "VAh" // + -> Unit.VOLT_AMPERE_HOURS; + case "var", "Var" // + -> Unit.VOLT_AMPERE_REACTIVE; + case "varh", "Varh" // + -> Unit.VOLT_AMPERE_REACTIVE_HOURS; + case "W" // + -> Unit.WATT; + case "Wh", "WH" // Validate manually: OpenEMS distinguishes CUMULATED and DISCRETE Watt-Hours. + -> Unit.CUMULATED_WATT_HOURS; + default // + -> throw new OpenemsException("Unhandled unit [" + s + "]"); + }; + }; + return toUnit.apply(unit); + } + + /** + * Gets the Symbol with the given Id. + * + * @param id the Symbol-Id + * @return the Symbol + * @throws OpenemsException on error + */ + public Point.Symbol getSymbol(String id) throws OpenemsException { + for (var symbol : this.symbols) { + if (symbol.id.equals(id)) { + return symbol; + } + } + throw new OpenemsException("Unable to find Symbol with ID " + id); + } + + @Override + public String toString() { + return "Point [id=" + this.id + ", len=" + this.len + ", offset=" + this.offset + ", type=" + this.type + + ", scaleFactor=" + this.scaleFactor.orElse("") + ", unit=" + this.unit + ", access=" + this.accessMode + + ", mandatory=" + this.mandatory + ", category=" + this.category + ", symbols=" + + Arrays.toString(this.symbols) + ", label=" + this.label + ", description=" + this.description + "]"; + } + + /** + * POJO container for a SunSpec Point Symbol. + */ + public static record Symbol(String id, int value, String label) { + + /** + * Builds a {@link Symbol} from a {@link JsonElement}. + * + * @param symbol the {@link JsonElement} + * @return a {@link Symbol} + * @throws OpenemsNamedException on error + */ + public static Symbol fromJson(JsonElement symbol) throws OpenemsNamedException { + var id = cleanId(getAsString(symbol, "name")); + var value = getAsInt(symbol, "value"); + var label = getAsStringOrElse(symbol, "label", ""); + return new Symbol(id, value, label); + } + + private static String cleanId(String id) { + return switch (id) { + // Special handling for ID 111 point "Operating State" + case "ggOFF", "ggSLEEPING", "ggSTARTING", "ggTHROTTLED", "ggSHUTTING_DOWN", "ggFAULT", "ggSTANDBY" // + -> id.substring(2); + + // Special handling for ID 202 point "Events" + case "M_EVENT_Power_Failure", "M_EVENT_Under_Voltage", "M_EVENT_Low_PF", "M_EVENT_Over_Current", + "M_EVENT_Over_Voltage", "M_EVENT_Missing_Sensor", "M_EVENT_Reserved1", "M_EVENT_Reserved2", + "M_EVENT_Reserved3", "M_EVENT_Reserved4", "M_EVENT_Reserved5", "M_EVENT_Reserved6", + "M_EVENT_Reserved7", "M_EVENT_Reserved8", "M_EVENT_OEM01", "M_EVENT_OEM02", "M_EVENT_OEM03", + "M_EVENT_OEM04", "M_EVENT_OEM05", "M_EVENT_OEM06", "M_EVENT_OEM07", "M_EVENT_OEM08", + "M_EVENT_OEM09", "M_EVENT_OEM10", "M_EVENT_OEM11", "M_EVENT_OEM12", "M_EVENT_OEM13", + "M_EVENT_OEM14", "M_EVENT_OEM15" // + -> id.substring(8); + + default // + -> id; + }; + } + } +} \ No newline at end of file diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/generator/SunSpecCodeGenerator.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/generator/SunSpecCodeGenerator.java new file mode 100644 index 00000000000..fd12bff73d0 --- /dev/null +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/generator/SunSpecCodeGenerator.java @@ -0,0 +1,505 @@ +package io.openems.edge.bridge.modbus.sunspec.generator; + +import static io.openems.common.utils.JsonUtils.parseToJsonObject; +import static io.openems.edge.bridge.modbus.sunspec.Utils.toLabel; +import static io.openems.edge.bridge.modbus.sunspec.Utils.toUpperUnderscore; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import com.google.gson.JsonObject; + +import io.openems.common.channel.Level; +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.common.channel.BooleanReadChannel; +import io.openems.edge.common.channel.StateChannel; + +/** + * This tool converts SunSpec Json definitions to Java code suitable for the + * OpenEMS SunSpec implementation. + * + *

    + * Download Json files from https://github.com/sunspec/models. + */ +public class SunSpecCodeGenerator { + + /** + * Path to the SunSpec model Json files; download them from + * https://github.com/sunspec/models. + */ + private static final String SUNSPEC_JSON_PATH = System.getProperty("user.home") + "\\git\\sunspec\\json\\"; + /** + * Path to the generated output file. + */ + private static final String OUT_FILE_PATH = System.getProperty("user.dir") + + "\\src\\io\\openems\\edge\\bridge\\modbus\\sunspec\\DefaultSunSpecModel.java"; + + /** + * Json files that should be ignored; mainly because certain features are not + * implemented yet. + */ + private static final Set IGNORE_FILES = new HashSet<>(Arrays.asList(// + "model_3.json", // + "model_4.json", // + "model_5.json", // + "model_6.json", // + "model_7.json", // + "model_8.json", // + "model_9.json", // + "model_10.json", // + "model_11.json", // + "model_12.json", // + "model_13.json", // + "model_14.json", // + "model_16.json", // + "model_17.json", // + "model_19.json", // + "model_126.json", // + "model_129.json", // + "model_130.json", // + "model_131.json", // + "model_132.json", // + "model_133.json", // + "model_134.json", // + "model_135.json", // + "model_136.json", // + "model_137.json", // + "model_138.json", // + "model_139.json", // + "model_140.json", // + "model_141.json", // + "model_142.json", // + "model_143.json", // + "model_144.json", // + "model_160.json", // + "model_211.json", // + "model_212.json", // + "model_213.json", // + "model_214.json", // + "model_220.json", // + "model_302.json", // + "model_303.json", // + "model_304.json", // + "model_401.json", // + "model_402.json", // + "model_403.json", // + "model_404.json", // + "model_501.json", // + "model_502.json", // + "model_601.json", // + "model_803.json", // + "model_804.json", // + "model_805.json", // + "model_806.json", // + "model_807.json", // + "model_808.json", // + "model_809.json", // + "model_63001.json", // + "model_63002.json", // + "model_64020.json" // + )); + + /** + * Run this method to start the code generator. + * + * @param args not supported + * @throws Exception on error + */ + public static void main(String[] args) throws Exception { + System.out.println("Parsing SunSpec files from " + SUNSPEC_JSON_PATH); + var generator = new SunSpecCodeGenerator(); + var models = generator.parseSunSpecFiles(); + generator.writeSunSpecModelJavaFile(models); + } + + /** + * Parses all SunSpec Json files in a directory. + * + * @return a list of Models + * @throws Exception on error + */ + private List parseSunSpecFiles() throws Exception { + List result = new ArrayList<>(); + for (var file : new File(SUNSPEC_JSON_PATH).listFiles(file -> // + file.getName().startsWith("model") // + && file.getName().endsWith(".json") // + && !IGNORE_FILES.contains(file.getName()))) { + try { + var model = this.parseSunSpecFile(Files.readString(file.toPath())); + result.add(model); + + } catch (Exception e) { + throw new Exception("Error while reading from " + file, e); + } + } + // Sort by model ids to have an ordered output + result.sort(new Comparator() { + @Override + public int compare(Model m1, Model m2) { + return m1.id() - m2.id(); + } + }); + + return result; + } + + /** + * Parses a SunSpec Json file. + * + * @param file the SunSpec Json file handler + * @return the Model + * @throws Exception on error + */ + private Model parseSunSpecFile(String file) throws Exception { + var json = parseToJsonObject(file); + + var generator = new SunSpecCodeGenerator(); + return generator.parseSunSpecModels(json); + } + + /** + * Parses the element sunSpecModels. + * + *

    +	 *   <sunSpecModels v="1">
    +	 * 
    + * + *
      + *
    • xs:attribute name="v" type="xs:string" default="1" + *
    + * + * @param sunSpecModels the 'sunSpecModels' json + * @return the Model + * @throws OpenemsNamedException on error + * @throws JSONException on json error + */ + private Model parseSunSpecModels(JsonObject sunSpecModels) throws OpenemsNamedException { + return Model.fromJson(sunSpecModels); + } + + private static enum PointType { + VALUE("ValuePoint", "ValuePoint.Type"), // + SCALED_VALUE("ScaledValuePoint", "ValuePoint.Type"), // + SCALE_FACTOR("ScaleFactorPoint", "ScaleFactorPoint.Type"), // + ENUM("EnumPoint", "EnumPoint.Type"), // + BITFIELD("BitFieldPoint", "BitFieldPoint.Type"); + + public final String clazz; + public final String typeClazz; + + private PointType(String clazz, String type) { + this.clazz = clazz; + this.typeClazz = type; + } + + public static PointType evaluate(Point point) { + if (point.scaleFactor().isPresent()) { + return PointType.SCALED_VALUE; + } + switch (point.type()) { + case "ENUM16", "ENUM32": + return PointType.ENUM; + case "SUNSSF": + return PointType.SCALE_FACTOR; + case "BITFIELD16", "BITFIELD32": + return PointType.BITFIELD; + } + return PointType.VALUE; + } + } + + /** + * Writes the SunSpecModel.java file. + * + * @param models a list of Models + * @throws IOException on error + */ + private void writeSunSpecModelJavaFile(List models) throws IOException { + try (var w = FluentWriter.to(OUT_FILE_PATH)) { + w // + .writeln("// CHECKSTYLE:OFF") // + .blank() // + .writeln("package io.openems.edge.bridge.modbus.sunspec;") // + .blank() // + .writeln("import io.openems.common.channel.AccessMode;") // + .writeln("import io.openems.common.channel.Level;") // + .writeln("import io.openems.common.channel.Unit;") // + .writeln("import io.openems.common.types.OptionsEnum;") // + .writeln("import io.openems.edge.bridge.modbus.sunspec.Point.BitFieldPoint;") // + .writeln("import io.openems.edge.bridge.modbus.sunspec.Point.BitFieldPoint.SunSpecBitPoint;") // + .writeln("import io.openems.edge.bridge.modbus.sunspec.Point.BitPoint;") // + .writeln("import io.openems.edge.bridge.modbus.sunspec.Point.EnumPoint;") // + .writeln("import io.openems.edge.bridge.modbus.sunspec.Point.ScaleFactorPoint;") // + .writeln("import io.openems.edge.bridge.modbus.sunspec.Point.ScaledValuePoint;") // + .writeln("import io.openems.edge.bridge.modbus.sunspec.Point.ValuePoint;") // + .blank() // + .writeln("/**") // + .writeln(" * Do not touch this file. It is auto-generated by SunSpecCodeGenerator.") // + .writeln(" */") // + .writeln("public enum DefaultSunSpecModel implements SunSpecModel {"); + + /* + * Write main Model enum + */ + for (var i = 0; i < models.size(); i++) { + var model = models.get(i); + w // + .writeln(" S_" + model.id() + "(" // + + "\"" + esc(model.label()) + "\", //") // + .writeln(" \"" + esc(model.description()) + "\", //") // + .write(" " + model.len() + " /* length */, " // + + "DefaultSunSpecModel.S" + model.id() + ".values(), " // + + "SunSpecModelType." + model.modelType()) // + .writelnIf(i == models.size() - 1, // + "); //", // + "), //"); + } + w.blank(); + + /* + * For each Model write enum with SunSpecPoints + */ + for (var model : models) { + w.writeln(" public static enum S" + model.id() + " implements SunSpecPoint {"); + for (var i = 0; i < model.points().size(); i++) { + final var point = model.points().get(i); + final var pointUpperId = toUpperUnderscore(point.id()); + final var pointType = PointType.evaluate(point); + w // + .write(" " + pointUpperId + "(new " + pointType.clazz + "(" // + + "\"S" + model.id() + "_" + pointUpperId + "\", " // + + "\"" + esc(point.label()) + "\", "); + if (!point.description().isEmpty()) { + w.writeln("//").write(" "); + } + w.write("\"" + esc(point.description()) + "\""); // + + if (pointType != PointType.SCALE_FACTOR) { + w // + .writeln(", //") // + .write(" " + pointType.typeClazz + "." + point.type() + ", " // + + point.mandatory() + " /* mandatory? */" // + + ", AccessMode." + point.accessMode().name()); + if (pointType == PointType.VALUE || pointType == PointType.SCALED_VALUE) { + w // + .write(", Unit." + point.unit().name()); + } + if (pointType == PointType.SCALED_VALUE) { + w // + .write(", \"" + point.scaleFactor().get() + "\""); + } else if (pointType == PointType.ENUM) { + w // + .write(", ") // + .writeIf(point.symbols().length == 0, // + "new OptionsEnum[0]", // + "S" + model.id() + "_" + point.id() + ".values()"); + } else if (pointType == PointType.BITFIELD) { + w // + .write(", ") // + .writeIf(point.symbols().length == 0, // + "new SunSpecBitPoint[0]", // + "S" + model.id() + "_" + point.id() + ".values()"); + } + } + + w.writelnIf(i == model.points().size() - 1, // + "));", // + ")), //"); + } + w // + .blank() // + .writeln(" private final Point point;") // + .blank() // + .writeln(" private S" + model.id() + "(Point point) {") // + .writeln(" this.point = point;") // + .writeln(" }") // + .blank() // + .writeln(" @Override") // + .writeln(" public Point get() {") // + .writeln(" return this.point;") // + .writeln(" }") // + .writeln(" }") // + .blank(); + + // Handle SunSpecPoints with Symbols + for (var point : model.points()) { + if (point.symbols().length == 0) { + continue; + } + final var pointType = PointType.evaluate(point); + /* + * Handle Enum points + */ + if (pointType == PointType.ENUM) { + w // + .writeln(" public static enum S" + model.id() + "_" + point.id() + + " implements OptionsEnum {") // + .writeln(" UNDEFINED(-1, \"Undefined\"), //"); + for (var i = 0; i < point.symbols().length; i++) { + final var symbol = point.symbols()[i]; + var symbolId = toUpperUnderscore(symbol.id()); + + switch (symbolId) { + case "RESERVED": + symbolId = symbolId + "_" + symbol.value(); // avoid duplicated "RESERVED" ids. + break; + } + + w // + .write(" " + symbolId + "(" + symbol.value() + ", \"" + symbolId + "\")") // + .writelnIf(i == point.symbols().length - 1, // + ";", // + ", //"); + } + w.blank() // + .writeln(" private final int value;") // + .writeln(" private final String name;") // + .blank() // + .writeln(" private S" + model.id() + "_" + point.id() + + "(int value, String name) {") // + .writeln(" this.value = value;") // + .writeln(" this.name = name;") // + .writeln(" }") // + .blank() // + .writeln(" @Override") // + .writeln(" public int getValue() {") // + .writeln(" return this.value;") // + .writeln(" }") // + .blank() // + .writeln(" @Override") // + .writeln(" public String getName() {") // + .writeln(" return this.name;") // + .writeln(" }") // + .blank() // + .writeln(" @Override") // + .writeln(" public OptionsEnum getUndefined() {") // + .writeln(" return UNDEFINED;") // + .writeln(" }") // + .writeln(" }") // + .blank(); + + } else if (pointType == PointType.BITFIELD) { + /* + * Handle BitField points + */ + final var name = "S" + model.id() + "_" + point.id(); + w.writeln(" public static enum " + name + " implements SunSpecBitPoint {"); + for (var i = 0; i < point.symbols().length; i++) { + final var symbol = point.symbols()[i]; + var symbolId = toUpperUnderscore(symbol.id()); + var channelId = toUpperUnderscore(name) + "_" + symbolId; + var label = toLabel(symbol.id()); + var level = getBitLevel(channelId); + w // + .write(" " + symbolId + "(new BitPoint(" + symbol.value() + ", \"" + + channelId + "\", \"" + label + "\"") // + .writeIf(level != null, () -> ", Level." + level.name()) // + .write("))") // + .writelnIf(i == point.symbols().length - 1, // + ";", // + ", //"); + } + w // + .blank() // + .writeln(" private final BitPoint point;") // + .blank() // + .writeln(" private " + name + "(BitPoint point) {") // + .writeln(" this.point = point;") // + .writeln(" }") // + .blank() // + .writeln(" @Override") // + .writeln(" public BitPoint get() {") // + .writeln(" return this.point;") // + .writeln(" }") // + .writeln(" }") // + .blank(); + + } + } + } + + w // + .writeln(" public final String label;") // + .writeln(" public final String description;") // + .writeln(" public final int length;") // + .writeln(" public final SunSpecPoint[] points;") // + .writeln(" public final SunSpecModelType modelType;") // + .blank() // + .writeln( + " private DefaultSunSpecModel(String label, String description, int length, SunSpecPoint[] points,") // + .writeln(" SunSpecModelType modelType) {") // + .writeln(" this.label = label;") // + .writeln(" this.description = description;") // + .writeln(" this.length = length;") // + .writeln(" this.points = points;") // + .writeln(" this.modelType = modelType;") // + .writeln(" }") // + .blank() // + .writeln(" @Override") // + .writeln(" public SunSpecPoint[] points() {") // + .writeln(" return this.points;") // + .writeln(" }") // + .blank() // + .writeln(" @Override") // + .writeln(" public String label() {") // + .writeln(" return this.label;") // + .writeln(" }") // + .writeln("}") // + .writeln("// CHECKSTYLE:ON"); + } + + } + + /** + * Gets the {@link StateChannel}-Level per Channel-ID. + * + * @param channelId the upper-case Channel-ID, e.g. "S2_EVT_GROUND_FAULT" + * @return {@link Level}, defaults to {@link Level#OK}; or null to create a + * {@link BooleanReadChannel} + */ + private static Level getBitLevel(String channelId) { + // RESERVED + if (channelId.contains("RESERVED")) { + return null; + } + + // Level.WARNING Points + for (var prefix : new String[] { "S2_EVT_", "S101_EVT1_", "S102_EVT1_", "S103_EVT1_", "S111_EVT1_", + "S112_EVT1_", "S113_EVT1_" }) { + if (channelId.startsWith(prefix)) { + // TODO: those should be Level.WARNING + return Level.INFO; + } + + } + + return switch (channelId) { + // This is the position for Channel-ID specific Levels + default -> null; + }; + } + + /** + * Helper method to escape a string. + * + * @param string original string + * @return escaped string + */ + private static final String esc(String string) { + if (string == null) { + return ""; + } + return string // + .replaceAll("[^\\x00-\\x7F]", "") // non-ascii chars + .replace("\"", "\\\"") // escape backslash + .trim(); + } + +} diff --git a/io.openems.edge.common/src/io/openems/edge/common/channel/EnumDoc.java b/io.openems.edge.common/src/io/openems/edge/common/channel/EnumDoc.java index ad081859f0f..92306580030 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/channel/EnumDoc.java +++ b/io.openems.edge.common/src/io/openems/edge/common/channel/EnumDoc.java @@ -43,7 +43,9 @@ public OptionsEnum[] getOptions() { * @return myself */ public EnumDoc initialValue(OptionsEnum initialValue) { - this.initialValue(initialValue.getValue()); + if (initialValue != null) { + this.initialValue(initialValue.getValue()); + } return this.self(); } diff --git a/io.openems.edge.common/src/io/openems/edge/common/filter/Pt1filter.java b/io.openems.edge.common/src/io/openems/edge/common/filter/Pt1filter.java index 75029dce386..3e1e56219be 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/filter/Pt1filter.java +++ b/io.openems.edge.common/src/io/openems/edge/common/filter/Pt1filter.java @@ -2,18 +2,19 @@ public class Pt1filter { - private final double filterTimeConstant; + private final int filterTimeConstant; - private double yOld = 0.0; - private double cycleTime = 0.0; + private double result; + private int cycleTime; /** * Creates a PT1 filter. * * @param filterTimeConstant filter time constant in seconds. - * @param cycleTime cycle time of calling applyPt1Filter in seconds + * @param cycleTime cycle time of calling applyPt1Filter in + * milliseconds */ - public Pt1filter(double filterTimeConstant, double cycleTime) { + public Pt1filter(int filterTimeConstant, int cycleTime) { this.filterTimeConstant = filterTimeConstant; this.cycleTime = cycleTime; } @@ -23,7 +24,7 @@ public Pt1filter(double filterTimeConstant, double cycleTime) { * * @param cycleTime cycle time of calling applyPt1Filter in seconds */ - public void setCycleTime(double cycleTime) { + public void setCycleTime(int cycleTime) { this.cycleTime = cycleTime; } @@ -33,19 +34,15 @@ public void setCycleTime(double cycleTime) { * @param value the input value * @return the filtered value */ - public double applyPt1Filter(double value) { - // cycle time has not to be zero - if (this.cycleTime == 0.0) { - return (0.0); - } + public int applyPt1Filter(double value) { // disable PT1-Filter if time constant is zero - if (this.filterTimeConstant == 0.0) { - this.yOld = value; - return (value); + if (this.filterTimeConstant == 0) { + this.result = value; + return (int) value; } // apply filter - this.yOld = (value + this.filterTimeConstant / this.cycleTime * this.yOld) - / (1 + this.filterTimeConstant / this.cycleTime); - return this.yOld; + final var cycle = this.cycleTime / 1000.; + this.result = (value + this.filterTimeConstant / cycle * this.result) / (1 + this.filterTimeConstant / cycle); + return (int) this.result; } } \ No newline at end of file diff --git a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome20.java b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome20.java index 083bd11673b..f0c98903754 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome20.java +++ b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome20.java @@ -259,6 +259,7 @@ public FeneconHome20(// } } + @SuppressWarnings("removal") @Override protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { return (t, p, l) -> { diff --git a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome30.java b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome30.java index 34d2c672789..60c8bacec42 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome30.java +++ b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome30.java @@ -260,6 +260,7 @@ public FeneconHome30(// } } + @SuppressWarnings("removal") @Override protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { return (t, p, l) -> { diff --git a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/AwattarHourly.java b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/AwattarHourly.java index 06dbbf9b32f..2a239b4579a 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/AwattarHourly.java +++ b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/AwattarHourly.java @@ -10,6 +10,7 @@ import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; import com.google.common.collect.Lists; @@ -56,7 +57,6 @@ "properties":{ "CTRL_ESS_TIME_OF_USE_TARIFF_ID": "ctrlEssTimeOfUseTariff0", "TIME_OF_USE_TARIFF_PROVIDER_ID": "timeOfUseTariff0", - "CONTROL_MODE": {@link ControlMode}, "ZONE": {@link Zone}, }, "appDescriptor": { @@ -65,7 +65,7 @@ } * */ -@org.osgi.service.component.annotations.Component(name = "App.TimeOfUseTariff.Awattar") +@Component(name = "App.TimeOfUseTariff.Awattar") public class AwattarHourly extends AbstractOpenemsAppWithProps implements OpenemsApp { diff --git a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/EntsoE.java b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/EntsoE.java index cb773d1e584..417b2e8a67b 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/EntsoE.java +++ b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/EntsoE.java @@ -8,6 +8,7 @@ import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; import com.google.common.collect.Lists; @@ -63,7 +64,7 @@ } * */ -@org.osgi.service.component.annotations.Component(name = "App.TimeOfUseTariff.ENTSO-E") +@Component(name = "App.TimeOfUseTariff.ENTSO-E") public class EntsoE extends AbstractOpenemsAppWithProps implements OpenemsApp { // TODO provide image in folder diff --git a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/RabotCharge.java b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/RabotCharge.java new file mode 100644 index 00000000000..c423c7bbcb9 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/RabotCharge.java @@ -0,0 +1,188 @@ +package io.openems.edge.app.timeofusetariff; + +import static io.openems.edge.core.appmanager.formly.enums.InputType.PASSWORD; +import static io.openems.edge.core.appmanager.validator.Checkables.checkHome; + +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.common.collect.Lists; +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.types.EdgeConfig; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.app.common.props.CommonProps; +import io.openems.edge.app.timeofusetariff.RabotCharge.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.ComponentManagerSupplier; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.Nameable; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.dependency.Tasks; +import io.openems.edge.core.appmanager.dependency.aggregatetask.SchedulerByCentralOrderConfiguration.SchedulerComponent; +import io.openems.edge.core.appmanager.formly.JsonFormlyUtil; +import io.openems.edge.core.appmanager.validator.ValidatorConfig; + +/** + * Describes a App for RabotCharge. + * + *
    +  {
    +    "appId":"App.TimeOfUseTariff.RabotCharge",
    +    "alias":"Rabot Charge",
    +    "instanceId": UUID,
    +    "image": base64,
    +    "properties":{
    +    	"CTRL_ESS_TIME_OF_USE_TARIFF_ID": "ctrlEssTimeOfUseTariff0",
    +    	"TIME_OF_USE_TARIFF_PROVIDER_ID": "timeOfUseTariff0",
    +    	"ACCESS_TOKEN": {token}
    +    },
    +    "appDescriptor": {
    +    	"websiteUrl": {@link AppDescriptor#getWebsiteUrl()}
    +    }
    +  }
    + * 
    + */ +@Component(name = "App.TimeOfUseTariff.RabotCharge") +public class RabotCharge extends AbstractOpenemsAppWithProps + implements OpenemsApp { + + public static enum Property implements Type, Nameable { + // Component-IDs + CTRL_ESS_TIME_OF_USE_TARIFF_ID(AppDef.componentId("ctrlEssTimeOfUseTariff0")), // + TIME_OF_USE_TARIFF_PROVIDER_ID(AppDef.componentId("timeOfUseTariff0")), // + + // Properties + ALIAS(CommonProps.alias()), // + ACCESS_TOKEN(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def// + .setTranslatedLabelWithAppPrefix(".accessToken.label") // + .setTranslatedDescriptionWithAppPrefix(".accessToken.description") // + .setRequired(true) // + .setField(JsonFormlyUtil::buildInput, (app, prop, l, params, field) -> { + field.setInputType(PASSWORD); + }) // + .bidirectional(TIME_OF_USE_TARIFF_PROVIDER_ID, "accessToken", + ComponentManagerSupplier::getComponentManager, t -> { + return JsonUtils.getAsOptionalString(t) // + .map(s -> { + if (s.isEmpty()) { + return null; + } + return new JsonPrimitive("xxx"); + }) // + .orElse(null); + }))); + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Property self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, Type.Parameter.BundleParameter> getParamter() { + return Type.Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + } + + @Activate + public RabotCharge(@Reference ComponentManager componentManager, ComponentContext context, + @Reference ConfigurationAdmin cm, @Reference ComponentUtil componentUtil) { + super(componentManager, context, cm, componentUtil); + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + final var ctrlEssTimeOfUseTariffId = this.getId(t, p, Property.CTRL_ESS_TIME_OF_USE_TARIFF_ID); + final var timeOfUseTariffProviderId = this.getId(t, p, Property.TIME_OF_USE_TARIFF_PROVIDER_ID); + + final var alias = this.getString(p, l, Property.ALIAS); + final var accessToken = this.getValueOrDefault(p, Property.ACCESS_TOKEN, null); + + var components = Lists.newArrayList(// + new EdgeConfig.Component(ctrlEssTimeOfUseTariffId, alias, "Controller.Ess.Time-Of-Use-Tariff", + JsonUtils.buildJsonObject() // + .addProperty("ess.id", "ess0") // + .build()), // + new EdgeConfig.Component(timeOfUseTariffProviderId, this.getName(l), "TimeOfUseTariff.RabotCharge", + JsonUtils.buildJsonObject() // + .onlyIf(accessToken != null && !accessToken.equals("xxx"), b -> { + b.addProperty("accessToken", accessToken); + }) // + .build())// + ); + + return AppConfiguration.create() // + .addTask(Tasks.component(components)) // + .addTask(Tasks.schedulerByCentralOrder(new SchedulerComponent(ctrlEssTimeOfUseTariffId, + "Controller.Ess.Time-Of-Use-Tariff", this.getAppId()))) // + .addTask(Tasks.persistencePredictor("_sum/UnmanagedConsumptionActivePower")) // + .build(); + }; + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.TIME_OF_USE_TARIFF }; + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.SINGLE_IN_CATEGORY; + } + + @Override + protected ValidatorConfig.Builder getValidateBuilder() { + return ValidatorConfig.create() // + .setCompatibleCheckableConfigs(checkHome()); + } + + @Override + protected RabotCharge getApp() { + return this; + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StromdaoCorrently.java b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StromdaoCorrently.java index 61521495bca..603fb81f5ba 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StromdaoCorrently.java +++ b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StromdaoCorrently.java @@ -8,6 +8,7 @@ import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; import com.google.common.collect.Lists; @@ -61,7 +62,7 @@ } * */ -@org.osgi.service.component.annotations.Component(name = "App.TimeOfUseTariff.Stromdao") +@Component(name = "App.TimeOfUseTariff.Stromdao") public class StromdaoCorrently extends AbstractOpenemsAppWithProps implements OpenemsApp { diff --git a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/Tibber.java b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/Tibber.java index d3bb47f83bf..38b7b7b8b8b 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/Tibber.java +++ b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/Tibber.java @@ -9,6 +9,7 @@ import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; import com.google.common.collect.Lists; @@ -64,7 +65,7 @@ } * */ -@org.osgi.service.component.annotations.Component(name = "App.TimeOfUseTariff.Tibber") +@Component(name = "App.TimeOfUseTariff.Tibber") public class Tibber extends AbstractOpenemsAppWithProps implements OpenemsApp { diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties index d0e0f07245e..36d9b9dd184 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties @@ -350,6 +350,10 @@ App.TimeOfUseTariff.ENTSO-E.biddingZone.option.sweden_se3 = Schweden (SE3) App.TimeOfUseTariff.ENTSO-E.biddingZone.option.sweden_se4 = Schweden (SE4) App.TimeOfUseTariff.ENTSO-E.biddingZone.option.belgium = Belgien App.TimeOfUseTariff.ENTSO-E.biddingZone.option.netherlands = Niederlande +App.TimeOfUseTariff.RabotCharge.Name = Time-of-Use Tariff (rabot.charge) +App.TimeOfUseTariff.RabotCharge.Name.short = rabot.charge +App.TimeOfUseTariff.RabotCharge.accessToken.label = Token +App.TimeOfUseTariff.RabotCharge.accessToken.description = Bitte stellen Sie das von rabot.charge bereitgestellte persönliche Zugangstoken bereit. Um ein Token zu erhalten, wenden Sie sich bitte an rabot.charge. App.TimeOfUseTariff.Stromdao.Name = Dynamischer Stromtarif (Stromdao Corrently) App.TimeOfUseTariff.Stromdao.Name.short = Stromdao Corrently App.TimeOfUseTariff.Stromdao.zipCode.label = PLZ diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties index 75b69cbbf27..fe9c08c25f9 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties @@ -349,6 +349,10 @@ App.TimeOfUseTariff.ENTSO-E.biddingZone.option.sweden_se3 = Sweden (SE3) App.TimeOfUseTariff.ENTSO-E.biddingZone.option.sweden_se4 = Sweden (SE4) App.TimeOfUseTariff.ENTSO-E.biddingZone.option.belgium = Belgium App.TimeOfUseTariff.ENTSO-E.biddingZone.option.netherlands = Netherlands +App.TimeOfUseTariff.RabotCharge.Name = Time-of-Use Tariff (rabot.charge) +App.TimeOfUseTariff.RabotCharge.Name.short = rabot.charge +App.TimeOfUseTariff.RabotCharge.accessToken.label = Token +App.TimeOfUseTariff.RabotCharge.accessToken.description = Please provide personal access token provided by rabot.charge. to get one, please contact rabot.charge. App.TimeOfUseTariff.Stromdao.Name = Time-of-Use Tariff (STROMDAO Corrently) App.TimeOfUseTariff.Stromdao.Name.short = STROMDAO Corrently App.TimeOfUseTariff.Stromdao.zipCode.label = ZIP Code diff --git a/io.openems.edge.core/src/io/openems/edge/core/host/NetworkInterface.java b/io.openems.edge.core/src/io/openems/edge/core/host/NetworkInterface.java index e88a7868206..4cce05f0a93 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/host/NetworkInterface.java +++ b/io.openems.edge.core/src/io/openems/edge/core/host/NetworkInterface.java @@ -1,5 +1,11 @@ package io.openems.edge.core.host; +import static io.openems.common.utils.JsonUtils.buildJsonArray; +import static io.openems.common.utils.JsonUtils.buildJsonObject; +import static io.openems.common.utils.JsonUtils.getAsInet4Address; +import static io.openems.common.utils.JsonUtils.getAsString; +import static io.openems.common.utils.JsonUtils.getOptionalSubElement; + import java.net.Inet4Address; import java.util.HashSet; import java.util.Optional; @@ -41,70 +47,70 @@ public class NetworkInterface
    { * @throws OpenemsNamedException on error */ public static NetworkInterface from(String name, JsonObject j) throws OpenemsNamedException { + var gateway = parseInet4Address(j, "gateway"); + var metric = parseInteger(j, "metric"); + var dns = parseInet4Address(j, "dns"); + var addresses = parseAddresses(j); + var dhcp = parseBoolean(j, "dhcp"); + var linkLocalAddressing = parseBoolean(j, "linkLocalAddressing"); + + return new NetworkInterface(name, dhcp, linkLocalAddressing, gateway, dns, addresses, metric, null); + } - // Gateway - ConfigurationProperty gateway; - { - ConfigurationProperty gatewayString = ConfigurationProperty - .fromJsonElement(JsonUtils.getOptionalSubElement(j, "gateway"), JsonUtils::getAsString); - if (gatewayString.isSet()) { - if (gatewayString.getValue() == null || gatewayString.getValue().trim().isEmpty()) { - gateway = ConfigurationProperty.asNull(); - } else { - gateway = ConfigurationProperty.fromJsonElement( - Optional.of(new JsonPrimitive(gatewayString.getValue())), JsonUtils::getAsInet4Address); - } + private static ConfigurationProperty parseInet4Address(JsonObject j, String member) + throws OpenemsNamedException { + ConfigurationProperty gatewayString = ConfigurationProperty + .fromJsonElement(getOptionalSubElement(j, member), JsonUtils::getAsString); + if (gatewayString.isSet()) { + if (gatewayString.getValue() == null || gatewayString.getValue().trim().isEmpty()) { + return ConfigurationProperty.asNull(); } else { - gateway = ConfigurationProperty.asNotSet(); + return ConfigurationProperty.fromJsonElement(// + Optional.of(new JsonPrimitive(gatewayString.getValue())), JsonUtils::getAsInet4Address); } + } else { + return ConfigurationProperty.asNotSet(); } + } - // DNS - ConfigurationProperty dns; - { - ConfigurationProperty dnsString = ConfigurationProperty - .fromJsonElement(JsonUtils.getOptionalSubElement(j, "dns"), JsonUtils::getAsString); - if (dnsString.isSet()) { - if (dnsString.getValue() == null || dnsString.getValue().trim().isEmpty()) { - dns = ConfigurationProperty.asNull(); - } else { - dns = ConfigurationProperty.fromJsonElement(Optional.of(new JsonPrimitive(dnsString.getValue())), - JsonUtils::getAsInet4Address); - } + private static ConfigurationProperty parseInteger(JsonObject j, String member) + throws OpenemsNamedException { + ConfigurationProperty metricElement = ConfigurationProperty + .fromJsonElement(getOptionalSubElement(j, member), JsonUtils::getAsInt); + if (metricElement.isSet()) { + if (metricElement.getValue() == null) { + return ConfigurationProperty.asNull(); } else { - dns = ConfigurationProperty.asNotSet(); + return ConfigurationProperty.fromJsonElement(// + Optional.of(new JsonPrimitive(metricElement.getValue())), JsonUtils::getAsInt); } + } else { + return ConfigurationProperty.asNotSet(); } + } - // Addresses - ConfigurationProperty> addresses; - { - ConfigurationProperty addressesArray = ConfigurationProperty - .fromJsonElement(JsonUtils.getOptionalSubElement(j, "addresses"), JsonUtils::getAsJsonArray); - if (addressesArray.isSet()) { - var value = new HashSet(); - for (JsonElement element : addressesArray.getValue()) { - var label = JsonUtils.getAsString(element, "label"); - var address = JsonUtils.getAsInet4Address(element, "address"); - var subnetmask = JsonUtils.getAsInet4Address(element, "subnetmask"); - var cidr = Inet4AddressWithSubnetmask.getCidrFromSubnetmask(subnetmask); - value.add(new Inet4AddressWithSubnetmask(label, address, cidr)); - } - addresses = ConfigurationProperty.of(value); - } else { - addresses = ConfigurationProperty.asNotSet(); + private static ConfigurationProperty> parseAddresses(JsonObject j) + throws OpenemsNamedException { + ConfigurationProperty addressesArray = ConfigurationProperty + .fromJsonElement(getOptionalSubElement(j, "addresses"), JsonUtils::getAsJsonArray); + if (addressesArray.isSet()) { + var value = new HashSet(); + for (JsonElement element : addressesArray.getValue()) { + var label = getAsString(element, "label"); + var address = getAsInet4Address(element, "address"); + var subnetmask = getAsInet4Address(element, "subnetmask"); + var cidr = Inet4AddressWithSubnetmask.getCidrFromSubnetmask(subnetmask); + value.add(new Inet4AddressWithSubnetmask(label, address, cidr)); } + return ConfigurationProperty.of(value); + } else { + return ConfigurationProperty.asNotSet(); } + } - // DHCP - ConfigurationProperty dhcp = ConfigurationProperty - .fromJsonElement(JsonUtils.getOptionalSubElement(j, "dhcp"), JsonUtils::getAsBoolean); - - // linkLocalAddressing - ConfigurationProperty linkLocalAddressing = ConfigurationProperty - .fromJsonElement(JsonUtils.getOptionalSubElement(j, "linkLocalAddressing"), JsonUtils::getAsBoolean); - - return new NetworkInterface(name, dhcp, linkLocalAddressing, gateway, dns, addresses, null); + private static ConfigurationProperty parseBoolean(JsonObject j, String member) + throws OpenemsNamedException { + return ConfigurationProperty.fromJsonElement(getOptionalSubElement(j, member), JsonUtils::getAsBoolean); } private final String name; @@ -113,6 +119,7 @@ public static NetworkInterface from(String name, JsonObject j) throws Openems private ConfigurationProperty gateway; private ConfigurationProperty dns; private ConfigurationProperty> addresses; + private ConfigurationProperty metric; /** * An arbitrary attachment to this NetworkInterface. Can be used to store e.g. a @@ -126,6 +133,7 @@ public NetworkInterface(String name, // ConfigurationProperty gateway, // ConfigurationProperty dns, // ConfigurationProperty> addresses, // + ConfigurationProperty metric, // A attachment) throws OpenemsException { this.name = name; this.dhcp = dhcp; @@ -134,6 +142,7 @@ public NetworkInterface(String name, // this.dns = dns; this.attachment = attachment; this.addresses = addresses; + this.metric = metric; } /** @@ -172,6 +181,15 @@ public ConfigurationProperty getGateway() { return this.gateway; } + /** + * Gets the network interface metric. + * + * @return the Metric + */ + public ConfigurationProperty getMetric() { + return this.metric; + } + /** * Gets the addresses configured in the network. * @@ -227,6 +245,7 @@ public ConfigurationProperty> getAddressesInclud * "linkLocalAddressing": boolean, * "gateway": string, * "dns": string, + * "metric": number, * "addresses": [{ * "label": string, * "address": string, @@ -239,20 +258,22 @@ public ConfigurationProperty> getAddressesInclud * @throws OpenemsNamedException on error. */ public JsonObject toJson() { - var result = JsonUtils.buildJsonObject() // + var result = buildJsonObject() // .onlyIf(this.dhcp.isSet(), // b -> b.addProperty("dhcp", this.dhcp.getValue())) .onlyIf(this.linkLocalAddressing.isSet(), // b -> b.addProperty("linkLocalAddressing", this.linkLocalAddressing.getValue())) .onlyIf(!this.gateway.isNull(), // b -> b.addProperty("gateway", this.gateway.getValue().getHostAddress())) + .onlyIf(!this.metric.isNull(), // + b -> b.addProperty("metric", this.metric.getValue().intValue())) .onlyIf(!this.dns.isNull(), // b -> b.addProperty("dns", this.dns.getValue().getHostAddress())) .onlyIf(this.addresses.isSet(), // b -> { - var arr = JsonUtils.buildJsonArray(); + var arr = buildJsonArray(); for (var address : this.addresses.getValue()) { - arr.add(JsonUtils.buildJsonObject() // + arr.add(buildJsonObject() // .addProperty("label", address.getLabel()) .addProperty("address", address.getInet4Address().getHostAddress()) .addProperty("subnetmask", address.getSubnetmaskAsString()).build()); @@ -271,43 +292,27 @@ public JsonObject toJson() { public boolean updateFrom(NetworkInterface change) { var isChanged = false; if (change.getDhcp().isSet()) { - if (change.getDhcp() == null) { - this.dhcp = ConfigurationProperty.asNotSet(); - } else { - this.dhcp = change.getDhcp(); - } + this.dhcp = change.getDhcp(); isChanged = true; } if (change.getLinkLocalAddressing().isSet()) { - if (change.getLinkLocalAddressing() == null) { - this.linkLocalAddressing = ConfigurationProperty.asNotSet(); - } else { - this.linkLocalAddressing = change.getLinkLocalAddressing(); - } + this.linkLocalAddressing = change.getLinkLocalAddressing(); isChanged = true; } if (change.getGateway().isSet()) { - if (change.getGateway() == null) { - this.gateway = ConfigurationProperty.asNotSet(); - } else { - this.gateway = change.getGateway(); - } + this.gateway = change.getGateway(); + isChanged = true; + } + if (change.getMetric().isSet()) { + this.metric = change.getMetric(); isChanged = true; } if (change.getDns().isSet()) { - if (change.getDns() == null) { - this.dns = ConfigurationProperty.asNotSet(); - } else { - this.dns = change.getDns(); - } + this.dns = change.getDns(); isChanged = true; } if (change.getAddresses().isSet()) { - if (change.getAddresses() == null) { - this.addresses = ConfigurationProperty.asNotSet(); - } else { - this.addresses = change.getAddressesIncludingDefaults(); - } + this.addresses = change.getAddressesIncludingDefaults(); isChanged = true; } return isChanged; diff --git a/io.openems.edge.core/src/io/openems/edge/core/host/OperatingSystemDebianSystemd.java b/io.openems.edge.core/src/io/openems/edge/core/host/OperatingSystemDebianSystemd.java index 5b0765051d2..f74bd442b16 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/host/OperatingSystemDebianSystemd.java +++ b/io.openems.edge.core/src/io/openems/edge/core/host/OperatingSystemDebianSystemd.java @@ -56,9 +56,16 @@ public class OperatingSystemDebianSystemd implements OperatingSystem { private static final String NETWORK_BASE_PATH = "/etc/systemd/network"; private static final Path UDEV_PATH = Paths.get("/etc/udev/rules.d/99-usb-serial.rules"); + private static final int DEFAULT_METRIC = 1024; + private static final String MATCH_SECTION = "[Match]"; + private static final String NETWORK_SECTION = "[Network]"; + private static final String ROUTE_SECTION = "[Route]"; + private static final String DHCP_SECTION = "[DHCP]"; + private static final String ADDRESS_SECTION = "[Address]"; + private static final String EMPTY_SECTION = ""; private static enum Block { - UNDEFINED, MATCH, NETWORK, ADDRESS + UNDEFINED, MATCH, NETWORK, ADDRESS, ROUTE, DHCP } private final HostImpl parent; @@ -195,16 +202,15 @@ private List toFileFormat(User user, NetworkInterface iface) throws O result.add("# changedBy: " // + user.getName()); result.add("# changedAt: " // - + LocalDateTime.now().truncatedTo(ChronoUnit.MINUTES).toString() // - ); - result.add("[Match]"); + + LocalDateTime.now().truncatedTo(ChronoUnit.MINUTES).toString()); + + // Match Section + result.add(MATCH_SECTION); result.add("Name=" + iface.getName()); - result.add(""); + result.add(EMPTY_SECTION); - result.add("[Network]"); - if (iface.getGateway().isSetAndNotNull()) { - result.add("Gateway=" + iface.getGateway().getValue().getHostAddress()); - } + // Network Section + result.add(NETWORK_SECTION); if (iface.getDhcp().isSetAndNotNull()) { result.add("DHCP=" + (iface.getDhcp().getValue() ? "yes" : "no")); } @@ -214,11 +220,31 @@ private List toFileFormat(User user, NetworkInterface iface) throws O if (iface.getLinkLocalAddressing().isSetAndNotNull()) { result.add("LinkLocalAddressing=" + (iface.getLinkLocalAddressing().getValue() ? "yes" : "no")); } + + var metric = DEFAULT_METRIC; + if (iface.getMetric().isSetAndNotNull()) { + metric = iface.getMetric().getValue().intValue(); + } + + if (iface.getDhcp().isSetAndNotNull()) { + var dhcp = iface.getDhcp().getValue(); + result.add(EMPTY_SECTION); + if (dhcp) { // dhcp == yes + result.add(DHCP_SECTION); + result.add("RouteMetric=" + metric); + } else { + result.add(ROUTE_SECTION); + if (iface.getGateway().isSetAndNotNull()) { + result.add("Gateway=" + iface.getGateway().getValue().getHostAddress()); + } + result.add("Metric=" + metric); + } + } if (iface.getAddresses().isSetAndNotNull()) { for (var address : iface.getAddresses().getValue()) { final var label = address.getLabel(); - result.add(""); - result.add("[Address]"); + result.add(EMPTY_SECTION); + result.add(ADDRESS_SECTION); result.add("Address=" + address.toString()); if (!label.isBlank()) { result.add("Label=" + label); @@ -393,6 +419,10 @@ public String getUsbConfiguration() throws OpenemsNamedException { .compile("^Gateway=(" + NetworkConfiguration.PATTERN_INET4ADDRESS + ")$"); private static final Pattern NETWORK_DNS = Pattern // .compile("^DNS=(" + NetworkConfiguration.PATTERN_INET4ADDRESS + ")$"); + private static final Pattern GATEWAY_METRIC = Pattern // + .compile("^Metric=([0-9]+)$"); + private static final Pattern ROUTE_METRIC = Pattern // + .compile("^RouteMetric=([0-9]+)$"); /** * Parses a Systemd-Networkd configuration file. @@ -419,6 +449,8 @@ protected static NetworkInterface parseSystemdNetworkdConfigurationFile(L ConfigurationProperty.asNotSet()); final var gateway = new AtomicReference>(// ConfigurationProperty.asNotSet()); + final var metric = new AtomicReference>(// + ConfigurationProperty.asNotSet()); final var dns = new AtomicReference>(// ConfigurationProperty.asNotSet()); final var addresses = new AtomicReference>>(// @@ -438,16 +470,22 @@ protected static NetworkInterface parseSystemdNetworkdConfigurationFile(L */ if (line.startsWith("[")) { switch (line) { - case "[Match]": + case MATCH_SECTION: currentBlock = Block.MATCH; break; - case "[Network]": + case NETWORK_SECTION: currentBlock = Block.NETWORK; break; - case "[Address]": + case ADDRESS_SECTION: tmpAddress.set(null); currentBlock = Block.ADDRESS; break; + case ROUTE_SECTION: + currentBlock = Block.ROUTE; + break; + case DHCP_SECTION: + currentBlock = Block.DHCP; + break; default: currentBlock = Block.UNDEFINED; break; @@ -486,8 +524,6 @@ protected static NetworkInterface parseSystemdNetworkdConfigurationFile(L addresses.set(ConfigurationProperty.of(addressDetails)); }); break; - case UNDEFINED: - break; case ADDRESS: onMatchString(NETWORK_ADDRESS, line, property -> { // Storing here temporarily so that we can use it if when we find label. @@ -518,11 +554,27 @@ protected static NetworkInterface parseSystemdNetworkdConfigurationFile(L addressDetails.add(address); }); break; + case ROUTE: + onMatchInet4Address(NETWORK_GATEWAY, line, property -> { + gateway.set(ConfigurationProperty.of(property)); + }); + onMatchString(GATEWAY_METRIC, line, property -> { + metric.set(ConfigurationProperty.of(Integer.parseInt(property))); + }); + break; + case DHCP: + onMatchString(ROUTE_METRIC, line, property -> { + metric.set(ConfigurationProperty.of(Integer.parseInt(property))); + }); + break; + case UNDEFINED: + break; default: break; } } return new NetworkInterface<>(name.get(), // - dhcp.get(), linkLocalAddressing.get(), gateway.get(), dns.get(), addresses.get(), attachment); + dhcp.get(), linkLocalAddressing.get(), gateway.get(), dns.get(), addresses.get(), metric.get(), + attachment); } } diff --git a/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/SetNetworkConfigRequest.java b/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/SetNetworkConfigRequest.java index dbd8186d247..fff7cf8ce8c 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/SetNetworkConfigRequest.java +++ b/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/SetNetworkConfigRequest.java @@ -26,6 +26,7 @@ * "dhcp"?: boolean, * "linkLocalAddressing"?: boolean, * "gateway"?: string, + * "metric"?:integer, * "dns"?: string, * "addresses"?: [{ * "label": string, diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/Apps.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/Apps.java index f599054f244..49d88adf37d 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/Apps.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/Apps.java @@ -50,6 +50,7 @@ import io.openems.edge.app.pvselfconsumption.SelfConsumptionOptimization; import io.openems.edge.app.timeofusetariff.AwattarHourly; import io.openems.edge.app.timeofusetariff.EntsoE; +import io.openems.edge.app.timeofusetariff.RabotCharge; import io.openems.edge.app.timeofusetariff.StromdaoCorrently; import io.openems.edge.app.timeofusetariff.Tibber; import io.openems.edge.common.component.ComponentManager; @@ -130,6 +131,16 @@ public static final EntsoE entsoE(AppManagerTestBundle t) { return app(t, EntsoE::new, "App.TimeOfUseTariff.ENTSO-E"); } + /** + * Test method for creating a {@link RabotCharge}. + * + * @param t the {@link AppManagerTestBundle} + * @return the {@link OpenemsApp} instance + */ + public static final RabotCharge rabotCharge(AppManagerTestBundle t) { + return app(t, RabotCharge::new, "App.TimeOfUseTariff.RabotCharge"); + } + /** * Test method for creating a {@link StromdaoCorrently}. * diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/ComponentUtilTest.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/ComponentUtilTest.java index 9f7ca0686de..e490643abad 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/ComponentUtilTest.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/ComponentUtilTest.java @@ -53,15 +53,16 @@ public void testEqualsJsonElementJsonElement() { public void testEqualsListOfNetworkInterface() throws Exception { var expectedInet4Addresses = new HashSet(); expectedInet4Addresses.add(Inet4AddressWithSubnetmask.fromString("foo", "192.168.178.2/24")); - List> expected = Lists.newArrayList(new NetworkInterface("eth0", - ConfigurationProperty.of(false), ConfigurationProperty.of(false), ConfigurationProperty.asNull(), - ConfigurationProperty.asNull(), ConfigurationProperty.of(expectedInet4Addresses), null)); + List> expected = Lists + .newArrayList(new NetworkInterface("eth0", ConfigurationProperty.of(false), + ConfigurationProperty.of(false), ConfigurationProperty.asNull(), ConfigurationProperty.asNull(), + ConfigurationProperty.of(expectedInet4Addresses), ConfigurationProperty.of(145), null)); var actualInet4Addresses = new HashSet(); actualInet4Addresses.add(Inet4AddressWithSubnetmask.fromString("foo", "192.168.178.2/24")); var networkInterface = new NetworkInterface("eth0", ConfigurationProperty.of(false), ConfigurationProperty.of(false), ConfigurationProperty.asNull(), ConfigurationProperty.asNull(), - ConfigurationProperty.of(actualInet4Addresses), null); + ConfigurationProperty.of(actualInet4Addresses), ConfigurationProperty.of(145), null); List> actual = Lists.newArrayList(networkInterface); diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestTranslations.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestTranslations.java index b70a23488fd..e414179bc38 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestTranslations.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestTranslations.java @@ -38,6 +38,9 @@ public void beforeEach() throws Exception { this.apps.add(new TestTranslation(Apps.entsoE(t), true, JsonUtils.buildJsonObject() // .addProperty("BIDDING_ZONE", "GERMANY") // .build())); + this.apps.add(new TestTranslation(Apps.rabotCharge(t), true, JsonUtils.buildJsonObject() // + .addProperty("ACCESS_TOKEN", "123456789") // + .build())); this.apps.add(new TestTranslation(Apps.stromdaoCorrently(t), true, JsonUtils.buildJsonObject() // .addProperty("ZIP_CODE", "123456789") // .build())); diff --git a/io.openems.edge.core/test/io/openems/edge/core/host/OperatingSystemDebianSystemdTest.java b/io.openems.edge.core/test/io/openems/edge/core/host/OperatingSystemDebianSystemdTest.java index 3e3a12f3fb5..e071594e3eb 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/host/OperatingSystemDebianSystemdTest.java +++ b/io.openems.edge.core/test/io/openems/edge/core/host/OperatingSystemDebianSystemdTest.java @@ -1,6 +1,10 @@ package io.openems.edge.core.host; +import static io.openems.common.utils.JsonUtils.prettyToString; +import static io.openems.edge.core.host.OperatingSystemDebianSystemd.parseSystemdNetworkdConfigurationFile; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import java.util.List; @@ -14,7 +18,7 @@ public class OperatingSystemDebianSystemdTest { @Test public void test() throws OpenemsNamedException { - List lines = Lists.newArrayList(// + var lines = Lists.newArrayList(// "[Match]", // "Name=eth0", // "", // @@ -27,17 +31,33 @@ public void test() throws OpenemsNamedException { "Label=normal" // ); - NetworkInterface n = OperatingSystemDebianSystemd.parseSystemdNetworkdConfigurationFile(lines, null); + var n = parseSystemdNetworkdConfigurationFile(lines, null); assertEquals("eth0", n.getName()); assertEquals(true, n.getDhcp().getValue()); assertEquals(true, n.getLinkLocalAddressing().getValue()); assertEquals("192.168.100.100/24", n.getAddresses().getValue().toArray()[0].toString()); + + assertEquals(""" + { + "dhcp": true, + "linkLocalAddressing": true, + "addresses": [ + { + "label": "normal", + "address": "192.168.100.100", + "subnetmask": "255.255.255.0" + } + ] + }""", prettyToString(n.toJson())); + + var json = n.toJson(); + assertEquals(json, NetworkInterface.from("eth0", json).toJson()); } @Test public void testMultipleAddresses() throws OpenemsNamedException { - List lines = Lists.newArrayList(// + var lines = Lists.newArrayList(// "[Match]", // "Name=eth0", // "", // @@ -54,7 +74,7 @@ public void testMultipleAddresses() throws OpenemsNamedException { "Label=" // ); - NetworkInterface n = OperatingSystemDebianSystemd.parseSystemdNetworkdConfigurationFile(lines, null); + var n = parseSystemdNetworkdConfigurationFile(lines, null); assertEquals("eth0", n.getName()); assertEquals(true, n.getDhcp().getValue()); @@ -69,11 +89,14 @@ public void testMultipleAddresses() throws OpenemsNamedException { assertEquals("192.168.123.123/24", address.toString()); assertEquals("", address.getLabel()); } + + var json = n.toJson(); + assertEquals(json, NetworkInterface.from("eth0", json).toJson()); } @Test public void testLabelBefore() throws OpenemsNamedException { - List lines = Lists.newArrayList(// + var lines = Lists.newArrayList(// "[Match]", // "Name=eth0", // "", // @@ -90,7 +113,7 @@ public void testLabelBefore() throws OpenemsNamedException { "Address=192.168.123.123/24" // ); - NetworkInterface n = OperatingSystemDebianSystemd.parseSystemdNetworkdConfigurationFile(lines, null); + var n = parseSystemdNetworkdConfigurationFile(lines, null); { var address = (Inet4AddressWithSubnetmask) n.getAddresses().getValue().toArray()[0]; assertEquals("192.168.100.100/24", address.toString()); @@ -101,6 +124,9 @@ public void testLabelBefore() throws OpenemsNamedException { assertEquals("192.168.123.123/24", address.toString()); assertEquals("", address.getLabel()); // NOTE: if Label is before Address, it is ignored } + + var json = n.toJson(); + assertEquals(json, NetworkInterface.from("eth0", json).toJson()); } @Test @@ -113,10 +139,146 @@ public void test2() throws OpenemsNamedException { "DHCP=yes" // ); - NetworkInterface n = OperatingSystemDebianSystemd.parseSystemdNetworkdConfigurationFile(lines, null); + var n = parseSystemdNetworkdConfigurationFile(lines, null); assertEquals("enx*", n.getName()); assertEquals(true, n.getDhcp().getValue()); + + var json = n.toJson(); + assertEquals(json, NetworkInterface.from("eth0", json).toJson()); } + @Test + public void test3() throws OpenemsNamedException { + var lines = """ + [Match] + Name=eth0 + + [Network] + DHCP=no + LinkLocalAddressing=yes + Address=192.168.100.100/24 + Address=10.4.0.1/24 + + [Route] + Gateway=10.4.0.2 + """.lines().toList(); + + var n = parseSystemdNetworkdConfigurationFile(lines, null); + + assertEquals("eth0", n.getName()); + assertEquals(false, n.getDhcp().getValue()); + assertEquals(true, n.getLinkLocalAddressing().getValue()); + assertEquals("192.168.100.100/24", n.getAddresses().getValue().toArray()[0].toString()); + assertEquals("10.4.0.1/24", n.getAddresses().getValue().toArray()[1].toString()); + + assertEquals("10.4.0.2", n.getGateway().getValue().getHostName()); + assertEquals(null, n.getMetric().getValue()); + + var json = n.toJson(); + assertEquals(json, NetworkInterface.from("eth0", json).toJson()); + } + + @Test + public void test4() throws OpenemsNamedException { + var lines = """ + [Match] + Name=eth0 + + [Network] + DHCP=no + LinkLocalAddressing=yes + Address=192.168.100.100/24 + Address=10.4.0.1/24 + Gateway=10.4.0.2 + """.lines().toList(); + + var n = parseSystemdNetworkdConfigurationFile(lines, null); + + assertEquals("eth0", n.getName()); + assertEquals(false, n.getDhcp().getValue()); + assertEquals(true, n.getLinkLocalAddressing().getValue()); + assertEquals("192.168.100.100/24", n.getAddresses().getValue().toArray()[0].toString()); + assertEquals("10.4.0.1/24", n.getAddresses().getValue().toArray()[1].toString()); + assertEquals("10.4.0.2", n.getGateway().getValue().getHostName()); + + var json = n.toJson(); + assertEquals(json, NetworkInterface.from("eth0", json).toJson()); + } + + @Test + public void test5() throws OpenemsNamedException { + var lines = """ + [Match] + Name=eth0 + + [Network] + DHCP=yes + + [DHCP] + RouteMetric=216 + """.lines().toList(); + + var n = parseSystemdNetworkdConfigurationFile(lines, null); + + assertEquals("eth0", n.getName()); + assertEquals(true, n.getDhcp().getValue()); + assertEquals(216, n.getMetric().getValue().intValue()); + + lines = """ + [Network] + DHCP=no + DNS=10.0.0.1 + LinkLocalAddressing=yes + + [Route] + Gateway=10.0.10.10 + Metric=520 + + [Address] + Address=10.4.0.1/16 + """.lines().toList(); + + n = parseSystemdNetworkdConfigurationFile(lines, null); + + assertEquals(false, n.getDhcp().getValue()); + assertEquals(520, n.getMetric().getValue().intValue()); + + var json = n.toJson(); + assertEquals(json, NetworkInterface.from("eth0", json).toJson()); + } + + @Test + public void testUpdate() throws OpenemsNamedException { + var n1 = parseSystemdNetworkdConfigurationFile(Lists.newArrayList(// + "[Match]", // + "Name=eth0", // + "", // + "[Network]", // + "DHCP=yes", // + "LinkLocalAddressing=yes", // + "", // + "[Address]", // + "Address=192.168.100.100/24", // + "Label=normal" // + ), null); + + assertTrue(n1.getDhcp().getValue()); + + var n2 = parseSystemdNetworkdConfigurationFile(Lists.newArrayList(// + "[Match]", // + "Name=eth0", // + "", // + "[Network]", // + "DHCP=no", // + "LinkLocalAddressing=yes", // + "", // + "[Address]", // + "Address=192.168.100.100/24", // + "Label=normal" // + ), null); + n1.updateFrom(n2); + + assertFalse(n1.getDhcp().getValue()); + } } diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/SolverStrategy.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/SolverStrategy.java index fe3e108b2a2..e6aaf0def57 100644 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/SolverStrategy.java +++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/SolverStrategy.java @@ -9,7 +9,8 @@ public enum SolverStrategy implements OptionsEnum { OPTIMIZE_BY_MOVING_TOWARDS_TARGET(1, "Optimize By Moving Towards Target"), // OPTIMIZE_BY_KEEPING_TARGET_DIRECTION_AND_MAXIMIZING_IN_ORDER(2, "Optimize By Keeping Target Direction And Maximizing In Order"), // - OPTIMIZE_BY_KEEPING_ALL_EQUAL(3, "Optimize By Keeping All Inverters Equal"); // + OPTIMIZE_BY_KEEPING_ALL_EQUAL(3, "Optimize By Keeping All Inverters Equal"), + OPTIMIZE_BY_KEEPING_ALL_NEAR_EQUAL(4, "Optimize By Keeping All Inverters Nearly Equal"); // private final int value; private final String name; diff --git a/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/Solver.java b/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/Solver.java index fa8b435a0ef..2e89950ee29 100644 --- a/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/Solver.java +++ b/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/Solver.java @@ -24,6 +24,7 @@ import io.openems.edge.ess.core.power.data.TargetDirection; import io.openems.edge.ess.core.power.optimizers.AddConstraintsForNotStrictlyDefinedCoefficients; import io.openems.edge.ess.core.power.optimizers.KeepAllEqual; +import io.openems.edge.ess.core.power.optimizers.KeepAllNearEqual; import io.openems.edge.ess.core.power.optimizers.KeepTargetDirectionAndMaximizeInOrder; import io.openems.edge.ess.core.power.optimizers.MoveTowardsTarget; import io.openems.edge.ess.core.power.optimizers.Optimizers; @@ -180,8 +181,10 @@ public void solve(SolverStrategy strategy) { break; case OPTIMIZE_BY_KEEPING_ALL_EQUAL: + case OPTIMIZE_BY_KEEPING_ALL_NEAR_EQUAL: solution = this.tryStrategies(targetDirection, allInverters, targetInverters, allConstraints, - SolverStrategy.OPTIMIZE_BY_KEEPING_ALL_EQUAL, + SolverStrategy.OPTIMIZE_BY_KEEPING_ALL_EQUAL, // + SolverStrategy.OPTIMIZE_BY_KEEPING_ALL_NEAR_EQUAL, // SolverStrategy.OPTIMIZE_BY_KEEPING_TARGET_DIRECTION_AND_MAXIMIZING_IN_ORDER, SolverStrategy.OPTIMIZE_BY_MOVING_TOWARDS_TARGET); break; @@ -257,6 +260,10 @@ private SolveSolution tryStrategies(TargetDirection targetDirection, List esss, + List allInverters, List allConstraints, TargetDirection direction) { + if (esss.isEmpty()) { + return null; + } + + var setActivePower = getPowerSetPoint(esss, allConstraints, direction, Pwr.ACTIVE); + var setReactivePower = getPowerSetPoint(esss, allConstraints, direction, Pwr.REACTIVE); + + if (Double.isNaN(setActivePower) && Double.isNaN(setReactivePower)) { + return null; + } + + var essList = getGenericEssList(esss); + + var activePowerSolved = solvePowerIfNotNaN(setActivePower, essList, Pwr.ACTIVE, direction); + var reactivePowerSolved = solvePowerIfNotNaN(setReactivePower, essList, Pwr.REACTIVE, direction); + + var mergedResult = mergeResults(coefficients, esss, activePowerSolved, reactivePowerSolved); + + var result = Arrays.stream(mergedResult)// + .map(d -> reverseAbsoluteData.apply(d, direction))// + .toArray(); + + return new PointValuePair(result, 0); + } + + /** + * Solve it only if the setpower is present. + * + * @param setPower the Setpower + * @param essList the {@link ManagedSymmetricEss} + * @param powerType the powerType {@link Pwr} + * @param direction the {@link TargetDirection} + * @return a solution + */ + private static PointValuePair solvePowerIfNotNaN(double setPower, List essList, Pwr powerType, + TargetDirection direction) { + if (Double.isNaN(setPower)) { + var defaultResult = new double[essList.size()]; + Arrays.fill(defaultResult, 0.0); + return new PointValuePair(defaultResult, 0); + } else { + return solvePower(setPower, essList, powerType, direction); + } + } + + /** + * Merges results of Active-Power and Reactive-Power to a {@link PointValuePair} + * compatible with default Solver. + * + * @param coefficients the {@link Coefficients} + * @param esss the {@link ManagedSymmetricEss}s + * @param activePower the {@link PointValuePair} for Active-Power + * @param reactivePower the {@link PointValuePair} for Reactive-Power + * @return new {@link PointValuePair} + */ + private static double[] mergeResults(Coefficients coefficients, List esss, + PointValuePair activePower, PointValuePair reactivePower) { + try { + var values = coefficients.getAll().stream() // + .mapToDouble(c -> { + var nonMetaEss = esss.stream() // + .filter(e -> !(e instanceof MetaEss)) // + .map(ManagedSymmetricEss::id) // + .toList(); + var indexOpt = IntStream.range(0, nonMetaEss.size()) // + .filter(i -> nonMetaEss.get(i) == c.getEssId()) // + .findFirst(); + if (indexOpt.isEmpty()) { + return 0; + } + var map = switch (c.getPwr()) { + case ACTIVE -> activePower; + case REACTIVE -> reactivePower; + }; + return map.getPoint()[indexOpt.getAsInt()]; + }).toArray(); + return values; + } catch (Exception e) { + return null; + } + } + + /** + * Solves the power optimization problem for a given set of coefficients, energy + * storage systems (ESSs), inverters, constraints, description, power type, and + * target direction. + * + * @param power the power to be distributed + * @param essList the {@link ManagedSymmetricEss}s + * @param pwr The {@link Pwr}. + * @param direction The {@link TargetDirection}. + * @return The optimized solution The {@link PointValuePair}. + */ + private static PointValuePair solvePower(double power, List essList, Pwr pwr, + TargetDirection direction) { + + var selectedFunction = switch (direction) { + case CHARGE -> getMinPowerFromEss; + case DISCHARGE -> getMaxPowerFromEss; + case KEEP_ZERO -> getZero; + }; + + var essUpperLimit = essList.stream()// + .mapToDouble(ess -> { + return selectedFunction.apply(ess, pwr); + })// + .boxed()// + .toList(); + + var size = essUpperLimit.size(); // omitting the cluster + + var essLowerLimit = essList.stream()// + .mapToDouble(ess -> { + var lowerLimit = selectedFunction.apply(ess, pwr); + return (Math.abs(lowerLimit) >= power / size) ? 0.0 : lowerLimit - (lowerLimit * 0.01); + })// + .boxed()// + .toList(); + + var model = new SolveNearEqual(); + model.setUpperBound(getData(essUpperLimit, direction)); + model.setLowerBound(getData(essLowerLimit, direction)); + model.setpowerSetValue(power); + + try { + return model.solve(size); + } catch (Exception e) { + return null; + } + } + + private static double getPowerSetPoint(List esss, List allConstraints, + TargetDirection direction, Pwr pwr) { + + var clusterEssId = esss.stream()// + .filter(ess -> ess instanceof MetaEss)// + .findFirst().get().id(); + + var noPowerSetPoint = Double.NaN; + + return allConstraints.stream()// + .filter(constraint -> constraint.getRelationship() == Relationship.EQUALS) + .filter(constraint -> constraint.getCoefficients().length == 1) + .filter(constraint -> clusterEssId.equals(constraint.getCoefficients()[0].getCoefficient().getEssId())) + .filter(constraint -> constraint.getCoefficients()[0].getCoefficient().getPwr() == pwr) + .mapToDouble(constraint -> constraint.getValue().get())// + .map(c -> absoluteData.apply(c, direction))// + .findFirst()// + .orElse(noPowerSetPoint); + } + + private static List getGenericEssList(List esss) { + return esss.stream()// + .filter(e -> !(e instanceof MetaEss))// + .toList(); + } + + /** + * Gets data from a list and applies a transformation based on the specified + * target direction. + * + * @param listData The list of Double data. + * @param direction The {@link TargetDirection} + * @return An array of transformed data. + */ + private static double[] getData(List listData, TargetDirection direction) { + return listData.stream()// + .mapToDouble(d -> absoluteData.apply(d, direction))// + .toArray(); + } + + /** + * Function to calculate absolute value or zero based on the + * {@link TargetDirection}. + */ + private static BiFunction absoluteData = (d, direction) -> { + return switch (direction) { + case CHARGE -> Math.abs(d); + case DISCHARGE -> d; + case KEEP_ZERO -> 0.0; + }; + }; + + /** + * Function to calculate reverse absolute value or zero based on the + * {@link TargetDirection}. + */ + private static BiFunction reverseAbsoluteData = (d, direction) -> { + return switch (direction) { + case CHARGE -> -d; + case DISCHARGE -> d; + case KEEP_ZERO -> 0.0; + }; + }; + + /** + * Function to get the maximum power from a {@link ManagedSymmetricEss}. + */ + private static BiFunction getMaxPowerFromEss = (ess, pwr) -> { + return ess.getPower().getMaxPower(ess, Phase.ALL, pwr); + }; + + /** + * Function to get the minimum power from a {@link ManagedSymmetricEss}. + */ + private static BiFunction getMinPowerFromEss = (ess, pwr) -> { + return ess.getPower().getMinPower(ess, Phase.ALL, pwr); + }; + + /** + * Function to return zero. + */ + private static BiFunction getZero = (ess, pwr) -> { + return 0; + }; + +} diff --git a/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/solver/nearequal/ConstraintWrapper.java b/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/solver/nearequal/ConstraintWrapper.java new file mode 100644 index 00000000000..47336a1adb4 --- /dev/null +++ b/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/solver/nearequal/ConstraintWrapper.java @@ -0,0 +1,120 @@ +package io.openems.edge.ess.core.power.solver.nearequal; + +import java.util.Arrays; +import java.util.stream.IntStream; + +import org.apache.commons.math3.analysis.MultivariateFunction; +import org.apache.commons.math3.optim.nonlinear.scalar.MultivariateFunctionPenaltyAdapter; + +public class ConstraintWrapper extends MultivariateFunctionPenaltyAdapter { + + private double[] lower; + private double[] upper; + private double[] point; + private MultivariateFunction function; + private double[] scale; + private double setVal; + private int itteration; + private double refrence; + + public ConstraintWrapper(MultivariateFunction bounded, double[] lower, double[] upper, double offset, + double[] scale, double setVal) { + + super(bounded, lower, upper, offset, scale); + + this.lower = lower; + this.function = bounded; + this.scale = scale; + this.upper = upper; + this.setVal = setVal; + this.refrence = 0; + this.itteration = 0; + } + + /** + * Computes the value of the objective function for a given point in the + * parameter space. + * + * @param point The point in the parameter space for which to evaluate the + * objective function. + * @return The computed value of the objective function. + */ + @Override + public double value(double[] point) { + this.point = point; + var standerDev = this.function.value(this.point); + final double convergence = standerDev - this.refrence; + this.refrence = standerDev; + var sumoffset = this.sumConstraint(point); + this.addOffset(sumoffset); + var constraintoffsetUpper = this.inequalityConstraintUpper(); + var constraintoffsetLower = this.inequalityConstraintLower(); + this.itteration = this.itteration + 1; + return (constraintoffsetUpper + convergence + constraintoffsetLower + Math.abs(sumoffset)); + } + + /** + * Computes the offset from the target value based on the sum of the elements in + * the input array. + * + * @param val An array of values to be summed. + * @return The computed offset from the target value based on the sum of the + * input array. + */ + private double sumConstraint(double[] val) { + double sum = Arrays.stream(val).sum(); + return (sum <= this.setVal || sum >= this.setVal) ? (this.setVal - sum) : 0; + } + + /** + * Computes the offset from the inequality constraints based on the current + * point. + * + * @return The computed offset from the inequality constraints. + */ + private double inequalityConstraintUpper() { + return IntStream.range(0, this.scale.length)// + .filter(i -> this.point[i] > this.upper[i])// + .mapToDouble(i -> { + double overshoot = this.scale[i] * (this.point[i] - this.upper[i]); + this.point[i] = this.upper[i]; + return overshoot; + }).sum(); + } + + /** + * Computes the offset from the inequality constraints based on the current + * point. + * + * @return The computed offset from the inequality constraints. + */ + private double inequalityConstraintLower() { + return IntStream.range(0, this.scale.length)// + .filter(i -> this.point[i] < this.lower[i])// + .mapToDouble(i -> { + double overshoot = this.scale[i] * (this.lower[i] - this.point[i]); + this.point[i] = this.lower[i]; + return overshoot; + }).sum(); + } + + /** + * Adds the specified offset value to each element of the point array. + * + * @param val The offset value to be added to each element of the point array. + */ + private void addOffset(double val) { + + double sum = Arrays.stream(this.upper).sum(); + + if (this.itteration == 0 || sum == 0) { + this.point = Arrays.stream(this.point)// + .map(i -> i + val / this.upper.length)// + .toArray(); + } else { + IntStream.range(0, this.point.length) + .forEach(i -> this.point[i] = this.point[i] + val * this.upper[i] / sum); + } + } + +} diff --git a/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/solver/nearequal/SolveNearEqual.java b/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/solver/nearequal/SolveNearEqual.java new file mode 100644 index 00000000000..093dc19fab8 --- /dev/null +++ b/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/solver/nearequal/SolveNearEqual.java @@ -0,0 +1,121 @@ +package io.openems.edge.ess.core.power.solver.nearequal; + +import java.util.Arrays; + +import org.apache.commons.math3.analysis.MultivariateFunction; +import org.apache.commons.math3.optim.InitialGuess; +import org.apache.commons.math3.optim.MaxEval; +import org.apache.commons.math3.optim.MaxIter; +import org.apache.commons.math3.optim.OptimizationData; +import org.apache.commons.math3.optim.PointValuePair; +import org.apache.commons.math3.optim.nonlinear.scalar.GoalType; +import org.apache.commons.math3.optim.nonlinear.scalar.MultivariateFunctionPenaltyAdapter; +import org.apache.commons.math3.optim.nonlinear.scalar.ObjectiveFunction; +import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.NelderMeadSimplex; +import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.SimplexOptimizer; + +public class SolveNearEqual { + + private double[] upperBound; + private double[] lowerBound; + private double powerSetValue; + + /** + * Solves an optimization problem using the Nelder-Mead simplex algorithm. + * + * @param totalVariables The total number of variables in the optimization + * problem. + * @return An array containing the optimal solution for the optimization + * problem. + */ + public PointValuePair solve(int totalVariables) { + + // If the SetPower is greater than Sum of inidividual upper bound, then return + // the upper bound + if (this.powerSetValue > Arrays.stream(this.upperBound).sum()) { + return new PointValuePair(this.upperBound, 0.0); + } + + MultivariateFunctionPenaltyAdapter adapter = new ConstraintWrapper(this.objectiveFunction(), // + this.lowerBound, // expected lower limit of the result + this.upperBound, // expected upper limit of the result + 0.0, // offset value + this.getScaleVal(1, totalVariables), // + this.powerSetValue); + + OptimizationData[] optimizationData = { new ObjectiveFunction(adapter), // + this.setInitialValue(0, totalVariables), // + new NelderMeadSimplex(totalVariables), // + new MaxIter(10000), // + new MaxEval(10000), // + GoalType.MINIMIZE }; + SimplexOptimizer solver = new SimplexOptimizer(1e-11, 1e-11); + return solver.optimize(optimizationData); + } + + /** + * Creates an objective function that calculates the standard deviation of a + * given set of points. + * + * @return The objective function that computes the standard deviation. + */ + private MultivariateFunction objectiveFunction() { + MultivariateFunction objective = new MultivariateFunction() { + + @Override + public double value(double[] point) { + double mean = Arrays.stream(point).sum() / point.length; + // Standard deviation + return Math.sqrt(// + Arrays.stream((Arrays.stream(point)// + .map(i -> Math.pow(i - mean, 2))// + .toArray()))// + .sum() / point.length); + } + }; + return objective; + } + + /** + * Sets up the initial guess for the optimization problem. + * + * @param value The initial value to set for each variable. + * @param totalVariables The total number of variables in the optimization + * problem. + * @return An InitialGuess object representing the initial guess for the + * optimization. + */ + + private InitialGuess setInitialValue(double value, int totalVariables) { + double[] intialValArray = new double[totalVariables]; + Arrays.fill(intialValArray, value); + return new InitialGuess(intialValArray); + } + + /** + * Generates an array of scale values with the specified scale value for each + * variable. + * + * @param scaleVal The value to set for each scale element. + * @param totalVariables The total number of variables for which scale values + * are generated. + * @return An array containing the specified scale value for each variable. + */ + private double[] getScaleVal(double scaleVal, int totalVariables) { + double[] scaleValArray = new double[totalVariables]; + Arrays.fill(scaleValArray, scaleVal); + return scaleValArray; + } + + public void setUpperBound(double[] val) { + this.upperBound = val; + } + + public void setLowerBound(double[] val) { + this.lowerBound = val; + } + + public void setpowerSetValue(double val) { + this.powerSetValue = val; + } +} diff --git a/io.openems.edge.ess.core/test/io/openems/edge/ess/core/power/NearEqualSolverTest.java b/io.openems.edge.ess.core/test/io/openems/edge/ess/core/power/NearEqualSolverTest.java new file mode 100644 index 00000000000..9766ada10cf --- /dev/null +++ b/io.openems.edge.ess.core/test/io/openems/edge/ess/core/power/NearEqualSolverTest.java @@ -0,0 +1,25 @@ +package io.openems.edge.ess.core.power; + +import org.junit.Test; + +import io.openems.edge.ess.core.power.solver.nearequal.SolveNearEqual; + +public class NearEqualSolverTest { + + @Test + public void solverTest() { + + double[] essUpperLimit = { 10000, 10000, 10000, 1900 }; + double[] essLowerLimit = { 0, 0, 0, 1800 }; + double setValue = 50000; + var model = new SolveNearEqual(); + model.setUpperBound(essUpperLimit); + model.setLowerBound(essLowerLimit); + model.setpowerSetValue(setValue); + var result = model.solve(4).getPoint(); + for (int i = 0; i < result.length; i++) { + System.out.println(result[i]); + } + } + +} diff --git a/io.openems.edge.ess.core/test/io/openems/edge/ess/core/power/PowerComponentTest.java b/io.openems.edge.ess.core/test/io/openems/edge/ess/core/power/PowerComponentTest.java index 20bacf1ee03..75baf32bbc0 100644 --- a/io.openems.edge.ess.core/test/io/openems/edge/ess/core/power/PowerComponentTest.java +++ b/io.openems.edge.ess.core/test/io/openems/edge/ess/core/power/PowerComponentTest.java @@ -524,6 +524,125 @@ public void testMultilayerCluster() throws Exception { componentTest.next(new TestCase("#1")); } + /** + * Testing near equals strategy. + * + * @throws Exception on exception + */ + // @Test + public void testNearEqualDistribution() throws Exception { + EssPower powerComponent = new EssPowerImpl(); + + var ess1 = new DummyManagedSymmetricEss("ess1") // + .setPower(powerComponent) // + .withAllowedChargePower(-12000) // + .withAllowedDischargePower(12000) // + .withMaxApparentPower(10000) // + .withSoc(60); + var ess2 = new DummyManagedSymmetricEss("ess2") // + .setPower(powerComponent) // + .withAllowedChargePower(-12000) // + .withAllowedDischargePower(12000) // + .withMaxApparentPower(10000) // + .withSoc(60); + var ess3 = new DummyManagedSymmetricEss("ess3") // + .setPower(powerComponent) // + .withAllowedChargePower(-12000) // + .withAllowedDischargePower(12000) // + .withMaxApparentPower(10000) // + .withSoc(30); + var ess4 = new DummyManagedSymmetricEss("ess4") // + .setPower(powerComponent) // + .withAllowedChargePower(-12000) // + .withAllowedDischargePower(12000) // + .withMaxApparentPower(10000) // + .withSoc(60); + var ess0 = new DummyMetaEss("ess0", ess1, ess2, ess3, ess4) // + .setPower(powerComponent); + + final var cm = new DummyConfigurationAdmin(); + cm.getOrCreateEmptyConfiguration(EssPower.SINGLETON_SERVICE_PID); + + final var componentTest = new ComponentTest(powerComponent) // + .addReference("cm", cm) // + .addReference("addEss", ess0) // + .addReference("addEss", ess1) // + .addReference("addEss", ess2) // + .addReference("addEss", ess3) // + .addReference("addEss", ess4) // + .activate(MyConfig.create() // + .setStrategy(SolverStrategy.OPTIMIZE_BY_KEEPING_ALL_EQUAL) // + .setSymmetricMode(true) // + .setDebugMode(false) // + .setEnablePid(false) // + .build()); // + + // #1 Discharging + expect("#1.1", ess1, 2500, 0); + expect("#1.2", ess2, 2500, 0); + expect("#1.3", ess3, 2500, 0); + expect("#1.4", ess4, 2500, 0); + + ess0.addPowerConstraint("SetActivePowerEquals", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, 10000); + ess0.setActivePowerEquals(10000); + componentTest.next(new TestCase("#1")); + + // #2 Charging + expect("#2.1", ess1, -2500, 0); + expect("#2.2", ess2, -2500, 0); + expect("#2.3", ess3, -2500, 0); + expect("#2.4", ess4, -2500, 0); + + ess0.addPowerConstraint("SetActivePowerEquals", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, -10000); + ess0.setActivePowerEquals(10000); + componentTest.next(new TestCase("#1")); + + // #3 Discharging with lower allowed discharge power + ess4.withAllowedDischargePower(1900); + + // Should be + expect("#3.1", ess1, 2701, 0); + expect("#3.2", ess2, 2701, 0); + expect("#3.3", ess3, 2701, 0); + expect("#3.4", ess4, 1897, 0); + + ess0.addPowerConstraint("SetActivePowerEquals", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, 10000); + componentTest.next(new TestCase("#3")); + + // #4 charging with lower allowed ccharge power + ess4.withAllowedDischargePower(12000); + ess4.withAllowedChargePower(-1900); + + expect("#4.1", ess1, -9899, 0); + expect("#4.2", ess2, -9899, 0); + expect("#4.3", ess3, -9900, 0); + expect("#4.4", ess4, -1881, 0); + + ess0.addPowerConstraint("SetActivePowerEquals", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, -10000); + componentTest.next(new TestCase("#4")); + + // #5 keeping zero + expect("#5.1", ess1, 0, 0); + expect("#5.2", ess2, 0, 0); + expect("#5.3", ess3, 0, 0); + expect("#5.4", ess4, 0, 0); + + ess0.addPowerConstraint("SetActivePowerEquals", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, 0); + componentTest.next(new TestCase("#5")); + + ess4.withAllowedChargePower(1000); + + // #6 keeping zero + expect("#5.1", ess1, 0, 0); + expect("#5.2", ess2, 0, 0); + expect("#5.3", ess3, 0, 0); + expect("#5.4", ess4, 0, 0); + + ess0.addPowerConstraint("SetActivePowerEquals", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, 0); + componentTest.next(new TestCase("#5")); + + } + private static void expect(String description, DummyManagedSymmetricEss ess, int p, int q) { openCallbacks.incrementAndGet(); ess.withSymmetricApplyPowerCallback(record -> { diff --git a/io.openems.edge.ess.core/test/io/openems/edge/ess/core/power/PowerComponentTest2.java b/io.openems.edge.ess.core/test/io/openems/edge/ess/core/power/PowerComponentTest2.java new file mode 100644 index 00000000000..7060c6e7393 --- /dev/null +++ b/io.openems.edge.ess.core/test/io/openems/edge/ess/core/power/PowerComponentTest2.java @@ -0,0 +1,205 @@ +package io.openems.edge.ess.core.power; + +import static org.junit.Assert.assertEquals; + +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import io.openems.edge.common.test.AbstractComponentTest.TestCase; +import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.common.test.DummyConfigurationAdmin; +import io.openems.edge.ess.power.api.Phase; +import io.openems.edge.ess.power.api.Pwr; +import io.openems.edge.ess.power.api.Relationship; +import io.openems.edge.ess.power.api.SolverStrategy; +import io.openems.edge.ess.test.DummyManagedSymmetricEss; +import io.openems.edge.ess.test.DummyMetaEss; + +public class PowerComponentTest2 { + + private static AtomicInteger openCallbacks; + + @Before + public void before() { + openCallbacks = new AtomicInteger(0); + } + + @After + public void after() { + assertEquals("Not all Callbacks were actually called", 0, openCallbacks.get()); + } + + @Test + public void testOnlyOneEssDistribution() throws Exception { + EssPower powerComponent = new EssPowerImpl(); + + var ess1 = new DummyManagedSymmetricEss("ess1") // + .setPower(powerComponent) // + .withAllowedChargePower(-12000) // + .withAllowedDischargePower(12000) // + .withMaxApparentPower(10000) // + .withSoc(60); + + var ess0 = new DummyMetaEss("ess0", ess1) // + .setPower(powerComponent); + + final var cm = new DummyConfigurationAdmin(); + cm.getOrCreateEmptyConfiguration(EssPower.SINGLETON_SERVICE_PID); + + final var componentTest = new ComponentTest(powerComponent) // + .addReference("cm", cm) // + .addReference("addEss", ess0) // + .addReference("addEss", ess1) // + + .activate(MyConfig.create() // + .setStrategy(SolverStrategy.OPTIMIZE_BY_KEEPING_ALL_EQUAL) // + .setSymmetricMode(true) // + .setDebugMode(false) // + .setEnablePid(false) // + .build()); // + + expect("#1.1", ess1, 10000, 0); + + ess0.setActivePowerEquals(10000); + componentTest.next(new TestCase("#1")); + + expect("#2.1", ess1, 10000, 0); + + ess0.setActivePowerEquals(12000); + componentTest.next(new TestCase("#2")); + + } + + /** + * Testing near equals strategy. + * + * @throws Exception on exception + */ + @Test + public void testNearEqualDistribution() throws Exception { + EssPower powerComponent = new EssPowerImpl(); + + var ess1 = new DummyManagedSymmetricEss("ess1") // + .setPower(powerComponent) // + .withAllowedChargePower(-12000) // + .withAllowedDischargePower(12000) // + .withMaxApparentPower(10000) // + .withSoc(60); + var ess2 = new DummyManagedSymmetricEss("ess2") // + .setPower(powerComponent) // + .withAllowedChargePower(-12000) // + .withAllowedDischargePower(12000) // + .withMaxApparentPower(10000) // + .withSoc(60); + var ess3 = new DummyManagedSymmetricEss("ess3") // + .setPower(powerComponent) // + .withAllowedChargePower(-12000) // + .withAllowedDischargePower(12000) // + .withMaxApparentPower(10000) // + .withSoc(30); + var ess4 = new DummyManagedSymmetricEss("ess4") // + .setPower(powerComponent) // + .withAllowedChargePower(-12000) // + .withAllowedDischargePower(12000) // + .withMaxApparentPower(10000) // + .withSoc(60); + var ess0 = new DummyMetaEss("ess0", ess1, ess2, ess3, ess4) // + .setPower(powerComponent); + + final var cm = new DummyConfigurationAdmin(); + cm.getOrCreateEmptyConfiguration(EssPower.SINGLETON_SERVICE_PID); + + final var componentTest = new ComponentTest(powerComponent) // + .addReference("cm", cm) // + .addReference("addEss", ess0) // + .addReference("addEss", ess1) // + .addReference("addEss", ess2) // + .addReference("addEss", ess3) // + .addReference("addEss", ess4) // + .activate(MyConfig.create() // + .setStrategy(SolverStrategy.OPTIMIZE_BY_KEEPING_ALL_EQUAL) // + .setSymmetricMode(true) // + .setDebugMode(false) // + .setEnablePid(false) // + .build()); // + + // #1 Discharging + expect("#1.1", ess1, 2500, 0); + expect("#1.2", ess2, 2500, 0); + expect("#1.3", ess3, 2500, 0); + expect("#1.4", ess4, 2500, 0); + + ess0.addPowerConstraint("SetActivePowerEquals1", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, 10000); + ess0.setActivePowerEquals(10000); + componentTest.next(new TestCase("#1")); + + // #2 Charging + expect("#2.1", ess1, -2500, 0); + expect("#2.2", ess2, -2500, 0); + expect("#2.3", ess3, -2500, 0); + expect("#2.4", ess4, -2500, 0); + + ess0.addPowerConstraint("SetActivePowerEquals2", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, -10000); + ess0.setActivePowerEquals(10000); + componentTest.next(new TestCase("#1")); + + // #3 Discharging with lower allowed discharge power + ess4.withAllowedDischargePower(1900); + + // Should be + expect("#3.1", ess1, 2701, 0); + expect("#3.2", ess2, 2701, 0); + expect("#3.3", ess3, 2701, 0); + expect("#3.4", ess4, 1897, 0); + + ess0.addPowerConstraint("SetActivePowerEquals3", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, 10000); + componentTest.next(new TestCase("#3")); + + // #4 charging with lower allowed charge power + ess4.withAllowedDischargePower(12000); + ess4.withAllowedChargePower(-1900); + + expect("#4.1", ess1, -2700, 0); + expect("#4.2", ess2, -2700, 0); + expect("#4.3", ess3, -2703, 0); + expect("#4.4", ess4, -1896, 0); + + ess0.addPowerConstraint("SetActivePowerEquals4", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, -10000); + componentTest.next(new TestCase("#4")); + + // #5 keeping zero + expect("#5.1", ess1, 0, 0); + expect("#5.2", ess2, 0, 0); + expect("#5.3", ess3, 0, 0); + expect("#5.4", ess4, 0, 0); + + ess0.addPowerConstraint("SetActivePowerEquals5", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, 0); + componentTest.next(new TestCase("#5")); + + ess4.withAllowedChargePower(1000); + + // #6 keeping zero + expect("#5.1", ess1, 0, 0); + expect("#5.2", ess2, 0, 0); + expect("#5.3", ess3, 0, 0); + expect("#5.4", ess4, 0, 0); + + ess0.addPowerConstraint("ctrl0", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, 0); + componentTest.next(new TestCase("#5")); + + } + + private static void expect(String description, DummyManagedSymmetricEss ess, int p, int q) { + openCallbacks.incrementAndGet(); + ess.withSymmetricApplyPowerCallback(record -> { + openCallbacks.decrementAndGet(); + // System.out.println(description + " for " + ess.id() + ": " + activePower); + assertEquals(description + " for " + ess.id(), p, record.activePower()); + assertEquals(description + " for " + ess.id(), q, record.reactivePower()); + }); + } + +} diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/AbstractAllowedChargeDischargeHandler.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/AbstractAllowedChargeDischargeHandler.java index 9a096506d43..3cc01152259 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/AbstractAllowedChargeDischargeHandler.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/AbstractAllowedChargeDischargeHandler.java @@ -1,22 +1,36 @@ package io.openems.edge.ess.generic.common; +import static io.openems.edge.common.type.TypeUtils.multiply; +import static io.openems.edge.common.type.TypeUtils.subtract; +import static java.lang.Math.abs; +import static java.lang.Math.max; +import static java.lang.Math.min; +import static java.lang.Math.round; + import java.time.Duration; import java.time.Instant; -import java.util.function.BiConsumer; +import java.util.function.BiFunction; + +import org.apache.logging.log4j.util.TriConsumer; import io.openems.edge.battery.api.Battery; +import io.openems.edge.batteryinverter.api.SymmetricBatteryInverter; +import io.openems.edge.common.channel.value.Value; import io.openems.edge.common.component.ClockProvider; +import io.openems.edge.common.filter.Pt1filter; import io.openems.edge.common.startstop.StartStoppable; +import io.openems.edge.common.type.TypeUtils; import io.openems.edge.ess.api.SymmetricEss; import io.openems.edge.ess.generic.symmetric.ChannelManager; +import io.openems.edge.ess.generic.symmetric.EssProtection; /** * Helper class to handle calculation of Allowed-Charge-Power and * Allowed-Discharge-Power. This class is used by {@link ChannelManager} as a * callback to updates of Battery Channels. */ -public abstract class AbstractAllowedChargeDischargeHandler - implements BiConsumer { +public abstract class AbstractAllowedChargeDischargeHandler + implements TriConsumer { public static final float DISCHARGE_EFFICIENCY_FACTOR = 0.95F; @@ -28,18 +42,31 @@ public abstract class AbstractAllowedChargeDischargeHandler AC Power) charge = chargeMaxCurrent * voltage; - discharge = Math.round(dischargeMaxCurrent * voltage * DISCHARGE_EFFICIENCY_FACTOR); + discharge = round(dischargeMaxCurrent * voltage * DISCHARGE_EFFICIENCY_FACTOR); } /* @@ -113,13 +154,13 @@ protected void calculateAllowedChargeDischargePower(ClockProvider clockProvider, // Force Charge is active // Make sure AllowedChargePower is greater-or-equals absolute // AllowedDischargePower - charge = Math.max(charge, Math.abs(discharge)); + charge = max(charge, abs(discharge)); } else if (charge < 0) { // Force Discharge is active // Make sure AllowedDischargePower is greater-or-equals absolute // AllowedChargePower - discharge = Math.max(Math.abs(charge), discharge); + discharge = max(abs(charge), discharge); } /* @@ -140,6 +181,45 @@ protected void calculateAllowedChargeDischargePower(ClockProvider clockProvider, this.lastBatteryAllowedDischargePower = discharge; } + private void checkEssProtectionExtremes(ClockProvider clockProvider, Integer chargeMaxCurrent, + Integer dischargeMaxCurrent, Value current) { + if (!(this.parent instanceof EssProtection ess)) { + return; + } + + if (dischargeMaxCurrent == null || chargeMaxCurrent == null || !current.isDefined()) { + return; + } + + if (dischargeMaxCurrent >= 0 || chargeMaxCurrent >= 0) { + this.onEntryEssProtection = null; + ess._setEpDeepDischargeProtection(false); + ess._setEpOverChargeProtection(false); + return; + } + + if (this.onEntryEssProtection == null) { + this.onEntryEssProtection = Instant.now(clockProvider.getClock()); + } + + if (dischargeMaxCurrent < 0// + && current.get() >= 0// + && this.isExtremeTimeoutPassed()) { + ess._setEpDeepDischargeProtection(true); + } + + if (chargeMaxCurrent < 0 // + && current.get() <= 0 // + && this.isExtremeTimeoutPassed()) { + ess._setEpOverChargeProtection(true); + } + } + + private boolean isExtremeTimeoutPassed() { + return Duration.between(this.onEntryEssProtection, Instant.now()) + .getSeconds() > ESS_PROTECTION_EXTREME_LIMIT_TIMEOUT; + } + /** * Applies the max increase ramp, built from MAX_INCREASE_PERCENTAGE. * @@ -158,7 +238,71 @@ private static float applyMaxIncrease(float lastValue, float thisValue, Instant } else { millis = Duration.between(lastInstant, thisInstant).toMillis(); } - return Math.min(thisValue, // + return min(thisValue, // lastValue + thisValue * millis * MAX_INCREASE_PERCENTAGE / 1000.F /* convert [mW] to [W] */); } + + private record RegulationValues(// + boolean isBatteryStarted, // + Value voltage, // + Value current, // + Value chargeMaxVoltage, // + Value dischargeMinVoltage, // + Value innerResistance, // + Value inverterDcMinVoltage, // + Value inverterDcMaxVoltage) { + public RegulationValues(Battery battery, SymmetricBatteryInverter inverter) { + this(// + battery.isStarted(), // + battery.getVoltage(), // + battery.getCurrent(), // + battery.getChargeMaxVoltage(), // + battery.getDischargeMinVoltage(), // + battery.getInnerResistance(), // + inverter.getDcMinVoltage(), // + inverter.getDcMaxVoltage()); + } + } + + private static boolean areRegulationValuesDefined(RegulationValues regulationValues) { + return regulationValues.isBatteryStarted()// + && regulationValues.voltage.isDefined()// + && regulationValues.current.isDefined() // + && regulationValues.chargeMaxVoltage.isDefined()// + && regulationValues.dischargeMinVoltage.isDefined()// + && regulationValues.innerResistance.isDefined()// + && regulationValues.inverterDcMinVoltage.isDefined()// + && regulationValues.inverterDcMaxVoltage.isDefined();// + } + + private static Integer calculateMaxCurrent(Battery battery, SymmetricBatteryInverter inverter, int cycleTime, + Pt1filter pt1Filter, BiFunction dcLimit, + BiFunction voltageOffset, BiFunction typeUtilsMethod, + boolean invert) { + var regulationValues = new RegulationValues(battery, inverter); + if (!areRegulationValuesDefined(regulationValues)) { + return null; + } + + final var batteryLimit = invert// + ? regulationValues.chargeMaxVoltage.get() + : regulationValues.dischargeMinVoltage.get(); + final var inverterLimit = invert // + ? regulationValues.inverterDcMaxVoltage.get() + : regulationValues.inverterDcMinVoltage.get(); + final var limitVoltage = dcLimit.apply(// + voltageOffset.apply(// + batteryLimit, // + VOLTAGE_CONTROL_OFFSET), + inverterLimit); + + var subtractLimit = subtract(regulationValues.voltage.get(), limitVoltage); + var voltageDifference = invert ? multiply(subtractLimit, -1) : subtractLimit; + + var resistance = regulationValues.innerResistance.get() / 1000.; + final var deltaChargeCurrent = voltageDifference / resistance; + var maxCurrentVoltLimit = typeUtilsMethod.apply(deltaChargeCurrent, (double) regulationValues.current.get()); + pt1Filter.setCycleTime(cycleTime); + return pt1Filter.applyPt1Filter(max(maxCurrentVoltLimit, -5.0)); + } } \ No newline at end of file diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/AbstractChannelManager.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/AbstractChannelManager.java index 73ae18df225..af85ef0b031 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/AbstractChannelManager.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/AbstractChannelManager.java @@ -18,7 +18,7 @@ * calculating the Ess-Channels based on the Channels of the Battery and * Battery-Inverter. Takes care of registering and unregistering listeners. */ -public class AbstractChannelManager +public class AbstractChannelManager extends AbstractChannelListenerManager { private final ESS parent; @@ -33,15 +33,14 @@ public AbstractChannelManager(ESS parent, /** * Called on Component activate(). * - * @param clockProvider the {@link ClockProvider} - * @param battery the {@link Battery} - * @param batteryInverter the {@link ManagedSymmetricBatteryInverter} + * @param clockProvider the {@link ClockProvider} + * @param battery the {@link Battery} + * @param inverter the {@link ManagedSymmetricBatteryInverter} */ - public void activate(ClockProvider clockProvider, Battery battery, - ManagedSymmetricBatteryInverter batteryInverter) { - this.addBatteryListener(clockProvider, battery); - this.addBatteryInverterListener(batteryInverter); - this.addEssListener(clockProvider, battery); + public void activate(ClockProvider clockProvider, Battery battery, ManagedSymmetricBatteryInverter inverter) { + this.addBatteryListener(clockProvider, battery, inverter); + this.addBatteryInverterListener(inverter); + this.addEssListener(clockProvider, battery, inverter); } private void addBatteryInverterListener(ManagedSymmetricBatteryInverter batteryInverter) { @@ -91,18 +90,18 @@ private void addBatteryInverterListener(ManagedSymmetricBatteryInverter batteryI } } - private void addBatteryListener(ClockProvider clockProvider, Battery battery) { + private void addBatteryListener(ClockProvider clockProvider, Battery battery, SymmetricBatteryInverter inverter) { /* * Battery */ this.addOnSetNextValueListener(battery, Battery.ChannelId.DISCHARGE_MIN_VOLTAGE, - ignored -> this.allowedChargeDischargeHandler.accept(clockProvider, battery)); + ignored -> this.allowedChargeDischargeHandler.accept(clockProvider, battery, inverter)); this.addOnSetNextValueListener(battery, Battery.ChannelId.DISCHARGE_MAX_CURRENT, - ignored -> this.allowedChargeDischargeHandler.accept(clockProvider, battery)); + ignored -> this.allowedChargeDischargeHandler.accept(clockProvider, battery, inverter)); this.addOnSetNextValueListener(battery, Battery.ChannelId.CHARGE_MAX_VOLTAGE, - ignored -> this.allowedChargeDischargeHandler.accept(clockProvider, battery)); + ignored -> this.allowedChargeDischargeHandler.accept(clockProvider, battery, inverter)); this.addOnSetNextValueListener(battery, Battery.ChannelId.CHARGE_MAX_CURRENT, - ignored -> this.allowedChargeDischargeHandler.accept(clockProvider, battery)); + ignored -> this.allowedChargeDischargeHandler.accept(clockProvider, battery, inverter)); this.addCopyListener(battery, // Battery.ChannelId.CAPACITY, // SymmetricEss.ChannelId.CAPACITY); @@ -111,13 +110,13 @@ private void addBatteryListener(ClockProvider clockProvider, Battery battery) { SymmetricEss.ChannelId.SOC); } - private void addEssListener(ClockProvider clockProvider, Battery battery) { + private void addEssListener(ClockProvider clockProvider, Battery battery, SymmetricBatteryInverter inverter) { /* * ESS / Parent */ if (this.parent instanceof StartStoppable) { - this.addOnChangeListener(this.parent, StartStoppable.ChannelId.START_STOP, - (ignored0, ignored1) -> this.allowedChargeDischargeHandler.accept(clockProvider, battery)); + this.addOnChangeListener(this.parent, StartStoppable.ChannelId.START_STOP, (ignored0, + ignored1) -> this.allowedChargeDischargeHandler.accept(clockProvider, battery, inverter)); } } @@ -137,4 +136,5 @@ protected void addCopyListener(OpenemsComponent sourceComponent, ChannelId s targetChannel.setNextValue(value); }); } + } 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 82907b6db2e..8f8c44bf659 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 @@ -39,7 +39,7 @@ * Parent class for different implementations of Managed Energy Storage Systems, * consisting of a Battery-Inverter component and a Battery component. */ -public abstract class AbstractGenericManagedEss +public abstract class AbstractGenericManagedEss extends AbstractOpenemsComponent implements GenericManagedEss, ManagedSymmetricEss, HybridEss, SymmetricEss, OpenemsComponent, EventHandler, StartStoppable, ModbusSlave { diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/CycleProvider.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/CycleProvider.java new file mode 100644 index 00000000000..4a9a8e92e44 --- /dev/null +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/CycleProvider.java @@ -0,0 +1,11 @@ +package io.openems.edge.ess.generic.common; + +public interface CycleProvider { + + /** + * Gets the duration of one global OpenEMS Cycle in [ms]. + * + * @return the duration in milliseconds + */ + public int getCycleTime(); +} 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 c455f7271a5..3cd2ffd64ef 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 @@ -1,5 +1,11 @@ package io.openems.edge.ess.generic.offgrid; +import static io.openems.edge.common.cycle.Cycle.DEFAULT_CYCLE_TIME; +import static io.openems.edge.common.sum.GridMode.OFF_GRID; +import static io.openems.edge.ess.generic.offgrid.statemachine.StateMachine.OffGridState.GRID_SWITCH; +import static io.openems.edge.ess.generic.offgrid.statemachine.StateMachine.OffGridState.STOP_BATTERY_INVERTER; +import static io.openems.edge.ess.generic.offgrid.statemachine.StateMachine.OffGridState.UNDEFINED; + import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; @@ -26,6 +32,7 @@ import io.openems.edge.batteryinverter.api.OffGridBatteryInverter; import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.cycle.Cycle; import io.openems.edge.common.event.EdgeEventConstants; import io.openems.edge.common.modbusslave.ModbusSlave; import io.openems.edge.common.modbusslave.ModbusSlaveTable; @@ -36,10 +43,10 @@ import io.openems.edge.ess.api.ManagedSymmetricEss; import io.openems.edge.ess.api.SymmetricEss; import io.openems.edge.ess.generic.common.AbstractGenericManagedEss; +import io.openems.edge.ess.generic.common.CycleProvider; import io.openems.edge.ess.generic.common.GenericManagedEss; import io.openems.edge.ess.generic.offgrid.statemachine.Context; import io.openems.edge.ess.generic.offgrid.statemachine.StateMachine; -import io.openems.edge.ess.generic.offgrid.statemachine.StateMachine.OffGridState; import io.openems.edge.ess.generic.symmetric.ChannelManager; import io.openems.edge.ess.generic.symmetric.EssGenericManagedSymmetric; import io.openems.edge.ess.offgrid.api.OffGridEss; @@ -58,15 +65,18 @@ public class EssGenericOffGridImpl extends AbstractGenericManagedEss implements EssGenericManagedSymmetric, OffGridEss, GenericManagedEss, ManagedSymmetricEss, SymmetricEss, - OpenemsComponent, EventHandler, StartStoppable, ModbusSlave { + OpenemsComponent, EventHandler, StartStoppable, ModbusSlave, CycleProvider { private final Logger log = LoggerFactory.getLogger(EssGenericOffGridImpl.class); - private final StateMachine stateMachine = new StateMachine(OffGridState.UNDEFINED); + private final StateMachine stateMachine = new StateMachine(UNDEFINED); private final ChannelManager channelManager = new ChannelManager(this); private final AtomicBoolean fromOffToOnGrid = new AtomicBoolean(false); private final AtomicReference targetGridMode = new AtomicReference<>(TargetGridMode.GO_ON_GRID); private final AtomicBoolean targetDeepDischarge = new AtomicBoolean(); + @Reference + private Cycle cycle; + @Reference private Power power; @@ -189,7 +199,7 @@ public Power getPower() { public void setStartStop(StartStop value) { if (this.startStopTarget.getAndSet(value) != value) { // Set only if value changed - this.stateMachine.forceNextState(OffGridState.UNDEFINED); + this.stateMachine.forceNextState(UNDEFINED); } } @@ -210,7 +220,7 @@ public void setTargetGridMode(TargetGridMode targetGridMode) { if (oldTargetGridMode == TargetGridMode.GO_OFF_GRID) { this.fromOffToOnGrid.set(true); } - this.stateMachine.forceNextState(OffGridState.GRID_SWITCH); + this.stateMachine.forceNextState(GRID_SWITCH); } /** @@ -234,7 +244,7 @@ private void requestGridOperationChange() { private void setTargetDeepDischarge(boolean value) { if (this.targetDeepDischarge.getAndSet(value) != value) { - this.stateMachine.forceNextState(OffGridState.STOP_BATTERY_INVERTER); + this.stateMachine.forceNextState(STOP_BATTERY_INVERTER); } } @@ -245,10 +255,15 @@ private void avoidBatteryDeepDischarge() { this.getAllowedDischargePowerChannel().onSetNextValue(allowedDischargePowerValue -> { var allowedDischargePower = allowedDischargePowerValue.orElse(0); var gridMode = this.offGridSwitch.getGridMode(); - if (allowedDischargePower > 0 || gridMode != GridMode.OFF_GRID) { + if (allowedDischargePower > 0 || gridMode != OFF_GRID) { return; } this.setTargetDeepDischarge(true); }); } + + @Override + public int getCycleTime() { + return this.cycle != null ? this.cycle.getCycleTime() : DEFAULT_CYCLE_TIME; + } } diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/AllowedChargeDischargeHandler.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/AllowedChargeDischargeHandler.java index 5ccb200a6c5..b789c52b717 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/AllowedChargeDischargeHandler.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/AllowedChargeDischargeHandler.java @@ -1,6 +1,7 @@ package io.openems.edge.ess.generic.symmetric; import io.openems.edge.battery.api.Battery; +import io.openems.edge.batteryinverter.api.SymmetricBatteryInverter; import io.openems.edge.common.component.ClockProvider; import io.openems.edge.common.type.TypeUtils; import io.openems.edge.ess.generic.common.AbstractAllowedChargeDischargeHandler; @@ -12,8 +13,8 @@ public AllowedChargeDischargeHandler(EssGenericManagedSymmetric parent) { } @Override - public void accept(ClockProvider clockProvider, Battery battery) { - this.calculateAllowedChargeDischargePower(clockProvider, battery); + public void accept(ClockProvider clockProvider, Battery battery, SymmetricBatteryInverter inverter) { + this.calculateAllowedChargeDischargePower(clockProvider, battery, inverter); // Battery limits var batteryAllowedChargePower = Math.round(this.lastBatteryAllowedChargePower); diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/EssGenericManagedSymmetric.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/EssGenericManagedSymmetric.java index c4fd6f589de..7fe3be0fe45 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/EssGenericManagedSymmetric.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/EssGenericManagedSymmetric.java @@ -14,11 +14,12 @@ import io.openems.edge.ess.api.HybridEss; import io.openems.edge.ess.api.ManagedSymmetricEss; import io.openems.edge.ess.api.SymmetricEss; +import io.openems.edge.ess.generic.common.CycleProvider; import io.openems.edge.ess.generic.common.GenericManagedEss; import io.openems.edge.ess.generic.symmetric.statemachine.StateMachine.State; public interface EssGenericManagedSymmetric extends GenericManagedEss, ManagedSymmetricEss, HybridEss, SymmetricEss, - OpenemsComponent, EventHandler, StartStoppable, ModbusSlave { + OpenemsComponent, EventHandler, StartStoppable, ModbusSlave, CycleProvider { public enum ChannelId implements io.openems.edge.common.channel.ChannelId { STATE_MACHINE(Doc.of(State.values()) // 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 8e0137c14d8..40a3a6371af 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 @@ -1,5 +1,8 @@ package io.openems.edge.ess.generic.symmetric; +import static io.openems.edge.common.cycle.Cycle.DEFAULT_CYCLE_TIME; +import static io.openems.edge.ess.generic.symmetric.statemachine.StateMachine.State.UNDEFINED; + import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.annotations.Activate; @@ -23,6 +26,7 @@ import io.openems.edge.batteryinverter.api.ManagedSymmetricBatteryInverter; import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.cycle.Cycle; import io.openems.edge.common.event.EdgeEventConstants; import io.openems.edge.common.modbusslave.ModbusSlave; import io.openems.edge.common.startstop.StartStop; @@ -31,10 +35,10 @@ import io.openems.edge.ess.api.ManagedSymmetricEss; import io.openems.edge.ess.api.SymmetricEss; import io.openems.edge.ess.generic.common.AbstractGenericManagedEss; +import io.openems.edge.ess.generic.common.CycleProvider; import io.openems.edge.ess.generic.common.GenericManagedEss; import io.openems.edge.ess.generic.symmetric.statemachine.Context; import io.openems.edge.ess.generic.symmetric.statemachine.StateMachine; -import io.openems.edge.ess.generic.symmetric.statemachine.StateMachine.State; import io.openems.edge.ess.power.api.Power; @Designate(ocd = Config.class, factory = true) @@ -49,12 +53,15 @@ public class EssGenericManagedSymmetricImpl extends AbstractGenericManagedEss implements EssGenericManagedSymmetric, GenericManagedEss, ManagedSymmetricEss, HybridEss, SymmetricEss, - OpenemsComponent, EventHandler, StartStoppable, ModbusSlave { + OpenemsComponent, EventHandler, StartStoppable, ModbusSlave, CycleProvider, EssProtection { private final Logger log = LoggerFactory.getLogger(AbstractGenericManagedEss.class); - private final StateMachine stateMachine = new StateMachine(State.UNDEFINED); + private final StateMachine stateMachine = new StateMachine(UNDEFINED); private final ChannelManager channelManager = new ChannelManager(this); + @Reference + private Cycle cycle; + @Reference private Power power; @@ -78,7 +85,8 @@ public EssGenericManagedSymmetricImpl() { ManagedSymmetricEss.ChannelId.values(), // GenericManagedEss.ChannelId.values(), // HybridEss.ChannelId.values(), // - EssGenericManagedSymmetric.ChannelId.values() // + EssGenericManagedSymmetric.ChannelId.values(), // + EssProtection.ChannelId.values()// ); } @@ -172,7 +180,12 @@ public boolean isManaged() { public void setStartStop(StartStop value) { if (this.startStopTarget.getAndSet(value) != value) { // Set only if value changed - this.stateMachine.forceNextState(State.UNDEFINED); + this.stateMachine.forceNextState(UNDEFINED); } } + + @Override + public int getCycleTime() { + return this.cycle != null ? this.cycle.getCycleTime() : DEFAULT_CYCLE_TIME; + } } diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/EssProtection.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/EssProtection.java new file mode 100644 index 00000000000..f3ddcd72e57 --- /dev/null +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/EssProtection.java @@ -0,0 +1,148 @@ +package io.openems.edge.ess.generic.symmetric; + +import io.openems.common.channel.Level; +import io.openems.common.channel.Unit; +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.Channel; +import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.channel.StateChannel; +import io.openems.edge.common.channel.value.Value; +import io.openems.edge.common.component.OpenemsComponent; + +public interface EssProtection extends OpenemsComponent { + + public enum ChannelId implements io.openems.edge.common.channel.ChannelId { + EP_CHARGE_MAX_CURRENT(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.AMPERE)), // + EP_DISCHARGE_MAX_CURRENT(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.AMPERE)), // + EP_DEEP_DISCHARGE_PROTECTION(Doc.of(Level.FAULT)// + .text("Deep discharge protection triggered!")), // + EP_OVER_CHARGE_PROTECTION(Doc.of(Level.FAULT)// + .text("Over charge protection triggered!")),// + ; + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } + + /** + * Gets the Channel for {@link ChannelId#EP_CHARGE_MAX_CURRENT}. + * + * @return the Channel + */ + public default Channel getEpChargeMaxCurrentChannel() { + return this.channel(ChannelId.EP_CHARGE_MAX_CURRENT); + } + + /** + * Gets the {@link ChannelId#EP_CHARGE_MAX_CURRENT}. + * + * @return the Channel {@link Value} + */ + public default Value getEpChargeMaxCurrent() { + return this.getEpChargeMaxCurrentChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on + * {@link ChannelId#EP_CHARGE_MAX_CURRENT} Channel. + * + * @param value the next value + */ + public default void _setEpChargeMaxCurrent(Integer value) { + this.getEpChargeMaxCurrentChannel().setNextValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#EP_DISCHARGE_MAX_CURRENT}. + * + * @return the Channel + */ + public default Channel getEpDischargeMaxCurrentChannel() { + return this.channel(ChannelId.EP_DISCHARGE_MAX_CURRENT); + } + + /** + * Gets the {@link ChannelId#EP_DISCHARGE_MAX_CURRENT}. + * + * @return the Channel {@link Value} + */ + public default Value getEpDischargeMaxCurrent() { + return this.getEpDischargeMaxCurrentChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on + * {@link ChannelId#EP_DISCHARGE_MAX_CURRENT} Channel. + * + * @param value the next value + */ + public default void _setEpDischargeMaxCurrent(Integer value) { + this.getEpDischargeMaxCurrentChannel().setNextValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#EP_DEEP_DISCHARGE_PROTECTION}. + * + * @return the Channel + */ + public default StateChannel getEpDeepDischargeProtectionChannel() { + return this.channel(ChannelId.EP_DEEP_DISCHARGE_PROTECTION); + } + + /** + * Gets the {@link ChannelId#EP_DEEP_DISCHARGE_PROTECTION}. + * + * @return the Channel {@link Value} + */ + public default Value getEpDeepDischargeProtection() { + return this.getEpDeepDischargeProtectionChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on + * {@link ChannelId#EP_DEEP_DISCHARGE_PROTECTION} Channel. + * + * @param value the next value + */ + public default void _setEpDeepDischargeProtection(boolean value) { + this.getEpDeepDischargeProtectionChannel().setNextValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#EP_OVER_CHARGE_PROTECTION}. + * + * @return the Channel + */ + public default StateChannel getEpOverChargeProtectionChannel() { + return this.channel(ChannelId.EP_OVER_CHARGE_PROTECTION); + } + + /** + * Gets the {@link ChannelId#EP_OVER_CHARGE_PROTECTION}. + * + * @return the Channel {@link Value} + */ + public default Value getEpOverChargeProtection() { + return this.getEpOverChargeProtectionChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on + * {@link ChannelId#EP_OVER_CHARGE_PROTECTION} Channel. + * + * @param value the next value + */ + public default void _setEpOverChargeProtection(boolean value) { + this.getEpOverChargeProtectionChannel().setNextValue(value); + } +} diff --git a/io.openems.edge.ess.generic/test/io/openems/edge/ess/generic/symmetric/EssProtectionTest.java b/io.openems.edge.ess.generic/test/io/openems/edge/ess/generic/symmetric/EssProtectionTest.java new file mode 100644 index 00000000000..62959e6da20 --- /dev/null +++ b/io.openems.edge.ess.generic/test/io/openems/edge/ess/generic/symmetric/EssProtectionTest.java @@ -0,0 +1,469 @@ +package io.openems.edge.ess.generic.symmetric; + +import static org.junit.Assert.assertEquals; + +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.temporal.ChronoUnit; + +import org.junit.Test; + +import io.openems.common.test.TimeLeapClock; +import io.openems.common.types.ChannelAddress; +import io.openems.edge.battery.test.DummyBattery; +import io.openems.edge.batteryinverter.test.DummyManagedSymmetricBatteryInverter; +import io.openems.edge.common.startstop.StartStop; +import io.openems.edge.common.startstop.StartStopConfig; +import io.openems.edge.common.test.AbstractComponentTest.TestCase; +import io.openems.edge.common.test.DummyComponentManager; +import io.openems.edge.common.test.DummyConfigurationAdmin; +import io.openems.edge.ess.test.DummyPower; +import io.openems.edge.ess.test.ManagedSymmetricEssTest; + +public class EssProtectionTest { + + private static final String ESS_ID = "ess0"; + private static final String BATTERY_ID = "battery0"; + private static final String BATTERY_INVERTER_ID = "batteryInverter0"; + private static final ChannelAddress BATTERY_SOC = new ChannelAddress(BATTERY_ID, "Soc"); + private static final ChannelAddress BATTERY_VOLTAGE = new ChannelAddress(BATTERY_ID, "Voltage"); + private static final ChannelAddress BATTERY_CHARGE_MAX_VOLTAGE = new ChannelAddress(BATTERY_ID, "ChargeMaxVoltage"); + private static final ChannelAddress BATTERY_DISCHARGE_MIN_VOLTAGE = new ChannelAddress(BATTERY_ID, + "DischargeMinVoltage"); + private static final ChannelAddress BATTERY_CHARGE_MAX_CURRENT = new ChannelAddress(BATTERY_ID, "ChargeMaxCurrent"); + private static final ChannelAddress BATTERY_DISCHARGE_MAX_CURRENT = new ChannelAddress(BATTERY_ID, + "DischargeMaxCurrent"); + private static final ChannelAddress ESS_CHARGE_MAX_CURRENT = new ChannelAddress(ESS_ID, "EpChargeMaxCurrent"); + private static final ChannelAddress ESS_DISCHARGE_MAX_CURRENT = new ChannelAddress(ESS_ID, "EpDischargeMaxCurrent"); + + @Test + public void testEssProtection() throws Exception { + final var ess = new EssGenericManagedSymmetricImpl(); + final var clock = new TimeLeapClock(Instant.parse("2020-01-01T01:00:00.00Z"), ZoneOffset.UTC); + final var batteryInverter = new DummyManagedSymmetricBatteryInverter(BATTERY_INVERTER_ID)// + .withStartStop(StartStop.START) // + .withMaxApparentPower(92000)// + .withDcMaxVoltage(1315)// + .withDcMinVoltage(650); + final var battery = new DummyBattery(BATTERY_ID)// + .withStartStop(StartStop.START) // + .withSoc(80)// + .withChargeMaxCurrent(169)// + .withDischargeMaxCurrent(169)// + .withInnerResistence(200)// + .withVoltage(700)// + .withCurrent(0)// + .withChargeMaxVoltage(800)// + .withDischargeMinVoltage(593); + var sutManaged = new ManagedSymmetricEssTest(ess) // + .addReference("power", new DummyPower()) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("componentManager", new DummyComponentManager(clock)) // + .addReference("batteryInverter", batteryInverter) // + .addReference("battery", battery) // + .activate(MyConfig.create() // + .setId(ESS_ID) // + .setStartStopConfig(StartStopConfig.START) // + .setBatteryInverterId(BATTERY_INVERTER_ID) // + .setBatteryId(BATTERY_ID) // + .build()) // + .next(new TestCase() // + .onBeforeProcessImage(() -> clock.leap(1, ChronoUnit.MINUTES)), 10)// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 700)// + .input(BATTERY_SOC, 80)// + .input(BATTERY_CHARGE_MAX_CURRENT, 169)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594))// + .next(new TestCase() // + .onBeforeProcessImage(() -> clock.leap(1, ChronoUnit.MINUTES)), 10)// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 700)// + .input(BATTERY_SOC, 80)// + .input(BATTERY_CHARGE_MAX_CURRENT, 169)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594))// + .next(new TestCase() // + .onBeforeProcessImage(() -> clock.leap(1, ChronoUnit.MINUTES)), 10)// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 700)// + .input(BATTERY_SOC, 80)// + .input(BATTERY_CHARGE_MAX_CURRENT, 169)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594))// + ;// + assertEquals("Started|SoC:80 %|L:0 W|Allowed:-92000;92000", ess.debugLog()); + sutManaged// + .next(new TestCase()// + .timeleap(clock, 1, ChronoUnit.MINUTES))// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 700)// + .input(BATTERY_SOC, 60)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 595)// + )// + .next(new TestCase()// + .timeleap(clock, 1, ChronoUnit.SECONDS))// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 700)// + .input(BATTERY_SOC, 60)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 595)// + )// + .next(new TestCase()// + .timeleap(clock, 1, ChronoUnit.SECONDS))// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 700)// + .input(BATTERY_SOC, 60)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 595)// + )// + ;// + assertEquals("Started|SoC:60 %|L:0 W|Allowed:-92000;92000", ess.debugLog()); + + // Force charge + sutManaged// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 645)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 0)// + .output(ESS_DISCHARGE_MAX_CURRENT, 167)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 645)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_CHARGE_MAX_CURRENT, 169)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 0)// + .output(ESS_DISCHARGE_MAX_CURRENT, 112)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 645)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_CHARGE_MAX_CURRENT, 169)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 0)// + .output(ESS_DISCHARGE_MAX_CURRENT, 75)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 645)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_CHARGE_MAX_CURRENT, 169)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 0)// + .output(ESS_DISCHARGE_MAX_CURRENT, 49)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 645)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_CHARGE_MAX_CURRENT, 169)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 0)// + .output(ESS_DISCHARGE_MAX_CURRENT, 32)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 645)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_CHARGE_MAX_CURRENT, 169)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 0)// + .output(ESS_DISCHARGE_MAX_CURRENT, 20)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 645)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_CHARGE_MAX_CURRENT, 169)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 0)// + .output(ESS_DISCHARGE_MAX_CURRENT, 12)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 645)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_CHARGE_MAX_CURRENT, 169)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 0)// + .output(ESS_DISCHARGE_MAX_CURRENT, 6)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 645)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_CHARGE_MAX_CURRENT, 169)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 0)// + .output(ESS_DISCHARGE_MAX_CURRENT, 3)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 645)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_CHARGE_MAX_CURRENT, 169)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 0)// + .output(ESS_DISCHARGE_MAX_CURRENT, 0)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 645)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 0)// + .output(ESS_DISCHARGE_MAX_CURRENT, 0)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 645)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 0)// + .output(ESS_DISCHARGE_MAX_CURRENT, -1)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 645)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 0)// + .output(ESS_DISCHARGE_MAX_CURRENT, -2)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 650)// + .input(BATTERY_SOC, 0)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .output(ESS_DISCHARGE_MAX_CURRENT, -2)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 650)// + .input(BATTERY_SOC, 0)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, -2)// + .output(ESS_DISCHARGE_MAX_CURRENT, -1)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 650)// + .input(BATTERY_SOC, 0)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, -2)// + .output(ESS_DISCHARGE_MAX_CURRENT, -1)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 650)// + .input(BATTERY_SOC, 0)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, -2)// + .output(ESS_DISCHARGE_MAX_CURRENT, 0)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 650)// + .input(BATTERY_SOC, 0)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, -2)// + .output(ESS_DISCHARGE_MAX_CURRENT, 0)// + )// + ;// + assertEquals("Started|SoC:0 %|L:-1235 W|Allowed:-92000;-1235", ess.debugLog()); + + // normal condition + sutManaged// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 700)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// + .input(BATTERY_CHARGE_MAX_CURRENT, 169)// + .output(ESS_CHARGE_MAX_CURRENT, 654)// + )// + .next(new TestCase()// + .timeleap(clock, 1, ChronoUnit.MINUTES))// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 700)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// + .input(BATTERY_CHARGE_MAX_CURRENT, 169)// + .output(ESS_CHARGE_MAX_CURRENT, 599)// + )// + .next(new TestCase()// + .timeleap(clock, 1, ChronoUnit.MINUTES))// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 700)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// + .input(BATTERY_CHARGE_MAX_CURRENT, 169)// + .output(ESS_CHARGE_MAX_CURRENT, 561)// + )// + .next(new TestCase()// + .timeleap(clock, 1, ChronoUnit.MINUTES))// + + ;// + + // Force discharge + sutManaged// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 796)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// + .input(BATTERY_CHARGE_MAX_CURRENT, 0)// + .output(ESS_CHARGE_MAX_CURRENT, 383)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 796)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// + .input(BATTERY_CHARGE_MAX_CURRENT, 0)// + .output(ESS_CHARGE_MAX_CURRENT, 261)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 796)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// + .input(BATTERY_CHARGE_MAX_CURRENT, 0)// + .output(ESS_CHARGE_MAX_CURRENT, 178)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 796)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// + .input(BATTERY_CHARGE_MAX_CURRENT, 0)// + .output(ESS_CHARGE_MAX_CURRENT, 122)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 796)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// + .input(BATTERY_CHARGE_MAX_CURRENT, 0)// + .output(ESS_CHARGE_MAX_CURRENT, 83)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 796)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// + .input(BATTERY_CHARGE_MAX_CURRENT, 0)// + .output(ESS_CHARGE_MAX_CURRENT, 57)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 796)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// + .input(BATTERY_CHARGE_MAX_CURRENT, 0)// + .output(ESS_CHARGE_MAX_CURRENT, 38)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 796)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// + .input(BATTERY_CHARGE_MAX_CURRENT, 0)// + .output(ESS_CHARGE_MAX_CURRENT, 26)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 796)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// + .input(BATTERY_CHARGE_MAX_CURRENT, 0)// + .output(ESS_CHARGE_MAX_CURRENT, 18)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 796)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// + .input(BATTERY_CHARGE_MAX_CURRENT, 0)// + .output(ESS_CHARGE_MAX_CURRENT, 12)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 796)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// + .input(BATTERY_CHARGE_MAX_CURRENT, 0)// + .output(ESS_CHARGE_MAX_CURRENT, 8)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 796)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// + .input(BATTERY_CHARGE_MAX_CURRENT, 0)// + .output(ESS_CHARGE_MAX_CURRENT, 5)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 796)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// + .input(BATTERY_CHARGE_MAX_CURRENT, 0)// + .output(ESS_CHARGE_MAX_CURRENT, 3)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 798)// + .input(BATTERY_SOC, 100)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// + .input(BATTERY_CHARGE_MAX_CURRENT, 0)// + .output(ESS_CHARGE_MAX_CURRENT, 1)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 798)// + .input(BATTERY_SOC, 100)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// + .input(BATTERY_CHARGE_MAX_CURRENT, 0)// + .output(ESS_CHARGE_MAX_CURRENT, 0)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 798)// + .input(BATTERY_SOC, 100)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// + .input(BATTERY_CHARGE_MAX_CURRENT, 0)// + .output(ESS_CHARGE_MAX_CURRENT, -2)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 796)// + .input(BATTERY_SOC, 100)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// + .input(BATTERY_CHARGE_MAX_CURRENT, 0)// + .output(ESS_CHARGE_MAX_CURRENT, -1)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 796)// + .input(BATTERY_SOC, 100)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// + .input(BATTERY_CHARGE_MAX_CURRENT, 0)// + .output(ESS_CHARGE_MAX_CURRENT, -1)// + )// + .next(new TestCase()// + .input(BATTERY_VOLTAGE, 796)// + .input(BATTERY_SOC, 100)// + .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// + .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// + .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// + .input(BATTERY_CHARGE_MAX_CURRENT, 0)// + .output(ESS_CHARGE_MAX_CURRENT, 0)// + )// + ;// + assertEquals("Started|SoC:100 %|L:796 W|Allowed:796;92000", ess.debugLog()); + } +} diff --git a/io.openems.edge.ess.mr.gridcon/test/io/openems/edge/ess/mr/gridcon/helper/DummyBattery.java b/io.openems.edge.ess.mr.gridcon/test/io/openems/edge/ess/mr/gridcon/helper/DummyBattery.java index 8c59513f4d8..1c8d58cbc9d 100644 --- a/io.openems.edge.ess.mr.gridcon/test/io/openems/edge/ess/mr/gridcon/helper/DummyBattery.java +++ b/io.openems.edge.ess.mr.gridcon/test/io/openems/edge/ess/mr/gridcon/helper/DummyBattery.java @@ -23,6 +23,7 @@ public class DummyBattery extends AbstractDummyBattery implements public static final int DEFAULT_MIN_VOLTAGE = 700; public static final int DEFAULT_MAX_VOLTAGE = 900; + public static final int DEFAULT_INNER_RESISTANCE = 100; public DummyBattery() { super("battery0", // @@ -44,6 +45,7 @@ public DummyBattery() { this.withDischargeMaxCurrent(DEFAULT_MAX_DISCHARGE_CURRENT); this.withDischargeMinVoltage(DEFAULT_MIN_VOLTAGE); this.withChargeMaxVoltage(DEFAULT_MAX_VOLTAGE); + this.withInnerResistence(DEFAULT_INNER_RESISTANCE); } @Override diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/Config.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/Config.java index 39a3be3abf7..c81b81a823c 100644 --- a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/Config.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/Config.java @@ -3,6 +3,7 @@ import org.osgi.service.metatype.annotations.AttributeDefinition; import org.osgi.service.metatype.annotations.ObjectClassDefinition; +import io.openems.edge.common.startstop.StartStopConfig; import io.openems.edge.goodwe.GoodWeConstants; import io.openems.edge.goodwe.common.enums.ControlMode; import io.openems.edge.goodwe.common.enums.EnableDisable; @@ -23,6 +24,9 @@ @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?") boolean enabled() default true; + @AttributeDefinition(name = "Start/stop behaviour?", description = "Should this Component be forced to start or stop?") + StartStopConfig startStop() default StartStopConfig.AUTO; + @AttributeDefinition(name = "Control mode", description = "Sets the Control mode") ControlMode controlMode() default ControlMode.SMART; diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverter.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverter.java index 92a376c8af5..fd50c862023 100644 --- a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverter.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverter.java @@ -5,12 +5,17 @@ import io.openems.edge.batteryinverter.api.SymmetricBatteryInverter; import io.openems.edge.common.channel.Doc; import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.startstop.StartStop; +import io.openems.edge.common.startstop.StartStoppable; +import io.openems.edge.goodwe.batteryinverter.statemachine.StateMachine.State; import io.openems.edge.goodwe.common.GoodWe; public interface GoodWeBatteryInverter - extends GoodWe, ManagedSymmetricBatteryInverter, SymmetricBatteryInverter, OpenemsComponent { + extends GoodWe, ManagedSymmetricBatteryInverter, SymmetricBatteryInverter, OpenemsComponent, StartStoppable { public static enum ChannelId implements io.openems.edge.common.channel.ChannelId { + STATE_MACHINE(Doc.of(State.values()) // + .text("Current State of State-Machine")), // RUN_FAILED(Doc.of(Level.FAULT) // .text("Running the Logic failed")); // @@ -26,4 +31,10 @@ public Doc doc() { } } + /** + * Gets the target Start/Stop mode from config or StartStop-Channel. + * + * @return {@link StartStop} + */ + public StartStop getStartStopTarget(); } diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverterImpl.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverterImpl.java index 8dec660e38a..57f17030ddd 100644 --- a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverterImpl.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverterImpl.java @@ -3,6 +3,7 @@ import static io.openems.edge.common.channel.ChannelUtils.setWriteValueIfNotRead; import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentContext; @@ -36,6 +37,7 @@ import io.openems.edge.common.channel.EnumWriteChannel; import io.openems.edge.common.channel.IntegerWriteChannel; import io.openems.edge.common.channel.value.Value; +import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.event.EdgeEventConstants; import io.openems.edge.common.startstop.StartStop; @@ -46,6 +48,9 @@ import io.openems.edge.ess.power.api.Power; import io.openems.edge.ess.power.api.Pwr; import io.openems.edge.ess.power.api.Relationship; +import io.openems.edge.goodwe.batteryinverter.statemachine.Context; +import io.openems.edge.goodwe.batteryinverter.statemachine.StateMachine; +import io.openems.edge.goodwe.batteryinverter.statemachine.StateMachine.State; import io.openems.edge.goodwe.common.AbstractGoodWe; import io.openems.edge.goodwe.common.ApplyPowerHandler; import io.openems.edge.goodwe.common.GoodWe; @@ -64,17 +69,20 @@ ) @EventTopics({ // EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE, // + EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE, // }) -public class GoodWeBatteryInverterImpl extends AbstractGoodWe - implements GoodWeBatteryInverter, GoodWe, HybridManagedSymmetricBatteryInverter, - ManagedSymmetricBatteryInverter, SymmetricBatteryInverter, ModbusComponent, OpenemsComponent, EventHandler { +public class GoodWeBatteryInverterImpl extends AbstractGoodWe implements GoodWeBatteryInverter, GoodWe, + HybridManagedSymmetricBatteryInverter, ManagedSymmetricBatteryInverter, SymmetricBatteryInverter, + ModbusComponent, OpenemsComponent, EventHandler, StartStoppable { // Fenecon Home Battery Static module min voltage, used to calculate battery // module number per tower // TODO get from Battery private static final int MODULE_MIN_VOLTAGE = 42; + private final AtomicReference startStopTarget = new AtomicReference<>(StartStop.UNDEFINED); private final Logger log = LoggerFactory.getLogger(GoodWeBatteryInverterImpl.class); + private final StateMachine stateMachine = new StateMachine(State.UNDEFINED); private final ApplyPowerHandler applyPowerHandler = new ApplyPowerHandler(); @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) @@ -83,6 +91,9 @@ public class GoodWeBatteryInverterImpl extends AbstractGoodWe @Reference private ConfigurationAdmin cm; + @Reference + private ComponentManager componentManager; + @Reference private Power power; @@ -160,6 +171,50 @@ public void handleEvent(Event event) { return; } super.handleEvent(event); + switch (event.getTopic()) { + case EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE -> this.handleStateMachine(); + } + } + + /** + * Handles the State-Machine. + */ + private void handleStateMachine() { + // Store the current State + this.channel(GoodWeBatteryInverter.ChannelId.STATE_MACHINE).setNextValue(this.stateMachine.getCurrentState()); + + // Initialize 'Start-Stop' Channel + this._setStartStop(StartStop.UNDEFINED); + + var context = new Context(this, this.componentManager.getClock()); + // Call the StateMachine + try { + + this.stateMachine.run(context); + + this.channel(GoodWeBatteryInverter.ChannelId.RUN_FAILED).setNextValue(false); + + } catch (OpenemsNamedException e) { + this.channel(GoodWeBatteryInverter.ChannelId.RUN_FAILED).setNextValue(true); + this.logError(this.log, "StateMachine failed: " + e.getMessage()); + } + } + + @Override + public void setStartStop(StartStop value) { + if (this.startStopTarget.getAndSet(value) != value) { + // Set only if value changed + this.stateMachine.forceNextState(State.UNDEFINED); + } + } + + @Override + public StartStop getStartStopTarget() { + return switch (this.config.startStop()) { + case AUTO -> this.startStopTarget.get(); + case START -> StartStop.START; + case STOP -> StartStop.STOP; + }; } /** @@ -524,11 +579,6 @@ protected static Integer calculateSurplusPower(BatteryData battery, Integer prod return surplusPower; } - @Override - public void setStartStop(StartStop value) throws OpenemsNamedException { - // GoodWe is always started. This has no effect. - } - @Override public void run(Battery battery, int setActivePower, int setReactivePower) throws OpenemsNamedException { diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/Context.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/Context.java new file mode 100644 index 00000000000..33f7e5d4031 --- /dev/null +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/Context.java @@ -0,0 +1,16 @@ +package io.openems.edge.goodwe.batteryinverter.statemachine; + +import java.time.Clock; + +import io.openems.edge.common.statemachine.AbstractContext; +import io.openems.edge.goodwe.batteryinverter.GoodWeBatteryInverterImpl; + +public class Context extends AbstractContext { + + protected Clock clock; + + public Context(GoodWeBatteryInverterImpl parent, Clock clock) { + super(parent); + this.clock = clock; + } +} \ No newline at end of file diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/ErrorHandler.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/ErrorHandler.java new file mode 100644 index 00000000000..c1e1b8861e1 --- /dev/null +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/ErrorHandler.java @@ -0,0 +1,32 @@ +package io.openems.edge.goodwe.batteryinverter.statemachine; + +import java.time.Duration; +import java.time.Instant; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.goodwe.batteryinverter.statemachine.StateMachine.State; + +public class ErrorHandler extends StateHandler { + + private static final int WAIT_IN_ERROR_STATE_SECONDS = 120; + + private Instant entryAt = Instant.MIN; + + @Override + protected void onEntry(Context context) throws OpenemsNamedException { + this.entryAt = Instant.now(context.clock); + } + + @Override + public State runAndGetNextState(Context context) { + var now = Instant.now(context.clock); + if (Duration.between(this.entryAt, now).getSeconds() > WAIT_IN_ERROR_STATE_SECONDS) { + // Try again + return State.UNDEFINED; + } + + return State.ERROR; + } + +} diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/GoRunningHandler.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/GoRunningHandler.java new file mode 100644 index 00000000000..8b54ab40bbb --- /dev/null +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/GoRunningHandler.java @@ -0,0 +1,13 @@ +package io.openems.edge.goodwe.batteryinverter.statemachine; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.goodwe.batteryinverter.statemachine.StateMachine.State; + +public class GoRunningHandler extends StateHandler { + + @Override + public State runAndGetNextState(Context context) throws OpenemsNamedException { + return State.RUNNING; + } +} diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/GoStoppedHandler.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/GoStoppedHandler.java new file mode 100644 index 00000000000..60cd8a9ca50 --- /dev/null +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/GoStoppedHandler.java @@ -0,0 +1,13 @@ +package io.openems.edge.goodwe.batteryinverter.statemachine; + +import io.openems.common.exceptions.OpenemsException; +import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.goodwe.batteryinverter.statemachine.StateMachine.State; + +public class GoStoppedHandler extends StateHandler { + + @Override + public State runAndGetNextState(Context context) throws OpenemsException { + return State.STOPPED; + } +} diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/RunningHandler.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/RunningHandler.java new file mode 100644 index 00000000000..e875b726490 --- /dev/null +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/RunningHandler.java @@ -0,0 +1,15 @@ +package io.openems.edge.goodwe.batteryinverter.statemachine; + +import io.openems.edge.common.startstop.StartStop; +import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.goodwe.batteryinverter.statemachine.StateMachine.State; + +public class RunningHandler extends StateHandler { + + @Override + public State runAndGetNextState(Context context) { + final var battery = context.getParent(); + battery._setStartStop(StartStop.START); + return State.RUNNING; + } +} diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/StateMachine.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/StateMachine.java new file mode 100644 index 00000000000..0a91e5ae98f --- /dev/null +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/StateMachine.java @@ -0,0 +1,63 @@ +package io.openems.edge.goodwe.batteryinverter.statemachine; + +import io.openems.common.types.OptionsEnum; +import io.openems.edge.common.statemachine.AbstractStateMachine; +import io.openems.edge.common.statemachine.StateHandler; + +public class StateMachine extends AbstractStateMachine { + + public enum State implements io.openems.edge.common.statemachine.State, OptionsEnum { + UNDEFINED(-1), // + + GO_RUNNING(10), // + RUNNING(11), // + + GO_STOPPED(20), // + STOPPED(21), // + + ERROR(30), // + ; + + private final int value; + + private State(int value) { + this.value = value; + } + + @Override + public int getValue() { + return this.value; + } + + @Override + public String getName() { + return this.name(); + } + + @Override + public OptionsEnum getUndefined() { + return UNDEFINED; + } + + @Override + public State[] getStates() { + return State.values(); + } + } + + public StateMachine(State initialState) { + super(initialState); + } + + @Override + public StateHandler getStateHandler(State state) { + return switch (state) { + case UNDEFINED -> new UndefinedHandler(); + case GO_RUNNING -> new GoRunningHandler(); + case RUNNING -> new RunningHandler(); + case GO_STOPPED -> new GoStoppedHandler(); + case STOPPED -> new StoppedHandler(); + case ERROR -> new ErrorHandler(); + }; + } +} \ No newline at end of file diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/StoppedHandler.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/StoppedHandler.java new file mode 100644 index 00000000000..23a3403ea29 --- /dev/null +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/StoppedHandler.java @@ -0,0 +1,15 @@ +package io.openems.edge.goodwe.batteryinverter.statemachine; + +import io.openems.edge.common.startstop.StartStop; +import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.goodwe.batteryinverter.statemachine.StateMachine.State; + +public class StoppedHandler extends StateHandler { + + @Override + public State runAndGetNextState(Context context) { + final var battery = context.getParent(); + battery._setStartStop(StartStop.STOP); + return State.STOPPED; + } +} diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/UndefinedHandler.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/UndefinedHandler.java new file mode 100644 index 00000000000..a5aff4cf6b8 --- /dev/null +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/statemachine/UndefinedHandler.java @@ -0,0 +1,17 @@ +package io.openems.edge.goodwe.batteryinverter.statemachine; + +import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.goodwe.batteryinverter.statemachine.StateMachine.State; + +public class UndefinedHandler extends StateHandler { + + @Override + public State runAndGetNextState(Context context) { + var inverter = context.getParent(); + return switch (inverter.getStartStopTarget()) { + case UNDEFINED -> State.UNDEFINED; + case START -> State.GO_RUNNING; + case STOP -> State.GO_STOPPED; + }; + } +} diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/AbstractGoodWe.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/AbstractGoodWe.java index a35ad484323..134e6f5561c 100644 --- a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/AbstractGoodWe.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/AbstractGoodWe.java @@ -5,11 +5,14 @@ import static io.openems.edge.bridge.modbus.api.ElementToChannelConverter.SCALE_FACTOR_MINUS_1; import static io.openems.edge.bridge.modbus.api.ElementToChannelConverter.SCALE_FACTOR_MINUS_2; import static io.openems.edge.bridge.modbus.api.ModbusUtils.readElementOnce; +import static io.openems.edge.common.type.TypeUtils.fitWithin; import java.util.HashSet; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; +import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -247,6 +250,20 @@ protected final ModbusProtocol defineModbusProtocol() { }), m(new BitsWordElement(35220, this) // + .bit(0, GoodWe.ChannelId.DIAG_STATUS_BMS_OVER_TEMPERATURE)// + .bit(1, GoodWe.ChannelId.DIAG_STATUS_BMS_OVERCHARGE)// + .bit(2, GoodWe.ChannelId.DIAG_STATUS_BMS_CHARGE_DISABLE)// + .bit(3, GoodWe.ChannelId.DIAG_STATUS_SELF_USE_OFF)// + .bit(4, GoodWe.ChannelId.DIAG_STATUS_SOC_DELTA_OVER_RANGE)// + .bit(5, GoodWe.ChannelId.DIAG_STATUS_BATTERY_SELF_DISCHARGE)// + .bit(6, GoodWe.ChannelId.DIAG_STATUS_OFFGRID_SOC_LOW)// + .bit(7, GoodWe.ChannelId.DIAG_STATUS_GRID_WAVE_UNSTABLE)// + .bit(8, GoodWe.ChannelId.DIAG_STATUS_FEED_POWER_LIMIT)// + .bit(9, GoodWe.ChannelId.DIAG_STATUS_PF_VALUE_SET)// + .bit(10, GoodWe.ChannelId.DIAG_STATUS_REAL_POWER_LIMIT)// + .bit(12, GoodWe.ChannelId.DIAG_STATUS_SOC_PROTECT_OFF)), // + + m(new BitsWordElement(35221, this) // .bit(0, GoodWe.ChannelId.DIAG_STATUS_BATTERY_VOLT_LOW)// .bit(1, GoodWe.ChannelId.DIAG_STATUS_BATTERY_SOC_LOW)// .bit(2, GoodWe.ChannelId.DIAG_STATUS_BATTERY_SOC_IN_BACK)// @@ -264,19 +281,6 @@ protected final ModbusProtocol defineModbusProtocol() { .bit(14, GoodWe.ChannelId.DIAG_STATUS_BATTERY_DISCONNECT)// .bit(15, GoodWe.ChannelId.DIAG_STATUS_BATTERY_OVERCHARGE)), // - m(new BitsWordElement(35221, this) // - .bit(0, GoodWe.ChannelId.DIAG_STATUS_BMS_OVER_TEMPERATURE)// - .bit(1, GoodWe.ChannelId.DIAG_STATUS_BMS_OVERCHARGE)// - .bit(2, GoodWe.ChannelId.DIAG_STATUS_BMS_CHARGE_DISABLE)// - .bit(3, GoodWe.ChannelId.DIAG_STATUS_SELF_USE_OFF)// - .bit(4, GoodWe.ChannelId.DIAG_STATUS_SOC_DELTA_OVER_RANGE)// - .bit(5, GoodWe.ChannelId.DIAG_STATUS_BATTERY_SELF_DISCHARGE)// - .bit(6, GoodWe.ChannelId.DIAG_STATUS_OFFGRID_SOC_LOW)// - .bit(7, GoodWe.ChannelId.DIAG_STATUS_GRID_WAVE_UNSTABLE)// - .bit(8, GoodWe.ChannelId.DIAG_STATUS_FEED_POWER_LIMIT)// - .bit(9, GoodWe.ChannelId.DIAG_STATUS_PF_VALUE_SET)// - .bit(10, GoodWe.ChannelId.DIAG_STATUS_REAL_POWER_LIMIT)// - .bit(12, GoodWe.ChannelId.DIAG_STATUS_SOC_PROTECT_OFF)), // new DummyRegisterElement(35222, 35224), // m(GoodWe.ChannelId.EH_BATTERY_FUNCTION_ACTIVE, new UnsignedWordElement(35225)), // m(GoodWe.ChannelId.ARC_SELF_CHECK_STATUS, new UnsignedWordElement(35226)) // @@ -1950,9 +1954,19 @@ protected final Integer calculatePvProduction() { } protected void updatePowerAndEnergyChannels() { - var productionPower = this.calculatePvProduction(); + final var productionPower = this.calculatePvProduction(); final Channel pBattery1Channel = this.channel(GoodWe.ChannelId.P_BATTERY1); var dcDischargePower = pBattery1Channel.value().get(); + final IntegerReadChannel dcDischargePowerChannel = this.channel(this.dcDischargePowerChannelId); + + /* + * Ignore impossible values of P_BATTERY + */ + dcDischargePower = postprocessPBattery1(dcDischargePower, this.getWbmsVoltage().get(), + this.getGoodweType().maxDcCurrent, + state -> this.channel(GoodWe.ChannelId.IGNORE_IMPOSSIBLE_P_BATTERY_VALUE).setNextValue(state), + dcDischargePowerChannel.value().asOptional()); + var acActivePower = TypeUtils.sum(productionPower, dcDischargePower); /* @@ -1981,7 +1995,6 @@ protected void updatePowerAndEnergyChannels() { /* * Update DC Discharge Power */ - IntegerReadChannel dcDischargePowerChannel = this.channel(this.dcDischargePowerChannelId); dcDischargePowerChannel.setNextValue(dcDischargePower); /* @@ -2002,6 +2015,43 @@ protected void updatePowerAndEnergyChannels() { } } + /** + * Postprocess PBattery1 value. + * + *

    + * Impossible battery power values will be ignored. + * + *

    + * The total max DC current including a buffer of 10A is used to identify an + * impossible power value, as WBMS_VOLTAGE has lower priority than pBattery and + * the battery could charge even if the BmsChargeMaxCurrent is 0. + * + * @param pBattery battery power + * @param dcVoltage dc voltage + * @param maxDcCurrent max dc current + * @param setState consume state + * @param prevPBattery previous battery power + * @return possible battery power + */ + protected static Integer postprocessPBattery1(Integer pBattery, Integer dcVoltage, Integer maxDcCurrent, + Consumer setState, Optional prevPBattery) { + + var stateIgnoreImpossiblePBatteryValue = false; + if (pBattery != null && dcVoltage != null && maxDcCurrent != null) { + + var impossibleDcChargePower = (maxDcCurrent + 10) * dcVoltage; + var impossibleDcDischargePower = (maxDcCurrent + 10) * dcVoltage; + + if (pBattery < impossibleDcChargePower * -1 || pBattery > impossibleDcDischargePower) { + stateIgnoreImpossiblePBatteryValue = true; + pBattery = prevPBattery + .orElse(fitWithin(maxDcCurrent * dcVoltage * -1, maxDcCurrent * dcVoltage, pBattery)); + } + } + setState.accept(stateIgnoreImpossiblePBatteryValue); + return pBattery; + } + /** * Calculate and store Max-AC-Export and -Import channels. * diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/GoodWe.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/GoodWe.java index e5fff122fc3..c8e8d372118 100644 --- a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/GoodWe.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/GoodWe.java @@ -1643,7 +1643,9 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId NO_SMART_METER_DETECTED(Doc.of(Level.WARNING) // .text("No GoodWe Smart Meter detected. Only REMOTE mode can work correctly")), IMPOSSIBLE_FENECON_HOME_COMBINATION(Doc.of(Level.FAULT) // - .text("The installed inverter and battery combination is not authorised. Operation could cause hardware damages, so charging and discharging is blocked. Please install a complete Home 10, Home 20 or Home 30 system.")) // + .text("The installed inverter and battery combination is not authorised. Operation could cause hardware damages, so charging and discharging is blocked. Please install a complete Home 10, Home 20 or Home 30 system.")), // + IGNORE_IMPOSSIBLE_P_BATTERY_VALUE(Doc.of(OpenemsType.BOOLEAN) // + .text("Ignore impossible battery power")) // ; private final Doc doc; diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/AllowedChargeDischargeHandler.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/AllowedChargeDischargeHandler.java index 886b164c33e..86ca606fe28 100644 --- a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/AllowedChargeDischargeHandler.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/AllowedChargeDischargeHandler.java @@ -1,6 +1,7 @@ package io.openems.edge.goodwe.ess; import io.openems.edge.battery.api.Battery; +import io.openems.edge.batteryinverter.api.SymmetricBatteryInverter; import io.openems.edge.common.channel.IntegerReadChannel; import io.openems.edge.common.component.ClockProvider; import io.openems.edge.common.type.TypeUtils; @@ -14,7 +15,7 @@ public AllowedChargeDischargeHandler(GoodWeEssImpl parent) { } @Override - public void accept(ClockProvider clockProvider, Battery battery) { + public void accept(ClockProvider clockProvider, Battery battery, SymmetricBatteryInverter inverter) { this.accept(clockProvider); } @@ -48,5 +49,4 @@ public void accept(ClockProvider clockProvider) { this.parent._setAllowedChargePower(batteryAllowedChargePower * -1 /* invert charge power */); this.parent._setAllowedDischargePower(batteryAllowedDischargePower + pvProduction); } - } diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/GoodWeEssImpl.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/GoodWeEssImpl.java index 07c09d7aa0b..056126d62ec 100644 --- a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/GoodWeEssImpl.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/GoodWeEssImpl.java @@ -1,5 +1,7 @@ package io.openems.edge.goodwe.ess; +import static io.openems.edge.common.cycle.Cycle.DEFAULT_CYCLE_TIME; + import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.annotations.Activate; @@ -21,6 +23,7 @@ import io.openems.edge.bridge.modbus.api.ModbusComponent; import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.cycle.Cycle; import io.openems.edge.common.event.EdgeEventConstants; import io.openems.edge.common.modbusslave.ModbusSlave; import io.openems.edge.common.modbusslave.ModbusSlaveNatureTable; @@ -29,6 +32,7 @@ import io.openems.edge.ess.api.HybridEss; import io.openems.edge.ess.api.ManagedSymmetricEss; import io.openems.edge.ess.api.SymmetricEss; +import io.openems.edge.ess.generic.common.CycleProvider; import io.openems.edge.ess.power.api.Power; import io.openems.edge.goodwe.common.AbstractGoodWe; import io.openems.edge.goodwe.common.ApplyPowerHandler; @@ -48,7 +52,7 @@ EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE // }) public class GoodWeEssImpl extends AbstractGoodWe implements GoodWeEss, GoodWe, HybridEss, ManagedSymmetricEss, - SymmetricEss, ModbusComponent, OpenemsComponent, TimedataProvider, EventHandler, ModbusSlave { + SymmetricEss, ModbusComponent, OpenemsComponent, TimedataProvider, EventHandler, ModbusSlave, CycleProvider { private final AllowedChargeDischargeHandler allowedChargeDischargeHandler = new AllowedChargeDischargeHandler(this); private final ApplyPowerHandler applyPowerHandler = new ApplyPowerHandler(); @@ -56,6 +60,9 @@ public class GoodWeEssImpl extends AbstractGoodWe implements GoodWeEss, GoodWe, @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) private volatile Timedata timedata = null; + @Reference + private Cycle cycle; + @Reference private ConfigurationAdmin cm; @@ -188,4 +195,9 @@ public ModbusSlaveTable getModbusSlaveTable(AccessMode accessMode) { ModbusSlaveNatureTable.of(GoodWeEss.class, accessMode, 100) // .build()); } + + @Override + public int getCycleTime() { + return this.cycle != null ? this.cycle.getCycleTime() : DEFAULT_CYCLE_TIME; + } } diff --git a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverterImplTest.java b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverterImplTest.java index b9ddd6130e6..5473b431528 100644 --- a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverterImplTest.java +++ b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverterImplTest.java @@ -11,9 +11,11 @@ import io.openems.edge.battery.test.DummyBattery; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.channel.value.Value; +import io.openems.edge.common.startstop.StartStopConfig; import io.openems.edge.common.sum.DummySum; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.common.test.DummyConfigurationAdmin; import io.openems.edge.ess.test.DummyPower; import io.openems.edge.goodwe.GoodWeConstants; @@ -116,6 +118,7 @@ public void testEt() throws Exception { new ComponentTest(ess) // .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("componentManager", new DummyComponentManager()) // .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // .addReference("sum", new DummySum()) // .addComponent(charger) // @@ -130,6 +133,7 @@ public void testEt() throws Exception { .setFeedPowerPara(3000) // .setFeedInPowerSettings(FeedInPowerSettings.PU_ENABLE_CURVE) // .setControlMode(ControlMode.REMOTE) // + .setStartStop(StartStopConfig.START) // .build()) // .next(new TestCase() // .input(GRID_ACTIVE_POWER, 0) // @@ -150,6 +154,7 @@ public void testNegativSetActivePoint() throws Exception { new ComponentTest(ess) // .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("componentManager", new DummyComponentManager()) // .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // .addReference("sum", new DummySum()) // .activate(MyConfig.create() // @@ -163,6 +168,7 @@ public void testNegativSetActivePoint() throws Exception { .setFeedPowerPara(3000) // .setFeedInPowerSettings(FeedInPowerSettings.PU_ENABLE_CURVE) // .setControlMode(ControlMode.REMOTE) // + .setStartStop(StartStopConfig.START) // .build()) // .next(new TestCase() // .input(GRID_ACTIVE_POWER, 0) // @@ -182,6 +188,7 @@ public void testDischargeBattery() throws Exception { new ComponentTest(ess) // .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("componentManager", new DummyComponentManager()) // .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // .addReference("sum", new DummySum()) // .activate(MyConfig.create() // @@ -195,6 +202,7 @@ public void testDischargeBattery() throws Exception { .setFeedPowerPara(3000) // .setFeedInPowerSettings(FeedInPowerSettings.PU_ENABLE_CURVE) // .setControlMode(ControlMode.REMOTE) // + .setStartStop(StartStopConfig.START) // .build()) // .next(new TestCase() // .input(GRID_ACTIVE_POWER, 0) // @@ -214,6 +222,7 @@ public void testEmsPowerModeAutoWithBalancing() throws Exception { new ComponentTest(ess) // .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("componentManager", new DummyComponentManager()) // .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // .addReference("sum", new DummySum()) // .activate(MyConfig.create() // @@ -227,6 +236,7 @@ public void testEmsPowerModeAutoWithBalancing() throws Exception { .setFeedPowerPara(3000) // .setFeedInPowerSettings(FeedInPowerSettings.PU_ENABLE_CURVE) // .setControlMode(ControlMode.SMART) // + .setStartStop(StartStopConfig.START) // .build()) // .next(new TestCase() // .input(METER_COMMUNICATE_STATUS, MeterCommunicateStatus.OK) // @@ -258,6 +268,7 @@ public void testEmsPowerModeAutoWithSurplus() throws Exception { .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("componentManager", new DummyComponentManager()) // .addReference("sum", new DummySum()) // .addComponent(charger) // .addComponent(BATTERY) // @@ -272,6 +283,7 @@ public void testEmsPowerModeAutoWithSurplus() throws Exception { .setFeedPowerPara(3000) // .setFeedInPowerSettings(FeedInPowerSettings.PU_ENABLE_CURVE) // .setControlMode(ControlMode.SMART) // + .setStartStop(StartStopConfig.START) // .build()) // .next(new TestCase() // .input(METER_COMMUNICATE_STATUS, MeterCommunicateStatus.OK) // @@ -289,6 +301,7 @@ public void testEmsPowerModeAutoWithMaxAcImport() throws Exception { new ComponentTest(ess) // .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("componentManager", new DummyComponentManager()) // .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // .addReference("sum", new DummySum()) // .activate(MyConfig.create() // @@ -302,6 +315,7 @@ public void testEmsPowerModeAutoWithMaxAcImport() throws Exception { .setFeedPowerPara(3000) // .setFeedInPowerSettings(FeedInPowerSettings.PU_ENABLE_CURVE) // .setControlMode(ControlMode.SMART) // + .setStartStop(StartStopConfig.START) // .build()) // .next(new TestCase() // .input(METER_COMMUNICATE_STATUS, MeterCommunicateStatus.OK) // @@ -319,6 +333,7 @@ public void testEmsPowerModeAutoWithMaxAcExport() throws Exception { new ComponentTest(ess) // .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("componentManager", new DummyComponentManager()) // .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // .addReference("sum", new DummySum()) // .activate(MyConfig.create() // @@ -332,6 +347,7 @@ public void testEmsPowerModeAutoWithMaxAcExport() throws Exception { .setFeedPowerPara(3000) // .setFeedInPowerSettings(FeedInPowerSettings.PU_ENABLE_CURVE) // .setControlMode(ControlMode.SMART) // + .setStartStop(StartStopConfig.START) // .build()) // .next(new TestCase() // .input(METER_COMMUNICATE_STATUS, MeterCommunicateStatus.OK) // @@ -349,6 +365,7 @@ public void testBatteryIsFull() throws Exception { new ComponentTest(ess) // .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("componentManager", new DummyComponentManager()) // .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // .addReference("sum", new DummySum()) // .activate(MyConfig.create() // @@ -362,6 +379,7 @@ public void testBatteryIsFull() throws Exception { .setFeedPowerPara(3000) // .setFeedInPowerSettings(FeedInPowerSettings.PU_ENABLE_CURVE) // .setControlMode(ControlMode.SMART) // + .setStartStop(StartStopConfig.START) // .build()) // .next(new TestCase() // .input(METER_COMMUNICATE_STATUS, MeterCommunicateStatus.OK) // @@ -379,6 +397,7 @@ public void testBatteryIsEmpty() throws Exception { new ComponentTest(ess) // .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("componentManager", new DummyComponentManager()) // .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // .addReference("sum", new DummySum()) // .activate(MyConfig.create() // @@ -392,6 +411,7 @@ public void testBatteryIsEmpty() throws Exception { .setFeedPowerPara(3000) // .setFeedInPowerSettings(FeedInPowerSettings.PU_ENABLE_CURVE) // .setControlMode(ControlMode.SMART) // + .setStartStop(StartStopConfig.START) // .build()) // .next(new TestCase() // .input(METER_COMMUNICATE_STATUS, MeterCommunicateStatus.OK) // @@ -409,6 +429,7 @@ public void testAcCalculation() throws Exception { new ComponentTest(ess) // .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("componentManager", new DummyComponentManager()) // .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // .addReference("sum", new DummySum()) // .addComponent(BATTERY).activate(MyConfig.create() // @@ -422,6 +443,7 @@ public void testAcCalculation() throws Exception { .setFeedPowerPara(3000) // .setFeedInPowerSettings(FeedInPowerSettings.PU_ENABLE_CURVE) // .setControlMode(ControlMode.SMART) // + .setStartStop(StartStopConfig.START) // .build()) // .next(new TestCase() // .input(WBMS_CHARGE_MAX_CURRENT, 0) // @@ -504,6 +526,7 @@ public void testTwoStringCharger() throws Exception { new ComponentTest(ess) // .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("componentManager", new DummyComponentManager()) // .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // .addReference("sum", new DummySum()) // .addComponent(charger1) // @@ -520,6 +543,7 @@ public void testTwoStringCharger() throws Exception { .setFeedPowerPara(3000) // .setFeedInPowerSettings(FeedInPowerSettings.PU_ENABLE_CURVE) // .setControlMode(ControlMode.SMART) // + .setStartStop(StartStopConfig.START) // .build()) // .next(new TestCase() // .input(MPPT1_I, 20) // @@ -576,6 +600,7 @@ public void testTwoStringCharger() throws Exception { new ComponentTest(ess) // .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("componentManager", new DummyComponentManager()) // .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // .addReference("sum", new DummySum()) // .addComponent(charger3) // @@ -592,6 +617,7 @@ public void testTwoStringCharger() throws Exception { .setFeedPowerPara(3000) // .setFeedInPowerSettings(FeedInPowerSettings.PU_ENABLE_CURVE) // .setControlMode(ControlMode.SMART) // + .setStartStop(StartStopConfig.START) // .build()) // .next(new TestCase() // .input(MPPT2_I, 20) // @@ -648,6 +674,7 @@ public void testTwoStringCharger() throws Exception { new ComponentTest(ess) // .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("componentManager", new DummyComponentManager()) // .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // .addReference("sum", new DummySum()) // .addComponent(charger5) // @@ -664,6 +691,7 @@ public void testTwoStringCharger() throws Exception { .setFeedPowerPara(3000) // .setFeedInPowerSettings(FeedInPowerSettings.PU_ENABLE_CURVE) // .setControlMode(ControlMode.SMART) // + .setStartStop(StartStopConfig.START) // .build()) // .next(new TestCase() // .input(MPPT3_I, 20) // diff --git a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/batteryinverter/MyConfig.java b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/batteryinverter/MyConfig.java index 5d5a2db41ee..8c8fe64615f 100644 --- a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/batteryinverter/MyConfig.java +++ b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/batteryinverter/MyConfig.java @@ -2,6 +2,7 @@ import io.openems.common.test.AbstractComponentConfig; import io.openems.common.utils.ConfigUtils; +import io.openems.edge.common.startstop.StartStopConfig; import io.openems.edge.goodwe.common.enums.ControlMode; import io.openems.edge.goodwe.common.enums.EnableDisable; import io.openems.edge.goodwe.common.enums.FeedInPowerSettings; @@ -22,6 +23,7 @@ public static class Builder { private int feedPowerPara; private FeedInPowerSettings feedInPowerSettings; private EnableDisable rcrEnable = EnableDisable.DISABLE; + private StartStopConfig startStop; private Builder() { } @@ -81,6 +83,11 @@ public Builder setRcrEnable(EnableDisable rcrEnable) { return this; } + public Builder setStartStop(StartStopConfig startStop) { + this.startStop = startStop; + return this; + } + public MyConfig build() { return new MyConfig(this); } @@ -156,4 +163,9 @@ public ControlMode controlMode() { public EnableDisable rcrEnable() { return this.builder.rcrEnable; } + + @Override + public StartStopConfig startStop() { + return this.builder.startStop; + } } \ No newline at end of file diff --git a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/mppt/twostring/GoodWeChargerMpptTwoStringImplTest.java b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/mppt/twostring/GoodWeChargerMpptTwoStringImplTest.java index 9ba2a25098a..591db516cd4 100644 --- a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/mppt/twostring/GoodWeChargerMpptTwoStringImplTest.java +++ b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/mppt/twostring/GoodWeChargerMpptTwoStringImplTest.java @@ -6,9 +6,11 @@ import io.openems.edge.battery.api.Battery; import io.openems.edge.battery.test.DummyBattery; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; +import io.openems.edge.common.startstop.StartStopConfig; import io.openems.edge.common.sum.DummySum; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.common.test.DummyConfigurationAdmin; import io.openems.edge.ess.test.DummyPower; import io.openems.edge.goodwe.GoodWeConstants; @@ -98,6 +100,7 @@ public void test() throws Exception { new ComponentTest(ess) // .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("componentManager", new DummyComponentManager()) // .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // .addReference("sum", new DummySum()) // .addComponent(charger1) // @@ -115,6 +118,7 @@ public void test() throws Exception { .setFeedPowerPara(3000) // .setFeedInPowerSettings(FeedInPowerSettings.PU_ENABLE_CURVE) // .setControlMode(ControlMode.SMART) // + .setStartStop(StartStopConfig.START) // .build()) // .next(new TestCase() // .input(MPPT1_I, 20) // diff --git a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/common/TestStatic.java b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/common/TestStatic.java index b0a95889b3e..65fe2da9a22 100644 --- a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/common/TestStatic.java +++ b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/common/TestStatic.java @@ -5,6 +5,9 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicBoolean; + import org.junit.Test; import io.openems.edge.goodwe.common.enums.GoodWeType; @@ -126,4 +129,65 @@ public void testDetectActiveDiagStatesH() { assertFalse(AbstractGoodWe.detectDiagStatesH(value) // .get(GoodWe.ChannelId.DIAG_STATUS_EXTERNAL_STOP_MODE_ENABLE)); } + + @Test + public void testPostprocessPBattery1() { + + AtomicBoolean stateResult = new AtomicBoolean(); + Optional prevPBattery = Optional.of(5000); + + // Max DC Power: 5750W + var pBattery = 200_000; + var dcVoltage = 230; + var dcMaxCurrent = 25; + + assertEquals(prevPBattery.get(), AbstractGoodWe.postprocessPBattery1(pBattery, dcVoltage, dcMaxCurrent, + state -> stateResult.set(state), prevPBattery)); // + assertTrue(stateResult.get()); + + pBattery = -100_000; + assertEquals(prevPBattery.get(), AbstractGoodWe.postprocessPBattery1(pBattery, dcVoltage, dcMaxCurrent, + state -> stateResult.set(state), prevPBattery)); // + assertTrue(stateResult.get()); + + pBattery = 4000; + assertEquals(4000, (int) AbstractGoodWe.postprocessPBattery1(pBattery, dcVoltage, dcMaxCurrent, + state -> stateResult.set(state), prevPBattery)); // + assertFalse(stateResult.get()); + + pBattery = -4000; + assertEquals(-4000, (int) AbstractGoodWe.postprocessPBattery1(pBattery, dcVoltage, dcMaxCurrent, + state -> stateResult.set(state), prevPBattery)); // + assertFalse(stateResult.get()); + + /* + * One of the given values is null + */ + assertEquals(-100_000, (int) AbstractGoodWe.postprocessPBattery1(-100_000, null, dcMaxCurrent, + state -> stateResult.set(state), prevPBattery)); // + assertFalse(stateResult.get()); + + assertEquals(-100_000, (int) AbstractGoodWe.postprocessPBattery1(-100_000, dcVoltage, null, + state -> stateResult.set(state), prevPBattery)); // + assertFalse(stateResult.get()); + + Integer pBatteryNull = null; + assertEquals(null, AbstractGoodWe.postprocessPBattery1(pBatteryNull, dcVoltage, dcMaxCurrent, + state -> stateResult.set(state), prevPBattery)); // + assertFalse(stateResult.get()); + + /* + * Previous value was null + */ + prevPBattery = Optional.empty(); + pBattery = 200_000; + assertEquals(5750, (int) AbstractGoodWe.postprocessPBattery1(pBattery, dcVoltage, dcMaxCurrent, + state -> stateResult.set(state), prevPBattery)); // + assertTrue(stateResult.get()); + + pBattery = -100_000; + assertEquals(-5750, (int) AbstractGoodWe.postprocessPBattery1(pBattery, dcVoltage, dcMaxCurrent, + state -> stateResult.set(state), prevPBattery)); // + assertTrue(stateResult.get()); + } } diff --git a/io.openems.edge.io.weidmueller/src/io/openems/edge/io/weidmueller/IoWeidmuellerUr20Impl.java b/io.openems.edge.io.weidmueller/src/io/openems/edge/io/weidmueller/IoWeidmuellerUr20Impl.java index fdceb8c3564..e1e444fbc73 100644 --- a/io.openems.edge.io.weidmueller/src/io/openems/edge/io/weidmueller/IoWeidmuellerUr20Impl.java +++ b/io.openems.edge.io.weidmueller/src/io/openems/edge/io/weidmueller/IoWeidmuellerUr20Impl.java @@ -30,6 +30,7 @@ import io.openems.edge.bridge.modbus.api.ModbusComponent; import io.openems.edge.bridge.modbus.api.ModbusProtocol; import io.openems.edge.bridge.modbus.api.ModbusUtils; +import io.openems.edge.bridge.modbus.api.ModbusUtils.ReadElementsResult; import io.openems.edge.bridge.modbus.api.element.BitsWordElement; import io.openems.edge.bridge.modbus.api.element.CoilElement; import io.openems.edge.bridge.modbus.api.element.ModbusRegisterElement; @@ -231,7 +232,8 @@ private CompletableFuture> readCurrentModuleList(int numberOfEntries) .map(index -> 0x2A00 + index * 2) // .mapToObj(address -> new UnsignedDoublewordElement(address)) // .toArray(ModbusRegisterElement[]::new); - return readElementsOnce(this.modbusProtocol, ModbusUtils::retryOnNull, elements); + return readElementsOnce(this.modbusProtocol, ModbusUtils::retryOnNull, elements) // + .thenApply(rsr -> ((ReadElementsResult) rsr).values()); } } diff --git a/io.openems.edge.timeofusetariff.rabotcharge/.classpath b/io.openems.edge.timeofusetariff.rabotcharge/.classpath new file mode 100644 index 00000000000..bbfbdbe40e7 --- /dev/null +++ b/io.openems.edge.timeofusetariff.rabotcharge/.classpath @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/io.openems.edge.timeofusetariff.rabotcharge/.gitignore b/io.openems.edge.timeofusetariff.rabotcharge/.gitignore new file mode 100644 index 00000000000..c2b941a96de --- /dev/null +++ b/io.openems.edge.timeofusetariff.rabotcharge/.gitignore @@ -0,0 +1,2 @@ +/bin_test/ +/generated/ diff --git a/io.openems.edge.timeofusetariff.rabotcharge/.project b/io.openems.edge.timeofusetariff.rabotcharge/.project new file mode 100644 index 00000000000..4a2faba62b4 --- /dev/null +++ b/io.openems.edge.timeofusetariff.rabotcharge/.project @@ -0,0 +1,23 @@ + + + io.openems.edge.timeofusetariff.rabotcharge + + + + + + org.eclipse.jdt.core.javabuilder + + + + + bndtools.core.bndbuilder + + + + + + org.eclipse.jdt.core.javanature + bndtools.core.bndnature + + diff --git a/io.openems.edge.timeofusetariff.rabotcharge/.settings/org.eclipse.core.resources.prefs b/io.openems.edge.timeofusetariff.rabotcharge/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 00000000000..896a9a53a53 --- /dev/null +++ b/io.openems.edge.timeofusetariff.rabotcharge/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 \ No newline at end of file diff --git a/io.openems.edge.timeofusetariff.rabotcharge/bnd.bnd b/io.openems.edge.timeofusetariff.rabotcharge/bnd.bnd new file mode 100644 index 00000000000..48ebeaea459 --- /dev/null +++ b/io.openems.edge.timeofusetariff.rabotcharge/bnd.bnd @@ -0,0 +1,14 @@ +Bundle-Name: OpenEMS Edge Time-Of-Use Tariff rabot.charge +Bundle-Vendor: FENECON GmbH +Bundle-License: https://opensource.org/licenses/EPL-2.0 +Bundle-Version: 1.0.0.${tstamp} + +-buildpath: \ + ${buildpath},\ + io.openems.common,\ + io.openems.edge.bridge.http,\ + io.openems.edge.common,\ + io.openems.edge.timeofusetariff.api,\ + +-testpath: \ + ${testpath} \ No newline at end of file diff --git a/io.openems.edge.timeofusetariff.rabotcharge/readme.adoc b/io.openems.edge.timeofusetariff.rabotcharge/readme.adoc new file mode 100644 index 00000000000..f2034d937ad --- /dev/null +++ b/io.openems.edge.timeofusetariff.rabotcharge/readme.adoc @@ -0,0 +1,5 @@ += Time-Of-Use Tariff rabot.charge + +Retrieves the hourly prices from the rabot.charge API and converts them into quarterly prices. + +https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.timeofusetariff.rabotcharge[Source Code icon:github[]] \ No newline at end of file diff --git a/io.openems.edge.timeofusetariff.rabotcharge/src/io/openems/edge/timeofusetariff/rabotcharge/Config.java b/io.openems.edge.timeofusetariff.rabotcharge/src/io/openems/edge/timeofusetariff/rabotcharge/Config.java new file mode 100644 index 00000000000..3074a7be4a0 --- /dev/null +++ b/io.openems.edge.timeofusetariff.rabotcharge/src/io/openems/edge/timeofusetariff/rabotcharge/Config.java @@ -0,0 +1,25 @@ +package io.openems.edge.timeofusetariff.rabotcharge; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.AttributeType; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +@ObjectClassDefinition(// + name = "Time-Of-Use Tariff rabot.charge", // + description = "Time-Of-Use Tariff implementation for rabot.charge.") +@interface Config { + + @AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component") + String id() default "timeOfUseTariff0"; + + @AttributeDefinition(name = "Alias", description = "Human-readable name of this Component; defaults to Component-ID") + String alias() default ""; + + @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?") + boolean enabled() default true; + + @AttributeDefinition(name = "Access Token", description = "Access token for rabot.charge API", type = AttributeType.PASSWORD) + String accessToken() default ""; + + String webconsole_configurationFactory_nameHint() default "Time-Of-Use Tariff rabot.charge [{id}]"; +} diff --git a/io.openems.edge.timeofusetariff.rabotcharge/src/io/openems/edge/timeofusetariff/rabotcharge/TimeOfUseTariffRabotCharge.java b/io.openems.edge.timeofusetariff.rabotcharge/src/io/openems/edge/timeofusetariff/rabotcharge/TimeOfUseTariffRabotCharge.java new file mode 100644 index 00000000000..cfb8faa495e --- /dev/null +++ b/io.openems.edge.timeofusetariff.rabotcharge/src/io/openems/edge/timeofusetariff/rabotcharge/TimeOfUseTariffRabotCharge.java @@ -0,0 +1,26 @@ +package io.openems.edge.timeofusetariff.rabotcharge; + +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.timeofusetariff.api.TimeOfUseTariff; + +public interface TimeOfUseTariffRabotCharge extends TimeOfUseTariff, OpenemsComponent { + + public enum ChannelId implements io.openems.edge.common.channel.ChannelId { + HTTP_STATUS_CODE(Doc.of(OpenemsType.INTEGER)// + .text("Displays the HTTP status code"))// + ; + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } +} diff --git a/io.openems.edge.timeofusetariff.rabotcharge/src/io/openems/edge/timeofusetariff/rabotcharge/TimeOfUseTariffRabotChargeImpl.java b/io.openems.edge.timeofusetariff.rabotcharge/src/io/openems/edge/timeofusetariff/rabotcharge/TimeOfUseTariffRabotChargeImpl.java new file mode 100644 index 00000000000..0156dfa039f --- /dev/null +++ b/io.openems.edge.timeofusetariff.rabotcharge/src/io/openems/edge/timeofusetariff/rabotcharge/TimeOfUseTariffRabotChargeImpl.java @@ -0,0 +1,212 @@ +package io.openems.edge.timeofusetariff.rabotcharge; + +import static io.openems.common.utils.JsonUtils.getAsDouble; +import static io.openems.common.utils.JsonUtils.getAsJsonArray; +import static io.openems.common.utils.JsonUtils.getAsString; +import static io.openems.common.utils.JsonUtils.parseToJsonObject; +import static io.openems.edge.timeofusetariff.api.utils.TimeOfUseTariffUtils.generateDebugLog; + +import java.time.Clock; +import java.time.Duration; +import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; +import java.util.Map; +import java.util.TreeMap; +import java.util.concurrent.atomic.AtomicReference; + +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.metatype.annotations.Designate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.bridge.http.api.BridgeHttp; +import io.openems.edge.bridge.http.api.BridgeHttp.Endpoint; +import io.openems.edge.bridge.http.api.BridgeHttpFactory; +import io.openems.edge.bridge.http.api.HttpMethod; +import io.openems.edge.bridge.http.time.DelayTimeProvider; +import io.openems.edge.bridge.http.time.DelayTimeProviderChain; +import io.openems.edge.common.component.AbstractOpenemsComponent; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.meta.Meta; +import io.openems.edge.timeofusetariff.api.TimeOfUsePrices; +import io.openems.edge.timeofusetariff.api.TimeOfUseTariff; + +@Designate(ocd = Config.class, factory = true) +@Component(// + name = "TimeOfUseTariff.RabotCharge", // + immediate = true, // + configurationPolicy = ConfigurationPolicy.REQUIRE // +) +public class TimeOfUseTariffRabotChargeImpl extends AbstractOpenemsComponent + implements TimeOfUseTariff, OpenemsComponent, TimeOfUseTariffRabotCharge { + + private static final String RABOT_CHARGE_API_URL = "https://api.rabot-charge.de/api/day-ahead-prices-limited"; + private static final int API_EXECUTE_HOUR = 14; + + private final Logger log = LoggerFactory.getLogger(TimeOfUseTariffRabotChargeImpl.class); + private final AtomicReference prices = new AtomicReference<>(TimeOfUsePrices.EMPTY_PRICES); + private String accessToken; + + @Reference + private Meta meta; + + @Reference + private ComponentManager componentManager; + + @Reference + private BridgeHttpFactory httpBridgeFactory; + private BridgeHttp httpBridge; + + public TimeOfUseTariffRabotChargeImpl() { + super(// + OpenemsComponent.ChannelId.values(), // + TimeOfUseTariffRabotCharge.ChannelId.values() // + ); + } + + @Activate + private void activate(ComponentContext context, Config config) { + super.activate(context, config.id(), config.alias(), config.enabled()); + + if (!config.enabled()) { + return; + } + + if (config.accessToken() == null || config.accessToken().isEmpty()) { + return; + } + + this.accessToken = config.accessToken(); + this.httpBridge = this.httpBridgeFactory.get(); + this.httpBridge.subscribeTime(new RabotChargeDelayTimeProvider(this.componentManager.getClock()), // + this.createRabotChargeEndpoint(), // + this::handleEndpointResponse, // + this::handleEndpointError); + } + + public static class RabotChargeDelayTimeProvider implements DelayTimeProvider { + + private final Clock clock; + + public RabotChargeDelayTimeProvider(Clock clock) { + super(); + this.clock = clock; + } + + @Override + public Duration nextRun(boolean firstRun, boolean lastRunSuccessful) { + if (firstRun) { + return Duration.ZERO; + } + + if (!lastRunSuccessful) { + return DelayTimeProviderChain.fixedDelay(Duration.ofHours(1))// + .plusRandomDelay(60, ChronoUnit.SECONDS) // + .getDelay(); + } + + var now = ZonedDateTime.now(this.clock).truncatedTo(ChronoUnit.HOURS); + ZonedDateTime nextRun; + + if (now.getHour() < API_EXECUTE_HOUR) { + nextRun = now.withHour(API_EXECUTE_HOUR); + } else { + nextRun = now.plusDays(1).withHour(API_EXECUTE_HOUR); + } + + return DelayTimeProviderChain.fixedDelay(Duration.between(now, nextRun)) + .plusRandomDelay(60, ChronoUnit.SECONDS) // + .getDelay(); + } + } + + private Endpoint createRabotChargeEndpoint() { + + return new Endpoint(RABOT_CHARGE_API_URL, // + HttpMethod.POST, // + BridgeHttp.DEFAULT_CONNECT_TIMEOUT, // + BridgeHttp.DEFAULT_READ_TIMEOUT, // + this.buildRequestBody(), // + this.buildRequestHeaders()); + } + + private String buildRequestBody() { + return JsonUtils.buildJsonObject() // + .build().toString(); + } + + private Map buildRequestHeaders() { + return Map.of(// + "Authorization", "Bearer " + this.accessToken, // + "Content-Type", "application/json" // + ); + + } + + private void handleEndpointResponse(String response) throws OpenemsNamedException { + // TODO + // Add response code to the channel once HttpError and HttpResponse is merged in + // develop. + + // Parse the response for the prices + this.prices.set(parsePrices(response)); + } + + private void handleEndpointError(Throwable error) { + this.log.error(error.getMessage(), error); + } + + @Override + @Deactivate + protected void deactivate() { + super.deactivate(); + this.httpBridgeFactory.unget(this.httpBridge); + } + + @Override + public TimeOfUsePrices getPrices() { + return TimeOfUsePrices.from(ZonedDateTime.now(), this.prices.get()); + } + + /** + * Parse the JSON to {@link TimeOfUsePrices}. + * + * @param jsonData the JSON + * @return the {@link TimeOfUsePrices} + * @throws OpenemsNamedException on error + */ + public static TimeOfUsePrices parsePrices(String jsonData) throws OpenemsNamedException { + var result = new TreeMap(); + var data = getAsJsonArray(parseToJsonObject(jsonData), "records"); + for (var element : data) { + // Cent/kWh -> Currency/MWh + // Example: 12 Cent/kWh => 0.12 EUR/kWh * 1000 kWh/MWh = 120 EUR/MWh. + var marketPrice = getAsDouble(element, "price_inCentPerKwh") * 10; + + // Converting time string to ZonedDateTime. + var startTimeStamp = ZonedDateTime // + .parse(getAsString(element, "moment")) // + .truncatedTo(ChronoUnit.HOURS); + + // Adding the values in the Map. + result.put(startTimeStamp, marketPrice); + result.put(startTimeStamp.plusMinutes(15), marketPrice); + result.put(startTimeStamp.plusMinutes(30), marketPrice); + result.put(startTimeStamp.plusMinutes(45), marketPrice); + } + return TimeOfUsePrices.from(result); + } + + @Override + public String debugLog() { + return generateDebugLog(this, this.meta.getCurrency()); + } +} diff --git a/io.openems.edge.timeofusetariff.rabotcharge/test/.gitignore b/io.openems.edge.timeofusetariff.rabotcharge/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.timeofusetariff.rabotcharge/test/io/openems/edge/timeofusetariff/rabotcharge/MyConfig.java b/io.openems.edge.timeofusetariff.rabotcharge/test/io/openems/edge/timeofusetariff/rabotcharge/MyConfig.java new file mode 100644 index 00000000000..f408845325b --- /dev/null +++ b/io.openems.edge.timeofusetariff.rabotcharge/test/io/openems/edge/timeofusetariff/rabotcharge/MyConfig.java @@ -0,0 +1,51 @@ +package io.openems.edge.timeofusetariff.rabotcharge; + +import io.openems.common.test.AbstractComponentConfig; + +@SuppressWarnings("all") +public class MyConfig extends AbstractComponentConfig implements Config { + + public static class Builder { + private String id; + private String accessToken; + + private Builder() { + } + + public Builder setId(String id) { + this.id = id; + return this; + } + + public Builder setAccessToken(String accessToken) { + this.accessToken = accessToken; + return this; + } + + public MyConfig build() { + return new MyConfig(this); + } + } + + /** + * Create a Config builder. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new Builder(); + } + + private final Builder builder; + + private MyConfig(Builder builder) { + super(Config.class, builder.id); + this.builder = builder; + } + + @Override + public String accessToken() { + return this.builder.accessToken; + } + +} \ No newline at end of file diff --git a/io.openems.edge.timeofusetariff.rabotcharge/test/io/openems/edge/timeofusetariff/rabotcharge/TimeOfUseTariffRabotChargeImplTest.java b/io.openems.edge.timeofusetariff.rabotcharge/test/io/openems/edge/timeofusetariff/rabotcharge/TimeOfUseTariffRabotChargeImplTest.java new file mode 100644 index 00000000000..e2a60c609dd --- /dev/null +++ b/io.openems.edge.timeofusetariff.rabotcharge/test/io/openems/edge/timeofusetariff/rabotcharge/TimeOfUseTariffRabotChargeImplTest.java @@ -0,0 +1,126 @@ +package io.openems.edge.timeofusetariff.rabotcharge; + +import static io.openems.edge.timeofusetariff.rabotcharge.TimeOfUseTariffRabotChargeImpl.parsePrices; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThrows; + +import java.time.Instant; +import java.time.ZoneOffset; + +import org.junit.Test; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.test.TimeLeapClock; +import io.openems.edge.bridge.http.dummy.DummyBridgeHttpFactory; +import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.common.test.DummyComponentManager; + +public class TimeOfUseTariffRabotChargeImplTest { + + private static final String CTRL_ID = "ctrl0"; + + @Test + public void test() throws Exception { + final TimeLeapClock clock = new TimeLeapClock(Instant.parse("2020-01-01T01:00:00.00Z"), ZoneOffset.UTC); + final DummyComponentManager cm = new DummyComponentManager(clock); + var rabotCharge = new TimeOfUseTariffRabotChargeImpl(); + new ComponentTest(rabotCharge) // + .addReference("httpBridgeFactory", new DummyBridgeHttpFactory()) // + .addReference("componentManager", cm) // + .activate(MyConfig.create() // + .setId(CTRL_ID) // + .setAccessToken("foo-bar") // + .build()) // + ; + } + + @Test + public void nonEmptyStringTest() throws OpenemsNamedException { + // Parsing with custom data + var prices = parsePrices(""" + { + "records": [ + { + "moment": "2024-05-14T09:00:00+02:00", + "price_inCentPerKwh": 0.564 + }, + { + "moment": "2024-05-14T10:00:00+02:00", + "price_inCentPerKwh": -0.233 + }, + { + "moment": "2024-05-14T11:00:00+02:00", + "price_inCentPerKwh": -1.112 + }, + { + "moment": "2024-05-14T12:00:00+02:00", + "price_inCentPerKwh": -3.633 + }, + { + "moment": "2024-05-14T13:00:00+02:00", + "price_inCentPerKwh": -4.295 + }, + { + "moment": "2024-05-14T14:00:00+02:00", + "price_inCentPerKwh": -3.966 + }, + { + "moment": "2024-05-14T15:00:00+02:00", + "price_inCentPerKwh": -1.986 + }, + { + "moment": "2024-05-14T16:00:00+02:00", + "price_inCentPerKwh": -0.293 + }, + { + "moment": "2024-05-14T17:00:00+02:00", + "price_inCentPerKwh": -0.004 + }, + { + "moment": "2024-05-14T18:00:00+02:00", + "price_inCentPerKwh": 4.374 + }, + { + "moment": "2024-05-14T19:00:00+02:00", + "price_inCentPerKwh": 8.390 + }, + { + "moment": "2024-05-14T20:00:00+02:00", + "price_inCentPerKwh": 9.347 + }, + { + "moment": "2024-05-14T21:00:00+02:00", + "price_inCentPerKwh": 7.641 + }, + { + "moment": "2024-05-14T22:00:00+02:00", + "price_inCentPerKwh": 4.535 + }, + { + "moment": "2024-05-14T23:00:00+02:00", + "price_inCentPerKwh": 2.771 + } + ], + "success": true, + "metadata": { + "messages": [], + "maintenanceMode": null + } + + }"""); // + + // To check if the Map is not empty + assertFalse(prices.isEmpty()); + + // To check if a value is present in map. + assertEquals(5.64, prices.getFirst(), 0.001); + } + + @Test + public void emptyStringTest() throws OpenemsNamedException { + assertThrows(OpenemsNamedException.class, () -> { + parsePrices(""); + }); + } +} diff --git a/io.openems.wrapper/retrofit2.bnd b/io.openems.wrapper/retrofit2.bnd index bb1a32d18ad..3eeec546637 100644 --- a/io.openems.wrapper/retrofit2.bnd +++ b/io.openems.wrapper/retrofit2.bnd @@ -33,3 +33,5 @@ Import-Package: \ -metatypeannotations: * -sources: false + +-fixupmessages "Classes found in the wrong directory" diff --git a/tools/common.sh b/tools/common.sh index 598a8341fb5..c5ee2450f1f 100644 --- a/tools/common.sh +++ b/tools/common.sh @@ -62,6 +62,13 @@ common_update_version_in_code() { sed --in-place "s#\(UI_VERSION = \"\).*\(\";\)#\1$VERSION\2#" $SRC_CHANGELOG_CONSTANTS } +# Build OpenEMS Backend +common_build_backend() { + echo "# Build OpenEMS Backend" + ./gradlew $@ --build-cache build buildBackend resolve.BackendApp + git diff --exit-code io.openems.backend.application/BackendApp.bndrun +} + # Build OpenEMS Edge and UI in parallel common_build_edge_and_ui_in_parallel() { # TODO use 'parallel' tool for reliable implementation @@ -76,6 +83,12 @@ common_build_edge() { git diff --exit-code io.openems.edge.application/EdgeApp.bndrun io.openems.backend.application/BackendApp.bndrun } +# Run OpenEMS Checkstyle +common_run_checkstyle() { + echo "# Run Checkstyle" + ./gradlew $@ checkstyleAll +} + # Build OpenEMS UI common_build_ui() { echo "# Build OpenEMS UI" diff --git a/tools/debian/etc/apt/apt.conf.d/99nodoc b/tools/debian/etc/apt/apt.conf.d/99nodoc new file mode 100644 index 00000000000..7b23b8f5a90 --- /dev/null +++ b/tools/debian/etc/apt/apt.conf.d/99nodoc @@ -0,0 +1,8 @@ +APT::Install-Recommends "0"; +APT::Install-Suggests "0"; +Dpkg::Options { + "--path-exclude=/usr/share/locale/*"; + "--path-exclude=/usr/share/man/*"; + "--path-exclude=/usr/share/doc/*"; + "--path-include=/usr/share/doc/*/copyright"; +}; \ No newline at end of file diff --git a/tools/debian/etc/dpkg/dpkg.cfg.d/01nodoc b/tools/debian/etc/dpkg/dpkg.cfg.d/01nodoc new file mode 100644 index 00000000000..0baaae606b8 --- /dev/null +++ b/tools/debian/etc/dpkg/dpkg.cfg.d/01nodoc @@ -0,0 +1,9 @@ +# Delete locales +path-exclude=/usr/share/locale/*; + +# Delete man pages +path-exclude=/usr/share/man/*; + +# Delete docs +path-exclude=/usr/share/doc/*; +path-include=/usr/share/doc/*/copyright; \ No newline at end of file diff --git a/ui/.eslintrc.json b/ui/.eslintrc.json index 6d53fb393b4..477e5e2c8dd 100644 --- a/ui/.eslintrc.json +++ b/ui/.eslintrc.json @@ -51,6 +51,9 @@ } } ], + "@angular-eslint/use-lifecycle-interface": [ + "error" + ], "@angular-eslint/directive-selector": [ "error", { diff --git a/ui/src/app/app-routing.module.ts b/ui/src/app/app-routing.module.ts index e1f9f03e9b3..4fb3687de15 100644 --- a/ui/src/app/app-routing.module.ts +++ b/ui/src/app/app-routing.module.ts @@ -110,7 +110,7 @@ const routes: Routes = [ { path: 'settings/profile', component: EdgeSettingsProfileComponent }, { path: 'settings/profile/:componentId', component: AliasUpdateComponent }, { path: 'settings/systemexecute', component: EdgeSettingsSystemExecuteComponent }, - { path: 'settings/systemlog', component: EdgeSettingsSystemLogComponent }, + { path: 'settings/systemlog', component: EdgeSettingsSystemLogComponent, data: { navbarTitleToBeTranslated: 'Edge.Config.Index.liveLog' } }, { path: 'settings/system', component: EdgeSettingsSystemComponent, data: { navbarTitleToBeTranslated: 'Edge.Config.Index.SYSTEM' } }, { path: 'settings/app', data: { navbarTitle: environment.edgeShortName + ' Apps' }, component: EdgeSettingsAppIndex }, { path: 'settings/app/install/:appId', component: EdgeSettingsAppInstall }, diff --git a/ui/src/app/app.module.ts b/ui/src/app/app.module.ts index 97e37811918..f76d84f27e3 100644 --- a/ui/src/app/app.module.ts +++ b/ui/src/app/app.module.ts @@ -10,6 +10,7 @@ import { FORMLY_CONFIG } from '@ngx-formly/core'; import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core'; import { CookieService } from 'ngx-cookie-service'; +import { AngularMyDatePickerModule } from '@nodro7/angular-mydatepicker'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { CheckForUpdateService } from './appupdateservice'; @@ -28,7 +29,6 @@ import { StatusSingleComponent } from './shared/status/single/status.component'; import { registerTranslateExtension } from './shared/translate.extension'; import { Language, MyTranslateLoader } from './shared/type/language'; import { UserModule } from './user/user.module'; -import { AngularMyDatePickerModule } from '@nodro7/angular-mydatepicker'; @NgModule({ declarations: [ @@ -47,7 +47,7 @@ import { AngularMyDatePickerModule } from '@nodro7/angular-mydatepicker'; EdgeModule, EdgeSettingsModule, IndexModule, - IonicModule.forRoot(), + IonicModule.forRoot({ innerHTMLTemplatesEnabled: true }), HttpClientModule, SharedModule, TranslateModule.forRoot({ loader: { provide: TranslateLoader, useClass: MyTranslateLoader } }), diff --git a/ui/src/app/edge/edge.component.ts b/ui/src/app/edge/edge.component.ts index 9e4d158846c..f732a106824 100644 --- a/ui/src/app/edge/edge.component.ts +++ b/ui/src/app/edge/edge.component.ts @@ -4,17 +4,21 @@ import { ActivatedRoute, Router } from "@angular/router"; import { SubscribeEdgesRequest } from "src/app/shared/jsonrpc/request/subscribeEdgesRequest"; import { ChannelAddress, Edge, Service, Websocket } from "src/app/shared/shared"; + /*** This component is needed as a routing parent and acts as a transit station without being displayed.*/ @Component({ selector: "edge", template: ` + `, }) export class EdgeComponent implements OnInit, OnDestroy { private edge: Edge | null = null; + protected latestIncident: { message: string | null, id: string } | null = null; constructor( private router: Router, @@ -30,6 +34,8 @@ export class EdgeComponent implements OnInit, OnDestroy { const edgeId = params['edgeId']; this.service.updateCurrentEdge(edgeId).then((edge) => { this.edge = edge; + + this.checkMessages(); this.service.websocket.sendRequest(new SubscribeEdgesRequest({ edges: [edgeId] })) .then(() => { @@ -44,6 +50,9 @@ export class EdgeComponent implements OnInit, OnDestroy { }); } + public checkMessages(): void { + } + public ngOnDestroy(): void { if (!this.edge) { return; diff --git a/ui/src/app/edge/settings/system/maintenance/maintenance.ts b/ui/src/app/edge/settings/system/maintenance/maintenance.ts index 34e27d47c15..05ffad598c8 100644 --- a/ui/src/app/edge/settings/system/maintenance/maintenance.ts +++ b/ui/src/app/edge/settings/system/maintenance/maintenance.ts @@ -9,7 +9,7 @@ import { ExecuteSystemRestartRequest, Type } from 'src/app/shared/jsonrpc/reques import { Role } from 'src/app/shared/type/role'; import { environment } from 'src/environments'; -import { Edge, Service, Utils, Websocket } from '../../../../shared/shared'; +import { Edge, presentAlert, Service, Utils, Websocket } from '../../../../shared/shared'; enum SystemRestartState { INITIAL, // No restart @@ -31,15 +31,13 @@ enum SystemRestartState { }) export class MaintenanceComponent implements OnInit { - private static readonly SELECTOR: string = 'oe-maintenance'; - private static readonly TIMEOUT: number = 3000; protected readonly environment = environment; protected edge: Edge | null = null; protected options: { key: string, message: string, color: 'success' | 'warning' | null, info: string, roleIsAtLeast: Role, button: { disabled: boolean, label: string, callback: () => void } }[] = [ { key: Type.HARD, message: null, color: null, info: this.translate.instant('SETTINGS.SYSTEM_UPDATE.RESTART_WARNING', { system: environment.edgeShortName }), roleIsAtLeast: Role.OWNER, button: { - callback: () => this.presentAlert(Type.HARD), disabled: false, label: this.translate.instant('SETTINGS.SYSTEM_UPDATE.EMS_RESTARTING', { edgeShortName: environment.edgeShortName }), + callback: () => this.confirmationAlert(Type.HARD), disabled: false, label: this.translate.instant('SETTINGS.SYSTEM_UPDATE.EMS_RESTARTING', { edgeShortName: environment.edgeShortName }), }, }, ]; @@ -47,6 +45,17 @@ export class MaintenanceComponent implements OnInit { protected systemRestartState: BehaviorSubject<{ key: Type, state: SystemRestartState }> = new BehaviorSubject({ key: null, state: SystemRestartState.INITIAL }); protected spinnerId: string = MaintenanceComponent.SELECTOR; protected readonly SystemRestartState = SystemRestartState; + protected confirmationAlert: Function = (type: Type) => presentAlert(this.alertCtrl, this.translate, { + message: this.translate.instant('SETTINGS.SYSTEM_UPDATE.RESTART_WARNING', { system: environment.edgeShortName }), + subHeader: this.translate.instant('SETTINGS.SYSTEM_UPDATE.RESTART_CONFIRMATION', { system: environment.edgeShortName }), + buttons: [{ + text: this.translate.instant('General.RESTART'), + handler: () => this.execRestart(type), + }], + }); + + private static readonly SELECTOR: string = 'oe-maintenance'; + private static readonly TIMEOUT: number = 3000; constructor( protected utils: Utils, diff --git a/ui/src/app/edge/settings/system/oe-system-update.component.html b/ui/src/app/edge/settings/system/oe-system-update.component.html index 8d72981632f..a4d54cc1894 100644 --- a/ui/src/app/edge/settings/system/oe-system-update.component.html +++ b/ui/src/app/edge/settings/system/oe-system-update.component.html @@ -146,7 +146,7 @@ - {{ + {{ 'SETTINGS.SYSTEM_UPDATE.NEW_VERSION_INSTALLING'| translate }} diff --git a/ui/src/app/edge/settings/system/oe-system-update.component.ts b/ui/src/app/edge/settings/system/oe-system-update.component.ts index fe7847136fc..f76d9d9725f 100644 --- a/ui/src/app/edge/settings/system/oe-system-update.component.ts +++ b/ui/src/app/edge/settings/system/oe-system-update.component.ts @@ -1,6 +1,8 @@ // @ts-strict-ignore import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'; -import { Edge, Service, Websocket } from 'src/app/shared/shared'; +import { AlertController } from '@ionic/angular'; +import { TranslateService } from '@ngx-translate/core'; +import { Edge, presentAlert, Service, Websocket } from 'src/app/shared/shared'; import { environment } from 'src/environments'; import { ExecuteSystemUpdate } from './executeSystemUpdate'; import { SystemUpdateState } from './getSystemUpdateStateResponse'; @@ -11,21 +13,31 @@ import { SystemUpdateState } from './getSystemUpdateStateResponse'; }) export class OeSystemUpdateComponent implements OnInit, OnDestroy { - private static readonly SELECTOR = "oe-system-update"; - public readonly spinnerId: string = OeSystemUpdateComponent.SELECTOR; - + @Output() public stateChanged: EventEmitter = new EventEmitter(); @Input() public executeUpdateInstantly: boolean = false; @Input() public edge: Edge; public readonly environment = environment; - protected executeUpdate: ExecuteSystemUpdate = null; + public readonly spinnerId: string = OeSystemUpdateComponent.SELECTOR; + protected executeUpdate: ExecuteSystemUpdate = null; protected isWaiting: boolean; + protected confirmationAlert: Function = () => presentAlert(this.alertCtrl, this.translate, { + message: this.translate.instant('SETTINGS.SYSTEM_UPDATE.WARNING', { system: environment.edgeShortName }), + subHeader: this.translate.instant('SETTINGS.SYSTEM_UPDATE.SUB_HEADER'), + buttons: [{ + text: this.translate.instant('SETTINGS.SYSTEM_UPDATE.UPDATE_EXECUTE'), + handler: () => this.executeSystemUpdate(), + }], + }); - @Output() public stateChanged: EventEmitter = new EventEmitter(); + private static readonly SELECTOR = "oe-system-update"; constructor( private websocket: Websocket, - private service: Service) { } + private service: Service, + private alertCtrl: AlertController, + private translate: TranslateService, + ) { } ngOnInit() { this.executeUpdate = new ExecuteSystemUpdate(this.edge, this.websocket); diff --git a/ui/src/app/edge/settings/systemlog/systemlog.component.html b/ui/src/app/edge/settings/systemlog/systemlog.component.html index 301bd7f72df..37919bc7547 100644 --- a/ui/src/app/edge/settings/systemlog/systemlog.component.html +++ b/ui/src/app/edge/settings/systemlog/systemlog.component.html @@ -10,15 +10,52 @@ - - - - Edge.Config.Log.automaticUpdating - + + + + + + + Edge.Config.Log.automaticUpdating + + + + + + + Edge.Config.Log.CONDENSED_OUTPUT + + + + + {{filters.placeholder}} + + + {{filter.name}} + + + + + + + + + + + + + + + - - + + + {{ line.time }} @@ -32,7 +69,7 @@ - {{ line.message }} + @@ -42,4 +79,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/settings/systemlog/systemlog.component.ts b/ui/src/app/edge/settings/systemlog/systemlog.component.ts index 2785a1df4b7..b062294443c 100644 --- a/ui/src/app/edge/settings/systemlog/systemlog.component.ts +++ b/ui/src/app/edge/settings/systemlog/systemlog.component.ts @@ -1,11 +1,36 @@ -// @ts-strict-ignore -import { ActivatedRoute } from '@angular/router'; import { Component, OnDestroy, OnInit } from '@angular/core'; +import { SelectCustomEvent } from '@ionic/angular'; +import { TranslateService } from '@ngx-translate/core'; import { parse } from 'date-fns'; -import { Service, Utils, Websocket } from '../../../shared/shared'; import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; -import { TranslateService } from '@ngx-translate/core'; +import { filter, take, takeUntil } from 'rxjs/operators'; +import { Filter } from 'src/app/index/filter/filter.component'; + +import { Service, Utils, Websocket } from '../../../shared/shared'; +import { Role } from 'src/app/shared/type/role'; + +export const LOG_LEVEL_FILTER = (translate: TranslateService): Filter => ({ + placeholder: translate.instant("Edge.Config.Log.level"), + category: "level", + options: [ + { + name: 'Debug', + value: "DEBUG", + }, + { + name: translate.instant('General.info'), + value: "INFO", + }, + { + name: translate.instant('General.warning'), + value: "WARN", + }, + { + name: translate.instant("General.fault"), + value: "ERROR", + }, + ], +}); @Component({ selector: SystemLogComponent.SELECTOR, @@ -13,21 +38,31 @@ import { TranslateService } from '@ngx-translate/core'; }) export class SystemLogComponent implements OnInit, OnDestroy { + public isSubscribed: boolean = false; + + /** Displayed loglines */ + protected logLines: typeof this._logLines = []; + protected query: string | null = null; + protected filters: Filter = LOG_LEVEL_FILTER(this.translate); + protected isCondensedOutput: boolean | null = null; + protected isAtLeastGuest: boolean = false; + private static readonly SELECTOR = "systemLog"; + private ngUnsubscribe = new Subject(); + private searchParams: string[] | null = null; + private MAX_LOG_ENTRIES = 200; + private static readonly DEBUG_LOG_CONTROLLER_ID = 'ctrlDebugLog0'; - public lines: { + /** Original loglines */ + private _logLines: { time: string, level: string, color: string, message: string, source: string }[] = []; - public isSubscribed: boolean = false; - private MAX_LOG_ENTRIES = 200; - private ngUnsubscribe = new Subject(); constructor( - private route: ActivatedRoute, protected utils: Utils, private websocket: Websocket, private service: Service, @@ -36,8 +71,23 @@ export class SystemLogComponent implements OnInit, OnDestroy { } ngOnInit() { - this.service.setCurrentComponent({ languageKey: 'Edge.Config.Index.liveLog' }, this.route); this.subscribe(); + + this.service.getCurrentEdge().then(edge => { + this.isAtLeastGuest = !edge.roleIsAtLeast(Role.OWNER); + edge.getConfig(this.websocket).pipe(filter(config => !!config), take(1)) + .subscribe(config => { + const component = config.getComponent(SystemLogComponent.DEBUG_LOG_CONTROLLER_ID); + + if (!component) { + this.isCondensedOutput = null; + } + + if (component.properties?.condensedOutput != null) { + this.isCondensedOutput = component.properties?.condensedOutput; + } + }); + }); } ngOnDestroy() { @@ -52,10 +102,22 @@ export class SystemLogComponent implements OnInit, OnDestroy { } } + protected toggleCondensedOutput(event: CustomEvent) { + this.service.currentEdge.pipe(filter(edge => !!edge), take(1)) + .subscribe(edge => + edge.updateComponentConfig(this.websocket, SystemLogComponent.DEBUG_LOG_CONTROLLER_ID, [{ + name: 'condensedOutput', value: event.detail['checked'], + }]).then(() => { + this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); + }).catch((reason) => { + this.service.toast(this.translate.instant('General.changeFailed') + '\n' + reason.error.message, 'danger'); + })); + } + public subscribe() { // put placeholder - if (this.lines.length > 0) { - this.lines.unshift({ + if (this.logLines.length > 0) { + this.logLines.unshift({ time: "-------------------", level: "----", color: "black", @@ -77,25 +139,27 @@ export class SystemLogComponent implements OnInit, OnDestroy { edge.systemLog.pipe( takeUntil(this.ngUnsubscribe), ).subscribe(line => { + // add line - this.lines.unshift({ + this._logLines.unshift({ time: parse(line.time, "yyyy-MM-dd'T'HH:mm:ss.SSSxxx", new Date()).toLocaleString(), color: this.getColor(line.level), level: line.level, source: line.source, - message: line.message, + message: line.message.replace(/\n/g, "
    "), }); + this.filterLogs(); // remove old lines - if (this.lines.length > this.MAX_LOG_ENTRIES) { - this.lines.length = this.MAX_LOG_ENTRIES; + if (this._logLines.length > this.MAX_LOG_ENTRIES) { + this._logLines.length = this.MAX_LOG_ENTRIES; } }); }); this.isSubscribed = true; } - private getColor(level): string { + private getColor(level: 'INFO' | 'WARN' | 'DEBUG' | 'ERROR'): string { switch (level) { case 'INFO': return 'green'; @@ -105,8 +169,9 @@ export class SystemLogComponent implements OnInit, OnDestroy { return 'gray'; case 'ERROR': return 'red'; + default: + return 'black'; } - return 'black'; } public unsubscribe() { @@ -117,4 +182,49 @@ export class SystemLogComponent implements OnInit, OnDestroy { this.ngUnsubscribe.complete(); this.ngUnsubscribe = new Subject(); } + + /** + * Search on change, triggered by searchbar input-event. + * + * @param event from template passed event + */ + protected searchOnChange(searchParams?: SelectCustomEvent): void { + + if (searchParams) { + this.searchParams = searchParams?.target?.value ?? null; + } + + this.filterLogs(); + } + + /** + * Filters the logs + */ + private filterLogs(): void { + + if (this.query === null && this.searchParams === null) { + this.logLines = this._logLines; + return; + } + + this.logLines = this._logLines + .filter(line => (this.searchParams != null && this.searchParams?.length > 0) + ? this.searchParams?.includes(line.level) + : true) + .reduce((arr: typeof this.logLines, el) => { + + if (this.query == null || !this.query.length) { + return this._logLines; + } + + const message = el.message.split('
    ').filter(el => el.toLowerCase().includes(this.query!.toLowerCase())).join('
    '); + + if (message?.length > 0) { + el.message = message; + arr.push(el); + } + + return arr; + }, []); + } } diff --git a/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts b/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts index c64b512460b..6cfedde7115 100644 --- a/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts +++ b/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts @@ -610,17 +610,15 @@ export abstract class AbstractHistoryChart implements OnInit { const isHidden = legendItem?.strokeThroughHidingStyle ?? null; - displayValues.filter(element => element.name == dataset.label?.split(":")[0]).forEach(() => { - chartLegendLabelItems.push({ - text: dataset.label, - datasetIndex: index, - fontColor: getComputedStyle(document.documentElement).getPropertyValue('--ion-color-text'), - fillStyle: dataset.backgroundColor?.toString(), - hidden: isHidden != null ? isHidden : !chart.isDatasetVisible(index), - lineWidth: 2, - strokeStyle: dataset.borderColor.toString(), - ...(dataset['borderDash'] != null && { lineDash: dataset['borderDash'] }), - }); + chartLegendLabelItems.push({ + text: dataset.label, + datasetIndex: index, + fontColor: getComputedStyle(document.documentElement).getPropertyValue('--ion-color-text'), + fillStyle: dataset.backgroundColor?.toString(), + hidden: isHidden != null ? isHidden : !chart.isDatasetVisible(index), + lineWidth: 2, + strokeStyle: dataset.borderColor.toString(), + ...(dataset['borderDash'] != null && { lineDash: dataset['borderDash'] }), }); }); diff --git a/ui/src/app/shared/genericComponents/shared/notification/notification.ts b/ui/src/app/shared/genericComponents/shared/notification/notification.ts index 67e08daab21..29c40f467ae 100644 --- a/ui/src/app/shared/genericComponents/shared/notification/notification.ts +++ b/ui/src/app/shared/genericComponents/shared/notification/notification.ts @@ -47,7 +47,6 @@ export class NotificationComponent implements OnInit, OnChanges { translucent: false, message: this.text, position: 'bottom', - cssClass: 'text-overflow-break', buttons: [ { icon: 'close-outline', role: 'cancel' }, ], diff --git a/ui/src/app/shared/header/header.component.ts b/ui/src/app/shared/header/header.component.ts index a1b4d2b76a7..c2d29797747 100644 --- a/ui/src/app/shared/header/header.component.ts +++ b/ui/src/app/shared/header/header.component.ts @@ -63,7 +63,7 @@ export class HeaderComponent implements OnInit, OnDestroy, AfterViewChecked { const urlArray = url.split('/'); const file = urlArray.pop(); - if (file == 'user' || file == 'settings' || file == 'changelog' || urlArray.length > 3) { + if (file == 'user' || file == 'settings' || file == 'changelog' || file == 'login' || urlArray.length > 3) { // disable side-menu; show back-button instead this.enableSideMenu = false; } else { diff --git a/ui/src/app/shared/shared.ts b/ui/src/app/shared/shared.ts index 90b7b4ca963..3d6b661fa1f 100644 --- a/ui/src/app/shared/shared.ts +++ b/ui/src/app/shared/shared.ts @@ -11,6 +11,8 @@ export { GridMode } from "./type/general"; export { SystemLog } from "./type/systemlog"; export { Widget, WidgetFactory, WidgetNature, Widgets } from "./type/widget"; +import { AlertController, AlertOptions } from "@ionic/angular"; +import { TranslateService } from "@ngx-translate/core"; import { addIcons } from 'ionicons'; import { Edge } from "./edge/edge"; import { User } from "./jsonrpc/shared"; @@ -124,3 +126,36 @@ export namespace Currency { CENT_PER_KWH = "Cent/kWh" } } + +export enum EssStateMachine { + UNDEFINED = -1, // + START_BATTERY = 10, // + START_BATTERY_INVERTER = 11, // + STARTED = 12, // + STOP_BATTERY_INVERTER = 20, // + STOP_BATTERY = 21, // + STOPPED = 22, // + ERROR = 30, +} + +/** +* Presents a simple +*/ +export async function presentAlert(alertController: AlertController, translate: TranslateService, alertOptions: AlertOptions) { + + if (!alertOptions?.buttons) { + throw new Error("Confirmation button is missing"); + } + + const alert = alertController.create({ + ...alertOptions, + buttons: [{ + text: translate.instant('General.cancel'), + role: 'cancel', + }, + ...(alertOptions?.buttons ?? []), + ], + cssClass: 'alertController', + }); + (await alert).present(); +} diff --git a/ui/src/app/shared/utils/date/dateutils.spec.ts b/ui/src/app/shared/utils/date/dateutils.spec.ts index 91af5e6dfb2..74726142dcd 100644 --- a/ui/src/app/shared/utils/date/dateutils.spec.ts +++ b/ui/src/app/shared/utils/date/dateutils.spec.ts @@ -35,4 +35,13 @@ describe('DateUtils', () => { expect(DateUtils.stringToDate('2023-01-02')).toEqual(new Date(Date.parse('2023-01-02'))); expect(DateUtils.stringToDate('wrong format')).toEqual(null); }); + + it('#isDateBefore - checks if given date is before date to be compared to', () => { + const date: Date = DateUtils.stringToDate('2023-01-01'); + expect(DateUtils.isDateBefore(date, DateUtils.stringToDate("2023-01-31"))).toEqual(true); + expect(DateUtils.isDateBefore(date, DateUtils.stringToDate("2022-12-31"))).toEqual(false); + expect(DateUtils.isDateBefore(date, DateUtils.stringToDate("2023-01-01"))).toEqual(false); + expect(DateUtils.isDateBefore(date, null)).toEqual(false); + expect(DateUtils.isDateBefore(null, DateUtils.stringToDate("2023-01-01"))).toEqual(false); + }); }); diff --git a/ui/src/app/shared/utils/date/dateutils.ts b/ui/src/app/shared/utils/date/dateutils.ts index 9ec1355b01f..ff97467488a 100644 --- a/ui/src/app/shared/utils/date/dateutils.ts +++ b/ui/src/app/shared/utils/date/dateutils.ts @@ -1,3 +1,4 @@ +import { isBefore } from "date-fns"; export namespace DateUtils { @@ -76,4 +77,18 @@ export namespace DateUtils { export function isFullHour(date: Date) { return date.getMinutes() != 0 ? null : date; } + + /** + * Checks if passed date is before a certain date + * + * @param date the date + * @param compareDate the date to compare it to + * @returns true, if the passed date is before compareDate + */ + export function isDateBefore(date: Date, compareDate: Date): boolean { + if (date != null && compareDate != null) { + return isBefore(date, compareDate); + } + return false; + } } diff --git a/ui/src/assets/i18n/de.json b/ui/src/assets/i18n/de.json index e1fd38cc65a..3051c67304f 100644 --- a/ui/src/assets/i18n/de.json +++ b/ui/src/assets/i18n/de.json @@ -350,7 +350,8 @@ "level": "Level", "message": "Nachricht", "source": "Quelle", - "timestamp": "Zeitpunkt" + "timestamp": "Zeitpunkt", + "CONDENSED_OUTPUT": "Komprimierte Ausgabe" }, "Controller": { "app": "Anwendung:", @@ -935,7 +936,11 @@ "RESTARTED": "{{system}} neu starten war erfolgreich.", "RESTART_FAILED": "{{system}}-Neustart fehlgeschlagen.", "RESTART_CONFIRMATION": "Möchten Sie {{system}} neu starten?", - "RESTART_WARNING": "Während {{system}} neu startet ist die Kommunikation unterbrochen. In dieser Zeit werden keine Daten aufgezeichnet oder Komponenten angesteuert. Bitte stellen Sie sicher, dass sich das Gesamtsystem in einem sicheren Zustand befindet." + "RESTART_WARNING": "Während {{system}} neu startet ist die Kommunikation unterbrochen. In dieser Zeit werden keine Daten aufgezeichnet oder Komponenten angesteuert. Bitte stellen Sie sicher, dass sich das Gesamtsystem in einem sicheren Zustand befindet.", + "CONFIRMATION_INFO": "Möchten Sie ihr {{edgeShortName}} aktualisieren?", + "WARNING": "Im Rahmen des Systemupdates wird {{system}} neu gestartet und dabei die Kommunikation unterbrochen. In dieser Zeit werden keine Daten aufgezeichnet oder Komponenten angesteuert. Bitte stellen Sie sicher, dass sich das Gesamtsystem in einem sicheren Zustand befindet.", + "UPDATE_EXECUTE": "Systemupdate durchführen", + "SUB_HEADER": "Möchten Sie ein Systemupdate durchführen?" } }, "CHANNELS": { diff --git a/ui/src/assets/i18n/en.json b/ui/src/assets/i18n/en.json index 96a04d721fd..ad2e259af25 100644 --- a/ui/src/assets/i18n/en.json +++ b/ui/src/assets/i18n/en.json @@ -351,7 +351,8 @@ "level": "Level", "message": "Message", "source": "Source", - "timestamp": "Timestamp" + "timestamp": "Timestamp", + "CONDENSED_OUTPUT": "Condensed Output" }, "Controller": { "app": "App:", @@ -938,7 +939,11 @@ "RESTARTING": "Restarting {{system}}. (This can take up to {{minutes}} minutes)", "RESTARTED": "{{system}} restarting successful.", "RESTART_CONFIRMATION": "Would you like to restart {{system}}?", - "RESTART_WARNING": "Communication is interrupted while {{system}} is restarting. No data is recorded or components controlled during this time. Please ensure that the entire system is in a safe state." + "RESTART_WARNING": "Communication is interrupted while {{system}} is restarting. No data is recorded or components controlled during this time. Please ensure that the entire system is in a safe state.", + "CONFIRMATION_INFO": "Would you like to update your {{edgeShortName}}?", + "WARNING": "The software will restart after the system update. No data is recorded or components controlled during this time. Please ensure that the entire system is in a safe state.", + "UPDATE_EXECUTE": "Execute system update", + "SUB_HEADER": "Would you like to execute a system update?" } }, "CHANNELS": { diff --git a/ui/src/global.scss b/ui/src/global.scss index fa6bb9d10a4..f29dac900c2 100644 --- a/ui/src/global.scss +++ b/ui/src/global.scss @@ -313,11 +313,6 @@ formly-input-section { width: 50%; color: var(--ion-color-primary); } - - // Used for notification component - .text-overflow-break { - line-break: anywhere; - } } // auto height for modals From 6937f290b343db5db014cf99f211dabf44729bbf Mon Sep 17 00:00:00 2001 From: Hannes Date: Sat, 1 Jun 2024 17:30:17 +0200 Subject: [PATCH 023/173] Shelly 2.5: refactored to use HttpBridge (#2573) * Refactored to use HttpBridge * Fix errors; improve code quality --------- Co-authored-by: Stefan Feilmeier --- .../edge/io/shelly/shelly25/IoShelly25.java | 121 ++++++---------- .../io/shelly/shelly25/IoShelly25Impl.java | 135 +++++++++++------- .../edge/io/shelly/shelly25/ShellyApi.java | 107 -------------- .../shelly/shelly25/IoShelly25ImplTest.java | 4 +- 4 files changed, 132 insertions(+), 235 deletions(-) delete mode 100644 io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/ShellyApi.java diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25.java index b276675dc5e..01149dde732 100644 --- a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25.java +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25.java @@ -5,10 +5,8 @@ import io.openems.common.channel.AccessMode; import io.openems.common.channel.Level; import io.openems.common.channel.PersistencePriority; -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.types.OpenemsType; import io.openems.edge.common.channel.BooleanDoc; -import io.openems.edge.common.channel.BooleanWriteChannel; import io.openems.edge.common.channel.Doc; import io.openems.edge.common.channel.StateChannel; import io.openems.edge.common.channel.value.Value; @@ -41,6 +39,29 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId .accessMode(AccessMode.READ_WRITE) // .persistencePriority(PersistencePriority.HIGH) // .onChannelSetNextWriteMirrorToDebugChannel(ChannelId.DEBUG_RELAY_1)), + + /** + * Indicates whether the associated Relay is in Overtemp-State. + * + *

      + *
    • Interface: Shelly25 + *
    • Type: Boolean + *
    • Level: WARN + *
    + */ + RELAY_1_OVERTEMP(Doc.of(Level.WARNING) // + .text("Relay 1 has been switched off due to Overtemperature.")), + /** + * Indicates whether the associated Relay is in Overpower-State. + * + *
      + *
    • Interface: Shelly25 + *
    • Type: Boolean + *
    • Level: WARN + *
    + */ + RELAY_1_OVERPOWER(Doc.of(Level.WARNING) // + .text("Relay 2 has been switched off due to Overpower.")), /** * Holds writes to Relay Output 2 for debugging. * @@ -64,6 +85,28 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId .accessMode(AccessMode.READ_WRITE) // .persistencePriority(PersistencePriority.HIGH) // .onChannelSetNextWriteMirrorToDebugChannel(ChannelId.DEBUG_RELAY_2)), + /** + * Indicates whether the associated Relay is in Overtemp-State. + * + *
      + *
    • Interface: Shelly25 + *
    • Type: Boolean + *
    • Level: WARN + *
    + */ + RELAY_2_OVERTEMP(Doc.of(Level.WARNING) // + .text("Relay 2 has been switched off due to Overtemperature.")), + /** + * Indicates whether the associated Relay is in Overpower-State. + * + *
      + *
    • Interface: Shelly25 + *
    • Type: Boolean + *
    • Level: WARN + *
    + */ + RELAY_2_OVERPOWER(Doc.of(Level.WARNING) // + .text("Relay 2 has been switched off due to Overpower.")), /** * Slave Communication Failed Fault. * @@ -86,80 +129,6 @@ public Doc doc() { } } - /** - * Gets the Channel for {@link ChannelId#RELAY_1}. - * - * @return the Channel - */ - public default BooleanWriteChannel getRelay1Channel() { - return this.channel(ChannelId.RELAY_1); - } - - /** - * Gets the Relay Output 1. See {@link ChannelId#RELAY_1}. - * - * @return the Channel {@link Value} - */ - public default Value getRelay1() { - return this.getRelay1Channel().value(); - } - - /** - * Internal method to set the 'nextValue' on {@link ChannelId#RELAY_1} Channel. - * - * @param value the next value - */ - public default void _setRelay1(Boolean value) { - this.getRelay1Channel().setNextValue(value); - } - - /** - * Sets the Relay Output 1. See {@link ChannelId#RELAY_1}. - * - * @param value the next write value - * @throws OpenemsNamedException on error - */ - public default void setRelay1(boolean value) throws OpenemsNamedException { - this.getRelay1Channel().setNextWriteValue(value); - } - - /** - * Gets the Channel for {@link ChannelId#RELAY_2}. - * - * @return the Channel - */ - public default BooleanWriteChannel getRelay2Channel() { - return this.channel(ChannelId.RELAY_2); - } - - /** - * Gets the Relay Output 2. See {@link ChannelId#RELAY_2}. - * - * @return the Channel {@link Value} - */ - public default Value getRelay2() { - return this.getRelay2Channel().value(); - } - - /** - * Internal method to set the 'nextValue' on {@link ChannelId#RELAY_2} Channel. - * - * @param value the next value - */ - public default void _setRelay2(Boolean value) { - this.getRelay2Channel().setNextValue(value); - } - - /** - * Sets the Relay Output 2. See {@link ChannelId#RELAY_2}. - * - * @param value the next write value - * @throws OpenemsNamedException on error - */ - public default void setRelay2(boolean value) throws OpenemsNamedException { - this.getRelay2Channel().setNextWriteValue(value); - } - /** * Gets the Channel for {@link ChannelId#SLAVE_COMMUNICATION_FAILED}. * diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java index aad007289db..d69c0cd2ffd 100644 --- a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java @@ -1,5 +1,9 @@ package io.openems.edge.io.shelly.shelly25; +import static io.openems.common.utils.JsonUtils.getAsBoolean; +import static io.openems.common.utils.JsonUtils.getAsJsonArray; +import static io.openems.common.utils.JsonUtils.getAsJsonObject; + import java.util.Objects; import org.osgi.service.component.ComponentContext; @@ -7,6 +11,7 @@ import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.ConfigurationPolicy; import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; import org.osgi.service.event.Event; import org.osgi.service.event.EventHandler; import org.osgi.service.event.propertytypes.EventTopics; @@ -14,10 +19,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.gson.JsonElement; + import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.utils.JsonUtils; +import io.openems.edge.bridge.http.api.BridgeHttp; +import io.openems.edge.bridge.http.api.BridgeHttpFactory; import io.openems.edge.common.channel.BooleanWriteChannel; -import io.openems.edge.common.channel.WriteChannel; import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.event.EdgeEventConstants; @@ -27,19 +34,23 @@ @Component(// name = "IO.Shelly.25", // immediate = true, // - configurationPolicy = ConfigurationPolicy.REQUIRE// + configurationPolicy = ConfigurationPolicy.REQUIRE // ) @EventTopics({ // - EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE, // EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE // }) + public class IoShelly25Impl extends AbstractOpenemsComponent implements IoShelly25, DigitalOutput, OpenemsComponent, EventHandler { private final Logger log = LoggerFactory.getLogger(IoShelly25Impl.class); private final BooleanWriteChannel[] digitalOutputChannels; - private ShellyApi shellyApi = null; + private String baseUrl; + + @Reference + private BridgeHttpFactory httpBridgeFactory; + private BridgeHttp httpBridge; public IoShelly25Impl() { super(// @@ -56,12 +67,18 @@ public IoShelly25Impl() { @Activate private void activate(ComponentContext context, Config config) { super.activate(context, config.id(), config.alias(), config.enabled()); - this.shellyApi = new ShellyApi(config.ip()); + this.baseUrl = "http://" + config.ip(); + this.httpBridge = this.httpBridgeFactory.get(); + + if (this.isEnabled()) { + this.httpBridge.subscribeJsonEveryCycle(this.baseUrl + "/status", this::processHttpResult); + } } - @Override @Deactivate protected void deactivate() { + this.httpBridgeFactory.unget(this.httpBridge); + this.httpBridge = null; super.deactivate(); } @@ -72,22 +89,22 @@ public BooleanWriteChannel[] digitalOutputChannels() { @Override public String debugLog() { + // TODO share code with AbstractKmtronicRelay.debugLog() var b = new StringBuilder(); var i = 1; - for (WriteChannel channel : this.digitalOutputChannels) { + for (var channel : this.digitalOutputChannels) { String valueText; var valueOpt = channel.value().asOptional(); if (valueOpt.isPresent()) { valueText = valueOpt.get() ? "x" : "-"; } else { - valueText = "?"; + valueText = "Unknown"; } - b.append(i + valueText); - - // add space for all but the last - if (++i <= this.digitalOutputChannels.length) { - b.append(" "); + b.append(valueText); + if (i < this.digitalOutputChannels.length) { + b.append("|"); } + i++; } return b.toString(); } @@ -99,68 +116,84 @@ public void handleEvent(Event event) { } switch (event.getTopic()) { - case EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE: - this.eventBeforeProcessImage(); - break; + case EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE // + -> this.eventExecuteWrite(); + } + } - case EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE: - this.eventExecuteWrite(); - break; + private record RelayState(Boolean relayIsOn, Boolean overtemp, Boolean overpower) { + private static RelayState from(JsonElement relay) throws OpenemsNamedException { + var relayIsOn = getAsBoolean(relay, "ison"); + var overtemp = getAsBoolean(relay, "overtemperature"); + var overpower = getAsBoolean(relay, "overpower"); + return new RelayState(relayIsOn, overtemp, overpower); + } + + private void applyChannels(IoShelly25 component, IoShelly25.ChannelId relayChannel, + IoShelly25.ChannelId overtempChannel, IoShelly25.ChannelId overpowerChannel) { + component.channel(relayChannel).setNextValue(this.relayIsOn); + component.channel(overtempChannel).setNextValue(this.overtemp); + component.channel(overpowerChannel).setNextValue(this.overpower); } } /** * Execute on Cycle Event "Before Process Image". + * + * @param result The JSON element containing the result of the HTTP request. + * @param error The throwable error, if any occurred during the HTTP request. + * @throws OpenemsNamedException if the processing of the HTTP result fails or + * communication with the slave device is + * unsuccessful. */ - private void eventBeforeProcessImage() { - Boolean relay1IsOn; - Boolean relay2IsOn; - try { - var json = this.shellyApi.getStatus(); - var relays = JsonUtils.getAsJsonArray(json, "relays"); - var relay1 = JsonUtils.getAsJsonObject(relays.get(0)); - relay1IsOn = JsonUtils.getAsBoolean(relay1, "ison"); - var relay2 = JsonUtils.getAsJsonObject(relays.get(1)); - relay2IsOn = JsonUtils.getAsBoolean(relay2, "ison"); + private void processHttpResult(JsonElement result, Throwable error) { + var slaveCommunicationFailed = result == null; + var relay1State = new RelayState(null, null, null); + var relay2State = new RelayState(null, null, null); - this._setSlaveCommunicationFailed(false); + try { + final var relays = getAsJsonArray(result, "relays"); + relay1State = RelayState.from(getAsJsonObject(relays.get(0))); + relay2State = RelayState.from(getAsJsonObject(relays.get(1))); } catch (OpenemsNamedException | IndexOutOfBoundsException e) { - relay1IsOn = null; - relay2IsOn = null; - this.logError(this.log, "Unable to read from Shelly API: " + e.getMessage()); - this._setSlaveCommunicationFailed(true); + this.logDebug(this.log, e.getMessage()); + slaveCommunicationFailed = true; } - this._setRelay1(relay1IsOn); - this._setRelay2(relay2IsOn); + + this._setSlaveCommunicationFailed(slaveCommunicationFailed); + relay1State.applyChannels(this, IoShelly25.ChannelId.RELAY_1, // + IoShelly25.ChannelId.RELAY_1_OVERTEMP, IoShelly25.ChannelId.RELAY_1_OVERPOWER); + relay2State.applyChannels(this, IoShelly25.ChannelId.RELAY_2, // + IoShelly25.ChannelId.RELAY_2_OVERTEMP, IoShelly25.ChannelId.RELAY_2_OVERPOWER); } /** * Execute on Cycle Event "Execute Write". */ private void eventExecuteWrite() { - try { - this.executeWrite(this.getRelay1Channel(), 0); - this.executeWrite(this.getRelay2Channel(), 1); - - this._setSlaveCommunicationFailed(false); - } catch (OpenemsNamedException e) { - this._setSlaveCommunicationFailed(true); + for (int i = 0; i < this.digitalOutputChannels.length; i++) { + this.executeWrite(this.digitalOutputChannels[i], i); } } - private void executeWrite(BooleanWriteChannel channel, int index) throws OpenemsNamedException { + private void executeWrite(BooleanWriteChannel channel, int index) { var readValue = channel.value().get(); var writeValue = channel.getNextWriteValueAndReset(); - if (!writeValue.isPresent()) { - // no write value + if (writeValue.isEmpty()) { return; } if (Objects.equals(readValue, writeValue.get())) { - // read value = write value return; } - this.shellyApi.setRelayTurn(index, writeValue.get()); + final String url = this.baseUrl + "/relay/" + index + "?turn=" + (writeValue.get() ? "on" : "off"); + this.httpBridge.get(url).whenComplete((t, e) -> { + this._setSlaveCommunicationFailed(e != null); + if (e == null) { + this.logInfo(this.log, "Executed write successfully for URL: " + url); + } else { + this.logError(this.log, "Failed to execute write for URL: " + url + "; Error: " + e.getMessage()); + } + }); } - -} \ No newline at end of file +} diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/ShellyApi.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/ShellyApi.java deleted file mode 100644 index 6b3b8a3db6f..00000000000 --- a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/ShellyApi.java +++ /dev/null @@ -1,107 +0,0 @@ -package io.openems.edge.io.shelly.shelly25; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.HttpURLConnection; -import java.net.URL; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; - -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.exceptions.OpenemsException; -import io.openems.common.utils.JsonUtils; - -// TODO replace with HttpBridge -/** - * Implements the local Shelly REST Api. - * - *

    - * See https://shelly-api-docs.shelly.cloud - */ -public class ShellyApi { - - private final String baseUrl; - - public ShellyApi(String ip) { - this.baseUrl = "http://" + ip; - } - - /** - * Gets the status of the device. - * - *

    - * See https://shelly-api-docs.shelly.cloud/#shelly2-5-status - * - * @return the status as JsonObject according to Shelly docs - * @throws OpenemsNamedException on error - */ - public JsonObject getStatus() throws OpenemsNamedException { - return JsonUtils.getAsJsonObject(this.sendGetRequest("/status")); - } - - /** - * Gets the "ison" state of the relay with the given index. - * - *

    - * See https://shelly-api-docs.shelly.cloud/#shelly2-5-relay-index - * - * @param index the index of the relay - * @return the boolean value - * @throws OpenemsNamedException on error - */ - public boolean getRelayIson(int index) throws OpenemsNamedException { - var json = this.sendGetRequest("/relay/" + index); - return JsonUtils.getAsBoolean(json, "ison"); - } - - /** - * Turns the relay with the given index on or off. - * - * @param index the index of the relay - * @param value true to turn on; false to turn off - * @throws OpenemsNamedException on error - */ - public void setRelayTurn(int index, boolean value) throws OpenemsNamedException { - this.sendGetRequest("/relay/" + index + "?turn=" + (value ? "on" : "off")); - } - - /** - * Sends a get request to the Shelly API. - * - * @param endpoint the REST Api endpoint - * @return a JsonObject or JsonArray - * @throws OpenemsNamedException on error - */ - private JsonElement sendGetRequest(String endpoint) throws OpenemsNamedException { - try { - var url = new URL(this.baseUrl + endpoint); - var con = (HttpURLConnection) url.openConnection(); - con.setRequestMethod("GET"); - con.setConnectTimeout(5000); - con.setReadTimeout(5000); - var status = con.getResponseCode(); - String body; - try (var in = new BufferedReader(new InputStreamReader(con.getInputStream()))) { - // Read HTTP response - var content = new StringBuilder(); - String line; - while ((line = in.readLine()) != null) { - content.append(line); - content.append(System.lineSeparator()); - } - body = content.toString(); - } - if (status < 300) { - // Parse response to JSON - return JsonUtils.parseToJsonObject(body); - } - throw new OpenemsException("Error while reading from Shelly API. Response code: " + status + ". " + body); - } catch (OpenemsNamedException | IOException e) { - throw new OpenemsException( - "Unable to read from Shelly API. " + e.getClass().getSimpleName() + ": " + e.getMessage()); - } - } - -} diff --git a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shelly25/IoShelly25ImplTest.java b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shelly25/IoShelly25ImplTest.java index 6e778d2393c..2e6e2a98902 100644 --- a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shelly25/IoShelly25ImplTest.java +++ b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shelly25/IoShelly25ImplTest.java @@ -2,6 +2,7 @@ import org.junit.Test; +import io.openems.edge.bridge.http.dummy.DummyBridgeHttpFactory; import io.openems.edge.common.test.ComponentTest; public class IoShelly25ImplTest { @@ -11,6 +12,7 @@ public class IoShelly25ImplTest { @Test public void test() throws Exception { new ComponentTest(new IoShelly25Impl()) // + .addReference("httpBridgeFactory", new DummyBridgeHttpFactory()) // .activate(MyConfig.create() // .setId(COMPONENT_ID) // .setIp("127.0.0.1") // @@ -18,4 +20,4 @@ public void test() throws Exception { ; } -} +} \ No newline at end of file From 217f089ec56308970879785642d99ab5c3fad2c2 Mon Sep 17 00:00:00 2001 From: Katsuya Oda Date: Sun, 2 Jun 2024 03:18:18 +0900 Subject: [PATCH 024/173] fix: ./gradlew buildEdge error (#2651) --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 1b669653067..e5169513417 100644 --- a/build.gradle +++ b/build.gradle @@ -97,7 +97,7 @@ task cleanEdge() { description 'Clean all Edge-Bundles' subprojects.each { proj -> - if( proj.name ==~ /io.openems.(common|edge|shared|wrapper).*/ ) { + if( proj.name ==~ /io.openems.(common|edge|oem|shared|wrapper).*/ ) { if (proj.tasks.findAll { it.name == 'clean' }) { dependsOn(proj.clean) } @@ -134,7 +134,7 @@ task assembleEdge() { description 'Assemble all Edge-Bundles' subprojects.each { proj -> - if( proj.name ==~ /io.openems.(common|edge|shared|wrapper).*/ ) { + if( proj.name ==~ /io.openems.(common|edge|oem|shared|wrapper).*/ ) { if (proj.tasks.findAll { it.name == 'assemble' }) { dependsOn(proj.assemble) } From e6a6e02476659a61c2d48de13b9961602882d7f3 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Sat, 1 Jun 2024 20:20:32 +0200 Subject: [PATCH 025/173] Gradle: update to version 8.8 (#2657) --- .gradle-wrapper/gradle-wrapper.jar | Bin 43462 -> 43453 bytes .gradle-wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/.gradle-wrapper/gradle-wrapper.jar b/.gradle-wrapper/gradle-wrapper.jar index d64cd4917707c1f8861d8cb53dd15194d4248596..e6441136f3d4ba8a0da8d277868979cfbc8ad796 100644 GIT binary patch delta 34118 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 delta 34176 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 SGW6ptSs!X7{rG*o_g?|vpSEZK diff --git a/.gradle-wrapper/gradle-wrapper.properties b/.gradle-wrapper/gradle-wrapper.properties index b82aa23a4f0..a4413138c96 100644 --- a/.gradle-wrapper/gradle-wrapper.properties +++ b/.gradle-wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 5a5c6b2b7e1656e0c588121f493c53270b884107 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Sat, 1 Jun 2024 21:04:51 +0200 Subject: [PATCH 026/173] Push version to 2024.6.0 --- io.openems.common/src/io/openems/common/OpenemsConstants.java | 2 +- ui/package-lock.json | 4 ++-- ui/package.json | 2 +- ui/src/app/changelog/view/component/changelog.constants.ts | 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 b016110bb8c..9d13d5d36a0 100644 --- a/io.openems.common/src/io/openems/common/OpenemsConstants.java +++ b/io.openems.common/src/io/openems/common/OpenemsConstants.java @@ -36,7 +36,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 958a26c12c8..a3bfb8b2253 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "openems-ui", - "version": "2024.6.0-SNAPSHOT", + "version": "2024.6.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "openems-ui", - "version": "2024.6.0-SNAPSHOT", + "version": "2024.6.0", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "~16.2.12", diff --git a/ui/package.json b/ui/package.json index a36b43361c9..470640ec874 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,6 +1,6 @@ { "name": "openems-ui", - "version": "2024.6.0-SNAPSHOT", + "version": "2024.6.0", "license": "AGPL-3.0", "private": true, "dependencies": { diff --git a/ui/src/app/changelog/view/component/changelog.constants.ts b/ui/src/app/changelog/view/component/changelog.constants.ts index a41211bc7ca..3c15c2b279c 100644 --- a/ui/src/app/changelog/view/component/changelog.constants.ts +++ b/ui/src/app/changelog/view/component/changelog.constants.ts @@ -2,7 +2,7 @@ import { Role } from "src/app/shared/type/role"; export class Changelog { - public static readonly UI_VERSION = "2024.6.0-SNAPSHOT"; + public static readonly UI_VERSION = "2024.6.0"; public static product(...products: Product[]) { return products.map(product => Changelog.link(product.name, product.url)).join(", ") + '. '; From 9ae827714b7d48ffe34349dfaa10d8598d34eea5 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Sat, 1 Jun 2024 21:12:41 +0200 Subject: [PATCH 027/173] Start development of version 2024.7.0-SNAPSHOT --- io.openems.common/src/io/openems/common/OpenemsConstants.java | 4 ++-- ui/package-lock.json | 4 ++-- ui/package.json | 2 +- ui/src/app/changelog/view/component/changelog.constants.ts | 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 9d13d5d36a0..28910dcf23c 100644 --- a/io.openems.common/src/io/openems/common/OpenemsConstants.java +++ b/io.openems.common/src/io/openems/common/OpenemsConstants.java @@ -22,7 +22,7 @@ public class OpenemsConstants { *

      * This is the month of the release. */ - public static final short VERSION_MINOR = 6; + public static final short VERSION_MINOR = 7; /** * The patch version of OpenEMS. @@ -36,7 +36,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 a3bfb8b2253..d4bf997d2a0 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "openems-ui", - "version": "2024.6.0", + "version": "2024.7.0-SNAPSHOT", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "openems-ui", - "version": "2024.6.0", + "version": "2024.7.0-SNAPSHOT", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "~16.2.12", diff --git a/ui/package.json b/ui/package.json index 470640ec874..460c0f8728b 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,6 +1,6 @@ { "name": "openems-ui", - "version": "2024.6.0", + "version": "2024.7.0-SNAPSHOT", "license": "AGPL-3.0", "private": true, "dependencies": { diff --git a/ui/src/app/changelog/view/component/changelog.constants.ts b/ui/src/app/changelog/view/component/changelog.constants.ts index 3c15c2b279c..fec1a68180b 100644 --- a/ui/src/app/changelog/view/component/changelog.constants.ts +++ b/ui/src/app/changelog/view/component/changelog.constants.ts @@ -2,7 +2,7 @@ import { Role } from "src/app/shared/type/role"; export class Changelog { - public static readonly UI_VERSION = "2024.6.0"; + public static readonly UI_VERSION = "2024.7.0-SNAPSHOT"; public static product(...products: Product[]) { return products.map(product => Changelog.link(product.name, product.url)).join(", ") + '. '; From bce81f975e8687139285d579143fce7bc1bfd81c Mon Sep 17 00:00:00 2001 From: Kai J <99220919+da-Kai@users.noreply.github.com> Date: Tue, 4 Jun 2024 22:24:18 +0200 Subject: [PATCH 028/173] CI: fix docker ui builds (#2662) --- build.gradle | 2 +- tools/docker/backend/Dockerfile | 5 ++--- tools/docker/edge/Dockerfile | 5 ++--- tools/docker/ui/Dockerfile | 12 ++++++------ tools/docker/ui/index.patch | 3 +++ ui/src/index.html | 3 +-- 6 files changed, 15 insertions(+), 15 deletions(-) create mode 100644 tools/docker/ui/index.patch diff --git a/build.gradle b/build.gradle index e5169513417..f616cf7b1e8 100644 --- a/build.gradle +++ b/build.gradle @@ -147,7 +147,7 @@ task assembleBackend() { description 'Assemble all Backend-Bundles' subprojects.each { proj -> - if( proj.name ==~ /io.openems.(backend|common|shared|wrapper).*/ ) { + if( proj.name ==~ /io.openems.(backend|common|oem|shared|wrapper).*/ ) { if (proj.tasks.findAll { it.name == 'assemble' }) { dependsOn(proj.assemble) } diff --git a/tools/docker/backend/Dockerfile b/tools/docker/backend/Dockerfile index 140504a0baa..b18b9f71b99 100644 --- a/tools/docker/backend/Dockerfile +++ b/tools/docker/backend/Dockerfile @@ -4,11 +4,10 @@ ARG JAVA_VERSION=21 FROM --platform=$BUILDPLATFORM eclipse-temurin:${JAVA_VERSION}-alpine AS build_backend WORKDIR /src +ENV OEMS_BACKEND_OUTPUT=/opt/openems-backend.jar RUN --mount=type=bind,target=.,readwrite \ --mount=type=cache,target=/root/.gradle \ - ./gradlew --no-build-cache assemble && \ - ./gradlew --no-build-cache buildBackend && \ - cp build/openems-backend.jar /opt + ./gradlew --no-build-cache buildBackend ### Build jar container base FROM ghcr.io/linuxserver/baseimage-alpine:edge AS base_container diff --git a/tools/docker/edge/Dockerfile b/tools/docker/edge/Dockerfile index 47e969f2574..2842259688c 100644 --- a/tools/docker/edge/Dockerfile +++ b/tools/docker/edge/Dockerfile @@ -4,11 +4,10 @@ ARG JAVA_VERSION=21 FROM --platform=$BUILDPLATFORM eclipse-temurin:${JAVA_VERSION}-alpine AS build_edge WORKDIR /src +ENV OEMS_EDGE_OUTPUT=/opt/openems-edge.jar RUN --mount=type=bind,target=.,readwrite \ --mount=type=cache,target=/root/.gradle \ - ./gradlew --no-build-cache assemble && \ - ./gradlew --no-build-cache buildEdge && \ - cp build/openems-edge.jar /opt/ + ./gradlew --no-build-cache buildEdge ### Build jar container base FROM ghcr.io/linuxserver/baseimage-alpine:edge AS base_container diff --git a/tools/docker/ui/Dockerfile b/tools/docker/ui/Dockerfile index 644ba1bee6d..e08c13bd40e 100644 --- a/tools/docker/ui/Dockerfile +++ b/tools/docker/ui/Dockerfile @@ -6,21 +6,21 @@ FROM --platform=$BUILDPLATFORM node:${NODE}-alpine AS build_ui ARG VERSION -RUN apk update && apk upgrade; +RUN apk add --update --no-cache patch COPY ui/ /src/ +COPY tools/docker/ui/index.patch /src/ WORKDIR /src -RUN npm install && \ +RUN patch src/index.html < index.patch && \ + npm install && \ node_modules/.bin/ng build -c "$VERSION"; ### Build ui base FROM ghcr.io/linuxserver/baseimage-alpine:edge AS ui_base -RUN apk update && apk upgrade - -RUN apk add --no-cache \ +RUN apk add --update --no-cache \ nginx openssl ### Build ui container @@ -37,4 +37,4 @@ VOLUME /var/log/nginx ENV UI_WEBSOCKET ws://localhost:8080 -EXPOSE 80 443 \ No newline at end of file +EXPOSE 80 443 diff --git a/tools/docker/ui/index.patch b/tools/docker/ui/index.patch new file mode 100644 index 00000000000..d20cbc4b037 --- /dev/null +++ b/tools/docker/ui/index.patch @@ -0,0 +1,3 @@ +@@ -12,1 +12,1 @@ +- ++ diff --git a/ui/src/index.html b/ui/src/index.html index 747757bf338..cfd90f2e9be 100644 --- a/ui/src/index.html +++ b/ui/src/index.html @@ -9,8 +9,7 @@ content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" /> - - + From a946ba09d5bb7f491f15256a215f6fdb926526bd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Jun 2024 23:51:20 +0200 Subject: [PATCH 029/173] Bump com.google.guava:guava from 33.2.0-jre to 33.2.1-jre in /cnf (#2661) * Bump com.google.guava:guava from 33.2.0-jre to 33.2.1-jre in /cnf Bumps [com.google.guava:guava](https://github.com/google/guava) from 33.2.0-jre to 33.2.1-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 bnd --------- 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 | 2 +- cnf/pom.xml | 2 +- io.openems.backend.application/BackendApp.bndrun | 2 +- io.openems.edge.application/EdgeApp.bndrun | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cnf/build.bnd b/cnf/build.bnd index c0bce03e8c1..b64f56b11b6 100644 --- a/cnf/build.bnd +++ b/cnf/build.bnd @@ -40,7 +40,7 @@ buildpath: \ org.osgi.service.metatype;version='1.4.1',\ org.osgi.service.metatype.annotations;version='1.4.1',\ org.osgi.util.promise;version='1.2.0',\ - com.google.guava;version='33.2.0.jre',\ + com.google.guava;version='33.2.1.jre',\ com.google.gson;version='2.11.0',\ testpath: \ diff --git a/cnf/pom.xml b/cnf/pom.xml index 93688eb6428..73a53791c40 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -38,7 +38,7 @@ com.google.guava guava - 33.2.0-jre + 33.2.1-jre com.google.guava diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index 4b2a142e8e8..2b107a25765 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -61,7 +61,7 @@ -runbundles: \ Java-WebSocket;version='[1.5.4,1.5.5)',\ com.google.gson;version='[2.11.0,2.11.1)',\ - com.google.guava;version='[33.2.0,33.2.1)',\ + com.google.guava;version='[33.2.1,33.2.2)',\ com.google.guava.failureaccess;version='[1.0.2,1.0.3)',\ com.squareup.okio;version='[3.9.0,3.9.1)',\ com.zaxxer.HikariCP;version='[5.1.0,5.1.1)',\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index 1ca35b83f67..31f9a35776c 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -196,7 +196,7 @@ com.fazecast.jSerialComm;version='[2.10.4,2.10.5)',\ com.ghgande.j2mod;version='[3.2.1,3.2.2)',\ com.google.gson;version='[2.11.0,2.11.1)',\ - com.google.guava;version='[33.2.0,33.2.1)',\ + com.google.guava;version='[33.2.1,33.2.2)',\ com.google.guava.failureaccess;version='[1.0.2,1.0.3)',\ com.squareup.okio;version='[3.9.0,3.9.1)',\ com.sun.jna;version='[5.14.0,5.14.1)',\ From 4fdbb8f7df0857e297bf560ec0188feba2db682d Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Sun, 9 Jun 2024 22:32:23 +0200 Subject: [PATCH 030/173] FEMS Backports 2023-06 (#2664) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Hardy Barth: correct Phase URL mapping - Wrong mapping of Phase 3 current - BridgeHttp: added support for http code & message - added support for http code & message - changed DelayTimeProvider to also be able to handle errors and success responses - improved testing - added common class HttpStatus with all official Http status codes as constants - added lazy endpoint construction to define unique params for each call - UI: Added metric field in 'Network configuration' - UI: fix tab title - setting web-app tab title to ```environment.edgeShortName``` - Backend: Remove edges from authenticate -Removed Edges from Authenticate response - UI: Split user and company related information - Splitting user and company related data, only user data is editable, non company assigned users are still seeing the same and are able to change all userInformation - EdgeConfig: remove Channels - Normal EdgeConfig does not contain Channels anymore - Added separate Requests to get channels for: - [x] Component Status View - [x] Component Channels View - [x] Subscribe only needed Channels in Soltaro ServiceAssistent - [x] Get Channel Units for variable channel for singlethreshold history & live - [x] Get DigitalInputChannels with separate request and fixed subscription - Time-of-Use Tariff Stadtwerk Haßfurt implementation - Time-of-Use Tariff Groupe-E implementation - Added new provider Groupe-E. - Added new currency CHF (Swiss francs) to the list of currencies in core meta. - Moved the exchangerate API to Utils so it is common for both ENTSO-E and Groupe-E providers. - UI: set secure=https property in Cookie -This fixes an issue where a token value could be exposed when redirecting from http to https - Update EdgeApp.bndrun --------- Co-authored-by: Sebastian Asen <47855186+sebastianasen@users.noreply.github.com> Co-authored-by: Michael Grill <59126309+michaelgrill@users.noreply.github.com> Co-authored-by: Sagar Venu <32655208+venu-sagar@users.noreply.github.com> Co-authored-by: Lukas Rieger <73471197+lukasrgr@users.noreply.github.com> Co-authored-by: Katsuya Oda <137796+katsuya@users.noreply.github.com> Co-authored-by: Hiromasa Ihara <118803+miettal@users.noreply.github.com> --- .../openems/backend/common/metadata/User.java | 36 -- .../backend/metadata/odoo/MetadataOdoo.java | 13 +- .../backend/uiwebsocket/impl/OnRequest.java | 20 +- .../response/AuthenticateResponse.java | 14 +- .../jsonrpc/serialization/JsonObjectPath.java | 17 + .../jsonrpc/serialization/JsonSerializer.java | 19 + .../common/oem/DummyOpenemsEdgeOem.java | 2 + .../io/openems/common/types/EdgeConfig.java | 4 +- .../io/openems/common/types/HttpStatus.java | 265 +++++++++++ .../openems/common/types/HttpStatusTest.java | 84 ++++ io.openems.edge.application/EdgeApp.bndrun | 4 + .../bridge/http/AsyncBridgeHttpExecutor.java | 42 ++ .../edge/bridge/http/BridgeHttpImpl.java | 174 ++++--- ...rImpl.java => NetworkEndpointFetcher.java} | 31 +- .../edge/bridge/http/api/BridgeHttp.java | 49 +- .../edge/bridge/http/api/BridgeHttpCycle.java | 217 +++++++-- .../bridge/http/api/BridgeHttpExecutor.java | 35 ++ .../bridge/http/api/BridgeHttpFactory.java | 7 +- .../edge/bridge/http/api/BridgeHttpTime.java | 288 ++++++++++-- .../http/{ => api}/CycleSubscriber.java | 2 +- .../EndpointFetcher.java} | 6 +- .../edge/bridge/http/api/HttpError.java | 57 +++ .../edge/bridge/http/api/HttpResponse.java | 34 ++ .../bridge/http/dummy/DummyBridgeHttp.java | 64 +-- .../http/dummy/DummyBridgeHttpBundle.java | 124 +++++ .../http/dummy/DummyBridgeHttpExecutor.java | 206 ++++++++ .../http/dummy/DummyBridgeHttpFactory.java | 150 +++++- .../http/dummy/DummyEndpointFetcher.java | 93 ++++ .../http/time/DefaultDelayTimeProvider.java | 40 +- .../bridge/http/time/DelayTimeProvider.java | 126 ++++- .../http/time/DelayTimeProviderChain.java | 39 +- .../edge/bridge/http/DummyUrlFetcher.java | 50 -- .../bridge/http/api/BridgeHttpCycleTest.java | 117 ++--- .../edge/bridge/http/api/BridgeHttpTest.java | 59 +-- .../bridge/http/api/BridgeHttpTimeTest.java | 58 ++- .../http/time/DelayTimeProviderChainTest.java | 17 +- .../edge/common/currency/Currency.java | 1 + .../edge/common/currency/CurrencyConfig.java | 7 +- .../common/test/AbstractComponentTest.java | 14 + .../handler/AuthenticationRequestHandler.java | 5 +- .../edge/app/timeofusetariff/GroupeE.java | 161 +++++++ .../timeofusetariff/StadtwerkHassfurt.java | 203 ++++++++ .../core/appmanager/translation_de.properties | 6 + .../core/appmanager/translation_en.properties | 6 + .../ComponentManagerImpl.java | 83 ++++ .../componentmanager/jsonrpc/GetChannel.java | 72 +++ .../jsonrpc/GetChannelsOfComponent.java | 127 +++++ .../GetDigitalInputChannelsOfComponents.java | 94 ++++ .../jsonrpc/GetStateChannelsOfComponent.java | 70 +++ .../io/openems/edge/core/appmanager/Apps.java | 22 + .../core/appmanager/TestTranslations.java | 4 + .../edge/evcs/hardybarth/EvcsHardyBarth.java | 2 +- .../io/shelly/shelly25/IoShelly25Impl.java | 6 +- .../io/shelly/shelly3em/IoShelly3EmImpl.java | 5 +- .../shelly/shellyplug/IoShellyPlugImpl.java | 7 +- .../IoShellyPlusPlugsImpl.java | 6 +- .../shelly/shelly25/IoShelly25ImplTest.java | 2 +- .../shelly/shelly3em/IoShelly3EmImplTest.java | 2 +- .../shellyplug/IoShellyPlugImplTest.java | 2 +- .../shellyplusplugs/IoShellyPlugImplTest.java | 63 ++- io.openems.edge.timeofusetariff.api/bnd.bnd | 7 +- .../api/utils}/ExchangeRateApi.java | 4 +- .../api/utils}/ExchangeRateApiTest.java | 4 +- .../timeofusetariff/entsoe/TouEntsoeImpl.java | 2 +- .../.classpath | 12 + .../.gitignore | 2 + .../.project | 23 + .../org.eclipse.core.resources.prefs | 2 + .../bnd.bnd | 14 + .../readme.adoc | 9 + .../edge/timeofusetariff/groupe/Config.java | 25 + .../groupe/TimeOfUseTariffGroupe.java | 26 + .../groupe/TimeOfUseTariffGroupeImpl.java | 239 ++++++++++ .../test/.gitignore | 0 .../edge/timeofusetariff/groupe/MyConfig.java | 51 ++ .../groupe/TimeOfUseTariffGroupeImplTest.java | 445 ++++++++++++++++++ .../.classpath | 12 + .../.gitignore | 2 + .../.project | 23 + .../org.eclipse.core.resources.prefs | 2 + .../bnd.bnd | 14 + .../readme.adoc | 5 + .../edge/timeofusetariff/hassfurt/Config.java | 24 + .../timeofusetariff/hassfurt/TariffType.java | 13 + .../hassfurt/TimeOfUseTariffHassfurt.java | 26 + .../hassfurt/TimeOfUseTariffHassfurtImpl.java | 247 ++++++++++ .../test/.gitignore | 0 .../timeofusetariff/hassfurt/MyConfig.java | 51 ++ .../TimeOfUseTariffHassfurtImplTest.java | 234 +++++++++ .../TimeOfUseTariffRabotChargeImpl.java | 44 +- .../TimeOfUseTariffRabotChargeImplTest.java | 2 +- ui/src/app/app-routing.module.ts | 2 +- ui/src/app/app.component.ts | 5 +- .../singlethreshold/chart.component.ts | 3 +- ...inglethresholdchartoverview.component.html | 52 +- .../singlethresholdchartoverview.component.ts | 15 +- .../Io_ChannelSingleThreshold.html | 4 +- .../Io_ChannelSingleThreshold.ts | 18 +- .../modal/modal.component.html | 10 +- .../modal/modal.component.ts | 1 + .../Api_DigitalInput/Io_Api_DigitalInput.ts | 15 +- .../modal/modal.component.html | 36 +- .../Api_DigitalInput/modal/modal.component.ts | 93 +++- .../settings/channels/channels.component.html | 53 ++- .../settings/channels/channels.component.ts | 280 ++++++++--- .../network/getNetworkConfigResponse.ts | 11 +- .../settings/network/network.component.html | 6 +- .../settings/network/network.component.ts | 258 +++++----- .../network/setNetworkConfigRequest.ts | 8 +- ui/src/app/edge/settings/network/shared.ts | 87 +++- ui/src/app/shared/edge/edge.ts | 65 ++- ui/src/app/shared/edge/edgeconfig.ts | 6 +- .../jsonrpc/request/getChannelRequest.ts | 16 + .../request/getChannelsOfComponentRequest.ts | 15 + .../getStateChannelsOfComponentRequest.ts | 15 + .../jsonrpc/response/getChannelResponse.ts | 15 + .../getChannelsOfComponentResponse.ts | 30 ++ ui/src/app/shared/service/websocket.ts | 2 +- ui/src/app/shared/shared.ts | 14 + .../status/single/status.component.html | 32 +- .../status/single/status.component.spec.ts | 47 +- .../shared/status/single/status.component.ts | 88 ++-- ui/src/app/user/user.component.html | 25 +- ui/src/app/user/user.component.ts | 230 +++++---- ui/src/assets/i18n/de.json | 3 +- ui/src/assets/i18n/en.json | 3 +- 126 files changed, 5576 insertions(+), 1084 deletions(-) create mode 100644 io.openems.common/src/io/openems/common/types/HttpStatus.java create mode 100644 io.openems.common/test/io/openems/common/types/HttpStatusTest.java create mode 100644 io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/AsyncBridgeHttpExecutor.java rename io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/{UrlFetcherImpl.java => NetworkEndpointFetcher.java} (60%) create mode 100644 io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/BridgeHttpExecutor.java rename io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/{ => api}/CycleSubscriber.java (97%) rename io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/{UrlFetcher.java => api/EndpointFetcher.java} (70%) create mode 100644 io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/HttpError.java create mode 100644 io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/HttpResponse.java create mode 100644 io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpBundle.java create mode 100644 io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpExecutor.java create mode 100644 io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyEndpointFetcher.java delete mode 100644 io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/DummyUrlFetcher.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/GroupeE.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StadtwerkHassfurt.java create mode 100644 io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetChannel.java create mode 100644 io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetChannelsOfComponent.java create mode 100644 io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetDigitalInputChannelsOfComponents.java create mode 100644 io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetStateChannelsOfComponent.java rename {io.openems.edge.timeofusetariff.entsoe/src/io/openems/edge/timeofusetariff/entsoe => io.openems.edge.timeofusetariff.api/src/io/openems/edge/timeofusetariff/api/utils}/ExchangeRateApi.java (94%) rename {io.openems.edge.timeofusetariff.entsoe/test/io/openems/edge/timeofusetariff/entsoe => io.openems.edge.timeofusetariff.api/test/io/openems/edge/timeofusetariff/api/utils}/ExchangeRateApiTest.java (88%) create mode 100644 io.openems.edge.timeofusetariff.groupe/.classpath create mode 100644 io.openems.edge.timeofusetariff.groupe/.gitignore create mode 100644 io.openems.edge.timeofusetariff.groupe/.project create mode 100644 io.openems.edge.timeofusetariff.groupe/.settings/org.eclipse.core.resources.prefs create mode 100644 io.openems.edge.timeofusetariff.groupe/bnd.bnd create mode 100644 io.openems.edge.timeofusetariff.groupe/readme.adoc create mode 100644 io.openems.edge.timeofusetariff.groupe/src/io/openems/edge/timeofusetariff/groupe/Config.java create mode 100644 io.openems.edge.timeofusetariff.groupe/src/io/openems/edge/timeofusetariff/groupe/TimeOfUseTariffGroupe.java create mode 100644 io.openems.edge.timeofusetariff.groupe/src/io/openems/edge/timeofusetariff/groupe/TimeOfUseTariffGroupeImpl.java create mode 100644 io.openems.edge.timeofusetariff.groupe/test/.gitignore create mode 100644 io.openems.edge.timeofusetariff.groupe/test/io/openems/edge/timeofusetariff/groupe/MyConfig.java create mode 100644 io.openems.edge.timeofusetariff.groupe/test/io/openems/edge/timeofusetariff/groupe/TimeOfUseTariffGroupeImplTest.java create mode 100644 io.openems.edge.timeofusetariff.hassfurt/.classpath create mode 100644 io.openems.edge.timeofusetariff.hassfurt/.gitignore create mode 100644 io.openems.edge.timeofusetariff.hassfurt/.project create mode 100644 io.openems.edge.timeofusetariff.hassfurt/.settings/org.eclipse.core.resources.prefs create mode 100644 io.openems.edge.timeofusetariff.hassfurt/bnd.bnd create mode 100644 io.openems.edge.timeofusetariff.hassfurt/readme.adoc create mode 100644 io.openems.edge.timeofusetariff.hassfurt/src/io/openems/edge/timeofusetariff/hassfurt/Config.java create mode 100644 io.openems.edge.timeofusetariff.hassfurt/src/io/openems/edge/timeofusetariff/hassfurt/TariffType.java create mode 100644 io.openems.edge.timeofusetariff.hassfurt/src/io/openems/edge/timeofusetariff/hassfurt/TimeOfUseTariffHassfurt.java create mode 100644 io.openems.edge.timeofusetariff.hassfurt/src/io/openems/edge/timeofusetariff/hassfurt/TimeOfUseTariffHassfurtImpl.java create mode 100644 io.openems.edge.timeofusetariff.hassfurt/test/.gitignore create mode 100644 io.openems.edge.timeofusetariff.hassfurt/test/io/openems/edge/timeofusetariff/hassfurt/MyConfig.java create mode 100644 io.openems.edge.timeofusetariff.hassfurt/test/io/openems/edge/timeofusetariff/hassfurt/TimeOfUseTariffHassfurtImplTest.java create mode 100644 ui/src/app/shared/jsonrpc/request/getChannelRequest.ts create mode 100644 ui/src/app/shared/jsonrpc/request/getChannelsOfComponentRequest.ts create mode 100644 ui/src/app/shared/jsonrpc/request/getStateChannelsOfComponentRequest.ts create mode 100644 ui/src/app/shared/jsonrpc/response/getChannelResponse.ts create mode 100644 ui/src/app/shared/jsonrpc/response/getChannelsOfComponentResponse.ts diff --git a/io.openems.backend.common/src/io/openems/backend/common/metadata/User.java b/io.openems.backend.common/src/io/openems/backend/common/metadata/User.java index 2769e26f35a..ecd0347072f 100644 --- a/io.openems.backend.common/src/io/openems/backend/common/metadata/User.java +++ b/io.openems.backend.common/src/io/openems/backend/common/metadata/User.java @@ -1,17 +1,12 @@ package io.openems.backend.common.metadata; -import java.util.ArrayList; -import java.util.List; -import java.util.Map.Entry; import java.util.NavigableMap; import java.util.TreeMap; import com.google.gson.JsonObject; -import io.openems.common.channel.Level; import io.openems.common.exceptions.OpenemsError; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.jsonrpc.response.GetEdgesResponse.EdgeMetadata; import io.openems.common.session.AbstractUser; import io.openems.common.session.Language; import io.openems.common.session.Role; @@ -74,37 +69,6 @@ public Role assertEdgeRoleIsAtLeast(String resource, String edgeId, Role role) t return thisRole; } - /** - * Gets the Metadata information of the accessible Edges. - * - * @param user the {@link User} - * @param metadataService a {@link Metadata} provider - * @return a list of {@link EdgeMetadata} - */ - public static List generateEdgeMetadatas(User user, Metadata metadataService) { - List metadatas = new ArrayList<>(); - for (Entry edgeRole : user.getEdgeRoles().entrySet()) { - var edgeId = edgeRole.getKey(); - var role = edgeRole.getValue(); - var edgeOpt = metadataService.getEdge(edgeId); - if (edgeOpt.isPresent()) { - var edge = edgeOpt.get(); - metadatas.add(new EdgeMetadata(// - edge.getId(), // Edge-ID - edge.getComment(), // Comment - edge.getProducttype(), // Product-Type - edge.getVersion(), // Version - role, // Role - edge.isOnline(), // Online-State - edge.getLastmessage(), // Last-Message Timestamp - null, // - Level.OK // - )); - } - } - return metadatas; - } - @Override public boolean hasMultipleEdges() { return this.hasMultipleEdges; diff --git a/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/MetadataOdoo.java b/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/MetadataOdoo.java index bab8ab64e22..1e5e88627ce 100644 --- a/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/MetadataOdoo.java +++ b/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/MetadataOdoo.java @@ -9,7 +9,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.NavigableMap; import java.util.Optional; import java.util.TreeMap; import java.util.UUID; @@ -176,16 +175,8 @@ public User authenticate(String sessionId) throws OpenemsNamedException { .flatMap(JsonUtils::getAsOptionalJsonObject) // .orElse(new JsonObject()); - var jDevices = JsonUtils.getAsJsonArray(result, "devices"); - NavigableMap roles = new TreeMap<>(); - for (JsonElement device : jDevices) { - var edgeId = JsonUtils.getAsString(device, "name"); - var role = Role.getRole(JsonUtils.getAsString(device, "role")); - roles.put(edgeId, role); - } - - var user = new MyUser(odooUserId, login, name, sessionId, language, globalRole, roles, hasMultipleEdges, - settings); + var user = new MyUser(odooUserId, login, name, sessionId, language, globalRole, new TreeMap<>(), + hasMultipleEdges, settings); var oldUser = this.users.put(login, user); if (oldUser != null) { oldUser.getEdgeRoles().forEach((edgeId, role) -> { diff --git a/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnRequest.java b/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnRequest.java index cc4b697ccbb..f30098586d3 100644 --- a/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnRequest.java +++ b/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnRequest.java @@ -170,8 +170,8 @@ private CompletableFuture handleAuthentication(WsData ws throws OpenemsNamedException { wsData.setUserId(user.getId()); wsData.setToken(user.getToken()); - return CompletableFuture.completedFuture(new AuthenticateResponse(requestId, user.getToken(), user, - User.generateEdgeMetadatas(user, this.parent.metadata), user.getLanguage())); + return CompletableFuture + .completedFuture(new AuthenticateResponse(requestId, user.getToken(), user, user.getLanguage())); } /** @@ -225,9 +225,8 @@ private CompletableFuture handleEdgeRpcRequest(WsData wsData, U this.handleSubscribeChannelsRequest(wsData, edgeId, user, SubscribeChannelsRequest.from(request)); case SubscribeSystemLogRequest.METHOD -> this.handleSubscribeSystemLogRequest(wsData, edgeId, user, SubscribeSystemLogRequest.from(request)); - case SimulationRequest.METHOD -> - this.handleSimulationRequest(edgeId, user, SimulationRequest.from(request)); - + case SimulationRequest.METHOD -> this.handleSimulationRequest(edgeId, user, SimulationRequest.from(request)); + case ComponentJsonApiRequest.METHOD -> { final var componentRequest = ComponentJsonApiRequest.from(request); if (!"_host".equals(componentRequest.getComponentId())) { @@ -287,19 +286,20 @@ private CompletableFuture handleEdgeRpcRequest(WsData wsData, U /** * Handles a {@link GetSimulationRequest}. * - * @param edgeId the Edge-ID - * @param user the {@link User} - no specific level required + * @param edgeId the Edge-ID + * @param user the {@link User} - no specific level required * @param request the {@link GetSimulationRequest} * @return the JSON-RPC Success Response Future * @throws OpenemsNamedException on error */ - private CompletableFuture handleSimulationRequest(String edgeId, User user, SimulationRequest request) throws OpenemsNamedException { - + private CompletableFuture handleSimulationRequest(String edgeId, User user, + SimulationRequest request) throws OpenemsNamedException { + final var simulation = this.parent.simulation; if (simulation == null) { throw new OpenemsException("simulation unavailable"); } - + return simulation.handleRequest(edgeId, user, request); } diff --git a/io.openems.common/src/io/openems/common/jsonrpc/response/AuthenticateResponse.java b/io.openems.common/src/io/openems/common/jsonrpc/response/AuthenticateResponse.java index 7ac780b1e3f..e0ca14a44f6 100644 --- a/io.openems.common/src/io/openems/common/jsonrpc/response/AuthenticateResponse.java +++ b/io.openems.common/src/io/openems/common/jsonrpc/response/AuthenticateResponse.java @@ -1,15 +1,13 @@ package io.openems.common.jsonrpc.response; -import java.util.Collections; -import java.util.List; import java.util.UUID; +import com.google.gson.JsonArray; import com.google.gson.JsonObject; import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; import io.openems.common.jsonrpc.request.AuthenticateWithPasswordRequest; import io.openems.common.jsonrpc.request.AuthenticateWithTokenRequest; -import io.openems.common.jsonrpc.response.GetEdgesResponse.EdgeMetadata; import io.openems.common.session.AbstractUser; import io.openems.common.session.Language; import io.openems.common.utils.JsonUtils; @@ -33,19 +31,12 @@ public class AuthenticateResponse extends JsonrpcResponseSuccess { private final String token; private final AbstractUser user; - private final List edges; private final Language language; public AuthenticateResponse(UUID id, String token, AbstractUser user, Language language) { - this(id, token, user, Collections.emptyList(), language); - } - - // TODO: remove after UI is updated to new version - public AuthenticateResponse(UUID id, String token, AbstractUser user, List edges, Language language) { super(id); this.token = token; this.user = user; - this.edges = edges; this.language = language; } @@ -65,7 +56,8 @@ public JsonObject getResult() { .add("settings", this.user.getSettings()) // .add("globalRole", this.user.getGlobalRole().asJson()) // .build()) // - .add("edges", EdgeMetadata.toJson(this.edges)) // + // still kept to avoid NPE in UI for older versions + .add("edges", new JsonArray()) // .build(); } diff --git a/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonObjectPath.java b/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonObjectPath.java index fbd925cec08..5281a2fde79 100644 --- a/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonObjectPath.java +++ b/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonObjectPath.java @@ -27,6 +27,23 @@ public default StringPath getStringPath(String member) { return this.getJsonElementPath(member).getAsStringPath(); } + /** + * Gets the enum value of the element associated with the member name of this + * object. + * + * @param the type of the enum + * @param member the name of the member + * @param enumClass the class of the enum + * @return the enum value + */ + public default > T getEnum(String member, Class enumClass) { + try { + return Enum.valueOf(enumClass, this.getString(member)); + } catch (Exception e) { + return enumClass.getEnumConstants()[0]; + } + } + /** * Gets the element associated with the member name from this object as a * {@link String}. diff --git a/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonSerializer.java b/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonSerializer.java index 2b8e52df570..e1606567e2e 100644 --- a/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonSerializer.java +++ b/io.openems.common/src/io/openems/common/jsonrpc/serialization/JsonSerializer.java @@ -1,5 +1,10 @@ package io.openems.common.jsonrpc.serialization; +import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.jsonSerializer; +import static io.openems.common.utils.JsonUtils.toJsonArray; + +import java.util.List; + import com.google.gson.JsonElement; public interface JsonSerializer { @@ -38,4 +43,18 @@ public default T deserialize(JsonElement json) { return this.deserializePath(new JsonElementPathActual(json)); } + /** + * Creates a new {@link JsonSerializer} which is able to serialize {@link List + * Lists} with their generic type of the current {@link JsonSerializer}. + * + * @return the new {@link JsonSerializer} of a {@link List} + */ + public default JsonSerializer> toListSerializer() { + return jsonSerializer(// + json -> json.getAsJsonArrayPath().getAsList(this), // + obj -> obj.stream() // + .map(this::serialize) // + .collect(toJsonArray())); + } + } diff --git a/io.openems.common/src/io/openems/common/oem/DummyOpenemsEdgeOem.java b/io.openems.common/src/io/openems/common/oem/DummyOpenemsEdgeOem.java index 63558ed64b3..9a75699e20a 100644 --- a/io.openems.common/src/io/openems/common/oem/DummyOpenemsEdgeOem.java +++ b/io.openems.common/src/io/openems/common/oem/DummyOpenemsEdgeOem.java @@ -65,6 +65,8 @@ public SystemUpdateParams getSystemUpdateParams() { .put("App.FENECON.Industrial.S.ISK011", "https://fenecon.de/fenecon-industrial-s/") // .put("App.TimeOfUseTariff.Awattar", "") // .put("App.TimeOfUseTariff.ENTSO-E", "") // + .put("App.TimeOfUseTariff.GroupeE", "") // + .put("App.TimeOfUseTariff.Hassfurt", "") // .put("App.TimeOfUseTariff.RabotCharge", "") // .put("App.TimeOfUseTariff.Stromdao", "") // .put("App.TimeOfUseTariff.Tibber", "") // diff --git a/io.openems.common/src/io/openems/common/types/EdgeConfig.java b/io.openems.common/src/io/openems/common/types/EdgeConfig.java index 232f2de63f0..0c54d0334eb 100644 --- a/io.openems.common/src/io/openems/common/types/EdgeConfig.java +++ b/io.openems.common/src/io/openems/common/types/EdgeConfig.java @@ -40,7 +40,7 @@ */ public class EdgeConfig { - private static Logger LOG = LoggerFactory.getLogger(EdgeConfig.class); + private static final Logger LOG = LoggerFactory.getLogger(EdgeConfig.class); /** * Represents an instance of an OpenEMS Component. @@ -1388,7 +1388,7 @@ public List getComponentsByFactory(String factoryId) { public synchronized JsonObject toJson() { if (this._json == null) { this._json = JsonUtils.buildJsonObject() // - .add("components", this.componentsToJson(JsonFormat.COMPLETE)) // + .add("components", this.componentsToJson(JsonFormat.WITHOUT_CHANNELS)) // .add("factories", this.factoriesToJson()) // .build(); } diff --git a/io.openems.common/src/io/openems/common/types/HttpStatus.java b/io.openems.common/src/io/openems/common/types/HttpStatus.java new file mode 100644 index 00000000000..3dc1b910993 --- /dev/null +++ b/io.openems.common/src/io/openems/common/types/HttpStatus.java @@ -0,0 +1,265 @@ +package io.openems.common.types; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public record HttpStatus(int code, String description) { + // 1xx Informational + public static final HttpStatus CONTINUE = new HttpStatus(100, "Continue"); + public static final HttpStatus SWITCHING_PROTOCOLS = new HttpStatus(101, "Switching Protocols"); + public static final HttpStatus PROCESSING = new HttpStatus(102, "Processing"); + public static final HttpStatus EARLY_HINTS = new HttpStatus(103, "Early Hints"); + + // 2xx Success + public static final HttpStatus OK = new HttpStatus(200, "OK"); + public static final HttpStatus CREATED = new HttpStatus(201, "Created"); + public static final HttpStatus ACCEPTED = new HttpStatus(202, "Accepted"); + public static final HttpStatus NON_AUTHORITATIVE_INFORMATION = new HttpStatus(203, "Non-Authoritative Information"); + public static final HttpStatus NO_CONTENT = new HttpStatus(204, "No Content"); + public static final HttpStatus RESET_CONTENT = new HttpStatus(205, "Reset Content"); + public static final HttpStatus PARTIAL_CONTENT = new HttpStatus(206, "Partial Content"); + public static final HttpStatus MULTI_STATUS = new HttpStatus(207, "Multi-Status"); + public static final HttpStatus ALREADY_REPORTED = new HttpStatus(208, "Already Reported"); + public static final HttpStatus IM_USED = new HttpStatus(226, "IM Used"); + + // 3xx Redirection + public static final HttpStatus MULTIPLE_CHOICES = new HttpStatus(300, "Multiple Choices"); + public static final HttpStatus MOVED_PERMANENTLY = new HttpStatus(301, "Moved Permanently"); + public static final HttpStatus FOUND = new HttpStatus(302, "Found"); + public static final HttpStatus SEE_OTHER = new HttpStatus(303, "See Other"); + public static final HttpStatus NOT_MODIFIED = new HttpStatus(304, "Not Modified"); + public static final HttpStatus USE_PROXY = new HttpStatus(305, "Use Proxy"); + public static final HttpStatus TEMPORARY_REDIRECT = new HttpStatus(307, "Temporary Redirect"); + public static final HttpStatus PERMANENT_REDIRECT = new HttpStatus(308, "Permanent Redirect"); + + // 4xx Client Error + public static final HttpStatus BAD_REQUEST = new HttpStatus(400, "Bad Request"); + public static final HttpStatus UNAUTHORIZED = new HttpStatus(401, "Unauthorized"); + public static final HttpStatus PAYMENT_REQUIRED = new HttpStatus(402, "Payment Required"); + public static final HttpStatus FORBIDDEN = new HttpStatus(403, "Forbidden"); + public static final HttpStatus NOT_FOUND = new HttpStatus(404, "Not Found"); + public static final HttpStatus METHOD_NOT_ALLOWED = new HttpStatus(405, "Method Not Allowed"); + public static final HttpStatus NOT_ACCEPTABLE = new HttpStatus(406, "Not Acceptable"); + public static final HttpStatus PROXY_AUTHENTICATION_REQUIRED = new HttpStatus(407, "Proxy Authentication Required"); + public static final HttpStatus REQUEST_TIMEOUT = new HttpStatus(408, "Request Timeout"); + public static final HttpStatus CONFLICT = new HttpStatus(409, "Conflict"); + public static final HttpStatus GONE = new HttpStatus(410, "Gone"); + public static final HttpStatus LENGTH_REQUIRED = new HttpStatus(411, "Length Required"); + public static final HttpStatus PRECONDITION_FAILED = new HttpStatus(412, "Precondition Failed"); + public static final HttpStatus PAYLOAD_TOO_LARGE = new HttpStatus(413, "Payload Too Large"); + public static final HttpStatus URI_TOO_LONG = new HttpStatus(414, "URI Too Long"); + public static final HttpStatus UNSUPPORTED_MEDIA_TYPE = new HttpStatus(415, "Unsupported Media Type"); + public static final HttpStatus RANGE_NOT_SATISFIABLE = new HttpStatus(416, "Range Not Satisfiable"); + public static final HttpStatus EXPECTATION_FAILED = new HttpStatus(417, "Expectation Failed"); + public static final HttpStatus IM_A_TEAPOT = new HttpStatus(418, "I'm a teapot"); + public static final HttpStatus MISDIRECTED_REQUEST = new HttpStatus(421, "Misdirected Request"); + public static final HttpStatus UNPROCESSABLE_ENTITY = new HttpStatus(422, "Unprocessable Entity"); + public static final HttpStatus LOCKED = new HttpStatus(423, "Locked"); + public static final HttpStatus FAILED_DEPENDENCY = new HttpStatus(424, "Failed Dependency"); + public static final HttpStatus TOO_EARLY = new HttpStatus(425, "Too Early"); + public static final HttpStatus UPGRADE_REQUIRED = new HttpStatus(426, "Upgrade Required"); + public static final HttpStatus PRECONDITION_REQUIRED = new HttpStatus(428, "Precondition Required"); + public static final HttpStatus TOO_MANY_REQUESTS = new HttpStatus(429, "Too Many Requests"); + public static final HttpStatus REQUEST_HEADER_FIELDS_TOO_LARGE = new HttpStatus(431, + "Request Header Fields Too Large"); + public static final HttpStatus UNAVAILABLE_FOR_LEGAL_REASONS = new HttpStatus(451, "Unavailable For Legal Reasons"); + + // 5xx Server Error + public static final HttpStatus INTERNAL_SERVER_ERROR = new HttpStatus(500, "Internal Server Error"); + public static final HttpStatus NOT_IMPLEMENTED = new HttpStatus(501, "Not Implemented"); + public static final HttpStatus BAD_GATEWAY = new HttpStatus(502, "Bad Gateway"); + public static final HttpStatus SERVICE_UNAVAILABLE = new HttpStatus(503, "Service Unavailable"); + public static final HttpStatus GATEWAY_TIMEOUT = new HttpStatus(504, "Gateway Timeout"); + public static final HttpStatus HTTP_VERSION_NOT_SUPPORTED = new HttpStatus(505, "HTTP Version Not Supported"); + public static final HttpStatus VARIANT_ALSO_NEGOTIATES = new HttpStatus(506, "Variant Also Negotiates"); + public static final HttpStatus INSUFFICIENT_STORAGE = new HttpStatus(507, "Insufficient Storage"); + public static final HttpStatus LOOP_DETECTED = new HttpStatus(508, "Loop Detected"); + public static final HttpStatus NOT_EXTENDED = new HttpStatus(510, "Not Extended"); + public static final HttpStatus NETWORK_AUTHENTICATION_REQUIRED = new HttpStatus(511, + "Network Authentication Required"); + + private static final Map CODE_MAP; + + static { + CODE_MAP = new HashMap<>(62); + for (final var statusCode : List.of(CONTINUE, SWITCHING_PROTOCOLS, PROCESSING, EARLY_HINTS, OK, CREATED, + ACCEPTED, NON_AUTHORITATIVE_INFORMATION, NO_CONTENT, RESET_CONTENT, PARTIAL_CONTENT, MULTI_STATUS, + ALREADY_REPORTED, IM_USED, MULTIPLE_CHOICES, MOVED_PERMANENTLY, FOUND, SEE_OTHER, NOT_MODIFIED, + USE_PROXY, TEMPORARY_REDIRECT, PERMANENT_REDIRECT, BAD_REQUEST, UNAUTHORIZED, PAYMENT_REQUIRED, + FORBIDDEN, NOT_FOUND, METHOD_NOT_ALLOWED, NOT_ACCEPTABLE, PROXY_AUTHENTICATION_REQUIRED, + REQUEST_TIMEOUT, CONFLICT, GONE, LENGTH_REQUIRED, PRECONDITION_FAILED, PAYLOAD_TOO_LARGE, URI_TOO_LONG, + UNSUPPORTED_MEDIA_TYPE, RANGE_NOT_SATISFIABLE, EXPECTATION_FAILED, IM_A_TEAPOT, MISDIRECTED_REQUEST, + UNPROCESSABLE_ENTITY, LOCKED, FAILED_DEPENDENCY, TOO_EARLY, UPGRADE_REQUIRED, PRECONDITION_REQUIRED, + TOO_MANY_REQUESTS, REQUEST_HEADER_FIELDS_TOO_LARGE, UNAVAILABLE_FOR_LEGAL_REASONS, + INTERNAL_SERVER_ERROR, NOT_IMPLEMENTED, BAD_GATEWAY, SERVICE_UNAVAILABLE, GATEWAY_TIMEOUT, + HTTP_VERSION_NOT_SUPPORTED, VARIANT_ALSO_NEGOTIATES, INSUFFICIENT_STORAGE, LOOP_DETECTED, NOT_EXTENDED, + NETWORK_AUTHENTICATION_REQUIRED)) { + CODE_MAP.put(statusCode.code(), statusCode); + } + } + + /** + * Gets the HttpStatus from the predefined status codes with the + * {@link HttpStatus#code} matching the provided code. + * + * @param code the code to find the corresponding {@link HttpStatus} + * @return if found {@link HttpStatus}; else null + */ + public static HttpStatus fromCodeOrNull(int code) { + return CODE_MAP.get(code); + } + + /** + * Gets the HttpStatus from the predefined status codes with the + * {@link HttpStatus#code} matching the provided code. If there is no predefined + * {@link HttpStatus} a new custom {@link HttpStatus} is created. + * + * @param code the code to find the corresponding {@link HttpStatus} + * @return if found {@link HttpStatus}; else a custom {@link HttpStatus} from + * the provided arguments + */ + public static HttpStatus fromCodeOrCustom(int code, String description) { + final var predefinedStatus = HttpStatus.fromCodeOrNull(code); + if (predefinedStatus != null) { + return predefinedStatus; + } + return new HttpStatus(code, description); + } + + /** + * Checks if the HTTP status code is defined as a information response + * (100-199). + * + * @param status the HTTP status to check + * @return true if the status is defined as informational; else false + */ + public static final boolean isStatusInformational(int status) { + return status >= 100 && status < 200; + } + + /** + * Checks if the HTTP status code is defined as a successful response (200-299). + * + * @param status the HTTP status to check + * @return true if the status is defined as successful; else false + */ + public static final boolean isStatusSuccessful(int status) { + return status >= 200 && status < 300; + } + + /** + * Checks if the HTTP status code is defined as a redirection message (300-399). + * + * @param status the HTTP status to check + * @return true if the status is defined as a redirection; else false + */ + public static final boolean isStatusRedirection(int status) { + return status >= 300 && status < 400; + } + + /** + * Checks if the HTTP status code is defined as a client error response + * (400-499). + * + * @param status the HTTP status to check + * @return true if the status is defined as a client error; else false + */ + public static final boolean isStatusClientError(int status) { + return status >= 400 && status < 500; + } + + /** + * Checks if the HTTP status code is defined as a server error response + * (500-599). + * + * @param status the HTTP status to check + * @return true if the status is defined as a server error; else false + */ + public static final boolean isStatusServerError(int status) { + return status >= 500 && status < 600; + } + + /** + * Checks if the HTTP status code is a client error or a server error. + * + * @param status the HTTP status to check + * @return true if the status is either a client error or server error; else + * false + * @see #isStatusClientError(int) + * @see #isStatusServerError(int) + */ + public static final boolean isStatusError(int status) { + return isStatusClientError(status) || isStatusServerError(status); + } + + @Override + public String toString() { + return this.code + " " + this.description; + } + + /** + * Checks if the HTTP status code is defined as a information response + * (100-199). + * + * @return true if the status is defined as informational; else false + * @see #isStatusInformational(int) + */ + public boolean isInformational() { + return isStatusInformational(this.code); + } + + /** + * Checks if the HTTP status code is defined as a successful response (200-299). + * + * @return true if the status is defined as successful; else false + * @see #isStatusSuccessful(int) + */ + public boolean isSuccessful() { + return isStatusSuccessful(this.code); + } + + /** + * Checks if the HTTP status code is defined as a redirection message (300-399). + * + * @return true if the status is defined as a redirection; else false + * @see #isStatusRedirection(int) + */ + public boolean isRedirection() { + return isStatusRedirection(this.code); + } + + /** + * Checks if the HTTP status code is defined as a client error response + * (400-499). + * + * @return true if the status is defined as a client error; else false + * @see #isStatusClientError(int) + */ + public boolean isClientError() { + return isStatusClientError(this.code); + } + + /** + * Checks if the HTTP status code is defined as a server error response + * (500-599). + * + * @return true if the status is defined as a server error; else false + * @see #isStatusServerError(int) + */ + public boolean isServerError() { + return isStatusServerError(this.code); + } + + /** + * Checks if the HTTP status code is a client error or a server error. + * + * @return true if the status is either a client error or server error; else + * false + * @see #isStatusError(int) + */ + public boolean isError() { + return isStatusError(this.code); + } + +} diff --git a/io.openems.common/test/io/openems/common/types/HttpStatusTest.java b/io.openems.common/test/io/openems/common/types/HttpStatusTest.java new file mode 100644 index 00000000000..f4500769d42 --- /dev/null +++ b/io.openems.common/test/io/openems/common/types/HttpStatusTest.java @@ -0,0 +1,84 @@ +package io.openems.common.types; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class HttpStatusTest { + + @Test + public void testIsStatusInformational() { + assertFalse(HttpStatus.isStatusInformational(99)); + assertTrue(HttpStatus.isStatusInformational(100)); + assertFalse(HttpStatus.isStatusInformational(200)); + assertTrue(HttpStatus.CONTINUE.isInformational()); + assertFalse(HttpStatus.NOT_FOUND.isInformational()); + } + + @Test + public void testIsStatusSuccessful() { + assertFalse(HttpStatus.isStatusSuccessful(199)); + assertTrue(HttpStatus.isStatusSuccessful(200)); + assertFalse(HttpStatus.isStatusSuccessful(400)); + assertTrue(HttpStatus.OK.isSuccessful()); + assertFalse(HttpStatus.NOT_FOUND.isSuccessful()); + } + + @Test + public void testIsStatusRedirection() { + assertFalse(HttpStatus.isStatusRedirection(299)); + assertTrue(HttpStatus.isStatusRedirection(300)); + assertFalse(HttpStatus.isStatusRedirection(400)); + assertTrue(HttpStatus.MULTIPLE_CHOICES.isRedirection()); + assertFalse(HttpStatus.NOT_FOUND.isRedirection()); + } + + @Test + public void testIsStatusClientError() { + assertFalse(HttpStatus.isStatusClientError(399)); + assertTrue(HttpStatus.isStatusClientError(400)); + assertFalse(HttpStatus.isStatusClientError(500)); + assertTrue(HttpStatus.NOT_FOUND.isClientError()); + assertFalse(HttpStatus.MULTIPLE_CHOICES.isClientError()); + } + + @Test + public void testIsStatusServerError() { + assertFalse(HttpStatus.isStatusServerError(499)); + assertTrue(HttpStatus.isStatusServerError(500)); + assertFalse(HttpStatus.isStatusServerError(600)); + assertTrue(HttpStatus.INTERNAL_SERVER_ERROR.isServerError()); + assertFalse(HttpStatus.NOT_FOUND.isServerError()); + } + + @Test + public void testIsStatusError() { + assertTrue(HttpStatus.isStatusError(400)); + assertTrue(HttpStatus.isStatusError(500)); + assertFalse(HttpStatus.isStatusError(200)); + assertTrue(HttpStatus.NOT_FOUND.isError()); + assertTrue(HttpStatus.INTERNAL_SERVER_ERROR.isError()); + assertFalse(HttpStatus.OK.isError()); + } + + @Test + public void testFromCodeOrNull() { + assertEquals(HttpStatus.OK, HttpStatus.fromCodeOrNull(HttpStatus.OK.code())); + assertNull(HttpStatus.fromCodeOrNull(666)); + } + + @Test + public void testFromCodeOrCustom() { + assertEquals(HttpStatus.OK, HttpStatus.fromCodeOrCustom(HttpStatus.OK.code(), HttpStatus.OK.description())); + assertEquals(new HttpStatus(666, "custom description"), HttpStatus.fromCodeOrCustom(666, "custom description")); + } + + @Test + public void testToString() { + assertEquals("200 OK", HttpStatus.OK.toString()); + } + +} diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index 31f9a35776c..b72c41b92c5 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -185,6 +185,8 @@ bnd.identity;id='io.openems.edge.timeofusetariff.awattar',\ bnd.identity;id='io.openems.edge.timeofusetariff.corrently',\ bnd.identity;id='io.openems.edge.timeofusetariff.entsoe',\ + bnd.identity;id='io.openems.edge.timeofusetariff.groupe',\ + bnd.identity;id='io.openems.edge.timeofusetariff.hassfurt',\ bnd.identity;id='io.openems.edge.timeofusetariff.rabotcharge',\ bnd.identity;id='io.openems.edge.timeofusetariff.tibber',\ @@ -363,6 +365,8 @@ io.openems.edge.timeofusetariff.awattar;version=snapshot,\ io.openems.edge.timeofusetariff.corrently;version=snapshot,\ io.openems.edge.timeofusetariff.entsoe;version=snapshot,\ + io.openems.edge.timeofusetariff.groupe;version=snapshot,\ + io.openems.edge.timeofusetariff.hassfurt;version=snapshot,\ io.openems.edge.timeofusetariff.rabotcharge;version=snapshot,\ io.openems.edge.timeofusetariff.tibber;version=snapshot,\ io.openems.oem.openems;version=snapshot,\ diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/AsyncBridgeHttpExecutor.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/AsyncBridgeHttpExecutor.java new file mode 100644 index 00000000000..67393ff110c --- /dev/null +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/AsyncBridgeHttpExecutor.java @@ -0,0 +1,42 @@ +package io.openems.edge.bridge.http; + +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.ServiceScope; + +import io.openems.common.utils.ThreadPoolUtils; +import io.openems.edge.bridge.http.api.BridgeHttpExecutor; +import io.openems.edge.bridge.http.time.DelayTimeProvider.Delay; + +@Component(scope = ServiceScope.PROTOTYPE) +public class AsyncBridgeHttpExecutor implements BridgeHttpExecutor { + + // TODO change to java 21 virtual threads + private final ScheduledExecutorService pool = Executors.newScheduledThreadPool(0); + + @Override + public ScheduledFuture schedule(Runnable task, Delay.DurationDelay durationDelay) { + return this.pool.schedule(task, durationDelay.getDuration().toMillis(), TimeUnit.MILLISECONDS); + } + + @Override + public void execute(Runnable task) { + this.pool.execute(task); + } + + @Override + public boolean isShutdown() { + return this.pool.isShutdown(); + } + + @Deactivate + private void deactivate() { + ThreadPoolUtils.shutdownAndAwaitTermination(this.pool, 0); + } + +} diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/BridgeHttpImpl.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/BridgeHttpImpl.java index 92da80fdd4e..460236c183c 100644 --- a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/BridgeHttpImpl.java +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/BridgeHttpImpl.java @@ -1,24 +1,33 @@ package io.openems.edge.bridge.http; +import java.util.ArrayList; +import java.util.Collection; import java.util.HashSet; -import java.util.PriorityQueue; +import java.util.Objects; import java.util.Set; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.PriorityBlockingQueue; +import java.util.function.Predicate; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Deactivate; import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceScope; import org.osgi.service.component.annotations.ServiceScope; import org.osgi.service.event.Event; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.openems.common.utils.ThreadPoolUtils; +import io.openems.common.utils.FunctionUtils; import io.openems.edge.bridge.http.api.BridgeHttp; +import io.openems.edge.bridge.http.api.BridgeHttpExecutor; +import io.openems.edge.bridge.http.api.CycleSubscriber; +import io.openems.edge.bridge.http.api.EndpointFetcher; +import io.openems.edge.bridge.http.api.HttpError; +import io.openems.edge.bridge.http.api.HttpResponse; +import io.openems.edge.bridge.http.time.DelayTimeProvider.Delay; import io.openems.edge.common.event.EdgeEventConstants; @Component(// @@ -28,7 +37,7 @@ public class BridgeHttpImpl implements BridgeHttp { public static class CycleEndpointCountdown { private volatile int cycleCount; - public final CycleEndpoint cycleEndpoint; + private final CycleEndpoint cycleEndpoint; private volatile boolean running = false; public CycleEndpointCountdown(CycleEndpoint endpoint) { @@ -36,13 +45,27 @@ public CycleEndpointCountdown(CycleEndpoint endpoint) { this.cycleEndpoint = endpoint; } + public CycleEndpoint getCycleEndpoint() { + return this.cycleEndpoint; + } + /** * Resets the current cycle count to the initial cycle count. * * @return this */ public CycleEndpointCountdown reset() { - this.cycleCount = this.cycleEndpoint.cycle(); + return this.resetTo(this.cycleEndpoint.cycle()); + } + + /** + * Resets the current cycle count to the given cycle count. + * + * @param cycleCount the cycleCount to reset the current cycleCount to + * @return this + */ + public CycleEndpointCountdown resetTo(int cycleCount) { + this.cycleCount = cycleCount; return this; } @@ -71,7 +94,7 @@ public static class TimeEndpointCountdown { private final TimeEndpoint timeEndpoint; private volatile boolean running = false; private volatile boolean shutdown = false; - private Runnable shutdownCurrentTask; + private Runnable shutdownCurrentTask = FunctionUtils::doNothing; public TimeEndpointCountdown(TimeEndpoint timeEndpoint) { this.timeEndpoint = timeEndpoint; @@ -98,7 +121,7 @@ public void setShutdown(boolean shutdown) { } public void setShutdownCurrentTask(Runnable shutdownCurrentTask) { - this.shutdownCurrentTask = shutdownCurrentTask; + this.shutdownCurrentTask = shutdownCurrentTask == null ? FunctionUtils::doNothing : shutdownCurrentTask; } /** @@ -106,36 +129,33 @@ public void setShutdownCurrentTask(Runnable shutdownCurrentTask) { */ public void shutdown() { this.setShutdown(true); - final var shutdownTask = this.shutdownCurrentTask; - if (shutdownTask != null) { - shutdownTask.run(); - } + this.shutdownCurrentTask.run(); } } private final Logger log = LoggerFactory.getLogger(BridgeHttpImpl.class); - @Reference - private CycleSubscriber cycleSubscriber; - - @Reference - private UrlFetcher urlFetcher; + private final CycleSubscriber cycleSubscriber; + private final EndpointFetcher urlFetcher; + private final BridgeHttpExecutor pool; - // TODO change to java 21 virtual threads - // TODO: Single pool for every http worker & avoid same endpoint in that pool - private final ScheduledExecutorService pool = Executors.newScheduledThreadPool(0); - - private final PriorityQueue cycleEndpoints = new PriorityQueue<>( + private final PriorityBlockingQueue cycleEndpoints = new PriorityBlockingQueue<>(11, (e1, e2) -> e1.getCycleCount() - e2.getCycleCount()); - private final Set timeEndpoints = new HashSet<>(); + private final Set timeEndpoints = ConcurrentHashMap.newKeySet(); - /** - * Activate method. - */ @Activate - public void activate() { + public BridgeHttpImpl(// + @Reference final CycleSubscriber cycleSubscriber, // + @Reference final EndpointFetcher urlFetcher, // + @Reference(scope = ReferenceScope.PROTOTYPE_REQUIRED) final BridgeHttpExecutor pool // + ) { + super(); + this.cycleSubscriber = cycleSubscriber; + this.urlFetcher = urlFetcher; + this.pool = pool; + this.cycleSubscriber.subscribe(this::handleEvent); } @@ -148,35 +168,46 @@ public void deactivate() { this.cycleEndpoints.clear(); this.timeEndpoints.forEach(TimeEndpointCountdown::shutdown); this.timeEndpoints.clear(); - ThreadPoolUtils.shutdownAndAwaitTermination(this.pool, 0); } @Override - public void subscribeCycle(CycleEndpoint endpoint) { + public CycleEndpoint subscribeCycle(CycleEndpoint endpoint) { + Objects.requireNonNull(endpoint, "CycleEndpoint is not allowed to be null!"); + if (!this.cycleEndpoints.offer(new CycleEndpointCountdown(endpoint))) { this.log.warn("Unable to add " + endpoint + "!"); + return null; } + return endpoint; } @Override - public void subscribeTime(TimeEndpoint endpoint) { + public TimeEndpoint subscribeTime(TimeEndpoint endpoint) { + Objects.requireNonNull(endpoint, "TimeEndpoint is not allowed to be null!"); + final var endpointCountdown = new TimeEndpointCountdown(endpoint); this.timeEndpoints.add(endpointCountdown); - final var delay = endpoint.delayTimeProvider().nextRun(true, true); - final var future = this.pool.schedule(this.createTask(endpointCountdown), delay.toMillis(), - TimeUnit.MILLISECONDS); - endpointCountdown.setShutdownCurrentTask(() -> future.cancel(false)); + final var delay = endpoint.delayTimeProvider().onFirstRunDelay(); + + // TODO change in java 21 to switch case + if (delay instanceof Delay.DurationDelay durationDelay) { + final var future = this.pool.schedule(this.createTask(endpointCountdown), durationDelay); + endpointCountdown.setShutdownCurrentTask(() -> future.cancel(false)); + } + return endpoint; } @Override - public CompletableFuture request(Endpoint endpoint) { - final var future = new CompletableFuture(); + public CompletableFuture> request(Endpoint endpoint) { + final var future = new CompletableFuture>(); this.pool.execute(() -> { try { final var result = this.urlFetcher.fetchEndpoint(endpoint); future.complete(result); - } catch (Exception e) { + } catch (HttpError e) { future.completeExceptionally(e); + } catch (Exception e) { + future.completeExceptionally(new HttpError.UnknownError(e)); } }); return future; @@ -193,13 +224,16 @@ private void handleEvent(Event event) { this.cycleEndpoints.forEach(CycleEndpointCountdown::decreaseCycleCount); - while (this.cycleEndpoints.peek().getCycleCount() == 0) { + while (!this.cycleEndpoints.isEmpty() // + && this.cycleEndpoints.peek().getCycleCount() == 0) { final var item = this.cycleEndpoints.poll(); synchronized (item) { if (item.isRunning()) { this.log.info( "Process for " + item.cycleEndpoint + " is still running. Task is not queued twice"); - this.cycleEndpoints.add(item.reset()); + if (!this.cycleEndpoints.offer(item.resetTo(1))) { + this.log.info("Unable to re-add " + item + " to queue again."); + } continue; } @@ -218,10 +252,10 @@ private void handleEvent(Event event) { private Runnable createTask(CycleEndpointCountdown endpointItem) { return () -> { try { - final var result = this.urlFetcher.fetchEndpoint(endpointItem.cycleEndpoint.endpoint()); - endpointItem.cycleEndpoint.result().accept(result); - } catch (Exception e) { - endpointItem.cycleEndpoint.onError().accept(e); + final var result = this.urlFetcher.fetchEndpoint(endpointItem.getCycleEndpoint().endpoint().get()); + endpointItem.getCycleEndpoint().onResult().accept(result); + } catch (HttpError e) { + endpointItem.getCycleEndpoint().onError().accept(e); } finally { synchronized (endpointItem) { endpointItem.setRunning(false); @@ -238,14 +272,17 @@ private Runnable createTask(TimeEndpointCountdown endpointCountdown) { } endpointCountdown.setRunning(true); } - boolean currentRunSuccessful; + HttpResponse result = null; + HttpError error = null; try { - final var result = this.urlFetcher.fetchEndpoint(endpointCountdown.getTimeEndpoint().endpoint()); + result = this.urlFetcher.fetchEndpoint(endpointCountdown.getTimeEndpoint().endpoint().get()); endpointCountdown.getTimeEndpoint().onResult().accept(result); - currentRunSuccessful = true; - } catch (Exception e) { + } catch (HttpError e) { endpointCountdown.getTimeEndpoint().onError().accept(e); - currentRunSuccessful = false; + error = e; + } catch (Exception e) { + error = new HttpError.UnknownError(e); + endpointCountdown.getTimeEndpoint().onError().accept(error); } synchronized (endpointCountdown) { if (endpointCountdown.isShutdown()) { @@ -254,12 +291,22 @@ private Runnable createTask(TimeEndpointCountdown endpointCountdown) { } try { - final var nextDelay = endpointCountdown.getTimeEndpoint().delayTimeProvider().nextRun(false, - currentRunSuccessful); + final Delay nextDelay; + if (error != null) { + nextDelay = endpointCountdown.getTimeEndpoint().delayTimeProvider().onErrorRunDelay(error); + } else { + nextDelay = endpointCountdown.getTimeEndpoint().delayTimeProvider().onSuccessRunDelay(result); + } + + // TODO change in java 21 to switch case + if (nextDelay instanceof Delay.InfiniteDelay) { + // do not queue again + return; + } else if (nextDelay instanceof Delay.DurationDelay durationDelay) { + final var future = this.pool.schedule(this.createTask(endpointCountdown), durationDelay); + endpointCountdown.setShutdownCurrentTask(() -> future.cancel(false)); + } - final var future = this.pool.schedule(this.createTask(endpointCountdown), nextDelay.toMillis(), - TimeUnit.MILLISECONDS); - endpointCountdown.setShutdownCurrentTask(() -> future.cancel(false)); } catch (Exception e) { if (this.pool.isShutdown()) { return; @@ -269,12 +316,23 @@ private Runnable createTask(TimeEndpointCountdown endpointCountdown) { }; } - public PriorityQueue getCycleEndpoints() { - return this.cycleEndpoints; + @Override + public Collection removeTimeEndpointIf(Predicate condition) { + return new HashSet<>(this.timeEndpoints).stream() // + .filter(t -> condition.test(t.getTimeEndpoint())) // + .filter(this.timeEndpoints::remove) // + .peek(TimeEndpointCountdown::shutdown) // + .map(TimeEndpointCountdown::getTimeEndpoint) // + .toList(); } - public Set getTimeEndpoints() { - return this.timeEndpoints; + @Override + public Collection removeCycleEndpointIf(Predicate condition) { + return new ArrayList<>(this.cycleEndpoints).stream() // + .filter(t -> condition.test(t.getCycleEndpoint())) // + .filter(this.cycleEndpoints::remove) // + .map(CycleEndpointCountdown::getCycleEndpoint) // + .toList(); } } diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/UrlFetcherImpl.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/NetworkEndpointFetcher.java similarity index 60% rename from io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/UrlFetcherImpl.java rename to io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/NetworkEndpointFetcher.java index c4ac5a52672..3a751cd7ffc 100644 --- a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/UrlFetcherImpl.java +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/NetworkEndpointFetcher.java @@ -7,21 +7,23 @@ import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.HttpURLConnection; -import java.net.URL; +import java.net.URI; import org.osgi.service.component.annotations.Component; -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.exceptions.OpenemsException; +import io.openems.common.types.HttpStatus; import io.openems.edge.bridge.http.api.BridgeHttp.Endpoint; +import io.openems.edge.bridge.http.api.EndpointFetcher; +import io.openems.edge.bridge.http.api.HttpError; +import io.openems.edge.bridge.http.api.HttpResponse; @Component -public class UrlFetcherImpl implements UrlFetcher { +public class NetworkEndpointFetcher implements EndpointFetcher { @Override - public String fetchEndpoint(final Endpoint endpoint) throws OpenemsNamedException { + public HttpResponse fetchEndpoint(final Endpoint endpoint) throws HttpError { try { - var url = new URL(endpoint.url()); + var url = URI.create(endpoint.url()).toURL(); var con = (HttpURLConnection) url.openConnection(); con.setRequestMethod(endpoint.method().name()); con.setConnectTimeout(endpoint.connectTimeout()); @@ -38,23 +40,22 @@ public String fetchEndpoint(final Endpoint endpoint) throws OpenemsNamedExceptio } } - final var status = con.getResponseCode(); + final var status = HttpStatus.fromCodeOrCustom(con.getResponseCode(), con.getResponseMessage()); + String body; try (var in = new BufferedReader(new InputStreamReader(con.getInputStream()))) { // Read HTTP response body = in.lines().collect(joining(System.lineSeparator())); + } catch (IOException e) { + throw new HttpError.ResponseError(status, null); } - // Check valid for all? - if (status < 300) { - return body; - } else { - throw new OpenemsException( - "Error while reading Endpoint " + endpoint.url() + ". Response code: " + status + ". " + body); + if (status.isError()) { + throw new HttpError.ResponseError(status, body); } - + return new HttpResponse<>(status, body); } catch (IOException e) { - throw new OpenemsException(e); + throw new HttpError.UnknownError(e); } } diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/BridgeHttp.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/BridgeHttp.java index 3a01db4f3f0..52e198f75f8 100644 --- a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/BridgeHttp.java +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/BridgeHttp.java @@ -3,11 +3,12 @@ import static java.util.Collections.emptyMap; import java.util.Map; +import java.util.Objects; import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; import com.google.gson.JsonElement; +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.function.ThrowingFunction; import io.openems.common.utils.JsonUtils; @@ -55,12 +56,6 @@ public interface BridgeHttp extends BridgeHttpCycle, BridgeHttpTime { public static int DEFAULT_CONNECT_TIMEOUT = 5000; // 5s public static int DEFAULT_READ_TIMEOUT = 5000; // 5s - /** - * Default empty error handler. - */ - public static final Consumer EMPTY_ERROR_HANDLER = t -> { - }; - public record Endpoint(// String url, // HttpMethod method, // @@ -70,6 +65,12 @@ public record Endpoint(// Map properties // ) { + public Endpoint { + Objects.requireNonNull(url, "Url of Endpoint must not be null!"); + Objects.requireNonNull(method, "Method of Endpoint must not be null!"); + Objects.requireNonNull(properties, "Properties of Endpoint must not be null!"); + } + } /** @@ -78,7 +79,7 @@ public record Endpoint(// * @param url the url to fetch * @return the result response future */ - public default CompletableFuture get(String url) { + public default CompletableFuture> get(String url) { final var endpoint = new Endpoint(// url, // HttpMethod.GET, // @@ -97,8 +98,8 @@ public default CompletableFuture get(String url) { * @param url the url to fetch * @return the result response future */ - public default CompletableFuture getJson(String url) { - return mapFuture(this.get(url), JsonUtils::parse); + public default CompletableFuture> getJson(String url) { + return mapFuture(this.get(url), BridgeHttp::mapToJson); } /** @@ -107,7 +108,7 @@ public default CompletableFuture getJson(String url) { * @param url the url to fetch * @return the result response future */ - public default CompletableFuture put(String url) { + public default CompletableFuture> put(String url) { final var endpoint = new Endpoint(// url, // HttpMethod.PUT, // @@ -126,8 +127,8 @@ public default CompletableFuture put(String url) { * @param url the url to fetch * @return the result response future */ - public default CompletableFuture putJson(String url) { - return mapFuture(this.put(url), JsonUtils::parse); + public default CompletableFuture> putJson(String url) { + return mapFuture(this.put(url), BridgeHttp::mapToJson); } /** @@ -137,7 +138,7 @@ public default CompletableFuture putJson(String url) { * @param body the request body to send * @return the result response future */ - public default CompletableFuture post(String url, String body) { + public default CompletableFuture> post(String url, String body) { final var endpoint = new Endpoint(// url, // HttpMethod.POST, // @@ -157,8 +158,8 @@ public default CompletableFuture post(String url, String body) { * @param body the request body to send * @return the result response future */ - public default CompletableFuture postJson(String url, JsonElement body) { - return mapFuture(this.post(url, body.toString()), JsonUtils::parse); + public default CompletableFuture> postJson(String url, JsonElement body) { + return mapFuture(this.post(url, body.toString()), BridgeHttp::mapToJson); } /** @@ -167,7 +168,7 @@ public default CompletableFuture postJson(String url, JsonElement b * @param url the url to fetch * @return the result response future */ - public default CompletableFuture delete(String url) { + public default CompletableFuture> delete(String url) { final var endpoint = new Endpoint(// url, // HttpMethod.DELETE, // @@ -186,8 +187,8 @@ public default CompletableFuture delete(String url) { * @param url the url to fetch * @return the result response future */ - public default CompletableFuture deleteJson(String url) { - return mapFuture(this.delete(url), JsonUtils::parse); + public default CompletableFuture> deleteJson(String url) { + return mapFuture(this.delete(url), BridgeHttp::mapToJson); } /** @@ -196,7 +197,7 @@ public default CompletableFuture deleteJson(String url) { * @param endpoint the {@link Endpoint} to fetch * @return the result response future */ - public CompletableFuture request(Endpoint endpoint); + public CompletableFuture> request(Endpoint endpoint); /** * Fetches the url once and expects the result to be in json format. @@ -204,8 +205,12 @@ public default CompletableFuture deleteJson(String url) { * @param endpoint the {@link Endpoint} to fetch * @return the result response future */ - public default CompletableFuture requestJson(Endpoint endpoint) { - return mapFuture(this.request(endpoint), JsonUtils::parse); + public default CompletableFuture> requestJson(Endpoint endpoint) { + return mapFuture(this.request(endpoint), BridgeHttp::mapToJson); + } + + private static HttpResponse mapToJson(HttpResponse origin) throws OpenemsNamedException { + return origin.withData(JsonUtils.parse(origin.data())); } private static CompletableFuture mapFuture(// diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/BridgeHttpCycle.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/BridgeHttpCycle.java index 2c1f7152e9f..0c7764eacf5 100644 --- a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/BridgeHttpCycle.java +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/BridgeHttpCycle.java @@ -2,12 +2,17 @@ import static java.util.Collections.emptyMap; +import java.util.Collection; +import java.util.Objects; import java.util.function.BiConsumer; import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.function.Supplier; import com.google.gson.JsonElement; import io.openems.common.function.ThrowingConsumer; +import io.openems.common.utils.FunctionUtils; import io.openems.common.utils.JsonUtils; import io.openems.edge.bridge.http.api.BridgeHttp.Endpoint; @@ -50,20 +55,29 @@ public record CycleEndpoint(// /** * The url which should be fetched. */ - Endpoint endpoint, // + Supplier endpoint, // /** * The callback to execute on every successful result. */ - Consumer result, // + Consumer> onResult, // /** * The callback to execute on every error. */ - Consumer onError // + Consumer onError // ) { + public CycleEndpoint { + Objects.requireNonNull(endpoint, "Endpoint of CycleEndpoint must not be null!"); + Objects.requireNonNull(onResult, "OnResult of CycleEndpoint must not be null!"); + Objects.requireNonNull(onError, "OnError of CycleEndpoint must not be null!"); + if (cycle < 1) { + throw new IllegalArgumentException("Cycle of CycleEndpoint must not be lower than 1!"); + } + } + @Override public String toString() { - return "Endpoint [cycle=" + this.cycle() + ", url=" + this.endpoint.url() + "]"; + return "CycleEndpoint [cycle=" + this.cycle + ", url=" + this.endpoint.get().url() + "]"; } } @@ -72,8 +86,10 @@ public String toString() { * Subscribes to one http endpoint. * * @param endpoint the {@link CycleEndpoint} configuration + * @return the added {@link CycleEndpoint} (always the provided one); or null if + * the {@link CycleEndpoint} could not be added */ - public void subscribeCycle(CycleEndpoint endpoint); + public CycleEndpoint subscribeCycle(CycleEndpoint endpoint); /** * Subscribes to one http endpoint. @@ -86,8 +102,10 @@ public String toString() { * @param cycle the number of cycles to wait between requests * @param url the url of the enpoint * @param result the consumer to call on every successful result + * @return the added {@link CycleEndpoint}; or null if the {@link CycleEndpoint} + * could not be added */ - public default void subscribeCycle(int cycle, String url, Consumer result) { + public default CycleEndpoint subscribeCycle(int cycle, String url, Consumer> result) { final var endpoint = new Endpoint(// url, // HttpMethod.GET, // @@ -96,7 +114,7 @@ public default void subscribeCycle(int cycle, String url, Consumer resul null, // emptyMap() // ); - this.subscribeCycle(new CycleEndpoint(cycle, endpoint, result, BridgeHttp.EMPTY_ERROR_HANDLER)); + return this.subscribeCycle(new CycleEndpoint(cycle, () -> endpoint, result, FunctionUtils::doNothing)); } /** @@ -107,16 +125,18 @@ public default void subscribeCycle(int cycle, String url, Consumer resul * the next get request to the url gets send when the last was finished either * successfully or with an error. * - * @param cycle the number of cycles to wait between requests - * @param url the url of the enpoint - * @param result the consumer to call on every successful result - * @param onError the consumer to call on a error + * @param cycle the number of cycles to wait between requests + * @param url the url of the enpoint + * @param onResult the consumer to call on every successful result + * @param onError the consumer to call on a error + * @return the added {@link CycleEndpoint}; or null if the {@link CycleEndpoint} + * could not be added */ - public default void subscribeCycle(// + public default CycleEndpoint subscribeCycle(// final int cycle, // final String url, // - final ThrowingConsumer result, // - final Consumer onError // + final ThrowingConsumer, Exception> onResult, // + final Consumer onError // ) { final var endpoint = new Endpoint(// url, // @@ -126,11 +146,63 @@ public default void subscribeCycle(// null, // emptyMap() // ); - this.subscribeCycle(new CycleEndpoint(cycle, endpoint, t -> { + return this.subscribeCycle(cycle, endpoint, onResult, onError); + } + + /** + * Subscribes to one http endpoint. + * + *

      + * Tries to fetch data every n-cycle. If receiving data takes more than n-cycle + * the next get request to the url gets send when the last was finished either + * successfully or with an error. + * + * @param cycle the number of cycles to wait between requests + * @param endpoint the {@link Endpoint} to fetch + * @param onResult the consumer to call on every successful result + * @param onError the consumer to call on a error + * @return the added {@link CycleEndpoint}; or null if the {@link CycleEndpoint} + * could not be added + */ + public default CycleEndpoint subscribeCycle(// + final int cycle, // + final Endpoint endpoint, // + final ThrowingConsumer, Exception> onResult, // + final Consumer onError // + ) { + return this.subscribeCycle(cycle, () -> endpoint, onResult, onError); + } + + /** + * Subscribes to one http endpoint. + * + *

      + * Tries to fetch data every n-cycle. If receiving data takes more than n-cycle + * the next get request to the url gets send when the last was finished either + * successfully or with an error. + * + * @param cycle the number of cycles to wait between requests + * @param endpointSupplier the supplier to get the {@link Endpoint} to fetch; + * the {@link Supplier} get called right before the + * fetch happens + * @param onResult the consumer to call on every successful result + * @param onError the consumer to call on a error + * @return the added {@link CycleEndpoint}; or null if the {@link CycleEndpoint} + * could not be added + */ + public default CycleEndpoint subscribeCycle(// + final int cycle, // + final Supplier endpointSupplier, // + final ThrowingConsumer, Exception> onResult, // + final Consumer onError // + ) { + return this.subscribeCycle(new CycleEndpoint(cycle, endpointSupplier, t -> { try { - result.accept(t); - } catch (Exception e) { + onResult.accept(t); + } catch (HttpError e) { onError.accept(e); + } catch (Exception e) { + onError.accept(new HttpError.UnknownError(e)); } }, onError)); } @@ -148,13 +220,15 @@ public default void subscribeCycle(// * @param action the action to perform; the first is the result of the endpoint * if existing and the second argument is passed if an error * happend. One of the params is always null and one not + * @return the added {@link CycleEndpoint}; or null if the {@link CycleEndpoint} + * could not be added */ - public default void subscribeCycle(// + public default CycleEndpoint subscribeCycle(// final int cycle, // final String url, // - final BiConsumer action // + final BiConsumer, HttpError> action // ) { - this.subscribeCycle(cycle, url, r -> action.accept(r, null), t -> action.accept(null, t)); + return this.subscribeCycle(cycle, url, r -> action.accept(r, null), t -> action.accept(null, t)); } /** @@ -165,16 +239,18 @@ public default void subscribeCycle(// * the next get request to the url gets send when the last was finished either * successfully or with an error. * - * @param url the url of the enpoint - * @param result the consumer to call on every successful result - * @param onError the consumer to call on a error + * @param url the url of the enpoint + * @param onResult the consumer to call on every successful result + * @param onError the consumer to call on a error + * @return the added {@link CycleEndpoint}; or null if the {@link CycleEndpoint} + * could not be added */ - public default void subscribeEveryCycle(// + public default CycleEndpoint subscribeEveryCycle(// final String url, // - final ThrowingConsumer result, // - final Consumer onError // + final ThrowingConsumer, Exception> onResult, // + final Consumer onError // ) { - this.subscribeCycle(1, url, result, onError); + return this.subscribeCycle(1, url, onResult, onError); } /** @@ -189,12 +265,14 @@ public default void subscribeEveryCycle(// * @param action the action to perform; the first is the result of the endpoint * if existing and the second argument is passed if an error * happend. One of the params is always null and one not + * @return the added {@link CycleEndpoint}; or null if the {@link CycleEndpoint} + * could not be added */ - public default void subscribeEveryCycle(// + public default CycleEndpoint subscribeEveryCycle(// final String url, // - final BiConsumer action // + final BiConsumer, HttpError> action // ) { - this.subscribeCycle(1, url, r -> action.accept(r, null), t -> action.accept(null, t)); + return this.subscribeCycle(1, url, r -> action.accept(r, null), t -> action.accept(null, t)); } /** @@ -207,12 +285,14 @@ public default void subscribeEveryCycle(// * * @param url the url of the enpoint * @param result the consumer to call on every successful result + * @return the added {@link CycleEndpoint}; or null if the {@link CycleEndpoint} + * could not be added */ - public default void subscribeEveryCycle(// + public default CycleEndpoint subscribeEveryCycle(// final String url, // - final Consumer result // + final Consumer> result // ) { - this.subscribeCycle(1, url, result); + return this.subscribeCycle(1, url, result); } /** @@ -227,14 +307,16 @@ public default void subscribeEveryCycle(// * @param url the url of the enpoint * @param result the consumer to call on every successful result * @param onError the consumer to call on a error + * @return the added {@link CycleEndpoint}; or null if the {@link CycleEndpoint} + * could not be added */ - public default void subscribeJsonCycle(// + public default CycleEndpoint subscribeJsonCycle(// final int cycle, // final String url, // - final ThrowingConsumer result, // - final Consumer onError // + final ThrowingConsumer, Exception> result, // + final Consumer onError // ) { - this.subscribeCycle(cycle, url, t -> result.accept(JsonUtils.parse(t)), onError); + return this.subscribeCycle(cycle, url, t -> result.accept(t.withData(JsonUtils.parse(t.data()))), onError); } /** @@ -250,13 +332,16 @@ public default void subscribeJsonCycle(// * @param action the action to perform; the first is the result of the endpoint * if existing and the second argument is passed if an error * happend. One of the params is always null and one not + * @return the added {@link CycleEndpoint}; or null if the {@link CycleEndpoint} + * could not be added */ - public default void subscribeJsonCycle(// + public default CycleEndpoint subscribeJsonCycle(// final int cycle, // final String url, // - final BiConsumer action // + final BiConsumer, HttpError> action // ) { - this.subscribeCycle(cycle, url, t -> action.accept(JsonUtils.parse(t), null), t -> action.accept(null, t)); + return this.subscribeCycle(cycle, url, t -> action.accept(t.withData(JsonUtils.parse(t.data())), null), + t -> action.accept(null, t)); } /** @@ -267,16 +352,18 @@ public default void subscribeJsonCycle(// * the next get request to the url gets send when the last was finished either * successfully or with an error. * - * @param url the url of the enpoint - * @param result the consumer to call on every successful result - * @param onError the consumer to call on a error + * @param url the url of the enpoint + * @param onResult the consumer to call on every successful result + * @param onError the consumer to call on a error + * @return the added {@link CycleEndpoint}; or null if the {@link CycleEndpoint} + * could not be added */ - public default void subscribeJsonEveryCycle(// + public default CycleEndpoint subscribeJsonEveryCycle(// final String url, // - final ThrowingConsumer result, // - final Consumer onError // + final ThrowingConsumer, Exception> onResult, // + final Consumer onError // ) { - this.subscribeJsonCycle(1, url, result, onError); + return this.subscribeJsonCycle(1, url, onResult, onError); } /** @@ -291,12 +378,42 @@ public default void subscribeJsonEveryCycle(// * @param action the action to perform; the first is the result of the endpoint * if existing and the second argument is passed if an error * happend. One of the params is always null and one not + * @return the added {@link CycleEndpoint}; or null if the {@link CycleEndpoint} + * could not be added */ - public default void subscribeJsonEveryCycle(// + public default CycleEndpoint subscribeJsonEveryCycle(// final String url, // - final BiConsumer action // + final BiConsumer, HttpError> action // ) { - this.subscribeJsonCycle(1, url, r -> action.accept(r, null), t -> action.accept(null, t)); + return this.subscribeJsonCycle(1, url, r -> action.accept(r, null), t -> action.accept(null, t)); + } + + /** + * Removes a {@link CycleEndpoint} if it matches the provided {@link Predicate}. + * + * @param condition the {@link Predicate} to match + * @return the removed {@link CycleEndpoint CycleEndpoints} + */ + public Collection removeCycleEndpointIf(Predicate condition); + + /** + * Removes all active {@link CycleEndpoint CycleEndpoints}. + * + * @return the removed {@link CycleEndpoint CycleEndpoints} + */ + public default Collection removeAllCycleEndpoints() { + return this.removeCycleEndpointIf(t -> true); + } + + /** + * Removes a {@link CycleEndpoint} if it matches the provided + * {@link CycleEndpoint}. + * + * @param cycleEndpoint the {@link CycleEndpoint} to match + * @return the removed {@link CycleEndpoint CycleEndpoints} + */ + public default boolean removeCycleEndpoint(CycleEndpoint cycleEndpoint) { + return !this.removeCycleEndpointIf(Predicate.isEqual(cycleEndpoint)).isEmpty(); } } diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/BridgeHttpExecutor.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/BridgeHttpExecutor.java new file mode 100644 index 00000000000..9d41f5a3f29 --- /dev/null +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/BridgeHttpExecutor.java @@ -0,0 +1,35 @@ +package io.openems.edge.bridge.http.api; + +import java.util.concurrent.ScheduledFuture; + +import io.openems.edge.bridge.http.time.DelayTimeProvider.Delay; + +/** + * Executor to handle tasks created by a {@link BridgeHttp}. + */ +public interface BridgeHttpExecutor { + + /** + * Schedules a task to be executed from now plus the given delay. + * + * @param task the task to execute + * @param durationDelay the delay to schedule toe task + * @return a {@link ScheduledFuture} + */ + public ScheduledFuture schedule(Runnable task, Delay.DurationDelay durationDelay); + + /** + * Executes the given task. + * + * @param task the task to execute + */ + public void execute(Runnable task); + + /** + * Determines if this executor is shutdown. + * + * @return true if this executor is shutdown else false + */ + public boolean isShutdown(); + +} diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/BridgeHttpFactory.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/BridgeHttpFactory.java index 39ed78988d7..e1971965d50 100644 --- a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/BridgeHttpFactory.java +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/BridgeHttpFactory.java @@ -31,12 +31,11 @@ private void deactivate() { @Component(service = BridgeHttpFactory.class) public class BridgeHttpFactory { - @Reference - private ComponentServiceObjects csoBridgeHttp; + private final ComponentServiceObjects csoBridgeHttp; @Activate - public BridgeHttpFactory() { - + public BridgeHttpFactory(@Reference ComponentServiceObjects csoBridgeHttp) { + this.csoBridgeHttp = csoBridgeHttp; } /** diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/BridgeHttpTime.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/BridgeHttpTime.java index 53196d2092a..1e84be71f1b 100644 --- a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/BridgeHttpTime.java +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/BridgeHttpTime.java @@ -1,18 +1,24 @@ package io.openems.edge.bridge.http.api; -import static io.openems.edge.bridge.http.time.DelayTimeProviderChain.immediate; import static java.util.Collections.emptyMap; +import java.util.Collection; +import java.util.Objects; import java.util.function.BiConsumer; import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.Supplier; import com.google.gson.JsonElement; import io.openems.common.function.ThrowingConsumer; +import io.openems.common.utils.FunctionUtils; import io.openems.common.utils.JsonUtils; import io.openems.edge.bridge.http.api.BridgeHttp.Endpoint; import io.openems.edge.bridge.http.time.DefaultDelayTimeProvider; import io.openems.edge.bridge.http.time.DelayTimeProvider; +import io.openems.edge.bridge.http.time.DelayTimeProvider.Delay; import io.openems.edge.bridge.http.time.DelayTimeProviderChain; /** @@ -54,17 +60,30 @@ public record TimeEndpoint(// /** * The url which should be fetched. */ - Endpoint endpoint, // + Supplier endpoint, // /** * The callback to execute on every successful result. */ - Consumer onResult, // + Consumer> onResult, // /** * The callback to execute on every error. */ - Consumer onError // + Consumer onError // ) { + public TimeEndpoint { + Objects.requireNonNull(endpoint, "Endpoint of TimeEndpoint must not be null!"); + Objects.requireNonNull(onResult, "OnResult of TimeEndpoint must not be null!"); + Objects.requireNonNull(onError, "OnError of TimeEndpoint must not be null!"); + Objects.requireNonNull(delayTimeProvider, "DelayTimeProvider of TimeEndpoint must not be null!"); + } + + @Override + public String toString() { + return "TimeEndpoint [delayTimeProvider=" + this.delayTimeProvider + ", endpoint=" + + this.endpoint.get().url() + "]"; + } + } /** @@ -75,8 +94,10 @@ public record TimeEndpoint(// * gets executed depending on the result. * * @param endpoint the {@link TimeEndpoint} to add a subscription + * @return the added {@link TimeEndpoint} (always the provided one); or null if + * the {@link TimeEndpoint} could not be added */ - public void subscribeTime(TimeEndpoint endpoint); + public TimeEndpoint subscribeTime(TimeEndpoint endpoint); /** * Subscribes to an {@link Endpoint} with the delay provided by the @@ -89,18 +110,47 @@ public record TimeEndpoint(// * @param onResult the method to call on successful fetch * @param onError the method to call if an error happens during * fetching or handling the result + * @return the added {@link TimeEndpoint}; or null if the {@link TimeEndpoint} + * could not be added */ - public default void subscribeTime(// + public default TimeEndpoint subscribeTime(// DelayTimeProvider delayTimeProvider, // Endpoint endpoint, // - ThrowingConsumer onResult, // - Consumer onError // + ThrowingConsumer, Exception> onResult, // + Consumer onError // ) { - this.subscribeTime(new TimeEndpoint(delayTimeProvider, endpoint, t -> { + return this.subscribeTime(delayTimeProvider, () -> endpoint, onResult, onError); + } + + /** + * Subscribes to an {@link Endpoint} with the delay provided by the + * {@link DelayTimeProvider} and after every endpoint fetch either the + * onResult or the onError method gets called. + * + * @param delayTimeProvider the {@link DelayTimeProvider} to provided the delay + * between the fetches + * @param endpointSupplier the supplier to get the {@link Endpoint} to fetch; + * the {@link Supplier} gets called right before the + * fetch happens + * @param onResult the method to call on successful fetch + * @param onError the method to call if an error happens during + * fetching or handling the result + * @return the added {@link TimeEndpoint}; or null if the {@link TimeEndpoint} + * could not be added + */ + public default TimeEndpoint subscribeTime(// + DelayTimeProvider delayTimeProvider, // + Supplier endpointSupplier, // + ThrowingConsumer, Exception> onResult, // + Consumer onError // + ) { + return this.subscribeTime(new TimeEndpoint(delayTimeProvider, endpointSupplier, t -> { try { onResult.accept(t); - } catch (Exception e) { + } catch (HttpError e) { onError.accept(e); + } catch (Exception e) { + onError.accept(new HttpError.UnknownError(e)); } }, onError)); } @@ -118,13 +168,41 @@ public default void subscribeTime(// * the endpoint if existing and the second argument is * passed if an error happend. One of the params is * always null and one not + * @return the added {@link TimeEndpoint}; or null if the {@link TimeEndpoint} + * could not be added */ - public default void subscribeTime(// + public default TimeEndpoint subscribeTime(// DelayTimeProvider delayTimeProvider, // Endpoint endpoint, // - BiConsumer action // + BiConsumer, HttpError> action // ) { - this.subscribeTime(new TimeEndpoint(delayTimeProvider, endpoint, r -> action.accept(r, null), + return this.subscribeTime(delayTimeProvider, () -> endpoint, action); + } + + /** + * Subscribes to an {@link Endpoint} with the delay provided by the + * {@link DelayTimeProvider} and after every endpoint fetch the + * action gets called either with the result or the error at least + * one is not null. + * + * @param delayTimeProvider the {@link DelayTimeProvider} to provided the delay + * between the fetches + * @param endpointSupplier the supplier to get the {@link Endpoint} to fetch; + * the {@link Supplier} gets called right before the + * fetch happens + * @param action the action to perform; the first is the result of + * the endpoint if existing and the second argument is + * passed if an error happend. One of the params is + * always null and one not + * @return the added {@link TimeEndpoint}; or null if the {@link TimeEndpoint} + * could not be added + */ + public default TimeEndpoint subscribeTime(// + DelayTimeProvider delayTimeProvider, // + Supplier endpointSupplier, // + BiConsumer, HttpError> action // + ) { + return this.subscribeTime(new TimeEndpoint(delayTimeProvider, endpointSupplier, r -> action.accept(r, null), t -> action.accept(null, t))); } @@ -136,29 +214,33 @@ public default void subscribeTime(// *

      * Note: the first fetch gets triggered immediately * - * @param onErrorDelay the {@link DelayTimeProviderChain} when the last fetch - * was not successful - * @param onSuccessDelay the {@link DelayTimeProviderChain} when the last fetch - * was successful + * @param onErrorDelay the delay provider when the last fetch was not + * successful + * @param onSuccessDelay the delay provider when the last fetch was successful * @param url the url to fetch * @param onResult the method to call on successful fetch * @param onError the method to call if an error happens during fetching * or handling the result + * @return the added {@link TimeEndpoint}; or null if the {@link TimeEndpoint} + * could not be added */ - public default void subscribeTime(// - DelayTimeProviderChain onErrorDelay, // - DelayTimeProviderChain onSuccessDelay, // + public default TimeEndpoint subscribeTime(// + Function onErrorDelay, // + Function, Delay> onSuccessDelay, // String url, // - ThrowingConsumer onResult, // - Consumer onError // + ThrowingConsumer, Exception> onResult, // + Consumer onError // ) { - this.subscribeTime(new DefaultDelayTimeProvider(immediate(), onErrorDelay, onSuccessDelay), new Endpoint(url, // - HttpMethod.GET, // - BridgeHttp.DEFAULT_CONNECT_TIMEOUT, // - BridgeHttp.DEFAULT_READ_TIMEOUT, // - null, // - emptyMap() // - ), onResult, onError); + return this.subscribeTime( + new DefaultDelayTimeProvider(() -> DelayTimeProviderChain.immediate().getDelay(), onErrorDelay, + onSuccessDelay), + new Endpoint(url, // + HttpMethod.GET, // + BridgeHttp.DEFAULT_CONNECT_TIMEOUT, // + BridgeHttp.DEFAULT_READ_TIMEOUT, // + null, // + emptyMap() // + ), onResult, onError); } /** @@ -174,14 +256,16 @@ public default void subscribeTime(// * @param onResult the method to call on successful fetch * @param onError the method to call if an error happens during fetching or * handling the result + * @return the added {@link TimeEndpoint}; or null if the {@link TimeEndpoint} + * could not be added */ - public default void subscribeTime(// + public default TimeEndpoint subscribeTime(// DelayTimeProviderChain delay, // String url, // - ThrowingConsumer onResult, // - Consumer onError // + ThrowingConsumer, Exception> onResult, // + Consumer onError // ) { - this.subscribeTime(delay, delay, url, onResult, onError); + return this.subscribeTime(t -> delay.getDelay(), t -> delay.getDelay(), url, onResult, onError); } /** @@ -195,13 +279,45 @@ public default void subscribeTime(// * @param delay the {@link DelayTimeProviderChain} between each fetch * @param url the url to fetch * @param onResult the method to call on successful fetch + * @return the added {@link TimeEndpoint}; or null if the {@link TimeEndpoint} + * could not be added */ - public default void subscribeTime(// + public default TimeEndpoint subscribeTime(// DelayTimeProviderChain delay, // String url, // - ThrowingConsumer onResult // + ThrowingConsumer, Exception> onResult // ) { - this.subscribeTime(delay, delay, url, onResult, BridgeHttp.EMPTY_ERROR_HANDLER); + return this.subscribeTime(t -> delay.getDelay(), t -> delay.getDelay(), url, onResult, + FunctionUtils::doNothing); + } + + /** + * Subscribes to an {@link Endpoint} with the delay provided by the delay + * provider and after every endpoint fetch either the onResult or + * the onError method gets called. + * + *

      + * Note: the first fetch gets triggered immediately + * + * @param onErrorDelay the delay provider when the last fetch was not + * successful + * @param onSuccessDelay the delay provider when the last fetch was successful + * @param url the url to fetch + * @param onResult the method to call on successful fetch + * @param onError the method to call if an error happens during fetching + * or handling the result + * @return the added {@link TimeEndpoint}; or null if the {@link TimeEndpoint} + * could not be added + */ + public default TimeEndpoint subscribeJsonTime(// + Function onErrorDelay, // + Function, Delay> onSuccessDelay, // + String url, // + ThrowingConsumer, Exception> onResult, // + Consumer onError // + ) { + return this.subscribeTime(onErrorDelay, onSuccessDelay, url, + t -> onResult.accept(t.withData(JsonUtils.parse(t.data()))), onError); } /** @@ -215,14 +331,42 @@ public default void subscribeTime(// * @param onResult the method to call on successful fetch * @param onError the method to call if an error happens during * fetching or handling the result + * @return the added {@link TimeEndpoint}; or null if the {@link TimeEndpoint} + * could not be added */ - public default void subscribeJsonTime(// + public default TimeEndpoint subscribeJsonTime(// DelayTimeProvider delayTimeProvider, // Endpoint endpoint, // - ThrowingConsumer onResult, // - Consumer onError // + ThrowingConsumer, Exception> onResult, // + Consumer onError // + ) { + return this.subscribeJsonTime(delayTimeProvider, () -> endpoint, onResult, onError); + } + + /** + * Subscribes to an {@link Endpoint} with the delay provided by the + * {@link DelayTimeProvider} and after every endpoint fetch either the + * onResult or the onError method gets called. + * + * @param delayTimeProvider the {@link DelayTimeProvider} to provided the delay + * between the fetches + * @param endpointSupplier the supplier to get the {@link Endpoint} to fetch; + * the {@link Supplier} gets called right before the + * fetch happens + * @param onResult the method to call on successful fetch + * @param onError the method to call if an error happens during + * fetching or handling the result + * @return the added {@link TimeEndpoint}; or null if the {@link TimeEndpoint} + * could not be added + */ + public default TimeEndpoint subscribeJsonTime(// + DelayTimeProvider delayTimeProvider, // + Supplier endpointSupplier, // + ThrowingConsumer, Exception> onResult, // + Consumer onError // ) { - this.subscribeTime(delayTimeProvider, endpoint, t -> onResult.accept(JsonUtils.parse(t)), onError); + return this.subscribeTime(delayTimeProvider, endpointSupplier, + t -> onResult.accept(t.withData(JsonUtils.parse(t.data()))), onError); } /** @@ -238,14 +382,70 @@ public default void subscribeJsonTime(// * the endpoint if existing and the second argument is * passed if an error happend. One of the params is * always null and one not + * @return the added {@link TimeEndpoint}; or null if the {@link TimeEndpoint} + * could not be added */ - public default void subscribeJsonTime(// + public default TimeEndpoint subscribeJsonTime(// DelayTimeProvider delayTimeProvider, // Endpoint endpoint, // - BiConsumer action // + BiConsumer, HttpError> action // + ) { + return this.subscribeJsonTime(delayTimeProvider, () -> endpoint, action); + } + + /** + * Subscribes to an {@link Endpoint} with the delay provided by the + * {@link DelayTimeProvider} and after every endpoint fetch the + * action gets called either with the result or the error at least + * one is not null. + * + * @param delayTimeProvider the {@link DelayTimeProvider} to provided the delay + * between the fetches + * @param endpointSupplier the supplier to get the {@link Endpoint} to fetch; + * the {@link Supplier} gets called right before the + * fetch happens + * @param action the action to perform; the first is the result of + * the endpoint if existing and the second argument is + * passed if an error happend. One of the params is + * always null and one not + * @return the added {@link TimeEndpoint}; or null if the {@link TimeEndpoint} + * could not be added + */ + public default TimeEndpoint subscribeJsonTime(// + DelayTimeProvider delayTimeProvider, // + Supplier endpointSupplier, // + BiConsumer, HttpError> action // ) { - this.subscribeTime(delayTimeProvider, endpoint, t -> action.accept(JsonUtils.parse(t), null), - e -> action.accept(null, e)); + return this.subscribeTime(delayTimeProvider, endpointSupplier, + t -> action.accept(t.withData(JsonUtils.parse(t.data())), null), e -> action.accept(null, e)); + } + + /** + * Removes a {@link TimeEndpoint} if it matches the provided {@link Predicate}. + * + * @param condition the {@link Predicate} to match + * @return the removed {@link TimeEndpoint TimeEndpoints} + */ + public Collection removeTimeEndpointIf(Predicate condition); + + /** + * Removes all active {@link TimeEndpoint TimeEndpoints}. + * + * @return the removed {@link TimeEndpoint TimeEndpoints} + */ + public default Collection removeAllTimeEndpoints() { + return this.removeTimeEndpointIf(t -> true); + } + + /** + * Removes a {@link TimeEndpoint} if it matches the provided + * {@link TimeEndpoint}. + * + * @param timeEndpoint the {@link TimeEndpoint} to match + * @return the removed {@link TimeEndpoint TimeEndpoints} + */ + public default boolean removeTimeEndpoint(TimeEndpoint timeEndpoint) { + return !this.removeTimeEndpointIf(Predicate.isEqual(timeEndpoint)).isEmpty(); } } diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/CycleSubscriber.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/CycleSubscriber.java similarity index 97% rename from io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/CycleSubscriber.java rename to io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/CycleSubscriber.java index af8b6122f1d..5409337bf16 100644 --- a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/CycleSubscriber.java +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/CycleSubscriber.java @@ -1,4 +1,4 @@ -package io.openems.edge.bridge.http; +package io.openems.edge.bridge.http.api; import java.util.HashSet; import java.util.Set; diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/UrlFetcher.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/EndpointFetcher.java similarity index 70% rename from io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/UrlFetcher.java rename to io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/EndpointFetcher.java index fdb4ebc01e6..c2467110749 100644 --- a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/UrlFetcher.java +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/EndpointFetcher.java @@ -1,9 +1,9 @@ -package io.openems.edge.bridge.http; +package io.openems.edge.bridge.http.api; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.edge.bridge.http.api.BridgeHttp.Endpoint; -public interface UrlFetcher { +public interface EndpointFetcher { /** * Creates a {@link Runnable} to execute a request with the given parameters. @@ -13,6 +13,6 @@ public interface UrlFetcher { * @return the result of the {@link Endpoint} * @throws OpenemsNamedException on error */ - public String fetchEndpoint(Endpoint endpoint) throws OpenemsNamedException; + public HttpResponse fetchEndpoint(Endpoint endpoint) throws HttpError; } diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/HttpError.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/HttpError.java new file mode 100644 index 00000000000..a5fcf2ea162 --- /dev/null +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/HttpError.java @@ -0,0 +1,57 @@ +package io.openems.edge.bridge.http.api; + +import io.openems.common.types.HttpStatus; + +public abstract sealed class HttpError extends Exception { + + private static final long serialVersionUID = 6341345161164781738L; + + private HttpError(String message) { + super(message); + } + + private HttpError(Throwable cause) { + super(cause); + } + + public static final class ResponseError extends HttpError { + + private static final long serialVersionUID = -5382307294288467972L; + + /** + * Creates a {@link HttpError#ResponseError} for a not found error. The + * predefined values are for status "404" and message "Not Found". + * + * @return the error + */ + public static ResponseError notFound() { + return new ResponseError(HttpStatus.NOT_FOUND, null); + } + + public final HttpStatus status; + public final String body; + + public ResponseError(HttpStatus status, String body) { + super("Http " + status + (body != null ? ", Body=" + body : "")); + this.status = status; + this.body = body; + } + + @Override + public String toString() { + return "ResponseError [status=" + this.status + ", body=" + this.body + "]"; + } + + } + + public static final class UnknownError extends HttpError { + + private static final long serialVersionUID = 5683236662459434998L; + + public UnknownError(Throwable cause) { + super(cause); + } + + } + +} diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/HttpResponse.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/HttpResponse.java new file mode 100644 index 00000000000..6d71a1949bf --- /dev/null +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/HttpResponse.java @@ -0,0 +1,34 @@ +package io.openems.edge.bridge.http.api; + +import io.openems.common.types.HttpStatus; + +public record HttpResponse(// + HttpStatus status, // + T data // +) { + + /** + * Creates a successful response with predefined values status 200 and message + * "OK". + * + * @param the type of the result data + * @param data the data (body) of the response + * @return the created {@link HttpResponse} + */ + public static HttpResponse ok(T data) { + return new HttpResponse(HttpStatus.OK, data); + } + + /** + * Creates a new {@link HttpResponse} with the given data set and all other + * fields from the current instance passed to the created object. + * + * @param the type of the new data + * @param newData the new data to set + * @return the new {@link HttpResponse} object + */ + public HttpResponse withData(O newData) { + return new HttpResponse(this.status(), newData); + } + +} diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttp.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttp.java index 5abccd97132..99040297ca2 100644 --- a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttp.java +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttp.java @@ -1,52 +1,58 @@ package io.openems.edge.bridge.http.dummy; -import static java.util.concurrent.CompletableFuture.completedFuture; +import static java.util.Collections.emptyList; -import java.util.ArrayList; -import java.util.List; +import java.util.Collection; import java.util.concurrent.CompletableFuture; +import java.util.function.Predicate; import io.openems.edge.bridge.http.api.BridgeHttp; +import io.openems.edge.bridge.http.api.HttpResponse; public class DummyBridgeHttp implements BridgeHttp { - public final List cycleEndpoints = new ArrayList<>(); - public final List timeEndpoints = new ArrayList<>(); - - private String nextRequestResult = null; - - @Override - public void subscribeCycle(CycleEndpoint endpoint) { - this.cycleEndpoints.add(endpoint); - } - - @Override - public void subscribeTime(TimeEndpoint endpoint) { - this.timeEndpoints.add(endpoint); - } - + /** + * {@inheritDoc} + * + * @implNote never gets executed in this class for actual testing a call use + * DummyBridgeHttpFactory#ofBridgeImpl + */ @Override - public CompletableFuture request(Endpoint endpoint) { - return completedFuture(this.nextRequestResult); + public CycleEndpoint subscribeCycle(CycleEndpoint endpoint) { + return endpoint; } /** - * Mocks a result for all {@link CycleEndpoint}s. + * {@inheritDoc} * - * @param result the mocked read result + * @implNote never gets executed in this class for actual testing a call use + * DummyBridgeHttpFactory#ofBridgeImpl */ - public void mockCycleResult(String result) { - this.cycleEndpoints.forEach(// - e -> e.result().accept(result)); + @Override + public TimeEndpoint subscribeTime(TimeEndpoint endpoint) { + return endpoint; } /** - * Mocks a result for simple request {@link Endpoint}. + * {@inheritDoc} * - * @param nextRequestResult the mocked read result + * @implNote this return future never completes for actual testing a call use + * DummyBridgeHttpFactory#ofBridgeImpl */ - public void mockRequestResult(String nextRequestResult) { - this.nextRequestResult = nextRequestResult; + @Override + public CompletableFuture> request(Endpoint endpoint) { + // NOTE: this future never completes + return new CompletableFuture<>(); + } + + @Override + public Collection removeCycleEndpointIf(Predicate condition) { + return emptyList(); + } + + @Override + public Collection removeTimeEndpointIf(Predicate condition) { + return emptyList(); } } diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpBundle.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpBundle.java new file mode 100644 index 00000000000..befb0e1ebca --- /dev/null +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpBundle.java @@ -0,0 +1,124 @@ +package io.openems.edge.bridge.http.dummy; + +import static java.util.Collections.emptyMap; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.osgi.service.event.Event; + +import io.openems.common.test.TimeLeapClock; +import io.openems.edge.bridge.http.api.BridgeHttp.Endpoint; +import io.openems.edge.bridge.http.api.BridgeHttpFactory; +import io.openems.edge.bridge.http.api.CycleSubscriber; +import io.openems.edge.bridge.http.api.HttpError; +import io.openems.edge.bridge.http.api.HttpResponse; +import io.openems.edge.common.event.EdgeEventConstants; + +public class DummyBridgeHttpBundle { + + private final DummyEndpointFetcher fetcher = DummyBridgeHttpFactory.dummyEndpointFetcher(); + private final DummyBridgeHttpExecutor pool = DummyBridgeHttpFactory.dummyBridgeHttpExecutor(new TimeLeapClock(), + true); + private final CycleSubscriber cycleSubscriber = DummyBridgeHttpFactory.cycleSubscriber(); + private final DummyBridgeHttpFactory bridgeFactory = DummyBridgeHttpFactory.ofBridgeImpl(() -> this.cycleSubscriber, + () -> this.fetcher, () -> this.pool); + + /** + * Passes a dummy event to the {@link CycleSubscriber} to trigger the next cycle + * event. + */ + public void triggerNextCycle() { + this.cycleSubscriber.handleEvent(new Event(EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE, emptyMap())); + } + + /** + * Sets a one time response which will be returned for the next http call. + * + * @param response the {@link HttpResponse} to return + */ + public void forceNextSuccessfulResult(HttpResponse response) { + this.fetcher.addSingleUseEndpointHandler(t -> response); + } + + /** + * Sets a one time error which will be thrown for the next http call. + * + * @param error the {@link HttpError} to throw + */ + public void forceNextFailedResult(HttpError error) { + this.fetcher.addSingleUseEndpointHandler(t -> { + throw error; + }); + } + + /** + * Creates a {@link EndpointExpect} which can be used to asynchronously check if + * a {@link Endpoint} was called. + * + *

      + * e. g. + * + *

      +	 * // create listener for check
      +	 * final var wasCalled = dummyBridgeTestBundle.expect("http://your.url").toBeCalled();
      +	 * ...
      +	 * // trigger url call
      +	 * // depending on your component trigger event, set channel...
      +	 * ...
      +	 * // check if endpoint was called
      +	 * assertTrue("Endpoint was not called", wasCalled.get());
      +	 * 
      + * + * @param url only handles request to this url + * @return the {@link EndpointExpect} to check + */ + public EndpointExpect expect(String url) { + final var request = new CompletableFuture(); + final var result = new EndpointExpect(request); + this.fetcher.addSingleUseEndpointHandler(t -> { + if (!t.url().equals(url)) { + return null; + } + request.complete(t); + return HttpResponse.ok(null); + }); + return result; + } + + /** + * Gets the {@link BridgeHttpFactory} of this test bundle. + * + * @return the {@link BridgeHttpFactory} + */ + public BridgeHttpFactory factory() { + return this.bridgeFactory; + } + + public static class EndpointExpect { + + private final CompletableFuture request; + + public EndpointExpect(CompletableFuture request) { + super(); + this.request = request; + } + + /** + * Creates a check for the current {@link Endpoint} request if it got called or + * not. + * + * @return a {@link AtomicBoolean} which will be set to true once the + * {@link Endpoint} got called + */ + public AtomicBoolean toBeCalled() { + final var result = new AtomicBoolean(false); + this.request.thenAccept(e -> { + result.set(true); + }); + return result; + } + + } + +} diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpExecutor.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpExecutor.java new file mode 100644 index 00000000000..2a74f1c7ea0 --- /dev/null +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpExecutor.java @@ -0,0 +1,206 @@ +package io.openems.edge.bridge.http.dummy; + +import java.time.Clock; +import java.time.Duration; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.PriorityQueue; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Delayed; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.openems.edge.bridge.http.api.BridgeHttpExecutor; +import io.openems.edge.bridge.http.time.DelayTimeProvider.Delay; + +public class DummyBridgeHttpExecutor implements BridgeHttpExecutor { + + private class Task implements ScheduledFuture { + private final Instant start; + private final Duration delay; + private final Runnable runnable; + private final CompletableFuture doneFuture = new CompletableFuture(); + private boolean cancelled = false; + + public Task(Instant start, Duration delay, Runnable task) { + super(); + this.start = start; + this.delay = delay; + this.runnable = task; + } + + @Override + public long getDelay(TimeUnit unit) { + return Duration.between(DummyBridgeHttpExecutor.this.clock.instant(), this.start.plus(this.delay)) + .get(unit.toChronoUnit()); + } + + @Override + public int compareTo(Delayed o) { + final var secondsCompareResult = Long.compare(this.getDelay(TimeUnit.SECONDS), + o.getDelay(TimeUnit.SECONDS)); + if (secondsCompareResult != 0) { + return secondsCompareResult; + } + return Long.compare(this.getDelay(TimeUnit.NANOSECONDS), o.getDelay(TimeUnit.NANOSECONDS)); + } + + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + if (this.cancelled) { + return true; + } + if (this.isDone()) { + return false; + } + DummyBridgeHttpExecutor.this.timePriorityTasks.remove(this); + this.doneFuture.completeExceptionally(new Exception("Cancelled")); + return this.cancelled = true; + } + + @Override + public boolean isCancelled() { + return this.cancelled; + } + + @Override + public boolean isDone() { + return this.doneFuture.isDone(); + } + + @Override + public Object get() throws InterruptedException, ExecutionException { + return this.doneFuture.get(); + } + + @Override + public Object get(long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + return this.doneFuture.get(timeout, unit); + } + + private void run() { + try { + this.runnable.run(); + } catch (Exception e) { + DummyBridgeHttpExecutor.this.log.error("Task completed exceptionally.", e); + } finally { + this.doneFuture.complete(null); + } + } + + } + + private final Logger log = LoggerFactory.getLogger(DummyBridgeHttpExecutor.class); + + private final Clock clock; + private final PriorityQueue timePriorityTasks = new PriorityQueue(); + private final TaskExecutor taskExecutor; + private boolean shutdown = false; + + public DummyBridgeHttpExecutor(Clock clock, boolean handleTasksImmediately) { + super(); + this.clock = clock; + this.taskExecutor = handleTasksImmediately ? new ImmediateTaskExecutor() : new DelayedTaskExecutor(); + } + + public DummyBridgeHttpExecutor(Clock clock) { + this(clock, false); + } + + @Override + public ScheduledFuture schedule(Runnable task, Delay.DurationDelay durationDelay) { + if (this.isShutdown()) { + throw new RuntimeException("Executor is shutdown."); + } + final var t = new Task(this.clock.instant(), durationDelay.getDuration(), task); + if (!this.timePriorityTasks.offer(t)) { + this.log.info("Unable to add Task to Queue."); + return null; + } + return t; + } + + @Override + public void execute(Runnable task) { + if (this.isShutdown()) { + throw new RuntimeException("Executor is shutdown."); + } + this.taskExecutor.execute(task); + } + + @Override + public boolean isShutdown() { + return this.shutdown; + } + + /** + * Updates the executor. Executes all tasks which got queued up and for + * scheduled tasks executes these where its time elapsed based on the provided + * {@link Clock}. + */ + public void update() { + this.taskExecutor.update(); + + while (!this.timePriorityTasks.isEmpty() // + && this.timePriorityTasks.peek().getDelay(TimeUnit.SECONDS) <= 0) { + final var task = this.timePriorityTasks.poll(); + task.run(); + } + } + + /** + * Shuts down this executor. + */ + public void shutdown() { + if (this.isShutdown()) { + return; + } + this.shutdown = true; + this.timePriorityTasks.forEach(t -> t.cancel(false)); + } + + private static interface TaskExecutor { + public void execute(Runnable task); + + public void update(); + } + + private static class DelayedTaskExecutor implements TaskExecutor { + private List instantTasks = new ArrayList(); + + @Override + public void execute(Runnable task) { + this.instantTasks.add(task); + } + + @Override + public void update() { + final var tasksToExecute = this.instantTasks; + this.instantTasks = new ArrayList<>(); + tasksToExecute.forEach(Runnable::run); + } + + } + + private static class ImmediateTaskExecutor implements TaskExecutor { + + @Override + public void execute(Runnable task) { + task.run(); + } + + @Override + public void update() { + // empty + } + + } + +} diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpFactory.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpFactory.java index f19ec95eca8..635b56ad885 100644 --- a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpFactory.java +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpFactory.java @@ -1,46 +1,168 @@ package io.openems.edge.bridge.http.dummy; -import java.lang.reflect.InvocationTargetException; +import java.time.Clock; +import java.util.function.Supplier; import org.osgi.framework.ServiceReference; import org.osgi.service.component.ComponentServiceObjects; -import io.openems.common.utils.ReflectionUtils; +import io.openems.edge.bridge.http.BridgeHttpImpl; +import io.openems.edge.bridge.http.NetworkEndpointFetcher; import io.openems.edge.bridge.http.api.BridgeHttp; +import io.openems.edge.bridge.http.api.BridgeHttp.Endpoint; +import io.openems.edge.bridge.http.api.BridgeHttpExecutor; import io.openems.edge.bridge.http.api.BridgeHttpFactory; +import io.openems.edge.bridge.http.api.CycleSubscriber; +import io.openems.edge.bridge.http.api.EndpointFetcher; public class DummyBridgeHttpFactory extends BridgeHttpFactory { - public final DummyBridgeHttp bridge = new DummyBridgeHttp(); + /** + * Creates a {@link DummyBridgeHttpFactory} of a {@link DummyBridgeHttp}. + * + * @return the created {@link DummyBridgeHttpFactory} + */ + public static DummyBridgeHttpFactory ofDummyBridge() { + return ofCustomBridge(DummyBridgeHttp::new); + } + + /** + * Creates a {@link DummyBridgeHttpFactory} of the actual implementation used + * during runtime. + * + * @param cycleSubscriber the {@link CycleSubscriber} to use for subscribing to + * cycle-events + * @param endpointFetcher the {@link EndpointFetcher} to use to handle + * {@link Endpoint} requests; either + * {@link #networkEndpointFetcher()} for the one used + * during runtime which actually tries to get the result + * from the requested url, should only be used for first + * tests in the beginning not for Unit-Test itself or + * {@link #dummyEndpointFetcher()} to define dummy + * request handler where "static" responses can be + * defined, should be used for Unit-Tests + * @param pool the {@link BridgeHttpExecutor} to use to handle the + * execution of an {@link EndpointFetcher}; either + * {@link #asyncBridgeHttpExecutor()} to handle the + * requests asynchronously or + * {@link #dummyBridgeHttpExecutor(Clock)} to manually + * execute these tasks with + * {@link DummyBridgeHttpExecutor#update()} + * @return the created {@link DummyBridgeHttpFactory} + */ + public static DummyBridgeHttpFactory ofBridgeImpl(// + final Supplier cycleSubscriber, // + final Supplier endpointFetcher, // + final Supplier pool // + ) { + return ofCustomBridge(() -> { + return new BridgeHttpImpl(// + cycleSubscriber.get(), // + endpointFetcher.get(), // + pool.get() // + ); + }); + } + + /** + * Creates a {@link DummyBridgeHttpFactory} of the provided factory. + * + * @param supplier the factory to get a new {@link BridgeHttp} instance + * @return the created {@link DummyBridgeHttpFactory} + */ + public static DummyBridgeHttpFactory ofCustomBridge(Supplier supplier) { + return new DummyBridgeHttpFactory(supplier); + } + + /** + * Creates a {@link CycleSubscriber}. + * + * @return the created {@link CycleSubscriber} + */ + public static CycleSubscriber cycleSubscriber() { + return new CycleSubscriber(); + } + + /** + * Creates a {@link EndpointFetcher} for actual requests to the request url over + * the network. Should only be used for first tests in the beginning not for + * Unit-Test itself. + * + * @return the created {@link EndpointFetcher} + */ + public static EndpointFetcher networkEndpointFetcher() { + return new NetworkEndpointFetcher(); + } + + /** + * Creates a {@link DummyEndpointFetcher} where "static" request handler can be + * defined. + * + * @return the created {@link DummyEndpointFetcher} + */ + public static DummyEndpointFetcher dummyEndpointFetcher() { + return new DummyEndpointFetcher(); + } - public DummyBridgeHttpFactory() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { - super(); - ReflectionUtils.setAttribute(BridgeHttpFactory.class, this, "csoBridgeHttp", - new DummyBridgeHttpCso(this.bridge)); + /** + * Creates a {@link DummyBridgeHttpExecutor} to handle the execution of the + * requests to fetch an {@link Endpoint}. + * + * @param clock the {@link Clock} to provide the current time + * for scheduled tasks + * @param handleTasksImmediately true if all tasks which are not scheduled + * should be executed immediately in the same + * thread; false if only executed during the + * {@link DummyBridgeHttpExecutor#update()} + * method. + * @return the created {@link DummyBridgeHttpExecutor} + */ + public static DummyBridgeHttpExecutor dummyBridgeHttpExecutor(// + Clock clock, // + boolean handleTasksImmediately // + ) { + return new DummyBridgeHttpExecutor(clock, handleTasksImmediately); + } + + /** + * Creates a {@link DummyBridgeHttpExecutor} to handle the execution of the + * requests to fetch an {@link Endpoint}. + * + * @param clock the {@link Clock} to provide the current time for scheduled + * tasks + * @return the created {@link DummyBridgeHttpExecutor} + */ + public static DummyBridgeHttpExecutor dummyBridgeHttpExecutor(Clock clock) { + return new DummyBridgeHttpExecutor(clock); + } + + private DummyBridgeHttpFactory(Supplier supplier) { + super(new DummyBridgeHttpCso(supplier)); } private static class DummyBridgeHttpCso implements ComponentServiceObjects { - private final DummyBridgeHttp bridge; + private final Supplier supplier; - public DummyBridgeHttpCso(DummyBridgeHttp bridge) { - this.bridge = bridge; + public DummyBridgeHttpCso(Supplier supplier) { + super(); + this.supplier = supplier; } @Override public BridgeHttp getService() { - return this.bridge; + return this.supplier.get(); } @Override - public void ungetService(BridgeHttp service) { + public ServiceReference getServiceReference() { // empty for tests + return null; } @Override - public ServiceReference getServiceReference() { + public void ungetService(BridgeHttp service) { // empty for tests - return null; } } diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyEndpointFetcher.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyEndpointFetcher.java new file mode 100644 index 00000000000..907c714f0d5 --- /dev/null +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyEndpointFetcher.java @@ -0,0 +1,93 @@ +package io.openems.edge.bridge.http.dummy; + +import java.util.LinkedList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.openems.common.function.ThrowingFunction; +import io.openems.common.utils.FunctionUtils; +import io.openems.edge.bridge.http.api.BridgeHttp.Endpoint; +import io.openems.edge.bridge.http.api.EndpointFetcher; +import io.openems.edge.bridge.http.api.HttpError; +import io.openems.edge.bridge.http.api.HttpResponse; + +public class DummyEndpointFetcher implements EndpointFetcher { + + public record DummyHandler(// + boolean singleUse, // + ThrowingFunction, HttpError> handler // + ) { + + } + + private final Logger log = LoggerFactory.getLogger(DummyEndpointFetcher.class); + + private final List urlHandler = new LinkedList<>(); + private Runnable onTaskFinished = FunctionUtils::doNothing; + + @Override + public HttpResponse fetchEndpoint(// + final Endpoint endpoint // + ) throws HttpError { + try { + for (final var iterator = this.urlHandler.iterator(); iterator.hasNext();) { + final var dummyHandler = iterator.next(); + try { + final var result = dummyHandler.handler().apply(endpoint); + if (result != null) { + if (dummyHandler.singleUse()) { + iterator.remove(); + } + if (result.status().isError()) { + this.log.info( + "Throw error response directly instead of returning a error status. Result Status: " + + result.status()); + throw new HttpError.ResponseError(result.status(), result.data()); + } + return result; + } + } catch (Exception e) { + if (dummyHandler.singleUse()) { + iterator.remove(); + } + throw e; + } + } + throw HttpError.ResponseError.notFound(); + } catch (RuntimeException e) { + throw new HttpError.UnknownError(e); + } finally { + this.onTaskFinished.run(); + } + } + + /** + * Adds a static handler for a fetch request. + * + * @param handler the handler + */ + public void addEndpointHandler(ThrowingFunction, HttpError> handler) { + this.urlHandler.add(new DummyHandler(false, handler)); + } + + /** + * Adds a single use static handler for a fetch request. The handler will be + * removed once it produced a valid result. + * + *

      + * A valid result would be to throw an {@link Exception} or return a + * {@link HttpResponse}. Invalid would be returning null. + * + * @param handler the handler to add + */ + public void addSingleUseEndpointHandler(ThrowingFunction, HttpError> handler) { + this.urlHandler.add(new DummyHandler(true, handler)); + } + + public void setOnTaskFinished(Runnable onTaskFinished) { + this.onTaskFinished = onTaskFinished == null ? FunctionUtils::doNothing : onTaskFinished; + } + +} diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/time/DefaultDelayTimeProvider.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/time/DefaultDelayTimeProvider.java index 95c883301c7..8c87b39a1d2 100644 --- a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/time/DefaultDelayTimeProvider.java +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/time/DefaultDelayTimeProvider.java @@ -1,34 +1,40 @@ package io.openems.edge.bridge.http.time; -import java.time.Duration; +import java.util.function.Function; +import java.util.function.Supplier; + +import io.openems.edge.bridge.http.api.HttpError; +import io.openems.edge.bridge.http.api.HttpResponse; public class DefaultDelayTimeProvider implements DelayTimeProvider { - private final DelayTimeProviderChain firstRunDelay; - private final DelayTimeProviderChain onErrorDelay; - private final DelayTimeProviderChain onSuccessDelay; + private final Supplier onFirstRunDelay; + private final Function onErrorDelay; + private final Function, Delay> onSuccessDelay; public DefaultDelayTimeProvider(// - DelayTimeProviderChain firstRunDelay, // - DelayTimeProviderChain onErrorDelay, // - DelayTimeProviderChain onSuccessDelay // + Supplier onFirstRunDelay, // + Function onErrorDelay, // + Function, Delay> onSuccessDelay // ) { - this.firstRunDelay = firstRunDelay == null ? onSuccessDelay : firstRunDelay; - this.onErrorDelay = onErrorDelay == null ? onSuccessDelay : onErrorDelay; + this.onFirstRunDelay = onFirstRunDelay; + this.onErrorDelay = onErrorDelay; this.onSuccessDelay = onSuccessDelay; } @Override - public Duration nextRun(boolean firstRun, boolean lastRunSuccessful) { - if (firstRun) { - return this.firstRunDelay.getDelay(); - } + public Delay onFirstRunDelay() { + return this.onFirstRunDelay.get(); + } - if (!lastRunSuccessful) { - return this.onErrorDelay.getDelay(); - } + @Override + public Delay onErrorRunDelay(HttpError error) { + return this.onErrorDelay.apply(error); + } - return this.onSuccessDelay.getDelay(); + @Override + public Delay onSuccessRunDelay(HttpResponse result) { + return this.onSuccessDelay.apply(result); } } \ No newline at end of file diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/time/DelayTimeProvider.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/time/DelayTimeProvider.java index 27561837d2f..de58aae32b2 100644 --- a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/time/DelayTimeProvider.java +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/time/DelayTimeProvider.java @@ -1,19 +1,131 @@ package io.openems.edge.bridge.http.time; import java.time.Duration; +import java.util.Objects; -import io.openems.edge.bridge.http.api.BridgeHttp.Endpoint; +import io.openems.edge.bridge.http.api.HttpError; +import io.openems.edge.bridge.http.api.HttpResponse; public interface DelayTimeProvider { + public static sealed interface Delay { + + /** + * Creates a {@link Delay} which represents delay of zero. + * + * @return a {@link Delay} which represents delay of zero. + */ + public static Delay immediate() { + return Delay.of(Duration.ZERO); + } + + /** + * Creates a {@link Delay} which represents a delay of the given + * {@link Duration}. + * + * @param duration the {@link Duration} of the {@link Delay} + * @return a {@link Delay} of the {@link Duration}. + */ + public static Delay of(Duration duration) { + return new DurationDelay(duration); + } + + /** + * Creates a {@link Delay} which represents a infinite delay. + * + * @return a {@link Delay} which never ends. + */ + public static Delay infinite() { + return InfiniteDelay.INSTANCE; + } + + /** + * Adds the provided {@link Delay} to the current {@link Delay} and returns its + * result. + * + * @param delay the {@link Delay} to add + * @return the result + */ + public Delay plus(Delay delay); + + public static final class DurationDelay implements Delay { + private final Duration duration; + + private DurationDelay(Duration duration) { + super(); + this.duration = duration; + } + + public Duration getDuration() { + return this.duration; + } + + @Override + public Delay plus(Delay delay) { + if (delay instanceof DurationDelay durationDelay) { + return new DurationDelay(this.duration.plus(durationDelay.getDuration())); + } + return delay.plus(this); + } + + @Override + public int hashCode() { + return Objects.hash(this.duration); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DurationDelay other) { + return Objects.equals(this.duration, other.duration); + } + return false; + } + + } + + public static final class InfiniteDelay implements Delay { + + public static final InfiniteDelay INSTANCE = new InfiniteDelay(); + + private InfiniteDelay() { + } + + @Override + public Delay plus(Delay delay) { + return this; + } + + } + + } + + /** + * Gives the {@link Delay} till the next run should be triggered on the first + * trigger. + * + * @return the {@link Delay} till the next run + */ + public Delay onFirstRunDelay(); + + /** + * Gives the {@link Delay} till the next run should be triggered when the last + * run completed with an error. + * + * @param error the {@link HttpError} which happened + * @return the {@link Delay} till the next run + */ + public Delay onErrorRunDelay(HttpError error); + /** - * Gives the {@link Duration} till the next run should be triggered. + * Gives the {@link Delay} till the next run should be triggered when the last + * run completed successfully. * - * @param firstRun true if this method gets executed for the first time - * @param lastRunSuccessful true if the last fetch of an {@link Endpoint} was - * successful - * @return the {@link Duration} till the next run + * @param result the result of the last run + * @return the {@link Delay} till the next run */ - public Duration nextRun(boolean firstRun, boolean lastRunSuccessful); + public Delay onSuccessRunDelay(HttpResponse result); } diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/time/DelayTimeProviderChain.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/time/DelayTimeProviderChain.java index e3b69e16e6e..bab5640b79d 100644 --- a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/time/DelayTimeProviderChain.java +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/time/DelayTimeProviderChain.java @@ -10,6 +10,8 @@ import com.google.common.base.Supplier; import io.openems.common.timedata.DurationUnit; +import io.openems.edge.bridge.http.api.BridgeHttp.Endpoint; +import io.openems.edge.bridge.http.time.DelayTimeProvider.Delay; public class DelayTimeProviderChain { @@ -20,17 +22,18 @@ public class DelayTimeProviderChain { * @return a {@link DelayTimeProviderChain} of zero delay */ public static DelayTimeProviderChain immediate() { - return new DelayTimeProviderChain(() -> Duration.ZERO); + return fixedDelay(Duration.ZERO); } /** * Creates a {@link DelayTimeProviderChain} which returns a fixed * {@link Duration} on request. * - * @param delay the {@link Duration} to return when requested + * @param duration the {@link Duration} to return when requested * @return a {@link DelayTimeProviderChain} of the given {@link Duration} */ - public static DelayTimeProviderChain fixedDelay(Duration delay) { + public static DelayTimeProviderChain fixedDelay(Duration duration) { + final var delay = Delay.of(duration); return new DelayTimeProviderChain(() -> delay); } @@ -52,18 +55,34 @@ public static DelayTimeProviderChain fixedAtEveryFull(Clock clock, DurationUnit return new DelayTimeProviderChain(() -> { final var now = LocalDateTime.now(clock); - return Duration.between(now, now.truncatedTo(durationUnit) // - .plus(durationUnit.getDuration())); + return Delay.of(Duration.between(now, now.truncatedTo(durationUnit) // + .plus(durationUnit.getDuration()))); }); } - private final Supplier supplier; + /** + * Creates a {@link DelayTimeProviderChain} which returns a {@link Delay} which + * indicates that the next run should never happen. May be used if + * {@link Endpoint} credentials are wrong or expired. + * + *

      + * NOTE: Do not use a very large {@link Duration} to indicate that a task should + * not be executed anymore. An Overflow exception could happen if additional + * delay gets added and the task would still be queued but never executed. + * + * @return a {@link DelayTimeProviderChain} which returns the {@link Delay} + */ + public static DelayTimeProviderChain runNeverAgain() { + return new DelayTimeProviderChain(Delay::infinite); + } + + private final Supplier supplier; - public DelayTimeProviderChain(Supplier supplier) { + public DelayTimeProviderChain(Supplier supplier) { this.supplier = supplier; } - public Duration getDelay() { + public Delay getDelay() { return this.supplier.get(); } @@ -80,7 +99,7 @@ public Duration getDelay() { */ public static DelayTimeProviderChain plusFixedAmount(DelayTimeProviderChain origin, Duration duration) { return new DelayTimeProviderChain(() -> { - return origin.getDelay().plus(duration); + return origin.getDelay().plus(Delay.of(duration)); }); } @@ -114,7 +133,7 @@ public DelayTimeProviderChain plusFixedAmount(Duration duration) { */ public static DelayTimeProviderChain plusRandomDelay(DelayTimeProviderChain origin, int bound, TemporalUnit unit) { return new DelayTimeProviderChain(() -> { - return origin.getDelay().plus(Duration.of(new Random().nextInt(bound), unit)); + return origin.getDelay().plus(Delay.of(Duration.of(new Random().nextInt(bound), unit))); }); } diff --git a/io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/DummyUrlFetcher.java b/io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/DummyUrlFetcher.java deleted file mode 100644 index f1da87db903..00000000000 --- a/io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/DummyUrlFetcher.java +++ /dev/null @@ -1,50 +0,0 @@ -package io.openems.edge.bridge.http; - -import java.util.LinkedList; -import java.util.List; - -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.exceptions.OpenemsException; -import io.openems.common.function.ThrowingFunction; -import io.openems.edge.bridge.http.api.BridgeHttp.Endpoint; - -public class DummyUrlFetcher implements UrlFetcher { - - private static final Runnable EMPTY_RUNNABLE = () -> { - // empty - }; - - private final List> urlHandler = new LinkedList<>(); - private Runnable onTaskFinished = EMPTY_RUNNABLE; - - @Override - public String fetchEndpoint(// - final Endpoint endpoint // - ) throws OpenemsNamedException { - try { - for (var handler : this.urlHandler) { - final var result = handler.apply(endpoint); - if (result != null) { - return result; - } - } - throw new OpenemsException(""); - } finally { - this.onTaskFinished.run(); - } - } - - /** - * Adds a static handler for a fetch request. - * - * @param handler the handler - */ - public void addEndpointHandler(ThrowingFunction handler) { - this.urlHandler.add(handler); - } - - public void setOnTaskFinished(Runnable onTaskFinished) { - this.onTaskFinished = onTaskFinished == null ? EMPTY_RUNNABLE : onTaskFinished; - } - -} diff --git a/io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/api/BridgeHttpCycleTest.java b/io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/api/BridgeHttpCycleTest.java index 77abb0aa35a..0e4ca875adc 100644 --- a/io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/api/BridgeHttpCycleTest.java +++ b/io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/api/BridgeHttpCycleTest.java @@ -1,12 +1,11 @@ package io.openems.edge.bridge.http.api; +import static java.util.Collections.emptyMap; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; import java.util.HashMap; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicInteger; import org.junit.After; @@ -14,35 +13,40 @@ import org.junit.Test; import org.osgi.service.event.Event; -import io.openems.common.utils.ReflectionUtils; +import io.openems.common.test.TimeLeapClock; +import io.openems.common.utils.FunctionUtils; import io.openems.edge.bridge.http.BridgeHttpImpl; -import io.openems.edge.bridge.http.CycleSubscriber; -import io.openems.edge.bridge.http.DummyUrlFetcher; +import io.openems.edge.bridge.http.api.BridgeHttp.Endpoint; +import io.openems.edge.bridge.http.api.BridgeHttpCycle.CycleEndpoint; +import io.openems.edge.bridge.http.dummy.DummyBridgeHttpExecutor; +import io.openems.edge.bridge.http.dummy.DummyEndpointFetcher; import io.openems.edge.common.event.EdgeEventConstants; public class BridgeHttpCycleTest { - private DummyUrlFetcher fetcher; + private DummyEndpointFetcher fetcher; private CycleSubscriber cycleSubscriber; + private DummyBridgeHttpExecutor pool; private BridgeHttp bridgeHttp; @Before public void before() throws Exception { this.cycleSubscriber = new CycleSubscriber(); - this.bridgeHttp = new BridgeHttpImpl(); - ReflectionUtils.setAttribute(BridgeHttpImpl.class, this.bridgeHttp, "cycleSubscriber", this.cycleSubscriber); + this.fetcher = new DummyEndpointFetcher(); + this.pool = new DummyBridgeHttpExecutor(new TimeLeapClock()); + this.bridgeHttp = new BridgeHttpImpl(// + this.cycleSubscriber, // + this.fetcher, // + this.pool // + ); - this.fetcher = new DummyUrlFetcher(); this.fetcher.addEndpointHandler(endpoint -> { return switch (endpoint.url()) { - case "dummy" -> "success"; + case "dummy" -> HttpResponse.ok("success"); case "error" -> throw new RuntimeException(); default -> null; }; }); - ReflectionUtils.setAttribute(BridgeHttpImpl.class, this.bridgeHttp, "urlFetcher", this.fetcher); - - ((BridgeHttpImpl) this.bridgeHttp).activate(); } @After @@ -53,99 +57,78 @@ public void after() throws Exception { @Test public void test() throws Exception { final var callCount = new AtomicInteger(0); - final var future = new CompletableFuture(); this.bridgeHttp.subscribeCycle(3, "dummy", t -> { - assertEquals("success", t); + assertEquals("success", t.data()); callCount.incrementAndGet(); - future.complete(null); }); assertEquals(0, callCount.get()); this.nextCycle(); + this.pool.update(); assertEquals(0, callCount.get()); this.nextCycle(); + this.pool.update(); assertEquals(0, callCount.get()); this.nextCycle(); + this.pool.update(); - // wait until finished - future.get(); assertEquals(1, callCount.get()); } @Test public void testNotRunningMultipleTimes() throws Exception { final var callCount = new AtomicInteger(0); - final var lock = new Object(); - final var waitUntilContinueHandler = new CompletableFuture(); this.bridgeHttp.subscribeEveryCycle("dummy", t -> { - assertEquals("success", t); + assertEquals("success", t.data()); callCount.incrementAndGet(); - synchronized (lock) { - lock.notify(); - - } - try { - waitUntilContinueHandler.get(); - } catch (InterruptedException | ExecutionException e) { - assertTrue(false); - } }); - synchronized (lock) { - assertEquals(0, callCount.get()); - this.nextCycle(); - lock.wait(); - } - - synchronized (lock) { - assertEquals(1, callCount.get()); - this.nextCycle(); - assertEquals(1, callCount.get()); - this.nextCycle(); - assertEquals(1, callCount.get()); - } + assertEquals(0, callCount.get()); + this.nextCycle(); + this.pool.update(); - waitUntilContinueHandler.complete(null); + assertEquals(1, callCount.get()); + this.nextCycle(); + assertEquals(1, callCount.get()); + this.nextCycle(); + assertEquals(1, callCount.get()); + this.nextCycle(); - this.waitUntilCycleRequestAreFinished(); - synchronized (lock) { - this.nextCycle(); - lock.wait(); - } + this.pool.update(); assertEquals(2, callCount.get()); + this.nextCycle(); + this.pool.update(); + assertEquals(3, callCount.get()); + this.nextCycle(); + this.pool.update(); } @Test public void testRequestFail() throws Exception { final var error = new CompletableFuture(); - this.bridgeHttp.subscribeEveryCycle("error", t -> { - // empty - }, error::complete); + this.bridgeHttp.subscribeEveryCycle("error", FunctionUtils::doNothing, error::complete); this.nextCycle(); + this.pool.update(); assertNotNull(error.get()); } + @Test(expected = IllegalArgumentException.class) + public void testCreateCycleEndpointWithZeroCycle() throws Exception { + new CycleEndpoint(// + 0, // + () -> new Endpoint("url", HttpMethod.GET, BridgeHttp.DEFAULT_CONNECT_TIMEOUT, + BridgeHttp.DEFAULT_READ_TIMEOUT, null, emptyMap()), // + FunctionUtils::doNothing, // + FunctionUtils::doNothing // + ); + } + private void nextCycle() { this.cycleSubscriber .handleEvent(new Event(EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE, new HashMap<>())); } - private void waitUntilCycleRequestAreFinished() { - while (this.isCycleRequestRunning()) { - // wait - } - } - - private boolean isCycleRequestRunning() { - for (var endpoint : ((BridgeHttpImpl) this.bridgeHttp).getCycleEndpoints()) { - if (endpoint.isRunning()) { - return true; - } - } - return false; - } - } diff --git a/io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/api/BridgeHttpTest.java b/io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/api/BridgeHttpTest.java index a0572b212a9..013e2ddc067 100644 --- a/io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/api/BridgeHttpTest.java +++ b/io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/api/BridgeHttpTest.java @@ -4,6 +4,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; import org.junit.After; import org.junit.Before; @@ -13,29 +14,25 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.function.ThrowingFunction; +import io.openems.common.test.TimeLeapClock; import io.openems.common.utils.JsonUtils; -import io.openems.common.utils.ReflectionUtils; import io.openems.edge.bridge.http.BridgeHttpImpl; -import io.openems.edge.bridge.http.CycleSubscriber; -import io.openems.edge.bridge.http.DummyUrlFetcher; import io.openems.edge.bridge.http.api.BridgeHttp.Endpoint; +import io.openems.edge.bridge.http.dummy.DummyBridgeHttpFactory; +import io.openems.edge.bridge.http.dummy.DummyEndpointFetcher; public class BridgeHttpTest { - private DummyUrlFetcher fetcher; + private DummyEndpointFetcher fetcher; private CycleSubscriber cycleSubscriber; private BridgeHttpImpl bridgeHttp; @Before public void before() throws Exception { - this.cycleSubscriber = new CycleSubscriber(); - this.bridgeHttp = new BridgeHttpImpl(); - ReflectionUtils.setAttribute(BridgeHttpImpl.class, this.bridgeHttp, "cycleSubscriber", this.cycleSubscriber); - - this.fetcher = new DummyUrlFetcher(); - ReflectionUtils.setAttribute(BridgeHttpImpl.class, this.bridgeHttp, "urlFetcher", this.fetcher); - - this.bridgeHttp.activate(); + this.cycleSubscriber = DummyBridgeHttpFactory.cycleSubscriber(); + this.fetcher = DummyBridgeHttpFactory.dummyEndpointFetcher(); + this.bridgeHttp = new BridgeHttpImpl(this.cycleSubscriber, this.fetcher, + DummyBridgeHttpFactory.dummyBridgeHttpExecutor(new TimeLeapClock(), true)); } @After @@ -46,32 +43,32 @@ public void after() throws Exception { @Test public void testGet() throws Exception { this.fetcher.addEndpointHandler(assertExact("dummy", HttpMethod.GET)); - assertEquals("success", this.bridgeHttp.get("dummy").get()); + assertEquals("success", this.bridgeHttp.get("dummy").get().data()); } @Test public void testGetJson() throws Exception { this.fetcher.addEndpointHandler(assertExactJson("dummy", HttpMethod.GET)); - assertEquals(successJson(), this.bridgeHttp.getJson("dummy").get()); + assertEquals(successJson(), this.bridgeHttp.getJson("dummy").get().data()); } @Test public void testPut() throws Exception { this.fetcher.addEndpointHandler(assertExact("dummy", HttpMethod.PUT)); - assertEquals("success", this.bridgeHttp.put("dummy").get()); + assertEquals("success", this.bridgeHttp.put("dummy").get().data()); } @Test public void testPutJson() throws Exception { this.fetcher.addEndpointHandler(assertExactJson("dummy", HttpMethod.PUT)); - assertEquals(successJson(), this.bridgeHttp.putJson("dummy").get()); + assertEquals(successJson(), this.bridgeHttp.putJson("dummy").get().data()); } @Test public void testPost() throws Exception { final var body = "body"; this.fetcher.addEndpointHandler(assertExact("dummy", HttpMethod.POST, body)); - assertEquals("success", this.bridgeHttp.post("dummy", body).get()); + assertEquals("success", this.bridgeHttp.post("dummy", body).get().data()); } @Test @@ -80,19 +77,19 @@ public void testPostJson() throws Exception { .addProperty("body", true) // .build(); this.fetcher.addEndpointHandler(assertExactJson("dummy", HttpMethod.POST, body)); - assertEquals(successJson(), this.bridgeHttp.postJson("dummy", body).get()); + assertEquals(successJson(), this.bridgeHttp.postJson("dummy", body).get().data()); } @Test public void testDelete() throws Exception { this.fetcher.addEndpointHandler(assertExact("dummy", HttpMethod.DELETE)); - assertEquals("success", this.bridgeHttp.delete("dummy").get()); + assertEquals("success", this.bridgeHttp.delete("dummy").get().data()); } @Test public void testDeleteJson() throws Exception { this.fetcher.addEndpointHandler(assertExactJson("dummy", HttpMethod.DELETE)); - assertEquals(successJson(), this.bridgeHttp.deleteJson("dummy").get()); + assertEquals(successJson(), this.bridgeHttp.deleteJson("dummy").get().data()); } @Test @@ -102,7 +99,7 @@ public void testRequest() throws Exception { final var response = this.bridgeHttp .request(new Endpoint("dummy", HttpMethod.DELETE, 12345, 1245, null, emptyMap())); - assertEquals("success", response.get()); + assertEquals("success", response.get().data()); } @Test @@ -112,17 +109,17 @@ public void testRequestJson() throws Exception { final var response = this.bridgeHttp .requestJson(new Endpoint("dummy", HttpMethod.DELETE, 12345, 1245, null, emptyMap())); - assertEquals(successJson(), response.get()); + assertEquals(successJson(), response.get().data()); } - private static ThrowingFunction assertExact(// + private static ThrowingFunction, HttpError> assertExact(// String url, // HttpMethod method // ) { return assertExact(url, method, null); } - private static ThrowingFunction assertExact(// + private static ThrowingFunction, HttpError> assertExact(// String url, // HttpMethod method, // String body // @@ -135,18 +132,18 @@ private static ThrowingFunction assertE assertEquals(method, endpoint.method()); assertEquals(body, endpoint.body()); - return "success"; + return HttpResponse.ok("success"); }; } - private static ThrowingFunction assertExactJson(// + private static ThrowingFunction, HttpError> assertExactJson(// String url, // HttpMethod method // ) { return assertExactJson(url, method, null); } - private static ThrowingFunction assertExactJson(// + private static ThrowingFunction, HttpError> assertExactJson(// String url, // HttpMethod method, // JsonElement body // @@ -160,12 +157,16 @@ private static ThrowingFunction assertE if (body != null) { assertNotNull(endpoint.body()); - assertEquals(body, JsonUtils.parse(endpoint.body())); + try { + assertEquals(body, JsonUtils.parse(endpoint.body())); + } catch (OpenemsNamedException e) { + fail(e.getMessage()); + } } else { assertNull(endpoint.body()); } - return successJson().toString(); + return HttpResponse.ok(successJson().toString()); }; } diff --git a/io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/api/BridgeHttpTimeTest.java b/io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/api/BridgeHttpTimeTest.java index 0edf0840df0..74f89ade961 100644 --- a/io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/api/BridgeHttpTimeTest.java +++ b/io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/api/BridgeHttpTimeTest.java @@ -1,41 +1,43 @@ package io.openems.edge.bridge.http.api; import static io.openems.edge.bridge.http.time.DelayTimeProviderChain.fixedDelay; +import static org.junit.Assert.assertEquals; import java.time.Duration; -import java.util.concurrent.CompletableFuture; +import java.time.temporal.ChronoUnit; +import java.util.concurrent.atomic.AtomicInteger; import org.junit.After; import org.junit.Before; import org.junit.Test; -import io.openems.common.utils.ReflectionUtils; +import io.openems.common.test.TimeLeapClock; import io.openems.edge.bridge.http.BridgeHttpImpl; -import io.openems.edge.bridge.http.CycleSubscriber; -import io.openems.edge.bridge.http.DummyUrlFetcher; +import io.openems.edge.bridge.http.dummy.DummyBridgeHttpExecutor; +import io.openems.edge.bridge.http.dummy.DummyEndpointFetcher; public class BridgeHttpTimeTest { - private DummyUrlFetcher fetcher; private BridgeHttp bridgeHttp; + private TimeLeapClock clock; + private DummyBridgeHttpExecutor pool; @Before public void before() throws Exception { final var cycleSubscriber = new CycleSubscriber(); - this.bridgeHttp = new BridgeHttpImpl(); - ReflectionUtils.setAttribute(BridgeHttpImpl.class, this.bridgeHttp, "cycleSubscriber", cycleSubscriber); - this.fetcher = new DummyUrlFetcher(); - this.fetcher.addEndpointHandler(endpoint -> { + final var fetcher = new DummyEndpointFetcher(); + fetcher.addEndpointHandler(endpoint -> { return switch (endpoint.url()) { - case "dummy" -> "success"; + case "dummy" -> HttpResponse.ok("success"); case "error" -> throw new RuntimeException(); default -> null; }; }); - ReflectionUtils.setAttribute(BridgeHttpImpl.class, this.bridgeHttp, "urlFetcher", this.fetcher); - ((BridgeHttpImpl) this.bridgeHttp).activate(); + this.pool = new DummyBridgeHttpExecutor(this.clock = new TimeLeapClock()); + + this.bridgeHttp = new BridgeHttpImpl(cycleSubscriber, fetcher, this.pool); } @After @@ -43,22 +45,28 @@ public void after() throws Exception { ((BridgeHttpImpl) this.bridgeHttp).deactivate(); } - @Test(timeout = 1000L) + @Test public void testSubscribeTime() throws Exception { - this.fetcher.addEndpointHandler(endpoint -> { - if (!endpoint.url().equals("dummy")) { - return null; - } - - return "success"; - }); - - final var executedOnce = new CompletableFuture(); - this.bridgeHttp.subscribeTime(fixedDelay(Duration.ofHours(99)), "dummy", result -> { - executedOnce.complete(null); + final var counter = new AtomicInteger(0); + this.bridgeHttp.subscribeTime(fixedDelay(Duration.ofMinutes(1)), "dummy", result -> { + counter.incrementAndGet(); }); - executedOnce.get(); + assertEquals(0, counter.get()); + this.pool.update(); + // first should be executed immediately + assertEquals(1, counter.get()); + this.pool.update(); + assertEquals(1, counter.get()); + this.clock.leap(1, ChronoUnit.MINUTES); + this.pool.update(); + assertEquals(2, counter.get()); + this.clock.leap(59, ChronoUnit.SECONDS); + this.pool.update(); + assertEquals(2, counter.get()); + this.clock.leap(1, ChronoUnit.SECONDS); + this.pool.update(); + assertEquals(3, counter.get()); } } diff --git a/io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/time/DelayTimeProviderChainTest.java b/io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/time/DelayTimeProviderChainTest.java index b6d8cf94157..4c0fbb424f6 100644 --- a/io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/time/DelayTimeProviderChainTest.java +++ b/io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/time/DelayTimeProviderChainTest.java @@ -15,34 +15,35 @@ import io.openems.common.test.TimeLeapClock; import io.openems.common.timedata.DurationUnit; +import io.openems.edge.bridge.http.time.DelayTimeProvider.Delay; public class DelayTimeProviderChainTest { @Test public void testImmediate() { final var delayProvider = immediate(); - assertEquals(Duration.ofSeconds(0), delayProvider.getDelay()); + assertEquals(Delay.of(Duration.ofSeconds(0)), delayProvider.getDelay()); } @Test public void testFixedDelay() { final var delay = Duration.ofSeconds(9); final var delayProvider = fixedDelay(delay); - assertEquals(delay, delayProvider.getDelay()); + assertEquals(Delay.of(delay), delayProvider.getDelay()); } @Test public void testFixedAtEveryFull() { final var clock = new TimeLeapClock(LocalDateTime.of(2000, 1, 1, 12, 30, 23).toInstant(ZoneOffset.UTC)); final var delayProvider = fixedAtEveryFull(clock, DurationUnit.ofMinutes(1)); - assertEquals(Duration.ofSeconds(60 - 23), delayProvider.getDelay()); + assertEquals(Delay.of(Duration.ofSeconds(60 - 23)), delayProvider.getDelay()); } @Test public void testPlusFixedAmountDelayTimeProviderChainIntTimeUnit() { final var delayProvider = fixedDelay(Duration.ofSeconds(5)) // .plusFixedAmount(Duration.ofSeconds(3)); - assertEquals(Duration.ofSeconds(8), delayProvider.getDelay()); + assertEquals(Delay.of(Duration.ofSeconds(8)), delayProvider.getDelay()); } @Test @@ -50,8 +51,12 @@ public void testPlusRandomDelayDelayTimeProviderChainIntTimeUnit() { final var delayProvider = fixedDelay(Duration.ofSeconds(5)) // .plusRandomDelay(10, ChronoUnit.SECONDS); final var createdDelay = delayProvider.getDelay(); - assertTrue(createdDelay.toSeconds() >= 5); - assertTrue(createdDelay.toSeconds() < 15); + + assertTrue(createdDelay instanceof Delay.DurationDelay); + final var durationDelay = (Delay.DurationDelay) createdDelay; + + assertTrue(durationDelay.getDuration().toSeconds() >= 5); + assertTrue(durationDelay.getDuration().toSeconds() < 15); } } diff --git a/io.openems.edge.common/src/io/openems/edge/common/currency/Currency.java b/io.openems.edge.common/src/io/openems/edge/common/currency/Currency.java index 47b6e41ade9..1aaa95601f7 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/currency/Currency.java +++ b/io.openems.edge.common/src/io/openems/edge/common/currency/Currency.java @@ -6,6 +6,7 @@ public enum Currency implements OptionsEnum { UNDEFINED(-1), // EUR(0), // SEK(1), // + CHF(2), // ; private final int value; diff --git a/io.openems.edge.common/src/io/openems/edge/common/currency/CurrencyConfig.java b/io.openems.edge.common/src/io/openems/edge/common/currency/CurrencyConfig.java index aef402c2f16..2448ff5b004 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/currency/CurrencyConfig.java +++ b/io.openems.edge.common/src/io/openems/edge/common/currency/CurrencyConfig.java @@ -17,7 +17,11 @@ public enum CurrencyConfig { /** * Swedish Krona. */ - SEK; + SEK, + /** + * Swiss Francs. + */ + CHF; /** * Converts the {@link CurrencyConfig} to the {@link Currency}. @@ -28,6 +32,7 @@ public Currency toCurrency() { return switch (this) { case EUR -> Currency.EUR; case SEK -> Currency.SEK; + case CHF -> Currency.CHF; }; } } diff --git a/io.openems.edge.common/src/io/openems/edge/common/test/AbstractComponentTest.java b/io.openems.edge.common/src/io/openems/edge/common/test/AbstractComponentTest.java index df40330b7c2..f714fb70658 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/test/AbstractComponentTest.java +++ b/io.openems.edge.common/src/io/openems/edge/common/test/AbstractComponentTest.java @@ -14,6 +14,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.function.Consumer; import java.util.stream.Stream; import org.osgi.framework.BundleContext; @@ -260,6 +261,19 @@ public TestCase onAfterWriteCallbacks(ThrowingRunnable callback) { return this; } + /** + * Helper method to scope variables or logic specifically for this + * {@link TestCase}. + * + * @param consumer the {@link Consumer} which gets immediately executed with the + * current {@link TestCase} + * @return myself + */ + public TestCase also(Consumer consumer) { + consumer.accept(this); + return this; + } + /** * Applies the time leap to the clock. */ diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/AuthenticationRequestHandler.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/AuthenticationRequestHandler.java index e36b38e030d..1ae6a69361e 100644 --- a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/AuthenticationRequestHandler.java +++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/AuthenticationRequestHandler.java @@ -1,6 +1,5 @@ package io.openems.edge.controller.api.websocket.handler; -import java.util.List; import java.util.Map; import java.util.Optional; import java.util.UUID; @@ -29,7 +28,6 @@ import io.openems.edge.common.user.User; import io.openems.edge.common.user.UserService; import io.openems.edge.controller.api.websocket.OnRequest; -import io.openems.edge.controller.api.websocket.Utils; import io.openems.edge.controller.api.websocket.WsData; @Component(property = "entry=" + RootRequestHandler.ENTRY_POINT) @@ -96,8 +94,7 @@ private JsonrpcResponseSuccess handleAuthentication(// this.sessionTokens.put(token, user); this.log.info("User [" + user.getId() + ":" + user.getName() + "] connected."); - return new AuthenticateResponse(requestId, token, user, List.of(Utils.getEdgeMetadata(user.getRole())), - Language.DEFAULT); + return new AuthenticateResponse(requestId, token, user, Language.DEFAULT); } } diff --git a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/GroupeE.java b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/GroupeE.java new file mode 100644 index 00000000000..1415ce3636b --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/GroupeE.java @@ -0,0 +1,161 @@ +package io.openems.edge.app.timeofusetariff; + +import static io.openems.edge.core.appmanager.validator.Checkables.checkHome; + +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.common.collect.Lists; +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.types.EdgeConfig; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.app.common.props.CommonProps; +import io.openems.edge.app.timeofusetariff.GroupeE.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.Nameable; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.dependency.Tasks; +import io.openems.edge.core.appmanager.dependency.aggregatetask.SchedulerByCentralOrderConfiguration.SchedulerComponent; +import io.openems.edge.core.appmanager.validator.ValidatorConfig; + +/** + * Describes a App for GroupeE. + * + *

      +  {
      +    "appId":"App.TimeOfUseTariff.GroupeE",
      +    "alias":"GroupeE",
      +    "instanceId": UUID,
      +    "image": base64,
      +    "properties":{
      +    	"CTRL_ESS_TIME_OF_USE_TARIFF_ID": "ctrlEssTimeOfUseTariff0",
      +    	"TIME_OF_USE_TARIFF_PROVIDER_ID": "timeOfUseTariff0"
      +    },
      +    "appDescriptor": {
      +    	"websiteUrl": {@link AppDescriptor#getWebsiteUrl()}
      +    }
      +  }
      + * 
      + */ +@Component(name = "App.TimeOfUseTariff.GroupeE") +public class GroupeE extends AbstractOpenemsAppWithProps + implements OpenemsApp { + + public static enum Property implements Type, Nameable { + // Component-IDs + CTRL_ESS_TIME_OF_USE_TARIFF_ID(AppDef.componentId("ctrlEssTimeOfUseTariff0")), // + TIME_OF_USE_TARIFF_PROVIDER_ID(AppDef.componentId("timeOfUseTariff0")), // + + // Properties + ALIAS(CommonProps.alias()); // + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Property self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, Type.Parameter.BundleParameter> getParamter() { + return Type.Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + } + + @Activate + public GroupeE(@Reference ComponentManager componentManager, ComponentContext context, + @Reference ConfigurationAdmin cm, @Reference ComponentUtil componentUtil) { + super(componentManager, context, cm, componentUtil); + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + final var ctrlEssTimeOfUseTariffId = this.getId(t, p, Property.CTRL_ESS_TIME_OF_USE_TARIFF_ID); + final var timeOfUseTariffProviderId = this.getId(t, p, Property.TIME_OF_USE_TARIFF_PROVIDER_ID); + + final var alias = this.getString(p, l, Property.ALIAS); + + var components = Lists.newArrayList(// + new EdgeConfig.Component(ctrlEssTimeOfUseTariffId, alias, "Controller.Ess.Time-Of-Use-Tariff", + JsonUtils.buildJsonObject() // + .addProperty("ess.id", "ess0") // + .build()), // + new EdgeConfig.Component(timeOfUseTariffProviderId, this.getName(l), "TimeOfUseTariff.GroupeE", + JsonUtils.buildJsonObject() // + .build())// + ); + + return AppConfiguration.create() // + .addTask(Tasks.component(components)) // + .addTask(Tasks.schedulerByCentralOrder(new SchedulerComponent(ctrlEssTimeOfUseTariffId, + "Controller.Ess.Time-Of-Use-Tariff", this.getAppId()))) // + .addTask(Tasks.persistencePredictor("_sum/UnmanagedConsumptionActivePower")) // + .build(); + }; + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.TIME_OF_USE_TARIFF }; + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.SINGLE_IN_CATEGORY; + } + + @Override + protected ValidatorConfig.Builder getValidateBuilder() { + return ValidatorConfig.create() // + .setCompatibleCheckableConfigs(checkHome()); + } + + @Override + protected GroupeE getApp() { + return this; + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StadtwerkHassfurt.java b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StadtwerkHassfurt.java new file mode 100644 index 00000000000..e013386d2dc --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StadtwerkHassfurt.java @@ -0,0 +1,203 @@ +package io.openems.edge.app.timeofusetariff; + +import static io.openems.edge.app.common.props.CommonProps.defaultDef; +import static io.openems.edge.core.appmanager.validator.Checkables.checkHome; + +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.common.collect.Lists; +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.types.EdgeConfig; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.app.common.props.CommonProps; +import io.openems.edge.app.enums.OptionsFactory; +import io.openems.edge.app.enums.TranslatableEnum; +import io.openems.edge.app.timeofusetariff.StadtwerkHassfurt.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.Nameable; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.dependency.Tasks; +import io.openems.edge.core.appmanager.dependency.aggregatetask.SchedulerByCentralOrderConfiguration.SchedulerComponent; +import io.openems.edge.core.appmanager.formly.JsonFormlyUtil; +import io.openems.edge.core.appmanager.validator.ValidatorConfig; + +/** + * Describes a App for StadtwerkHassfurt. + * + *
      +  {
      +    "appId":"App.TimeOfUseTariff.Hassfurt",
      +    "alias":"Stadtwerk Hassfurt",
      +    "instanceId": UUID,
      +    "image": base64,
      +    "properties":{
      +    	"CTRL_ESS_TIME_OF_USE_TARIFF_ID": "ctrlEssTimeOfUseTariff0",
      +    	"TIME_OF_USE_TARIFF_PROVIDER_ID": "timeOfUseTariff0",
      +    	"TARIFF_TYPE": {@link TariffType}
      +    },
      +    "appDescriptor": {
      +    	"websiteUrl": {@link AppDescriptor#getWebsiteUrl()}
      +    }
      +  }
      + * 
      + */ +@Component(name = "App.TimeOfUseTariff.Hassfurt") +public class StadtwerkHassfurt extends + AbstractOpenemsAppWithProps implements OpenemsApp { + + public static enum Property implements Type, Nameable { + // Component-IDs + CTRL_ESS_TIME_OF_USE_TARIFF_ID(AppDef.componentId("ctrlEssTimeOfUseTariff0")), // + TIME_OF_USE_TARIFF_PROVIDER_ID(AppDef.componentId("timeOfUseTariff0")), // + + // Properties + ALIAS(CommonProps.alias()), // + TARIFF_TYPE(AppDef.copyOfGeneric(defaultDef(), def -> def // + .setTranslatedLabelWithAppPrefix(".tariffType.label") // + .setTranslatedDescriptionWithAppPrefix(".tariffType.description") // + .setRequired(true)// + .setDefaultValue(TariffType.STROM_FLEX)// + .setField(JsonFormlyUtil::buildSelectFromNameable, (app, property, l, parameter, field) -> { + field.setOptions(TariffType.optionsFactory(), l); + }))); + + private final AppDef def; + + private Property( + AppDef def) { + this.def = def; + } + + @Override + public Property self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, Type.Parameter.BundleParameter> getParamter() { + return Type.Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + } + + @Activate + public StadtwerkHassfurt(@Reference ComponentManager componentManager, ComponentContext context, + @Reference ConfigurationAdmin cm, @Reference ComponentUtil componentUtil) { + super(componentManager, context, cm, componentUtil); + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + final var ctrlEssTimeOfUseTariffId = this.getId(t, p, Property.CTRL_ESS_TIME_OF_USE_TARIFF_ID); + final var timeOfUseTariffProviderId = this.getId(t, p, Property.TIME_OF_USE_TARIFF_PROVIDER_ID); + + final var alias = this.getString(p, l, Property.ALIAS); + final var tariffType = this.getEnum(p, TariffType.class, Property.TARIFF_TYPE); + + var components = Lists.newArrayList(// + new EdgeConfig.Component(ctrlEssTimeOfUseTariffId, alias, "Controller.Ess.Time-Of-Use-Tariff", + JsonUtils.buildJsonObject() // + .addProperty("ess.id", "ess0") // + .build()), // + new EdgeConfig.Component(timeOfUseTariffProviderId, this.getName(l), "TimeOfUseTariff.Hassfurt", + JsonUtils.buildJsonObject() // + .addProperty("tariffType", tariffType) // + .build())// + ); + + return AppConfiguration.create() // + .addTask(Tasks.component(components)) // + .addTask(Tasks.schedulerByCentralOrder(new SchedulerComponent(ctrlEssTimeOfUseTariffId, + "Controller.Ess.Time-Of-Use-Tariff", this.getAppId()))) // + .addTask(Tasks.persistencePredictor("_sum/UnmanagedConsumptionActivePower")) // + .build(); + }; + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.TIME_OF_USE_TARIFF }; + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.SINGLE_IN_CATEGORY; + } + + @Override + protected ValidatorConfig.Builder getValidateBuilder() { + return ValidatorConfig.create() // + .setCompatibleCheckableConfigs(checkHome()); + } + + @Override + protected StadtwerkHassfurt getApp() { + return this; + } + + public enum TariffType implements TranslatableEnum { + STROM_FLEX("haStrom Flex"), // + STROM_FLEX_PRO("haStrom Flex Pro"), // + ; + + private final String label; + + private TariffType(String label) { + this.label = label; + } + + @Override + public final String getTranslation(Language l) { + return this.label; + } + + /** + * Creates a {@link OptionsFactory} of this enum. + * + * @return the {@link OptionsFactory} + */ + public static final OptionsFactory optionsFactory() { + return OptionsFactory.of(values()); + } + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties index 36d9b9dd184..a7bb8211d12 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties @@ -350,6 +350,12 @@ App.TimeOfUseTariff.ENTSO-E.biddingZone.option.sweden_se3 = Schweden (SE3) App.TimeOfUseTariff.ENTSO-E.biddingZone.option.sweden_se4 = Schweden (SE4) App.TimeOfUseTariff.ENTSO-E.biddingZone.option.belgium = Belgien App.TimeOfUseTariff.ENTSO-E.biddingZone.option.netherlands = Niederlande +App.TimeOfUseTariff.GroupeE.Name = Dynamischer Stromtarif (Groupe-E) +App.TimeOfUseTariff.GroupeE.Name.short = Groupe-E +App.TimeOfUseTariff.Hassfurt.Name = Dynamischer Stromtarif (Stadtwerk Haßfurt) +App.TimeOfUseTariff.Hassfurt.Name.short = Stadtwerk Haßfurt +App.TimeOfUseTariff.Hassfurt.tariffType.label = Tariftyp +App.TimeOfUseTariff.Hassfurt.tariffType.description = Ihr gewählter Stromtarif App.TimeOfUseTariff.RabotCharge.Name = Time-of-Use Tariff (rabot.charge) App.TimeOfUseTariff.RabotCharge.Name.short = rabot.charge App.TimeOfUseTariff.RabotCharge.accessToken.label = Token diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties index fe9c08c25f9..00e23e68823 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties @@ -349,6 +349,12 @@ App.TimeOfUseTariff.ENTSO-E.biddingZone.option.sweden_se3 = Sweden (SE3) App.TimeOfUseTariff.ENTSO-E.biddingZone.option.sweden_se4 = Sweden (SE4) App.TimeOfUseTariff.ENTSO-E.biddingZone.option.belgium = Belgium App.TimeOfUseTariff.ENTSO-E.biddingZone.option.netherlands = Netherlands +App.TimeOfUseTariff.GroupeE.Name = Time-of-Use Tariff (Groupe-E) +App.TimeOfUseTariff.GroupeE.Name.short = Groupe-E +App.TimeOfUseTariff.Hassfurt.Name = Time-of-Use Tariff (Stadtwerk Hassfurt) +App.TimeOfUseTariff.Hassfurt.Name.short = Stadtwerk Hassfurt +App.TimeOfUseTariff.Hassfurt.tariffType.label = Tariff type +App.TimeOfUseTariff.Hassfurt.tariffType.description = Energy tariff you subscribed to App.TimeOfUseTariff.RabotCharge.Name = Time-of-Use Tariff (rabot.charge) App.TimeOfUseTariff.RabotCharge.Name.short = rabot.charge App.TimeOfUseTariff.RabotCharge.accessToken.label = Token diff --git a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java index 1df00beb666..bf41766cd55 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java @@ -1,10 +1,13 @@ package io.openems.edge.core.componentmanager; +import static java.util.stream.Collectors.toMap; + import java.io.IOException; import java.time.Clock; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Dictionary; import java.util.Hashtable; @@ -29,9 +32,11 @@ import org.osgi.service.metatype.annotations.Designate; import org.slf4j.Logger; +import com.google.common.collect.Lists; import com.google.gson.JsonNull; import io.openems.common.OpenemsConstants; +import io.openems.common.channel.ChannelCategory; import io.openems.common.exceptions.OpenemsError; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; @@ -43,8 +48,12 @@ import io.openems.common.jsonrpc.request.UpdateComponentConfigRequest.Property; import io.openems.common.jsonrpc.response.GetEdgeConfigResponse; import io.openems.common.session.Role; +import io.openems.common.types.ChannelAddress; import io.openems.common.types.EdgeConfig; import io.openems.common.utils.JsonUtils; +import io.openems.edge.common.channel.Channel; +import io.openems.edge.common.channel.EnumDoc; +import io.openems.edge.common.channel.StateChannelDoc; import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.ClockProvider; import io.openems.edge.common.component.ComponentManager; @@ -56,6 +65,12 @@ import io.openems.edge.common.user.User; import io.openems.edge.core.componentmanager.jsonrpc.ChannelExportXlsxRequest; import io.openems.edge.core.componentmanager.jsonrpc.ChannelExportXlsxResponse; +import io.openems.edge.core.componentmanager.jsonrpc.GetChannel; +import io.openems.edge.core.componentmanager.jsonrpc.GetChannelsOfComponent; +import io.openems.edge.core.componentmanager.jsonrpc.GetChannelsOfComponent.ChannelRecord; +import io.openems.edge.core.componentmanager.jsonrpc.GetDigitalInputChannelsOfComponents; +import io.openems.edge.core.componentmanager.jsonrpc.GetStateChannelsOfComponent; +import io.openems.edge.io.api.DigitalInput; @Designate(ocd = Config.class, factory = false) @Component(// @@ -343,6 +358,74 @@ public void buildJsonApiRoutes(JsonApiBuilder builder) { return this.handleChannelExportXlsxRequest(t.get(EdgeKeys.USER_KEY), // ChannelExportXlsxRequest.from(t.getRequest())); }); + + builder.handleRequest(new GetStateChannelsOfComponent(), endpoint -> { + endpoint.setDescription(""" + Handles a GetStateChannelsOfComponent. + """); + }, call -> { + // TODO could be used for translating channel texts + // final var user = call.get(EdgeKeys.USER_KEY); + + final var channels = this.getPossiblyDisabledComponent(call.getRequest().componentId()).channels().stream() // + .filter(t -> t.channelDoc().getChannelCategory() == ChannelCategory.STATE) // + .map(ComponentManagerImpl::toChannelRecord) // + .toList(); + + return new GetStateChannelsOfComponent.Response(channels); + }); + + builder.handleRequest(new GetChannelsOfComponent(), endpoint -> { + endpoint.setDescription(""" + Handles a GetStateChannelsOfComponent. + """); + }, call -> { + final var channels = this.getPossiblyDisabledComponent(call.getRequest().componentId()).channels().stream() // + .map(ComponentManagerImpl::toChannelRecord) // + .toList(); + + return new GetChannelsOfComponent.Response(channels); + }); + + builder.handleRequest(new GetChannel(), endpoint -> { + endpoint.setDescription(""" + Handles a GetChannel. + """); + }, call -> { + final var request = call.getRequest(); + final var channel = this.getChannel(new ChannelAddress(request.componentId(), request.channelId())); + + Thread.sleep(5000); + return new GetChannel.Response(toChannelRecord(channel)); + }); + + builder.handleRequest(new GetDigitalInputChannelsOfComponents(), endpoint -> { + endpoint.setDescription(""" + Handles a GetDigitalInputChannelsOfComponent. + """); + }, call -> { + + final var result = this.getEnabledComponentsOfType(DigitalInput.class).stream() // + .filter(t -> call.getRequest().componentIds().contains(t.id())) // + .collect(toMap(OpenemsComponent::id, t -> Arrays.stream(t.digitalInputChannels()) // + .map(ComponentManagerImpl::toChannelRecord) // + .toList())); + + return new GetDigitalInputChannelsOfComponents.Response(result); + }); + } + + private static ChannelRecord toChannelRecord(Channel channel) { + return new GetChannelsOfComponent.ChannelRecord(// + channel.channelId().id(), // + channel.channelDoc().getAccessMode(), // + channel.channelDoc().getPersistencePriority(), // + channel.channelDoc().getText(), // + channel.channelDoc().getType(), // + channel.channelDoc().getUnit(), // + channel.channelDoc().getChannelCategory(), // + channel.channelDoc() instanceof StateChannelDoc c ? c.getLevel() : null, // + channel.channelDoc() instanceof EnumDoc c ? Lists.newArrayList(c.getOptions()) : null); } /** diff --git a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetChannel.java b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetChannel.java new file mode 100644 index 00000000000..516c1908170 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetChannel.java @@ -0,0 +1,72 @@ +package io.openems.edge.core.componentmanager.jsonrpc; + +import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.jsonObjectSerializer; + +import io.openems.common.jsonrpc.serialization.JsonSerializer; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.common.jsonapi.EndpointRequestType; +import io.openems.edge.core.appmanager.jsonrpc.AddAppInstance; +import io.openems.edge.core.componentmanager.jsonrpc.GetChannel.Request; +import io.openems.edge.core.componentmanager.jsonrpc.GetChannel.Response; +import io.openems.edge.core.componentmanager.jsonrpc.GetChannelsOfComponent.ChannelRecord; + +public class GetChannel implements EndpointRequestType { + + @Override + public String getMethod() { + return "getChannel"; + } + + @Override + public JsonSerializer getRequestSerializer() { + return Request.serializer(); + } + + @Override + public JsonSerializer getResponseSerializer() { + return Response.serializer(); + } + + public record Request(// + String componentId, // + String channelId // + ) { + + /** + * Returns a {@link JsonSerializer} for a {@link AddAppInstance.Request}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(Request.class, // + json -> new Request(// + json.getString("componentId"), // + json.getString("channelId")), // + obj -> JsonUtils.buildJsonObject() // + .addProperty("componentId", obj.componentId()) // + .addProperty("channelId", obj.channelId()) // + .build()); + } + + } + + public record Response(ChannelRecord channel) { + + /** + * Returns a {@link JsonSerializer} for a {@link GetChannel.Response}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(GetChannel.Response.class, json -> { + return new Response(json.getElement("channel", ChannelRecord.serializer())); + }, obj -> { + return JsonUtils.buildJsonObject() // + .add("channel", ChannelRecord.serializer().serialize(obj.channel())) // + .build(); + }); + } + + } + +} \ No newline at end of file diff --git a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetChannelsOfComponent.java b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetChannelsOfComponent.java new file mode 100644 index 00000000000..b632c12ab2e --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetChannelsOfComponent.java @@ -0,0 +1,127 @@ +package io.openems.edge.core.componentmanager.jsonrpc; + +import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.jsonObjectSerializer; +import static io.openems.common.utils.JsonUtils.toJsonObject; +import static java.util.Collections.emptyList; + +import java.util.List; + +import com.google.gson.JsonPrimitive; + +import io.openems.common.channel.AccessMode; +import io.openems.common.channel.ChannelCategory; +import io.openems.common.channel.Level; +import io.openems.common.channel.PersistencePriority; +import io.openems.common.channel.Unit; +import io.openems.common.jsonrpc.serialization.JsonSerializer; +import io.openems.common.types.OpenemsType; +import io.openems.common.types.OptionsEnum; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.common.jsonapi.EndpointRequestType; +import io.openems.edge.core.appmanager.jsonrpc.AddAppInstance; +import io.openems.edge.core.componentmanager.jsonrpc.GetChannelsOfComponent.Request; +import io.openems.edge.core.componentmanager.jsonrpc.GetChannelsOfComponent.Response; + +public class GetChannelsOfComponent implements EndpointRequestType { + + @Override + public String getMethod() { + return "getChannelsOfComponent"; + } + + @Override + public JsonSerializer getRequestSerializer() { + return Request.serializer(); + } + + @Override + public JsonSerializer getResponseSerializer() { + return Response.serializer(); + } + + public record Request(// + String componentId // + ) { + + /** + * Returns a {@link JsonSerializer} for a {@link AddAppInstance.Request}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(Request.class, // + json -> new Request(json.getString("componentId")), // + obj -> JsonUtils.buildJsonObject() // + .addProperty("componentId", obj.componentId()) // + .build()); + } + + } + + public record Response(List channels) { + + /** + * Returns a {@link JsonSerializer} for a + * {@link GetChannelsOfComponent.Response}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(GetChannelsOfComponent.Response.class, json -> { + // TODO + return new Response(emptyList()); + }, obj -> { + return JsonUtils.buildJsonObject() // + .add("channels", ChannelRecord.serializer().toListSerializer().serialize(obj.channels())) + .build(); + }); + } + + } + + public record ChannelRecord(// + String id, // + AccessMode accessMode, // + PersistencePriority persistencePriority, // + String text, // + OpenemsType type, // + Unit unit, // + + ChannelCategory category, // + + // category = ChannelCategory.STATE + Level level, // + + // category = ChannelCategory.ENUM + List options // + ) { + + /** + * Returns a {@link JsonSerializer} for a + * {@link GetChannelsOfComponent.ChannelRecord}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(GetChannelsOfComponent.ChannelRecord.class, json -> { + + return null; // new GetChannelsOfComponent.ChannelRecord(); + }, obj -> { + return JsonUtils.buildJsonObject() // + .addProperty("id", obj.id()) // + .addProperty("accessMode", obj.accessMode().getAbbreviation()) // + .addProperty("persistencePriority", obj.persistencePriority()) // + .addProperty("text", obj.text()) // + .addProperty("type", obj.type()) // + .addProperty("unit", obj.unit().symbol) // + .addProperty("category", obj.category()) // + .onlyIf(obj.level() != null, t -> t.addProperty("level", obj.level())) // + .onlyIf(obj.options() != null, t -> t.add("options", obj.options().stream() // + .collect(toJsonObject(i -> i.getName(), i -> new JsonPrimitive(i.getValue()))))) // + .build(); + }); + } + + } + +} \ No newline at end of file diff --git a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetDigitalInputChannelsOfComponents.java b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetDigitalInputChannelsOfComponents.java new file mode 100644 index 00000000000..cb820d51cc8 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetDigitalInputChannelsOfComponents.java @@ -0,0 +1,94 @@ +package io.openems.edge.core.componentmanager.jsonrpc; + +import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.jsonObjectSerializer; +import static io.openems.common.utils.JsonUtils.toJsonArray; +import static java.util.stream.Collectors.toMap; + +import java.util.List; +import java.util.Map; + +import com.google.gson.JsonPrimitive; + +import io.openems.common.jsonrpc.serialization.JsonElementPath; +import io.openems.common.jsonrpc.serialization.JsonSerializer; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.common.jsonapi.EndpointRequestType; +import io.openems.edge.common.type.Tuple; +import io.openems.edge.core.appmanager.jsonrpc.AddAppInstance; +import io.openems.edge.core.componentmanager.jsonrpc.GetChannelsOfComponent.ChannelRecord; +import io.openems.edge.core.componentmanager.jsonrpc.GetDigitalInputChannelsOfComponents.Request; +import io.openems.edge.core.componentmanager.jsonrpc.GetDigitalInputChannelsOfComponents.Response; + +public class GetDigitalInputChannelsOfComponents implements EndpointRequestType { + + @Override + public String getMethod() { + return "getDigitalInputChannelsOfComponents"; + } + + @Override + public JsonSerializer getRequestSerializer() { + return Request.serializer(); + } + + @Override + public JsonSerializer getResponseSerializer() { + return Response.serializer(); + } + + public record Request(// + List componentIds // + ) { + + /** + * Returns a {@link JsonSerializer} for a {@link AddAppInstance.Request}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(Request.class, // + json -> new Request(// + json.getList("componentIds", JsonElementPath::getAsString)), // + obj -> JsonUtils.buildJsonObject() // + .add("componentIds", obj.componentIds().stream() // + .map(JsonPrimitive::new) // + .collect(toJsonArray())) // + .build()); + } + + } + + public record Response(Map> channelsPerComponent) { + + /** + * Returns a {@link JsonSerializer} for a + * {@link GetDigitalInputChannelsOfComponents.Response}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(GetDigitalInputChannelsOfComponents.Response.class, json -> { + final var resultMap = json.getList("channelsPerComponent", t -> { + final var element = t.getAsJsonObjectPath(); + return Tuple.of(element.getString("componentId"), + element.getList("channels", ChannelRecord.serializer())); + }).stream().collect(toMap(Tuple::a, Tuple::b)); + + return new Response(resultMap); + }, obj -> { + return JsonUtils.buildJsonObject() // + .add("channelsPerComponent", obj.channelsPerComponent().entrySet().stream() // + .map(t -> JsonUtils.buildJsonObject() // + .addProperty("componentId", t.getKey()) // + .add("channels", t.getValue().stream() // + .map(ChannelRecord.serializer()::serialize) // + .collect(toJsonArray())) + .build()) // + .collect(toJsonArray())) // + .build(); + }); + } + + } + +} \ No newline at end of file diff --git a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetStateChannelsOfComponent.java b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetStateChannelsOfComponent.java new file mode 100644 index 00000000000..181233e0eb5 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetStateChannelsOfComponent.java @@ -0,0 +1,70 @@ +package io.openems.edge.core.componentmanager.jsonrpc; + +import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.jsonObjectSerializer; + +import java.util.List; + +import io.openems.common.jsonrpc.serialization.JsonSerializer; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.common.jsonapi.EndpointRequestType; +import io.openems.edge.core.appmanager.jsonrpc.AddAppInstance; +import io.openems.edge.core.componentmanager.jsonrpc.GetChannelsOfComponent.ChannelRecord; +import io.openems.edge.core.componentmanager.jsonrpc.GetStateChannelsOfComponent.Request; +import io.openems.edge.core.componentmanager.jsonrpc.GetStateChannelsOfComponent.Response; + +public class GetStateChannelsOfComponent implements EndpointRequestType { + + @Override + public String getMethod() { + return "getStateChannelsOfComponent"; + } + + @Override + public JsonSerializer getRequestSerializer() { + return Request.serializer(); + } + + @Override + public JsonSerializer getResponseSerializer() { + return Response.serializer(); + } + + public record Request(// + String componentId // + ) { + + /** + * Returns a {@link JsonSerializer} for a {@link AddAppInstance.Request}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(Request.class, // + json -> new Request(json.getString("componentId")), // + obj -> JsonUtils.buildJsonObject() // + .addProperty("componentId", obj.componentId()) // + .build()); + } + + } + + public record Response(// + List channels // + ) { + + /** + * Returns a {@link JsonSerializer} for a {@link AddAppInstance.Request}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(Response.class, // + json -> new Response(json.getList("channels", ChannelRecord.serializer())), // + obj -> JsonUtils.buildJsonObject() // + .add("channels", ChannelRecord.serializer().toListSerializer().serialize(obj.channels())) // + .build()); + } + + } + +} \ No newline at end of file diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/Apps.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/Apps.java index 49d88adf37d..28c448cf56f 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/Apps.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/Apps.java @@ -50,7 +50,9 @@ import io.openems.edge.app.pvselfconsumption.SelfConsumptionOptimization; import io.openems.edge.app.timeofusetariff.AwattarHourly; import io.openems.edge.app.timeofusetariff.EntsoE; +import io.openems.edge.app.timeofusetariff.GroupeE; import io.openems.edge.app.timeofusetariff.RabotCharge; +import io.openems.edge.app.timeofusetariff.StadtwerkHassfurt; import io.openems.edge.app.timeofusetariff.StromdaoCorrently; import io.openems.edge.app.timeofusetariff.Tibber; import io.openems.edge.common.component.ComponentManager; @@ -131,6 +133,26 @@ public static final EntsoE entsoE(AppManagerTestBundle t) { return app(t, EntsoE::new, "App.TimeOfUseTariff.ENTSO-E"); } + /** + * Test method for creating a {@link GroupeE}. + * + * @param t the {@link AppManagerTestBundle} + * @return the {@link OpenemsApp} instance + */ + public static final GroupeE groupeE(AppManagerTestBundle t) { + return app(t, GroupeE::new, "App.TimeOfUseTariff.GroupeE"); + } + + /** + * Test method for creating a {@link StadtwerkHassfurt}. + * + * @param t the {@link AppManagerTestBundle} + * @return the {@link OpenemsApp} instance + */ + public static final StadtwerkHassfurt stadtwerkHassfurt(AppManagerTestBundle t) { + return app(t, StadtwerkHassfurt::new, "App.TimeOfUseTariff.Hassfurt"); + } + /** * Test method for creating a {@link RabotCharge}. * diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestTranslations.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestTranslations.java index e414179bc38..05f25ba9c60 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestTranslations.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestTranslations.java @@ -38,9 +38,13 @@ public void beforeEach() throws Exception { this.apps.add(new TestTranslation(Apps.entsoE(t), true, JsonUtils.buildJsonObject() // .addProperty("BIDDING_ZONE", "GERMANY") // .build())); + this.apps.add(new TestTranslation(Apps.groupeE(t), true, JsonUtils.buildJsonObject() // + .build())); this.apps.add(new TestTranslation(Apps.rabotCharge(t), true, JsonUtils.buildJsonObject() // .addProperty("ACCESS_TOKEN", "123456789") // .build())); + this.apps.add(new TestTranslation(Apps.stadtwerkHassfurt(t), true, JsonUtils.buildJsonObject() // + .build())); this.apps.add(new TestTranslation(Apps.stromdaoCorrently(t), true, JsonUtils.buildJsonObject() // .addProperty("ZIP_CODE", "123456789") // .build())); diff --git a/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/EvcsHardyBarth.java b/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/EvcsHardyBarth.java index c4f24c8e393..4029d0495fd 100644 --- a/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/EvcsHardyBarth.java +++ b/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/EvcsHardyBarth.java @@ -88,7 +88,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { RAW_ACTIVE_POWER_L3(Doc.of(OpenemsType.LONG).unit(Unit.WATT), value -> { Double doubleValue = TypeUtils.getAsType(OpenemsType.DOUBLE, value); return TypeUtils.getAsType(OpenemsType.LONG, TypeUtils.multiply(doubleValue, SCALE_FACTOR_MINUS_1)); - }, "secc", "port0", "metering", "power", "active", "ac", "l2", "actual"), // + }, "secc", "port0", "metering", "power", "active", "ac", "l3", "actual"), // // METERING - CURRENT RAW_ACTIVE_CURRENT_L1(Doc.of(OpenemsType.LONG).unit(Unit.MILLIAMPERE), "secc", "port0", "metering", "current", diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java index d69c0cd2ffd..6a517ca0895 100644 --- a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly25/IoShelly25Impl.java @@ -24,6 +24,8 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.edge.bridge.http.api.BridgeHttp; import io.openems.edge.bridge.http.api.BridgeHttpFactory; +import io.openems.edge.bridge.http.api.HttpError; +import io.openems.edge.bridge.http.api.HttpResponse; import io.openems.edge.common.channel.BooleanWriteChannel; import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.OpenemsComponent; @@ -146,13 +148,13 @@ private void applyChannels(IoShelly25 component, IoShelly25.ChannelId relayChann * communication with the slave device is * unsuccessful. */ - private void processHttpResult(JsonElement result, Throwable error) { + private void processHttpResult(HttpResponse result, HttpError error) { var slaveCommunicationFailed = result == null; var relay1State = new RelayState(null, null, null); var relay2State = new RelayState(null, null, null); try { - final var relays = getAsJsonArray(result, "relays"); + final var relays = getAsJsonArray(result.data(), "relays"); relay1State = RelayState.from(getAsJsonObject(relays.get(0))); relay2State = RelayState.from(getAsJsonObject(relays.get(1))); diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly3em/IoShelly3EmImpl.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly3em/IoShelly3EmImpl.java index 1cb2c8d1f1e..ca9eaf27fcb 100644 --- a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly3em/IoShelly3EmImpl.java +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shelly3em/IoShelly3EmImpl.java @@ -30,6 +30,7 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.edge.bridge.http.api.BridgeHttp; import io.openems.edge.bridge.http.api.BridgeHttpFactory; +import io.openems.edge.bridge.http.api.HttpResponse; import io.openems.edge.common.channel.BooleanWriteChannel; import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.OpenemsComponent; @@ -127,7 +128,7 @@ public void handleEvent(Event event) { } } - private void processHttpResult(JsonElement result, Throwable error) { + private void processHttpResult(HttpResponse result, Throwable error) { this._setSlaveCommunicationFailed(result == null); // Prepare variables @@ -150,7 +151,7 @@ private void processHttpResult(JsonElement result, Throwable error) { } else { try { - var response = getAsJsonObject(result); + var response = getAsJsonObject(result.data()); var relays = getAsJsonArray(response, "relays"); if (!relays.isEmpty()) { diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplug/IoShellyPlugImpl.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplug/IoShellyPlugImpl.java index a883becf42c..2bdad4b9521 100644 --- a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplug/IoShellyPlugImpl.java +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplug/IoShellyPlugImpl.java @@ -23,6 +23,7 @@ import io.openems.common.utils.JsonUtils; import io.openems.edge.bridge.http.api.BridgeHttp; import io.openems.edge.bridge.http.api.BridgeHttpFactory; +import io.openems.edge.bridge.http.api.HttpResponse; import io.openems.edge.common.channel.BooleanWriteChannel; import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.OpenemsComponent; @@ -117,7 +118,7 @@ public void handleEvent(Event event) { } } - private void processHttpResult(JsonElement result, Throwable error) { + private void processHttpResult(HttpResponse result, Throwable error) { this._setSlaveCommunicationFailed(result == null); if (error != null) { this._setRelay(null); @@ -127,10 +128,10 @@ private void processHttpResult(JsonElement result, Throwable error) { return; } try { - final var relays = JsonUtils.getAsJsonArray(result, "relays"); + final var relays = JsonUtils.getAsJsonArray(result.data(), "relays"); final var relay1 = JsonUtils.getAsJsonObject(relays.get(0)); final var relayIson = JsonUtils.getAsBoolean(relay1, "ison"); - final var meters = JsonUtils.getAsJsonArray(result, "meters"); + final var meters = JsonUtils.getAsJsonArray(result.data(), "meters"); final var meter1 = JsonUtils.getAsJsonObject(meters.get(0)); final var power = Math.round(JsonUtils.getAsFloat(meter1, "power")); final var energy = JsonUtils.getAsLong(meter1, "total") /* Unit: Wm */ / 60 /* Wh */; diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlusPlugsImpl.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlusPlugsImpl.java index fd441091fa7..cdd253f120f 100644 --- a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlusPlugsImpl.java +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlusPlugsImpl.java @@ -28,6 +28,8 @@ import io.openems.edge.bridge.http.api.BridgeHttp; import io.openems.edge.bridge.http.api.BridgeHttpFactory; +import io.openems.edge.bridge.http.api.HttpError; +import io.openems.edge.bridge.http.api.HttpResponse; import io.openems.edge.common.channel.BooleanWriteChannel; import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.OpenemsComponent; @@ -138,7 +140,7 @@ public void handleEvent(Event event) { } } - private void processHttpResult(JsonElement result, Throwable error) { + private void processHttpResult(HttpResponse result, HttpError error) { this._setSlaveCommunicationFailed(result == null); Boolean relayStatus = null; @@ -152,7 +154,7 @@ private void processHttpResult(JsonElement result, Throwable error) { } else { try { - var response = getAsJsonObject(result); + var response = getAsJsonObject(result.data()); var sysInfo = getAsJsonObject(response, "sys"); var update = getAsJsonObject(sysInfo, "available_updates"); updatesAvailable = update != null && !update.entrySet().isEmpty(); diff --git a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shelly25/IoShelly25ImplTest.java b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shelly25/IoShelly25ImplTest.java index 2e6e2a98902..06b3f7975cf 100644 --- a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shelly25/IoShelly25ImplTest.java +++ b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shelly25/IoShelly25ImplTest.java @@ -12,7 +12,7 @@ public class IoShelly25ImplTest { @Test public void test() throws Exception { new ComponentTest(new IoShelly25Impl()) // - .addReference("httpBridgeFactory", new DummyBridgeHttpFactory()) // + .addReference("httpBridgeFactory", DummyBridgeHttpFactory.ofDummyBridge()) // .activate(MyConfig.create() // .setId(COMPONENT_ID) // .setIp("127.0.0.1") // diff --git a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shelly3em/IoShelly3EmImplTest.java b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shelly3em/IoShelly3EmImplTest.java index d7184c4c84f..1c06c65f443 100644 --- a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shelly3em/IoShelly3EmImplTest.java +++ b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shelly3em/IoShelly3EmImplTest.java @@ -13,7 +13,7 @@ public class IoShelly3EmImplTest { @Test public void test() throws Exception { new ComponentTest(new IoShelly3EmImpl()) // - .addReference("httpBridgeFactory", new DummyBridgeHttpFactory()) // + .addReference("httpBridgeFactory", DummyBridgeHttpFactory.ofDummyBridge()) // .activate(MyConfig.create() // .setId(COMPONENT_ID) // .setIp("127.0.0.1") // diff --git a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplug/IoShellyPlugImplTest.java b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplug/IoShellyPlugImplTest.java index fd99bec6db1..efef443c6b0 100644 --- a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplug/IoShellyPlugImplTest.java +++ b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplug/IoShellyPlugImplTest.java @@ -14,7 +14,7 @@ public class IoShellyPlugImplTest { @Test public void test() throws Exception { new ComponentTest(new IoShellyPlugImpl()) // - .addReference("httpBridgeFactory", new DummyBridgeHttpFactory()) // + .addReference("httpBridgeFactory", DummyBridgeHttpFactory.ofDummyBridge()) // .activate(MyConfig.create() // .setId(COMPONENT_ID) // .setPhase(SinglePhase.L1) // diff --git a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlugImplTest.java b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlugImplTest.java index 88da88fe9ff..9b1a1d50795 100644 --- a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlugImplTest.java +++ b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlugImplTest.java @@ -1,11 +1,14 @@ package io.openems.edge.io.shelly.shellyplusplugs; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import org.junit.Test; import io.openems.common.types.ChannelAddress; -import io.openems.edge.bridge.http.dummy.DummyBridgeHttpFactory; +import io.openems.edge.bridge.http.api.HttpError; +import io.openems.edge.bridge.http.api.HttpResponse; +import io.openems.edge.bridge.http.dummy.DummyBridgeHttpBundle; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.meter.api.MeterType; @@ -27,11 +30,11 @@ public class IoShellyPlugImplTest { @Test public void test() throws Exception { - final var bridgeFactory = new DummyBridgeHttpFactory(); - final var bridge = bridgeFactory.bridge; + final var httpTestBundle = new DummyBridgeHttpBundle(); + final var sut = new IoShellyPlusPlugsImpl(); new ComponentTest(sut) // - .addReference("httpBridgeFactory", bridgeFactory) // + .addReference("httpBridgeFactory", httpTestBundle.factory()) // .addReference("timedata", new DummyTimedata("timedata0")) // .activate(MyConfig.create() // .setId(COMPONENT_ID) // @@ -41,21 +44,24 @@ public void test() throws Exception { .build()) // .next(new TestCase("Successfull read response") // - .onBeforeControllersCallbacks(() -> bridge.mockCycleResult(""" - { - "sys": { - "available_updates": { - "foo": "bar" - } - }, - "switch:0": { - "current": 1.234, - "voltage": 231.5, - "output": false, - "apower": 789.1 - } - } - """)) // + .onBeforeControllersCallbacks(() -> { + httpTestBundle.forceNextSuccessfulResult(HttpResponse.ok(""" + { + "sys": { + "available_updates": { + "foo": "bar" + } + }, + "switch:0": { + "current": 1.234, + "voltage": 231.5, + "output": false, + "apower": 789.1 + } + } + """)); + httpTestBundle.triggerNextCycle(); + }) // .output(ACTIVE_POWER, 789) // .output(ACTIVE_POWER_L1, 789) // .output(ACTIVE_POWER_L2, null) // @@ -65,7 +71,10 @@ public void test() throws Exception { .next(new TestCase("Invalid read response") // .onBeforeControllersCallbacks(() -> assertEquals("Off|789 W", sut.debugLog())) - .onBeforeControllersCallbacks(() -> bridge.mockCycleResult("failed")) // + .onBeforeControllersCallbacks(() -> { + httpTestBundle.forceNextFailedResult(HttpError.ResponseError.notFound()); + httpTestBundle.triggerNextCycle(); + }) // .output(ACTIVE_POWER, null) // .output(ACTIVE_POWER_L1, null) // .output(ACTIVE_POWER_L2, null) // @@ -77,12 +86,22 @@ public void test() throws Exception { .next(new TestCase("Write") // .onBeforeControllersCallbacks(() -> assertEquals("Unknown|UNDEFINED", sut.debugLog())) - .onBeforeControllersCallbacks(() -> { sut.setRelay(true); - bridge.mockRequestResult("FOO-BAR"); + }) // + .also(testCase -> { + final var relayTurnedOn = httpTestBundle.expect("http://127.0.0.1/relay/0?turn=on") + .toBeCalled(); + + testCase.onBeforeControllersCallbacks(() -> { + httpTestBundle.triggerNextCycle(); + }); + testCase.onAfterWriteCallbacks(() -> { + assertTrue("Failed to turn on relay", relayTurnedOn.get()); + }); })) // .deactivate(); } + } diff --git a/io.openems.edge.timeofusetariff.api/bnd.bnd b/io.openems.edge.timeofusetariff.api/bnd.bnd index bef6d48d25c..c141ce501b6 100644 --- a/io.openems.edge.timeofusetariff.api/bnd.bnd +++ b/io.openems.edge.timeofusetariff.api/bnd.bnd @@ -5,8 +5,11 @@ Bundle-Version: 1.0.0.${tstamp} -buildpath: \ ${buildpath},\ + com.squareup.okio,\ io.openems.common,\ io.openems.edge.common,\ - + io.openems.wrapper.okhttp,\ + -testpath: \ - ${testpath} + org.jetbrains.kotlin.osgi-bundle,\ + ${testpath} \ No newline at end of file diff --git a/io.openems.edge.timeofusetariff.entsoe/src/io/openems/edge/timeofusetariff/entsoe/ExchangeRateApi.java b/io.openems.edge.timeofusetariff.api/src/io/openems/edge/timeofusetariff/api/utils/ExchangeRateApi.java similarity index 94% rename from io.openems.edge.timeofusetariff.entsoe/src/io/openems/edge/timeofusetariff/entsoe/ExchangeRateApi.java rename to io.openems.edge.timeofusetariff.api/src/io/openems/edge/timeofusetariff/api/utils/ExchangeRateApi.java index ac2a51920a7..bdb5eeb4575 100644 --- a/io.openems.edge.timeofusetariff.entsoe/src/io/openems/edge/timeofusetariff/entsoe/ExchangeRateApi.java +++ b/io.openems.edge.timeofusetariff.api/src/io/openems/edge/timeofusetariff/api/utils/ExchangeRateApi.java @@ -1,4 +1,4 @@ -package io.openems.edge.timeofusetariff.entsoe; +package io.openems.edge.timeofusetariff.api.utils; import static io.openems.common.utils.JsonUtils.getAsDouble; import static io.openems.common.utils.JsonUtils.getAsJsonObject; @@ -38,7 +38,7 @@ public class ExchangeRateApi { * @throws IOException on error. * @throws OpenemsNamedException on error */ - protected static double getExchangeRate(String accessKey, String source, Currency target) + public static double getExchangeRate(String accessKey, String source, Currency target) throws IOException, OpenemsNamedException { var request = new Request.Builder() // .url(String.format(BASE_URL, accessKey, source, target.name())) // diff --git a/io.openems.edge.timeofusetariff.entsoe/test/io/openems/edge/timeofusetariff/entsoe/ExchangeRateApiTest.java b/io.openems.edge.timeofusetariff.api/test/io/openems/edge/timeofusetariff/api/utils/ExchangeRateApiTest.java similarity index 88% rename from io.openems.edge.timeofusetariff.entsoe/test/io/openems/edge/timeofusetariff/entsoe/ExchangeRateApiTest.java rename to io.openems.edge.timeofusetariff.api/test/io/openems/edge/timeofusetariff/api/utils/ExchangeRateApiTest.java index 908bb60b00e..81657b127c0 100644 --- a/io.openems.edge.timeofusetariff.entsoe/test/io/openems/edge/timeofusetariff/entsoe/ExchangeRateApiTest.java +++ b/io.openems.edge.timeofusetariff.api/test/io/openems/edge/timeofusetariff/api/utils/ExchangeRateApiTest.java @@ -1,6 +1,6 @@ -package io.openems.edge.timeofusetariff.entsoe; +package io.openems.edge.timeofusetariff.api.utils; -import static io.openems.edge.timeofusetariff.entsoe.ExchangeRateApi.getExchangeRate; +import static io.openems.edge.timeofusetariff.api.utils.ExchangeRateApi.getExchangeRate; import static org.junit.Assert.assertEquals; import java.io.IOException; diff --git a/io.openems.edge.timeofusetariff.entsoe/src/io/openems/edge/timeofusetariff/entsoe/TouEntsoeImpl.java b/io.openems.edge.timeofusetariff.entsoe/src/io/openems/edge/timeofusetariff/entsoe/TouEntsoeImpl.java index bef7df345a7..873b6357fa7 100644 --- a/io.openems.edge.timeofusetariff.entsoe/src/io/openems/edge/timeofusetariff/entsoe/TouEntsoeImpl.java +++ b/io.openems.edge.timeofusetariff.entsoe/src/io/openems/edge/timeofusetariff/entsoe/TouEntsoeImpl.java @@ -1,8 +1,8 @@ package io.openems.edge.timeofusetariff.entsoe; import static io.openems.common.utils.StringUtils.definedOrElse; +import static io.openems.edge.timeofusetariff.api.utils.ExchangeRateApi.getExchangeRate; import static io.openems.edge.timeofusetariff.api.utils.TimeOfUseTariffUtils.generateDebugLog; -import static io.openems.edge.timeofusetariff.entsoe.ExchangeRateApi.getExchangeRate; import static io.openems.edge.timeofusetariff.entsoe.Utils.parseCurrency; import static io.openems.edge.timeofusetariff.entsoe.Utils.parsePrices; diff --git a/io.openems.edge.timeofusetariff.groupe/.classpath b/io.openems.edge.timeofusetariff.groupe/.classpath new file mode 100644 index 00000000000..bbfbdbe40e7 --- /dev/null +++ b/io.openems.edge.timeofusetariff.groupe/.classpath @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/io.openems.edge.timeofusetariff.groupe/.gitignore b/io.openems.edge.timeofusetariff.groupe/.gitignore new file mode 100644 index 00000000000..c2b941a96de --- /dev/null +++ b/io.openems.edge.timeofusetariff.groupe/.gitignore @@ -0,0 +1,2 @@ +/bin_test/ +/generated/ diff --git a/io.openems.edge.timeofusetariff.groupe/.project b/io.openems.edge.timeofusetariff.groupe/.project new file mode 100644 index 00000000000..072b481db89 --- /dev/null +++ b/io.openems.edge.timeofusetariff.groupe/.project @@ -0,0 +1,23 @@ + + + io.openems.edge.timeofusetariff.groupe + + + + + + org.eclipse.jdt.core.javabuilder + + + + + bndtools.core.bndbuilder + + + + + + org.eclipse.jdt.core.javanature + bndtools.core.bndnature + + diff --git a/io.openems.edge.timeofusetariff.groupe/.settings/org.eclipse.core.resources.prefs b/io.openems.edge.timeofusetariff.groupe/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 00000000000..99f26c0203a --- /dev/null +++ b/io.openems.edge.timeofusetariff.groupe/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/io.openems.edge.timeofusetariff.groupe/bnd.bnd b/io.openems.edge.timeofusetariff.groupe/bnd.bnd new file mode 100644 index 00000000000..858afd7f16a --- /dev/null +++ b/io.openems.edge.timeofusetariff.groupe/bnd.bnd @@ -0,0 +1,14 @@ +Bundle-Name: OpenEMS Edge Time-Of-Use Groupe-E +Bundle-Vendor: FENECON GmbH +Bundle-License: https://opensource.org/licenses/EPL-2.0 +Bundle-Version: 1.0.0.${tstamp} + +-buildpath: \ + ${buildpath},\ + io.openems.common,\ + io.openems.edge.bridge.http,\ + io.openems.edge.common,\ + io.openems.edge.timeofusetariff.api,\ + +-testpath: \ + ${testpath} \ No newline at end of file diff --git a/io.openems.edge.timeofusetariff.groupe/readme.adoc b/io.openems.edge.timeofusetariff.groupe/readme.adoc new file mode 100644 index 00000000000..2d36804c53d --- /dev/null +++ b/io.openems.edge.timeofusetariff.groupe/readme.adoc @@ -0,0 +1,9 @@ += Time-Of-Use Tariff Groupe-E + +This implementation uses the Groupe-E platform to receive day-ahead quarterly prices. + +Prices retrieved from Groupe-E are subsequently converted to the user's currency (defined in Core.Meta Component) using the Exchange Rates API. + +For detailed information about the Exchange Rates API, please refer to: https://exchangerate.host/#/docs + +https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.timeofusetariff.groupe[Source Code icon:github[]] \ No newline at end of file diff --git a/io.openems.edge.timeofusetariff.groupe/src/io/openems/edge/timeofusetariff/groupe/Config.java b/io.openems.edge.timeofusetariff.groupe/src/io/openems/edge/timeofusetariff/groupe/Config.java new file mode 100644 index 00000000000..4204fc86375 --- /dev/null +++ b/io.openems.edge.timeofusetariff.groupe/src/io/openems/edge/timeofusetariff/groupe/Config.java @@ -0,0 +1,25 @@ +package io.openems.edge.timeofusetariff.groupe; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.AttributeType; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +@ObjectClassDefinition(// + name = "Time-Of-Use Tariff GroupeE", // + description = "Time-Of-Use Tariff implementation for GroupeE.") +@interface Config { + + @AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component") + String id() default "timeOfUseTariff0"; + + @AttributeDefinition(name = "Alias", description = "Human-readable name of this Component; defaults to Component-ID") + String alias() default ""; + + @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?") + boolean enabled() default true; + + @AttributeDefinition(name = "Exchangerate.host API Access Key", description = "Access key for Exchangerate.host: Please register at https://exchangerate.host/ to get your personal access key", type = AttributeType.PASSWORD) + String exchangerateAccesskey() default ""; + + String webconsole_configurationFactory_nameHint() default "Time-Of-Use Tariff GroupeE [{id}]"; +} diff --git a/io.openems.edge.timeofusetariff.groupe/src/io/openems/edge/timeofusetariff/groupe/TimeOfUseTariffGroupe.java b/io.openems.edge.timeofusetariff.groupe/src/io/openems/edge/timeofusetariff/groupe/TimeOfUseTariffGroupe.java new file mode 100644 index 00000000000..598fa6dff58 --- /dev/null +++ b/io.openems.edge.timeofusetariff.groupe/src/io/openems/edge/timeofusetariff/groupe/TimeOfUseTariffGroupe.java @@ -0,0 +1,26 @@ +package io.openems.edge.timeofusetariff.groupe; + +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.timeofusetariff.api.TimeOfUseTariff; + +public interface TimeOfUseTariffGroupe extends TimeOfUseTariff, OpenemsComponent { + + public enum ChannelId implements io.openems.edge.common.channel.ChannelId { + HTTP_STATUS_CODE(Doc.of(OpenemsType.INTEGER)// + .text("Displays the HTTP status code"))// + ; + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } +} diff --git a/io.openems.edge.timeofusetariff.groupe/src/io/openems/edge/timeofusetariff/groupe/TimeOfUseTariffGroupeImpl.java b/io.openems.edge.timeofusetariff.groupe/src/io/openems/edge/timeofusetariff/groupe/TimeOfUseTariffGroupeImpl.java new file mode 100644 index 00000000000..b05f68bc2c2 --- /dev/null +++ b/io.openems.edge.timeofusetariff.groupe/src/io/openems/edge/timeofusetariff/groupe/TimeOfUseTariffGroupeImpl.java @@ -0,0 +1,239 @@ +package io.openems.edge.timeofusetariff.groupe; + +import static io.openems.common.utils.JsonUtils.getAsDouble; +import static io.openems.common.utils.JsonUtils.getAsString; +import static io.openems.common.utils.JsonUtils.parseToJsonArray; +import static io.openems.common.utils.StringUtils.definedOrElse; +import static io.openems.edge.timeofusetariff.api.utils.TimeOfUseTariffUtils.generateDebugLog; +import static java.util.Collections.emptyMap; + +import java.io.IOException; +import java.time.Clock; +import java.time.Duration; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.util.TreeMap; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.BiConsumer; + +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.metatype.annotations.Designate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.exceptions.OpenemsException; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.timedata.DurationUnit; +import io.openems.edge.bridge.http.api.BridgeHttp; +import io.openems.edge.bridge.http.api.BridgeHttp.Endpoint; +import io.openems.edge.bridge.http.api.BridgeHttpFactory; +import io.openems.edge.bridge.http.api.HttpError; +import io.openems.edge.bridge.http.api.HttpMethod; +import io.openems.edge.bridge.http.api.HttpResponse; +import io.openems.edge.bridge.http.time.DelayTimeProvider; +import io.openems.edge.bridge.http.time.DelayTimeProviderChain; +import io.openems.edge.common.channel.value.Value; +import io.openems.edge.common.component.AbstractOpenemsComponent; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.currency.Currency; +import io.openems.edge.common.meta.Meta; +import io.openems.edge.timeofusetariff.api.TimeOfUsePrices; +import io.openems.edge.timeofusetariff.api.TimeOfUseTariff; +import io.openems.edge.timeofusetariff.api.utils.ExchangeRateApi; + +@Designate(ocd = Config.class, factory = true) +@Component(// + name = "TimeOfUseTariff.GroupeE", // + immediate = true, // + configurationPolicy = ConfigurationPolicy.REQUIRE // +) +public class TimeOfUseTariffGroupeImpl extends AbstractOpenemsComponent + implements TimeOfUseTariff, OpenemsComponent, TimeOfUseTariffGroupe { + private static final String URL = "https://api.tariffs.groupe-e.ch/v1/tariffs?start_timestamp=%s&end_timestamp=%s"; + private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ISO_OFFSET_DATE_TIME; + private static final int INTERNAL_ERROR = -1; // parsing, handle exception... + + private final Logger log = LoggerFactory.getLogger(TimeOfUseTariffGroupeImpl.class); + private final AtomicReference prices = new AtomicReference<>(TimeOfUsePrices.EMPTY_PRICES); + private String exchangerateAccesskey = null; + + @Reference + private BridgeHttpFactory httpBridgeFactory; + private BridgeHttp httpBridge; + + @Reference + private OpenemsEdgeOem oem; + + @Reference + private Meta meta; + + @Reference + private ComponentManager componentManager; + + public TimeOfUseTariffGroupeImpl() { + super(// + OpenemsComponent.ChannelId.values(), // + TimeOfUseTariffGroupe.ChannelId.values() // + ); + } + + private final BiConsumer, Value> onCurrencyChange = (a, b) -> { + this.httpBridge = this.httpBridgeFactory.get(); + this.httpBridge.subscribeTime(new GroupeDelayTimeProvider(this.componentManager.getClock()), // + this::createGroupeEndpoint, // + this::handleEndpointResponse, // + this::handleEndpointError); + }; + + @Activate + private void activate(ComponentContext context, Config config) { + super.activate(context, config.id(), config.alias(), config.enabled()); + + if (!config.enabled()) { + return; + } + + this.exchangerateAccesskey = definedOrElse(config.exchangerateAccesskey(), this.oem.getExchangeRateAccesskey()); + if (this.exchangerateAccesskey == null) { + this.logError(this.log, "Please configure personal Access key to access Exchange rate host API"); + return; + } + + // React on updates to Currency. + this.meta.getCurrencyChannel().onChange(this.onCurrencyChange); + + this.httpBridge = this.httpBridgeFactory.get(); + this.httpBridge.subscribeTime(new GroupeDelayTimeProvider(this.componentManager.getClock()), // + this::createGroupeEndpoint, // + this::handleEndpointResponse, // + this::handleEndpointError); + } + + private Endpoint createGroupeEndpoint() { + final var now = ZonedDateTime.now().truncatedTo(ChronoUnit.DAYS); + final var startTimestamp = now.format(DATE_FORMATTER); // eg. 2024-05-22T00:00:00+02:00 + final var endTimestamp = now.plusDays(1).format(DATE_FORMATTER); + + return new Endpoint(String.format(URL, startTimestamp, endTimestamp), // + HttpMethod.GET, // + BridgeHttp.DEFAULT_CONNECT_TIMEOUT, // + BridgeHttp.DEFAULT_READ_TIMEOUT, // + null, // + emptyMap()); + } + + @Override + @Deactivate + protected void deactivate() { + super.deactivate(); + this.meta.getCurrencyChannel().removeOnChangeCallback(this.onCurrencyChange); + this.httpBridgeFactory.unget(this.httpBridge); + } + + public static class GroupeDelayTimeProvider implements DelayTimeProvider { + + private final Clock clock; + + public GroupeDelayTimeProvider(Clock clock) { + super(); + this.clock = clock; + } + + @Override + public Delay onFirstRunDelay() { + return Delay.immediate(); + } + + @Override + public Delay onErrorRunDelay(HttpError error) { + return DelayTimeProviderChain.fixedDelay(Duration.ofHours(1))// + .plusRandomDelay(60, ChronoUnit.SECONDS) // + .getDelay(); + } + + @Override + public Delay onSuccessRunDelay(HttpResponse result) { + return DelayTimeProviderChain.fixedAtEveryFull(this.clock, DurationUnit.ofDays(1)) + .plusRandomDelay(60, ChronoUnit.SECONDS) // + .getDelay(); + } + } + + private void handleEndpointResponse(HttpResponse response) throws OpenemsNamedException, IOException { + this.channel(TimeOfUseTariffGroupe.ChannelId.HTTP_STATUS_CODE).setNextValue(response.status().code()); + + final var groupeCurrency = Currency.CHF.name(); // Swiss Franc + final var globalCurrency = this.meta.getCurrency(); + final var exchangerateAccesskey = this.exchangerateAccesskey; + if (globalCurrency == Currency.UNDEFINED) { + throw new OpenemsException("Global Currency is UNDEFINED. Please configure it in Core.Meta component"); + } + + final var exchangeRate = globalCurrency.name().equals(groupeCurrency) // + ? 1. // No need to fetch exchange rate from API. + : ExchangeRateApi.getExchangeRate(exchangerateAccesskey, groupeCurrency, globalCurrency); + + // Parse the response for the prices + this.prices.set(parsePrices(response.data(), exchangeRate)); + } + + private void handleEndpointError(HttpError error) { + var httpStatusCode = INTERNAL_ERROR; + if (error instanceof HttpError.ResponseError re) { + httpStatusCode = re.status.code(); + } + + this.channel(TimeOfUseTariffGroupe.ChannelId.HTTP_STATUS_CODE).setNextValue(httpStatusCode); + this.log.error(error.getMessage(), error); + } + + @Override + public TimeOfUsePrices getPrices() { + return TimeOfUsePrices.from(ZonedDateTime.now(this.componentManager.getClock()), this.prices.get()); + } + + /** + * Parses JSON data to extract time-of-use prices and returns a + * {@link TimeOfUsePrices} object. + * + * @param jsonData the JSON data as a {@code String} containing the + * electricity price information. + * @param exchangeRate The exchange rate of user currency to EUR. + * @return a {@link TimeOfUsePrices} object containing the parsed prices mapped + * to their respective timestamps. + * @throws OpenemsNamedException if an error occurs during the parsing of the + * JSON data. + */ + public static TimeOfUsePrices parsePrices(String jsonData, double exchangeRate) throws OpenemsNamedException { + var result = new TreeMap(); + var data = parseToJsonArray(jsonData); + for (var element : data) { + var priceString = "vario_plus"; + + // Cent/kWh -> Currency/MWh + // Example: 12 Cent/kWh => 0.12 EUR/kWh * 1000 kWh/MWh = 120 EUR/MWh. + var marketPrice = getAsDouble(element, priceString) * 10 * exchangeRate; + var startTimeString = getAsString(element, "start_timestamp"); + + // Convert LocalDateTime to ZonedDateTime + var startTimeStamp = ZonedDateTime.parse(startTimeString, DateTimeFormatter.ISO_OFFSET_DATE_TIME); + + // Adding the values in the Map. + result.put(startTimeStamp, marketPrice); + } + return TimeOfUsePrices.from(result); + } + + @Override + public String debugLog() { + return generateDebugLog(this, this.meta.getCurrency()); + } +} diff --git a/io.openems.edge.timeofusetariff.groupe/test/.gitignore b/io.openems.edge.timeofusetariff.groupe/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.timeofusetariff.groupe/test/io/openems/edge/timeofusetariff/groupe/MyConfig.java b/io.openems.edge.timeofusetariff.groupe/test/io/openems/edge/timeofusetariff/groupe/MyConfig.java new file mode 100644 index 00000000000..13fa3e31c71 --- /dev/null +++ b/io.openems.edge.timeofusetariff.groupe/test/io/openems/edge/timeofusetariff/groupe/MyConfig.java @@ -0,0 +1,51 @@ +package io.openems.edge.timeofusetariff.groupe; + +import io.openems.common.test.AbstractComponentConfig; + +@SuppressWarnings("all") +public class MyConfig extends AbstractComponentConfig implements Config { + + public static class Builder { + private String id; + private String exchangerateAccesskey; + + private Builder() { + } + + public Builder setId(String id) { + this.id = id; + return this; + } + + public Builder setExchangerateAccesskey(String exchangerateAccesskey) { + this.exchangerateAccesskey = exchangerateAccesskey; + return this; + } + + public MyConfig build() { + return new MyConfig(this); + } + } + + /** + * Create a Config builder. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new Builder(); + } + + private final Builder builder; + + private MyConfig(Builder builder) { + super(Config.class, builder.id); + this.builder = builder; + } + + @Override + public String exchangerateAccesskey() { + return this.builder.exchangerateAccesskey; + } + +} \ No newline at end of file diff --git a/io.openems.edge.timeofusetariff.groupe/test/io/openems/edge/timeofusetariff/groupe/TimeOfUseTariffGroupeImplTest.java b/io.openems.edge.timeofusetariff.groupe/test/io/openems/edge/timeofusetariff/groupe/TimeOfUseTariffGroupeImplTest.java new file mode 100644 index 00000000000..8bdb01e4e1a --- /dev/null +++ b/io.openems.edge.timeofusetariff.groupe/test/io/openems/edge/timeofusetariff/groupe/TimeOfUseTariffGroupeImplTest.java @@ -0,0 +1,445 @@ +package io.openems.edge.timeofusetariff.groupe; + +import static io.openems.edge.common.currency.Currency.CHF; +import static io.openems.edge.timeofusetariff.groupe.TimeOfUseTariffGroupeImpl.parsePrices; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThrows; + +import java.time.Instant; +import java.time.ZoneOffset; + +import org.junit.Test; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.oem.DummyOpenemsEdgeOem; +import io.openems.common.test.TimeLeapClock; +import io.openems.edge.bridge.http.dummy.DummyBridgeHttpFactory; +import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.common.test.DummyComponentManager; +import io.openems.edge.common.test.DummyMeta; + +public class TimeOfUseTariffGroupeImplTest { + + private static final String CTRL_ID = "ctrl0"; + private static final double GROUPE_E_EXCHANGE_RATE = 1; + + private static final String PRICE_RESULT_STRING = """ + [ + { + "start_timestamp": "2024-05-27T10:00:00+02:00", + "end_timestamp": "2024-05-27T10:15:00+02:00", + "vario_plus": 35.14, + "vario_grid": 7.76, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T10:15:00+02:00", + "end_timestamp": "2024-05-27T10:30:00+02:00", + "vario_plus": 34.55, + "vario_grid": 7.21, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T10:30:00+02:00", + "end_timestamp": "2024-05-27T10:45:00+02:00", + "vario_plus": 34.5, + "vario_grid": 7.16, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T10:45:00+02:00", + "end_timestamp": "2024-05-27T11:00:00+02:00", + "vario_plus": 33.63, + "vario_grid": 6.36, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T11:00:00+02:00", + "end_timestamp": "2024-05-27T11:15:00+02:00", + "vario_plus": 37.13, + "vario_grid": 9.59, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T11:15:00+02:00", + "end_timestamp": "2024-05-27T11:30:00+02:00", + "vario_plus": 34.69, + "vario_grid": 7.34, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T11:30:00+02:00", + "end_timestamp": "2024-05-27T11:45:00+02:00", + "vario_plus": 32.9, + "vario_grid": 5.69, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T11:45:00+02:00", + "end_timestamp": "2024-05-27T12:00:00+02:00", + "vario_plus": 32.16, + "vario_grid": 5, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T12:00:00+02:00", + "end_timestamp": "2024-05-27T12:15:00+02:00", + "vario_plus": 31.97, + "vario_grid": 4.82, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T12:15:00+02:00", + "end_timestamp": "2024-05-27T12:30:00+02:00", + "vario_plus": 33.16, + "vario_grid": 5.93, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T12:30:00+02:00", + "end_timestamp": "2024-05-27T12:45:00+02:00", + "vario_plus": 33.58, + "vario_grid": 6.31, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T12:45:00+02:00", + "end_timestamp": "2024-05-27T13:00:00+02:00", + "vario_plus": 33.76, + "vario_grid": 6.48, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T13:00:00+02:00", + "end_timestamp": "2024-05-27T13:15:00+02:00", + "vario_plus": 32.64, + "vario_grid": 5.45, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T13:15:00+02:00", + "end_timestamp": "2024-05-27T13:30:00+02:00", + "vario_plus": 31.56, + "vario_grid": 4.45, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T13:30:00+02:00", + "end_timestamp": "2024-05-27T13:45:00+02:00", + "vario_plus": 27.05, + "vario_grid": 0.27, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T13:45:00+02:00", + "end_timestamp": "2024-05-27T14:00:00+02:00", + "vario_plus": 26.12, + "vario_grid": -0.59, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T14:00:00+02:00", + "end_timestamp": "2024-05-27T14:15:00+02:00", + "vario_plus": 30.02, + "vario_grid": 3.02, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T14:15:00+02:00", + "end_timestamp": "2024-05-27T14:30:00+02:00", + "vario_plus": 30.44, + "vario_grid": 3.41, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T14:30:00+02:00", + "end_timestamp": "2024-05-27T14:45:00+02:00", + "vario_plus": 28.78, + "vario_grid": 1.87, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T14:45:00+02:00", + "end_timestamp": "2024-05-27T15:00:00+02:00", + "vario_plus": 29.21, + "vario_grid": 2.27, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T15:00:00+02:00", + "end_timestamp": "2024-05-27T15:15:00+02:00", + "vario_plus": 28.92, + "vario_grid": 2, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T15:15:00+02:00", + "end_timestamp": "2024-05-27T15:30:00+02:00", + "vario_plus": 27.82, + "vario_grid": 0.99, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T15:30:00+02:00", + "end_timestamp": "2024-05-27T15:45:00+02:00", + "vario_plus": 28.31, + "vario_grid": 1.44, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T15:45:00+02:00", + "end_timestamp": "2024-05-27T16:00:00+02:00", + "vario_plus": 27.31, + "vario_grid": 0.51, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T16:00:00+02:00", + "end_timestamp": "2024-05-27T16:15:00+02:00", + "vario_plus": 29.52, + "vario_grid": 2.56, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T16:15:00+02:00", + "end_timestamp": "2024-05-27T16:30:00+02:00", + "vario_plus": 28.44, + "vario_grid": 1.56, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T16:30:00+02:00", + "end_timestamp": "2024-05-27T16:45:00+02:00", + "vario_plus": 30.36, + "vario_grid": 3.33, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T16:45:00+02:00", + "end_timestamp": "2024-05-27T17:00:00+02:00", + "vario_plus": 31.66, + "vario_grid": 4.54, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T17:00:00+02:00", + "end_timestamp": "2024-05-27T17:15:00+02:00", + "vario_plus": 30.53, + "vario_grid": 3.5, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T17:15:00+02:00", + "end_timestamp": "2024-05-27T17:30:00+02:00", + "vario_plus": 31.47, + "vario_grid": 4.36, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T17:30:00+02:00", + "end_timestamp": "2024-05-27T17:45:00+02:00", + "vario_plus": 32.13, + "vario_grid": 4.97, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T17:45:00+02:00", + "end_timestamp": "2024-05-27T18:00:00+02:00", + "vario_plus": 32.74, + "vario_grid": 5.54, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T18:00:00+02:00", + "end_timestamp": "2024-05-27T18:15:00+02:00", + "vario_plus": 32.98, + "vario_grid": 5.76, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T18:15:00+02:00", + "end_timestamp": "2024-05-27T18:30:00+02:00", + "vario_plus": 34.31, + "vario_grid": 6.98, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T18:30:00+02:00", + "end_timestamp": "2024-05-27T18:45:00+02:00", + "vario_plus": 35.51, + "vario_grid": 8.1, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T18:45:00+02:00", + "end_timestamp": "2024-05-27T19:00:00+02:00", + "vario_plus": 35.85, + "vario_grid": 8.42, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T19:00:00+02:00", + "end_timestamp": "2024-05-27T19:15:00+02:00", + "vario_plus": 37.84, + "vario_grid": 10.25, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T19:15:00+02:00", + "end_timestamp": "2024-05-27T19:30:00+02:00", + "vario_plus": 40.16, + "vario_grid": 12.4, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T19:30:00+02:00", + "end_timestamp": "2024-05-27T19:45:00+02:00", + "vario_plus": 42.88, + "vario_grid": 14.92, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T19:45:00+02:00", + "end_timestamp": "2024-05-27T20:00:00+02:00", + "vario_plus": 46.44, + "vario_grid": 18.21, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T20:00:00+02:00", + "end_timestamp": "2024-05-27T20:15:00+02:00", + "vario_plus": 40.79, + "vario_grid": 12.98, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T20:15:00+02:00", + "end_timestamp": "2024-05-27T20:30:00+02:00", + "vario_plus": 41.56, + "vario_grid": 13.7, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T20:30:00+02:00", + "end_timestamp": "2024-05-27T20:45:00+02:00", + "vario_plus": 41.82, + "vario_grid": 13.93, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T20:45:00+02:00", + "end_timestamp": "2024-05-27T21:00:00+02:00", + "vario_plus": 41.74, + "vario_grid": 13.86, + "dt_plus": 35.44, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T21:00:00+02:00", + "end_timestamp": "2024-05-27T21:15:00+02:00", + "vario_plus": 34.36, + "vario_grid": 11.34, + "dt_plus": 25.08, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T21:15:00+02:00", + "end_timestamp": "2024-05-27T21:30:00+02:00", + "vario_plus": 34.06, + "vario_grid": 11.06, + "dt_plus": 25.08, + "unit": "Rp./kWh" + }, + { + "start_timestamp": "2024-05-27T21:30:00+02:00", + "end_timestamp": "2024-05-27T21:45:00+02:00", + "vario_plus": 35.8, + "vario_grid": 12.67, + "dt_plus": 25.08, + "unit": "Rp./kWh" + } + ] + """; + + @Test + public void test() throws Exception { + final TimeLeapClock clock = new TimeLeapClock(Instant.parse("2020-01-01T01:00:00.00Z"), ZoneOffset.UTC); + final DummyComponentManager cm = new DummyComponentManager(clock); + var groupe = new TimeOfUseTariffGroupeImpl(); + var dummyMeta = new DummyMeta("foo0") // + .withCurrency(CHF); + new ComponentTest(groupe) // + .addReference("httpBridgeFactory", DummyBridgeHttpFactory.ofDummyBridge()) // + .addReference("meta", dummyMeta) // + .addReference("oem", new DummyOpenemsEdgeOem()) // + .addReference("componentManager", cm) // + .activate(MyConfig.create() // + .setId(CTRL_ID) // + .setExchangerateAccesskey("") // + .build()) // + ; + } + + @Test + public void nonEmptyStringTest() throws OpenemsNamedException { + // Parsing with custom data + var prices = parsePrices(PRICE_RESULT_STRING, GROUPE_E_EXCHANGE_RATE); // + + // To check if the Map is not empty + assertFalse(prices.isEmpty()); + + // To check if a value is present in map. + assertEquals(351.4, prices.getFirst(), 0.001); + } + + @Test + public void emptyStringTest() throws OpenemsNamedException { + assertThrows(OpenemsNamedException.class, () -> { + parsePrices("", GROUPE_E_EXCHANGE_RATE); + }); + } +} diff --git a/io.openems.edge.timeofusetariff.hassfurt/.classpath b/io.openems.edge.timeofusetariff.hassfurt/.classpath new file mode 100644 index 00000000000..bbfbdbe40e7 --- /dev/null +++ b/io.openems.edge.timeofusetariff.hassfurt/.classpath @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/io.openems.edge.timeofusetariff.hassfurt/.gitignore b/io.openems.edge.timeofusetariff.hassfurt/.gitignore new file mode 100644 index 00000000000..c2b941a96de --- /dev/null +++ b/io.openems.edge.timeofusetariff.hassfurt/.gitignore @@ -0,0 +1,2 @@ +/bin_test/ +/generated/ diff --git a/io.openems.edge.timeofusetariff.hassfurt/.project b/io.openems.edge.timeofusetariff.hassfurt/.project new file mode 100644 index 00000000000..b760941e03a --- /dev/null +++ b/io.openems.edge.timeofusetariff.hassfurt/.project @@ -0,0 +1,23 @@ + + + io.openems.edge.timeofusetariff.hassfurt + + + + + + org.eclipse.jdt.core.javabuilder + + + + + bndtools.core.bndbuilder + + + + + + org.eclipse.jdt.core.javanature + bndtools.core.bndnature + + diff --git a/io.openems.edge.timeofusetariff.hassfurt/.settings/org.eclipse.core.resources.prefs b/io.openems.edge.timeofusetariff.hassfurt/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 00000000000..896a9a53a53 --- /dev/null +++ b/io.openems.edge.timeofusetariff.hassfurt/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 \ No newline at end of file diff --git a/io.openems.edge.timeofusetariff.hassfurt/bnd.bnd b/io.openems.edge.timeofusetariff.hassfurt/bnd.bnd new file mode 100644 index 00000000000..8408f57218a --- /dev/null +++ b/io.openems.edge.timeofusetariff.hassfurt/bnd.bnd @@ -0,0 +1,14 @@ +Bundle-Name: OpenEMS Edge Time-Of-Use Tariff Stadtwerk Hassfurt +Bundle-Vendor: FENECON GmbH +Bundle-License: https://opensource.org/licenses/EPL-2.0 +Bundle-Version: 1.0.0.${tstamp} + +-buildpath: \ + ${buildpath},\ + io.openems.common,\ + io.openems.edge.bridge.http,\ + io.openems.edge.common,\ + io.openems.edge.timeofusetariff.api,\ + +-testpath: \ + ${testpath} \ No newline at end of file diff --git a/io.openems.edge.timeofusetariff.hassfurt/readme.adoc b/io.openems.edge.timeofusetariff.hassfurt/readme.adoc new file mode 100644 index 00000000000..92324039f18 --- /dev/null +++ b/io.openems.edge.timeofusetariff.hassfurt/readme.adoc @@ -0,0 +1,5 @@ += Time-Of-Use Tariff Stadtwerk Hassfurt + +Retrieves the hourly prices from the Stadtwerk Hassfurt API and converts them into quarterly prices. The current implementation supports both "haStrom Flex" and "haStrom Flex Pro" models provided by Stadtwerk Hassfurt. + +https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.timeofusetariff.hassfurt[Source Code icon:github[]] \ No newline at end of file diff --git a/io.openems.edge.timeofusetariff.hassfurt/src/io/openems/edge/timeofusetariff/hassfurt/Config.java b/io.openems.edge.timeofusetariff.hassfurt/src/io/openems/edge/timeofusetariff/hassfurt/Config.java new file mode 100644 index 00000000000..1875b929bd1 --- /dev/null +++ b/io.openems.edge.timeofusetariff.hassfurt/src/io/openems/edge/timeofusetariff/hassfurt/Config.java @@ -0,0 +1,24 @@ +package io.openems.edge.timeofusetariff.hassfurt; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +@ObjectClassDefinition(// + name = "Time-Of-Use Tariff Stadwerke Hassfurt", // + description = "Time-Of-Use Tariff implementation for Stadwerke Hassfurt.") +@interface Config { + + @AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component") + String id() default "timeOfUseTariff0"; + + @AttributeDefinition(name = "Alias", description = "Human-readable name of this Component; defaults to Component-ID") + String alias() default ""; + + @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?") + boolean enabled() default true; + + @AttributeDefinition(name = "Tariff Type", description = "Tariff type that the customer has subscribed to") + TariffType tariffType() default TariffType.STROM_FLEX; + + String webconsole_configurationFactory_nameHint() default "Time-Of-Use Tariff Stadwerke Hassfurt [{id}]"; +} diff --git a/io.openems.edge.timeofusetariff.hassfurt/src/io/openems/edge/timeofusetariff/hassfurt/TariffType.java b/io.openems.edge.timeofusetariff.hassfurt/src/io/openems/edge/timeofusetariff/hassfurt/TariffType.java new file mode 100644 index 00000000000..77a9e13618a --- /dev/null +++ b/io.openems.edge.timeofusetariff.hassfurt/src/io/openems/edge/timeofusetariff/hassfurt/TariffType.java @@ -0,0 +1,13 @@ +package io.openems.edge.timeofusetariff.hassfurt; + +public enum TariffType { + /** + * haStrom Flex. + */ + STROM_FLEX, // + + /** + * haStrom Flex Pro. + */ + STROM_FLEX_PRO +} \ No newline at end of file diff --git a/io.openems.edge.timeofusetariff.hassfurt/src/io/openems/edge/timeofusetariff/hassfurt/TimeOfUseTariffHassfurt.java b/io.openems.edge.timeofusetariff.hassfurt/src/io/openems/edge/timeofusetariff/hassfurt/TimeOfUseTariffHassfurt.java new file mode 100644 index 00000000000..1d154f27211 --- /dev/null +++ b/io.openems.edge.timeofusetariff.hassfurt/src/io/openems/edge/timeofusetariff/hassfurt/TimeOfUseTariffHassfurt.java @@ -0,0 +1,26 @@ +package io.openems.edge.timeofusetariff.hassfurt; + +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.timeofusetariff.api.TimeOfUseTariff; + +public interface TimeOfUseTariffHassfurt extends TimeOfUseTariff, OpenemsComponent { + + public enum ChannelId implements io.openems.edge.common.channel.ChannelId { + HTTP_STATUS_CODE(Doc.of(OpenemsType.INTEGER)// + .text("Displays the HTTP status code"))// + ; + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } +} diff --git a/io.openems.edge.timeofusetariff.hassfurt/src/io/openems/edge/timeofusetariff/hassfurt/TimeOfUseTariffHassfurtImpl.java b/io.openems.edge.timeofusetariff.hassfurt/src/io/openems/edge/timeofusetariff/hassfurt/TimeOfUseTariffHassfurtImpl.java new file mode 100644 index 00000000000..b03228a4117 --- /dev/null +++ b/io.openems.edge.timeofusetariff.hassfurt/src/io/openems/edge/timeofusetariff/hassfurt/TimeOfUseTariffHassfurtImpl.java @@ -0,0 +1,247 @@ +package io.openems.edge.timeofusetariff.hassfurt; + +import static io.openems.common.utils.JsonUtils.getAsDouble; +import static io.openems.common.utils.JsonUtils.getAsJsonArray; +import static io.openems.common.utils.JsonUtils.getAsString; +import static io.openems.common.utils.JsonUtils.parseToJsonObject; +import static io.openems.edge.timeofusetariff.api.utils.TimeOfUseTariffUtils.generateDebugLog; +import static java.util.Collections.emptyMap; + +import java.time.Clock; +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.util.TreeMap; +import java.util.concurrent.atomic.AtomicReference; + +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.metatype.annotations.Designate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.bridge.http.api.BridgeHttp; +import io.openems.edge.bridge.http.api.BridgeHttp.Endpoint; +import io.openems.edge.bridge.http.api.BridgeHttpFactory; +import io.openems.edge.bridge.http.api.HttpError; +import io.openems.edge.bridge.http.api.HttpMethod; +import io.openems.edge.bridge.http.api.HttpResponse; +import io.openems.edge.bridge.http.time.DelayTimeProvider; +import io.openems.edge.bridge.http.time.DelayTimeProviderChain; +import io.openems.edge.common.component.AbstractOpenemsComponent; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.meta.Meta; +import io.openems.edge.timeofusetariff.api.TimeOfUsePrices; +import io.openems.edge.timeofusetariff.api.TimeOfUseTariff; + +@Designate(ocd = Config.class, factory = true) +@Component(// + name = "TimeOfUseTariff.Hassfurt", // + immediate = true, // + configurationPolicy = ConfigurationPolicy.REQUIRE // +) +public class TimeOfUseTariffHassfurtImpl extends AbstractOpenemsComponent + implements TimeOfUseTariff, OpenemsComponent, TimeOfUseTariffHassfurt { + private static final String FLEX_PRO_URL = "http://eex.stwhas.de/api/spotprices/flexpro"; + private static final String FLEX_PRO_START_END_URL = FLEX_PRO_URL + "?start_date=%s&end_date=%s"; + private static final String FLEX_URL = "http://eex.stwhas.de/api/spotprices"; + private static final String FLEX_START_END_URL = FLEX_URL + "?start_date=%s&end_date=%s"; + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + private static final int API_EXECUTE_HOUR = 14; + private static final int INTERNAL_ERROR = -1; // parsing, handle exception... + + private final Logger log = LoggerFactory.getLogger(TimeOfUseTariffHassfurtImpl.class); + private final AtomicReference prices = new AtomicReference<>(TimeOfUsePrices.EMPTY_PRICES); + + @Reference + private BridgeHttpFactory httpBridgeFactory; + private BridgeHttp httpBridge; + + private Config config = null; + + @Reference + private Meta meta; + + @Reference + private ComponentManager componentManager; + + public TimeOfUseTariffHassfurtImpl() { + super(// + OpenemsComponent.ChannelId.values(), // + TimeOfUseTariffHassfurt.ChannelId.values() // + ); + } + + @Activate + private void activate(ComponentContext context, Config config) { + super.activate(context, config.id(), config.alias(), config.enabled()); + + if (!config.enabled()) { + return; + } + + this.config = config; + this.httpBridge = this.httpBridgeFactory.get(); + this.httpBridge.subscribeTime(new HassfurtDelayTimeProvider(this.componentManager.getClock()), // + this::createHassfurtEndpoint, // + this::handleEndpointResponse, // + this::handleEndpointError); + } + + private Endpoint createHassfurtEndpoint() { + + var now = ZonedDateTime.now().truncatedTo(ChronoUnit.HOURS); + var dateFormatter = DateTimeFormatter.ofPattern("yyyyMMdd"); + var startDate = now.format(dateFormatter); + var endDate = now.plusDays(1).format(dateFormatter); + + var url = switch (this.config.tariffType()) { + + case STROM_FLEX -> { + if (now.getHour() < 14) { + yield FLEX_URL; + } else { + yield String.format(FLEX_START_END_URL, startDate, endDate); + } + } + case STROM_FLEX_PRO -> { + if (now.getHour() < 14) { + yield FLEX_PRO_URL; + } else { + yield String.format(FLEX_PRO_START_END_URL, startDate, endDate); + } + } + }; + + return new Endpoint(url, // + HttpMethod.GET, // + BridgeHttp.DEFAULT_CONNECT_TIMEOUT, // + BridgeHttp.DEFAULT_READ_TIMEOUT, // + null, // + emptyMap()); + } + + @Override + @Deactivate + protected void deactivate() { + super.deactivate(); + this.httpBridgeFactory.unget(this.httpBridge); + } + + public static class HassfurtDelayTimeProvider implements DelayTimeProvider { + + private final Clock clock; + + public HassfurtDelayTimeProvider(Clock clock) { + super(); + this.clock = clock; + } + + @Override + public Delay onFirstRunDelay() { + return Delay.immediate(); + } + + @Override + public Delay onErrorRunDelay(HttpError error) { + return DelayTimeProviderChain.fixedDelay(Duration.ofHours(1))// + .plusRandomDelay(60, ChronoUnit.SECONDS) // + .getDelay(); + } + + @Override + public Delay onSuccessRunDelay(HttpResponse result) { + var now = ZonedDateTime.now(this.clock).truncatedTo(ChronoUnit.HOURS); + ZonedDateTime nextRun; + + if (now.getHour() < API_EXECUTE_HOUR) { + nextRun = now.withHour(API_EXECUTE_HOUR); + } else { + nextRun = now.plusDays(1).withHour(API_EXECUTE_HOUR); + } + + return DelayTimeProviderChain.fixedDelay(Duration.between(now, nextRun)) + .plusRandomDelay(60, ChronoUnit.SECONDS) // + .getDelay(); + } + } + + private void handleEndpointResponse(HttpResponse response) throws OpenemsNamedException { + this.channel(TimeOfUseTariffHassfurt.ChannelId.HTTP_STATUS_CODE).setNextValue(response.status().code()); + + // Parse the response for the prices + this.prices.set(parsePrices(response.data(), this.config.tariffType())); + } + + private void handleEndpointError(HttpError error) { + var httpStatusCode = INTERNAL_ERROR; + if (error instanceof HttpError.ResponseError re) { + httpStatusCode = re.status.code(); + } + + this.channel(TimeOfUseTariffHassfurt.ChannelId.HTTP_STATUS_CODE).setNextValue(httpStatusCode); + this.log.error(error.getMessage(), error); + } + + @Override + public TimeOfUsePrices getPrices() { + return TimeOfUsePrices.from(ZonedDateTime.now(this.componentManager.getClock()), this.prices.get()); + } + + /** + * Parses JSON data to extract time-of-use prices and returns a + * {@link TimeOfUsePrices} object. + * + * @param jsonData the JSON data as a {@code String} containing the + * electricity price information. + * @param tariffType the tariff type which determines the specific price field + * to be extracted from the JSON data. + * @return a {@link TimeOfUsePrices} object containing the parsed prices mapped + * to their respective timestamps. + * @throws OpenemsNamedException if an error occurs during the parsing of the + * JSON data. + */ + public static TimeOfUsePrices parsePrices(String jsonData, TariffType tariffType) throws OpenemsNamedException { + var result = new TreeMap(); + final var data = getAsJsonArray(parseToJsonObject(jsonData), "data"); + + final var priceString = switch (tariffType) { + case STROM_FLEX -> "t_price_has_incl_vat"; + case STROM_FLEX_PRO -> "t_price_has_pro_incl_vat"; + }; + for (var element : data) { + + // Cent/kWh -> Currency/MWh + // Example: 12 Cent/kWh => 0.12 EUR/kWh * 1000 kWh/MWh = 120 EUR/MWh. + final var marketPrice = getAsDouble(element, priceString) * 10; + final var startTimeString = getAsString(element, "start_timestamp"); + + // Parse the string to LocalDateTime + final var localDateTime = LocalDateTime.parse(startTimeString, FORMATTER); + + // Convert LocalDateTime to ZonedDateTime + final var startTimeStamp = localDateTime.atZone(ZoneId.systemDefault()).truncatedTo(ChronoUnit.HOURS); + + // Adding the values in the Map. + result.put(startTimeStamp, marketPrice); + result.put(startTimeStamp.plusMinutes(15), marketPrice); + result.put(startTimeStamp.plusMinutes(30), marketPrice); + result.put(startTimeStamp.plusMinutes(45), marketPrice); + } + return TimeOfUsePrices.from(result); + } + + @Override + public String debugLog() { + return generateDebugLog(this, this.meta.getCurrency()); + } +} diff --git a/io.openems.edge.timeofusetariff.hassfurt/test/.gitignore b/io.openems.edge.timeofusetariff.hassfurt/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.timeofusetariff.hassfurt/test/io/openems/edge/timeofusetariff/hassfurt/MyConfig.java b/io.openems.edge.timeofusetariff.hassfurt/test/io/openems/edge/timeofusetariff/hassfurt/MyConfig.java new file mode 100644 index 00000000000..e583ed155ad --- /dev/null +++ b/io.openems.edge.timeofusetariff.hassfurt/test/io/openems/edge/timeofusetariff/hassfurt/MyConfig.java @@ -0,0 +1,51 @@ +package io.openems.edge.timeofusetariff.hassfurt; + +import io.openems.common.test.AbstractComponentConfig; + +@SuppressWarnings("all") +public class MyConfig extends AbstractComponentConfig implements Config { + + public static class Builder { + private String id; + private TariffType tariffType; + + private Builder() { + } + + public Builder setId(String id) { + this.id = id; + return this; + } + + public Builder setTariffType(TariffType tariffType) { + this.tariffType = tariffType; + return this; + } + + public MyConfig build() { + return new MyConfig(this); + } + } + + /** + * Create a Config builder. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new Builder(); + } + + private final Builder builder; + + private MyConfig(Builder builder) { + super(Config.class, builder.id); + this.builder = builder; + } + + @Override + public TariffType tariffType() { + return this.builder.tariffType; + } + +} \ No newline at end of file diff --git a/io.openems.edge.timeofusetariff.hassfurt/test/io/openems/edge/timeofusetariff/hassfurt/TimeOfUseTariffHassfurtImplTest.java b/io.openems.edge.timeofusetariff.hassfurt/test/io/openems/edge/timeofusetariff/hassfurt/TimeOfUseTariffHassfurtImplTest.java new file mode 100644 index 00000000000..2f363b27876 --- /dev/null +++ b/io.openems.edge.timeofusetariff.hassfurt/test/io/openems/edge/timeofusetariff/hassfurt/TimeOfUseTariffHassfurtImplTest.java @@ -0,0 +1,234 @@ +package io.openems.edge.timeofusetariff.hassfurt; + +import static io.openems.edge.timeofusetariff.hassfurt.TimeOfUseTariffHassfurtImpl.parsePrices; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThrows; + +import java.time.Instant; +import java.time.ZoneOffset; + +import org.junit.Test; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.test.TimeLeapClock; +import io.openems.edge.bridge.http.dummy.DummyBridgeHttpFactory; +import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.common.test.DummyComponentManager; + +public class TimeOfUseTariffHassfurtImplTest { + + private static final String CTRL_ID = "ctrl0"; + private static final String STROM_FLEX_PRO_STRING = """ + { + "object": "list", + "tariff_info_flex_pro": { + "name": "haStrom FLEX PRO", + "minimal_energy_price": "5.95 ct/kWh", + "taxes": "5.59 ct/kWh", + "netcosts": "8.57 ct/kWh", + "margin": "2.97 ct/kWh", + "basic_charge": "210.0 EUR/year", + "vat": "19 %" + }, + "data": [ + { + "start_timestamp": "2024-05-22 00:00:00", + "end_timestamp": "2024-05-22 01:00:00", + "e_price_epex_excl_vat": 7.099, + "e_price_has_pro_incl_vat": 11.423, + "t_price_has_pro_incl_vat": 25.58, + "unit": "ct/kWh" + }, + { + "start_timestamp": "2024-05-22 01:00:00", + "end_timestamp": "2024-05-22 02:00:00", + "e_price_epex_excl_vat": 6.675, + "e_price_has_pro_incl_vat": 10.918, + "t_price_has_pro_incl_vat": 25.08, + "unit": "ct/kWh" + }, + { + "start_timestamp": "2024-05-22 02:00:00", + "end_timestamp": "2024-05-22 03:00:00", + "e_price_epex_excl_vat": 6.471, + "e_price_has_pro_incl_vat": 10.675, + "t_price_has_pro_incl_vat": 24.84, + "unit": "ct/kWh" + }, + { + "start_timestamp": "2024-05-22 03:00:00", + "end_timestamp": "2024-05-22 04:00:00", + "e_price_epex_excl_vat": 5.428, + "e_price_has_pro_incl_vat": 9.434, + "t_price_has_pro_incl_vat": 23.6, + "unit": "ct/kWh" + }, + { + "start_timestamp": "2024-05-22 04:00:00", + "end_timestamp": "2024-05-22 05:00:00", + "e_price_epex_excl_vat": 6.228, + "e_price_has_pro_incl_vat": 10.386, + "t_price_has_pro_incl_vat": 24.55, + "unit": "ct/kWh" + }, + { + "start_timestamp": "2024-05-22 05:00:00", + "end_timestamp": "2024-05-22 06:00:00", + "e_price_epex_excl_vat": 7.029, + "e_price_has_pro_incl_vat": 11.34, + "t_price_has_pro_incl_vat": 25.5, + "unit": "ct/kWh" + }, + { + "start_timestamp": "2024-05-22 06:00:00", + "end_timestamp": "2024-05-22 07:00:00", + "e_price_epex_excl_vat": 9.726, + "e_price_has_pro_incl_vat": 14.549, + "t_price_has_pro_incl_vat": 28.71, + "unit": "ct/kWh" + } + ] + } + """; + + private static final String STROM_FLEX_STRING = """ + { + "object": "list", + "tariff_info": { + "name": "haStrom flex", + "minimal_energy_price": "17.37 ct/kWh", + "maximal_energy_price": "28.5 ct/kWh", + "taxes": "5.59 ct/kWh", + "netcosts": "8.57 ct/kWh", + "margin": "2.97 ct/kWh", + "basic_charge": "210.0 EUR/year", + "vat": "19 %" + }, + "data": [ + { + "start_timestamp": "2024-05-20 00:00:00", + "end_timestamp": "2024-05-20 01:00:00", + "e_price_epex_excl_vat": 9.1, + "e_price_has_incl_vat": 17.374, + "t_price_has_incl_vat": 31.54, + "unit": "ct/kWh" + }, + { + "start_timestamp": "2024-05-20 01:00:00", + "end_timestamp": "2024-05-20 02:00:00", + "e_price_epex_excl_vat": 8.296, + "e_price_has_incl_vat": 17.374, + "t_price_has_incl_vat": 31.54, + "unit": "ct/kWh" + }, + { + "start_timestamp": "2024-05-20 02:00:00", + "end_timestamp": "2024-05-20 03:00:00", + "e_price_epex_excl_vat": 8.619, + "e_price_has_incl_vat": 17.374, + "t_price_has_incl_vat": 31.54, + "unit": "ct/kWh" + }, + { + "start_timestamp": "2024-05-20 03:00:00", + "end_timestamp": "2024-05-20 04:00:00", + "e_price_epex_excl_vat": 8.558, + "e_price_has_incl_vat": 17.374, + "t_price_has_incl_vat": 31.54, + "unit": "ct/kWh" + }, + { + "start_timestamp": "2024-05-20 04:00:00", + "end_timestamp": "2024-05-20 05:00:00", + "e_price_epex_excl_vat": 8.769, + "e_price_has_incl_vat": 17.374, + "t_price_has_incl_vat": 31.54, + "unit": "ct/kWh" + }, + { + "start_timestamp": "2024-05-20 05:00:00", + "end_timestamp": "2024-05-20 06:00:00", + "e_price_epex_excl_vat": 9.061, + "e_price_has_incl_vat": 17.374, + "t_price_has_incl_vat": 31.54, + "unit": "ct/kWh" + }, + { + "start_timestamp": "2024-05-20 06:00:00", + "end_timestamp": "2024-05-20 07:00:00", + "e_price_epex_excl_vat": 10.348, + "e_price_has_incl_vat": 17.374, + "t_price_has_incl_vat": 31.54, + "unit": "ct/kWh" + }, + { + "start_timestamp": "2024-05-20 07:00:00", + "end_timestamp": "2024-05-20 08:00:00", + "e_price_epex_excl_vat": 10.41, + "e_price_has_incl_vat": 17.374, + "t_price_has_incl_vat": 31.54, + "unit": "ct/kWh" + }, + { + "start_timestamp": "2024-05-20 08:00:00", + "end_timestamp": "2024-05-20 09:00:00", + "e_price_epex_excl_vat": 7.19, + "e_price_has_incl_vat": 17.374, + "t_price_has_incl_vat": 31.54, + "unit": "ct/kWh" + }, + { + "start_timestamp": "2024-05-20 09:00:00", + "end_timestamp": "2024-05-20 10:00:00", + "e_price_epex_excl_vat": 3.289, + "e_price_has_incl_vat": 17.374, + "t_price_has_incl_vat": 31.54, + "unit": "ct/kWh" + } + ] + } + """; + + @Test + public void test() throws Exception { + final TimeLeapClock clock = new TimeLeapClock(Instant.parse("2020-01-01T01:00:00.00Z"), ZoneOffset.UTC); + final DummyComponentManager cm = new DummyComponentManager(clock); + var hassfurt = new TimeOfUseTariffHassfurtImpl(); + new ComponentTest(hassfurt) // + .addReference("httpBridgeFactory", DummyBridgeHttpFactory.ofDummyBridge()) // + .addReference("componentManager", cm) // + .activate(MyConfig.create() // + .setId(CTRL_ID) // + .setTariffType(TariffType.STROM_FLEX) // + .build()) // + ; + } + + @Test + public void nonEmptyStringTest() throws OpenemsNamedException { + // Parsing with custom data + var prices = parsePrices(STROM_FLEX_STRING, TariffType.STROM_FLEX); // + + // To check if the Map is not empty + assertFalse(prices.isEmpty()); + + // To check if a value is present in map. + assertEquals(315.4, prices.getFirst(), 0.001); + + prices = parsePrices(STROM_FLEX_PRO_STRING, TariffType.STROM_FLEX_PRO); // + + // To check if the Map is not empty + assertFalse(prices.isEmpty()); + + // To check if a value is present in map. + assertEquals(255.8, prices.getFirst(), 0.001); + } + + @Test + public void emptyStringTest() { + assertThrows(OpenemsNamedException.class, () -> { + parsePrices("", TariffType.STROM_FLEX); + }); + } +} diff --git a/io.openems.edge.timeofusetariff.rabotcharge/src/io/openems/edge/timeofusetariff/rabotcharge/TimeOfUseTariffRabotChargeImpl.java b/io.openems.edge.timeofusetariff.rabotcharge/src/io/openems/edge/timeofusetariff/rabotcharge/TimeOfUseTariffRabotChargeImpl.java index 0156dfa039f..42d223b88b9 100644 --- a/io.openems.edge.timeofusetariff.rabotcharge/src/io/openems/edge/timeofusetariff/rabotcharge/TimeOfUseTariffRabotChargeImpl.java +++ b/io.openems.edge.timeofusetariff.rabotcharge/src/io/openems/edge/timeofusetariff/rabotcharge/TimeOfUseTariffRabotChargeImpl.java @@ -29,7 +29,9 @@ import io.openems.edge.bridge.http.api.BridgeHttp; import io.openems.edge.bridge.http.api.BridgeHttp.Endpoint; import io.openems.edge.bridge.http.api.BridgeHttpFactory; +import io.openems.edge.bridge.http.api.HttpError; import io.openems.edge.bridge.http.api.HttpMethod; +import io.openems.edge.bridge.http.api.HttpResponse; import io.openems.edge.bridge.http.time.DelayTimeProvider; import io.openems.edge.bridge.http.time.DelayTimeProviderChain; import io.openems.edge.common.component.AbstractOpenemsComponent; @@ -50,6 +52,7 @@ public class TimeOfUseTariffRabotChargeImpl extends AbstractOpenemsComponent private static final String RABOT_CHARGE_API_URL = "https://api.rabot-charge.de/api/day-ahead-prices-limited"; private static final int API_EXECUTE_HOUR = 14; + private static final int INTERNAL_ERROR = -1; // parsing, handle exception... private final Logger log = LoggerFactory.getLogger(TimeOfUseTariffRabotChargeImpl.class); private final AtomicReference prices = new AtomicReference<>(TimeOfUsePrices.EMPTY_PRICES); @@ -102,17 +105,12 @@ public RabotChargeDelayTimeProvider(Clock clock) { } @Override - public Duration nextRun(boolean firstRun, boolean lastRunSuccessful) { - if (firstRun) { - return Duration.ZERO; - } - - if (!lastRunSuccessful) { - return DelayTimeProviderChain.fixedDelay(Duration.ofHours(1))// - .plusRandomDelay(60, ChronoUnit.SECONDS) // - .getDelay(); - } + public Delay onFirstRunDelay() { + return Delay.immediate(); + } + @Override + public Delay onSuccessRunDelay(HttpResponse result) { var now = ZonedDateTime.now(this.clock).truncatedTo(ChronoUnit.HOURS); ZonedDateTime nextRun; @@ -126,6 +124,14 @@ public Duration nextRun(boolean firstRun, boolean lastRunSuccessful) { .plusRandomDelay(60, ChronoUnit.SECONDS) // .getDelay(); } + + @Override + public Delay onErrorRunDelay(HttpError error) { + return DelayTimeProviderChain.fixedDelay(Duration.ofHours(1))// + .plusRandomDelay(60, ChronoUnit.SECONDS) // + .getDelay(); + } + } private Endpoint createRabotChargeEndpoint() { @@ -151,16 +157,20 @@ private Map buildRequestHeaders() { } - private void handleEndpointResponse(String response) throws OpenemsNamedException { - // TODO - // Add response code to the channel once HttpError and HttpResponse is merged in - // develop. + private void handleEndpointResponse(HttpResponse response) throws OpenemsNamedException { + this.channel(TimeOfUseTariffRabotCharge.ChannelId.HTTP_STATUS_CODE).setNextValue(response.status().code()); // Parse the response for the prices - this.prices.set(parsePrices(response)); + this.prices.set(parsePrices(response.data())); } - private void handleEndpointError(Throwable error) { + private void handleEndpointError(HttpError error) { + var httpStatusCode = INTERNAL_ERROR; + if (error instanceof HttpError.ResponseError re) { + httpStatusCode = re.status.code(); + } + + this.channel(TimeOfUseTariffRabotCharge.ChannelId.HTTP_STATUS_CODE).setNextValue(httpStatusCode); this.log.error(error.getMessage(), error); } @@ -173,7 +183,7 @@ protected void deactivate() { @Override public TimeOfUsePrices getPrices() { - return TimeOfUsePrices.from(ZonedDateTime.now(), this.prices.get()); + return TimeOfUsePrices.from(ZonedDateTime.now(this.componentManager.getClock()), this.prices.get()); } /** diff --git a/io.openems.edge.timeofusetariff.rabotcharge/test/io/openems/edge/timeofusetariff/rabotcharge/TimeOfUseTariffRabotChargeImplTest.java b/io.openems.edge.timeofusetariff.rabotcharge/test/io/openems/edge/timeofusetariff/rabotcharge/TimeOfUseTariffRabotChargeImplTest.java index e2a60c609dd..46c41dec126 100644 --- a/io.openems.edge.timeofusetariff.rabotcharge/test/io/openems/edge/timeofusetariff/rabotcharge/TimeOfUseTariffRabotChargeImplTest.java +++ b/io.openems.edge.timeofusetariff.rabotcharge/test/io/openems/edge/timeofusetariff/rabotcharge/TimeOfUseTariffRabotChargeImplTest.java @@ -26,7 +26,7 @@ public void test() throws Exception { final DummyComponentManager cm = new DummyComponentManager(clock); var rabotCharge = new TimeOfUseTariffRabotChargeImpl(); new ComponentTest(rabotCharge) // - .addReference("httpBridgeFactory", new DummyBridgeHttpFactory()) // + .addReference("httpBridgeFactory", DummyBridgeHttpFactory.ofDummyBridge()) // .addReference("componentManager", cm) // .activate(MyConfig.create() // .setId(CTRL_ID) // diff --git a/ui/src/app/app-routing.module.ts b/ui/src/app/app-routing.module.ts index 4fb3687de15..a520f995833 100644 --- a/ui/src/app/app-routing.module.ts +++ b/ui/src/app/app-routing.module.ts @@ -106,7 +106,7 @@ const routes: Routes = [ { path: 'settings/component.install/:factoryId', component: EdgeSettingsComponentInstallComponentComponent }, { path: 'settings/component.update', component: EdgeSettingsComponentUpdateIndexComponentComponent }, { path: 'settings/component.update/:componentId', component: EdgeSettingsComponentUpdateComponentComponent }, - { path: 'settings/network', component: EdgeSettingsNetworkComponent }, + { path: 'settings/network', component: EdgeSettingsNetworkComponent, data: { navbarTitleToBeTranslated: 'Edge.Config.Index.networkConfiguration' } }, { path: 'settings/profile', component: EdgeSettingsProfileComponent }, { path: 'settings/profile/:componentId', component: AliasUpdateComponent }, { path: 'settings/systemexecute', component: EdgeSettingsSystemExecuteComponent }, diff --git a/ui/src/app/app.component.ts b/ui/src/app/app.component.ts index bcf853fe001..72d01cd471d 100644 --- a/ui/src/app/app.component.ts +++ b/ui/src/app/app.component.ts @@ -1,11 +1,11 @@ // @ts-strict-ignore import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Meta, Title } from '@angular/platform-browser'; import { NavigationEnd, Router } from '@angular/router'; import { MenuController, ModalController, Platform, ToastController } from '@ionic/angular'; import { Subject, Subscription } from 'rxjs'; import { filter, takeUntil } from 'rxjs/operators'; -import { Meta } from '@angular/platform-browser'; import { environment } from '../environments'; import { GlobalRouteChangeHandler } from './shared/service/globalRouteChangeHandler'; import { Service, UserPermission, Websocket } from './shared/shared'; @@ -38,6 +38,7 @@ export class AppComponent implements OnInit, OnDestroy { public websocket: Websocket, private globalRouteChangeHandler: GlobalRouteChangeHandler, private meta: Meta, + private title: Title, ) { service.setLang(Language.getByKey(localStorage.LANGUAGE) ?? Language.getByBrowserLang(navigator.language)); @@ -94,6 +95,8 @@ export class AppComponent implements OnInit, OnDestroy { this.checkSmartphoneResolution(false); }); }); + + this.title.setTitle(environment.edgeShortName); } private checkSmartphoneResolution(init: boolean): void { diff --git a/ui/src/app/edge/history/singlethreshold/chart.component.ts b/ui/src/app/edge/history/singlethreshold/chart.component.ts index df56ee64199..41371fa0bc4 100644 --- a/ui/src/app/edge/history/singlethreshold/chart.component.ts +++ b/ui/src/app/edge/history/singlethreshold/chart.component.ts @@ -19,6 +19,7 @@ export class SinglethresholdChartComponent extends AbstractHistoryChart implemen @Input() public period: DefaultTypes.HistoryPeriod; @Input() public componentId: string; + @Input() public inputChannelUnit: string; ngOnChanges() { this.updateChart(); @@ -230,7 +231,7 @@ export class SinglethresholdChartComponent extends AbstractHistoryChart implemen this.unit = YAxisTitle.ENERGY; options.scales[ChartAxis.LEFT]['title'].text = labelString; } else { - labelString = config.getChannel(inputChannel)['unit']; + labelString = this.inputChannelUnit; options.scales[ChartAxis.LEFT]['title'].text = labelString; } diff --git a/ui/src/app/edge/history/singlethreshold/singlethresholdchartoverview/singlethresholdchartoverview.component.html b/ui/src/app/edge/history/singlethreshold/singlethresholdchartoverview/singlethresholdchartoverview.component.html index 76ccbce5438..ebd9b564647 100644 --- a/ui/src/app/edge/history/singlethreshold/singlethresholdchartoverview/singlethresholdchartoverview.component.html +++ b/ui/src/app/edge/history/singlethreshold/singlethresholdchartoverview/singlethresholdchartoverview.component.html @@ -15,29 +15,33 @@ - - - - - - -
      - - + + + + + + + + +
      + + +
      +
      + + + + + + + + Edge.Index.Widgets.twoWayInfoGrid + + + + -
      - - - - - - - - Edge.Index.Widgets.twoWayInfoGrid - - - - - +
      - \ No newline at end of file + diff --git a/ui/src/app/edge/history/singlethreshold/singlethresholdchartoverview/singlethresholdchartoverview.component.ts b/ui/src/app/edge/history/singlethreshold/singlethresholdchartoverview/singlethresholdchartoverview.component.ts index 0c9fae32c4f..06a1d3d1f9e 100644 --- a/ui/src/app/edge/history/singlethreshold/singlethresholdchartoverview/singlethresholdchartoverview.component.ts +++ b/ui/src/app/edge/history/singlethreshold/singlethresholdchartoverview/singlethresholdchartoverview.component.ts @@ -1,7 +1,7 @@ // @ts-strict-ignore import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { Edge, EdgeConfig, Service, Utils } from '../../../../shared/shared'; +import { ChannelAddress, Edge, EdgeConfig, Service, Utils, Websocket } from '../../../../shared/shared'; @Component({ selector: SinglethresholdChartOverviewComponent.SELECTOR, @@ -10,11 +10,13 @@ import { Edge, EdgeConfig, Service, Utils } from '../../../../shared/shared'; export class SinglethresholdChartOverviewComponent implements OnInit { private static readonly SELECTOR = "channelthreshold-chart-overview"; + protected readonly spinnerid = SinglethresholdChartOverviewComponent.SELECTOR; public edge: Edge = null; public component: EdgeConfig.Component = null; public inputChannel: string; + protected inputChannelUnit: string; // reference to the Utils method to access via html public isLastElement = Utils.isLastElement; @@ -22,14 +24,25 @@ export class SinglethresholdChartOverviewComponent implements OnInit { constructor( public service: Service, private route: ActivatedRoute, + private websocket: Websocket, ) { } ngOnInit() { + this.service.startSpinner(this.spinnerid); this.service.setCurrentComponent('', this.route).then(edge => { this.service.getConfig().then(config => { this.edge = edge; this.component = config.getComponent(this.route.snapshot.params.componentId); this.inputChannel = config.getComponentProperties(this.component.id)['inputChannelAddress']; + + this.edge.getChannel(this.websocket, ChannelAddress.fromString(this.inputChannel)).then(c => { + this.inputChannelUnit = c.unit; + }).catch(e => { + console.error(e); + this.inputChannelUnit = ''; + }).finally(() => { + this.service.stopSpinner(this.spinnerid); + }); }); }); } diff --git a/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/Io_ChannelSingleThreshold.html b/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/Io_ChannelSingleThreshold.html index 4510f427b0e..4d5daaa2a78 100644 --- a/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/Io_ChannelSingleThreshold.html +++ b/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/Io_ChannelSingleThreshold.html @@ -8,7 +8,7 @@ leftColumnWidth="20"> + [value]="dependendOnValue + ' ' + (unitOfInputChannel ?? '')"> @@ -16,4 +16,4 @@ - \ No newline at end of file + 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 df989ea5c05..19869fbe442 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 @@ -3,7 +3,6 @@ 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 { Icon } from 'src/app/shared/type/widget'; - import { Controller_Io_ChannelSingleThresholdModalComponent } from './modal/modal.component'; @Component({ @@ -25,12 +24,22 @@ export class Controller_Io_ChannelSingleThresholdComponent extends AbstractFlatW public dependendOn: string; public dependendOnValue: any; public isOtherInputAddress: boolean; - public unitOfInputChannel: any; + public unitOfInputChannel: string | null = null; public outputChannelValue: number | null = null; public switchState: string; public switchValue: number | string; public switchConverter = Utils.CONVERT_WATT_TO_KILOWATT; + protected override afterIsInitialized(): void { + this.inputChannel = ChannelAddress.fromString( + this.component.properties['inputChannelAddress']); + + this.edge.getChannel(this.websocket, this.inputChannel) + .then(channel => { + this.unitOfInputChannel = channel.unit; + }); + } + protected override getChannelAddresses() { const outputChannelAddress: string | string[] = this.component.properties['outputChannelAddress']; if (typeof outputChannelAddress === 'string') { @@ -39,8 +48,6 @@ export class Controller_Io_ChannelSingleThresholdComponent extends AbstractFlatW // Takes only the first output for simplicity reasons this.outputChannel = ChannelAddress.fromString(outputChannelAddress[0]); } - this.inputChannel = ChannelAddress.fromString( - this.component.properties['inputChannelAddress']); return [ this.outputChannel, this.inputChannel, @@ -80,7 +87,6 @@ export class Controller_Io_ChannelSingleThresholdComponent extends AbstractFlatW // 'AUTOMATIC'-Mode dependend on this.dependendOnValue = currentData.allComponents[this.inputChannel.toString()]; - this.unitOfInputChannel = this.config.getChannel(this.inputChannel)['unit']; // Set dependendOn Value for different inputChannel && Set the switchConverter and switchValue switch (this.inputChannel.toString()) { @@ -176,8 +182,10 @@ export class Controller_Io_ChannelSingleThresholdComponent extends AbstractFlatW edge: this.edge, outputChannel: this.outputChannel, inputChannel: this.inputChannel, + inputChannelUnit: this.unitOfInputChannel, }, }); return await modal.present(); } } + diff --git a/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/modal/modal.component.html b/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/modal/modal.component.html index 4a0688ab835..157118d7b01 100644 --- a/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/modal/modal.component.html +++ b/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/modal/modal.component.html @@ -149,8 +149,8 @@ {{ currentData.channel[component.properties['inputChannelAddress']] }} -
      -  {{config.getChannel(inputChannel)['unit']}} +
      +  {{inputChannelUnit}}
      @@ -194,8 +194,8 @@  W -
      -  {{ config.getChannel(inputChannel)['unit'] }} +
      +  {{ inputChannelUnit }}
      @@ -296,4 +296,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/modal/modal.component.ts b/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/modal/modal.component.ts index 68a871803e4..7c5dffdbfc9 100644 --- a/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/modal/modal.component.ts +++ b/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/modal/modal.component.ts @@ -19,6 +19,7 @@ export class Controller_Io_ChannelSingleThresholdModalComponent implements OnIni @Input() public component: EdgeConfig.Component; @Input() public outputChannel: ChannelAddress | null = null; @Input() public inputChannel: ChannelAddress; + @Input() public inputChannelUnit: string | null = null; public formGroup: FormGroup; 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 0fdc12f4202..ce4fc315570 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,7 @@ // @ts-strict-ignore import { Component } from '@angular/core'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; -import { ChannelAddress, EdgeConfig } from 'src/app/shared/shared'; +import { EdgeConfig } from 'src/app/shared/shared'; import { Io_Api_DigitalInput_ModalComponent } from './modal/modal.component'; @@ -15,22 +15,11 @@ export class Io_Api_DigitalInputComponent extends AbstractFlatWidget { public ioComponents: EdgeConfig.Component[] = null; public ioComponentCount = 0; - protected override getChannelAddresses() { - const channels: ChannelAddress[] = []; + protected override afterIsInitialized(): void { this.service.getConfig().then(config => { - this.ioComponents = config.getComponentsImplementingNature("io.openems.edge.io.api.DigitalInput").filter(component => component.isEnabled); - for (const component of this.ioComponents) { - - for (const channel in component.channels) { - channels.push( - new ChannelAddress(component.id, channel), - ); - } - } this.ioComponentCount = this.ioComponents.length; }); - return channels; } async presentModal() { diff --git a/ui/src/app/edge/live/Io/Api_DigitalInput/modal/modal.component.html b/ui/src/app/edge/live/Io/Api_DigitalInput/modal/modal.component.html index a6a124c8d27..3d98e20dabb 100644 --- a/ui/src/app/edge/live/Io/Api_DigitalInput/modal/modal.component.html +++ b/ui/src/app/edge/live/Io/Api_DigitalInput/modal/modal.component.html @@ -12,30 +12,24 @@ - + - + - - - - - - - - - - + + + + +
      {{ component.alias}}{{ channelsPerComponent.componentAlias}}
      {{ channel.key }} - - - - - -
      {{ channel.id }} + + + + + +
      @@ -43,4 +37,4 @@
      -
      \ No newline at end of file + diff --git a/ui/src/app/edge/live/Io/Api_DigitalInput/modal/modal.component.ts b/ui/src/app/edge/live/Io/Api_DigitalInput/modal/modal.component.ts index 2402bb3ea24..eda63d38897 100644 --- a/ui/src/app/edge/live/Io/Api_DigitalInput/modal/modal.component.ts +++ b/ui/src/app/edge/live/Io/Api_DigitalInput/modal/modal.component.ts @@ -1,21 +1,106 @@ // @ts-strict-ignore -import { Component, Input } from '@angular/core'; -import { Edge, Service, EdgeConfig } from '../../../../../shared/shared'; +import { Component, Input, OnDestroy, OnInit } from '@angular/core'; +import { Edge, Service, EdgeConfig, Websocket, ChannelAddress, EdgePermission } from '../../../../../shared/shared'; import { ModalController } from '@ionic/angular'; +import { Channel } from 'src/app/shared/jsonrpc/response/getChannelsOfComponentResponse'; +import { ComponentJsonApiRequest } from 'src/app/shared/jsonrpc/request/componentJsonApiRequest'; +import { JsonrpcRequest, JsonrpcResponseSuccess } from 'src/app/shared/jsonrpc/base'; @Component({ selector: 'Io_Api_DigitalInputModal', templateUrl: './modal.component.html', }) -export class Io_Api_DigitalInput_ModalComponent { +export class Io_Api_DigitalInput_ModalComponent implements OnInit, OnDestroy { + private static readonly SELECTOR = "Io_Api_DigitalInput_ModalComponent"; @Input() public edge: Edge; @Input() public ioComponents: EdgeConfig.Component[]; - public config: EdgeConfig = null; + protected digitalInputChannelsPerComponent: { componentId: string, componentAlias: string, channels: Channel[] }[]; constructor( public service: Service, public modalCtrl: ModalController, + private websocket: Websocket, ) { } + + ngOnInit(): void { + this.getDigitalInputChannels().then(channelsPerComponent => { + this.digitalInputChannelsPerComponent = channelsPerComponent; + const channels = this.digitalInputChannelsPerComponent.reduce((p, c) => { + return [...p, ...c.channels.map(e => new ChannelAddress(c.componentId, e.id))]; + }, []); + this.edge.subscribeChannels(this.websocket, Io_Api_DigitalInput_ModalComponent.SELECTOR, channels); + }); + } + + ngOnDestroy(): void { + this.edge.unsubscribeChannels(this.websocket, Io_Api_DigitalInput_ModalComponent.SELECTOR); + } + + private async getDigitalInputChannels(): Promise<{ componentId: string, componentAlias: string, channels: Channel[] }[]> { + if (EdgePermission.hasChannelsInEdgeConfig(this.edge)) { + return this.ioComponents.map(e => { + return { + componentId: e.id, + componentAlias: e.alias, + channels: Object.entries(e.channels) + .filter(([key, value]) => { + if (value.accessMode !== 'RO') { + return false; + } + if (value.type !== 'BOOLEAN') { + return false; + } + if (key === '_PropertyEnabled') { + return false; + } + return true; + }) + .map(([key, value]) => { + return { id: key, ...value }; + }), + }; + }); + } + + const response = await this.edge.sendRequest(this.websocket, new ComponentJsonApiRequest({ + componentId: '_componentManager', + payload: new GetDigitalInputChannelsOfComponentsRequest({ componentIds: this.ioComponents.map(e => e.id) }), + })); + return response.result.channelsPerComponent.map(e => { + return { + componentAlias: this.ioComponents.find(c => c.id == e.componentId)?.alias ?? e.componentId, + ...e, + }; + }); + } + +} + +export class GetDigitalInputChannelsOfComponentsRequest extends JsonrpcRequest { + + private static METHOD: string = "getDigitalInputChannelsOfComponents"; + + public constructor( + public override readonly params: { + componentIds: string[], + }, + ) { + super(GetDigitalInputChannelsOfComponentsRequest.METHOD, params); + } + +} + +export class GetDigitalInputChannelsOfComponentsResponse extends JsonrpcResponseSuccess { + + public constructor( + public override readonly id: string, + public override readonly result: { + channelsPerComponent: { componentId: string, channels: Channel[] }[], + }, + ) { + super(id, result); + } + } diff --git a/ui/src/app/edge/settings/channels/channels.component.html b/ui/src/app/edge/settings/channels/channels.component.html index eca4d6c2c62..9640d5ecdb8 100644 --- a/ui/src/app/edge/settings/channels/channels.component.html +++ b/ui/src/app/edge/settings/channels/channels.component.html @@ -15,18 +15,19 @@ + [placeholder]="'CHANNELS.Component'| translate" (ionChange)="onSelectedComponentChanged($event)"> {{ entry.value.id }} ({{ entry.value.alias }}) + {{ entry.key }} @@ -51,7 +52,7 @@ - CHANNELS.SAVE CHANNELS.SAVE_DESCRIPTION @@ -62,8 +63,8 @@ - - + + @@ -71,15 +72,17 @@ - - - - CHANNELS.CHANNEL: - {{channelAddress.channelId}} - - - - + + + CHANNELS.CHANNEL: + {{channel.key}} + + + + +
      @@ -99,25 +102,27 @@ CHANNELS.VALUE - {{ currentData.channel[channelAddress.toString()] }} {{ channelConfig.unit }} + {{ currentData.channel[component.key + '/' + channel.key] }} {{ channelConfig.unit }} - + ({{ option.key }}) - (State is SET) - (State is not set) + (State is + SET) + (State is not + set) - (On) - (Off) + (On) + (Off) @@ -140,7 +145,7 @@ - + Warnung: @@ -154,9 +159,11 @@ CHANNELS.MORE_CHANNELS - - {{ entry.key }} + {{ entry.key }} + diff --git a/ui/src/app/edge/settings/channels/channels.component.ts b/ui/src/app/edge/settings/channels/channels.component.ts index 2709b475a2e..660aee32288 100644 --- a/ui/src/app/edge/settings/channels/channels.component.ts +++ b/ui/src/app/edge/settings/channels/channels.component.ts @@ -6,11 +6,10 @@ import { PersistencePriority } from 'src/app/shared/edge/edgeconfig'; import { SetChannelValueRequest } from 'src/app/shared/jsonrpc/request/setChannelValueRequest'; import { environment } from 'src/environments'; -import { ChannelAddress, Edge, EdgeConfig, Service, Websocket } from '../../../shared/shared'; - -export type ComponentChannels = { - [componentId: string]: ChannelAddress[]; -} +import { ChannelAddress, Edge, EdgeConfig, EdgePermission, Service, Websocket } from '../../../shared/shared'; +import { ComponentJsonApiRequest } from 'src/app/shared/jsonrpc/request/componentJsonApiRequest'; +import { Channel, GetChannelsOfComponentResponse } from 'src/app/shared/jsonrpc/response/getChannelsOfComponentResponse'; +import { GetChannelsOfComponentRequest } from 'src/app/shared/jsonrpc/request/getChannelsOfComponentRequest'; @Component({ selector: ChannelsComponent.SELECTOR, @@ -24,10 +23,12 @@ export class ChannelsComponent { 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(); + private persistencePriority: string = PersistencePriority.DEFAULT_GLOBAL_PRIORITY; + protected channelsPerComponent = new Map(); + + protected selectedComponentChannels = new Map>(); + // TODO should be a simple SET but equality checking in SETs is currently not changeable and therefore not very useful for objects + private subscribedChannels = new Map(); constructor( private service: Service, @@ -47,66 +48,71 @@ export class ChannelsComponent { }); this.service.getConfig().then(config => { this.config = config; + this.persistencePriority = this.config.getComponentsByFactory("Controller.Api.Backend")?.[0]?.properties['persistencePriority'] ?? PersistencePriority.DEFAULT_GLOBAL_PRIORITY; this.service.startSpinner(this.spinnerId); - this.loadSavedChannels(); + this.loadSavedChannels().then(message => { + if (message) { + this.service.toast(message, 'success'); + } + }).catch(reason => { + this.service.toast(reason, 'danger'); + }).finally(() => { + this.service.stopSpinner(this.spinnerId); + }); }); } /** - * Subscribes a channel + * Subscribes a channel. * * @param componentId the componentId * @param channelId the channelId */ - protected subscribeChannel(componentId: string, channelId: string): void { - const address = new ChannelAddress(componentId, channelId); - if (this.componentChannels[componentId]?.filter(element => element.channelId == address.channelId)?.length === 0) { - this.componentChannels[componentId].push(address); - } else { - this.componentChannels[componentId] = [address]; + protected async subscribeChannel(componentId: string, channelId: string): Promise { + const channelEntry = { + showPersistencePriority: true, + }; + let selectedChannels = this.selectedComponentChannels.get(componentId); + if (!selectedChannels) { + selectedChannels = new Map(); + this.selectedComponentChannels.set(componentId, selectedChannels); } - this.channelsToBeSubscribed.push(address); - this.componentChannelConfig.set(address.toString(), { ...this.config.getChannel(address), ...{ showPersistencePriority: false } }); - - if (this.config) { - const globalPersistencePriority = this.config.getComponentsByFactory("Controller.Api.Backend")?.[0]?.properties['persistencePriority'] ?? PersistencePriority.DEFAULT_GLOBAL_PRIORITY; + selectedChannels.set(channelId, channelEntry); - const channelConfig = this.config.getChannel(address); - if (channelConfig) { - if (channelConfig.accessMode == "WO") { - // do not subscribe Write-Only Channels - return; - } + const channelData = await this.getChannel(componentId, channelId); + channelEntry.showPersistencePriority = PersistencePriority.isLessThan(channelData.persistencePriority, this.persistencePriority); - if (PersistencePriority.isLessThan(channelConfig.persistencePriority, globalPersistencePriority)) { - this.componentChannelConfig.set(address.toString(), { ...this.config.getChannel(address), ...{ showPersistencePriority: true } }); - } + if (channelData.accessMode != 'WO') { + const channelAddress = new ChannelAddress(componentId, channelId); + this.subscribedChannels.set(channelAddress.toString(), channelAddress); + if (this.edge) { + this.edge.subscribeChannels(this.websocket, ChannelsComponent.SELECTOR, Array.from(this.subscribedChannels.values())); } } - - if (this.edge) { - this.edge.subscribeChannels(this.websocket, ChannelsComponent.SELECTOR, this.channelsToBeSubscribed); - } - this.saveChannels(); + this.saveChannelsInUrl(); } + /** * 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); + protected unsubscribeChannel(componentId: string, channelId: string): void { + const channels = this.selectedComponentChannels.get(componentId); + if (channels) { + channels.delete(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); + if (channels.size === 0) { + this.selectedComponentChannels.delete(componentId); } - }); - this.saveChannels(); + } + + const channelAddress = new ChannelAddress(componentId, channelId); + if (this.subscribedChannels.delete(channelAddress.toString())) { + this.edge.subscribeChannels(this.websocket, ChannelsComponent.SELECTOR, Array.from(this.subscribedChannels.values())); + } + + this.saveChannelsInUrl(); } protected setChannelValue(address: ChannelAddress, channelValue: any) { @@ -126,46 +132,166 @@ export class ChannelsComponent { } } - /** - * Saves Channels as queryParams in route - * and navigates to the new route - */ - private saveChannels(): void { - const data = Object.entries(this.channelsToBeSubscribed).map(([componentId, channels]) => { - return channels.toString(); - }).toString(); - this.router.navigate(['device/' + (this.edge.id) + '/settings/channels/'], { queryParams: { save: data } }); + private saveChannelsInUrl(): void { + const selectedChannels = this.getSelectedChannelStrings(); + if (selectedChannels && selectedChannels.length > 0) { + this.router.navigate(['device/' + (this.edge.id) + '/settings/channels/'], { queryParams: { save: selectedChannels.toString() } }); + } else { + this.router.navigate(['device/' + (this.edge.id) + '/settings/channels/']); + } } - /** - * Saves channels for the current edge in localstorage - */ - protected localSave() { - const dataStr = JSON.stringify(this.channelsToBeSubscribed); - localStorage.setItem(ChannelsComponent.URL_PREFIX + "-" + this.edge.id, dataStr); + protected saveChannelsInLocalStorage() { + const selectedChannels = this.getSelectedChannels(); + if (selectedChannels && selectedChannels.length > 0) { + localStorage.setItem(ChannelsComponent.URL_PREFIX + "-" + this.edge.id, JSON.stringify(selectedChannels)); + } else { + localStorage.removeItem(ChannelsComponent.URL_PREFIX + "-" + this.edge.id); + } this.service.toast("Successfully saved subscribed channels", "success"); } - protected loadSavedChannels() { - this.service.startSpinner(ChannelsComponent.SELECTOR); + private getSelectedChannelStrings(): string[] { + return this.getSelectedChannels().map(e => e.toString()); + } + + private getSelectedChannels(): ChannelAddress[] { + const channels: ChannelAddress[] = []; + for (const [componentId, value] of this.selectedComponentChannels.entries()) { + for (const [channelId] of value.entries()) { + channels.push(new ChannelAddress(componentId, channelId)); + } + } + return channels; + } + + private async loadSavedChannels(): Promise { const address = this.route.snapshot.queryParamMap.get('save'); - const 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) { - const savedData = JSON.parse(storedValue); - savedData.map(el => this.subscribeChannel(el.componentId, el.channelId)); - this.service.toast("Successfully loaded saved channels", "success"); + const channels = address.split(',')?.map(element => ChannelAddress.fromString(element)); + try { + await Promise.all(channels.map(el => this.subscribeChannel(el.componentId, el.channelId))); + return 'Successfully loaded saved channels from url'; + } catch (reason) { + throw 'Some channels may not have been loaded from url: ' + reason; + } + } + + const storedValue = localStorage.getItem(ChannelsComponent.URL_PREFIX + "-" + this.edge.id); + if (storedValue) { + const savedData: ChannelAddress[] = JSON.parse(storedValue); + try { + await Promise.all(savedData.map(el => this.subscribeChannel(el.componentId, el.channelId))); + return 'Successfully loaded saved channels from session'; + } catch (reason) { + throw 'Some channels may not have been loaded from session: ' + reason; + } } - this.service.stopSpinner(this.spinnerId); } - ionViewDidLeave() { - this.componentChannels = []; - this.channelsToBeSubscribed = []; - if (this.edge != null) { - this.edge.unsubscribeChannels(this.websocket, ChannelsComponent.SELECTOR); + protected onSelectedComponentChanged(event) { + const componentId: string = event.detail.value; + + if (!componentId || this.channelsPerComponent.has(componentId)) { + return; } + + this.loadChannelsAndStore(componentId).then(() => { + // ignore + }).catch(reason => { + this.service.toast('Unable to load channels for ' + componentId + ': ' + reason, 'danger'); + }); + } + + private getChannel(componentId: string, channelId: string): Promise { + return new Promise((resolve, reject) => { + // check if channels of component are already loaded + const componentEntry = this.channelsPerComponent.get(componentId); + if (componentEntry && !componentEntry.activeRequest) { + const channel = componentEntry.channels[channelId]; + if (channel) { + resolve(channel); + } else { + reject(channelId + ' is not defined by component ' + componentId); + } + return; + } + // get channels from edge and store + this.loadChannelsAndStore(componentId).then(channels => { + const channel = channels.channels[channelId]; + if (channel) { + resolve(channel); + } else { + reject(channelId + ' is not defined by component ' + componentId); + } + }).catch(reject); + }); + } + + private loadChannels(componentId: string): Promise { + return new Promise((resolve, reject) => { + if (EdgePermission.hasChannelsInEdgeConfig(this.edge)) { + const component = this.config.components[componentId]; + if (!component) { + reject(); + return; + } + const channels: Channel[] = []; + for (const [key, value] of Object.entries(component.channels)) { + channels.push({ + id: key, + ...value, + }); + } + resolve(channels); + return; + } + + this.edge.sendRequest(this.websocket, new ComponentJsonApiRequest({ + componentId: '_componentManager', + payload: new GetChannelsOfComponentRequest({ componentId: componentId }), + })).then((response: GetChannelsOfComponentResponse) => { + resolve(response.result.channels); + }).catch(reject); + }); + } + + private loadChannelsAndStore(componentId: string): Promise { + return new Promise((resolve, reject) => { + if (!componentId) { + reject(); + return; + } + let componentEntry: ComponentChannels; + if (!this.channelsPerComponent.has(componentId)) { + componentEntry = { channels: {} }; + this.channelsPerComponent.set(componentId, componentEntry); + } else { + componentEntry = this.channelsPerComponent.get(componentId); + } + + this.service.startSpinnerTransparentBackground(componentId); + const request = componentEntry.activeRequest ?? (componentEntry.activeRequest = this.loadChannels(componentId)); + request.then(channels => { + channels.forEach(channel => { + componentEntry.channels[channel.id] = channel; + }); + resolve(componentEntry); + }).catch(reject) + .finally(() => { + componentEntry.activeRequest = undefined; + this.service.stopSpinner(componentId); + }); + }); + } + + ionViewDidLeave() { + this.selectedComponentChannels = new Map(); + this.edge?.unsubscribeChannels(this.websocket, ChannelsComponent.SELECTOR); } } + +type ComponentChannels = { + activeRequest?: Promise, + channels: { [channelId: string]: Channel }, +}; diff --git a/ui/src/app/edge/settings/network/getNetworkConfigResponse.ts b/ui/src/app/edge/settings/network/getNetworkConfigResponse.ts index 89f462a4b75..dec96bea028 100644 --- a/ui/src/app/edge/settings/network/getNetworkConfigResponse.ts +++ b/ui/src/app/edge/settings/network/getNetworkConfigResponse.ts @@ -1,5 +1,5 @@ import { JsonrpcResponseSuccess } from "../../../shared/jsonrpc/base"; -import { NetworkInterface } from './shared'; +import { NetworkConfig } from "./shared"; /** * JSON-RPC Response to "getNetworkConfig" Request. @@ -17,7 +17,8 @@ import { NetworkInterface } from './shared'; * "linkLocalAddressing": boolean, * "gateway": string, * "dns": string, - * "addresses": IpAddress[] + * "metric": number, + * "addresses": IpAddress[], * } * } * } @@ -28,11 +29,7 @@ export class GetNetworkConfigResponse extends JsonrpcResponseSuccess { public constructor( public override readonly id: string, - public override readonly result: { - interfaces: { - [name: string]: NetworkInterface - } - }, + public override readonly result: NetworkConfig, ) { super(id, result); } diff --git a/ui/src/app/edge/settings/network/network.component.html b/ui/src/app/edge/settings/network/network.component.html index 9db3a479d78..aaae39ad4ae 100644 --- a/ui/src/app/edge/settings/network/network.component.html +++ b/ui/src/app/edge/settings/network/network.component.html @@ -2,14 +2,14 @@ - + {{ form.name === 'eth0' ? 'LAN' : form.name + ' (INTERNAL)' }} Edge.Network.advancedMode + hideOrShowFields(form)"> @@ -28,4 +28,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/settings/network/network.component.ts b/ui/src/app/edge/settings/network/network.component.ts index 6d56284c258..f738769bbcb 100644 --- a/ui/src/app/edge/settings/network/network.component.ts +++ b/ui/src/app/edge/settings/network/network.component.ts @@ -1,8 +1,6 @@ -// @ts-strict-ignore import { Component, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; -import { ActivatedRoute } from '@angular/router'; -import { FormlyFieldConfig } from '@ngx-formly/core'; +import { FormlyFieldConfig, FormlyForm } from '@ngx-formly/core'; import { TranslateService } from '@ngx-translate/core'; import { ComponentJsonApiRequest } from 'src/app/shared/jsonrpc/request/componentJsonApiRequest'; import { Role } from 'src/app/shared/type/role'; @@ -10,14 +8,7 @@ import { Edge, Service, Websocket } from '../../../shared/shared'; import { GetNetworkConfigRequest } from './getNetworkConfigRequest'; import { GetNetworkConfigResponse } from './getNetworkConfigResponse'; import { SetNetworkConfigRequest } from './setNetworkConfigRequest'; -import { IpAddress } from './shared'; - -export type InterfaceForm = { - name: string, - formGroup: FormGroup, - model: any, - fields: FormlyFieldConfig[] -}; +import { InterfaceForm, InterfaceModel, IpAddress, NetworkConfig, NetworkInterface, NetworkUtils } from './shared'; @Component({ selector: NetworkComponent.SELECTOR, @@ -25,7 +16,10 @@ export type InterfaceForm = { }) export class NetworkComponent implements OnInit { - private static readonly SELECTOR = 'network'; + private static readonly SELECTOR: string = 'network'; + private static readonly ETH_0: string = 'eth0'; + private static readonly STATIC_LABEL: string = 'static'; + private static readonly NO_LABEL: string = ''; public edge: Edge | null = null; protected forms: InterfaceForm[] = []; @@ -35,35 +29,36 @@ export class NetworkComponent implements OnInit { private translate: TranslateService, private service: Service, private websocket: Websocket, - private route: ActivatedRoute, ) { } public ngOnInit() { + this.initializeComponent(); + } - this.service.setCurrentComponent({ languageKey: 'Edge.Config.Index.networkConfiguration' }, this.route).then(edge => { - this.edge = edge; - - this.edge.sendRequest(this.websocket, - new ComponentJsonApiRequest({ componentId: '_host', payload: new GetNetworkConfigRequest() })).then(response => { - - const result = (response as GetNetworkConfigResponse).result; - for (const name of Object.keys(result.interfaces)) { - const iface = result.interfaces[name]; + private async initializeComponent() { + try { + this.edge = await this.service.getCurrentEdge(); + if (this.edge) { + const response: GetNetworkConfigResponse = await this.edge.sendRequest(this.websocket, new ComponentJsonApiRequest({ componentId: '_host', payload: new GetNetworkConfigRequest() })) as GetNetworkConfigResponse; + this.handleNetworkConfigResponse(response); + } + } catch (reason: any) { + this.service.toast(this.translate.instant('Edge.Network.errorReading') + reason?.error?.message ?? 'Unknown error', 'danger'); + } + } - if (this.edge.roleIsAtLeast(Role.ADMIN)) { - // Display all interfaces available for user with role Admin. - this.generateInterface(name, iface); - } else { - // Display only eth0 (LAN) interface for user with role less than Admin. - if (name === 'eth0') { - this.generateInterface(name, iface); - } - } - } - }).catch(reason => { - this.service.toast(this.translate.instant('Edge.Network.errorReading') + reason.error.message, 'danger'); - }); - }); + private handleNetworkConfigResponse(response: GetNetworkConfigResponse) { + const result: NetworkConfig = response.result; + if (this.edge) { + const isAdmin: boolean = this.edge.roleIsAtLeast(Role.ADMIN); + for (const name of Object.keys(result.interfaces)) { + if (isAdmin || name === NetworkComponent.ETH_0) { + // Display all interfaces available for user with role Admin. + // Display only eth0 (LAN) interface for user with role less than Admin. + this.generateInterface(name, result.interfaces[name]); + } + } + } } public submit(iface: InterfaceForm): void { @@ -73,25 +68,66 @@ export class NetworkComponent implements OnInit { } // Adds the static addresses entered in form field "Statische IP-Adressen hinzufügen" to addressJson in json format. + const addressJson: IpAddress[] = this.buildAddressJson(iface); + const request: NetworkConfig = this.buildRequest(iface, addressJson); + const interfaceName: string = iface.name === NetworkComponent.ETH_0 ? NetworkComponent.ETH_0 : iface.name; + + this.sendRequest(interfaceName, request); + } + + /** + * Builds an array of IP address objects from the provided list of addresses extracted from the interface form data. + * Any IP address entered in the array will be labeled with an empty string. + * + * Example: + * ```typescript + * + * Input: + * const addressList = ['192.168.1.50/24', '10.0.0.1/16']; + * + * Result: + * [ + * { label: '', ip: '192.168.1.50', subnetmask: '255.255.255.0' }, + * { label: '', ip: '10.0.0.1', subnetmask: '255.255.0.0' } + * ] + * ``` + * + * @param iface The {@link InterfaceForm} data containing the list of IP addresses. + * @returns An array of {@link IpAddress} objects with labels, IP addresses, and subnet masks. + */ + private buildAddressJson(iface: InterfaceForm): IpAddress[] { const addressJson: IpAddress[] = []; - // Converts ["192.168.1.50/24"] -> {label: " ''/'static' ", ip: "192.168.1.50", subnetmask: "255.255.255.0" } - // Any ip address entered in the array("Statische IP-Adressen hinzufügen") will be labeled with emty string. - for (const addr of iface.model.addressesList) { - if (!this.ipRegex.test(addr)) { - this.service.toast(this.translate.instant('Edge.Network.validAddressWarning'), 'danger'); - return; - } - const ip = addr.split('/'); - const subnetmask = this.getSubnetmaskAsString(ip[1]); + if (iface.model.addressesList) { + for (const addr of iface.model.addressesList) { + if (!this.ipRegex.test(addr)) { + this.service.toast(this.translate.instant('Edge.Network.validAddressWarning'), 'danger'); + return []; + } + const [address, subnet] = addr.split('/'); + const subnetmask = NetworkUtils.getSubnetmaskAsString(Number.parseInt(subnet)); - addressJson.push({ - label: '', //TODO with specific labels with specific systems. - address: ip[0], - subnetmask: subnetmask, - }); + addressJson.push({ + label: NetworkComponent.NO_LABEL, + address: address, + subnetmask: subnetmask, + }); + } } + return addressJson; + } + + /** + * Builds the request payload for setting network configuration based on the provided interface form data and address information. + * + * @param iface The {@link InterfaceForm} data containing the network configuration details. + * @param addressJson An array of {@link IpAddress} extracted from the form data. + * @returns The request payload object containing the network configuration for the specified interface. + */ + private buildRequest(iface: InterfaceForm, addressJson: IpAddress[]): NetworkConfig { + const request: NetworkConfig = { interfaces: {} }; + // Unset Gateway and DNS if DHCP is activated if (iface.model.dhcp) { iface.model.gateway = null; @@ -100,105 +136,103 @@ export class NetworkComponent implements OnInit { iface.model.subnetmask = null; } else { // Ip address and subnetmask entered from regular form will be labelled as 'static'. - addressJson.push({ - label: 'static', - address: iface.model.ip, - subnetmask: iface.model.subnetmask, - }); + const ip = iface.model.ip; + const subnetmask = iface.model.subnetmask; + if (ip && subnetmask) { + addressJson.push({ + label: NetworkComponent.STATIC_LABEL, + address: ip, + subnetmask: subnetmask, + }); + } } - // updates the addresses array with latest values. - iface.model.addresses = addressJson; - - const request = { - interfaces: {}, + request.interfaces[iface.name] = { + ...iface.model, + addresses: addressJson, }; - request.interfaces[iface.name] = iface.model; - const interfaceName = iface.name === 'eth0' ? 'eth0' : iface.name; - // Sends the request to edge with the configuration. - this.edge.sendRequest(this.websocket, - new ComponentJsonApiRequest({ - componentId: '_host', payload: new SetNetworkConfigRequest(request), - })).then(response => { - this.service.toast(this.translate.instant('Edge.Network.successUpdate') + '[' + interfaceName + '].', 'success'); - }).catch(reason => { - this.service.toast(this.translate.instant('Edge.Network.errorUpdating') + '[' + interfaceName + ']:' + reason.error.message, 'danger'); - }); + return request; } /** - * Hide expression dosent work with custom type 'repeat'. - * So this is the workaround for that functionality. + * Sends the request to edge with the configuration. * - * @param index index of the form from form array. - * @param value boolean value respresenting to show or hide. + * @param interfaceName The name of the interface. for eg, 'enx', 'eth0'.. + * @param request {@link SetNetworkConfigRequest} payload object containing the network configuration for the specified interface. */ - protected hideOrShowFields(index: number, value: boolean): void { - if (this.forms[index] != null) { - const addressField = this.forms[index].fields.find(element => element.key == 'addressesList'); - const linkLocalAddressField = this.forms[index].fields.find(element => element.key == 'linkLocalAddressing'); - - addressField.hide = !value; - linkLocalAddressField.hide = !value; + private async sendRequest(interfaceName: string, request: NetworkConfig): Promise { + try { + await this.edge?.sendRequest(this.websocket, new ComponentJsonApiRequest({ + componentId: '_host', + payload: new SetNetworkConfigRequest(request), + })); + this.service.toast(this.translate.instant('Edge.Network.successUpdate') + `[${interfaceName}].`, 'success'); + } catch (reason: any) { + this.service.toast(this.translate.instant('Edge.Network.errorUpdating') + `[${interfaceName}].` + reason?.error?.message ?? 'Unknown error', 'danger'); } } /** - * Converts the subnetmask to a string address. - * - * e. g. Converts "24" to "255.255.255.0" + * Hide expression dosent work with custom type 'repeat'. + * So this is the workaround for that functionality. * - * @param cidr the CIDR - * @returns the subnetmask as a string + * @param form the form fields that need to be changed. */ - protected getSubnetmaskAsString(subnetmask: number): string { - const result = []; - for (let i = 0; i < 4; i++) { - const n = Math.min(subnetmask, 8); - result.push(256 - Math.pow(2, 8 - n)); - subnetmask -= n; - } - return result.join('.'); + protected hideOrShowFields(form: FormlyForm): void { + + const addressField: FormlyFieldConfig | undefined = form.fields.find(element => element.key == 'addressesList'); + const linkLocalAddressField: FormlyFieldConfig | undefined = form.fields.find(element => element.key == 'linkLocalAddressing'); + const metric: FormlyFieldConfig | undefined = form.fields.find(element => element.key == 'metric'); + const advancedMode: boolean = form.model.advancedMode; + + if (addressField) { addressField.hide = !advancedMode; } + if (linkLocalAddressField) { linkLocalAddressField.hide = !advancedMode; } + if (metric) { metric.hide = !advancedMode; } } /** - * Generates the interface for the individual networks. + * Generates the interface configuration based on the provided name and source data. * - * @param name string to display on the individual network interface window. - * @param source contains values for individual network. + * @param name The name of the interface to be displayed. + * @param source The data containing values for the individual {@link NetworkInterface}. */ - private generateInterface(name: string, source: any): void { + private generateInterface(name: string, source: NetworkInterface): void { const addressArray: string[] = []; + const interfaceModel: InterfaceModel = { ...source }; // extracts the addresses json values to form values. if (source.addresses) { for (const address of source.addresses) { - if (address.label == 'static') { - source.ip = address.address; - source.subnetmask = address.subnetmask; + if (address.label == NetworkComponent.STATIC_LABEL) { + interfaceModel.ip = address.address; + interfaceModel.subnetmask = address.subnetmask; } else { // Converts ip:"192.168.1.50" and subnetmask:"255.255.255.0" -> ["192.168.1.50/24"] - const cidr = address.subnetmask.split('.').map(Number).map(part => (part >>> 0).toString(2)).join('').split('1').length - 1; + const cidr: number = NetworkUtils.getCidrFromSubnetmask(address.subnetmask); const ip: string = address.address.concat('/' + cidr.toString()); addressArray.push(ip); } } } + interfaceModel.addressesList = addressArray; + // Generates the form. this.forms.push({ name: name, fields: this.fillFields(addressArray), formGroup: new FormGroup({}), - model: source, + model: interfaceModel, }); } /** - * fills the fields with source. + * Fills the form fields based on the provided list of IP addresses. + * + * @param addressArray - The array of of IP addresses extracted from the form data. + * @returns An array of {@link FormlyFieldConfig} representing the filled form fields. * - * @returns FormlyFieldConfig[]. */ private fillFields(addressArray: string[]): FormlyFieldConfig[] { const fields: FormlyFieldConfig[] = [ @@ -289,6 +323,18 @@ export class NetworkComponent implements OnInit { resetOnHide: false, }, }, + { + hide: true, + key: 'metric', + type: 'input', + resetOnHide: false, + templateOptions: { + label: 'Metric', + placeholder: 'z.B. 512, 1024 ...', + }, + defaultValue: 1024, + parsers: [Number], + }, ]; return fields; diff --git a/ui/src/app/edge/settings/network/setNetworkConfigRequest.ts b/ui/src/app/edge/settings/network/setNetworkConfigRequest.ts index d42a2e71eaf..71d4d613978 100644 --- a/ui/src/app/edge/settings/network/setNetworkConfigRequest.ts +++ b/ui/src/app/edge/settings/network/setNetworkConfigRequest.ts @@ -1,5 +1,5 @@ import { JsonrpcRequest } from "../../../shared/jsonrpc/base"; -import { NetworkInterface } from './shared'; +import { NetworkConfig } from './shared'; /** * Represents a JSON-RPC Request for 'setNetworkConfig': Updates the current network configuration. @@ -27,11 +27,7 @@ export class SetNetworkConfigRequest extends JsonrpcRequest { private static METHOD: string = "setNetworkConfig"; public constructor( - public override readonly params: { - interfaces: { - [name: string]: NetworkInterface - } - }, + public override readonly params: NetworkConfig, ) { super(SetNetworkConfigRequest.METHOD, params); } diff --git a/ui/src/app/edge/settings/network/shared.ts b/ui/src/app/edge/settings/network/shared.ts index c6727c765b9..62b0949264a 100644 --- a/ui/src/app/edge/settings/network/shared.ts +++ b/ui/src/app/edge/settings/network/shared.ts @@ -1,13 +1,84 @@ +import { FormGroup } from "@angular/forms"; +import { FormlyFieldConfig } from "@ngx-formly/core"; + export type NetworkInterface = { - dhcp?: boolean, - gateway?: string, - dns?: string, - linkLocalAddressing?: boolean, - addresses?: IpAddress[] + dhcp: boolean, + gateway?: string | null, + dns?: string | null, + linkLocalAddressing?: boolean, + metric?: number, + addresses?: IpAddress[] } export type IpAddress = { - label: string, - address: string, - subnetmask: string + label: string, + address: string, + subnetmask: string +} + +export type InterfaceForm = { + name: string, + formGroup: FormGroup, + model: InterfaceModel, + fields: FormlyFieldConfig[] +}; + +export type InterfaceModel = NetworkInterface & { + addressesList?: string[], + ip?: string | null, + subnetmask?: string | null, +} + +export type NetworkConfig = { + interfaces: { + [name: string]: NetworkInterface; + } +} + +export namespace NetworkUtils { + + /** + * Converts the CIDR notation to a subnet mask string. + * For example, converts "24" to "255.255.255.0". + * + * @param cidr The CIDR notation representing the subnet mask length. + * @returns the subnetmask as a string. + * @remarks + * This method calculates the subnet mask based on the CIDR notation provided. + * It splits the CIDR into octets and determines the corresponding subnet mask values. + * The resulting subnet mask string is returned. + * + */ + export function getSubnetmaskAsString(cidr: number): string { + const octets: number[] = []; + for (let i = 0; i < 4; i++) { + const bits = Math.min(cidr, 8); + octets.push(256 - Math.pow(2, 8 - bits)); + cidr -= bits; + } + return octets.join('.'); + } + + /** + * Converts a subnet mask to its CIDR notation. + * + * @param subnetmask - The subnet mask in dotted-decimal notation (e.g., "255.255.255.0"). + * @returns The CIDR notation as a number. + * + * @example + * ```typescript + * const cidr = getCidrFromSubnetmask("255.255.255.0"); // Returns 24 + * ``` + */ + export function getCidrFromSubnetmask(subnetmask: string): number { + // Split the subnet mask into its octets, convert them to binary, and join the binary strings + const binaryString = subnetmask + .split('.') + .map(Number) + .map(part => (part >>> 0).toString(2).padStart(8, '0')) // Ensure each part is represented as 8 bits + .join(''); + + // return the number of '1's in the binary string to get the CIDR notation + return binaryString.split('1').length - 1; + } } diff --git a/ui/src/app/shared/edge/edge.ts b/ui/src/app/shared/edge/edge.ts index 6be4ef0e4da..93e0077735d 100644 --- a/ui/src/app/shared/edge/edge.ts +++ b/ui/src/app/shared/edge/edge.ts @@ -22,6 +22,12 @@ import { Role } from '../type/role'; import { SystemLog } from '../type/systemlog'; import { CurrentData } from './currentdata'; import { EdgeConfig } from './edgeconfig'; +import { ComponentJsonApiRequest } from '../jsonrpc/request/componentJsonApiRequest'; +import { GetChannelRequest } from '../jsonrpc/request/getChannelRequest'; +import { GetChannelResponse } from '../jsonrpc/response/getChannelResponse'; +import { Channel, GetChannelsOfComponentResponse } from '../jsonrpc/response/getChannelsOfComponentResponse'; +import { GetChannelsOfComponentRequest } from '../jsonrpc/request/getChannelsOfComponentRequest'; +import { EdgePermission } from '../shared'; export class Edge { @@ -65,6 +71,63 @@ export class Edge { return this.config; } + /** + * Gets a channel either from {@link EdgeConfig edgeconfig} or requests it from the edge. + * + * @param websocket the websocket to send a request if the + * channel is not included in the edgeconfig + * @param channel the address of the channel to get + * @returns a promise of the found channel + */ + public async getChannel(websocket: Websocket, channel: ChannelAddress): Promise { + if (EdgePermission.hasChannelsInEdgeConfig(this)) { + const config = await this.getConfig(websocket); + const foundChannel = config.value.getChannel(channel); + if (!foundChannel) { + throw new Error("Channel not found: " + channel); + } + return { id: channel.channelId, ...foundChannel }; + } + + const response = await this.sendRequest(websocket, new ComponentJsonApiRequest({ + componentId: '_componentManager', + payload: new GetChannelRequest({ + componentId: channel.componentId, + channelId: channel.channelId, + }), + })); + + return response.result.channel; + } + + /** + * Gets all channels of the component with the provided component id. + * + * @param websocket the websocket to send a request if the + * channels are not included in the edgeconfig + * @param componentId the id of the component + * @returns a promise with the reuslt channels + */ + public async getChannels(websocket: Websocket, componentId: string): Promise { + if (EdgePermission.hasChannelsInEdgeConfig(this)) { + const config = await this.getConfig(websocket); + const component = config.value.components[componentId]; + if (!component) { + throw new Error('Component not found'); + } + return Object.entries(component.channels).reduce((p, c) => { + return [...p, { id: c[0], ...c[1] }]; + }, []); + } + + const response = await this.sendRequest(websocket, new ComponentJsonApiRequest({ + componentId: '_componentManager', + payload: new GetChannelsOfComponentRequest({ componentId: componentId }), + })); + + return response.result.channels; + } + /** * Called by Service, when this Edge is set as currentEdge. */ @@ -278,7 +341,7 @@ export class Edge { * @param request the JSON-RPC Request * @param responseCallback the JSON-RPC Response callback */ - public sendRequest(ws: Websocket, request: JsonrpcRequest): Promise { + public sendRequest(ws: Websocket, request: JsonrpcRequest): Promise { const wrap = new EdgeRpcRequest({ edgeId: this.id, payload: request }); return new Promise((resolve, reject) => { ws.sendRequest(wrap).then(response => { diff --git a/ui/src/app/shared/edge/edgeconfig.ts b/ui/src/app/shared/edge/edgeconfig.ts index ebeec7e0231..47b529147d6 100644 --- a/ui/src/app/shared/edge/edgeconfig.ts +++ b/ui/src/app/shared/edge/edgeconfig.ts @@ -535,7 +535,7 @@ export class EdgeConfig { /** * Lists all active Components, grouped by category. */ - public listActiveComponents(ignoreComponentIds: string[]): CategorizedComponents[] { + public listActiveComponents(ignoreComponentIds: string[] = []): CategorizedComponents[] { const allComponents = []; const factories = this.listAvailableFactories(); for (const entry of factories) { @@ -659,6 +659,8 @@ export module EdgeConfig { public readonly category: "OPENEMS_TYPE" | "ENUM" | "STATE"; public readonly level: "INFO" | "OK" | "WARNING" | "FAULT"; public readonly persistencePriority: PersistencePriority; + public readonly text: string; + public readonly options?: { [key: string]: number }; } export class Component { @@ -669,7 +671,7 @@ export module EdgeConfig { constructor( public readonly factoryId: string = "", public readonly properties: { [key: string]: any } = {}, - public readonly channels: { [channelId: string]: ComponentChannel } = {}, + public readonly channels?: { [channelId: string]: ComponentChannel }, ) { } } diff --git a/ui/src/app/shared/jsonrpc/request/getChannelRequest.ts b/ui/src/app/shared/jsonrpc/request/getChannelRequest.ts new file mode 100644 index 00000000000..0bf21ac30df --- /dev/null +++ b/ui/src/app/shared/jsonrpc/request/getChannelRequest.ts @@ -0,0 +1,16 @@ +import { JsonrpcRequest } from "../base"; + +export class GetChannelRequest extends JsonrpcRequest { + + private static METHOD: string = "getChannel"; + + public constructor( + public override readonly params: { + componentId: string, + channelId: string, + }, + ) { + super(GetChannelRequest.METHOD, params); + } + +} diff --git a/ui/src/app/shared/jsonrpc/request/getChannelsOfComponentRequest.ts b/ui/src/app/shared/jsonrpc/request/getChannelsOfComponentRequest.ts new file mode 100644 index 00000000000..9b159c5ed21 --- /dev/null +++ b/ui/src/app/shared/jsonrpc/request/getChannelsOfComponentRequest.ts @@ -0,0 +1,15 @@ +import { JsonrpcRequest } from "../base"; + +export class GetChannelsOfComponentRequest extends JsonrpcRequest { + + private static METHOD: string = "getChannelsOfComponent"; + + public constructor( + public override readonly params: { + componentId: string, + }, + ) { + super(GetChannelsOfComponentRequest.METHOD, params); + } + +} diff --git a/ui/src/app/shared/jsonrpc/request/getStateChannelsOfComponentRequest.ts b/ui/src/app/shared/jsonrpc/request/getStateChannelsOfComponentRequest.ts new file mode 100644 index 00000000000..3ea35de17eb --- /dev/null +++ b/ui/src/app/shared/jsonrpc/request/getStateChannelsOfComponentRequest.ts @@ -0,0 +1,15 @@ +import { JsonrpcRequest } from "../base"; + +export class GetStateChannelsOfComponentRequest extends JsonrpcRequest { + + private static METHOD: string = "getStateChannelsOfComponent"; + + public constructor( + public override readonly params: { + componentId: string, + }, + ) { + super(GetStateChannelsOfComponentRequest.METHOD, params); + } + +} diff --git a/ui/src/app/shared/jsonrpc/response/getChannelResponse.ts b/ui/src/app/shared/jsonrpc/response/getChannelResponse.ts new file mode 100644 index 00000000000..f1382b8161d --- /dev/null +++ b/ui/src/app/shared/jsonrpc/response/getChannelResponse.ts @@ -0,0 +1,15 @@ +import { JsonrpcResponseSuccess } from "../base"; +import { Channel } from "./getChannelsOfComponentResponse"; + +export class GetChannelResponse extends JsonrpcResponseSuccess { + + public constructor( + public override readonly id: string, + public override readonly result: { + channel: Channel, + }, + ) { + super(id, result); + } + +} diff --git a/ui/src/app/shared/jsonrpc/response/getChannelsOfComponentResponse.ts b/ui/src/app/shared/jsonrpc/response/getChannelsOfComponentResponse.ts new file mode 100644 index 00000000000..75ce015d155 --- /dev/null +++ b/ui/src/app/shared/jsonrpc/response/getChannelsOfComponentResponse.ts @@ -0,0 +1,30 @@ +import { EdgeConfig } from "../../edge/edgeconfig"; +import { JsonrpcResponseSuccess } from "../base"; + +export type Channel = { id: string } & EdgeConfig.ComponentChannel; + +/** + * Represents a JSON-RPC Response for a {@link GetChannelsOfComponentResponse}. + * + *
      + * {
      + *   "jsonrpc": "2.0",
      + *   "id": UUID,
      + *   "result": {
      + *     "channels": Channel[]
      + *   }
      + * }
      + * 
      + */ +export class GetChannelsOfComponentResponse extends JsonrpcResponseSuccess { + + public constructor( + public override readonly id: string, + public override readonly result: { + channels: Channel[], + }, + ) { + super(id, result); + } + +} diff --git a/ui/src/app/shared/service/websocket.ts b/ui/src/app/shared/service/websocket.ts index 429879edf00..a6295c1dbb9 100644 --- a/ui/src/app/shared/service/websocket.ts +++ b/ui/src/app/shared/service/websocket.ts @@ -168,7 +168,7 @@ export class Websocket implements WebsocketInterface { this.status = 'online'; // received login token -> save in cookie - this.cookieService.set('token', authenticateResponse.token, { expires: 365, path: '/', sameSite: 'Strict' }); + this.cookieService.set('token', authenticateResponse.token, { expires: 365, path: '/', sameSite: 'Strict', secure: location.protocol === 'https:' }); this.service.currentUser = authenticateResponse.user; diff --git a/ui/src/app/shared/shared.ts b/ui/src/app/shared/shared.ts index 3d6b661fa1f..48d7fa729f0 100644 --- a/ui/src/app/shared/shared.ts +++ b/ui/src/app/shared/shared.ts @@ -56,6 +56,20 @@ export class EdgePermission { return arr; }, []); } + + /** + * Determines if the edge has its channels in the edgeconfig + * or if they should be obtained with a separate request. + * + * The reason this was introduced is to reduce the size of the EdgeConfig + * and therefore improve performance in network, backend, ui, edge. + * + * @returns true if the channels are included in the edgeconfig + */ + public static hasChannelsInEdgeConfig(edge: Edge): boolean { + return !edge.isVersionAtLeast('2024.6.1'); + } + } export class UserPermission { diff --git a/ui/src/app/shared/status/single/status.component.html b/ui/src/app/shared/status/single/status.component.html index 41acd8689de..296f7dda136 100644 --- a/ui/src/app/shared/status/single/status.component.html +++ b/ui/src/app/shared/status/single/status.component.html @@ -55,10 +55,9 @@

      {{ item.alias }} *ngIf="address.componentId === item.id && address.channelId !== 'State'"> - + + [ngSwitch]="channels[address.componentId][address.channelId].level"> General.info  @@ -70,24 +69,13 @@

      {{ item.alias }} General.fault  - {{ item.channels[address.channelId]['text'] }} - - - - - General.info  - - - General.warning  - - - General.fault  - - - {{ address.channelId.toString() }} + + {{ channels[address.componentId][address.channelId].text }} + + + {{ address.channelId.toString() }} + @@ -119,4 +107,4 @@

      {{ item.alias }} - \ No newline at end of file + diff --git a/ui/src/app/shared/status/single/status.component.spec.ts b/ui/src/app/shared/status/single/status.component.spec.ts index cee24623420..7499acb1944 100644 --- a/ui/src/app/shared/status/single/status.component.spec.ts +++ b/ui/src/app/shared/status/single/status.component.spec.ts @@ -2,11 +2,11 @@ import { TestBed } from "@angular/core/testing"; import { ModalController } from "@ionic/angular"; import { PersistencePriority } from "../../edge/edgeconfig"; -import { DummyService } from "../../service/test/dummyservice"; import { DummyWebsocket } from "../../service/test/dummywebsocket"; -import { EdgeConfig, Service, Websocket } from "../../shared"; +import { ChannelAddress, Edge, EdgeConfig, Service, Websocket } from "../../shared"; import { DummyModalController } from "../../test/DummyModalController"; import { StatusSingleComponent } from "./status.component"; +import { BehaviorSubject } from "rxjs"; describe('StatusComponent', () => { const testComponent = new EdgeConfig.Component("test", {}, { @@ -17,9 +17,15 @@ describe('StatusComponent', () => { unit: "W", level: "OK", persistencePriority: PersistencePriority.HIGH, + text: "", }, }); + testComponent.id = 'test0'; + let statusComponent: StatusSingleComponent; + const serviceSpy = jasmine.createSpyObj('Service', ['getConfig'], ['currentEdge']); + const edgeSpy = jasmine.createSpyObj('Edge', ['subscribeChannels', 'isVersionAtLeast', 'unsubscribeChannels']); + const edgeConfigSpy = jasmine.createSpyObj('EdgeConfig', ['listActiveComponents'], ['components']); // initialize variables only in beforeEach, beforeAll beforeEach((() => { TestBed.configureTestingModule({ @@ -27,19 +33,40 @@ describe('StatusComponent', () => { providers: [ StatusSingleComponent, { provide: ModalController, useClass: DummyModalController }, - { provide: Service, useClass: DummyService }, + { provide: Service, useValue: serviceSpy }, { provide: Websocket, useClass: DummyWebsocket }, + { provide: Edge, useValue: edgeSpy }, + { provide: EdgeConfig, useValue: edgeConfigSpy }, ], }); + const valueEdgeSpy = TestBed.inject(Edge) as jasmine.SpyObj; + valueEdgeSpy.isVersionAtLeast.and.returnValue(false); // check should be false then + valueEdgeSpy.unsubscribeChannels.and.callThrough(); + + const valueServiceSpy = TestBed.inject(Service) as jasmine.SpyObj; + spyPropertyGetter(valueServiceSpy, 'currentEdge').and.returnValue(new BehaviorSubject(TestBed.inject(Edge))); + + const valueEdgeConfigSpy = TestBed.inject(EdgeConfig) as jasmine.SpyObj; + valueEdgeConfigSpy.listActiveComponents.and.returnValue([{ category: { icon: '', title: 'title' }, components: [testComponent] }]); + spyPropertyGetter(valueEdgeConfigSpy, 'components').and.returnValue({ [testComponent.id]: testComponent }); + valueServiceSpy.getConfig.and.resolveTo(TestBed.inject(EdgeConfig)); + statusComponent = TestBed.inject(StatusSingleComponent); })); - it('Test add Channels for subscription', () => { - statusComponent.ngOnInit(); - statusComponent.subscribeInfoChannels(testComponent); - expect(statusComponent.subscribedInfoChannels.length).toBe(1); - statusComponent.subscribedInfoChannels.forEach((channelAddress) => { - expect(channelAddress.channelId).toBe('testChannel'); - }); + it('Test add Channels for subscription', async () => { + await statusComponent.ngOnInit(); + await statusComponent.subscribeInfoChannels(testComponent); + expect(statusComponent.subscribedInfoChannels).toHaveSize(2); + expect(statusComponent.subscribedInfoChannels).toContain(new ChannelAddress(testComponent.id, 'State')); + expect(statusComponent.subscribedInfoChannels).toContain(new ChannelAddress(testComponent.id, 'testChannel')); }); }); + +// TODO should be some common method +function spyPropertyGetter( + spyObj: jasmine.SpyObj, + propName: K, +): jasmine.Spy<() => T[K]> { + return Object.getOwnPropertyDescriptor(spyObj, propName)?.get as jasmine.Spy<() => T[K]>; +} diff --git a/ui/src/app/shared/status/single/status.component.ts b/ui/src/app/shared/status/single/status.component.ts index bcc032a56ae..c1d8c019409 100644 --- a/ui/src/app/shared/status/single/status.component.ts +++ b/ui/src/app/shared/status/single/status.component.ts @@ -3,8 +3,11 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; import { ModalController } from '@ionic/angular'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; -import { ChannelAddress, Edge, Service, Websocket } from '../../../shared/shared'; +import { ChannelAddress, Edge, EdgePermission, Service, Websocket } from '../../../shared/shared'; import { CategorizedComponents, EdgeConfig } from '../../edge/edgeconfig'; +import { ComponentJsonApiRequest } from '../../jsonrpc/request/componentJsonApiRequest'; +import { GetStateChannelsOfComponentRequest } from '../../jsonrpc/request/getStateChannelsOfComponentRequest'; +import { GetChannelsOfComponentResponse } from '../../jsonrpc/response/getChannelsOfComponentResponse'; @Component({ selector: StatusSingleComponent.SELECTOR, @@ -14,9 +17,10 @@ export class StatusSingleComponent implements OnInit, OnDestroy { private stopOnDestroy: Subject = new Subject(); - public edge: Edge; + public edge?: Edge; public config: EdgeConfig; public components: CategorizedComponents[]; + protected channels: { [componentId: string]: { [channelId: string]: { text: string, level: string } } } = {}; public subscribedInfoChannels: ChannelAddress[] = []; public onInfoChannels: ChannelAddress[] = []; @@ -28,41 +32,38 @@ export class StatusSingleComponent implements OnInit, OnDestroy { private websocket: Websocket, ) { } - ngOnInit() { - this.service.getConfig().then(config => { - this.config = config; - const categorizedComponentIds: string[] = []; - this.components = config.listActiveComponents(categorizedComponentIds); - this.components.forEach(categorizedComponent => { - categorizedComponent.components.forEach(component => { - // sets all arrow buttons to standard position (folded) - component['showProperties'] = false; - this.subscribedInfoChannels.push( - new ChannelAddress(component.id, 'State'), - ); - }); - }); - //need to subscribe on currentedge because component is opened by app.component - this.service.currentEdge.pipe(takeUntil(this.stopOnDestroy)).subscribe(edge => { - this.edge = edge; - edge.subscribeChannels(this.websocket, StatusSingleComponent.SELECTOR, this.subscribedInfoChannels); + async ngOnInit() { + this.config = await this.service.getConfig(); + this.components = this.config.listActiveComponents(); + this.components.forEach(categorizedComponent => { + categorizedComponent.components.forEach(component => { + // sets all arrow buttons to standard position (folded) + component['showProperties'] = false; + this.subscribedInfoChannels.push( + new ChannelAddress(component.id, 'State'), + ); }); }); + //need to subscribe on currentedge because component is opened by app.component + this.service.currentEdge.pipe(takeUntil(this.stopOnDestroy)).subscribe(edge => { + this.edge = edge; + edge.subscribeChannels(this.websocket, StatusSingleComponent.SELECTOR, this.subscribedInfoChannels); + }); } - public subscribeInfoChannels(component: EdgeConfig.Component) { - Object.keys(component.channels).forEach(channel => { - if (component.channels[channel]['level']) { - this.subscribedInfoChannels.push(new ChannelAddress(component.id, channel)); - this.onInfoChannels.push(new ChannelAddress(component.id, channel)); - } - }); - if (this.edge) { - this.edge.subscribeChannels(this.websocket, StatusSingleComponent.SELECTOR, this.subscribedInfoChannels); + public async subscribeInfoChannels(component: EdgeConfig.Component) { + const channels = await this.getStateChannels(component.id); + for (const key of Object.keys(channels)) { + const channelAddress = new ChannelAddress(component.id, key); + this.subscribedInfoChannels.push(channelAddress); + this.onInfoChannels.push(channelAddress); } + this.channels[component.id] = channels; + this.edge?.subscribeChannels(this.websocket, StatusSingleComponent.SELECTOR, this.subscribedInfoChannels); } public unsubscribeInfoChannels(component: EdgeConfig.Component) { + delete this.channels[component.id]; //removes unsubscribed elements from subscribedInfoChannels array this.onInfoChannels.forEach(onInfoChannel => { this.subscribedInfoChannels.forEach((subChannel, index) => { @@ -73,12 +74,35 @@ export class StatusSingleComponent implements OnInit, OnDestroy { }); //clear onInfoChannels Array this.onInfoChannels = this.onInfoChannels.filter((channel) => channel.componentId != component.id); - if (this.edge) { - this.edge.subscribeChannels(this.websocket, StatusSingleComponent.SELECTOR, this.subscribedInfoChannels); - } + this.edge?.subscribeChannels(this.websocket, StatusSingleComponent.SELECTOR, this.subscribedInfoChannels); + } + + private getStateChannels(componentId: string): Promise { + return new Promise((resolve, reject) => { + if (EdgePermission.hasChannelsInEdgeConfig(this.edge)) { + const channels: typeof this.channels['componentId'] = {}; + for (const [key, value] of Object.entries(this.config.components[componentId].channels)) { + channels[key] = { text: value.text, level: value.level }; + } + resolve(channels); + return; + } + + this.edge.sendRequest(this.websocket, new ComponentJsonApiRequest({ + componentId: '_componentManager', + payload: new GetStateChannelsOfComponentRequest({ componentId: componentId }), + })).then((response: GetChannelsOfComponentResponse) => { + const channels: typeof this.channels['componentId'] = {}; + for (const item of response.result.channels) { + channels[item.id] = { text: item.text, level: item.level }; + } + resolve(channels); + }).catch(reject); + }); } ngOnDestroy() { + this.edge?.unsubscribeChannels(this.websocket, StatusSingleComponent.SELECTOR); this.stopOnDestroy.next(); this.stopOnDestroy.complete(); } diff --git a/ui/src/app/user/user.component.html b/ui/src/app/user/user.component.html index d0999b213d9..1f3f7407448 100644 --- a/ui/src/app/user/user.component.html +++ b/ui/src/app/user/user.component.html @@ -62,8 +62,13 @@ - - Register.Form.contactDetails + + + Register.Form.contactDetails + + + (Register.Form.PRIVATE) + @@ -86,6 +91,22 @@ + + + + + + + Register.Form.contactDetails + + (Register.Form.company) + + + + + + diff --git a/ui/src/app/user/user.component.ts b/ui/src/app/user/user.component.ts index 4be869cd4ea..9a5eeb23737 100644 --- a/ui/src/app/user/user.component.ts +++ b/ui/src/app/user/user.component.ts @@ -5,6 +5,7 @@ import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { Changelog } from 'src/app/changelog/view/component/changelog.constants'; +import { FormlyFieldConfig } from '@ngx-formly/core'; import { environment } from '../../environments'; import { GetUserInformationRequest } from '../shared/jsonrpc/request/getUserInformationRequest'; import { SetUserInformationRequest } from '../shared/jsonrpc/request/setUserInformationRequest'; @@ -13,12 +14,12 @@ import { GetUserInformationResponse } from '../shared/jsonrpc/response/getUserIn import { Service, Websocket } from '../shared/shared'; import { COUNTRY_OPTIONS } from '../shared/type/country'; import { Language } from '../shared/type/language'; -import { FormlyFieldConfig } from '@ngx-formly/core'; + +type CompanyUserInformation = UserInformation & { companyName: string }; type UserInformation = { firstname: string, lastname: string, - companyname?: string, email: string, phone: string, street: string, @@ -26,19 +27,36 @@ type UserInformation = { city: string, country: string } + @Component({ templateUrl: './user.component.html', }) export class UserComponent implements OnInit { - public environment = environment; - public uiVersion = Changelog.UI_VERSION; - - public readonly languages: Language[] = Language.ALL; - public currentLanguage: Language; - public isEditModeDisabled: boolean = true; - public form: { formGroup: FormGroup, model: UserInformation }; - public showInformation: boolean = false; + protected readonly environment = environment; + protected readonly uiVersion = Changelog.UI_VERSION; + protected readonly languages: Language[] = Language.ALL; + protected currentLanguage: Language; + protected isEditModeDisabled: boolean = true; + protected form: { formGroup: FormGroup, model: UserInformation | CompanyUserInformation }; + protected showInformation: boolean = false; + protected userInformationFields: FormlyFieldConfig[] = [{ + key: "firstname", + type: "input", + props: { + label: this.translate.instant("Register.Form.firstname"), + disabled: true, + }, + }, + { + key: "lastname", + type: "input", + props: { + label: this.translate.instant("Register.Form.lastname"), + disabled: true, + }, + }]; + protected readonly companyInformationFields: FormlyFieldConfig[] = []; constructor( public translate: TranslateService, @@ -56,12 +74,86 @@ export class UserComponent implements OnInit { formGroup: new FormGroup({}), model: userInformation, }; - this.showInformation = true; + + const baseInformationFields: FormlyFieldConfig[] = [{ + key: "street", + type: "input", + props: { + label: this.translate.instant("Register.Form.street"), + disabled: true, + }, + }, + { + key: "zip", + type: "input", + props: { + label: this.translate.instant("Register.Form.zip"), + disabled: true, + }, + }, + { + key: "city", + type: "input", + props: { + label: this.translate.instant("Register.Form.city"), + disabled: true, + }, + }, + { + key: "country", + type: "select", + props: { + label: this.translate.instant("Register.Form.country"), + options: COUNTRY_OPTIONS(this.translate), + disabled: true, + }, + }, + { + key: "email", + type: "input", + props: { + label: this.translate.instant("Register.Form.email"), + disabled: true, + }, + validators: { + validation: [Validators.email], + }, + }, + { + key: "phone", + type: "input", + props: { + label: this.translate.instant("Register.Form.phone"), + disabled: true, + }, + }]; + + if (Object.prototype.hasOwnProperty.call(userInformation, 'companyName')) { + this.companyInformationFields.push( + { + key: "companyName", + type: "input", + props: { + label: this.translate.instant('Register.Form.companyName'), + disabled: true, + }, + }, + ...baseInformationFields, + ); + } else { + this.userInformationFields.push(...baseInformationFields); + } + + }).then(() => { + this.service.metadata.subscribe(entry => { + this.showInformation = true; + }); }); } public applyChanges() { - const user = { + + const params: SetUserInformationRequest['params'] = { user: { lastname: this.form.model.lastname, firstname: this.form.model.firstname, @@ -75,7 +167,8 @@ export class UserComponent implements OnInit { }, }, }; - this.service.websocket.sendRequest(new SetUserInformationRequest(user)).then(() => { + + this.service.websocket.sendRequest(new SetUserInformationRequest(params)).then(() => { this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); }).catch((reason) => { this.service.toast(this.translate.instant('General.changeFailed') + '\n' + reason.error.message, 'danger'); @@ -99,114 +192,15 @@ export class UserComponent implements OnInit { public enableAndDisableFormFields(): boolean { - /** Fields, that are allowed to be edited for company assigned users */ - const ALLOWED_FIELDS_FOR_COMPANY_USER: string[] = [ - 'firstname', 'lastname', - ]; - - const hasUserCompany = this.userInformationFields.find(field => field.key === 'companyname').model.companyname; - - // Update Fields - this.userInformationFields.reduce((arr, field) => { - - if (hasUserCompany && ALLOWED_FIELDS_FOR_COMPANY_USER.find(key => key === field.key)?.length > 0) { - field.props.disabled = !field.props.disabled; - } - - if (!hasUserCompany) { - field.props.disabled = !field.props.disabled; - } - - arr.push(field); - return arr; - }, []); + this.userInformationFields = this.userInformationFields.map(field => { + field.props.disabled = !field.props.disabled; + return field; + }); return this.isEditModeDisabled = !this.isEditModeDisabled; } - /** Needs to be predefined to make wrapper work with ion-skeleton */ - protected userInformationFields: FormlyFieldConfig[] = [{ - key: "firstname", - type: "input", - templateOptions: { - label: this.translate.instant("Register.Form.firstname"), - disabled: true, - }, - }, - { - key: "lastname", - type: "input", - templateOptions: { - label: this.translate.instant("Register.Form.lastname"), - disabled: true, - }, - }, - { - key: "street", - type: "input", - templateOptions: { - label: this.translate.instant("Register.Form.street"), - disabled: true, - }, - }, - { - key: "zip", - type: "input", - templateOptions: { - label: this.translate.instant("Register.Form.zip"), - disabled: true, - }, - }, - { - key: "city", - type: "input", - templateOptions: { - label: this.translate.instant("Register.Form.city"), - disabled: true, - }, - }, - { - key: "country", - type: "select", - templateOptions: { - label: this.translate.instant("Register.Form.country"), - options: COUNTRY_OPTIONS(this.translate), - disabled: true, - }, - }, - { - key: "email", - type: "input", - templateOptions: { - label: this.translate.instant("Register.Form.email"), - disabled: true, - }, - validators: { - validation: [Validators.email], - }, - }, - { - key: "phone", - type: "input", - templateOptions: { - label: this.translate.instant("Register.Form.phone"), - disabled: true, - }, - }, - { - key: "companyname", - type: "input", - props: { - label: this.translate.instant('Register.Form.companyName'), - disabled: true, - }, - expressions: { - hide: (fields) => !fields.model.companyname, - }, - }, - ]; - - public getUserInformation(): Promise { + public getUserInformation(): Promise { return new Promise(resolve => { const interval = setInterval(() => { @@ -219,13 +213,13 @@ export class UserComponent implements OnInit { firstname: user.firstname, // Show company if available - ...(user.company.name && { companyname: user.company.name }), email: user.email, phone: user.phone, street: user.address.street, zip: user.address.zip, city: user.address.city, country: user.address.country, + ...(user.company?.name ? { companyName: user.company.name } : {}), }); }).catch(() => { resolve({ diff --git a/ui/src/assets/i18n/de.json b/ui/src/assets/i18n/de.json index 3051c67304f..fbd56096e39 100644 --- a/ui/src/assets/i18n/de.json +++ b/ui/src/assets/i18n/de.json @@ -902,7 +902,8 @@ "email": "E-Mail Adresse", "password": "Passwort", "confirmPassword": "Passwort wiederholen", - "confirmEmail": "E-Mail Adresse wiederholen" + "confirmEmail": "E-Mail Adresse wiederholen", + "PRIVATE": "Privat" }, "button": "Anlegen", "errors": { diff --git a/ui/src/assets/i18n/en.json b/ui/src/assets/i18n/en.json index ad2e259af25..3b4def7a994 100644 --- a/ui/src/assets/i18n/en.json +++ b/ui/src/assets/i18n/en.json @@ -905,7 +905,8 @@ "password": "Password", "confirmPassword": "Confirm password", "company": "Company", - "confirmEmail": "confirm E-Mail" + "confirmEmail": "confirm E-Mail", + "PRIVATE": "Private" }, "button": "Create", "errors": { From dd9bfffe63e9fe25edb30c4e221c28e85d62a27a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jun 2024 09:44:38 +0200 Subject: [PATCH 031/173] Bump org.apache.felix:org.apache.felix.http.jetty from 5.1.14 to 5.1.16 in /cnf (#2669) * Bump org.apache.felix:org.apache.felix.http.jetty in /cnf Bumps org.apache.felix:org.apache.felix.http.jetty from 5.1.14 to 5.1.16. --- updated-dependencies: - dependency-name: org.apache.felix:org.apache.felix.http.jetty 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 73a53791c40..70662b7d92b 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -203,7 +203,7 @@ org.apache.felix org.apache.felix.http.jetty - 5.1.14 + 5.1.16 diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index 2b107a25765..88211316e12 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -104,7 +104,7 @@ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ org.apache.felix.eventadmin;version='[1.6.4,1.6.5)',\ org.apache.felix.fileinstall;version='[3.7.4,3.7.5)',\ - org.apache.felix.http.jetty;version='[5.1.14,5.1.15)',\ + org.apache.felix.http.jetty;version='[5.1.16,5.1.17)',\ org.apache.felix.http.servlet-api;version='[3.0.0,3.0.1)',\ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index b72c41b92c5..326a917abf3 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -398,7 +398,7 @@ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ org.apache.felix.eventadmin;version='[1.6.4,1.6.5)',\ org.apache.felix.fileinstall;version='[3.7.4,3.7.5)',\ - org.apache.felix.http.jetty;version='[5.1.14,5.1.15)',\ + org.apache.felix.http.jetty;version='[5.1.16,5.1.17)',\ org.apache.felix.http.servlet-api;version='[3.0.0,3.0.1)',\ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ From 4c6dd78a95f29e8b325575ee11f209c9453004c5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jun 2024 10:06:18 +0200 Subject: [PATCH 032/173] Bump org.apache.felix:org.apache.felix.scr from 2.2.10 to 2.2.12 in /cnf (#2668) * Bump org.apache.felix:org.apache.felix.scr from 2.2.10 to 2.2.12 in /cnf Bumps org.apache.felix:org.apache.felix.scr from 2.2.10 to 2.2.12. --- updated-dependencies: - dependency-name: org.apache.felix:org.apache.felix.scr 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 70662b7d92b..29b68ef06d0 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -230,7 +230,7 @@ org.apache.felix org.apache.felix.scr - 2.2.10 + 2.2.12 diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index 88211316e12..e4c9ac0e3c4 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -108,7 +108,7 @@ org.apache.felix.http.servlet-api;version='[3.0.0,3.0.1)',\ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ - org.apache.felix.scr;version='[2.2.10,2.2.11)',\ + org.apache.felix.scr;version='[2.2.12,2.2.13)',\ org.apache.felix.webconsole;version='[5.0.2,5.0.3)',\ org.apache.felix.webconsole.plugins.ds;version='[2.3.0,2.3.1)',\ org.jetbrains.kotlin.osgi-bundle;version='[2.0.0,2.0.1)',\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index 326a917abf3..5b4727c90a7 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -402,7 +402,7 @@ org.apache.felix.http.servlet-api;version='[3.0.0,3.0.1)',\ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ - org.apache.felix.scr;version='[2.2.10,2.2.11)',\ + org.apache.felix.scr;version='[2.2.12,2.2.13)',\ org.apache.felix.webconsole;version='[5.0.2,5.0.3)',\ org.apache.felix.webconsole.plugins.ds;version='[2.3.0,2.3.1)',\ org.eclipse.jetty.client;version='[9.4.28,9.4.29)',\ From 54dcd4e7d0b4aaed0273564648feb989ae31ce1d Mon Sep 17 00:00:00 2001 From: Hiromasa Ihara Date: Sun, 16 Jun 2024 05:39:01 +0900 Subject: [PATCH 033/173] UI: add stylistic eslint plugin (#2671) * npm -i -D @stylistic/eslint-plugin * update eslintrc for migration to stylistic * apply `eslint src/ --fix` --- ui/.eslintrc.json | 13 +- ui/package-lock.json | 448 +++++++++++++++++- ui/package.json | 1 + .../app/edge/history/abstracthistorychart.ts | 4 +- .../app/edge/history/abstracthistorywidget.ts | 2 +- ui/src/app/edge/history/shared.ts | 14 +- .../modal/predictionChart.ts | 2 +- .../TimeOfUseTariff/Ess_TimeOfUseTariff.ts | 2 +- .../edge/live/Controller/Evcs/flat/flat.ts | 6 +- .../edge/live/Controller/Evcs/modal/modal.ts | 4 +- .../modal/modal.component.ts | 2 +- .../Controller/Io/HeatingElement/flat/flat.ts | 2 +- .../Io/Heatpump/modal/modal.component.ts | 2 +- .../modal/evcs-chart/evcs.chart.ts | 4 +- .../modal/evcsCluster-modal.page.ts | 4 +- .../section/abstractsection.component.ts | 2 +- .../settings/alerting/alerting.component.ts | 2 +- .../optionGroupPickerConfiguration.ts | 8 +- .../formly-reorder-array.component.ts | 4 +- .../settings/app/jsonrpc/getAppAssistant.ts | 2 +- ui/src/app/edge/settings/app/keypopup/app.ts | 2 +- ui/src/app/edge/settings/app/keypopup/key.ts | 2 +- .../edge/settings/jsonrpctest/jsonrpctest.ts | 12 +- ui/src/app/edge/settings/network/shared.ts | 8 +- ui/src/app/index/filter/filter.component.ts | 6 +- ui/src/app/index/shared/sumState.ts | 2 +- .../form-field-default-cases.wrapper.ts | 2 +- .../modal/modal-button/modal-button.ts | 2 +- .../modal/modal-line/modal-line.ts | 2 +- .../modal-value-line/modal-value-line.ts | 2 +- .../shared/genericComponents/modal/modal.ts | 2 +- .../shared/oe-formly-component.ts | 16 +- .../shared/testing/common.ts | 2 +- .../shared/testing/tester.ts | 26 +- ui/src/app/shared/service/defaulttypes.ts | 12 +- ui/src/app/shared/service/logger.ts | 2 +- ui/src/app/shared/service/utils.ts | 12 +- ui/src/app/shared/shared.ts | 2 +- ui/src/app/shared/type/general.ts | 4 +- ui/src/app/shared/type/widget.ts | 6 +- ui/src/app/user/user.component.ts | 2 +- 41 files changed, 547 insertions(+), 107 deletions(-) diff --git a/ui/.eslintrc.json b/ui/.eslintrc.json index 477e5e2c8dd..419e1faab58 100644 --- a/ui/.eslintrc.json +++ b/ui/.eslintrc.json @@ -20,7 +20,8 @@ "createDefaultProgram": true }, "plugins": [ - "unused-imports" + "unused-imports", + "@stylistic" ], "extends": [ "eslint:recommended", @@ -30,11 +31,11 @@ ], "rules": { "unused-imports/no-unused-imports": "error", - "semi": [ + "@stylistic/semi": [ "error", "always" ], - "quote-props": [ + "@stylistic/quote-props": [ "warn", "consistent" ], @@ -67,15 +68,15 @@ } ], "curly": "error", - "comma-dangle": [ + "@stylistic/comma-dangle": [ "error", "always-multiline" ], - "eol-last": [ + "@stylistic/eol-last": [ "error", "always" ], - "no-trailing-spaces": "error", + "@stylistic/no-trailing-spaces": "error", "@typescript-eslint/no-unused-vars": [ "error", { diff --git a/ui/package-lock.json b/ui/package-lock.json index d4bf997d2a0..2042a1d21cd 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -52,6 +52,7 @@ "@angular/compiler-cli": "^16.2.12", "@angular/language-service": "^16.2.12", "@ionic/angular-toolkit": "^11.0.1", + "@stylistic/eslint-plugin": "^2.1.0", "@types/jasmine": "~4.3.6", "@types/jasminewd2": "~2.0.13", "@types/node": "^20.12.6", @@ -3955,6 +3956,441 @@ "npm": ">=6.0.0" } }, + "node_modules/@stylistic/eslint-plugin": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.1.0.tgz", + "integrity": "sha512-cBBowKP2u/+uE5CzgH5w8pE9VKqcM7BXdIDPIbGt2rmLJGnA6MJPr9vYGaqgMoJFs7R/FzsMQerMvvEP40g2uw==", + "dev": true, + "dependencies": { + "@stylistic/eslint-plugin-js": "2.1.0", + "@stylistic/eslint-plugin-jsx": "2.1.0", + "@stylistic/eslint-plugin-plus": "2.1.0", + "@stylistic/eslint-plugin-ts": "2.1.0", + "@types/eslint": "^8.56.10" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.1.0.tgz", + "integrity": "sha512-gdXUjGNSsnY6nPyqxu6lmDTtVrwCOjun4x8PUn0x04d5ucLI74N3MT1Q0UhdcOR9No3bo5PGDyBgXK+KmD787A==", + "dev": true, + "dependencies": { + "@types/eslint": "^8.56.10", + "acorn": "^8.11.3", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-js/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-js/node_modules/espree": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.0.1.tgz", + "integrity": "sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==", + "dev": true, + "dependencies": { + "acorn": "^8.11.3", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-jsx": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-jsx/-/eslint-plugin-jsx-2.1.0.tgz", + "integrity": "sha512-mMD7S+IndZo2vxmwpHVTCwx2O1VdtE5tmpeNwgaEcXODzWV1WTWpnsc/PECQKIr/mkLPFWiSIqcuYNhQ/3l6AQ==", + "dev": true, + "dependencies": { + "@stylistic/eslint-plugin-js": "^2.1.0", + "@types/eslint": "^8.56.10", + "estraverse": "^5.3.0", + "picomatch": "^4.0.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-jsx/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@stylistic/eslint-plugin-jsx/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@stylistic/eslint-plugin-plus": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-2.1.0.tgz", + "integrity": "sha512-S5QAlgYXESJaSBFhBSBLZy9o36gXrXQwWSt6QkO+F0SrT9vpV5JF/VKoh+ojO7tHzd8Ckmyouq02TT9Sv2B0zQ==", + "dev": true, + "dependencies": { + "@types/eslint": "^8.56.10", + "@typescript-eslint/utils": "^7.8.0" + }, + "peerDependencies": { + "eslint": "*" + } + }, + "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/scope-manager": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.0.tgz", + "integrity": "sha512-ZrMCe1R6a01T94ilV13egvcnvVJ1pxShkE0+NDjDzH4nvG1wXpwsVI5bZCvE7AEDH1mXEx5tJSVR68bLgG7Dng==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/visitor-keys": "7.13.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/types": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.0.tgz", + "integrity": "sha512-QWuwm9wcGMAuTsxP+qz6LBBd3Uq8I5Nv8xb0mk54jmNoCyDspnMvVsOxI6IsMmway5d1S9Su2+sCKv1st2l6eA==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.0.tgz", + "integrity": "sha512-cAvBvUoobaoIcoqox1YatXOnSl3gx92rCZoMRPzMNisDiM12siGilSM4+dJAekuuHTibI2hVC2fYK79iSFvWjw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/visitor-keys": "7.13.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/utils": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.0.tgz", + "integrity": "sha512-jceD8RgdKORVnB4Y6BqasfIkFhl4pajB1wVxrF4akxD2QPM8GNYjgGwEzYS+437ewlqqrg7Dw+6dhdpjMpeBFQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.13.0", + "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/typescript-estree": "7.13.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.0.tgz", + "integrity": "sha512-nxn+dozQx+MK61nn/JP+M4eCkHDSxSLDpgE3WcQo0+fkjEolnaB5jswvIKC4K56By8MMgIho7f1PVxERHEo8rw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.13.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-plus/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@stylistic/eslint-plugin-plus/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@stylistic/eslint-plugin-plus/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@stylistic/eslint-plugin-plus/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@stylistic/eslint-plugin-ts": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-ts/-/eslint-plugin-ts-2.1.0.tgz", + "integrity": "sha512-2ioFibufHYBALx2TBrU4KXovCkN8qCqcb9yIHc0fyOfTaO5jw4d56WW7YRcF3Zgde6qFyXwAN6z/+w4pnmos1g==", + "dev": true, + "dependencies": { + "@stylistic/eslint-plugin-js": "2.1.0", + "@types/eslint": "^8.56.10", + "@typescript-eslint/utils": "^7.8.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/scope-manager": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.0.tgz", + "integrity": "sha512-ZrMCe1R6a01T94ilV13egvcnvVJ1pxShkE0+NDjDzH4nvG1wXpwsVI5bZCvE7AEDH1mXEx5tJSVR68bLgG7Dng==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/visitor-keys": "7.13.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/types": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.0.tgz", + "integrity": "sha512-QWuwm9wcGMAuTsxP+qz6LBBd3Uq8I5Nv8xb0mk54jmNoCyDspnMvVsOxI6IsMmway5d1S9Su2+sCKv1st2l6eA==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.0.tgz", + "integrity": "sha512-cAvBvUoobaoIcoqox1YatXOnSl3gx92rCZoMRPzMNisDiM12siGilSM4+dJAekuuHTibI2hVC2fYK79iSFvWjw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/visitor-keys": "7.13.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/utils": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.0.tgz", + "integrity": "sha512-jceD8RgdKORVnB4Y6BqasfIkFhl4pajB1wVxrF4akxD2QPM8GNYjgGwEzYS+437ewlqqrg7Dw+6dhdpjMpeBFQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.13.0", + "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/typescript-estree": "7.13.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.0.tgz", + "integrity": "sha512-nxn+dozQx+MK61nn/JP+M4eCkHDSxSLDpgE3WcQo0+fkjEolnaB5jswvIKC4K56By8MMgIho7f1PVxERHEo8rw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.13.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/@tootallnate/once": { "version": "1.1.2", "dev": true, @@ -4077,9 +4513,10 @@ } }, "node_modules/@types/eslint": { - "version": "8.56.2", + "version": "8.56.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", + "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -16037,11 +16474,12 @@ } }, "node_modules/ts-api-utils": { - "version": "1.0.3", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", "dev": true, - "license": "MIT", "engines": { - "node": ">=16.13.0" + "node": ">=16" }, "peerDependencies": { "typescript": ">=4.2.0" diff --git a/ui/package.json b/ui/package.json index 460c0f8728b..a90eca749bc 100644 --- a/ui/package.json +++ b/ui/package.json @@ -47,6 +47,7 @@ "@angular/compiler-cli": "^16.2.12", "@angular/language-service": "^16.2.12", "@ionic/angular-toolkit": "^11.0.1", + "@stylistic/eslint-plugin": "^2.1.0", "@types/jasmine": "~4.3.6", "@types/jasminewd2": "~2.0.13", "@types/node": "^20.12.6", diff --git a/ui/src/app/edge/history/abstracthistorychart.ts b/ui/src/app/edge/history/abstracthistorychart.ts index b225e292d7c..7f94b600242 100644 --- a/ui/src/app/edge/history/abstracthistorychart.ts +++ b/ui/src/app/edge/history/abstracthistorychart.ts @@ -242,12 +242,12 @@ export abstract class AbstractHistoryChart { /** * Sets the Label of Chart */ - protected abstract setLabel(config: EdgeConfig) + protected abstract setLabel(config: EdgeConfig); /** * Updates and Fills the Chart */ - protected abstract updateChart() + protected abstract updateChart(); /** * Initializes empty chart on error diff --git a/ui/src/app/edge/history/abstracthistorywidget.ts b/ui/src/app/edge/history/abstracthistorywidget.ts index 8a0e419c4c4..8f07ccf5cc4 100644 --- a/ui/src/app/edge/history/abstracthistorywidget.ts +++ b/ui/src/app/edge/history/abstracthistorywidget.ts @@ -96,5 +96,5 @@ export abstract class AbstractHistoryWidget { /** * Updates and Fills the Chart */ - protected abstract updateValues() + protected abstract updateValues(); } diff --git a/ui/src/app/edge/history/shared.ts b/ui/src/app/edge/history/shared.ts index 506dce92d5d..647edc7191c 100644 --- a/ui/src/app/edge/history/shared.ts +++ b/ui/src/app/edge/history/shared.ts @@ -27,7 +27,7 @@ export type Data = { label: string, _meta: {} }[] -} +}; export type TooltipItem = { datasetIndex: number, @@ -37,7 +37,7 @@ export type TooltipItem = { value: number, y: number, yLabel: number -} +}; export type YAxis = { @@ -61,7 +61,7 @@ export type YAxis = { stepSize?: number, callback?(value: number | string, index: number, values: number[] | string[]): string | number | null | undefined; } -} +}; export type ChartOptions = { plugins: {}, @@ -144,7 +144,7 @@ export type ChartOptions = { } }, legendCallback?(chart: Chart.Chart): string -} +}; export const DEFAULT_TIME_CHART_OPTIONS: Chart.ChartOptions = { responsive: true, @@ -409,7 +409,7 @@ export function setLabelVisible(label: string, visible: boolean | null): void { export type Resolution = { value: number, unit: ChronoUnit.Type -} +}; export namespace ChronoUnit { @@ -419,7 +419,7 @@ export namespace ChronoUnit { HOURS = "Hours", DAYS = "Days", MONTHS = "Months", - YEARS = "Years" + YEARS = "Years", } /** @@ -460,5 +460,5 @@ export type ChartData = { }, /** Name to be displayed on the left y-axis */ yAxisTitle: string, -} +}; 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 e785684e2b0..746098619b3 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 @@ -244,4 +244,4 @@ export type ChannelChartDescription = { channelName: string, datasets: number[], colorRgb: string, -} +}; diff --git a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/Ess_TimeOfUseTariff.ts b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/Ess_TimeOfUseTariff.ts index 3e068cbf248..bb6eda0caa8 100644 --- a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/Ess_TimeOfUseTariff.ts +++ b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/Ess_TimeOfUseTariff.ts @@ -162,6 +162,6 @@ export namespace Controller_Ess_TimeOfUseTariff { export enum ControlMode { CHARGE_CONSUMPTION = 'CHARGE_CONSUMPTION', - DELAY_DISCHARGE = 'DELAY_DISCHARGE' + DELAY_DISCHARGE = 'DELAY_DISCHARGE', } } diff --git a/ui/src/app/edge/live/Controller/Evcs/flat/flat.ts b/ui/src/app/edge/live/Controller/Evcs/flat/flat.ts index 50cb8fede3e..c8b9a0bbd5b 100644 --- a/ui/src/app/edge/live/Controller/Evcs/flat/flat.ts +++ b/ui/src/app/edge/live/Controller/Evcs/flat/flat.ts @@ -190,7 +190,7 @@ enum ChargeState { ERROR, //Error AUTHORIZATION_REJECTED, //Authorization rejected ENERGY_LIMIT_REACHED, //Energy limit reached - CHARGING_FINISHED //Charging has finished + CHARGING_FINISHED, //Charging has finished } @@ -200,9 +200,9 @@ enum ChargePlug { 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 + PLUGGED_ON_EVCS_AND_ON_EV_AND_LOCKED = 7, //Plugged on EVCS and on EV and locked } enum Prioritization { CAR, - STORAGE + STORAGE, } diff --git a/ui/src/app/edge/live/Controller/Evcs/modal/modal.ts b/ui/src/app/edge/live/Controller/Evcs/modal/modal.ts index 3971ecd4e94..cac24905c11 100644 --- a/ui/src/app/edge/live/Controller/Evcs/modal/modal.ts +++ b/ui/src/app/edge/live/Controller/Evcs/modal/modal.ts @@ -286,7 +286,7 @@ enum ChargeState { ERROR, //Error AUTHORIZATION_REJECTED, //Authorization rejected ENERGY_LIMIT_REACHED, //Energy limit reached - CHARGING_FINISHED //Charging has finished + CHARGING_FINISHED, //Charging has finished } enum ChargePlug { @@ -295,5 +295,5 @@ enum ChargePlug { 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 + 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/Io/ChannelSingleThreshold/modal/modal.component.ts b/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/modal/modal.component.ts index 7c5dffdbfc9..5e58e17716d 100644 --- a/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/modal/modal.component.ts +++ b/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/modal/modal.component.ts @@ -6,7 +6,7 @@ import { TranslateService } from '@ngx-translate/core'; import { ChannelAddress, Edge, EdgeConfig, Service, Websocket } from 'src/app/shared/shared'; type mode = 'ON' | 'AUTOMATIC' | 'OFF'; -type inputMode = 'SOC' | 'GRIDSELL' | 'GRIDBUY' | 'PRODUCTION' | 'OTHER' +type inputMode = 'SOC' | 'GRIDSELL' | 'GRIDBUY' | 'PRODUCTION' | 'OTHER'; @Component({ selector: 'Io_ChannelSingleThresholdModalComponent', 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 ac081a96468..2d654ebc840 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 @@ -105,5 +105,5 @@ export enum Status { "Undefined" = -1, "Inactive" = 0, "Active" = 1, - "ActiveForced" = 2 + "ActiveForced" = 2, } diff --git a/ui/src/app/edge/live/Controller/Io/Heatpump/modal/modal.component.ts b/ui/src/app/edge/live/Controller/Io/Heatpump/modal/modal.component.ts index 367e192854f..0970982b294 100644 --- a/ui/src/app/edge/live/Controller/Io/Heatpump/modal/modal.component.ts +++ b/ui/src/app/edge/live/Controller/Io/Heatpump/modal/modal.component.ts @@ -6,7 +6,7 @@ import { TranslateService } from '@ngx-translate/core'; import { Edge, EdgeConfig, Service, Websocket } from 'src/app/shared/shared'; type ManualMode = 'FORCE_ON' | 'RECOMMENDATION' | 'REGULAR' | 'LOCK'; -type AutomaticEnableMode = 'automaticRecommendationCtrlEnabled' | 'automaticForceOnCtrlEnabled' | 'automaticLockCtrlEnabled' +type AutomaticEnableMode = 'automaticRecommendationCtrlEnabled' | 'automaticForceOnCtrlEnabled' | 'automaticLockCtrlEnabled'; @Component({ selector: 'heatpump-modal', diff --git a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcs-chart/evcs.chart.ts b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcs-chart/evcs.chart.ts index e78268eda98..75ba5857c7a 100644 --- a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcs-chart/evcs.chart.ts +++ b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcs-chart/evcs.chart.ts @@ -212,11 +212,11 @@ export type BarChartOptions = { } }] } -} +}; export type BarChartTooltipItem = { datasetIndex: number, index: number, y: number, yLabel: number -} +}; diff --git a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcsCluster-modal.page.ts b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcsCluster-modal.page.ts index f1f6edc62d6..065900afded 100644 --- a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcsCluster-modal.page.ts +++ b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcsCluster-modal.page.ts @@ -348,7 +348,7 @@ enum ChargeState { ERROR, //Error AUTHORIZATION_REJECTED, //Authorization rejected ENERGY_LIMIT_REACHED, //Charge limit reached - CHARGING_FINISHED //Charging has finished + CHARGING_FINISHED, //Charging has finished } enum ChargePlug { @@ -357,5 +357,5 @@ enum ChargePlug { 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 + 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/energymonitor/chart/section/abstractsection.component.ts b/ui/src/app/edge/live/energymonitor/chart/section/abstractsection.component.ts index 95045c5cd53..9acc93e8d58 100644 --- a/ui/src/app/edge/live/energymonitor/chart/section/abstractsection.component.ts +++ b/ui/src/app/edge/live/energymonitor/chart/section/abstractsection.component.ts @@ -119,7 +119,7 @@ export class EnergyFlow { export enum GridMode { "undefined", "ongrid", - "offgrid" + "offgrid", } export abstract class AbstractSection { diff --git a/ui/src/app/edge/settings/alerting/alerting.component.ts b/ui/src/app/edge/settings/alerting/alerting.component.ts index cf41c78d8a5..fa73c4828b5 100644 --- a/ui/src/app/edge/settings/alerting/alerting.component.ts +++ b/ui/src/app/edge/settings/alerting/alerting.component.ts @@ -11,7 +11,7 @@ import { Edge, Service, Utils, Websocket } from 'src/app/shared/shared'; export enum AlertingType { offline = 0, fault = 1, - warning = 2 + warning = 2, } type DefaultValues = { [K in AlertingType]: Delay[]; }; diff --git a/ui/src/app/edge/settings/app/formly/option-group-picker/optionGroupPickerConfiguration.ts b/ui/src/app/edge/settings/app/formly/option-group-picker/optionGroupPickerConfiguration.ts index b94cf2c456c..99648c3eae4 100644 --- a/ui/src/app/edge/settings/app/formly/option-group-picker/optionGroupPickerConfiguration.ts +++ b/ui/src/app/edge/settings/app/formly/option-group-picker/optionGroupPickerConfiguration.ts @@ -10,25 +10,25 @@ export type OptionConfig = { title?: (field: FormlyFieldConfig) => string, disabled?: (field: FormlyFieldConfig) => boolean, } -} +}; export type OptionGroupConfig = { group: string, title: string, options: OptionConfig[] -} +}; export type OptionGroup = { group: string, title: string, options: Option[] -} +}; export type Option = { value: string, title: string, disabled: boolean, selected: boolean, -} +}; /** * Gets the title of an OptionConfig that should be display. diff --git a/ui/src/app/edge/settings/app/formly/reorder-select/formly-reorder-array.component.ts b/ui/src/app/edge/settings/app/formly/reorder-select/formly-reorder-array.component.ts index 04cb6f3138b..a6282146ab1 100644 --- a/ui/src/app/edge/settings/app/formly/reorder-select/formly-reorder-array.component.ts +++ b/ui/src/app/edge/settings/app/formly/reorder-select/formly-reorder-array.component.ts @@ -116,7 +116,7 @@ export type SelectOptionConfig = { expressions?: { locked?: (field: FormlyFieldConfig) => boolean, } -} +}; type SelectOption = { label: string, @@ -124,4 +124,4 @@ type SelectOption = { expressions: { locked: boolean, } -} +}; diff --git a/ui/src/app/edge/settings/app/jsonrpc/getAppAssistant.ts b/ui/src/app/edge/settings/app/jsonrpc/getAppAssistant.ts index 1e8088be0b9..c77c8436432 100644 --- a/ui/src/app/edge/settings/app/jsonrpc/getAppAssistant.ts +++ b/ui/src/app/edge/settings/app/jsonrpc/getAppAssistant.ts @@ -343,4 +343,4 @@ function convertFormlyReorderArray(rootFields: FormlyFieldConfig[], field: Forml } -type FormlyFieldConfigWithInitialModel = FormlyFieldConfig & { initialModel: {} } +type FormlyFieldConfigWithInitialModel = FormlyFieldConfig & { initialModel: {} }; diff --git a/ui/src/app/edge/settings/app/keypopup/app.ts b/ui/src/app/edge/settings/app/keypopup/app.ts index 4159d4499fa..f827b503707 100644 --- a/ui/src/app/edge/settings/app/keypopup/app.ts +++ b/ui/src/app/edge/settings/app/keypopup/app.ts @@ -4,4 +4,4 @@ export type App = { id: number, appId: string -} +}; diff --git a/ui/src/app/edge/settings/app/keypopup/key.ts b/ui/src/app/edge/settings/app/keypopup/key.ts index a4ada0ee594..3d29d9a395a 100644 --- a/ui/src/app/edge/settings/app/keypopup/key.ts +++ b/ui/src/app/edge/settings/app/keypopup/key.ts @@ -3,4 +3,4 @@ import { App } from "./app"; export type Key = { keyId: string bundles?: (App[])[] -} +}; diff --git a/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.ts b/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.ts index ce87c5b6db7..c06265ca312 100644 --- a/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.ts +++ b/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.ts @@ -135,21 +135,21 @@ type EndpointResponse = { examples: RequestExample[] }, parent: { method: string, request: { base: any, pathToSubrequest: string[] } }[], -} +}; type Tag = { name: string -} +}; type Guard = { name: string, description: string -} +}; type RequestExample = { key: string, value: {} -} +}; type EndpointType = { @@ -159,7 +159,7 @@ type EndpointType = | { type: 'string', constraints: string[] - } + }; type Endpoint = { method: string, @@ -185,4 +185,4 @@ type Endpoint = { loading?: boolean, response?: string; } -} +}; diff --git a/ui/src/app/edge/settings/network/shared.ts b/ui/src/app/edge/settings/network/shared.ts index 62b0949264a..911c82bc03b 100644 --- a/ui/src/app/edge/settings/network/shared.ts +++ b/ui/src/app/edge/settings/network/shared.ts @@ -8,13 +8,13 @@ export type NetworkInterface = { linkLocalAddressing?: boolean, metric?: number, addresses?: IpAddress[] -} +}; export type IpAddress = { label: string, address: string, subnetmask: string -} +}; export type InterfaceForm = { name: string, @@ -27,13 +27,13 @@ export type InterfaceModel = NetworkInterface & { addressesList?: string[], ip?: string | null, subnetmask?: string | null, -} +}; export type NetworkConfig = { interfaces: { [name: string]: NetworkInterface; } -} +}; export namespace NetworkUtils { diff --git a/ui/src/app/index/filter/filter.component.ts b/ui/src/app/index/filter/filter.component.ts index a7598c9c8e2..c1019a9afd9 100644 --- a/ui/src/app/index/filter/filter.component.ts +++ b/ui/src/app/index/filter/filter.component.ts @@ -69,7 +69,7 @@ export class FilterComponent { } } -export type ChosenFilter = TKeyValue +export type ChosenFilter = TKeyValue; export type Filter = { placeholder: string, @@ -78,9 +78,9 @@ export type Filter = { // sets additional filter setAdditionalFilter?: () => ChosenFilter -} +}; export type FilterOption = { name: string, value: string | null -} +}; diff --git a/ui/src/app/index/shared/sumState.ts b/ui/src/app/index/shared/sumState.ts index e26f3d72f01..528e62069e7 100644 --- a/ui/src/app/index/shared/sumState.ts +++ b/ui/src/app/index/shared/sumState.ts @@ -8,7 +8,7 @@ export enum SumState { OK = 'OK', INFO = 'INFO', WARNING = 'WARNING', - FAULT = 'FAULT' + FAULT = 'FAULT', } @Component({ diff --git a/ui/src/app/shared/formly/form-field-default-cases.wrapper.ts b/ui/src/app/shared/formly/form-field-default-cases.wrapper.ts index 0b649c05ac8..a50d3b32d6d 100644 --- a/ui/src/app/shared/formly/form-field-default-cases.wrapper.ts +++ b/ui/src/app/shared/formly/form-field-default-cases.wrapper.ts @@ -94,4 +94,4 @@ export class FormlyWrapperDefaultValueWithCasesComponent extends FieldWrapper im } -type FieldDefaultCases = { field: string, cases: [{ case: any, defaultValue: any }] } +type FieldDefaultCases = { field: string, cases: [{ case: any, defaultValue: any }] }; diff --git a/ui/src/app/shared/genericComponents/modal/modal-button/modal-button.ts b/ui/src/app/shared/genericComponents/modal/modal-button/modal-button.ts index f1b50ef6328..74d01588bb1 100644 --- a/ui/src/app/shared/genericComponents/modal/modal-button/modal-button.ts +++ b/ui/src/app/shared/genericComponents/modal/modal-button/modal-button.ts @@ -19,4 +19,4 @@ export type ButtonLabel = { /** Icons for Button, displayed above the corresponding name */ icons?: Icon; callback?: Function; -} +}; 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 57e97e2e0af..9da02e03038 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 @@ -32,5 +32,5 @@ export class ModalLineComponent extends AbstractModalLine { export enum TextIndentation { NONE = '0%', SINGLE = '5%', - DOUBLE = '10%' + DOUBLE = '10%', } diff --git a/ui/src/app/shared/genericComponents/modal/modal-value-line/modal-value-line.ts b/ui/src/app/shared/genericComponents/modal/modal-value-line/modal-value-line.ts index 6857fdf23dd..6f5ce00db9a 100644 --- a/ui/src/app/shared/genericComponents/modal/modal-value-line/modal-value-line.ts +++ b/ui/src/app/shared/genericComponents/modal/modal-value-line/modal-value-line.ts @@ -37,5 +37,5 @@ export class ModalValueLineComponent extends AbstractModalLine { export enum TextIndentation { NONE = '0%', SINGLE = '5%', - DOUBLE = '10%' + DOUBLE = '10%', } diff --git a/ui/src/app/shared/genericComponents/modal/modal.ts b/ui/src/app/shared/genericComponents/modal/modal.ts index 10481fb647a..df2dab11224 100644 --- a/ui/src/app/shared/genericComponents/modal/modal.ts +++ b/ui/src/app/shared/genericComponents/modal/modal.ts @@ -10,7 +10,7 @@ import { Icon } from "../../type/widget"; export enum Status { SUCCESS, ERROR, - PENDING + PENDING, } @Component({ diff --git a/ui/src/app/shared/genericComponents/shared/oe-formly-component.ts b/ui/src/app/shared/genericComponents/shared/oe-formly-component.ts index 54f74ccc739..67d6d92e92a 100644 --- a/ui/src/app/shared/genericComponents/shared/oe-formly-component.ts +++ b/ui/src/app/shared/genericComponents/shared/oe-formly-component.ts @@ -50,13 +50,13 @@ export abstract class AbstractFormlyComponent { * @param role the Role of the User for this Edge * @param translate the Translate-Service */ - protected abstract generateView(config: EdgeConfig, role: Role, translate: TranslateService): OeFormlyView + protected abstract generateView(config: EdgeConfig, role: Role, translate: TranslateService): OeFormlyView; } export type OeFormlyView = { title: string, lines: OeFormlyField[] -} +}; export type OeFormlyField = | OeFormlyField.InfoLine @@ -71,21 +71,21 @@ export namespace OeFormlyField { export type InfoLine = { type: 'info-line', name: string - } + }; export type Item = { type: 'item', channel: string, filter?: (value: number | null) => boolean, converter?: (value: number | null) => string - } + }; export type ChildrenLine = { type: 'children-line', name: /* actual name string */ string | /* name string derived from channel value */ { channel: ChannelAddress, converter: Converter }, indentation?: TextIndentation, children: Item[], - } + }; export type ChannelLine = { type: 'channel-line', @@ -94,7 +94,7 @@ export namespace OeFormlyField { filter?: (value: number | null) => boolean, converter?: (value: number | null) => string indentation?: TextIndentation, - } + }; export type ValueFromChannelsLine = { type: 'value-from-channels-line', @@ -103,9 +103,9 @@ export namespace OeFormlyField { channelsToSubscribe: ChannelAddress[], indentation?: TextIndentation, filter?: (value: number[] | null) => boolean, - } + }; export type HorizontalLine = { type: 'horizontal-line', - } + }; } diff --git a/ui/src/app/shared/genericComponents/shared/testing/common.ts b/ui/src/app/shared/genericComponents/shared/testing/common.ts index 06ecc495617..3b66a4b3c78 100644 --- a/ui/src/app/shared/genericComponents/shared/testing/common.ts +++ b/ui/src/app/shared/genericComponents/shared/testing/common.ts @@ -18,7 +18,7 @@ export namespace OeTester { energyPerPeriodChannelWithValues?: QueryHistoricTimeseriesEnergyPerPeriodResponse, /** data from a {@link QueryHistoricTimeseriesDataResponse} */ dataChannelWithValues?: QueryHistoricTimeseriesDataResponse - } + }; } export namespace ChartOptions { diff --git a/ui/src/app/shared/genericComponents/shared/testing/tester.ts b/ui/src/app/shared/genericComponents/shared/testing/tester.ts index 96559478cc7..4a15e82e174 100644 --- a/ui/src/app/shared/genericComponents/shared/testing/tester.ts +++ b/ui/src/app/shared/genericComponents/shared/testing/tester.ts @@ -187,7 +187,7 @@ export namespace OeChartTester { export type Context = { energyChannel: { [id: string]: number[] }[] powerChannel: { [id: string]: number[] }[] - }[] + }[]; export type View = { datasets: { @@ -195,12 +195,12 @@ export namespace OeChartTester { labels: OeChartTester.Dataset.LegendLabel, options: OeChartTester.Dataset.Option } - } + }; export type Dataset = | Dataset.Data | Dataset.LegendLabel - | Dataset.Option + | Dataset.Option; export namespace Dataset { @@ -208,16 +208,16 @@ export namespace OeChartTester { type: 'data', label: string | Converter, value: number[] | null - } + }; export type LegendLabel = { type: 'label', timestamps: Date[] - } + }; export type Option = { type: 'option', options: Chart.ChartOptions - } + }; } } @@ -327,7 +327,7 @@ export namespace OeFormlyViewTester { export type View = { title: string, lines: Field[] - } + }; export type Field = | Field.InfoLine @@ -342,37 +342,37 @@ export namespace OeFormlyViewTester { export type InfoLine = { type: 'info-line', name: string - } + }; export type Item = { type: 'item', value: string - } + }; export type ChannelLine = { type: 'channel-line', name: string, value?: string, indentation?: TextIndentation, - } + }; export type ValueLine = { type: 'value-from-channels-line', name: string, value?: string, indentation?: TextIndentation, - } + }; export type ChildrenLine = { type: 'children-line', name: string, indentation?: TextIndentation, children?: Field[] - } + }; export type HorizontalLine = { type: 'horizontal-line', - } + }; } export function applyLineWithChildren(field: OeFormlyField.ChildrenLine, context: Context): { rawValue: number | null, value: string } diff --git a/ui/src/app/shared/service/defaulttypes.ts b/ui/src/app/shared/service/defaulttypes.ts index 98527a673a6..c9cef0f0cbf 100644 --- a/ui/src/app/shared/service/defaulttypes.ts +++ b/ui/src/app/shared/service/defaulttypes.ts @@ -102,7 +102,7 @@ export module DefaultTypes { export enum YAxisTitle { PERCENTAGE, - ENERGY + ENERGY, } export type InputChannel = { @@ -113,7 +113,7 @@ export module DefaultTypes { /** Choose between predefined converters */ converter?: (value: number) => number | null, - } + }; export type DisplayValues = { name: string, /** suffix to the name */ @@ -128,11 +128,11 @@ export module DefaultTypes { color: string, /** the stack for barChart */ stack?: number, - } + }; export type ChannelData = { [name: string]: number[] - } + }; export type ChartData = { /** Input Channels that need to be queried from the database */ @@ -146,7 +146,7 @@ export module DefaultTypes { }, /** Name to be displayed on the left y-axis, also the unit to be displayed in tooltips and legend */ unit: YAxisTitle, - } + }; } export class HistoryPeriod { @@ -241,4 +241,4 @@ export module DefaultTypes { export type TKeyValue = { key: string, value: T -} +}; diff --git a/ui/src/app/shared/service/logger.ts b/ui/src/app/shared/service/logger.ts index 1f5899413d6..ac53b4ac5d7 100644 --- a/ui/src/app/shared/service/logger.ts +++ b/ui/src/app/shared/service/logger.ts @@ -10,7 +10,7 @@ export enum Level { DEBUG = "debug", INFO = "info", WARNING = "warning", - ERROR = "error" + ERROR = "error", } @Injectable() diff --git a/ui/src/app/shared/service/utils.ts b/ui/src/app/shared/service/utils.ts index d3f9652c6e5..c751bfd0527 100644 --- a/ui/src/app/shared/service/utils.ts +++ b/ui/src/app/shared/service/utils.ts @@ -618,7 +618,7 @@ export enum YAxisTitle { ENERGY, VOLTAGE, TIME, - CURRENCY + CURRENCY, } export enum ChartAxis { @@ -655,7 +655,7 @@ export namespace HistoryUtils { /** Choose between predefined converters */ converter?: (value: number) => number | null, - } + }; export type DisplayValues = { name: string, /** suffix to the name */ @@ -696,7 +696,7 @@ export namespace HistoryUtils { * @default Number.MAX_VALUE */ order?: number, - } + }; /** * Data from a subscription to Channel or from a historic data query. @@ -705,7 +705,7 @@ export namespace HistoryUtils { */ export type ChannelData = { [name: string]: number[] - } + }; export type ChartData = { /** Input Channels that need to be queried from the database */ @@ -718,7 +718,7 @@ export namespace HistoryUtils { 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 */ @@ -728,7 +728,7 @@ export namespace HistoryUtils { yAxisId: ChartAxis, /** Default: true */ displayGrid?: boolean - } + }; export namespace ValueConverter { diff --git a/ui/src/app/shared/shared.ts b/ui/src/app/shared/shared.ts index 48d7fa729f0..12eb25994cb 100644 --- a/ui/src/app/shared/shared.ts +++ b/ui/src/app/shared/shared.ts @@ -137,7 +137,7 @@ export namespace Currency { export enum Label { OERE_PER_KWH = "Öre/kWh", - CENT_PER_KWH = "Cent/kWh" + CENT_PER_KWH = "Cent/kWh", } } diff --git a/ui/src/app/shared/type/general.ts b/ui/src/app/shared/type/general.ts index 00e36175403..6673c96b70f 100644 --- a/ui/src/app/shared/type/general.ts +++ b/ui/src/app/shared/type/general.ts @@ -6,9 +6,9 @@ export enum GridMode { export enum Mode { MANUAL_ON = 'MANUAL_ON', MANUAL_OFF = 'MANUAL_OFF', - AUTOMATIC = 'AUTOMATIC' + AUTOMATIC = 'AUTOMATIC', } export enum WorkMode { TIME = 'TIME', - NONE = 'NONE' + NONE = 'NONE', } diff --git a/ui/src/app/shared/type/widget.ts b/ui/src/app/shared/type/widget.ts index 44370393bed..d15ae895846 100644 --- a/ui/src/app/shared/type/widget.ts +++ b/ui/src/app/shared/type/widget.ts @@ -10,7 +10,7 @@ export enum WidgetClass { 'Grid', 'Common_Production', 'Consumption', - 'Controller_ChannelThreshold' + 'Controller_ChannelThreshold', } export enum WidgetNature { @@ -42,7 +42,7 @@ export type Icon = { color: string; size: string; name: string; -} +}; export class Widget { public name: WidgetNature | WidgetFactory | string; @@ -151,5 +151,5 @@ export class Widgets { } export enum ProductType { - HOME = "home" + HOME = "home", } diff --git a/ui/src/app/user/user.component.ts b/ui/src/app/user/user.component.ts index 9a5eeb23737..ee2ee865b0b 100644 --- a/ui/src/app/user/user.component.ts +++ b/ui/src/app/user/user.component.ts @@ -26,7 +26,7 @@ type UserInformation = { zip: string, city: string, country: string -} +}; @Component({ templateUrl: './user.component.html', From ab730982075b69b4cf1d144586ba90f5c3f68f25 Mon Sep 17 00:00:00 2001 From: Hannes Date: Sun, 16 Jun 2024 12:32:21 +0200 Subject: [PATCH 034/173] Implement Edge2Edge Meter (#2621) --- io.openems.edge.edge2edge/bnd.bnd | 3 +- .../edge/edge2edge/ess/Edge2EdgeEssImpl.java | 9 +- .../openems/edge/edge2edge/meter/Config.java | 39 ++++++++ .../edge/edge2edge/meter/Edge2EdgeMeter.java | 22 +++++ .../edge2edge/meter/Edge2EdgeMeterImpl.java | 98 +++++++++++++++++++ .../meter/Edge2EdgeEssMeterImplTest.java | 30 ++++++ .../edge/edge2edge/meter/MyConfig.java | 91 +++++++++++++++++ 7 files changed, 286 insertions(+), 6 deletions(-) create mode 100644 io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/meter/Config.java create mode 100644 io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/meter/Edge2EdgeMeter.java create mode 100644 io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/meter/Edge2EdgeMeterImpl.java create mode 100644 io.openems.edge.edge2edge/test/io/openems/edge/edge2edge/meter/Edge2EdgeEssMeterImplTest.java create mode 100644 io.openems.edge.edge2edge/test/io/openems/edge/edge2edge/meter/MyConfig.java diff --git a/io.openems.edge.edge2edge/bnd.bnd b/io.openems.edge.edge2edge/bnd.bnd index f0d5bb62d42..037f5faf4f1 100644 --- a/io.openems.edge.edge2edge/bnd.bnd +++ b/io.openems.edge.edge2edge/bnd.bnd @@ -10,6 +10,7 @@ Bundle-Version: 1.0.0.${tstamp} io.openems.edge.bridge.modbus,\ io.openems.edge.common,\ io.openems.edge.ess.api,\ + io.openems.edge.meter.api,\ -testpath: \ - ${testpath} \ No newline at end of file + ${testpath} diff --git a/io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/ess/Edge2EdgeEssImpl.java b/io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/ess/Edge2EdgeEssImpl.java index 3273b2127fd..73f48371bc4 100644 --- a/io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/ess/Edge2EdgeEssImpl.java +++ b/io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/ess/Edge2EdgeEssImpl.java @@ -1,5 +1,6 @@ package io.openems.edge.edge2edge.ess; +import java.util.List; import java.util.function.Consumer; import org.osgi.service.cm.ConfigurationAdmin; @@ -14,8 +15,6 @@ import org.osgi.service.component.annotations.ReferencePolicyOption; import org.osgi.service.metatype.annotations.Designate; -import com.google.common.collect.Lists; - import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; import io.openems.common.types.OpenemsType; @@ -56,7 +55,7 @@ protected void setModbus(BridgeModbus modbus) { public Edge2EdgeEssImpl() { super(// - Lists.newArrayList(// + List.of(// OpenemsComponent::getModbusSlaveNatureTable, // SymmetricEss::getModbusSlaveNatureTable, // AsymmetricEss::getModbusSlaveNatureTable, // @@ -105,8 +104,8 @@ protected Consumer getOnUpdateCallback(ModbusSlaveNatureTable modbusSlav @Override protected io.openems.edge.common.channel.ChannelId getWriteChannelId(ModbusSlaveNatureTable modbusSlaveNatureTable, ModbusRecord record) { - if (record instanceof ModbusRecordChannel) { - var c = ((ModbusRecordChannel) record).getChannelId(); + if (record instanceof ModbusRecordChannel r) { + var c = r.getChannelId(); if (c == ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_EQUALS) { return Edge2EdgeEss.ChannelId.REMOTE_SET_ACTIVE_POWER_EQUALS; diff --git a/io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/meter/Config.java b/io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/meter/Config.java new file mode 100644 index 00000000000..2622f6c7e6d --- /dev/null +++ b/io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/meter/Config.java @@ -0,0 +1,39 @@ +package io.openems.edge.edge2edge.meter; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +import io.openems.edge.meter.api.MeterType; + +@ObjectClassDefinition(// + name = "Edge-2-Edge Meter", // + description = "Connects an energy storage system from a slave OpenEMS Edge via Modbus") +@interface Config { + + @AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component") + String id() default "meter0"; + + @AttributeDefinition(name = "Alias", description = "Human-readable name of this Component; defaults to Component-ID") + String alias() default ""; + + @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?") + boolean enabled() default true; + + @AttributeDefinition(name = "Remote Component-ID", description = "Component-ID of ESS at the slave OpenEMS Edge.") + String remoteComponentId() default "meter0"; + + @AttributeDefinition(name = "Modbus-ID", description = "ID of Modbus bridge.") + String modbus_id() default "modbus0"; + + @AttributeDefinition(name = "Modbus Unit-ID", description = "The Unit-ID of the Modbus device.") + int modbusUnitId() default 1; + + @AttributeDefinition(name = "Meter-Type", description = "What is measured by this Meter?") + MeterType type() default MeterType.PRODUCTION; + + @AttributeDefinition(name = "Modbus target filter", description = "This is auto-generated by 'Modbus-ID'.") + String Modbus_target() default "(enabled=true)"; + + String webconsole_configurationFactory_nameHint() default "Edge-2-Edge Meter [{id}]"; + +} \ No newline at end of file diff --git a/io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/meter/Edge2EdgeMeter.java b/io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/meter/Edge2EdgeMeter.java new file mode 100644 index 00000000000..edd735f7967 --- /dev/null +++ b/io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/meter/Edge2EdgeMeter.java @@ -0,0 +1,22 @@ +package io.openems.edge.edge2edge.meter; + +import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.component.OpenemsComponent; + +public interface Edge2EdgeMeter extends OpenemsComponent { + + public enum ChannelId implements io.openems.edge.common.channel.ChannelId { + ; + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } +} diff --git a/io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/meter/Edge2EdgeMeterImpl.java b/io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/meter/Edge2EdgeMeterImpl.java new file mode 100644 index 00000000000..7890cb4b9a5 --- /dev/null +++ b/io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/meter/Edge2EdgeMeterImpl.java @@ -0,0 +1,98 @@ +package io.openems.edge.edge2edge.meter; + +import java.util.List; +import java.util.function.Consumer; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.metatype.annotations.Designate; + +import io.openems.common.channel.AccessMode; +import io.openems.common.exceptions.OpenemsException; +import io.openems.edge.bridge.modbus.api.BridgeModbus; +import io.openems.edge.bridge.modbus.api.ModbusComponent; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.modbusslave.ModbusRecord; +import io.openems.edge.common.modbusslave.ModbusSlaveNatureTable; +import io.openems.edge.edge2edge.common.AbstractEdge2Edge; +import io.openems.edge.edge2edge.common.Edge2Edge; +import io.openems.edge.meter.api.ElectricityMeter; +import io.openems.edge.meter.api.MeterType; + +@Designate(ocd = Config.class, factory = true) +@Component(// + name = "Edge2Edge.Meter", // + immediate = true, // + configurationPolicy = ConfigurationPolicy.REQUIRE // +) +public class Edge2EdgeMeterImpl extends AbstractEdge2Edge + implements Edge2EdgeMeter, ElectricityMeter, Edge2Edge, ModbusComponent, OpenemsComponent { + + @Reference + protected ConfigurationAdmin cm; + + @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) + protected void setModbus(BridgeModbus modbus) { + super.setModbus(modbus); + } + + private Config config; + + public Edge2EdgeMeterImpl() throws OpenemsException { + super(// + List.of(// + OpenemsComponent::getModbusSlaveNatureTable, // + ElectricityMeter::getModbusSlaveNatureTable // + ), // + OpenemsComponent.ChannelId.values(), // + ModbusComponent.ChannelId.values(), // + Edge2Edge.ChannelId.values(), // + ElectricityMeter.ChannelId.values() // + ); + } + + @Activate + private void activate(ComponentContext context, Config config) throws OpenemsException { + this.config = config; + if (super.activate(context, config.id(), config.alias(), config.enabled(), config.modbusUnitId(), this.cm, + "Modbus", config.modbus_id(), config.remoteComponentId(), AccessMode.READ_ONLY)) { + return; + } + } + + @Deactivate + protected void deactivate() { + super.deactivate(); + } + + @Override + protected Consumer getOnUpdateCallback(ModbusSlaveNatureTable modbusSlaveNatureTable, ModbusRecord record) { + return null; + } + + @Override + protected io.openems.edge.common.channel.ChannelId getWriteChannelId(ModbusSlaveNatureTable modbusSlaveNatureTable, + ModbusRecord record) { + // No writable Channels + return null; + } + + @Override + public String debugLog() { + return "L:" + this.getActivePower().asString(); + } + + @Override + public MeterType getMeterType() { + return this.config.type(); + } + +} diff --git a/io.openems.edge.edge2edge/test/io/openems/edge/edge2edge/meter/Edge2EdgeEssMeterImplTest.java b/io.openems.edge.edge2edge/test/io/openems/edge/edge2edge/meter/Edge2EdgeEssMeterImplTest.java new file mode 100644 index 00000000000..a52aed0a22b --- /dev/null +++ b/io.openems.edge.edge2edge/test/io/openems/edge/edge2edge/meter/Edge2EdgeEssMeterImplTest.java @@ -0,0 +1,30 @@ +package io.openems.edge.edge2edge.meter; + +import org.junit.Test; + +import io.openems.edge.bridge.modbus.test.DummyModbusBridge; +import io.openems.edge.common.test.AbstractComponentTest.TestCase; +import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.common.test.DummyConfigurationAdmin; +import io.openems.edge.meter.api.MeterType; + +public class Edge2EdgeEssMeterImplTest { + + private static final String COMPONENT_ID = "meter0"; + private static final String MODBUS_ID = "modbus0"; + + @Test + public void test() throws Exception { + new ComponentTest(new Edge2EdgeMeterImpl()) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .activate(MyConfig.create() // + .setId(COMPONENT_ID) // + .setModbusId(MODBUS_ID) // + .setRemoteComponentId(COMPONENT_ID) // + .setMeterType(MeterType.PRODUCTION) // + .build()) + .next(new TestCase()); + } + +} diff --git a/io.openems.edge.edge2edge/test/io/openems/edge/edge2edge/meter/MyConfig.java b/io.openems.edge.edge2edge/test/io/openems/edge/edge2edge/meter/MyConfig.java new file mode 100644 index 00000000000..a78c1af3e8a --- /dev/null +++ b/io.openems.edge.edge2edge/test/io/openems/edge/edge2edge/meter/MyConfig.java @@ -0,0 +1,91 @@ +package io.openems.edge.edge2edge.meter; + +import io.openems.common.test.AbstractComponentConfig; +import io.openems.common.utils.ConfigUtils; +import io.openems.edge.meter.api.MeterType; + +@SuppressWarnings("all") +public class MyConfig extends AbstractComponentConfig implements Config { + + protected static class Builder { + private String id; + private String modbusId = null; + private int modbusUnitId; + private String remoteComponentId; + private MeterType type; + + private Builder() { + } + + public Builder setId(String id) { + this.id = id; + return this; + } + + public Builder setModbusId(String modbusId) { + this.modbusId = modbusId; + return this; + } + + public Builder setModbusUnitId(int modbusUnitId) { + this.modbusUnitId = modbusUnitId; + return this; + } + + public Builder setRemoteComponentId(String remoteComponentId) { + this.remoteComponentId = remoteComponentId; + return this; + } + + public Builder setMeterType(MeterType type) { + this.type = type; + return this; + } + + public MyConfig build() { + return new MyConfig(this); + } + } + + /** + * Create a Config builder. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new Builder(); + } + + private final Builder builder; + + private MyConfig(Builder builder) { + super(Config.class, builder.id); + this.builder = builder; + } + + @Override + public String modbus_id() { + return this.builder.modbusId; + } + + @Override + public String Modbus_target() { + return ConfigUtils.generateReferenceTargetFilter(this.id(), this.modbus_id()); + } + + @Override + public int modbusUnitId() { + return this.builder.modbusUnitId; + } + + @Override + public String remoteComponentId() { + return this.builder.remoteComponentId; + } + + @Override + public MeterType type() { + return this.builder.type; + } + +} \ No newline at end of file From d7cf502683aa31a7ada6b55e4ca489faa6e07dd6 Mon Sep 17 00:00:00 2001 From: DerWahreKlinki <102486171+DerWahreKlinki@users.noreply.github.com> Date: Sun, 16 Jun 2024 14:51:25 +0200 Subject: [PATCH 035/173] InfluxDB Edge Timedata: handle persistence priority (#2663) * Ignore channels with a peristence priority less than a configured level * Copy logic from io.openems.edge.timedata.rrd4j.RecordWorker * Modernize & cleanup code --- .../edge/timedata/influxdb/Config.java | 4 + .../influxdb/TimedataInfluxDbImpl.java | 80 +++++++------------ .../edge/timedata/influxdb/MyConfig.java | 12 +++ .../influxdb/TimedataInfluxDbImplTest.java | 2 + 4 files changed, 49 insertions(+), 49 deletions(-) diff --git a/io.openems.edge.timedata.influxdb/src/io/openems/edge/timedata/influxdb/Config.java b/io.openems.edge.timedata.influxdb/src/io/openems/edge/timedata/influxdb/Config.java index 287aec74cfe..17e01cf4e57 100644 --- a/io.openems.edge.timedata.influxdb/src/io/openems/edge/timedata/influxdb/Config.java +++ b/io.openems.edge.timedata.influxdb/src/io/openems/edge/timedata/influxdb/Config.java @@ -3,6 +3,7 @@ import org.osgi.service.metatype.annotations.AttributeDefinition; import org.osgi.service.metatype.annotations.ObjectClassDefinition; +import io.openems.common.channel.PersistencePriority; import io.openems.shared.influxdb.QueryLanguageConfig; @ObjectClassDefinition(// @@ -46,5 +47,8 @@ @AttributeDefinition(name = "Read-Only mode", description = "Activates the read-only mode. Then no data is written to InfluxDB.") boolean isReadOnly() default false; + @AttributeDefinition(name = "Persistence Priority", description = "Store only Channels with a Persistence Priority above this. Be aware that too many writes can wear-out your flash storage.") + PersistencePriority persistencePriority() default PersistencePriority.MEDIUM; + String webconsole_configurationFactory_nameHint() default "Timedata InfluxDB [{id}]"; } \ No newline at end of file diff --git a/io.openems.edge.timedata.influxdb/src/io/openems/edge/timedata/influxdb/TimedataInfluxDbImpl.java b/io.openems.edge.timedata.influxdb/src/io/openems/edge/timedata/influxdb/TimedataInfluxDbImpl.java index 10517dc27a4..22370abb9ef 100644 --- a/io.openems.edge.timedata.influxdb/src/io/openems/edge/timedata/influxdb/TimedataInfluxDbImpl.java +++ b/io.openems.edge.timedata.influxdb/src/io/openems/edge/timedata/influxdb/TimedataInfluxDbImpl.java @@ -27,6 +27,7 @@ import com.influxdb.client.domain.WritePrecision; import com.influxdb.client.write.Point; +import io.openems.common.channel.AccessMode; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.oem.OpenemsEdgeOem; import io.openems.common.timedata.Resolution; @@ -127,56 +128,37 @@ protected synchronized void collectAndWriteChannelValues() { final var point = Point.measurement(this.config.measurement()).time(timestamp, WritePrecision.MS); final var addedAtLeastOneChannelValue = new AtomicBoolean(false); - this.componentManager.getEnabledComponents().stream().filter(OpenemsComponent::isEnabled) - .forEach(component -> { - component.channels().forEach(channel -> { - switch (channel.channelDoc().getAccessMode()) { - case WRITE_ONLY: - // ignore Write-Only-Channels - return; - case READ_ONLY: - case READ_WRITE: - break; - } - - Optional valueOpt = channel.value().asOptional(); - if (!valueOpt.isPresent()) { - // ignore not available channels - return; - } - Object value = valueOpt.get(); - var address = channel.address().toString(); - try { - switch (channel.getType()) { - case BOOLEAN: - point.addField(address, (Boolean) value ? 1 : 0); - break; - case SHORT: - point.addField(address, (Short) value); - break; - case INTEGER: - point.addField(address, (Integer) value); - break; - case LONG: - point.addField(address, (Long) value); - break; - case FLOAT: - point.addField(address, (Float) value); - break; - case DOUBLE: - point.addField(address, (Double) value); - break; - case STRING: - point.addField(address, (String) value); - break; - } - } catch (IllegalArgumentException e) { - this.log.warn("Unable to add Channel [" + address + "] value [" + value + "]: " - + e.getMessage()); - return; + this.componentManager.getEnabledComponents().stream() // + .flatMap(component -> component.channels().stream()) // + .filter(channel -> { + final var doc = channel.channelDoc(); + return doc.getPersistencePriority().isAtLeast(this.config.persistencePriority()) + && doc.getAccessMode() != AccessMode.WRITE_ONLY; // + }) // + .forEach(channel -> { + Optional valueOpt = channel.value().asOptional(); + if (!valueOpt.isPresent()) { + // ignore not available channels + return; + } + Object value = valueOpt.get(); + var address = channel.address().toString(); + try { + switch (channel.getType()) { + case BOOLEAN -> point.addField(address, (Boolean) value ? 1 : 0); + case SHORT -> point.addField(address, (Short) value); + case INTEGER -> point.addField(address, (Integer) value); + case LONG -> point.addField(address, (Long) value); + case FLOAT -> point.addField(address, (Float) value); + case DOUBLE -> point.addField(address, (Double) value); + case STRING -> point.addField(address, (String) value); } - addedAtLeastOneChannelValue.set(true); - }); + } catch (IllegalArgumentException e) { + this.log.warn( + "Unable to add Channel [" + address + "] value [" + value + "]: " + e.getMessage()); + return; + } + addedAtLeastOneChannelValue.set(true); }); if (addedAtLeastOneChannelValue.get()) { diff --git a/io.openems.edge.timedata.influxdb/test/io/openems/edge/timedata/influxdb/MyConfig.java b/io.openems.edge.timedata.influxdb/test/io/openems/edge/timedata/influxdb/MyConfig.java index 37b1713dfd0..b08d4b7666e 100644 --- a/io.openems.edge.timedata.influxdb/test/io/openems/edge/timedata/influxdb/MyConfig.java +++ b/io.openems.edge.timedata.influxdb/test/io/openems/edge/timedata/influxdb/MyConfig.java @@ -1,5 +1,6 @@ package io.openems.edge.timedata.influxdb; +import io.openems.common.channel.PersistencePriority; import io.openems.common.test.AbstractComponentConfig; import io.openems.shared.influxdb.QueryLanguageConfig; @@ -17,6 +18,7 @@ protected static class Builder { private String url; private QueryLanguageConfig queryLanguage; private String measurement; + private PersistencePriority persistencePriority; private Builder() { } @@ -71,6 +73,11 @@ public Builder setMeasurement(String measurement) { return this; } + public Builder setPersistencePriority(PersistencePriority persistencePriority) { + this.persistencePriority = persistencePriority; + return this; + } + public MyConfig build() { return new MyConfig(this); } @@ -132,6 +139,11 @@ public boolean isReadOnly() { return this.builder.isReadOnly; } + @Override + public PersistencePriority persistencePriority() { + return this.builder.persistencePriority; + } + @Override public String measurement() { return this.builder.measurement; diff --git a/io.openems.edge.timedata.influxdb/test/io/openems/edge/timedata/influxdb/TimedataInfluxDbImplTest.java b/io.openems.edge.timedata.influxdb/test/io/openems/edge/timedata/influxdb/TimedataInfluxDbImplTest.java index 0810dcdfe68..4c097c21c69 100644 --- a/io.openems.edge.timedata.influxdb/test/io/openems/edge/timedata/influxdb/TimedataInfluxDbImplTest.java +++ b/io.openems.edge.timedata.influxdb/test/io/openems/edge/timedata/influxdb/TimedataInfluxDbImplTest.java @@ -2,6 +2,7 @@ import org.junit.Test; +import io.openems.common.channel.PersistencePriority; import io.openems.common.oem.DummyOpenemsEdgeOem; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; @@ -30,6 +31,7 @@ public void test() throws Exception { .setNoOfCycles(1) // .setMaxQueueSize(5000) // .setReadOnly(false) // + .setPersistencePriority(PersistencePriority.MEDIUM) .build()) // .next(new TestCase()) // ; From 625122c26170fc1b5bafcda2e0c23d3d9c8ad211 Mon Sep 17 00:00:00 2001 From: Hannes Date: Sun, 16 Jun 2024 17:17:43 +0200 Subject: [PATCH 036/173] Controller.Api.MQTT: reconnect on connection failure (#2602) # Add Reconnection Logic to MQTT Controller This PR introduces reconnection logic to the MQTT Controller, ensuring robustness in the face of connection losses with the MQTT broker. The implementation schedules reconnection attempts with an exponential backoff strategy, aiming to minimize the impact on both the broker and the controller while trying to re-establish a lost connection. # Key Changes: 1. **Scheduled Reconnection Attempts**: Utilizes a single-threaded `ScheduledExecutorService` to manage reconnection attempts, allowing for delayed execution with exponential backoff. 2. **Adaptive Delay Calculation**: Implements an adaptive delay calculation using a base delay, a maximum delay cap, and a multiplier to manage the delay between reconnection attempts, preventing aggressive reconnection attempts. 3. **Integration with Component Lifecycle**: Hooks the reconnection logic into the component's activation process, ensuring attempts to connect or reconnect are made upon activation. Similarly, ensures proper shutdown of the executor service upon deactivation to clean up resources. ## Integration: This implementation ensures that the MQTT Controller attempts to reconnect to the broker following a connection loss, employing an exponential backoff strategy to balance between prompt reconnection and avoiding overwhelming the broker or the network. --- .../api/mqtt/ControllerApiMqttImpl.java | 81 +++++++++++++++++-- 1 file changed, 73 insertions(+), 8 deletions(-) diff --git a/io.openems.edge.controller.api.mqtt/src/io/openems/edge/controller/api/mqtt/ControllerApiMqttImpl.java b/io.openems.edge.controller.api.mqtt/src/io/openems/edge/controller/api/mqtt/ControllerApiMqttImpl.java index 7707612270a..07e030a0abf 100644 --- a/io.openems.edge.controller.api.mqtt/src/io/openems/edge/controller/api/mqtt/ControllerApiMqttImpl.java +++ b/io.openems.edge.controller.api.mqtt/src/io/openems/edge/controller/api/mqtt/ControllerApiMqttImpl.java @@ -1,6 +1,13 @@ package io.openems.edge.controller.api.mqtt; +import static io.openems.common.utils.ThreadPoolUtils.shutdownAndAwaitTermination; + import java.nio.charset.StandardCharsets; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import org.eclipse.paho.mqttv5.client.IMqttClient; import org.eclipse.paho.mqttv5.common.MqttException; @@ -46,21 +53,28 @@ public class ControllerApiMqttImpl extends AbstractOpenemsComponent protected static final String COMPONENT_NAME = "Controller.Api.MQTT"; + private static final long INITIAL_RECONNECT_DELAY_SECONDS = 5; + private static final long MAX_RECONNECT_DELAY_SECONDS = 300; // 5 minutes maximum delay. + private static final double RECONNECT_DELAY_MULTIPLIER = 1.5; + private final Logger log = LoggerFactory.getLogger(ControllerApiMqttImpl.class); + private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); + private final AtomicInteger reconnectionAttempt = new AtomicInteger(0); private final SendChannelValuesWorker sendChannelValuesWorker = new SendChannelValuesWorker(this); private final MqttConnector mqttConnector = new MqttConnector(); + protected Config config; + + private volatile ScheduledFuture reconnectFuture = null; + private String topicPrefix; + private IMqttClient mqttClient = null; + @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) private volatile Timedata timedata = null; @Reference protected ComponentManager componentManager; - protected Config config; - - private String topicPrefix; - private IMqttClient mqttClient = null; - public ControllerApiMqttImpl() { super(// OpenemsComponent.ChannelId.values(), // @@ -82,6 +96,7 @@ private void activate(ComponentContext context, Config config) throws Exception this.mqttClient = client; this.logInfo(this.log, "Connected to MQTT Broker [" + config.uri() + "]"); }); + this.scheduleReconnect(); } /** @@ -113,13 +128,13 @@ protected static String createTopicPrefix(Config config) { @Deactivate protected void deactivate() { super.deactivate(); - this.mqttConnector.deactivate(); - this.sendChannelValuesWorker.deactivate(); + shutdownAndAwaitTermination(this.scheduledExecutorService, 0); + if (this.mqttClient != null) { try { this.mqttClient.close(); } catch (MqttException e) { - this.logWarn(this.log, "Unable to close connection to MQTT brokwer: " + e.getMessage()); + this.logWarn(this.log, "Unable to close connection to MQTT broker: " + e.getMessage()); e.printStackTrace(); } } @@ -159,6 +174,7 @@ public void handleEvent(Event event) { // Trigger sending of all channel values, because a Component might have // disappeared this.sendChannelValuesWorker.sendValuesOfAllChannelsOnce(); + break; } } @@ -199,4 +215,53 @@ protected boolean publish(String subTopic, String message, int qos, boolean reta var msg = new MqttMessage(message.getBytes(StandardCharsets.UTF_8), qos, retained, properties); return this.publish(subTopic, msg); } + + private synchronized void scheduleReconnect() { + if (this.reconnectFuture != null && !this.reconnectFuture.isDone()) { + this.reconnectFuture.cancel(false); + } + + this.attemptConnect(); + } + + private void attemptConnect() { + if (this.mqttClient != null && this.mqttClient.isConnected()) { + return; // Already connected + } + try { + this.mqttConnector + .connect(this.config.uri(), this.config.clientId(), this.config.username(), this.config.password(), + this.config.certPem(), this.config.privateKeyPem(), this.config.trustStorePem()) + .thenAccept(client -> { + this.mqttClient = client; + this.logInfo(this.log, "Connected to MQTT Broker [" + this.config.uri() + "]"); + this.reconnectionAttempt.set(0); // Reset on successful connection. + }) // + .exceptionally(ex -> { + this.log.error("Failed to connect to MQTT broker: " + ex.getMessage(), ex); + this.scheduleNextAttempt(); // Schedule the next attempt with an increased delay. + return null; + }); + } catch (Exception e) { + this.log.error("Error attempting to connect to MQTT broker", e); + this.scheduleNextAttempt(); // Schedule the next attempt with an increased delay. + } + } + + private void scheduleNextAttempt() { + long delay = this.calculateNextDelay(); + // Ensure the executor service is not shut down + if (!this.scheduledExecutorService.isShutdown()) { + this.reconnectFuture = this.scheduledExecutorService.schedule(this::attemptConnect, delay, + TimeUnit.SECONDS); + } + } + + private long calculateNextDelay() { + long delay = (long) (INITIAL_RECONNECT_DELAY_SECONDS + * Math.pow(RECONNECT_DELAY_MULTIPLIER, this.reconnectionAttempt.getAndIncrement())); + delay = Math.min(delay, MAX_RECONNECT_DELAY_SECONDS); // Ensure delay does not exceed maximum + return delay; + } + } \ No newline at end of file From c7ed5d06fc15528dfb304dc827b9744fc717a32f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Jun 2024 17:33:24 +0200 Subject: [PATCH 037/173] Bump swiper from 11.1.1 to 11.1.4 in /ui (#2659) Bumps [swiper](https://github.com/nolimits4web/Swiper) from 11.1.1 to 11.1.4. - [Release notes](https://github.com/nolimits4web/Swiper/releases) - [Changelog](https://github.com/nolimits4web/swiper/blob/master/CHANGELOG.md) - [Commits](https://github.com/nolimits4web/Swiper/compare/v11.1.1...v11.1.4) --- updated-dependencies: - dependency-name: swiper dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 7 ++++--- ui/package.json | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 2042a1d21cd..88dcd29a732 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -36,7 +36,7 @@ "ngx-spinner": "^16.0.2", "roboto-fontface": "^0.10.0", "rxjs": "~6.6.7", - "swiper": "11.1.1", + "swiper": "11.1.4", "tslib": "^2.6.2", "uuid": "^9.0.1", "zone.js": "~0.13.3" @@ -16151,7 +16151,9 @@ } }, "node_modules/swiper": { - "version": "11.1.1", + "version": "11.1.4", + "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.1.4.tgz", + "integrity": "sha512-1n7kbYJB2dFEpUHRFszq7gys/ofIBrMNibwTiMvPHwneKND/t9kImnHt6CfGPScMHgI+dWMbGTycCKGMoOO1KA==", "funding": [ { "type": "patreon", @@ -16162,7 +16164,6 @@ "url": "http://opencollective.com/swiper" } ], - "license": "MIT", "engines": { "node": ">= 4.7.0" } diff --git a/ui/package.json b/ui/package.json index a90eca749bc..1254dc7838a 100644 --- a/ui/package.json +++ b/ui/package.json @@ -31,7 +31,7 @@ "ngx-spinner": "^16.0.2", "roboto-fontface": "^0.10.0", "rxjs": "~6.6.7", - "swiper": "11.1.1", + "swiper": "11.1.4", "tslib": "^2.6.2", "uuid": "^9.0.1", "zone.js": "~0.13.3" From a724c17166de986dcaa45bf5f14a9780db1b1618 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Jun 2024 17:33:47 +0200 Subject: [PATCH 038/173] Bump typescript-strict-plugin from 2.4.3 to 2.4.4 in /ui (#2665) Bumps [typescript-strict-plugin](https://github.com/allegro/typescript-strict-plugin) from 2.4.3 to 2.4.4. - [Release notes](https://github.com/allegro/typescript-strict-plugin/releases) - [Changelog](https://github.com/allegro/typescript-strict-plugin/blob/master/CHANGELOG.md) - [Commits](https://github.com/allegro/typescript-strict-plugin/commits) --- updated-dependencies: - dependency-name: typescript-strict-plugin dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 8 ++++---- ui/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 88dcd29a732..005acae9472 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -75,7 +75,7 @@ "protractor": "~7.0.0", "ts-node": "^10.9.2", "typescript": "~4.9.5", - "typescript-strict-plugin": "^2.4.3" + "typescript-strict-plugin": "^2.4.4" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -16801,9 +16801,9 @@ } }, "node_modules/typescript-strict-plugin": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/typescript-strict-plugin/-/typescript-strict-plugin-2.4.3.tgz", - "integrity": "sha512-xKdyZGKg3Sy4tPU+b0U1DuxsDoCpMbu41iQvibTPiVjdZJvtG7Ou04a9NpEWuV/Dho8Xo3c34WmROtkHZe0pkg==", + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/typescript-strict-plugin/-/typescript-strict-plugin-2.4.4.tgz", + "integrity": "sha512-OXcWHQk+pW9gqEL/Mb1eTgj/Yiqk1oHBERr9v4VInPOYN++p+cXejmQK/h/VlUPGD++FXQ8pgiqVMyEtxU4T6A==", "dev": true, "dependencies": { "chalk": "^3.0.0", diff --git a/ui/package.json b/ui/package.json index 1254dc7838a..717ec9f1837 100644 --- a/ui/package.json +++ b/ui/package.json @@ -70,7 +70,7 @@ "protractor": "~7.0.0", "ts-node": "^10.9.2", "typescript": "~4.9.5", - "typescript-strict-plugin": "^2.4.3" + "typescript-strict-plugin": "^2.4.4" }, "scripts": { "lint": "ng lint", From 7174d772336750bca1c6c81fd2b424722238d4ac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Jun 2024 17:35:15 +0200 Subject: [PATCH 039/173] Bump @ngx-formly/ionic from 6.3.0 to 6.3.4 in /ui (#2667) Bumps [@ngx-formly/ionic](https://github.com/ngx-formly/ngx-formly) from 6.3.0 to 6.3.4. - [Release notes](https://github.com/ngx-formly/ngx-formly/releases) - [Changelog](https://github.com/ngx-formly/ngx-formly/blob/main/CHANGELOG.md) - [Commits](https://github.com/ngx-formly/ngx-formly/compare/v6.3.0...v6.3.4) --- updated-dependencies: - dependency-name: "@ngx-formly/ionic" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 14 ++++++++------ ui/package.json | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 005acae9472..339ca19b9a9 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -19,7 +19,7 @@ "@angular/service-worker": "~16.2.12", "@ionic/angular": "^6.7.5", "@ngx-formly/core": "^6.3.0", - "@ngx-formly/ionic": "^6.3.0", + "@ngx-formly/ionic": "^6.3.4", "@ngx-formly/schematics": "^6.3.0", "@ngx-translate/core": "^15.0.0", "@nodro7/angular-mydatepicker": "^0.14.0", @@ -3360,8 +3360,9 @@ } }, "node_modules/@ngx-formly/core": { - "version": "6.3.0", - "license": "MIT", + "version": "6.3.4", + "resolved": "https://registry.npmjs.org/@ngx-formly/core/-/core-6.3.4.tgz", + "integrity": "sha512-xpO0FB50gpQI4uDrz6nYNolMvMIOdgP19diflcvAAtDy15I4BS+tzLKOCkM9HmAwmKQ59z3FUyzaODFEu+cuEg==", "dependencies": { "tslib": "^2.0.0" }, @@ -3371,14 +3372,15 @@ } }, "node_modules/@ngx-formly/ionic": { - "version": "6.3.0", - "license": "MIT", + "version": "6.3.4", + "resolved": "https://registry.npmjs.org/@ngx-formly/ionic/-/ionic-6.3.4.tgz", + "integrity": "sha512-OHFZHe0E2sQoXEfYAzXMtvxt11mED2KZDjIAy0V35HGN0cC03GW1sToyTB2kmzLAyrH/HkhC3V7TurnrMbDSeQ==", "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@ionic/angular": "^6.0.0 || ^7.0.0", - "@ngx-formly/core": "6.3.0" + "@ngx-formly/core": "6.3.4" } }, "node_modules/@ngx-formly/schematics": { diff --git a/ui/package.json b/ui/package.json index 717ec9f1837..20cf3b9868f 100644 --- a/ui/package.json +++ b/ui/package.json @@ -14,7 +14,7 @@ "@angular/service-worker": "~16.2.12", "@ionic/angular": "^6.7.5", "@ngx-formly/core": "^6.3.0", - "@ngx-formly/ionic": "^6.3.0", + "@ngx-formly/ionic": "^6.3.4", "@ngx-formly/schematics": "^6.3.0", "@ngx-translate/core": "^15.0.0", "@nodro7/angular-mydatepicker": "^0.14.0", From 623d58b894df4afe020cf8a2628abe19175cfd6f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Jun 2024 17:36:12 +0200 Subject: [PATCH 040/173] Bump uuid from 9.0.1 to 10.0.0 in /ui (#2666) Bumps [uuid](https://github.com/uuidjs/uuid) from 9.0.1 to 10.0.0. - [Changelog](https://github.com/uuidjs/uuid/blob/main/CHANGELOG.md) - [Commits](https://github.com/uuidjs/uuid/compare/v9.0.1...v10.0.0) --- updated-dependencies: - dependency-name: uuid dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 7 ++++--- ui/package.json | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 339ca19b9a9..1dc1196fbb4 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -38,7 +38,7 @@ "rxjs": "~6.6.7", "swiper": "11.1.4", "tslib": "^2.6.2", - "uuid": "^9.0.1", + "uuid": "^10.0.0", "zone.js": "~0.13.3" }, "devDependencies": { @@ -17149,12 +17149,13 @@ } }, "node_modules/uuid": { - "version": "9.0.1", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], - "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } diff --git a/ui/package.json b/ui/package.json index 20cf3b9868f..e8094c44c0a 100644 --- a/ui/package.json +++ b/ui/package.json @@ -33,7 +33,7 @@ "rxjs": "~6.6.7", "swiper": "11.1.4", "tslib": "^2.6.2", - "uuid": "^9.0.1", + "uuid": "^10.0.0", "zone.js": "~0.13.3" }, "devDependencies": { From cbca0bdb90bc5c2564f39bea1bd42ca0cdc72422 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Jun 2024 18:01:27 +0200 Subject: [PATCH 041/173] Bump braces from 3.0.2 to 3.0.3 in /ui (#2670) * Bump swiper from 11.1.1 to 11.1.4 in /ui Bumps [swiper](https://github.com/nolimits4web/Swiper) from 11.1.1 to 11.1.4. - [Release notes](https://github.com/nolimits4web/Swiper/releases) - [Changelog](https://github.com/nolimits4web/swiper/blob/master/CHANGELOG.md) - [Commits](https://github.com/nolimits4web/Swiper/compare/v11.1.1...v11.1.4) --- updated-dependencies: - dependency-name: swiper dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Bump typescript-strict-plugin from 2.4.3 to 2.4.4 in /ui Bumps [typescript-strict-plugin](https://github.com/allegro/typescript-strict-plugin) from 2.4.3 to 2.4.4. - [Release notes](https://github.com/allegro/typescript-strict-plugin/releases) - [Changelog](https://github.com/allegro/typescript-strict-plugin/blob/master/CHANGELOG.md) - [Commits](https://github.com/allegro/typescript-strict-plugin/commits) --- updated-dependencies: - dependency-name: typescript-strict-plugin dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Bump uuid from 9.0.1 to 10.0.0 in /ui Bumps [uuid](https://github.com/uuidjs/uuid) from 9.0.1 to 10.0.0. - [Changelog](https://github.com/uuidjs/uuid/blob/main/CHANGELOG.md) - [Commits](https://github.com/uuidjs/uuid/compare/v9.0.1...v10.0.0) --- updated-dependencies: - dependency-name: uuid dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * Bump @ngx-formly/ionic from 6.3.0 to 6.3.4 in /ui Bumps [@ngx-formly/ionic](https://github.com/ngx-formly/ngx-formly) from 6.3.0 to 6.3.4. - [Release notes](https://github.com/ngx-formly/ngx-formly/releases) - [Changelog](https://github.com/ngx-formly/ngx-formly/blob/main/CHANGELOG.md) - [Commits](https://github.com/ngx-formly/ngx-formly/compare/v6.3.0...v6.3.4) --- updated-dependencies: - dependency-name: "@ngx-formly/ionic" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Bump braces from 3.0.2 to 3.0.3 in /ui Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3. - [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md) - [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3) --- updated-dependencies: - dependency-name: braces dependency-type: indirect ... Signed-off-by: dependabot[bot] --------- 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 | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 1dc1196fbb4..29378316821 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -6263,11 +6263,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "devOptional": true, - "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -9277,9 +9278,10 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "devOptional": true, - "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -10712,8 +10714,9 @@ }, "node_modules/is-number": { "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "devOptional": true, - "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -16418,8 +16421,9 @@ }, "node_modules/to-regex-range": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "devOptional": true, - "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, From dce35842f1dd5bd6cc3950693bee0671bb29ade1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Jun 2024 18:13:55 +0200 Subject: [PATCH 042/173] Bump chart.js from 4.4.2 to 4.4.3 in /ui (#2643) updated-dependencies: - dependency-name: chart.js dependency-type: direct:production update-type: version-update:semver-patch ... 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 | 7 ++++--- ui/package.json | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 29378316821..13cd93805a0 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -23,7 +23,7 @@ "@ngx-formly/schematics": "^6.3.0", "@ngx-translate/core": "^15.0.0", "@nodro7/angular-mydatepicker": "^0.14.0", - "chart.js": "^4.4.2", + "chart.js": "^4.4.3", "chartjs-adapter-date-fns": "^3.0.0", "chartjs-plugin-zoom": "^2.0.1", "classlist.js": "^1.1.20150312", @@ -6519,8 +6519,9 @@ "license": "MIT" }, "node_modules/chart.js": { - "version": "4.4.2", - "license": "MIT", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.3.tgz", + "integrity": "sha512-qK1gkGSRYcJzqrrzdR6a+I0vQ4/R+SoODXyAjscQ/4mzuNzySaMCd+hyVxitSY1+L2fjPD1Gbn+ibNqRmwQeLw==", "dependencies": { "@kurkle/color": "^0.3.0" }, diff --git a/ui/package.json b/ui/package.json index e8094c44c0a..1aa057eb7bf 100644 --- a/ui/package.json +++ b/ui/package.json @@ -18,7 +18,7 @@ "@ngx-formly/schematics": "^6.3.0", "@ngx-translate/core": "^15.0.0", "@nodro7/angular-mydatepicker": "^0.14.0", - "chart.js": "^4.4.2", + "chart.js": "^4.4.3", "chartjs-adapter-date-fns": "^3.0.0", "chartjs-plugin-zoom": "^2.0.1", "classlist.js": "^1.1.20150312", From dc240a7bad095626c8fa296304d6b910e6f58ce8 Mon Sep 17 00:00:00 2001 From: Hannes Date: Sun, 16 Jun 2024 20:18:35 +0200 Subject: [PATCH 043/173] Implement Samsung SDI ESS System (legacy) (#2638) Implemented components: - ESS - Charger - Grid-Meter --- io.openems.edge.application/EdgeApp.bndrun | 2 + io.openems.edge.ess.samsung/.classpath | 12 + io.openems.edge.ess.samsung/.gitignore | 2 + io.openems.edge.ess.samsung/.project | 23 ++ .../org.eclipse.core.resources.prefs | 2 + io.openems.edge.ess.samsung/bnd.bnd | 19 ++ io.openems.edge.ess.samsung/readme.adoc | 8 + .../edge/ess/samsung/charger/Config.java | 29 +++ .../samsung/charger/SamsungEssCharger.java | 88 +++++++ .../charger/SamsungEssChargerImpl.java | 166 ++++++++++++ .../openems/edge/ess/samsung/ess/Config.java | 32 +++ .../edge/ess/samsung/ess/SamsungEss.java | 197 +++++++++++++++ .../edge/ess/samsung/ess/SamsungEssImpl.java | 236 ++++++++++++++++++ .../edge/ess/samsung/gridmeter/Config.java | 29 +++ .../gridmeter/SamsungEssGridMeter.java | 87 +++++++ .../gridmeter/SamsungEssGridMeterImpl.java | 194 ++++++++++++++ io.openems.edge.ess.samsung/test/.gitignore | 0 .../edge/ess/samsung/charger/MyConfig.java | 62 +++++ .../charger/SamsungEssChargerImplTest.java | 25 ++ .../edge/ess/samsung/ess/MyConfig.java | 73 ++++++ .../ess/samsung/ess/SamsungEssImplTest.java | 26 ++ .../edge/ess/samsung/gridmeter/MyConfig.java | 62 +++++ .../SamsungEssGridMeterImplTest.java | 25 ++ 23 files changed, 1399 insertions(+) create mode 100644 io.openems.edge.ess.samsung/.classpath create mode 100644 io.openems.edge.ess.samsung/.gitignore create mode 100644 io.openems.edge.ess.samsung/.project create mode 100644 io.openems.edge.ess.samsung/.settings/org.eclipse.core.resources.prefs create mode 100644 io.openems.edge.ess.samsung/bnd.bnd create mode 100644 io.openems.edge.ess.samsung/readme.adoc create mode 100644 io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/charger/Config.java create mode 100644 io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/charger/SamsungEssCharger.java create mode 100644 io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/charger/SamsungEssChargerImpl.java create mode 100644 io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/Config.java create mode 100644 io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/SamsungEss.java create mode 100644 io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/SamsungEssImpl.java create mode 100644 io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/gridmeter/Config.java create mode 100644 io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/gridmeter/SamsungEssGridMeter.java create mode 100644 io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/gridmeter/SamsungEssGridMeterImpl.java create mode 100644 io.openems.edge.ess.samsung/test/.gitignore create mode 100644 io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/charger/MyConfig.java create mode 100644 io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/charger/SamsungEssChargerImplTest.java create mode 100644 io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/ess/MyConfig.java create mode 100644 io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/ess/SamsungEssImplTest.java create mode 100644 io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/gridmeter/MyConfig.java create mode 100644 io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/gridmeter/SamsungEssGridMeterImplTest.java diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index 5b4727c90a7..003fdb945f4 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -113,6 +113,7 @@ bnd.identity;id='io.openems.edge.ess.fenecon.commercial40',\ bnd.identity;id='io.openems.edge.ess.generic',\ bnd.identity;id='io.openems.edge.ess.mr.gridcon',\ + bnd.identity;id='io.openems.edge.ess.samsung',\ bnd.identity;id='io.openems.edge.ess.sma',\ bnd.identity;id='io.openems.edge.evcs.alpitronic.hypercharger',\ bnd.identity;id='io.openems.edge.evcs.cluster',\ @@ -284,6 +285,7 @@ io.openems.edge.ess.fenecon.commercial40;version=snapshot,\ io.openems.edge.ess.generic;version=snapshot,\ io.openems.edge.ess.mr.gridcon;version=snapshot,\ + io.openems.edge.ess.samsung;version=snapshot,\ io.openems.edge.ess.sma;version=snapshot,\ io.openems.edge.evcs.alpitronic.hypercharger;version=snapshot,\ io.openems.edge.evcs.api;version=snapshot,\ diff --git a/io.openems.edge.ess.samsung/.classpath b/io.openems.edge.ess.samsung/.classpath new file mode 100644 index 00000000000..bbfbdbe40e7 --- /dev/null +++ b/io.openems.edge.ess.samsung/.classpath @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/io.openems.edge.ess.samsung/.gitignore b/io.openems.edge.ess.samsung/.gitignore new file mode 100644 index 00000000000..c2b941a96de --- /dev/null +++ b/io.openems.edge.ess.samsung/.gitignore @@ -0,0 +1,2 @@ +/bin_test/ +/generated/ diff --git a/io.openems.edge.ess.samsung/.project b/io.openems.edge.ess.samsung/.project new file mode 100644 index 00000000000..eacef3ce5c3 --- /dev/null +++ b/io.openems.edge.ess.samsung/.project @@ -0,0 +1,23 @@ + + + io.openems.edge.ess.samsung + + + + + + org.eclipse.jdt.core.javabuilder + + + + + bndtools.core.bndbuilder + + + + + + org.eclipse.jdt.core.javanature + bndtools.core.bndnature + + diff --git a/io.openems.edge.ess.samsung/.settings/org.eclipse.core.resources.prefs b/io.openems.edge.ess.samsung/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 00000000000..99f26c0203a --- /dev/null +++ b/io.openems.edge.ess.samsung/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/io.openems.edge.ess.samsung/bnd.bnd b/io.openems.edge.ess.samsung/bnd.bnd new file mode 100644 index 00000000000..1858db68e77 --- /dev/null +++ b/io.openems.edge.ess.samsung/bnd.bnd @@ -0,0 +1,19 @@ +Bundle-Name: OpenEMS Edge ESS Samsung +Bundle-Vendor: FENECON GmbH +Bundle-License: https://opensource.org/licenses/EPL-2.0 +Bundle-Version: 1.0.0.${tstamp} + +-buildpath: \ + ${buildpath},\ + io.openems.common,\ + io.openems.edge.bridge.http,\ + io.openems.edge.common,\ + io.openems.edge.ess.api,\ + io.openems.edge.io.api,\ + io.openems.edge.meter.api,\ + io.openems.edge.pvinverter.api,\ + io.openems.edge.thermometer.api,\ + io.openems.edge.timedata.api,\ + +-testpath: \ + ${testpath} diff --git a/io.openems.edge.ess.samsung/readme.adoc b/io.openems.edge.ess.samsung/readme.adoc new file mode 100644 index 00000000000..7e70818f5a4 --- /dev/null +++ b/io.openems.edge.ess.samsung/readme.adoc @@ -0,0 +1,8 @@ += Samsung ESS + +This bundle implements the Samsung SDI ESS. + +Compatible with +- https://www.photovoltaik4all.de/speicher/samsung/samsung-sdi-lithium-ionen-speicher-3-6-kwh/SA23695 + +https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.ess.samsung[Source Code icon:github[]] \ No newline at end of file diff --git a/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/charger/Config.java b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/charger/Config.java new file mode 100644 index 00000000000..60b745cf475 --- /dev/null +++ b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/charger/Config.java @@ -0,0 +1,29 @@ +package io.openems.edge.ess.samsung.charger; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +import io.openems.edge.meter.api.MeterType; + +@ObjectClassDefinition(// + name = "Samsung ESS Charger", // + description = "Implements the Samsung ESS Charger.") +@interface Config { + + @AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component") + String id() default "charger0"; + + @AttributeDefinition(name = "Alias", description = "Human-readable name of this Component; defaults to Component-ID") + String alias() default ""; + + @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?") + boolean enabled() default true; + + @AttributeDefinition(name = "IP-Address", description = "The IP address of the ESS.") + String ip() default ""; + + @AttributeDefinition(name = "Meter-Type", description = "What is measured by this Meter?") + MeterType type() default MeterType.PRODUCTION; + + String webconsole_configurationFactory_nameHint() default "Samsung ESS Charger [{id}]"; +} \ No newline at end of file diff --git a/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/charger/SamsungEssCharger.java b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/charger/SamsungEssCharger.java new file mode 100644 index 00000000000..8e526a3f123 --- /dev/null +++ b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/charger/SamsungEssCharger.java @@ -0,0 +1,88 @@ +package io.openems.edge.ess.samsung.charger; + +import org.osgi.service.event.EventHandler; + +import io.openems.common.channel.Level; +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.channel.StateChannel; +import io.openems.edge.common.channel.value.Value; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.meter.api.ElectricityMeter; +import io.openems.edge.pvinverter.api.ManagedSymmetricPvInverter; + +public interface SamsungEssCharger + extends ElectricityMeter, OpenemsComponent, EventHandler, ManagedSymmetricPvInverter { + + public static enum ChannelId implements io.openems.edge.common.channel.ChannelId { + /** + * Warning when one or more Inverters are not reachable. + * + *
        + *
      • Type: State + *
      + */ + COMMUNICATION_FAILED(Doc.of(Level.FAULT) // + .text("Samsung ESS not reachable or wrong output!")), + + /** + * Measures the power produced by photovoltaic (PV) panels. + * + *
        + *
      • Type: Double
      • + *
      + */ + PV_PW(Doc.of(OpenemsType.DOUBLE) // + .text("PV Power")); + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#GRID_PW} Channel. + * + * @param value the next value + */ + public default void _setPvPw(double value) { + this.channel(ChannelId.PV_PW).setNextValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#SLAVE_COMMUNICATION_FAILED}. + * + * @return the Channel + */ + public default StateChannel getSlaveCommunicationFailedChannel() { + return this.channel(ChannelId.COMMUNICATION_FAILED); + } + + /** + * Gets the Slave Communication Failed State. See + * {@link ChannelId#SLAVE_COMMUNICATION_FAILED}. + * + * @return the Channel {@link Value} + */ + public default Value getSlaveCommunicationFailed() { + return this.getSlaveCommunicationFailedChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on + * {@link ChannelId#SLAVE_COMMUNICATION_FAILED} Channel. + * + * @param value the next value + */ + public default void _setSlaveCommunicationFailed(boolean value) { + this.getSlaveCommunicationFailedChannel().setNextValue(value); + } + +} diff --git a/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/charger/SamsungEssChargerImpl.java b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/charger/SamsungEssChargerImpl.java new file mode 100644 index 00000000000..8b6af1cabf7 --- /dev/null +++ b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/charger/SamsungEssChargerImpl.java @@ -0,0 +1,166 @@ +package io.openems.edge.ess.samsung.charger; + +import static io.openems.common.utils.JsonUtils.getAsFloat; +import static io.openems.common.utils.JsonUtils.getAsJsonObject; +import static java.lang.Math.round; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventHandler; +import org.osgi.service.event.propertytypes.EventTopics; +import org.osgi.service.metatype.annotations.Designate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.bridge.http.api.BridgeHttp; +import io.openems.edge.bridge.http.api.BridgeHttpFactory; +import io.openems.edge.bridge.http.api.HttpError; +import io.openems.edge.bridge.http.api.HttpResponse; +import io.openems.edge.common.component.AbstractOpenemsComponent; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.event.EdgeEventConstants; +import io.openems.edge.meter.api.ElectricityMeter; +import io.openems.edge.meter.api.MeterType; +import io.openems.edge.pvinverter.api.ManagedSymmetricPvInverter; +import io.openems.edge.timedata.api.Timedata; +import io.openems.edge.timedata.api.TimedataProvider; +import io.openems.edge.timedata.api.utils.CalculateEnergyFromPower; + +@Designate(ocd = Config.class, factory = true) +@Component(// + name = "Samsung.ESS.Charger", // + immediate = true, // + configurationPolicy = ConfigurationPolicy.REQUIRE) + +@EventTopics({ // + EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE, // +}) +public class SamsungEssChargerImpl extends AbstractOpenemsComponent implements SamsungEssCharger, ElectricityMeter, + OpenemsComponent, EventHandler, TimedataProvider, ManagedSymmetricPvInverter { + + private final Logger log = LoggerFactory.getLogger(SamsungEssChargerImpl.class); + private final CalculateEnergyFromPower calculateActualEnergy = new CalculateEnergyFromPower(this, + ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY); + + @Reference + protected ConfigurationAdmin cm; + + @Reference(cardinality = ReferenceCardinality.MANDATORY) + private BridgeHttpFactory httpBridgeFactory; + private BridgeHttp httpBridge; + + @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) + private volatile Timedata timedata; + + private String baseUrl; + private Config config; + + public SamsungEssChargerImpl() { + super(// + OpenemsComponent.ChannelId.values(), // + ElectricityMeter.ChannelId.values(), // + SamsungEssCharger.ChannelId.values(), // + ManagedSymmetricPvInverter.ChannelId.values() // + ); + ElectricityMeter.calculatePhasesFromActivePower(this); + } + + @Activate + private void activate(ComponentContext context, Config config) { + super.activate(context, config.id(), config.alias(), config.enabled()); + this.baseUrl = "http://" + config.ip(); + this.httpBridge = this.httpBridgeFactory.get(); + this.config = config; + + if (!this.isEnabled()) { + return; + } + + this.httpBridge.subscribeJsonEveryCycle(this.baseUrl + "/R3EMSAPP_REAL.ems?file=ESSRealtimeStatus.json", + this::fetchAndUpdateEssRealtimeStatus); + } + + @Override + @Deactivate + protected void deactivate() { + this.httpBridgeFactory.unget(this.httpBridge); + this.httpBridge = null; + super.deactivate(); + } + + @Override + public void handleEvent(Event event) { + if (!this.isEnabled()) { + return; + } + + switch (event.getTopic()) { + case EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE: + this.calculateEnergy(); + break; + } + } + + private void fetchAndUpdateEssRealtimeStatus(HttpResponse result, HttpError error) { + Integer pvPower = null; + + if (error != null) { + this.logDebug(this.log, error.getMessage()); + + } else { + try { + var response = getAsJsonObject(result.data()); + var essRealtimeStatus = getAsJsonObject(response, "ESSRealtimeStatus"); + + pvPower = round(getAsFloat(essRealtimeStatus, "PvPw") * 1000); + + } catch (OpenemsNamedException e) { + this.logDebug(this.log, e.getMessage()); + } + } + + this._setActivePower(pvPower); + } + + /** + * Calculate the Energy values from ActivePower. + */ + private void calculateEnergy() { + var actualPower = this.getActivePower().get(); + if (actualPower == null) { + this.calculateActualEnergy.update(null); + } else if (actualPower > 0) { + this.calculateActualEnergy.update(actualPower); + } else { + this.calculateActualEnergy.update(0); + } + } + + @Override + public String debugLog() { + return "L:" + this.getActivePower().asString(); // + } + + @Override + public Timedata getTimedata() { + return this.timedata; + } + + @Override + public MeterType getMeterType() { + return this.config.type(); + } + +} \ No newline at end of file diff --git a/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/Config.java b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/Config.java new file mode 100644 index 00000000000..9b96d04d16d --- /dev/null +++ b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/Config.java @@ -0,0 +1,32 @@ +package io.openems.edge.ess.samsung.ess; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +import io.openems.edge.ess.power.api.Phase; + +@ObjectClassDefinition(// + name = "Samsung ESS", // + description = "Implements the Sasmung ESS Combined System.") +@interface Config { + + @AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component") + String id() default "ess0"; + + @AttributeDefinition(name = "Alias", description = "Human-readable name of this Component; defaults to Component-ID") + String alias() default ""; + + @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?") + boolean enabled() default true; + + @AttributeDefinition(name = "Phase", description = "Which Phase is this ESS connected to?") + Phase phase() default Phase.L1; + + @AttributeDefinition(name = "Capacity", description = "The Capacity of the ESS in Wh") + int capacity() default 3600; + + @AttributeDefinition(name = "IP-Address", description = "The IP address of the ESS.") + String ip() default ""; + + String webconsole_configurationFactory_nameHint() default "Samsung ESS [{id}]"; +} \ No newline at end of file diff --git a/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/SamsungEss.java b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/SamsungEss.java new file mode 100644 index 00000000000..84d064fe637 --- /dev/null +++ b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/SamsungEss.java @@ -0,0 +1,197 @@ +package io.openems.edge.ess.samsung.ess; + +import org.osgi.service.event.EventHandler; + +import io.openems.common.channel.Level; +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.channel.StateChannel; +import io.openems.edge.common.channel.value.Value; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.ess.api.SymmetricEss; + +public interface SamsungEss extends SymmetricEss, OpenemsComponent, EventHandler { + + public static enum ChannelId implements io.openems.edge.common.channel.ChannelId { + /** + * Warning when one or more Inverters are not reachable. + * + *
        + *
      • Type: State + *
      + */ + SLAVE_COMMUNICATION_FAILED(Doc.of(Level.FAULT) // + .text("Samsung ESS not reachable!")), + + /** + * Describes the collection time. This represents the timestamp at which data + * was collected or recorded. + * + *
        + *
      • Type: String
      • + *
      + */ + COLEC_TM(Doc.of(OpenemsType.STRING) // + .text("Collection Time")), + + /** + * Measures the power imported from or exported to the grid. + * + *
        + *
      • Type: Double
      • + *
      + */ + GRID_PW(Doc.of(OpenemsType.DOUBLE) // + .text("Grid Power")), + + /** + * Measures the power produced by photovoltaic (PV) panels. + * + *
        + *
      • Type: Double
      • + *
      + */ + PV_PW(Doc.of(OpenemsType.DOUBLE) // + .text("PV Power")), + + /** + * Indicates the absolute discharge power. + * + *
        + *
      • Type: Double
      • + *
      + */ + ABS_DSC_POWER(Doc.of(OpenemsType.DOUBLE) // + .text("Absolute Discharge Power")), + + /** + * Measures the total power consumption of the system or facility. + * + *
        + *
      • Type: Double
      • + *
      + */ + CONS_PW(Doc.of(OpenemsType.DOUBLE) // + .text("Consumption Power")), + + /** + * Reports the current state of charge of the battery. This percentage reflects + * the remaining energy capacity of the battery. + * + *
        + *
      • Type: Integer
      • + *
      + */ + BT_SOC(Doc.of(OpenemsType.INTEGER) // + .text("Battery State of Charge")), + + /** + * Accumulates the total energy consumed actively by the system or facility. + * This parameter is typically measured in kilowatt-hours. + * + *
        + *
      • Type: Integer
      • + *
      + */ + ACTIVE_CONSUMPTION_ENERGY(Doc.of(OpenemsType.INTEGER) // + .text("Active Consumption Energy")), + + /** + * Accumulates the total energy produced actively by the system. This value is + * crucial for calculating the efficiency and output of energy production + * systems. + * + *
        + *
      • Type: Integer
      • + *
      + */ + ACTIVE_PRODUCTION_ENERGY(Doc.of(OpenemsType.INTEGER) // + .text("Active Production Energy")); + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#GRID_PW} Channel. + * + * @param value the next value + */ + public default void _setGridPw(double value) { + this.channel(ChannelId.GRID_PW).setNextValue(value); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#GRID_PW} Channel. + * + * @param value the next value + */ + public default void _setPvPw(double value) { + this.channel(ChannelId.PV_PW).setNextValue(value); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#GRID_PW} Channel. + * + * @param value the next value + */ + public default void _setAbsPcsPw(double value) { + this.channel(ChannelId.ABS_DSC_POWER).setNextValue(value); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#CONS_PW} Channel. + * + * @param value the next value + */ + public default void _setConsPw(double value) { + this.channel(ChannelId.CONS_PW).setNextValue(value); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#BT_SOC} Channel. + * + * @param value the next value + */ + public default void _setBtSoc(int value) { + this.channel(ChannelId.BT_SOC).setNextValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#SLAVE_COMMUNICATION_FAILED}. + * + * @return the Channel + */ + public default StateChannel getSlaveCommunicationFailedChannel() { + return this.channel(ChannelId.SLAVE_COMMUNICATION_FAILED); + } + + /** + * Gets the Slave Communication Failed State. See + * {@link ChannelId#SLAVE_COMMUNICATION_FAILED}. + * + * @return the Channel {@link Value} + */ + public default Value getSlaveCommunicationFailed() { + return this.getSlaveCommunicationFailedChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on + * {@link ChannelId#SLAVE_COMMUNICATION_FAILED} Channel. + * + * @param value the next value + */ + public default void _setSlaveCommunicationFailed(boolean value) { + this.getSlaveCommunicationFailedChannel().setNextValue(value); + } + +} diff --git a/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/SamsungEssImpl.java b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/SamsungEssImpl.java new file mode 100644 index 00000000000..d4e04fd5b95 --- /dev/null +++ b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/SamsungEssImpl.java @@ -0,0 +1,236 @@ +package io.openems.edge.ess.samsung.ess; + +import static io.openems.common.utils.JsonUtils.getAsFloat; +import static io.openems.common.utils.JsonUtils.getAsInt; +import static io.openems.common.utils.JsonUtils.getAsJsonObject; +import static java.lang.Math.round; + +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventHandler; +import org.osgi.service.event.propertytypes.EventTopics; +import org.osgi.service.metatype.annotations.Designate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.bridge.http.api.BridgeHttp; +import io.openems.edge.bridge.http.api.BridgeHttpFactory; +import io.openems.edge.bridge.http.api.HttpError; +import io.openems.edge.bridge.http.api.HttpResponse; +import io.openems.edge.common.component.AbstractOpenemsComponent; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.event.EdgeEventConstants; +import io.openems.edge.common.sum.GridMode; +import io.openems.edge.ess.api.HybridEss; +import io.openems.edge.ess.api.SymmetricEss; +import io.openems.edge.ess.dccharger.api.EssDcCharger; +import io.openems.edge.timedata.api.Timedata; +import io.openems.edge.timedata.api.TimedataProvider; +import io.openems.edge.timedata.api.utils.CalculateEnergyFromPower; + +@Designate(ocd = Config.class, factory = true) +@Component(// + name = "Samsung.ESS", immediate = true, // + configurationPolicy = ConfigurationPolicy.REQUIRE// +) + +@EventTopics({ // + EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE, // +}) +public class SamsungEssImpl extends AbstractOpenemsComponent + implements SamsungEss, SymmetricEss, OpenemsComponent, EventHandler, TimedataProvider, HybridEss { + + private final Logger log = LoggerFactory.getLogger(SamsungEssImpl.class); + private final CalculateEnergyFromPower calculateAcChargeEnergy = new CalculateEnergyFromPower(this, + SymmetricEss.ChannelId.ACTIVE_CHARGE_ENERGY); + private final CalculateEnergyFromPower calculateAcDischargeEnergy = new CalculateEnergyFromPower(this, + SymmetricEss.ChannelId.ACTIVE_DISCHARGE_ENERGY); + private final CalculateEnergyFromPower calculateDcChargeEnergy = new CalculateEnergyFromPower(this, + HybridEss.ChannelId.DC_CHARGE_ENERGY); + private final CalculateEnergyFromPower calculateDcDischargeEnergy = new CalculateEnergyFromPower(this, + HybridEss.ChannelId.DC_DISCHARGE_ENERGY); + + @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) + private volatile Timedata timedata = null; + + @Reference(cardinality = ReferenceCardinality.MANDATORY) + private BridgeHttpFactory httpBridgeFactory; + private BridgeHttp httpBridge; + + private String baseUrl; + private Integer latestGridPw = 0; + private Integer latestPvPw = 0; + private Integer latestPcsPw = 0; + private Integer latestConsPw = 0; + private Integer latestBatteryStatus = -1; + private Integer latestGridStatus = -1; + + public SamsungEssImpl() { + super(// + OpenemsComponent.ChannelId.values(), // + SymmetricEss.ChannelId.values(), // + SamsungEss.ChannelId.values(), // + EssDcCharger.ChannelId.values(), // + HybridEss.ChannelId.values() // + // + ); + } + + @Activate + private void activate(ComponentContext context, Config config) { + super.activate(context, config.id(), config.alias(), config.enabled()); + this.baseUrl = "http://" + config.ip(); + this.httpBridge = this.httpBridgeFactory.get(); + this._setCapacity(config.capacity()); + this._setGridMode(GridMode.ON_GRID); // Has no Backup function + + if (!this.isEnabled()) { + return; + } + + this.httpBridge.subscribeJsonEveryCycle(this.baseUrl + "/R3EMSAPP_REAL.ems?file=ESSRealtimeStatus.json", + this::fetchAndUpdateEssRealtimeStatus); + } + + @Override + @Deactivate + protected void deactivate() { + this.httpBridgeFactory.unget(this.httpBridge); + this.httpBridge = null; + super.deactivate(); + } + + @Override + public void handleEvent(Event event) { + if (!this.isEnabled()) { + return; + } + + switch (event.getTopic()) { + case EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE: + this.calculateEnergy(); + break; + } + } + + private void fetchAndUpdateEssRealtimeStatus(HttpResponse result, HttpError error) { + Integer pvPw = null; + Integer pcsPw = null; + Integer gridPw = null; + Integer consPw = null; + Integer batteryStatus = null; + Integer gridStatus = null; + Integer soc = null; + + if (error != null) { + this.logDebug(this.log, error.getMessage()); + + } else { + try { + var response = getAsJsonObject(result.data()); + var essRealtimeStatus = getAsJsonObject(response, "ESSRealtimeStatus"); + pvPw = round(getAsFloat(essRealtimeStatus, "PvPw") * 1000); + pcsPw = round(getAsFloat(essRealtimeStatus, "PcsPw")); + gridPw = round(getAsFloat(essRealtimeStatus, "GridPw")); + consPw = round(getAsFloat(essRealtimeStatus, "ConsPw")); + batteryStatus = getAsInt(essRealtimeStatus, "BtStusCd"); + gridStatus = getAsInt(essRealtimeStatus, "GridStusCd"); + soc = round(getAsInt(essRealtimeStatus, "BtSoc")); + + } catch (OpenemsNamedException e) { + this.logDebug(this.log, e.getMessage()); + } + } + + var dcDischargePower = switch (batteryStatus) { + // Battery is in Discharge mode + case 0 -> null; + // Battery is in Charge mode + case 1 -> pcsPw; + // Battery is in Idle mode + case 2 -> 0; + // Handle unknown status codes + default -> { + this.logWarn(this.log, "Unknown Battery Status Code: " + batteryStatus); + yield null; + } + }; + + this._setSlaveCommunicationFailed(error != null); + this._setActivePower(pcsPw - pvPw); + this._setDcDischargePower(dcDischargePower); + this._setSoc(soc); + + this.latestPvPw = pvPw; + this.latestPcsPw = pcsPw; + this.latestGridPw = gridPw; + this.latestConsPw = consPw; + this.latestBatteryStatus = batteryStatus; + this.latestGridStatus = gridStatus; + } + + @Override + public String debugLog() { + return "SoC:" + this.getSoc().asString() // + + "|L:" + this.getActivePower().asString(); + } + + @Override + public Timedata getTimedata() { + return this.timedata; + } + + @Override + public Integer getSurplusPower() { + // Adjust the sign of gridPw and pcsPw based on the status codes + if (this.latestGridStatus == 1) { + this.latestGridPw = -this.latestGridPw; + } + if (this.latestBatteryStatus == 0) { + this.latestPcsPw = -this.latestPcsPw; + } + + // Calculate surplus power + double surplusPower = (this.latestGridPw + this.latestPvPw) - (this.latestPcsPw + this.latestConsPw); + // Return the surplus power or 'null' if there is no surplus power + return surplusPower > 0 ? (int) surplusPower : null; + } + + private void calculateEnergy() { + // Calculate AC Energy + var activePower = this.getActivePowerChannel().getNextValue().get(); + if (activePower == null) { + // Not available + this.calculateAcChargeEnergy.update(null); + this.calculateAcDischargeEnergy.update(null); + this.calculateDcChargeEnergy.update(null); + this.calculateDcDischargeEnergy.update(null); + } else { + if (activePower > 0) { + // Discharge + this.calculateAcChargeEnergy.update(0); + this.calculateAcDischargeEnergy.update(activePower); + this.calculateDcChargeEnergy.update(0); + this.calculateDcDischargeEnergy.update(activePower); + } else { + // Charge + this.calculateAcChargeEnergy.update(activePower * -1); + this.calculateAcDischargeEnergy.update(0); + this.calculateDcChargeEnergy.update(activePower * -1); + this.calculateDcDischargeEnergy.update(0); + } + } + } + +} diff --git a/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/gridmeter/Config.java b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/gridmeter/Config.java new file mode 100644 index 00000000000..23a064d4734 --- /dev/null +++ b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/gridmeter/Config.java @@ -0,0 +1,29 @@ +package io.openems.edge.ess.samsung.gridmeter; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +import io.openems.edge.meter.api.MeterType; + +@ObjectClassDefinition(// + name = "Samsung ESS Grid-Meter", // + description = "Implements the Samsung ESS Grid-Meter.") +@interface Config { + + @AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component") + String id() default "meter0"; + + @AttributeDefinition(name = "Alias", description = "Human-readable name of this Component; defaults to Component-ID") + String alias() default ""; + + @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?") + boolean enabled() default true; + + @AttributeDefinition(name = "IP-Address", description = "The IP address of the ESS.") + String ip(); + + @AttributeDefinition(name = "Meter-Type", description = "What is measured by this Meter?") + MeterType type() default MeterType.GRID; + + String webconsole_configurationFactory_nameHint() default "Samsung ESS Grid-Meter [{id}]"; +} \ No newline at end of file diff --git a/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/gridmeter/SamsungEssGridMeter.java b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/gridmeter/SamsungEssGridMeter.java new file mode 100644 index 00000000000..169099b62fa --- /dev/null +++ b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/gridmeter/SamsungEssGridMeter.java @@ -0,0 +1,87 @@ +package io.openems.edge.ess.samsung.gridmeter; + +import org.osgi.service.event.EventHandler; + +import io.openems.common.channel.Level; +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.channel.StateChannel; +import io.openems.edge.common.channel.value.Value; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.meter.api.ElectricityMeter; +import io.openems.edge.pvinverter.api.ManagedSymmetricPvInverter; + +public interface SamsungEssGridMeter + extends ElectricityMeter, OpenemsComponent, EventHandler, ManagedSymmetricPvInverter { + + public static enum ChannelId implements io.openems.edge.common.channel.ChannelId { + /** + * Warning when one or more Inverters are not reachable. + * + *
        + *
      • Type: State + *
      + */ + GRID_COMMUNICATION_FAILED(Doc.of(Level.FAULT) // + .text("Samsung Grid Meter not reachable!")), + /** + * Measures the power imported from or exported to the grid. + * + *
        + *
      • Type: Double
      • + *
      + */ + GRID_PW(Doc.of(OpenemsType.DOUBLE) // + .text("PV Power")); + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#GRID_PW} Channel. + * + * @param value the next value + */ + public default void _setPvPw(double value) { + this.channel(ChannelId.GRID_PW).setNextValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#SLAVE_COMMUNICATION_FAILED}. + * + * @return the Channel + */ + public default StateChannel getSlaveCommunicationFailedChannel() { + return this.channel(ChannelId.GRID_COMMUNICATION_FAILED); + } + + /** + * Gets the Slave Communication Failed State. See + * {@link ChannelId#SLAVE_COMMUNICATION_FAILED}. + * + * @return the Channel {@link Value} + */ + public default Value getSlaveCommunicationFailed() { + return this.getSlaveCommunicationFailedChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on + * {@link ChannelId#SLAVE_COMMUNICATION_FAILED} Channel. + * + * @param value the next value + */ + public default void _setSlaveCommunicationFailed(boolean value) { + this.getSlaveCommunicationFailedChannel().setNextValue(value); + } + +} diff --git a/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/gridmeter/SamsungEssGridMeterImpl.java b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/gridmeter/SamsungEssGridMeterImpl.java new file mode 100644 index 00000000000..aafac47ce2f --- /dev/null +++ b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/gridmeter/SamsungEssGridMeterImpl.java @@ -0,0 +1,194 @@ +package io.openems.edge.ess.samsung.gridmeter; + +import static io.openems.common.utils.JsonUtils.getAsFloat; +import static io.openems.common.utils.JsonUtils.getAsInt; +import static io.openems.common.utils.JsonUtils.getAsJsonObject; +import static java.lang.Math.round; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventHandler; +import org.osgi.service.event.propertytypes.EventTopics; +import org.osgi.service.metatype.annotations.Designate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.bridge.http.api.BridgeHttp; +import io.openems.edge.bridge.http.api.BridgeHttpFactory; +import io.openems.edge.bridge.http.api.HttpError; +import io.openems.edge.bridge.http.api.HttpResponse; +import io.openems.edge.common.component.AbstractOpenemsComponent; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.event.EdgeEventConstants; +import io.openems.edge.meter.api.ElectricityMeter; +import io.openems.edge.meter.api.MeterType; +import io.openems.edge.timedata.api.Timedata; +import io.openems.edge.timedata.api.TimedataProvider; +import io.openems.edge.timedata.api.utils.CalculateEnergyFromPower; + +@Designate(ocd = Config.class, factory = true) +@Component(// + name = "Samsung.ESS.Grid-Meter", // + immediate = true, // + configurationPolicy = ConfigurationPolicy.REQUIRE) + +@EventTopics({ // + EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE, // +}) +public class SamsungEssGridMeterImpl extends AbstractOpenemsComponent + implements SamsungEssGridMeter, ElectricityMeter, OpenemsComponent, EventHandler, TimedataProvider { + + private final Logger log = LoggerFactory.getLogger(SamsungEssGridMeterImpl.class); + private final CalculateEnergyFromPower calculateProductionEnergy = new CalculateEnergyFromPower(this, + ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY); + private final CalculateEnergyFromPower calculateConsumptionEnergy = new CalculateEnergyFromPower(this, + ElectricityMeter.ChannelId.ACTIVE_CONSUMPTION_ENERGY); + + @Reference + protected ConfigurationAdmin cm; + + @Reference(cardinality = ReferenceCardinality.MANDATORY) + private BridgeHttpFactory httpBridgeFactory; + private BridgeHttp httpBridge; + + @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) + private volatile Timedata timedata; + + private String currentGridStatus = "Unknown"; + private String baseUrl; + private Config config; + + public SamsungEssGridMeterImpl() { + super(// + OpenemsComponent.ChannelId.values(), // + ElectricityMeter.ChannelId.values(), // + SamsungEssGridMeter.ChannelId.values() // + ); + ElectricityMeter.calculatePhasesFromActivePower(this); + } + + @Activate + private void activate(ComponentContext context, Config config) { + super.activate(context, config.id(), config.alias(), config.enabled()); + this.baseUrl = "http://" + config.ip(); + this.httpBridge = this.httpBridgeFactory.get(); + this.config = config; + + if (!this.isEnabled()) { + return; + } + + this.httpBridge.subscribeJsonEveryCycle(this.baseUrl + "/R3EMSAPP_REAL.ems?file=ESSRealtimeStatus.json", + this::fetchAndUpdateEssRealtimeStatus); + } + + @Override + @Deactivate + protected void deactivate() { + this.httpBridgeFactory.unget(this.httpBridge); + this.httpBridge = null; + super.deactivate(); + } + + @Override + public void handleEvent(Event event) { + if (!this.isEnabled()) { + return; + } + + switch (event.getTopic()) { + case EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE: + this.calculateEnergy(); // Call the calculateEnergy method here + break; + } + } + + private void fetchAndUpdateEssRealtimeStatus(HttpResponse result, HttpError error) { + Integer gridPw = null; + String currentGridStatus = "Unknown"; + + if (error != null) { + this.logDebug(this.log, error.getMessage()); + } else { + try { + + var response = getAsJsonObject(result.data()); + var essRealtimeStatus = getAsJsonObject(response, "ESSRealtimeStatus"); + + gridPw = round(getAsFloat(essRealtimeStatus, "GridPw") * 1000); + var gridStatusCode = getAsInt(essRealtimeStatus, "GridStusCd"); + + switch (gridStatusCode) { + case 0: + // Buy from Grid is positive + currentGridStatus = "Buy from Grid"; + break; + + case 1: + // Sell to Grid is negative + gridPw = -gridPw; + currentGridStatus = "Sell to Grid"; + + break; + default: + // Handle unknown status codes if needed + currentGridStatus = "Unknown"; + gridPw = 0; + + } + } catch (OpenemsNamedException e) { + this.logDebug(this.log, e.getMessage()); + } + } + + this._setActivePower(gridPw); + + this.currentGridStatus = currentGridStatus; + } + + private void calculateEnergy() { + Integer activePower = this.getActivePower().orElse(null); + if (activePower == null) { + // Not available + this.calculateProductionEnergy.update(null); + this.calculateConsumptionEnergy.update(null); + } else if (activePower > 0) { + // Buy-From-Grid + this.calculateProductionEnergy.update(activePower); + this.calculateConsumptionEnergy.update(0); + } else { + // Sell-To-Grid + this.calculateProductionEnergy.update(0); + this.calculateConsumptionEnergy.update(-activePower); + } + } + + @Override + public String debugLog() { + return "L:" + this.getActivePower().asString() // + + " |Status: " + this.currentGridStatus; + } + + @Override + public Timedata getTimedata() { + return this.timedata; + } + + @Override + public MeterType getMeterType() { + return this.config.type(); + } + +} \ No newline at end of file diff --git a/io.openems.edge.ess.samsung/test/.gitignore b/io.openems.edge.ess.samsung/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/charger/MyConfig.java b/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/charger/MyConfig.java new file mode 100644 index 00000000000..643021116ee --- /dev/null +++ b/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/charger/MyConfig.java @@ -0,0 +1,62 @@ +package io.openems.edge.ess.samsung.charger; + +import io.openems.common.test.AbstractComponentConfig; +import io.openems.edge.meter.api.MeterType; + +@SuppressWarnings("all") +public class MyConfig extends AbstractComponentConfig implements Config { + + protected static class Builder { + private String id; + private String ip; + private MeterType type; + + private Builder() { + } + + public Builder setId(String id) { + this.id = id; + return this; + } + + public Builder setIp(String ip) { + this.ip = ip; + return this; + } + + public Builder setType(MeterType type) { + this.type = type; + return this; + } + + public MyConfig build() { + return new MyConfig(this); + } + } + + /** + * Create a Config builder. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new Builder(); + } + + private final Builder builder; + + private MyConfig(Builder builder) { + super(Config.class, builder.id); + this.builder = builder; + } + + @Override + public String ip() { + return this.builder.ip; + } + + @Override + public MeterType type() { + return this.builder.type; + } +} \ No newline at end of file diff --git a/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/charger/SamsungEssChargerImplTest.java b/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/charger/SamsungEssChargerImplTest.java new file mode 100644 index 00000000000..ba3891b1616 --- /dev/null +++ b/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/charger/SamsungEssChargerImplTest.java @@ -0,0 +1,25 @@ +package io.openems.edge.ess.samsung.charger; + +import org.junit.Test; + +import io.openems.edge.bridge.http.dummy.DummyBridgeHttpFactory; +import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.meter.api.MeterType; + +public class SamsungEssChargerImplTest { + + private static final String COMPONENT_ID = "charger0"; + + @Test + public void test() throws Exception { + new ComponentTest(new SamsungEssChargerImpl()) // + .addReference("httpBridgeFactory", DummyBridgeHttpFactory.ofDummyBridge()) // + .activate(MyConfig.create() // + .setId(COMPONENT_ID) // + .setIp("127.0.0.1") // + .setType(MeterType.PRODUCTION) // + .build()) // + ; + } + +} \ No newline at end of file diff --git a/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/ess/MyConfig.java b/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/ess/MyConfig.java new file mode 100644 index 00000000000..b6bdecba198 --- /dev/null +++ b/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/ess/MyConfig.java @@ -0,0 +1,73 @@ +package io.openems.edge.ess.samsung.ess; + +import io.openems.common.test.AbstractComponentConfig; +import io.openems.edge.ess.power.api.Phase; + +@SuppressWarnings("all") +public class MyConfig extends AbstractComponentConfig implements Config { + + protected static class Builder { + private String id; + private String ip; + private Phase phase; + private int capacity; + + private Builder() { + } + + public Builder setId(String id) { + this.id = id; + return this; + } + + public Builder setIp(String ip) { + this.ip = ip; + return this; + } + + public Builder setPhase(Phase phase) { + this.phase = phase; + return this; + } + + public Builder setCapacity(int capacity) { + this.capacity = capacity; + return this; + } + + public MyConfig build() { + return new MyConfig(this); + } + } + + /** + * Create a Config builder. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new Builder(); + } + + private final Builder builder; + + private MyConfig(Builder builder) { + super(Config.class, builder.id); + this.builder = builder; + } + + @Override + public String ip() { + return this.builder.ip; + } + + @Override + public Phase phase() { + return this.builder.phase; + } + + @Override + public int capacity() { + return this.builder.capacity; + } +} \ No newline at end of file diff --git a/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/ess/SamsungEssImplTest.java b/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/ess/SamsungEssImplTest.java new file mode 100644 index 00000000000..c67ca193fad --- /dev/null +++ b/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/ess/SamsungEssImplTest.java @@ -0,0 +1,26 @@ +package io.openems.edge.ess.samsung.ess; + +import org.junit.Test; + +import io.openems.edge.bridge.http.dummy.DummyBridgeHttpFactory; +import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.ess.power.api.Phase; + +public class SamsungEssImplTest { + + private static final String COMPONENT_ID = "charger0"; + + @Test + public void test() throws Exception { + new ComponentTest(new SamsungEssImpl()) // + .addReference("httpBridgeFactory", DummyBridgeHttpFactory.ofDummyBridge()) // + .activate(MyConfig.create() // + .setId(COMPONENT_ID) // + .setIp("127.0.0.1") // + .setPhase(Phase.L1) // + .setCapacity(3600) // + .build()) // + ; + } + +} \ No newline at end of file diff --git a/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/gridmeter/MyConfig.java b/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/gridmeter/MyConfig.java new file mode 100644 index 00000000000..fc924bc6e93 --- /dev/null +++ b/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/gridmeter/MyConfig.java @@ -0,0 +1,62 @@ +package io.openems.edge.ess.samsung.gridmeter; + +import io.openems.common.test.AbstractComponentConfig; +import io.openems.edge.meter.api.MeterType; + +@SuppressWarnings("all") +public class MyConfig extends AbstractComponentConfig implements Config { + + protected static class Builder { + private String id; + private String ip; + private MeterType type; + + private Builder() { + } + + public Builder setId(String id) { + this.id = id; + return this; + } + + public Builder setIp(String ip) { + this.ip = ip; + return this; + } + + public Builder setType(MeterType type) { + this.type = type; + return this; + } + + public MyConfig build() { + return new MyConfig(this); + } + } + + /** + * Create a Config builder. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new Builder(); + } + + private final Builder builder; + + private MyConfig(Builder builder) { + super(Config.class, builder.id); + this.builder = builder; + } + + @Override + public String ip() { + return this.builder.ip; + } + + @Override + public MeterType type() { + return this.builder.type; + } +} \ No newline at end of file diff --git a/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/gridmeter/SamsungEssGridMeterImplTest.java b/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/gridmeter/SamsungEssGridMeterImplTest.java new file mode 100644 index 00000000000..50d708ab648 --- /dev/null +++ b/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/gridmeter/SamsungEssGridMeterImplTest.java @@ -0,0 +1,25 @@ +package io.openems.edge.ess.samsung.gridmeter; + +import org.junit.Test; + +import io.openems.edge.bridge.http.dummy.DummyBridgeHttpFactory; +import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.meter.api.MeterType; + +public class SamsungEssGridMeterImplTest { + + private static final String COMPONENT_ID = "charger0"; + + @Test + public void test() throws Exception { + new ComponentTest(new SamsungEssGridMeterImpl()) // + .addReference("httpBridgeFactory", DummyBridgeHttpFactory.ofDummyBridge()) // + .activate(MyConfig.create() // + .setId(COMPONENT_ID) // + .setIp("127.0.0.1") // + .setType(MeterType.GRID) // + .build()) // + ; + } + +} \ No newline at end of file From 27eaf50221908899a03186d469ef1ea14d8e2a2d Mon Sep 17 00:00:00 2001 From: Hannes Date: Mon, 17 Jun 2024 14:52:52 +0200 Subject: [PATCH 044/173] UI: fix ion-row css-syntax-error (#2628) --- ui/src/app/shared/footer/footer.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/src/app/shared/footer/footer.ts b/ui/src/app/shared/footer/footer.ts index 38539365640..926db2d72d0 100644 --- a/ui/src/app/shared/footer/footer.ts +++ b/ui/src/app/shared/footer/footer.ts @@ -21,11 +21,11 @@ import { Role } from "../type/role"; width: 100%; font-size: 14px !important; - ion-row { + :is(ion-row) { text-align: center; } - ion-item { + :is(ion-item) { --min-height: initial !important; font-size: inherit; } From 93a384a86a8986a85d083d07cbfbcbdfba85df30 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Jun 2024 13:56:44 +0200 Subject: [PATCH 045/173] Bump org.apache.felix:org.apache.felix.http.jetty from 5.1.16 to 5.1.20 in /cnf (#2673) * Bump org.apache.felix:org.apache.felix.http.jetty in /cnf Bumps org.apache.felix:org.apache.felix.http.jetty from 5.1.16 to 5.1.20. --- updated-dependencies: - dependency-name: org.apache.felix:org.apache.felix.http.jetty 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 29b68ef06d0..2231de4e1b2 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -203,7 +203,7 @@ org.apache.felix org.apache.felix.http.jetty - 5.1.16 + 5.1.20 diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index e4c9ac0e3c4..03d14f79f83 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -104,7 +104,7 @@ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ org.apache.felix.eventadmin;version='[1.6.4,1.6.5)',\ org.apache.felix.fileinstall;version='[3.7.4,3.7.5)',\ - org.apache.felix.http.jetty;version='[5.1.16,5.1.17)',\ + org.apache.felix.http.jetty;version='[5.1.20,5.1.21)',\ org.apache.felix.http.servlet-api;version='[3.0.0,3.0.1)',\ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index 003fdb945f4..6e383385d34 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -400,7 +400,7 @@ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ org.apache.felix.eventadmin;version='[1.6.4,1.6.5)',\ org.apache.felix.fileinstall;version='[3.7.4,3.7.5)',\ - org.apache.felix.http.jetty;version='[5.1.16,5.1.17)',\ + org.apache.felix.http.jetty;version='[5.1.20,5.1.21)',\ org.apache.felix.http.servlet-api;version='[3.0.0,3.0.1)',\ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ From e51be8db51868ab8ef1e75936ee5d03603d95675 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Jun 2024 14:09:58 +0200 Subject: [PATCH 046/173] Bump @stylistic/eslint-plugin from 2.1.0 to 2.2.1 in /ui (#2674) Bumps [@stylistic/eslint-plugin](https://github.com/eslint-stylistic/eslint-stylistic/tree/HEAD/packages/eslint-plugin) from 2.1.0 to 2.2.1. - [Release notes](https://github.com/eslint-stylistic/eslint-stylistic/releases) - [Changelog](https://github.com/eslint-stylistic/eslint-stylistic/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint-stylistic/eslint-stylistic/commits/v2.2.1/packages/eslint-plugin) --- updated-dependencies: - dependency-name: "@stylistic/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 153 ++++++++++++++++++++++--------------------- ui/package.json | 2 +- 2 files changed, 78 insertions(+), 77 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 13cd93805a0..b6b69c0cf64 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -52,7 +52,7 @@ "@angular/compiler-cli": "^16.2.12", "@angular/language-service": "^16.2.12", "@ionic/angular-toolkit": "^11.0.1", - "@stylistic/eslint-plugin": "^2.1.0", + "@stylistic/eslint-plugin": "^2.2.1", "@types/jasmine": "~4.3.6", "@types/jasminewd2": "~2.0.13", "@types/node": "^20.12.6", @@ -3959,15 +3959,15 @@ } }, "node_modules/@stylistic/eslint-plugin": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.1.0.tgz", - "integrity": "sha512-cBBowKP2u/+uE5CzgH5w8pE9VKqcM7BXdIDPIbGt2rmLJGnA6MJPr9vYGaqgMoJFs7R/FzsMQerMvvEP40g2uw==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.2.1.tgz", + "integrity": "sha512-YErqfwWFbRCpkyPtrcVYaJhvEn9aXE4WzxxkZ7Q3OKS4QD9CE6qZjzEw5DhcA2wL3Jo6JbzSB3/stJMNocGMgQ==", "dev": true, "dependencies": { - "@stylistic/eslint-plugin-js": "2.1.0", - "@stylistic/eslint-plugin-jsx": "2.1.0", - "@stylistic/eslint-plugin-plus": "2.1.0", - "@stylistic/eslint-plugin-ts": "2.1.0", + "@stylistic/eslint-plugin-js": "2.2.1", + "@stylistic/eslint-plugin-jsx": "2.2.1", + "@stylistic/eslint-plugin-plus": "2.2.1", + "@stylistic/eslint-plugin-ts": "2.2.1", "@types/eslint": "^8.56.10" }, "engines": { @@ -3978,9 +3978,9 @@ } }, "node_modules/@stylistic/eslint-plugin-js": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.1.0.tgz", - "integrity": "sha512-gdXUjGNSsnY6nPyqxu6lmDTtVrwCOjun4x8PUn0x04d5ucLI74N3MT1Q0UhdcOR9No3bo5PGDyBgXK+KmD787A==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.2.1.tgz", + "integrity": "sha512-M2dQkKw2R4R+b1SJ/xElJ9bDVq/vCI31VpIIxkZD9KXCqbUHvtsGpZH3eO6MzmFWOZj4PfNdEQdP332MtqjCPg==", "dev": true, "dependencies": { "@types/eslint": "^8.56.10", @@ -4008,12 +4008,12 @@ } }, "node_modules/@stylistic/eslint-plugin-js/node_modules/espree": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.0.1.tgz", - "integrity": "sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", "dev": true, "dependencies": { - "acorn": "^8.11.3", + "acorn": "^8.12.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.0.0" }, @@ -4025,12 +4025,12 @@ } }, "node_modules/@stylistic/eslint-plugin-jsx": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-jsx/-/eslint-plugin-jsx-2.1.0.tgz", - "integrity": "sha512-mMD7S+IndZo2vxmwpHVTCwx2O1VdtE5tmpeNwgaEcXODzWV1WTWpnsc/PECQKIr/mkLPFWiSIqcuYNhQ/3l6AQ==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-jsx/-/eslint-plugin-jsx-2.2.1.tgz", + "integrity": "sha512-J/R4tU38v8gVqKPy6Mh22dq8btLSPWK06SuRc/ryOxT8LpW2ZdcSDP4HNvQiOte0Wy9xzgKJHP4JlYauDZ/oVw==", "dev": true, "dependencies": { - "@stylistic/eslint-plugin-js": "^2.1.0", + "@stylistic/eslint-plugin-js": "^2.2.1", "@types/eslint": "^8.56.10", "estraverse": "^5.3.0", "picomatch": "^4.0.2" @@ -4064,26 +4064,26 @@ } }, "node_modules/@stylistic/eslint-plugin-plus": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-2.1.0.tgz", - "integrity": "sha512-S5QAlgYXESJaSBFhBSBLZy9o36gXrXQwWSt6QkO+F0SrT9vpV5JF/VKoh+ojO7tHzd8Ckmyouq02TT9Sv2B0zQ==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-2.2.1.tgz", + "integrity": "sha512-VGdTcQzZ/cZNcJnvjDos1VLzUerPapvYCVSCQZEhupMtmxt+mbITiJWzLLHYNfqGBnW7ABqViLfob+s3Q2GcKw==", "dev": true, "dependencies": { "@types/eslint": "^8.56.10", - "@typescript-eslint/utils": "^7.8.0" + "@typescript-eslint/utils": "^7.12.0" }, "peerDependencies": { "eslint": "*" } }, "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/scope-manager": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.0.tgz", - "integrity": "sha512-ZrMCe1R6a01T94ilV13egvcnvVJ1pxShkE0+NDjDzH4nvG1wXpwsVI5bZCvE7AEDH1mXEx5tJSVR68bLgG7Dng==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.1.tgz", + "integrity": "sha512-adbXNVEs6GmbzaCpymHQ0MB6E4TqoiVbC0iqG3uijR8ZYfpAXMGttouQzF4Oat3P2GxDVIrg7bMI/P65LiQZdg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0" + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/visitor-keys": "7.13.1" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -4094,9 +4094,9 @@ } }, "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.0.tgz", - "integrity": "sha512-QWuwm9wcGMAuTsxP+qz6LBBd3Uq8I5Nv8xb0mk54jmNoCyDspnMvVsOxI6IsMmway5d1S9Su2+sCKv1st2l6eA==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.1.tgz", + "integrity": "sha512-7K7HMcSQIAND6RBL4kDl24sG/xKM13cA85dc7JnmQXw2cBDngg7c19B++JzvJHRG3zG36n9j1i451GBzRuHchw==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -4107,13 +4107,13 @@ } }, "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.0.tgz", - "integrity": "sha512-cAvBvUoobaoIcoqox1YatXOnSl3gx92rCZoMRPzMNisDiM12siGilSM4+dJAekuuHTibI2hVC2fYK79iSFvWjw==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.1.tgz", + "integrity": "sha512-uxNr51CMV7npU1BxZzYjoVz9iyjckBduFBP0S5sLlh1tXYzHzgZ3BR9SVsNed+LmwKrmnqN3Kdl5t7eZ5TS1Yw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0", + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/visitor-keys": "7.13.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -4135,15 +4135,15 @@ } }, "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.0.tgz", - "integrity": "sha512-jceD8RgdKORVnB4Y6BqasfIkFhl4pajB1wVxrF4akxD2QPM8GNYjgGwEzYS+437ewlqqrg7Dw+6dhdpjMpeBFQ==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.1.tgz", + "integrity": "sha512-h5MzFBD5a/Gh/fvNdp9pTfqJAbuQC4sCN2WzuXme71lqFJsZtLbjxfSk4r3p02WIArOF9N94pdsLiGutpDbrXQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.13.0", - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/typescript-estree": "7.13.0" + "@typescript-eslint/scope-manager": "7.13.1", + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/typescript-estree": "7.13.1" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -4157,12 +4157,12 @@ } }, "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.0.tgz", - "integrity": "sha512-nxn+dozQx+MK61nn/JP+M4eCkHDSxSLDpgE3WcQo0+fkjEolnaB5jswvIKC4K56By8MMgIho7f1PVxERHEo8rw==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.1.tgz", + "integrity": "sha512-k/Bfne7lrP7hcb7m9zSsgcBmo+8eicqqfNAJ7uUY+jkTFpKeH2FSkWpFRtimBxgkyvqfu9jTPRbYOvud6isdXA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/types": "7.13.1", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -4227,14 +4227,14 @@ } }, "node_modules/@stylistic/eslint-plugin-ts": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-ts/-/eslint-plugin-ts-2.1.0.tgz", - "integrity": "sha512-2ioFibufHYBALx2TBrU4KXovCkN8qCqcb9yIHc0fyOfTaO5jw4d56WW7YRcF3Zgde6qFyXwAN6z/+w4pnmos1g==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-ts/-/eslint-plugin-ts-2.2.1.tgz", + "integrity": "sha512-2AbpXGGorCEzDryth7RhOMJWlko+sxSs1lxL2tSXB5H/EffmXgLn1tMoMKgwYJW3s6v0BxJRr5BWj9B9JaZTUQ==", "dev": true, "dependencies": { - "@stylistic/eslint-plugin-js": "2.1.0", + "@stylistic/eslint-plugin-js": "2.2.1", "@types/eslint": "^8.56.10", - "@typescript-eslint/utils": "^7.8.0" + "@typescript-eslint/utils": "^7.12.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4244,13 +4244,13 @@ } }, "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/scope-manager": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.0.tgz", - "integrity": "sha512-ZrMCe1R6a01T94ilV13egvcnvVJ1pxShkE0+NDjDzH4nvG1wXpwsVI5bZCvE7AEDH1mXEx5tJSVR68bLgG7Dng==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.1.tgz", + "integrity": "sha512-adbXNVEs6GmbzaCpymHQ0MB6E4TqoiVbC0iqG3uijR8ZYfpAXMGttouQzF4Oat3P2GxDVIrg7bMI/P65LiQZdg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0" + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/visitor-keys": "7.13.1" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -4261,9 +4261,9 @@ } }, "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.0.tgz", - "integrity": "sha512-QWuwm9wcGMAuTsxP+qz6LBBd3Uq8I5Nv8xb0mk54jmNoCyDspnMvVsOxI6IsMmway5d1S9Su2+sCKv1st2l6eA==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.1.tgz", + "integrity": "sha512-7K7HMcSQIAND6RBL4kDl24sG/xKM13cA85dc7JnmQXw2cBDngg7c19B++JzvJHRG3zG36n9j1i451GBzRuHchw==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -4274,13 +4274,13 @@ } }, "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.0.tgz", - "integrity": "sha512-cAvBvUoobaoIcoqox1YatXOnSl3gx92rCZoMRPzMNisDiM12siGilSM4+dJAekuuHTibI2hVC2fYK79iSFvWjw==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.1.tgz", + "integrity": "sha512-uxNr51CMV7npU1BxZzYjoVz9iyjckBduFBP0S5sLlh1tXYzHzgZ3BR9SVsNed+LmwKrmnqN3Kdl5t7eZ5TS1Yw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0", + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/visitor-keys": "7.13.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -4302,15 +4302,15 @@ } }, "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.0.tgz", - "integrity": "sha512-jceD8RgdKORVnB4Y6BqasfIkFhl4pajB1wVxrF4akxD2QPM8GNYjgGwEzYS+437ewlqqrg7Dw+6dhdpjMpeBFQ==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.1.tgz", + "integrity": "sha512-h5MzFBD5a/Gh/fvNdp9pTfqJAbuQC4sCN2WzuXme71lqFJsZtLbjxfSk4r3p02WIArOF9N94pdsLiGutpDbrXQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.13.0", - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/typescript-estree": "7.13.0" + "@typescript-eslint/scope-manager": "7.13.1", + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/typescript-estree": "7.13.1" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -4324,12 +4324,12 @@ } }, "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.0.tgz", - "integrity": "sha512-nxn+dozQx+MK61nn/JP+M4eCkHDSxSLDpgE3WcQo0+fkjEolnaB5jswvIKC4K56By8MMgIho7f1PVxERHEo8rw==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.1.tgz", + "integrity": "sha512-k/Bfne7lrP7hcb7m9zSsgcBmo+8eicqqfNAJ7uUY+jkTFpKeH2FSkWpFRtimBxgkyvqfu9jTPRbYOvud6isdXA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/types": "7.13.1", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -5462,9 +5462,10 @@ } }, "node_modules/acorn": { - "version": "8.11.3", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", + "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", "dev": true, - "license": "MIT", "bin": { "acorn": "bin/acorn" }, diff --git a/ui/package.json b/ui/package.json index 1aa057eb7bf..0d3a435f1cc 100644 --- a/ui/package.json +++ b/ui/package.json @@ -47,7 +47,7 @@ "@angular/compiler-cli": "^16.2.12", "@angular/language-service": "^16.2.12", "@ionic/angular-toolkit": "^11.0.1", - "@stylistic/eslint-plugin": "^2.1.0", + "@stylistic/eslint-plugin": "^2.2.1", "@types/jasmine": "~4.3.6", "@types/jasminewd2": "~2.0.13", "@types/node": "^20.12.6", From ce7f4cf79c2935cddea970a89927947255e952d0 Mon Sep 17 00:00:00 2001 From: Hannes Date: Wed, 19 Jun 2024 10:34:50 +0200 Subject: [PATCH 047/173] Implement ShellyPro3Em + fix issue in EdgeConfig (#2567) * ShellyPro3Em Implements Shelly Pro 3 EM 3-Phase Meter. https://www.shelly.com/de/products/shop/shelly-pro-3-em-120-a-1 * EdgeConfig: fix parsing of service components Previously `constains()` would match even partly matching factory IDs. This is fixed by a full string compare for the XML file path. This fixes an issue with "Samsung.ESS" not showing up, because there is also a factory ID "Samsung.ESS.Grid-Meter". --------- Co-authored-by: Stefan Feilmeier --- .../componentmanager/EdgeConfigWorker.java | 4 +- .../openems/edge/ess/samsung/ess/Config.java | 2 +- .../edge/ess/samsung/ess/SamsungEssImpl.java | 4 +- io.openems.edge.io.shelly/readme.adoc | 1 + .../edge/io/shelly/shellypro3em/Config.java | 30 +++ .../shelly/shellypro3em/IoShellyPro3Em.java | 117 ++++++++++ .../shellypro3em/IoShellyPro3EmImpl.java | 219 ++++++++++++++++++ .../shellypro3em/IoShelly3EmImplTest.java | 25 ++ .../edge/io/shelly/shellypro3em/MyConfig.java | 62 +++++ 9 files changed, 459 insertions(+), 5 deletions(-) create mode 100644 io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/Config.java create mode 100644 io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/IoShellyPro3Em.java create mode 100644 io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/IoShellyPro3EmImpl.java create mode 100644 io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3em/IoShelly3EmImplTest.java create mode 100644 io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3em/MyConfig.java diff --git a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/EdgeConfigWorker.java b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/EdgeConfigWorker.java index 23dbf32ea80..9679cfb5a6a 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/EdgeConfigWorker.java +++ b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/EdgeConfigWorker.java @@ -495,8 +495,8 @@ private String[] getNatures(Bundle bundle, Manifest manifest, String factoryPid) var serviceComponents = serviceComponentsString.split(","); // read Service-Component XML files from OSGI-INF folder - for (String serviceComponent : serviceComponents) { - if (!serviceComponent.contains(factoryPid)) { + for (var serviceComponent : serviceComponents) { + if (!serviceComponent.equals("OSGI-INF/" + factoryPid + ".xml")) { // search for correct XML file continue; } diff --git a/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/Config.java b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/Config.java index 9b96d04d16d..02f59e64887 100644 --- a/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/Config.java +++ b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/Config.java @@ -7,7 +7,7 @@ @ObjectClassDefinition(// name = "Samsung ESS", // - description = "Implements the Sasmung ESS Combined System.") + description = "Implements the Samsung ESS System.") @interface Config { @AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component") diff --git a/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/SamsungEssImpl.java b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/SamsungEssImpl.java index d4e04fd5b95..cce31ff8a29 100644 --- a/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/SamsungEssImpl.java +++ b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/SamsungEssImpl.java @@ -41,10 +41,10 @@ @Designate(ocd = Config.class, factory = true) @Component(// - name = "Samsung.ESS", immediate = true, // + name = "Samsung.ESS", // + immediate = true, // configurationPolicy = ConfigurationPolicy.REQUIRE// ) - @EventTopics({ // EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE, // }) diff --git a/io.openems.edge.io.shelly/readme.adoc b/io.openems.edge.io.shelly/readme.adoc index 16eed94af93..220c84fcbb4 100644 --- a/io.openems.edge.io.shelly/readme.adoc +++ b/io.openems.edge.io.shelly/readme.adoc @@ -7,5 +7,6 @@ Compatible with - https://www.shelly.com/en/products/shop/shelly-3-em[Shelly 3EM] - Shelly Plug S - https://www.shelly.com/de/products/shop/shelly-plus-plug-s-1[Shelly Plus Plug S] +- https://www.shelly.com/de/products/shop/shelly-pro-3-em-120-a-1[Shelly Pro 3EM 3-Phase Meter] https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.io.shelly[Source Code icon:github[]] \ No newline at end of file diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/Config.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/Config.java new file mode 100644 index 00000000000..b594f9b1603 --- /dev/null +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/Config.java @@ -0,0 +1,30 @@ +package io.openems.edge.io.shelly.shellypro3em; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +import io.openems.edge.meter.api.MeterType; + +@ObjectClassDefinition( + name = "IO Shelly Pro 3EM", // + description = "Implements the Shelly Pro 3EM Energy Meter.") +@interface Config { + + @AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component") + String id() default "meter0"; + + @AttributeDefinition(name = "Alias", description = "Human-readable name of this Component; defaults to Component-ID") + String alias() default ""; + + @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?") + boolean enabled() default true; + + @AttributeDefinition(name = "Meter-Type", description = "Grid, Production (=default), Consumption") + MeterType type() default MeterType.GRID; + + @AttributeDefinition(name = "IP-Address", description = "The IP address of the Shelly device.") + String ip(); + + String webconsole_configurationFactory_nameHint() default "IO Shelly Pro 3EM [{id}]"; + +} \ No newline at end of file diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/IoShellyPro3Em.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/IoShellyPro3Em.java new file mode 100644 index 00000000000..c5899305afe --- /dev/null +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/IoShellyPro3Em.java @@ -0,0 +1,117 @@ +package io.openems.edge.io.shelly.shellypro3em; + +import io.openems.common.channel.Level; +import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.channel.StateChannel; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.channel.value.Value; + +public interface IoShellyPro3Em extends OpenemsComponent { + + public enum ChannelId implements io.openems.edge.common.channel.ChannelId { + /** + * Phase Sequence Error. + * + *

      + * Represents an error indicating if the sequence of zero-crossing events is + * Phase A followed by Phase C followed by Phase B. The regular succession of + * these zero-crossing events is Phase A followed by Phase B followed by Phase + * C. + * + *

        + *
      • Interface: ShellyPlug + *
      • Type: State + *
      + */ + PHASE_SEQUENCE_ERROR(Doc.of(Level.FAULT) // + .text("Incorrect phase sequence. Expected A-B-C but found A-C-B.")), + + /** + * Power Meter Failure. + * + *

      + * Represents a failure in the power meter, potentially leading to inaccurate or + * missing measurements. + * + *

        + *
      • Interface: ShellyPlug + *
      • Type: State + *
      + */ + POWER_METER_FAILURE(Doc.of(Level.FAULT) // + .text("Power meter failure; unable to record or measure power accurately.")), + + /** + * No Load Error. + * + *

      + * Indicates that the power meter is in a no-load condition and is not + * accumulating the registered energies, therefore, the measured values can be + * discarded. + * + *

        + *
      • Interface: ShellyPlug + *
      • Type: State + *
      + */ + NO_LOAD(Doc.of(Level.FAULT) // + .text("No load condition detected; the power meter is not accumulating energy.")), + + /** + * Slave Communication Failed Fault. + * + *

      + * Indicates a failure in communication with a slave device, which might affect + * system operations. + * + *

        + *
      • Interface: ShellyPlug + *
      • Type: State + *
      + */ + SLAVE_COMMUNICATION_FAILED(Doc.of(Level.FAULT) // + .text("Communication with slave device failed.")); + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } + + /** + * Gets the Channel for {@link ChannelId#SLAVE_COMMUNICATION_FAILED}. + * + * @return the StateChannel representing communication failure with a slave + * device. + */ + public default StateChannel getSlaveCommunicationFailedChannel() { + return this.channel(ChannelId.SLAVE_COMMUNICATION_FAILED); + } + + /** + * Gets the current state of the Slave Communication Failed channel. + * + * @return the Channel {@link Value} indicating whether communication has + * failed. + */ + public default Value getSlaveCommunicationFailed() { + return this.getSlaveCommunicationFailedChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on + * {@link ChannelId#SLAVE_COMMUNICATION_FAILED} Channel. + * + * @param value the next value indicating communication failure state. + */ + public default void _setSlaveCommunicationFailed(boolean value) { + this.getSlaveCommunicationFailedChannel().setNextValue(value); + } + +} diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/IoShellyPro3EmImpl.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/IoShellyPro3EmImpl.java new file mode 100644 index 00000000000..dfa0c2085b4 --- /dev/null +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/IoShellyPro3EmImpl.java @@ -0,0 +1,219 @@ +package io.openems.edge.io.shelly.shellypro3em; + +import static io.openems.common.utils.JsonUtils.getAsFloat; +import static io.openems.common.utils.JsonUtils.getAsJsonObject; +import static io.openems.common.utils.JsonUtils.getAsOptionalJsonArray; +import static io.openems.common.utils.JsonUtils.getAsString; +import static java.lang.Math.round; + +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventHandler; +import org.osgi.service.event.propertytypes.EventTopics; +import org.osgi.service.metatype.annotations.Designate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.bridge.http.api.BridgeHttp; +import io.openems.edge.bridge.http.api.BridgeHttpFactory; +import io.openems.edge.bridge.http.api.HttpError; +import io.openems.edge.bridge.http.api.HttpResponse; +import io.openems.edge.common.component.AbstractOpenemsComponent; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.event.EdgeEventConstants; +import io.openems.edge.meter.api.ElectricityMeter; +import io.openems.edge.meter.api.MeterType; +import io.openems.edge.timedata.api.Timedata; +import io.openems.edge.timedata.api.TimedataProvider; +import io.openems.edge.timedata.api.utils.CalculateEnergyFromPower; + +@Designate(ocd = Config.class, factory = true) +@Component(// + name = "IO.Shelly.Pro.3EM", // + immediate = true, // + configurationPolicy = ConfigurationPolicy.REQUIRE // +) +@EventTopics({ // + EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE, // + EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE // +}) +public class IoShellyPro3EmImpl extends AbstractOpenemsComponent + implements IoShellyPro3Em, ElectricityMeter, OpenemsComponent, TimedataProvider, EventHandler { + + private final CalculateEnergyFromPower calculateProductionEnergy = new CalculateEnergyFromPower(this, + ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY); + private final CalculateEnergyFromPower calculateConsumptionEnergy = new CalculateEnergyFromPower(this, + ElectricityMeter.ChannelId.ACTIVE_CONSUMPTION_ENERGY); + + private final Logger log = LoggerFactory.getLogger(IoShellyPro3EmImpl.class); + + private MeterType meterType = null; + private String baseUrl; + + @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) + private volatile Timedata timedata; + + @Reference() + private BridgeHttpFactory httpBridgeFactory; + private BridgeHttp httpBridge; + + public IoShellyPro3EmImpl() { + super(// + OpenemsComponent.ChannelId.values(), // + ElectricityMeter.ChannelId.values(), // + IoShellyPro3Em.ChannelId.values() // + ); + + ElectricityMeter.calculateSumActivePowerFromPhases(this); + } + + @Activate + protected void activate(ComponentContext context, Config config) { + super.activate(context, config.id(), config.alias(), config.enabled()); + this.meterType = config.type(); + this.baseUrl = "http://" + config.ip(); + this.httpBridge = this.httpBridgeFactory.get(); + + if (this.isEnabled()) { + this.httpBridge.subscribeJsonEveryCycle(this.baseUrl + "/rpc/EM.GetStatus?id=0", this::processHttpResult); + } + } + + @Deactivate + protected void deactivate() { + this.httpBridgeFactory.unget(this.httpBridge); + this.httpBridge = null; + super.deactivate(); + } + + @Override + public String debugLog() { + return "L:" + this.getActivePower().asString(); + } + + @Override + public void handleEvent(Event event) { + if (!this.isEnabled()) { + return; + } + + switch (event.getTopic()) { + case EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE // + -> this.calculateEnergy(); + } + } + + private void processHttpResult(HttpResponse result, HttpError error) { + this._setSlaveCommunicationFailed(result == null); + + Integer activePower = null; + Integer activePowerL1 = null; + Integer activePowerL2 = null; + Integer activePowerL3 = null; + Integer voltageL1 = null; + Integer voltageL2 = null; + Integer voltageL3 = null; + Integer currentL1 = null; + Integer currentL2 = null; + Integer currentL3 = null; + boolean phaseSequenceError = false; + boolean powerMeterFailure = false; + boolean noLoadCondition = false; + + if (error != null) { + this.logDebug(this.log, error.getMessage()); + + } else { + try { + var response = getAsJsonObject(result.data()); + + // Check for 'errors' and process if present + var errors = getAsOptionalJsonArray(response, "errors"); + if (errors.isPresent()) { + for (var e : errors.get()) { + switch (getAsString(e)) { + case "phase_sequence" -> phaseSequenceError = true; + case "power_meter_failure" -> powerMeterFailure = true; + case "no_load" -> noLoadCondition = true; + } + } + } + + // Total Active Power + activePower = round(getAsFloat(response, "total_act_power")); + + // Extract phase data + activePowerL1 = round(getAsFloat(response, "a_act_power")); + voltageL1 = round(getAsFloat(response, "a_voltage") * 1000); + currentL1 = round(getAsFloat(response, "a_current") * 1000); + + activePowerL2 = round(getAsFloat(response, "b_act_power")); + voltageL2 = round(getAsFloat(response, "b_voltage") * 1000); + currentL2 = round(getAsFloat(response, "b_current") * 1000); + + activePowerL3 = round(getAsFloat(response, "c_act_power")); + voltageL3 = round(getAsFloat(response, "c_voltage") * 1000); + currentL3 = round(getAsFloat(response, "c_current") * 1000); + + } catch (OpenemsNamedException e) { + this.logDebug(this.log, e.getMessage()); + } + } + + this._setActivePower(activePower); + this.channel(IoShellyPro3Em.ChannelId.PHASE_SEQUENCE_ERROR).setNextValue(phaseSequenceError); + this.channel(IoShellyPro3Em.ChannelId.NO_LOAD).setNextValue(noLoadCondition); + this.channel(IoShellyPro3Em.ChannelId.POWER_METER_FAILURE).setNextValue(powerMeterFailure); + + this._setActivePowerL1(activePowerL1); + this._setVoltageL1(voltageL1); + this._setCurrentL1(currentL1); + + this._setActivePowerL2(activePowerL2); + this._setVoltageL2(voltageL2); + this._setCurrentL2(currentL2); + + this._setActivePowerL3(activePowerL3); + this._setVoltageL3(voltageL3); + this._setCurrentL3(currentL3); + } + + /** + * Calculate the Energy values from ActivePower. + */ + private void calculateEnergy() { + // Calculate Energy + final var activePower = this.getActivePower().get(); + if (activePower == null) { + this.calculateProductionEnergy.update(null); + this.calculateConsumptionEnergy.update(null); + } else if (activePower >= 0) { + this.calculateProductionEnergy.update(activePower); + this.calculateConsumptionEnergy.update(0); + } else { + this.calculateProductionEnergy.update(0); + this.calculateConsumptionEnergy.update(-activePower); + } + } + + @Override + public Timedata getTimedata() { + return this.timedata; + } + + @Override + public MeterType getMeterType() { + return this.meterType; + } +} diff --git a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3em/IoShelly3EmImplTest.java b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3em/IoShelly3EmImplTest.java new file mode 100644 index 00000000000..29b0136a7a6 --- /dev/null +++ b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3em/IoShelly3EmImplTest.java @@ -0,0 +1,25 @@ +package io.openems.edge.io.shelly.shellypro3em; + +import org.junit.Test; + +import io.openems.edge.bridge.http.dummy.DummyBridgeHttpFactory; +import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.meter.api.MeterType; + +public class IoShelly3EmImplTest { + + private static final String COMPONENT_ID = "io0"; + + @Test + public void test() throws Exception { + new ComponentTest(new IoShellyPro3EmImpl()) // + .addReference("httpBridgeFactory", DummyBridgeHttpFactory.ofDummyBridge()) // + .activate(MyConfig.create() // + .setId(COMPONENT_ID) // + .setIp("127.0.0.1") // + .setType(MeterType.CONSUMPTION_METERED) // + .build()) // + ; + } + +} diff --git a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3em/MyConfig.java b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3em/MyConfig.java new file mode 100644 index 00000000000..68261ee3841 --- /dev/null +++ b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3em/MyConfig.java @@ -0,0 +1,62 @@ +package io.openems.edge.io.shelly.shellypro3em; + +import io.openems.common.test.AbstractComponentConfig; +import io.openems.edge.meter.api.MeterType; + +@SuppressWarnings("all") +public class MyConfig extends AbstractComponentConfig implements Config { + + protected static class Builder { + private String id; + private String ip; + private MeterType type; + + private Builder() { + } + + public Builder setId(String id) { + this.id = id; + return this; + } + + public Builder setIp(String ip) { + this.ip = ip; + return this; + } + + public Builder setType(MeterType type) { + this.type = type; + return this; + } + + public MyConfig build() { + return new MyConfig(this); + } + } + + /** + * Create a Config builder. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new Builder(); + } + + private final Builder builder; + + private MyConfig(Builder builder) { + super(Config.class, builder.id); + this.builder = builder; + } + + @Override + public String ip() { + return this.builder.ip; + } + + @Override + public MeterType type() { + return this.builder.type; + } +} \ No newline at end of file From 514d5d4e21e492edc5f9b84a1804db637d0e2048 Mon Sep 17 00:00:00 2001 From: Hannes Date: Wed, 19 Jun 2024 11:22:48 +0200 Subject: [PATCH 048/173] Implement ShellyPlus1PM (#2571) --- io.openems.edge.io.shelly/readme.adoc | 3 +- .../edge/io/shelly/shellyplus1pm/Config.java | 33 +++ .../shelly/shellyplus1pm/IoShellyPlus1Pm.java | 144 +++++++++++ .../shellyplus1pm/IoShellyPlus1PmImpl.java | 241 ++++++++++++++++++ .../IoShellyPlus1PmImplTest.java | 159 ++++++++++++ .../io/shelly/shellyplus1pm/MyConfig.java | 74 ++++++ .../shellyplusplugs/IoShellyPlugImplTest.java | 2 +- 7 files changed, 654 insertions(+), 2 deletions(-) create mode 100644 io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplus1pm/Config.java create mode 100644 io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplus1pm/IoShellyPlus1Pm.java create mode 100644 io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplus1pm/IoShellyPlus1PmImpl.java create mode 100644 io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplus1pm/IoShellyPlus1PmImplTest.java create mode 100644 io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplus1pm/MyConfig.java diff --git a/io.openems.edge.io.shelly/readme.adoc b/io.openems.edge.io.shelly/readme.adoc index 220c84fcbb4..423f94ec0c9 100644 --- a/io.openems.edge.io.shelly/readme.adoc +++ b/io.openems.edge.io.shelly/readme.adoc @@ -1,6 +1,6 @@ = Shelly WiFi Relay Switch -This bundle implements Shelly WiFi Relay Switches. +This bundle implements Shelly WiFi Relay Switches and Meters. Compatible with - https://www.shelly.com/de/products/shop/1xs25[Shelly 2.5] @@ -8,5 +8,6 @@ Compatible with - Shelly Plug S - https://www.shelly.com/de/products/shop/shelly-plus-plug-s-1[Shelly Plus Plug S] - https://www.shelly.com/de/products/shop/shelly-pro-3-em-120-a-1[Shelly Pro 3EM 3-Phase Meter] +- https://www.shelly.com/de/products/shop/shelly-plus-1-pm[Shelly Plus 1PM] https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.io.shelly[Source Code icon:github[]] \ No newline at end of file diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplus1pm/Config.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplus1pm/Config.java new file mode 100644 index 00000000000..2de9b0a17f0 --- /dev/null +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplus1pm/Config.java @@ -0,0 +1,33 @@ +package io.openems.edge.io.shelly.shellyplus1pm; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +import io.openems.edge.meter.api.MeterType; +import io.openems.edge.meter.api.SinglePhase; + +@ObjectClassDefinition(// + name = "IO Shelly Plus 1PM", // + description = "Implements the Shelly 2ndGen / Plug WiFi Switch.") +@interface Config { + + @AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component") + String id() default "io0"; + + @AttributeDefinition(name = "Alias", description = "Human-readable name of this Component; defaults to Component-ID") + String alias() default ""; + + @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?") + boolean enabled() default true; + + @AttributeDefinition(name = "Phase", description = "Which Phase is this Shelly Plug connected to?") + SinglePhase phase() default SinglePhase.L1; + + @AttributeDefinition(name = "IP-Address", description = "The IP address of the Shelly device.") + String ip(); + + @AttributeDefinition(name = "Meter-Type", description = "What is measured by this Meter?") + MeterType type() default MeterType.CONSUMPTION_METERED; + + String webconsole_configurationFactory_nameHint() default "IO Shelly Plus 1PM [{id}]"; +} diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplus1pm/IoShellyPlus1Pm.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplus1pm/IoShellyPlus1Pm.java new file mode 100644 index 00000000000..3fe7bb35bfe --- /dev/null +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplus1pm/IoShellyPlus1Pm.java @@ -0,0 +1,144 @@ +package io.openems.edge.io.shelly.shellyplus1pm; + +import org.osgi.service.event.EventHandler; + +import io.openems.common.channel.AccessMode; +import io.openems.common.channel.Level; +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.BooleanDoc; +import io.openems.edge.common.channel.BooleanWriteChannel; +import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.channel.StateChannel; +import io.openems.edge.common.channel.value.Value; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.io.api.DigitalOutput; +import io.openems.edge.meter.api.ElectricityMeter; +import io.openems.edge.meter.api.SinglePhaseMeter; + +public interface IoShellyPlus1Pm + extends DigitalOutput, SinglePhaseMeter, ElectricityMeter, OpenemsComponent, EventHandler { + + public static enum ChannelId implements io.openems.edge.common.channel.ChannelId { + /** + * Holds writes to Relay Output for debugging. + * + *
        + *
      • Interface: ShellyPlus1PM + *
      • Type: Boolean + *
      • Range: On/Off + *
      + */ + DEBUG_RELAY(Doc.of(OpenemsType.BOOLEAN)), // + /** + * Relay Output. + * + *
        + *
      • Interface: ShellyPlus1PM + *
      • Type: Boolean + *
      • Range: On/Off + *
      + */ + RELAY(new BooleanDoc() // + .accessMode(AccessMode.READ_WRITE) // + .onChannelSetNextWriteMirrorToDebugChannel(ChannelId.DEBUG_RELAY)), + /** + * Indicates whether the Shelly needs a restart. + * + *
        + *
      • Interface: ShellyPlus1PM + *
      • Type: Boolean + *
      • Level: WARN + *
      + */ + NEEDS_RESTART(Doc.of(Level.INFO) // + .text("Shelly suggests a restart.")), + /** + * Slave Communication Failed Fault. + * + *
        + *
      • Interface: ShellyPlus1PM + *
      • Type: State + *
      + */ + SLAVE_COMMUNICATION_FAILED(Doc.of(Level.FAULT)); // + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } + + /** + * Gets the Channel for {@link ChannelId#RELAY}. + * + * @return the Channel + */ + public default BooleanWriteChannel getRelayChannel() { + return this.channel(ChannelId.RELAY); + } + + /** + * Gets the Relay Output 1. See {@link ChannelId#RELAY}. + * + * @return the Channel {@link Value} + */ + public default Value getRelay() { + return this.getRelayChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#RELAY} Channel. + * + * @param value the next value + */ + public default void _setRelay(Boolean value) { + this.getRelayChannel().setNextValue(value); + } + + /** + * Sets the Relay Output. See {@link ChannelId#RELAY}. + * + * @param value the next write value + * @throws OpenemsNamedException on error + */ + public default void setRelay(boolean value) throws OpenemsNamedException { + this.getRelayChannel().setNextWriteValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#SLAVE_COMMUNICATION_FAILED}. + * + * @return the Channel + */ + public default StateChannel getSlaveCommunicationFailedChannel() { + return this.channel(ChannelId.SLAVE_COMMUNICATION_FAILED); + } + + /** + * Gets the Slave Communication Failed State. See + * {@link ChannelId#SLAVE_COMMUNICATION_FAILED}. + * + * @return the Channel {@link Value} + */ + public default Value getSlaveCommunicationFailed() { + return this.getSlaveCommunicationFailedChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on + * {@link ChannelId#SLAVE_COMMUNICATION_FAILED} Channel. + * + * @param value the next value + */ + public default void _setSlaveCommunicationFailed(boolean value) { + this.getSlaveCommunicationFailedChannel().setNextValue(value); + } + +} diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplus1pm/IoShellyPlus1PmImpl.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplus1pm/IoShellyPlus1PmImpl.java new file mode 100644 index 00000000000..16bd2cf3af0 --- /dev/null +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplus1pm/IoShellyPlus1PmImpl.java @@ -0,0 +1,241 @@ +package io.openems.edge.io.shelly.shellyplus1pm; + +import static io.openems.common.utils.JsonUtils.getAsBoolean; +import static io.openems.common.utils.JsonUtils.getAsFloat; +import static io.openems.common.utils.JsonUtils.getAsJsonObject; +import static io.openems.edge.io.shelly.common.Utils.generateDebugLog; +import static java.lang.Math.round; + +import java.util.Objects; + +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventHandler; +import org.osgi.service.event.propertytypes.EventTopics; +import org.osgi.service.metatype.annotations.Designate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.bridge.http.api.BridgeHttp; +import io.openems.edge.bridge.http.api.BridgeHttpFactory; +import io.openems.edge.bridge.http.api.HttpResponse; +import io.openems.edge.common.channel.BooleanWriteChannel; +import io.openems.edge.common.component.AbstractOpenemsComponent; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.event.EdgeEventConstants; +import io.openems.edge.io.api.DigitalOutput; +import io.openems.edge.meter.api.ElectricityMeter; +import io.openems.edge.meter.api.MeterType; +import io.openems.edge.meter.api.SinglePhase; +import io.openems.edge.meter.api.SinglePhaseMeter; +import io.openems.edge.timedata.api.Timedata; +import io.openems.edge.timedata.api.TimedataProvider; +import io.openems.edge.timedata.api.utils.CalculateEnergyFromPower; + +@Designate(ocd = Config.class, factory = true) +@Component(// + name = "IO.Shelly.Plus1PM", // + immediate = true, // + configurationPolicy = ConfigurationPolicy.REQUIRE// +) +@EventTopics({ // + EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE, // + EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE // +}) +public class IoShellyPlus1PmImpl extends AbstractOpenemsComponent implements IoShellyPlus1Pm, DigitalOutput, + SinglePhaseMeter, ElectricityMeter, OpenemsComponent, TimedataProvider, EventHandler { + + private final CalculateEnergyFromPower calculateProductionEnergy = new CalculateEnergyFromPower(this, + ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY); + private final CalculateEnergyFromPower calculateConsumptionEnergy = new CalculateEnergyFromPower(this, + ElectricityMeter.ChannelId.ACTIVE_CONSUMPTION_ENERGY); + + private final Logger log = LoggerFactory.getLogger(IoShellyPlus1PmImpl.class); + private final BooleanWriteChannel[] digitalOutputChannels; + + private MeterType meterType = null; + private SinglePhase phase = null; + private String baseUrl; + + @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) + private volatile Timedata timedata; + + @Reference(cardinality = ReferenceCardinality.MANDATORY) + private BridgeHttpFactory httpBridgeFactory; + private BridgeHttp httpBridge; + + public IoShellyPlus1PmImpl() { + super(// + OpenemsComponent.ChannelId.values(), // + ElectricityMeter.ChannelId.values(), // + DigitalOutput.ChannelId.values(), // + IoShellyPlus1Pm.ChannelId.values() // + ); + this.digitalOutputChannels = new BooleanWriteChannel[] { // + this.channel(IoShellyPlus1Pm.ChannelId.RELAY) // + }; + + SinglePhaseMeter.calculateSinglePhaseFromActivePower(this); + SinglePhaseMeter.calculateSinglePhaseFromCurrent(this); + SinglePhaseMeter.calculateSinglePhaseFromVoltage(this); + } + + @Activate + protected void activate(ComponentContext context, Config config) { + super.activate(context, config.id(), config.alias(), config.enabled()); + this.meterType = config.type(); + this.phase = config.phase(); + this.baseUrl = "http://" + config.ip(); + this.httpBridge = this.httpBridgeFactory.get(); + + if (!this.isEnabled()) { + return; + } + + this.httpBridge.subscribeJsonEveryCycle(this.baseUrl + "/rpc/Shelly.GetStatus", this::processHttpResult); + } + + @Override + @Deactivate + protected void deactivate() { + if (this.httpBridge != null) { + this.httpBridgeFactory.unget(this.httpBridge); + this.httpBridge = null; + } + super.deactivate(); + } + + @Override + public BooleanWriteChannel[] digitalOutputChannels() { + return this.digitalOutputChannels; + } + + @Override + public String debugLog() { + return generateDebugLog(this.getRelayChannel(), this.getActivePowerChannel()); + } + + @Override + public void handleEvent(Event event) { + if (!this.isEnabled()) { + return; + } + + switch (event.getTopic()) { + case EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE // + -> this.calculateEnergy(); + case EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE // + -> this.executeWrite(this.getRelayChannel(), 0); + } + } + + private void processHttpResult(HttpResponse result, Throwable error) { + this._setSlaveCommunicationFailed(result == null); + + Integer power = null; + Integer voltage = null; + Integer current = null; + Boolean relay0 = null; + boolean restartRequired = false; + + if (error != null) { + this.logDebug(this.log, error.getMessage()); + + } else { + try { + var jsonResponse = getAsJsonObject(result.data()); + var switch0 = getAsJsonObject(jsonResponse, "switch:0"); + power = round(getAsFloat(switch0, "apower")); + voltage = round(getAsFloat(switch0, "voltage") * 1000); + current = round(getAsFloat(switch0, "current") * 1000); + relay0 = getAsBoolean(switch0, "output"); + + var sys = getAsJsonObject(jsonResponse, "sys"); + restartRequired = getAsBoolean(sys, "restart_required"); + + } catch (OpenemsNamedException e) { + this.logDebug(this.log, e.getMessage()); + } + } + + this._setRelay(relay0); + this._setActivePower(power); + this._setCurrent(current); + this._setVoltage(voltage); + this.channel(IoShellyPlus1Pm.ChannelId.NEEDS_RESTART).setNextValue(restartRequired); + } + + /** + * Execute on Cycle Event "Execute Write". + * + * @param channel write channel + * @param index index + */ + private void executeWrite(BooleanWriteChannel channel, int index) { + var readValue = channel.value().get(); + var writeValue = channel.getNextWriteValueAndReset(); + if (writeValue.isEmpty()) { + // no write value + return; + } + if (Objects.equals(readValue, writeValue.get())) { + // read value equals write value, so no need to write + return; + } + final String url = this.baseUrl + "/relay/" + index + "?turn=" + (writeValue.get() ? "on" : "off"); + this.httpBridge.get(url).whenComplete((response, error) -> { + if (error != null) { + this.logError(this.log, "HTTP request failed: " + error.getMessage()); + this._setSlaveCommunicationFailed(true); + } else { + // Optionally log success or handle response + this._setSlaveCommunicationFailed(false); + } + }); + } + + /** + * Calculate the Energy values from ActivePower. + */ + private void calculateEnergy() { + // Calculate Energy + final var activePower = this.getActivePower().get(); + if (activePower == null) { + this.calculateProductionEnergy.update(null); + this.calculateConsumptionEnergy.update(null); + } else if (activePower >= 0) { + this.calculateProductionEnergy.update(activePower); + this.calculateConsumptionEnergy.update(0); + } else { + this.calculateProductionEnergy.update(0); + this.calculateConsumptionEnergy.update(-activePower); + } + } + + @Override + public MeterType getMeterType() { + return this.meterType; + } + + @Override + public SinglePhase getPhase() { + return this.phase; + } + + @Override + public Timedata getTimedata() { + return this.timedata; + } + +} diff --git a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplus1pm/IoShellyPlus1PmImplTest.java b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplus1pm/IoShellyPlus1PmImplTest.java new file mode 100644 index 00000000000..e3443f8d6b1 --- /dev/null +++ b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplus1pm/IoShellyPlus1PmImplTest.java @@ -0,0 +1,159 @@ +package io.openems.edge.io.shelly.shellyplus1pm; + +import static io.openems.edge.meter.api.MeterType.CONSUMPTION_METERED; +import static io.openems.edge.meter.api.SinglePhase.L1; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import io.openems.common.types.ChannelAddress; +import io.openems.edge.bridge.http.api.HttpError; +import io.openems.edge.bridge.http.api.HttpResponse; +import io.openems.edge.bridge.http.dummy.DummyBridgeHttpBundle; +import io.openems.edge.common.test.AbstractComponentTest.TestCase; +import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.timedata.test.DummyTimedata; + +public class IoShellyPlus1PmImplTest { + + private static final String COMPONENT_ID = "io0"; + + private static final ChannelAddress ACTIVE_POWER = new ChannelAddress(COMPONENT_ID, "ActivePower"); + private static final ChannelAddress ACTIVE_POWER_L1 = new ChannelAddress(COMPONENT_ID, "ActivePowerL1"); + private static final ChannelAddress ACTIVE_POWER_L2 = new ChannelAddress(COMPONENT_ID, "ActivePowerL2"); + private static final ChannelAddress CURRENT = new ChannelAddress(COMPONENT_ID, "Current"); + private static final ChannelAddress VOLTAGE = new ChannelAddress(COMPONENT_ID, "Voltage"); + private static final ChannelAddress PRODUCTION_ENERGY = new ChannelAddress(COMPONENT_ID, "ActiveProductionEnergy"); + private static final ChannelAddress CONSUMPTION_ENERGY = new ChannelAddress(COMPONENT_ID, + "ActiveConsumptionEnergy"); + + @Test + public void test() throws Exception { + final var httpTestBundle = new DummyBridgeHttpBundle(); + final var sut = new IoShellyPlus1PmImpl(); + + new ComponentTest(sut) // + .addReference("httpBridgeFactory", httpTestBundle.factory()) // + .addReference("timedata", new DummyTimedata("timedata0")) // + .activate(MyConfig.create() // + .setId(COMPONENT_ID) // + .setIp("127.0.0.1") // + .setType(CONSUMPTION_METERED) // + .setPhase(L1) // + .build()) // + + .next(new TestCase("Successful read response") // + .onBeforeControllersCallbacks(() -> { + httpTestBundle.forceNextSuccessfulResult(HttpResponse.ok(""" + { + "ble":{ + + }, + "cloud":{ + "connected":true + }, + "input:0":{ + "id":0, + "state":false + }, + "mqtt":{ + "connected":false + }, + "switch:0":{ + "id":0, + "source":"init", + "output":false, + "apower":123.0, + "voltage":231.3, + "current":0.500, + "aenergy":{ + "total":8629.000, + "by_minute":[ + 0.000, + 0.000, + 0.000 + ], + "minute_ts":1708858380 + }, + "temperature":{ + "tC":44.3, + "tF":111.7 + } + }, + "sys":{ + "mac":"80646FE34998", + "restart_required":false, + "time":"11:53", + "unixtime":1708858386, + "uptime":150390, + "ram_size":260364, + "ram_free":115308, + "fs_size":458752, + "fs_free":143360, + "cfg_rev":22, + "kvs_rev":2, + "schedule_rev":0, + "webhook_rev":0, + "available_updates":{ + + }, + "reset_reason":3 + }, + "wifi":{ + "sta_ip":"192.168.178.169", + "status":"got ip", + "ssid":"heizung", + "rssi":-48, + "ap_client_count":0 + }, + "ws":{ + "connected":false + } + } + """)); + httpTestBundle.triggerNextCycle(); + }) // + .output(ACTIVE_POWER, 123) // + .output(ACTIVE_POWER_L1, 123) // + .output(ACTIVE_POWER_L2, null) // + .output(CURRENT, 500) // + .output(VOLTAGE, 231300)) // + + .next(new TestCase("Invalid read response") // + .onBeforeControllersCallbacks(() -> assertEquals("Off|123 W", sut.debugLog())) + + .onBeforeControllersCallbacks(() -> { + httpTestBundle.forceNextFailedResult(HttpError.ResponseError.notFound()); + httpTestBundle.triggerNextCycle(); + }) // + .output(ACTIVE_POWER, null) // + .output(ACTIVE_POWER_L1, null) // + .output(ACTIVE_POWER_L2, null) // + .output(CURRENT, null) // + .output(VOLTAGE, null) // + + .output(PRODUCTION_ENERGY, 0L) // + .output(CONSUMPTION_ENERGY, 0L)) // + + .next(new TestCase("Write") // + .onBeforeControllersCallbacks(() -> assertEquals("Unknown|UNDEFINED", sut.debugLog())) + .onBeforeControllersCallbacks(() -> { + sut.setRelay(true); + }) // + .also(testCase -> { + final var relayTurnedOn = httpTestBundle.expect("http://127.0.0.1/relay/0?turn=on") + .toBeCalled(); + + testCase.onBeforeControllersCallbacks(() -> { + httpTestBundle.triggerNextCycle(); + }); + testCase.onAfterWriteCallbacks(() -> { + assertTrue("Failed to turn on relay", relayTurnedOn.get()); + }); + })) // + + .deactivate(); + } + +} diff --git a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplus1pm/MyConfig.java b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplus1pm/MyConfig.java new file mode 100644 index 00000000000..e653d439747 --- /dev/null +++ b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplus1pm/MyConfig.java @@ -0,0 +1,74 @@ +package io.openems.edge.io.shelly.shellyplus1pm; + +import io.openems.common.test.AbstractComponentConfig; +import io.openems.edge.meter.api.MeterType; +import io.openems.edge.meter.api.SinglePhase; + +@SuppressWarnings("all") +public class MyConfig extends AbstractComponentConfig implements Config { + + protected static class Builder { + private String id; + private String ip; + private MeterType type; + private SinglePhase phase; + + private Builder() { + } + + public Builder setId(String id) { + this.id = id; + return this; + } + + public Builder setPhase(SinglePhase phase) { + this.phase = phase; + return this; + } + + public Builder setIp(String ip) { + this.ip = ip; + return this; + } + + public Builder setType(MeterType type) { + this.type = type; + return this; + } + + public MyConfig build() { + return new MyConfig(this); + } + } + + /** + * Create a Config builder. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new Builder(); + } + + private final Builder builder; + + private MyConfig(Builder builder) { + super(Config.class, builder.id); + this.builder = builder; + } + + @Override + public String ip() { + return this.builder.ip; + } + + @Override + public MeterType type() { + return this.builder.type; + } + + @Override + public SinglePhase phase() { + return this.builder.phase; + } +} diff --git a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlugImplTest.java b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlugImplTest.java index 9b1a1d50795..c91c4c52720 100644 --- a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlugImplTest.java +++ b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlugImplTest.java @@ -43,7 +43,7 @@ public void test() throws Exception { .setType(MeterType.PRODUCTION) // .build()) // - .next(new TestCase("Successfull read response") // + .next(new TestCase("Successful read response") // .onBeforeControllersCallbacks(() -> { httpTestBundle.forceNextSuccessfulResult(HttpResponse.ok(""" { From 4cdae0c315e7ba05c6611ba1e13057d3b7a5b634 Mon Sep 17 00:00:00 2001 From: Hannes Date: Wed, 19 Jun 2024 12:03:29 +0200 Subject: [PATCH 049/173] Implement Shelly Pro 3 (#2572) --- io.openems.edge.io.shelly/readme.adoc | 1 + .../openems/edge/io/shelly/common/Utils.java | 26 ++ .../io/shelly/shelly25/IoShelly25Impl.java | 20 +- .../edge/io/shelly/shellypro3/Config.java | 24 ++ .../io/shelly/shellypro3/IoShellyPro3.java | 247 ++++++++++++++++++ .../shelly/shellypro3/IoShellyPro3Impl.java | 167 ++++++++++++ .../shellypro3em/IoShellyPro3EmImpl.java | 2 +- .../shellypro3/IoShellyPro3ImplTest.java | 23 ++ .../edge/io/shelly/shellypro3/MyConfig.java | 50 ++++ 9 files changed, 541 insertions(+), 19 deletions(-) create mode 100644 io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3/Config.java create mode 100644 io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3/IoShellyPro3.java create mode 100644 io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3/IoShellyPro3Impl.java create mode 100644 io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3/IoShellyPro3ImplTest.java create mode 100644 io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3/MyConfig.java diff --git a/io.openems.edge.io.shelly/readme.adoc b/io.openems.edge.io.shelly/readme.adoc index 423f94ec0c9..c4a28621bff 100644 --- a/io.openems.edge.io.shelly/readme.adoc +++ b/io.openems.edge.io.shelly/readme.adoc @@ -9,5 +9,6 @@ Compatible with - https://www.shelly.com/de/products/shop/shelly-plus-plug-s-1[Shelly Plus Plug S] - https://www.shelly.com/de/products/shop/shelly-pro-3-em-120-a-1[Shelly Pro 3EM 3-Phase Meter] - https://www.shelly.com/de/products/shop/shelly-plus-1-pm[Shelly Plus 1PM] +- https://www.shelly.com/de/products/shop/shelly-pro-3-1[Shelly Pro 3] https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.io.shelly[Source Code icon:github[]] \ No newline at end of file diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/common/Utils.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/common/Utils.java index 14595f04ea6..ca4ac6ff5b4 100644 --- a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/common/Utils.java +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/common/Utils.java @@ -1,5 +1,6 @@ package io.openems.edge.io.shelly.common; +import io.openems.edge.common.channel.BooleanWriteChannel; import io.openems.edge.common.channel.Channel; import io.openems.edge.common.component.OpenemsComponent; @@ -26,4 +27,29 @@ public static String generateDebugLog(Channel relayChannel, Channel + *
    1. Interface: Shelly3Pro + *
    2. Type: Boolean + *
    3. Range: On/Off + * + */ + DEBUG_RELAY_1(Doc.of(OpenemsType.BOOLEAN)), // + /** + * Relay Output 1. + * + *
        + *
      • Interface: Shelly3Pro + *
      • Type: Boolean + *
      • Range: On/Off + *
      + */ + RELAY_1(new BooleanDoc() // + .accessMode(AccessMode.READ_WRITE) // + .onChannelSetNextWriteMirrorToDebugChannel(ChannelId.DEBUG_RELAY_1)), + /** + * Holds writes to Relay Output 2 for debugging. + * + *
        + *
      • Interface: Shelly3Pro + *
      • Type: Boolean + *
      • Range: On/Off + *
      + */ + DEBUG_RELAY_2(Doc.of(OpenemsType.BOOLEAN)), // + /** + * Relay Output 2. + * + *
        + *
      • Interface: Shelly3Pro + *
      • Type: Boolean + *
      • Range: On/Off + *
      + */ + RELAY_2(new BooleanDoc() // + .accessMode(AccessMode.READ_WRITE) // + .onChannelSetNextWriteMirrorToDebugChannel(ChannelId.DEBUG_RELAY_2)), + /** + * Holds writes to Relay Output 3 for debugging. + * + *
        + *
      • Interface: Shelly3Pro + *
      • Type: Boolean + *
      • Range: On/Off + *
      + */ + DEBUG_RELAY_3(Doc.of(OpenemsType.BOOLEAN)), // + /** + * Relay Output 3. + * + *
        + *
      • Interface: Shelly3Pro + *
      • Type: Boolean + *
      • Range: On/Off + *
      + */ + RELAY_3(new BooleanDoc() // + .accessMode(AccessMode.READ_WRITE) // + .onChannelSetNextWriteMirrorToDebugChannel(ChannelId.DEBUG_RELAY_3)), + /** + * Slave Communication Failed Fault. + * + *
        + *
      • Interface: Shelly3Pro + *
      • Type: State + *
      + */ + SLAVE_COMMUNICATION_FAILED(Doc.of(Level.FAULT)); // + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } + + /** + * Gets the Channel for {@link ChannelId#RELAY_1}. + * + * @return the Channel + */ + public default BooleanWriteChannel getRelay1Channel() { + return this.channel(ChannelId.RELAY_1); + } + + /** + * Gets the Relay Output 1. See {@link ChannelId#RELAY_1}. + * + * @return the Channel {@link Value} + */ + public default Value getRelay1() { + return this.getRelay1Channel().value(); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#RELAY_1} Channel. + * + * @param value the next value + */ + public default void _setRelay1(Boolean value) { + this.getRelay1Channel().setNextValue(value); + } + + /** + * Sets the Relay Output 1. See {@link ChannelId#RELAY_1}. + * + * @param value the next write value + * @throws OpenemsNamedException on error + */ + public default void setRelay1(boolean value) throws OpenemsNamedException { + this.getRelay1Channel().setNextWriteValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#RELAY_2}. + * + * @return the Channel + */ + public default BooleanWriteChannel getRelay2Channel() { + return this.channel(ChannelId.RELAY_2); + } + + /** + * Gets the Relay Output 2. See {@link ChannelId#RELAY_2}. + * + * @return the Channel {@link Value} + */ + public default Value getRelay2() { + return this.getRelay2Channel().value(); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#RELAY_2} Channel. + * + * @param value the next value + */ + public default void _setRelay2(Boolean value) { + this.getRelay2Channel().setNextValue(value); + } + + /** + * Sets the Relay Output 2. See {@link ChannelId#RELAY_2}. + * + * @param value the next write value + * @throws OpenemsNamedException on error + */ + public default void setRelay2(boolean value) throws OpenemsNamedException { + this.getRelay2Channel().setNextWriteValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#RELAY_3}. + * + * @return the Channel + */ + public default BooleanWriteChannel getRelay3Channel() { + return this.channel(ChannelId.RELAY_3); + } + + /** + * Gets the Relay Output 3. See {@link ChannelId#RELAY_3}. + * + * @return the Channel {@link Value} + */ + public default Value getRelay3() { + return this.getRelay3Channel().value(); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#RELAY_3} Channel. + * + * @param value the next value + */ + public default void _setRelay3(Boolean value) { + this.getRelay3Channel().setNextValue(value); + } + + /** + * Sets the Relay Output 3. See {@link ChannelId#RELAY_3}. + * + * @param value the next write value + * @throws OpenemsNamedException on error + */ + public default void setRelay3(boolean value) throws OpenemsNamedException { + this.getRelay3Channel().setNextWriteValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#SLAVE_COMMUNICATION_FAILED}. + * + * @return the Channel + */ + public default StateChannel getSlaveCommunicationFailedChannel() { + return this.channel(ChannelId.SLAVE_COMMUNICATION_FAILED); + } + + /** + * Gets the Slave Communication Failed State. See + * {@link ChannelId#SLAVE_COMMUNICATION_FAILED}. + * + * @return the Channel {@link Value} + */ + public default Value getSlaveCommunicationFailed() { + return this.getSlaveCommunicationFailedChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on + * {@link ChannelId#SLAVE_COMMUNICATION_FAILED} Channel. + * + * @param value the next value + */ + public default void _setSlaveCommunicationFailed(boolean value) { + this.getSlaveCommunicationFailedChannel().setNextValue(value); + } +} diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3/IoShellyPro3Impl.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3/IoShellyPro3Impl.java new file mode 100644 index 00000000000..888ceb58da3 --- /dev/null +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3/IoShellyPro3Impl.java @@ -0,0 +1,167 @@ +package io.openems.edge.io.shelly.shellypro3; + +import static io.openems.common.utils.JsonUtils.getAsBoolean; +import static io.openems.common.utils.JsonUtils.getAsJsonObject; +import static io.openems.edge.io.shelly.common.Utils.generateDebugLog; + +import java.util.Objects; + +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventHandler; +import org.osgi.service.event.propertytypes.EventTopics; +import org.osgi.service.metatype.annotations.Designate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonElement; + +import io.openems.edge.bridge.http.api.BridgeHttp; +import io.openems.edge.bridge.http.api.BridgeHttpFactory; +import io.openems.edge.bridge.http.api.HttpError; +import io.openems.edge.bridge.http.api.HttpResponse; +import io.openems.edge.common.channel.BooleanWriteChannel; +import io.openems.edge.common.component.AbstractOpenemsComponent; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.event.EdgeEventConstants; +import io.openems.edge.io.api.DigitalOutput; + +@Designate(ocd = Config.class, factory = true) +@Component(// + name = "IO.Shelly.Pro3", // + immediate = true, // + configurationPolicy = ConfigurationPolicy.REQUIRE // +) +@EventTopics({ // + EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE // +}) + +public class IoShellyPro3Impl extends AbstractOpenemsComponent + implements IoShellyPro3, DigitalOutput, OpenemsComponent, EventHandler { + + private final Logger log = LoggerFactory.getLogger(IoShellyPro3Impl.class); + private final BooleanWriteChannel[] digitalOutputChannels; + + private String baseUrl; + + @Reference + private BridgeHttpFactory httpBridgeFactory; + private BridgeHttp httpBridge; + + public IoShellyPro3Impl() { + super(// + OpenemsComponent.ChannelId.values(), // + DigitalOutput.ChannelId.values(), // + IoShellyPro3.ChannelId.values() // + ); + this.digitalOutputChannels = new BooleanWriteChannel[] { // + this.channel(IoShellyPro3.ChannelId.RELAY_1), // + this.channel(IoShellyPro3.ChannelId.RELAY_2), // + this.channel(IoShellyPro3.ChannelId.RELAY_3), // + }; + } + + @Activate + protected void activate(ComponentContext context, Config config) { + super.activate(context, config.id(), config.alias(), config.enabled()); + this.baseUrl = "http://" + config.ip(); + this.httpBridge = this.httpBridgeFactory.get(); + + for (int i = 0; i < 3; i++) { + final int relayIndex = i; + String url = this.baseUrl + "/rpc/Switch.GetStatus?id=" + relayIndex; + this.httpBridge.subscribeJsonEveryCycle(url, (result, error) -> { + this.processHttpResult(result, error, relayIndex); + }); + } + } + + @Deactivate + protected void deactivate() { + this.httpBridgeFactory.unget(this.httpBridge); + this.httpBridge = null; + super.deactivate(); + } + + @Override + public BooleanWriteChannel[] digitalOutputChannels() { + return this.digitalOutputChannels; + } + + @Override + public String debugLog() { + return generateDebugLog(this.digitalOutputChannels); + } + + @Override + public void handleEvent(Event event) { + if (!this.isEnabled()) { + return; + } + + switch (event.getTopic()) { + case EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE // + -> this.eventExecuteWrite(); + } + } + + // NOTE: this method is called once per each relay + private void processHttpResult(HttpResponse result, HttpError error, int relayIndex) { + this._setSlaveCommunicationFailed(result == null); + + Boolean isOn = null; + + if (error != null) { + this.logDebug(this.log, error.getMessage()); + + } else { + try { + var switchStatus = getAsJsonObject(result.data()); + isOn = getAsBoolean(switchStatus, "output"); + + } catch (Exception e) { + this.logError(this.log, "Error processing HTTP response: " + e.getMessage()); + return; + } + } + + switch (relayIndex) { + case 0 -> this._setRelay1(isOn); + case 1 -> this._setRelay2(isOn); + case 2 -> this._setRelay3(isOn); + } + } + + /** + * Execute on Cycle Event "Execute Write". + */ + private void eventExecuteWrite() { + for (int i = 0; i < this.digitalOutputChannels.length; i++) { + this.executeWrite(this.digitalOutputChannels[i], i); + } + } + + private void executeWrite(BooleanWriteChannel channel, int index) { + var readValue = channel.value().get(); + var writeValue = channel.getNextWriteValueAndReset(); + if (writeValue.isEmpty()) { + return; + } + if (Objects.equals(readValue, writeValue.get())) { + return; + } + final String url = this.baseUrl + "/relay/" + index + "?turn=" + (writeValue.get() ? "on" : "off"); + this.httpBridge.get(url).whenComplete((t, e) -> { + if (e != null) { + this.logError(this.log, "HTTP request failed: " + e.getMessage()); + this._setSlaveCommunicationFailed(true); + } + }); + } + +} diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/IoShellyPro3EmImpl.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/IoShellyPro3EmImpl.java index dfa0c2085b4..15db1dac66f 100644 --- a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/IoShellyPro3EmImpl.java +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/IoShellyPro3EmImpl.java @@ -40,7 +40,7 @@ @Designate(ocd = Config.class, factory = true) @Component(// - name = "IO.Shelly.Pro.3EM", // + name = "IO.Shelly.Pro3EM", // immediate = true, // configurationPolicy = ConfigurationPolicy.REQUIRE // ) diff --git a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3/IoShellyPro3ImplTest.java b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3/IoShellyPro3ImplTest.java new file mode 100644 index 00000000000..ed4f8d960b6 --- /dev/null +++ b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3/IoShellyPro3ImplTest.java @@ -0,0 +1,23 @@ +package io.openems.edge.io.shelly.shellypro3; + +import org.junit.Test; + +import io.openems.edge.bridge.http.dummy.DummyBridgeHttpFactory; +import io.openems.edge.common.test.ComponentTest; + +public class IoShellyPro3ImplTest { + + private static final String COMPONENT_ID = "io0"; + + @Test + public void test() throws Exception { + new ComponentTest(new IoShellyPro3Impl()) // + .addReference("httpBridgeFactory", DummyBridgeHttpFactory.ofDummyBridge()) // + .activate(MyConfig.create() // + .setId(COMPONENT_ID) // + .setIp("127.0.0.1") // + .build()) // + ; + } + +} \ No newline at end of file diff --git a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3/MyConfig.java b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3/MyConfig.java new file mode 100644 index 00000000000..3d58882f769 --- /dev/null +++ b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3/MyConfig.java @@ -0,0 +1,50 @@ +package io.openems.edge.io.shelly.shellypro3; + +import io.openems.common.test.AbstractComponentConfig; + +@SuppressWarnings("all") +public class MyConfig extends AbstractComponentConfig implements Config { + + protected static class Builder { + private String id; + private String ip; + + private Builder() { + } + + public Builder setId(String id) { + this.id = id; + return this; + } + + public Builder setIp(String ip) { + this.ip = ip; + return this; + } + + public MyConfig build() { + return new MyConfig(this); + } + } + + /** + * Create a Config builder. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new Builder(); + } + + private final Builder builder; + + private MyConfig(Builder builder) { + super(Config.class, builder.id); + this.builder = builder; + } + + @Override + public String ip() { + return this.builder.ip; + } +} \ No newline at end of file From 2d8c2a9033a0b745659aaff78ab9597a3594b230 Mon Sep 17 00:00:00 2001 From: Hannes Date: Mon, 24 Jun 2024 10:50:33 +0200 Subject: [PATCH 050/173] UI: improve select channels view (#2599) If no component was selected, it used to be possible to select a channel. This is fixed now. --- ui/src/app/edge/settings/channels/channels.component.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/src/app/edge/settings/channels/channels.component.html b/ui/src/app/edge/settings/channels/channels.component.html index 9640d5ecdb8..8c192b88627 100644 --- a/ui/src/app/edge/settings/channels/channels.component.html +++ b/ui/src/app/edge/settings/channels/channels.component.html @@ -24,8 +24,9 @@ - + From 941bc101044caede0cd0af6e4632894fa16a9f62 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Jun 2024 15:33:50 +0200 Subject: [PATCH 051/173] Bump @types/uuid from 9.0.8 to 10.0.0 in /ui (#2682) Bumps [@types/uuid](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/uuid) from 9.0.8 to 10.0.0. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/uuid) --- updated-dependencies: - dependency-name: "@types/uuid" dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 9 +++++---- ui/package.json | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index b6b69c0cf64..f39f06c978a 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -56,7 +56,7 @@ "@types/jasmine": "~4.3.6", "@types/jasminewd2": "~2.0.13", "@types/node": "^20.12.6", - "@types/uuid": "^9.0.8", + "@types/uuid": "^10.0.0", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", "eslint": "^8.57.0", @@ -4696,9 +4696,10 @@ } }, "node_modules/@types/uuid": { - "version": "9.0.8", - "dev": true, - "license": "MIT" + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", + "dev": true }, "node_modules/@types/ws": { "version": "8.5.10", diff --git a/ui/package.json b/ui/package.json index 0d3a435f1cc..2729650ac7d 100644 --- a/ui/package.json +++ b/ui/package.json @@ -51,7 +51,7 @@ "@types/jasmine": "~4.3.6", "@types/jasminewd2": "~2.0.13", "@types/node": "^20.12.6", - "@types/uuid": "^9.0.8", + "@types/uuid": "^10.0.0", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", "eslint": "^8.57.0", From 66219b4574097cee59999787841bc37c7cd2165f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Jun 2024 15:40:02 +0200 Subject: [PATCH 052/173] Bump @stylistic/eslint-plugin from 2.2.1 to 2.2.2 in /ui (#2681) Bumps [@stylistic/eslint-plugin](https://github.com/eslint-stylistic/eslint-stylistic/tree/HEAD/packages/eslint-plugin) from 2.2.1 to 2.2.2. - [Release notes](https://github.com/eslint-stylistic/eslint-stylistic/releases) - [Changelog](https://github.com/eslint-stylistic/eslint-stylistic/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint-stylistic/eslint-stylistic/commits/v2.2.2/packages/eslint-plugin) --- updated-dependencies: - dependency-name: "@stylistic/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-patch ... 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 | 136 +++++++++++++++++++++---------------------- ui/package.json | 2 +- 2 files changed, 69 insertions(+), 69 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index f39f06c978a..77326d2363d 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -52,7 +52,7 @@ "@angular/compiler-cli": "^16.2.12", "@angular/language-service": "^16.2.12", "@ionic/angular-toolkit": "^11.0.1", - "@stylistic/eslint-plugin": "^2.2.1", + "@stylistic/eslint-plugin": "^2.2.2", "@types/jasmine": "~4.3.6", "@types/jasminewd2": "~2.0.13", "@types/node": "^20.12.6", @@ -3959,15 +3959,15 @@ } }, "node_modules/@stylistic/eslint-plugin": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.2.1.tgz", - "integrity": "sha512-YErqfwWFbRCpkyPtrcVYaJhvEn9aXE4WzxxkZ7Q3OKS4QD9CE6qZjzEw5DhcA2wL3Jo6JbzSB3/stJMNocGMgQ==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.2.2.tgz", + "integrity": "sha512-GNRtyhhPsc9I9FNTaU2L0V/4LdSPAciQNEdYo6NBRdAz7sdiaxgEJKLNSXeXSQAuO9JBWWjZBs/57+WvrU0Iug==", "dev": true, "dependencies": { - "@stylistic/eslint-plugin-js": "2.2.1", - "@stylistic/eslint-plugin-jsx": "2.2.1", - "@stylistic/eslint-plugin-plus": "2.2.1", - "@stylistic/eslint-plugin-ts": "2.2.1", + "@stylistic/eslint-plugin-js": "2.2.2", + "@stylistic/eslint-plugin-jsx": "2.2.2", + "@stylistic/eslint-plugin-plus": "2.2.2", + "@stylistic/eslint-plugin-ts": "2.2.2", "@types/eslint": "^8.56.10" }, "engines": { @@ -3978,9 +3978,9 @@ } }, "node_modules/@stylistic/eslint-plugin-js": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.2.1.tgz", - "integrity": "sha512-M2dQkKw2R4R+b1SJ/xElJ9bDVq/vCI31VpIIxkZD9KXCqbUHvtsGpZH3eO6MzmFWOZj4PfNdEQdP332MtqjCPg==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.2.2.tgz", + "integrity": "sha512-Vj2Q1YHVvJw+ThtOvmk5Yx7wZanVrIBRUTT89horLDb4xdP9GA1um9XOYQC6j67VeUC2gjZQnz5/RVJMzaOhtw==", "dev": true, "dependencies": { "@types/eslint": "^8.56.10", @@ -4025,12 +4025,12 @@ } }, "node_modules/@stylistic/eslint-plugin-jsx": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-jsx/-/eslint-plugin-jsx-2.2.1.tgz", - "integrity": "sha512-J/R4tU38v8gVqKPy6Mh22dq8btLSPWK06SuRc/ryOxT8LpW2ZdcSDP4HNvQiOte0Wy9xzgKJHP4JlYauDZ/oVw==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-jsx/-/eslint-plugin-jsx-2.2.2.tgz", + "integrity": "sha512-xfIMdLivoMV1wV+5Tl0PtkLN/oUwjIt7LuIu48vhrZfJ2jCXwjlTGPGSoM7dnLZYD65XjtrHHIFAvPuvvvjlaw==", "dev": true, "dependencies": { - "@stylistic/eslint-plugin-js": "^2.2.1", + "@stylistic/eslint-plugin-js": "^2.2.2", "@types/eslint": "^8.56.10", "estraverse": "^5.3.0", "picomatch": "^4.0.2" @@ -4064,9 +4064,9 @@ } }, "node_modules/@stylistic/eslint-plugin-plus": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-2.2.1.tgz", - "integrity": "sha512-VGdTcQzZ/cZNcJnvjDos1VLzUerPapvYCVSCQZEhupMtmxt+mbITiJWzLLHYNfqGBnW7ABqViLfob+s3Q2GcKw==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-2.2.2.tgz", + "integrity": "sha512-oeqPs01yAH4ad4bSchGtx8Jf5XTbxRx++A0joNYiOoq3EBTAUHE/ZB7dVv3BhNuCKiwojOQduLkUCXI5UMHoSw==", "dev": true, "dependencies": { "@types/eslint": "^8.56.10", @@ -4077,13 +4077,13 @@ } }, "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/scope-manager": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.1.tgz", - "integrity": "sha512-adbXNVEs6GmbzaCpymHQ0MB6E4TqoiVbC0iqG3uijR8ZYfpAXMGttouQzF4Oat3P2GxDVIrg7bMI/P65LiQZdg==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.14.1.tgz", + "integrity": "sha512-gPrFSsoYcsffYXTOZ+hT7fyJr95rdVe4kGVX1ps/dJ+DfmlnjFN/GcMxXcVkeHDKqsq6uAcVaQaIi3cFffmAbA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.13.1", - "@typescript-eslint/visitor-keys": "7.13.1" + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/visitor-keys": "7.14.1" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -4094,9 +4094,9 @@ } }, "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/types": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.1.tgz", - "integrity": "sha512-7K7HMcSQIAND6RBL4kDl24sG/xKM13cA85dc7JnmQXw2cBDngg7c19B++JzvJHRG3zG36n9j1i451GBzRuHchw==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.14.1.tgz", + "integrity": "sha512-mL7zNEOQybo5R3AavY+Am7KLv8BorIv7HCYS5rKoNZKQD9tsfGUpO4KdAn3sSUvTiS4PQkr2+K0KJbxj8H9NDg==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -4107,13 +4107,13 @@ } }, "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.1.tgz", - "integrity": "sha512-uxNr51CMV7npU1BxZzYjoVz9iyjckBduFBP0S5sLlh1tXYzHzgZ3BR9SVsNed+LmwKrmnqN3Kdl5t7eZ5TS1Yw==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.14.1.tgz", + "integrity": "sha512-k5d0VuxViE2ulIO6FbxxSZaxqDVUyMbXcidC8rHvii0I56XZPv8cq+EhMns+d/EVIL41sMXqRbK3D10Oza1bbA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.13.1", - "@typescript-eslint/visitor-keys": "7.13.1", + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/visitor-keys": "7.14.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -4135,15 +4135,15 @@ } }, "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/utils": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.1.tgz", - "integrity": "sha512-h5MzFBD5a/Gh/fvNdp9pTfqJAbuQC4sCN2WzuXme71lqFJsZtLbjxfSk4r3p02WIArOF9N94pdsLiGutpDbrXQ==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.14.1.tgz", + "integrity": "sha512-CMmVVELns3nak3cpJhZosDkm63n+DwBlDX8g0k4QUa9BMnF+lH2lr3d130M1Zt1xxmB3LLk3NV7KQCq86ZBBhQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.13.1", - "@typescript-eslint/types": "7.13.1", - "@typescript-eslint/typescript-estree": "7.13.1" + "@typescript-eslint/scope-manager": "7.14.1", + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/typescript-estree": "7.14.1" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -4157,12 +4157,12 @@ } }, "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.1.tgz", - "integrity": "sha512-k/Bfne7lrP7hcb7m9zSsgcBmo+8eicqqfNAJ7uUY+jkTFpKeH2FSkWpFRtimBxgkyvqfu9jTPRbYOvud6isdXA==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.14.1.tgz", + "integrity": "sha512-Crb+F75U1JAEtBeQGxSKwI60hZmmzaqA3z9sYsVm8X7W5cwLEm5bRe0/uXS6+MR/y8CVpKSR/ontIAIEPFcEkA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/types": "7.14.1", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -4227,12 +4227,12 @@ } }, "node_modules/@stylistic/eslint-plugin-ts": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-ts/-/eslint-plugin-ts-2.2.1.tgz", - "integrity": "sha512-2AbpXGGorCEzDryth7RhOMJWlko+sxSs1lxL2tSXB5H/EffmXgLn1tMoMKgwYJW3s6v0BxJRr5BWj9B9JaZTUQ==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-ts/-/eslint-plugin-ts-2.2.2.tgz", + "integrity": "sha512-n6cYMSWTDDcrQLLxEKIrL/ihQ1lyyq6+gGp0g5VdstBElmImSRsQkCq+g3jRoDJIUo7tGO9lwQtGnuJ7oGB4kg==", "dev": true, "dependencies": { - "@stylistic/eslint-plugin-js": "2.2.1", + "@stylistic/eslint-plugin-js": "2.2.2", "@types/eslint": "^8.56.10", "@typescript-eslint/utils": "^7.12.0" }, @@ -4244,13 +4244,13 @@ } }, "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/scope-manager": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.1.tgz", - "integrity": "sha512-adbXNVEs6GmbzaCpymHQ0MB6E4TqoiVbC0iqG3uijR8ZYfpAXMGttouQzF4Oat3P2GxDVIrg7bMI/P65LiQZdg==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.14.1.tgz", + "integrity": "sha512-gPrFSsoYcsffYXTOZ+hT7fyJr95rdVe4kGVX1ps/dJ+DfmlnjFN/GcMxXcVkeHDKqsq6uAcVaQaIi3cFffmAbA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.13.1", - "@typescript-eslint/visitor-keys": "7.13.1" + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/visitor-keys": "7.14.1" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -4261,9 +4261,9 @@ } }, "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/types": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.1.tgz", - "integrity": "sha512-7K7HMcSQIAND6RBL4kDl24sG/xKM13cA85dc7JnmQXw2cBDngg7c19B++JzvJHRG3zG36n9j1i451GBzRuHchw==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.14.1.tgz", + "integrity": "sha512-mL7zNEOQybo5R3AavY+Am7KLv8BorIv7HCYS5rKoNZKQD9tsfGUpO4KdAn3sSUvTiS4PQkr2+K0KJbxj8H9NDg==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -4274,13 +4274,13 @@ } }, "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.1.tgz", - "integrity": "sha512-uxNr51CMV7npU1BxZzYjoVz9iyjckBduFBP0S5sLlh1tXYzHzgZ3BR9SVsNed+LmwKrmnqN3Kdl5t7eZ5TS1Yw==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.14.1.tgz", + "integrity": "sha512-k5d0VuxViE2ulIO6FbxxSZaxqDVUyMbXcidC8rHvii0I56XZPv8cq+EhMns+d/EVIL41sMXqRbK3D10Oza1bbA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.13.1", - "@typescript-eslint/visitor-keys": "7.13.1", + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/visitor-keys": "7.14.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -4302,15 +4302,15 @@ } }, "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/utils": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.1.tgz", - "integrity": "sha512-h5MzFBD5a/Gh/fvNdp9pTfqJAbuQC4sCN2WzuXme71lqFJsZtLbjxfSk4r3p02WIArOF9N94pdsLiGutpDbrXQ==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.14.1.tgz", + "integrity": "sha512-CMmVVELns3nak3cpJhZosDkm63n+DwBlDX8g0k4QUa9BMnF+lH2lr3d130M1Zt1xxmB3LLk3NV7KQCq86ZBBhQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.13.1", - "@typescript-eslint/types": "7.13.1", - "@typescript-eslint/typescript-estree": "7.13.1" + "@typescript-eslint/scope-manager": "7.14.1", + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/typescript-estree": "7.14.1" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -4324,12 +4324,12 @@ } }, "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.1.tgz", - "integrity": "sha512-k/Bfne7lrP7hcb7m9zSsgcBmo+8eicqqfNAJ7uUY+jkTFpKeH2FSkWpFRtimBxgkyvqfu9jTPRbYOvud6isdXA==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.14.1.tgz", + "integrity": "sha512-Crb+F75U1JAEtBeQGxSKwI60hZmmzaqA3z9sYsVm8X7W5cwLEm5bRe0/uXS6+MR/y8CVpKSR/ontIAIEPFcEkA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/types": "7.14.1", "eslint-visitor-keys": "^3.4.3" }, "engines": { diff --git a/ui/package.json b/ui/package.json index 2729650ac7d..284fe8a119d 100644 --- a/ui/package.json +++ b/ui/package.json @@ -47,7 +47,7 @@ "@angular/compiler-cli": "^16.2.12", "@angular/language-service": "^16.2.12", "@ionic/angular-toolkit": "^11.0.1", - "@stylistic/eslint-plugin": "^2.2.1", + "@stylistic/eslint-plugin": "^2.2.2", "@types/jasmine": "~4.3.6", "@types/jasminewd2": "~2.0.13", "@types/node": "^20.12.6", From f53933045d65bbff74c23899000dfbf567b3e9a1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Jun 2024 15:43:24 +0200 Subject: [PATCH 053/173] Bump @ngx-formly/ionic from 6.3.4 to 6.3.5 in /ui (#2680) Bumps [@ngx-formly/ionic](https://github.com/ngx-formly/ngx-formly) from 6.3.4 to 6.3.5. - [Release notes](https://github.com/ngx-formly/ngx-formly/releases) - [Changelog](https://github.com/ngx-formly/ngx-formly/blob/main/CHANGELOG.md) - [Commits](https://github.com/ngx-formly/ngx-formly/compare/v6.3.4...v6.3.5) --- updated-dependencies: - dependency-name: "@ngx-formly/ionic" dependency-type: direct:production update-type: version-update:semver-patch ... 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 | 16 ++++++++-------- ui/package.json | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 77326d2363d..68e4c750c74 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -19,7 +19,7 @@ "@angular/service-worker": "~16.2.12", "@ionic/angular": "^6.7.5", "@ngx-formly/core": "^6.3.0", - "@ngx-formly/ionic": "^6.3.4", + "@ngx-formly/ionic": "^6.3.5", "@ngx-formly/schematics": "^6.3.0", "@ngx-translate/core": "^15.0.0", "@nodro7/angular-mydatepicker": "^0.14.0", @@ -3360,9 +3360,9 @@ } }, "node_modules/@ngx-formly/core": { - "version": "6.3.4", - "resolved": "https://registry.npmjs.org/@ngx-formly/core/-/core-6.3.4.tgz", - "integrity": "sha512-xpO0FB50gpQI4uDrz6nYNolMvMIOdgP19diflcvAAtDy15I4BS+tzLKOCkM9HmAwmKQ59z3FUyzaODFEu+cuEg==", + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/@ngx-formly/core/-/core-6.3.5.tgz", + "integrity": "sha512-9p4yl7fr2Ojmm/uN7/nM1hYezheUxecEC0WZ0YI6jeSoEJR8NYTglVxTmHrpW5had2oolHeO39sAo9ttJNifSA==", "dependencies": { "tslib": "^2.0.0" }, @@ -3372,15 +3372,15 @@ } }, "node_modules/@ngx-formly/ionic": { - "version": "6.3.4", - "resolved": "https://registry.npmjs.org/@ngx-formly/ionic/-/ionic-6.3.4.tgz", - "integrity": "sha512-OHFZHe0E2sQoXEfYAzXMtvxt11mED2KZDjIAy0V35HGN0cC03GW1sToyTB2kmzLAyrH/HkhC3V7TurnrMbDSeQ==", + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/@ngx-formly/ionic/-/ionic-6.3.5.tgz", + "integrity": "sha512-WqcsG9YXr9PZdWOV+DVT++2cHrndMabRNlOOHx+VIf8QXQc1cyxq9UWW3CmBKw5lT1P2cy4cxxuKMk4EzNJV+Q==", "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@ionic/angular": "^6.0.0 || ^7.0.0", - "@ngx-formly/core": "6.3.4" + "@ngx-formly/core": "6.3.5" } }, "node_modules/@ngx-formly/schematics": { diff --git a/ui/package.json b/ui/package.json index 284fe8a119d..9790d1c8f7e 100644 --- a/ui/package.json +++ b/ui/package.json @@ -14,7 +14,7 @@ "@angular/service-worker": "~16.2.12", "@ionic/angular": "^6.7.5", "@ngx-formly/core": "^6.3.0", - "@ngx-formly/ionic": "^6.3.4", + "@ngx-formly/ionic": "^6.3.5", "@ngx-formly/schematics": "^6.3.0", "@ngx-translate/core": "^15.0.0", "@nodro7/angular-mydatepicker": "^0.14.0", From de0f1c27ec16b313d5e4fd46f6e1df0a01a63755 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Jun 2024 15:47:28 +0200 Subject: [PATCH 054/173] Bump org.apache.felix:org.apache.felix.http.jetty from 5.1.20 to 5.1.22 in /cnf (#2679) * Bump org.apache.felix:org.apache.felix.http.jetty in /cnf Bumps org.apache.felix:org.apache.felix.http.jetty from 5.1.20 to 5.1.22. --- updated-dependencies: - dependency-name: org.apache.felix:org.apache.felix.http.jetty 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 2231de4e1b2..885dc5f1629 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -203,7 +203,7 @@ org.apache.felix org.apache.felix.http.jetty - 5.1.20 + 5.1.22 diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index 03d14f79f83..ce9f9ce5f85 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -104,7 +104,7 @@ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ org.apache.felix.eventadmin;version='[1.6.4,1.6.5)',\ org.apache.felix.fileinstall;version='[3.7.4,3.7.5)',\ - org.apache.felix.http.jetty;version='[5.1.20,5.1.21)',\ + org.apache.felix.http.jetty;version='[5.1.22,5.1.23)',\ org.apache.felix.http.servlet-api;version='[3.0.0,3.0.1)',\ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index 6e383385d34..372ce3104b4 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -400,7 +400,7 @@ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ org.apache.felix.eventadmin;version='[1.6.4,1.6.5)',\ org.apache.felix.fileinstall;version='[3.7.4,3.7.5)',\ - org.apache.felix.http.jetty;version='[5.1.20,5.1.21)',\ + org.apache.felix.http.jetty;version='[5.1.22,5.1.23)',\ org.apache.felix.http.servlet-api;version='[3.0.0,3.0.1)',\ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ From e0bbfcd43c51bf0815f8d5e8c1278ba4a840e836 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Jun 2024 15:51:55 +0200 Subject: [PATCH 055/173] Bump org.apache.felix:org.apache.felix.webconsole from 5.0.2 to 5.0.4 in /cnf (#2678) * Bump org.apache.felix:org.apache.felix.webconsole in /cnf Bumps org.apache.felix:org.apache.felix.webconsole from 5.0.2 to 5.0.4. --- updated-dependencies: - dependency-name: org.apache.felix:org.apache.felix.webconsole 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 885dc5f1629..271f2e7233a 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -237,7 +237,7 @@ org.apache.felix org.apache.felix.webconsole - 5.0.2 + 5.0.4 diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index ce9f9ce5f85..3187a198622 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -109,7 +109,7 @@ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ org.apache.felix.scr;version='[2.2.12,2.2.13)',\ - org.apache.felix.webconsole;version='[5.0.2,5.0.3)',\ + org.apache.felix.webconsole;version='[5.0.4,5.0.5)',\ org.apache.felix.webconsole.plugins.ds;version='[2.3.0,2.3.1)',\ org.jetbrains.kotlin.osgi-bundle;version='[2.0.0,2.0.1)',\ org.jsr-305;version='[3.0.2,3.0.3)',\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index 372ce3104b4..f158c0a74bd 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -405,7 +405,7 @@ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ org.apache.felix.scr;version='[2.2.12,2.2.13)',\ - org.apache.felix.webconsole;version='[5.0.2,5.0.3)',\ + org.apache.felix.webconsole;version='[5.0.4,5.0.5)',\ org.apache.felix.webconsole.plugins.ds;version='[2.3.0,2.3.1)',\ org.eclipse.jetty.client;version='[9.4.28,9.4.29)',\ org.eclipse.jetty.http;version='[9.4.28,9.4.29)',\ From 679fe0f3f00e6855566e85cf5f23ea8b14b68c4b Mon Sep 17 00:00:00 2001 From: Kai J <99220919+da-Kai@users.noreply.github.com> Date: Wed, 26 Jun 2024 12:52:53 +0200 Subject: [PATCH 056/173] CI: implement codecov (#2685) --- .github/workflows/build.yml | 34 +++--------------------- .github/workflows/comment.yml | 50 ----------------------------------- README.md | 1 + build.gradle | 2 +- codecov.yml | 15 +++++++++++ 5 files changed, 20 insertions(+), 82 deletions(-) delete mode 100644 .github/workflows/comment.yml create mode 100644 codecov.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 74fa7fb6190..8211dc2cec2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -34,41 +34,13 @@ jobs: - name: Validate EdgeApp.bndrun run: git diff --exit-code io.openems.edge.application/EdgeApp.bndrun - # - # Generate Code-coverage-report - # - name: Generate JaCoCo Code-coverage-report run: ./gradlew jacocoTestReport - - - name: Summarize JaCoCo Report - id: jacoco - uses: cicirello/jacoco-badge-generator@v2 - with: - jacoco-csv-file: 'io.openems.*/generated/reports/jacoco/**/*.csv' - generate-coverage-badge: false - - - 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 > 90" | bc -l) )); then - color=success; - elif (( $(echo "$coverage > 80" | bc -l) )); then - color=green; - elif (( $(echo "$coverage > 60" | bc -l) )); then - color=yellow; - fi; - 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@v4 + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v4 with: - name: jacoco_report - path: jacoco/ + token: ${{ secrets.CODECOV_TOKEN }} build-ui: runs-on: ubuntu-latest diff --git a/.github/workflows/comment.yml b/.github/workflows/comment.yml deleted file mode 100644 index f8ce4e26a0f..00000000000 --- a/.github/workflows/comment.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: Comment Pull_Request -on: - workflow_run: - workflows: [Build OpenEMS] - types: - - completed - -jobs: - comment_jacoco: - runs-on: ubuntu-latest - if: ${{ github.event.workflow_run.conclusion == 'success' }} - steps: - - name: 'Download artifact' - 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, - }); - let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => { - 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', - }); - let fs = require('fs'); - fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/jacoco_report.zip`, Buffer.from(download.data)); - - - name: 'Unzip artifact' - run: unzip jacoco_report.zip - - - name: 'Comment on PR' - uses: actions/github-script@v6 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - let fs = require('fs'); - 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, - issue_number: issue_number, - body: comment - }); \ No newline at end of file diff --git a/README.md b/README.md index 19a294a511f..09bf75eeaac 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ [![Build Status](https://github.com/OpenEMS/openems/actions/workflows/build.yml/badge.svg)](https://github.com/OpenEMS/openems/actions/workflows/build.yml) [![Gitpod live-demo](https://img.shields.io/badge/Gitpod-live--demo-blue?logo=gitpod)](https://gitpod.io/#https://github.com/OpenEMS/openems/tree/main) [![Cite via Zenodo](https://zenodo.org/badge/DOI/10.5281/zenodo.4440884.svg)](https://doi.org/10.5281/zenodo.4440883) +[![codecov](https://codecov.io/gh/openems/openems/graph/badge.svg?token=xliIughqt1)](https://codecov.io/gh/openems/openems)

      the Feneco - OpenEMS Logo diff --git a/build.gradle b/build.gradle index f616cf7b1e8..a432a1fa395 100644 --- a/build.gradle +++ b/build.gradle @@ -56,7 +56,7 @@ subprojects { jacocoTestReport { reports { xml.required = true - csv.required = true + csv.required = false html.required = false } // Exclude com.dalsemi.onewire diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 00000000000..3ee859df746 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,15 @@ +coverage: + round: up + precision: 2 + status: + project: + default: + target: '60%' + +comment: + layout: "condensed_header, diff" + behavior: default + require_changes: false + require_base: false + require_head: true + hide_project_coverage: true \ No newline at end of file From d54ba1b926c26871da3161c8a385958509aa8e87 Mon Sep 17 00:00:00 2001 From: Kai J <99220919+da-Kai@users.noreply.github.com> Date: Wed, 26 Jun 2024 21:39:15 +0200 Subject: [PATCH 057/173] CI: update docs build (#2686) --- doc/build.gradle | 2 +- doc/build/.gitignore | 2 +- doc/build/package.json | 4 ++-- doc/build/uibundle_openems.zip | Bin 280789 -> 580960 bytes settings.gradle | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/build.gradle b/doc/build.gradle index 95939554fd6..4aaf5ee6b5a 100644 --- a/doc/build.gradle +++ b/doc/build.gradle @@ -3,7 +3,7 @@ plugins { } node { - nodeModulesDir = file("${projectDir}/build") + nodeProjectDir = file("${projectDir}/build") } /* diff --git a/doc/build/.gitignore b/doc/build/.gitignore index c712b273a34..45220110096 100644 --- a/doc/build/.gitignore +++ b/doc/build/.gitignore @@ -1,2 +1,2 @@ -/mode_modules/ +/node_modules/ /www/ \ No newline at end of file diff --git a/doc/build/package.json b/doc/build/package.json index b83512c5802..fbf607bbcb4 100644 --- a/doc/build/package.json +++ b/doc/build/package.json @@ -1,7 +1,7 @@ { "name": "openems-doc", "version": "1.0.0", - "dependencies": { - "antora": "^3.1.6" + "devDependencies": { + "antora": "^3.1.8" } } diff --git a/doc/build/uibundle_openems.zip b/doc/build/uibundle_openems.zip index e984c39af21352fee7236c36e1f68bde63266396..2ed7adc83ec03e5b88208014814702f6b9060e07 100644 GIT binary patch delta 375762 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�eQyhyI>(m-?aqLuia87OK? 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 z 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Μ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

      c6BiduX-xXulDvN~O8mlUC*F+9)Rv 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 diff --git a/settings.gradle b/settings.gradle index aa1e1f279aa..8d98e1d0be0 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,7 +2,7 @@ pluginManagement { plugins { id 'biz.aQute.bnd.workspace' version "${bnd_version}" id 'biz.aQute.bnd' version "${bnd_version}" - id 'com.github.node-gradle.node' version "5.0.0" + id 'com.github.node-gradle.node' version "7.0.2" } repositories { maven { From 89db02871164617043a9954908e5038676e76212 Mon Sep 17 00:00:00 2001 From: Hiromasa Ihara Date: Thu, 27 Jun 2024 04:40:35 +0900 Subject: [PATCH 058/173] UI: remove ts-strict-ignore for env files and add typing (#2683) --- ui/src/environments/index.ts | 9 +++++---- ui/src/themes/openems/environments/backend-dev.ts | 1 - ui/src/themes/openems/environments/backend-docker.ts | 9 +++++++-- ui/src/themes/openems/environments/backend-prod.ts | 1 - ui/src/themes/openems/environments/edge-dev.ts | 1 - ui/src/themes/openems/environments/edge-docker.ts | 9 +++++++-- ui/src/themes/openems/environments/edge-prod.ts | 1 - ui/src/themes/openems/environments/gitpod.ts | 1 - 8 files changed, 19 insertions(+), 13 deletions(-) diff --git a/ui/src/environments/index.ts b/ui/src/environments/index.ts index d0180b57ae8..8134ed5feee 100644 --- a/ui/src/environments/index.ts +++ b/ui/src/environments/index.ts @@ -21,7 +21,7 @@ export interface Environment { readonly docsUrlPrefix: string; readonly links: { - readonly COMMON_STORAGE: string, + readonly COMMON_STORAGE: string | null, readonly FORGET_PASSWORD: string, readonly EVCS_KEBA_KECONTACT: string, readonly EVCS_HARDY_BARTH: string, @@ -41,8 +41,9 @@ export interface Environment { readonly CONTROLLER_API_REST_READ: string, readonly CONTROLLER_API_REST_READWRITE: string, - readonly SETTINGS_ALERTING: string, - readonly SETTINGS_NETWORK_CONFIGURATION: string, + readonly SETTINGS_ALERTING: string | null, + readonly SETTINGS_NETWORK_CONFIGURATION: string | null, + readonly EVCS_CLUSTER: string, readonly WARRANTY: { readonly HOME: { @@ -89,5 +90,5 @@ export interface Environment { APP_IMAGE: (language: string, appId: string) => string | null; }, }, - readonly PRODUCT_TYPES: (translate: TranslateService) => Filter + readonly PRODUCT_TYPES: (translate: TranslateService) => Filter | null } diff --git a/ui/src/themes/openems/environments/backend-dev.ts b/ui/src/themes/openems/environments/backend-dev.ts index 0f93f985f5d..f48b00c5e42 100644 --- a/ui/src/themes/openems/environments/backend-dev.ts +++ b/ui/src/themes/openems/environments/backend-dev.ts @@ -1,4 +1,3 @@ -// @ts-strict-ignore import { Environment } from "src/environments"; import { theme } from "./theme"; diff --git a/ui/src/themes/openems/environments/backend-docker.ts b/ui/src/themes/openems/environments/backend-docker.ts index 5ca08fb74f8..28c03b27713 100644 --- a/ui/src/themes/openems/environments/backend-docker.ts +++ b/ui/src/themes/openems/environments/backend-docker.ts @@ -1,12 +1,17 @@ -// @ts-strict-ignore import { Environment } from "src/environments"; import { theme } from "./theme"; +// In docker test environment variable window.env is injected. +// cf. +// - tools/docker/ui/root/etc/s6-overlay/s6-rc.d/init-nginx/run +// - tools/docker/ui/assets/env.template.js +const window_env = (window as any).env as { [key: string]: string}; + export const environment: Environment = { ...theme, ...{ backend: 'OpenEMS Backend', - url: window["env"]["websocket"], + url: window_env.websocket, production: true, debugMode: false, diff --git a/ui/src/themes/openems/environments/backend-prod.ts b/ui/src/themes/openems/environments/backend-prod.ts index 114c43274f1..ae5bb5eb32f 100644 --- a/ui/src/themes/openems/environments/backend-prod.ts +++ b/ui/src/themes/openems/environments/backend-prod.ts @@ -1,4 +1,3 @@ -// @ts-strict-ignore import { Environment } from "src/environments"; import { theme } from "./theme"; diff --git a/ui/src/themes/openems/environments/edge-dev.ts b/ui/src/themes/openems/environments/edge-dev.ts index a6fd796b39e..164dd04f34e 100644 --- a/ui/src/themes/openems/environments/edge-dev.ts +++ b/ui/src/themes/openems/environments/edge-dev.ts @@ -1,4 +1,3 @@ -// @ts-strict-ignore import { Environment } from "src/environments"; import { theme } from "./theme"; diff --git a/ui/src/themes/openems/environments/edge-docker.ts b/ui/src/themes/openems/environments/edge-docker.ts index 80ed1d80a99..479b15e852b 100644 --- a/ui/src/themes/openems/environments/edge-docker.ts +++ b/ui/src/themes/openems/environments/edge-docker.ts @@ -1,12 +1,17 @@ -// @ts-strict-ignore import { Environment } from "src/environments"; import { theme } from "./theme"; +// In docker test environment, variable window.env is injected. +// cf. +// - tools/docker/ui/root/etc/s6-overlay/s6-rc.d/init-nginx/run +// - tools/docker/ui/assets/env.template.js +const window_env = (window as any).env as { [key: string]: string}; + export const environment: Environment = { ...theme, ...{ backend: 'OpenEMS Edge', - url: window["env"]["websocket"], + url: window_env.websocket, production: true, debugMode: false, diff --git a/ui/src/themes/openems/environments/edge-prod.ts b/ui/src/themes/openems/environments/edge-prod.ts index 4f023294025..bcaf40f6901 100644 --- a/ui/src/themes/openems/environments/edge-prod.ts +++ b/ui/src/themes/openems/environments/edge-prod.ts @@ -1,4 +1,3 @@ -// @ts-strict-ignore import { Environment } from "src/environments"; import { theme } from "./theme"; diff --git a/ui/src/themes/openems/environments/gitpod.ts b/ui/src/themes/openems/environments/gitpod.ts index 4b8f7f22ead..1ef2f8ca499 100644 --- a/ui/src/themes/openems/environments/gitpod.ts +++ b/ui/src/themes/openems/environments/gitpod.ts @@ -1,4 +1,3 @@ -// @ts-strict-ignore import { Environment } from "src/environments"; import { theme } from "./theme"; From f13032596b609147d5d0dc0ae186618b111a2f0c Mon Sep 17 00:00:00 2001 From: Hiromasa Ihara Date: Thu, 27 Jun 2024 04:42:28 +0900 Subject: [PATCH 059/173] UI: update eslint rules and refactor types (#2676) * fix: ban Object, Function types * fix: snip always option in eol-last. because this is default. * fix: snip always option in semi. because this is default. cf. https://eslint.style/rules/default/semi * fix: reorder eslint rules to clear rule category 1. eslint native rules 2. unused-imports 3. typescript-eslint 4. angular-eslint 5. stylistic --- ui/.eslintrc.json | 24 +++++++------------ .../system/maintenance/maintenance.ts | 2 +- .../system/oe-system-update.component.ts | 2 +- .../modal/modal-button/modal-button.ts | 2 +- .../shared/oe-formly-component.ts | 4 ++-- ui/src/app/shared/service/service.ts | 2 +- 6 files changed, 14 insertions(+), 22 deletions(-) diff --git a/ui/.eslintrc.json b/ui/.eslintrc.json index 419e1faab58..939db3ad5a0 100644 --- a/ui/.eslintrc.json +++ b/ui/.eslintrc.json @@ -30,15 +30,8 @@ "plugin:@angular-eslint/template/process-inline-templates" ], "rules": { + "curly": "error", "unused-imports/no-unused-imports": "error", - "@stylistic/semi": [ - "error", - "always" - ], - "@stylistic/quote-props": [ - "warn", - "consistent" - ], "@typescript-eslint/explicit-member-accessibility": [ "error", { @@ -67,15 +60,16 @@ "style": "camelCase" } ], - "curly": "error", + "@stylistic/semi": "error", + "@stylistic/quote-props": [ + "warn", + "consistent" + ], "@stylistic/comma-dangle": [ "error", "always-multiline" ], - "@stylistic/eol-last": [ - "error", - "always" - ], + "@stylistic/eol-last": "error", "@stylistic/no-trailing-spaces": "error", "@typescript-eslint/no-unused-vars": [ "error", @@ -90,9 +84,7 @@ { "extendDefaults": true, "types": { - "{}": false, - "Object": false, - "Function": false + "{}": false } } ] diff --git a/ui/src/app/edge/settings/system/maintenance/maintenance.ts b/ui/src/app/edge/settings/system/maintenance/maintenance.ts index 05ffad598c8..cb50d645a98 100644 --- a/ui/src/app/edge/settings/system/maintenance/maintenance.ts +++ b/ui/src/app/edge/settings/system/maintenance/maintenance.ts @@ -45,7 +45,7 @@ export class MaintenanceComponent implements OnInit { protected systemRestartState: BehaviorSubject<{ key: Type, state: SystemRestartState }> = new BehaviorSubject({ key: null, state: SystemRestartState.INITIAL }); protected spinnerId: string = MaintenanceComponent.SELECTOR; protected readonly SystemRestartState = SystemRestartState; - protected confirmationAlert: Function = (type: Type) => presentAlert(this.alertCtrl, this.translate, { + protected confirmationAlert: (type: Type) => void = (type: Type) => presentAlert(this.alertCtrl, this.translate, { message: this.translate.instant('SETTINGS.SYSTEM_UPDATE.RESTART_WARNING', { system: environment.edgeShortName }), subHeader: this.translate.instant('SETTINGS.SYSTEM_UPDATE.RESTART_CONFIRMATION', { system: environment.edgeShortName }), buttons: [{ diff --git a/ui/src/app/edge/settings/system/oe-system-update.component.ts b/ui/src/app/edge/settings/system/oe-system-update.component.ts index f76d9d9725f..7b0689beab5 100644 --- a/ui/src/app/edge/settings/system/oe-system-update.component.ts +++ b/ui/src/app/edge/settings/system/oe-system-update.component.ts @@ -21,7 +21,7 @@ export class OeSystemUpdateComponent implements OnInit, OnDestroy { protected executeUpdate: ExecuteSystemUpdate = null; protected isWaiting: boolean; - protected confirmationAlert: Function = () => presentAlert(this.alertCtrl, this.translate, { + protected confirmationAlert: () => void = () => presentAlert(this.alertCtrl, this.translate, { message: this.translate.instant('SETTINGS.SYSTEM_UPDATE.WARNING', { system: environment.edgeShortName }), subHeader: this.translate.instant('SETTINGS.SYSTEM_UPDATE.SUB_HEADER'), buttons: [{ diff --git a/ui/src/app/shared/genericComponents/modal/modal-button/modal-button.ts b/ui/src/app/shared/genericComponents/modal/modal-button/modal-button.ts index 74d01588bb1..0c118509ce9 100644 --- a/ui/src/app/shared/genericComponents/modal/modal-button/modal-button.ts +++ b/ui/src/app/shared/genericComponents/modal/modal-button/modal-button.ts @@ -18,5 +18,5 @@ export type ButtonLabel = { value: string; /** Icons for Button, displayed above the corresponding name */ icons?: Icon; - callback?: Function; + callback?: () => void; }; diff --git a/ui/src/app/shared/genericComponents/shared/oe-formly-component.ts b/ui/src/app/shared/genericComponents/shared/oe-formly-component.ts index 67d6d92e92a..50516a057d5 100644 --- a/ui/src/app/shared/genericComponents/shared/oe-formly-component.ts +++ b/ui/src/app/shared/genericComponents/shared/oe-formly-component.ts @@ -4,7 +4,7 @@ import { FormlyFieldConfig } from "@ngx-formly/core"; import { TranslateService } from "@ngx-translate/core"; import { filter } from "rxjs/operators"; -import { ChannelAddress, EdgeConfig, Service } from "../../shared"; +import { CurrentData, ChannelAddress, EdgeConfig, Service } from "../../shared"; import { SharedModule } from "../../shared.module"; import { Role } from "../../type/role"; import { TextIndentation } from "../modal/modal-line/modal-line"; @@ -99,7 +99,7 @@ export namespace OeFormlyField { export type ValueFromChannelsLine = { type: 'value-from-channels-line', name: string, - value: Function, + value: (data: CurrentData) => string, channelsToSubscribe: ChannelAddress[], indentation?: TextIndentation, filter?: (value: number[] | null) => boolean, diff --git a/ui/src/app/shared/service/service.ts b/ui/src/app/shared/service/service.ts index 771b140ab6e..64997f0428c 100644 --- a/ui/src/app/shared/service/service.ts +++ b/ui/src/app/shared/service/service.ts @@ -126,7 +126,7 @@ export class Service extends AbstractService { // this.notify(notification); } - public setCurrentComponent(currentPageTitle: string | { languageKey: string, interpolateParams?: Object }, activatedRoute: ActivatedRoute): Promise { + public setCurrentComponent(currentPageTitle: string | { languageKey: string, interpolateParams?: {} }, activatedRoute: ActivatedRoute): Promise { return new Promise((resolve, reject) => { // Set the currentPageTitle only once per ActivatedRoute if (this.currentActivatedRoute != activatedRoute) { From f63a533b36f7f05a135ecbbb8565b66c696100f3 Mon Sep 17 00:00:00 2001 From: Kai J <99220919+da-Kai@users.noreply.github.com> Date: Fri, 28 Jun 2024 10:49:21 +0200 Subject: [PATCH 060/173] CI: update github-actions using dependabot (#2688) --- .github/dependabot.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index abb98f69b4c..21080d06c45 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -12,3 +12,9 @@ updates: interval: weekly open-pull-requests-limit: 10 target-branch: develop +- package-ecosystem: "github-actions" + directory: "/.github/workflows" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + target-branch: develop From 7ea3e06953679d2cfee830467ee8d9fa3910fd0c Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Fri, 28 Jun 2024 12:26:24 +0200 Subject: [PATCH 061/173] FEMS Backports 2024-06 (2) (#2692) - UI: prepare build for native Android App - SymmetricEss: add Min-/MaxCellVoltage-/Temperature channels to modbus slave table - Added the following register to the Modbus slave table - MIN_CELL_VOLTAGE - MAX_CELL_VOLTAGE - MIN_CELL_TEMPERATURE - MAX_CELL_TEMPERATURE - UI: add footer subnavigation - New subnavigation in /history/production - HeatingElement: added JUnit test - UI: allow SNAPSHOT update for OWNER/INSTALLER - Remove special handling for SNAPSHOT versions in update handler - Tools: add internal tool to convert between JSONRPC and XLSX - UI: add loading screen during authentication - Introduction of loading screen, shown during authentification process - Skip "Login"-screen if a valid authentication token exists - EdgeConfig: remove unused factories & properties - Removed unused factories & factory properties from EdgeConfig - Added separate request to get all factories and properties for component update / installation - UI: fix error messages shown in status.component - fix display of error message in status.component, was showing property channels as well - Apps for DiscovergyMeter and TimeInfluxDb - SunSpec: set persistence priority VERY_LOW - Backend improvements - Add logging for certain commands - Improve Metadata Odoo performance - Improve Postgres performance - reduce update time from 120 to 30 seconds - fix Sum-State update bug - InfluxDB: - extract channel filter to separate class; add unit tests - add configurable channel blacklist - improve FieldTypeConflictHandler; add unit tests - StringUtils: drop matchesIntegerPattern and matchesFloatPattern; replace with Guava - ThreadPoolUtils: fix possible NullPointerException - ComponentManagerImpl: remove Thread Sleep - Remove test thread sleep in "GetChannel" handler - UI: Channels fix setting values - Bug: "Cannot read properties of undefined (reading 'componentId')" when setting a value in the channels view - Debian package: implement apt purge - CI: Improve java build - Debian: fix build ```bash + dpkg-deb -Zxz --build debian /woodpecker/src/git.intranet.fenecon.de/FENECON/fems/build/target/fems.debdpkg-deb: error: maintainer script 'postrm' has bad permissions 644 (must be >=0555 and <=0775) ``` - CI: split build image - Split android sdk into a seperate image. - add bash image to git - Replace StringUtils.matches*Pattern --------- Co-authored-by: Johann Kaufmann <165755282+johannk24@users.noreply.github.com> Co-authored-by: Kai Jeschek <99220919+da-Kai@users.noreply.github.com> Co-authored-by: Lukas Rieger <73471197+lukasrgr@users.noreply.github.com> Co-authored-by: Manoj-Kumar Varikela <20610573+manojniit@users.noreply.github.com> Co-authored-by: Maximilian Lang <35968713+mlang97@users.noreply.github.com> Co-authored-by: Michael Grill <59126309+michaelgrill@users.noreply.github.com> Co-authored-by: Pooran Chandrashekaraiah <46567310+pooran-c@users.noreply.github.com> Co-authored-by: Sebastian Asen <47855186+sebastianasen@users.noreply.github.com> Co-authored-by: Stefan Feilmeier <3515268+sfeilmeier@users.noreply.github.com> Co-authored-by: Hueseyin Sahutoglu <34771592+huseyinsaht@users.noreply.github.com> --- build.gradle | 4 +- cnf/pom.xml | 9 +- codecov.yml | 4 +- gradle.properties | 2 +- .../BackendApp.bndrun | 6 +- .../EdgeRpcRequestHandler.java | 166 +- .../backend/metadata/odoo/MetadataOdoo.java | 104 +- .../odoo/postgres/PeriodicWriteWorker.java | 124 +- .../aggregatedinflux/AllowedChannels.java | 26 +- .../timedata/influx/ChannelFilter.java | 96 + .../backend/timedata/influx/Config.java | 3 + .../influx/FieldTypeConflictHandler.java | 179 +- .../timedata/influx/TimedataInfluxDb.java | 175 +- .../timedata/influx/ChannelFilterTest.java | 52 + .../influx/FieldTypeConflictHandlerTest.java | 51 + .../timedata/influx/TimedataInfluxDbTest.java | 34 - .../timedata/timescaledb/internal/Type.java | 32 +- .../timescaledb/internal/TypeTest.java | 2 +- .../backend/uiwebsocket/impl/OnRequest.java | 115 +- .../common/oem/DummyOpenemsEdgeOem.java | 2 + .../io/openems/common/types/EdgeConfig.java | 18 +- .../io/openems/common/utils/StringUtils.java | 29 - .../openems/common/utils/ThreadPoolUtils.java | 10 +- .../jsonrpc/response/JsonrpcToXlsxApp.java | 63 + .../jsonrpc/response/XlsxToJsonrpcApp.java | 70 + .../openems/common/utils/StringUtilsTest.java | 5 - io.openems.edge.application/EdgeApp.bndrun | 6 +- .../edge/bridge/modbus/sunspec/Point.java | 6 +- .../edge/bridge/modbus/sunspec/PointTest.java | 29 + .../ControllerHeatingElementImplTest4.java | 95 + .../edge/app/api/TimedataInfluxDb.java | 219 + .../app/integratedsystem/FeneconHome20.java | 1 - .../app/integratedsystem/FeneconHome30.java | 1 - .../edge/app/meter/DiscovergyMeter.java | 229 + .../core/appmanager/OpenemsAppCategory.java | 6 + .../core/appmanager/translation_de.properties | 35 + .../core/appmanager/translation_en.properties | 34 + .../ComponentManagerImpl.java | 37 +- .../jsonrpc/GetAllComponentFactories.java | 66 + .../jsonrpc/GetPropertiesOfFactory.java | 76 + .../io/openems/edge/core/appmanager/Apps.java | 22 + .../core/appmanager/TestTranslations.java | 8 + .../io/openems/edge/ess/api/SymmetricEss.java | 4 + .../common/AbstractChannelManager.java | 12 + .../shared/influxdb/proxy/InfluxQlProxy.java | 64 +- .../influxdb/proxy/InfluxQlProxyTest.java | 10 + io.openems.wrapper/bnd.bnd | 3 +- io.openems.wrapper/fastexcel.bnd | 7 +- tools/build-debian-package.sh | 12 +- tools/debian/DEBIAN/postrm | 16 + tools/drone/openems-android.sh | 37 + tools/drone/openems-bash.sh | 19 + tools/drone/openems-build.sh | 29 + ui/README.md | 36 +- ui/android/.idea/.gitignore | 3 + ui/android/.idea/compiler.xml | 6 + ui/android/.idea/jarRepositories.xml | 30 + ui/android/.idea/misc.xml | 9 + ui/android/app/.gitignore | 2 + ui/android/app/build.gradle | 88 + ui/android/app/capacitor.build.gradle | 24 + ui/android/app/proguard-rules.pro | 21 + .../myapp/ExampleInstrumentedTest.java | 26 + ui/android/app/src/main/AndroidManifest.xml | 39 + .../getcapacitor/myapp/ExampleUnitTest.java | 18 + ui/android/build.gradle | 32 + ui/android/capacitor.settings.gradle | 21 + ui/android/gradle.properties | 22 + ui/android/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 61608 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + ui/android/gradlew | 244 + ui/android/gradlew.bat | 92 + ui/android/keystore.properties | 4 + ui/android/settings.gradle | 5 + ui/android/variables.gradle | 16 + ui/capacitor.config.ts | 47 + ui/ionic.config.json | 6 +- ui/package-lock.json | 10601 +++++++++++----- ui/package.json | 18 +- ui/src/app/app-routing.module.ts | 17 +- ui/src/app/app.component.ts | 6 + ui/src/app/app.module.ts | 2 + ui/src/app/app.service.ts | 154 + .../edge/history/common/energy/flat/flat.ts | 8 + .../common/production/details/chart/chart.ts | 88 + .../production/details/details.overview.html | 6 + .../production/details/details.overview.ts | 24 + .../common/production/overview/overview.html | 1 + .../common/production/overview/overview.ts | 19 +- .../history/common/production/production.ts | 4 + .../app/edge/history/history.component.html | 5 +- ui/src/app/edge/history/history.component.ts | 2 + ui/src/app/edge/history/historydataservice.ts | 6 + ui/src/app/edge/live/live.component.html | 4 + ui/src/app/edge/live/live.component.ts | 4 + ui/src/app/edge/live/livedataservice.ts | 10 + .../settings/channels/channels.component.html | 4 +- .../settings/channels/channels.component.ts | 10 +- .../component/install/index.component.ts | 67 +- .../component/install/install.component.ts | 100 +- .../component/update/index.component.ts | 3 - .../component/update/update.component.ts | 82 +- .../settings/system/executeSystemUpdate.ts | 48 +- ui/src/app/index/index.module.ts | 2 + ui/src/app/index/login.component.html | 2 +- ui/src/app/index/login.component.ts | 4 + ui/src/app/index/shared/loading-screen.html | 5 + ui/src/app/index/shared/loading-screen.ts | 38 + ui/src/app/shared/directive/autofill.ts | 25 + ui/src/app/shared/edge/edge.spec.ts | 53 + ui/src/app/shared/edge/edge.ts | 36 +- ui/src/app/shared/edge/edgeconfig.spec.ts | 56 +- ui/src/app/shared/edge/edgeconfig.ts | 115 +- .../chart/abstracthistorychart.html | 7 +- .../shared/genericComponents/chart/chart.html | 4 +- .../footer-navigation/footerNavigation.html | 48 + .../footer-navigation/footerNavigation.ts | 114 + .../genericComponents/genericComponents.ts | 3 + .../genericComponents/shared/converter.ts | 1 + .../genericComponents/shared/dataservice.ts | 3 + .../request/getPropertiesOfFactoryRequest.ts | 33 + .../getPropertiesOfFactoryResponse.ts | 31 + ui/src/app/shared/service/service.ts | 12 +- ui/src/app/shared/service/utils.ts | 2 +- ui/src/app/shared/service/websocket.ts | 2 +- ui/src/app/shared/shared.ts | 13 + .../status/single/status.component.spec.ts | 2 +- .../shared/status/single/status.component.ts | 6 + ui/src/assets/i18n/de.json | 5 +- ui/src/assets/i18n/en.json | 5 +- 130 files changed, 11325 insertions(+), 3857 deletions(-) create mode 100644 io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/ChannelFilter.java create mode 100644 io.openems.backend.timedata.influx/test/io/openems/backend/timedata/influx/ChannelFilterTest.java delete mode 100644 io.openems.backend.timedata.influx/test/io/openems/backend/timedata/influx/TimedataInfluxDbTest.java create mode 100644 io.openems.common/test/io/openems/common/jsonrpc/response/JsonrpcToXlsxApp.java create mode 100644 io.openems.common/test/io/openems/common/jsonrpc/response/XlsxToJsonrpcApp.java create mode 100644 io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/PointTest.java create mode 100644 io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerHeatingElementImplTest4.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/api/TimedataInfluxDb.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/meter/DiscovergyMeter.java create mode 100644 io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetAllComponentFactories.java create mode 100644 io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetPropertiesOfFactory.java create mode 100755 tools/debian/DEBIAN/postrm create mode 100755 tools/drone/openems-android.sh create mode 100644 tools/drone/openems-bash.sh create mode 100644 tools/drone/openems-build.sh create mode 100644 ui/android/.idea/.gitignore create mode 100644 ui/android/.idea/compiler.xml create mode 100644 ui/android/.idea/jarRepositories.xml create mode 100644 ui/android/.idea/misc.xml create mode 100644 ui/android/app/.gitignore create mode 100644 ui/android/app/build.gradle create mode 100644 ui/android/app/capacitor.build.gradle create mode 100644 ui/android/app/proguard-rules.pro create mode 100644 ui/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java create mode 100644 ui/android/app/src/main/AndroidManifest.xml create mode 100644 ui/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java create mode 100644 ui/android/build.gradle create mode 100644 ui/android/capacitor.settings.gradle create mode 100644 ui/android/gradle.properties create mode 100644 ui/android/gradle/wrapper/gradle-wrapper.jar create mode 100644 ui/android/gradle/wrapper/gradle-wrapper.properties create mode 100644 ui/android/gradlew create mode 100644 ui/android/gradlew.bat create mode 100644 ui/android/keystore.properties create mode 100644 ui/android/settings.gradle create mode 100644 ui/android/variables.gradle create mode 100644 ui/capacitor.config.ts create mode 100644 ui/src/app/app.service.ts create mode 100644 ui/src/app/edge/history/common/production/details/chart/chart.ts create mode 100644 ui/src/app/edge/history/common/production/details/details.overview.html create mode 100644 ui/src/app/edge/history/common/production/details/details.overview.ts create mode 100644 ui/src/app/index/shared/loading-screen.html create mode 100644 ui/src/app/index/shared/loading-screen.ts create mode 100644 ui/src/app/shared/directive/autofill.ts create mode 100644 ui/src/app/shared/edge/edge.spec.ts create mode 100644 ui/src/app/shared/genericComponents/footer-navigation/footerNavigation.html create mode 100644 ui/src/app/shared/genericComponents/footer-navigation/footerNavigation.ts create mode 100644 ui/src/app/shared/jsonrpc/request/getPropertiesOfFactoryRequest.ts create mode 100644 ui/src/app/shared/jsonrpc/response/getPropertiesOfFactoryResponse.ts diff --git a/build.gradle b/build.gradle index a432a1fa395..72457c55315 100644 --- a/build.gradle +++ b/build.gradle @@ -80,8 +80,8 @@ subprojects { html.required = false sarif.required = false } - minHeapSize = "256m" - maxHeapSize = "1g" + minHeapSize = "512m" + maxHeapSize = "2048m" // Exclude com.dalsemi.onewire exclude '**/com/dalsemi/onewire/*' } diff --git a/cnf/pom.xml b/cnf/pom.xml index 271f2e7233a..79d3e7d73c3 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -9,8 +9,8 @@ - biz.aQute.bnd.workspace - biz.aQute.bnd.workspace.gradle.plugin + biz.aQute.bnd + biz.aQute.bnd.gradle 7.0.0 @@ -262,6 +262,11 @@ fastexcel 0.18.0 + + org.dhatim + fastexcel-reader + 0.18.0 + org.eclipse.paho diff --git a/codecov.yml b/codecov.yml index 3ee859df746..1f9dcb53ef3 100644 --- a/codecov.yml +++ b/codecov.yml @@ -4,7 +4,7 @@ coverage: status: project: default: - target: '60%' + target: auto #default comment: layout: "condensed_header, diff" @@ -12,4 +12,4 @@ comment: require_changes: false require_base: false require_head: true - hide_project_coverage: true \ No newline at end of file + hide_project_coverage: true diff --git a/gradle.properties b/gradle.properties index 9779ffb8f4e..ac682e37020 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,4 +10,4 @@ maven.repo.local=cnf org.gradle.caching=true org.gradle.parallel=false org.gradle.workers.max=1 -org.gradle.jvmargs=-Xms256m -Xmx512m "-XX:MaxMetaspaceSize=256m" +org.gradle.jvmargs=-Xms512m -Xmx2048m "-XX:MaxMetaspaceSize=512m" diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index 3187a198622..e103405ba64 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -60,6 +60,7 @@ -runbundles: \ Java-WebSocket;version='[1.5.4,1.5.5)',\ + com.fasterxml.aalto-xml;version='[1.3.2,1.3.3)',\ com.google.gson;version='[2.11.0,2.11.1)',\ com.google.guava;version='[33.2.1,33.2.2)',\ com.google.guava.failureaccess;version='[1.0.2,1.0.3)',\ @@ -100,7 +101,9 @@ io.openems.wrapper.retrofit-converter-scalars;version=snapshot,\ io.openems.wrapper.retrofit2;version=snapshot,\ io.reactivex.rxjava3.rxjava;version='[3.1.8,3.1.9)',\ + org.apache.commons.commons-compress;version='[1.26.1,1.26.2)',\ org.apache.commons.commons-csv;version='[1.10.0,1.10.1)',\ + org.apache.commons.commons-io;version='[2.15.1,2.15.2)',\ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ org.apache.felix.eventadmin;version='[1.6.4,1.6.5)',\ org.apache.felix.fileinstall;version='[3.7.4,3.7.5)',\ @@ -121,4 +124,5 @@ org.osgi.util.promise;version='[1.3.0,1.3.1)',\ org.owasp.encoder;version='[1.2.3,1.2.4)',\ org.postgresql.jdbc;version='[42.7.3,42.7.4)',\ - reactive-streams;version='[1.0.4,1.0.5)' \ No newline at end of file + reactive-streams;version='[1.0.4,1.0.5)',\ + stax2-api;version='[4.2.0,4.2.1)' \ No newline at end of file diff --git a/io.openems.backend.core/src/io/openems/backend/core/jsonrpcrequesthandler/EdgeRpcRequestHandler.java b/io.openems.backend.core/src/io/openems/backend/core/jsonrpcrequesthandler/EdgeRpcRequestHandler.java index dcb7a5a800e..c98e855c17d 100644 --- a/io.openems.backend.core/src/io/openems/backend/core/jsonrpcrequesthandler/EdgeRpcRequestHandler.java +++ b/io.openems.backend.core/src/io/openems/backend/core/jsonrpcrequesthandler/EdgeRpcRequestHandler.java @@ -1,14 +1,23 @@ package io.openems.backend.core.jsonrpcrequesthandler; +import static io.openems.common.utils.JsonUtils.getAsOptionalBoolean; +import static io.openems.common.utils.JsonUtils.getAsOptionalString; +import static io.openems.common.utils.JsonUtils.getAsString; +import static java.util.Collections.emptyMap; + +import java.util.Map; +import java.util.Optional; import java.util.UUID; import java.util.concurrent.CompletableFuture; import io.openems.backend.common.metadata.AppCenterHandler; +import io.openems.backend.common.metadata.Metadata.GenericSystemLog; import io.openems.backend.common.metadata.User; import io.openems.common.exceptions.OpenemsError; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; import io.openems.common.jsonrpc.request.AppCenterRequest; +import io.openems.common.jsonrpc.request.ComponentJsonApiRequest; import io.openems.common.jsonrpc.request.EdgeRpcRequest; import io.openems.common.jsonrpc.request.GetEdgeConfigRequest; import io.openems.common.jsonrpc.request.QueryHistoricTimeseriesDataRequest; @@ -49,39 +58,62 @@ protected CompletableFuture handleRequest(User user, UUID messa } user.assertEdgeRoleIsAtLeast(EdgeRpcRequest.METHOD, edgeRpcRequest.getEdgeId(), Role.GUEST); - CompletableFuture resultFuture; - switch (request.getMethod()) { - case AppCenterRequest.METHOD: - resultFuture = AppCenterHandler.handleUserRequest(this.parent.appCenterMetadata, // - t -> this.handleRequest(user, messageId, t), // - AppCenterRequest.from(request), user, edgeId); - break; - - case QueryHistoricTimeseriesDataRequest.METHOD: - resultFuture = this.handleQueryHistoricDataRequest(edgeId, user, - QueryHistoricTimeseriesDataRequest.from(request)); - break; - - case QueryHistoricTimeseriesEnergyRequest.METHOD: - resultFuture = this.handleQueryHistoricEnergyRequest(edgeId, user, - QueryHistoricTimeseriesEnergyRequest.from(request)); - break; - - case QueryHistoricTimeseriesEnergyPerPeriodRequest.METHOD: - resultFuture = this.handleQueryHistoricEnergyPerPeriodRequest(edgeId, user, - QueryHistoricTimeseriesEnergyPerPeriodRequest.from(request)); - break; - - case QueryHistoricTimeseriesExportXlxsRequest.METHOD: - resultFuture = this.handleQueryHistoricTimeseriesExportXlxsRequest(edgeId, user, - QueryHistoricTimeseriesExportXlxsRequest.from(request)); - break; - - case GetEdgeConfigRequest.METHOD: - resultFuture = this.handleGetEdgeConfigRequest(edgeId, user, GetEdgeConfigRequest.from(request)); - break; - - default: + var resultFuture = switch (request.getMethod()) { + case AppCenterRequest.METHOD -> AppCenterHandler.handleUserRequest(this.parent.appCenterMetadata, // + t -> this.handleRequest(user, messageId, t), // + AppCenterRequest.from(request), user, edgeId); + + case QueryHistoricTimeseriesDataRequest.METHOD -> + this.handleQueryHistoricDataRequest(edgeId, user, QueryHistoricTimeseriesDataRequest.from(request)); + + case QueryHistoricTimeseriesEnergyRequest.METHOD -> + this.handleQueryHistoricEnergyRequest(edgeId, user, QueryHistoricTimeseriesEnergyRequest.from(request)); + + case QueryHistoricTimeseriesEnergyPerPeriodRequest.METHOD -> this.handleQueryHistoricEnergyPerPeriodRequest( + edgeId, user, QueryHistoricTimeseriesEnergyPerPeriodRequest.from(request)); + + case QueryHistoricTimeseriesExportXlxsRequest.METHOD -> this.handleQueryHistoricTimeseriesExportXlxsRequest( + edgeId, user, QueryHistoricTimeseriesExportXlxsRequest.from(request)); + + case GetEdgeConfigRequest.METHOD -> + this.handleGetEdgeConfigRequest(edgeId, user, GetEdgeConfigRequest.from(request)); + + case ComponentJsonApiRequest.METHOD -> { + final var componentRequest = ComponentJsonApiRequest.from(request); + if (!"_host".equals(componentRequest.getComponentId())) { + yield null; + } + switch (componentRequest.getPayload().getMethod()) { + case "executeSystemCommand" -> { + final var executeSystemCommandRequest = componentRequest.getPayload(); + final var p = executeSystemCommandRequest.getParams(); + this.parent.metadata.logGenericSystemLog(new LogSystemExecuteCommend(edgeId, user, // + getAsString(p, "command"), // + getAsOptionalBoolean(p, "sudo").orElse(null), // + getAsOptionalString(p, "username").orElse(null), // + getAsOptionalString(p, "password").orElse(null), // + getAsOptionalBoolean(p, "runInBackground").orElse(null) // + )); + } + case "executeSystemUpdate" -> { + this.parent.metadata.logGenericSystemLog(new LogUpdateSystem(edgeId, user)); + } + case "executeSystemRestart" -> { + final var executeSystemCommandRequest = componentRequest.getPayload(); + final var p = executeSystemCommandRequest.getParams(); + this.parent.metadata.logGenericSystemLog(new LogRestartSystem(edgeId, user, // + getAsOptionalString(p, "type").orElse(null) // + )); + } + } + yield null; + } + + default -> null; + }; + + if (resultFuture == null) { + // Request not handled delegate to edge resultFuture = this.parent.edgeWebsocket.send(edgeId, user, request); } @@ -100,6 +132,74 @@ protected CompletableFuture handleRequest(User user, UUID messa return result; } + private record LogSystemExecuteCommend(// + String edgeId, // non-null + User user, // non-null + String command, // non-null + Boolean sudo, // null-able + String username, // null-able + String password, // null-able + Boolean runInBackground // null-able + ) implements GenericSystemLog { + + @Override + public String teaser() { + return "Systemcommand: " + this.command; + } + + @Override + public Map getValues() { + return Map.of(// + "Sudo", Boolean.toString(Optional.ofNullable(this.sudo()).orElse(false)), // + "Command", this.command(), // + "Username", this.username(), // + "Password", this.password() == null || this.password().isEmpty() ? "[NOT_SET]" : "[SET]", // + "Run in Background", Boolean.toString(Optional.ofNullable(this.runInBackground()).orElse(false)) // + ); + } + + } + + private record LogUpdateSystem(// + String edgeId, // non-null + User user // non-null + ) implements GenericSystemLog { + + @Override + public String teaser() { + return "Systemupdate"; + } + + @Override + public Map getValues() { + return emptyMap(); + } + + } + + private record LogRestartSystem(// + String edgeId, // non-null + User user, // non-null + String type // null-able + ) implements GenericSystemLog { + + @Override + public String teaser() { + return "Systemrestart"; + } + + @Override + public Map getValues() { + if (this.type == null) { + return emptyMap(); + } + return Map.of(// + "type", this.type // + ); + } + + } + /** * Handles a {@link QueryHistoricTimeseriesDataRequest}. * diff --git a/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/MetadataOdoo.java b/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/MetadataOdoo.java index 1e5e88627ce..6c544232e40 100644 --- a/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/MetadataOdoo.java +++ b/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/MetadataOdoo.java @@ -1,19 +1,25 @@ package io.openems.backend.metadata.odoo; +import static io.openems.common.utils.JsonUtils.getAsBoolean; +import static io.openems.common.utils.JsonUtils.getAsInt; +import static io.openems.common.utils.JsonUtils.getAsJsonArray; +import static io.openems.common.utils.JsonUtils.getAsJsonObject; +import static io.openems.common.utils.JsonUtils.getAsOptionalJsonArray; +import static io.openems.common.utils.JsonUtils.getAsOptionalString; +import static io.openems.common.utils.JsonUtils.getAsString; import static io.openems.common.utils.ThreadPoolUtils.shutdownAndAwaitTermination; +import static java.util.stream.Collectors.toUnmodifiableMap; import java.sql.SQLException; import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.TreeMap; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; @@ -95,8 +101,7 @@ public class MetadataOdoo extends AbstractMetadata implements AppCenterMetadata, private final ConcurrentHashMap users = new ConcurrentHashMap<>(); private final ConcurrentHashMap activeTasks = new ConcurrentHashMap<>(100); - private ThreadPoolExecutor defaultExecutor = null; - private ThreadPoolExecutor edgeConfigExecutor = null; + private ThreadPoolExecutor executor = null; private final ConcurrentHashMap pendingEdgeConfigIds = new ConcurrentHashMap<>(); @Reference @@ -125,10 +130,8 @@ private void activate(Config config) throws SQLException { + "Database [" + config.database() + "]"); this.debugMode = config.debugMode(); - this.defaultExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(config.poolSize() / 2, - new ThreadFactoryBuilder().setNameFormat("Metadata.Odoo.Default-%d").build()); - this.edgeConfigExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(config.poolSize() / 2, - new ThreadFactoryBuilder().setNameFormat("Metadata.Odoo.EdgeConfig-%d").build()); + this.executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(config.poolSize(), + new ThreadFactoryBuilder().setNameFormat("Metadata.Odoo-%d").build()); this.odooHandler = new OdooHandler(this, this.edgeCache, config); this.postgresHandler = new PostgresHandler(this, this.edgeCache, config, () -> { this.setInitialized(); @@ -138,8 +141,7 @@ private void activate(Config config) throws SQLException { @Deactivate private void deactivate() { this.logInfo(this.log, "Deactivate"); - shutdownAndAwaitTermination(this.defaultExecutor, 5); - shutdownAndAwaitTermination(this.edgeConfigExecutor, 5); + shutdownAndAwaitTermination(this.executor, 5); if (this.postgresHandler != null) { this.postgresHandler.deactivate(); } @@ -162,15 +164,15 @@ public User authenticate(String sessionId) throws OpenemsNamedException { var result = this.odooHandler.authenticateSession(sessionId); // Parse Result - var jUser = JsonUtils.getAsJsonObject(result, "user"); - var odooUserId = JsonUtils.getAsInt(jUser, "id"); - var login = JsonUtils.getAsString(jUser, "login"); - var name = JsonUtils.getAsString(jUser, "name"); - var language = Language.from(JsonUtils.getAsString(jUser, "language")); - var globalRole = Role.getRole(JsonUtils.getAsString(jUser, "global_role")); - var hasMultipleEdges = JsonUtils.getAsBoolean(jUser, "has_multiple_edges"); - - final var settings = JsonUtils.getAsOptionalString(jUser, "settings") // + var jUser = getAsJsonObject(result, "user"); + var odooUserId = getAsInt(jUser, "id"); + var login = getAsString(jUser, "login"); + var name = getAsString(jUser, "name"); + var language = Language.from(getAsString(jUser, "language")); + var globalRole = Role.getRole(getAsString(jUser, "global_role")); + var hasMultipleEdges = getAsBoolean(jUser, "has_multiple_edges"); + + final var settings = getAsOptionalString(jUser, "settings") // .flatMap(JsonUtils::parseOptional) // .flatMap(JsonUtils::getAsOptionalJsonObject) // .orElse(new JsonObject()); @@ -293,7 +295,7 @@ public int submitSetupProtocol(User user, JsonObject jsonObject) throws OpenemsN public void registerUser(JsonObject jsonObject, String oem) throws OpenemsNamedException { final OdooUserRole role; - var roleOpt = JsonUtils.getAsOptionalString(jsonObject, "role"); + var roleOpt = getAsOptionalString(jsonObject, "role"); if (roleOpt.isPresent()) { role = OdooUserRole.getRole(roleOpt.get()); } else { @@ -365,7 +367,7 @@ public void handleEvent(Event event) { var edge = (MyEdge) reader.getProperty(Edge.Events.OnSetProducttype.EDGE); var producttype = reader.getString(Edge.Events.OnSetProducttype.PRODUCTTYPE); // Set Producttype in Odoo/Postgres - this.execute(this.defaultExecutor, "OnSetProducttype", () -> { + this.execute("OnSetProducttype", () -> { try { this.postgresHandler.edge.updateProductType(edge.getOdooId(), producttype); } catch (SQLException | OpenemsNamedException e) { @@ -381,7 +383,7 @@ public void handleEvent(Event event) { @Override public void logGenericSystemLog(GenericSystemLog systemLog) { - this.execute(this.defaultExecutor, "LogGenericSystemLog", () -> { + this.execute("LogGenericSystemLog", () -> { try { final var edge = (MyEdge) this.getEdgeOrError(systemLog.edgeId()); this.postgresHandler.edge.insertGenericSystemLog(edge.getOdooId(), systemLog); @@ -401,7 +403,7 @@ private void onSetConfigEvent(EventReader reader) { return; } - this.execute(this.edgeConfigExecutor, "OnSetConfig", () -> { + this.execute("OnSetConfig", () -> { try { var newConfig = (EdgeConfig) reader.getProperty(Edge.Events.OnSetConfig.CONFIG); @@ -496,7 +498,7 @@ public void sendAddUnregisterKeyHistory(String edgeId, String appId, String key, @Override public JsonArray sendGetRegisteredKeys(String edgeId, String appId) throws OpenemsNamedException { var response = this.odooHandler.getRegisteredKeys(edgeId, appId); - return JsonUtils.getAsOptionalJsonArray(response, "keys") // + return getAsOptionalJsonArray(response, "keys") // .orElse(new JsonArray()) // ; } @@ -504,7 +506,7 @@ public JsonArray sendGetRegisteredKeys(String edgeId, String appId) throws Opene @Override public JsonArray sendGetPossibleApps(String key, String edgeId) throws OpenemsNamedException { var response = this.odooHandler.getPossibleApps(key, edgeId); - return JsonUtils.getAsJsonArray(response, "bundles"); + return getAsJsonArray(response, "bundles"); } @Override @@ -574,7 +576,7 @@ public List getPageDevice(// final PaginationOptions paginationOptions // ) throws OpenemsNamedException { var result = this.odooHandler.getEdges((MyUser) user, paginationOptions); - final var jsonArray = JsonUtils.getAsJsonArray(result, "devices"); + final var jsonArray = getAsJsonArray(result, "devices"); final var resultMetadata = new ArrayList(jsonArray.size()); for (var jElement : jsonArray) { resultMetadata.add(this.convertToEdgeMetadata(user, jElement)); @@ -588,7 +590,7 @@ public EdgeMetadata getEdgeMetadataForUser(User user, String edgeId) throws Open } private EdgeMetadata convertToEdgeMetadata(User user, JsonElement jDevice) throws OpenemsNamedException { - final var edgeId = JsonUtils.getAsString(jDevice, "name"); + final var edgeId = getAsString(jDevice, "name"); // TODO remove cached edge final var cachedEdge = this.getEdge(edgeId).orElse(null); @@ -596,23 +598,23 @@ private EdgeMetadata convertToEdgeMetadata(User user, JsonElement jDevice) throw throw new OpenemsException("Unable to find edge with id [" + edgeId + "]"); } - final var role = Role.getRole(JsonUtils.getAsString(jDevice, "role")); + final var role = Role.getRole(getAsString(jDevice, "role")); user.setRole(edgeId, role); - final var sumState = JsonUtils.getAsOptionalString(jDevice, "openems_sum_state_level") // + final var sumState = getAsOptionalString(jDevice, "openems_sum_state_level") // .map(String::toUpperCase) // .map(Level::valueOf) // .orElse(Level.OK); final var commment = this.oem.anonymizeEdgeComment(user, // - JsonUtils.getAsOptionalString(jDevice, "comment").orElse(""), // + getAsOptionalString(jDevice, "comment").orElse(""), // edgeId); - final var producttype = JsonUtils.getAsOptionalString(jDevice, "producttype").orElse(""); - final var firstSetupProtocol = JsonUtils.getAsOptionalString(jDevice, "first_setup_protocol_date") + final var producttype = getAsOptionalString(jDevice, "producttype").orElse(""); + final var firstSetupProtocol = getAsOptionalString(jDevice, "first_setup_protocol_date") .map(DateTime::stringToDateTime) // .orElse(null); - final var lastmessage = JsonUtils.getAsOptionalString(jDevice, "lastmessage") // + final var lastmessage = getAsOptionalString(jDevice, "lastmessage") // .map(DateTime::stringToDateTime) // .orElse(null); @@ -649,18 +651,17 @@ public void updateUserSettings(User user, JsonObject settings) throws OpenemsNam /** * Execute a {@link Runnable} using the shared {@link ExecutorService}. * - * @param executor the {@link Executor} - * @param id the identifier for this type of command - * @param command the {@link Runnable} + * @param id the identifier for this type of command + * @param command the {@link Runnable} */ - private void execute(Executor executor, String id, Runnable command) { - if (executor == null) { + private void execute(String id, Runnable command) { + if (this.executor == null) { return; } if (this.debugMode.isAtLeast(DebugMode.DETAILED)) { this.activeTasks.computeIfAbsent(id, ATOMIC_INTEGER_PROVIDER).incrementAndGet(); - executor.execute(() -> { + this.executor.execute(() -> { try { command.run(); } catch (Throwable t) { @@ -670,17 +671,15 @@ private void execute(Executor executor, String id, Runnable command) { } }); } else { - executor.execute(command); + this.executor.execute(command); } } @Override public String debugLog() { var b = new StringBuilder("[").append(this.getName()).append("] [monitor] ") // - .append("Default: ") // - .append(ThreadPoolUtils.debugLog(this.defaultExecutor)) // - .append(", EdgeConfig: ") // - .append(ThreadPoolUtils.debugLog(this.edgeConfigExecutor)); + .append("Executor: ") // + .append(ThreadPoolUtils.debugLog(this.executor)); if (this.debugMode.isAtLeast(DebugMode.DETAILED)) { b.append(", Tasks: "); @@ -697,18 +696,11 @@ public String debugLog() { @Override public Map debugMetrics() { - // TODO implement getId() - final var metrics = new HashMap(); - var defaultExecutorMetrics = ThreadPoolUtils.debugMetrics(this.defaultExecutor); - var edgeConfigExecutorMetrics = ThreadPoolUtils.debugMetrics(this.edgeConfigExecutor); - defaultExecutorMetrics.forEach((key, value) -> { - var value2 = edgeConfigExecutorMetrics.get(key); - if (value2 != null) { - value += value2; - } - metrics.put("metadata0/" + key, new JsonPrimitive(value)); - }); - return metrics; + return ThreadPoolUtils.debugMetrics(this.executor).entrySet().stream() // + .collect(toUnmodifiableMap(// + // TODO implement getId() + e -> "metadata0/" + e.getKey(), // + e -> new JsonPrimitive(e.getValue()))); } } diff --git a/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/postgres/PeriodicWriteWorker.java b/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/postgres/PeriodicWriteWorker.java index aa9707fface..feade9c8c5c 100644 --- a/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/postgres/PeriodicWriteWorker.java +++ b/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/postgres/PeriodicWriteWorker.java @@ -1,16 +1,28 @@ package io.openems.backend.metadata.odoo.postgres; +import static java.util.Collections.emptySet; +import static java.util.stream.Collectors.groupingBy; +import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.mapping; +import static java.util.stream.Collectors.toSet; + import java.sql.SQLException; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Consumer; +import java.util.stream.Stream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,7 +45,7 @@ public class PeriodicWriteWorker { */ private static final boolean DEBUG_MODE = true; - private static final int UPDATE_INTERVAL_IN_SECONDS = 120; + private static final int UPDATE_INTERVAL_IN_SECONDS = 30; private final Logger log = LoggerFactory.getLogger(PeriodicWriteWorker.class); private final PostgresHandler parent; @@ -58,7 +70,7 @@ public PeriodicWriteWorker(PostgresHandler parent) { */ public synchronized void start() { this.future = this.executor.scheduleWithFixedDelay(// - () -> this.task.accept(this.parent.edge), // + this::applyChanges, // PeriodicWriteWorker.UPDATE_INTERVAL_IN_SECONDS, PeriodicWriteWorker.UPDATE_INTERVAL_IN_SECONDS, TimeUnit.SECONDS); } @@ -76,14 +88,13 @@ public synchronized void stop() { } private final LinkedBlockingQueue lastMessageOdooIds = new LinkedBlockingQueue<>(); - private final LinkedBlockingQueue isOnlineOdooIds = new LinkedBlockingQueue<>(); - private final LinkedBlockingQueue isOfflineOdooIds = new LinkedBlockingQueue<>(); - private final LinkedBlockingQueue sumStateOk = new LinkedBlockingQueue<>(); - private final LinkedBlockingQueue sumStateInfo = new LinkedBlockingQueue<>(); - private final LinkedBlockingQueue sumStateWarning = new LinkedBlockingQueue<>(); - private final LinkedBlockingQueue sumStateFault = new LinkedBlockingQueue<>(); - - private final Consumer task = edge -> { + private ExchangableObject> connectionStatesToUpdate = new ExchangableObject<>( + new ConcurrentHashMap<>()); + private ExchangableObject> sumStatesToUpdate = new ExchangableObject<>( + new ConcurrentHashMap<>()); + + private final void applyChanges() { + final var edge = this.parent.edge; if (PeriodicWriteWorker.DEBUG_MODE) { this.debugLog(); } @@ -93,19 +104,37 @@ public synchronized void stop() { edge.updateLastMessage(drainToSet(this.lastMessageOdooIds)); // Online/Offline - edge.updateOpenemsIsConnected(drainToSet(this.isOfflineOdooIds), false); - edge.updateOpenemsIsConnected(drainToSet(this.isOnlineOdooIds), true); + final var connectionToUpdate = this.connectionStatesToUpdate.exchange(new ConcurrentHashMap<>()); + final var edgesByConnection = connectionToUpdate.entrySet().stream() // + .collect(groupingBy(Entry::getValue, mapping(Entry::getKey, toSet()))); + edge.updateOpenemsIsConnected(edgesByConnection.getOrDefault(false, emptySet()), false); + edge.updateOpenemsIsConnected(edgesByConnection.getOrDefault(true, emptySet()), true); + if (PeriodicWriteWorker.DEBUG_MODE) { + this.parent.logInfo(this.log, + "Update Edge connection states online[" + + edgesByConnection.getOrDefault(true, emptySet()).size() + "] offline[" + + edgesByConnection.getOrDefault(false, emptySet()).size() + "]"); + } // Sum-State - edge.updateSumState(drainToSet(this.sumStateOk), Level.OK); - edge.updateSumState(drainToSet(this.sumStateInfo), Level.INFO); - edge.updateSumState(drainToSet(this.sumStateWarning), Level.WARNING); - edge.updateSumState(drainToSet(this.sumStateFault), Level.FAULT); + final var statesToUpdate = this.sumStatesToUpdate.exchange(new ConcurrentHashMap<>()); + final var edgesByState = statesToUpdate.entrySet().stream() + .collect(groupingBy(Entry::getValue, mapping(Entry::getKey, toSet()))); + for (var stateEntry : edgesByState.entrySet()) { + edge.updateSumState(stateEntry.getValue(), stateEntry.getKey()); + } + if (PeriodicWriteWorker.DEBUG_MODE) { + this.parent.logInfo(this.log, "Update Edge sum states " + Stream.of(Level.values()) // + .map(level -> { + final var itemsToUpdate = edgesByState.getOrDefault(level, emptySet()); + return level.getName() + "[" + itemsToUpdate.size() + "]"; + }).collect(joining(" "))); + } } catch (SQLException e) { this.log.error("Unable to execute WriteWorker task: " + e.getMessage()); } - }; + } /** * Called on {@link Edge.Events#ON_SET_LAST_MESSAGE_TIMESTAMP} event. @@ -123,12 +152,10 @@ public void onLastMessage(MyEdge edge) { * @param isOnline true if online, false if offline */ public void onSetOnline(MyEdge edge, boolean isOnline) { - var odooId = edge.getOdooId(); - if (isOnline) { - this.isOnlineOdooIds.add(odooId); - } else { - this.isOfflineOdooIds.add(odooId); - } + final var odooId = edge.getOdooId(); + this.connectionStatesToUpdate.lockReading(t -> { + t.put(odooId, isOnline); + }); } /** @@ -138,21 +165,10 @@ public void onSetOnline(MyEdge edge, boolean isOnline) { * @param sumState Sum-State {@link Level} */ public void onSetSumState(MyEdge edge, Level sumState) { - var odooId = edge.getOdooId(); - switch (sumState) { - case OK: - this.sumStateOk.add(odooId); - break; - case INFO: - this.sumStateInfo.add(odooId); - break; - case WARNING: - this.sumStateWarning.add(odooId); - break; - case FAULT: - this.sumStateFault.add(odooId); - break; - } + final var odooId = edge.getOdooId(); + this.sumStatesToUpdate.lockReading(t -> { + t.put(odooId, sumState); + }); } /** @@ -182,4 +198,36 @@ private synchronized void debugLog() { } this.lastExecute = now; } + + private static class ExchangableObject { + private final ReadWriteLock lock = new ReentrantReadWriteLock(); + private volatile T currentObject; + + public ExchangableObject(T currentObject) { + super(); + this.currentObject = currentObject; + } + + public T exchange(T newObject) { + this.lock.writeLock().lock(); + try { + final var prev = this.currentObject; + this.currentObject = newObject; + return prev; + } finally { + this.lock.writeLock().unlock(); + } + } + + public void lockReading(Consumer block) { + this.lock.readLock().lock(); + try { + block.accept(this.currentObject); + } finally { + this.lock.readLock().unlock(); + } + } + + } + } diff --git a/io.openems.backend.timedata.aggregatedinflux/src/io/openems/backend/timedata/aggregatedinflux/AllowedChannels.java b/io.openems.backend.timedata.aggregatedinflux/src/io/openems/backend/timedata/aggregatedinflux/AllowedChannels.java index f7d8fc2813d..4a85a09cf1e 100644 --- a/io.openems.backend.timedata.aggregatedinflux/src/io/openems/backend/timedata/aggregatedinflux/AllowedChannels.java +++ b/io.openems.backend.timedata.aggregatedinflux/src/io/openems/backend/timedata/aggregatedinflux/AllowedChannels.java @@ -46,12 +46,13 @@ private AllowedChannels() { .putAll(multiChannels("ess", 0, 17, "ReactivePower", DataType.LONG)) // .put("ctrlIoHeatingElement0/Level", DataType.LONG) // .put("ctrlGridOptimizedCharge0/DelayChargeMaximumChargeLimit", DataType.LONG) // - .putAll(multiChannels("charger", 0, 10, "ActualPower", DataType.LONG)) // + .putAll(multiChannels("charger", 0, 20, "ActualPower", DataType.LONG)) // .put("ctrlEmergencyCapacityReserve0/ActualReserveSoc", DataType.LONG) // .put("ctrlGridOptimizedCharge0/_PropertyMaximumSellToGridPower", DataType.LONG) // .putAll(multiChannels("meter", 0, 10, "ActivePower", DataType.LONG)) // .putAll(multiChannels("meter", 0, 10, "ActivePowerL", 1, 4, DataType.LONG)) // .putAll(multiChannels("pvInverter", 0, 10, "ActivePower", DataType.LONG)) // + .putAll(multiChannels("pvInverter", 0, 10, "ActivePowerL", 1, 4, DataType.LONG)) // .put("_sum/EssDischargePower", DataType.LONG) // used for xlsx export .put("ctrlGridOptimizedCharge0/SellToGridLimitMinimumChargeLimit", DataType.LONG) // .put("ctrlEssTimeOfUseTariff0/QuarterlyPrices", DataType.DOUBLE) // @@ -87,10 +88,13 @@ private AllowedChannels() { .put("ctrlEssTimeOfUseTariff0/ChargedTime", DataType.LONG) // .putAll(multiChannels("evcs", 0, 10, "ActiveConsumptionEnergy", DataType.LONG)) // .putAll(multiChannels("meter", 0, 10, "ActiveProductionEnergy", DataType.LONG)) // + .putAll(multiChannels("meter", 0, 10, "ActiveProductionEnergyL", 1, 4, DataType.LONG)) // .putAll(multiChannels("meter", 0, 10, "ActiveConsumptionEnergy", DataType.LONG)) // + .putAll(multiChannels("meter", 0, 10, "ActiveConsumptionEnergyL", 1, 4, DataType.LONG)) // .putAll(multiChannels("io", 0, 10, "ActiveProductionEnergy", DataType.LONG)) // .putAll(multiChannels("pvInverter", 0, 10, "ActiveProductionEnergy", DataType.LONG)) // - .putAll(multiChannels("charger", 0, 10, "ActualEnergy", DataType.LONG)) // + .putAll(multiChannels("pvInverter", 0, 10, "ActiveProductionEnergyL", 1, 4, DataType.LONG)) // + .putAll(multiChannels("charger", 0, 20, "ActualEnergy", DataType.LONG)) // .put("ctrlGridOptimizedCharge0/AvoidLowChargingTime", DataType.LONG) // .put("ctrlGridOptimizedCharge0/NoLimitationTime", DataType.LONG) // .put("ctrlGridOptimizedCharge0/SellToGridLimitTime", DataType.LONG) // @@ -170,16 +174,18 @@ public static boolean addWithSpecificChannelType(Point builder, String field, Js if (type == null) { return false; } - final var number = value.getAsNumber(); + + var number = value.getAsNumber(); + + if (number.getClass().getName().equals("com.google.gson.internal.LazilyParsedNumber")) { + number = number.doubleValue(); + } + switch (type) { - case DOUBLE: - builder.addField(field, number.doubleValue()); - return true; - case LONG: - builder.addField(field, number.longValue()); - return true; + case DOUBLE -> builder.addField(field, number.doubleValue()); + case LONG -> builder.addField(field, number.longValue()); } - return false; + return true; } protected static enum DataType { diff --git a/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/ChannelFilter.java b/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/ChannelFilter.java new file mode 100644 index 00000000000..3bdeef18022 --- /dev/null +++ b/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/ChannelFilter.java @@ -0,0 +1,96 @@ +package io.openems.backend.timedata.influx; + +import static java.util.stream.Collectors.toUnmodifiableSet; + +import java.util.Arrays; +import java.util.Set; +import java.util.function.Predicate; +import java.util.regex.Pattern; + +public class ChannelFilter { + + private static final Predicate SUNSPEC_PATTERN = // + Pattern.compile("^S[0-9]+[A-Z][a-zA-Z0-9]*$").asPredicate(); + + /** + * Pattern for Component-IDs. + * + *

      + * Either: + * + *

      + * + *

      + * Or: + *

        + *
      • starts with underscore (by convention for singleton Components) + *
      • continues with lower case letter + *
      • contains only ASCII letters and numbers + *
      • ends with a letter + *
      + */ + // TODO move to io.openems.common and validate pattern on Edge + private static final Predicate COMPONENT_ID_PATTERN = // + Pattern.compile("^([a-z][a-zA-Z0-9]+[0-9]+|_[a-z][a-zA-Z0-9]+[a-zA-Z])$").asPredicate(); + + /** + * Creates a new {@link ChannelFilter} from the provided arguments. + * + * @param blacklistedChannels a array of the blacklisted channels + * @return the created {@link ChannelFilter} + */ + public static ChannelFilter from(String[] blacklistedChannels) { + return new ChannelFilter(Arrays.stream(blacklistedChannels) // + .collect(toUnmodifiableSet())); + } + + private final Set blacklistedChannels; + + private ChannelFilter(Set blacklistedChannels) { + super(); + this.blacklistedChannels = blacklistedChannels; + } + + /** + * Checks if the provided channel is valid or not. + * + * @param channelAddress the channel to check with the format + * "component0/Channel" + * @return true if the channel is valid; else false + */ + public boolean isValid(String channelAddress) { + if (channelAddress == null) { + return false; + } + + if (this.blacklistedChannels.contains(channelAddress)) { + return false; + } + + final var c = channelAddress.split("/"); + if (c.length != 2) { + return false; + } + + // Valid Component-ID + final var componentId = c[0]; + if (!COMPONENT_ID_PATTERN.test(componentId)) { + return false; + } + + // Valid Channel-ID + final var channelId = c[1]; + if (SUNSPEC_PATTERN.test(channelId)) { + // SunSpec Channels + return false; + } + + return true; + } + + +} diff --git a/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/Config.java b/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/Config.java index 5bcef3e9e7e..ac7bd5783b1 100644 --- a/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/Config.java +++ b/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/Config.java @@ -46,6 +46,9 @@ @AttributeDefinition(name = "Number of max scheduled tasks", description = "Max-Size of Queued tasks.") int maxQueueSize() default 5000; + @AttributeDefinition(name = "List of blacklisted channels", description = "Blacklisted channels which are not saved by this influx. e.g. \"kacoCore0/Serialnumber\"") + String[] blacklistedChannels() default {}; + String webconsole_configurationFactory_nameHint() default "Timedata InfluxDB"; } diff --git a/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/FieldTypeConflictHandler.java b/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/FieldTypeConflictHandler.java index 39bd1b07e67..8bb057dfaf9 100644 --- a/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/FieldTypeConflictHandler.java +++ b/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/FieldTypeConflictHandler.java @@ -7,10 +7,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.primitives.Doubles; +import com.google.common.primitives.Longs; import com.google.gson.JsonElement; import com.influxdb.client.write.Point; import com.influxdb.exceptions.InfluxException; +import io.openems.common.utils.JsonUtils; + /** * Handles Influx FieldTypeConflictExceptions. This helper provides conversion * functions to provide the correct field types for InfluxDB. @@ -54,18 +58,13 @@ protected synchronized boolean handleExceptionMessage(String message) return false; } - var handler = this.createAndAddHandler(field, requiredType); + this.specialCaseFieldHandlers.computeIfAbsent(field, t -> this.createHandler(t, requiredType)); - if (handler == null) { - this.parent.logWarn(this.log, "Unable to add special field handler for [" + field + "] from [" + thisType - + "] to [" + requiredType.name().toLowerCase() + "]"); - } this.parent.logInfo(this.log, "Add handler for [" + field + "] from [" + thisType + "] to [" + requiredType.name().toLowerCase() + "]\n" // + "Add predefined FieldTypeConflictHandler: this.createAndAddHandler(\"" + field + "\", RequiredType." + requiredType.name() + ");"); - ; return true; } @@ -74,15 +73,6 @@ private static enum RequiredType { STRING, INTEGER, FLOAT; } - private BiConsumer createAndAddHandler(String field, RequiredType requiredType) - throws IllegalStateException { - var handler = this.createHandler(field, requiredType); - if (this.specialCaseFieldHandlers.put(field, handler) != null) { - throw new IllegalStateException("Handler for field [" + field + "] was already existing"); - } - return handler; - } - /** * Creates a Handler for the given field, to convert a Point to a * 'requiredType'. @@ -91,51 +81,35 @@ private BiConsumer createAndAddHandler(String field, Require * @param requiredType the {@link RequiredType} * @return the Handler */ - private BiConsumer createHandler(String field, RequiredType requiredType) { - switch (requiredType) { - case STRING: - return (builder, jValue) -> { - var value = getAsFieldTypeString(jValue); - if (value != null) { - builder.addField(field, value); - } - }; - - case INTEGER: - return (builder, jValue) -> { - try { - var value = getAsFieldTypeNumber(jValue); - if (value != null) { - builder.addField(field, value); - } - } catch (NumberFormatException e1) { - try { - // Failed -> try conversion to float and then to int - var value = getAsFieldTypeFloat(jValue); - if (value != null) { - builder.addField(field, Math.round(value)); - } - } catch (NumberFormatException e2) { - this.parent.logWarn(this.log, "Unable to convert field [" + field + "] value [" + jValue - + "] to integer: " + e2.getMessage()); - } - } - }; - - case FLOAT: - return (builder, jValue) -> { - try { - var value = getAsFieldTypeFloat(jValue); - if (value != null) { - builder.addField(field, value); - } - } catch (NumberFormatException e1) { - this.parent.logInfo(this.log, "Unable to convert field [" + field + "] value [" + jValue - + "] to float: " + e1.getMessage()); - } - }; - } - return null; // can never happen + protected BiConsumer createHandler(String field, RequiredType requiredType) { + return switch (requiredType) { + case STRING -> (builder, jValue) -> { + var value = getAsFieldTypeString(jValue); + if (value != null) { + builder.addField(field, value); + } + }; + + case INTEGER -> (builder, jValue) -> { + final var value = getAsFieldTypeLong(jValue); + if (value == null) { + this.parent.logWarn(this.log, + "Unable to convert field [" + field + "] value [" + jValue + "] to integer"); + return; + } + builder.addField(field, value); + }; + + case FLOAT -> (builder, jValue) -> { + final var value = getAsFieldTypeDouble(jValue); + if (value == null) { + this.parent.logWarn(this.log, + "Unable to convert field [" + field + "] value [" + jValue + "] to float"); + return; + } + builder.addField(field, value); + }; + }; } /** @@ -144,7 +118,7 @@ private BiConsumer createHandler(String field, RequiredType * @param jValue the value * @return the value as String; null if value represents null */ - private static String getAsFieldTypeString(JsonElement jValue) { + protected static String getAsFieldTypeString(JsonElement jValue) { if (jValue.isJsonNull()) { return null; } @@ -152,49 +126,80 @@ private static String getAsFieldTypeString(JsonElement jValue) { } /** - * Convert JsonElement to Number. + * Convert JsonElement to Long. * * @param jValue the value - * @return the value as Number; null if value represents null - * @throws NumberFormatException on error + * @return the value as Long; null if value represents null */ - private static Number getAsFieldTypeNumber(JsonElement jValue) throws NumberFormatException { - if (jValue.isJsonNull()) { + protected static Long getAsFieldTypeLong(JsonElement jValue) { + if (!jValue.isJsonPrimitive()) { return null; } - var value = jValue.toString().replace("\"", ""); - if (value.isEmpty()) { - return null; + if (JsonUtils.isNumber(jValue)) { + return jValue.getAsNumber().longValue(); } - try { - return Long.parseLong(value); - } catch (NumberFormatException e1) { - if (value.equalsIgnoreCase("false")) { - return 0L; - } else if (value.equalsIgnoreCase("true")) { - return 1L; - } else { - throw e1; - } + final var string = jValue.getAsString().replace("\"", ""); + + final var longValue = Longs.tryParse(string); + if (longValue != null) { + return longValue; + } + + final var doubleValue = Doubles.tryParse(string); + if (doubleValue != null) { + return doubleValue.longValue(); } + + final var bool = tryParseToBooleanNumber(string); + if (bool != null) { + return bool.longValue(); + } + + return null; } /** - * Convert JsonElement to Float. + * Convert JsonElement to Double. * * @param jValue the value - * @return the value as Float; null if value represents null - * @throws NumberFormatException on error + * @return the value as Double; null if value represents null */ - private static Float getAsFieldTypeFloat(JsonElement jValue) throws NumberFormatException { - if (jValue.isJsonNull()) { + protected static Double getAsFieldTypeDouble(JsonElement jValue) { + if (!jValue.isJsonPrimitive()) { return null; } - var value = jValue.toString().replace("\"", ""); - if (value.isEmpty()) { + if (JsonUtils.isNumber(jValue)) { + return jValue.getAsNumber().doubleValue(); + } + final var string = jValue.getAsString().replace("\"", ""); + + final var doubleValue = Doubles.tryParse(string); + if (doubleValue != null) { + return doubleValue; + } + + final var bool = tryParseToBooleanNumber(string); + if (bool != null) { + return bool.doubleValue(); + } + + return null; + } + + private static Boolean tryParseBoolean(String value) { + return switch (value) { + case "true" -> true; + case "false" -> false; + default -> null; + }; + } + + private static Integer tryParseToBooleanNumber(String value) { + final var bool = tryParseBoolean(value); + if (bool == null) { return null; } - return Float.parseFloat(value); + return bool ? 1 : 0; } /** diff --git a/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/TimedataInfluxDb.java b/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/TimedataInfluxDb.java index 678ef6f3b6c..d3c957f38dc 100644 --- a/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/TimedataInfluxDb.java +++ b/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/TimedataInfluxDb.java @@ -7,8 +7,6 @@ import java.util.Set; import java.util.SortedMap; import java.util.function.BiFunction; -import java.util.function.Predicate; -import java.util.regex.Pattern; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; @@ -24,6 +22,8 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; +import com.google.common.primitives.Doubles; +import com.google.common.primitives.Longs; import com.google.gson.JsonElement; import com.google.gson.JsonPrimitive; import com.influxdb.client.domain.WritePrecision; @@ -44,7 +44,6 @@ import io.openems.common.oem.OpenemsBackendOem; import io.openems.common.timedata.Resolution; import io.openems.common.types.ChannelAddress; -import io.openems.common.utils.StringUtils; import io.openems.shared.influxdb.InfluxConnector; @Designate(ocd = Config.class, factory = true) @@ -70,6 +69,7 @@ public class TimedataInfluxDb extends AbstractOpenemsBackendComponent implements private Config config; private InfluxConnector influxConnector = null; private TimeFilter timeFilter; + private ChannelFilter channelFilter; // edgeId, channelIds which are timestamped channels private final Multimap timestampedChannelsForEdge = HashMultimap.create(); @@ -83,6 +83,7 @@ public TimedataInfluxDb() { private void activate(Config config) throws OpenemsException, IllegalArgumentException { this.config = config; this.timeFilter = TimeFilter.from(config.startDate(), config.endDate()); + this.channelFilter = ChannelFilter.from(config.blacklistedChannels()); this.logInfo(this.log, "Activate [" // + "url=" + config.url() + ";"// @@ -223,6 +224,9 @@ private void writeData(// if (!shouldWriteValue.apply(influxEdgeId, channelEntry.getKey())) { continue; } + if (!this.channelFilter.isValid(channelEntry.getKey())) { + continue; + } this.addValue(// point, // channelEntry.getKey(), // @@ -284,69 +288,75 @@ public SortedMap> queryHis */ private void addValue(Point builder, String field, JsonElement element) { if (element == null || element.isJsonNull() // - || !isAllowed(field) // Channel-Address is not allowed/blacklisted - // already handled by special case handling - || this.specialCaseFieldHandling(builder, field, element)) { + || this.specialCaseFieldHandling(builder, field, element)) { // already handled by special case handling return; } - if (element.isJsonPrimitive()) { - var p = (JsonPrimitive) element; - if (p.isNumber()) { - // Numbers can be directly converted - var n = p.getAsNumber(); - if (n.getClass().getName().equals("com.google.gson.internal.LazilyParsedNumber")) { - // Avoid 'discouraged access' - // LazilyParsedNumber stores value internally as String - if (StringUtils.matchesFloatPattern(n.toString())) { - builder.addField(field, n.doubleValue()); - return; - } - builder.addField(field, n.longValue()); - return; + if (!element.isJsonPrimitive()) { + // Non-Primitives are ignored + this.logWarn(this.log, "Ignoring non-primitive Field [" + field + "] Value [" + element + "]"); + return; + } - } else if (n instanceof Integer || n instanceof Long || n instanceof Short || n instanceof Byte) { - builder.addField(field, n.longValue()); + final var p = (JsonPrimitive) element; + if (p.isNumber()) { + // Numbers can be directly converted + final var n = p.getAsNumber(); + if (n.getClass().getName().equals("com.google.gson.internal.LazilyParsedNumber")) { + // Avoid 'discouraged access' + // LazilyParsedNumber stores value internally as String + final var s = n.toString(); + + final var longValue = Longs.tryParse(s); + if (longValue != null) { + builder.addField(field, longValue); return; + } + final var doubleValue = Doubles.tryParse(s); + if (doubleValue != null) { + builder.addField(field, doubleValue); + return; } - builder.addField(field, n.doubleValue()); - return; - } else if (p.isBoolean()) { - // Booleans are converted to integer (0/1) - builder.addField(field, p.getAsBoolean()); + // unable to parse lazy number return; + } - } else if (p.isString()) { - // Strings are parsed if they start with a number or minus - var s = p.getAsString(); - if (StringUtils.matchesFloatPattern(s)) { - try { - builder.addField(field, Double.parseDouble(s)); // try parsing to Double - return; - } catch (NumberFormatException e) { - builder.addField(field, s); - return; - } - - } else if (StringUtils.matchesIntegerPattern(s)) { - try { - builder.addField(field, Long.parseLong(s)); // try parsing to Long - return; - } catch (NumberFormatException e) { - builder.addField(field, s); - return; - } - } - builder.addField(field, s); + if (n instanceof Integer || n instanceof Long || n instanceof Short || n instanceof Byte) { + builder.addField(field, n.longValue()); return; } - } else { - builder.addField(field, element.toString()); + builder.addField(field, n.doubleValue()); return; } + + if (p.isBoolean()) { + // Booleans are converted to integer (0/1) + builder.addField(field, p.getAsBoolean()); + return; + } + + if (p.isString()) { + // Strings are parsed if they start with a number or minus + final var s = p.getAsString(); + + // try to save string value as numbers + final var longValue = Longs.tryParse(s); + if (longValue != null) { + builder.addField(field, longValue); + return; + } + + final var doubleValue = Doubles.tryParse(s); + if (doubleValue != null) { + builder.addField(field, doubleValue); + return; + } + + // string not can not be parsed to any number => currently not saved + } } /** @@ -367,8 +377,13 @@ private boolean specialCaseFieldHandling(Point builder, String field, JsonElemen // no special handling exists for this field return false; } - // call special handler - handler.accept(builder, value); + try { + // call special handler + handler.accept(builder, value); + } catch (RuntimeException e) { + this.logError(this.log, + "Unexpected error in special case field handler for Field [" + field + "] Value [" + value + "]"); + } return true; } @@ -387,60 +402,6 @@ public String id() { return this.config.id(); } - private static final Predicate SUNSPEC_PATTERN = // - Pattern.compile("^S[0-9]+[A-Z][a-zA-Z0-9]*$").asPredicate(); - - /** - * Pattern for Component-IDs. - * - *

      - * Either: - * - *

        - *
      • starts with lower case letter - *
      • contains only ASCII letters and numbers - *
      • ends with a number - *
      - * - *

      - * Or: - *

        - *
      • starts with underscore (by convention for singleton Components) - *
      • continues with lower case letter - *
      • contains only ASCII letters and numbers - *
      • ends with a letter - *
      - */ - // TODO move to io.openems.common and validate pattern on Edge - private static final Predicate COMPONENT_ID_PATTERN = // - Pattern.compile("^([a-z][a-zA-Z0-9]+[0-9]+|_[a-z][a-zA-Z0-9]+[a-zA-Z])$").asPredicate(); - - protected static boolean isAllowed(String channelAddress) { - if (channelAddress == null) { - return false; - } - - var c = channelAddress.split("/"); - if (c.length != 2) { - return false; - } - - // Valid Component-ID - var componentId = c[0]; - if (!COMPONENT_ID_PATTERN.test(componentId)) { - return false; - } - - // Valid Channel-ID - var channelId = c[1]; - if (SUNSPEC_PATTERN.test(channelId)) { - // SunSpec Channels - return false; - } - - return true; - } - @Override public String debugLog() { return "[" + this.getName() + "] " + this.config.id() + " " + this.influxConnector.debugLog(); diff --git a/io.openems.backend.timedata.influx/test/io/openems/backend/timedata/influx/ChannelFilterTest.java b/io.openems.backend.timedata.influx/test/io/openems/backend/timedata/influx/ChannelFilterTest.java new file mode 100644 index 00000000000..0f473a6d56d --- /dev/null +++ b/io.openems.backend.timedata.influx/test/io/openems/backend/timedata/influx/ChannelFilterTest.java @@ -0,0 +1,52 @@ +package io.openems.backend.timedata.influx; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class ChannelFilterTest { + + @Test + public void testFromDuplicatedChannel() { + final var filter = ChannelFilter.from(new String[] { // + "component0/Channel", // + "component0/Channel", // + }); + + assertNotNull(filter); + } + + @Test + public void testIsValid() { + final var filter = ChannelFilter.from(new String[] { // + "component0/Channel", // + }); + + assertFalse(filter.isValid("component0/Channel")); + assertTrue(filter.isValid("component0/SomeOtherChannel")); + + assertFalse(filter.isValid(null)); + assertFalse(filter.isValid("invalid")); + assertFalse(filter.isValid("in/va/lid")); + + // Channel-ID + assertTrue(filter.isValid("ess0/ActivePower")); + assertTrue(filter.isValid("_sum/EssActivePower")); + assertTrue(filter.isValid("_cycle/MeasuredCycleTime")); + + assertFalse(filter.isValid("ess/ActivePower")); + assertFalse(filter.isValid("Ess1/ActivePower")); + assertFalse(filter.isValid("cycle/MeasuredCycleTime")); + assertFalse(filter.isValid("_cycle1/MeasuredCycleTime")); + assertFalse(filter.isValid("My Heat-Pump/Status")); + assertFalse(filter.isValid("äöü/Status")); + assertFalse(filter.isValid("äöü0/Status")); + + // SunSpec + assertFalse(filter.isValid("pvInverter0/S1Evt")); + assertFalse(filter.isValid("pvInverter0/S111A")); + } + +} diff --git a/io.openems.backend.timedata.influx/test/io/openems/backend/timedata/influx/FieldTypeConflictHandlerTest.java b/io.openems.backend.timedata.influx/test/io/openems/backend/timedata/influx/FieldTypeConflictHandlerTest.java index 82ed6467f87..32cde5dfa15 100644 --- a/io.openems.backend.timedata.influx/test/io/openems/backend/timedata/influx/FieldTypeConflictHandlerTest.java +++ b/io.openems.backend.timedata.influx/test/io/openems/backend/timedata/influx/FieldTypeConflictHandlerTest.java @@ -1,9 +1,15 @@ package io.openems.backend.timedata.influx; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import org.junit.Test; +import com.google.gson.JsonNull; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; + public class FieldTypeConflictHandlerTest { @Test @@ -16,4 +22,49 @@ public void testHandleExceptionMessage() { already exists as type float dropped=2""")); } + @Test + public void testGetAsFieldTypeString() throws Exception { + assertEquals("123", FieldTypeConflictHandler.getAsFieldTypeString(new JsonPrimitive(123))); + assertEquals("123", FieldTypeConflictHandler.getAsFieldTypeString(new JsonPrimitive("123"))); + assertEquals("123.5", FieldTypeConflictHandler.getAsFieldTypeString(new JsonPrimitive(123.5))); + assertEquals("123.5", FieldTypeConflictHandler.getAsFieldTypeString(new JsonPrimitive("123.5"))); + assertEquals("string", FieldTypeConflictHandler.getAsFieldTypeString(new JsonPrimitive("string"))); + assertEquals("{}", FieldTypeConflictHandler.getAsFieldTypeString(new JsonObject())); + assertNull(FieldTypeConflictHandler.getAsFieldTypeString(JsonNull.INSTANCE)); + assertEquals("true", FieldTypeConflictHandler.getAsFieldTypeString(new JsonPrimitive(true))); + assertEquals("true", FieldTypeConflictHandler.getAsFieldTypeString(new JsonPrimitive("true"))); + assertEquals("false", FieldTypeConflictHandler.getAsFieldTypeString(new JsonPrimitive(false))); + assertEquals("false", FieldTypeConflictHandler.getAsFieldTypeString(new JsonPrimitive("false"))); + } + + @Test + public void testGetAsFieldTypeLong() throws Exception { + assertEquals((Long) 123L, FieldTypeConflictHandler.getAsFieldTypeLong(new JsonPrimitive(123))); + assertEquals((Long) 123L, FieldTypeConflictHandler.getAsFieldTypeLong(new JsonPrimitive("123"))); + assertEquals((Long) 123L, FieldTypeConflictHandler.getAsFieldTypeLong(new JsonPrimitive(123.5))); + assertEquals((Long) 123L, FieldTypeConflictHandler.getAsFieldTypeLong(new JsonPrimitive("123.5"))); + assertNull(FieldTypeConflictHandler.getAsFieldTypeLong(new JsonPrimitive("string"))); + assertNull(FieldTypeConflictHandler.getAsFieldTypeLong(new JsonObject())); + assertNull(FieldTypeConflictHandler.getAsFieldTypeLong(JsonNull.INSTANCE)); + assertEquals((Long) 1L, FieldTypeConflictHandler.getAsFieldTypeLong(new JsonPrimitive(true))); + assertEquals((Long) 1L, FieldTypeConflictHandler.getAsFieldTypeLong(new JsonPrimitive("true"))); + assertEquals((Long) 0L, FieldTypeConflictHandler.getAsFieldTypeLong(new JsonPrimitive(false))); + assertEquals((Long) 0L, FieldTypeConflictHandler.getAsFieldTypeLong(new JsonPrimitive("false"))); + } + + @Test + public void testGetAsFieldTypeDouble() throws Exception { + assertEquals((Double) 123D, FieldTypeConflictHandler.getAsFieldTypeDouble(new JsonPrimitive(123))); + assertEquals((Double) 123D, FieldTypeConflictHandler.getAsFieldTypeDouble(new JsonPrimitive("123"))); + assertEquals((Double) 123.5, FieldTypeConflictHandler.getAsFieldTypeDouble(new JsonPrimitive(123.5))); + assertEquals((Double) 123.5, FieldTypeConflictHandler.getAsFieldTypeDouble(new JsonPrimitive("123.5"))); + assertNull(FieldTypeConflictHandler.getAsFieldTypeDouble(new JsonPrimitive("string"))); + assertNull(FieldTypeConflictHandler.getAsFieldTypeDouble(new JsonObject())); + assertNull(FieldTypeConflictHandler.getAsFieldTypeDouble(JsonNull.INSTANCE)); + assertEquals((Double) 1D, FieldTypeConflictHandler.getAsFieldTypeDouble(new JsonPrimitive(true))); + assertEquals((Double) 1D, FieldTypeConflictHandler.getAsFieldTypeDouble(new JsonPrimitive("true"))); + assertEquals((Double) 0D, FieldTypeConflictHandler.getAsFieldTypeDouble(new JsonPrimitive(false))); + assertEquals((Double) 0D, FieldTypeConflictHandler.getAsFieldTypeDouble(new JsonPrimitive("false"))); + } + } diff --git a/io.openems.backend.timedata.influx/test/io/openems/backend/timedata/influx/TimedataInfluxDbTest.java b/io.openems.backend.timedata.influx/test/io/openems/backend/timedata/influx/TimedataInfluxDbTest.java deleted file mode 100644 index 707f19f9340..00000000000 --- a/io.openems.backend.timedata.influx/test/io/openems/backend/timedata/influx/TimedataInfluxDbTest.java +++ /dev/null @@ -1,34 +0,0 @@ -package io.openems.backend.timedata.influx; - -import static io.openems.backend.timedata.influx.TimedataInfluxDb.isAllowed; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -public class TimedataInfluxDbTest { - - @Test - public void testIsAllowed() { - assertFalse(isAllowed(null)); - assertFalse(isAllowed("invalid")); - assertFalse(isAllowed("in/va/lid")); - - // Channel-ID - assertTrue(isAllowed("ess0/ActivePower")); - assertTrue(isAllowed("_sum/EssActivePower")); - assertTrue(isAllowed("_cycle/MeasuredCycleTime")); - - assertFalse(isAllowed("ess/ActivePower")); - assertFalse(isAllowed("Ess1/ActivePower")); - assertFalse(isAllowed("cycle/MeasuredCycleTime")); - assertFalse(isAllowed("_cycle1/MeasuredCycleTime")); - assertFalse(isAllowed("My Heat-Pump/Status")); - assertFalse(isAllowed("äöü/Status")); - - // SunSpec - assertFalse(isAllowed("pvInverter0/S1Evt")); - assertFalse(isAllowed("pvInverter0/S111A")); - } - -} diff --git a/io.openems.backend.timedata.timescaledb/src/io/openems/backend/timedata/timescaledb/internal/Type.java b/io.openems.backend.timedata.timescaledb/src/io/openems/backend/timedata/timescaledb/internal/Type.java index 925d52ad8b4..d9cd35eccf9 100644 --- a/io.openems.backend.timedata.timescaledb/src/io/openems/backend/timedata/timescaledb/internal/Type.java +++ b/io.openems.backend.timedata.timescaledb/src/io/openems/backend/timedata/timescaledb/internal/Type.java @@ -6,6 +6,8 @@ import java.util.Map; import java.util.function.Consumer; +import com.google.common.primitives.Doubles; +import com.google.common.primitives.Longs; import com.google.gson.JsonElement; import com.google.gson.JsonNull; import com.google.gson.JsonPrimitive; @@ -17,7 +19,6 @@ import io.openems.common.function.ThrowingBiFunction; import io.openems.common.types.OpenemsType; import io.openems.common.utils.JsonUtils; -import io.openems.common.utils.StringUtils; public enum Type { INTEGER(1, "data_integer", "bigint" /* 8 bytes; covers Java byte, int and long */, // @@ -151,7 +152,8 @@ public static Type detect(JsonElement value) { if (n.getClass().getName().equals("com.google.gson.internal.LazilyParsedNumber")) { // Avoid 'discouraged access' // LazilyParsedNumber stores value internally as String - if (StringUtils.matchesFloatPattern(n.toString())) { + final var doubleValue = Doubles.tryParse(n.toString()); + if (doubleValue != null) { return Type.FLOAT; } return Type.INTEGER; @@ -168,24 +170,18 @@ public static Type detect(JsonElement value) { } else if (p.isString()) { // Strings are parsed if they start with a number or minus - var s = p.getAsString(); - if (StringUtils.matchesFloatPattern(s)) { - try { - Double.parseDouble(s); // try parsing to Double - return Type.FLOAT; - } catch (NumberFormatException e) { - return Type.STRING; - } + final var s = p.getAsString(); - } else if (StringUtils.matchesIntegerPattern(s)) { - try { - Long.parseLong(s); // try parsing to Long - return Type.INTEGER; - } catch (NumberFormatException e) { - return Type.STRING; - } + // try to save string value as numbers + final var longValue = Longs.tryParse(s); + if (longValue != null) { + return Type.INTEGER; + } + + final var doubleValue = Doubles.tryParse(s); + if (doubleValue != null) { + return Type.FLOAT; } - return Type.STRING; } } // TODO parse JsonObject and JsonArray diff --git a/io.openems.backend.timedata.timescaledb/test/io/openems/backend/timedata/timescaledb/internal/TypeTest.java b/io.openems.backend.timedata.timescaledb/test/io/openems/backend/timedata/timescaledb/internal/TypeTest.java index 88815512917..db6f7eadd90 100644 --- a/io.openems.backend.timedata.timescaledb/test/io/openems/backend/timedata/timescaledb/internal/TypeTest.java +++ b/io.openems.backend.timedata.timescaledb/test/io/openems/backend/timedata/timescaledb/internal/TypeTest.java @@ -20,7 +20,7 @@ public void testDetect() throws OpenemsNamedException { assertEquals((Long) 101180500005L, JsonUtils.getAsType(OpenemsType.LONG, j)); } { - var j = new JsonPrimitive("519100001009210611000019"); + var j = new JsonPrimitive("X519100001009210611000019"); assertEquals(Type.STRING, Type.detect(j)); assertEquals(j.getAsString(), JsonUtils.getAsType(OpenemsType.STRING, j)); } diff --git a/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnRequest.java b/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnRequest.java index f30098586d3..9883cf030ac 100644 --- a/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnRequest.java +++ b/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnRequest.java @@ -1,15 +1,13 @@ package io.openems.backend.uiwebsocket.impl; -import static java.util.Collections.emptyMap; - import java.util.List; -import java.util.Map; import java.util.Objects; -import java.util.Optional; import java.util.UUID; import java.util.concurrent.CompletableFuture; import org.java_websocket.WebSocket; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import io.openems.backend.common.alerting.UserAlertingSettings; import io.openems.backend.common.jsonrpc.request.AddEdgeToUserRequest; @@ -26,7 +24,6 @@ import io.openems.backend.common.jsonrpc.response.AddEdgeToUserResponse; import io.openems.backend.common.jsonrpc.response.GetUserAlertingConfigsResponse; import io.openems.backend.common.jsonrpc.response.GetUserInformationResponse; -import io.openems.backend.common.metadata.Metadata.GenericSystemLog; import io.openems.backend.common.metadata.User; import io.openems.common.exceptions.OpenemsError; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; @@ -36,7 +33,6 @@ import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; import io.openems.common.jsonrpc.request.AuthenticateWithPasswordRequest; import io.openems.common.jsonrpc.request.AuthenticateWithTokenRequest; -import io.openems.common.jsonrpc.request.ComponentJsonApiRequest; import io.openems.common.jsonrpc.request.EdgeRpcRequest; import io.openems.common.jsonrpc.request.GetEdgeRequest; import io.openems.common.jsonrpc.request.GetEdgesRequest; @@ -55,6 +51,8 @@ public class OnRequest implements io.openems.common.websocket.OnRequest { + private final Logger log = LoggerFactory.getLogger(OnRequest.class); + private final UiWebsocketImpl parent; public OnRequest(UiWebsocketImpl parent) { @@ -218,6 +216,12 @@ private CompletableFuture handleEdgeRpcRequest(WsData wsData, U EdgeRpcRequest edgeRpcRequest) throws OpenemsNamedException { var edgeId = edgeRpcRequest.getEdgeId(); var request = edgeRpcRequest.getPayload(); + + // TODO still not the best to check the access => should be separate service + if (user.getRole(edgeId).isEmpty()) { + this.parent.metadata.getEdgeMetadataForUser(user, edgeId); + this.parent.logInfo(this.log, "Role was not defined for user=" + user.getId() + ", edge=" + edgeId); + } user.assertEdgeRoleIsAtLeast(EdgeRpcRequest.METHOD, edgeId, Role.GUEST); CompletableFuture resultFuture = switch (request.getMethod()) { @@ -227,37 +231,6 @@ private CompletableFuture handleEdgeRpcRequest(WsData wsData, U this.handleSubscribeSystemLogRequest(wsData, edgeId, user, SubscribeSystemLogRequest.from(request)); case SimulationRequest.METHOD -> this.handleSimulationRequest(edgeId, user, SimulationRequest.from(request)); - case ComponentJsonApiRequest.METHOD -> { - final var componentRequest = ComponentJsonApiRequest.from(request); - if (!"_host".equals(componentRequest.getComponentId())) { - yield null; - } - switch (componentRequest.getPayload().getMethod()) { - case "executeSystemCommand" -> { - final var executeSystemCommandRequest = componentRequest.getPayload(); - final var p = executeSystemCommandRequest.getParams(); - this.parent.metadata.logGenericSystemLog(new LogSystemExecuteCommend(edgeId, user, // - JsonUtils.getAsString(p, "command"), // - JsonUtils.getAsOptionalBoolean(p, "sudo").orElse(null), // - JsonUtils.getAsOptionalString(p, "username").orElse(null), // - JsonUtils.getAsOptionalString(p, "password").orElse(null), // - JsonUtils.getAsOptionalBoolean(p, "runInBackground").orElse(null) // - )); - } - case "executeSystemUpdate" -> { - this.parent.metadata.logGenericSystemLog(new LogUpdateSystem(edgeId, user)); - } - case "executeSystemRestart" -> { - final var executeSystemCommandRequest = componentRequest.getPayload(); - final var p = executeSystemCommandRequest.getParams(); - this.parent.metadata.logGenericSystemLog(new LogRestartSystem(edgeId, user, // - JsonUtils.getAsOptionalString(p, "type").orElse(null) // - )); - } - } - - yield null; - } default -> { // unable to handle; try generic handler yield null; @@ -303,74 +276,6 @@ private CompletableFuture handleSimulationRequest(String return simulation.handleRequest(edgeId, user, request); } - private record LogSystemExecuteCommend(// - String edgeId, // non-null - User user, // non-null - String command, // non-null - Boolean sudo, // null-able - String username, // null-able - String password, // null-able - Boolean runInBackground // null-able - ) implements GenericSystemLog { - - @Override - public String teaser() { - return "Systemcommand: " + this.command; - } - - @Override - public Map getValues() { - return Map.of(// - "Sudo", Boolean.toString(Optional.ofNullable(this.sudo()).orElse(false)), // - "Command", this.command(), // - "Username", this.username(), // - "Password", this.password() == null || this.password().isEmpty() ? "[NOT_SET]" : "[SET]", // - "Run in Background", Boolean.toString(Optional.ofNullable(this.runInBackground()).orElse(false)) // - ); - } - - } - - private record LogUpdateSystem(// - String edgeId, // non-null - User user // non-null - ) implements GenericSystemLog { - - @Override - public String teaser() { - return "Systemupdate"; - } - - @Override - public Map getValues() { - return emptyMap(); - } - - } - - private record LogRestartSystem(// - String edgeId, // non-null - User user, // non-null - String type // null-able - ) implements GenericSystemLog { - - @Override - public String teaser() { - return "Systemrestart"; - } - - @Override - public Map getValues() { - if (this.type == null) { - return emptyMap(); - } - return Map.of(// - "type", this.type // - ); - } - - } - /** * Handles a {@link SubscribeChannelsRequest}. * diff --git a/io.openems.common/src/io/openems/common/oem/DummyOpenemsEdgeOem.java b/io.openems.common/src/io/openems/common/oem/DummyOpenemsEdgeOem.java index 9a75699e20a..4b0aabf35b8 100644 --- a/io.openems.common/src/io/openems/common/oem/DummyOpenemsEdgeOem.java +++ b/io.openems.common/src/io/openems/common/oem/DummyOpenemsEdgeOem.java @@ -74,6 +74,7 @@ public SystemUpdateParams getSystemUpdateParams() { .put("App.Api.ModbusTcp.ReadWrite", "") // .put("App.Api.RestJson.ReadOnly", "") // .put("App.Api.RestJson.ReadWrite", "") // + .put("App.Timedata.InfluxDb", "")// .put("App.Evcs.HardyBarth", "") // .put("App.Evcs.Keba", "") // .put("App.Evcs.IesKeywatt", "") // @@ -92,6 +93,7 @@ public SystemUpdateParams getSystemUpdateParams() { .put("App.Meter.Socomec", "") // .put("App.Meter.CarloGavazzi", "") // .put("App.Meter.Janitza", "") // + .put("App.Meter.Discovergy", "")// .put("App.PvInverter.Fronius", "") // .put("App.PvInverter.Kaco", "") // .put("App.PvInverter.Kostal", "") // diff --git a/io.openems.common/src/io/openems/common/types/EdgeConfig.java b/io.openems.common/src/io/openems/common/types/EdgeConfig.java index 0c54d0334eb..1a7ad131b23 100644 --- a/io.openems.common/src/io/openems/common/types/EdgeConfig.java +++ b/io.openems.common/src/io/openems/common/types/EdgeConfig.java @@ -9,6 +9,7 @@ import java.util.SortedMap; import java.util.TreeMap; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.osgi.service.metatype.AttributeDefinition; import org.osgi.service.metatype.ObjectClassDefinition; @@ -1060,19 +1061,12 @@ public String[] getNatureIds() { * @return configuration as a JSON Object */ public JsonObject toJson() { - var natureIds = new JsonArray(); - for (String naturId : this.getNatureIds()) { - natureIds.add(naturId); - } - var properties = new JsonArray(); - for (Property property : this.getProperties()) { - properties.add(property.toJson()); - } return JsonUtils.buildJsonObject() // .addProperty("name", this.name) // .addProperty("description", this.description) // - .add("natureIds", natureIds) // - .add("properties", properties) // + .add("natureIds", Stream.of(this.getNatureIds()) // + .map(JsonPrimitive::new) // + .collect(JsonUtils.toJsonArray())) // .build(); } @@ -1431,6 +1425,10 @@ public JsonObject componentsToJson(JsonFormat jsonFormat) { public JsonObject factoriesToJson() { var b = JsonUtils.buildJsonObject(); for (Entry entry : this.getFactories().entrySet()) { + if (!this.getComponents().values().stream() // + .anyMatch(c -> c.factoryId.equals(entry.getKey()))) { + continue; + } b.add(entry.getKey(), entry.getValue().toJson()); } return b.build(); diff --git a/io.openems.common/src/io/openems/common/utils/StringUtils.java b/io.openems.common/src/io/openems/common/utils/StringUtils.java index 1402944d8d8..13bc4a34e1a 100644 --- a/io.openems.common/src/io/openems/common/utils/StringUtils.java +++ b/io.openems.common/src/io/openems/common/utils/StringUtils.java @@ -1,7 +1,6 @@ package io.openems.common.utils; import java.util.OptionalInt; -import java.util.function.Predicate; import java.util.regex.Pattern; import com.google.gson.JsonElement; @@ -90,36 +89,8 @@ public static int matchWildcard(String source, String pattern) { } } - private static final Predicate DETECT_INTEGER_PATTERN = // - Pattern.compile("^[-+]?[0-9]+$").asPredicate(); - - private static final Predicate DETECT_FLOAT_PATTERN = // - Pattern.compile("^[-+]?[0-9]*\\.[0-9]+$").asPredicate(); - private static final Pattern NAME_NUMBER_PATTERN = Pattern.compile("[^0-9]+([0-9]+)$"); - /** - * Checks if the given string matches an Integer pattern, i.e. if could be - * parsed to Integer/Long. - * - * @param string a string - * @return true if it matches Integer - */ - public static boolean matchesIntegerPattern(String string) { - return DETECT_INTEGER_PATTERN.test(string); - } - - /** - * Checks if the given string matches an Float pattern, i.e. if could be parsed - * to Float/Double. - * - * @param string a string - * @return true if it matches Float - */ - public static boolean matchesFloatPattern(String string) { - return DETECT_FLOAT_PATTERN.test(string); - } - /** * Causes this character sequence to be replaced by the reverse of the sequence. * diff --git a/io.openems.common/src/io/openems/common/utils/ThreadPoolUtils.java b/io.openems.common/src/io/openems/common/utils/ThreadPoolUtils.java index 1d875582b70..1167c401294 100644 --- a/io.openems.common/src/io/openems/common/utils/ThreadPoolUtils.java +++ b/io.openems.common/src/io/openems/common/utils/ThreadPoolUtils.java @@ -56,6 +56,10 @@ public static void shutdownAndAwaitTermination(ExecutorService pool, int timeout * @return a String */ public static String debugLog(ThreadPoolExecutor executor) { + if (executor == null) { + return "UNDEFINED"; + } + var activeCount = executor.getActiveCount(); var b = new StringBuilder() // .append("Pool: ").append(executor.getPoolSize()).append("/").append(executor.getMaximumPoolSize()) // @@ -75,7 +79,11 @@ public static String debugLog(ThreadPoolExecutor executor) { * @return a Map of key to value */ public static Map debugMetrics(ThreadPoolExecutor executor) { - return Map.of(// + if (executor == null) { + return Map.of(); + } + + return Map.of(// "PoolSize", Long.valueOf(executor.getPoolSize()), // "MaxPoolSize", Long.valueOf(executor.getMaximumPoolSize()), // "Active", Long.valueOf(executor.getActiveCount()), // diff --git a/io.openems.common/test/io/openems/common/jsonrpc/response/JsonrpcToXlsxApp.java b/io.openems.common/test/io/openems/common/jsonrpc/response/JsonrpcToXlsxApp.java new file mode 100644 index 00000000000..154dcbdf4b4 --- /dev/null +++ b/io.openems.common/test/io/openems/common/jsonrpc/response/JsonrpcToXlsxApp.java @@ -0,0 +1,63 @@ +package io.openems.common.jsonrpc.response; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.ZonedDateTime; + +import org.dhatim.fastexcel.Workbook; + +import com.google.gson.JsonParser; + +public class JsonrpcToXlsxApp { + + private static final String PATH = ""; + private static final String FILE_IN = "file.json"; + private static final String FILE_OUT = "file.xlsx"; + + /** + * Tool to convert from JSONRPC to XLSX. + * + * @param args arguments + * @throws IOException on error + */ + public static void main(String[] args) throws IOException { + var json = JsonParser.parseString(// + String.join("", // + Files.readAllLines(Path.of(PATH, FILE_IN)))) + .getAsJsonObject(); + if (json.has("result")) { + // handle full JSONRPC-Response and UI log output object + json = json.getAsJsonObject("result"); + } + var timestamps = json.getAsJsonArray("timestamps"); + var data = json.getAsJsonObject("data"); + + try (// + var os = new FileOutputStream(Path.of(PATH, FILE_OUT).toFile()); + var wb = new Workbook(os, "", null) // + ) { + var ws = wb.newWorksheet(FILE_IN); + var cols = data.keySet().toArray(String[]::new); + + // Header + ws.value(0, 0, "Timestamp"); + for (var i = 0; i < cols.length; i++) { + ws.value(0, i + 1, cols[i]); + } + + // Data + for (var i = 0; i < timestamps.size(); i++) { + var timestamp = ZonedDateTime.parse(timestamps.get(i).getAsString()); + ws.value(i + 1, 0, timestamp); + ws.style(i + 1, 0).format("yyyy-MM-dd H:mm:ss").set(); + for (var j = 0; j < cols.length; j++) { + var d = data.get(cols[j]).getAsJsonArray().get(i); + ws.value(i + 1, j + 1, d.isJsonNull() ? null : d.getAsNumber()); + } + } + } + } + +} diff --git a/io.openems.common/test/io/openems/common/jsonrpc/response/XlsxToJsonrpcApp.java b/io.openems.common/test/io/openems/common/jsonrpc/response/XlsxToJsonrpcApp.java new file mode 100644 index 00000000000..e7a34d5c98a --- /dev/null +++ b/io.openems.common/test/io/openems/common/jsonrpc/response/XlsxToJsonrpcApp.java @@ -0,0 +1,70 @@ +package io.openems.common.jsonrpc.response; + +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.dhatim.fastexcel.reader.Cell; +import org.dhatim.fastexcel.reader.ReadableWorkbook; + +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; + +public class XlsxToJsonrpcApp { + + private static final String PATH = ""; + private static final String FILE_IN = "file.xlsx"; + private static final String FILE_OUT = "file.json"; + + /** + * Tool to convert from XLSX to JSONRPC. + * + * @param args arguments + * @throws IOException on error + */ + public static void main(String[] args) throws IOException { + var timestamps = new JsonArray(); + var data = new JsonObject(); + + try (// + var is = new FileInputStream(Path.of(PATH, FILE_IN).toFile()); + var wb = new ReadableWorkbook(is) // + ) { + var ws = wb.getFirstSheet(); + var rows = ws.read(); + var cols = rows.get(0).stream() // + .skip(1) // + .map(Cell::asString) // + .toArray(String[]::new); + for (var col : cols) { + data.add(col, new JsonArray()); + } + for (var i = 1; i < rows.size(); i++) { + var row = rows.get(i); + timestamps.add(row.getCell(0).asDate().toString() + ":00Z"); + for (var j = 0; j < cols.length; j++) { + var cell = row.getCell(j + 1); + if (cell == null) { + continue; + } + data.get(cols[j]).getAsJsonArray()// + .add(cell.asNumber()); + } + } + + var result = new JsonObject(); + result.add("timestamps", timestamps); + result.add("data", data); + var json = new JsonObject(); + json.addProperty("jsonrpc", "2.0"); + json.addProperty("id", ""); + json.add("result", result); + + Files.writeString(Path.of(PATH, FILE_OUT), + new GsonBuilder().setPrettyPrinting().serializeNulls().create().toJson(json)); + } + } + +} diff --git a/io.openems.common/test/io/openems/common/utils/StringUtilsTest.java b/io.openems.common/test/io/openems/common/utils/StringUtilsTest.java index 2b5fa1ce8af..2203d0de5b8 100644 --- a/io.openems.common/test/io/openems/common/utils/StringUtilsTest.java +++ b/io.openems.common/test/io/openems/common/utils/StringUtilsTest.java @@ -50,11 +50,6 @@ public void testMatchWildcard() { assertEquals(-1, StringUtils.matchWildcard(activePower, foobar)); } - @Test - public void testMatchesFloatPattern() { - assertTrue(StringUtils.matchesFloatPattern("208.6")); - } - @Test public void testDefinedOrElse() { assertEquals("foo", definedOrElse("foo", "bar")); diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index f158c0a74bd..addfe0c17f4 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -196,6 +196,7 @@ bcpkix;version='[1.70.0,1.70.1)',\ bcprov;version='[1.70.0,1.70.1)',\ bcutil;version='[1.70.0,1.70.1)',\ + com.fasterxml.aalto-xml;version='[1.3.2,1.3.3)',\ com.fazecast.jSerialComm;version='[2.10.4,2.10.5)',\ com.ghgande.j2mod;version='[3.2.1,3.2.2)',\ com.google.gson;version='[2.11.0,2.11.1)',\ @@ -395,7 +396,9 @@ io.reactivex.rxjava3.rxjava;version='[3.1.8,3.1.9)',\ javax.jmdns;version='[3.4.1,3.4.2)',\ javax.xml.soap-api;version='[1.4.0,1.4.1)',\ + org.apache.commons.commons-compress;version='[1.26.1,1.26.2)',\ org.apache.commons.commons-csv;version='[1.10.0,1.10.1)',\ + org.apache.commons.commons-io;version='[2.15.1,2.15.2)',\ org.apache.commons.math3;version='[3.6.1,3.6.2)',\ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ org.apache.felix.eventadmin;version='[1.6.4,1.6.5)',\ @@ -424,4 +427,5 @@ org.osgi.util.promise;version='[1.3.0,1.3.1)',\ org.owasp.encoder;version='[1.2.3,1.2.4)',\ reactive-streams;version='[1.0.4,1.0.5)',\ - rrd4j;version='[3.9.0,3.9.1)' \ No newline at end of file + rrd4j;version='[3.9.0,3.9.1)',\ + stax2-api;version='[4.2.0,4.2.1)' \ No newline at end of file diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/Point.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/Point.java index 3ea9dc3bbdd..9f43d5aadcb 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/Point.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/Point.java @@ -9,6 +9,7 @@ import io.openems.common.channel.AccessMode; import io.openems.common.channel.Level; +import io.openems.common.channel.PersistencePriority; import io.openems.common.channel.Unit; import io.openems.common.types.OpenemsType; import io.openems.common.types.OptionsEnum; @@ -34,6 +35,8 @@ */ public abstract sealed class Point { + private static final PersistencePriority DEFAULT_PERSISTENCE_PRIORITY = PersistencePriority.VERY_LOW; + /** * A Point that relates to a {@link ModbusElement}. */ @@ -69,7 +72,7 @@ public static sealed interface Type { public final boolean mandatory; public final AccessMode accessMode; - public Point(String name, String label, String description, Point.Type type, boolean mandatory, + protected Point(String name, String label, String description, Point.Type type, boolean mandatory, AccessMode accessMode) { this.name = name; this.description = description; @@ -110,6 +113,7 @@ private ChannelIdPoint(String name, String label, String description, Point.Type doc.text(description); } doc.accessMode(accessMode); + doc.persistencePriority(DEFAULT_PERSISTENCE_PRIORITY); this.channelId = new SunSChannelId<>(name, doc); } diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/PointTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/PointTest.java new file mode 100644 index 00000000000..8e62fa932a5 --- /dev/null +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/PointTest.java @@ -0,0 +1,29 @@ +package io.openems.edge.bridge.modbus.sunspec; + +import static io.openems.common.channel.AccessMode.READ_ONLY; +import static io.openems.common.channel.ChannelCategory.OPENEMS_TYPE; +import static io.openems.common.channel.PersistencePriority.VERY_LOW; +import static io.openems.common.channel.Unit.AMPERE; +import static io.openems.common.types.OpenemsType.INTEGER; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import io.openems.edge.bridge.modbus.sunspec.Point.ChannelIdPoint; + +public class PointTest { + + @Test + public void testChannelIdPoint() { + var point = (ChannelIdPoint) DefaultSunSpecModel.S111.A.get(); + var channelId = point.channelId; + var doc = channelId.doc(); + assertEquals(READ_ONLY, doc.getAccessMode()); + assertEquals(OPENEMS_TYPE, doc.getChannelCategory()); + assertEquals(VERY_LOW, doc.getPersistencePriority()); + assertEquals("Amps. AC Current", doc.getText()); + assertEquals(INTEGER, doc.getType()); + assertEquals(AMPERE, doc.getUnit()); + } + +} diff --git a/io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerHeatingElementImplTest4.java b/io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerHeatingElementImplTest4.java new file mode 100644 index 00000000000..854d4f90087 --- /dev/null +++ b/io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerHeatingElementImplTest4.java @@ -0,0 +1,95 @@ +package io.openems.edge.controller.io.heatingelement; + +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.temporal.ChronoUnit; + +import org.junit.Test; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.test.TimeLeapClock; +import io.openems.common.types.ChannelAddress; +import io.openems.edge.common.sum.DummySum; +import io.openems.edge.common.sum.Sum; +import io.openems.edge.common.test.AbstractComponentTest.TestCase; +import io.openems.edge.common.test.DummyComponentManager; +import io.openems.edge.controller.io.heatingelement.enums.Level; +import io.openems.edge.controller.io.heatingelement.enums.Mode; +import io.openems.edge.controller.io.heatingelement.enums.WorkMode; +import io.openems.edge.controller.test.ControllerTest; +import io.openems.edge.io.test.DummyInputOutput; + +public class ControllerHeatingElementImplTest4 { + private static final String CTRL_ID = "ctrl0"; + private static final String IO_ID = "io0"; + + private static final ChannelAddress IO_OUTPUT1 = new ChannelAddress(IO_ID, "InputOutput1"); + private static final ChannelAddress IO_OUTPUT2 = new ChannelAddress(IO_ID, "InputOutput2"); + private static final ChannelAddress IO_OUTPUT3 = new ChannelAddress(IO_ID, "InputOutput3"); + private static final TimeLeapClock clock = new TimeLeapClock( + Instant.ofEpochSecond(1577836800) /* starts at 1. January 2020 00:00:00 */, ZoneOffset.UTC); + + private static ControllerTest prepareTest(Mode mode, Level level) throws OpenemsNamedException, Exception { + return new ControllerTest(new ControllerIoHeatingElementImpl()) // + .addReference("componentManager", new DummyComponentManager(clock)) // + .addReference("sum", new DummySum()) // + .addComponent(new DummyInputOutput("io0")) // + .activate(MyConfig.create() // + .setId(CTRL_ID) // + .setOutputChannelPhaseL1(IO_OUTPUT1.toString()) // + .setOutputChannelPhaseL2(IO_OUTPUT2.toString()) // + .setOutputChannelPhaseL3(IO_OUTPUT3.toString()) // + .setEndTime("15:45:00") // + .setPowerOfPhase(2000) // + .setMode(mode) // + .setDefaultLevel(level) // + .setWorkMode(WorkMode.NONE) // + .setMinTime(1) // + .setMinimumSwitchingTime(180) // + .build()); // + } + + private static final ChannelAddress ESSO_DISCHARGE_POWER = new ChannelAddress("_sum", + Sum.ChannelId.ESS_DISCHARGE_POWER.id()); + private static final ChannelAddress LEVEL = new ChannelAddress(CTRL_ID, + ControllerIoHeatingElement.ChannelId.LEVEL.id()); + private static final ChannelAddress GRID_ACTIVE_POWER = new ChannelAddress("_sum", + Sum.ChannelId.GRID_ACTIVE_POWER.id()); + + @Test + public void testDischargeTakeIntoAccount() throws OpenemsNamedException, Exception { + prepareTest(Mode.AUTOMATIC, Level.LEVEL_3)// + .next(new TestCase()// + .input(GRID_ACTIVE_POWER, -2500)// + .output(LEVEL, Level.LEVEL_1)) // + .next(new TestCase() // + .timeleap(clock, 181, ChronoUnit.SECONDS)// + .input(GRID_ACTIVE_POWER, -2500)// + .output(LEVEL, Level.LEVEL_2))// + // Grid power reducing because of 2kW heating power + .next(new TestCase()// + .timeleap(clock, 181, ChronoUnit.SECONDS)// + .input(GRID_ACTIVE_POWER, -500) // + .output(LEVEL, Level.LEVEL_2)// + ).next(new TestCase() // + .timeleap(clock, 181, ChronoUnit.SECONDS)// + .input(GRID_ACTIVE_POWER, -500) // + .input(ESSO_DISCHARGE_POWER, 2300) // + .output(LEVEL, Level.LEVEL_1)// + ); // ; + } + + @Test + public void realDataTest() throws OpenemsNamedException, Exception { + prepareTest(Mode.AUTOMATIC, Level.LEVEL_3)// + // ensure level 3 + .next(new TestCase()// + .input(GRID_ACTIVE_POWER, -6000)// + .output(LEVEL, Level.LEVEL_3)) // + .next(new TestCase()// + .timeleap(clock, 181, ChronoUnit.SECONDS)// + .input(GRID_ACTIVE_POWER, 0)// + .input(ESSO_DISCHARGE_POWER, 2280)// + .output(LEVEL, Level.LEVEL_1)); // ; + } +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/api/TimedataInfluxDb.java b/io.openems.edge.core/src/io/openems/edge/app/api/TimedataInfluxDb.java new file mode 100644 index 00000000000..88bcaef205e --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/api/TimedataInfluxDb.java @@ -0,0 +1,219 @@ +package io.openems.edge.app.api; + +import java.util.ArrayList; +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.common.collect.Lists; +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.common.types.EdgeConfig; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.app.api.TimedataInfluxDb.Property; +import io.openems.edge.app.common.props.CommonProps; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.AppManagerUtil; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.OpenemsAppStatus; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter; +import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; +import io.openems.edge.core.appmanager.dependency.Tasks; +import io.openems.edge.core.appmanager.formly.JsonFormlyUtil; +import io.openems.edge.core.appmanager.formly.enums.InputType; + +@Component(name = "App.Timedata.InfluxDb") +public class TimedataInfluxDb extends AbstractOpenemsAppWithProps + implements OpenemsApp { + + public enum Property implements Type { + // Component-IDs + TIMEDATE_ID(AppDef.componentId("timedate0")), // + // Properties + ALIAS(AppDef.copyOfGeneric(CommonProps.alias())), // + QUERY_LANGUAGE(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def // + .setTranslatedLabelWithAppPrefix(".queryLanguage.label") // + .setField(JsonFormlyUtil::buildSelectFromNameable, (app, prop, l, params, field) -> { + final var options = new ArrayList(); + options.add("INFLUX_QL"); + options.add("FLUX"); + field.setOptions(options); + }) // + .setDefaultValue("INFLUX_QL"))), // + URL(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def // + .setTranslatedLabelWithAppPrefix(".url.label") // + .setTranslatedDescriptionWithAppPrefix(".url.description") // + .setField(JsonFormlyUtil::buildInput) // + .setDefaultValue("http://localhost:8086"))), // + ORG(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def // + .setTranslatedLabelWithAppPrefix(".org.label") // + .setTranslatedDescriptionWithAppPrefix(".org.description") // + .setField(JsonFormlyUtil::buildInput) // + .setDefaultValue("-"))), // + API_KEY(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def // + .setTranslatedDescriptionWithAppPrefix(".apiKey.label") // + .setTranslatedLabelWithAppPrefix(".apiKey.description") // + .setField(JsonFormlyUtil::buildInput)// + .setRequired(true))), + BUCKET(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def // + .setTranslatedDescriptionWithAppPrefix(".bucket.label") // + .setTranslatedLabelWithAppPrefix(".bucket.description") // + .setField(JsonFormlyUtil::buildInput)// + .setRequired(true))), + MEASUREMENT(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def // + .setTranslatedDescriptionWithAppPrefix(".measurement.label") // + .setTranslatedLabelWithAppPrefix(".measurement.description") // + .setField(JsonFormlyUtil::buildInput) // + .setDefaultValue("data"))), // + NO_OF_CYCLES(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def // + .setTranslatedDescriptionWithAppPrefix(".noOfCycles.description") // + .setTranslatedLabelWithAppPrefix(".noOfCycles.label") // + .setDefaultValue(1) // + .setField(JsonFormlyUtil::buildInputFromNameable, (app, property, l, parameter, first) -> { + first.setInputType(InputType.NUMBER); + first.setMin(1); + }))), // + MAX_QUEUE_SIZE(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def // + .setTranslatedDescriptionWithAppPrefix(".maxQueueSize.description")// + .setTranslatedLabelWithAppPrefix(".maxQueueSize.label") // + .setDefaultValue(50) // + .setField(JsonFormlyUtil::buildInputFromNameable, (app, property, l, parameter, first) -> { + first.setInputType(InputType.NUMBER); + }))), // + IS_READ_ONLY(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def // + .setTranslatedDescriptionWithAppPrefix(".isReadOnly.description") // + .setTranslatedLabelWithAppPrefix(".isReadOnly.label") // + .setDefaultValue(false) // + .setField(JsonFormlyUtil::buildCheckbox))); + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, BundleParameter> getParamter() { + return Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + } + + @Activate + public TimedataInfluxDb(// + @Reference ComponentManager componentManager, // + ComponentContext componentContext, // + @Reference ConfigurationAdmin cm, // + @Reference ComponentUtil componentUtil, // + @Reference AppManagerUtil appManagerUtil // + ) { + super(componentManager, componentContext, cm, componentUtil); + + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + final var id = this.getId(t, p, Property.TIMEDATE_ID); + + final var alias = this.getString(p, l, Property.ALIAS); + final var queryLanguage = this.getString(p, Property.QUERY_LANGUAGE); + final var url = this.getString(p, Property.URL); + final var apiKey = this.getString(p, Property.API_KEY); + final var bucket = this.getString(p, Property.BUCKET); + final var measuremtn = this.getString(p, Property.MEASUREMENT); + final var noOfCycles = this.getInt(p, Property.NO_OF_CYCLES); + final var maxQueueSize = this.getInt(p, Property.MAX_QUEUE_SIZE); + final var isReadOnly = this.getBoolean(p, Property.IS_READ_ONLY); + + var components = Lists.newArrayList(// + new EdgeConfig.Component(id, alias, "Timedata.InfluxDB", // + JsonUtils.buildJsonObject() // + .addProperty("queryLanguage", queryLanguage) // + .addProperty("url", url) // + .addProperty("apiKey", apiKey) // + .addProperty("bucket", bucket) // + .addProperty("measurement", measuremtn) // + .addProperty("noOfCycles", noOfCycles) // + .addProperty("maxQueueSize", maxQueueSize) // + .addProperty("isReadOnly", isReadOnly)// + .build()) // + ); + + return AppConfiguration.create() // + .addTask(Tasks.component(components)) // + .build(); + }; + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public final OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.TIMEDATA }; + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.MULTIPLE; + } + + @Override + protected TimedataInfluxDb getApp() { + return this; + } + + @Override + protected OpenemsAppStatus getStatus() { + return OpenemsAppStatus.BETA; + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create()// + .setCanSee(Role.ADMIN)// + .build(); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome20.java b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome20.java index f0c98903754..083bd11673b 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome20.java +++ b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome20.java @@ -259,7 +259,6 @@ public FeneconHome20(// } } - @SuppressWarnings("removal") @Override protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { return (t, p, l) -> { diff --git a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome30.java b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome30.java index 60c8bacec42..34d2c672789 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome30.java +++ b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome30.java @@ -260,7 +260,6 @@ public FeneconHome30(// } } - @SuppressWarnings("removal") @Override protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { return (t, p, l) -> { diff --git a/io.openems.edge.core/src/io/openems/edge/app/meter/DiscovergyMeter.java b/io.openems.edge.core/src/io/openems/edge/app/meter/DiscovergyMeter.java new file mode 100644 index 00000000000..be525db7656 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/meter/DiscovergyMeter.java @@ -0,0 +1,229 @@ +package io.openems.edge.app.meter; + +import java.util.ArrayList; +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.common.collect.Lists; +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.common.types.EdgeConfig; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.app.common.props.CommonProps; +import io.openems.edge.app.enums.MeterType; +import io.openems.edge.app.meter.DiscovergyMeter.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.AppManagerUtil; +import io.openems.edge.core.appmanager.AppManagerUtilSupplier; +import io.openems.edge.core.appmanager.ComponentManagerSupplier; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.OpenemsAppStatus; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter; +import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; +import io.openems.edge.core.appmanager.dependency.Tasks; +import io.openems.edge.core.appmanager.formly.Exp; +import io.openems.edge.core.appmanager.formly.JsonFormlyUtil; + +@Component(name = "App.Meter.Discovergy") +public class DiscovergyMeter extends AbstractOpenemsAppWithProps + implements OpenemsApp, AppManagerUtilSupplier { + + public enum Property implements Type { + // Component-IDs + METER_ID(AppDef.componentId("meter0")), // + // Properties + ALIAS(AppDef.copyOfGeneric(CommonProps.alias())), // + TYPE(AppDef.copyOfGeneric(MeterProps.type(MeterType.GRID))), // + EMAIL(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def // + .setTranslatedLabelWithAppPrefix(".email.label") // + .setTranslatedDescriptionWithAppPrefix(".email.description") // + .setField(JsonFormlyUtil::buildInputFromNameable).setRequired(true))), // + PASSWORD(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def// + .setTranslatedLabelWithAppPrefix(".password.label") // + .setTranslatedDescriptionWithAppPrefix(".password.description") // + .setRequired(true) // + .setField(JsonFormlyUtil::buildInput, (app, prop, l, params, field) -> { + field.setInputType(io.openems.edge.core.appmanager.formly.enums.InputType.PASSWORD); + }) // + .bidirectional(METER_ID, "password", ComponentManagerSupplier::getComponentManager, t -> { + return JsonUtils.getAsOptionalString(t) // + .map(s -> { + if (s.isEmpty()) { + return null; + } + return new JsonPrimitive("xxx"); + }) // + .orElse(null); + }))), // + SERIAL_NUMBER_TYPE(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def // + .setTranslatedLabelWithAppPrefix(".serialType.label") + .setField(JsonFormlyUtil::buildSelect, (app, prop, l, params, field) -> { + final var options = new ArrayList(); + options.add("SERIAL_NUMBER"); + options.add("FULL_SERIAL_NUMBER"); + options.add("METER_ID"); + field.setOptions(options); + }) // + )), // + SERIAL_NUMBER(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def // + .setTranslatedLabelWithAppPrefix(".serialNumber.label") // + .setDefaultValue("")// + .setTranslatedDescriptionWithAppPrefix(".serialNumber.description") // + .setField(JsonFormlyUtil::buildInputFromNameable) // + .wrapField((app, property, l, parameter, field) -> { + field.onlyShowIf(Exp.currentModelValue(SERIAL_NUMBER_TYPE).equal(Exp.staticValue("SERIAL_NUMBER"))); // + }))), // + FULL_SERIAL_NUMBER(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def // + .setTranslatedLabelWithAppPrefix(".fullSerialNumber.label") // + .setDefaultValue("")// + .setTranslatedDescriptionWithAppPrefix(".fullSerialNumber.description") // + .setField(JsonFormlyUtil::buildInputFromNameable, (app, property, l, parameter, field) -> { // + field.onlyShowIf( + Exp.currentModelValue(SERIAL_NUMBER_TYPE).equal(Exp.staticValue("FULL_SERIAL_NUMBER"))); // + }))), // + DISCOVERGY_METER_ID(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def // + .setTranslatedDescriptionWithAppPrefix(".meterId.description") // + .setTranslatedLabelWithAppPrefix(".meterId.label")// + .setDefaultValue("")// + .setField(JsonFormlyUtil::buildInputFromNameable, (app, property, l, parameter, field) -> { // + field.onlyShowIf(Exp.currentModelValue(SERIAL_NUMBER_TYPE).equal(Exp.staticValue("METER_ID"))); // + }))),// + ; + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, BundleParameter> getParamter() { + return Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + } + + private final AppManagerUtil appManagerUtil; + + @Activate + public DiscovergyMeter(// + @Reference ComponentManager componentManager, // + ComponentContext componentContext, // + @Reference ConfigurationAdmin cm, // + @Reference ComponentUtil componentUtil, // + @Reference AppManagerUtil appManagerUtil // + ) { + super(componentManager, componentContext, cm, componentUtil); + this.appManagerUtil = appManagerUtil; + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + final var id = this.getId(t, p, Property.METER_ID); + + final var alias = this.getString(p, l, Property.ALIAS); + final var meterType = this.getString(p, Property.TYPE); + final var email = this.getString(p, Property.EMAIL); + final var password = this.getString(p, Property.PASSWORD); + final var meterId = this.getString(p, Property.DISCOVERGY_METER_ID); + final var serialNumber = this.getString(p, Property.SERIAL_NUMBER); + final var fullSerialNumber = this.getString(p, Property.FULL_SERIAL_NUMBER); + + var components = Lists.newArrayList(// + new EdgeConfig.Component(id, alias, "Meter.Discovergy", // + JsonUtils.buildJsonObject() // + .addProperty("type", meterType)// + .addProperty("meterId", meterId) // + .addProperty("email", email) // + .addProperty("serialNumber", serialNumber) // + .addProperty("fullSerialNumber", fullSerialNumber)// + .onlyIf(password != null && !password.equals("xxx"), b -> { + b.addProperty("password", password); + }) // + .build()) // + ); + + return AppConfiguration.create() // + .addTask(Tasks.component(components)) // + .build(); + }; + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public final OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.METER }; + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + + @Override + public AppManagerUtil getAppManagerUtil() { + return this.appManagerUtil; + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.MULTIPLE; + } + + @Override + protected DiscovergyMeter getApp() { + return this; + } + + @Override + protected OpenemsAppStatus getStatus() { + return OpenemsAppStatus.BETA; + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create()// + .setCanSee(Role.ADMIN)// + .build(); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/OpenemsAppCategory.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/OpenemsAppCategory.java index d6508f37f9b..3e287c25f9b 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/OpenemsAppCategory.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/OpenemsAppCategory.java @@ -69,6 +69,12 @@ public enum OpenemsAppCategory { */ API("api"), + /** + * Timedata.. + * + */ + TIMEDATA("timedata"), + /** * Category for test apps. * diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties index a7bb8211d12..fb814f5c16c 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties @@ -94,6 +94,27 @@ App.Api.RestJson.ReadOnly.Name.short = REST/JSON lesend App.Api.RestJson.ReadWrite.Name = REST/JSON Schreibzugriff App.Api.RestJson.ReadWrite.Name.short = REST/JSON Schreibzugriff +App.Timedata.InfluxDb.Name = Influx Db Timedata +App.Timedata.InfluxDb.Name.short = Timedata +App.Timedata.InfluxDb.queryLanguage.label = Abfragesprache +App.Timedata.InfluxDb.url.label = URL +App.Timedata.InfluxDb.url.description = Die InfluxDB-URL, z. B.: http://localhost:8086 +App.Timedata.InfluxDb.org.label = Organisation +App.Timedata.InfluxDb.org.description = Die Organisation; für InfluxDB v1: '-' +App.Timedata.InfluxDb.apiKey.label = API Key +App.Timedata.InfluxDb.apiKey.description = Der API Key; für InfluxDB v1: 'Benutzername:Passwort', z. B. 'admin:admin' +App.Timedata.InfluxDb.measurement.label = Measurement +App.Timedata.InfluxDb.measurement.description = Die InfluxDB measurement +App.Timedata.InfluxDb.noOfCycles.description = Wie viele Zyklen bis die Daten in InfluxDB geschrieben werden +App.Timedata.InfluxDb.noOfCycles.label = Anzahl der Zyklen +App.Timedata.InfluxDb.maxQueueSize.description = Maximale Größe der Warteschlangenaufgaben. +App.Timedata.InfluxDb.maxQueueSize.label = Anzahl der maximal geplanten Aufgaben +App.Timedata.InfluxDb.isReadOnly.label = Read Only Modus +App.Timedata.InfluxDb.isReadOnly.description = Aktiviert Read Only Modus. Dann werden keine Daten in InfluxDB geschrieben. +App.Timedata.InfluxDb.bucket.label = Bucket +App.Timedata.InfluxDb.bucket.description = Der Bucket-Name; für InfluxDB v1: 'Datenbank/retentionPolicy', z. B. 'db/daten' + + # Evcs App.Evcs.controller.alias = Ladestation Steuerung App.Evcs.ip.description = Die IP-Adresse der Ladestation. @@ -294,6 +315,20 @@ App.Meter.Kdk.Name = KDK Zähler App.Meter.Kdk.Name.short = KDK App.Meter.Microcare.Sdm630.Name = SDM630 Zähler App.Meter.Microcare.Sdm630.Name.short = SDM630 +App.Meter.Discovergy.Name = Discovergy Zähler +App.Meter.Discovergy.Name.short = Discovergy +App.Meter.Discovergy.email.label = Authentifizierungs E-Mail +App.Meter.Discovergy.email.description = E-Mail für Ihren my.discovergy.com Zugang. +App.Meter.Discovergy.password.label = Authentifizierungs Passwort +App.Meter.Discovergy.password.description = Passwort für deinen my.discovergy.com Zugang. +App.Meter.Discovergy.serialNumber.label = Discovergy Seriennummer +App.Meter.Discovergy.serialNumber.description = Seriennummer Ihres Zähler, z.B. 12345678. Siehe https://my.discovergy.com/readings +App.Meter.Discovergy.fullSerialNumber.description = Komplette Seriennummer Ihres Zähler, z.B. 1ESY1234567890. +App.Meter.Discovergy.fullSerialNumber.label = Discovergy Komplette Seriennummer +App.Meter.Discovergy.meterId.label = Discovergy MeterId +App.Meter.Discovergy.meterId.description = Interne Zähler Id. Dieser is ein Hex String mit Länge 32. +App.Meter.Discovergy.serialType.label = Typ der Seriennummer + # PeakShaving App.PeakShaving.power.label = Maximale Netzbezugsleistung diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties index 00e23e68823..bbec3469d64 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties @@ -94,6 +94,27 @@ App.Api.RestJson.ReadOnly.Name.short = REST/JSON reading App.Api.RestJson.ReadWrite.Name = REST/JSON write access App.Api.RestJson.ReadWrite.Name.short = REST/JSON write access +App.Timedata.InfluxDb.Name = Influx Db Timedata +App.Timedata.InfluxDb.Name.short = Timedata +App.Timedata.InfluxDb.queryLanguage.label = Query language +App.Timedata.InfluxDb.url.label = URL +App.Timedata.InfluxDb.url.description = The InfluxDB URL, e.g.: http://localhost:8086 +App.Timedata.InfluxDb.org.label = Org +App.Timedata.InfluxDb.org.description = The Organisation; for InfluxDB v1: '-' +App.Timedata.InfluxDb.apiKey.label = ApiKey +App.Timedata.InfluxDb.apiKey.description = The ApiKey; for InfluxDB v1: 'username:password', e.g. 'admin:admin' +App.Timedata.InfluxDb.measurement.label = Measurement +App.Timedata.InfluxDb.measurement.description = The InfluxDB measurement +App.Timedata.InfluxDb.noOfCycles.description = How many Cycles till data is written to InfluxDB +App.Timedata.InfluxDb.noOfCycles.label = No of Cycles +App.Timedata.InfluxDb.maxQueueSize.description = Max-Size of Queued tasks. +App.Timedata.InfluxDb.maxQueueSize.label = Number of max scheduled tasks +App.Timedata.InfluxDb.isReadOnly.label = Read-Only mode +App.Timedata.InfluxDb.isReadOnly.description = Activates the read-only mode. Then no data is written to InfluxDB. +App.Timedata.InfluxDb.bucket.label = Bucket +App.Timedata.InfluxDb.bucket.description = The bucket name; for InfluxDB v1: 'database/retentionPolicy', e.g. 'db/data' + + # Evcs App.Evcs.controller.alias = Charging station control App.Evcs.ip.description = The IP address of the charging station. @@ -294,6 +315,19 @@ App.Meter.Kdk.Name = KDK meter App.Meter.Kdk.Name.short = KDK App.Meter.Microcare.Sdm630.Name = SDM630 meter App.Meter.Microcare.Sdm630.Name.short = SDM630 +App.Meter.Discovergy.Name = Discovergy Meter +App.Meter.Discovergy.Name.short = Discovergy +App.Meter.Discovergy.email.label = Authentication E-Mail +App.Meter.Discovergy.email.description = E-Mail for your my.discovergy.com access. +App.Meter.Discovergy.password.label = Authentication Password +App.Meter.Discovergy.password.description = Password for your my.discovergy.com access. +App.Meter.Discovergy.serialNumber.label = Discovergy Serial-Number +App.Meter.Discovergy.serialNumber.description = Serial-Number of the meter, e.g. 12345678. See https://my.discovergy.com/readings +App.Meter.Discovergy.fullSerialNumber.description = Full Serial-Number of the meter, e.g. 1ESY1234567890. +App.Meter.Discovergy.fullSerialNumber.label = Discovergy Full Serial-Number +App.Meter.Discovergy.meterId.label = Discovergy MeterId +App.Meter.Discovergy.meterId.description = Internal MeterId. This is a hex string with length 32. +App.Meter.Discovergy.serialType.label = Type of the serial number # PeakShaving App.PeakShaving.power.label = Peak-Shaving power diff --git a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java index bf41766cd55..2dd6105f73c 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java @@ -12,6 +12,8 @@ import java.util.Dictionary; import java.util.Hashtable; import java.util.List; +import java.util.Map.Entry; +import java.util.stream.Stream; import org.osgi.framework.BundleContext; import org.osgi.framework.InvalidSyntaxException; @@ -65,10 +67,12 @@ import io.openems.edge.common.user.User; import io.openems.edge.core.componentmanager.jsonrpc.ChannelExportXlsxRequest; import io.openems.edge.core.componentmanager.jsonrpc.ChannelExportXlsxResponse; +import io.openems.edge.core.componentmanager.jsonrpc.GetAllComponentFactories; import io.openems.edge.core.componentmanager.jsonrpc.GetChannel; import io.openems.edge.core.componentmanager.jsonrpc.GetChannelsOfComponent; import io.openems.edge.core.componentmanager.jsonrpc.GetChannelsOfComponent.ChannelRecord; import io.openems.edge.core.componentmanager.jsonrpc.GetDigitalInputChannelsOfComponents; +import io.openems.edge.core.componentmanager.jsonrpc.GetPropertiesOfFactory; import io.openems.edge.core.componentmanager.jsonrpc.GetStateChannelsOfComponent; import io.openems.edge.io.api.DigitalInput; @@ -395,7 +399,6 @@ public void buildJsonApiRoutes(JsonApiBuilder builder) { final var request = call.getRequest(); final var channel = this.getChannel(new ChannelAddress(request.componentId(), request.channelId())); - Thread.sleep(5000); return new GetChannel.Response(toChannelRecord(channel)); }); @@ -413,6 +416,38 @@ public void buildJsonApiRoutes(JsonApiBuilder builder) { return new GetDigitalInputChannelsOfComponents.Response(result); }); + + builder.handleRequest(new GetAllComponentFactories(), endpoint -> { + endpoint.setDescription(""" + Handles a GetAllComponentFactories. + """) // + .setGuards(EdgeGuards.roleIsAtleast(Role.ADMIN)); + }, call -> { + final var edgeConfig = this.getEdgeConfig(); + + return new GetAllComponentFactories.Response(edgeConfig.getFactories().entrySet().stream() + .collect(JsonUtils.toJsonObject(Entry::getKey, i -> i.getValue().toJson()))); + }); + + builder.handleRequest(new GetPropertiesOfFactory(), endpoint -> { + endpoint.setDescription(""" + Handles a GetPropertiesOfFactory. + """) // + .setGuards(EdgeGuards.roleIsAtleast(Role.ADMIN)); + }, call -> { + final var factoryId = call.getRequest().factoryId(); + + final var edgeConfig = this.getEdgeConfig(); + final var factory = edgeConfig.getFactories().get(factoryId); + + if (factory == null) { + throw new OpenemsException("Factory with id " + factoryId + " could not be found."); + } + + return new GetPropertiesOfFactory.Response(factory.toJson(), Stream.of(factory.getProperties()) // + .map(EdgeConfig.Factory.Property::toJson) // + .collect(JsonUtils.toJsonArray())); + }); } private static ChannelRecord toChannelRecord(Channel channel) { diff --git a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetAllComponentFactories.java b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetAllComponentFactories.java new file mode 100644 index 00000000000..8d9301f7cb2 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetAllComponentFactories.java @@ -0,0 +1,66 @@ +package io.openems.edge.core.componentmanager.jsonrpc; + +import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.emptyObjectSerializer; +import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.jsonObjectSerializer; + +import com.google.gson.JsonObject; + +import io.openems.common.jsonrpc.serialization.JsonSerializer; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.common.jsonapi.EndpointRequestType; +import io.openems.edge.core.appmanager.jsonrpc.AddAppInstance; +import io.openems.edge.core.componentmanager.jsonrpc.GetAllComponentFactories.Request; +import io.openems.edge.core.componentmanager.jsonrpc.GetAllComponentFactories.Response; + +public class GetAllComponentFactories implements EndpointRequestType { + + @Override + public String getMethod() { + return "getAllComponentFactories"; + } + + @Override + public JsonSerializer getRequestSerializer() { + return Request.serializer(); + } + + @Override + public JsonSerializer getResponseSerializer() { + return Response.serializer(); + } + + public record Request() { + + /** + * Returns a {@link JsonSerializer} for a {@link AddAppInstance.Request}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return emptyObjectSerializer(Request::new); + } + + } + + // TODO change to proper type + public record Response(JsonObject factories) { + + /** + * Returns a {@link JsonSerializer} for a + * {@link GetAllComponentFactories.Response}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(GetAllComponentFactories.Response.class, json -> { + return new Response(json.getJsonElementPath("factories").getAsJsonObjectPath().get()); + }, obj -> { + return JsonUtils.buildJsonObject() // + .add("factories", obj.factories()) // + .build(); + }); + } + + } + +} \ No newline at end of file diff --git a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetPropertiesOfFactory.java b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetPropertiesOfFactory.java new file mode 100644 index 00000000000..e942097bd79 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetPropertiesOfFactory.java @@ -0,0 +1,76 @@ +package io.openems.edge.core.componentmanager.jsonrpc; + +import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.jsonObjectSerializer; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; + +import io.openems.common.jsonrpc.serialization.JsonSerializer; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.common.jsonapi.EndpointRequestType; +import io.openems.edge.core.appmanager.jsonrpc.AddAppInstance; +import io.openems.edge.core.componentmanager.jsonrpc.GetPropertiesOfFactory.Request; +import io.openems.edge.core.componentmanager.jsonrpc.GetPropertiesOfFactory.Response; + +public class GetPropertiesOfFactory implements EndpointRequestType { + + @Override + public String getMethod() { + return "getPropertiesOfFactory"; + } + + @Override + public JsonSerializer getRequestSerializer() { + return Request.serializer(); + } + + @Override + public JsonSerializer getResponseSerializer() { + return Response.serializer(); + } + + public record Request(// + String factoryId // + ) { + + /** + * Returns a {@link JsonSerializer} for a {@link AddAppInstance.Request}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(Request.class, // + json -> new Request(// + json.getString("factoryId")), // + obj -> JsonUtils.buildJsonObject() // + .addProperty("factoryId", obj.factoryId()) // + .build()); + } + + } + + // TODO change to proper types + public record Response(JsonObject factory, JsonArray properties) { + + /** + * Returns a {@link JsonSerializer} for a + * {@link GetPropertiesOfFactory.Response}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(GetPropertiesOfFactory.Response.class, json -> { + return new Response(// + json.getJsonObject("factory"), // + json.getJsonArray("properties")); + }, obj -> { + return JsonUtils.buildJsonObject() // + .add("factory", obj.factory()) // + .add("properties", obj.properties()) // + .build(); + }); + } + + } + +} \ No newline at end of file diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/Apps.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/Apps.java index 28c448cf56f..ca6f501674b 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/Apps.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/Apps.java @@ -16,6 +16,7 @@ import io.openems.edge.app.api.ModbusTcpApiReadWrite; import io.openems.edge.app.api.RestJsonApiReadOnly; import io.openems.edge.app.api.RestJsonApiReadWrite; +import io.openems.edge.app.api.TimedataInfluxDb; import io.openems.edge.app.ess.FixActivePower; import io.openems.edge.app.ess.FixStateOfCharge; import io.openems.edge.app.ess.PowerPlantController; @@ -36,6 +37,7 @@ import io.openems.edge.app.loadcontrol.ManualRelayControl; import io.openems.edge.app.loadcontrol.ThresholdControl; import io.openems.edge.app.meter.CarloGavazziMeter; +import io.openems.edge.app.meter.DiscovergyMeter; import io.openems.edge.app.meter.JanitzaMeter; import io.openems.edge.app.meter.MicrocareSdm630Meter; import io.openems.edge.app.meter.SocomecMeter; @@ -299,6 +301,16 @@ public static final IesKeywattEvcs iesKeywattEvcs(AppManagerTestBundle t) { return app(t, IesKeywattEvcs::new, "App.Evcs.IesKeywatt"); } + /** + * Test method for creating a {@link TimedataInfluxDb}. + * + * @param t the {@link AppManagerTestBundle} + * @return the {@link OpenemsApp} instance + */ + public static final TimedataInfluxDb timedataInfluxDb(AppManagerTestBundle t) { + return app(t, TimedataInfluxDb::new, "App.Timedata.InfluxDb"); + } + /** * Test method for creating a {@link AlpitronicEvcs}. * @@ -427,6 +439,16 @@ public static final SocomecMeter socomecMeter(AppManagerTestBundle t) { return app(t, SocomecMeter::new, "App.Meter.Socomec"); } + /** + * Test method for creating a {@link DiscoveregyMeter}. + * + * @param t the {@link AppManagerTestBundle} + * @return the {@link OpenemsApp} instance + */ + public static final DiscovergyMeter discovergyMeter(AppManagerTestBundle t) { + return app(t, DiscovergyMeter::new, "App.Meter.Discovergy"); + } + /** * Test method for creating a {@link CarloGavazziMeter}. * diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestTranslations.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestTranslations.java index 05f25ba9c60..1e5ae260b70 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestTranslations.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestTranslations.java @@ -60,6 +60,10 @@ public void beforeEach() throws Exception { this.apps.add(new TestTranslation(Apps.restJsonApiReadWrite(t), true, JsonUtils.buildJsonObject() // .addProperty("API_TIMEOUT", 60) // .build())); + this.apps.add(new TestTranslation(Apps.timedataInfluxDb(t), true, JsonUtils.buildJsonObject() // + .addProperty("API_KEY", "123456789") // + .addProperty("BUCKET", "bucket")// + .build())); this.apps.add(new TestTranslation(Apps.hardyBarthEvcs(t), true, new JsonObject())); this.apps.add(new TestTranslation(Apps.kebaEvcs(t), true, new JsonObject())); this.apps.add(new TestTranslation(Apps.iesKeywattEvcs(t), true, new JsonObject())); @@ -92,6 +96,10 @@ public void beforeEach() throws Exception { this.apps.add(new TestTranslation(Apps.thresholdControl(t), false, JsonUtils.buildJsonObject() // .add("OUTPUT_CHANNELS", JsonUtils.buildJsonArray().add("io0/Relay1").build()) // .build())); + this.apps.add(new TestTranslation(Apps.discovergyMeter(t), false, JsonUtils.buildJsonObject() // + .addProperty("EMAIL", "test@test.test") // + .addProperty("PASSWORD", "xxxx") // + .build())); this.apps.add(new TestTranslation(Apps.socomecMeter(t), false, JsonUtils.buildJsonObject() // .addProperty("MODBUS_ID", "modbus0") // .build())); diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/SymmetricEss.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/SymmetricEss.java index 392eb4324cb..4c8c476ec44 100644 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/SymmetricEss.java +++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/SymmetricEss.java @@ -211,6 +211,10 @@ public static ModbusSlaveNatureTable getModbusSlaveNatureTable(AccessMode access .channel(1, ChannelId.GRID_MODE, ModbusType.UINT16) // .channel(2, ChannelId.ACTIVE_POWER, ModbusType.FLOAT32) // .channel(4, ChannelId.REACTIVE_POWER, ModbusType.FLOAT32) // + .channel(6, ChannelId.MIN_CELL_VOLTAGE, ModbusType.FLOAT32) // + .channel(8, ChannelId.MAX_CELL_VOLTAGE, ModbusType.FLOAT32) // + .channel(10, ChannelId.MIN_CELL_TEMPERATURE, ModbusType.FLOAT32) // + .channel(12, ChannelId.MAX_CELL_TEMPERATURE, ModbusType.FLOAT32) // .build(); } diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/AbstractChannelManager.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/AbstractChannelManager.java index af85ef0b031..c77a5496cc1 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/AbstractChannelManager.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/AbstractChannelManager.java @@ -108,6 +108,18 @@ private void addBatteryListener(ClockProvider clockProvider, Battery battery, Sy this.addCopyListener(battery, // Battery.ChannelId.SOC, // SymmetricEss.ChannelId.SOC); + this.addCopyListener(battery, // + Battery.ChannelId.MIN_CELL_VOLTAGE, // + SymmetricEss.ChannelId.MIN_CELL_VOLTAGE); + this.addCopyListener(battery, // + Battery.ChannelId.MAX_CELL_VOLTAGE, // + SymmetricEss.ChannelId.MAX_CELL_VOLTAGE); + this.addCopyListener(battery, // + Battery.ChannelId.MIN_CELL_TEMPERATURE, // + SymmetricEss.ChannelId.MIN_CELL_TEMPERATURE); + this.addCopyListener(battery, // + Battery.ChannelId.MAX_CELL_TEMPERATURE, // + SymmetricEss.ChannelId.MAX_CELL_TEMPERATURE); } private void addEssListener(ClockProvider clockProvider, Battery battery, SymmetricBatteryInverter inverter) { diff --git a/io.openems.shared.influxdb/src/io/openems/shared/influxdb/proxy/InfluxQlProxy.java b/io.openems.shared.influxdb/src/io/openems/shared/influxdb/proxy/InfluxQlProxy.java index 4a78e42f73b..bdd64fb4cb5 100644 --- a/io.openems.shared.influxdb/src/io/openems/shared/influxdb/proxy/InfluxQlProxy.java +++ b/io.openems.shared.influxdb/src/io/openems/shared/influxdb/proxy/InfluxQlProxy.java @@ -19,6 +19,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.primitives.Doubles; +import com.google.common.primitives.Longs; import com.google.gson.JsonElement; import com.google.gson.JsonNull; import com.google.gson.JsonPrimitive; @@ -34,7 +36,6 @@ import io.openems.common.types.ChannelAddress; import io.openems.common.utils.CollectorUtils; import io.openems.common.utils.JsonUtils; -import io.openems.common.utils.StringUtils; import io.openems.shared.influxdb.DbDataUtils; import io.openems.shared.influxdb.InfluxConnector.InfluxConnection; @@ -628,17 +629,8 @@ private static JsonElement convertToJsonElement(Object valueObj) { } else { str = valueObj.toString(); } - if (str.isEmpty()) { - return JsonNull.INSTANCE; - } - if (StringUtils.matchesFloatPattern(str)) { - return new JsonPrimitive(Double.parseDouble(str)); - } - if (StringUtils.matchesIntegerPattern(str)) { - return new JsonPrimitive(Long.parseLong(str)); - } - return new JsonPrimitive(valueObj.toString()); + return parseToJsonElement(str); } private static SortedMap convertHistoricEnergyResultSingleValueInDay(// @@ -685,7 +677,7 @@ private static SortedMap convertHistoricEnergyResul continue; } var valueObj = record.getValueByKey(column); - JsonElement value; + final JsonElement value; if (valueObj == null) { value = JsonNull.INSTANCE; } else if (valueObj instanceof Number n) { @@ -697,15 +689,7 @@ private static SortedMap convertHistoricEnergyResul } else { str = valueObj.toString(); } - if (str.isEmpty()) { - value = JsonNull.INSTANCE; - } else if (StringUtils.matchesFloatPattern(str)) { - value = new JsonPrimitive(Double.parseDouble(str)); - } else if (StringUtils.matchesIntegerPattern(str)) { - value = new JsonPrimitive(Long.parseLong(str)); - } else { - value = new JsonPrimitive(valueObj.toString()); - } + value = parseToJsonElement(str); } try { m.accept(new Pair<>(ChannelAddress.fromString(column), value)); @@ -758,15 +742,7 @@ private static SortedMap convertHistoricEnergyResul } else { str = valueObj.toString(); } - if (str.isEmpty()) { - value = JsonNull.INSTANCE; - } else if (StringUtils.matchesFloatPattern(str)) { - value = assertPositive(Double.parseDouble(str), influxEdgeId, channels); - } else if (StringUtils.matchesIntegerPattern(str)) { - value = assertPositive(Long.parseLong(str), influxEdgeId, channels); - } else { - value = new JsonPrimitive(valueObj.toString()); - } + value = parseToJsonElement(str); } map.put(ChannelAddress.fromString(column), value); } @@ -844,4 +820,32 @@ private static JsonElement assertPositive(Number number, Optional influ return new JsonPrimitive(number); } } + + /** + * Parses a String to a JsonElement; handles null/empty, double and long. + * + * @param str the String + * @return the {@link JsonElement} + */ + protected static JsonElement parseToJsonElement(String str) { + // Null/Empty + if (str == null || str.isEmpty()) { + return JsonNull.INSTANCE; + } + + // Try to parse long + var l = Longs.tryParse(str); + if (l != null) { + return new JsonPrimitive(l); + } + + // Try to parse double + var d = Doubles.tryParse(str); + if (d != null) { + return new JsonPrimitive(d); + } + + // Fallback + return new JsonPrimitive(str); + } } diff --git a/io.openems.shared.influxdb/test/io/openems/shared/influxdb/proxy/InfluxQlProxyTest.java b/io.openems.shared.influxdb/test/io/openems/shared/influxdb/proxy/InfluxQlProxyTest.java index 5d76d9c7f69..f4e35cc4ec2 100644 --- a/io.openems.shared.influxdb/test/io/openems/shared/influxdb/proxy/InfluxQlProxyTest.java +++ b/io.openems.shared.influxdb/test/io/openems/shared/influxdb/proxy/InfluxQlProxyTest.java @@ -1,5 +1,6 @@ package io.openems.shared.influxdb.proxy; +import static io.openems.shared.influxdb.proxy.InfluxQlProxy.parseToJsonElement; import static org.junit.Assert.assertEquals; import java.util.List; @@ -33,4 +34,13 @@ public void testAverage() { assertEquals(4d, last.getAsDouble(), 0d); } + @Test + public void testParseToJsonElement() { + assertEquals(123.456, parseToJsonElement("123.456").getAsNumber()); + assertEquals(123L, parseToJsonElement("123").getAsNumber()); + assertEquals(" 123 ", parseToJsonElement(" 123 ").getAsString()); + assertEquals("foo-bar", parseToJsonElement("foo-bar").getAsString()); + assertEquals(JsonNull.INSTANCE, parseToJsonElement(null)); + assertEquals(JsonNull.INSTANCE, parseToJsonElement("")); + } } diff --git a/io.openems.wrapper/bnd.bnd b/io.openems.wrapper/bnd.bnd index a4088ac1113..eaa0db0019f 100644 --- a/io.openems.wrapper/bnd.bnd +++ b/io.openems.wrapper/bnd.bnd @@ -25,5 +25,6 @@ Bundle-Description: This wraps external java libraries that do not have OSGi hea de.bytefish:pgbulkinsert;version='8.1.3',\ fr.turri:aXMLRPC;version='1.13.0',\ org.dhatim:fastexcel;version='0.18.0',\ + org.dhatim:fastexcel-reader;version='0.18',\ org.eclipse.paho.mqttv5.client;version='1.2.5',\ - org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm;version='1.7.3',\ + org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm;version='1.7.3',\ \ No newline at end of file diff --git a/io.openems.wrapper/fastexcel.bnd b/io.openems.wrapper/fastexcel.bnd index ab7f758a06e..92ccb7bb914 100644 --- a/io.openems.wrapper/fastexcel.bnd +++ b/io.openems.wrapper/fastexcel.bnd @@ -3,13 +3,16 @@ Bundle-DocURL: https://github.com/dhatim/fastexcel Bundle-License: https://opensource.org/licenses/Apache-2.0 Bundle-Version: 0.18.0 -Include-Resource: @fastexcel-0.18.0.jar +Include-Resource: \ + @fastexcel-0.18.0.jar,\ + @fastexcel-reader-0.18.0.jar,\ -dsannotations: * -metatypeannotations: * Export-Package: \ - org.dhatim.fastexcel + org.dhatim.fastexcel,\ + org.dhatim.fastexcel.reader,\ -sources: false diff --git a/tools/build-debian-package.sh b/tools/build-debian-package.sh index 9582af59322..a57747c6e13 100755 --- a/tools/build-debian-package.sh +++ b/tools/build-debian-package.sh @@ -1,7 +1,9 @@ -#!/bin/bash -e +#!/bin/bash # # Creates a Debian package for OpenEMS Edge + UI +set -e + OUTPUT=$( realpath ${1:-.} ) DEBIAN_UI_LOCATION=tools/debian/usr/share/openems/www @@ -28,7 +30,7 @@ initialize_environment() { source $SCRIPT_DIR/common.sh common_initialize_environment common_build_snapshot_version - + DEB_FILE="${PACKAGE_NAME}.deb" VERSION_FILE="${PACKAGE_NAME}.version" } @@ -53,6 +55,12 @@ prepare_deb_template() { echo "# Build Debian package" sed --in-place "s/^\(Version: \).*$/\1$VERSION/" tools/debian/DEBIAN/control + for script in preinst postinst prerm postrm + do + script="tools/debian/DEBIAN/$script" + [ -f $script ] && chmod 755 $script + done + echo "## Add OpenEMS Edge" if [ -f "$DEBIAN_EDGE_LOCATION/openems.jar" ]; then echo "openems.jar exists. Skipping common_build_edge." diff --git a/tools/debian/DEBIAN/postrm b/tools/debian/DEBIAN/postrm new file mode 100755 index 00000000000..5f387c310fe --- /dev/null +++ b/tools/debian/DEBIAN/postrm @@ -0,0 +1,16 @@ +#!/bin/bash +# postrm script for openems-edge + +set -o errexit + +function purge-openems { + local confdir="/etc/openems.d" + local libdir="/var/lib/openems" + + if [ -d "${confdir}" ]; then rm -r "${confdir}"; fi + if [ -d "${libdir}" ]; then rm -r "${libdir}"; fi +} + +case "$1" in + "purge") purge-openems;; +esac diff --git a/tools/drone/openems-android.sh b/tools/drone/openems-android.sh new file mode 100755 index 00000000000..8e19fd37bea --- /dev/null +++ b/tools/drone/openems-android.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +NODE_MAJOR=20 + +ANDROID_SDK_VERSION=9477386 +ANDROID_HOME="/opt/android-sdk" +ANDROID_BUILD_TOOLS_VERSION=32.0.0 +ANDROID_PLATFORMS_VERSION=32 + +# Build/Update 'openems-android' Container for Drone/Woodpecker CI + +docker pull node:${NODE_MAJOR} + +docker build -t openems-android:${NODE_MAJOR}.${ANDROID_PLATFORMS_VERSION} -f - . < /usr/bin/copy \ + && chmod +x /usr/bin/copy + +RUN ln -sf /bin/bash /bin/sh + +EOF \ No newline at end of file diff --git a/tools/drone/openems-build.sh b/tools/drone/openems-build.sh new file mode 100644 index 00000000000..810fbb5922b --- /dev/null +++ b/tools/drone/openems-build.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +JAVA_VERSION=21 +NODE_MAJOR=20 + +# Build/Update 'openems-build' Container for Drone/Woodpecker CI + +docker pull eclipse-temurin:${JAVA_VERSION}-jdk + +docker build -t openems-build:${JAVA_VERSION}.${NODE_MAJOR} -f - . < [!IMPORTANT] +> Crucial information necessary for users to succeed. Only provide /resources/logo-dark.png and logo.png +* Move the files from res(except values and xml) to ```/android/app/src/$theme/``` (```/main``` acts as default) +* Build apps: `gradlew bundle{$theme}Release` + +Important (if not generated, can be copied and adjusted from existing theme): +- `ui\android\app\src\{$theme}\res\xml\file_paths.xml` +- `ui\android\app\src\{$theme}\res\values` + +### Debugging + +Use `gradlew install{$theme}Release to install it on any device` + +- Available Tasks: `gradlew tasks` +- list available devices + emulators: `$npx native-run android --list --json` + +## i18n - internationalization Translation is based on [ngx-translate](https://github.com/ngx-translate). The language can be changed at runtime in the "About UI" dialog. @@ -84,4 +114,4 @@ ngOnDestroy() { ``` #### Debugging Angular PWA Via USB-Connection -Please follow this: https://medium.com/nerd-for-tech/google-chrome-how-to-inspect-websites-on-mobile-devices-804677f863ce +Please follow this: https://medium.com/nerd-for-tech/google-chrome-how-to-inspect-websites-on-mobile-devices-804677f863ce \ No newline at end of file diff --git a/ui/android/.idea/.gitignore b/ui/android/.idea/.gitignore new file mode 100644 index 00000000000..26d33521af1 --- /dev/null +++ b/ui/android/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/ui/android/.idea/compiler.xml b/ui/android/.idea/compiler.xml new file mode 100644 index 00000000000..b589d56e9f2 --- /dev/null +++ b/ui/android/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/ui/android/.idea/jarRepositories.xml b/ui/android/.idea/jarRepositories.xml new file mode 100644 index 00000000000..de647e0dbb5 --- /dev/null +++ b/ui/android/.idea/jarRepositories.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ui/android/.idea/misc.xml b/ui/android/.idea/misc.xml new file mode 100644 index 00000000000..8978d23db56 --- /dev/null +++ b/ui/android/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/ui/android/app/.gitignore b/ui/android/app/.gitignore new file mode 100644 index 00000000000..043df802a29 --- /dev/null +++ b/ui/android/app/.gitignore @@ -0,0 +1,2 @@ +/build/* +!/build/.npmkeep diff --git a/ui/android/app/build.gradle b/ui/android/app/build.gradle new file mode 100644 index 00000000000..04b12182cfc --- /dev/null +++ b/ui/android/app/build.gradle @@ -0,0 +1,88 @@ +apply plugin: 'com.android.application' + +def keystorePropertiesFile = rootProject.file("keystore.properties") +def keystoreProperties = new Properties() +keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) + +android { + compileSdkVersion rootProject.ext.compileSdkVersion + defaultConfig { + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion + versionCode 29 + versionName "2024.5.1.1" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + aaptOptions { + // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. + // Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61 + ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~' + } + multiDexEnabled true //important + } + + flavorDimensions "version" + productFlavors { + // create("example") { + // applicationId "io.example.ui" + // namespace "io.example.ui" + // dimension "version" + // } + } + + sourceSets { + // example { + // res { + // srcDirs 'src/example/res' + // } + // java { + // srcDirs 'src/example/java' + // } + // } + } + + signingConfigs { + release { + keyAlias keystoreProperties['keyAlias'] + keyPassword keystoreProperties['keyPassword'] + storeFile file(keystoreProperties['storeFile']) + storePassword keystoreProperties['storePassword'] + } + } + + buildTypes { + release { + signingConfig signingConfigs.release + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +repositories { + flatDir{ + dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs' + } +} + +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" + implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion" + implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion" + implementation project(':capacitor-android') + testImplementation "junit:junit:$junitVersion" + androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" + androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion" + implementation project(':capacitor-cordova-android-plugins') +} + +apply from: 'capacitor.build.gradle' + +try { + def servicesJSON = file('google-services.json') + if (servicesJSON.text) { + apply plugin: 'com.google.gms.google-services' + } +} catch(Exception e) { + logger.info("google-services.json not found, google-services plugin not applied. Push Notifications won't work") +} \ No newline at end of file diff --git a/ui/android/app/capacitor.build.gradle b/ui/android/app/capacitor.build.gradle new file mode 100644 index 00000000000..65d219eae7a --- /dev/null +++ b/ui/android/app/capacitor.build.gradle @@ -0,0 +1,24 @@ +// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN + +android { + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } +} + +apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle" +dependencies { + implementation project(':capacitor-community-file-opener') + implementation project(':capacitor-app') + implementation project(':capacitor-filesystem') + implementation project(':capacitor-splash-screen') + implementation project(':capacitor-blob-writer') + implementation project(':capacitor-secure-storage-plugin') + +} + + +if (hasProperty('postBuildExtras')) { + postBuildExtras() +} diff --git a/ui/android/app/proguard-rules.pro b/ui/android/app/proguard-rules.pro new file mode 100644 index 00000000000..f1b424510da --- /dev/null +++ b/ui/android/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/ui/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java b/ui/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java new file mode 100644 index 00000000000..f2c2217efa5 --- /dev/null +++ b/ui/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.getcapacitor.myapp; + +import static org.junit.Assert.*; + +import android.content.Context; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see
      Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + + @Test + public void useAppContext() throws Exception { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + + assertEquals("com.getcapacitor.app", appContext.getPackageName()); + } +} diff --git a/ui/android/app/src/main/AndroidManifest.xml b/ui/android/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000000..665cbc6d021 --- /dev/null +++ b/ui/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/ui/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java b/ui/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java new file mode 100644 index 00000000000..0297327842d --- /dev/null +++ b/ui/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java @@ -0,0 +1,18 @@ +package com.getcapacitor.myapp; + +import static org.junit.Assert.*; + +import org.junit.Test; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + + @Test + public void addition_isCorrect() throws Exception { + assertEquals(4, 2 + 2); + } +} diff --git a/ui/android/build.gradle b/ui/android/build.gradle new file mode 100644 index 00000000000..3bdeb1b77f0 --- /dev/null +++ b/ui/android/build.gradle @@ -0,0 +1,32 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + + ext { + agp_version = '8.1.4' + } + repositories { + google() + mavenCentral() + } + dependencies { + classpath "com.android.tools.build:gradle:$agp_version" + classpath 'com.google.gms:google-services:4.3.15' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +apply from: "variables.gradle" + +allprojects { + repositories { + google() + mavenCentral() + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/ui/android/capacitor.settings.gradle b/ui/android/capacitor.settings.gradle new file mode 100644 index 00000000000..917fdb649c8 --- /dev/null +++ b/ui/android/capacitor.settings.gradle @@ -0,0 +1,21 @@ +// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN +include ':capacitor-android' +project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor') + +include ':capacitor-community-file-opener' +project(':capacitor-community-file-opener').projectDir = new File('../node_modules/@capacitor-community/file-opener/android') + +include ':capacitor-app' +project(':capacitor-app').projectDir = new File('../node_modules/@capacitor/app/android') + +include ':capacitor-filesystem' +project(':capacitor-filesystem').projectDir = new File('../node_modules/@capacitor/filesystem/android') + +include ':capacitor-splash-screen' +project(':capacitor-splash-screen').projectDir = new File('../node_modules/@capacitor/splash-screen/android') + +include ':capacitor-blob-writer' +project(':capacitor-blob-writer').projectDir = new File('../node_modules/capacitor-blob-writer/android') + +include ':capacitor-secure-storage-plugin' +project(':capacitor-secure-storage-plugin').projectDir = new File('../node_modules/capacitor-secure-storage-plugin/android') diff --git a/ui/android/gradle.properties b/ui/android/gradle.properties new file mode 100644 index 00000000000..2e87c52f83c --- /dev/null +++ b/ui/android/gradle.properties @@ -0,0 +1,22 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx1536m + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true + +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true diff --git a/ui/android/gradle/wrapper/gradle-wrapper.jar b/ui/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..ccebba7710deaf9f98673a68957ea02138b60d0a GIT binary patch literal 61608 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 literal 0 HcmV?d00001 diff --git a/ui/android/gradle/wrapper/gradle-wrapper.properties b/ui/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..cab95f43c39 --- /dev/null +++ b/ui/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +#Thu Apr 04 11:31:47 CEST 2024 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/ui/android/gradlew b/ui/android/gradlew new file mode 100644 index 00000000000..79a61d421cc --- /dev/null +++ b/ui/android/gradlew @@ -0,0 +1,244 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/ui/android/gradlew.bat b/ui/android/gradlew.bat new file mode 100644 index 00000000000..93e3f59f135 --- /dev/null +++ b/ui/android/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/ui/android/keystore.properties b/ui/android/keystore.properties new file mode 100644 index 00000000000..9ac490bd3ea --- /dev/null +++ b/ui/android/keystore.properties @@ -0,0 +1,4 @@ +storePassword=Halelilu4 +keyPassword=Halelilu4 +keyAlias=key1 +storeFile=./../../key.jks \ No newline at end of file diff --git a/ui/android/settings.gradle b/ui/android/settings.gradle new file mode 100644 index 00000000000..3b4431d7724 --- /dev/null +++ b/ui/android/settings.gradle @@ -0,0 +1,5 @@ +include ':app' +include ':capacitor-cordova-android-plugins' +project(':capacitor-cordova-android-plugins').projectDir = new File('./capacitor-cordova-android-plugins/') + +apply from: 'capacitor.settings.gradle' \ No newline at end of file diff --git a/ui/android/variables.gradle b/ui/android/variables.gradle new file mode 100644 index 00000000000..5946adabdd2 --- /dev/null +++ b/ui/android/variables.gradle @@ -0,0 +1,16 @@ +ext { + minSdkVersion = 22 + compileSdkVersion = 33 + targetSdkVersion = 33 + androidxActivityVersion = '1.7.0' + androidxAppCompatVersion = '1.6.1' + androidxCoordinatorLayoutVersion = '1.2.0' + androidxCoreVersion = '1.10.0' + androidxFragmentVersion = '1.5.6' + coreSplashScreenVersion = '1.0.0' + androidxWebkitVersion = '1.6.1' + junitVersion = '4.13.2' + androidxJunitVersion = '1.1.5' + androidxEspressoCoreVersion = '3.5.1' + cordovaAndroidVersion = '10.1.1' +} \ No newline at end of file diff --git a/ui/capacitor.config.ts b/ui/capacitor.config.ts new file mode 100644 index 00000000000..7702fbd212e --- /dev/null +++ b/ui/capacitor.config.ts @@ -0,0 +1,47 @@ +import { CapacitorConfig } from '@capacitor/cli'; +import { Theme } from 'src/environments'; + +let config: CapacitorConfig; + +const baseConfig: CapacitorConfig = { + webDir: 'target', + server: { + androidScheme: 'https', + iosScheme: 'https', + }, + plugins: { + SplashScreen: { + launchShowDuration: 1000, + launchAutoHide: false, + launchFadeOutDuration: 1000, + backgroundColor: "#ffffffff", + androidSplashResourceName: "splash", + androidScaleType: "CENTER_INSIDE", + splashFullScreen: false, + splashImmersive: true, + useDialog: true, + }, + CapacitorCookies: { + enabled: true + } + } +} + +switch (process.env.NODE_ENV as Theme) { + // case 'EXAMPLE': + // config = { + // ...baseConfig, + // appId: 'io.openems.ui', + // appName: 'EXAMPL', + // server: { + // ...baseConfig.server, + // hostname: 'portal.openems.io' + // } + // } + // break; + default: + throw new Error(`Capacitor config for theme ${process.env.NODE_ENV} not implemented.`) +} +console.warn(config); + +export default config; diff --git a/ui/ionic.config.json b/ui/ionic.config.json index 5d37ec1d4cc..9ecee1c52ce 100644 --- a/ui/ionic.config.json +++ b/ui/ionic.config.json @@ -1,5 +1,7 @@ { "name": "openems-ui", - "integrations": {}, + "integrations": { + "capacitor": {} + }, "type": "angular" -} \ No newline at end of file +} diff --git a/ui/package-lock.json b/ui/package-lock.json index 68e4c750c74..2fb7e864c4f 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -17,12 +17,25 @@ "@angular/platform-browser-dynamic": "~16.2.12", "@angular/router": "~16.2.12", "@angular/service-worker": "~16.2.12", + "@capacitor-community/file-opener": "^1.0.5", + "@capacitor/android": "5.2.3", + "@capacitor/app": "^5.0.6", + "@capacitor/core": "5.2.3", + "@capacitor/filesystem": "^5.2.0", + "@capacitor/ios": "5.2.3", + "@capacitor/splash-screen": "^5.0.6", + "@ionic-native/core": "^5.36.0", + "@ionic-native/file-opener": "^5.36.0", "@ionic/angular": "^6.7.5", + "@ionic/cli": "^7.1.6", "@ngx-formly/core": "^6.3.0", "@ngx-formly/ionic": "^6.3.5", "@ngx-formly/schematics": "^6.3.0", "@ngx-translate/core": "^15.0.0", "@nodro7/angular-mydatepicker": "^0.14.0", + "capacitor-blob-writer": "^1.1.14", + "capacitor-ios-autofill-save-password": "^2.0.0", + "capacitor-secure-storage-plugin": "^0.9.0", "chart.js": "^4.4.3", "chartjs-adapter-date-fns": "^3.0.0", "chartjs-plugin-zoom": "^2.0.1", @@ -51,6 +64,8 @@ "@angular/compiler": "^16.2.12", "@angular/compiler-cli": "^16.2.12", "@angular/language-service": "^16.2.12", + "@capacitor/assets": "^3.0.0", + "@capacitor/cli": "5.2.3", "@ionic/angular-toolkit": "^11.0.1", "@stylistic/eslint-plugin": "^2.2.2", "@types/jasmine": "~4.3.6", @@ -122,9 +137,8 @@ }, "node_modules/@angular-devkit/build-angular": { "version": "16.2.14", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-16.2.14.tgz", - "integrity": "sha512-bXQ6i7QPhwmYHuh+DSNkBhjTIHQF0C6fqZEg2ApJA3NmnzE98oQnmJ9AnGnAkdf1Mjn3xi2gxoZWPDDxGEINMw==", "dev": true, + "license": "MIT", "dependencies": { "@ampproject/remapping": "2.2.1", "@angular-devkit/architect": "0.1602.14", @@ -256,9 +270,8 @@ }, "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/architect": { "version": "0.1602.14", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.14.tgz", - "integrity": "sha512-eSdONEV5dbtLNiOMBy9Ue9DdJ1ct6dH9RdZfYiedq6VZn0lejePAjY36MYVXgq2jTE+v/uIiaNy7caea5pt55A==", "dev": true, + "license": "MIT", "dependencies": { "@angular-devkit/core": "16.2.14", "rxjs": "7.8.1" @@ -271,9 +284,8 @@ }, "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core": { "version": "16.2.14", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.14.tgz", - "integrity": "sha512-Ui14/d2+p7lnmXlK/AX2ieQEGInBV75lonNtPQgwrYgskF8ufCuN0DyVZQUy9fJDkC+xQxbJyYrby/BS0R0e7w==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "8.12.0", "ajv-formats": "2.1.1", @@ -298,9 +310,8 @@ }, "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core/node_modules/ajv": { "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -314,15 +325,13 @@ }, "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core/node_modules/json-schema-traverse": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core/node_modules/source-map": { "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">= 8" } @@ -632,9 +641,8 @@ }, "node_modules/@angular-devkit/build-webpack": { "version": "0.1602.14", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1602.14.tgz", - "integrity": "sha512-f+ZTCjOoA1SCQEaX3L/63ubqr/vlHkwDXAtKjBsQgyz6srnETcjy96Us5k/LoK7/hPc85zFneqLinfqOMVWHJQ==", "dev": true, + "license": "MIT", "dependencies": { "@angular-devkit/architect": "0.1602.14", "rxjs": "7.8.1" @@ -651,9 +659,8 @@ }, "node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/architect": { "version": "0.1602.14", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.14.tgz", - "integrity": "sha512-eSdONEV5dbtLNiOMBy9Ue9DdJ1ct6dH9RdZfYiedq6VZn0lejePAjY36MYVXgq2jTE+v/uIiaNy7caea5pt55A==", "dev": true, + "license": "MIT", "dependencies": { "@angular-devkit/core": "16.2.14", "rxjs": "7.8.1" @@ -666,9 +673,8 @@ }, "node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/core": { "version": "16.2.14", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.14.tgz", - "integrity": "sha512-Ui14/d2+p7lnmXlK/AX2ieQEGInBV75lonNtPQgwrYgskF8ufCuN0DyVZQUy9fJDkC+xQxbJyYrby/BS0R0e7w==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "8.12.0", "ajv-formats": "2.1.1", @@ -693,15 +699,13 @@ }, "node_modules/@angular-devkit/build-webpack/node_modules/jsonc-parser": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@angular-devkit/build-webpack/node_modules/rxjs": { "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -2833,578 +2837,719 @@ "node": ">=6.9.0" } }, - "node_modules/@colors/colors": { - "version": "1.5.0", - "dev": true, + "node_modules/@capacitor-community/file-opener": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@capacitor-community/file-opener/-/file-opener-1.0.6.tgz", + "integrity": "sha512-iHsPblcgqTF8rEmvpVyAGfxuTUtV8BthoBv/zBLKEEb1vSUVONed0UTRjvvqjHxewS8LNEWVXzuMzXfQU1r1cA==", "license": "MIT", "engines": { - "node": ">=0.1.90" + "node": ">=16.0.0", + "npm": ">=8.0.0" + }, + "peerDependencies": { + "@capacitor/core": "^5.0.0" } }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "dev": true, + "node_modules/@capacitor/android": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@capacitor/android/-/android-5.2.3.tgz", + "integrity": "sha512-TqXOq5RIniMACcAckn/X84XajPP2GU4VH7Er390Ja2Y2BWSeUKgk7T8aURcwLYu2hnv+Op9eTww5MTBb3zBtmg==", "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" + "peerDependencies": { + "@capacitor/core": "^5.2.0" } }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "dev": true, + "node_modules/@capacitor/app": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@capacitor/app/-/app-5.0.8.tgz", + "integrity": "sha512-ClUPJG6Awkf5HncVCZQwLrnuugjU8TnACSJ1dKJb6QNCHv2jQzmXvB3KvTvxTZyWbh5EVvlla0qlobYyU1lb6A==", "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "peerDependencies": { + "@capacitor/core": "^5.0.0" } }, - "node_modules/@discoveryjs/json-ext": { - "version": "0.5.7", - "dev": true, - "license": "MIT", + "node_modules/@capacitor/assets": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@capacitor/assets/-/assets-3.0.5.tgz", + "integrity": "sha512-ohz/OUq61Y1Fc6aVSt0uDrUdeOA7oTH4pkWDbv/8I3UrPjH7oPkzYhShuDRUjekNp9RBi198VSFdt0CetpEOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@capacitor/cli": "^5.3.0", + "@ionic/utils-array": "2.1.6", + "@ionic/utils-fs": "3.1.7", + "@trapezedev/project": "^7.0.10", + "commander": "8.3.0", + "debug": "4.3.4", + "fs-extra": "10.1.0", + "node-fetch": "2.7.0", + "node-html-parser": "5.4.2", + "sharp": "0.32.6", + "tslib": "2.6.2", + "yargs": "17.7.2" + }, + "bin": { + "capacitor-assets": "bin/capacitor-assets" + }, "engines": { - "node": ">=10.0.0" + "node": ">=10.3.0" } }, - "node_modules/@es-joy/jsdoccomment": { - "version": "0.42.0", + "node_modules/@capacitor/assets/node_modules/@capacitor/cli": { + "version": "5.7.6", + "resolved": "https://registry.npmjs.org/@capacitor/cli/-/cli-5.7.6.tgz", + "integrity": "sha512-CDDcBF7wHm5v/j0dA2bls0vK954XlD1JCjMuTgLtjZMvWrIlTJAkwCQLkiqRhS2P63AXqfqQqkb/qs2RHc1zDQ==", "dev": true, "license": "MIT", "dependencies": { - "comment-parser": "1.4.1", - "esquery": "^1.5.0", - "jsdoc-type-pratt-parser": "~4.0.0" + "@ionic/cli-framework-output": "^2.2.5", + "@ionic/utils-fs": "^3.1.6", + "@ionic/utils-subprocess": "^2.1.11", + "@ionic/utils-terminal": "^2.3.3", + "commander": "^9.3.0", + "debug": "^4.3.4", + "env-paths": "^2.2.0", + "kleur": "^4.1.4", + "native-run": "^2.0.0", + "open": "^8.4.0", + "plist": "^3.0.5", + "prompts": "^2.4.2", + "rimraf": "^4.4.1", + "semver": "^7.3.7", + "tar": "^6.1.11", + "tslib": "^2.4.0", + "xml2js": "^0.5.0" + }, + "bin": { + "cap": "bin/capacitor", + "capacitor": "bin/capacitor" }, "engines": { - "node": ">=16" + "node": ">=16.0.0" } }, - "node_modules/@esbuild/linux-x64": { - "version": "0.18.17", - "cpu": [ - "x64" - ], + "node_modules/@capacitor/assets/node_modules/@capacitor/cli/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=12" + "node": "^12.20.0 || >=14" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", + "node_modules/@capacitor/assets/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + "balanced-match": "^1.0.0" } }, - "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", + "node_modules/@capacitor/assets/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", "dev": true, "license": "MIT", "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "node": ">= 12" } }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", + "node_modules/@capacitor/assets/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, "license": "MIT", "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=12" } }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", + "node_modules/@capacitor/assets/node_modules/glob": { + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", + "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "fs.realpath": "^1.0.0", + "minimatch": "^8.0.2", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@eslint/eslintrc/node_modules/argparse": { - "version": "2.0.1", + "node_modules/@capacitor/assets/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, - "license": "Python-2.0" + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.24.0", + "node_modules/@capacitor/assets/node_modules/minimatch": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", + "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "type-fest": "^0.20.2" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=8" + "node": ">=16 || 14 >=14.17" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@eslint/eslintrc/node_modules/js-yaml": { - "version": "4.1.0", + "node_modules/@capacitor/assets/node_modules/minipass": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", + "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/@capacitor/assets/node_modules/native-run": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/native-run/-/native-run-2.0.1.tgz", + "integrity": "sha512-XfG1FBZLM50J10xH9361whJRC9SHZ0Bub4iNRhhI61C8Jv0e1ud19muex6sNKB51ibQNUJNuYn25MuYET/rE6w==", "dev": true, "license": "MIT", "dependencies": { - "argparse": "^2.0.1" + "@ionic/utils-fs": "^3.1.7", + "@ionic/utils-terminal": "^2.3.4", + "bplist-parser": "^0.3.2", + "debug": "^4.3.4", + "elementtree": "^0.1.7", + "ini": "^4.1.1", + "plist": "^3.1.0", + "split2": "^4.2.0", + "through2": "^4.0.2", + "tslib": "^2.6.2", + "yauzl": "^2.10.0" }, "bin": { - "js-yaml": "bin/js-yaml.js" + "native-run": "bin/native-run" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { - "version": "0.4.1", - "dev": true, - "license": "MIT" - }, - "node_modules/@eslint/eslintrc/node_modules/type-fest": { - "version": "0.20.2", + "node_modules/@capacitor/assets/node_modules/rimraf": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.1.tgz", + "integrity": "sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==", "dev": true, - "license": "(MIT OR CC0-1.0)", + "license": "ISC", + "dependencies": { + "glob": "^9.2.0" + }, + "bin": { + "rimraf": "dist/cjs/src/bin.js" + }, "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@eslint/js": { - "version": "8.57.0", + "node_modules/@capacitor/assets/node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", "dev": true, - "license": "MIT", + "license": "ISC", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">= 10.x" } }, - "node_modules/@gar/promisify": { - "version": "1.1.3", + "node_modules/@capacitor/assets/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", + "node_modules/@capacitor/assets/node_modules/xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" }, "engines": { - "node": ">=10.10.0" + "node": ">=4.0.0" } }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", + "node_modules/@capacitor/cli": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@capacitor/cli/-/cli-5.2.3.tgz", + "integrity": "sha512-iqjOnA9fCxm+cFv5iTvxb/vElK2Z1kDpVS+N9XyD2Msyv3l3ezuOZTSvABiDoo6w6CGkj4/AUMpdT4nrZkTHTg==", "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" + "license": "MIT", + "dependencies": { + "@ionic/cli-framework-output": "^2.2.5", + "@ionic/utils-fs": "^3.1.6", + "@ionic/utils-subprocess": "^2.1.11", + "@ionic/utils-terminal": "^2.3.3", + "commander": "^9.3.0", + "debug": "^4.3.4", + "env-paths": "^2.2.0", + "kleur": "^4.1.4", + "native-run": "^1.7.2", + "open": "^8.4.0", + "plist": "^3.0.5", + "prompts": "^2.4.2", + "rimraf": "^4.4.1", + "semver": "^7.3.7", + "tar": "^6.1.11", + "tslib": "^2.4.0", + "xml2js": "^0.5.0" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "bin": { + "cap": "bin/capacitor", + "capacitor": "bin/capacitor" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.2", + "node_modules/@capacitor/cli/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@ionic/angular": { - "version": "6.7.5", "license": "MIT", "dependencies": { - "@ionic/core": "6.7.5", - "ionicons": "^6.1.3", - "jsonc-parser": "^3.0.0", - "tslib": "^2.0.0" - }, - "peerDependencies": { - "@angular/core": ">=12.0.0", - "@angular/forms": ">=12.0.0", - "@angular/router": ">=12.0.0", - "rxjs": ">=6.6.0", - "zone.js": ">=0.11.0" + "balanced-match": "^1.0.0" } }, - "node_modules/@ionic/angular-toolkit": { - "version": "11.0.1", + "node_modules/@capacitor/cli/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", "dev": true, "license": "MIT", - "dependencies": { - "@angular-devkit/core": "^17.0.0", - "@angular-devkit/schematics": "^17.0.0", - "@schematics/angular": "^17.0.0" + "engines": { + "node": "^12.20.0 || >=14" } }, - "node_modules/@ionic/angular-toolkit/node_modules/@angular-devkit/core": { - "version": "17.3.3", + "node_modules/@capacitor/cli/node_modules/glob": { + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", + "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "ajv": "8.12.0", - "ajv-formats": "2.1.1", - "jsonc-parser": "3.2.1", - "picomatch": "4.0.1", - "rxjs": "7.8.1", - "source-map": "0.7.4" + "fs.realpath": "^1.0.0", + "minimatch": "^8.0.2", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" }, "engines": { - "node": "^18.13.0 || >=20.9.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^3.5.2" + "node": ">=16 || 14 >=14.17" }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@ionic/angular-toolkit/node_modules/@angular-devkit/schematics": { - "version": "17.3.3", + "node_modules/@capacitor/cli/node_modules/minimatch": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", + "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "@angular-devkit/core": "17.3.3", - "jsonc-parser": "3.2.1", - "magic-string": "0.30.8", - "ora": "5.4.1", - "rxjs": "7.8.1" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "^18.13.0 || >=20.9.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@ionic/angular-toolkit/node_modules/@schematics/angular": { - "version": "17.3.3", + "node_modules/@capacitor/cli/node_modules/minipass": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", + "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", "dev": true, - "license": "MIT", - "dependencies": { - "@angular-devkit/core": "17.3.3", - "@angular-devkit/schematics": "17.3.3", - "jsonc-parser": "3.2.1" - }, + "license": "ISC", "engines": { - "node": "^18.13.0 || >=20.9.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" + "node": ">=8" } }, - "node_modules/@ionic/angular-toolkit/node_modules/magic-string": { - "version": "0.30.8", + "node_modules/@capacitor/cli/node_modules/rimraf": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.1.tgz", + "integrity": "sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" + "glob": "^9.2.0" + }, + "bin": { + "rimraf": "dist/cjs/src/bin.js" }, "engines": { - "node": ">=12" - } - }, - "node_modules/@ionic/angular-toolkit/node_modules/picomatch": { - "version": "4.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@ionic/angular-toolkit/node_modules/rxjs": { - "version": "7.8.1", + "node_modules/@capacitor/cli/node_modules/xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "tslib": "^2.1.0" + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" } }, - "node_modules/@ionic/core": { - "version": "6.7.5", + "node_modules/@capacitor/core": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-5.2.3.tgz", + "integrity": "sha512-Q1zbgt3Mvldy7six2/GX54kTL0ozgnR37jeDUAXL/fOJBF4Iorr/8A0OjGEAnwEjpR1la7uFZUunESMFyMLhEQ==", "license": "MIT", "dependencies": { - "@stencil/core": "^2.18.0", - "ionicons": "^6.1.3", "tslib": "^2.1.0" } }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" + "node_modules/@capacitor/filesystem": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@capacitor/filesystem/-/filesystem-5.2.2.tgz", + "integrity": "sha512-h0Ta0NXF/zX9bXoD5qtoEoWSWCewow8Kredb2bBFO+vrd4NVthZH+GyrII2dk0++UIw40HjyLNk4apwGGSu9Sg==", + "license": "MIT", + "peerDependencies": { + "@capacitor/core": "^5.1.1" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.0.1", - "dev": true, + "node_modules/@capacitor/ios": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@capacitor/ios/-/ios-5.2.3.tgz", + "integrity": "sha512-ailR/Mer48GEXdqip+ENyN3Qk+ZtUBNDTlHh83WLNbx6uv71z6lCeoLKBXdtSEBFwzFrwtCO5upzbdzK79pONQ==", "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "peerDependencies": { + "@capacitor/core": "^5.2.0" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "dev": true, + "node_modules/@capacitor/splash-screen": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@capacitor/splash-screen/-/splash-screen-5.0.8.tgz", + "integrity": "sha512-mDRJS9QFxL5UMN74gRr6cBhOtkZjWwdttPCjBJNgcMDJIGi9IAKRJuDGTsqSUbp6zWrPF4AW29Mu6qhXtHpHWg==", "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "peerDependencies": { + "@capacitor/core": "^5.0.0" } }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "dev": true, - "license": "MIT" - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", + "node_modules/@colors/colors": { + "version": "1.5.0", "dev": true, "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.1.90" } }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^6.0.1" + "@jridgewell/trace-mapping": "0.3.9" }, "engines": { "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", "dev": true, - "license": "ISC", - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=10.0.0" } }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", + "node_modules/@es-joy/jsdoccomment": { + "version": "0.42.0", "dev": true, "license": "MIT", + "dependencies": { + "comment-parser": "1.4.1", + "esquery": "^1.5.0", + "jsdoc-type-pratt-parser": "~4.0.0" + }, "engines": { - "node": ">=8" + "node": ">=16" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" + "eslint-visitor-keys": "^3.3.0" }, "engines": { - "node": ">=6.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", "dev": true, "license": "MIT", "engines": { - "node": ">=6.0.0" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", "dev": true, "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, "engines": { - "node": ">=6.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.5", + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", "dev": true, - "license": "MIT" + "license": "Python-2.0" }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@kurkle/color": { - "version": "0.3.2", + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, "license": "MIT" }, - "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", - "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", - "dev": true + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/@ngtools/webpack": { - "version": "16.2.14", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-16.2.14.tgz", - "integrity": "sha512-3+zPP3Wir46qrZ3FEiTz5/emSoVHYUCH+WgBmJ57mZCx1qBOYh2VgllnPr/Yusl1sc/jUZjdwq/es/9ZNw+zDQ==", + "node_modules/@eslint/js": { + "version": "8.57.0", "dev": true, + "license": "MIT", "engines": { - "node": "^16.14.0 || >=18.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.2", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@hutson/parse-repository-url": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz", + "integrity": "sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@ionic-native/core": { + "version": "5.36.0", + "resolved": "https://registry.npmjs.org/@ionic-native/core/-/core-5.36.0.tgz", + "integrity": "sha512-lOrkktadlKYbYf1LrDyAtsu1JnQ0oCCdkOU7iHQ8oXnNOkMwobFfD2m62F1CoOr0u9LIkpYnZSPjng8lZbmbNw==", + "license": "MIT", + "dependencies": { + "@types/cordova": "latest" }, "peerDependencies": { - "@angular/compiler-cli": "^16.0.0", - "typescript": ">=4.9.3 <5.2", - "webpack": "^5.54.0" + "rxjs": "^5.5.0 || ^6.5.0" } }, - "node_modules/@ngx-formly/core": { - "version": "6.3.5", - "resolved": "https://registry.npmjs.org/@ngx-formly/core/-/core-6.3.5.tgz", - "integrity": "sha512-9p4yl7fr2Ojmm/uN7/nM1hYezheUxecEC0WZ0YI6jeSoEJR8NYTglVxTmHrpW5had2oolHeO39sAo9ttJNifSA==", + "node_modules/@ionic-native/file-opener": { + "version": "5.36.0", + "resolved": "https://registry.npmjs.org/@ionic-native/file-opener/-/file-opener-5.36.0.tgz", + "integrity": "sha512-UKp3pbqvQXsAtLMJ5JE+KcTMxpjSZMFebf6nvy/KJvwy85JGIaCV4ZVM/H9CFUrHJMWBH6wDbY+WPygnsrl4Yg==", + "license": "MIT", "dependencies": { - "tslib": "^2.0.0" + "@types/cordova": "latest" }, "peerDependencies": { - "@angular/forms": ">=13.2.0", - "rxjs": "^6.5.3 || ^7.0.0" + "@ionic-native/core": "^5.1.0", + "rxjs": "^5.5.0 || ^6.5.0" } }, - "node_modules/@ngx-formly/ionic": { - "version": "6.3.5", - "resolved": "https://registry.npmjs.org/@ngx-formly/ionic/-/ionic-6.3.5.tgz", - "integrity": "sha512-WqcsG9YXr9PZdWOV+DVT++2cHrndMabRNlOOHx+VIf8QXQc1cyxq9UWW3CmBKw5lT1P2cy4cxxuKMk4EzNJV+Q==", + "node_modules/@ionic/angular": { + "version": "6.7.5", + "license": "MIT", "dependencies": { + "@ionic/core": "6.7.5", + "ionicons": "^6.1.3", + "jsonc-parser": "^3.0.0", "tslib": "^2.0.0" }, "peerDependencies": { - "@ionic/angular": "^6.0.0 || ^7.0.0", - "@ngx-formly/core": "6.3.5" + "@angular/core": ">=12.0.0", + "@angular/forms": ">=12.0.0", + "@angular/router": ">=12.0.0", + "rxjs": ">=6.6.0", + "zone.js": ">=0.11.0" } }, - "node_modules/@ngx-formly/schematics": { - "version": "6.3.0", + "node_modules/@ionic/angular-toolkit": { + "version": "11.0.1", + "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "^13.0.3", - "@angular-devkit/schematics": "^13.0.3", - "@schematics/angular": "^13.0.3" + "@angular-devkit/core": "^17.0.0", + "@angular-devkit/schematics": "^17.0.0", + "@schematics/angular": "^17.0.0" } }, - "node_modules/@ngx-formly/schematics/node_modules/@angular-devkit/core": { - "version": "13.3.11", + "node_modules/@ionic/angular-toolkit/node_modules/@angular-devkit/core": { + "version": "17.3.3", + "dev": true, "license": "MIT", "dependencies": { - "ajv": "8.9.0", + "ajv": "8.12.0", "ajv-formats": "2.1.1", - "fast-json-stable-stringify": "2.1.0", - "magic-string": "0.25.7", - "rxjs": "6.6.7", - "source-map": "0.7.3" + "jsonc-parser": "3.2.1", + "picomatch": "4.0.1", + "rxjs": "7.8.1", + "source-map": "0.7.4" }, "engines": { - "node": "^12.20.0 || ^14.15.0 || >=16.10.0", + "node": "^18.13.0 || >=20.9.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" }, @@ -3417,879 +3562,2493 @@ } } }, - "node_modules/@ngx-formly/schematics/node_modules/@angular-devkit/schematics": { - "version": "13.3.11", + "node_modules/@ionic/angular-toolkit/node_modules/@angular-devkit/schematics": { + "version": "17.3.3", + "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "13.3.11", - "jsonc-parser": "3.0.0", - "magic-string": "0.25.7", + "@angular-devkit/core": "17.3.3", + "jsonc-parser": "3.2.1", + "magic-string": "0.30.8", "ora": "5.4.1", - "rxjs": "6.6.7" + "rxjs": "7.8.1" }, "engines": { - "node": "^12.20.0 || ^14.15.0 || >=16.10.0", + "node": "^18.13.0 || >=20.9.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" } }, - "node_modules/@ngx-formly/schematics/node_modules/@schematics/angular": { - "version": "13.3.11", + "node_modules/@ionic/angular-toolkit/node_modules/@schematics/angular": { + "version": "17.3.3", + "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "13.3.11", - "@angular-devkit/schematics": "13.3.11", - "jsonc-parser": "3.0.0" + "@angular-devkit/core": "17.3.3", + "@angular-devkit/schematics": "17.3.3", + "jsonc-parser": "3.2.1" }, "engines": { - "node": "^12.20.0 || ^14.15.0 || >=16.10.0", + "node": "^18.13.0 || >=20.9.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" } }, - "node_modules/@ngx-formly/schematics/node_modules/ajv": { - "version": "8.9.0", + "node_modules/@ionic/angular-toolkit/node_modules/magic-string": { + "version": "0.30.8", + "dev": true, "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "@jridgewell/sourcemap-codec": "^1.4.15" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "engines": { + "node": ">=12" } }, - "node_modules/@ngx-formly/schematics/node_modules/jsonc-parser": { - "version": "3.0.0", - "license": "MIT" - }, - "node_modules/@ngx-formly/schematics/node_modules/magic-string": { - "version": "0.25.7", + "node_modules/@ionic/angular-toolkit/node_modules/picomatch": { + "version": "4.0.1", + "dev": true, "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@ionic/angular-toolkit/node_modules/rxjs": { + "version": "7.8.1", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "sourcemap-codec": "^1.4.4" + "tslib": "^2.1.0" } }, - "node_modules/@ngx-formly/schematics/node_modules/source-map": { - "version": "0.7.3", - "license": "BSD-3-Clause", + "node_modules/@ionic/cli": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@ionic/cli/-/cli-7.2.0.tgz", + "integrity": "sha512-IEms9Df8mJOoWPqgvZEXmqKztttHDFAz+9ewDPZGYv8Xx66Cj7zSen13O2Vf4FuLXhl+U95HXT9sAs4lDwFmcQ==", + "license": "MIT", + "dependencies": { + "@ionic/cli-framework": "6.0.1", + "@ionic/cli-framework-output": "2.2.8", + "@ionic/cli-framework-prompts": "2.1.13", + "@ionic/utils-array": "2.1.6", + "@ionic/utils-fs": "3.1.7", + "@ionic/utils-network": "2.1.7", + "@ionic/utils-process": "2.1.12", + "@ionic/utils-stream": "3.1.7", + "@ionic/utils-subprocess": "3.0.1", + "@ionic/utils-terminal": "2.3.5", + "chalk": "^4.0.0", + "debug": "^4.0.0", + "diff": "^4.0.1", + "elementtree": "^0.1.7", + "leek": "0.0.24", + "lodash": "^4.17.5", + "open": "^7.0.4", + "os-name": "^4.0.0", + "proxy-agent": "^6.3.0", + "semver": "^7.1.1", + "split2": "^3.0.0", + "ssh-config": "^1.1.1", + "stream-combiner2": "^1.1.1", + "superagent": "^8.0.9", + "tar": "^6.0.1", + "tslib": "^2.0.1" + }, + "bin": { + "ionic": "bin/ionic" + }, "engines": { - "node": ">= 8" + "node": ">=16.0.0" } }, - "node_modules/@ngx-translate/core": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-15.0.0.tgz", - "integrity": "sha512-Am5uiuR0bOOxyoercDnAA3rJVizo4RRqJHo8N3RqJ+XfzVP/I845yEnMADykOHvM6HkVm4SZSnJBOiz0Anx5BA==", - "engines": { - "node": "^16.13.0 || >=18.10.0" + "node_modules/@ionic/cli-framework": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@ionic/cli-framework/-/cli-framework-6.0.1.tgz", + "integrity": "sha512-Fyix4eQt2HKTV+GoeoiziQGZyqIA8RfoMqjGyAS5XgNXLOYW0P27Ph348hQZh9Mphjf+m0lOYa6dWQTEPzUHiQ==", + "license": "MIT", + "dependencies": { + "@ionic/cli-framework-output": "2.2.8", + "@ionic/utils-array": "2.1.6", + "@ionic/utils-fs": "3.1.7", + "@ionic/utils-object": "2.1.6", + "@ionic/utils-process": "2.1.12", + "@ionic/utils-stream": "3.1.7", + "@ionic/utils-subprocess": "3.0.1", + "@ionic/utils-terminal": "2.3.5", + "chalk": "^4.0.0", + "debug": "^4.0.0", + "lodash": "^4.17.5", + "minimist": "^1.2.0", + "rimraf": "^3.0.0", + "tslib": "^2.0.1", + "write-file-atomic": "^3.0.0" }, - "peerDependencies": { - "@angular/common": ">=16.0.0", - "@angular/core": ">=16.0.0", - "rxjs": "^6.5.5 || ^7.4.0" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "dev": true, + "node_modules/@ionic/cli-framework-output": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/@ionic/cli-framework-output/-/cli-framework-output-2.2.8.tgz", + "integrity": "sha512-TshtaFQsovB4NWRBydbNFawql6yul7d5bMiW1WYYf17hd99V6xdDdk3vtF51bw6sLkxON3bDQpWsnUc9/hVo3g==", "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "@ionic/utils-terminal": "2.3.5", + "debug": "^4.0.0", + "tslib": "^2.0.1" }, "engines": { - "node": ">= 8" + "node": ">=16.0.0" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "dev": true, + "node_modules/@ionic/cli-framework-prompts": { + "version": "2.1.13", + "resolved": "https://registry.npmjs.org/@ionic/cli-framework-prompts/-/cli-framework-prompts-2.1.13.tgz", + "integrity": "sha512-Yj1fz6p7OehreQ8C70bd9+M6tYP/rvzLw5JVj8pT/N9s0kQSjqEFRbs96LKr3lfd3TADZaS8OlZrQIqenFIUpg==", "license": "MIT", + "dependencies": { + "@ionic/utils-terminal": "2.3.5", + "debug": "^4.0.0", + "inquirer": "^7.0.0", + "tslib": "^2.0.1" + }, "engines": { - "node": ">= 8" + "node": ">=16.0.0" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "dev": true, + "node_modules/@ionic/cli-framework-prompts/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "license": "MIT", "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">= 8" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@nodro7/angular-mydatepicker": { - "version": "0.14.0", + "node_modules/@ionic/cli-framework-prompts/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "license": "MIT", "dependencies": { - "tslib": "^2.0.0" - } - }, - "node_modules/@npmcli/fs": { - "version": "3.1.0", - "dev": true, - "license": "ISC", - "dependencies": { - "semver": "^7.3.5" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@npmcli/git": { - "version": "4.1.0", - "dev": true, - "license": "ISC", + "node_modules/@ionic/cli-framework-prompts/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", "dependencies": { - "@npmcli/promise-spawn": "^6.0.0", - "lru-cache": "^7.4.4", - "npm-pick-manifest": "^8.0.0", - "proc-log": "^3.0.0", - "promise-inflight": "^1.0.1", - "promise-retry": "^2.0.1", - "semver": "^7.3.5", - "which": "^3.0.0" + "color-name": "~1.1.4" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=7.0.0" } }, - "node_modules/@npmcli/git/node_modules/lru-cache": { - "version": "7.18.3", - "dev": true, - "license": "ISC", + "node_modules/@ionic/cli-framework-prompts/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=8" } }, - "node_modules/@npmcli/git/node_modules/which": { - "version": "3.0.1", - "dev": true, - "license": "ISC", + "node_modules/@ionic/cli-framework-prompts/node_modules/inquirer": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", + "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", + "license": "MIT", "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/which.js" + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.19", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.6.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=8.0.0" } }, - "node_modules/@npmcli/installed-package-contents": { - "version": "2.0.2", - "dev": true, - "license": "ISC", + "node_modules/@ionic/cli-framework-prompts/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", "dependencies": { - "npm-bundled": "^3.0.0", - "npm-normalize-package-bin": "^3.0.0" - }, - "bin": { - "installed-package-contents": "lib/index.js" + "has-flag": "^4.0.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=8" } }, - "node_modules/@npmcli/move-file": { - "version": "2.0.1", - "dev": true, + "node_modules/@ionic/cli-framework/node_modules/@ionic/utils-subprocess": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@ionic/utils-subprocess/-/utils-subprocess-3.0.1.tgz", + "integrity": "sha512-cT4te3AQQPeIM9WCwIg8ohroJ8TjsYaMb2G4ZEgv9YzeDqHZ4JpeIKqG2SoaA3GmVQ3sOfhPM6Ox9sxphV/d1A==", "license": "MIT", "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" + "@ionic/utils-array": "2.1.6", + "@ionic/utils-fs": "3.1.7", + "@ionic/utils-process": "2.1.12", + "@ionic/utils-stream": "3.1.7", + "@ionic/utils-terminal": "2.3.5", + "cross-spawn": "^7.0.3", + "debug": "^4.0.0", + "tslib": "^2.0.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/@npmcli/node-gyp": { - "version": "3.0.0", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=16.0.0" } }, - "node_modules/@npmcli/promise-spawn": { - "version": "6.0.2", - "dev": true, - "license": "ISC", + "node_modules/@ionic/cli-framework/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", "dependencies": { - "which": "^3.0.0" + "color-convert": "^2.0.1" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/promise-spawn/node_modules/which": { - "version": "3.0.1", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/which.js" + "node": ">=8" }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@npmcli/run-script": { - "version": "6.0.2", - "dev": true, - "license": "ISC", + "node_modules/@ionic/cli-framework/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", "dependencies": { - "@npmcli/node-gyp": "^3.0.0", - "@npmcli/promise-spawn": "^6.0.0", - "node-gyp": "^9.0.0", - "read-package-json-fast": "^3.0.0", - "which": "^3.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@npmcli/run-script/node_modules/which": { - "version": "3.0.1", - "dev": true, - "license": "ISC", + "node_modules/@ionic/cli-framework/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/which.js" + "color-name": "~1.1.4" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=7.0.0" } }, - "node_modules/@nrwl/devkit": { - "version": "16.5.1", - "dev": true, + "node_modules/@ionic/cli-framework/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "license": "MIT", - "dependencies": { - "@nx/devkit": "16.5.1" + "engines": { + "node": ">=8" } }, - "node_modules/@nrwl/tao": { - "version": "16.5.1", - "dev": true, + "node_modules/@ionic/cli-framework/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "license": "MIT", "dependencies": { - "nx": "16.5.1" + "has-flag": "^4.0.0" }, - "bin": { - "tao": "index.js" + "engines": { + "node": ">=8" } }, - "node_modules/@nx/devkit": { - "version": "16.5.1", - "dev": true, + "node_modules/@ionic/cli/node_modules/@ionic/utils-subprocess": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@ionic/utils-subprocess/-/utils-subprocess-3.0.1.tgz", + "integrity": "sha512-cT4te3AQQPeIM9WCwIg8ohroJ8TjsYaMb2G4ZEgv9YzeDqHZ4JpeIKqG2SoaA3GmVQ3sOfhPM6Ox9sxphV/d1A==", "license": "MIT", "dependencies": { - "@nrwl/devkit": "16.5.1", - "ejs": "^3.1.7", - "ignore": "^5.0.4", - "semver": "7.5.3", - "tmp": "~0.2.1", - "tslib": "^2.3.0" + "@ionic/utils-array": "2.1.6", + "@ionic/utils-fs": "3.1.7", + "@ionic/utils-process": "2.1.12", + "@ionic/utils-stream": "3.1.7", + "@ionic/utils-terminal": "2.3.5", + "cross-spawn": "^7.0.3", + "debug": "^4.0.0", + "tslib": "^2.0.1" }, - "peerDependencies": { - "nx": ">= 15 <= 17" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@nx/devkit/node_modules/lru-cache": { - "version": "6.0.0", - "dev": true, - "license": "ISC", + "node_modules/@ionic/cli/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@nx/devkit/node_modules/semver": { - "version": "7.5.3", - "dev": true, - "license": "ISC", + "node_modules/@ionic/cli/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@nx/devkit/node_modules/tmp": { - "version": "0.2.3", - "dev": true, + "node_modules/@ionic/cli/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, "engines": { - "node": ">=14.14" + "node": ">=7.0.0" } }, - "node_modules/@nx/devkit/node_modules/yallist": { + "node_modules/@ionic/cli/node_modules/has-flag": { "version": "4.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/@nx/nx-linux-x64-gnu": { - "version": "16.5.1", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nx/nx-linux-x64-musl": { - "version": "16.5.1", - "cpu": [ - "x64" - ], - "dev": true, + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">= 10" + "node": ">=8" } }, - "node_modules/@parcel/watcher": { - "version": "2.0.4", - "dev": true, - "hasInstallScript": true, + "node_modules/@ionic/cli/node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", "license": "MIT", "dependencies": { - "node-addon-api": "^3.2.1", - "node-gyp-build": "^4.3.0" + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" }, "engines": { - "node": ">= 10.0.0" + "node": ">=8" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "dev": true, + "node_modules/@ionic/cli/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "license": "MIT", - "optional": true, + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": ">=14" + "node": ">=8" } }, - "node_modules/@schematics/angular": { - "version": "16.2.13", - "dev": true, + "node_modules/@ionic/core": { + "version": "6.7.5", "license": "MIT", "dependencies": { - "@angular-devkit/core": "16.2.13", - "@angular-devkit/schematics": "16.2.13", - "jsonc-parser": "3.2.0" + "@stencil/core": "^2.18.0", + "ionicons": "^6.1.3", + "tslib": "^2.1.0" + } + }, + "node_modules/@ionic/utils-array": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@ionic/utils-array/-/utils-array-2.1.6.tgz", + "integrity": "sha512-0JZ1Zkp3wURnv8oq6Qt7fMPo5MpjbLoUoa9Bu2Q4PJuSDWM8H8gwF3dQO7VTeUj3/0o1IB1wGkFWZZYgUXZMUg==", + "license": "MIT", + "dependencies": { + "debug": "^4.0.0", + "tslib": "^2.0.1" }, "engines": { - "node": "^16.14.0 || >=18.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" + "node": ">=16.0.0" } }, - "node_modules/@schematics/angular/node_modules/jsonc-parser": { - "version": "3.2.0", - "dev": true, - "license": "MIT" - }, - "node_modules/@sigstore/bundle": { - "version": "1.1.0", - "dev": true, - "license": "Apache-2.0", + "node_modules/@ionic/utils-fs": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@ionic/utils-fs/-/utils-fs-3.1.7.tgz", + "integrity": "sha512-2EknRvMVfhnyhL1VhFkSLa5gOcycK91VnjfrTB0kbqkTFCOXyXgVLI5whzq7SLrgD9t1aqos3lMMQyVzaQ5gVA==", + "license": "MIT", "dependencies": { - "@sigstore/protobuf-specs": "^0.2.0" + "@types/fs-extra": "^8.0.0", + "debug": "^4.0.0", + "fs-extra": "^9.0.0", + "tslib": "^2.0.1" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=16.0.0" } }, - "node_modules/@sigstore/protobuf-specs": { - "version": "0.2.1", - "dev": true, - "license": "Apache-2.0", + "node_modules/@ionic/utils-fs/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=10" } }, - "node_modules/@sigstore/sign": { - "version": "1.0.0", - "dev": true, - "license": "Apache-2.0", + "node_modules/@ionic/utils-fs/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "license": "MIT", "dependencies": { - "@sigstore/bundle": "^1.1.0", - "@sigstore/protobuf-specs": "^0.2.0", - "make-fetch-happen": "^11.0.1" + "universalify": "^2.0.0" }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "optionalDependencies": { + "graceful-fs": "^4.1.6" } }, - "node_modules/@sigstore/sign/node_modules/@tootallnate/once": { - "version": "2.0.0", - "dev": true, + "node_modules/@ionic/utils-fs/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "license": "MIT", "engines": { - "node": ">= 10" + "node": ">= 10.0.0" } }, - "node_modules/@sigstore/sign/node_modules/http-proxy-agent": { - "version": "5.0.0", - "dev": true, + "node_modules/@ionic/utils-network": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@ionic/utils-network/-/utils-network-2.1.7.tgz", + "integrity": "sha512-5Q3NdZtSLiLs7ufuX9X293BvAwo8CxaD93Hkp3ODPgctLYErv3nFibhq3j+eguEqUh2um9WNXEUOuQ8x+Sd1fw==", "license": "MIT", "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" + "debug": "^4.0.0", + "tslib": "^2.0.1" }, "engines": { - "node": ">= 6" + "node": ">=16.0.0" } }, - "node_modules/@sigstore/sign/node_modules/lru-cache": { - "version": "7.18.3", - "dev": true, - "license": "ISC", + "node_modules/@ionic/utils-object": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@ionic/utils-object/-/utils-object-2.1.6.tgz", + "integrity": "sha512-vCl7sl6JjBHFw99CuAqHljYJpcE88YaH2ZW4ELiC/Zwxl5tiwn4kbdP/gxi2OT3MQb1vOtgAmSNRtusvgxI8ww==", + "license": "MIT", + "dependencies": { + "debug": "^4.0.0", + "tslib": "^2.0.1" + }, "engines": { - "node": ">=12" + "node": ">=16.0.0" } }, - "node_modules/@sigstore/sign/node_modules/make-fetch-happen": { - "version": "11.1.1", - "dev": true, - "license": "ISC", + "node_modules/@ionic/utils-process": { + "version": "2.1.12", + "resolved": "https://registry.npmjs.org/@ionic/utils-process/-/utils-process-2.1.12.tgz", + "integrity": "sha512-Jqkgyq7zBs/v/J3YvKtQQiIcxfJyplPgECMWgdO0E1fKrrH8EF0QGHNJ9mJCn6PYe2UtHNS8JJf5G21e09DfYg==", + "license": "MIT", "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^17.0.0", - "http-cache-semantics": "^4.1.1", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^5.0.0", - "minipass-fetch": "^3.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^10.0.0" + "@ionic/utils-object": "2.1.6", + "@ionic/utils-terminal": "2.3.5", + "debug": "^4.0.0", + "signal-exit": "^3.0.3", + "tree-kill": "^1.2.2", + "tslib": "^2.0.1" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=16.0.0" } }, - "node_modules/@sigstore/sign/node_modules/minipass-fetch": { - "version": "3.0.4", - "dev": true, + "node_modules/@ionic/utils-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@ionic/utils-stream/-/utils-stream-3.1.7.tgz", + "integrity": "sha512-eSELBE7NWNFIHTbTC2jiMvh1ABKGIpGdUIvARsNPMNQhxJB3wpwdiVnoBoTYp+5a6UUIww4Kpg7v6S7iTctH1w==", "license": "MIT", "dependencies": { - "minipass": "^7.0.3", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" + "debug": "^4.0.0", + "tslib": "^2.0.1" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" + "node": ">=16.0.0" } }, - "node_modules/@sigstore/sign/node_modules/minipass-fetch/node_modules/minipass": { - "version": "7.0.4", + "node_modules/@ionic/utils-subprocess": { + "version": "2.1.14", + "resolved": "https://registry.npmjs.org/@ionic/utils-subprocess/-/utils-subprocess-2.1.14.tgz", + "integrity": "sha512-nGYvyGVjU0kjPUcSRFr4ROTraT3w/7r502f5QJEsMRKTqa4eEzCshtwRk+/mpASm0kgBN5rrjYA5A/OZg8ahqg==", "dev": true, - "license": "ISC", + "license": "MIT", + "dependencies": { + "@ionic/utils-array": "2.1.6", + "@ionic/utils-fs": "3.1.7", + "@ionic/utils-process": "2.1.11", + "@ionic/utils-stream": "3.1.6", + "@ionic/utils-terminal": "2.3.4", + "cross-spawn": "^7.0.3", + "debug": "^4.0.0", + "tslib": "^2.0.1" + }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=16.0.0" } }, - "node_modules/@sigstore/tuf": { - "version": "1.0.3", + "node_modules/@ionic/utils-subprocess/node_modules/@ionic/utils-process": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/@ionic/utils-process/-/utils-process-2.1.11.tgz", + "integrity": "sha512-Uavxn+x8j3rDlZEk1X7YnaN6wCgbCwYQOeIjv/m94i1dzslqWhqIHEqxEyeE8HsT5Negboagg7GtQiABy+BLbA==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@sigstore/protobuf-specs": "^0.2.0", - "tuf-js": "^1.1.7" + "@ionic/utils-object": "2.1.6", + "@ionic/utils-terminal": "2.3.4", + "debug": "^4.0.0", + "signal-exit": "^3.0.3", + "tree-kill": "^1.2.2", + "tslib": "^2.0.1" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=16.0.0" } }, - "node_modules/@socket.io/component-emitter": { - "version": "3.1.0", + "node_modules/@ionic/utils-subprocess/node_modules/@ionic/utils-stream": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@ionic/utils-stream/-/utils-stream-3.1.6.tgz", + "integrity": "sha512-4+Kitey1lTA1yGtnigeYNhV/0tggI3lWBMjC7tBs1K9GXa/q7q4CtOISppdh8QgtOhrhAXS2Igp8rbko/Cj+lA==", "dev": true, - "license": "MIT" - }, - "node_modules/@stencil/core": { - "version": "2.22.3", "license": "MIT", - "bin": { - "stencil": "bin/stencil" + "dependencies": { + "debug": "^4.0.0", + "tslib": "^2.0.1" }, "engines": { - "node": ">=12.10.0", - "npm": ">=6.0.0" + "node": ">=16.0.0" } }, - "node_modules/@stylistic/eslint-plugin": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.2.2.tgz", - "integrity": "sha512-GNRtyhhPsc9I9FNTaU2L0V/4LdSPAciQNEdYo6NBRdAz7sdiaxgEJKLNSXeXSQAuO9JBWWjZBs/57+WvrU0Iug==", + "node_modules/@ionic/utils-subprocess/node_modules/@ionic/utils-terminal": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@ionic/utils-terminal/-/utils-terminal-2.3.4.tgz", + "integrity": "sha512-cEiMFl3jklE0sW60r8JHH3ijFTwh/jkdEKWbylSyExQwZ8pPuwoXz7gpkWoJRLuoRHHSvg+wzNYyPJazIHfoJA==", "dev": true, + "license": "MIT", "dependencies": { - "@stylistic/eslint-plugin-js": "2.2.2", - "@stylistic/eslint-plugin-jsx": "2.2.2", - "@stylistic/eslint-plugin-plus": "2.2.2", - "@stylistic/eslint-plugin-ts": "2.2.2", - "@types/eslint": "^8.56.10" + "@types/slice-ansi": "^4.0.0", + "debug": "^4.0.0", + "signal-exit": "^3.0.3", + "slice-ansi": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "tslib": "^2.0.1", + "untildify": "^4.0.0", + "wrap-ansi": "^7.0.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=16.0.0" + } + }, + "node_modules/@ionic/utils-terminal": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@ionic/utils-terminal/-/utils-terminal-2.3.5.tgz", + "integrity": "sha512-3cKScz9Jx2/Pr9ijj1OzGlBDfcmx7OMVBt4+P1uRR0SSW4cm1/y3Mo4OY3lfkuaYifMNBW8Wz6lQHbs1bihr7A==", + "license": "MIT", + "dependencies": { + "@types/slice-ansi": "^4.0.0", + "debug": "^4.0.0", + "signal-exit": "^3.0.3", + "slice-ansi": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "tslib": "^2.0.1", + "untildify": "^4.0.0", + "wrap-ansi": "^7.0.0" }, - "peerDependencies": { - "eslint": ">=8.40.0" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@stylistic/eslint-plugin-js": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.2.2.tgz", - "integrity": "sha512-Vj2Q1YHVvJw+ThtOvmk5Yx7wZanVrIBRUTT89horLDb4xdP9GA1um9XOYQC6j67VeUC2gjZQnz5/RVJMzaOhtw==", + "node_modules/@isaacs/cliui": { + "version": "8.0.2", "dev": true, + "license": "ISC", "dependencies": { - "@types/eslint": "^8.56.10", - "acorn": "^8.11.3", - "eslint-visitor-keys": "^4.0.0", - "espree": "^10.0.1" + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "peerDependencies": { - "eslint": ">=8.40.0" + "node": ">=12" } }, - "node_modules/@stylistic/eslint-plugin-js/node_modules/eslint-visitor-keys": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", - "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", "dev": true, + "license": "MIT", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=12" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/@stylistic/eslint-plugin-js/node_modules/espree": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", - "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", "dev": true, - "dependencies": { - "acorn": "^8.12.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.0.0" - }, + "license": "MIT", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=12" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@stylistic/eslint-plugin-jsx": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-jsx/-/eslint-plugin-jsx-2.2.2.tgz", - "integrity": "sha512-xfIMdLivoMV1wV+5Tl0PtkLN/oUwjIt7LuIu48vhrZfJ2jCXwjlTGPGSoM7dnLZYD65XjtrHHIFAvPuvvvjlaw==", + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", "dev": true, + "license": "MIT", "dependencies": { - "@stylistic/eslint-plugin-js": "^2.2.2", - "@types/eslint": "^8.56.10", - "estraverse": "^5.3.0", - "picomatch": "^4.0.2" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=12" }, - "peerDependencies": { - "eslint": ">=8.40.0" - } - }, - "node_modules/@stylistic/eslint-plugin-jsx/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@stylistic/eslint-plugin-jsx/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, "engines": { "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/@stylistic/eslint-plugin-plus": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-2.2.2.tgz", - "integrity": "sha512-oeqPs01yAH4ad4bSchGtx8Jf5XTbxRx++A0joNYiOoq3EBTAUHE/ZB7dVv3BhNuCKiwojOQduLkUCXI5UMHoSw==", + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", "dev": true, + "license": "MIT", "dependencies": { - "@types/eslint": "^8.56.10", - "@typescript-eslint/utils": "^7.12.0" + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" }, - "peerDependencies": { - "eslint": "*" + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/scope-manager": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.14.1.tgz", - "integrity": "sha512-gPrFSsoYcsffYXTOZ+hT7fyJr95rdVe4kGVX1ps/dJ+DfmlnjFN/GcMxXcVkeHDKqsq6uAcVaQaIi3cFffmAbA==", + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", "dev": true, + "license": "ISC", "dependencies": { - "@typescript-eslint/types": "7.14.1", - "@typescript-eslint/visitor-keys": "7.14.1" + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@kurkle/color": { + "version": "0.3.2", + "license": "MIT" + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@ngtools/webpack": { + "version": "16.2.14", + "dev": true, + "license": "MIT", + "engines": { + "node": "^16.14.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "@angular/compiler-cli": "^16.0.0", + "typescript": ">=4.9.3 <5.2", + "webpack": "^5.54.0" + } + }, + "node_modules/@ngx-formly/core": { + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/@ngx-formly/core/-/core-6.3.5.tgz", + "integrity": "sha512-9p4yl7fr2Ojmm/uN7/nM1hYezheUxecEC0WZ0YI6jeSoEJR8NYTglVxTmHrpW5had2oolHeO39sAo9ttJNifSA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/forms": ">=13.2.0", + "rxjs": "^6.5.3 || ^7.0.0" + } + }, + "node_modules/@ngx-formly/ionic": { + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/@ngx-formly/ionic/-/ionic-6.3.5.tgz", + "integrity": "sha512-WqcsG9YXr9PZdWOV+DVT++2cHrndMabRNlOOHx+VIf8QXQc1cyxq9UWW3CmBKw5lT1P2cy4cxxuKMk4EzNJV+Q==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@ionic/angular": "^6.0.0 || ^7.0.0", + "@ngx-formly/core": "6.3.5" + } + }, + "node_modules/@ngx-formly/schematics": { + "version": "6.3.0", + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "^13.0.3", + "@angular-devkit/schematics": "^13.0.3", + "@schematics/angular": "^13.0.3" + } + }, + "node_modules/@ngx-formly/schematics/node_modules/@angular-devkit/core": { + "version": "13.3.11", + "license": "MIT", + "dependencies": { + "ajv": "8.9.0", + "ajv-formats": "2.1.1", + "fast-json-stable-stringify": "2.1.0", + "magic-string": "0.25.7", + "rxjs": "6.6.7", + "source-map": "0.7.3" + }, + "engines": { + "node": "^12.20.0 || ^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@ngx-formly/schematics/node_modules/@angular-devkit/schematics": { + "version": "13.3.11", + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "13.3.11", + "jsonc-parser": "3.0.0", + "magic-string": "0.25.7", + "ora": "5.4.1", + "rxjs": "6.6.7" + }, + "engines": { + "node": "^12.20.0 || ^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@ngx-formly/schematics/node_modules/@schematics/angular": { + "version": "13.3.11", + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "13.3.11", + "@angular-devkit/schematics": "13.3.11", + "jsonc-parser": "3.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@ngx-formly/schematics/node_modules/ajv": { + "version": "8.9.0", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/types": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.14.1.tgz", - "integrity": "sha512-mL7zNEOQybo5R3AavY+Am7KLv8BorIv7HCYS5rKoNZKQD9tsfGUpO4KdAn3sSUvTiS4PQkr2+K0KJbxj8H9NDg==", + "node_modules/@ngx-formly/schematics/node_modules/jsonc-parser": { + "version": "3.0.0", + "license": "MIT" + }, + "node_modules/@ngx-formly/schematics/node_modules/magic-string": { + "version": "0.25.7", + "license": "MIT", + "dependencies": { + "sourcemap-codec": "^1.4.4" + } + }, + "node_modules/@ngx-formly/schematics/node_modules/source-map": { + "version": "0.7.3", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@ngx-translate/core": { + "version": "15.0.0", + "license": "SEE LICENSE IN LICENSE", + "engines": { + "node": "^16.13.0 || >=18.10.0" + }, + "peerDependencies": { + "@angular/common": ">=16.0.0", + "@angular/core": ">=16.0.0", + "rxjs": "^6.5.5 || ^7.4.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodro7/angular-mydatepicker": { + "version": "0.14.0", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + } + }, + "node_modules/@npmcli/fs": { + "version": "3.1.0", + "dev": true, + "license": "ISC", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git": { + "version": "4.1.0", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/promise-spawn": "^6.0.0", + "lru-cache": "^7.4.4", + "npm-pick-manifest": "^8.0.0", + "proc-log": "^3.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git/node_modules/lru-cache": { + "version": "7.18.3", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/@npmcli/git/node_modules/which": { + "version": "3.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/installed-package-contents": { + "version": "2.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "bin": { + "installed-package-contents": "lib/index.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/move-file": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/node-gyp": { + "version": "3.0.0", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/promise-spawn": { + "version": "6.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/which": { + "version": "3.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script": { + "version": "6.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/promise-spawn": "^6.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^3.0.0", + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script/node_modules/which": { + "version": "3.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@nrwl/devkit": { + "version": "16.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@nx/devkit": "16.5.1" + } + }, + "node_modules/@nrwl/tao": { + "version": "16.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "nx": "16.5.1" + }, + "bin": { + "tao": "index.js" + } + }, + "node_modules/@nx/devkit": { + "version": "16.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@nrwl/devkit": "16.5.1", + "ejs": "^3.1.7", + "ignore": "^5.0.4", + "semver": "7.5.3", + "tmp": "~0.2.1", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "nx": ">= 15 <= 17" + } + }, + "node_modules/@nx/devkit/node_modules/lru-cache": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@nx/devkit/node_modules/semver": { + "version": "7.5.3", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@nx/devkit/node_modules/tmp": { + "version": "0.2.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@nx/devkit/node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/@parcel/watcher": { + "version": "2.0.4", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^3.2.1", + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@prettier/plugin-xml": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@prettier/plugin-xml/-/plugin-xml-2.2.0.tgz", + "integrity": "sha512-UWRmygBsyj4bVXvDiqSccwT1kmsorcwQwaIy30yVh8T+Gspx4OlC0shX1y+ZuwXZvgnafmpRYKks0bAu9urJew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xml-tools/parser": "^1.0.11", + "prettier": ">=2.4.0" + } + }, + "node_modules/@schematics/angular": { + "version": "16.2.13", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "16.2.13", + "@angular-devkit/schematics": "16.2.13", + "jsonc-parser": "3.2.0" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@schematics/angular/node_modules/jsonc-parser": { + "version": "3.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@sigstore/bundle": { + "version": "1.1.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.2.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/protobuf-specs": { + "version": "0.2.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/sign": { + "version": "1.0.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^1.1.0", + "@sigstore/protobuf-specs": "^0.2.0", + "make-fetch-happen": "^11.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/sign/node_modules/@tootallnate/once": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@sigstore/sign/node_modules/http-proxy-agent": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@sigstore/sign/node_modules/lru-cache": { + "version": "7.18.3", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/@sigstore/sign/node_modules/make-fetch-happen": { + "version": "11.1.1", + "dev": true, + "license": "ISC", + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^5.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/sign/node_modules/minipass-fetch": { + "version": "3.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/@sigstore/sign/node_modules/minipass-fetch/node_modules/minipass": { + "version": "7.0.4", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/@sigstore/tuf": { + "version": "1.0.3", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.2.0", + "tuf-js": "^1.1.7" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@stencil/core": { + "version": "2.22.3", + "license": "MIT", + "bin": { + "stencil": "bin/stencil" + }, + "engines": { + "node": ">=12.10.0", + "npm": ">=6.0.0" + } + }, + "node_modules/@stylistic/eslint-plugin": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.3.0.tgz", + "integrity": "sha512-rtiz6u5gRyyEZp36FcF1/gHJbsbT3qAgXZ1qkad6Nr/xJ9wrSJkiSFFQhpYVTIZ7FJNRJurEcumZDCwN9dEI4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@stylistic/eslint-plugin-js": "2.3.0", + "@stylistic/eslint-plugin-jsx": "2.3.0", + "@stylistic/eslint-plugin-plus": "2.3.0", + "@stylistic/eslint-plugin-ts": "2.3.0", + "@types/eslint": "^8.56.10" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-js": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.3.0.tgz", + "integrity": "sha512-lQwoiYb0Fs6Yc5QS3uT8+T9CPKK2Eoxc3H8EnYJgM26v/DgtW+1lvy2WNgyBflU+ThShZaHm3a6CdD9QeKx23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint": "^8.56.10", + "acorn": "^8.11.3", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-js/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-js/node_modules/espree": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-jsx": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-jsx/-/eslint-plugin-jsx-2.3.0.tgz", + "integrity": "sha512-tsQ0IEKB195H6X9A4iUSgLLLKBc8gUBWkBIU8tp1/3g2l8stu+PtMQVV/VmK1+3bem5FJCyvfcZIQ/WF1fsizA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@stylistic/eslint-plugin-js": "^2.3.0", + "@types/eslint": "^8.56.10", + "estraverse": "^5.3.0", + "picomatch": "^4.0.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-jsx/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@stylistic/eslint-plugin-jsx/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@stylistic/eslint-plugin-plus": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-2.3.0.tgz", + "integrity": "sha512-xboPWGUU5yaPlR+WR57GwXEuY4PSlPqA0C3IdNA/+1o2MuBi95XgDJcZiJ9N+aXsqBXAPIpFFb+WQ7QEHo4f7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint": "^8.56.10", + "@typescript-eslint/utils": "^7.12.0" + }, + "peerDependencies": { + "eslint": "*" + } + }, + "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/scope-manager": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.14.1.tgz", + "integrity": "sha512-gPrFSsoYcsffYXTOZ+hT7fyJr95rdVe4kGVX1ps/dJ+DfmlnjFN/GcMxXcVkeHDKqsq6uAcVaQaIi3cFffmAbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/visitor-keys": "7.14.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/types": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.14.1.tgz", + "integrity": "sha512-mL7zNEOQybo5R3AavY+Am7KLv8BorIv7HCYS5rKoNZKQD9tsfGUpO4KdAn3sSUvTiS4PQkr2+K0KJbxj8H9NDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.14.1.tgz", + "integrity": "sha512-k5d0VuxViE2ulIO6FbxxSZaxqDVUyMbXcidC8rHvii0I56XZPv8cq+EhMns+d/EVIL41sMXqRbK3D10Oza1bbA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/visitor-keys": "7.14.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/utils": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.14.1.tgz", + "integrity": "sha512-CMmVVELns3nak3cpJhZosDkm63n+DwBlDX8g0k4QUa9BMnF+lH2lr3d130M1Zt1xxmB3LLk3NV7KQCq86ZBBhQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.14.1", + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/typescript-estree": "7.14.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.14.1.tgz", + "integrity": "sha512-Crb+F75U1JAEtBeQGxSKwI60hZmmzaqA3z9sYsVm8X7W5cwLEm5bRe0/uXS6+MR/y8CVpKSR/ontIAIEPFcEkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.14.1", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-plus/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@stylistic/eslint-plugin-plus/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@stylistic/eslint-plugin-plus/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@stylistic/eslint-plugin-plus/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@stylistic/eslint-plugin-ts": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-ts/-/eslint-plugin-ts-2.3.0.tgz", + "integrity": "sha512-wqOR38/uz/0XPnHX68ftp8sNMSAqnYGjovOTN7w00xnjS6Lxr3Sk7q6AaxWWqbMvOj7V2fQiMC5HWAbTruJsCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@stylistic/eslint-plugin-js": "2.3.0", + "@types/eslint": "^8.56.10", + "@typescript-eslint/utils": "^7.12.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/scope-manager": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.14.1.tgz", + "integrity": "sha512-gPrFSsoYcsffYXTOZ+hT7fyJr95rdVe4kGVX1ps/dJ+DfmlnjFN/GcMxXcVkeHDKqsq6uAcVaQaIi3cFffmAbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/visitor-keys": "7.14.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/types": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.14.1.tgz", + "integrity": "sha512-mL7zNEOQybo5R3AavY+Am7KLv8BorIv7HCYS5rKoNZKQD9tsfGUpO4KdAn3sSUvTiS4PQkr2+K0KJbxj8H9NDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.14.1.tgz", + "integrity": "sha512-k5d0VuxViE2ulIO6FbxxSZaxqDVUyMbXcidC8rHvii0I56XZPv8cq+EhMns+d/EVIL41sMXqRbK3D10Oza1bbA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/visitor-keys": "7.14.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/utils": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.14.1.tgz", + "integrity": "sha512-CMmVVELns3nak3cpJhZosDkm63n+DwBlDX8g0k4QUa9BMnF+lH2lr3d130M1Zt1xxmB3LLk3NV7KQCq86ZBBhQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.14.1", + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/typescript-estree": "7.14.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.14.1.tgz", + "integrity": "sha512-Crb+F75U1JAEtBeQGxSKwI60hZmmzaqA3z9sYsVm8X7W5cwLEm5bRe0/uXS6+MR/y8CVpKSR/ontIAIEPFcEkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.14.1", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "license": "MIT" + }, + "node_modules/@trapezedev/gradle-parse": { + "version": "7.0.10", + "resolved": "https://registry.npmjs.org/@trapezedev/gradle-parse/-/gradle-parse-7.0.10.tgz", + "integrity": "sha512-k822Is3jGroqOTKF0gAFm80LmhFJWBAyZvNtyuXq6uQUzDDe2fj/gHwixP6VFzlpaWKLP7IuR609Xv8gwJCXyg==", + "dev": true, + "license": "SEE LICENSE" + }, + "node_modules/@trapezedev/project": { + "version": "7.0.10", + "resolved": "https://registry.npmjs.org/@trapezedev/project/-/project-7.0.10.tgz", + "integrity": "sha512-UjwsStjhHq/+D1bWREmFDoyKql+qFIgJX93zQLg7R6CyWZUdtlGP2hU3l7tsVRtjJBVXpVu5mj8tdwJJoABO3A==", + "dev": true, + "license": "SEE LICENSE", + "dependencies": { + "@ionic/utils-fs": "^3.1.5", + "@ionic/utils-subprocess": "^2.1.8", + "@prettier/plugin-xml": "^2.2.0", + "@trapezedev/gradle-parse": "7.0.10", + "@xmldom/xmldom": "^0.7.5", + "conventional-changelog": "^3.1.4", + "cross-fetch": "^3.1.5", + "cross-spawn": "^7.0.3", + "diff": "^5.1.0", + "env-paths": "^3.0.0", + "gradle-to-js": "^2.0.0", + "ini": "^2.0.0", + "kleur": "^4.1.5", + "lodash": "^4.17.21", + "mergexml": "^1.2.3", + "npm-watch": "^0.9.0", + "plist": "^3.0.4", + "prettier": "^2.7.1", + "prompts": "^2.4.2", + "replace": "^1.1.0", + "tempy": "^1.0.1", + "tmp": "^0.2.1", + "ts-node": "^10.2.1", + "xcode": "^3.0.1", + "xml-js": "^1.6.11", + "xpath": "^0.0.32", + "yargs": "^17.2.1" + } + }, + "node_modules/@trapezedev/project/node_modules/diff": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/@trapezedev/project/node_modules/env-paths": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", + "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@trapezedev/project/node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/@trapezedev/project/node_modules/tmp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@tufjs/canonical-json": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@tufjs/canonical-json": "1.0.0", + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models/node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@tufjs/models/node_modules/minimatch": { + "version": "9.0.4", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/cordova": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-11.0.3.tgz", + "integrity": "sha512-kyuRQ40/NWQVhqGIHq78Ehu2Bf9Mlg0LhmSmis6ZFJK7z933FRfYi8tHe/k/0fB+PGfCf95rJC6TO7dopaFvAg==", + "license": "MIT" + }, + "node_modules/@types/cors": { + "version": "2.8.17", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/eslint": { + "version": "8.56.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", + "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/express": { + "version": "4.17.21", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/fs-extra": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.5.tgz", + "integrity": "sha512-0dzKcwO+S8s2kuF5Z9oUWatQJj5Uq/iqphEtE3GQJVRRYm/tD1LglU2UnXi2A8jLq5umkGouOXOR9y0n613ZwQ==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/http-proxy": { + "version": "1.17.14", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/jasmine": { + "version": "4.3.6", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/jasminewd2": { + "version": "2.0.13", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/jasmine": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.12.7", + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/q": { + "version": "0.0.32", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/qs": { + "version": "6.9.15", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/selenium-webdriver": { + "version": "3.0.26", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/semver": { + "version": "7.5.8", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "0.17.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-+OpjSaq85gvlZAYINyzKpLeiFkSC4EsC6IIiT6v6TLSU5k5U83fHGj9Lel8oKEXM0HqgrMVCjXPDPVICtxF7EQ==", + "license": "MIT" + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ws": { + "version": "8.5.10", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.21.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/type-utils": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.14.1.tgz", - "integrity": "sha512-k5d0VuxViE2ulIO6FbxxSZaxqDVUyMbXcidC8rHvii0I56XZPv8cq+EhMns+d/EVIL41sMXqRbK3D10Oza1bbA==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { + "version": "6.21.0", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.14.1", - "@typescript-eslint/visitor-keys": "7.14.1", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/utils": "6.21.0", "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, "peerDependenciesMeta": { "typescript": { "optional": true } } }, - "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/utils": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.14.1.tgz", - "integrity": "sha512-CMmVVELns3nak3cpJhZosDkm63n+DwBlDX8g0k4QUa9BMnF+lH2lr3d130M1Zt1xxmB3LLk3NV7KQCq86ZBBhQ==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { + "version": "6.21.0", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.14.1", - "@typescript-eslint/types": "7.14.1", - "@typescript-eslint/typescript-estree": "7.14.1" + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "semver": "^7.5.4" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.56.0" + "eslint": "^7.0.0 || ^8.0.0" } }, - "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.14.1.tgz", - "integrity": "sha512-Crb+F75U1JAEtBeQGxSKwI60hZmmzaqA3z9sYsVm8X7W5cwLEm5bRe0/uXS6+MR/y8CVpKSR/ontIAIEPFcEkA==", + "node_modules/@typescript-eslint/parser": { + "version": "6.21.0", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "7.14.1", - "eslint-visitor-keys": "^3.4.3" + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@stylistic/eslint-plugin-plus/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@stylistic/eslint-plugin-plus/node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" }, - "engines": { - "node": ">=10" + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@stylistic/eslint-plugin-plus/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.21.0", "dev": true, + "license": "MIT", "dependencies": { - "brace-expansion": "^2.0.1" + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "^16.0.0 || >=18.0.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@stylistic/eslint-plugin-plus/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@stylistic/eslint-plugin-ts": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-ts/-/eslint-plugin-ts-2.2.2.tgz", - "integrity": "sha512-n6cYMSWTDDcrQLLxEKIrL/ihQ1lyyq6+gGp0g5VdstBElmImSRsQkCq+g3jRoDJIUo7tGO9lwQtGnuJ7oGB4kg==", - "dev": true, - "dependencies": { - "@stylistic/eslint-plugin-js": "2.2.2", - "@types/eslint": "^8.56.10", - "@typescript-eslint/utils": "^7.12.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "peerDependencies": { - "eslint": ">=8.40.0" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/scope-manager": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.14.1.tgz", - "integrity": "sha512-gPrFSsoYcsffYXTOZ+hT7fyJr95rdVe4kGVX1ps/dJ+DfmlnjFN/GcMxXcVkeHDKqsq6uAcVaQaIi3cFffmAbA==", + "node_modules/@typescript-eslint/type-utils": { + "version": "5.62.0", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.14.1", - "@typescript-eslint/visitor-keys": "7.14.1" + "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/types": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.14.1.tgz", - "integrity": "sha512-mL7zNEOQybo5R3AavY+Am7KLv8BorIv7HCYS5rKoNZKQD9tsfGUpO4KdAn3sSUvTiS4PQkr2+K0KJbxj8H9NDg==", + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { + "version": "5.62.0", "dev": true, + "license": "MIT", "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.14.1.tgz", - "integrity": "sha512-k5d0VuxViE2ulIO6FbxxSZaxqDVUyMbXcidC8rHvii0I56XZPv8cq+EhMns+d/EVIL41sMXqRbK3D10Oza1bbA==", + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "7.14.1", - "@typescript-eslint/visitor-keys": "7.14.1", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" + "semver": "^7.3.7", + "tsutils": "^3.21.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", @@ -4301,59 +6060,100 @@ } } }, - "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/utils": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.14.1.tgz", - "integrity": "sha512-CMmVVELns3nak3cpJhZosDkm63n+DwBlDX8g0k4QUa9BMnF+lH2lr3d130M1Zt1xxmB3LLk3NV7KQCq86ZBBhQ==", + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", "dev": true, + "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.14.1", - "@typescript-eslint/types": "7.14.1", - "@typescript-eslint/typescript-estree": "7.14.1" + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/globby": { + "version": "11.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" }, - "peerDependencies": { - "eslint": "^8.56.0" + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.14.1.tgz", - "integrity": "sha512-Crb+F75U1JAEtBeQGxSKwI60hZmmzaqA3z9sYsVm8X7W5cwLEm5bRe0/uXS6+MR/y8CVpKSR/ontIAIEPFcEkA==", + "node_modules/@typescript-eslint/type-utils/node_modules/slash": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.21.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.21.0", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "7.14.1", - "eslint-visitor-keys": "^3.4.3" + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@stylistic/eslint-plugin-ts/node_modules/brace-expansion": { + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, - "node_modules/@stylistic/eslint-plugin-ts/node_modules/globby": { + "node_modules/@typescript-eslint/typescript-estree/node_modules/globby": { "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, + "license": "MIT", "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -4369,11 +6169,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@stylistic/eslint-plugin-ts/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.3", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -4384,1566 +6183,1608 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@stylistic/eslint-plugin-ts/node_modules/slash": { + "node_modules/@typescript-eslint/typescript-estree/node_modules/slash": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", "dev": true, "license": "MIT", "engines": { - "node": ">= 6" + "node": ">=8" } }, - "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "dev": true, - "license": "MIT" - }, - "node_modules/@tufjs/canonical-json": { - "version": "1.0.0", + "node_modules/@typescript-eslint/utils": { + "version": "5.62.0", "dev": true, "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/@tufjs/models": { - "version": "1.0.4", + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", "dev": true, "license": "MIT", "dependencies": { - "@tufjs/canonical-json": "1.0.0", - "minimatch": "^9.0.0" + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@tufjs/models/node_modules/brace-expansion": { - "version": "2.0.1", + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { + "version": "5.62.0", "dev": true, "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@tufjs/models/node_modules/minimatch": { - "version": "9.0.4", + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", "dev": true, - "license": "ISC", + "license": "BSD-2-Clause", "dependencies": { - "brace-expansion": "^2.0.1" + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@types/body-parser": { - "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", - "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", - "dev": true, - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/bonjour": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", - "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/connect-history-api-fallback": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", - "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", - "dev": true, - "dependencies": { - "@types/express-serve-static-core": "*", - "@types/node": "*" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@types/cookie": { - "version": "0.4.1", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/cors": { - "version": "2.8.17", + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", "dev": true, "license": "MIT", "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/eslint": { - "version": "8.56.10", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", - "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", - "dev": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", + "node_modules/@typescript-eslint/utils/node_modules/globby": { + "version": "11.1.0", "dev": true, "license": "MIT", "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@types/estree": { - "version": "1.0.5", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/express": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", - "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "node_modules/@typescript-eslint/utils/node_modules/slash": { + "version": "3.0.0", "dev": true, - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/@types/express-serve-static-core": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz", - "integrity": "sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==", + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.21.0", "dev": true, + "license": "MIT", "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" + "@typescript-eslint/types": "6.21.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@types/http-errors": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", - "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true - }, - "node_modules/@types/http-proxy": { - "version": "1.17.14", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", - "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", - "dev": true, - "dependencies": { - "@types/node": "*" - } + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "dev": true, + "license": "ISC" }, - "node_modules/@types/jasmine": { - "version": "4.3.6", + "node_modules/@vitejs/plugin-basic-ssl": { + "version": "1.0.1", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=14.6.0" + }, + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0" + } }, - "node_modules/@types/jasminewd2": { - "version": "2.0.13", + "node_modules/@webassemblyjs/ast": { + "version": "1.12.1", "dev": true, "license": "MIT", "dependencies": { - "@types/jasmine": "*" + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" } }, - "node_modules/@types/json-schema": { - "version": "7.0.15", + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", "dev": true, "license": "MIT" }, - "node_modules/@types/json5": { - "version": "0.0.29", + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", "dev": true, "license": "MIT" }, - "node_modules/@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true - }, - "node_modules/@types/node": { - "version": "20.12.7", + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.12.1", "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~5.26.4" - } + "license": "MIT" }, - "node_modules/@types/node-forge": { - "version": "1.3.11", - "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", - "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", "dev": true, + "license": "MIT", "dependencies": { - "@types/node": "*" + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" } }, - "node_modules/@types/q": { - "version": "0.0.32", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/qs": { - "version": "6.9.15", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", - "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", - "dev": true - }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true - }, - "node_modules/@types/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", - "dev": true - }, - "node_modules/@types/selenium-webdriver": { - "version": "3.0.26", + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", "dev": true, "license": "MIT" }, - "node_modules/@types/semver": { - "version": "7.5.8", + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.12.1", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" + } }, - "node_modules/@types/send": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", - "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", "dev": true, + "license": "MIT", "dependencies": { - "@types/mime": "^1", - "@types/node": "*" + "@xtuc/ieee754": "^1.2.0" } }, - "node_modules/@types/serve-index": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", - "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@types/express": "*" + "@xtuc/long": "4.2.2" } }, - "node_modules/@types/serve-static": { - "version": "1.15.7", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", - "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.12.1", "dev": true, + "license": "MIT", "dependencies": { - "@types/http-errors": "*", - "@types/node": "*", - "@types/send": "*" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" } }, - "node_modules/@types/sockjs": { - "version": "0.3.36", - "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", - "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.12.1", "dev": true, + "license": "MIT", "dependencies": { - "@types/node": "*" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, - "node_modules/@types/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", - "dev": true - }, - "node_modules/@types/ws": { - "version": "8.5.10", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", - "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.12.1", "dev": true, + "license": "MIT", "dependencies": { - "@types/node": "*" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" } }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.21.0", + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.12.1", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/type-utils": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.2.4", - "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { - "version": "6.21.0", + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.12.1", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "@webassemblyjs/ast": "1.12.1", + "@xtuc/long": "4.2.2" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "6.21.0", + "node_modules/@wessberg/ts-evaluator": { + "version": "0.0.27", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "semver": "^7.5.4" + "chalk": "^4.1.0", + "jsdom": "^16.4.0", + "object-path": "^0.11.5", + "tslib": "^2.0.3" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": ">=10.1.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "type": "github", + "url": "https://github.com/wessberg/ts-evaluator?sponsor=1" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "typescript": ">=3.2.x || >= 4.x" } }, - "node_modules/@typescript-eslint/parser": { - "version": "6.21.0", + "node_modules/@wessberg/ts-evaluator/node_modules/ansi-styles": { + "version": "4.3.0", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4" + "color-convert": "^2.0.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": ">=8" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "6.21.0", + "node_modules/@wessberg/ts-evaluator/node_modules/chalk": { + "version": "4.1.2", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "5.62.0", + "node_modules/@wessberg/ts-evaluator/node_modules/color-convert": { + "version": "2.0.1", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "5.62.0", - "@typescript-eslint/utils": "5.62.0", - "debug": "^4.3.4", - "tsutils": "^3.21.0" + "color-name": "~1.1.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "node": ">=7.0.0" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "5.62.0", + "node_modules/@wessberg/ts-evaluator/node_modules/has-flag": { + "version": "4.0.0", "dev": true, "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=8" + } + }, + "node_modules/@wessberg/ts-evaluator/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "engines": { + "node": ">=8" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.62.0", + "node_modules/@xml-tools/parser": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@xml-tools/parser/-/parser-1.0.11.tgz", + "integrity": "sha512-aKqQ077XnR+oQtHJlrAflaZaL7qZsulWc/i/ZEooar5JiWj1eLt0+Wg28cpa+XLney107wXqneC+oG1IZvxkTA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "chevrotain": "7.1.1" + } + }, + "node_modules/@xmldom/xmldom": { + "version": "0.7.13", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.13.tgz", + "integrity": "sha512-lm2GW5PkosIzccsaZIz7tp8cPADSIlIHWDFTR1N0SzfinhhYgeIQjFMz4rYzanCScr3DqQLeomUDArp6MWKm+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/@yarnpkg/parsers": { + "version": "3.0.0-rc.46", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "js-yaml": "^3.10.0", + "tslib": "^2.4.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=14.15.0" + } + }, + "node_modules/@zkochan/js-yaml": { + "version": "0.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.62.0", + "node_modules/@zkochan/js-yaml/node_modules/argparse": { + "version": "2.0.1", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/abab": { + "version": "2.0.6", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/abbrev": { + "version": "1.1.1", + "dev": true, + "license": "ISC" + }, + "node_modules/accepts": { + "version": "1.3.8", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "5.62.0", - "eslint-visitor-keys": "^3.3.0" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", + "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "engines": { + "node": ">=0.4.0" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/globby": { - "version": "11.1.0", + "node_modules/acorn-globals": { + "version": "6.0.0", "dev": true, "license": "MIT", "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, + "node_modules/acorn-globals/node_modules/acorn": { + "version": "7.4.1", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.4.0" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/slash": { - "version": "3.0.0", + "node_modules/acorn-globals/node_modules/acorn-walk": { + "version": "7.2.0", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=0.4.0" } }, - "node_modules/@typescript-eslint/types": { - "version": "6.21.0", + "node_modules/acorn-import-assertions": { + "version": "1.9.0", "dev": true, "license": "MIT", - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "peerDependencies": { + "acorn": "^8" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.21.0", + "node_modules/acorn-jsx": { + "version": "5.3.2", "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.1", + "node_modules/acorn-walk": { + "version": "8.3.1", "dev": true, "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" + "engines": { + "node": ">=0.4.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/globby": { - "version": "11.1.0", + "node_modules/add-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz", + "integrity": "sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/adjust-sourcemap-loader": { + "version": "4.0.0", "dev": true, "license": "MIT", "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8.9" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.3", + "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { + "version": "2.0.4", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "brace-expansion": "^2.0.1" + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" }, "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=8.9.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/slash": { - "version": "3.0.0", + "node_modules/adm-zip": { + "version": "0.5.12", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=6.0" } }, - "node_modules/@typescript-eslint/utils": { - "version": "5.62.0", + "node_modules/agent-base": { + "version": "6.0.2", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" + "debug": "4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "node": ">= 6.0.0" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { - "version": "5.62.0", + "node_modules/agentkeepalive": { + "version": "4.5.0", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0" + "humanize-ms": "^1.2.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">= 8.0.0" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "5.62.0", + "node_modules/aggregate-error": { + "version": "3.1.0", "dev": true, "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.62.0", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/ajv-formats": { + "version": "2.1.1", + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "ajv": "^8.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "peerDependencies": { + "ajv": "^8.0.0" }, "peerDependenciesMeta": { - "typescript": { + "ajv": { "optional": true } } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.62.0", + "node_modules/ajv-keywords": { + "version": "5.1.0", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "5.62.0", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "fast-deep-equal": "^3.1.3" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "peerDependencies": { + "ajv": "^8.8.2" } }, - "node_modules/@typescript-eslint/utils/node_modules/globby": { - "version": "11.1.0", + "node_modules/ansi-colors": { + "version": "4.1.3", "dev": true, "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "license": "MIT", "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" + "type-fest": "^0.21.3" }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@typescript-eslint/utils/node_modules/slash": { - "version": "3.0.0", + "node_modules/ansi-html-community": { + "version": "0.0.8", "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "license": "Apache-2.0", + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.21.0", + "node_modules/ansi-styles": { + "version": "3.2.1", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "6.21.0", - "eslint-visitor-keys": "^3.4.1" + "color-convert": "^1.9.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "devOptional": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "engines": { + "node": ">= 8" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", + "node_modules/aproba": { + "version": "2.0.0", "dev": true, "license": "ISC" }, - "node_modules/@vitejs/plugin-basic-ssl": { - "version": "1.0.1", + "node_modules/are-docs-informative": { + "version": "0.0.2", "dev": true, "license": "MIT", "engines": { - "node": ">=14.6.0" - }, - "peerDependencies": { - "vite": "^3.0.0 || ^4.0.0" + "node": ">=14" } }, - "node_modules/@webassemblyjs/ast": { - "version": "1.12.1", + "node_modules/are-we-there-yet": { + "version": "3.0.1", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.6", - "dev": true, - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.6", - "dev": true, - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.12.1", + "node_modules/arg": { + "version": "4.1.3", "dev": true, "license": "MIT" }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.6", + "node_modules/argparse": { + "version": "1.0.10", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", - "@xtuc/long": "4.2.2" + "sprintf-js": "~1.0.2" } }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.6", - "dev": true, - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.12.1", + "node_modules/aria-query": { + "version": "5.3.0", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/wasm-gen": "1.12.1" + "dequal": "^2.0.3" } }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.6", + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", "dev": true, "license": "MIT", "dependencies": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.11.6", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@xtuc/long": "4.2.2" + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.11.6", + "node_modules/array-flatten": { + "version": "1.1.1", "dev": true, "license": "MIT" }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.12.1", + "node_modules/array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", "dev": true, - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/helper-wasm-section": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-opt": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1", - "@webassemblyjs/wast-printer": "1.12.1" - } + "license": "MIT" }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.12.1", + "node_modules/array-includes": { + "version": "3.1.7", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.12.1", + "node_modules/array-union": { + "version": "2.1.0", "dev": true, "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1" + "engines": { + "node": ">=8" } }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.12.1", + "node_modules/array-uniq": { + "version": "1.0.3", "dev": true, "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-api-error": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.12.1", + "node_modules/array.prototype.findlastindex": { + "version": "1.2.5", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@xtuc/long": "4.2.2" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@wessberg/ts-evaluator": { - "version": "0.0.27", + "node_modules/array.prototype.flat": { + "version": "1.3.2", "dev": true, "license": "MIT", "dependencies": { - "chalk": "^4.1.0", - "jsdom": "^16.4.0", - "object-path": "^0.11.5", - "tslib": "^2.0.3" + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" }, "engines": { - "node": ">=10.1.0" + "node": ">= 0.4" }, "funding": { - "type": "github", - "url": "https://github.com/wessberg/ts-evaluator?sponsor=1" - }, - "peerDependencies": { - "typescript": ">=3.2.x || >= 4.x" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@wessberg/ts-evaluator/node_modules/ansi-styles": { - "version": "4.3.0", + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", "dev": true, "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" }, "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@wessberg/ts-evaluator/node_modules/chalk": { - "version": "4.1.2", + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@wessberg/ts-evaluator/node_modules/color-convert": { - "version": "2.0.1", + "node_modules/arrify": { + "version": "1.0.1", "dev": true, "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, "engines": { - "node": ">=7.0.0" + "node": ">=0.10.0" } }, - "node_modules/@wessberg/ts-evaluator/node_modules/has-flag": { - "version": "4.0.0", + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "license": "MIT" + }, + "node_modules/asn1": { + "version": "0.2.6", "dev": true, "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "safer-buffer": "~2.1.0" } }, - "node_modules/@wessberg/ts-evaluator/node_modules/supports-color": { - "version": "7.2.0", + "node_modules/assert-plus": { + "version": "1.0.0", "dev": true, "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "tslib": "^2.0.1" }, + "engines": { + "node": ">=4" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", + "node_modules/async": { + "version": "3.2.5", "dev": true, - "license": "BSD-3-Clause" + "license": "MIT" }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "dev": true, - "license": "Apache-2.0" + "node_modules/asynckit": { + "version": "0.4.0", + "license": "MIT" }, - "node_modules/@yarnpkg/lockfile": { - "version": "1.1.0", - "dev": true, - "license": "BSD-2-Clause" + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "license": "ISC", + "engines": { + "node": ">= 4.0.0" + } }, - "node_modules/@yarnpkg/parsers": { - "version": "3.0.0-rc.46", + "node_modules/autoprefixer": { + "version": "10.4.14", "dev": true, - "license": "BSD-2-Clause", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + } + ], + "license": "MIT", "dependencies": { - "js-yaml": "^3.10.0", - "tslib": "^2.4.0" + "browserslist": "^4.21.5", + "caniuse-lite": "^1.0.30001464", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" }, "engines": { - "node": ">=14.15.0" + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/@zkochan/js-yaml": { - "version": "0.0.6", + "node_modules/available-typed-arrays": { + "version": "1.0.7", "dev": true, "license": "MIT", "dependencies": { - "argparse": "^2.0.1" + "possible-typed-array-names": "^1.0.0" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@zkochan/js-yaml/node_modules/argparse": { - "version": "2.0.1", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/abab": { - "version": "2.0.6", + "node_modules/aws-sign2": { + "version": "0.7.0", "dev": true, - "license": "BSD-3-Clause" + "license": "Apache-2.0", + "engines": { + "node": "*" + } }, - "node_modules/abbrev": { - "version": "1.1.1", + "node_modules/aws4": { + "version": "1.12.0", "dev": true, - "license": "ISC" + "license": "MIT" }, - "node_modules/accepts": { - "version": "1.3.8", + "node_modules/axios": { + "version": "1.6.8", "dev": true, "license": "MIT", "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" } }, - "node_modules/acorn": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", - "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", + "node_modules/axios/node_modules/form-data": { + "version": "4.0.0", "dev": true, - "bin": { - "acorn": "bin/acorn" + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" }, "engines": { - "node": ">=0.4.0" + "node": ">= 6" } }, - "node_modules/acorn-globals": { - "version": "6.0.0", + "node_modules/axobject-query": { + "version": "4.0.0", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" + "dequal": "^2.0.3" } }, - "node_modules/acorn-globals/node_modules/acorn": { - "version": "7.4.1", + "node_modules/b4a": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", + "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/babel-loader": { + "version": "9.1.3", "dev": true, "license": "MIT", - "bin": { - "acorn": "bin/acorn" + "dependencies": { + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" }, "engines": { - "node": ">=0.4.0" + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0", + "webpack": ">=5" } }, - "node_modules/acorn-globals/node_modules/acorn-walk": { - "version": "7.2.0", + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, "engines": { - "node": ">=0.4.0" + "node": ">=8" } }, - "node_modules/acorn-import-assertions": { - "version": "1.9.0", + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.10", "dev": true, "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.1", + "semver": "^6.3.1" + }, "peerDependencies": { - "acorn": "^8" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/acorn-jsx": { - "version": "5.3.2", + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.8.7", "dev": true, "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.4.4", + "core-js-compat": "^3.33.1" + }, "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/acorn-walk": { - "version": "8.3.1", + "node_modules/babel-plugin-polyfill-corejs3/node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.4.4", "dev": true, "license": "MIT", - "engines": { - "node": ">=0.4.0" + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/adjust-sourcemap-loader": { - "version": "4.0.0", + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.5.5", "dev": true, "license": "MIT", "dependencies": { - "loader-utils": "^2.0.0", - "regex-parser": "^2.2.11" + "@babel/helper-define-polyfill-provider": "^0.5.0" }, - "engines": { - "node": ">=8.9" + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { - "version": "2.0.4", + "node_modules/babel-plugin-polyfill-regenerator/node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.5.0", "dev": true, "license": "MIT", "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" }, - "engines": { - "node": ">=8.9.0" + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/adm-zip": { - "version": "0.5.12", + "node_modules/balanced-match": { + "version": "1.0.2", + "license": "MIT" + }, + "node_modules/bare-events": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.4.2.tgz", + "integrity": "sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0" + "license": "Apache-2.0", + "optional": true + }, + "node_modules/bare-fs": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.3.1.tgz", + "integrity": "sha512-W/Hfxc/6VehXlsgFtbB5B4xFcsCl+pAh30cYhoFyXErf6oGrwjh8SwiPAdHgpmWonKuYpZgGywN0SXt7dgsADA==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-events": "^2.0.0", + "bare-path": "^2.0.0", + "bare-stream": "^2.0.0" } }, - "node_modules/agent-base": { - "version": "6.0.2", + "node_modules/bare-os": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.4.0.tgz", + "integrity": "sha512-v8DTT08AS/G0F9xrhyLtepoo9EJBJ85FRSMbu1pQUlAf6A8T0tEEQGMVObWeqpjhSPXsE0VGlluFBJu2fdoTNg==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", + "optional": true + }, + "node_modules/bare-path": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.3.tgz", + "integrity": "sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA==", + "dev": true, + "license": "Apache-2.0", + "optional": true, "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" + "bare-os": "^2.1.0" } }, - "node_modules/agentkeepalive": { - "version": "4.5.0", + "node_modules/bare-stream": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.1.3.tgz", + "integrity": "sha512-tiDAH9H/kP+tvNO5sczyn9ZAA7utrSMobyDchsnyyXBuUe2FSQWbxhtuHB8jwpHYYevVo2UJpcmvvjrbHboUUQ==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", + "optional": true, "dependencies": { - "humanize-ms": "^1.2.1" - }, - "engines": { - "node": ">= 8.0.0" + "streamx": "^2.18.0" } }, - "node_modules/aggregate-error": { - "version": "3.1.0", + "node_modules/base64-js": { + "version": "1.5.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/base64id": { + "version": "2.0.0", "dev": true, "license": "MIT", - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, "engines": { - "node": ">=8" + "node": "^4.5.0 || >= 5.9" } }, - "node_modules/ajv": { - "version": "8.12.0", + "node_modules/basic-ftp": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", + "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "engines": { + "node": ">=10.0.0" } }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "license": "MIT", + "node_modules/batch": { + "version": "0.6.1", + "dev": true, + "license": "MIT" + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } + "tweetnacl": "^0.14.3" } }, - "node_modules/ajv-keywords": { - "version": "5.1.0", + "node_modules/big-integer": { + "version": "1.6.52", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", + "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" + "license": "Unlicense", + "engines": { + "node": ">=0.6" } }, - "node_modules/ansi-colors": { - "version": "4.1.3", + "node_modules/big.js": { + "version": "5.2.2", "dev": true, "license": "MIT", "engines": { - "node": ">=6" + "node": "*" } }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "dev": true, + "node_modules/binary-extensions": { + "version": "2.2.0", + "devOptional": true, "license": "MIT", - "dependencies": { - "type-fest": "^0.21.3" - }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-html-community": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", - "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", - "dev": true, - "engines": [ - "node >= 0.8.0" - ], - "bin": { - "ansi-html": "bin/ansi-html" } }, - "node_modules/ansi-regex": { - "version": "5.0.1", + "node_modules/bl": { + "version": "4.1.0", "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" } }, - "node_modules/ansi-styles": { - "version": "3.2.1", + "node_modules/blocking-proxy": { + "version": "1.0.1", "dev": true, "license": "MIT", "dependencies": { - "color-convert": "^1.9.0" + "minimist": "^1.2.0" + }, + "bin": { + "blocking-proxy": "built/lib/bin.js" }, "engines": { - "node": ">=4" + "node": ">=6.9.x" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "devOptional": true, - "license": "ISC", + "node_modules/body-parser": { + "version": "1.20.2", + "dev": true, + "license": "MIT", "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" }, "engines": { - "node": ">= 8" + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/aproba": { - "version": "2.0.0", + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", "dev": true, - "license": "ISC" + "license": "MIT", + "engines": { + "node": ">= 0.8" + } }, - "node_modules/are-docs-informative": { - "version": "0.0.2", + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", "dev": true, "license": "MIT", - "engines": { - "node": ">=14" + "dependencies": { + "ms": "2.0.0" } }, - "node_modules/are-we-there-yet": { - "version": "3.0.1", + "node_modules/body-parser/node_modules/iconv-lite": { + "version": "0.4.24", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" + "safer-buffer": ">= 2.1.2 < 3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=0.10.0" } }, - "node_modules/arg": { - "version": "4.1.3", + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", "dev": true, "license": "MIT" }, - "node_modules/argparse": { - "version": "1.0.10", + "node_modules/bonjour-service": { + "version": "1.2.1", "dev": true, "license": "MIT", "dependencies": { - "sprintf-js": "~1.0.2" + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" } }, - "node_modules/aria-query": { - "version": "5.3.0", + "node_modules/boolbase": { + "version": "1.0.0", "dev": true, - "license": "Apache-2.0", + "license": "ISC" + }, + "node_modules/bplist-creator": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.1.0.tgz", + "integrity": "sha512-sXaHZicyEEmY86WyueLTQesbeoH/mquvarJaQNbjuOQO+7gbFcDEWqKmcWA4cOTLzFlfgvkiVxolk1k5bBIpmg==", + "dev": true, + "license": "MIT", "dependencies": { - "dequal": "^2.0.3" + "stream-buffers": "2.2.x" } }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.1", + "node_modules/bplist-parser": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.3.2.tgz", + "integrity": "sha512-apC2+fspHGI3mMKj+dGevkGo/tCqVB8jMb6i+OX+E29p0Iposz07fABkRIfVUPNd5A5VbuOz1bZbnmkKLYF+wQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.5", - "is-array-buffer": "^3.0.4" + "big-integer": "1.6.x" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 5.10.0" } }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "dev": true + "node_modules/brace-expansion": { + "version": "1.1.11", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } }, - "node_modules/array-includes": { - "version": "3.1.7", - "dev": true, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "devOptional": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-string": "^1.0.7" + "fill-range": "^7.1.1" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/array-union": { - "version": "2.1.0", + "node_modules/browser-process-hrtime": { + "version": "1.0.0", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/browserslist": { + "version": "4.23.0", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, "engines": { - "node": ">=8" + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/array-uniq": { - "version": "1.0.3", + "node_modules/browserstack": { + "version": "1.6.1", "dev": true, "license": "MIT", - "engines": { - "node": ">=0.10.0" + "dependencies": { + "https-proxy-agent": "^2.2.1" } }, - "node_modules/array.prototype.findlastindex": { - "version": "1.2.5", + "node_modules/browserstack/node_modules/agent-base": { + "version": "4.3.0", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" + "es6-promisify": "^5.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 4.0.0" } }, - "node_modules/array.prototype.flat": { - "version": "1.3.2", + "node_modules/browserstack/node_modules/debug": { + "version": "3.2.7", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" + "ms": "^2.1.1" + } + }, + "node_modules/browserstack/node_modules/https-proxy-agent": { + "version": "2.2.4", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 4.5.0" } }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.2", - "dev": true, + "node_modules/buffer": { + "version": "5.7.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" } }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.3", + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "dev": true, "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.2.1", - "get-intrinsic": "^1.2.3", - "is-array-buffer": "^3.0.4", - "is-shared-array-buffer": "^1.0.2" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "*" } }, - "node_modules/arrify": { - "version": "1.0.1", + "node_modules/buffer-from": { + "version": "1.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/builtin-modules": { + "version": "3.3.0", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/asn1": { - "version": "0.2.6", + "node_modules/builtins": { + "version": "5.0.1", "dev": true, "license": "MIT", "dependencies": { - "safer-buffer": "~2.1.0" + "semver": "^7.0.0" } }, - "node_modules/assert-plus": { - "version": "1.0.0", + "node_modules/bytes": { + "version": "3.0.0", "dev": true, "license": "MIT", "engines": { - "node": ">=0.8" + "node": ">= 0.8" } }, - "node_modules/async": { - "version": "3.2.5", + "node_modules/cacache": { + "version": "17.1.4", "dev": true, - "license": "MIT" + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^7.7.1", + "minipass": "^7.0.3", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } }, - "node_modules/asynckit": { - "version": "0.4.0", + "node_modules/cacache/node_modules/lru-cache": { + "version": "7.18.3", "dev": true, - "license": "MIT" + "license": "ISC", + "engines": { + "node": ">=12" + } }, - "node_modules/autoprefixer": { - "version": "10.4.14", + "node_modules/cacache/node_modules/minipass": { + "version": "7.0.4", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - } - ], - "license": "MIT", - "dependencies": { - "browserslist": "^4.21.5", - "caniuse-lite": "^1.0.30001464", - "fraction.js": "^4.2.0", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, + "license": "ISC", "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" + "node": ">=16 || 14 >=14.17" } }, - "node_modules/available-typed-arrays": { + "node_modules/call-bind": { "version": "1.0.7", - "dev": true, "license": "MIT", "dependencies": { - "possible-typed-array-names": "^1.0.0" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" }, "engines": { "node": ">= 0.4" @@ -5952,942 +7793,953 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/aws-sign2": { - "version": "0.7.0", + "node_modules/callsites": { + "version": "3.1.0", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "engines": { - "node": "*" + "node": ">=6" } }, - "node_modules/aws4": { - "version": "1.12.0", - "dev": true, - "license": "MIT" - }, - "node_modules/axios": { - "version": "1.6.8", + "node_modules/camelcase": { + "version": "5.3.1", "dev": true, "license": "MIT", - "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" + "engines": { + "node": ">=6" } }, - "node_modules/axios/node_modules/form-data": { - "version": "4.0.0", + "node_modules/camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", "dev": true, "license": "MIT", "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" }, "engines": { - "node": ">= 6" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/axobject-query": { - "version": "4.0.0", + "node_modules/caniuse-lite": { + "version": "1.0.30001606", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "dequal": "^2.0.3" - } + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" }, - "node_modules/babel-loader": { - "version": "9.1.3", - "dev": true, + "node_modules/capacitor-blob-writer": { + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/capacitor-blob-writer/-/capacitor-blob-writer-1.1.16.tgz", + "integrity": "sha512-MKeqLUB7hBmRiJQcMeucD22Ckql1tk1GFnk/xYQDtFNBhKcAJBoV5rMXgkTphvZoRFw9b8025PAdjSj23dbg7A==", "license": "MIT", - "dependencies": { - "find-cache-dir": "^4.0.0", - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 14.15.0" - }, "peerDependencies": { - "@babel/core": "^7.12.0", - "webpack": ">=5" + "@capacitor/core": ">=3.0.0", + "@capacitor/filesystem": ">=1.0.0" } }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" + "node_modules/capacitor-ios-autofill-save-password": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/capacitor-ios-autofill-save-password/-/capacitor-ios-autofill-save-password-2.0.0.tgz", + "integrity": "sha512-7Tnu7qU5elnv1YkcXtXPIBhvyCZX9nskKrI78kJG65qaf6rSL1EE5IBOdTSQcpyPSyVio+UX1EFsS/QZjQrPuA==", + "license": "MIT", + "peerDependencies": { + "@capacitor/core": "^5.0.0" } }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.10", - "dev": true, + "node_modules/capacitor-secure-storage-plugin": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/capacitor-secure-storage-plugin/-/capacitor-secure-storage-plugin-0.9.0.tgz", + "integrity": "sha512-P5fiC94opcLHu41vceo9weXH+20g0SPYKkeAx+qm9eKNcVFqpcuI4dqwivXlGXYNMDygyjSQuAaFwZ4gW0Y91Q==", "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.22.6", - "@babel/helper-define-polyfill-provider": "^0.6.1", - "semver": "^6.3.1" - }, "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "@capacitor/core": "^5.0.0" } }, - "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { - "version": "6.3.1", + "node_modules/caseless": { + "version": "0.12.0", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } + "license": "Apache-2.0" }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.8.7", + "node_modules/chalk": { + "version": "2.4.2", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.4.4", - "core-js-compat": "^3.33.1" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "engines": { + "node": ">=4" } }, - "node_modules/babel-plugin-polyfill-corejs3/node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.4.4", - "dev": true, + "node_modules/chardet": { + "version": "0.7.0", + "license": "MIT" + }, + "node_modules/chart.js": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.3.tgz", + "integrity": "sha512-qK1gkGSRYcJzqrrzdR6a+I0vQ4/R+SoODXyAjscQ/4mzuNzySaMCd+hyVxitSY1+L2fjPD1Gbn+ibNqRmwQeLw==", "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.22.6", - "@babel/helper-plugin-utils": "^7.22.5", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2" + "@kurkle/color": "^0.3.0" }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "engines": { + "pnpm": ">=8" } }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.5.5", - "dev": true, + "node_modules/chartjs-adapter-date-fns": { + "version": "3.0.0", "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.5.0" - }, "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "chart.js": ">=2.8.0", + "date-fns": ">=2.0.0" } }, - "node_modules/babel-plugin-polyfill-regenerator/node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.5.0", - "dev": true, + "node_modules/chartjs-plugin-zoom": { + "version": "2.0.1", "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.22.6", - "@babel/helper-plugin-utils": "^7.22.5", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2" + "hammerjs": "^2.0.8" }, "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "chart.js": ">=3.2.0" } }, - "node_modules/balanced-match": { - "version": "1.0.2", + "node_modules/chevrotain": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-7.1.1.tgz", + "integrity": "sha512-wy3mC1x4ye+O+QkEinVJkPf5u2vsrDIYW9G7ZuwFl6v/Yu0LwUuT2POsb+NUWApebyxfkQq6+yDfRExbnI5rcw==", "dev": true, - "license": "MIT" + "license": "Apache-2.0", + "dependencies": { + "regexp-to-ast": "0.5.0" + } }, - "node_modules/base64-js": { - "version": "1.5.1", + "node_modules/chokidar": { + "version": "3.5.3", + "devOptional": true, "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" + "type": "individual", + "url": "https://paulmillr.com/funding/" } ], - "license": "MIT" - }, - "node_modules/base64id": { - "version": "2.0.0", - "dev": true, "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, "engines": { - "node": "^4.5.0 || >= 5.9" + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" } }, - "node_modules/batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", - "dev": true - }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "tweetnacl": "^0.14.3" + "node_modules/chownr": { + "version": "2.0.0", + "license": "ISC", + "engines": { + "node": ">=10" } }, - "node_modules/big.js": { - "version": "5.2.2", + "node_modules/chrome-trace-event": { + "version": "1.0.3", "dev": true, "license": "MIT", "engines": { - "node": "*" + "node": ">=6.0" } }, - "node_modules/binary-extensions": { + "node_modules/classlist.js": { + "version": "1.1.20150312", + "license": "Dedicated to the public domain" + }, + "node_modules/clean-stack": { "version": "2.2.0", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/bl": { - "version": "4.1.0", + "node_modules/cli-cursor": { + "version": "3.1.0", "license": "MIT", "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/blocking-proxy": { - "version": "1.0.1", - "dev": true, + "node_modules/cli-spinners": { + "version": "2.9.2", "license": "MIT", - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "blocking-proxy": "built/lib/bin.js" + "engines": { + "node": ">=6" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "license": "ISC", "engines": { - "node": ">=6.9.x" + "node": ">= 10" } }, - "node_modules/body-parser": { - "version": "1.20.2", + "node_modules/cliui": { + "version": "8.0.1", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" }, "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" + "node": ">=12" } }, - "node_modules/body-parser/node_modules/bytes": { - "version": "3.1.2", - "dev": true, + "node_modules/clone": { + "version": "1.0.4", "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">=0.8" } }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", + "node_modules/clone-deep": { + "version": "4.0.1", "dev": true, "license": "MIT", "dependencies": { - "ms": "2.0.0" + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" } }, - "node_modules/body-parser/node_modules/iconv-lite": { - "version": "0.4.24", + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", "dev": true, "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "color-convert": "^2.0.1", + "color-string": "^1.9.0" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/bonjour-service": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", - "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "multicast-dns": "^7.2.5" + "node": ">=12.5.0" } }, - "node_modules/boolbase": { - "version": "1.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/brace-expansion": { - "version": "1.1.11", + "node_modules/color-convert": { + "version": "1.9.3", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "devOptional": true, - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" + "color-name": "1.1.3" } }, - "node_modules/browser-process-hrtime": { - "version": "1.0.0", + "node_modules/color-convert/node_modules/color-name": { + "version": "1.1.3", "dev": true, - "license": "BSD-2-Clause" + "license": "MIT" }, - "node_modules/browserslist": { - "version": "4.23.0", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], + "node_modules/color-name": { + "version": "1.1.4", + "license": "MIT" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dev": true, "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001587", - "electron-to-chromium": "^1.4.668", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" - }, + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color-support": { + "version": "1.1.3", + "dev": true, + "license": "ISC", "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + "color-support": "bin.js" } }, - "node_modules/browserstack": { - "version": "1.6.1", + "node_modules/color/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "license": "MIT", "dependencies": { - "https-proxy-agent": "^2.2.1" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "node_modules/browserstack/node_modules/agent-base": { - "version": "4.3.0", + "node_modules/colorette": { + "version": "2.0.20", + "dev": true, + "license": "MIT" + }, + "node_modules/colors": { + "version": "1.4.0", "dev": true, "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "license": "MIT", "dependencies": { - "es6-promisify": "^5.0.0" + "delayed-stream": "~1.0.0" }, "engines": { - "node": ">= 4.0.0" + "node": ">= 0.8" } }, - "node_modules/browserstack/node_modules/debug": { - "version": "3.2.7", - "dev": true, + "node_modules/commander": { + "version": "7.2.0", "license": "MIT", - "dependencies": { - "ms": "^2.1.1" + "engines": { + "node": ">= 10" } }, - "node_modules/browserstack/node_modules/https-proxy-agent": { - "version": "2.2.4", + "node_modules/comment-parser": { + "version": "1.4.1", "dev": true, "license": "MIT", - "dependencies": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - }, "engines": { - "node": ">= 4.5.0" + "node": ">= 12.0.0" } }, - "node_modules/buffer": { - "version": "5.7.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], + "node_modules/common-path-prefix": { + "version": "3.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dev": true, "license": "MIT", "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" } }, - "node_modules/buffer-from": { - "version": "1.1.2", - "dev": true, + "node_modules/compare-versions": { + "version": "6.1.0", "license": "MIT" }, - "node_modules/builtin-modules": { - "version": "3.3.0", - "dev": true, + "node_modules/component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", "license": "MIT", - "engines": { - "node": ">=6" - }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/builtins": { - "version": "5.0.1", + "node_modules/compressible": { + "version": "2.0.18", "dev": true, "license": "MIT", "dependencies": { - "semver": "^7.0.0" - } - }, - "node_modules/bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", - "dev": true, + "mime-db": ">= 1.43.0 < 2" + }, "engines": { - "node": ">= 0.8" + "node": ">= 0.6" } }, - "node_modules/cacache": { - "version": "17.1.4", + "node_modules/compression": { + "version": "1.7.4", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "@npmcli/fs": "^3.1.0", - "fs-minipass": "^3.0.0", - "glob": "^10.2.2", - "lru-cache": "^7.7.1", - "minipass": "^7.0.3", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "p-map": "^4.0.0", - "ssri": "^10.0.0", - "tar": "^6.1.11", - "unique-filename": "^3.0.0" + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">= 0.8.0" } }, - "node_modules/cacache/node_modules/lru-cache": { - "version": "7.18.3", + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" + "license": "MIT", + "dependencies": { + "ms": "2.0.0" } }, - "node_modules/cacache/node_modules/minipass": { - "version": "7.0.4", + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", "dev": true, - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } + "license": "MIT" }, - "node_modules/call-bind": { - "version": "1.0.7", + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "license": "MIT" + }, + "node_modules/connect": { + "version": "3.7.0", "dev": true, "license": "MIT", "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 0.10.0" } }, - "node_modules/callsites": { - "version": "3.1.0", + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", "dev": true, "license": "MIT", "engines": { - "node": ">=6" + "node": ">=0.8" } }, - "node_modules/camelcase": { - "version": "5.3.1", + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", "dev": true, "license": "MIT", - "engines": { - "node": ">=6" + "dependencies": { + "ms": "2.0.0" } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001606", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/caseless": { - "version": "0.12.0", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/chalk": { - "version": "2.4.2", + "node_modules/connect/node_modules/finalhandler": { + "version": "1.1.2", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" }, "engines": { - "node": ">=4" + "node": ">= 0.8" } }, - "node_modules/chardet": { - "version": "0.7.0", + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", "dev": true, "license": "MIT" }, - "node_modules/chart.js": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.3.tgz", - "integrity": "sha512-qK1gkGSRYcJzqrrzdR6a+I0vQ4/R+SoODXyAjscQ/4mzuNzySaMCd+hyVxitSY1+L2fjPD1Gbn+ibNqRmwQeLw==", + "node_modules/connect/node_modules/on-finished": { + "version": "2.3.0", + "dev": true, + "license": "MIT", "dependencies": { - "@kurkle/color": "^0.3.0" + "ee-first": "1.1.1" }, "engines": { - "pnpm": ">=8" + "node": ">= 0.8" } }, - "node_modules/chartjs-adapter-date-fns": { - "version": "3.0.0", + "node_modules/connect/node_modules/statuses": { + "version": "1.5.0", + "dev": true, "license": "MIT", - "peerDependencies": { - "chart.js": ">=2.8.0", - "date-fns": ">=2.0.0" + "engines": { + "node": ">= 0.6" } }, - "node_modules/chartjs-plugin-zoom": { - "version": "2.0.1", + "node_modules/console-control-strings": { + "version": "1.1.0", + "dev": true, + "license": "ISC" + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "dev": true, "license": "MIT", "dependencies": { - "hammerjs": "^2.0.8" + "safe-buffer": "5.2.1" }, - "peerDependencies": { - "chart.js": ">=3.2.0" + "engines": { + "node": ">= 0.6" } }, - "node_modules/chokidar": { - "version": "3.5.3", - "devOptional": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], + "node_modules/content-type": { + "version": "1.0.5", + "dev": true, "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "node": ">= 0.6" } }, - "node_modules/chownr": { - "version": "2.0.0", + "node_modules/conventional-changelog": { + "version": "3.1.25", + "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-3.1.25.tgz", + "integrity": "sha512-ryhi3fd1mKf3fSjbLXOfK2D06YwKNic1nC9mWqybBHdObPd8KJ2vjaXZfYj1U23t+V8T8n0d7gwnc9XbIdFbyQ==", "dev": true, - "license": "ISC", + "license": "MIT", + "dependencies": { + "conventional-changelog-angular": "^5.0.12", + "conventional-changelog-atom": "^2.0.8", + "conventional-changelog-codemirror": "^2.0.8", + "conventional-changelog-conventionalcommits": "^4.5.0", + "conventional-changelog-core": "^4.2.1", + "conventional-changelog-ember": "^2.0.9", + "conventional-changelog-eslint": "^3.0.9", + "conventional-changelog-express": "^2.0.6", + "conventional-changelog-jquery": "^3.0.11", + "conventional-changelog-jshint": "^2.0.9", + "conventional-changelog-preset-loader": "^2.3.4" + }, "engines": { "node": ">=10" } }, - "node_modules/chrome-trace-event": { - "version": "1.0.3", + "node_modules/conventional-changelog-angular": { + "version": "5.0.13", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz", + "integrity": "sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA==", "dev": true, - "license": "MIT", + "license": "ISC", + "dependencies": { + "compare-func": "^2.0.0", + "q": "^1.5.1" + }, "engines": { - "node": ">=6.0" + "node": ">=10" } }, - "node_modules/classlist.js": { - "version": "1.1.20150312", - "license": "Dedicated to the public domain" - }, - "node_modules/clean-stack": { - "version": "2.2.0", + "node_modules/conventional-changelog-angular/node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", "dev": true, "license": "MIT", "engines": { - "node": ">=6" + "node": ">=0.6.0", + "teleport": ">=0.2.0" } }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "license": "MIT", + "node_modules/conventional-changelog-atom": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/conventional-changelog-atom/-/conventional-changelog-atom-2.0.8.tgz", + "integrity": "sha512-xo6v46icsFTK3bb7dY/8m2qvc8sZemRgdqLb/bjpBsH2UyOS8rKNTgcb5025Hri6IpANPApbXMg15QLb1LJpBw==", + "dev": true, + "license": "ISC", "dependencies": { - "restore-cursor": "^3.1.0" + "q": "^1.5.1" }, "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/cli-spinners": { - "version": "2.9.2", + "node_modules/conventional-changelog-atom/node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", + "dev": true, "license": "MIT", "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.6.0", + "teleport": ">=0.2.0" } }, - "node_modules/cli-width": { - "version": "3.0.0", + "node_modules/conventional-changelog-codemirror": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/conventional-changelog-codemirror/-/conventional-changelog-codemirror-2.0.8.tgz", + "integrity": "sha512-z5DAsn3uj1Vfp7po3gpt2Boc+Bdwmw2++ZHa5Ak9k0UKsYAO5mH1UBTN0qSCuJZREIhX6WU4E1p3IW2oRCNzQw==", "dev": true, "license": "ISC", + "dependencies": { + "q": "^1.5.1" + }, "engines": { - "node": ">= 10" + "node": ">=10" } }, - "node_modules/cliui": { - "version": "8.0.1", + "node_modules/conventional-changelog-codemirror/node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/conventional-changelog-conventionalcommits": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.6.3.tgz", + "integrity": "sha512-LTTQV4fwOM4oLPad317V/QNQ1FY4Hju5qeBIM1uTHbrnCE+Eg4CdRZ3gO2pUeR+tzWdp80M2j3qFFEDWVqOV4g==", "dev": true, "license": "ISC", "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" + "compare-func": "^2.0.0", + "lodash": "^4.17.15", + "q": "^1.5.1" }, "engines": { - "node": ">=12" + "node": ">=10" } }, - "node_modules/clone": { - "version": "1.0.4", + "node_modules/conventional-changelog-conventionalcommits/node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", + "dev": true, "license": "MIT", "engines": { - "node": ">=0.8" + "node": ">=0.6.0", + "teleport": ">=0.2.0" } }, - "node_modules/clone-deep": { - "version": "4.0.1", + "node_modules/conventional-changelog-core": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-4.2.4.tgz", + "integrity": "sha512-gDVS+zVJHE2v4SLc6B0sLsPiloR0ygU7HaDW14aNJE1v4SlqJPILPl/aJC7YdtRE4CybBf8gDwObBvKha8Xlyg==", "dev": true, "license": "MIT", "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" + "add-stream": "^1.0.0", + "conventional-changelog-writer": "^5.0.0", + "conventional-commits-parser": "^3.2.0", + "dateformat": "^3.0.0", + "get-pkg-repo": "^4.0.0", + "git-raw-commits": "^2.0.8", + "git-remote-origin-url": "^2.0.0", + "git-semver-tags": "^4.1.1", + "lodash": "^4.17.15", + "normalize-package-data": "^3.0.0", + "q": "^1.5.1", + "read-pkg": "^3.0.0", + "read-pkg-up": "^3.0.0", + "through2": "^4.0.0" }, "engines": { - "node": ">=6" + "node": ">=10" } }, - "node_modules/color-convert": { - "version": "1.9.3", + "node_modules/conventional-changelog-core/node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "color-name": "1.1.3" + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" } }, - "node_modules/color-convert/node_modules/color-name": { - "version": "1.1.3", - "dev": true, - "license": "MIT" - }, - "node_modules/color-name": { - "version": "1.1.4", - "license": "MIT" - }, - "node_modules/color-support": { - "version": "1.1.3", + "node_modules/conventional-changelog-core/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "license": "ISC", - "bin": { - "color-support": "bin.js" - } - }, - "node_modules/colorette": { - "version": "2.0.20", - "dev": true, - "license": "MIT" - }, - "node_modules/colors": { - "version": "1.4.0", - "dev": true, - "license": "MIT", + "dependencies": { + "yallist": "^4.0.0" + }, "engines": { - "node": ">=0.1.90" + "node": ">=10" } }, - "node_modules/combined-stream": { - "version": "1.0.8", + "node_modules/conventional-changelog-core/node_modules/normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "delayed-stream": "~1.0.0" + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" }, "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "7.2.0", - "license": "MIT", - "engines": { - "node": ">= 10" + "node": ">=10" } }, - "node_modules/comment-parser": { - "version": "1.4.1", + "node_modules/conventional-changelog-core/node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", "dev": true, "license": "MIT", "engines": { - "node": ">= 12.0.0" + "node": ">=0.6.0", + "teleport": ">=0.2.0" } }, - "node_modules/common-path-prefix": { - "version": "3.0.0", + "node_modules/conventional-changelog-core/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true, "license": "ISC" }, - "node_modules/compare-versions": { - "version": "6.1.0", - "license": "MIT" - }, - "node_modules/compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "node_modules/conventional-changelog-ember": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/conventional-changelog-ember/-/conventional-changelog-ember-2.0.9.tgz", + "integrity": "sha512-ulzIReoZEvZCBDhcNYfDIsLTHzYHc7awh+eI44ZtV5cx6LVxLlVtEmcO+2/kGIHGtw+qVabJYjdI5cJOQgXh1A==", "dev": true, + "license": "ISC", "dependencies": { - "mime-db": ">= 1.43.0 < 2" + "q": "^1.5.1" }, "engines": { - "node": ">= 0.6" + "node": ">=10" } }, - "node_modules/compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "node_modules/conventional-changelog-ember/node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", "dev": true, - "dependencies": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", - "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", - "vary": "~1.1.2" - }, + "license": "MIT", "engines": { - "node": ">= 0.8.0" + "node": ">=0.6.0", + "teleport": ">=0.2.0" } }, - "node_modules/compression/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/conventional-changelog-eslint": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/conventional-changelog-eslint/-/conventional-changelog-eslint-3.0.9.tgz", + "integrity": "sha512-6NpUCMgU8qmWmyAMSZO5NrRd7rTgErjrm4VASam2u5jrZS0n38V7Y9CzTtLT2qwz5xEChDR4BduoWIr8TfwvXA==", "dev": true, + "license": "ISC", "dependencies": { - "ms": "2.0.0" + "q": "^1.5.1" + }, + "engines": { + "node": ">=10" } }, - "node_modules/compression/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/compression/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", + "node_modules/conventional-changelog-eslint/node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } }, - "node_modules/connect": { - "version": "3.7.0", + "node_modules/conventional-changelog-express": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/conventional-changelog-express/-/conventional-changelog-express-2.0.6.tgz", + "integrity": "sha512-SDez2f3iVJw6V563O3pRtNwXtQaSmEfTCaTBPCqn0oG0mfkq0rX4hHBq5P7De2MncoRixrALj3u3oQsNK+Q0pQ==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "debug": "2.6.9", - "finalhandler": "1.1.2", - "parseurl": "~1.3.3", - "utils-merge": "1.0.1" + "q": "^1.5.1" }, "engines": { - "node": ">= 0.10.0" + "node": ">=10" } }, - "node_modules/connect-history-api-fallback": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", - "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "node_modules/conventional-changelog-express/node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.8" + "node": ">=0.6.0", + "teleport": ">=0.2.0" } }, - "node_modules/connect/node_modules/debug": { - "version": "2.6.9", + "node_modules/conventional-changelog-jquery": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/conventional-changelog-jquery/-/conventional-changelog-jquery-3.0.11.tgz", + "integrity": "sha512-x8AWz5/Td55F7+o/9LQ6cQIPwrCjfJQ5Zmfqi8thwUEKHstEn4kTIofXub7plf1xvFA2TqhZlq7fy5OmV6BOMw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "ms": "2.0.0" + "q": "^1.5.1" + }, + "engines": { + "node": ">=10" } }, - "node_modules/connect/node_modules/finalhandler": { - "version": "1.1.2", + "node_modules/conventional-changelog-jquery/node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", "dev": true, "license": "MIT", + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/conventional-changelog-jshint": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/conventional-changelog-jshint/-/conventional-changelog-jshint-2.0.9.tgz", + "integrity": "sha512-wMLdaIzq6TNnMHMy31hql02OEQ8nCQfExw1SE0hYL5KvU+JCTuPaDO+7JiogGT2gJAxiUGATdtYYfh+nT+6riA==", + "dev": true, + "license": "ISC", "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" + "compare-func": "^2.0.0", + "q": "^1.5.1" }, "engines": { - "node": ">= 0.8" + "node": ">=10" } }, - "node_modules/connect/node_modules/ms": { - "version": "2.0.0", + "node_modules/conventional-changelog-jshint/node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } }, - "node_modules/connect/node_modules/on-finished": { - "version": "2.3.0", + "node_modules/conventional-changelog-preset-loader": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.4.tgz", + "integrity": "sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g==", "dev": true, "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, "engines": { - "node": ">= 0.8" + "node": ">=10" } }, - "node_modules/connect/node_modules/statuses": { - "version": "1.5.0", + "node_modules/conventional-changelog-writer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-5.0.1.tgz", + "integrity": "sha512-5WsuKUfxW7suLblAbFnxAcrvf6r+0b7GvNaWUwUIk0bXMnENP/PEieGKVUQrjPqwPT4o3EPAASBXiY6iHooLOQ==", "dev": true, "license": "MIT", + "dependencies": { + "conventional-commits-filter": "^2.0.7", + "dateformat": "^3.0.0", + "handlebars": "^4.7.7", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "semver": "^6.0.0", + "split": "^1.0.0", + "through2": "^4.0.0" + }, + "bin": { + "conventional-changelog-writer": "cli.js" + }, "engines": { - "node": ">= 0.6" + "node": ">=10" } }, - "node_modules/console-control-strings": { - "version": "1.1.0", + "node_modules/conventional-changelog-writer/node_modules/semver": { + "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" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "node_modules/conventional-commits-filter": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz", + "integrity": "sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA==", "dev": true, + "license": "MIT", "dependencies": { - "safe-buffer": "5.2.1" + "lodash.ismatch": "^4.4.0", + "modify-values": "^1.0.0" }, "engines": { - "node": ">= 0.6" + "node": ">=10" } }, - "node_modules/content-type": { - "version": "1.0.5", + "node_modules/conventional-commits-parser": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.2.4.tgz", + "integrity": "sha512-nK7sAtfi+QXbxHCYfhpZsfRtaitZLIA6889kFIouLvz6repszQDgxBu7wf2WbU+Dco7sAnNCJYERCwt54WPC2Q==", "dev": true, "license": "MIT", + "dependencies": { + "is-text-path": "^1.0.1", + "JSONStream": "^1.0.4", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "split2": "^3.0.0", + "through2": "^4.0.0" + }, + "bin": { + "conventional-commits-parser": "cli.js" + }, "engines": { - "node": ">= 0.6" + "node": ">=10" } }, "node_modules/convert-source-map": { @@ -6897,18 +8749,22 @@ }, "node_modules/cookie": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/cookie-signature": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/cookiejar": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", + "license": "MIT" }, "node_modules/copy-anything": { "version": "2.0.6", @@ -6969,7 +8825,6 @@ }, "node_modules/core-util-is": { "version": "1.0.2", - "dev": true, "license": "MIT" }, "node_modules/cors": { @@ -7103,9 +8958,18 @@ "node": ">=8" } }, + "node_modules/cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", - "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -7116,6 +8980,16 @@ "node": ">= 8" } }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/css-loader": { "version": "6.8.1", "dev": true, @@ -7543,6 +9417,16 @@ "node": ">=12" } }, + "node_modules/dargs": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz", + "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/dashdash": { "version": "1.14.1", "dev": true, @@ -7554,6 +9438,15 @@ "node": ">=0.10" } }, + "node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/data-urls": { "version": "2.0.0", "dev": true, @@ -7637,9 +9530,18 @@ "node": ">=4.0" } }, + "node_modules/dateformat": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/debug": { "version": "4.3.4", - "dev": true, "license": "MIT", "dependencies": { "ms": "2.1.2" @@ -7661,11 +9563,64 @@ "node": ">=0.10.0" } }, + "node_modules/decamelize-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", + "dev": true, + "license": "MIT", + "dependencies": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decamelize-keys/node_modules/map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/decimal.js": { "version": "10.4.3", "dev": true, "license": "MIT" }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/deep-is": { "version": "0.1.4", "dev": true, @@ -7673,9 +9628,8 @@ }, "node_modules/default-gateway": { "version": "6.0.3", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", - "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "execa": "^5.0.0" }, @@ -7695,7 +9649,6 @@ }, "node_modules/define-data-property": { "version": "1.1.4", - "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", @@ -7733,6 +9686,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "license": "MIT", + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/del": { "version": "2.2.2", "dev": true, @@ -7824,7 +9791,6 @@ }, "node_modules/delayed-stream": { "version": "1.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=0.4.0" @@ -7860,11 +9826,30 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/detect-node": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "license": "ISC", + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } }, "node_modules/di": { "version": "0.0.1", @@ -7873,7 +9858,6 @@ }, "node_modules/diff": { "version": "4.0.2", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -7892,9 +9876,8 @@ }, "node_modules/dns-packet": { "version": "5.6.1", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", - "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", "dev": true, + "license": "MIT", "dependencies": { "@leichtgewicht/ip-codec": "^2.0.1" }, @@ -7994,6 +9977,19 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/dotenv": { "version": "10.0.0", "dev": true, @@ -8007,6 +10003,45 @@ "dev": true, "license": "MIT" }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "license": "BSD-3-Clause", + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/duplexer2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/duplexer2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/duplexer2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "dev": true, @@ -8028,27 +10063,43 @@ }, "node_modules/ejs": { "version": "3.1.10", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", - "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.728", + "dev": true, + "license": "ISC" + }, + "node_modules/elementtree": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/elementtree/-/elementtree-0.1.7.tgz", + "integrity": "sha512-wkgGT6kugeQk/P6VZ/f4T+4HB41BVgNBq5CDIZVbQ02nvTVqAiVTbskxxu3eA/X96lMlfYOwnLQpN2v5E1zDEg==", + "license": "Apache-2.0", "dependencies": { - "jake": "^10.8.5" - }, - "bin": { - "ejs": "bin/cli.js" + "sax": "1.1.4" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4.0" } }, - "node_modules/electron-to-chromium": { - "version": "1.4.728", - "dev": true, + "node_modules/elementtree/node_modules/sax": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.1.4.tgz", + "integrity": "sha512-5f3k2PbGGp+YtKJjOItpg3P99IMD84E4HOvcfleTb5joCHNXYLsR9yWFPOYGgaeMPDubQILTCMdsFb2OMeOjtg==", "license": "ISC" }, "node_modules/emoji-regex": { "version": "8.0.0", - "dev": true, "license": "MIT" }, "node_modules/emojis-list": { @@ -8078,14 +10129,15 @@ }, "node_modules/end-of-stream": { "version": "1.4.4", - "dev": true, "license": "MIT", "dependencies": { "once": "^1.4.0" } }, "node_modules/engine.io": { - "version": "6.5.4", + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz", + "integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==", "dev": true, "license": "MIT", "dependencies": { @@ -8098,7 +10150,7 @@ "cors": "~2.8.5", "debug": "~4.3.1", "engine.io-parser": "~5.2.1", - "ws": "~8.11.0" + "ws": "~8.17.1" }, "engines": { "node": ">=10.2.0" @@ -8121,7 +10173,9 @@ } }, "node_modules/engine.io/node_modules/ws": { - "version": "8.11.0", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "dev": true, "license": "MIT", "engines": { @@ -8129,7 +10183,7 @@ }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -8273,7 +10327,6 @@ }, "node_modules/es-define-property": { "version": "1.0.0", - "dev": true, "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.4" @@ -8284,7 +10337,6 @@ }, "node_modules/es-errors": { "version": "1.3.0", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -8418,7 +10470,6 @@ }, "node_modules/escape-string-regexp": { "version": "1.0.5", - "dev": true, "license": "MIT", "engines": { "node": ">=0.8.0" @@ -8426,7 +10477,6 @@ }, "node_modules/escodegen": { "version": "2.1.0", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "esprima": "^4.0.1", @@ -8446,7 +10496,6 @@ }, "node_modules/escodegen/node_modules/estraverse": { "version": "5.3.0", - "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -8454,7 +10503,6 @@ }, "node_modules/escodegen/node_modules/source-map": { "version": "0.6.1", - "dev": true, "license": "BSD-3-Clause", "optional": true, "engines": { @@ -8666,9 +10714,8 @@ }, "node_modules/eslint-plugin-unused-imports": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-3.2.0.tgz", - "integrity": "sha512-6uXyn6xdINEpxE1MtDjxQsyXB37lfyO2yKGVVgtD7WEWQGORSOZjgrD6hBhvGv4/SO+TOlS+UnC6JppRqbuwGQ==", "dev": true, + "license": "MIT", "dependencies": { "eslint-rule-composer": "^0.3.0" }, @@ -8956,7 +11003,6 @@ }, "node_modules/esprima": { "version": "4.0.1", - "dev": true, "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", @@ -9014,7 +11060,6 @@ }, "node_modules/esutils": { "version": "2.0.3", - "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" @@ -9022,9 +11067,8 @@ }, "node_modules/etag": { "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -9049,9 +11093,8 @@ }, "node_modules/execa": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, + "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -9077,6 +11120,16 @@ "node": ">= 0.8.0" } }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "dev": true, + "license": "(MIT OR WTFPL)", + "engines": { + "node": ">=6" + } + }, "node_modules/exponential-backoff": { "version": "3.1.1", "dev": true, @@ -9084,9 +11137,8 @@ }, "node_modules/express": { "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "dev": true, + "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", @@ -9126,18 +11178,16 @@ }, "node_modules/express/node_modules/debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/express/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/extend": { "version": "3.0.2", @@ -9146,7 +11196,6 @@ }, "node_modules/external-editor": { "version": "3.1.0", - "dev": true, "license": "MIT", "dependencies": { "chardet": "^0.7.0", @@ -9159,7 +11208,6 @@ }, "node_modules/external-editor/node_modules/iconv-lite": { "version": "0.4.24", - "dev": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" @@ -9180,6 +11228,13 @@ "version": "3.1.3", "license": "MIT" }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true, + "license": "MIT" + }, "node_modules/fast-glob": { "version": "3.3.2", "dev": true, @@ -9204,6 +11259,12 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "license": "MIT" + }, "node_modules/fastq": { "version": "1.16.0", "dev": true, @@ -9214,9 +11275,8 @@ }, "node_modules/faye-websocket": { "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", "dev": true, + "license": "Apache-2.0", "dependencies": { "websocket-driver": ">=0.5.1" }, @@ -9224,9 +11284,18 @@ "node": ">=0.8.0" } }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, "node_modules/figures": { "version": "3.2.0", - "dev": true, "license": "MIT", "dependencies": { "escape-string-regexp": "^1.0.5" @@ -9285,6 +11354,7 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "devOptional": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -9294,9 +11364,8 @@ }, "node_modules/finalhandler": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", "dev": true, + "license": "MIT", "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", @@ -9312,18 +11381,16 @@ }, "node_modules/finalhandler/node_modules/debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/finalhandler/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/find-cache-dir": { "version": "4.0.0", @@ -9452,11 +11519,25 @@ "node": ">= 6" } }, + "node_modules/formidable": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.1.tgz", + "integrity": "sha512-WJWKelbRHN41m5dumb0/k8TeAx7Id/y3a+Z7QfhxP/htI9Js5zYaEDtG8uMgG0vM0lOlqnmjE99/kfpOYi/0Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "dezalgo": "^1.0.4", + "hexoid": "^1.0.0", + "once": "^1.4.0" + }, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, "node_modules/forwarded": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -9475,9 +11556,8 @@ }, "node_modules/fresh": { "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -9526,40 +11606,255 @@ }, "node_modules/fs.realpath": { "version": "1.0.0", + "license": "ISC" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gauge": { + "version": "4.0.4", + "dev": true, + "license": "ISC", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-pkg-repo": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz", + "integrity": "sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@hutson/parse-repository-url": "^3.0.0", + "hosted-git-info": "^4.0.0", + "through2": "^2.0.0", + "yargs": "^16.2.0" + }, + "bin": { + "get-pkg-repo": "src/cli.js" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-pkg-repo/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/get-pkg-repo/node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/get-pkg-repo/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/get-pkg-repo/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/get-pkg-repo/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/get-pkg-repo/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/get-pkg-repo/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/get-pkg-repo/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true, "license": "ISC" }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "node_modules/get-pkg-repo/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/get-pkg-repo/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], + "license": "ISC", "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": ">=10" } }, - "node_modules/function-bind": { - "version": "1.1.2", + "node_modules/get-stream": { + "version": "6.0.1", "dev": true, "license": "MIT", + "engines": { + "node": ">=10" + }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/function.prototype.name": { - "version": "1.1.6", + "node_modules/get-symbol-description": { + "version": "1.0.2", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" }, "engines": { "node": ">= 0.4" @@ -9568,110 +11863,159 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "dev": true, + "node_modules/get-uri": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz", + "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==", "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4", + "fs-extra": "^11.2.0" + }, + "engines": { + "node": ">= 14" } }, - "node_modules/gauge": { - "version": "4.0.4", - "dev": true, - "license": "ISC", + "node_modules/get-uri/node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "license": "MIT", "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=14.14" } }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "dev": true, + "node_modules/get-uri/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/get-uri/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "license": "MIT", "engines": { - "node": ">=6.9.0" + "node": ">= 10.0.0" } }, - "node_modules/get-caller-file": { - "version": "2.0.5", + "node_modules/getpass": { + "version": "0.1.7", "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0" } }, - "node_modules/get-intrinsic": { - "version": "1.2.4", + "node_modules/git-raw-commits": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz", + "integrity": "sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==", "dev": true, "license": "MIT", "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "dargs": "^7.0.0", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "split2": "^3.0.0", + "through2": "^4.0.0" }, - "engines": { - "node": ">= 0.4" + "bin": { + "git-raw-commits": "cli.js" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=10" } }, - "node_modules/get-package-type": { - "version": "0.1.0", + "node_modules/git-remote-origin-url": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz", + "integrity": "sha512-eU+GGrZgccNJcsDH5LkXR3PB9M958hxc7sbA8DFJjrv9j4L2P/eZfKhM+QD6wyzpiv+b1BpK0XrYCxkovtjSLw==", "dev": true, "license": "MIT", + "dependencies": { + "gitconfiglocal": "^1.0.0", + "pify": "^2.3.0" + }, "engines": { - "node": ">=8.0.0" + "node": ">=4" } }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "node_modules/git-remote-origin-url/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "dev": true, + "license": "MIT", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/get-symbol-description": { - "version": "1.0.2", + "node_modules/git-semver-tags": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-4.1.1.tgz", + "integrity": "sha512-OWyMt5zBe7xFs8vglMmhM9lRQzCWL3WjHtxNNfJTMngGym7pC1kh8sP6jevfydJ6LP3ZvGxfb6ABYgPUM0mtsA==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4" + "meow": "^8.0.0", + "semver": "^6.0.0" }, - "engines": { - "node": ">= 0.4" + "bin": { + "git-semver-tags": "cli.js" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=10" } }, - "node_modules/getpass": { - "version": "0.1.7", + "node_modules/git-semver-tags/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "license": "MIT", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/gitconfiglocal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz", + "integrity": "sha512-spLUXeTAVHxDtKsJc8FkFVgFtMdEN9qPGpL23VfSHx4fP4+Ds097IXLvymbnDH8FnmxX5Nr9bPw3A+AQ6mWEaQ==", + "dev": true, + "license": "BSD", "dependencies": { - "assert-plus": "^1.0.0" + "ini": "^1.3.2" } }, + "node_modules/gitconfiglocal/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "dev": true, + "license": "MIT" + }, "node_modules/glob": { "version": "10.3.12", "dev": true, @@ -9781,7 +12125,6 @@ }, "node_modules/gopd": { "version": "1.0.1", - "dev": true, "license": "MIT", "dependencies": { "get-intrinsic": "^1.1.3" @@ -9792,9 +12135,21 @@ }, "node_modules/graceful-fs": { "version": "4.2.11", - "dev": true, "license": "ISC" }, + "node_modules/gradle-to-js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/gradle-to-js/-/gradle-to-js-2.0.1.tgz", + "integrity": "sha512-is3hDn9zb8XXnjbEeAEIqxTpLHUiGBqjegLmXPuyMBfKAggpadWFku4/AP8iYAGBX6qR9/5UIUIp47V0XI3aMw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "lodash.merge": "^4.6.2" + }, + "bin": { + "gradle-to-js": "cli.js" + } + }, "node_modules/graphemer": { "version": "1.4.0", "dev": true, @@ -9820,9 +12175,40 @@ }, "node_modules/handle-thing": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/handlebars/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } }, "node_modules/har-schema": { "version": "2.0.0", @@ -9864,6 +12250,16 @@ "dev": true, "license": "MIT" }, + "node_modules/hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/has-ansi": { "version": "2.0.0", "dev": true, @@ -9901,7 +12297,6 @@ }, "node_modules/has-property-descriptors": { "version": "1.0.2", - "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" @@ -9912,7 +12307,6 @@ }, "node_modules/has-proto": { "version": "1.0.3", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -9923,7 +12317,6 @@ }, "node_modules/has-symbols": { "version": "1.0.3", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -9953,7 +12346,6 @@ }, "node_modules/hasown": { "version": "2.0.2", - "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -9977,6 +12369,25 @@ "dev": true, "license": "MIT" }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/hexoid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", + "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/hosted-git-info": { "version": "6.1.1", "dev": true, @@ -9998,9 +12409,8 @@ }, "node_modules/hpack.js": { "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", "dev": true, + "license": "MIT", "dependencies": { "inherits": "^2.0.1", "obuf": "^1.0.0", @@ -10010,9 +12420,8 @@ }, "node_modules/hpack.js/node_modules/readable-stream": { "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, + "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -10025,15 +12434,13 @@ }, "node_modules/hpack.js/node_modules/safe-buffer": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/hpack.js/node_modules/string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" } @@ -10051,8 +12458,6 @@ }, "node_modules/html-entities": { "version": "2.5.2", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", - "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", "dev": true, "funding": [ { @@ -10063,7 +12468,8 @@ "type": "patreon", "url": "https://patreon.com/mdevils" } - ] + ], + "license": "MIT" }, "node_modules/html-escaper": { "version": "2.0.2", @@ -10095,9 +12501,8 @@ }, "node_modules/http-deceiver": { "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/http-errors": { "version": "2.0.0", @@ -10116,9 +12521,8 @@ }, "node_modules/http-parser-js": { "version": "0.5.8", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", - "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/http-proxy": { "version": "1.18.1", @@ -10148,9 +12552,8 @@ }, "node_modules/http-proxy-middleware": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", - "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", "dev": true, + "license": "MIT", "dependencies": { "@types/http-proxy": "^1.17.8", "http-proxy": "^1.18.1", @@ -10198,9 +12601,8 @@ }, "node_modules/human-signals": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=10.17.0" } @@ -10260,6 +12662,13 @@ "node": ">= 4" } }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, "node_modules/ignore-walk": { "version": "6.0.4", "dev": true, @@ -10340,7 +12749,6 @@ }, "node_modules/imurmurhash": { "version": "0.1.4", - "dev": true, "license": "MIT", "engines": { "node": ">=0.8.19" @@ -10361,7 +12769,6 @@ }, "node_modules/inflight": { "version": "1.0.6", - "dev": true, "license": "ISC", "dependencies": { "once": "^1.3.0", @@ -10501,7 +12908,6 @@ }, "node_modules/ip-address": { "version": "9.0.5", - "dev": true, "license": "MIT", "dependencies": { "jsbn": "1.1.0", @@ -10513,19 +12919,16 @@ }, "node_modules/ip-address/node_modules/jsbn": { "version": "1.1.0", - "dev": true, "license": "MIT" }, "node_modules/ip-address/node_modules/sprintf-js": { "version": "1.1.3", - "dev": true, "license": "BSD-3-Clause" }, "node_modules/ipaddr.js": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", - "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10" } @@ -10653,7 +13056,6 @@ }, "node_modules/is-docker": { "version": "2.2.1", - "dev": true, "license": "MIT", "bin": { "is-docker": "cli.js" @@ -10675,7 +13077,6 @@ }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -10720,6 +13121,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "devOptional": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -10738,6 +13140,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-path-cwd": { "version": "1.0.0", "dev": true, @@ -10778,9 +13190,8 @@ }, "node_modules/is-plain-obj": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -10835,7 +13246,6 @@ }, "node_modules/is-stream": { "version": "2.0.1", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -10872,6 +13282,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-text-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", + "integrity": "sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "text-extensions": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-typed-array": { "version": "1.1.13", "dev": true, @@ -10888,7 +13311,6 @@ }, "node_modules/is-typedarray": { "version": "1.0.0", - "dev": true, "license": "MIT" }, "node_modules/is-unicode-supported": { @@ -10919,7 +13341,6 @@ }, "node_modules/is-wsl": { "version": "2.2.0", - "dev": true, "license": "MIT", "dependencies": { "is-docker": "^2.0.0" @@ -10930,7 +13351,6 @@ }, "node_modules/isarray": { "version": "1.0.0", - "dev": true, "license": "MIT" }, "node_modules/isbinaryfile": { @@ -10946,7 +13366,6 @@ }, "node_modules/isexe": { "version": "2.0.0", - "dev": true, "license": "ISC" }, "node_modules/isobject": { @@ -11357,6 +13776,13 @@ "dev": true, "license": "MIT" }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true, + "license": "MIT" + }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "dev": true, @@ -11412,6 +13838,23 @@ ], "license": "MIT" }, + "node_modules/JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, "node_modules/jsprim": { "version": "1.4.2", "dev": true, @@ -11755,6 +14198,16 @@ "node": ">=0.10.0" } }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/klona": { "version": "2.0.6", "dev": true, @@ -11765,14 +14218,39 @@ }, "node_modules/launch-editor": { "version": "2.6.1", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.1.tgz", - "integrity": "sha512-eB/uXmFVpY4zezmGp5XtU21kwo7GBbKB+EQ+UZeWtGb9yAM5xt/Evk+lYH3eRNAtId+ej4u7TYPFZ07w4s7rRw==", "dev": true, + "license": "MIT", "dependencies": { "picocolors": "^1.0.0", "shell-quote": "^1.8.1" } }, + "node_modules/leek": { + "version": "0.0.24", + "resolved": "https://registry.npmjs.org/leek/-/leek-0.0.24.tgz", + "integrity": "sha512-6PVFIYXxlYF0o6hrAsHtGpTmi06otkwNrMcmQ0K96SeSRHPREPa9J3nJZ1frliVH7XT0XFswoJFQoXsDukzGNQ==", + "license": "MIT", + "dependencies": { + "debug": "^2.1.0", + "lodash.assign": "^3.2.0", + "rsvp": "^3.0.21" + } + }, + "node_modules/leek/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/leek/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, "node_modules/less": { "version": "4.2.0", "dev": true, @@ -11869,6 +14347,46 @@ "dev": true, "license": "MIT" }, + "node_modules/load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/load-json-file/node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/load-json-file/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/loader-runner": { "version": "4.3.0", "dev": true, @@ -11898,23 +14416,114 @@ }, "node_modules/lodash": { "version": "4.17.21", - "dev": true, "license": "MIT" }, "node_modules/lodash-es": { "version": "4.17.21", "license": "MIT" }, + "node_modules/lodash._baseassign": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", + "integrity": "sha512-t3N26QR2IdSN+gqSy9Ds9pBu/J1EAFEshKlUHpJG3rvyJOYgcELIxcIeKKfZk7sjOz11cFfzJRsyFry/JyabJQ==", + "license": "MIT", + "dependencies": { + "lodash._basecopy": "^3.0.0", + "lodash.keys": "^3.0.0" + } + }, + "node_modules/lodash._basecopy": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha512-rFR6Vpm4HeCK1WPGvjZSJ+7yik8d8PVUdCJx5rT2pogG4Ve/2ZS7kfmO5l5T2o5V2mqlNIfSF5MZlr1+xOoYQQ==", + "license": "MIT" + }, + "node_modules/lodash._bindcallback": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz", + "integrity": "sha512-2wlI0JRAGX8WEf4Gm1p/mv/SZ+jLijpj0jyaE/AXeuQphzCgD8ZQW4oSpoN8JAopujOFGU3KMuq7qfHBWlGpjQ==", + "license": "MIT" + }, + "node_modules/lodash._createassigner": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz", + "integrity": "sha512-LziVL7IDnJjQeeV95Wvhw6G28Z8Q6da87LWKOPWmzBLv4u6FAT/x5v00pyGW0u38UoogNF2JnD3bGgZZDaNEBw==", + "license": "MIT", + "dependencies": { + "lodash._bindcallback": "^3.0.0", + "lodash._isiterateecall": "^3.0.0", + "lodash.restparam": "^3.0.0" + } + }, + "node_modules/lodash._getnative": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha512-RrL9VxMEPyDMHOd9uFbvMe8X55X16/cGM5IgOKgRElQZutpX89iS6vwl64duTV1/16w5JY7tuFNXqoekmh1EmA==", + "license": "MIT" + }, + "node_modules/lodash._isiterateecall": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha512-De+ZbrMu6eThFti/CSzhRvTKMgQToLxbij58LMfM8JnYDNSOjkjTCIaa8ixglOeGh2nyPlakbt5bJWJ7gvpYlQ==", + "license": "MIT" + }, + "node_modules/lodash.assign": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-3.2.0.tgz", + "integrity": "sha512-/VVxzgGBmbphasTg51FrztxQJ/VgAUpol6zmJuSVSGcNg4g7FA4z7rQV8Ovr9V3vFBNWZhvKWHfpAytjTVUfFA==", + "license": "MIT", + "dependencies": { + "lodash._baseassign": "^3.0.0", + "lodash._createassigner": "^3.0.0", + "lodash.keys": "^3.0.0" + } + }, "node_modules/lodash.debounce": { "version": "4.0.8", "dev": true, "license": "MIT" }, + "node_modules/lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==", + "license": "MIT" + }, + "node_modules/lodash.isarray": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha512-JwObCrNJuT0Nnbuecmqr5DgtuBppuCvGD9lxjFpAzwnVtdGoDQ1zig+5W8k5/6Gcn0gZ3936HDAlGd28i7sOGQ==", + "license": "MIT" + }, + "node_modules/lodash.ismatch": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", + "integrity": "sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha512-CuBsapFjcubOGMn3VD+24HOAPxM79tH+V6ivJL3CHYjtrawauDJHUk//Yew9Hvc6e9rbCrURGk8z6PC+8WJBfQ==", + "license": "MIT", + "dependencies": { + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + } + }, "node_modules/lodash.merge": { "version": "4.6.2", "dev": true, "license": "MIT" }, + "node_modules/lodash.restparam": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", + "integrity": "sha512-L4/arjjuq4noiUJpt3yS6KIKDtJwNe2fIYgMqyYYKoeIfV1iEqvPwhCx23o+R9dzouGihDAPN1dTIRWa7zk8tw==", + "license": "MIT" + }, "node_modules/log-symbols": { "version": "4.1.0", "license": "MIT", @@ -12006,6 +14615,18 @@ "yallist": "^3.0.2" } }, + "node_modules/macos-release": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.5.1.tgz", + "integrity": "sha512-DXqXhEM7gW59OjZO8NIjBCz9AQ1BEMrfiOAl4AYByHCtVHRF4KoGNO8mqQeM8lRCtQe/UnJ4imO/d2HdkKsd+A==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/magic-string": { "version": "0.30.1", "dev": true, @@ -12234,6 +14855,19 @@ "dev": true, "license": "ISC" }, + "node_modules/map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/media-typer": { "version": "0.3.0", "dev": true, @@ -12253,30 +14887,230 @@ "node": ">= 4.0.0" } }, + "node_modules/meow": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", + "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/meow/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/meow/node_modules/normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/meow/node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/read-pkg/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true, + "license": "ISC" + }, + "node_modules/meow/node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/meow/node_modules/read-pkg/node_modules/semver": { + "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" + } + }, + "node_modules/meow/node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/meow/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/merge-descriptors": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } }, - "node_modules/merge-stream": { - "version": "2.0.0", + "node_modules/mergexml": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/mergexml/-/mergexml-1.2.4.tgz", + "integrity": "sha512-yiOlDqcVCz7AG1eSboonc18FTlfqDEKYfGoAV3Lul98u6YRV/s0kjtf4bjk47t0hLTFJR0BSYMd6BpmX3xDjNQ==", "dev": true, - "license": "MIT" + "license": "ISC", + "dependencies": { + "@xmldom/xmldom": "^0.7.0", + "formidable": "^3.5.1", + "xpath": "0.0.27" + } }, - "node_modules/merge2": { - "version": "1.4.1", + "node_modules/mergexml/node_modules/xpath": { + "version": "0.0.27", + "resolved": "https://registry.npmjs.org/xpath/-/xpath-0.0.27.tgz", + "integrity": "sha512-fg03WRxtkCV6ohClePNAECYsmpKKTv5L8y/X3Dn1hQrec3POx2jHZ/0P2qQ6HvsrU1BmeqXcof3NGGueG6LxwQ==", "dev": true, "license": "MIT", "engines": { - "node": ">= 8" + "node": ">=0.6.0" } }, "node_modules/methods": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -12306,7 +15140,6 @@ }, "node_modules/mime-db": { "version": "1.52.0", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -12314,7 +15147,6 @@ }, "node_modules/mime-types": { "version": "2.1.35", - "dev": true, "license": "MIT", "dependencies": { "mime-db": "1.52.0" @@ -12330,6 +15162,29 @@ "node": ">=6" } }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/mini-css-extract-plugin": { "version": "2.7.6", "dev": true, @@ -12350,13 +15205,11 @@ }, "node_modules/minimalistic-assert": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/minimatch": { "version": "3.1.2", - "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -12367,15 +15220,38 @@ }, "node_modules/minimist": { "version": "1.2.8", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/minimist-options/node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/minipass": { "version": "5.0.0", - "dev": true, "license": "ISC", "engines": { "node": ">=8" @@ -12548,7 +15424,6 @@ }, "node_modules/minizlib": { "version": "2.1.2", - "dev": true, "license": "MIT", "dependencies": { "minipass": "^3.0.0", @@ -12560,7 +15435,6 @@ }, "node_modules/minizlib/node_modules/minipass": { "version": "3.3.6", - "dev": true, "license": "ISC", "dependencies": { "yallist": "^4.0.0" @@ -12571,12 +15445,10 @@ }, "node_modules/minizlib/node_modules/yallist": { "version": "4.0.0", - "dev": true, "license": "ISC" }, "node_modules/mkdirp": { "version": "1.0.4", - "dev": true, "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" @@ -12585,6 +15457,23 @@ "node": ">=10" } }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true, + "license": "MIT" + }, + "node_modules/modify-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", + "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/mrmime": { "version": "1.0.1", "dev": true, @@ -12595,14 +15484,12 @@ }, "node_modules/ms": { "version": "2.1.2", - "dev": true, "license": "MIT" }, "node_modules/multicast-dns": { "version": "7.2.5", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", - "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", "dev": true, + "license": "MIT", "dependencies": { "dns-packet": "^5.2.2", "thunky": "^1.0.2" @@ -12613,7 +15500,6 @@ }, "node_modules/mute-stream": { "version": "0.0.8", - "dev": true, "license": "ISC" }, "node_modules/nanoid": { @@ -12633,6 +15519,59 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", + "dev": true, + "license": "MIT" + }, + "node_modules/native-run": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/native-run/-/native-run-1.7.4.tgz", + "integrity": "sha512-yDEwTp66vmXpqFiSQzz4sVQgyq5U58gGRovglY4GHh12ITyWa6mh6Lbpm2gViVOVD1JYFtYnwcgr7GTFBinXNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ionic/utils-fs": "^3.1.6", + "@ionic/utils-terminal": "^2.3.3", + "bplist-parser": "^0.3.2", + "debug": "^4.3.4", + "elementtree": "^0.1.7", + "ini": "^3.0.1", + "plist": "^3.0.6", + "split2": "^4.1.0", + "through2": "^4.0.2", + "tslib": "^2.4.0", + "yauzl": "^2.10.0" + }, + "bin": { + "native-run": "bin/native-run" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/native-run/node_modules/ini": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.1.tgz", + "integrity": "sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/native-run/node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "dev": true, @@ -12667,6 +15606,15 @@ "dev": true, "license": "MIT" }, + "node_modules/netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/ng2-charts": { "version": "4.1.1", "license": "ISC", @@ -12705,18 +15653,17 @@ "@angular/core": ">=15.0.0" } }, - "node_modules/nice-napi": { - "version": "1.0.2", + "node_modules/node-abi": { + "version": "3.65.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.65.0.tgz", + "integrity": "sha512-ThjYBfoDNr08AWx6hGaRbfPwxKV9kVzAzOzlLKbk2CuqXE2xnCh+cbAGnwM3t8Lq4v9rUB7VfondlkBckcJrVA==", "dev": true, - "hasInstallScript": true, "license": "MIT", - "optional": true, - "os": [ - "!win32" - ], "dependencies": { - "node-addon-api": "^3.0.0", - "node-gyp-build": "^4.2.2" + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" } }, "node_modules/node-addon-api": { @@ -12724,73 +15671,251 @@ "dev": true, "license": "MIT" }, - "node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", - "dev": true, - "engines": { - "node": ">= 6.13.0" - } - }, - "node_modules/node-gyp": { - "version": "9.4.1", + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "dev": true, + "license": "(BSD-3-Clause OR GPL-2.0)", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-gyp": { + "version": "9.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^10.0.3", + "nopt": "^6.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^12.13 || ^14.13 || >=16" + } + }, + "node_modules/node-gyp-build": { + "version": "4.8.0", + "dev": true, + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-gyp/node_modules/glob": { + "version": "7.2.3", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-html-parser": { + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-5.4.2.tgz", + "integrity": "sha512-RaBPP3+51hPne/OolXxcz89iYvQvKOydaqoePpOgXcrOKZhjVIzmpKZz+Hd/RBO2/zN2q6CNJhQzucVz+u3Jyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-select": "^4.2.1", + "he": "1.2.0" + } + }, + "node_modules/node-html-parser/node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/node-html-parser/node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/node-html-parser/node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/node-html-parser/node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/node-html-parser/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/node-releases": { + "version": "2.0.14", + "dev": true, + "license": "MIT" + }, + "node_modules/nodemon": { + "version": "2.0.22", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", + "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", "dev": true, "license": "MIT", "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^10.0.3", - "nopt": "^6.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" }, "bin": { - "node-gyp": "bin/node-gyp.js" + "nodemon": "bin/nodemon.js" }, "engines": { - "node": "^12.13 || ^14.13 || >=16" + "node": ">=8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" } }, - "node_modules/node-gyp-build": { - "version": "4.8.0", + "node_modules/nodemon/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "license": "MIT", - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" + "dependencies": { + "ms": "^2.1.1" } }, - "node_modules/node-gyp/node_modules/glob": { - "version": "7.2.3", + "node_modules/nodemon/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "bin": { + "semver": "bin/semver" } }, - "node_modules/node-releases": { - "version": "2.0.14", - "dev": true, - "license": "MIT" - }, "node_modules/nopt": { "version": "6.0.0", "dev": true, @@ -13001,7 +16126,6 @@ }, "node_modules/npm-run-path": { "version": "4.0.1", - "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.0.0" @@ -13010,6 +16134,20 @@ "node": ">=8" } }, + "node_modules/npm-watch": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/npm-watch/-/npm-watch-0.9.0.tgz", + "integrity": "sha512-C5Rgh5+jvY33K1EH8Qjr1hfpH9Nhasc90QJ0W+JyKg2ogE0LOCZI4xirC8QmywW7XinyBpynwxlrN6aPfjc3Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "nodemon": "^2.0.7", + "through2": "^4.0.2" + }, + "bin": { + "npm-watch": "cli.js" + } + }, "node_modules/npmlog": { "version": "6.0.2", "dev": true, @@ -13361,7 +16499,6 @@ }, "node_modules/object-inspect": { "version": "1.13.1", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -13448,9 +16585,8 @@ }, "node_modules/obuf": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/on-finished": { "version": "2.4.1", @@ -13465,16 +16601,14 @@ }, "node_modules/on-headers": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/once": { "version": "1.4.0", - "dev": true, "license": "ISC", "dependencies": { "wrappy": "1" @@ -13600,9 +16734,24 @@ "node": ">=8" } }, + "node_modules/os-name": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/os-name/-/os-name-4.0.1.tgz", + "integrity": "sha512-xl9MAoU97MH1Xt5K9ERft2YfCAoaO6msy1OBA0ozxEC0x0TmIoE6K3QvgJMMZA9yKGLmHXNY/YZoDbiGDj4zYw==", + "license": "MIT", + "dependencies": { + "macos-release": "^2.5.0", + "windows-release": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/os-tmpdir": { "version": "1.0.2", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -13649,9 +16798,8 @@ }, "node_modules/p-retry": { "version": "4.6.2", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", - "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/retry": "0.12.0", "retry": "^0.13.1" @@ -13662,9 +16810,8 @@ }, "node_modules/p-retry/node_modules/retry": { "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } @@ -13677,6 +16824,90 @@ "node": ">=6" } }, + "node_modules/pac-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.2.tgz", + "integrity": "sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==", + "license": "MIT", + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.5", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/socks-proxy-agent": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", + "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.1", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "license": "MIT", + "dependencies": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/pacote": { "version": "15.2.0", "dev": true, @@ -13818,7 +17049,6 @@ }, "node_modules/path-is-absolute": { "version": "1.0.1", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -13831,7 +17061,6 @@ }, "node_modules/path-key": { "version": "3.1.1", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -13867,9 +17096,8 @@ }, "node_modules/path-to-regexp": { "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/path-type": { "version": "4.0.0", @@ -13879,6 +17107,13 @@ "node": ">=8" } }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true, + "license": "MIT" + }, "node_modules/performance-now": { "version": "2.1.0", "dev": true, @@ -14030,6 +17265,41 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/plist": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz", + "integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + }, + "engines": { + "node": ">=10.4.0" + } + }, + "node_modules/plist/node_modules/@xmldom/xmldom": { + "version": "0.8.10", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz", + "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/plist/node_modules/xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0" + } + }, "node_modules/possible-typed-array-names": { "version": "1.0.0", "dev": true, @@ -14158,6 +17428,53 @@ "dev": true, "license": "MIT" }, + "node_modules/prebuild-install": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz", + "integrity": "sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prebuild-install/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true, + "license": "ISC" + }, + "node_modules/prebuild-install/node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "license": "MIT", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "dev": true, @@ -14166,6 +17483,22 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/pretty-bytes": { "version": "5.6.0", "dev": true, @@ -14187,7 +17520,6 @@ }, "node_modules/process-nextick-args": { "version": "2.0.1", - "dev": true, "license": "MIT" }, "node_modules/promise-inflight": { @@ -14207,6 +17539,30 @@ "node": ">=10" } }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prompts/node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/protractor": { "version": "7.0.0", "dev": true, @@ -14447,9 +17803,8 @@ }, "node_modules/proxy-addr": { "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "dev": true, + "license": "MIT", "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -14460,16 +17815,94 @@ }, "node_modules/proxy-addr/node_modules/ipaddr.js": { "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.10" } }, + "node_modules/proxy-agent": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz", + "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.3", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.0.1", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/proxy-agent/node_modules/socks-proxy-agent": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", + "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.1", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", - "dev": true, "license": "MIT" }, "node_modules/prr": { @@ -14483,9 +17916,15 @@ "dev": true, "license": "MIT" }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, "node_modules/pump": { "version": "3.0.0", - "dev": true, "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", @@ -14518,7 +17957,6 @@ }, "node_modules/qs": { "version": "6.11.0", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.0.4" @@ -14554,6 +17992,23 @@ ], "license": "MIT" }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", + "dev": true, + "license": "MIT" + }, + "node_modules/quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/randombytes": { "version": "2.1.0", "dev": true, @@ -14603,6 +18058,39 @@ "node": ">=0.10.0" } }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/read-package-json": { "version": "6.0.4", "dev": true, @@ -14645,6 +18133,161 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true, + "license": "ISC" + }, + "node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/read-pkg/node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/semver": { + "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" + } + }, "node_modules/readable-stream": { "version": "3.6.0", "license": "MIT", @@ -14668,6 +18311,20 @@ "node": ">=8.10.0" } }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/reflect-metadata": { "version": "0.1.14", "dev": true, @@ -14683,78 +18340,217 @@ "dev": true, "license": "MIT", "dependencies": { - "regenerate": "^1.4.2" + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "license": "MIT" + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regex-parser": { + "version": "2.3.0", + "dev": true, + "license": "MIT" + }, + "node_modules/regexp-to-ast": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/regexp-to-ast/-/regexp-to-ast-0.5.0.tgz", + "integrity": "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==", + "dev": true, + "license": "MIT" + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/replace": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/replace/-/replace-1.2.2.tgz", + "integrity": "sha512-C4EDifm22XZM2b2JOYe6Mhn+lBsLBAvLbK8drfUQLTfD1KYl/n3VaW/CDju0Ny4w3xTtegBpg8YNSpFJPUDSjA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "2.4.2", + "minimatch": "3.0.5", + "yargs": "^15.3.1" + }, + "bin": { + "replace": "bin/replace.js", + "search": "bin/search.js" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/replace/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/replace/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/replace/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" }, "engines": { - "node": ">=4" + "node": ">=7.0.0" } }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "license": "MIT" - }, - "node_modules/regenerator-transform": { - "version": "0.15.2", + "node_modules/replace/node_modules/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "@babel/runtime": "^7.8.4" + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, - "node_modules/regex-parser": { - "version": "2.3.0", - "dev": true, - "license": "MIT" - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.2", + "node_modules/replace/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.6", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "set-function-name": "^2.0.1" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/regexpu-core": { - "version": "5.3.2", + "node_modules/replace/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/replace/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/regjsgen": "^0.8.0", - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsparser": "^0.9.1", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.1.0" + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/regjsparser": { - "version": "0.9.1", + "node_modules/replace/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "dev": true, - "license": "BSD-2-Clause", + "license": "ISC", "dependencies": { - "jsesc": "~0.5.0" + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" + "engines": { + "node": ">=6" } }, "node_modules/request": { @@ -14948,7 +18744,6 @@ }, "node_modules/rimraf": { "version": "3.0.2", - "dev": true, "license": "ISC", "dependencies": { "glob": "^7.1.3" @@ -14962,7 +18757,6 @@ }, "node_modules/rimraf/node_modules/glob": { "version": "7.2.3", - "dev": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -15002,9 +18796,17 @@ "fsevents": "~2.3.2" } }, + "node_modules/rsvp": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-3.6.2.tgz", + "integrity": "sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw==", + "license": "MIT", + "engines": { + "node": "0.12.* || 4.* || 6.* || >= 7.*" + } + }, "node_modules/run-async": { "version": "2.4.1", - "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -15239,9 +19041,8 @@ }, "node_modules/select-hose": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/selenium-webdriver": { "version": "3.6.0", @@ -15300,9 +19101,8 @@ }, "node_modules/selfsigned": { "version": "2.4.1", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", - "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", "dev": true, + "license": "MIT", "dependencies": { "@types/node-forge": "^1.3.0", "node-forge": "^1" @@ -15313,7 +19113,6 @@ }, "node_modules/semver": { "version": "7.6.0", - "dev": true, "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" @@ -15327,7 +19126,6 @@ }, "node_modules/semver/node_modules/lru-cache": { "version": "6.0.0", - "dev": true, "license": "ISC", "dependencies": { "yallist": "^4.0.0" @@ -15338,14 +19136,12 @@ }, "node_modules/semver/node_modules/yallist": { "version": "4.0.0", - "dev": true, "license": "ISC" }, "node_modules/send": { "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "dev": true, + "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -15367,24 +19163,21 @@ }, "node_modules/send/node_modules/debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/send/node_modules/debug/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/send/node_modules/ms": { "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/serialize-javascript": { "version": "6.0.2", @@ -15396,9 +19189,8 @@ }, "node_modules/serve-index": { "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", "dev": true, + "license": "MIT", "dependencies": { "accepts": "~1.3.4", "batch": "0.6.1", @@ -15414,27 +19206,24 @@ }, "node_modules/serve-index/node_modules/debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/serve-index/node_modules/depd": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/serve-index/node_modules/http-errors": { "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", "dev": true, + "license": "MIT", "dependencies": { "depd": "~1.1.2", "inherits": "2.0.3", @@ -15447,36 +19236,31 @@ }, "node_modules/serve-index/node_modules/inherits": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/serve-index/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/serve-index/node_modules/setprototypeof": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/serve-index/node_modules/statuses": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/serve-static": { "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "dev": true, + "license": "MIT", "dependencies": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", @@ -15494,7 +19278,6 @@ }, "node_modules/set-function-length": { "version": "1.2.2", - "dev": true, "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", @@ -15543,9 +19326,39 @@ "node": ">=8" } }, + "node_modules/sharp": { + "version": "0.32.6", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.32.6.tgz", + "integrity": "sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.2", + "node-addon-api": "^6.1.0", + "prebuild-install": "^7.1.1", + "semver": "^7.5.4", + "simple-get": "^4.0.1", + "tar-fs": "^3.0.4", + "tunnel-agent": "^0.6.0" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/sharp/node_modules/node-addon-api": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", + "dev": true, + "license": "MIT" + }, "node_modules/shebang-command": { "version": "2.0.0", - "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -15556,7 +19369,6 @@ }, "node_modules/shebang-regex": { "version": "3.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -15564,16 +19376,14 @@ }, "node_modules/shell-quote": { "version": "1.8.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", - "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/side-channel": { "version": "1.0.4", - "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.0", @@ -15665,39 +19475,201 @@ "dev": true, "license": "MIT", "dependencies": { - "minipass": "^7.0.3", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/sigstore/node_modules/minipass-fetch/node_modules/minipass": { + "version": "7.0.4", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/simple-plist": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/simple-plist/-/simple-plist-1.3.1.tgz", + "integrity": "sha512-iMSw5i0XseMnrhtIzRb7XpQEXepa9xhWxGUojHBL43SIpQuDQkh3Wpy67ZbDzZVr6EKxvwVChnVpdl8hEVLDiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bplist-creator": "0.1.0", + "bplist-parser": "0.3.1", + "plist": "^3.0.5" + } + }, + "node_modules/simple-plist/node_modules/bplist-parser": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.3.1.tgz", + "integrity": "sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "big-integer": "1.6.x" + }, + "engines": { + "node": ">= 5.10.0" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/simple-update-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", + "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "~7.0.0" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/slash": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=10" }, - "optionalDependencies": { - "encoding": "^0.1.13" + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "node_modules/sigstore/node_modules/minipass-fetch/node_modules/minipass": { - "version": "7.0.4", - "dev": true, - "license": "ISC", + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/slash": { - "version": "4.0.0", - "dev": true, + "node_modules/slice-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "license": "MIT", - "engines": { - "node": ">=12" + "dependencies": { + "color-name": "~1.1.4" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=7.0.0" } }, "node_modules/smart-buffer": { "version": "4.2.0", - "dev": true, "license": "MIT", "engines": { "node": ">= 6.0.0", @@ -15722,15 +19694,20 @@ } }, "node_modules/socket.io-adapter": { - "version": "2.5.2", + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", + "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", "dev": true, "license": "MIT", "dependencies": { - "ws": "~8.11.0" + "debug": "~4.3.4", + "ws": "~8.17.1" } }, "node_modules/socket.io-adapter/node_modules/ws": { - "version": "8.11.0", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "dev": true, "license": "MIT", "engines": { @@ -15738,7 +19715,7 @@ }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -15763,9 +19740,8 @@ }, "node_modules/sockjs": { "version": "0.3.24", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", - "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", "dev": true, + "license": "MIT", "dependencies": { "faye-websocket": "^0.11.3", "uuid": "^8.3.2", @@ -15774,16 +19750,16 @@ }, "node_modules/sockjs/node_modules/uuid": { "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true, + "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } }, "node_modules/socks": { - "version": "2.8.1", - "dev": true, + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", "license": "MIT", "dependencies": { "ip-address": "^9.0.5", @@ -15894,9 +19870,8 @@ }, "node_modules/spdy": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^4.1.0", "handle-thing": "^2.0.0", @@ -15910,9 +19885,8 @@ }, "node_modules/spdy-transport": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^4.1.0", "detect-node": "^2.0.4", @@ -15922,11 +19896,39 @@ "wbuf": "^1.7.3" } }, + "node_modules/split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "through": "2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "license": "ISC", + "dependencies": { + "readable-stream": "^3.0.0" + } + }, "node_modules/sprintf-js": { "version": "1.0.3", "dev": true, "license": "BSD-3-Clause" }, + "node_modules/ssh-config": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/ssh-config/-/ssh-config-1.1.6.tgz", + "integrity": "sha512-ZPO9rECxzs5JIQ6G/2EfL1I9ho/BVZkx9HRKn8+0af7QgwAmumQ7XBFP1ggMyPMo+/tUbmv0HFdv4qifdO/9JA==", + "license": "MIT" + }, "node_modules/sshpk": { "version": "1.18.0", "dev": true, @@ -15978,6 +19980,56 @@ "node": ">= 0.8" } }, + "node_modules/stream-buffers": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz", + "integrity": "sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==", + "dev": true, + "license": "Unlicense", + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/stream-combiner2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", + "integrity": "sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw==", + "license": "MIT", + "dependencies": { + "duplexer2": "~0.1.0", + "readable-stream": "^2.0.2" + } + }, + "node_modules/stream-combiner2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/stream-combiner2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/stream-combiner2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/streamroller": { "version": "3.1.5", "dev": true, @@ -15991,6 +20043,21 @@ "node": ">=8.0" } }, + "node_modules/streamx": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.18.0.tgz", + "integrity": "sha512-LLUC1TWdjVdn1weXGcSxyTR3T4+acB6tVGXT95y0nGbca4t4o/ng1wKAGTljm9VicuCVLvRlqFYXYy5GwgM7sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-fifo": "^1.3.2", + "queue-tick": "^1.0.1", + "text-decoder": "^1.1.0" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "license": "MIT", @@ -16000,7 +20067,6 @@ }, "node_modules/string-width": { "version": "4.2.3", - "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -16103,12 +20169,24 @@ }, "node_modules/strip-final-newline": { "version": "2.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=6" } }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "dev": true, @@ -16136,6 +20214,69 @@ "node": ">=4" } }, + "node_modules/superagent": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.1.2.tgz", + "integrity": "sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA==", + "deprecated": "Please upgrade to v9.0.0+ as we have fixed a public vulnerability with formidable dependency. Note that v9.0.0+ requires Node.js v14.18.0+. See https://github.com/ladjs/superagent/pull/1800 for insight. This project is supported and maintained by the team at Forward Email @ https://forwardemail.net", + "license": "MIT", + "dependencies": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.4", + "debug": "^4.3.4", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.0", + "formidable": "^2.1.2", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.11.0", + "semver": "^7.3.8" + }, + "engines": { + "node": ">=6.4.0 <13 || >=14" + } + }, + "node_modules/superagent/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/superagent/node_modules/formidable": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz", + "integrity": "sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==", + "license": "MIT", + "dependencies": { + "dezalgo": "^1.0.4", + "hexoid": "^1.0.0", + "once": "^1.4.0", + "qs": "^6.11.0" + }, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, + "node_modules/superagent/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/supports-color": { "version": "5.5.0", "dev": true, @@ -16172,6 +20313,7 @@ "url": "http://opencollective.com/swiper" } ], + "license": "MIT", "engines": { "node": ">= 4.7.0" } @@ -16194,67 +20336,197 @@ "dev": true, "license": "MIT", "engines": { - "node": ">=6" + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar-fs": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.6.tgz", + "integrity": "sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^2.1.1", + "bare-path": "^2.1.0" + } + }, + "node_modules/tar-fs/node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "license": "ISC" + }, + "node_modules/temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/tempy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-1.0.1.tgz", + "integrity": "sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "del": "^6.0.0", + "is-stream": "^2.0.0", + "temp-dir": "^2.0.0", + "type-fest": "^0.16.0", + "unique-string": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/del": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", + "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", + "dev": true, + "license": "MIT", + "dependencies": { + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/tar": { - "version": "6.2.1", + "node_modules/tempy/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/tar-stream": { + "node_modules/tempy/node_modules/is-path-cwd": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", "dev": true, "license": "MIT", - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, "engines": { "node": ">=6" } }, - "node_modules/tar/node_modules/fs-minipass": { - "version": "2.1.0", + "node_modules/tempy/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, + "license": "MIT", "engines": { - "node": ">= 8" + "node": ">=8" } }, - "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", + "node_modules/tempy/node_modules/type-fest": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", + "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, + "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/tar/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "license": "ISC" - }, "node_modules/terser": { "version": "5.29.1", "dev": true, @@ -16387,6 +20659,26 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/text-decoder": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.1.0.tgz", + "integrity": "sha512-TmLJNj6UgX8xcUZo4UDStGQtDiTzF7BzWlzn9g7UWrjkpHr5uJTK1ld16wZ3LXb2vb6jH8qU89dW5whuMdXYdw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, + "node_modules/text-extensions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", + "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, "node_modules/text-table": { "version": "0.2.0", "dev": true, @@ -16394,18 +20686,25 @@ }, "node_modules/through": { "version": "2.3.8", - "dev": true, "license": "MIT" }, + "node_modules/through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "3" + } + }, "node_modules/thunky": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/tmp": { "version": "0.0.33", - "dev": true, "license": "MIT", "dependencies": { "os-tmpdir": "~1.0.2" @@ -16427,6 +20726,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "devOptional": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -16442,6 +20742,16 @@ "node": ">=0.6" } }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, "node_modules/tough-cookie": { "version": "4.1.3", "dev": true, @@ -16477,17 +20787,27 @@ }, "node_modules/tree-kill": { "version": "1.2.2", - "dev": true, "license": "MIT", "bin": { "tree-kill": "cli.js" } }, + "node_modules/trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/ts-api-utils": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=16" }, @@ -16702,7 +21022,6 @@ }, "node_modules/type-fest": { "version": "0.21.3", - "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" @@ -16797,6 +21116,15 @@ "dev": true, "license": "MIT" }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "license": "MIT", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, "node_modules/typescript": { "version": "4.9.5", "dev": true, @@ -16814,6 +21142,7 @@ "resolved": "https://registry.npmjs.org/typescript-strict-plugin/-/typescript-strict-plugin-2.4.4.tgz", "integrity": "sha512-OXcWHQk+pW9gqEL/Mb1eTgj/Yiqk1oHBERr9v4VInPOYN++p+cXejmQK/h/VlUPGD++FXQ8pgiqVMyEtxU4T6A==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^3.0.0", "execa": "^4.0.0", @@ -17005,6 +21334,20 @@ "node": "*" } }, + "node_modules/uglify-js": { + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.18.0.tgz", + "integrity": "sha512-SyVVbcNBCk0dzr9XL/R/ySrmYf0s372K6/hFklzgcp2lBFyXtw4I7BOdDjlLhE1aVqaI/SHWXWmYdlZxuyF38A==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/unbox-primitive": { "version": "1.0.2", "dev": true, @@ -17019,9 +21362,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, "node_modules/undici-types": { "version": "5.26.5", - "dev": true, "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { @@ -17082,6 +21431,19 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/universalify": { "version": "0.1.2", "dev": true, @@ -17098,6 +21460,15 @@ "node": ">= 0.8" } }, + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/update-browserslist-db": { "version": "1.0.13", "dev": true, @@ -17163,6 +21534,7 @@ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], + "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } @@ -17220,9 +21592,8 @@ }, "node_modules/vite": { "version": "4.5.3", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.3.tgz", - "integrity": "sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==", "dev": true, + "license": "MIT", "dependencies": { "esbuild": "^0.18.10", "postcss": "^8.4.27", @@ -17314,9 +21685,8 @@ }, "node_modules/wbuf": { "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", "dev": true, + "license": "MIT", "dependencies": { "minimalistic-assert": "^1.0.0" } @@ -17541,9 +21911,8 @@ }, "node_modules/webpack-dev-server": { "version": "4.15.1", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", - "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", "dev": true, + "license": "MIT", "dependencies": { "@types/bonjour": "^3.5.9", "@types/connect-history-api-fallback": "^1.3.5", @@ -17600,9 +21969,8 @@ }, "node_modules/webpack-dev-server/node_modules/webpack-dev-middleware": { "version": "5.3.4", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", - "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", "dev": true, + "license": "MIT", "dependencies": { "colorette": "^2.0.10", "memfs": "^3.4.3", @@ -17622,10 +21990,11 @@ } }, "node_modules/webpack-dev-server/node_modules/ws": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz", - "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -17733,9 +22102,8 @@ }, "node_modules/websocket-driver": { "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", @@ -17747,9 +22115,8 @@ }, "node_modules/websocket-extensions": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=0.8.0" } @@ -17793,7 +22160,6 @@ }, "node_modules/which": { "version": "2.0.2", - "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -17856,9 +22222,77 @@ "dev": true, "license": "MIT" }, + "node_modules/windows-release": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-4.0.0.tgz", + "integrity": "sha512-OxmV4wzDKB1x7AZaZgXMVsdJ1qER1ed83ZrTYd5Bwq2HfJVg3DJS8nqlAG4sMoJ7mu8cuRmLEYyU13BKwctRAg==", + "license": "MIT", + "dependencies": { + "execa": "^4.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/windows-release/node_modules/execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/windows-release/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/windows-release/node_modules/human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.12.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, "node_modules/wrap-ansi": { "version": "7.0.0", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -17916,7 +22350,6 @@ }, "node_modules/wrap-ansi/node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -17930,7 +22363,6 @@ }, "node_modules/wrap-ansi/node_modules/color-convert": { "version": "2.0.1", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -17941,11 +22373,24 @@ }, "node_modules/wrappy": { "version": "1.0.2", - "dev": true, "license": "ISC" }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, "node_modules/ws": { - "version": "7.5.9", + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", "dev": true, "license": "MIT", "engines": { @@ -17964,6 +22409,43 @@ } } }, + "node_modules/xcode": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/xcode/-/xcode-3.0.1.tgz", + "integrity": "sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "simple-plist": "^1.1.0", + "uuid": "^7.0.3" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/xcode/node_modules/uuid": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz", + "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "sax": "^1.2.4" + }, + "bin": { + "xml-js": "bin/cli.js" + } + }, "node_modules/xml-name-validator": { "version": "3.0.0", "dev": true, @@ -17994,6 +22476,26 @@ "dev": true, "license": "MIT" }, + "node_modules/xpath": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/xpath/-/xpath-0.0.32.tgz", + "integrity": "sha512-rxMJhSIoiO8vXcWvSifKqhvV96GjiD5wYb8/QHdoRyQvraTpp4IEv944nhGausZZ3u7dhQXteZuZbaqfpB7uYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, "node_modules/y18n": { "version": "5.0.8", "dev": true, @@ -18032,6 +22534,17 @@ "node": ">=12" } }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, "node_modules/yn": { "version": "3.1.1", "dev": true, diff --git a/ui/package.json b/ui/package.json index 9790d1c8f7e..4107030261c 100644 --- a/ui/package.json +++ b/ui/package.json @@ -12,12 +12,25 @@ "@angular/platform-browser-dynamic": "~16.2.12", "@angular/router": "~16.2.12", "@angular/service-worker": "~16.2.12", + "@capacitor-community/file-opener": "^1.0.5", + "@capacitor/android": "5.2.3", + "@capacitor/app": "^5.0.6", + "@capacitor/core": "5.2.3", + "@capacitor/filesystem": "^5.2.0", + "@capacitor/ios": "5.2.3", + "@capacitor/splash-screen": "^5.0.6", + "@ionic-native/core": "^5.36.0", + "@ionic-native/file-opener": "^5.36.0", "@ionic/angular": "^6.7.5", + "@ionic/cli": "^7.1.6", "@ngx-formly/core": "^6.3.0", "@ngx-formly/ionic": "^6.3.5", "@ngx-formly/schematics": "^6.3.0", "@ngx-translate/core": "^15.0.0", "@nodro7/angular-mydatepicker": "^0.14.0", + "capacitor-blob-writer": "^1.1.14", + "capacitor-ios-autofill-save-password": "^2.0.0", + "capacitor-secure-storage-plugin": "^0.9.0", "chart.js": "^4.4.3", "chartjs-adapter-date-fns": "^3.0.0", "chartjs-plugin-zoom": "^2.0.1", @@ -46,6 +59,8 @@ "@angular/compiler": "^16.2.12", "@angular/compiler-cli": "^16.2.12", "@angular/language-service": "^16.2.12", + "@capacitor/assets": "^3.0.0", + "@capacitor/cli": "5.2.3", "@ionic/angular-toolkit": "^11.0.1", "@stylistic/eslint-plugin": "^2.2.2", "@types/jasmine": "~4.3.6", @@ -74,6 +89,7 @@ }, "scripts": { "lint": "ng lint", - "test": "ng test" + "test": "ng test", + "capacitor-assets": "capacitor-assets" } } diff --git a/ui/src/app/app-routing.module.ts b/ui/src/app/app-routing.module.ts index a520f995833..4f24cc18d84 100644 --- a/ui/src/app/app-routing.module.ts +++ b/ui/src/app/app-routing.module.ts @@ -48,12 +48,14 @@ import { LoginComponent } from './index/login.component'; import { OverViewComponent } from './index/overview/overview.component'; import { DataService } from './shared/genericComponents/shared/dataservice'; import { UserComponent } from './user/user.component'; +import { DetailsOverviewComponent } from './edge/history/common/production/details/details.overview'; +import { LoadingScreenComponent } from './index/shared/loading-screen'; const routes: Routes = [ // TODO should be removed in the future - { path: 'index', redirectTo: 'login', pathMatch: 'full' }, - { path: '', redirectTo: 'login', pathMatch: 'full' }, + { path: '', redirectTo: 'index', pathMatch: 'full' }, + { path: 'index', component: LoadingScreenComponent }, { path: 'login', component: LoginComponent, data: { navbarTitle: environment.uiTitle } }, { path: 'overview', component: OverViewComponent }, @@ -92,6 +94,7 @@ const routes: Routes = [ { path: 'consumptionchart', component: ConsumptionChartOverviewComponent }, { path: 'gridchart', component: GridChartOverviewComponent }, { path: 'productionchart', component: ProductionChartOverviewComponent }, + { path: 'productionchart/:componentId', component: DetailsOverviewComponent }, { path: 'selfconsumptionchart', component: SelfconsumptionChartOverviewComponent }, { path: 'storagechart', component: StorageChartOverviewComponent }, @@ -102,10 +105,10 @@ const routes: Routes = [ { path: 'settings', data: { navbarTitleToBeTranslated: 'Menu.edgeSettings' }, component: EdgeSettingsComponent }, { path: 'settings/channels', component: EdgeSettingsChannelsComponent }, - { path: 'settings/component.install', component: EdgeSettingsComponentInstallIndexComponentComponent }, - { path: 'settings/component.install/:factoryId', component: EdgeSettingsComponentInstallComponentComponent }, - { path: 'settings/component.update', component: EdgeSettingsComponentUpdateIndexComponentComponent }, - { path: 'settings/component.update/:componentId', component: EdgeSettingsComponentUpdateComponentComponent }, + { path: 'settings/component.install', component: EdgeSettingsComponentInstallIndexComponentComponent, data: { navbarTitleToBeTranslated: 'Edge.Config.Index.addComponents' } }, + { path: 'settings/component.install/:factoryId', component: EdgeSettingsComponentInstallComponentComponent, data: { navbarTitleToBeTranslated: 'Edge.Config.Index.addComponents' } }, + { path: 'settings/component.update', component: EdgeSettingsComponentUpdateIndexComponentComponent, data: { navbarTitleToBeTranslated: 'Edge.Config.Index.adjustComponents' } }, + { path: 'settings/component.update/:componentId', component: EdgeSettingsComponentUpdateComponentComponent, data: { navbarTitleToBeTranslated: 'Edge.Config.Index.adjustComponents' } }, { path: 'settings/network', component: EdgeSettingsNetworkComponent, data: { navbarTitleToBeTranslated: 'Edge.Config.Index.networkConfiguration' } }, { path: 'settings/profile', component: EdgeSettingsProfileComponent }, { path: 'settings/profile/:componentId', component: AliasUpdateComponent }, @@ -123,7 +126,7 @@ const routes: Routes = [ { path: 'demo', component: LoginComponent }, // Fallback - { path: '**', pathMatch: 'full', redirectTo: 'login' }, + { path: '**', pathMatch: 'full', redirectTo: 'index' }, ]; export const appRoutingProviders: any[] = []; diff --git a/ui/src/app/app.component.ts b/ui/src/app/app.component.ts index 72d01cd471d..c0981692639 100644 --- a/ui/src/app/app.component.ts +++ b/ui/src/app/app.component.ts @@ -10,6 +10,8 @@ import { environment } from '../environments'; import { GlobalRouteChangeHandler } from './shared/service/globalRouteChangeHandler'; import { Service, UserPermission, Websocket } from './shared/shared'; import { Language } from './shared/type/language'; +import { SplashScreen } from '@capacitor/splash-screen'; +import { AppService } from './app.service'; @Component({ selector: 'app-root', @@ -38,6 +40,7 @@ export class AppComponent implements OnInit, OnDestroy { public websocket: Websocket, private globalRouteChangeHandler: GlobalRouteChangeHandler, private meta: Meta, + private appService: AppService, private title: Title, ) { service.setLang(Language.getByKey(localStorage.LANGUAGE) ?? Language.getByBrowserLang(navigator.language)); @@ -55,6 +58,9 @@ export class AppComponent implements OnInit, OnDestroy { const segments = e.url.split('/'); this.isHistoryDetailView = segments.slice(0, -1).includes('history'); })); + + this.appService.listen(); + SplashScreen.hide(); } ngOnInit() { diff --git a/ui/src/app/app.module.ts b/ui/src/app/app.module.ts index f76d84f27e3..343f78f6534 100644 --- a/ui/src/app/app.module.ts +++ b/ui/src/app/app.module.ts @@ -13,6 +13,7 @@ import { CookieService } from 'ngx-cookie-service'; import { AngularMyDatePickerModule } from '@nodro7/angular-mydatepicker'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; +import { AppService } from './app.service'; import { CheckForUpdateService } from './appupdateservice'; import { ChangelogModule } from './changelog/changelog.module'; import { EdgeModule } from './edge/edge.module'; @@ -63,6 +64,7 @@ import { UserModule } from './user/user.module'; { provide: FORMLY_CONFIG, multi: true, useFactory: registerTranslateExtension, deps: [TranslateService] }, Pagination, CheckForUpdateService, + AppService, ], bootstrap: [AppComponent], }) diff --git a/ui/src/app/app.service.ts b/ui/src/app/app.service.ts new file mode 100644 index 00000000000..397e6c06b35 --- /dev/null +++ b/ui/src/app/app.service.ts @@ -0,0 +1,154 @@ +// @ts-strict-ignore +import { Injectable } from '@angular/core'; +import { App } from '@capacitor/app'; +import { Capacitor } from '@capacitor/core'; +import { Directory, Encoding, Filesystem } from '@capacitor/filesystem'; +import { FileOpener } from '@ionic-native/file-opener'; +import { AlertController } from '@ionic/angular'; +import { TranslateService } from '@ngx-translate/core'; +import { saveAs } from 'file-saver-es'; +import { BehaviorSubject, Subject } from 'rxjs'; +import { JsonrpcRequest } from './shared/jsonrpc/base'; +import { Websocket } from './shared/shared'; + +@Injectable() +export class AppService { + public static isActive: BehaviorSubject = new BehaviorSubject(null); + public static lastActive: Subject = new Subject(); + public static readonly isApp: boolean = Capacitor.getPlatform() !== 'web'; + public static notifications: Map = new Map(); + + constructor( + private websocket: Websocket, + private alertCtrl: AlertController, + private translate: TranslateService, + ) { } + + private async updateState() { + const { isActive } = await App.getState(); + + if (isActive === true && AppService.isActive?.getValue() === false) { + window.location.reload(); + } + + AppService.isActive.next(isActive); + } + + public listen() { + + // // Don't use in web + if (!AppService.isApp) { + return; + } + + this.updateState(); + + App.addListener('appStateChange', () => { + this.updateState(); + }); + } + + public async downloadFile(path: string, blob: Blob, fileName: string) { + + // await this.presentAlert("Di", "asd", () => { }).then((state) => { + // console.log("state", state); + // }); + + fileName = "test.txt"; + + const writeSecretFile = async () => { + await Filesystem.writeFile({ + path: fileName, + data: "this is a test", + directory: Directory.Data, + encoding: Encoding.UTF8, + }); + }; + + // const openFile = async () => { + // const { uri } = await Filesystem.getUri({ path: fileName, directory: Directory.Data }); + + // let fOpts = { + // filePath: uri + fileName, + // openWithDefault: true + // } + + // FileOpener.open(fOpts); + // } + + const readSecretFile = async () => { + const contents = await Filesystem.readFile({ + path: fileName, + directory: Directory.Documents, + encoding: Encoding.UTF8, + }); + + console.log('secrets:', contents); + }; + + await writeSecretFile(); + // await openFile(); + await readSecretFile(); + } + + + /** + * Method that shows a confirmation window for the app selection + * + * @param clickedApp the app that has been clicked + */ + public async presentAlert(header: string, message: string, successCallback: () => void) { + + const alert = this.alertCtrl.create({ + header: header, + message: message, + buttons: [{ + text: this.translate.instant('INSTALLATION.BACK'), + role: 'cancel', + }, + { + text: this.translate.instant('INSTALLATION.FORWARD'), + handler: () => { + successCallback(); + }, + }], + cssClass: 'alertController', + }); + (await alert).present(); + } + + static async writeAndOpenFile(data: Blob, fileName: string) { + + if (!AppService.isApp) { + saveAs(data, fileName); + } + + const reader = new FileReader(); + reader.readAsDataURL(data); + reader.onloadend = async function () { + try { + const result = await Filesystem.writeFile({ + path: fileName, + data: reader.result.toString(), + directory: Directory.Data, + recursive: true, + encoding: Encoding.UTF8, + }); + + FileOpener.open(result.uri, data.type) + .then(() => console.log('File is opened')) + .catch(e => console.log('Error opening file', e)); + + console.log('Wrote file', result.uri); + } catch (e) { + console.error('Unable to write file', e); + } + }; + } + + public static handleRefresh() { + setTimeout(() => + window.location.reload() + , 1000); + } +} diff --git a/ui/src/app/edge/history/common/energy/flat/flat.ts b/ui/src/app/edge/history/common/energy/flat/flat.ts index f69ce558271..b6b06fa87fc 100644 --- a/ui/src/app/edge/history/common/energy/flat/flat.ts +++ b/ui/src/app/edge/history/common/energy/flat/flat.ts @@ -6,6 +6,7 @@ import { Base64PayloadResponse } from 'src/app/shared/jsonrpc/response/base64Pay import { QueryHistoricTimeseriesExportXlxsRequest } from 'src/app/shared/jsonrpc/request/queryHistoricTimeseriesExportXlxs'; import { isSameDay, format, isSameMonth, isSameYear } from 'date-fns'; import { saveAs } from 'file-saver-es'; +import { AppService } from 'src/app/app.service'; @Component({ selector: 'energy', @@ -17,6 +18,7 @@ export class FlatComponent extends AbstractFlatWidget { private static readonly EXCEL_TYPE = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8'; private static readonly EXCEL_EXTENSION = '.xlsx'; protected readonly isSmartphoneResolution = this.service.isSmartphoneResolution; + protected readonly isApp: boolean = AppService.isApp; protected override onCurrentData(currentData: CurrentData) { this.autarchyValue = @@ -40,6 +42,12 @@ export class FlatComponent extends AbstractFlatWidget { * Export historic data to Excel file. */ protected exportToXlxs() { + + if (AppService.isApp) { + this.service.toast(this.translate.instant('APP.FUNCTIONALITY_TEMPORARILY_NOT_AVAILABLE'), "warning"); + return; + } + this.service.getCurrentEdge().then(edge => { edge.sendRequest(this.websocket, new QueryHistoricTimeseriesExportXlxsRequest(this.service.historyPeriod.value.from, this.service.historyPeriod.value.to)).then(response => { const r = response as Base64PayloadResponse; diff --git a/ui/src/app/edge/history/common/production/details/chart/chart.ts b/ui/src/app/edge/history/common/production/details/chart/chart.ts new file mode 100644 index 00000000000..6797a9c1612 --- /dev/null +++ b/ui/src/app/edge/history/common/production/details/chart/chart.ts @@ -0,0 +1,88 @@ +import { Component } from '@angular/core'; +import { AbstractHistoryChart } from 'src/app/shared/genericComponents/chart/abstracthistorychart'; +import { Phase } from 'src/app/shared/genericComponents/shared/phase'; +import { QueryHistoricTimeseriesEnergyResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; +import { ChartAxis, HistoryUtils, YAxisTitle } from 'src/app/shared/service/utils'; +import { ChannelAddress } from 'src/app/shared/shared'; + +@Component({ + selector: 'meterChart', + templateUrl: '../../../../../../shared/genericComponents/chart/abstracthistorychart.html', +}) +export class ChartComponent extends AbstractHistoryChart { + + + protected override getChartData(): HistoryUtils.ChartData { + + const component = this.config.getComponent(this.route.snapshot.params.componentId); + const isProductionMeter = this.config.hasComponentNature("io.openems.edge.meter.api.ElectricityMeter", component.id) && this.config.isProducer(component); + const isCharger = this.config.hasComponentNature("io.openems.edge.ess.dccharger.api.EssDcCharger", component.id); + + const channels: HistoryUtils.InputChannel[] = []; + + if (isCharger) { + channels.push({ + name: component.id, + powerChannel: ChannelAddress.fromString(component.id + '/ActualPower'), + energyChannel: ChannelAddress.fromString(component.id + '/ActualEnergy'), + }); + } + + if (isProductionMeter) { + channels.push({ + name: component.id, + powerChannel: ChannelAddress.fromString(component.id + '/ActivePower'), + energyChannel: ChannelAddress.fromString(component.id + '/ActiveProductionEnergy'), + }); + + channels.push(...Phase.THREE_PHASE.map(phase => ({ + name: 'ProductionAcActivePower' + phase, + powerChannel: ChannelAddress.fromString(component.id + '/ActivePower' + phase), + }))); + } + + const chartObject: HistoryUtils.ChartData = { + input: channels, + output: (data: HistoryUtils.ChannelData) => { + const datasets: HistoryUtils.DisplayValues[] = []; + datasets.push({ + name: component.alias, + nameSuffix: (energyQueryResponse: QueryHistoricTimeseriesEnergyResponse) => { + return energyQueryResponse.result.data[isCharger ? component.id + '/ActualEnergy' : component.id + '/ActiveProductionEnergy']; + }, + converter: () => { + return data[component.id]; + }, + color: 'rgb(0,152,204)', + hiddenOnInit: false, + stack: 2, + }); + + if (!isProductionMeter) { + return datasets; + } + + datasets.push(...Phase.THREE_PHASE.map((phase, i) => ({ + name: "Phase " + phase, + converter: () => + data['ProductionAcActivePower' + phase], + color: 'rgb(' + AbstractHistoryChart.phaseColors[i] + ')', + stack: 3, + }))); + + return datasets; + }, + tooltip: { + formatNumber: '1.1-2', + afterTitle: this.translate.instant('General.TOTAL'), + }, + yAxes: [{ + unit: YAxisTitle.ENERGY, + position: 'left', + yAxisId: ChartAxis.LEFT, + }], + }; + + return chartObject; + } +} diff --git a/ui/src/app/edge/history/common/production/details/details.overview.html b/ui/src/app/edge/history/common/production/details/details.overview.html new file mode 100644 index 00000000000..5e3c861b1f3 --- /dev/null +++ b/ui/src/app/edge/history/common/production/details/details.overview.html @@ -0,0 +1,6 @@ + + + + diff --git a/ui/src/app/edge/history/common/production/details/details.overview.ts b/ui/src/app/edge/history/common/production/details/details.overview.ts new file mode 100644 index 00000000000..8a2e5bc46ac --- /dev/null +++ b/ui/src/app/edge/history/common/production/details/details.overview.ts @@ -0,0 +1,24 @@ +import { Component } from '@angular/core'; +import { AbstractHistoryChartOverview } from 'src/app/shared/genericComponents/chart/abstractHistoryChartOverview'; +import { ChannelAddress, EdgeConfig } from 'src/app/shared/shared'; + +@Component({ + templateUrl: './details.overview.html', +}) +export class DetailsOverviewComponent extends AbstractHistoryChartOverview { + protected chargerComponents: EdgeConfig.Component[] = []; + protected productionMeterComponents: EdgeConfig.Component[] = []; + + protected override getChannelAddresses(): ChannelAddress[] { + // Get Chargers + this.chargerComponents = + this.config.getComponentsImplementingNature("io.openems.edge.ess.dccharger.api.EssDcCharger") + .filter(component => component.isEnabled); + + // Get productionMeters + this.productionMeterComponents = + this.config.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") + .filter(component => component.isEnabled && this.config.isProducer(component)); + return []; + } +} diff --git a/ui/src/app/edge/history/common/production/overview/overview.html b/ui/src/app/edge/history/common/production/overview/overview.html index c4706da4aaf..d02fe0a1f66 100644 --- a/ui/src/app/edge/history/common/production/overview/overview.html +++ b/ui/src/app/edge/history/common/production/overview/overview.html @@ -34,3 +34,4 @@ + diff --git a/ui/src/app/edge/history/common/production/overview/overview.ts b/ui/src/app/edge/history/common/production/overview/overview.ts index 480d20dc501..715e2dfff07 100644 --- a/ui/src/app/edge/history/common/production/overview/overview.ts +++ b/ui/src/app/edge/history/common/production/overview/overview.ts @@ -1,6 +1,9 @@ import { Component } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { ModalController } from '@ionic/angular'; +import { NavigationOption } from 'src/app/shared/genericComponents/footer-navigation/footerNavigation'; import { AbstractHistoryChartOverview } from '../../../../../shared/genericComponents/chart/abstractHistoryChartOverview'; -import { ChannelAddress, EdgeConfig } from '../../../../../shared/shared'; +import { ChannelAddress, EdgeConfig, Service } from '../../../../../shared/shared'; @Component({ templateUrl: './overview.html', @@ -8,6 +11,16 @@ import { ChannelAddress, EdgeConfig } from '../../../../../shared/shared'; export class OverviewComponent extends AbstractHistoryChartOverview { protected chargerComponents: EdgeConfig.Component[] = []; protected productionMeterComponents: EdgeConfig.Component[] = []; + protected navigationButtons: NavigationOption[] = []; + + constructor( + public override service: Service, + protected override route: ActivatedRoute, + public override modalCtrl: ModalController, + private router: Router, + ) { + super(service, route, modalCtrl); + } protected override getChannelAddresses(): ChannelAddress[] { // Get Chargers @@ -19,6 +32,10 @@ export class OverviewComponent extends AbstractHistoryChartOverview { this.productionMeterComponents = this.config.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") .filter(component => component.isEnabled && this.config.isProducer(component)); + + this.navigationButtons = [...this.chargerComponents, ...this.productionMeterComponents].map(el => ( + { id: el.id, alias: el.alias, callback: () => { this.router.navigate(['./' + el.id], { relativeTo: this.route }); } } + )); return []; } } diff --git a/ui/src/app/edge/history/common/production/production.ts b/ui/src/app/edge/history/common/production/production.ts index 890070a3e15..bb70ba25068 100644 --- a/ui/src/app/edge/history/common/production/production.ts +++ b/ui/src/app/edge/history/common/production/production.ts @@ -7,6 +7,8 @@ import { ProductionMeterChartComponent } from './chart/productionMeterChart'; import { TotalAcChartComponent } from './chart/totalAcChart'; import { TotalChartComponent } from './chart/totalChart'; import { TotalDcChartComponent } from './chart/totalDcChart'; +import { ChartComponent } from './details/chart/chart'; +import { DetailsOverviewComponent } from './details/details.overview'; import { FlatComponent } from './flat/flat'; import { OverviewComponent } from './overview/overview'; @@ -23,6 +25,8 @@ import { OverviewComponent } from './overview/overview'; TotalAcChartComponent, TotalChartComponent, ChargerChartComponent, + DetailsOverviewComponent, + ChartComponent, ], exports: [ FlatComponent, diff --git a/ui/src/app/edge/history/history.component.html b/ui/src/app/edge/history/history.component.html index 18e1b0c4574..e284994f2ce 100644 --- a/ui/src/app/edge/history/history.component.html +++ b/ui/src/app/edge/history/history.component.html @@ -1,5 +1,8 @@
      + + + @@ -105,4 +108,4 @@ - + \ No newline at end of file diff --git a/ui/src/app/edge/history/history.component.ts b/ui/src/app/edge/history/history.component.ts index 61166b75f5d..03e9c052124 100644 --- a/ui/src/app/edge/history/history.component.ts +++ b/ui/src/app/edge/history/history.component.ts @@ -2,6 +2,7 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; +import { AppService } from 'src/app/app.service'; import { HeaderComponent } from 'src/app/shared/header/header.component'; import { JsonrpcResponseError } from 'src/app/shared/jsonrpc/base'; import { Edge, EdgeConfig, Service, Widgets } from 'src/app/shared/shared'; @@ -33,6 +34,7 @@ export class HistoryComponent implements OnInit { // public channelthresholdComponents: string[] = []; public config: EdgeConfig = null; + protected handleRefresh: () => void = () => AppService.handleRefresh(); constructor( public service: Service, diff --git a/ui/src/app/edge/history/historydataservice.ts b/ui/src/app/edge/history/historydataservice.ts index 51e5a033ab5..07f2bec9050 100644 --- a/ui/src/app/edge/history/historydataservice.ts +++ b/ui/src/app/edge/history/historydataservice.ts @@ -8,6 +8,7 @@ import { DateUtils } from "src/app/shared/utils/date/dateutils"; import { QueryHistoricTimeseriesEnergyRequest } from "src/app/shared/jsonrpc/request/queryHistoricTimeseriesEnergyRequest"; import { Websocket } from "src/app/shared/service/websocket"; import { Service } from "src/app/shared/service/service"; +import { RefresherCustomEvent } from "@ionic/angular"; @Injectable() export class HistoryDataService extends DataService { @@ -56,4 +57,9 @@ export class HistoryDataService extends DataService { public override unsubscribeFromChannels(channels: ChannelAddress[]) { return; } + + public override refresh(ev: RefresherCustomEvent) { + this.getValues(Object.values(this.channelAddresses), this.edge, ""); + ev.target.complete(); + } } diff --git a/ui/src/app/edge/live/live.component.html b/ui/src/app/edge/live/live.component.html index 77f76e165e3..e771887a085 100644 --- a/ui/src/app/edge/live/live.component.html +++ b/ui/src/app/edge/live/live.component.html @@ -1,5 +1,9 @@
      + + + + diff --git a/ui/src/app/edge/live/live.component.ts b/ui/src/app/edge/live/live.component.ts index 8f36b79cb9f..8363d1c811d 100644 --- a/ui/src/app/edge/live/live.component.ts +++ b/ui/src/app/edge/live/live.component.ts @@ -1,7 +1,9 @@ // @ts-strict-ignore import { Component, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; +import { RefresherCustomEvent } from '@ionic/angular'; import { Subject } from 'rxjs'; +import { DataService } from 'src/app/shared/genericComponents/shared/dataservice'; import { Edge, EdgeConfig, Service, Utils, Websocket, Widgets } from 'src/app/shared/shared'; @Component({ @@ -14,12 +16,14 @@ export class LiveComponent implements OnInit, OnDestroy { public config: EdgeConfig = null; public widgets: Widgets = null; private stopOnDestroy: Subject = new Subject(); + protected handleRefresh: (ev: RefresherCustomEvent) => void = (ev: RefresherCustomEvent) => this.dataService.refresh(ev); constructor( private route: ActivatedRoute, public service: Service, protected utils: Utils, protected websocket: Websocket, + private dataService: DataService, ) { } public ngOnInit() { diff --git a/ui/src/app/edge/live/livedataservice.ts b/ui/src/app/edge/live/livedataservice.ts index 6dd0c30ddbe..4bfbaaf98ac 100644 --- a/ui/src/app/edge/live/livedataservice.ts +++ b/ui/src/app/edge/live/livedataservice.ts @@ -5,6 +5,7 @@ import { v4 as uuidv4 } from 'uuid'; import { DataService } from "../../shared/genericComponents/shared/dataservice"; import { ChannelAddress, Edge, Service, Websocket } from "../../shared/shared"; +import { RefresherCustomEvent } from "@ionic/angular"; @Directive() export class LiveDataService extends DataService implements OnDestroy { @@ -52,4 +53,13 @@ export class LiveDataService extends DataService implements OnDestroy { public unsubscribeFromChannels(channels: ChannelAddress[]) { this.edge.unsubscribeFromChannels(this.websocket, channels); } + + public override refresh(ev: RefresherCustomEvent) { + this.currentValue.next({ allComponents: {} }); + this.edge.unsubscribeFromChannels(this.websocket, this.subscribedChannelAddresses); + setTimeout(() => { + this.edge.subscribeChannels(this.websocket, "", this.subscribedChannelAddresses); + ev.target.complete(); + }, 1000); + } } diff --git a/ui/src/app/edge/settings/channels/channels.component.html b/ui/src/app/edge/settings/channels/channels.component.html index 8c192b88627..90d4834506c 100644 --- a/ui/src/app/edge/settings/channels/channels.component.html +++ b/ui/src/app/edge/settings/channels/channels.component.html @@ -133,14 +133,14 @@ - - diff --git a/ui/src/app/edge/settings/channels/channels.component.ts b/ui/src/app/edge/settings/channels/channels.component.ts index 660aee32288..a848236abae 100644 --- a/ui/src/app/edge/settings/channels/channels.component.ts +++ b/ui/src/app/edge/settings/channels/channels.component.ts @@ -115,19 +115,19 @@ export class ChannelsComponent { this.saveChannelsInUrl(); } - protected setChannelValue(address: ChannelAddress, channelValue: any) { + protected setChannelValue(componentId: string, channelId: string, channelValue: any) { if (this.edge) { this.edge.sendRequest( this.service.websocket, new SetChannelValueRequest({ - componentId: address.componentId, - channelId: address.channelId, + componentId: componentId, + channelId: channelId, value: channelValue, }), ).then(() => { - this.service.toast("Successfully set " + address.toString() + " to [" + channelValue + "]", "success"); + this.service.toast("Successfully set " + componentId + "/" + channelId + " to [" + channelValue + "]", "success"); }).catch(() => { - this.service.toast("Error setting " + address.toString() + " to [" + channelValue + "]", 'danger'); + this.service.toast("Error setting " + componentId + "/" + channelId + " to [" + channelValue + "]", 'danger'); }); } } diff --git a/ui/src/app/edge/settings/component/install/index.component.ts b/ui/src/app/edge/settings/component/install/index.component.ts index 147379b3235..7814b549482 100644 --- a/ui/src/app/edge/settings/component/install/index.component.ts +++ b/ui/src/app/edge/settings/component/install/index.component.ts @@ -1,9 +1,9 @@ // @ts-strict-ignore -import { ActivatedRoute } from '@angular/router'; import { CategorizedFactories } from 'src/app/shared/edge/edgeconfig'; import { Component, OnInit } from '@angular/core'; -import { Service, Utils, EdgeConfig } from '../../../../shared/shared'; -import { TranslateService } from '@ngx-translate/core'; +import { Service, Utils, EdgeConfig, Websocket, Edge, EdgePermission } from '../../../../shared/shared'; +import { JsonrpcRequest, JsonrpcResponseSuccess } from 'src/app/shared/jsonrpc/base'; +import { ComponentJsonApiRequest } from 'src/app/shared/jsonrpc/request/componentJsonApiRequest'; interface MyCategorizedFactories extends CategorizedFactories { isClicked?: boolean, @@ -18,27 +18,42 @@ export class IndexComponent implements OnInit { private static readonly SELECTOR = "indexComponentInstall"; + private edge: Edge; public list: MyCategorizedFactories[]; public showAllFactories = false; constructor( - private route: ActivatedRoute, private service: Service, - private translate: TranslateService, + private websocket: Websocket, ) { } - ngOnInit() { - this.service.setCurrentComponent({ languageKey: 'Edge.Config.Index.addComponents' }, this.route); - this.service.getConfig().then(config => { - this.list = config.listAvailableFactories(); - for (const entry of this.list) { - entry.isClicked = false; - entry.filteredFactories = entry.factories; + async ngOnInit() { + this.edge = await this.service.getCurrentEdge(); + this.list = await this.getCategorizedFactories(); + for (const entry of this.list) { + entry.isClicked = false; + entry.filteredFactories = entry.factories; + } + this.updateFilter(""); + } + + private async getCategorizedFactories(): Promise { + if (EdgePermission.hasReducedFactories(this.edge)) { + const response = await this.edge.sendRequest(this.websocket, new ComponentJsonApiRequest({ + componentId: '_componentManager', + payload: new GetAllComponentFactoriesRequest(), + })); + for (const [factoryId, factory] of Object.entries(response.result.factories)) { + factory.id = factoryId; } - this.updateFilter(""); - }); + + return EdgeConfig.listAvailableFactories(response.result.factories); + } + + const config = await this.service.getConfig(); + return config.listAvailableFactories(); } updateFilter(completeFilter: string) { @@ -64,3 +79,27 @@ export class IndexComponent implements OnInit { } } } + +class GetAllComponentFactoriesRequest extends JsonrpcRequest { + + private static METHOD: string = "getAllComponentFactories"; + + public constructor() { + super(GetAllComponentFactoriesRequest.METHOD, {}); + } + +} + +class GetAllComponentFactoriesResponse extends JsonrpcResponseSuccess { + + public constructor( + public override readonly id: string, + public override readonly result: { + factories: { [factoryId: string]: EdgeConfig.Factory }, + }, + ) { + super(id, result); + } + +} + diff --git a/ui/src/app/edge/settings/component/install/install.component.ts b/ui/src/app/edge/settings/component/install/install.component.ts index 89ad5585219..d53a0a642fc 100644 --- a/ui/src/app/edge/settings/component/install/install.component.ts +++ b/ui/src/app/edge/settings/component/install/install.component.ts @@ -4,7 +4,6 @@ import { Component, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { FormlyFieldConfig } from '@ngx-formly/core'; import { Service, Utils, Websocket, EdgeConfig, Edge } from '../../../../shared/shared'; -import { TranslateService } from '@ngx-translate/core'; @Component({ selector: ComponentInstallComponent.SELECTOR, @@ -27,67 +26,64 @@ export class ComponentInstallComponent implements OnInit { protected utils: Utils, private websocket: Websocket, private service: Service, - private translate: TranslateService, ) { } - ngOnInit() { - this.service.setCurrentComponent({ languageKey: 'Edge.Config.Index.addComponents' }, this.route).then(edge => { - this.edge = edge; - }); - const factoryId = this.route.snapshot.params["factoryId"]; - this.service.getConfig().then(config => { - this.factoryId = factoryId; - this.factory = config.factories[factoryId]; - const fields: FormlyFieldConfig[] = []; - const model = {}; - for (const property of this.factory.properties) { - const property_id = property.id.replace('.', '_'); - let defaultValue = property.defaultValue; - // if the type is an array and there is no defaultValue then set the defaultValue to an empty array - if (property.schema["type"] === 'repeat' && defaultValue === null) { - defaultValue = []; - } - const field: FormlyFieldConfig = { - key: property_id, - type: 'input', - templateOptions: { - label: property.name, - required: defaultValue === null, - description: property.description, - }, - }; - // add Property Schema - Utils.deepCopy(property.schema, field); - fields.push(field); - if (defaultValue != null) { - model[property_id] = defaultValue; + async ngOnInit() { + this.factoryId = this.route.snapshot.params["factoryId"]; + this.edge = await this.service.getCurrentEdge(); + const config = await this.service.getConfig(); + + const [factory, properties] = await this.edge.getFactoryProperties(this.websocket, this.factoryId); + this.factory = factory; + const fields: FormlyFieldConfig[] = []; + const model = {}; + for (const property of properties) { + const property_id = property.id.replace('.', '_'); + let defaultValue = property.defaultValue; + // if the type is an array and there is no defaultValue then set the defaultValue to an empty array + if (property.schema["type"] === 'repeat' && defaultValue === null) { + defaultValue = []; + } + const field: FormlyFieldConfig = { + key: property_id, + type: 'input', + templateOptions: { + label: property.name, + required: defaultValue === null, + description: property.description, + }, + }; + // add Property Schema + Utils.deepCopy(property.schema, field); + fields.push(field); + if (defaultValue != null) { + model[property_id] = defaultValue; - // Set the next free Component-ID as defaultValue - if (property_id == 'id' && property.schema["type"] !== 'repeat') { - const thisMatch = defaultValue.match(/^(.*)(\d+)$/); - if (thisMatch) { - const thisPrefix = thisMatch[1]; - let highestSuffix = Number.parseInt(thisMatch[2]); - for (const componentId of Object.keys(config.components)) { - const componentMatch = componentId.match(/^(.*)(\d+)$/); - if (componentMatch) { - const componentPrefix = componentMatch[1]; - if (componentPrefix === thisPrefix) { - const componentSuffix = Number.parseInt(componentMatch[2]); - highestSuffix = Math.max(highestSuffix, componentSuffix + 1); - } + // Set the next free Component-ID as defaultValue + if (property_id == 'id' && property.schema["type"] !== 'repeat') { + const thisMatch = defaultValue.match(/^(.*)(\d+)$/); + if (thisMatch) { + const thisPrefix = thisMatch[1]; + let highestSuffix = Number.parseInt(thisMatch[2]); + for (const componentId of Object.keys(config.components)) { + const componentMatch = componentId.match(/^(.*)(\d+)$/); + if (componentMatch) { + const componentPrefix = componentMatch[1]; + if (componentPrefix === thisPrefix) { + const componentSuffix = Number.parseInt(componentMatch[2]); + highestSuffix = Math.max(highestSuffix, componentSuffix + 1); } } - model[property_id] = thisPrefix + highestSuffix; } + model[property_id] = thisPrefix + highestSuffix; } } } - this.form = new FormGroup({}); - this.fields = fields; - this.model = model; - }); + } + this.form = new FormGroup({}); + this.fields = fields; + this.model = model; } public submit() { diff --git a/ui/src/app/edge/settings/component/update/index.component.ts b/ui/src/app/edge/settings/component/update/index.component.ts index fcec4e80b41..fb24d9860f9 100644 --- a/ui/src/app/edge/settings/component/update/index.component.ts +++ b/ui/src/app/edge/settings/component/update/index.component.ts @@ -1,6 +1,5 @@ // @ts-strict-ignore import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; import { CategorizedComponents } from 'src/app/shared/edge/edgeconfig'; import { EdgeConfig, Service, Utils } from '../../../../shared/shared'; @@ -23,13 +22,11 @@ export class IndexComponent implements OnInit { public showAllEntries = false; constructor( - private route: ActivatedRoute, private service: Service, ) { } public ngOnInit() { - this.service.setCurrentComponent({ languageKey: 'Edge.Config.Index.adjustComponents' }, this.route); this.service.getConfig().then(config => { this.config = config; const categorizedComponentIds: string[] = []; diff --git a/ui/src/app/edge/settings/component/update/update.component.ts b/ui/src/app/edge/settings/component/update/update.component.ts index e4e0f1b7f5b..08a268df402 100644 --- a/ui/src/app/edge/settings/component/update/update.component.ts +++ b/ui/src/app/edge/settings/component/update/update.component.ts @@ -4,7 +4,6 @@ import { Component, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { FormlyFieldConfig } from '@ngx-formly/core'; import { Service, Utils, Websocket, EdgeConfig, Edge } from '../../../../shared/shared'; -import { TranslateService } from '@ngx-translate/core'; @Component({ selector: ComponentUpdateComponent.SELECTOR, @@ -28,55 +27,54 @@ export class ComponentUpdateComponent implements OnInit { protected utils: Utils, private websocket: Websocket, private service: Service, - private translate: TranslateService, ) { } - ngOnInit() { - this.service.setCurrentComponent({ languageKey: 'Edge.Config.Index.adjustComponents' }, this.route).then(edge => { - this.edge = edge; - }); + async ngOnInit() { + this.edge = await this.service.getCurrentEdge(); const componentId = this.route.snapshot.params["componentId"]; - this.service.getConfig().then(config => { - this.componentId = componentId; - const component = config.components[componentId]; - this.factory = config.factories[component.factoryId]; - this.componentIcon = config.getFactoryIcon(this.factory); - const fields: FormlyFieldConfig[] = []; - const model = {}; - for (const property of this.factory.properties) { - if (property.id === 'id') { - continue; // ignore Component-ID - } - const property_id = property.id.replace('.', '_'); - const field: FormlyFieldConfig = { - key: property_id, - type: 'input', - templateOptions: { - label: property.name, - description: property.description, - required: property.isRequired, - }, - }; - // add Property Schema - Utils.deepCopy(property.schema, field); - fields.push(field); - if (component.properties[property.id]) { + const config = await this.service.getConfig(); + this.componentId = componentId; + const component = config.components[componentId]; + this.componentIcon = config.getFactoryIcon(this.factory); + const fields: FormlyFieldConfig[] = []; + const model = {}; - // filter arrays with nested objects - if (Array.isArray(component.properties[property.id]) && component.properties[property.id]?.length > 0 && component.properties[property.id]?.every(element => typeof element === 'object')) { + const [factory, properties] = await this.edge.getFactoryProperties(this.websocket, component.factoryId); + this.factory = factory; + + for (const property of properties) { + if (property.id === 'id') { + continue; // ignore Component-ID + } + const property_id = property.id.replace('.', '_'); + const field: FormlyFieldConfig = { + key: property_id, + type: 'input', + templateOptions: { + label: property.name, + description: property.description, + required: property.isRequired, + }, + }; + // add Property Schema + Utils.deepCopy(property.schema, field); + fields.push(field); + if (component.properties[property.id]) { - // Stringify json for objects nested inside an array - model[property_id] = JSON.stringify(component.properties[property.id]); - } else { - model[property_id] = component.properties[property.id]; - } + // filter arrays with nested objects + if (Array.isArray(component.properties[property.id]) && component.properties[property.id]?.length > 0 && component.properties[property.id]?.every(element => typeof element === 'object')) { + + // Stringify json for objects nested inside an array + model[property_id] = JSON.stringify(component.properties[property.id]); + } else { + model[property_id] = component.properties[property.id]; } } - this.form = new FormGroup({}); - this.fields = fields; - this.model = model; - }); + } + this.form = new FormGroup({}); + this.fields = fields; + this.model = model; } public submit() { diff --git a/ui/src/app/edge/settings/system/executeSystemUpdate.ts b/ui/src/app/edge/settings/system/executeSystemUpdate.ts index 00b806ce07c..04da612d21d 100644 --- a/ui/src/app/edge/settings/system/executeSystemUpdate.ts +++ b/ui/src/app/edge/settings/system/executeSystemUpdate.ts @@ -3,7 +3,6 @@ import { Subject, timer } from "rxjs"; import { takeUntil } from "rxjs/operators"; import { ComponentJsonApiRequest } from "src/app/shared/jsonrpc/request/componentJsonApiRequest"; import { Edge, Websocket } from "src/app/shared/shared"; -import { Role } from "src/app/shared/type/role"; import { environment } from "src/environments"; import { ExecuteSystemUpdateRequest } from "./executeSystemUpdateRequest"; import { GetSystemUpdateStateRequest } from "./getSystemUpdateStateRequest"; @@ -51,35 +50,26 @@ export class ExecuteSystemUpdate { private refreshSystemUpdateState(): Promise { return new Promise((resolve, reject) => { - // if the version is a SNAPSHOT always set the udpate state - // to updated with the current SNAPSHOT version - if (this.edge.isSnapshot() && !this.edge.roleIsAtLeast(Role.ADMIN)) { - const updateState = { updated: { version: this.edge.version } }; - this.setSystemUpdateState(updateState); - this.stopRefreshSystemUpdateState(); - resolve(updateState); - } else { - this.edge.sendRequest(this.websocket, - new ComponentJsonApiRequest({ - componentId: "_host", - payload: new GetSystemUpdateStateRequest(), - })).then(response => { - const result = (response as GetSystemUpdateStateResponse).result; + this.edge.sendRequest(this.websocket, + new ComponentJsonApiRequest({ + componentId: "_host", + payload: new GetSystemUpdateStateRequest(), + })).then(response => { + const result = (response as GetSystemUpdateStateResponse).result; - this.setSystemUpdateState(result); - // Stop regular check if there is no Update available - if (result.updated) { - this.stopRefreshSystemUpdateState(); - } - resolve(this.systemUpdateState); - }).catch(error => { - if (this.systemUpdateState.running) { - this.isEdgeRestarting = true; - return; - } - reject(error); - }); - } + this.setSystemUpdateState(result); + // Stop regular check if there is no Update available + if (result.updated) { + this.stopRefreshSystemUpdateState(); + } + resolve(this.systemUpdateState); + }).catch(error => { + if (this.systemUpdateState.running) { + this.isEdgeRestarting = true; + return; + } + reject(error); + }); }); } diff --git a/ui/src/app/index/index.module.ts b/ui/src/app/index/index.module.ts index 9c1805b0a24..fc90698bdaf 100644 --- a/ui/src/app/index/index.module.ts +++ b/ui/src/app/index/index.module.ts @@ -6,6 +6,7 @@ import { FilterComponent } from './filter/filter.component'; import { OverViewComponent } from './overview/overview.component'; import { SumStateComponent } from './shared/sumState'; import { LoginComponent } from './login.component'; +import { LoadingScreenComponent } from './shared/loading-screen'; @NgModule({ imports: [ @@ -17,6 +18,7 @@ import { LoginComponent } from './login.component'; SumStateComponent, LoginComponent, OverViewComponent, + LoadingScreenComponent, ], }) export class IndexModule { } diff --git a/ui/src/app/index/login.component.html b/ui/src/app/index/login.component.html index 8c901dfc4d6..4c4cf15f044 100644 --- a/ui/src/app/index/login.component.html +++ b/ui/src/app/index/login.component.html @@ -93,4 +93,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/index/login.component.ts b/ui/src/app/index/login.component.ts index 4cb1c9ff054..1197e06d501 100644 --- a/ui/src/app/index/login.component.ts +++ b/ui/src/app/index/login.component.ts @@ -5,6 +5,7 @@ import { ActivatedRoute, Router } from '@angular/router'; import { Subject } from 'rxjs'; import { environment } from 'src/environments'; +import { AppService } from '../app.service'; import { AuthenticateWithPasswordRequest } from '../shared/jsonrpc/request/authenticateWithPasswordRequest'; import { Edge, Service, Utils, Websocket } from '../shared/shared'; @@ -19,6 +20,9 @@ export class LoginComponent implements OnInit, AfterContentChecked, OnDestroy { private page = 0; protected formIsDisabled: boolean = false; + protected popoverActive: 'android' | 'iOS' | null = null; + protected readonly isApp: boolean = AppService.isApp; + constructor( public service: Service, public websocket: Websocket, diff --git a/ui/src/app/index/shared/loading-screen.html b/ui/src/app/index/shared/loading-screen.html new file mode 100644 index 00000000000..c20266ac0b3 --- /dev/null +++ b/ui/src/app/index/shared/loading-screen.html @@ -0,0 +1,5 @@ + + +

      Loading...

      +
      +
      \ No newline at end of file diff --git a/ui/src/app/index/shared/loading-screen.ts b/ui/src/app/index/shared/loading-screen.ts new file mode 100644 index 00000000000..8538a706089 --- /dev/null +++ b/ui/src/app/index/shared/loading-screen.ts @@ -0,0 +1,38 @@ +// @ts-strict-ignore +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; + +import { Service, Websocket } from '../../shared/shared'; + +@Component({ + selector: 'index', + templateUrl: './loading-screen.html', +}) +export class LoadingScreenComponent implements OnInit { + + protected readonly spinnerId: string = "IndexComponent"; + + constructor( + public service: Service, + public websocket: Websocket, + private router: Router, + ) { } + + ngOnInit() { + + // TODO add websocket status observable + const interval = setInterval(() => { + this.service.startSpinner(this.spinnerId); + if (this.websocket.status === 'online') { + this.service.stopSpinner(this.spinnerId); + this.router.navigate(['/overview']); + clearInterval(interval); + } + if (this.websocket.status === 'waiting for credentials') { + this.service.stopSpinner(this.spinnerId); + this.router.navigate(['/login']); + clearInterval(interval); + } + }, 1000); + } +} diff --git a/ui/src/app/shared/directive/autofill.ts b/ui/src/app/shared/directive/autofill.ts new file mode 100644 index 00000000000..8665630df5b --- /dev/null +++ b/ui/src/app/shared/directive/autofill.ts @@ -0,0 +1,25 @@ +// @ts-strict-ignore +import { Directive, ElementRef, OnInit } from '@angular/core'; +import { Capacitor } from '@capacitor/core'; +import { Logger } from '../shared'; + +@Directive({ + selector: '[appAutofill]', +}) +export class AutofillDirective implements OnInit { + + constructor(private el: ElementRef, private logger: Logger) { } + + ngOnInit(): void { + if (Capacitor.getPlatform() !== 'ios') { return; } + setTimeout(() => { + try { + this.el.nativeElement.children[0].addEventListener('change', (e) => { + this.el.nativeElement.value = (e.target as any).value; + }); + } catch { + console.error("Android Autofill Directive inactive"); + } + }, 100); // Need some time for the ion-input to create the input element + } +} diff --git a/ui/src/app/shared/edge/edge.spec.ts b/ui/src/app/shared/edge/edge.spec.ts new file mode 100644 index 00000000000..9d943acd1ed --- /dev/null +++ b/ui/src/app/shared/edge/edge.spec.ts @@ -0,0 +1,53 @@ + +import { TestBed } from "@angular/core/testing"; +import { DummyConfig } from "./edgeconfig.spec"; +import { EdgeConfig, Websocket } from "../shared"; +import { GetPropertiesOfFactoryResponse } from "../jsonrpc/response/getPropertiesOfFactoryResponse"; +import { JsonrpcResponseSuccess } from "../jsonrpc/base"; +import { GetEdgeConfigResponse } from "../jsonrpc/response/getEdgeConfigResponse"; + +describe('Edge', () => { + const websocketSpyObject = jasmine.createSpyObj('Websocket', ['sendRequest']); + + let websocket: Websocket; + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + { provide: Websocket, useValue: websocketSpyObject }, + ], + }); + websocket = TestBed.inject(Websocket); + }); + + it('#getFactoryPropertiesOldVersion', async () => { + const edge = DummyConfig.dummyEdge({ version: '2024.1.1' }); + + const dummyConfig = DummyConfig.from(DummyConfig.Component.EVCS_KEBA_KECONTACT('evcs0')); + dummyConfig.factories[DummyConfig.Factory.EVCS_KEBA_KECONTACT.id].properties.push(new EdgeConfig.FactoryProperty()); + websocketSpyObject.sendRequest.and.resolveTo(new JsonrpcResponseSuccess('', { + payload: new GetEdgeConfigResponse('', dummyConfig), + })); + + const [factory, properties] = await edge.getFactoryProperties(websocket, DummyConfig.Factory.EVCS_KEBA_KECONTACT.id); + expect(factory.id).toBe(DummyConfig.Factory.EVCS_KEBA_KECONTACT.id); + expect(properties).toBe(dummyConfig.factories[DummyConfig.Factory.EVCS_KEBA_KECONTACT.id].properties); + }); + + it('#getFactoryPropertiesNewVersion', async () => { + const edge = DummyConfig.dummyEdge({ version: '2024.6.1' }); + + const dummmyFactory = new EdgeConfig.Factory('dummy.factory.id', 'description'); + const dummyProperties: EdgeConfig.FactoryProperty[] = [new EdgeConfig.FactoryProperty()]; + + websocketSpyObject.sendRequest.and.resolveTo(new JsonrpcResponseSuccess('', { + payload: new GetPropertiesOfFactoryResponse('', { + factory: dummmyFactory, + properties: dummyProperties, + }), + })); + + const [factory, properties] = await edge.getFactoryProperties(websocket, 'dummy.factory.id'); + expect(factory).toBe(dummmyFactory); + expect(properties).toBe(dummyProperties); + }); +}); diff --git a/ui/src/app/shared/edge/edge.ts b/ui/src/app/shared/edge/edge.ts index 93e0077735d..2a8c11a4dcc 100644 --- a/ui/src/app/shared/edge/edge.ts +++ b/ui/src/app/shared/edge/edge.ts @@ -28,6 +28,9 @@ import { GetChannelResponse } from '../jsonrpc/response/getChannelResponse'; import { Channel, GetChannelsOfComponentResponse } from '../jsonrpc/response/getChannelsOfComponentResponse'; import { GetChannelsOfComponentRequest } from '../jsonrpc/request/getChannelsOfComponentRequest'; import { EdgePermission } from '../shared'; +import { filter, first } from 'rxjs/operators'; +import { GetPropertiesOfFactoryRequest } from '../jsonrpc/request/getPropertiesOfFactoryRequest'; +import { GetPropertiesOfFactoryResponse } from '../jsonrpc/response/getPropertiesOfFactoryResponse'; export class Edge { @@ -71,6 +74,18 @@ export class Edge { return this.config; } + /** + * Gets the first valid Config. If not available yet, it requests it via Websocket. + * + * @param websocket the Websocket connection + */ + public getFirstValidConfig(websocket: Websocket): Promise { + return this.getConfig(websocket) + .pipe(filter(config => config != null && config.isValid()), + first()) + .toPromise(); + } + /** * Gets a channel either from {@link EdgeConfig edgeconfig} or requests it from the edge. * @@ -81,8 +96,8 @@ export class Edge { */ public async getChannel(websocket: Websocket, channel: ChannelAddress): Promise { if (EdgePermission.hasChannelsInEdgeConfig(this)) { - const config = await this.getConfig(websocket); - const foundChannel = config.value.getChannel(channel); + const config = await this.getFirstValidConfig(websocket); + const foundChannel = config.getChannel(channel); if (!foundChannel) { throw new Error("Channel not found: " + channel); } @@ -110,8 +125,8 @@ export class Edge { */ public async getChannels(websocket: Websocket, componentId: string): Promise { if (EdgePermission.hasChannelsInEdgeConfig(this)) { - const config = await this.getConfig(websocket); - const component = config.value.components[componentId]; + const config = await this.getFirstValidConfig(websocket); + const component = config.components[componentId]; if (!component) { throw new Error('Component not found'); } @@ -128,6 +143,19 @@ export class Edge { return response.result.channels; } + public async getFactoryProperties(websocket: Websocket, factoryId: string): Promise<[EdgeConfig.Factory, EdgeConfig.FactoryProperty[]]> { + if (EdgePermission.hasReducedFactories(this)) { + const response = await this.sendRequest(websocket, new ComponentJsonApiRequest({ + componentId: '_componentManager', + payload: new GetPropertiesOfFactoryRequest({ factoryId }), + })); + return [response.result.factory, response.result.properties]; + } + + const factory = (await this.getFirstValidConfig(websocket)).factories[factoryId]; + return [factory, factory.properties]; + } + /** * Called by Service, when this Edge is set as currentEdge. */ diff --git a/ui/src/app/shared/edge/edgeconfig.spec.ts b/ui/src/app/shared/edge/edgeconfig.spec.ts index 9b6a9bb0b99..f2fbe800b66 100644 --- a/ui/src/app/shared/edge/edgeconfig.spec.ts +++ b/ui/src/app/shared/edge/edgeconfig.spec.ts @@ -10,12 +10,42 @@ import { EdgeConfig, PersistencePriority } from "./edgeconfig"; export namespace DummyConfig { + export function dummyEdge(values: { + edgeId?: string, + comment?: string, + producttype?: string, + version?: string, + role?: Role, + isOnline?: boolean, + lastmessage?: Date, + sumState?: SumState, + firstSetupProtocol?: Date, + }): Edge { + return new Edge( + values.edgeId ?? "edge0", + values.comment ?? "edge0", + values.producttype ?? "", + values.version ?? "2023.3.5", + values.role ?? Role.ADMIN, + values.isOnline ?? true, + values.lastmessage ?? new Date(), + values.sumState ?? SumState.OK, + values.firstSetupProtocol ?? new Date(0), + ); + } + const DUMMY_EDGE: Edge = new Edge("edge0", "", "", "2023.3.5", Role.ADMIN, true, new Date(), SumState.OK, new Date(0)); export function from(...components: Component[]): EdgeConfig { - return new EdgeConfig(DUMMY_EDGE, { - components: components?.reduce((acc, c) => ({ ...acc, [c.id]: c }), {}), - factories: components?.map(c => c.factory), + return new EdgeConfig(DUMMY_EDGE, { + components: components?.reduce((acc, c) => { + c.factoryId = c.factory.id; + return ({ ...acc, [c.id]: c }); + }, {}), + factories: components?.reduce((p, c) => { + p[c.factory.id] = new EdgeConfig.Factory(c.factory.id, '', c.factory.natureIds); + return p; + }, {}), }); } @@ -24,16 +54,15 @@ export namespace DummyConfig { const factories = {}; components.forEach(obj => { - const component = obj as unknown; - if (factories[component['factoryId']]) { - factories[component['factoryId']].componentIds = [...factories[component['factoryId']].componentIds, ...component['factory'].componentIds]; + if (factories[obj.factoryId]) { + factories[obj.factoryId].componentIds = [...factories[obj.factoryId].componentIds, obj.id]; } else { - factories[component['factoryId']] = { - componentIds: component['factory'].componentIds, + factories[obj.factoryId] = { + componentIds: [obj.id], description: "", - id: component['factoryId'], - name: component['factoryId'], - natureIds: component['factory'].natureIds, + id: obj.factoryId, + name: obj.factoryId, + natureIds: edgeConfig.factories[obj.factoryId].natureIds, properties: [], }; } @@ -45,7 +74,7 @@ export namespace DummyConfig { }); } - namespace Factory { + export namespace Factory { export const METER_SOCOMEC_THREEPHASE = { id: "Meter.Socomec.Threephase", @@ -210,7 +239,8 @@ export namespace DummyConfig { // identifier `Factory` is also used in namespace // eslint-disable-next-line @typescript-eslint/no-unused-vars type Factory = { - id: string + id: string, + natureIds: string[], }; /** diff --git a/ui/src/app/shared/edge/edgeconfig.ts b/ui/src/app/shared/edge/edgeconfig.ts index 47b529147d6..e5e04a8b8f8 100644 --- a/ui/src/app/shared/edge/edgeconfig.ts +++ b/ui/src/app/shared/edge/edgeconfig.ts @@ -120,34 +120,62 @@ export class EdgeConfig { } } + public getFactoriesByNature(natureId: string): EdgeConfig.Factory[] { + return EdgeConfig.getFactoriesByNature(this.factories, natureId); + } + /** * Get Factories of Nature. * * @param natureId the given Nature. */ - public getFactoriesByNature(natureId: string): EdgeConfig.Factory[] { + public static getFactoriesByNature(factories: { [id: string]: EdgeConfig.Factory }, natureId: string): EdgeConfig.Factory[] { const result = []; - const nature = this.natures[natureId]; + const nature = EdgeConfig.getNaturesOfFactories(factories)[natureId]; if (nature) { for (const factoryId of nature.factoryIds) { - if (factoryId in this.factories) { - result.push(this.factories[factoryId]); + if (factoryId in factories) { + result.push(factories[factoryId]); } } } return result; } + public static getNaturesOfFactories(factories: { [id: string]: EdgeConfig.Factory }): { [natureId: string]: EdgeConfig.Nature } { + const natures: { [natureId: string]: EdgeConfig.Nature } = {}; + // initialize Factorys + for (const [factoryId, factory] of Object.entries(factories)) { + // Fill 'natures' map + for (const natureId of factory.natureIds) { + if (!(natureId in natures)) { + const parts = natureId.split("."); + const name = parts[parts.length - 1]; + natures[natureId] = { + id: natureId, + name: name, + factoryIds: [], + }; + } + natures[natureId].factoryIds.push(factoryId); + } + } + return natures; + } + /** * Get Factories by Factory-IDs. * * @param ids the given Factory-IDs. */ public getFactoriesByIds(factoryIds: string[]): EdgeConfig.Factory[] { + return EdgeConfig.getFactoriesByIds(this.factories, factoryIds); + } + public static getFactoriesByIds(factories: { [id: string]: EdgeConfig.Factory }, factoryIds: string[]): EdgeConfig.Factory[] { const result = []; for (const factoryId of factoryIds) { - if (factoryId in this.factories) { - result.push(this.factories[factoryId]); + if (factoryId in factories) { + result.push(factories[factoryId]); } } return result; @@ -159,11 +187,15 @@ export class EdgeConfig { * @param ids the given Factory-IDs pattern. */ public getFactoriesByIdsPattern(patterns: RegExp[]): EdgeConfig.Factory[] { + return EdgeConfig.getFactoriesByIdsPattern(this.factories, patterns); + } + + public static getFactoriesByIdsPattern(factories: { [id: string]: EdgeConfig.Factory }, patterns: RegExp[]): EdgeConfig.Factory[] { const result = []; for (const pattern of patterns) { - for (const factoryId in this.factories) { + for (const factoryId in factories) { if (pattern.test(factoryId)) { - result.push(this.factories[factoryId]); + result.push(factories[factoryId]); } } } @@ -248,6 +280,17 @@ export class EdgeConfig { } } + /** + * Determines if component has nature + * + * @param nature the given Nature. + * @param componentId the Component-ID + */ + public hasComponentNature(nature: string, componentId: string) { + const natureIds = this.getNatureIdsByComponentId(componentId); + return natureIds.includes(nature); + } + /** * Determines if Edge has a Storage device */ @@ -362,35 +405,41 @@ export class EdgeConfig { return false; } + public listAvailableFactories(): CategorizedFactories[] { + return EdgeConfig.listAvailableFactories(this.factories); + } + /** * Lists all available Factories, grouped by category. */ - public listAvailableFactories(): CategorizedFactories[] { + public static listAvailableFactories(factories: { [id: string]: EdgeConfig.Factory }): CategorizedFactories[] { const allFactories = [ { category: { title: 'Simulatoren', icon: 'flask-outline' }, - factories: Object.values(this.factories).filter(factory => factory.id.startsWith('Simulator.')), + factories: Object.entries(factories) + .filter(([factory]) => factory.startsWith('Simulator.')) + .map(e => e[1]), }, { category: { title: 'Zähler', icon: 'speedometer-outline' }, factories: [ - this.getFactoriesByNature("io.openems.edge.meter.api.SymmetricMeter"), // TODO replaced by ElectricityMeter - this.getFactoriesByNature("io.openems.edge.meter.api.ElectricityMeter"), - this.getFactoriesByNature("io.openems.edge.ess.dccharger.api.EssDcCharger"), + EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.meter.api.SymmetricMeter"), // TODO replaced by ElectricityMeter + EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.meter.api.ElectricityMeter"), + EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.ess.dccharger.api.EssDcCharger"), ], }, { category: { title: 'Speichersysteme', icon: 'battery-charging-outline' }, factories: [ - this.getFactoriesByNature("io.openems.edge.ess.api.SymmetricEss"), - this.getFactoriesByNature("io.openems.edge.battery.api.Battery"), - this.getFactoriesByNature("io.openems.edge.batteryinverter.api.ManagedSymmetricBatteryInverter"), + EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.ess.api.SymmetricEss"), + EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.battery.api.Battery"), + EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.batteryinverter.api.ManagedSymmetricBatteryInverter"), ], }, { category: { title: 'Speichersystem-Steuerung', icon: 'options-outline' }, factories: [ - this.getFactoriesByIdsPattern([ + EdgeConfig.getFactoriesByIdsPattern(factories, [ /Controller\.Asymmetric.*/, /Controller\.Ess.*/, /Controller\.Symmetric.*/, @@ -400,13 +449,13 @@ export class EdgeConfig { { category: { title: 'E-Auto-Ladestation', icon: 'car-outline' }, factories: [ - this.getFactoriesByNature("io.openems.edge.evcs.api.Evcs"), + EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.evcs.api.Evcs"), ], }, { category: { title: 'E-Auto-Ladestation-Steuerung', icon: 'options-outline' }, factories: [ - this.getFactoriesByIds([ + EdgeConfig.getFactoriesByIds(factories, [ 'Controller.Evcs', ]), ], @@ -414,14 +463,14 @@ export class EdgeConfig { { category: { title: 'I/Os', icon: 'log-in-outline' }, factories: [ - this.getFactoriesByNature("io.openems.edge.io.api.DigitalOutput"), - this.getFactoriesByNature("io.openems.edge.io.api.DigitalInput"), + EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.io.api.DigitalOutput"), + EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.io.api.DigitalInput"), ], }, { category: { title: 'I/O-Steuerung', icon: 'options-outline' }, factories: [ - this.getFactoriesByIds([ + EdgeConfig.getFactoriesByIds(factories, [ 'Controller.IO.ChannelSingleThreshold', 'Controller.Io.FixDigitalOutput', 'Controller.IO.HeatingElement', @@ -432,13 +481,13 @@ export class EdgeConfig { { category: { title: 'Temperatursensoren', icon: 'thermometer-outline' }, factories: [ - this.getFactoriesByNature("io.openems.edge.thermometer.api.Thermometer"), + EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.thermometer.api.Thermometer"), ], }, { category: { title: 'Externe Schnittstellen', icon: 'megaphone-outline' }, factories: [ - this.getFactoriesByIds([ + EdgeConfig.getFactoriesByIds(factories, [ 'Controller.Api.Websocket', 'Controller.Api.ModbusTcp', 'Controller.Api.ModbusTcp.ReadOnly', @@ -452,10 +501,10 @@ export class EdgeConfig { { category: { title: 'Cloud-Schnittstellen', icon: 'cloud-outline' }, factories: [ - this.getFactoriesByIdsPattern([ + EdgeConfig.getFactoriesByIdsPattern(factories, [ /TimeOfUseTariff\.*/, ]), - this.getFactoriesByIds([ + EdgeConfig.getFactoriesByIds(factories, [ 'Controller.Api.Backend', ]), ], @@ -463,7 +512,7 @@ export class EdgeConfig { { category: { title: 'Geräte-Schnittstellen', icon: 'swap-horizontal-outline' }, factories: [ - this.getFactoriesByIds([ + EdgeConfig.getFactoriesByIds(factories, [ 'Bridge.Mbus', 'Bridge.Onewire', 'Bridge.Modbus.Serial', @@ -475,24 +524,24 @@ export class EdgeConfig { { category: { title: 'Standard-Komponenten', icon: 'resize-outline' }, factories: [ - this.getFactoriesByIds([ + EdgeConfig.getFactoriesByIds(factories, [ 'Controller.Debug.Log', 'Controller.Debug.DetailedLog', ]), - this.getFactoriesByNature("io.openems.edge.timedata.api.Timedata"), - this.getFactoriesByNature("io.openems.edge.predictor.api.oneday.Predictor24Hours"), - this.getFactoriesByNature("io.openems.edge.scheduler.api.Scheduler"), + EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.timedata.api.Timedata"), + EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.predictor.api.oneday.Predictor24Hours"), + EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.scheduler.api.Scheduler"), ], }, { category: { title: 'Spezial-Controller', icon: 'repeat-outline' }, factories: [ - this.getFactoriesByNature("io.openems.edge.controller.api.Controller"), + EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.controller.api.Controller"), ], }, { category: { title: 'Weitere', icon: 'radio-button-off-outline' }, - factories: Object.values(this.factories), + factories: Object.values(factories), }, ]; diff --git a/ui/src/app/shared/genericComponents/chart/abstracthistorychart.html b/ui/src/app/shared/genericComponents/chart/abstracthistorychart.html index e0ac9bd56e9..0c1225b56f0 100644 --- a/ui/src/app/shared/genericComponents/chart/abstracthistorychart.html +++ b/ui/src/app/shared/genericComponents/chart/abstracthistorychart.html @@ -1,5 +1,5 @@ - +
      @@ -7,6 +7,7 @@
      - + -
      \ No newline at end of file + diff --git a/ui/src/app/shared/genericComponents/chart/chart.html b/ui/src/app/shared/genericComponents/chart/chart.html index f6f67a457d5..075411661cb 100644 --- a/ui/src/app/shared/genericComponents/chart/chart.html +++ b/ui/src/app/shared/genericComponents/chart/chart.html @@ -19,7 +19,7 @@ - + - \ No newline at end of file + diff --git a/ui/src/app/shared/genericComponents/footer-navigation/footerNavigation.html b/ui/src/app/shared/genericComponents/footer-navigation/footerNavigation.html new file mode 100644 index 00000000000..bfa8f32655c --- /dev/null +++ b/ui/src/app/shared/genericComponents/footer-navigation/footerNavigation.html @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + {{button.alias ?? button.id}} + + + ... + + + + + + + + + {{popoverbtn.alias ?? popoverbtn.id}} + + + + + + + + + + + + + + + diff --git a/ui/src/app/shared/genericComponents/footer-navigation/footerNavigation.ts b/ui/src/app/shared/genericComponents/footer-navigation/footerNavigation.ts new file mode 100644 index 00000000000..b0774b0538b --- /dev/null +++ b/ui/src/app/shared/genericComponents/footer-navigation/footerNavigation.ts @@ -0,0 +1,114 @@ +import { Location } from "@angular/common"; +import { AfterViewInit, ChangeDetectorRef, Component, ElementRef, HostListener, Input, QueryList, ViewChild, ViewChildren } from "@angular/core"; +import { PopoverController } from "@ionic/angular"; + +export type NavigationOption = { + id: string, + callback: () => void, + alias?: string, +}; + +@Component({ + selector: 'oe-footer-subnavigation', + templateUrl: 'footerNavigation.html', +}) +export class FooterNavigationComponent implements AfterViewInit { + + @ViewChildren('subnavigationbuttons', { read: ElementRef }) + public subnavigationbuttons!: QueryList; + @ViewChild('container', { read: ElementRef }) public container!: ElementRef; + + @Input() public backButton: boolean = false; + @Input() public set navigationOptions(nodes: NavigationOption[]) { + this._buttons = nodes; + this.buttons = nodes; + } + + protected areButtonsReadyToShow: boolean = false; + protected buttons: NavigationOption[] = []; + protected popoverButtons: NavigationOption[] | null = []; + protected showPopover: boolean = false; + + private _buttons: NavigationOption[] = []; + + private static readonly INTERVAL: number = 1000; + + constructor( + protected location: Location, + protected popoverCtrl: PopoverController, + private cdr: ChangeDetectorRef, + ) { + } + + ngAfterViewInit() { + this.cdr.detectChanges(); + this.initializeFooterSubnavigation(); + } + + protected togglePopover(popoverbtn: NavigationOption) { + popoverbtn.callback(); + this.showPopover = false; + } + + @HostListener('window:resize', ['$event.target.innerWidth']) + private onResize(width: number) { + this.initializeFooterSubnavigation(); + } + + + /** + * Initializes sub-navigation + */ + private initializeFooterSubnavigation(): void { + this.buttons = this._buttons; + this.getSplitIndex() + .then((indexToSplit) => { + + if (indexToSplit == null) { + return; + } + + this.buttons = this._buttons.slice(0, indexToSplit); + this.popoverButtons = this._buttons.slice(indexToSplit); + this.areButtonsReadyToShow = true; + }); + } + + /** + * Gets the split index for navigation buttons + * + * @returns a promise + */ + private async getSplitIndex(): Promise { + return new Promise((resolve) => { + let indexToSplit: number = 0; + + const interval = setInterval(() => { + if (this.subnavigationbuttons && this.container) { + + const colLeftPadding = 16; + const paddingLeftRight = 24; + const ionItemWidth = this.container?.nativeElement.offsetWidth - colLeftPadding; + if (ionItemWidth) { + + let sum: number = colLeftPadding; + this.subnavigationbuttons.forEach((b, index, el) => { + sum += b.nativeElement.offsetWidth + paddingLeftRight; + if ((ionItemWidth) > sum) { + indexToSplit = index; + } + }); + + // Workaround + if (ionItemWidth > sum) { + ++indexToSplit; + } + + clearInterval(interval); + resolve(indexToSplit); + } + } + }, FooterNavigationComponent.INTERVAL); + }); + } +} diff --git a/ui/src/app/shared/genericComponents/genericComponents.ts b/ui/src/app/shared/genericComponents/genericComponents.ts index 417ac36b721..7136735eded 100644 --- a/ui/src/app/shared/genericComponents/genericComponents.ts +++ b/ui/src/app/shared/genericComponents/genericComponents.ts @@ -13,6 +13,7 @@ import { FlatWidgetHorizontalLineComponent } from './flat/flat-widget-horizontal import { FlatWidgetLineComponent } from './flat/flat-widget-line/flat-widget-line'; import { FlatWidgetLineItemComponent } from './flat/flat-widget-line/flat-widget-line-item/flat-widget-line-item'; import { FlatWidgetPercentagebarComponent } from './flat/flat-widget-percentagebar/flat-widget-percentagebar'; +import { FooterNavigationComponent } from './footer-navigation/footerNavigation'; import { HelpButtonComponent } from './modal/help-button/help-button'; import { ModalComponent } from './modal/modal'; import { ModalButtonsComponent } from './modal/modal-button/modal-button'; @@ -59,6 +60,7 @@ import { NotificationComponent } from './shared/notification/notification'; PickDateComponent, HelpButtonComponent, NotificationComponent, + FooterNavigationComponent, ], exports: [ // Flat @@ -85,6 +87,7 @@ import { NotificationComponent } from './shared/notification/notification'; PickDateComponent, HelpButtonComponent, NotificationComponent, + FooterNavigationComponent, ], schemas: [CUSTOM_ELEMENTS_SCHEMA], diff --git a/ui/src/app/shared/genericComponents/shared/converter.ts b/ui/src/app/shared/genericComponents/shared/converter.ts index 12458d38a0e..4054c9f9ec0 100644 --- a/ui/src/app/shared/genericComponents/shared/converter.ts +++ b/ui/src/app/shared/genericComponents/shared/converter.ts @@ -1,6 +1,7 @@ // @ts-strict-ignore import { TranslateService } from "@ngx-translate/core"; + import { CurrentData, EdgeConfig, Utils } from "../../shared"; import { TimeUtils } from "../../utils/time/timeutils"; import { Formatter } from "./formatter"; diff --git a/ui/src/app/shared/genericComponents/shared/dataservice.ts b/ui/src/app/shared/genericComponents/shared/dataservice.ts index 7af1ff7bb55..c43aad16467 100644 --- a/ui/src/app/shared/genericComponents/shared/dataservice.ts +++ b/ui/src/app/shared/genericComponents/shared/dataservice.ts @@ -3,6 +3,7 @@ import { Injectable } from "@angular/core"; import { BehaviorSubject, Subject } from "rxjs"; import { ChannelAddress, Edge } from "../../shared"; +import { RefresherCustomEvent } from "@ionic/angular"; @Injectable() export abstract class DataService { @@ -29,4 +30,6 @@ export abstract class DataService { * @param channels the channels */ public abstract unsubscribeFromChannels(channels: ChannelAddress[]); + + public abstract refresh(ev: RefresherCustomEvent); } diff --git a/ui/src/app/shared/jsonrpc/request/getPropertiesOfFactoryRequest.ts b/ui/src/app/shared/jsonrpc/request/getPropertiesOfFactoryRequest.ts new file mode 100644 index 00000000000..b5ed8cf783e --- /dev/null +++ b/ui/src/app/shared/jsonrpc/request/getPropertiesOfFactoryRequest.ts @@ -0,0 +1,33 @@ + +import { JsonrpcRequest } from "../base"; + +/** + * Represents a JSON-RPC Request to get properties and the factory of a factoryId. + * + *

      + * This is used by UI to get the properties for component update and installation. + * + *

      + * {
      + *   "jsonrpc": "2.0",
      + *   "id": "UUID",
      + *   "method": "getPropertiesOfFactory",
      + *   "params": {
      + *      "factoryId": string
      + *   }
      + * }
      + * 
      + */ +export class GetPropertiesOfFactoryRequest extends JsonrpcRequest { + + private static METHOD: string = "getPropertiesOfFactory"; + + public constructor( + params: { + factoryId: string, + }, + ) { + super(GetPropertiesOfFactoryRequest.METHOD, params); + } + +} diff --git a/ui/src/app/shared/jsonrpc/response/getPropertiesOfFactoryResponse.ts b/ui/src/app/shared/jsonrpc/response/getPropertiesOfFactoryResponse.ts new file mode 100644 index 00000000000..7ca2647c505 --- /dev/null +++ b/ui/src/app/shared/jsonrpc/response/getPropertiesOfFactoryResponse.ts @@ -0,0 +1,31 @@ +import { EdgeConfig } from "../../edge/edgeconfig"; +import { JsonrpcResponseSuccess } from "../base"; + +/** + * Represents a JSON-RPC Response for a {@link GetPropertiesOfFactoryResponse}. + * + *
      + * {
      + *   "jsonrpc": "2.0",
      + *   "id": UUID,
      + *   "result": {
      + *     "factory": EdgeConfig.Factory,
      + *     "properties": EdgeConfig.FactoryProperty[]
      + *   }
      + * }
      + * 
      + */ +export class GetPropertiesOfFactoryResponse extends JsonrpcResponseSuccess { + + public constructor( + public override readonly id: string, + public override readonly result: { + factory: EdgeConfig.Factory, + properties: EdgeConfig.FactoryProperty[], + }, + ) { + super(id, result); + } + +} + diff --git a/ui/src/app/shared/service/service.ts b/ui/src/app/shared/service/service.ts index 64997f0428c..fb192b6ae74 100644 --- a/ui/src/app/shared/service/service.ts +++ b/ui/src/app/shared/service/service.ts @@ -169,14 +169,10 @@ export class Service extends AbstractService { public getConfig(): Promise { return new Promise((resolve, reject) => { this.getCurrentEdge().then(edge => { - edge.getConfig(this.websocket).pipe( - filter(config => config != null && config.isValid()), - first(), - ).toPromise() - .then(config => resolve(config)) - .catch(reason => reject(reason)); - }) - .catch(reason => reject(reason)); + edge.getFirstValidConfig(this.websocket) + .then(resolve) + .catch(reject); + }).catch(reason => reject(reason)); }); } diff --git a/ui/src/app/shared/service/utils.ts b/ui/src/app/shared/service/utils.ts index c751bfd0527..8f3b5d125fd 100644 --- a/ui/src/app/shared/service/utils.ts +++ b/ui/src/app/shared/service/utils.ts @@ -659,7 +659,7 @@ export namespace HistoryUtils { export type DisplayValues = { name: string, /** suffix to the name */ - nameSuffix?: (energyValues: QueryHistoricTimeseriesEnergyResponse) => number | string, + nameSuffix?: (energyValues: QueryHistoricTimeseriesEnergyResponse) => number | string | null, /** Convert the values to be displayed in Chart */ converter: () => any, /** If dataset should be hidden on Init */ diff --git a/ui/src/app/shared/service/websocket.ts b/ui/src/app/shared/service/websocket.ts index a6295c1dbb9..2cfa39ac454 100644 --- a/ui/src/app/shared/service/websocket.ts +++ b/ui/src/app/shared/service/websocket.ts @@ -82,6 +82,7 @@ export class Websocket implements WebsocketInterface { } const token = this.cookieService.get('token'); if (token) { + // Login with Session Token this.login(new AuthenticateWithTokenRequest({ token: token })); this.status = 'authenticating'; @@ -89,7 +90,6 @@ export class Websocket implements WebsocketInterface { } else { // No Token -> directly ask for Login credentials this.status = 'waiting for credentials'; - this.router.navigate(['/login']); } }, }, diff --git a/ui/src/app/shared/shared.ts b/ui/src/app/shared/shared.ts index 12eb25994cb..86e15a76d18 100644 --- a/ui/src/app/shared/shared.ts +++ b/ui/src/app/shared/shared.ts @@ -70,6 +70,19 @@ export class EdgePermission { return !edge.isVersionAtLeast('2024.6.1'); } + /** + * Determines if the edge has only the factories which are used by the + * active components in the edgeconfig or if all factories are inlcuded. + * + * The reason this was introduced is to reduce the size of the EdgeConfig + * and therefore improve performance in network, backend, ui, edge. + * + * @returns true if only the factories of the used components are in the edgeconfig + */ + public static hasReducedFactories(edge: Edge): boolean { + return edge.isVersionAtLeast('2024.6.1'); + } + } export class UserPermission { diff --git a/ui/src/app/shared/status/single/status.component.spec.ts b/ui/src/app/shared/status/single/status.component.spec.ts index 7499acb1944..4f92151f8fb 100644 --- a/ui/src/app/shared/status/single/status.component.spec.ts +++ b/ui/src/app/shared/status/single/status.component.spec.ts @@ -12,7 +12,7 @@ describe('StatusComponent', () => { const testComponent = new EdgeConfig.Component("test", {}, { "testChannel": { accessMode: "RO", - category: "ENUM", + category: "STATE", type: "BOOLEAN", unit: "W", level: "OK", diff --git a/ui/src/app/shared/status/single/status.component.ts b/ui/src/app/shared/status/single/status.component.ts index c1d8c019409..c203e873a27 100644 --- a/ui/src/app/shared/status/single/status.component.ts +++ b/ui/src/app/shared/status/single/status.component.ts @@ -82,6 +82,12 @@ export class StatusSingleComponent implements OnInit, OnDestroy { if (EdgePermission.hasChannelsInEdgeConfig(this.edge)) { const channels: typeof this.channels['componentId'] = {}; for (const [key, value] of Object.entries(this.config.components[componentId].channels)) { + + // show only state channels + if (value.category !== "STATE") { + continue; + } + channels[key] = { text: value.text, level: value.level }; } resolve(channels); diff --git a/ui/src/assets/i18n/de.json b/ui/src/assets/i18n/de.json index fbd56096e39..b582b58c8b2 100644 --- a/ui/src/assets/i18n/de.json +++ b/ui/src/assets/i18n/de.json @@ -954,5 +954,8 @@ "SET_VALUE": "Eingestellter Wert", "MORE_CHANNELS": "Weitere Kanäle hinzufügen", "CHANNEL": "Kanal" + }, + "APP": { + "FUNCTIONALITY_TEMPORARILY_NOT_AVAILABLE": "Diese Funktion ist vorübergehend in der App nicht verfügbar, verwenden Sie bitte dafür die Web-App." } -} +} \ No newline at end of file diff --git a/ui/src/assets/i18n/en.json b/ui/src/assets/i18n/en.json index 3b4def7a994..70acb7994e9 100644 --- a/ui/src/assets/i18n/en.json +++ b/ui/src/assets/i18n/en.json @@ -957,5 +957,8 @@ "SET_VALUE": "Set value", "MORE_CHANNELS": "Add More Channels", "CHANNEL": "Channel" + }, + "APP": { + "FUNCTIONALITY_TEMPORARILY_NOT_AVAILABLE": "This function is temporarily not available in the app, please use the web app instead." } -} +} \ No newline at end of file From d6eaac18841ce38b42b305d417a4b315cb996838 Mon Sep 17 00:00:00 2001 From: Kai J <99220919+da-Kai@users.noreply.github.com> Date: Mon, 1 Jul 2024 11:14:23 +0200 Subject: [PATCH 062/173] CI: add Codecov for UI (#2693) --- .github/workflows/build.yml | 8 +++++++- codecov.yml | 3 ++- ui/karma.conf.js | 6 +++++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8211dc2cec2..a67813b0d63 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -70,4 +70,10 @@ jobs: node_modules/.bin/ng build -c "openems,openems-edge-prod,prod" node_modules/.bin/ng lint export CHROME_BIN=/usr/bin/google-chrome-stable - npm run test -- --no-watch --no-progress --browsers=ChromeHeadlessCI \ No newline at end of file + npm run test -- --no-watch --no-progress --browsers=ChromeHeadlessCI + + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v4 + with: + directory: ./ui/ + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/codecov.yml b/codecov.yml index 1f9dcb53ef3..00b2350eb74 100644 --- a/codecov.yml +++ b/codecov.yml @@ -4,7 +4,8 @@ coverage: status: project: default: - target: auto #default + target: auto + threshold: 10% comment: layout: "condensed_header, diff" diff --git a/ui/karma.conf.js b/ui/karma.conf.js index 65647d92cac..0980006d7ec 100644 --- a/ui/karma.conf.js +++ b/ui/karma.conf.js @@ -5,6 +5,9 @@ module.exports = function (config) { config.set({ basePath: '', frameworks: ['jasmine', '@angular-devkit/build-angular'], + preprocessor: { + 'src/**/*.ts': ['coverage'] + }, plugins: [ require('karma-jasmine'), require('karma-chrome-launcher'), @@ -28,11 +31,12 @@ module.exports = function (config) { dir: require('path').join(__dirname, './coverage/ngv'), subdir: '.', reporters: [ + {type: 'lcov'}, { type: 'html' }, { type: 'text-summary' } ], }, - reporters: ['progress', 'kjhtml'], + reporters: ['progress', 'kjhtml', 'coverage'], port: 9876, colors: true, logLevel: config.LOG_INFO, From 8011483ef5d6e3ff3084663b372468f058a937fa Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Mon, 1 Jul 2024 11:34:18 +0200 Subject: [PATCH 063/173] Push version to 2024.7.0 --- io.openems.common/src/io/openems/common/OpenemsConstants.java | 2 +- ui/package-lock.json | 4 ++-- ui/package.json | 2 +- ui/src/app/changelog/view/component/changelog.constants.ts | 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 28910dcf23c..848265f9c22 100644 --- a/io.openems.common/src/io/openems/common/OpenemsConstants.java +++ b/io.openems.common/src/io/openems/common/OpenemsConstants.java @@ -36,7 +36,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 2fb7e864c4f..b38f652d904 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "openems-ui", - "version": "2024.7.0-SNAPSHOT", + "version": "2024.7.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "openems-ui", - "version": "2024.7.0-SNAPSHOT", + "version": "2024.7.0", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "~16.2.12", diff --git a/ui/package.json b/ui/package.json index 4107030261c..cf51861bf7d 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,6 +1,6 @@ { "name": "openems-ui", - "version": "2024.7.0-SNAPSHOT", + "version": "2024.7.0", "license": "AGPL-3.0", "private": true, "dependencies": { diff --git a/ui/src/app/changelog/view/component/changelog.constants.ts b/ui/src/app/changelog/view/component/changelog.constants.ts index fec1a68180b..1341682b050 100644 --- a/ui/src/app/changelog/view/component/changelog.constants.ts +++ b/ui/src/app/changelog/view/component/changelog.constants.ts @@ -2,7 +2,7 @@ import { Role } from "src/app/shared/type/role"; export class Changelog { - public static readonly UI_VERSION = "2024.7.0-SNAPSHOT"; + public static readonly UI_VERSION = "2024.7.0"; public static product(...products: Product[]) { return products.map(product => Changelog.link(product.name, product.url)).join(", ") + '. '; From 30b35800ac5d976017d252097fa27c3a71be6fe6 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Mon, 1 Jul 2024 11:43:33 +0200 Subject: [PATCH 064/173] Push version to 2024.7.0 --- io.openems.common/src/io/openems/common/OpenemsConstants.java | 2 +- ui/package-lock.json | 4 ++-- ui/package.json | 2 +- ui/src/app/changelog/view/component/changelog.constants.ts | 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 28910dcf23c..848265f9c22 100644 --- a/io.openems.common/src/io/openems/common/OpenemsConstants.java +++ b/io.openems.common/src/io/openems/common/OpenemsConstants.java @@ -36,7 +36,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 2fb7e864c4f..b38f652d904 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "openems-ui", - "version": "2024.7.0-SNAPSHOT", + "version": "2024.7.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "openems-ui", - "version": "2024.7.0-SNAPSHOT", + "version": "2024.7.0", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "~16.2.12", diff --git a/ui/package.json b/ui/package.json index 4107030261c..cf51861bf7d 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,6 +1,6 @@ { "name": "openems-ui", - "version": "2024.7.0-SNAPSHOT", + "version": "2024.7.0", "license": "AGPL-3.0", "private": true, "dependencies": { diff --git a/ui/src/app/changelog/view/component/changelog.constants.ts b/ui/src/app/changelog/view/component/changelog.constants.ts index fec1a68180b..1341682b050 100644 --- a/ui/src/app/changelog/view/component/changelog.constants.ts +++ b/ui/src/app/changelog/view/component/changelog.constants.ts @@ -2,7 +2,7 @@ import { Role } from "src/app/shared/type/role"; export class Changelog { - public static readonly UI_VERSION = "2024.7.0-SNAPSHOT"; + public static readonly UI_VERSION = "2024.7.0"; public static product(...products: Product[]) { return products.map(product => Changelog.link(product.name, product.url)).join(", ") + '. '; From a3ca778d6903b10bc79bbd36d30859be58026a91 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Mon, 1 Jul 2024 11:45:55 +0200 Subject: [PATCH 065/173] Start development of version 2024.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/changelog/view/component/changelog.constants.ts | 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 848265f9c22..803d88b7e4a 100644 --- a/io.openems.common/src/io/openems/common/OpenemsConstants.java +++ b/io.openems.common/src/io/openems/common/OpenemsConstants.java @@ -22,7 +22,7 @@ public class OpenemsConstants { *

      * This is the month of the release. */ - public static final short VERSION_MINOR = 7; + public static final short VERSION_MINOR = 8; /** * The patch version of OpenEMS. @@ -36,7 +36,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 b38f652d904..2a040ed94b9 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "openems-ui", - "version": "2024.7.0", + "version": "2024.8.0-SNAPSHOT", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "openems-ui", - "version": "2024.7.0", + "version": "2024.8.0-SNAPSHOT", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "~16.2.12", diff --git a/ui/package.json b/ui/package.json index cf51861bf7d..4971ace7628 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,6 +1,6 @@ { "name": "openems-ui", - "version": "2024.7.0", + "version": "2024.8.0-SNAPSHOT", "license": "AGPL-3.0", "private": true, "dependencies": { diff --git a/ui/src/app/changelog/view/component/changelog.constants.ts b/ui/src/app/changelog/view/component/changelog.constants.ts index 1341682b050..473e291c675 100644 --- a/ui/src/app/changelog/view/component/changelog.constants.ts +++ b/ui/src/app/changelog/view/component/changelog.constants.ts @@ -2,7 +2,7 @@ import { Role } from "src/app/shared/type/role"; export class Changelog { - public static readonly UI_VERSION = "2024.7.0"; + public static readonly UI_VERSION = "2024.8.0-SNAPSHOT"; public static product(...products: Product[]) { return products.map(product => Changelog.link(product.name, product.url)).join(", ") + '. '; From 504954f19d73c244c7feabd69d182ad39ce53abe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jul 2024 16:06:50 +0200 Subject: [PATCH 066/173] Bump peaceiris/actions-gh-pages from 3 to 4 in /.github/workflows (#2690) Bumps [peaceiris/actions-gh-pages](https://github.com/peaceiris/actions-gh-pages) from 3 to 4. - [Release notes](https://github.com/peaceiris/actions-gh-pages/releases) - [Changelog](https://github.com/peaceiris/actions-gh-pages/blob/main/CHANGELOG.md) - [Commits](https://github.com/peaceiris/actions-gh-pages/compare/v3...v4) --- updated-dependencies: - dependency-name: peaceiris/actions-gh-pages dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 07b07ba9953..5050d32b4bf 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -24,7 +24,7 @@ jobs: run: ./gradlew buildAntoraDocs --continue - name: Deploy to GitHub pages - uses: peaceiris/actions-gh-pages@v3 + uses: peaceiris/actions-gh-pages@v4 with: personal_token: ${{ secrets.DOCS }} external_repository: OpenEMS/openems.io From aa3f01793194622fdffd87f0923d2f3c77f34197 Mon Sep 17 00:00:00 2001 From: Hiromasa Ihara Date: Mon, 1 Jul 2024 23:18:18 +0900 Subject: [PATCH 067/173] UI: resolve ts-strict and angular compatibility (#2687) * fix: resolve ts-strict -- angular compatibility This change add non-null assertion to angular mandatory component inputs and marked as `required` in input decolation argument. problem background - typescript strictPropertyInitialization option check non-initialized property. - In angular mandatory component inputs has no initialization in ts code. - strictPropertyInitialization dont consider it, so the checking point mandatory component inputs as error. detail procedure for addressing problem 1. finding non-initialized property in angular components. 2. regarding these inputs will be initialized in angular lifecycle (=> mandatory component inputs). 3. marking these inputs peroperty type as non-null assertion type(!). 3. marking these inputs as required directive({ required: true }). --- .../Controller/Ess/TimeOfUseTariff/chart/chart.ts | 2 +- .../Controller/Ess/TimeOfUseTariff/flat/flat.ts | 3 +-- ui/src/app/edge/history/chpsoc/chart.component.ts | 4 ++-- ui/src/app/edge/history/chpsoc/widget.component.ts | 4 ++-- .../edge/history/delayedselltogrid/chart.component.ts | 4 ++-- .../edge/history/delayedselltogrid/widget.component.ts | 4 ++-- .../history/fixdigitaloutput/singlechart.component.ts | 4 ++-- .../history/fixdigitaloutput/totalchart.component.ts | 2 +- .../edge/history/fixdigitaloutput/widget.component.ts | 4 ++-- ui/src/app/edge/history/grid/chart.component.ts | 4 ++-- .../history/gridoptimizedcharge/chart.component.ts | 4 ++-- .../sellToGridLimitChart.component.ts | 4 ++-- .../history/gridoptimizedcharge/widget.component.ts | 4 ++-- .../app/edge/history/heatingelement/chart.component.ts | 4 ++-- .../edge/history/heatingelement/widget.component.ts | 4 ++-- ui/src/app/edge/history/heatpump/chart.component.ts | 4 ++-- ui/src/app/edge/history/heatpump/widget.component.ts | 4 ++-- .../history/peakshaving/asymmetric/chart.component.ts | 4 ++-- .../history/peakshaving/asymmetric/widget.component.ts | 4 ++-- .../history/peakshaving/symmetric/chart.component.ts | 4 ++-- .../history/peakshaving/symmetric/widget.component.ts | 4 ++-- .../history/peakshaving/timeslot/chart.component.ts | 4 ++-- .../history/peakshaving/timeslot/widget.component.ts | 4 ++-- .../edge/history/singlethreshold/chart.component.ts | 6 +++--- .../edge/history/singlethreshold/widget.component.ts | 4 ++-- .../app/edge/history/storage/chargerchart.component.ts | 4 ++-- ui/src/app/edge/history/storage/esschart.component.ts | 6 +++--- .../app/edge/history/storage/singlechart.component.ts | 4 ++-- ui/src/app/edge/history/storage/socchart.component.ts | 2 +- .../app/edge/history/storage/totalchart.component.ts | 4 ++-- ui/src/app/edge/history/storage/widget.component.ts | 2 +- .../live/Controller/ChpSoc/modal/modal.component.ts | 8 ++++---- .../Ess/GridOptimizedCharge/modal/predictionChart.ts | 10 +++++----- .../Ess/TimeOfUseTariff/modal/powerSocChart.ts | 6 +++--- .../Ess/TimeOfUseTariff/modal/statePriceChart.ts | 6 +++--- .../Evcs/administration/administration.component.ts | 4 ++-- .../Io/ChannelSingleThreshold/modal/modal.component.ts | 8 ++++---- .../Io/FixDigitalOutput/modal/modal.component.ts | 5 ++--- .../PeakShaving/Asymmetric/modal/modal.component.ts | 6 +++--- .../PeakShaving/Symmetric/modal/modal.component.ts | 4 ++-- .../live/Io/Api_DigitalInput/modal/modal.component.ts | 4 ++-- .../Evcs_Api_Cluster/modal/evcs-chart/evcs.chart.ts | 8 ++++---- .../Evcs_Api_Cluster/modal/evcsCluster-modal.page.ts | 4 ++-- .../edge/live/common/storage/modal/modal.component.ts | 6 +++--- .../delayedselltogrid/delayedselltogrid.component.ts | 2 +- .../live/delayedselltogrid/modal/modal.component.ts | 4 ++-- .../safe-input/formly-safe-input-modal.component.ts | 8 ++++---- .../app/edge/settings/app/keypopup/modal.component.ts | 4 ++-- .../edge/settings/system/oe-system-update.component.ts | 2 +- .../app/shared/chartoptions/chartoptions.component.ts | 4 ++-- .../shared/edge/meter/esscharger/modal.component.ts | 3 +-- .../formly/formly-select-field-modal.component.ts | 5 ++--- ui/src/app/shared/formly/formly-skeleton-wrapper.ts | 7 +++---- .../shared/genericComponents/abstracthistorywidget.ts | 8 ++++---- .../genericComponents/chart/abstracthistorychart.ts | 6 +++--- ui/src/app/shared/genericComponents/chart/chart.ts | 2 +- .../flat/flat-widget-line/flat-widget-line.ts | 7 +++---- ui/src/app/shared/genericComponents/flat/flat.ts | 8 ++++---- .../genericComponents/modal/abstract-modal-line.ts | 6 +++--- .../modal/modal-button/modal-button.ts | 3 +-- .../modal/modal-info-line/modal-info-line.ts | 9 ++++----- .../genericComponents/modal/modal-line/modal-line.ts | 9 ++++----- .../modal/modal-value-line/modal-value-line.ts | 6 +++--- ui/src/app/shared/genericComponents/modal/modal.ts | 2 +- .../model-horizontal-line/modal-horizontal-line.ts | 5 ++--- .../shared/percentagebar/percentagebar.component.ts | 3 +-- 66 files changed, 150 insertions(+), 161 deletions(-) diff --git a/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/chart/chart.ts b/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/chart/chart.ts index 84ad2eb878e..aeceaec2560 100644 --- a/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/chart/chart.ts +++ b/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/chart/chart.ts @@ -13,7 +13,7 @@ import { ColorUtils } from 'src/app/shared/utils/color/color.utils'; }) export class ChartComponent extends AbstractHistoryChart { - @Input() public override component: EdgeConfig.Component; + @Input({ required: true }) public override component!: EdgeConfig.Component; private currencyLabel: Currency.Label; // Default diff --git a/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/flat/flat.ts b/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/flat/flat.ts index eeb4fb4fab2..de855a23302 100644 --- a/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/flat/flat.ts +++ b/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/flat/flat.ts @@ -1,4 +1,3 @@ -// @ts-strict-ignore import { Component, Input } from '@angular/core'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; @@ -11,7 +10,7 @@ import { ChannelAddress, CurrentData } from 'src/app/shared/shared'; }) export class FlatComponent extends AbstractFlatWidget { - @Input() public period: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; protected delayedActiveTimeOverPeriod: number | null = null; protected chargedConsumptionActiveTimeOverPeriod: number | null = null; diff --git a/ui/src/app/edge/history/chpsoc/chart.component.ts b/ui/src/app/edge/history/chpsoc/chart.component.ts index aa37afaee2f..5a5a82d43ec 100644 --- a/ui/src/app/edge/history/chpsoc/chart.component.ts +++ b/ui/src/app/edge/history/chpsoc/chart.component.ts @@ -14,8 +14,8 @@ import { YAxisTitle } from 'src/app/shared/service/utils'; }) export class ChpSocChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; ngOnChanges() { this.updateChart(); diff --git a/ui/src/app/edge/history/chpsoc/widget.component.ts b/ui/src/app/edge/history/chpsoc/widget.component.ts index 090b3ed1da8..78c42a533c8 100644 --- a/ui/src/app/edge/history/chpsoc/widget.component.ts +++ b/ui/src/app/edge/history/chpsoc/widget.component.ts @@ -14,8 +14,8 @@ import { calculateActiveTimeOverPeriod } from '../shared'; }) export class ChpSocWidgetComponent extends AbstractHistoryWidget implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; private static readonly SELECTOR = "chpsocWidget"; diff --git a/ui/src/app/edge/history/delayedselltogrid/chart.component.ts b/ui/src/app/edge/history/delayedselltogrid/chart.component.ts index e51dd2b147c..a1dd843c2b2 100644 --- a/ui/src/app/edge/history/delayedselltogrid/chart.component.ts +++ b/ui/src/app/edge/history/delayedselltogrid/chart.component.ts @@ -14,8 +14,8 @@ import { AbstractHistoryChart } from '../abstracthistorychart'; }) export class DelayedSellToGridChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; ngOnChanges() { this.updateChart(); diff --git a/ui/src/app/edge/history/delayedselltogrid/widget.component.ts b/ui/src/app/edge/history/delayedselltogrid/widget.component.ts index 3b4e3442ca5..85480c54c97 100644 --- a/ui/src/app/edge/history/delayedselltogrid/widget.component.ts +++ b/ui/src/app/edge/history/delayedselltogrid/widget.component.ts @@ -10,8 +10,8 @@ import { Edge, Service, EdgeConfig } from 'src/app/shared/shared'; }) export class DelayedSellToGridWidgetComponent implements OnInit { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; private static readonly SELECTOR = "delayedSellToGridWidget"; diff --git a/ui/src/app/edge/history/fixdigitaloutput/singlechart.component.ts b/ui/src/app/edge/history/fixdigitaloutput/singlechart.component.ts index 7dba882fa89..e86032d5ff7 100644 --- a/ui/src/app/edge/history/fixdigitaloutput/singlechart.component.ts +++ b/ui/src/app/edge/history/fixdigitaloutput/singlechart.component.ts @@ -16,8 +16,8 @@ import { AbstractHistoryChart } from '../abstracthistorychart'; }) export class FixDigitalOutputSingleChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; ngOnChanges() { this.updateChart(); diff --git a/ui/src/app/edge/history/fixdigitaloutput/totalchart.component.ts b/ui/src/app/edge/history/fixdigitaloutput/totalchart.component.ts index ede98a6e38b..c43325a0c39 100644 --- a/ui/src/app/edge/history/fixdigitaloutput/totalchart.component.ts +++ b/ui/src/app/edge/history/fixdigitaloutput/totalchart.component.ts @@ -15,7 +15,7 @@ import { AbstractHistoryChart } from '../abstracthistorychart'; }) export class FixDigitalOutputTotalChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; ngOnChanges() { this.updateChart(); diff --git a/ui/src/app/edge/history/fixdigitaloutput/widget.component.ts b/ui/src/app/edge/history/fixdigitaloutput/widget.component.ts index f4990c751fb..b640b941b56 100644 --- a/ui/src/app/edge/history/fixdigitaloutput/widget.component.ts +++ b/ui/src/app/edge/history/fixdigitaloutput/widget.component.ts @@ -14,8 +14,8 @@ import { calculateActiveTimeOverPeriod } from '../shared'; }) export class FixDigitalOutputWidgetComponent extends AbstractHistoryWidget implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; private config: EdgeConfig = null; public component: EdgeConfig.Component = null; diff --git a/ui/src/app/edge/history/grid/chart.component.ts b/ui/src/app/edge/history/grid/chart.component.ts index 285c8d4961e..76758432d1c 100644 --- a/ui/src/app/edge/history/grid/chart.component.ts +++ b/ui/src/app/edge/history/grid/chart.component.ts @@ -15,8 +15,8 @@ import * as Chart from 'chart.js'; }) export class GridChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public showPhases: boolean; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public showPhases!: boolean; ngOnChanges() { this.updateChart(); diff --git a/ui/src/app/edge/history/gridoptimizedcharge/chart.component.ts b/ui/src/app/edge/history/gridoptimizedcharge/chart.component.ts index 828617a2266..11523c2d1a1 100644 --- a/ui/src/app/edge/history/gridoptimizedcharge/chart.component.ts +++ b/ui/src/app/edge/history/gridoptimizedcharge/chart.component.ts @@ -16,8 +16,8 @@ import { AbstractHistoryChart } from '../abstracthistorychart'; }) export class GridOptimizedChargeChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public component: EdgeConfig.Component; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public component!: EdgeConfig.Component; ngOnChanges() { this.updateChart(); diff --git a/ui/src/app/edge/history/gridoptimizedcharge/sellToGridLimitChart.component.ts b/ui/src/app/edge/history/gridoptimizedcharge/sellToGridLimitChart.component.ts index 0c556547ae4..6f65d69c923 100644 --- a/ui/src/app/edge/history/gridoptimizedcharge/sellToGridLimitChart.component.ts +++ b/ui/src/app/edge/history/gridoptimizedcharge/sellToGridLimitChart.component.ts @@ -14,8 +14,8 @@ import { AbstractHistoryChart } from '../abstracthistorychart'; }) export class SellToGridLimitChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public component: EdgeConfig.Component; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public component!: EdgeConfig.Component; private gridMeter: string; diff --git a/ui/src/app/edge/history/gridoptimizedcharge/widget.component.ts b/ui/src/app/edge/history/gridoptimizedcharge/widget.component.ts index fd5361b5b33..5b0d61878a5 100644 --- a/ui/src/app/edge/history/gridoptimizedcharge/widget.component.ts +++ b/ui/src/app/edge/history/gridoptimizedcharge/widget.component.ts @@ -12,8 +12,8 @@ import { AbstractHistoryWidget } from '../abstracthistorywidget'; }) export class GridOptimizedChargeWidgetComponent extends AbstractHistoryWidget implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; private static readonly SELECTOR = "gridOptimizedChargeWidget"; diff --git a/ui/src/app/edge/history/heatingelement/chart.component.ts b/ui/src/app/edge/history/heatingelement/chart.component.ts index d2647126584..1835620d460 100644 --- a/ui/src/app/edge/history/heatingelement/chart.component.ts +++ b/ui/src/app/edge/history/heatingelement/chart.component.ts @@ -17,8 +17,8 @@ import { AbstractHistoryChart } from '../abstracthistorychart'; }) export class HeatingelementChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public component: EdgeConfig.Component; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public component!: EdgeConfig.Component; ngOnChanges() { this.updateChart(); diff --git a/ui/src/app/edge/history/heatingelement/widget.component.ts b/ui/src/app/edge/history/heatingelement/widget.component.ts index 54c59de124b..1bdd6ae51cb 100644 --- a/ui/src/app/edge/history/heatingelement/widget.component.ts +++ b/ui/src/app/edge/history/heatingelement/widget.component.ts @@ -13,8 +13,8 @@ import { AbstractHistoryWidget } from '../abstracthistorywidget'; }) export class HeatingelementWidgetComponent extends AbstractHistoryWidget implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; private static readonly SELECTOR = "heatingelementWidget"; diff --git a/ui/src/app/edge/history/heatpump/chart.component.ts b/ui/src/app/edge/history/heatpump/chart.component.ts index a026c2e3d71..42e87f0c482 100644 --- a/ui/src/app/edge/history/heatpump/chart.component.ts +++ b/ui/src/app/edge/history/heatpump/chart.component.ts @@ -15,8 +15,8 @@ import { AbstractHistoryChart } from '../abstracthistorychart'; }) export class HeatPumpChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public component: EdgeConfig.Component; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public component!: EdgeConfig.Component; ngOnChanges() { this.updateChart(); diff --git a/ui/src/app/edge/history/heatpump/widget.component.ts b/ui/src/app/edge/history/heatpump/widget.component.ts index 14ef01243f7..8bc60b9106c 100644 --- a/ui/src/app/edge/history/heatpump/widget.component.ts +++ b/ui/src/app/edge/history/heatpump/widget.component.ts @@ -13,8 +13,8 @@ import { AbstractHistoryWidget } from '../abstracthistorywidget'; }) export class HeatpumpWidgetComponent extends AbstractHistoryWidget implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; private static readonly SELECTOR = "heatpumpWidget"; 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 158d68ca676..8cbe32085b3 100644 --- a/ui/src/app/edge/history/peakshaving/asymmetric/chart.component.ts +++ b/ui/src/app/edge/history/peakshaving/asymmetric/chart.component.ts @@ -14,8 +14,8 @@ import { AbstractHistoryChart } from '../../abstracthistorychart'; }) export class AsymmetricPeakshavingChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public component: EdgeConfig.Component; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public component!: EdgeConfig.Component; ngOnChanges() { this.updateChart(); diff --git a/ui/src/app/edge/history/peakshaving/asymmetric/widget.component.ts b/ui/src/app/edge/history/peakshaving/asymmetric/widget.component.ts index daf215d6681..5a5f8cfaa6f 100644 --- a/ui/src/app/edge/history/peakshaving/asymmetric/widget.component.ts +++ b/ui/src/app/edge/history/peakshaving/asymmetric/widget.component.ts @@ -10,8 +10,8 @@ import { Edge, Service, EdgeConfig } from 'src/app/shared/shared'; }) export class AsymmetricPeakshavingWidgetComponent implements OnInit { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; private static readonly SELECTOR = "asymmetricPeakshavingWidget"; 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 8cd625e16b9..a7a103273ab 100644 --- a/ui/src/app/edge/history/peakshaving/symmetric/chart.component.ts +++ b/ui/src/app/edge/history/peakshaving/symmetric/chart.component.ts @@ -13,8 +13,8 @@ import { AbstractHistoryChart } from '../../abstracthistorychart'; }) export class SymmetricPeakshavingChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; ngOnChanges() { this.updateChart(); diff --git a/ui/src/app/edge/history/peakshaving/symmetric/widget.component.ts b/ui/src/app/edge/history/peakshaving/symmetric/widget.component.ts index 179d46e5e31..0f8a8392aa8 100644 --- a/ui/src/app/edge/history/peakshaving/symmetric/widget.component.ts +++ b/ui/src/app/edge/history/peakshaving/symmetric/widget.component.ts @@ -10,8 +10,8 @@ import { Edge, EdgeConfig, Service } from 'src/app/shared/shared'; }) export class SymmetricPeakshavingWidgetComponent implements OnInit { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; private static readonly SELECTOR = "symmetricPeakshavingWidget"; 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 1e65baae7f0..05ac5a3a27f 100644 --- a/ui/src/app/edge/history/peakshaving/timeslot/chart.component.ts +++ b/ui/src/app/edge/history/peakshaving/timeslot/chart.component.ts @@ -14,8 +14,8 @@ import { AbstractHistoryChart } from '../../abstracthistorychart'; }) export class TimeslotPeakshavingChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; ngOnChanges() { this.updateChart(); diff --git a/ui/src/app/edge/history/peakshaving/timeslot/widget.component.ts b/ui/src/app/edge/history/peakshaving/timeslot/widget.component.ts index ab34310c2a0..39b3fe686cb 100644 --- a/ui/src/app/edge/history/peakshaving/timeslot/widget.component.ts +++ b/ui/src/app/edge/history/peakshaving/timeslot/widget.component.ts @@ -10,8 +10,8 @@ import { Edge, EdgeConfig, Service } from 'src/app/shared/shared'; }) export class TimeslotPeakshavingWidgetComponent implements OnInit { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; private static readonly SELECTOR = "timeslotPeakshavingWidget"; diff --git a/ui/src/app/edge/history/singlethreshold/chart.component.ts b/ui/src/app/edge/history/singlethreshold/chart.component.ts index 41371fa0bc4..240c429afd4 100644 --- a/ui/src/app/edge/history/singlethreshold/chart.component.ts +++ b/ui/src/app/edge/history/singlethreshold/chart.component.ts @@ -17,9 +17,9 @@ import { AbstractHistoryChart } from '../abstracthistorychart'; }) export class SinglethresholdChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; - @Input() public inputChannelUnit: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; + @Input({ required: true }) public inputChannelUnit!: string; ngOnChanges() { this.updateChart(); diff --git a/ui/src/app/edge/history/singlethreshold/widget.component.ts b/ui/src/app/edge/history/singlethreshold/widget.component.ts index 5af56a066b8..d8c1dce7e06 100644 --- a/ui/src/app/edge/history/singlethreshold/widget.component.ts +++ b/ui/src/app/edge/history/singlethreshold/widget.component.ts @@ -14,8 +14,8 @@ import { calculateActiveTimeOverPeriod } from '../shared'; }) export class SinglethresholdWidgetComponent extends AbstractHistoryWidget implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; private static readonly SELECTOR = "singlethresholdWidget"; diff --git a/ui/src/app/edge/history/storage/chargerchart.component.ts b/ui/src/app/edge/history/storage/chargerchart.component.ts index 354e37e2aec..093f68da279 100644 --- a/ui/src/app/edge/history/storage/chargerchart.component.ts +++ b/ui/src/app/edge/history/storage/chargerchart.component.ts @@ -13,8 +13,8 @@ import { AbstractHistoryChart } from '../abstracthistorychart'; }) export class StorageChargerChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; private moreThanOneProducer: boolean = null; diff --git a/ui/src/app/edge/history/storage/esschart.component.ts b/ui/src/app/edge/history/storage/esschart.component.ts index 507377c51dd..10f63f0715a 100644 --- a/ui/src/app/edge/history/storage/esschart.component.ts +++ b/ui/src/app/edge/history/storage/esschart.component.ts @@ -14,9 +14,9 @@ import { AbstractHistoryChart } from '../abstracthistorychart'; export class StorageESSChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; - @Input() public showPhases: boolean; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; + @Input({ required: true }) public showPhases!: boolean; private moreThanOneProducer: boolean = null; diff --git a/ui/src/app/edge/history/storage/singlechart.component.ts b/ui/src/app/edge/history/storage/singlechart.component.ts index 44bebe80fff..54c71ec221f 100644 --- a/ui/src/app/edge/history/storage/singlechart.component.ts +++ b/ui/src/app/edge/history/storage/singlechart.component.ts @@ -16,8 +16,8 @@ import { AbstractHistoryChart } from '../abstracthistorychart'; }) export class StorageSingleChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public showPhases: boolean; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public showPhases!: boolean; ngOnChanges() { this.updateChart(); diff --git a/ui/src/app/edge/history/storage/socchart.component.ts b/ui/src/app/edge/history/storage/socchart.component.ts index b6e67531da2..b185c72cc30 100644 --- a/ui/src/app/edge/history/storage/socchart.component.ts +++ b/ui/src/app/edge/history/storage/socchart.component.ts @@ -14,7 +14,7 @@ import { AbstractHistoryChart } from '../abstracthistorychart'; }) export class SocStorageChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; private emergencyCapacityReserveComponents: EdgeConfig.Component[] = []; public ngOnChanges() { diff --git a/ui/src/app/edge/history/storage/totalchart.component.ts b/ui/src/app/edge/history/storage/totalchart.component.ts index 36cfb326953..e371ec9121e 100644 --- a/ui/src/app/edge/history/storage/totalchart.component.ts +++ b/ui/src/app/edge/history/storage/totalchart.component.ts @@ -15,8 +15,8 @@ import { formatNumber } from '@angular/common'; templateUrl: '../abstracthistorychart.html', }) export class StorageTotalChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public showPhases: boolean; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public showPhases!: boolean; ngOnChanges() { this.updateChart(); diff --git a/ui/src/app/edge/history/storage/widget.component.ts b/ui/src/app/edge/history/storage/widget.component.ts index 1673230f739..185c962da11 100644 --- a/ui/src/app/edge/history/storage/widget.component.ts +++ b/ui/src/app/edge/history/storage/widget.component.ts @@ -12,7 +12,7 @@ import { AbstractHistoryWidget } from '../abstracthistorywidget'; }) export class StorageComponent extends AbstractHistoryWidget implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; private static readonly SELECTOR = "storageWidget"; diff --git a/ui/src/app/edge/live/Controller/ChpSoc/modal/modal.component.ts b/ui/src/app/edge/live/Controller/ChpSoc/modal/modal.component.ts index 3a4ab019f79..636e1265b75 100644 --- a/ui/src/app/edge/live/Controller/ChpSoc/modal/modal.component.ts +++ b/ui/src/app/edge/live/Controller/ChpSoc/modal/modal.component.ts @@ -17,10 +17,10 @@ export class Controller_ChpSocModalComponent implements OnInit { private static readonly SELECTOR = "chpsoc-modal"; - @Input() public edge: Edge; - @Input() public component: EdgeConfig.Component; - @Input() public outputChannel: ChannelAddress; - @Input() public inputChannel: ChannelAddress; + @Input({ required: true }) public edge!: Edge; + @Input({ required: true }) public component!: EdgeConfig.Component; + @Input({ required: true }) public outputChannel!: ChannelAddress; + @Input({ required: true }) public inputChannel!: ChannelAddress; public thresholds: RangeValue = { lower: null, 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 746098619b3..66d67ee2cf5 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,11 +15,11 @@ 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 override edge: Edge; - @Input() public component: EdgeConfig.Component; - @Input() public targetEpochSeconds: number; - @Input() public chargeStartEpochSeconds: number; + @Input({ required: true }) protected refresh!: boolean; + @Input({ required: true }) protected override edge!: Edge; + @Input({ required: true }) public component!: EdgeConfig.Component; + @Input({ required: true }) public targetEpochSeconds!: number; + @Input({ required: true }) public chargeStartEpochSeconds!: number; private static DEFAULT_PERIOD: DefaultTypes.HistoryPeriod = new DefaultTypes.HistoryPeriod(new Date(), new Date()); diff --git a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/powerSocChart.ts b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/powerSocChart.ts index 562a139ceae..37e03611dc0 100644 --- a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/powerSocChart.ts +++ b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/powerSocChart.ts @@ -18,9 +18,9 @@ import { GetScheduleResponse } from '../../../../../../shared/jsonrpc/response/g }) export class SchedulePowerAndSocChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public refresh: boolean; - @Input() public override edge: Edge; - @Input() public component: EdgeConfig.Component; + @Input({ required: true }) public refresh!: boolean; + @Input({ required: true }) public override edge!: Edge; + @Input({ required: true }) public component!: EdgeConfig.Component; public ngOnChanges() { this.updateChart(); diff --git a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/statePriceChart.ts b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/statePriceChart.ts index cb6fc333a81..797f22701c0 100644 --- a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/statePriceChart.ts +++ b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/statePriceChart.ts @@ -21,9 +21,9 @@ import { Controller_Ess_TimeOfUseTariff } from '../Ess_TimeOfUseTariff'; }) export class ScheduleStateAndPriceChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public refresh: boolean; - @Input() public override edge: Edge; - @Input() public component: EdgeConfig.Component; + @Input({ required: true }) public refresh!: boolean; + @Input({ required: true }) public override edge!: Edge; + @Input({ required: true }) public component!: EdgeConfig.Component; private currencyLabel: Currency.Label; // Default diff --git a/ui/src/app/edge/live/Controller/Evcs/administration/administration.component.ts b/ui/src/app/edge/live/Controller/Evcs/administration/administration.component.ts index bc9fb3b4fef..9fafeee392b 100644 --- a/ui/src/app/edge/live/Controller/Evcs/administration/administration.component.ts +++ b/ui/src/app/edge/live/Controller/Evcs/administration/administration.component.ts @@ -11,8 +11,8 @@ import { Edge, EdgeConfig, Service, Websocket } from '../../../../../shared/shar }) export class AdministrationComponent implements OnInit { - @Input() public evcsComponent: EdgeConfig.Component; - @Input() public edge: Edge; + @Input({ required: true }) public evcsComponent!: EdgeConfig.Component; + @Input({ required: true }) public edge!: Edge; private static readonly SELECTOR = "administration"; diff --git a/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/modal/modal.component.ts b/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/modal/modal.component.ts index 5e58e17716d..93ea4683053 100644 --- a/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/modal/modal.component.ts +++ b/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/modal/modal.component.ts @@ -14,11 +14,11 @@ type inputMode = 'SOC' | 'GRIDSELL' | 'GRIDBUY' | 'PRODUCTION' | 'OTHER'; }) export class Controller_Io_ChannelSingleThresholdModalComponent implements OnInit { - @Input() public edge: Edge; - @Input() public config: EdgeConfig; - @Input() public component: EdgeConfig.Component; + @Input({ required: true }) public edge!: Edge; + @Input({ required: true }) public config!: EdgeConfig; + @Input({ required: true }) public component!: EdgeConfig.Component; @Input() public outputChannel: ChannelAddress | null = null; - @Input() public inputChannel: ChannelAddress; + @Input({ required: true }) public inputChannel!: ChannelAddress; @Input() public inputChannelUnit: string | null = null; public formGroup: FormGroup; diff --git a/ui/src/app/edge/live/Controller/Io/FixDigitalOutput/modal/modal.component.ts b/ui/src/app/edge/live/Controller/Io/FixDigitalOutput/modal/modal.component.ts index 3a6111ccab2..b1564acb6da 100644 --- a/ui/src/app/edge/live/Controller/Io/FixDigitalOutput/modal/modal.component.ts +++ b/ui/src/app/edge/live/Controller/Io/FixDigitalOutput/modal/modal.component.ts @@ -1,4 +1,3 @@ -// @ts-strict-ignore import { Component, Input } from '@angular/core'; import { Router } from '@angular/router'; import { ModalController } from '@ionic/angular'; @@ -11,8 +10,8 @@ import { Edge, EdgeConfig, Service, Websocket } from 'src/app/shared/shared'; }) export class Controller_Io_FixDigitalOutputModalComponent { - @Input() public edge: Edge; - @Input() public component: EdgeConfig.Component; + @Input({ required: true }) public edge!: Edge; + @Input({ required: true }) public component!: EdgeConfig.Component; constructor( public service: Service, diff --git a/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/modal/modal.component.ts b/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/modal/modal.component.ts index 751df3e54b1..327a63386d6 100644 --- a/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/modal/modal.component.ts +++ b/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/modal/modal.component.ts @@ -12,9 +12,9 @@ import { Edge, EdgeConfig, Service, Websocket } from '../../../../../../shared/s }) export class Controller_Asymmetric_PeakShavingModalComponent implements OnInit { - @Input() protected component: EdgeConfig.Component; - @Input() protected edge: Edge; - @Input() protected mostStressedPhase: Subject<{ name: 'L1' | 'L2' | 'L3' | '', value: number }>; + @Input({ required: true }) protected component!: EdgeConfig.Component; + @Input({ required: true }) protected edge!: Edge; + @Input({ required: true }) protected mostStressedPhase!: Subject<{ name: 'L1' | 'L2' | 'L3' | '', value: number }>; public formGroup: FormGroup; public loading: boolean = false; diff --git a/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/modal/modal.component.ts b/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/modal/modal.component.ts index 2f1c86eed96..b733e98f5b9 100644 --- a/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/modal/modal.component.ts +++ b/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/modal/modal.component.ts @@ -11,8 +11,8 @@ import { Edge, EdgeConfig, Service, Websocket } from '../../../../../../shared/s }) export class Controller_Symmetric_PeakShavingModalComponent implements OnInit { - @Input() protected component: EdgeConfig.Component; - @Input() protected edge: Edge; + @Input({ required: true }) protected component!: EdgeConfig.Component; + @Input({ required: true }) protected edge!: Edge; public formGroup: FormGroup; diff --git a/ui/src/app/edge/live/Io/Api_DigitalInput/modal/modal.component.ts b/ui/src/app/edge/live/Io/Api_DigitalInput/modal/modal.component.ts index eda63d38897..5169a6f4ae5 100644 --- a/ui/src/app/edge/live/Io/Api_DigitalInput/modal/modal.component.ts +++ b/ui/src/app/edge/live/Io/Api_DigitalInput/modal/modal.component.ts @@ -13,8 +13,8 @@ import { JsonrpcRequest, JsonrpcResponseSuccess } from 'src/app/shared/jsonrpc/b export class Io_Api_DigitalInput_ModalComponent implements OnInit, OnDestroy { private static readonly SELECTOR = "Io_Api_DigitalInput_ModalComponent"; - @Input() public edge: Edge; - @Input() public ioComponents: EdgeConfig.Component[]; + @Input({ required: true }) public edge!: Edge; + @Input({ required: true }) public ioComponents!: EdgeConfig.Component[]; protected digitalInputChannelsPerComponent: { componentId: string, componentAlias: string, channels: Channel[] }[]; diff --git a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcs-chart/evcs.chart.ts b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcs-chart/evcs.chart.ts index 75ba5857c7a..a80251edbf6 100644 --- a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcs-chart/evcs.chart.ts +++ b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcs-chart/evcs.chart.ts @@ -13,11 +13,11 @@ import { TranslateService } from '@ngx-translate/core'; }) export class EvcsChartComponent implements OnInit, OnChanges { - @Input() private evcsMap: { [sourceId: string]: EdgeConfig.Component }; - @Input() private edge: Edge; - @Input() private currentData: CurrentData; + @Input({ required: true }) private evcsMap!: { [sourceId: string]: EdgeConfig.Component }; + @Input({ required: true }) private edge!: Edge; + @Input({ required: true }) private currentData!: CurrentData; @Input() private evcsConfigMap: { [evcsId: string]: EdgeConfig.Component } = {}; - @Input() private componentId: string; + @Input({ required: true }) private componentId!: string; private static readonly SELECTOR = "evcsChart"; public loading: boolean = true; diff --git a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcsCluster-modal.page.ts b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcsCluster-modal.page.ts index 065900afded..c6c79c7e69c 100644 --- a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcsCluster-modal.page.ts +++ b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcsCluster-modal.page.ts @@ -14,9 +14,9 @@ type Priority = 'CAR' | 'STORAGE'; }) export class Evcs_Api_ClusterModalComponent implements OnInit { - @Input() public edge: Edge; + @Input({ required: true }) public edge!: Edge; @Input() public config: EdgeConfig.Component = null; - @Input() public componentId: string; + @Input({ required: true }) public componentId!: string; @Input() public evcsMap: { [sourceId: string]: EdgeConfig.Component } = {}; @ViewChild(IonReorderGroup, { static: true }) diff --git a/ui/src/app/edge/live/common/storage/modal/modal.component.ts b/ui/src/app/edge/live/common/storage/modal/modal.component.ts index 8fc10a04131..0c4de15b7d4 100644 --- a/ui/src/app/edge/live/common/storage/modal/modal.component.ts +++ b/ui/src/app/edge/live/common/storage/modal/modal.component.ts @@ -15,10 +15,10 @@ export class StorageModalComponent implements OnInit, OnDestroy { // TODO after refactoring of Model: subscribe to EssActivePowerL1/L2/L3 here instead of Flat Widget - @Input() protected edge: Edge; - @Input() protected config: EdgeConfig; + @Input({ required: true }) protected edge!: Edge; + @Input({ required: true }) protected config!: EdgeConfig; @Input() protected essComponents: EdgeConfig.Component[] | null = null; - @Input() protected chargerComponents: EdgeConfig.Component[]; + @Input({ required: true }) protected chargerComponents!: EdgeConfig.Component[]; @Input() protected singleComponent: EdgeConfig.Component = null; // reference to the Utils method to access via html diff --git a/ui/src/app/edge/live/delayedselltogrid/delayedselltogrid.component.ts b/ui/src/app/edge/live/delayedselltogrid/delayedselltogrid.component.ts index 5f14f0149a4..ea2ca6e7d0a 100644 --- a/ui/src/app/edge/live/delayedselltogrid/delayedselltogrid.component.ts +++ b/ui/src/app/edge/live/delayedselltogrid/delayedselltogrid.component.ts @@ -14,7 +14,7 @@ export class DelayedSellToGridComponent implements OnInit, OnDestroy { private static readonly SELECTOR = "delayedselltogrid"; - @Input() public componentId: string; + @Input({ required: true }) public componentId!: string; public edge: Edge = null; diff --git a/ui/src/app/edge/live/delayedselltogrid/modal/modal.component.ts b/ui/src/app/edge/live/delayedselltogrid/modal/modal.component.ts index c9a4efbb5b5..e8cd66dad20 100644 --- a/ui/src/app/edge/live/delayedselltogrid/modal/modal.component.ts +++ b/ui/src/app/edge/live/delayedselltogrid/modal/modal.component.ts @@ -11,8 +11,8 @@ import { Edge, EdgeConfig, Service, Websocket } from '../../../../shared/shared' }) export class DelayedSellToGridModalComponent implements OnInit { - @Input() protected component: EdgeConfig.Component; - @Input() protected edge: Edge; + @Input({ required: true }) protected component!: EdgeConfig.Component; + @Input({ required: true }) protected edge!: Edge; private static readonly SELECTOR = "delayedselltogrid-modal"; diff --git a/ui/src/app/edge/settings/app/formly/safe-input/formly-safe-input-modal.component.ts b/ui/src/app/edge/settings/app/formly/safe-input/formly-safe-input-modal.component.ts index 745dcf43183..60ef52e3be1 100644 --- a/ui/src/app/edge/settings/app/formly/safe-input/formly-safe-input-modal.component.ts +++ b/ui/src/app/edge/settings/app/formly/safe-input/formly-safe-input-modal.component.ts @@ -10,12 +10,12 @@ import { FormlyFieldConfig } from "@ngx-formly/core"; }) export class FormlySafeInputModalComponent implements OnInit { - @Input() - protected title: string; + @Input({ required: true }) + protected title!: string; @Input() protected fields: FormlyFieldConfig[] = null; - @Input() - protected model: {}; + @Input({ required: true }) + protected model!: {}; protected form: FormGroup = new FormGroup({}); protected myModel: {}; 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 d94779ef5c8..43c1345b999 100644 --- a/ui/src/app/edge/settings/app/keypopup/modal.component.ts +++ b/ui/src/app/edge/settings/app/keypopup/modal.component.ts @@ -22,10 +22,10 @@ import { hasPredefinedKey } from '../permissions'; }) export class KeyModalComponent implements OnInit { - @Input() public edge: Edge; + @Input({ required: true }) public edge!: Edge; @Input() public appId: string | null = null; @Input() public appName: string | null = null; - @Input() public behaviour: KeyValidationBehaviour; + @Input({ required: true }) public behaviour!: KeyValidationBehaviour; @Input() public knownApps: GetApps.App[] | null = null; diff --git a/ui/src/app/edge/settings/system/oe-system-update.component.ts b/ui/src/app/edge/settings/system/oe-system-update.component.ts index 7b0689beab5..b04d15d2f26 100644 --- a/ui/src/app/edge/settings/system/oe-system-update.component.ts +++ b/ui/src/app/edge/settings/system/oe-system-update.component.ts @@ -15,7 +15,7 @@ export class OeSystemUpdateComponent implements OnInit, OnDestroy { @Output() public stateChanged: EventEmitter = new EventEmitter(); @Input() public executeUpdateInstantly: boolean = false; - @Input() public edge: Edge; + @Input({ required: true }) public edge!: Edge; public readonly environment = environment; public readonly spinnerId: string = OeSystemUpdateComponent.SELECTOR; diff --git a/ui/src/app/shared/chartoptions/chartoptions.component.ts b/ui/src/app/shared/chartoptions/chartoptions.component.ts index d7cefe3fd04..842a726c003 100644 --- a/ui/src/app/shared/chartoptions/chartoptions.component.ts +++ b/ui/src/app/shared/chartoptions/chartoptions.component.ts @@ -11,8 +11,8 @@ import { TranslateService } from '@ngx-translate/core'; }) export class ChartOptionsComponent { - @Input() public showPhases: boolean | null; - @Input() public showTotal: boolean | null; + @Input({ required: true }) public showPhases!: boolean | null; + @Input({ required: true }) public showTotal!: boolean | null; @Output() public setShowPhases = new EventEmitter(); @Output() public setShowTotal = new EventEmitter(); diff --git a/ui/src/app/shared/edge/meter/esscharger/modal.component.ts b/ui/src/app/shared/edge/meter/esscharger/modal.component.ts index 594394991e8..e0f8bc8887d 100644 --- a/ui/src/app/shared/edge/meter/esscharger/modal.component.ts +++ b/ui/src/app/shared/edge/meter/esscharger/modal.component.ts @@ -1,4 +1,3 @@ -// @ts-strict-ignore import { Component, Input } from '@angular/core'; import { Converter } from 'src/app/shared/genericComponents/shared/converter'; import { Utils } from 'src/app/shared/shared'; @@ -10,7 +9,7 @@ import { EdgeConfig } from '../../edgeconfig'; templateUrl: './modal.component.html', }) export class EssChargerComponent { - @Input() public component: EdgeConfig.Component; + @Input({ required: true }) public component!: EdgeConfig.Component; protected readonly Role = Role; protected readonly Utils = Utils; protected readonly Converter = Converter; diff --git a/ui/src/app/shared/formly/formly-select-field-modal.component.ts b/ui/src/app/shared/formly/formly-select-field-modal.component.ts index d2a72af4576..2ef2314fced 100644 --- a/ui/src/app/shared/formly/formly-select-field-modal.component.ts +++ b/ui/src/app/shared/formly/formly-select-field-modal.component.ts @@ -1,4 +1,3 @@ -// @ts-strict-ignore import { Component, Input, OnInit } from "@angular/core"; import { ModalController } from "@ionic/angular"; @@ -8,8 +7,8 @@ import { ModalController } from "@ionic/angular"; }) export class FormlySelectFieldModalComponent implements OnInit { - @Input() public title: string; - @Input() public options: { label: string, value: string, description?: string }[]; + @Input({ required: true }) public title!: string; + @Input({ required: true }) public options!: { label: string, value: string, description?: string }[]; @Input() public initialSelectedValue: string | null = null; diff --git a/ui/src/app/shared/formly/formly-skeleton-wrapper.ts b/ui/src/app/shared/formly/formly-skeleton-wrapper.ts index fdc339aebae..f0c2bb276dd 100644 --- a/ui/src/app/shared/formly/formly-skeleton-wrapper.ts +++ b/ui/src/app/shared/formly/formly-skeleton-wrapper.ts @@ -1,4 +1,3 @@ -// @ts-strict-ignore import { Component, Input } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { FormlyFieldConfig } from '@ngx-formly/core'; @@ -25,7 +24,7 @@ import { FormlyFieldConfig } from '@ngx-formly/core'; }) export class FormlyFieldWithLoadingAnimationComponent { @Input() public show: boolean = false; - @Input() public fields: FormlyFieldConfig[]; - @Input() public form: FormGroup; - @Input() public model: any; + @Input({ required: true }) public fields!: FormlyFieldConfig[]; + @Input({ required: true }) public form!: FormGroup; + @Input({ required: true }) public model!: any; } diff --git a/ui/src/app/shared/genericComponents/abstracthistorywidget.ts b/ui/src/app/shared/genericComponents/abstracthistorywidget.ts index 6786e3e0417..550a34c1907 100644 --- a/ui/src/app/shared/genericComponents/abstracthistorywidget.ts +++ b/ui/src/app/shared/genericComponents/abstracthistorywidget.ts @@ -12,11 +12,11 @@ import { v4 as uuidv4 } from 'uuid'; @Directive() export abstract class AbstractHistoryWidget implements OnInit, OnChanges, OnDestroy { - @Input() - public period: DefaultTypes.HistoryPeriod; + @Input({ required: true }) + public period!: DefaultTypes.HistoryPeriod; - @Input() - protected componentId: string; + @Input({ required: true }) + protected componentId!: string; /** * True after this.edge, this.config and this.component are set. diff --git a/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts b/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts index 6cfedde7115..b134b507eed 100644 --- a/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts +++ b/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts @@ -37,9 +37,9 @@ export abstract class AbstractHistoryChart implements OnInit { @Input() public chartTitle: string = ""; /** TODO: workaround with Observables, to not have to pass the period on Initialisation */ - @Input() public component: EdgeConfig.Component; - @Input() public showPhases: boolean; - @Input() public showTotal: boolean; + @Input() public component?: EdgeConfig.Component; + @Input() public showPhases: boolean = false; + @Input() public showTotal: boolean = false; @Input() public isOnlyChart: boolean = false; public edge: Edge | null = null; diff --git a/ui/src/app/shared/genericComponents/chart/chart.ts b/ui/src/app/shared/genericComponents/chart/chart.ts index 35436b36467..d9e1da57d0b 100644 --- a/ui/src/app/shared/genericComponents/chart/chart.ts +++ b/ui/src/app/shared/genericComponents/chart/chart.ts @@ -23,7 +23,7 @@ export class ChartComponent implements OnInit, OnChanges { @Input() public isPopoverNeeded: boolean = false; // Manually trigger ChangeDetection through Inputchange - @Input() private period: DefaultTypes.PeriodString; + @Input() private period?: DefaultTypes.PeriodString; protected showPopover: boolean = false; constructor( 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 7ce3eab9718..78d3dcabd73 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,3 @@ -// @ts-strict-ignore import { Component, Input } from "@angular/core"; import { AbstractFlatWidgetLine } from "../abstract-flat-widget-line"; @@ -9,10 +8,10 @@ import { AbstractFlatWidgetLine } from "../abstract-flat-widget-line"; }) export class FlatWidgetLineComponent extends AbstractFlatWidgetLine { /** Name for parameter, displayed on the left side */ - @Input() - public name: string; + @Input({ required: true }) + public name!: string; /** Width of left Column, right Column is (100 - width of left Column) */ @Input() - public leftColumnWidth: number; + public leftColumnWidth?: number; } diff --git a/ui/src/app/shared/genericComponents/flat/flat.ts b/ui/src/app/shared/genericComponents/flat/flat.ts index c15744a15ed..5d651dd208f 100644 --- a/ui/src/app/shared/genericComponents/flat/flat.ts +++ b/ui/src/app/shared/genericComponents/flat/flat.ts @@ -9,14 +9,14 @@ import { Icon } from 'src/app/shared/type/widget'; export class FlatWidgetComponent { /** Image in Header */ - @Input() public img: string; + @Input() public img?: string; /** Icon in Header */ - @Input() public icon: Icon = null; + @Input() public icon: Icon | null = null; /** BackgroundColor of the Header (light or dark) */ - @Input() public color: string; + @Input() public color?: string; /** Title in Header */ - @Input() public title: string; + @Input() public title?: string; } 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 5381137990c..77bfd7fc851 100644 --- a/ui/src/app/shared/genericComponents/modal/abstract-modal-line.ts +++ b/ui/src/app/shared/genericComponents/modal/abstract-modal-line.ts @@ -17,13 +17,13 @@ import { Filter } from "../shared/filter"; export abstract class AbstractModalLine implements OnInit, OnDestroy, OnChanges { /** FormGroup */ - @Input() public formGroup: FormGroup; + @Input({ required: true }) public formGroup!: FormGroup; /** component */ @Input() public component: EdgeConfig.Component = null; /** FormGroup ControlName */ - @Input() public controlName: string; + @Input({ required: true }) public controlName!: string; /** * Use `converter` to convert/map a CurrentData value to another value, e.g. an Enum number to a text. @@ -53,7 +53,7 @@ export abstract class AbstractModalLine implements OnInit, OnDestroy, OnChanges } } - @Input() public value: number | string; + @Input({ required: true }) public value!: number | string; @Input() public roleIsAtLeast?: Role = Role.GUEST; protected show: boolean = true; diff --git a/ui/src/app/shared/genericComponents/modal/modal-button/modal-button.ts b/ui/src/app/shared/genericComponents/modal/modal-button/modal-button.ts index 0c118509ce9..ffa19945c66 100644 --- a/ui/src/app/shared/genericComponents/modal/modal-button/modal-button.ts +++ b/ui/src/app/shared/genericComponents/modal/modal-button/modal-button.ts @@ -1,4 +1,3 @@ -// @ts-strict-ignore import { Component, Input } from "@angular/core"; import { Icon } from "src/app/shared/type/widget"; import { AbstractModalLine } from "../abstract-modal-line"; @@ -9,7 +8,7 @@ import { AbstractModalLine } from "../abstract-modal-line"; }) export class ModalButtonsComponent extends AbstractModalLine { - @Input() protected buttons: ButtonLabel[]; + @Input({ required: true }) protected buttons!: ButtonLabel[]; } export type ButtonLabel = { diff --git a/ui/src/app/shared/genericComponents/modal/modal-info-line/modal-info-line.ts b/ui/src/app/shared/genericComponents/modal/modal-info-line/modal-info-line.ts index ec2b7ff70d1..a1138593a91 100644 --- a/ui/src/app/shared/genericComponents/modal/modal-info-line/modal-info-line.ts +++ b/ui/src/app/shared/genericComponents/modal/modal-info-line/modal-info-line.ts @@ -1,4 +1,3 @@ -// @ts-strict-ignore import { Component, Input } from "@angular/core"; import { Icon } from "src/app/shared/type/widget"; @@ -9,15 +8,15 @@ import { Icon } from "src/app/shared/type/widget"; export class ModalInfoLineComponent { /** Icon, displayed on the left side */ - @Input() protected icon: Icon; + @Input({ required: true }) protected icon!: Icon; /** * Info-Text, displayed on the right side, optional style for all lines * Multiple lines with own style is possible * */ - @Input() public info: { text: string, lineStyle?: string }[] | string; + @Input({ required: true }) public info!: { text: string, lineStyle?: string }[] | string; - @Input() protected lineStyle: string; + @Input({ required: true }) protected lineStyle!: string; - @Input() protected rowStyle: string; + @Input({ required: true }) protected rowStyle!: string; } 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 9da02e03038..ce9542a386d 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,4 +1,3 @@ -// @ts-strict-ignore import { Component, Input } from "@angular/core"; import { AbstractModalLine } from "../abstract-modal-line"; import { ButtonLabel } from "../modal-button/modal-button"; @@ -10,14 +9,14 @@ import { ButtonLabel } from "../modal-button/modal-button"; export class ModalLineComponent extends AbstractModalLine { // Width of Left Column, Right Column is (100% - leftColumn) - @Input() - protected leftColumnWidth: number; + @Input({ required: true }) + protected leftColumnWidth!: number; /** ControlName for Form Field */ - @Input() public override controlName: string; + @Input({ required: true }) public override controlName!: string; @Input() protected button: ButtonLabel | null = null; /** ControlName for Toggle Button */ - @Input() protected control: + @Input({ required: true }) protected control!: { type: 'TOGGLE' } | { type: 'INPUT', properties?: {unit:'W'} } | /* the available select options*/ diff --git a/ui/src/app/shared/genericComponents/modal/modal-value-line/modal-value-line.ts b/ui/src/app/shared/genericComponents/modal/modal-value-line/modal-value-line.ts index 6f5ce00db9a..a6946e68d33 100644 --- a/ui/src/app/shared/genericComponents/modal/modal-value-line/modal-value-line.ts +++ b/ui/src/app/shared/genericComponents/modal/modal-value-line/modal-value-line.ts @@ -20,11 +20,11 @@ export class ModalValueLineComponent extends AbstractModalLine { return this.channels; } - @Input() private valueCallback: (currentData: CurrentData) => string; + @Input({ required: true }) private valueCallback!: (currentData: CurrentData) => string; // Width of Left Column, Right Column is (100% - leftColumn) - @Input() - protected leftColumnWidth: number; + @Input({ required: true }) + protected leftColumnWidth!: number; /** Fixed indentation of the modal-line */ @Input() protected textIndent: TextIndentation = TextIndentation.NONE; diff --git a/ui/src/app/shared/genericComponents/modal/modal.ts b/ui/src/app/shared/genericComponents/modal/modal.ts index df2dab11224..7911468e26b 100644 --- a/ui/src/app/shared/genericComponents/modal/modal.ts +++ b/ui/src/app/shared/genericComponents/modal/modal.ts @@ -29,7 +29,7 @@ export class ModalComponent { @Input() protected formGroup: FormGroup = new FormGroup({}); /** Title in Header */ - @Input() public title: string; + @Input({ required: true }) public title!: string; @Input() protected toolbarButtons: { url: string, icon: Icon }[] | { url: string, icon: Icon } | { callback: () => diff --git a/ui/src/app/shared/genericComponents/modal/model-horizontal-line/modal-horizontal-line.ts b/ui/src/app/shared/genericComponents/modal/model-horizontal-line/modal-horizontal-line.ts index 03214110464..b6971de84de 100644 --- a/ui/src/app/shared/genericComponents/modal/model-horizontal-line/modal-horizontal-line.ts +++ b/ui/src/app/shared/genericComponents/modal/model-horizontal-line/modal-horizontal-line.ts @@ -1,4 +1,3 @@ -// @ts-strict-ignore import { Component, Input } from "@angular/core"; /** @@ -11,7 +10,7 @@ import { Component, Input } from "@angular/core"; export class ModalHorizontalLineComponent { /** Components-Array to iterate over */ - @Input() protected components: any[]; + @Input({ required: true }) protected components!: any[]; /** index is an iterator */ - @Input() protected index: number; + @Input({ required: true }) protected index!: number; } diff --git a/ui/src/app/shared/percentagebar/percentagebar.component.ts b/ui/src/app/shared/percentagebar/percentagebar.component.ts index dfa6da83147..221c1a837ad 100644 --- a/ui/src/app/shared/percentagebar/percentagebar.component.ts +++ b/ui/src/app/shared/percentagebar/percentagebar.component.ts @@ -1,4 +1,3 @@ -// @ts-strict-ignore import { Component, Input } from '@angular/core'; @Component({ @@ -7,7 +6,7 @@ import { Component, Input } from '@angular/core'; }) export class PercentageBarComponent { - @Input() public value: number; + @Input({ required: true }) public value!: number; @Input() public showPercentageValue: boolean = true; constructor( From b82772be20c22804221cce3b5cb79f18e1d4aad9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jul 2024 23:33:58 +0200 Subject: [PATCH 068/173] Bump docker/build-push-action from 5 to 6 in /.github/workflows (#2689) Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5 to 6. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/v5...v6) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 37698ef7701..df0a15180f9 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -78,7 +78,7 @@ jobs: type=raw,value=develop,enable=${{ github.ref == 'refs/heads/develop' }} - name: Build and push Docker images - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: file: ${{ matrix.dockerfile }} platforms: linux/amd64, linux/arm64 From 99f1b6dc748fd3b476bf7dde4afc4004cce3e233 Mon Sep 17 00:00:00 2001 From: HarmOtten <10838083+HarmOtten@users.noreply.github.com> Date: Mon, 1 Jul 2024 23:46:31 +0200 Subject: [PATCH 069/173] Docs: fix typo (#1150) Co-authored-by: Stefan Feilmeier --- doc/modules/ROOT/pages/edge/deploy.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/modules/ROOT/pages/edge/deploy.adoc b/doc/modules/ROOT/pages/edge/deploy.adoc index cbeeb1fad82..2088195edbd 100644 --- a/doc/modules/ROOT/pages/edge/deploy.adoc +++ b/doc/modules/ROOT/pages/edge/deploy.adoc @@ -16,7 +16,7 @@ This guide covers a simple, manual approach. For productive systems it is requir Prerequisites: * A target device running Debian Linux like a Raspberry Pi, Beaglebone Black or an IoT gateway. You need the IP address and SSH access. -* Create a JAR-file that should be deployes. See xref:edge/build.adoc[Build OpenEMS Edge] for details. Alternatively you may download the latest release `openems-edge.jar` file from https://github.com/OpenEMS/openems/releases[GitHub] under _Assets_. +* Create a JAR-file that should be deployed. See xref:edge/build.adoc[Build OpenEMS Edge] for details. Alternatively you may download the latest release `openems-edge.jar` file from https://github.com/OpenEMS/openems/releases[GitHub] under _Assets_. * Setup an SSH client to connect to the Linux console, e.g. http://www.9bis.net/kitty/[KiTTY] * Setup an SCP client to copy the JAR file via SSH, e.g. https://winscp.net/eng/docs/lang:de[WinSCP] @@ -132,4 +132,4 @@ Execute `systemctl restart openems --no-block; journalctl -lfu openems` The command restarts the service (_systemctl restart openems_) while not waiting for the OpenEMS startup notification (_--no-block_). Then it directly prints the OpenEMS system log (_journalctl -lfu openems_). + .OpenEMS Edge start-up -image::deploy-openems-start.png[OpenEMS Edge start-up] \ No newline at end of file +image::deploy-openems-start.png[OpenEMS Edge start-up] From 051489e41aba2e4f21ec91adc7152e427e1c4ad2 Mon Sep 17 00:00:00 2001 From: parapluplu Date: Wed, 3 Jul 2024 11:46:10 +0200 Subject: [PATCH 070/173] Unit Tests: Add test case for alphabetical scheduler (#2698) * Unit Tests: Add test case for alphabetical scheduler * Improve test coverage; fix Eclipse autoformat --------- Co-authored-by: Felix Remmel Co-authored-by: Stefan Feilmeier --- .../SchedulerAllAlphabeticallyImplTest.java | 48 +++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/io.openems.edge.scheduler.allalphabetically/test/io/openems/edge/scheduler/allalphabetically/SchedulerAllAlphabeticallyImplTest.java b/io.openems.edge.scheduler.allalphabetically/test/io/openems/edge/scheduler/allalphabetically/SchedulerAllAlphabeticallyImplTest.java index d70d542d30b..204e4e48109 100644 --- a/io.openems.edge.scheduler.allalphabetically/test/io/openems/edge/scheduler/allalphabetically/SchedulerAllAlphabeticallyImplTest.java +++ b/io.openems.edge.scheduler.allalphabetically/test/io/openems/edge/scheduler/allalphabetically/SchedulerAllAlphabeticallyImplTest.java @@ -2,7 +2,9 @@ import static org.junit.Assert.assertEquals; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import org.junit.Test; @@ -25,7 +27,7 @@ public class SchedulerAllAlphabeticallyImplTest { private static final String CTRL4_ID = "ctrl4"; @Test - public void test() throws Exception { + public void testWithFixedPriorities() throws Exception { final SchedulerAllAlphabetically sut = new SchedulerAllAlphabeticallyImpl(); new ComponentTest(sut) // .addReference("componentManager", new DummyComponentManager()) // @@ -36,15 +38,55 @@ public void test() throws Exception { .addComponent(new DummyController(CTRL4_ID)) // .activate(MyConfig.create() // .setId(SCHEDULER_ID) // - .setControllersIds(CTRL2_ID, CTRL1_ID) // + .setControllersIds(CTRL2_ID, CTRL1_ID, "") // .build()) - .next(new TestCase()); + .next(new TestCase()) // + .deactivate(); assertEquals(// Arrays.asList(CTRL2_ID, CTRL1_ID, CTRL0_ID, CTRL3_ID, CTRL4_ID), // getControllerIds(sut)); } + @Test + public void testOnlyAlphabeticalOrdering() throws Exception { + final var controllerIds = new ArrayList<>(List.of(// + "ctrlController1", // + "a", // + "aa", // + "aA", // + "ab", // + "aB", // + "A", // + "0", // + "1", // + "0controller", // + "0Controller", // + "bla", // + "controller0", // + "controller1", // + "dontroller0", // + "dontroller1", // + "d0", // + "D0", // + "Z", // + "z")); + final var sut = new SchedulerAllAlphabeticallyImpl(); + final var test = new ComponentTest(sut); // + controllerIds.forEach(controllerId -> test.addComponent(new DummyController(controllerId))); + test // + .addReference("componentManager", new DummyComponentManager()) // + .activate(MyConfig.create() // + .setId(SCHEDULER_ID) // + .setControllersIds() // + .build()) // + .next(new TestCase()); + + Collections.sort(controllerIds); + + assertEquals(controllerIds, getControllerIds(sut)); + } + private static List getControllerIds(Scheduler scheduler) throws OpenemsNamedException { return scheduler.getControllers().stream() // .toList(); From 7b6e98245d21dc816920e3077b1bb331b637dd63 Mon Sep 17 00:00:00 2001 From: Kai J <99220919+da-Kai@users.noreply.github.com> Date: Wed, 3 Jul 2024 16:45:55 +0200 Subject: [PATCH 071/173] CI: Update build actions (#2697) * ui coverage * name artifacts * Update release.yml --- .github/workflows/build.yml | 10 ++++++---- .github/workflows/release.yml | 32 +++++++++++++++++++------------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a67813b0d63..6f1d4022ad0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,11 +22,14 @@ jobs: - uses: kiancross/checkstyle-annotations-action@v1 + - name: Checkstyle + run: ./gradlew checkstyleAll --console=plain --warn + - name: Build all Java packages - run: ./gradlew build + run: ./gradlew build --console=plain --warn - name: Resolve OpenEMS bundles - run: ./gradlew resolve + run: ./gradlew resolve --console=plain --warn - name: Validate BackendApp.bndrun run: git diff --exit-code io.openems.backend.application/BackendApp.bndrun @@ -64,13 +67,12 @@ jobs: - name: Build OpenEMS UI run: | cd ui - npm install npm ci --prefer-offline --cache ~/.npm node_modules/.bin/ng config cli.cache.path "~/.ng" node_modules/.bin/ng build -c "openems,openems-edge-prod,prod" node_modules/.bin/ng lint export CHROME_BIN=/usr/bin/google-chrome-stable - npm run test -- --no-watch --no-progress --browsers=ChromeHeadlessCI + npm run test -- --code-coverage --no-watch --no-progress --browsers=ChromeHeadlessCI - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8acfebfebf7..aaf7c10fc6e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,11 +20,14 @@ jobs: - uses: kiancross/checkstyle-annotations-action@v1 + - name: Checkstyle + run: ./gradlew checkstyleAll --console=plain --warn + - name: Build all Java packages - run: ./gradlew build + run: ./gradlew build --console=plain --warn - name: Resolve OpenEMS bundles - run: ./gradlew resolve + run: ./gradlew resolve --console=plain --warn - name: Validate BackendApp.bndrun run: git diff --exit-code io.openems.backend.application/BackendApp.bndrun @@ -33,12 +36,12 @@ jobs: run: git diff --exit-code io.openems.edge.application/EdgeApp.bndrun - name: Prepare Edge+Backend assets - run: ./gradlew buildEdge buildBackend + run: ./gradlew buildEdge buildBackend --console=plain --warn - name: Save build-artifacts uses: actions/upload-artifact@v4 with: - name: build-artifacts + name: java-build-artifacts path: | build/openems-edge.jar build/openems-backend.jar @@ -65,7 +68,6 @@ jobs: - name: Build OpenEMS UI run: | cd ui - npm install npm ci --prefer-offline --cache ~/.npm node_modules/.bin/ng config cli.cache.path "~/.ng" node_modules/.bin/ng build -c "openems,openems-edge-prod,prod" @@ -75,24 +77,28 @@ jobs: - name: Prepare UI asset run: | - mkdir build - cd ui/target - zip -r ../../build/openems-ui.zip ./* + tar --xz --transform 's|^ui/target|openems-ui|' -cvf openems-ui.tar.xz ui/target/ - name: Save build-artifacts uses: actions/upload-artifact@v4 with: - name: build-artifacts - path: build/openems-ui.zip + name: ui-build-artifacts + path: openems-ui.tar.xz release: runs-on: ubuntu-latest needs: [build-java, build-ui] steps: - - name: Load build-artifacts + - name: Load Java build-artifacts + uses: actions/download-artifact@v4 + with: + name: java-build-artifacts + path: build + + - name: Load UI build-artifacts uses: actions/download-artifact@v4 with: - name: build-artifacts + name: ui-build-artifacts path: build - name: Create draft Release @@ -102,4 +108,4 @@ jobs: files: | build/openems-edge.jar build/openems-backend.jar - build/openems-ui.zip \ No newline at end of file + build/openems-ui.tar.xz \ No newline at end of file From bcffd3bb61e885faf460b9b9d2d5942cd8ac4677 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Mon, 15 Jul 2024 21:54:46 +0200 Subject: [PATCH 072/173] Update Gradle to 8.9 (#2706) `./gradlew wrapper --gradle-version=8.9` --- .gradle-wrapper/gradle-wrapper.properties | 2 +- gradlew | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gradle-wrapper/gradle-wrapper.properties b/.gradle-wrapper/gradle-wrapper.properties index a4413138c96..09523c0e549 100644 --- a/.gradle-wrapper/gradle-wrapper.properties +++ b/.gradle-wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 2b542f22740..09d360f6284 100755 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. From d6ac6375b9843a1d2c644483481138717db33d62 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Jul 2024 23:51:16 +0200 Subject: [PATCH 073/173] Build(deps): Bump org.apache.felix:org.apache.felix.webconsole from 5.0.4 to 5.0.6 in /cnf (#2713) * Build(deps): Bump org.apache.felix:org.apache.felix.webconsole in /cnf Bumps org.apache.felix:org.apache.felix.webconsole from 5.0.4 to 5.0.6. --- updated-dependencies: - dependency-name: org.apache.felix:org.apache.felix.webconsole 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 79d3e7d73c3..b139b3f31ab 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -237,7 +237,7 @@ org.apache.felix org.apache.felix.webconsole - 5.0.4 + 5.0.6 diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index e103405ba64..43d11213f54 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -112,7 +112,7 @@ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ org.apache.felix.scr;version='[2.2.12,2.2.13)',\ - org.apache.felix.webconsole;version='[5.0.4,5.0.5)',\ + org.apache.felix.webconsole;version='[5.0.6,5.0.7)',\ org.apache.felix.webconsole.plugins.ds;version='[2.3.0,2.3.1)',\ org.jetbrains.kotlin.osgi-bundle;version='[2.0.0,2.0.1)',\ org.jsr-305;version='[3.0.2,3.0.3)',\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index addfe0c17f4..795dd1ffade 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -408,7 +408,7 @@ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ org.apache.felix.scr;version='[2.2.12,2.2.13)',\ - org.apache.felix.webconsole;version='[5.0.4,5.0.5)',\ + org.apache.felix.webconsole;version='[5.0.6,5.0.7)',\ org.apache.felix.webconsole.plugins.ds;version='[2.3.0,2.3.1)',\ org.eclipse.jetty.client;version='[9.4.28,9.4.29)',\ org.eclipse.jetty.http;version='[9.4.28,9.4.29)',\ From fd05297ece5043512e28a2496fc85c497914db34 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Jul 2024 00:16:10 +0200 Subject: [PATCH 074/173] Build(deps): Bump de.bytefish:pgbulkinsert from 8.1.3 to 8.1.4 in /cnf (#2712) * Build(deps): Bump de.bytefish:pgbulkinsert from 8.1.3 to 8.1.4 in /cnf Bumps [de.bytefish:pgbulkinsert](https://github.com/bytefish/PgBulkInsert) from 8.1.3 to 8.1.4. - [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.3...8.1.4) --- updated-dependencies: - dependency-name: de.bytefish:pgbulkinsert dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Update bnd --------- 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/bnd.bnd | 4 ++-- io.openems.wrapper/pgbulkinsert.bnd | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cnf/pom.xml b/cnf/pom.xml index b139b3f31ab..bd59021ca59 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -105,7 +105,7 @@ de.bytefish pgbulkinsert - 8.1.3 + 8.1.4 diff --git a/io.openems.wrapper/bnd.bnd b/io.openems.wrapper/bnd.bnd index eaa0db0019f..73b692cd3cb 100644 --- a/io.openems.wrapper/bnd.bnd +++ b/io.openems.wrapper/bnd.bnd @@ -22,9 +22,9 @@ Bundle-Description: This wraps external java libraries that do not have OSGi hea info.faljse:SDNotify;version='1.5.0',\ io.reactivex.rxjava3.rxjava;version='3.1.8',\ com.google.gson;version='2.10.1',\ - de.bytefish:pgbulkinsert;version='8.1.3',\ + de.bytefish:pgbulkinsert;version='8.1.4',\ fr.turri:aXMLRPC;version='1.13.0',\ org.dhatim:fastexcel;version='0.18.0',\ org.dhatim:fastexcel-reader;version='0.18',\ org.eclipse.paho.mqttv5.client;version='1.2.5',\ - org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm;version='1.7.3',\ \ No newline at end of file + org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm;version='1.7.3',\ diff --git a/io.openems.wrapper/pgbulkinsert.bnd b/io.openems.wrapper/pgbulkinsert.bnd index 85d5e2aa364..891add35c08 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.3 +Bundle-Version: 8.1.4 Include-Resource: \ - @pgbulkinsert-8.1.3.jar,\ + @pgbulkinsert-8.1.4.jar,\ -dsannotations: * From 7e15583b829d821b5cf061cb886d62583b7cb6d9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Jul 2024 09:06:58 +0200 Subject: [PATCH 075/173] Build(deps): Bump org.jsoup:jsoup from 1.17.2 to 1.18.1 in /cnf (#2711) * Build(deps): Bump org.jsoup:jsoup from 1.17.2 to 1.18.1 in /cnf Bumps [org.jsoup:jsoup](https://github.com/jhy/jsoup) from 1.17.2 to 1.18.1. - [Release notes](https://github.com/jhy/jsoup/releases) - [Changelog](https://github.com/jhy/jsoup/blob/master/CHANGES.md) - [Commits](https://github.com/jhy/jsoup/compare/jsoup-1.17.2...jsoup-1.18.1) --- updated-dependencies: - dependency-name: org.jsoup:jsoup 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.edge.application/EdgeApp.bndrun | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cnf/pom.xml b/cnf/pom.xml index bd59021ca59..bc174ab2833 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -312,7 +312,7 @@ org.jsoup jsoup - 1.17.2 + 1.18.1 org.osgi diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index 795dd1ffade..954e6795b11 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -416,7 +416,7 @@ 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='[2.0.0,2.0.1)',\ - org.jsoup;version='[1.17.2,1.17.3)',\ + org.jsoup;version='[1.18.1,1.18.2)',\ org.jsr-305;version='[3.0.2,3.0.3)',\ org.openmuc.jmbus;version='[3.3.0,3.3.1)',\ org.openmuc.jrxtx;version='[1.0.1,1.0.2)',\ From 584fc5a33110cc5b7948a976dc43dfc6fd3a6872 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Jul 2024 11:40:41 +0200 Subject: [PATCH 076/173] Build(deps): Bump org.apache.felix:org.apache.felix.http.jetty from 5.1.22 to 5.1.24 in /cnf (#2710) * Build(deps): Bump org.apache.felix:org.apache.felix.http.jetty in /cnf Bumps org.apache.felix:org.apache.felix.http.jetty from 5.1.22 to 5.1.24. --- updated-dependencies: - dependency-name: org.apache.felix:org.apache.felix.http.jetty 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 bc174ab2833..06a780a8931 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -203,7 +203,7 @@ org.apache.felix org.apache.felix.http.jetty - 5.1.22 + 5.1.24 diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index 43d11213f54..5c8dedd876c 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -107,7 +107,7 @@ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ org.apache.felix.eventadmin;version='[1.6.4,1.6.5)',\ org.apache.felix.fileinstall;version='[3.7.4,3.7.5)',\ - org.apache.felix.http.jetty;version='[5.1.22,5.1.23)',\ + org.apache.felix.http.jetty;version='[5.1.24,5.1.25)',\ org.apache.felix.http.servlet-api;version='[3.0.0,3.0.1)',\ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index 954e6795b11..7204fb4f29c 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -403,7 +403,7 @@ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ org.apache.felix.eventadmin;version='[1.6.4,1.6.5)',\ org.apache.felix.fileinstall;version='[3.7.4,3.7.5)',\ - org.apache.felix.http.jetty;version='[5.1.22,5.1.23)',\ + org.apache.felix.http.jetty;version='[5.1.24,5.1.25)',\ org.apache.felix.http.servlet-api;version='[3.0.0,3.0.1)',\ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ From 16ed514ad7ecb8f02306700990d30463f83b26ef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Jul 2024 14:24:43 +0200 Subject: [PATCH 077/173] Build(deps): Bump swiper from 11.1.4 to 11.1.5 in /ui (#2709) Bumps [swiper](https://github.com/nolimits4web/Swiper) from 11.1.4 to 11.1.5. - [Release notes](https://github.com/nolimits4web/Swiper/releases) - [Changelog](https://github.com/nolimits4web/swiper/blob/master/CHANGELOG.md) - [Commits](https://github.com/nolimits4web/Swiper/compare/v11.1.4...v11.1.5) --- updated-dependencies: - dependency-name: swiper dependency-type: direct:production update-type: version-update:semver-patch ... 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 | 9 ++++----- ui/package.json | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 2a040ed94b9..4b109092ce2 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -49,7 +49,7 @@ "ngx-spinner": "^16.0.2", "roboto-fontface": "^0.10.0", "rxjs": "~6.6.7", - "swiper": "11.1.4", + "swiper": "11.1.5", "tslib": "^2.6.2", "uuid": "^10.0.0", "zone.js": "~0.13.3" @@ -20300,9 +20300,9 @@ } }, "node_modules/swiper": { - "version": "11.1.4", - "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.1.4.tgz", - "integrity": "sha512-1n7kbYJB2dFEpUHRFszq7gys/ofIBrMNibwTiMvPHwneKND/t9kImnHt6CfGPScMHgI+dWMbGTycCKGMoOO1KA==", + "version": "11.1.5", + "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.1.5.tgz", + "integrity": "sha512-JJQWFXdxiMGC2j6ZGTYat5Z7NN9JORJBgHp0/joX9uPod+cRj0wr5H5VnWSNIz9JeAamQvYKaG7aFrGHIF9OEg==", "funding": [ { "type": "patreon", @@ -20313,7 +20313,6 @@ "url": "http://opencollective.com/swiper" } ], - "license": "MIT", "engines": { "node": ">= 4.7.0" } diff --git a/ui/package.json b/ui/package.json index 4971ace7628..b0dd51cc7cd 100644 --- a/ui/package.json +++ b/ui/package.json @@ -44,7 +44,7 @@ "ngx-spinner": "^16.0.2", "roboto-fontface": "^0.10.0", "rxjs": "~6.6.7", - "swiper": "11.1.4", + "swiper": "11.1.5", "tslib": "^2.6.2", "uuid": "^10.0.0", "zone.js": "~0.13.3" From 4922269acf562ffbe9fb7456ac04d5437f9e0201 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Jul 2024 14:31:09 +0200 Subject: [PATCH 078/173] Build(deps): Bump @ngx-formly/ionic from 6.3.5 to 6.3.6 in /ui (#2708) Bumps [@ngx-formly/ionic](https://github.com/ngx-formly/ngx-formly) from 6.3.5 to 6.3.6. - [Release notes](https://github.com/ngx-formly/ngx-formly/releases) - [Changelog](https://github.com/ngx-formly/ngx-formly/blob/main/CHANGELOG.md) - [Commits](https://github.com/ngx-formly/ngx-formly/compare/v6.3.5...v6.3.6) --- updated-dependencies: - dependency-name: "@ngx-formly/ionic" dependency-type: direct:production update-type: version-update:semver-patch ... 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 | 18 ++++++++---------- ui/package.json | 2 +- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 4b109092ce2..d937f6702b2 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -29,7 +29,7 @@ "@ionic/angular": "^6.7.5", "@ionic/cli": "^7.1.6", "@ngx-formly/core": "^6.3.0", - "@ngx-formly/ionic": "^6.3.5", + "@ngx-formly/ionic": "^6.3.6", "@ngx-formly/schematics": "^6.3.0", "@ngx-translate/core": "^15.0.0", "@nodro7/angular-mydatepicker": "^0.14.0", @@ -4400,10 +4400,9 @@ } }, "node_modules/@ngx-formly/core": { - "version": "6.3.5", - "resolved": "https://registry.npmjs.org/@ngx-formly/core/-/core-6.3.5.tgz", - "integrity": "sha512-9p4yl7fr2Ojmm/uN7/nM1hYezheUxecEC0WZ0YI6jeSoEJR8NYTglVxTmHrpW5had2oolHeO39sAo9ttJNifSA==", - "license": "MIT", + "version": "6.3.6", + "resolved": "https://registry.npmjs.org/@ngx-formly/core/-/core-6.3.6.tgz", + "integrity": "sha512-0GDllrb9fFBTKG+yT+iQf96N3/CN+qRXIYsSX3uft12+c28qKVfMTsWTPYQsmKfGcrqtOZkMVTc+jGGD2JLZLg==", "dependencies": { "tslib": "^2.0.0" }, @@ -4413,16 +4412,15 @@ } }, "node_modules/@ngx-formly/ionic": { - "version": "6.3.5", - "resolved": "https://registry.npmjs.org/@ngx-formly/ionic/-/ionic-6.3.5.tgz", - "integrity": "sha512-WqcsG9YXr9PZdWOV+DVT++2cHrndMabRNlOOHx+VIf8QXQc1cyxq9UWW3CmBKw5lT1P2cy4cxxuKMk4EzNJV+Q==", - "license": "MIT", + "version": "6.3.6", + "resolved": "https://registry.npmjs.org/@ngx-formly/ionic/-/ionic-6.3.6.tgz", + "integrity": "sha512-GaZav6bGGuQ3BqEVYK9DV+QsdM92jjfPmKbN9qz5s+kXH4ahjGfMqcq6Rm4SP49vvl5Am3mJZbZU4g9XrJI5tQ==", "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@ionic/angular": "^6.0.0 || ^7.0.0", - "@ngx-formly/core": "6.3.5" + "@ngx-formly/core": "6.3.6" } }, "node_modules/@ngx-formly/schematics": { diff --git a/ui/package.json b/ui/package.json index b0dd51cc7cd..2f87b1a3920 100644 --- a/ui/package.json +++ b/ui/package.json @@ -24,7 +24,7 @@ "@ionic/angular": "^6.7.5", "@ionic/cli": "^7.1.6", "@ngx-formly/core": "^6.3.0", - "@ngx-formly/ionic": "^6.3.5", + "@ngx-formly/ionic": "^6.3.6", "@ngx-formly/schematics": "^6.3.0", "@ngx-translate/core": "^15.0.0", "@nodro7/angular-mydatepicker": "^0.14.0", From 4223d33760ed4552fcde1bf3c8da867bc111559f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Jul 2024 14:36:05 +0200 Subject: [PATCH 079/173] Build(deps): Bump capacitor-blob-writer from 1.1.16 to 1.1.17 in /ui (#2707) Bumps [capacitor-blob-writer](https://github.com/diachedelic/capacitor-blob-writer) from 1.1.16 to 1.1.17. - [Commits](https://github.com/diachedelic/capacitor-blob-writer/commits) --- updated-dependencies: - dependency-name: capacitor-blob-writer dependency-type: direct:production update-type: version-update:semver-patch ... 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 | 9 ++++----- ui/package.json | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index d937f6702b2..b21790239d7 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -33,7 +33,7 @@ "@ngx-formly/schematics": "^6.3.0", "@ngx-translate/core": "^15.0.0", "@nodro7/angular-mydatepicker": "^0.14.0", - "capacitor-blob-writer": "^1.1.14", + "capacitor-blob-writer": "^1.1.17", "capacitor-ios-autofill-save-password": "^2.0.0", "capacitor-secure-storage-plugin": "^0.9.0", "chart.js": "^4.4.3", @@ -7845,10 +7845,9 @@ "license": "CC-BY-4.0" }, "node_modules/capacitor-blob-writer": { - "version": "1.1.16", - "resolved": "https://registry.npmjs.org/capacitor-blob-writer/-/capacitor-blob-writer-1.1.16.tgz", - "integrity": "sha512-MKeqLUB7hBmRiJQcMeucD22Ckql1tk1GFnk/xYQDtFNBhKcAJBoV5rMXgkTphvZoRFw9b8025PAdjSj23dbg7A==", - "license": "MIT", + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/capacitor-blob-writer/-/capacitor-blob-writer-1.1.17.tgz", + "integrity": "sha512-IixJbl0k4NQ+aPo+UbDvHJxztnaGymVMCkYoHKTjj3F3KDTsMEl5iK7fEZkQ5jhQabe8YJKW0wTGu6Qm/RmXrw==", "peerDependencies": { "@capacitor/core": ">=3.0.0", "@capacitor/filesystem": ">=1.0.0" diff --git a/ui/package.json b/ui/package.json index 2f87b1a3920..06f25d32483 100644 --- a/ui/package.json +++ b/ui/package.json @@ -28,7 +28,7 @@ "@ngx-formly/schematics": "^6.3.0", "@ngx-translate/core": "^15.0.0", "@nodro7/angular-mydatepicker": "^0.14.0", - "capacitor-blob-writer": "^1.1.14", + "capacitor-blob-writer": "^1.1.17", "capacitor-ios-autofill-save-password": "^2.0.0", "capacitor-secure-storage-plugin": "^0.9.0", "chart.js": "^4.4.3", From 3506820c5675576ea552393cc297f82be4c5cdcb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Jul 2024 14:44:34 +0200 Subject: [PATCH 080/173] Build(deps): Bump @capacitor/core from 5.2.3 to 5.7.6 in /ui (#2695) Bumps [@capacitor/core](https://github.com/ionic-team/capacitor) from 5.2.3 to 5.7.6. - [Release notes](https://github.com/ionic-team/capacitor/releases) - [Changelog](https://github.com/ionic-team/capacitor/blob/5.7.6/CHANGELOG.md) - [Commits](https://github.com/ionic-team/capacitor/compare/5.2.3...5.7.6) --- updated-dependencies: - dependency-name: "@capacitor/core" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 9 ++++----- ui/package.json | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index b21790239d7..4ae20c6eb84 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -20,7 +20,7 @@ "@capacitor-community/file-opener": "^1.0.5", "@capacitor/android": "5.2.3", "@capacitor/app": "^5.0.6", - "@capacitor/core": "5.2.3", + "@capacitor/core": "5.7.6", "@capacitor/filesystem": "^5.2.0", "@capacitor/ios": "5.2.3", "@capacitor/splash-screen": "^5.0.6", @@ -3242,10 +3242,9 @@ } }, "node_modules/@capacitor/core": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-5.2.3.tgz", - "integrity": "sha512-Q1zbgt3Mvldy7six2/GX54kTL0ozgnR37jeDUAXL/fOJBF4Iorr/8A0OjGEAnwEjpR1la7uFZUunESMFyMLhEQ==", - "license": "MIT", + "version": "5.7.6", + "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-5.7.6.tgz", + "integrity": "sha512-YVCNegFg04Pm6Rfc6KbZT2wnxAUzhcyi3b+MWFj+FwUOOFNmnGkzxCFo4tQakXFblfOK6pU0Va5XuiNs1+Fnow==", "dependencies": { "tslib": "^2.1.0" } diff --git a/ui/package.json b/ui/package.json index 06f25d32483..c3da96975b1 100644 --- a/ui/package.json +++ b/ui/package.json @@ -15,7 +15,7 @@ "@capacitor-community/file-opener": "^1.0.5", "@capacitor/android": "5.2.3", "@capacitor/app": "^5.0.6", - "@capacitor/core": "5.2.3", + "@capacitor/core": "5.7.6", "@capacitor/filesystem": "^5.2.0", "@capacitor/ios": "5.2.3", "@capacitor/splash-screen": "^5.0.6", From 1c08496f2b4e2ea9845c7d35a5aff42c98d2374f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Jul 2024 14:49:05 +0200 Subject: [PATCH 081/173] Build(deps-dev): Bump @capacitor/cli from 5.2.3 to 6.1.0 in /ui (#2696) Bumps [@capacitor/cli](https://github.com/ionic-team/capacitor) from 5.2.3 to 6.1.0. - [Release notes](https://github.com/ionic-team/capacitor/releases) - [Changelog](https://github.com/ionic-team/capacitor/blob/main/CHANGELOG.md) - [Commits](https://github.com/ionic-team/capacitor/compare/5.2.3...6.1.0) --- updated-dependencies: - dependency-name: "@capacitor/cli" dependency-type: direct:development update-type: version-update:semver-major ... 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 | 230 ++++++++++++++++++++++++++++++------------- ui/package.json | 2 +- 2 files changed, 165 insertions(+), 67 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 4ae20c6eb84..410b17c9daf 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -65,7 +65,7 @@ "@angular/compiler-cli": "^16.2.12", "@angular/language-service": "^16.2.12", "@capacitor/assets": "^3.0.0", - "@capacitor/cli": "5.2.3", + "@capacitor/cli": "6.1.0", "@ionic/angular-toolkit": "^11.0.1", "@stylistic/eslint-plugin": "^2.2.2", "@types/jasmine": "~4.3.6", @@ -3031,32 +3031,6 @@ "node": ">=8" } }, - "node_modules/@capacitor/assets/node_modules/native-run": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/native-run/-/native-run-2.0.1.tgz", - "integrity": "sha512-XfG1FBZLM50J10xH9361whJRC9SHZ0Bub4iNRhhI61C8Jv0e1ud19muex6sNKB51ibQNUJNuYn25MuYET/rE6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@ionic/utils-fs": "^3.1.7", - "@ionic/utils-terminal": "^2.3.4", - "bplist-parser": "^0.3.2", - "debug": "^4.3.4", - "elementtree": "^0.1.7", - "ini": "^4.1.1", - "plist": "^3.1.0", - "split2": "^4.2.0", - "through2": "^4.0.2", - "tslib": "^2.6.2", - "yauzl": "^2.10.0" - }, - "bin": { - "native-run": "bin/native-run" - }, - "engines": { - "node": ">=16.0.0" - } - }, "node_modules/@capacitor/assets/node_modules/rimraf": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.1.tgz", @@ -3076,16 +3050,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@capacitor/assets/node_modules/split2": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">= 10.x" - } - }, "node_modules/@capacitor/assets/node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", @@ -3111,21 +3075,21 @@ } }, "node_modules/@capacitor/cli": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@capacitor/cli/-/cli-5.2.3.tgz", - "integrity": "sha512-iqjOnA9fCxm+cFv5iTvxb/vElK2Z1kDpVS+N9XyD2Msyv3l3ezuOZTSvABiDoo6w6CGkj4/AUMpdT4nrZkTHTg==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@capacitor/cli/-/cli-6.1.0.tgz", + "integrity": "sha512-HEKDh3+FuNZKFHmSDZ7nAnaX3bzhtznYk9GsZBMac1y4CTAxIykPX9wzZ3DzLeM/EbMBGFClUbefkIkimAyfYg==", "dev": true, - "license": "MIT", "dependencies": { "@ionic/cli-framework-output": "^2.2.5", "@ionic/utils-fs": "^3.1.6", - "@ionic/utils-subprocess": "^2.1.11", + "@ionic/utils-process": "^2.1.11", + "@ionic/utils-subprocess": "2.1.11", "@ionic/utils-terminal": "^2.3.3", "commander": "^9.3.0", "debug": "^4.3.4", "env-paths": "^2.2.0", "kleur": "^4.1.4", - "native-run": "^1.7.2", + "native-run": "^2.0.0", "open": "^8.4.0", "plist": "^3.0.5", "prompts": "^2.4.2", @@ -3140,7 +3104,117 @@ "capacitor": "bin/capacitor" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@capacitor/cli/node_modules/@ionic/utils-array": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@ionic/utils-array/-/utils-array-2.1.5.tgz", + "integrity": "sha512-HD72a71IQVBmQckDwmA8RxNVMTbxnaLbgFOl+dO5tbvW9CkkSFCv41h6fUuNsSEVgngfkn0i98HDuZC8mk+lTA==", + "dev": true, + "dependencies": { + "debug": "^4.0.0", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=10.3.0" + } + }, + "node_modules/@capacitor/cli/node_modules/@ionic/utils-fs": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@ionic/utils-fs/-/utils-fs-3.1.6.tgz", + "integrity": "sha512-eikrNkK89CfGPmexjTfSWl4EYqsPSBh0Ka7by4F0PLc1hJZYtJxUZV3X4r5ecA8ikjicUmcbU7zJmAjmqutG/w==", + "dev": true, + "dependencies": { + "@types/fs-extra": "^8.0.0", + "debug": "^4.0.0", + "fs-extra": "^9.0.0", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=10.3.0" + } + }, + "node_modules/@capacitor/cli/node_modules/@ionic/utils-object": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@ionic/utils-object/-/utils-object-2.1.5.tgz", + "integrity": "sha512-XnYNSwfewUqxq+yjER1hxTKggftpNjFLJH0s37jcrNDwbzmbpFTQTVAp4ikNK4rd9DOebX/jbeZb8jfD86IYxw==", + "dev": true, + "dependencies": { + "debug": "^4.0.0", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=10.3.0" + } + }, + "node_modules/@capacitor/cli/node_modules/@ionic/utils-stream": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@ionic/utils-stream/-/utils-stream-3.1.5.tgz", + "integrity": "sha512-hkm46uHvEC05X/8PHgdJi4l4zv9VQDELZTM+Kz69odtO9zZYfnt8DkfXHJqJ+PxmtiE5mk/ehJWLnn/XAczTUw==", + "dev": true, + "dependencies": { + "debug": "^4.0.0", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=10.3.0" + } + }, + "node_modules/@capacitor/cli/node_modules/@ionic/utils-subprocess": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/@ionic/utils-subprocess/-/utils-subprocess-2.1.11.tgz", + "integrity": "sha512-6zCDixNmZCbMCy5np8klSxOZF85kuDyzZSTTQKQP90ZtYNCcPYmuFSzaqDwApJT4r5L3MY3JrqK1gLkc6xiUPw==", + "dev": true, + "dependencies": { + "@ionic/utils-array": "2.1.5", + "@ionic/utils-fs": "3.1.6", + "@ionic/utils-process": "2.1.10", + "@ionic/utils-stream": "3.1.5", + "@ionic/utils-terminal": "2.3.3", + "cross-spawn": "^7.0.3", + "debug": "^4.0.0", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=10.3.0" + } + }, + "node_modules/@capacitor/cli/node_modules/@ionic/utils-subprocess/node_modules/@ionic/utils-process": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@ionic/utils-process/-/utils-process-2.1.10.tgz", + "integrity": "sha512-mZ7JEowcuGQK+SKsJXi0liYTcXd2bNMR3nE0CyTROpMECUpJeAvvaBaPGZf5ERQUPeWBVuwqAqjUmIdxhz5bxw==", + "dev": true, + "dependencies": { + "@ionic/utils-object": "2.1.5", + "@ionic/utils-terminal": "2.3.3", + "debug": "^4.0.0", + "signal-exit": "^3.0.3", + "tree-kill": "^1.2.2", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=10.3.0" + } + }, + "node_modules/@capacitor/cli/node_modules/@ionic/utils-terminal": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@ionic/utils-terminal/-/utils-terminal-2.3.3.tgz", + "integrity": "sha512-RnuSfNZ5fLEyX3R5mtcMY97cGD1A0NVBbarsSQ6yMMfRJ5YHU7hHVyUfvZeClbqkBC/pAqI/rYJuXKCT9YeMCQ==", + "dev": true, + "dependencies": { + "@types/slice-ansi": "^4.0.0", + "debug": "^4.0.0", + "signal-exit": "^3.0.3", + "slice-ansi": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "tslib": "^2.0.1", + "untildify": "^4.0.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=10.3.0" } }, "node_modules/@capacitor/cli/node_modules/brace-expansion": { @@ -3163,6 +3237,21 @@ "node": "^12.20.0 || >=14" } }, + "node_modules/@capacitor/cli/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@capacitor/cli/node_modules/glob": { "version": "9.3.5", "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", @@ -3182,6 +3271,18 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@capacitor/cli/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/@capacitor/cli/node_modules/minimatch": { "version": "8.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", @@ -3227,6 +3328,15 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@capacitor/cli/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/@capacitor/cli/node_modules/xml2js": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", @@ -15523,39 +15633,28 @@ "license": "MIT" }, "node_modules/native-run": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/native-run/-/native-run-1.7.4.tgz", - "integrity": "sha512-yDEwTp66vmXpqFiSQzz4sVQgyq5U58gGRovglY4GHh12ITyWa6mh6Lbpm2gViVOVD1JYFtYnwcgr7GTFBinXNA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/native-run/-/native-run-2.0.1.tgz", + "integrity": "sha512-XfG1FBZLM50J10xH9361whJRC9SHZ0Bub4iNRhhI61C8Jv0e1ud19muex6sNKB51ibQNUJNuYn25MuYET/rE6w==", "dev": true, - "license": "MIT", "dependencies": { - "@ionic/utils-fs": "^3.1.6", - "@ionic/utils-terminal": "^2.3.3", + "@ionic/utils-fs": "^3.1.7", + "@ionic/utils-terminal": "^2.3.4", "bplist-parser": "^0.3.2", "debug": "^4.3.4", "elementtree": "^0.1.7", - "ini": "^3.0.1", - "plist": "^3.0.6", - "split2": "^4.1.0", + "ini": "^4.1.1", + "plist": "^3.1.0", + "split2": "^4.2.0", "through2": "^4.0.2", - "tslib": "^2.4.0", + "tslib": "^2.6.2", "yauzl": "^2.10.0" }, "bin": { "native-run": "bin/native-run" }, "engines": { - "node": ">=12.13.0" - } - }, - "node_modules/native-run/node_modules/ini": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.1.tgz", - "integrity": "sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=16.0.0" } }, "node_modules/native-run/node_modules/split2": { @@ -15563,7 +15662,6 @@ "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", "dev": true, - "license": "ISC", "engines": { "node": ">= 10.x" } diff --git a/ui/package.json b/ui/package.json index c3da96975b1..f6c1386c83f 100644 --- a/ui/package.json +++ b/ui/package.json @@ -60,7 +60,7 @@ "@angular/compiler-cli": "^16.2.12", "@angular/language-service": "^16.2.12", "@capacitor/assets": "^3.0.0", - "@capacitor/cli": "5.2.3", + "@capacitor/cli": "6.1.0", "@ionic/angular-toolkit": "^11.0.1", "@stylistic/eslint-plugin": "^2.2.2", "@types/jasmine": "~4.3.6", From 705707b4c886e12eebdb614be6a603db9dd1e56c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 26 Jul 2024 14:39:14 +0200 Subject: [PATCH 082/173] Build(deps-dev): Bump @capacitor/cli from 6.1.0 to 6.1.1 in /ui (#2720) Bumps [@capacitor/cli](https://github.com/ionic-team/capacitor) from 6.1.0 to 6.1.1. - [Release notes](https://github.com/ionic-team/capacitor/releases) - [Changelog](https://github.com/ionic-team/capacitor/blob/main/CHANGELOG.md) - [Commits](https://github.com/ionic-team/capacitor/compare/6.1.0...6.1.1) --- updated-dependencies: - dependency-name: "@capacitor/cli" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 8 ++++---- ui/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 410b17c9daf..1cbf0a59a01 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -65,7 +65,7 @@ "@angular/compiler-cli": "^16.2.12", "@angular/language-service": "^16.2.12", "@capacitor/assets": "^3.0.0", - "@capacitor/cli": "6.1.0", + "@capacitor/cli": "6.1.1", "@ionic/angular-toolkit": "^11.0.1", "@stylistic/eslint-plugin": "^2.2.2", "@types/jasmine": "~4.3.6", @@ -3075,9 +3075,9 @@ } }, "node_modules/@capacitor/cli": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@capacitor/cli/-/cli-6.1.0.tgz", - "integrity": "sha512-HEKDh3+FuNZKFHmSDZ7nAnaX3bzhtznYk9GsZBMac1y4CTAxIykPX9wzZ3DzLeM/EbMBGFClUbefkIkimAyfYg==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@capacitor/cli/-/cli-6.1.1.tgz", + "integrity": "sha512-rsRqEadfnBSUX90RZj59oXvi30bpSusLMfIcgbOIArOloTgfaaWr9R471F6m3gGWF7BhNoskJpZcCgSUsfywwA==", "dev": true, "dependencies": { "@ionic/cli-framework-output": "^2.2.5", diff --git a/ui/package.json b/ui/package.json index f6c1386c83f..cf16875880f 100644 --- a/ui/package.json +++ b/ui/package.json @@ -60,7 +60,7 @@ "@angular/compiler-cli": "^16.2.12", "@angular/language-service": "^16.2.12", "@capacitor/assets": "^3.0.0", - "@capacitor/cli": "6.1.0", + "@capacitor/cli": "6.1.1", "@ionic/angular-toolkit": "^11.0.1", "@stylistic/eslint-plugin": "^2.2.2", "@types/jasmine": "~4.3.6", From 5009b4a4d040d79be3ff8b670e24ef28ed56e6c8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 26 Jul 2024 14:39:31 +0200 Subject: [PATCH 083/173] Build(deps): Bump @capacitor/ios from 5.2.3 to 5.7.7 in /ui (#2719) Bumps [@capacitor/ios](https://github.com/ionic-team/capacitor) from 5.2.3 to 5.7.7. - [Release notes](https://github.com/ionic-team/capacitor/releases) - [Changelog](https://github.com/ionic-team/capacitor/blob/5.7.7/CHANGELOG.md) - [Commits](https://github.com/ionic-team/capacitor/compare/5.2.3...5.7.7) --- updated-dependencies: - dependency-name: "@capacitor/ios" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 11 +++++------ ui/package.json | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 1cbf0a59a01..8182534d2d0 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -22,7 +22,7 @@ "@capacitor/app": "^5.0.6", "@capacitor/core": "5.7.6", "@capacitor/filesystem": "^5.2.0", - "@capacitor/ios": "5.2.3", + "@capacitor/ios": "5.7.7", "@capacitor/splash-screen": "^5.0.6", "@ionic-native/core": "^5.36.0", "@ionic-native/file-opener": "^5.36.0", @@ -3369,12 +3369,11 @@ } }, "node_modules/@capacitor/ios": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@capacitor/ios/-/ios-5.2.3.tgz", - "integrity": "sha512-ailR/Mer48GEXdqip+ENyN3Qk+ZtUBNDTlHh83WLNbx6uv71z6lCeoLKBXdtSEBFwzFrwtCO5upzbdzK79pONQ==", - "license": "MIT", + "version": "5.7.7", + "resolved": "https://registry.npmjs.org/@capacitor/ios/-/ios-5.7.7.tgz", + "integrity": "sha512-bgvSJGia5C5Klfd7t/qlqlRAWzGGAwlIlzkOJYsxpJiYuz6OXVgeesuXRxMNOaUZQ9fmL7OWukmhcv03t9Up+w==", "peerDependencies": { - "@capacitor/core": "^5.2.0" + "@capacitor/core": "^5.7.0" } }, "node_modules/@capacitor/splash-screen": { diff --git a/ui/package.json b/ui/package.json index cf16875880f..e3df9fb71eb 100644 --- a/ui/package.json +++ b/ui/package.json @@ -17,7 +17,7 @@ "@capacitor/app": "^5.0.6", "@capacitor/core": "5.7.6", "@capacitor/filesystem": "^5.2.0", - "@capacitor/ios": "5.2.3", + "@capacitor/ios": "5.7.7", "@capacitor/splash-screen": "^5.0.6", "@ionic-native/core": "^5.36.0", "@ionic-native/file-opener": "^5.36.0", From 1c4a081104f79015a0dfe1aa11c6c0008f35b622 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 26 Jul 2024 14:59:11 +0200 Subject: [PATCH 084/173] Build(deps): Bump compare-versions from 6.1.0 to 6.1.1 in /ui (#2718) Bumps [compare-versions](https://github.com/omichelsen/compare-versions) from 6.1.0 to 6.1.1. - [Changelog](https://github.com/omichelsen/compare-versions/blob/main/CHANGELOG.md) - [Commits](https://github.com/omichelsen/compare-versions/compare/v6.1.0...v6.1.1) --- updated-dependencies: - dependency-name: compare-versions dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 7 ++++--- ui/package.json | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 8182534d2d0..3410c60f21e 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -40,7 +40,7 @@ "chartjs-adapter-date-fns": "^3.0.0", "chartjs-plugin-zoom": "^2.0.1", "classlist.js": "^1.1.20150312", - "compare-versions": "^6.1.0", + "compare-versions": "^6.1.1", "d3": "^7.9.0", "date-fns": "^2.30.0", "file-saver-es": "^2.0.5", @@ -8272,8 +8272,9 @@ } }, "node_modules/compare-versions": { - "version": "6.1.0", - "license": "MIT" + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz", + "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==" }, "node_modules/component-emitter": { "version": "1.3.1", diff --git a/ui/package.json b/ui/package.json index e3df9fb71eb..5ac6b171f50 100644 --- a/ui/package.json +++ b/ui/package.json @@ -35,7 +35,7 @@ "chartjs-adapter-date-fns": "^3.0.0", "chartjs-plugin-zoom": "^2.0.1", "classlist.js": "^1.1.20150312", - "compare-versions": "^6.1.0", + "compare-versions": "^6.1.1", "d3": "^7.9.0", "date-fns": "^2.30.0", "file-saver-es": "^2.0.5", From acb5a20eb2fabc45cbcb77307116c980dc4b1613 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 26 Jul 2024 16:19:21 +0200 Subject: [PATCH 085/173] Build(deps): Bump @capacitor/core from 5.7.6 to 5.7.7 in /ui (#2716) Bumps [@capacitor/core](https://github.com/ionic-team/capacitor) from 5.7.6 to 5.7.7. - [Release notes](https://github.com/ionic-team/capacitor/releases) - [Changelog](https://github.com/ionic-team/capacitor/blob/5.7.7/CHANGELOG.md) - [Commits](https://github.com/ionic-team/capacitor/compare/5.7.6...5.7.7) --- updated-dependencies: - dependency-name: "@capacitor/core" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 8 ++++---- ui/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 3410c60f21e..cc7d61e71ec 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -20,7 +20,7 @@ "@capacitor-community/file-opener": "^1.0.5", "@capacitor/android": "5.2.3", "@capacitor/app": "^5.0.6", - "@capacitor/core": "5.7.6", + "@capacitor/core": "5.7.7", "@capacitor/filesystem": "^5.2.0", "@capacitor/ios": "5.7.7", "@capacitor/splash-screen": "^5.0.6", @@ -3352,9 +3352,9 @@ } }, "node_modules/@capacitor/core": { - "version": "5.7.6", - "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-5.7.6.tgz", - "integrity": "sha512-YVCNegFg04Pm6Rfc6KbZT2wnxAUzhcyi3b+MWFj+FwUOOFNmnGkzxCFo4tQakXFblfOK6pU0Va5XuiNs1+Fnow==", + "version": "5.7.7", + "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-5.7.7.tgz", + "integrity": "sha512-LeV1ljAihl/1lFGHZERNY2DtD1fbPBF3rNOSHFPMXIluK4Cq4nK4a4z/dLPX+Cv4F0TyCIzX3+/t79PMbhDwrg==", "dependencies": { "tslib": "^2.1.0" } diff --git a/ui/package.json b/ui/package.json index 5ac6b171f50..de9a35b390f 100644 --- a/ui/package.json +++ b/ui/package.json @@ -15,7 +15,7 @@ "@capacitor-community/file-opener": "^1.0.5", "@capacitor/android": "5.2.3", "@capacitor/app": "^5.0.6", - "@capacitor/core": "5.7.6", + "@capacitor/core": "5.7.7", "@capacitor/filesystem": "^5.2.0", "@capacitor/ios": "5.7.7", "@capacitor/splash-screen": "^5.0.6", From 2f205c5a9999e187ad4b8c0e229c82cd1c57b3f1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Jul 2024 18:56:46 +0200 Subject: [PATCH 086/173] Build(deps): Bump swiper from 11.1.5 to 11.1.8 in /ui (#2726) Bumps [swiper](https://github.com/nolimits4web/Swiper) from 11.1.5 to 11.1.8. - [Release notes](https://github.com/nolimits4web/Swiper/releases) - [Changelog](https://github.com/nolimits4web/swiper/blob/master/CHANGELOG.md) - [Commits](https://github.com/nolimits4web/Swiper/compare/v11.1.5...v11.1.8) --- updated-dependencies: - dependency-name: swiper dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 8 ++++---- ui/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index cc7d61e71ec..0e9e711631d 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -49,7 +49,7 @@ "ngx-spinner": "^16.0.2", "roboto-fontface": "^0.10.0", "rxjs": "~6.6.7", - "swiper": "11.1.5", + "swiper": "11.1.8", "tslib": "^2.6.2", "uuid": "^10.0.0", "zone.js": "~0.13.3" @@ -20394,9 +20394,9 @@ } }, "node_modules/swiper": { - "version": "11.1.5", - "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.1.5.tgz", - "integrity": "sha512-JJQWFXdxiMGC2j6ZGTYat5Z7NN9JORJBgHp0/joX9uPod+cRj0wr5H5VnWSNIz9JeAamQvYKaG7aFrGHIF9OEg==", + "version": "11.1.8", + "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.1.8.tgz", + "integrity": "sha512-sBFp7fA+IfZ/7BMcg8/JSEqDD1qZXBUyliT76yk3zIYVu2fMwFVAghhAJ9vBM5tJUtHW5qcD0pmeEGQs1EK14w==", "funding": [ { "type": "patreon", diff --git a/ui/package.json b/ui/package.json index de9a35b390f..7d94205c236 100644 --- a/ui/package.json +++ b/ui/package.json @@ -44,7 +44,7 @@ "ngx-spinner": "^16.0.2", "roboto-fontface": "^0.10.0", "rxjs": "~6.6.7", - "swiper": "11.1.5", + "swiper": "11.1.8", "tslib": "^2.6.2", "uuid": "^10.0.0", "zone.js": "~0.13.3" From 28e18198c0170034f4251a6f902fac372996d4d9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Jul 2024 18:57:29 +0200 Subject: [PATCH 087/173] Build(deps-dev): Bump @stylistic/eslint-plugin in /ui (#2725) Bumps [@stylistic/eslint-plugin](https://github.com/eslint-stylistic/eslint-stylistic/tree/HEAD/packages/eslint-plugin) from 2.3.0 to 2.4.0. - [Release notes](https://github.com/eslint-stylistic/eslint-stylistic/releases) - [Changelog](https://github.com/eslint-stylistic/eslint-stylistic/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint-stylistic/eslint-stylistic/commits/v2.4.0/packages/eslint-plugin) --- updated-dependencies: - dependency-name: "@stylistic/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 195 ++++++++++++++++++------------------------- ui/package.json | 2 +- 2 files changed, 84 insertions(+), 113 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 0e9e711631d..19c1c495f92 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -67,7 +67,7 @@ "@capacitor/assets": "^3.0.0", "@capacitor/cli": "6.1.1", "@ionic/angular-toolkit": "^11.0.1", - "@stylistic/eslint-plugin": "^2.2.2", + "@stylistic/eslint-plugin": "^2.4.0", "@types/jasmine": "~4.3.6", "@types/jasminewd2": "~2.0.13", "@types/node": "^20.12.6", @@ -5087,17 +5087,16 @@ } }, "node_modules/@stylistic/eslint-plugin": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.3.0.tgz", - "integrity": "sha512-rtiz6u5gRyyEZp36FcF1/gHJbsbT3qAgXZ1qkad6Nr/xJ9wrSJkiSFFQhpYVTIZ7FJNRJurEcumZDCwN9dEI4g==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.4.0.tgz", + "integrity": "sha512-GJ86m60wpKPm0m8sSuApOITjCvKUbyzhVO/BTQb7BNYXVUJMS3ql+uAro0V+4yoHwyBVXTB4EDy3UGkOqtEyyw==", "dev": true, - "license": "MIT", "dependencies": { - "@stylistic/eslint-plugin-js": "2.3.0", - "@stylistic/eslint-plugin-jsx": "2.3.0", - "@stylistic/eslint-plugin-plus": "2.3.0", - "@stylistic/eslint-plugin-ts": "2.3.0", - "@types/eslint": "^8.56.10" + "@stylistic/eslint-plugin-js": "2.4.0", + "@stylistic/eslint-plugin-jsx": "2.4.0", + "@stylistic/eslint-plugin-plus": "2.4.0", + "@stylistic/eslint-plugin-ts": "2.4.0", + "@types/eslint": "^9.6.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5107,16 +5106,15 @@ } }, "node_modules/@stylistic/eslint-plugin-js": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.3.0.tgz", - "integrity": "sha512-lQwoiYb0Fs6Yc5QS3uT8+T9CPKK2Eoxc3H8EnYJgM26v/DgtW+1lvy2WNgyBflU+ThShZaHm3a6CdD9QeKx23w==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.4.0.tgz", + "integrity": "sha512-ScIYDFAwNz+ELr3KfAZMuYMCUq7Q6TdEEIq4RBRR77EHucpDrwi5Kx2d0VdYxb4s4o6nOtSkJmY9MCZupDYJow==", "dev": true, - "license": "MIT", "dependencies": { - "@types/eslint": "^8.56.10", - "acorn": "^8.11.3", + "@types/eslint": "^9.6.0", + "acorn": "^8.12.1", "eslint-visitor-keys": "^4.0.0", - "espree": "^10.0.1" + "espree": "^10.1.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5130,7 +5128,6 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", "dev": true, - "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -5143,7 +5140,6 @@ "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.12.0", "acorn-jsx": "^5.3.2", @@ -5157,14 +5153,13 @@ } }, "node_modules/@stylistic/eslint-plugin-jsx": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-jsx/-/eslint-plugin-jsx-2.3.0.tgz", - "integrity": "sha512-tsQ0IEKB195H6X9A4iUSgLLLKBc8gUBWkBIU8tp1/3g2l8stu+PtMQVV/VmK1+3bem5FJCyvfcZIQ/WF1fsizA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-jsx/-/eslint-plugin-jsx-2.4.0.tgz", + "integrity": "sha512-yaZXaRj9lOwrQd1YA1d1Ssz58IrDKDYTvLzlKcKED4NlpjDdMbj//Y4DlNhlW9M9v0ZsRsmKNQl2p5OWFfmdEw==", "dev": true, - "license": "MIT", "dependencies": { - "@stylistic/eslint-plugin-js": "^2.3.0", - "@types/eslint": "^8.56.10", + "@stylistic/eslint-plugin-js": "^2.4.0", + "@types/eslint": "^9.6.0", "estraverse": "^5.3.0", "picomatch": "^4.0.2" }, @@ -5180,7 +5175,6 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -5190,7 +5184,6 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -5199,28 +5192,26 @@ } }, "node_modules/@stylistic/eslint-plugin-plus": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-2.3.0.tgz", - "integrity": "sha512-xboPWGUU5yaPlR+WR57GwXEuY4PSlPqA0C3IdNA/+1o2MuBi95XgDJcZiJ9N+aXsqBXAPIpFFb+WQ7QEHo4f7g==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-2.4.0.tgz", + "integrity": "sha512-yqVZ2ps3lSzT3Atcx/jSbzTaRJfxtWeuPk1WvINUod1fRVxNlgKLDwiM+63Hq3Q7H4aM0lS5ccAbFlEGINNg0Q==", "dev": true, - "license": "MIT", "dependencies": { - "@types/eslint": "^8.56.10", - "@typescript-eslint/utils": "^7.12.0" + "@types/eslint": "^9.6.0", + "@typescript-eslint/utils": "^7.17.0" }, "peerDependencies": { "eslint": "*" } }, "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/scope-manager": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.14.1.tgz", - "integrity": "sha512-gPrFSsoYcsffYXTOZ+hT7fyJr95rdVe4kGVX1ps/dJ+DfmlnjFN/GcMxXcVkeHDKqsq6uAcVaQaIi3cFffmAbA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", + "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.14.1", - "@typescript-eslint/visitor-keys": "7.14.1" + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -5231,11 +5222,10 @@ } }, "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/types": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.14.1.tgz", - "integrity": "sha512-mL7zNEOQybo5R3AavY+Am7KLv8BorIv7HCYS5rKoNZKQD9tsfGUpO4KdAn3sSUvTiS4PQkr2+K0KJbxj8H9NDg==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", "dev": true, - "license": "MIT", "engines": { "node": "^18.18.0 || >=20.0.0" }, @@ -5245,14 +5235,13 @@ } }, "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.14.1.tgz", - "integrity": "sha512-k5d0VuxViE2ulIO6FbxxSZaxqDVUyMbXcidC8rHvii0I56XZPv8cq+EhMns+d/EVIL41sMXqRbK3D10Oza1bbA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", + "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "7.14.1", - "@typescript-eslint/visitor-keys": "7.14.1", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -5274,16 +5263,15 @@ } }, "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/utils": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.14.1.tgz", - "integrity": "sha512-CMmVVELns3nak3cpJhZosDkm63n+DwBlDX8g0k4QUa9BMnF+lH2lr3d130M1Zt1xxmB3LLk3NV7KQCq86ZBBhQ==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", + "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.14.1", - "@typescript-eslint/types": "7.14.1", - "@typescript-eslint/typescript-estree": "7.14.1" + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -5297,13 +5285,12 @@ } }, "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.14.1.tgz", - "integrity": "sha512-Crb+F75U1JAEtBeQGxSKwI60hZmmzaqA3z9sYsVm8X7W5cwLEm5bRe0/uXS6+MR/y8CVpKSR/ontIAIEPFcEkA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", + "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/types": "7.18.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -5319,7 +5306,6 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } @@ -5329,7 +5315,6 @@ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, - "license": "MIT", "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -5350,7 +5335,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -5366,21 +5350,19 @@ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@stylistic/eslint-plugin-ts": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-ts/-/eslint-plugin-ts-2.3.0.tgz", - "integrity": "sha512-wqOR38/uz/0XPnHX68ftp8sNMSAqnYGjovOTN7w00xnjS6Lxr3Sk7q6AaxWWqbMvOj7V2fQiMC5HWAbTruJsCg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-ts/-/eslint-plugin-ts-2.4.0.tgz", + "integrity": "sha512-0zi3hHrrqaXPGZESTfPNUm4YMvxq+aqPGCUiZfEnn7l5VNC19oKaPonZ6LmKzoksebzpJ7w6nieZLVeQm4o7tg==", "dev": true, - "license": "MIT", "dependencies": { - "@stylistic/eslint-plugin-js": "2.3.0", - "@types/eslint": "^8.56.10", - "@typescript-eslint/utils": "^7.12.0" + "@stylistic/eslint-plugin-js": "2.4.0", + "@types/eslint": "^9.6.0", + "@typescript-eslint/utils": "^7.17.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5390,14 +5372,13 @@ } }, "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/scope-manager": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.14.1.tgz", - "integrity": "sha512-gPrFSsoYcsffYXTOZ+hT7fyJr95rdVe4kGVX1ps/dJ+DfmlnjFN/GcMxXcVkeHDKqsq6uAcVaQaIi3cFffmAbA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", + "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.14.1", - "@typescript-eslint/visitor-keys": "7.14.1" + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -5408,11 +5389,10 @@ } }, "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/types": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.14.1.tgz", - "integrity": "sha512-mL7zNEOQybo5R3AavY+Am7KLv8BorIv7HCYS5rKoNZKQD9tsfGUpO4KdAn3sSUvTiS4PQkr2+K0KJbxj8H9NDg==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", "dev": true, - "license": "MIT", "engines": { "node": "^18.18.0 || >=20.0.0" }, @@ -5422,14 +5402,13 @@ } }, "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.14.1.tgz", - "integrity": "sha512-k5d0VuxViE2ulIO6FbxxSZaxqDVUyMbXcidC8rHvii0I56XZPv8cq+EhMns+d/EVIL41sMXqRbK3D10Oza1bbA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", + "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "7.14.1", - "@typescript-eslint/visitor-keys": "7.14.1", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -5451,16 +5430,15 @@ } }, "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/utils": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.14.1.tgz", - "integrity": "sha512-CMmVVELns3nak3cpJhZosDkm63n+DwBlDX8g0k4QUa9BMnF+lH2lr3d130M1Zt1xxmB3LLk3NV7KQCq86ZBBhQ==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", + "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.14.1", - "@typescript-eslint/types": "7.14.1", - "@typescript-eslint/typescript-estree": "7.14.1" + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -5474,13 +5452,12 @@ } }, "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.14.1.tgz", - "integrity": "sha512-Crb+F75U1JAEtBeQGxSKwI60hZmmzaqA3z9sYsVm8X7W5cwLEm5bRe0/uXS6+MR/y8CVpKSR/ontIAIEPFcEkA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", + "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/types": "7.18.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -5496,7 +5473,6 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } @@ -5506,7 +5482,6 @@ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, - "license": "MIT", "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -5527,7 +5502,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -5543,7 +5517,6 @@ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -5764,11 +5737,10 @@ } }, "node_modules/@types/eslint": { - "version": "8.56.10", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", - "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.0.tgz", + "integrity": "sha512-gi6WQJ7cHRgZxtkQEoyHMppPjq9Kxo5Tjn2prSKDSmZrCz8TZ3jSRCeTJm+WoM+oB0WG37bRqLzaaU3q7JypGg==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -6748,11 +6720,10 @@ } }, "node_modules/acorn": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", - "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, - "license": "MIT", "bin": { "acorn": "bin/acorn" }, diff --git a/ui/package.json b/ui/package.json index 7d94205c236..147cd97471f 100644 --- a/ui/package.json +++ b/ui/package.json @@ -62,7 +62,7 @@ "@capacitor/assets": "^3.0.0", "@capacitor/cli": "6.1.1", "@ionic/angular-toolkit": "^11.0.1", - "@stylistic/eslint-plugin": "^2.2.2", + "@stylistic/eslint-plugin": "^2.4.0", "@types/jasmine": "~4.3.6", "@types/jasminewd2": "~2.0.13", "@types/node": "^20.12.6", From 6f727ace0c1e59d711cf81ddb5891c1dcffd90f0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Jul 2024 19:47:15 +0200 Subject: [PATCH 088/173] Build(deps): Bump org.dhatim:fastexcel from 0.18.0 to 0.18.1 in /cnf (#2724) * Build(deps): Bump org.dhatim:fastexcel-reader in /cnf Bumps [org.dhatim:fastexcel-reader](https://github.com/dhatim/fastexcel) from 0.18.0 to 0.18.1. - [Release notes](https://github.com/dhatim/fastexcel/releases) - [Commits](https://github.com/dhatim/fastexcel/compare/0.18.0...0.18.1) --- updated-dependencies: - dependency-name: org.dhatim:fastexcel-reader dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Build(deps): Bump org.dhatim:fastexcel from 0.18.0 to 0.18.1 in /cnf Bumps [org.dhatim:fastexcel](https://github.com/dhatim/fastexcel) from 0.18.0 to 0.18.1. - [Release notes](https://github.com/dhatim/fastexcel/releases) - [Commits](https://github.com/dhatim/fastexcel/compare/0.18.0...0.18.1) --- updated-dependencies: - dependency-name: org.dhatim:fastexcel dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Update bnd --------- 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 | 4 ++-- io.openems.backend.application/BackendApp.bndrun | 7 +++---- io.openems.edge.application/EdgeApp.bndrun | 7 +++---- io.openems.wrapper/bnd.bnd | 4 ++-- io.openems.wrapper/fastexcel.bnd | 6 +++--- 5 files changed, 13 insertions(+), 15 deletions(-) diff --git a/cnf/pom.xml b/cnf/pom.xml index 06a780a8931..5483a448725 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -260,12 +260,12 @@ org.dhatim fastexcel - 0.18.0 + 0.18.1 org.dhatim fastexcel-reader - 0.18.0 + 0.18.1 diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index 5c8dedd876c..1d0b0dde4e4 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -60,7 +60,7 @@ -runbundles: \ Java-WebSocket;version='[1.5.4,1.5.5)',\ - com.fasterxml.aalto-xml;version='[1.3.2,1.3.3)',\ + com.fasterxml.aalto-xml;version='[1.3.3,1.3.4)',\ com.google.gson;version='[2.11.0,2.11.1)',\ com.google.guava;version='[33.2.1,33.2.2)',\ com.google.guava.failureaccess;version='[1.0.2,1.0.3)',\ @@ -101,9 +101,8 @@ io.openems.wrapper.retrofit-converter-scalars;version=snapshot,\ io.openems.wrapper.retrofit2;version=snapshot,\ io.reactivex.rxjava3.rxjava;version='[3.1.8,3.1.9)',\ - org.apache.commons.commons-compress;version='[1.26.1,1.26.2)',\ + org.apache.commons.commons-compress;version='[1.26.2,1.26.3)',\ org.apache.commons.commons-csv;version='[1.10.0,1.10.1)',\ - org.apache.commons.commons-io;version='[2.15.1,2.15.2)',\ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ org.apache.felix.eventadmin;version='[1.6.4,1.6.5)',\ org.apache.felix.fileinstall;version='[3.7.4,3.7.5)',\ @@ -125,4 +124,4 @@ org.owasp.encoder;version='[1.2.3,1.2.4)',\ org.postgresql.jdbc;version='[42.7.3,42.7.4)',\ reactive-streams;version='[1.0.4,1.0.5)',\ - stax2-api;version='[4.2.0,4.2.1)' \ No newline at end of file + stax2-api;version='[4.2.2,4.2.3)' \ No newline at end of file diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index 7204fb4f29c..7de47026cfe 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -196,7 +196,7 @@ bcpkix;version='[1.70.0,1.70.1)',\ bcprov;version='[1.70.0,1.70.1)',\ bcutil;version='[1.70.0,1.70.1)',\ - com.fasterxml.aalto-xml;version='[1.3.2,1.3.3)',\ + com.fasterxml.aalto-xml;version='[1.3.3,1.3.4)',\ com.fazecast.jSerialComm;version='[2.10.4,2.10.5)',\ com.ghgande.j2mod;version='[3.2.1,3.2.2)',\ com.google.gson;version='[2.11.0,2.11.1)',\ @@ -396,9 +396,8 @@ io.reactivex.rxjava3.rxjava;version='[3.1.8,3.1.9)',\ javax.jmdns;version='[3.4.1,3.4.2)',\ javax.xml.soap-api;version='[1.4.0,1.4.1)',\ - org.apache.commons.commons-compress;version='[1.26.1,1.26.2)',\ + org.apache.commons.commons-compress;version='[1.26.2,1.26.3)',\ org.apache.commons.commons-csv;version='[1.10.0,1.10.1)',\ - org.apache.commons.commons-io;version='[2.15.1,2.15.2)',\ org.apache.commons.math3;version='[3.6.1,3.6.2)',\ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ org.apache.felix.eventadmin;version='[1.6.4,1.6.5)',\ @@ -428,4 +427,4 @@ org.owasp.encoder;version='[1.2.3,1.2.4)',\ reactive-streams;version='[1.0.4,1.0.5)',\ rrd4j;version='[3.9.0,3.9.1)',\ - stax2-api;version='[4.2.0,4.2.1)' \ No newline at end of file + stax2-api;version='[4.2.2,4.2.3)' \ No newline at end of file diff --git a/io.openems.wrapper/bnd.bnd b/io.openems.wrapper/bnd.bnd index 73b692cd3cb..8bed7415c14 100644 --- a/io.openems.wrapper/bnd.bnd +++ b/io.openems.wrapper/bnd.bnd @@ -24,7 +24,7 @@ Bundle-Description: This wraps external java libraries that do not have OSGi hea com.google.gson;version='2.10.1',\ de.bytefish:pgbulkinsert;version='8.1.4',\ fr.turri:aXMLRPC;version='1.13.0',\ - org.dhatim:fastexcel;version='0.18.0',\ - org.dhatim:fastexcel-reader;version='0.18',\ + org.dhatim:fastexcel;version='0.18.1',\ + org.dhatim:fastexcel-reader;version='0.18.1',\ org.eclipse.paho.mqttv5.client;version='1.2.5',\ org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm;version='1.7.3',\ diff --git a/io.openems.wrapper/fastexcel.bnd b/io.openems.wrapper/fastexcel.bnd index 92ccb7bb914..e3fa142345c 100644 --- a/io.openems.wrapper/fastexcel.bnd +++ b/io.openems.wrapper/fastexcel.bnd @@ -1,11 +1,11 @@ Bundle-Name: fastexcel Bundle-DocURL: https://github.com/dhatim/fastexcel Bundle-License: https://opensource.org/licenses/Apache-2.0 -Bundle-Version: 0.18.0 +Bundle-Version: 0.18.1 Include-Resource: \ - @fastexcel-0.18.0.jar,\ - @fastexcel-reader-0.18.0.jar,\ + @fastexcel-0.18.1.jar,\ + @fastexcel-reader-0.18.1.jar,\ -dsannotations: * From 5985dfbb1ced7ab9855a1c764494973e1205cb9a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Jul 2024 19:47:39 +0200 Subject: [PATCH 089/173] Build(deps): Bump @capacitor/android from 5.2.3 to 5.7.7 in /ui (#2717) Bumps [@capacitor/android](https://github.com/ionic-team/capacitor) from 5.2.3 to 5.7.7. - [Release notes](https://github.com/ionic-team/capacitor/releases) - [Changelog](https://github.com/ionic-team/capacitor/blob/5.7.7/CHANGELOG.md) - [Commits](https://github.com/ionic-team/capacitor/compare/5.2.3...5.7.7) --- updated-dependencies: - dependency-name: "@capacitor/android" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 11 +++++------ ui/package.json | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 19c1c495f92..1a4250a7f02 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -18,7 +18,7 @@ "@angular/router": "~16.2.12", "@angular/service-worker": "~16.2.12", "@capacitor-community/file-opener": "^1.0.5", - "@capacitor/android": "5.2.3", + "@capacitor/android": "5.7.7", "@capacitor/app": "^5.0.6", "@capacitor/core": "5.7.7", "@capacitor/filesystem": "^5.2.0", @@ -2851,12 +2851,11 @@ } }, "node_modules/@capacitor/android": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@capacitor/android/-/android-5.2.3.tgz", - "integrity": "sha512-TqXOq5RIniMACcAckn/X84XajPP2GU4VH7Er390Ja2Y2BWSeUKgk7T8aURcwLYu2hnv+Op9eTww5MTBb3zBtmg==", - "license": "MIT", + "version": "5.7.7", + "resolved": "https://registry.npmjs.org/@capacitor/android/-/android-5.7.7.tgz", + "integrity": "sha512-gkc8p0jjbRHu5oxKvWQV1d6zRHNeK7/GQUHOL9J6yQqnnttLDf1tSZ4BVjicMdyKlxUailuBcboWvng+KYilvQ==", "peerDependencies": { - "@capacitor/core": "^5.2.0" + "@capacitor/core": "^5.7.0" } }, "node_modules/@capacitor/app": { diff --git a/ui/package.json b/ui/package.json index 147cd97471f..9c7fd08eec7 100644 --- a/ui/package.json +++ b/ui/package.json @@ -13,7 +13,7 @@ "@angular/router": "~16.2.12", "@angular/service-worker": "~16.2.12", "@capacitor-community/file-opener": "^1.0.5", - "@capacitor/android": "5.2.3", + "@capacitor/android": "5.7.7", "@capacitor/app": "^5.0.6", "@capacitor/core": "5.7.7", "@capacitor/filesystem": "^5.2.0", From ebcf2445b14e09f061c4cda52fe21931544066d7 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Wed, 31 Jul 2024 15:20:30 +0200 Subject: [PATCH 090/173] FEMS Backports 2024-07 (#2727) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Common/General - Gradle: automate version update for android build.gradle - `Controller.Ess.Limiter14a`: Edge Controller and UI visualization for "dimming" according to German law §14a EnWG ## OpenEMS Backend - Performance optimizations - Drop PerMessageDeflate because it has bad effects on performance with a high number of connected Edges - Add a copy of Draft6455 which does not throw an exception internally - Reduce Exceptions - OnOpen: no unnecessary parsing of handshake + do not throw Exception - Parse JsonrpcMessage inside Executor Thread - sendMessage by default never throws Exception - use StringBuilders where feasible - throw the same Exception for all disposed requests in WsData - InfluxDB: remove filter for sunspec channels - Metadata: add handling of "ems type" - Aggregated Influx: add channels for ctrlEssLimiter14a0 - Cleanup logs: - "No measurement provided for zoneId" - "Channels missing in Current-Data " - WsData: - handle failed send message - set WsData.WebSocket via constructor - Change debugLog interval to 5 seconds - Replace run() with standard method names - Add internal WebsocketPerformanceTestApp - Drop now unused Websocket DebugMode ## OpenEMS Edge - Home Battery: - fix calculation of number of towers - handle tower exceptionally not 0/null for some bms versions - downgrade uncritical states to INFO - Battery-Protection: add SoC-to-Percent characteristics & implement for FENECON Home Battery - KACO Battery-Inverter: optimize state machine handling - MR Gridcon: move obsolete bundle to archive - See https://github.com/fenecon/openems-archive/tree/main/io.openems.edge.ess.mr.gridcon - Translation keys for timedata category ## OpenEMS UI - Fix Nullpointer thrown through chart.js after failed query. - Apparently chartjs not having completely rendered datasets and property borderColor was missing - Extend vscode extensions with 18n ally - add `i18n ally` to vscode extensions - Fix ChartJs yAxis scaling for only 0 values in data series - Chartjs y-axis Scaling for only null or/and 0 values in data series results in doing negative and positive scaling - Add missing redirect after token expired - Token expired, old route got reloaded, no redirection to `/login` - Add Power-Assistant - Add Power-Assistant to UI Settings - Show relevant channels for power constraints; sorted by Scheduler - Cleanup Settings + separate ADMIN widgets - Add subnavigation to consumption history - restructured overdue shared folder - added current and voltage chart (only visible for Role.INSTALLER to consumption and production history - added subnavigation to consumption history - Add missing module for angular date picker - Add missing import for pickdatepopovercomponent, unittest will follow soon - Fix live modal visualization of meters - Add Unittest for [angular-my-date-picker](https://github.com/nodro7/angular-mydatepicker) - Testing if button click is opening calendar or rather if this component exists in the DOM after button click - Move Helpbutton to its right module - Prepare platform check to login page - Fix other consumption calculation - Adding unittest for calculation of other consumption - Fixing wrong calculation of other consumption for multiple evcs and consumptionMeters - Refactor gridOptimizedCharge history - Replace global role with edge role check - /settings: replacing check for global Role with edge Role - Add unittest for role in /settings - Live-EnergyMonitor: use new sum Max/Min ESS DischargePower channels - refactor variables and methods in right order - Refactors every variable and method to member-ordering rule. - See: [https://typescript-eslint.io/rules/member-ordering/] --------- Co-authored-by: Sebastian Asen <47855186+sebastianasen@users.noreply.github.com> Co-authored-by: Lukas Rieger <73471197+lukasrgr@users.noreply.github.com> Co-authored-by: Johann Kaufmann <165755282+johannk24@users.noreply.github.com> Co-authored-by: Michael Grill <59126309+michaelgrill@users.noreply.github.com> Co-authored-by: Jonas Ernst <11683792+JonasE99@users.noreply.github.com> Co-authored-by: Stefan Feilmeier <3515268+sfeilmeier@users.noreply.github.com> Co-authored-by: Hueseyin Sahutoglu <34771592+huseyinsaht@users.noreply.github.com> Co-authored-by: Fabian Brandtner <10850256+fabian94533@users.noreply.github.com> Co-authored-by: Anas Shetla <141644226+AnasShetla@users.noreply.github.com> --- .../backend/edge/application/TestClient.java | 122 + .../WebsocketPerformanceTestApp.java | 77 + .../Backend2BackendWebsocket.java | 3 +- .../openems/backend/b2bwebsocket/Config.java | 6 - .../openems/backend/b2bwebsocket/OnClose.java | 4 +- .../openems/backend/b2bwebsocket/OnError.java | 2 +- .../backend/b2bwebsocket/OnNotification.java | 2 +- .../openems/backend/b2bwebsocket/OnOpen.java | 85 +- .../backend/b2bwebsocket/OnRequest.java | 2 +- .../SubscribedEdgesChannelsWorker.java | 7 +- .../backend/b2bwebsocket/WebsocketServer.java | 13 +- .../openems/backend/b2bwebsocket/WsData.java | 5 +- .../b2bwebsocket/B2bWebsocketTest.java | 11 +- .../backend/b2bwebsocket/TestClient.java | 12 +- .../common/edgewebsocket/EdgeWebsocket.java | 12 +- .../jsonrpc/request/GetEmsTypeRequest.java | 63 + .../jsonrpc/response/GetEmsTypeResponse.java | 40 + .../backend/common/metadata/Metadata.java | 8 + .../backend/common/test/DummyMetadata.java | 5 + .../common/uiwebsocket/UiWebsocket.java | 10 +- .../core/debugcycle/DebugCycleExecutor.java | 2 +- .../openems/backend/edgewebsocket/Config.java | 6 - .../edgewebsocket/EdgeWebsocketImpl.java | 20 +- .../backend/edgewebsocket/OnClose.java | 9 +- .../backend/edgewebsocket/OnError.java | 2 +- .../backend/edgewebsocket/OnNotification.java | 4 +- .../openems/backend/edgewebsocket/OnOpen.java | 117 +- .../backend/edgewebsocket/OnRequest.java | 21 +- .../edgewebsocket/SystemLogHandler.java | 39 +- .../edgewebsocket/WebsocketServer.java | 66 +- .../openems/backend/edgewebsocket/WsData.java | 6 + .../backend/metadata/dummy/Config.java | 7 + .../backend/metadata/dummy/MetadataDummy.java | 28 +- .../backend/metadata/file/MetadataFile.java | 5 + .../openems/backend/metadata/odoo/Config.java | 1 - .../backend/metadata/odoo/DebugMode.java | 16 + .../openems/backend/metadata/odoo/Field.java | 18 +- .../backend/metadata/odoo/MetadataOdoo.java | 6 +- .../metadata/odoo/odoo/OdooHandler.java | 27 + .../aggregatedinflux/AggregatedInflux.java | 66 +- .../aggregatedinflux/AllowedChannels.java | 2 + .../timedata/influx/ChannelFilter.java | 11 - .../timedata/influx/ChannelFilterTest.java | 4 +- .../backend/uiwebsocket/impl/Config.java | 6 - .../backend/uiwebsocket/impl/OnClose.java | 21 - .../backend/uiwebsocket/impl/OnError.java | 2 +- .../uiwebsocket/impl/OnNotification.java | 2 +- .../backend/uiwebsocket/impl/OnOpen.java | 17 - .../backend/uiwebsocket/impl/OnRequest.java | 25 +- .../uiwebsocket/impl/UiWebsocketImpl.java | 38 +- .../uiwebsocket/impl/WebsocketServer.java | 31 +- .../backend/uiwebsocket/impl/WsData.java | 35 +- .../common/exceptions/OpenemsError.java | 2 + .../common/websocket/AbstractWebsocket.java | 64 +- .../websocket/AbstractWebsocketClient.java | 149 +- .../websocket/AbstractWebsocketServer.java | 239 +- .../websocket/ClientReconnectorWorker.java | 14 +- .../websocket/DummyWebsocketServer.java | 32 +- .../openems/common/websocket/DummyWsData.java | 10 - .../openems/common/websocket/MyDraft6455.java | 1221 ++++ .../io/openems/common/websocket/OnClose.java | 8 +- .../common/websocket/OnCloseHandler.java | 24 +- .../io/openems/common/websocket/OnError.java | 8 +- .../common/websocket/OnErrorHandler.java | 21 +- .../common/websocket/OnInternalError.java | 6 +- .../websocket/OnInternalErrorHandler.java | 2 +- .../common/websocket/OnMessageHandler.java | 182 + .../common/websocket/OnNotification.java | 8 +- .../websocket/OnNotificationHandler.java | 29 - .../io/openems/common/websocket/OnOpen.java | 24 +- .../common/websocket/OnOpenHandler.java | 43 +- .../openems/common/websocket/OnRequest.java | 13 +- .../common/websocket/OnRequestHandler.java | 111 - .../common/websocket/OnResponseHandler.java | 30 - .../common/websocket/WebsocketUtils.java | 51 +- .../io/openems/common/websocket/WsData.java | 48 +- .../ClientReconnectorWorkerTest.java | 12 +- io.openems.edge.application/EdgeApp.bndrun | 4 +- .../battery/protection/BatteryProtection.java | 30 + .../BatteryProtectionDefinition.java | 20 + .../AbstractMaxCurrentHandler.java | 36 +- .../ChargeMaxCurrentHandler.java | 14 +- .../DischargeMaxCurrentHandler.java | 14 +- .../BatteryProtectionDefinitionBydC130.java | 10 + .../BatteryProtectionDefinition.java | 10 + .../fenecon/home/BatteryFeneconHome.java | 9 +- .../fenecon/home/BatteryFeneconHomeImpl.java | 38 +- .../home/FeneconHomeBatteryProtection52.java | 19 + .../home/FeneconHomeBatteryProtection64.java | 19 +- .../home/BatteryFeneconHomeImplTest.java | 171 + .../edge/battery/fenecon/home/TestStatic.java | 48 + ...actBatteryProtectionDefinitionSoltaro.java | 10 + ...BatteryInverterKacoBlueplanetGridsave.java | 123 +- ...eryInverterKacoBlueplanetGridsaveImpl.java | 91 +- .../statemachine/Context.java | 6 +- .../statemachine/GoRunningHandler.java | 5 - .../statemachine/RunningHandler.java | 4 - .../statemachine/StoppedHandler.java | 4 - .../statemachine/UndefinedHandler.java | 27 +- ...nverterKacoBlueplanetGridsaveImplTest.java | 2 +- .../src/io/openems/edge/common/sum/Sum.java | 43 +- .../api/backend/BackendOnRequest.java | 2 +- .../api/backend/ControllerApiBackendImpl.java | 3 +- .../edge/controller/api/backend/OnError.java | 2 +- .../api/backend/OnNotification.java | 2 +- .../edge/controller/api/backend/OnOpen.java | 8 +- .../api/backend/WebsocketClient.java | 5 +- .../edge/controller/api/backend/WsData.java | 6 + .../api/backend/api/ControllerApiBackend.java | 5 +- .../websocket/ControllerApiWebsocketImpl.java | 12 +- .../controller/api/websocket/OnClose.java | 4 +- .../controller/api/websocket/OnError.java | 2 +- .../api/websocket/OnNotification.java | 2 +- .../edge/controller/api/websocket/OnOpen.java | 15 - .../controller/api/websocket/OnRequest.java | 2 +- .../api/websocket/WebsocketServer.java | 16 +- .../edge/controller/api/websocket/WsData.java | 17 +- .../SubscribeSystemLogRequestHandler.java | 12 +- .../.classpath | 0 .../.gitignore | 2 +- .../.project | 2 +- .../org.eclipse.core.resources.prefs | 0 .../bnd.bnd | 11 +- .../readme.adoc | 8 + .../controller/ess/limiter14a/Config.java | 28 + .../limiter14a/ControllerEssLimiter14a.java | 64 + .../ControllerEssLimiter14aImpl.java | 98 + .../ess/limiter14a/RestrictionMode.java | 32 + .../test/.gitignore | 0 .../ControllerEssLimiter14aTest.java | 61 + .../controller/ess/limiter14a/MyConfig.java | 61 + .../core/appmanager/translation_de.properties | 4 +- .../core/appmanager/translation_en.properties | 4 +- .../PredictorManagerImpl.java | 2 +- .../src/io/openems/edge/core/sum/SumImpl.java | 17 +- .../appmanager/OpenemsAppCategoryTest.java | 33 + ...st\303\244nde_OnOffGrid_konsolidiert.xlsx" | Bin 14698 -> 0 bytes .../doc/Fehlerliste.csv | 1165 ---- .../doc/Fehlerliste.xlsx | Bin 64298 -> 0 bytes ...tware-Manual-Anybus-GRIDCON-ACF_PCS_DE.pdf | Bin 1343847 -> 0 bytes ...itung-Hardware-GRIDCON-ACF-Building_DE.pdf | Bin 809083 -> 0 bytes ...2-24-BA_Software-Manual-GRIDCON-PCS_DE.pdf | Bin 2436945 -> 0 bytes .../doc/PQ-01-13-00-PD_GRIDCON_PCS_3W_DE.pdf | Bin 113900 -> 0 bytes .../doc/PQ-01-13-00-PD_PCS-4W_DE.pdf | Bin 115412 -> 0 bytes .../doc/errordesc.txt | 24 - .../doc/handling_off_grid.xlsx | Bin 10280 -> 0 bytes .../doc/mr_schematic_setup.jpg | Bin 2728481 -> 0 bytes io.openems.edge.ess.mr.gridcon/doc/start0.png | Bin 184178 -> 0 bytes io.openems.edge.ess.mr.gridcon/doc/start1.png | Bin 183696 -> 0 bytes io.openems.edge.ess.mr.gridcon/doc/start2.png | Bin 200136 -> 0 bytes io.openems.edge.ess.mr.gridcon/readme.adoc | 9 - .../openems/edge/ess/mr/gridcon/Config.java | 57 - .../edge/ess/mr/gridcon/EssGridcon.java | 365 -- .../edge/ess/mr/gridcon/GridconPcs.java | 169 - .../edge/ess/mr/gridcon/GridconPcsImpl.java | 1601 ----- .../edge/ess/mr/gridcon/GridconSettings.java | 79 - .../openems/edge/ess/mr/gridcon/Helper.java | 38 - .../openems/edge/ess/mr/gridcon/IState.java | 7 - .../edge/ess/mr/gridcon/StateController.java | 88 - .../edge/ess/mr/gridcon/StateObject.java | 35 - .../edge/ess/mr/gridcon/WeightingHelper.java | 105 - .../gridcon/controller/balancing/Config.java | 29 - .../balancing/ControllerMrSetBalancing.java | 23 - .../ControllerMrSetBalancingImpl.java | 58 - .../fundamentalfrequency/Config.java | 35 - .../ControllerMrFundamentalFrequency.java | 23 - .../ControllerMrFundamentalFrequencyImpl.java | 64 - .../ess/mr/gridcon/enums/BalancingMode.java | 26 - .../edge/ess/mr/gridcon/enums/CcuState.java | 47 - .../mr/gridcon/enums/ErrorCodeChannelId0.java | 5688 ----------------- .../mr/gridcon/enums/ErrorCodeChannelId1.java | 900 --- .../edge/ess/mr/gridcon/enums/ErrorDoc.java | 73 - .../enums/FundamentalFrequencyMode.java | 26 - .../mr/gridcon/enums/GridConChannelId.java | 552 -- .../enums/HarmonicCompensationMode.java | 26 - .../ess/mr/gridcon/enums/InverterCount.java | 25 - .../edge/ess/mr/gridcon/enums/Mode.java | 12 - .../ess/mr/gridcon/enums/PControlMode.java | 33 - .../ess/mr/gridcon/enums/ParameterSet.java | 5 - .../gridcon/enums/StatusIpuStateMachine.java | 41 - .../mr/gridcon/enums/StatusIpuStatusMcu.java | 47 - .../edge/ess/mr/gridcon/meter/Config.java | 29 - .../ess/mr/gridcon/meter/MeterGridcon.java | 24 - .../mr/gridcon/meter/MeterGridconImpl.java | 129 - .../edge/ess/mr/gridcon/ongrid/Config.java | 53 - .../mr/gridcon/ongrid/MrGridconOngrid.java | 30 - .../gridcon/ongrid/MrGridconOngridImpl.java | 105 - .../edge/ess/mr/gridcon/onoffgrid/Config.java | 96 - .../gridcon/onoffgrid/MrGridconOnOffgrid.java | 31 - .../onoffgrid/MrGridconOnOffgridImpl.java | 148 - .../gridcon/state/gridconstate/BaseState.java | 233 - .../mr/gridcon/state/gridconstate/Error.java | 346 - .../state/gridconstate/GridconState.java | 35 - .../gridconstate/GridconStateObject.java | 32 - .../mr/gridcon/state/gridconstate/Run.java | 230 - .../gridcon/state/gridconstate/Stopped.java | 186 - .../gridcon/state/gridconstate/Undefined.java | 69 - .../mr/gridcon/state/ongrid/BasteState.java | 7 - .../ess/mr/gridcon/state/ongrid/Error.java | 29 - .../ess/mr/gridcon/state/ongrid/OnGrid.java | 30 - .../mr/gridcon/state/ongrid/OnGridState.java | 34 - .../mr/gridcon/state/ongrid/Undefined.java | 30 - .../state/onoffgrid/AdjustParameter.java | 77 - .../mr/gridcon/state/onoffgrid/BaseState.java | 342 - .../onoffgrid/DecisionTableCondition.java | 112 - .../onoffgrid/DecisionTableConditionImpl.java | 177 - .../state/onoffgrid/DecisionTableHelper.java | 129 - .../mr/gridcon/state/onoffgrid/OffGrid.java | 83 - .../state/onoffgrid/OffGridGridBack.java | 67 - .../mr/gridcon/state/onoffgrid/OnGrid.java | 67 - .../state/onoffgrid/OnOffGridState.java | 39 - .../gridcon/state/onoffgrid/StartSystem.java | 52 - .../mr/gridcon/state/onoffgrid/Undefined.java | 75 - .../state/onoffgrid/WaitForDevices.java | 52 - .../state/onoffgrid/WaitForGridAvailable.java | 70 - .../mr/gridcon/writewords/CcuParameters1.java | 111 - .../mr/gridcon/writewords/CcuParameters2.java | 129 - .../ess/mr/gridcon/writewords/Commands.java | 370 -- .../gridcon/writewords/CosPhiParameters.java | 46 - .../mr/gridcon/writewords/DcDcParameter.java | 118 - .../mr/gridcon/writewords/HexFormatter.java | 102 - .../mr/gridcon/writewords/IpuParameter.java | 90 - .../ess/mr/gridcon/WeightingHelperTest.java | 397 -- .../ess/mr/gridcon/helper/DummyBattery.java | 56 - .../edge/ess/mr/gridcon/helper/DummyEss.java | 344 - .../gridcon/ongrid/state/TestUndefined.java | 53 - .../io/openems/edge/wago/Fieldbus5xxDO.java | 2 +- io.openems.wrapper/pgbulkinsert.bnd | 1 + tools/common.sh | 5 + ui/.eslintrc.json | 3 +- ui/.vscode/extensions.json | 3 +- ui/android/app/build.gradle | 4 +- ui/package-lock.json | 29 +- ui/package.json | 2 + ui/src/app/app-routing.module.ts | 19 +- ui/src/app/app.component.ts | 19 +- ui/src/app/app.module.ts | 10 +- ui/src/app/app.service.ts | 108 +- .../view/component/changelog.component.ts | 24 +- ui/src/app/edge/edge.component.ts | 4 +- .../chart/totalchart.component.ts | 17 +- .../Controller/ChannelThreshold/flat/flat.ts | 4 +- .../ChannelThreshold/overview/overview.ts | 2 +- .../Ess/GridoptimizedCharge/chart/chart.ts | 93 + .../chart/sellToGridLimitChart.component.ts | 71 + .../Ess/GridoptimizedCharge/flat/flat.html | 13 + .../Ess/GridoptimizedCharge/flat/flat.ts | 14 + .../gridOptimizeCharge.module.ts | 28 + .../overview/overview.html | 32 + .../GridoptimizedCharge/overview/overview.ts | 9 + .../Ess/TimeOfUseTariff/chart/chart.ts | 4 +- .../Ess/TimeOfUseTariff/flat/flat.ts | 13 +- .../Ess/TimeOfUseTariff/overview/overview.ts | 2 +- .../history/Controller/controller.module.ts | 4 + .../app/edge/history/abstracthistorychart.ts | 400 +- .../edge/history/chpsoc/chart.component.ts | 15 +- .../chpsocchartoverview.component.ts | 4 +- .../edge/history/chpsoc/widget.component.ts | 3 +- .../history/common/autarchy/chart/chart.ts | 4 +- .../edge/history/common/autarchy/flat/flat.ts | 2 +- .../common/autarchy/overview/overview.ts | 2 +- .../history/common/consumption/Consumption.ts | 16 + .../common/consumption/chart/channels.spec.ts | 2 +- .../consumption/chart/chart.constants.spec.ts | 8 +- .../common/consumption/chart/chart.spec.ts | 8 +- .../history/common/consumption/chart/chart.ts | 16 +- .../common/consumption/details/chart/chart.ts | 93 + .../consumption/details/details.overview.html | 7 + .../consumption/details/details.overview.ts | 37 + .../history/common/consumption/flat/flat.ts | 2 +- .../common/consumption/overview/overview.html | 3 +- .../common/consumption/overview/overview.ts | 40 +- .../common/energy/chart/channels.spec.ts | 18 +- .../energy/chart/chart.constants.spec.ts | 8 +- .../history/common/energy/chart/chart.spec.ts | 4 +- .../edge/history/common/energy/chart/chart.ts | 16 +- .../edge/history/common/energy/flat/flat.ts | 20 +- .../common/grid/chart/chart.constants.spec.ts | 8 +- .../history/common/grid/chart/chart.spec.ts | 159 +- .../edge/history/common/grid/chart/chart.ts | 195 +- .../edge/history/common/grid/flat/flat.html | 9 +- .../app/edge/history/common/grid/flat/flat.ts | 33 +- .../history/common/grid/overview/overview.ts | 2 +- .../common/production/chart/chargerChart.ts | 4 +- .../production/chart/productionMeterChart.ts | 6 +- .../common/production/chart/totalAcChart.ts | 6 +- .../common/production/chart/totalChart.ts | 21 +- .../common/production/chart/totalDcChart.ts | 4 +- .../common/production/details/chart/chart.ts | 8 +- .../production/details/details.overview.html | 3 +- .../production/details/details.overview.ts | 37 +- .../history/common/production/flat/flat.ts | 2 +- .../common/production/overview/overview.ts | 5 +- .../history/common/production/production.ts | 4 + .../selfconsumption/chart/chart.component.ts | 4 +- .../common/selfconsumption/flat/flat.ts | 2 +- .../selfconsumption/overview/overview.ts | 2 +- .../common/storage/overview/overview.html | 6 + .../delayedselltogrid/chart.component.ts | 14 +- ...elayedselltogridchartoverview.component.ts | 3 +- .../delayedselltogrid/widget.component.ts | 3 +- .../fixdigitaloutput/singlechart.component.ts | 14 +- .../fixdigitaloutput/totalchart.component.ts | 14 +- .../fixdigitaloutput/widget.component.ts | 8 +- .../app/edge/history/grid/chart.component.ts | 195 - .../gridoptimizedcharge/chart.component.ts | 238 - ...ptimizedchargechartoverview.component.html | 68 - ...doptimizedchargechartoverview.component.ts | 33 - .../sellToGridLimitChart.component.ts | 202 - .../gridoptimizedcharge/widget.component.html | 33 - .../gridoptimizedcharge/widget.component.ts | 88 - .../history/heatingelement/chart.component.ts | 15 +- .../heatingelementchartoverview.component.ts | 3 +- .../heatingelement/widget.component.ts | 2 +- .../edge/history/heatpump/chart.component.ts | 22 +- .../edge/history/heatpump/widget.component.ts | 3 +- .../app/edge/history/history.component.html | 4 +- ui/src/app/edge/history/history.component.ts | 16 +- ui/src/app/edge/history/history.module.ts | 12 +- ui/src/app/edge/history/historydataservice.ts | 4 +- ...etricpeakshavingchartoverview.component.ts | 3 +- .../peakshaving/asymmetric/chart.component.ts | 15 +- .../asymmetric/widget.component.ts | 2 +- .../peakshaving/symmetric/chart.component.ts | 15 +- ...etricpeakshavingchartoverview.component.ts | 4 +- .../peakshaving/symmetric/widget.component.ts | 2 +- .../peakshaving/timeslot/chart.component.ts | 15 +- ...eslotpeakshavingchartoverview.component.ts | 4 +- .../peakshaving/timeslot/widget.component.ts | 2 +- ui/src/app/edge/history/shared.ts | 7 +- .../singlethreshold/chart.component.ts | 15 +- .../singlethresholdchartoverview.component.ts | 6 +- .../singlethreshold/widget.component.ts | 4 +- .../history/storage/chargerchart.component.ts | 15 +- .../history/storage/esschart.component.ts | 15 +- .../history/storage/singlechart.component.ts | 49 +- .../history/storage/socchart.component.ts | 15 +- .../storagechartoverview.component.ts | 4 +- .../history/storage/totalchart.component.ts | 19 +- .../edge/history/storage/widget.component.ts | 3 +- .../Channelthreshold/Channelthreshold.ts | 2 +- .../app/edge/live/Controller/ChpSoc/ChpSoc.ts | 30 +- .../Ess/FixActivePower/flat/flat.ts | 27 +- .../Ess/FixActivePower/modal/modal.ts | 2 +- .../Ess/GridOptimizedCharge/flat/flat.ts | 21 +- .../Ess/GridOptimizedCharge/modal/modal.ts | 2 +- .../modal/predictionChart.ts | 43 +- .../Ess/TimeOfUseTariff/flat/flat.ts | 2 +- .../Ess/TimeOfUseTariff/modal/modal.ts | 2 +- .../TimeOfUseTariff/modal/powerSocChart.ts | 53 +- .../TimeOfUseTariff/modal/statePriceChart.ts | 40 +- .../administration.component.ts | 4 +- .../edge/live/Controller/Evcs/flat/flat.ts | 33 +- .../edge/live/Controller/Evcs/modal/modal.ts | 85 +- .../live/Controller/Evcs/popover/popover.ts | 2 +- .../Io_ChannelSingleThreshold.ts | 32 +- .../modal/modal.component.ts | 85 +- .../FixDigitalOutput/Io_FixDigitalOutput.ts | 29 +- .../Controller/Io/HeatingElement/flat/flat.ts | 23 +- .../Io/HeatingElement/modal/modal.ts | 25 +- .../Controller/Io/Heatpump/Io_Heatpump.ts | 38 +- .../PeakShaving/Asymmetric/Asymmetric.ts | 25 +- .../PeakShaving/Symmetric/Symmetric.ts | 23 +- .../Symmetric_TimeSlot/Symmetric_TimeSlot.ts | 34 +- .../modal/modal.component.ts | 4 +- .../Api_DigitalInput/Io_Api_DigitalInput.ts | 16 +- .../Evcs_Api_Cluster/Evcs_Api_Cluster.ts | 27 +- .../modal/evcs-chart/evcs.chart.ts | 27 +- .../modal/evcsCluster-modal.page.ts | 6 +- .../edge/live/common/autarchy/flat/flat.ts | 16 +- .../live/common/autarchy/modal/modal.spec.ts | 6 +- .../edge/live/common/autarchy/modal/modal.ts | 11 +- .../edge/live/common/consumption/flat/flat.ts | 15 +- .../consumption/modal/modal.constants.spec.ts | 6 +- .../common/consumption/modal/modal.spec.ts | 8 +- .../live/common/consumption/modal/modal.ts | 21 +- .../app/edge/live/common/grid/flat/flat.html | 7 +- ui/src/app/edge/live/common/grid/flat/flat.ts | 38 +- .../live/common/grid/modal/constants.spec.ts | 5 +- .../edge/live/common/grid/modal/modal.spec.ts | 13 +- .../app/edge/live/common/grid/modal/modal.ts | 73 +- .../edge/live/common/production/flat/flat.ts | 15 +- .../live/common/production/modal/modal.ts | 2 +- .../live/common/selfconsumption/flat/flat.ts | 15 +- .../selfconsumption/modal/modal.spec.ts | 6 +- .../common/selfconsumption/modal/modal.ts | 11 +- .../live/common/storage/storage.component.ts | 165 +- .../modal/modal.component.ts | 2 +- .../energymonitor/chart/chart.component.ts | 19 +- .../section/abstractsection.component.ts | 211 +- .../chart/section/consumption.component.ts | 11 +- .../chart/section/grid.component.ts | 93 +- .../chart/section/production.component.ts | 15 +- .../chart/section/storage.component.ts | 133 +- .../energymonitor/energymonitor.component.ts | 11 +- ui/src/app/edge/live/live.component.ts | 5 +- ui/src/app/edge/live/livedataservice.ts | 4 +- .../settings/alerting/alerting.component.ts | 205 +- .../formly-option-group-picker.component.ts | 58 +- .../formly-reorder-array.component.ts | 32 +- .../safe-input/formly-safe-input.extended.ts | 36 +- .../app/edge/settings/app/index.component.ts | 219 +- .../edge/settings/app/install.component.ts | 50 +- .../edge/settings/app/jsonrpc/flag/flag.ts | 2 +- .../app/jsonrpc/getAppAssistant.spec.ts | 2 +- .../settings/app/jsonrpc/getAppAssistant.ts | 2 +- .../settings/app/keypopup/modal.component.ts | 331 +- ui/src/app/edge/settings/app/permissions.ts | 7 - .../app/edge/settings/app/single.component.ts | 78 +- .../app/edge/settings/app/update.component.ts | 3 +- .../settings/channels/channels.component.ts | 66 +- .../component/install/index.component.ts | 41 +- .../component/update/index.component.ts | 2 +- .../jsonrpctest/jsonrpctest.module.ts | 16 + .../jsonrpctest/jsonrpctest.permission.ts | 11 + .../edge/settings/jsonrpctest/jsonrpctest.ts | 2 +- .../edge/settings/jsonrpctest/permission.ts | 7 - .../settings/network/network.component.ts | 63 +- .../powerassistant/powerassistant.html | 53 + .../powerassistant/powerassistant.module.ts | 16 + .../settings/powerassistant/powerassistant.ts | 244 + .../settings/profile/aliasupdate.component.ts | 4 +- .../settings/profile/profile.component.ts | 2 +- .../app/edge/settings/settings.component.html | 283 +- .../app/edge/settings/settings.component.ts | 21 +- ui/src/app/edge/settings/settings.module.ts | 2 + ui/src/app/edge/settings/settings.spec.ts | 70 + .../settings/system/executeSystemUpdate.ts | 71 +- .../system/executesystemupdate.component.ts | 7 +- .../system/maintenance/maintenance.ts | 67 +- .../system/oe-system-update.component.ts | 22 +- .../systemexecute/systemexecute.component.ts | 10 +- .../settings/systemlog/systemlog.component.ts | 132 +- ui/src/app/index/login.component.ts | 45 +- .../app/index/overview/overview.component.ts | 100 +- ui/src/app/index/shared/sumState.ts | 2 +- .../abstracthistorywidget.ts | 0 .../chart/abstractHistoryChartOverview.ts | 13 +- .../chart/abstracthistorychart.html | 0 .../chart/abstracthistorychart.ts | 824 ++- .../chart/chart.constants.spec.ts | 0 .../chart/chart.constants.ts | 50 +- .../chart/chart.html | 0 .../shared/components/chart/chart.module.ts | 37 + .../chart/chart.ts | 32 +- .../shared/components/components.module.ts | 69 + .../components/edge/currentdata.spec.ts | 58 + .../{ => components}/edge/currentdata.ts | 61 +- .../shared/{ => components}/edge/edge.spec.ts | 11 +- .../app/shared/{ => components}/edge/edge.ts | 188 +- .../{ => components}/edge/edgeconfig.spec.ts | 27 +- .../{ => components}/edge/edgeconfig.ts | 433 +- .../edge/meter/currentVoltage/chart/chart.ts | 68 + .../currentVoltage.overview.html | 6 + .../currentVoltage/currentVoltage.overview.ts | 7 + .../currentVoltage/currentVoltageModule.ts | 39 + .../meter/electricity/modal.component.html | 0 .../edge/meter/electricity/modal.component.ts | 4 +- .../meter/esscharger/modal.component.html | 0 .../edge/meter/esscharger/modal.component.ts | 2 +- .../components/edge/meter/meter.module.ts | 38 + .../flat/abstract-flat-widget-line.ts | 75 +- .../flat/abstract-flat-widget.ts | 6 +- .../flat-widget-horizontal-line.html | 0 .../flat-widget-horizontal-line.ts | 0 .../flat-widget-line-item.html | 0 .../flat-widget-line-item.ts | 0 .../flat-widget-line/flat-widget-line.html | 0 .../flat/flat-widget-line/flat-widget-line.ts | 0 .../flat-widget-percentagebar.html | 0 .../flat-widget-percentagebar.ts | 0 .../flat/flat-widget.component.html | 0 .../flat/flat.html | 0 .../flat/flat.ts | 0 .../{ => components}/footer/footer.html | 0 .../shared/{ => components}/footer/footer.ts | 57 +- .../subnavigation}/footerNavigation.html | 2 +- .../subnavigation/footerNavigation.module.ts | 29 + .../footer/subnavigation}/footerNavigation.ts | 28 +- ...form-field-checkbox-hyperlink.wrapper.html | 0 .../form-field-checkbox-hyperlink.wrapper.ts | 0 .../form-field-default-cases.wrapper.ts | 0 .../formly/form-field.wrapper.html | 0 .../formly/form-field.wrapper.ts | 0 .../formly-field-checkbox-with-image.html | 0 .../formly-field-checkbox-with-image.ts | 0 .../formly-field-modal/formlyfieldmodal.html | 0 .../formly-field-modal/formlyfieldmodal.ts | 0 .../formly/formly-field-modal/template.html | 0 .../formly-field-radio-with-image.html | 0 .../formly-field-radio-with-image.ts | 0 .../formly-select-field-modal.component.html | 0 .../formly-select-field-modal.component.ts | 0 .../formly/formly-select-field.extended.html | 0 .../formly/formly-select-field.extended.ts | 0 .../formly/formly-skeleton-wrapper.ts | 0 .../formly/input-serial-number-wrapper.html | 0 .../formly/input-serial-number-wrapper.ts | 0 .../shared/{ => components}/formly/input.html | 0 .../shared/{ => components}/formly/input.ts | 0 .../formly/panel-wrapper.component.ts | 0 .../{ => components}/formly/repeat.html | 0 .../shared/{ => components}/formly/repeat.ts | 0 .../header/header.component.html | 0 .../header/header.component.ts | 2 +- .../history-data-error.component.ts | 0 .../history-data-error.module.ts | 24 + .../modal/abstract-modal-line.ts | 80 +- .../modal/abstractModal.ts | 38 +- .../modal/help-button/help-button.html | 0 .../modal/help-button/help-button.ts | 0 .../modal/modal-button/modal-button.html | 0 .../modal/modal-button/modal-button.ts | 0 .../modal-info-line/modal-info-line.html | 0 .../modal/modal-info-line/modal-info-line.ts | 3 +- .../modal-line-item/modal-line-item.html | 0 .../modal-line-item/modal-line-item.ts | 0 .../modal/modal-line/modal-line.html | 0 .../modal/modal-line/modal-line.ts | 10 +- .../modal/modal-phases/modal-phases.html | 0 .../modal/modal-phases/modal-phases.ts | 4 +- .../modal-value-line/modal-value-line.html | 0 .../modal-value-line/modal-value-line.ts | 21 +- .../modal/modal.html | 0 .../shared/components/modal/modal.module.ts | 53 + .../modal/modal.ts | 6 +- .../modal-horizontal-line.html | 0 .../modal-horizontal-line.ts | 0 .../percentagebar.component.html | 0 .../percentagebar/percentagebar.component.ts | 0 .../pickdate/pickdate.component.html | 0 .../pickdate/pickdate.component.spec.ts | 4 +- .../pickdate/pickdate.component.ts | 158 +- .../components/pickdate/pickdate.module.ts | 28 + .../pickdate/popover/popover.component.html | 2 +- .../pickdate/popover/popover.component.ts | 24 +- .../pickdate/popover/popover.spec.ts | 49 + .../shared/converter.ts | 20 +- .../shared/dataservice.ts | 6 +- .../shared/filter.ts | 0 .../shared/formatter.ts | 0 .../shared/name.ts | 0 .../shared/notification/notification.ts | 3 +- .../shared/oe-formly-component.ts | 0 .../shared/phase.ts | 0 .../shared/testing}/DummyModalController.ts | 0 .../components/shared/testing/common.ts | 116 + .../shared/testing/tester.ts | 4 +- .../shared/testing}/utils.spec.ts | 7 +- .../status/single/status.component.html | 0 .../status/single/status.component.spec.ts | 9 +- .../status/single/status.component.ts | 30 +- ui/src/app/shared/directive/directive.ts | 4 + ui/src/app/shared/directive/ngvar.ts | 21 +- ui/src/app/shared/edge/meter/meter.module.ts | 26 - .../genericComponents/genericComponents.ts | 95 - .../shared/testing/common.ts | 59 - ui/src/app/shared/jsonrpc/base.ts | 7 +- .../notification/edgeConfigNotification.ts | 2 +- .../getChannelsOfComponentResponse.ts | 2 +- .../jsonrpc/response/getEdgeResponse.ts | 2 +- .../jsonrpc/response/getEdgesResponse.ts | 2 +- .../getPropertiesOfFactoryResponse.ts | 2 +- .../chartoptions/chartoptions.component.html | 0 .../chartoptions/chartoptions.component.ts | 7 +- .../popover/popover.component.html | 0 .../chartoptions/popover/popover.component.ts | 2 +- .../formatSecondsToDuration.pipe.ts | 2 +- ui/src/app/shared/service/abstractservice.ts | 4 +- ui/src/app/shared/service/defaulttypes.ts | 86 +- ui/src/app/shared/service/logger.ts | 26 +- ui/src/app/shared/service/service.ts | 51 +- .../app/shared/service/test/dummyservice.ts | 6 +- ui/src/app/shared/service/utils.spec.ts | 45 +- ui/src/app/shared/service/utils.ts | 46 +- ui/src/app/shared/service/websocket.ts | 250 +- ui/src/app/shared/shared.module.ts | 52 +- ui/src/app/shared/shared.ts | 7 +- ui/src/app/shared/type/channeladdress.ts | 11 +- ui/src/app/shared/type/general.ts | 5 + ui/src/app/shared/type/language.ts | 17 +- ui/src/app/shared/type/widget.ts | 52 +- ui/src/assets/i18n/de.json | 17 +- ui/src/assets/i18n/en.json | 15 +- ui/src/assets/img/icon/gridRestriction.svg | 39 + ui/src/environments/index.ts | 4 + .../openems/environments/backend-docker.ts | 3 +- .../openems/environments/edge-docker.ts | 3 +- ui/src/themes/openems/environments/theme.ts | 4 + ui/tsconfig.json | 2 +- 590 files changed, 9575 insertions(+), 22664 deletions(-) create mode 100644 io.openems.backend.application/test/io/openems/backend/edge/application/TestClient.java create mode 100644 io.openems.backend.application/test/io/openems/backend/edge/application/WebsocketPerformanceTestApp.java create mode 100644 io.openems.backend.common/src/io/openems/backend/common/jsonrpc/request/GetEmsTypeRequest.java create mode 100644 io.openems.backend.common/src/io/openems/backend/common/jsonrpc/response/GetEmsTypeResponse.java create mode 100644 io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/DebugMode.java delete mode 100644 io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnClose.java delete mode 100644 io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnOpen.java delete mode 100644 io.openems.common/src/io/openems/common/websocket/DummyWsData.java create mode 100644 io.openems.common/src/io/openems/common/websocket/MyDraft6455.java create mode 100644 io.openems.common/src/io/openems/common/websocket/OnMessageHandler.java delete mode 100644 io.openems.common/src/io/openems/common/websocket/OnNotificationHandler.java delete mode 100644 io.openems.common/src/io/openems/common/websocket/OnRequestHandler.java delete mode 100644 io.openems.common/src/io/openems/common/websocket/OnResponseHandler.java delete mode 100644 io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnOpen.java rename {io.openems.edge.ess.mr.gridcon => io.openems.edge.controller.ess.limiter14a}/.classpath (100%) rename {io.openems.edge.ess.mr.gridcon => io.openems.edge.controller.ess.limiter14a}/.gitignore (100%) rename {io.openems.edge.ess.mr.gridcon => io.openems.edge.controller.ess.limiter14a}/.project (89%) rename {io.openems.edge.ess.mr.gridcon => io.openems.edge.controller.ess.limiter14a}/.settings/org.eclipse.core.resources.prefs (100%) rename {io.openems.edge.ess.mr.gridcon => io.openems.edge.controller.ess.limiter14a}/bnd.bnd (64%) create mode 100644 io.openems.edge.controller.ess.limiter14a/readme.adoc create mode 100644 io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/Config.java create mode 100644 io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/ControllerEssLimiter14a.java create mode 100644 io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/ControllerEssLimiter14aImpl.java create mode 100644 io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/RestrictionMode.java rename {io.openems.edge.ess.mr.gridcon => io.openems.edge.controller.ess.limiter14a}/test/.gitignore (100%) create mode 100644 io.openems.edge.controller.ess.limiter14a/test/io/openems/edge/controller/ess/limiter14a/ControllerEssLimiter14aTest.java create mode 100644 io.openems.edge.controller.ess.limiter14a/test/io/openems/edge/controller/ess/limiter14a/MyConfig.java create mode 100644 io.openems.edge.core/test/io/openems/edge/core/appmanager/OpenemsAppCategoryTest.java delete mode 100644 "io.openems.edge.ess.mr.gridcon/doc/Entscheidungstabelle_Zust\303\244nde_OnOffGrid_konsolidiert.xlsx" delete mode 100644 io.openems.edge.ess.mr.gridcon/doc/Fehlerliste.csv delete mode 100644 io.openems.edge.ess.mr.gridcon/doc/Fehlerliste.xlsx delete mode 100644 io.openems.edge.ess.mr.gridcon/doc/PQ-01-12-05-BA_Software-Manual-Anybus-GRIDCON-ACF_PCS_DE.pdf delete mode 100644 io.openems.edge.ess.mr.gridcon/doc/PQ-01-12-21-BA_Beriebsanleitung-Hardware-GRIDCON-ACF-Building_DE.pdf delete mode 100644 io.openems.edge.ess.mr.gridcon/doc/PQ-01-12-24-BA_Software-Manual-GRIDCON-PCS_DE.pdf delete mode 100644 io.openems.edge.ess.mr.gridcon/doc/PQ-01-13-00-PD_GRIDCON_PCS_3W_DE.pdf delete mode 100644 io.openems.edge.ess.mr.gridcon/doc/PQ-01-13-00-PD_PCS-4W_DE.pdf delete mode 100644 io.openems.edge.ess.mr.gridcon/doc/errordesc.txt delete mode 100644 io.openems.edge.ess.mr.gridcon/doc/handling_off_grid.xlsx delete mode 100644 io.openems.edge.ess.mr.gridcon/doc/mr_schematic_setup.jpg delete mode 100644 io.openems.edge.ess.mr.gridcon/doc/start0.png delete mode 100644 io.openems.edge.ess.mr.gridcon/doc/start1.png delete mode 100644 io.openems.edge.ess.mr.gridcon/doc/start2.png delete mode 100644 io.openems.edge.ess.mr.gridcon/readme.adoc delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/Config.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/EssGridcon.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/GridconPcs.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/GridconPcsImpl.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/GridconSettings.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/Helper.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/IState.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/StateController.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/StateObject.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/WeightingHelper.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/controller/balancing/Config.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/controller/balancing/ControllerMrSetBalancing.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/controller/balancing/ControllerMrSetBalancingImpl.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/controller/fundamentalfrequency/Config.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/controller/fundamentalfrequency/ControllerMrFundamentalFrequency.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/controller/fundamentalfrequency/ControllerMrFundamentalFrequencyImpl.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/enums/BalancingMode.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/enums/CcuState.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/enums/ErrorCodeChannelId0.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/enums/ErrorCodeChannelId1.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/enums/ErrorDoc.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/enums/FundamentalFrequencyMode.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/enums/GridConChannelId.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/enums/HarmonicCompensationMode.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/enums/InverterCount.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/enums/Mode.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/enums/PControlMode.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/enums/ParameterSet.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/enums/StatusIpuStateMachine.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/enums/StatusIpuStatusMcu.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/meter/Config.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/meter/MeterGridcon.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/meter/MeterGridconImpl.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/ongrid/Config.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/ongrid/MrGridconOngrid.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/ongrid/MrGridconOngridImpl.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/onoffgrid/Config.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/onoffgrid/MrGridconOnOffgrid.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/onoffgrid/MrGridconOnOffgridImpl.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/state/gridconstate/BaseState.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/state/gridconstate/Error.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/state/gridconstate/GridconState.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/state/gridconstate/GridconStateObject.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/state/gridconstate/Run.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/state/gridconstate/Stopped.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/state/gridconstate/Undefined.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/state/ongrid/BasteState.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/state/ongrid/Error.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/state/ongrid/OnGrid.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/state/ongrid/OnGridState.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/state/ongrid/Undefined.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/state/onoffgrid/AdjustParameter.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/state/onoffgrid/BaseState.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/state/onoffgrid/DecisionTableCondition.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/state/onoffgrid/DecisionTableConditionImpl.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/state/onoffgrid/DecisionTableHelper.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/state/onoffgrid/OffGrid.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/state/onoffgrid/OffGridGridBack.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/state/onoffgrid/OnGrid.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/state/onoffgrid/OnOffGridState.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/state/onoffgrid/StartSystem.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/state/onoffgrid/Undefined.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/state/onoffgrid/WaitForDevices.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/state/onoffgrid/WaitForGridAvailable.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/writewords/CcuParameters1.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/writewords/CcuParameters2.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/writewords/Commands.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/writewords/CosPhiParameters.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/writewords/DcDcParameter.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/writewords/HexFormatter.java delete mode 100644 io.openems.edge.ess.mr.gridcon/src/io/openems/edge/ess/mr/gridcon/writewords/IpuParameter.java delete mode 100644 io.openems.edge.ess.mr.gridcon/test/io/openems/edge/ess/mr/gridcon/WeightingHelperTest.java delete mode 100644 io.openems.edge.ess.mr.gridcon/test/io/openems/edge/ess/mr/gridcon/helper/DummyBattery.java delete mode 100644 io.openems.edge.ess.mr.gridcon/test/io/openems/edge/ess/mr/gridcon/helper/DummyEss.java delete mode 100644 io.openems.edge.ess.mr.gridcon/test/io/openems/edge/ess/mr/gridcon/ongrid/state/TestUndefined.java create mode 100644 ui/src/app/edge/history/Controller/Ess/GridoptimizedCharge/chart/chart.ts create mode 100644 ui/src/app/edge/history/Controller/Ess/GridoptimizedCharge/chart/sellToGridLimitChart.component.ts create mode 100644 ui/src/app/edge/history/Controller/Ess/GridoptimizedCharge/flat/flat.html create mode 100644 ui/src/app/edge/history/Controller/Ess/GridoptimizedCharge/flat/flat.ts create mode 100644 ui/src/app/edge/history/Controller/Ess/GridoptimizedCharge/gridOptimizeCharge.module.ts create mode 100644 ui/src/app/edge/history/Controller/Ess/GridoptimizedCharge/overview/overview.html create mode 100644 ui/src/app/edge/history/Controller/Ess/GridoptimizedCharge/overview/overview.ts create mode 100644 ui/src/app/edge/history/common/consumption/details/chart/chart.ts create mode 100644 ui/src/app/edge/history/common/consumption/details/details.overview.html create mode 100644 ui/src/app/edge/history/common/consumption/details/details.overview.ts create mode 100644 ui/src/app/edge/history/common/storage/overview/overview.html delete mode 100644 ui/src/app/edge/history/grid/chart.component.ts delete mode 100644 ui/src/app/edge/history/gridoptimizedcharge/chart.component.ts delete mode 100644 ui/src/app/edge/history/gridoptimizedcharge/gridoptimizedchargechartoverview/gridoptimizedchargechartoverview.component.html delete mode 100644 ui/src/app/edge/history/gridoptimizedcharge/gridoptimizedchargechartoverview/gridoptimizedchargechartoverview.component.ts delete mode 100644 ui/src/app/edge/history/gridoptimizedcharge/sellToGridLimitChart.component.ts delete mode 100644 ui/src/app/edge/history/gridoptimizedcharge/widget.component.html delete mode 100644 ui/src/app/edge/history/gridoptimizedcharge/widget.component.ts create mode 100644 ui/src/app/edge/settings/jsonrpctest/jsonrpctest.module.ts create mode 100644 ui/src/app/edge/settings/jsonrpctest/jsonrpctest.permission.ts delete mode 100644 ui/src/app/edge/settings/jsonrpctest/permission.ts create mode 100644 ui/src/app/edge/settings/powerassistant/powerassistant.html create mode 100644 ui/src/app/edge/settings/powerassistant/powerassistant.module.ts create mode 100644 ui/src/app/edge/settings/powerassistant/powerassistant.ts create mode 100644 ui/src/app/edge/settings/settings.spec.ts rename ui/src/app/shared/{genericComponents => components}/abstracthistorywidget.ts (100%) rename ui/src/app/shared/{genericComponents => components}/chart/abstractHistoryChartOverview.ts (97%) rename ui/src/app/shared/{genericComponents => components}/chart/abstracthistorychart.html (100%) rename ui/src/app/shared/{genericComponents => components}/chart/abstracthistorychart.ts (87%) rename ui/src/app/shared/{genericComponents => components}/chart/chart.constants.spec.ts (100%) rename ui/src/app/shared/{genericComponents => components}/chart/chart.constants.ts (53%) rename ui/src/app/shared/{genericComponents => components}/chart/chart.html (100%) create mode 100644 ui/src/app/shared/components/chart/chart.module.ts rename ui/src/app/shared/{genericComponents => components}/chart/chart.ts (96%) create mode 100644 ui/src/app/shared/components/components.module.ts create mode 100644 ui/src/app/shared/components/edge/currentdata.spec.ts rename ui/src/app/shared/{ => components}/edge/currentdata.ts (90%) rename ui/src/app/shared/{ => components}/edge/edge.spec.ts (86%) rename ui/src/app/shared/{ => components}/edge/edge.ts (86%) rename ui/src/app/shared/{ => components}/edge/edgeconfig.spec.ts (94%) rename ui/src/app/shared/{ => components}/edge/edgeconfig.ts (99%) create mode 100644 ui/src/app/shared/components/edge/meter/currentVoltage/chart/chart.ts create mode 100644 ui/src/app/shared/components/edge/meter/currentVoltage/currentVoltage.overview.html create mode 100644 ui/src/app/shared/components/edge/meter/currentVoltage/currentVoltage.overview.ts create mode 100644 ui/src/app/shared/components/edge/meter/currentVoltage/currentVoltageModule.ts rename ui/src/app/shared/{ => components}/edge/meter/electricity/modal.component.html (100%) rename ui/src/app/shared/{ => components}/edge/meter/electricity/modal.component.ts (90%) rename ui/src/app/shared/{ => components}/edge/meter/esscharger/modal.component.html (100%) rename ui/src/app/shared/{ => components}/edge/meter/esscharger/modal.component.ts (86%) create mode 100644 ui/src/app/shared/components/edge/meter/meter.module.ts rename ui/src/app/shared/{genericComponents => components}/flat/abstract-flat-widget-line.ts (91%) rename ui/src/app/shared/{genericComponents => components}/flat/abstract-flat-widget.ts (100%) rename ui/src/app/shared/{genericComponents => components}/flat/flat-widget-horizontal-line/flat-widget-horizontal-line.html (100%) rename ui/src/app/shared/{genericComponents => components}/flat/flat-widget-horizontal-line/flat-widget-horizontal-line.ts (100%) rename ui/src/app/shared/{genericComponents => components}/flat/flat-widget-line/flat-widget-line-item/flat-widget-line-item.html (100%) rename ui/src/app/shared/{genericComponents => components}/flat/flat-widget-line/flat-widget-line-item/flat-widget-line-item.ts (100%) rename ui/src/app/shared/{genericComponents => components}/flat/flat-widget-line/flat-widget-line.html (100%) rename ui/src/app/shared/{genericComponents => components}/flat/flat-widget-line/flat-widget-line.ts (100%) rename ui/src/app/shared/{genericComponents => components}/flat/flat-widget-percentagebar/flat-widget-percentagebar.html (100%) rename ui/src/app/shared/{genericComponents => components}/flat/flat-widget-percentagebar/flat-widget-percentagebar.ts (100%) rename ui/src/app/shared/{genericComponents => components}/flat/flat-widget.component.html (100%) rename ui/src/app/shared/{genericComponents => components}/flat/flat.html (100%) rename ui/src/app/shared/{genericComponents => components}/flat/flat.ts (100%) rename ui/src/app/shared/{ => components}/footer/footer.html (100%) rename ui/src/app/shared/{ => components}/footer/footer.ts (92%) rename ui/src/app/shared/{genericComponents/footer-navigation => components/footer/subnavigation}/footerNavigation.html (99%) create mode 100644 ui/src/app/shared/components/footer/subnavigation/footerNavigation.module.ts rename ui/src/app/shared/{genericComponents/footer-navigation => components/footer/subnavigation}/footerNavigation.ts (92%) rename ui/src/app/shared/{ => components}/formly/form-field-checkbox-hyperlink/form-field-checkbox-hyperlink.wrapper.html (100%) rename ui/src/app/shared/{ => components}/formly/form-field-checkbox-hyperlink/form-field-checkbox-hyperlink.wrapper.ts (100%) rename ui/src/app/shared/{ => components}/formly/form-field-default-cases.wrapper.ts (100%) rename ui/src/app/shared/{ => components}/formly/form-field.wrapper.html (100%) rename ui/src/app/shared/{ => components}/formly/form-field.wrapper.ts (100%) rename ui/src/app/shared/{ => components}/formly/formly-field-checkbox-image/formly-field-checkbox-with-image.html (100%) rename ui/src/app/shared/{ => components}/formly/formly-field-checkbox-image/formly-field-checkbox-with-image.ts (100%) rename ui/src/app/shared/{ => components}/formly/formly-field-modal/formlyfieldmodal.html (100%) rename ui/src/app/shared/{ => components}/formly/formly-field-modal/formlyfieldmodal.ts (100%) rename ui/src/app/shared/{ => components}/formly/formly-field-modal/template.html (100%) rename ui/src/app/shared/{ => components}/formly/formly-field-radio-with-image/formly-field-radio-with-image.html (100%) rename ui/src/app/shared/{ => components}/formly/formly-field-radio-with-image/formly-field-radio-with-image.ts (100%) rename ui/src/app/shared/{ => components}/formly/formly-select-field-modal.component.html (100%) rename ui/src/app/shared/{ => components}/formly/formly-select-field-modal.component.ts (100%) rename ui/src/app/shared/{ => components}/formly/formly-select-field.extended.html (100%) rename ui/src/app/shared/{ => components}/formly/formly-select-field.extended.ts (100%) rename ui/src/app/shared/{ => components}/formly/formly-skeleton-wrapper.ts (100%) rename ui/src/app/shared/{ => components}/formly/input-serial-number-wrapper.html (100%) rename ui/src/app/shared/{ => components}/formly/input-serial-number-wrapper.ts (100%) rename ui/src/app/shared/{ => components}/formly/input.html (100%) rename ui/src/app/shared/{ => components}/formly/input.ts (100%) rename ui/src/app/shared/{ => components}/formly/panel-wrapper.component.ts (100%) rename ui/src/app/shared/{ => components}/formly/repeat.html (100%) rename ui/src/app/shared/{ => components}/formly/repeat.ts (100%) rename ui/src/app/shared/{ => components}/header/header.component.html (100%) rename ui/src/app/shared/{ => components}/header/header.component.ts (99%) rename ui/src/app/shared/{ => components/history-data-error}/history-data-error.component.ts (100%) create mode 100644 ui/src/app/shared/components/history-data-error/history-data-error.module.ts rename ui/src/app/shared/{genericComponents => components}/modal/abstract-modal-line.ts (99%) rename ui/src/app/shared/{genericComponents => components}/modal/abstractModal.ts (100%) rename ui/src/app/shared/{genericComponents => components}/modal/help-button/help-button.html (100%) rename ui/src/app/shared/{genericComponents => components}/modal/help-button/help-button.ts (100%) rename ui/src/app/shared/{genericComponents => components}/modal/modal-button/modal-button.html (100%) rename ui/src/app/shared/{genericComponents => components}/modal/modal-button/modal-button.ts (100%) rename ui/src/app/shared/{genericComponents => components}/modal/modal-info-line/modal-info-line.html (100%) rename ui/src/app/shared/{genericComponents => components}/modal/modal-info-line/modal-info-line.ts (99%) rename ui/src/app/shared/{genericComponents => components}/modal/modal-line/modal-line-item/modal-line-item.html (100%) rename ui/src/app/shared/{genericComponents => components}/modal/modal-line/modal-line-item/modal-line-item.ts (100%) rename ui/src/app/shared/{genericComponents => components}/modal/modal-line/modal-line.html (100%) rename ui/src/app/shared/{genericComponents => components}/modal/modal-line/modal-line.ts (90%) rename ui/src/app/shared/{genericComponents => components}/modal/modal-phases/modal-phases.html (100%) rename ui/src/app/shared/{genericComponents => components}/modal/modal-phases/modal-phases.ts (100%) rename ui/src/app/shared/{genericComponents => components}/modal/modal-value-line/modal-value-line.html (100%) rename ui/src/app/shared/{genericComponents => components}/modal/modal-value-line/modal-value-line.ts (94%) rename ui/src/app/shared/{genericComponents => components}/modal/modal.html (100%) create mode 100644 ui/src/app/shared/components/modal/modal.module.ts rename ui/src/app/shared/{genericComponents => components}/modal/modal.ts (100%) rename ui/src/app/shared/{genericComponents => components}/modal/model-horizontal-line/modal-horizontal-line.html (100%) rename ui/src/app/shared/{genericComponents => components}/modal/model-horizontal-line/modal-horizontal-line.ts (100%) rename ui/src/app/shared/{ => components}/percentagebar/percentagebar.component.html (100%) rename ui/src/app/shared/{ => components}/percentagebar/percentagebar.component.ts (100%) rename ui/src/app/shared/{ => components}/pickdate/pickdate.component.html (100%) rename ui/src/app/shared/{ => components}/pickdate/pickdate.component.spec.ts (98%) rename ui/src/app/shared/{ => components}/pickdate/pickdate.component.ts (97%) create mode 100644 ui/src/app/shared/components/pickdate/pickdate.module.ts rename ui/src/app/shared/{ => components}/pickdate/popover/popover.component.html (96%) rename ui/src/app/shared/{ => components}/pickdate/popover/popover.component.ts (96%) create mode 100644 ui/src/app/shared/components/pickdate/popover/popover.spec.ts rename ui/src/app/shared/{genericComponents => components}/shared/converter.ts (87%) rename ui/src/app/shared/{genericComponents => components}/shared/dataservice.ts (100%) rename ui/src/app/shared/{genericComponents => components}/shared/filter.ts (100%) rename ui/src/app/shared/{genericComponents => components}/shared/formatter.ts (100%) rename ui/src/app/shared/{genericComponents => components}/shared/name.ts (100%) rename ui/src/app/shared/{genericComponents => components}/shared/notification/notification.ts (99%) rename ui/src/app/shared/{genericComponents => components}/shared/oe-formly-component.ts (100%) rename ui/src/app/shared/{genericComponents => components}/shared/phase.ts (100%) rename ui/src/app/shared/{test => components/shared/testing}/DummyModalController.ts (100%) create mode 100644 ui/src/app/shared/components/shared/testing/common.ts rename ui/src/app/shared/{genericComponents => components}/shared/testing/tester.ts (98%) rename ui/src/app/shared/{test => components/shared/testing}/utils.spec.ts (89%) rename ui/src/app/shared/{ => components}/status/single/status.component.html (100%) rename ui/src/app/shared/{ => components}/status/single/status.component.spec.ts (90%) rename ui/src/app/shared/{ => components}/status/single/status.component.ts (91%) delete mode 100644 ui/src/app/shared/edge/meter/meter.module.ts delete mode 100644 ui/src/app/shared/genericComponents/genericComponents.ts delete mode 100644 ui/src/app/shared/genericComponents/shared/testing/common.ts rename ui/src/app/shared/{ => legacy}/chartoptions/chartoptions.component.html (100%) rename ui/src/app/shared/{ => legacy}/chartoptions/chartoptions.component.ts (97%) rename ui/src/app/shared/{ => legacy}/chartoptions/popover/popover.component.html (100%) rename ui/src/app/shared/{ => legacy}/chartoptions/popover/popover.component.ts (95%) create mode 100644 ui/src/assets/img/icon/gridRestriction.svg diff --git a/io.openems.backend.application/test/io/openems/backend/edge/application/TestClient.java b/io.openems.backend.application/test/io/openems/backend/edge/application/TestClient.java new file mode 100644 index 00000000000..c6030384134 --- /dev/null +++ b/io.openems.backend.application/test/io/openems/backend/edge/application/TestClient.java @@ -0,0 +1,122 @@ +package io.openems.backend.edge.application; + +import java.net.URI; +import java.util.Map; + +import org.java_websocket.WebSocket; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.openems.common.websocket.AbstractWebsocketClient; +import io.openems.common.websocket.OnClose; +import io.openems.common.websocket.OnError; +import io.openems.common.websocket.OnNotification; +import io.openems.common.websocket.OnOpen; +import io.openems.common.websocket.OnRequest; +import io.openems.common.websocket.WsData; + +public class TestClient extends AbstractWebsocketClient { + + private final Logger log = LoggerFactory.getLogger(TestClient.class); + + private OnOpen onOpen; + private OnRequest onRequest; + private OnNotification onNotification; + private OnError onError; + private OnClose onClose; + + protected TestClient(URI serverUri, Map httpHeaders) { + super("WebsocketPerformanceTestApp", serverUri, httpHeaders); + this.onOpen = (ws, handshake) -> { + return null; + }; + this.onRequest = (ws, request) -> { + this.log.info("OnRequest: " + request); + return null; + }; + this.onNotification = (ws, notification) -> { + this.log.info("OnNotification: " + notification); + }; + this.onError = (ws, ex) -> { + this.log.info("onError: " + ex.getMessage()); + }; + this.onClose = (ws, code, reason, remote) -> { + this.log.info("onClose: " + reason); + }; + } + + @Override + public OnOpen getOnOpen() { + return this.onOpen; + } + + public void setOnOpen(OnOpen onOpen) { + this.onOpen = onOpen; + } + + @Override + public OnRequest getOnRequest() { + return this.onRequest; + } + + public void setOnRequest(OnRequest onRequest) { + this.onRequest = onRequest; + } + + @Override + public OnError getOnError() { + return this.onError; + } + + public void setOnError(OnError onError) { + this.onError = onError; + } + + @Override + public OnClose getOnClose() { + return this.onClose; + } + + public void setOnClose(OnClose onClose) { + this.onClose = onClose; + } + + @Override + protected OnNotification getOnNotification() { + return this.onNotification; + } + + public void setOnNotification(OnNotification onNotification) { + this.onNotification = onNotification; + } + + @Override + protected WsData createWsData(WebSocket ws) { + return new WsData(ws) { + @Override + public String toString() { + return "TestClient.WsData []"; + } + }; + } + + @Override + protected void logInfo(Logger log, String message) { + log.info(message); + } + + @Override + protected void logWarn(Logger log, String message) { + log.warn(message); + } + + @Override + protected void logError(Logger log, String message) { + log.error(message); + } + + @Override + protected void execute(Runnable command) { + command.run(); + } +} diff --git a/io.openems.backend.application/test/io/openems/backend/edge/application/WebsocketPerformanceTestApp.java b/io.openems.backend.application/test/io/openems/backend/edge/application/WebsocketPerformanceTestApp.java new file mode 100644 index 00000000000..322fa365c86 --- /dev/null +++ b/io.openems.backend.application/test/io/openems/backend/edge/application/WebsocketPerformanceTestApp.java @@ -0,0 +1,77 @@ +package io.openems.backend.edge.application; + +import java.net.URI; +import java.net.URISyntaxException; +import java.time.Instant; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Executors; + +import com.google.common.collect.TreeBasedTable; +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; + +import io.openems.common.jsonrpc.notification.EdgeConfigNotification; +import io.openems.common.jsonrpc.notification.TimestampedDataNotification; +import io.openems.common.types.EdgeConfig; + +public class WebsocketPerformanceTestApp { + + /** + * Main. + * + * @param args args + * @throws URISyntaxException on error + * @throws InterruptedException on error + */ + public static void main(String[] args) throws URISyntaxException, InterruptedException { + final var executor = Executors.newCachedThreadPool(); + + for (var i = 0; i < 10000; i++) { + var client = prepareTestClient(String.format("edge%d", i)); + executor.execute(() -> { + client.sendMessage(new EdgeConfigNotification(EdgeConfig.empty())); + for (var j = 0; j < 1000; j++) { + sleep(1000); + if (j % 100 == 0) { + System.out.println("."); + } + client.sendMessage(buildDummyData()); + } + }); + } + } + + private static TestClient prepareTestClient(String edgeId) { + try { + Map httpHeaders = new HashMap<>(); + httpHeaders.put("apikey", edgeId); + var client = new TestClient(new URI("ws://localhost:8081"), httpHeaders); + client.startBlocking(); + return client; + + } catch (URISyntaxException | InterruptedException e) { + e.printStackTrace(); + System.exit(1); + return null; + } + } + + private static void sleep(long millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException e) { + e.printStackTrace(); + System.exit(1); + } + } + + private static TimestampedDataNotification buildDummyData() { + var timestamp = Instant.now().toEpochMilli(); + var table = TreeBasedTable.create(); + for (var i = 0; i < 100; i++) { + table.put(timestamp, String.format("channel%d", i), new JsonPrimitive(i)); + } + return new TimestampedDataNotification(table); + } +} diff --git a/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/Backend2BackendWebsocket.java b/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/Backend2BackendWebsocket.java index 4e90e76af80..2ac5a5dad70 100644 --- a/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/Backend2BackendWebsocket.java +++ b/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/Backend2BackendWebsocket.java @@ -88,8 +88,7 @@ private void deactivate() { */ private synchronized void startServer() { if (this.server == null) { - this.server = new WebsocketServer(this, this.getName(), this.config.port(), this.config.poolSize(), - this.config.debugMode()); + this.server = new WebsocketServer(this, this.getName(), this.config.port(), this.config.poolSize()); this.server.start(); } } diff --git a/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/Config.java b/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/Config.java index 5e6f2e71f8e..1ae6982dddb 100644 --- a/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/Config.java +++ b/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/Config.java @@ -3,8 +3,6 @@ import org.osgi.service.metatype.annotations.AttributeDefinition; import org.osgi.service.metatype.annotations.ObjectClassDefinition; -import io.openems.common.websocket.AbstractWebsocketServer.DebugMode; - @ObjectClassDefinition(// name = "Backend2Backend.Websocket", // description = "Provides a websocket server for backend-to-backend communication.") @@ -16,9 +14,5 @@ @AttributeDefinition(name = "Number of Threads", description = "Pool-Size: the number of threads dedicated to handle the tasks") int poolSize() default 10; - @AttributeDefinition(name = "Debug Mode", description = "Activates the debug mode") - DebugMode debugMode() default DebugMode.OFF; - String webconsole_configurationFactory_nameHint() default "Backend2Backend Websocket"; - } \ No newline at end of file diff --git a/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/OnClose.java b/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/OnClose.java index a7aa0411459..9c464da3f7d 100644 --- a/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/OnClose.java +++ b/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/OnClose.java @@ -4,8 +4,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.openems.common.exceptions.OpenemsException; - public class OnClose implements io.openems.common.websocket.OnClose { private final Logger log = LoggerFactory.getLogger(OnClose.class); @@ -16,7 +14,7 @@ public OnClose(Backend2BackendWebsocket parent) { } @Override - public void run(WebSocket ws, int code, String reason, boolean remote) throws OpenemsException { + public void accept(WebSocket ws, int code, String reason, boolean remote) { WsData wsData = ws.getAttachment(); var user = wsData.getUserOpt(); if (user.isPresent()) { diff --git a/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/OnError.java b/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/OnError.java index 053511987df..46b79cc67b3 100644 --- a/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/OnError.java +++ b/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/OnError.java @@ -16,7 +16,7 @@ public OnError(Backend2BackendWebsocket parent) { } @Override - public void run(WebSocket ws, Exception ex) throws OpenemsException { + public void accept(WebSocket ws, Exception ex) throws OpenemsException { this.parent.logInfo(this.log, "Error: " + ex.getMessage()); } diff --git a/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/OnNotification.java b/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/OnNotification.java index 09704e2c8c5..78755848fe1 100644 --- a/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/OnNotification.java +++ b/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/OnNotification.java @@ -17,7 +17,7 @@ public OnNotification(Backend2BackendWebsocket parent) { } @Override - public void run(WebSocket ws, JsonrpcNotification notification) throws OpenemsException { + public void accept(WebSocket ws, JsonrpcNotification notification) throws OpenemsException { this.parent.logWarn(this.log, "Unhandled Notification: " + notification); } diff --git a/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/OnOpen.java b/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/OnOpen.java index 0eaa5d3ccc0..bb585cfcd0e 100644 --- a/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/OnOpen.java +++ b/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/OnOpen.java @@ -1,57 +1,78 @@ package io.openems.backend.b2bwebsocket; +import static io.openems.common.websocket.WebsocketUtils.getAsString; + import java.nio.charset.StandardCharsets; import java.util.Base64; +import java.util.function.BiConsumer; +import java.util.function.Supplier; import org.java_websocket.WebSocket; +import org.java_websocket.handshake.Handshakedata; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.gson.JsonObject; - +import io.openems.backend.common.metadata.Metadata; +import io.openems.backend.common.metadata.User; import io.openems.common.exceptions.OpenemsError; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.utils.JsonUtils; public class OnOpen implements io.openems.common.websocket.OnOpen { private final Logger log = LoggerFactory.getLogger(OnClose.class); - private final Backend2BackendWebsocket parent; + private final Supplier metadata; + private final BiConsumer logInfo; - public OnOpen(Backend2BackendWebsocket parent) { - this.parent = parent; + public OnOpen(// + Supplier metadata, // + BiConsumer logInfo) { + this.metadata = metadata; + this.logInfo = logInfo; } @Override - public void run(WebSocket ws, JsonObject handshake) throws OpenemsNamedException { - try { - // Read "Authorization" header for Simple HTTP authentication. Source: - // https://stackoverflow.com/questions/16000517/how-to-get-password-from-http-basic-authentication - final var authorization = JsonUtils.getAsString(handshake, "authorization"); - if (authorization == null || !authorization.toLowerCase().startsWith("basic")) { - throw OpenemsError.COMMON_AUTHENTICATION_FAILED.exception(); - } - - var base64Credentials = authorization.substring("Basic".length()).trim(); - var credDecoded = Base64.getDecoder().decode(base64Credentials); - var credentials = new String(credDecoded, StandardCharsets.UTF_8); - // credentials = username:password - final var values = credentials.split(":", 2); - if (values.length != 2) { - throw OpenemsError.COMMON_AUTHENTICATION_FAILED.exception(); - } - var username = values[0]; - var password = values[1]; - var user = this.parent.metadata.authenticate(username, password); - - WsData wsData = ws.getAttachment(); - wsData.setUser(user); - this.parent.logInfo(this.log, "User [" + user.getName() + "] logged in"); + public OpenemsError apply(WebSocket ws, Handshakedata handshakedata) { + var error = this._apply(ws, handshakedata); + if (error != null) { + ws.close(); + } + return error; + } + + private OpenemsError _apply(WebSocket ws, Handshakedata handshakedata) { + // Read "Authorization" header for Simple HTTP authentication. Source: + // https://stackoverflow.com/questions/16000517/how-to-get-password-from-http-basic-authentication + final var authorization = getAsString(handshakedata, "authorization"); + if (authorization == null || !authorization.toLowerCase().startsWith("basic")) { + return OpenemsError.COMMON_AUTHENTICATION_FAILED; + } + var base64Credentials = authorization.substring("Basic".length()).trim(); + var credDecoded = Base64.getDecoder().decode(base64Credentials); + var credentials = new String(credDecoded, StandardCharsets.UTF_8); + // credentials = username:password + final var values = credentials.split(":", 2); + if (values.length != 2) { + return OpenemsError.COMMON_AUTHENTICATION_FAILED; + } + var username = values[0]; + var password = values[1]; + final var metadata = this.metadata.get(); + if (metadata == null) { + return OpenemsError.COMMON_SERVICE_NOT_AVAILABLE; + } + User user; + try { + user = this.metadata.get().authenticate(username, password); } catch (OpenemsNamedException e) { - ws.close(); - throw e; + return OpenemsError.COMMON_AUTHENTICATION_FAILED; } + + WsData wsData = ws.getAttachment(); + wsData.setUser(user); + this.logInfo.accept(this.log, "User [" + user.getName() + "] logged in"); + + return null; // No error } } diff --git a/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/OnRequest.java b/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/OnRequest.java index 4343d72c388..5869c0f6356 100644 --- a/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/OnRequest.java +++ b/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/OnRequest.java @@ -24,7 +24,7 @@ public OnRequest(Backend2BackendWebsocket parent) { } @Override - public CompletableFuture run(WebSocket ws, JsonrpcRequest request) + public CompletableFuture apply(WebSocket ws, JsonrpcRequest request) throws OpenemsException, OpenemsNamedException { WsData wsData = ws.getAttachment(); var user = wsData.getUserWithTimeout(5, TimeUnit.SECONDS); diff --git a/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/SubscribedEdgesChannelsWorker.java b/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/SubscribedEdgesChannelsWorker.java index 276192f8e73..619b716c54d 100644 --- a/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/SubscribedEdgesChannelsWorker.java +++ b/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/SubscribedEdgesChannelsWorker.java @@ -12,6 +12,7 @@ import io.openems.backend.b2bwebsocket.jsonrpc.notification.EdgesCurrentDataNotification; import io.openems.backend.b2bwebsocket.jsonrpc.request.SubscribeEdgesChannelsRequest; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.jsonrpc.base.JsonrpcNotification; import io.openems.common.session.Role; import io.openems.common.types.ChannelAddress; @@ -93,12 +94,16 @@ private synchronized void updateSubscription(Set edgeIds, Set { private final OnError onError; private final OnClose onClose; - public WebsocketServer(Backend2BackendWebsocket parent, String name, int port, int poolSize, DebugMode debugMode) { - super(name, port, poolSize, debugMode); + public WebsocketServer(Backend2BackendWebsocket parent, String name, int port, int poolSize) { + super(name, port, poolSize); this.parent = parent; - this.onOpen = new OnOpen(parent); + this.onOpen = new OnOpen(// + () -> parent.metadata, // + this::logInfo); this.onRequest = new OnRequest(parent); this.onNotification = new OnNotification(parent); this.onError = new OnError(parent); @@ -24,8 +27,8 @@ public WebsocketServer(Backend2BackendWebsocket parent, String name, int port, i } @Override - protected WsData createWsData() { - return new WsData(this.parent); + protected WsData createWsData(WebSocket ws) { + return new WsData(ws, this.parent); } @Override diff --git a/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/WsData.java b/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/WsData.java index 501de1925fb..24298d8c0f2 100644 --- a/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/WsData.java +++ b/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/WsData.java @@ -6,6 +6,8 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.java_websocket.WebSocket; + import io.openems.backend.common.metadata.User; import io.openems.common.exceptions.OpenemsError; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; @@ -15,7 +17,8 @@ public class WsData extends io.openems.common.websocket.WsData { private final SubscribedEdgesChannelsWorker worker; private final CompletableFuture user = new CompletableFuture<>(); - public WsData(Backend2BackendWebsocket parent) { + public WsData(WebSocket ws, Backend2BackendWebsocket parent) { + super(ws); this.worker = new SubscribedEdgesChannelsWorker(parent, this); } diff --git a/io.openems.backend.b2bwebsocket/test/io/openems/backend/b2bwebsocket/B2bWebsocketTest.java b/io.openems.backend.b2bwebsocket/test/io/openems/backend/b2bwebsocket/B2bWebsocketTest.java index b56f303d50c..cfb62d7d473 100644 --- a/io.openems.backend.b2bwebsocket/test/io/openems/backend/b2bwebsocket/B2bWebsocketTest.java +++ b/io.openems.backend.b2bwebsocket/test/io/openems/backend/b2bwebsocket/B2bWebsocketTest.java @@ -13,7 +13,6 @@ import io.openems.backend.b2bwebsocket.jsonrpc.request.SubscribeEdgesChannelsRequest; import io.openems.backend.common.jsonrpc.request.GetEdgesChannelsValuesRequest; import io.openems.backend.common.jsonrpc.request.GetEdgesStatusRequest; -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.jsonrpc.request.EdgeRpcRequest; import io.openems.common.jsonrpc.request.GetEdgeConfigRequest; import io.openems.common.jsonrpc.request.SetGridConnScheduleRequest; @@ -51,7 +50,7 @@ public void getEdgesStatusRequest() throws Exception { try { var responseFuture = client.sendRequest(request); System.out.println(responseFuture.get().toString()); - } catch (InterruptedException | ExecutionException | OpenemsNamedException e) { + } catch (InterruptedException | ExecutionException e) { System.out.println(e.getMessage()); } client.stop(); @@ -65,7 +64,7 @@ public void getEdgeConfigRequest() throws Exception { try { var responseFuture = client.sendRequest(request); System.out.println(responseFuture.get().toString()); - } catch (InterruptedException | ExecutionException | OpenemsNamedException e) { + } catch (InterruptedException | ExecutionException e) { System.out.println(e.getMessage()); } client.stop(); @@ -82,7 +81,7 @@ public void getEdgesChannelsValuesRequest() throws Exception { try { var responseFuture = client.sendRequest(request); System.out.println(responseFuture.get().toString()); - } catch (InterruptedException | ExecutionException | OpenemsNamedException e) { + } catch (InterruptedException | ExecutionException e) { System.out.println(e.getMessage()); } client.stop(); @@ -102,7 +101,7 @@ public void subscribeEdgesChannelsRequest() throws Exception { try { var responseFuture = client.sendRequest(request); System.out.println(responseFuture.get().toString()); - } catch (InterruptedException | ExecutionException | OpenemsNamedException e) { + } catch (InterruptedException | ExecutionException e) { System.out.println(e.getMessage()); } @@ -120,7 +119,7 @@ public void setGridConnSchedule() throws Exception { try { var responseFuture = client.sendRequest(request); System.out.println(responseFuture.get().toString()); - } catch (InterruptedException | ExecutionException | OpenemsNamedException e) { + } catch (InterruptedException | ExecutionException e) { System.out.println(e.getMessage()); } client.stop(); diff --git a/io.openems.backend.b2bwebsocket/test/io/openems/backend/b2bwebsocket/TestClient.java b/io.openems.backend.b2bwebsocket/test/io/openems/backend/b2bwebsocket/TestClient.java index d016c808f69..3f313d2c93b 100644 --- a/io.openems.backend.b2bwebsocket/test/io/openems/backend/b2bwebsocket/TestClient.java +++ b/io.openems.backend.b2bwebsocket/test/io/openems/backend/b2bwebsocket/TestClient.java @@ -3,11 +3,11 @@ import java.net.URI; import java.util.Map; +import org.java_websocket.WebSocket; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import io.openems.common.websocket.AbstractWebsocketClient; -import io.openems.common.websocket.DummyWsData; import io.openems.common.websocket.OnClose; import io.openems.common.websocket.OnError; import io.openems.common.websocket.OnNotification; @@ -29,6 +29,7 @@ protected TestClient(URI serverUri, Map httpHeaders) { super("B2bwebsocket.Unittest", serverUri, httpHeaders); this.onOpen = (ws, handshake) -> { this.log.info("OnOpen: " + handshake); + return null; }; this.onRequest = (ws, request) -> { this.log.info("OnRequest: " + request); @@ -91,8 +92,13 @@ public void setOnNotification(OnNotification onNotification) { } @Override - protected WsData createWsData() { - return new DummyWsData(); + protected WsData createWsData(WebSocket ws) { + return new WsData(ws) { + @Override + public String toString() { + return "TestClient.WsData []"; + } + }; } @Override diff --git a/io.openems.backend.common/src/io/openems/backend/common/edgewebsocket/EdgeWebsocket.java b/io.openems.backend.common/src/io/openems/backend/common/edgewebsocket/EdgeWebsocket.java index b99ee59d9cb..aa8a96cb7d9 100644 --- a/io.openems.backend.common/src/io/openems/backend/common/edgewebsocket/EdgeWebsocket.java +++ b/io.openems.backend.common/src/io/openems/backend/common/edgewebsocket/EdgeWebsocket.java @@ -11,7 +11,6 @@ import com.google.gson.JsonNull; import io.openems.backend.common.metadata.User; -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.jsonrpc.base.JsonrpcNotification; import io.openems.common.jsonrpc.base.JsonrpcRequest; import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; @@ -29,19 +28,17 @@ public interface EdgeWebsocket { * @param user the authenticated {@link User} * @param request the {@link JsonrpcRequest} * @return the JSON-RPC Success Response Future - * @throws OpenemsNamedException on error */ - public CompletableFuture send(String edgeId, User user, JsonrpcRequest request) - throws OpenemsNamedException; + public CompletableFuture send(String edgeId, User user, JsonrpcRequest request); /** * Send a JSON-RPC Notification to an Edge. * * @param edgeId the Edge-ID * @param notification the JsonrpcNotification - * @throws OpenemsNamedException on error + * @return true if sending was successful; false otherwise */ - public void send(String edgeId, JsonrpcNotification notification) throws OpenemsNamedException; + public boolean send(String edgeId, JsonrpcNotification notification); /** * Handles a {@link SubscribeSystemLogRequest}. @@ -51,10 +48,9 @@ public CompletableFuture send(String edgeId, User user, * @param websocketId the id of the UI websocket connection * @param request the {@link SubscribeSystemLogRequest} * @return a reply - * @throws OpenemsNamedException on error */ public CompletableFuture handleSubscribeSystemLogRequest(String edgeId, User user, - UUID websocketId, SubscribeSystemLogRequest request) throws OpenemsNamedException; + UUID websocketId, SubscribeSystemLogRequest request); /** * Gets the latest values for the given ChannelAddresses. diff --git a/io.openems.backend.common/src/io/openems/backend/common/jsonrpc/request/GetEmsTypeRequest.java b/io.openems.backend.common/src/io/openems/backend/common/jsonrpc/request/GetEmsTypeRequest.java new file mode 100644 index 00000000000..0b6ff214dad --- /dev/null +++ b/io.openems.backend.common/src/io/openems/backend/common/jsonrpc/request/GetEmsTypeRequest.java @@ -0,0 +1,63 @@ +package io.openems.backend.common.jsonrpc.request; + +import com.google.gson.JsonObject; + +import io.openems.backend.common.metadata.Edge; +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.jsonrpc.base.JsonrpcRequest; +import io.openems.common.utils.JsonUtils; + +/** + * Gets the ems type of a edge. + * + *

      + * {
      + *   "jsonrpc": "2.0",
      + *   "id": UUID,
      + *   "method": "getEmsType",
      + *   "params": {
      + *      "edgeId": string
      + *   }
      + * }
      + * 
      + */ +public class GetEmsTypeRequest extends JsonrpcRequest { + + public static final String METHOD = "getEmsType"; + + /** + * Create {@link GetEmsTypeRequest} from a template {@link JsonrpcRequest}. + * + * @param request the template {@link JsonrpcRequest} + * @return Created {@link GetEmsTypeRequest} + */ + public static GetEmsTypeRequest from(JsonrpcRequest request) throws OpenemsNamedException { + var params = request.getParams(); + + return new GetEmsTypeRequest(request, JsonUtils.getAsString(params, "edgeId")); + } + + private final String edgeId; + + private GetEmsTypeRequest(JsonrpcRequest request, String edgeId) { + super(request, METHOD); + this.edgeId = edgeId; + } + + @Override + public JsonObject getParams() { + return JsonUtils.buildJsonObject() // + .addProperty("edgeId", this.edgeId) // + .build(); + } + + /** + * Get the {@link Edge} ID. + * + * @return the {@link Edge} ID + */ + public String getEdgeId() { + return this.edgeId; + } + +} diff --git a/io.openems.backend.common/src/io/openems/backend/common/jsonrpc/response/GetEmsTypeResponse.java b/io.openems.backend.common/src/io/openems/backend/common/jsonrpc/response/GetEmsTypeResponse.java new file mode 100644 index 00000000000..cf2b2420c69 --- /dev/null +++ b/io.openems.backend.common/src/io/openems/backend/common/jsonrpc/response/GetEmsTypeResponse.java @@ -0,0 +1,40 @@ +package io.openems.backend.common.jsonrpc.response; + +import java.util.UUID; + +import com.google.gson.JsonObject; + +import io.openems.backend.common.jsonrpc.request.AddEdgeToUserRequest; +import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; +import io.openems.common.utils.JsonUtils; + +/** + * Represents a JSON-RPC Response for {@link AddEdgeToUserRequest}. + * + *
      + * {
      + *   "jsonrpc": "2.0",
      + *   "id": "UUID",
      + *   "result": {
      + *     "emsType": String
      + *   }
      + * }
      + * 
      + */ +public class GetEmsTypeResponse extends JsonrpcResponseSuccess { + + private final String emsType; + + public GetEmsTypeResponse(UUID id, String emsType) { + super(id); + this.emsType = emsType; + } + + @Override + public JsonObject getResult() { + return JsonUtils.buildJsonObject() // + .addPropertyIfNotNull("emsType", this.emsType) // + .build(); + } + +} diff --git a/io.openems.backend.common/src/io/openems/backend/common/metadata/Metadata.java b/io.openems.backend.common/src/io/openems/backend/common/metadata/Metadata.java index 98fb65c4002..79696ccbde7 100644 --- a/io.openems.backend.common/src/io/openems/backend/common/metadata/Metadata.java +++ b/io.openems.backend.common/src/io/openems/backend/common/metadata/Metadata.java @@ -376,6 +376,14 @@ public static final class Events { */ public Optional getSerialNumberForEdge(Edge edge); + /** + * Get ems type for the given {@link Edge}. + * + * @param edgeId id of the edge to search for ems type + * @return ems type or empty {@link Optional} + */ + public Optional getEmsTypeForEdge(String edgeId); + /** * Gets a map of Edge-IDs with the role of the given user. * diff --git a/io.openems.backend.common/src/io/openems/backend/common/test/DummyMetadata.java b/io.openems.backend.common/src/io/openems/backend/common/test/DummyMetadata.java index 1d161b9496e..87df24ee5da 100644 --- a/io.openems.backend.common/src/io/openems/backend/common/test/DummyMetadata.java +++ b/io.openems.backend.common/src/io/openems/backend/common/test/DummyMetadata.java @@ -171,6 +171,11 @@ public Optional getSerialNumberForEdge(Edge edge) { throw new UnsupportedOperationException("Unsupported by Dummy Class"); } + @Override + public Optional getEmsTypeForEdge(String edgeId) { + throw new UnsupportedOperationException("Unsupported by Dummy Class"); + } + @Override public List getPageDevice(User user, PaginationOptions paginationOptions) throws OpenemsNamedException { diff --git a/io.openems.backend.common/src/io/openems/backend/common/uiwebsocket/UiWebsocket.java b/io.openems.backend.common/src/io/openems/backend/common/uiwebsocket/UiWebsocket.java index 2174caa1e98..03d39fef744 100644 --- a/io.openems.backend.common/src/io/openems/backend/common/uiwebsocket/UiWebsocket.java +++ b/io.openems.backend.common/src/io/openems/backend/common/uiwebsocket/UiWebsocket.java @@ -23,17 +23,16 @@ public interface UiWebsocket { * @return the JSON-RPC Success Response Future * @throws OpenemsNamedException on error */ - public CompletableFuture send(UUID websocketId, JsonrpcRequest request) - throws OpenemsNamedException; + public CompletableFuture send(UUID websocketId, JsonrpcRequest request); /** * Send a JSON-RPC Notification to a UI session. * * @param websocketId the id of the UI websocket connection * @param notification the JsonrpcNotification - * @throws OpenemsNamedException on error + * @return true if sending was successful; false otherwise */ - public void send(UUID websocketId, JsonrpcNotification notification) throws OpenemsNamedException; + public boolean send(UUID websocketId, JsonrpcNotification notification); /** * Send a JSON-RPC Notification broadcast to all UI sessions with a given @@ -41,9 +40,8 @@ public CompletableFuture send(UUID websocketId, JsonrpcR * * @param edgeId the Edge-ID * @param notification the JsonrpcNotification - * @throws OpenemsNamedException on error */ - public void sendBroadcast(String edgeId, JsonrpcNotification notification) throws OpenemsNamedException; + public void sendBroadcast(String edgeId, JsonrpcNotification notification); /** * Sends the subscribed Channels to the UI session. diff --git a/io.openems.backend.core/src/io/openems/backend/core/debugcycle/DebugCycleExecutor.java b/io.openems.backend.core/src/io/openems/backend/core/debugcycle/DebugCycleExecutor.java index 3df861ff00a..2e262abefc5 100644 --- a/io.openems.backend.core/src/io/openems/backend/core/debugcycle/DebugCycleExecutor.java +++ b/io.openems.backend.core/src/io/openems/backend/core/debugcycle/DebugCycleExecutor.java @@ -49,7 +49,7 @@ public class DebugCycleExecutor implements Runnable { @Activate public DebugCycleExecutor() { - this.debugCycleScheduledExecutor.scheduleAtFixedRate(this, 10, 10, TimeUnit.SECONDS); + this.debugCycleScheduledExecutor.scheduleAtFixedRate(this, 5, 5, TimeUnit.SECONDS); } /** diff --git a/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/Config.java b/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/Config.java index 560e9f21ae2..fdc781be51f 100644 --- a/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/Config.java +++ b/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/Config.java @@ -3,8 +3,6 @@ import org.osgi.service.metatype.annotations.AttributeDefinition; import org.osgi.service.metatype.annotations.ObjectClassDefinition; -import io.openems.common.websocket.AbstractWebsocketServer.DebugMode; - @ObjectClassDefinition(// name = "Edge.Websocket", // description = "Configures the websocket server for OpenEMS Edge") @@ -16,9 +14,5 @@ @AttributeDefinition(name = "Number of Threads", description = "Pool-Size: the number of threads dedicated to handle the tasks") int poolSize() default 10; - @AttributeDefinition(name = "Debug Mode", description = "Activates the debug mode") - DebugMode debugMode() default DebugMode.OFF; - String webconsole_configurationFactory_nameHint() default "Edge Websocket"; - } diff --git a/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/EdgeWebsocketImpl.java b/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/EdgeWebsocketImpl.java index 8498c05aefc..bb1b088522c 100644 --- a/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/EdgeWebsocketImpl.java +++ b/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/EdgeWebsocketImpl.java @@ -42,7 +42,6 @@ import io.openems.backend.common.uiwebsocket.UiWebsocket; import io.openems.common.exceptions.OpenemsError; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.exceptions.OpenemsException; import io.openems.common.jsonrpc.base.JsonrpcNotification; import io.openems.common.jsonrpc.base.JsonrpcRequest; import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; @@ -111,8 +110,7 @@ private void deactivate() { */ private synchronized void startServer() { if (this.server == null) { - this.server = new WebsocketServer(this, this.getName(), this.config.port(), this.config.poolSize(), - this.config.debugMode()); + this.server = new WebsocketServer(this, this.getName(), this.config.port(), this.config.poolSize()); this.server.start(); } } @@ -140,11 +138,10 @@ protected boolean isOnline(String edgeId) { } @Override - public CompletableFuture send(String edgeId, User user, JsonrpcRequest request) - throws OpenemsNamedException { + public CompletableFuture send(String edgeId, User user, JsonrpcRequest request) { var ws = this.getWebSocketForEdgeId(edgeId); if (ws == null) { - throw OpenemsError.BACKEND_EDGE_NOT_CONNECTED.exception(edgeId); + return CompletableFuture.failedFuture(OpenemsError.BACKEND_EDGE_NOT_CONNECTED.exception(edgeId)); } WsData wsData = ws.getAttachment(); // Wrap Request in AuthenticatedRpc @@ -173,12 +170,13 @@ public CompletableFuture send(String edgeId, User user, } @Override - public void send(String edgeId, JsonrpcNotification notification) throws OpenemsException { + public boolean send(String edgeId, JsonrpcNotification notification) { var ws = this.getWebSocketForEdgeId(edgeId); - if (ws != null) { - WsData wsData = ws.getAttachment(); - wsData.send(notification); + if (ws == null) { + return false; } + WsData wsData = ws.getAttachment(); + return wsData.send(notification); } /** @@ -247,7 +245,7 @@ protected void logError(Logger log, String message) { @Override public CompletableFuture handleSubscribeSystemLogRequest(String edgeId, User user, - UUID websocketId, SubscribeSystemLogRequest request) throws OpenemsNamedException { + UUID websocketId, SubscribeSystemLogRequest request) { return this.systemLogHandler.handleSubscribeSystemLogRequest(edgeId, user, websocketId, request); } diff --git a/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/OnClose.java b/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/OnClose.java index 5366fe34072..e21a648c899 100644 --- a/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/OnClose.java +++ b/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/OnClose.java @@ -5,8 +5,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.openems.common.exceptions.OpenemsException; - public class OnClose implements io.openems.common.websocket.OnClose { private final Logger log = LoggerFactory.getLogger(OnClose.class); @@ -17,7 +15,7 @@ public OnClose(EdgeWebsocketImpl parent) { } @Override - public void run(WebSocket ws, int code, String reason, boolean remote) throws OpenemsException { + public void accept(WebSocket ws, int code, String reason, boolean remote) { // get edgeId from websocket WsData wsData = ws.getAttachment(); var edgeIdOpt = wsData.getEdgeId(); @@ -30,7 +28,6 @@ public void run(WebSocket ws, int code, String reason, boolean remote) throws Op if (edgeOpt.isPresent()) { var isOnline = this.parent.isOnline(edgeId); edgeOpt.get().setOnline(isOnline); - } } else { @@ -47,7 +44,9 @@ public void run(WebSocket ws, int code, String reason, boolean remote) throws Op // pong in time. For more information check: // https://github.com/TooTallNate/Java-WebSocket/wiki/Lost-connection-detection" } else { - this.parent.logInfo(this.log, edgeId, "Disconnected. Code [" + code + "] Reason [" + reason + "]"); + this.parent.logInfo(this.log, edgeId, new StringBuilder() // + .append("Disconnected. Code [").append(code).append("] Reason [").append(reason).append("]") + .toString()); } } diff --git a/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/OnError.java b/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/OnError.java index b1cc0720688..afb3cedb4e7 100644 --- a/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/OnError.java +++ b/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/OnError.java @@ -16,7 +16,7 @@ public OnError(EdgeWebsocketImpl parent) { } @Override - public void run(WebSocket ws, Exception ex) throws OpenemsException { + public void accept(WebSocket ws, Exception ex) throws OpenemsException { WsData wsData = ws.getAttachment(); var edgeIdOpt = wsData.getEdgeId(); this.parent.logWarn(this.log, edgeIdOpt.orElse(null), diff --git a/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/OnNotification.java b/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/OnNotification.java index 3f6c0498372..2ccb8cc68a9 100644 --- a/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/OnNotification.java +++ b/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/OnNotification.java @@ -36,7 +36,7 @@ public OnNotification(EdgeWebsocketImpl parent) { } @Override - public void run(WebSocket ws, JsonrpcNotification notification) throws OpenemsNamedException { + public void accept(WebSocket ws, JsonrpcNotification notification) throws OpenemsNamedException { // Validate authentication WsData wsData = ws.getAttachment(); final String edgeId; @@ -92,8 +92,6 @@ private void handleEdgeConfigNotification(EdgeConfigNotification message, WsData if (this.parent.uiWebsocket != null) { this.parent.uiWebsocket.sendBroadcast(edgeId, new EdgeRpcNotification(edgeId, message)); } - } catch (OpenemsNamedException e) { - this.parent.logWarn(this.log, edgeId, "Unable to forward EdgeConfigNotification to UI: " + e.getMessage()); } catch (NullPointerException e) { this.parent.logWarn(this.log, edgeId, "Unable to forward EdgeConfigNotification to UI: NullPointerException"); diff --git a/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/OnOpen.java b/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/OnOpen.java index e92aed90a5f..fbf05fe7a7f 100644 --- a/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/OnOpen.java +++ b/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/OnOpen.java @@ -1,12 +1,14 @@ package io.openems.backend.edgewebsocket; -import org.java_websocket.WebSocket; -import org.java_websocket.framing.CloseFrame; +import static io.openems.common.websocket.WebsocketUtils.getAsString; +import static io.openems.common.websocket.WebsocketUtils.parseRemoteIdentifier; +import static org.java_websocket.framing.CloseFrame.REFUSE; +import static org.java_websocket.framing.CloseFrame.TRY_AGAIN_LATER; -import com.google.gson.JsonObject; +import org.java_websocket.WebSocket; +import org.java_websocket.handshake.Handshakedata; -import io.openems.common.exceptions.OpenemsException; -import io.openems.common.utils.JsonUtils; +import io.openems.common.exceptions.OpenemsError; public class OnOpen implements io.openems.common.websocket.OnOpen { @@ -17,81 +19,54 @@ public OnOpen(EdgeWebsocketImpl parent) { } @Override - public void run(WebSocket ws, JsonObject handshake) { - // get websocket attachment - WsData wsData = ws.getAttachment(); - - var apikey = ""; - try { - // get apikey from handshake - var apikeyOpt = JsonUtils.getAsOptionalString(handshake, "apikey"); - if (!apikeyOpt.isPresent()) { - throw new OpenemsException("Apikey is missing in handshake"); - } - apikey = apikeyOpt.get().trim(); - - // get edgeId for apikey - var edgeIdOpt = this.parent.metadata.getEdgeIdForApikey(apikey); - if (!edgeIdOpt.isPresent()) { - throw new OpenemsException("Unable to authenticate this Apikey"); - } - var edgeId = edgeIdOpt.get(); - - // get metadata for Edge - var edgeOpt = this.parent.metadata.getEdge(edgeId); - if (!edgeOpt.isPresent()) { - throw new OpenemsException("Unable to get metadata for Edge [" + edgeId + "]"); - } - var edge = edgeOpt.get(); - - // announce Edge as online - edge.setOnline(true); - edge.setLastmessage(); - wsData.setEdgeId(edgeId); + public OpenemsError apply(WebSocket ws, Handshakedata handshakedata) { + // get apikey from handshake + final var apikey = getAsString(handshakedata, "apikey"); - // TODO send notification to UI - } catch (OpenemsException e) { + var error = this._apply(ws, apikey); + if (error != null) { if (this.parent.metadata.isInitialized()) { - // close websocket - ws.closeConnection(CloseFrame.REFUSE, "Connection to backend failed. " // + ws.closeConnection(REFUSE, "Connection to backend failed. " // + "Apikey [" + apikey + "]. " // - + "Remote [" + parseRemoteIdentifier(ws, handshake) + "] " // - + "Error: " + e.getMessage()); + + "Remote [" + parseRemoteIdentifier(ws, handshakedata) + "] " // + + "Error: " + error.name()); } else { - // close websocket - ws.closeConnection(CloseFrame.TRY_AGAIN_LATER, - "Connection to backend failed. Metadata is not yet initialized. " // - + "Apikey [" + apikey + "]. " // - + "Remote [" + parseRemoteIdentifier(ws, handshake) + "] " // - + "Error: " + e.getMessage()); + ws.closeConnection(TRY_AGAIN_LATER, "Connection to backend failed. Metadata is not yet initialized. " // + + "Apikey [" + apikey + "]. " // + + "Remote [" + parseRemoteIdentifier(ws, handshakedata) + "] " // + + "Error: " + error.name()); } } + return error; } - /** - * Parses a identifier for the Remote from the handshake. - * - *

      - * Tries to use the headers "Forwarded", "X-Forwarded-For" or "X-Real-IP". Falls - * back to `ws.getRemoteSocketAddress()`. See https://serverfault.com/a/920060 - * - * @param ws the {@link WebSocket} - * @param handshake the Handshake - * @return an identifier String - */ - private static String parseRemoteIdentifier(WebSocket ws, JsonObject handshake) { - for (var key : REMOTE_IDENTIFICATION_HEADERS) { - var value = JsonUtils.getAsOptionalString(handshake, - key.toLowerCase() /* handshake keys are all lower case */); - if (value.isPresent()) { - return value.get(); - } + private OpenemsError _apply(WebSocket ws, String apikey) { + // get websocket attachment + final WsData wsData = ws.getAttachment(); + + if (apikey == null) { + return OpenemsError.COMMON_AUTHENTICATION_FAILED; } - // fallback - return ws.getRemoteSocketAddress().toString(); - } - private static final String[] REMOTE_IDENTIFICATION_HEADERS = new String[] { // - "Forwarded", "X-Forwarded-For", "X-Real-IP" }; + // get edgeId for apikey + var edgeIdOpt = this.parent.metadata.getEdgeIdForApikey(apikey); + if (!edgeIdOpt.isPresent()) { + return OpenemsError.COMMON_AUTHENTICATION_FAILED; + } + var edgeId = edgeIdOpt.get(); + + // get metadata for Edge + var edgeOpt = this.parent.metadata.getEdge(edgeId); + if (!edgeOpt.isPresent()) { + return OpenemsError.COMMON_SERVICE_NOT_AVAILABLE; + } + var edge = edgeOpt.get(); + // announce Edge as online + edge.setOnline(true); + edge.setLastmessage(); + wsData.setEdgeId(edgeId); + + return null; // No error + } } diff --git a/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/OnRequest.java b/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/OnRequest.java index 778d47a9a80..f81752aa6ec 100644 --- a/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/OnRequest.java +++ b/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/OnRequest.java @@ -1,12 +1,15 @@ package io.openems.backend.edgewebsocket; import java.util.concurrent.CompletableFuture; +import java.util.function.BiConsumer; +import java.util.function.Supplier; import org.java_websocket.WebSocket; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import io.openems.backend.common.metadata.AppCenterHandler; +import io.openems.backend.common.metadata.AppCenterMetadata; import io.openems.common.exceptions.OpenemsError; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; @@ -17,14 +20,18 @@ public class OnRequest implements io.openems.common.websocket.OnRequest { private final Logger log = LoggerFactory.getLogger(OnRequest.class); - private final EdgeWebsocketImpl parent; - - public OnRequest(EdgeWebsocketImpl parent) { - this.parent = parent; + private final Supplier appCenterMetadata; + private final BiConsumer logWarn; + + public OnRequest(// + Supplier appCenterMetadata, // + BiConsumer logWarn) { + this.appCenterMetadata = appCenterMetadata; + this.logWarn = logWarn; } @Override - public CompletableFuture run(WebSocket ws, JsonrpcRequest request) + public CompletableFuture apply(WebSocket ws, JsonrpcRequest request) throws OpenemsException, OpenemsNamedException { final WsData wsData = ws.getAttachment(); @@ -34,7 +41,7 @@ public CompletableFuture run(WebSocket ws, Jso switch (request.getMethod()) { case AppCenterRequest.METHOD: - resultFuture = AppCenterHandler.handleEdgeRequest(this.parent.appCenterMetadata, // + resultFuture = AppCenterHandler.handleEdgeRequest(this.appCenterMetadata.get(), // AppCenterRequest.from(request), edgeId); break; @@ -43,7 +50,7 @@ public CompletableFuture run(WebSocket ws, Jso if (resultFuture != null) { return resultFuture; } - this.parent.logWarn(this.log, "Unhandled Request: " + request); + this.logWarn.accept(this.log, "Unhandled Request: " + request); throw OpenemsError.JSONRPC_UNHANDLED_METHOD.exception(request.getMethod()); } diff --git a/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/SystemLogHandler.java b/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/SystemLogHandler.java index 41bd8ce5961..45078b35435 100644 --- a/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/SystemLogHandler.java +++ b/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/SystemLogHandler.java @@ -12,7 +12,6 @@ import com.google.gson.JsonObject; import io.openems.backend.common.metadata.User; -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.jsonrpc.base.GenericJsonrpcResponseSuccess; import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; import io.openems.common.jsonrpc.notification.EdgeRpcNotification; @@ -43,10 +42,9 @@ public SystemLogHandler(EdgeWebsocketImpl parent) { * @param websocketId the id of the UI websocket connection * @param request the {@link SubscribeSystemLogRequest} * @return a reply - * @throws OpenemsNamedException on error */ public CompletableFuture handleSubscribeSystemLogRequest(String edgeId, User user, - UUID websocketId, SubscribeSystemLogRequest request) throws OpenemsNamedException { + UUID websocketId, SubscribeSystemLogRequest request) { if (request.isSubscribe()) { // Add subscription this.addSubscriptionId(edgeId, websocketId); @@ -81,39 +79,18 @@ public void handleSystemLogNotification(String edgeId, SystemLogNotification not if (ids == null) { // No Tokens exist, but we still receive Notification? -> send unsubscribe - try { - var dummyGuestUser = new User("internal", "UnsubscribeSystemLogNotification", - UUID.randomUUID().toString(), Language.EN, Role.GUEST, false, new JsonObject()); - this.parent.send(edgeId, dummyGuestUser, SubscribeSystemLogRequest.unsubscribe()); - this.parent.logInfo(this.log, edgeId, "Was still sending SystemLogNotification. Sent unsubscribe."); - - } catch (OpenemsNamedException e) { - this.parent.logWarn(this.log, edgeId, - "Was still sending SystemLogNotification. Unable to send unsubscribe: " + e.getMessage()); - } + var dummyGuestUser = new User("internal", "UnsubscribeSystemLogNotification", UUID.randomUUID().toString(), + Language.EN, Role.GUEST, false, new JsonObject()); + this.parent.send(edgeId, dummyGuestUser, SubscribeSystemLogRequest.unsubscribe()); + this.parent.logInfo(this.log, edgeId, "Was still sending SystemLogNotification. Sent unsubscribe."); return; } // Forward Notification to each Session token for (var id : ids) { - try { - // TODO use events - if (this.parent.uiWebsocket != null) { - this.parent.uiWebsocket.send(id, new EdgeRpcNotification(edgeId, notification)); - } - - } catch (OpenemsNamedException | NullPointerException e) { - this.parent.logWarn(this.log, edgeId, "Unable to handle SystemLogNotification: " + e.getMessage()); - // error -> send unsubscribe - try { - var dummyGuestUser = new User("internal", "UnsubscribeSystemLogNotification", - UUID.randomUUID().toString(), Language.EN, Role.GUEST, false, new JsonObject()); - this.handleSubscribeSystemLogRequest(edgeId, dummyGuestUser, id, - SubscribeSystemLogRequest.unsubscribe()); - - } catch (OpenemsNamedException e1) { - this.parent.logWarn(this.log, edgeId, "Unable to send unsubscribe: " + e1.getMessage()); - } + // TODO use events + if (this.parent.uiWebsocket != null) { + this.parent.uiWebsocket.send(id, new EdgeRpcNotification(edgeId, notification)); } } } diff --git a/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/WebsocketServer.java b/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/WebsocketServer.java index 1e9abdcac89..d1bfefd54ad 100644 --- a/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/WebsocketServer.java +++ b/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/WebsocketServer.java @@ -1,11 +1,5 @@ package io.openems.backend.edgewebsocket; -import java.time.Instant; -import java.time.ZoneId; -import java.time.ZonedDateTime; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; import java.util.Objects; import java.util.Optional; import java.util.Set; @@ -18,14 +12,7 @@ import com.google.gson.JsonElement; -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.exceptions.OpenemsException; -import io.openems.common.jsonrpc.base.JsonrpcMessage; -import io.openems.common.jsonrpc.notification.SystemLogNotification; -import io.openems.common.jsonrpc.notification.TimestampedDataNotification; import io.openems.common.types.ChannelAddress; -import io.openems.common.types.SystemLog; -import io.openems.common.utils.JsonUtils; import io.openems.common.websocket.AbstractWebsocketServer; public class WebsocketServer extends AbstractWebsocketServer { @@ -37,19 +24,21 @@ public class WebsocketServer extends AbstractWebsocketServer { private final OnError onError; private final OnClose onClose; - public WebsocketServer(EdgeWebsocketImpl parent, String name, int port, int poolSize, DebugMode debugMode) { - super(name, port, poolSize, debugMode); + public WebsocketServer(EdgeWebsocketImpl parent, String name, int port, int poolSize) { + super(name, port, poolSize); this.parent = parent; this.onOpen = new OnOpen(parent); - this.onRequest = new OnRequest(parent); + this.onRequest = new OnRequest(// + () -> parent.appCenterMetadata, // + this::logWarn); this.onNotification = new OnNotification(parent); this.onError = new OnError(parent); this.onClose = new OnClose(parent); } @Override - protected WsData createWsData() { - return new WsData(); + protected WsData createWsData(WebSocket ws) { + return new WsData(ws); } /** @@ -89,47 +78,6 @@ protected OnClose getOnClose() { return this.onClose; } - @Override - protected JsonrpcMessage handleNonJsonrpcMessage(WebSocket ws, String stringMessage, - OpenemsNamedException lastException) throws OpenemsNamedException { - var message = JsonUtils.parseToJsonObject(stringMessage); - - // config - if (message.has("config")) { - // Unable to handle deprecated configurations - return null; - } - - // timedata - if (message.has("timedata")) { - var d = new TimestampedDataNotification(); - var timedata = JsonUtils.getAsJsonObject(message, "timedata"); - for (Entry entry : timedata.entrySet()) { - var timestamp = Long.parseLong(entry.getKey()); - var values = JsonUtils.getAsJsonObject(entry.getValue()); - Map data = new HashMap<>(); - for (Entry value : values.entrySet()) { - data.put(value.getKey(), value.getValue()); - } - d.add(timestamp, data); - } - return d; - } - - // log - if (message.has("log")) { - var log = JsonUtils.getAsJsonObject(message, "log"); - return new SystemLogNotification(new SystemLog( - ZonedDateTime.ofInstant(Instant.ofEpochMilli(JsonUtils.getAsLong(log, "time")), - ZoneId.systemDefault()), // - SystemLog.Level.valueOf(JsonUtils.getAsString(log, "level").toUpperCase()), // - JsonUtils.getAsString(log, "source"), // - JsonUtils.getAsString(log, "message"))); - } - - throw new OpenemsException("EdgeWs. handleNonJsonrpcMessage", lastException); - } - @Override protected void logInfo(Logger log, String message) { this.parent.logInfo(log, message); diff --git a/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/WsData.java b/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/WsData.java index 6a0abcf2479..180eaca7c5a 100644 --- a/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/WsData.java +++ b/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/WsData.java @@ -6,6 +6,8 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.java_websocket.WebSocket; + import io.openems.backend.common.edgewebsocket.EdgeCache; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; @@ -23,6 +25,10 @@ public class WsData extends io.openems.common.websocket.WsData { private final CompletableFuture isAuthenticated = new CompletableFuture<>(); public final EdgeCache edgeCache = new EdgeCache(); + public WsData(WebSocket ws) { + super(ws); + } + /** * Asserts that the Edge-ID is available (i.e. properly authenticated). * diff --git a/io.openems.backend.metadata.dummy/src/io/openems/backend/metadata/dummy/Config.java b/io.openems.backend.metadata.dummy/src/io/openems/backend/metadata/dummy/Config.java index b21abffdd83..b76c1d977dd 100644 --- a/io.openems.backend.metadata.dummy/src/io/openems/backend/metadata/dummy/Config.java +++ b/io.openems.backend.metadata.dummy/src/io/openems/backend/metadata/dummy/Config.java @@ -1,5 +1,6 @@ package io.openems.backend.metadata.dummy; +import org.osgi.service.metatype.annotations.AttributeDefinition; import org.osgi.service.metatype.annotations.ObjectClassDefinition; @ObjectClassDefinition(// @@ -7,6 +8,12 @@ description = "Configures the Metadata Dummy provider") @interface Config { + @AttributeDefinition(name = "Edge-ID template", description = "Template for Edge-IDs, defaults to 'edge%d'") + String edgeIdTemplate() default "edge%d"; + + @AttributeDefinition(name = "Max Edge-ID", description = "Default predefines Edge-IDs from 'edge0' to 'edge10'") + int edgeIdMax() default 10; + String webconsole_configurationFactory_nameHint() default "Metadata Dummy"; } diff --git a/io.openems.backend.metadata.dummy/src/io/openems/backend/metadata/dummy/MetadataDummy.java b/io.openems.backend.metadata.dummy/src/io/openems/backend/metadata/dummy/MetadataDummy.java index 899de4292de..c2f7e9bc9ce 100644 --- a/io.openems.backend.metadata.dummy/src/io/openems/backend/metadata/dummy/MetadataDummy.java +++ b/io.openems.backend.metadata.dummy/src/io/openems/backend/metadata/dummy/MetadataDummy.java @@ -79,11 +79,20 @@ public class MetadataDummy extends AbstractMetadata implements Metadata, EventHa private JsonObject settings = new JsonObject(); @Activate - public MetadataDummy(@Reference EventAdmin eventadmin) { + public MetadataDummy(@Reference EventAdmin eventadmin, Config config) { super("Metadata.Dummy"); this.eventAdmin = eventadmin; this.logInfo(this.log, "Activate"); + // Prefill + this.logInfo(this.log, "Prefilling Edges [" // + + String.format(config.edgeIdTemplate(), 0) + "..." + + String.format(config.edgeIdTemplate(), config.edgeIdMax()) + "]"); + for (var i = 0; i < config.edgeIdMax() + 1; i++) { + this.createEdge(config.edgeIdTemplate(), i); + } + this.nextEdgeId.set(config.edgeIdMax() + 1); + // Allow the services some time to settle this.executor.schedule(() -> { this.setInitialized(); @@ -166,7 +175,18 @@ public Optional getEdgeIdForApikey(String apikey) { var edge = new MyEdge(this, edgeId, apikey, setupPassword, "OpenEMS Edge #" + id, "", ""); this.edges.put(edgeId, edge); return Optional.ofNullable(edgeId); + } + /** + * Creates and adds a {@link MyEdge}. + * + * @param edgeIdTemplate the Edge-ID template + * @param i value to be filled in the template + */ + private void createEdge(String edgeIdTemplate, int i) { + var edgeId = String.format(edgeIdTemplate, i); + var edge = new MyEdge(this, edgeId, edgeId, edgeId, "OpenEMS Edge #" + i, "", ""); + this.edges.put(edgeId, edge); } @Override @@ -277,6 +297,11 @@ public Optional getSerialNumberForEdge(Edge edge) { throw new UnsupportedOperationException("DummyMetadata.getSerialNumberForEdge() is not implemented"); } + @Override + public Optional getEmsTypeForEdge(String edgeId) { + throw new UnsupportedOperationException("DummyMetadata.getEmsTypeForEdge() is not implemented"); + } + @Override public UserAlertingSettings getUserAlertingSettings(String edgeId, String userId) throws OpenemsException { throw new UnsupportedOperationException("DummyMetadata.getUserAlertingSettings() is not implemented"); @@ -383,5 +408,4 @@ public void logGenericSystemLog(GenericSystemLog systemLog) { public void updateUserSettings(User user, JsonObject settings) { this.settings = settings == null ? new JsonObject() : settings; } - } diff --git a/io.openems.backend.metadata.file/src/io/openems/backend/metadata/file/MetadataFile.java b/io.openems.backend.metadata.file/src/io/openems/backend/metadata/file/MetadataFile.java index e1fda5d7540..014d47bca20 100644 --- a/io.openems.backend.metadata.file/src/io/openems/backend/metadata/file/MetadataFile.java +++ b/io.openems.backend.metadata.file/src/io/openems/backend/metadata/file/MetadataFile.java @@ -306,6 +306,11 @@ public Optional getSerialNumberForEdge(Edge edge) { throw new UnsupportedOperationException("FileMetadata.getSerialNumberForEdge() is not implemented"); } + @Override + public Optional getEmsTypeForEdge(String edgeId) { + throw new UnsupportedOperationException("FileMetadata.getEmsTypeForEdge() is not implemented"); + } + @Override public UserAlertingSettings getUserAlertingSettings(String edgeId, String userId) throws OpenemsException { throw new UnsupportedOperationException("FileMetadata.getUserAlertingSettings() is not implemented"); diff --git a/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/Config.java b/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/Config.java index 24780745baa..8512870c35e 100644 --- a/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/Config.java +++ b/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/Config.java @@ -4,7 +4,6 @@ import org.osgi.service.metatype.annotations.ObjectClassDefinition; import io.openems.backend.metadata.odoo.odoo.Protocol; -import io.openems.common.websocket.AbstractWebsocketServer.DebugMode; @ObjectClassDefinition(// name = "Metadata.Odoo", // diff --git a/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/DebugMode.java b/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/DebugMode.java new file mode 100644 index 00000000000..66c334c44c9 --- /dev/null +++ b/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/DebugMode.java @@ -0,0 +1,16 @@ +package io.openems.backend.metadata.odoo; + +public enum DebugMode { + + OFF, SIMPLE, DETAILED; + + /** + * Is this {@link DebugMode} at least as high as the other {@link DebugMode}?. + * + * @param other the other {@link DebugMode} + * @return true if yes + */ + public boolean isAtLeast(DebugMode other) { + return this.ordinal() >= other.ordinal(); + } +} diff --git a/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/Field.java b/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/Field.java index cfd7dc2ef1c..b2e415dd370 100644 --- a/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/Field.java +++ b/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/Field.java @@ -114,14 +114,22 @@ public enum EdgeDevice implements Field { NAME("name", true), // COMMENT("comment", true), // OPENEMS_VERSION("openems_version", true), // - PRODUCTTYPE("producttype", true), // - OPENEMS_CONFIG("openems_config", false), // - OPENEMS_CONFIG_COMPONENTS("openems_config_components", false), // LASTMESSAGE("lastmessage", true), // OPENEMS_SUM_STATE("openems_sum_state_level", false), // OPENEMS_IS_CONNECTED("openems_is_connected", false), // - STOCK_PRODUCTION_LOT_ID("stock_production_lot_id", false), - FIRST_SETUP_PROTOCOL("first_setup_protocol_date", false); + FIRST_SETUP_PROTOCOL("first_setup_protocol_date", false), // + + // Hardware + PRODUCTTYPE("producttype", true), // + EMS_TYPE("ems_type", false), // + + // Configuration + OPENEMS_CONFIG("openems_config", false), // + OPENEMS_CONFIG_COMPONENTS("openems_config_components", false), // + + // Product + STOCK_PRODUCTION_LOT_ID("stock_production_lot_id", false), // + ; public static final String ODOO_MODEL = "openems.device"; public static final String ODOO_TABLE = ODOO_MODEL.replace(".", "_"); diff --git a/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/MetadataOdoo.java b/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/MetadataOdoo.java index 6c544232e40..9f28bc32346 100644 --- a/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/MetadataOdoo.java +++ b/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/MetadataOdoo.java @@ -76,7 +76,6 @@ import io.openems.common.types.SemanticVersion; import io.openems.common.utils.JsonUtils; import io.openems.common.utils.ThreadPoolUtils; -import io.openems.common.websocket.AbstractWebsocketServer.DebugMode; @Designate(ocd = Config.class, factory = false) @Component(// @@ -457,6 +456,11 @@ public Optional getSerialNumberForEdge(Edge edge) { return this.odooHandler.getSerialNumberForEdge(edge); } + @Override + public Optional getEmsTypeForEdge(String edgeId) { + return this.odooHandler.getEmsTypeForEdge(edgeId); + } + @Override public void sendMail(ZonedDateTime sendAt, String template, JsonElement params) { try { diff --git a/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/odoo/OdooHandler.java b/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/odoo/OdooHandler.java index faf69a04d76..b79cab0cace 100644 --- a/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/odoo/OdooHandler.java +++ b/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/odoo/OdooHandler.java @@ -936,6 +936,33 @@ public Optional getSerialNumberForEdge(Edge edge) { return Optional.empty(); } + /** + * Get ems type for the given {@link Edge}. + * + * @param edgeId the id of the edge for the ems type + * @return ems type or empty {@link Optional} + */ + public Optional getEmsTypeForEdge(String edgeId) { + try { + final var queryResult = OdooUtils.searchRead(this.credentials, Field.EdgeDevice.ODOO_MODEL, + new Field[] { Field.EdgeDevice.EMS_TYPE }, new Domain(Field.EdgeDevice.NAME, Operator.EQ, edgeId)); + + if (queryResult.length != 1) { + return Optional.empty(); + } + + final var emsTypeObj = queryResult[0].get(Field.EdgeDevice.EMS_TYPE.id()); + + if (emsTypeObj instanceof String emsTypeString) { + return Optional.of(emsTypeString); + } + } catch (OpenemsException ex) { + this.parent.logInfo(this.log, "Unable to find serial number for Edge [" + edgeId + "]"); + } + + return Optional.empty(); + } + /** * Gets if the given key can be applied to the given app and edge id. * diff --git a/io.openems.backend.timedata.aggregatedinflux/src/io/openems/backend/timedata/aggregatedinflux/AggregatedInflux.java b/io.openems.backend.timedata.aggregatedinflux/src/io/openems/backend/timedata/aggregatedinflux/AggregatedInflux.java index 4781e471dbb..a9027b47f54 100644 --- a/io.openems.backend.timedata.aggregatedinflux/src/io/openems/backend/timedata/aggregatedinflux/AggregatedInflux.java +++ b/io.openems.backend.timedata.aggregatedinflux/src/io/openems/backend/timedata/aggregatedinflux/AggregatedInflux.java @@ -421,7 +421,71 @@ private String getMeasurement(ZoneId zoneId) throws OpenemsNamedException { if (measurement != null) { return measurement; } - this.log.warn("No measurement provided for zoneId " + zoneId); + // this.log.warn("No measurement provided for zoneId " + zoneId); + + // TODO: add more zoneToMeasurement. Logs from 2024-07-21: + // - +00:00:02 + // - +01:00 + // - +02:00 + // - -07:00 + // - Africa/Cairo + // - Africa/Casablanca + // - Africa/Johannesburg + // - Africa/Nairobi + // - Africa/Windhoek + // - America/Chicago + // - America/Detroit + // - America/Edmonton + // - America/Los_Angeles + // - America/New_York + // - America/Sao_Paulo + // - America/Toronto + // - America/Vancouver + // - Asia/Calcutta + // - Asia/Colombo + // - Asia/Jerusalem + // - Asia/Makassar + // - Asia/Nicosia + // - Asia/Shanghai + // - Asia/Tbilisi + // - Atlantic/Canary + // - Atlantic/Reykjavik + // - Australia/Adelaide + // - Etc/GMT-2 + // - Europe/Amsterdam + // - Europe/Athens + // - Europe/Bratislava + // - Europe/Brussels + // - Europe/Bucharest + // - Europe/Budapest + // - Europe/Copenhagen + // - Europe/Dublin + // - Europe/Helsinki + // - Europe/Istanbul + // - Europe/Lisbon + // - Europe/Ljubljana + // - Europe/London + // - Europe/Luxembourg + // - Europe/Madrid + // - Europe/Malta + // - Europe/Oslo + // - Europe/Paris + // - Europe/Podgorica + // - Europe/Prague + // - Europe/Riga + // - Europe/Rome + // - Europe/Sarajevo + // - Europe/Sofia + // - Europe/Stockholm + // - Europe/Tallinn + // - Europe/Tirane + // - Europe/Vaduz + // - Europe/Vienna + // - Europe/Vilnius + // - Europe/Warsaw + // - Europe/Zagreb + // - Europe/Zurich + // - Indian/Maldives for (var entry : this.zoneToMeasurement.entrySet()) { return entry.getValue(); } diff --git a/io.openems.backend.timedata.aggregatedinflux/src/io/openems/backend/timedata/aggregatedinflux/AllowedChannels.java b/io.openems.backend.timedata.aggregatedinflux/src/io/openems/backend/timedata/aggregatedinflux/AllowedChannels.java index 4a85a09cf1e..5b93270894c 100644 --- a/io.openems.backend.timedata.aggregatedinflux/src/io/openems/backend/timedata/aggregatedinflux/AllowedChannels.java +++ b/io.openems.backend.timedata.aggregatedinflux/src/io/openems/backend/timedata/aggregatedinflux/AllowedChannels.java @@ -70,6 +70,7 @@ private AllowedChannels() { .putAll(multiChannels("ctrlApiModbusTcp", 0, 3, "Ess0SetReactivePowerLessOrEquals", DataType.LONG)) // .putAll(multiChannels("ctrlApiModbusTcp", 0, 3, "Ess0SetReactivePowerGreaterOrEquals", DataType.LONG)) // .putAll(multiChannels("ctrlApiModbusTcp", 0, 3, "Ess0SetActivePowerGreaterOrEquals", DataType.LONG)) // + .put("ctrlEssLimiter14a0/RestrictionMode", DataType.LONG) // .build(); ALLOWED_CUMULATED_CHANNELS = ImmutableMap.builder() // @@ -115,6 +116,7 @@ private AllowedChannels() { .putAll(multiChannels("ess", 0, 17, "ActiveDischargeEnergy", DataType.LONG)) // .putAll(multiChannels("ctrlApiModbusTcp", 0, 3, "CumulatedActiveTime", DataType.LONG)) // .putAll(multiChannels("ctrlApiModbusTcp", 0, 3, "CumulatedInactiveTime", DataType.LONG)) // + .put("ctrlEssLimiter14a0/CumulatedRestrictionTime", DataType.LONG) // .build(); } diff --git a/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/ChannelFilter.java b/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/ChannelFilter.java index 3bdeef18022..6193e38775f 100644 --- a/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/ChannelFilter.java +++ b/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/ChannelFilter.java @@ -9,9 +9,6 @@ public class ChannelFilter { - private static final Predicate SUNSPEC_PATTERN = // - Pattern.compile("^S[0-9]+[A-Z][a-zA-Z0-9]*$").asPredicate(); - /** * Pattern for Component-IDs. * @@ -82,15 +79,7 @@ public boolean isValid(String channelAddress) { return false; } - // Valid Channel-ID - final var channelId = c[1]; - if (SUNSPEC_PATTERN.test(channelId)) { - // SunSpec Channels - return false; - } - return true; } - } diff --git a/io.openems.backend.timedata.influx/test/io/openems/backend/timedata/influx/ChannelFilterTest.java b/io.openems.backend.timedata.influx/test/io/openems/backend/timedata/influx/ChannelFilterTest.java index 0f473a6d56d..e3d8447a915 100644 --- a/io.openems.backend.timedata.influx/test/io/openems/backend/timedata/influx/ChannelFilterTest.java +++ b/io.openems.backend.timedata.influx/test/io/openems/backend/timedata/influx/ChannelFilterTest.java @@ -45,8 +45,8 @@ public void testIsValid() { assertFalse(filter.isValid("äöü0/Status")); // SunSpec - assertFalse(filter.isValid("pvInverter0/S1Evt")); - assertFalse(filter.isValid("pvInverter0/S111A")); + assertTrue(filter.isValid("pvInverter0/S1Evt")); + assertTrue(filter.isValid("pvInverter0/S111A")); } } diff --git a/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/Config.java b/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/Config.java index ca928c2920c..1c578a6ccff 100644 --- a/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/Config.java +++ b/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/Config.java @@ -3,8 +3,6 @@ import org.osgi.service.metatype.annotations.AttributeDefinition; import org.osgi.service.metatype.annotations.ObjectClassDefinition; -import io.openems.common.websocket.AbstractWebsocketServer.DebugMode; - @ObjectClassDefinition(// name = "Ui.Websocket", // description = "Configures the websocket server for OpenEMS UI") @@ -16,9 +14,5 @@ @AttributeDefinition(name = "Number of Threads", description = "Pool-Size: the number of threads dedicated to handle the tasks") int poolSize() default 10; - @AttributeDefinition(name = "Debug Mode", description = "Activates the debug mode") - DebugMode debugMode() default DebugMode.OFF; - String webconsole_configurationFactory_nameHint() default "Ui Websocket"; - } diff --git a/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnClose.java b/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnClose.java deleted file mode 100644 index 3ac723327a7..00000000000 --- a/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnClose.java +++ /dev/null @@ -1,21 +0,0 @@ -package io.openems.backend.uiwebsocket.impl; - -import org.java_websocket.WebSocket; - -import io.openems.common.exceptions.OpenemsException; - -public class OnClose implements io.openems.common.websocket.OnClose { - - public OnClose(UiWebsocketImpl parent) { - } - - @Override - public void run(WebSocket ws, int code, String reason, boolean remote) throws OpenemsException { - // get current User - WsData wsData = ws.getAttachment(); - if (wsData != null) { - wsData.dispose(); - } - } - -} diff --git a/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnError.java b/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnError.java index e66a53fc58b..37e5afb936e 100644 --- a/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnError.java +++ b/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnError.java @@ -16,7 +16,7 @@ public OnError(UiWebsocketImpl parent) { } @Override - public void run(WebSocket ws, Exception ex) throws OpenemsException { + public void accept(WebSocket ws, Exception ex) throws OpenemsException { WsData wsData = ws.getAttachment(); this.parent.logWarn(this.log, "User [" + wsData.getUserId().orElse("UNKNOWN") + "] websocket error. " + ex.getClass().getSimpleName() + ": " + ex.getMessage()); diff --git a/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnNotification.java b/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnNotification.java index 43063567657..15a9900ac96 100644 --- a/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnNotification.java +++ b/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnNotification.java @@ -19,7 +19,7 @@ public OnNotification(UiWebsocketImpl parent) { } @Override - public void run(WebSocket ws, JsonrpcNotification notification) throws OpenemsNamedException { + public void accept(WebSocket ws, JsonrpcNotification notification) throws OpenemsNamedException { WsData wsData = ws.getAttachment(); User user = null; try { diff --git a/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnOpen.java b/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnOpen.java deleted file mode 100644 index 4d467dab6b6..00000000000 --- a/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnOpen.java +++ /dev/null @@ -1,17 +0,0 @@ -package io.openems.backend.uiwebsocket.impl; - -import org.java_websocket.WebSocket; - -import com.google.gson.JsonObject; - -import io.openems.common.exceptions.OpenemsException; - -public class OnOpen implements io.openems.common.websocket.OnOpen { - - public OnOpen(UiWebsocketImpl parent) { - } - - @Override - public void run(WebSocket ws, JsonObject handshake) throws OpenemsException { - } -} diff --git a/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnRequest.java b/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnRequest.java index 9883cf030ac..39ea48803f6 100644 --- a/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnRequest.java +++ b/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnRequest.java @@ -11,6 +11,7 @@ import io.openems.backend.common.alerting.UserAlertingSettings; import io.openems.backend.common.jsonrpc.request.AddEdgeToUserRequest; +import io.openems.backend.common.jsonrpc.request.GetEmsTypeRequest; import io.openems.backend.common.jsonrpc.request.GetSetupProtocolDataRequest; import io.openems.backend.common.jsonrpc.request.GetSetupProtocolRequest; import io.openems.backend.common.jsonrpc.request.GetUserAlertingConfigsRequest; @@ -22,6 +23,7 @@ import io.openems.backend.common.jsonrpc.request.SubmitSetupProtocolRequest; import io.openems.backend.common.jsonrpc.request.SubscribeEdgesRequest; import io.openems.backend.common.jsonrpc.response.AddEdgeToUserResponse; +import io.openems.backend.common.jsonrpc.response.GetEmsTypeResponse; import io.openems.backend.common.jsonrpc.response.GetUserAlertingConfigsResponse; import io.openems.backend.common.jsonrpc.response.GetUserInformationResponse; import io.openems.backend.common.metadata.User; @@ -60,7 +62,7 @@ public OnRequest(UiWebsocketImpl parent) { } @Override - public CompletableFuture run(WebSocket ws, JsonrpcRequest request) + public CompletableFuture apply(WebSocket ws, JsonrpcRequest request) throws OpenemsNamedException { WsData wsData = ws.getAttachment(); @@ -87,6 +89,8 @@ public CompletableFuture run(WebSocket ws, Jso this.handleEdgeRpcRequest(wsData, user, EdgeRpcRequest.from(request)); case AddEdgeToUserRequest.METHOD -> // this.handleAddEdgeToUserRequest(user, AddEdgeToUserRequest.from(request)); + case GetEmsTypeRequest.METHOD -> // + this.handleGetEmsTypeRequest(user, GetEmsTypeRequest.from(request)); case GetUserInformationRequest.METHOD -> // this.handleGetUserInformationRequest(user, GetUserInformationRequest.from(request)); case SetUserInformationRequest.METHOD -> // @@ -347,6 +351,25 @@ private CompletableFuture handleAddEdgeToUserRequest(User .completedFuture(new AddEdgeToUserResponse(request.getId(), edge, serialNumber.orElse(null))); } + /** + * Handles an {@link GetEmsTypeRequest}. + * + * @param user the {@link User} + * @param request the {@link GetEmsTypeRequest} + * @return the JSON-RPC Success Response Future + * @throws OpenemsNamedException on error + */ + private CompletableFuture handleGetEmsTypeRequest(User user, GetEmsTypeRequest request) + throws OpenemsNamedException { + if (user.getRole(request.getEdgeId()).isEmpty()) { + this.parent.metadata.getEdgeMetadataForUser(user, request.getEdgeId()); + } + user.assertEdgeRoleIsAtLeast(GetEmsTypeRequest.METHOD, request.getEdgeId(), Role.GUEST); + final var emsType = this.parent.metadata.getEmsTypeForEdge(request.getEdgeId()); + + return CompletableFuture.completedFuture(new GetEmsTypeResponse(request.getId(), emsType.orElse(null))); + } + /** * Handles a {@link GetUserInformationRequest}. * diff --git a/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/UiWebsocketImpl.java b/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/UiWebsocketImpl.java index 98fe60fb108..6c63b521b4b 100644 --- a/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/UiWebsocketImpl.java +++ b/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/UiWebsocketImpl.java @@ -69,7 +69,7 @@ public class UiWebsocketImpl extends AbstractOpenemsBackendComponent @Reference protected volatile TimedataManager timedataManager; - + @Reference(policy = ReferencePolicy.DYNAMIC, cardinality = ReferenceCardinality.OPTIONAL) protected volatile SimulationEngine simulation; @@ -98,8 +98,7 @@ private void deactivate() { */ private synchronized void startServer() { if (this.server == null) { - this.server = new WebsocketServer(this, this.getName(), this.config.port(), this.config.poolSize(), - this.config.debugMode()); + this.server = new WebsocketServer(this, this.getName(), this.config.port(), this.config.poolSize()); this.server.start(); } } @@ -130,37 +129,38 @@ protected void logError(Logger log, String message) { } @Override - public void send(UUID websocketId, JsonrpcNotification notification) throws OpenemsNamedException { - var wsData = this.getWsDataForIdOrError(websocketId); - wsData.send(notification); + public boolean send(UUID websocketId, JsonrpcNotification notification) { + final WsData wsData; + try { + wsData = this.getWsDataForIdOrError(websocketId); + } catch (OpenemsNamedException e) { + return false; + } + return wsData.send(notification); } @Override - public CompletableFuture send(UUID websocketId, JsonrpcRequest request) - throws OpenemsNamedException { - var wsData = this.getWsDataForIdOrError(websocketId); + public CompletableFuture send(UUID websocketId, JsonrpcRequest request) { + WsData wsData; + try { + wsData = this.getWsDataForIdOrError(websocketId); + } catch (OpenemsNamedException e) { + return CompletableFuture.failedFuture(e); + } return wsData.send(request); } @Override - public void sendBroadcast(String edgeId, JsonrpcNotification notification) throws OpenemsNamedException { + public void sendBroadcast(String edgeId, JsonrpcNotification notification) { if (this.server == null) { return; } var wsDatas = this.getWsDatasForEdgeId(edgeId); - OpenemsNamedException exception = null; for (WsData wsData : wsDatas) { if (!wsData.isEdgeSubscribed(edgeId)) { continue; } - try { - wsData.send(notification); - } catch (OpenemsNamedException e) { - exception = e; - } - } - if (exception != null) { - throw exception; + wsData.send(notification); } } diff --git a/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/WebsocketServer.java b/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/WebsocketServer.java index 9f8212b9b44..321a4fc9f9d 100644 --- a/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/WebsocketServer.java +++ b/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/WebsocketServer.java @@ -2,42 +2,34 @@ import org.java_websocket.WebSocket; import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.exceptions.OpenemsException; -import io.openems.common.jsonrpc.base.JsonrpcMessage; import io.openems.common.websocket.AbstractWebsocketServer; +import io.openems.common.websocket.OnClose; +import io.openems.common.websocket.OnOpen; public class WebsocketServer extends AbstractWebsocketServer { - private final Logger log = LoggerFactory.getLogger(WebsocketServer.class); - protected final UiWebsocketImpl parent; - private final OnOpen onOpen; private final OnRequest onRequest; private final OnNotification onNotification; private final OnError onError; - private final OnClose onClose; - public WebsocketServer(UiWebsocketImpl parent, String name, int port, int poolSize, DebugMode debugMode) { - super(name, port, poolSize, debugMode); + public WebsocketServer(UiWebsocketImpl parent, String name, int port, int poolSize) { + super(name, port, poolSize); this.parent = parent; - this.onOpen = new OnOpen(parent); this.onRequest = new OnRequest(parent); this.onNotification = new OnNotification(parent); this.onError = new OnError(parent); - this.onClose = new OnClose(parent); } @Override - protected WsData createWsData() { - return new WsData(this); + protected WsData createWsData(WebSocket ws) { + return new WsData(ws); } @Override protected OnOpen getOnOpen() { - return this.onOpen; + return OnOpen.NO_OP; } @Override @@ -57,14 +49,7 @@ protected OnError getOnError() { @Override protected OnClose getOnClose() { - return this.onClose; - } - - @Override - protected JsonrpcMessage handleNonJsonrpcMessage(WebSocket ws, String stringMessage, - OpenemsNamedException lastException) throws OpenemsNamedException { - this.log.info("UiWs. handleNonJsonrpcMessage: " + stringMessage); - throw new OpenemsException("UiWs. handleNonJsonrpcMessage", lastException); + return OnClose.NO_OP; } @Override diff --git a/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/WsData.java b/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/WsData.java index 885e71cb4d6..c60424b0d3d 100644 --- a/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/WsData.java +++ b/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/WsData.java @@ -9,8 +9,7 @@ import java.util.SortedSet; import java.util.UUID; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.java_websocket.WebSocket; import com.google.gson.JsonElement; @@ -19,7 +18,6 @@ import io.openems.backend.common.metadata.User; import io.openems.common.exceptions.OpenemsError; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.exceptions.OpenemsException; import io.openems.common.jsonrpc.notification.CurrentDataNotification; import io.openems.common.jsonrpc.notification.EdgeRpcNotification; import io.openems.common.jsonrpc.request.SubscribeChannelsRequest; @@ -28,13 +26,9 @@ public class WsData extends io.openems.common.websocket.WsData { private static class SubscribedChannels { - private static final Logger LOG = LoggerFactory.getLogger(SubscribedChannels.class); - private int lastRequestCount = Integer.MIN_VALUE; private final Map> subscribedChannels = new HashMap<>(); - private Set currentDataMissingChannelValues = Collections.emptySet(); - /** * Applies a SubscribeChannelsRequest. * @@ -61,13 +55,6 @@ public Map getChannelValues(String edgeId, EdgeCache edgeCa } var result = edgeCache.getChannelValues(subscribedChannels); - if (!result.b().isEmpty()) { - if (!result.b().equals(this.currentDataMissingChannelValues)) { - LOG.info("[" + edgeId + "] Channels missing in Current-Data: [" + String.join(", ", result.b()) - + "]"); - } - this.currentDataMissingChannelValues = result.b(); - } return result.a(); } @@ -76,19 +63,16 @@ protected void dispose() { } } - private final Logger log = LoggerFactory.getLogger(WsData.class); - private final UUID id = UUID.randomUUID(); - private final WebsocketServer parent; private final SubscribedChannels subscribedChannels = new SubscribedChannels(); private Optional userId = Optional.empty(); private Optional token = Optional.empty(); private Set subscribedEdges = new HashSet<>(); - public WsData(WebsocketServer parent) { - this.parent = parent; + public WsData(WebSocket ws) { + super(ws); } /** @@ -214,16 +198,9 @@ public void sendSubscribedChannels(String edgeId, EdgeCache edgeCache) { if (values.isEmpty()) { return; } - try { - this.send(// - new EdgeRpcNotification(edgeId, // - new CurrentDataNotification(values))); - - } catch (OpenemsException e) { - // Log & stop subscribes - this.parent.logWarn(this.log, "Unable to send CurrentDataNotification: " + e.getMessage()); - this.subscribedChannels.dispose(); - } + this.send(// + new EdgeRpcNotification(edgeId, // + new CurrentDataNotification(values))); } /** diff --git a/io.openems.common/src/io/openems/common/exceptions/OpenemsError.java b/io.openems.common/src/io/openems/common/exceptions/OpenemsError.java index 5f43f05d9b5..36b11e48cb3 100644 --- a/io.openems.common/src/io/openems/common/exceptions/OpenemsError.java +++ b/io.openems.common/src/io/openems/common/exceptions/OpenemsError.java @@ -24,6 +24,7 @@ public enum OpenemsError { COMMON_AUTHENTICATION_FAILED(1003, "Authentication failed"), // COMMON_USER_UNDEFINED(1004, "User [%s] is not defined"), // COMMON_ROLE_UNDEFINED(1005, "Access to this resource [%s] is denied. Role for User [%s] is not defined"), // + COMMON_SERVICE_NOT_AVAILABLE(1006, "This service is currently not available. Please try again later"), // /* * Edge errors. 2000-2999 */ @@ -46,6 +47,7 @@ public enum OpenemsError { JSONRPC_UNHANDLED_METHOD(4001, "Unhandled JSON-RPC method [%s]"), // JSONRPC_INVALID_MESSAGE(4002, "JSON-RPC Message is not a valid Request, Result or Notification: %s"), // JSONRPC_RESPONSE_WITHOUT_REQUEST(4003, "Got Response without Request: %s"), // + JSONRPC_SEND_FAILED(4004, "Send failed"), // /* * JSON Errors. 5000-5999 diff --git a/io.openems.common/src/io/openems/common/websocket/AbstractWebsocket.java b/io.openems.common/src/io/openems/common/websocket/AbstractWebsocket.java index 5e89a3c20d4..c76b34dd560 100644 --- a/io.openems.common/src/io/openems/common/websocket/AbstractWebsocket.java +++ b/io.openems.common/src/io/openems/common/websocket/AbstractWebsocket.java @@ -1,18 +1,30 @@ package io.openems.common.websocket; +import static io.openems.common.utils.JsonrpcUtils.simplifyJsonrpcMessage; +import static io.openems.common.utils.StringUtils.toShortString; +import static io.openems.common.websocket.WebsocketUtils.generateWsDataString; + +import org.java_websocket.WebSocket; +import org.java_websocket.exceptions.WebsocketNotConnectedException; import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.openems.common.jsonrpc.base.JsonrpcMessage; public abstract class AbstractWebsocket { + private final Logger log = LoggerFactory.getLogger(AbstractWebsocket.class); + private final String name; /** - * Creates an empty WsData object that is attached to the WebSocket as early as - * possible. - * + * Creates an empty WsData object that is attached to the given + * {@link WebSocket} as early as possible. + * + * @param ws the {@link WebSocket} * @return the typed {@link WsData} */ - protected abstract T createWsData(); + protected abstract T createWsData(WebSocket ws); /** * Callback for internal error. @@ -86,25 +98,43 @@ protected void stop() { * * @param command the {@link Runnable} */ - protected abstract void execute(Runnable command) throws Exception; + protected abstract void execute(Runnable command); /** - * Handles an internal Error asynchronously. - * - * @param t the {@link Throwable} to be handled - * @param wsDataString the toString() content of the WsData attachment of the - * WebSocket + * Sends a {@link JsonrpcMessage} to the {@link WebSocket}. Returns true if + * sending was successful, otherwise false. Also logs a warning in that case. + * + * @param ws the {@link WebSocket} + * @param message the {@link JsonrpcMessage} + * @return true if sending was successful */ - protected void handleInternalErrorAsync(Throwable t, String wsDataString) { + protected final boolean sendMessage(WebSocket ws, JsonrpcMessage message) { + if (!ws.isOpen()) { + // Catch status before to avoid throwing an expensive + // WebsocketNotConnectedException + this.sendMessageFailedLog(ws, message); + return false; + } + try { - this.execute(new OnInternalErrorHandler(this.getOnInternalError(), t, wsDataString)); + ws.send(message.toString()); + return true; - } catch (Throwable t1) { - this.handleInternalErrorSync(t, wsDataString); - this.handleInternalErrorSync(t1, wsDataString); + } catch (WebsocketNotConnectedException e) { + // Fallback for race condition if Connection was closed inbetween + this.sendMessageFailedLog(ws, message); + return false; } } + private void sendMessageFailedLog(WebSocket ws, JsonrpcMessage message) { + this.logWarn(this.log, new StringBuilder() // + .append("[").append(generateWsDataString(ws)) // + .append("] Unable to send message: Connection is closed. ") // + .append(toShortString(simplifyJsonrpcMessage(message), 100)) // + .toString()); + } + /** * Handles an internal Error synchronously. * @@ -112,8 +142,8 @@ protected void handleInternalErrorAsync(Throwable t, String wsDataString) { * @param wsDataString the toString() content of the WsData attachment of the * WebSocket */ - protected void handleInternalErrorSync(Throwable t, String wsDataString) { - this.getOnInternalError().run(t, wsDataString); + protected void handleInternalError(Throwable t, String wsDataString) { + this.getOnInternalError().accept(t, wsDataString); } /** diff --git a/io.openems.common/src/io/openems/common/websocket/AbstractWebsocketClient.java b/io.openems.common/src/io/openems/common/websocket/AbstractWebsocketClient.java index 79c805a69c3..23ea41409e3 100644 --- a/io.openems.common/src/io/openems/common/websocket/AbstractWebsocketClient.java +++ b/io.openems.common/src/io/openems/common/websocket/AbstractWebsocketClient.java @@ -6,24 +6,19 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; +import org.java_websocket.WebSocket; import org.java_websocket.client.WebSocketClient; import org.java_websocket.drafts.Draft; import org.java_websocket.drafts.Draft_6455; -import org.java_websocket.exceptions.WebsocketNotConnectedException; import org.java_websocket.extensions.permessage_deflate.PerMessageDeflateExtension; import org.java_websocket.framing.CloseFrame; import org.java_websocket.handshake.ServerHandshake; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.exceptions.OpenemsException; import io.openems.common.jsonrpc.base.JsonrpcMessage; -import io.openems.common.jsonrpc.base.JsonrpcNotification; import io.openems.common.jsonrpc.base.JsonrpcRequest; -import io.openems.common.jsonrpc.base.JsonrpcResponse; import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; -import io.openems.common.utils.StringUtils; /** * A Websocket Client implementation that automatically tries to reconnect a @@ -68,75 +63,44 @@ private void logInfo(String message) { @Override public void onOpen(ServerHandshake handshake) { - try { - var jHandshake = WebsocketUtils.handshakeToJsonObject(handshake); - AbstractWebsocketClient.this.execute(new OnOpenHandler(AbstractWebsocketClient.this, - AbstractWebsocketClient.this.ws, jHandshake)); - - } catch (Exception e) { - AbstractWebsocketClient.this.handleInternalErrorSync(e, - WebsocketUtils.getWsDataString(AbstractWebsocketClient.this.ws)); - } + AbstractWebsocketClient.this.execute(new OnOpenHandler(// + AbstractWebsocketClient.this.ws, handshake, // + AbstractWebsocketClient.this.getOnOpen(), // + AbstractWebsocketClient.this::logWarn, // + AbstractWebsocketClient.this::handleInternalError)); } @Override - public void onMessage(String stringMessage) { - final JsonrpcMessage message; - try { - message = JsonrpcMessage.from(stringMessage); - } catch (OpenemsNamedException e) { - AbstractWebsocketClient.this.handleInternalErrorAsync(e, - WebsocketUtils.getWsDataString(AbstractWebsocketClient.this.ws)); - return; - } - - try { - if (message instanceof JsonrpcRequest) { - AbstractWebsocketClient.this.execute(new OnRequestHandler(AbstractWebsocketClient.this, - AbstractWebsocketClient.this.ws, (JsonrpcRequest) message, response -> { - AbstractWebsocketClient.this.sendMessage(response); - })); - - } else if (message instanceof JsonrpcResponse) { - AbstractWebsocketClient.this.execute(new OnResponseHandler(AbstractWebsocketClient.this, - AbstractWebsocketClient.this.ws, (JsonrpcResponse) message)); - - } else if (message instanceof JsonrpcNotification) { - AbstractWebsocketClient.this.execute(new OnNotificationHandler(AbstractWebsocketClient.this, - AbstractWebsocketClient.this.ws, (JsonrpcNotification) message)); - } - - } catch (Exception e) { - AbstractWebsocketClient.this.handleInternalErrorSync(e, - WebsocketUtils.getWsDataString(AbstractWebsocketClient.this.ws)); - } + public void onMessage(String message) { + AbstractWebsocketClient.this.execute(new OnMessageHandler(// + AbstractWebsocketClient.this.ws, message, // + AbstractWebsocketClient.this.getOnRequest(), // + AbstractWebsocketClient.this.getOnNotification(), // + AbstractWebsocketClient.this::sendMessage, // + AbstractWebsocketClient.this::handleInternalError, // + AbstractWebsocketClient.this::logWarn)); } @Override public void onError(Exception ex) { - try { - AbstractWebsocketClient.this.execute( - new OnErrorHandler(AbstractWebsocketClient.this, AbstractWebsocketClient.this.ws, ex)); - - } catch (Exception e) { - AbstractWebsocketClient.this.handleInternalErrorSync(e, - WebsocketUtils.getWsDataString(AbstractWebsocketClient.this.ws)); - } + AbstractWebsocketClient.this.execute(new OnErrorHandler(// + AbstractWebsocketClient.this.ws, ex, // + AbstractWebsocketClient.this.getOnError(), // + AbstractWebsocketClient.this::handleInternalError)); } @Override public void onClose(int code, String reason, boolean remote) { - try { - AbstractWebsocketClient.this.execute(new OnCloseHandler(AbstractWebsocketClient.this, - AbstractWebsocketClient.this.ws, code, reason, remote)); - - } catch (Exception e) { - AbstractWebsocketClient.this.handleInternalErrorSync(e, - WebsocketUtils.getWsDataString(AbstractWebsocketClient.this.ws)); - } - - this.logInfo( - "Websocket [" + serverUri.toString() + "] closed. Code [" + code + "] Reason [" + reason + "]"); + AbstractWebsocketClient.this.execute(new OnCloseHandler(// + AbstractWebsocketClient.this.ws, code, reason, remote, // + AbstractWebsocketClient.this.getOnClose(), // + AbstractWebsocketClient.this::handleInternalError)); + + this.logInfo(new StringBuilder() // + .append("Websocket [").append(serverUri.toString()) // + .append("] closed. Code [").append(code) // + .append("] Reason [").append(reason).append("]") // + .toString()); AbstractWebsocketClient.this.reconnectorWorker.triggerNextRun(); } }; @@ -144,8 +108,7 @@ public void onClose(int code, String reason, boolean remote) { this.ws.setConnectionLostTimeout(100); // initialize WsData - var wsData = AbstractWebsocketClient.this.createWsData(); - wsData.setWebsocket(this.ws); + var wsData = AbstractWebsocketClient.this.createWsData(this.ws); this.ws.setAttachment(wsData); // Initialize reconnector @@ -167,7 +130,7 @@ public void start() { } /** - * Starts the websocket client; waiting till it started. + * Starts the {@link WebSocketClient}; waiting till it started. * * @throws InterruptedException on waiting error */ @@ -189,49 +152,26 @@ public void stop() { this.ws.close(CloseFrame.NORMAL, "Closing connection [" + this.getName() + "]"); } - @Override - protected OnInternalError getOnInternalError() { - return (t, wsDataString) -> { - this.logError(this.log, - "OnInternalError for " + wsDataString + ". " + t.getClass() + ": " + t.getMessage()); - t.printStackTrace(); - }; - } - /** - * Sends a {@link JsonrpcMessage}. + * Sends a {@link JsonrpcMessage} to the {@link WebSocket}. Returns true if + * sending was successful, otherwise false. Also logs a warning in that case. * * @param message the {@link JsonrpcMessage} - * @throws OpenemsException on error, e.g. if the websocket is not connected - */ - public void sendMessageOrError(JsonrpcMessage message) throws OpenemsException { - try { - this.ws.send(message.toString()); - } catch (Exception e) { - if (e instanceof WebsocketNotConnectedException) { - AbstractWebsocketClient.this.reconnectorWorker.triggerNextRun(); - } - throw new OpenemsException("Unable to send JSON-RPC message. " + e.getClass().getSimpleName() + ": " - + StringUtils.toShortString(message.toString(), 100)); - } - } - - /** - * Sends a JSON-RPC message. Returns true if sending was successful, otherwise - * false. Also logs a warning in that case. - * - * @param message the {@link JsonrpcMessage}. * @return true if sending was successful */ public boolean sendMessage(JsonrpcMessage message) { - try { - this.sendMessageOrError(message); - return true; + return this.sendMessage(this.ws, message); + } - } catch (OpenemsException e) { - this.logWarn(this.log, e.getMessage()); - return false; - } + @Override + protected OnInternalError getOnInternalError() { + return (t, wsDataString) -> { + this.logError(this.log, new StringBuilder() // + .append("OnInternalError for ").append(wsDataString).append(". ") // + .append(t.getClass()).append(": ").append(t.getMessage()) // + .toString()); + t.printStackTrace(); + }; } /** @@ -239,9 +179,8 @@ public boolean sendMessage(JsonrpcMessage message) { * * @param request the JSON-RPC Request * @return the future JSON-RPC Response - * @throws OpenemsNamedException on error */ - public CompletableFuture sendRequest(JsonrpcRequest request) throws OpenemsNamedException { + public CompletableFuture sendRequest(JsonrpcRequest request) { WsData wsData = this.ws.getAttachment(); return wsData.send(request); } diff --git a/io.openems.common/src/io/openems/common/websocket/AbstractWebsocketServer.java b/io.openems.common/src/io/openems/common/websocket/AbstractWebsocketServer.java index 72880facf42..64a90b1bda4 100644 --- a/io.openems.common/src/io/openems/common/websocket/AbstractWebsocketServer.java +++ b/io.openems.common/src/io/openems/common/websocket/AbstractWebsocketServer.java @@ -1,23 +1,19 @@ package io.openems.common.websocket; +import static io.openems.common.utils.ThreadPoolUtils.shutdownAndAwaitTermination; + import java.net.BindException; import java.net.InetSocketAddress; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Function; import org.java_websocket.WebSocket; -import org.java_websocket.drafts.Draft; -import org.java_websocket.drafts.Draft_6455; -import org.java_websocket.exceptions.WebsocketNotConnectedException; -import org.java_websocket.extensions.permessage_deflate.PerMessageDeflateExtension; import org.java_websocket.handshake.ClientHandshake; import org.java_websocket.server.WebSocketServer; import org.slf4j.Logger; @@ -25,58 +21,29 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder; -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.exceptions.OpenemsException; import io.openems.common.jsonrpc.base.JsonrpcMessage; -import io.openems.common.jsonrpc.base.JsonrpcNotification; -import io.openems.common.jsonrpc.base.JsonrpcRequest; -import io.openems.common.jsonrpc.base.JsonrpcResponse; -import io.openems.common.utils.JsonrpcUtils; -import io.openems.common.utils.StringUtils; import io.openems.common.utils.ThreadPoolUtils; public abstract class AbstractWebsocketServer extends AbstractWebsocket { - public static enum DebugMode { - OFF, SIMPLE, DETAILED; - - /** - * Is this {@link DebugMode} at least as high as the other {@link DebugMode}?. - * - * @param other the other {@link DebugMode} - * @return true if yes - */ - public boolean isAtLeast(DebugMode other) { - return this.ordinal() >= other.ordinal(); - } - } - /** * Shared {@link ExecutorService}. */ private final ThreadPoolExecutor executor; - private final ConcurrentHashMap activeTasks = new ConcurrentHashMap<>(100); - private static final Function ATOMIC_INTEGER_PROVIDER = (key) -> { - return new AtomicInteger(0); - }; - private final Logger log = LoggerFactory.getLogger(AbstractWebsocketServer.class); private final int port; private final WebSocketServer ws; - private final DebugMode debugMode; private final Collection connections = ConcurrentHashMap.newKeySet(); - private final Draft perMessageDeflateDraft = new Draft_6455(new PerMessageDeflateExtension()); /** * Construct an {@link AbstractWebsocketServer}. * - * @param name to identify this server - * @param port to listen on - * @param poolSize number of threads dedicated to handle the tasks - * @param debugMode activate a regular debug log about the state of the tasks + * @param name to identify this server + * @param port to listen on + * @param poolSize number of threads dedicated to handle the tasks */ - protected AbstractWebsocketServer(String name, int port, int poolSize, DebugMode debugMode) { + protected AbstractWebsocketServer(String name, int port, int poolSize) { super(name); this.executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(poolSize, new ThreadFactoryBuilder().setNameFormat(name + "-%d").build()); @@ -84,7 +51,7 @@ protected AbstractWebsocketServer(String name, int port, int poolSize, DebugMode this.port = port; this.ws = new WebSocketServer(new InetSocketAddress(port), /* AVAILABLE_PROCESSORS */ Runtime.getRuntime().availableProcessors(), // - /* enable perMessageDeflate */ Collections.singletonList(this.perMessageDeflateDraft), // + /* drafts, no filter */ List.of(new MyDraft6455()), // this.connections) { @Override @@ -93,83 +60,40 @@ public void onStart() { @Override public void onOpen(WebSocket ws, ClientHandshake handshake) { - try { - T wsData = AbstractWebsocketServer.this.createWsData(); - wsData.setWebsocket(ws); - ws.setAttachment(wsData); - var jHandshake = WebsocketUtils.handshakeToJsonObject(handshake); - AbstractWebsocketServer.this - .execute(new OnOpenHandler(AbstractWebsocketServer.this, ws, jHandshake)); - - } catch (Throwable t) { - AbstractWebsocketServer.this.handleInternalErrorSync(t, WebsocketUtils.getWsDataString(ws)); - } + T wsData = AbstractWebsocketServer.this.createWsData(ws); + ws.setAttachment(wsData); + AbstractWebsocketServer.this.execute(new OnOpenHandler(// + ws, handshake, // + AbstractWebsocketServer.this.getOnOpen(), // + AbstractWebsocketServer.this::logWarn, // + AbstractWebsocketServer.this::handleInternalError)); } @Override - public void onMessage(WebSocket ws, String stringMessage) { - try { - JsonrpcMessage message; - try { - try { - message = JsonrpcMessage.from(stringMessage); - - } catch (OpenemsNamedException e) { - // handle deprecated non-JSON-RPC messages - message = AbstractWebsocketServer.this.handleNonJsonrpcMessage(ws, stringMessage, e); - } - if (message == null) { - // silently ignore 'null' - return; - } - } catch (OpenemsNamedException e) { - AbstractWebsocketServer.this.handleInternalErrorAsync(e, WebsocketUtils.getWsDataString(ws)); - return; - } - - if (message instanceof JsonrpcRequest) { - AbstractWebsocketServer.this.execute(new OnRequestHandler(AbstractWebsocketServer.this, ws, - (JsonrpcRequest) message, response -> { - AbstractWebsocketServer.this.sendMessage(ws, response); - })); - - } else if (message instanceof JsonrpcResponse) { - AbstractWebsocketServer.this.execute( - new OnResponseHandler(AbstractWebsocketServer.this, ws, (JsonrpcResponse) message)); - - } else if (message instanceof JsonrpcNotification) { - AbstractWebsocketServer.this.execute(new OnNotificationHandler(AbstractWebsocketServer.this, ws, - (JsonrpcNotification) message)); - } - - } catch (Throwable t) { - AbstractWebsocketServer.this.handleInternalErrorSync(t, WebsocketUtils.getWsDataString(ws)); - } + public void onMessage(WebSocket ws, String message) { + AbstractWebsocketServer.this.execute(new OnMessageHandler(// + ws, message, // + AbstractWebsocketServer.this.getOnRequest(), // + AbstractWebsocketServer.this.getOnNotification(), // + AbstractWebsocketServer.this::sendMessage, // + AbstractWebsocketServer.this::handleInternalError, // + AbstractWebsocketServer.this::logWarn)); } @Override public void onError(WebSocket ws, Exception ex) { - try { - if (ws == null) { - AbstractWebsocketServer.this.handleInternalErrorAsync(ex, WebsocketUtils.getWsDataString(ws)); - } else { - AbstractWebsocketServer.this.execute(new OnErrorHandler(AbstractWebsocketServer.this, ws, ex)); - } - - } catch (Throwable t) { - AbstractWebsocketServer.this.handleInternalErrorSync(t, WebsocketUtils.getWsDataString(ws)); - } + AbstractWebsocketServer.this.execute(new OnErrorHandler(// + ws, ex, // + AbstractWebsocketServer.this.getOnError(), // + AbstractWebsocketServer.this::handleInternalError)); } @Override public void onClose(WebSocket ws, int code, String reason, boolean remote) { - try { - AbstractWebsocketServer.this - .execute(new OnCloseHandler(AbstractWebsocketServer.this, ws, code, reason, remote)); - - } catch (Throwable t) { - AbstractWebsocketServer.this.handleInternalErrorSync(t, WebsocketUtils.getWsDataString(ws)); - } + AbstractWebsocketServer.this.execute(new OnCloseHandler(// + ws, code, reason, remote, // + AbstractWebsocketServer.this.getOnClose(), // + AbstractWebsocketServer.this::handleInternalError)); } @Override @@ -205,12 +129,10 @@ public Collection getConnections() { return AbstractWebsocketServer.this.connections; } }; + // Allow the port to be reused. See // https://stackoverflow.com/questions/3229860/what-is-the-meaning-of-so-reuseaddr-setsockopt-option-linux this.ws.setReuseAddr(true); - - // Debug-Mode - this.debugMode = debugMode == null ? DebugMode.OFF : debugMode; } /** @@ -219,20 +141,10 @@ public Collection getConnections() { * @return the debug log string */ public String debugLog() { - var b = new StringBuilder("[monitor] ") // - .append("Connections: ").append(this.ws.getConnections().size()).append(", ") // - .append(ThreadPoolUtils.debugLog(this.executor)); // - if (this.debugMode.isAtLeast(DebugMode.DETAILED) && this.executor.getActiveCount() > 0) { - b.append(", Tasks: "); - this.activeTasks.forEach((id, count) -> { - var cnt = count.get(); - if (cnt > 0) { - b.append(id).append(':').append(cnt).append(", "); - } - }); - } - - return b.toString(); + return new StringBuilder("[monitor] ") // + .append("Connections: ").append(this.connections.size()).append(", ") // + .append(ThreadPoolUtils.debugLog(this.executor)) // + .toString(); } /** @@ -253,8 +165,10 @@ protected OnInternalError getOnInternalError() { if (t instanceof BindException) { this.logError(this.log, "Unable to Bind to port [" + this.port + "]"); } else { - this.logError(this.log, - "OnInternalError for " + wsDataString + ". " + t.getClass() + ": " + t.getMessage()); + this.logError(this.log, new StringBuilder() // + .append("OnInternalError for ").append(wsDataString).append(". ") // + .append(t.getClass()).append(": ") // + .append(t.getMessage()).toString()); } t.printStackTrace(); }; @@ -265,35 +179,12 @@ public Collection getConnections() { } /** - * Sends a message to WebSocket. - * - * @param ws the WebSocket - * @param message the JSON-RPC Message - */ - public void sendMessage(WebSocket ws, JsonrpcMessage message) { - try { - ws.send(message.toString()); - - } catch (WebsocketNotConnectedException e) { - WsData wsData = ws.getAttachment(); - - if (wsData != null) { - this.logWarn(this.log, "Connection [" + wsData.toString() + "] is closed. Unable to send message: " - + StringUtils.toShortString(JsonrpcUtils.simplifyJsonrpcMessage(message), 100)); - } else { - this.logWarn(this.log, "Connection is closed. Unable to send message: " - + StringUtils.toShortString(JsonrpcUtils.simplifyJsonrpcMessage(message), 100)); - } - } - } - - /** - * Broadcasts a message to all connected WebSockets. + * Broadcasts a {@link JsonrpcMessage} to all connected WebSockets. * - * @param message the JSON-RPC Message + * @param message the {@link JsonrpcMessage} */ public void broadcastMessage(JsonrpcMessage message) { - for (WebSocket ws : this.getConnections()) { + for (var ws : this.getConnections()) { this.sendMessage(ws, message); } } @@ -308,7 +199,7 @@ public int getPort() { } /** - * Starts the websocket server. + * Starts the {@link WebSocketServer}. */ @Override public void start() { @@ -324,37 +215,16 @@ public void start() { */ @Override protected void execute(Runnable command) { - if (this.debugMode.isAtLeast(DebugMode.DETAILED)) { - this.executor.execute(() -> { - String id = AbstractWebsocketServer.getRunnableIdentifier(command); - try { - this.activeTasks.computeIfAbsent(id, ATOMIC_INTEGER_PROVIDER).incrementAndGet(); - command.run(); - } catch (Throwable t) { - throw t; - } finally { - this.activeTasks.get(id).decrementAndGet(); - } - }); - } else { - this.executor.execute(command); - } - } - - private static final String getRunnableIdentifier(Runnable r) { - if (r instanceof OnRequestHandler) { - return ((OnRequestHandler) r).getRequestMethod(); - } - return r.getClass().getSimpleName(); + this.executor.execute(command); } /** - * Stops the websocket server. + * Stops the {@link WebSocketServer}. */ @Override public void stop() { // Shutdown executors - ThreadPoolUtils.shutdownAndAwaitTermination(this.executor, 5); + shutdownAndAwaitTermination(this.executor, 5); var tries = 3; while (tries-- > 0) { @@ -374,19 +244,4 @@ public void stop() { this.logError(this.log, "Stopping websocket server failed too often."); super.stop(); } - - /** - * Handle Non-JSON-RPC messages. - * - * @param ws the {@link WebSocket} - * @param stringMessage the message - * @param e the parse error - * @return message converted to {@link JsonrpcMessage}; or null - * @throws OpenemsNamedException if conversion is not possible - */ - protected JsonrpcMessage handleNonJsonrpcMessage(WebSocket ws, String stringMessage, OpenemsNamedException e) - throws OpenemsNamedException { - throw new OpenemsException("Unhandled Non-JSON-RPC message", e); - } - } diff --git a/io.openems.common/src/io/openems/common/websocket/ClientReconnectorWorker.java b/io.openems.common/src/io/openems/common/websocket/ClientReconnectorWorker.java index fc6f95c41a1..23fabe595e1 100644 --- a/io.openems.common/src/io/openems/common/websocket/ClientReconnectorWorker.java +++ b/io.openems.common/src/io/openems/common/websocket/ClientReconnectorWorker.java @@ -7,8 +7,9 @@ import java.util.Random; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import java.util.function.Supplier; +import java.util.function.Function; +import org.java_websocket.WebSocket; import org.java_websocket.WebSocketImpl; import org.java_websocket.client.WebSocketClient; import org.java_websocket.drafts.Draft; @@ -90,12 +91,12 @@ protected void forever() throws Exception { * Waiting for https://github.com/TooTallNate/Java-WebSocket/pull/1251 to be * merged. * - * @param the type of the attachment - * @param ws the {@link WebSocketClient} - * @param attachmentSupplier the supplier for the new attachment + * @param the type of the attachment + * @param ws the {@link WebSocketClient} + * @param wsData {@link Function} to provide a the new attachment * @throws Exception on error */ - protected static void resetWebSocketClient(WebSocketClient ws, Supplier attachmentSupplier) + protected static void resetWebSocketClient(WebSocketClient ws, Function wsData) throws Exception { /* * Get methods and fields via Reflection @@ -168,8 +169,7 @@ protected static void resetWebSocketClient(WebSocketClient ws closeLatchField.set(ws, new CountDownLatch(1)); // this.engine = new WebSocketImpl(this, this.draft); -> to reflection final var newEngine = new WebSocketImpl(ws, draft); - final var newAttachment = attachmentSupplier.get(); - newAttachment.setWebsocket(ws); + final var newAttachment = wsData.apply(ws); newEngine.setAttachment(newAttachment); engineField.set(ws, newEngine); } diff --git a/io.openems.common/src/io/openems/common/websocket/DummyWebsocketServer.java b/io.openems.common/src/io/openems/common/websocket/DummyWebsocketServer.java index 9c32681f1d8..b815deeb71c 100644 --- a/io.openems.common/src/io/openems/common/websocket/DummyWebsocketServer.java +++ b/io.openems.common/src/io/openems/common/websocket/DummyWebsocketServer.java @@ -1,23 +1,16 @@ package io.openems.common.websocket; +import org.java_websocket.WebSocket; import org.slf4j.Logger; -import io.openems.common.exceptions.NotImplementedException; - public class DummyWebsocketServer extends AbstractWebsocketServer implements AutoCloseable { public static class Builder { - private OnOpen onOpen = (ws, handshake) -> { - }; - private OnRequest onRequest = (ws, request) -> { - throw new NotImplementedException("On-Request handler is not implemented"); - }; - private OnNotification onNotification = (ws, notification) -> { - }; - private OnError onError = (ws, ex) -> { - }; - private OnClose onClose = (ws, code, reason, remote) -> { - }; + private OnOpen onOpen = OnOpen.NO_OP; + private OnRequest onRequest = OnRequest.NO_OP; + private OnNotification onNotification = OnNotification.NO_OP; + private OnError onError = OnError.NO_OP; + private OnClose onClose = OnClose.NO_OP; private Builder() { } @@ -94,13 +87,18 @@ public static DummyWebsocketServer.Builder create() { private final DummyWebsocketServer.Builder builder; private DummyWebsocketServer(DummyWebsocketServer.Builder builder) { - super("DummyWebsocketServer", 0 /* auto-select port */, 1 /* pool size */, DebugMode.OFF); + super("DummyWebsocketServer", 0 /* auto-select port */, 1 /* pool size */); this.builder = builder; } @Override - protected WsData createWsData() { - return new DummyWsData(); + protected WsData createWsData(WebSocket ws) { + return new WsData(ws) { + @Override + public String toString() { + return "DummyWebsocketServer.WsData []"; + } + }; } @Override @@ -144,7 +142,7 @@ protected void logError(Logger log, String message) { } @Override - public void close() throws Exception { + public void close() { this.stop(); } } diff --git a/io.openems.common/src/io/openems/common/websocket/DummyWsData.java b/io.openems.common/src/io/openems/common/websocket/DummyWsData.java deleted file mode 100644 index 755b42a79d6..00000000000 --- a/io.openems.common/src/io/openems/common/websocket/DummyWsData.java +++ /dev/null @@ -1,10 +0,0 @@ -package io.openems.common.websocket; - -public class DummyWsData extends WsData { - - @Override - public String toString() { - return "DummyWsData[]"; - } - -} \ No newline at end of file diff --git a/io.openems.common/src/io/openems/common/websocket/MyDraft6455.java b/io.openems.common/src/io/openems/common/websocket/MyDraft6455.java new file mode 100644 index 00000000000..a89e41b5d39 --- /dev/null +++ b/io.openems.common/src/io/openems/common/websocket/MyDraft6455.java @@ -0,0 +1,1221 @@ +package io.openems.common.websocket; + +import java.math.BigInteger; +import java.nio.ByteBuffer; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Objects; +import java.util.TimeZone; + +import org.java_websocket.WebSocketImpl; +import org.java_websocket.drafts.Draft; +import org.java_websocket.drafts.Draft_6455; +import org.java_websocket.enums.CloseHandshakeType; +import org.java_websocket.enums.HandshakeState; +import org.java_websocket.enums.Opcode; +import org.java_websocket.enums.ReadyState; +import org.java_websocket.enums.Role; +import org.java_websocket.exceptions.InvalidDataException; +import org.java_websocket.exceptions.InvalidFrameException; +import org.java_websocket.exceptions.InvalidHandshakeException; +import org.java_websocket.exceptions.LimitExceededException; +import org.java_websocket.exceptions.NotSendableException; +import org.java_websocket.extensions.DefaultExtension; +import org.java_websocket.extensions.IExtension; +import org.java_websocket.framing.BinaryFrame; +import org.java_websocket.framing.CloseFrame; +import org.java_websocket.framing.Framedata; +import org.java_websocket.framing.FramedataImpl1; +import org.java_websocket.framing.TextFrame; +import org.java_websocket.handshake.ClientHandshake; +import org.java_websocket.handshake.ClientHandshakeBuilder; +import org.java_websocket.handshake.HandshakeBuilder; +import org.java_websocket.handshake.Handshakedata; +import org.java_websocket.handshake.ServerHandshake; +import org.java_websocket.handshake.ServerHandshakeBuilder; +import org.java_websocket.protocols.IProtocol; +import org.java_websocket.protocols.Protocol; +import org.java_websocket.util.Base64; +import org.java_websocket.util.Charsetfunctions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.primitives.Ints; + +/** + * This class is basically a copy of the class {@link Draft_6455}. The only + * difference is that it does not throw a IncompleteException internally instead + * it returns normally in those cases and checks afterwards with an "if" if the + * result is correct. + */ +public class MyDraft6455 extends Draft { + + private static class Either { + public final LEFT left; + public final RIGHT right; + + public static Either right(RIGHT right) { + return new Either(null, Objects.requireNonNull(right)); + } + + public static Either left(LEFT left) { + return new Either(Objects.requireNonNull(left), null); + } + + private Either(LEFT left, RIGHT right) { + super(); + this.left = left; + this.right = right; + } + + } + + /** + * Handshake specific field for the key. + */ + private static final String SEC_WEB_SOCKET_KEY = "Sec-WebSocket-Key"; + + /** + * Handshake specific field for the protocol. + */ + private static final String SEC_WEB_SOCKET_PROTOCOL = "Sec-WebSocket-Protocol"; + + /** + * Handshake specific field for the extension. + */ + private static final String SEC_WEB_SOCKET_EXTENSIONS = "Sec-WebSocket-Extensions"; + + /** + * Handshake specific field for the accept. + */ + private static final String SEC_WEB_SOCKET_ACCEPT = "Sec-WebSocket-Accept"; + + /** + * Handshake specific field for the upgrade. + */ + private static final String UPGRADE = "Upgrade"; + + /** + * Handshake specific field for the connection. + */ + private static final String CONNECTION = "Connection"; + + private final Logger log = LoggerFactory.getLogger(MyDraft6455.class); + + /** + * Attribute for the used extension in this draft. + */ + private IExtension negotiatedExtension = new DefaultExtension(); + + /** + * Attribute for the default extension. + */ + private IExtension defaultExtension = new DefaultExtension(); + + /** + * Attribute for all available extension in this draft. + */ + private List knownExtensions; + + /** + * Current active extension used to decode messages. + */ + private IExtension currentDecodingExtension; + + /** + * Attribute for the used protocol in this draft. + */ + private IProtocol protocol; + + /** + * Attribute for all available protocols in this draft. + */ + private List knownProtocols; + + /** + * Attribute for the current continuous frame. + */ + private Framedata currentContinuousFrame; + + /** + * Attribute for the payload of the current continuous frame. + */ + private final List byteBufferList; + + /** + * Attribute for the current incomplete frame. + */ + private ByteBuffer incompleteframe; + + /** + * Attribute for the reusable random instance. + */ + private final SecureRandom reuseableRandom = new SecureRandom(); + + /** + * Attribute for the maximum allowed size of a frame. + * + * @since 1.4.0 + */ + private int maxFrameSize; + + /** + * Constructor for the websocket protocol specified by RFC 6455 with default + * extensions. + * + * @since 1.3.5 + */ + public MyDraft6455() { + this(Collections.emptyList()); + } + + /** + * Constructor for the websocket protocol specified by RFC 6455 with custom + * extensions. + * + * @param inputExtension the extension which should be used for this draft + * @since 1.3.5 + */ + public MyDraft6455(IExtension inputExtension) { + this(Collections.singletonList(inputExtension)); + } + + /** + * Constructor for the websocket protocol specified by RFC 6455 with custom + * extensions. + * + * @param inputExtensions the extensions which should be used for this draft + * @since 1.3.5 + */ + public MyDraft6455(List inputExtensions) { + this(inputExtensions, Collections.singletonList(new Protocol(""))); + } + + /** + * Constructor for the websocket protocol specified by RFC 6455 with custom + * extensions and protocols. + * + * @param inputExtensions the extensions which should be used for this draft + * @param inputProtocols the protocols which should be used for this draft + * @since 1.3.7 + */ + public MyDraft6455(List inputExtensions, List inputProtocols) { + this(inputExtensions, inputProtocols, Integer.MAX_VALUE); + } + + /** + * Constructor for the websocket protocol specified by RFC 6455 with custom + * extensions and protocols. + * + * @param inputExtensions the extensions which should be used for this draft + * @param inputMaxFrameSize the maximum allowed size of a frame (the real + * payload size, decoded frames can be bigger) + * @since 1.4.0 + */ + public MyDraft6455(List inputExtensions, int inputMaxFrameSize) { + this(inputExtensions, Collections.singletonList(new Protocol("")), inputMaxFrameSize); + } + + /** + * Constructor for the websocket protocol specified by RFC 6455 with custom + * extensions and protocols. + * + * @param inputExtensions the extensions which should be used for this draft + * @param inputProtocols the protocols which should be used for this draft + * @param inputMaxFrameSize the maximum allowed size of a frame (the real + * payload size, decoded frames can be bigger) + * @since 1.4.0 + */ + public MyDraft6455(List inputExtensions, List inputProtocols, int inputMaxFrameSize) { + if (inputExtensions == null || inputProtocols == null || inputMaxFrameSize < 1) { + throw new IllegalArgumentException(); + } + this.knownExtensions = new ArrayList<>(inputExtensions.size()); + this.knownProtocols = new ArrayList<>(inputProtocols.size()); + boolean hasDefault = false; + this.byteBufferList = new ArrayList<>(); + for (IExtension inputExtension : inputExtensions) { + if (inputExtension.getClass().equals(DefaultExtension.class)) { + hasDefault = true; + } + } + this.knownExtensions.addAll(inputExtensions); + // We always add the DefaultExtension to implement the normal RFC 6455 + // specification + if (!hasDefault) { + this.knownExtensions.add(this.knownExtensions.size(), this.negotiatedExtension); + } + this.knownProtocols.addAll(inputProtocols); + this.maxFrameSize = inputMaxFrameSize; + this.currentDecodingExtension = null; + } + + @Override + public HandshakeState acceptHandshakeAsServer(ClientHandshake handshakedata) throws InvalidHandshakeException { + int v = readVersionFrom(handshakedata); + if (v != 13) { + this.log.trace("acceptHandshakeAsServer - Wrong websocket version."); + return HandshakeState.NOT_MATCHED; + } + HandshakeState extensionState = HandshakeState.NOT_MATCHED; + String requestedExtension = handshakedata.getFieldValue(SEC_WEB_SOCKET_EXTENSIONS); + for (IExtension knownExtension : this.knownExtensions) { + if (knownExtension.acceptProvidedExtensionAsServer(requestedExtension)) { + this.negotiatedExtension = knownExtension; + extensionState = HandshakeState.MATCHED; + this.log.trace("acceptHandshakeAsServer - Matching extension found: {}", this.negotiatedExtension); + break; + } + } + HandshakeState protocolState = this + .containsRequestedProtocol(handshakedata.getFieldValue(SEC_WEB_SOCKET_PROTOCOL)); + if (protocolState == HandshakeState.MATCHED && extensionState == HandshakeState.MATCHED) { + return HandshakeState.MATCHED; + } + this.log.trace("acceptHandshakeAsServer - No matching extension or protocol found."); + return HandshakeState.NOT_MATCHED; + } + + private static int readVersionFrom(Handshakedata handshakedata) { + String vers = handshakedata.getFieldValue("Sec-WebSocket-Version"); + final var i = Ints.tryParse(vers); + if (i != null) { + return i; + } + return -1; + } + + /** + * Check if the requested protocol is part of this draft. + * + * @param requestedProtocol the requested protocol + * @return MATCHED if it is matched, otherwise NOT_MATCHED + */ + private HandshakeState containsRequestedProtocol(String requestedProtocol) { + for (IProtocol knownProtocol : this.knownProtocols) { + if (knownProtocol.acceptProvidedProtocol(requestedProtocol)) { + this.protocol = knownProtocol; + this.log.trace("acceptHandshake - Matching protocol found: {}", this.protocol); + return HandshakeState.MATCHED; + } + } + return HandshakeState.NOT_MATCHED; + } + + @Override + public HandshakeState acceptHandshakeAsClient(ClientHandshake request, ServerHandshake response) + throws InvalidHandshakeException { + if (!basicAccept(response)) { + this.log.trace("acceptHandshakeAsClient - Missing/wrong upgrade or connection in handshake."); + return HandshakeState.NOT_MATCHED; + } + if (!request.hasFieldValue(SEC_WEB_SOCKET_KEY) || !response.hasFieldValue(SEC_WEB_SOCKET_ACCEPT)) { + this.log.trace("acceptHandshakeAsClient - Missing Sec-WebSocket-Key or Sec-WebSocket-Accept"); + return HandshakeState.NOT_MATCHED; + } + + String seckeyAnswer = response.getFieldValue(SEC_WEB_SOCKET_ACCEPT); + String seckeyChallenge = request.getFieldValue(SEC_WEB_SOCKET_KEY); + seckeyChallenge = this.generateFinalKey(seckeyChallenge); + + if (!seckeyChallenge.equals(seckeyAnswer)) { + this.log.trace("acceptHandshakeAsClient - Wrong key for Sec-WebSocket-Key."); + return HandshakeState.NOT_MATCHED; + } + HandshakeState extensionState = HandshakeState.NOT_MATCHED; + String requestedExtension = response.getFieldValue(SEC_WEB_SOCKET_EXTENSIONS); + for (IExtension knownExtension : this.knownExtensions) { + if (knownExtension.acceptProvidedExtensionAsClient(requestedExtension)) { + this.negotiatedExtension = knownExtension; + extensionState = HandshakeState.MATCHED; + this.log.trace("acceptHandshakeAsClient - Matching extension found: {}", this.negotiatedExtension); + break; + } + } + HandshakeState protocolState = this.containsRequestedProtocol(response.getFieldValue(SEC_WEB_SOCKET_PROTOCOL)); + if (protocolState == HandshakeState.MATCHED && extensionState == HandshakeState.MATCHED) { + return HandshakeState.MATCHED; + } + this.log.trace("acceptHandshakeAsClient - No matching extension or protocol found."); + return HandshakeState.NOT_MATCHED; + } + + /** + * Getter for the extension which is used by this draft. + * + * @return the extension which is used or null, if handshake is not yet done + */ + public IExtension getExtension() { + return this.negotiatedExtension; + } + + /** + * Getter for all available extensions for this draft. + * + * @return the extensions which are enabled for this draft + */ + public List getKnownExtensions() { + return this.knownExtensions; + } + + /** + * Getter for the protocol which is used by this draft. + * + * @return the protocol which is used or null, if handshake is not yet done or + * no valid protocols + * @since 1.3.7 + */ + public IProtocol getProtocol() { + return this.protocol; + } + + /** + * Getter for the maximum allowed payload size which is used by this draft. + * + * @return the size, which is allowed for the payload + * @since 1.4.0 + */ + public int getMaxFrameSize() { + return this.maxFrameSize; + } + + /** + * Getter for all available protocols for this draft. + * + * @return the protocols which are enabled for this draft + * @since 1.3.7 + */ + public List getKnownProtocols() { + return this.knownProtocols; + } + + @Override + public ClientHandshakeBuilder postProcessHandshakeRequestAsClient(ClientHandshakeBuilder request) { + request.put(UPGRADE, "websocket"); + request.put(CONNECTION, UPGRADE); // to respond to a Connection keep alives + byte[] random = new byte[16]; + this.reuseableRandom.nextBytes(random); + request.put(SEC_WEB_SOCKET_KEY, Base64.encodeBytes(random)); + request.put("Sec-WebSocket-Version", "13");// overwriting the previous + StringBuilder requestedExtensions = new StringBuilder(); + for (IExtension knownExtension : this.knownExtensions) { + if (knownExtension.getProvidedExtensionAsClient() != null + && knownExtension.getProvidedExtensionAsClient().length() != 0) { + if (requestedExtensions.length() > 0) { + requestedExtensions.append(", "); + } + requestedExtensions.append(knownExtension.getProvidedExtensionAsClient()); + } + } + if (requestedExtensions.length() != 0) { + request.put(SEC_WEB_SOCKET_EXTENSIONS, requestedExtensions.toString()); + } + StringBuilder requestedProtocols = new StringBuilder(); + for (IProtocol knownProtocol : this.knownProtocols) { + if (knownProtocol.getProvidedProtocol().length() != 0) { + if (requestedProtocols.length() > 0) { + requestedProtocols.append(", "); + } + requestedProtocols.append(knownProtocol.getProvidedProtocol()); + } + } + if (requestedProtocols.length() != 0) { + request.put(SEC_WEB_SOCKET_PROTOCOL, requestedProtocols.toString()); + } + return request; + } + + @Override + public HandshakeBuilder postProcessHandshakeResponseAsServer(ClientHandshake request, + ServerHandshakeBuilder response) throws InvalidHandshakeException { + response.put(UPGRADE, "websocket"); + response.put(CONNECTION, request.getFieldValue(CONNECTION)); // to respond to a Connection keep alives + String seckey = request.getFieldValue(SEC_WEB_SOCKET_KEY); + if (seckey == null || "".equals(seckey)) { + throw new InvalidHandshakeException("missing Sec-WebSocket-Key"); + } + response.put(SEC_WEB_SOCKET_ACCEPT, this.generateFinalKey(seckey)); + if (this.getExtension().getProvidedExtensionAsServer().length() != 0) { + response.put(SEC_WEB_SOCKET_EXTENSIONS, this.getExtension().getProvidedExtensionAsServer()); + } + if (this.getProtocol() != null && this.getProtocol().getProvidedProtocol().length() != 0) { + response.put(SEC_WEB_SOCKET_PROTOCOL, this.getProtocol().getProvidedProtocol()); + } + response.setHttpStatusMessage("Web Socket Protocol Handshake"); + response.put("Server", "TooTallNate Java-WebSocket"); + response.put("Date", this.getServerTime()); + return response; + } + + @Override + public Draft copyInstance() { + ArrayList newExtensions = new ArrayList<>(); + for (IExtension knownExtension : this.getKnownExtensions()) { + newExtensions.add(knownExtension.copyInstance()); + } + ArrayList newProtocols = new ArrayList<>(); + for (IProtocol knownProtocol : this.getKnownProtocols()) { + newProtocols.add(knownProtocol.copyInstance()); + } + return new MyDraft6455(newExtensions, newProtocols, this.maxFrameSize); + } + + @Override + public ByteBuffer createBinaryFrame(Framedata framedata) { + this.getExtension().encodeFrame(framedata); + if (this.log.isTraceEnabled()) { + this.log.trace("afterEnconding({}): {}", framedata.getPayloadData().remaining(), + (framedata.getPayloadData().remaining() > 1000 ? "too big to display" + : new String(framedata.getPayloadData().array()))); + } + return this.createByteBufferFromFramedata(framedata); + } + + private ByteBuffer createByteBufferFromFramedata(Framedata framedata) { + ByteBuffer mes = framedata.getPayloadData(); + boolean mask = role == Role.CLIENT; + int sizebytes = this.getSizeBytes(mes); + final var buf = ByteBuffer + .allocate(1 + (sizebytes > 1 ? sizebytes + 1 : sizebytes) + (mask ? 4 : 0) + mes.remaining()); + byte optcode = this.fromOpcode(framedata.getOpcode()); + byte one = (byte) (framedata.isFin() ? -128 : 0); + one |= optcode; + if (framedata.isRSV1()) { + one |= this.getRsvByte(1); + } + if (framedata.isRSV2()) { + one |= this.getRsvByte(2); + } + if (framedata.isRSV3()) { + one |= this.getRsvByte(3); + } + buf.put(one); + byte[] payloadlengthbytes = this.toByteArray(mes.remaining(), sizebytes); + assert (payloadlengthbytes.length == sizebytes); + + if (sizebytes == 1) { + buf.put((byte) (payloadlengthbytes[0] | this.getMaskByte(mask))); + } else if (sizebytes == 2) { + buf.put((byte) ((byte) 126 | this.getMaskByte(mask))); + buf.put(payloadlengthbytes); + } else if (sizebytes == 8) { + buf.put((byte) ((byte) 127 | this.getMaskByte(mask))); + buf.put(payloadlengthbytes); + } else { + throw new IllegalStateException("Size representation not supported/specified"); + } + if (mask) { + ByteBuffer maskkey = ByteBuffer.allocate(4); + maskkey.putInt(this.reuseableRandom.nextInt()); + buf.put(maskkey.array()); + for (int i = 0; mes.hasRemaining(); i++) { + buf.put((byte) (mes.get() ^ maskkey.get(i % 4))); + } + } else { + buf.put(mes); + // Reset the position of the bytebuffer e.g. for additional use + mes.flip(); + } + assert (buf.remaining() == 0) : buf.remaining(); + buf.flip(); + return buf; + } + + private Either translateSingleFrame(ByteBuffer buffer) throws InvalidDataException { + if (buffer == null) { + throw new IllegalArgumentException(); + } + int maxpacketsize = buffer.remaining(); + int realpacketsize = 2; + if (!this.isFrameSizeValid(maxpacketsize, realpacketsize)) { + return Either.left(realpacketsize); + } + byte b1 = buffer.get(/* 0 */); + final var fin = b1 >> 8 != 0; + final var rsv1 = (b1 & 0x40) != 0; + final var rsv2 = (b1 & 0x20) != 0; + final var rsv3 = (b1 & 0x10) != 0; + byte b2 = buffer.get(/* 1 */); + boolean mask = (b2 & -128) != 0; + int payloadlength = (byte) (b2 & ~(byte) 128); + Opcode optcode = this.toOpcode((byte) (b1 & 15)); + + if (!(payloadlength >= 0 && payloadlength <= 125)) { + Either payloadData = this.translateSingleFramePayloadLength(buffer, + optcode, payloadlength, maxpacketsize, realpacketsize); + if (payloadData.left != null) { + return Either.left(payloadData.left); + } + payloadlength = payloadData.right.getPayloadLength(); + realpacketsize = payloadData.right.getRealPackageSize(); + } + this.translateSingleFrameCheckLengthLimit(payloadlength); + realpacketsize += (mask ? 4 : 0); + realpacketsize += payloadlength; + + if (!this.isFrameSizeValid(maxpacketsize, realpacketsize)) { + return Either.left(realpacketsize); + } + + ByteBuffer payload = ByteBuffer.allocate(checkAlloc(payloadlength)); + if (mask) { + byte[] maskskey = new byte[4]; + buffer.get(maskskey); + for (int i = 0; i < payloadlength; i++) { + payload.put((byte) (buffer.get(/* payloadstart + i */) ^ maskskey[i % 4])); + } + } else { + payload.put(buffer.array(), buffer.position(), payload.limit()); + buffer.position(buffer.position() + payload.limit()); + } + + FramedataImpl1 frame = FramedataImpl1.get(optcode); + frame.setFin(fin); + frame.setRSV1(rsv1); + frame.setRSV2(rsv2); + frame.setRSV3(rsv3); + payload.flip(); + frame.setPayload(payload); + if (frame.getOpcode() != Opcode.CONTINUOUS) { + // Prioritize the negotiated extension + if (frame.isRSV1() || frame.isRSV2() || frame.isRSV3()) { + this.currentDecodingExtension = this.getExtension(); + } else { + // No encoded message, so we can use the default one + this.currentDecodingExtension = this.defaultExtension; + } + } + if (this.currentDecodingExtension == null) { + this.currentDecodingExtension = this.defaultExtension; + } + this.currentDecodingExtension.isFrameValid(frame); + this.currentDecodingExtension.decodeFrame(frame); + if (this.log.isTraceEnabled()) { + this.log.trace("afterDecoding({}): {}", frame.getPayloadData().remaining(), + (frame.getPayloadData().remaining() > 1000 ? "too big to display" + : new String(frame.getPayloadData().array()))); + } + frame.isValid(); + return Either.right(frame); + } + + /** + * Translate the buffer depending when it has an extended payload length (126 or + * 127). + * + * @param buffer the buffer to read from + * @param optcode the decoded optcode + * @param oldPayloadlength the old payload length + * @param maxpacketsize the max packet size allowed + * @param oldRealpacketsize the real packet size + * @return the new payload data containing new payload length and new packet + * size + * @throws InvalidFrameException thrown if a control frame has an invalid + * length + * @throws IncompleteException if the maxpacketsize is smaller than the + * realpackagesize + * @throws LimitExceededException if the payload length is to big + */ + private Either translateSingleFramePayloadLength(ByteBuffer buffer, + Opcode optcode, int oldPayloadlength, int maxpacketsize, int oldRealpacketsize) + throws InvalidFrameException, LimitExceededException { + int payloadlength = oldPayloadlength; + int realpacketsize = oldRealpacketsize; + if (optcode == Opcode.PING || optcode == Opcode.PONG || optcode == Opcode.CLOSING) { + this.log.trace("Invalid frame: more than 125 octets"); + throw new InvalidFrameException("more than 125 octets"); + } + if (payloadlength == 126) { + realpacketsize += 2; // additional length bytes + + if (!this.isFrameSizeValid(maxpacketsize, realpacketsize)) { + return Either.left(realpacketsize); + } + byte[] sizebytes = new byte[3]; + sizebytes[1] = buffer.get(/* 1 + 1 */); + sizebytes[2] = buffer.get(/* 1 + 2 */); + payloadlength = new BigInteger(sizebytes).intValue(); + } else { + realpacketsize += 8; // additional length bytes + + if (!this.isFrameSizeValid(maxpacketsize, realpacketsize)) { + return Either.left(realpacketsize); + } + byte[] bytes = new byte[8]; + for (int i = 0; i < 8; i++) { + bytes[i] = buffer.get(/* 1 + i */); + } + long length = new BigInteger(bytes).longValue(); + this.translateSingleFrameCheckLengthLimit(length); + payloadlength = (int) length; + } + return Either.right(new TranslatedPayloadMetaData(payloadlength, realpacketsize)); + } + + /** + * Check if the frame size exceeds the allowed limit. + * + * @param length the current payload length + * @throws LimitExceededException if the payload length is to big + */ + private void translateSingleFrameCheckLengthLimit(long length) throws LimitExceededException { + if (length > Integer.MAX_VALUE) { + this.log.trace("Limit exedeed: Payloadsize is to big..."); + throw new LimitExceededException("Payloadsize is to big..."); + } + if (length > this.maxFrameSize) { + this.log.trace("Payload limit reached. Allowed: {} Current: {}", this.maxFrameSize, length); + throw new LimitExceededException("Payload limit reached.", this.maxFrameSize); + } + if (length < 0) { + this.log.trace("Limit underflow: Payloadsize is to little..."); + throw new LimitExceededException("Payloadsize is to little..."); + } + } + + private boolean isFrameSizeValid(int maxpacketsize, int realpacketsize) { + if (maxpacketsize < realpacketsize) { + this.log.trace("TranslateSingleFrameCheckPacketSize: maxpacketsize < realpacketsize"); + return false; + } + return true; + } + + /** + * Get a byte that can set RSV bits when OR(|)'d. 0 1 2 3 4 5 6 7 + * +-+-+-+-+-------+ |F|R|R|R| opcode| |I|S|S|S| (4) | |N|V|V|V| | | |1|2|3| | + * + * @param rsv Can only be {0, 1, 2, 3} + * @return byte that represents which RSV bit is set. + */ + private byte getRsvByte(int rsv) { + switch (rsv) { + case 1: // 0100 0000 + return 0x40; + case 2: // 0010 0000 + return 0x20; + case 3: // 0001 0000 + return 0x10; + default: + return 0; + } + } + + /** + * Get the mask byte if existing. + * + * @param mask is mask active or not + * @return -128 for true, 0 for false + */ + private byte getMaskByte(boolean mask) { + return mask ? (byte) -128 : 0; + } + + /** + * Get the size bytes for the byte buffer. + * + * @param mes the current buffer + * @return the size bytes + */ + private int getSizeBytes(ByteBuffer mes) { + if (mes.remaining() <= 125) { + return 1; + } else if (mes.remaining() <= 65535) { + return 2; + } + return 8; + } + + @Override + public List translateFrame(ByteBuffer buffer) throws InvalidDataException { + while (true) { + List frames = new LinkedList<>(); + Either cur; + if (this.incompleteframe != null) { + // complete an incomplete frame + buffer.mark(); + int availableNextByteCount = buffer.remaining();// The number of bytes received + int expectedNextByteCount = this.incompleteframe.remaining();// The number of bytes to complete + // the + // incomplete frame + + if (expectedNextByteCount > availableNextByteCount) { + // did not receive enough bytes to complete the frame + this.incompleteframe.put(buffer.array(), buffer.position(), availableNextByteCount); + buffer.position(buffer.position() + availableNextByteCount); + return Collections.emptyList(); + } + this.incompleteframe.put(buffer.array(), buffer.position(), expectedNextByteCount); + buffer.position(buffer.position() + expectedNextByteCount); + cur = this.translateSingleFrame((ByteBuffer) this.incompleteframe.duplicate().position(0)); + + if (cur.left != null) { + // extending as much as suggested + ByteBuffer extendedframe = ByteBuffer.allocate(checkAlloc(cur.left)); + assert (extendedframe.limit() > this.incompleteframe.limit()); + this.incompleteframe.rewind(); + extendedframe.put(this.incompleteframe); + this.incompleteframe = extendedframe; + continue; + } + frames.add(cur.right); + this.incompleteframe = null; + } + + // Read as much as possible full frames + while (buffer.hasRemaining()) { + buffer.mark(); + cur = this.translateSingleFrame(buffer); + if (cur.left != null) { + // remember the incomplete data + buffer.reset(); + this.incompleteframe = ByteBuffer.allocate(checkAlloc(cur.left)); + this.incompleteframe.put(buffer); + break; + } + frames.add(cur.right); + } + return frames; + } + } + + @Override + public List createFrames(ByteBuffer binary, boolean mask) { + BinaryFrame curframe = new BinaryFrame(); + curframe.setPayload(binary); + curframe.setTransferemasked(mask); + try { + curframe.isValid(); + } catch (InvalidDataException e) { + throw new NotSendableException(e); + } + return Collections.singletonList((Framedata) curframe); + } + + @Override + public List createFrames(String text, boolean mask) { + TextFrame curframe = new TextFrame(); + curframe.setPayload(ByteBuffer.wrap(Charsetfunctions.utf8Bytes(text))); + curframe.setTransferemasked(mask); + try { + curframe.isValid(); + } catch (InvalidDataException e) { + throw new NotSendableException(e); + } + return Collections.singletonList((Framedata) curframe); + } + + @Override + public void reset() { + this.incompleteframe = null; + if (this.negotiatedExtension != null) { + this.negotiatedExtension.reset(); + } + this.negotiatedExtension = new DefaultExtension(); + this.protocol = null; + } + + /** + * Generate a date for for the date-header. + * + * @return the server time + */ + private String getServerTime() { + Calendar calendar = Calendar.getInstance(); + SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US); + dateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); + return dateFormat.format(calendar.getTime()); + } + + /** + * Generate a final key from a input string. + * + * @param in the input string + * @return a final key + */ + private String generateFinalKey(String in) { + String seckey = in.trim(); + String acc = seckey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; + MessageDigest sh1; + try { + sh1 = MessageDigest.getInstance("SHA1"); + } catch (NoSuchAlgorithmException e) { + throw new IllegalStateException(e); + } + return Base64.encodeBytes(sh1.digest(acc.getBytes())); + } + + private byte[] toByteArray(long val, int bytecount) { + byte[] buffer = new byte[bytecount]; + int highest = 8 * bytecount - 8; + for (int i = 0; i < bytecount; i++) { + buffer[i] = (byte) (val >>> (highest - 8 * i)); + } + return buffer; + } + + private byte fromOpcode(Opcode opcode) { + if (opcode == Opcode.CONTINUOUS) { + return 0; + } else if (opcode == Opcode.TEXT) { + return 1; + } else if (opcode == Opcode.BINARY) { + return 2; + } else if (opcode == Opcode.CLOSING) { + return 8; + } else if (opcode == Opcode.PING) { + return 9; + } else if (opcode == Opcode.PONG) { + return 10; + } + throw new IllegalArgumentException("Don't know how to handle " + opcode.toString()); + } + + private Opcode toOpcode(byte opcode) throws InvalidFrameException { + switch (opcode) { + case 0: + return Opcode.CONTINUOUS; + case 1: + return Opcode.TEXT; + case 2: + return Opcode.BINARY; + // 3-7 are not yet defined + case 8: + return Opcode.CLOSING; + case 9: + return Opcode.PING; + case 10: + return Opcode.PONG; + // 11-15 are not yet defined + default: + throw new InvalidFrameException("Unknown opcode " + (short) opcode); + } + } + + @Override + public void processFrame(WebSocketImpl webSocketImpl, Framedata frame) throws InvalidDataException { + Opcode curop = frame.getOpcode(); + if (curop == Opcode.CLOSING) { + this.processFrameClosing(webSocketImpl, frame); + } else if (curop == Opcode.PING) { + webSocketImpl.getWebSocketListener().onWebsocketPing(webSocketImpl, frame); + } else if (curop == Opcode.PONG) { + webSocketImpl.updateLastPong(); + webSocketImpl.getWebSocketListener().onWebsocketPong(webSocketImpl, frame); + } else if (!frame.isFin() || curop == Opcode.CONTINUOUS) { + this.processFrameContinuousAndNonFin(webSocketImpl, frame, curop); + } else if (this.currentContinuousFrame != null) { + this.log.error("Protocol error: Continuous frame sequence not completed."); + throw new InvalidDataException(CloseFrame.PROTOCOL_ERROR, "Continuous frame sequence not completed."); + } else if (curop == Opcode.TEXT) { + this.processFrameText(webSocketImpl, frame); + } else if (curop == Opcode.BINARY) { + this.processFrameBinary(webSocketImpl, frame); + } else { + this.log.error("non control or continious frame expected"); + throw new InvalidDataException(CloseFrame.PROTOCOL_ERROR, "non control or continious frame expected"); + } + } + + /** + * Process the frame if it is a continuous frame or the fin bit is not set. + * + * @param webSocketImpl the websocket implementation to use + * @param frame the current frame + * @param curop the current Opcode + * @throws InvalidDataException if there is a protocol error + */ + private void processFrameContinuousAndNonFin(WebSocketImpl webSocketImpl, Framedata frame, Opcode curop) + throws InvalidDataException { + if (curop != Opcode.CONTINUOUS) { + this.processFrameIsNotFin(frame); + } else if (frame.isFin()) { + this.processFrameIsFin(webSocketImpl, frame); + } else if (this.currentContinuousFrame == null) { + this.log.error("Protocol error: Continuous frame sequence was not started."); + throw new InvalidDataException(CloseFrame.PROTOCOL_ERROR, "Continuous frame sequence was not started."); + } + // Check if the whole payload is valid utf8, when the opcode indicates a text + if (curop == Opcode.TEXT && !Charsetfunctions.isValidUTF8(frame.getPayloadData())) { + this.log.error("Protocol error: Payload is not UTF8"); + throw new InvalidDataException(CloseFrame.NO_UTF8); + } + // Checking if the current continuous frame contains a correct payload with the + // other frames combined + if (curop == Opcode.CONTINUOUS && this.currentContinuousFrame != null) { + this.addToBufferList(frame.getPayloadData()); + } + } + + /** + * Process the frame if it is a binary frame. + * + * @param webSocketImpl the websocket impl + * @param frame the frame + */ + private void processFrameBinary(WebSocketImpl webSocketImpl, Framedata frame) { + try { + webSocketImpl.getWebSocketListener().onWebsocketMessage(webSocketImpl, frame.getPayloadData()); + } catch (RuntimeException e) { + this.logRuntimeException(webSocketImpl, e); + } + } + + /** + * Log the runtime exception to the specific WebSocketImpl. + * + * @param webSocketImpl the implementation of the websocket + * @param e the runtime exception + */ + private void logRuntimeException(WebSocketImpl webSocketImpl, RuntimeException e) { + this.log.error("Runtime exception during onWebsocketMessage", e); + webSocketImpl.getWebSocketListener().onWebsocketError(webSocketImpl, e); + } + + /** + * Process the frame if it is a text frame. + * + * @param webSocketImpl the websocket impl + * @param frame the frame + */ + private void processFrameText(WebSocketImpl webSocketImpl, Framedata frame) throws InvalidDataException { + try { + webSocketImpl.getWebSocketListener().onWebsocketMessage(webSocketImpl, + Charsetfunctions.stringUtf8(frame.getPayloadData())); + } catch (RuntimeException e) { + this.logRuntimeException(webSocketImpl, e); + } + } + + /** + * Process the frame if it is the last frame. + * + * @param webSocketImpl the websocket impl + * @param frame the frame + * @throws InvalidDataException if there is a protocol error + */ + private void processFrameIsFin(WebSocketImpl webSocketImpl, Framedata frame) throws InvalidDataException { + if (this.currentContinuousFrame == null) { + this.log.trace("Protocol error: Previous continuous frame sequence not completed."); + throw new InvalidDataException(CloseFrame.PROTOCOL_ERROR, "Continuous frame sequence was not started."); + } + this.addToBufferList(frame.getPayloadData()); + this.checkBufferLimit(); + if (this.currentContinuousFrame.getOpcode() == Opcode.TEXT) { + ((FramedataImpl1) this.currentContinuousFrame).setPayload(this.getPayloadFromByteBufferList()); + ((FramedataImpl1) this.currentContinuousFrame).isValid(); + try { + webSocketImpl.getWebSocketListener().onWebsocketMessage(webSocketImpl, + Charsetfunctions.stringUtf8(this.currentContinuousFrame.getPayloadData())); + } catch (RuntimeException e) { + this.logRuntimeException(webSocketImpl, e); + } + } else if (this.currentContinuousFrame.getOpcode() == Opcode.BINARY) { + ((FramedataImpl1) this.currentContinuousFrame).setPayload(this.getPayloadFromByteBufferList()); + ((FramedataImpl1) this.currentContinuousFrame).isValid(); + try { + webSocketImpl.getWebSocketListener().onWebsocketMessage(webSocketImpl, + this.currentContinuousFrame.getPayloadData()); + } catch (RuntimeException e) { + this.logRuntimeException(webSocketImpl, e); + } + } + this.currentContinuousFrame = null; + this.clearBufferList(); + } + + /** + * Process the frame if it is not the last frame. + * + * @param frame the frame + * @throws InvalidDataException if there is a protocol error + */ + private void processFrameIsNotFin(Framedata frame) throws InvalidDataException { + if (this.currentContinuousFrame != null) { + this.log.trace("Protocol error: Previous continuous frame sequence not completed."); + throw new InvalidDataException(CloseFrame.PROTOCOL_ERROR, + "Previous continuous frame sequence not completed."); + } + this.currentContinuousFrame = frame; + this.addToBufferList(frame.getPayloadData()); + this.checkBufferLimit(); + } + + /** + * Process the frame if it is a closing frame. + * + * @param webSocketImpl the websocket impl + * @param frame the frame + */ + private void processFrameClosing(WebSocketImpl webSocketImpl, Framedata frame) { + int code = CloseFrame.NOCODE; + String reason = ""; + if (frame instanceof CloseFrame) { + CloseFrame cf = (CloseFrame) frame; + code = cf.getCloseCode(); + reason = cf.getMessage(); + } + if (webSocketImpl.getReadyState() == ReadyState.CLOSING) { + // complete the close handshake by disconnecting + webSocketImpl.closeConnection(code, reason, true); + } else { + // echo close handshake + if (this.getCloseHandshakeType() == CloseHandshakeType.TWOWAY) { + webSocketImpl.close(code, reason, true); + } else { + webSocketImpl.flushAndClose(code, reason, false); + } + } + } + + /** + * Clear the current bytebuffer list. + */ + private void clearBufferList() { + synchronized (this.byteBufferList) { + this.byteBufferList.clear(); + } + } + + /** + * Add a payload to the current bytebuffer list. + * + * @param payloadData the new payload + */ + private void addToBufferList(ByteBuffer payloadData) { + synchronized (this.byteBufferList) { + this.byteBufferList.add(payloadData); + } + } + + /** + * Check the current size of the buffer and throw an exception if the size is + * bigger than the max allowed frame size. + * + * @throws LimitExceededException if the current size is bigger than the allowed + * size + */ + private void checkBufferLimit() throws LimitExceededException { + long totalSize = this.getByteBufferListSize(); + if (totalSize > this.maxFrameSize) { + this.clearBufferList(); + this.log.trace("Payload limit reached. Allowed: {} Current: {}", this.maxFrameSize, totalSize); + throw new LimitExceededException(this.maxFrameSize); + } + } + + @Override + public CloseHandshakeType getCloseHandshakeType() { + return CloseHandshakeType.TWOWAY; + } + + @Override + public String toString() { + String result = super.toString(); + if (this.getExtension() != null) { + result += " extension: " + this.getExtension().toString(); + } + if (this.getProtocol() != null) { + result += " protocol: " + this.getProtocol().toString(); + } + result += " max frame size: " + this.maxFrameSize; + return result; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + MyDraft6455 that = (MyDraft6455) o; + + if (this.maxFrameSize != that.getMaxFrameSize()) { + return false; + } + if (this.negotiatedExtension != null ? !this.negotiatedExtension.equals(that.getExtension()) + : that.getExtension() != null) { + return false; + } + return this.protocol != null ? this.protocol.equals(that.getProtocol()) : that.getProtocol() == null; + } + + @Override + public int hashCode() { + int result = this.negotiatedExtension != null ? this.negotiatedExtension.hashCode() : 0; + result = 31 * result + (this.protocol != null ? this.protocol.hashCode() : 0); + result = 31 * result + (this.maxFrameSize ^ (this.maxFrameSize >>> 32)); + return result; + } + + /** + * Method to generate a full bytebuffer out of all the fragmented frame payload. + * + * @return a bytebuffer containing all the data + * @throws LimitExceededException will be thrown when the totalSize is bigger + * then Integer.MAX_VALUE due to not being able + * to allocate more + */ + private ByteBuffer getPayloadFromByteBufferList() throws LimitExceededException { + long totalSize = 0; + ByteBuffer resultingByteBuffer; + synchronized (this.byteBufferList) { + for (ByteBuffer buffer : this.byteBufferList) { + totalSize += buffer.limit(); + } + this.checkBufferLimit(); + resultingByteBuffer = ByteBuffer.allocate((int) totalSize); + for (ByteBuffer buffer : this.byteBufferList) { + resultingByteBuffer.put(buffer); + } + } + resultingByteBuffer.flip(); + return resultingByteBuffer; + } + + /** + * Get the current size of the resulting bytebuffer in the bytebuffer list. + * + * @return the size as long (to not get an integer overflow) + */ + private long getByteBufferListSize() { + long totalSize = 0; + synchronized (this.byteBufferList) { + for (ByteBuffer buffer : this.byteBufferList) { + totalSize += buffer.limit(); + } + } + return totalSize; + } + + private class TranslatedPayloadMetaData { + + private int payloadLength; + private int realPackageSize; + + private int getPayloadLength() { + return this.payloadLength; + } + + private int getRealPackageSize() { + return this.realPackageSize; + } + + TranslatedPayloadMetaData(int newPayloadLength, int newRealPackageSize) { + this.payloadLength = newPayloadLength; + this.realPackageSize = newRealPackageSize; + } + } + +} diff --git a/io.openems.common/src/io/openems/common/websocket/OnClose.java b/io.openems.common/src/io/openems/common/websocket/OnClose.java index 9a2c25c395a..3ded7e8db62 100644 --- a/io.openems.common/src/io/openems/common/websocket/OnClose.java +++ b/io.openems.common/src/io/openems/common/websocket/OnClose.java @@ -2,11 +2,12 @@ import org.java_websocket.WebSocket; -import io.openems.common.exceptions.OpenemsException; - @FunctionalInterface public interface OnClose { + public static final OnClose NO_OP = (ws, code, reason, remote) -> { + }; + /** * Called after the websocket connection has been closed. * @@ -15,8 +16,7 @@ public interface OnClose { * @param reason the close reason * @param remote Returns whether or not the closing of the connection was * initiated by the remote host - * @throws OpenemsException on error */ - public void run(WebSocket ws, int code, String reason, boolean remote) throws OpenemsException; + public void accept(WebSocket ws, int code, String reason, boolean remote); } diff --git a/io.openems.common/src/io/openems/common/websocket/OnCloseHandler.java b/io.openems.common/src/io/openems/common/websocket/OnCloseHandler.java index 9254e2794d1..fcfbb97780b 100644 --- a/io.openems.common/src/io/openems/common/websocket/OnCloseHandler.java +++ b/io.openems.common/src/io/openems/common/websocket/OnCloseHandler.java @@ -1,36 +1,42 @@ package io.openems.common.websocket; +import static io.openems.common.websocket.WebsocketUtils.generateWsDataString; + +import java.util.function.BiConsumer; + import org.java_websocket.WebSocket; public class OnCloseHandler implements Runnable { - private final AbstractWebsocket parent; private final WebSocket ws; private final int code; private final String reason; private final boolean remote; + private final OnClose onClose; + private final BiConsumer handleInternalError; - public OnCloseHandler(AbstractWebsocket parent, WebSocket ws, int code, String reason, boolean remote) { - this.parent = parent; + public OnCloseHandler(// + WebSocket ws, int code, String reason, boolean remote, OnClose onClose, // + BiConsumer handleInternalError) { this.ws = ws; this.code = code; this.reason = reason; this.remote = remote; + this.onClose = onClose; + this.handleInternalError = handleInternalError; } @Override public final void run() { try { - this.parent.getOnClose().run(this.ws, this.code, this.reason, this.remote); + this.onClose.accept(this.ws, this.code, this.reason, this.remote); - // remove websocket from WsData + // dispose WsData WsData wsData = this.ws.getAttachment(); - if (wsData != null) { - wsData.setWebsocket(null); - } + wsData.dispose(); } catch (Throwable t) { - this.parent.handleInternalErrorSync(t, WebsocketUtils.getWsDataString(this.ws)); + this.handleInternalError.accept(t, generateWsDataString(this.ws)); } } diff --git a/io.openems.common/src/io/openems/common/websocket/OnError.java b/io.openems.common/src/io/openems/common/websocket/OnError.java index 443fdb411bf..00ffa1bb59b 100644 --- a/io.openems.common/src/io/openems/common/websocket/OnError.java +++ b/io.openems.common/src/io/openems/common/websocket/OnError.java @@ -3,9 +3,13 @@ import org.java_websocket.WebSocket; import io.openems.common.exceptions.OpenemsException; +import io.openems.common.function.ThrowingBiConsumer; @FunctionalInterface -public interface OnError { +public interface OnError extends ThrowingBiConsumer { + + public static final OnError NO_OP = (ws, ex) -> { + }; /** * Handles a websocket error. @@ -14,6 +18,6 @@ public interface OnError { * @param ex the {@link Exception} * @throws OpenemsException on error */ - public void run(WebSocket ws, Exception ex) throws OpenemsException; + public void accept(WebSocket ws, Exception ex) throws OpenemsException; } diff --git a/io.openems.common/src/io/openems/common/websocket/OnErrorHandler.java b/io.openems.common/src/io/openems/common/websocket/OnErrorHandler.java index 450a8640c5b..96b1bcf991e 100644 --- a/io.openems.common/src/io/openems/common/websocket/OnErrorHandler.java +++ b/io.openems.common/src/io/openems/common/websocket/OnErrorHandler.java @@ -1,26 +1,37 @@ package io.openems.common.websocket; +import static io.openems.common.websocket.WebsocketUtils.generateWsDataString; + +import java.util.function.BiConsumer; + import org.java_websocket.WebSocket; +/** + * Handler for WebSocket OnError event. + */ public class OnErrorHandler implements Runnable { - private final AbstractWebsocket parent; private final WebSocket ws; private final Exception ex; + private final OnError onError; + private final BiConsumer handleInternalError; - public OnErrorHandler(AbstractWebsocket parent, WebSocket ws, Exception ex) { - this.parent = parent; + public OnErrorHandler(// + WebSocket ws, Exception ex, OnError onError, // + BiConsumer handleInternalError) { this.ws = ws; this.ex = ex; + this.onError = onError; + this.handleInternalError = handleInternalError; } @Override public final void run() { try { - this.parent.getOnError().run(this.ws, this.ex); + this.onError.accept(this.ws, this.ex); } catch (Throwable t) { - this.parent.handleInternalErrorSync(t, WebsocketUtils.getWsDataString(this.ws)); + this.handleInternalError.accept(t, generateWsDataString(this.ws)); } } diff --git a/io.openems.common/src/io/openems/common/websocket/OnInternalError.java b/io.openems.common/src/io/openems/common/websocket/OnInternalError.java index 28c32e10d52..cb1da961361 100644 --- a/io.openems.common/src/io/openems/common/websocket/OnInternalError.java +++ b/io.openems.common/src/io/openems/common/websocket/OnInternalError.java @@ -1,7 +1,9 @@ package io.openems.common.websocket; +import java.util.function.BiConsumer; + @FunctionalInterface -public interface OnInternalError { +public interface OnInternalError extends BiConsumer { /** * Handles an internal error. @@ -9,6 +11,6 @@ public interface OnInternalError { * @param t the error {@link Throwable} * @param wsDataString the content from WsData.toString() */ - public void run(Throwable t, String wsDataString); + public void accept(Throwable t, String wsDataString); } diff --git a/io.openems.common/src/io/openems/common/websocket/OnInternalErrorHandler.java b/io.openems.common/src/io/openems/common/websocket/OnInternalErrorHandler.java index 68f2bf492ae..3b692c52374 100644 --- a/io.openems.common/src/io/openems/common/websocket/OnInternalErrorHandler.java +++ b/io.openems.common/src/io/openems/common/websocket/OnInternalErrorHandler.java @@ -14,7 +14,7 @@ public OnInternalErrorHandler(OnInternalError onInternalError, Throwable t, Stri @Override public final void run() { - this.onInternalError.run(this.t, this.wsDataString); + this.onInternalError.accept(this.t, this.wsDataString); } } diff --git a/io.openems.common/src/io/openems/common/websocket/OnMessageHandler.java b/io.openems.common/src/io/openems/common/websocket/OnMessageHandler.java new file mode 100644 index 00000000000..9efe41ba425 --- /dev/null +++ b/io.openems.common/src/io/openems/common/websocket/OnMessageHandler.java @@ -0,0 +1,182 @@ +package io.openems.common.websocket; + +import static io.openems.common.exceptions.OpenemsError.JSONRPC_UNHANDLED_METHOD; +import static io.openems.common.utils.JsonrpcUtils.simplifyJsonrpcMessage; +import static io.openems.common.utils.StringUtils.toShortString; +import static io.openems.common.websocket.WebsocketUtils.generateWsDataString; +import static java.util.concurrent.TimeUnit.SECONDS; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeoutException; +import java.util.function.BiConsumer; +import java.util.function.BiPredicate; + +import org.java_websocket.WebSocket; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.jsonrpc.base.JsonrpcMessage; +import io.openems.common.jsonrpc.base.JsonrpcNotification; +import io.openems.common.jsonrpc.base.JsonrpcRequest; +import io.openems.common.jsonrpc.base.JsonrpcResponse; +import io.openems.common.jsonrpc.base.JsonrpcResponseError; +import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; + +/** + * Handler for WebSocket OnMessage event. + */ +public final class OnMessageHandler implements Runnable { + + private final Logger log = LoggerFactory.getLogger(OnMessageHandler.class); + private final WebSocket ws; + private final String message; + private final OnRequest onRequest; + private final OnNotification onNotification; + private final BiPredicate sendMessage; + private final BiConsumer handleInternalError; + private final BiConsumer logWarn; + + public OnMessageHandler(// + WebSocket ws, String message, // + OnRequest onRequest, // + OnNotification onNotification, // + BiPredicate sendMessage, // + BiConsumer handleInternalError, // + BiConsumer logWarn) { + this.ws = ws; + this.message = message; + this.onRequest = onRequest; + this.onNotification = onNotification; + this.sendMessage = sendMessage; + this.handleInternalError = handleInternalError; + this.logWarn = logWarn; + } + + @Override + public final void run() { + try { + var message = JsonrpcMessage.from(this.message); + + if (message instanceof JsonrpcRequest request) { + this.handleJsonrpcRequest(this.ws, request); + + } else if (message instanceof JsonrpcResponse response) { + this.handleJsonrpcResponse(this.ws, response); + + } else if (message instanceof JsonrpcNotification notification) { + this.handleJsonrpcNotification(this.ws, notification); + } + + } catch (OpenemsNamedException e) { + this.handleInternalError.accept(e, generateWsDataString(this.ws)); + return; + } + } + + /** + * Handle a {@link JsonrpcRequest}. + * + * @param ws the {@link WebSocket} + * @param request the {@link JsonrpcRequest} + */ + protected void handleJsonrpcRequest(WebSocket ws, JsonrpcRequest request) { + CompletableFuture responseFuture; + try { + responseFuture = this.onRequest.apply(ws, request); + } catch (Throwable t) { + this.handleJsonrpcRequestException(ws, request, t); + return; + } + + var timeout = request.getTimeout(); + if (timeout.isPresent() && timeout.get() > 0) { + // Apply timeout to CompleteableFuture + responseFuture.orTimeout(timeout.get(), SECONDS); + } + + // ...without timeout + responseFuture.whenComplete((r, ex) -> { + if (ex != null) { + this.handleJsonrpcRequestException(ws, request, ex); + } else if (r != null) { + this.handleJsonrpcRequestResponse(ws, r); + } else { + this.handleJsonrpcRequestException(ws, request, + new OpenemsNamedException(JSONRPC_UNHANDLED_METHOD, request.getMethod())); + } + }); + } + + private void handleJsonrpcRequestResponse(WebSocket ws, JsonrpcResponse response) { + this.sendMessage.test(ws, response); + } + + private void handleJsonrpcRequestException(WebSocket ws, JsonrpcRequest request, Throwable t) { + // Log Error + var log = new StringBuilder() // + .append("JSON-RPC Error "); // + + if (t.getMessage() != null && !t.getMessage().isBlank()) { + log // + .append("\"") // + .append(t.getMessage()) // + .append("\" "); + } + + if (!(t instanceof OpenemsNamedException)) { + log // + .append("of type ") // + .append(t.getClass().getSimpleName()) // + .append(" "); + + if (t instanceof TimeoutException) { + log // + .append("[").append(request.getTimeout().orElse(0)).append("s] "); + } + } + + log // + .append("for Request ") // + .append(toShortString(simplifyJsonrpcMessage(request), 200)); + this.logWarn.accept(this.log, log.toString()); + + // Get JSON-RPC Response Error + if (t instanceof OpenemsNamedException one) { + this.sendMessage.test(ws, new JsonrpcResponseError(request.getId(), one)); + } else { + this.sendMessage.test(ws, new JsonrpcResponseError(request.getId(), t.getMessage())); + } + } + + /** + * Handle a {@link JsonrpcResponse}. + * + * @param ws the {@link WebSocket} + * @param response the {@link JsonrpcResponse} + */ + protected void handleJsonrpcResponse(WebSocket ws, JsonrpcResponse response) { + try { + WsData wsData = this.ws.getAttachment(); + wsData.handleJsonrpcResponse(response); + + } catch (Throwable t) { + this.handleInternalError.accept(t, generateWsDataString(this.ws)); + } + } + + /** + * Handle a {@link JsonrpcNotification}. + * + * @param ws the {@link WebSocket} + * @param notification the {@link JsonrpcNotification} + */ + protected void handleJsonrpcNotification(WebSocket ws, JsonrpcNotification notification) { + try { + this.onNotification.accept(ws, notification); + + } catch (Throwable t) { + this.handleInternalError.accept(t, generateWsDataString(this.ws)); + } + } +} diff --git a/io.openems.common/src/io/openems/common/websocket/OnNotification.java b/io.openems.common/src/io/openems/common/websocket/OnNotification.java index 8634e4cac3a..6de529fbfa4 100644 --- a/io.openems.common/src/io/openems/common/websocket/OnNotification.java +++ b/io.openems.common/src/io/openems/common/websocket/OnNotification.java @@ -3,10 +3,14 @@ import org.java_websocket.WebSocket; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingBiConsumer; import io.openems.common.jsonrpc.base.JsonrpcNotification; @FunctionalInterface -public interface OnNotification { +public interface OnNotification extends ThrowingBiConsumer { + + public static final OnNotification NO_OP = (ws, notification) -> { + }; /** * Handles a JSON-RPC notification. @@ -15,6 +19,6 @@ public interface OnNotification { * @param notification the JSON-RPC Notification * @throws OpenemsNamedException on error */ - public void run(WebSocket websocket, JsonrpcNotification notification) throws OpenemsNamedException; + public void accept(WebSocket websocket, JsonrpcNotification notification) throws OpenemsNamedException; } diff --git a/io.openems.common/src/io/openems/common/websocket/OnNotificationHandler.java b/io.openems.common/src/io/openems/common/websocket/OnNotificationHandler.java deleted file mode 100644 index ec58024ff59..00000000000 --- a/io.openems.common/src/io/openems/common/websocket/OnNotificationHandler.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.openems.common.websocket; - -import org.java_websocket.WebSocket; - -import io.openems.common.jsonrpc.base.JsonrpcNotification; - -public class OnNotificationHandler implements Runnable { - - private final AbstractWebsocket parent; - private final WebSocket ws; - private final JsonrpcNotification notification; - - public OnNotificationHandler(AbstractWebsocket parent, WebSocket ws, JsonrpcNotification notification) { - this.parent = parent; - this.ws = ws; - this.notification = notification; - } - - @Override - public final void run() { - try { - this.parent.getOnNotification().run(this.ws, this.notification); - - } catch (Throwable t) { - this.parent.handleInternalErrorSync(t, WebsocketUtils.getWsDataString(this.ws)); - } - } - -} diff --git a/io.openems.common/src/io/openems/common/websocket/OnOpen.java b/io.openems.common/src/io/openems/common/websocket/OnOpen.java index b7e0870704d..75389b64986 100644 --- a/io.openems.common/src/io/openems/common/websocket/OnOpen.java +++ b/io.openems.common/src/io/openems/common/websocket/OnOpen.java @@ -1,21 +1,25 @@ package io.openems.common.websocket; -import org.java_websocket.WebSocket; +import java.util.function.BiFunction; -import com.google.gson.JsonObject; +import org.java_websocket.WebSocket; +import org.java_websocket.handshake.Handshakedata; -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.exceptions.OpenemsError; @FunctionalInterface -public interface OnOpen { +public interface OnOpen extends BiFunction { + + public static final OnOpen NO_OP = (ws, handshakedata) -> { + return null; + }; /** * Handles OnOpen event of WebSocket. * - * @param ws the WebSocket - * @param handshake the HTTP handshake/headers - * @throws OpenemsNamedException on error + * @param ws the {@link WebSocket} + * @param handshakedata the {@link Handshakedata} with HTTP headers + * @return {@link OpenemsError} or null */ - public void run(WebSocket ws, JsonObject handshake) throws OpenemsNamedException; - -} + public OpenemsError apply(WebSocket ws, Handshakedata handshakedata); +} \ No newline at end of file diff --git a/io.openems.common/src/io/openems/common/websocket/OnOpenHandler.java b/io.openems.common/src/io/openems/common/websocket/OnOpenHandler.java index 636281e755d..a6e6389dc77 100644 --- a/io.openems.common/src/io/openems/common/websocket/OnOpenHandler.java +++ b/io.openems.common/src/io/openems/common/websocket/OnOpenHandler.java @@ -1,37 +1,52 @@ package io.openems.common.websocket; +import static io.openems.common.websocket.WebsocketUtils.generateWsDataString; + +import java.util.function.BiConsumer; + import org.java_websocket.WebSocket; import org.java_websocket.exceptions.WebsocketNotConnectedException; +import org.java_websocket.handshake.Handshakedata; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.gson.JsonObject; - -public class OnOpenHandler implements Runnable { +/** + * Handler for WebSocket OnOpen event. + */ +public final class OnOpenHandler implements Runnable { private final Logger log = LoggerFactory.getLogger(OnOpenHandler.class); - private final AbstractWebsocket parent; private final WebSocket ws; - private final JsonObject handshake; - - public OnOpenHandler(AbstractWebsocket parent, WebSocket ws, JsonObject handshake) { - this.parent = parent; + private final Handshakedata handshake; + private final OnOpen onOpen; + private final BiConsumer logWarn; + private final BiConsumer handleInternalError; + + public OnOpenHandler(// + WebSocket ws, Handshakedata handshake, OnOpen onOpen, // + BiConsumer logWarn, // + BiConsumer handleInternalError) { this.ws = ws; this.handshake = handshake; + this.onOpen = onOpen; + this.logWarn = logWarn; + this.handleInternalError = handleInternalError; } @Override public final void run() { try { - this.parent.getOnOpen().run(this.ws, this.handshake); + var error = this.onOpen.apply(this.ws, this.handshake); + if (error != null) { + this.logWarn.accept(this.log, "Error during OnOpen of " + generateWsDataString(this.ws)); + } } catch (WebsocketNotConnectedException e) { - this.parent.logWarn(this.log, - "Websocket was closed before it has been fully opened: " + WebsocketUtils.getWsDataString(this.ws)); + this.logWarn.accept(this.log, + "Websocket was closed before it has been fully opened: " + generateWsDataString(this.ws)); } catch (Throwable t) { - this.parent.handleInternalErrorSync(t, WebsocketUtils.getWsDataString(this.ws)); + this.handleInternalError.accept(t, generateWsDataString(this.ws)); } } - -} +} \ No newline at end of file diff --git a/io.openems.common/src/io/openems/common/websocket/OnRequest.java b/io.openems.common/src/io/openems/common/websocket/OnRequest.java index 410c9bae854..5b59cd941f4 100644 --- a/io.openems.common/src/io/openems/common/websocket/OnRequest.java +++ b/io.openems.common/src/io/openems/common/websocket/OnRequest.java @@ -1,15 +1,24 @@ package io.openems.common.websocket; +import static java.util.concurrent.CompletableFuture.completedFuture; + import java.util.concurrent.CompletableFuture; import org.java_websocket.WebSocket; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingBiFunction; +import io.openems.common.jsonrpc.base.GenericJsonrpcResponseSuccess; import io.openems.common.jsonrpc.base.JsonrpcRequest; import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; @FunctionalInterface -public interface OnRequest { +public interface OnRequest extends + ThrowingBiFunction, OpenemsNamedException> { + + public static final OnRequest NO_OP = (ws, request) -> { + return completedFuture(new GenericJsonrpcResponseSuccess(request.id)); + }; /** * Handle a JSON-RPC Request, receive a JSON-RPC Response via callback. @@ -19,7 +28,7 @@ public interface OnRequest { * @return the JSON-RPC Success Response Future * @throws OpenemsNamedException on error */ - public CompletableFuture run(WebSocket ws, JsonrpcRequest request) + public CompletableFuture apply(WebSocket ws, JsonrpcRequest request) throws OpenemsNamedException; } diff --git a/io.openems.common/src/io/openems/common/websocket/OnRequestHandler.java b/io.openems.common/src/io/openems/common/websocket/OnRequestHandler.java deleted file mode 100644 index 0e4cf55c695..00000000000 --- a/io.openems.common/src/io/openems/common/websocket/OnRequestHandler.java +++ /dev/null @@ -1,111 +0,0 @@ -package io.openems.common.websocket; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.function.Consumer; - -import org.java_websocket.WebSocket; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.openems.common.exceptions.OpenemsError; -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.jsonrpc.base.JsonrpcRequest; -import io.openems.common.jsonrpc.base.JsonrpcResponse; -import io.openems.common.jsonrpc.base.JsonrpcResponseError; -import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; -import io.openems.common.utils.JsonrpcUtils; -import io.openems.common.utils.StringUtils; - -public class OnRequestHandler implements Runnable { - - private final Logger log = LoggerFactory.getLogger(OnRequestHandler.class); - - private final AbstractWebsocket parent; - private final WebSocket ws; - private final JsonrpcRequest request; - private final Consumer responseCallback; - - public OnRequestHandler(AbstractWebsocket parent, WebSocket ws, JsonrpcRequest request, - Consumer responseCallback) { - this.parent = parent; - this.ws = ws; - this.request = request; - this.responseCallback = responseCallback; - } - - @Override - public final void run() { - CompletableFuture responseFuture; - try { - responseFuture = this.parent.getOnRequest().run(this.ws, this.request); - } catch (Throwable t) { - this.handleException(t); - return; - } - - if (this.request.getTimeout().isPresent() && this.request.getTimeout().get() > 0) { - // Apply timeout to CompleteableFuture - responseFuture.orTimeout(this.request.getTimeout().get(), TimeUnit.SECONDS); - } - - // ...without timeout - responseFuture.whenComplete((r, ex) -> { - if (ex != null) { - this.handleException(ex); - } else if (r != null) { - this.handleResponse(r); - } else { - this.handleException( - new OpenemsNamedException(OpenemsError.JSONRPC_UNHANDLED_METHOD, this.request.getMethod())); - } - }); - } - - private void handleResponse(JsonrpcResponse response) { - this.responseCallback.accept(response); - } - - private void handleException(Throwable t) { - // Log Error - var log = new StringBuilder() // - .append("JSON-RPC Error "); // - - if (t.getMessage() != null && !t.getMessage().isBlank()) { - log // - .append("\"") // - .append(t.getMessage()) // - .append("\" "); - } - - if (!(t instanceof OpenemsNamedException)) { - log // - .append("of type ") // - .append(t.getClass().getSimpleName()) // - .append(" "); - - if (t instanceof TimeoutException) { - log // - .append("[").append(this.request.getTimeout().get()).append("s] "); - } - } - - log // - .append("for Request ") // - .append(StringUtils.toShortString(JsonrpcUtils.simplifyJsonrpcMessage(this.request), 200)); // - this.parent.logWarn(this.log, log.toString()); - - // Get JSON-RPC Response Error - if (t instanceof OpenemsNamedException) { - this.responseCallback.accept(new JsonrpcResponseError(this.request.getId(), (OpenemsNamedException) t)); - } else { - this.responseCallback.accept(new JsonrpcResponseError(this.request.getId(), t.getMessage())); - } - } - - // TODO REMOVE DEBUG - public String getRequestMethod() { - return this.request.getFullyQualifiedMethod(); - } -} diff --git a/io.openems.common/src/io/openems/common/websocket/OnResponseHandler.java b/io.openems.common/src/io/openems/common/websocket/OnResponseHandler.java deleted file mode 100644 index e9938030b7b..00000000000 --- a/io.openems.common/src/io/openems/common/websocket/OnResponseHandler.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.openems.common.websocket; - -import org.java_websocket.WebSocket; - -import io.openems.common.jsonrpc.base.JsonrpcResponse; - -public class OnResponseHandler implements Runnable { - - private final AbstractWebsocket parent; - private final WebSocket ws; - private final JsonrpcResponse response; - - public OnResponseHandler(AbstractWebsocket parent, WebSocket ws, JsonrpcResponse response) { - this.parent = parent; - this.ws = ws; - this.response = response; - } - - @Override - public final void run() { - try { - WsData wsData = this.ws.getAttachment(); - wsData.handleJsonrpcResponse(this.response); - - } catch (Throwable t) { - this.parent.handleInternalErrorSync(t, WebsocketUtils.getWsDataString(this.ws)); - } - } - -} diff --git a/io.openems.common/src/io/openems/common/websocket/WebsocketUtils.java b/io.openems.common/src/io/openems/common/websocket/WebsocketUtils.java index a60902b90bc..e9f51ae5b04 100644 --- a/io.openems.common/src/io/openems/common/websocket/WebsocketUtils.java +++ b/io.openems.common/src/io/openems/common/websocket/WebsocketUtils.java @@ -3,29 +3,53 @@ import org.java_websocket.WebSocket; import org.java_websocket.handshake.Handshakedata; -import com.google.gson.JsonObject; - public class WebsocketUtils { /** - * Converts a Handshake to a JsonObject. + * Gets a String value from a {@link Handshakedata}. * *

      * NOTE: Per specification - * "Field names are case-insensitive". Because of this fields are converted to - * lower-case. + * "Field names are case-insensitive". * - * @param handshake the {@link Handshakedata} - * @return the converted {@link JsonObject} + * @param handshakedata the {@link Handshakedata} + * @param fieldName the name of the field + * @return the field value; or null */ - public static JsonObject handshakeToJsonObject(Handshakedata handshake) { - var j = new JsonObject(); - for (var iter = handshake.iterateHttpFields(); iter.hasNext();) { + public static String getAsString(Handshakedata handshakedata, String fieldName) { + for (var iter = handshakedata.iterateHttpFields(); iter.hasNext();) { var field = iter.next(); - j.addProperty(field.toLowerCase(), handshake.getFieldValue(field)); + if (fieldName.equalsIgnoreCase(field)) { + return handshakedata.getFieldValue(field).trim(); + } } - return j; + return null; + } + + private static final String[] REMOTE_IDENTIFICATION_HEADERS = new String[] { // + "Forwarded", "X-Forwarded-For", "X-Real-IP" }; + + /** + * Parses a identifier for the Remote from the {@link Handshakedata}. + * + *

      + * Tries to use the headers "Forwarded", "X-Forwarded-For" or "X-Real-IP". Falls + * back to `ws.getRemoteSocketAddress()`. See https://serverfault.com/a/920060 + * + * @param ws the {@link WebSocket} + * @param handshakedata the {@link Handshakedata} + * @return an identifier String + */ + public static String parseRemoteIdentifier(WebSocket ws, Handshakedata handshakedata) { + for (var key : REMOTE_IDENTIFICATION_HEADERS) { + var value = getAsString(handshakedata, key); + if (value != null) { + return value; + } + } + // fallback + return ws.getRemoteSocketAddress().toString(); } /** @@ -35,7 +59,7 @@ public static JsonObject handshakeToJsonObject(Handshakedata handshake) { * @param ws the WebSocket * @return the {@link WsData#toString()} content */ - public static String getWsDataString(WebSocket ws) { + public static String generateWsDataString(WebSocket ws) { if (ws == null) { return ""; } @@ -45,5 +69,4 @@ public static String getWsDataString(WebSocket ws) { } return wsData.toString(); } - } diff --git a/io.openems.common/src/io/openems/common/websocket/WsData.java b/io.openems.common/src/io/openems/common/websocket/WsData.java index f7a9f595ac7..b43aedad7f7 100644 --- a/io.openems.common/src/io/openems/common/websocket/WsData.java +++ b/io.openems.common/src/io/openems/common/websocket/WsData.java @@ -24,9 +24,13 @@ public abstract class WsData { /** - * Holds the Websocket. Possibly null! + * Holds the WebSocket. */ - private WebSocket websocket = null; + private final WebSocket websocket; + + protected WsData(WebSocket ws) { + this.websocket = ws; + } /** * Holds Futures for JSON-RPC Requests. @@ -39,21 +43,12 @@ public abstract class WsData { * blocked resources. */ public void dispose() { + final var e = new OpenemsException("Websocket connection closed"); // Complete all pending requests - this.requestFutures.values() - .forEach(r -> r.completeExceptionally(new OpenemsException("Websocket connection closed."))); + this.requestFutures.values().forEach(r -> r.completeExceptionally(e)); this.requestFutures.clear(); } - /** - * Sets the WebSocket. - * - * @param ws the WebSocket instance - */ - public synchronized void setWebsocket(WebSocket ws) { - this.websocket = ws; - } - /** * Gets the WebSocket. Possibly null! * @@ -68,15 +63,16 @@ public WebSocket getWebsocket() { * * @param request the JSON-RPC Request * @return a promise for a successful JSON-RPC Response - * @throws OpenemsNamedException on error */ - public CompletableFuture send(JsonrpcRequest request) throws OpenemsNamedException { + public CompletableFuture send(JsonrpcRequest request) { var future = new CompletableFuture(); var existingFuture = this.requestFutures.putIfAbsent(request.getId(), future); if (existingFuture != null) { - throw OpenemsError.JSONRPC_ID_NOT_UNIQUE.exception(request.getId()); + return CompletableFuture.failedFuture(OpenemsError.JSONRPC_ID_NOT_UNIQUE.exception(request.getId())); + } + if (!this.sendMessage(request)) { + future.completeExceptionally(OpenemsError.JSONRPC_SEND_FAILED.exception()); } - this.sendMessage(request); return future; } @@ -84,26 +80,28 @@ public CompletableFuture send(JsonrpcRequest request) th * Sends a JSON-RPC Notification to a WebSocket. * * @param notification the JSON-RPC Notification - * @throws OpenemsException on error + * @return true if sending was successful; false otherwise */ - public void send(JsonrpcNotification notification) throws OpenemsException { - this.sendMessage(notification); + public boolean send(JsonrpcNotification notification) { + return this.sendMessage(notification); } /** * Sends the JSON-RPC message. * * @param message the JSON-RPC Message - * @throws OpenemsException on error + * @return true if sending was successful; false otherwise */ - private void sendMessage(JsonrpcMessage message) throws OpenemsException { - if (this.websocket == null) { - throw new OpenemsException("There is no Websocket defined for this WsData."); + private boolean sendMessage(JsonrpcMessage message) { + if (!this.websocket.isOpen()) { + return false; } try { this.websocket.send(message.toString()); + return true; } catch (WebsocketNotConnectedException e) { - throw new OpenemsException("Websocket is not connected: " + e.getMessage()); + // handles corner cases + return false; } } diff --git a/io.openems.common/test/io/openems/common/websocket/ClientReconnectorWorkerTest.java b/io.openems.common/test/io/openems/common/websocket/ClientReconnectorWorkerTest.java index 39697e8793e..3eb4161bd07 100644 --- a/io.openems.common/test/io/openems/common/websocket/ClientReconnectorWorkerTest.java +++ b/io.openems.common/test/io/openems/common/websocket/ClientReconnectorWorkerTest.java @@ -2,6 +2,7 @@ import java.net.URI; +import org.java_websocket.WebSocket; import org.junit.Ignore; import org.junit.Test; import org.slf4j.Logger; @@ -10,6 +11,10 @@ public class ClientReconnectorWorkerTest { private static class MyWsData extends WsData { + public MyWsData(WebSocket ws) { + super(ws); + } + @Override public String toString() { return ""; @@ -24,8 +29,8 @@ public MyWebsocketClient(String name, URI serverUri) { } @Override - protected MyWsData createWsData() { - return new MyWsData(); + protected MyWsData createWsData(WebSocket ws) { + return new MyWsData(ws); } @Override @@ -59,9 +64,8 @@ protected OnClose getOnClose() { } @Override - protected void execute(Runnable command) throws Exception { + protected void execute(Runnable command) { // TODO Auto-generated method stub - } @Override diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index 7de47026cfe..46f4680d966 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -78,6 +78,7 @@ bnd.identity;id='io.openems.edge.controller.ess.fixstateofcharge',\ bnd.identity;id='io.openems.edge.controller.ess.gridoptimizedcharge',\ bnd.identity;id='io.openems.edge.controller.ess.hybrid.surplusfeedtogrid',\ + bnd.identity;id='io.openems.edge.controller.ess.limiter14a',\ bnd.identity;id='io.openems.edge.controller.ess.limittotaldischarge',\ bnd.identity;id='io.openems.edge.controller.ess.linearpowerband',\ bnd.identity;id='io.openems.edge.controller.ess.mindischargeperiod',\ @@ -112,7 +113,6 @@ bnd.identity;id='io.openems.edge.ess.core',\ bnd.identity;id='io.openems.edge.ess.fenecon.commercial40',\ bnd.identity;id='io.openems.edge.ess.generic',\ - bnd.identity;id='io.openems.edge.ess.mr.gridcon',\ bnd.identity;id='io.openems.edge.ess.samsung',\ bnd.identity;id='io.openems.edge.ess.sma',\ bnd.identity;id='io.openems.edge.evcs.alpitronic.hypercharger',\ @@ -249,6 +249,7 @@ io.openems.edge.controller.ess.fixstateofcharge;version=snapshot,\ io.openems.edge.controller.ess.gridoptimizedcharge;version=snapshot,\ io.openems.edge.controller.ess.hybrid.surplusfeedtogrid;version=snapshot,\ + io.openems.edge.controller.ess.limiter14a;version=snapshot,\ io.openems.edge.controller.ess.limittotaldischarge;version=snapshot,\ io.openems.edge.controller.ess.linearpowerband;version=snapshot,\ io.openems.edge.controller.ess.mindischargeperiod;version=snapshot,\ @@ -285,7 +286,6 @@ io.openems.edge.ess.core;version=snapshot,\ io.openems.edge.ess.fenecon.commercial40;version=snapshot,\ io.openems.edge.ess.generic;version=snapshot,\ - io.openems.edge.ess.mr.gridcon;version=snapshot,\ io.openems.edge.ess.samsung;version=snapshot,\ io.openems.edge.ess.sma;version=snapshot,\ io.openems.edge.evcs.alpitronic.hypercharger;version=snapshot,\ diff --git a/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/BatteryProtection.java b/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/BatteryProtection.java index 44cf766ce8b..b4e927e862d 100644 --- a/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/BatteryProtection.java +++ b/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/BatteryProtection.java @@ -23,6 +23,7 @@ *

    4. Voltage-to-Percent characteristics based on Min- and Max-Cell-Voltage *
    5. Temperature-to-Percent characteristics based on Min- and * Max-Cell-Temperature + *
    6. SoC-to-Percent characteristics *
    7. Linear max increase limit (e.g. 0.5 A per second) *
    8. Force Charge/Discharge mode (e.g. -1 A to enforce charge/discharge) * @@ -150,6 +151,33 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { BP_DISCHARGE_MAX_TEMPERATURE(Doc.of(OpenemsType.INTEGER) // .unit(Unit.DEGREE_CELSIUS) // .persistencePriority(PersistencePriority.MEDIUM)), // + + /** + * Charge Maximum Current limited by the state of charge. + * + *
        + *
      • Interface: BatteryProtection + *
      • Type: Integer + *
      • Unit: Ampere + *
      + */ + BP_CHARGE_MAX_SOC(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.AMPERE) // + .persistencePriority(PersistencePriority.MEDIUM)), // + + /** + * Discharge Maximum Current limited by the state of charge. + * + *
        + *
      • Interface: BatteryProtection + *
      • Type: Integer + *
      • Unit: Ampere + *
      + */ + BP_DISCHARGE_MAX_SOC(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.AMPERE) // + .persistencePriority(PersistencePriority.MEDIUM)), // + /** * Charge Max-Increase Current limit. * @@ -242,6 +270,7 @@ public Builder applyBatteryProtectionDefinition(BatteryProtectionDefinition def, ChargeMaxCurrentHandler.create(clockProvider, def.getInitialBmsMaxEverChargeCurrent()) // .setVoltageToPercent(def.getChargeVoltageToPercent()) // .setTemperatureToPercent(def.getChargeTemperatureToPercent()) // + .setSocToPercent(def.getChargeSocToPercent()) // .setMaxIncreasePerSecond(def.getMaxIncreaseAmperePerSecond()) // .setForceDischarge(def.getForceDischargeParams()) // .build()) // @@ -249,6 +278,7 @@ public Builder applyBatteryProtectionDefinition(BatteryProtectionDefinition def, DischargeMaxCurrentHandler.create(clockProvider, def.getInitialBmsMaxEverDischargeCurrent()) // .setVoltageToPercent(def.getDischargeVoltageToPercent()) .setTemperatureToPercent(def.getDischargeTemperatureToPercent()) // + .setSocToPercent(def.getDischargeSocToPercent()) // .setMaxIncreasePerSecond(def.getMaxIncreaseAmperePerSecond()) // .setForceCharge(def.getForceChargeParams()) // .build()) // diff --git a/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/BatteryProtectionDefinition.java b/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/BatteryProtectionDefinition.java index 13f38dc6dc5..759591db1ed 100644 --- a/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/BatteryProtectionDefinition.java +++ b/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/BatteryProtectionDefinition.java @@ -70,6 +70,26 @@ public interface BatteryProtectionDefinition { */ public PolyLine getDischargeTemperatureToPercent(); + /** + * Defines the SoC-to-Percent limits for Charging. + * + *

      + * SoC values are in [%], Percentage in [0,1]. + * + * @return a {@link PolyLine} + */ + public PolyLine getChargeSocToPercent(); + + /** + * Defines the SoC-to-Percent limits for Discharging. + * + *

      + * SoC values are in [%], Percentage in [0,1]. + * + * @return a {@link PolyLine} + */ + public PolyLine getDischargeSocToPercent(); + /** * Defines the parameters for Force-Discharge mode. * diff --git a/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/currenthandler/AbstractMaxCurrentHandler.java b/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/currenthandler/AbstractMaxCurrentHandler.java index 83c84e4d6a1..98bd99b774d 100644 --- a/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/currenthandler/AbstractMaxCurrentHandler.java +++ b/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/currenthandler/AbstractMaxCurrentHandler.java @@ -22,6 +22,7 @@ public abstract static class Builder> { protected PolyLine voltageToPercent = PolyLine.empty(); protected PolyLine temperatureToPercent = PolyLine.empty(); + protected PolyLine socToPercent = PolyLine.empty(); protected Double maxIncreasePerSecond = null; /** @@ -61,6 +62,17 @@ public T setTemperatureToPercent(PolyLine temperatureToPercent) { return this.self(); } + /** + * Sets the SoC-To-Percent characteristics. + * + * @param socToPercent the {@link PolyLine} + * @return a {@link Builder} + */ + public T setSocToPercent(PolyLine socToPercent) { + this.socToPercent = socToPercent; + return this.self(); + } + /** * Sets the Max-Increase-Per-Second parameter in [A]. * @@ -78,6 +90,7 @@ public T setMaxIncreasePerSecond(double maxIncreasePerSecond) { protected final ClockProvider clockProvider; protected final PolyLine voltageToPercent; protected final PolyLine temperatureToPercent; + protected final PolyLine socToPercent; protected final AbstractForceChargeDischarge forceChargeDischarge; protected int bmsMaxEverCurrent; @@ -88,12 +101,13 @@ public T setMaxIncreasePerSecond(double maxIncreasePerSecond) { protected Double lastCurrentLimit = null; protected AbstractMaxCurrentHandler(ClockProvider clockProvider, int initialBmsMaxEverCurrent, - PolyLine voltageToPercent, PolyLine temperatureToPercent, Double maxIncreasePerSecond, - AbstractForceChargeDischarge forceChargeDischarge) { + PolyLine voltageToPercent, PolyLine temperatureToPercent, PolyLine socToPercent, + Double maxIncreasePerSecond, AbstractForceChargeDischarge forceChargeDischarge) { this.clockProvider = clockProvider; this.bmsMaxEverCurrent = initialBmsMaxEverCurrent; this.voltageToPercent = voltageToPercent; this.temperatureToPercent = temperatureToPercent; + this.socToPercent = socToPercent; this.maxIncreasePerSecond = maxIncreasePerSecond; this.forceChargeDischarge = forceChargeDischarge; } @@ -158,6 +172,18 @@ protected AbstractMaxCurrentHandler(ClockProvider clockProvider, int initialBmsM */ protected abstract ChannelId getBpMaxTemperatureChannelId(); + /** + * Gets the ChannelId for Battery-Protection Limit by state of charge. + * + *

        + *
      • {@link ChannelId#BP_CHARGE_MAX_SOC} + *
      • {@link ChannelId#BP_DISCHARGE_MAX_SOC} + *
      + * + * @return the {@link ChannelId} + */ + protected abstract ChannelId getBpMaxSocChannelId(); + /** * Gets the ChannelId for Battery-Protection Limit by Force Charge/Discharge * Mode. @@ -195,6 +221,7 @@ protected AbstractMaxCurrentHandler(ClockProvider clockProvider, int initialBmsM *
    9. Voltage-to-Percent characteristics for Max-Cell-Voltage *
    10. Temperature-to-Percent characteristics for Min-Cell-Temperature *
    11. Temperature-to-Percent characteristics for Max-Cell-Temperature + *
    12. SoC-to-Percent characteristics for SoC limitations *
    13. Applied max increase limit (e.g. 0.5 A per second) *
    14. Force Charge/Discharge mode (e.g. -1 A to enforce charge/discharge) * @@ -208,6 +235,7 @@ public synchronized int calculateCurrentLimit(Battery battery) { var maxCellVoltage = battery.getMaxCellVoltage().get(); var minCellTemperature = battery.getMinCellTemperature().get(); var maxCellTemperature = battery.getMaxCellTemperature().get(); + var soc = battery.getSoc().get(); IntegerReadChannel bpBmsChannel = battery.channel(this.getBpBmsChannelId()); var bpBms = bpBmsChannel.value().get(); @@ -227,6 +255,8 @@ public synchronized int calculateCurrentLimit(Battery battery) { // Calculate Ampere limit for Max-Cell-Temperature final var maxCellTemperatureLimit = this .percentToAmpere(this.temperatureToPercent.getValue(maxCellTemperature)); + // Calculate Ampere limit for State of Charge + final var maxSocLimit = this.percentToAmpere(this.socToPercent.getValue(soc)); // Calculate Max Increase Ampere Limit final var maxIncreaseAmpereLimit = this.getMaxIncreaseAmpereLimit(); // Calculate Force Current @@ -244,6 +274,8 @@ public synchronized int calculateCurrentLimit(Battery battery) { .setNextValue(TypeUtils.orElse(minCellTemperatureLimit, this.bmsMaxEverCurrent)); battery.channel(this.getBpMaxTemperatureChannelId()) .setNextValue(TypeUtils.orElse(maxCellTemperatureLimit, this.bmsMaxEverCurrent)); + battery.channel(this.getBpMaxSocChannelId()) + .setNextValue(TypeUtils.orElse(maxSocLimit, this.bmsMaxEverCurrent)); battery.channel(this.getBpMaxIncreaseAmpereChannelId()) .setNextValue(TypeUtils.orElse(maxIncreaseAmpereLimit, this.bmsMaxEverCurrent)); battery.channel(this.getBpForceCurrentChannelId()) diff --git a/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/currenthandler/ChargeMaxCurrentHandler.java b/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/currenthandler/ChargeMaxCurrentHandler.java index 406feec4463..f7844017f0b 100644 --- a/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/currenthandler/ChargeMaxCurrentHandler.java +++ b/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/currenthandler/ChargeMaxCurrentHandler.java @@ -66,7 +66,7 @@ public Builder setForceDischarge(ForceDischarge.Params forceDischargeParams) { */ public ChargeMaxCurrentHandler build() { return new ChargeMaxCurrentHandler(this.clockProvider, this.initialBmsMaxEverCurrent, this.voltageToPercent, - this.temperatureToPercent, this.maxIncreasePerSecond, this.forceDischargeParams); + this.temperatureToPercent, this.socToPercent, this.maxIncreasePerSecond, this.forceDischargeParams); } @Override @@ -92,10 +92,10 @@ public static Builder create(ClockProvider clockProvider, int initialBmsMaxEverA } protected ChargeMaxCurrentHandler(ClockProvider clockProvider, int initialBmsMaxEverAllowedChargeCurrent, - PolyLine voltageToPercent, PolyLine temperatureToPercent, Double maxIncreasePerSecond, - ForceDischarge.Params forceDischargeParams) { + PolyLine voltageToPercent, PolyLine temperatureToPercent, PolyLine socToPercent, + Double maxIncreasePerSecond, ForceDischarge.Params forceDischargeParams) { super(clockProvider, initialBmsMaxEverAllowedChargeCurrent, voltageToPercent, temperatureToPercent, - maxIncreasePerSecond, ForceDischarge.from(forceDischargeParams)); + socToPercent, maxIncreasePerSecond, ForceDischarge.from(forceDischargeParams)); } @Override @@ -123,6 +123,11 @@ protected ChannelId getBpMaxTemperatureChannelId() { return BatteryProtection.ChannelId.BP_CHARGE_MAX_TEMPERATURE; } + @Override + protected ChannelId getBpMaxSocChannelId() { + return BatteryProtection.ChannelId.BP_CHARGE_MAX_SOC; + } + @Override protected ChannelId getBpMaxIncreaseAmpereChannelId() { return BatteryProtection.ChannelId.BP_CHARGE_INCREASE; @@ -132,5 +137,4 @@ protected ChannelId getBpMaxIncreaseAmpereChannelId() { protected ChannelId getBpForceCurrentChannelId() { return BatteryProtection.ChannelId.BP_FORCE_DISCHARGE; } - } diff --git a/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/currenthandler/DischargeMaxCurrentHandler.java b/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/currenthandler/DischargeMaxCurrentHandler.java index d3adbb24852..997f4fd6e77 100644 --- a/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/currenthandler/DischargeMaxCurrentHandler.java +++ b/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/currenthandler/DischargeMaxCurrentHandler.java @@ -65,7 +65,7 @@ public Builder setForceCharge(ForceCharge.Params forceChargeParams) { */ public DischargeMaxCurrentHandler build() { return new DischargeMaxCurrentHandler(this.clockProvider, this.initialBmsMaxEverCurrent, - this.voltageToPercent, this.temperatureToPercent, this.maxIncreasePerSecond, + this.voltageToPercent, this.temperatureToPercent, this.socToPercent, this.maxIncreasePerSecond, ForceCharge.from(this.forceChargeParams)); } @@ -92,9 +92,9 @@ public static Builder create(ClockProvider clockProvider, int initialBmsMaxEverD } protected DischargeMaxCurrentHandler(ClockProvider clockProvider, int initialBmsMaxEverDischargeCurrent, - PolyLine voltageToPercent, PolyLine temperatureToPercent, Double maxIncreasePerSecond, - ForceCharge forceCharge) { - super(clockProvider, initialBmsMaxEverDischargeCurrent, voltageToPercent, temperatureToPercent, + PolyLine voltageToPercent, PolyLine temperatureToPercent, PolyLine socToPercent, + Double maxIncreasePerSecond, ForceCharge forceCharge) { + super(clockProvider, initialBmsMaxEverDischargeCurrent, voltageToPercent, temperatureToPercent, socToPercent, maxIncreasePerSecond, forceCharge); } @@ -123,6 +123,11 @@ protected ChannelId getBpMaxTemperatureChannelId() { return BatteryProtection.ChannelId.BP_DISCHARGE_MAX_TEMPERATURE; } + @Override + protected ChannelId getBpMaxSocChannelId() { + return BatteryProtection.ChannelId.BP_DISCHARGE_MAX_SOC; + } + @Override protected ChannelId getBpMaxIncreaseAmpereChannelId() { return BatteryProtection.ChannelId.BP_DISCHARGE_INCREASE; @@ -132,5 +137,4 @@ protected ChannelId getBpMaxIncreaseAmpereChannelId() { protected ChannelId getBpForceCurrentChannelId() { return BatteryProtection.ChannelId.BP_FORCE_CHARGE; } - } diff --git a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/BatteryProtectionDefinitionBydC130.java b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/BatteryProtectionDefinitionBydC130.java index 8af87ce25bc..6baf45b8ea5 100644 --- a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/BatteryProtectionDefinitionBydC130.java +++ b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/BatteryProtectionDefinitionBydC130.java @@ -80,4 +80,14 @@ public ForceCharge.Params getForceChargeParams() { public Double getMaxIncreaseAmperePerSecond() { return 0.1; // [A] per second } + + @Override + public PolyLine getChargeSocToPercent() { + return PolyLine.empty(); + } + + @Override + public PolyLine getDischargeSocToPercent() { + return PolyLine.empty(); + } } \ No newline at end of file diff --git a/io.openems.edge.battery.fenecon.commercial/src/io/openems/edge/battery/fenecon/commercial/BatteryProtectionDefinition.java b/io.openems.edge.battery.fenecon.commercial/src/io/openems/edge/battery/fenecon/commercial/BatteryProtectionDefinition.java index 0f6aa0daadb..78a82bdf242 100644 --- a/io.openems.edge.battery.fenecon.commercial/src/io/openems/edge/battery/fenecon/commercial/BatteryProtectionDefinition.java +++ b/io.openems.edge.battery.fenecon.commercial/src/io/openems/edge/battery/fenecon/commercial/BatteryProtectionDefinition.java @@ -82,4 +82,14 @@ public ForceCharge.Params getForceChargeParams() { public Double getMaxIncreaseAmperePerSecond() { return 0.5; // [A] per second } + + @Override + public PolyLine getChargeSocToPercent() { + return PolyLine.empty(); + } + + @Override + public PolyLine getDischargeSocToPercent() { + return PolyLine.empty(); + } } \ No newline at end of file diff --git a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/BatteryFeneconHome.java b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/BatteryFeneconHome.java index 9de0fccbd03..0ea7cc798ae 100644 --- a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/BatteryFeneconHome.java +++ b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/BatteryFeneconHome.java @@ -125,7 +125,7 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId .text("Rack Under Temperature Alarm")), // RACK_PRE_ALARM_CELL_VOLTAGE_DIFFERENCE(Doc.of(OpenemsType.BOOLEAN) // .accessMode(AccessMode.READ_ONLY) // - .text("Rack Cell VOltage Difference Alarm")), // + .text("Rack Cell Voltage Difference Alarm")), // RACK_PRE_ALARM_BCU_TEMP_DIFFERENCE(Doc.of(OpenemsType.BOOLEAN) // .accessMode(AccessMode.READ_ONLY) // .text("Rack BCU Temp Difference Alarm")), // @@ -167,7 +167,7 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId RACK_LEVEL_1_OVER_DISCHARGING_POWER(Doc.of(OpenemsType.BOOLEAN) // .accessMode(AccessMode.READ_ONLY) // .text("Rack Over Discharging warning")), // - RACK_LEVEL_2_CELL_OVER_VOLTAGE(Doc.of(Level.WARNING) // + RACK_LEVEL_2_CELL_OVER_VOLTAGE(Doc.of(Level.INFO) // .accessMode(AccessMode.READ_ONLY) // .text("Rack Cell Over Voltage Fault")), // RACK_LEVEL_2_CELL_UNDER_VOLTAGE(Doc.of(Level.WARNING) // @@ -272,7 +272,7 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId .text("Warning BCU 10 Position")), // // Fault BCU Position - FAULT_POSITION_BCU_1(Doc.of(Level.WARNING) // + FAULT_POSITION_BCU_1(Doc.of(Level.INFO) // .accessMode(AccessMode.READ_ONLY) // .text("Fault BCU 1 Position")), // FAULT_POSITION_BCU_2(Doc.of(Level.WARNING) // @@ -657,7 +657,8 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId TOWER_0_BMS_SOFTWARE_VERSION(new IntegerDoc() // .unit(Unit.NONE) // .accessMode(AccessMode.READ_ONLY) // - .text("Bms software version of first tower")), + .text("Bms software version of first tower") // + .onChannelChange(BatteryFeneconHomeImpl::updateNumberOfTowersAndModules)), BATTERY_HARDWARE_TYPE(Doc.of(BatteryFeneconHomeHardwareType.values()) // .onChannelChange(BatteryFeneconHomeImpl::updateNumberOfTowersAndModules)), 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 51dad2bc072..c941c32eab6 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 @@ -6,7 +6,6 @@ import java.time.Instant; import java.util.List; -import java.util.Objects; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; @@ -59,6 +58,7 @@ import io.openems.edge.common.channel.ChannelId.ChannelIdImpl; import io.openems.edge.common.channel.ChannelUtils; import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.channel.IntegerReadChannel; import io.openems.edge.common.channel.internal.OpenemsTypeDoc; import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.component.OpenemsComponent; @@ -494,13 +494,22 @@ protected synchronized void updateNumberOfTowersAndModules() { BatteryFeneconHome.ChannelId.TOWER_2_BMS_SOFTWARE_VERSION, // BatteryFeneconHome.ChannelId.TOWER_3_BMS_SOFTWARE_VERSION, // BatteryFeneconHome.ChannelId.TOWER_4_BMS_SOFTWARE_VERSION// - ); + ) // + .stream() // + .map(c -> { + IntegerReadChannel channel = this.channel(c); + return channel.value().get(); + }) // + .toList(); - final var numberOfTowers = this.calculateTowerNumberFromSoftwareVersion(softwareVersionlist); + final var numberOfTowers = calculateTowerNumberFromSoftwareVersion(softwareVersionlist); // Write 'TOWER_NUMBER' Debug Channel Channel numberOfTowersChannel = this.channel(BatteryFeneconHome.ChannelId.NUMBER_OF_TOWERS); numberOfTowersChannel.setNextValue(numberOfTowers); + if (numberOfTowers == null) { + return; + } final var moduleMaxVoltage = this.getBatteryHardwareType().moduleMaxVoltage; final var moduleMinVoltage = this.getBatteryHardwareType().moduleMinVoltage; @@ -521,20 +530,19 @@ protected synchronized void updateNumberOfTowersAndModules() { } } - private int calculateTowerNumberFromSoftwareVersion(List channelIdList) { - var numberOftowers = 1; - for (var channelId : channelIdList) { - if (channelId == null) { - return numberOftowers; + protected static Integer calculateTowerNumberFromSoftwareVersion(List versionList) { + var numberOfTowers = 0; + for (var version : versionList) { + if (version == null) { + return null; } - Channel channel = this.channel(channelId); - var softwareVersion = channel.value(); - if (softwareVersion.isDefined() && !Objects.equals(softwareVersion.get(), 0) - && !Objects.equals(softwareVersion.get(), 256)) { - numberOftowers++; + if (version == 0 || version == 256) { + // Ensure number of towers is never '0' if registers are not null. + return Math.max(1, numberOfTowers); } + numberOfTowers++; } - return numberOftowers; + return numberOfTowers; } private int lastNumberOfTowers = 0; @@ -638,7 +646,7 @@ private synchronized void initializeTowerModulesChannels(int numberOfTowers, int OpenemsType.BOOLEAN))), m(new BitsWordElement(towerOffset + 5, this) .bit(0, this.generateTowerChannel(tower, "LEVEL_2_CELL_OVER_VOLTAGE", - Level.WARNING)) // + Level.INFO)) // .bit(1, this.generateTowerChannel(tower, "LEVEL_2_CELL_UNDER_VOLTAGE", Level.WARNING)) // .bit(2, this.generateTowerChannel(tower, "LEVEL_2_OVER_CHARGING_CURRENT", diff --git a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/FeneconHomeBatteryProtection52.java b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/FeneconHomeBatteryProtection52.java index 23af1a9c6f5..5e834bbe2a3 100644 --- a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/FeneconHomeBatteryProtection52.java +++ b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/FeneconHomeBatteryProtection52.java @@ -40,6 +40,25 @@ public PolyLine getDischargeTemperatureToPercent() { return PolyLine.empty(); } + @Override + public PolyLine getChargeSocToPercent() { + return PolyLine.create() // + .addPoint(0, 1) // + .addPoint(Math.nextDown(95), 1) // + .addPoint(95, 1) // + .addPoint(96, 1) // + .addPoint(97, 0.625) // + .addPoint(98, 0.4) // + .addPoint(99, 0.2) // + .addPoint(100, 0.05) // + .build(); + } + + @Override + public PolyLine getDischargeSocToPercent() { + return PolyLine.empty(); + } + @Override public ForceDischarge.Params getForceDischargeParams() { return new ForceDischarge.Params(3550, 3490, 3450); diff --git a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/FeneconHomeBatteryProtection64.java b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/FeneconHomeBatteryProtection64.java index a6bacc3659a..bbad1e67bde 100644 --- a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/FeneconHomeBatteryProtection64.java +++ b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/FeneconHomeBatteryProtection64.java @@ -50,6 +50,24 @@ public PolyLine getDischargeTemperatureToPercent() { return PolyLine.empty(); } + @Override + public PolyLine getChargeSocToPercent() { + return PolyLine.create() // + .addPoint(0, 1) // + .addPoint(Math.nextDown(96), 1) // + .addPoint(96, 0.8) // + .addPoint(97, 0.6) // + .addPoint(98, 0.4) // + .addPoint(99, 0.2) // + .addPoint(100, 0.08) // + .build(); + } + + @Override + public PolyLine getDischargeSocToPercent() { + return PolyLine.empty(); + } + @Override public ForceDischarge.Params getForceDischargeParams() { return new ForceDischarge.Params(3600, 3540, 3450); @@ -64,5 +82,4 @@ public ForceCharge.Params getForceChargeParams() { public Double getMaxIncreaseAmperePerSecond() { return 0.1; // [A] per second } - } diff --git a/io.openems.edge.battery.fenecon.home/test/io/openems/edge/battery/fenecon/home/BatteryFeneconHomeImplTest.java b/io.openems.edge.battery.fenecon.home/test/io/openems/edge/battery/fenecon/home/BatteryFeneconHomeImplTest.java index 9327aaa91cc..432eccdcb6e 100644 --- a/io.openems.edge.battery.fenecon.home/test/io/openems/edge/battery/fenecon/home/BatteryFeneconHomeImplTest.java +++ b/io.openems.edge.battery.fenecon.home/test/io/openems/edge/battery/fenecon/home/BatteryFeneconHomeImplTest.java @@ -51,6 +51,23 @@ public class BatteryFeneconHomeImplTest { private static final ChannelAddress CURRENT = new ChannelAddress(BATTERY_ID, Battery.ChannelId.CURRENT.id()); private static final ChannelAddress MIN_CELL_VOLTAGE = new ChannelAddress(BATTERY_ID, Battery.ChannelId.MIN_CELL_VOLTAGE.id()); + private static final ChannelAddress TOWER_0_BMS_SOFTWARE_VERSION = new ChannelAddress(BATTERY_ID, + BatteryFeneconHome.ChannelId.TOWER_0_BMS_SOFTWARE_VERSION.id()); + private static final ChannelAddress TOWER_1_BMS_SOFTWARE_VERSION = new ChannelAddress(BATTERY_ID, + BatteryFeneconHome.ChannelId.TOWER_1_BMS_SOFTWARE_VERSION.id()); + private static final ChannelAddress TOWER_2_BMS_SOFTWARE_VERSION = new ChannelAddress(BATTERY_ID, + BatteryFeneconHome.ChannelId.TOWER_2_BMS_SOFTWARE_VERSION.id()); + private static final ChannelAddress TOWER_3_BMS_SOFTWARE_VERSION = new ChannelAddress(BATTERY_ID, + BatteryFeneconHome.ChannelId.TOWER_3_BMS_SOFTWARE_VERSION.id()); + private static final ChannelAddress TOWER_4_BMS_SOFTWARE_VERSION = new ChannelAddress(BATTERY_ID, + BatteryFeneconHome.ChannelId.TOWER_4_BMS_SOFTWARE_VERSION.id()); + private static final ChannelAddress NUMBER_OF_TOWERS = new ChannelAddress(BATTERY_ID, + BatteryFeneconHome.ChannelId.NUMBER_OF_TOWERS.id()); + private static final ChannelAddress NUMBER_OF_MODULES_PER_TOWER = new ChannelAddress(BATTERY_ID, + BatteryFeneconHome.ChannelId.NUMBER_OF_MODULES_PER_TOWER.id()); + private static final ChannelAddress BP_CHARGE_MAX_SOC = new ChannelAddress(BATTERY_ID, + BatteryProtection.ChannelId.BP_CHARGE_MAX_SOC.id()); + private static final ChannelAddress SOC = new ChannelAddress(BATTERY_ID, Battery.ChannelId.SOC.id()); private static final ChannelAddress BATTERY_RELAY = new ChannelAddress(IO_ID, "InputOutput4"); @@ -496,4 +513,158 @@ public void testMinVoltageCharging() throws Exception { .output(LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED, false) // ); } + + @Test + public void testNumberOfTowers() throws Exception { + final var clock = new TimeLeapClock(Instant.parse("2020-01-01T01:00:00.00Z"), ZoneOffset.UTC); + var sut = new BatteryFeneconHomeImpl(); + new ComponentTest(sut) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("componentManager", new DummyComponentManager(clock)) // + .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addComponent(new DummyInputOutput(IO_ID)) // + .activate(MyConfig.create() // + .setId(BATTERY_ID) // + .setModbusId(MODBUS_ID) // + .setModbusUnitId(0) // + .setStartStop(StartStopConfig.START) // + .setBatteryStartUpRelay("io0/InputOutput4")// + .build())// + + .next(new TestCase() // + .input(BATTERY_RELAY, false) // + .input(BMS_CONTROL, true) // Switched On + .output(STATE_MACHINE, StateMachine.State.UNDEFINED))// + .next(new TestCase() // + .onBeforeProcessImage(assertLog(sut, "GoRunning-Undefined")) // + .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .next(new TestCase() // + .onBeforeProcessImage(assertLog(sut, "GoRunning-StartUpRelayOff")) // + .output(STATE_MACHINE, StateMachine.State.GO_RUNNING))// + .next(new TestCase() // + .onBeforeProcessImage(assertLog(sut, "GoRunning-RetryModbusCommunication")) // + .output(STATE_MACHINE, StateMachine.State.GO_RUNNING))// + .next(new TestCase() // + .onBeforeProcessImage(assertLog(sut, "GoRunning-WaitForBmsControl")) // + .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .next(new TestCase() // + .onBeforeProcessImage(assertLog(sut, "GoRunning-WaitForModbusCommunication")) // + .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .next(new TestCase() // + .output(STATE_MACHINE, StateMachine.State.RUNNING)) + .next(new TestCase() // + .output(NUMBER_OF_TOWERS, null)) + .next(new TestCase() // + .input(NUMBER_OF_MODULES_PER_TOWER, 7) // + .input(TOWER_0_BMS_SOFTWARE_VERSION, 262) // + .input(TOWER_1_BMS_SOFTWARE_VERSION, 0) // + .input(TOWER_2_BMS_SOFTWARE_VERSION, 0) // + .input(TOWER_3_BMS_SOFTWARE_VERSION, 0) // + .input(TOWER_4_BMS_SOFTWARE_VERSION, 256) // + .output(NUMBER_OF_TOWERS, 1)) // + .next(new TestCase() // + .input(TOWER_0_BMS_SOFTWARE_VERSION, 262) // + .input(TOWER_1_BMS_SOFTWARE_VERSION, null) // + .input(TOWER_2_BMS_SOFTWARE_VERSION, null) // + .input(TOWER_3_BMS_SOFTWARE_VERSION, null) // + .input(TOWER_4_BMS_SOFTWARE_VERSION, null) // + .output(NUMBER_OF_TOWERS, null)) // + .next(new TestCase() // + .input(TOWER_0_BMS_SOFTWARE_VERSION, 262) // + .input(TOWER_1_BMS_SOFTWARE_VERSION, 0) // + .input(TOWER_2_BMS_SOFTWARE_VERSION, 0) // + .input(TOWER_3_BMS_SOFTWARE_VERSION, 0) // + .input(TOWER_4_BMS_SOFTWARE_VERSION, 256) // + .output(NUMBER_OF_TOWERS, 1)) // + .next(new TestCase() // + .output(NUMBER_OF_TOWERS, 1)) // + .next(new TestCase() // + .input(NUMBER_OF_TOWERS, null) // + .input(NUMBER_OF_MODULES_PER_TOWER, 7) // + .output(NUMBER_OF_TOWERS, null)) // + .next(new TestCase() // + .input(TOWER_0_BMS_SOFTWARE_VERSION, null) // + .input(TOWER_1_BMS_SOFTWARE_VERSION, 0) // + .input(TOWER_2_BMS_SOFTWARE_VERSION, 0) // + .input(TOWER_3_BMS_SOFTWARE_VERSION, 0) // + .input(TOWER_4_BMS_SOFTWARE_VERSION, 256) // + .output(NUMBER_OF_TOWERS, null)) // + .next(new TestCase() // Number of towers changes after TOWER_0_BMS_SOFTWARE_VERSION is set + .input(TOWER_0_BMS_SOFTWARE_VERSION, 262) // + .input(TOWER_1_BMS_SOFTWARE_VERSION, 0) // + .input(TOWER_2_BMS_SOFTWARE_VERSION, 0) // + .input(TOWER_3_BMS_SOFTWARE_VERSION, 0) // + .input(TOWER_4_BMS_SOFTWARE_VERSION, 256) // + .output(NUMBER_OF_TOWERS, 1)) // + ; + } + + /** + * Battery charge power limited by the {@link FeneconHomeBatteryProtection52}. + * + * @throws Exception on error + */ + @Test + public void testBatteryProtectionSocLimitations() throws Exception { + var sut = new BatteryFeneconHomeImpl(); + new ComponentTest(sut) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("componentManager", new DummyComponentManager()) // + .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addComponent(new DummyInputOutput(IO_ID))// + .activate(MyConfig.create() // + .setId(BATTERY_ID) // + .setModbusId(MODBUS_ID) // + .setModbusUnitId(0) // + .setStartStop(StartStopConfig.START) // + .setBatteryStartUpRelay("io0/InputOutput4")// + .build()) // + + .next(new TestCase() // + .input(BATTERY_RELAY, false) // + .input(BMS_CONTROL, true) // Switched On + .output(STATE_MACHINE, StateMachine.State.UNDEFINED))// + .next(new TestCase() // + .onBeforeProcessImage(assertLog(sut, "GoRunning-Undefined")) // + .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .next(new TestCase() // + .onBeforeProcessImage(assertLog(sut, "GoRunning-StartUpRelayOff")) // + .output(STATE_MACHINE, StateMachine.State.GO_RUNNING))// + .next(new TestCase() // + .onBeforeProcessImage(assertLog(sut, "GoRunning-RetryModbusCommunication")) // + .output(STATE_MACHINE, StateMachine.State.GO_RUNNING))// + .next(new TestCase() // + .onBeforeProcessImage(assertLog(sut, "GoRunning-WaitForBmsControl")) // + .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .next(new TestCase() // + .onBeforeProcessImage(assertLog(sut, "GoRunning-WaitForModbusCommunication")) // + .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .next(new TestCase() // + .output(STATE_MACHINE, StateMachine.State.RUNNING)) // + .next(new TestCase() // + .output(BP_CHARGE_MAX_SOC, 40)) // + + .next(new TestCase() // + .input(SOC, 97) // + .output(SOC, 97)) // + .next(new TestCase() // + .output(BP_CHARGE_MAX_SOC, (int) Math.round(40 * 0.625))) // + .next(new TestCase() // + .input(SOC, 98)) // + .next(new TestCase() // + .output(BP_CHARGE_MAX_SOC, (int) Math.round(40 * 0.4))) // + .next(new TestCase() // + .input(SOC, 99)) // + .next(new TestCase() // + .output(BP_CHARGE_MAX_SOC, (int) Math.round(40 * 0.2))) // + .next(new TestCase() // + .input(SOC, 100)) // + .next(new TestCase() // + .output(BP_CHARGE_MAX_SOC, (int) Math.round(40 * 0.05))) // + .next(new TestCase() // + .input(SOC, 99)) // + .next(new TestCase() // + .output(BP_CHARGE_MAX_SOC, (int) Math.round(40 * 0.2)) // + ); + } } diff --git a/io.openems.edge.battery.fenecon.home/test/io/openems/edge/battery/fenecon/home/TestStatic.java b/io.openems.edge.battery.fenecon.home/test/io/openems/edge/battery/fenecon/home/TestStatic.java index 3c8d218c3f4..820440a8a49 100644 --- a/io.openems.edge.battery.fenecon.home/test/io/openems/edge/battery/fenecon/home/TestStatic.java +++ b/io.openems.edge.battery.fenecon.home/test/io/openems/edge/battery/fenecon/home/TestStatic.java @@ -1,6 +1,10 @@ package io.openems.edge.battery.fenecon.home; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import java.util.Arrays; +import java.util.List; import org.junit.Test; @@ -21,4 +25,48 @@ public void testGetMinVoltageSubState() { BatteryFeneconHomeImpl.getMinVoltageSubState(2800, Integer.MAX_VALUE, 0)); assertEquals(MinVoltageSubState.ABOVE_LIMIT, BatteryFeneconHomeImpl.getMinVoltageSubState(2800, 2900, 1000)); } + + @Test + public void testCalculateTowerNumberFromSoftwareVersion() { + + List nullList = Arrays.asList(1, null, null, null, null); + + assertNull(BatteryFeneconHomeImpl // + .calculateTowerNumberFromSoftwareVersion(nullList)); + + assertNull(BatteryFeneconHomeImpl // + .calculateTowerNumberFromSoftwareVersion(Arrays.asList(1, null, null, null, null))); + + assertNull(BatteryFeneconHomeImpl // + .calculateTowerNumberFromSoftwareVersion(Arrays.asList(null, null, null, null, 1))); + + assertNull(BatteryFeneconHomeImpl // + .calculateTowerNumberFromSoftwareVersion(Arrays.asList(1, null, 0, null, null))); + + assertNull(BatteryFeneconHomeImpl // + .calculateTowerNumberFromSoftwareVersion(Arrays.asList(null, 1, 0, null, null))); + + // End-Condition met + assertEquals(1, (int) BatteryFeneconHomeImpl // + .calculateTowerNumberFromSoftwareVersion(Arrays.asList(1, 0, null, null, null))); + + assertEquals(1, (int) BatteryFeneconHomeImpl // + .calculateTowerNumberFromSoftwareVersion(Arrays.asList(1, 256, null, null, null))); + + assertEquals(1, (int) BatteryFeneconHomeImpl // + .calculateTowerNumberFromSoftwareVersion(Arrays.asList(1, 256, null, null, null))); + + assertEquals(2, (int) BatteryFeneconHomeImpl // + .calculateTowerNumberFromSoftwareVersion(Arrays.asList(1, 2, 0, 0, 1))); + + assertEquals(3, (int) BatteryFeneconHomeImpl // + .calculateTowerNumberFromSoftwareVersion(Arrays.asList(1, 2, 3, 0, 0))); + + assertEquals(4, (int) BatteryFeneconHomeImpl // + .calculateTowerNumberFromSoftwareVersion(Arrays.asList(4, 4, 4, 4, 0))); + + // Exceptionally not null + assertEquals(1, (int) BatteryFeneconHomeImpl // + .calculateTowerNumberFromSoftwareVersion(Arrays.asList(256, 0, 0, 0, 0))); + } } diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/common/batteryprotection/AbstractBatteryProtectionDefinitionSoltaro.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/common/batteryprotection/AbstractBatteryProtectionDefinitionSoltaro.java index 45ee70893a0..8d1f28b129c 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/common/batteryprotection/AbstractBatteryProtectionDefinitionSoltaro.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/common/batteryprotection/AbstractBatteryProtectionDefinitionSoltaro.java @@ -68,4 +68,14 @@ public final ForceCharge.Params getForceChargeParams() { public final Double getMaxIncreaseAmperePerSecond() { return 0.1; // [A] per second } + + @Override + public PolyLine getChargeSocToPercent() { + return PolyLine.empty(); + } + + @Override + public PolyLine getDischargeSocToPercent() { + return PolyLine.empty(); + } } \ No newline at end of file diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsave.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsave.java index 193b3dbd1d7..d9124765b01 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsave.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsave.java @@ -45,6 +45,19 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { .text("The 'CurrentState' is invalid")), // GRID_DISCONNECTION(Doc.of(Level.FAULT) // .text("External grid protection disconnection (17)")), // + GRID_FAILURE_LINE_TO_LINE(Doc.of(Level.FAULT) // + .text("Grid failure phase-to-phase voltage (47)")), // + LINE_FAILURE_UNDER_FREQ(Doc.of(Level.FAULT) // + .text("Line failure: Grid frequency is too low (48)")), // + LINE_FAILURE_OVER_FREQ(Doc.of(Level.FAULT) // + .text("Line failure: Grid frequency is too high (49)")), // + PROTECTION_SHUTDOWN_LINE_1(Doc.of(Level.FAULT) // + .text("Grid Failure: grid voltage L1 protection (81)")), // + PROTECTION_SHUTDOWN_LINE_2(Doc.of(Level.FAULT) // + .text("Grid Failure: grid voltage L2 protection (82)")), // + PROTECTION_SHUTDOWN_LINE_3(Doc.of(Level.FAULT) // + .text("Grid Failure: grid voltage L3 protection (83)")), // + ; private final Doc doc; @@ -214,27 +227,111 @@ public default void _setGridDisconnection(boolean value) { } /** - * Checks if the system is in a running state. This method retrieves the - * system's global state and determines whether the system is in a running - * state. + * Gets the Channel for ChannelId.GRID_FAILURE_LINE_TO_LINE. + * + * @return the Channel + */ + public default Channel getGridFailureLineToLineChannel() { + return this.channel(ChannelId.GRID_FAILURE_LINE_TO_LINE); + } + + /** + * Writes the value to the ChannelId.GRID_FAILURE_LINE_TO_LINE. + * + * @param value the next value + */ + public default void _setGridFailureLineToLine(boolean value) { + this.getGridFailureLineToLineChannel().setNextValue(value); + } + + /** + * Gets the Channel for ChannelId.LINE_FAILURE_UNDER_FREQ. + * + * @return the Channel + */ + public default Channel getLineFailureUnderFreqChannel() { + return this.channel(ChannelId.LINE_FAILURE_UNDER_FREQ); + } + + /** + * Writes the value to the ChannelId.LINE_FAILURE_UNDER_FREQ. + * + * @param value the next value + */ + public default void _setLineFailureUnderFreq(boolean value) { + this.getLineFailureUnderFreqChannel().setNextValue(value); + } + + /** + * Gets the Channel for ChannelId.LINE_FAILURE_OVER_FREQ. + * + * @return the Channel + */ + public default Channel getLineFailureOverFreqChannel() { + return this.channel(ChannelId.LINE_FAILURE_OVER_FREQ); + } + + /** + * Writes the value to the ChannelId.LINE_FAILURE_OVER_FREQ. * - * @return true if the system is in a running state, false otherwise. + * @param value the next value + */ + public default void _setLineFailureOverFreq(boolean value) { + this.getLineFailureOverFreqChannel().setNextValue(value); + } + + /** + * Gets the Channel for ChannelId.PROTECTION_SHUTDOWN_LINE_1. + * + * @return the Channel */ - public boolean isRunning(); + public default Channel getProtectionShutdownLine1Channel() { + return this.channel(ChannelId.PROTECTION_SHUTDOWN_LINE_1); + } /** - * Checks if the system is in a stop state. This method retrieves the system's - * global state and determines whether the system is in a stop state. + * Writes the value to the ChannelId.PROTECTION_SHUTDOWN_LINE_1. * - * @return true if the system is in a stop state, false otherwise. + * @param value the next value */ - public boolean isShutdown(); + public default void _setProtectionShutdownLine1(boolean value) { + this.getProtectionShutdownLine1Channel().setNextValue(value); + } /** - * Checks if the system is in a fault state. This method retrieves the system's - * global state and determines whether the system is in a fault state. + * Gets the Channel for ChannelId.PROTECTION_SHUTDOWN_LINE_2. * - * @return true if the system is in a fault state, false otherwise. + * @return the Channel */ - public boolean hasFailure(); + public default Channel getProtectionShutdownLine2Channel() { + return this.channel(ChannelId.PROTECTION_SHUTDOWN_LINE_2); + } + + /** + * Writes the value to the ChannelId.PROTECTION_SHUTDOWN_LINE_2. + * + * @param value the next value + */ + public default void _setProtectionShutdownLine2(boolean value) { + this.getProtectionShutdownLine2Channel().setNextValue(value); + } + + /** + * Gets the Channel for ChannelId.PROTECTION_SHUTDOWN_LINE_3. + * + * @return the Channel + */ + public default Channel getProtectionShutdownLine3Channel() { + return this.channel(ChannelId.PROTECTION_SHUTDOWN_LINE_3); + } + + /** + * Writes the value to the ChannelId.PROTECTION_SHUTDOWN_LINE_3. + * + * @param value the next value + */ + public default void _setProtectionShutdownLine3(boolean value) { + this.getProtectionShutdownLine3Channel().setNextValue(value); + } + } 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 80774e5c800..84ec0153305 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 @@ -7,7 +7,9 @@ import java.time.Instant; import java.util.Map; import java.util.Optional; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; +import java.util.stream.Stream; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentContext; @@ -28,10 +30,12 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; +import io.openems.common.types.OptionsEnum; import io.openems.edge.battery.api.Battery; import io.openems.edge.batteryinverter.api.BatteryInverterConstraint; import io.openems.edge.batteryinverter.api.ManagedSymmetricBatteryInverter; import io.openems.edge.batteryinverter.api.SymmetricBatteryInverter; +import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.KacoSunSpecModel.S64201.S64201ControlMode; import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.KacoSunSpecModel.S64201.S64201CurrentState; import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.KacoSunSpecModel.S64201.S64201StVnd; import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.KacoSunSpecModel.S64202.S64202EnLimit; @@ -78,8 +82,9 @@ public class BatteryInverterKacoBlueplanetGridsaveImpl extends AbstractSunSpecBa private static final int DC_MIN_VOLTAGE_LIMIT = 650; private static final int DC_MAX_VOLTAGE_LIMIT = 1315; - private final Logger log = LoggerFactory.getLogger(BatteryInverterKacoBlueplanetGridsaveImpl.class); private final StateMachine stateMachine = new StateMachine(State.UNDEFINED); + private final Logger log = LoggerFactory.getLogger(BatteryInverterKacoBlueplanetGridsaveImpl.class); + private final AtomicReference startStopTarget = new AtomicReference<>(StartStop.UNDEFINED); private final CalculateEnergyFromPower calculateChargeEnergy = new CalculateEnergyFromPower(this, SymmetricBatteryInverter.ChannelId.ACTIVE_CHARGE_ENERGY); @@ -107,7 +112,6 @@ protected void setModbus(BridgeModbus modbus) { * Kaco 92 does not have model 64203. */ private boolean hasSunSpecModel64203 = false; - private StartStop startStopTarget = StartStop.UNDEFINED; /** * Active SunSpec models for KACO blueplanet gridsave. Commented models are @@ -199,11 +203,14 @@ public void run(Battery battery, int setActivePower, int setReactivePower) throw this.setBatteryLimits(battery); // Set if there is grid disconnection failure - this.setGridDisconnectionFailure(); + this.handleGridDisconnection(); // Calculate the Energy values from ActivePower. this.calculateEnergy(); + // Enable reactive power by default + this.enableReactivePower(); + if (this.config.activateWatchdog()) { // Trigger the Watchdog this.triggerWatchdog(); @@ -226,13 +233,50 @@ public void run(Battery battery, int setActivePower, int setReactivePower) throw } } - private void setGridDisconnectionFailure() throws OpenemsException { - Channel stVndChannel = this.getSunSpecChannelOrError(KacoSunSpecModel.S64201.ST_VND); - Value stVnd = stVndChannel.value(); - if (!stVnd.isDefined()) { - return; + /** + * Enable the reactive power by default. + */ + private void enableReactivePower() { + try { + EnumWriteChannel channel = this.getSunSpecChannelOrError(KacoSunSpecModel.S64201.CONTROL_MODE); + setWriteValueIfNotRead(channel, S64201ControlMode.SUNSPEC_CTRL_MODE_QFIX); + } catch (OpenemsNamedException e) { + e.printStackTrace(); } - this._setGridDisconnection(stVnd.asEnum() == S64201StVnd.POWADORPROTECT_DISCONNECTION); + } + + private record HandleFaultChannels(// + SunSpecPoint model, // + OptionsEnum stateEnum, // + Consumer method// + ) { + + } + + private void handleGridDisconnection() { + Stream.of( + new HandleFaultChannels(KacoSunSpecModel.S64201.ST_VND, S64201StVnd.POWADORPROTECT_DISCONNECTION, + this::_setGridDisconnection), // + new HandleFaultChannels(KacoSunSpecModel.S64201.ST_VND, S64201StVnd.GRID_FAILURE_PHASETOPHASE, + this::_setGridFailureLineToLine), // + new HandleFaultChannels(KacoSunSpecModel.S64201.ST_VND, S64201StVnd.LINE_FAILURE_UNDERFREQ, + this::_setLineFailureUnderFreq), // + new HandleFaultChannels(KacoSunSpecModel.S64201.ST_VND, S64201StVnd.LINE_FAILURE_OVERFREQ, + this::_setLineFailureOverFreq), // + new HandleFaultChannels(KacoSunSpecModel.S64201.ST_VND, S64201StVnd.PROTECTION_SHUTDOWN_LINE_1, + this::_setProtectionShutdownLine1), // + new HandleFaultChannels(KacoSunSpecModel.S64201.ST_VND, S64201StVnd.PROTECTION_SHUTDOWN_LINE_2, + this::_setProtectionShutdownLine2), // + new HandleFaultChannels(KacoSunSpecModel.S64201.ST_VND, S64201StVnd.PROTECTION_SHUTDOWN_LINE_3, + this::_setProtectionShutdownLine3))// + .forEach(t -> { + try { + var channel = this.getSunSpecChannelOrError(t.model); + t.method.accept(Objects.equal(channel.value().get(), t.stateEnum)); + } catch (OpenemsException e) { + this.logWarn(this.log, e.getMessage()); + } + }); } @Override @@ -390,13 +434,15 @@ public String debugLog() { @Override public void setStartStop(StartStop value) { - this.startStopTarget = value; + if (this.startStopTarget.getAndSet(value) != value) { + this.stateMachine.forceNextState(State.UNDEFINED); + } } @Override public StartStop getStartStopTarget() { return switch (this.config.startStop()) { - case AUTO -> this.startStopTarget; + case AUTO -> this.startStopTarget.get(); case START -> StartStop.START; case STOP -> StartStop.STOP; }; @@ -461,13 +507,24 @@ protected void addBlock(int startAddress, SunSpecModel model, Priority priority) } } - @Override + /** + * Checks if the system is in a running state. This method retrieves the + * system's global state and determines whether the system is in a running + * state. + * + * @return true if the system is in a running state, false otherwise. + */ public boolean isRunning() { return this.getCurrentState() == S64201CurrentState.GRID_CONNECTED// || this.getCurrentState() == S64201CurrentState.THROTTLED; } - @Override + /** + * Checks if the system is in a stop state. This method retrieves the system's + * global state and determines whether the system is in a stop state. + * + * @return true if the system is in a stop state, false otherwise. + */ public boolean isShutdown() { return this.getCurrentState() == S64201CurrentState.OFF // || this.getCurrentState() == S64201CurrentState.STANDBY // @@ -475,8 +532,14 @@ public boolean isShutdown() { || this.getCurrentState() == S64201CurrentState.SHUTTING_DOWN; } - @Override + /** + * Checks if the system is in a fault state. This method retrieves the system's + * global state and determines whether the system is in a fault state. + * + * @return true if the system is in a fault state, false otherwise. + */ public boolean hasFailure() { return this.hasFaults() || this.getCurrentState() == S64201CurrentState.FAULT; } + } diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/Context.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/Context.java index 9620e98ffba..adc1d2145de 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/Context.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/Context.java @@ -4,10 +4,10 @@ import java.time.Instant; import io.openems.edge.battery.api.Battery; -import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.BatteryInverterKacoBlueplanetGridsave; +import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.BatteryInverterKacoBlueplanetGridsaveImpl; import io.openems.edge.common.statemachine.AbstractContext; -public class Context extends AbstractContext { +public class Context extends AbstractContext { protected final Battery battery; protected final int setActivePower; @@ -16,7 +16,7 @@ public class Context extends AbstractContext { @@ -30,10 +29,6 @@ public State runAndGetNextState(Context context) throws OpenemsNamedException { return State.ERROR; } - if (inverter.getStartStopTarget() == StartStop.STOP) { - return State.GO_STOPPED; - } - if (inverter.isRunning()) { return State.RUNNING; } diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/RunningHandler.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/RunningHandler.java index 986127e902e..810afcbc4ba 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/RunningHandler.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/RunningHandler.java @@ -19,10 +19,6 @@ public State runAndGetNextState(Context context) throws OpenemsNamedException { return State.ERROR; } - if (inverter.getStartStopTarget() == StartStop.STOP) { - return State.GO_STOPPED; - } - this.applyPower(context); inverter._setStartStop(StartStop.START); return State.RUNNING; diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/StoppedHandler.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/StoppedHandler.java index c2a6b23cca2..4aaa423b5e4 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/StoppedHandler.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/StoppedHandler.java @@ -14,10 +14,6 @@ public State runAndGetNextState(Context context) { return State.ERROR; } - if (inverter.getStartStopTarget() == StartStop.START) { - return State.GO_RUNNING; - } - inverter._setStartStop(StartStop.STOP); return State.STOPPED; } diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/UndefinedHandler.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/UndefinedHandler.java index c177bd4538a..6dfb345b6b1 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/UndefinedHandler.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/UndefinedHandler.java @@ -8,23 +8,16 @@ public class UndefinedHandler extends StateHandler { @Override public State runAndGetNextState(Context context) { final var inverter = context.getParent(); - - if (inverter.getCurrentState().isUndefined()) { - return State.UNDEFINED; - } - - if (inverter.hasFailure()) { - return State.ERROR; - } - - if (inverter.isRunning()) { - return State.RUNNING; + return switch (inverter.getStartStopTarget()) { + case UNDEFINED -> State.UNDEFINED; + case START -> { + if (inverter.hasFailure()) { + yield State.ERROR; + } + yield State.GO_RUNNING; } - - if (inverter.isShutdown()) { - return State.STOPPED; - } - - return State.GO_STOPPED; + case STOP -> State.GO_STOPPED; + }; } + } diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/test/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsaveImplTest.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/test/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsaveImplTest.java index d4d2c215065..4bc316e97c5 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/test/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsaveImplTest.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/test/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsaveImplTest.java @@ -109,7 +109,7 @@ public void testStart() throws Exception { .output(STATE_MACHINE, State.UNDEFINED)) // .next(new TestCase() // .timeleap(clock, 4, ChronoUnit.SECONDS) // - .output(STATE_MACHINE, State.STOPPED)) // + .output(STATE_MACHINE, State.GO_RUNNING)) // .next(new TestCase() // .timeleap(clock, 1, ChronoUnit.SECONDS) // .input(CURRENT_STATE, S64201CurrentState.GRID_CONNECTED) // diff --git a/io.openems.edge.common/src/io/openems/edge/common/sum/Sum.java b/io.openems.edge.common/src/io/openems/edge/common/sum/Sum.java index 28d5b71e4bb..c6a903df67c 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/sum/Sum.java +++ b/io.openems.edge.common/src/io/openems/edge/common/sum/Sum.java @@ -486,7 +486,18 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ GRID_MODE(Doc.of(GridMode.values()) // .persistencePriority(PersistencePriority.VERY_HIGH)), // - + /** + * Cumulated Off-Grid time. + * + *
        + *
      • Interface: Sum + *
      • Type: Cumulated Seconds + *
      + */ + GRID_MODE_OFF_GRID_TIME(Doc.of(OpenemsType.LONG) // + .unit(Unit.CUMULATED_SECONDS) // + .persistencePriority(PersistencePriority.VERY_HIGH) // + .text("Total Off-Grid time")), // /** * Ess: Max Apparent Power. * @@ -704,6 +715,7 @@ public static ModbusSlaveNatureTable getModbusSlaveNatureTable(AccessMode access .channel(111, ChannelId.CONSUMPTION_ACTIVE_POWER_L3, ModbusType.FLOAT32) // .channel(113, ChannelId.ESS_DISCHARGE_POWER, ModbusType.FLOAT32) // .channel(115, ChannelId.GRID_MODE, ModbusType.ENUM16) // + .channel(116, ChannelId.GRID_MODE_OFF_GRID_TIME, ModbusType.FLOAT32) // .build(); } @@ -1878,6 +1890,35 @@ public default void _setGridMode(GridMode value) { this.getGridModeChannel().setNextValue(value); } + /** + * Internal method to set the 'nextValue' on + * {@link ChannelId#GRID_MODE_OFF_GRID_TIME} Channel. + * + * @param value the next value + */ + public default void _setGridModeOffGridTime(int value) { + this.getGridModeOffGridTimeChannel().setNextValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#GRID_MODE_OFF_GRID_TIME}. + * + * @return the Channel + */ + public default LongReadChannel getGridModeOffGridTimeChannel() { + return this.channel(ChannelId.GRID_MODE_OFF_GRID_TIME); + } + + /** + * Gets the Overall GridMode of all Energy Storage Systems. See + * {@link ChannelId#GRID_MODE_OFF_GRID_TIME}. + * + * @return the Channel {@link Value} + */ + public default Value getGridModeOffGridTimeValue() { + return this.getGridModeOffGridTimeChannel().value(); + } + /** * Gets the Channel for {@link ChannelId#ESS_ACTIVE_CHARGE_ENERGY}. * diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/BackendOnRequest.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/BackendOnRequest.java index c3d38665a53..30a9194c27a 100644 --- a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/BackendOnRequest.java +++ b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/BackendOnRequest.java @@ -66,7 +66,7 @@ public BackendOnRequest(@Reference RootRequestHandler handler) { } @Override - public CompletableFuture run(// + public CompletableFuture apply(// final WebSocket ws, // final JsonrpcRequest request // ) throws OpenemsNamedException { diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/ControllerApiBackendImpl.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/ControllerApiBackendImpl.java index 50f6109cba7..561e464af4c 100644 --- a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/ControllerApiBackendImpl.java +++ b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/ControllerApiBackendImpl.java @@ -263,8 +263,7 @@ public ScheduledFuture scheduleWithFixedDelay(Runnable command, long initialD } @Override - public CompletableFuture sendRequest(User user, JsonrpcRequest request) - throws OpenemsNamedException { + public CompletableFuture sendRequest(User user, JsonrpcRequest request) { return this.websocket.sendRequest(request); } diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/OnError.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/OnError.java index 4aef7fd29d5..28a652a62ed 100644 --- a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/OnError.java +++ b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/OnError.java @@ -16,7 +16,7 @@ public OnError(ControllerApiBackendImpl parent) { } @Override - public void run(WebSocket ws, Exception ex) throws OpenemsException { + public void accept(WebSocket ws, Exception ex) throws OpenemsException { this.parent.logWarn(this.log, "Error: " + ex.getMessage()); } diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/OnNotification.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/OnNotification.java index e3437e3b337..895c1c1c6ce 100644 --- a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/OnNotification.java +++ b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/OnNotification.java @@ -17,7 +17,7 @@ public OnNotification(ControllerApiBackendImpl parent) { } @Override - public void run(WebSocket ws, JsonrpcNotification notification) throws OpenemsException { + public void accept(WebSocket ws, JsonrpcNotification notification) throws OpenemsException { this.parent.logWarn(this.log, "Unhandled Notification: " + notification); } diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/OnOpen.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/OnOpen.java index 58bea7049ac..815439fa166 100644 --- a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/OnOpen.java +++ b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/OnOpen.java @@ -1,11 +1,11 @@ package io.openems.edge.controller.api.backend; import org.java_websocket.WebSocket; +import org.java_websocket.handshake.Handshakedata; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.gson.JsonObject; - +import io.openems.common.exceptions.OpenemsError; import io.openems.common.jsonrpc.notification.EdgeConfigNotification; public class OnOpen implements io.openems.common.websocket.OnOpen { @@ -18,7 +18,7 @@ public OnOpen(ControllerApiBackendImpl parent) { } @Override - public void run(WebSocket ws, JsonObject handshake) { + public OpenemsError apply(WebSocket ws, Handshakedata handshakedata) { this.parent.logInfo(this.log, "Connected to OpenEMS Backend"); // Immediately send Config @@ -31,6 +31,8 @@ public void run(WebSocket ws, JsonObject handshake) { // Trigger resending data this.parent.resendHistoricDataWorker.triggerNextRun(); + + return null; // No error } } diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/WebsocketClient.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/WebsocketClient.java index 9730473734e..aeb2e73a5ba 100644 --- a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/WebsocketClient.java +++ b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/WebsocketClient.java @@ -7,6 +7,7 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import org.java_websocket.WebSocket; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -63,8 +64,8 @@ public OnClose getOnClose() { } @Override - protected WsData createWsData() { - return new WsData(); + protected WsData createWsData(WebSocket es) { + return new WsData(ws); } @Override diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/WsData.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/WsData.java index 4e762bdc03c..2dfdd355c5b 100644 --- a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/WsData.java +++ b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/WsData.java @@ -1,7 +1,13 @@ package io.openems.edge.controller.api.backend; +import org.java_websocket.WebSocket; + public class WsData extends io.openems.common.websocket.WsData { + public WsData(WebSocket ws) { + super(ws); + } + @Override public String toString() { return "BackendApi.WsData []"; diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/api/ControllerApiBackend.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/api/ControllerApiBackend.java index 90023b35f81..ad3a5694556 100644 --- a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/api/ControllerApiBackend.java +++ b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/api/ControllerApiBackend.java @@ -7,7 +7,6 @@ import io.openems.common.channel.Level; import io.openems.common.channel.PersistencePriority; import io.openems.common.channel.Unit; -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.jsonrpc.base.JsonrpcRequest; import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; import io.openems.common.types.OpenemsType; @@ -86,9 +85,7 @@ public default LongReadChannel getLastSuccessFulResendChannel() { * @param user the user * @param request the request to send * @return the result future - * @throws OpenemsNamedException on error */ - public CompletableFuture sendRequest(User user, JsonrpcRequest request) - throws OpenemsNamedException; + public CompletableFuture sendRequest(User user, JsonrpcRequest request); } diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/ControllerApiWebsocketImpl.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/ControllerApiWebsocketImpl.java index f352756454f..1b5b3a23629 100644 --- a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/ControllerApiWebsocketImpl.java +++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/ControllerApiWebsocketImpl.java @@ -22,7 +22,6 @@ import io.openems.common.jsonrpc.notification.EdgeRpcNotification; import io.openems.common.types.EdgeConfig; import io.openems.common.utils.ThreadPoolUtils; -import io.openems.common.websocket.AbstractWebsocketServer.DebugMode; import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.component.OpenemsComponent; @@ -91,7 +90,7 @@ private void activate(ComponentContext context, Config config) { call.put(ComponentConfigRequestHandler.API_WORKER_KEY, this.apiWorker); }); this.onRequest.setDebug(config.debugMode()); - this.startServer(config.port(), POOL_SIZE, DebugMode.OFF); + this.startServer(config.port(), POOL_SIZE); } @@ -107,12 +106,11 @@ protected void deactivate() { /** * Create and start new server. * - * @param port the port - * @param poolSize number of threads dedicated to handle the tasks - * @param debugMode activate a regular debug log about the state of the tasks + * @param port the port + * @param poolSize number of threads dedicated to handle the tasks */ - private synchronized void startServer(int port, int poolSize, DebugMode debugMode) { - this.server = new WebsocketServer(this, "Websocket Api", port, poolSize, debugMode); + private synchronized void startServer(int port, int poolSize) { + this.server = new WebsocketServer(this, "Websocket Api", port, poolSize); this.server.start(); } diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnClose.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnClose.java index 55be08f5c87..20a3e707600 100644 --- a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnClose.java +++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnClose.java @@ -4,8 +4,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.openems.common.exceptions.OpenemsException; - public class OnClose implements io.openems.common.websocket.OnClose { private final Logger log = LoggerFactory.getLogger(OnClose.class); @@ -16,7 +14,7 @@ public OnClose(ControllerApiWebsocketImpl parent) { } @Override - public void run(WebSocket ws, int code, String reason, boolean remote) throws OpenemsException { + public void accept(WebSocket ws, int code, String reason, boolean remote) { // get websocket attachment WsData wsData = ws.getAttachment(); var user = wsData.getUser(); diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnError.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnError.java index 45e43281920..05655fff44c 100644 --- a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnError.java +++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnError.java @@ -16,7 +16,7 @@ public OnError(ControllerApiWebsocketImpl parent) { } @Override - public void run(WebSocket ws, Exception ex) throws OpenemsException { + public void accept(WebSocket ws, Exception ex) throws OpenemsException { // get websocket attachment WsData wsData = ws.getAttachment(); var user = wsData.getUser(); diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnNotification.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnNotification.java index 63936d150e0..335d2054a4b 100644 --- a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnNotification.java +++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnNotification.java @@ -17,7 +17,7 @@ public OnNotification(ControllerApiWebsocketImpl parent) { } @Override - public void run(WebSocket ws, JsonrpcNotification notification) throws OpenemsException { + public void accept(WebSocket ws, JsonrpcNotification notification) throws OpenemsException { this.parent.logWarn(this.log, "Unhandled Notification: " + notification); } diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnOpen.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnOpen.java deleted file mode 100644 index 6b6dafee1b7..00000000000 --- a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnOpen.java +++ /dev/null @@ -1,15 +0,0 @@ -package io.openems.edge.controller.api.websocket; - -import org.java_websocket.WebSocket; - -import com.google.gson.JsonObject; - -public class OnOpen implements io.openems.common.websocket.OnOpen { - - public OnOpen(ControllerApiWebsocket parent) { - } - - @Override - public void run(WebSocket ws, JsonObject handshake) { - } -} diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnRequest.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnRequest.java index 66f4cd88d34..de44f4eb261 100644 --- a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnRequest.java +++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnRequest.java @@ -77,7 +77,7 @@ protected void unbindRootHandler(RootRequestHandler rootHandler) { } @Override - public CompletableFuture run(WebSocket ws, JsonrpcRequest request) + public CompletableFuture apply(WebSocket ws, JsonrpcRequest request) throws OpenemsNamedException { return this.apiBinder.handleRequest(request, call -> { WsData wsData = ws.getAttachment(); diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WebsocketServer.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WebsocketServer.java index cc0c451279e..708c85e8ea4 100644 --- a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WebsocketServer.java +++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WebsocketServer.java @@ -2,36 +2,36 @@ import java.util.concurrent.RejectedExecutionException; +import org.java_websocket.WebSocket; import org.slf4j.Logger; import io.openems.common.websocket.AbstractWebsocketServer; +import io.openems.common.websocket.OnOpen; +import io.openems.common.websocket.OnRequest; public class WebsocketServer extends AbstractWebsocketServer { private final ControllerApiWebsocketImpl parent; - private final OnOpen onOpen; private final OnNotification onNotification; private final OnError onError; private final OnClose onClose; - public WebsocketServer(ControllerApiWebsocketImpl parent, String name, int port, int poolSize, - DebugMode debugMode) { - super(name, port, poolSize, debugMode); + public WebsocketServer(ControllerApiWebsocketImpl parent, String name, int port, int poolSize) { + super(name, port, poolSize); this.parent = parent; - this.onOpen = new OnOpen(parent); this.onNotification = new OnNotification(parent); this.onError = new OnError(parent); this.onClose = new OnClose(parent); } @Override - protected WsData createWsData() { - return new WsData(this.parent); + protected WsData createWsData(WebSocket ws) { + return new WsData(ws, this.parent); } @Override protected OnOpen getOnOpen() { - return this.onOpen; + return OnOpen.NO_OP; } @Override diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WsData.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WsData.java index 6a455a86972..a92eca5bba8 100644 --- a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WsData.java +++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WsData.java @@ -7,6 +7,7 @@ import java.util.SortedSet; import java.util.TreeSet; +import org.java_websocket.WebSocket; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -14,7 +15,6 @@ import com.google.gson.JsonNull; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.exceptions.OpenemsException; import io.openems.common.jsonrpc.notification.CurrentDataNotification; import io.openems.common.jsonrpc.notification.EdgeRpcNotification; import io.openems.common.jsonrpc.request.SubscribeChannelsRequest; @@ -74,7 +74,6 @@ protected void dispose() { } } - private final Logger log = LoggerFactory.getLogger(WsData.class); private final ControllerApiWebsocketImpl parent; private final SubscribedChannels subscribedChannels = new SubscribedChannels(); @@ -86,7 +85,8 @@ protected void dispose() { private Optional user = Optional.empty(); - public WsData(ControllerApiWebsocketImpl parent) { + public WsData(WebSocket ws, ControllerApiWebsocketImpl parent) { + super(ws); this.parent = parent; } @@ -172,14 +172,9 @@ public void sendSubscribedChannels() { return; } this.parent.server.execute(() -> { - try { - this.send(// - new EdgeRpcNotification(ControllerApiWebsocket.EDGE_ID, // - new CurrentDataNotification(values))); - - } catch (OpenemsException e) { - this.parent.logWarn(this.log, "Unable to send CurrentDataNotification: " + e.getMessage()); - } + this.send(// + new EdgeRpcNotification(ControllerApiWebsocket.EDGE_ID, // + new CurrentDataNotification(values))); }); } diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/SubscribeSystemLogRequestHandler.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/SubscribeSystemLogRequestHandler.java index 172251df193..5b8a75f4d25 100644 --- a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/SubscribeSystemLogRequestHandler.java +++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/SubscribeSystemLogRequestHandler.java @@ -6,10 +6,7 @@ import org.ops4j.pax.logging.spi.PaxAppender; import org.ops4j.pax.logging.spi.PaxLoggingEvent; import org.osgi.service.component.annotations.Component; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import io.openems.common.exceptions.OpenemsException; import io.openems.common.jsonrpc.base.GenericJsonrpcResponseSuccess; import io.openems.common.jsonrpc.notification.EdgeRpcNotification; import io.openems.common.jsonrpc.notification.SystemLogNotification; @@ -26,8 +23,6 @@ }) public class SubscribeSystemLogRequestHandler implements JsonApi, PaxAppender { - private final Logger log = LoggerFactory.getLogger(SubscribeSystemLogRequestHandler.class); - private final Set subscribers = ConcurrentHashMap.newKeySet(); @Override @@ -63,12 +58,7 @@ public void doAppend(PaxLoggingEvent event) { iter.remove(); continue; } - try { - wsData.send(notification); - } catch (OpenemsException e) { - this.log.warn("Unable to handle PaxLoggingEvent", e); - iter.remove(); - } + wsData.send(notification); } } diff --git a/io.openems.edge.ess.mr.gridcon/.classpath b/io.openems.edge.controller.ess.limiter14a/.classpath similarity index 100% rename from io.openems.edge.ess.mr.gridcon/.classpath rename to io.openems.edge.controller.ess.limiter14a/.classpath diff --git a/io.openems.edge.ess.mr.gridcon/.gitignore b/io.openems.edge.controller.ess.limiter14a/.gitignore similarity index 100% rename from io.openems.edge.ess.mr.gridcon/.gitignore rename to io.openems.edge.controller.ess.limiter14a/.gitignore index 36573722b7e..c2b941a96de 100644 --- a/io.openems.edge.ess.mr.gridcon/.gitignore +++ b/io.openems.edge.controller.ess.limiter14a/.gitignore @@ -1,2 +1,2 @@ -/generated/ /bin_test/ +/generated/ diff --git a/io.openems.edge.ess.mr.gridcon/.project b/io.openems.edge.controller.ess.limiter14a/.project similarity index 89% rename from io.openems.edge.ess.mr.gridcon/.project rename to io.openems.edge.controller.ess.limiter14a/.project index 013d1ddbe42..31715aabf64 100644 --- a/io.openems.edge.ess.mr.gridcon/.project +++ b/io.openems.edge.controller.ess.limiter14a/.project @@ -1,6 +1,6 @@ - io.openems.edge.ess.mr.gridcon + io.openems.edge.controller.ess.limiter14a diff --git a/io.openems.edge.ess.mr.gridcon/.settings/org.eclipse.core.resources.prefs b/io.openems.edge.controller.ess.limiter14a/.settings/org.eclipse.core.resources.prefs similarity index 100% rename from io.openems.edge.ess.mr.gridcon/.settings/org.eclipse.core.resources.prefs rename to io.openems.edge.controller.ess.limiter14a/.settings/org.eclipse.core.resources.prefs diff --git a/io.openems.edge.ess.mr.gridcon/bnd.bnd b/io.openems.edge.controller.ess.limiter14a/bnd.bnd similarity index 64% rename from io.openems.edge.ess.mr.gridcon/bnd.bnd rename to io.openems.edge.controller.ess.limiter14a/bnd.bnd index 4ebae0cb9b6..dd10c2715b1 100644 --- a/io.openems.edge.ess.mr.gridcon/bnd.bnd +++ b/io.openems.edge.controller.ess.limiter14a/bnd.bnd @@ -1,19 +1,16 @@ -Bundle-Name: OpenEMS Edge ESS MR Gridcon +Bundle-Name: OpenEMS Edge Controller for §14a EnWG Bundle-Vendor: FENECON GmbH Bundle-License: https://opensource.org/licenses/EPL-2.0 Bundle-Version: 1.0.0.${tstamp} -buildpath: \ ${buildpath},\ - com.ghgande.j2mod,\ io.openems.common,\ - io.openems.edge.battery.api,\ - io.openems.edge.bridge.modbus,\ io.openems.edge.common,\ io.openems.edge.controller.api,\ io.openems.edge.ess.api,\ - io.openems.edge.io.api,\ - io.openems.edge.meter.api + io.openems.edge.timedata.api,\ -testpath: \ - ${testpath} \ No newline at end of file + ${testpath},\ + io.openems.edge.io.api,\ diff --git a/io.openems.edge.controller.ess.limiter14a/readme.adoc b/io.openems.edge.controller.ess.limiter14a/readme.adoc new file mode 100644 index 00000000000..d6723012d8c --- /dev/null +++ b/io.openems.edge.controller.ess.limiter14a/readme.adoc @@ -0,0 +1,8 @@ += ESS §14a EnWG Controller + +Established by law (for Germany), this controller lowers active power to `-4200 W` in response to grid operator limitations, aiming to alleviate load on transformers. + +Link to legislative text: +https://www.gesetze-im-internet.de/enwg_2005/__14a.html + +https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.controller.ess.limiter14a[Source Code icon:github[]] \ No newline at end of file diff --git a/io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/Config.java b/io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/Config.java new file mode 100644 index 00000000000..6a7c1da734c --- /dev/null +++ b/io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/Config.java @@ -0,0 +1,28 @@ +package io.openems.edge.controller.ess.limiter14a; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +@ObjectClassDefinition(// + name = "Controller Ess Limiter §14a", // + description = "Established by law (for Germany), this controller lowers active power to -4200W in response to grid operator limitations, aiming to alleviate load on transformers.") +@interface Config { + + @AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component") + String id() default "ctrlEssLimiter14a0"; + + @AttributeDefinition(name = "Alias", description = "Human-readable name of this Component; defaults to Component-ID") + String alias() default ""; + + @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?") + boolean enabled() default true; + + @AttributeDefinition(name = "Ess-ID", description = "ID of Ess.") + String ess_id() default "ess0"; + + @AttributeDefinition(name = "Input Channel", description = "When receiveing a signal, this channel triggers the execution of the limitation.") + String inputChannelAddress(); + + String webconsole_configurationFactory_nameHint() default "Controller Ess Limiter §14a [{id}]"; + +} \ No newline at end of file diff --git a/io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/ControllerEssLimiter14a.java b/io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/ControllerEssLimiter14a.java new file mode 100644 index 00000000000..1a517ebf33c --- /dev/null +++ b/io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/ControllerEssLimiter14a.java @@ -0,0 +1,64 @@ +package io.openems.edge.controller.ess.limiter14a; + +import io.openems.common.channel.PersistencePriority; +import io.openems.common.channel.Unit; +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.Channel; +import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.channel.value.Value; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.controller.api.Controller; + +public interface ControllerEssLimiter14a extends Controller, OpenemsComponent { + + public enum ChannelId implements io.openems.edge.common.channel.ChannelId { + + RESTRICTION_MODE(Doc.of(RestrictionMode.values()) // + .persistencePriority(PersistencePriority.HIGH)), // + + CUMULATED_RESTRICTION_TIME(Doc.of(OpenemsType.LONG) // + .unit(Unit.CUMULATED_SECONDS) // + .persistencePriority(PersistencePriority.HIGH)); // + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + + } + + /** + * Gets the Channel for {@link ChannelId#RESTRICTION_MODE}. + * + * @return the Channel + */ + public default Channel getRestrictionModeChannel() { + return this.channel(ChannelId.RESTRICTION_MODE); + } + + /** + * Gets the Status. See {@link ChannelId#RESTRICTION_MODE}. + * + * @return the Channel {@link Value} + */ + public default Boolean getRestrictionMode() { + return this.getRestrictionModeChannel().value().get(); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#RESTRICTION_MODE} + * Channel. + * + * @param value the next value + */ + public default void _setRestrictionMode(boolean value) { + this.getRestrictionModeChannel().setNextValue(value); + } + +} diff --git a/io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/ControllerEssLimiter14aImpl.java b/io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/ControllerEssLimiter14aImpl.java new file mode 100644 index 00000000000..a9c1082637f --- /dev/null +++ b/io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/ControllerEssLimiter14aImpl.java @@ -0,0 +1,98 @@ +package io.openems.edge.controller.ess.limiter14a; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.metatype.annotations.Designate; +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.types.ChannelAddress; +import io.openems.edge.common.channel.BooleanReadChannel; +import io.openems.edge.common.component.AbstractOpenemsComponent; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.sum.GridMode; +import io.openems.edge.common.sum.Sum; +import io.openems.edge.controller.api.Controller; +import io.openems.edge.ess.api.ManagedSymmetricEss; +import io.openems.edge.timedata.api.Timedata; +import io.openems.edge.timedata.api.TimedataProvider; +import io.openems.edge.timedata.api.utils.CalculateActiveTime; + +@Designate(ocd = Config.class, factory = true) +@Component(// + name = "Controller.Ess.Limiter14a", // + immediate = true, // + configurationPolicy = ConfigurationPolicy.REQUIRE // +) +public class ControllerEssLimiter14aImpl extends AbstractOpenemsComponent implements // + ControllerEssLimiter14a, Controller, OpenemsComponent, TimedataProvider { + + @Reference + private Sum sum; + + @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) + private volatile Timedata timedata = null; + + @Reference + private ConfigurationAdmin cm; + + @Reference + private ComponentManager componentManager; + + @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) + private ManagedSymmetricEss ess; + + private ChannelAddress inputChannelAddress; + + private final CalculateActiveTime cumulatedRestrictionTime = new CalculateActiveTime(this, + ControllerEssLimiter14a.ChannelId.CUMULATED_RESTRICTION_TIME); + + public ControllerEssLimiter14aImpl() { + super(// + OpenemsComponent.ChannelId.values(), // + Controller.ChannelId.values(), // + ControllerEssLimiter14a.ChannelId.values() // + ); + } + + @Activate + private void activate(ComponentContext context, Config config) throws OpenemsNamedException { + super.activate(context, config.id(), config.alias(), config.enabled()); + this.inputChannelAddress = ChannelAddress.fromString(config.inputChannelAddress()); + + if (OpenemsComponent.updateReferenceFilter(this.cm, this.servicePid(), "ess", config.ess_id())) { + return; + } + } + + @Deactivate + protected void deactivate() { + super.deactivate(); + } + + @Override + public void run() throws OpenemsNamedException { + BooleanReadChannel inputChannel = this.componentManager.getChannel(this.inputChannelAddress); + var onGrid = this.sum.channel(Sum.ChannelId.GRID_MODE).value().asEnum() != GridMode.OFF_GRID; + // 0/1 is reversed on relays board + var isActive = onGrid && !inputChannel.value().orElse(true); + if (isActive) { + this.ess.setActivePowerGreaterOrEquals(-4200); + } + + this.channel(ControllerEssLimiter14a.ChannelId.RESTRICTION_MODE).setNextValue(isActive); + this.cumulatedRestrictionTime.update(isActive); + } + + @Override + public Timedata getTimedata() { + return this.timedata; + } +} \ No newline at end of file diff --git a/io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/RestrictionMode.java b/io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/RestrictionMode.java new file mode 100644 index 00000000000..99858973ea1 --- /dev/null +++ b/io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/RestrictionMode.java @@ -0,0 +1,32 @@ +package io.openems.edge.controller.ess.limiter14a; + +import io.openems.common.types.OptionsEnum; + +public enum RestrictionMode implements OptionsEnum { + UNDEFINED(-1, "Undefined"), // + ON(1, "On"), // + OFF(0, "Off"); + + private int value; + private String name; + + private RestrictionMode(int value, String name) { + this.value = value; + this.name = name; + } + + @Override + public int getValue() { + return this.value; + } + + @Override + public String getName() { + return this.name; + } + + @Override + public OptionsEnum getUndefined() { + return UNDEFINED; + } +} \ No newline at end of file diff --git a/io.openems.edge.ess.mr.gridcon/test/.gitignore b/io.openems.edge.controller.ess.limiter14a/test/.gitignore similarity index 100% rename from io.openems.edge.ess.mr.gridcon/test/.gitignore rename to io.openems.edge.controller.ess.limiter14a/test/.gitignore diff --git a/io.openems.edge.controller.ess.limiter14a/test/io/openems/edge/controller/ess/limiter14a/ControllerEssLimiter14aTest.java b/io.openems.edge.controller.ess.limiter14a/test/io/openems/edge/controller/ess/limiter14a/ControllerEssLimiter14aTest.java new file mode 100644 index 00000000000..22405060dc7 --- /dev/null +++ b/io.openems.edge.controller.ess.limiter14a/test/io/openems/edge/controller/ess/limiter14a/ControllerEssLimiter14aTest.java @@ -0,0 +1,61 @@ +package io.openems.edge.controller.ess.limiter14a; + +import org.junit.Test; + +import io.openems.common.exceptions.OpenemsException; +import io.openems.common.types.ChannelAddress; +import io.openems.edge.common.sum.DummySum; +import io.openems.edge.common.sum.GridMode; +import io.openems.edge.common.test.DummyComponentManager; +import io.openems.edge.common.test.DummyConfigurationAdmin; +import io.openems.edge.common.test.AbstractComponentTest.TestCase; +import io.openems.edge.controller.test.ControllerTest; +import io.openems.edge.ess.test.DummyManagedSymmetricEss; +import io.openems.edge.timedata.test.DummyTimedata; +import io.openems.edge.io.test.DummyInputOutput; + +public class ControllerEssLimiter14aTest { + + private static final String ESS_ID = "ess0"; + private static final String CTRL_ID = "ctrlEssLimiter14a0"; + + private static final ChannelAddress RESTRICTION_MODE = new ChannelAddress(CTRL_ID, "RestrictionMode"); + private static final ChannelAddress GPIO = new ChannelAddress("io0", "InputOutput0"); + private static final ChannelAddress LIMITATION = new ChannelAddress(ESS_ID, "SetActivePowerGreaterOrEquals"); + private static final ChannelAddress GRID_MODE = new ChannelAddress("_sum", "GridMode"); + + @Test + public void testController() throws OpenemsException, Exception { + new ControllerTest(new ControllerEssLimiter14aImpl()) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("componentManager", new DummyComponentManager()) // + .addReference("timedata", new DummyTimedata("timedata0")) // + .addReference("ess", new DummyManagedSymmetricEss(ESS_ID)) // + .addReference("sum", new DummySum()) // + .addComponent(new DummyInputOutput("io0")) // + .activate(MyConfig.create() // + .setId(CTRL_ID) // + .setEssId(ESS_ID)// + .setInputChannelAddress("io0/InputOutput0")// + .build()) + .next(new TestCase() // + // Since logic is reversed + .input(GPIO, false) // + .input(GRID_MODE, GridMode.ON_GRID) + .output(LIMITATION, -4200) + .output(RESTRICTION_MODE, RestrictionMode.ON)) // + .next(new TestCase() // + .input(GPIO, null) // + .output(LIMITATION, null)) // + .next(new TestCase() // + .input(GPIO, 1) // + .input(GRID_MODE, GridMode.OFF_GRID) // + .output(RESTRICTION_MODE, RestrictionMode.OFF)) // + .next(new TestCase() // + .input(GPIO, false) // + .input(GRID_MODE, GridMode.OFF_GRID) // + .output(LIMITATION, null)) // + ; + } + +} diff --git a/io.openems.edge.controller.ess.limiter14a/test/io/openems/edge/controller/ess/limiter14a/MyConfig.java b/io.openems.edge.controller.ess.limiter14a/test/io/openems/edge/controller/ess/limiter14a/MyConfig.java new file mode 100644 index 00000000000..c0c2a3ddab8 --- /dev/null +++ b/io.openems.edge.controller.ess.limiter14a/test/io/openems/edge/controller/ess/limiter14a/MyConfig.java @@ -0,0 +1,61 @@ +package io.openems.edge.controller.ess.limiter14a; + +import io.openems.common.test.AbstractComponentConfig; + +@SuppressWarnings("all") +public class MyConfig extends AbstractComponentConfig implements Config { + + protected static class Builder { + private String id; + private String inputChannelAddress; + private String essId; + + private Builder() { + } + + public Builder setInputChannelAddress(String inputChannelAddress) { + this.inputChannelAddress = inputChannelAddress; + return this; + } + + public Builder setId(String id) { + this.id = id; + return this; + } + + public Builder setEssId(String id) { + this.essId = id; + return this; + } + + public MyConfig build() { + return new MyConfig(this); + } + } + + /** + * Create a Config builder. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new Builder(); + } + + private final Builder builder; + + private MyConfig(Builder builder) { + super(Config.class, builder.id); + this.builder = builder; + } + + @Override + public String inputChannelAddress() { + return this.builder.inputChannelAddress; + } + + @Override + public String ess_id() { + return this.builder.essId; + } +} \ No newline at end of file diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties index fb814f5c16c..78905f75ed7 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties @@ -11,6 +11,8 @@ meter = Erzeugungs- und Verbrauchszähler peakShaving = Lastspitzenkappung und atypische Netznutzung api = Schnittstellen ess = Speichersystemsteuerung +timedata = Timedata +test = Test # Global alias = Alias @@ -95,7 +97,7 @@ App.Api.RestJson.ReadWrite.Name = REST/JSON Schreibzugriff App.Api.RestJson.ReadWrite.Name.short = REST/JSON Schreibzugriff App.Timedata.InfluxDb.Name = Influx Db Timedata -App.Timedata.InfluxDb.Name.short = Timedata +App.Timedata.InfluxDb.Name.short = Influx Db App.Timedata.InfluxDb.queryLanguage.label = Abfragesprache App.Timedata.InfluxDb.url.label = URL App.Timedata.InfluxDb.url.description = Die InfluxDB-URL, z. B.: http://localhost:8086 diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties index bbec3469d64..3e1bbf49ec2 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties @@ -11,6 +11,8 @@ meter = Production and consumption meter peakShaving = Peak shaving and atypical grid usage api = Interfaces ess = Energy Storage controller +timedata = Timedata +test = Test # Global alias = Alias @@ -95,7 +97,7 @@ App.Api.RestJson.ReadWrite.Name = REST/JSON write access App.Api.RestJson.ReadWrite.Name.short = REST/JSON write access App.Timedata.InfluxDb.Name = Influx Db Timedata -App.Timedata.InfluxDb.Name.short = Timedata +App.Timedata.InfluxDb.Name.short = Influx Db App.Timedata.InfluxDb.queryLanguage.label = Query language App.Timedata.InfluxDb.url.label = URL App.Timedata.InfluxDb.url.description = The InfluxDB URL, e.g.: http://localhost:8086 diff --git a/io.openems.edge.core/src/io/openems/edge/core/predictormanager/PredictorManagerImpl.java b/io.openems.edge.core/src/io/openems/edge/core/predictormanager/PredictorManagerImpl.java index 5e820a73686..934c788a24f 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/predictormanager/PredictorManagerImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/predictormanager/PredictorManagerImpl.java @@ -129,7 +129,7 @@ private Prediction getPredictionSum(Sum.ChannelId channelId) { GRID_ACTIVE_POWER, GRID_ACTIVE_POWER_L1, GRID_ACTIVE_POWER_L2, GRID_ACTIVE_POWER_L3, GRID_BUY_PRICE, GRID_BUY_ACTIVE_ENERGY, GRID_MAX_ACTIVE_POWER, GRID_MIN_ACTIVE_POWER, GRID_MODE, - GRID_SELL_ACTIVE_ENERGY, // + GRID_MODE_OFF_GRID_TIME, GRID_SELL_ACTIVE_ENERGY, // PRODUCTION_ACTIVE_ENERGY, PRODUCTION_AC_ACTIVE_ENERGY, PRODUCTION_AC_ACTIVE_POWER_L1, PRODUCTION_AC_ACTIVE_POWER_L2, PRODUCTION_AC_ACTIVE_POWER_L3, PRODUCTION_DC_ACTIVE_ENERGY, diff --git a/io.openems.edge.core/src/io/openems/edge/core/sum/SumImpl.java b/io.openems.edge.core/src/io/openems/edge/core/sum/SumImpl.java index c7aca7017cc..6bf8c875d46 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/sum/SumImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/sum/SumImpl.java @@ -29,6 +29,7 @@ import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.modbusslave.ModbusSlave; import io.openems.edge.common.modbusslave.ModbusSlaveTable; +import io.openems.edge.common.sum.GridMode; import io.openems.edge.common.sum.Sum; import io.openems.edge.common.type.TypeUtils; import io.openems.edge.ess.api.AsymmetricEss; @@ -43,6 +44,8 @@ import io.openems.edge.meter.api.ElectricityMeter; import io.openems.edge.meter.api.VirtualMeter; import io.openems.edge.timedata.api.Timedata; +import io.openems.edge.timedata.api.TimedataProvider; +import io.openems.edge.timedata.api.utils.CalculateActiveTime; import io.openems.edge.timeofusetariff.api.TimeOfUseTariff; @Designate(ocd = Config.class, factory = false) @@ -52,7 +55,7 @@ property = { // "enabled=true" // }) -public class SumImpl extends AbstractOpenemsComponent implements Sum, OpenemsComponent, ModbusSlave { +public class SumImpl extends AbstractOpenemsComponent implements Sum, OpenemsComponent, ModbusSlave, TimedataProvider { @Reference private ConfigurationAdmin cm; @@ -66,6 +69,9 @@ public class SumImpl extends AbstractOpenemsComponent implements Sum, OpenemsCom private final EnergyValuesHandler energyValuesHandler; private final Set ignoreStateComponents = new HashSet<>(); + private final CalculateActiveTime calculateOffGridTime = new CalculateActiveTime(this, + Sum.ChannelId.GRID_MODE_OFF_GRID_TIME); + private final ExtremeEverValues extremeEverValues = ExtremeEverValues.create(SINGLETON_SERVICE_PID) // .add(Sum.ChannelId.GRID_MIN_ACTIVE_POWER, "gridMinActivePower", // NEGATIVE, Sum.ChannelId.GRID_ACTIVE_POWER) // @@ -145,6 +151,11 @@ public void updateChannelsBeforeProcessImage() { this.calculateState(); } + @Override + public Timedata getTimedata() { + return this.timedata; + } + /** * Calculates the sum-value for each Channel. */ @@ -333,7 +344,9 @@ private void calculateChannelValues() { var essMaxApparentPowerSum = essMaxApparentPower.calculate(); this._setEssMaxApparentPower(essMaxApparentPowerSum); - this._setGridMode(essGridMode.calculate()); + var gridMode = essGridMode.calculate(); + this._setGridMode(gridMode); + this.calculateOffGridTime.update(gridMode == GridMode.OFF_GRID); var essActiveChargeEnergySum = essActiveChargeEnergy.calculate(); essActiveChargeEnergySum = this.energyValuesHandler.setValue(Sum.ChannelId.ESS_ACTIVE_CHARGE_ENERGY, diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/OpenemsAppCategoryTest.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/OpenemsAppCategoryTest.java new file mode 100644 index 00000000000..ac2472e6254 --- /dev/null +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/OpenemsAppCategoryTest.java @@ -0,0 +1,33 @@ +package io.openems.edge.core.appmanager; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import io.openems.common.session.Language; + +public class OpenemsAppCategoryTest { + + @Test + public void testEnglishTranslations() { + this.testTranslations(Language.EN); + } + + @Test + public void testGermanTranslations() { + this.testTranslations(Language.DE); + } + + private void testTranslations(Language l) { + final var debugTranslator = TranslationUtil.enableDebugMode(); + + for (var entry : OpenemsAppCategory.values()) { + entry.getReadableName(l); + } + + assertTrue( + "Missing Translation Keys for Language " + l + " [" + + String.join(", ", debugTranslator.getMissingKeys()) + "]", + debugTranslator.getMissingKeys().isEmpty()); + } +} diff --git "a/io.openems.edge.ess.mr.gridcon/doc/Entscheidungstabelle_Zust\303\244nde_OnOffGrid_konsolidiert.xlsx" "b/io.openems.edge.ess.mr.gridcon/doc/Entscheidungstabelle_Zust\303\244nde_OnOffGrid_konsolidiert.xlsx" deleted file mode 100644 index 1698a8f42a4f7b1427be631c888ed6ec6434a6f2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14698 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 Valid (DC contactor ON) |Target Voltage - System Voltage|> Setting Voltage -> Invalid (DC contactor OFF) -ESS;Samsung Mega 3.3;Rack Group;Modbus;30012;13;0x05;0;3;0x05030D;ERROR_CODES::ESS::SAMSUNG::MEGA_33::SYSTEM;NO_CONTACTOR_ON_COMMAND;Close contactor command timeout;Blackfin;Extern;;;;;;;WARNING;SINGLE;"|Target Voltage - System Voltage|<= Setting Voltage -> Valid (DC contactor ON) Not receive ""Command On"" within a Setting Time -> Invalid (DC contactor OFF)" -ESS;Samsung Mega 3.3;Rack;Blackfin;CSamsungMega33Rack;0;0x04;0;2;0x040200;ERROR_CODES::ESS::GROUP::RACK;CLOSE_BLOCKED;Contactor closing blocked;Blackfin;HIGH;3;0;;;;;WARNING;SINGLE;Max Cell T >= 65*C, 5sec -ESS;Samsung Mega 3.3;Rack;Blackfin;CSamsungMega33Rack;1;0x04;0;2;0x040201;ERROR_CODES::ESS::GROUP::RACK;OPEN_BLOCKED;Contactor opening blocked;Blackfin;HIGH;0.1;0;;;;;WARNING;SINGLE;Max Cell T >= 65*C, 5sec -ESS;Samsung Mega 3.3;Rack;Modbus;30061+(#r-1)*26;1;0x04;0;3;0x040301;ERROR_CODES::ESS::SAMSUNG::MEGA_33::RACK::TRIP;CELL_OVERTEMPERATURE;Cell Overtemperature Trip;Blackfin;Extern;;;;;;;SHUTDOWN;SINGLE;Max Cell T >= 65*C, 5sec -ESS;Samsung Mega 3.3;Rack;Modbus;30061+(#r-1)*26;2;0x04;0;3;0x040302;ERROR_CODES::ESS::SAMSUNG::MEGA_33::RACK::TRIP;CELL_UNDERVOLTAGE;Cell Undervoltage Trip;Blackfin;Extern;;;;;;;SHUTDOWN;SINGLE;Min Cell V <= 2.50V, 3sec -ESS;Samsung Mega 3.3;Rack;Modbus;30061+(#r-1)*26;3;0x04;0;3;0x040303;ERROR_CODES::ESS::SAMSUNG::MEGA_33::RACK::TRIP;CELL_OVERVOLTAGE;Cell Overvoltage Trip;Blackfin;Extern;;;;;;;SHUTDOWN;SINGLE;Max Cell V >= 4.20V, 5sec -ESS;Samsung Mega 3.3;Rack;Modbus;30061+(#r-1)*26;7;0x04;0;3;0x040307;ERROR_CODES::ESS::SAMSUNG::MEGA_33::RACK::TRIP;RACK_UNDERVOLTAGE;Rack Undervoltage Trip;Blackfin;Extern;;;;;;;SHUTDOWN;SINGLE;Rack V <= *Reference level, 3sec -ESS;Samsung Mega 3.3;Rack;Modbus;30061+(#r-1)*26;8;0x04;0;3;0x040308;ERROR_CODES::ESS::SAMSUNG::MEGA_33::RACK::TRIP;RACK_OVERVOLTAGE;Rack Overvoltage Trip;Blackfin;Extern;;;;;;;SHUTDOWN;SINGLE;Rack V >= *Reference level, 5sec -ESS;Samsung Mega 3.3;Rack;Modbus;30061+(#r-1)*26;9;0x04;0;3;0x040309;ERROR_CODES::ESS::SAMSUNG::MEGA_33::RACK::TRIP;RACK_COMM_FAULT;Rack Communication Fault;Blackfin;Extern;;;;;;;SHUTDOWN;SINGLE;No response from Rack, 30sec -ESS;Samsung Mega 3.3;Rack;Modbus;30061+(#r-1)*26;10;0x04;0;3;0x04030A;ERROR_CODES::ESS::SAMSUNG::MEGA_33::RACK::TRIP;TRAY_COMM_FAULT;Tray Communication Fault;Blackfin;Extern;;;;;;;SHUTDOWN;SINGLE;No response from Tray, 30sec -ESS;Samsung Mega 3.3;Rack;Modbus;30061+(#r-1)*26;11;0x04;0;3;0x04030B;ERROR_CODES::ESS::SAMSUNG::MEGA_33::RACK::TRIP;OVERCURRENT;Overcurrent Trip;Blackfin;Extern;;;;;;;SHUTDOWN;SINGLE;Charge : Current >= 205A, 1sec // Discharge : Current >= 335A, 1sec -ESS;Samsung Mega 3.3;Rack;Modbus;30061+(#r-1)*26;13;0x04;0;3;0x04030D;ERROR_CODES::ESS::SAMSUNG::MEGA_33::RACK::TRIP;ADDITIONAL_PROTECTION;Additional Protection Tray;Blackfin;Extern;;;;;;;SHUTDOWN;SINGLE;Rack OVP or OCP fault by 2nd MCU -ESS;Samsung Mega 3.3;Rack;Modbus;30061+(#r-1)*26;14;0x04;0;3;0x04030E;ERROR_CODES::ESS::SAMSUNG::MEGA_33::RACK::TRIP;DC_CONTACTOR_FAULT;DC Contactor Fault;Blackfin;Extern;;;;;;;SHUTDOWN;SINGLE;Current >= 300mA even if the contactor is opened, 3sec -ESS;Samsung Mega 3.3;Rack;Modbus;30061+(#r-1)*26;15;0x04;0;3;0x04030F;ERROR_CODES::ESS::SAMSUNG::MEGA_33::RACK::TRIP;DC_CONTACTOR_SENSOR_FAULT;DC Contactor Sensor Fault;Blackfin;Extern;;;;;;;SHUTDOWN;SINGLE;Feedback Status of contactor ≠ Contactor command, 3sec -ESS;Samsung Mega 3.3;Rack;Modbus;30062+(#r-1)*26;0;0x04;0;3;0x040310;ERROR_CODES::ESS::SAMSUNG::MEGA_33::RACK::WARNING;CELL_UNDERTEMPERATURE;Warning: Cell Undertemperature;Blackfin;Extern;;;;;x;;WARNING;SINGLE;Min Cell T <= -21*C, 3sec -ESS;Samsung Mega 3.3;Rack;Modbus;30062+(#r-1)*26;1;0x04;0;3;0x040311;ERROR_CODES::ESS::SAMSUNG::MEGA_33::RACK::WARNING;CELL_OVERTEMPERATURE;Warning: Cell Overtemperature;Blackfin;Extern;;;;;;;WARNING;SINGLE;Max Cell T >= 60*C, 3sec -ESS;Samsung Mega 3.3;Rack;Modbus;30062+(#r-1)*26;2;0x04;0;3;0x040312;ERROR_CODES::ESS::SAMSUNG::MEGA_33::RACK::WARNING;CELL_UNDERVOLTAGE;Warning: Cell Undervoltage;Blackfin;Extern;;;;;;;WARNING;SINGLE;Min Cell V <= 2.70V, 1sec -ESS;Samsung Mega 3.3;Rack;Modbus;30062+(#r-1)*26;3;0x04;0;3;0x040313;ERROR_CODES::ESS::SAMSUNG::MEGA_33::RACK::WARNING;CELL_OVERVOLTAGE;Warning: Cell Overvoltage;Blackfin;Extern;;;;;;;WARNING;SINGLE;Max Cell V >= 4.18V, 3sec -ESS;Samsung Mega 3.3;Rack;Modbus;30062+(#r-1)*26;4;0x04;0;3;0x040314;ERROR_CODES::ESS::SAMSUNG::MEGA_33::RACK::WARNING;RACK_VOLTAGE_ERROR;Warning: Rack voltage deviates from sum;Blackfin;Extern;;;;;;;WARNING;SINGLE;(Rack Voltage - Sum of cell voltage) >= 77V, 3 sec -ESS;Samsung Mega 3.3;Rack;Modbus;30062+(#r-1)*26;5;0x04;0;3;0x040315;ERROR_CODES::ESS::SAMSUNG::MEGA_33::RACK::WARNING;CELL_VOLTAGE_IMBALANCE;Warning: Cell Voltage Imbalance;Blackfin;Extern;;;;;x;;WARNING;SINGLE;Max Cell >= 3.5V & d cell V >= 300mV, 5sec -ESS;Samsung Mega 3.3;Rack;Modbus;30062+(#r-1)*26;6;0x04;0;3;0x040316;ERROR_CODES::ESS::SAMSUNG::MEGA_33::RACK::WARNING;CELL_TEMPERATURE_IMBALANCE;Warning: Cell Temperature Imbalance;Blackfin;Extern;;;;;;;WARNING;SINGLE;dCell T >= 20*C, 30sec -ESS;Samsung Mega 3.3;Rack;Modbus;30062+(#r-1)*26;7;0x04;0;3;0x040317;ERROR_CODES::ESS::SAMSUNG::MEGA_33::RACK::WARNING;RACK_UNDERVOLTAGE;Warning: Rack Undervoltage;Blackfin;Extern;;;;;;;WARNING;SINGLE;Rack V <= *Reference level, 1sec -ESS;Samsung Mega 3.3;Rack;Modbus;30062+(#r-1)*26;8;0x04;0;3;0x040318;ERROR_CODES::ESS::SAMSUNG::MEGA_33::RACK::WARNING;RACK_OVERVOLTAGE;Warning: Rack Overvoltage;Blackfin;Extern;;;;;;;WARNING;SINGLE;Rack V >= *Reference level, 3sec -ESS;Samsung Mega 3.3;Rack;Modbus;30062+(#r-1)*26;9;0x04;0;3;0x040319;ERROR_CODES::ESS::SAMSUNG::MEGA_33::RACK::WARNING;RACK_COMM_FAULT;Warning: Rack Communication Fault;Blackfin;Extern;;;;;;;WARNING;SINGLE;No response from Rack, 10sec -ESS;Samsung Mega 3.3;Rack;Modbus;30062+(#r-1)*26;10;0x04;0;3;0x04031A;ERROR_CODES::ESS::SAMSUNG::MEGA_33::RACK::WARNING;TRAY_COMM_FAULT;Warning: Tray Communication Fault;Blackfin;Extern;;;;;;;WARNING;SINGLE;No response from Tray, 10sec -ESS;Samsung Mega 3.3;Rack;Modbus;30062+(#r-1)*26;11;0x04;0;3;0x04031B;ERROR_CODES::ESS::SAMSUNG::MEGA_33::RACK::WARNING;OVERCURRENT;Warning: Rack Overcurrent;Blackfin;Extern;;;;;;;WARNING;SINGLE;Charge : Current >= 200A, 3sec // Discharge : Current >= 315A, 3sec -ESS;Samsung Mega 3.3;Rack;Modbus;30062+(#r-1)*26;12;0x04;0;3;0x04031C;ERROR_CODES::ESS::SAMSUNG::MEGA_33::RACK::WARNING;SOC_FULL;Rack Charge Completed;Blackfin;Extern;;;;;;;INFO;SINGLE;Just before SOC 100% -ESS;Samsung Mega 3.3;Rack;Modbus;30062+(#r-1)*26;13;0x04;0;3;0x04031D;ERROR_CODES::ESS::SAMSUNG::MEGA_33::RACK::WARNING;SENSOR_COMMUNICATION_FAULT;Warning: Current Sensor Communication Fault;Blackfin;Extern;;;;;;;WARNING;SINGLE;Sensor Communication Pending, 3sec -ESS;Samsung Mega 3.3;Rack;Modbus;30062+(#r-1)*26;14;0x04;0;3;0x04031E;ERROR_CODES::ESS::SAMSUNG::MEGA_33::RACK::WARNING;CHARGE_OVERCURRENT;Warning: Charge Current Limit Exceeded;Blackfin;Extern;;;;;;;WARNING;SINGLE;Exceed Permissive Current Value, 5sec -ESS;Samsung Mega 3.3;Rack;Modbus;30062+(#r-1)*26;15;0x04;0;3;0x04031F;ERROR_CODES::ESS::SAMSUNG::MEGA_33::RACK::WARNING;FAN_FAULT;Warning: Fan Fault;Blackfin;Extern;;;;;;;WARNING;SINGLE;One more fan not operated under active circumstance, 5sec diff --git a/io.openems.edge.ess.mr.gridcon/doc/Fehlerliste.xlsx b/io.openems.edge.ess.mr.gridcon/doc/Fehlerliste.xlsx deleted file mode 100644 index d4e9c3d72c0734626c97d48621bcd753862b9267..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 64298 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 diff --git a/io.openems.edge.ess.mr.gridcon/doc/PQ-01-12-05-BA_Software-Manual-Anybus-GRIDCON-ACF_PCS_DE.pdf b/io.openems.edge.ess.mr.gridcon/doc/PQ-01-12-05-BA_Software-Manual-Anybus-GRIDCON-ACF_PCS_DE.pdf deleted file mode 100644 index e779bfc0c5ba9c0b7cac9a540b88bc056215fc08..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1343847 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%0A{eMM%ah4Za%VTB`|0C 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

      ^N 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 z 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 @cYUkjTY%<_d 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

    15. ?s_cARfY*qoqlSa_Pe=3ivBHu849W1t*nkI$ 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≺M)B893E9S3g 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

      SEDh#bmagy{A66#4$k~WyqCA}H7Yo- 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

      mg~p%eqqBz6Go5>K!pXHi{m2z| zu^81AH-PB{opH&R1-^BePJ9Bxta*U))4{se*5DLBiHYhQGlA$;6j1f6qE3T`A1!mX ziFL`c1+FG9CE>`%S3Bb6Lw^M;SzWg3kPA(70D2K)Tx@=I)E>-VKSq82dLlam@$;7l zc^|C0?mgCqX9|O5@z{{{60%OwwSh-FNGhN2dGBf2#BXr475V&v`Flu-N3;Wo+cD6A zxZ@vH;wF$ii!xBJYn)5Q=Krz_n}c|ymB`Joy|0`85T*jlC^hLLQnCZiR^8zc?1x0F18 zvKmvcY<{EA3W>kUrkx?Rz#FHe4A%#Panz`gQUo#ho3WwlvZZFfkGMSw+uUTJU_Mcv|w6Y7IcBImGPT29XiQr=m1fF*ejXGY1_%>{$@EP5uSr1tQ%?joBHmakKzYksGm&8vTaJ_)s@;DQkpcWv5C_U!p zVZ*}aRVp#lM0sGmv99~Ur0nuJ9sa%2&xA>j(ba$QvT_wF4Tfmz+B&9yMk zPkmBUN5&hZ;dSq%nPLOs2C3R7eq@)ozuor`2ryQW9v(?knQQ*3$#O~SYI8`oR#+k| zH=Z)iZa^bzm=hd2^7SR_q0sK%-K*_S7T*+_S>cA-lIribN%ZxQ)6G;mA$ zd(*@uiRTuvBS9w8ez(OY=6$O}i&P7m?+2dl$_E%J6vXCU{R;$-4X4re^!y~bE zM#@^BvrmyjC2@?nw6Nww@w&}x=E&?yh)-bKdI*1!rlN(r>% zdR|r^Hlw$x2I~ag+jCxVw|C2tDf2@~H-5IOip$og7DN_*#!cO9SJm_GXh-B#c=sN` zUdd~s)ohqw4ozNSxaW75|k&Eft2(YMC7xHc^`NakC2k6+yUK1lRA`>m4_PRRSs z1oy3%vm)%W@<=}}Q+4=6c+}W0)#3#m_obIVSE++ldpGe3tz4=KNw=YAShCdRENJ+W?0}IB8&~s43bs)08B6k5oFB|D(Y@{91I#WSfGdpAVv$q!by3%vxg|E7rctNny?8--?ySPxXbuRblPAO(qRRKJ8 zW&+=sfUgUN$3U|3ishLx*_AF;x3fz)H@u(-=benb>pc)_3PVjuza$<}TB(Se z>SU+4j_|5ZzA$LyWp-h?GcerMkQt7(YP?JIOR4mpf_mn?bw*VCh33o=zcxw#6t_o~ zMX(t1c&&sWi7e!1tl~ouU`*NHgrKv(q`&E%eJ+Mq-Ch6Xb`d9!?u+J|{1iypjp0f5 zorEX_pMU_GE0dNu%E?P3W&Vztk~+#wtsvtG&a@g&_g$9 zgt&4HN5!iPJ;effMk~!TE4Z;nVLeCW*%Kgk9KEA)T;|DX)HY+Eu1YKFg8{S8=Euve z@l9j4F7!2(cE??dQYV!DsG*^Ls6BM7!^qZB{|eScvJM6g26F9ZS$BSR#510JWs zEX60u-T_-a6G)Pl&>%$DRga%xJf{kl{`^wt60z6tjb~pk4r8R@tg}=Dl&({pIbdvT|!BmwnKcZ597UmV;ai@+w?YVfn80 z(u}^o=0dXbjXuCT#O8otdAh3B#&+U29w^clf1!`7)&f*qRVui`g}I#RJ@#iX7AoyxqIe%x4eAj>)u(pW8Q+_ zRF!dPzU*b+lwo(=#`}%|wz<~|YRdDT6|^P

      ^&o$R$e+=@1LG1uUMXx9>MjhiQ# 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⪻L#JX#OFMj<3OUwhMLKNI!EVNm0(CCL*EZo1^4)-o+7K3hUzQ!R!w@wvS;QrcbYYY&!I^eS7~aO*7x} z)bQ_o_H$8MZ&NQ_jNv*bX8Sq5JImc;(uA~OcA7iHtc{JHBdA7>Da@_-3G4$4r%Qvo zb#ZN!_`J~N^Qu+54jmd(?V-D0d`zHax25<&OY0B){;#|}FY?@%8y%IDEFIRIF?d?! zZd+o?j(3pq)h^ez++XW;V^Y_oGWY-)=6esC>V=UoNn4@$v#Af3Ivk>`AiFxJeIh zdXQvxckGRV&=JGLsy#3GCVF70{N$TPAF~P<)Uc1W0tks=b$+}39jeiH6-{gdL$=3N z?yw?xjGEczo>5W_a8y{8_}}Qd zcZya-`eRCK446+xW7QhIR(uk1vQTKK&FU2lORV&L1h1T(4v(~ccRJ67FeLS)(TBje zbf6~9N+`+u4(GX@531SFR}C9#ha(KR!wf{t4of{W>bo9ONuR|eDJb>f&3^6N`7T7s zU~$pzO#%#6la&?L8*myLd`dT7f0lPi3|?w^!=T~J8v9oDOzhmw_>CqCVUG3bdIBZn z!AgxA&V$`Midt{hbxdO9{kGL%tWRbZIo$mX-HQy4Vkj$8CujijX z%F&90)qTa7)A`5VKkhvIY^Rxlbu%jL%6R{aU>kv}cfO_MSLW4BH0-&|VL0V@B$#7* zW~=DoiJfgrx1PQ0nC~4fxI+2Pq!7UWM6~{3ZpH?$(43XJxBo-YQ0a#?Mb|$oc$|;)nr3E#mG+qWB~)OMk6rhnVVeZV0Y=wphl{9hD}1vBNP~ zSM!M8pK^X^b#Jh0Q^lQ*lQHZkBr@^+jC~e(`M$6YR?!I zR1$J>qs@}S3Wb@!_;4!dyZ5GyvKfDK7ro8ouY1gJ?R%!1zm0{A!CJgqnDC29`--ma z7h4tc1)XB*=)`ZmDqnh>wrNy9S6yf}aN#?qz5BD?HkERxyfM?o0pCyD-u)M)^p>q~ z%;BLCWLZgp);b1n`p|1NR{OG+M&?h5wgt!!?|Z4YjS_n1xxdDeMMX{g=E-7zU-=gO zzJbYWXZ(FqnFKf9m@b<$V>oirC2yZdxR;pN$v1BUTZ(gtcq;h94y#oo zOt36o4P)oe5-SF_sNXbtlhqjZ<`JpuVb+~+{M2$OW5*T!V_(h|JgXvAzT}#`8h`Xb zfkN%!{(`*S-BYqGh8o6xyD!zu9`AR(W;6S35U#oJ-pkl}ZY>4HjM)ppBa(AVa?v$8 zK?gFU{gv8!bMx*WP{EO3ykB@*(ZRLL!cGlIxLklf2L!Xvb$5WLo_QoJ8UoP zKEw2u>QlE#$s4a#j-|es*1c9~bExfNd*WK->g(+lGfeQcgJ)|b>+wR031f90dx z4-Pg)U#ms)tRy=3c?8eJy67nf}&8Il^R z{kN1qf2MXubEzy9;#Pf!ibr{_*#~Z zPw3^fbDe$Jf3$8qMS*vwL4smxTJAI)6r$MmjpI&~NZO5!YD~pid6Ugt@=YWAziWM9 z=?I_n>ka>LK5?xaS1h@3OZ`%97c8^@1PF{dBEGg+=g#SJbvG}F!QVE9uJGD zLB)OS4keEF?E{n(o-vRYkJKLF^FZ9Iy{c=}%{BL-W(Q@D%R-X(1{s`gXa9kw=h^)3 z!JQvIAU0U!J6$I9HoeF_@hPLyPG$74ca5jdB0HRkBPG~5^*JBv6lzUR-0Dsq9S%iDeErEt2$&)l^@#HxzOJvl>6m^Ap+G`=a|8b zDO~M($CRVhX;ptPr`=$@x7sYUxh6)?l5gm;#d$x6yKkM{c)m3mZr-%uU8cBP5P}5|(Of0ye;5)c^Xc0Fuj++b>CWfDGFw|GLGrzC>4mqMLj`Bnw-eAP513( zq2^_Q>Mhm8cP>TA`w)>`O1om?BG0iF?YmtR^~io=kDX?crTN4~*Me@Z(|U(*S=18u zY`WC#eZ+9jzCsR<0-GaI{_f(}0Ik3D@^7dChJ z*7e~@-5v4Hn79-9PK3`Po)+OYYqMvo=jZo#qzyQ?m>+7n;$kq_arP8PeY4(9Vj^?j zy)##Zv{Nhc-@Apq!g&$-EQgKD#P3?_op*5Mt!h6P@#?MY%;&*9mCL3U6PgiK+@}o&R46i zpO-h5wzoH4T$M~o)(+DdE4~zdWV~)Rz2(Ba0|urWMKyCrmL*}!`L#Th;!iJ*njM@w z;p3LF`grHY@i>XAQB}LA4?mUI>$Peqr*Lp_;a0=K1>?ez(X*R_($sEUeNBF5@+jHt zCHMJNGvhrgJLY%sU(;<&m>hCouIHU|@^#Q2da3_lh=;H*lAX6QkgbdP+x1T@BZ8Rr zePP=@?qBV++nEz1?iX`0(7a^y?F-(Ov)`Sb8_YeA$^=8^6 zQua$ApGa$_W;%bGo{U@^QnLz442=BV=smF5>i#g{-RiNO*9)D4C)=Xz`oqp|t4j1* zwbEr#ZWpNk);z(vyh34L8c=t~qk5k3!{E<%2lS?nm-{%&%dm8P5Pr_8`ARJ*j+<9KOvjig zbR&6dzw~|U!nbhA_>-x_jH-gZFSlP&@V!fvc!5+qxA5)Y$f?(@O(*?=M6CIlcD9;7 zdeiuF`nr0u>G#CfPYa~oT1nr{1Z|@QjP;`4vZqA6-yFrTCuGm64Bdhb_uZSf_?M(# zBQjU>JnAcef9$$D;*pVz2Hx<*nnJd2I9qAQ^ zGOP~wMDHoRH(vlO7?u}WxW!dzgH#~f#>?F(dAXLymJxR8PBBS+D)ka-VzpX#uj}c# z*)mUrhF&YaZ$!R$KyM>+j6VypOll~JiT_6Tn9~rh(AIV1qvvWvA8;R3q$j&`1E0um zVYGcMkHwyNO0jLPV8`*A5w=I0bafQV?tb(2!NRbZ5N zcbt+>!ps31KA*(5JnW3}>HW1R{`VhJ>FMN;i3O+{jhfdZ3t1KL4X9j;a}T`uh?OO-qJm4Q$%w;VRk7-gfs3ov_48+l+q=v)Xyc5%z+iE5Gi=j4sjp0z zJ4Jcgwy$~IsPMUJ%n_Kh-RHx{v&2uuO;HW)BWL|R1~t-$E;+H+E9{KD?;>-!{q9bC z2iMEJ%WU@V>Lnj%qPX&Js_ht&J}JQW(BQ`DdcAg0ZqEMb#0NO5Yr#=FG&yPuuluFc zpOeycn%k3HtS2z9Ry$|eEVL}gYr5}h1$)*RHRTjt`la*7A9~x}xowhidjZYUlJe|* zl+~+eQu7+(t^=?R`Jnf>fsRy%GVd2CIEVb;+iqS~Hs>gwLo>psO47YrZ7r{k-oCF! z*ybWjKPjE``8k*QJGO1(4^3Gv9*m0|S*tfG;FuQm-6^CjN>P))m)@4%Ha+01HQ<=6iWp@a?0M8wCvb^vBlpr!S-iC7XFp@( zMPk&u>V#*E?af8sLmM!I8udIZJGxZN53xKbaA17QFTbIxTxI`s_A7;N{r237?8LBP z!ix>7gOy8dH51csOH988qfcEF@GzUoZnft2J0evpe4xub?Y#C0!40QEKfQ@*WjJt8 zc=np=2E@$%gw^)^7Hg)B9I|iuEvoGUrot?jLvzpHVZ0d|+|^%)%H7g%>}Y}XXUSXn zEE`ofcQ7uM2BCdn8&&$!?%s@@6;>|Ld|a1KSqp__zb?q&d6ywle*o?K&`90mREFz| zA{nRc`@dOeG&jHPv5@XPZ8p1gtJ3R@O%+VI~jqqdb zEZtApyV2w!)*ZVu243;s9I0$MGCyM@(l~S0Y>$eA)AX~KK2jN$Nt-+kBn0u15?k(E zGy|V06rfzucCSetKQwplR(DH+K3)#Ne`5C4u4>8zq4a(nlldWXqD)`G=Qs_z7}c%! zj^$!k{Ran(B)Jl=5Thaq~S$zBFW_>tkm2jzo=FLonosq?J&Rpjv^7HRDXt*n38s+)Vp@Y-ym=iX0 z!ld?Jk~yGi_nALt({}LtLJiNOvXgh8{kS$dOVqj+y7u<+HQxF@2-Vf`+iJD<=4Se1TkYm85fQa!1&8te*OJ_{Z$8J@ zY?&lSANAfkAcb+IMBi}9UFtm}*Y1r8LY;8k+1;LcCE1lZgQf1Vw4k__-WboxNV&8Q z7AXNM9-Tg1?^)zT6b1jTxBk=iN>-k3#c!$^F8hty)6&IVzr=lg?zrhhHEVW;!-+Ew z887j&`sv!;bU1V`s_hZ~boaxPV>8EtM|yUz`K<65Em;aWuXMHCFcov?%`iO}_hHS? zs);=90XMfeL2Nb6q7jwAPA(OLl z_3zrAypeSC4-K9ZwtKzG`ltr$FDcEu)XH`4T|;-ET4^BKwjl83r5Ju0OTMnX;bxO7 zHzKxk`M4W5eiZWfq{uP3U~i9mg?~DKcC0VP*P*;NKQpoT$#-9mVjZ6-^o~vUBj$`F z#_rWTp!jt@`jWm=U$%8AMyDixi^#mI{`O|4Gsz|Uzjt02;qls3B+co1NJ+%}__9sL z>YmchThG!@HnqL5nnw!mdL3}jO2XBgyaiw6 z62WcRDD3X>?W&FBxx$&}gu1yVuk&4!*OrUIMF1`{}*z8BucQ*_z-#YaLi!Y*X$ zh3Hlkm%jb1{N(&%?bkdc%=+6-^DHNbVFOniYc@pf(0eR>?WmSs*#47SliY5L+XT@CcQt4^%;g*@ImaU5<;ej@;)8APpwA0n95X{c=TxN zyilf9hH6fCpIo8K+b3`DB$C;x^lP_75NuiJZy;nM9~XLu>1og2$Q6y&8aqAYbgJLh z^^r>qzIf8e!|sKH>8Q^!#DvQM-G!4A{^wqdSot<6e&>98^jc6CW3;!#fc5T_eQ6Gu zpp>-on(OZ>W|!YQZ#RzbA(CI1yks0^K%KcoBCuvOh2<7nglT0pg*`TLc;j(YC;Vk^ z358P9C(!${$BNQR=__rBZz$=dto5zUUX0>m8D5J-k+hx_=c%dnIulpRJ3Bj@-hONv zd;4to;(|(AXpsS5%sV2^nZPzOTvkLfIBbH5iY@2Pz7bs4-q9rBm;mUF%P;j^`xJD9* zgA?H>I1+({OTxh$IPPy-0*AqUP?98SODIWjJ=jL#(OBprs8z59$4U}$1SuIJ2`vMi zDk&p_ht34O`JcT*fcsJJD1(rZLLm?`C^$k2oQIN>grngo1PV?<6TlFlrO{F{QnKJ3 z3J8joLP(*cNK!~CSrh^Zu0j5~1`7nEU4sJWK-UnZB*7vDu0cwJE2MBpATZbm9gzVo zf^mk<0PRXk5u}iy*S|)F)(;%$2NHA?G>w!3Z_$4vi7Xs}0F6lzkVL89`iF*td;ZUR z5vlzL@$pX`(C#D!-3g6GOM-DAB7g?L5CFXaQ4lE5FBA&A2Qs4&lGyd5vVVURXy(5o z3SsEC5tTv60_6T1970G0C}NiNMU7B1W5!I53VJkP*@V0Le~(;GhgZBuY|NMhZ!i#!C^2(nLH7g(83s5J-~J1QJ3@h5#5u3fvr+q%4|9!eWt< zcsvS#ONxNT5+#XvA_<3=l7_=c(vk!MmWapVkyu%{v|bmbj{o1v(bnx2+@EH*zxNgK z|MkAYNq^-RBnjecI2J$*P}fg>rj9%~7Y+Ua)_|jB!Rp_jo653ObOSx2&~O5YKmY_P zDI<-*5oJhdBpP54MFJX^lmS+QCCNx4Wl3lhT9O1Xhet@u;&Esq8i|)eOXFpv@d&iE zELsu`won8tfrv-p30NEv2~a6RLV^EiDL7G57K_Fr0i{XygrE1Rf6u z-`0sl;Bj~oI17cB1w4p@BhV-$0Zk&vN+Yl&A_{?)mBJ&Wa40E)BoZq{!lPvg05p=o z&tj!fSO8%e98y{uNr31aypxe7$zVZ$kkWw8AkzR4l9G`DOb0dyI5b`s*aRLSgOfoJ ziA1a{QHn%FgSWtS%ffMz!2hG+GB`l~D9DKb!vz*2BP%V9!(mClz5Ms@za#M95%}*2 z{C5QYI|Bb5fj=4nB?%1&XHTNLgbKk8M?7p`pnKH8lPIAlq9zBTI1uTF!arg4@Bog%82t+|ocQ2yS zkFJ5H)UcjJ5gjjAK?Fh&35UxFB9U^EC^XH3NZyA}{~ zXf$ZS%~f3kRDO=Roxr-gQtu5q_@fEXh!K%QbSJvvi59emu!2Z5^f;xFgqnjL(Zlno z8y@TF;O1%}g#>Z0APW80y3+btdPGlqH-dzon&kS9<5*`eq5>8#34&`G8Ib;hAcusI z!4p6$XdGS|WTr%dj1m|atg8pf&D~|a1vNLko|?h0-3C~9tcwTent>of!sP5J;=dk} zI4*%Wj0A#E4;nkz0fCg1tR#%RaO=tk$pZ24DJQ&#^kD+g6N|Se5`Lbnq{L2i1>kUG zM@q{6R#|iK^e`a0tGcnp6@g@+?s!7I*LK0$5dlsJ;0Smi_1E*LYaMG7Fb*nE zVFVcXqg(5Oslqr|H?eQp$idFWzL}F_3(vmoJX~BnhXnWR+=o6aErmJ^u%cqDA*Xmu z35nFgX&*a&(#qOOMxEqBGz-UGf zeiUdgjD8Cp!xp-=3YY-sBNH9<59%-UM@P@V$i&RDVI%7%a6W13e=H6B8pN zIO+$E!x*HSYiMd|>lmAu9zSu?%p4DLLOXj0M-NXgZ=W+~eS@#JYzVYHn$5Yw!5bIq-3C=+p4X=h3n0 zZ!@!V-{%(=mms<5U<@>|!0X@2wFSsU&&bHY$O6elNACj(zJ-x#4}y8CiXjX3^tQdo z3mdqOL_EkX-zbDKn&QT}H?s2VLk|c~L!wb7`_BXm{6~`g6zrE=oiH{AI-op;Eieph zHbx{dfc5`(OL78J;+=1M*`8;FdxYS?lj|4FK9UrJ0`2J?|F4Y2qg|!j?b~ikFmy*p zaO}cG(#SIjtXK87Vw_sg!<{aX%;>HJ$ERkyUwdU z5%6v^p0gEU$WMGGt0eSF>C**_8F{I7(|Ik**O2hc;Q&R}keSO15zp}mIztL zKX=-&QYX(kl4@ve-nUtjw0uKNDdMJ{lGHTAYEAeGGus+W=Mbt@Bu8uwcJX1QkzYsZ zig@W#3%^_CH_z)slg)84yNx}m>&^MH@^SO?MG=!kHn-(^7LPN!Io+czGJ!Q z<-I(ABYa_-z^MN2O(hurr9HEZ?^#l$a#J7nwuo!4=G#oCSyad!@oEuV*(EvhuK#R! zUyJgRdi=PN#D&`n`P(sCrAxDPU4E<6k!%PWcQed7EgIU~i+9@b7H+z~2T!Ni`SXCl;bAmvAz5&y8 z=e+*MtNx=!03GFPu(s?z`ViPaY5of{3H?IK26e&M%J4N9rZg1yJVu1!qLco%TK7Kt zk>zIc+?Z6O*F5jdur-)JmLmCCC?q3X-|>9E=x7rKxwxo7lGoZvX@(inV%|LIC*Vo;^D`t+#?o#3>CA)TD; zb;aFX0yn1K`ldfLib`KmYtCYgQG1vBvVAs7vCSbXM~W@oy(?h0&eL~y*6Kt1tV7~% zr^E7GR;tq;g=JJK0%Xo63adE_Q$R!YlTuCkv@pbruG#|vAQky9YW z^hK|RTtW9u3U_5VLnqIn`P+;)Zw4@VzSTa9)LwkvayL~d#)fh9^`yQhxnG&AbL;%B z6plpir8ia__H{69&c!^hHCQx<|C5~&=MhOcD@Ex`xtO;684Y^|$@7@x9Ni6M?mC@f zr8_Ut%QnliVqdxFtUQ;6mkYedXRnf9CG$*4^jt>F8XA#8VD{?#+?wx=(^2X$ajqy* z08d!6hjt9i+djFD3ubpiE?#Gs81n7AIU~``(`X5i5QR?~go&gBGHJ>82f(*^eODX0 z>`YO3&-8%nVe&CD8(Gd?oA(3HfkR3AJgY|x^@S^DH1=O(jMeDo<6MJTDefmcABPytz7IJU&H*wOjE8v+=On=1X)Q*YCG{ zP;b%LY}dgRnY0`lV{5UjP-1ucO2wV}xOCPo49aM^<6WhnM zy|(yd@6oT;aHYJOF#Tt5;MYvuPq!>{zD{wzrmJAaqgK;{F&}Tn9Wvo;DZNd2wVTmDlyGpkjL@|InUl5 z=tH-Qb$E7{_32zDzjT|!)SAqY)7?^3Fug%zG%akf@dmyqdFJN@Xr^zx}3h7t7F~{q4V*pV_pc3I^NW#;Q;;^(L4i&v^rrf zSW$9f2uvh7F@Pt;Re4NvL?wddgyF(_hIG-(!%X97{Mf5Rr)A0I_EVh8_9FC^+(*Yc zedk^VQI@%PImO`SUWQJ|Ca`lKy3WtBSf7#UkxUte1U3ixn=SW?vOO1yyB1trIr~K)RtBurDS0fsXVJ{V3%nk^FRH}` zR~G6mO8R)Up}Q#sa~w0E2i#-0p<7Y1^vCKI5r&5_x&XLHHh$U7+^s0(!d#v7vVMj5 zyt9yi0l6wbF09eAwDZN$Rq;fdg$--4ov4q&Uw5v-%8p-%Q{=Aoi?8Ht8`wT&GnKR~ zUlBf^6R;#e$%lEioItFG=3shT?)dF!T!U>GezXQ7o7|)Drx6>kNpF_7gdLIpAsyIL0mK^^`Abf`F^#e2U7ng)O zm1`|=IPuw{Dc zo)$xO7}p;z?jA?qZ$1BH;K><|1y_9IX<(x#(&+ zH(M9IvTwJ!N+0DUm+9BDTfef>bAij&;2>Z1_xsPPhnh?{&oYTVpWfuxqr^QgVFl-U zmS88?Hx(@(m)a>gTb9mLc(rTNN=+$%e96nxfaTz7+((|}&cN`5HQ2b}YG_trZ>yyr zyO)Upi#Sl)_tZY}@%Sk`1x;oe6!z6bOkzR+&04s-9Dx@tGscZ|IA)Rb4za{D%c zs$yRehS=R4xf9>wfqH}v?{FHhf_q(w2k`~FLlDKPd?}_QF#y^AddYDO z_AbMJZ?e_4W7g3T5>Fvks5 z$?c_>0vl}*#}s44tTI1~+9xn}DvFfNrX&Vz6LSDW*?0R>;qcnPVSqYJkazsc0y%g4TjL-2n>-oRIW&jjttm(?>gQ&{B5i{%;vhv z-XZ_J@g^<}lhHZGoBxn%=o-}L>+}pYDUVz7)@e!{>Wu-NI@hm7TbJ5J(COcZEXt^f zdInVzCgER_P)`fc5p@uuv!EyrEgkpptHB5iA5k+Nb{13&0Ws$Rck9Mn;F&3UmGHJq%!uhA<1nXU5RrdbMAtF5t`S4+qtxIN-1!C*mthPH2x$AW=Ri0?=N$ljT+TB!ydC zU7&A8%n_yonR8-v$oduhoQD5L81{yg?CLQg?f>v&3H>dm4d){1K;Q=tE%Kg){!hs^s^ z;R`Gvi+t!pqFaL<8p2#s>s(==oU9>>9pbBTi^vpMblMDZAoASj<--}|Ps1QxhH7DQPR7&HRkU33k+<9@WTx<5O? zBf4u-&D+7o2nH9(5+t*V*pG z$n;pOF8s>z)uYi340b`~HLFf_&il`ud06bc-K%qx@6GDD6}pu76Z=AqPlVmuN;jXt zX?pRg_P%TthYd1@0dT}|CgUf<4~+c8`aw-9Iz(BN#)|iP1eXLx%n#5UnI|C3IG7vo z#4IYaR3=KmK^}~;pl>|5>7OI&b@(J_3UI^o!A&WD&AkDU!*l@Y?d%bI8NA|exvKe% z8(VC8j&ot9XeoS1gh5?tYN=)3KATI<&2qN#Na-0r$J$;8K{XRTGB-@~d%&U!SAgv| zO@aDY$4eV!V0Jq?S-wdU(mPLe59T-$umQWe5e-w*tM+sghO)TKiDP2>W9U=N?XL(i zqBtBiO>SUYZTPR$sWKWaHv5kZw(WrYR4ooGAgcK;){OWnO1Mg5!tv05MR8O&|2 z>E~Xr9-|9Il-`M$!oFbMrqs)Y888qG%F>sU@u?2icAm91hlPG&I+T$UV43a9td^u<_=IIvwL(U}IUA(UO){_(^eP|yniM$5e z?d~VWj-e=)_Uo96nD#JMoP2D>0VgARDA4zd1a;K6pZ8V&cj3Z3aDp0sUk5`AvZ z&>%@>vrgF3nQ-R9K76>_%v`1~%Vpuh)50~d5t;0M@Z&qm3CyZH)L7+B^5}Gxfg}1s zF0l}~jH|5&0N)uL!7tKUsD} ztPaekXY8O%Et#~yqVf!tH|m183pj2loT0f&$zKob+T9J359=Ul&WbzAxVW z&EfMEd~d5|1*{#DW4hBl1>u#^yu2Qfm_t5u58q_!WEIYDIDM~3(5rgxp>6U0)+@-a z2T_{Oq#66A54OkL)Df(d+9*^zcmVV2rQ%bw(5&t^8zR&*J>G^zGsrZUYqTE@R=-Ft z(_d&LZP(~|Z*|wD{7ik5%J^5kvyob6_--wMibn@y$y=_&XL{-P~A zl&tiC>xre*@NrfdhLAh?!k!1Ca{z1C>!+yTDM=K@zStQe#h$sKbAez53h$~0Xs5(Q!5){sdfXEIYC-Q#@np_ApjxrEv zK8)8Ms7fZ z!xXOAxoyA|Eo=wjN$91kU3!`~&*>ialRmv@Ol(THb-^d<27H6_=>-$nmhdy6We~cc zvy;i6lJOKq@~hBGp&L^y63UQUCWhX7W*WDi1bN)G;|RwC6blW^HqD4MfyFZ_i)*lJ z+c#~ywzFdE`TP2QRkxRSm+`H}d5qsQEqQm|w?|@#Ty^uyiQue`HCPEi&Z%5`2e~t{ z%jmP2aEo&16znxTOC--z%+m=@i<}i7P?gsF?p&P(vi}kXrqJRb&L=W8Z_>V0?ZHe6 zjF{fmmA`QA>IS}knAnntI_nEMPG1((PfiFw}t-Strv{1RW?VfFe{7z=Ley zCu{uHX=+SN&AiG$L?rq%34(z8e-I`2e~Ln;hEmXL^B-rQ*W=IlONy&eU;k2*_>qeR zK;arl8i0+_kZc6fAZm_9bBnZm0B|l%V91tI5-(g`PZ#&B!M;HmbUc-}HE9}}rTTCe zkgkES@Mr!>C;Y$34r=sYV0K0(>6b2oH2Uw24~)Im4~;+pqYgFwfLuGsv1k-Pbs&(u zG&Rzy@HmijZ#V-82guPy^FQP?ka^N#+kg)sum#}=9yFpu4HT%Er`T7cLXd#|1Lwml z3P?`wrznQHRG$OoU3Y#~D`@o#buMa-4`p;e5>Ws-ss@09*5?pt60Zx$41r65)_ag< zCauQQh{&-)axkMEj>Brin5MB^h3cm=^8XNAsgB z@4@gfJ99)uC8Y?{Lt0^`CZGQ+c)f*ymA`cj_Go1c$~dT5e=^h=V7&IUH&DHWnq7k$ zL^4#pS?}xL6=@(n(3H3?Bd5UFzNO>m$nPLg5=wtR&^(NK>6BjKl-^Nk=m)`%d7x=|R2tPZqZPHJI5icqvoC0RRFdp@pqfW2Ej_ z#{dmoznjMoTcH{5?-zqcIDhNBy~NU8P-<+%RY8EYE-z zV1d6G2~`&IN-@W!PnSLbikQ<=6 z`*rz$dZQmw>cDROu7=jxHJI^%rnJ(P$B?0r;;8-#_*QE5N(<92vG|p$mfI`e|A{=| zbMaTx9TC9QZ!G5x2^K15*A66By)a%KqduP(y=Ee{1x5lt4omFos`xfr=(StzvxxMCFaj z7irW$tFl3k3;^rbxx9zSW66MiX^wtug$$ALcG}h`U7~}io-mwhc2pWWj~S27G2H=_ zV*STTp$`V4#CImK%ma)$umQJw0mLo;>KXy@Q)@F&oCM91Mg0u1er)`USA^Q2UZN-P z7Zxl1>!vDNPgryu%!@#tp6c!eAP#HQ5CFuS{>Rf84FV7)hlKg9!75s!0;pM2N@8RH zPb5`Ce@RNH8_bYTySSc7QWGm`{1QlIh9B1?p_|GK7(S=HXr)Z8jFy*wwx?^!i^^k* z#{6a~Uj7o$*2Q=#B?zMR&2^01)?GaRk!43b{@}7Gq+OPQye8~%Nkv?a*Y@h z(@aqUMCf~Gcb|iFENkwV`pHLih*I~&yi0-yLLr(25zn`3D9WR5{UA+2^sX%7gI>w0 z)cB(Ua*`~sDMkKZRuQZm=l-~^$fel_$mQ+|`D!}To=a4-AQ54|*5>OL8jUq+aVS7@gbsrNB(@Olnbp3 z^i%qmoJ;9qQE}9eStG~`-RS`qs>gw5v~*zqD{>2m$PE-T1y(k+1m36woJ%vCA8bVp z{(nTzP}Z~_4bv)@(76l{%`yUgKOWQA-63|9f7109l12W)L8lI-dxNbzmr< z$mkb~P^JGpu?DA5Ig&~k6@VizQ1c&jvz|gTJ4~b1-26$awGJ$!$0=+&9T-M|z!!lL zt5~n>gH?Ug%WeR`4KoQGdX#zdLT9OdpKh_FK}mOp+dJmC%4TD&^K)5LPJVysgyRTI zW(PSc(o|MX1-R{OkmrFc#AJw;dBEPgy>Q4IUapFz`iKixp^$(xc-4K?an6vo`g5ir zhml`63dk9WL~lbErGLlHoqq*^$6IZoVazNo%{y8m#3F z7#vP0C3w!VbXV-=Y%nxyXOHOxrsFrL_xFSfc=aE!$hT$+qr+^&q63%?SPyh|7(uSz zP@Vqw==qmp{jv7~#K2H(X%Dra3B@;1bhJxLT`n?USBO+|u7(Kxw#^3;lD}1_=!YCN zKnfo<2{8H?7s9B=38adp76Yt;AqSFjpa(ot<9XQzXpII15G(x%7dV$bEwzp%aW1uj z6%JC^pDZFERhSYoG9g2fI_juyjlR+Jp4w$BHTL}JMyNqIz`(jxg2{;?)OsJ}Oqqna z3KnWcxj)4TgKJmg$bxMYQiqXvp@aRT;b|oc4Cq)8!G$n4&_O8jDF0z#A z)Mn^X+Or%`m@r2RfaWq={y3KdTo+B1$c8GBx$>Try|5U%8B^*#o2rn)hDcK`RVGqJgv4 zOXW1jCITWsXeXq^K+r+p@u-sVu1f?S;~F`EgNWGZHua%2xg!##kX5Y$tAd*S>5xv0 zQzJRB`tum|0g!_X$#HA@3aCw85EwUV0%Hp*!cd<@sonY!(^2b~(1tKIE`eMTP}VOg zpdvgr&>7mf;mX1vkc$jPK3pLsh^&f(stqdsn>0Bxx%u*AgDZo=U zS=JeF+WL=^2nGzroLm+@m+mM4X^R0<+md(rhdlHlqU-!hWe!@L8VDltpHf3;fs{d~ zP0Ivn;za$6mK12XgC4dM8={IN3yCzF%=8_&hhvbRC?8 zu9p5>CNdM#5+2A1 z=J}{1Kw^L=3yq-5L=u>wo#p_&8$YhgM9Jo?UNWtr5yToS6Hs_mznSNt5Doa3C z2L=Et5$V{jj|7cWezPmseQIJCRXW!HKa@nAY5RZJd+Vqu+pZ6E00AkHZU#hBQW}9F zq(M?zK)ORgN*IuCq`NyrX+#-BQlvvVrAs;{I5+yd@AH1^eCwR`yyu+%&L6Jfo|$`= z*M05%+rM4cPDnZ}Dq+0QBEYTBPzJf1?f|f`9Spg7+4{#G?01*b0n{a`fmwcWXBK%3 z(38>MMUOx$*}vrNe>k&$2_TSb_!CS)lVkoZXYGHKnju|Gku(6{Y?+E9!SS-9ufLa|i>`l2AaW#F zHDxw5yT44*Uu*l9>J>QD9oSXcWW_4^}*fYAP%#1a7jp1Y;9b`8?QUPa!3 z18@bD_}^Ty;|~|aDgU*e8;*+sC;?!JU^o=^3T?AH>4U5;!xjau zfM~p?RM*Y({iE4`RtD^emd4HY0m!Z-h4&Y>fi#tF-uV5d>c98o?*{+~@6Efn)G4l- zuAZ_(C%yvJ(aJ6V<4Vf*j8t>VkFA97H+tVNENnScgMWj6*`JqxO!e^7A**XQOR>y7 zJX$=+@L(X1ROSaXTXiG@Q0trSB4%c)BJ>fZ41SWfgu0aRXuj~?_J^eROp3TJ=3-m|L4Wq9|kG_;AV4x7N&J2<#0CC$6 zun@2ifF9jkD+qvgM>1>#UP=)H-6_`5!?%)>2F6><(8jerf#O{c(z%;w!>=|#m4|Je zD3D$>@cTaC0fkvdkMYafQX)n&oNWit=`xJ}y8QiJO{EOOKTuhC4FVF4H;UK{{iBHg zaVbU3bW=eCFWds2=8YcS*fzS~X6-7U;)d@2a}&T<4B6rV;KhA(ybjv)J@+6Zrb1qY zlG6^Q*C3PkHZZrN2rXcHyptz&Pa##_6y6;(v<=|^34ygQN1Y@~Qhl#Mb(fm!!sl`z z78(gPN|ys_axG)@=JSDjbD{Sg8G<4~#=U;z(}Fx{IrTZ_Kwns#9crs+#*aW{owcm&U5QRZ zau9y-eSaM^TCJjQhWyPKZxpJPE>TajmlML|LZaS$|E?}^PW_{O*A|^#!nXaCOlU-Y z1{8)duGzFuJSBn2D80!>ML#1n9z{9lwWp9G!A3;?Rq6eBn|@*c6;N7U!n+IX-zLa^&)eHk=U2u?Q(sn%II~=p96xr=v+Q0B0coH{ z+Du{QVOs!3;%ZhZLnif=fWB5UXb!u4g9E~Kj%O0`tCYZ0UE%6UyAN{Iu~z^rr^Xw^RP?C%f06Fa?%;biSK=zX;>w`6D{{LY=OFvRUK z3_aV^qL~LgaAL+$C2RyfP@u(nb`Lsa2Rm4W#(?bi$V^TZrkTaf7$L<9cF)f=+EtiB zMK80m{M~nYkL`F^Y3_KR6=8XXFg(xi?8N8iCmd{4mF)QNnxi%w_nyIrmd4{*mil*E zdxf1Ol(Q0w*q6h%P?{$KnUtRPgWc~wa}%|Fh}%-gt>k$ccnw;*4>bghd?j45f4F)P zW8(+YH2rKt;zt{|B|YJsda$*D!eD_GgG?h89wwWM((2f~WH+PaF{XV=xEI}z*Ur7VAy1d$#s8oX*E)$54zSigo;yZO^hX2IGzA1NyIm z9qQkYz-MvC)p6KaUXin#i&r=`^6qAN^UjpSCZRt{dt&y8x4Yka>*b^ zPHu{R{>sk(HZ!@JhGe-ESL0Wa!~fg`B8FaECL&ig1yvvjKPA**S=xBuea^~+d5&kl zEK+*Lbu9oIhhg+jC1!?SrswbHd6)nSgV9y69B870e)P3VYm=XarN4a>0Po%AWdJZVKEGs&dD&>07G*{nY0f#;LUOUPb7o39$q&(BR#Y(@{(9K3kQ*;|z%XDAZ>0PU6%fx0npiA;`P1~~7 zSqdmDXh#4^??f1)&1Q#sWX*o@_#`*lJZ_Ip_H!h3@hgfHYG-;48kT?_902A%fOCdx zI~1;3fjA8568oj-#0)x>A*3JgS80t1@}68!!j8)oMY5kK2v4)n_~g_1m0>*Us8e=l zlgA=UyYtAp{+;tX^Ef`K+D0E6vg~D*5L8FVW1BT=?75$l*#iin!-Kc?yWNi7*`lYO zHOwH9A^?0@{cgjnS6KXz_2H*vg9uidLdiJ~IlcMQti&;D`j5!#q65 zv~C#6fM-q7J>YD($0+YtXcIZ0Zll`N`-t$lCb#pYs@8Mq4S9`zCA?l+m=f&Ecf6 zm>Lar&7m?T`vyAE&*PLog-hS619t~JPzQqVE~n**#j?QDRe@HkX0xM-L$??IR>-GQ zD1fv_!?yE(8^Bw3HFKuLT=$S&S6X9~NdQy+ojw!eIW0e}#{I7?peRu6ysds7^SHYh zz=pVT$buk=PILn4;#+kGGdVfpl-^sB@jcv$6ZMyYV z;VgL@xdZY~fS#7232*N#%(s<6yMsI`V&5Azt+OxAj1s~u*sgd5V6#NmAhK#8vl0-5 zv_*&9C`^*VZv*_&UeA8ku8&UqweA&jFy2LRyf*oX2~N*y2WIAjRMry|3?bAUM#g@c^OiRg}?V z{|}=!df*=zd=?c4nNe##Xup1&Kc0;2p zgz!xb4EdVUoOk`FF|dwQxWW^cOBe78pE~$?;(i~VAEkC%k0X+da5N2{!qC?}2e?5S zHaxZZJv{e3L}0722W3#Rrs~Hsan%h=W?(tuGOD*ZDiV6tb3t5@eFumf_6s7)VN z1HrPYcnZH^*zQiIJ#;Mt^;8c|O#gj#6M$fyJ{P;z?|YVYnoqUcsB3K)*7K!RTLYpzNI-c)zG#(#2EmHO<$MT z(LE=t%gh_{nTLOXI}6@rO9QH*_`un=b5r#rd&Hk!Z?JVz5B@64gx_KM4A4*{zoGEG zlb$GV^hTfBASp6vo%4@M z%Ynd$!s?d}B-fx%xl6Wi`HIixfiQGPHF%~;<$RY0g?E+zLmu~As;i`Mmt zr78Zw+BC|IE|=Ez?TNkhiTi1@n{tBnI{-;7qj}sQaTnL-?7qdmc+`nG8@leuo>7&9 zW@CuG4+B`)r3zCndi#qi7g?hqR9Cp)kGKBOc0JtU9k;^#=NmH&+#5Cz%RKyoN^+S9^CCom0GAAGJE5Sz1OW^Z zHAu3r{7&k@1;ASXCVDD8dVT}Qg?m0}J5D$V#lpRr@Et2Ez=DM#*g!`fK)#Ge8M>EN zbad)+c@c*~Mw;&7q0aCCrv!lM+!;OC2_g6#s3feGBInXQafYjgFJ$VG!ePR@wE+rj zzP{RA&KsGYnGS12V;h4|WsjfHTvnH2zqu%+qplwrc6X*(*Gyz*z|MF8p-xcLr>~p@~w|g>=CvlMHKZ}^vc)>aIH!SKfn}%k(Am-Dh$qCLi8%IWgDopepQ>LXuR*;IC{i?u#*~y%3WfNe7MKxa-b}dCs0R6&Mra%6}^zf1g-konBe?LT)mOh!UNtd$hp4uhp zv9sG3rcGO_r}dAt&oy{P(~*&tsCRbS$RGC-;X-?miA4Z+H!eq!xd7$#GD5ClUumEr z)7@b&u9p0ab2k90av$FG&OZ;lC69ati3JJ+y&>%*XP=+?pMD}Z>CMA%uKLUx16zr+`7?{8NL4VDjg&kkY*KR4IBK77yw3nYLK*NIpJp~oGW7Xfie?z;2|=6 zol%7Oj*Ma<->&SPBvztc$CX55Sg9{M>sKa~sB!65!c=ZWt`oq2@ zSbu=$tS!r@Kdu7&D-R3mSmUb_ctLnr2)E}x`+mi8`(Krw%L zGLkkWGSsKm%!#bdEZDNKI&9YJ`4Vy^tX zG~&j;)FpiL)ivmA@)foEZe<8OwFv`-WecY-fW5ksJq2({SqeP0=D+rR=OjK7QscZN9lmor8Lftj!w2X4`BC`h35R3%gt5Ha=jGf#-p#zGyr;>kOMe_@aY5>n15q^Fy zyaX8L8(hqTq3Y2XjABWJTYA>DfB_o^aQT7*hZm3~41_J3v&Di8W87>MqgO;$rA*?;VSFSKEeoP>H-0QK+4;Su<81LhEN^eo9Qtn&$2SG;*x z1S&UFl=A9OU0BRpg#SyfC#he;$kpwkRmB;r%F`HIG*A5|B}RxmX`5Q1`_a&FWMI9+ zO(^IG5DL0so*>fpy0b^RC`^Gc^#*{t*yj&B`JzJrVP$*tD6WuN%23QIA3$i8OYJAg zcGn>B)T4^UDZ3f(uu)myydm?qquapV>)sgE&zMQ%mq+p3J}U`F%tEyrwIo+MuTr=i zDZP*Sa{N76Nt-^9*ztV-`crgcCV(Ho4wNYo|6!a+2jz8Op1p1I>V~L1!=z2ftsa^1 z14m~knCfKm(CjDJi8sjc)M|(nO%E=13P7K#WHo?rZ!1~nKh2|#crG+IwznqCpcgpc zNgz%nCy9&{hQCud$;0q}pWB7^M+;^JpTZ|^JOhQZ&aVesM}+6b)TVoYIf$KHhAuGx zp(K#{-lH}68R$3oDV%*OJeX3J45s#)+#OmVu9@V2Lfw{ggIh#MHnboE8Q00w2SC6Z z`)Vw<&hZYlC;&_Xr{eIU9 z*loVjM*nJ;QVrJTzuDH1E9J#iC1mOg$vxyvs3dsou#yJ> zI6vh|>)T&1%>FP>movYMEvWE{bP=4sNX!(rQiuSIsoey&J_971bykpZa+3eVLW%$` zR3T=vu^ojX&Cz`aS=%C<{t=;vytjiruInyP7`8r!8wrw0OcUfsoj8xWs*&txG zMzHv$uQ=Zt*Qc>8Goc5MI#ThFLAbk+2fPsDjIn0en|Wbn+P_#QbXFC%!^r~PkGF$1 zalvBog0D)T$;uz!Wo=-Yl_HCou5=1kI-VrTK$m0!9>h4PL%gS<3xLy{CCJ4GY}5)* zPuzyCc&34vx6O@D00)pG#XR1A$E|W5QNH zSIAyIKr7o!Tgy}~mTt@~`*1a!A3!$s-N$8HelFVJp)?}Nj0&O7?^>I_Vj zo-8#*mP9EQ7ZZ58Vc zZ}hBO2{7P?&`JQN0_KxDWz57=;SF%nkCfz2wk?oOZPEfH? zNkxbTw)B&Ko{+%(x8`}3&H(~-0s|C}PYXj#hkLaAQn9DGlCtPQ2A1yeI^9z>k!K=1 zln4T44Q*BP0BRly&9GHO3>jP_!*6YDqK6+-&YcgB&?}&0RGL40YE+rqMd_COSHpm{8v}NCJFZ zuw-ZHqxsgLITPh0ydiIM4a$j;qJE0GG>|n#yX)xxRNJoyaUu|Xev6FT)oV+NaF{FM zhf*j@_ih4|*g?85B8-80AYv^B{SB{#9AxidY(+^RdB(T-kKGM;Te{Vge5w>q3y|Ki zkj?#QHYyU^l+uFLEmbj2i+!bgNXm(PpX~Fvjx3&gs7r(#NE_9k?!Wf)D+?u%k0d-@JTSgMvahQn&tb-U$OrptTER?ftR# z8gz@`0(@8m*DVp7ee54RS+f0*4TERz$7*!~xbTLxp+-K@IT8XwinJeJi3L7`Yb|-a zhkgM<5MzXwuBpHgNacZ>Y%^_d0@w|=c^)M@D4Dkp>c`q|E9%F^M;h}Ki$*-ay z_pbm+&*1M;a4p??0fue?kvu8=sDH~C5QMoAGJs;KU!2AL5weOKQblo943MfnLRM|m z)8I*8k{==rd%vT{9&Y%rinV|6%F8{id!}oS9{Mx47#MuHs&*i5-&S;}QpVBHnLqyU zGKk?sf}`N8i)%ucWG)7#h|U*KOwZyN8H1rwIGu3ONbOZ9WjR@L=+p5yi>Eeq^>Ex- zWbo(aOI6#Spq8t#>UuRnr|*0+!%Q|YQ;>A3QnMBt`jwalc`lY7HL8F)b9qqqY$NHc?LZ|G z^v;4blu?&YDH2PU57#bgrh2bvRw~jOY%hEJq%zY^X!zmVH;H{r`GTHKG;BnQOtI06 z+1$)@_o0K;yM=<1RPtC%*~df-2YNpwN?I5@R4faZ>pRlLixm;pW22 z|LH>&;X|TJ?GD^$^|!-AZ8&=pwRuR(`f8 zafsI{z=^>WSK1%u+|}XUOmMMaIkDhpyf4cOI_pji<2E*bG%lV`T zj~6K!6|X_=+HK<(-Q$P~PR&SAtOp6pXdZr0PlG^-y`z?S{M}3QR4bK8KB?YUxa!;` zU6gsZ#XqWZmjZv_u5+k!RIMbE-mWq)I;xnQQLD$VT+{M?>f*#Q11ev8J2%qMBM-?o zoR$9us!mr>uov$OJIwe{8&7(*d-ZInA8p~g zgK`~CqfzcK`zPDuInP*ArNWRE5P5J2TT9e9>M3Ee(wYWloFo&%Jaqto4r-K#PS>8= zQ5luz_c-{@;J>TH66IN0UYo_HoVgJ*v28g6Aioq&e1e`!EetKlsme*ImcorZ)OT~RzXCm-K+{1R*3n>@01gk%_{SwD=r^UK zz(4$X*(W5N3EldA@v|>@6?-n8n$;|bqMfigI7jMYU@88*Q}gqijt8Ss7nYP*RnT^5 zQ&~Z~8C3zDF<}iUPJwd*JHo*~ZKTj|P4_B##EkDnX)|KWL1$(*=e+_@O&DqS0dQ@; zK+xm@zIRbpliYA=YlV?sRDGCQ(1& zI8wRUefp6xVHf1;BuqWC{zL8sP9AR3)5Pa5#3pE>NV~W2TTZ!a;8s5<5I;c(OTEL z$+HK>u!hy2-%kr4Dx?m+uH~rXT!)&{7OEGPi4(C7lh=fyHFE9VSlmQ z_Uk^nH08S*(ou*{t}K$RnRe&m)p9ZRUJ(zd%;XM)dJEmDDZ&q@xU}i23{?`qT?%jy zo%bc@8+kjL-47!%pT(dv02n6u=M>7{)v!0Emj7S;LpP%@$gq%|AVtbaMuLK8rF_1E zkw@$$g8*CUCqr;_0eSN&z(ukF7@gf%H5?l(FZd!7RNy|tx9OB1H$s9B=Yzs{O_g)dOiKW46Nq+d#KL822e9R{5@Vs78t4|W(W^3F!A@DT2?PzJYHB>-HZjgnQg=X4Bq|y0WgNi zLfgvSh)3hGJdci*m;1Au0Y@(Gzdk zVLpEi@VOb6`uCh3udE59z8ADTM4yNBz7NdbQL8)a66U+_QeYV=qeztU8YIea8y649 zOwni=d<5Opz90}gT&mhPtgU=O&4h6$tlX@u^drZEAE^cg15FM>t{<$IVJE*<%)2H_ zE1Mn&_x`e>?HuCao{Wprjmr_Gw6ga*dC`S+@Oj1g^}r8u|ELCw*LQacqnQt@{?srDv`r}^u0FJhFguLjeg4&``sEzx(iG4 z3kf^iIW5Mgb17<1SRVS6;Jy8!S`U_}bGRM7@{=Fj)E)iA4-Jl*!;`eNp=I-4#kQ+| zIp1g#gtqf_kQFH}P0Hug&L@1Aro$I6Cx_KIrDyEOi=S(C?$w4guCu`70R!*HB+kBk zB2xhy1NcKPnguUX`w|pw)(dPU^|e<{j|(S$Jh&s3_t}JoT-EAF#TDzJ(TPoyZVPeVZL>N3Jr>F#_zTYBFpk7{1{#{GW8Vp zHYjlhbBQ+#+bO!^^E27M$1Oagg-Xu^~5S)T#aH{MC`9%nN69FLJ)O zldPY=qPTY`-WP19Vwfcfe-lqzZ;4;VoJ8u$o%blUP)HYMJ>ZIxn3P+N`^I#OoUlI` zz0(C}9*bvUsfO_m%LBegGLmN5R(+mz4{*DqmcB8hlBkkfv8SDCa1h~&WL5selSvQ` z@%!nc*j80`T##TWwx(Q!gB7mZIhK{L_Z^b<`o;HAeerfaKK)9J=s>zG?DR&tPl?1{ zKLV29UyOgqFBs)_y+~ohjH+!W*|p z1UD_STRQGzw#21=0fA&ncQP|&x+A#)CO_wA4MU>Ntr5*mTjQ{=S$y`dS28KVqK-YK zYO{y3m7nC&*3GNXf>z&KTDB?}God~AF!wqG@Ncczqt1GYeAnSFe4J znQlDe&S0vt(x7NzORsKW%_5B5D(n9yQlgh&S|s2j9i`6J#^>(aR7sXrWkiJu9hUd! z28wv8wB*)*(&=3NvNf9cGR0%JYxRwZ8gegdKvan2&iCvuixl2J^g=nJ(@ zMjumI(FpK5%~WPNLsnK_hXGt;=@_;J@unPeY?eM}iD)@ByDNT2=uK1bs+XLlmLjba z>8Mu3Dp|6UW<;u?=B;GAPbCjIcw-xJ9s4>DBk?7COnK?l^|~Xa3&e7ncuTkE`3E*`abn3pV&`jzsbyW2>2fQd@e6y0(S7mnxcm?|-f;$&q3CjD z?q;IB?^Kh;UWMYT&Yfn59FlSQGd1exg)}LTnlmMMKz^BqCYpwx5sKi zXmZ&?1rXL3WAePNEKAtsOg1^^A@g-6iT!PA%*57#nR%)dB$6Z#>pf)Xo{#Ugi}e2j zce~l`UaT~Jx^0w8erz>st({H$+9|4JCcChzyWCpUM-?-BuTHDrfmlrtPoK2+&U;f% zT@KsU51M5NhAP#G-m2GCI<&Z)$~_0Z!(nSCZ<#S?t~3Vneb{-Xh>s)n^aj0DbewF8 zW1|UM<<&^}yEwSY8;Mz+E=oHLOajdq`@I$(D7sFju|=6j7WLYA7#b!jxwyUMtfHYz z{4$%mO{ep{5x2S1kT`#8tly?q_;JM`nlZSUy#3w$lm}$3 zxOLKN(XyB6l?aRLRAI^P?|xvaBS_IEbCvDo|IcW-6_RbddCx~w_5Dc9u{7x5E zYfzh)8Zwz95P-HGK&j5Z_*PCntI~0BnzifOc%LiLRFsk8T8CQy*VGLi!T6nlM#j=e z-1`d`sqBM-_el;kvh--iYUN@EGXrmF<+og*^Y=xVK#Ilc^fYKyUUbP9oR;dw9Fj~OhPS{pbcP%Oi!F>VegZ*N^yh{; zUTHRzzs$FcRRX_OwZSkH*^+-s%pywC;@vMJQp%IW8BWcyo^i(^Q(5g!0m%?0Xs8kq7nGF;ApO7Yfp9!W*RmU+nQM zyFIqQCi7&Az`Hf`sAHE4QP7b1%i=;hTFF8Cg6r()l_f9jS;#kh`0>nWke{rov2&nC zim7wYXuPhZB(7wQO(SK2nB&!?bK=R<4o3gP_I?kqmLB>Ca^qh(Zsbdm_4-DxKVJUgD-eFRQ^H$` z&ScrJ^LlLC@tvqjDHQs?FlPUonw?3?FETVz*3LKTDq1b~>yJNZ-r`WUiEq(3-|K6Q z2q~ty<=i(Vg$!&3tyLK(#mkL6ZUrDAmV#S5NYripfkJ_ zaNtCGuqy1hHQ=F}g5zsfCPqIj-T~aOzTl{jmuZ#=AvTn3G!z4UQ%mB1@mKi&_6Yv% zul(^k{$KT1{`}-W_E&Ch`@i*91O)j0hrhCy-T#WViAYMl5fM3UCAM+5gJyHrvcE?0 ztyB77Uqlw>X#u5@tik={$E=HQhk7Zz(_MPMMUh^i=>UXf_-A~OU1Njm2b!Ahyq#BM zxa~vy%9Od9=QU(Gut#}yi9xx9oJ9Mu?RzP?uuQ*K?yd(BA(c9Vu_kmHS}DbrjUNZB zu~6&$DpbpLg`U{Q25u)!7#7L}O9u+r3NT+Ws0Ld{z0NCt-P`x%*!wRtSBCEvRxKa* zzmblS|8?2Aa`!Q}fhg3V)bd#FfiWrb^GOYyr?edAMfv8aX6~8Z%P<+@@-o4f#Lm}k zsbQ(d2U&{CXqO218=}5yfn(X!XDP)w+Ism#NdxIFPR;#@XY?)oKh}|)I{H` zHcv?eN!~>ikG^3Oglb8oq^Jq&Z^p-kFn(vtUoY)qWKD9DfDmR=a_3xf;_(Qo*HG1f z)%6#IKD0ga&@Pve;k(w$f1V`uz}4A3_iDEhh1O!*Nj;F@sDg{7ss7R33$l=7ha&>yQ&xGQtx^jeN&nxcr5Bm8-&D zN`!#-oArKdqCj2k1uhMM@lnm^!O8sHVjlyJ8hI}wm`QOYo>839=uK5rP)%?@Q$)F= z1jSD_9zS8IwKeNL0GmLfxUr=L>D&)_hEJzEYUh7plvJSc-mA7f zR$+82kBZ+bSnAZm9Flm@%v&UoobhrmQD%|ugVufJyNoJDiq5qr%n!X!+#;JMK9h;! zZz>Oj-l1LV{VMXwT?&7KZA?&EgWXGS)zFp8$Q`GqwfdC7VL}XN$qaKdHKxI6i-XY0 zsp`{6NAnpR)7AhK7Zk~$%hsQ@jY)0yEG6*io|CcZX&XLmh&Tn+ZWy zgX#FE0W6_CWHMqW-lOyn!nsQ*<)>Hb8(+$315yXGu)LIOO0p?sT0iDljyIgX z`jnRQGF-X0R+jB}>aaTt_GZcbX){ho8ruL%bN&hh3r^Ik#bx;h+#qODy-Q}7)*ZL$ z;z>DUb4vKmvAgKuF_c{Ot^swFQLL)bNwbR^_B!7Bw|YkAI zn-W#A=@}(Dfz?13^X+L8jn)f)egbr+JrQH^Q+{q2w_@jRc{kxCSD%U`7j?Y^cX zZ<0I1jWQBid{;zR^WX8YzO1C1PX~=|aYz)n|CmM3^UL&h^`F1YZ7j3&Wf(^`Ul-pY z4?MT2z7Qu&-pO-lhulKB z&k`s^m`ai>I8j=kUw``U5=GFjc$_i~U5*g9Jq0f9w?o_BmVF4-<%Wv`JjLns4`7W_GG3Fhx-<=iDGHo7%=Fk8p zZkKYD_`yt!jAv7c1V6lAV@^z^scW>cW?_~>Q}X`nL6QEMHaDgua^km$+trKAxuj30mc>7s4X^hpbjCv14&*`K%9XV)sRO``u|D*Pr^VDkTN? z8=6Kr`0&aa^mUU|%qzTy5#+Dh9wCeP%-?g79y{C%vM1^rjl;f+zY#HOf|NQ>vkQ%s zwx04XdQ3{UIQ8aNe^1A$#rpG?+OF4M;>S{_bs?`s8-A5d2Ul;L5{OH>86h*H29iFI zy_8*$bL_;=(-jk;whw&%{D+1^eE(2tvMQI(qoXffGJAKOO)&2xs68;-BIWy#piXvX zy-J1&CSzJn+u}n*#Z$c(UG4D39-iU{U-5iG^>&P3dUw4FeP^WaCb(=1aTSnvccSw5 z6`Ee-?J0i&-eJVeVv#PDGZFKk{;Ao-+-Luj07snAikXRU0%ak!aPL;8cogMhe_h;p z@whZ0zCye&>}|9U8qIO3Z25vs>S;XkaQJi4=5NJoUfkPy_3J*1EjM1FTzP(m1N!uZ z)GOh9&xV{q4Et7#=VGz;~)T{NV z#lHYmQEP1{qzM-3$SQ92E3+_H_&F3ID4!cTZp5yh?nWyp7|Kx=QoTE%drKJ?E0Cfg zadnDQsL??c(W3EiHfJ#Cbt{H-utDWlrefY|ZC#d7g#u3Y<+qHYcjDZwGomcUak)|@ z3HTDhNR!5zUwcBNcSCeSci99+_tf#dIQs|f_e>G?dp2^MdBkfnI2zB&Fm2yn(9nh{ zE!$P*ixjl?7{$1*s@_#TyfX(UZWj`BgMJkLDmSz9hBlp%*`xL35nV?$k;gD&v~Nz; zI+LN-=VzVl`D$q&KUq&%usxXOmT6ctp0cnS4nPkZEnPE#!w)^fbX^V(Y+mK82v!xA zmyUJLq4U-_nSA(JHh?zgkf*}9Xup03XXZqXnMrsYY2}`|BzJ@`wyePKY4~Ic%jf-e z#GZu{MEvRCmQJj28-&I!1foSGU1#9Ud&do-k&bxV6fj8JNw!P7lCjI=*kGg8eoYN2 zQ9e-x9!ySOJgqMaT0Aq6p~22QRs3bMq|_;JxR6J5?%-)MNim0tr;N#t8-ityFjL-t zzt}}Krw6qHrKR{XTsqhLIX{oesM$Ol`yAj!kfhFsEu3k6GCY5GG=G@i)|!@M=pf&Y{j$1bT#(LF zO}d;VxaNGPw@ro3cG*v0p`C`T_q9~4coMs_siU}n<<=`FN!3h=z24XFnGx@O9)kC0 z6!t77RbNT17*?e~pW!-*4Cvo3bD%@Li|o{D9t-w6q{$qU;j71{Q#ne0RAa#3NAUWU za8ylfhbp;Y=4qKHIgTW*0p)A_W2>J_KNDTcB8JfQ*XEo+T>-@ddlYEn{seU$1ebR7 zW|28RTN^Kd)(~|}6Aqz)_i_zW1YA&h2*$pE#Y?m$Ck>t;s=Rq=o^*bKvoxpkkLq0} zGwxbJpBpbMcSFv^am=KAt-UI|wL}-h3FD6}W$JwvgGdX&l1vY3)o-u=*vMB>G`^>w zJSB#e;;b1sb4kO;;dW}j8DUn)GDT;;RNwu8D8_E*t&sprU70jfu|LL@j!?;mkIxHv zAXKqsa?s$JbaHemuU;+L70&2#=s9mVzNAYpM<{^jP;7@J5o)jS}}C zj^0z>U)5NvLk&iSrG07pdG(xmLbJ8*nECyiIS(9KvuMX*7YB!oS?2zi;O1x89~{hs zdyUd#av!8exk0Y>MbohLUWFC9pPC+r8%d8#(HA$At!uJDk`*3$>&v?DcfBq%;kUUZ{;T=Xu|T#lfimWC4^~mZIKFf_ z@Lw-3lY`x&G+*=E&W}q^*RhP- z)n!*pNiRz8q$Ao-HMQp}xP6h7nT05^*A{}NsufozGIaCN{F?Xd)&fW#r*vOM;4KTi zbvSw*&WR^eM{&9R52lL2#cL}@6=SE%B{i(TCFpa300|%BMtRsk$>dwWFjb>p>QLC{(|`O&}Sp8NuDUM?*}F1y80NI(;LrGJ%OLhyvN4nU;Aja zB-^NUB3Ha0^k&Y#MTCn(?K0@0`(w6`k*{Q8!N$l%#q#i?GWJ6Rn^S4^0<|RJ z_`XX+^k9Ma7Si4}h+M~~s8V+yL^8Xx_Q|HTboa^hAnf#IVSy$qd^X#!6e;VxU|e!k z^CfT6{1zpP$Pc5%*o#u0MC9+sWPl@5M+mCL zdUQRCMn>I;83ZY2LCxN`N3u-2mG{RVjWKJs`X@gmesHQTia)+rdHunz zeXi4PC$4(MQ6+df8JR#nGAZMjen0b5pcb*y56xYlS^bcs#Lt0ca<(!KM2br_&z>8? z^F240H3EAh>rlo=-$!(Hu zH0;v~*{NW0wiYHynS7S7{~UctrK4!lX%A#0ehLZMWI4d`4X`vzp0# z#wt0S^mxwKi}>*R)Y^h$Z$Sjz6m!x$@6(+`TFGaQ`7E*l6JE_8j=TSS2)>v`OrRGE!I zrbCewylfRHIR~h}qtA83yA+>2eYUW#^plZ!V<~Pv#&?wqiIA-MK_YEm&L^c7TyeA* zh9n1@g5P3IJW#r#Cy45@ho%lsY;kq$Ct6~sNM!FU%Y+nDlV)Fy+$+1H$+4%4c@arB z93|=T8O@alA$?dJ;ud7N$Li0D;<7%tn8}rMZfnoSTVSOS4iz#~ISlG(MxS0kdfvob zcyHFprZf&74HqVH(Wjs6oro?iBS>t_C=Jw#!!@O)drkO%u=b8YvPN6BXknLa+qSEA z*|xpQ+GX3eZQHhO+qU)UoYSwnZ@lif_rB;~Ut~sP=8W~N_2nF6jydM{7aY#VHo||w z4zc_P|MKtb5bMu-3UvRY?9e}cMuG1CnjQK_B>!7>h>4Ar<3CrkFEb~tv0D**V#~7( ztW#m}X}`Vg!1ab@>OyPPs~g4OiNMz5j0T$;EYz{|Vvk1*4?=+s>ZW59VF})YmGh4t zYFL=guH>t0`OJc->o_(a9b*Ugo}nbrb!Tp>5w<+I^TO}*ucN6EcDwHcsk>iWTs-U^ z2HBRpB@XuvE)htkI7TgBSv1kV*>u&$z;!b`xHV|Q;=6G$_CxNxdAT@W2geWN1rUk~ z>&D9k;3+a3#-9gk2}IQUli5J-X)t?}@xl%1>_#{4Dkw*jk|S?g{|2ZF7TWBoArQf! zj8{`GiqP_+#EA)4sw2LFr0BK+M*V((N?vXyev*ogX|qw@b5lLN*NBLjJa^#iexX5hC@Ag`SF#@&Tm4tTd2Waj2cUkV<;aIRIwtW61!A z>aKPxAj+JJJo&f6iX6-=kH>AU8bvzL7vxvK(*u(~Z|ynz(C24qkyV88$L8~kOuFGS zP&LmkTz@!QQSg(WYB-89a7Td6P*t!hZb=0-R&*OH>y{5>|^JT>+1Q$=-d6D3qX z5v$`rkT8#1+Uswq(9jomc0Wx265$0cjDRo!;I_fs#c@FPWqH~ITF`P{HYUxyah5bsc!Fh7_Ldz~#?F!a3G3e^wD$2VW3>TZBx=!rORb}O;bTKOy z4{pbI@1ZIi3q&)=O0q=6uZ5;Z-cIE0hn|WabxdZCl>=msf6^ttsqz;qfAm%+*UiL; zA}fzcM+mZhK>7Y&k?K z3QD&vAd=vJ^wrF##Il}o%7|_?^;yzDy=g3jK;WR6=1(+Y#0r+wjbPbQhxJ=w$=IiX~?p(B|SP?*DckX*ro;5 zHK43*=TAvvGa2HY`XklTGetkJ?)_yratErWt}9Ik(9QX~@uwwBYv^2EP7&qGv&0B@)nrEzpW%2aum*mg zE+&kzsh#2#bimmQps^sqqT*3e-~W1ltkb89ZK4Jqbn1tY0{bRaSt~(td_Qtx*%mw$ z{;tPR=M3p{UP2?5D@HAJ-Zf?*NXo);9$@UqXOQ$oBx()nM;86vK_VB~oRId|X?yh> zKfF&9Y|nHhM++0cLZ}f^s6&0EY01iB?UazBcyCF`{y4HWG5lAXoi_0XXO@y5M>Bes z&whA&W)Zu5uzB^xg_*2`cK%B667jOToIh%>+^=CcxgD!IfHMeaZ@I=ga90a6<=oMY zGw1bi5DrFyaE(z;2$`Ev4S%8OPz#@SiP^R-{S4g|Vf^;9fy2;|pb3HdulJ=~L@_>C zc}*EQ-Sj$N5!<6_J!bZH>%FKCu$IN5{hiwf{^$q^`Hy-iET$|ZfOq1?d$LCRR#{5r zEqw!77_;FM_6fTXRztOFd^Sf`4gIma!7$`#KxhuUU+e@hp&?U-{&bO2x;V#=8Yjic zV$Z$Bfg*k8o!i%2p`A@eYoE=b%l^&sMoibO6WsM%bDB?;^-b>l8x-!AC8rvvE*Wwm zT34s?Ktqqfrf`1qib&vSXw#B{d#GvFi7}yW@0`?TuGvQ_6wFn~BzhE6O`a!M4rCCF> zz9Fz4M%)FZ@oTX?yl~wp1?;m`+{HE;SGa3yM|`NJG{QBC5pxbmqUVH54G|i{EVesH z;clovw+OW3w&iejvK@jt+IB zn>X;;cfh9r5#AfTm|ZSWY}}?l#??Cwx^1~5%uy+zt}|#ff}dNDi<{AS%01V4IK?Ag zhe3q%JKW*TVx7e8C#;BG9w0p0BNfq9&0Xy1n4=GsrTgbtVRCJijsUs6GA?-!E*367 z=sXcHXn|2wXsNg;8gy_g37Ng6@y{K?iwVOd*H5rirveSrczqaG;(%0f`p8?Jl%MX# zT&og@iObO?U}Bclh!EEm`_UvcbA@=CvuRSSv)TNoS1l}=I!O8!@dWAYmc`w1rH?R@ z<^$FA+~Sp4s!a@ z`7JyIARFwCFN%GxTsE(zhe?uC;B3Yx!Dgnl9QBE{omDN9Dd`N(@O#Yk%@|%lcRkO( zy5TI^82rS^0jh;o#uD&KBxGdZ$lk3Vh;xQos0@We=Y)x)hSCZ#N|Xo%0HvOZ6K4p7 z)S-I>bffBt-TevjF`-I$V#^dE;VH=nwcnlz@`o7v7VR|XHf}V5){h$Onpr?SehNr- zG*JYDeKq3z1^C#(GQV4((G=0Z(6=^;LDa<`2=HgY&eKnbjELHK;BBatGoxm#Q%`{% z4nYC-mh^8;`@0UIZYcALZ?oI2*2261!X%?fbn%l5&FB{!o&LHz6S{Q>x3^JOL2Ep> z;nd?9AX^7tGx4U3Qgu?V9a9UyI5FiC6x!@Js-KMQ~$+-V`g^)lUtH5{`<2JN_*{k6E zH2^=nx7>z40_0peiLHUdf()ai8el!u%safP_4@6*54NL`p?72%Y*9a5#(9rCjnIvH_c;O{%K ztgX7ud62iLLanQxX*ex9dum4*qV#k7DW)5R&k1Oavo#EOvM5+Qe*05v$XM?K5k6H~ ztb0q&(?i#BP|j4LL_0a}9LGB?ll>X?e>H+!g!X=}edL?Jk9Ri3()?E6T*a!Cv`h^b z7x0xi?U$2^$&$r{mpX{8Z^av-Lc@%0Nd|?-pkGi_UHCal@?O#)b$fkERGdZ83@9RI39$C$p_6<6TPwOjoIeo<}*Xm0@%}b zFWbw_H<`0fxF(b9f;X$A)a1;h{%)|k9}86<`Vz~VG>HOdx+Jl~95^}$=s9T1Alag^ zS>$cXA30oo()S*Zgi~~APQy+Ddo|;x3f|L;xY_AUkOq^|QFrZ{v5uK%*h%~Wm0_}9 zQ(?DqFy2Sz^i{wYcF4OIt%{rXGu@)Md*JS!rSA}d$DB)yJ`UpHzQtvQG!u=$kp|rW z#`#G;n)%MS=hkzrD)hrYPtv5D(yEmH{2;?}>%k=nLss>4SZ?80hy4C9*srkP6oi&q z$%53EQw{R8b(2`Yq-M{@k%0A^+eb^OY@in+9yXZsKM`|seK{eKXg3))!P*eU+i{}E9!aQs8HuJHe=&pH12 z;(x*G;#NOGb3wX)Uc~>UMW<7fH83|a{E@4({PP3<8*TbOLjONN^Gt028O=}rhc?|- z1i^H%>xML~PB@()mhg|T*qtvv9{?#|2(g$3q<6gcD4M6g3@3ZN#rV}2ZiE>9pR=4a z4aWL9J6CmWmsV7NB@5s0#G(1|M78WHovOZ^+wB$cby>P)XE@btFPt3Jl*irrM0A4) zksw>ODxMFObNqvxrQqc9NjLYG>BMK-nw$6Dvzz#9w&y0Nn5mVT*0rdX-<@ z7;86~){$Z9!7Io${Ee;+iT?7vFOz_@Yz%FYd_f}Mt+C2$td!>^1|o}7jm}v6(|k4L z#6Q|}LeA13(Qqbi#ij?3^>}JU5CEiW`=kGZ%KGH%6CaEKWwYyM!U|{gSsYqpqVsiu z#QHox3c~zNNs;NgQ0MFOl5e69vI7eSnxm^2Sc!u?&n|Gk+k13>cU8i@|2(Ya(T&R^ zPiE=aM3aaLg*M5LIDG`52n8y2SiEqKRN7Y^GcW9X=zuu37D;=hjdb?w!J<3KDI{v8 zHFc%6S&!cIc-ub&%;09OoqaBW6Mbdp2k$H?Y6~ zURc1vF5h~G99qsJaII!Z*nw29v;g20R=)^GAmPtZcM}+_ismJM1gCvxqWR61>jshr z1iYI^xpN$arDW4f*Ppi0Gfh=Y`5ND%VfUM;HpWh|?tbI=f z@em1=@^nMiQxe0-=9fP1d*W^#uQ=5<(Gmzxt`Ncubh4X60r7 zita`k7MUi9a^PSE{&TgKki>JJ$;n}iy5K4sjs@>bkjG;NW)v#yAb;A=Q|+>9cE=B8 z9@fN8uq%pv3L)q*3vl#B51~r&M_Dy1pm^b25{QF5FIT)Q=HT7hJtx=)BBH7@U1?wY zbl|}$7{>Ei^Pa8;p(i{Y9{)A4!c7hOxXjAL8J#e^n;+SCl!zJZcXp69<9o0)kzKc0 znFL?SXN{HO=n%w-{I6T7IJyfr_*_CW*YIBH-lB|Cr} ze=a~40Af(~C+i26zl}b{kp;xyLZsNuN9jw%NHUuDj`@EV+#s|k+5rae17^4EeP(+B z5PMe?Ij3WMqC)bY2Z*Oi_{(AA3w##2xR-~ESIbk!1&}LZeFrFEf&Plj1yAtgS3fZ4 zM^FHcRY<|zf=@>e_=VDrB+#X4+wJb9*kfB0f^kN*U&?St0+JCk>c}$nuOlL7H##0u zAe#f+3>)xI^(4qaDt71QDe?R!-`h@?G!Kx^CvIi4 z8FN!*68KF3r0}~uw%rxgeGf=tax`{b_(LlSU(c_M>It%3U>9W~s-~=^<_!l6Uv~Ay zdCAS&N*WPm8jC5buT8oIOtT4>6(&ie__vK>C^L8jXgMDZAJnr?GZRISBnZm+qY4Zl zD-~6_oQ1p5P)S-nL}6_y$tsMG4Oc6EvE>cdIHV%Hx!vg8l#(57&Zk>O z%POEMKC-%v-m-=j4Emzxc>yEA`JvrS`T7P2Ue9_n^P42r@B9A6{6wwnD(VCb4aySG zk2Oq~fFC3M(X-Vt3P50$Js*f3gaHh&r*@rZ$vwV+{&WW%(&uw!Tnfh$pk8CEcyRpR z4!#5h1P}{+L)!%Nd0_|@5L}|=7}7U8!0`fFM1NqPNl@um$rMS zwPNpmc<7eT8NRh#hVtQj}8Ph2zruV?n7Veq31X8PufW0iicE0v0SrWI2cm zb?_8zMlw_6?a7Q6Hniidiu?q}5+;JgtK;Z4LmhE5Y-8tI)}S;W5@d0u9)@};#Pc=8PEd+Ah=NzD+K zP!k|C@HJ%y4i~of53}^C&N2Tm&NM*o4R1EOz3y9?{Y&&U5@_r zCXo`aXUm@0xMWv+tYh!d!Ilk`&qfEFvFp0um+@>lL84yTLquGjA-{s3|4wCwymadE zgz}0~$E`f~p9Jf<3cMMw@Z27M?Y%p8@%SL3+Z`R;dvDUC5_9oJ5V5wOc}BW+_U!(K zy^!frxtNh?MXJ)JJO&pZ;1Iy9Mmr!xAA@qESE8`hBS*^c&D|LH&y})4fOd>STbYLk z2Xh}I2XhD4(9@spTSIsvU)PJysSyo?bZ?ks)~zbIv95Fga!BscDSf*q{GOnqyE}Nh zw|u;O8w3+&L1D>}?m4x65g>af<@SwgZ$SbjZvhJ1Hs0Y1Ds-iQs4hu3w zRD`<9%`n~&DjYll~pz$_H3{zjdk8jo$rM?JfcjyiVUSBG?P%vRCz zaD?CijVwfER z1gUn7nz83=edAW>Z`zz`BgT_LEfrLU)(Uw8J9Pr~Nu$E#Nu$6m1=@3x>edO*6V2Q zhh*E^g;vutaKp#cOHp*Sx4tn8FAc4%vUZBQ&giCZCw}?Tj0C(cy~R{@^6Wj`01z+5 zG6nZC=^82=^{yZDs8ZY~^q@w(=ry45pasf(J7`I^oi#tyQP&dnzI#_hEI`vB_k1_D z&6O>t01_BjWg%Yl=_yIff`R9?c?RgCe)>`F$xWP;qU+k2n>20O0K%9*O`7%pSo9blxpXsLf#pf&OlWxA9bE4&T%zT2%%zR%-onWc^Ug zF@y=%p%(T_T}>R)6iRDk#(A|ZiLhf}y?L9+)DA*qJynJzGO#F?zQ(VJl0T*+^DRQ0 zd^53M&V%2BaLl-Pyc#Cx0Zxlq!@Oi1RS((*NCE>7g|;|d#<{?+mUobI5ejn+%=D$V z!!<^QC1*2)XGL&6OI4IYP((J;L@AKHfKKNFgF0k=XqhJ`?wR1aj))h?PmZl{O{fhS z-WY>hcfPel9*SJ~DV}=FiIA|9gk2yX+bIi{scj}&a~ua-x7eoE;{F;)atbGfNyqw$XEf)oV& zI4vfKBge;<=Az&v8Y$W4=dCL8!v1z~c88x~B!qx0$0uoA?l@Xad_YTtze*~-V)aADwG5{lXSFl8{5 zZkS$w-4NfNS_Wu+aQgk38mkjR;v;dyzLwJ)?z$od%b2a*SCi82?UWJ4c^4q0yJ3c? z`SvALc-@Wi418Wo+lp5v?*e{q%P-BzADfzX13^?=WbLG&n6*`2S{%h~^taxs*qRsY zLyIgdnTzYzt?y^w5{qZLyO+8%wr(@wcb|JUyy1N=MnwG=X#F1$_`ip@B4&2>4*0Be z|JH)d!a^s5&+xAf?jI1X=wS69px1PZk-1TcUaqEg7LJisj-HtT(9X}tk_dkteT)^b zE;7eb5q}+ij1{;JhR>3V%Lf1$;Is+m=)VYw;UA#>-(vcA27%#Ut>yod^?i>2pWW*J z4CTLHvwvGFMg}I9|5zQDj7E*|IP6Bm&1cnxC`vzC$zoFQtLU%r=7?JY;N+=A}h zJEwq5{e8X1cNo;xWlC{%8fQ=R4(@#jXG#(hMp@hv%8NFc=p+t=AB97QlM)W9<=ZOO zO1s;{2bbgNSEt602Z2PTJ=XWeBqG;55^Rp+Q*$;a88Ji->FLVbFzMNE$hpL~1R$xsVub{(N@KH9{Buyr5fXJl}awZ3a3FZ-JAg_jtC{GIj~&b=`R;3rXKaxT}5 z`PKYt3^EiYg3&i|RJ=%41)*La5xXi8Pj+48T0ms_$~-xKqEMP&44yQiWvhz1I%M|H zhejG5YR~Jc&s8dFgFa>JYhMmQ4|rTXa?yxh*)Sw)FL4;dx?%&aATlSX!AJ@4lwA1A zN_`y&l=DKocs^6zfVLEzgNrwGbh*-Ek_)2;LBvmT5X*<-nPZl`(j5gHN!Wacvb|W& z)ko_LNgqv(10*IkiOZh{n=1`Y7o(*(CD~V3iD0(G`<*pOvBr!i>$v zREj>t@4@-Zi|ypp+Z~m4FDbf3g12d~LA!s$G>|cT(o1*4ZoMXs5D=NMq0W+UiY9~9 z&&WyUG&H`u8w#wK49Q8s;~`|gb4EBU`m|lmy;7vOA-pmaIB@QHsHq~G%nTr_%9j|i+&+Jiu;uw2;D}S$~@{% zNr|`?xd;?xhR%&-)<>K*I@%JE3X}R1zen8b!!9wn7sP^Htg->auEwLJDzVUvO#-7D zg-c_8p}U)Z>(!Fd5=>gcERxe}BAqa(X^7uGE(}a62Nr+g7WBxR@QF59p2_{C7Qb`?Y2B%S89>Y z7jj?=OH6#HC+7k^Y8)q5INyveLJRST{Mh5aY&<-!kI7GW?rwvq!mMC6ogA-$<2oEC zaujpD{TIvb0N!l#uRQ7(5FL7C43v!5-2}7Wq0EDD*Y4IeSz}!W`rm#ELDV=Sh7ij_j^Sy{87Q;=z^E%-(8J zA}uDl){6&V%98l4H78({q8k$hQK5z7+p$dO-0f~Or9-~Q^oO}*ak;`dd7_5A>K}16 z#nUb)PPlaxbskqWTc<`tucMBUgAu|0gH(w^XD~`exeIL8;@11gQNbDm!o*1SO5MMQ)i)4QR+bdSQS%ach14m?sBMj z$mqW6%fl$n54j|D*s=DpsJ{$l!yMiuLWIquaNOtX$hFSn++j=ZFKDJTr}&+Xj(K4N zucL^`AeG6EsVm~`b={4d{&52sIZW`C9c5@lVLL=J^E>9j;uL+@=N%z%jFvryzieE| z9H#qkVwK)kE=^?C;zlkiI3GSb99d~~QVx%j4>6{ooixH1hqqayX0;8U;QWgyKuQjg z-UDsnI$v=Lvz$_h9y5rhm>zHV1QQ=yd#?y(!{R;lgIjM41{ri&*^f@tDLYH%9Z{D~ z+p05DIut~=YQ(am?|#Ap!g)rJHc%WbFrq283P7Hg!X)c(P{#vug-K&Qt*g zkq@OiHbVH(QBouiy6+4(#pfc6%^V0@-9CSl{+EEC&2uuY-5FRpd`|Oq#s;?!nBjPA zSS|SX4nW&2>jGH>ukI%v1wa+qf0aG`!`A2jlRf>TpZ0%N9m(-8`=I}&+VX$m^~3O= zT6_O{vmaJ^HunFVJuUM5WKV2S&tG9}?0M!YnG%ene~Jugy`mcPAJ-H#kr=Xg9Ln*| zl*=`f+IS2Hy@tJphOWM)2DBbv?Ct9vD=BXSHuuK0Pz8UD)3YsjV{Wf zz9n~G%l+LPZEyPdRatJg0S*q2t5vdbakxF^02`dj^Y8uJ&fd3DtzRrv0Kb~bt5_4Y zaXLBGs#!(9z2F6OU0>dBduMIBbiKQ76U{QOm)O#a?4+;X9>*v3OZ=|=w70FGAJ8$| zy&5?J@*InFvkTLVJ+&d5)4Le8OK==)Ps(=$HY>ViO8hmuS6jwj+n~5aX!bE^Kjm3ND@O`i#zU%xc66;p_G8~cPdw(G1HyRfUOjhvL1o6(Oj)zAyBRdb2|ABN*YWzOG?Az89K)i5098NkLa3!k8d{SVreY%h$Ys1 zZT4JtI;M6LW{G0BUZdYl*F03O9GpwnG*v_$m(Rb%s1C1Tg4RG*iCf(3+M?qQ$P$BN zwb6uI&_Ek?v}IdjgNHR88on{gPBmzid1?p^Y3uZLQAy&6e};t>n+KjZMDt;wsYx8% z49@m8(SH~|p zp3p<@GtR7}J(KT3ga%w6NFt?Ra=7Ng0bJ%p z_;91<>1W!JO@%Ux2{V1tqlZFq$4GiKdOGO4WEhoN% z$mXDyo)cFWKt_z%g{M%(&u@xE;T`D*9{Q9-{J>SPZ4VS@9VG2V4pLxMdfPevumNqt zXZqd*$+PZ~_|?_7J1e(x98Brk2u()xrJj+iofpSBHcgTECnqP)>`;gVgR)d;&xvaL zF;avC(t|Ir=UITn>Y8$$gwj>QV22~L5Y3>Tj*Zk@T)ICLyjzDvxe68sDWVxufAeqY znv!&8l$YF#r4f(f#A;LA3PxtWltQuyaYNmMlVqI6$h?AE_(FdgJqe5Sa6pw5SO8-7 z6!zdNY{DMJAj(d{p3tH19;A|7h94Fubj^OKpVYLiq>BLI?t5;Fr3tAr1RE>~_+_j} zKt$WspYUcRm1uu6el()aYC5-UKeWyMUw{;6P>ZaLqdeu zj=p&!&=~h``QU-L#+v-?##2pFm;ZpC&WN)cSMUMDLP}#Jy1Laj%T2Y0ha@jsxFEK| zApZi2h2-fSwwI`UkXOe{uu-u$n&LRbh%FfX1M&SZ%6|##YLHA7A(j=5`d|%G`OBhczk8*#=bHi$*z8#V4ob#3*n$9 z5)Jg3EFGAMHm=xvJA=<}ydQc)mqY(Fq*-h!jRb*gaVLJ&fZC0v0vA!8Wo(}tSyu6`^o7%!hg^8s{v4g-tshPedWHd;&mGZC{`QJf*1Y73*wH(5`hzeZ# zJ#4kv90=G{OR_#i;*sL9{sM!9_w}1g}BV&I5xJ=^TwH)vrF)rmdq#yWc#4hl9Y~cbRgEY{rLzazJC#@z*yYdtU^?Ec6X5#e0q~(WQ z)}_aWMrqFoF$O@{^3H5)21s_KM9Of?6gJy2Mz;b8QA)R=XW_{}QLP?V10sz1<_&bh zUA42seL(W?#giQkcD!1vQM{J0>0Ra>p$l+$Z}fFjP#~swf&+pwu6IB?1b9kJn|z#?Xx>&W0}Op(imT+ z_TYUj&q<41%D?;t#{9K2wJfX-GaHVp6H}vXG!hPx;>vKM31u}NSqt^)ZRQn;YnBCs zO!M2}8j)}L8-hxT-&qJZG4hWT=2(#u((bPXu5PBo1T99Vp`^P=yb1DKt{njRu43Is zNZV4{*>-vRKi_i%{bi)2r?^epd!ifVE^7rvaCpI5_X1ff{9vmyxX7mzMs*Lv7* z3ta3vck0JG=$UoILSniz{B|_OVw<@014Dg!>VK~D7_hDjhcbKx46{^ZFztgRBGvbT z^1?yweu35iKr{p4#gN~8nojWf(!S4UN$=_9X-Mv}x}E$AH=}r?D<3iNf**Rge8nH$ zGh`Z4%Dpd#&lK|4`nrVQx76zIcOzdaP7`u5Qf~dV0e9=Ay$y!@P4pQOHT*57N21zK zK^o$UDCt80bu*j)AXx%u;TecR0gS(nI~1*o8N1DpQ0UN`cPts<9Yt>b9t0C-kZT$d z|KoXv3v&S|i3uNP_Z(^Fw298xx$cGl2nODXSk zW(bJ^elQbBfFBJII(rGNQbulw8B=xWu!?m_d1%d)WTh#MH7ivgLs%Ta*7th8w$HoR zGF#%b*bLrmY$274laG6pff%%I4xc0b> zCxsI}FbshUwoJm{-TZ5>+Y1AIFVF|ar{f$tBoT=-efvT$3lqV7_&ByI9c&ScB^2Lm*h^1vhiL# z{F)5f4JaBTP>=x&=-+A-x}mzVwF7D%m|wp=yo<5rC*JZV0_xQj$4ULZsU%{M27wd; zr)EL#k;PMH)Y%tdKzHo6Fdau^mURg^XpxifVY!zb#xGU+i46@a0=;w&3e!42HFmu) zr)5iKPgH=}5F{Rg*6mO?3T{D;PdCP+VQN4ZTjM%L<0mh*M<}`OBnV zpe45%C)Zgk9vl5MHJq|E(b5JG@9lxPcqi_VT;&C7rDLZ zZ|ox$NUo9ml48d(5-c#!})){AW(i|XJF=7uo&CLg7{H8%bTWR+KcKi{?O7!#njfFXld)sYZ=KfUF z(8Rlo6HdV(w1jr*>k~i0NOd%{r`w@IVnq(ks?&WI_`^4zg7-AhS!un?mn6LFu^IOs zo1~K=>DG%?RKDB|eRJp0_MmtQUs_cM#UOb=GEG9d2B{=%;MSi8l+%Z z#uaV_q|p{72`30NdyWa9ny8_hg!>^2H$7HAnw-ac8P%eboxl$%$WYYTm}bH8Z2iwK z5a3)F=-`OltRt(alN&XC1`_-*0nI~Z(AJ*4$StU&B}VRr04&WeTCl(I4SBY;Dzra4)U!?_y{uJr4>3y<*bOg^B&YWm zzRD&_ez)|9iH6R+vt z|5GXUPY6=0;-MPobZTyPWRxB^$?Af8)@3moBwT-#K#gpc+|heJZW_@BOP%rZrBbU) z0Uf}TaF9xq|C)}GfZcgekkt|@dHeu5ZE$RyYtM8i$2g4ns>m`7-P>TH@-XxlFAw~v zCdhMfqx8@sTiZ@hc+=Zr4kX^cyS?Zp&Lk>x&n?elTXsg4O+ejG$txO##kJ=v-&;6Xki!~(in>AIc7mhp{8UoXj)IDk#kPCaageg?@}KAOG&{@;wxE`d6n?oNS+VesHQo4 z6irDBo;u3o_K{-pvT6POSCdVlVjDnlo~RP8kgPA{Z2nFVELSyWA<94RBLYv8Xfdw;O6go|kW@3@U);YcwGQW(qak1v`?7Li z#~gZxS3(w{!4InalH-OExlSpl6RUO>p}3tgXt&R{tvJq-i3C^%g*tbr-Zz|yjOclM zaq*l*VPwgL?PZ%Rd^d|VgcZWC8!Rk}@MZ@;po|RMh+m`f52hnKvvdi<&|W zkSW4ql?K%@7C6kzQFCJWe{dP7QAq;-5B5i|cpFRm=fjAXk(|>a!-eqv4{x=cY~bR9 zI@V*Kvkxg4&yM!D7wY?au87Q_+q>kYM2J$u_p^WKDTF4 z7attBxO6MrH+2?yT6=B{3&R#cG+lGPXGzc~>FdeoaCevkgsjC-nbAThNTMpXaqHEs zs0*v`&qr(^m5&hvTo#D;w^oSlZKN7Yj5C||?{*^*=C0Wycm?PqI*$Va$9358I*|s%m!YDcf)^g=h7RIjq)t2nK@-gz)LkK zvqVJrsW*R?^hQ;zJ&_a6MN(rIX7rt=`Ll=CE=QrEZ_8hRSWKYv85`J)({57`^1CHmMXVtcKc^ z7b1i_i2<(bEkUdkI|VyS*{fsvqjuCE0%}$a<3cH0KX`FP7~M^^PY$5Z3(ZnoK;g>B zhR73@EM({&#Dys8$gEQC5R0F}l}&B3%WNwq#>&6dQ@2a9x<*!YA@gAsG1^vEGVgD^ zvfW~BrVc$|DjzY1ea6;CqRNU)UzyTfmD{Y}dX1$U=IkK12}F^o=988|gg@OeuVdJ{ z$OK%Klxg9!E_Zo|%zcBOy_VSmhH_5_ic25OtLQY$;I8t$5^?9{7n3##z3lK0qw3D@0&PbV!f5JjFh!3D_Il;p1@7+421{;po^%`gxi!88W$xMI4i@@*INc_b zc^e(uLRgrrR#}#DOSThxa?5#6Bb)FocPBJ8d>E!^lpPLhjLj4MQt*QLR3rHmI^u2+-U#}xQ!1w+@iVjG#22vzuxW=oO6_4#lGw%R@jW_2X>lxz| zO|MKJP2Fkzog-89@jEU`M4C1#Ip7Fg-xXoRlLVz2j{4;Uj_e;F0;R?A4XFgHkwd&{qA{ELI5!7sJyfOcG>$4l&nL~{9hF*{*!~|e@Hz3 z<+t!ZD)IPN-Q)khNb#Q>CjR>(1tZ)4I+37J^Pdi%n?Dl?Xg4|1P`BVNg?Js1sTxS; zM+K(*;>g2lg;p6)4-Q_^Ka^i%khe^gY$xtZR;QJ4J1oXK%G9oKQjuC_3P!C&o)2~f6V7ePo{A&M zrj^_^e}ej%L||%AjP^5$VBXfwYVpBLC46pT)yym!FPF1Vb~}L3A2#gtbpnkfqi&v7 zNp&kdG!PWU&|{Bf?I~fo*w2OXX^F=ihBv5(dta|5k^qxdFhmEd)s&|*WRsB+&fg#K z)u;)oS>x=~U@J7xR=+5F9iR2au+mOlvh_JAe1Ydw2!eqps{g=|DPg|4-d7z+{-Lq` zxI)GG6a-Q|sLKKjcl;HP%zG8w5RC|CA~l{ZJ-M^6B&ia%T0ZT}1MBlInBq7Z+jbGb zA!j7Al;k4Jpt8jQb?a<-?cYY3JDehp4m8E$RtIC2$x4P;5Th(!5B=x+KJzT9jtm)N zT77WK^z~}VT^y+oVV800js}emQ>0dntfap8r<#4i{57+E=~VAxM;QT_d>-A1%q$^D zm)yGoD93E$U>!$T-txj~i^Tm^$XJmnYe!yqg>`Ot0eVwB5rJa;7a9jSU@}4UzBYx= zAX{W00d=^8ef7ZRKW`~rQvJp*nNW}~FtqbjOdg!oh0Mxb z?5o_ta*1pcRC01K+R)MZV$G0WzyBZh-Z5IXXG{Cswr$(CZJce}wr$&I+h^OhZQHhW z_Iv*K*8A4I)wim;d(^k?7@0Xn=2{~o=347R#Ekj;o@|@#ZIE^-PXp-5l%-V+1wF;F zVtRN2p0FtkmQcW7nF4g`J4C}t$k96!LI%ZW+eS+RzwW=wncUV#=SsW@*cz&H@BOkl zMW~`FDxkyCGN4yPmKt(EcYEoF-RkiKZdMCa$Yl^8Jp)37p7WqBL1-)R9uwbsX|@8` z1vM}UviEc5thLz$mdhk6V-~v-l?^Fs$#HmEz>tt+y zQoBU-SyXv0aX8JL-X@f3Q*hLiAr)0@(9~oe>#9vmXmZU6ia3Pg1%RE3WD=&FH+D=Q z_-RB5RVF>~;$l_={0^wAmgbTInyY$Y?}&Cul(tpE=wI)BNhM|Foc*qGI%Pum7Zt&GYM05%*S>uES*&JWZa=me$HK;LR@r$;78*e2c@Q1LP5;3 zjEf|NW*r`?O`}|7s$!A(C>Ir0Go2wLTm%%Lgwz}ak84i9FgqlVYk0r#DF|K= z$?b-d9Ur20V?w|Jn=}O0X@j23Y>;u549q2+X+P<(e=va^%Q@<;4Z zK~waggwG!KS}XCgHc6^Tw2--jiZsS4Lefzc%q{SvF%8Of2$y*Zmqc_&5+$-|m3vGh z6-8c3Y8Hl6UlT(IDP4GJ2s3DjG)O{6?4XDaQ}mokliY={68TE(qKt0HQ#oypt6W+v zp`GB**HtcLbXdsNP(soN$mr5(WcN$5VWlt#p3vAk6q4Z^aUGi0DR79H_>xW=>l@>} z<4FRkK})w3h%PSU-&)dI5CI-)8ozfmJ>!-jA$CxX4Z*5zg_dWnH!&%#K7rn5E_^>! z&uP8{9URJ6keHL#*BrOl0(()OJXbe6u`5UKxBVxcR6(uM%N5rUFAQDhFb3qv-Qm7me)o+xG z5)hjs@~=D~@~?{Ojui%~jzKsi^1oa30E*ihbU#N37@1|v2^@U=q5%q}XTwh_hR2X| zUEAp~mEcTwE0IU;SkqAO0~#(u zI0PBN@TtoOM{x#be*7!u!e>7s_+)|Lh)7X zg2WqBv_Gt}@Ydj>lG0qFx9L6>h3{Y8*H?ma*Eg1{sMOSE>qg0)J*^|PQ<-Ysj{uHr zVjOZ=mhDjZ#;*|Y`wGC6T(+UF7nmq;a60ERCX=)zo9V&E@o4Fsjes|;{G%<}2=*pt z9qF43)Ies-?~ku!`L(Sn@r#45D6O20jx)e~`htm@;j1S9sSeY?P2IE!#GM)Dmni3t zCNYnYCbA$2t3OXEE2gL>vnF{JVI?ypYCh|b=VIm@mxZiY!t$Soly$Xz)*T1Q9yU`p z=fHr6v+woGJOE`6Yo!eI%FDe2cdnRbOKr$DZM_@Gb>y}J`HfD+LAxAOwaG54!ZvLq zeC@fz&eG!5A02*ieL;Lmb|JLdZlp}Sg7>x-``QkvN(#R0LrzbnndLe6Pd&<<&<^GD znkX@Dsd1iESZ>ZTSDM#QnN@Aa>>|iP0dj@&LL{xGn&7I+z)k-;fTV4Y9Z$_vV})r= zIDuyPNz+0e)rV+B#ATcdK?mJsPlKye*~TXvMRwk6;Q}gj!*q`TG7jd@;iN41RR$Fx=s5Ubdj$SKWLY+ zSKVBOrU`H$29ynnw2^A?Tn&s4`f)GdyccDpY10E}(=S=IeF9AeXmqvkY$bsJL6q*m z96WpzjOz9ZO9Ej1ol~n9Ij3TTbUA$Z9z?l`#{q&z)UNI{R!k{f2>Ai~Apx`f6gPQD zwf$6~^w1v;0zbiwk)*Piyw|B&d8<*oVe$g_#-6q1#doT-qEd2-UqRKX_O2al?#4Qy z*-K=U54Ch4SKvz2U-a->BUf~CLUR42iu}6Y@HIDHF8OThg@Bc=u&G--E^Z$I_&dR~?PipNeoe4+WmW=HO%IVAL z45*D5tHQ3N;pxEx5|cG7`K4AdrKi(>~4ob;$eXK5*bgy%| zInFv9a7dXKY?`qzzu%@GD-SwKYvi6g1{Uz;Lk%vIzrOM1bADgIf6&AIGSZ}K@bf{) zMk&O3@#Fjnx0N^9`_ck#>V*Tc)5G<1Jy*Nl!EZ0u_#^9R-X^2x0!hV(!{Hv**68KNeiU*!yLTr^)Mn+_KUW9+=TO@$g~!MnOoHel8qG zIy0@?JyB5@^xbeZo56Yym#hcAp8dBb;lH07WeOwVBfq}!8jF#*q2AfrcEVO-b_D2B zi^;!MH}-G&<-ZStFY*_Jv@$(BeeZ#N62r(3xM`w)gblkXaZjqxW2KpPKS+-!>rqOl zCejRjtd51)iIG|{hPrugxFuIhl`#em2r=uOSFwJTf=5iU_mNtRhsgJv+P0^dIy0^gdAzxgDx25jW zx;f4b$~!nQzCBxQYZO5Rqo+-Kk?P3aeQvM69HUt~6LjDwv~Bg7k_&H;!?f9?N%wKC zt?_V9ir zwcf3|SgC$c_abP1`rXUDVAa8UQ?DAr*rf?p5rZr=*<@0FQnP?1Q6S=n1Ur8)>u|t+T1P6|5fGHsSuflq(x+kfvNO+O)U0(Tv5i!C7)w2H z6)}I=teJpjyK!dm5sGxUF6+(S__DP~o@=VhB9!x?PtJC`U4M9Sbgk8b=2}rg3lqfI zaLMufcY^exV2f?dK{j@+y0Q1Q1r&khM;`BE+5>1A>;JX`NxRub-6)c{&ACZQ9jc;k16* z)jFlg$6)r5sfXTeuFzcWc%Rl%1=V%ES>P>wMv-u#fuRy}DWaWW$H5nPyVWo%NbLfT}OU*%lGZ~N?h>ZYCbK~~~ z-57EAMDe?U^QnuhK(h}jjaBJ0Il5VnoRcUpD$rP0#-FH)j}mHdHD)|CG52l+*LQ2A z$H4F_I7qraAjzyEBw(BkPVIVp+U3dCH$b|)5k`E?fSV$whN#!6&G#`26qUQHYfe&} zVxHpDZcen?OAM0!L{+`}=tZF3=R_<BA(6y||uN3&wDpDr|?cw1)iJhgZ#$Gee2zf5zBOzcwL z{O()ifln6h667#JaVH|1;= zluYEOQ|gs5zaU3FfYMfeiCz?f|8rJ9NZ6?6Qjcq4-Dml1$}_ zvq70IY?c@cI|?*JN8uHD%M5g=@H<9%F;)C?mfWIsL=^ONtqj^)mG^JB+A}Q%yWrGt zAe;VYROric8%>S2b@C|C!7tfOIVwZnme6frUb|XJw$;aPOfA98CmJn0d1rj7guCU3 zw)icAqy95`qwk&)ZuW!;+EvaxFFqO}&^kwNm`VrJ>qHM$Q7NER=|DRn(nIB5pzg)3 zRqb}FPQqSI`eKAkLb2swE2QV_mqg3cn;`P)RcPssV5tNlGWl%>_UdJK=Zf4z@!iFN zcSgY_3G3g{mXr-$U-_BYR}k9~t7{G3%G z1=X)Lc^kh&>?D{cF!qS2~Y)pRhU z+Fhb$ecv7r#~?R!a>^91KrXht-6A)Nn?v`nuZG5=kf%PfF&drS4hdXU9Y3%)42y+r z1SSiBxlzh1lLd(lCu8+76XQb@7#T}m}e)>Z61O` z_5_@Tz{GWYBT!pcyEAi2Wc|i6&>tz1LMCe}IONMvep133u5gZXRATBQ7~y&ls?ZZ3 zrsj1!}bTiHi z=p+&dNa-s;SOMZ*kaz=P+$u1Tu4?nt0Ia1#cNj>z$EEqIZ{Klyn>6 zV{+OE%ElSt6GAe*3t})b?lQInIRS8a7D(PQ?NIp|2i)=7-)ci*ZTDz`2i$ zO!itDz|H(s{+Vq-o75`65n|df zsQ9w_t&N%Qu*;KSYW3o*`#=~4QRjiec6>(4pR%ukKTLl`HKnz0KRqdxtRBHyXM)`D zO+zXS^;%ESUfg8GxN;|U3asTRl4`iGY@-!ryY4#CkW(R31;17)9YV229b>OeuTQF` zRfT;Jd-Lhal@zLiK$>6XEAdjDE{YhywN?laBOQxrmZ!uEYrl0!sotR?Q&Gt)bu zVp?uXF`9fSRH$uAE#5tbPS%ZkH4_(b8DvJqM>2^S786$n%oW;>(=1ATS&|0XI!q9! zq2ztV$T52NcDxJD2#_Sy=g9!G%|D-hk}{is&kRq{Gv+nx@6;L1eQ60rdUp9E0~7G~ zh_4Zv`49EWhEput2=|hR@!=$yci1y0#d}7e-cV)OdL(f;)*^{02e)@fiYgz5;F|lV zYX#oO69V-Gx?~kgC6GC%P6}slv;0ymJ4Ha&)J%pw^yGF8az~&)G4#-3xJ0Y{ZU1d%p7FY z3*aQv3_{Q_Z2jooF*aJc{HXsus4X$qJ|Z%Ro@M zYJNNCciv>6^*xXjiY*$iEwM-+o5iz4_>pdEu=;9biy-7c9uY)ZArEzMc|rw;BabqE zewRv%(eaMJVVqB6o`?ad9li7u8Q6u3Wo%elody&&Xbs%hd%SYPES3iT%?2GPoCDfP zMije4p_&mzLm-XEmpUkAj0XegSXI^0+9G#`NewojA5EC!q`x~1XlMM}%Hx-}q0M~3 za+U|>C~DByOC0NMO`e$>^(al24VWRLbv2qrWU)Ulbo}enrMP9J?Tp;|uk}pxqO)v& z4)U2~$szplFj8d!?=lL4Mc2WV3>EVSeXgdJ1won-60}7tl>`p)wLT6?yPyUKVJtkv z+2Z>F#;8!}XF5>x5%Qye=W|d6CsO3Y{wbr|;fm|wbm!adz9+a7BICG$DUm|f;;mz; zu1X2JJ2fB8lpMp}1CtVDxAV%=c>?@!)S=O>a%p7hVXF2iHe=?@fETnPToTodW$kPl zKzd$+B19(%oj4VzLJr4$C7S&3k_RV|(>FMU*P1uEuO?I{?A!>(y22mXn4yck!KqWr zhgu{C`kC^HwVjqlmBGdFLc?orLtMWC_&6sRSoPm0LC!3VgYWM032HFFxPfNcM^cIn zup#@5j0Xy$pHbbQprAe}hsC7^xF|+)sZb`K|FTojY2VhaB2U=3_u6| zOdl3sc|jW*A^IWLW{J&wS#%b1plF0zbt3P#zCwvoYmcRX1ZRq*afhVL4U$43v5=mDsec~W}<$biMwFL zgu?Cl1BGNx!IHk?XAo>lHg0up&O__F}1T;N7Zxe5m@a3me4nMmrj zFV!bmKuQB(N~bg&KX1fEKxkhQM)G(^MR}G=&+1q=jK+q6+W^)V0PXm1v+}v-541Ru za?VJyIj};al))fSe6h+HEPnYEETm=;P@IHz`>^^is=)ow2ykZK!Bb1dh1xgKlHbF} zguJKL4O3@$LlG3Piz?=yvX~SJ2;&RcvH8HGoWUIN0f>rXA2Kxh-a7b!S|Zl;W77V+ z+)%pyZap5$($|(&VW2m|ac-+2g{=-30VebmJW%r`IfuD?Zfln9L(87twV4KL{&lVB z#PkI?NvMmN%CF=dNhyn+)98}>5D4eSA7{uMC+%a9s4I-4jFe4Q4J8LK&dU(&eVaF? zXi$6frv!IUjW_9#b9b8Uv&}RY@>B;D9p>XLaYF*C1tJ^Nxmg%MCZK6cG1BuVj{Z)j z^bx-4ie0CL79^Jp=pW*x3Vt5>3^A$LSQ%o{L0l{&uNc*u7vl4O?pY8Ndjju|Xm7^A zKvtlbyrb$h$(#*=L2G}XKsSDsaSx+mHW~O9w+-9ICWla4KBD8kDaZnv8GtFH5 z&{huw10=iQ=E$BkFL*fm*BgojW^j!pBWXa7WF|8BwEaTD5XoU|sRKV=d_#H~!C-HJ zXtlsq0YUXoC@tHUyA(cMqiZFg{@JhSu&%xH2~^auEz1{zxpVTuDQWRIRU%5B7Q!Dv z3lN!>JQI5mm#=5wE-cw;ZW0c}ZK?VBmk_YH;`~1M4 z0g3Wfp>7UrpCIFcun?LWIkO&YJC(!r9#o?ZY_h;nd1%reqpeth&k~(U_m2K!5{IO` zJ(Kk8oc{Jn6%h=EUCAz>%Lj=ExsevuQ*#?otEs1<0vN47bYZ#-PHPdAZ3EQHeUlYr zQMu>3bkNgQ=oFW!6b(T}mXpb-M9c16n9K20&Om8b8>cOwjPCpc1z=?ny^>yr!?EH{ z4)j{&;nqs_?}dH7;1E&=Nz!N+#wuKwZVz%~&%tdkZ!1y*owaSNmUZA?7fI)ito z``);uKln7nW1jCdy}o3TVQ!9_yr zOykTwGx?j*QGI?gb)XGr&_~8d6j~T*uS?k>!@MbhlXWEg;H?4YeG2|`NcWL`ArX`2 zCA`!Cjzo2uF8d;RA|(u?(HnJQ2PN;lieSCoBV7>)_JS19jq9t+6=$ntpcUHuP#)5P zGRb%=Kx6(nr1~d13=S{^F3DZ&$8t?;{mg~fTpb2tCOJjx>lKQ@E}^OW>{=V%CG2fW zyKX+-&l)pN`)xrfa?8|seMVK)V3xINO5l0nqr4r0x7#H{ z$yk_0ep?2(i89{mgnofNBy05M(ur(J9}Pig0;6j#7nIPPu{Qpq#tidj_tA8|?YHbsdu*?DW9^PyV)SdqbD3W*wN2=&1MdwU;(@u;cy z6>svNuYX=~VfY!xy>W*5IFE%iD@vcO+O)UC=9?~K-pSp)aYs)deQ`#1D+S+SkYOts zc#5m!_#F_I5fV5zaJjd%m<+IHEeEVqh2nD&uK|p{fG*b+XKo;(G*7)Up`N?@%mU@` zzO0pv8rCMccY}oOWRsS|skfAz)a79kXw|7gjN7mSW$Yukfte)K(bUsQ*=H>g{j*Co z&A;&gVm7_faCl=Y#Mpy#&IOOScZq)-LLe2wUUOlT{Ki}e_QGi|$LCWgruWm7 z-1BxG%J_4^mO;#KnqMb1l`a-$pF>t1i;s+)yu(jrEj+_sp?FzH^v7~3AE~)DVNY>m z^{o7C!#?BgO-kRZd9B$;>3q+Jhu;9iY3xD&DvkeNGfMvh#D$sTzlOLlEBs#|F31EM z5QEJPzz_@oPI+LR|7r;Tz>)bsI|)pGr?dXg6!iSlPQu?wum84_@OQZEKh^mB*E)bvnrVI-#h9}1OZ&~Xd|07&pa1Sh}i5xSJ26Moaf*U-BT z?mM5PWzSwb?f?wV)X<~BzqnoV!ULe1*7?;Fzhe|87`W4-{_yi%x}vqA&#uew&^+HhH8*@QZTmw%2vXac`T-PAJ za!EHa@Wk}YFHG{j13cpKTcaFYGG;9T;NvqU0a!>vh#t4*Y_nsdgv; z^u5EG*I8Bb)|;c+lMvO4k9pLpznaUai4T_9P0{$mU)a}&3xkXToACCJmHEH0ukI|K z^yjznsAbL?o`c}J7e_lU-|dAzZ?awWnLot2YZyv?rQ1YT{%Du-W}Hm`OdSpuIuX@X zvUvCrpo7(jwh}YpP+~+LMR^LFoz32D;E@9e3q} zS+t;esw)niNbp{R{nfyR=imbm^ei=$j$qthi`XOHSWUeG@9urdOH(-PNR3t{yM2M~w zZX$I|dMSgRKCMeVN*2i2?Rz{6nV_LjM@yGpzsBrkiNqsbw9QIgcOUTeodbrZRR(3g=&YGrA+cf}qq`;Gu27VV7gizF4 z%0f$amUw`f{_HFK$~N1@BI81YwO&VfL9ew(Q2hdGJ{kHr$WB7-HK(4XQtJINE|E~I zjAw8G<)+H8Ivon7GPio)&yi2b1urWk{HcIh7A$)2a7zLSj33T?Ys35#bx#~C;Ril? zAD(b5KT-zgpy(R(l26c7L8gF;nWO&UOwGoDh9GCJoYxi%M#jr2jc1JHYT2Yr{s0qF znPsaJtI}oBF%YRG*=Z0C9^0lOBAj%8FL(}0PK44cE@h*+663n}&qNUNnEO@flYFEQ zZV23MVV>XEFfx2KTY2{fOAf9nDar+fZKvv$pgFciG%P6Wkr9Z(Daf|m6%UYM>bN1l zLZvHX_2E_7h02$v=D;~CYppR1c7f%gW(FxgV=JdA)b|p(ehgH6Om&o4v|Fu&VILn+ zvJxa?RWflK16RzW@~v=`TvkiMF@w$z=JRbbt!8lSbS2hPDzj=Ex`KEybRbGi*~apX z<`eaJG2RA{hnVf7_==l?M@V2CWE)IgBPR9E$A>T}7(=s9UK9=&?)#)AIT$HYz52=| z82j@m3b9^v>EgfsDwgTL@N)nQ(Kf`!{t>Xj@V5?xLA+}75v6R*|8zje(__H&zdK-O zGd@^7^jOju4#q=6-k&VCRny*gl3;6kSs?MmvtYx(N4Fqz(en8!$T-9u)Y5FPg77kv zSqh?JdPh>+4qIu4SDf5ukI6Hi71XjkFBoCoI?d-zTPGzXa~yMMlvqlqUs|oyWbH3g z&38cFP5bs&2XOd0O}HVZ0yo|wW7@GqM$DPeq4;wVkN_Z_5dg#}U;&&SNx~p)bDWH8 zi?QKAg<{nFAF$#GdHQJ^@oVyyZw`y9CA-F`0-rnVN_KY;ngmZ{*%2iO2f+ zU9Cy3;B_dVb)6WT%a!Ys2ksP8jyC~(vhaMI`}V|x8QAuNrL%~GX)t?5UA%faHbIBS z{X>KRHTqsg48{$hc9i@0%#;n3=sWpxjFl;Q@SY4QUEnE$Wn?=9MGWeRMMqOfIer97 z&_>fclK;3#&^Ckh)^ICjQ`4;U{d0L|jvn`Nh|5(@2L5jQQnCt7au5tN)r> zajaR*zm!UCnS)n9H5T+7j-XKJWTe#8B#wAa`I2MTLzmhOFJ>O1)n+r>$I$1!$`}o~ z9b4n#yz#79mFR)mV}c#y-R>viYR&?($6FS&#)t(E&i>@GUdjh|C6LcjO*jj79NjYn z<_ic78_A|yO{sb+7Zys`iGN(xwx}=qHjqin@J*zM^liBJ{S*c zRn#TIlFOSb6DL^zU_#bx!$&GBJZ)~$%JZ<(>O+*Gc;g!9kXiDS4Q7?CHaQ3(gO^W|u&&ae`ec`ExIGOox4u%6yb}GNhePi&+`96I)(X+3qLZ?~iJSy@H`q zoLLt9tmWmGFNxW#_Bsv?w^SX{fJn6{og+_XoRUvU{F274kv?71WSWA&`JiCjoh2wR z(G&{IDIKQ!Ie?b}&EX=#-nG@Y#Vy1Hab%(tShdn@`H!mb(Gk-&H5+}%u;rR9%aYW2 zPeN~s_d%E*w(G;1rDO(hs;(+lB1P zgY>bC-b3I3pmX@NVFU!M$G}r1h;)>$9o2rFZ9M{{_?aq+-|A?z&)a|}e$aw zAo4)Gbtf4Z#aJ-W&4Fcy%8ji6%ND(*937h%8cFTVJUbM5f zDl*<;>tVEM$L|SlFja9!n+jMq*QM6&_WMcMvAv=ik-!Ltl@Sd+vNtZbx)iz3L`d_W zdXAEW$cqS^i&6(SRFy|9D@al-2e9SuSM8Of3T@2F^KkICPH_dEZWoG^AITb7V}(vO z50=;+IGO_9l9SwiLX>NH^Oa_K$uY@B7eCl`Q@Z0dlIqvK-Nv6CCfBpPZZK_RLldHHMj#FC|5EH04$C_mf{uj1!Nw7Ir|oIU z&;hBrQ28t`xa|5a%4L(wqi%qY4xTT~DL=}n-+U?YaGDh{8`c7E+3OBTUXY3Cjm^t# zDP@DfY*MG{8Fe!6v5QGMX|-NbZ?wKfy`7oSezh27t)k;gI8b4gz^Zo%yE_CMJT3$^ zH&8J;Mn-?nDVD-B9QU;)vx+BS6kXENjmqxIlSRoC$oP39olK>3wY(Ksn)mTL4j8XR zbI(X;&Y6;tuPIM!8kWj<=Aqo~oX3uUDlOkyg_b z&39XJd61Fe30C~=IG#VnX9pp1bm@#3_p%8RbMW1DO5>K8Ce3+Ep;s`TOyi}Gyb=lm z8Jr%{FEN?vYlb?$2;`n^Jp{NSBuZibZ zz>&TBN+S%pouQv>i-fJ?2SN@-XoKR-+V}n4?xjwLPebJHl{S{<6K& zuSPC;F>v=*S)-+-wNc~Lok$Wr=8Garn?LU!V>PVWH}il7uRc(8k`a(eiLE{r)D8xC zRMM4vxQ#&-C{rp4WG~(6mP7!T#OQwznI%>ceskX?j0`*#A!Cg|<8PNe(o_``dlp_7V&ch=w-V*UUt712h|2ytRziW7KMLun1<$}*%r zaSj zJS->Lv;wjG{Zc@dczPxLGifuP7ghTi5BunT-t(5|aLdR_`tAC}BxiqJo~)M+^zJ86 z^7hgVd~$PwA@vm&ENZ{uF?8U&1}WbQGnG`LJU63sbUn$RiL=5h?rVmm8b@ZKo8VxQ6gC3Ja%+Jk^s5we!_$+6F0mbph{tzgU{m zDSM`H9T{7Svu?1C0j-XwJXA@Pv#g{kd8=rl6@*CDdd8q4`%(qjor_J;xJRbZv}&tT zm9R+)NZx|e(aSWDpk_oUKH;np%u|V@jf1$Lwl=W*lKKciyQ`r@V5JvHJIky3B9<=> z#Oaca2Docf!0gZ(*~TOx7AhE|i#@~937@=Rie5ZlW2#jxP#XGO0HAiJ)aB3fW-h^k z$?XRsea0DunXQLVHEDvmrbwZy`d8XHBpY5gf6-piQoTruK6Ch8S@J-r!xybpU9hVf zg;R~AYB_|Hje%D)GKukK*=itk%V}}z-1G*zjU<7P?iLTM&~|rNx^9E`toT=9PJ2xP zs#VG-T9O^6uq;%4cobsjyu(>wZ9^$QY4yjrW{ zHVv&bpQ=OlZ@t&pXa#XKos#dYqNORpj`|sVBpdq%Mc}g{i<>DO3edQ8z}H1Bj?nWV z82yZq1@+ayNI=c+bH`D>Ri(~$omoN8L#0LYQuBYdKJh!r3jFd3;c zw%Au5nl?x+&4@5tU~&~r**Vlp{-yni?LAHi8wi3W!p|35qg0gV??Ja-XhduuY_ zNr#2@yL5PLDU{VLD-C;P;+CCf@G7a|cwt~_WCn-Fc(9oHK5S&E(CC7iWgQ$s=51xKZMv3X59 zusPI_Pe%-|hZisFwsZH%G!v*a&gnMQgz<;$&-Gu=Dy5#q84WhMdVW7*5W9V_GGW*# z*6p~rsrQm?;QQ^5x-2x*6&Q!La>}OcJUpqxTMQj8OFj0&1k%lLxY&RrLMH_Nz>l9b zTV_ISFj?#S0EKb85dCvw#483`4$1XM% zo4-$C%pny5#0y_&VBHk`h2$#5FM6%kzMgI?Vi=m)=l!Q~a%{Utcty`MMs7ulC6m|( zcs2p8lCzFI@I1y{j8RXEg*x4n)YgVQocmyMhGl5^=pOEvH|)2(f|PYpsq9!!25nko2?dCeyY`uqE|8T4_@7{r9p*g@TOw*u{PZ{I73%Z4iiT!! zIJFd z4>>Dl>FqAu6-Y+tLxJU4=}ZqZj0x zEFaCgMOi!}Jgrg_I@pWr0AAxR&zRyxbq5D5xpT<{^RVZ+;>}?$uoQR=*qnSdZrkqc^RAcZf&_4W-2AMF&Wla+!6$$ zFHv&gdhRNMkc8#-CVB3nYWHHYrsot=3X3GSFE;;{60g1!6FW?jU>~I7^mEix^v)-% zje-UMoh)buuJ}qT0Rv|P= zW`UE_)0^!cK5s#ygC&HFbfmfeXUky8Z-%y@tTR#$6F@#4&ZHDuEep-mJ;Z!8Ngvx^ z0r*MBzuh6~=my85%sb~Fm(RxB=^OaS=368^ptZ8;B_i${*D-8Lb3=E>+UD7m5Zp7# z_-Ut1wc0x-Nd~ba`&po>zJ#+Rv2@z(C$xC0ik%WQPdrj`x$!2KD`?6xb)rlY&^bmy zcrn7kAC=c0C?@r1sGv|l*(;R_p}xD2@ra1SUFXFFSj*Z-o#8Z`VOX0~wv?kaQMH2U z-W`Co_iP{MLk#jYmd{8WWk;OgE9=nZQS_#9`*%rP&({NC{7xmZcN#J>B8|SJm?FR` zJ;{{$#0eVYKXnAm=U2)|LEh$OIBP7#!Aa0+O@wHeTM}N#!-%2p@7LI%$mQublUcNp zHN$#0IQz5)6%IXL0z)3(ZASJE^})U4`i1gkNaSZIh|`n3w8|&Y;>v z>VRLt2RS3U9)YDYsH*wp9kQE`sOZ+9dUk2G;ecvn5BvC%IUg{a+6k1ljA+fj3M1za zX!;w6gEpg;pl#kpG4m;hd#PBBUa@R=$c`cqcG#3O8N!s&`~C8irosn6FF@tM(&$Wf7G zB?Yhg*AohE_yj;Vbwn7QZiStB6$G zcuBn*hm6l)*SDX=k;P9APrA#2*+(?s(D*>?{(gB(6l8J1vkPjJQK*TQD!#1xMpO@e(sl7>N`QDUmTHm`bFi^<;L zvm7I3$y9Jy2ODy`W7VxDu~F~ARbIy!ZZ}}LMMc=WS>~=Rx#tK0hF~S&O&>5NDfoc> z^^o$L;*UL*hgbQ~Q~^=y0XJ0NpBFm7pLOiY;-7?tG|#=WjuFVZ!*SyxiLEt z*F#*f?n0sFvW8bcS#>DcgSvOBAyxYq4wYB)g`$l*$x0=n089cBgiIU@q$A>1?zboQ z`TkLs8_j6&WGh-bmMm}dbiQ}Xcu zzg*t7ubPbyft8J*8lhBAi~~zvU-Y$V zsiw*Ch7|7zc1l+0a*|$Q265p%xP!Y)$mE|6;4$^RBeZAg8As&qgk4bz z4lBiaY3+J3fj`Be8~ysOANd|Ofxky#b;4>egh`RCu}V}Xd!)frPX@wQ%~o?&_!0Dr z7u?ly@8oQ;gNYtK!CR*@xwan_w@1G#QGX9{>G};4|WuEw6y333KJijUr5zE=U08b3V35i4< zU}6N(ANwMy&VR6Dq@7f330;dtq*CEdPL}eKJd_cLZ9RU?#Wp2wY&<~pav)bwI zAmWF0%$2M2dr}Dk`mXLWW2i`@;p$v5stp!a>Auz;hz}7O`FI=4d~agimYIglf9tT- zB)YBNXItgo{4Shihm38Hh>@yj%S)7Md?N(>dA!F8g&4AO6g5+E%}K%)cVm??!hLz_ zi>`l@1Ws9CqnMl0b-!E{us(Ul*|-yQ5ng`tO_c`4p&@uufZIH zvryRY=Z_8l-SjaJ&)j9P?{_31%`M8s*hT)wbNBwrqdets=x$-0<#}t7g4h;?Ft(Lq z`7-)};*5!Y9Zac%#sn(;K=lEc{RT9>F*6^DyXDA;Y?z~f5 zPwi2dx<4BRc9Ii(T$oHggvE3@~I%BX{!PR)U~41D+CBVMP}Xh5HCTa3Hb(=v8R|5rr$g$o9KI#z-tj&s&dkC3sB zGo3fsDXQ*;4Y;@4yhdlQP0_gA(bWt*`;M)y?XC)OqeEBS)RLIH!Tij`>q4Mop9PX{ zX!qO7+wsiQ)3FJ05eC19b0VuSK4&z48x*9|4o`bPO1~ydi7QWaQK#$KiOHu$GX9Ba z8SI5O2sGnu4_x~EVvL#@_SJy3s_aHQ(^qFSf0gn50AT^eJ}w>xcotQyk^H@%_S&Ji4!ed2K;#CLg)YP? zR=PIq^nB~-x~In{F;>4@_omdOA9y~9CXEd6;*RSKa!zhOBwKd(CU!!jUcWAu{O|iF z11K#&Svb8Xzm8rdS01t>Qk2!Xlz#;u4ZlO3Es#YU&!AM#d(lX66=_PR=f_ZtfnQLBS!RVc`*xiAl*RscGpM znFWPK#U-U><-h718k?G1THD(D2L^|RM@GlS=NA^2mRDBS*7x=g4v&scPS4Ko?jIhX zo?l+y-v5dV5CHh^Vg331mvJHfi31Q-PTuebn#-2Mt25d@Tw5e!LC5!}E5nTRO> z0!1hxzpf9GnEA&os-fc?6dDQ39_ig*q5Ung|9gQ2{=bUs{{;5$ajgTu00aKHdBBJO z`~Wv)1(69MD2f80|Nr~{yVn3Uu42mLtFUxkQ^zOk3eWWTe&A~sV)r+TpV|30z$5lI zz?jH402YX~qWU+$+I!Cz*f+ra|Dx_a!=mW2wc#QN2q=P}fM6p*l9&jR8$^P=`AO5;{n7gxh;5(9Ags^!zC-MOCbBLxFy~Q=vCGC+mxCm-FlUx38vO z!a5j#-9FqyB^j5qX(UG8YoHJA5MW>!MsvgaA2}2P)kD^dI(L1Od6>f zMN)(QT^nt-AHp}V8x-j91}?ODm7dgqoQF@%tAvOCde;Agddo?~kiz88kt={e>~X>8 zhik$byhq?6AQIGNLrd5UX2wm^&HmMr!Ow!m3Mks^u+*ye-WnG@3iQrs)RaE!(sahH zL00)&W+V6qGo@#Vbi+Q_S@TtNOFxo)uMmEGdGP5gb`zuODzK4GKJ|^gg9}}craK&P zhq)hGI=Xw?zN!##xV<3y{?l?xM%VbfjY;UI&Z)QZMsj7BPKenk-x-r#Zbsl_Tn*Nk zUfs1T!rWghJAc)7ysByR!7K9t)2^w;KUo{CegAB2_Ex$LMI}10mzfIhpvYKpM1<3d z))&P&6k`J-#y;zgy8@LGyS_Q3ug?B|>p}IKz}EP8|Gs+VBG+#drBki$nz@dpEki`! zX1bJ)0>R3DyMqseLkHB4`xUvBbvCklG_i?vN%3-MKqS#Tcg9QIf@ksz8)Wsk-eo3j zRK9GV?YPpIZDl@pz~W_Clh&Xu{XOh?muq)_SRS90U^~MVzQPYNe!9lBe}Ddc2$Q&03hPgIb;lY+y`4e^`NxNZ2Z;;_!4dBjJ=Ix__- z+^)mjG(kQ=PH|Bnt5vkQ%1y9T%p$3w&_6nWy*pJ!fdb)|sY9@`5ONd_`w&Ed5OPYB z^+1x5WG{WG$&vB3baObL;$1P)my}zqQz;YWy`21DpXIy?KWwhZBKekB0KN77FTqkewW+TdkI5$#U?EtKe>LLn@Edoph1& zM)!LNrACyR1hVUEU8WLFPG_#@*UqtMG7dLWMzfO{#Y|P)>LfglV1@x^oOncB&ZIYc4f5Rab?0N!- zU$95#ueig-IuvUD6?;eVi~<3DopDv6 z{}W&X_8F%74cIv0(ydU^HI{SlygV+wd9)*6ptVImZ(;NYU^$%{Dgyn3gF5ABFA9Z4 z;$)dMU504UGlE995}k6#masiWU(c{#Yb*O&wi9^}%y-Gj)zMAh{!%A$n(QDXnW`n?vsvv;ZtEp?+@P!F$McTC{oW;~MbbVu4Qy zm0|bj+$WGYt%h4MN=;(YQqgzM;Ey_Nm0pf05ypNeLpRyhsv?$ID!z2L6~WIaYg9Z4+%&tv*A z^B2mg&Hvr_>>8l|<)fG+PJ#G03P~&!NX>a5AI%7mTCEEOq5;-mFz5(SI2uNg)WAPI z&U@_5$kg&Yh*fbqEq3`#I@K&U1-e-5afV^j4jIj8JGU>$Kz2|z=Onu441TJ3vW$FS zSF0-br~|)&Tw$3v=+R!k+Ttg|w7rG~)TN40Hs-JzIUSiof#!S4*b{a4ZU~_-fiVSX zOLw&&)uIlsW4f`k20fr{j*aN%K1+5skEx*+$8IpAYl2A;=nNfQ@3AANviV;zxd+Q^ z=sE7FXsfduQ?V+yK=x(ignS4LJt-8AE@dEvY#Wsw_&Gy? zN+03@%8GrmK&7wUwt_itfp6Z(aXwjLwUo7vBs&YzmT|O`{8}{iBnh_-x=s(LA01~O ztS(~e3ym0#tq6Nvqv3qK%P^!0U76Lv@)MaMuf#ug_xViO#MoHk1WPI&5kt*BZ+=%$q9qbTn8*Og{ea6k zl^)mpQkT0YU;ci~ zxS8H#-y;~UUx#U}c`kh=>zE2>Ga}pq{y>4U3vz(9LXe#mkre0*l1PE#h#;UiLxGCw z=EQT+-!&wgDvBLzXR%gMq=#A{(1{p{V{Qb&@$qyLhGqY7G zP!dsy~oZM#^ZQ;xO)%CzreRP@krPIQ&vhwSm z)#RW==Y-^T;ltp?y3yO)7;+yl5{}hD81iEZq;F|RfvAzho=>H^xj1r84mN(jo4oCK z_h|W?ICgt0k^*_Tk*YF;(`Y3B{7thp_&Oy$TEXR{T)7=h#puOF)Nhl~{p{s&_su{= zAOeVe<|);93N&D~!O@Fc5dg1#DdfUuR&a56zQ&&B6r#z9`eC-VxU7Iy z3A&pivk+au8(PfmzX(U#FQZzArf^2iyfoOKlM{A^^YBq%aL}8F$?D!H5(9WelfV+RVGN#sBrQ(`scZDQ|8BBCYCny9Ru+FD@Ptx0`fd zmYYbRy%H?){i*d+YK@1CY02!wztIkKx;>hgk_s1J5SVY@K7fa}kEYdS<1To6nV#pm zV$0eQYCy#)z}M#%_sVHWYJKa*u^;WEb+?Bra=?m6&HMsMZMM;{H5!EXr|=-WU!g#x zk6=1st67WRq3bRfRlf~q`^jTTca02y+wa)?MvOKXM(4QK!)5Ga^WSR65!veYB3(uVSUTD5_d>&<3rMCZ(eQatu z1=35~sXH~=K0EnXN*yoe=r7wYg zbVmcdFFb+PvGbQ$^*4Fr!2F;!I$Vk+5kTE z#taCE^%`~ttlGwj9kSK#n~?#JC{XypTb-vsxXg#b=fka5{eO)w)Ng+js;g8B(3F;t z?m2t*^&{&SG2JTisUdMOwH7ohoUm`|;V;#a-b3yEwTBuG98X37<|?O8%QKp%=jQ{< zX812fFTX?(GzwRg4F*SiDw1>%>NkPLb>xopwwXjqb<6ZveT*KU8txiCA9rX?jqkHo z2CAd)=#yrHSN?5z!UO0#+!0~u=@jB7$&uAl;&{)KIQ>0*bFs;*8)(DDuF}p!QVgLS znh;f>Xpi0>flKaTbLY32Q@vlx`nNhf;5G$JUty;T`%U)*2N%B=2S%FCeo72Rj2aH3 z#UgB`=gVj0EiQCb^uE(4x@Gj;K-iwUIM2SB{D~(dd4qlcpN&7hqyDy{9j=}_Z-%Zs z99S2OG^cg`AB*VChi8g5=yD&v^2HP(w`cNfZLPB#Vv8y_#EAr#D@H!(<9o7!d|&df zCySW}?>9HuK+n+QbMme%fb}w_qMf#lsw)9jWL9s`q3z12_Sn60%9R4d-W(e&Apo61tJlssFfMoUTMk9=2KIt71`2$z)og*M)%z2m@)wtvK8y&h9(v_soIRH+{ zgR&h6_p6ZA!(_28U;$Te(Tow}sMGn9PCrciycpP51W`-a8Gon#hJdWhlo{TM=1whuX7eO5qny7B1ecF55ZJLU3{YMABO) z*au2w=l{St5k5u}B*@=hq>$CcUCf;+Q0v4AfA%G0WU~EZ8BMLI*BXqWXRjnunN1r$ zcRP`v75^H;PtYb*AR|+}W>4Chd5c~cx@vs!LpiCU%JK&x5L})aA$vw~^ zLnzRcFmOU^01koR5Cn;BD7bDCjwx1o@XLvR;2fjHVAtbECj#R0VtCFl#Kg%lH`Yn& zi&O}$Q^h)XSE85M(B`jS^0=@&KmCwhpVj@qS@bk;U4VGQNs~(t>s#oEm}TySs!p%Y zqN=NcyGF7q{i6!b4hZws=+X8V&_puKI63|YtNpJKhX3lA?e7TEy3+0EyEL)6(-g=K z$JpMdAC5`lUV8qm&+cdqN?@%euUISk!gCEZfxyq29*zfyAgS?0MS#{;kHd5+Q29aZ zUqoD7L7z~FZ=pc5CCG_zn7`CTMqm?s0)zg{pynhEJaoNcf*ST>=mJ)e6ZoxN-kj<; zcP5T#pg`-p#2f*gaZ``)mlOY5!)js z>hL@r7so9$f!h^5|BV7A*=|Sa239k&d|M7wL^B75!PbvE(H0?w$+dM6O$<7szCy@7umKauHp^k2UT$Vcj{W z!!vWuTcYk_^v!tnsxKIwX}YT-`5BFYaDDI%ylcFjEA?Ce!MNe(7Sjle$$bn)-PSSXWY2%eE2;s^5Nb#fl887eMqb~6rv#qru)7-{(4ErJO#+GnpkGb5> z^3dVdJN)ivmLa|^cbsyo-eE~y_Y=B%+GIz#6RJ>ZuBS!%2=L2b z*rxQ4y)VtL*hIy}oJfwsXQy}PXGFd& z_gPx}WdBqf86noo&Kz`e(cmE4(D~wn&x0TXe@|2}gKPgyR!ue{e<1SW^HACgn;qI> zpI4f?PL13GgGfz=N=Ky|=`Dx1(Mv?Ulp>07@f0=6-%OB-LRQZ)WJE|krM?jQL|!b6 z(Vv})TaDdOUqJo5wpcDCH?JAR5;ftgPmpbnD|Kzo6uT($m+BEO>e$f#h_3&uHueAS zc`m6fk9pNZzdty;4@Ba2ocq0YawIfK>pLKF923s^uI{9-!ZlRpxP9hZo08faL@Ql# zagQ{w##e<`eipV7m%e|JWIL@jb9fLWP(IYHoie9D^?(YKNxsnZl{o$^Z&^YiP=+Rdi=hATi9mt=drtIUKp0Td(MB=|dLMluPRC`y zFxzN9bXun>vxzzHnDUP!GjJ-F`tM9@WjAd}QSFZF;h*Dj?s7{_l?`T;cPzRRR&}}f=paVC z2)L+E2R%kA1Z2O8Ff(z`+In-%nteW#>zl>p#LTzjd!v}}P=_%no2%K3w`1o!sIV7a zmnv{sAQ8Exz^(bx1*xg{9DX8@p;th^i+hAwveS$4v^|{2?G5n+jijzS(vF#FZt6EW!n$)_f^q)SdYOICFN8C- z%!SIA@K9ZW55~%LxQ?3|%+}m`*h0YQ8{~^-J69Z^*vnrg7WHws;Ae8IK-B~lKEL*4 zC(GmHw@(@~Lo1-F>0<(gaORMGHwT10DgyrwNFA0L@6g z2MweaQ=kg;90#B~0SkH!vp7b4?2O$8;H*D+U#K`@=MJ1=o&^I2e`DtV;I+R|t~T4= zwrlR`&$(`_7feK%7>fdni!k!<~C^r_qV-G2u}ZUtOTxk97k-yZ2hzcdR{_yIbU)!!UBaHEwk4Ai5)jL z;>%k_TMhsLZ);m6?f0`p%#{uVF*%P`7)0Zhfz>e&^t3%vNHjwbI79ET;Qau9t6M?< zgcEmk#*EeO?XTyPHG_TNh5ff@KZBYM4s3RgT@_9ArYQ|DQyT{MFW#M+Z;?K#xQTr4 z*1XY<$1#3=M`)b6rdD4gx#bDj*dQR~F9kcq|iA`DfoZNy}fQ@KH5r1Nd40%QZ za(UXjiW3RI<3DrnH1aNY= z$4@|0DBfy3QIzQF>|{9*yHH?}8Y;@pzMB?ru`^3GJE&lh>9nD#5&fkLHx{8fyCH3| z<)%xXKb)N!`uqV9SUN7FOHn*a-Y1kFa>3SEBfA^qlABf2pP~tc+s1R5IBV-=53q0- z|5L6lbYijm1@RcjVjGvyiDy}!p5wnwoA&w1o(r>V$=o;!EoiW`8e;rm)I ze}`N#vQ4PU(xgB~eM0(F(28B?wllylx|5kZuxtClQ1_5iVwW-N+A5J)reW!y{=Nx-X1I~VJtg4BJhKJZ3=Wu7C9e=C9)a&pFpQu z9^HvYPiP~X;tai4km`gtO~1;hv8gW5X1gr1CyGpKoXZ-63MbaJ0nA|gpIK@ykB@N) zwLQ^+KYQ{$1#TS{<1AOYd~e6Z1nU<5eY-$q$kXk)4$s47QRe2tl-bb1sq({Xi|rd}WRo>L&JUjsbT={>f0|D6yA*7|=^IY@Ty z{WRn%ia(FO7=k)t?Y&fp=|IezyrWaQMzpIINlh*S>QAG5g906_@xg}`PDcYP()ZZD zO{*_eDWVZrL_1-kNzB#FYr!5PL@@1oj(_OcuCD#b!Eudb|H0!PJ0EOpoi_?bNXLe( zr+*Il7&_Q;oay$gCl}edA<UA-#uXp-yeix_fb?@)C4pyA9TI7Y{iJQ|;m4!Y$D|6qTKljzS;*!RW^ zlS_fdvq)ki#;+z5+7Qc8+Y9b1c}A=faT`6m67+Hr7{jOj4cNBm^XL}&Zt@HTicgP& zRe<^K=R!thpa^t>=vu@&hp;9JJL3pAR83i9GrIX4Qy3)6&Z0lyj19jmB%|9oU{|ed zZ*h&G{3VM%;C?#9)sel09VT`qblnA^i5O8d-T*sq?gZlk9z3$NJT*@Qe3$4;jsXY# zCtIw@Ia88YK^**MW|QqS$W~)uX-DuwRVft|L}b3|+JdXWl%$lM%$)xo@NC@~`+P7dv;9c-b=;P(>8%S`1!j>Zdb;X_Upami`d^1Y{(ALp4GRTg_!>oll(7U> z3e<%8<*}uU)uCI1O(9tp{trJ@3{8zRA0#c@%97(r=={59{99Sv-@Q2);?IlZcB7h5 z(LU3crgBd=d5GT;^9FrB3Ft1j_1-b`kE#~|&rEGz3OP~p#1Fan@z9W+Gma=RJSr$d zfI`Xy-8n(l=_$UVqhk}jatK&hPndifP2P+C5H-ZTpoUmm8U`^+$hP4Gso*5~Yh&Ki z*iiw2X*ZSe;UKc}>r|FRPBbkWg5-<*5Do+>Rb;WoQ~8zZP54FigXP0w^5mF$5}ItR zXHo)JA3Wz*IGC;38PKE(MO_~n2A60oUJ6k6~TLHvB4_H z6e+TeuuhUHRKzH`qym?|Fdip+^Q14Hnom)h!0mgnew<10W`ojMI_G<7+2=^wZk(R+ zENgk5k=BMoj?xl-8N$mJEg90CahH2IUCI6N505s~DhsbYUR^vg;Q&|V5CQj=5UWxL9% zF#OXGm_}8&bVPAa$%SiCv0>K(_tz_g_ z6Mv)#(UqPMeWCxT3rC;H<3yo6D! z6vg(qY2q`HugSP!tw8jc1S~B-d@x(7g7Zqu`{n0a$QGmhs+BJ&kk1cx;B5s+jx^kz z(Y=a=9p|=TFY}#Erp;y8c1u#~_Mq5n!54Xc;rZxzcFRj0pKc!Jd~O+zA8aNB={XCM z3mSN7tB|os-0@tk*pCtYOuHW7f_2h6boNEv+xP3#0DGGszKdt5|Lpj~{uXc9A+}fY zIHGdqbdS_l4_I9^1{?YEwrHrz%2A->LCqS^%u|;hAW+Ju$jnA>Sn%5{{t-yy{Aab6 zS>YUBwU;=ec&5gRuA|V-e)B?Ep{f~k@hYHdLUV)UpL3;5=yP07mAXy%eKwV@jq{rN zn*mrH|8|g-g4Y+_A`eeG4}bY?Nh$Xsd+e=&ulzPd?mS$0wFS*W9Tw4-GwfpJR2nPQ zEiE}EdX>O)yBQ}mm3?xtO;e{A8pdHu98&1}2ctDgCsMopzgQG*Z@-~H1;CQ1*P7>x zmc>S;if7EB1(xJ079S}2&!HAqYuq=l<w(>fwj+vQ!o5I`}`b$0UZ36ez z8TR)Nblg`-`M@h_$gFXmz!OF2J|p9tdpoCnkr@qq^M~x;W=tdDlf_e8`D;1BjPyig zrayT`RN-oz?s>1L&9?$=I-a~hU+j4@C8(S$jxFhV%_RJ|^vk7^L+=lfuH%a4j=Kg_gjBme)RPa#44v3M|XHCmd$R;9N-_k<+&V61$S_Q&V+qsGw9g1L|;+ z0xGuy{8JG*$REa1_2{41D`!0@P=qgBX6zk&_|`?QT088+8!Q~Og&Y*pV>@J(>`6O1;3TyXxeO(K)s(#Iw>I9|1k2leAF z!pANQ)#>*1dk#v{odp8HZ~kduFts@1U9J(Bpgj?g3>jr*Wurp|btHN?;Df0s5E0Mz zM{~wd-3B8lOhEu>s=2vLK3|3+(St;Mhk$ix^Y0Na@|Qq4P(~yl{Y$W%_G_R_^WVBO zcdNR@QqUyNA=`rKse#OMt@6P1HLCWjdeqMHkFg{{ZVUfRiK3SmLOec9s&GknP;*kJ zAMm9$5n6nE#^v6LGasKFI2a!28U7%D_UWd}(2y(z>d`RJYTi0W6La(%7cdZ)fdT{E z{+Aw*D=>J~cq|#+N*1>+CjG7UNe{g7?s**hCNh~sr}SeZWIU9#KzNK{9Z@|p+p^AI zeN9u~q%Wi7bIpvK?-fm1_wq#vs&&4YFjew);jN90Y+yN2QS|otmXDm^6wc~%wMiar zheg}Z$*Vd%d!K*29^70gyppUj0yI2aUd zhWJIAjOxlJO_CRq@CskcGUjme%$0Md-;Imi)qLBk0NA|rxfv| zJk8ty^vb18msXf6od6H24QR0Y2i!tOrbmZ6apJ|Yl`A7bdlA9J#d)akkbc%!_#5WJ z=&v%Y5w*VbM-#i=<#NyHkg?fzS9v&n5u%*){Zm=6Ds2Bc`JIc@-OmKJgByHQq%YzK z8K>r}L!!j#JKH9{y<6?#X#2SfQa5Ct$QgdU-Cjw`i6vIj)@=r)9G{6g8#$fnJKr%K zYH@6tf3a`+DVHyQ=YStJ4)HmE4$^VX>yb<$JwbLAfA3w3nnu;#S2?f{BDckZR|=PP z5o~bAWzEs%aPjkm97ByvW37@?@}wsz5UqA*E&4n6Ie{;o)UWTi^r96RqteCGeIG_o z*xFPLU762~${c#X`zo|5MIn=}=??UY(>w;5xu%yN3_ER2bnkPzsK;JSX29EXRIn|R3e!SXl()=Na z?dC90a&i5bwR6ruVa4Z(9Pb+q|2j4OA?H!UV7R>pA&QCRnVu3Bc%9gTxAWErk5K-m zz%t&_zEjXZ>^!-z=lLBoYt%Xg@;9-2hnu{VwWCZfnMypNnD}lNKVR5i40_F2$Y-iossBw3 z*erq7_n?R4)HbQ|XbT#3vWW}u3&_e5kS$BljyurQr7qE4H&mo&bdQ{!5 zR+EMuVbiOpbH94#Tu{1!?kL>uO~3)-;c3`D3UnzQk&Avzb@W|Wf$u8AW;uKlU2ptM zf2TEVxV4?URt9`VWD|OT2GsI87lW#1iMshby>Q`*Plo^^w-@>iKByx}!8qjn3+#@B zt~dOyZSx?4Of~m*oO>h>-7RA^PZpJQ3Q3SF56FYC>T$WAV__hHU3R``$ z*cXPceiXE})}sP3m;W$0zRV~ zAGW~uqMP!@u-oxw_x3d-Rs<1!`LbU#_TnE?AOq|V)x2$+nN}$f@KPUX-(JVURTXQw z=J9mm=g|*Tg@3a5&PP=b>fK`(z~^#DBZ@T0AKk_X%n6qUBj)?@Cw0H{RutP1(HnD( zrg1P5M}bCelX4sBZhhPH_dH+rDG7tMZz;Eocn*B_Fp5w`s2O&u@O+u+i8Jep`cfKw zDnTGR^2j9D355XqHC!tb@=aP?WUC_Xoi;<$_<{nYV9fhVf7{=cSN)!yHu7g<< z#f5OcaV71I+)*G5@eX8kBiY3|2)vidhd;x<*>j%Sg8IHH&xQ0q%YM22dZFEfw|T2`{TYQiww-cweHMy!K1v zaw=*gm#8XeIlb*5rX0vJpAc6XYSBzwKdg&TKxo;ZS}L|X>5qTY+Ijwo=!R(N%s4RS z^#1Foi~eVZHqsy0{dDZKS$cT{A4Y)|dPbLtaD|Y0D-kZ|!LCj_*S>8;fOvS`K>hQ# z@5kRx@ z)*)=&m+28#*U6%?+-h~%PDmLE{rtyXWM#L&ea$mAHl$Uu?? zEWuii7!9+JJ}~tQfAsX^xZBxCkbdz;z)b}v0nbNm18#8MVAt}0a&;U~TR6t2c?#UB zBUgb9dhn;h`fozaxC;0(z^yC^!(WVVzPobLa~2B-5u6DKMI#f(E26o`*YeD;ct6bD zh5%abXzvojVO;&8PO1(*M23$3dpH%jrMZ?P7Itkx>}}oZjvM-$C#mj3zOip*b@|o_ zBnmD&)_jYF5DLumQqN{$epa6;d^dLBfAYQEVz&m*sOD++X8No2y` zuW%!FY@;6p#M0N$1m?jVQCK72(trN;tO$I;*d;>x+08rk;Mr}{zvRGSB`)xrX}B7! zZEC);pVdYj@{db7tRKoPaqO9)Yx;gvHM}kcrGGWNujEuNE76esj{1>q_@yms3k8Sp zS}4vjEwYk<H9AJW zma8O?HPXfnx%d*dm(Iq+f1lp{R~9EHQYcWTeYA8|cRyZO_?$^I{IUXWHOWoj`C_k$ z60O@buR71~k1POg&QNfdyZQBK?m~wO1yVJYJ@?n7KG$t^Q<NOs~UtpeX5^x96aY%KN99pYxo+sC3ODN z$+4A-2g0-&Bf3A2<)On5F$N6X|L7ITN3^*Ef4LxtcBEb6HfbiW!_vO`M#aWZaqD$& zC1i$CQt6UN)8?A!=Ob9jyw)FhECX_pyRs$!^GDm9md$j>-XzWl zy@`M;IR<6HKm16c=3SDrU)gP!XjX*j@yD~O6dZ!8{eJ+{Jxw%P$ek|>6zJ$x(k^GP zAZOCgPFBG$el9yciYYvGzIFksJd~8S^I;iw`wL&_L|40Bt~O zMuzBB&+w$S%7e;W4Dw|;^GjtuUwq6|;+qC~Y*w;Pu;Pk>Oj#cd(D~VL@CW8XGjw~{ zVwUGUH4ar|gv|>P%4ij-#97)vjPxy6=eUH2_Uxu(oxvE{xjZUW@=XDA$ZdpSATp9e z^CD-s=GKj;Xg=px)i+-xI5DN=SZE4fe|aT9(~*3rR5UmDAtS^kOr4}J+%_Z?I;jo( zn}Hs1n15f?_3Q6cW*X95sC;eWA;8sU(35LuLp=1k^33o z(wBO}x!5&UG?74o2E|RJDA4v6nz(oh4s#CDIvncnb_G2FdgaWDIm?MPpqjrU++l^> z2o&>W(6!~Dy^B*gW32F%kWLxI7dylc6ZZ)IFrp4(?mODN5b)hk;{)oOka&mfE_?hY z;p~^fu}Y<|ECOS(@gjP%g6!>FtoovY(YE1q3%x-W!Em7*KhBhm!S%?mG-d)@j8(2k}l z8+JDRUTFK%iow}0n71#R$tBWhW_=BZh=42d_9PqwY2k{EZ_jStmI$Kf8w5_Q(>uj1 zR)GF8eRk<}^ct^I$AiK~@|_#NU`Xz!UO?&5J>2r9Pm;t~+?4NK!W|nqK5vpE^&|+S zQ$P)P$3d_l-6RpXqZgRiy%Z?g31(;bBeh>DjV4l~CkD}v5rf=yWGdvEEAm6&zF*Om zcw&|7HGhrI%R2(@-zrFTPHHtC&DVO}chq)wqY#F5v$pmA2)qCER$w=Z>(^Z3Hct~O zspNrw&HaJi&1u<|uOigWyD6$a?cxC2G>9M9y}VI&X3m1;Ny@Gznc|C&q z*dM)7CXcUfU3>ENb$c&J#ppS5U~z2a%ni9q0x;nQ$ou1{z1AxV;~%bHN8&7z;aol2 zT=#c-RL%b_g~ynZfqzAgWg;-vnN=$<;}>^bYIhKxlf!e{s^u$cRHp|Ng^KN?{xi(` z%ikHJWrije;|1mL@2ysI-QtVAcwfnfy;NhdeY*>YJUvzxXy|NBjo^lXdnS2hT zz^b2yz3p3Jr31tXI5Y29 z>&CpxCWiCk6iCrH6la4iDOQ?{gpYhhUMx8;iTwz`Ri-uuap)p)Iw>_k7NCTVkXL!p zGe!Ye^1ZLdr(Eyl1}wgNzn~fo5S8h|*XgQAFW+0pJs_CV?>4kI|4XUHw({b0%#Tw< zYVq?WIPINFp09HqklWkMGft9Ppc1U$=Qqr#1!k$f0bo1C4|9&Btn&GgYpcPu=pjwS zj)WsH4IhD&Nd8eunUCf`x7316IRuQrZkK+e)!HdbbUhL;ovhKwZX%QBA29e}V753b z{-9s0h=K|}+5QX1Q#+jeRq`{FFbmM$&V;EF?&y2wd}uyfDE6m=_b|i-`4RQ_L36&! zhdirmjW+ZzPihN0^RIm!2|QX_5$9>9V)r6C`mr&WgIoRnsoZa7T3ZOWchGRulku-6 z9QdPfW)S<*iAjHXB9Q{oO$@cLoxW96&|SZ^A)S$qZaLZvS89Sa4V6X{XvWa}dy)8q z8o)E~`5}lu5by&L>dD<(|4K}nfW1Thmgl}Ohy+`qjFCa=rDLC4-yx8R6W9;-MY)N@ z)0msbkmOyXhldXq`|Z#7qq@Z8y|?<2C6oJ^`)e7Scj}jkeH?Y6diG8ViG~^-W0soWbLXI`32-5ie?$g(W=)-h zoghM{Jr{587xv|h$F6SRX2*ar`J>nh;DJB=dBD;_sK+@%i}8IBV!9)0yVLV#+&TPz?Lt4>vHoFA31+*-Q=0U!U2ZyK3& zMV%ouuTx`>d??+-=nsHjkNqWLcP{nOiq&bS`KEP z&Sp=+)}%EXIYpKXU3KWyh0{aL%+ISG&X!Mof~}@&b=BEvT$lbj>0sB3Lc-yKy6*@g zcOQ_uJXn3caGM?uE(H!XRD{cXvuO}Uh|L}2-`qf`={Z$Pzm9L~>r7fWZ5DA^N&I{$ zBvv~)Y@)|yCphuLSi@|nh^8uaZAn~&`OWiN9=T~J7D0Zk;hiWK0lg=kC->Ev{l~Qef@m1a9{94~G z-#Jsy$NE(=5p&Ub+d{KA%5BGcrq5-Ak^Mu@9+UN13Ud}WaN>9Q%Y%*qwF9lFWrtSOU8&WmX~XF_G@WAu8Q;Hx zHIGrC>!1KK$D;S)IZ}ig{GI~s7zEQL0YvO&DzX|{(qa>QwUTS_ zv(b1zt-fcDxrNT8j*K9Ukg?7Ir4`xyoNKdh)iTMsvI2tIK}TX`hsJ_T9LnFmsd>HB zY&&~q-wBrYEt~`kA~&sqS?{549m#sabM-dO8v+%|BYwT{-bb8VU%Q{q_YA5{*HA&8 z7Dt-Y=qxkodLB4ttLJeK6Ypt$xbHmN&~nlSDK1Wx$l5YqOS2&HF2m*4x!gV(tp0?-s&ZPDQ84l#PbVT~wLhZiRVKQ{ z0RZU$B$+P$+3h(KpLTv-`KHcn`(YLc56JK|CuUY1!Fs_o(f2|jMe}B#TzN*tUu(0U z38fWdQPEcH9w)ptJNL3zA|wub-Zwq4tE}e1BGb_4H;{*C58}Lnv6FX_GKYlF=j{D@ z;aPILcbn&pZx9sCJOp+MZ{m(4YhNQTV$>>h6B6@N5_Fy(nC|c)JI;D0u+42AD0LC) zx!yu`?bhjgJewrvE%T`p662Wnx63=swUP#~H^ytOEROkG4shR$xMUhVXw<3}(5F@l4-GM8$fjTEh zVF)w>pbCir6hyIV{HblBJ_+nBvp6s4QlCwafMJBZMpUfmg96mGGho9QP>9aABU6&E zHq|OKCOjQeafYBh(XV;M{8!)H%kbccK;q2f^uND1gTZ|KIYTP8RPuO7}7| zut{+m^JZ5(5O-wbJRskU=yh}|P&l`o`*A@AjjqF~ zSKQ?ve4@TmEh#lR0BXlLl>)Ud!{^Z}`3Q#jdjYR9TK7#h#|T`yx-abRU|P|p6xFZ^ z^Vpgk%MM6(EMBa+ftw}1SlpM?{EEL|P3H7C-<_jBb98}Pf_z#L8tzF6$^w8r?5|vo zc;exx0hfDk*Cu{gGp6P7cD;4$B*yrab@WQS8cIcab1P6Evm>?Nxyzp&uO*({_)WF z_saugiQlI;Qa09Tov&J|-OTP*?i6@r_}~`ma?CXeD^!AJghF;J--(f6dc)TtEBSK0 z1&Wdxg6We};o8d)DrB*xLKpUgObn~a0ZC@60mu{oGpVeon%n2z6_-tfClqrz3r0$jWC*JmazJX2jMMGNq zEc~9hrLeu{|HL)(A#dNc_Zh6uVumdoWfipXBi+bwTeY{UKRGIXsFe?+{oJL6f}=U$ zr*1fZpBs1k&jjlxM~vO+3zTtqTTvb(kf47=zJwWHKi{sZThilt>e(}=zVk_%e3-8# z(mJ+Si!STvDfRtY$i_hVo;66(a4!w*V7WhhL*%t zSGHEE+$UpR*q_Ax8!rXVC0vR-eCTtWOu>{HzoL9}&%-g$B3M@uwQ%%^d+Bgn#&>3) zMb3%n!Js&tJFf7YFI%wa){6%W#D`xTj#nMtEbXX4Mn0+WWSaK5e7nghHeBIu65Lgk zj39sZJ3-4iDto{|1QE|YP> z!EsN7l81sZijYvZ*ba7d%yh&`!?|ndf*pdP%J z%M#bXc?GsmU47UAwzC*FE61JyUl^o7Ii~)}UbKZ$LZu$t67_mILxeEY?Xb?NqZ*T6 zdJaWBJt=slCz09@t2(b+URzOZ>S)`7s;#;>zMgAnrhUi3MvCpp5}#hn6}!u(w5&RN z8pfU_DH9RLJ&z)6?95PHhH4g1y=+(J$_+mkH_A-eJU(VYyTfChql?o#RJQ5kaNvZd z&oS#e(?^q(n%UKqMxS3Ve`}P`8?Vl@x?)O+pR)u|^^nHaK- zyGgTm^F7ye23WN2Ww5#IIMZTOKR(&6sm}{vq5Y-H*Zo7(b5tR(^Mrw5XMR+X*Nw>f z6?N+wlg?+gCYEW(e?-s7gJOJagVoxeM?TEo(PJ7x+&%xYCut&2~mrJ$|klcFzSWW7d!XO&cp z!d_la_c?dRv9R~hrBiDyB(V*4Dzkjo!G?uv*CaL<2U(oMrO2^Oh_VsZNVS*BcFosS zW;gOm_4s4nCGni2z7y*-1?9fQB_(gvb5aL)+nj4!lCuxhXj%z>eBZ03(K0nqJR{x7 zUt&OFN-Ky#IE>M56wA@`RMd$-;mqUM;|)}^OUh+#p>)P2MZs+?EtV6JlM_*IzHCU9 zm+KEUpVjz!;f+*yWkgni*cW!Hi%RmG_>$|~D8ZCV&(B?lk8U_~#&X&`)fNk7cPQAS z97+qI_J7<4s(ICv^sL`%g@wG&1yrT{>L_V%8vC_Y<|m*1to`XjZdgghb^6=te~+_e? zKh-y4cpFurfJw$Bh|pj|jH|nr_LRRlr_szhB0@m*lR#1HwP#lr?7h49Id^xT zci!#qeSO|{e^k|4HRl>r)|_JwAM!#b^j{yssEsxKs=TaBYF~G9+feaoK95n=)6tv6 zB>X_5U!OphBJz|A5SvAdoL)NuasY8|7~}v8knok=10-`)5k^R{)4Ag|z}|f5&#W-$ z7r745oM?OiYa9~-Xv?Z07bvAuZ9_jnOV7uF6Db7gZ*B8td5qp$h@R0t#IC&!Sr9TY zdU7#_%}W1PBW-IdHMgF;=Hcy&Y>1Ki^roKHpQ&D!AE8s|!RWV0aG4^1_TpVA`B})G`-`U1 zzToNiV4Ctaq%x}wmNDp;(FGS$TOam;gv9F(-y6aK7QXL`*?H5mneS0=ccR|UEB_;E zJMP9T3Gp{-yXeEWcD&>EsgKF@I7Ii^IYtPqLqP?J_oV$!oj&GteKHf1nmDB^yK-M z8UmJ+Pg{r>umaQTa&2U$u35VsIH);Zrn4&noH|MdZ{o*?_%GZ|oL@+<_~eV!TS6j4 zR}})_l!YD?D6eO!19C>zwXHJEZ`(25)*r8zO2{?));=v%*RR|txTqLuQ|?^Rhdb?_ z_@=zpi!Ah$Bq}ptOSz3-ZQd}z_O-*K!{vNbo5W1*J5QTDPeU2|_U%Q-)8bJTPK2J% z-EWNuu@ZZ1)6{bM!tP!153koVocYS@&vJd)6zm3u1B?u+N&&OW`YFTCC zXieE_onp=-5mqY>B;D5=AR)e8f^r^}Nb`-w%HAAKp^iP(BL;u10?HI5YH>r7@BYU5B zq>46HVM`r^Q9gktJktCp5PuH$3z+5n6R$kL)SaEJ%DwJG-AnF91@3ZARJ*fobg%KU z#0ZK6i^yEv=VBV+cinFsd~eh|zoMlrzo%`e9zVvAxA|=6YBI;tAoM?$odT~Vqu&82b0HQ)^zBq!nNi`qc8f)Go1&k;G1nbDv zJWp+OfxahrI+)&Mgu^gh3B*d@T;hM#x^w`)gD; zhbv6LgaD9w7~t-n$xI+$3f3Ue0E?5-($8~e@iSpUpFDyx5|S6D6X!BE^<7mR|0dh| zGoSTudX4M*AJi@o)f-eV1)zGs78O+b56;EkDTv?HK>s9k;=fxxrnK=~2Rq8wA7usB z!SZzjKLq`Fuxm$GR+#ziCd$(lGP>a%{*V5H_B(Inm~oe-EPZ8E-tLph>vyp4>@J5E zCB$wzp58XzFK-OA7~ph^$C*+Q1afogH7TmMcWY9C5GRapZ6NukXPQ%gi(UJNH1B`n zFTq>dFH_-t7~#Rpu0rN@{6wE!3P?c~Bs3;vEby2U_9 z*;om^wC6K&f2ZlXSTE&kS*{MI77^tU)k~aTVGs0rKJ*1mj-|C~>?&Zd#vGPdlRjDBPTY0UKk@|A)@Va3#Zlq~+uLR#KQ)&qAkHdJqu_xm*+aR0 zFGdX63o|Y0P(zH_7;5%|tC=t9Nnc03hHA!Gw{nJ0dK{zb5U(A>c3=oPSM7)6<0GHZ zhwWlrUQfV;qUMha-dEX>i%LfBz*&;a@WP#;D7vDQ0A;oVa3O}!qM;&xAN@R36jFSw zeMCK$i^+gSd6Qjr4I{OwkQb!uP>U`_$RkA;p|kj`q!XmgvrrKGb)f@^aqnxz^U!en z-GNP|{acsMs`7L=u6v?)ni>Gy22CRk?xGHKMc~~Lc5YqZ+^Qeb%9duPzI~v ze4X{_$KVhuc3MUm9I6e%T}SfUOqd;m4fPR6>r%`1L~?aUR`;%;Jn5$mwEbit#Ty`a1d%X&T)o%ZHT;<@JcLPCoXNM5(ISBP)uga2lckWM1path z`;yDWIhMhY%$gapSaCcz5}yE8A-54zL zX|Lq`K!h>K0ZC(RanW1u)f+obhzPqC&~#4hi6h#qFp8uP*0y@B z3n29X;*Q+yyn7^h`>N;(C%Y%u?gO#WUd+0mSlqTm#(e9{QM;vwKTqOE)1qw_)Oi|8 z-`VCtWI|J-R(badZ6(v{St2|Bs(MARS_ukP0k`MNew&N-(vHOOap#glgXfy+apPIz zrFsLcdt!j09gh9QDqTGwfiQO7o0cG@$i0hpp}rFQ+u+@%Hn6X)h$G4-g)a;qYF!yj zp-|nMKq~+?O@el7MKTc9la3ONChIl%$2db?5D`GSYN+Uo+Y;%wg2n4Z^)LpOl`cc4 zsI31=K>Y7QxMbH!u#^l%mIT2$)PR6>N6Er7bbZ&)4X&N~3`%Bb&hgz$z7x?rPG9>T zH9-yVJ|JeoexA36a-67)HtoUvzKHF(enAy1=G&E*7u(^n&0=a-)Q-l5bloOd ze=p2TRoGkpbl*=RY6QHCSy3HU>848r8BVJ*X?m@1D0MYueb2D7Vqua9@ij@iML2w4 z)3tfKPpX~ut;W+kGE>jh2N#EH+?3BT02X}WAyTTY4|PK8t?Zj^9&o^YeQXoFNM&b6 z)|@pr!Z+ORT{WCRGEdu@wzoB(XAX{$ONw$#3zc@;)*#T0GK}k`)0J?ASlAeBI+j z)e%^?dvpxM6=1T{9V?@@vK8+Ns)Z?=%mz*$W@71}`MSG3RHMRCo0LIP?4AMDMiIaK z>skJTGTy>woKG+!WU@4!`+G~BvozY8h?DmAyuP=`ym(N=lc+Wz;1b7CBdZ-$tudP0 zV))07Ci)K6diV<-{mc6&Z9BS^VFink>WRUs2T`krcwm$S^7PD;7cfsZvSCHyr<#UE zsgV6bS9wP6ZB}MjGVx$)JWZsM_ju6%9^LlenXpx_AF(S#+^?u~iHv(XZQw`!eo^(d zuN(zcL#W$P`eR6+3{o=(uyb-4yYM808Ud`~S&DF)nmtW@O^wloDY3=XbkuOARi-4f zFXt@r(}5<>&a0~A8ukl!NRZ*5q5=Oq&%uA)H`VV7)h7oEKN2G3?+X4MJzcXYNU6BWz8^ZMN+ua=xz8 z>Fet)(o!yO7J3WUtXC(I`aN1^QOa|NGufSlou<)sklN*wAFKHU&X+RM3A>MXNcvX` zU7^hI20^t$e9CdZZ>|DSI|NsGhaohkkk2E>`BnjkTUtnO{Uo1+Z})Wg#3$$pu%?!p z_7I0(Gi3&A`PZCcVziH9@5EV%cO7V-t53~;1LVAFf5cq;vz6`tsB3lFH*{|nqV1(I zbS#N6GbBNPJ<8t$H59wRc)1=wk$3dT#R;LgE5doldK-*g?2tb-t+>*P({ah`Q-?-8 zpp<}{!kR%7zH58Sv@Uq1RdkWR6o&yNjO6hXTFHAaYplpjM+lycC{|X)q)$N}e`x(o z=BL|I?D|jBg8Zw@GX5`||8LA+{+08L`o(k!z`80?KmRg6DGwz(rGtqzp0MyAc}Jye zpSzm>o_SOX=IjC_9{nTjC>J}M5+w(l#!b>uWfN<4S36Nr7guNV=XQ8FRS79H+7}t;N`lhDJsgQ=HLp<0VVryBUO2B zX)Y>?XKoMVQMJbV)x&>0V+!W>mOvU-P7ZGVzt4?FYN>8dBv}o?%!Kx6g`C*P((<%W z&ja~t0)g16?k8O)2;vCaLQ5)LQ#7e2>WmmRoM=clRfwjKyJn4`jQrh}GWl8gbnl(O z(U5d5aS?p@$dBW)#cRdWEEk1f=t!s6mDdFHyStI_i?gqq&AuZ}D~;N1iY7z)S9!Be ztp#&C^;wV_=!u|+cxLrMq&^40{(}AU7uLgVsa~~a&v4TgrAL`o2K7Z*ve-idGwjEkvA45BAgLv zuJNiBCE7^3=hc`RJ~V>V#2}j3kC8Gl>V;>w9Yy;HsrcbOBB!!lSGaY_Etw&tISTV} zE9=HsLh99yP)@rww<7#P6d!8 z$(o4=%};aAXJ1?$E8M>G^*VY&q?GQ;g+w2=W%detwfxRyyG-y}F}KfyYU(SW3S&hN z(xlXc>u>h2xeC+RO+3_;UN{-cHRgLfN$8V#XE^U=#QYG8Zn-vlSRq>U-A zWcj1thxih=od=-l7HaX;S!d<#u_Q%V$y-T>jKoi` z%+Oqq=!?X^S4gB6-?^`HPH;{LwQJmY=R}1V*lEcoj>xt8qfvm-Eib57bC|T^h8% zG(w$w8}IUyOP=7dC&>7 z&dhs6B51f`|KxZ?W$8)t;!wHA;C0WKd6X0Dk*6>_A9HO+h{5g5*T-M-+qhWn?;$_6 zFpc`%b9Rm0MU_vG_^dJhoj|h2+`|xVsM^dXZAz)cGD(9GMj-SQgM_V9t?}pQYVTmu zTf0?NU&6Ovq#aBxXY8(KfF=i^w@~!1m&VTQPTyi(+nr|7vs_i8!G4&Xbq4FQ_O_8@ z&!q3L?HHfx(qHVIE-Hp#mQRFEvv)e{h@D>S*Lxpka)rD8B(=yU--dTIXP%wsMDm|M z8?p77$O^jGIL^Oc`S#&{Ac`B4XXV``tjA6K=aKFp7kaOpd#~uKitXZqIm;RAIL7X| z7Q6_nZ0gmh?OP&xmN&)}?BW++l|x#afXYVbm~%PW_{6Q$Sba(zt(dc8{GfobwLbft z?1S|vC4~dZ27igB+*Q5VPwO+&T7g%iw)hJYYNdm!Ni7zOif(>;hJ0tycizTQMWx&q zEw%7w_33h1p%SeO7=UWwbi_SLR`|r1OH_7jl;uA&t}qf5s;Qn9>`L_fh@$do5;s!_ zxWR(R*b0rbFT8kJRsD&Fc2uvwAUx*W2C4e(YpzJ zgxyQJ_RgwtMO=Q6+5s^9fveDGDBQWLbge z19*hw!kgDAAGNc3B;zz#YnBNcjG`#7avP+{9-m2>DYS$=ea1ZaQ_t`;8J&y8v#zxJ z9rtoT^QcdvGeW*~VCh<6c_0&6?6|K9qdc|WRiZZPw9QhhC>}`kSDI<3 z-YmD2Dkj{X8ShL}djr8Jy%D;>CCTJf;-lDoq-$ftbn*E6o-ZqBpHQzoYM-Yr6w1vt z{;Xr+vh9|KP`md2`0Ktp;wTTfoq|?{n@2}U_T{^DitoABZ%xi<#v&gYE!-MULBVkBj@#)@U->3aHxN366W zF_K`+GQcQCd4TfZOT9)bl7Gx*qEcm2g3Xys!y%k!JglD}C1upjCG~W~8-qPBmx46KvA`vLmFbIKeU;&901@lUolfmJ_Q&J}X&Yp~Mg|J7b8zziW%hXiPOiUGJ^%LE=P~%v z-u>U~^S6QY^i}u%r)Qr(0xZk_aRSBvTlW8txnXLksP!%O$0{hGSa5~5Nf&}q{6YsF z9-#GF`-OmyM<1T$JUE9yIFpK-9&EvGtJ}cP(DiG#Mud+U1u&0X&jV;}<&NwlAd$niOJ92ku zp&Pmy>gU?Lmk2l;2%BE@vHeyy9<}v}?fge`DG6qdbeIv+gML-|inanifPU2{4AU|? z+-WX_O#b!@RDsX4z|T*WdxrthlHT0mPR8jN+ll7etIPMB(!T?YKvM-;skyq$UzG=} ziJX9#6K+5}kV1IHR`cqN6|x72<(J`>$@2hte-Y5mZ33D-_2zk2^6k#+V?|^)P@0Z* z$PG6Gd?5x<&Qs7-=l0&RU0uQ#N8xSHnh&>u$d2mp3S0Q9|5YFTiDJ~%9wa%F2Ld$Z z1s^B}T3VM50{~~J1As^2lf2Nw7C(!qt#^>~A5bo-mxXLswEOUZV)z{V+8R2~7KZfI zM_vNfO&UgjuX{5i08lz0E@(a5`H92jF5o)~Ox!IWqr;84(>cK6I2-x(kFJ{Q!f$#C zdW*b&*1S5_yxWYdg6zF*2S(R-(+Q)S`D=x9N#D#A@Hz(3oBv)4Sd!jyH9Fja@79N1 zGW8%m*j8Y763l^@gtcOYCkvlvi$eNFU7rGPWgnQ4n*joLNn;OxA35T0GlmJcb^ivo z6L|rccCGyctpam6r-}7@)tq18@q33dt(9*Yh2Jz<1f6FA8W^}fR)POM4roP5^UdUf z{$8sdI?wv68-K0^yiTANN}(z8KG4qUcc3kejJ?E8VAwzpfM5iZ?nb}O{mlx4av`~` zND}|n955bW=)cBO)ckAdK#~D>U+B#$@xK~48~jyQ>16fSU`Bx#3Wzg(HQ`%5H^6pt zklY!+;KS#nudMLop?_-_82U|Zhbu3j3+9vXfqTGnko}xX&HFYX8MqG}636Z-Nzy*UV_ z(Cn-ldVUJ@f%~jVNFQ>!kpnC?H;y>eYeIujJcM4(^Lca8SA!()yo_G6R1r5smx2*y zm`jkXQm@50#p;O9*%cqwB($0$6|A~$fL$`T6C8BBmLL(Mf z<2)V9F3U=)gn<(>0N+D@ky&w-?+ z+)X+;J(*ZxZ#reUj@yNwDF_y2v}GQwO-VnoLLF>|wm)2gEnIMo>G%=IuN)(~cTlo_ zz;4$n?=NmJNhb1MmgTS6&`0eIKUX%DY?^qLNW`#2PU-;`1 z!~vE8C2{N5%z71W_{YP(0AMWM5RpN2Gk>zNL!R*G zefH$$d>k4ql`QKf(7N77IF-7m^FuE<${Q`io!j4CnO}>4>4$4}GWpmSM$u`XPO9(+ z{aDaNC2|aQ!f3Nq>vFVOFvk?)_$1fx$p*$7YJUu)2AqTQpCExu^sWxs#qmg|v`DP7 z5!Fuj{h0u}13wFFZ&x5vxted0g@dqM*Ozp`_ak6X;A5pheTsniU^H4C{9I}B&9=AL z552m(9ofaHr*oguK5ljI>E2O9dkmN-U^{Y1llBRGQN`=qU1NSX>ef@-`N%Lk@Q5L&u38cNhMHI<#2yE$IyNmsVr6)444&vk43GC(J39cj(mPmO~_1Nhg2! zb~9%kYf;swQEQRJ`lhT!2|=hY#x>T_@!i+am5Nj-om#pI^4m+d-_gjE_408_IScMb zwN(~&t6GJ_4%HHNH(V8P%GF27NIn{KQTs|ty7hgAsNk=w!{&UOvKtP^c#JRm&NPm3 zA)Y`eq?G9Yu5yq7I6d@WjfKO&hPHOF1_gp^a~c^CD4`tk@?v=HMER<~Hyz`V3L5XQ zT_J}Q11eSJI}G_y4j|$q;$Xu^H53$RPO9Tdm)A~eg$jAMDLddsAUdU3iGoi)9?n)< zSRJYu;7@eR=o2;mmys_ccVbtfb14i#a;*8}Pcqt4*>rq?!-rb)gv5Y-2fzW1N*itI ztn<+JsDdIRJ|9S1+y-E3oc&R1hFp138J!}8=WP&jJrg9z0XD$XV`di)MC2b9qK`x^ z;GL_ZUK7X|$_Zw2&wF044g9b|ogpwV?C{!w1PL2Fg@^lbqp*MnH)e<+S-F`QC211Z zt{KYfdSfvK@b|#>WeHHVIc-8a2sEc zfDDF!e{(SX31h=m`v5zG8sv_mok1c@i&Rwa3cD10S zH+vsA|5k4fhG!{}>(tF(dl#`B0R(ZMdKputXyY@6{`ttAMccu&S`#Hlm#g)&95Cqg zooCNyG>BSW_FK->y6u-W{>^d*!0bE5?>!?zI1P2T79bt?`erT%44k5rbA>QNL3}lR zRcf3wx-J>WDjw$#*kYs-_5*%(x!L|07BYIYt?H>}M+hL86{qHyKVIc3`a(?4CoW=Q z*)@V%aAi^^dJH0F(T`wptz{J&1npg_XbXFUWch;RZ|9BmzxRTvD+jAr;IT4yCbM0p?H5UqG{Cp=k*~!k_XR`5S?6ZT; zxy?;Ounhx@Hmm1#=7!C~!mo{^vCP4?A(ZJNf?7>4ZCJLyxB!#|#YxNj>uWCU?4e4J zcP@aJ@R=uMxU8FXZJZ(JZcF1m@9_ki_A(u6CVm*Bi(*8~Rkz{ggU;d7^*PU`D!KQt z8U5?sbpy*xYl+j0y}}|Q(L*Ew59NQ?9vdLIDo4E4bAb&rIy;Jj$AHKM`~Onn1DQ(x z^7sTcktB$Yp`8T`O3DFmFrd^T+C{^Gtu$1PXs2U96{)l(0E$796>&X<<-pz|f8|OS z&R42GjY$4 z&MBU(3*|`xxYFClZb}Cw^=h(D8=rlg7_Is3NB#lgKHV{k#1X|gJRm_j`X=y*WSb6WE=3HcrKUjnCr;9n?Z71iYW`$9#Io4?rfulQp(V|}Ul1kfW3++!_h&o@lRA5+ z)K$l`fK)HVvd`AbBtHP3VX2%p(sR3AG1O>54&(#{7EQNBD;+YGTW;x7 z`U1gY!6r!+OK6p&Mb2CUi(+827}4=ZI4?}ytyz5FUlQTDiZqb*CO>bxcFFgEu?LAm zE+sS1l2&3h(gr1|gA*23riZ@>Nh+DUJ5@5}%K0E9@=2L0fRKWcp4CR8V>Qox`qQ)mPc&vN1FC#X|l(&*;c|ke`MLU;GZA)0pSx{~eI3aUH-X z*iOSe{9J#5@;)xpb`=0h;a6S}dpF!C&>T=}3~sBpxQpMbdi~Mndj5QZr3rF=3Pfls z6z+nr0<0iKcB@MfaN&EZL z&QOCJXaycP@?g^HP zY!@;1g#stED+=JXX|D^sUCFC*p zIm{N25+>Qdyvtgqip_-hk#cN=-$6B;ExE>krVNHOR91%UmV!i~4Rb;As-34Ph<}{N z;ScNB|MZJf@f%_13gnl0H|0;23y#l@zAY~+51@(Pv63usNYUQdqOs8a-B$9(;`RoS z-2R25fCCJmj6rI{zdxdhfHaC$Srpxzh#*b8RvO6Rrjl8kBd1>i@rEPg>g!;9Zcr8` z%90@p`cgS3ahZ zEco_Cr=hNfidlLj_j-w;1unB460C}GG)lF$I>Pmi@tm0jd}{5Nu}l1Yw_X%I6!guF zccRVqkD|Kol6s7o2{Az!&wFgEZ&TZQ%#6%d*)Pu6Hg$Z=qn#x~xh#)*PXip^h@CfH z;3|Ho=iTRlH5vVdzNuOrMH1hsQCijDdf6U%@=UKCy)}xlJLTd)>DFQls1O>{Tnd?^ zViYGCY3`QyOE|)zAEfi;R0qH)IBh7o2fjtd46T{ixDvv{M2A!Pl%Ya{7!K5-j;~De zsUsPI!`zcHRGE3IFx5aQL`?`tC5__uX~%)kYVYdO*4rvC1@Lw`Ntm5(r`N6C_xD_aw(g1%nF)B%vcc z%;U+2_%;hRe;Cod1@`ap=J*K`Aw4X5$U80mx%|q;S*Fi&MoLUr9S!`&SJ6u+L#Q?1g&s}}3h9og6zY^CU;j_aX9N`-y^C=D&;V9|!Of+1|?qok2TIxQo zwQXlfrX0{!%U>q60Ggq#hSx(&AEnL)Wz@7a<A<2I@1NQHoV11lb z=l@KynYnZ4RD&e!DN;Hbq|Cv8JG7?6z(Cv$KgPn|Pc@aDsOaL|$HqF3DXx|LuQDQy zMZ_{Sz!@bCiLmVXAWZ5jYU{N$4up2zz*^K@5sAVcxajvwjnO856GK=DHhiRDN4W^m z>wD~?=hfh+`IXM4O6J;zyG&6P7mF?z4cxAtIvUoMhjwdMHZ^=Sh%q$HkpYD(JsvkO z#Y4{>lb;(j=$R`_5ns?S9MhGF-E&{^5siBF;jWA}oj-{zcjW;PTrO9MKNGu^8|{3g zC6h4|6Gh6ikoQnVD+worDpeX>UWOqY9?5_zDlMll`iWyahHc_#F~;@ZNX?zSzfrI)k-a z$^tBBon|>PQPI-lLMHx;nsG$lf1eTr7B4^vDj%21PWdyZS7t{aXR4u$W{$Xsaiah( zC?p8`9hw)sgTKS}u2yu2^}8POH&<)1>}%S2z6>Z4U{mz{-IN5UO5-K3QB{d@-a57cb#)M`zaS1M z_}6k5*Jc%+FLLr7lED%DFpBpb`rHZxEN3*$V>Z6N>Ib%SD`oCS>smbee05E)bGOF7 zseZ8}F5saxOP|!897qv>$_1;je1{hrb$m>d>&8@ifg5G72s3~eLL_uQ$$FfwLO-7a z0Ur$9X(Prp$JfQ3Wyl=`md5>70a|f4Mo%zrSLDU@b_3F)fFxUIQ9k?Q%VExug~bP-Nc#$ksS|pm*BqIM14yu0Hrbp1lQ$Kt zLG^CML&M@XEj^!L3%RNSsuZ!P@_=A)dw{APP`xREjqeUzRbOLR43FG?+yCBc#u6G` z@a$sw43;$JBrk)}BZSwh=w4I9s{*UO?PjxD6VLv_l%RutmS7FvAx}PE_quUN=P5^G zJFeA7Yt2$>hEM8NE&Yznar^PNT?+L&&ZnfUx2W!wFqOLyK^RZUl-nT(#8nq?ISCGK zd2G|s>=+4qViDis;iKKNBe}zC8hBp*Am9gbL=HuYJXjYaECi^tYev|wZ_wGV%_x0k zr02{2w`Kmva{n)WnYxixg?KkR@`g97+mw~_8dd|*MN`0T<=LorEevPG33ILW%+Pn# z54A$;YtMD~23KA^7$4{Yc4cx>WpH9ly$U)$9ll=Jc65Mv0;iBgku}#jgrgrn*QLob z#nZo5UlWb;!-f^{x7)9~=7R*xwJuBWjIBC$w=NqF?0U|h_7;#i)nTD~ zjeb>RMi4&qC0%zcLEIgwE|ci za%VK%d!cXe=R=%-cHW#Q-3J?J?0oQm6ckA z94-i|kyoV&^|}iuiTw-YqQ{VleS;KYe227lpkpb8z?p~=Q`VW=l!bK?7UY=Y&?^lI zqTPF~Z2ic%dnGa=W4^G;yO!k`Tgyh4o>mH{^AiC@=EkXeu13M37eS|Wq8h7mFZG%Y z^hGj_!OP|S<5iv<=tay?(f!vclTY%@`)?7i_i4D(J@qOkW<`5BYWcoV?N&MhzoTrX zBfsbSohLv{RBpyKIG4gx$%jx6bp=x_T>M34_6{LP?});^d$D!YvoG&*8)q~y26J4` zt2bEP6yVS+HWy}^*^s1{VJ#}LQ?64&BiIs?E}IJx2LShozhQM3TiaeD@GR6a(N}s^ z?R6YER9!kTJ>-zPCFJ=rB#j}8zTm1|emOr2P`Sq6{Ew^rG2D0mJXF;ld)fa=`fT_d z2J}ig(ccw%I)p$YA$x(f4^9U-6dH|my$eY1ukzg-1#BQy+o*aX`Haj>%wdwaugVet zV?+Xb?wRBxMHaFO5!z@{%50zXz0T=!(Rf*OF2i>2n2zDd2&9ATCo5 zd;XJ?eiL4jYc)klF-6m#udV@!$Snr{W z-A9BwZA%bWfu)$u!lUIF&_kCR0GZ>XV)!XM*Dcy?TKbbvb@)mh8yMbYKX*NHRfwAl zP?DV&KS4l70WZu9fUAFVRE8!CSzkx4BQ@6uA^RH{a-ffZ4wwaNI57^Xho4JH6Lr>9 zd0_@`Kh7Wd@0!e`egyPS*06OY_;JK>UJ9se29}pT+JQh<`bH4vS*oWiTj7aqYYDQb z%;#5s=DDDr_7wg}j9hI0S;}O1*M>|dGoasYlg`)EIp^wsnuR?Dj@y3bM&3~K!b!ia z&hrk2-adI{^+z#UkZ4OOkfHo2mN&FffY8oNmwL7n3iZ3v3QBcO&X1jSfyAPLXr?o) zS4%A4Vi0HsOK4R-)W+8D6F+1fJ0Xyg&Vi{DA5DAehCMV`I_9x2TxWWyPy+(-qP^5+ zxLbKol5t&(SPvndBdpD1|8CXIv8;}IMa8D1i8y?M$GUm_KD@!oR4OfP;Ozsc>Iyq4 z>g8upoXJWTC(IQI3NOq}72T*KRphZj&4!g2g*fC3V|cCyU2aSlQ%;?Lz`EkQqHBhG zN9f=zMm^fp(eMULU}Qr+F8@bC)5(vbaRM^(T!Cw zYlYQDB>7b+a{*C5YA8cLAoK?)sGC@V0jt-#zu_|Y@3>4_E#*Sw$s?F;+#}W6kK66y z1&KDBhMSe=XAb@!YEJ#gZP z8-+4ggo%wCV$?PKM!I>)3gzerm#Sxa@>K+?0Y%6GHwr7G`+mFh3hoh*1ox0*kPoQR zqW(dVU4|bJkId1%WV3~I4WgAx^7WoTV{-b?%C90o!X}}XDI)mS2QcB*H8{1{eH8gn zhmj)nhkp*)NCE0gYz$V$AAsb7=sd_x@5|IHS!))B zY$$`J$x59Ea_?fo#xD4YQQRD~*kmUZqtWZ~z=< zE1~BLQMj2!Efffe(H!BJF8j}_I{NZ5%KQD1+iIA0Dht+jB-^0SYC zHjSbj&?L3fUsXcn^pwx7MC1Kqp$iuy>oG^r|2L#Y^F_zSFh%@(WO-9%JPJzQJv9;- z*uR+nYsz8sef+be@C$83{gO6Uv4^ii+0`6-K2Zk)T1e!MJZYEx^NzKC>y`W$bcK2E z3LVXKz1=bE3HPkKnm46 zguqeLkoOkLmPx2xlQEW%lC)lxSP;0e089~&B6oVNTjo5FyadQ%0ZGK#d*z)zmumRt z@Asg!EkJNNjl|GqLGBm18%$@M77aTR#rb1^9xtAj@3)H9WOa5-ZPhpi-y;+k8|_N>U5+(Bi)2yL3cPc68zk!Upip1^m9#>OPu^*fRA%W2W` zbus)1lBZpjZ%kdj#)YVSek@v7eDZ)$qcdqpjx*W7)A&ws#UxQz?_itxOkFu0)Jyco zm88DntZnI17u+N2pgZGT?G*!>W;~y&%q+%xBvhM(NZd5gqG9&lp%tR3;dD)@&@oxOtu~`8W0f+zyoNsUjz!Zsrd4#Mi zM;ADs$)aHpX}qpak-BU4) z*%{G*toX3E(s!eB)n1cz);jy`u4><8WsEwtj!k3%*>glRU8U4+$vEn_ zWIc9fQAZnmM*#As=v%ugE^MV>h866E3eSB;Paw6o?0!Nsh|Xrp)xJVBsbRbnDNxk= z>P0DvFLW}6E;_-OD`s6I+23{qRXBA~05yQ~`@Z6Um)dugM=c=FLNLQ>_^90Ert*&z zOgT?-P~KhGVjiPlstV{;T!6Jo)6q~65n77#Ao^?keG)ivhi5@6e?CfN4mg-U)WKd6 z*Bi&)shu5cmeBzFVtk5F9mo|D9z=8YS{f}7Sx;Ill}pORph{3FM@<`bQhs&^hJq#& zAeNfp>}bAvl{)D_tuJy&?H&Rzhp(jSV3$7%?) z^gv-?K(B)B2ndB>dH%GoxN4`kA{Afo1n#clC|l1{q4gS-x?QvfRc@p8 zct!Ii=Gfp{DtrTdONT(j?;34g?6kY zS0_fQgZ4={q|_DxBWj~6I8qJGGWOXlz0Q84zAv0IocqvMTGjc}EqO@-DH8xcRYnZ^ zbFmo(FlYF0B|iCbM|NqUn#V1g)s+9Z1Vburo5I#)(K+oEJE- zU3?bREHsfGryVaCe*_3nbd+SYYcKvR?ru?!|JsSbLNr7+*To}vPED5zTlz7R?p zbm!GTEvh5C&Sjw5RQrkoIOv7;jPPqYyeKU{X<+jxv3Kv6Rxk4fw z5D^%KGsO{*8D>amTGYva9uvReN0E{(WGPcyQONH4B>f1W9qi-P)I!l&Sim?S24Iu_ z!AVlq{RC-Qry61y{JMxY!~m%`H`@4W@sEFneP%cxa>fw%m_8O#uX?-UNBUk|i!DRN zP>TZwW+NP`{bW4mUD2soJqr@>Lm9}GV0>sVy%Ta-B`*8o_0hrE#bHXbvl9_yYmC;M z4Rh$!?{pQA@R{!D`}BV6kaE&|(^{-uB7DL;7#=lV&}IF`griTTPJsSfN=>?Tcs{Ey zp9&SGu!dQz;8>zcXXMzuu$3jGMoUy=+B)_sd6CoIRk|GW)(!@gklFMGvLl4BTKI!q zvHLk*!{Kr5+-%EgY~*W1^v|p%iPu$6^RqhjKykT`Osu--bNNmDNn>FxWCAXb_YY`4t^sgt?D;*f06a#)X}s86vhht8T`{C0}U5= zvC(M(YF%DB;}>=PP-BiDsWC=jlkDeWcSST)O1m{yGO@c6n1Nyo{^W9ugz;{fx3VA& zMy2k8=^?b2lAH>KuT%p>ilYLrO|ESU#^IGsLk}l`s7~}I*S(9mblkQ zfqGA+yIomTjz1G4EJoHx>|^}>ht$L(AD{9_eBr!j6~nkZeUwXY?xLrc`&CSl0Ld8^`CB*l!=DW8mZp|R*m zOg~%iV^OS&`vl1RG}N4iYp&y3pd#QQYbo>wZ?^37{nopY+~(rb1T4hdD8%N^N}~#> zQY>G&B|sl2)RqS?#W9#DUrM9xm8>7dS68R&xX={6Dqteb=t#`8WyIw~+}mLKRQGVr zKQ5_z3cq%xP7&u)tmnf0i3O=@2)dGF%O94dJnJ8f$6PNMt*a-PP~ zx#yppw{%gMl=&Ab5hmz5{NGzh4$Q}SFk%)Suxp>|+*zo4G~p%=2V1O2g|qVu4}Wtq z=V}l=oO($mL8k7#5=Bm#LC=OqRV!Pe`*x6|}@0otdh- z8YL_l82j!g2zQhZVii04^k6Vi4NK2jnmxhN)!_9>yqedl2<&@|eJX7)Zs+Z|?hDN@ z--EB%Olx4X3z9HX19RFMQg6J;VqUE`w!NldJ$Mtd(GMBhV&m2C-e}?fP@dgr5AGVm zi+SW&1IlKAUn$lAf2P@~8O5TURvBfS|lJ( z!Jr~`E;Wo*?$MoF`H>hP0c9S_f_U{-1gFA6&bw=!&eOurRh*^=?=RV`RdpX_|UcL+@ynOcmi?p{6Yis?wMT1L` z3KWMHC|cY#NO32)wm@-;dm&H?Z7FVr;O140o8ez*F2Q3znO4!Wz6{)-!$?zfu& zJ3`i*y|X-kM-(+uW(74BGLb;qr7!LNk2s{MNY(^4m3O@%+{)%>b!?`wM2hEu@KYqFdJV2_CR_yX`dooj}!1 z(>jQ$`~Y6XG_egP)~l z#&{eDuY|vYZh>0AeWv4IAlsD}Pp$!_huMdd!0~0rr@0hA0}$oO8C#vd_)|q*$L0l- zXOT1dO-A^6X16q&KNHdVDe9_T|8P!yyXq-n6wtSCvUug;z2eM)z9%k(mQK0@8YPU? zp|2Y7Q+nKol)p3Oh9)zK*E5V;WN!H7Mqd)@NRlwkdB5yR8BOT@wz^#qKd5m){Ilpq z5}?8d<2UF!^>QlzZrrsWO^cFe2Ro2*s%O8+0S34gh316+cS_F6r>M@xI}REsK+cqC z(PC-1Ej=wcqQwGfjdSu}o;8kcV=#8>JNOz`seXAiQGWXseeW%SWt(AhOVek4#otxF zt89GqU&(K`TYuD7;k{<_YRB0DmgB%T5@<6UteBV_?Av7iv%)N31Uy5kq~!f68jBlr zwo&e=LZ*qy`$0q)=u>@C3Q4k5|HpX9G9w2_irn zgJB#EJtg2-OrOgtz#vcCtV4^|QjzKgaUMxswH0G=NhW~Se$GQWhZNFW!(#(*vn<0{ z<@vh#(W#;mkhLIUld+&Yt!^%nl_2U|30C~I6Xhl?m?obT`dJ}$8q7Z8yzu2wILMEH z(_TF%R~$`4!w*~BqcGeSp^gzQB}}lAB7CL4ZHL6VTZrQ$^z>|kg-Jz2+~oF5#e_UX z=r|?S8TMlnN|7LWHGVf+W*Axd6J}*qcja`JVg3%-9MUg9&TDE@=_J7vlW*Dcr^Bba zeG}jy7fEOAMd@ZMCf76?vS;-rSb1`GUIvGs96YAGOl@B^3+rHu@T?R&Qu-)9-Hv?9 zsqbC_EY70A&M5M54FF!WT|=54bMEJQLQc%b19g0d_tbw|+%f1HB5hb)8A}UD+s4nv z#j?5@;y|~~vwR>%&G4Jt^DkP^eS5S8Wiyuu04f@wn&vN_dM9I((IU`R7Ic}VR_t6~ z@YuVHPpji5JoAs8(G1HTpHcLkg;XUy&`K1R)d%sBb z*SF7TlG~aS*w?1xXoB0O6GYoWBbZmY0z}()7wqoo_-_lvhlAYPxT(iq?hCMuU_y#t zcTn(8I~m(9TP!|M`m9u1j=ol*=+ z5uEKn=3^$K>`jvg9eyrJ8(y$&D8e4S3rE}hW{;e?`f!s|vf#^S@cu#IUm#)TS=h9O z>qXT;xDbk7M6xcPNxE~TzCwP^!4);6neoi0Z%e^1$1r0;qu>Pft26>vn1NJRVQKgR z*aZo3Vn-8>V782htU)0WQLKVTFijp9ksoa>C<{MUgY@AC)E=iI320e_DUW0Xk77?9 zq{*|Ru^MHU796Wc1vZibQy+!nu8rxOs2`|;Z1RPviR{FVG#L0nYYgIJL08+{JVU~? zN)iarKAWa+Q9_Wt?v51Pl2PY#ZxP(cN1_|V^;X9{U_x>u@29=UhyHem)O||3LIM7< z2NXrKdG?V-=wv1Co~6;cOnI2tiMDY5oFFE%g!vQY!f>}j5eZxL#Z=-{@B7Sj+!Z1E z4dZk=hV&1Uc_k66)Ov!6fYj?3w9S;Tw=rX1UN?o_82UrT#9LJ zhurS`B7db&?mP8q_*R|iI&)L;HP=08Z%6xn0|0+RkjhB*UU3d!6#}ytn}LP-j`&RF zGz*Uv=lc68fQR2ASwU+z?Vk$AEboqxe@${11KS|~hy1(UkRQld3mTL?1)8 z$TS_l1DmeZ>sH)266;Fr*WFxH2eP%!AhRU^g$>X;sr+$4BU z9TT9ae#wD2H&93Ui>UVeXC(U=t?={w6RHsit8Jr!Phxw^_2^aMO+jwX=kOojysL75 z(uU>ad=CB8dUSB5eKoM7`Ae?rN6)LMoNV7}zh6qh2w@Q$24}Jcvuyb>W4xXr1_7--#Y_B%{_;@FWeD)1iS$CSK3(8<8P+WtgCV!ZdNg*K6~h7EDNir)-T zpdW$4r43GT;04l5@g-}|MZP9!^3#I)XE1LC!LM}Z;NlY1naB@yCICW=7K3`A3W^^c z(~9Xn?A?eoK=%vQd94;wsI6w(Hxfvyyc#5YhVsBI(03`=g&Tcw7N*FK{a|8|{2;V5 zAJN-Q;9HQi5kzf*HpJwe`6XCu)!!XbawJ7W!zwoVXxci#HCPHxkVcfS3vuzM473Gd ze9b}^)2;*?;SGbd(cJ80AIY5O!6jIOHmEHpqm^~VZ)XZ$@+?PaqxA*ZOHYM=j`1O7 z1Ar&K4+j4)ga!>321$jej=PP;CQxQmj#b*S7m1QVY5<|!IA7jxJaRTy!uA10fq?iJ zW%B(#-Djk(+hw^hP*9Ye%veX^OKp&DN8t$0fJ*pFvr*_OitZxRd2z?Ry9k;1QiIFI z6fRN$1!_4l@4*N7+s<6I*>9gDl2%|4FCU!c^?ZKr9&u4AbOglqPd}D`MKns&9N;h{ zt^!n$K1Da7Ji_!3D{ntcAtzC~yZ8SBm6+%IT!cc`B>ya{S09kt0PmwLeK9-&0LpJm zp-*V&=5GhO%r-kpb?`$9Okv}^l0o2M1-^aDr{Qee}{BNR?|Lp{y)$YHc+FcIK3a;fiv|I`qIg)elZh!k1 z=z!8zb?>>=r{&rA58I^5%pc8=)Fz>rUOo3gAQxA@Xc#`7SdRy{_>5bQuQa?#w5mzC zkIUvGkYgwI*_hT6+2%ryL$A&gMlO(BXku)CaR_&NCPjvW6F~sWxW-+Av<})!;kriK zS2|I9jfq5Ymu+dr_MnwFA^PkicE{#NePKJ0W5=~e##s27+?WqwKA{V4C5o?l*lFkF zVTMNz+yo+hSJ1@!+mxZXJzspl>z{6S%7FM2rE$Z1(#n+RF;IE6 z;!t{b#lWt?aO05*GTjrfiYivX!Z{y{#1@)DhZ)o#lS!=DBUo~NTV~u4^mEf&9wePj2H_%(ebs7G+kS6~0tRtu7T~ixT|pQdl0$zujh~m#YAHTu}b)erqvT2BwV*5@_SB_>0t5I5M3o27pKP1vQ1#d>_8+~yB6@LHs78?mn@jV43m;VPFXXTO5O;3ozpQF?R7$~1VCx(z7Ca0t*2a>Cgtm6a(s1KZSo&K1% z63f~Q>$~I}V-02-ucR)r2<#MQP77aMtc%Gh{hq@*3H-$}4;Mq*iz-MdUT^)V|CO9} zqn_Ub+u>ci8~sy_@0B~S+H$IxGcPWnXYYHhHRcP2bx3G_x3#VQjW~3kB=hy>n>q(4 z@|+GG!Pv~-NIS`%%)LNQcPA>_uO#1k+EUs@CHoKzx(l^VIh}6NGjz2dj`MDwx1Wpz z>O$|HM6t2>>eo1m^buZ62FXet{*k8R{4Og$7EY34SCZ~`g0o^BRUJC6qG2QH6OD(} z>ssd#*ON)JA6x3l_^P;kqBm8(;3UIp1xNQvznTm!x(+&BX>AZ7CvQttoSvH7KPTgR zy9O7b3#EM=`(uRW5Um)EPwc zde5aePU4XhDBVDm(^uKYzA^Ea_?FyE5ma;VgF5Kx16>RG#Pb|7$*u;5uMmOm?t%9W zj)B4;E!uK?QQ5+dV5Ls$71(qV)0bDS1UHL<_zHee9JI3d&kxgzb{*u|XUz7k7V%lT zmUSLCTo8pDsU9Iz_3rr_IN3ZzrppFL{%|+&_JW1JKQ@_FG!wMwR&efW4sCrCl^qIp zPuBPemyrIQlrS^QwlSjjKKFB9^roSE6!}9h2wC~j zm~2ai+_D{$6=Mt`P5JOj!#|HZRJV4xE!5LU~$H8B?o zaBzS)?o{j?qA`^v?YGKQVp_5Zsvj-f zSgvqYl}lw$YSobF&<2?h|7<<^frDZi1Nb$ErV*2GX+NT(gRk(H&sNk+C84c$1b5K+ zX)h|QEeYJ%u6$I957d<1z}c17(feGZK{Qe~Lvk1g0#B$jT_DB97g+y;-Cto5dJ#!N z+`4o?X#|QG9kC?|0*a7;BQYr)q^t@Ug9sVIyC-qxuP1+(IlXqJY{(>Qu+Nt!OIZ+3rS8= z&2v?)Z~#ODrXo9Aw8p;;Zhs$FO82Kn>7-$G;loWS42@RS7%n*R2N34huK8}{Zd1h% zP#BFUbEMyRwLLkIBm!%`IN5mUl6)0i&n`I2@$9uZM@(Plmknmv7m?|}JXGg&1;C$AVQ|#0}g>Q>F0bX7Bme?zcYWr3wkZf;x13x|`RuP(Lm@_qgyCW6cDzNaJr|5Ck# zGEx@rx%SGk4%nL;_Vxy?2zQ0jrhq2>mwp4|^k z3o+D8DmftuYqXP0G*_Y9LY$JI^Rp1>tN~vDxvSKG%fj=_=2Xm#u&kC~y$uGovY3cN zeUY*T8-kl^Nr;i1*nn+pgPEk`dA>hZg@wJB5ZEd1d{nJF%8Pb_roJ|Jt?6T4NJOwP z4b7qZkZyZjm`|q%#o2-BgHj51wfie$tKXrehhwpr3n%dz)rVw zz^wK?skJ{!#F(P5`J!Uy&5|79VLG#tn?!b5ORpVgxnH^RVbFBOdJAV&6A>@ouvI~v zB(-YG4sYYOD@sj%r+A?6SpGZeScEicLQ`pB{zglGhGkZ?noY!0$oo}LDMr4o2rq%h z4(uy2O}l8Hqcd?RQBGC%7KgxZl|k7*H8kP?sj!1WonJr7)CJY zkbUGnG#wc36cNcJ7(T+lD!-8SAY`=l#0-2SkcnJ1%LkKXo)1CGea#x7D|RBl#PQ%b z9|%e|7A3Iz3)y*ENpYBY8@5_$tovnP4zc%Cmd;`A%LP$=ymLhu6|I%7kKz%)H8s#h1Ch4gAeY8n~#IB)%i)t>+ z!>mNie*}wSKlg*~$4{j7jXgyEQ%;nHarrz^)0JYhbS-xDcKUr7aY_|CDj6cX@Pyy* z-nJ*29i1}U`6U(eDXYoslUSwckSIMOQ(F+pGt^4Uid7-Xm0*jkD7Cdbj(FerQ;POX zUCbY=nYZr8`#1Awm@k21t*p>_rk2Xr>+rJX$U+U_K>j1BJ#@V}(4!;O(qF5tt%S$d z5xU+Ay_gU->GD&~Ob3Y(B9w;nS(5mEO`YV==XuhlgMWmNiIXZXtbV%P z4JU5eYVC;uczX+q|kf>JwKB!%R=3d2>8Z!OS#-O={dS@4A%x7@9(qFx@b zT@aLvu*atz^JvQvf4Q#-$H*4oob_TgT81dTt*U((SjU`1;UaHuQH!RE51G#U?aQX0 zO(Jde#M)_hEl32t5>1)}zyE?wphR$4VUb+Gl)p}fI9ai`cUAqUSfNuMb=Owz zRWbVsV+n!pa)V_h{7pPkrxYP*Ex99{2zPLLzYCg!?#C+ghhDP{aOtZAEI&U3reEe>g(vW3jhc(TWgdTYJ+b0bHbj-q z1Y~P9Nc-!t2h^*`=YN43+b3HKjloC!naJ%kK-RLl*FJB)W2R9~z3mRL-%N3v{$4lLz;rACz(I&4`mcMrLBk< zR7yl^8S8(yI%?0=7bxo)F>9@|aT9h8pG+!;H>ImR42b&ulU?-MM82zBR&;)*Tht>~ zx@<`9o2=okt>spHvZuF8_9sktQ-wK$Gev;3U*oR8$t8Y26X|CRA`ox}d6lJEuX~){OE4Oia4H|-o-W?8Azp@FPvpxvylhJHxC9y~ z4MA}VXe7Z`XRl7<>JYYHO?qz7y~12i<6_HnyjtiK?k4a}kQi`U1jJM-w9rM_j}whV zh@|ug&nM=}vwQ_m2c63*3S_V28S7TafPlR8gP4a%h26Qu!%9s8#`M&58*d7NMAW1W zE39>#qU16BfH<_r^-yYbsitT<8%Mxh3xDcSY5fEP<|g?{jg#Z9_G_zVn-~w;H|~ly zN`+A6kus#%wO*)VS3x~con>Q70zy?maKr?3b>>@QpD`5Pc|Bzev|WPN1hB{5Rf$5* z3i?D}1>lZH=617MkH0%Ap1@ z!kzBi{yfj8w~UfCllGSyy{Oy*f1j4Z;J3caNKd*!eNO3! zt61dNMFLcGI_cB|p~Wf!{7D2Tlv^84Y!y<dX?N3IcKg~o*nj^bW zb!)Tm+xLZlf4xx-R--O^BH~*UK64l zyAD6M0t}GUtT;yjc6N6Mpl0y-v=9OTlA!c|U%4xtXkP^XOc;ZdLR+Ef!Xp^0a?d!P z+7Di2_jE|)i#TuTnp@BJO=AcNm%OIMbpE0aaZ802Nk z+1+PlFQxp-W>>HFi0Aly=2MB_J;Uqw*$K;Mr34!r^Rx4B3v{W>>-Q%H%=+A|86!VG zY$cdDcJ~~Qa(L`9_<6(81+9F*xN#qYyzfe#NSgFhHdngyMlWtm5)MMYHhysFU=nZV zWyAqHjafP>r$Sc(Fea5OBlK+l2uA+cum98F0gf3Q?il$_GGUWiFEB@at0Mt^JnBc# zOipRk|7k5EqTgz`+>BuHG%1HkKyP&)=C5d9{v$$XC7HUX!1B?&@6vYFNdS*wlA9f& zXc_J|o5S0%`i+_ll~2??GPIirgTFwt^moDm9Uw=wKq>)z3gYYXYMPu(-)@vAh^!Qs<4Bi>%>L<(3wSUd_VBdFk4e^E|M7y}EhOwZX=dg05Y5Kl!&Ud2w3QeW?ogPP-)`@z593zCUx@VEOP zrs!+S4|~b=&6q@489v{WFrgS8qB8F7`~q_MJ{u>1yKKXv{yTh2K!r!3dWbSwz;Cs& zB0y4p=9W28GGn6GDHQwO!G4y;_5t-fY?E<*j^+jL)`xGthk3MuWOWI(Dk76}prMq~f+jQ>-Cd@yoe#(sDY_Q>HCe?~+d;W!t6rgi8qyys{VqB_mI@0h`RlYyyJ>@|rN zg0W-twY7X7H%wT*AJw@+S}QDZyOnzpyX~usi1LF;57FXg)MDG+kbXToCH&G~qng~TgvZFgfc;!(u?DzyWv6l-RELfl{Rpj)Sj zjxL=y{04131B@|)ATv)a?AtrY2`FA(3R{F&J#m`pq&(GS(pJQ)mx-dRHQUc zjtJ;budU$A9s}pw>IJ4C+2!+IL5zTaK&Kp50H6UA$%K&y+e?3k9`ICVxhJgQPkJM! z0i-vo@s5&lo>NK;5dWxrygd}joFmjhsbT+0B|6_Y>RfliD#&24mkep!BkDh4?4E9> zEf4l;rJZ=5!w78g3ks-~Xe6dq1AzwQg{2Ve1M)5L8mr+~7YD^%S zJ$`@FbFC&v*9eQ!86Z66&(NI!*SDBz`2j7Ib$9g1Xwbc6U82c#*LVYc?@asH-|v@y z%u%@Th;$;ShYS72jz|ZLW`=l?>l$Bn;&8SdVz6>vhY9@%LZ*{vM93rPc4p&Qic1j7 z>}uFOVSIHV)Om!+dE(Z9orm-z3t`RzF=tmYN2e8wlVp?0jn)kfk+{BS>tDpJpgw0z zUp=wLCY|bo=ee*xku%SQ+sgU-JU-X_m^zOf7tvml-7$TZU~XygG}*WKc))8~QlH_% zW@=1;Ddm-uZ+>bd&jM$zHlymQ_a(JAX}Z6Q4Lh!OeaQ>AVsLr?O|rZ&aI^rEaU z9#6JrUM@RvGWRwinK!qg%+$jO`Y5j`*S&qUms@eQMrm42eF@~53#$j0<&^6K_a>x- zIBI1~zg5#E;s8~WZ62!Zn@za{XmMI}(i6q5`x;!grAe){kZO~sQCc%UO`^5M^w!AG z=ia&z3$iQ?bi#+Y^y3frE+GdV(@)0aP*v{qEfw_9m%{}IklP|Dw}<@BaA(gU2ir+( zYaBNPN8F_+PQThExcw+g^8%taZWX-Qr73PI#OM&FI*0WUT5r%Yuw;%xLF~u8#`B&9 z^t(b@)3|!C){UC*2vkKN!<+$x_Ir_C>7O$~q7vatO6MOu8v{C%Wf`tZ-J&lk7sfcv z)X0^1e#C|;5oeo`qhw3ONOa`aKp#V!6*o#`TB!LwSWRV|IR6jh zF(*pWsP*cxUY>``mC3F>N3+dhV#%A1d>Ct;{G}vHN=WKK}()HqSnT!2fSBZWn=6FNf;a=MM0Jn-xaIEv?LJbA|U~0iyM`D zURZ+)tM{}uauCkfr7%I4V9&g_)>j+Bkl8z>PEtsyOzP?CbPoOKQz8PdMx-_~Zl~uHWcA3<;@`z;}m)Cn&y^@H$#z zV5`Dek3k#pn{p+1CpV7B~LJA7lZW7dQT$nF%P;|3TGgxWh)4M0Uezu4-?Vl%)jkN&toV zcj;m|ZKB@hJ`A+RH8$9sE=$53IWX?3TV7_wijg|A20yH^qRiBKkW%pi{vfl}J&G+f zO;r150UpV~v@=tljaI?wExSz3>0)N6tv0#NWcv=_eJTXD0^>`Flw2wFE>DaHQfTwb zDgD3C691fyS*24$XU%8h9B;rguD6B@qa|}TH)c-L!$~RKhEbzl6O1X&YX(QCB9MZH zU%69k=}>&!1Cg`h*Yr%ZCa{EXUx0!Ll_u#?_`W<|v(KOn*ATj8_3$~Lmzj~5X^auR z`Bo_4U}3fqn%tc~LLJQ!1zl#UM7*{bTP1KEch}9*xo>u5!x}bsI&1H*#2~mLG)#e5 zOs4q83ErZ>Szn-Fp7V5z2DXho-!HN#tngjW#-#lohu6JC!DtfE!r%<{h)8Rg>v{!K z;`^#-r7s^KXFFHgmZEAx4=?qOoOo~kPbm!b1axEEmRJbyRUtLMn3*;av!dT z{TiOf84s)*+U7M_uqS*@l@le~_)c<J1R z=DFvMI~vgB;qAC-#P$Uhz(BNpb4P@yO4Yj;v-kDYVfI21HOC6eY!ZHg#>>)k=SAQR4WZLhP|;S@8u|LIH0(Gsj3RSMXcRrDIg3g=v5a|8+@QdW%W_al?ML&51YN zZ}%UuNDb$%TCRh=%G&Ol3A~0z>1I~bz{9;vS(!(|kO%WE3IYf+HjPk^;ab2Jy(+TP zU^k2sGXdI_uof|X8LLdB_&IL_Z6F<8Tp+Yvt9mz|ZP55zUzjoD$0>R$rn@&6DuhQu zE)4(zZLOB46(5t-aP$~j6rlnpe}VW6PK>@}_9v5HG{UR^F2VIlSMde-w<-VQL61+b z5?*Z*S)FqYBVw<#DSm#OsOb87r8bWbUBK%o*T8%G)!gJP9U^(f7;o^?iU%Z|A*YKm zYTF230jJv{gqT$uRf$8IObx@8~>*ttmY&cclc~ zzv_s#q&*lpxtx3}7h(SwsJnXN1T`W|mv7Ps#xYRjFGl*~ARUL-_KhxE)yL0)$PaKIzgUH@z>5gsySwx$#vMwFXc=++n!6h;kxhgeOi3Jc7UR)=OZIOQZQ9dlt zALnf6JflG*o_Q$jTRR0K*$b+pJPf$BilQjK(Z4U4XsrBgZiT2tU*3@uX?~g*wj`SW zuilM!oz&1Z?d%9avMkG!*hMMW&3Jx#OgX~*Xt8+&X6++WGU@C%igbv|Q-Rh(aZNt? zVWeRxsoC9;J|p$u;ThwA-8fLNEw9wL}IYkhVbR67bwE$&U8k>RA3 zcZ%FJoky>NefSvN?AY>}qpHr){A@+#bNPOVAb9d)wW!~?AXKni5?k`c>LC!2v7O*r z(&IznQNsPPO+mEdN2ul-)HgLDkpsQ@r?APNlHc8<-U$M9o*GBI^^*WO-3CWvlcIxr znYSJj0oAM@A2A8f)w*7e-GiO%vA7RYN89%_S5H^BN`)r8Y4pStl6{xC=XX6B#4E?` z9b6!<3BpMfDWzX9V}sqlPB*AXWp#641w(zd)xyXf{z;v&{j5zxUS% zsU$~R#idYNYsYXJv*H;a^?h*C`e%8+5<#?zobPH;quj-mJvcy*IR|!se=#WMqu@TV z=%M&=SY^?Sbdk(R?{{ln#ciIEXjdirQ#{hxEU|1M1$k}Y}!B; zW-=s{mZmB)$F}G3iv9nAQ(Rug0zKg>~+*sG!i9y@(hww@!VxhH;N9B5hAL^{&3X znD2)IH0k42isWzesP|)bwXWP8kFY*}Wf8sugKFbMPx|e?|H^ z4?Xe>bdiJym6GkED{uP*hK|@Uz8qKfSw*QY2J-)&OuZ$%97S8r%Fm-=wfonWC~e8eyNb=KT6Ff` zanu!YS9HD$pZ^G9|I>U=@lW*RQtlb|qnu6+a(JZqHbjcT&z0WyqwrHA)@I4VXFVn7 z$8m!D_xi-Xx(*ya~7;3z0>&Yhs`R302EvqSz*X@G=xC!Yz5nOvhb^BCY_&M`yKi8>1l81-h5$ z;mRG0fff{CcZvpASt0Zvl+=THc`ZB`J}Dah*eV0wAO|1JK_k6tUuxn2gc2UzN1pfs z;+ylORfStd08Jv%;m8~3ql&3;ZV46)poi=Gcr$=t2H5Uzl+l+;o}E)bi3d*EqDriM z_k_>D6H<+VCusijgu04r4V37_%(5Row*(f*HS;ju0ep%Fyv7K4`C0TeCQ#BWH%-FH z%EcJb#GwH`f;>?3kcz(&V7`4u*$}{pQZtSE=clydkP`1v;O%MiC0QrHTlbeLFZIm< zDx}xW-mPLGiZ*xd4f$N)?bEvw_zC0{!N8zQ!H~zDB%Y;EQwW_M|m}0`Kt+;O>As zw7!N2l0%Q3@Rvs(%G}K!t6S{lKCAdjx*g{wBWZYD|bfJ4d?Q67dp>KdILC zQSp89_YCRN;)lOi1F9eDFV;i~5C;=o%oln)ttY{r?)QV!-LKQ;;zK4|m^Jm?mP1S` z+FsT0$p~)`=%sh&(BT4h@GQx?ot)O_F6zs$xg)?To)Zi-&w&QFQ@ZS^0hL_qAX-uF z(fanc1H)D9@=3yg5hAw#n9Kh(XjBI5Z6PX(w&-=gx+piftoj%P zMiv2cai1CZ;NwLW&P;AeFCt2s_RK~mF@l$!$590E^)~w;r#5d9Fxt1p;3e?Sn$IoV z1#{ju`qoen#bWyOXGsQAV!6U1q=a9tVfCQX@&}FoiGlys84{hB`%h$R2zT(z`~L>E zH(AAu4fhyGWPD$`hL_sd*v5SbM=ZeQcsI(nv7f~)4~IMsbPO-HzJ{pgEI@|#jx%?( z`3lDZ4}R-!hoxRX@!J(G#?SAv{&#<8{hC3QWkA-CWd8yLG&AsGMJ}+8qxG)!xhzqw z&^DbuAasKx;&sPuNnLSIDfds8Pkn_H9#y5P)jb7kj|QF!VC53;v3emF ziX;3i@)HDj%Zru9@%r+@U7sStRZ#~JAO;m)g-0uEUYu|D(z0UXE{t3Z8BK>d8WPW& zTwmD$^(XE6=7422eo)&5cQ_xU24j;LcLsb@Y>z}al^CLGIR-hU3`ydp z9%*aA{w`VG;rBZm#NBV3f{-23!K9Jc^%w_Xl06>Lnb=9tO6?&axEU?OKOP*xxB+sZe@~s|nR@_ITcGB9%0K-L z@efqk0tmF)iI?9Qj%X9MrT%u||LNVE@OSI#KafGMi9*(-Aouair;2*#W{32NM;lB* zY%?Z~5x?1T#~Y2#&-+3y zq}C?RxE$Mm(6ao=|>cR%m z?g7v|FpSF)o%b z7MJPke+Tu!Mb&AKrE6P8ye;lFj95xH+q4bo#atCxFu3pwu4>D)-%pv42_6&9mg}1# zY+;Wd@Fd~cX4}W$|A97t%$6Rxnc_{YSwyf)<|^C+e1h`$Me!PweO{dJOd`W=Z;WiG zIHEZTKOb~^7~R)fNZFo7svGYKt{6D|UV5M!SDL}?j&z`Q@cwmDgR$UHRWq6wM)Bg9 zpgBfS1da(ciW8$EA7O8d$M{AlJQ4ou2et7`n!QhkOQ26|J38B%o1V*gKH&7Q}{!35D$$4L?=^G z`r;YGHuyV9z1PrdpSb?tE1GVtC-BMC2o8^~gAxvv0BX7&V#iUAHTUPKcv!+Bdj_z$ zVUC3#A4}-h-<@?7W`S#fAtWGKpjoVFENsL~phxQnF&?%epzRo!85#IFj zc8A?zGoY)>fzhmKsa&z70ZlHQH(fc~uR`*hirt@X{xvS(K`doa-Ip3E9n7RJ=`0O7 zqLOzxNK(%EZKlV_Yqf2re`Q)q-BVJ^v{VKfwb$y<|0b4xO3@=jcbL0}hn%?sS)m{` z70u7@Q9vWwz4opzdw2+D09pas+G05w&PSsf0Opxg6lBD2ABf6iD52Q4X{^SbuO0+zS8znZgs(a!`PG({?5%V7da(T?$D z!00)i#1a(Q$#|^rN_TnOh&|t&Usybb%BAx_iss&F*+4NURv!BCt^`+sEMPJ}`+PM? zo6Sw;`f`nC0Sss=U1MA8VwHL+dbioRAQ|#?wu>^$$8I)+%-2AT5S8Gd?t>@!`=jPX24x@DfxDDZ1SokhDZ`g;*188MWIz_pT*j&*an=i>7E4{LM#f)oMZ|&>m-&l%3E+G$oI(V6Hoh;f7H>+9|nozFS?pg1v^sdAvCML5|xf&1g z%`K{Zn9VyT)cLGbf8#uxB-uK{%A(9}84+#w!? zq1XQt+blKyMh}^QIP4BR@BpHvO1cAx6)bknM6eLbX!I`IB=J*FxAw^Cr}c5#l{2?( zY0P6RL0qS2M-mqqooPHXw0^KH@xw1*iwMhp-NgVT+k6vgjM2?!(uvSqjdP#x{nS?< z=(-n6)XL|3f3Qxs?@qp@+i?a&c_aRhKdcw*zWMe`cF7YXP^65H9Yb$>2n^22OD}Ut${NVn+6J$l zldgJF+Z5I*JkF#SX3~^L{%}W()=t0IhG$Wf{4&LRHdht2tC(H-Der>ubyvNFEyXb8 z3X-|s5NMZ-=(sITP$r8~w{u|)!3b`&nT>bt6aj2HzZ3&?nS$d)VJ5D9L!ejiqWRR$ zW<^!U4&2TGz3H{h+0ydR>UrN4(ucI(7G-~dNbN-AZdsIg%d~eRIH~We2g;vaYqdU9 z!kO9^FwUu=(6!Qv4;#KIN0H#^i+slb{`E`UW)}3~M1Sm#^H)gLx7~X!$IgePI<;u} zL)yMLJHwaSpYD5u%Z+k^*eD<(G;Kq?hMGMf#;R9v=El;3oEShe>%752hI3iUw79&n zttT=!%pg&+k>_K6(Vkt_Vm(JVBY^|V@S$?5P~z{6bhtkNQo;x}WpvFse#mpG$v(WA z#*`D+983GV$$hk?H#regP?~~d{mnaln!s=ia*&G#deaR;`JQ{m&~2piBD$r?qme0r zQfiL&U+uBQvZ6P zs2+VO@b1bC^3Ro8w6RMrl#J)rYQ8W0UHcmIrG9Qy0x0(`+Kh$%Uxl1)Xga$Ge{8@Q zU{6f*qXZ4GS$+|4WJwf7ca8ENhgA9n)M$hBY|}8}h(Q@B_|nxx{>$(5DU7ei4~dJ; zidLSPW5!9`0AXYcy&H%L{{#pnse6jHStFRdrvf3x8H8^JMy4c6(y+4#QVlaG$P3T} zvI%c*Mjqlm$I7c8kdc1#i;s5ljMV!l66m{r_oH`;&E zkhEfm#`1xYsLjr?(#cuLXXFDS$;_7GmmPqm*pQlc$V&G*Hq-#9I~fEfnw1$r%fQOE z_{~$dehs5dkzy!GoSTWU9rL5@CFKqNgUd_vi{fe((SZ19l5L@KDxoiNpQBq{XKSB- zmMnDH=id98S;00)Mz%C7^Z*%2*!Yu?*Ag76Up;)D{?iA{d|d396WMS*aPk*OLruFR z!s`Da?JMJ=`nt9UP(UO^LOPZ1Pk$Vr*nttuP zJaD?YHuT$o7=q%LIuOl(>|jO;2XvGh@hS-dZ%6;Yf(8ZVGh zP)z&QxPASS%<#uK8Q9AmV*@3!cNpm~&a_X@pCTNNi6LmOLL(%hEqDr56Pl>k z+^Wg&oT+UV2#8NTn15;vR6wYf2SLIJbdN!0j!^0AKk1{4=$~2?0b1=4vrP`4(I+#o zRP{>6uG+g6&+-=Z1Tik=VFZJt?9XpHxOZlBU$J1MG{iY{Cf`|hB=go&S?Jy4gMN`e zW8(`J*RAO$7KkKQ3~(zyhJTLPVKUBJm5zrZ-m6%*rFdr#I-%_+U0cGeNws_BgxrEL z8g{!URq`qZQ~9(Gp6g;(jS-v}o@s|~+cz%t5S-jO)7}~@ngFQIpCzfAOis}_({QwQ zhO?hu-i`bDTE|VIKJUu1D6Y#ZSacaf(v{tn3gmes!KzJ#>`Wwt7V9&r)?W1Q3cROVTOT=$X*?n3%&%JjmlE^$ zE9Wia{Um=c!q}Uqt4|2AL`-o_id))fwQO))4mExR$)<=qvqdhjlBlbN%gr2^cS-BF z7!X!LQw6XrQJw$@ZU+4pi!~)t0+~%L%#ajT>IC&fA&rqih!@6>JZ)D6imWfyI%W`I z(3a)*KmE0Z*_X1NM4Qk01x@568D}@!tu`5S(+RtXRzNPf%c1R&V@x_Vzi!>O2l=@U z+3OHVFVD3RoovUekjo7^i_NLd9=9FsJxUz6c18LGRY~C^;x#>wDGrIJN9#5r^B#|E z%s2o87pfg;8u?4xn^eCbHq&dRT4&m0W6lwZtCsc2U2e&*rwLjzKZ5#( z)bUYRf;0!*N_J}-oz^r1_Y4^CTN~aIxM=EEq$g68DOhKdnCP~Y}u?zqSSBx+}tMd7LP0}Y%KR>JmIc%wJU}@ray<~ zIIq{@BLxFdFXd8^V!LQ4#WxsXbOAim!B5j=8c2jiq_^zmgbHfvnT5; z#aQAEMK4o8YGl+?o?UPtN_w&xDv7EYx3ml!7&XTgc$^#4? zSkFtJ>~#>ys(oMN%RA}W!Sok3VE2#es4AW(BchoeSID)CG5)A<_a-Y-nXT*41pO^~OM>wimx z!QO=@_~c1~X<^+A3kK#d2vP#=5-P1jM`ti|n?K;i(PF7B&b82)Ze&oQLFJTPVEDq@ z&Jw}uv<`vy_ddvP?em@md29Gun=*a~JTXY<=vFdk=}f7=eU*h-8S~{;yzN$-*6=$j zA=}<}&GF@_G8xg?v1mdbhbKj~!{|@xmhFMIZ+mTkyv4JQdtrM~d)y`Z2Yu~z&xEzH zek{RVQrEJ+M;*$;rfGYMxixflurD~EDF1UmIx_pfnti4J|7odm{uruU zf4U^NG{I~Ed_!IOWCP8^TU!$dRGr>I_SoudXegX?UbF&f?__skb%}M9QT(lyo`D{X zKu|z}o&?qG=v%6|YaSL;Yx{sWg_F)}=Jks%^3}3-bLY?WY&>K{1NCy*1asYoCC#B+ zm&#HiKU_AAQ~8|JPL{(*6f>Ao<|6Q^fNiyur_j@U zSpcnfZuZH{jm!(}nDBWLp?38O#H8?T1!gZC>gf|f!ENWSMx3qJL(&w4_7p7bo>8&} zn0>>7D5OZbi@<=n`KrAwv2d=_EDy|$#M!wviFn?e6C4{S1y~p0E!00iO56cfcPnQM zq!dOQ68bjMfBtCPBUsb!7TlSW7pYhbX|5xmRU|rs4>vB~^N4((bfy!+?TEKC0{y;! zX7@oUCg^e#4~l%K2ixP`&$oOx)`@<2gt^i94z2|h1*qgs9;6=~&V3tv9cYk!-_8Km zb^ioegR(4R>DMCAKT4NJvcZ!s1NJ~flJ?tUm>%w*B9ny%y~>JcW9z)l%-+3NGb6ig z#L;`ZJh4aFt?k{k8V37epX1gz=k>ZB+Vc*2t*fObq*v(^vT!}LEZ+u0GIR6(!MZM# z5Kjbsa!N!@6}7ICTaSY%1IAp9Z4n9L_2jA0Jc%YIlwyl>+eCYolkrxQw&)EA`yC^P z6UOw8Pl7B0TQ8fUrv2mZ17%mN>}ceuRUU zZE0v3WkgfVNkhY7Zvp4_Q$8WWJhgaN{$ZNc&voKF5BS>Zz>aPm0ju>ELAuX8Uul?L zkT7>dlQ~K_l{&?@zDeS=V^JS{cHuWp){~}a&P;Y>yIO%wZ2m%Y;PUV;K&$;D69zjO zItgD*lv}qm_~pGI_mX%g)UM!_%{|e#o9E0~*G{QTkP0egI{gl@7YH#FF&VcmADfKT zZizCwk?~{dXG3DAV~|Vud6Na}$D~P~D%f914`97KveFmcx)&{z&l&3^!$_yu%DQ7; zzY1yXMT4FWAEiyPGYot^JT@fth9MX>HTLZHog3WqOo$IGw#NA zOKtw1`g+UhRV!h1RM*nMVpw>Aujh)Ww8KXMY4_IjSpK;vVE;Dh$$E;sH1~zh&MlId z^AM%0G7fXz&OL1~KhI@?tWY1_h{Borl3YYYy7)UkJ?Px!ISyo{6qhb0T1DhL#CV8w z;Q5=+t((Cmc3bx;93tAD4=N%)F6u#B`~u1hZLF|k_h;qzo~pY}`MroLgZ3l`*;F1( ze6()yEtLA&OHLTGDQDGbyK#8tP-b?Zb(^${!?!lH$t;ZWVWe7e@0v!%(F(`KKfLBGI(}9aT_tn8>5;SVyH;5EEZD)Nwq^vZP|N#VVQ-b z@AjD?r1w5T_6#3M48Snnr z+I06eT2!)&!PBnq?O86!i5$N6Mnaq<#<2pDc#u#4jW^xBT!Fh)3=IP=!Sv1dNh2Ed zSh^ zNOU0b_T@MPwpIw*q59_1o^7V5>hA9X)*u9|Z;D7Qms^-hAw*)hApiR$>`hpsO(4>{ zY)x*`6ntVpA@**vg^{e>XPuCQc%Q!ND_+HU=#B>L1yVMi2bTN{YeYjy`5`KSBUqRU zn$b9qDwWk*V?;LcWTckf@sX-AdR8xOc|ZB!O;tF@#L_ZD$&CDvSbvN_G39QVRv+K& z(aQT?J65x$y_k0SzA0MZ*g6&hs_$Wudk~4)@LoDxN^8>h;4s&}05}GnMS8-yu+A3H zZZ_53;J15Q`|Q$(`Jx4|12{Y2$Gs(ePREYVojrAY!G`hxwpX@au(Q2-VL9D6c{{;= zkv^PzEhSJDxVCTRuH0#R;EB(s=tw;gG|#6$buK-kw_I`*-=Lp%-`a)^0Bn4)(3eH} zs_4Lx6sac~Ox|uV5nPjL{oehe9QvnzqLL$t)CJewpzn>|_MLmGvK^hnm}Q+wRpGMp zgdYx+an%T8KO3xNevK0BJ?po>BKV#Qjd~Y&uBWvqlwwEz+>OK1!sH|=ecdiG;&og? zgi-;Mw#MjUv}x0c)|Cx!Dpj%h4~GLo=c(k|;t$X+i~5xWpFj5wK2}ehT;iXU&yepC z8jx%qe>H%p+3GcfR`D4c6}*b->Ga2{2gF$Nnlb{-<`L;F2tCq&bwR(&fE)YiycTygryD?Dqmd92$`O_ zNs^S$H#!V!s#WW_rJcp4sL>8^AGgT1g&=s#VIq-_a2qV_by@hiO#M8puhozPtlRYZEWhXDDD6Z`6zZ3r${0xQl(t$icGtx(sJY-jQzUrsf z0SJm-aFgUMjPaaWomLMTZU9yvg79;>igI{@jXAIS|%e4Bmm)y9afV+mZ!(QnAclXz_36B+09)!l z(AuSctbKpGnW5Au+~KXC74uA#?R)uG@R5>bmmvIcO@fD)beAje;oVJK%4GC{xph8uvb)~ZI3TDKw|h7gQq5OH!(fJ8 z=;^Fr?%uP6TkqRhqUP96QrDmpzck@Vva798qLu<>>}u^BEU>Y+ZRbr!S5@;F4dJ4g zRi94SWv7^Rh)Wo_HWukxvGQg5j)B9Z@pN)iv?EP*pO>ib!BLso2w-%)mFanK^5Syq z8|5Bt36Cf&Xl|eI{naGEILv>HBOemMYOd^t-_Vgp`?g=Q`r2Sko3!}T$`JqO3ZFS9 zo<9NRXu|*mLXqxynHks?8#;>@M`EdL*vKn7t}?|)lLm>R%T1XLjouT07$e=$7<}77 zM-1j^&`jsIy#5~sgn=T2^)qg^FYAapBpdLvB#f-`^*0cc-*$(Sa23w4Y>$EF+3lf} z5F8`*Ywu{v-v{UCnuV)loDgUzRC^CwXJ9#+7-Z)^mU-T_5?bqiSd^Sij2nsF#>>V{ zr=39sx`i0@yN{gQ43i<&4ftLCV5cKmR%^S2`fH7mP<`Oj9ZsqIz8Y`1gm2~ugWfRN zln~}+n3AaNnW#az?J(n_G1cr#^?JZPw*C9_rz7E$pD%(pblY`)4+XdepKMOvZ|H2c z=gm671+H_tA;k@9X1I|OM5ve`YaF^XT9k?ak--9VmbO1gp~Nu-dK|HJLu*G)wAqz) z(&-X5bM6&*rkyyhUa_-m)?pdr_Rc3W=+ai49|;A!)K)%HhvSRLXqEmGwxbJa7eLY# zSWoC=ezm8ePkU$=b$;r!YOC(GWxyH!y~z4>c+X`}*5!;MZS-?Z;qy*Xy|AsDw1{lY z=8qQcVh#{zn^&2x8JXQpVniG3b}6+L7xZSYTWOTan=D#X33@~eO4`h-I2<+g9^SE$ zO3xP*s0`!Kr#tAvn|$?wCeJwnvn8ezdqpFvYi@@fKd7efn<3J`{0C?Ze4ZDa%gXSb zG2c<~hdPqP--osE8B$#RiYyeObR%&zW{LhTXq6Z|MSb1eWe|e{y@gksP?ZSx{QosubE!_c0?1$Yqe0Us&%rkP4j{nKKt0F;9JB-g ze{zi=$EEfT5d8&_R!vCYSc^b7iNAufEfY-yYBkZP+|y6AWRGg7|0GG3(0XPf5WUUf z*=e85#NTh^9eG+zIc^xlN2(VS#m8t4)e&c}9~H1J9d={osw?82#hOCYP)kdW7#QWK z@KBQ{+4-55KrHV*i!=^Ck-k2#G+ANKmGm^=VUU1mLQ=f{d92?FA~Q^SG?3u%p+ufw zqv^u_cEk&shjp*nE3g(2(RT!<%su$THa!`g@Lq)lb>jO5+s?hy>uv5<=kZmm*Gwc} zxNh_yq1x%j2!U;=QV1R*`XFKdXKG&Q%P2SxzY|Bp0Kb^DThG)%2b~aI_dpp;vAecf zCBpHIqP(Z*gPX!fSYmFIUzz+BDBs-8cE<_~UEM2x@V5KQ?E4xvB3Gi_yr`aNs)W<~ zh&NH+bQpz%oJKtI^o`0@8lQJ)MejOe4asTgl?kZG%F%sK6CrCxPwZ?>iH_$D?!qcE zck`=feO2b*vQ}Uj(sfrjaXKnRIwokVWn3+1k^>vzbU;1zQkZOdrV&kBAoVu8Mjhq> z0mrtVneDzJL!D*94A}>ko6QE0p{&B`Z$BSmH!&B87mR7v4et67ZL*;Eanb=K0o9=v zSCdc`^j0!e7a2)%CCj?|l*&U;7x65W(vOcoW7ePI=W5aAkdTECW4$$TpA?6Wrj4K# zy781u@#L{m@;U9nWX*9O}T31+ja(q?>Mb=!~Lc9boX|$#@zuZi+eNw+}D?# zf+P*!=<_Mt&EYe1vJX5FgGcA1`3fQNj)gA9 z2?)*F??I%h+S?}vces`wmn?@LnuZ=IRntta%71uT(C*FHxBt_qDkS4E_B*+6A{U`; zoA)IEQ88Hsxpq{hTE=&34IN(l1#zthjplabB^Hsy^$~OzVW(PXhXCRr{tq8IVY`0J zXNa_*_jjf*)eiC=NK4-8Mig}-KcoD1Fht+cg3EEwUh18Vgdwt%_WVrx{qLI8vfA9) zMGT_)7Na9jmjn^j^?RK6AjI)NFBu1P??eZ6;^?S4Fckge_W{(u1_gmr%&@`7r-9-T zd>mxwzwO|OWt`aS*u5mntbP```%G;0ejMX|L0$^`^TfvrIK}ubgKMFYEZYViH6h&Z zS-R}gY-Jt3`vSLCM|WVC7H*KkYx~<|>J{wx9r&_lSaN!zEaw&bU(1;>4g;1m9Y};O zLQjGZa=RZaq+F`JpqZpcUo$`ZklvCpjCJlXr)qh0T##8=M`Zl<$?lskl~4|!#t1zi zTC}=_{7Mm|@s9GYtaXeMcZzJR_!o7b6AaoKXSqwv+{hQ%kvy$pXv1&} z-to31W~3>|?95@N`6#$_2!P;Z?|bRnhtb#=>9)^Dk?WWF7%?ysTSa*aEyAfl0MXpg zh0n>u#%iyMu7=JuL34{CP~cAwjz0mK36e=y)-)WAAnl_JDy1(_e9oMS#u?fKh^u+K zXZ_(@m;rQwqi*0bfC+F#Yx_{2p;7Uh(zy&Mo$MfKl%YHqlLL64pSPg95sPUqLvP`uD^o2yaKs;?ZmiPT2xjk==(rcnSws0Dc+ zL+&edkY$Iy@eoB#CA(K`w`@g{s_OFIFl>+wc5tcz=50TBh?9PaBpEqV0HT@s`@vvGkHo;{Uk=odUFm!OSZ?F~<<}37F=)eL9NnTfjfP-so zzcl^#W#kgmr%k|&pZ~O42tw>)pAZ)<4i>$FPruq`&xtXOxXG7~F&RsbTNJO;iSQTx zx%d;zd#bGGgV>Y$!>zKOS|}5AmwQE(P!2UKjQ2F$YUfzSe%g&ck~-(q0LQq&F6Z}q z1wQ#Gy`uz(8|+82%xudR@+{*;%UpfJAaMM~6_(q9*6#RzMl&HGh1!5`#)IVk?9n=D zv^4A>=wq0dwcxNz?0u~?QJ!;1Nx;Qlkiieb4L; zwl|^CbXiT|YmY{JJ*#YIEEV7|BJBDlsNM3XU(z8xHqia?JK|37{D5zR!dVy&#Ftp( zKi7JRz8Yu)_Snr`U_zD%pqCZ=|<U zEO7$d)hdE?UXaNPIdYl`(8F+S$3W&xnoD78Kcz4w;e#BWbKuWDgYdL2N@Er6Gi}_} z^pt@xtuN6Fj*L*P(CWxy(DrFZp}k~~DXpyr-p4QC2pan3@SbH0^tHq}A7$KN$;Hg} zfQW>Kd<*;V5#o_|!`zW%7VP=DncAt+M&c|{wyX_ z0zdsr!l|dnI1+Qo6_2ilL3U*0gUjP8mYW5~rU0j0TM3^UNb4wRyBN3GnuLEXw|hrI z{AzFG@$tTEm)|~>rZo|s0g;O-hjb8Q=)w4NIkqKSd^~S~T^tKNqLLN~1cGjB>@|P> zsZHNXH;{vl1w%?ii+K;ZcSOA2ulpW~?13d`+_;l@o?;-g4uaLc z8o8X1d;iqTC@3ia@v}dG=< zPDfg7;JbRRWBbKs6x{QCiB*7by85ZS{pu37hw~kk`ZZ9IN zuPLg2e{fWI{zPKP4G03Mi2F^(&DJH|3iJ7Z{vm3tX35JyIza{(OO&u^?sjWwe3y>Vj45;=)80>C*T$aIeHtk36<~Xb$7VbI%X~RtQ{Mio2lJppFyMQ4f&hVpEIAZNWW{M8?KCg4z zvbWjCA&ctwTx82XL~zH(g6#+ARKE6hk%>xm6_lxH8E!sftr2~niG0fTWK^Ga)?M%^ zjR-}zy$9!;tT?Cv|F%uI0W1GeHUOwm<7GaU0A!Pm(2a1JlyQU=)UQYk(SrWqAUBQ! zNsHG;Uxexc14VGE^`^})4|yhlCIruy`SY~VI%)*fa@e1VI4koGA?yX}MbZv0>?P>L zDo8>w$$&grx4wAv=+)P_rbU0|KJt7T^?DVV;~eDa~{)qRE_F zE1nKq<5|r5-!`E)dJp`SBgc*f>g(eaO!L)C*`*Ja`0i*Mmvo0KSpN)ui-^8Uk$Xc>hZy zg8YAthykqDPT26I0?u=$V%{z0q84ON0htco4J~7|%$wGqe?xWHcdud_HvZr@vKd5(nVh zHen5pHYMlrw$Q>!Z^k>jX|?!#{5JpQsQuaFFQVV{KLiU&BnWhi<*g(yku`6qw$zZ8 zuys2m(8nJNzRP`Zt_;l0aP4rZL|f<0H@#Feqtc3>QzwOo9>{&oU-cJ0E7{|&2%BI` zRAc^jFHm?A)6PwDcoHifySsH>n5-+){he%{_|D=N^ks&^;{huCikzgcOtIt-r(WAb zRBzB!0f`_cdH;f^dLM&7m27hG#GQZ`0Nfhq3OlbSWf+b3g>KlbLj6M$Vz)ituQ=yK3PpjTj@#IDx5aIGt52XM>{0PQ(`@Qo+WFo} zF2%(iWz(AUr|^gn4OB2Kg|GV4M!B608*R%vz95H_GnR1i@pxt6z7V9${faIV@~H0( z&Uf1hYTFM6mN|M%?jbh_ysJf0YO1St-6o^kY*k)3Dsm^^O`VL5$!Qf03=* zB|lHOHuS^Oe9EOrU_p{ZxqFZY7={9*>vI5**&qZ!Xgv5L)2;gg3x`P11$C4 zCx1k+A%*3I%J53sSLcKiS2L1OkB zoaLP#`i&9f_Bclz=3L|BVY7Q5A2e!#by1PW*$mXL`S#*8qh)XMhR>^COZ1Fuak*jU zb|Tqtmp!~Y=|boHAOIhWN)HO3=o!X~g?wM5TC6quG=;awfZslt5OP%+6ER9Cq1e zm6bCEd|Zj2+3B|G_-?5D_aA3)Q$qzj+hhgBV<~`_sn}7ZJPmaHa+Z7UfD{eR!0Y_s zJkDWeK|6J)IneS^F(V{MtJC1ZN9c+||$T4dpAOHH)36Lyj#`mPv{!CW zM7evP`kdjJ<_8su`SiUggMI+r9CM$qUCGGzFQSE*11DO$`(%7ey&0JWHO|VFJ}4VY zrpgPgMwIz33$ApQct?ftUd4D0NZ24NR%X^Q5E2xyPJm<>>=gx^+5tcF%avVy4rI=y zAwIA0%7${60;~=HO;oJ$A3oUHPhdos8*#8AC%6Rn*VFVh1?Cw6|K^%kA5|Va3VM+8 zAdNap0Tj!k3Yt-KP^xM|3_rCM|+g5QFu4o_$)mC$q=z4FcpRc!)*eyO^`+({0^Hde6Ibo$+GE>z2~B$|sEv%0 zi;-5*oEyhOC(>;Avp~TuW!mI@xeCSc8=oHI&(B~}Q2;LMT3Ox0#C_s7mnXE%6po!s zk8i)|I3oK6$;!nl$iQC`TMS+15HnfpB3-}v)SI84{cK!=q@|Z4!P2aiO?&wP!k@XF ztoR}<&+xI;<0Z|Eg_mpMyt-Kl&spq3maQ(nsxe2|LK0&OW=%RBh(x<$*nk}KIMi+N zt=@Z!gXmunLL&@GYDhqh?eMYVq>^Tz=f(LJoxCKItp{6@l*HQHJe1FC z^UbT=+%Yrw6^@&4)dXMZoAHUPx`d!MP6gy)8n|*yo<48dpw^;)u9OTTqB5)TgEbCwi^s0G~s!4gK?xW`#%c{ zny<|dqEFX6TBwXN(z0K+Vd$kg7|SJ#L1PT;$76vwV_t^{X@;T#Vwroykg-BftkB9) z#ih&)eDBj=5cspp!~D!O)%ST?WAFxuDuG){zj zIG+k8cC^^I7{#KYuYn%cU6(*HP28g$gP!(RdXT{8KD!XzcagV!M*7Wqyg0ekNjrsQ zk7yFg3XC}0estCOye3?CWvhhedGVb+zM5_n;Jg|;EIf|&iiuvj-ML@s%Wu@Fv3U#C zx${IuG2Pd%;(GC0!Ovp$G<0v5BGbOHA?I3Rt-AxxjgrWp{nCpS91dfY z9*|p7%w_cocVXt_xKyHx>tnlLRRuYN)d7ysZ1n;uX zFnk`T0RA(tck39eV>9{#i!}B}R(&tE-ixN6FVCId$o)D8S(F}UF?+06qp)KesHR?Bbi`p!SN)-%U@ z&az?nwD1vw>vKlFW+p!EvRPQJ&9mXC#1rqpk`x}YdwyQ{;$H{(>7P}-YuUy69tkz5 zA*peFqQ#tW2m0W=efK`k#mE&?54E(9ixI;>|HKDCv+XZQu1nNkRpXKm(O;TsQ}u=p zrj=ul50_r9$val^3(ephT(q5>l*oOloLMcltGjHj7vGA(l+|Kbu`;vNxayAEBgiBf zyMp7#91qO1t}acHcdoVHAy0sLn{iTqG|Kq4m0lfOeNt+++m}USaqpX}TQ#iM$@rV! zjxE~VXMK0y?ca5|Iy2cVn`aXaPG#?OsA%22olOuOGkUNt>dS)hz9O!>+Cr##yQF%x z!kkV0%)U8zcE4Z#JabD29!bDYn0mU|^wf_e(+Z34Q6Fo#YcbY4GUR^RX`ZQ3Mc&z@ zPtV8e4>S)}3K*Cn2Zv6!o7*{+^&!g1aj@%Apq*885`>J={%&!DeNl&gcy^RjT2^`a zjY&=!M!)NWqMbSUUYDH$K_2ev-YEuVe;v$Fh`A1XOmk6*POed)B-QB2`O2j&r8?g0 z%&(tF@;q$s#;BR52!!cIxpvhnFbcpWWcnsl#b)>1FmbcvH)ial^b>Ghbhyk}T^P`U zBdSTPCf@R7q`!}OHCvC*Ng&^*?d?e=uIx2Uvo&V^9bfYz#AVt}BeQ z*_PCqf9o@Pznc;??K6Vrfq7kLVyN))YpO**e+Qo7llTsleq+>@0X~ssG!8F z!M_m+@Ma+8@qg>{|FPKR8laNw@1%a$ll%)aKoM^Ko`uaKpl*!;Rlmpz!TQEB0;uH# zbu8qHV`CczE3;Q=e5yoG7mI*8_`z?_4h#q@@hwLQ)8f5Fn2n3Y72HNk>SAn$ph?QB3mHyPls5OD&xm(~d z)8)5DK@SNAxtC~s;k`FGnqXhMulSAL6YxC^!HtP%y*Zi@7u~vUZGN8{r*+7ui(mQY~r)0$M!Qd>}OW%M!d&adlhAn z!&v;|mW_MSDbp&hyEvv)pZ3kSnY(^NXqSr7FlFstF9)~{LEZ*}d^L{7XDHxdU?)vp zg=TcO6W^Cx7dPB3H|~bt&!_3ZIw+tJs1y6@n0a$}`wKyna68|=k?rU6_hSR|AGDFQ zI5bw$HH^XA>$BBo9{}v8qh_QRtW|B@q5pZh16rpSY|@(|DU*%8I^y27vO*ysB;IYN zwiO!I$xk{?bN?bHe^Mfw`6z$sZNjy|8l6Dyn@ggDmrVrDHj_K;xn(%hU?+Q4A0Zk0 zfcE9I*28C_*K&npmdr}A8A;Zk+cIhQy+we`VX`Mej-=y^$ z$s3a1Qsd6O`0{?N%Oh91(8DXX^iuxDQ=25XP1cs&p4%`(M+6t@-D))#GBSpHHYUCpur5vC0h zptE9-Q0OEn%H}oJ9Jii++>)NTrOi~%bJ?}QA-7wb*0`X1SR>KNT7ye7kFnArJk>c1 zRm@VcOO9cv);Q6)r*Wuv9i}OxUr9E)#F*cx3~P$x)HY0J>`e@ipD)pVmj~wUM+Rzrl~PjHS1JDOk3wy9^dx6OCHMk5C{#GS-ZRfsq0w3YU{xxWW{4&nAI!=j9a?z8;i-w(Ah7@yCN>8D*XCRiH^_n;U#TRAMA~m zeqx-DM)0lCbzD9RATU?6uIvLyPA=?%Z!Do;U$Ik{qN?J}?3EIsJkIEj$PYuMcQ^J2 zOl;dKlLBrmQ&Ci`z5;q*8D)!0z(KT`BAa7cI23O8D)T-xA?a(BwzPM=M$k&KX1tCu zjHHBhiI|)eRhKd@G+qY6QD)H_LNFtcw-+jXVxu-o{J(=q%mGXScMOUJj$;ZXu!VMk zubDopetG7=s*ooGQyxqB*~WQT#x_Qksw$nX2swoR#EXQEt*x`Iz?b!kR$CNQPS@7$ zI;kU9*AVrhEwcBA%y`l7xb*uz|1gLp8BUI-iOrY~FRZl>yB98_>dfO;Vf(vN$lp@` zoQ&%^a8Swln|J|qd2`_Z71aV^_up?^2RbsSj3#KH_NVMdN(vw+1AooshzO3p#E*<; zDbpL{RU+NioNx~XC0-n7%+2k?^wU$2=q~LjHc<21agMSIyVXzCJ^rH|#gJJ1&5!_= z^SD3G)&D3NXfepbs~+M>!(Ghjsg-vwHxaw&CFEap2VXsNE;@N+5BoW+TAn5&Nz!Ga z7yuBMq1`)U%+S*vo!NE0HA@ICL}VC4aXImN@|q_VGU40w)J^K1lI1CM{eDSNG_efo zk+IF*Pg6U*J)6#YPY330`fQnAdxgp~?xv04E|f9rY1~Qt^e}t*&6!DI^;SyT2a;%q z+YaJE1Y5>_*$W#FKYo0Cizqf#9f|oVz1847uK4Fl5h?^aC1s!kTlpjQL$yY@l8V8&e1A8C}bQS9FKB^;YruH2;^qLMpt zFZFXrx-%Er5$%#rh0?uhw0EK9kAy6@Vtzr!=7)Fh>2EVdB$|u5`PV%YmntGuBL12G zhDnyJ+oMS%GVQQwB{!~{R?P736V30=$`Zxmaz1*(`3+|j(!p+{OO9%zc%CU~QPhL8 zI^lr{mO^yn>;*4gswXt-*UdxU`s1B}8oIak7|?H#bDFpOn5v3PHL?j6yDKHk6Xd$l z&eJLs=KvWin#eYLrorBiWXJ|db8octviq^$y6GEQ|HWt`{R!W!mAeV|#q1S-@bWgD zo$eW9w1)7=Nd<_@=)O?CK_;4VYfeZb7OR41w#{kZz&A}7ZR+yz;kgzD+a}l%1Y%gt z*&VIO+L)2v1Y3_qB3eRlUCRB8^0*9NC!YsM>><7i(-9SsOq0|=!u3RbGv$ltEOFo0 z&};M27N)VHbs7Z{z0qJ}-EI@Q#NN`izqcyWom84fq6P1_0Qhh4=X@t#XY{^9{gr*flGtxAaRbrS`m{I#^EZ} z;cJcVts#$6ZDh%TQ(HrFW7KjO{OLRj5u7S78D(y;`}@l0bEf77yFLAIM7@sYKR+_u zOp|Bru(BxC19i5Ej1OtozvV1rY7m!F=Wh3Os7O5WiN#CNmN-^DEW3+yiiXdmiOL^7 zhQ)0ia0_M^H{%yr^-;3Tw0DkA7T6r~b)oZHw#+ANgs-J+2Hn$x?`_<59&YWAF!5Zl zWLG|E+5)}H)PKbRT6R^n8d15W|T?1i!zC}l32S)U=yR@^cRg0 ztQSig|NB51*u$)U%;L?1i==bC_)XA#i)M^>R;z%v*ob z9)Cb4tTOLCSa_1TAXU{0z{sXP9n z;(il1{$=j|5;*=j>0kB_MHqbb8w|$`#lzq~!VgF!sACoUJ+NSiOj66>^(uG}N%xNs z9%yXXy?>v94FF>s`{EshQo-%>$7E})YtB$K6%;Rba}N;3`VyZ#j*lcy6f`G`zntjm zqpy{KB^`T(u2KH%97}AkoWOUv7)M$a%X<3m+C7qrxq=rKAj9bQi!HHoaUB?&8XJnDB}tWc$wY)-YZUksx_}ZSjBiDny81o4WG~v!M$yF@ zv|+!gU}~qz0IAHdNKXggaQusYplqmg25!Zo!hL`;r`esU(?=n_Pz<%A)8>%Y4OjEQ zbYulahm0)dI~JPGUyu@Gv4%%VHA9l;T1)yC>OG-S#~JwgFQ&#-laS|tYYl$17JIDA zR^VMUG@g%+dffs%IIyl7WLN@d&z93qx-#(fkf<0f!>2Ko@f0J)NpD(}WA;taT-7y|bT{Mw^ms*a?!+T2;RoH4)Pn>PTA{sVrI0TAV z@3IGl@B3-JQV}hBTSV12{r&-gk1k&G>^B1M^`p~Aq=N$=&Vp^u&&RoTx&_eI)A6w` z6~RjP`>MDkK?O_|ll11%_d&><=TA7)$Cs5rtt0;GC+Odp|96?A(n0^zM-lDJr3&8Q z(4PT;A*%ihqB*CyUt)-SsP?4D@20F|*@IE{-d4ZeO3*285l21)*J;tI#5+BxV-Bws zxs-BX`Kg9WvMQJ_g$Qi@K=gVyO0kd0WN3=;z~OL9=1Kk?kywM@JePj<8C;si5&L zTO-i}Vl|R?9vN1s4_M9jcJ}TONd?w1>GkEhNNVM9r3LerPB&M}YLuI)KFyJ?d{ipCm((kb z{@n`2iHdJ(eEvg>D+8ulcPlM`4S!8^nEz#4XYfd>j_4-0xaS)2kDrpxb)=o%#a#0m zRsCxHMSTnd&Tol|c$+XJ4$n+Xjql7N1$@(aC0a6Lk1SrL@yR*9C|3GT!%Az*E}!Fk z71GE47L2Z_KIHe`8LS08^jxmrn)A z1U@OAlZ;2ulWw5sXG>cybG39vVFHG|!NF@I6@Q3RHo7lnDvQuvKB!+SuOLj2Y8IF) z|6MkV-cAzd>0{t>O%+r2g}54A!SscJY{VR$Cv#@T&0*)<&nZv$m#UktRIH~J1NaZh z){J)Q-i@RxAO(LxzUQMKwPah|)(Ivjc`G3KM24bEO^mSJ-EC6NS;8l9GY_+{Goy9Q zE6e5q3kQE7Xo)FUJlR?~U!WCDIa|Ha6U_NFbkoPG{V*i8_EUG~f)Ut%vmJtF1`JMN zAc5rSYm~BOm-vIMBc#z_(IjbHJWgqA32$c_I%mN&&CfQ;2&6{~-)1x($4`KN&8 z@b5ADzic2l_+LT0Kzy!0e+B-WfxEa(O0drPaORdIRYjZ)jpaZrQUBU=DeI*pZ!6?X{VKZw*+y#aA7ynmnHHug&&eI!F$0!@WRo<|?&tq&zxq!bce>i*VsHofaTYP9iNx5?(R~M?gj~A2m#4q z=sN95d`{is#D`3^JtC+MCQX1V>CSjS6E_ zJMb0u9&OI&m(CZ$Co&Kyl>%2&Q8UTp#Kq(VMr}-^8^}iYUCzswhyA#D0gF)`%qN>2 zwsyYyH1Ap^WCcVUTxFi+nvF5@)7xNEaE6tPDp!~A7oGG{1#t9pZ!fFxk;qaqZVFF= z_}t-43Cb~o8F1@G5kRbKLWPM4VdmrIN(04PU*8`Hg$t(;_tRnTWC@TfW9CkjyW$v4 ziCN4WFU#}Gf75eJC*`jsjY{_xL(ZT`#Hz}4us!&nq+`S1p zi&>vGmF_p*)!Da2)xoE!Mx(nT=FZc*YogTD0Zf50R$a~AZg_;o#QYy1>)IxoC5R=d z;7;goa(-n>Z?ugWOCV#~3R)KfSt__tTc+>F3bDV)R;X7NXE6cFzhd|A1D@GG%6?7B z{(718BL&-a;kv{_XQUXunD2$O|E!$%h3FT*5;0q;#upl#vP@Qea%3~}-1BPh$h+># zQ-6L-cgzkvFGYTT{N^L4BW;9htq;0!sl+)xdUqW=MNu6qP!)&otmznU*;#2gd<}iF zd#i&2On4(cLOQ^(QsQ~fQqw!=!zP6JlUDdO0NXB|iR}EHFWB6@5KbW7Ejph=WMq6c zD?R+#HkAT=q5DRc+3(K^&~ksXO4wlJ=kQGGimd+yx3Y~eoy-6I_R0f3zEvbMmmSFn0E^M!GDdWnZ|r65IT2*^Y>e{qy( zT0=U?ikKt*yfj}nFsca+8AqU{tkrEG`QoUB#ViBaL=bLgxwubnC8ukfPslJm8Sms$ z=nzsL+ArUv<#~~U=e?Wua?S#h^kkOjN_ZA4oW7g$TbzDprhypRXqvT5LcAhxy8C2{ zSzYH{cYfo(n82hXvFvN1*F-PgA9ba=ctQe_A(M2Fd}eBvl4Wfm3T1w zki?LBd`em#QT62EAwa-PS>%$#%^-93oo@4UwtjStb85DUKzP8lx${p*_X`2>yI&R- z0otV>*|s19G)N_b=yVRSH^~arcp#?fMKx=L=>rEgFW_|nJWkQelCeT~ETDu6d-p&( z_0q!Ap_`*8W!K*;TD9KAfCTzWcM5>^(*PLLX!B_F$bT&I**(j_@DW*CIGJ@i$*jdO zd$ZCWm?|giQOy^1MB{N+*%NUrEaFKYZfbVHpz0zY2vHYcod=R^z*ay2Bni;Nfnk-$ zVsWZPcG>mdGj-^7|2a3pBGRZ_`>QZ`=z})y6%S4J$}m6_EZt}#MW2P;2mb(iLUp5~ zux(0%y>^Sfbf>F_yq39b+1XeM*bmAZl-IMZ7+pUB>z%nn!^?laNjnXUH}4rAi^Koi zL9QPVD9ORGnElqiO#(i+0l5sfLrpKlwdz`J+k+7U=om1R#o}=IEd5Q;C_`R;+b6R> zaUr=9EuPRKah2OXDI$IQHgb;<5&nNw3;yHo_GcOg>}UL=Q+QM}{4d)Cz})WfEj)qh znR}gls1jNIL#gv__^P<~anr+XmbX2|HLDEBq>q9WdoS39d68zcU^ydfRfqA|>t# zzCm983k3Yh>oDTxPNq=7wN)L_6RwlBJXp|Axj9rrioR76hBL^lI%8lAr8#pk$wZ3of_hIc!gPV_ z6J{mU1ArVA{M&7~AP3n@iw!ztdzd!fCQJg_1rCfJaPaQ;o2)4nly(DQD$QMqXZwnb zXevut=ZDd$Rxhq(q2ha$?VjnMzlKM*NR7_XrA?E{MN`s`H zY&QynrEwGq)m=0k!aarZ&pIQgbXNc?0IUWe-mSpeV z7P4Usx~?MknM7K+r*kXFB|r4}EKCX1lGf$^0R)%Em5g`54{-nM3DCIy7u!5qz`*E_ znzmRLIIHT*Wa897V8tY2NcA{1kEzWJVeOK-%$qMF9SsUYs>^spj0a$R_V3xxzx(SySIgs8 z?w>8Ve=Z#0vQhXGGk~CAgMu2sRsC=dx0wL`h{}J?t>oICH4v9_W?oVC4k_GSu;5E*lwMcD5BeAE{dGO$D6e#;8OXAQ8 z`Eq|?@EzAWcP!bhPgMQ!bWS!*6`s$8i^DQ3>u3NqgL1#XI%H3xRgUb_CV3-tTa4(v zmpry-D3rm4oMUMVdz(KI zd#Y)K3gVVmJTbw^Dl;uZ7)e*s!!ZOnuuwz<)#bo)Q|sDGk7%FXV(e1~o_-iXzg8u52<|6Xp4)MMXOhZ<-6`km8GvU9!k?QV^2dYAjU&8P?M|TvyF5=5 zo4+J3e6AWL+5BxLo^-#z{7Uq8q1Y-rvBmhR-6EZQN(9ACwt32meaf`H@uC5JmZ|V2ZjlG>^-zx>(d|;BKJP?kl3Dz-Qqk)} z%kvXsu5DV!38~aEfqw1lvPFlFy0g6%#W;eP4fVk#zplz{oaeEKfVC*0kG=snfKRN* zr+qPUtdMzF8fj&yJ7}o^I+NmdG)DAFE(kQcr6FU) z5TrM#oh*hnQ8WUn5#OS(K$ek#nZ76lmsseLDJb0fjyBz$qo*TQ4_1iP4F!GZQ!-w>UJ^OLas6Kf>WV-CvX_)Fx7 zEL?LFssT)AC1XKgkPtgP*;_2_PtB*a$8VD;zq?p(Fj}GH_UiB@u!P0@CTEyo?lxE~ z{Bo8TA&!c-6+R{g^cp zhNH#1htU^g`xDh}Ivv9u8nR^CeiAQ&7RjJ3v-SD+(r%cF4fMKVbRm?)w88q&!dyo{jO+FBlg+_tLfIP z-7TUvO&nXwex1n^uEN9IKI9{|@>AbY;~8bAmle8Xg+p2jHSf})w_7vfju9=Ey9_*z z0vd{TLB$XHd<5TI{J8~cnyQ%me^&MPF~G4`o44<}14PohDbG0!NcxZOh6!z35Jwf1fdLpGpP9AWR}L{V>JTkivAG_{r?{SkXwJ^E&uR{z;^;M zH-B3j{83$^M&KxbMyEvq7(9D_OJV`+;sT{N+hgGmD>Ae>6BiP9pX3k@7T~|7uD|CD=nh>3sE#i2DkU`5gxPMNt=~AGQ#y`MC8N z=QmQu!R_vw_0sLN{Rl}xN-Q~p?K8mq^)u@2E_Cwqhv?Zz_-V}mgpzyrvJ#5Pg3mqA z+=ST%UO`5IbE&E_-N6A;Q+sUL>C>CELB`5ot( zZP;qX5Ju&T&_&n^Y%J)#Hf1>Ga8Qom+Ck`Y$|ci*e4A=KktFWoEf2}}cN(s(0dI-EO-0r!um?4e=u*058N)9EYe&eK4nG^W^3 zwDw`Wt+lf0G^%^x}v3jrss=Ney4FT8aBFD;z$)>*kiGhIvQ$R}rpxi@b64Y@R*ECR_ELo(SLqKN?AzH+hE)n?U))h>%F=TuhL`JFyam29XHA}~_4iC^$&600_#&i~fZohqZ94E`B<(BOu zag^SO*A|K`!dx3n;F}uC75%0Ei<}{C^`;yqC0<3XK`~0Ah>-59PA^?QSHg*4qlWEz zQynVM>U7r?&J)N0-s`@Hm)xaOXWY<bnZ129kl$a7BycIy1=f45TR78%2@Zm071TmTqMH*@o4tA9LYBmXt^4aieJB+lP6TVdoNx9V#&mXHpSKUlO(= z7bj$S+oPc$+5G+FE*fFp+Z%k*1kYN|T1uXc9`MoQetnvnOuY;mMZ4oa>9`tMIl3Fb zjq~Zgp}Zd4()BCZuUP?&qI14pad#;2=NVi5ZF^w3+zh#%dH?7>Wom%jx2wI`4z2fp zqwKV}9Nzxr+*>p1l`e|dD%Ukgq|LH?@wekI`az7WgPiQ?Gs86ha57HsINJKPwb-o( zAfc5$yYN*!yl~_E8N!aK>*8{&V^ z+5Vm)D?qF6x0Sk0YDl{|{`7~=obp*w()Opdo38yUW?kd60j~{?T9iLiS*v1y66Y;O z+d=!{w4dhgsm9zV$sC3BAbN$JT~wJNCefje6s7&i%4?J3D0XCb=f+=s+-L%2kva3Q zbv=x+qo?$;^mrkS(DG0TJ%p88BSH+AswttemrWMgE|e_TAf(cHaZ4Q&L>yixY-t=w zf7i-KLF-`V=M%;l5#TN)d})c?3jfs6@M5-y4Q(vH`i5{!=9o@l0OE^2CL-esZ+y>N9Ppo>shI0;2>r6*FxN|UvUXL-qK3ZbTX~{wyeC3j)*(UtJGv-OGi|jCz zw(GdW8Govgewb>`hHAPW- zl)nG7+WJUNJ>nd_4e@8@`uO9Vr-mVg|jqVl3Vxw`0Zpk~m^* z@xI;Nm_&+X(X?N6@EELUSo5b(w{EHv>CaD3M(+=vGQFafa*hEB$?mFmX%|~84PBSx z1@BvNv2;JfsxXNV0dPr+1s@`FFObcK~_$ zVb;=`8=)B9@E*PmK(O`0Qrng4-A)}AV-6PhxV-uo_%sdNc=84RyaHgXRPP)QC&5GU zcb>am*ctsWkL9z3#r-Bcgk-w^TP7npUYEdNyC)VepFGu zHuPkD2zxP^j+7%xo!tH`dn|ZEUL0va#c$LUUtQ?Kuo%hdCOSTNuf*kHhP5+_!jkr= zjN@U(6@PHp&*s+7Vl_YrP&#EGD%YMp%ut^hA^;nuJrB24*4c@rF*`#Yu36QWQmPmyxL z&zjc;6D8L|>7VQygxnxSL#5Pr!}DRmX?eqk5k>XsxS?3}ut-8TKL=kVQxBKUT8 zh6?GQgI-)V6@S|FLkaD>^#8pH``_x5e}5l>wvRu38XQaD@c}S*B9^f(s@Vu25S7t| zDRW)~4wgBKE=l+SS-`Bz^-+F%NaDq`B{ZqK@e}wO-LBGxy&w%87eb-ff13J(PHVcXeWSNnSo%|nYq3$KyU(SCxP)$KVCI{Hr>S~>k1iH*_(bo z0k+Zxn2umw4ADlJr|miXz?H)FXPC{ctySdz*~yjN-v7nm&xi(rQ3Q)146raQc@(fb z+TH!(;r_?g`d>3$6atEbgreBTV(Re4p$hb*QQ$_I6G$pHh1-1JwKJ=l0!+q4`!){j zn51U?#n6I`$fijcZbSb9d3R_e9jB~ zo9Yq-a<^g|Q)-ikKz#*<*PD4vFbhF*CVnq$OC32_1cn6?x|l>Mny@Ge~He<@`s6 z4EqKnVuMFa2r4??qD1zaN4XpI;#V_>e5Pt@=}VB*h>h8{o~KA@rOGGY_XQk5gZWtkYV4q06x$1<0nR61 z%TJ z&taykU<1~dWJ?AD0;^!=PE06)LI!z0VJSQlU3u8|{Ps-w4)NLfYVJMS?YPXimr;>eN!;E?Z96}|qPXkNI0w%aGbFB57up4R@jRLMBuZqY8#TUSW zCK_DMUPbjSFL_^~LT8?VYfLAr8t$e@eA8z>$={lqicB-?H zusq-YDp!$xu&YwQ@nfpO+2#{xuWO!w7koB*dJw_3^3CJtxn87US7qUV!HoK&5x9ng z2t!W~iMiRKK|^vbuq6TRtKUOV)h=dOb?Q#>sT2{t`0s2cwccij7j;Ui7$4YF1I zxmIB|U_|_wG?m?|^}zF{{xD3q7U8PWheM1QW_^Z~nlgAip%dj&U`t5A9MhfoxasgO z=`W6?qOu4UND|nZM|wP+f&U&@0arRE;36FO*z*J!JZ{yFbOMu$Yy($U=$NSHI54vU zCWye7X2TyY7a@rt%XvdO9ZrX~B&T%Y!3-@yhI`+pyV3joS;~c?S=BlzzTm<0ak9Gz zN8qKU*oE&rc%jh?x%&mTpW#K_bM$=yC};-u-C$c?=XC>R2unRDWy!; z@-k%;7Q@_dcjLKBZWyR@>{!s+lrY$|m6%}SxlwXJ>kcb+tdHf4jSf0BSwbTgtxutD zjRV1L-wWyRIBf{kj4{$c z-NZ0zalK8QIc@C(?iXeSo=6KPiIlakmr?MU2lg?~WL@!7v>; zqRq5ods@4a8A;}oLCt+#w3VFaWn1Q2_RKnm>J3O#Nu`6jbo<(LhjQkqnJ=ckP!~)2 z;P~K@ETE1_q@u;Tx($?EeofV_UM07+QBNBEs+LN;zAJF5G&y~SdDjS7yVh)m8y5K?e~m)AsM^L>x~C3qmb;vuY%OS=4*5g4q&{j2HTZ6_0?N z(j+(M^R>B*jht2;cELpZ(=k73c2;TECXV6Hl*tjF^KnZ~KovrITX(PS2*YgxK|Urk zaAA2ejhoy+WM`ileS>R;bi=1!Lv*BJ{DslTv6%&^Ww!wr=E#U%$GuXsBa@B9U(LF( zBI3eH1T+XZ+1a?__{%i7UWwflGgOPPi03^S+%c!DHYlcAAw3k}TK;N}h&Sa$G05X~TFyn+!Y14I zWX!A7y${P>cQMBq)SVH)U+P}ZQJXwHlo%$Yle@zVH=TE}qgG@g z+V3%c$e`e^8tU);DtE(;luFTKwre)!y%)5!#Qx#J&sGnR;D7Vy zAkm2Q~w86Vncv?J_Rr%l%{&T{>^}vCN?AwfSVAeeR=WyKOD-T=Anw@r{%!x zgtLDk%kJ<8k3|=;2;L?xc^jIB3>ZjuMDAmc&2Hy+GvR#Rk#(Wtg!)9dcUrH>(k2GRCtrAE{06SF3uMmpRXcwd+xtsY$sy5FKaJyPj@l@?O?1F)tK{5P8^0^%1@ThT zJs`r|?@A{HKGYj0hrA8~W6U52PVdepP}nTLGVe(A)PEBGL>$m_qVUu&b>kAf*uIR_ zndj!Ly0QRKZU_j7t|l10de@lgDTcbl{};$!Go*gjQ)P;6oGXBn#h$`@r~J*r(?pOQ zJ~{tDE~j}_g_%Ldc(W%(OZo5+hRNsW>UG?03o#t^&|Ov4W~P9?lEp&X@DPwVtCmj_ z@F7VfVyzS_#xGi5pwS1;e1cV;xn`*z+f}klu)>lK_@sG}eE3P-h{hV*a@UtPRojFi zPTNF)Fw4cpPxZj_?SRSS*PL}eETM^v%)KhNa)*2y4(={(-zTZ@UO>zsAL55IQD;ol zH9s$V0z=*Cr`%mE3Q%~766rc5!awQ=FXM%JwMuj}7x@+O?z=p@XAZz)kBbgQj)Rbq zP^MDO1^71?dbo{U5$#f$#?l6;Yzegtj#>=Bi@~wRiUf`W`f`h05m83vGP;TH`X{U8 z3ZWyPYpzR%0HJ$X*iW7u0{xV4=^1T|0t}U!=}rmkdhv5SRRgN`pQC_57O+}?-`o6Q zc1ZSa8fECYc(P(jlMzXsIRGtxfjqO$9)4`%Cg>3Hzf;HizCajGx^09ykRyY#7)*Ve zR^4E$e~pXdrncR0ki)j*O-iWn;YN67z5i&l@kPXVQwFjW2coOL?POyb)&8%j`gbl3 zKGU`NEox05&tBC+VVe^AD+a2-t0E;@I&ZPSdS^eEQAu;z#f|<-SsB4L@_U`e_Xf(< zi_1kTOU_;IuM3&TTwb}5540m?HE1Z(w@p?=j1u^2ZOP4#^SrV)ZIGhF%SR6WTKW7N z**HK1ZQRcCKm|iO;qJz}hN3T#`=1N!)N*fAIyCO?T)eoMK&!J}JKIRi)#8TyK2zuv zL%17Og_ir-gq^aAf;Vm_kQ4qJ)y!*1X%SdbmHeS7-~Teeg6CnsSd;FtQb`E;jGTcH zGhTW-9l>SNQc?k6jtxRJ05Jy{*osGxo#F${l_UySUk8;Lk>n zCTbPiv2kQLCp@S9zZ4ws7nkcCfjcW0K35U zXG61=M?BGIuHuX0i3lb(+hMpe9pz)o&`$XUY@i4MYF9#95kl}x^@K)NC`@z%&Iop& zc@h!9SioWP$gg_gw#oz1l^+5koT!_R8#MI0d&t|oM+vNYd0de)S z84?R0c3*T8i&_$LA+I0(wO~2yH`(*_Slv4N>}2hf@1kIeRFSui^riB4=mvuDZcKga zzaZ+VxhB`EfNC{YW}?roAhN5{Er(jvJ~5uRoTY8?1DBOgXa@B2qy6_$paQ#r8uAZy zKg*Qg$N7nx(FhRymoe_ep0yz zHH<{B4z`~rsq*Q*=TI4;O3scLqeOCGvx9$>OL0fS8!sPh>R#4QEr3M&Zu)M?QPnIg;eLe&R)ZRPR$hTGj@m_Md) z@W;aTW9m`*_K%L=am2>Wi`e=;dk7>F4#ELOa0GfIx_8AqFJpV7j8zZCVqAYZ#Fk-# z99PP)!@*2m-HiFf|gWZ zE8+_iEKg(dL!n!Qax_a+rZ#baunB~@lE9EbX8a7}LzG_pvGS*QX7jUVEw)0f-zwkh z_nqq7Xz}xoG-Lb8_Ya>1t&aiK+fSNFitLJ}A0hJOyAxAn`s>?LSr5 zzXBV;z?)x16UnnRuL@A>$)yd;Vm$~QQ?MXFDAS0YCXL_j{-P*Dz=D-5rzqBTH=r&=lCwk_X83{)mjOQfZib&1L! zV?jQRAfD%u!2k95;Q}I~^Ae(}4*RoSi#X^?e z7Q;N!yvpZZmMbSaUQC#a2Ij)4&+aQ6`nZKrb;E~s#X~**MP6#xa;+82JkxaJu!(fn z5IIOKcG&CKmrc(xVOFW=N#jBAo`8q6lsDE{uAnHhpO}dyPt0b0nrb?-mm{$O|DpP< z?7&}L^8kE4epc4jTtq!$OV7Pw%gg;FLQ>nfQZIJKN_di}N6O6QtFTqWOHqn^01n#R zAZ;40rv zb%QN7^up_8$Q@%QT^3 zw4yo`5+yGqN{Jndc@#|Ys0es{cV`>*@bB5P`|{0Ku5&;BDITT~GHnaF!<#%7ZD(@+ z0!f6yzpBQuo49k7<&ymOLWkp zL4FWQRny0`6f9P#YYOYW)z0V2nwx{fffp-A`61sHmmXSQUsU>;!-oc^AX~42(exW# zphl>*0iSJ>zbzBgz4w;AET0C2omNjw*SI@XO8MWyu@qm({Fj9S)4vOa6gUE9K#%HDY1!2t&V2NuAyB$E@JTP#iwS90TGKt-SzQt-%R6pRvp8q!PPeU&7m z032xi0|aqPa92n>V>>`o_}3c%Cl@f!mb1!ZSfNzVxhsPC@7-!Nt?)=t1Bz+Mf2hfS zbmf19=0HF6IL4^QWKva7z)?W9FosmCRtjVGP(9Kgg`9VAA3qzFwYuT9lOus!HI%19 zmJyR0bFL##%@Ji@EarTNY_4>!I_=6A{{^yuXBpQXb2_55#%HZqKmH4#m~q-w(rKNIGrri3Sh4eH1~xFVFOZI91Z%FOe;#P7u;+PXntZW$BQ z%@Bm#Msc`AM_fAH{MU1j?raiCNan*hANuAsvn-(WN#-+YdCPXsv8;w=2 zfv7kl-!!YhTeVOVtJh$9oawR*p)CC6in3WRp9i(D8nP=%#fq&BmRMh6D4&R}9I76r z&!;R~J?tlRXKA2C*hmt#3fd}hpCBGnnu>u}9kg9g>slRVJv3%WTg9O?nG9#6&bZ%5 zAvfB3CDrJ1Y;^S9JC2Obmi&xcSE(dZ3e~efQl!xJ7-tuC z{s_il-tR%3?*2T?Mh2~p&?o8PgE!t~Q?&BfT}X+3Jy=RlV^>*c+AF&QJkMQpzM@hQ z1V>?Gy_0m{n_s}=G`9&~`mGHY6<|Hiko(Acbj;(a^W};*^}?XXF$I0elPhK;D~One z*@$V+mNd6x6G)vBIF|n$kN9@7z|ceu1v)e5GG4`UhC%0)%>M75Fd?@F>ufxV|Z zYux^9-U+wm!g0*gw(GA|TPS@(DU{QU1p(A{u`hh|ny-?8kOO?#Y3G|BqYE{Wy5vtp;Kca6<<9 zF|)7%r!^Mx_*CfeDQFJhJGFJN^C~qFC;=dG6C7XRnf$v@$O?@|N{)xWt7OG_kVpc? zj5>C}Z_87hi}O1Tuu%9SXZ3-xfI$0+fdY%*8_OZ4_B!fU{B)RsVkF#}c+xPWTohFa zrfE<^YN=meCG*I1$EJoE|Ka#m@u76}EkF&d5+r9IDnHLY1PEC#4W#e7C(uHyYvrfc z(!gi6Pu2tp8bp7@B)}&i^5>7H4p5N%Pga2VzPy5u8mjX3?d9#%*Kc@aR$Ib8Q?ENW ze~8xq$fj3r9-E4qpcNe2E@*)H_r4O2sskaExEuezhFoV=7?5sS0_o|v2wA+A<$IlH zKvvl)_@d-hsD@;a;53Fze^)=*On9@2ZQZ&g{n|;^Rc>lV6(N*|W)#|{MJ-?Ta)H2s zHvU@L4q`Tr{MO>~%;1~g`gYm0(B~Ez{cJBhHY>f|oGlx04ouT1Z0WOUGA(?G zuc6h0qd>63i?brBY1sUZ|R+wk${;ZLF+?U)UAGCAD)M-$<)1U4<%|Es13|;{x(S*wJ0(k7Z@+(>Wss~TA6S*RwTEUWE8*0 zB6}w@(MKlFi|w^5tnm_FA4N!?Ot)FcfsfqV?Es=oc}S>iZbO=*1t-$3V;!?ZfB6aS z4ywqf(b=8XG0JY=J!ihv%Xi+UH}M+xF*AAvt9K%$=&KaY)eCmciRrZ|k_4Efd|=`X zxxLDXz^_e_D2vth46u#vqR_*LYR7duG*mj0y&X{fp0^Aw=w>HFNxE6CcYYtEZw-t~33w6&6jvxl6 zbj!Xjn&<^xXlN99Wyc9VQ;FFfvOmOLgf9m|jkIo!idZhs&)Se5h{}3CsrYPEc=?E2 zYt-yMje^Tn6td|x8jYoG%gWDvr4!-%i%xX9fn)mv%yrz;xVsw-F!`3}`+d@yM~vCi`rga*vGa+_v$$sG`rpAI+lW4a<+ zJ6PJ6!$5ivrhTkc9vT?#n`JLcj@ke+_wCxhFo|dZ2rt*=s&MC-lD{V1H|ndIm^5*- z2YVablKchw){Xx#W1ihuz~6KC01mbordsEXaqCuvq^sr9h3-b!VaNlo(-hX*R4}qoyHw{>c?V*H+c| zsj}b*z8fz2dyJT^9Z7=@(i*$S-o&tzjje3Wd9A>OYH>-wDMe+cR@;w~(ggnkt3NW0 zKN2>;B)Q%+nc#^6lZ&J?dY?5gtYu~a_DfN`^Us&BjCKi`fEFnI^!IO|>~TX5Ap209 ztq=nMV*$f#X5t-p+rvpub|E68f#D!|M#w2$3Vs(Arkk4e+5sher(mkH4yC@+g4x)4 zobDn^@OwU_Bp$vCEVtLhUHvM_nGd_psD>2Ezvj^wKVSYV!aOpHm88yCaDlH-)AgmEL zJ^;ORWzTja!DHFdMbkjxyHVes%6ddt>OB)Gti0cP?d$TD_hE2;9^=HeBX(e; zua^oJhj7eC%`6dZHPy`z-}Sn|bWfK2STU}%Z!x_ zqptN5*cS`y;@z9Hs=_i1!1>(wWMG~XXEMjNSU$E|f_VhOng(eG0|{=)%twb!JlKQ2 zjbM_jy_Q&SZ!#?=q&g@^^SJQLljx>hgkefs*M3@dB7yQltkx0UmUVy*uA+)srh3I& zIw)EnkcUd!w_^=!)sqy<)i4efj>b(SBx;o9)D+ zDTYwVq)3$@Ni<7O{P$MDFUjV1c*YDHuvf83+TR12?BUK=T`d@P#C2FOe8DXWQF8482`UR zw%nBtfUpfMc%TKeOaQb+{DC%Rg$T%%@?`;M@_lphWPZ)*RdM$3Gw8nhg8RMovl@WA zwXN(_*C`EH0M9f{wm7_Lozsz#VTqevPa;;?7E+Ztvf)TE?l)XSwm8NA?#&a4$*IgP z_dOMA!qWKt^7Ql4juNqPm5{H7nDuvQLNW8-@ekr*@E=CD*=cQ*c#r}1zd-FQk!Wd2 zXf{9U(oz2cL2fbTDvUA7_D>&f0FtLP2P5cYQmDC64yT4(T2)>N^VyG2N^J$1L$?SK zOHDy6dOD11G}tqbO5EscWdh&>BrTRtkONo=5H#lpP6vtwXl$fde)4ek&zST+yk|WA zt%lrOh?slv(y5KexHKO>tLnubQ=ll*QyTb=`tNB`8UMRFKV`-Ux}%l?cEb{-4n6y( ziOq|Bje%{gM5An_85_3BJk!GI&qo3eTH{T@4`t}aYeYHHvFD%1hw}H+cste=<6~wd zb{@<>vY%7aZC*puhSPN%ibp!{si3!MY+QxMqiBUzdsC5-tOt{yUwJ2N&1?dmRaZ!n zA*Ii1oS6EKsMp_@@X+2}mC~^Ovhm#X?1`G7$&CJ*G^X~dAPg;T=migU^h2KNbyjhm z-43ALdx}`)wJ1-g?MDe$%0BJ9DDh2_WgNI?ZU&SibyHvTl26XGXCh^`Zb@n}Vqx(* z$vI^;Ao+5ZV-2-VAH7>=@vXavCXn$lvD{Ld^%(l7x~KJnb6~*X7>8O%J{6iZbAN}e zx1j*Dgo*)4&9^wY^bBkPGB-tE?96)BNl^2_7iG6vrE^}riv#{5p*k}+{Fqc8TLvk2 z9X`|6@2tts3|{nKhuVy95UH6y;`lL?L*Mr`zT?QXTin?CVToqn2vE+RUls{)k$YMKP{ zVZ3ZHJ6UlU)_{F*U3{=net)a|Yd4+f&ZJ`dp7%MWj=g<+BG`rr<|bSjBwJgPY*|(w z^GH@-%)gz-*SA4cYy}uHP@f7%EVYJmPo!Bd#LHxxy1$fR$L7$`*HcA4cms~4+ZBm+ zbMW;kjvNfT$DA4VZTt0!qZLwWOZu5^VWxz}l`FXZ;zrBsWi~lq+D`A)o}(4(Y45AF z%w;9C^uW2CihN4H5eM!Hy8$A(u28bG0GrwYi>SVd`1vi8F2U8@EOH1TAsxx+eUvyO zWSyt{r8kMLVU{p5)jFGyHfjA!(6fYruf6;S*OJvq5Dai5{Zdjiqml!+!r}IwmuOH` z)3D9Ba`t2`!^}#&-4boF2A6iVM_ATq-g$fbx;cp{^T+`mGe@8t5yh1(!yFI&2BG|^ zl5~STt{>BeWX6nCQV}Lb8mPXXiqdwz0X`O%eaZ_q=zXiMddE`-9xO2EUx_)`tSnO; znQ0SB(~UFu_(>IC$bLPvm*ecSSrLEfmZEG^jE05 z&JaBy{7e_{nU_EW^e6xEV4N7JyVf+-J0&$B_2FWdTQ#XQ?LUIde z00jyZD9Kie^xf|PmmOg<;37!3m^#bB@`bcB&uBH>byrS-3e0tl1Vbr4YD`XWzq-c8`Lygnwt9wV^J!u$2<8Q?5^zYz*K)al=@{xx)XAi$n&k0A=p*b?Un!c=iLQv zX?d^kn+v*(F%etcLJt8dirP@WqQL7I-zg2oB$}g@{*{+E*mh1SI~rq&(1^NI}uf2jhp8!FnLygDo9u$K1=M^90GZvS zyg&%Py)yN?d!DDOMi5uVu<{OT#OWF#SSYj5g;=Bbu-ny6Ny7*fhfj=re#Gv9M|+hW z9k!DUzwQFWcxE20>~HpnexlkI&emDjaY>AvGXK=zA0`>DZ-Jev)6_{RFE?x07S*6u zyOfN5e&d(4_S?|Q2$U~AD}oNc;b;uEK)89pvo_%$QoS8c&4y19XwoF%dyo|PW_;dGiDO2= z-rZ^vf4E_@9eHL{QDUGR*=!*Zf?8m<8|NhQiykE6xp~E-;mwEmvQ_%F<8(snninS0 zQy+t^Dj{F8bo3d=IOnMtp(Eb-ohZ#IcLdpaWK@PPa7sWf4rX8Oh>5bd4e(XQZHR+r z%!e}&0pAzo>_vL|;lkR@X?jMa_lh=YBi?5fj@Y~OoX!>m1JpPga_;VA&I}azGN80B9kP5r=AZB+XlPNd@+IfnL3V}!F`^Q8$Q37~ z<8p;lgxyfVLC%WKiY|Ls5oiI+fY-moBFf(uYeA-~>+7+`Fc5r}`=*F*DJx8%oQqjj zN9#;`qx|V)PR$v|MWRcruU4EylcunYNTBR$*G_qqU!G{D@5}&VWXr%(bBr^V*ughgqBdXNqkE)lRN4UvKmbxa$r{2~YY6e*?$bU8~z8~i$5 z(Y5Jd!M)Un4j7g*QBZuuxR+wXF*pW`eCjI-V}rFil)S#P+LIq)0RtK7$c4Wd_kgyo|4I*DAVJ@ugiQv65c_hM(7Ir%Ggp|)uT*hgiqUb(XT#m^*u+J=)%&}QjU zDnx7`!J1<8iOTg0geOqnAyX>AC>xBdbu6EDnL1-pF4XoNwvqd~i9N^l-xm#Ptd8Gp z{0PDHu4wZb9w)FWHDR&c+?g&AfpHiS7TVCtS3bpG@XLFWB3CAX5QN1my%<2zL-3~G z-7Km*jsT$lT_kshi4P-=_sq?0DgBs>;sJ2j>nOg_u9SqE&Nxs$NS-}_hf>B3rT`Jo zB)HI^tda6;pYkrRVgeB|Y}{S31iTr5eCo2b^SPhpfXx0NY#NyG;o<>v?f8P3SY7 zw7+H*!1OjW#Ip6s{^Y_?bWJ-k7^u-imR?zy|CIme;c5mLKohce+zuxb!_H~SPKR7 zhb=0K;`03i!UASq&f&w_L52@)#eZyrKdR0HdYaRbZeWuy*o=t3QUJy|yamo8apdI| zCP%*xNqYp|mD;gxwy7z`U$jb?0CwmXtsk#nQ48v?Tls{X*(}2asW9xZ63GS330N<< z5rLC9V56BXJK&6 zT3t@J4@u?9#V{aGt?pJI6r=7~FTJR6TBH3<)3m04T7u)tI2ZOs&h8&j;>moPs2p(d ze2};zZk~=x^98y5?zIkYqQBdFD&BN6;Gl0mhcN-wbb&uIX?xF-DB6U9`Af^x?dRVo zOXR*=EyD#k4_0v!)Lart+ul1lw0OsJX4hv_^-(R0+t);(3?@0>Q}+Jz4vgvR$4)iQ zNz8ZaMEII_yJ3oJMuNW6#y9W`RGt)-G=cZ+aDJ!>mMQWZ7n2bOW?}uDMwz+bormO) zFN=yMDllVRF{@`+M{2M+8s!kTM^g~0uL&0Kh5~8A-b@+f6 z5eB*UxD7m5q2Lr1oI34U7|_qf!E z7VK`Ur!sC|PcOtA+SeuMiw`s;^NKc~n7*5h;hgE0^B1F9`I*Ah%J6;{wLw6+op|qh zklf(fn71tyCf-}~J#;StOCKzwn1K~rF8VeKm6}|;K$odqV{`3LPLr+6QWrFYqdER? zW#)72GSHCzkn&0XW=5zrY0&OK-J@*a4Q|1U`pb%F5H3;seXx+?c`i->cZ%$!;PTzP z?&bS%1Ga2CZupx|cpH7q_xv(k50DgR{DWf{Q_zpzRpt|8?VqW8{LQR3!erucd+gP; zmMr`k>dTeoYlSs?unC9W;OVjlQV$tMKu2?I*{&stv7PJ`1kekVf%oKhljGf}&bts- zhA#6pC&`&m0BB+L{v36aebZBc-wS@{Cix4?m4%_1>rdi_ym1xu# zMUc`L(RAc`GL4W>DYh@6$o)*GBa-;DcngVdjDzMYgD{tSW4T`@TaJFaMo0gWja7_u z?Jd6LGyuox{K_-7S}e(fOU3$`T2VgkC^|~weRu7k0M+yj{DW(1pf)~}IbzK7EtrL5 zDC8Nind8BPc{Tv_(fDi1$d}RPqBe*z6e{&F_syWPS^pX2z#{y*kK{$E4=|Mfg9c<3!q7%!1({O?DSieK4^ zs)BFVDp@nrD?Sc3NsrQCNg}d2`5bXmr_QX@mItidT{=MH@Y$zF@e$z;^Y%st{}g0$}Q6j*B_QeTq#TR-HIm=I^~_yV7b_+KhAP| zBGGR{l3owr2%VikDHJ3!=LOfl?^oY`@lG{S;@W>F2YSltnlI|Ao4OT~fmlrt24_li zzlIp?r`eRhHN>UgsUhq;t;*VA<0Ka|HEv29o+%fKsQh7hWVr}EQ-mp-dvb+!;-6~Z zL?)knY75u*1D{Rj-*CbbW!VdYMVfpgyEK--MCl_<33ldSV+>7=F4xb`yjlsToqQzL z$d6SkKUJCUf3vO|Hhk?4y$k}K3)6(EAiqgH{{5rgMkS9SP2)p z!1FOT10lHWX%YT+#9LQ$hr~(96&v(!jQ@i z7<6dnQ$U`~ntWbX37f8-NJ(V6^GpbG-DdeE38G%#R8u~{HjO`)&!9*tVormaz?YK6 zU+`Yi^lA*`z=Fic^YR;yrs?(r{{d~Hq;897)*62-;(Y6HNSgb^KycG$tKTjWrs0%W zMWOzH$NM@bU8lu*Js6{fm(a9KM6hpWSe4NKR1mtIK2iSSgKT6_Qw6F$<`?%Qc6Zhl znP%Ds|2<@l9xt*;V?y{OO%7hoowb_Us7bzQthNC`Uj~BYI*5Fxu!x?yk`KB8tEYNj zGkfs|MJD0)$z0qZ{=COU?AJ(&>eYH{%lB#_q|N?Y`j9`*2P#B}2=P{J$zASuY( z*9^e&46LDcUm8vt50FsHd&*DMBE+EdI{;q=@w2XM-psnDh}uNZ$!I0)oK~_-$U~a6 z{@R&f;`0pnS6tc7XMykhS0yvp1N|4`qC^nP5WHWP%{xiol3 zoVQ!o!c1DyjH^fQ+n$z?wZkEEnZ45f-{}t|#~ir56n^wus!m#Wa^p8&XKK(jZ z6c@lrw){52kDwN-dQo6T;u{$kPphyNQz8#wP;8pfGkrSlGhul2MczG3_mB(@nnj~r zJf56-5*5B;qg=D}AuAB1h@R%V{R9JD7^mG?C@pr){*)wwM?kic51AU90UB|IyRS6TO)d zoNN_G>v<@2lPSIXN#~-7p_i}QS979uh;CcCq}bcy@UdA z`l>^|k*kJQd5VDftl+%LT{IJa1h0 z8G4}64FDGCe|}f)({2cG(QrWg)Q!Bqw8UiPjzk z0I2%v0c}DUHO2~ov351?-~lnZ3sa@Gt*uww~C+ansb4$Jpe5Jx(Rq z?ONQR@H%-wjK35F9$Esb9;Mg=q^7sS8|Z!^tea@01YV_}<|ja_HgAmH~w zyTONCw%2x@ESupnF|PRWXoVk4L74-wc3{yRe%i;{0W zY)<;Fg6hP1^S$VWy{=Wp=tj?G6`4#&FJCw|L(DZ7*ZmaE1#*t#&DjeR$B^xTl6om& z#h_{RHWTPV7xT`j_k^@O{{*&mUz2vU*l7Jfpf~E0TG|VuKh!1=m$9gTSdYslrzSDY z0!?`%0Ud%Hg$kZ#E8FLgN8KpVxFvfgvI*+)JJ-4%|CN&y|1t$e{T=>Q>sTtlFOA|r zn(6y-J8jmNxjszonx^&l9snrv;QX%#wP`|py5OQMe}1S_tBm4F6-=kO0W+@gsX+#F z+o*xQy6p`UyGX~x05CJ1FSqe}Gs!nx_oPp|jvjG5ydW0{X5bd+QxZ2})ONR3J-(1e z{knZOHKaVUyoE}ZPhL_*oxeIM5wT=D=;sJmAM(cDN{KIFlaCNR>M)*j6iI$+OSYch z^w&iFV1GuX?>-eH0eZ&l24&stdiuKqciOrf4X)3jFHTeXJK&CG_B)NOUXAK8kN0M> zmg9S!of>cDcXA@-_|rB$%$vUnMgqj7Nt?s zbxCK`^9#mJ1}t&d1?n5iXN)=i0oiFHo0`>|6OHC|=-9-W9sZQ!Hzh~KINz5H>k<#0 zmQ2m&GH^fv1R#Y?$hRYIiei_%BqmS&ebbG)k9{|$*EnNR=d_+% %;-ry*RY2HPd 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

      %Ir=R{!;ic1#G& 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

      9<{y1NeLy4HH=mS9`S-}MsKG0F!tL9 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
      rA&2tKO^sR&VFma_*>w+eLtMEpNWJfO%*O`~`I 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
      Y9c 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

    16. {{chartTitle}}
      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�m8PkIEO)orLm+xRC3mrefQD&-B-X4+M6WmprdG-CAc-KYc>B zv~HW-m)kLp)}fQK6k|TMF02r?dYtU#xQdBmQ&gXMJ=F~qQ%TF-!%1Mow~ZEJ1kcAf z!0Y4vY|PtMKtd}p8VYtk21f0yNi^xPJ~H}or%fxT=Kb}kR!4!u$U#SG-Xl8(9adB6`mvW37)5{XF3`SemNvh!vBcYHNIP-#$9n9>jeQY`Q(l??$k%O{K40;5c*K&%NW?iyYl< zt7Q}lAqImkfCZj@?r?msuO)T*G0h}RJEtK-{^}T}?vopwp2=nNG2~EXA$jnUc~@@Q z3iP&%N7O|vzo zrbc9*(@azdo3+uxlO^i!G}f5i!6`5NLb_TUFRjHj zZ@o}UhOvJm{KA^DKlsSD2^H4I=n2CCZ6hHpH@&>hG^pBTCJ*(}b(BM4hT&y4 zdsyjV1bsr`YbR{1dfE@pC*8xr|)@w<+@q;jx2mRdwkpvcg~XDA^tj9pIioe2p z8&JM#D4xW7k;v0@k1Tn+mS00FL)5~6n2L#+k}UcDoWD+7D2Mw=-cgt$@ML)M;DfLc+q} z$;FK9U9xr?g1i#ODk-I-NFcJ~-gkbeN5xnWjS0tlomcrdF0~sqx0@8XY3m``pe#&> z>(Oo_kgD^#iJ@AIT!}{>|3{0`;&6V-P1QDaMj6JXt**FpyGM0uh}ddX0U?j6D6#Rw2iX^NX=~xzXFJ(Z=wB^&>8f z-ZvKY0N$IjpFVZb;5`6SVo(sIxngasl2C}Ec=&QNcQH&lZbx=mUrhRXvfL(Usro9D zUG#!A{mC2V=9)NwQ=JkU3(oR0Fu!wu#Q(vo#)0m{vf}bNWs51dy}ZfZmuf)+8w0m> zC30JtWbd^Nd*k`QcA4OzlxNpS>at;2ya-O5_Ji5`G+d$RsBqQna(IsRA(u_Hu=d7+ z90mbdyQ>;#$%S>j>YBqNlvFvn?u*r;ednD@%}*rZy6rXb>d`TIKbO8ZG!3mI>{Uyg zR>y@TC-x>5gSsf=1Mi(nm8YB!Aru`mf{i5I#l`&_3afS(@YpF8dquEnN?#zXJUY4( zQ#+z4=7=AgEzaE9?33gU4bu0sl-#?feo|mFjXrbL=sQnbdN*uu6U|0ytlA5`h_i3& zghXeK5;u7!v1z9{=cJ`xf$Tcd&}1;BaE9n5>aDHVzGzllL^Cw2*yv+XdvQ*!Jur4e zMIEZjFzHfCL1$RF*wSYb^KFB~D5rfQu9}qHzh<==Uy4#jG-#E3j-^eE#O%U8`KFXA ztaF)onSGRX8SxdeNAkj#0xEi8-c`4zims0QiXy5pc1ubx{mKgB<|~!!_s-{iTRx~GLEcC3>?W?hVm!w(9&u~+~jU2 z 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

      P%Xgjf}L?!}Q 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%0D_1M`X6+*;5UaO=)9i*|EI(}3Jt zR&?RE82@KLK$$NiqXYgyeKZAo9jak~;|=&2&x+g3;=JImV1sP=$@0Wegy+!f@d+%K zP?eRNrr)4PXwW^Bs+t9fse&i1LhW#|jo7|2o9U))rc=BJ+A5M16qdKS&)5 zeYMbL!^iCNkU^B52Vsr!)`e=F#c+w|S<$^aohFs48*Z65m4uO!FTc!$v0QphHh|M>5Ue z5=I6q8J>uKvcSsow`8jdtBJ92RZ3ElfV&8ZQ^ktnHyi9W5MeP!5?y>{oLNxo4<5W5 zl~D6kp`G{873K5PU=r*Nc#8Fd6pASfH4z+VdH)Vh(5i(xR0$L{XLyFTG94{Cm;zG% zwo%0C&$dSzC&^IjmkSfqRw3bZ2^ROP;|FEAx36=yc&uh6Q#T|hS8)oj%w&;h2}i}p zbO7q%Z)IzplA?{u7zTY+8b}lkS-_;?r+xrAo{<*Vpe`Wykb={^-4)Sb@^9H!Ay}o= zU^Gv&H}gYT0FBWtb|D;)KrgW3AzNOUpyukFJM#QJ4q1QrffXq4`Qx zy{L(Ni80>%2W%Hhp#c%N3n#hOpx|d_QM;IFXiu4w$1QzCPH|v3egnMW5XLiZNa`mjjp|}Lq zv|;CchpO86_xrP3+rwM;j8Zj!Kc&s%z)5k zpU@f;7jlJw5CHXk#+w)SvZi{swWaq96#+Y&oTg_&m4K?^E6&Y(&n0AanF$(LvM1v6 zvaP3C=$x^Ej3YTokWd^jN~k3{f&-7u5c^4iI($XHrgt(D0nYOunl=eRrD2`PMy~$T z)WUmdrUO_kIIHnd;E6z*@BR%vOyf|aiKM1HqL**!0^C%2rKM1qX;%Y5>(M*a$tUvT z8Vr1c`k;Q;qAHSqJ?6U%|!ky;a)90Mxif+9hBFQ`vxKatd`pGx@86 zW{>k8vlt$o<`7DZ(?4JSc?xHIFFIf-d){TT*3t2hS7c-Dw2LWidi)HxzAG|HkC(M3 z{9)b3K1q}sl<|eOwZPca!c1kl!)bvH4b!6zR&?(b8Yw!TA`e3RA4RJC(O!O74R1~A ziOK0*qZVtQo%F1l7WCuPZMk`sKS=V8o^P@%sOj1_#OtP$WMNn}J}rBRvu!Ys)3$HJ z$MNN}@K$1ss)~DeOrDb)OZvH)EhUq+bZgbw3XndiIcvQ<_*jJ9?{j{54-VFC3tEHW z>r2{|qAhg|uKlhfo?C1DEbzU2r~E#ws=<7JuIakObtS?K11Ky;a##Gb$~k$8r)y&$cy~y~6;yME&!- z?$FfwKD6HMh4gnjlEUJH=UGfFNaARN7>O=HWT2hS&;d=*_=$2+cdLs31SFbMBf|tP zQGMvW&Bm8uniAS(7AAI9h^{$>bPt6kz^=!efB_oVy!Ijp@ZH9iJ;W?fpNI;Ygj@jO z))zr_P$L+!29*+glY7EX0Cx|t45}N0MsxLLWtV};2%W}9_vn-6%6$W>8xsr9a=_rR zv)p4~7n7^6)ls2|x-2j}3PjNwYZ1Yw3vWZcHh!fi(OSSoK-`4+{N>yzRQYW&f`S{0 zbu6C)UP>)j{t}S^~b>`ARkfF%*Ae7kihHw18r>c z)o3!E&#g5o!%D#ku;DlMFpq;Tn>!HL*f@Sn$+T`yZ_QeGnHET$#Dp+8yMZHYZ7jNe zy}rpQmOjS=c3T4cB^3#+ZKBfk7SdFnX-dUe9c2HICufrdsBvH5fYqH2fSy`leg?V~ z3fXAa&0Ug{_M0TL0}V67n8IyVR3Hf8M0%g4^uaa&!F{79m3iIiSxSXwa<1!R4r$_ zLr&k~L6_Jq)e{hejRy7zB+Jc;Q#?thho=27(I@-iKZQsSfw-FsZH}(0v>&lWx(#3yjp1 zK;VtE;k+D3{zA=#6a~3FDwrB$28oQc#R@TZ>p?Oi$(Gy8DVfiBHNf%=gdBcLwq@xK z$l=bROC(b{=Jgx#l94Hw=#R}_KMgb*#(AH?3bRUK8=>^e;pkzVOX0B#96ktE<~nc> z%Z{pq#tP5T@J8&0k~ERjaTn0hCkw#A^&pCO;sJ-i+@<%uhHL1e**awDxo?U=v!2SB zIhsMg#d{MPa!z7iQict*_zWF7MgB%VD&vU0@NuJ#I!1G2a%KFMgpQyXKab*iI_&76 zZsMhe#nS?+RqP(M+x;iKjogPw_>-grnAK;w_X70aUQNEoG@;+KarIJP>kZ< zEQ=6HlEqLh3J_|CC;U_HK$6I$!ALK123nLX}J z7~{&3EdgAwVz~&6`LX%=KQr0Q2PUFoQHA$}~PMp*XY9{a)C_^xq7 zu%Gq5CP+`R#nm@9U#YhuoXIvO$Fl0R#C;JlQ$?o1E6`kOC$llTMkxmYvx*rNZr4eL z*gn$(nO%)te`h(U5_OU>Z{=B!7&57_*AVhV5;I3FdxOkD4svveEnZ7t6WGcyh((*_ zim#BbMv9_7npRBo3oS@-pA=a8$jIU1f8B3sVT4_ug3_mJgQMfef)tdi=tgeyGH6$> zwI_Hp9I3X(Ft3Iq(*rDp#euPZGDqI=rL$X_jmKWbvk0_PNG5-VyU|3>_&XS8-I@Ze zuT`^hePS>8a+E|0*eeLnRsvbBu_PG{#%F-rDmK*Tvr2N0@~CK+lXG z#}Cc~8pqtv$I8vZ%@e%hp#e%uAe=6-#nlz6BC`>v1=R@^Pd(!5_34i>+iT|W{Z@}p z9L4>tz-j40%@5&DXcHrSRHdT@T`hI&mc1DW}e0w$lWvJ;2^7~ z<%m>&B?6WwwS3>C>iPb@m_zK%!oH;4nNY6~xI z>J44xHzaZQV#`2KAtdRgAh6(!0rDA6BBW!gw-{VV4K5p z89=2O^yxyJDUP3AyQ!`G3W{1yl*CeGs@RddlBc>IV0HAZ5e*P=9J;#5!8jk3WxZY< z8FFqv0+x-#e07&_D6$z$%2E%_>?MF*70@-aGMY*Z2F!IFwXdf zoD~N8{{{h;Hkpe*rGe(H;y*GP{C1qn)_WoAGQS;SbaFWi_KY%fqEE@g0Y){wYprCr z!DZ+p6(Oj1K=z6ximcd``)Dq7J4|$a{}%9y5Yic8ULmWo9Di) z)R1IYb?Nf8(V>I$Nn!xAePP-)`AZEm!YK5WEtQ#&3}AXD^@{TJPFSdK+M;gZF|4>5 zfs}^YuB`ZVQvmU}*u_m`D4=&_Sf6L&oQD+Onp`ZR?W9Rx zAul#0@$7?wQRuF6CAtnVV@H$fq+Ky@+Twpw8CxN*$w1%r#p1KX@fpGtS$fd?*#y`$ zlkGjW*$N$bYN{q_wNW}b%!n%Jcx_PQVB@hy%_EVn6Gq4b zC{|>6AZ-t|qnWh7s(huZf{tcl_kpT02=dL+WWkwM8(gcjyXZbBqJdTlXJeEacsNI# ze)NCx*c1r`4}jl9f|QOel8$M80v z)x{bf>a^sfuc|g)R{ZR4_PcrmiE9=XGrcZjG02~IB2RxX@eP=N6)5-+Rm{%)^kpjb zY|oXdy^n3L!G#ZugM{c(5fV0TN`%N#u4v;6w%@84^+`QOJIw)49g_(;uRYG>5-3W*DymBn)M zhUr^PVz(l!J07^y#hUM2kMuHePV{cv$lS;wJ`&PCrX`jvpL!fU*ip304LU0k{0>Pt zY1chRHK!!{VBud*MiD=YwgUA)Kt(oDf7G*W6zV`$)O1vwJx@BBFt0~Uk~}_}l!(qc zp<+Agz{ozDr zucO9WgwpBk8~K&Dkf0xQ3XUBO)6ROD3ROS+$Vkc0KJ;~4*4!Rj&w8bP<2t*yX-qdw z9sROTH|m8?`L9?);@ooLpTE1?1fiJgZDY}4ZTjjuHdxp!`#l*u<8`RP zlCWk07r@f8c*Ps<{fd^we)2dgs<)bUxxwp2ZbaP?{>i4Z^^oB8eIZY}DS~&%O);d- z%*^Gw=VZDraww{9T6aq3JR}%}#d9wU!E-s8ZRG9re8dp(X=F9jJqz@TSKL)3K&a5> zqClRwlX~H%2pbw#p*i;PiH8%sVO6Q%KFONb)>!4-7G=e!mRV!vdgh4UwE0ZeDxL0UaKTNJ#F;R z7pg~&-ShECU=|6nt*ZR$)|7E>HngLl$KjK-@e_W18W`9|zl%-COdRTT^pSZsWSs|G zP7d$PUMm4THz;?hA0_#y$Phw^0I zd$4r}xEZaOKiyTlm91nFO5z8juAJ!5Qk34bBkw6b1m!(T!C!67Z< zQNyASHj->%w}R9PIx`Gpeu}`t)Oq*~-B+YbwF+i%(@*Gip$^S}nDSI|4aZdDQa zx3RZBa)IP<02#O;PJd>|2uL@54Wv-6blrTa>`YuX8PkhJ-U9fjh{R>5Yuv8Cu(#Kx zEbU#@b#KEM@q8U`!^~mkm+8o0;MKVh2F$S4cVkKJU`~KG04!}@Ts||i1hp-mOIR2c z6D@r0Ib>SmA%IKN^aq+eb~l?8HvHlbfH-h1jgUmym1fBHLOej~-I+T|?-04w-@-S! zAc#x#!`xK#)XJK-Vp-qAKiJUXFT7``xnb#8IHh=pyaixU5y^Li$^wLv-m{EdQg1d@)p5~kUah$)g@o^ipTKdRo zHnTAa*b;vBS;e(uC2FI_1ZHu^}zGvBT(+ARCZ{S0r?kixLS2V1oODJI|c~*WJRiTw&;~jxo&Y zvJlV&>`wb!=def^aN(WM3j2fmH~F@`uZLZ_`e8gs@*!Y~_t&L=bSBZdoc*VLKx%Am zj8j0ucu>HnV1Js}GPe!2BgNmKlny{&(6-p!12RClrhg3RPPyKzQN{u86AbQMWB0%O z230j_1Gq&gKuoI*76zIA^@r|1cgC2r^VvCz%O4jm8q=D7fmhwtDwTS3cO~ElWjS{O zh~@sPRHQkD<@qj*oN?$P=zPEgW_g*53;`UK0eZJ=YU#@%llp*70wAgY^HUr`^Vyf= z57mV2v&&5B_&PR_rgwG->>mT{5Kg**l>XaS;kf7NAN9|nh5YbvcC4)|7U;>H$#7k2 z-6@s|Iq~Pq-9tBT77(^_LVNmV%11!@b4oR!NmyG*{$)n?)qhx)rNe5_3Cb=vtTRoY zcsu|IBt)A5Ps;wQBZU4Tpn}v5m>F6(09Xxw*;qPSJ=3~+0paCnwwmyce!Jok>(H(0 zzu6#sI^eEjl>TY%1268q8+pSDaT{k*vfCY|zwGEgDE_y0?idx0)1L&<=d1Y|kCIa{ z2W>rPQ99zGLQejXk~XaJRtdKL_>UO?eJ9#1s0aD1Jy0Bb>xU)G?D7LL7*N}ty@2J9 z047pO|5%xNDkl4ra7>dS{uIdki(X{c5eov{^sl}WB6q|v_(Z>92N?rk`2*dtXj>%y zaydmQYlR7sG2wL10%&!U{ZET|$o3-&H^gTO*iJB@W(jlJ(osf9FgVth5M+#UHQ{v* zc>~{MBm85{h=^sbYaE$a^{PA54oUuSnEs8hr`VGXNu=hR3|)G@F!hRY5LR>lFFJB% zj;Mr@KVyXlU;ibBhUeZt5?eHZouAMpmE$*JdtKikhb8c-U%(tHr`ifRRdK0BN7!NR zRs!@iz?y*Zq4xz4BQ*T}kr0^k_S_)=UZ`K{KzAWTfRSr)-GOS$pJTp(ZL(4RsRs&3 zg(EI63XSTZ8sLUi$5I%KS=b9}D}fMR2A+*C1B9_7$#SKRu(nF>#-P92=u6k5Isx4R ztC#e(qIRdAA=S>3OmN5J$!C8VG9qXha*cC0xc+s0Pg|k(!leatu3x=oFc)4yXPgd8MpzQ+&@FWN=BO3WqT!8C zJ6(q6SdQ|6{Q`a+)BwJH2@sbm0g8BwE`t>BeFAJ#<$VmG5kG;EKE@R>VZfH&=3hlH zNen5y7Ou$pRsvhdFUZET%QN1#iP}Ku=K}1L^-ZlDI#w^;$G8e1jY%zt#kVsP9yfC; z0ebTi-9*Ig_tr`1_FXvYYPdnaF??B4QeF7R!wC+UH~jM8QY)5lClKX)Q|Rm+Km0Iu z=QXUr0JadXoJyD+zh{a8Dc*`llC{xVcx_C^!LEO@+%l#8a^=dwoO$GR%XEDJJ>rhY zf`20ep8cF8Hw%}CX$qFDq`e;KvytHnZOcctPF4c1=R^0d>v&+$!a_D?AimRHUrFDw z`6j}=4}`r}4-4aopK|Dg&2U27N?~o#^8NYqOF$TgVc_=b?I?U{$jvG1hE#8_16ix* zn+wv-9VFSBV#*4Q|66Uuqn^X_dKY9SCgik3<%e}PzMVYM$QYs!#(3CS4O>G(+8E_|33QG9Lky~oYXwKX z9UTwF$=_nZ!thxlY3=#+E9|dIVdpOv=&1my!es#K0O%8$0vyek@Pm2UP2uN*T{)_* zZK_JEFNK7OF{dK7g;`E+*RVhrdH2A~l!%&GB$Ip$FZ$nV9U4 z_%MY?il~7)S%(F0agNr*yMWn(nI3G3a-uS}u6+!$t(y+Wyr3%k64+i?0R4$0JnYH~ z>TOwN?0V&bU}eNm)K9y^qg8WRE#`CK=6TzO*7v%q zz%Nn{I)W%&HhKLHtx@O6WmG0k%WRnaxwNXA6}kx~#yEl$Hwg&I0|IeaOMC;0?TX*! z+OCDww9hIhGm&upqDS}+qxb%Kc8PC!v0bjs=)$iCW$)hbNBJ?&gJUoo$WUA(S#wY$ z+4;1O=-=k5likZIv#{XEW&J=}LP5vZvvnYO&s~eD^i6pbHI;=vZLqja)@!Ks4Ky8+ zT?I?7cbv_zqI1dOlOzGkKZE`{v}%8r?(cIgM#_9|lOpe23M|!tYEQ12NK#stmO(qN z2`XG2s^{(0n=;tk=$hL^9q80hwz@y3g@3fkf3E1`FVgBnjgsdW!pw?LAZw|Tl}l`A z9&JnL9Q_f?LmtEyA0Iz^KQ9kOmQ3US=>s#`Hr741XiGq4*?~s4X<~+7=m8OPH(ZV{ zgWyIz-@(9E_gLTdgXTbS)3=F+`_D5U$6F@JQmIiNev}M*%N)7CJY3!FVK=Y&nCR7l zT)bhgqJ(Kt3l$4ER%*x>m^Nd1hVm%z`EERi--kX) z$2cA^bq`v|knch1YrZ_2zQV^f#YVeJ3^kA0E7kc9RufOG7M_r05sy6ZSMRU!R8@i0 zNLwZLy1Kl_ZnUjzxeCOLsYdC$3^Dl0PuW$~mH zv2mCJd+V@x-jeHMX!uiE#jIdddpy+}EpKNvS#4Ogx>PkN z=)0#%`h%fYB-vyeALJ7gHQc?}%?wth3SB zZvCPcjJ?q;U*ydsIlfpMY$q5a>gQ%1JhQ9-b9PA??4UxYe<HpLqkrnsZ7^*RLmG`8_@bcCj#rBEvWPO*-O9=TTB&@gcN9QQ>Id zj7cAlrRYcd$Gv+W(?s9#6U#DFl01F=MG9+H-_bD8c^Z;h7>mEf5d2tT?`RzJ0D_bt za7FkJ(TNvH<8U>T)DJbfaETd5>7Lz5`yOUi3_njE zxB}i)4o|F+lQsQrw=Ii6pfJ$c*R@3fc_5Dl>f@wXxIeAY$+2wIqZ>YCb<9o>x ziB0K#C6rl5RQ%gb3iG?{Jn zOIS6YzoQpdTpebLQnJAMB#ru^iy3dxYAo?;m`AD`EefKvY8B3gWPei-%^Y1#fmfar zEOs=0Z)b;8|1c}M{8#?kEh+yNafG{`){k$zt~$ZoXjYXugd$&m-kWWiIH%CwUS1Z2 zr*+s=Q2l7q`l9E?28^Ng?N_J3~`m}d_%?Aq)ICI++-E)VYE(J#$@o{XsFc|cmXAAs9?S#^v(Fppj_kfx z%>Pkhs4_7*p?g00f#!w2)=D3qVhg6@dMi`?X<0VfjDLjg(aXyEtPRUgAp`Z!gA1ES z^lBJ(zB}z{s@vPjZkAs;3y5BZdm`3{Q7^6(K(0Jv;x^x`BKYU;PaNaw)U$j4*zhSg zPhJ(3KHmNDeG^<^3tA;PSKqB5^FIE?KTlUWY$M}@N)>c2?;ihHiw|z3 z>s_IBFEqG>%GHfpjdtkq>JLlecs0;YSnYSQKbJKM%K3zI~&^K*PA4Ait}2MC}3A`%^S2ph3+yD3}BAM@PDgr z=f6*tD2`^(h)NB4_~T$@$-DG!;UG`ct(gH}C(U1Plj`qr2{E8R$?T9 zy8}kZU`p7<=}0f8o~bQ&Ci#tC$~t=tIUeqMY>3p)fV)Tf0EtZdSBw8|l4_1kS}kn#-&N&7{$re?@*wM3 zG;Bs_z^yocJBEAm;wfxW_p>gNhTbam;me^To*qEubc3H=iW1R-t6k{tnR0jd`TE=G zDU80Kd9qwSvsEdHL59;*LS~HfSs#6dP*d*bDOt4!qd-MYuI)9>3s#hWefmoVrhlXn z&MdAQ%Le_%cB%mu%R_GF_Nwnk`jdf%fZte;6K_6c%Yyjse!DwaI3kI6_uKymZ{U~9 z&B+H51iz02{pZ@!|N8tddHl-;{`a(j!-XjLvCs?HWH4;AhkbBoM1mJUe_OHvvetlj zWG-{LQR_(FFRsy*Wb%On2dn?l(?zb-Wtk#OXj!IUo&yB1d0$#79ht!hk6PNhM`EP`o6IKn4-m1bsP?)KvLYl{d}p)KQD1Kp`7SuY)XltP}^~H zDN3ka9Vfga+p<YEW34hj@jx)v*5XY0&JX*U(&2_;nnvu$KN1@ zn(-!?W!&25KaxZHC_h+HS-E8fqKrY>uEj6$Kc@(92FkP@P>MUYwPHUgpk+4 z(x_)bwA=%N8g-*%t=HzQ76z&GE4>!cFmG@XVrkHujwg*1^NB2(Ht16%>;LemczXE+ z0I3A#qTWzsR7}%;GwI^wZ44#sY!Qf(@rr;h9{pFB!2fWanBWT6Z45>B*<$uJuhL4B zcu{-aWpF3b!!r_F=1UZ6ho5=m>CoF(gp&Z@qJGVs?R!KIK6MUk+&2kn=%fzXly!k0 zmNuCHwa#O2QzPymA@OkWC1>ma7ig~)(csr)x6BsW<+>UOvA!~XhVz^)T3cU*wSJ95qYl|CL9;` zxLb?f>O2S~6d)R;BI3ogC(c6H`elb0%iFossSNZ zixt9aG}vlCfcFRads;uW$Pm8ST}fAWqrI#hU8{P{x;CX4EWC9R8_=ZfaJC6)pQz>i zwJqR9VJbykv-S{A8MMINik9WG48;7t9z`Hfp~sd0l3(nl?kgb5pCgY{X$La;MvVEG z$2mBg`0Olr8e)!nR(b4Y&EteI6XW!##G?(4D4H?8#<~Fr8C8SN`pj=z@(2_}8>p$l z4nWGzKc&|6GDI^%XCl8T=%tx^v}7D8K>w$@v|q^c#7&ze*fHwH|L;{i8 zzD~#~)^AWx3INImS}iKCLy~`pf^Gt_;Y5I)Blo{!GEn#tI}i-~Cj{mYC`Io4Q(bQU zi;#b??*9!XQo42FU{d_z7pIpLuM!Wk2lHAFh_nBlF#>rS|7k#wB#~Jj5P?!QAJt@R z(JQrmF?PbKw^$JxJR5qoUUll=&+t+Uw`ad>0`XqP#pYtg!&IJ{8q)K?OR;k4@ z`W0H$#NLd-=kR7?4s8{TW#V>=E1^Zt0p_%@u*q--`$9qDU(dzDAHOM0z+^af#aY3u zEQ9{@j>LiaKo-Ci{kuUi_a8b|%m2SR+dsUHy8nKZ@HE1I4XN<<>+quV&5xK~^plG= z7?kg$l!;;|1?mEx`ToN@>A&pGt?==2Dx6XD@ZxPpGvi`%*VJWCyA1jby8jSx)ELSm zLs`Kt2aj``!UxuMvMelP_BhNZ7|mxw5DIY>Hlm(Aa^MC zl<@lW8?a}ZJ?*fkam=9!>V|*T6MTNXK4Yh6YzlszM^4o(Yz#ulqM_ zwcHOBy_uI@P*-@dHvM#r13UEb2eUvST7TbXUtUT%kG=s4tQ7L}R0hqglw`|vFW0~E zcx;MK->-I2DR_RWJJLLA|K7mTC3?=Sl}X~~$0Zs8k%~855|eJ#wuxQm{_VY+5uQ95 zNPd*bk$(@`|1Eg`U-};W0Q?iTts|KYtLNRQ+ZEOWWom6aE^Cm~@_g#nMxh8{&v+kU;4rYJ{e5C&i zCH%jqg+Kp>F#TPr4A@(o?|45W;CpMzwn{C}~&&>pt4Kavz%Xj@a35u=*M2@YP{ z(d-m{+hpHIy`g%cb^$Bp%H}(4yvCYUc=vEJa_gwY37vVf&Qi+2f()Y0{|HZUCBt$4 z1(&V8(9G>xj)Lj0-47GH1SnaA>7`tU=u4h#!8iRY{R+_0qi?b+l7G=xUEq~kaC1}K zQ+%qQqUWHwP9Cxt7_yUjqjOPW$c3s8yPYcyT3rX{e!V>dYTXU|{WO ze)N9z&NHb1ZaaI%hQ|837q+?e`svxvEbIcDYNs}#i)x?x<90S=OR#)7bk@0El1^vC3o# zhB}VRp-wsXa&w>yd33I@}w-0_!t4?L)=YJ2bJYzOpVyK!sq!|R{G_?H02zkjaK@R|=7 z^FI>xPu0B%ESI(T7n=U1LZ^Eh0(ygHqjrN=Z@;}6rJc(0o>9=DfGJc4mb{|@)*AoB z(7!&+0dBbcT(HnC=S!WUX`Qf*cOw5;OPt}73DTLWjZf=|m-}72oS?h+kLZlhW!{NR zFT#5Dr0|3?MIcUBRR5V-fGY8yvX#~={6=0$Gkcsg$*n{f>~@!sg#D4Ojekn7xD|CN ztq~`!ktPPs5?k0GTOzv&mim{3;FMt#p;KDYN3A-JvZK0irD`fqW_On z2;I3a$^p~_3CvEGc0ug5H-UH3}_hQNb5 z;cpxRRV-CQTjt+t>X`0Iok5CP3LrN!{p+%I#n3#4pGGQ|zrL2CA!~jshZRqxo9WdH zj(?^x9II~B$>~|eNUD0bcpQiCzTa0c4RMItk&Kl)sCGT6=xjPFO<9hzf6?OdaDCM+ zxx-Qv8qQ9b0YA>n)c*LbdXm;g>iMEnhR;axf$cSB)i|Vr?#Jp|j>Jjvd_3LbYH0<( zmJUYiNv?M6pUNwGnswWocS@>}V||t-*QEN-Aj*Hs4!aDv#L}eoVjasnco(H&kS|;) za+Wq)+4%WGBeHiEgXTHa;ewx$fNt}&2mlS;vmGgYse|bS14EWL;^Oc!_}o1Sbv6Yy zKtT{UL6s~okb#vxqA#QIPbBz-SQo~33+#9f0;}ENeZc>&Z$%@0j@%S}&HIYg2&uQP zsEJXHne>ThbzK+TQv9&4zQ#+~oPE1Dwc^8P!-BU$9Fj5n<8;Rx8mI3UB;_?Lcc*$| zrly(dzIr${);)$Wo;+Jzy(ZAE{zEv_fyGGr{@Yk@!1c65eE>dZlvs?%oJrKzRnmcb z`I#{(2EWGTN@^=2ouGz?A2LX^2aYzx>uc|rNBx@gc-inVWST;!#+;5w*k`P|;k7A| zWh}SFD)kE^!9JafO9|JBwkLQ*XzlZ7pjtE?A$aEisIY;1jVSYWoSe4o$nvvi zA`tw=PS*I=xb}N*-`sgrPP;y8_o09(FvcW!S{-+?b&1CQC^547Wzra>B6G3)a(;iB zi=rLL0>#H_AxkVOV9hwL9Un5ed4c_Rl)3_1$n{aJ)pq;^2CP0 z*4i>wNc{b0wi89V*AT0JQWf|=s8}&OcKQE-U%qucR{o>p%2e3%O;lj|&@a4!kuqLW z43s3-P{IBa_v*kF8;DI)I!f%%)x`^-3Yh#7`AO^XE-cX(SJ2_E1ok}C)m-wM$I5c7$M&ghHA zqMSdk@0+yVmwEr8UGQ&jdX{3G$avTZLQDS7t874ltl_>nW@p{{uh);{t0kE#h#9mh z!=Kli*clYA{|{vnxastN6IH>%^LTn{3Dr#BnLMxHqHiC z*iOa{^8Z*v(u=|~gzRs~)zt=hA6{_W4!qy8MHUy}h7%QBlV|-e(P&r@eY%PM?l=606;YZ~KG<7Tbdt~(e8$G%4VY2ZhCvBcUYAg$D) zhAi*D?Y;UR^?Lo+bN_z8=YPrSzhw1aI`IE%9T0`?QNDT@aYN=#_O9<~8)9$W3dNEM zHkaS|f+Z0+Wq4XV)YPtV4xG-6%$~Ra#o1i8G2n$s!VIqZ$~jBL0me>6+ofuJF;X67c;`7v41qo0saVKa3~sr z*g+vsIEN0!PdVL1;eTWh)q#6)aqnWhJEODyf^Ib1qYcN%O_)*WB>h zY8F~6oIC8+!1DAH3*hkH-JeQ>-`oF<vW;|PB~r30Tu62Q$aS#-Na@u}z?E$h3 zO0LKK47fDq|Dk69&}TJLBxrL0HroPvn2k$Q46lDeIIUnHR zn(7YdQ?e0&ayZziTl`C3SoiQjf(DYmNYWKN=ZU5=dD;fwdJmf8p)Y*#U`X>7qG{|m zB>esAJ+bmrMU)Is0?^F@!QY;C)^37V0Fs78?cD29NM+hyo(sg@BWCRv8^0kf!*Awy z7>K{*8lQ{S$5XnAAW%$i$q`olrI(VueuX$XAg0V|7zh6TJKKlw6m(YVo{unS%aT%XpU?; zyf##59iESqCAX%@aN3jm=41WfZ=D!)751@%=uM_9+dqWd<$kITp!ZJvonoeXLIvAD}&gCRScvLNA_1W4?+&h&PcKY((3eD--y8 z@K+?NxPRRtj3LVa1pmFtVwX7vFOZHUYcHRgB8nI|pe(>7bCcNgQi#Er0H7Ox#+O1V z_C3fy3JG5wN({%r2!`mgy+whfK$~>UKzAMkT?SK7R2E7H+A75eg-XLu&fsmS1A&q4 z(eJ<>fX?@7exSitAYY+uaLOxR-E!hDSHbks2{MHL#TH@-&~sXRpUL#Coq0cOFONYH z!iDVzT4!UxWQE38zbyDSgb@UUfjZdto;Jw9$Bp1?4S;z;{BhGKMVKAnWh@Bo?#(+1 z30LdhOt%{MeBbN==Ekefz5?oaP|=r4sUTrgmUR|*2?c$5spD{4-@;39oTb(sE&x)+ zP9Flem+aG2l}@7Dw3F`8!+T;RS~)kUC~q58Y3z~}FdIcIHxrvIaQI!J+yOy*s5 zUs91leVdx1E|j4gUS?Z366E%(+w?C3UDL78{Uf3m&{JKNy97Nu6$;4w&YTXYHog>h&G7T^62$xglwV3CIDnc){tYQP1!}&=)u1 z8&PSo$|T)Hx{`&)r}2-vKj}~7x1$cjZoLg2-t3FK7vPM3tgzLxYr*J=T8!jOiG(Ea^3?evMZ)u;_)3ec z9z^mi->UI$sx4LDF+Z5Q|K74gdToe`FrW=;du3KiBU@E^%2RQl*gGRTh`1g)2Pm7I zi)@^YRgmZcoY+#j;M9;YmGJ3Y=caD3B>`E;F8v8lyVQ&)#lP{OY{?rsv;$E3J)B zV($|c9q2k+K+TO~{)%Q{VoU zr)zY|Yiu>7{zo;?$-mp*Ep4elCyZBq`~kC52zDhC+kf8r?(0yc5$m|V_uvP08L@C} zZ)rxNiB%_gnbBYy(LKFy`@>JJNxqxb^E=?Y&Nr4Vh;_f$*?nQ=K6RDopn`?*t!}Xp z_x&+8T#J3R2S&GohhW)d9t*TvT80&~1!=Y~Xv1R5o<5W^nbf`lL9TSLiOlKVhuU#V zda4H)&Mm@Xz+kM^+%Agd$nd%Hr?spm5Mm}uQg!F4yc1hz!zOzta{iUY?Qk~|-+tU+ zC*uaOk-O&biN20?@saLo@#q#EdZX~6so-JHZ0nBQ$VwMmpU9!IwOdgli)^P4Zr+V9 zgDx9oxO}^AXtZuM_7g-qm2kD+8S+Y!`xHC7xgSHr+k%q>$tvS495@~k<+1+_x#CKv ziZE5n9Glwn5I^T?)wg#fL*J?q+Mj$EtJKk|hX)BF_C|{KJx?==6s)tl>HOq-f8+LY z)MkpD7=8UGl6j-7iC-r?Lf^7>)!-Mp%KK};T7Vqi$HFCz@d-Bkz|K^gDbhy4%9+#e zux6y=veC0OhV~UUJ}K#uFN+FPWR8vgp2SAo`jB4^AC|}gA+j@WwUr_BCkGR%=TW}Z z@uuk#d!g43&IBOO}}9D?s?7>P@i$(g@$urS_%$((17l-j#qTW;{Yx&Pr~2Y*=@ zT1FhGc0|(v0BOPMvbR?AN;&AJ=T!{#G6ijg*5c@DV068Q6 z#nsB1o9FwIQf)6fgQ@24Z<1Tg`RIa~oe=i$Hzd;&ak7OtEgm1e{du_ZMHl-Kp|%wY>nGL@kD!mLW?$xoB^XzK@gsp#>)xQ|F@08AG=ccu zF#tzqAki1b7|t)l&MeOtb0D(bY$&dic2tCzBl-xW*DY6nqh1k3{=m;psSviIi+b+t zwkr3lZKrnE-I;9V_}J)8r8eo)NtO9qUqa<2DOhlak6MPFWULi@)MZ{Iw7Ag8eJ6KD z5&UA23gbSeE3l9^<62N&p7I;=slSF=SvKO0r@He2!i!*ptL8Le&eK%eZHbFEfL4_5 zb*(vD5ba*+;}*#uW^;7h&SPG=?1~*Ya4^MHHBrG0Q-z|^fVCE=e(T1KOgVWJamwq^;PntZP;D~+Me=s#m3L_u+MC91r zl2|pPMsnM$w2JFlb$z&HcpJVcs-)*glFXQ3!}fO3U2rTz(0g0Fr~t)h|7ktzxC@xT zWnHZv8?N)m3DK!HiAaVQVWm!H94`pUGIq>|e~caFUz=anID^;12 zVJT`K0;aRx7tW+Ai={1xzUWn3y_VLGIOdt3NHDCq`3mjV5{T=L*?>ocQ|g(&j|ptA z(BM{s#aq~x8%jD~tfqS@hHqH?%7)@XO_cIf0Z7HbNoUUDqIe8L=Be3RvF6KSJ`|YK z_fHDTK5cFHkjj9LemvZK{w1+0Ry;f6EDi^yhlH*>8(9t)u)bFr;JTImi+QN@=*m#! z&%9ophcasZ8F(B_d)#SK@7Psv2r;Y~_HPM9yU6y-KmN8bk3y3TF>mR?aWRd;w%5m1FBJ*dc>RZ(v z47urf$0dwF5xMp>(w3>CjJD-%;{=8|PC>5!G{Jnfd?WSXeV;~2(#wIGt`*McliGsP zCdWlX;>HF^PLbT0milnqz;WOX%40nyiC8+B1M8jV7Aka06`Y8z%O#54=lp5df`n6*O$A!*?dEKo%yD#b*f{xwcYq-eiE^S>I5yXLUA^fT z9p7sviQptstzFTJro(K&2EPVld)(eTF#S56`s_C2mU;Tota>tbZOcz-#;h3zo1Y=I z`l1e)CnRes&<|wsC_TEP0$R^i`cA22j5}6%;6+!2XJq5|m#-q?mzT2SV1ohT-9lm{ zKT{vDw@pW%*bu8x$(#<-Eizjn)vc)$<9l2 zg(_}MZ9eYrg=ZG_94t)>%ii}6d1rA{?;k8jIcLguMV#byLmeBIP$_wLo6fGe8ccjm z)}Q!A^-|d9eQPz;8v!NFAMd{EnXg&ChW|KaQumu3EvY-L3A{AeiJHc^Q)QRzH9lMqFq~iz7_4ng&DJ zz%ckNM39epcIZ}u=%zeKfBu+i?fkX6w+POjpo0ip1l0U8ze>Y(s>(aov)%#E zu<{yvFv?S9FRVUT8aH2B$KG2KM8(^y&~Z*PvHQhr&=Yf*jA}%?*UO51%9FBA8Ox#R zUy5BkIfsS6`&8$+NwsAbpVIR=oVv|5$|#Mxx#{r3_^*xDr2QubYaR&uG^EX2c}*xa zTp$q@Hu&}Dr|7WC`7+rLviPBU!g$uFWZ3v;Vg7Y}Pr1HPN5-#2eWht!EJF5i=^B0- zD)vBKGgyvUIo`m0qXll#viv%|vxWxHZIi%yx1>7?`5_YhmEXq0#~c@;FXi^fvyiGk#6-sa*|zIMNtX*48Xkxr0W2*dh0N#&cuh2hQ}@`ui6nBc4{w zxMr2#ha<)I(yQgA_!Elz6GgWBgm(KvE%*2hD?M$YG1~MUPel7_4?n!R`sQ&InTw`V z%Fz$Aub$t(QK%8NyS?!mWAN5`t6J}z<+`C~yZaNXn6Pc+HgoTR62A0Ky4Ah)4{gM* zD@pZ358AyA6PSK}-PkDlHOB2-3v{DA6bN9WuuLb)vW^h|X#F?jVOiX3DzJ)*|Ak$ z!+}?g;a-o|pfQ(XL@2Tcr|bpIDoHnDlxP0+l0PGF^ux$t4)pFS^j)^~=q{`;SE6wi z-cjZ5{?k{S6GIl*jGICyTtS3r(bWZ}m{lgc6}zkp9U~$F2IX?h_jfg?Z|&#w8b9e& zBeSZ^8!r+qF%**$z(+WlgyYP{U@(N3*U<-TJw{^Cr7sBd{Yo9Xcc%roW>fs3YS32_ zJ6DD3j}6V(;yVunP86wTq8*i%9Q;{n-{@y!I&}_6<2@%oM?@f8>hXOg$)za7uGhL! zhrd5ip#5g{$oX{aE-)XCl$A~#;D{^SPyZ%0GPZ1qL0;(O zfl2GWTe057Lm*V=DL)FIkN>19S8b6``SU|sXN;vr+|h~0zfSNlFoS;vU;!$ANH zWC*YsV_#;3!5*mk{iqS$yv9ca;O#!5;OB=qRBUWxd#Kgh5jn%|P0Z(mzT=Bh4gE~| zdSFH6s0JKF0=C4$!ee>t2ULZY)byS3d5sPXTNatfG^-+ZU^sPr+xg$IMTp z^;Vp)L&Q>407F6m{WKf>K1gVbU1=E6{X@b%f0OMFtH`P+Lsp)+xFRdxX*`B})N(U6 z+AbBc;A`qK>Jw6#SCjABUIC?8k9hn8f|h!ac$`f#&v~UWJ=X3Z+Rd zAKBtV=@DWX9`7Ub_Tf_->TfJe?E5+d)~Y^7{|qO0bj)|>W2N+3)--00o2uJV(F-5=-C zh&-QjMZ9;m^dleMu<(~Hn@&GgnGnzEx(C)#l%&wVOuq#9!h8pOZN(UUr6lj$ZpISk zj**V#OKAoncEy?fMahcEG}C#mF2v31;-UK{Ho5U8Y#vnC#m&F^Y>+BXOr>p3A;))r z(Uey<@=P^$)r}eyb(E>KZnKPjC$4x{Jo^+N4OOpiU*qg4vto`SmDhD>(uMThJvvZk z<5y^%qHjE(Dd|u+VF-OsKAvMGLSJ;-U8na)=;jryG{S@HSQ|sgNr`{i-R3F=~-R>OG`vF$|5TKfD1oYl&VG=2YEkWj?MATRV2azjbu zi?iIQgl}V_OyNw9L~(Rm1S37=K_26r38r%917-YqKh}QmNfOM!hA;|tlpS5>U+J0& z{H58%&+lUIKL1&M`{U5!Fs=Hv+7vO_?_<~2ZkjC@7{;Wj4ZM~0r z>YZn)`yP!9#iu*@t#Z6=m#T%0Cb3hAg@opL6DY}M*H(Rd^2U;=Ny4^?*twapMkOlo zhBc-A{EHcQZ=j>2rFWjmqgL*@k5KB12Dh>|rt2zMuNLB?br;@1>ZQ%dAsGSmS8yU+ z6ktkL7vD_!O2uObvdEkK`9=DWkA9d}NG)lbEJZ!p%j;81#%M$4>Mpv@HG;&od>HD$ zC_8Mi5dA=2i--s37G+{Yn~Ht1pMCUojkuw^JLBS?l534>;p}SO z=z+M3S-n~uX!&T^)fe5PzsSYFFhfo~NL7tI+l@bcN$tRl{j_)p~@MQ^`@ zJ&=R+6nFkl5fP1P|{;yqKNFT~+?yxy9tddHLR z^TQ`j7V9LZk9Edc(6=UD?Q_#z5IxQt4YqO_kAFd&=Gs(zZO-rJgOt00AoSvV-CLgGT2cl_MC;8hgd5%S;Gz_Lx(w8)s>CFE7aM!$~B>rSF1IVFQD;&X^d8>L9 zi$#(~AB%7&Ks4WgBkGD#>r5I;<_E=2c=t%c?$M`+BInbQdV4W(kLfb~FW7o}s$5sP z{9m|H!BTP$6eT`IH-Qx@)LR|LKR@2q9xjUN;g>y-p_=|SV}lbv3mirpgP|t8YD=oz zPXK;TTQWZVCm9R^?X%qAZ7ca3685@9xIu;GduHR(voGc8OJr~X)mW8RI@O8H`8HUK zPs#R5XG50W-XNL0lV{&|)sDg;E#X+|TP?+8*6U+cOt~7^qzVN7RhqA!a~Z7L^LcSI z!WEs2i||CSrH0QPA@B;T{X!n~+*{ry5e<{e zN#It=WF9fb7}gjDqM!~^B}CB zZ|B~5tTYq;Or${1rkrlj$VkQNOVUn<9E2gjgF^P^Dz|J`^eI3#qYc-!8{?O-D#i)$ zugys?>`2L{)V(3$+d@2IA~xqDzbH3--H8}al%CzFh)PEmwt23(P2D7O%2#}QU6=@~ zS1Kr(FjPdvXZYPCfnGHhf@rGF*;A|6X4lUGOdyh{`PJG>+ee%1orb8Mb>cn6D#exi zii$ zeZkqnJ0s3nXNZ*7Z-^wPx6%sx)91RA@g&vLl}&W7G(585+fj{C&wC=@@TXW_(IYAj zMy;PeVL_~qrSHqM9~N*aT%|UTZKE1tA6K3BOyMl&bRp4P$ykZ4oe#wy3REcPbahl>;jdStRv)^Lt>>D-aF zJoEcJbe8fN1GOJfx>M{>|(^f|awvxioo#<0Zsk>1TKEhgEL zyTlybr;|Uo>ftlRN-cGU$^3DAv{++_&xsT~=}cVYq4$itV_cRN$7~8XT(ZMOnc0@- zv{>X++?tX72LKVhLi33g3O{`)Cw5SRTKsTQUP;%Z`A4nPPp@pEyJ||hX}z!BnepEb zepETk&4}fBvz_j!G&GF}i;NCiAb2!86aTjTGOt?2+~~dC!;<#5xmvPv_Qa|-dqFAp zDB5yd`D5trf9+TT5I(m*s?1G)Jp8_rr!3+k?7KwdyN-Cv6-q5dMz*rtSmL-V=&rBH zUIVExHD^m=1I94SXFyvz&?QfL8;p1c{zKG86%nL?A&Y04l_3yX@3o-dy>bnfN;%bO zQYphL0JA3ka+o>ezwsmA8T9?cUy}8FnYC1ygutNSSDkD@N(U+rBnlvyW4_F6KJ0{0 z?Ujd%?>ZOK-f{&qD2jHn3C?-3VD;f}Nr&c&jUw0M;9$8Q*%q6hn5~T z=9ZfB_j&HyxVfrZx;${ScXD*FbZ}!7;gPekbF*~edH6v4p{2Q_1t`-2Tst}1nYvjr zy1BSp@~BukSb_2d1qDS!q@=D9{GHC<ux3!-L{o z!G}VjSFhp|5RqRaA|xcDCc8mGPEP}4pr@guV`SlGW4v{TnU0QKnBxvFA1E8fCMqey zFTpJ!$bVS~*43+5i3o|Pu3e+zXQE@`|L^|!-2@@U$C|@o#KF1+!6wDRA;tRL0)asw zSXThGmjwUq2MZeq_X-{q|0)3?xS{Gg1RDzn2OAgX$`xE(aJL`$9)e4Hg^Y<$2JeQ3 zDfE^zIe%d6JACH*70ncy1G_8&W-dWj32stSQPbRJWn<^y6uc)SEFvoQ;GwLXyn>>V zmbT7gT|IpRa|_F7R@OGpUESP0JiWYqf?tM&hP?`Z9T%UF_%vw-Dzkv* zE`^!P0KrWb!OKukz}g?q{yoNm{)agG561qJuSp0I4i;!U98w4zaf__fGBo#JxD>}vnU#b!kvP`u!cL*E<$}9BK>CPQ9`laP-goU(}jUf)6_I#hs zR}K$*tm!lM0AA%8GJo%IMm`zs+k7_UaL(rys|+O_B0LnXRT);s_gY!{RgkdEC?=YLprytt^p*B2J^HHRI-G+Z+ zE#2o?LMX)b9C5S?`87wBZdD+PNf_LU4+X9@so`AVG6V_cD7~)u*Xw8NM2_>OTaKPv6RRSX|H})T>nzZ*j_u-(}u{>k2x>9jp7A-es2$n?g#UA3N zeLSJMMB;|Th{wk0kvJ>Yoy{$Ik~h61R)cLvS?~0%vST$*iHZYP67{YcHynof3W-xd z9^^;P;3;eq3jmVg4ZpHpfCZf!=S%0zBv zW_q=u#${CgGbZLfotH=4QwZ_|7j?7B7HDoD&zmh4r~=R%$%|UbD!LMhRqeS1Dio6^}MNznjSu7w@?xLm&#= zw2a#>l8tCL!EP@_SiTP^c1>6c+Iea(7%EML*<3mgmc~jsXikbEVM9HKSE@Yl-G)%_ zfFQn&bgm$XLw%^*rG7fL%@c97*28k~i3t~W zupyJGH9A8Jk3P!Bm9x)|=em)Z23A{#!(V2Yx6*FoKgL#x@sj%X(%&ra_C8`@j2_;1 z@9{u}d83r^lf`robT@fG#c??KlEPAabfYTe4KjZlpze<4i;7=tu6~D*6yYV%$5zCc z2R66z5nZUfv`7)zcne=tK28ZDyNYZ~w!WQwa~$uH7=e?#Ukf*6$x;oj1c{h7Ji=X^ zh!pQlhA4kQ7IOP>Y~6^F2B7LW2nj6}GH&M}Nsk&qNT%D5749bYrOZU?y2QlK+@gz< znPi%x5wTG%pm_wFIhuhVG$Oqp@=2*DUOadfN+n2r8@4}rUkFK^PvI`pNE^N>rq1lw zw5>wCM5oSVk!olD0&5mB#Gs$Ral_@2bB{zjlVbumd{LSV6`6ML&#qn;#$>c||;PNU1Gwe=akO+RgZ%FK4A zU2b1gjBQr8@wP?v(eSrhQ)}z}Yc$5mCEvUF_J=P*a9I4DY=KuLr1`@So^!b*Qx?RG z>Z;m;B1WgdX(YGoy~&=o*_mOaDN71dfraR*D@L$BZzf)V%zKeJ`eHqANWy&nH-xHj zB2~Z~ggkYLEHm?97Kusv=PtDQb7PFEDmR;(etx7P=Higk@QC{?q^kIodzD6CO7<}e zaUEOMXl!nl^#mKe(^arem6L{u#DG!aQGx?bz`i+pJ0UdYu@N|<0kq%z>N=T+;l`s04Y}8i!s-28Rr&ABV6o6G1wd9J zH!2ek?7ALL`B(m1-6-TwyXqI9Q+*2zbBZg^{nZq6S&rk-vdj9@BAcm}sf zJ3K@1bKul|?p-#+y~Au0sbL2Fg^|NXrnllfhO)=)rpqlYto&lg<->O7)QRCE!rJ!N z5xV^BRiUgk$ZfKSM{p(sEo-5n@!83WH2cGR8(L=07WOM%i?lNI-i7WY*IElz1tUFQ z;Mawl){;^%xJ1lVYaetjndNsA)U3IBmfcS9iJWP$&97?THYDnxmu6#JGC3?YB3OSi zL-2juM&QoJ64ABzC{-1=j;LHmSGKfc^XHVz*7ut~9|4D8sm7G`LhoHMt`{YFp`8Ty zs3zPxL*G-n#lkf;b)N0^JwBB6wM-luM6diWl=baXWU7g94V%<(-HBj*hMWuhh7$Ex zHKg>_5Yda-V8l_8T(?CiYVD^ny;t6qPd=#-FwOQ|PP2)hk45XFw`oRW%2Qj4)?bWT zy#nLpOY_Hz(G@))OqXWF^`dRgU1D&ZpH~a!9=52Qz((cRS1Q3E_F4r=mCwYRJg+8c z)2!_Q&tQTrWnrp#z`hIE*cr_>4>(@jPz+p)KgwZr2k_dLpV{|~%>w46Lz*zFs2-g1 z8CXiT{bApt@;PWC&K2Mk{Gpm$)X${y3O^0Y}RM?{GbY==Tu%k7AFo3A$ zK&i-I!j5e~jvxB7ll)~UwPSAp5zd+_R|G_k!zm}S=WNivbA2`oEP(>Aw(+Gtm|8*E zEPILcBKoQrJJxC8#+WLI01NCWY*jixg#^wE4^tb=Yi9;lSDyS+1P$bs$Ql^uXPLoP zHxaU%5$1@gk_hQIOM|8oa9~)o@htH{It)Mm9Z*54zVk_z)GDX?*I+nU36JJ+5{vpk z!d!~lHvP2KEvPS$dm61u8j9<)8Nyw#Ewq3%DYeY{5{Q156|4Z!z;oo<3%98*hN;Gw zi_Tv|g1tLv+oirowj9Rz-_IwVb81V+!iiIxm!?RpgNrRrSc`UuH||ZQBrp)t`Ei6$ zW;P%`OJD1hBu31^(a&wB1%lh(8Mtx=rekPr8rc>%0;REV_en6~3KXB@uI`-3a%e9_ zAZBmHLvW%HbGHHs__3zdmK7_5yND&FTiFc*e1fO2lgAC0=&Zi6V_B#>2@@RxZ5-1u zv7oDv3^VkvT!7qdgJY>OwGq!}qF}q(xHf$4322|WA^qxo(y%#1TSS~s@Kz-l$e5T> zMVGTRZPffeA9UCaZBu~5QUFK(3Yu_wVl62K9wtfH&nXAO#ipSZVI{+&4*+A2>9gK> zQjv9!=)EGNF~ZDZ*L3r9E#D^SPr2Ej0i?E-+%Fjoe-^1jcwfe%&8pO--QPK4?#45S&%zqz9`BshU}^MKkiS*}(2rOL|= z(PkDa3VBUc?q6+GO#AaylzVqO^r^0B{%~TcU^LI1dF}wcZ*Jm(>*e4j$q_1w?V{Bv z9_donEdej@v1G}bSRcsy?C^}bnVTY<4YIZKtD2|sl*d=+*!Cq4fqwmaJWH&XuLbsF z)Nlv7Z}MzX-RXXrDSq)neM+q>x%#-7`CM1xlOe6!VCsTVn9dVsUdQx@(hgr;BVN}b zY_8>cj2igdOZN#`QWtM$eoNq*?!cD*EXt&!gpS#jB93nuDT$y{@1nBX2}y7gh0W_L zJ2GS~aOvGioUg7AHT-Tgju(M9b3lirrU*YyOO_CDryHs}Sd4q&(b5fS8jX zjB=Pa|2UQPWgtc#avh#0@IIqe0Sd8dtReqW)$M_O?Bw*(QH1fh7i#dm`b8;BZMbwf zF*kFPqK@^EA`gR}A5IBLTSki=hdLgFTG9#eJ;^N2i-n~8^s$?deN}Zrk{O(TuT-Lw zn?d(Z?^=ADb6}>(mdb#6wb0G|N&QEk)2zE|ZrqttzD{UTG1YmPlYGa`M>S|>UE|$M zg}*0ML@GGDSc+`~IpUsjxM98YLRErn9*Zg259w&RD!Kn6!tqocKDlk6dG-4o@sHGb zDY^|NU&SILqd4U!oh)@omM`&W+xI~=f?NLDt_w!PHU$pPbiUN+$NRWkGdDW*KUa?a zT$-@rN|hkTEdCm{(4OaWuR7euv81!8asW7nB|f4nEa09tORSQOZ^ct5y>1%6a_JCX zQ<6s?+g9rhe`5fnaDex2Q_Wtzt>Y11j5zA$iZ3DNjAx-jMg$xL}1H@CT0tNw%)Kb>1u0eN492NqBWJeg!ypX#FnSd%03}*;43_ za|k)K<2vd&B!95O&PhLPbdJ2Ni)*m2S#q1-dZeLPuXJ(dE>6X5k~t}!AWhNFOP86m zrunI4{?%koA@zq@l2=jDRB;Li-=u|Eox`aJhPeoF!f#NuVeg?f`ov##s$YR78c3eH+-HNsH7*lPB{sV2M%0zpu=^k7X6t(Q$&hxx@1 zg##HiU%Uk7e*Zww54-x0y!ggoA;fxYpPggjHm6Cp+3tqmV1tTa5{@DYXhX%^nlWy- z@@G?`)OL# zjFck>1E}j1mnjc&tsuK4XG14e#f2yvJgA7qX+IubQqjzFGDE}8d$mCv77-Ker2P4V z(p?Vg>gw$e*4j-cbDVrKTpus>*9*zBV#3bOqv^=|U{4F>L29j#e!@oRO^DNS;q& z$yidGjjNT$uILjH6=~z7I(%|6xza?Jp^t!ubNR%yWL#OXJa89fvG9hJBNH~$(GvRX?1Be}dj0uvqt)HxSeBaup~+o@SGb{sx8ld50{W9_=$0ZI zwOS=AsDGv-3&j` zmzZl{PRVJUfoBNgNIGw+VfndAQ-8bFhhnCwV8$4(>|mNpb^Aa-H;-$tEmwveGKG!vekqMMxPTIEX6d8ZsI<=*zg4WSpJPG9y`bwfFA9WV5N%<2z>amf zbW7(p2~xS2Um&_vJbp|9Si(oE&F!>}0vJKaOENKrh64qU%xtvH91H>0C`YS5Jjk&a zZou5!vfsNCPG$-tzi~LVkAXwOkeM8+srGyh>;S|FCLz!8pf>tvJTb{H7&vAF(NL2z z5-jXHfA{DN^gHCQ;C9_+45Ad9w#pm*3pyARvU=lCF!#J>Lr#u_Ez7wF!ZZ~iL^2vr zpvKOpTq!KaJekT2Ia&m3ey0Gx=DsTKmOgyQxu&;m5N(#Ps|pu2#J=NP9p`m`)AiuP z>>xQIU@=6}skY7bt24`dFMoOnsrT+3ip~a;v=EWG6-)+0ejQ(w&iPlWj=W=cKUUEH z#ok-T#kD2-;*A7?lLQFf5Zr@1jRXr2oZu1&8r&hIks!gH-~`to!6gvf-QC??`}{UJ zXJ*csckkSL-<$jS&3*6u!ESoXTD5D{T3xH^TU98{p_06cFdY1r6*!k`Wv;Xha1rz1 zYu`J-JOE06o&jN5354Gud$6@9H|@NkFW`(5Kiz}~7;T(9aWagSlxcEs=Ds5L7F;P- zKWf_Qqh6LGa^0Kug!lC)!xe1o%D$q)IcyXL7=QdR(g{}XZ+Fa|S_Du2JkpJfqJ|@# zJ(#&~avMX6cx6AyZ9V)uwBc$Hfrw1sQ}To9Kq%4rtUV3HT?Fw;>2|K23#3u1}I zqBIE;lOk7=J{AGLlnYdOt3~1#Xf_jU`R=R(r^z-5zm=gwHbFQOd`2;Gpo~U;ri7Kf zB>R{aneqnv6pn@rsCtaBX)lFf1+KvdJeFtqTn;q+ldQXh$&I|A(t{oa@}|b47nmM| zQT&N;NN#6o#MDxPe6g7nsE{vd$ZQf?p9g^e=3VVbTot2Z{t`&UaId(pyeMfZlTyh&})MS2#mN2Q;6uqNf9tyqO=WkAzwcX zLBFBFlZkbX_8{xS6jvT5SqbB;w~SGmI#Ye9vorj-Cq`Eq8ct7JD}@sSSYJP@})_qUHaw^f0b6~&&LF|DYRCyYxOiw^U%Qa%cf z8qi%SvW!+j!T79amOt-+3y{8P+J)cKi?d=M z5x5@Pd}hkT#1!Pus?|n>s~nsUvP~jQFAUCW`34dMt(<;Q*@&Q)AGxKK67NGj*{zMx zAc9w&=Go_kR2`Eilsp~nxVOH%`8H%EEGA0>pMaVo~b;fg-_HM=AUlS9u z_rU@}N&KAh=EJ%z~<#*oXiuJL^Z!1jas+HJxX^WoHb9E+-vL84%CgzF89bQ9B z%U#JyXgr?=hiQkVhSE)YY(=!%`Z>e4;pJBuMjbZgbhHlkT_5KKe5}#AcGz|16W`e^ z;hKEBk3xQ&UF9@g+|IXnbG~oE|MC;Z9E0NMs*bmI3u^4FsJHY6g218!ab5wJ6SpXs zTVc+`GB~;8G4~ME|L8VfO7eVdR*6wmka;qU4jEnoIT&j{Y~ykQk2;fN1+(rpbe4+# z6P?OdRqwYfO*9?mheqL_glD^P4*MeAucOqw+lycoWiB__MSQE^&l_V}_b42=h1~E9 ze41N};C+Szoh!r?I~)J7@u>G&W!y&45@^SC;qJSn0~*24C)dNcJ*01W&#VD!Fd17% z9lTf=BDyc}|gnYyIh8^UP0_e0?MEnVYt*x}ig z1rcx=2v&Rwl#r*nRDKn)YzU;UG6lR0&A>K|*$9v8+XS$cUEoOCxIBVw7TRWBes&lG zwtbCg04~7jG7;u|1YGt7)&bsdjYQ(8u|{$!G1A0Fat-j55H(;WsE1xGL7Ss)C|Vm& z@qk`fE){#ddnYGXqiSV8fR`j5cCcKjNuJApYTRT2-(3QQ>2GLS7f$hl?g;{JZSTh_ z_@JVHU9}3(dVl4fRG^W&sAcPGGyu==;mIxSx`^>R%Qx~g#b2_fB@vw00^4C-N8EQ0 z08wp30SJBT0uVX`T>un6fKK(9A0z{-W+K+IFx*dfam()wZ!{U96Ntb?NLf9At`IS8 zJZOgc3K`)Ur(~HrVleOb*o5t2*K3_`SgipuRD$Ls#HBndynE_;Qy=bMvRn){2h2!V z&k^MA!Sb)2)&TsdSqWREvj>P&SHn8j`veq>V|jXaDSwy+>;2uGSNC`R0^-R!XotT1 zL1-O_eB1V0BT(bZ41mSZMLy{LXmG!hSFk<9NyFxy1JoF`r{~sz&`s8-FoYa{A<4^O z*Jy2kV!s8$u_r5SNFx0ObTLNTFAoG@tAnRtboZm7cP|Dqcd5&%Kko&YM|VQ@jSu}g zMW~$E_5|Du^}V+w|912J(1n$_mPTYWDLN7NhRbpjF`)Z_K3A)Y-jGH_# zZv1VKQ~aNTbU(!NycGE0WX=E**3-^H$nF6SfYvpJ+#IF?=_sA=$^P}Jc+}qMSuDld zyi0s!{6d!9h5P&70QWU6N#7*`WTMmDT>(-N{~*4h4%{YXf4AuI4dDBCTHtk>p$jp< zs3~V(rk#yb0DNco`RbKunA|3?2hvfYS~NTA{<25B03;0%#I<`tWNE$n1r+}4w@_e& zH`N5gw)y~Ybu*vIr-9qHdzk@*I~5q&c1Xo<-vEBr3S9s;orq9=HT>aQS;#sQFp_$Q zX{vucZ~$aQePQYY&2JL{0`$+&It%1Um}Z7f?+^Y8?z0<*ZHdq z{f*q;Issl1crDH*8q1FuQ@K5FC(wX(+2TWMgXsQ;WP zWJC2*>>+B*fF~m(=TZrnj^=!!nICwvALmqe0>N0EiFcoX)ETINblyuGq~umS38>oL zmU_L|xFjEs%)k+#0BTy9_5l(&esD~_^9SV3#4Q5 z+wS|{(ifj|16eqj0KKphV28ih5drab>93;18*UdH2<$*ua>W3Zmkm00?J)wwmA^r5 zg`DC5Yf>>V(Y%(y*Qod019EHtOzEMdqku!=--9f@#MKBD{;_qOdYJFu0wWW2hk2I*3+ugf z10*e^XFOXLD$ zGD4LB3egj@K035LL&QoDcsHnww~ zTcRQ!DX;JPtt;7P87-QV{f_uE+tEOx2}#Ep7v|KNOJZdoo-}JHEQd}>9w_+DAR+ZMp){NZMz5KV`fI!9P{scN#XRBaX z1t4<|*Q=6(HsQ_#lY#$XbpyAu&n8hNG|2NL@FG!w&PHC62q$ zj$0B|SSFCK2=a9UV(l;VUE%&UpOH_oHNm@EftO^BoQP~w&x67a3xJF+J9Ska--!V! zAQwJ_)n*_l_`~i{c?a#v62+hEqzkrQ^8tg(t7Od6zVJrn7tqVH_kv%Ep*bQQcdR&I z%pH@WQ}D&AV!uyBbg!}%W#u3gSgldL_uH%nGrLJdt~6{4b4H16HECKjhkgOYO(GAI zOTA|;0$)M>4+9i?ePTX?^~d+{nLfe7`1x6Ykyd);Q>`#O~&M+fn0ltf^>hR;d z=PZCoUicz>*k1`*gR$IPNb+H-*_UoU(JqNns(Jbf^M%Mc`E{uDEztdh@OB-XVuy*g z;c)@bvSnhw6-bB0TX&}H~W8ECnZisYu2mk0t%tx{hX}P6K7p-^wa$og$a%|yJ{H)M$ z@9?zaItK85HPaPtz#z+8VP~SD4#dHpY$d!8Z6}hTFCU6T%9^uA$^hdu;9F6ahVhcK zspAodET42qTgZ{ ziEreLi2Wg2+}T>-3N(V0KzmVEJ-h2199^w}LxPbAnQa zJ*$jyI3NS1MF@u$yOc6QXI2w09<#_jpDG<~W^iw1_44-8}P&WNhlU~`dFVRl!h7{f?phP-6qt_M12VSWxFybf!X6%2Pt zlz3TLPIT)Yw~-&--K?iaHSQ3FIxTb%1 zh+OS+WDKLA=31KyvaN7G&*Kz?A9t5i|B*92tG)d)-DQ8SJ}=NSpNL?_lh5lwm;i?5 zo_laBo-?aArz>grzEt#rnV|Wzp&bgyB$l(Zc;MXf@j7%*{j`x0=|(%hFwdLMZ_#Ij znAC-AT+jQKlg0nt!S}(+qaIfWljk%1^|ly+USg2mS!QW6JGa-;l(yYy91xbErs|3C8NbNs*X4s|LaOyRgPbmlXIhgqaprHTBe_3u z?a`B{bDQq zqwDz5uUA~Nl2ZY)8L}WuPAR_2qb{>$`a>$E2?k%#^3!9quF z*l+2IVW50U1dNMJeFSfWxNJ6+Gb^Mj8q(&hO{lcyj zS90#5#wTHZ%QlepYpP{SryGfJONnG#lDpP!oJ}uwMjskBirj9;)yA$4RnDUNSiIrP-aA>_m7xS zY{?WpA03Z37Nk#xDrQFO8@-K_pFQ6X+*YrWc=fVG0u+4C0oUpx3OjzZl!zwdUCB0U z9?_f=1E$B25{Vs_{gDh3QKH0}^@jLthY$^64HU+Q zb4{HH35ajZG(&n}41+79%n3{7JAG;+du$-W7s1p7C7^yDO3X1`ChOM?9tIrl4Q~x< zhKxoF!3xJc>;)l3c=Mvqd0IejwmQ3{kB6APj4b>0=9WaPdDTzM5}ee3GhwNt;s2IU zV7bH(!TMAzAZQHys&^fe%k)eI(-G*u1UbLcW%t#cT=t|mjIH1fD6X)4#T#GVtRFZA z`3R=vFS(8f0qXo~W%ch*1}T8>+``k(-A^9JMnu>Y?#i$tj8Lx3;8qAX2hwK3iQ_2z z|MsU^LD2R+RUm$q4q@8`T%=KmcH@(0j$(oJym`urgrEU}Y6jORZlt~CY}J}I*Bo~K z*5J;(_#D^_06G?+~8ZtC}G4jiuq@4}$JfFKvpi@V15uwB4U0Bk$!00n9f22>Uw z9MZlx7yQFhkbBK(19kv7{;Mv5TJ&P#_6w81mh%Kia08_LoVhiHbutG$Fc_i9xp6UI%s^|rxi(!xC`hl7-|f?bc|V0-oDSW^7XTJ1(E}JPfme8Y z^Q-a=`)j~J0#xF?*z3Pk(7cHpS z>vfE1Fr2Cds7_>?cKW+_Y#<`_*eQ;so`{S%=+FOt<-xn3+<4yVpFgxlb0IDSRH2DZ zox^dJz8jKH_awMKN2&yMP~J>Kx<4m*fAN|YE(JKJ_&@N0fKdmWG`K;fq5rs;Iqn+x zalOHP;Z&#d1Yq3&DyND^#B~9cQ*D#Vq6Se{pi9P=Eii9DxnRQj1@uT5{9;ItAKKgp z6sCRvL}Y4$Vb8)YHNHOw7OX~?3}8`hRX`r%c-_Bn`0c#`u;M{)WBq>t1!TbRtbwY} zEWdyv0gKWR4&136?n%`x;{s5GTMx)&0hpSW0UM)lB2Y&g4ah=V4!IQvc{~xnuNsBM z-3~r|3TT6-&`ZFW^d~)k^5;+a`E!2#)7Kw{vP+8<4EI(cit6$)7T6HHCP(1+m(=)t z=xZvZ9|w^O{&&k9FEtWCSFOtdA3xv$9*TSoUaEWODF0|ueRluYIGSRQhv$02;3y6z zaU*|yD1S#lW%vD23XwJ5R+K!w_~Tb-0>QW{Zjo*ZO{oear#s1Tj+R0wmZ)=gky39H zdzE7t@wt%rh{Lj!>IYevgnGqhW+m;`X|t+6^F77yj+#8?yB_;e#8s3xsbyY_V=v1ksj`kS^X5>E7>A{-x|0T6r|+oPY61Z{Y1+^z?^x!#79OHzMu$ zNIFx9k9^vIR2?ZnwwZ-c^Vpd_eH346^sR`9YRsfZ8WmN`Q%f~RRIMd1Biju>B8T`O z1cZ}HRzEAHOZ%r*c^W%h`$(8wg%Q)f7n$j4$;0o>syB+-U2sjZIa0BM)@)NUOHp-` z77U9|L&Hex6ks7Or|xnOqv=HJ)Fu|PA1sR)sn8k~;7!Hec5=cZR*PlClm1GD`f143 zaC@rFT5EQTqIF@?(!+`)cW>pB6?Yh8trRsSX;S3QIVgz_{jvj2SJG2*=%?ZqDF8z=Y5DtiONSK*I8KS zRbvR>UR9PTu7wtDyNzv~QP-9q@$1Q%R@qb4(l;*_L_30MXm}6=jPqxI4%72ltpi|~ zh6K8Q8z$$iEm=&rK-%no*Z8CR>CgfuiPm_12)!d9ah-Fc`B8jD3~22;KY(4BkptYm z%73C>>AzLu)Wy18?~0fSvhxFSY812KcvgV}cPxkdmk&)nO_?=UX9e!0-crkOk~RBk zmaot4LqBtxVoQkhf!@c6d+1Rfc5o=v=a#*c3L)@h7Vc^~@amHn22&2{X|BQ}xt(UE zVMUr27v=u9edH8dajK08_36JG!+S)*+00HHOM!ssru6QJ<@RD2de94G^as6f6Zhc% z*4lWo060<`*`P-%|GJk|(Tj_lu=`vyBuJW>FIR~^AA)+0<+DKVhr~Tth-*)?MM(Ao z*SU`u-r129-Hn_ax)QsO&Irf=`7TaVZ%zO>1g8_KYL#E> zE7rh|RoesQ|K-)Wp0?)jq)M;AJ_By`Hswl}IGFnu57EWTNDKrD6S!k`w(ZRF?~-fbgE(cr)twrt7eVbT(J?NJ(HTpjd=A%zdYvcjO4|up!SWdC)7zqk@1A`wFTHvn z_S}Ie`Z4QpCCh1IP=mABcjc!s`qWPtp43!zlv}P$OyDLirDAGt+KF2*r)CS_Ew#Sh zWVLCE@|2jzL_yq7lc4c$TnB`wxJVL!ri|S&XuF(xkoJg=Sfiy+Y&8+I4(!H*U1ACFj9=4P{EyOKjyx7;*YI__ zR(SSWfS*cC5AFamnf{$fCgM|FDrv3e>GjM!kaY2jAOgzA0h{m}kkevDJmY)r-g#x79do`ux0&-;zq#Qm9l$E?QL`y5Q94w z<7XSnpmfmUR?$}(Ve7!LC;AIW?&O(6^+23Gkv_b%vj3IJDFtsDvX+I@_1M721EZ4Q zK8Fh;^%`nqsY$L`8#|RycNG|X_2_;*gt%%CCju|3E3VfhrqN~bptEBH@kk9)%53!g z@NT%p||yu59Y7DB763{9a#hsr)Pw3?~}Ui>;gC+m2rrgjfG z)?|#o_~HKxp9DRCWa2cQZKhrmsfC!Z+y*NFxQuk@rllswePQH3{JjPjnh$M#5GZqn z4G#(>lT9JYv-GVqV~!y&B3|^xQP%0AiB;I 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 i9?l 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

      *@w_-D;;zIH!=f97-ldm6!*$FI3d zp-6FvR7{wbXFae;G8n)a{zkOiqYwW4(W?FhQueI*@c+mW1JQsAHEA>NiV%L2HztgE zI&tsr;?vmwJo%r|`2Q^>JirHlxj6dL_aPep_#pH`0friZC;todQO)lk@z<_&|0ADu zidRTGq&OE9fanAa1b-Yap8r!K*V_+Y;kS<@#J_{j{u_Q{i~sM|jx*o>!!e4hr<9n5 zl!U<>0KelE(=o<>PHC%MD&xkA3NpW+hx~p8;eWFJ&oKSJfh3Tk{zJfS8g4u#qB+r1 zXjVoU#-AME3!W)dbJyCvx%|2^jJ^E;>k2Paq&V$bEDVNnp?h}#C})--4TSGg!tNfv zWA<+I^cYfh!h6-@AAde|A$NBTsAkYQ-hqF;6AqWnn@W&m1 zr-u-E$UN}kni+VN+!E4j09dEAe!b5GxaR^S!K`9(SL&Y6y&6IVc$Uuzr@%*Rkb4J( zK!Ruz@Cy&P#5>`vh}$9!gFcWa9+6*P2Hp(;&|&LWQy1@m!`0jSvLUOakXwx1w5$8Z z%@Xs1xnUR5zDGBSh(EcZR3Xc1K)Jg>xvj^c6mzu&VYjus=kJb;Y`Zb|nV zum{VOr^J6WowJ_XSr4rt3#|bkWe|KV26IeNg2MsyIi5I_3UWaNymbmW;jHJ~70GEQ z>V+#K_`oS8CaV*dvJ3fQQ&7PtbD5)N3R{CGoTo5rJV5(ZIXBZj~{` zbIc~UUQ0_uY+Fs=#BskT9G@bqjDR_tZ7fPeb?%dv6HZ2h9GoV#D3g2fL}&FEsO~fP zj#+paotgZqwm`@uQvqf^sEc`!xl{1Yvm)#yXYh;uo=Fbyvf#jtRJ8~Eqwd9k6hVr)V_={>zuK$r0|9Uens_(V3wGUute!UwXvu^eWT= zAR#2;($^E;xhbe>wQdeka;iH%(Qn2&y%`I8%Hp=3O3xMEH`qeC725P?WdrZxL*K%-|R%`$@tK)k+r$iN}p>K>)&oZ8U-rEP=Sw#7&))4^X z43US?0zFCo#6ehEQV6(&Jijk)(Kn?F?dpvQK}PZgIG*5bJmff}42Dtzw99G&Xj{6A znXFy0dD_(tFdqw4!FQgJlIOuMb-TS9`~|opA!~MpCh$gDfG|ale}aFq7J3M50OeX( z`X>9r=olVe9rdNN48FV;2W~K|9`b1-Y{2>nS%sxRl&5C)o`=C=>oV#CmxyV2up*K0 zu7vkAxa5~zyk+)h*feJ=gx)GJ97TxS4Gv->oDk z)R9Y&JmuvvFyq!>Kg*4~EAB7wIh^Bs(sn*2kF7?V;#QcscCQmF@yDFKHH-F(dSDnb z%{Tz9azgIW$$hFesf~onQOoxtdP1(F42N6Y7<@T7Ht5q$JNHrE^+aU`j{JM=%~dN+ zbg8`s_(eZJkX64x=*t}*2RY!&se+Ex9{(O`4e-&P0+5d`O7F$5Z zMb1(?4}5)K751ft;(hEmWO+i40%4Rer#kKG_`WuZ19mc(NPsHv?nfQ~fTX5AYX<-B znN1jysm1t1@X>1F)e>sCg%j6%L;L*xBCa>??m&fIbR64Ta*Fehokk?Pf`_lP5WHdm5c+iP2G0N;8Vrbz zzECiXo(!o4>?BZrBy*@SrX5%*!S8@3Byz+p`WBjh+1|U)kRGn*ER+;>Jzm`?_b~Nl zS=48L!0H7cN)FF0n4#Re??CP^kYO+1?zcF(n|oevUY%6=_MPjdJ)}F9;O^~r4!QVK zX=?;=d(%pcD(W4pd6g*~@|^drS3{zLaX%&#ICT{4CW(~*@+U9pqgAQ5z+#}}+raFj zB4a?BaB!%0Lx}X?pR`)duD>Ze%61l1eMBI>6$z1w9g}2FxKjyurmHjgxC*M6Pno)) z(p9bT_`RU6!bklWql5?G(77u2<148qu}6#AUC*{Pd~r4ygPTS#Mo`~BjFjV=3R}{S zwlO9TYkrt+mZDKFm~U-=k6&+O~pW=kvW_{l@7_=NLU|! z46jya>1WPs;hCzTv{|};MTX?lyfe9y0?4gD3y@}(U=4ZSRfOhYwyvvMF)eKfM15d1 z0<#<9_Kf1_x-ormGK82&*CQ3_p7KiptH~(esP0sjQnN+(Dn}s<>Qp;ff%s24!doTI0`&+vm%FF6{IW9VBvYbCR3*!7M8s zKAcut;Q`2Q(e66~9{~W!YONqLGCZR1aEyV&kXE5Fg(vuLLPqvbkgI&n> zrW%V}V)&qP>byC&gSPv3O2u{%1v1IQx~!5rwOJ$gVS!wPlM~swvjER!N96Rl}8Pt`i0Bo)=9>|I;b4g zi-P;Oh2;wTKC>lEe#Cint*Fn}nq-lxA!GQj(mi{T~ zi{$$Y^h`$>M+w+r*UWMsx`k-o5pP}j0`pmNKq~Pe8%KX+Pv)7cjMwct(#hTAzTaT~ z0P-LjROV$*!I>BuoL}~iv!xFiI0yktxENVynG4?oa>rn68kf>mJAKgaLDwq!I~jUPr!Eed>;kw97Mw% z*k7uhsdZ?6lXSM@OR~3P^lx8iiD~~w@UC<6j|Im+3%t^k>}5feoi$ra|8&8Xaj5Mm zK3d97_9m=x8P=KmICT9iPYOu#tOG1VDxh0(7-|5$9V7QXq*uK_4Jk$#o(nEO`U2iM z$&C>p?>Q@^4$q1hle@W{a7tw(JnOm0_0w~!^$1}Z$M+#Rnc)Bh7e5X*_q&8PrlHGO zrcQ+*$4ReRmOi5d4B?iN5B#X`;x7Scxltmg*~@Lb_wfYC+sMlxln4V=OK2zJ;2Ul|9?ifb>4xOR zcD(M|x=!LBKYYvj3+IKAxl{n}I25is5~#a~lNNFW=W%wTn_?AgavTbTOsn38&zxzjMp|)q8s14SU`8tcbc#`_-xdMEIX{dq zty-7bus~xH9p9d=MIS3WPUIV^4FpW)Vr<>*_7X+*dSDm7K+`!}$?KFy zN{>!LqgNJeR}d5qg#sZYik%;|;T(XkceIhT^t_eBjkNwulz^SEET9L3Cl2r_B;HnB zoFxf9Xxh3CO90n4pY3^VFl0TmA?=X^N3y}jMQN6l&NsoxTVY@ckrQBMp|1DbauDLa zsoZ@-8qE~YD2awftY;3sR{sWu9s}OzTJAYYDbUbEKNE`WA2^~5zD64vc-2Wu z>u9v$#uc{LwI?q!5?fBu9?r@ZYv5$HMaW}nJP7-BDXtOCwm^Ql2(1f4| zj+8bTYz@4kjF42gS?%!#ydVf(| z?d|WO#HGi-Xm%P9uHYuLx3{PI>Ukcrjdrok=v8qY=9btf<5qadM&|ke^#k!r0i0?t zwYfsWlfjhsgnXrmJE{*aTIn)IMTH!(w8Q%#vHP@o`R1w-fF;%dPSqU`^=&z(`1^FK zKOHi%CKZ`V^$9kn9vQh?}Ds1qx;kJ;h70&^jRzY z?kto(JH1B;I+^6Yk9;@bWWXcQck$ed7pAyn$^Iray;Nl0N17$8G90>{X|tLxs$XZzQfH|NwhrClHCg%@T03!+rWNB%deH?k z1NxJxhpuAvxAh=5e9Xc5kWTnpeS{IZr*2lrK_6^85m3h?D$Qi zVi%#OfG_& zX)5m!4gOl>g4G+gGYrmo6(&I%cKPL69>oCHki6Gr3wh#oHyaWr!VITrk<~Ad;w+#} zh4^tWdVlAhZ~<-~$f7CPdS&?Q9Z08XpC-Q7E_Oem1us*sN+=}A^>);E;2ftv2(q#U zk$*vhnsYBbM2HC3M`hwJ2MQNhaKHO~SVl5JLgmkJX0o^n+PHcZJ&`<~(cgX&9f zEof1@{%!BJWZOvjuDR>$eS_v}vXH5;RY||2faIvg{cWi`+y@1*UE&Ufp+p=qtdW9) zk2NKAud^+U;_uSnbyAyYYuIUN*O&ibUvcWR`-Hj|eE=K5d;juTmm3i#Gv7|bdBvu& z%Ur#ys8Vem|IxMjttN$48RY0QaHuFMtBsx48kg_&D>=+mL+=PDGBjCEJT|kdZ7%D0 z`wOIJ)_So=2=}2Id{w=jy*gRkNUZi~F6~XImf9%i59Y5lujb`=`cwVCIfk4*R zPe#B}BPYq`oB{FJnkdXiXOCeF7A{C{O9>_;et`tRcO)yJJ$cVp;>(a7-|wT+CoFVU zfOQ7C#F+b#q5TN7FcTmEu4ENTIbUeQ20Z3%SVV`VNIg5(;=K2K>IGlf<<#6P%jQJM zD91I=GHkNQX7cTfP6c1AzK@*sHQ&Iu%Z2?fB&H(R_ zaqUiotVK?P7XdlaYtA2^a~@7uOC9c=2tbX@z85Mu$#7p$jY1jA7A*Ka#SuOv;d>{K zJj_}nXYXNN7yR*ojg@QxB1(M_%ouG+S2w@-2!V^ktaT5difwwGZ|SMi>Payljd-sJ zM!tU5*XU;GW6wk5mHli)>onH3JtJ$Sf&J65ZFt zYSpYUD$+84^tHr9!$43%z;|0*-Xp|rNywTB2jKYoHNA7oBSt)_bH@G(P$@THhkd+n zF_{(DT}v*-GCnhUvIk(e*0ib1$ORP+8TtgQ@bk+^G1x^gNDP_Fp7(Ub%~hsMh%IZSejgKE_pO>E6{>giuoK;+T%r|E0zIaZ zo;j(5a~x%I$xjH1;a%9)8kL zKKbXWGDA(@Kpiv0*{2^c&iaS}nMEjlixT%BB_LrdUtX1YNVC{DQ|71-qeHB%A+uO* zR>@+3j0LQo+BH~s|3h-TZ1FS&4kw3)?|eS(du8?U0rO}@baQ5t zX^21=?I6)jqsCVQzd1CX#fUwH_caw${qF~y$=<)Sz@wfJC3Z5w#Gpc1{BGM*-vzR= zmg&@kD<8BOfX+)HI;s4+LZ)+92kr>o;X@l#6ogJf!t687=1T@Ovsl?k?dfRNHw}xD z4PV<>AS)bRWge|D^i;5@3w+RivVGoZ4z2IZX)ZnGqHce(R$hO@tvphX$Z4{ot=8fC zcv8K0NY-fvfD_w?}-b7NgrG8G%JlQsH@=@5t$MOKjeJ zzIMobV`0IS#UMwKPJWORDvJnGDJKN^h%Ggg76I;X!UcXGBx9@XLQ`(1)dF5foX3e- z3WNp(ErzZ@!fB85OH@_Nc?Sw|&{=b2UJIh%+79Ny+M#nn?I|ejdxIT8jCrY< z=9cx7FXh<h>s;NpL^rbr*3$Vczt%}y`2=UH;C^kXwQDu z%L@uClbiMuIMa!vV3VktcIna8soAw<0V3Mn6=t265uI>u%{Ez@IQDliSt~muq1~!g zX^mh_RjWN2XDXNSUU%H?cLN61f%1_J3zGmp+4R`}a+;|MGhU3Pl{FidtFKFtlBJ1C zizQj`LMz%#iF;>x7oTM!M+AFHafUyH#P^P?1OBO`^=KT3@$0l&5xw0JtI+Ust(?6~ zDUrP{VuONW=7KTou~~Uv!4jX~cSc5Sc1Em@r#`NwX=`G6u6c`Q-{(%(7InzV16ALx zlxaUsJdFK5M6SX7R81*-fW!x9Q!a6C$sTi5oc?{%C>NOTMR4wJVe&T?Z%oW}k%_IT z<~s`9PvQkfn2yp1ZI4I~UWVf+%*=YKOnm}R+mu12^y`7Bf2>HgKTM3ZH(lE~w*h(7 zH09YQa9HzdlKYmd(gLcy`Evuh#gK5D+{<_tq)PXe!}~KMK>zg@N65!Jvmmjir1An!`Zrc z%tvlL(B{(d3-m?{vYZ1P2Mb+p6?}sH_9JOZH547}RY)3b3i>|rOtLs)kp67=mb#K% zh(AQd`kvn~@nDxn&mZMEkwE}!-ve)l8>N>opH|el9vUi#h&%KN`A*KHz0WLA=x3PO zc5`u)1>pHd)_Ls6?xmbazd&-pC3joJ`bDQg#e7Qh4o5z<1-&(mVi_RUV z8NkGwcNAb}49BCY8)SGT&1gv3=_`!G(212JDJViqG1;xbK7det)}Hr-Vb^IZHNzp$ z%+jX=@?LhL3-lE0M*z}A4*I4D8#j31G`BkaT$K#lb#F)3DhD5T0nu&<^i-AFn+k76 z0OH5pPsJP4V+q)}2t^l)O>}^GhQYU!*>8WKQ1c3Xfzo?pmJfa~!WJh#cF+#f-U6U7 zou`4kai3&MTM8YtRx9i~awBE8SY9GwD#^+eISEL~VeY*X(qVG|Y~sq^AH#~nx4(T- z%+SDH;&2pH_5%erKYwFI9P3II$ay!oPawW#kv!ETM^@fk8m|%KKU3e0Du~x`3)k4i zlx0)@oJAe;#jpJh_I!{vY_QpL#}Ug~Ech^l6_--m5$2%Q)LfAnBQg=v5jZ%ZCrP7b zG8Z(F)?{Jie^6iFx7a(RPhj}5Z^5sr1_{C0A)?7as)R`2%a<%HnIxVq80po9b6fV= zBNpVMYP(e4!p9@m#q?u3YqL^Zhm^GBSRYdnTV%xBr&qWP>x{qlWS~(2LJ+EpLg$DM zftNT5q>PB!WcG~l$FOra&diHo|JZ(;SW&cmG=ItiYzVsowX*J;rWqcu(q*Zzze#P%<5G-kFJXOFN}4*nhCCDpHVQHch-6c4)(B6pjA{nrH`3*NTm#ebXIM_4Nim`LFLP zR&a*XYbz!Mz=qeS2h0OUR>QVhAZI~aG=f2k#O2GZLNOA4o=|yil##1|gMDysf76s^ zskE_;f9{T=ynD9%M6^dy_=7pgA&Z~SZ6A>x^9sr+R=>dqge^|eccCa6*vq`@6v>Lx zB6Utwa=7)>WZuJUri70xf3mGArwVf%zkz_P+BU*@Vf1;fq*63!JXTFgNRiExgwiJ- zF%zt(s>&wTo`<%}Ic~82L!Gvb$Km2`XE={`=$%b|f-;pYeZ#@%i^n#B^0PfT<~EfQ zUJ^#u!C9GUulaBkj%IkDubs1bQXziLTd~(^LxLk|xV`kXsllq!wXUfX@T1z&KZjHH zoR+C3$<;Q*GWwE8ofvj+Ak_&KYU|}BYN`mVHRo%(@f`|>2!>~_4FZ9Ce7Aei8nym zwK)gR-Y+&q3GL+Y$A_&_EVbD(hMp!jl!hV5tFi=M`*}s>vo?bvjIVBlH-X-5+FZ-FkA+Jz=h5eaZfNb=U9x=ruxAm~& ze0AJBB(xuZqCkZ?Tw<{?T`5x^=$}M@*5FYkvtU3Z-bx}-tEd%9GyFu>=g;E}8 z1E#Xe9UZwvPuP#(1Zo5cO=@F+yd?>+b*%ex7FBfb zEzFM)gZTuW-e&}_ zavopuPCbP_yf1|yVH7loBLFjVy=c3g0RuhH`vP#%XA%(IV_^6EJm1lJj_(Vci_o1# zjBU2aiO%3t#Cq(_0lz?Q<#HiSJR*ReCYv%M3yufDzUK@$(?Na-tqop3-vBWj6}BFE z-jTUaqXEM~Cg{im);$JZl*2MektKuSTq}HhV*Cq~Y%64Z`7`CGkju-9A)xN#Bo`aF zk1f1)RUAqKCj&+?TQ>n{fSQOgSldU#CS{fgj3cV^0Fa{kjggh*m#ilV%%oq#p0hLLaZN zY84svBya}$gX!E_2jq+cexd_HJ}9}v=vcbB`HuP4$Ion~AbD|Jw{cbKb()6OYuQhn z6L+#qZVu8woiqNe+w_!svfG?|GCj_kGCh>;=cP7qyfiGxs46R9Ik=vNbvb1K9U>%1 z7=N-}Mk&RN}~PX;GplD+>Zp=wV2m+F}Zcb5cxMqg0DNiXWKz+l5Z)GbJ8z(W@bKFpL*=& z=w2!jaA<}FktVPl&78wyrXk<;SFIf&HX{|l)KOwww$}FC_wK{|vPF|?+*Q`@GR(Xg ziGPr$A=b2r+7@;==P+j)*PwMR5g+7hA?=M^14C&) zHaoId+DfboHQ#r#=4fxdg83I!>Ky2w`#vNM$a)v_s9O!f)@t3&6BZ1bGOfBq0;sW`bNXOC5OuacjfK%h#keJ^&mrFiJCel3-@ zd}t+A!Pisv{c8BIUtkp0f#NWE22+Lr@X*V5U9#yPt@I0l+u!+3-@ioD;RV2NuD=?Y zNAWfEP&}SaGMm50Dv4Y_=2Nj}06^PJ+Q7*bjU?hKU9{r^k&h_ zQFEJzaYM`5n6A5+7DPa~C~Oa2vAl_H9n}mdH=(U%bKsjjq1{T%j-c?GeuY=hD<-0naBE zV4QaoUdueW2Kg1O;r_-ndLpijIwrx`6_=C=Ak)D?0@O|w>qhx+8wqcUY~jqTHiIfn z5ML(%u%Zo0$xNg)OG(2xpi;JDKD7gaz3PH5_IrPVczzB7us1Dfmyb!0&vMz`zcxUY zsp@z)fKvpVg3#p(D?BEd%h+B@ouxt5xiQN3e5X9;-n1WYGs6lq>qW)dt*`@S<}Ib^zDS%<(@uLA+x5BYv7Q-m1uDj}vIQ?+MZHw8@EIh_l&d39Z#U z*|gA|c!GVurz_#igz+A*nnz0(E*^_*oJ6q2sx*yq0iw&k#RLA4aSR~EKMeNauCXH2 zbHaU`Qt-w50(^H77{;>oi|6Mcz=?|aqC>$5-~&;~)2sR){5}>KpWxM}1r%&tHTKhF zGsq(1z8gDusuYU<@X)f%J;H_ zA`krkeGcFn$pX;gpf>?bKv{tw;*%uv2j~mT*6*eQK-g9QI7J2EfIfiGM!efpD}e0? z6|i4DWdJN{1jsY_)iYmDfY7S{dDZ`H;QxTd|KQdCKdD8dEiGwBo5x8)QL0d?>A4Jw zJjBl$9JGn8v6Hi-iGj_3HSG*7;h-7VSn=uc|EtN(O($w$?QG&mCu(irY$9x8WM^zb zCv9SD=4_77%1Teq%L@nn|Ezby4*q??IaN`j*j)iu%QgWAb&_O)%`FU;M_96cJqq4J8=*_@MwbgajwaPVoDa3%rM6cWDew|4`-zmR8-4z3TR$9LI0Ti^D3q=j1o&aR7*BXd zE?0^^ItoJ^jpxUX!Ng=9y?=avfEsUrdte)BuX=qWToHd9%ATH}AsBmAA7Te%C)?#K zG+C6v2}vxYizx6I(TvM7UrvSRvLvLZ-4pH#|27;Z`ocC8roJyw9kBGgncDIoM=eIM z!?X5PYaX!k@j=-N_MPN{Ta9dmI+xXwNOMlfF$}m%Q8{Z`1>bVyHH#6MK$7sF{SuQg zrYiWF`oI&~_sMn2)y-F%bis^#WT|;@N@5n6wYcfno@7dXh@ZazxJg}K1i|VsgUtu-=lZydE&ahUcz*gJu&^Aql8mX7mQ?%ADRc03ls2q;eGK**`T}PR-fPwHnJRLS3J=ZX=ou0_lBV zT#?kxom)H}AzNJ+n!QfkOB(jL1-raxH1N>ewQJMQzi5?b6Z^P}G>shPA@lN5x~)wV z(O1?=dUNm_dqz(>XJfFYyV}@ia_81U&+3e~MQ`AwP0S^)ljl5q_Yu2q%prI=K}@g` zo|QlDoEZ)a89Xu{DLy)Qe|kb;cbcjurBr$J%0`-MyT0QrPP4q{W;8fpz{*5IRPd{3 zAYr$MutpVMWt2xtn$CQZJY}9re%A9XaV=prk)uWhU)fg(X+a{>quGoi2L!A-N$*90 zto3@d8M^3P-Ae4~JeZ~w$4UDLIu0lM`lZHH%w+#QeQxL`;eN?q+SD3s zQ$AyG^hnP?CSgfK2{@C846*U8Ha8sOXoF_sh{)XbO}^m{!PE?$;)i7_H0$I-lan5y z2)l%3s~JxP5tZQ{DgB7C5K)BTURR0YdgB1SDjaf(JWID+R=Bv+E{oaUTA}>bDGzFxn<>D z=Ja4S=56ZPJsmS$hQj~0@4Y#HIE3}f(Ulh0N*I31Y@r!f|7+9VzF-wx_tMKaxVe*V z;Mb&bz2)`rAarLi$O5K_SilMm(M*m~>F>;LL73gZKKI^ewB#m=KiQ6jOKNL$w%AhTz!uNUs{OB+$$NKw&Q~>;&-=!2E&9}hTd#==hfsX|h8UOH zY+Sr5kObBP$+MCH7OlOu$5Bj5ZLbW-1G4RR2fM)sUq36q&n0hr_oiP~mxw#}DTRRx zENrE!wLNQ*Q+_G3R7)$;@{zJ>iG-#K-Q7(*90Y4w!0U4xba}YDzMpceVerLaa38(` z6oPalZ4N^9ZBA0PBsle{hxG+wyX%HShKw;MOZ%J~CecwrXG1igwl!3ATX3wrZ$f-&n@7>$lEWh2#kgnjJqmX3qweLU($|a0cT48oJ2c2(D9+@`y^67l5ZnT%97E2H&Z6PvCx@`43 z6EaaIII+*2ch;EsmQ*Dzv$d$;C7EIkN_Y0yE3GJ%?Q*WI0r9Y#P zaie*|Auf%ey0aV<)u#K@30>tbs(Um*~82^LT&XE#Lc?p zy9Zy`$Bx!#vF-17!V#nUL5(^>b+-bh^Z`?y(9@)U)mRPpI}yZgZq=2vU0S}3iGb*F zt8x^vwPtj)oWyULHxq*8G3WHj;hY2hW|tv{iv}>8n8-R+=u@H<)EQKASr$$!7C1l$3t$9&r3Lon7_B* zb5!Q#5G78>wy*#^J|#DN%9ST-gqbE<`0o%IkRb{o15lr+D06x>NQ#Y0fPq)5IWX2u z;~xfGq#{jFU#>nfAOvA&Q1-;s4-Nw27pCPF6HUP_vAaLSUu6&aWQPuG3I`(knAS;VXYM#9mOX(6zvdc2@ zg;xeX5a<=W;TK9)>!5N7*np!P0TO{`WTc{Zg6G_bv>ugWFRUD;-iXlG+|zba$v1)y zGzM6atO>D*=aImvo_|j0&9-q*Ck* z_^qu^*kA{Ao)caXwYR#gAhjHK*1+0Khf9hfXjQa>j@&_DFA$>;DtQoNk}3;qE+7pH z5F-<_)V`Qt2mxNn<3H2-Rh|ihNb^YRRI$aXD8XZ;H{4>7-rP#^Xkz4A&?ZL>*XF~> z$@5T?&>YhPRgBKU*(q#?*wc~6r=Zc;gJTR$r<(TBI-wX4rE7`D;$iZ^ihgINBC z`34q7|QW>MNT=%m2GXQ%a9Y92`%pcK3`)0^~ftBKXa;O0JhFEAPw z!F#pgAc$PA0&<5=w^d!^spFbgc@8$#<>X8B;V??|DRBq4mk&4k9o!lN)9$Q&N>#bc z5>|ucN0+sNf7StfS>hiB7RDc!f*F3OY(H5yA#Xh%wm&9<={I`Zo#uOP$6ge93{o51 zOd_z~Nan9mX18vEd{oyIP+G}t&kE^A5r3w5Rt-od9k$vs8kjt^lf*K|LMTEq%b6WO zhQ90`7Pz#W)w{N3-Xg>Y!Gr~~m`55fy4AULCDl?Fhu^tXp`>$dZjp;kutC}+wITdu z!zTvZ(J-vLz_}p~+6AHb30pE131jcHNo4yQjT zRDq6>Bqa>U9@0zZe_eLN5wh)*&y0x@KtE9DD|35Khk4W}h`dCI$M$o>M04Rv=DGTo zG+<1c!UwerBCat<8Dh%qb<4X!=fzqI1kyXHlQ@Lov=1c%8Pq7ve1;Iu>=KyOGgCT5xO&*sie0nANxH|`mmXs$k=POZ;hQ=I z6zyS*)DcgdWKS}_X5v4BZGTrS=_rf=F>t!M+bHzcqM8r|yM^uBc3NB-KElpOBT<+i zhs6Q1vz{?`1P1!IGY->0A)HhSd{(f_Iqygi41wTI{1>Yv{kyPlqvt4UD8aBPP>&;OJXr0ki=w&vE;Nspnr_} zGhAJ0n&RpBm9S$*QzQq94GhEQ!rKzrS;_ajnOpjeu=RR>n$Ka@wFleMYNwDPDqX}3 z>?(2yHV&op;eugBtWn_qL;#}Oq1A7D{re7e|LUk-BVhKNuy z^13l}*p;A5DmtFjMG7{}0%|s@T&^KqiPsVS)fNp|{HR=YPlCz$2gFHspbMLSOWYQht;gt}Y@iF}Sz3ZxGG2irl?01z@-IW$sMVx7R?LJnK9QkY7;9f% zcS1#CpG@CxKcKlTOi?z87@-4tmIxAAVjcqV84|aVn4cmk7OO{(MeH6sJyAR<&50JP zhr}fZcN6Dn=xNn&b!}>ix+Dp1CnB>J0q$H|VLGHWHDOsGcg}C;L>?RO)O+%5R|oNN6PMuN>^MSr+7| zQi&Pt#kNO>car(&){Oy>(GNQ_YWyi}H^)vTO}zej^%Jh9)To%g-09$uQ?*-I&mf{t z&y8QhbXv;<`7Ups2ux~*-Ul-T891Jfk+0%n%dE$F0zao#h1yNFIYb7ngonS>o1pn#DJS9QId?T5{qq=Y~mZ6rHYl*3Msa zM6Mgkwa9@w^<}wKSZ&Jus((GjmXAbeg(Pntnax(JDDqcq=?*vCLcEn`REoozFia7a zJd!=Q2zja_MVwfIl9xnDjp12qJkjBXf4L|M0wUodDGReQsm~OWH0iXgW{yfOfcKY_ zauP3p$Yx^gu={1?26Uc8yL{wK=GAqxmpV`v!r>dHJ^?{Zs86BgL71jc>F{bxzX6V6 z?zoQMj|saL%^4V^=G#8_6U?d}kDq05VEal*=e3|0YZ$5kZNJoD54z zOa~j%v`QBLz5%i?dE=SA!ss?9Kim2iZp2oB-Uy%=M$?4a-Eo15ksQPmM$bRKf+#q8 z_w=|b6J#5Omp|SDy6!z7_R6DedH5yAq9+!KL4%+C74diseaf1e_>z$i3yklyVCj+@ zj0hw)8Dgjz-4Ly&$>?KHmH7C@3s!@cHQCn9<{I_YH6{jLZFV=JT+7_I&Qy%A>t=iOb#D$=+An zW80E8^?gb0;rz}1cK6Mb%J^DaA(>l8T>GFLSu`#@-eA15+57T!leqQe6_>ly`?4GH z4&?jwx%A})G>Md(OkLebU5+8wE}q+~r0?ghN~+ch?c^BpQ!&~5ZU3_!rPAQ z?3o$&a@SKH`D#*#zi>phGb^`+YTunEMHI*QyFQx`sd)r#eSog zYMGQ1FK->GXbJ7@&PEgYU9dCZv#&T z-2ow%7Kwl4qyi7`J*Sd;-(Q*wx4iC9NM=GRvQks#RYS*uO68G#A70~5pt4j??}}tE z2GmYdL=qx_C;T+*8kUAViBzY2b82n%D#E?sem?Wh3k+SlI|JRjf_5%<KzjxItU_{K{;~M!%rq_X+bXD8 zq#!%KNVCZEv7JL~Ik?M`*fbYtRa}Xmr56{AJ09I+m>wfYYqE7lw8pQcrM#x>!vA zGoh;FkSxK)dC#lEV@aFE6)p=qXR90rry*lBgPwd2oYExAYGT8VNXe~kBb}jAp-m!l z#-CsWip5M~78^M}Qq*ihN-sQOJ?2qa&Awj5fa8MhEP^=!oQZQ zTlUS9T%8|%&OJ+7h93^)v?fiSts1LXd1y3I5{os|g8hL4X=wdXEI1H=5}7RAUc8$_ zWN_GCVdn*!w_4veXL30=_K(4soA!whqNGYBUCt_j+bBiz!C%Grnz0#4N*IoyYNdJ9 zmUT-C2BcO=7%Pn}3#CvjG~)YBfLtDM2nN?okI7Nw$I@q!s8N^9jU%Q({s^VB=8{}T zQLV1FQ6jc2o=NOnO*V1@iU$z1M1`z93nRa0Q>r#C6jSs!#io##OoU`SzZWe(J>wY> zD9RX&AmejTou?-#c-{)15_45; zBOfo?!gkS%&StB{XKrz``%P4mWQZihyJ0ZG&f^w8ud;-?yja4Nup)oXh+q2ZSm6=_ z1Dr?y685pVnEdXfql60#8|fw^E>ysvC2kBk9n8-^DzCfp#83q0AWiTOQA3N+0zrxJ z?N4KVW(=pz z%VZ0W{l*=IE>(f2NdH~#@_Q<0%S}f>Msy!{+3#oVrZ!fwX7l~9 z<~b_@XGGX)x3EuhPJM*xfCMzU;#Kxy`*+(5%CGC&zMEFn9znk5dN*-#=_+4^FODJi zL?0utelI87WKn)OUI*^RPyouWc*uIYMyd_BWd0ya>glF)csR6CH!)$)V4l$syXq^j@>O>_tv+1WslD#wbFJH^xxtOx>mtVB&2SU{v`X|cw$BP@ zT8s^qoPP2J+S}?1#tUOhKCzS#`AtXBBX=w!$p26!C+oarZZU32lag5QiFL2W7ewZy z4z6)v2>&7dm{d=t8+%5j}H4Bm&9XPq9V=xFHo{1 z^y@n@x3!HA;Ls|I_mGF1z<<35@^jD&Y8%`XQ3V#G7cBFfp|f_YwriN4~9 zZ%u3a)5Wod+r~5kadLnb#LIn#?|>eTC~@N46*Zh|#lib-=6g*_Wq6it>{h=TM4gE4 zmV#8@R64Cg{Ja?{yl)##kT{Kahlu7RF9K~$w}hYg%-$L`m@Ac#-L`?FNpXGq1R256 zM)-$;7Km;&x&0Yf7k?W#IJnaGS{EGu9RtCu&mUjM49UmL(nBD@>yjN`Y9dDxuaFTH zRS>5==d@Et%=NWNYzCNP?b6|afl>(#e=#8_vL`6?$cbOzP1`q0UPlehM-4s+&~>yO z6e}YtMfWNFUAX`Zwq)@_`|CV3>@-YFof85jd75T)-93jN>5Cs4=EOg6U|0Z7?P_|s zCgVnO%{}Gy`E0a@I%Uiv+L)QB>y|;W=vK7s-AJi=-lO)}!`!K)`nr_o233@&?pw+lQ4G(??#|Fo%+csfsYA;VInOzU`Q@AafP0yjbsb zl2qCFZAjB$`8$+X_p_DK~3&4q_W|FJX62obi~SI5Z{HSO#_IIHNA7W zy%!4*5MC#h&*C5zm7aTwvMbC>U)vr1J3s#*BjN&3(`He9mF)$}m95$CsA*9Zi!}8zehTGx<9gltyS6j1g9-n! z3*-iRYPD8A2W1V4>kcd-4sW+}%@ydBJYaUqqERHpCLEr}@#Xxp=$Tk&zp4B-bG zST`uj!s*i`hx8=8)MVFU1=#KxgYNcVFE6Yx={L>T{QIwkQ17ay61C|h)L$O5Verb{TOr9e%v08C0Kq4>sXD^o!5tKj)&@ z=gtGq0lGzi3p?=k;{kf@(u|(|s@~`AE4UpE_Ac^c6;}Ssqr1WnkMJl=?m%kHj0qog zHJJvA1t|qj45{nee1r}ulimQ+xOlyDcY?#2(P7y(2CH&fIUD3USp^%UbDGKVL&*? zlAV>qX{DHY^7zclo0(&%mKN69M~;2x$3j77DrMz4vaK_%H~wwPi0>m{%O4;#m?G z@9=aT`Q0y5H8e1Onh)coC1pCZ*i5>hy2dpZpXjEu=x!Ck$_CpiH-M;a_u0J1tixxP z?Roo>Q>xPW!0k)A<|*pV)2>oRNrnDh==bTp+MErs63-^mz6&We&V=H~i`q>Zh-9L- z{2*~Er{4mFxgX=l(7Jrf$B~3%UW`2 zLB8jxF5s^CZiUcads1?Zb5@6P^Es=5s+bFm_?WO|z-;xMW>$9#WH5iIVYsDp8G+Xt zk<0W9kf03EX*g+9G5r&PAKUqhHmY(th^Shv=2~7i zINh|}9E(neVxlwnDIpkCC?S2c-N@?;tf?$Q>6ikA_S(TM^{{<65Qj61`OE;CIhL%l z7|`uQwA1wn+Q<~et$>tlXgnk^4Sv%SauypymlW9FG#hf9cI1uZbqK^1*qIJx`dk(^ zxB;SK^$+R$h^+{e1)IqHUwk{y$R6spKU?Twbn#I-0T<5?dB@`?qtHfeMLFo?y*H9y zk7_riMv9_o`aD|g@o_1G32B|tK3g%UNGhE9Y;sF9B1@1Pz@%VeK$ae2t>I#KCyG!q zn)YYkS4U);ZsJ1X(tR{drEk=E0oAoVG4Y^D+o%I+^ue9x1fOLT@(-hSKTZVfxVjPh zSA*lKZOG~N84ej%x=xA2$J688-~=>B2*b@KV?gJ=Gib-2y(L`Pxa%L2TR4zlFq$$A zS_Ecu!OmszHu8ZjU-AV{XKvNGoCh?3_EA7^y`r*t$QT8RDP|%DqyR=to|ejQ(>z?4 z@Gw_6F*53px)-V8kw96gxa`a z8X7~$)%qJ95&sUfZ`=}E=<&1m?88o@bD)XK1j3emx#wf#*$A6S-!5T4rhA)45!7(J zfmgm4mh};~$qhkWqdz(w-pD@e*&QJr%wZB(JgAG@?z;IC zE{uf(VIr^l%w2fhcoBTuc#+r-9&-%S{70VtRWaV^E8<(89&~K03iM3KTD_XRz+!mOy!2KE{mA|_|t>it%bfi;R}2}659AL64HQ- zH`a+O4T6sZhqwcVwHm-!q*0)*Fll2RwaG{-Ck$yKbR^9*1P;2Zj@eimufz zENCU@jzg!@9z!|0uZd^I11oR|Nr*H_AP2} z-%qARdDog}7LI;(FkbG8ELnNYozOE*SW_Blo2DDQ{UHj=m|6FSIbdR_)&> ztQ1BK#r*JqjQ(KEQI|qn$f+xJvfNZdp`;Ozb3t7vjK{DHy>O}69;Cn z|J>4N9bzo-{6ZF{i5Eyl84{AEBohmDG*5V4D^c}xIz%>B+0m^hE2#6I)mG< zq$&M86dogoteHX5O@|%xSa7?vg59GYL-JEH!=HC%=UB0EQTv>~$&_sTr)9C_{Ezd} zWxdr(JBuGiZpHK=e_!i+3JS#Edh+*Gfg~0aIrki-L-k|~<$yh6_kw+$Qqj?Z$s%oo z?b8`BK_^M)!JYWwP(O8-#B3#`01Enk(BCYO--Aw)rgKv!l!w2%Gr*f%T&U3oBMVDL zM*bF%%=)+s2EHW;nKq;y-I|(b`=%*{@^xmha~Riv+vD=}&yO+h$~|v;iG`IZ3K;h& z0@JqBT>obAr5he4EiCz4U49`xoOg=|!3Sy(&-xyq z!okT_&t#8Gw;tFr&5jTtsTcn$92|s(4bTSFb3-Ihe4}7|(#n1OcohSTf9B->lxm|U zQpOfBmo3Us7YT*ozM}@1m+^uV;1!&_(*CNN+RJ-q#@rZ6aQ(T%}S%hE>4YDpFsU91p`DvnE?l>N-XBq$?0cG^*lXMpm$qCxT` zn)5x3k9h%$yeZ}!N|v}3vlpk9Swoc_*ZGW5&T>vo2)&?=7r*OQ-*PK_?X1Smd7&eU z`d#IwtK?qsxr$86&YAN0{psRi$^Mp;|9oJ?bKmEj-+xu&oL5@WjUX>JVqrMz%__XX z`{&R6;vbD)x%IXbh)hJ)ClF1Y}yX~gLy_8HL) zOLoeXhbUXN3jNBG`e6I8082JarvBjCUjnRY%qj7~_KBF@J?q(DSkuf**PDy~P^{S( z%r6t*458SvEr_ol1*QHo;>pm{CjviFZo_V-vNMYVv|u+~(Sxdmv9Uf?(GwAS8_pZe z%8w8?XNxdGP6u14f_zxIVoocy6_1s-BCk}cqmVAT5m|NbL$JnJz2i~U|MJ^ZXgRm} z1(jK;_1}z~)fm28t5bC5;I}8u(`81;+d+tDtf5^K)_Hg=yn9)Bt$*YI^Sac7<~Q3S zTn<_84tH<8?I}0n6vmHVwe4vgqFFKm0|05KHw)-vSoghw5m&;qq}v+kP-Fb8jser< zv9jf5SVTrZY9X* z#aqS70@lS3oDNDyqq5qY$34lP-yz;E^{YpdV?F+EOi<4w>qeocul6w0WkG?E!i73G zy<~BZqa_JVUkrQ_6@08IXwRdD2hPAUo<@WbD%kBcR0kVTV#=n(x9a+bJs9W!ffx}4O&#P~0UhBdYnb<}R< z*G!-6u>)H?wag0Wh7E`X6s!d=P%<7~5?G=UOHWzHV3K2?5NHD06SV!JF@JZV)+Pgk zZO|Y>sGfd6Pa88u{|~k|_WwKE8v`5Lf49AL>uA|wkJkI5=l{^t0lR|Qv-@Oh1Q_%s zUJ6H~3<@)T=3_ueIfyVchthfYwbLk+PZqX2%8}KJdgX> zTKc|yT3KsEpJ~*~<)yd>`L@c;G!ap4F`;!|7SBazp8T_ie{?%?;|wC8nR{q@17o`{5Po#&>e}+rk3b z4rQpH&pSYg5y|rTIQMXsjec9(x^sVtzgm?(*vN zaA0$4E7}!ZTcdluIzBib7|(VRTpdhp&XU_;Qnh>5YHwH38?~wY^is9`ZfGHlPHC_D zjKp3>Up}0qqY9h*`VH@7^H=*A?gcz~pV~6u&iQU-=_oR?>2mFTK(p7xVLm+Y03W8M zLtEp-=Ajr|1I^>;#n>-7x|XhOYJ!gCUu2~VIj1`!c0nz*sqIK-?qOkShG`Nq@IgP19vvB;=5+tj1o^o-+W$? zC!CNL#P@HSF5lhz>GLS6iv7pe%`3;|xz&uXYuok60F#Vsn$@myE_d8%tg*w8!>;55 zW^$VFBS+Imqu!(1w{0W0IV-QV_+7F8srJjjYlLmITtrn-N;MunZfPA49%G%&64Vz0 zW-QF8rv)6lB{XwhpIQH6t!FU(P9cHqHmn4`R;7S+=_Z+3Mf5M>jo;2k({%eA#*af@ zpn`G|r# zgE*sMfh(VZ#3FNfF}5Nk@Y;wzvo~PoQFL%r8pGOERXT^QupiPSAvFa2fczBDYAm_7 zR^?CO%#W7=mT=^cF3cbP7kXq%-4(LN`PyYn*_0KJASM7qp@OE$$y0 zYyP*f7=P#RNQb$Ob9vRT-7JS9R}_p%Awn#(Sn)V_apS_GnFzV?=%k?Rs;EHWBR8z%uYvjd zFFsOGjZC1%VE(S6fT~kg_tPxUT_r^8HiLlpQeVx)Q+O+u3)H_wr(f`_`nq+kv2q5r z>3H3SuOO}?WVxgfvHxw`2{BEBG&3*|)%-}DcJ*$AdC+dg7tH-g(F8Ak-v>kfv?AP- znCmy|S3OpdnzCo?&!U=&W@k}PlcZv(zLVO_7+feJj=W2#vOvYdvJFN?(Q1g-QC?iIE3Kt?he7- z-6as*?@oT_oO}Lvy|>nVZ?k6YX{L8oeO1*xJ<~J&$?MI#Ojrb$Wh8|ZYs$*hgR?iB z#smjdnp-v)DCg2Au93Wp|ID?x?2=JSDW(siNuT4O3q7QbJlW|-87&+;#;wEpZZs{3 z;u=P6cxNXJZU9TDXhH;!sxY#s(Gx(AG6`4oSkQ|pI#=G+@n|>< zU`*#nf+Nr(V0AxsC*qwwGD!F`K^hEye}^TcfN{^lYrY(()^F(PO2t|ve#7XWZHf#y zH%G*XVFAmZ;atTSxa<`8K}t$MbWlj}DcaPN++$OjoLmn;Dq>+J4B}D`@Ss+ zlO0+VBS*0ARhhzmd~W}g@Quq?gbX@{!0J^J?#ObMlT6phAQ$9aVE01dT0G))0VS>&_!{cjS zmWwZv$IxE*-4qhaRyuWg0LG8~))oo1a%K123S^~gPRP69cfre}up5iS77=?*X!ppS zc`h>p>?A6*nbkOM5eWk{uv8_}>?Qm0VBsJVP5Q!ymIYzwQYG68N&8Yusp&?rv>MM` zBIHyE5C$%K3_Toshp!DEu6dsbAxb9n)DckILx)-P=%2j7U%x7BdpuI zg2<6k>D(C+LFtgZc$PxfHHyZeMgc{{s8Qt#?6pii*ZCyyfl`_lk!&vD+q=Xucew>$ z@IzS_d3^Z2WsIT;ca3CmztuQ-(r7}BfmWj=jWeO@ac{QZJ5&#{ZicLMIjO( z=g8tyWtUGP!_0|AgccDfCszT6VXoX{Fi+k0IkMtWyoUX}L1DbkV!@LM%vI}ib85}% zlNJ>6m%g?$Sopw_qzeM)5mXIJ0N+AChBJysMmdK%TZ~pNbZ5bI67pKV%}C2WT1D2- zXITEHU1kLD33XHQ$rh5?Vr4FEy#o4u2V3 z3t>UR&#>_c4ugg;dW=V2O&Px3FA{u06PtnEYR@Jk78wVB31SB!)}mS@>_ih`)y6Uu z8C5n(XGB2p2q6y?fwMWy1Sw^lk(q&{xHu*=Ar$wN0(+y1DzpDZYYxv){gBBEhPMOK9j zvc;B>or@6dF(mn6CB7_5W*LqsQlEBY*s7vAisXsGxom@8x?`PP;h;Ub(7+}cpZPru z_fM!<--m^*ouw=optOg;xO~S-O|m40T`g3Ja{&Su+jBcvgxpAR^$try}D9_5_8$hxBlO@AokVs)$UB zfB8(aAjI3SLAA^kq6q(;q=7P^w6$-w!%iG`4CIJVQXM=}Z(lKdN?f8cmct{t8 zLu4Sb@0&VUpQ&ZBL(M;(LSH95R3?uvLJ;}IQhAJkMTnkshIL`}WTy@?M5dJ&crWyu zAX6!{)KXhqIK}^2T3X6 zess(w9QVpQ)gFlm&n~|!SX{a``lB=^s7ss*(Zra}X-qalYO2%w*lu04D41&^u!Qu1 zPbWkMc1bmIsFT1wNZz@Bnocu9wM;%;R+vsRK)p=HG2aX6qRmt&R}sW^yEGg^J57PD zsRb}Q!mvw2eB&fijiZ{UL$8U7fY7+NJhV!41pjQuK6M#W_#+-mM>r|isH}Lrfn|J# zQ}gh?1({NJOv@pE`E0-=qYN(w-Hd?-*I^bSuLySd_^Wf0FO&2f?#8@aQy$ZoKB6YE5H0H~mPqMW?KsV?H%($_N8TXKL|;AeT^YZOy^BoxH0^64 zAmriUFZHrFRg^8h!2K``Rnlvh&zWI3AbnQ~`Ya-xr^Sa+7)(<#9NEzl@SA6?4kZUB z1vKhvgft&}GvKoAZkJG3fjTU9iS13H!z6#Mt&M15?*69D2QB z;~3S;!iJi4RYjJJ8>wE5_*5W5|#AR=(KPT_sDZ5{PW!i9mvG7U}Soz$C_9%+`(LM^A`%Rzg)0* zf1a$c1}<|6<9O45T0ke&QW)~7`!<`9zyTrk*4Kf-u6IQpdcq5H>C(4fIn^_Zx$|2S zoXf}Z)T9B6-S#g6#4D@XCxk$|YRXJ4vW^LjvT&GB>SN((v;$ zQ4M&^9WeR`Uf^I~ys8Cu*R45@Eh@OIXZ3`NKJ?VJ`B|?GOrzs&2_O25j`O7iQzM*` z_kodz=Dp({nzMtsuu!a~ZLPJe%tSK6DdTj+lh9wP)D#leNUi3MXp5yn~uKB@w>Uz zk1-dI+tNJ?CbQg32zvPU=^p2+D#}d~TS!61aVxpTfZoguSX0R$H#H6n-$hwvAr+4~ zk~|eP?4(wBL86NvRI@!HLA1}Y0d>n7i{zO zZwv1rxP#ldP*(*=(&=TCMO6;`dc1=^kn)MPk{Sv`S+QMGjQ-Mk2okV zrT8_rZtc)~L!a@hdHi_TYOckqJTku=FQKuXr(l(jP;B3nY($1ltG&k2`+OOvC>{Z8 zHTE^SNiKMG)h66ArSe)LSWUEhf|@?XxhCZtVOky9cGEh2I`d`3^3cxZD|e-^gJ!ME z!aWyeyNF6#^_s}<^=jw*S&vjx%dV=)3jc?yXIVZ-q@uBKuCY&P&cd!oOB4p4Dy}|k zP#vyFi})OyCp%PkIjEi6?Vq!utzqj%QM=A)cN;cAzmcRmXP{nW6EWQXGSE9G@Z}%E zQ=d{CSt|(ExO(kuw$zba_0!E);NR;~BY&waI}JYL?KQenJc=M@x?BEct^~012=%;r z<}Sdx&2Io3>|o%wh8kPJ#J?BKA|>IoJaiUPiFan?2{hs!R({KgoK*2YRts5H_=_iZz$R~wHoa*C%O{VhB1Dw z(wj_4k7XK20_}CquQgAz{V1j$gS67BM5!$~vYM+0c~gmAntimpeYMsgoi`2*sGI=> z88R+wG3}vC=$@JxnnxO^MG{ET-vHZU6G|agXGi7~Qdz_zSmq{TG1b)fObxxVjtwAU z87AO0zY~u{Py7d9g)&DZN}xItIR|qb*s|mK2UuT>Z-iB)-w1OkcUkbDn~fg6+`Ep` zI3eDk-c6s$ykV^q2%cj49yeYDTlzD6-Q>PKJ;N&KQO<@oMp=#1>*wG+Alig((LlW# zQc3#No3H+IHE2#_HL&2R+L$aB$NGwbWdHiLZyb(o*P?rxmUEmP_qEP*K$DlMOOo?tDH)CLaPeU>b6iI+IRQBg?DJrIv6F5F(YkYsH3Y^ofYF9WLN&N{WwgCZT%GnE+_pvY?XZct+Ms^?HXpcmbkIu zFuNoxC|+;*+D3d#xGDISZ>ttPA#ntTEaHhHML~*?)-t_lU-u>lS#hIW;aiV!O80g> z!Y8tHzA>qGF`e{L^$dc7W<&`iLCVN5p>6L@i}8Km1mjFv8izPH6#k+qf`wH>yWKip zo67@wbrV12Su5W!&blc21!oT+9u!0{i**(Xq<#ow9bzVS5j!BWszG0Ex|gtCC0fKg zP0VFgn+a56q$=ElD73LV>kRf*(q+ajr$4eBSFx`Ron=?k<1TFjp)|KW)ypK4n`s-W z{-^+TD*asXyVL7VyX9^N`pr|p;JjwgA+Fl>?7^a{0ws(*>`4`ecg9B=qq$y`MoEL~ zZPA@}tvqDW$-z*_gU9PzQP&+@(dpXLtaHFwT9Z%!&(>O7-yID`rG1RX+6TIhI29IS zjB3Ns9Rrzh43BmewWGYQn{2G{;AvHPd?(KD-9j|E8Rn&8Kdp2g^_o&AdG;(hI9-3E zX60%7{lW+8tnVqdmRWSkrcxWql_tPjHVd~K;FY2Q)WAXgplw+#1}w|MW$6&JW*36_ zMhG%1Mo2#JHo;=M?;GjerA~U$Hs7cznD&TbFAW5*wjg?k&Z2@QY7Ao4Cr92_i0ZxF z3vv5GrMRf(Z8q!hE)aFu1Z&!Dvt{?V2i;DSRt1P^+@uGr%~WGDOyw&a`u9CY^@ao; zT6aUSeZECk6MPFyR9G3!RyGDB23&GYIci`-bQ>azUtWcg>|GcWuThvri5^;QF4&+gxkqk#B!FaMI>SHi@F?kbjSAHYvCsHmI4A z$I2oAuWIibTnMbl+5Fi`JCs6c*(H|hxQ(^!WS8$|4DDHyL2YT;(CxHdZ{ifwtwyTH z=aiC0sk$oMF$T7yk+3N!6p4#gQssGiG2*xV_6I~8KZoT1%WMPJ|J7^*D;q1*|1sO3 zBkhDMj@VT$^<54-#GNnp}ePlOKC)o0GS5h#304YoFpAs-upUsN_D+I-;P?cwRTk&kFL#)4;JgoGkiR& zhI*E=m2LdDaGVWXBeJj2VAVJ(jDN>(8k zUB;r6w2Yj8W3sBF$D6Bj)3QVBmtOMaKa&i{{o8#iV;+Lb{ohmz;`UJ0qEBn_CU&+g zbprh4=a0kk(G6q@nICBC@bom&nY$~{)F0%v4yT1$Wuz|=sJ3Zgzg*uw7xx}S@|v$C z?S!cMj?We$V;75>THCkQNtFL~qEj-lxO^~nN{L2dXpvet(lVYTMslG~9Pfp|q@Czk z)NB_XD(gumBQ6^=n33v1h z{4W)~AANp3zy(~L-CKqF>RwIN`r&AlHAPNQ5i_ZR{NUeHf~3_=K6m7M`#a~iNThru zTkLN|dD^!M{UA|b_^GysDx)GCl}t+qN)pyw9_)UXYZb=VnX>Dj8LC?-8ajGnH4uC> zrI$^Jm{Xx21CFupjQVf>j#qBq zDSaA2Zw8mWHIl47UpJr|eGzCx-x^RT`$h;>7n!FVFrTeE?a0qi)k5%I@Fs5jDPC*p zn)J7;e+>nd=L1H{`D@o#XMb8-tjEIVf)OczJP4Umhv`tbL=1vVSgLONS+u-v=Aj3J zvC)+zUKg#(I;@A&pxtT1j(mg7{TUCERJyONlz|lG@_a(6i5pF>s&$aLG8{QISC`G4 zyZEs5sl55qbW1bQv6(s&R?W>dOxOlmbIH1_^yXq>?+(N%M8o>;3VC!B6=YuN5J!G= z_=Je9!dR7ZnIDRAhjNf;=qWc;!)DxkS`{`6()QE&a&1d0z!{~*dezPWj@KXQjtK$}=Gy;|xVUmAYsTE@y#;f|wl*yTt(4&kh3SMk!dyl42f{F428 z3fycJ8h!_)8cT?3jX_eEl4*pHpKFn;s%j^v4wQfH&`->z=^%kY2)mlFSVgppxM&YW zX~m6sdy*LIhF0qJ7}4b`B&%aPbyNVRcJDa*AMoeysoA~)>04y>eYvlWOtyvXh-$rj zhDprUCX?D;`_^J!4^Kh#Ec^%i2?&-UQ%7-4y9P>KVe0u?T3-slMKxJ(C?XdAhWS#-SAh8NO@q zZOPoZJ5p+FmY!jE%Y+&M3(`7xdj;LqR6BG~OEHqV!_O|6^!ak&y`xr)hjdylj`D1D z??}+HI#2({{HuvXdfdcw=oI?-u4?Ha%!O)BC=6Yig&BPUhRrtS!NCB7evUxO=w9jsebX`%h3*)ZM z$tE83j=ayvGb7wYg->5ZJR`&0-l^Z`dHq^9AYQq4G-_wOK|NUOI@pVmL9>+}U20tS zgAveNZHbH3&@?JF{Fz2vwy@ZA&Buym`Zblm7RD5U2P~&5t@|tO#1dgQuI|Y;zea_#8WGQ+xY>A}oBOAni+5<7lRM z)UlzqwzOH}s6d{lh->=G=bW)33Us&0wM=sPQ~vx%ynXUkK?KfI`28#zsruSk;z7|Ig@9LSjO7Eox*iwGQ`xGks3o(Uw#*^ zmRF8y>1Ux;`OzvCd0>L@4b#P^<+EH#KE= za)C2M+Zcdw*aj$S%*rSIJYweuR1!P5bnk$NkVzfSHL{zP7S_V+&kmd-ORyu$sUlQM zfNwm*sUn1R?rNY4f;=q_)5eE9< ztmPy(;PeCM1g4LdTunsF+lpadU~@Y(7r}4weltShtA1_d!CCBiWWge(nJu%4hKqk8 zDq>x>doeoe+a}MsW_6%Cu zAE0DUK_Ss?Ca`ugECaq@$v~bw*J@swC=@3*Rf?z|1j@n4NYa}xi)6xgL|h5YfsyR- zGvb4Ch)cRey1we638to*y*K#6wTK!Xad9@mUh3u^^nJQidd>OKG1!FD8a*EWn78_6 zL#?8VCAAX1tnM7-qJu-{a&q+6D5Q_N#&v3)waww%EL$6g*Id!l zDVD-b<7j`=4+JFnht+%2B`NEN?=cy5pGG1H4!QW|zi*eso?Vg_4973GkR%RyW{Q}O zTA7%SYCm(5(EMz?1tu#$yNN zPM;8AW5e0ZV z4#j5?;w5|6kh922SJOv`R5Z87$I-I_l;z3x6_NPfp1fJSsOKRr*rm{)g(rzvUrVd9 zK0kŪ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 z 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

      ?H27scgM# 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

      V0@4bhnfq(Cx1EizAzA_htX$LSSQ&?pi@ z-+`bg-raffcGezB(Iv@jk$B?Q2GdaHIB<_}8DlAWjbXN~_A3_GX^eSe8%eJOR3*fM z=!y?f5H1H%TgHYjoQEdyJztdm@z7;O27hm_QPY2t842vRX<7ng*ejz{vmW5k59U_C zUHVfQzbB0bFGIrRuyu~rj7hShT%}cgu^@%RJIJ(HV!qE?!qqx6_Vdm(x^**geL@m+ z`6BJLIwO6f{!s!6SM68_Np9Pkl>cv(b6G-aLzx3T`wP4g8~eO-M6m2;<@V*`%f>Z> zt*id6)OC`&;;ZQ3*D3#-Mj{hVz5QQtOM_ft$-s}NF3SOSURCHEA zMMIGE;2<^Qev4h*ohTV7wCS1_pRylaCf86U1reJjpXtCLvdX@RLHsiB(6IPAdugF5 z>BvL`NI+u>Q|;aUIEg)@{1l_NSr!mvOI_l^fH4Fo|2iTVigL`Btg#k!sEppIv&&2lv;BHCPd{zMzDvzg$VvvmX0u_ zy*DlFE*?;Q>zjLZTc{A9hTHgy z&_8}z1AxrT)h6adgLv#GN)EFEi5VYX*nLwa`{))t>^zOPh#HA$j{B?@#1fOVbIW2X4< zggIFF`D8(8_=m(LcLpN)UYj?}6C)>o@Ue4{vUFA+5IM3_>hNkH3eH;=v5!fYi zBWV$35$J-~T6*y)34*3&9DN+sIFQ(+TEBvD=wh(W(NvgF2}6%wXjf7-$!(y!a<(gu zaRn(yy6=Z{LmCY581ue!5dOztQFY2JS{1iMnC&$9d2DQ`sB1hz{WbX7eG5^&U{!2U zsLXRbDE+y)hXG2CQ3*LmU@iLytf(Mj(b0&dDm~&-Ho&hs!dx=NG|nOUvA$^cEEEwL zC(JeA5X>~JHW3x@UmD4YdTc?2WsqNzC7@4)MS#Cm@hEQY>uV3uKZ4Rqs7eSqbbDEd zQN(`N{?F~vMG(cNT^fro5#1J{eD9J~l%V|;zh9l8e+1{szl`vC@1B#W%7kDC`a=&l?{v(m4_ziHlny9QuD$R+LvCi#im zCvRdBykJYSZ)JD&oH+c$)1VYG?88$+=AVyw&akC|z%8plcUijsi=O&{}$B9Gm&Gd*@>A zpiRjMaL9CWRR3wNkU`dTShMZ1ex&BXefIo^hnvdv%!(#fdMY zliJLU$JM?}skM(~)aAoXu?=rG?7xz25HtS$BNN_>&R+uHDe~7wP@JQAZwB1MC6zHC z7aOrt4-+vRZy7?7)+rVf-te5lA%)GBcz7|ABk*=GjYD*7#&3Cm30ELP6KOeL?F-uK z`Dfc76PM+=_$g!WLH?wJ!0A|@=v_N}94HVi0gS?-!=qP93Wx4ZQwe9%er6PCxT}k;LHM@6IiVD-~MoUe6=U?10{m{#Wu+1~xf(=)dw{f3Jr^F%~#>$G}#7VjT5 z`m3Rx+JcY(7PV8!l^P6uuczVXk;U64-)ctG+B+7QUv?|A7Rz;-s(0vLhmZ^gz~~}O z%Gk-pmcD!FPY<6A#x2`<-4JAk6-Gh?_YcO+ z{jZf_{NXzAA^!?2DV%_d)vbWFm6?EA$vvK+0Y(B?Tt}2UrTo9_lU(4LSg?mYVHh}! z@bN&)P41LHRFA$1b|QO;L-iP%X#+FNQ+XfLhUzXnRNLf3_`so{_aKVj-Bv6FT) zkO)1V_WS~|`1}f@HuNS^LLlKg2lN3(6uIz334%t=908FK@f;43_PtU{v9DaX>Fwly&Qw=o+!%_i+Ol)k@ z_K>h3!$d|MB}ZDEg;~FywrKz|kx{;@`&=xnEB74~0>eUAx0zU~yXhq~K4lkFR7fU= z-f$GbFT3AtwEc}{%|AEPuE;B3kooU5-@$L`iMfF|J_`ipW&x$3`oVhG_1Nfae4fNA zMShT=UA6SzX?a*HWVuP$al%+F%sFmDbPWbhmgWeu3!534resUP_7P@5Nt2NQ6@3t# z^Gr*`%ghaqT4kX!usy2`x=ihmI%T!FP=T{`U_tikCA*>PPB6=L$^DS^_+sodr&x3j1E8C4Z?KN0| zDG6Mj?^fRU_e%?hLz209HHZ`}dWcrgH|yfJb%1gaZXO{15|FQNaAeYzDc6COw;;v` z0xVdpPy0Zvm5S;f+fel_0AA^O;Cs!vf>8bd!qKciO&>-va57!~P&6B|mQ5T)cq6PY zw@@A$K-y{HPcYV3m3Hrm3Cp+=_FZf*+7p7US^-=}yWat_10N;VF6P-}P(5sox1F8K z+$t#F`MyO!Zwu`jS58Jk07bZ;c>~YM+e$YY{JXYi5U6(I7u-DcSD+DisW7ID(%JgG zthOC?W1=tt({dKoeZ-$g5+oQuh)D8yMXRSShJ7tB&$g^5-RlY1p0{ja`e?obu$Kun zTJB(*9m5qKH+OBwV^tMt*14MrRqF%a1=(X)IxPqeO>1yDDqc3{4bVC@y|15o`0>&j zB1_>FPxC3cp9%v&Mto370Sh)-XEYW=9Mprm%vzo3*T=}?;Y;Y zmDum<9_-J~-}VGkuvE2lz&-0sp(IBhuG1h;SHewMv;ybsxm82(RkMwRPTZ)=r5m1L zCF*!Q8O&*WniCKFj%eN7jekKg1eMfN7|?BiMoH=s%%pScIpy0~_yVG)iF(Y$(wGco zu4HUiR3hf0OFNqmI~OEOE(WYekR$p2Ex=Y+%I%ifyLC?Pxk_kmP$$S*-PU*bX_#hI zJSfRAIlI9s?FCKe^2diu3{r4w4fR^+4lnaj)5uqqmX=JVp^=rOI3$GLO!Cz2tI-4} za)<^lmJoIwvqEI0mg?=XvBzAhkk&Ww$i>1s5IsBs-Pj|EHrXKv#t;0_f%2#IU9?0L z@%-Q&t#(~u>v4)Om-Z~ZD{9lAj{uAVYGjhz*2vzh9s4Q|Uji|q_`@sRlpa}RKo z(AY@9ZEY*x#g>q|MERvGc3=JcI|3f%PFZbWbTe1eTmu<+g3^-77`>iJ9f*_-ql5RT zE~y<1sX)+Df?l+U^T+c(8Pe?0)f$|GJ$tv)S;m!O-H*b}fVp6eq3WU==HQkKOGVc zncZwYob{;80E}t7wxb_?sus+r$7XZM9>_is+YVj69tuTKhg3OlT+?07UykH~21g?$ zSE26?(%8ChpsArKJ^0b7n?gppM{h-~rg(dY6%dZ$2GM~AnLKzrxDdn^4^)gSM)=I{ zay=@(vJ>QP&@7_Tr!{D27FkDnD3l&@;Ez+iMHtz8!dj>6O4^g6IP$M{_Jn=cqBshy zP)w?`t7b~;2wpYc{Kpf*PHHZskL_w{>Gx8Ib=?jcvHdbbmGm&E!S0MA$N z4X7`>4;CO-DjsVN&RR;*yNlHZmt6BNuA5Ix-J5pfST@i>zvA` z65jo5gL8{qZVfds`x%jDs~NnO5#%d?W}7a=rGSfvdrj6%eO9bZy-niR9+)iw>whs5 z2T*op2ok6;Sn(MJcBI*68Q3VgpbsMZi2Yw%VcN2DiC+SlgAJJ??=svI2s-PqJo{P1 z%Hr0__cDPx-LIW(=EB=VGcMt%WgNnQ?!@iLJpn)oW!vjcoY?Rv7dmzN$&x1B={O#glV?7*lyA#+8c?*(9h^5XMf*8@_58RGEI8 zg3C#+$!v{u&DhDhx7vLEmg_hHadK8hyjzaP)52xU{u#jnUce**>WGZrswczTx>|>hO9e z`WP7i6V}=FwcZG;991g0S1_?Ae#jrcZid74dg!ovx$Qfu2!+G>g4gNQ?eTcH1%O0N z8%-y;DW|Z6ii1k)@&Gf??X;@Dc*$k&SmtedE}_NYd38yu>Y35`dfN+};osB61~ zW7P0l^f875Z`j?rbz{3TH}HLMb>;J>FB!Mu@w=2g!qz}atIKITp9WegN?I60B>`J@ zPv~x2DsoW36x$MkSHCozDqJt1<|>;nESds;UM^twJ@Zs_sjb8QQq-K+;=4`+Hno8p z96!iwLSwkj}Zz~*5c}k?)=c6ckhZQ(y-V7 z%$gX)P6Wo0A00>pH{-WtKO1k)(52SZ0o~kWut)d&NzytYsHyyl$+R(=Ds+{#8B6zi z);i2mz6AOR$hSRyKN~}H${8trN<4yXa`ltSZb|5iJ1HAO_7e=W;XZpNJ>9(mO-x3_ z_aS~-+cn6CmTuadYF(%^I7LLa#m1s%srt{SAP)T}zd+GcM4M2}Lg$t9mC8-s zpta7xg>6b|7-EMINKgJGhcik19StTGn_+7SE8V2^vy=B+l}x0oS?(+V1mxSI3Wr~@ zI|%?QIO{)WR~X)bm?I0%X!{+3(uyVSYkDoyc1EZ0+8McT$dBPE*$XIuo;LsPW1#L3 zfsGFD?ngNys@|&n5Qk=@I0SYpU>gO9;Hscfq1_z--}67M)trTB&T$hIK*JVN?hl+5 z`?y_rc6e%(QFv%D%TFS3afQMbiQ9P=kg5E+?UNZ8B+4`!f`T9bsS65LU1@vi$~8Eo-s-KF}m0E5uBe6*x?48 z6P?)v@WX>DB#M;Uth7-0b$9*_ z^+I3-M&o4&juZaLK&1)QyGoeTz&qcTCvP=6M&`rC`3 z(1EYWN$gjRmsDE{z6ZGKGV6k1+$)X|SVe@{KW(VwUZw@EiPs|B2t5iADj`rDcsd){ z-M@Te{)~G1Ap~GqM}4^w2UYd2-MTU56P&{2kHH?m;;rkG)1RHHS-lM{vW4FBZ$J&# zE$hym(+2v#@1}YkQ{*khMMEMq+>M}Px@NR|Od+=4?^_%UEk^7UrL%{Cw0zRA7)eZR zg%$shk&c^XO8?2wHE~EB!7KS_*(V0>rvge2PxFJ7EIE>e0+Pj&N&6-qy^Y!*&s;^_ zCp#jRt1sFaaG(#c_6*loWf@B0tx>2&C=076#9LL5m*aDPR&wq)m9}#h$lc z%gsl!6*P_lR2Ffl3@T*R>gy;0Y0SkMBbaKAXdDZhO<4V0a*_DmD+d|tEVfRDg-}uY z>!$=XO-9ZpuXWEx@Z~pA>!+qHx`{BDp%%u-b!y85)lF2EsSH+^1?kKD&&!aBcIgtG z0e*16IUsUggEMfuf~vbAzVGAVearHPAxF}Vgv~mnyw9fM6V+vA)rlc05_@4<Czt6fez+(UaK_JaDK9<)=3OdUSVP{8sLgZ9CMF+pQU>C@$Q5Da2L+f{ z|849RzI?OkF9MI#CT$~ABF!vg)ET2mf$iF54soWx5yICa&;9Pu&@rvDu{E?pyRxt) zD+AvZY29pM2_nv9jhAhN8%w^`t<5@`=m%j_{WLdX#OMuAn7aYf2=mUT-!b#&^+eNk zvvGsgGT`q!a3Y=msTOEPGUy`Bj1}7NL@^@i#xE0B7A(=j`Hyx#84zPy{_6+78MVD~leLV)(ykOxGd&j-+x zVOY3>>o0xnXKJ61oZGDzNz6s&)^M-KAbZS4m*jL94VV7K!65N@A<-GDfY5@LfxrpO zOv;Y%4VfTo;`WDUPb5%;fxVmYwS(>@0KAewQPxnl|Z-L#Ye!k|MHvSKmn$rP*hK zi9S>JWrHro1yA;Ti9Up;^Eh zDD8XP!@6MEcAWaz^2&U@fSlad9zvEG9lxD$3ZheVg7M*jsK2ASv8mh*nX{SVEI#4w zEmQt~3$Wc70<;nUl2K`^D&d$xu(()!Dej*71`{GO9gH+^-rv_SwyFzs9! z^#o1INDu>=UP}?or4mmXQ<+a@i>PcC^PNJi^VU8L`Z)3hliiS(oJe3(vL?413~&sX zK@x2?@$^_1n*jYc_5nK>m-rtFqd%Jpu`HImw7dcQKYVdRlLF^gHf(R(i zc`Rme#YA?j9Ba~jjdQ!o9V^7RZ0p}H|MI`1iON8(gesHEvgx~L4ToO=holf6h28{K zpUG=DU?Me*72E_^_aPKmm55~jXymW=h1<%9iT|7`$8z7-s^~u*XD=x4YliD>BBq6g5CbkXcM20v!fl_&2bvHv}E)iep6$Q*Gy&F1z5> zG`<*(6?{Es6vhM))4{Iuz{=8E?qfOq4r@qwL22l;FDjE0dG$81K>I}F>M^t6)GWRj zTu_Y0rX-+Aiac5Y7>>fAJD<%gA|Fj0uaZ=}UyIIWN!%T!hTRCF+-&r}C z_>qDvS+D7q%3uD#H6)6jN>Xp}H4C9C#26wIrNutCsg_EAS1W+Hwz>5MEss7j z_O?cXO<8WSStugk>_bODs$}b74r`wX^H!!%EdTGqg(4|B9;8_$*(X~dT`EKgWCTaI z>^#yD+#cHer#?-39-Mw7n|CdIL=MFwlBLW%5;2_qhvMjfl-30Hzo!gM3up_koR(rW zi->$OM{xC=QLN)VjeWbumCJbxK13O0i--ym^N9J7gN7?1tqF`@6-$!%hG>Fv@(6=W z{HENjuqB2iMhSE-lS8GvVmI@EY%+cD4H<-xG__5NgkDq&=6$GH>aqA^D9CeT$6nOK z#%L!Bv2MLatXmLvYbJ4KpMg;{#zUwsjGc&hi_hzD6~@asFb%C52}^rU2#pB<-P5I3 zn`O?FeW*<8?k(abw(GORQ9pzg*o5De9=2>Mu&dP9BauZB3rIuP==a11~|SZGdz(xO2eTU?A4MC!+gT<;S z3mbJZ6FT)JAtum?LScBrkRyOXB(by(#MdZj!Jvu25=)z>C$yasGrQp#2vcuf6bu2S zA>rTz+D`++a2t@Py-+B@vU6wD9W*5)iDIg!G+>$q!OTZPgn?0cf6Rp$NyAT?4L3Rq zBh*4YI$(kcV?!@h27a%ARY>P2^UR+KlX($LJw{L_|0$+8SA<>Wp;hRE-Z!gb2LGwa zhV}Zig0AaUKN#oCU-8JCyEHwE;A&34iOD_&i(}&s7CK!i#Fz1*zmtl5)D&=)tP$gb z9ZUxMwq-ID+AIj zGw)yw)T4_;SNMy-Oqj4yHxr>zQ)QsDrRXtMQg;)RHmxe%OPH|?klCl@Vss9U{vNXE ztwom^77k0Q`#v$MboBHzXBik*o3UdsWKld1Y-GzYCxpvwh{(4prnq-`e@2x5kK5|f z=t!naO#Ind5J59)(`Gx|vVvlaKzW1l&1(S|4EYd8r7+#wf9)h@Z2UP+NFyCJLK-kS zPNULCDL-~g>0s^~W}h}%A0@o+EGA2U*vRQOGTGN4aje|gBruaZ=rYE17s^&fGG@TP zKunwD(wZ>(_nfZ%2xA7AU``k_`jDP4b^L0@3BSUSX83iyo_S~$$wk0Rd!9TN6kU?` z9|w~6$&(z=8%l-v3S}=L8Z+o`h?6iPMrxKTq)wi~zd`aY%FjuOoW)4!(>6R&h>;jJ z-lnXfF;^dJ8m>-QMPaA{MPocOV3rIe0~Z8$O|sb03>mR${&p|3s4F{6n*Dv2m4G^)YbalhU zgo(2u58TD``8W5{@eD93NPcJ^;=5PmxrX+#XB_D=VR?R*j~j4GJDgpPq`FZJ98WV- zLd+AP&@1T5jP1(NIb>1q80rz^sNdN~Fh?r@s>h*O8h)a7R^*vZ@*7tHATM{j8jglD znlE6wmyRh5mXfz{o_D$6eeicHdDH-{C4S?DZ!fCPpsw`J=Z8=rkq<&=E>(ngs;Q{8 z4OQabs$O2b>zsYUxQUXW{u7$O-4ij0Q9kh~WXJsBG&gx%1v_rfr;df5;7_|x@4G`j z8x@7(tSacm*!TqrlaS5_PK1epmDjfc;CFNi09G~Z=ZZjCl$BSm3w9mlrMimqBX(8gPp8u} zZ&o#B)R6_a0?<2HT-DL{pI&%CADvAUGYWFeY5BHvl%3f~zmJ%qJ&iAb(Z$o*Dr64i zdYkuweM_ONmHh&Djr|M@CL@KMJPz~p?>U6AX?4A%C8X=x%f*BG1sr9U+tEXT(T8XN z@bJ{@lgygypxbY4XHu@`hNUdJ&9!q_`gUK*tv9i37w1s1^Iv96l9h&%5urSGu24m~h=7u&v zjvj~hx4R!UOXF}G49w5q@6Q)qI^8V%NLE6G40u3Z58nan-Hi>nOBIhpKv5y(M^I5W zO71<-5i32<;Dc2~aL;#B{i`>oi?&g0SRKVj1kqb?(ldk+Ej`c31GAAdAlb{}otiXn$9dW#-UzQGpBYl>N0V6-;sIX^7fmz(Q zEU*OE)Di+{5s$>6Ht{UMKvek%`jIrfD?4n}9RsWclr;02i=-sBkq-AX7s~WRtzEY; zeITZZ8TYi@e{X%XR}=;=%SO^B3)sjjn9fwx^$Nr?I@o}Xl?DfSLk`QYm3HK=N{j>DXsAfxJTq^5KRM!NEk^cA# z#VI?-el>UEpa1uPs!U8$s6rrlk=;S(70`>OhSc&je3cINlTHZGa~xYXB#>P?kJ}UA z^66p--+y|5ih!;JW^>FASw$1@+QhYp)t+aQPpT%iW5*Nl=b4&iZ*Au>d*u0dpn(tA z4ok&Fk#u7H*aZ#!vHxU>*rFl=+NY>=l z7R>^woTek-6R}L<6!NIe-R)SWa9U2Z-?rHMNxRP0g?Hf;vg=&0>7s&ZM2*Ta0e=FmfSFunjFb-J|&guC{$Qs@3j4Mn7hPKHz<2TIv zv99Y{(p{PKzZVmU^ytYi&(DXQ<)W#NuVs-L8O6DGcaKmzjM20|b*tVj(~R67di_cL zo!vXzUuFnUC)!8H)W_Sf6{D74*UvwJyyq{;J^YxDn%kzhyEC>^SRLmj8zowE{th(a=ZmFCa3Q~-8C%7|1xx(dL=_=j;%90!~L=z zWbarPOmStg{sB{vU|6t~R88@-1;0Q;wDz>V2i93zhp*-@)LZiIXjS6tPF{rt&YLYm zs`}!&cPLkPg*8#H+-qi8c3k#cJMX^`3!xT#smS7J&Dt4H(6GKv`P|$+B{GVj16^@P zGajYIy0bqi#dLP`(Zg1hr7f+UGz(ojb*IVOTmo7afA-mfzLtw?#mq%dou|#ktqH5q zioKgFCM-gA6i_`jVfAB&K8$EQDxqc%nM$dvzQ(x*5l7CTbyA1tu%d<#Mn=)#x)ix6 zo5;03P3UgDJc(BEjKQY3GXg#8mrUc`o;q%!?VO`tS{E=Dd9U=Zb7EibsaswBGjMbq zJ2{J{{8&ZkN9&$;v5~sD#blI}3b0y^#p2|Sc1?YJsTD~tvlihj2*gSxJyF}TN_#$C zr}fn2p72@wbW5Slrp_ANg75c^6s@?V@KSAMVw*DjhKoa7YWRO3Fzo+-2n+)q>;H|w zbZKunY_imMyC&`Ur!aaFL;yp4TV0Kj{~V5(UR7eVj|H0a_AewQtG<3ej@;0F>gKOPV;d;~Ya5!~# zkrBh2)BXKr==$#9?B1kfU1PIcV(Mz!ay!?ub>6w*^=5qkdX{jA3x{iD4*J6^okgln zpqYk3U@j47VqAari=mv!j=k>%j@01tuzhKG1K{>_yS@GiYao(6r?Q@4Ft6vD625;A zB=|V4l%cUjJ~>4Av3S(o;qtmQiKFtB(fN590MjK8slnk%t@O*6?)JDNVmDs@d^PFl zdh2EVxX8%3`kX>>*U&Ght6CjA6sn_{U~&Jtp4vZ~@}DvWVI80L>9a-YnWT{_7NG0D zPIm8jt>qfK5N@GDwS4+Mjdpr-60$ao88Hos0u61ez|n#$BHC0h`2 z1Cp?(IR`vAJE~YaLP54%OLz-z@|iFwA!qQ9p1fZ>N_Jjn$*G8AkfiJ(-BLL=@aeOr z;8i80%p1-#BNS%u*yWIAtZ}|6NOF!-*`D5W86Sx;N!ds=?~Ceqh~bhR3ZA;G7b0GW zK-cWiRbfl`Y_CLBZJ9_g$vd`vLZ2pE+e}ANk28^KFvazasFYC_>3vGpI7Sm2yL_g( z=dyRk5GCyMK}HAzA#DAL^AI?gi_r&f`C?XjHG&KG!dG%T~QdS z@YTVb+`hUDD3WV6-&VmeD#e*Ctwdp{nkb}DdMN3!(FJtzx;tE3Ama4y*3c!1 zwDGw7Os00hhcHJOTsYD&Z0)9lIT`o9H*WpQ$22}O4nZ>!abkq04{#i z)sNpHTO}J8b}ce_cLa`k-D3aTDjR`Z>RMF1I2^h!)Y;6W{Dmyk;*Qb=te+y^`5*x7 zd*2{Cj*B&Y{dIlMm;XqfkrQ756J_=B;&SeK6*c;RX>@}Tvykn9G6URgk(~J%MEgb+ zIFcZyC{uV9WI%p|Sb)oB^Q39J1<$w#f83uI3;|pl7IJ%*MSTX|$EgwhMPq+A&Ztb3 z_33*Lc&c$2TNAzAgggMs^lS;~p{3`V4csbvM>;sssGHNJG&#?CI@*Mxlt^o~njlLi z?~f8-y@hgt`JB`D+ZK>AsN}CC_0=U~r0VvE>wt=ScwynOhI?JytGP{NnD7=hjVqaI z)i;&MiZN1n1n>a5{AbNzBd6=SQZD(TdtnnTyRAQw8_C=r`Q-gnLr1dtX9jOcp zxWQAF>@Q`T2*W@l=X-?UML41IWKaTBYU+v1A2xesO`z^As-jP?_lv$+gbB$qMe#$wtqdrxf@Pwt!BzefHzs}C5-Y=h=N11 z&@GO5#LI9n#~Fk|n_Yp&ow(2Rt_Yj)9u}}#PhXasvi}wtY9Pf-(Wq~x$drMEJHlG! zbEuqhfJxZ7R4KtLfmQQ^Ba{o;y^HE)XAkyeWzI{>AOQ^h^8xQ8#@Z#Q3zF5MYR1z| z7L>}ZYNdo3jc#}-vWOT-;;9lnsS1zAp)K?~P&~>A^qc(6bi7ZS>5}xctO!CXo|h+4 zDe{#VxeHc<;G32u4(tESt(&t)UHbH(3n(Ok3szfJ`f(ulx6;fgw+?EpaGX5>msP$* znf1isxSnibN3m(X+Jjwd4#Z4^ecWIEed3})QqM@f2gf~bTNYX*poTmUQrji_l3@xe zq=gU3OogK4FRpLav6|11aHpsB;FOM=XrCK>-Z;|?)(%qRigd5y62i<`SqG%>7ImA7 zlFGMMz>i)TXQ)zdF_%zKQw04o8BQgb$iplDQX%Up+aoz{U8i3{8ml~sa_Xt-9)^F= zID#$y*&5DV#VSmrC8S<&G-1xz7iJVgmT=0(q@^f2AHNY26oW+69}OjFKsaxV9S*Jf zb0VxocE2sBczBPqSpVe$=yuQab^(c4G^GGn)bV%w)=wj+z!zOkce1iOfObjE+s`*R zZHQQ3J9892CD{DSB{=db;uLOD!dLN?3@b06O~_H!FIhNwx$;;MF9H2_d_HS$DRFeL zB#+QJjs`7z{=NnuG4C|7m6I4HO9qsQpW;HBdJQ*&)+v~f)=Wcoo=JY&3*J$WJHdt` z)HZDr-m=GCTDfG&mOeTii0NKfNprse49>kD+MNNhRzr`Z8bvOYwGcWFry!0FNm1B@ zSd47`B3Hq$IDA?onDOw}$sW`HaWXkl#Grw*YghChp?#PD&WJd(s<=+!6+` z1?UTeUaCJAGRAV_vn9m%{>m-k#C^8V!EgGjUAUQ#vcnH2+y~@ZSIpOlm7)X`rPgE3 zZ6s1*##>8*R)UU9*V0j~zFZ*0D z)UU`U7AX_DT&h;qE5X*V9hpuZtlM6-C8;BzU=Hh9@^+L*4;D1gLxfXwB#%hNZP6? zIP0(e*FS;4p=fLgXf0XCd~C*{ttB3|JWoNM(OCH@k)Ca!u3&m!8}xVLeUm8=eS2h1 zh_#|HoNk$h^GI~f2(Q(jXuc3R+pF*}xyn%MHNB#m>{y_vy5MkM{GM|6AEw&W8bSH| z(ec*!%^oD*-e0LRWxQGgnIszOSPE_a1#z1`FF-;ackQ_ciXW_Gj^%@{wGr{4eMD25 znfELEdW=D69d!@#+Ct@=r>wWDdR>bC+P08C@4&Chy~Td+$V3m4%;3xiQjb$HkU~G1 zokLGzw;im6k_?mVl`UG^_Jq!hwy!!P zz?m1z*aPK*ZrnJ276i)F&@bJP7w(Gb_M29i)ojhaS4I^^#uONRman-5&ZLwk7D4)Q zi!7!U6xr^IgtZ?ZOW`)8%R^X1zi%w8nh1}YQ!y^hS+ejg^AhpFs+Q?gGWyACdjcVy zb&ghMCG98XJd7F+3RRG;47XN{IILF~>L3vt)h5)e0CBt11)FNZ7v|;Tl{8dTJTb)! zzz`?Z?!nc|4x7Pc^aodDoajd?KHWU;?du(qu5V0B`~jo@Ci>G6OsehOhp8G^6W`w~ zXi>)1P;RRxhLpI&pcDz~{tValHEtLis^VaB&w5IrqcpIML*M0TLs&lco=~!@<@Qq; zrWmCAP@x?-MoUAZ4wBHIYSP*|>E7YFMT)9vTSYg{#U1jmqcqlr%;n)-K=M%r2aI>6 zYm0IMpPm9lKO4vjj>DRdiURQ%go<$Djf!Tpl;A(Wnl;`9cr}^_yk81%{MFtii6E(3 z)fW-M!=4}pJu9@*ANaPJ@dcR>Z&Zw7+27JCUAqKi)L&0ylVO5eAx32{JdUEVcN0Z; z5($Y#j|A_8qK_cC@VT;|SQ`r7T3NH!=RfJ(QTTKthxk6l&L;JM!s40>gl$kvlD>&i zzy__UJGb4{u2?!gNi#0rmRHW4WGlqW^Y{@QUDHB0f-FEQ)XSVQj2H-lFJA4?O-;-U zO4kO(*R*$z5zjQp?XUO|QnD}A6GHaHoIX4vQl|9@y&UdaCXX_x4Vd$RtY(v<+KcFl zHko%qkeKMe&#?dF0+<6{tEY4lH^iS0u6}7vl2CLJR=l(ro5eQD5iAd_LAU;}x=*Jc zM*ZBd*b991S4%9(V01G8YL50ib+cd?`v*lw?;p!J2Q?xL?Vw#53M1R$0#FnHVMaQJ z2uTdebvi}#$Ka?y6h3Z3HwR?6Hjf7u5fAq$8eKiR4Ie%u(_ca;Mo=#+9IIEfRQyd4 z;d73`5x{5w+zd*vM|%GvOq1N<*qE^rAW()p08`P^Su!CG4KLU3kth0;!PkZOS&k_` zp^ot*f)Ju%2mqSl?&P54R4oL<_CKhGNq#gPc!JLF6p#!=AMJ)wl1N6q8B7Q8yGIT| z^h*Cc{cAWuZil`t4haUVb$pojUjvAS?}CkXS~7dd(hEPDV)i48VsG=M#cdCQwj0O= zU-!wD8Ze%#{@n`KV8qbFCRB*%>eyfz#?G=0$70ds^pi!G5g|teJyED`30;H%bk8%_Fq;&bepD9~GaY|d zAbkV^L84}FtT2$e4x0WWRVoPd6mbA86{ZbL z9TZx+B%11Nd#c>LG-N*HHXR94Vk=7!`TLE!l)ku|)SiProv>eIT_y1z{eQ0Fd@0yc z@+^Rz+kEjO(KK2hgp&jzB;&)H?7uk`OsLW)aPY-lI*ujHlaYGOa-^0?7EX#R~3=L;h$cj&?2|~*6 zS}{{BS@pfJA8fpP!>W-2VwDo3(4f)as6R;%e;m$t?bV}u@yEPx$6dc@T*#hE^XSYQ zkV{p3qfBGnmrMVta&Q=KHXY^uesw*lsmu4=!$*=WE-UGSrreFqetpAp3PA<6c?%nM zz6YJhcdB}PHJYzo02EW<~AHeS7 z*O2si^O%Tq>Ge6+s3#tFLcOcH4xH-{IRl@qFI*3I@s|u)>*$G zi&Z${8vdiu;SA(G75xny~qiFHczZ%hc9z{pYPndP+_^&hb;AwO)f`*$ z9AfWC-D!TUGAA$Y+Xe&;y4?WjTCKeyLT_5y-ZcYk`c&2AZf7%L<(RvdN;vNIThnH- z8^S90pTshgC(IcE=RtU{A0cuc;X?6W$*+NO=zpa( z|J-$kS*+IOZN9U_U%kkJw+ijgTubT>YQU|o*`2d!$C<3DfqZrk{Su_~<6htcLjLB^ z`NZ!`d3L~&*AZrs>%X4ww3P=p{YJ=L@*KhirH>WbVn>aij=cHkw?*b;u}uF~ zt?rq0U!D3A!FcKVz-y+TKsX1e7h9_XUaNJ*MiM??YAXTcTA*WvGeSN+(4rvW4uo%?!^hG?gK)Ze z`?kgA;Pa}OAEYTC~MJ?TQda?TptNL-$g_44o%cSg;{Z!K< zsy$^-9(M(|FCiN|VpE|)8L7@nPb0kY!!Zljnd;?U=V?q-mp1q9=U(f;ZIo<=S*_IF z?y2Lv?W@IHl6d&MRYk~GTuR2I+%jh-WmEFTh*QYIho6qE8)e=?GWDsp-=~JZqkprg zv(aT*;_gZyb5_pb9QdC}8<_K!8QRaz=jztn|5A27pN$Gj(mlIcP zd(i#DL2@;uQpRHs+!(R!nWo7vvG%@-V>VCj_IX`@OKU{n%}#XZ`OuvdvWCa{hPNVK zq>Qq1DwMEDu8Kcxa&>_8DH)#P9o&Wpj1#PMI#W;@;VXA}>&`SAJU)@vM!N?4c^}d3 z<|KPkt8iS`8)mxeBSM|M{ObNoE8gEKu}`(M8Vsz@>6D{o1$gWqXRFHz59WGYP6Y*L`fd!6kFyI>Y5o{v(#lR#qK?$ z(Yz}t>){!pJ=F4w2kWm+m-@8gl-Qt2Xff1Q?Br{RxfZt1IF*Oke?Rw?4VmiVJ~J#$ z+=^8yLDKYPhL-7*^8uPWzo{Feth^dl>#{cIn<~0&LalNO%RfKKz|6G1*jTGe|W!DK+v9H0|&bh0Q zbLWk>B?j!B7EO1|X!nin_*ZWUCl7vX{;Gw03rB{ItYLZ}z2)S0g3QTmzn0IbTBF3_ zHbG-${r8N|W}n?GFTja>SbRu~5cJ8zX^Rop?5RCj3h8W({LPHw=0S;d33@vYIra;8 zS;0CMSqTaIj~-f0LhVJ!a5$IN3Tp<5N4noM^z-IZ&zGsP_2y%RmBrOkEDP&5F6TIr zo?#m^R(JWbc-z)wYHSXSm6rz8N4zh76fxl6d1*$}YVFEcV%?c_T{F;d;lk5~H~@LF zV&S6|Fhg7)ciLEL6l5iTzi!_b#v~%)`r$)#wFrjJK7W*v+hkx)j8;Mq#X3^o>SYq@ zYg*K{z+UiUn2~Onj*7tA(g|5!cyg2ZQLwx^L(r}A8%ZHA?sq3L$2zTs zqhSMT=O6ypYZ21I|F#xk=<8}D^ib!SgN>D^kipAmo>%W0PET!ZgiP$Mf%~JRge8U4 zZR~CBJlXDui3{CzaddGvaD8fJBXrNk%ihXHUrkv^+1}Gb*T(&>i<7I1vyHPSo76uq zq`G(4@E_MvX*dHHRJpobT~Nj5>HhLx_fv_BN=Zrm`P3$d1l*B! z^-krfNA>sf6&(oYO%@1L9(_3tx(gyAARr{bCn6*yympO&pw@dzc+-tWG$i&j5r=Yl8?FA(9;etd_t0y^ zbo302H*VeL;^yHMzat?jB`tIJo{FlPy2gD2LnC98hmTCHtZkm#+SxmJc)s-V_VM)# zd-eLw+jsB7ka(C zlz8~;A_P=QdW28isBemf5YZ^delBmj#v!J^NBhiuh?tI3eDT))Ro4FG?EhWHLjQl| z>|YuCJ6}^EQot~ADZ!K=C}^;{?zfAeRZUG@eVqMu+Iz+DO#>azYE)o`1+8)oW9JBe zgN!Za`D|vC+pf{Kog35Izipxw9HzltXcUUN?-JA{8N`^syVqPr{LxrcV(EtwEJ=VB z)W$f~Y}wPs=^wuFSy>FY#!c-u2PLojeTg${*sZ3~g-=U~JL{Zx-x%<@!enfZKVE{+ z*qKYv{MaSv#%J8Vm^S8oSvI5XiRyW@$1gOm>1u+n_0R~Thl=RO$@T}tBtfpkBwZ+g*pPiv>WB zu!Bwi5Ci)=P|3kN)S&Fs5P?8}x_Z>+m4nCCITJko~FUO0>;58r^>h3QQ^CvBQN`KmL<^ z^54Qk6N9-fY~cT(QkVp?45fz6KhMg|x`rLUdZPkBc%HQF4Mpt>VU8V$^%SWCOOV*0 zTbH2bexa!y7;?!1*w{r=i39!T%h2)H%(K%Z?8O~28X&X;`iBGvjXvAG;&HQZU6t<|Gfx&%YyWe$zJhj*Z7Lal9mnLGDAh<8|uZVg3Oss#; z6}`d;6nz{Ih@=$&X&!$9jJPuM1jy;VOAu;G=VEPCyb?!fiVI*f44YR?+NK7$*h6=- z_4E{}FkfJ2+gzAK`=BAoD<sb>Cz$$O?7pcZS zU&NaO=25?aQqR`YAH-`8X!+|!EmH`61Os&Nti<6;|Lb`Osre5EECL{nKQ9pMxp=c@ z3u@>OgF$Xw9T|(WHNZHBa#1#b;?Y1pZ$u>qbE2&O`6f3BMP>uA81@3x5;|vV^XWpV zT2Nq95*;-shG1 z^kLkyamg|>s)J?ThG1=B=}x!Z&EapFZh6zS8u>mG5y2 zPv10~R*cRRuRj`N3UWm~aS8CNO)pJvlpMR1K<`YxD1jQmBU4lyO zS`N(<2ANU?ngn6HdzYXkyGf^Yz@lMqFG18#VEgwbr|r)J(cVcCb8Izfk!+@s2bvs~ zqK?>G93U(>ZQG%R9JrPI{max@Ki{_>;)S(rxhE3G&hYQu`Y#QqQ*$ z8?pZDiMh?Hcm2iS%WcE;lw18<#$}1G2-^g@XGCT8)Zuc7!Lh_&Zfz;bf!PdLPY?WP z0UDD+r)t3DDgeXzdvy2|5K0twNmwIC!k6KHLc|?0C)D^Qll)(ku+6n|DBqviB0r>C-_e_(}%}DZ~u4r zp?Xbsgq({Vr+#bpcCIc8jEDq-C6tjFNbvq)&sQ^nE&}^&#}QU%LjWG<;fE}LgYaLV zhG{;={*5lv->`b%M-hbYR{vYU{AXU1`CSdG=Kd4>f5!?aFZAYLZHz*D5~ z#j`6S7249P(A$Ysc7Oz%a6bL3P#XdJtEBz8#W${!%5)r_(7EISO_mODCrHCxF_L$P z>r7q?3Qn_3j0;GpDPju^`7&W)HfMTD<+CHO{OB2M`@y!2G$FwQRyDuF4IXnZX|w*j zhE1tD0$Jv&iQ{GF<@A&yyiwOc&df`BGF2Dd16YRo=ax9r1-!0e(e(&<9ShTS?k{Wn z9_1S+L-#AVUOP(`$Z9&s?#CFWiNEsXs#41{w`lw3kWzX6p!<2Kc=(Jaqpf90leZ;# zGHc*|%6h?MU~Mk7DP+C&JB+-UW+NZy$t8W{M*)?YZc>F0esj@ClMxB8`DLQjvC zR@DP`XZ?Xstflp!VBZiKapOuuTUoWCBO2v3Z&ti?n2ozX@Ge9MgI5{2N(;a0Pfo#+ zzSV<0$gbu7CL9!X=Eo+JRcCUD$Waz)Cc`DDJG&4zF0{cjg)KUNa4x&*a@&7|W|Ndm ztp1Fu49Ae}qBlQedPIDewq2m>brq52`<0JNKfdrhmx~HE&K--qHQNz!aM$(5fQQ^u zlh97d=nR=>z`9zn^dmWKltWS|*r$33_WVmub-(jsUY*a(l3|a&1TyL;ZhkD;{D;z# z#ycgC*Y_TEx!K!ru2=6rF?)t1Ya5Ygl|UMkY`$P={%WHj z*+i<-go^M1YlEoN&Duzgj`75LIhoh9{YR&PteTT5EBTZ0@OvhdKbCHhG6syG15}9? zm{00eKX~M>(YfY{gnKU3(JJ2sOe~du{j~xn@fva61x;mExc!M*jR$Q6PU@0BWKmxPv}S5JZO@} zOmx3?#!q+VR*UHWdaG(q_0A&#-AEaqO#MT+=;52{+SqSM-}ZW38}C~aEx#fdiQ>T^ zQFf3MZVaO&t7zEP?n@gQ(Mjy0@xhV@9`UfM4F*Ab`wr2wcFUDqqXi_zFaMorb}vd7ZRC8>fdh) zW0qg!%XKJ%tgVrxI(=d>!h~iovNi180_9w1=o-^>*lZSrBRLRJ$q_-)-!9+;X7f#L z^)(H#f`X*r&LQ|_}?MNol2;Ln_C!S!A;w3wXj zI~~V`0n=UuwfBq^)wxz8DX3hfE!DdidiuPBnCes3cN}+KvdBDgLoz)?+I6$6+0w{`L;ucJEQL4wX)kimm5o=j}Hv&Z=#U zb34Vi@ADS&w(e&(YDmBq=^>Nz&klCbrPY`kS>O5N=t`^n+4-&#S!4>RJ*l(&?lVEw z-;~)QS`%@ug)hXk*$izt@B`X}1;s)rrDT(Y%}y6fN;oR2s>+)i<2>I5hUrl&e@1*7 zt$a;DBrLI58Iwa?}kzItliOycCm^h7&8=^p6k+TB8(BnB$*?dwXm?n*N%ls={l z=4R%zj~$Y}PwOC6QLn)m^VsdFcV8p!cd-$0F>->y;LMhNiLW^?=sS<6Ivm+5zd!F^ z)T4=)i{0UW1`*r?Qw14mwNl+5azVVQuZ`**8|yqj&=_VvCcCFa{5Hx~f0%}Wt#$g% zuyTwl;$U2<&_{Q}1ZIEx{2Fm*>2g7P@Bc2ZOmnx6 zN6v;C7Zoo-CY=6WUw9Ez<=r^%J2e0gqJ^<&+2Dh<_aeXfe-%mF7^4UjIY}cllFUuKST8He6X1sc`(rGoB^A{md`7GP?Sv zS3wL_R}_e4vy7aR{y#2n|o>CsR{G>HoPW)U@- z1j@&)YtpW)6q!Fs&WjtE&=H)!ZSo_p3*Pr3jRzsm8Kg6XZdG6?WUHkb^I_mZ z19fsXry9_d>UEa6jdYQM|I+1({ASR7;SiXLxuGF=W_uxC*dnsm0zLnbne29vc|0xy z+j|F{f{r^tpIzuoHMf_`l}h%ZyqzakVc*X7TNn{L=t`}H2F>Uymx=^T-ijd8$=!&T zN(Y#(zSOrc8H?Q%5IpSXxX@R#^^plPGxPec)oIOuF9;8|=OVX7_+P}4yn(nsz%>NN zDR54uig~@ye-LM;DMw+paZ@v-fG=)UrheD8N{>G4_HM>=pF<^ zq^G%L`E)2RTvuOBw>PrQlEqzdhd^zWyC~}C_s^*=Q@6YE&LYulCwCw{YtY?TolK}* zDz;ui>Lkxy1~OdisEJF>i~|^UxE&9?7a-8y9?X2gBXP74r22uKtQ)(Aetmlp14nxr zgu9Jmfz$Fb8FpnvX5bz0B?!k$QtRMIJY9v^H&a5;sV*)qH%hfA?nJ1T8UiN%= zOIPQYcDJCQ`bObVYc9Of;v6AJpH2uB2csFbp@(GBwQ{qMA?W0|U~yIW4tcl18=(2%zXa_M zY0Z$k3?xXlEZdctE9mTaVb^kdz1~4iiE{C*N;kE4=TX^;6pqrE;bXo_GSojmeyCCKCSFL?_GoRkqU}-TGRbPX` z7gd5E2%%9A{I+R^sUtXHC*Aor<^O&U^8m!1M2y9|rT1{$9XV3A|~W_ni*Qe&hV zMyVRi&KlbpSjOGDO9eip0o=cy*k>{EabAdhnn(DpuMHvr-)ca(PCVo#P~57BC;}hs zUTzN|12mluhd5NHI}6sJQKjlm18e2!NWQL=N2R`~3WGP%f!L)lT24AZpXF%+jZ;zN zi)fU_JO>z+Zw(H45~7=V0zDsX5%L)gq)YkyRylhgiqP)ao^H0QAPM11a{@!Q$oI0g z;7WjS*ipfZ5@b=`BTnYx*~ieu14IpG5Beh>T!se&ruk#}mb4eyTvMr)!9QpL}3zV6Z+5o@zPi0tjPsTNjni z)${|p!WuTCu}$KI%WpXL0rQK@mD_7%ZGOy^86QLVB;&Dq(Q+W7s|8>X%<%G=nj-|; zM5oLl<~cBzIg?|Lp@GedFMzmC06%yL>}XwKlX{i<2nNt76|~8UKzSoz-!+lv+kj)@ zS$b_ooE4Vv5;UH-W9e#5h$U1B-NNg04^oOg7SljV0``GMEnq91*$!r`!dCU2fz_AT z5#0Oy^en5c?uvj_cp8}A&B%ha!p;w8N)|Ldb}m5}zlbycw>_(D|;TFWn}$Q7H6_7-+)-NiKWYuKa6r zSvKZ$ZL^#8$$ep~Y|9rz*7Vk^D_#3AL<`2jz;)WaG{X<@YHk`5Z_w{V_mLx2*XlE} ztAPRpz9Ok89TSG#1&~c~u_1f?G$SnfmaE%i*2 z6dVSWf|a(U!F3Yq_(|CLZzlCDYegOT25f@w*UIO!QH18OqrwTn4tnac85>KHb)eXD zE)0K0Rw#&NgrRvNhNzgjgM5qHtgw>?%T_jNeOaY2i5uc%nk_F<3u2=PwX)GX#eoug z;4*ko^j?8xSY%B6^o~I`L<(Qzh;aA=@s?Y262D}#+OsU!ec($hi|KC{v9yfbU9Se_ zPN4|pVAm|NK4D)#%Ob#Xm|b?H*~-xc^y8#;RKi^a3_0K^Wn6i4u+}seUT|Pzn@Y^% zxYX&07-nq32uuO(ybb3lRwW@%z*VazM?BzZ*!k+w>B?O}QlaPT+5TR!D_4Sodi8u!ZGJ#rTkOGw)7Xz6maZ~8dDSb#Ucvs6hp#Od zxJA}mO4k92A)|u8rHm3X&iS{F#zsDM8b)F4UrAbU<7^?(JaZ56tho<+#2?{LC*Ij?{*I(5!#x zqgFXYJbYbudis~=CRwck2c%w9>S(o|ar@Bay4kJHQej`S9ktM(na3vQ843y8-qxY# zkH6!)luYbP4@e^~LB;o71W_TbQkzxpu?a~nw2qE5#d&Y}W2125j3R&z3YBMu*4i5= zx_2Wzq544=)9l?Wpc-9QTQO~vH!NAQ{yOa3d+*Khij~x-$>;}?fN@3FJl^i@o;(x) z%%Sj(CQZ$I=WQG6N3}DIOkRY~h&FgrBurcrgq_`KAf4rdzh^$WltQqk8o{y2A>&s$3*$I=3DcXUxJ()37J;m)B|&N3*3n6Wy;jbl&_3)&e$IDs zB$YWldou#iemc*I6gX%oe=cLS9G`jS6BT|(!NnvW9R|tA1gNRlj!ruI-CHJkUtxx^ z@;bT0_!8PV|51|%VwVg77U23uu7Nx;_Qmh5A2D3?cRA|8ANNO}*e@gSN<;?4G*(G5 zQ!S|^jUxq}cS^fkQgHBF!^NYd!V$fZ72fPzN%BNR7E=|o znA8{MO3j^2-;d31rzOTPgI_svPX%6s6NZ^pA8&$ZWD5I#HoriYPrUD95e_>l`kJH0 zOjq6}-``-?nz*Fin`o^InytGZf9e(=Rf*#;rg8gw=%dfVJ)G*>)TA_=;7Vj||AXr? zZtB5B+&HOroo0**NRYwznG)!Nc&kMtVV`OsK8SRo4qd1ueUXKwsgq_V?+vDK!d?U! z-Bp>!q|9WVUeqs>pZmmBy31^1_@H;Yj$Z)1vXJ+~OHk{39vm32#@X~iZZFIq@>(ho zACLULKy3p!&~$eAXY_h2 zxiN-ExMd#t5yZAWL%pkh*Gig8;V_3330vdIfmNLoTY?oTUscPDR3mHAg&B2NE1EfwP%ZoUXknz!!2~b*Vl{PzeAn|5 zWUY(q`}Q*rygZMND{p=*bGhW&43yV^7*UW#R8wxT$f0oP5%vD;1}si2wi2UiuY6s5 zl=U==$QM4V9k|9ZDYHBZOu^ADAB8&!nUbKUpa}d{oM#HaNNrqQk#OZ9W<#qv0t(jJ z{^fZ-2=)&sO2^pOA*BpDrTWzkVm!{PxOA2v#UQo;w*$nCu3`M3<>A6`s1Dnq!r@4# zuus>68z5t4>WYi=ppVyQyt|~Y`lx)0hPRLm`+WJ(3y<-mEIc8Gi>^%6w$@w@0jUpi z`pn=%&4UuyJOrU7C~^`Ew07kCS$7|N2);`m06Q;`)nI0Rxr?QtKT||RU38re^*n7| zc0&O)1TN;5gi=xn?^AvC%|QZ%G|5xLPr4Bd!Lwz7>ykL#ZBocpn$`%7#^9{w6C|2D z_WQ{wVngjPf7zLkt5lxbM!MV4@-U0QMrpwobqOLSK{qFFzY)jI`-Ys4Xm6p1%YiSf zfFiART`Bz0#j1O-m1OB1Q66n?WPf~qJ}~-8d${1i4$c$7isR7jhpKaMTy%boPI?sa z`Vy4H7)^Ew(z5(&&20T1ht}jNb|RYn!14JZF!n6-*SCBxaS5V$z?$3*Y^L$&=_Gx0 zUIQ>pT_FwVow>LK9TgnB@x6OA3!sz;qg`S}y@rEPNwePoe1q-7%){A9;C<9jk^9>Hljt+n_7 zS0NmXXP6V=C#mzB+IH5u3QznO z5RhX1rW!5LG5dD)6XVThV=*cwmpLYdH5SFze!kAZO>g!YN0m@q@>$Yt?%AVTv@nQ+ zAf3S0(-ZoT@l{|PHlmXZ!K0jykKWXs;*I3fd8TAr8PdZQ_rO6zdPn09jSzc1>X&o) zVg`5imRuw1bm<9f(o~R-I*BP&uxkT>wi8HXh&jXpTVWzqUQqQ@&8c&G`&tu!72_@9 zNa!3?l;+iu-qf3VH@CB#s=4`Tc#W3`JNQiH0Kvxc)>eO#a6E&%_F;Ls+s~}P`>69l ziEV~hnU}o)H}=Hkkau^jc0DxMJ|-;UMtE#LP{ma4oqD%_cR0D$Yz+RTy`@9kGKy9B z_|shLc0R|H% zK|f!wvLdn?#4);URRA3IrL^X?A4&EhIW zPG>YJRgISLUt4~zUIBY67u}jUR+kAetzePd*87=~`lEAAC2C?y8_FD{@Uc$(;IV@Y z{$y2j9Im#d$`i3gKDk zeUKXO=WMn>x0Dy^1R!NsX8{=gB4UWjPf$1wd>b6N^=%|(lLyfOy zOyfZ#TenN{vhk0pdxExgQ*+jZ%#NbMxbz(RXYgg-+?`0;OHg{ffAXt+UooQl=hhp{AN;J13q2ORcR^xGqE$O5s_?hzpXxQ zTfcV`e=SxX^^lZ0M)6MZ?M%GFfT)NbzpaBpj(T1Sc`3cKlsEFMY<(#6*%|c%#g!Fn z_>Or!PL&!Xmvj%Z_{N*poGqi-8Fyu;^5R55`|V4Lj>KhRX%NNzJ>fpFH(yi zsFul^G3LIy1bw-W=Pw!1X>h>&v6E0P+OG-oiNv=dqNTAuYP+m`mn$h)YW*S?K00(g zqs+Xq+}!+|&8PlazLi9Io!Qw@WQmyS=g*N=fo@M1BN-o!X_Q#KzR6?H@ov0lwzrTU zN$jpFbI5SVYwG-b$)70Vg|l_I{d1Jlj2OTB&440xzFLXJv<0g$gS=>}M=B0A^lXZ) zZR~vY6a<6xE1jV3WmaSr%d~?FN-ig0dP&#mP*IVk!I%5i(@n$eG@NTi8)+J~QMJWOQ4)6&UIeN_9e&)NwYWM-3|E z)mAiPpcuey1X2|BffQr~sv%W9rh#5@Q&;AM<7%{!1w!OQKQdd%VGS2_bjBeVhbM1C zVeD9%V9Omh_;3PFu&COiHscXA37Gpt0L~}CGlG+vnz%EjeJ&OyC6`##!KmofM#ql|?rs{4xb`-41 zq+P(E#@wzM_s~KWA zo1O5cgxrB*uHYk&RpG7xVsH(kyEe3*n}U)-N;u6gMmjIyEyF={4b73&Ov{S8l4Beb z^u8tg8;K{n$f@M9eeln~ifg%!6q@u$3%j`9%wG++{ps(S;8M6~}%&w7sw%l#BmqIZcvisI0`n zkHZ-w>y=mOp@UaGuVrVf-YcTP$o36jD)w5q z?!LO9;Lw+b`bvtjX})g}*0KKR+No=R3vfJF<0i?cs%xBaa*v6U99lT+6XHiORUMC} za4$jMZUz2=y%uaOKIziVsiGtKD3R>BX~*FcQ8uMU{GAHtrDAisC~tXr)f=Mhs+r;G ztx3)#F{fua)F1f`aXmWcj`F%07Q^>sB7ZaSMyKL5?E_u!mp1ntzMBJkYVtLcKff7$ zN){%aWCP_e$92WYjC{e28c?itnk6QHw3U+)7I1C{_dbTq1l!C8AZd=&d}wR5_2&5? zUo8Dgkl+k;8cOTA03#EP*!65Vqc_|^#`1)ZTQGi4Us3)j?7EQW2{Bo^2c60wtr~rb zpD~~~02-it!*n1E<1l|+6R7|%Sf`h;7sW)4nhiie>I&u|p+1OaS(BHv^AnUy_3Cq- zmPX@65qnCkz_p$~SxM_hZoeqzd4ke*EF+TCApd?n#~QXCC_58*w`a@-#>b130v+$hhqn|u3~f@_Q?@Y=Y2>$d4=W5Z zM)lFQah>Yu^7T6jNyMVu9C-EKhN2?%_4WiNZnl)T?ML5PSyGx#)q zU!|_jC{XFmgr!dMXF0EpE-6I5yobTMmyQc*oH=mRqNCk8A?EtL3PcC_#Kyj(ior43 z_!Vb-!ii1N1c9bn>k-h#>r2Llpl%`y2B5h*-&YAU(pUhuCGnwb%YIw@xiP`AO*W3s zCx-1`pc7dT4JU1Gch9ERnPfM|ZjoC1-RAQb>fJo}3Q5?3S00SPli&J|daB`JHgO99++d+fe~mN_jz3fnZjba2Rr+{fZ@!&D~Qnqmkl_;lZCP zk0MZ-2S^6r$6bgwv`MR{`PhIh7~rkEAvaG0pp^a=D~}a_jQ^?mIy6Z-moO|XNVV<~ zB-sH)tpEcQ02!h5rOdN~vVS5YdD`V53p@G>hVSbFvui$bv_IND0N5T4gC}PGNdRcr zzYF*=ShB#;OVGU=Z5L`lc7N&o;SgPU`V|{c37q7Cq3u?ctg@ELmw+V^dtW$C3%mKr z)E}H>U{^}D*aO&{0wWOs^r61cE|rl>&~H_#&2!k%X8MKBf92^3@bv$~^GmyJDUfVD zdld{Ap!s4gz~{{V5)==MgxLN4Os{11ne&{=UV1xi9D1C2WiyGHXOgEw$kVS)i5V~g z03^ZC&SPL@Vu_5qjYR{!nTcvN03ervEzct~kE3Z35Gz2b+W?_-%%fDq__;nsAc4Zi z5TsARCFobiU)%tDxXN%(OXr8I@}_R6cXU=xoAjBg!pAV=RooWzihLnhxG7#j4%}_q{DLbG}`{b91jP? z>TgC9ZE_*e`mpoSfab8$Qedc7hTf&M0w}uBBxrld(|qX*+CN6%!S-FE$I&$#3(T!H z^+s_G1I2(*;5Yd>Zh6No7~m$kVIkJR&^7T53RI^2zSqy49ObH)bveYrw&2a!NB(kvkt!rwTvaHhzn&i+0vjiQN+EBbwU|I*h@A>YQ^Rrv)fg4FlSN zD>VYP+n8;ks6kldZNgp!ivTDv1}b2JQBy`&OkTA#U*>;iV;?(Sg8m`myPEA2RbU2d z@POYV5xgGd@Ih(mIRL;PZN$xdl3~A!lc2kQG57f_%~ZP{QDP^8j6t&YRjF;w-5v<~ zWeo#k#WQX8fqO$aP9Z=GL&zueQL0V)yyEv$5|VvaiET~$o1H5?{QI%nLrjMS3SCQ2 zj>l{xymKU;aB@LyD$vmY+F>7)2)66k5Kh0WU>7veGKY`{Z+Ke6Go5v#g z(-yi`9e{xWZLpxR8A^KKx{k66cZ?H61T5zko+A#YbgQ2mjqbX`b?nu2)%c;WD|ldO zJlIxjDmGk|p0h|hsLp55;2c5`MjcVjI1sDqu8Y;AEz=#5VCDD`4tNtc zNAUCC5u)o%kFfh$lc%riC#Qh*Yb{Lx5mv@&C_A1v(Bzcr#Z0gjN;86OQLAA#OW^23 z*(cB`@j!t0_hVTLU`P+J?tG?l(Y>Ok15BPO^0Irr+o`cO!~nK*-?32l=X*8$Vp~o0y78U9i}96K_-DX$RPFa916q$deK7W2I{P?yfr;~(=XRs>Tk{k! zcyY_PzaD^gOuZ}zkFrs18yx!Ph4i;05(%OF-pzH=7VkajZp@2^_8Dw&iRvya!6@vx zPnh(DKn>;)Xp(#Tcwm(!Hn&mj#x?raD}>*pPHV&uv9mnOO8Iy5m33sjupv^=es zIE59&rfNN;XDMbq<%|szHy(W)$-E~0C^LUuWOCqnt&p3ipVm#x{E4bhG1+oNQH%!S zTJ)xtjB2wP)TSC)+Glq|yCqI5w-A1zr6x+x$JzmRNse%D!F&`G6~vhee8+eR8Z3}e zsP~(EbYE?sE2@@F#>~&GF$9ecsRx6 zTG+0}CFn6Q(N-3({I};S4r1;vG59okivK74i24dd`)K@AY%|HxN5DBjedVkI;KHhQ z=|jRQO-0JHJ)kKy1iIqatN~EeZ|Lr4eZBuxsGfxbU5d?D^SK!{JigyEh&|T)sS0s& zx<{wM7X7&55{a+X(nW}w*x~|%yFBKrgeB!pVaOubymGVx(Z@Z z&xLUihg=f)6~mT%P?JK{ur6NEKV+-@LrKE~ec%9ij5~Kh_`6l*Fs1>9>u*Cnj+Wl& zaZWQO7!kTW16u5&V0!omtY1FnkQ=oKxb+Kx>o4viNK3OO>YJmc{x}*|IaWyoN5VoJe(-tq3cc0Qr-Mn?`WRV#s7)?5E6a5>5vgl_sFJ!NOqisdpJ(8ZQGumoHqf7Wtr&84-Pz|S zK=}Kq9%a`g$c@QkU_{XuJ~wahHp8P(dCDs1aVO~iV*7Yt!(snHMM#J8ZfZ|#OvRjO zWl=|DWXwseh(iF|pyb9eO`DHH4Yi+AgJS&xn3ImNCdw|j_0sYE-K1%#k?)E>rPM7R ztnpBO@=-k3!NE!k*=;G&pv_AH%;eA?51+mNddw7as)|+@>XBY&O+$O@&~>Nq6Qrov zbPgB2hzpSd?C0S4oTrCs@S$IU}konhH7tMF|Ie zxAs`|Ft(w5wxOb6dd}BW7c1iO>!Qt`_TVuTmfO&+AJ>V{`t@==ushhCpC@W<=<@jQzo8_P5C?a!pZf1mlr8(#kc z#@e(73W}l}@-|poTB4%TFPVQebg5Q%OVXTBp*K{LsKPJlM$CY!hTk8H{d%w-2c*_c zWfV+OR|h5LR2RU=leIDfb+dOQNUp_NBMWK5n)GiC*_63u{XB@PJ{&Oc%2K&}#62ly zdG+`?$Wbl08_cW?u8~RR2u&}V^UqdqS}gzZy}u&3GPvU&LN9U)o6kID%`-~7w(*@# z<&=Yi(b?=1fvTB~zDnM{QNeZ2r?EKCf@N`(T{HECo>ffF>WtUm$}D(abQZoN8h{>S zI%a#T?!Thl8Lyyo=*|WGI=ZwC9C^C6ngP39lvNylU)+6t$l%D6exAop`&6n#}J zpLR6Mm?-sOW_HMrB^F=6Ak&yXBTB4m^wjk`GGkav<8xb;0x7<(n6BmP1gZF~ zyiD)#l}t8g-``m5#qAH*IWg2;c*XpPt-RdbAjCd6hbDqeSpuSz_##nFHyt<@)XEa_ z?PH3=NhKe%Ss!uUQb%Bez|hS0Opa)6;;R|p`lr&X6NKV2qmew+vVj$}xZ#NAu5n^c zcOrusJF75}Ftu7>>EOQeR#hVxGFnNh9Kjja>1`-CY6_K5<`!XNlt} zV4WRfKQP{d9Y2H)tsj-GDN;8dp?-5p2HSh~EcuWR4`G1z$#lb<2qQVM-&6L5IaSN3 z!CUF?QbWfho1PBw4Y~G1Bj2A5lh}wh&6egQN*R2)^-AlrCNzy)WatSi@mw#*6h=8i znQ{!twk2&$i1TrCTHlyfO;{HyJbBbmALc^(`LcZjf{S5Pq_?MeB_ub;(Wf0^iB3|r?LWjB2UY(C+$*U zB3%Pk1MOX)+}9gc({H86$dU^fZlEGvY`#masFAx)WPCj<#nr#+K*$!wSetQR75n3b zp5a8;Nv6q8Nkw#reZbqh@okO4mD0y3)lR%S8lIKn@=lig!|(fw51v2m(fY)KgM|L3 zhrY^z-{C3Op2Nk}tz-+thieGNuI^uE?y)Ip{~Ax`Ko*@M8v72v!`G}f-ouCQOATG< zjGPxr>;((S$w6^&NwXE0d-V%QG`Wn(hBQq+_VBf9N7Vz ze7U(U4BZ6eP40PT&X^&3jdLPl>Bm7F#v<4-vr^c-%8EyUptY3-zGci(j=lYJYA)4D z(+7|8lG%NYGE59dF;SA+74N&7(#@vMQ$BPXn##?#CE7|8sS8_lZ%qGuA+V4=IQUTw z5B_?mJ;fd1WaP{!^_oPDM3u<-gNKG=4j;mpo>hMpeAmwMU3u@m%bTRmiDp9wyr@U} zNkbN)J5wSV^_8C=5%i17ynNnAwMI50MOPWk7tH*%a&l37l5sTq7Fphu-aqTrGwRM! z&HD<(j$k^x65S^ZChZ}V&RHV@m`szLCSx9o*25R}F`WgAr5#lQE&YS^*%UclI@YQK z*)IFN8F-Z(uO7piPaWw(`>-*%@Kd6QW7s}>@h5-7s*iAKMKyM&(u5qv+W=vzW_vvz zNFC?IC|dF=eI{r0exKn=0Udc7EyqyN<(Qvs`(PN(=;weKyerITx57``JyAr&HRzi< z0iN{bdNzYyv<}YpHFTOACm>Z!)u)zYtNMN)=uZV_=RaFOVt#n;2T0n-mUh1gbZ>O5 zuqwLF`aV=C9eHe^--{B4=RC`(<&ckqY>rY4@)oWW?{{)y9HPpxHGFG5)Pa;n@`T+# zka5bPCAH1FN$sokv4cQJ3D4K%{+vYAP|+hsmErGGA2%%PVoFCDKe6!SK-F|BzOf_G zS$)NmzyhLUaF*r_^=3qi3gY3BJNuvnkkAwsNaxs)HO99!J+nfdldA}P zS;S(7CP(q@ynsKI*N&;Np{YUs&~aYRE0h7pn0cnjeD1q2GP@$rH;S2}qB|!g#E%gH zYOcYPfLS{Z*ylRW!5tmpo*}+*`anL*uhab5xEsZs=^QEJosLr%<)XdFiu73o3?hV} zfeiSEXhj@?^4Tb0qf)*wP&q_j`LUg?rlhEp&W)z0*Lb1!obBzL{I?w$SI06Zf!Qs7 z%2ZZ=QSbHO8{PE;p|Izn7H(_t4r7)vI`K+H%b)IPJrIk$cL6~&v^m7S?$(aI?1wr) zkFigMF_t2~^hjznILq}K$${bwj>VPC^C_{5zcVz#1QYR5!&@fEL*<k3Qf+cU&6ZFx`q^sCs%A_8`yoxqrH;93 zv+la-g$O;NVJM5F1~bLbz|k5~ESf?v z<~IhxT_){u$8#I?(e+?zzBQlPLcX5XI#6UZeXEvO*T&lZ$&Y8+H6XWXubH(4rpEGd z%keQvMPW`ou}@UhgA4_JbO`QeGl4 zgBkN7uvN57PEolr_m{R=L*)^-H{+#%9{9FcUZ3J%L9t*AJ(4j@pC#75rOt8`>e%Qm8}3XD;hx?hG~Yn?gf#BaGS0zjCqJrSt&qsBR2MA92qaA_ zcdQaGP9(b2J~UT8S89k-x`ya$H<4sNnG(QZR^z5CV~)KSxqVRugSo})(g^()O4Y<$ zE6c9|qh&9Rq)*ERi6IsX^WNR@Oz3fSK|O>2b1DJq9Z~1h^a8A*Hs*`O7~g0e=eD?%dw?Yy&e*7%(8izO!w6ekW7n>1prlZ{49xGJ87P{)*cU-3 z7Z{|*R)t_*d3LQTxA0oK0(bQE=1X|ziuA?BmOWyeb5m$PNAKgtj4G$a^bxm>oc1PYo@v2WZu#ahMNS8Y^#p76%<#Xlt@ z{?}_Wz<(p z_U%G`T%7)x>1Th$@wTV(#q*rGX6cvj;op0(PaiHeK-&~k2Ej5DB|mD&&myH5MHgq) zhc=EMH^efSaUgCL`jju2aOti!SIgJ8{=rrRnOrdwE+Y!Haq^O`8unTlya zkv$m-if+CFm8RO{aa9JPAl1jJV|3nLt>_-O7iZfM z)4r-|)P2Z9Uyjd4&@8E&z~9v##eCm+Kisz^wR0*zLkY((yBcPbCl)vpI^&L>2IDJO zo!*stFrg+*2f!_Xzke9sAS70Qf}A0&vDyE84a8c3>mJ`*l={5KL1%Lg5;;YBIWB<- z?!0n2G|YXq`v5PwOyB20NM#@Tyi0rj$T{)1lX;^bOZRsWd<|(QKB2pI*lusTo1)@n zE7vCPn4V3(c5ooB(`e7PX8s;FG)yjhL45~+3BXy?cOHvat@L_DyS_wjk5c;UGtRrs z5o339MWO(Ji8gH5}(r4H(?UnJafb4%-60oV@1#C2_! z-_xI(#rl0dU2A(oSpm&2U-KPDj-M2#F1RunF7$Rh^N+LP`!QF}s#6bO7}Mx;)8O1^ z4rL3NaPhINn-vx}EK+WHXwyso;mp+<>z#5t(Ux#K8jglUl`(=KMP{;1S6|$gsHT9Y zaf;*T>4f_JanjX>_)nZ*Tw)tExs46*clMJQ(*PRPp(C{TLljQQMFKCAoO9B)Uq#`B z@Wh;zJuBhDzfx2%zntkoM-g_P!#ynly1B6#wcn>aG=Dr0~x-5CD(- z@%gWiyz0lkbhl%WX;}bujO6(3Rjw_JIS1(%;eZbi`MgEaP?q7-8PB*tGv z`RfUlqmN(lp_lbGer?}}Dbs2Y^(@ph=6lRS&ObW!SHl05p0JW&?f$fQ+W8YC06^ohVN(B5NE8oj zGaO-u5O_q4bRVBFY@mt62b3nit+4#&!+om=-kYdX_>KbeJur|iBK=nrXv`tQWbkRY z?LU6~Be#*hzE9c1ri5<)4!ZYiCOLV&t7)QIeJnxBCsT{6AIzF6PgiyD2rgn`#v@L( zk>f!aR7l^DovtQ6s{c{+uR{2J{_1cca|Q++0A$j*uFI~*`1;y0Dbyh!-hYEfDoTUs znV)M>6Pu`y{u)Bnejf*9holwq-n|174Dj1;!I3EOV=(UOE1JE%l9LW6E3xH#PWv(Gciu(z|I7kOZnd~GRK`;+S zcyq1mO{k)&z!@4L@FU~Cs4H2(W_!H^i?>sg`gi&NrqBN(|3qK8sen%ahMdj{a3#U(Vf*%|A)mdlYa9v6BFJ7;};%Wa~_Wxd*-1pX3 zM!!=)Xqic%b%C3(5L)@tARXus#@9VtFjfjPH7W-&(t4T*U;t@cMYN{h>aj8(55ps; zX)kbq%Uh#r@<`jYi#x!ba4>MV+ctFePU9cqTj|AL)|7wcCqDb%dMgWstU1>IWq6ds zSE>aL4=kRK{sf&dXlM%llMp7q}Dx0!GR|4)k0n6uGF?M$tl z%U${L=tqLQRyJe~Gu1N$)q4m}KN?M>XDCXsF`;K(c1;wOUCoh!*Tjmce;x+9r$UY9 z>n24CTV_2byF;&0f#bx%t$#sm9mZ!gli(v>mE)p1J;TZPW)0wKP+w7B){5Y3-UD@2 z9uth#HN31`2Q0WEigomh@xJoR;0+O(i`ycF3M>`jA-*?T*7uCB6q==ff}ZSa0C!m# z0UZeZw~A;eCvcRQ{l&XVNK$MCuTVBYsdviwYqmu;I#GU)@)L>~?HYcpX-OM#clOR! zuRFWFsW%rPMzTW?mJvWk`~WQQTQ9gP>OWUvAu86JYs&{a_+p=GQ|x z_}kpKgBoK`$!N^=%Pmg^-dy!QIdSFoxt)ypd&dD)^>1VYNnV$H@wg>$kz^krwGoe@ z`lyCudK_`W?cKWOUb>4(S9MF4iWdhQ0453-!T;g(wn6$-i0_ro44SOC#}_{Yfzy2e z|3v?_?2CZgqOPQypZx?$Q3J9Cv=^Z{7RA zFyp-}v2r?l#JW6ETx7?IKi;EpuE|pVLJsz`2FJ7WR=?eBY&J|IX|~S;Gj91Uu^8k3yjZJA>58Y=N$t*C#2o&w}w+*aT}}%cRHncOVZHIC31E84w=&9pE!0 zKr-X09A)4nvFZO0snVPE??V1Fr~I2H|M%JRuSApSqcV8p4c8r{^(QEsH10pmff{k4 zOJ;@i!UTn&hm^mh%=qbK~X(qwmoPlOEqI_%1b zo;M3Aa=O_9E<_L%7E%7L>~Q~X+xz{Upi#qSa4h-%;h43~!)3o)40mP$%+1M&-hB2; z_4&KPtZ!OYmWv;m#3P$mg;xSaZ`d9v`IKZf_$v&S&al~VF+?&F@^yTg!B#&Jtc|$_6AF?I*?3v zmQ{*J-geUY`kb%9rSEINTdA%18{E)pO+nSJG~l zxioviT&IS|fWlRQZ01^e#xvNv=URns)qTo$amKR7v+iW?5VqRoaLo(PMOb$C#-k?2 zeY>u$B@VPxGdNF!74+wS-_g-?DACplkipT3WDMVk*SvmVE84iZv1CQD<<5V58-Bgv zQTu^CR-RrSr=w>Gs#clojHXrYMZ@!L81#T&ho@wxG2($tp_7LbN$%*lqa(*!b)yZ> zdI3tT8dkKSOT^`NP%7nzO?7}}M?gQn1G3mvcGY%)-?5^b{o2al3uLrMe-xw}{$ zaFq|W`tvgQY}lNH(cdNJO8e`$%(xW!gIDp7llh17LbCMx9$L!p<0p)zaZ@~p(5G0y zhoO>}dZE;KCo>BaCZR(tCM`m$-@6~aWI!V#kakW%Zpc}dJZ7Le`0__XaF|BFa0>Vc z0Cz#Y4Ce4WKaNG{7t0wcKRt{%RD<$Gz;jrL6m1GhH)r>yi{=fUP?2G>RWbT0-tUn@ zEjRqCQRhXKhv#vTB$x#189Q^@YieJY+|?|vtqynTM{M=>JEO}QrNOa6$7Sl@C?Cx? ziA$dirn#UjS2!M1H@ls3??U;`O6T(;^8!UwaP$_8tOID0_US?whGtky?)MqyJ|+yT z)kH-ytf#D$TXVS18-|gJ(lhZ@*wwTIm_sVr62mx($vZ+A?_ll*KPrtEY$7;|gi#v`=a z>5S0y4^s%BUVn6GwL8Qj%`TdMkV!twUvyr18_)<61%vO|KhB8ZSRcuW=x{ERp6?)@A;pUAq+G8MWFvykDw`l zeb54_|4&Y$--XM6_jmECzX?#9-;E_KbP|HU*+f)-6Rm}Tz*z~+o~BU(wtfl6^-T-j*0=#!=>q^oH`?jk1sg^ zZzyl)VO!WhO?-gAB-*27*d3Ap7>))xDyEBAP4em!MZ04zHvsTuOu!Yy2oZp3{?SwL zvXIlwy&dB#;84l34zHNw?!Js{v6@MPB7!LNuZ|4=>WK5=8R|dCS!Usz-W37e2uJNR z{;j5L1Q9^IjK{#4xWHiqiPs6dpbLqK3Lo&4&H`xz{4xOJ@e}mNfFvS_Y`|OSKy&_R zuldeby0rNp4pZD@#oR-7$?08K$Pe*ork%)ct*fI2JO3{|gM(0mjGp>cu+HIZ~jMz%m4h zzlDx!e;ta8%6=>neQJoC5Q0bqvV{sj`fLFGnSi`N`>_AYJi0q=N#1?QBOScq^`HI% zFY_lN0`>9{_h47rp_-m5eM#NcJp@5>D*$!DM@fo6Q#pXqLNbQ4Kz>WBWoWL}P*H~$ zEWqfv?u)g2@Y>}|a6ms5Z`q5IN3fV2zLDQk|6=eQ*x5Y**9Dxtv^8(gKDf#q9)1-F znXZCF+O)5<_#A&lrM>8Ucbr39RZ%%J&`JOI1cG2MaARp6)q1I9E~zUgLQDCMG9I`SVB`^7YW7Wt2EftLj# zH}`D+99tdv)vqcoIIifWq}U%}zyBi(f4mPgMCs3QV_g!Vmb5ixbkzyE2G~{qZ@dT8 z|2KB~(o5{D|M`n0&ypj9@QlQuS>(&PLO%@01BQM2wod&mmp51HBLZB1=0g69N#lSr zsonok9~-^lGXvV4>fN~Wx050Q_$0Iqd2#_2kn^n(-&ESaHH`(lEd0+&Wl(JFJ$=Pr zHUvhrNKFSwNbu*t&3}US3PuFPX#b0aWd$*QjEo3UMKA;5R(*$8=hn7ktnPrtrBf}V z=5INHRqOY~u7N-Zsnbq zMd;5J1##j7gVr6`W>+?~z-^1K)wZOJ)z>iPc?c0zM%(0H+Vr zaGNKNZ($OWra;jmA0W%(#y2Rov{!hG%L?M27(Jusv~YB%qdaboGy}-D5TQOgLER5D zCBS0(@oEpRQ8Ej>KM!jQS}pgrzWMMIRQIc|f%yY+LlWO1k@TH>jV0EKG$7pJ)2!Bk zm%q119n$6r-XbXYLpW%)oY*s<`TPWVdt;R@-b|6K?h@f%cd%kwx9u|cQLyK!JD zYSKZq(0l|@CqMz2Odzf=OV%PXS*8x^=;hPN2j)!4VnR#?`h`1v?>?f zx_S3&(0&L3k@us<&^Hpah&sWVkz3V_Y+mf zWtm0~h=89+hvp38U#YAD6#?@6?#k)t*GxlzZ%~Z^&IhD1)&^Hu_S;X(lICZ0c(4$Y zIqxDr9b>^sU8DnyUsTBg76RY&Gfd#x3ot;yBKZ10zL0d;B<<%Fx!{BVb0WjT!H<|?a?pxV#k1Ok^R|xHc;Yl-*HM>KJgT8z3V5Y3AH|| zO~5dU35T3v{YO>b!i5q2Ux)8pfI;xblz4jH%NVt-GSh+o86BKUl{w&;{+=7!Xm|t& zWsYC#PI+b*q>9VsC&)mre6Xn!sow3okY0Gdv;HHV^u)L%k!PRdo0VQSCNxgJj|hMK zNqLH#fv5|dOQNBPV$94)boc2F|Cih2M``g~@YjmdcjjI|l!k92j0pGZbTYzV^qa1= zJ0D2&w|KAesbQ7^!51rhLBUj> zt^Uk~h|%}$g`a8ykNx4?fx0uduUUajTy6v5P~knnc^`~k#k~`9p6vCbJuouQeIs{jyXp^ z;h$%-aNGGnWm~`{rKR4R7r3~QR#8t%#+(5hpfm@ zu_BQ5y%EX9f_xl^d%(x>STO`~HuQ5I@+qQ+HiU&0e5bkK?2~VC8=wiwfWlY5k6U!d zUJa}GdhS6m!B3RpqoUz7X&;d~v6;^~Jlloa>YNwoAibc#OOGSuoj;x{-EX zs$6p7Qry*lI|=tE=>2Q3-{!1MT`3X4M%#$w5A^lcGl6Z$E5r`GKe+nXPl9p&Sw&^V{}%b)ho9A38Ha<&$rl`;a^74gqFmt zowjc7${B3ttN1>NmhS~?$PVa;WT5m=6Tiwzz37fbL&iBPRQU`oJ{#2jdP+K^&HfHc z9tcl5G+|&nlN*};aIm>DAs*69OgiHaWh>Oe$^>}X1SCw-z7^-6-Qii9vbT7Xt>dQK zQ=S#ZD#b=~2;fUbh6rx1B9}G$D?@LK&&BW1an`Ki0});G6Ty7(;Ib zO#AE>74OC)JhxD>p+PIy{Zc(j;o zM=I++H%Jrfr1?I1X~bF`=I|)rlE#A3W;M3dC?h=dvwsa&}4-X#p4v~ZKm6_Rp-1es|9WkqL7cQ&h z175aWOCqNo1Jdto%^rFQUn>YLt2vpcWFb79`r~c`H}BG_$Ekv<%KZgZ>0zHAgD06X zzvU7N_2p{%PDD}#I>VrSPbh;%Vi5b>L~i$GG|B)))F^Ia2EPa6@|XX*x2{}b;Nuw^ z96Ui9zaS}G&LUog^Ub7)X8-qVOQuC;(1x~(VdV88mNcEgMA;tdXgn}0NY)a|fM@u& zJt;}QfrC&?jGu5vh>4bGS@v}doK^G&L0@&~NID~6R+6bN4!tWn42>HKTh)k5jJ}pr zv7}1zm%l@Oks21p^<(?U<|nAd?IOHQ((eO0SQ@c)L0kG#$V$Ripkw-xJ|hYfMYoIA z7jvzlxu`3Gl77w?wbMtRI5Xw59kJ>MeWu?xGrMC~Pw-Ef+7EV#cKJ)jPd#A>|K4>m zJB%8YYiBU~B{NUOepPH_b$9kWlUpQ}^Kk#-{jH?EX}RcwM&f;SMdXw;TsKiZaWAe1 zc}KDgH1S_c=`#k4gJF9~KPV(9Ok1%iJ-rdzdGog2d3&U}^Wp&eq=>=%ZP?a@stf;WEdHgAgg#ZQuise-6U;h6 z>piWgIx!9~T^~30+i8yTZ#mrGG`UW`9q@Stmw%k~VvJdiqlACXM~%*HN>;@4reY({ zu0F*+I-7->l3XBdxbXtN5D`zz(YSW|98&s3n!~U4fl&>Sq8*{$g89Q})0Z~{2GAH6 zuk5+6sb0;jsrBqK?Ff=>?UNL!UGi~FuutvfR=pJ^)lJMe{8sDn<1frx_@Cs(W15eF zz!-1aY#whOeF@vph|}#& z$~8Ui#clL)mZh==hY%y(XmHY3!6Lf79EkhcQAFQpt%Qm=ykR4bbF+ZH+mMi!ZCUZJ z#Ieex#+4i5>PW*d1P*f9+Mp(oI1B`y($-%To~6p}CoI2uXi1LSySdQxU15+?mJSCh zST51&(|lALQ>sKrh~lVeUcawH`XV88l{Za%L`Jxs;LcV&Yn3Yn+7xv)0k&!F{TKud zFh;a67`>i-J#_}A>z*#Pw$MG5qh%}GfOKV(5n3fs;cdb;wUUksnY_Cz&+lxXxHN=1 zd-tvc5)VIIBO0bwp)IA{SlVO6TRO`N&k$ivp;bY&i0z~FR+GcH5G|lrJC>0WfuWGbRva z>BW8i(P2g&{))ItnFvyY^Va<1-!{`|;KF0q3mcgI`bV0rIH8{B@b#eZwU1=^BG*wz) zM9Ze=;~cF<4_B$<*F^}#DrZ+kU^MZb9h&re`P6xA$L06?(*hd0Q(c7|W35FyCwEz9 z=0GfuxP%@fMhUUkEmGS?lLiM(OLt}}%xGaQXS zLB^Tu+Wn9E?vfYt7N-Z|S`+F>jR-4(cgR9bn=6G|DLfe%>QFR1jIVK-?wo0Fh;*J9 zAOMZ&VGVFu7#rBD3HVedr_3!Hs_3PV2s3krboj-$4noCsNOpwan5lZ4KRJHEp zeZoO;WqBe@g{*jT^ME%yLTFtIcL;xuqG0p&(^V@c+Z66I0jdG<#A_85Jy219s%vix zz0)0vW&r1En=gPdY~1(zAU9oajnvio*OJco>o8H-ydjjxJnng ziwBzq=nO-?Z8b9tzdZx=*B8K~vxS|I8Q-kHZiuw@iB$aAo>y1+phTgV>V9-qQkw*? zaf5fm09aPZ2vsImUCGO8Of5W8xbsXdt#d;6vD;Yw98ZeSrmC*+EtNMmu-hf;eki;7 zB4bX-zx_}#Z9#VxMm)dV#I&i{gq($N2a!^&<4+aZHp#@h&N@H0hbS~!Ah}Axcg6HS z;*uWi)9&b}E=(W|dOw2S+01@vg}3WuO((tPbrSsvQnkP91k~9~o!lw=s-#J{L*CZR z#{{AKhRqd$@{yWl3=-dcr}(^2pCs()I`Z#+euj$umHB&wzh3%^G17uv(%SUV;xj_I zqIL$j5 zN*rM>3Deu;`uf0l-gs_~GuN@0y_8NpG8z+zkJomq%OZbrHaC^s~jA#$QAP^jN3H9R{$Y zD7{@3ZPck*-Q%O*I?+FT1I6(?neK1nld08+p=o)K?V2em|D4Zs`c)Mu8JOO)nKP&W_~7z6W-cpiAkU>y5t_nncm zPiwxZUB$$U7#GjkkO)N`p_H-d%(xHf&tdhIUoq!X0wi0-HW*rd2NcNJGQJN_hPrD zTao*lVnH{-vS%fOW&?}cr?a0_2HxJobJ3;6^N8B(J>aK2Eth}1r5lBGLjw2ihD~M3 z6{PMVlSKlm(C{e)O27p1}H9RUQC|t z!d>#mu5P2I0>!$AFfwx3D5X$}^ON23se(TJs3Gr{T2i|a>JHbCNjy;;M0J|cORB=& z-D0vb^E+HPHNYU zI4mcGNw`2AlhC0R6HVL&TEpAHHSuB51X z@9|(WvKh^Q9}uZP$q~iZ-r>STN2K>qdq#vDsfVU3qxKm|Wr5`ouQRI|rV*9JnV6jh zsZgI6MK8HzvzFcZ4@)l2fg+c&JnkV-$JMYp0GR?&B4qZ7SbN9`ps5fAlb2T>u63%m zOd>IcZf6WpyM`P+A_5x$xD%A^k{n4>$F+L%_#B_kjDQ%V0Zd~pMk_d{FIxuHVu){v zoU&;*Y`Rtl`cN0svg=lrZjnD5rhZlL2xOhmZUtg{rM!p{%(zw4ymyCh3a-}Ev&aJkw%Eee}ZF}s!Pz*)@~=ekmT z^~jlw&f{7K&P;eOA1hnjza2rmGLU^BgS2^&epLEGYT&zCJyO&G6c*1<%0xL$lY;}< z;vZ$^M8e+fOHr?mP^FTN{7%aP*dstO6Vco~{@#E!#O9t`@O`VY-k+fF<0Na0Tzz8x z;|Tu!J@Qyg17F(X44i$9@bztA_IGV@gI8BXnJ4j_KCaRpa|D3*mzn?A63V70e`o;j zQsz%gSZaFA?~dhu0``bX!}64M4S80hRaXEK*mJ@&*>I7~5Oiw3t+Ixf5tYk%P!Fti zHbFFy1$f~zmxwfpLPdO|#d-d>nVUcmYmnvVv02@(305h$Su+(LLZ1@`6Fp&X4PtjBQx3DQH7W8R;6J0+4GBwX=&WfW{r;yyBi&p zHs=(F3g67Ctq}LSsx@gH5IxU5uulO$&UDC&U-km{lV-6un{Js7g>1;gJaIOCqO3M+ zD$YvhSUlrw5A4w#nxpxk5Tfhxhjn#zI`{QEF=Fb#iR6ae6RU+cqb3a+gJHWJ_j{4i zB6JmI6Z2@~Y6DF5Pm1AqpI2wH!=@JIgzM@;@9#Ij>)Q?_^O57u3q2!JxVELR<9ZMu zJ~(|je)riW3}%~Q*@ofSGWguRbo~tldMJ>w7E&~)z01+!2B?6eqY2GGFJQQIN{yB z^+WWfydooSU$F%CO5V*_9$nWfyeSBbEj_c)cC{fZfd0x)m}p?}phHO{fX*5kpymnL z|4^cJxww;En9BgZnU2e{m1u5VHzCfumnuGq#$CIH#t0~57jm*GplBB5hd zDU>!9*HDbZ?m)7n=tfQ|b6GV+o4vE#f)h`8H9nia7yR^odZT`>se$*sspStbi$@Sd z&Et1&ItWsscU2*2uYQ6&>1}q8k)_>E!m9uWy-KD`?aAaltS14yS_N-T;YziRajRV*`bMF3ank-Vn=At5Gi-?wqF{OzZweRG zsDoo*4btM5esp2ahu^VEA29;a%wX4W=5_2u@Un$|dQV1K)^(8uDrc}!q zr30Tx5IkHX?ybNN=!d0AB2U*lk1r0A#D9V=uURdRi-nXPJKf&YNQ(=T<-9v7Onl~Y zX+h;%nEjE{*qBtzeGD+fz=}1v-mg0*S->vO?IhfLb#jWkZy)FA+eORiG6(~XrxTeC zA1Id22`TZa07dC$wM>3li9IL8w$}HRDy^^bWVhw!GDirve0`>JE0Z0;UXfoP6?1(o z%Z8mbxXY@9BjspMYMS<@?)suYF~U`%F%7H`%8Vr@^2&xX!P8N`P%vs)SY*g{tb$|i zfqa;*R)KiIAEEh04ajv2a2E2q1m_|!R^*h7Q6SAnB>HR_&0ygzzOi@1G9Jhi z>4=)=B*)WCyJ6}P-dw|(wxGn62szO91SEw2V75QtMfJBYZ=+SzCC`Ok55i?*0s)15 zIs=t}(A)kda`)wf;ddPaj;2_Z%xjKRQ>)m4^(xaq0-4za+AcBo%79sN`Stkz!2%(aP%tg`in37=j|xIFi@!v{>=UYON?BA?d{{-PK@acmOzAuk9=+Gb#=VNakyOw-E=TaL;GmB5O!#Pn@o$N{tzd#67#h}kP zSjrr(FTXp>?_H(lK|d%hd+gY%rgP4yBYdO1;qW%!Wh81-4Oi4OqK9WUNUcYQmuts} zzGWiYIxM%eaH%UY!E|eIdk=k6bN`{&M-eOrqoAgw@`QW5WuY9~^;B9gUS$kCp79OZ zRn2Tu5d%{!-HJLOEFdWbIW?N7X2^OM7Hryi^E?+UhLf;l4yXVRvM?fIRu6a%&$8Y9 zo_zNW01w5F@KI;hU!dPi=s%)eK)#y;qUwNpr`(S{U$3cr_D46Ks^$liEZCHDl#V68 zS2gvb;*EMS@r}fwYB1&W1PCg;Ls=>*GV8)wia1nIGRS44#=2@(u&b8t~OR?QCQE9Xjn#5GtTTbTem#2d2*^rQe~={^J)G zNSz1x2Dc7@tpT7bYX28=?;THt7ypkZ-N>w5gbC5s9u%_Q=f0-jtD0ks0BN z?44{9l9iQ_EqjxhdHv44lHQ;1=lA>l@%!iZPmg=U+0QgSH1`07}1_vhM(%nk1celkdBL zT~5CEpQJq@US3u~`Gp>x@$CVBGAz=^X2EBZ>d#uq!5mnJ)mc8BcA&Pdg*>p2IX!1N zI44x`EEtd6yy|nZ_kY*`enas8)9kZHXKXD~(g5az;j_#(8pnYTi2c&3IdBHQpabge ze&GI)w1nK@&_@a11J&;HxnRWn$p|d5@oT-{cRm?|{GZ)bwM!bS{*AAynE8BXvG*bpV()M0@R&q6_6=LPyeV@hR~zGl2#JO0ebe&f{5j| ze~D3&{tVQP_vj4w$&O+rTbz4@0{^T()KfFZcS7ALh`;c(Q|f4k+(Qq~haL}C_OZ4U z+oTZNVMALCRELdo`#90qMyBh?j+H_V75V#U|8%lL02Lym8LQGGEkZ zLId4C=D@vIUyklfcWApIKtZ;$hrQ z7(0ZJg8_i?Yc2ZAnB`D-KzS!4m89!x57S+MxTV1nRDBNYL;q)gosY!`IE0eVFARyP z|K|?aDwR0bRTU9FOCX2=pE>B_vk3)xJLtocqTRv9USdV46QLAZH+7m@wjhu zU*o!l`6wd7dB?)a(Zrtfj+LRKiIj=4?L!kzc@rBmNAqg}+`IxX7$M%teAoDDQ3Z#q z0(mYPyJDMmri+=qH{Kq;mdkAUFkyAexi4sW#IHKAkUzS(@TQrFoO9`DhlkiC^#;`_ zbD+$VYv~?w*E~$!r S@4}Xdjt0gt)SOOE&Uq(Ds3};AFn<0YQ3ucf~s$N$WK*= z2cg|DN2n?huTNzapC06Z9{|6vKU}R_ui>M|!4Z>PRJ3$3VYl5{k0Y)3xh5@BTK!=~ zZ+Z9wm6j@|qTcm!znUZFO1GV#2h;U9>4 zosUI`4HBh}=nZ>kV^scZZr5s1;vpCRb&0vEoVph|X^eeS^zy8MeO>`=@o^b!8+XnN zN7m+81{}`sg0~)Oq^tuG^FhUi%@avV0blNr8QE8uB$T#!@hg+Nk@h_-jgq*JC~MpD z;{Oo-mFOlFb8GX3AM~8Q-$n1RK8n()t?ifDdfH@Qc&S{LrrE>N_uJvb*W1W)Vk9R+N~i84=_3MeMcdMbeoX zuA{fjnTre>wRxWB9Nwk2IJrj8_m7dcHqWy}v3}Jr)9XNdR#Z^<0Cj5%i`UCbozEY4 zTQ0*^ePl6_W}!V#FS+5nMyRzRFTfzw`aZ9AJ4oGExa4WaeWc{l&eEC-`Gdj>xH8p` zsMJlYN7WBq6^%93HRw45d56|5Z;NG`(ayR%yI}k1CbS{sc4*Sdr)72?<6P=d+fE6} zXc-s~CkrfOq`dC(tn%G3acXL<1s=)%rMNv)Q_4)U{LycW4D4+p*}bC0D#7$Izi+BC zcj{gsq1vksyv)n}uBCs4 zUU4bm{ogvIVGWVK-W;>0d%F1sOW1jwKNV~IXlbwAYHP1O|5?PF&}UdDZWTO`b+t}b zKc_ba=d3C}Yd(eLCLHbh!f%*}o#MrdQd)75niP%k8xC8%ugD%cC+MF2Y#${m>4(+v zBMp+wBXNn4-}J)E-E*sxvmN-dTW9aD8#BF<+*%B}dW9{wGPBZiYd66u7cP@45Wj<}b#XGt8G26;4s$GP|^d$?sJ zdp};J8yhpnB@t0a8e}-#sZT+DS#zPoMw-`8E(YWvDA7b!TD`|fJBy&&Ymwoah9bg&kkmOgu}t-%tjPqICF zvA4MJA{BSa!Q&eeOF3L+s#mlrsiJg~9@^Rxelz>Xc>6x8p)gKEjm~A7{g-P{^*B*m zBc-U{(Fc`ZU%g*(6^=4LFqX72U@1j43*m2-WGaN`K&w9U@tH)l)LSb*VGMr9!cLc6 z+(vTlT*As^;E;w2)uRV972{>Hckj^lYQ;dNlvca6a4yiaX$5BP>U4j-s*`79E9Pfr zqx%~2BC*-aK}qAM9JdZNlmRERI85*pV~`}hQqg5G7n+EWS92*LuMA4wi=-Es2zcM} z!rxx1U$xn;tT_L2>w5HcC)$BJt!-yxArjszDi1BIbw>I#R`3#)n|2z6{RG`6Lzf`W zfAUs+{7f+-6dHjeU-9I|g>L`IuFO}Kj#7l2!zo=CE{nu7K28Rk43+0z+Q3_rv%~$2b>H zPTgxgcMGg}Je(=ZDLKBo+#ZUl@3jX`F$uS%9ugS28x^sofdui(1&yapjiOGbnFq z=XU)Hf*jtnYf_zruw8R~J7;YD$M1M=&M?2kDe0#8Hn~a3>vB#)+>x*o#x{mvSMB<| zV)*RW6!o1rqHh1p@$;9Jddr?p4J=QO#AF5y?ZjDFHeJ!mlB2M%Q;I6^5&Ins?pGcaRN=BztP?k!c4`kDJK^?NR?kf65g zDk~nf>Eb2)d}F+T`R(9q3dk@*;|Tv7T9NBLUzHS}`CCZG##|c7csE9#Vj+FAUp4!d zt}=1Vd#fzct2+(p)0Czb@xB_&7oztcH@-K3G!EkqvG8%9#Zim=VK8(JVMr>Z*vj?v zj+5qX`ZPaE^5>4`rWZ{{<>v}VWi6qG>aSn9YO2q+woX&KvOL=-!m; z)Y08YrLxg*S{Oy7KOL&uC3?Ndg?3VU%PXvg4OoUyf&c1@glT+uC=DdOpY}6@qUcu)Zv}@e0h96Vaz$Ey$Xreo6n0 zrSlT8OTXEh%jM6m^0aR~NUVpwFypu$(U~zC()#31Ysu$xU84-Lw~aFbo~X$Q1VS&8 z`jakPYc{2SsERCRG%R|+7ieG*uV~gNjb>;XnxPHrqNdF&usoHxN52i9BdnM5%Rb=F z-1<0Qa|3x?A^N)s@(!`SoA^s-~zA$S(E6Z}ZwK{&NFq zOCk^PrD=Ft69c11-rV?%R4w!Dx}>f29QGb(Eg3t^`g=R+N5!vPjr|*+WqZ%!lxI64 zE8lI3$f~;koV6+|@+Rs?z>cPN;rUE`^$lc}xh?@G$bQz8A78qN61}Fb8S`g-3#dk^ z*NDyZq=>9cY5nHQqAs!)g48>Ab~ZZ0XYM>9T1%IHYG@+mO>=`q%q&Q@65_AQ=0T$w z{*IGk1?0dnde_?CT-5vVF!Fml*UOfy!OJW1T-wp!+NI31BJl{<&Sz>n=3<%ty1hTK z_JA8lu}&5za5R~Z8ebT7F{KEXim1!npDV7byjIgvoa~EiieTII7fiasFC^kF-gw^i zvWoA{T>f`sKCP^*f@>oN^S89mD@oA$IpJ8AJh{v5-{oW*efLL$X1I29?FS3G!$-5% z-%*6VmyhR}D12X{7M*+U(sEH;F^-ZB*~1{7`(GG_q@WhgQ>hKqq<2%sdDU;Fe0_|f zcqQ>Lf4Mou-q~T%#rkL5bltM&PNR4{4A7WK{)a)SY+Px{8AK@gDgk7Z8;O7BqFy z1y9ZW`aa<-o!%w&`+HOL+Z4^j=Xb&d3~m#b@@m>W&C#O?eotz#_#+4$*TQ47a;5{Kzs9p2<_;+ z1Fp&BAfLUOE7h|fRnBEEwePZd`rD|SCm5?Af)OR%ApG^}>;nI&$=#}1owNA$ zSD$EGT8qbwpBWQwC4#_~jn-Pdo(Ej`QXRN-8;iI+?hOh zRC~9Z>dcMKKstWsuqTwI207u$uCfrNE8(`G(ZjxUF1rH({ghybH6H?@AcnU5y@EB>!nhD8V44>$rzk>N#3hluUJhUY4(zJVu#fdvK(9 z(f9Jb$iANIEz?H3mt4cS)m-H#l(1$B*5In+Y1Fk!3OH&N5&19gz6hC>`FZ!edTkdM zN5NnSTY!3H@V5Y}ino%lnqPzrHC~f@rcvoqRNoZ$+G1{*jgS1Cc}#yEiE~WI80b5% zV7RiIWPvccWi_a#%5kNWqd9Nl&Wn%{^qO3Tqq}EJIkj&258Ra(#Zo=Im}YfuIKDZ6 z>!wag-Yq(U3RmpLzIQ(*uGD?FVCZgMwYqrQP~wWjq~seI*(^2SGp?kjCvJEB#Gx5k zNC)y-v;uCo{Rm$=f_DS{T%vrV_-5s6g$33T_=bC$@yK?b$vugIDfTVM&5hc+ zwV85V(K%nin>LC+Qw+Y>=mOmzql^VH`4Y z4Y%_%EVx2i;Yjq`{^=Jw&(E(rGgwj1cJ(v@!y)$CRFZXyG$eJJan~iTtUPJEBGoKT zpChIf;AZ^ZG@|UHpeMv^OL9$`=#2L> z3_^F{t7AF<`>z-Q_CM=aQ*94Qh9v~kv2aLHKV_tl^mm&D%b5>cF=FK2I;UvUaM5I5 zW$fLRI>844!JK|piUr*M4VU%L&p)nfxJahpNO7a?MF<^R^c;`uxe#7lvU{Es?|;01 zOkmjcB?eAET$U$g9n9`0^~TPt_FA?vx4%z&<3%c{6~U#yOf@oke$3L`D-y+*H64UQ z*CnFkU)~+AB5RCXA0xeLOhse3tb46iaMj~78H6m{0GDyZC3&HgqTxoPHSLu^mgzcP z_BTBNV=>b96E0*tv3KYfof#V*erqU8;Yz*g_U!1=tAkIDxvVvn!#SMtsv~z&-wc=i zw1=ie3e!&c#0%GO8ZLIOvI)i=J7knidWxw!y&OY#RiOpeqa>{LF)7~Nc zQdh6ex!Xi)EyZS9pDVWaBP3_N&7Qt?nRFLiCJSy3389fOl)DZ7yL66U4JW_jnhS|K z0@uE^fs+MENmRb`RohaT%x`3d0Svv34Av8ZNu6xv{}!IG5(1 zW`vAcEB7~)nqTICb-WBEvwoWlJ`ij{dXwl6?x%maD$!%0hA(u`r~UE@wnSbUBq&eR z+I5X8vIYLF@ZB`gmesotdNDv;%1(nTx6Gsb&ZKqU68c;c&?3Z2#!?YSYMY1?d@FR1 z7cL!BJuw9`zWBG~?5dt#IgASB3LV%^@0qbPmOdK2o4~hN+jdJb-;dX2u=}b$Jkhox z-Zk^mk8*Iey;rDvSn@q(m6Y+U2Tf};MdpG|#t22%KF`?^n5LO-Y^^Gxz-5i{&%rTg ziE?Kz5>k#(y9)P&;m|?%NDOI+DqqUs%&Uo1=PQ_5waaZ}dwQm|aq>n7uOGPhiU*n}DdK zi+=H$^;PqwQTNF_rlfnj@j}b|VTMjZiW6^aUQG24;387K1#ENHv1Sfg$F(cmH=bLM zsTLfB-#w&$RHTz1!^-yD0qb_zw7cCQx08}m%Jw)X^gS7+ZuBAlgS|_GqRF|D=l$z{ zwTjx%JtcKYW0#%fY2)bpOrz<3j=C!Rv)<(a!xxplMfEyOPIl`Is9U9v&+l$@MvLK7 z-&U<@(Eq9EzhW-ORf0bD5>#nhXr@lIshWop)$xXH%Q=^QzqESYBi`$Y z5^7&YI|zG4Q?EkkJlSSu+xR@3TI#?GpQmD7sx;dQ>%R5`%}o6uJ7Lw;lKlbu`_n>8 zx+?`qKedq6v7*?8IX_enm*2-7mVD_>T3jO5NPSq|!m-@tA_)I*2`Xp)bXvRs7uV{N z%H~zPFXM!3)#2fc{A%L0jhZb{k7;D+&)+jwFd4VW)9;srero9(f|QIz^VP-`m5jI+ ziXEK!w8pG$Zi#pmu-3m2H@Ty^-sNO2^zQX~E~~ce7OKElJpX~|{rtBdlG1#ribo4w zt}n4hpI_wTd2yeeEaRTx5|w0|I$zOE`=9>p5Y>Wgvk+3;hbnuU$bMt1Vx^(#SE<#? zaOU|!$Y(2s;9_d8n^-|Fm3DXN4Oc5v2a43J~(Y2+LjXRD#wJU{6g z61rTaSaEf=t(s(B7gKKx_x*CgK^w2B_H3{|`*2x9c)p%e3B|xjnqZsR&yDSnN=+ZC zkKINdUUZ{cvc-?B{gkxKg-7d=X>A7TYcxt^UZcf$IZV&BVE?y|Xi4U$I=# ze~7T-mZmfB*?828^b-M+GtGa5LD*%?dLd!5u{1-FuZi`SU#5^C zi>-%`3Yi{UnnWvKvSKPD3%VtENv=n!2C&e@l59+}}!yJMf~5bx@}#VHCdL zj60O<6Pr(BQtc@?_o`@a_8a-r`aKQJWUmXPpK=~qw_0?(oQlc5M@4qEzWJHl=i-St z$^mtw2<%rZsWwJf9Hkmo(6pYY6p7fUpENFKtZ;s+57(k@L6uEeM`>7DHqH`@yjqre zj-b@y8z*?t!Bb%V`~g$Fit@|LU1S9xgq~ddX;@|zWitdXj%0eisEzxb)sctkVz=Q} zGMf3d$)_TPZN`u;bAN*wz{_qls66bEP5N^(&2USi_DmsGW`qplm779%+Fl-BgoTdAn@ zO6}(=s@J0w!t6C=_sMQqWRJMvGZaH}GH8?F0)}^a1I?%TnD~V^al^`_#q~U1HjdU! zNiOix-XW-Nr_>E*&?onsdp6DcAufn1SogsNn>8CEl_;ioZr>`XRsM&H3t)&R3(?`sC@0o^|UBXA)EVg zT>8ZR=7BezG(|7cO|6JL`#8Y#xShB&E#FI{J1lW?+OvL>&oJ|;@VcB?=7ig3724yHlq)};iUJQSFp}sSc zG5m?(EZjx7nAI(^)1;z5M?AI3SW-VF#L&IPoSv{KhzR`MrYKcA)}EiH5H!oX`6amDerKB^fuE~V*K zpQf~@q+c?o*ktAGol*2maW$^nY<#b8&OP2GejQ_n!o5*T`{1DfLyolR?sank7QQGI z++RN^$G;3nK8L#W9bAm$7PEd>c@c|53IFOqde5R;t(RQ&tC-RBhchH5smdCK)^dES z&=s!6pGkLm4I;0W7+x1=qA-R}m=ehcnO|LW@{5UnhX3*j#bN=hiY-R`R=hMDH9VD# zx<6b(c>AY;q~?c*4Y!s8R`zdR>Cpf7{gP_k_t-UyWc-P|p3Wb>!w-bXNE7{n?sY)I z$XHAkUp&pK`sMGY7BEosjEzIY_bzUz(fel~MC^=l&Sz~MsHy4Q&AWxK^?}Kch@m}c zW75L>eNFOHTxgSwBmk$2pM8qA}GO5 zE>M2Yg7{d=`v{)(vR|=*G&xH~%_$Ql_G_(d&Lb>CN_@O1Uc{8fFk5$TXYffnyI0cgUSCxU6PyUwgAt63zJJDN1<0| z4g1HB=%t^M9r}K?z@MdxPm;nDc&t-$pFk@}h2j&F>HPbroUQ~W`GbjH8UY8;g~H66H1>rGc74px!SlDZUvQ8Ci23-e!8@EBgCj zHh)=UXq(Bv4S94h%c=hfe9!dFZ2O}qUXlUrVQ+V6g6IIc8!z}K6I0T=Qjzr%0kH#7 z>(H~&=}DTtzGvfHS9Uvmz?*mIEfTlLd+@?@5D4E|m%b=9ev1^%w6Y=_9FC<>HT}A@ z!I$T?OgR*KPf_vn_bg@+5;v#%ghw7FggVtv*D}7%7 zI=N=fXXycjnz|r{QqJI|C7n65eGiUxW+}$^?3sQ}2;@wGJ|5l~gBmFG%x7 znVFI>?CR06!{fAJSYJ39XPGA$KrTSy=7fiL%oBc%__~m{K~+LP#W3v3dYcFoLI8;D zn325-i1FB_w?K}^1TUne0~KjYJt38M0j(sb8{F{%+NGCpGQBMWJw03Hgno-mw3hPz zp=WZMsdto8f`i*hf`{kM z2JMM!KUj#-^PI-#IK-+?O-gF)Q&Qwap;iyuyO3ocw^nx67C2D{Ej1AF-^@&Ng;C_H z@f4mY0pxS!=>9tEyOg?;!PT>!USKh+X$Yy2#cTvE(tEmNtjxt?aYP{hV8ycLl6d2v zsn1h2YBndng& zYmEJokDBQ4*}EQ^`-{r@$<{H$iWuC!3a$8M*|_a(2&^T-?_qi12OE)Q3miM~^5@Dk&|M6byKdw_j>A zf(Idm5eh%rb4HI*RAdHPV(x{Z={tGNPQyI8q*TIf2ZohKu?oA%JMuZPhYL3}eyft_ z*J-Hj8=B1=5QP0Z&pR_g$jNf1;i3p#_Jnu;1)MKw!NR@XA_g8F!b^c0UqUqA<=2I1 z}&r(C+@hZ55o7!~<0g25PCL4_82x zs@V*eaf^n;aAv4@)NwXuYvezBo<$z%vdyie_yCVZ8qJ%nYS&(>wUx0N+HGSMHS)A| z2)|cj&lJ_{xyjz#qzdK)Iu%8VKVyrNBw!6DNm-S(=^DIEJj&}7!7#{8EqqU90s zV3Z_0747Yv@-rwTn56DkSwekTmNZtg@N2fvI}pFEq$LU|4GH8V7$G%gKCtLDFl@}f z4^@5UE2jjcoVXw{|F;1=<;%v&F7uvkCLuX^>e7mZ2UNTk3f+9;dsdSK0ucqSw@(TV z4`pV0!jINhJUj!1|8zfb_L?rvzbfW6(WNhR$>X{e2uiz>wBGub9;+Rw9bTVb13d$J z9?QiehgU)y9XcG2P=_g+ zjBP8}`gDIPso7YmiJ|PEMUB&X8;K>lFJzXBDG54kZ20@`mHQmwk5Hi3@b2I(qETI( zobPd4fb@nUvv=JRT_=J@+!o5rlIY(2*dqXKI?r4u0nNeG^xOl zo;|37J_@hbVt<1ee-rzl3VAS>;^VlnTM}4v5gja!c~=1A-Q8>>_R?Th`p5}5$9$|| z1`6lH5hM`l-IHNN_08!)zR8|{M5S2{pYE1|E5RU9?~;_E(44-`b&KRACgdLlS2usM z%crCmiGZ6hWk4a2Y@TnPaZF4t>BoBJ8+FAB26#UGM@8TclI{O4Z*KncKhqVO{_WL_ z^9;s>HjH}J+E1xSqa)%mC2Vk*f{J3~Nl5Ba!ecQ(N8BgjP3aWCr^&;ySm}_!Bcs(J zE&|~I92qxo?>CU(7?|(E5P!zqi$J&?&uD#(Abt-#DG2-Lc0b|*_T}K9w*$e8dEEkz ziOnKFhe33n2}gv0{qO%dxYN3Y{y(%5?0(e$hs$xETE6HIeysl)P3hB2=s=CJMPFGM zyTa+Y@I9fm$LG^PKso%8o$xuL$kG%AW*57#Yn zF--KW4M!}dVHidb;W>B)V{`^!D^n&6w8S!4t)tBiZf2J5}G!XP%ZJrySga!-_H4(XlRwUPBJ1qO+W1HhphS z?>jwPviW)@{;6n`ICeiWn3Z-=3wm-D_l9cx6`}OIsqVch)Ys|+^1Q(1p54aKcoE9q z_09*ILBA{xT~BF=l!aN}ISlT8XRN(d|Ifl#cRzAF;4e%ImzwFRo-X@fs+)oOw%g{; zJc;Sroai6*g}g?*CC|#N2ozcB5WRCM{?sr;!aql$Z%QxGao=l}Y%F<&gsrV74CTSQ zG)@wRSIUaal^%mMkSQ=MegsCoJ`d=wZ~Osb_|%lrZ+LAd6BARUr)AgEdK^hXg>4(= ze7#KCV}XHV6lX7_W+f3(4^`}bU-@Q;u>rW;C(DYz?5jlr`{1U0ES2k__sVej}r{^gtg1qEdGn|{# zmA^Dre*1^RWX>nz6lA2>OMGhW(yUV| zmlmp_aV&b_acCv}vwT|wA~hrJS2E!LEG4x1{jq@?)laFw0h6wTqotD#X|8YFGd$Jw z{u{fh@sET%zHT)GjT8EPYyBVpd+QF2bQYsg<-6Z)4!KUX(CV2d3tFt{wEpDed>KHf zf5{*WLj>UMLc`~Q$_eNXz9c4hCJfe7K916bHtU(@Ylkj{Dawuic#GUAl`aWbz~f-s zT724B7}ORx`7u`!nwNL1Lz7dWsx2#tAnzAzPX8WYDP+HH?n$r5|5` %J17T)REk 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

      GLP?q$Pfhn*E{I^ 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 z zUeYhZuPTZNjgB^V@QT0gCXn7=Oj~@vmkZ}7=XXgn5V6MfCe=_6QPE5Cd7iS*VXt%l zN=P@I3HH?|pBbG{w9W5`?q>zI&~Z3?5kE_Ur-*VLKWw7Ze0mFcI7(*WomuML8pOJy ze|R~|E%EgB&VB@sBU&Onit_qZeblg979*4{Jvv;@C^3ZP1{L5ySJA4VP zE%~DPL@H$F{HdtKHZXr(FTkuUu{$YJkefff;W_)eCb zN$@2`2ezEXOXLvz?_Nwf>pvlL?01lM%1G>Gkv-H}!{I#entY?!h2VHgeIwu@nZBt{ z%iG23v}=Eb31I>2ftH0>ux$s1KafBGs(iFp24pG=+fyAX{x2SO|99g>e|6xPX-*&l>zR z;8;u4oha8@n5J4ppYw1bl&_0xYhdi#Oq==cM1l^bc09!C<}X$!>m*1w5Ya Q;vVs^;|Xf8W$AcU4` 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

      l)<(( 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

      !gB=irQGPnED@mpI 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%0D5VCaDC5yO^PT=Js!peI>c`kBIA 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%0Dw0lJj`vr6lPsRTI63sNpO`xPOVp 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%0DW2TN}hQs?82T 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π`t!BtE45X?lo|-3TY>Zb4;zEh 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�{l=4gO~7X&5oS5}h%`6SY@ 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

      8YXq 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�<(*T7?Xj~-y!1i*XzX~pUS;@Pj+_7t-V;vrAJFAM@J>c>-4~Hg`{3pzh!bqii zLuTT_)p!y)BG?NIS?J53C$DJpSR(l|zMz2yGET&U zwS(ngz0mm0QXwe#_fi2tz<<9~#OdaS7zk4BoZGEZxZ)o{R->(v0-iadag=*z_yL&% z!FP;qbDQeP#4w=jda{YyEr2N(HTTkM9_Q3J#kU#fX?D;y<7qk}0<3}|fCR>dc=Jn4 z0By>cH2OkJG8QSQASL{u#mp}(X!$U^U2g*CiP;TX+S2&r)h+D|$j`VBIgGfFoJaj? zDacRvo!`H#=VPq!(Tm;Dv{+~>Ho60vTjU7ZO!)+IP<3IjD`@b)7VBE!p;kAl9Na|j zXP&@xxEL zta;8^4|-6o#D3WcikiOTMb}w1ADxz^Xv5Z8bav*|DWbOSwTN7&-KuW3mrmz4YZxYN zHtzP)R;)x_NPLU7I9;r#Q9;DsT4}M0QovFg=gCNhIfwOJsF!STm(Es$&?@S4#+t@G z_F9_^-9qSLr|zD(9RgxGs+)Y|%SRJLwjVe>Zbe#$>WWW}V$TCnJrsraBu2!|Wp!#K z%{X;;Yhj}ImMZ@8;7&_SuYmjd!o64n87I=zH9}l>fMluMni~TDnAr;Sob23rG2*j|(qK z7K0XuHb=@`N*cKFiJgBE*jo2_)Nb(=>8DP7<*Z*1ZDe-hhZ3~A+x|#Lhp3?r6a6p;jkvhy z=EnMEH8taTuPsWm!Rulo;+|#R=_zh@%a7lPm%l#IG+lY^(AA?#5?$VBz4#6bbELDG zr5%+y3cper@dx6`8Q#;{OseE1uOI`O>Ht2xOK97~f| zU!&}s4JXzm@X#3AehHA$VJaDYf35)@Ty9RMmGt!Du`aH3SqTA(XE)S?y}G3uuDw(b z^$FnBLMO0Mp3_TzBPm1ga1mvHGF|Dq;o+$>>d|*fj&^c9<-0qm#;i2u@Nhy!*u3|K zaOBf~r&IFU!kGaIkJ+ zYrgOk`0`<$OufqTb0N;;Ws?eng(4wRxAz>LmsvZnNDZs>t-NkW`c=BwJzp~qxqKKe zREm!bDWTm_yK{(aSq=#M#SF~<|1krT#>%%Z>u@ma|1tr`ybfVPP~9_@!Gq3t%2e8n z2gdPQn%2vl7z+~~zWuT4_3J=XO{Ug4s#~I2_f0~l3|HP{f&H=&BDQ)cK#g{NqfaJH zXfRKC-|lPLf;}|xq9HC0Wg4>OB}zV{F6Y)QEyNHjs|PrG$m8U{`6 zax^@wfEn`N(n}|YwE5Th-n@~-RU5#T!Xi77ay++J7p6a>D@}S#x-mc&+e&}MPChUc z0ju?G>d9Wv>nWs)b=-!avtigb2B&q&V%k~zn`YG4C4@VJuT_mso^li`wO(m{k}}*P z95nZq-*vP_xL?!(y=MLL3eyJ@bci{)x+ne0a(wZ$fiR18xQ~Mpi$PC1&EqfBgxk6L zK^XuGa6M;UoqwI(6HzUlK+3=`?wqngo8%KO3Rz_%r>suRYT~{9n~<%EzF5ZE`iF*e zsn1KPIU)0~KQ7@4B*xp#y<-xaVa3M+Va4_z&ArJV3|j6e#ob;4%1_- zRe)G{3)oWi-Db7Rm(aqs9k&(ZJs{Tnub~IqSrJ%z{=X2}Uj1B%a1iI-&fjML?8 z72QRJuhne3B{k^g8*Vsu&6S{TFbCWvybp`5ad#l6{R8EK9~2q%tUukrzdq91K&g6L z+~e{kpeIUt(ZIva&1HRKW#7~I(&Y;G-M#K2@x9HZ`Mx4?35>+X2K8JfvqH{P2*8Z_hP+0*jZ9{F61S zFy|;T@3MSf21ZGLVq!$y8fMUP*ESzJVDk^a@qn?Nn4z+twCl#_WZ#3~?Q@;NW!N#FrWb`_srMLOr9o`WA2KHEbLL>ip@|1FJ%z;d)e>L3_Y9VBo> z!x1It9+Zt^1O}*~_RCkx`nABOyQ<~x|%<0usO;jIfZQE!wc;&lj`M9sC@Yyyi zG#BJ~f8mF*YF-Hwvm0GGbd-UNavL=Ei$(~1Z^WMy2R}au0@SoOAs(dox+==woK(RO zk!U0l`90eg5qGjdqAV~(788sq&RUdhzO;gk1&0=8(-BYssn|$i%y9B91dOJOsus${ z0);@ciHlK)I0-pf*;tX#Se&dZt?h)IMA?v}%?OMTseHf&vax&>AzFyCNgPzL=&Go* zNZ|<>76CpO00jaIu)v{wU;zXi4B};hfJpNk2mu6x03e7E6fDFKV)^sMCPqOji4f3O zAq{ESKh2RSQ8qIo(MAXebaZs&bL8j46HI|%1OfphwHpEfkR$+h&elYv6TsT;$~Ta| zaHKJIC<4xgh{Id69N;2N@b*MeHnsypf4{!93yu2Qj*UIR@~agz3W%}9SYfP*c0e#6 z82BqaQgr@Sw6^2>8XG_>heyL>hL#zIwM5-Vu@&8hZWJyKk_qMF8fPV*o z)IJe3N(hT5SRsjGNE;hV913|52_VUc2=IH=_h1~zqevT0L_Fc^wfH+kUoVO##`d4w z0}BUHwZw^;BT;x0oCxqw@;l^#%vbI|wZGc`Pg5eKHVR1{cz}^6y~Rkq1r7iq0APp~ zm|sW$Ap`>Rkh%>BBm(?N^1H?F7hAN(e@||;Ww@Mhu9D5 zU;B-aG#+Jt(32IU#q8~IXdx5001^rjKmzz-NF)F%fP@2(Xaov?HUXgpO)v-n2-f6l zgj7_1)cp@!1#3GZ(i(;N3m49hL}FoJC;%=12Lqrm2pE9iM+*QA&7Jh5fY+BLF$rh57G^9#jLQo|D_=*aB?kxdG~2Z&BtBfx)0h0*=>B`DxK7 zPn}>-O{4GYIY{9)`=}&;;g8_|#2+vz2mQT6H@`W=3wZkm*#1UQxkat9v(u4JQHA$y zQ>&cN;b#FGe$SfC22D)J4spuX zzq%fF_pS=P^h?-X`KV2nutlyv#s!XtQk|`2>%KF!Uz+MA!@wZ-_D0x4_Obpp8wL)! yjxH{QR>!#x@f`S(>!fXotKn20zX%-Z>obAqM8IIFDZpUTwju|IjG8Pp#s2}a1rCt_ diff --git a/io.openems.edge.ess.mr.gridcon/doc/PQ-01-13-00-PD_PCS-4W_DE.pdf b/io.openems.edge.ess.mr.gridcon/doc/PQ-01-13-00-PD_PCS-4W_DE.pdf deleted file mode 100644 index b17c93a127d56e17ae79e25491d47f9807e83484..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 115412 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

      - \ No newline at end of file + diff --git a/ui/src/app/edge/history/delayedselltogrid/widget.component.ts b/ui/src/app/edge/history/delayedselltogrid/widget.component.ts index 5a537af8d69..a31ec5da133 100644 --- a/ui/src/app/edge/history/delayedselltogrid/widget.component.ts +++ b/ui/src/app/edge/history/delayedselltogrid/widget.component.ts @@ -1,7 +1,7 @@ -import { ActivatedRoute } from '@angular/router'; import { Component, Input, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; -import { Edge, Service, EdgeConfig } from 'src/app/shared/shared'; +import { Edge, EdgeConfig, Service } from 'src/app/shared/shared'; @Component({ selector: DelayedSellToGridWidgetComponent.SELECTOR, diff --git a/ui/src/app/edge/history/fixdigitaloutput/fixdigitaloutputchartoverview/fixdigitaloutputchartoverview.component.html b/ui/src/app/edge/history/fixdigitaloutput/fixdigitaloutputchartoverview/fixdigitaloutputchartoverview.component.html index 887b62548da..e516087b8b3 100644 --- a/ui/src/app/edge/history/fixdigitaloutput/fixdigitaloutputchartoverview/fixdigitaloutputchartoverview.component.html +++ b/ui/src/app/edge/history/fixdigitaloutput/fixdigitaloutputchartoverview/fixdigitaloutputchartoverview.component.html @@ -41,4 +41,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/history/fixdigitaloutput/widget.component.html b/ui/src/app/edge/history/fixdigitaloutput/widget.component.html index 6a243ca093c..fb8bf4bc466 100644 --- a/ui/src/app/edge/history/fixdigitaloutput/widget.component.html +++ b/ui/src/app/edge/history/fixdigitaloutput/widget.component.html @@ -14,4 +14,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/history/heatingelement/heatingelementchartoverview/heatingelementchartoverview.component.html b/ui/src/app/edge/history/heatingelement/heatingelementchartoverview/heatingelementchartoverview.component.html index bcfa40fc435..9b116e552fb 100644 --- a/ui/src/app/edge/history/heatingelement/heatingelementchartoverview/heatingelementchartoverview.component.html +++ b/ui/src/app/edge/history/heatingelement/heatingelementchartoverview/heatingelementchartoverview.component.html @@ -20,4 +20,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/history/heatingelement/widget.component.html b/ui/src/app/edge/history/heatingelement/widget.component.html index 4af8de75ce2..49b50bff319 100644 --- a/ui/src/app/edge/history/heatingelement/widget.component.html +++ b/ui/src/app/edge/history/heatingelement/widget.component.html @@ -34,4 +34,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/history/heatpump/heatpumpchartoverview/heatpumpchartoverview.component.html b/ui/src/app/edge/history/heatpump/heatpumpchartoverview/heatpumpchartoverview.component.html index a244ed42441..f8d4c9d4459 100644 --- a/ui/src/app/edge/history/heatpump/heatpumpchartoverview/heatpumpchartoverview.component.html +++ b/ui/src/app/edge/history/heatpump/heatpumpchartoverview/heatpumpchartoverview.component.html @@ -25,4 +25,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/history/heatpump/widget.component.html b/ui/src/app/edge/history/heatpump/widget.component.html index b3537ee557c..c664db8d882 100644 --- a/ui/src/app/edge/history/heatpump/widget.component.html +++ b/ui/src/app/edge/history/heatpump/widget.component.html @@ -35,4 +35,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/history/peakshaving/asymmetric/asymmetricpeakshavingchartoverview/asymmetricpeakshavingchartoverview.component.html b/ui/src/app/edge/history/peakshaving/asymmetric/asymmetricpeakshavingchartoverview/asymmetricpeakshavingchartoverview.component.html index 25d95ace1ac..4c6ce917658 100644 --- a/ui/src/app/edge/history/peakshaving/asymmetric/asymmetricpeakshavingchartoverview/asymmetricpeakshavingchartoverview.component.html +++ b/ui/src/app/edge/history/peakshaving/asymmetric/asymmetricpeakshavingchartoverview/asymmetricpeakshavingchartoverview.component.html @@ -20,4 +20,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/history/peakshaving/asymmetric/widget.component.html b/ui/src/app/edge/history/peakshaving/asymmetric/widget.component.html index a2459516627..89e8082f29d 100644 --- a/ui/src/app/edge/history/peakshaving/asymmetric/widget.component.html +++ b/ui/src/app/edge/history/peakshaving/asymmetric/widget.component.html @@ -13,4 +13,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/history/peakshaving/asymmetric/widget.component.ts b/ui/src/app/edge/history/peakshaving/asymmetric/widget.component.ts index 85a4b2581e2..befb0fa19ef 100644 --- a/ui/src/app/edge/history/peakshaving/asymmetric/widget.component.ts +++ b/ui/src/app/edge/history/peakshaving/asymmetric/widget.component.ts @@ -1,7 +1,7 @@ -import { ActivatedRoute } from '@angular/router'; import { Component, Input, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; -import { Edge, Service, EdgeConfig } from 'src/app/shared/shared'; +import { Edge, EdgeConfig, Service } from 'src/app/shared/shared'; @Component({ selector: AsymmetricPeakshavingWidgetComponent.SELECTOR, @@ -13,7 +13,6 @@ export class AsymmetricPeakshavingWidgetComponent implements OnInit { @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; @Input({ required: true }) public componentId!: string; - public edge: Edge | null = null; public component: EdgeConfig.Component | null = null; diff --git a/ui/src/app/edge/history/peakshaving/symmetric/symmetricpeakshavingchartoverview/symmetricpeakshavingchartoverview.component.html b/ui/src/app/edge/history/peakshaving/symmetric/symmetricpeakshavingchartoverview/symmetricpeakshavingchartoverview.component.html index 86c26ef7e42..278617c5783 100644 --- a/ui/src/app/edge/history/peakshaving/symmetric/symmetricpeakshavingchartoverview/symmetricpeakshavingchartoverview.component.html +++ b/ui/src/app/edge/history/peakshaving/symmetric/symmetricpeakshavingchartoverview/symmetricpeakshavingchartoverview.component.html @@ -20,4 +20,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/history/peakshaving/symmetric/widget.component.html b/ui/src/app/edge/history/peakshaving/symmetric/widget.component.html index 23e49ec1b9f..dbf3842991d 100644 --- a/ui/src/app/edge/history/peakshaving/symmetric/widget.component.html +++ b/ui/src/app/edge/history/peakshaving/symmetric/widget.component.html @@ -13,4 +13,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/history/peakshaving/symmetric/widget.component.ts b/ui/src/app/edge/history/peakshaving/symmetric/widget.component.ts index 0ae228ca9f5..2a4a3720976 100644 --- a/ui/src/app/edge/history/peakshaving/symmetric/widget.component.ts +++ b/ui/src/app/edge/history/peakshaving/symmetric/widget.component.ts @@ -13,7 +13,6 @@ export class SymmetricPeakshavingWidgetComponent implements OnInit { @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; @Input({ required: true }) public componentId!: string; - public edge: Edge | null = null; public component: EdgeConfig.Component | null = null; diff --git a/ui/src/app/edge/history/peakshaving/timeslot/timeslotpeakshavingchartoverview/timeslotpeakshavingchartoverview.component.html b/ui/src/app/edge/history/peakshaving/timeslot/timeslotpeakshavingchartoverview/timeslotpeakshavingchartoverview.component.html index 3d253a4ca80..61e67f32806 100644 --- a/ui/src/app/edge/history/peakshaving/timeslot/timeslotpeakshavingchartoverview/timeslotpeakshavingchartoverview.component.html +++ b/ui/src/app/edge/history/peakshaving/timeslot/timeslotpeakshavingchartoverview/timeslotpeakshavingchartoverview.component.html @@ -20,4 +20,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/history/peakshaving/timeslot/widget.component.html b/ui/src/app/edge/history/peakshaving/timeslot/widget.component.html index ea2fdd0d94a..912f7c07fc5 100644 --- a/ui/src/app/edge/history/peakshaving/timeslot/widget.component.html +++ b/ui/src/app/edge/history/peakshaving/timeslot/widget.component.html @@ -13,4 +13,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/history/peakshaving/timeslot/widget.component.ts b/ui/src/app/edge/history/peakshaving/timeslot/widget.component.ts index 6903d838553..a8748d264b0 100644 --- a/ui/src/app/edge/history/peakshaving/timeslot/widget.component.ts +++ b/ui/src/app/edge/history/peakshaving/timeslot/widget.component.ts @@ -13,7 +13,6 @@ export class TimeslotPeakshavingWidgetComponent implements OnInit { @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; @Input({ required: true }) public componentId!: string; - public edge: Edge | null = null; public component: EdgeConfig.Component | null = null; diff --git a/ui/src/app/edge/history/singlethreshold/widget.component.html b/ui/src/app/edge/history/singlethreshold/widget.component.html index 53e0a2d3687..a0d04bc95ca 100644 --- a/ui/src/app/edge/history/singlethreshold/widget.component.html +++ b/ui/src/app/edge/history/singlethreshold/widget.component.html @@ -15,4 +15,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/history/storage/storagechartoverview/storagechartoverview.component.html b/ui/src/app/edge/history/storage/storagechartoverview/storagechartoverview.component.html index 801f94f1d4b..749335aba84 100644 --- a/ui/src/app/edge/history/storage/storagechartoverview/storagechartoverview.component.html +++ b/ui/src/app/edge/history/storage/storagechartoverview/storagechartoverview.component.html @@ -150,4 +150,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/history/storage/widget.component.html b/ui/src/app/edge/history/storage/widget.component.html index fe64475d93c..79f3aaac4ce 100644 --- a/ui/src/app/edge/history/storage/widget.component.html +++ b/ui/src/app/edge/history/storage/widget.component.html @@ -29,4 +29,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/live/Controller/Channelthreshold/Channelthreshold.html b/ui/src/app/edge/live/Controller/Channelthreshold/Channelthreshold.html index 677d4630fab..8cb74e66409 100644 --- a/ui/src/app/edge/live/Controller/Channelthreshold/Channelthreshold.html +++ b/ui/src/app/edge/live/Controller/Channelthreshold/Channelthreshold.html @@ -5,4 +5,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/live/Controller/ChpSoc/ChpSoc.html b/ui/src/app/edge/live/Controller/ChpSoc/ChpSoc.html index 751a66c868e..8dc374e330e 100644 --- a/ui/src/app/edge/live/Controller/ChpSoc/ChpSoc.html +++ b/ui/src/app/edge/live/Controller/ChpSoc/ChpSoc.html @@ -27,4 +27,4 @@ height="16" style="fill:blue" /> - \ No newline at end of file + diff --git a/ui/src/app/edge/live/Controller/ChpSoc/modal/modal.component.html b/ui/src/app/edge/live/Controller/ChpSoc/modal/modal.component.html index a1a9d050f1c..531dec7234d 100644 --- a/ui/src/app/edge/live/Controller/ChpSoc/modal/modal.component.html +++ b/ui/src/app/edge/live/Controller/ChpSoc/modal/modal.component.html @@ -103,4 +103,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/live/Controller/Ess/FixActivePower/flat/flat.html b/ui/src/app/edge/live/Controller/Ess/FixActivePower/flat/flat.html index 55b1aa87dc2..61ce74a5bd8 100644 --- a/ui/src/app/edge/live/Controller/Ess/FixActivePower/flat/flat.html +++ b/ui/src/app/edge/live/Controller/Ess/FixActivePower/flat/flat.html @@ -10,4 +10,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/live/Controller/Ess/FixActivePower/modal/modal.html b/ui/src/app/edge/live/Controller/Ess/FixActivePower/modal/modal.html index 98c41b705c5..78d026f8af5 100644 --- a/ui/src/app/edge/live/Controller/Ess/FixActivePower/modal/modal.html +++ b/ui/src/app/edge/live/Controller/Ess/FixActivePower/modal/modal.html @@ -31,4 +31,4 @@ [info]="('Edge.Index.Widgets.InfoStorageForCharge' | translate) + '. ' + ('Edge.Index.Widgets.InfoStorageForDischarge' | translate)"> - \ No newline at end of file + 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 d20fff09d10..3acb6e36570 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 @@ -33,4 +33,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/Ess_TimeOfUseTariff.ts b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/Ess_TimeOfUseTariff.ts index bb6eda0caa8..34ad15b24e1 100644 --- a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/Ess_TimeOfUseTariff.ts +++ b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/Ess_TimeOfUseTariff.ts @@ -26,7 +26,20 @@ import { ScheduleStateAndPriceChartComponent } from "./modal/statePriceChart"; FlatComponent, ], }) -export class Controller_Ess_TimeOfUseTariff { +export class Controller_Ess_TimeOfUseTariff { } + +export namespace Controller_Ess_TimeOfUseTariff { + + export type ScheduleChartData = { + datasets: ChartDataset[], + colors: any[], + labels: Date[] + }; + + export enum ControlMode { + CHARGE_CONSUMPTION = 'CHARGE_CONSUMPTION', + DELAY_DISCHARGE = 'DELAY_DISCHARGE', + } /** * Gets the schedule chart data containing datasets, colors and labels. @@ -41,7 +54,7 @@ export class Controller_Ess_TimeOfUseTariff { * @param controlMode The Control mode of the controller. * @returns The ScheduleChartData. */ - public static getScheduleChartData(size: number, prices: number[], states: number[], timestamps: string[], + export function getScheduleChartData(size: number, prices: number[], states: number[], timestamps: string[], gridBuy: number[], socArray: number[], translate: TranslateService, controlMode: Controller_Ess_TimeOfUseTariff.ControlMode): Controller_Ess_TimeOfUseTariff.ScheduleChartData { @@ -152,16 +165,3 @@ export class Controller_Ess_TimeOfUseTariff { return scheduleChartData; } } - -export namespace Controller_Ess_TimeOfUseTariff { - export type ScheduleChartData = { - datasets: ChartDataset[], - colors: any[], - labels: Date[] - }; - - export enum ControlMode { - CHARGE_CONSUMPTION = 'CHARGE_CONSUMPTION', - DELAY_DISCHARGE = 'DELAY_DISCHARGE', - } -} diff --git a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/flat/flat.html b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/flat/flat.html index 4c9a749c8f7..25962cb6b4a 100644 --- a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/flat/flat.html +++ b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/flat/flat.html @@ -7,4 +7,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/powerSocChart.ts b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/powerSocChart.ts index 1c646bf9601..f28a7ee3b36 100644 --- a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/powerSocChart.ts +++ b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/powerSocChart.ts @@ -5,11 +5,10 @@ import { TranslateService } from '@ngx-translate/core'; import * as Chart from 'chart.js'; import { AbstractHistoryChart } from 'src/app/edge/history/abstracthistorychart'; import { AbstractHistoryChart as NewAbstractHistoryChart } from 'src/app/shared/components/chart/abstracthistorychart'; +import { ChartConstants } from 'src/app/shared/components/chart/chart.constants'; import { ComponentJsonApiRequest } from 'src/app/shared/jsonrpc/request/componentJsonApiRequest'; import { ChartAxis, HistoryUtils, TimeOfUseTariffUtils, Utils, YAxisTitle } from 'src/app/shared/service/utils'; import { ChannelAddress, Edge, EdgeConfig, Service, Websocket } from 'src/app/shared/shared'; - -import { ChartConstants } from 'src/app/shared/components/chart/chart.constants'; import { GetScheduleRequest } from '../../../../../../shared/jsonrpc/request/getScheduleRequest'; import { GetScheduleResponse } from '../../../../../../shared/jsonrpc/response/getScheduleResponse'; diff --git a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/statePriceChart.ts b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/statePriceChart.ts index 51737b33769..a11644b8445 100644 --- a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/statePriceChart.ts +++ b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/statePriceChart.ts @@ -10,11 +10,11 @@ import { ChartAxis, HistoryUtils, TimeOfUseTariffUtils, YAxisTitle } from 'src/a import { ChannelAddress, Currency, Edge, EdgeConfig, Service, Websocket } from 'src/app/shared/shared'; import { calculateResolution } from 'src/app/edge/history/shared'; +import { ChartConstants } from 'src/app/shared/components/chart/chart.constants'; import { ColorUtils } from 'src/app/shared/utils/color/color.utils'; import { GetScheduleRequest } from '../../../../../../shared/jsonrpc/request/getScheduleRequest'; import { GetScheduleResponse } from '../../../../../../shared/jsonrpc/response/getScheduleResponse'; import { Controller_Ess_TimeOfUseTariff } from '../Ess_TimeOfUseTariff'; -import { ChartConstants } from 'src/app/shared/components/chart/chart.constants'; @Component({ selector: 'statePriceChart', diff --git a/ui/src/app/edge/live/Controller/Evcs/administration/administration.component.html b/ui/src/app/edge/live/Controller/Evcs/administration/administration.component.html index ac292531413..6d2c10d1903 100644 --- a/ui/src/app/edge/live/Controller/Evcs/administration/administration.component.html +++ b/ui/src/app/edge/live/Controller/Evcs/administration/administration.component.html @@ -32,4 +32,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/live/Controller/Evcs/modal/modal.html b/ui/src/app/edge/live/Controller/Evcs/modal/modal.html index 8c8c836f943..da7866b9130 100644 --- a/ui/src/app/edge/live/Controller/Evcs/modal/modal.html +++ b/ui/src/app/edge/live/Controller/Evcs/modal/modal.html @@ -154,4 +154,4 @@ - \ 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 index 3e284d228be..428cef4b69a 100644 --- a/ui/src/app/edge/live/Controller/Evcs/popover/popover.html +++ b/ui/src/app/edge/live/Controller/Evcs/popover/popover.html @@ -26,4 +26,4 @@ style="text-align: center"> - \ No newline at end of file + diff --git a/ui/src/app/edge/live/Controller/Io/FixDigitalOutput/Io_FixDigitalOutput.html b/ui/src/app/edge/live/Controller/Io/FixDigitalOutput/Io_FixDigitalOutput.html index b11e04690a6..6a40da4eee7 100644 --- a/ui/src/app/edge/live/Controller/Io/FixDigitalOutput/Io_FixDigitalOutput.html +++ b/ui/src/app/edge/live/Controller/Io/FixDigitalOutput/Io_FixDigitalOutput.html @@ -2,4 +2,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/live/Controller/Io/FixDigitalOutput/modal/modal.component.html b/ui/src/app/edge/live/Controller/Io/FixDigitalOutput/modal/modal.component.html index edbd3cb1964..2fd0e5ba02f 100644 --- a/ui/src/app/edge/live/Controller/Io/FixDigitalOutput/modal/modal.component.html +++ b/ui/src/app/edge/live/Controller/Io/FixDigitalOutput/modal/modal.component.html @@ -36,4 +36,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/live/Controller/Io/HeatingElement/flat/flat.html b/ui/src/app/edge/live/Controller/Io/HeatingElement/flat/flat.html index 3f6ebad1873..f2440c4a5d5 100644 --- a/ui/src/app/edge/live/Controller/Io/HeatingElement/flat/flat.html +++ b/ui/src/app/edge/live/Controller/Io/HeatingElement/flat/flat.html @@ -13,4 +13,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/live/Controller/Io/HeatingElement/modal/modal.html b/ui/src/app/edge/live/Controller/Io/HeatingElement/modal/modal.html index f83d0dc6aef..3a8e729979e 100644 --- a/ui/src/app/edge/live/Controller/Io/HeatingElement/modal/modal.html +++ b/ui/src/app/edge/live/Controller/Io/HeatingElement/modal/modal.html @@ -75,4 +75,4 @@ [formGroup]="formGroup"> - \ No newline at end of file + diff --git a/ui/src/app/edge/live/Controller/Io/Heatpump/Io_Heatpump.html b/ui/src/app/edge/live/Controller/Io/Heatpump/Io_Heatpump.html index 95f97d5a51c..c0ade929d82 100644 --- a/ui/src/app/edge/live/Controller/Io/Heatpump/Io_Heatpump.html +++ b/ui/src/app/edge/live/Controller/Io/Heatpump/Io_Heatpump.html @@ -10,4 +10,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/live/Controller/Io/Heatpump/modal/modal.component.html b/ui/src/app/edge/live/Controller/Io/Heatpump/modal/modal.component.html index eb3859cf803..59063fd023e 100644 --- a/ui/src/app/edge/live/Controller/Io/Heatpump/modal/modal.component.html +++ b/ui/src/app/edge/live/Controller/Io/Heatpump/modal/modal.component.html @@ -278,4 +278,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/Asymmetric.html b/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/Asymmetric.html index c6780f64a77..9f457005bed 100644 --- a/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/Asymmetric.html +++ b/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/Asymmetric.html @@ -9,4 +9,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/modal/modal.component.html b/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/modal/modal.component.html index a25fdfa4fce..ebcb86c320f 100644 --- a/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/modal/modal.component.html +++ b/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/modal/modal.component.html @@ -121,4 +121,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/Symmetric.html b/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/Symmetric.html index f5b77fe7087..1ae94833bb1 100644 --- a/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/Symmetric.html +++ b/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/Symmetric.html @@ -7,4 +7,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/modal/modal.component.html b/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/modal/modal.component.html index 4597da00889..fabeafa884e 100644 --- a/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/modal/modal.component.html +++ b/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/modal/modal.component.html @@ -71,4 +71,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/live/Controller/PeakShaving/Symmetric_TimeSlot/Symmetric_TimeSlot.html b/ui/src/app/edge/live/Controller/PeakShaving/Symmetric_TimeSlot/Symmetric_TimeSlot.html index 59ae34dcc6a..20ba62c9fe4 100644 --- a/ui/src/app/edge/live/Controller/PeakShaving/Symmetric_TimeSlot/Symmetric_TimeSlot.html +++ b/ui/src/app/edge/live/Controller/PeakShaving/Symmetric_TimeSlot/Symmetric_TimeSlot.html @@ -5,4 +5,4 @@ [converter]="CONVERT_WATT_TO_KILOWATT" [value]="peakShavingPower"> - \ No newline at end of file + diff --git a/ui/src/app/edge/live/Controller/PeakShaving/Symmetric_TimeSlot/modal/modal.component.html b/ui/src/app/edge/live/Controller/PeakShaving/Symmetric_TimeSlot/modal/modal.component.html index 53301087624..a143c88db41 100644 --- a/ui/src/app/edge/live/Controller/PeakShaving/Symmetric_TimeSlot/modal/modal.component.html +++ b/ui/src/app/edge/live/Controller/PeakShaving/Symmetric_TimeSlot/modal/modal.component.html @@ -207,4 +207,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/live/Io/Api_DigitalInput/Io_Api_DigitalInput.html b/ui/src/app/edge/live/Io/Api_DigitalInput/Io_Api_DigitalInput.html index bad2fcee243..b3c997ef533 100644 --- a/ui/src/app/edge/live/Io/Api_DigitalInput/Io_Api_DigitalInput.html +++ b/ui/src/app/edge/live/Io/Api_DigitalInput/Io_Api_DigitalInput.html @@ -2,4 +2,4 @@ [icon]="{name: 'radio-button-off-outline', color: 'dark'}"> - \ No newline at end of file + diff --git a/ui/src/app/edge/live/Io/Api_DigitalInput/modal/modal.component.ts b/ui/src/app/edge/live/Io/Api_DigitalInput/modal/modal.component.ts index 5169a6f4ae5..fe0490cb871 100644 --- a/ui/src/app/edge/live/Io/Api_DigitalInput/modal/modal.component.ts +++ b/ui/src/app/edge/live/Io/Api_DigitalInput/modal/modal.component.ts @@ -1,10 +1,10 @@ // @ts-strict-ignore import { Component, Input, OnDestroy, OnInit } from '@angular/core'; -import { Edge, Service, EdgeConfig, Websocket, ChannelAddress, EdgePermission } from '../../../../../shared/shared'; import { ModalController } from '@ionic/angular'; -import { Channel } from 'src/app/shared/jsonrpc/response/getChannelsOfComponentResponse'; -import { ComponentJsonApiRequest } from 'src/app/shared/jsonrpc/request/componentJsonApiRequest'; import { JsonrpcRequest, JsonrpcResponseSuccess } from 'src/app/shared/jsonrpc/base'; +import { ComponentJsonApiRequest } from 'src/app/shared/jsonrpc/request/componentJsonApiRequest'; +import { Channel } from 'src/app/shared/jsonrpc/response/getChannelsOfComponentResponse'; +import { ChannelAddress, Edge, EdgeConfig, EdgePermission, Service, Websocket } from '../../../../../shared/shared'; @Component({ selector: 'Io_Api_DigitalInputModal', diff --git a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/Evcs_Api_Cluster.html b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/Evcs_Api_Cluster.html index da1d7b2a74a..7743c265a65 100644 --- a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/Evcs_Api_Cluster.html +++ b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/Evcs_Api_Cluster.html @@ -13,4 +13,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcs-chart/evcs.chart.html b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcs-chart/evcs.chart.html index 7c11c16ed1a..dea298a6b67 100644 --- a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcs-chart/evcs.chart.html +++ b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcs-chart/evcs.chart.html @@ -4,4 +4,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcs-chart/evcs.chart.ts b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcs-chart/evcs.chart.ts index fec7d8e1ebb..426c5ad9ec5 100644 --- a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcs-chart/evcs.chart.ts +++ b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcs-chart/evcs.chart.ts @@ -1,11 +1,11 @@ // @ts-strict-ignore -import * as Chart from 'chart.js'; -import { Component, Input, OnInit, OnChanges } from '@angular/core'; -import { CurrentData } from 'src/app/shared/components/edge/currentdata'; -import { Data } from 'src/app/edge/history/shared'; -import { EdgeConfig, Edge } from 'src/app/shared/shared'; +import { Component, Input, OnChanges, OnInit } from '@angular/core'; import { ModalController } from '@ionic/angular'; import { TranslateService } from '@ngx-translate/core'; +import * as Chart from 'chart.js'; +import { Data } from 'src/app/edge/history/shared'; +import { CurrentData } from 'src/app/shared/components/edge/currentdata'; +import { Edge, EdgeConfig } from 'src/app/shared/shared'; @Component({ selector: EvcsChartComponent.SELECTOR, diff --git a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcsCluster-modal.page.html b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcsCluster-modal.page.html index 4d5e81a8835..e73fe3f8906 100644 --- a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcsCluster-modal.page.html +++ b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcsCluster-modal.page.html @@ -327,4 +327,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcsCluster-modal.page.ts b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcsCluster-modal.page.ts index 13b2dfaeb2d..219e685ada7 100644 --- a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcsCluster-modal.page.ts +++ b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcsCluster-modal.page.ts @@ -1,9 +1,9 @@ // @ts-strict-ignore -import { ActivatedRoute, Router } from '@angular/router'; import { Component, Input, OnInit, ViewChild } from '@angular/core'; -import { Edge, EdgeConfig, Service, Websocket } from 'src/app/shared/shared'; +import { ActivatedRoute, Router } from '@angular/router'; import { IonReorderGroup, ModalController } from '@ionic/angular'; import { TranslateService } from '@ngx-translate/core'; +import { Edge, EdgeConfig, Service, Websocket } from 'src/app/shared/shared'; type ChargeMode = 'FORCE_CHARGE' | 'EXCESS_POWER'; type Priority = 'CAR' | 'STORAGE'; diff --git a/ui/src/app/edge/live/common/autarchy/flat/flat.html b/ui/src/app/edge/live/common/autarchy/flat/flat.html index 6ad3ab9290a..1b425accf5e 100644 --- a/ui/src/app/edge/live/common/autarchy/flat/flat.html +++ b/ui/src/app/edge/live/common/autarchy/flat/flat.html @@ -4,4 +4,4 @@ - \ No newline at end of file + 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 4ac5da6b99d..761302becfe 100644 --- a/ui/src/app/edge/live/common/consumption/flat/flat.html +++ b/ui/src/app/edge/live/common/consumption/flat/flat.html @@ -35,4 +35,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/live/common/grid/flat/flat.html b/ui/src/app/edge/live/common/grid/flat/flat.html index 9c330d1db35..0005f51617a 100644 --- a/ui/src/app/edge/live/common/grid/flat/flat.html +++ b/ui/src/app/edge/live/common/grid/flat/flat.html @@ -12,4 +12,4 @@ - \ No newline at end of file + 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 3f5ed5d187b..77b660e2749 100644 --- a/ui/src/app/edge/live/common/production/flat/flat.html +++ b/ui/src/app/edge/live/common/production/flat/flat.html @@ -10,4 +10,4 @@ [converter]="CONVERT_WATT_TO_KILOWATT"> - \ No newline at end of file + diff --git a/ui/src/app/edge/live/common/production/flat/flat.ts b/ui/src/app/edge/live/common/production/flat/flat.ts index c0459210a0c..8141104ce0c 100644 --- a/ui/src/app/edge/live/common/production/flat/flat.ts +++ b/ui/src/app/edge/live/common/production/flat/flat.ts @@ -1,6 +1,6 @@ -import { EdgeConfig, Utils } from 'src/app/shared/shared'; import { Component } from '@angular/core'; import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; +import { EdgeConfig, Utils } from 'src/app/shared/shared'; import { ModalComponent } from '../modal/modal'; @Component({ diff --git a/ui/src/app/edge/live/common/production/modal/modal.html b/ui/src/app/edge/live/common/production/modal/modal.html index e48c4cf52f6..81848b9b156 100644 --- a/ui/src/app/edge/live/common/production/modal/modal.html +++ b/ui/src/app/edge/live/common/production/modal/modal.html @@ -47,4 +47,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/live/common/selfconsumption/flat/flat.html b/ui/src/app/edge/live/common/selfconsumption/flat/flat.html index d013066fd28..87d7e770b3e 100644 --- a/ui/src/app/edge/live/common/selfconsumption/flat/flat.html +++ b/ui/src/app/edge/live/common/selfconsumption/flat/flat.html @@ -1,4 +1,4 @@ - \ No newline at end of file + 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 13715f5e0ca..ad219c8d17f 100644 --- a/ui/src/app/edge/live/common/storage/storage.component.html +++ b/ui/src/app/edge/live/common/storage/storage.component.html @@ -60,4 +60,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/live/delayedselltogrid/delayedselltogrid.component.html b/ui/src/app/edge/live/delayedselltogrid/delayedselltogrid.component.html index 10874fd1d55..352d15d1357 100644 --- a/ui/src/app/edge/live/delayedselltogrid/delayedselltogrid.component.html +++ b/ui/src/app/edge/live/delayedselltogrid/delayedselltogrid.component.html @@ -25,4 +25,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/live/delayedselltogrid/modal/modal.component.html b/ui/src/app/edge/live/delayedselltogrid/modal/modal.component.html index a439486f2c1..0327fd96b05 100644 --- a/ui/src/app/edge/live/delayedselltogrid/modal/modal.component.html +++ b/ui/src/app/edge/live/delayedselltogrid/modal/modal.component.html @@ -57,4 +57,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/live/energymonitor/chart/chart.component.html b/ui/src/app/edge/live/energymonitor/chart/chart.component.html index f1a4f537a10..c2eddea61c8 100644 --- a/ui/src/app/edge/live/energymonitor/chart/chart.component.html +++ b/ui/src/app/edge/live/energymonitor/chart/chart.component.html @@ -10,4 +10,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/live/energymonitor/chart/section/abstractsection.component.ts b/ui/src/app/edge/live/energymonitor/chart/section/abstractsection.component.ts index 869a8d30bf9..047bdff0e4d 100644 --- a/ui/src/app/edge/live/energymonitor/chart/section/abstractsection.component.ts +++ b/ui/src/app/edge/live/energymonitor/chart/section/abstractsection.component.ts @@ -1,8 +1,8 @@ // @ts-strict-ignore -import { DefaultTypes } from '../../../../../shared/service/defaulttypes'; -import { GridMode, Service } from 'src/app/shared/shared'; import { TranslateService } from '@ngx-translate/core'; import * as d3 from 'd3'; +import { GridMode, Service } from 'src/app/shared/shared'; +import { DefaultTypes } from '../../../../../shared/service/defaulttypes'; export type Ratio = 'Only Positive [0,1]' | 'Negative and Positive [-1,1]'; 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 3d3d27d3451..fdef929c624 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 @@ -23,4 +23,4 @@ [attr.width]="square.image.length" [attr.height]="square.image.length" [attr.href]="square.image.image + '#root'"> - \ 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 3d84fdbbdb2..d35a089e698 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 @@ -29,4 +29,4 @@ [attr.width]="square.image.length" [attr.height]="square.image.length" [attr.href]="square.image.image + '#root'"> - \ 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 28d77c53120..520a36472ff 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 @@ -23,4 +23,4 @@ [attr.width]="square.image.length" [attr.height]="square.image.length" [attr.href]="square.image.image + '#root'"> - \ 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 9fd35bf0f26..266ac898342 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 @@ -29,4 +29,4 @@ [attr.y]="square.image.y" [attr.width]="square.image.length" [attr.height]="square.image.length" [attr.href]="square.image.image + '#root'"> - \ No newline at end of file + diff --git a/ui/src/app/edge/live/energymonitor/energymonitor.component.html b/ui/src/app/edge/live/energymonitor/energymonitor.component.html index f7c1e05e63a..779a8c37cc4 100644 --- a/ui/src/app/edge/live/energymonitor/energymonitor.component.html +++ b/ui/src/app/edge/live/energymonitor/energymonitor.component.html @@ -8,4 +8,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/live/energymonitor/energymonitor.module.ts b/ui/src/app/edge/live/energymonitor/energymonitor.module.ts index ac7eb9461f4..1939bbf9d45 100644 --- a/ui/src/app/edge/live/energymonitor/energymonitor.module.ts +++ b/ui/src/app/edge/live/energymonitor/energymonitor.module.ts @@ -1,14 +1,13 @@ -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { SharedModule } from './../../../shared/shared.module'; - -import { ConsumptionSectionComponent } from './chart/section/consumption.component'; import { EnergymonitorChartComponent } from './chart/chart.component'; -import { EnergymonitorComponent } from './energymonitor.component'; +import { ConsumptionSectionComponent } from './chart/section/consumption.component'; import { GridSectionComponent } from './chart/section/grid.component'; import { ProductionSectionComponent } from './chart/section/production.component'; import { StorageSectionComponent } from './chart/section/storage.component'; +import { EnergymonitorComponent } from './energymonitor.component'; @NgModule({ imports: [ diff --git a/ui/src/app/edge/live/info/info.component.html b/ui/src/app/edge/live/info/info.component.html index 2e49a4083b3..47687b987ab 100644 --- a/ui/src/app/edge/live/info/info.component.html +++ b/ui/src/app/edge/live/info/info.component.html @@ -1,2 +1,2 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/live/live.component.html b/ui/src/app/edge/live/live.component.html index e771887a085..bef5c983782 100644 --- a/ui/src/app/edge/live/live.component.html +++ b/ui/src/app/edge/live/live.component.html @@ -44,7 +44,6 @@ - @@ -57,7 +56,6 @@ *ngIf="factoryId !== 'Evcs.Cluster.PeakShaving' && factoryId !== 'Evcs.Cluster.SelfConsumption'"> - @@ -159,4 +157,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/live/live.module.ts b/ui/src/app/edge/live/live.module.ts index 62c2a8b672e..a21b0b2caae 100644 --- a/ui/src/app/edge/live/live.module.ts +++ b/ui/src/app/edge/live/live.module.ts @@ -16,6 +16,7 @@ import { Controller_Ess_FixActivePower } from './Controller/Ess/FixActivePower/E import { Controller_Ess_GridOptimizedCharge } from './Controller/Ess/GridOptimizedCharge/Ess_GridOptimizedCharge'; import { Controller_Ess_TimeOfUseTariff } from './Controller/Ess/TimeOfUseTariff/Ess_TimeOfUseTariff'; import { AdministrationComponent } from './Controller/Evcs/administration/administration.component'; +import { Controller_Evcs } from './Controller/Evcs/Evcs'; 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'; @@ -40,7 +41,6 @@ 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: [ diff --git a/ui/src/app/edge/live/livedataservice.ts b/ui/src/app/edge/live/livedataservice.ts index 268b392bf72..3bcde8edb9c 100644 --- a/ui/src/app/edge/live/livedataservice.ts +++ b/ui/src/app/edge/live/livedataservice.ts @@ -1,11 +1,10 @@ // @ts-strict-ignore import { Directive, Inject, OnDestroy } from "@angular/core"; +import { RefresherCustomEvent } from "@ionic/angular"; import { takeUntil } from "rxjs/operators"; import { v4 as uuidv4 } from 'uuid'; - import { DataService } from "../../shared/components/shared/dataservice"; import { ChannelAddress, Edge, Service, Websocket } from "../../shared/shared"; -import { RefresherCustomEvent } from "@ionic/angular"; @Directive() export class LiveDataService extends DataService implements OnDestroy { diff --git a/ui/src/app/edge/settings/app/app.module.ts b/ui/src/app/edge/settings/app/app.module.ts index 3b12184a7ed..932b021cfa7 100644 --- a/ui/src/app/edge/settings/app/app.module.ts +++ b/ui/src/app/edge/settings/app/app.module.ts @@ -1,20 +1,20 @@ // @ts-strict-ignore import { NgModule } from '@angular/core'; -import { SharedModule } from 'src/app/shared/shared.module'; -import { InstallAppComponent } from './install.component'; -import { IndexComponent } from './index.component'; -import { SingleAppComponent } from './single.component'; -import { UpdateAppComponent } from './update.component'; -import { KeyModalComponent } from './keypopup/modal.component'; import { FormControl, ValidationErrors } from '@angular/forms'; -import { FormlyModule, FORMLY_CONFIG } from '@ngx-formly/core'; +import { FORMLY_CONFIG, FormlyModule } from '@ngx-formly/core'; import { TranslateService } from '@ngx-translate/core'; -import { FormlySafeInputModalComponent } from './formly/safe-input/formly-safe-input-modal.component'; -import { FormlySafeInputWrapperComponent } from './formly/safe-input/formly-safe-input.extended'; +import { SharedModule } from 'src/app/shared/shared.module'; import { FormlyTextComponent } from './formly/formly-text'; import { FormlyInputWithUnitComponent } from './formly/input-with-unit'; import { FormlyOptionGroupPickerComponent } from './formly/option-group-picker/formly-option-group-picker.component'; import { FormlyReorderArrayComponent } from './formly/reorder-select/formly-reorder-array.component'; +import { FormlySafeInputModalComponent } from './formly/safe-input/formly-safe-input-modal.component'; +import { FormlySafeInputWrapperComponent } from './formly/safe-input/formly-safe-input.extended'; +import { IndexComponent } from './index.component'; +import { InstallAppComponent } from './install.component'; +import { KeyModalComponent } from './keypopup/modal.component'; +import { SingleAppComponent } from './single.component'; +import { UpdateAppComponent } from './update.component'; export function KeyValidator(control: FormControl): ValidationErrors { return /^(.{4}-){3}.{4}$/.test(control.value) ? null : { 'key': true }; diff --git a/ui/src/app/edge/settings/app/formly/formly-text.ts b/ui/src/app/edge/settings/app/formly/formly-text.ts index 6e206169d13..ff08690c381 100644 --- a/ui/src/app/edge/settings/app/formly/formly-text.ts +++ b/ui/src/app/edge/settings/app/formly/formly-text.ts @@ -11,7 +11,7 @@ import { FieldType, FieldTypeConfig } from "@ngx-formly/core"; `, encapsulation: ViewEncapsulation.None, }) -export class FormlyTextComponent extends FieldType { +export class FormlyTextComponent extends FieldType { constructor( ) { diff --git a/ui/src/app/edge/settings/app/formly/option-group-picker/formly-option-group-picker.component.html b/ui/src/app/edge/settings/app/formly/option-group-picker/formly-option-group-picker.component.html index 4b291de45e1..3919cd33ff9 100644 --- a/ui/src/app/edge/settings/app/formly/option-group-picker/formly-option-group-picker.component.html +++ b/ui/src/app/edge/settings/app/formly/option-group-picker/formly-option-group-picker.component.html @@ -39,4 +39,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/settings/app/formly/option-group-picker/formly-option-group-picker.component.ts b/ui/src/app/edge/settings/app/formly/option-group-picker/formly-option-group-picker.component.ts index b707644d911..ce5b702e4b1 100644 --- a/ui/src/app/edge/settings/app/formly/option-group-picker/formly-option-group-picker.component.ts +++ b/ui/src/app/edge/settings/app/formly/option-group-picker/formly-option-group-picker.component.ts @@ -1,7 +1,7 @@ // @ts-strict-ignore import { Component, OnInit } from "@angular/core"; import { FieldType, FieldTypeConfig, FormlyFieldConfig } from "@ngx-formly/core"; -import { OptionGroup, OptionGroupConfig, Option, getTitleFromOptionConfig } from "./optionGroupPickerConfiguration"; +import { Option, OptionGroup, OptionGroupConfig, getTitleFromOptionConfig } from "./optionGroupPickerConfiguration"; @Component({ selector: 'formly-option-group-picker', diff --git a/ui/src/app/edge/settings/app/formly/reorder-select/formly-reorder-array.component.html b/ui/src/app/edge/settings/app/formly/reorder-select/formly-reorder-array.component.html index 61f3a2ecd8c..16c3d0ff194 100644 --- a/ui/src/app/edge/settings/app/formly/reorder-select/formly-reorder-array.component.html +++ b/ui/src/app/edge/settings/app/formly/reorder-select/formly-reorder-array.component.html @@ -41,4 +41,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/settings/app/formly/safe-input/formly-safe-input-modal.component.html b/ui/src/app/edge/settings/app/formly/safe-input/formly-safe-input-modal.component.html index 9415c5a3319..56855d3e69d 100644 --- a/ui/src/app/edge/settings/app/formly/safe-input/formly-safe-input-modal.component.html +++ b/ui/src/app/edge/settings/app/formly/safe-input/formly-safe-input-modal.component.html @@ -36,4 +36,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/settings/app/formly/safe-input/formly-safe-input.extended.html b/ui/src/app/edge/settings/app/formly/safe-input/formly-safe-input.extended.html index 58d5124f8b3..08481c07142 100644 --- a/ui/src/app/edge/settings/app/formly/safe-input/formly-safe-input.extended.html +++ b/ui/src/app/edge/settings/app/formly/safe-input/formly-safe-input.extended.html @@ -22,4 +22,4 @@

      - \ No newline at end of file + diff --git a/ui/src/app/edge/settings/app/formly/safe-input/formly-safe-input.extended.ts b/ui/src/app/edge/settings/app/formly/safe-input/formly-safe-input.extended.ts index 32aae50bfda..c0c55317216 100644 --- a/ui/src/app/edge/settings/app/formly/safe-input/formly-safe-input.extended.ts +++ b/ui/src/app/edge/settings/app/formly/safe-input/formly-safe-input.extended.ts @@ -2,9 +2,9 @@ import { Component, OnInit } from "@angular/core"; import { ModalController } from "@ionic/angular"; import { FieldWrapper, FormlyFieldConfig } from "@ngx-formly/core"; -import { FormlySafeInputModalComponent } from "./formly-safe-input-modal.component"; import { GetAppAssistant } from "../../jsonrpc/getAppAssistant"; import { OptionGroupConfig, getTitleFromOptionConfig } from "../option-group-picker/optionGroupPickerConfiguration"; +import { FormlySafeInputModalComponent } from "./formly-safe-input-modal.component"; @Component({ selector: 'formly-safe-input-wrapper', diff --git a/ui/src/app/edge/settings/app/index.component.ts b/ui/src/app/edge/settings/app/index.component.ts index 02051b79b30..328e4f384f5 100644 --- a/ui/src/app/edge/settings/app/index.component.ts +++ b/ui/src/app/edge/settings/app/index.component.ts @@ -10,16 +10,16 @@ import { Role } from 'src/app/shared/type/role'; import { Environment, environment } from 'src/environments'; import { Edge, Service, Websocket } from '../../../shared/shared'; import { ExecuteSystemUpdate } from '../system/executeSystemUpdate'; +import { InstallAppComponent } from './install.component'; +import { Flags } from './jsonrpc/flag/flags'; import { GetApps } from './jsonrpc/getApps'; +import { App } from './keypopup/app'; import { AppCenter } from './keypopup/appCenter'; import { AppCenterGetPossibleApps } from './keypopup/appCenterGetPossibleApps'; +import { AppCenterGetRegisteredKeys } from './keypopup/appCenterGetRegisteredKeys'; import { Key } from './keypopup/key'; import { KeyModalComponent, KeyValidationBehaviour } from './keypopup/modal.component'; import { canEnterKey } from './permissions'; -import { Flags } from './jsonrpc/flag/flags'; -import { App } from './keypopup/app'; -import { InstallAppComponent } from './install.component'; -import { AppCenterGetRegisteredKeys } from './keypopup/appCenterGetRegisteredKeys'; @Component({ selector: IndexComponent.SELECTOR, diff --git a/ui/src/app/edge/settings/app/install.component.html b/ui/src/app/edge/settings/app/install.component.html index 92b8960b12f..2418d652e3a 100644 --- a/ui/src/app/edge/settings/app/install.component.html +++ b/ui/src/app/edge/settings/app/install.component.html @@ -27,4 +27,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/settings/app/jsonrpc/getAppAssistant.spec.ts b/ui/src/app/edge/settings/app/jsonrpc/getAppAssistant.spec.ts index d6cb07561a0..28dbc11b1b0 100644 --- a/ui/src/app/edge/settings/app/jsonrpc/getAppAssistant.spec.ts +++ b/ui/src/app/edge/settings/app/jsonrpc/getAppAssistant.spec.ts @@ -1,6 +1,6 @@ // @ts-strict-ignore -import { GetAppAssistant } from "./getAppAssistant"; import { FormlyFieldConfig } from "@ngx-formly/core"; +import { GetAppAssistant } from "./getAppAssistant"; describe('GetAppAssistant', () => { let fields: FormlyFieldConfig[]; diff --git a/ui/src/app/edge/settings/app/keypopup/modal.component.html b/ui/src/app/edge/settings/app/keypopup/modal.component.html index 9e2ede39af0..ea56ffdf288 100644 --- a/ui/src/app/edge/settings/app/keypopup/modal.component.html +++ b/ui/src/app/edge/settings/app/keypopup/modal.component.html @@ -50,4 +50,4 @@ - \ No newline at end of file + 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 211f1f1a1b1..e8a3e2847b4 100644 --- a/ui/src/app/edge/settings/app/keypopup/modal.component.ts +++ b/ui/src/app/edge/settings/app/keypopup/modal.component.ts @@ -7,14 +7,14 @@ 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'; +import { Flags } from '../jsonrpc/flag/flags'; import { GetApps } from '../jsonrpc/getApps'; +import { hasPredefinedKey } from '../permissions'; import { AppCenter } from './appCenter'; import { AppCenterAddRegisterKeyHistory } from './appCenterAddRegisterKeyHistory'; import { AppCenterGetRegisteredKeys } from './appCenterGetRegisteredKeys'; import { AppCenterIsKeyApplicable } from './appCenterIsKeyApplicable'; import { Key } from './key'; -import { Flags } from '../jsonrpc/flag/flags'; -import { hasPredefinedKey } from '../permissions'; @Component({ selector: KeyModalComponent.SELECTOR, diff --git a/ui/src/app/edge/settings/app/single.component.html b/ui/src/app/edge/settings/app/single.component.html index 5234280d784..465413bd056 100644 --- a/ui/src/app/edge/settings/app/single.component.html +++ b/ui/src/app/edge/settings/app/single.component.html @@ -55,4 +55,4 @@

      - \ No newline at end of file + diff --git a/ui/src/app/edge/settings/app/single.component.ts b/ui/src/app/edge/settings/app/single.component.ts index df22cb61b85..10e07150acd 100644 --- a/ui/src/app/edge/settings/app/single.component.ts +++ b/ui/src/app/edge/settings/app/single.component.ts @@ -4,10 +4,13 @@ import { FormGroup } from '@angular/forms'; import { DomSanitizer } from '@angular/platform-browser'; import { ActivatedRoute, Router } from '@angular/router'; import { ModalController } from '@ionic/angular'; +import { TranslateService } from '@ngx-translate/core'; import { Subject } from 'rxjs'; import { filter, takeUntil } from 'rxjs/operators'; import { ComponentJsonApiRequest } from 'src/app/shared/jsonrpc/request/componentJsonApiRequest'; +import { environment } from 'src/environments'; import { Edge, Service, Utils, Websocket } from '../../../shared/shared'; +import { InstallAppComponent } from './install.component'; import { GetApp } from './jsonrpc/getApp'; import { GetAppDescriptor } from './jsonrpc/getAppDescriptor'; import { GetApps } from './jsonrpc/getApps'; @@ -16,9 +19,6 @@ import { AppCenterGetPossibleApps } from './keypopup/appCenterGetPossibleApps'; import { AppCenterIsAppFree } from './keypopup/appCenterIsAppFree'; import { KeyModalComponent, KeyValidationBehaviour } from './keypopup/modal.component'; import { canEnterKey, hasKeyModel, hasPredefinedKey } from './permissions'; -import { InstallAppComponent } from './install.component'; -import { TranslateService } from '@ngx-translate/core'; -import { environment } from 'src/environments'; @Component({ selector: SingleAppComponent.SELECTOR, diff --git a/ui/src/app/edge/settings/app/update.component.html b/ui/src/app/edge/settings/app/update.component.html index b773512c8e0..039d79b1826 100644 --- a/ui/src/app/edge/settings/app/update.component.html +++ b/ui/src/app/edge/settings/app/update.component.html @@ -17,7 +17,8 @@ [disabled]="(!((!varinstance.form.pristine) && (varinstance.form.valid))) || varinstance.isDeleting || varinstance.isUpdating" translate> Edge.Config.App.updateApp - + Edge.Config.App.deleteApp
      diff --git a/ui/src/app/edge/settings/app/update.component.ts b/ui/src/app/edge/settings/app/update.component.ts index 26bf353a98f..361070f1e21 100644 --- a/ui/src/app/edge/settings/app/update.component.ts +++ b/ui/src/app/edge/settings/app/update.component.ts @@ -6,11 +6,11 @@ import { FormlyFieldConfig } from '@ngx-formly/core'; import { TranslateService } from '@ngx-translate/core'; import { ComponentJsonApiRequest } from 'src/app/shared/jsonrpc/request/componentJsonApiRequest'; import { Edge, Service, Utils, Websocket } from '../../../shared/shared'; +import { InstallAppComponent } from './install.component'; import { DeleteAppInstance } from './jsonrpc/deleteAppInstance'; import { GetAppAssistant } from './jsonrpc/getAppAssistant'; import { GetAppInstances } from './jsonrpc/getAppInstances'; import { UpdateAppInstance } from './jsonrpc/updateAppInstance'; -import { InstallAppComponent } from './install.component'; interface MyInstance { instanceId: string, // uuid diff --git a/ui/src/app/edge/settings/channels/channels.component.html b/ui/src/app/edge/settings/channels/channels.component.html index fd240402020..ecef95c38f1 100644 --- a/ui/src/app/edge/settings/channels/channels.component.html +++ b/ui/src/app/edge/settings/channels/channels.component.html @@ -197,4 +197,4 @@ - \ 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 f911ef9520f..a6adc4dd12c 100644 --- a/ui/src/app/edge/settings/channels/channels.component.ts +++ b/ui/src/app/edge/settings/channels/channels.component.ts @@ -6,10 +6,10 @@ import { PersistencePriority } from 'src/app/shared/components/edge/edgeconfig'; import { SetChannelValueRequest } from 'src/app/shared/jsonrpc/request/setChannelValueRequest'; import { environment } from 'src/environments'; -import { ChannelAddress, Edge, EdgeConfig, EdgePermission, Service, Websocket } from '../../../shared/shared'; import { ComponentJsonApiRequest } from 'src/app/shared/jsonrpc/request/componentJsonApiRequest'; -import { Channel, GetChannelsOfComponentResponse } from 'src/app/shared/jsonrpc/response/getChannelsOfComponentResponse'; import { GetChannelsOfComponentRequest } from 'src/app/shared/jsonrpc/request/getChannelsOfComponentRequest'; +import { Channel, GetChannelsOfComponentResponse } from 'src/app/shared/jsonrpc/response/getChannelsOfComponentResponse'; +import { ChannelAddress, Edge, EdgeConfig, EdgePermission, Service, Websocket } from '../../../shared/shared'; @Component({ selector: ChannelsComponent.SELECTOR, diff --git a/ui/src/app/edge/settings/component/install/index.component.html b/ui/src/app/edge/settings/component/install/index.component.html index 4515acc6a17..c918b508485 100644 --- a/ui/src/app/edge/settings/component/install/index.component.html +++ b/ui/src/app/edge/settings/component/install/index.component.html @@ -24,4 +24,4 @@

      {{ item.name }}

      - \ No newline at end of file + diff --git a/ui/src/app/edge/settings/component/install/index.component.ts b/ui/src/app/edge/settings/component/install/index.component.ts index 05950505890..5b5ec1ecf07 100644 --- a/ui/src/app/edge/settings/component/install/index.component.ts +++ b/ui/src/app/edge/settings/component/install/index.component.ts @@ -1,9 +1,9 @@ // @ts-strict-ignore -import { CategorizedFactories } from 'src/app/shared/components/edge/edgeconfig'; import { Component, OnInit } from '@angular/core'; -import { Service, Utils, EdgeConfig, Websocket, Edge, EdgePermission } from '../../../../shared/shared'; +import { CategorizedFactories } from 'src/app/shared/components/edge/edgeconfig'; import { JsonrpcRequest, JsonrpcResponseSuccess } from 'src/app/shared/jsonrpc/base'; import { ComponentJsonApiRequest } from 'src/app/shared/jsonrpc/request/componentJsonApiRequest'; +import { Edge, EdgeConfig, EdgePermission, Service, Utils, Websocket } from '../../../../shared/shared'; interface MyCategorizedFactories extends CategorizedFactories { isClicked?: boolean, diff --git a/ui/src/app/edge/settings/component/install/install.component.html b/ui/src/app/edge/settings/component/install/install.component.html index f93712cddf2..ae3916b1def 100644 --- a/ui/src/app/edge/settings/component/install/install.component.html +++ b/ui/src/app/edge/settings/component/install/install.component.html @@ -24,4 +24,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/settings/component/install/install.component.ts b/ui/src/app/edge/settings/component/install/install.component.ts index 360f2895de0..53be5a1fef2 100644 --- a/ui/src/app/edge/settings/component/install/install.component.ts +++ b/ui/src/app/edge/settings/component/install/install.component.ts @@ -1,9 +1,9 @@ // @ts-strict-ignore -import { ActivatedRoute } from '@angular/router'; import { Component, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; +import { ActivatedRoute } from '@angular/router'; import { FormlyFieldConfig } from '@ngx-formly/core'; -import { Service, Utils, Websocket, EdgeConfig, Edge } from '../../../../shared/shared'; +import { Edge, EdgeConfig, Service, Utils, Websocket } from '../../../../shared/shared'; @Component({ selector: ComponentInstallComponent.SELECTOR, diff --git a/ui/src/app/edge/settings/component/update/index.component.html b/ui/src/app/edge/settings/component/update/index.component.html index c4ebd8a90c5..30373db23e2 100644 --- a/ui/src/app/edge/settings/component/update/index.component.html +++ b/ui/src/app/edge/settings/component/update/index.component.html @@ -27,4 +27,4 @@

      {{ item.alias }} - \ No newline at end of file + diff --git a/ui/src/app/edge/settings/component/update/update.component.html b/ui/src/app/edge/settings/component/update/update.component.html index 38297852e60..aeaee6f0114 100644 --- a/ui/src/app/edge/settings/component/update/update.component.html +++ b/ui/src/app/edge/settings/component/update/update.component.html @@ -31,4 +31,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/settings/component/update/update.component.ts b/ui/src/app/edge/settings/component/update/update.component.ts index ff1f9201fcd..e4177748d18 100644 --- a/ui/src/app/edge/settings/component/update/update.component.ts +++ b/ui/src/app/edge/settings/component/update/update.component.ts @@ -1,9 +1,9 @@ // @ts-strict-ignore -import { ActivatedRoute } from '@angular/router'; import { Component, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; +import { ActivatedRoute } from '@angular/router'; import { FormlyFieldConfig } from '@ngx-formly/core'; -import { Service, Utils, Websocket, EdgeConfig, Edge } from '../../../../shared/shared'; +import { Edge, EdgeConfig, Service, Utils, Websocket } from '../../../../shared/shared'; @Component({ selector: ComponentUpdateComponent.SELECTOR, diff --git a/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.html b/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.html index d10ae978751..0468ec0c4d5 100644 --- a/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.html +++ b/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.html @@ -13,7 +13,7 @@ "{{item.key}}": , -
      +
        @@ -25,7 +25,7 @@ + [ngTemplateOutletContext]="{value: value.elementType, indentation: indentation + 4}"> [] diff --git a/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.permission.ts b/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.permission.ts index 789e472d542..67edc0ee8a0 100644 --- a/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.permission.ts +++ b/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.permission.ts @@ -5,7 +5,7 @@ import { User } from "src/app/shared/jsonrpc/shared"; export namespace JsonrpcTestPermission { export function canSee(user: User, edge: Edge): boolean { - return true; + return true; } } diff --git a/ui/src/app/edge/settings/powerassistant/powerassistant.ts b/ui/src/app/edge/settings/powerassistant/powerassistant.ts index 1cdedeeefe6..8dfaabf14dd 100644 --- a/ui/src/app/edge/settings/powerassistant/powerassistant.ts +++ b/ui/src/app/edge/settings/powerassistant/powerassistant.ts @@ -1,11 +1,10 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; - import { formatNumber } from '@angular/common'; -import { ChannelAddress, CurrentData, EdgeConfig, Utils } from '../../../shared/shared'; -import { LiveDataService } from '../../live/livedataservice'; +import { Component } from '@angular/core'; import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; import { DataService } from 'src/app/shared/components/shared/dataservice'; +import { ChannelAddress, CurrentData, EdgeConfig, Utils } from '../../../shared/shared'; +import { LiveDataService } from '../../live/livedataservice'; type Channel = { title: string, diff --git a/ui/src/app/edge/settings/profile/aliasupdate.component.html b/ui/src/app/edge/settings/profile/aliasupdate.component.html index 9daf445a05b..1e63df550f6 100644 --- a/ui/src/app/edge/settings/profile/aliasupdate.component.html +++ b/ui/src/app/edge/settings/profile/aliasupdate.component.html @@ -37,4 +37,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/settings/settings.component.html b/ui/src/app/edge/settings/settings.component.html index a08457cce91..abfdf9a2a04 100644 --- a/ui/src/app/edge/settings/settings.component.html +++ b/ui/src/app/edge/settings/settings.component.html @@ -103,7 +103,8 @@ Edge.Config.Index.adjustComponents - + @@ -117,7 +118,8 @@ Edge.Config.Index.addComponents - + @@ -146,7 +148,8 @@ Power Assistant - + diff --git a/ui/src/app/edge/settings/system/executeSystemUpdate.ts b/ui/src/app/edge/settings/system/executeSystemUpdate.ts index 6bb7f6b8c2e..8ad1732c5bd 100644 --- a/ui/src/app/edge/settings/system/executeSystemUpdate.ts +++ b/ui/src/app/edge/settings/system/executeSystemUpdate.ts @@ -5,8 +5,8 @@ import { ComponentJsonApiRequest } from "src/app/shared/jsonrpc/request/componen import { Edge, Websocket } from "src/app/shared/shared"; import { environment } from "src/environments"; import { ExecuteSystemUpdateRequest } from "./executeSystemUpdateRequest"; -import { GetSystemUpdateStateResponse, SystemUpdateState } from "./getSystemUpdateStateResponse"; import { GetSystemUpdateStateRequest } from "./getSystemUpdateStateRequest"; +import { GetSystemUpdateStateResponse, SystemUpdateState } from "./getSystemUpdateStateResponse"; export class ExecuteSystemUpdate { diff --git a/ui/src/app/edge/settings/system/executesystemupdate.component.html b/ui/src/app/edge/settings/system/executesystemupdate.component.html index a2e0205fe5d..53281fa214c 100644 --- a/ui/src/app/edge/settings/system/executesystemupdate.component.html +++ b/ui/src/app/edge/settings/system/executesystemupdate.component.html @@ -118,4 +118,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/settings/systemexecute/systemexecute.component.html b/ui/src/app/edge/settings/systemexecute/systemexecute.component.html index 11216d1262f..c22504d89c5 100644 --- a/ui/src/app/edge/settings/systemexecute/systemexecute.component.html +++ b/ui/src/app/edge/settings/systemexecute/systemexecute.component.html @@ -130,4 +130,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/edge/settings/systemlog/systemlog.component.ts b/ui/src/app/edge/settings/systemlog/systemlog.component.ts index b460c3c7710..489f7c9bda2 100644 --- a/ui/src/app/edge/settings/systemlog/systemlog.component.ts +++ b/ui/src/app/edge/settings/systemlog/systemlog.component.ts @@ -1,13 +1,12 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; +import { SelectCustomEvent } from '@ionic/angular'; import { TranslateService } from '@ngx-translate/core'; +import { parse } from 'date-fns'; import { Subject } from 'rxjs'; import { filter, take, takeUntil } from 'rxjs/operators'; import { Filter } from 'src/app/index/filter/filter.component'; - -import { Service, Utils, Websocket } from '../../../shared/shared'; import { Role } from 'src/app/shared/type/role'; -import { parse } from 'date-fns'; -import { SelectCustomEvent } from '@ionic/angular'; +import { Service, Utils, Websocket } from '../../../shared/shared'; export const LOG_LEVEL_FILTER = (translate: TranslateService): Filter => ({ placeholder: translate.instant("Edge.Config.Log.level"), diff --git a/ui/src/app/index/filter/filter.component.html b/ui/src/app/index/filter/filter.component.html index 5d4b4593d89..aa8c62bc3e6 100644 --- a/ui/src/app/index/filter/filter.component.html +++ b/ui/src/app/index/filter/filter.component.html @@ -15,4 +15,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/index/filter/filter.component.ts b/ui/src/app/index/filter/filter.component.ts index c1019a9afd9..16cc1e4b1a4 100644 --- a/ui/src/app/index/filter/filter.component.ts +++ b/ui/src/app/index/filter/filter.component.ts @@ -2,9 +2,9 @@ import { Component, EventEmitter, Output } from "@angular/core"; import { TranslateService } from "@ngx-translate/core"; import { TKeyValue } from "src/app/shared/service/defaulttypes"; +import { Utils } from "src/app/shared/shared"; import { environment } from "src/environments"; import { SUM_STATES } from "../shared/sumState"; -import { Utils } from "src/app/shared/shared"; @Component({ selector: 'oe-filter', diff --git a/ui/src/app/index/index.module.ts b/ui/src/app/index/index.module.ts index fc90698bdaf..427fb34c7f5 100644 --- a/ui/src/app/index/index.module.ts +++ b/ui/src/app/index/index.module.ts @@ -1,12 +1,11 @@ import { NgModule } from '@angular/core'; - import { RegistrationModule } from '../registration/registration.module'; import { SharedModule } from './../shared/shared.module'; import { FilterComponent } from './filter/filter.component'; -import { OverViewComponent } from './overview/overview.component'; -import { SumStateComponent } from './shared/sumState'; import { LoginComponent } from './login.component'; +import { OverViewComponent } from './overview/overview.component'; import { LoadingScreenComponent } from './shared/loading-screen'; +import { SumStateComponent } from './shared/sumState'; @NgModule({ imports: [ diff --git a/ui/src/app/index/overview/overview.component.html b/ui/src/app/index/overview/overview.component.html index ceb8d8c680a..e1a0fa4e05d 100644 --- a/ui/src/app/index/overview/overview.component.html +++ b/ui/src/app/index/overview/overview.component.html @@ -128,4 +128,4 @@

      {{ edge.comment }}

      - \ No newline at end of file + diff --git a/ui/src/app/index/shared/loading-screen.html b/ui/src/app/index/shared/loading-screen.html index c20266ac0b3..2001205da68 100644 --- a/ui/src/app/index/shared/loading-screen.html +++ b/ui/src/app/index/shared/loading-screen.html @@ -2,4 +2,4 @@

      Loading...

      - \ No newline at end of file + diff --git a/ui/src/app/index/shared/sumState.ts b/ui/src/app/index/shared/sumState.ts index c2de550bd7d..a0a4dc504a0 100644 --- a/ui/src/app/index/shared/sumState.ts +++ b/ui/src/app/index/shared/sumState.ts @@ -1,8 +1,8 @@ import { Component, Input, OnInit } from "@angular/core"; import { TranslateService } from "@ngx-translate/core"; -import { Filter } from "../filter/filter.component"; -import { Role } from "src/app/shared/type/role"; import { Service } from "src/app/shared/shared"; +import { Role } from "src/app/shared/type/role"; +import { Filter } from "../filter/filter.component"; export enum SumState { OK = 'OK', diff --git a/ui/src/app/registration/modal/modal.component.html b/ui/src/app/registration/modal/modal.component.html index 93158068f8d..87cbc68a2dc 100644 --- a/ui/src/app/registration/modal/modal.component.html +++ b/ui/src/app/registration/modal/modal.component.html @@ -204,4 +204,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/registration/registration.component.html b/ui/src/app/registration/registration.component.html index 399bd0a13d2..8f36566a6fa 100644 --- a/ui/src/app/registration/registration.component.html +++ b/ui/src/app/registration/registration.component.html @@ -1,3 +1,3 @@ Register.createUser - \ No newline at end of file + diff --git a/ui/src/app/shared/components/chart/abstracthistorychart.ts b/ui/src/app/shared/components/chart/abstracthistorychart.ts index e0e569d889a..feaadfa5623 100644 --- a/ui/src/app/shared/components/chart/abstracthistorychart.ts +++ b/ui/src/app/shared/components/chart/abstracthistorychart.ts @@ -414,10 +414,10 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { text: dataset.label, datasetIndex: index, fontColor: getComputedStyle(document.documentElement).getPropertyValue('--ion-color-text'), - ...(dataset.backgroundColor != null && {fillStyle: dataset.backgroundColor.toString()}), + ...(dataset.backgroundColor != null && { fillStyle: dataset.backgroundColor.toString() }), hidden: isHidden != null ? isHidden : !chart.isDatasetVisible(index), lineWidth: 2, - ...(dataset.borderColor != null && {strokeStyle: dataset.borderColor.toString()}), + ...(dataset.borderColor != null && { strokeStyle: dataset.borderColor.toString() }), ...(dataset['borderDash'] != null && { lineDash: dataset['borderDash'] }), }); }); diff --git a/ui/src/app/shared/components/edge/edge.ts b/ui/src/app/shared/components/edge/edge.ts index 29a53ed556d..55ede05a5cf 100644 --- a/ui/src/app/shared/components/edge/edge.ts +++ b/ui/src/app/shared/components/edge/edge.ts @@ -1,12 +1,9 @@ // @ts-strict-ignore import { compareVersions } from 'compare-versions'; import { BehaviorSubject, Subject } from 'rxjs'; -import { SumState } from 'src/app/index/shared/sumState'; - -import { CurrentData } from './currentdata'; -import { EdgeConfig } from './edgeconfig'; import { filter, first } from 'rxjs/operators'; -import { JsonrpcResponseSuccess, JsonrpcRequest } from '../../jsonrpc/base'; +import { SumState } from 'src/app/index/shared/sumState'; +import { JsonrpcRequest, JsonrpcResponseSuccess } from '../../jsonrpc/base'; import { CurrentDataNotification } from '../../jsonrpc/notification/currentDataNotification'; import { EdgeConfigNotification } from '../../jsonrpc/notification/edgeConfigNotification'; import { SystemLogNotification } from '../../jsonrpc/notification/systemLogNotification'; @@ -16,18 +13,20 @@ import { DeleteComponentConfigRequest } from '../../jsonrpc/request/deleteCompon import { EdgeRpcRequest } from '../../jsonrpc/request/edgeRpcRequest'; import { GetChannelRequest } from '../../jsonrpc/request/getChannelRequest'; import { GetChannelsOfComponentRequest } from '../../jsonrpc/request/getChannelsOfComponentRequest'; +import { GetEdgeConfigRequest } from '../../jsonrpc/request/getEdgeConfigRequest'; import { GetPropertiesOfFactoryRequest } from '../../jsonrpc/request/getPropertiesOfFactoryRequest'; import { SubscribeChannelsRequest } from '../../jsonrpc/request/subscribeChannelsRequest'; import { SubscribeSystemLogRequest } from '../../jsonrpc/request/subscribeSystemLogRequest'; import { UpdateComponentConfigRequest } from '../../jsonrpc/request/updateComponentConfigRequest'; import { GetChannelResponse } from '../../jsonrpc/response/getChannelResponse'; import { Channel, GetChannelsOfComponentResponse } from '../../jsonrpc/response/getChannelsOfComponentResponse'; +import { GetEdgeConfigResponse } from '../../jsonrpc/response/getEdgeConfigResponse'; import { GetPropertiesOfFactoryResponse } from '../../jsonrpc/response/getPropertiesOfFactoryResponse'; import { ArrayUtils } from '../../service/arrayutils'; -import { ChannelAddress, SystemLog, Websocket, EdgePermission } from '../../shared'; +import { ChannelAddress, EdgePermission, SystemLog, Websocket } from '../../shared'; import { Role } from '../../type/role'; -import { GetEdgeConfigResponse } from '../../jsonrpc/response/getEdgeConfigResponse'; -import { GetEdgeConfigRequest } from '../../jsonrpc/request/getEdgeConfigRequest'; +import { CurrentData } from './currentdata'; +import { EdgeConfig } from './edgeconfig'; export class Edge { diff --git a/ui/src/app/shared/components/edge/meter/currentVoltage/currentVoltage.overview.html b/ui/src/app/shared/components/edge/meter/currentVoltage/currentVoltage.overview.html index 4db1a8ebaba..71727e415e6 100644 --- a/ui/src/app/shared/components/edge/meter/currentVoltage/currentVoltage.overview.html +++ b/ui/src/app/shared/components/edge/meter/currentVoltage/currentVoltage.overview.html @@ -5,4 +5,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/shared/components/edge/meter/currentVoltage/currentVoltageModule.ts b/ui/src/app/shared/components/edge/meter/currentVoltage/currentVoltageModule.ts index 91fbe244d4b..8daaa2c37ac 100644 --- a/ui/src/app/shared/components/edge/meter/currentVoltage/currentVoltageModule.ts +++ b/ui/src/app/shared/components/edge/meter/currentVoltage/currentVoltageModule.ts @@ -8,10 +8,9 @@ import { FooterNavigationModule } from "src/app/shared/components/footer/subnavi import { ChartModule } from "../../../chart/chart.module"; import { HistoryDataErrorModule } from "../../../history-data-error/history-data-error.module"; import { PickdateModule } from "../../../pickdate/pickdate.module"; - +import { CurrentVoltageAsymmetricChartComponent } from "./chart/asymmetricMeter"; import { CurrentVoltageSymmetricChartComponent } from "./chart/symmetricMeter"; import { CurrentAndVoltageOverviewComponent } from "./currentVoltage.overview"; -import { CurrentVoltageAsymmetricChartComponent } from "./chart/asymmetricMeter"; @NgModule({ imports: [ diff --git a/ui/src/app/shared/components/edge/meter/electricity/modal.component.html b/ui/src/app/shared/components/edge/meter/electricity/modal.component.html index 6a899a8f470..389bd90116b 100644 --- a/ui/src/app/shared/components/edge/meter/electricity/modal.component.html +++ b/ui/src/app/shared/components/edge/meter/electricity/modal.component.html @@ -3,4 +3,4 @@ [converter]="Utils.CONVERT_TO_WATT"> - \ No newline at end of file + diff --git a/ui/src/app/shared/components/edge/meter/esscharger/modal.component.html b/ui/src/app/shared/components/edge/meter/esscharger/modal.component.html index 8b551aa89f7..d607901c8df 100644 --- a/ui/src/app/shared/components/edge/meter/esscharger/modal.component.html +++ b/ui/src/app/shared/components/edge/meter/esscharger/modal.component.html @@ -7,4 +7,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/shared/components/flat/flat-widget-horizontal-line/flat-widget-horizontal-line.html b/ui/src/app/shared/components/flat/flat-widget-horizontal-line/flat-widget-horizontal-line.html index a38f40454db..1a5d6a96871 100644 --- a/ui/src/app/shared/components/flat/flat-widget-horizontal-line/flat-widget-horizontal-line.html +++ b/ui/src/app/shared/components/flat/flat-widget-horizontal-line/flat-widget-horizontal-line.html @@ -9,4 +9,4 @@
      -
      \ No newline at end of file + diff --git a/ui/src/app/shared/components/flat/flat-widget-line/flat-widget-line-item/flat-widget-line-item.html b/ui/src/app/shared/components/flat/flat-widget-line/flat-widget-line-item/flat-widget-line-item.html index 17bd64df05e..7ac84753d40 100644 --- a/ui/src/app/shared/components/flat/flat-widget-line/flat-widget-line-item/flat-widget-line-item.html +++ b/ui/src/app/shared/components/flat/flat-widget-line/flat-widget-line-item/flat-widget-line-item.html @@ -1,4 +1,4 @@   {{ displayValue }} - \ No newline at end of file + diff --git a/ui/src/app/shared/components/flat/flat-widget-line/flat-widget-line.html b/ui/src/app/shared/components/flat/flat-widget-line/flat-widget-line.html index 48644948aae..46424574ca4 100644 --- a/ui/src/app/shared/components/flat/flat-widget-line/flat-widget-line.html +++ b/ui/src/app/shared/components/flat/flat-widget-line/flat-widget-line.html @@ -18,4 +18,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/shared/components/flat/flat-widget-percentagebar/flat-widget-percentagebar.html b/ui/src/app/shared/components/flat/flat-widget-percentagebar/flat-widget-percentagebar.html index 8c5bb50478f..eba1a1964a0 100644 --- a/ui/src/app/shared/components/flat/flat-widget-percentagebar/flat-widget-percentagebar.html +++ b/ui/src/app/shared/components/flat/flat-widget-percentagebar/flat-widget-percentagebar.html @@ -7,4 +7,4 @@ {{ displayValue | unitvalue: '%' }} - \ No newline at end of file + diff --git a/ui/src/app/shared/components/flat/flat-widget.component.html b/ui/src/app/shared/components/flat/flat-widget.component.html index 5efe3ab68f3..a969eb76a61 100644 --- a/ui/src/app/shared/components/flat/flat-widget.component.html +++ b/ui/src/app/shared/components/flat/flat-widget.component.html @@ -16,4 +16,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/shared/components/flat/flat.html b/ui/src/app/shared/components/flat/flat.html index e40a1627541..0e2ae2de349 100644 --- a/ui/src/app/shared/components/flat/flat.html +++ b/ui/src/app/shared/components/flat/flat.html @@ -18,4 +18,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/shared/components/footer/subnavigation/footerNavigation.html b/ui/src/app/shared/components/footer/subnavigation/footerNavigation.html index 1d51d859e10..bfa8f32655c 100644 --- a/ui/src/app/shared/components/footer/subnavigation/footerNavigation.html +++ b/ui/src/app/shared/components/footer/subnavigation/footerNavigation.html @@ -45,4 +45,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/shared/components/formly/form-field-checkbox-hyperlink/form-field-checkbox-hyperlink.wrapper.html b/ui/src/app/shared/components/formly/form-field-checkbox-hyperlink/form-field-checkbox-hyperlink.wrapper.html index a590984e1f7..34a2dbbaa28 100644 --- a/ui/src/app/shared/components/formly/form-field-checkbox-hyperlink/form-field-checkbox-hyperlink.wrapper.html +++ b/ui/src/app/shared/components/formly/form-field-checkbox-hyperlink/form-field-checkbox-hyperlink.wrapper.html @@ -14,4 +14,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/shared/components/formly/form-field-checkbox-hyperlink/form-field-checkbox-hyperlink.wrapper.ts b/ui/src/app/shared/components/formly/form-field-checkbox-hyperlink/form-field-checkbox-hyperlink.wrapper.ts index c923b6718f3..84185208942 100644 --- a/ui/src/app/shared/components/formly/form-field-checkbox-hyperlink/form-field-checkbox-hyperlink.wrapper.ts +++ b/ui/src/app/shared/components/formly/form-field-checkbox-hyperlink/form-field-checkbox-hyperlink.wrapper.ts @@ -1,5 +1,5 @@ // @ts-strict-ignore -import { Component, ChangeDetectionStrategy, OnInit } from '@angular/core'; +import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; import { FieldWrapper } from '@ngx-formly/core'; @Component({ diff --git a/ui/src/app/shared/components/formly/form-field.wrapper.html b/ui/src/app/shared/components/formly/form-field.wrapper.html index 82ad53b779f..18ebda3222c 100644 --- a/ui/src/app/shared/components/formly/form-field.wrapper.html +++ b/ui/src/app/shared/components/formly/form-field.wrapper.html @@ -14,4 +14,4 @@

      - \ No newline at end of file + diff --git a/ui/src/app/shared/components/formly/form-field.wrapper.ts b/ui/src/app/shared/components/formly/form-field.wrapper.ts index 785582964ed..64b6e3a1fd9 100644 --- a/ui/src/app/shared/components/formly/form-field.wrapper.ts +++ b/ui/src/app/shared/components/formly/form-field.wrapper.ts @@ -1,4 +1,4 @@ -import { Component, ChangeDetectionStrategy } from '@angular/core'; +import { ChangeDetectionStrategy, Component } from '@angular/core'; import { FieldWrapper } from '@ngx-formly/core'; @Component({ diff --git a/ui/src/app/shared/components/formly/formly-field-checkbox-image/formly-field-checkbox-with-image.html b/ui/src/app/shared/components/formly/formly-field-checkbox-image/formly-field-checkbox-with-image.html index e48b0e25839..bd1c0ab4da9 100644 --- a/ui/src/app/shared/components/formly/formly-field-checkbox-image/formly-field-checkbox-with-image.html +++ b/ui/src/app/shared/components/formly/formly-field-checkbox-image/formly-field-checkbox-with-image.html @@ -12,8 +12,8 @@ - - + + diff --git a/ui/src/app/shared/components/formly/formly-field-modal/formlyfieldmodal.html b/ui/src/app/shared/components/formly/formly-field-modal/formlyfieldmodal.html index 88bfdd9af17..cd59a9539c3 100644 --- a/ui/src/app/shared/components/formly/formly-field-modal/formlyfieldmodal.html +++ b/ui/src/app/shared/components/formly/formly-field-modal/formlyfieldmodal.html @@ -34,4 +34,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/shared/components/formly/formly-field-modal/template.html b/ui/src/app/shared/components/formly/formly-field-modal/template.html index 51c68cc8d91..1ab0804b0ba 100644 --- a/ui/src/app/shared/components/formly/formly-field-modal/template.html +++ b/ui/src/app/shared/components/formly/formly-field-modal/template.html @@ -1 +1 @@ - \ No newline at end of file + diff --git a/ui/src/app/shared/components/formly/formly-field-radio-with-image/formly-field-radio-with-image.html b/ui/src/app/shared/components/formly/formly-field-radio-with-image/formly-field-radio-with-image.html index 7eb91db5f1f..1c8e08a72cd 100644 --- a/ui/src/app/shared/components/formly/formly-field-radio-with-image/formly-field-radio-with-image.html +++ b/ui/src/app/shared/components/formly/formly-field-radio-with-image/formly-field-radio-with-image.html @@ -24,4 +24,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/shared/components/formly/formly-field-radio-with-image/formly-field-radio-with-image.ts b/ui/src/app/shared/components/formly/formly-field-radio-with-image/formly-field-radio-with-image.ts index 5908a6cd96c..c66a5c192e0 100644 --- a/ui/src/app/shared/components/formly/formly-field-radio-with-image/formly-field-radio-with-image.ts +++ b/ui/src/app/shared/components/formly/formly-field-radio-with-image/formly-field-radio-with-image.ts @@ -1,4 +1,4 @@ -import { Component, ChangeDetectionStrategy, OnInit } from '@angular/core'; +import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; import { FieldWrapper } from '@ngx-formly/core'; @Component({ diff --git a/ui/src/app/shared/components/formly/formly-select-field-modal.component.html b/ui/src/app/shared/components/formly/formly-select-field-modal.component.html index 77488ad7fbd..834fbb753d5 100644 --- a/ui/src/app/shared/components/formly/formly-select-field-modal.component.html +++ b/ui/src/app/shared/components/formly/formly-select-field-modal.component.html @@ -51,4 +51,4 @@ -
      \ No newline at end of file + diff --git a/ui/src/app/shared/components/formly/formly-select-field.extended.html b/ui/src/app/shared/components/formly/formly-select-field.extended.html index 1409c0b07f6..1313a64eb0c 100644 --- a/ui/src/app/shared/components/formly/formly-select-field.extended.html +++ b/ui/src/app/shared/components/formly/formly-select-field.extended.html @@ -8,4 +8,4 @@ {{ formControl.value }} - \ No newline at end of file + diff --git a/ui/src/app/shared/components/formly/input-serial-number-wrapper.html b/ui/src/app/shared/components/formly/input-serial-number-wrapper.html index e2401c3aec9..169d30f12e8 100644 --- a/ui/src/app/shared/components/formly/input-serial-number-wrapper.html +++ b/ui/src/app/shared/components/formly/input-serial-number-wrapper.html @@ -29,4 +29,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/shared/components/formly/input.html b/ui/src/app/shared/components/formly/input.html index abc8b4b0ea0..f85472cc915 100644 --- a/ui/src/app/shared/components/formly/input.html +++ b/ui/src/app/shared/components/formly/input.html @@ -1,6 +1,5 @@ diff --git a/ui/src/app/shared/components/formly/repeat.html b/ui/src/app/shared/components/formly/repeat.html index 09aaee84302..ec9a8f1a311 100644 --- a/ui/src/app/shared/components/formly/repeat.html +++ b/ui/src/app/shared/components/formly/repeat.html @@ -26,4 +26,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/shared/components/header/header.component.html b/ui/src/app/shared/components/header/header.component.html index 875067f79e3..b1e4714c831 100644 --- a/ui/src/app/shared/components/header/header.component.html +++ b/ui/src/app/shared/components/header/header.component.html @@ -68,4 +68,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/shared/components/modal/abstractModal.ts b/ui/src/app/shared/components/modal/abstractModal.ts index 5c5ca8f55aa..78331d04b12 100644 --- a/ui/src/app/shared/components/modal/abstractModal.ts +++ b/ui/src/app/shared/components/modal/abstractModal.ts @@ -10,8 +10,8 @@ import { ChannelAddress, CurrentData, Edge, EdgeConfig, Service, Utils, Websocke import { v4 as uuidv4 } from 'uuid'; import { Role } from "../../type/role"; -import { TextIndentation } from "./modal-line/modal-line"; import { Converter } from "../shared/converter"; +import { TextIndentation } from "./modal-line/modal-line"; @Directive() export abstract class AbstractModal implements OnInit, OnDestroy { diff --git a/ui/src/app/shared/components/modal/help-button/help-button.html b/ui/src/app/shared/components/modal/help-button/help-button.html index b0e195c58ba..203148b44fe 100644 --- a/ui/src/app/shared/components/modal/help-button/help-button.html +++ b/ui/src/app/shared/components/modal/help-button/help-button.html @@ -3,4 +3,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/shared/components/modal/modal-button/modal-button.html b/ui/src/app/shared/components/modal/modal-button/modal-button.html index cfe065fc432..77f3b1a88b4 100644 --- a/ui/src/app/shared/components/modal/modal-button/modal-button.html +++ b/ui/src/app/shared/components/modal/modal-button/modal-button.html @@ -9,4 +9,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/shared/components/modal/modal-info-line/modal-info-line.html b/ui/src/app/shared/components/modal/modal-info-line/modal-info-line.html index 6f66261a711..208186bbb6a 100644 --- a/ui/src/app/shared/components/modal/modal-info-line/modal-info-line.html +++ b/ui/src/app/shared/components/modal/modal-info-line/modal-info-line.html @@ -18,4 +18,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/shared/components/modal/modal-line/modal-line-item/modal-line-item.html b/ui/src/app/shared/components/modal/modal-line/modal-line-item/modal-line-item.html index 1d44987f67e..85028091b7a 100644 --- a/ui/src/app/shared/components/modal/modal-line/modal-line-item/modal-line-item.html +++ b/ui/src/app/shared/components/modal/modal-line/modal-line-item/modal-line-item.html @@ -2,4 +2,4 @@ *ngIf="isAllowedToBeSeen && show && displayValue">   {{ displayValue }} - \ No newline at end of file + diff --git a/ui/src/app/shared/components/modal/modal-line/modal-line.html b/ui/src/app/shared/components/modal/modal-line/modal-line.html index 2f795565950..c75997960ec 100644 --- a/ui/src/app/shared/components/modal/modal-line/modal-line.html +++ b/ui/src/app/shared/components/modal/modal-line/modal-line.html @@ -30,7 +30,7 @@ - + diff --git a/ui/src/app/shared/components/modal/modal-phases/modal-phases.html b/ui/src/app/shared/components/modal/modal-phases/modal-phases.html index d368f4813cf..49679489ecf 100644 --- a/ui/src/app/shared/components/modal/modal-phases/modal-phases.html +++ b/ui/src/app/shared/components/modal/modal-phases/modal-phases.html @@ -10,4 +10,4 @@ [converter]="CONVERT_TO_POSITIVE_WATT"> - \ No newline at end of file + diff --git a/ui/src/app/shared/components/modal/modal-value-line/modal-value-line.html b/ui/src/app/shared/components/modal/modal-value-line/modal-value-line.html index 311cd8e2246..b8a6d8478f0 100644 --- a/ui/src/app/shared/components/modal/modal-value-line/modal-value-line.html +++ b/ui/src/app/shared/components/modal/modal-value-line/modal-value-line.html @@ -12,4 +12,4 @@ {{ displayValue }} - \ No newline at end of file + diff --git a/ui/src/app/shared/components/modal/model-horizontal-line/modal-horizontal-line.html b/ui/src/app/shared/components/modal/model-horizontal-line/modal-horizontal-line.html index 2af26b6ecc4..2a2f2922aaf 100644 --- a/ui/src/app/shared/components/modal/model-horizontal-line/modal-horizontal-line.html +++ b/ui/src/app/shared/components/modal/model-horizontal-line/modal-horizontal-line.html @@ -11,4 +11,4 @@
      - \ No newline at end of file + diff --git a/ui/src/app/shared/components/percentagebar/percentagebar.component.html b/ui/src/app/shared/components/percentagebar/percentagebar.component.html index 1c7ce71728c..c06ff0ba341 100644 --- a/ui/src/app/shared/components/percentagebar/percentagebar.component.html +++ b/ui/src/app/shared/components/percentagebar/percentagebar.component.html @@ -4,4 +4,4 @@ {{ value | unitvalue:'%' }} - \ No newline at end of file + diff --git a/ui/src/app/shared/components/pickdate/pickdate.component.html b/ui/src/app/shared/components/pickdate/pickdate.component.html index ea2c96f7009..a3987add648 100644 --- a/ui/src/app/shared/components/pickdate/pickdate.component.html +++ b/ui/src/app/shared/components/pickdate/pickdate.component.html @@ -8,4 +8,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/shared/components/pickdate/pickdate.module.ts b/ui/src/app/shared/components/pickdate/pickdate.module.ts index 4cf6632c20b..c555a743cac 100644 --- a/ui/src/app/shared/components/pickdate/pickdate.module.ts +++ b/ui/src/app/shared/components/pickdate/pickdate.module.ts @@ -3,10 +3,9 @@ import { ReactiveFormsModule } from '@angular/forms'; import { BrowserModule } from '@angular/platform-browser'; import { IonicModule } from '@ionic/angular'; import { TranslateModule } from '@ngx-translate/core'; - +import { AngularMyDatePickerModule } from '@nodro7/angular-mydatepicker'; import { PickDateComponent } from './pickdate.component'; import { PickDatePopoverComponent } from './popover/popover.component'; -import { AngularMyDatePickerModule } from '@nodro7/angular-mydatepicker'; @NgModule({ imports: [ @@ -23,6 +22,5 @@ import { AngularMyDatePickerModule } from '@nodro7/angular-mydatepicker'; exports: [ PickDateComponent, ], - }) export class PickdateModule { } diff --git a/ui/src/app/shared/components/shared/converter.ts b/ui/src/app/shared/components/shared/converter.ts index bb3318e2621..94f0c2a7635 100644 --- a/ui/src/app/shared/components/shared/converter.ts +++ b/ui/src/app/shared/components/shared/converter.ts @@ -1,7 +1,5 @@ // @ts-strict-ignore - import { TranslateService } from "@ngx-translate/core"; - import { CurrentData, EdgeConfig, GridMode, Utils } from "../../shared"; import { TimeUtils } from "../../utils/time/timeutils"; import { Formatter } from "./formatter"; diff --git a/ui/src/app/shared/components/shared/dataservice.ts b/ui/src/app/shared/components/shared/dataservice.ts index 15b1b79600d..b1d7a835af2 100644 --- a/ui/src/app/shared/components/shared/dataservice.ts +++ b/ui/src/app/shared/components/shared/dataservice.ts @@ -1,9 +1,8 @@ // @ts-strict-ignore import { Injectable } from "@angular/core"; +import { RefresherCustomEvent } from "@ionic/angular"; import { BehaviorSubject, Subject } from "rxjs"; - import { ChannelAddress, Edge } from "../../shared"; -import { RefresherCustomEvent } from "@ionic/angular"; @Injectable() export abstract class DataService { diff --git a/ui/src/app/shared/components/shared/oe-formly-component.ts b/ui/src/app/shared/components/shared/oe-formly-component.ts index 50516a057d5..a463642482f 100644 --- a/ui/src/app/shared/components/shared/oe-formly-component.ts +++ b/ui/src/app/shared/components/shared/oe-formly-component.ts @@ -3,8 +3,7 @@ import { ActivatedRoute } from "@angular/router"; import { FormlyFieldConfig } from "@ngx-formly/core"; import { TranslateService } from "@ngx-translate/core"; import { filter } from "rxjs/operators"; - -import { CurrentData, ChannelAddress, EdgeConfig, Service } from "../../shared"; +import { ChannelAddress, CurrentData, EdgeConfig, Service } from "../../shared"; import { SharedModule } from "../../shared.module"; import { Role } from "../../type/role"; import { TextIndentation } from "../modal/modal-line/modal-line"; diff --git a/ui/src/app/shared/components/status/single/status.component.spec.ts b/ui/src/app/shared/components/status/single/status.component.spec.ts index 6f4c1868bbc..3894b66e66b 100644 --- a/ui/src/app/shared/components/status/single/status.component.spec.ts +++ b/ui/src/app/shared/components/status/single/status.component.spec.ts @@ -1,13 +1,12 @@ import { TestBed } from "@angular/core/testing"; import { ModalController } from "@ionic/angular"; - -import { EdgeConfig, PersistencePriority } from "../../edge/edgeconfig"; -import { StatusSingleComponent } from "./status.component"; import { BehaviorSubject } from "rxjs"; import { DummyWebsocket } from "src/app/shared/service/test/dummywebsocket"; -import { Service, Websocket, ChannelAddress } from "src/app/shared/shared"; +import { ChannelAddress, Service, Websocket } from "src/app/shared/shared"; import { Edge } from "../../edge/edge"; +import { EdgeConfig, PersistencePriority } from "../../edge/edgeconfig"; import { DummyModalController } from "../../shared/testing/DummyModalController"; +import { StatusSingleComponent } from "./status.component"; describe('StatusComponent', () => { const testComponent = new EdgeConfig.Component("test", {}, { diff --git a/ui/src/app/shared/directive/directive.ts b/ui/src/app/shared/directive/directive.ts index 619719018a9..cd1e4561875 100644 --- a/ui/src/app/shared/directive/directive.ts +++ b/ui/src/app/shared/directive/directive.ts @@ -1,7 +1,7 @@ import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; -import { VarDirective } from './ngvar'; import { AutofillDirective } from './autofill'; +import { VarDirective } from './ngvar'; @NgModule({ imports: [ diff --git a/ui/src/app/shared/jsonrpc/notification/systemLogNotification.ts b/ui/src/app/shared/jsonrpc/notification/systemLogNotification.ts index 0c233a75fdd..d7ebcab68be 100644 --- a/ui/src/app/shared/jsonrpc/notification/systemLogNotification.ts +++ b/ui/src/app/shared/jsonrpc/notification/systemLogNotification.ts @@ -1,5 +1,5 @@ -import { JsonrpcNotification } from "../base"; import { SystemLog } from "../../type/systemlog"; +import { JsonrpcNotification } from "../base"; /** * Represents a JSON-RPC Notification for sending the current system log. diff --git a/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesDataRequest.ts b/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesDataRequest.ts index 77146413230..170c5b8af7f 100644 --- a/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesDataRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesDataRequest.ts @@ -1,9 +1,9 @@ // @ts-strict-ignore -import { ChannelAddress } from "../../../shared/type/channeladdress"; import { format } from 'date-fns'; +import { Resolution } from "src/app/edge/history/shared"; +import { ChannelAddress } from "../../../shared/type/channeladdress"; import { JsonrpcRequest } from "../base"; import { JsonRpcUtils } from "../jsonrpcutils"; -import { Resolution } from "src/app/edge/history/shared"; /** * Represents a JSON-RPC Request to query Historic Timeseries Data. diff --git a/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesEnergyPerPeriodRequest.ts b/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesEnergyPerPeriodRequest.ts index c81fd430687..af0a86a679c 100644 --- a/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesEnergyPerPeriodRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesEnergyPerPeriodRequest.ts @@ -1,9 +1,9 @@ // @ts-strict-ignore -import { ChannelAddress } from "../../type/channeladdress"; import { format } from 'date-fns'; +import { Resolution } from "src/app/edge/history/shared"; +import { ChannelAddress } from "../../type/channeladdress"; import { JsonrpcRequest } from "../base"; import { JsonRpcUtils } from "../jsonrpcutils"; -import { Resolution } from "src/app/edge/history/shared"; /** * Represents a JSON-RPC Request to query Timeseries Energy data. diff --git a/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesEnergyRequest.ts b/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesEnergyRequest.ts index cd44298b563..054c45038b6 100644 --- a/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesEnergyRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesEnergyRequest.ts @@ -1,6 +1,6 @@ // @ts-strict-ignore -import { ChannelAddress } from "../../type/channeladdress"; import { format } from 'date-fns'; +import { ChannelAddress } from "../../type/channeladdress"; import { JsonrpcRequest } from "../base"; import { JsonRpcUtils } from "../jsonrpcutils"; diff --git a/ui/src/app/shared/legacy/chartoptions/chartoptions.component.html b/ui/src/app/shared/legacy/chartoptions/chartoptions.component.html index 33dd2721bb4..02980ba1e0d 100644 --- a/ui/src/app/shared/legacy/chartoptions/chartoptions.component.html +++ b/ui/src/app/shared/legacy/chartoptions/chartoptions.component.html @@ -1,3 +1,3 @@ - \ No newline at end of file + diff --git a/ui/src/app/shared/legacy/chartoptions/popover/popover.component.html b/ui/src/app/shared/legacy/chartoptions/popover/popover.component.html index 82bd75f8572..94793aee035 100644 --- a/ui/src/app/shared/legacy/chartoptions/popover/popover.component.html +++ b/ui/src/app/shared/legacy/chartoptions/popover/popover.component.html @@ -13,4 +13,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/shared/pipe/unitvalue/unitvalue.pipe.spec.ts b/ui/src/app/shared/pipe/unitvalue/unitvalue.pipe.spec.ts index bba039ef456..d6c567b4fa1 100644 --- a/ui/src/app/shared/pipe/unitvalue/unitvalue.pipe.spec.ts +++ b/ui/src/app/shared/pipe/unitvalue/unitvalue.pipe.spec.ts @@ -1,7 +1,7 @@ import { DecimalPipe, registerLocaleData } from "@angular/common"; import localDE from '@angular/common/locales/de'; -import { UnitvaluePipe } from "./unitvalue.pipe"; import { Language } from "../../type/language"; +import { UnitvaluePipe } from "./unitvalue.pipe"; describe('UnitvaluePipe', () => { registerLocaleData(localDE); diff --git a/ui/src/app/shared/service/service.ts b/ui/src/app/shared/service/service.ts index a0efd655628..1cd5bdfb98a 100644 --- a/ui/src/app/shared/service/service.ts +++ b/ui/src/app/shared/service/service.ts @@ -9,7 +9,6 @@ import { BehaviorSubject, Subject } from 'rxjs'; import { filter, first, take } from 'rxjs/operators'; import { ChosenFilter } from 'src/app/index/filter/filter.component'; import { environment } from 'src/environments'; - import { Edge } from '../components/edge/edge'; import { EdgeConfig } from '../components/edge/edgeconfig'; import { JsonrpcResponseError } from '../jsonrpc/base'; diff --git a/ui/src/app/shared/service/test/dummyservice.ts b/ui/src/app/shared/service/test/dummyservice.ts index e8b9cdc102f..58101b949a1 100644 --- a/ui/src/app/shared/service/test/dummyservice.ts +++ b/ui/src/app/shared/service/test/dummyservice.ts @@ -1,7 +1,6 @@ import { ActivatedRoute } from "@angular/router"; import { BehaviorSubject } from "rxjs"; import { SumState } from "src/app/index/shared/sumState"; - import { QueryHistoricTimeseriesEnergyResponse } from "../../jsonrpc/response/queryHistoricTimeseriesEnergyResponse"; import { ChannelAddress, Edge, EdgeConfig } from "../../shared"; import { Language } from "../../type/language"; @@ -62,8 +61,8 @@ export class DummyService extends AbstractService { isPartnerAllowed(edge: Edge): boolean { throw new Error("Method not implemented."); } - // https://v16.angular.io/api/core/ErrorHandler#errorhandler - // eslint-disable-next-line @typescript-eslint/no-explicit-any + // https://v16.angular.io/api/core/ErrorHandler#errorhandler + // eslint-disable-next-line @typescript-eslint/no-explicit-any override handleError(error: any): void { throw new Error("Method not implemented."); } diff --git a/ui/src/app/shared/service/test/dummywebsocket.ts b/ui/src/app/shared/service/test/dummywebsocket.ts index 04f579818f3..56d91ec80f1 100644 --- a/ui/src/app/shared/service/test/dummywebsocket.ts +++ b/ui/src/app/shared/service/test/dummywebsocket.ts @@ -1,4 +1,4 @@ -import { JsonrpcRequest, JsonrpcResponseSuccess, JsonrpcNotification } from "../../jsonrpc/base"; +import { JsonrpcNotification, JsonrpcRequest, JsonrpcResponseSuccess } from "../../jsonrpc/base"; import { AuthenticateWithPasswordRequest } from "../../jsonrpc/request/authenticateWithPasswordRequest"; import { AuthenticateWithTokenRequest } from "../../jsonrpc/request/authenticateWithTokenRequest"; import { WebsocketInterface } from "../websocketInterface"; diff --git a/ui/src/app/shared/shared.module.ts b/ui/src/app/shared/shared.module.ts index 7d6fc9ccbd2..de8f4e59542 100644 --- a/ui/src/app/shared/shared.module.ts +++ b/ui/src/app/shared/shared.module.ts @@ -10,7 +10,6 @@ import { FormlyIonicModule } from '@ngx-formly/ionic'; import { TranslateModule } from '@ngx-translate/core'; import { NgChartsModule } from 'ng2-charts'; import { NgxSpinnerModule } from "ngx-spinner"; - import { appRoutingProviders } from '../app-routing.module'; import { ComponentsModule } from './components/components.module'; import { MeterModule } from './components/edge/meter/meter.module'; diff --git a/ui/src/app/shared/type/language.ts b/ui/src/app/shared/type/language.ts index 4737bf4510a..2a4f71af9c7 100644 --- a/ui/src/app/shared/type/language.ts +++ b/ui/src/app/shared/type/language.ts @@ -2,8 +2,8 @@ import localDE from '@angular/common/locales/de'; import localEN from '@angular/common/locales/en'; import localES from '@angular/common/locales/es'; import localFR from '@angular/common/locales/fr'; -import localNL from '@angular/common/locales/nl'; import localJA from '@angular/common/locales/ja'; +import localNL from '@angular/common/locales/nl'; import { TranslateLoader } from "@ngx-translate/core"; import { Observable, of } from 'rxjs'; import cz from 'src/assets/i18n/cz.json'; @@ -11,8 +11,8 @@ import de from 'src/assets/i18n/de.json'; import en from 'src/assets/i18n/en.json'; import es from 'src/assets/i18n/es.json'; import fr from 'src/assets/i18n/fr.json'; -import nl from 'src/assets/i18n/nl.json'; import ja from 'src/assets/i18n/ja.json'; +import nl from 'src/assets/i18n/nl.json'; interface Translation { [key: string]: string | Translation; diff --git a/ui/src/app/shared/type/widget.ts b/ui/src/app/shared/type/widget.ts index f91e01905fd..367bc6fac51 100644 --- a/ui/src/app/shared/type/widget.ts +++ b/ui/src/app/shared/type/widget.ts @@ -75,7 +75,6 @@ export class Widgets { } public static parseWidgets(edge: Edge, config: EdgeConfig): Widgets { - const classes: string[] = Object.values(WidgetClass) // .filter(v => typeof v === 'string') .filter(clazz => { diff --git a/ui/src/app/user/user.component.html b/ui/src/app/user/user.component.html index 1f3f7407448..bc5370ebca3 100644 --- a/ui/src/app/user/user.component.html +++ b/ui/src/app/user/user.component.html @@ -17,9 +17,11 @@ Menu.name - {{ this.form?.model ? ((this.form?.model?.firstname ?? '') + ' ' + (this.form?.model?.lastname ?? '')).trim() : user.name }} - + {{ + this.form?.model + ? ((this.form?.model?.firstname ?? '') + ' ' + (this.form?.model?.lastname ?? '')).trim() + : user.name + }} diff --git a/ui/src/app/user/user.component.ts b/ui/src/app/user/user.component.ts index ee2ee865b0b..363937cb827 100644 --- a/ui/src/app/user/user.component.ts +++ b/ui/src/app/user/user.component.ts @@ -2,10 +2,9 @@ import { Component, OnInit } from '@angular/core'; import { FormGroup, Validators } from '@angular/forms'; import { ActivatedRoute } from '@angular/router'; +import { FormlyFieldConfig } from '@ngx-formly/core'; import { TranslateService } from '@ngx-translate/core'; import { Changelog } from 'src/app/changelog/view/component/changelog.constants'; - -import { FormlyFieldConfig } from '@ngx-formly/core'; import { environment } from '../../environments'; import { GetUserInformationRequest } from '../shared/jsonrpc/request/getUserInformationRequest'; import { SetUserInformationRequest } from '../shared/jsonrpc/request/setUserInformationRequest'; diff --git a/ui/src/assets/i18n/de.json b/ui/src/assets/i18n/de.json index 6f0d3426a53..3096991606a 100644 --- a/ui/src/assets/i18n/de.json +++ b/ui/src/assets/i18n/de.json @@ -974,4 +974,4 @@ "APP": { "FUNCTIONALITY_TEMPORARILY_NOT_AVAILABLE": "Diese Funktion ist vorübergehend in der App nicht verfügbar, verwenden Sie bitte dafür die Web-App." } -} \ No newline at end of file +} diff --git a/ui/src/assets/i18n/en.json b/ui/src/assets/i18n/en.json index 99aa7e38184..45f7388ab29 100644 --- a/ui/src/assets/i18n/en.json +++ b/ui/src/assets/i18n/en.json @@ -977,4 +977,4 @@ "APP": { "FUNCTIONALITY_TEMPORARILY_NOT_AVAILABLE": "This function is temporarily not available in the app, please use the web app instead." } -} \ No newline at end of file +} diff --git a/ui/src/global.scss b/ui/src/global.scss index f29dac900c2..e0007c5fbe7 100644 --- a/ui/src/global.scss +++ b/ui/src/global.scss @@ -250,6 +250,7 @@ formly-input-section { .alert-button-group { justify-content: space-between; + .alert-button { color: $primary-color; font-size: small; diff --git a/ui/src/main.ts b/ui/src/main.ts index 43c16a32c32..001a8fbd192 100644 --- a/ui/src/main.ts +++ b/ui/src/main.ts @@ -1,7 +1,7 @@ import { enableProdMode } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; -import { environment } from 'src/environments'; import { AppModule } from 'src/app/app.module'; +import { environment } from 'src/environments'; if (environment.production) { enableProdMode(); diff --git a/ui/src/polyfills.ts b/ui/src/polyfills.ts index 5aacd21714a..9c6628376e2 100644 --- a/ui/src/polyfills.ts +++ b/ui/src/polyfills.ts @@ -19,7 +19,7 @@ */ /** IE11 requires the following for NgClass support on SVG elements */ -import 'classlist.js'; // Run `npm install --save classlist.js`. +import 'classlist.js'; // Run `npm install --save classlist.js`. /** * Web Animations `@angular/platform-browser/animations` @@ -57,7 +57,7 @@ import './zone-flags'; /*************************************************************************************************** * Zone JS is required by default for Angular itself. */ -import 'zone.js/dist/zone'; // Included with Angular CLI. +import 'zone.js/dist/zone'; // Included with Angular CLI. /*************************************************************************************************** diff --git a/ui/src/test.ts b/ui/src/test.ts index d8e68564e1b..2d851fa6be3 100644 --- a/ui/src/test.ts +++ b/ui/src/test.ts @@ -8,6 +8,7 @@ // This file is required by karma.conf.js and loads recursively all the .spec and framework files import 'zone.js/testing'; + import { getTestBed } from '@angular/core/testing'; import { BrowserDynamicTestingModule, diff --git a/ui/src/themes/openems/root/site.webmanifest b/ui/src/themes/openems/root/site.webmanifest index 58e369e755e..b4bc8f030b2 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/tsconfig.app.json b/ui/tsconfig.app.json index da9cb8b9de2..82d91dc4a4d 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 87be9d5b3f1..092345b02e8 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 d00e0e9ea6063a35863548763341b7295ab160b3 Mon Sep 17 00:00:00 2001 From: Felix S <39899210+DerStoecki@users.noreply.github.com> Date: Tue, 13 Aug 2024 18:06:23 +0200 Subject: [PATCH 103/173] UI: AppCenter Index: Refresh after install/delete of an App (#2533) * Refresh Index after install/delete User gets feedback after installing an app. (Manual refresh was nec. before) Admins get Feedback after removing an app due to auto refresh. * renamed installedAnApp to appInstanceChange * added a takeUntil as suggested in the code review to unsubscribe --- ui/src/app/edge/settings/app/index.component.ts | 15 +++++++++++++-- ui/src/app/edge/settings/app/install.component.ts | 3 ++- ui/src/app/edge/settings/app/update.component.ts | 3 ++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/ui/src/app/edge/settings/app/index.component.ts b/ui/src/app/edge/settings/app/index.component.ts index 328e4f384f5..7540ea72633 100644 --- a/ui/src/app/edge/settings/app/index.component.ts +++ b/ui/src/app/edge/settings/app/index.component.ts @@ -1,10 +1,10 @@ // @ts-strict-ignore import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; +import { ActivatedRoute, NavigationEnd, NavigationExtras, Router } from '@angular/router'; import { IonPopover, ModalController } from '@ionic/angular'; import { TranslateService } from '@ngx-translate/core'; import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; +import { filter, switchMap, takeUntil } from 'rxjs/operators'; import { ComponentJsonApiRequest } from 'src/app/shared/jsonrpc/request/componentJsonApiRequest'; import { Role } from 'src/app/shared/type/role'; import { Environment, environment } from 'src/environments'; @@ -76,6 +76,17 @@ export class IndexComponent implements OnInit, OnDestroy { public ngOnInit() { this.init(); + this.router.events.pipe( + filter(event => event instanceof NavigationEnd), + switchMap(() => this.route.url), + takeUntil(this.stopOnDestroy), + ).subscribe(() => { + const navigationExtras = this.router.getCurrentNavigation()?.extras as NavigationExtras; + const appInstanceChange = navigationExtras?.state?.appInstanceChange; + if (appInstanceChange != null && appInstanceChange) { + this.init(); + } + }); } public ngOnDestroy(): void { diff --git a/ui/src/app/edge/settings/app/install.component.ts b/ui/src/app/edge/settings/app/install.component.ts index 18468365653..49d5591524b 100644 --- a/ui/src/app/edge/settings/app/install.component.ts +++ b/ui/src/app/edge/settings/app/install.component.ts @@ -180,7 +180,8 @@ export class InstallAppComponent implements OnInit, OnDestroy { } this.form.markAsPristine(); - this.router.navigate(['device/' + (this.edge.id) + '/settings/app/']); + const navigationExtras = { state: { appInstanceChange: true } }; + this.router.navigate(['device/' + (this.edge.id) + '/settings/app/'], navigationExtras); }) .catch(InstallAppComponent.errorToast(this.service, error => this.translate.instant('Edge.Config.App.failInstall', { error: error }))) .finally(() => { diff --git a/ui/src/app/edge/settings/app/update.component.ts b/ui/src/app/edge/settings/app/update.component.ts index 361070f1e21..a5cb88b67ea 100644 --- a/ui/src/app/edge/settings/app/update.component.ts +++ b/ui/src/app/edge/settings/app/update.component.ts @@ -138,7 +138,8 @@ export class UpdateAppComponent implements OnInit { })).then(response => { this.instances.splice(this.instances.indexOf(instance), 1); this.service.toast(this.translate.instant('Edge.Config.App.successDelete'), 'success'); - this.router.navigate(['device/' + (this.edge.id) + '/settings/app/']); + const navigationExtras = { state: { appInstanceChange: true } }; + this.router.navigate(['device/' + (this.edge.id) + '/settings/app/'], navigationExtras); }) .catch(InstallAppComponent.errorToast(this.service, error => this.translate.instant('Edge.Config.App.failDelete', { error: error }))) .finally(() => { From d1b10125c320c59710e13749cc49687928fb438d Mon Sep 17 00:00:00 2001 From: Hannes Date: Thu, 22 Aug 2024 14:20:12 +0200 Subject: [PATCH 104/173] Fix for Configuration & Status not populated Fully (#2738) * Update edgeconfig.ts * Update edgeconfig.ts * Removed Comments for concat --- ui/src/app/shared/components/edge/edgeconfig.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/app/shared/components/edge/edgeconfig.ts b/ui/src/app/shared/components/edge/edgeconfig.ts index 345c440e2cf..020caa6d9eb 100644 --- a/ui/src/app/shared/components/edge/edgeconfig.ts +++ b/ui/src/app/shared/components/edge/edgeconfig.ts @@ -588,7 +588,7 @@ export class EdgeConfig { for (const entry of factories) { const components: EdgeConfig.Component[] = []; for (const factory of entry.factories) { - components.concat(...this.getComponentsByFactory(factory.id)); + components.push(...this.getComponentsByFactory(factory.id)); } allComponents.push({ category: entry.category, From 21633deedb7586854a6a76850196e59ec2e3321f Mon Sep 17 00:00:00 2001 From: "Kai J." Date: Sun, 25 Aug 2024 22:21:17 +0200 Subject: [PATCH 105/173] UI: fix percentagebar svg (#2732) --- .../edge/live/common/storage/storage.component.html | 6 +++--- .../flat-widget-percentagebar.html | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) 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 ad219c8d17f..d7ffcb21081 100644 --- a/ui/src/app/edge/live/common/storage/storage.component.html +++ b/ui/src/app/edge/live/common/storage/storage.component.html @@ -16,9 +16,9 @@ - + diff --git a/ui/src/app/shared/components/flat/flat-widget-percentagebar/flat-widget-percentagebar.html b/ui/src/app/shared/components/flat/flat-widget-percentagebar/flat-widget-percentagebar.html index eba1a1964a0..5570abc71b8 100644 --- a/ui/src/app/shared/components/flat/flat-widget-percentagebar/flat-widget-percentagebar.html +++ b/ui/src/app/shared/components/flat/flat-widget-percentagebar/flat-widget-percentagebar.html @@ -1,8 +1,8 @@ - - - - + + + {{ displayValue | unitvalue: '%' }} From 6116728aa0b0ec8cf07c8f09cf0cfae484702213 Mon Sep 17 00:00:00 2001 From: Saeedniko <118315460+saeedniko@users.noreply.github.com> Date: Wed, 28 Aug 2024 11:27:08 +0200 Subject: [PATCH 106/173] Docs: use openems.io-theme repository in openems (#2754) Use https://github.com/OpenEMS/openems.io-theme as theme for the OpenEMS Docs Antora page at https://openems.github.io/openems.io/openems/latest/ --- doc/build/site.yml | 4 ++-- doc/build/uibundle_openems.zip | Bin 580960 -> 0 bytes .../ROOT/pages/backend/backend-to-backend.adoc | 1 - doc/modules/ROOT/pages/backend/build.adoc | 1 - doc/modules/ROOT/pages/backend/deploy.adoc | 1 - doc/modules/ROOT/pages/backend/metadata.adoc | 1 - doc/modules/ROOT/pages/backend/service.adoc | 1 - doc/modules/ROOT/pages/backend/timedata.adoc | 1 - .../pages/component-communication/index.adoc | 1 - .../pages/contribute/coding-guidelines.adoc | 1 - .../ROOT/pages/contribute/documentation.adoc | 1 - doc/modules/ROOT/pages/coreconcepts.adoc | 1 - doc/modules/ROOT/pages/edge/architecture.adoc | 1 - doc/modules/ROOT/pages/edge/bridge.adoc | 1 - doc/modules/ROOT/pages/edge/build.adoc | 1 - doc/modules/ROOT/pages/edge/configuration.adoc | 1 - doc/modules/ROOT/pages/edge/controller.adoc | 1 - doc/modules/ROOT/pages/edge/deploy.adoc | 1 - .../ROOT/pages/edge/device_service.adoc | 1 - doc/modules/ROOT/pages/edge/implement.adoc | 1 - doc/modules/ROOT/pages/edge/nature.adoc | 1 - doc/modules/ROOT/pages/edge/scheduler.adoc | 1 - doc/modules/ROOT/pages/edge/timedata.adoc | 1 - doc/modules/ROOT/pages/gettingstarted.adoc | 1 - doc/modules/ROOT/pages/intellij.adoc | 1 - doc/modules/ROOT/pages/simulation/gitpod.adoc | 1 - .../ROOT/pages/simulation/realtime.adoc | 1 - .../ROOT/pages/simulation/ui-history.adoc | 1 - doc/modules/ROOT/pages/ui/architecture.adoc | 1 - doc/modules/ROOT/pages/ui/build.adoc | 1 - .../ui/implementing-a-widget/introduction.adoc | 1 - doc/modules/ROOT/pages/ui/setup-ide.adoc | 1 - 32 files changed, 2 insertions(+), 32 deletions(-) delete mode 100644 doc/build/uibundle_openems.zip diff --git a/doc/build/site.yml b/doc/build/site.yml index 876e6391607..be6edfdcade 100644 --- a/doc/build/site.yml +++ b/doc/build/site.yml @@ -6,14 +6,14 @@ site: content: sources: - - url: ./../../ + - url: https://github.com/OpenEMS/openems.git edit_url: https://github.com/OpenEMS/openems/tree/{refname}/{path} branches: HEAD start_path: doc ui: bundle: - url: uibundle_openems.zip + url: https://github.com/OpenEMS/openems.io-theme/releases/latest/download/ui-bundle.zip output: dir: www diff --git a/doc/build/uibundle_openems.zip b/doc/build/uibundle_openems.zip deleted file mode 100644 index 2ed7adc83ec03e5b88208014814702f6b9060e07..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 580960 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

      wZfb8zH@0qP@&;#4KcuWF?4odv?!`KP%N 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

      N<&W)1-!~8a#Md^kcw$ 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%0D%nx$Y|36j1jnOoGP^9uCl~#%9+hQ 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

      _8t_<0iNL1 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 Date: Thu, 29 Aug 2024 09:38:03 +0200 Subject: [PATCH 107/173] Fix build (#2759) --- build.gradle | 13 ++++++++++--- doc/antora.yml | 2 +- doc/build.gradle | 11 ++++++++--- doc/build/site.yml | 4 ++-- io.openems.edge.evcs.spelsberg/readme.adoc | 6 +++--- 5 files changed, 24 insertions(+), 12 deletions(-) diff --git a/build.gradle b/build.gradle index 72457c55315..82249fb14f2 100644 --- a/build.gradle +++ b/build.gradle @@ -344,12 +344,19 @@ task copyBundleReadmes() { */ task buildAntoraDocs(dependsOn: copyBundleReadmes) { group 'Documentation' - dependsOn ":doc:buildAntoraDocs" + + def source = file("doc/build/www") + def output = file("${buildDir}/www") + doLast { + output.deleteDir() copy { - from "doc/build/www" - into "${buildDir}/www" + from source + into output } + source.deleteDir() + + println("Built ${output}!") } } diff --git a/doc/antora.yml b/doc/antora.yml index 44a009a71f4..e2a06e35be5 100644 --- a/doc/antora.yml +++ b/doc/antora.yml @@ -3,4 +3,4 @@ title: Open Energy Management System version: latest start_page: ROOT:introduction.adoc nav: -- modules/ROOT/nav.adoc + - modules/ROOT/nav.adoc diff --git a/doc/build.gradle b/doc/build.gradle index 4aaf5ee6b5a..100f1e0ffd9 100644 --- a/doc/build.gradle +++ b/doc/build.gradle @@ -12,11 +12,16 @@ node { task buildAntoraDocs(type: NodeTask) { dependsOn npmInstall script = file("build/node_modules/@antora/cli/bin/antora") - args = ["site.yml"] + args = ["--log-format=pretty", "site.yml"] + + def nojekyll = file("build/.nojekyll") + def source = file("build/CNAME") + def output = file("build/www") + doLast { copy { - from "build/.nojekyll", "build/CNAME" - into "build/www" + from nojekyll, source + into output } } } diff --git a/doc/build/site.yml b/doc/build/site.yml index be6edfdcade..79e4816da4f 100644 --- a/doc/build/site.yml +++ b/doc/build/site.yml @@ -6,8 +6,8 @@ site: content: sources: - - url: https://github.com/OpenEMS/openems.git - edit_url: https://github.com/OpenEMS/openems/tree/{refname}/{path} + - url: ./../../ + edit_url: https://github.com/OpenEMS/openems/tree/develop/{path} branches: HEAD start_path: doc diff --git a/io.openems.edge.evcs.spelsberg/readme.adoc b/io.openems.edge.evcs.spelsberg/readme.adoc index 00dc5bbffa0..5e972a157f1 100644 --- a/io.openems.edge.evcs.spelsberg/readme.adoc +++ b/io.openems.edge.evcs.spelsberg/readme.adoc @@ -5,7 +5,7 @@ Implementation of the Spelsberg SMART PRO charging station. This EVCS component implementation is not yet fully feature tested. Please consider it BETA quality. -=== Technical Data +== Technical Data * Rated current: 16A single and three phase * Charging cable: Type 2, up to 16A @@ -13,7 +13,7 @@ This EVCS component implementation is not yet fully feature tested. Please consi * Communication protocol: Modbus TCP -=== This implementation includes: +== This implementation includes: ** Reading of current and power from the EVCS ** Setting charge power/current via OpenEMS Edge EVCS Controller @@ -21,7 +21,7 @@ This EVCS component implementation is not yet fully feature tested. Please consi ** EVCS status updates ** Validation of Modbus TCP connection -=== Planned Features: +== Planned Features: ** Support for automatic phase shifting From fae53c21520df849343e7316376be61bca043b95 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 15:54:16 +0200 Subject: [PATCH 108/173] Build(deps): Bump org.jetbrains.kotlin:kotlin-osgi-bundle from 2.0.0 to 2.0.20 in /cnf (#2758) * Build(deps): Bump org.jetbrains.kotlin:kotlin-osgi-bundle in /cnf Bumps org.jetbrains.kotlin:kotlin-osgi-bundle from 2.0.0 to 2.0.20. --- updated-dependencies: - dependency-name: org.jetbrains.kotlin:kotlin-osgi-bundle 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 5483a448725..0b8026955b7 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -301,7 +301,7 @@ org.jetbrains.kotlin kotlin-osgi-bundle - 2.0.0 + 2.0.20 org.jetbrains.kotlinx diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index 1d0b0dde4e4..86353f9f27a 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -113,7 +113,7 @@ org.apache.felix.scr;version='[2.2.12,2.2.13)',\ org.apache.felix.webconsole;version='[5.0.6,5.0.7)',\ org.apache.felix.webconsole.plugins.ds;version='[2.3.0,2.3.1)',\ - org.jetbrains.kotlin.osgi-bundle;version='[2.0.0,2.0.1)',\ + org.jetbrains.kotlin.osgi-bundle;version='[2.0.20,2.0.21)',\ 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 46f4680d966..e1209754dfa 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -414,7 +414,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='[2.0.0,2.0.1)',\ + org.jetbrains.kotlin.osgi-bundle;version='[2.0.20,2.0.21)',\ org.jsoup;version='[1.18.1,1.18.2)',\ org.jsr-305;version='[3.0.2,3.0.3)',\ org.openmuc.jmbus;version='[3.3.0,3.3.1)',\ From 0e0aabf0366c7973bca430e39b992a3140add59a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 16:07:55 +0200 Subject: [PATCH 109/173] Build(deps): Bump io.reactivex.rxjava3:rxjava from 3.1.8 to 3.1.9 in /cnf (#2753) * Build(deps): Bump io.reactivex.rxjava3:rxjava in /cnf Bumps [io.reactivex.rxjava3:rxjava](https://github.com/ReactiveX/RxJava) from 3.1.8 to 3.1.9. - [Release notes](https://github.com/ReactiveX/RxJava/releases) - [Commits](https://github.com/ReactiveX/RxJava/compare/v3.1.8...v3.1.9) --- updated-dependencies: - dependency-name: io.reactivex.rxjava3:rxjava 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 0b8026955b7..2f0d9bd5be2 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -142,7 +142,7 @@ io.reactivex.rxjava3 rxjava - 3.1.8 + 3.1.9 diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index 86353f9f27a..7df1c1145b4 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -100,7 +100,7 @@ io.openems.wrapper.retrofit-converter-gson;version=snapshot,\ io.openems.wrapper.retrofit-converter-scalars;version=snapshot,\ io.openems.wrapper.retrofit2;version=snapshot,\ - io.reactivex.rxjava3.rxjava;version='[3.1.8,3.1.9)',\ + io.reactivex.rxjava3.rxjava;version='[3.1.9,3.1.10)',\ org.apache.commons.commons-compress;version='[1.26.2,1.26.3)',\ org.apache.commons.commons-csv;version='[1.10.0,1.10.1)',\ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index e1209754dfa..603edfffe9b 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -393,7 +393,7 @@ io.openems.wrapper.retrofit-converter-scalars;version=snapshot,\ io.openems.wrapper.retrofit2;version=snapshot,\ io.openems.wrapper.sdnotify;version=snapshot,\ - io.reactivex.rxjava3.rxjava;version='[3.1.8,3.1.9)',\ + io.reactivex.rxjava3.rxjava;version='[3.1.9,3.1.10)',\ javax.jmdns;version='[3.4.1,3.4.2)',\ javax.xml.soap-api;version='[1.4.0,1.4.1)',\ org.apache.commons.commons-compress;version='[1.26.2,1.26.3)',\ From b650e888a40f4e15d482fdc3eaeb310a4dad838c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 16:29:44 +0200 Subject: [PATCH 110/173] Build(deps): Bump com.influxdb:influxdb from 7.1.0 to 7.2.0 in /cnf (#2744) * Build(deps): Bump com.influxdb:influxdb-client-core in /cnf Bumps [com.influxdb:influxdb-client-core](https://github.com/influxdata/influxdb-client-java) from 7.1.0 to 7.2.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/v7.1.0...v7.2.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] * Build(deps): Bump com.influxdb:flux-dsl from 7.1.0 to 7.2.0 in /cnf Bumps [com.influxdb:flux-dsl](https://github.com/influxdata/influxdb-client-java) from 7.1.0 to 7.2.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/v7.1.0...v7.2.0) --- updated-dependencies: - dependency-name: com.influxdb:flux-dsl dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Build(deps): Bump com.influxdb:influxdb-client-java in /cnf Bumps [com.influxdb:influxdb-client-java](https://github.com/influxdata/influxdb-client-java) from 7.1.0 to 7.2.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/v7.1.0...v7.2.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] * Build(deps): Bump com.influxdb:influxdb-client-utils in /cnf Bumps [com.influxdb:influxdb-client-utils](https://github.com/influxdata/influxdb-client-java) from 7.1.0 to 7.2.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/v7.1.0...v7.2.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] * Update bnd --------- 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.backend.application/BackendApp.bndrun | 4 +++- io.openems.edge.application/EdgeApp.bndrun | 4 +++- 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 ++-- 7 files changed, 18 insertions(+), 14 deletions(-) diff --git a/cnf/pom.xml b/cnf/pom.xml index 2f0d9bd5be2..6e19ea4a87e 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -276,22 +276,22 @@ com.influxdb influxdb-client-java - 7.1.0 + 7.2.0 com.influxdb influxdb-client-core - 7.1.0 + 7.2.0 com.influxdb influxdb-client-utils - 7.1.0 + 7.2.0 com.influxdb flux-dsl - 7.1.0 + 7.2.0 org.java-websocket diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index 7df1c1145b4..11760f6ee1e 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -101,8 +101,10 @@ io.openems.wrapper.retrofit-converter-scalars;version=snapshot,\ io.openems.wrapper.retrofit2;version=snapshot,\ io.reactivex.rxjava3.rxjava;version='[3.1.9,3.1.10)',\ + org.apache.commons.commons-codec;version='[1.17.0,1.17.1)',\ org.apache.commons.commons-compress;version='[1.26.2,1.26.3)',\ - org.apache.commons.commons-csv;version='[1.10.0,1.10.1)',\ + org.apache.commons.commons-csv;version='[1.11.0,1.11.1)',\ + org.apache.commons.commons-io;version='[2.16.1,2.16.2)',\ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ org.apache.felix.eventadmin;version='[1.6.4,1.6.5)',\ org.apache.felix.fileinstall;version='[3.7.4,3.7.5)',\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index 603edfffe9b..e317511eab6 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -396,8 +396,10 @@ io.reactivex.rxjava3.rxjava;version='[3.1.9,3.1.10)',\ javax.jmdns;version='[3.4.1,3.4.2)',\ javax.xml.soap-api;version='[1.4.0,1.4.1)',\ + org.apache.commons.commons-codec;version='[1.17.0,1.17.1)',\ org.apache.commons.commons-compress;version='[1.26.2,1.26.3)',\ - org.apache.commons.commons-csv;version='[1.10.0,1.10.1)',\ + org.apache.commons.commons-csv;version='[1.11.0,1.11.1)',\ + org.apache.commons.commons-io;version='[2.16.1,2.16.2)',\ org.apache.commons.math3;version='[3.6.1,3.6.2)',\ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ org.apache.felix.eventadmin;version='[1.6.4,1.6.5)',\ diff --git a/io.openems.wrapper/influxdb-client-core.bnd b/io.openems.wrapper/influxdb-client-core.bnd index 7798c9f3287..051a463b074 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: 7.1.0 +Bundle-Version: 7.2.0 Include-Resource: \ - @influxdb-client-core-7.1.0.jar,\ + @influxdb-client-core-7.2.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 d104a2e8891..577af489e58 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: 7.1.0 +Bundle-Version: 7.2.0 Include-Resource: \ - @influxdb-client-java-7.1.0.jar,\ + @influxdb-client-java-7.2.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 32ffc20d813..d272fc79b37 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: 7.1.0 +Bundle-Version: 7.2.0 Include-Resource: \ - @influxdb-client-utils-7.1.0.jar,\ + @influxdb-client-utils-7.2.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 d7c95c16634..98b1eac6822 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: 7.1.0 +Bundle-Version: 7.2.0 Include-Resource: \ - @flux-dsl-7.1.0.jar,\ + @flux-dsl-7.2.0.jar,\ Export-Package: \ com.influxdb.query,\ From 8edaa796b373b76001045237fb9a7810235b9a47 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 21:58:11 +0200 Subject: [PATCH 111/173] Build(deps): Bump @capacitor/core from 5.7.7 to 5.7.8 in /ui (#2741) Bumps [@capacitor/core](https://github.com/ionic-team/capacitor) from 5.7.7 to 5.7.8. - [Release notes](https://github.com/ionic-team/capacitor/releases) - [Changelog](https://github.com/ionic-team/capacitor/blob/5.7.8/CHANGELOG.md) - [Commits](https://github.com/ionic-team/capacitor/compare/5.7.7...5.7.8) --- updated-dependencies: - dependency-name: "@capacitor/core" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 9 ++++----- ui/package.json | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 43a20ab0945..03807d1468f 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -20,7 +20,7 @@ "@capacitor-community/file-opener": "^1.0.5", "@capacitor/android": "5.7.7", "@capacitor/app": "^5.0.6", - "@capacitor/core": "5.7.7", + "@capacitor/core": "5.7.8", "@capacitor/filesystem": "^5.2.0", "@capacitor/ios": "5.7.7", "@capacitor/splash-screen": "^5.0.6", @@ -3740,10 +3740,9 @@ } }, "node_modules/@capacitor/core": { - "version": "5.7.7", - "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-5.7.7.tgz", - "integrity": "sha512-LeV1ljAihl/1lFGHZERNY2DtD1fbPBF3rNOSHFPMXIluK4Cq4nK4a4z/dLPX+Cv4F0TyCIzX3+/t79PMbhDwrg==", - "license": "MIT", + "version": "5.7.8", + "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-5.7.8.tgz", + "integrity": "sha512-rrZcm/2vJM0WdWRQup1TUidbjQV9PfIadSkV4rAGLD7R6PuzZSMPGT0gmoZzCRlXkqrazrWWDkurei3ozU02FA==", "dependencies": { "tslib": "^2.1.0" } diff --git a/ui/package.json b/ui/package.json index 667c971c560..32b1c126036 100644 --- a/ui/package.json +++ b/ui/package.json @@ -15,7 +15,7 @@ "@capacitor-community/file-opener": "^1.0.5", "@capacitor/android": "5.7.7", "@capacitor/app": "^5.0.6", - "@capacitor/core": "5.7.7", + "@capacitor/core": "5.7.8", "@capacitor/filesystem": "^5.2.0", "@capacitor/ios": "5.7.7", "@capacitor/splash-screen": "^5.0.6", From a3a0f967d661f2659378d9dc8adc2d9480bfd6c3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 21:58:29 +0200 Subject: [PATCH 112/173] Build(deps): Bump @capacitor/ios from 5.7.7 to 5.7.8 in /ui (#2748) Bumps [@capacitor/ios](https://github.com/ionic-team/capacitor) from 5.7.7 to 5.7.8. - [Release notes](https://github.com/ionic-team/capacitor/releases) - [Changelog](https://github.com/ionic-team/capacitor/blob/5.7.8/CHANGELOG.md) - [Commits](https://github.com/ionic-team/capacitor/compare/5.7.7...5.7.8) --- updated-dependencies: - dependency-name: "@capacitor/ios" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 9 ++++----- ui/package.json | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 03807d1468f..94fc0190729 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -22,7 +22,7 @@ "@capacitor/app": "^5.0.6", "@capacitor/core": "5.7.8", "@capacitor/filesystem": "^5.2.0", - "@capacitor/ios": "5.7.7", + "@capacitor/ios": "5.7.8", "@capacitor/splash-screen": "^5.0.6", "@ionic-native/core": "^5.36.0", "@ionic-native/file-opener": "^5.36.0", @@ -3757,10 +3757,9 @@ } }, "node_modules/@capacitor/ios": { - "version": "5.7.7", - "resolved": "https://registry.npmjs.org/@capacitor/ios/-/ios-5.7.7.tgz", - "integrity": "sha512-bgvSJGia5C5Klfd7t/qlqlRAWzGGAwlIlzkOJYsxpJiYuz6OXVgeesuXRxMNOaUZQ9fmL7OWukmhcv03t9Up+w==", - "license": "MIT", + "version": "5.7.8", + "resolved": "https://registry.npmjs.org/@capacitor/ios/-/ios-5.7.8.tgz", + "integrity": "sha512-XhGrziBnlRmCJ97LdPXOJquHPpYTwSJZIxYSXuPl7SDDuAEve8vs2wY76gLdaaFH2Z6ctdugUX+jR6VNu+ds+w==", "peerDependencies": { "@capacitor/core": "^5.7.0" } diff --git a/ui/package.json b/ui/package.json index 32b1c126036..5db7462df40 100644 --- a/ui/package.json +++ b/ui/package.json @@ -17,7 +17,7 @@ "@capacitor/app": "^5.0.6", "@capacitor/core": "5.7.8", "@capacitor/filesystem": "^5.2.0", - "@capacitor/ios": "5.7.7", + "@capacitor/ios": "5.7.8", "@capacitor/splash-screen": "^5.0.6", "@ionic-native/core": "^5.36.0", "@ionic-native/file-opener": "^5.36.0", From 4c577bc65f5acc1d54164e28786c1cc5275ae4ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 22:16:23 +0200 Subject: [PATCH 113/173] Build(deps): Bump @capacitor/android from 5.7.7 to 5.7.8 in /ui (#2749) * Build(deps): Bump @capacitor/android from 5.7.7 to 5.7.8 in /ui Bumps [@capacitor/android](https://github.com/ionic-team/capacitor) from 5.7.7 to 5.7.8. - [Release notes](https://github.com/ionic-team/capacitor/releases) - [Changelog](https://github.com/ionic-team/capacitor/blob/5.7.8/CHANGELOG.md) - [Commits](https://github.com/ionic-team/capacitor/compare/5.7.7...5.7.8) --- updated-dependencies: - dependency-name: "@capacitor/android" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Build(deps): Bump @capacitor/android from 5.7.7 to 5.7.8 in /ui Bumps [@capacitor/android](https://github.com/ionic-team/capacitor) from 5.7.7 to 5.7.8. - [Release notes](https://github.com/ionic-team/capacitor/releases) - [Changelog](https://github.com/ionic-team/capacitor/blob/5.7.8/CHANGELOG.md) - [Commits](https://github.com/ionic-team/capacitor/compare/5.7.7...5.7.8) --- updated-dependencies: - dependency-name: "@capacitor/android" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Group dependabot PRs - https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#groups - https://github.com/eve-val/eve-roster/pull/1815/files * Dependabot: add more groups --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- .github/dependabot.yml | 62 ++++++++++++++++++++++++++++++------------ ui/package-lock.json | 9 +++--- ui/package.json | 2 +- 3 files changed, 49 insertions(+), 24 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 21080d06c45..ac7721a4511 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,20 +1,46 @@ version: 2 updates: -- package-ecosystem: maven - directory: "/cnf" - schedule: - interval: weekly - open-pull-requests-limit: 10 - target-branch: develop -- package-ecosystem: npm - directory: "/ui" - schedule: - interval: weekly - open-pull-requests-limit: 10 - target-branch: develop -- package-ecosystem: "github-actions" - directory: "/.github/workflows" - schedule: - interval: "weekly" - open-pull-requests-limit: 10 - target-branch: develop + - package-ecosystem: maven + directory: "/cnf" + schedule: + interval: weekly + open-pull-requests-limit: 10 + target-branch: develop + + - package-ecosystem: npm + directory: "/ui" + schedule: + interval: weekly + open-pull-requests-limit: 10 + target-branch: develop + groups: + angular: + patterns: + - "@angular/*" + capacitor: + patterns: + - "@capacitor/*" + ionic-native: + patterns: + - "@ionic-native/*" + ngx-formly: + patterns: + - "@ngx-formly/*" + karma: + patterns: + - "karma-*" + - "karma" + eslint: + patterns: + - "@angular-eslint/*" + - "@stylistic/eslint-plugin" + - "@typescript-eslint/*" + - "eslint-*" + - "eslint" + + - package-ecosystem: "github-actions" + directory: "/.github/workflows" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + target-branch: develop diff --git a/ui/package-lock.json b/ui/package-lock.json index 94fc0190729..e152abb7551 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -18,7 +18,7 @@ "@angular/router": "~16.2.12", "@angular/service-worker": "~16.2.12", "@capacitor-community/file-opener": "^1.0.5", - "@capacitor/android": "5.7.7", + "@capacitor/android": "5.7.8", "@capacitor/app": "^5.0.6", "@capacitor/core": "5.7.8", "@capacitor/filesystem": "^5.2.0", @@ -3228,10 +3228,9 @@ } }, "node_modules/@capacitor/android": { - "version": "5.7.7", - "resolved": "https://registry.npmjs.org/@capacitor/android/-/android-5.7.7.tgz", - "integrity": "sha512-gkc8p0jjbRHu5oxKvWQV1d6zRHNeK7/GQUHOL9J6yQqnnttLDf1tSZ4BVjicMdyKlxUailuBcboWvng+KYilvQ==", - "license": "MIT", + "version": "5.7.8", + "resolved": "https://registry.npmjs.org/@capacitor/android/-/android-5.7.8.tgz", + "integrity": "sha512-ooWclwcuW0dy3YfqgoozkHkjatX8H2fb2/RwRsJa3cew1P1lUXIXri3Dquuy4LdqFAJA7UHcJ19Bl/6UKdsZYA==", "peerDependencies": { "@capacitor/core": "^5.7.0" } diff --git a/ui/package.json b/ui/package.json index 5db7462df40..dd5a7f195b1 100644 --- a/ui/package.json +++ b/ui/package.json @@ -13,7 +13,7 @@ "@angular/router": "~16.2.12", "@angular/service-worker": "~16.2.12", "@capacitor-community/file-opener": "^1.0.5", - "@capacitor/android": "5.7.7", + "@capacitor/android": "5.7.8", "@capacitor/app": "^5.0.6", "@capacitor/core": "5.7.8", "@capacitor/filesystem": "^5.2.0", From 524fca94cbe8f3b11c9e169c6c75da87e0b2e94f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 22:16:58 +0200 Subject: [PATCH 114/173] Build(deps-dev): Bump @capacitor/cli from 6.1.1 to 6.1.2 in /ui (#2750) Bumps [@capacitor/cli](https://github.com/ionic-team/capacitor) from 6.1.1 to 6.1.2. - [Release notes](https://github.com/ionic-team/capacitor/releases) - [Changelog](https://github.com/ionic-team/capacitor/blob/main/CHANGELOG.md) - [Commits](https://github.com/ionic-team/capacitor/compare/6.1.1...6.1.2) --- updated-dependencies: - dependency-name: "@capacitor/cli" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 9 ++++----- ui/package.json | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index e152abb7551..e7e618b800d 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -68,7 +68,7 @@ "@angular/compiler-cli": "^16.2.12", "@angular/language-service": "^16.2.12", "@capacitor/assets": "^3.0.0", - "@capacitor/cli": "6.1.1", + "@capacitor/cli": "6.1.2", "@ionic/angular-toolkit": "^11.0.1", "@stylistic/eslint-plugin": "^2.4.0", "@types/jasmine": "~4.3.6", @@ -3451,11 +3451,10 @@ } }, "node_modules/@capacitor/cli": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@capacitor/cli/-/cli-6.1.1.tgz", - "integrity": "sha512-rsRqEadfnBSUX90RZj59oXvi30bpSusLMfIcgbOIArOloTgfaaWr9R471F6m3gGWF7BhNoskJpZcCgSUsfywwA==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@capacitor/cli/-/cli-6.1.2.tgz", + "integrity": "sha512-HKCNGE0RP8U7aiEF2vg5wTivJROS8BVfu8a3yYJb1mRQvzv+czpmtHNsTWS/WukvwoxUjyjRmsNQSAACHfMTmQ==", "dev": true, - "license": "MIT", "dependencies": { "@ionic/cli-framework-output": "^2.2.5", "@ionic/utils-fs": "^3.1.6", diff --git a/ui/package.json b/ui/package.json index dd5a7f195b1..2d255880924 100644 --- a/ui/package.json +++ b/ui/package.json @@ -63,7 +63,7 @@ "@angular/compiler-cli": "^16.2.12", "@angular/language-service": "^16.2.12", "@capacitor/assets": "^3.0.0", - "@capacitor/cli": "6.1.1", + "@capacitor/cli": "6.1.2", "@ionic/angular-toolkit": "^11.0.1", "@stylistic/eslint-plugin": "^2.4.0", "@types/jasmine": "~4.3.6", From 483facaad8de7b4720e4f842f874db99a3d5f01f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 22:17:33 +0200 Subject: [PATCH 115/173] Build(deps-dev): Bump axios from 1.6.8 to 1.7.5 in /ui (#2760) Bumps [axios](https://github.com/axios/axios) from 1.6.8 to 1.7.5. - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md) - [Commits](https://github.com/axios/axios/compare/v1.6.8...v1.7.5) --- updated-dependencies: - dependency-name: axios dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 151 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 147 insertions(+), 4 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index e7e618b800d..be2ff6ae782 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -5450,6 +5450,150 @@ "dev": true, "license": "ISC" }, + "node_modules/@nx/nx-darwin-arm64": { + "version": "16.5.1", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-16.5.1.tgz", + "integrity": "sha512-q98TFI4B/9N9PmKUr1jcbtD4yAFs1HfYd9jUXXTQOlfO9SbDjnrYJgZ4Fp9rMNfrBhgIQ4x1qx0AukZccKmH9Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nx/nx-darwin-x64": { + "version": "16.5.1", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-16.5.1.tgz", + "integrity": "sha512-j9HmL1l8k7EVJ3eOM5y8COF93gqrydpxCDoz23ZEtsY+JHY77VAiRQsmqBgEx9GGA2dXi9VEdS67B0+1vKariw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nx/nx-freebsd-x64": { + "version": "16.5.1", + "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-16.5.1.tgz", + "integrity": "sha512-CXSPT01aVS869tvCCF2tZ7LnCa8l41wJ3mTVtWBkjmRde68E5Up093hklRMyXb3kfiDYlfIKWGwrV4r0eH6x1A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nx/nx-linux-arm-gnueabihf": { + "version": "16.5.1", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-16.5.1.tgz", + "integrity": "sha512-BhrumqJSZCWFfLFUKl4CAUwR0Y0G2H5EfFVGKivVecEQbb+INAek1aa6c89evg2/OvetQYsJ+51QknskwqvLsA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nx/nx-linux-arm64-gnu": { + "version": "16.5.1", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-16.5.1.tgz", + "integrity": "sha512-x7MsSG0W+X43WVv7JhiSq2eKvH2suNKdlUHEG09Yt0vm3z0bhtym1UCMUg3IUAK7jy9hhLeDaFVFkC6zo+H/XQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nx/nx-linux-arm64-musl": { + "version": "16.5.1", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-16.5.1.tgz", + "integrity": "sha512-J+/v/mFjOm74I0PNtH5Ka+fDd+/dWbKhpcZ2R1/6b9agzZk+Ff/SrwJcSYFXXWKbPX+uQ4RcJoytT06Zs3s0ow==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nx/nx-linux-x64-gnu": { + "version": "16.5.1", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-16.5.1.tgz", + "integrity": "sha512-igooWJ5YxQ94Zft7IqgL+Lw0qHaY15Btw4gfK756g/YTYLZEt4tTvR1y6RnK/wdpE3sa68bFTLVBNCGTyiTiDQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nx/nx-linux-x64-musl": { + "version": "16.5.1", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-16.5.1.tgz", + "integrity": "sha512-zF/exnPqFYbrLAduGhTmZ7zNEyADid2bzNQiIjJkh8Y6NpDwrQIwVIyvIxqynsjMrIs51kBH+8TUjKjj2Jgf5A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nx/nx-win32-arm64-msvc": { + "version": "16.5.1", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-16.5.1.tgz", + "integrity": "sha512-qtqiLS9Y9TYyAbbpq58kRoOroko4ZXg5oWVqIWFHoxc5bGPweQSJCROEqd1AOl2ZDC6BxfuVHfhDDop1kK05WA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@nx/nx-win32-x64-msvc": { "version": "16.5.1", "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-16.5.1.tgz", @@ -8188,11 +8332,10 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", - "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.5.tgz", + "integrity": "sha512-fZu86yCo+svH3uqJ/yTdQ0QHpQu5oL+/QE+QPSv6BZSkDAoky9vytxp7u5qk83OJFS3kEBcesWni9WTZAv3tSw==", "dev": true, - "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", From 12f2c9c1f251caef91623d13ed3fc9fe749b4744 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 22:18:18 +0200 Subject: [PATCH 116/173] Build(deps): Bump webpack and @angular-devkit/build-angular in /ui (#2761) Bumps [webpack](https://github.com/webpack/webpack) to 5.94.0 and updates ancestor dependency [@angular-devkit/build-angular](https://github.com/angular/angular-cli). These dependencies need to be updated together. Updates `webpack` from 5.88.2 to 5.94.0 - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v5.88.2...v5.94.0) Updates `@angular-devkit/build-angular` from 16.2.14 to 16.2.15 - [Release notes](https://github.com/angular/angular-cli/releases) - [Changelog](https://github.com/angular/angular-cli/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular-cli/compare/16.2.14...16.2.15) --- updated-dependencies: - dependency-name: webpack dependency-type: indirect - dependency-name: "@angular-devkit/build-angular" dependency-type: direct:development ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 455 ++++++++++--------------------------------- ui/package.json | 2 +- 2 files changed, 100 insertions(+), 357 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index be2ff6ae782..5b3db5a9f2e 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -58,7 +58,7 @@ "zone.js": "~0.13.3" }, "devDependencies": { - "@angular-devkit/build-angular": "^16.2.14", + "@angular-devkit/build-angular": "^16.2.15", "@angular-eslint/builder": "^16.3.1", "@angular-eslint/eslint-plugin": "^16.3.1", "@angular-eslint/eslint-plugin-template": "^16.3.1", @@ -147,16 +147,15 @@ } }, "node_modules/@angular-devkit/build-angular": { - "version": "16.2.14", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-16.2.14.tgz", - "integrity": "sha512-bXQ6i7QPhwmYHuh+DSNkBhjTIHQF0C6fqZEg2ApJA3NmnzE98oQnmJ9AnGnAkdf1Mjn3xi2gxoZWPDDxGEINMw==", + "version": "16.2.15", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-16.2.15.tgz", + "integrity": "sha512-gw9wQENYVNUCB2bnzk0yKd6YGlemDwuwKnrPnSm4myyMuScZpW+e+zliGW+JXRuVWZqiTJNcdd58e4CrrreILg==", "dev": true, - "license": "MIT", "dependencies": { "@ampproject/remapping": "2.2.1", - "@angular-devkit/architect": "0.1602.14", - "@angular-devkit/build-webpack": "0.1602.14", - "@angular-devkit/core": "16.2.14", + "@angular-devkit/architect": "0.1602.15", + "@angular-devkit/build-webpack": "0.1602.15", + "@angular-devkit/core": "16.2.15", "@babel/core": "7.22.9", "@babel/generator": "7.22.9", "@babel/helper-annotate-as-pure": "7.22.5", @@ -168,7 +167,7 @@ "@babel/runtime": "7.22.6", "@babel/template": "7.22.5", "@discoveryjs/json-ext": "0.5.7", - "@ngtools/webpack": "16.2.14", + "@ngtools/webpack": "16.2.15", "@vitejs/plugin-basic-ssl": "1.0.1", "ansi-colors": "4.1.3", "autoprefixer": "10.4.14", @@ -212,7 +211,7 @@ "tree-kill": "1.2.2", "tslib": "2.6.1", "vite": "4.5.3", - "webpack": "5.88.2", + "webpack": "5.94.0", "webpack-dev-middleware": "6.1.2", "webpack-dev-server": "4.15.1", "webpack-merge": "5.9.0", @@ -284,13 +283,12 @@ } }, "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/architect": { - "version": "0.1602.14", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.14.tgz", - "integrity": "sha512-eSdONEV5dbtLNiOMBy9Ue9DdJ1ct6dH9RdZfYiedq6VZn0lejePAjY36MYVXgq2jTE+v/uIiaNy7caea5pt55A==", + "version": "0.1602.15", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.15.tgz", + "integrity": "sha512-+yPlUG5c8l7Z/A6dyeV7NQjj4WDWnWWQt+8eW/KInwVwoYiM32ntTJ0M4uU/aDdHuwKQnMLly28AcSWPWKYf2Q==", "dev": true, - "license": "MIT", "dependencies": { - "@angular-devkit/core": "16.2.14", + "@angular-devkit/core": "16.2.15", "rxjs": "7.8.1" }, "engines": { @@ -300,11 +298,10 @@ } }, "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core": { - "version": "16.2.14", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.14.tgz", - "integrity": "sha512-Ui14/d2+p7lnmXlK/AX2ieQEGInBV75lonNtPQgwrYgskF8ufCuN0DyVZQUy9fJDkC+xQxbJyYrby/BS0R0e7w==", + "version": "16.2.15", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.15.tgz", + "integrity": "sha512-68BgPWpcjNKz++uvLFG8IZaOH3ti2BWQVqaE3yTIYaMoNt0y0A0X2MUVd7EGbAGUk2JdloWJv5LTPVZMzCuK4w==", "dev": true, - "license": "MIT", "dependencies": { "ajv": "8.12.0", "ajv-formats": "2.1.1", @@ -327,36 +324,11 @@ } } }, - "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core/node_modules/source-map": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", "dev": true, - "license": "BSD-3-Clause", "engines": { "node": ">= 8" } @@ -430,33 +402,6 @@ "node": ">=6.9.0" } }, - "node_modules/@angular-devkit/build-angular/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "ajv": "^6.9.1" - } - }, "node_modules/@angular-devkit/build-angular/node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -481,19 +426,11 @@ "node": ">=8.6.0" } }, - "node_modules/@angular-devkit/build-angular/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, "node_modules/@angular-devkit/build-angular/node_modules/jsonc-parser": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@angular-devkit/build-angular/node_modules/less": { "version": "4.1.3", @@ -576,30 +513,10 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, - "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } }, - "node_modules/@angular-devkit/build-angular/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/@angular-devkit/build-angular/node_modules/semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -653,54 +570,6 @@ "dev": true, "license": "0BSD" }, - "node_modules/@angular-devkit/build-angular/node_modules/webpack": { - "version": "5.88.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz", - "integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.0", - "@webassemblyjs/ast": "^1.11.5", - "@webassemblyjs/wasm-edit": "^1.11.5", - "@webassemblyjs/wasm-parser": "^1.11.5", - "acorn": "^8.7.1", - "acorn-import-assertions": "^1.9.0", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.15.0", - "es-module-lexer": "^1.2.1", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.2.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.7", - "watchpack": "^2.4.0", - "webpack-sources": "^3.2.3" - }, - "bin": { - "webpack": "bin/webpack.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, "node_modules/@angular-devkit/build-angular/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -709,13 +578,12 @@ "license": "ISC" }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.1602.14", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1602.14.tgz", - "integrity": "sha512-f+ZTCjOoA1SCQEaX3L/63ubqr/vlHkwDXAtKjBsQgyz6srnETcjy96Us5k/LoK7/hPc85zFneqLinfqOMVWHJQ==", + "version": "0.1602.15", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1602.15.tgz", + "integrity": "sha512-ms1+vCDdV0KX8BplJ7JoKH3wKjWHxxZTOX+mSPIjt4wS1uAk5DnezXHIjpBiJ3HY9XVHFI9C0HT4n7o6kFIOEQ==", "dev": true, - "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.1602.14", + "@angular-devkit/architect": "0.1602.15", "rxjs": "7.8.1" }, "engines": { @@ -729,13 +597,12 @@ } }, "node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/architect": { - "version": "0.1602.14", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.14.tgz", - "integrity": "sha512-eSdONEV5dbtLNiOMBy9Ue9DdJ1ct6dH9RdZfYiedq6VZn0lejePAjY36MYVXgq2jTE+v/uIiaNy7caea5pt55A==", + "version": "0.1602.15", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.15.tgz", + "integrity": "sha512-+yPlUG5c8l7Z/A6dyeV7NQjj4WDWnWWQt+8eW/KInwVwoYiM32ntTJ0M4uU/aDdHuwKQnMLly28AcSWPWKYf2Q==", "dev": true, - "license": "MIT", "dependencies": { - "@angular-devkit/core": "16.2.14", + "@angular-devkit/core": "16.2.15", "rxjs": "7.8.1" }, "engines": { @@ -745,11 +612,10 @@ } }, "node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/core": { - "version": "16.2.14", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.14.tgz", - "integrity": "sha512-Ui14/d2+p7lnmXlK/AX2ieQEGInBV75lonNtPQgwrYgskF8ufCuN0DyVZQUy9fJDkC+xQxbJyYrby/BS0R0e7w==", + "version": "16.2.15", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.15.tgz", + "integrity": "sha512-68BgPWpcjNKz++uvLFG8IZaOH3ti2BWQVqaE3yTIYaMoNt0y0A0X2MUVd7EGbAGUk2JdloWJv5LTPVZMzCuK4w==", "dev": true, - "license": "MIT", "dependencies": { "ajv": "8.12.0", "ajv-formats": "2.1.1", @@ -776,15 +642,13 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@angular-devkit/build-webpack/node_modules/rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, - "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -4982,15 +4846,13 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@ngtools/webpack": { - "version": "16.2.14", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-16.2.14.tgz", - "integrity": "sha512-3+zPP3Wir46qrZ3FEiTz5/emSoVHYUCH+WgBmJ57mZCx1qBOYh2VgllnPr/Yusl1sc/jUZjdwq/es/9ZNw+zDQ==", + "version": "16.2.15", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-16.2.15.tgz", + "integrity": "sha512-rD4IHt3nS6PdIKvmoqwIadMIGKsemBSz412kD8Deetl0TiCVhD/Tn1M00dxXzMSHSFCQcOKxdZAeD53yRwTOOA==", "dev": true, - "license": "MIT", "engines": { "node": "^16.14.0 || >=18.10.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", @@ -6485,7 +6347,6 @@ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", "dev": true, - "license": "MIT", "dependencies": { "@types/connect": "*", "@types/node": "*" @@ -6496,7 +6357,6 @@ "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -6506,7 +6366,6 @@ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -6516,7 +6375,6 @@ "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", "dev": true, - "license": "MIT", "dependencies": { "@types/express-serve-static-core": "*", "@types/node": "*" @@ -6556,17 +6414,6 @@ "@types/json-schema": "*" } }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, "node_modules/@types/estree": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", @@ -6579,7 +6426,6 @@ "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", @@ -6588,11 +6434,10 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.19.3", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.3.tgz", - "integrity": "sha512-KOzM7MhcBFlmnlr/fzISFF5vGWVSvN6fTd4T+ExOt08bA/dA5kpSzY52nMsI1KDFmUREpJelPYyuslLRSjjgCg==", + "version": "4.19.5", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", + "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -6613,15 +6458,13 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/http-proxy": { - "version": "1.17.14", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", - "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", + "version": "1.17.15", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.15.tgz", + "integrity": "sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -6661,8 +6504,7 @@ "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/minimist": { "version": "1.2.5", @@ -6685,7 +6527,6 @@ "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -6708,22 +6549,19 @@ "version": "6.9.15", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/range-parser": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/selenium-webdriver": { "version": "3.0.26", @@ -6744,7 +6582,6 @@ "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", "dev": true, - "license": "MIT", "dependencies": { "@types/mime": "^1", "@types/node": "*" @@ -6755,7 +6592,6 @@ "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", "dev": true, - "license": "MIT", "dependencies": { "@types/express": "*" } @@ -6765,7 +6601,6 @@ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", "dev": true, - "license": "MIT", "dependencies": { "@types/http-errors": "*", "@types/node": "*", @@ -6783,7 +6618,6 @@ "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -6796,11 +6630,10 @@ "license": "MIT" }, "node_modules/@types/ws": { - "version": "8.5.10", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", - "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "version": "8.5.12", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", + "integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -7738,12 +7571,11 @@ "node": ">=0.4.0" } }, - "node_modules/acorn-import-assertions": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", - "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", "dev": true, - "license": "MIT", "peerDependencies": { "acorn": "^8" } @@ -7933,7 +7765,6 @@ "engines": [ "node >= 0.8.0" ], - "license": "Apache-2.0", "bin": { "ansi-html": "bin/ansi-html" } @@ -8053,8 +7884,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/array-ify": { "version": "1.0.0", @@ -8595,8 +8425,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/bcrypt-pbkdf": { "version": "1.0.2", @@ -8735,7 +8564,6 @@ "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", "dev": true, - "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "multicast-dns": "^7.2.5" @@ -8950,7 +8778,6 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -9485,7 +9312,6 @@ "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", "dev": true, - "license": "MIT", "dependencies": { "mime-db": ">= 1.43.0 < 2" }, @@ -9498,7 +9324,6 @@ "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", "dev": true, - "license": "MIT", "dependencies": { "accepts": "~1.3.5", "bytes": "3.0.0", @@ -9517,7 +9342,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -9526,15 +9350,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/compression/node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/concat-map": { "version": "0.0.1", @@ -9563,7 +9385,6 @@ "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.8" } @@ -9639,7 +9460,6 @@ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "dev": true, - "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" }, @@ -10087,7 +9907,6 @@ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -10096,8 +9915,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/cookiejar": { "version": "2.1.4", @@ -11104,7 +10922,6 @@ "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "execa": "^5.0.0" }, @@ -11347,8 +11164,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/dezalgo": { "version": "1.0.4", @@ -11394,7 +11210,6 @@ "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", "dev": true, - "license": "MIT", "dependencies": { "@leichtgewicht/ip-codec": "^2.0.1" }, @@ -11756,11 +11571,10 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", - "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", "dev": true, - "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -12771,7 +12585,6 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -12805,7 +12618,6 @@ "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, - "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -12855,7 +12667,6 @@ "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "dev": true, - "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", @@ -12898,7 +12709,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -12907,8 +12717,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/extend": { "version": "3.0.2", @@ -13017,7 +12826,6 @@ "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", "dev": true, - "license": "Apache-2.0", "dependencies": { "websocket-driver": ">=0.5.1" }, @@ -13120,7 +12928,6 @@ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", "dev": true, - "license": "MIT", "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", @@ -13139,7 +12946,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -13148,8 +12954,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/find-cache-dir": { "version": "4.0.0", @@ -13320,7 +13125,6 @@ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -13344,7 +13148,6 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -13656,7 +13459,6 @@ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" }, @@ -13877,8 +13679,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true, - "license": "BSD-2-Clause" + "dev": true }, "node_modules/glob/node_modules/brace-expansion": { "version": "2.0.1", @@ -14026,8 +13827,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/handlebars": { "version": "4.7.8", @@ -14299,7 +14099,6 @@ "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", "dev": true, - "license": "MIT", "dependencies": { "inherits": "^2.0.1", "obuf": "^1.0.0", @@ -14312,7 +14111,6 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, - "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -14327,15 +14125,13 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/hpack.js/node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" } @@ -14367,8 +14163,7 @@ "type": "patreon", "url": "https://patreon.com/mdevils" } - ], - "license": "MIT" + ] }, "node_modules/html-escaper": { "version": "2.0.2", @@ -14408,8 +14203,7 @@ "version": "1.2.7", "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/http-errors": { "version": "2.0.0", @@ -14432,8 +14226,7 @@ "version": "0.5.8", "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/http-proxy": { "version": "1.18.1", @@ -14470,7 +14263,6 @@ "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", "dev": true, - "license": "MIT", "dependencies": { "@types/http-proxy": "^1.17.8", "http-proxy": "^1.18.1", @@ -14525,7 +14317,6 @@ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=10.17.0" } @@ -14917,7 +14708,6 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 10" } @@ -15226,7 +15016,6 @@ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" }, @@ -16430,11 +16219,10 @@ } }, "node_modules/launch-editor": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.1.tgz", - "integrity": "sha512-eB/uXmFVpY4zezmGp5XtU21kwo7GBbKB+EQ+UZeWtGb9yAM5xt/Evk+lYH3eRNAtId+ej4u7TYPFZ07w4s7rRw==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.8.1.tgz", + "integrity": "sha512-elBx2l/tp9z99X5H/qev8uyDywVh0VXAwEbjk8kJhnc5grOFkGh7aW6q55me9xnYbss261XtnUrysZ+XvGbhQA==", "dev": true, - "license": "MIT", "dependencies": { "picocolors": "^1.0.0", "shell-quote": "^1.8.1" @@ -17372,8 +17160,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/merge-stream": { "version": "2.0.0", @@ -17526,8 +17313,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/minimatch": { "version": "3.1.2", @@ -17866,7 +17652,6 @@ "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", "dev": true, - "license": "MIT", "dependencies": { "dns-packet": "^5.2.2", "thunky": "^1.0.2" @@ -18121,7 +17906,6 @@ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", "dev": true, - "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { "node": ">= 6.13.0" } @@ -19102,8 +18886,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/on-finished": { "version": "2.4.1", @@ -19123,7 +18906,6 @@ "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -19350,7 +19132,6 @@ "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/retry": "0.12.0", "retry": "^0.13.1" @@ -19364,7 +19145,6 @@ "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 4" } @@ -19689,8 +19469,7 @@ "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/path-type": { "version": "4.0.0", @@ -20499,7 +20278,6 @@ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "dev": true, - "license": "MIT", "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -20513,7 +20291,6 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.10" } @@ -21886,8 +21663,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/selenium-webdriver": { "version": "3.6.0", @@ -21957,7 +21733,6 @@ "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", "dev": true, - "license": "MIT", "dependencies": { "@types/node-forge": "^1.3.0", "node-forge": "^1" @@ -22004,7 +21779,6 @@ "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "dev": true, - "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -22029,7 +21803,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -22038,15 +21811,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/serialize-javascript": { "version": "6.0.2", @@ -22063,7 +21834,6 @@ "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", "dev": true, - "license": "MIT", "dependencies": { "accepts": "~1.3.4", "batch": "0.6.1", @@ -22082,7 +21852,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -22092,7 +21861,6 @@ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -22102,7 +21870,6 @@ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", "dev": true, - "license": "MIT", "dependencies": { "depd": "~1.1.2", "inherits": "2.0.3", @@ -22117,29 +21884,25 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/serve-index/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/serve-index/node_modules/setprototypeof": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/serve-index/node_modules/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -22149,7 +21912,6 @@ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "dev": true, - "license": "MIT", "dependencies": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", @@ -22284,7 +22046,6 @@ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", "dev": true, - "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -22676,7 +22437,6 @@ "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", "dev": true, - "license": "MIT", "dependencies": { "faye-websocket": "^0.11.3", "uuid": "^8.3.2", @@ -22688,7 +22448,6 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true, - "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } @@ -22832,7 +22591,6 @@ "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", "dev": true, - "license": "MIT", "dependencies": { "debug": "^4.1.0", "handle-thing": "^2.0.0", @@ -22849,7 +22607,6 @@ "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", "dev": true, - "license": "MIT", "dependencies": { "debug": "^4.1.0", "detect-node": "^2.0.4", @@ -23343,7 +23100,6 @@ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -23743,8 +23499,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/tmp": { "version": "0.0.33", @@ -24855,11 +24610,10 @@ } }, "node_modules/watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", "dev": true, - "license": "MIT", "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" @@ -24873,7 +24627,6 @@ "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", "dev": true, - "license": "MIT", "dependencies": { "minimalistic-assert": "^1.0.0" } @@ -25049,26 +24802,25 @@ } }, "node_modules/webpack": { - "version": "5.90.3", + "version": "5.94.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz", + "integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==", "dev": true, - "license": "MIT", - "peer": true, "dependencies": { - "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.5", - "@webassemblyjs/ast": "^1.11.5", - "@webassemblyjs/wasm-edit": "^1.11.5", - "@webassemblyjs/wasm-parser": "^1.11.5", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", "acorn": "^8.7.1", - "acorn-import-assertions": "^1.9.0", + "acorn-import-attributes": "^1.9.5", "browserslist": "^4.21.10", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.15.0", + "enhanced-resolve": "^5.17.1", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", + "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", @@ -25076,7 +24828,7 @@ "schema-utils": "^3.2.0", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.3.10", - "watchpack": "^2.4.0", + "watchpack": "^2.4.1", "webpack-sources": "^3.2.3" }, "bin": { @@ -25129,7 +24881,6 @@ "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", "dev": true, - "license": "MIT", "dependencies": { "@types/bonjour": "^3.5.9", "@types/connect-history-api-fallback": "^1.3.5", @@ -25189,7 +24940,6 @@ "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", "dev": true, - "license": "MIT", "dependencies": { "colorette": "^2.0.10", "memfs": "^3.4.3", @@ -25209,11 +24959,10 @@ } }, "node_modules/webpack-dev-server/node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "dev": true, - "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -25282,7 +25031,6 @@ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -25300,7 +25048,6 @@ "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", "dev": true, "license": "MIT", - "peer": true, "peerDependencies": { "ajv": "^6.9.1" } @@ -25310,8 +25057,7 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/webpack/node_modules/schema-utils": { "version": "3.3.0", @@ -25319,7 +25065,6 @@ "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -25338,7 +25083,6 @@ "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", "dev": true, - "license": "Apache-2.0", "dependencies": { "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", @@ -25353,7 +25097,6 @@ "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=0.8.0" } diff --git a/ui/package.json b/ui/package.json index 2d255880924..1b1f1064ed3 100644 --- a/ui/package.json +++ b/ui/package.json @@ -53,7 +53,7 @@ "zone.js": "~0.13.3" }, "devDependencies": { - "@angular-devkit/build-angular": "^16.2.14", + "@angular-devkit/build-angular": "^16.2.15", "@angular-eslint/builder": "^16.3.1", "@angular-eslint/eslint-plugin": "^16.3.1", "@angular-eslint/eslint-plugin-template": "^16.3.1", From 9e2fd4cf11e94cf0777e8cf37415fd6388532452 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 22:22:51 +0200 Subject: [PATCH 117/173] Build(deps): Bump org.postgresql:postgresql from 42.7.3 to 42.7.4 in /cnf (#2762) * Build(deps): Bump org.postgresql:postgresql in /cnf Bumps [org.postgresql:postgresql](https://github.com/pgjdbc/pgjdbc) from 42.7.3 to 42.7.4. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.7.3...REL42.7.4) --- updated-dependencies: - dependency-name: org.postgresql:postgresql 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 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cnf/pom.xml b/cnf/pom.xml index 6e19ea4a87e..ef81464a4c9 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -399,7 +399,7 @@ org.postgresql postgresql - 42.7.3 + 42.7.4 diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index 11760f6ee1e..130a02f2f85 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -124,6 +124,6 @@ org.osgi.util.function;version='[1.2.0,1.2.1)',\ org.osgi.util.promise;version='[1.3.0,1.3.1)',\ org.owasp.encoder;version='[1.2.3,1.2.4)',\ - org.postgresql.jdbc;version='[42.7.3,42.7.4)',\ + org.postgresql.jdbc;version='[42.7.4,42.7.5)',\ reactive-streams;version='[1.0.4,1.0.5)',\ stax2-api;version='[4.2.2,4.2.3)' \ No newline at end of file From f7196624a0a93bca4a1417235cb73bb1cdc1eebc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 22:41:32 +0200 Subject: [PATCH 118/173] Build(deps): Bump org.owasp.encoder:encoder from 1.2.3 to 1.3.1 in /cnf (#2763) * Build(deps): Bump org.owasp.encoder:encoder from 1.2.3 to 1.3.1 in /cnf Bumps [org.owasp.encoder:encoder](https://github.com/owasp/owasp-java-encoder) from 1.2.3 to 1.3.1. - [Release notes](https://github.com/owasp/owasp-java-encoder/releases) - [Commits](https://github.com/owasp/owasp-java-encoder/compare/v1.2.3...v1.3.1) --- updated-dependencies: - dependency-name: org.owasp.encoder:encoder dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Add influxdb dependabot group * Update bndrun --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- .github/dependabot.yml | 4 ++++ cnf/pom.xml | 2 +- io.openems.backend.application/BackendApp.bndrun | 2 +- io.openems.edge.application/EdgeApp.bndrun | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index ac7721a4511..a7dddbfd65c 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -6,6 +6,10 @@ updates: interval: weekly open-pull-requests-limit: 10 target-branch: develop + groups: + influxdb: + patterns: + - "com.influxdb:*" - package-ecosystem: npm directory: "/ui" diff --git a/cnf/pom.xml b/cnf/pom.xml index ef81464a4c9..1df3f146eb2 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -393,7 +393,7 @@ org.owasp.encoder encoder - 1.2.3 + 1.3.1 diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index 130a02f2f85..50097343494 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -123,7 +123,7 @@ org.osgi.service.jdbc;version='[1.1.0,1.1.1)',\ org.osgi.util.function;version='[1.2.0,1.2.1)',\ org.osgi.util.promise;version='[1.3.0,1.3.1)',\ - org.owasp.encoder;version='[1.2.3,1.2.4)',\ + org.owasp.encoder;version='[1.3.1,1.3.2)',\ org.postgresql.jdbc;version='[42.7.4,42.7.5)',\ reactive-streams;version='[1.0.4,1.0.5)',\ stax2-api;version='[4.2.2,4.2.3)' \ No newline at end of file diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index e317511eab6..1464a8d7850 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -426,7 +426,7 @@ org.osgi.service.component;version='[1.5.1,1.5.2)',\ org.osgi.util.function;version='[1.2.0,1.2.1)',\ org.osgi.util.promise;version='[1.3.0,1.3.1)',\ - org.owasp.encoder;version='[1.2.3,1.2.4)',\ + org.owasp.encoder;version='[1.3.1,1.3.2)',\ reactive-streams;version='[1.0.4,1.0.5)',\ rrd4j;version='[3.9.0,3.9.1)',\ stax2-api;version='[4.2.2,4.2.3)' \ No newline at end of file From 7dc7dba96607981e4cbdaba0b53c4dc83df37aa4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 22:55:59 +0200 Subject: [PATCH 119/173] Build(deps): Bump com.google.guava:guava from 33.2.1-jre to 33.3.0-jre in /cnf (#2764) * Build(deps): Bump com.google.guava:guava in /cnf Bumps [com.google.guava:guava](https://github.com/google/guava) from 33.2.1-jre to 33.3.0-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-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/build.bnd | 2 +- cnf/pom.xml | 2 +- io.openems.backend.application/BackendApp.bndrun | 2 +- io.openems.edge.application/EdgeApp.bndrun | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cnf/build.bnd b/cnf/build.bnd index b64f56b11b6..3a846baa49b 100644 --- a/cnf/build.bnd +++ b/cnf/build.bnd @@ -40,7 +40,7 @@ buildpath: \ org.osgi.service.metatype;version='1.4.1',\ org.osgi.service.metatype.annotations;version='1.4.1',\ org.osgi.util.promise;version='1.2.0',\ - com.google.guava;version='33.2.1.jre',\ + com.google.guava;version='33.3.0.jre',\ com.google.gson;version='2.11.0',\ testpath: \ diff --git a/cnf/pom.xml b/cnf/pom.xml index 1df3f146eb2..fe40c659af6 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -38,7 +38,7 @@ com.google.guava guava - 33.2.1-jre + 33.3.0-jre com.google.guava diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index 50097343494..923ac4c24c1 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -62,7 +62,7 @@ Java-WebSocket;version='[1.5.4,1.5.5)',\ com.fasterxml.aalto-xml;version='[1.3.3,1.3.4)',\ com.google.gson;version='[2.11.0,2.11.1)',\ - com.google.guava;version='[33.2.1,33.2.2)',\ + com.google.guava;version='[33.3.0,33.3.1)',\ com.google.guava.failureaccess;version='[1.0.2,1.0.3)',\ com.squareup.okio;version='[3.9.0,3.9.1)',\ com.zaxxer.HikariCP;version='[5.1.0,5.1.1)',\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index 1464a8d7850..c621ec4d944 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -200,7 +200,7 @@ com.fazecast.jSerialComm;version='[2.10.4,2.10.5)',\ com.ghgande.j2mod;version='[3.2.1,3.2.2)',\ com.google.gson;version='[2.11.0,2.11.1)',\ - com.google.guava;version='[33.2.1,33.2.2)',\ + com.google.guava;version='[33.3.0,33.3.1)',\ com.google.guava.failureaccess;version='[1.0.2,1.0.3)',\ com.squareup.okio;version='[3.9.0,3.9.1)',\ com.sun.jna;version='[5.14.0,5.14.1)',\ From 5d68743e81236cecfa5a578aed87a02efea83089 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 22:58:06 +0200 Subject: [PATCH 120/173] Build(deps-dev): Bump the eslint group in /ui with 2 updates (#2767) Bumps the eslint group in /ui with 2 updates: [@stylistic/eslint-plugin](https://github.com/eslint-stylistic/eslint-stylistic/tree/HEAD/packages/eslint-plugin) and [eslint-plugin-unused-imports](https://github.com/sweepline/eslint-plugin-unused-imports). Updates `@stylistic/eslint-plugin` from 2.6.2 to 2.7.2 - [Release notes](https://github.com/eslint-stylistic/eslint-stylistic/releases) - [Changelog](https://github.com/eslint-stylistic/eslint-stylistic/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint-stylistic/eslint-stylistic/commits/v2.7.2/packages/eslint-plugin) Updates `eslint-plugin-unused-imports` from 3.2.0 to 4.1.3 - [Commits](https://github.com/sweepline/eslint-plugin-unused-imports/commits/v4.1.3) --- updated-dependencies: - dependency-name: "@stylistic/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: eslint - dependency-name: eslint-plugin-unused-imports dependency-type: direct:development update-type: version-update:semver-major dependency-group: eslint ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 443 ++++++++----------------------------------- ui/package.json | 4 +- 2 files changed, 85 insertions(+), 362 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 5b3db5a9f2e..e506fd383f4 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -70,7 +70,7 @@ "@capacitor/assets": "^3.0.0", "@capacitor/cli": "6.1.2", "@ionic/angular-toolkit": "^11.0.1", - "@stylistic/eslint-plugin": "^2.4.0", + "@stylistic/eslint-plugin": "^2.7.2", "@types/jasmine": "~4.3.6", "@types/jasminewd2": "~2.0.13", "@types/node": "^20.12.6", @@ -81,7 +81,7 @@ "eslint-plugin-import": "2.29.1", "eslint-plugin-jsdoc": "48.2.3", "eslint-plugin-prefer-arrow": "1.2.3", - "eslint-plugin-unused-imports": "^3.2.0", + "eslint-plugin-unused-imports": "^4.1.3", "jasmine-core": "~4.5.0", "jasmine-spec-reporter": "~7.0.0", "karma": "~6.4.2", @@ -5701,84 +5701,15 @@ } }, "node_modules/@stylistic/eslint-plugin": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.6.2.tgz", - "integrity": "sha512-Ic5oFNM/25iuagob6LiIBkSI/A2y45TsyKtDtODXHRZDy52WfPfeexI6r+OH5+aWN9QGob2Bw+4JRM9/4areWw==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.7.2.tgz", + "integrity": "sha512-3DVLU5HEuk2pQoBmXJlzvrxbKNpu2mJ0SRqz5O/CJjyNCr12ZiPcYMEtuArTyPOk5i7bsAU44nywh1rGfe3gKQ==", "dev": true, - "license": "MIT", "dependencies": { - "@stylistic/eslint-plugin-js": "2.6.2", - "@stylistic/eslint-plugin-jsx": "2.6.2", - "@stylistic/eslint-plugin-plus": "2.6.2", - "@stylistic/eslint-plugin-ts": "2.6.2", - "@types/eslint": "^9.6.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "peerDependencies": { - "eslint": ">=8.40.0" - } - }, - "node_modules/@stylistic/eslint-plugin-js": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.6.2.tgz", - "integrity": "sha512-wCr/kVctAPayMU3pcOI1MKR7MoKIh6VKZU89lPklAqtJoxT+Em6RueiiARbpznUYG5eg3LymiU+aMD+aIZXdqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/eslint": "^9.6.0", - "acorn": "^8.12.1", + "@types/eslint": "^9.6.1", + "@typescript-eslint/utils": "^8.3.0", "eslint-visitor-keys": "^4.0.0", - "espree": "^10.1.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "peerDependencies": { - "eslint": ">=8.40.0" - } - }, - "node_modules/@stylistic/eslint-plugin-js/node_modules/eslint-visitor-keys": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", - "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@stylistic/eslint-plugin-js/node_modules/espree": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", - "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.12.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@stylistic/eslint-plugin-jsx": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-jsx/-/eslint-plugin-jsx-2.6.2.tgz", - "integrity": "sha512-dSXK/fSPA938J1fBi10QmhzLKtZ/2TuyVNHQMk8jUhWfKJDleAogaSqcWNAbN8fwcoe9UWmt/3StiIf2oYC1aQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@stylistic/eslint-plugin-js": "^2.6.2", - "@types/eslint": "^9.6.0", + "espree": "^10.1.0", "estraverse": "^5.3.0", "picomatch": "^4.0.2" }, @@ -5789,52 +5720,14 @@ "eslint": ">=8.40.0" } }, - "node_modules/@stylistic/eslint-plugin-jsx/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/@stylistic/eslint-plugin-jsx/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/@stylistic/eslint-plugin-plus": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-2.6.2.tgz", - "integrity": "sha512-cANcPASfRvq3VTbbQCrSIXq+2AI0IW68PNYaZoXXS0ENlp7HDB8dmrsJnOgWCcoEvdCB8z/eWcG/eq/v5Qcl+Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/eslint": "^9.6.0", - "@typescript-eslint/utils": "^8.0.0" - }, - "peerDependencies": { - "eslint": "*" - } - }, - "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/scope-manager": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.0.1.tgz", - "integrity": "sha512-NpixInP5dm7uukMiRyiHjRKkom5RIFA4dfiHvalanD2cF0CLUuQqxfg8PtEUo9yqJI2bBhF+pcSafqnG3UBnRQ==", + "node_modules/@stylistic/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.3.0.tgz", + "integrity": "sha512-mz2X8WcN2nVu5Hodku+IR8GgCOl4C0G/Z1ruaWN4dgec64kDBabuXyPAr+/RgJtumv8EEkqIzf3X2U5DUKB2eg==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.0.1", - "@typescript-eslint/visitor-keys": "8.0.1" + "@typescript-eslint/types": "8.3.0", + "@typescript-eslint/visitor-keys": "8.3.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5844,12 +5737,11 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/types": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.0.1.tgz", - "integrity": "sha512-PpqTVT3yCA/bIgJ12czBuE3iBlM3g4inRSC5J0QOdQFAn07TYrYEQBBKgXH1lQpglup+Zy6c1fxuwTk4MTNKIw==", + "node_modules/@stylistic/eslint-plugin/node_modules/@typescript-eslint/types": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.3.0.tgz", + "integrity": "sha512-y6sSEeK+facMaAyixM36dQ5NVXTnKWunfD1Ft4xraYqxP0lC0POJmIaL/mw72CUMqjY9qfyVfXafMeaUj0noWw==", "dev": true, - "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -5858,17 +5750,16 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.0.1.tgz", - "integrity": "sha512-8V9hriRvZQXPWU3bbiUV4Epo7EvgM6RTs+sUmxp5G//dBGy402S7Fx0W0QkB2fb4obCF8SInoUzvTYtc3bkb5w==", + "node_modules/@stylistic/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.3.0.tgz", + "integrity": "sha512-Mq7FTHl0R36EmWlCJWojIC1qn/ZWo2YiWYc1XVtasJ7FIgjo0MVv9rZWXEE7IK2CGrtwe1dVOxWwqXUdNgfRCA==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "8.0.1", - "@typescript-eslint/visitor-keys": "8.0.1", + "@typescript-eslint/types": "8.3.0", + "@typescript-eslint/visitor-keys": "8.3.0", "debug": "^4.3.4", - "globby": "^11.1.0", + "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", @@ -5887,17 +5778,16 @@ } } }, - "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/utils": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.0.1.tgz", - "integrity": "sha512-CBFR0G0sCt0+fzfnKaciu9IBsKvEKYwN9UZ+eeogK1fYHg4Qxk1yf/wLQkLXlq8wbU2dFlgAesxt8Gi76E8RTA==", + "node_modules/@stylistic/eslint-plugin/node_modules/@typescript-eslint/utils": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.3.0.tgz", + "integrity": "sha512-F77WwqxIi/qGkIGOGXNBLV7nykwfjLsdauRB/DOFPdv6LTF3BHHkBpq81/b5iMPSF055oO2BiivDJV4ChvNtXA==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.0.1", - "@typescript-eslint/types": "8.0.1", - "@typescript-eslint/typescript-estree": "8.0.1" + "@typescript-eslint/scope-manager": "8.3.0", + "@typescript-eslint/types": "8.3.0", + "@typescript-eslint/typescript-estree": "8.3.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5910,14 +5800,13 @@ "eslint": "^8.57.0 || ^9.0.0" } }, - "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.0.1.tgz", - "integrity": "sha512-W5E+o0UfUcK5EgchLZsyVWqARmsM7v54/qEq6PY3YI5arkgmCzHiuk0zKSJJbm71V0xdRna4BGomkCTXz2/LkQ==", + "node_modules/@stylistic/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.3.0.tgz", + "integrity": "sha512-RmZwrTbQ9QveF15m/Cl28n0LXD6ea2CjkhH5rQ55ewz3H24w+AMCJHPVYaZ8/0HoG8Z3cLLFFycRXxeO2tz9FA==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.0.1", + "@typescript-eslint/types": "8.3.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -5928,220 +5817,70 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@stylistic/eslint-plugin-plus/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@stylistic/eslint-plugin-plus/node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@stylistic/eslint-plugin-plus/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@stylistic/eslint-plugin-plus/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@stylistic/eslint-plugin-ts": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-ts/-/eslint-plugin-ts-2.6.2.tgz", - "integrity": "sha512-6OEN3VtUNxjgOvWPavnC10MByr1H4zsgwNND3rQXr5lDFv93MLUnTsH+/SH15OkuqdyJgrQILI6b9lYecb1vIg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@stylistic/eslint-plugin-js": "2.6.2", - "@types/eslint": "^9.6.0", - "@typescript-eslint/utils": "^8.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "peerDependencies": { - "eslint": ">=8.40.0" - } - }, - "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/scope-manager": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.0.1.tgz", - "integrity": "sha512-NpixInP5dm7uukMiRyiHjRKkom5RIFA4dfiHvalanD2cF0CLUuQqxfg8PtEUo9yqJI2bBhF+pcSafqnG3UBnRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.0.1", - "@typescript-eslint/visitor-keys": "8.0.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/types": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.0.1.tgz", - "integrity": "sha512-PpqTVT3yCA/bIgJ12czBuE3iBlM3g4inRSC5J0QOdQFAn07TYrYEQBBKgXH1lQpglup+Zy6c1fxuwTk4MTNKIw==", + "node_modules/@stylistic/eslint-plugin/node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "license": "MIT", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://opencollective.com/eslint" } }, - "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.0.1.tgz", - "integrity": "sha512-8V9hriRvZQXPWU3bbiUV4Epo7EvgM6RTs+sUmxp5G//dBGy402S7Fx0W0QkB2fb4obCF8SInoUzvTYtc3bkb5w==", + "node_modules/@stylistic/eslint-plugin/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "8.0.1", - "@typescript-eslint/visitor-keys": "8.0.1", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "balanced-match": "^1.0.0" } }, - "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/utils": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.0.1.tgz", - "integrity": "sha512-CBFR0G0sCt0+fzfnKaciu9IBsKvEKYwN9UZ+eeogK1fYHg4Qxk1yf/wLQkLXlq8wbU2dFlgAesxt8Gi76E8RTA==", + "node_modules/@stylistic/eslint-plugin/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.0.1", - "@typescript-eslint/types": "8.0.1", - "@typescript-eslint/typescript-estree": "8.0.1" - }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" + "url": "https://opencollective.com/eslint" } }, - "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.0.1.tgz", - "integrity": "sha512-W5E+o0UfUcK5EgchLZsyVWqARmsM7v54/qEq6PY3YI5arkgmCzHiuk0zKSJJbm71V0xdRna4BGomkCTXz2/LkQ==", + "node_modules/@stylistic/eslint-plugin/node_modules/espree": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.0.1", - "eslint-visitor-keys": "^3.4.3" + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@stylistic/eslint-plugin-ts/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" + "url": "https://opencollective.com/eslint" } }, - "node_modules/@stylistic/eslint-plugin-ts/node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "node_modules/@stylistic/eslint-plugin/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "license": "MIT", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=4.0" } }, - "node_modules/@stylistic/eslint-plugin-ts/node_modules/minimatch": { + "node_modules/@stylistic/eslint-plugin/node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -6152,14 +5891,16 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@stylistic/eslint-plugin-ts/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "node_modules/@stylistic/eslint-plugin/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, - "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/@tootallnate/once": { @@ -6404,11 +6145,10 @@ } }, "node_modules/@types/eslint": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.0.tgz", - "integrity": "sha512-gi6WQJ7cHRgZxtkQEoyHMppPjq9Kxo5Tjn2prSKDSmZrCz8TZ3jSRCeTJm+WoM+oB0WG37bRqLzaaU3q7JypGg==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -12166,20 +11906,13 @@ } }, "node_modules/eslint-plugin-unused-imports": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-3.2.0.tgz", - "integrity": "sha512-6uXyn6xdINEpxE1MtDjxQsyXB37lfyO2yKGVVgtD7WEWQGORSOZjgrD6hBhvGv4/SO+TOlS+UnC6JppRqbuwGQ==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.1.3.tgz", + "integrity": "sha512-lqrNZIZjFMUr7P06eoKtQLwyVRibvG7N+LtfKtObYGizAAGrcqLkc3tDx+iAik2z7q0j/XI3ihjupIqxhFabFA==", "dev": true, - "license": "MIT", - "dependencies": { - "eslint-rule-composer": "^0.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, "peerDependencies": { - "@typescript-eslint/eslint-plugin": "6 - 7", - "eslint": "8" + "@typescript-eslint/eslint-plugin": "^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0", + "eslint": "^9.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "@typescript-eslint/eslint-plugin": { @@ -12187,16 +11920,6 @@ } } }, - "node_modules/eslint-rule-composer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", - "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4.0.0" - } - }, "node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", diff --git a/ui/package.json b/ui/package.json index 1b1f1064ed3..16085e90ca2 100644 --- a/ui/package.json +++ b/ui/package.json @@ -65,7 +65,7 @@ "@capacitor/assets": "^3.0.0", "@capacitor/cli": "6.1.2", "@ionic/angular-toolkit": "^11.0.1", - "@stylistic/eslint-plugin": "^2.4.0", + "@stylistic/eslint-plugin": "^2.7.2", "@types/jasmine": "~4.3.6", "@types/jasminewd2": "~2.0.13", "@types/node": "^20.12.6", @@ -76,7 +76,7 @@ "eslint-plugin-import": "2.29.1", "eslint-plugin-jsdoc": "48.2.3", "eslint-plugin-prefer-arrow": "1.2.3", - "eslint-plugin-unused-imports": "^3.2.0", + "eslint-plugin-unused-imports": "^4.1.3", "jasmine-core": "~4.5.0", "jasmine-spec-reporter": "~7.0.0", "karma": "~6.4.2", From 63f606951a61fe5a770983c1e48c6e25e1abe4a0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 22:58:38 +0200 Subject: [PATCH 121/173] Build(deps): Bump swiper from 11.1.9 to 11.1.11 in /ui (#2768) Bumps [swiper](https://github.com/nolimits4web/Swiper) from 11.1.9 to 11.1.11. - [Release notes](https://github.com/nolimits4web/Swiper/releases) - [Changelog](https://github.com/nolimits4web/swiper/blob/master/CHANGELOG.md) - [Commits](https://github.com/nolimits4web/Swiper/compare/v11.1.9...v11.1.11) --- updated-dependencies: - dependency-name: swiper dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 9 ++++----- ui/package.json | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index e506fd383f4..9d5b618650d 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -52,7 +52,7 @@ "ngx-spinner": "^16.0.2", "roboto-fontface": "^0.10.0", "rxjs": "~6.6.7", - "swiper": "11.1.9", + "swiper": "11.1.11", "tslib": "^2.6.2", "uuid": "^10.0.0", "zone.js": "~0.13.3" @@ -22783,9 +22783,9 @@ } }, "node_modules/swiper": { - "version": "11.1.9", - "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.1.9.tgz", - "integrity": "sha512-rflu8zvfGa3x1v/aeSufk4zRJffhOQowyvtJlp46sUBnOqAuk1Rdv5Ldj0AWWBV595iZ+ZMk7VB35ZRtRUomtA==", + "version": "11.1.11", + "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.1.11.tgz", + "integrity": "sha512-077Aw3OrlZpkkBRf/6+44bGh/HZY/vsLEyate2db2KkJgYUIR5TvDgvvhcJtW/puXzw79w5KBc30DauEX6GZYQ==", "funding": [ { "type": "patreon", @@ -22796,7 +22796,6 @@ "url": "http://opencollective.com/swiper" } ], - "license": "MIT", "engines": { "node": ">= 4.7.0" } diff --git a/ui/package.json b/ui/package.json index 16085e90ca2..85b1d20a316 100644 --- a/ui/package.json +++ b/ui/package.json @@ -47,7 +47,7 @@ "ngx-spinner": "^16.0.2", "roboto-fontface": "^0.10.0", "rxjs": "~6.6.7", - "swiper": "11.1.9", + "swiper": "11.1.11", "tslib": "^2.6.2", "uuid": "^10.0.0", "zone.js": "~0.13.3" From 31e7c7889482ee1ad364b7f0752b8ccfb27814ee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 22:59:16 +0200 Subject: [PATCH 122/173] Build(deps): Bump chart.js from 4.4.3 to 4.4.4 in /ui (#2769) Bumps [chart.js](https://github.com/chartjs/Chart.js) from 4.4.3 to 4.4.4. - [Release notes](https://github.com/chartjs/Chart.js/releases) - [Commits](https://github.com/chartjs/Chart.js/compare/v4.4.3...v4.4.4) --- updated-dependencies: - dependency-name: chart.js dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 9 ++++----- ui/package.json | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 9d5b618650d..1e2cea1fdd0 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -36,7 +36,7 @@ "capacitor-blob-writer": "^1.1.17", "capacitor-ios-autofill-save-password": "^2.0.0", "capacitor-secure-storage-plugin": "^0.9.0", - "chart.js": "^4.4.3", + "chart.js": "^4.4.4", "chartjs-adapter-date-fns": "^3.0.0", "chartjs-plugin-annotation": "^3.0.1", "chartjs-plugin-datalabels": "^2.2.0", @@ -8701,10 +8701,9 @@ "license": "MIT" }, "node_modules/chart.js": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.3.tgz", - "integrity": "sha512-qK1gkGSRYcJzqrrzdR6a+I0vQ4/R+SoODXyAjscQ/4mzuNzySaMCd+hyVxitSY1+L2fjPD1Gbn+ibNqRmwQeLw==", - "license": "MIT", + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.4.tgz", + "integrity": "sha512-emICKGBABnxhMjUjlYRR12PmOXhJ2eJjEHL2/dZlWjxRAZT1D8xplLFq5M0tMQK8ja+wBS/tuVEJB5C6r7VxJA==", "dependencies": { "@kurkle/color": "^0.3.0" }, diff --git a/ui/package.json b/ui/package.json index 85b1d20a316..15d2ea454e1 100644 --- a/ui/package.json +++ b/ui/package.json @@ -31,7 +31,7 @@ "capacitor-blob-writer": "^1.1.17", "capacitor-ios-autofill-save-password": "^2.0.0", "capacitor-secure-storage-plugin": "^0.9.0", - "chart.js": "^4.4.3", + "chart.js": "^4.4.4", "chartjs-adapter-date-fns": "^3.0.0", "chartjs-plugin-annotation": "^3.0.1", "chartjs-plugin-datalabels": "^2.2.0", From 4a852f706c76ffeca23e4ca3277a2ee9647df361 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Sat, 31 Aug 2024 14:51:11 +0200 Subject: [PATCH 123/173] FEMS-Backports 2024-08 (2) (#2771) * UI: fix sum chart in consumption history - Wrong variable used in consumption detail html * UI: add routing guards for settings - Introduction of [Routing Guards](https://v17.angular.io/api/router#types) - Not visible routes could be accessed through manually going there - Adding edge role check before accessing this route * UI: center refresher-spinner - Center refresh-content-spinner * Rrd4j: Fix query for custom range - fix start for timeranges with not the first day of the month - fix readonly only worked with debugmode * UI: Migration to angular 18 - Update Angular, Zone.js, Typescript * UI: Eslint: no-multiple-empty-lines * UI: fix tooltip afterTitle display bug * UI: enforce double quotes - Enforce usage of double quotes - prohibit single quotes - backticks are still usable -> [ref](https://eslint.org/docs/latest/rules/quotes#double) * UI: add exhaustive switch eslint rule - Add eslint rule [`switch-exhaustiveness-check`](https://typescript-eslint.io/rules/switch-exhaustiveness-check/) * UI: App: Update android api due to googles new policy - Updating android api level due to googles new policy, enforcing `ANDROID_API_LEVEL=34` to be minimum version * Build android app - Add CI pipeline for building Android apps * GridOptimizedCharge: avoid fail state in OFF * UI: Reduce history queries & overloading of chartData - If a history chart takes too long to load and the user switches the timerange, the old timerange will be shown instead of the actual one (at least for a few seconds, until the new chart is finished) * UI: Replace `setCurrentComponent` with `getCurrentEdge` - Replace `setCurrentComponent` with `getCurrentEdge`, setCurrentComponent is already deprecated and shouldnt be used anymore * UI: Unify fixDigitalOutput & singlethreshold history (#1315) - Unify and refactor all FixDigitalOutputControllers and SingleThresholds in one widget in history - Refactoring them and using the new `CumulatedLevelActiveTime`-Channel * UI: fix TimeOfUseTariff powerSocChart - Fix `TypeError: this.options.plugins is undefined` - To reproduce the error see "live" screen and open the modal for Time-of-Use with ADMIN role. --------- Co-authored-by: Lukas Rieger <73471197+lukasrgr@users.noreply.github.com> Co-authored-by: Michael Grill <59126309+michaelgrill@users.noreply.github.com> Co-authored-by: Kai Jeschek <99220919+da-Kai@users.noreply.github.com> Co-authored-by: Johann Kaufmann <165755282+johannk24@users.noreply.github.com> Co-authored-by: Fabian Brandtner <10850256+fabian94533@users.noreply.github.com> Co-authored-by: Sebastian Asen <47855186+sebastianasen@users.noreply.github.com> Reviewed-by: Sagar Venu <32655208+venu-sagar@users.noreply.github.com> Reviewed-by: Lukas Rieger <73471197+lukasrgr@users.noreply.github.com> Reviewed-by: Sebastian Asen <47855186+sebastianasen@users.noreply.github.com> Reviewed-by: Stefan Feilmeier <3515268+sfeilmeier@users.noreply.github.com> Reviewed-by: Hueseyin Sahutoglu <34771592+huseyinsaht@users.noreply.github.com> --- .woodpecker/ui-build.yml | 80 + .../ControllerEssGridOptimizedChargeImpl.java | 3 +- .../edge/timedata/rrd4j/RecordWorker.java | 6 +- .../edge/timedata/rrd4j/Rrd4jReadHandler.java | 22 +- .../timedata/rrd4j/Rrd4jReadHandlerTest.java | 15 + tools/common.sh | 35 +- tools/drone/openems-android.sh | 8 +- ui/.eslintrc.json | 13 +- ui/.vscode/settings.json | 5 +- ui/android/.gitignore | 101 + ui/android/app/build.gradle | 34 +- ui/android/build.gradle | 66 +- ui/android/gradle/wrapper/gradle-wrapper.jar | Bin 61608 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 - ui/android/gradlew | 246 +- ui/android/gradlew.bat | 96 +- ui/android/variables.gradle | 4 +- ui/capacitor.config.ts | 13 +- ui/package-lock.json | 20503 ++++++++-------- ui/package.json | 77 +- ui/src/app/app-routing.module.ts | 225 +- ui/src/app/app.component.ts | 44 +- ui/src/app/app.module.ts | 62 +- ui/src/app/app.service.ts | 50 +- ui/src/app/appupdateservice.ts | 10 +- ui/src/app/changelog/changelog.module.ts | 8 +- .../view/component/changelog.component.ts | 22 +- .../view/component/changelog.constants.ts | 100 +- ui/src/app/changelog/view/view.ts | 4 +- ui/src/app/edge/edge.component.ts | 8 +- ui/src/app/edge/edge.module.ts | 10 +- .../chart/totalchart.component.ts | 28 +- .../Controller/ChannelThreshold/flat/flat.ts | 18 +- .../ChannelThreshold/overview/overview.ts | 4 +- .../Ess/GridoptimizedCharge/chart/chart.ts | 76 +- .../chart/sellToGridLimitChart.component.ts | 58 +- .../Ess/GridoptimizedCharge/flat/flat.ts | 12 +- .../GridoptimizedCharge/overview/overview.ts | 8 +- .../Ess/TimeOfUseTariff/chart/chart.ts | 114 +- .../Ess/TimeOfUseTariff/flat/flat.ts | 20 +- .../Ess/TimeOfUseTariff/overview/overview.ts | 6 +- .../edge/history/Controller/Ess/ess.module.ts | 12 + .../Io/DigitalOutput/chart/chart.ts | 68 + .../Io/DigitalOutput/details/chart/chart.ts | 163 + .../details/details.overview.html | 4 + .../DigitalOutput/details/details.overview.ts | 7 + .../Io/DigitalOutput/digitalOutput.module.ts | 32 + .../Io/DigitalOutput/flat/flat.html | 19 + .../Controller/Io/DigitalOutput/flat/flat.ts | 22 + .../Io/DigitalOutput/overview/overview.html | 5 + .../Io/DigitalOutput/overview/overview.ts | 36 + .../edge/history/Controller/Io/Io.module.ts | 12 + .../history/Controller/controller.module.ts | 7 +- .../app/edge/history/abstracthistorychart.ts | 156 +- .../app/edge/history/abstracthistorywidget.ts | 24 +- .../edge/history/chpsoc/chart.component.ts | 59 +- .../chpsocchartoverview.component.ts | 10 +- .../edge/history/chpsoc/widget.component.ts | 24 +- .../edge/history/common/autarchy/Autarchy.ts | 12 +- .../history/common/autarchy/chart/chart.ts | 44 +- .../edge/history/common/autarchy/flat/flat.ts | 18 +- .../common/autarchy/overview/overview.ts | 6 +- ui/src/app/edge/history/common/common.ts | 14 +- .../history/common/consumption/Consumption.ts | 24 +- .../common/consumption/chart/channels.spec.ts | 40 +- .../consumption/chart/chart.constants.spec.ts | 2 +- .../common/consumption/chart/chart.spec.ts | 52 +- .../history/common/consumption/chart/chart.ts | 70 +- .../details/chart/channels.spec.ts | 18 +- .../details/chart/consumptionMeter.spec.ts | 32 +- .../details/chart/consumptionMeter.ts | 46 +- .../consumption/details/chart/evcs.spec.ts | 20 +- .../common/consumption/details/chart/evcs.ts | 34 +- .../consumption/details/chart/sum.spec.ts | 26 +- .../common/consumption/details/chart/sum.ts | 44 +- .../consumption/details/details.overview.html | 2 +- .../consumption/details/details.overview.ts | 38 +- .../history/common/consumption/flat/flat.ts | 24 +- .../common/consumption/overview/overview.ts | 26 +- .../common/energy/chart/channels.spec.ts | 100 +- .../energy/chart/chart.constants.spec.ts | 2 +- .../history/common/energy/chart/chart.spec.ts | 120 +- .../edge/history/common/energy/chart/chart.ts | 199 +- .../app/edge/history/common/energy/energy.ts | 10 +- .../edge/history/common/energy/flat/flat.ts | 38 +- .../common/grid/chart/chart.constants.spec.ts | 2 +- .../history/common/grid/chart/chart.spec.ts | 52 +- .../edge/history/common/grid/chart/chart.ts | 138 +- .../grid/details/chart/channels.spec.ts | 8 +- .../common/grid/details/chart/chart.spec.ts | 24 +- .../common/grid/details/chart/chart.ts | 42 +- .../common/grid/details/details.overview.ts | 20 +- .../app/edge/history/common/grid/flat/flat.ts | 20 +- ui/src/app/edge/history/common/grid/grid.ts | 18 +- .../history/common/grid/overview/overview.ts | 22 +- .../production/chart/productionMeterChart.ts | 42 +- .../common/production/chart/totalChart.ts | 80 +- .../production/details/chart/channels.spec.ts | 20 +- .../production/details/chart/charger.spec.ts | 20 +- .../production/details/chart/charger.ts | 34 +- .../details/chart/productionMeter.spec.ts | 28 +- .../details/chart/productionMeter.ts | 44 +- .../production/details/chart/sum.spec.ts | 60 +- .../common/production/details/chart/sum.ts | 52 +- .../production/details/details.overview.ts | 32 +- .../history/common/production/flat/flat.ts | 10 +- .../common/production/overview/overview.ts | 22 +- .../history/common/production/production.ts | 24 +- .../selfconsumption/chart/chart.component.ts | 46 +- .../common/selfconsumption/flat/flat.ts | 18 +- .../selfconsumption/overview/overview.ts | 6 +- .../delayedselltogrid/chart.component.ts | 77 +- ...elayedselltogridchartoverview.component.ts | 10 +- .../delayedselltogrid/widget.component.ts | 12 +- ...xdigitaloutputchartoverview.component.html | 44 - ...fixdigitaloutputchartoverview.component.ts | 49 - .../fixdigitaloutput/singlechart.component.ts | 108 - .../fixdigitaloutput/totalchart.component.ts | 126 - .../fixdigitaloutput/widget.component.html | 17 - .../fixdigitaloutput/widget.component.ts | 68 - .../history/heatingelement/chart.component.ts | 43 +- .../heatingelementchartoverview.component.ts | 10 +- .../heatingelement/widget.component.ts | 28 +- .../edge/history/heatpump/chart.component.ts | 59 +- .../heatpumpchartoverview.component.ts | 12 +- .../edge/history/heatpump/widget.component.ts | 40 +- .../app/edge/history/history.component.html | 2 +- ui/src/app/edge/history/history.component.ts | 25 +- ui/src/app/edge/history/history.module.ts | 82 +- ui/src/app/edge/history/historydataservice.ts | 35 +- ...etricpeakshavingchartoverview.component.ts | 10 +- .../peakshaving/asymmetric/chart.component.ts | 85 +- .../asymmetric/widget.component.ts | 12 +- .../peakshaving/symmetric/chart.component.ts | 73 +- ...etricpeakshavingchartoverview.component.ts | 10 +- .../peakshaving/symmetric/widget.component.ts | 12 +- .../peakshaving/timeslot/chart.component.ts | 81 +- ...eslotpeakshavingchartoverview.component.ts | 10 +- .../peakshaving/timeslot/widget.component.ts | 12 +- ui/src/app/edge/history/shared.ts | 124 +- .../singlethreshold/chart.component.ts | 276 - ...inglethresholdchartoverview.component.html | 47 - .../singlethresholdchartoverview.component.ts | 51 - .../singlethreshold/widget.component.html | 18 - .../singlethreshold/widget.component.ts | 74 - .../history/storage/chargerchart.component.ts | 25 +- .../history/storage/esschart.component.ts | 45 +- .../history/storage/singlechart.component.ts | 93 +- .../history/storage/socchart.component.ts | 53 +- .../storagechartoverview.component.ts | 10 +- .../history/storage/totalchart.component.ts | 101 +- .../edge/history/storage/widget.component.ts | 20 +- .../Channelthreshold/Channelthreshold.ts | 30 +- .../app/edge/live/Controller/ChpSoc/ChpSoc.ts | 52 +- .../ChpSoc/modal/modal.component.ts | 62 +- .../Ess/FixActivePower/Ess_FixActivePower.ts | 10 +- .../Ess/FixActivePower/flat/flat.ts | 18 +- .../Ess/FixActivePower/modal/modal.ts | 12 +- .../Ess_GridOptimizedCharge.ts | 12 +- .../Ess/GridOptimizedCharge/flat/flat.ts | 48 +- .../Ess/GridOptimizedCharge/modal/modal.ts | 74 +- .../modal/predictionChart.ts | 53 +- .../TimeOfUseTariff/Ess_TimeOfUseTariff.ts | 44 +- .../Ess/TimeOfUseTariff/flat/flat.ts | 16 +- .../Ess/TimeOfUseTariff/modal/modal.ts | 22 +- .../TimeOfUseTariff/modal/powerSocChart.ts | 125 +- .../TimeOfUseTariff/modal/statePriceChart.ts | 71 +- ui/src/app/edge/live/Controller/Evcs/Evcs.ts | 12 +- .../administration.component.ts | 26 +- .../edge/live/Controller/Evcs/flat/flat.ts | 98 +- .../edge/live/Controller/Evcs/modal/modal.ts | 146 +- .../live/Controller/Evcs/popover/popover.ts | 8 +- .../Io_ChannelSingleThreshold.ts | 100 +- .../modal/modal.component.ts | 136 +- .../FixDigitalOutput/Io_FixDigitalOutput.ts | 20 +- .../FixDigitalOutput/modal/modal.component.ts | 22 +- .../Controller/Io/HeatingElement/flat/flat.ts | 54 +- .../Io/HeatingElement/modal/modal.ts | 42 +- .../Controller/Io/Heatpump/Io_Heatpump.ts | 44 +- .../Io/Heatpump/modal/modal.component.ts | 44 +- .../PeakShaving/Asymmetric/Asymmetric.ts | 36 +- .../Asymmetric/modal/modal.component.ts | 42 +- .../PeakShaving/Symmetric/Symmetric.ts | 26 +- .../Symmetric/modal/modal.component.ts | 34 +- .../Symmetric_TimeSlot/Symmetric_TimeSlot.ts | 26 +- .../modal/modal.component.ts | 44 +- .../Api_DigitalInput/Io_Api_DigitalInput.ts | 12 +- .../Api_DigitalInput/modal/modal.component.ts | 24 +- .../Evcs_Api_Cluster/Evcs_Api_Cluster.ts | 58 +- .../modal/evcs-chart/evcs.chart.ts | 46 +- .../modal/evcsCluster-modal.page.ts | 102 +- .../live/common/autarchy/Common_Autarchy.ts | 10 +- .../edge/live/common/autarchy/flat/flat.ts | 20 +- .../live/common/autarchy/modal/modal.spec.ts | 4 +- .../edge/live/common/autarchy/modal/modal.ts | 16 +- .../common/consumption/Common_Consumption.ts | 10 +- .../edge/live/common/consumption/flat/flat.ts | 44 +- .../common/consumption/modal/modal.spec.ts | 68 +- .../live/common/consumption/modal/modal.ts | 74 +- .../app/edge/live/common/grid/Common_Grid.ts | 10 +- ui/src/app/edge/live/common/grid/flat/flat.ts | 30 +- .../edge/live/common/grid/modal/modal.spec.ts | 6 +- .../app/edge/live/common/grid/modal/modal.ts | 80 +- .../common/production/Common_Production.ts | 10 +- .../edge/live/common/production/flat/flat.ts | 12 +- .../live/common/production/modal/modal.ts | 16 +- .../selfconsumption/Common_Selfconsumption.ts | 10 +- .../live/common/selfconsumption/flat/flat.ts | 20 +- .../selfconsumption/modal/modal.spec.ts | 4 +- .../common/selfconsumption/modal/modal.ts | 16 +- .../common/storage/modal/modal.component.ts | 54 +- .../live/common/storage/storage.component.ts | 82 +- .../delayedselltogrid.component.ts | 16 +- .../modal/modal.component.ts | 32 +- .../energymonitor/chart/chart.component.ts | 28 +- .../section/abstractsection.component.ts | 22 +- .../chart/section/consumption.component.ts | 40 +- .../chart/section/grid.component.ts | 86 +- .../chart/section/production.component.ts | 40 +- .../chart/section/storage.component.ts | 78 +- .../energymonitor/energymonitor.component.ts | 24 +- .../energymonitor/energymonitor.module.ts | 23 +- ui/src/app/edge/live/info/info.component.ts | 6 +- ui/src/app/edge/live/live.component.html | 2 +- ui/src/app/edge/live/live.component.ts | 17 +- ui/src/app/edge/live/live.module.ts | 86 +- ui/src/app/edge/live/livedataservice.ts | 2 +- .../edge/live/offline/offline.component.ts | 10 +- .../settings/alerting/alerting.component.ts | 44 +- ui/src/app/edge/settings/app/app.module.ts | 42 +- .../edge/settings/app/formly/formly-text.ts | 4 +- .../settings/app/formly/input-with-unit.ts | 6 +- .../formly-option-group-picker.component.ts | 4 +- .../formly-reorder-array.component.ts | 4 +- .../formly-safe-input-modal.component.ts | 4 +- .../safe-input/formly-safe-input.extended.ts | 22 +- .../app/edge/settings/app/index.component.ts | 76 +- .../edge/settings/app/install.component.ts | 72 +- .../edge/settings/app/jsonrpc/flag/flags.ts | 2 +- .../app/jsonrpc/getAppAssistant.spec.ts | 48 +- .../settings/app/jsonrpc/getAppAssistant.ts | 50 +- .../app/edge/settings/app/jsonrpc/getApps.ts | 4 +- .../settings/app/keypopup/modal.component.ts | 130 +- ui/src/app/edge/settings/app/permissions.ts | 2 +- .../app/edge/settings/app/single.component.ts | 74 +- .../app/edge/settings/app/update.component.ts | 62 +- .../settings/channels/channels.component.ts | 64 +- .../component/install/index.component.ts | 16 +- .../component/install/install.component.ts | 26 +- .../component/update/index.component.ts | 10 +- .../component/update/update.component.ts | 30 +- .../jsonrpctest/jsonrpctest.module.ts | 6 +- .../edge/settings/jsonrpctest/jsonrpctest.ts | 40 +- .../settings/network/network.component.ts | 132 +- .../network/setNetworkConfigRequest.ts | 2 +- ui/src/app/edge/settings/network/shared.ts | 10 +- .../settings/powerassistant/powerassistant.ts | 26 +- .../settings/profile/aliasupdate.component.ts | 24 +- .../channelexport/channelExportXlsxRequest.ts | 2 +- .../getModbusProtocolExportXlsxRequest.ts | 2 +- .../modbusapi/getModbusProtocolRequest.ts | 2 +- .../modbusapi/getModbusProtocolResponse.ts | 2 +- .../settings/profile/profile.component.ts | 32 +- .../app/edge/settings/settings.component.ts | 18 +- ui/src/app/edge/settings/settings.module.ts | 40 +- ui/src/app/edge/settings/settings.spec.ts | 24 +- .../system/executesystemupdate.component.ts | 12 +- .../system/maintenance/maintenance.ts | 69 +- .../system/oe-system-update.component.ts | 22 +- .../edge/settings/system/system.component.ts | 10 +- .../systemexecute/systemexecute.component.ts | 59 +- .../settings/systemlog/systemlog.component.ts | 58 +- ui/src/app/index/filter/filter.component.ts | 8 +- ui/src/app/index/index.module.ts | 16 +- ui/src/app/index/login.component.ts | 56 +- ui/src/app/index/login.spec.ts | 4 +- .../app/index/overview/overview.component.ts | 20 +- ui/src/app/index/shared/loading-screen.ts | 18 +- ui/src/app/index/shared/sumState.ts | 18 +- .../app/registration/modal/modal.component.ts | 32 +- .../registration/registration.component.ts | 10 +- .../app/registration/registration.module.ts | 10 +- .../components/abstracthistorywidget.ts | 18 +- .../chart/abstractHistoryChartOverview.ts | 2 +- .../components/chart/abstracthistorychart.ts | 381 +- .../components/chart/chart.constants.spec.ts | 14 +- .../components/chart/chart.constants.ts | 23 +- .../shared/components/chart/chart.module.ts | 2 +- ui/src/app/shared/components/chart/chart.ts | 12 +- .../shared/components/components.module.ts | 40 +- .../components/edge/currentdata.spec.ts | 22 +- .../app/shared/components/edge/currentdata.ts | 58 +- .../app/shared/components/edge/edge.spec.ts | 26 +- ui/src/app/shared/components/edge/edge.ts | 66 +- .../shared/components/edge/edgeconfig.spec.ts | 28 +- .../app/shared/components/edge/edgeconfig.ts | 153 +- .../currentVoltage/chart/asymmetricMeter.ts | 46 +- .../currentVoltage/chart/symmetricMeter.ts | 44 +- .../currentVoltage/currentVoltage.overview.ts | 6 +- .../currentVoltage/currentVoltageModule.ts | 2 +- .../edge/meter/electricity/modal.component.ts | 26 +- .../edge/meter/esscharger/modal.component.ts | 14 +- .../components/edge/meter/meter.module.ts | 2 +- .../flat/abstract-flat-widget-line.ts | 4 +- .../components/flat/abstract-flat-widget.ts | 2 +- .../flat-widget-horizontal-line.ts | 4 +- .../flat-widget-line-divider.ts | 4 +- .../flat/flat-widget-line/flat-widget-line.ts | 4 +- .../flat-widget-percentagebar.ts | 4 +- ui/src/app/shared/components/flat/flat.ts | 8 +- ui/src/app/shared/components/footer/footer.ts | 8 +- .../footer/subnavigation/footerNavigation.ts | 12 +- .../form-field-checkbox-hyperlink.wrapper.ts | 10 +- .../form-field-default-cases.wrapper.ts | 10 +- .../components/formly/form-field.wrapper.ts | 8 +- .../formly-field-checkbox-with-image.ts | 8 +- .../formly-field-modal/formlyfieldmodal.ts | 4 +- .../formly-field-radio-with-image.ts | 8 +- .../formly-select-field-modal.component.ts | 4 +- .../formly/formly-select-field.extended.ts | 6 +- .../formly/formly-skeleton-wrapper.ts | 8 +- .../formly/input-serial-number-wrapper.ts | 8 +- ui/src/app/shared/components/formly/input.ts | 8 +- .../formly/panel-wrapper.component.ts | 2 +- ui/src/app/shared/components/formly/repeat.ts | 8 +- .../components/header/header.component.ts | 80 +- .../history-data-error.component.ts | 8 +- .../components/modal/abstract-modal-line.ts | 12 +- .../shared/components/modal/abstractModal.ts | 4 +- .../modal/help-button/help-button.ts | 6 +- .../modal/modal-button/modal-button.ts | 4 +- .../modal/modal-info-line/modal-info-line.ts | 4 +- .../components/modal/modal-line/modal-line.ts | 18 +- .../modal/modal-phases/modal-phases.ts | 8 +- .../modal-value-line/modal-value-line.ts | 10 +- .../shared/components/modal/modal.module.ts | 32 +- ui/src/app/shared/components/modal/modal.ts | 12 +- .../modal-horizontal-line.ts | 4 +- .../percentagebar/percentagebar.component.ts | 6 +- .../pickdate/pickdate.component.spec.ts | 34 +- .../components/pickdate/pickdate.component.ts | 33 +- .../components/pickdate/pickdate.module.ts | 16 +- .../pickdate/popover/popover.component.ts | 34 +- .../pickdate/popover/popover.spec.ts | 10 +- .../app/shared/components/shared/converter.ts | 30 +- .../app/shared/components/shared/formatter.ts | 12 +- ui/src/app/shared/components/shared/name.ts | 4 +- .../shared/notification/notification.ts | 14 +- .../components/shared/oe-formly-component.ts | 18 +- ui/src/app/shared/components/shared/phase.ts | 2 +- .../components/shared/testing/common.ts | 48 +- .../components/shared/testing/tester.ts | 46 +- .../components/shared/testing/utils.spec.ts | 14 +- .../status/single/status.component.spec.ts | 22 +- .../status/single/status.component.ts | 34 +- ui/src/app/shared/directive/autofill.ts | 12 +- ui/src/app/shared/directive/directive.ts | 8 +- ui/src/app/shared/directive/ngvar.ts | 4 +- ui/src/app/shared/guards/functional-guards.ts | 35 + ui/src/app/shared/jsonrpc/base.ts | 2 +- .../notification/edgeConfigNotification.ts | 2 +- .../queryHistoricTimeseriesDataRequest.ts | 6 +- ...istoricTimeseriesEnergyPerPeriodRequest.ts | 6 +- .../queryHistoricTimeseriesEnergyRequest.ts | 6 +- .../queryHistoricTimeseriesExportXlxs.ts | 8 +- .../chartoptions/chartoptions.component.ts | 26 +- .../chartoptions/popover/popover.component.ts | 16 +- .../shared/pipe/classname/classname.pipe.ts | 4 +- .../formatSecondsToDuration.pipe.ts | 12 +- .../app/shared/pipe/isclass/isclass.pipe.ts | 6 +- ui/src/app/shared/pipe/keys/keys.pipe.ts | 4 +- ui/src/app/shared/pipe/pipe.ts | 22 +- ui/src/app/shared/pipe/sign/sign.pipe.ts | 4 +- ui/src/app/shared/pipe/typeof/typeof.pipe.ts | 4 +- .../pipe/unitvalue/unitvalue.pipe.spec.ts | 28 +- .../shared/pipe/unitvalue/unitvalue.pipe.ts | 20 +- .../shared/pipe/version/version.pipe.spec.ts | 10 +- .../app/shared/pipe/version/version.pipe.ts | 10 +- ui/src/app/shared/service/abstractservice.ts | 22 +- ui/src/app/shared/service/arrayutils.ts | 2 +- ui/src/app/shared/service/defaulttypes.ts | 70 +- .../service/globalRouteChangeHandler.ts | 8 +- ui/src/app/shared/service/pagination.ts | 16 +- ui/src/app/shared/service/service.ts | 142 +- ui/src/app/shared/service/utils.spec.ts | 28 +- ui/src/app/shared/service/utils.ts | 143 +- ui/src/app/shared/service/websocket.ts | 102 +- .../app/shared/service/websocketInterface.ts | 6 +- ui/src/app/shared/shared.module.ts | 106 +- ui/src/app/shared/shared.spec.ts | 26 +- ui/src/app/shared/shared.ts | 32 +- ui/src/app/shared/translate.extension.ts | 10 +- ui/src/app/shared/type/channeladdress.ts | 2 +- ui/src/app/shared/type/country.ts | 24 +- ui/src/app/shared/type/general.ts | 10 +- ui/src/app/shared/type/language.spec.ts | 8 +- ui/src/app/shared/type/language.ts | 28 +- ui/src/app/shared/type/role.ts | 4 +- ui/src/app/shared/type/systemlog.ts | 2 +- ui/src/app/shared/type/widget.ts | 102 +- .../shared/utils/array/array.utils.spec.ts | 12 +- ui/src/app/shared/utils/array/array.utils.ts | 2 +- .../shared/utils/color/color.utils.spec.ts | 14 +- ui/src/app/shared/utils/color/color.utils.ts | 8 +- .../app/shared/utils/date/dateutils.spec.ts | 16 +- ui/src/app/shared/utils/date/dateutils.ts | 2 +- .../shared/utils/datetime/datetime-utils.ts | 11 +- .../app/shared/utils/time/timeutils.spec.ts | 10 +- ui/src/app/shared/utils/time/timeutils.ts | 8 +- ui/src/app/user/user.component.ts | 51 +- ui/src/app/user/user.module.ts | 6 +- ui/src/assets/i18n/de.json | 9 +- ui/src/assets/i18n/en.json | 9 +- ui/src/environments/index.ts | 10 +- ui/src/global.scss | 9 +- ui/src/main.ts | 8 +- ui/src/polyfills.ts | 8 +- ui/src/test.ts | 6 +- .../openems/environments/backend-dev.ts | 2 +- .../openems/environments/backend-docker.ts | 2 +- .../openems/environments/backend-prod.ts | 2 +- .../themes/openems/environments/edge-dev.ts | 2 +- .../openems/environments/edge-docker.ts | 2 +- .../themes/openems/environments/edge-prod.ts | 2 +- ui/src/themes/openems/environments/gitpod.ts | 2 +- ui/src/themes/openems/environments/theme.ts | 2 +- 426 files changed, 17338 insertions(+), 17185 deletions(-) create mode 100644 .woodpecker/ui-build.yml create mode 100644 ui/android/.gitignore delete mode 100644 ui/android/gradle/wrapper/gradle-wrapper.jar delete mode 100644 ui/android/gradle/wrapper/gradle-wrapper.properties mode change 100644 => 100755 ui/android/gradlew create mode 100644 ui/src/app/edge/history/Controller/Ess/ess.module.ts create mode 100644 ui/src/app/edge/history/Controller/Io/DigitalOutput/chart/chart.ts create mode 100644 ui/src/app/edge/history/Controller/Io/DigitalOutput/details/chart/chart.ts create mode 100644 ui/src/app/edge/history/Controller/Io/DigitalOutput/details/details.overview.html create mode 100644 ui/src/app/edge/history/Controller/Io/DigitalOutput/details/details.overview.ts create mode 100644 ui/src/app/edge/history/Controller/Io/DigitalOutput/digitalOutput.module.ts create mode 100644 ui/src/app/edge/history/Controller/Io/DigitalOutput/flat/flat.html create mode 100644 ui/src/app/edge/history/Controller/Io/DigitalOutput/flat/flat.ts create mode 100644 ui/src/app/edge/history/Controller/Io/DigitalOutput/overview/overview.html create mode 100644 ui/src/app/edge/history/Controller/Io/DigitalOutput/overview/overview.ts create mode 100644 ui/src/app/edge/history/Controller/Io/Io.module.ts delete mode 100644 ui/src/app/edge/history/fixdigitaloutput/fixdigitaloutputchartoverview/fixdigitaloutputchartoverview.component.html delete mode 100644 ui/src/app/edge/history/fixdigitaloutput/fixdigitaloutputchartoverview/fixdigitaloutputchartoverview.component.ts delete mode 100644 ui/src/app/edge/history/fixdigitaloutput/singlechart.component.ts delete mode 100644 ui/src/app/edge/history/fixdigitaloutput/totalchart.component.ts delete mode 100644 ui/src/app/edge/history/fixdigitaloutput/widget.component.html delete mode 100644 ui/src/app/edge/history/fixdigitaloutput/widget.component.ts delete mode 100644 ui/src/app/edge/history/singlethreshold/chart.component.ts delete mode 100644 ui/src/app/edge/history/singlethreshold/singlethresholdchartoverview/singlethresholdchartoverview.component.html delete mode 100644 ui/src/app/edge/history/singlethreshold/singlethresholdchartoverview/singlethresholdchartoverview.component.ts delete mode 100644 ui/src/app/edge/history/singlethreshold/widget.component.html delete mode 100644 ui/src/app/edge/history/singlethreshold/widget.component.ts create mode 100644 ui/src/app/shared/guards/functional-guards.ts diff --git a/.woodpecker/ui-build.yml b/.woodpecker/ui-build.yml new file mode 100644 index 00000000000..224fc19ad14 --- /dev/null +++ b/.woodpecker/ui-build.yml @@ -0,0 +1,80 @@ +variables: + - &sftp-settings + server: ${CACHE_SERVER} + username: user + password: pass + ignore_branch: true + port: 2222 + path: /cache + mount: + - cache + + - &rsync-settings + user: fenecon-docs + hosts: + - ${ARTIFACT_SERVER} + port: 22 + key: + from_secret: ssh_key_intranet + args: '-v' + + - &main-build + - branch: [main, develop] + - evaluate: 'CI_COMMIT_MESSAGE contains "[APP]"' + - path: + include: ['.woodpecker/ui-build.yml'] + on_empty: false + +when: + event: + - push + +matrix: + THEME: + - fenecon + - heckert + +clone: + git: + when: *main-build + image: woodpeckerci/plugin-git + +steps: + restore-cache: + when: *main-build + image: appleboy/drone-sftp-cache + settings: + restore: true + <<: *sftp-settings + + prepare-environment: + when: *main-build + image: openems-bash + commands: + - export CACHE=$CI_WORKSPACE/cache + - mkdir -p $CI_WORKSPACE/cache build/target + - source tools/common.sh + - common_initialize_environment + - common_build_snapshot_version + - common_save_environment $CI_WORKSPACE/.openems-env + depends_on: [restore-cache] + + build-android-app: + when: *main-build + image: openems-android:20.32 + environment: + - THEME=${THEME} + commands: + - source $CI_WORKSPACE/.openems-env + - source tools/common.sh + - common_build_android_app + depends_on: [prepare-environment] + + refresh-dev-android: + when: *main-build + image: woodpeckerci/rsync:latest + settings: + <<: *rsync-settings + source: $CI_WORKSPACE/ui/android/target/ + target: /var/opt/develop/fems-artifacts/html/${CI_COMMIT_BRANCH} + depends_on: [build-android-app] diff --git a/io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedChargeImpl.java b/io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedChargeImpl.java index 8f323515b5e..aa727e503b4 100644 --- a/io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedChargeImpl.java +++ b/io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedChargeImpl.java @@ -145,8 +145,7 @@ private void updateConfig(Config config) { @Override public void run() throws OpenemsNamedException { - - if (!this.ess.isManaged()) { + if (!this.ess.isManaged() && this.config.mode() != Mode.OFF) { this._setConfiguredEssIsNotManaged(true); return; } diff --git a/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/RecordWorker.java b/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/RecordWorker.java index fc51ebd37b5..f363bc0293b 100644 --- a/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/RecordWorker.java +++ b/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/RecordWorker.java @@ -202,8 +202,10 @@ public void collectData() { protected void forever() throws InterruptedException { final var record = this.records.take(); - if (this.config.readOnly() && this.config.debugMode()) { - this.log.info("Read-Only-Mode is activated. Not writing record: " + record.toString()); + if (this.config.readOnly()) { + if (this.config.debugMode()) { + this.log.info("Read-Only-Mode is activated. Not writing record: " + record.toString()); + } return; } diff --git a/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/Rrd4jReadHandler.java b/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/Rrd4jReadHandler.java index 6747b3b96d9..7ee00663374 100644 --- a/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/Rrd4jReadHandler.java +++ b/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/Rrd4jReadHandler.java @@ -4,6 +4,7 @@ import java.time.Instant; import java.time.ZoneOffset; import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; import java.util.List; import java.util.Optional; import java.util.Set; @@ -479,10 +480,10 @@ public SortedMap> queryHis }, (t, u) -> t, TreeMap::new)); } - private static record Range(ZonedDateTime from, ZonedDateTime to) { + protected static record Range(ZonedDateTime from, ZonedDateTime to) { } - private static Stream streamRanges(// + protected static Stream streamRanges(// final ZonedDateTime from, // final ZonedDateTime to, // final Resolution resolution // @@ -493,7 +494,8 @@ private static Stream streamRanges(// final var builder = Stream.builder(); var fromRange = from; - var toRange = increase(from, resolution); + + var toRange = truncate(increase(from, resolution), resolution); if (toRange.isAfter(to)) { toRange = to; } @@ -501,7 +503,7 @@ private static Stream streamRanges(// while (!fromRange.equals(toRange)) { builder.accept(new Range(fromRange, toRange)); fromRange = toRange; - toRange = increase(toRange, resolution); + toRange = truncate(increase(fromRange, resolution), resolution); if (toRange.isAfter(to)) { toRange = to; } @@ -510,6 +512,18 @@ private static Stream streamRanges(// return builder.build(); } + private static ZonedDateTime truncate(ZonedDateTime date, Resolution resolution) { + return switch (resolution.getUnit()) { + case DAYS, HALF_DAYS, HOURS, SECONDS, MINUTES, MILLIS, NANOS, MICROS -> { + yield date.truncatedTo(resolution.getUnit()); + } + case CENTURIES, DECADES, ERAS, FOREVER, MILLENNIA, YEARS, WEEKS -> { + throw new UnsupportedOperationException(); + } + case MONTHS -> date.withDayOfMonth(1).truncatedTo(ChronoUnit.DAYS); + }; + } + private static ZonedDateTime increase(ZonedDateTime date, Resolution resolution) { return switch (resolution.getUnit()) { case DAYS, HALF_DAYS, HOURS, SECONDS, MINUTES, MILLIS, NANOS, MICROS -> { diff --git a/io.openems.edge.timedata.rrd4j/test/io/openems/edge/timedata/rrd4j/Rrd4jReadHandlerTest.java b/io.openems.edge.timedata.rrd4j/test/io/openems/edge/timedata/rrd4j/Rrd4jReadHandlerTest.java index 635a3035742..f0c0eab0d27 100644 --- a/io.openems.edge.timedata.rrd4j/test/io/openems/edge/timedata/rrd4j/Rrd4jReadHandlerTest.java +++ b/io.openems.edge.timedata.rrd4j/test/io/openems/edge/timedata/rrd4j/Rrd4jReadHandlerTest.java @@ -163,6 +163,21 @@ public void testQueryHistoricDataWithResolution15minutes() throws Exception { ), this.query(new Resolution(15, ChronoUnit.MINUTES))); } + @Test + public void testStreamRanges() throws Exception { + final var utc = ZoneId.of("UTC"); + final var from = ZonedDateTime.of(2023, 12, 26, 0, 0, 0, 0, utc); + final var to = ZonedDateTime.of(2024, 3, 8, 0, 0, 0, 0, utc); + final var result = Rrd4jReadHandler.streamRanges(from, to, new Resolution(1, ChronoUnit.MONTHS)).toList(); + assertEquals(4, result.size()); + assertEquals(new Rrd4jReadHandler.Range(from, ZonedDateTime.of(2024, 1, 1, 0, 0, 0, 0, utc)), result.get(0)); + assertEquals(new Rrd4jReadHandler.Range(ZonedDateTime.of(2024, 1, 1, 0, 0, 0, 0, utc), + ZonedDateTime.of(2024, 2, 1, 0, 0, 0, 0, utc)), result.get(1)); + assertEquals(new Rrd4jReadHandler.Range(ZonedDateTime.of(2024, 2, 1, 0, 0, 0, 0, utc), + ZonedDateTime.of(2024, 3, 1, 0, 0, 0, 0, utc)), result.get(2)); + assertEquals(new Rrd4jReadHandler.Range(ZonedDateTime.of(2024, 3, 1, 0, 0, 0, 0, utc), to), result.get(3)); + } + private SortedMap> query(Resolution resolution) throws IllegalArgumentException, OpenemsNamedException { return this.readHandler.queryHistoricData(this.rrdbId, // diff --git a/tools/common.sh b/tools/common.sh index 47370e548d1..d18b68f18be 100644 --- a/tools/common.sh +++ b/tools/common.sh @@ -11,8 +11,9 @@ common_initialize_environment() { SRC_ANDROID_GRADLE="ui/android/app/build.gradle" # Set environment variables - THEME="openems" + THEME="${THEME:-openems}" PACKAGE_NAME="openems-edge" + VERSION_STRING="" VERSION="$(cd ui && node -p "require('./package.json').version" && cd ..)" local tmp_version=$(echo $VERSION | cut -d'-' -f1) @@ -120,6 +121,36 @@ common_build_ui() { fi } +common_build_android_app() { + echo "# Build OpenEMS Android APP" + if [ "${NODE_MODULES_CACHE}" != "" -a -d "$NODE_MODULES_CACHE" ]; then + echo "## Use cached node_modules" + mv -f "${NODE_MODULES_CACHE}" "ui/node_modules" + fi + cd ui + + # Install dependencies from package.json + npm ci + if [ "${NG_CLI_CACHE_PATH}" != "" ]; then + echo "## Angular Cache: $NG_CLI_CACHE_PATH" + node_modules/.bin/ng config cli.cache.path "$NG_CLI_CACHE_PATH" + fi + + case "${THEME^^}" in + "FENECON") NODE_ENV="FENECON";; + "HECKERT") NODE_ENV="Heckert";; + esac + + # Install depencencies for capacitor + NODE_ENV=${NODE_ENV} ionic cap build android -c "${THEME},${THEME}-backend-deploy-app" + + # Build App + cd android + THEME=${THEME} ./gradlew buildThemeRelease + + cd ../.. +} + common_save_environment() { local file=${1:-build.environment} echo " @@ -132,4 +163,4 @@ common_save_environment() { export VERSION_DEV_COMMIT=\"$VERSION_DEV_COMMIT\" export VERSION_DEV_BUILD_TIME=\"$VERSION_DEV_BUILD_TIME\" " | tee $file -} \ No newline at end of file +} diff --git a/tools/drone/openems-android.sh b/tools/drone/openems-android.sh index 8e19fd37bea..91067d639ab 100755 --- a/tools/drone/openems-android.sh +++ b/tools/drone/openems-android.sh @@ -2,10 +2,10 @@ NODE_MAJOR=20 -ANDROID_SDK_VERSION=9477386 +ANDROID_SDK_VERSION=11076708 ANDROID_HOME="/opt/android-sdk" -ANDROID_BUILD_TOOLS_VERSION=32.0.0 -ANDROID_PLATFORMS_VERSION=32 +ANDROID_BUILD_TOOLS_VERSION=34.0.0 +ANDROID_PLATFORMS_VERSION=34 # Build/Update 'openems-android' Container for Drone/Woodpecker CI @@ -14,6 +14,8 @@ docker pull node:${NODE_MAJOR} docker build -t openems-android:${NODE_MAJOR}.${ANDROID_PLATFORMS_VERSION} -f - . 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 diff --git a/ui/android/gradle/wrapper/gradle-wrapper.properties b/ui/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index cab95f43c39..00000000000 --- a/ui/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -#Thu Apr 04 11:31:47 CEST 2024 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip -networkTimeout=10000 -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/ui/android/gradlew b/ui/android/gradlew old mode 100644 new mode 100755 index 79a61d421cc..5b9a91774fe --- a/ui/android/gradlew +++ b/ui/android/gradlew @@ -1,244 +1,6 @@ -#!/bin/sh +#!/bin/bash -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# +SCRIPT_DIR="$( readlink -f $( dirname -- "${BASH_SOURCE[0]}" ))" +ROOT="${SCRIPT_DIR%/*/*}" -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" +$ROOT/gradlew $@ diff --git a/ui/android/gradlew.bat b/ui/android/gradlew.bat index 93e3f59f135..0aaa0ca9698 100644 --- a/ui/android/gradlew.bat +++ b/ui/android/gradlew.bat @@ -1,92 +1,4 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@echo off&setlocal +set ROOT=%~dp0..\.. + +CALL %ROOT%\gradlew.bat diff --git a/ui/android/variables.gradle b/ui/android/variables.gradle index 232bd9dd0c5..631e62221ee 100644 --- a/ui/android/variables.gradle +++ b/ui/android/variables.gradle @@ -1,7 +1,7 @@ ext { minSdkVersion = 22 - compileSdkVersion = 33 - targetSdkVersion = 33 + compileSdkVersion = 34 + targetSdkVersion = 34 androidxActivityVersion = '1.7.0' androidxAppCompatVersion = '1.6.1' androidxCoordinatorLayoutVersion = '1.2.0' diff --git a/ui/capacitor.config.ts b/ui/capacitor.config.ts index 7702fbd212e..eadd5c3ecba 100644 --- a/ui/capacitor.config.ts +++ b/ui/capacitor.config.ts @@ -22,10 +22,10 @@ const baseConfig: CapacitorConfig = { useDialog: true, }, CapacitorCookies: { - enabled: true - } - } -} + enabled: true, + }, + }, +}; switch (process.env.NODE_ENV as Theme) { // case 'EXAMPLE': @@ -40,8 +40,7 @@ switch (process.env.NODE_ENV as Theme) { // } // break; default: - throw new Error(`Capacitor config for theme ${process.env.NODE_ENV} not implemented.`) -} -console.warn(config); + throw new Error(`Capacitor config for theme ${process.env.NODE_ENV} not implemented.`); +} export default config; diff --git a/ui/package-lock.json b/ui/package-lock.json index 1e2cea1fdd0..eb23f05a996 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -9,33 +9,32 @@ "version": "2024.9.0-SNAPSHOT", "license": "AGPL-3.0", "dependencies": { - "@angular/animations": "~16.2.12", - "@angular/common": "~16.2.12", - "@angular/core": "~16.2.12", - "@angular/forms": "~16.2.12", - "@angular/platform-browser": "~16.2.12", - "@angular/platform-browser-dynamic": "~16.2.12", - "@angular/router": "~16.2.12", - "@angular/service-worker": "~16.2.12", - "@capacitor-community/file-opener": "^1.0.5", - "@capacitor/android": "5.7.8", - "@capacitor/app": "^5.0.6", - "@capacitor/core": "5.7.8", - "@capacitor/filesystem": "^5.2.0", - "@capacitor/ios": "5.7.8", - "@capacitor/splash-screen": "^5.0.6", + "@angular/animations": "18.0.5", + "@angular/common": "18.0.5", + "@angular/core": "18.0.5", + "@angular/forms": "18.0.5", + "@angular/platform-browser": "18.0.5", + "@angular/platform-browser-dynamic": "18.0.5", + "@angular/router": "18.0.5", + "@angular/service-worker": "18.0.5", + "@capacitor-community/file-opener": "^6.0.0", + "@capacitor/android": "^6.0.0", + "@capacitor/app": "^6.0.0", + "@capacitor/core": "^6.0.0", + "@capacitor/filesystem": "^6.0.0", + "@capacitor/ios": "^6.0.0", + "@capacitor/splash-screen": "^6.0.0", "@ionic-native/core": "^5.36.0", "@ionic-native/file-opener": "^5.36.0", "@ionic/angular": "^6.7.5", - "@ionic/cli": "^7.1.6", "@ngx-formly/core": "^6.3.0", "@ngx-formly/ionic": "^6.3.6", "@ngx-formly/schematics": "^6.3.0", "@ngx-translate/core": "^15.0.0", "@nodro7/angular-mydatepicker": "^0.14.0", "capacitor-blob-writer": "^1.1.17", - "capacitor-ios-autofill-save-password": "^2.0.0", - "capacitor-secure-storage-plugin": "^0.9.0", + "capacitor-ios-autofill-save-password": "^3.0.0", + "capacitor-secure-storage-plugin": "^0.10.0", "chart.js": "^4.4.4", "chartjs-adapter-date-fns": "^3.0.0", "chartjs-plugin-annotation": "^3.0.1", @@ -47,39 +46,47 @@ "date-fns": "^2.30.0", "file-saver-es": "^2.0.5", "ng2-charts": "4.1.1", - "ngx-cookie-service": "^16.1.0", - "ngx-device-detector": "^6.0.2", + "ngx-cookie-service": "18.0.0", + "ngx-device-detector": "^8.0.0", "ngx-spinner": "^16.0.2", "roboto-fontface": "^0.10.0", "rxjs": "~6.6.7", "swiper": "11.1.11", "tslib": "^2.6.2", "uuid": "^10.0.0", - "zone.js": "~0.13.3" + "zone.js": "~0.14.7" }, "devDependencies": { - "@angular-devkit/build-angular": "^16.2.15", - "@angular-eslint/builder": "^16.3.1", - "@angular-eslint/eslint-plugin": "^16.3.1", - "@angular-eslint/eslint-plugin-template": "^16.3.1", - "@angular-eslint/template-parser": "^16.3.1", - "@angular/cli": "^16.2.13", - "@angular/compiler": "^16.2.12", - "@angular/compiler-cli": "^16.2.12", - "@angular/language-service": "^16.2.12", - "@capacitor/assets": "^3.0.0", + "@angular-devkit/build-angular": "^18.0.5", + "@angular-devkit/core": "18.0.5", + "@angular-devkit/schematics": "18.0.5", + "@angular-eslint/builder": "^18.1.0", + "@angular-eslint/eslint-plugin": "^18.1.0", + "@angular-eslint/eslint-plugin-template": "^18.1.0", + "@angular-eslint/template-parser": "^18.1.0", + "@angular/cli": "18.1.0", + "@angular/compiler": "18.0.5", + "@angular/compiler-cli": "18.0.5", + "@angular/language-service": "18.0.5", + "@capacitor/assets": "^3.0.5", "@capacitor/cli": "6.1.2", "@ionic/angular-toolkit": "^11.0.1", + "@ionic/cli": "^7.2.0", "@stylistic/eslint-plugin": "^2.7.2", "@types/jasmine": "~4.3.6", "@types/jasminewd2": "~2.0.13", + "@types/json-schema": "^7.0.15", "@types/node": "^20.12.6", + "@types/qs": "^6.9.15", + "@types/range-parser": "^1.2.7", + "@types/send": "^0.17.4", "@types/uuid": "^10.0.0", - "@typescript-eslint/eslint-plugin": "^6.21.0", - "@typescript-eslint/parser": "^6.21.0", + "@typescript-eslint/eslint-plugin": "^7.0.0", + "@typescript-eslint/parser": "^7.0.0", + "@typescript-eslint/types": "^7.0.0", "eslint": "^8.57.0", "eslint-plugin-import": "2.29.1", - "eslint-plugin-jsdoc": "48.2.3", + "eslint-plugin-jsdoc": "48.10.0", "eslint-plugin-prefer-arrow": "1.2.3", "eslint-plugin-unused-imports": "^4.1.3", "jasmine-core": "~4.5.0", @@ -92,20 +99,10 @@ "karma-jasmine-html-reporter": "^2.1.0", "protractor": "~7.0.0", "ts-node": "^10.9.2", - "typescript": "~4.9.5", + "typescript": "~5.4.5", "typescript-strict-plugin": "^2.4.4" } }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@ampproject/remapping": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", @@ -121,19 +118,64 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.1602.13", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.13.tgz", - "integrity": "sha512-ejrOYoXgbhDYjdaW4B2SyWeb6AqR8vqqzMyvCq2JX7fo08IhLnVu1fcl0fwr161l37TuzgPNWrHSciOzzmZDkw==", + "version": "0.1802.2", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1802.2.tgz", + "integrity": "sha512-LPRl9jhcf0NgshaL6RoUy1uL/cAyNt7oxctoZ9EHUu8eh5E9W/jZGhVowjOLpirwqYhmEzKJJIeS49Ssqs3RQg==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "16.2.13", + "@angular-devkit/core": "18.2.2", "rxjs": "7.8.1" }, "engines": { - "node": "^16.14.0 || >=18.10.0", + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/architect/node_modules/@angular-devkit/core": { + "version": "18.2.2", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.2.tgz", + "integrity": "sha512-Zz0tGptI/QQnUBDdp+1G5wGwQWMjpfe2oO+UohkrDVgFS71yVj4VDnOy51kMTxBvzw+36evTgthPpmzqPIfxBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "8.17.1", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.2", + "rxjs": "7.8.1", + "source-map": "0.7.4" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/architect/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, "node_modules/@angular-devkit/architect/node_modules/rxjs": { @@ -147,96 +189,97 @@ } }, "node_modules/@angular-devkit/build-angular": { - "version": "16.2.15", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-16.2.15.tgz", - "integrity": "sha512-gw9wQENYVNUCB2bnzk0yKd6YGlemDwuwKnrPnSm4myyMuScZpW+e+zliGW+JXRuVWZqiTJNcdd58e4CrrreILg==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "2.2.1", - "@angular-devkit/architect": "0.1602.15", - "@angular-devkit/build-webpack": "0.1602.15", - "@angular-devkit/core": "16.2.15", - "@babel/core": "7.22.9", - "@babel/generator": "7.22.9", - "@babel/helper-annotate-as-pure": "7.22.5", - "@babel/helper-split-export-declaration": "7.22.6", - "@babel/plugin-proposal-async-generator-functions": "7.20.7", - "@babel/plugin-transform-async-to-generator": "7.22.5", - "@babel/plugin-transform-runtime": "7.22.9", - "@babel/preset-env": "7.22.9", - "@babel/runtime": "7.22.6", - "@babel/template": "7.22.5", - "@discoveryjs/json-ext": "0.5.7", - "@ngtools/webpack": "16.2.15", - "@vitejs/plugin-basic-ssl": "1.0.1", + "version": "18.2.2", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-18.2.2.tgz", + "integrity": "sha512-7HEnTN2T1jnjuItXKcApOsoYGgfou4+POju3ZbwIQukDZ3B2COskvQkVTxqPNrQ0ZjT2mxZYoVlmGW9M+7N25g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "2.3.0", + "@angular-devkit/architect": "0.1802.2", + "@angular-devkit/build-webpack": "0.1802.2", + "@angular-devkit/core": "18.2.2", + "@angular/build": "18.2.2", + "@babel/core": "7.25.2", + "@babel/generator": "7.25.0", + "@babel/helper-annotate-as-pure": "7.24.7", + "@babel/helper-split-export-declaration": "7.24.7", + "@babel/plugin-transform-async-generator-functions": "7.25.0", + "@babel/plugin-transform-async-to-generator": "7.24.7", + "@babel/plugin-transform-runtime": "7.24.7", + "@babel/preset-env": "7.25.3", + "@babel/runtime": "7.25.0", + "@discoveryjs/json-ext": "0.6.1", + "@ngtools/webpack": "18.2.2", + "@vitejs/plugin-basic-ssl": "1.1.0", "ansi-colors": "4.1.3", - "autoprefixer": "10.4.14", + "autoprefixer": "10.4.20", "babel-loader": "9.1.3", - "babel-plugin-istanbul": "6.1.1", "browserslist": "^4.21.5", - "chokidar": "3.5.3", - "copy-webpack-plugin": "11.0.0", - "critters": "0.0.20", - "css-loader": "6.8.1", - "esbuild-wasm": "0.18.17", - "fast-glob": "3.3.1", - "guess-parser": "0.4.22", - "https-proxy-agent": "5.0.1", - "inquirer": "8.2.4", - "jsonc-parser": "3.2.0", + "copy-webpack-plugin": "12.0.2", + "critters": "0.0.24", + "css-loader": "7.1.2", + "esbuild-wasm": "0.23.0", + "fast-glob": "3.3.2", + "http-proxy-middleware": "3.0.0", + "https-proxy-agent": "7.0.5", + "istanbul-lib-instrument": "6.0.3", + "jsonc-parser": "3.3.1", "karma-source-map-support": "1.4.0", - "less": "4.1.3", - "less-loader": "11.1.0", + "less": "4.2.0", + "less-loader": "12.2.0", "license-webpack-plugin": "4.0.2", - "loader-utils": "3.2.1", - "magic-string": "0.30.1", - "mini-css-extract-plugin": "2.7.6", - "mrmime": "1.0.1", - "open": "8.4.2", + "loader-utils": "3.3.1", + "magic-string": "0.30.11", + "mini-css-extract-plugin": "2.9.0", + "mrmime": "2.0.0", + "open": "10.1.0", "ora": "5.4.1", "parse5-html-rewriting-stream": "7.0.0", - "picomatch": "2.3.1", - "piscina": "4.0.0", - "postcss": "8.4.31", - "postcss-loader": "7.3.3", + "picomatch": "4.0.2", + "piscina": "4.6.1", + "postcss": "8.4.41", + "postcss-loader": "8.1.1", "resolve-url-loader": "5.0.0", "rxjs": "7.8.1", - "sass": "1.64.1", - "sass-loader": "13.3.2", - "semver": "7.5.4", - "source-map-loader": "4.0.1", + "sass": "1.77.6", + "sass-loader": "16.0.0", + "semver": "7.6.3", + "source-map-loader": "5.0.0", "source-map-support": "0.5.21", - "terser": "5.19.2", - "text-table": "0.2.0", + "terser": "5.31.6", "tree-kill": "1.2.2", - "tslib": "2.6.1", - "vite": "4.5.3", + "tslib": "2.6.3", + "vite": "5.4.0", + "watchpack": "2.4.1", "webpack": "5.94.0", - "webpack-dev-middleware": "6.1.2", - "webpack-dev-server": "4.15.1", - "webpack-merge": "5.9.0", + "webpack-dev-middleware": "7.3.0", + "webpack-dev-server": "5.0.4", + "webpack-merge": "6.0.1", "webpack-subresource-integrity": "5.1.0" }, "engines": { - "node": "^16.14.0 || >=18.10.0", + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" }, "optionalDependencies": { - "esbuild": "0.18.17" + "esbuild": "0.23.0" }, "peerDependencies": { - "@angular/compiler-cli": "^16.0.0", - "@angular/localize": "^16.0.0", - "@angular/platform-server": "^16.0.0", - "@angular/service-worker": "^16.0.0", + "@angular/compiler-cli": "^18.0.0", + "@angular/localize": "^18.0.0", + "@angular/platform-server": "^18.0.0", + "@angular/service-worker": "^18.0.0", + "@web/test-runner": "^0.18.0", + "browser-sync": "^3.0.2", "jest": "^29.5.0", "jest-environment-jsdom": "^29.5.0", "karma": "^6.3.0", - "ng-packagr": "^16.0.0", + "ng-packagr": "^18.0.0", "protractor": "^7.0.0", "tailwindcss": "^2.0.0 || ^3.0.0", - "typescript": ">=4.9.3 <5.2" + "typescript": ">=5.4 <5.6" }, "peerDependenciesMeta": { "@angular/localize": { @@ -248,6 +291,12 @@ "@angular/service-worker": { "optional": true }, + "@web/test-runner": { + "optional": true + }, + "browser-sync": { + "optional": true + }, "jest": { "optional": true }, @@ -268,50 +317,22 @@ } } }, - "node_modules/@angular-devkit/build-angular/node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/architect": { - "version": "0.1602.15", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.15.tgz", - "integrity": "sha512-+yPlUG5c8l7Z/A6dyeV7NQjj4WDWnWWQt+8eW/KInwVwoYiM32ntTJ0M4uU/aDdHuwKQnMLly28AcSWPWKYf2Q==", - "dev": true, - "dependencies": { - "@angular-devkit/core": "16.2.15", - "rxjs": "7.8.1" - }, - "engines": { - "node": "^16.14.0 || >=18.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core": { - "version": "16.2.15", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.15.tgz", - "integrity": "sha512-68BgPWpcjNKz++uvLFG8IZaOH3ti2BWQVqaE3yTIYaMoNt0y0A0X2MUVd7EGbAGUk2JdloWJv5LTPVZMzCuK4w==", + "version": "18.2.2", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.2.tgz", + "integrity": "sha512-Zz0tGptI/QQnUBDdp+1G5wGwQWMjpfe2oO+UohkrDVgFS71yVj4VDnOy51kMTxBvzw+36evTgthPpmzqPIfxBw==", "dev": true, + "license": "MIT", "dependencies": { - "ajv": "8.12.0", - "ajv-formats": "2.1.1", - "jsonc-parser": "3.2.0", - "picomatch": "2.3.1", + "ajv": "8.17.1", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.2", "rxjs": "7.8.1", "source-map": "0.7.4" }, "engines": { - "node": "^16.14.0 || >=18.10.0", + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" }, @@ -324,351 +345,525 @@ } } }, - "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core/node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/@babel/core": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.9.tgz", - "integrity": "sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.5", - "@babel/generator": "^7.22.9", - "@babel/helper-compilation-targets": "^7.22.9", - "@babel/helper-module-transforms": "^7.22.9", - "@babel/helpers": "^7.22.6", - "@babel/parser": "^7.22.7", - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.8", - "@babel/types": "^7.22.5", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", - "semver": "^6.3.1" + "node_modules/@angular-devkit/build-angular/node_modules/@angular/build": { + "version": "18.2.2", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-18.2.2.tgz", + "integrity": "sha512-okaDdTMXnDhvnnnih6rPQnexL6htfEAPr19bB1Ci9d31gEjVuKZCjlcw2sPZ6BUyilwC9nZlCI5vbH1Ljf6mzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "2.3.0", + "@angular-devkit/architect": "0.1802.2", + "@babel/core": "7.25.2", + "@babel/helper-annotate-as-pure": "7.24.7", + "@babel/helper-split-export-declaration": "7.24.7", + "@babel/plugin-syntax-import-attributes": "7.24.7", + "@inquirer/confirm": "3.1.22", + "@vitejs/plugin-basic-ssl": "1.1.0", + "browserslist": "^4.23.0", + "critters": "0.0.24", + "esbuild": "0.23.0", + "fast-glob": "3.3.2", + "https-proxy-agent": "7.0.5", + "listr2": "8.2.4", + "lmdb": "3.0.13", + "magic-string": "0.30.11", + "mrmime": "2.0.0", + "parse5-html-rewriting-stream": "7.0.0", + "picomatch": "4.0.2", + "piscina": "4.6.1", + "rollup": "4.20.0", + "sass": "1.77.6", + "semver": "7.6.3", + "vite": "5.4.0", + "watchpack": "2.4.1" }, "engines": { - "node": ">=6.9.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" + "peerDependencies": { + "@angular/compiler-cli": "^18.0.0", + "@angular/localize": "^18.0.0", + "@angular/platform-server": "^18.0.0", + "@angular/service-worker": "^18.0.0", + "less": "^4.2.0", + "postcss": "^8.4.0", + "tailwindcss": "^2.0.0 || ^3.0.0", + "typescript": ">=5.4 <5.6" + }, + "peerDependenciesMeta": { + "@angular/localize": { + "optional": true + }, + "@angular/platform-server": { + "optional": true + }, + "@angular/service-worker": { + "optional": true + }, + "less": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tailwindcss": { + "optional": true + } } }, - "node_modules/@angular-devkit/build-angular/node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.20.0.tgz", + "integrity": "sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA==", + "cpu": [ + "arm" + ], "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } + "license": "MIT", + "optional": true, + "os": [ + "android" + ] }, - "node_modules/@angular-devkit/build-angular/node_modules/@babel/runtime": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.6.tgz", - "integrity": "sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-android-arm64": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.20.0.tgz", + "integrity": "sha512-u00Ro/nok7oGzVuh/FMYfNoGqxU5CPWz1mxV85S2w9LxHR8OoMQBuSk+3BKVIDYgkpeOET5yXkx90OYFc+ytpQ==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "regenerator-runtime": "^0.13.11" - }, - "engines": { - "node": ">=6.9.0" - } + "optional": true, + "os": [ + "android" + ] }, - "node_modules/@angular-devkit/build-angular/node_modules/@babel/template": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", - "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.20.0.tgz", + "integrity": "sha512-uFVfvzvsdGtlSLuL0ZlvPJvl6ZmrH4CBwLGEFPe7hUmf7htGAN+aXo43R/V6LATyxlKVC/m6UsLb7jbG+LG39Q==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@angular-devkit/build-angular/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-darwin-x64": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.20.0.tgz", + "integrity": "sha512-xbrMDdlev53vNXexEa6l0LffojxhqDTBeL+VUxuuIXys4x6xyvbKq5XqTXBCEUA8ty8iEJblHvFaWRJTk/icAQ==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@angular-devkit/build-angular/node_modules/fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.20.0.tgz", + "integrity": "sha512-jMYvxZwGmoHFBTbr12Xc6wOdc2xA5tF5F2q6t7Rcfab68TT0n+r7dgawD4qhPEvasDsVpQi+MgDzj2faOLsZjA==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@angular-devkit/build-angular/node_modules/less": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/less/-/less-4.1.3.tgz", - "integrity": "sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.20.0.tgz", + "integrity": "sha512-1asSTl4HKuIHIB1GcdFHNNZhxAYEdqML/MW4QmPS4G0ivbEcBr1JKlFLKsIRqjSwOBkdItn3/ZDlyvZ/N6KPlw==", + "cpu": [ + "arm" + ], "dev": true, - "license": "Apache-2.0", - "dependencies": { - "copy-anything": "^2.0.1", - "parse-node-version": "^1.0.1", - "tslib": "^2.3.0" - }, - "bin": { - "lessc": "bin/lessc" - }, - "engines": { - "node": ">=6" - }, - "optionalDependencies": { - "errno": "^0.1.1", - "graceful-fs": "^4.1.2", - "image-size": "~0.5.0", - "make-dir": "^2.1.0", - "mime": "^1.4.1", - "needle": "^3.1.0", - "source-map": "~0.6.0" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@angular-devkit/build-angular/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.20.0.tgz", + "integrity": "sha512-COBb8Bkx56KldOYJfMf6wKeYJrtJ9vEgBRAOkfw6Ens0tnmzPqvlpjZiLgkhg6cA3DGzCmLmmd319pmHvKWWlQ==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@angular-devkit/build-angular/node_modules/postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.20.0.tgz", + "integrity": "sha512-+it+mBSyMslVQa8wSPvBx53fYuZK/oLTu5RJoXogjk6x7Q7sz1GNRsXWjn6SwyJm8E/oMjNVwPhmNdIjwP135Q==", + "cpu": [ + "arm64" ], + "dev": true, "license": "MIT", - "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@angular-devkit/build-angular/node_modules/regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.20.0.tgz", + "integrity": "sha512-yAMvqhPfGKsAxHN8I4+jE0CpLWD8cv4z7CK7BMmhjDuz606Q2tFKkWRY8bHR9JQXYcoLfopo5TTqzxgPUjUMfw==", + "cpu": [ + "ppc64" + ], "dev": true, - "license": "MIT" - }, - "node_modules/@angular-devkit/build-angular/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.20.0.tgz", + "integrity": "sha512-qmuxFpfmi/2SUkAw95TtNq/w/I7Gpjurx609OOOV7U4vhvUhBcftcmXwl3rqAek+ADBwSjIC4IVNLiszoj3dPA==", + "cpu": [ + "riscv64" + ], "dev": true, - "dependencies": { - "tslib": "^2.1.0" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@angular-devkit/build-angular/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==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.20.0.tgz", + "integrity": "sha512-I0BtGXddHSHjV1mqTNkgUZLnS3WtsqebAXv11D5BZE/gfw5KoyXSAXVqyJximQXNvNzUo4GKlCK/dIwXlz+jlg==", + "cpu": [ + "s390x" + ], "dev": true, - "license": "ISC", + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.20.0.tgz", + "integrity": "sha512-y+eoL2I3iphUg9tN9GB6ku1FA8kOfmF4oUEWhztDJ4KXJy1agk/9+pejOuZkNFhRwHAOxMsBPLbXPd6mJiCwew==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.20.0.tgz", + "integrity": "sha512-hM3nhW40kBNYUkZb/r9k2FKK+/MnKglX7UYd4ZUy5DJs8/sMsIbqWK2piZtVGE3kcXVNj3B2IrUYROJMMCikNg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.20.0.tgz", + "integrity": "sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.20.0.tgz", + "integrity": "sha512-GabekH3w4lgAJpVxkk7hUzUf2hICSQO0a/BLFA11/RMxQT92MabKAqyubzDZmMOC/hcJNlc+rrypzNzYl4Dx7A==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.20.0.tgz", + "integrity": "sha512-aJ1EJSuTdGnM6qbVC4B5DSmozPTqIag9fSzXRNNo+humQLG89XpPgdt16Ia56ORD7s+H8Pmyx44uczDQ0yDzpg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@angular-devkit/build-angular/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" }, - "bin": { - "semver": "bin/semver.js" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@angular-devkit/build-angular/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/@angular-devkit/build-angular/node_modules/emoji-regex": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", "dev": true, - "license": "BSD-3-Clause", - "optional": true, + "license": "MIT" + }, + "node_modules/@angular-devkit/build-angular/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@angular-devkit/build-angular/node_modules/listr2": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.4.tgz", + "integrity": "sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=18.0.0" } }, - "node_modules/@angular-devkit/build-angular/node_modules/terser": { - "version": "5.19.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.19.2.tgz", - "integrity": "sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==", + "node_modules/@angular-devkit/build-angular/node_modules/rollup": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.20.0.tgz", + "integrity": "sha512-6rbWBChcnSGzIlXeIdNIZTopKYad8ZG8ajhl78lGRLsI2rX8IkaotQhVas2Ma+GPxJav19wrSzvRvuiv0YKzWw==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" + "@types/estree": "1.0.5" }, "bin": { - "terser": "bin/terser" + "rollup": "dist/bin/rollup" }, "engines": { - "node": ">=10" + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.20.0", + "@rollup/rollup-android-arm64": "4.20.0", + "@rollup/rollup-darwin-arm64": "4.20.0", + "@rollup/rollup-darwin-x64": "4.20.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.20.0", + "@rollup/rollup-linux-arm-musleabihf": "4.20.0", + "@rollup/rollup-linux-arm64-gnu": "4.20.0", + "@rollup/rollup-linux-arm64-musl": "4.20.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.20.0", + "@rollup/rollup-linux-riscv64-gnu": "4.20.0", + "@rollup/rollup-linux-s390x-gnu": "4.20.0", + "@rollup/rollup-linux-x64-gnu": "4.20.0", + "@rollup/rollup-linux-x64-musl": "4.20.0", + "@rollup/rollup-win32-arm64-msvc": "4.20.0", + "@rollup/rollup-win32-ia32-msvc": "4.20.0", + "@rollup/rollup-win32-x64-msvc": "4.20.0", + "fsevents": "~2.3.2" } }, - "node_modules/@angular-devkit/build-angular/node_modules/tslib": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", - "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==", + "node_modules/@angular-devkit/build-angular/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, - "license": "0BSD" + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } }, - "node_modules/@angular-devkit/build-angular/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "node_modules/@angular-devkit/build-angular/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, - "license": "ISC" + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/@angular-devkit/build-webpack": { - "version": "0.1602.15", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1602.15.tgz", - "integrity": "sha512-ms1+vCDdV0KX8BplJ7JoKH3wKjWHxxZTOX+mSPIjt4wS1uAk5DnezXHIjpBiJ3HY9XVHFI9C0HT4n7o6kFIOEQ==", + "node_modules/@angular-devkit/build-angular/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, + "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.1602.15", - "rxjs": "7.8.1" + "ansi-regex": "^6.0.1" }, "engines": { - "node": "^16.14.0 || >=18.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" + "node": ">=12" }, - "peerDependencies": { - "webpack": "^5.30.0", - "webpack-dev-server": "^4.0.0" + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/architect": { - "version": "0.1602.15", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.15.tgz", - "integrity": "sha512-+yPlUG5c8l7Z/A6dyeV7NQjj4WDWnWWQt+8eW/KInwVwoYiM32ntTJ0M4uU/aDdHuwKQnMLly28AcSWPWKYf2Q==", + "node_modules/@angular-devkit/build-angular/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true, + "license": "0BSD" + }, + "node_modules/@angular-devkit/build-angular/node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", "dev": true, + "license": "MIT", "dependencies": { - "@angular-devkit/core": "16.2.15", - "rxjs": "7.8.1" + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": "^16.14.0 || >=18.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/core": { - "version": "16.2.15", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.15.tgz", - "integrity": "sha512-68BgPWpcjNKz++uvLFG8IZaOH3ti2BWQVqaE3yTIYaMoNt0y0A0X2MUVd7EGbAGUk2JdloWJv5LTPVZMzCuK4w==", + "node_modules/@angular-devkit/build-webpack": { + "version": "0.1802.2", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1802.2.tgz", + "integrity": "sha512-Pj+YmKh0nJOKl6QAsqYh3SqfuVJrFqjyp5WrG9BgfsMD9GCMD+5teMHNYJlp+vG/C8e7VdZp4rqOon8K9Xn4Mw==", "dev": true, + "license": "MIT", "dependencies": { - "ajv": "8.12.0", - "ajv-formats": "2.1.1", - "jsonc-parser": "3.2.0", - "picomatch": "2.3.1", - "rxjs": "7.8.1", - "source-map": "0.7.4" + "@angular-devkit/architect": "0.1802.2", + "rxjs": "7.8.1" }, "engines": { - "node": "^16.14.0 || >=18.10.0", + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" }, "peerDependencies": { - "chokidar": "^3.5.2" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } + "webpack": "^5.30.0", + "webpack-dev-server": "^5.0.2" } }, - "node_modules/@angular-devkit/build-webpack/node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - }, "node_modules/@angular-devkit/build-webpack/node_modules/rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@angular-devkit/core": { - "version": "16.2.13", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.13.tgz", - "integrity": "sha512-6jTlYOIeYsOF/Vw/hBNusjoCmKJBByoyGS1Fu2Yav8ltxYK04aDtI73l9JJB/5Cpzhc4YELrMqBMH7in5Vowaw==", + "version": "18.0.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.0.5.tgz", + "integrity": "sha512-sGtrS0SqkcBvyuv0QkIfyadwPgDhMroz1r51lMh1hwzJaJ0LNuVMLviEeYIybeBnvAdp9YvYC8I1WgB/FUEFBw==", "dev": true, "license": "MIT", "dependencies": { - "ajv": "8.12.0", - "ajv-formats": "2.1.1", - "jsonc-parser": "3.2.0", - "picomatch": "2.3.1", + "ajv": "8.13.0", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.2.1", + "picomatch": "4.0.2", "rxjs": "7.8.1", "source-map": "0.7.4" }, "engines": { - "node": "^16.14.0 || >=18.10.0", + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" }, @@ -682,9 +877,9 @@ } }, "node_modules/@angular-devkit/core/node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", "dev": true, "license": "MIT" }, @@ -699,31 +894,41 @@ } }, "node_modules/@angular-devkit/schematics": { - "version": "16.2.13", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-16.2.13.tgz", - "integrity": "sha512-uhhJZpppaeuT/2V6RiCheJKzS4bAZADL+Gw59VJaojqS8ssdG1UzvqRJokIzFzP7+MhHWylZBWUvWLQxuUvtsA==", + "version": "18.0.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.0.5.tgz", + "integrity": "sha512-hZwAq3hwuJzCuh7uqO/7T9IMERhYVxz+ganJlEykpyr58o0IjUM1Q4ZSH5UOYlGRPdBCZJbfiafZ0Sg5w5xBww==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "16.2.13", - "jsonc-parser": "3.2.0", - "magic-string": "0.30.1", + "@angular-devkit/core": "18.0.5", + "jsonc-parser": "3.2.1", + "magic-string": "0.30.10", "ora": "5.4.1", "rxjs": "7.8.1" }, "engines": { - "node": "^16.14.0 || >=18.10.0", + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" } }, "node_modules/@angular-devkit/schematics/node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", "dev": true, "license": "MIT" }, + "node_modules/@angular-devkit/schematics/node_modules/magic-string": { + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + } + }, "node_modules/@angular-devkit/schematics/node_modules/rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", @@ -735,135 +940,106 @@ } }, "node_modules/@angular-eslint/builder": { - "version": "16.3.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-16.3.1.tgz", - "integrity": "sha512-PmIOnRwqdOW1bvZtpTGBTDcOq/Czm3D+IPC/k90yIMs1VsAtcxqUmUtELje+ylJeb2LPeEZavekSnEpcatM4HQ==", + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-18.3.0.tgz", + "integrity": "sha512-httEQyqyBw3+0CRtAa7muFxHrauRfkEfk/jmrh5fn2Eiu+I53hAqFPgrwVi1V6AP/kj2zbAiWhd5xM3pMJdoRQ==", "dev": true, "license": "MIT", - "dependencies": { - "@nx/devkit": "16.5.1", - "nx": "16.5.1" - }, "peerDependencies": { - "eslint": "^7.20.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, "node_modules/@angular-eslint/bundled-angular-compiler": { - "version": "16.3.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-16.3.1.tgz", - "integrity": "sha512-m4WP1xwS9XLcC/3n6lIcG5HZoai/5eb5W3xm48GVcv//0qE2p7S96RSgKPgGHvif5pF8O9xAqEWs3gDEG45+7A==", + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-18.3.0.tgz", + "integrity": "sha512-v/59FxUKnMzymVce99gV43huxoqXWMb85aKvzlNvLN+ScDu6ZE4YMiTQNpfapVL2lkxhs0uwB3jH17EYd5TcsA==", "dev": true, "license": "MIT" }, "node_modules/@angular-eslint/eslint-plugin": { - "version": "16.3.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-16.3.1.tgz", - "integrity": "sha512-kSc8ESfoy8TUSthbq0Lpq9e17I+3Smy4rHoNpKCFEGuJgPs0+OssZMxB6a5EawGbv2EKTPEtrxzFm1WsLR0U9Q==", + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-18.3.0.tgz", + "integrity": "sha512-Vl7gfPMXxvtHTjYdlzR161aj5xrqW6T57wd8ToQ7Gqzm0qHGfY6kE4SQobUa2LCYckTNSlv+zXe48C4ah/dSjw==", "dev": true, "license": "MIT", "dependencies": { - "@angular-eslint/utils": "16.3.1", - "@typescript-eslint/utils": "5.62.0" + "@angular-eslint/bundled-angular-compiler": "18.3.0", + "@angular-eslint/utils": "18.3.0" }, "peerDependencies": { - "eslint": "^7.20.0 || ^8.0.0", + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, "node_modules/@angular-eslint/eslint-plugin-template": { - "version": "16.3.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-16.3.1.tgz", - "integrity": "sha512-+RcFEWqNiRt3+5jXvmlIDlXtP9+vjdmgmVL6tt8yDbqdjBOewtyMu4pE4YaR4sFboyxgME9PbO2WrOyPXh6xjg==", + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-18.3.0.tgz", + "integrity": "sha512-ddR/qwYbUeq9IpyVKrPbfZyRBTy6V8uc5I0JcBKttQ4CZ4joXhqsVgWFsI+JAMi8E66uNj1VC7NuKCOjDINv2Q==", "dev": true, "license": "MIT", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "16.3.1", - "@angular-eslint/utils": "16.3.1", - "@typescript-eslint/type-utils": "5.62.0", - "@typescript-eslint/utils": "5.62.0", + "@angular-eslint/bundled-angular-compiler": "18.3.0", + "@angular-eslint/utils": "18.3.0", "aria-query": "5.3.0", - "axobject-query": "4.0.0" + "axobject-query": "4.1.0" }, "peerDependencies": { - "eslint": "^7.20.0 || ^8.0.0", + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, "node_modules/@angular-eslint/template-parser": { - "version": "16.3.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-16.3.1.tgz", - "integrity": "sha512-9+SxUtxB2iOnm0ldS2ow0stMxe02rB/TxeMIe8fxsLFHZdw8RQvs/p3HLvVHXzv6gUblMHebIb/ubUmwEVb2SA==", + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-18.3.0.tgz", + "integrity": "sha512-1mUquqcnugI4qsoxcYZKZ6WMi6RPelDcJZg2YqGyuaIuhWmi3ZqJZLErSSpjP60+TbYZu7wM8Kchqa1bwJtEaQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "16.3.1", - "eslint-scope": "^7.0.0" + "@angular-eslint/bundled-angular-compiler": "18.3.0", + "eslint-scope": "^8.0.2" }, "peerDependencies": { - "eslint": "^7.20.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, - "node_modules/@angular-eslint/template-parser/node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@angular-eslint/template-parser/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, "node_modules/@angular-eslint/utils": { - "version": "16.3.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-16.3.1.tgz", - "integrity": "sha512-tEBcce0rG+DmcPO8jhRffUFDioGw3G4cUAE15XlRctY1J3QzOBH9HdUOTDt0mMjBgpWCzh0YVT1Moh2bPXU9Xg==", + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-18.3.0.tgz", + "integrity": "sha512-sCrkHkpxBJZLuCikdboZoawCfc2UgbJv+T14tu2uQCv+Vwzeadnu04vkeY2vTkA8GeBdBij/G9/N/nvwmwVw3g==", "dev": true, "license": "MIT", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "16.3.1", - "@typescript-eslint/utils": "5.62.0" + "@angular-eslint/bundled-angular-compiler": "18.3.0" }, "peerDependencies": { - "eslint": "^7.20.0 || ^8.0.0", + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, "node_modules/@angular/animations": { - "version": "16.2.12", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-16.2.12.tgz", - "integrity": "sha512-MD0ElviEfAJY8qMOd6/jjSSvtqER2RDAi0lxe6EtUacC1DHCYkaPrKW4vLqY+tmZBg1yf+6n+uS77pXcHHcA3w==", + "version": "18.0.5", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-18.0.5.tgz", + "integrity": "sha512-RYwlS+4I33beAWdzFFmaDPqXZN+r66qPzzMOk9LQguwF76eBJbykHniODalSLvjrY6Iz7CULavByYNpzq2TT7A==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^16.14.0 || >=18.10.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "16.2.12" + "@angular/core": "18.0.5" } }, "node_modules/@angular/cdk": { - "version": "15.2.9", + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-18.2.1.tgz", + "integrity": "sha512-6y4MmpEPXze6igUHkLsBUPkxw32F8+rmW0xVXZchkSyGlFgqfh53ueXoryWb0qL4s5enkNY6AzXnKAqHfPNkVQ==", "license": "MIT", "peer": true, "dependencies": { @@ -873,46 +1049,33 @@ "parse5": "^7.1.2" }, "peerDependencies": { - "@angular/common": "^15.0.0 || ^16.0.0", - "@angular/core": "^15.0.0 || ^16.0.0", + "@angular/common": "^18.0.0 || ^19.0.0", + "@angular/core": "^18.0.0 || ^19.0.0", "rxjs": "^6.5.3 || ^7.4.0" } }, - "node_modules/@angular/cdk/node_modules/parse5": { - "version": "7.1.2", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "entities": "^4.4.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, "node_modules/@angular/cli": { - "version": "16.2.13", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-16.2.13.tgz", - "integrity": "sha512-Zs/IHV0qeQBlRYp3XTJP96KKMFrOVd4gFWEXyt8xVbma9W7UCWr/0C6D8HRFjheiT40TSa2Suwpk6Hppm+9ESA==", + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-18.1.0.tgz", + "integrity": "sha512-2E+b7S/736AOmxf5je9OWoPpgPY240TfJfFXwQiVvq/4KyC+ZR9lBrqRx72Xghn8nu3z8Q2BPZIXVGZppl0USQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.1602.13", - "@angular-devkit/core": "16.2.13", - "@angular-devkit/schematics": "16.2.13", - "@schematics/angular": "16.2.13", + "@angular-devkit/architect": "0.1801.0", + "@angular-devkit/core": "18.1.0", + "@angular-devkit/schematics": "18.1.0", + "@inquirer/prompts": "5.0.7", + "@listr2/prompt-adapter-inquirer": "2.0.13", + "@schematics/angular": "18.1.0", "@yarnpkg/lockfile": "1.1.0", - "ansi-colors": "4.1.3", - "ini": "4.1.1", - "inquirer": "8.2.4", - "jsonc-parser": "3.2.0", - "npm-package-arg": "10.1.0", - "npm-pick-manifest": "8.0.1", - "open": "8.4.2", - "ora": "5.4.1", - "pacote": "15.2.0", - "resolve": "1.22.2", - "semver": "7.5.4", + "ini": "4.1.3", + "jsonc-parser": "3.3.1", + "listr2": "8.2.3", + "npm-package-arg": "11.0.2", + "npm-pick-manifest": "9.0.1", + "pacote": "18.0.6", + "resolve": "1.22.8", + "semver": "7.6.2", "symbol-observable": "4.0.0", "yargs": "17.7.2" }, @@ -920,58 +1083,117 @@ "ng": "bin/ng.js" }, "engines": { - "node": "^16.14.0 || >=18.10.0", + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" } }, - "node_modules/@angular/cli/node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "node_modules/@angular/cli/node_modules/@angular-devkit/architect": { + "version": "0.1801.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1801.0.tgz", + "integrity": "sha512-iZa3J3CrZT6MKiHPw8ijgVwMyCMewCsP4xc75SetUwF/yuqRUHygALs5jJVZQFQjSFUrkg9gqXa1cCjFDwpT8A==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "18.1.0", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } }, - "node_modules/@angular/cli/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/@angular/cli/node_modules/@angular-devkit/core": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.1.0.tgz", + "integrity": "sha512-6eXQDzHZCbpSMLv9Ohl+1QyLVDmGEXpuuHz3y64LfUTP0aEiBaxk96FjLXIxzJ4f2pbbW2XHzc+yuboGToRA0w==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" + "ajv": "8.16.0", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.2", + "rxjs": "7.8.1", + "source-map": "0.7.4" }, "engines": { - "node": ">=10" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } } }, - "node_modules/@angular/cli/node_modules/resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "node_modules/@angular/cli/node_modules/@angular-devkit/schematics": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.1.0.tgz", + "integrity": "sha512-BjrYutLfYFiPOSEcLBWCj3ENkwDn8gMfBSJesaBz7OrZBZGK5j0dVgBLIsGTP96TKo4o4vszJQOvS4AtV6xMGg==", "dev": true, "license": "MIT", "dependencies": { - "is-core-module": "^2.11.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" + "@angular-devkit/core": "18.1.0", + "jsonc-parser": "3.3.1", + "magic-string": "0.30.10", + "ora": "5.4.1", + "rxjs": "7.8.1" }, - "bin": { - "resolve": "bin/resolve" + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/cli/node_modules/ajv": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@angular/cli/node_modules/magic-string": { + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + } + }, + "node_modules/@angular/cli/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" } }, "node_modules/@angular/cli/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==", + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, "bin": { "semver": "bin/semver.js" }, @@ -979,42 +1201,35 @@ "node": ">=10" } }, - "node_modules/@angular/cli/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, "node_modules/@angular/common": { - "version": "16.2.12", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-16.2.12.tgz", - "integrity": "sha512-B+WY/cT2VgEaz9HfJitBmgdk4I333XG/ybC98CMC4Wz8E49T8yzivmmxXB3OD6qvjcOB6ftuicl6WBqLbZNg2w==", + "version": "18.0.5", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-18.0.5.tgz", + "integrity": "sha512-yItVQSu+Rx8gthWJDTOHwbzItY8/lqmmmYA1RMex0u3GkJoX3/3TZSGXbbBXl8GH8vmQOfp9yj3C02JmlwldRg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^16.14.0 || >=18.10.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "16.2.12", + "@angular/core": "18.0.5", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "16.2.12", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-16.2.12.tgz", - "integrity": "sha512-6SMXUgSVekGM7R6l1Z9rCtUGtlg58GFmgbpMCsGf+VXxP468Njw8rjT2YZkf5aEPxEuRpSHhDYjqz7n14cwCXQ==", + "version": "18.0.5", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-18.0.5.tgz", + "integrity": "sha512-U1/qjNDjxMukXwQrJZjmr87KVxQmHbD7fxVlg0+qafHLe+YDuCtyOfQSGEZrWhwktxvAYZbl3FK+m3Hnk/D3Nw==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^16.14.0 || >=18.10.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "16.2.12" + "@angular/core": "18.0.5" }, "peerDependenciesMeta": { "@angular/core": { @@ -1023,17 +1238,17 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "16.2.12", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-16.2.12.tgz", - "integrity": "sha512-pWSrr152562ujh6lsFZR8NfNc5Ljj+zSTQO44DsuB0tZjwEpnRcjJEgzuhGXr+CoiBf+jTSPZKemtSktDk5aaA==", + "version": "18.0.5", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-18.0.5.tgz", + "integrity": "sha512-aFKDDTsRmc691EkNRj9OkrKNXDOaHdXB42MyUrj3WwJIJFMnSY/UDf6h+CRVF0U+CITszFyWhmeHQRA/3mJWNg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "7.23.2", + "@babel/core": "7.24.7", "@jridgewell/sourcemap-codec": "^1.4.14", "chokidar": "^3.0.0", "convert-source-map": "^1.5.1", - "reflect-metadata": "^0.1.2", + "reflect-metadata": "^0.2.0", "semver": "^7.0.0", "tslib": "^2.3.0", "yargs": "^17.2.1" @@ -1044,72 +1259,120 @@ "ngcc": "bundles/ngcc/index.js" }, "engines": { - "node": "^16.14.0 || >=18.10.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/compiler": "16.2.12", - "typescript": ">=4.9.3 <5.2" + "@angular/compiler": "18.0.5", + "typescript": ">=5.4 <5.5" + } + }, + "node_modules/@angular/compiler-cli/node_modules/@babel/core": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.7.tgz", + "integrity": "sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.7", + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helpers": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/template": "^7.24.7", + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/semver": { + "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" } }, "node_modules/@angular/core": { - "version": "16.2.12", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-16.2.12.tgz", - "integrity": "sha512-GLLlDeke/NjroaLYOks0uyzFVo6HyLl7VOm0K1QpLXnYvW63W9Ql/T3yguRZa7tRkOAeFZ3jw+1wnBD4O8MoUA==", + "version": "18.0.5", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-18.0.5.tgz", + "integrity": "sha512-0UuL+aMMWGYksz09YBsiHq1li7GmL8obB3IC3T5MwDqnn7FGRUBfBUOZEkM6B+pwgg+RAtNdJkbCfbh1z74bFQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^16.14.0 || >=18.10.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { "rxjs": "^6.5.3 || ^7.4.0", - "zone.js": "~0.13.0" + "zone.js": "~0.14.0" } }, "node_modules/@angular/forms": { - "version": "16.2.12", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-16.2.12.tgz", - "integrity": "sha512-1Eao89hlBgLR3v8tU91vccn21BBKL06WWxl7zLpQmG6Hun+2jrThgOE4Pf3os4fkkbH4Apj0tWL2fNIWe/blbw==", + "version": "18.0.5", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-18.0.5.tgz", + "integrity": "sha512-nO7bN+nO2/czgKSvPx6ewqpfb8xXOyns06uovWpAXSH4jYoiZ6CHTHhOKrOL/3SRkhUV9u+EUXTTAOSBkS+OBA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^16.14.0 || >=18.10.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "16.2.12", - "@angular/core": "16.2.12", - "@angular/platform-browser": "16.2.12", + "@angular/common": "18.0.5", + "@angular/core": "18.0.5", + "@angular/platform-browser": "18.0.5", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/language-service": { - "version": "16.2.12", - "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-16.2.12.tgz", - "integrity": "sha512-sZwB+ZEjChx9EYcqPaS4OnhC/q5RcedZjIdM9mCxuU/MtseURRYRI/8Hnm1RHo9qyc5PmsQpg7p9Vp/5hXLUjw==", + "version": "18.0.5", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-18.0.5.tgz", + "integrity": "sha512-ahZnsUk8q/4k+okP9hBcfWRiOiMximSAI7Vq5M/fe9cezykt8cWEzxgRoduTvDKoQPqcRl0nHlDYju2zkXcU6g==", "dev": true, "license": "MIT", "engines": { - "node": "^16.14.0 || >=18.10.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" } }, "node_modules/@angular/platform-browser": { - "version": "16.2.12", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-16.2.12.tgz", - "integrity": "sha512-NnH7ju1iirmVEsUq432DTm0nZBGQsBrU40M3ZeVHMQ2subnGiyUs3QyzDz8+VWLL/T5xTxWLt9BkDn65vgzlIQ==", + "version": "18.0.5", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-18.0.5.tgz", + "integrity": "sha512-hBKaGz7dhsjNhD0aWB8G2/YZQ/MaBhzFIQSAZMPs2ccAqH1Jx772/Y11k57seA3VaPpnL8WZ1apOSJgALUJ//w==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^16.14.0 || >=18.10.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/animations": "16.2.12", - "@angular/common": "16.2.12", - "@angular/core": "16.2.12" + "@angular/animations": "18.0.5", + "@angular/common": "18.0.5", + "@angular/core": "18.0.5" }, "peerDependenciesMeta": { "@angular/animations": { @@ -1118,43 +1381,45 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "16.2.12", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-16.2.12.tgz", - "integrity": "sha512-ya54jerNgreCVAR278wZavwjrUWImMr2F8yM5n9HBvsMBbFaAQ83anwbOEiHEF2BlR+gJiEBLfpuPRMw20pHqw==", + "version": "18.0.5", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-18.0.5.tgz", + "integrity": "sha512-i8CXojKcjsKzD2JR2clIisqavlHCW1jw+F2hJVrf/JR9iu6kVpGpZOqb3yYHoQCsPa7hUzQnn0ewYwBvlWsDmw==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^16.14.0 || >=18.10.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "16.2.12", - "@angular/compiler": "16.2.12", - "@angular/core": "16.2.12", - "@angular/platform-browser": "16.2.12" + "@angular/common": "18.0.5", + "@angular/compiler": "18.0.5", + "@angular/core": "18.0.5", + "@angular/platform-browser": "18.0.5" } }, "node_modules/@angular/router": { - "version": "16.2.12", + "version": "18.0.5", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-18.0.5.tgz", + "integrity": "sha512-GmdzD5FZYPKCGP6mV3AZraAU6czfGcjjCym6mIsdJr3DyMwnQSwaaHAu8qlQbPDVfsP+gKVSPh1JxI1lzzarLA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^16.14.0 || >=18.10.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "16.2.12", - "@angular/core": "16.2.12", - "@angular/platform-browser": "16.2.12", + "@angular/common": "18.0.5", + "@angular/core": "18.0.5", + "@angular/platform-browser": "18.0.5", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/service-worker": { - "version": "16.2.12", - "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-16.2.12.tgz", - "integrity": "sha512-o0z0s4c76NmRASa+mUHn/q6vUKQNa06mGmLBDKm84vRQ1sQ2TJv+R1p8K9WkiM5mGy6tjQCDOgaz13TcxMFWOQ==", + "version": "18.0.5", + "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-18.0.5.tgz", + "integrity": "sha512-Uz3rKHY0pBOvAfxhaGI9X8glS8oaPv03e3GsucZhzuDCijQGHQb1Plaz56NntIGvGaghLMq3zwV7YLPnquarvw==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -1163,28 +1428,21 @@ "ngsw-config": "ngsw-config.js" }, "engines": { - "node": "^16.14.0 || >=18.10.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "16.2.12", - "@angular/core": "16.2.12" + "@angular/common": "18.0.5", + "@angular/core": "18.0.5" } }, - "node_modules/@assemblyscript/loader": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.10.1.tgz", - "integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==", - "dev": true, - "license": "Apache-2.0" - }, "node_modules/@babel/code-frame": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", - "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/highlight": "^7.24.2", + "@babel/highlight": "^7.24.7", "picocolors": "^1.0.0" }, "engines": { @@ -1192,9 +1450,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", - "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.4.tgz", + "integrity": "sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==", "dev": true, "license": "MIT", "engines": { @@ -1202,22 +1460,22 @@ } }, "node_modules/@babel/core": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz", - "integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-module-transforms": "^7.23.0", - "@babel/helpers": "^7.23.2", - "@babel/parser": "^7.23.0", - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.2", - "@babel/types": "^7.23.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -1232,22 +1490,6 @@ "url": "https://opencollective.com/babel" } }, - "node_modules/@babel/core/node_modules/@babel/generator": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz", - "integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.24.0", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/core/node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -1266,15 +1508,15 @@ } }, "node_modules/@babel/generator": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.9.tgz", - "integrity": "sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz", + "integrity": "sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", + "@babel/types": "^7.25.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" }, "engines": { @@ -1282,41 +1524,42 @@ } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", - "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", + "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", - "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz", + "integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.22.15" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", - "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", + "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.23.5", - "@babel/helper-validator-option": "^7.23.5", - "browserslist": "^4.22.2", + "@babel/compat-data": "^7.25.2", + "@babel/helper-validator-option": "^7.24.8", + "browserslist": "^4.23.1", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -1335,20 +1578,18 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.4.tgz", - "integrity": "sha512-lG75yeuUSVu0pIcbhiYMXBXANHrpUPaOfu7ryAzskCgKUHuAxRQI5ssrtmF0X9UXldPlvT0XM/A4F44OXRt6iQ==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.4.tgz", + "integrity": "sha512-ro/bFs3/84MDgDmMwbcHgDa8/E6J3QKNTk4xJJnVeFtGE+tL0K26E3pNxhYz2b67fJpt7Aphw5XcploKXuCvCQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-member-expression-to-functions": "^7.23.0", - "@babel/helper-optimise-call-expression": "^7.22.5", - "@babel/helper-replace-supers": "^7.24.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-member-expression-to-functions": "^7.24.8", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/helper-replace-supers": "^7.25.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/traverse": "^7.25.4", "semver": "^6.3.1" }, "engines": { @@ -1369,13 +1610,13 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", - "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.2.tgz", + "integrity": "sha512-+wqVGP+DFmqwFD3EH6TMTfUNeqDehV3E/dl+Sd54eaXqm17tEUNbEIn4sVivVowbvUpOtIGxdo3GoXyDH9N/9g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-annotate-as-pure": "^7.24.7", "regexpu-core": "^5.3.1", "semver": "^6.3.1" }, @@ -1397,9 +1638,9 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.1.tgz", - "integrity": "sha512-o7SDgTJuvx5vLKD6SFvkydkSMBvahDKGiNJzG22IZYXhiqoe9efY7zocICBgzHV4IRg5wdgl2nEL/tulKIEIbA==", + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", + "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1413,81 +1654,45 @@ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", - "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", + "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.23.0" + "@babel/traverse": "^7.24.8", + "@babel/types": "^7.24.8" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.22.15" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", - "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", + "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.20" + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.2" }, "engines": { "node": ">=6.9.0" @@ -1497,22 +1702,22 @@ } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", - "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", + "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", - "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", + "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", "dev": true, "license": "MIT", "engines": { @@ -1520,15 +1725,15 @@ } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", - "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.0.tgz", + "integrity": "sha512-NhavI2eWEIz/H9dbrG0TuOicDhNexze43i5z7lEqwYm0WEZVTwnPpA0EafUTP7+6/W79HWIP2cTe3Z5NiSTVpw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-wrap-function": "^7.22.20" + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-wrap-function": "^7.25.0", + "@babel/traverse": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -1538,15 +1743,15 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.1.tgz", - "integrity": "sha512-QCR1UqC9BzG5vZl8BMicmZ28RuUBnHhAMddD8yHFHDRH9lLTZ9uUPehX8ctVPT8l0TKblJidqcgUUKGVrePleQ==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.0.tgz", + "integrity": "sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-member-expression-to-functions": "^7.23.0", - "@babel/helper-optimise-call-expression": "^7.22.5" + "@babel/helper-member-expression-to-functions": "^7.24.8", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/traverse": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -1556,48 +1761,50 @@ } }, "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", - "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", + "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", "dev": true, "license": "MIT", "engines": { @@ -1605,9 +1812,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", "dev": true, "license": "MIT", "engines": { @@ -1615,9 +1822,9 @@ } }, "node_modules/@babel/helper-validator-option": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", - "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", + "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", "dev": true, "license": "MIT", "engines": { @@ -1625,43 +1832,42 @@ } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", - "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.0.tgz", + "integrity": "sha512-s6Q1ebqutSiZnEjaofc/UKDyC4SbzV5n5SrA2Gq8UawLycr3i04f1dX4OzoQVnexm6aOCh37SQNYlJ/8Ku+PMQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-function-name": "^7.22.5", - "@babel/template": "^7.22.15", - "@babel/types": "^7.22.19" + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.0", + "@babel/types": "^7.25.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz", - "integrity": "sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.0.tgz", + "integrity": "sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.1", - "@babel/types": "^7.24.0" + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", - "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-validator-identifier": "^7.24.7", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" @@ -1671,11 +1877,14 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", - "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.4.tgz", + "integrity": "sha512-nq+eWrOgdtu3jG5Os4TQP3x3cLA8hR8TvJNjD8vnPa20WGycimcparWnLK4jJhElTK6SDyuJo1weMKO/5LpmLA==", "dev": true, "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.4" + }, "bin": { "parser": "bin/babel-parser.js" }, @@ -1683,14 +1892,15 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.1.tgz", - "integrity": "sha512-y4HqEnkelJIOQGd+3g1bTeKsA5c6qM7eOn7VggGVbBc0y8MLSKHacwcIE2PplNlQSj0PqS9rrXL/nkPVK+kUNg==", + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.3.tgz", + "integrity": "sha512-wUrcsxZg6rqBXG05HG1FPYgsP6EvwF4WpBbxIpWIIYnH8wG0gzx3yZY3dtEHas4sTAOGkbTsc9EGPxwff8lRoA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.3" }, "engines": { "node": ">=6.9.0" @@ -1699,68 +1909,81 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.1.tgz", - "integrity": "sha512-Hj791Ii4ci8HqnaKHAlLNs+zaLXb0EzSDhiAWp5VNlyvCNymYfacs64pxTxbH1znW/NcArSmwpmG9IKE/TUVVQ==", + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.0.tgz", + "integrity": "sha512-Bm4bH2qsX880b/3ziJ8KD711LT7z4u8CFudmjqle65AZj/HNUFhEf90dqYv6O86buWvSBmeQDjv0Tn2aF/bIBA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/plugin-transform-optional-chaining": "^7.24.1" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.13.0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz", - "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==", + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.0.tgz", + "integrity": "sha512-lXwdNZtTmeVOOFtwM/WDe7yg1PL8sYhRk/XH0FzbR2HDQ0xC+EnQ/JHeoMYSavtU115tnUk0q9CDyq8si+LMAA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-remap-async-to-generator": "^7.18.9", - "@babel/plugin-syntax-async-generators": "^7.8.4" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0-placeholder-for-preset-env.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", - "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz", + "integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==", "dev": true, "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.7" + }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.13.0" } }, - "node_modules/@babel/plugin-proposal-unicode-property-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", - "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.0.tgz", + "integrity": "sha512-tggFrk1AIShG/RUQbEwt2Tr/E+ObkfwrPjR6BjbRvsx24+PSjK8zrq0GWPNCjo8qpRx4DuJzlcvWJqlm+0h3kw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.0" }, "engines": { - "node": ">=4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" @@ -1835,13 +2058,13 @@ } }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.1.tgz", - "integrity": "sha512-IuwnI5XnuF189t91XbxmXeCDz3qs6iDRO7GJ++wcfgeXNs/8FmIlKcpDSXNVyuLQxlwvskmI3Ct73wUODkJBlQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz", + "integrity": "sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1851,13 +2074,13 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.1.tgz", - "integrity": "sha512-zhQTMH0X2nVLnb04tz+s7AMuasX8U0FnpE+nHTOhSOINjWMnopoZTxtIKsd45n4GQ/HIZLyfIpoul8e2m0DnRA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz", + "integrity": "sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2020,13 +2243,13 @@ } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.1.tgz", - "integrity": "sha512-ngT/3NkRhsaep9ck9uj2Xhv9+xB1zShY3tM3g6om4xxCELwCDN4g4Aq5dRn48+0hasAql7s2hdBOysCfNpr4fw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz", + "integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2036,16 +2259,16 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.24.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.3.tgz", - "integrity": "sha512-Qe26CMYVjpQxJ8zxM1340JFNjZaF+ISWpr1Kt/jGo+ZTUzKkfw/pphEWbRCb+lmSM6k/TOgfYLvmbHkUQ0asIg==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.0.tgz", + "integrity": "sha512-uaIi2FdqzjpAMvVqvB51S42oC2JEVgh0LDsGfZVDysWE8LrJtQC2jvKmOqEYThKyB7bDEb7BP1GYWDm7tABA0Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-remap-async-to-generator": "^7.22.20", - "@babel/plugin-syntax-async-generators": "^7.8.4" + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-remap-async-to-generator": "^7.25.0", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/traverse": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -2055,15 +2278,15 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.22.5.tgz", - "integrity": "sha512-b1A8D8ZzE/VhNDoV1MSJTnpKkCG5bJo+19R4o4oy03zM7ws8yEMK755j61Dc3EyvdysbqH5BOOTquJ7ZX9C6vQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz", + "integrity": "sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-remap-async-to-generator": "^7.22.5" + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-remap-async-to-generator": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2073,13 +2296,13 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.1.tgz", - "integrity": "sha512-TWWC18OShZutrv9C6mye1xwtam+uNi2bnTOCBUd5sZxyHOiWbU6ztSROofIMrK84uweEZC219POICK/sTYwfgg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz", + "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2089,13 +2312,13 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.4.tgz", - "integrity": "sha512-nIFUZIpGKDf9O9ttyRXpHFpKC+X3Y5mtshZONuEUYBomAKoM4y029Jr+uB1bHGPhNmK8YXHevDtKDOLmtRrp6g==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.0.tgz", + "integrity": "sha512-yBQjYoOjXlFv9nlXb3f1casSHOZkWr29NX+zChVanLg5Nc157CrbEX9D7hxxtTpuFy7Q0YzmmWfJxzvps4kXrQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -2105,14 +2328,14 @@ } }, "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.1.tgz", - "integrity": "sha512-OMLCXi0NqvJfORTaPQBwqLXHhb93wkBKZ4aNwMl6WtehO7ar+cmp+89iPEQPqxAnxsOKTaMcs3POz3rKayJ72g==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.4.tgz", + "integrity": "sha512-nZeZHyCWPfjkdU5pA/uHiTaDAFUEqkpzf1YoQT2NeSynCGYq9rxfyI3XpQbfx/a0hSnFH6TGlEXvae5Vi7GD8g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.1", - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-create-class-features-plugin": "^7.25.4", + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -2122,14 +2345,14 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.4.tgz", - "integrity": "sha512-B8q7Pz870Hz/q9UgP8InNpY01CSLDSCyqX7zcRuv3FcPl87A2G17lASroHWaCtbdIcbYzOZ7kWmXFKbijMSmFg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz", + "integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.4", - "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-class-static-block": "^7.14.5" }, "engines": { @@ -2140,19 +2363,17 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.1.tgz", - "integrity": "sha512-ZTIe3W7UejJd3/3R4p7ScyyOoafetUShSf4kCqV0O7F/RiHxVj/wRaRnQlrGwflvcehNA8M42HkAiEDYZu2F1Q==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.4.tgz", + "integrity": "sha512-oexUfaQle2pF/b6E0dwsxQtAol9TLSO88kQvym6HHBWFliV2lGdrPieX+WgMRLSJDVzdYywk7jXbLPuO2KLTLg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-replace-supers": "^7.24.1", - "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-replace-supers": "^7.25.0", + "@babel/traverse": "^7.25.4", "globals": "^11.1.0" }, "engines": { @@ -2163,14 +2384,14 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.1.tgz", - "integrity": "sha512-5pJGVIUfJpOS+pAqBQd+QMaTD2vCL/HcePooON6pDpHgRp4gNRmzyHTPIkXntwKsq3ayUFVfJaIKPw2pOkOcTw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", + "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/template": "^7.24.0" + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/template": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2180,13 +2401,13 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.1.tgz", - "integrity": "sha512-ow8jciWqNxR3RYbSNVuF4U2Jx130nwnBnhRw6N6h1bOejNkABmcI5X5oz29K4alWX7vf1C+o6gtKXikzRKkVdw==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.8.tgz", + "integrity": "sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -2196,14 +2417,14 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.1.tgz", - "integrity": "sha512-p7uUxgSoZwZ2lPNMzUkqCts3xlp8n+o05ikjy7gbtFJSt9gdU88jAmtfmOxHM14noQXBxfgzf2yRWECiNVhTCw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz", + "integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2213,13 +2434,13 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.1.tgz", - "integrity": "sha512-msyzuUnvsjsaSaocV6L7ErfNsa5nDWL1XKNnDePLgmz+WdU4w/J8+AxBMrWfi9m4IxfL5sZQKUPQKDQeeAT6lA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz", + "integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2228,14 +2449,31 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.0.tgz", + "integrity": "sha512-YLpb4LlYSc3sCUa35un84poXoraOiQucUTTu8X1j18JV+gNa8E0nyUf/CjZ171IRGr4jEguF+vzJU66QZhn29g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.1.tgz", - "integrity": "sha512-av2gdSTyXcJVdI+8aFZsCAtR29xJt0S5tas+Ef8NvBNmD1a+N/3ecMLeMBgfcK+xzsjdLDT6oHt+DFPyeqUbDA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", + "integrity": "sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3" }, "engines": { @@ -2246,14 +2484,14 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.1.tgz", - "integrity": "sha512-U1yX13dVBSwS23DEAqU+Z/PkwE9/m7QQy8Y9/+Tdb8UWYaGNDYwTLi19wqIAiROr8sXVum9A/rtiH5H0boUcTw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz", + "integrity": "sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2263,13 +2501,13 @@ } }, "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.1.tgz", - "integrity": "sha512-Ft38m/KFOyzKw2UaJFkWG9QnHPG/Q/2SkOrRk4pNBPg5IPZ+dOxcmkK5IyuBcxiNPyyYowPGUReyBvrvZs7IlQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz", + "integrity": "sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" }, "engines": { @@ -2280,14 +2518,14 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.1.tgz", - "integrity": "sha512-OxBdcnF04bpdQdR3i4giHZNZQn7cm8RQKcSwA17wAAqEELo1ZOwp5FFgeptWUQXFyT9kwHo10aqqauYkRZPCAg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz", + "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2297,15 +2535,15 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.1.tgz", - "integrity": "sha512-BXmDZpPlh7jwicKArQASrj8n22/w6iymRnvHYYd2zO30DbE277JO20/7yXJT3QxDPtiQiOxQBbZH4TpivNXIxA==", + "version": "7.25.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.1.tgz", + "integrity": "sha512-TVVJVdW9RKMNgJJlLtHsKDTydjZAbwIsn6ySBPQaEAUU5+gVvlJt/9nRmqVbsV/IBanRjzWoaAQKLoamWVOUuA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.1" }, "engines": { "node": ">=6.9.0" @@ -2315,13 +2553,13 @@ } }, "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.1.tgz", - "integrity": "sha512-U7RMFmRvoasscrIFy5xA4gIp8iWnWubnKkKuUGJjsuOH7GfbMkB+XZzeslx2kLdEGdOJDamEmCqOks6e8nv8DQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz", + "integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-json-strings": "^7.8.3" }, "engines": { @@ -2332,13 +2570,13 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.1.tgz", - "integrity": "sha512-zn9pwz8U7nCqOYIiBaOxoQOtYmMODXTJnkxG4AtX8fPmnCRYWBOHD0qcpwS9e2VDSp1zNJYpdnFMIKb8jmwu6g==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.2.tgz", + "integrity": "sha512-HQI+HcTbm9ur3Z2DkO+jgESMAMcYLuN/A7NRw9juzxAezN9AvqvUTnpKP/9kkYANz6u7dFlAyOu44ejuGySlfw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -2348,13 +2586,13 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.1.tgz", - "integrity": "sha512-OhN6J4Bpz+hIBqItTeWJujDOfNP+unqv/NJgyhlpSqgBTPm37KkMmZV6SYcOj+pnDbdcl1qRGV/ZiIjX9Iy34w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz", + "integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" }, "engines": { @@ -2365,13 +2603,13 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.1.tgz", - "integrity": "sha512-4ojai0KysTWXzHseJKa1XPNXKRbuUrhkOPY4rEGeR+7ChlJVKxFa3H3Bz+7tWaGKgJAXUWKOGmltN+u9B3+CVg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz", + "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2381,14 +2619,14 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.1.tgz", - "integrity": "sha512-lAxNHi4HVtjnHd5Rxg3D5t99Xm6H7b04hUS7EHIXcUl2EV4yl1gWdqZrNzXnSrHveL9qMdbODlLF55mvgjAfaQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz", + "integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2398,15 +2636,15 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.1.tgz", - "integrity": "sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz", + "integrity": "sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-simple-access": "^7.22.5" + "@babel/helper-module-transforms": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-simple-access": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2416,16 +2654,16 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.1.tgz", - "integrity": "sha512-mqQ3Zh9vFO1Tpmlt8QPnbwGHzNz3lpNEMxQb1kAemn/erstyqw1r9KeOlOfo3y6xAnFEcOv2tSyrXfmMk+/YZA==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.0.tgz", + "integrity": "sha512-YPJfjQPDXxyQWg/0+jHKj1llnY5f/R6a0p/vP4lPymxLu7Lvl4k2WMitqi08yxwQcCVUUdG9LCUj4TNEgAp3Jw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-validator-identifier": "^7.22.20" + "@babel/helper-module-transforms": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -2435,14 +2673,14 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.1.tgz", - "integrity": "sha512-tuA3lpPj+5ITfcCluy6nWonSL7RvaG0AOTeAuvXqEKS34lnLzXpDb0dcP6K8jD0zWZFNDVly90AGFJPnm4fOYg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz", + "integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2452,14 +2690,14 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", - "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz", + "integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2469,13 +2707,13 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.1.tgz", - "integrity": "sha512-/rurytBM34hYy0HKZQyA0nHbQgQNFm4Q/BOc9Hflxi2X3twRof7NaE5W46j4kQitm7SvACVRXsa6N/tSZxvPug==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz", + "integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2485,13 +2723,13 @@ } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.1.tgz", - "integrity": "sha512-iQ+caew8wRrhCikO5DrUYx0mrmdhkaELgFa+7baMcVuhxIkN7oxt06CZ51D65ugIb1UWRQ8oQe+HXAVM6qHFjw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz", + "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" }, "engines": { @@ -2502,13 +2740,13 @@ } }, "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.1.tgz", - "integrity": "sha512-7GAsGlK4cNL2OExJH1DzmDeKnRv/LXq0eLUSvudrehVA5Rgg4bIrqEUW29FbKMBRT0ztSqisv7kjP+XIC4ZMNw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz", + "integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-numeric-separator": "^7.10.4" }, "engines": { @@ -2519,16 +2757,16 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.1.tgz", - "integrity": "sha512-XjD5f0YqOtebto4HGISLNfiNMTTs6tbkFf2TOqJlYKYmbo+mN9Dnpl4SRoofiziuOWMIyq3sZEUqLo3hLITFEA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz", + "integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.24.1" + "@babel/plugin-transform-parameters": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2538,14 +2776,14 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.1.tgz", - "integrity": "sha512-oKJqR3TeI5hSLRxudMjFQ9re9fBVUU0GICqM3J1mi8MqlhVr6hC/ZN4ttAyMuQR6EZZIY6h/exe5swqGNNIkWQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz", + "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-replace-supers": "^7.24.1" + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2555,13 +2793,13 @@ } }, "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.1.tgz", - "integrity": "sha512-oBTH7oURV4Y+3EUrf6cWn1OHio3qG/PVwO5J03iSJmBg6m2EhKjkAu/xuaXaYwWW9miYtvbWv4LNf0AmR43LUA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz", + "integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" }, "engines": { @@ -2572,14 +2810,14 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.1.tgz", - "integrity": "sha512-n03wmDt+987qXwAgcBlnUUivrZBPZ8z1plL0YvgQalLm+ZE5BMhGm94jhxXtA1wzv1Cu2aaOv1BM9vbVttrzSg==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz", + "integrity": "sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", "@babel/plugin-syntax-optional-chaining": "^7.8.3" }, "engines": { @@ -2590,13 +2828,13 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.1.tgz", - "integrity": "sha512-8Jl6V24g+Uw5OGPeWNKrKqXPDw2YDjLc53ojwfMcKwlEoETKU9rU0mHUtcg9JntWI/QYzGAXNWEcVHZ+fR+XXg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz", + "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2606,14 +2844,14 @@ } }, "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.1.tgz", - "integrity": "sha512-tGvisebwBO5em4PaYNqt4fkw56K2VALsAbAakY0FjTYqJp7gfdrgr7YX76Or8/cpik0W6+tj3rZ0uHU9Oil4tw==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.4.tgz", + "integrity": "sha512-ao8BG7E2b/URaUQGqN3Tlsg+M3KlHY6rJ1O1gXAEUnZoyNQnvKyH87Kfg+FoxSeyWUB8ISZZsC91C44ZuBFytw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.1", - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-create-class-features-plugin": "^7.25.4", + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -2623,15 +2861,15 @@ } }, "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.1.tgz", - "integrity": "sha512-pTHxDVa0BpUbvAgX3Gat+7cSciXqUcY9j2VZKTbSB6+VQGpNgNO9ailxTGHSXlqOnX1Hcx1Enme2+yv7VqP9bg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz", + "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-create-class-features-plugin": "^7.24.1", - "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-private-property-in-object": "^7.14.5" }, "engines": { @@ -2642,13 +2880,13 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.1.tgz", - "integrity": "sha512-LetvD7CrHmEx0G442gOomRr66d7q8HzzGGr4PMHGr+5YIm6++Yke+jxj246rpvsbyhJwCLxcTn6zW1P1BSenqA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz", + "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2658,13 +2896,13 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.1.tgz", - "integrity": "sha512-sJwZBCzIBE4t+5Q4IGLaaun5ExVMRY0lYwos/jNecjMrVCygCdph3IKv0tkP5Fc87e/1+bebAmEAGBfnRD+cnw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz", + "integrity": "sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-plugin-utils": "^7.24.7", "regenerator-transform": "^0.15.2" }, "engines": { @@ -2675,13 +2913,13 @@ } }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.1.tgz", - "integrity": "sha512-JAclqStUfIwKN15HrsQADFgeZt+wexNQ0uLhuqvqAUFoqPMjEcFCYZBhq0LUdz6dZK/mD+rErhW71fbx8RYElg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz", + "integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2691,17 +2929,17 @@ } }, "node_modules/@babel/plugin-transform-runtime": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.22.9.tgz", - "integrity": "sha512-9KjBH61AGJetCPYp/IEyLEp47SyybZb0nDRpBvmtEkm+rUIwxdlKpyNHI1TmsGkeuLclJdleQHRZ8XLBnnh8CQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.24.7.tgz", + "integrity": "sha512-YqXjrk4C+a1kZjewqt+Mmu2UuV1s07y8kqcUf4qYLnoqemhR4gRQikhdAhSVJioMjVTu6Mo6pAbaypEA3jY6fw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5", - "babel-plugin-polyfill-corejs2": "^0.4.4", - "babel-plugin-polyfill-corejs3": "^0.8.2", - "babel-plugin-polyfill-regenerator": "^0.5.1", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.1", + "babel-plugin-polyfill-regenerator": "^0.6.1", "semver": "^6.3.1" }, "engines": { @@ -2722,13 +2960,13 @@ } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.1.tgz", - "integrity": "sha512-LyjVB1nsJ6gTTUKRjRWx9C1s9hE7dLfP/knKdrfeH9UPtAGjYGgxIbFfx7xyLIEWs7Xe1Gnf8EWiUqfjLhInZA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz", + "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2738,14 +2976,14 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.1.tgz", - "integrity": "sha512-KjmcIM+fxgY+KxPVbjelJC6hrH1CgtPmTvdXAfn3/a9CnWGSTY7nH4zm5+cjmWJybdcPSsD0++QssDsjcpe47g==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz", + "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2755,13 +2993,13 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.1.tgz", - "integrity": "sha512-9v0f1bRXgPVcPrngOQvLXeGNNVLc8UjMVfebo9ka0WF3/7+aVUHmaJVT3sa0XCzEFioPfPHZiOcYG9qOsH63cw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz", + "integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2771,13 +3009,13 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.1.tgz", - "integrity": "sha512-WRkhROsNzriarqECASCNu/nojeXCDTE/F2HmRgOzi7NGvyfYGq1NEjKBK3ckLfRgGc6/lPAqP0vDOSw3YtG34g==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", + "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2787,13 +3025,13 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.1.tgz", - "integrity": "sha512-CBfU4l/A+KruSUoW+vTQthwcAdwuqbpRNB8HQKlZABwHRhsdHZ9fezp4Sn18PeAlYxTNiLMlx4xUBV3AWfg1BA==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz", + "integrity": "sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -2803,13 +3041,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.1.tgz", - "integrity": "sha512-RlkVIcWT4TLI96zM660S877E7beKlQw7Ig+wqkKBiWfj0zH5Q4h50q6er4wzZKRNSYpfo6ILJ+hrJAGSX2qcNw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz", + "integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2819,14 +3057,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.1.tgz", - "integrity": "sha512-Ss4VvlfYV5huWApFsF8/Sq0oXnGO+jB+rijFEFugTd3cwSObUSnUi88djgR5528Csl0uKlrI331kRqe56Ov2Ng==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz", + "integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2836,14 +3074,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.1.tgz", - "integrity": "sha512-2A/94wgZgxfTsiLaQ2E36XAOdcZmGAaEEgVmxQWwZXWkGhvoHbaqXcKnU8zny4ycpu3vNqg0L/PcCiYtHtA13g==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz", + "integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2853,14 +3091,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.1.tgz", - "integrity": "sha512-fqj4WuzzS+ukpgerpAoOnMfQXwUHFxXUZUE84oL2Kao2N8uSlvcpnAidKASgsNgzZHBsHWvcm8s9FPWUhAb8fA==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.4.tgz", + "integrity": "sha512-qesBxiWkgN1Q+31xUE9RcMk79eOXXDCv6tfyGMRSs4RGlioSg2WVyQAm07k726cSE56pa+Kb0y9epX2qaXzTvA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-create-regexp-features-plugin": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -2870,26 +3108,29 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.9.tgz", - "integrity": "sha512-wNi5H/Emkhll/bqPjsjQorSykrlfY5OWakd6AulLvMEytpKasMVUpVy8RL4qBIBs5Ac6/5i0/Rv0b/Fg6Eag/g==", + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.3.tgz", + "integrity": "sha512-QsYW7UeAaXvLPX9tdVliMJE7MD7M6MLYVTovRTIwhoYQVFHR1rM4wO8wqAezYi3/BpSD+NzVCZ69R6smWiIi8g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-compilation-targets": "^7.22.9", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-validator-option": "^7.22.5", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.22.5", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.22.5", + "@babel/compat-data": "^7.25.2", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-validator-option": "^7.24.8", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.3", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.0", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.0", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.0", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.22.5", - "@babel/plugin-syntax-import-attributes": "^7.22.5", + "@babel/plugin-syntax-import-assertions": "^7.24.7", + "@babel/plugin-syntax-import-attributes": "^7.24.7", "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", @@ -2901,60 +3142,60 @@ "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.22.5", - "@babel/plugin-transform-async-generator-functions": "^7.22.7", - "@babel/plugin-transform-async-to-generator": "^7.22.5", - "@babel/plugin-transform-block-scoped-functions": "^7.22.5", - "@babel/plugin-transform-block-scoping": "^7.22.5", - "@babel/plugin-transform-class-properties": "^7.22.5", - "@babel/plugin-transform-class-static-block": "^7.22.5", - "@babel/plugin-transform-classes": "^7.22.6", - "@babel/plugin-transform-computed-properties": "^7.22.5", - "@babel/plugin-transform-destructuring": "^7.22.5", - "@babel/plugin-transform-dotall-regex": "^7.22.5", - "@babel/plugin-transform-duplicate-keys": "^7.22.5", - "@babel/plugin-transform-dynamic-import": "^7.22.5", - "@babel/plugin-transform-exponentiation-operator": "^7.22.5", - "@babel/plugin-transform-export-namespace-from": "^7.22.5", - "@babel/plugin-transform-for-of": "^7.22.5", - "@babel/plugin-transform-function-name": "^7.22.5", - "@babel/plugin-transform-json-strings": "^7.22.5", - "@babel/plugin-transform-literals": "^7.22.5", - "@babel/plugin-transform-logical-assignment-operators": "^7.22.5", - "@babel/plugin-transform-member-expression-literals": "^7.22.5", - "@babel/plugin-transform-modules-amd": "^7.22.5", - "@babel/plugin-transform-modules-commonjs": "^7.22.5", - "@babel/plugin-transform-modules-systemjs": "^7.22.5", - "@babel/plugin-transform-modules-umd": "^7.22.5", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", - "@babel/plugin-transform-new-target": "^7.22.5", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.22.5", - "@babel/plugin-transform-numeric-separator": "^7.22.5", - "@babel/plugin-transform-object-rest-spread": "^7.22.5", - "@babel/plugin-transform-object-super": "^7.22.5", - "@babel/plugin-transform-optional-catch-binding": "^7.22.5", - "@babel/plugin-transform-optional-chaining": "^7.22.6", - "@babel/plugin-transform-parameters": "^7.22.5", - "@babel/plugin-transform-private-methods": "^7.22.5", - "@babel/plugin-transform-private-property-in-object": "^7.22.5", - "@babel/plugin-transform-property-literals": "^7.22.5", - "@babel/plugin-transform-regenerator": "^7.22.5", - "@babel/plugin-transform-reserved-words": "^7.22.5", - "@babel/plugin-transform-shorthand-properties": "^7.22.5", - "@babel/plugin-transform-spread": "^7.22.5", - "@babel/plugin-transform-sticky-regex": "^7.22.5", - "@babel/plugin-transform-template-literals": "^7.22.5", - "@babel/plugin-transform-typeof-symbol": "^7.22.5", - "@babel/plugin-transform-unicode-escapes": "^7.22.5", - "@babel/plugin-transform-unicode-property-regex": "^7.22.5", - "@babel/plugin-transform-unicode-regex": "^7.22.5", - "@babel/plugin-transform-unicode-sets-regex": "^7.22.5", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.22.5", - "babel-plugin-polyfill-corejs2": "^0.4.4", - "babel-plugin-polyfill-corejs3": "^0.8.2", - "babel-plugin-polyfill-regenerator": "^0.5.1", - "core-js-compat": "^3.31.0", + "@babel/plugin-transform-arrow-functions": "^7.24.7", + "@babel/plugin-transform-async-generator-functions": "^7.25.0", + "@babel/plugin-transform-async-to-generator": "^7.24.7", + "@babel/plugin-transform-block-scoped-functions": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.25.0", + "@babel/plugin-transform-class-properties": "^7.24.7", + "@babel/plugin-transform-class-static-block": "^7.24.7", + "@babel/plugin-transform-classes": "^7.25.0", + "@babel/plugin-transform-computed-properties": "^7.24.7", + "@babel/plugin-transform-destructuring": "^7.24.8", + "@babel/plugin-transform-dotall-regex": "^7.24.7", + "@babel/plugin-transform-duplicate-keys": "^7.24.7", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.0", + "@babel/plugin-transform-dynamic-import": "^7.24.7", + "@babel/plugin-transform-exponentiation-operator": "^7.24.7", + "@babel/plugin-transform-export-namespace-from": "^7.24.7", + "@babel/plugin-transform-for-of": "^7.24.7", + "@babel/plugin-transform-function-name": "^7.25.1", + "@babel/plugin-transform-json-strings": "^7.24.7", + "@babel/plugin-transform-literals": "^7.25.2", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", + "@babel/plugin-transform-member-expression-literals": "^7.24.7", + "@babel/plugin-transform-modules-amd": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.8", + "@babel/plugin-transform-modules-systemjs": "^7.25.0", + "@babel/plugin-transform-modules-umd": "^7.24.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", + "@babel/plugin-transform-new-target": "^7.24.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", + "@babel/plugin-transform-numeric-separator": "^7.24.7", + "@babel/plugin-transform-object-rest-spread": "^7.24.7", + "@babel/plugin-transform-object-super": "^7.24.7", + "@babel/plugin-transform-optional-catch-binding": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.8", + "@babel/plugin-transform-parameters": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.24.7", + "@babel/plugin-transform-private-property-in-object": "^7.24.7", + "@babel/plugin-transform-property-literals": "^7.24.7", + "@babel/plugin-transform-regenerator": "^7.24.7", + "@babel/plugin-transform-reserved-words": "^7.24.7", + "@babel/plugin-transform-shorthand-properties": "^7.24.7", + "@babel/plugin-transform-spread": "^7.24.7", + "@babel/plugin-transform-sticky-regex": "^7.24.7", + "@babel/plugin-transform-template-literals": "^7.24.7", + "@babel/plugin-transform-typeof-symbol": "^7.24.8", + "@babel/plugin-transform-unicode-escapes": "^7.24.7", + "@babel/plugin-transform-unicode-property-regex": "^7.24.7", + "@babel/plugin-transform-unicode-regex": "^7.24.7", + "@babel/plugin-transform-unicode-sets-regex": "^7.24.7", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.4", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.37.1", "semver": "^6.3.1" }, "engines": { @@ -2975,15 +3216,13 @@ } }, "node_modules/@babel/preset-modules": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6.tgz", - "integrity": "sha512-ID2yj6K/4lKfhuU3+EX4UvNbIt7eACFbHmNUjzA+ep+B5971CknnA/9DEWKbRokfbbtblxxxXFJJrH47UEAMVg==", + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", "@babel/types": "^7.4.4", "esutils": "^2.0.2" }, @@ -2999,9 +3238,9 @@ "license": "MIT" }, "node_modules/@babel/runtime": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz", - "integrity": "sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz", + "integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==", "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" @@ -3011,35 +3250,32 @@ } }, "node_modules/@babel/template": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", - "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", + "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.23.5", - "@babel/parser": "^7.24.0", - "@babel/types": "^7.24.0" + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.25.0", + "@babel/types": "^7.25.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", - "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.4.tgz", + "integrity": "sha512-VJ4XsrD+nOvlXyLzmLzUs/0qjFS4sK30te5yEFlvbbUNEgKaVb2BHZUpAL+ttLPQAHNrsI3zZisbfha5Cvr8vg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.24.1", - "@babel/generator": "^7.24.1", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.24.1", - "@babel/types": "^7.24.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.4", + "@babel/parser": "^7.25.4", + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.4", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -3048,13 +3284,13 @@ } }, "node_modules/@babel/traverse/node_modules/@babel/generator": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz", - "integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==", + "version": "7.25.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.5.tgz", + "integrity": "sha512-abd43wyLfbWoxC6ahM8xTkqLpGB2iWBVyuKC9/srhFunCd1SDNrV1s72bBpK4hLj8KLzHBBcOblvLQZBNw9r3w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.24.0", + "@babel/types": "^7.25.4", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" @@ -3064,14 +3300,14 @@ } }, "node_modules/@babel/types": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", - "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.4.tgz", + "integrity": "sha512-zQ1ijeeCXVEh+aNL0RlmkPkG8HUiDcU2pzQQFjtbntgAczRASFzj4H+6+bV+dy1ntKR14I/DypeuRG1uma98iQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", "to-fast-properties": "^2.0.0" }, "engines": { @@ -3079,33 +3315,34 @@ } }, "node_modules/@capacitor-community/file-opener": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@capacitor-community/file-opener/-/file-opener-1.0.6.tgz", - "integrity": "sha512-iHsPblcgqTF8rEmvpVyAGfxuTUtV8BthoBv/zBLKEEb1vSUVONed0UTRjvvqjHxewS8LNEWVXzuMzXfQU1r1cA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@capacitor-community/file-opener/-/file-opener-6.0.0.tgz", + "integrity": "sha512-nJ9S5rCqnVDBKfqdjDhrYOIO9JLeScFkRfKLs2G+d6Df73vrJMes8dr+dGSEvKiPhyjRhICW5imDJEbzaD8KpA==", "license": "MIT", "engines": { "node": ">=16.0.0", "npm": ">=8.0.0" }, "peerDependencies": { - "@capacitor/core": "^5.0.0" + "@capacitor/core": "^6.0.0" } }, "node_modules/@capacitor/android": { - "version": "5.7.8", - "resolved": "https://registry.npmjs.org/@capacitor/android/-/android-5.7.8.tgz", - "integrity": "sha512-ooWclwcuW0dy3YfqgoozkHkjatX8H2fb2/RwRsJa3cew1P1lUXIXri3Dquuy4LdqFAJA7UHcJ19Bl/6UKdsZYA==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@capacitor/android/-/android-6.1.2.tgz", + "integrity": "sha512-Yh0gQDY1bgRrL25J6ecIlvvs2kF8iNSwIPXjyw6Yz9mnwYxBazF5KZbjpKtGPnJgicJhFkYGsqOkEtxrve0EoQ==", + "license": "MIT", "peerDependencies": { - "@capacitor/core": "^5.7.0" + "@capacitor/core": "^6.1.0" } }, "node_modules/@capacitor/app": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/@capacitor/app/-/app-5.0.8.tgz", - "integrity": "sha512-ClUPJG6Awkf5HncVCZQwLrnuugjU8TnACSJ1dKJb6QNCHv2jQzmXvB3KvTvxTZyWbh5EVvlla0qlobYyU1lb6A==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@capacitor/app/-/app-6.0.1.tgz", + "integrity": "sha512-0kXbOl7LPPMFVcAii3u/7Ps0DvXlr7dtHT97r9J1faDlgdQLQUvtGp48tjvFm48gqHI0aOPRJnTBr5JXW4ETYg==", "license": "MIT", "peerDependencies": { - "@capacitor/core": "^5.0.0" + "@capacitor/core": "^6.0.0" } }, "node_modules/@capacitor/assets": { @@ -3136,9 +3373,9 @@ } }, "node_modules/@capacitor/assets/node_modules/@capacitor/cli": { - "version": "5.7.6", - "resolved": "https://registry.npmjs.org/@capacitor/cli/-/cli-5.7.6.tgz", - "integrity": "sha512-CDDcBF7wHm5v/j0dA2bls0vK954XlD1JCjMuTgLtjZMvWrIlTJAkwCQLkiqRhS2P63AXqfqQqkb/qs2RHc1zDQ==", + "version": "5.7.8", + "resolved": "https://registry.npmjs.org/@capacitor/cli/-/cli-5.7.8.tgz", + "integrity": "sha512-qN8LDlREMhrYhOvVXahoJVNkP8LP55/YPRJrzTAFrMqlNJC18L3CzgWYIblFPnuwfbH/RxbfoZT/ydkwgVpMrw==", "dev": true, "license": "MIT", "dependencies": { @@ -3178,147 +3415,94 @@ "node": "^12.20.0 || >=14" } }, - "node_modules/@capacitor/assets/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "node_modules/@capacitor/assets/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/@capacitor/assets/node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "node_modules/@capacitor/assets/node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", "dev": true, "license": "MIT", "engines": { - "node": ">= 12" + "node": ">=8" } }, - "node_modules/@capacitor/assets/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "node_modules/@capacitor/assets/node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "dev": true, "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "bin": { + "is-docker": "cli.js" }, "engines": { - "node": ">=12" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@capacitor/assets/node_modules/glob": { - "version": "9.3.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", - "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "minimatch": "^8.0.2", - "minipass": "^4.2.4", - "path-scurry": "^1.6.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@capacitor/assets/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "node_modules/@capacitor/assets/node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "dev": true, "license": "MIT", "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/@capacitor/assets/node_modules/minimatch": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", - "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" + "is-docker": "^2.0.0" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@capacitor/assets/node_modules/minipass": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", - "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", - "dev": true, - "license": "ISC", "engines": { "node": ">=8" } }, - "node_modules/@capacitor/assets/node_modules/rimraf": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.1.tgz", - "integrity": "sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==", + "node_modules/@capacitor/assets/node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "glob": "^9.2.0" - }, - "bin": { - "rimraf": "dist/cjs/src/bin.js" + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" }, "engines": { - "node": ">=14" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@capacitor/assets/node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 10.0.0" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@capacitor/assets/node_modules/xml2js": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", - "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "node_modules/@capacitor/assets/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", "dev": true, - "license": "MIT", - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } + "license": "0BSD" }, "node_modules/@capacitor/cli": { "version": "6.1.2", "resolved": "https://registry.npmjs.org/@capacitor/cli/-/cli-6.1.2.tgz", "integrity": "sha512-HKCNGE0RP8U7aiEF2vg5wTivJROS8BVfu8a3yYJb1mRQvzv+czpmtHNsTWS/WukvwoxUjyjRmsNQSAACHfMTmQ==", "dev": true, + "license": "MIT", "dependencies": { "@ionic/cli-framework-output": "^2.2.5", "@ionic/utils-fs": "^3.1.6", @@ -3347,377 +3531,583 @@ "node": ">=18.0.0" } }, - "node_modules/@capacitor/cli/node_modules/@ionic/utils-array": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@ionic/utils-array/-/utils-array-2.1.5.tgz", - "integrity": "sha512-HD72a71IQVBmQckDwmA8RxNVMTbxnaLbgFOl+dO5tbvW9CkkSFCv41h6fUuNsSEVgngfkn0i98HDuZC8mk+lTA==", + "node_modules/@capacitor/cli/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", "dev": true, "license": "MIT", - "dependencies": { - "debug": "^4.0.0", - "tslib": "^2.0.1" - }, "engines": { - "node": ">=10.3.0" + "node": "^12.20.0 || >=14" } }, - "node_modules/@capacitor/cli/node_modules/@ionic/utils-fs": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/@ionic/utils-fs/-/utils-fs-3.1.6.tgz", - "integrity": "sha512-eikrNkK89CfGPmexjTfSWl4EYqsPSBh0Ka7by4F0PLc1hJZYtJxUZV3X4r5ecA8ikjicUmcbU7zJmAjmqutG/w==", + "node_modules/@capacitor/cli/node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", "dev": true, "license": "MIT", - "dependencies": { - "@types/fs-extra": "^8.0.0", - "debug": "^4.0.0", - "fs-extra": "^9.0.0", - "tslib": "^2.0.1" - }, "engines": { - "node": ">=10.3.0" + "node": ">=8" } }, - "node_modules/@capacitor/cli/node_modules/@ionic/utils-object": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@ionic/utils-object/-/utils-object-2.1.5.tgz", - "integrity": "sha512-XnYNSwfewUqxq+yjER1hxTKggftpNjFLJH0s37jcrNDwbzmbpFTQTVAp4ikNK4rd9DOebX/jbeZb8jfD86IYxw==", + "node_modules/@capacitor/cli/node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "dev": true, "license": "MIT", - "dependencies": { - "debug": "^4.0.0", - "tslib": "^2.0.1" + "bin": { + "is-docker": "cli.js" }, "engines": { - "node": ">=10.3.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@capacitor/cli/node_modules/@ionic/utils-stream": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/@ionic/utils-stream/-/utils-stream-3.1.5.tgz", - "integrity": "sha512-hkm46uHvEC05X/8PHgdJi4l4zv9VQDELZTM+Kz69odtO9zZYfnt8DkfXHJqJ+PxmtiE5mk/ehJWLnn/XAczTUw==", + "node_modules/@capacitor/cli/node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "dev": true, "license": "MIT", "dependencies": { - "debug": "^4.0.0", - "tslib": "^2.0.1" + "is-docker": "^2.0.0" }, "engines": { - "node": ">=10.3.0" + "node": ">=8" } }, - "node_modules/@capacitor/cli/node_modules/@ionic/utils-subprocess": { - "version": "2.1.11", - "resolved": "https://registry.npmjs.org/@ionic/utils-subprocess/-/utils-subprocess-2.1.11.tgz", - "integrity": "sha512-6zCDixNmZCbMCy5np8klSxOZF85kuDyzZSTTQKQP90ZtYNCcPYmuFSzaqDwApJT4r5L3MY3JrqK1gLkc6xiUPw==", + "node_modules/@capacitor/cli/node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", "dev": true, "license": "MIT", "dependencies": { - "@ionic/utils-array": "2.1.5", - "@ionic/utils-fs": "3.1.6", - "@ionic/utils-process": "2.1.10", - "@ionic/utils-stream": "3.1.5", - "@ionic/utils-terminal": "2.3.3", - "cross-spawn": "^7.0.3", - "debug": "^4.0.0", - "tslib": "^2.0.1" + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" }, "engines": { - "node": ">=10.3.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@capacitor/cli/node_modules/@ionic/utils-subprocess/node_modules/@ionic/utils-process": { - "version": "2.1.10", - "resolved": "https://registry.npmjs.org/@ionic/utils-process/-/utils-process-2.1.10.tgz", - "integrity": "sha512-mZ7JEowcuGQK+SKsJXi0liYTcXd2bNMR3nE0CyTROpMECUpJeAvvaBaPGZf5ERQUPeWBVuwqAqjUmIdxhz5bxw==", - "dev": true, + "node_modules/@capacitor/core": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-6.1.2.tgz", + "integrity": "sha512-xFy1/4qLFLp5WCIzIhtwUuVNNoz36+V7/BzHmLqgVJcvotc4MMjswW/TshnPQaLLujEOaLkA4h8ZJ0uoK3ImGg==", "license": "MIT", "dependencies": { - "@ionic/utils-object": "2.1.5", - "@ionic/utils-terminal": "2.3.3", - "debug": "^4.0.0", - "signal-exit": "^3.0.3", - "tree-kill": "^1.2.2", - "tslib": "^2.0.1" - }, + "tslib": "^2.1.0" + } + }, + "node_modules/@capacitor/filesystem": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@capacitor/filesystem/-/filesystem-6.0.1.tgz", + "integrity": "sha512-eHhXm6tzBIQhErzFnfOE6eA1U+15DHc2212/COfzzGGRk/dyGympoVV3ct2YPVzvpTSxMEW3xFocORv/xD9gFg==", + "license": "MIT", + "peerDependencies": { + "@capacitor/core": "^6.0.0" + } + }, + "node_modules/@capacitor/ios": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@capacitor/ios/-/ios-6.1.2.tgz", + "integrity": "sha512-HaeW68KisBd/7TmavzPDlL2bpoDK5AjR2ZYrqU4TlGwM88GtQfvduBCAlSCj20X0w/4+rWMkseD9dAAkacjiyQ==", + "license": "MIT", + "peerDependencies": { + "@capacitor/core": "^6.1.0" + } + }, + "node_modules/@capacitor/splash-screen": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@capacitor/splash-screen/-/splash-screen-6.0.2.tgz", + "integrity": "sha512-WC0KYZ+ev15up03xs4fTnoTKwBVUSxXsKKQr/8XAncvi/nAG8qrpanW8OlavSC5zF5e1IZZDLsI2GSv0SkZ7VQ==", + "license": "MIT", + "peerDependencies": { + "@capacitor/core": "^6.0.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=10.3.0" + "node": ">=0.1.90" } }, - "node_modules/@capacitor/cli/node_modules/@ionic/utils-terminal": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/@ionic/utils-terminal/-/utils-terminal-2.3.3.tgz", - "integrity": "sha512-RnuSfNZ5fLEyX3R5mtcMY97cGD1A0NVBbarsSQ6yMMfRJ5YHU7hHVyUfvZeClbqkBC/pAqI/rYJuXKCT9YeMCQ==", + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, "license": "MIT", "dependencies": { - "@types/slice-ansi": "^4.0.0", - "debug": "^4.0.0", - "signal-exit": "^3.0.3", - "slice-ansi": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "tslib": "^2.0.1", - "untildify": "^4.0.0", - "wrap-ansi": "^7.0.0" + "@jridgewell/trace-mapping": "0.3.9" }, "engines": { - "node": ">=10.3.0" + "node": ">=12" } }, - "node_modules/@capacitor/cli/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "node_modules/@capacitor/cli/node_modules/commander": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", - "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "node_modules/@discoveryjs/json-ext": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.6.1.tgz", + "integrity": "sha512-boghen8F0Q8D+0/Q1/1r6DUEieUJ8w2a1gIknExMSHBsJFOr2+0KUfHiVYBvucPwl3+RU5PFBK833FjFCh3BhA==", "dev": true, "license": "MIT", "engines": { - "node": "^12.20.0 || >=14" + "node": ">=14.17.0" } }, - "node_modules/@capacitor/cli/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "node_modules/@es-joy/jsdoccomment": { + "version": "0.46.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.46.0.tgz", + "integrity": "sha512-C3Axuq1xd/9VqFZpW4YAzOx5O9q/LP46uIQy/iNDpHG3fmPa6TBtvfglMCs3RBiBxAIi0Go97r8+jvTt55XMyQ==", "dev": true, "license": "MIT", "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "comment-parser": "1.4.1", + "esquery": "^1.6.0", + "jsdoc-type-pratt-parser": "~4.0.0" }, "engines": { - "node": ">=10" + "node": ">=16" } }, - "node_modules/@capacitor/cli/node_modules/glob": { - "version": "9.3.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", - "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", + "node_modules/@esbuild/aix-ppc64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.0.tgz", + "integrity": "sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==", + "cpu": [ + "ppc64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "minimatch": "^8.0.2", - "minipass": "^4.2.4", - "path-scurry": "^1.6.1" - }, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=18" } }, - "node_modules/@capacitor/cli/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "node_modules/@esbuild/android-arm": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.0.tgz", + "integrity": "sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@capacitor/cli/node_modules/minimatch": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", - "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", + "node_modules/@esbuild/android-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.0.tgz", + "integrity": "sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=18" } }, - "node_modules/@capacitor/cli/node_modules/minipass": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", - "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", + "node_modules/@esbuild/android-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.0.tgz", + "integrity": "sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==", + "cpu": [ + "x64" + ], "dev": true, - "license": "ISC", + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/@capacitor/cli/node_modules/rimraf": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.1.tgz", - "integrity": "sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==", + "node_modules/@esbuild/darwin-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.0.tgz", + "integrity": "sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^9.2.0" - }, - "bin": { - "rimraf": "dist/cjs/src/bin.js" - }, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=18" } }, - "node_modules/@capacitor/cli/node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "node_modules/@esbuild/darwin-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.0.tgz", + "integrity": "sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">= 10.0.0" + "node": ">=18" } }, - "node_modules/@capacitor/cli/node_modules/xml2js": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", - "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.0.tgz", + "integrity": "sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/@capacitor/core": { - "version": "5.7.8", - "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-5.7.8.tgz", - "integrity": "sha512-rrZcm/2vJM0WdWRQup1TUidbjQV9PfIadSkV4rAGLD7R6PuzZSMPGT0gmoZzCRlXkqrazrWWDkurei3ozU02FA==", - "dependencies": { - "tslib": "^2.1.0" + "node": ">=18" } }, - "node_modules/@capacitor/filesystem": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/@capacitor/filesystem/-/filesystem-5.2.2.tgz", - "integrity": "sha512-h0Ta0NXF/zX9bXoD5qtoEoWSWCewow8Kredb2bBFO+vrd4NVthZH+GyrII2dk0++UIw40HjyLNk4apwGGSu9Sg==", + "node_modules/@esbuild/freebsd-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.0.tgz", + "integrity": "sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", - "peerDependencies": { - "@capacitor/core": "^5.1.1" - } - }, - "node_modules/@capacitor/ios": { - "version": "5.7.8", - "resolved": "https://registry.npmjs.org/@capacitor/ios/-/ios-5.7.8.tgz", - "integrity": "sha512-XhGrziBnlRmCJ97LdPXOJquHPpYTwSJZIxYSXuPl7SDDuAEve8vs2wY76gLdaaFH2Z6ctdugUX+jR6VNu+ds+w==", - "peerDependencies": { - "@capacitor/core": "^5.7.0" + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@capacitor/splash-screen": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/@capacitor/splash-screen/-/splash-screen-5.0.8.tgz", - "integrity": "sha512-mDRJS9QFxL5UMN74gRr6cBhOtkZjWwdttPCjBJNgcMDJIGi9IAKRJuDGTsqSUbp6zWrPF4AW29Mu6qhXtHpHWg==", + "node_modules/@esbuild/linux-arm": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.0.tgz", + "integrity": "sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==", + "cpu": [ + "arm" + ], + "dev": true, "license": "MIT", - "peerDependencies": { - "@capacitor/core": "^5.0.0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "node_modules/@esbuild/linux-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.0.tgz", + "integrity": "sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=0.1.90" + "node": ">=18" } }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "node_modules/@esbuild/linux-ia32": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.0.tgz", + "integrity": "sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12" + "node": ">=18" } }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "node_modules/@esbuild/linux-loong64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.0.tgz", + "integrity": "sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==", + "cpu": [ + "loong64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@discoveryjs/json-ext": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", - "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "node_modules/@esbuild/linux-mips64el": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.0.tgz", + "integrity": "sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==", + "cpu": [ + "mips64el" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=10.0.0" + "node": ">=18" } }, - "node_modules/@es-joy/jsdoccomment": { - "version": "0.42.0", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.42.0.tgz", - "integrity": "sha512-R1w57YlVA6+YE01wch3GPYn6bCsrOV3YW/5oGGE2tmX6JcL9Nr+b5IikrjMPF+v9CV3ay+obImEdsDhovhJrzw==", + "node_modules/@esbuild/linux-ppc64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.0.tgz", + "integrity": "sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==", + "cpu": [ + "ppc64" + ], "dev": true, "license": "MIT", - "dependencies": { - "comment-parser": "1.4.1", - "esquery": "^1.5.0", - "jsdoc-type-pratt-parser": "~4.0.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=16" + "node": ">=18" } }, - "node_modules/@esbuild/win32-x64": { - "version": "0.18.17", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.17.tgz", - "integrity": "sha512-fGEb8f2BSA3CW7riJVurug65ACLuQAzKq0SSqkY2b2yHHH0MzDfbLyKIGzHwOI/gkHcxM/leuSW6D5w/LMNitA==", + "node_modules/@esbuild/linux-riscv64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.0.tgz", + "integrity": "sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==", "cpu": [ - "x64" + "riscv64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" + "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "node_modules/@esbuild/linux-s390x": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.0.tgz", + "integrity": "sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==", + "cpu": [ + "s390x" + ], "dev": true, "license": "MIT", - "dependencies": { + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.0.tgz", + "integrity": "sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.0.tgz", + "integrity": "sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.0.tgz", + "integrity": "sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.0.tgz", + "integrity": "sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.0.tgz", + "integrity": "sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.0.tgz", + "integrity": "sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.0.tgz", + "integrity": "sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.0.tgz", + "integrity": "sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "license": "MIT", + "dependencies": { "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -3727,10 +4117,23 @@ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", "dev": true, "license": "MIT", "engines": { @@ -3778,12 +4181,47 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@eslint/eslintrc/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "license": "Python-2.0" + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } }, "node_modules/@eslint/eslintrc/node_modules/globals": { "version": "13.24.0", @@ -3801,19 +4239,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@eslint/eslintrc/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -3821,6 +4246,19 @@ "dev": true, "license": "MIT" }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@eslint/eslintrc/node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -3844,17 +4282,11 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@gar/promisify": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", - "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", - "dev": true, - "license": "MIT" - }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "deprecated": "Use @eslint/config-array instead", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -3866,6 +4298,30 @@ "node": ">=10.10.0" } }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -3881,9 +4337,10 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", - "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", "dev": true, "license": "BSD-3-Clause" }, @@ -3897,39 +4354,239 @@ "node": ">=6.9.0" } }, - "node_modules/@ionic-native/core": { - "version": "5.36.0", - "resolved": "https://registry.npmjs.org/@ionic-native/core/-/core-5.36.0.tgz", - "integrity": "sha512-lOrkktadlKYbYf1LrDyAtsu1JnQ0oCCdkOU7iHQ8oXnNOkMwobFfD2m62F1CoOr0u9LIkpYnZSPjng8lZbmbNw==", + "node_modules/@inquirer/checkbox": { + "version": "2.4.7", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-2.4.7.tgz", + "integrity": "sha512-5YwCySyV1UEgqzz34gNsC38eKxRBtlRDpJLlKcRtTjlYA/yDKuc1rfw+hjw+2WJxbAZtaDPsRl5Zk7J14SBoBw==", + "dev": true, "license": "MIT", "dependencies": { - "@types/cordova": "latest" + "@inquirer/core": "^9.0.10", + "@inquirer/figures": "^1.0.5", + "@inquirer/type": "^1.5.2", + "ansi-escapes": "^4.3.2", + "yoctocolors-cjs": "^2.1.2" }, - "peerDependencies": { - "rxjs": "^5.5.0 || ^6.5.0" + "engines": { + "node": ">=18" } }, - "node_modules/@ionic-native/file-opener": { - "version": "5.36.0", - "resolved": "https://registry.npmjs.org/@ionic-native/file-opener/-/file-opener-5.36.0.tgz", - "integrity": "sha512-UKp3pbqvQXsAtLMJ5JE+KcTMxpjSZMFebf6nvy/KJvwy85JGIaCV4ZVM/H9CFUrHJMWBH6wDbY+WPygnsrl4Yg==", + "node_modules/@inquirer/confirm": { + "version": "3.1.22", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-3.1.22.tgz", + "integrity": "sha512-gsAKIOWBm2Q87CDfs9fEo7wJT3fwWIJfnDGMn9Qy74gBnNFOACDNfhUzovubbJjWnKLGBln7/NcSmZwj5DuEXg==", + "dev": true, "license": "MIT", "dependencies": { - "@types/cordova": "latest" + "@inquirer/core": "^9.0.10", + "@inquirer/type": "^1.5.2" }, - "peerDependencies": { - "@ionic-native/core": "^5.1.0", - "rxjs": "^5.5.0 || ^6.5.0" + "engines": { + "node": ">=18" } }, - "node_modules/@ionic/angular": { - "version": "6.7.5", - "resolved": "https://registry.npmjs.org/@ionic/angular/-/angular-6.7.5.tgz", - "integrity": "sha512-nV8HP7RedjYkIAT8nVr5ifHNT0D3XzA74RPG3/WCCFJKunERNJ9SBiNkCTWhUpSkqsYYwEB4+SOOHz+R5NLk/w==", + "node_modules/@inquirer/core": { + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.10.tgz", + "integrity": "sha512-TdESOKSVwf6+YWDz8GhS6nKscwzkIyakEzCLJ5Vh6O3Co2ClhCJ0A4MG909MUWfaWdpJm7DE45ii51/2Kat9tA==", + "dev": true, "license": "MIT", "dependencies": { - "@ionic/core": "6.7.5", - "ionicons": "^6.1.3", + "@inquirer/figures": "^1.0.5", + "@inquirer/type": "^1.5.2", + "@types/mute-stream": "^0.0.4", + "@types/node": "^22.1.0", + "@types/wrap-ansi": "^3.0.0", + "ansi-escapes": "^4.3.2", + "cli-spinners": "^2.9.2", + "cli-width": "^4.1.0", + "mute-stream": "^1.0.0", + "signal-exit": "^4.1.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/core/node_modules/@types/node": { + "version": "22.5.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.0.tgz", + "integrity": "sha512-DkFrJOe+rfdHTqqMg0bSNlGlQ85hSoh2TPzZyhHsXnMtligRWpxUySiyw8FY14ITt24HVCiQPWxS3KO/QlGmWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/@inquirer/editor": { + "version": "2.1.22", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-2.1.22.tgz", + "integrity": "sha512-K1QwTu7GCK+nKOVRBp5HY9jt3DXOfPGPr6WRDrPImkcJRelG9UTx2cAtK1liXmibRrzJlTWOwqgWT3k2XnS62w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^9.0.10", + "@inquirer/type": "^1.5.2", + "external-editor": "^3.1.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/expand": { + "version": "2.1.22", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-2.1.22.tgz", + "integrity": "sha512-wTZOBkzH+ItPuZ3ZPa9lynBsdMp6kQ9zbjVPYEtSBG7UulGjg2kQiAnUjgyG4SlntpTce5bOmXAPvE4sguXjpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^9.0.10", + "@inquirer/type": "^1.5.2", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/figures": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.5.tgz", + "integrity": "sha512-79hP/VWdZ2UVc9bFGJnoQ/lQMpL74mGgzSYX1xUqCVk7/v73vJCMw1VuyWN1jGkZ9B3z7THAbySqGbCNefcjfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/input": { + "version": "2.2.9", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-2.2.9.tgz", + "integrity": "sha512-7Z6N+uzkWM7+xsE+3rJdhdG/+mQgejOVqspoW+w0AbSZnL6nq5tGMEVASaYVWbkoSzecABWwmludO2evU3d31g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^9.0.10", + "@inquirer/type": "^1.5.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/password": { + "version": "2.1.22", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-2.1.22.tgz", + "integrity": "sha512-5Fxt1L9vh3rAKqjYwqsjU4DZsEvY/2Gll+QkqR4yEpy6wvzLxdSgFhUcxfDAOtO4BEoTreWoznC0phagwLU5Kw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^9.0.10", + "@inquirer/type": "^1.5.2", + "ansi-escapes": "^4.3.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/prompts": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-5.0.7.tgz", + "integrity": "sha512-GFcigCxJTKCH3aECzMIu4FhgLJWnFvMXzpI4CCSoELWFtkOOU2P+goYA61+OKpGrB8fPE7q6n8zAXBSlZRrHjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/checkbox": "^2.3.7", + "@inquirer/confirm": "^3.1.11", + "@inquirer/editor": "^2.1.11", + "@inquirer/expand": "^2.1.11", + "@inquirer/input": "^2.1.11", + "@inquirer/password": "^2.1.11", + "@inquirer/rawlist": "^2.1.11", + "@inquirer/select": "^2.3.7" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/rawlist": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-2.2.4.tgz", + "integrity": "sha512-pb6w9pWrm7EfnYDgQObOurh2d2YH07+eDo3xQBsNAM2GRhliz6wFXGi1thKQ4bN6B0xDd6C3tBsjdr3obsCl3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^9.0.10", + "@inquirer/type": "^1.5.2", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/select": { + "version": "2.4.7", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-2.4.7.tgz", + "integrity": "sha512-JH7XqPEkBpNWp3gPCqWqY8ECbyMoFcCZANlL6pV9hf59qK6dGmkOlx1ydyhY+KZ0c5X74+W6Mtp+nm2QX0/MAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^9.0.10", + "@inquirer/figures": "^1.0.5", + "@inquirer/type": "^1.5.2", + "ansi-escapes": "^4.3.2", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/type": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-1.5.2.tgz", + "integrity": "sha512-w9qFkumYDCNyDZmNQjf/n6qQuvQ4dMC3BJesY4oF+yr0CxR5vxujflAVeIcS6U336uzi9GM0kAfZlLrZ9UTkpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mute-stream": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@ionic-native/core": { + "version": "5.36.0", + "resolved": "https://registry.npmjs.org/@ionic-native/core/-/core-5.36.0.tgz", + "integrity": "sha512-lOrkktadlKYbYf1LrDyAtsu1JnQ0oCCdkOU7iHQ8oXnNOkMwobFfD2m62F1CoOr0u9LIkpYnZSPjng8lZbmbNw==", + "license": "MIT", + "dependencies": { + "@types/cordova": "latest" + }, + "peerDependencies": { + "rxjs": "^5.5.0 || ^6.5.0" + } + }, + "node_modules/@ionic-native/file-opener": { + "version": "5.36.0", + "resolved": "https://registry.npmjs.org/@ionic-native/file-opener/-/file-opener-5.36.0.tgz", + "integrity": "sha512-UKp3pbqvQXsAtLMJ5JE+KcTMxpjSZMFebf6nvy/KJvwy85JGIaCV4ZVM/H9CFUrHJMWBH6wDbY+WPygnsrl4Yg==", + "license": "MIT", + "dependencies": { + "@types/cordova": "latest" + }, + "peerDependencies": { + "@ionic-native/core": "^5.1.0", + "rxjs": "^5.5.0 || ^6.5.0" + } + }, + "node_modules/@ionic/angular": { + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@ionic/angular/-/angular-6.7.5.tgz", + "integrity": "sha512-nV8HP7RedjYkIAT8nVr5ifHNT0D3XzA74RPG3/WCCFJKunERNJ9SBiNkCTWhUpSkqsYYwEB4+SOOHz+R5NLk/w==", + "license": "MIT", + "dependencies": { + "@ionic/core": "6.7.5", + "ionicons": "^6.1.3", "jsonc-parser": "^3.0.0", "tslib": "^2.0.0" }, @@ -3954,9 +4611,9 @@ } }, "node_modules/@ionic/angular-toolkit/node_modules/@angular-devkit/core": { - "version": "17.3.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-17.3.3.tgz", - "integrity": "sha512-J22Sh3M7rj8Ar3iEs20ko5wgC3DE7vWfYZNdimt2IJiS4J7BEX8R3Awf+TRt+6AN3NFm3/xe1Sz4yvDh3FvNFg==", + "version": "17.3.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-17.3.8.tgz", + "integrity": "sha512-Q8q0voCGudbdCgJ7lXdnyaxKHbNQBARH68zPQV72WT8NWy+Gw/tys870i6L58NWbBaCJEUcIj/kb6KoakSRu+Q==", "dev": true, "license": "MIT", "dependencies": { @@ -3982,13 +4639,13 @@ } }, "node_modules/@ionic/angular-toolkit/node_modules/@angular-devkit/schematics": { - "version": "17.3.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-17.3.3.tgz", - "integrity": "sha512-SABqTtj2im4PJhQjNaAsSypbNkpZFW8YozJ3P748tlh5a9XoHpgiqXv5JhRbyKElLDAyk5i9fe2++JmSudPG/Q==", + "version": "17.3.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-17.3.8.tgz", + "integrity": "sha512-QRVEYpIfgkprNHc916JlPuNbLzOgrm9DZalHasnLUz4P6g7pR21olb8YCyM2OTJjombNhya9ZpckcADU5Qyvlg==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "17.3.3", + "@angular-devkit/core": "17.3.8", "jsonc-parser": "3.2.1", "magic-string": "0.30.8", "ora": "5.4.1", @@ -4001,14 +4658,14 @@ } }, "node_modules/@ionic/angular-toolkit/node_modules/@schematics/angular": { - "version": "17.3.3", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-17.3.3.tgz", - "integrity": "sha512-kNlyjIKTBhfi8Jab3MCkxNRbbpErbzdu0lZNSL8Nidmqs6Tk23Dc1bZe4t/gPNOCkCvQlwYa6X88SjC/ntyVng==", + "version": "17.3.8", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-17.3.8.tgz", + "integrity": "sha512-2g4OmSyE9YGq50Uj7fNI26P/TSAFJ7ZuirwTF2O7Xc4XRQ29/tYIIqhezpNlTb6rlYblcQuMcUZBrMfWJHcqJw==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "17.3.3", - "@angular-devkit/schematics": "17.3.3", + "@angular-devkit/core": "17.3.8", + "@angular-devkit/schematics": "17.3.8", "jsonc-parser": "3.2.1" }, "engines": { @@ -4017,6 +4674,48 @@ "yarn": ">= 1.13.0" } }, + "node_modules/@ionic/angular-toolkit/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@ionic/angular-toolkit/node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/@ionic/angular-toolkit/node_modules/jsonc-parser": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", + "dev": true, + "license": "MIT" + }, "node_modules/@ionic/angular-toolkit/node_modules/magic-string": { "version": "0.30.8", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", @@ -4057,6 +4756,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/@ionic/cli/-/cli-7.2.0.tgz", "integrity": "sha512-IEms9Df8mJOoWPqgvZEXmqKztttHDFAz+9ewDPZGYv8Xx66Cj7zSen13O2Vf4FuLXhl+U95HXT9sAs4lDwFmcQ==", + "dev": true, "license": "MIT", "dependencies": { "@ionic/cli-framework": "6.0.1", @@ -4097,6 +4797,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/@ionic/cli-framework/-/cli-framework-6.0.1.tgz", "integrity": "sha512-Fyix4eQt2HKTV+GoeoiziQGZyqIA8RfoMqjGyAS5XgNXLOYW0P27Ph348hQZh9Mphjf+m0lOYa6dWQTEPzUHiQ==", + "dev": true, "license": "MIT", "dependencies": { "@ionic/cli-framework-output": "2.2.8", @@ -4123,6 +4824,7 @@ "version": "2.2.8", "resolved": "https://registry.npmjs.org/@ionic/cli-framework-output/-/cli-framework-output-2.2.8.tgz", "integrity": "sha512-TshtaFQsovB4NWRBydbNFawql6yul7d5bMiW1WYYf17hd99V6xdDdk3vtF51bw6sLkxON3bDQpWsnUc9/hVo3g==", + "dev": true, "license": "MIT", "dependencies": { "@ionic/utils-terminal": "2.3.5", @@ -4137,6 +4839,7 @@ "version": "2.1.13", "resolved": "https://registry.npmjs.org/@ionic/cli-framework-prompts/-/cli-framework-prompts-2.1.13.tgz", "integrity": "sha512-Yj1fz6p7OehreQ8C70bd9+M6tYP/rvzLw5JVj8pT/N9s0kQSjqEFRbs96LKr3lfd3TADZaS8OlZrQIqenFIUpg==", + "dev": true, "license": "MIT", "dependencies": { "@ionic/utils-terminal": "2.3.5", @@ -4148,10 +4851,31 @@ "node": ">=16.0.0" } }, - "node_modules/@ionic/cli-framework-prompts/node_modules/ansi-styles": { + "node_modules/@ionic/cli-framework/node_modules/@ionic/utils-subprocess": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@ionic/utils-subprocess/-/utils-subprocess-3.0.1.tgz", + "integrity": "sha512-cT4te3AQQPeIM9WCwIg8ohroJ8TjsYaMb2G4ZEgv9YzeDqHZ4JpeIKqG2SoaA3GmVQ3sOfhPM6Ox9sxphV/d1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ionic/utils-array": "2.1.6", + "@ionic/utils-fs": "3.1.7", + "@ionic/utils-process": "2.1.12", + "@ionic/utils-stream": "3.1.7", + "@ionic/utils-terminal": "2.3.5", + "cross-spawn": "^7.0.3", + "debug": "^4.0.0", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@ionic/cli-framework/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -4163,10 +4887,11 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@ionic/cli-framework-prompts/node_modules/chalk": { + "node_modules/@ionic/cli-framework/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -4179,10 +4904,11 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@ionic/cli-framework-prompts/node_modules/color-convert": { + "node_modules/@ionic/cli-framework/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -4191,43 +4917,45 @@ "node": ">=7.0.0" } }, - "node_modules/@ionic/cli-framework-prompts/node_modules/has-flag": { + "node_modules/@ionic/cli-framework/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@ionic/cli-framework/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/@ionic/cli-framework-prompts/node_modules/inquirer": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", - "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", - "license": "MIT", + "node_modules/@ionic/cli-framework/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", "dependencies": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.19", - "mute-stream": "0.0.8", - "run-async": "^2.4.0", - "rxjs": "^6.6.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6" + "glob": "^7.1.3" }, - "engines": { - "node": ">=8.0.0" + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@ionic/cli-framework-prompts/node_modules/supports-color": { + "node_modules/@ionic/cli-framework/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -4236,10 +4964,11 @@ "node": ">=8" } }, - "node_modules/@ionic/cli-framework/node_modules/@ionic/utils-subprocess": { + "node_modules/@ionic/cli/node_modules/@ionic/utils-subprocess": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@ionic/utils-subprocess/-/utils-subprocess-3.0.1.tgz", "integrity": "sha512-cT4te3AQQPeIM9WCwIg8ohroJ8TjsYaMb2G4ZEgv9YzeDqHZ4JpeIKqG2SoaA3GmVQ3sOfhPM6Ox9sxphV/d1A==", + "dev": true, "license": "MIT", "dependencies": { "@ionic/utils-array": "2.1.6", @@ -4255,10 +4984,11 @@ "node": ">=16.0.0" } }, - "node_modules/@ionic/cli-framework/node_modules/ansi-styles": { + "node_modules/@ionic/cli/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -4270,10 +5000,11 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@ionic/cli-framework/node_modules/chalk": { + "node_modules/@ionic/cli/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -4286,10 +5017,11 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@ionic/cli-framework/node_modules/color-convert": { + "node_modules/@ionic/cli/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -4298,94 +5030,48 @@ "node": ">=7.0.0" } }, - "node_modules/@ionic/cli-framework/node_modules/has-flag": { + "node_modules/@ionic/cli/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@ionic/cli/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/@ionic/cli-framework/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@ionic/cli/node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@ionic/cli/node_modules/@ionic/utils-subprocess": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@ionic/utils-subprocess/-/utils-subprocess-3.0.1.tgz", - "integrity": "sha512-cT4te3AQQPeIM9WCwIg8ohroJ8TjsYaMb2G4ZEgv9YzeDqHZ4JpeIKqG2SoaA3GmVQ3sOfhPM6Ox9sxphV/d1A==", - "license": "MIT", - "dependencies": { - "@ionic/utils-array": "2.1.6", - "@ionic/utils-fs": "3.1.7", - "@ionic/utils-process": "2.1.12", - "@ionic/utils-stream": "3.1.7", - "@ionic/utils-terminal": "2.3.5", - "cross-spawn": "^7.0.3", - "debug": "^4.0.0", - "tslib": "^2.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@ionic/cli/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" + "bin": { + "is-docker": "cli.js" }, "engines": { "node": ">=8" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@ionic/cli/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@ionic/cli/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@ionic/cli/node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "is-docker": "^2.0.0" }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@ionic/cli/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "license": "MIT", "engines": { "node": ">=8" } @@ -4394,6 +5080,7 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "dev": true, "license": "MIT", "dependencies": { "is-docker": "^2.0.0", @@ -4410,6 +5097,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -4433,6 +5121,7 @@ "version": "2.1.6", "resolved": "https://registry.npmjs.org/@ionic/utils-array/-/utils-array-2.1.6.tgz", "integrity": "sha512-0JZ1Zkp3wURnv8oq6Qt7fMPo5MpjbLoUoa9Bu2Q4PJuSDWM8H8gwF3dQO7VTeUj3/0o1IB1wGkFWZZYgUXZMUg==", + "dev": true, "license": "MIT", "dependencies": { "debug": "^4.0.0", @@ -4446,6 +5135,7 @@ "version": "3.1.7", "resolved": "https://registry.npmjs.org/@ionic/utils-fs/-/utils-fs-3.1.7.tgz", "integrity": "sha512-2EknRvMVfhnyhL1VhFkSLa5gOcycK91VnjfrTB0kbqkTFCOXyXgVLI5whzq7SLrgD9t1aqos3lMMQyVzaQ5gVA==", + "dev": true, "license": "MIT", "dependencies": { "@types/fs-extra": "^8.0.0", @@ -4461,6 +5151,7 @@ "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, "license": "MIT", "dependencies": { "at-least-node": "^1.0.0", @@ -4472,31 +5163,11 @@ "node": ">=10" } }, - "node_modules/@ionic/utils-fs/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/@ionic/utils-fs/node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, "node_modules/@ionic/utils-network": { "version": "2.1.7", "resolved": "https://registry.npmjs.org/@ionic/utils-network/-/utils-network-2.1.7.tgz", "integrity": "sha512-5Q3NdZtSLiLs7ufuX9X293BvAwo8CxaD93Hkp3ODPgctLYErv3nFibhq3j+eguEqUh2um9WNXEUOuQ8x+Sd1fw==", + "dev": true, "license": "MIT", "dependencies": { "debug": "^4.0.0", @@ -4510,6 +5181,7 @@ "version": "2.1.6", "resolved": "https://registry.npmjs.org/@ionic/utils-object/-/utils-object-2.1.6.tgz", "integrity": "sha512-vCl7sl6JjBHFw99CuAqHljYJpcE88YaH2ZW4ELiC/Zwxl5tiwn4kbdP/gxi2OT3MQb1vOtgAmSNRtusvgxI8ww==", + "dev": true, "license": "MIT", "dependencies": { "debug": "^4.0.0", @@ -4523,6 +5195,7 @@ "version": "2.1.12", "resolved": "https://registry.npmjs.org/@ionic/utils-process/-/utils-process-2.1.12.tgz", "integrity": "sha512-Jqkgyq7zBs/v/J3YvKtQQiIcxfJyplPgECMWgdO0E1fKrrH8EF0QGHNJ9mJCn6PYe2UtHNS8JJf5G21e09DfYg==", + "dev": true, "license": "MIT", "dependencies": { "@ionic/utils-object": "2.1.6", @@ -4536,10 +5209,18 @@ "node": ">=16.0.0" } }, + "node_modules/@ionic/utils-process/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, "node_modules/@ionic/utils-stream": { "version": "3.1.7", "resolved": "https://registry.npmjs.org/@ionic/utils-stream/-/utils-stream-3.1.7.tgz", "integrity": "sha512-eSELBE7NWNFIHTbTC2jiMvh1ABKGIpGdUIvARsNPMNQhxJB3wpwdiVnoBoTYp+5a6UUIww4Kpg7v6S7iTctH1w==", + "dev": true, "license": "MIT", "dependencies": { "debug": "^4.0.0", @@ -4550,82 +5231,106 @@ } }, "node_modules/@ionic/utils-subprocess": { - "version": "2.1.14", - "resolved": "https://registry.npmjs.org/@ionic/utils-subprocess/-/utils-subprocess-2.1.14.tgz", - "integrity": "sha512-nGYvyGVjU0kjPUcSRFr4ROTraT3w/7r502f5QJEsMRKTqa4eEzCshtwRk+/mpASm0kgBN5rrjYA5A/OZg8ahqg==", + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/@ionic/utils-subprocess/-/utils-subprocess-2.1.11.tgz", + "integrity": "sha512-6zCDixNmZCbMCy5np8klSxOZF85kuDyzZSTTQKQP90ZtYNCcPYmuFSzaqDwApJT4r5L3MY3JrqK1gLkc6xiUPw==", "dev": true, "license": "MIT", "dependencies": { - "@ionic/utils-array": "2.1.6", - "@ionic/utils-fs": "3.1.7", - "@ionic/utils-process": "2.1.11", - "@ionic/utils-stream": "3.1.6", - "@ionic/utils-terminal": "2.3.4", + "@ionic/utils-array": "2.1.5", + "@ionic/utils-fs": "3.1.6", + "@ionic/utils-process": "2.1.10", + "@ionic/utils-stream": "3.1.5", + "@ionic/utils-terminal": "2.3.3", "cross-spawn": "^7.0.3", "debug": "^4.0.0", "tslib": "^2.0.1" }, "engines": { - "node": ">=16.0.0" + "node": ">=10.3.0" } }, - "node_modules/@ionic/utils-subprocess/node_modules/@ionic/utils-process": { - "version": "2.1.11", - "resolved": "https://registry.npmjs.org/@ionic/utils-process/-/utils-process-2.1.11.tgz", - "integrity": "sha512-Uavxn+x8j3rDlZEk1X7YnaN6wCgbCwYQOeIjv/m94i1dzslqWhqIHEqxEyeE8HsT5Negboagg7GtQiABy+BLbA==", + "node_modules/@ionic/utils-subprocess/node_modules/@ionic/utils-array": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@ionic/utils-array/-/utils-array-2.1.5.tgz", + "integrity": "sha512-HD72a71IQVBmQckDwmA8RxNVMTbxnaLbgFOl+dO5tbvW9CkkSFCv41h6fUuNsSEVgngfkn0i98HDuZC8mk+lTA==", "dev": true, "license": "MIT", "dependencies": { - "@ionic/utils-object": "2.1.6", - "@ionic/utils-terminal": "2.3.4", "debug": "^4.0.0", - "signal-exit": "^3.0.3", - "tree-kill": "^1.2.2", "tslib": "^2.0.1" }, "engines": { - "node": ">=16.0.0" + "node": ">=10.3.0" } }, - "node_modules/@ionic/utils-subprocess/node_modules/@ionic/utils-stream": { + "node_modules/@ionic/utils-subprocess/node_modules/@ionic/utils-fs": { "version": "3.1.6", - "resolved": "https://registry.npmjs.org/@ionic/utils-stream/-/utils-stream-3.1.6.tgz", - "integrity": "sha512-4+Kitey1lTA1yGtnigeYNhV/0tggI3lWBMjC7tBs1K9GXa/q7q4CtOISppdh8QgtOhrhAXS2Igp8rbko/Cj+lA==", + "resolved": "https://registry.npmjs.org/@ionic/utils-fs/-/utils-fs-3.1.6.tgz", + "integrity": "sha512-eikrNkK89CfGPmexjTfSWl4EYqsPSBh0Ka7by4F0PLc1hJZYtJxUZV3X4r5ecA8ikjicUmcbU7zJmAjmqutG/w==", "dev": true, "license": "MIT", "dependencies": { + "@types/fs-extra": "^8.0.0", "debug": "^4.0.0", + "fs-extra": "^9.0.0", "tslib": "^2.0.1" }, "engines": { - "node": ">=16.0.0" + "node": ">=10.3.0" } }, - "node_modules/@ionic/utils-subprocess/node_modules/@ionic/utils-terminal": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/@ionic/utils-terminal/-/utils-terminal-2.3.4.tgz", - "integrity": "sha512-cEiMFl3jklE0sW60r8JHH3ijFTwh/jkdEKWbylSyExQwZ8pPuwoXz7gpkWoJRLuoRHHSvg+wzNYyPJazIHfoJA==", + "node_modules/@ionic/utils-subprocess/node_modules/@ionic/utils-object": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@ionic/utils-object/-/utils-object-2.1.5.tgz", + "integrity": "sha512-XnYNSwfewUqxq+yjER1hxTKggftpNjFLJH0s37jcrNDwbzmbpFTQTVAp4ikNK4rd9DOebX/jbeZb8jfD86IYxw==", "dev": true, "license": "MIT", "dependencies": { - "@types/slice-ansi": "^4.0.0", + "debug": "^4.0.0", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=10.3.0" + } + }, + "node_modules/@ionic/utils-subprocess/node_modules/@ionic/utils-process": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@ionic/utils-process/-/utils-process-2.1.10.tgz", + "integrity": "sha512-mZ7JEowcuGQK+SKsJXi0liYTcXd2bNMR3nE0CyTROpMECUpJeAvvaBaPGZf5ERQUPeWBVuwqAqjUmIdxhz5bxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ionic/utils-object": "2.1.5", + "@ionic/utils-terminal": "2.3.3", "debug": "^4.0.0", "signal-exit": "^3.0.3", - "slice-ansi": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "tslib": "^2.0.1", - "untildify": "^4.0.0", - "wrap-ansi": "^7.0.0" + "tree-kill": "^1.2.2", + "tslib": "^2.0.1" }, "engines": { - "node": ">=16.0.0" + "node": ">=10.3.0" } }, - "node_modules/@ionic/utils-terminal": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@ionic/utils-terminal/-/utils-terminal-2.3.5.tgz", - "integrity": "sha512-3cKScz9Jx2/Pr9ijj1OzGlBDfcmx7OMVBt4+P1uRR0SSW4cm1/y3Mo4OY3lfkuaYifMNBW8Wz6lQHbs1bihr7A==", + "node_modules/@ionic/utils-subprocess/node_modules/@ionic/utils-stream": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@ionic/utils-stream/-/utils-stream-3.1.5.tgz", + "integrity": "sha512-hkm46uHvEC05X/8PHgdJi4l4zv9VQDELZTM+Kz69odtO9zZYfnt8DkfXHJqJ+PxmtiE5mk/ehJWLnn/XAczTUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.0.0", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=10.3.0" + } + }, + "node_modules/@ionic/utils-subprocess/node_modules/@ionic/utils-terminal": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@ionic/utils-terminal/-/utils-terminal-2.3.3.tgz", + "integrity": "sha512-RnuSfNZ5fLEyX3R5mtcMY97cGD1A0NVBbarsSQ6yMMfRJ5YHU7hHVyUfvZeClbqkBC/pAqI/rYJuXKCT9YeMCQ==", + "dev": true, "license": "MIT", "dependencies": { "@types/slice-ansi": "^4.0.0", @@ -4639,73 +5344,232 @@ "wrap-ansi": "^7.0.0" }, "engines": { - "node": ">=16.0.0" + "node": ">=10.3.0" } }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "node_modules/@ionic/utils-subprocess/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" + "node": ">=8" }, "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "node_modules/@ionic/utils-subprocess/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=12" + "dependencies": { + "color-name": "~1.1.4" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "engines": { + "node": ">=7.0.0" } }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "node_modules/@ionic/utils-subprocess/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true, "license": "MIT" }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "node_modules/@ionic/utils-subprocess/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "license": "MIT", "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@ionic/utils-subprocess/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@ionic/utils-subprocess/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@ionic/utils-terminal": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@ionic/utils-terminal/-/utils-terminal-2.3.5.tgz", + "integrity": "sha512-3cKScz9Jx2/Pr9ijj1OzGlBDfcmx7OMVBt4+P1uRR0SSW4cm1/y3Mo4OY3lfkuaYifMNBW8Wz6lQHbs1bihr7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/slice-ansi": "^4.0.0", + "debug": "^4.0.0", + "signal-exit": "^3.0.3", + "slice-ansi": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "tslib": "^2.0.1", + "untildify": "^4.0.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@ionic/utils-terminal/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@ionic/utils-terminal/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@ionic/utils-terminal/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@ionic/utils-terminal/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@ionic/utils-terminal/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -4745,23 +5609,6 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/@istanbuljs/schema": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", @@ -4788,9 +5635,9 @@ } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, "license": "MIT", "engines": { @@ -4808,20 +5655,20 @@ } }, "node_modules/@jridgewell/source-map": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", - "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "dev": true, "license": "MIT" }, @@ -4836,6 +5683,63 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@jsonjoy.com/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pack": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.1.0.tgz", + "integrity": "sha512-zlQONA+msXPPwHWZMKFVS78ewFczIll5lXiVPwFPCZUsrOKdxc2AvxU1HoNBmMRhqDZUR9HkC3UOm+6pME6Xsg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/base64": "^1.1.1", + "@jsonjoy.com/util": "^1.1.2", + "hyperdyperid": "^1.2.0", + "thingies": "^1.20.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/util": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.3.0.tgz", + "integrity": "sha512-Cebt4Vk7k1xHy87kHY7KSPLT77A7Ev7IfOblyLZhtYEhrdQ6fX4EoLq3xOQ3O/DRMEh2ok5nyC180E+ABS8Wmw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, "node_modules/@kurkle/color": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz", @@ -4846,44 +5750,230 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", - "dev": true - }, - "node_modules/@ngtools/webpack": { - "version": "16.2.15", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-16.2.15.tgz", - "integrity": "sha512-rD4IHt3nS6PdIKvmoqwIadMIGKsemBSz412kD8Deetl0TiCVhD/Tn1M00dxXzMSHSFCQcOKxdZAeD53yRwTOOA==", "dev": true, - "engines": { - "node": "^16.14.0 || >=18.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "@angular/compiler-cli": "^16.0.0", - "typescript": ">=4.9.3 <5.2", - "webpack": "^5.54.0" - } + "license": "MIT" }, - "node_modules/@ngx-formly/core": { - "version": "6.3.6", - "resolved": "https://registry.npmjs.org/@ngx-formly/core/-/core-6.3.6.tgz", - "integrity": "sha512-0GDllrb9fFBTKG+yT+iQf96N3/CN+qRXIYsSX3uft12+c28qKVfMTsWTPYQsmKfGcrqtOZkMVTc+jGGD2JLZLg==", + "node_modules/@listr2/prompt-adapter-inquirer": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-2.0.13.tgz", + "integrity": "sha512-nAl6teTt7EWSjttNavAnv3uFR3w3vPP3OTYmHyPNHzKhAj2NoBDHmbS3MGpvvO8KXXPASnHjEGrrKrdKTMKPnQ==", + "dev": true, "license": "MIT", "dependencies": { - "tslib": "^2.0.0" + "@inquirer/type": "^1.3.3" + }, + "engines": { + "node": ">=18.0.0" }, "peerDependencies": { - "@angular/forms": ">=13.2.0", - "rxjs": "^6.5.3 || ^7.0.0" + "@inquirer/prompts": ">= 3 < 6" } }, - "node_modules/@ngx-formly/ionic": { - "version": "6.3.6", - "resolved": "https://registry.npmjs.org/@ngx-formly/ionic/-/ionic-6.3.6.tgz", - "integrity": "sha512-GaZav6bGGuQ3BqEVYK9DV+QsdM92jjfPmKbN9qz5s+kXH4ahjGfMqcq6Rm4SP49vvl5Am3mJZbZU4g9XrJI5tQ==", + "node_modules/@lmdb/lmdb-darwin-arm64": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-3.0.13.tgz", + "integrity": "sha512-uiKPB0Fv6WEEOZjruu9a6wnW/8jrjzlZbxXscMB8kuCJ1k6kHpcBnuvaAWcqhbI7rqX5GKziwWEdD+wi2gNLfA==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "tslib": "^2.0.0" + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@lmdb/lmdb-darwin-x64": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-3.0.13.tgz", + "integrity": "sha512-bEVIIfK5mSQoG1R19qA+fJOvCB+0wVGGnXHT3smchBVahYBdlPn2OsZZKzlHWfb1E+PhLBmYfqB5zQXFP7hJig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@lmdb/lmdb-linux-arm": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-3.0.13.tgz", + "integrity": "sha512-Yml1KlMzOnXj/tnW7yX8U78iAzTk39aILYvCPbqeewAq1kSzl+w59k/fiVkTBfvDi/oW/5YRxL+Fq+Y1Fr1r2Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-linux-arm64": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-3.0.13.tgz", + "integrity": "sha512-afbVrsMgZ9dUTNUchFpj5VkmJRxvht/u335jUJ7o23YTbNbnpmXif3VKQGCtnjSh+CZaqm6N3CPG8KO3zwyZ1Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-linux-x64": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-3.0.13.tgz", + "integrity": "sha512-vOtxu0xC0SLdQ2WRXg8Qgd8T32ak4SPqk5zjItRszrJk2BdeXqfGxBJbP7o4aOvSPSmSSv46Lr1EP4HXU8v7Kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-win32-x64": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-3.0.13.tgz", + "integrity": "sha512-UCrMJQY/gJnOl3XgbWRZZUvGGBuKy6i0YNSptgMzHBjs+QYDYR1Mt/RLTOPy4fzzves65O1EDmlL//OzEqoLlA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz", + "integrity": "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz", + "integrity": "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz", + "integrity": "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz", + "integrity": "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz", + "integrity": "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz", + "integrity": "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@ngtools/webpack": { + "version": "18.2.2", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.2.2.tgz", + "integrity": "sha512-YhADmc+lVjLt3kze07A+yLry2yzcghdclu+7D3EDfa6fG2Pk33HK3MY2I0Z0BO+Ivoq7cV7yxm+naR+Od0Y5ng==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "@angular/compiler-cli": "^18.0.0", + "typescript": ">=5.4 <5.6", + "webpack": "^5.54.0" + } + }, + "node_modules/@ngx-formly/core": { + "version": "6.3.6", + "resolved": "https://registry.npmjs.org/@ngx-formly/core/-/core-6.3.6.tgz", + "integrity": "sha512-0GDllrb9fFBTKG+yT+iQf96N3/CN+qRXIYsSX3uft12+c28qKVfMTsWTPYQsmKfGcrqtOZkMVTc+jGGD2JLZLg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/forms": ">=13.2.0", + "rxjs": "^6.5.3 || ^7.0.0" + } + }, + "node_modules/@ngx-formly/ionic": { + "version": "6.3.6", + "resolved": "https://registry.npmjs.org/@ngx-formly/ionic/-/ionic-6.3.6.tgz", + "integrity": "sha512-GaZav6bGGuQ3BqEVYK9DV+QsdM92jjfPmKbN9qz5s+kXH4ahjGfMqcq6Rm4SP49vvl5Am3mJZbZU4g9XrJI5tQ==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" }, "peerDependencies": { "@ionic/angular": "^6.0.0 || ^7.0.0", @@ -4891,9 +5981,9 @@ } }, "node_modules/@ngx-formly/schematics": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@ngx-formly/schematics/-/schematics-6.3.0.tgz", - "integrity": "sha512-XSzOvrZ1NoUhmd733bcgUFkl+26pSw8eyXChi9LwrS26nEPweR8RA/JxN+lFvIb92MWzLShLd1DY2oBz/0r0ZQ==", + "version": "6.3.6", + "resolved": "https://registry.npmjs.org/@ngx-formly/schematics/-/schematics-6.3.6.tgz", + "integrity": "sha512-QdrvdL4YrfhU9AxIXczSyzbZHWq7uuDtsIeEZ3lC0dFyvA0YyTxZRWfNyyMwCXCRXvn70WGlaU8UpeahTXsoAg==", "license": "MIT", "dependencies": { "@angular-devkit/core": "^13.0.3", @@ -4978,6 +6068,23 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/@ngx-formly/schematics/node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, "node_modules/@ngx-formly/schematics/node_modules/jsonc-parser": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", @@ -5063,10 +6170,34 @@ "tslib": "^2.0.0" } }, + "node_modules/@npmcli/agent": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz", + "integrity": "sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==", + "dev": true, + "license": "ISC", + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/agent/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, "node_modules/@npmcli/fs": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", - "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz", + "integrity": "sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==", "dev": true, "license": "ISC", "dependencies": { @@ -5077,55 +6208,63 @@ } }, "node_modules/@npmcli/git": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-4.1.0.tgz", - "integrity": "sha512-9hwoB3gStVfa0N31ymBmrX+GuDGdVA/QWShZVqE0HK2Af+7QGGrCTbZia/SW0ImUTjTne7SP91qxDmtXvDHRPQ==", + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.8.tgz", + "integrity": "sha512-liASfw5cqhjNW9UFd+ruwwdEf/lbOAQjLL2XY2dFW/bkJheXDYZgOyul/4gVvEV4BWkTXjYGmDqMw9uegdbJNQ==", "dev": true, "license": "ISC", "dependencies": { - "@npmcli/promise-spawn": "^6.0.0", - "lru-cache": "^7.4.4", - "npm-pick-manifest": "^8.0.0", - "proc-log": "^3.0.0", + "@npmcli/promise-spawn": "^7.0.0", + "ini": "^4.1.3", + "lru-cache": "^10.0.1", + "npm-pick-manifest": "^9.0.0", + "proc-log": "^4.0.0", "promise-inflight": "^1.0.1", "promise-retry": "^2.0.1", "semver": "^7.3.5", - "which": "^3.0.0" + "which": "^4.0.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@npmcli/git/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "node_modules/@npmcli/git/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "dev": true, "license": "ISC", "engines": { - "node": ">=12" + "node": ">=16" } }, + "node_modules/@npmcli/git/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, "node_modules/@npmcli/git/node_modules/which": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", - "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", "dev": true, "license": "ISC", "dependencies": { - "isexe": "^2.0.0" + "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^16.13.0 || >=18.0.0" } }, "node_modules/@npmcli/installed-package-contents": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz", - "integrity": "sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.1.0.tgz", + "integrity": "sha512-c8UuGLeZpm69BryRykLuKRyKFZYJsZSCT4aVY5ds4omyZqJ172ApzgfKJ5eV/r3HgLdUYgFVe54KSFVjKoe27w==", "dev": true, "license": "ISC", "dependencies": { @@ -5133,26 +6272,12 @@ "npm-normalize-package-bin": "^3.0.0" }, "bin": { - "installed-package-contents": "lib/index.js" + "installed-package-contents": "bin/index.js" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/@npmcli/move-file": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", - "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/@npmcli/node-gyp": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", @@ -5163,303 +6288,423 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/@npmcli/promise-spawn": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-6.0.2.tgz", - "integrity": "sha512-gGq0NJkIGSwdbUt4yhdF8ZrmkGKVz9vAdVzpOfnom+V8PLSmSOVhZwbNvZZS1EYcJN5hzzKBxmmVVAInM6HQLg==", + "node_modules/@npmcli/package-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-5.2.0.tgz", + "integrity": "sha512-qe/kiqqkW0AGtvBjL8TJKZk/eBBSpnJkUWvHdQ9jM2lKHXRYYJuyNpJPlJw3c8QjC2ow6NZYiLExhUaeJelbxQ==", "dev": true, "license": "ISC", "dependencies": { - "which": "^3.0.0" + "@npmcli/git": "^5.0.0", + "glob": "^10.2.2", + "hosted-git-info": "^7.0.0", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "proc-log": "^4.0.0", + "semver": "^7.5.3" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@npmcli/promise-spawn/node_modules/which": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", - "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", + "node_modules/@npmcli/package-json/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, "license": "ISC", "dependencies": { - "isexe": "^2.0.0" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, "bin": { - "node-which": "bin/which.js" + "glob": "dist/esm/bin.mjs" }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@npmcli/run-script": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-6.0.2.tgz", - "integrity": "sha512-NCcr1uQo1k5U+SYlnIrbAh3cxy+OQT1VtqiAbxdymSlptbzBb62AjH2xXgjNCoP073hoa1CfCAcwoZ8k96C4nA==", + "node_modules/@npmcli/package-json/node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", "dev": true, "license": "ISC", "dependencies": { - "@npmcli/node-gyp": "^3.0.0", - "@npmcli/promise-spawn": "^6.0.0", - "node-gyp": "^9.0.0", - "read-package-json-fast": "^3.0.0", - "which": "^3.0.0" + "lru-cache": "^10.0.1" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@npmcli/run-script/node_modules/which": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", - "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", + "node_modules/@npmcli/package-json/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true, - "license": "ISC", + "license": "ISC" + }, + "node_modules/@npmcli/package-json/node_modules/normalize-package-data": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", + "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", + "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/which.js" + "hosted-git-info": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@nrwl/devkit": { - "version": "16.5.1", - "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-16.5.1.tgz", - "integrity": "sha512-NB+DE/+AFJ7lKH/WBFyatJEhcZGj25F24ncDkwjZ6MzEiSOGOJS0LaV/R+VUsmS5EHTPXYOpn3zHWWAcJhyOmA==", - "dev": true, - "license": "MIT", + "node_modules/@npmcli/promise-spawn": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.2.tgz", + "integrity": "sha512-xhfYPXoV5Dy4UkY0D+v2KkwvnDfiA/8Mt3sWCGI/hM03NsYIH8ZaG6QzS9x7pje5vHZBZJ2v6VRFVTWACnqcmQ==", + "dev": true, + "license": "ISC", "dependencies": { - "@nx/devkit": "16.5.1" + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@nrwl/tao": { - "version": "16.5.1", - "resolved": "https://registry.npmjs.org/@nrwl/tao/-/tao-16.5.1.tgz", - "integrity": "sha512-x+gi/fKdM6uQNIti9exFlm3V5LBP3Y8vOEziO42HdOigyrXa0S0HD2WMpccmp6PclYKhwEDUjKJ39xh5sdh4Ig==", + "node_modules/@npmcli/promise-spawn/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "dev": true, - "license": "MIT", + "license": "ISC", + "engines": { + "node": ">=16" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "license": "ISC", "dependencies": { - "nx": "16.5.1" + "isexe": "^3.1.1" }, "bin": { - "tao": "index.js" + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" } }, - "node_modules/@nx/devkit": { - "version": "16.5.1", - "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-16.5.1.tgz", - "integrity": "sha512-T1acZrVVmJw/sJ4PIGidCBYBiBqlg/jT9e8nIGXLSDS20xcLvfo4zBQf8UZLrmHglnwwpDpOWuVJCp2rYA5aDg==", + "node_modules/@npmcli/redact": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-2.0.1.tgz", + "integrity": "sha512-YgsR5jCQZhVmTJvjduTOIHph0L73pK8xwMVaDY0PatySqVM9AZj93jpoXYSJqfHFxFkN9dmqTw6OiqExsS3LPw==", "dev": true, - "license": "MIT", - "dependencies": { - "@nrwl/devkit": "16.5.1", - "ejs": "^3.1.7", - "ignore": "^5.0.4", - "semver": "7.5.3", - "tmp": "~0.2.1", - "tslib": "^2.3.0" - }, - "peerDependencies": { - "nx": ">= 15 <= 17" + "license": "ISC", + "engines": { + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@nx/devkit/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/@npmcli/run-script": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-8.1.0.tgz", + "integrity": "sha512-y7efHHwghQfk28G2z3tlZ67pLG0XdfYbcVG26r7YIXALRsrVQcTq4/tdenSmdOrEsNahIYA/eh8aEVROWGFUDg==", "dev": true, "license": "ISC", "dependencies": { - "yallist": "^4.0.0" + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^5.0.0", + "@npmcli/promise-spawn": "^7.0.0", + "node-gyp": "^10.0.0", + "proc-log": "^4.0.0", + "which": "^4.0.0" }, "engines": { - "node": ">=10" + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16" } }, - "node_modules/@nx/devkit/node_modules/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "node_modules/@npmcli/run-script/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", "dev": true, "license": "ISC", "dependencies": { - "lru-cache": "^6.0.0" + "isexe": "^3.1.1" }, "bin": { - "semver": "bin/semver.js" + "node-which": "bin/which.js" }, "engines": { - "node": ">=10" + "node": "^16.13.0 || >=18.0.0" } }, - "node_modules/@nx/devkit/node_modules/tmp": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", - "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, "license": "MIT", + "optional": true, "engines": { - "node": ">=14.14" + "node": ">=14" } }, - "node_modules/@nx/devkit/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", "dev": true, - "license": "ISC" + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@prettier/plugin-xml": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@prettier/plugin-xml/-/plugin-xml-2.2.0.tgz", + "integrity": "sha512-UWRmygBsyj4bVXvDiqSccwT1kmsorcwQwaIy30yVh8T+Gspx4OlC0shX1y+ZuwXZvgnafmpRYKks0bAu9urJew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xml-tools/parser": "^1.0.11", + "prettier": ">=2.4.0" + } }, - "node_modules/@nx/nx-darwin-arm64": { - "version": "16.5.1", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-16.5.1.tgz", - "integrity": "sha512-q98TFI4B/9N9PmKUr1jcbtD4yAFs1HfYd9jUXXTQOlfO9SbDjnrYJgZ4Fp9rMNfrBhgIQ4x1qx0AukZccKmH9Q==", + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.2.tgz", + "integrity": "sha512-fSuPrt0ZO8uXeS+xP3b+yYTCBUd05MoSp2N/MFOgjhhUhMmchXlpTQrTpI8T+YAwAQuK7MafsCOxW7VrPMrJcg==", "cpu": [ - "arm64" + "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ - "darwin" + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.2.tgz", + "integrity": "sha512-xGU5ZQmPlsjQS6tzTTGwMsnKUtu0WVbl0hYpTPauvbRAnmIvpInhJtgjj3mcuJpEiuUw4v1s4BimkdfDWlh7gA==", + "cpu": [ + "arm64" ], - "engines": { - "node": ">= 10" - } + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] }, - "node_modules/@nx/nx-darwin-x64": { - "version": "16.5.1", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-16.5.1.tgz", - "integrity": "sha512-j9HmL1l8k7EVJ3eOM5y8COF93gqrydpxCDoz23ZEtsY+JHY77VAiRQsmqBgEx9GGA2dXi9VEdS67B0+1vKariw==", + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.2.tgz", + "integrity": "sha512-99AhQ3/ZMxU7jw34Sq8brzXqWH/bMnf7ZVhvLk9QU2cOepbQSVTns6qoErJmSiAvU3InRqC2RRZ5ovh1KN0d0Q==", "cpu": [ - "x64" + "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" - ], - "engines": { - "node": ">= 10" - } + ] }, - "node_modules/@nx/nx-freebsd-x64": { - "version": "16.5.1", - "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-16.5.1.tgz", - "integrity": "sha512-CXSPT01aVS869tvCCF2tZ7LnCa8l41wJ3mTVtWBkjmRde68E5Up093hklRMyXb3kfiDYlfIKWGwrV4r0eH6x1A==", + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.2.tgz", + "integrity": "sha512-ZbRaUvw2iN/y37x6dY50D8m2BnDbBjlnMPotDi/qITMJ4sIxNY33HArjikDyakhSv0+ybdUxhWxE6kTI4oX26w==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10" - } + "darwin" + ] }, - "node_modules/@nx/nx-linux-arm-gnueabihf": { - "version": "16.5.1", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-16.5.1.tgz", - "integrity": "sha512-BhrumqJSZCWFfLFUKl4CAUwR0Y0G2H5EfFVGKivVecEQbb+INAek1aa6c89evg2/OvetQYsJ+51QknskwqvLsA==", + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.2.tgz", + "integrity": "sha512-ztRJJMiE8nnU1YFcdbd9BcH6bGWG1z+jP+IPW2oDUAPxPjo9dverIOyXz76m6IPA6udEL12reYeLojzW2cYL7w==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.2.tgz", + "integrity": "sha512-flOcGHDZajGKYpLV0JNc0VFH361M7rnV1ee+NTeC/BQQ1/0pllYcFmxpagltANYt8FYf9+kL6RSk80Ziwyhr7w==", + "cpu": [ + "arm" ], - "engines": { - "node": ">= 10" - } + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@nx/nx-linux-arm64-gnu": { - "version": "16.5.1", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-16.5.1.tgz", - "integrity": "sha512-x7MsSG0W+X43WVv7JhiSq2eKvH2suNKdlUHEG09Yt0vm3z0bhtym1UCMUg3IUAK7jy9hhLeDaFVFkC6zo+H/XQ==", + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.2.tgz", + "integrity": "sha512-69CF19Kp3TdMopyteO/LJbWufOzqqXzkrv4L2sP8kfMaAQ6iwky7NoXTp7bD6/irKgknDKM0P9E/1l5XxVQAhw==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">= 10" - } + ] }, - "node_modules/@nx/nx-linux-arm64-musl": { - "version": "16.5.1", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-16.5.1.tgz", - "integrity": "sha512-J+/v/mFjOm74I0PNtH5Ka+fDd+/dWbKhpcZ2R1/6b9agzZk+Ff/SrwJcSYFXXWKbPX+uQ4RcJoytT06Zs3s0ow==", + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.2.tgz", + "integrity": "sha512-48pD/fJkTiHAZTnZwR0VzHrao70/4MlzJrq0ZsILjLW/Ab/1XlVUStYyGt7tdyIiVSlGZbnliqmult/QGA2O2w==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.2.tgz", + "integrity": "sha512-cZdyuInj0ofc7mAQpKcPR2a2iu4YM4FQfuUzCVA2u4HI95lCwzjoPtdWjdpDKyHxI0UO82bLDoOaLfpZ/wviyQ==", + "cpu": [ + "ppc64" ], - "engines": { - "node": ">= 10" - } + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@nx/nx-linux-x64-gnu": { - "version": "16.5.1", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-16.5.1.tgz", - "integrity": "sha512-igooWJ5YxQ94Zft7IqgL+Lw0qHaY15Btw4gfK756g/YTYLZEt4tTvR1y6RnK/wdpE3sa68bFTLVBNCGTyiTiDQ==", + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.2.tgz", + "integrity": "sha512-RL56JMT6NwQ0lXIQmMIWr1SW28z4E4pOhRRNqwWZeXpRlykRIlEpSWdsgNWJbYBEWD84eocjSGDu/XxbYeCmwg==", "cpu": [ - "x64" + "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.2.tgz", + "integrity": "sha512-PMxkrWS9z38bCr3rWvDFVGD6sFeZJw4iQlhrup7ReGmfn7Oukrr/zweLhYX6v2/8J6Cep9IEA/SmjXjCmSbrMQ==", + "cpu": [ + "s390x" ], - "engines": { - "node": ">= 10" - } + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@nx/nx-linux-x64-musl": { - "version": "16.5.1", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-16.5.1.tgz", - "integrity": "sha512-zF/exnPqFYbrLAduGhTmZ7zNEyADid2bzNQiIjJkh8Y6NpDwrQIwVIyvIxqynsjMrIs51kBH+8TUjKjj2Jgf5A==", + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.2.tgz", + "integrity": "sha512-B90tYAUoLhU22olrafY3JQCFLnT3NglazdwkHyxNDYF/zAxJt5fJUB/yBoWFoIQ7SQj+KLe3iL4BhOMa9fzgpw==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.2.tgz", + "integrity": "sha512-7twFizNXudESmC9oneLGIUmoHiiLppz/Xs5uJQ4ShvE6234K0VB1/aJYU3f/4g7PhssLGKBVCC37uRkkOi8wjg==", + "cpu": [ + "x64" ], - "engines": { - "node": ">= 10" - } + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@nx/nx-win32-arm64-msvc": { - "version": "16.5.1", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-16.5.1.tgz", - "integrity": "sha512-qtqiLS9Y9TYyAbbpq58kRoOroko4ZXg5oWVqIWFHoxc5bGPweQSJCROEqd1AOl2ZDC6BxfuVHfhDDop1kK05WA==", + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.2.tgz", + "integrity": "sha512-9rRero0E7qTeYf6+rFh3AErTNU1VCQg2mn7CQcI44vNUWM9Ze7MSRS/9RFuSsox+vstRt97+x3sOhEey024FRQ==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.2.tgz", + "integrity": "sha512-5rA4vjlqgrpbFVVHX3qkrCo/fZTj1q0Xxpg+Z7yIo3J2AilW7t2+n6Q8Jrx+4MrYpAnjttTYF8rr7bP46BPzRw==", + "cpu": [ + "ia32" ], - "engines": { - "node": ">= 10" - } + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@nx/nx-win32-x64-msvc": { - "version": "16.5.1", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-16.5.1.tgz", - "integrity": "sha512-kUJBLakK7iyA9WfsGGQBVennA4jwf5XIgm0lu35oMOphtZIluvzItMt0EYBmylEROpmpEIhHq0P6J9FA+WH0Rg==", + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.2.tgz", + "integrity": "sha512-6UUxd0+SKomjdzuAcp+HAmxw1FlGBnl1v2yEPSabtx4lBfdXHDVsW7+lQkgz9cNFJGY3AWR7+V8P5BqkD9L9nA==", "cpu": [ "x64" ], @@ -5468,222 +6713,206 @@ "optional": true, "os": [ "win32" - ], + ] + }, + "node_modules/@schematics/angular": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-18.1.0.tgz", + "integrity": "sha512-k9Dy6JD7hqvCzDqnMjDm7J8H/P6m5mLuX2yEgQWKRAJ/YMINtBQAaKA1T9qXk97kEX6RNLpHMuDIsrIfK/H31Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "18.1.0", + "@angular-devkit/schematics": "18.1.0", + "jsonc-parser": "3.3.1" + }, "engines": { - "node": ">= 10" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" } }, - "node_modules/@parcel/watcher": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.0.4.tgz", - "integrity": "sha512-cTDi+FUDBIUOBKEtj+nhiJ71AZVlkAsQFuGQTun5tV9mwQBQgZvhCzG+URPQc8myeN32yRVZEfVAPCs1RW+Jvg==", + "node_modules/@schematics/angular/node_modules/@angular-devkit/core": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.1.0.tgz", + "integrity": "sha512-6eXQDzHZCbpSMLv9Ohl+1QyLVDmGEXpuuHz3y64LfUTP0aEiBaxk96FjLXIxzJ4f2pbbW2XHzc+yuboGToRA0w==", "dev": true, - "hasInstallScript": true, "license": "MIT", "dependencies": { - "node-addon-api": "^3.2.1", - "node-gyp-build": "^4.3.0" + "ajv": "8.16.0", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.2", + "rxjs": "7.8.1", + "source-map": "0.7.4" }, "engines": { - "node": ">= 10.0.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } } }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "node_modules/@schematics/angular/node_modules/@angular-devkit/schematics": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.1.0.tgz", + "integrity": "sha512-BjrYutLfYFiPOSEcLBWCj3ENkwDn8gMfBSJesaBz7OrZBZGK5j0dVgBLIsGTP96TKo4o4vszJQOvS4AtV6xMGg==", "dev": true, "license": "MIT", - "optional": true, + "dependencies": { + "@angular-devkit/core": "18.1.0", + "jsonc-parser": "3.3.1", + "magic-string": "0.30.10", + "ora": "5.4.1", + "rxjs": "7.8.1" + }, "engines": { - "node": ">=14" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" } }, - "node_modules/@prettier/plugin-xml": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@prettier/plugin-xml/-/plugin-xml-2.2.0.tgz", - "integrity": "sha512-UWRmygBsyj4bVXvDiqSccwT1kmsorcwQwaIy30yVh8T+Gspx4OlC0shX1y+ZuwXZvgnafmpRYKks0bAu9urJew==", + "node_modules/@schematics/angular/node_modules/ajv": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", "dev": true, "license": "MIT", "dependencies": { - "@xml-tools/parser": "^1.0.11", - "prettier": ">=2.4.0" + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@schematics/angular": { - "version": "16.2.13", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-16.2.13.tgz", - "integrity": "sha512-SFE9e7X/CEtzwGEqHUqXriAm4J4uTjcfoRXslc7BuqOKABM8RXPphGQsVG4xOt3n25kXXGkFO2dvDRHuLTP1fQ==", + "node_modules/@schematics/angular/node_modules/magic-string": { + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "16.2.13", - "@angular-devkit/schematics": "16.2.13", - "jsonc-parser": "3.2.0" - }, - "engines": { - "node": "^16.14.0 || >=18.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" + "@jridgewell/sourcemap-codec": "^1.4.15" } }, - "node_modules/@schematics/angular/node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "node_modules/@schematics/angular/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, - "license": "MIT" + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } }, "node_modules/@sigstore/bundle": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-1.1.0.tgz", - "integrity": "sha512-PFutXEy0SmQxYI4texPw3dd2KewuNqv7OuK1ZFtY2fM754yhvG2KdgwIhRnoEE2uHdtdGNQ8s0lb94dW9sELog==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.3.2.tgz", + "integrity": "sha512-wueKWDk70QixNLB363yHc2D2ItTgYiMTdPwK8D9dKQMR3ZQ0c35IxP5xnwQ8cNLoCgCRcHf14kE+CLIvNX1zmA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@sigstore/protobuf-specs": "^0.2.0" + "@sigstore/protobuf-specs": "^0.3.2" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@sigstore/protobuf-specs": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.2.1.tgz", - "integrity": "sha512-XTWVxnWJu+c1oCshMLwnKvz8ZQJJDVOlciMfgpJBQbThVjKTCG8dwyhgLngBD2KN0ap9F/gOV8rFDEx8uh7R2A==", + "node_modules/@sigstore/core": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-1.1.0.tgz", + "integrity": "sha512-JzBqdVIyqm2FRQCulY6nbQzMpJJpSiJ8XXWMhtOX9eKgaXXpfNOF53lzQEjIydlStnd/eFtuC1dW4VYdD93oRg==", "dev": true, "license": "Apache-2.0", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@sigstore/sign": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-1.0.0.tgz", - "integrity": "sha512-INxFVNQteLtcfGmcoldzV6Je0sbbfh9I16DM4yJPw3j5+TFP8X6uIiA18mvpEa9yyeycAKgPmOA3X9hVdVTPUA==", + "node_modules/@sigstore/protobuf-specs": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.3.2.tgz", + "integrity": "sha512-c6B0ehIWxMI8wiS/bj6rHMPqeFvngFV7cDU/MY+B16P9Z3Mp9k8L93eYZ7BYzSickzuqAQqAq0V956b3Ju6mLw==", "dev": true, "license": "Apache-2.0", - "dependencies": { - "@sigstore/bundle": "^1.1.0", - "@sigstore/protobuf-specs": "^0.2.0", - "make-fetch-happen": "^11.0.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@sigstore/sign/node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "dev": true, - "license": "MIT", "engines": { - "node": ">= 10" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@sigstore/sign/node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "node_modules/@sigstore/sign": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.3.2.tgz", + "integrity": "sha512-5Vz5dPVuunIIvC5vBb0APwo7qKA4G9yM48kPWJT+OEERs40md5GoUR1yedwpekWZ4m0Hhw44m6zU+ObsON+iDA==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" + "@sigstore/bundle": "^2.3.2", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.2", + "make-fetch-happen": "^13.0.1", + "proc-log": "^4.2.0", + "promise-retry": "^2.0.1" }, "engines": { - "node": ">= 6" - } - }, - "node_modules/@sigstore/sign/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@sigstore/sign/node_modules/make-fetch-happen": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", - "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", + "node_modules/@sigstore/tuf": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.3.4.tgz", + "integrity": "sha512-44vtsveTPUpqhm9NCrbU8CWLe3Vck2HO1PNLw7RIajbB7xhtn5RBPm1VNSCMwqGYHhDsBJG8gDF0q4lgydsJvw==", "dev": true, - "license": "ISC", + "license": "Apache-2.0", "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^17.0.0", - "http-cache-semantics": "^4.1.1", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^5.0.0", - "minipass-fetch": "^3.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^10.0.0" + "@sigstore/protobuf-specs": "^0.3.2", + "tuf-js": "^2.2.1" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@sigstore/sign/node_modules/minipass-fetch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", - "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "node_modules/@sigstore/verify": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-1.2.1.tgz", + "integrity": "sha512-8iKx79/F73DKbGfRf7+t4dqrc0bRr0thdPrxAtCKWRm/F0tG71i6O1rvlnScncJLLBZHn3h8M3c1BSUAb9yu8g==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "minipass": "^7.0.3", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" + "@sigstore/bundle": "^2.3.2", + "@sigstore/core": "^1.1.0", + "@sigstore/protobuf-specs": "^0.3.2" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@sigstore/sign/node_modules/minipass-fetch/node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", "dev": true, - "license": "ISC", + "license": "MIT", "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/@sigstore/tuf": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-1.0.3.tgz", - "integrity": "sha512-2bRovzs0nJZFlCN3rXirE4gwxCn97JNjMmwpecqlbgV9WcxX7WRuIrgzx/X7Ib7MYRbyUTpBYE0s2x6AmZXnlg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/protobuf-specs": "^0.2.0", - "tuf-js": "^1.1.7" + "node": ">=18" }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@socket.io/component-emitter": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", - "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", "dev": true, "license": "MIT" }, @@ -5705,6 +6934,7 @@ "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.7.2.tgz", "integrity": "sha512-3DVLU5HEuk2pQoBmXJlzvrxbKNpu2mJ0SRqz5O/CJjyNCr12ZiPcYMEtuArTyPOk5i7bsAU44nywh1rGfe3gKQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/eslint": "^9.6.1", "@typescript-eslint/utils": "^8.3.0", @@ -5720,367 +6950,139 @@ "eslint": ">=8.40.0" } }, - "node_modules/@stylistic/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.3.0.tgz", - "integrity": "sha512-mz2X8WcN2nVu5Hodku+IR8GgCOl4C0G/Z1ruaWN4dgec64kDBabuXyPAr+/RgJtumv8EEkqIzf3X2U5DUKB2eg==", + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@trapezedev/gradle-parse": { + "version": "7.0.10", + "resolved": "https://registry.npmjs.org/@trapezedev/gradle-parse/-/gradle-parse-7.0.10.tgz", + "integrity": "sha512-k822Is3jGroqOTKF0gAFm80LmhFJWBAyZvNtyuXq6uQUzDDe2fj/gHwixP6VFzlpaWKLP7IuR609Xv8gwJCXyg==", + "dev": true, + "license": "SEE LICENSE" + }, + "node_modules/@trapezedev/project": { + "version": "7.0.10", + "resolved": "https://registry.npmjs.org/@trapezedev/project/-/project-7.0.10.tgz", + "integrity": "sha512-UjwsStjhHq/+D1bWREmFDoyKql+qFIgJX93zQLg7R6CyWZUdtlGP2hU3l7tsVRtjJBVXpVu5mj8tdwJJoABO3A==", "dev": true, + "license": "SEE LICENSE", "dependencies": { - "@typescript-eslint/types": "8.3.0", - "@typescript-eslint/visitor-keys": "8.3.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "@ionic/utils-fs": "^3.1.5", + "@ionic/utils-subprocess": "^2.1.8", + "@prettier/plugin-xml": "^2.2.0", + "@trapezedev/gradle-parse": "7.0.10", + "@xmldom/xmldom": "^0.7.5", + "conventional-changelog": "^3.1.4", + "cross-fetch": "^3.1.5", + "cross-spawn": "^7.0.3", + "diff": "^5.1.0", + "env-paths": "^3.0.0", + "gradle-to-js": "^2.0.0", + "ini": "^2.0.0", + "kleur": "^4.1.5", + "lodash": "^4.17.21", + "mergexml": "^1.2.3", + "npm-watch": "^0.9.0", + "plist": "^3.0.4", + "prettier": "^2.7.1", + "prompts": "^2.4.2", + "replace": "^1.1.0", + "tempy": "^1.0.1", + "tmp": "^0.2.1", + "ts-node": "^10.2.1", + "xcode": "^3.0.1", + "xml-js": "^1.6.11", + "xpath": "^0.0.32", + "yargs": "^17.2.1" } }, - "node_modules/@stylistic/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.3.0.tgz", - "integrity": "sha512-y6sSEeK+facMaAyixM36dQ5NVXTnKWunfD1Ft4xraYqxP0lC0POJmIaL/mw72CUMqjY9qfyVfXafMeaUj0noWw==", + "node_modules/@trapezedev/project/node_modules/diff": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", "dev": true, + "license": "BSD-3-Clause", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=0.3.1" } }, - "node_modules/@stylistic/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.3.0.tgz", - "integrity": "sha512-Mq7FTHl0R36EmWlCJWojIC1qn/ZWo2YiWYc1XVtasJ7FIgjo0MVv9rZWXEE7IK2CGrtwe1dVOxWwqXUdNgfRCA==", + "node_modules/@trapezedev/project/node_modules/env-paths": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", + "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==", "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.3.0", - "@typescript-eslint/visitor-keys": "8.3.0", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, + "license": "MIT", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@stylistic/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.3.0.tgz", - "integrity": "sha512-F77WwqxIi/qGkIGOGXNBLV7nykwfjLsdauRB/DOFPdv6LTF3BHHkBpq81/b5iMPSF055oO2BiivDJV4ChvNtXA==", + "node_modules/@trapezedev/project/node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.3.0", - "@typescript-eslint/types": "8.3.0", - "@typescript-eslint/typescript-estree": "8.3.0" - }, + "license": "ISC", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" + "node": ">=10" } }, - "node_modules/@stylistic/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.3.0.tgz", - "integrity": "sha512-RmZwrTbQ9QveF15m/Cl28n0LXD6ea2CjkhH5rQ55ewz3H24w+AMCJHPVYaZ8/0HoG8Z3cLLFFycRXxeO2tz9FA==", + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.3.0", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } + "license": "MIT" }, - "node_modules/@stylistic/eslint-plugin/node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tufjs/canonical-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", + "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==", "dev": true, + "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@stylistic/eslint-plugin/node_modules/brace-expansion": { + "node_modules/@tufjs/models": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-2.0.1.tgz", + "integrity": "sha512-92F7/SFyufn4DXsha9+QfKnN03JGqtMFMXgSHbZOo8JG59WkTni7UzAouNQDf7AuP9OAMxVOPQcqG3sB7w+kkg==", "dev": true, + "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@stylistic/eslint-plugin/node_modules/eslint-visitor-keys": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", - "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@stylistic/eslint-plugin/node_modules/espree": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", - "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", - "dev": true, - "dependencies": { - "acorn": "^8.12.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@stylistic/eslint-plugin/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/@stylistic/eslint-plugin/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@stylistic/eslint-plugin/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/@tootallnate/quickjs-emscripten": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", - "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", - "license": "MIT" - }, - "node_modules/@trapezedev/gradle-parse": { - "version": "7.0.10", - "resolved": "https://registry.npmjs.org/@trapezedev/gradle-parse/-/gradle-parse-7.0.10.tgz", - "integrity": "sha512-k822Is3jGroqOTKF0gAFm80LmhFJWBAyZvNtyuXq6uQUzDDe2fj/gHwixP6VFzlpaWKLP7IuR609Xv8gwJCXyg==", - "dev": true, - "license": "SEE LICENSE" - }, - "node_modules/@trapezedev/project": { - "version": "7.0.10", - "resolved": "https://registry.npmjs.org/@trapezedev/project/-/project-7.0.10.tgz", - "integrity": "sha512-UjwsStjhHq/+D1bWREmFDoyKql+qFIgJX93zQLg7R6CyWZUdtlGP2hU3l7tsVRtjJBVXpVu5mj8tdwJJoABO3A==", - "dev": true, - "license": "SEE LICENSE", - "dependencies": { - "@ionic/utils-fs": "^3.1.5", - "@ionic/utils-subprocess": "^2.1.8", - "@prettier/plugin-xml": "^2.2.0", - "@trapezedev/gradle-parse": "7.0.10", - "@xmldom/xmldom": "^0.7.5", - "conventional-changelog": "^3.1.4", - "cross-fetch": "^3.1.5", - "cross-spawn": "^7.0.3", - "diff": "^5.1.0", - "env-paths": "^3.0.0", - "gradle-to-js": "^2.0.0", - "ini": "^2.0.0", - "kleur": "^4.1.5", - "lodash": "^4.17.21", - "mergexml": "^1.2.3", - "npm-watch": "^0.9.0", - "plist": "^3.0.4", - "prettier": "^2.7.1", - "prompts": "^2.4.2", - "replace": "^1.1.0", - "tempy": "^1.0.1", - "tmp": "^0.2.1", - "ts-node": "^10.2.1", - "xcode": "^3.0.1", - "xml-js": "^1.6.11", - "xpath": "^0.0.32", - "yargs": "^17.2.1" - } - }, - "node_modules/@trapezedev/project/node_modules/diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", - "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/@trapezedev/project/node_modules/env-paths": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", - "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@trapezedev/project/node_modules/ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/@trapezedev/project/node_modules/tmp": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", - "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.14" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tufjs/canonical-json": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-1.0.0.tgz", - "integrity": "sha512-QTnf++uxunWvG2z3UFNzAoQPHxnSXOwtaI3iJ+AohhV+5vONuArPjJE7aPXPVXfXJsqrVbZBu9b81AJoSd09IQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@tufjs/models": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-1.0.4.tgz", - "integrity": "sha512-qaGV9ltJP0EO25YfFUPhxRVK0evXFIAGicsVXuRim4Ed9cjPxYhNnNJ49SFmbeLgtxpslIkX317IgpfcHPVj/A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@tufjs/canonical-json": "1.0.0", - "minimatch": "^9.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@tufjs/models/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@tufjs/models/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^9.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" } }, "node_modules/@types/body-parser": { @@ -6088,6 +7090,7 @@ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", "dev": true, + "license": "MIT", "dependencies": { "@types/connect": "*", "@types/node": "*" @@ -6098,6 +7101,7 @@ "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -6107,6 +7111,7 @@ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -6116,6 +7121,7 @@ "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", "dev": true, + "license": "MIT", "dependencies": { "@types/express-serve-static-core": "*", "@types/node": "*" @@ -6149,6 +7155,7 @@ "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", "dev": true, + "license": "MIT", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -6166,6 +7173,7 @@ "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", @@ -6178,6 +7186,7 @@ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -6189,6 +7198,7 @@ "version": "8.1.5", "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.5.tgz", "integrity": "sha512-0dzKcwO+S8s2kuF5Z9oUWatQJj5Uq/iqphEtE3GQJVRRYm/tD1LglU2UnXi2A8jLq5umkGouOXOR9y0n613ZwQ==", + "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" @@ -6198,13 +7208,15 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/http-proxy": { "version": "1.17.15", "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.15.tgz", "integrity": "sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -6244,7 +7256,8 @@ "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/minimist": { "version": "1.2.5", @@ -6253,13 +7266,24 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/mute-stream": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@types/mute-stream/-/mute-stream-0.0.4.tgz", + "integrity": "sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/node": { - "version": "20.12.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", - "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", + "version": "20.16.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.1.tgz", + "integrity": "sha512-zJDo7wEadFtSyNz5QITDfRcrhqDvQI1xQNQ0VoizPjM/dVAODqqIUWbJPkvsxmTI0MYRGRikcdjMPhOssnPejQ==", + "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.19.2" } }, "node_modules/@types/node-forge": { @@ -6267,6 +7291,7 @@ "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -6289,19 +7314,22 @@ "version": "6.9.15", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/range-parser": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", - "dev": true + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", + "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", + "dev": true, + "license": "MIT" }, "node_modules/@types/selenium-webdriver": { "version": "3.0.26", @@ -6310,18 +7338,12 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/semver": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/send": { "version": "0.17.4", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", "dev": true, + "license": "MIT", "dependencies": { "@types/mime": "^1", "@types/node": "*" @@ -6332,6 +7354,7 @@ "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", "dev": true, + "license": "MIT", "dependencies": { "@types/express": "*" } @@ -6341,6 +7364,7 @@ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", "dev": true, + "license": "MIT", "dependencies": { "@types/http-errors": "*", "@types/node": "*", @@ -6351,6 +7375,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/slice-ansi/-/slice-ansi-4.0.0.tgz", "integrity": "sha512-+OpjSaq85gvlZAYINyzKpLeiFkSC4EsC6IIiT6v6TLSU5k5U83fHGj9Lel8oKEXM0HqgrMVCjXPDPVICtxF7EQ==", + "dev": true, "license": "MIT" }, "node_modules/@types/sockjs": { @@ -6358,6 +7383,7 @@ "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -6369,72 +7395,50 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/wrap-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz", + "integrity": "sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/ws": { "version": "8.5.12", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", "integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", - "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", + "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/type-utils": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/type-utils": "7.18.0", + "@typescript-eslint/utils": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", "graphemer": "^1.4.0", - "ignore": "^5.2.4", + "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", - "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -6443,53 +7447,50 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", - "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", + "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "semver": "^7.5.4" + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", - "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", + "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", "debug": "^4.3.4" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -6498,17 +7499,17 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", - "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", + "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0" + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -6516,68 +7517,26 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", - "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", + "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "5.62.0", - "@typescript-eslint/utils": "5.62.0", + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/utils": "7.18.0", "debug": "^4.3.4", - "tsutils": "^3.21.0" + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", - "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", - "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -6585,63 +7544,37 @@ } } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", - "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", + "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "5.62.0", - "eslint-visitor-keys": "^3.3.0" + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" + "peerDependencies": { + "eslint": "^8.56.0" } }, "node_modules/@typescript-eslint/types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", - "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", "dev": true, "license": "MIT", "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -6649,23 +7582,23 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", - "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", + "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -6677,102 +7610,41 @@ } } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/@typescript-eslint/utils": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", - "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.3.0.tgz", + "integrity": "sha512-F77WwqxIi/qGkIGOGXNBLV7nykwfjLsdauRB/DOFPdv6LTF3BHHkBpq81/b5iMPSF055oO2BiivDJV4ChvNtXA==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.3.0", + "@typescript-eslint/types": "8.3.0", + "@typescript-eslint/typescript-estree": "8.3.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^8.57.0 || ^9.0.0" } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", - "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.3.0.tgz", + "integrity": "sha512-mz2X8WcN2nVu5Hodku+IR8GgCOl4C0G/Z1ruaWN4dgec64kDBabuXyPAr+/RgJtumv8EEkqIzf3X2U5DUKB2eg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0" + "@typescript-eslint/types": "8.3.0", + "@typescript-eslint/visitor-keys": "8.3.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -6780,13 +7652,13 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", - "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.3.0.tgz", + "integrity": "sha512-y6sSEeK+facMaAyixM36dQ5NVXTnKWunfD1Ft4xraYqxP0lC0POJmIaL/mw72CUMqjY9qfyVfXafMeaUj0noWw==", "dev": true, "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -6794,22 +7666,23 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", - "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.3.0.tgz", + "integrity": "sha512-Mq7FTHl0R36EmWlCJWojIC1qn/ZWo2YiWYc1XVtasJ7FIgjo0MVv9rZWXEE7IK2CGrtwe1dVOxWwqXUdNgfRCA==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0", + "@typescript-eslint/types": "8.3.0", + "@typescript-eslint/visitor-keys": "8.3.0", "debug": "^4.3.4", - "globby": "^11.1.0", + "fast-glob": "^3.3.2", "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -6822,72 +7695,67 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", - "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.3.0.tgz", + "integrity": "sha512-RmZwrTbQ9QveF15m/Cl28n0LXD6ea2CjkhH5rQ55ewz3H24w+AMCJHPVYaZ8/0HoG8Z3cLLFFycRXxeO2tz9FA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "5.62.0", - "eslint-visitor-keys": "^3.3.0" + "@typescript-eslint/types": "8.3.0", + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/utils/node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "node_modules/@typescript-eslint/utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "license": "MIT", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, + "license": "Apache-2.0", "engines": { - "node": ">=10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" + "url": "https://opencollective.com/eslint" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", - "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", + "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "6.21.0", - "eslint-visitor-keys": "^3.4.1" + "@typescript-eslint/types": "7.18.0", + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", @@ -6896,16 +7764,16 @@ "license": "ISC" }, "node_modules/@vitejs/plugin-basic-ssl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.0.1.tgz", - "integrity": "sha512-pcub+YbFtFhaGRTo1832FQHQSHvMrlb43974e2eS8EKleR3p1cDdkJFPci1UhwkEf1J9Bz+wKBSzqpKp7nNj2A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.1.0.tgz", + "integrity": "sha512-wO4Dk/rm8u7RNhOf95ZzcEmC9rYOncYgvq4z3duaJrCgjN8BxAnDVyndanfcJZ0O6XZzHz6Q0hTimxTg8Y9g/A==", "dev": true, "license": "MIT", "engines": { "node": ">=14.6.0" }, "peerDependencies": { - "vite": "^3.0.0 || ^4.0.0" + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" } }, "node_modules/@webassemblyjs/ast": { @@ -7069,104 +7937,12 @@ "@xtuc/long": "4.2.2" } }, - "node_modules/@wessberg/ts-evaluator": { - "version": "0.0.27", - "resolved": "https://registry.npmjs.org/@wessberg/ts-evaluator/-/ts-evaluator-0.0.27.tgz", - "integrity": "sha512-7gOpVm3yYojUp/Yn7F4ZybJRxyqfMNf0LXK5KJiawbPfL0XTsJV+0mgrEDjOIR6Bi0OYk2Cyg4tjFu1r8MCZaA==", + "node_modules/@xml-tools/parser": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@xml-tools/parser/-/parser-1.0.11.tgz", + "integrity": "sha512-aKqQ077XnR+oQtHJlrAflaZaL7qZsulWc/i/ZEooar5JiWj1eLt0+Wg28cpa+XLney107wXqneC+oG1IZvxkTA==", "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.1.0", - "jsdom": "^16.4.0", - "object-path": "^0.11.5", - "tslib": "^2.0.3" - }, - "engines": { - "node": ">=10.1.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/wessberg/ts-evaluator?sponsor=1" - }, - "peerDependencies": { - "typescript": ">=3.2.x || >= 4.x" - } - }, - "node_modules/@wessberg/ts-evaluator/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@wessberg/ts-evaluator/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@wessberg/ts-evaluator/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@wessberg/ts-evaluator/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@wessberg/ts-evaluator/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@xml-tools/parser": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@xml-tools/parser/-/parser-1.0.11.tgz", - "integrity": "sha512-aKqQ077XnR+oQtHJlrAflaZaL7qZsulWc/i/ZEooar5JiWj1eLt0+Wg28cpa+XLney107wXqneC+oG1IZvxkTA==", - "dev": true, - "license": "Apache-2.0", + "license": "Apache-2.0", "dependencies": { "chevrotain": "7.1.1" } @@ -7202,54 +7978,16 @@ "dev": true, "license": "BSD-2-Clause" }, - "node_modules/@yarnpkg/parsers": { - "version": "3.0.0-rc.46", - "resolved": "https://registry.npmjs.org/@yarnpkg/parsers/-/parsers-3.0.0-rc.46.tgz", - "integrity": "sha512-aiATs7pSutzda/rq8fnuPwTglyVwjM22bNnK2ZgjrpAjQHSSl3lztd2f9evst1W/qnC58DRz7T7QndUDumAR4Q==", + "node_modules/abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "js-yaml": "^3.10.0", - "tslib": "^2.4.0" - }, + "license": "ISC", "engines": { - "node": ">=14.15.0" - } - }, - "node_modules/@zkochan/js-yaml": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/@zkochan/js-yaml/-/js-yaml-0.0.6.tgz", - "integrity": "sha512-nzvgl3VfhcELQ8LyVrYOru+UtAy1nrygk2+AGbTm8a5YcO6o8lSjAT+pfg3vJWxIoZKOUhrK6UU7xW/+00kQrg==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/@zkochan/js-yaml/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/abab": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true, - "license": "ISC" - }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -7277,45 +8015,12 @@ "node": ">=0.4.0" } }, - "node_modules/acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - } - }, - "node_modules/acorn-globals/node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-globals/node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/acorn-import-attributes": { "version": "1.9.5", "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^8" } @@ -7331,11 +8036,14 @@ } }, "node_modules/acorn-walk": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.1.tgz", - "integrity": "sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==", + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", + "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", "dev": true, "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, "engines": { "node": ">=0.4.0" } @@ -7377,39 +8085,26 @@ } }, "node_modules/adm-zip": { - "version": "0.5.12", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.12.tgz", - "integrity": "sha512-6TVU49mK6KZb4qG6xWaaM4C7sA/sgUMLy/JYMOzkcp3BvVLpW0fXDFQiIzAuxFCt/2+xD7fNIiPFAoLZPhVNLQ==", + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.15.tgz", + "integrity": "sha512-jYPWSeOA8EFoZnucrKCNihqBjoEGQSU4HKgHYQgKNEQ0pQF9a/DYuo/+fAxY76k4qe75LUlLWpAM1QWcBMTOKw==", "dev": true, "license": "MIT", "engines": { - "node": ">=6.0" + "node": ">=12.0" } }, "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/agentkeepalive": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", - "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", "dev": true, "license": "MIT", "dependencies": { - "humanize-ms": "^1.2.1" + "debug": "^4.3.4" }, "engines": { - "node": ">= 8.0.0" + "node": ">= 14" } }, "node_modules/aggregate-error": { @@ -7427,15 +8122,16 @@ } }, "node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz", + "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==", + "dev": true, "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", + "fast-deep-equal": "^3.1.3", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "uri-js": "^4.4.1" }, "funding": { "type": "github", @@ -7443,9 +8139,10 @@ } }, "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "dev": true, "license": "MIT", "dependencies": { "ajv": "^8.0.0" @@ -7486,6 +8183,7 @@ "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, "license": "MIT", "dependencies": { "type-fest": "^0.21.3" @@ -7505,6 +8203,7 @@ "engines": [ "node >= 0.8.0" ], + "license": "Apache-2.0", "bin": { "ansi-html": "bin/ansi-html" } @@ -7545,12 +8244,18 @@ "node": ">= 8" } }, - "node_modules/aproba": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "dev": true, - "license": "ISC" + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } }, "node_modules/are-docs-informative": { "version": "0.0.2", @@ -7562,20 +8267,6 @@ "node": ">=14" } }, - "node_modules/are-we-there-yet": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", - "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", - "dev": true, - "license": "ISC", - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -7584,14 +8275,11 @@ "license": "MIT" }, "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true, - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } + "license": "Python-2.0" }, "node_modules/aria-query": { "version": "5.3.0", @@ -7624,7 +8312,8 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/array-ify": { "version": "1.0.0", @@ -7634,16 +8323,17 @@ "license": "MIT" }, "node_modules/array-includes": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", - "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", "is-string": "^1.0.7" }, "engines": { @@ -7769,6 +8459,7 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true, "license": "MIT" }, "node_modules/asn1": { @@ -7795,6 +8486,7 @@ "version": "0.13.4", "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "dev": true, "license": "MIT", "dependencies": { "tslib": "^2.0.1" @@ -7807,37 +8499,33 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", - "dev": true, - "license": "MIT" - }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, "license": "MIT" }, "node_modules/at-least-node": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, "license": "ISC", "engines": { "node": ">= 4.0.0" } }, "node_modules/autoprefixer": { - "version": "10.4.14", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", - "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", + "version": "10.4.20", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", + "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", "dev": true, "funding": [ { @@ -7847,15 +8535,19 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "license": "MIT", "dependencies": { - "browserslist": "^4.21.5", - "caniuse-lite": "^1.0.30001464", - "fraction.js": "^4.2.0", + "browserslist": "^4.23.3", + "caniuse-lite": "^1.0.30001646", + "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", + "picocolors": "^1.0.1", "postcss-value-parser": "^4.2.0" }, "bin": { @@ -7895,46 +8587,20 @@ } }, "node_modules/aws4": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", - "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.1.tgz", + "integrity": "sha512-u5w79Rd7SU4JaIlA/zFqG+gOiuq25q5VLyZ8E+ijJeILuTxVzZgp2CaGw/UTw6pXYN9XMO9yiqj/nEHmhTG5CA==", "dev": true, "license": "MIT" }, - "node_modules/axios": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.5.tgz", - "integrity": "sha512-fZu86yCo+svH3uqJ/yTdQ0QHpQu5oL+/QE+QPSv6BZSkDAoky9vytxp7u5qk83OJFS3kEBcesWni9WTZAv3tSw==", - "dev": true, - "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, - "node_modules/axios/node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/axobject-query": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.0.0.tgz", - "integrity": "sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", "dev": true, "license": "Apache-2.0", - "dependencies": { - "dequal": "^2.0.3" + "engines": { + "node": ">= 0.4" } }, "node_modules/b4a": { @@ -7962,32 +8628,15 @@ "webpack": ">=5" } }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.10", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.10.tgz", - "integrity": "sha512-rpIuu//y5OX6jVU+a5BCn1R5RSZYWAl2Nar76iwaOdycqb6JPxediskWFMMl7stfwNJR4b7eiQvh5fB5TEQJTQ==", + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", + "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.22.6", - "@babel/helper-define-polyfill-provider": "^0.6.1", + "@babel/helper-define-polyfill-provider": "^0.6.2", "semver": "^6.3.1" }, "peerDependencies": { @@ -8005,61 +8654,27 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.8.7", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.7.tgz", - "integrity": "sha512-KyDvZYxAzkC0Aj2dAPyDzi2Ym15e5JKZSK+maI7NAwSqofvuFglbSsxE7wUOvTg9oFVnHMzVzBKcqEb4PJgtOA==", + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", + "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.4.4", - "core-js-compat": "^3.33.1" + "@babel/helper-define-polyfill-provider": "^0.6.2", + "core-js-compat": "^3.38.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/babel-plugin-polyfill-corejs3/node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.4.tgz", - "integrity": "sha512-QcJMILQCu2jm5TFPGA3lCpJJTeEP+mqeXooG/NZbg/h5FTFi6V0+99ahlRsW8/kRLyb24LZVCCiclDedhLKcBA==", + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", + "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.22.6", - "@babel/helper-plugin-utils": "^7.22.5", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.5.tgz", - "integrity": "sha512-OJGYZlhLqBh2DDHeqAxWB1XIvr49CxiJ2gIt61/PU55CQK4Z58OzMqjDe1zwQdQk+rBYsRc+1rJmdajM3gimHg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.5.0" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-regenerator/node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz", - "integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.22.6", - "@babel/helper-plugin-utils": "^7.22.5", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2" + "@babel/helper-define-polyfill-provider": "^0.6.2" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -8069,6 +8684,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, "license": "MIT" }, "node_modules/bare-events": { @@ -8156,6 +8772,7 @@ "version": "5.0.5", "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", + "dev": true, "license": "MIT", "engines": { "node": ">=10.0.0" @@ -8165,7 +8782,8 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/bcrypt-pbkdf": { "version": "1.0.2", @@ -8198,13 +8816,16 @@ } }, "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "devOptional": true, "license": "MIT", "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/bl": { @@ -8259,16 +8880,6 @@ "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/body-parser/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/body-parser/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -8304,6 +8915,7 @@ "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "multicast-dns": "^7.2.5" @@ -8340,13 +8952,13 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "node_modules/braces": { @@ -8362,17 +8974,10 @@ "node": ">=8" } }, - "node_modules/browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true, - "license": "BSD-2-Clause" - }, "node_modules/browserslist": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", - "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", + "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", "dev": true, "funding": [ { @@ -8390,10 +8995,10 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001587", - "electron-to-chromium": "^1.4.668", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" + "caniuse-lite": "^1.0.30001646", + "electron-to-chromium": "^1.5.4", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" }, "bin": { "browserslist": "cli.js" @@ -8490,51 +9095,45 @@ "dev": true, "license": "MIT" }, - "node_modules/builtin-modules": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", - "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", "dev": true, "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, "engines": { - "node": ">=6" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/builtins": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", - "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.0.0" - } - }, "node_modules/bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/cacache": { - "version": "17.1.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.1.4.tgz", - "integrity": "sha512-/aJwG2l3ZMJ1xNAnqbMpA40of9dj/pIH3QfiuQSqjfPJF747VR0J/bHn+/KdNnHKc6XQcWt/AfRSBft82W1d2A==", + "version": "18.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.4.tgz", + "integrity": "sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==", "dev": true, "license": "ISC", "dependencies": { "@npmcli/fs": "^3.1.0", "fs-minipass": "^3.0.0", "glob": "^10.2.2", - "lru-cache": "^7.7.1", + "lru-cache": "^10.0.1", "minipass": "^7.0.3", - "minipass-collect": "^1.0.2", + "minipass-collect": "^2.0.1", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "p-map": "^4.0.0", @@ -8543,33 +9142,42 @@ "unique-filename": "^3.0.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/cacache/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "node_modules/cacache/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, "license": "ISC", - "engines": { - "node": ">=12" + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/cacache/node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "node_modules/cacache/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true, - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } + "license": "ISC" }, "node_modules/call-bind": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", @@ -8624,9 +9232,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001606", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001606.tgz", - "integrity": "sha512-LPbwnW4vfpJId225pwjZJOgX1m9sGfbw/RKJvw/t0QhYOOaTXHvkjVGFGPpvwEzufrjvTlsULnVTxdy4/6cqkg==", + "version": "1.0.30001653", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001653.tgz", + "integrity": "sha512-XGWQVB8wFQ2+9NZwZ10GxTYC5hk0Fa+q8cSkr0tgvMhYhMHP/QC+WTgrePMDBWiWc/pV+1ik82Al20XOK25Gcw==", "dev": true, "funding": [ { @@ -8655,21 +9263,21 @@ } }, "node_modules/capacitor-ios-autofill-save-password": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/capacitor-ios-autofill-save-password/-/capacitor-ios-autofill-save-password-2.0.0.tgz", - "integrity": "sha512-7Tnu7qU5elnv1YkcXtXPIBhvyCZX9nskKrI78kJG65qaf6rSL1EE5IBOdTSQcpyPSyVio+UX1EFsS/QZjQrPuA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/capacitor-ios-autofill-save-password/-/capacitor-ios-autofill-save-password-3.0.0.tgz", + "integrity": "sha512-FGWralgZ47FtpRcIaJP+IcNDZfmoaCUmkeGBKo84V3nYMKQwQbpN9wLIzXa+TtHj8h1SenRuSR2eTsQBrRewAQ==", "license": "MIT", "peerDependencies": { - "@capacitor/core": "^5.0.0" + "@capacitor/core": "^6.0.0" } }, "node_modules/capacitor-secure-storage-plugin": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/capacitor-secure-storage-plugin/-/capacitor-secure-storage-plugin-0.9.0.tgz", - "integrity": "sha512-P5fiC94opcLHu41vceo9weXH+20g0SPYKkeAx+qm9eKNcVFqpcuI4dqwivXlGXYNMDygyjSQuAaFwZ4gW0Y91Q==", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/capacitor-secure-storage-plugin/-/capacitor-secure-storage-plugin-0.10.0.tgz", + "integrity": "sha512-dV4E+HTZAJWC3gef7sBXaAkkb6wvcZHyXjJIHXNb3yz9gRQ/5VMLqCxa0khqpwgWh5oIbo4XFxg3g5tEkfaNMg==", "license": "MIT", "peerDependencies": { - "@capacitor/core": "^5.0.0" + "@capacitor/core": "^6.0.0" } }, "node_modules/caseless": { @@ -8698,12 +9306,14 @@ "version": "0.7.0", "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true, "license": "MIT" }, "node_modules/chart.js": { "version": "4.4.4", "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.4.tgz", "integrity": "sha512-emICKGBABnxhMjUjlYRR12PmOXhJ2eJjEHL2/dZlWjxRAZT1D8xplLFq5M0tMQK8ja+wBS/tuVEJB5C6r7VxJA==", + "license": "MIT", "dependencies": { "@kurkle/color": "^0.3.0" }, @@ -8725,6 +9335,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/chartjs-plugin-annotation/-/chartjs-plugin-annotation-3.0.1.tgz", "integrity": "sha512-hlIrXXKqSDgb+ZjVYHefmlZUXK8KbkCPiynSVrTb/HjTMkT62cOInaT1NTQCKtxKKOm9oHp958DY3RTAFKtkHg==", + "license": "MIT", "peerDependencies": { "chart.js": ">=4.0.0" } @@ -8733,6 +9344,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/chartjs-plugin-datalabels/-/chartjs-plugin-datalabels-2.2.0.tgz", "integrity": "sha512-14ZU30lH7n89oq+A4bWaJPnAG8a7ZTk7dKf48YAzMvJjQtjrgg5Dpk9f+LbjCF6bpx3RAGTeL13IXpKQYyRvlw==", + "license": "MIT", "peerDependencies": { "chart.js": ">=3.0.0" } @@ -8760,16 +9372,10 @@ } }, "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "devOptional": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], "license": "MIT", "dependencies": { "anymatch": "~3.1.2", @@ -8783,6 +9389,9 @@ "engines": { "node": ">= 8.10.0" }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, "optionalDependencies": { "fsevents": "~2.3.2" } @@ -8791,15 +9400,16 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, "license": "ISC", "engines": { "node": ">=10" } }, "node_modules/chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", "dev": true, "license": "MIT", "engines": { @@ -8846,125 +9456,285 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "license": "ISC", + "node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, "engines": { - "node": ">= 10" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "node_modules/cli-truncate/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, + "license": "MIT", "engines": { "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "node_modules/cli-truncate/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, "license": "MIT", "engines": { - "node": ">=0.8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "node_modules/cli-truncate/node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "dev": true, + "license": "MIT" + }, + "node_modules/cli-truncate/node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", "dev": true, "license": "MIT", - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, "engines": { - "node": ">=6" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/color": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", - "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "node_modules/cli-truncate/node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", "dev": true, "license": "MIT", "dependencies": { - "color-convert": "^2.0.1", - "color-string": "^1.9.0" + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" }, "engines": { - "node": ">=12.5.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "node_modules/cli-truncate/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, "license": "MIT", "dependencies": { - "color-name": "1.1.3" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/color-convert/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "license": "MIT" - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT" - }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "node_modules/cli-truncate/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, "license": "MIT", "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", "dev": true, "license": "ISC", - "bin": { - "color-support": "bin.js" + "engines": { + "node": ">= 12" } }, - "node_modules/color/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "color-name": "~1.1.4" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/cliui/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" }, "engines": { "node": ">=7.0.0" } }, + "node_modules/color/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, "node_modules/colorette": { "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", @@ -8986,6 +9756,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" @@ -8995,12 +9766,13 @@ } }, "node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 10" + "node": ">= 12" } }, "node_modules/comment-parser": { @@ -9041,6 +9813,7 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -9051,6 +9824,7 @@ "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", "dev": true, + "license": "MIT", "dependencies": { "mime-db": ">= 1.43.0 < 2" }, @@ -9063,6 +9837,7 @@ "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", "dev": true, + "license": "MIT", "dependencies": { "accepts": "~1.3.5", "bytes": "3.0.0", @@ -9076,11 +9851,22 @@ "node": ">= 0.8.0" } }, + "node_modules/compression/node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/compression/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -9089,18 +9875,21 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/compression/node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, "license": "MIT" }, "node_modules/connect": { @@ -9124,6 +9913,7 @@ "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8" } @@ -9138,25 +9928,6 @@ "ms": "2.0.0" } }, - "node_modules/connect/node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/connect/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -9164,41 +9935,12 @@ "dev": true, "license": "MIT" }, - "node_modules/connect/node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", - "dev": true, - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/connect/node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "dev": true, - "license": "ISC" - }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" }, @@ -9253,18 +9995,6 @@ "node": ">=10" } }, - "node_modules/conventional-changelog-angular/node_modules/q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", - "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, "node_modules/conventional-changelog-atom": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/conventional-changelog-atom/-/conventional-changelog-atom-2.0.8.tgz", @@ -9278,18 +10008,6 @@ "node": ">=10" } }, - "node_modules/conventional-changelog-atom/node_modules/q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", - "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, "node_modules/conventional-changelog-codemirror": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/conventional-changelog-codemirror/-/conventional-changelog-codemirror-2.0.8.tgz", @@ -9303,18 +10021,6 @@ "node": ">=10" } }, - "node_modules/conventional-changelog-codemirror/node_modules/q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", - "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, "node_modules/conventional-changelog-conventionalcommits": { "version": "4.6.3", "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.6.3.tgz", @@ -9330,18 +10036,6 @@ "node": ">=10" } }, - "node_modules/conventional-changelog-conventionalcommits/node_modules/q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", - "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, "node_modules/conventional-changelog-core": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-4.2.4.tgz", @@ -9368,67 +10062,6 @@ "node": ">=10" } }, - "node_modules/conventional-changelog-core/node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/conventional-changelog-core/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/conventional-changelog-core/node_modules/normalize-package-data": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/conventional-changelog-core/node_modules/q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", - "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, - "node_modules/conventional-changelog-core/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, "node_modules/conventional-changelog-ember": { "version": "2.0.9", "resolved": "https://registry.npmjs.org/conventional-changelog-ember/-/conventional-changelog-ember-2.0.9.tgz", @@ -9442,18 +10075,6 @@ "node": ">=10" } }, - "node_modules/conventional-changelog-ember/node_modules/q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", - "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, "node_modules/conventional-changelog-eslint": { "version": "3.0.9", "resolved": "https://registry.npmjs.org/conventional-changelog-eslint/-/conventional-changelog-eslint-3.0.9.tgz", @@ -9467,18 +10088,6 @@ "node": ">=10" } }, - "node_modules/conventional-changelog-eslint/node_modules/q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", - "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, "node_modules/conventional-changelog-express": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/conventional-changelog-express/-/conventional-changelog-express-2.0.6.tgz", @@ -9492,18 +10101,6 @@ "node": ">=10" } }, - "node_modules/conventional-changelog-express/node_modules/q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", - "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, "node_modules/conventional-changelog-jquery": { "version": "3.0.11", "resolved": "https://registry.npmjs.org/conventional-changelog-jquery/-/conventional-changelog-jquery-3.0.11.tgz", @@ -9517,18 +10114,6 @@ "node": ">=10" } }, - "node_modules/conventional-changelog-jquery/node_modules/q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", - "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, "node_modules/conventional-changelog-jshint": { "version": "2.0.9", "resolved": "https://registry.npmjs.org/conventional-changelog-jshint/-/conventional-changelog-jshint-2.0.9.tgz", @@ -9543,18 +10128,6 @@ "node": ">=10" } }, - "node_modules/conventional-changelog-jshint/node_modules/q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", - "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, "node_modules/conventional-changelog-preset-loader": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.4.tgz", @@ -9642,10 +10215,11 @@ "license": "MIT" }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -9654,12 +10228,14 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cookiejar": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", + "dev": true, "license": "MIT" }, "node_modules/copy-anything": { @@ -9676,21 +10252,21 @@ } }, "node_modules/copy-webpack-plugin": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", - "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-12.0.2.tgz", + "integrity": "sha512-SNwdBeHyII+rWvee/bTnAYyO8vfVdcSTud4EIb6jcZ8inLeWucJE0DnxXQBjlQ5zlteuuvooGQy3LIyGxhvlOA==", "dev": true, "license": "MIT", "dependencies": { - "fast-glob": "^3.2.11", + "fast-glob": "^3.3.2", "glob-parent": "^6.0.1", - "globby": "^13.1.1", + "globby": "^14.0.0", "normalize-path": "^3.0.0", - "schema-utils": "^4.0.0", - "serialize-javascript": "^6.0.0" + "schema-utils": "^4.2.0", + "serialize-javascript": "^6.0.2" }, "engines": { - "node": ">= 14.15.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", @@ -9713,14 +10289,61 @@ "node": ">=10.13.0" } }, + "node_modules/copy-webpack-plugin/node_modules/globby": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.2.tgz", + "integrity": "sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.2", + "ignore": "^5.2.4", + "path-type": "^5.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/copy-webpack-plugin/node_modules/path-type": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", + "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/copy-webpack-plugin/node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/core-js-compat": { - "version": "3.36.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.1.tgz", - "integrity": "sha512-Dk997v9ZCt3X/npqzyGdTlq6t7lDBhZwGvV94PKzDArjp7BTRm7WlDAXYd/OWdeFHO8OChQYRJNJvUCqCbrtKA==", + "version": "3.38.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.38.1.tgz", + "integrity": "sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.23.0" + "browserslist": "^4.23.3" }, "funding": { "type": "opencollective", @@ -9731,6 +10354,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true, "license": "MIT" }, "node_modules/cors": { @@ -9748,16 +10372,16 @@ } }, "node_modules/cosmiconfig": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", "dev": true, "license": "MIT", "dependencies": { + "env-paths": "^2.2.1", "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" + "parse-json": "^5.2.0" }, "engines": { "node": ">=14" @@ -9774,26 +10398,6 @@ } } }, - "node_modules/cosmiconfig/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/cosmiconfig/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", @@ -9802,9 +10406,9 @@ "license": "MIT" }, "node_modules/critters": { - "version": "0.0.20", - "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.20.tgz", - "integrity": "sha512-CImNRorKOl5d8TWcnAz5n5izQ6HFsvz29k327/ELy6UFcmbiZNOsinaKvzv16WZR0P6etfSWYzE47C4/56B3Uw==", + "version": "0.0.24", + "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.24.tgz", + "integrity": "sha512-Oyqew0FGM0wYUSNqR0L6AteO5MpMoUU0rhKRieXeiKs+PmRTxiJMyaunYB2KF6fQ3dzChXKCpbFOEJx3OQ1v/Q==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -9814,7 +10418,7 @@ "domhandler": "^5.0.2", "htmlparser2": "^8.0.2", "postcss": "^8.4.23", - "pretty-bytes": "^5.3.0" + "postcss-media-query-parser": "^0.2.3" } }, "node_modules/critters/node_modules/ansi-styles": { @@ -9863,6 +10467,13 @@ "node": ">=7.0.0" } }, + "node_modules/critters/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, "node_modules/critters/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -9900,6 +10511,7 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -9921,30 +10533,39 @@ } }, "node_modules/css-loader": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.8.1.tgz", - "integrity": "sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.2.tgz", + "integrity": "sha512-6WvYYn7l/XEGN8Xu2vWFt9nVzrCn39vKyTEFf/ExEyoksJjjSZV/0/35XPlMbpnr6VGhZIUg5yJrL8tGfes/FA==", "dev": true, "license": "MIT", "dependencies": { "icss-utils": "^5.1.0", - "postcss": "^8.4.21", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.3", - "postcss-modules-scope": "^3.0.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", "postcss-modules-values": "^4.0.0", "postcss-value-parser": "^4.2.0", - "semver": "^7.3.8" + "semver": "^7.5.4" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "^5.0.0" + "@rspack/core": "0.x || 1.x", + "webpack": "^5.27.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } } }, "node_modules/css-select": { @@ -9990,33 +10611,6 @@ "node": ">=4" } }, - "node_modules/cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true, - "license": "MIT" - }, - "node_modules/cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, - "license": "MIT", - "dependencies": { - "cssom": "~0.3.6" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cssstyle/node_modules/cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true, - "license": "MIT" - }, "node_modules/custom-event": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", @@ -10194,6 +10788,15 @@ "node": ">=12" } }, + "node_modules/d3-dsv/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, "node_modules/d3-ease": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", @@ -10239,9 +10842,9 @@ } }, "node_modules/d3-geo": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.0.tgz", - "integrity": "sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", "license": "ISC", "dependencies": { "d3-array": "2.5.0 - 3" @@ -10324,9 +10927,9 @@ } }, "node_modules/d3-scale-chromatic": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", - "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", "license": "ISC", "dependencies": { "d3-color": "1 - 3", @@ -10452,24 +11055,10 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", "dev": true, "license": "MIT", - "dependencies": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" - }, "engines": { - "node": ">=10" + "node": ">= 14" } }, "node_modules/data-view-buffer": { @@ -10563,9 +11152,10 @@ } }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dev": true, "license": "MIT", "dependencies": { "ms": "2.1.2" @@ -10616,13 +11206,6 @@ "node": ">=0.10.0" } }, - "node_modules/decimal.js": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", - "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", - "dev": true, - "license": "MIT" - }, "node_modules/decompress-response": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", @@ -10656,20 +11239,105 @@ "dev": true, "license": "MIT" }, - "node_modules/default-gateway": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", - "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "node_modules/default-browser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", + "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", "dev": true, + "license": "MIT", "dependencies": { - "execa": "^5.0.0" + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" }, "engines": { - "node": ">= 10" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/defaults": { - "version": "1.0.4", + "node_modules/default-browser-id": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", + "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/default-gateway/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/default-gateway/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-gateway/node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/default-gateway/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/defaults": { + "version": "1.0.4", "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", "license": "MIT", @@ -10684,6 +11352,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", @@ -10698,13 +11367,16 @@ } }, "node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/define-properties": { @@ -10729,6 +11401,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "dev": true, "license": "MIT", "dependencies": { "ast-types": "^0.13.4", @@ -10740,90 +11413,33 @@ } }, "node_modules/del": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", - "integrity": "sha512-Z4fzpbIRjOu7lO5jCETSWoqUDVe0IPOlfugBsF6suen2LKDlVb4QZpKEM9P+buNJ4KI1eN7I083w/pbKUpsrWQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "globby": "^5.0.0", - "is-path-cwd": "^1.0.0", - "is-path-in-cwd": "^1.0.0", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "rimraf": "^2.2.8" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/del/node_modules/array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", + "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", "dev": true, "license": "MIT", "dependencies": { - "array-uniq": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/del/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", + "slash": "^3.0.0" }, "engines": { - "node": "*" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/del/node_modules/globby": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", - "integrity": "sha512-HJRTIH2EeH44ka+LWig+EqT2ONSYpVlNfx6pyd592/VF1TbfljJ7elwie7oSwcViLGqOdWocSdu2txwBF9bjmQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-union": "^1.0.1", - "arrify": "^1.0.0", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/del/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/del/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", "dependencies": { @@ -10831,33 +11447,30 @@ }, "bin": { "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/delaunator": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz", - "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", "license": "ISC", "dependencies": { - "robust-predicates": "^3.0.0" + "robust-predicates": "^3.0.2" } }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.4.0" } }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "dev": true, - "license": "MIT" - }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -10903,12 +11516,14 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/dezalgo": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, "license": "ISC", "dependencies": { "asap": "^2.0.0", @@ -10926,6 +11541,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -10949,6 +11565,7 @@ "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", "dev": true, + "license": "MIT", "dependencies": { "@leichtgewicht/ip-codec": "^2.0.1" }, @@ -11010,29 +11627,6 @@ ], "license": "BSD-2-Clause" }, - "node_modules/domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", - "dev": true, - "license": "MIT", - "dependencies": { - "webidl-conversions": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/domexception/node_modules/webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=8" - } - }, "node_modules/domhandler": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", @@ -11077,36 +11671,28 @@ "node": ">=8" } }, - "node_modules/dotenv": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=10" - } - }, - "node_modules/duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true, - "license": "MIT" - }, "node_modules/duplexer2": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "readable-stream": "^2.0.2" } }, + "node_modules/duplexer2/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, "node_modules/duplexer2/node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", @@ -11122,12 +11708,14 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, "license": "MIT" }, "node_modules/duplexer2/node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" @@ -11151,6 +11739,13 @@ "safer-buffer": "^2.1.0" } }, + "node_modules/ecc-jsbn/node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true, + "license": "MIT" + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -11158,26 +11753,10 @@ "dev": true, "license": "MIT" }, - "node_modules/ejs": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", - "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "jake": "^10.8.5" - }, - "bin": { - "ejs": "bin/cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/electron-to-chromium": { - "version": "1.4.728", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.728.tgz", - "integrity": "sha512-Ud1v7hJJYIqehlUJGqR6PF1Ek8l80zWwxA6nGxigBsGJ9f9M2fciHyrIiNMerSHSH3p+0/Ia7jIlnDkt41h5cw==", + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz", + "integrity": "sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==", "dev": true, "license": "ISC" }, @@ -11185,6 +11764,7 @@ "version": "0.1.7", "resolved": "https://registry.npmjs.org/elementtree/-/elementtree-0.1.7.tgz", "integrity": "sha512-wkgGT6kugeQk/P6VZ/f4T+4HB41BVgNBq5CDIZVbQ02nvTVqAiVTbskxxu3eA/X96lMlfYOwnLQpN2v5E1zDEg==", + "dev": true, "license": "Apache-2.0", "dependencies": { "sax": "1.1.4" @@ -11193,16 +11773,11 @@ "node": ">= 0.4.0" } }, - "node_modules/elementtree/node_modules/sax": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.1.4.tgz", - "integrity": "sha512-5f3k2PbGGp+YtKJjOItpg3P99IMD84E4HOvcfleTb5joCHNXYLsR9yWFPOYGgaeMPDubQILTCMdsFb2OMeOjtg==", - "license": "ISC" - }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, "license": "MIT" }, "node_modules/emojis-list": { @@ -11240,6 +11815,7 @@ "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, "license": "MIT", "dependencies": { "once": "^1.4.0" @@ -11268,52 +11844,21 @@ } }, "node_modules/engine.io-parser": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz", - "integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", "dev": true, "license": "MIT", "engines": { "node": ">=10.0.0" } }, - "node_modules/engine.io/node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "node_modules/enhanced-resolve": { + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/engine.io/node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/enhanced-resolve": { - "version": "5.17.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", - "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", - "dev": true, "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -11322,26 +11867,19 @@ "node": ">=10.13.0" } }, - "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "node_modules/ent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.1.tgz", + "integrity": "sha512-QHuXVeZx9d+tIQAz/XztU0ZwZf2Agg9CcXcgE1rurqvdBeDBrpSwjl8/6XUqMg7tw2Y7uAdKb2sRv+bSEFqQ5A==", "dev": true, "license": "MIT", "dependencies": { - "ansi-colors": "^4.1.1" + "punycode": "^1.4.1" }, "engines": { - "node": ">=8.6" + "node": ">= 0.4" } }, - "node_modules/ent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", - "dev": true, - "license": "MIT" - }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -11365,6 +11903,19 @@ "node": ">=6" } }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/err-code": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", @@ -11461,6 +12012,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.4" @@ -11473,15 +12025,16 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/es-module-lexer": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.0.tgz", - "integrity": "sha512-pqrTKmwEIgafsYZAGw9kszYzmagcE/n4dbgwGWLEXg7J4QFJVQRBld8j3Q3GNez79jzxZshq0bcT962QHOghjw==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", "dev": true, "license": "MIT" }, @@ -11559,9 +12112,9 @@ } }, "node_modules/esbuild": { - "version": "0.18.17", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.17.tgz", - "integrity": "sha512-1GJtYnUxsJreHYA0Y+iQz2UEykonY66HNWOb0yXYZi9/kNrORUEHVg87eQsCtqh59PEJ5YVZJO98JHznMJSWjg==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.0.tgz", + "integrity": "sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -11569,50 +12122,52 @@ "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/android-arm": "0.18.17", - "@esbuild/android-arm64": "0.18.17", - "@esbuild/android-x64": "0.18.17", - "@esbuild/darwin-arm64": "0.18.17", - "@esbuild/darwin-x64": "0.18.17", - "@esbuild/freebsd-arm64": "0.18.17", - "@esbuild/freebsd-x64": "0.18.17", - "@esbuild/linux-arm": "0.18.17", - "@esbuild/linux-arm64": "0.18.17", - "@esbuild/linux-ia32": "0.18.17", - "@esbuild/linux-loong64": "0.18.17", - "@esbuild/linux-mips64el": "0.18.17", - "@esbuild/linux-ppc64": "0.18.17", - "@esbuild/linux-riscv64": "0.18.17", - "@esbuild/linux-s390x": "0.18.17", - "@esbuild/linux-x64": "0.18.17", - "@esbuild/netbsd-x64": "0.18.17", - "@esbuild/openbsd-x64": "0.18.17", - "@esbuild/sunos-x64": "0.18.17", - "@esbuild/win32-arm64": "0.18.17", - "@esbuild/win32-ia32": "0.18.17", - "@esbuild/win32-x64": "0.18.17" + "@esbuild/aix-ppc64": "0.23.0", + "@esbuild/android-arm": "0.23.0", + "@esbuild/android-arm64": "0.23.0", + "@esbuild/android-x64": "0.23.0", + "@esbuild/darwin-arm64": "0.23.0", + "@esbuild/darwin-x64": "0.23.0", + "@esbuild/freebsd-arm64": "0.23.0", + "@esbuild/freebsd-x64": "0.23.0", + "@esbuild/linux-arm": "0.23.0", + "@esbuild/linux-arm64": "0.23.0", + "@esbuild/linux-ia32": "0.23.0", + "@esbuild/linux-loong64": "0.23.0", + "@esbuild/linux-mips64el": "0.23.0", + "@esbuild/linux-ppc64": "0.23.0", + "@esbuild/linux-riscv64": "0.23.0", + "@esbuild/linux-s390x": "0.23.0", + "@esbuild/linux-x64": "0.23.0", + "@esbuild/netbsd-x64": "0.23.0", + "@esbuild/openbsd-arm64": "0.23.0", + "@esbuild/openbsd-x64": "0.23.0", + "@esbuild/sunos-x64": "0.23.0", + "@esbuild/win32-arm64": "0.23.0", + "@esbuild/win32-ia32": "0.23.0", + "@esbuild/win32-x64": "0.23.0" } }, "node_modules/esbuild-wasm": { - "version": "0.18.17", - "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.18.17.tgz", - "integrity": "sha512-9OHGcuRzy+I8ziF9FzjfKLWAPbvi0e/metACVg9k6bK+SI4FFxeV6PcZsz8RIVaMD4YNehw+qj6UMR3+qj/EuQ==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.23.0.tgz", + "integrity": "sha512-6jP8UmWy6R6TUUV8bMuC3ZyZ6lZKI56x0tkxyCIqWwRRJ/DgeQKneh/Oid5EoGoPFLrGNkz47ZEtWAYuiY/u9g==", "dev": true, "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true, "license": "MIT", "engines": { @@ -11630,6 +12185,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.8.0" @@ -11639,6 +12195,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "esprima": "^4.0.1", @@ -11656,19 +12213,11 @@ "source-map": "~0.6.1" } }, - "node_modules/escodegen/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, "node_modules/escodegen/node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, "license": "BSD-3-Clause", "optional": true, "engines": { @@ -11754,9 +12303,9 @@ } }, "node_modules/eslint-module-utils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", - "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.2.tgz", + "integrity": "sha512-3XnC5fDyc8M4J2E8pt8pmSVRX2M+5yWMCfI/kDZwauQeFgzQOuhcRBFKjTeJagqgk4sFKxe1mvNVnaWwImx/Tg==", "dev": true, "license": "MIT", "dependencies": { @@ -11813,6 +12362,17 @@ "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" } }, + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/eslint-plugin-import/node_modules/debug": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", @@ -11836,6 +12396,19 @@ "node": ">=0.10.0" } }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/eslint-plugin-import/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -11847,21 +12420,22 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "48.2.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.2.3.tgz", - "integrity": "sha512-r9DMAmFs66VNvNqRLLjHejdnJtILrt3xGi+Qx0op0oRfFGVpOR1Hb3BC++MacseHx93d8SKYPhyrC9BS7Os2QA==", + "version": "48.10.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.10.0.tgz", + "integrity": "sha512-BEli0k8E0dzhJairAllwlkGnyYDZVKNn4WDmyKy+v6J5qGNuofjzxwNUi+55BOGmyO9mKBhqaidwGy+dxndn/Q==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "@es-joy/jsdoccomment": "~0.42.0", + "@es-joy/jsdoccomment": "~0.46.0", "are-docs-informative": "^0.0.2", "comment-parser": "1.4.1", - "debug": "^4.3.4", + "debug": "^4.3.5", "escape-string-regexp": "^4.0.0", - "esquery": "^1.5.0", - "is-builtin-module": "^3.2.1", - "semver": "^7.6.0", - "spdx-expression-parse": "^4.0.0" + "esquery": "^1.6.0", + "parse-imports": "^2.1.1", + "semver": "^7.6.3", + "spdx-expression-parse": "^4.0.0", + "synckit": "^0.9.1" }, "engines": { "node": ">=18" @@ -11883,17 +12457,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint-plugin-jsdoc/node_modules/spdx-expression-parse": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", - "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, "node_modules/eslint-plugin-prefer-arrow": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/eslint-plugin-prefer-arrow/-/eslint-plugin-prefer-arrow-1.2.3.tgz", @@ -11909,6 +12472,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.1.3.tgz", "integrity": "sha512-lqrNZIZjFMUr7P06eoKtQLwyVRibvG7N+LtfKtObYGizAAGrcqLkc3tDx+iAik2z7q0j/XI3ihjupIqxhFabFA==", "dev": true, + "license": "MIT", "peerDependencies": { "@typescript-eslint/eslint-plugin": "^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0", "eslint": "^9.0.0 || ^8.0.0" @@ -11920,27 +12484,30 @@ } }, "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", + "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", "dev": true, "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "estraverse": "^5.2.0" }, "engines": { - "node": ">=8.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", "dev": true, "license": "Apache-2.0", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -11979,12 +12546,16 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/eslint/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "license": "Python-2.0" + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } }, "node_modules/eslint/node_modules/chalk": { "version": "4.1.2", @@ -12016,6 +12587,13 @@ "node": ">=7.0.0" } }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, "node_modules/eslint/node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -12046,31 +12624,35 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "license": "BSD-2-Clause", + "license": "Apache-2.0", "engines": { - "node": ">=4.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "node_modules/eslint/node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": ">=10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint/node_modules/glob-parent": { @@ -12112,19 +12694,6 @@ "node": ">=8" } }, - "node_modules/eslint/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/eslint/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -12132,52 +12701,17 @@ "dev": true, "license": "MIT" }, - "node_modules/eslint/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "p-limit": "^3.0.2" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "*" } }, "node_modules/eslint/node_modules/supports-color": { @@ -12207,18 +12741,18 @@ } }, "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.12.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^4.0.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -12228,6 +12762,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", @@ -12238,9 +12773,9 @@ } }, "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -12250,16 +12785,6 @@ "node": ">=0.10" } }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -12273,7 +12798,7 @@ "node": ">=4.0" } }, - "node_modules/esrecurse/node_modules/estraverse": { + "node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", @@ -12283,20 +12808,11 @@ "node": ">=4.0" } }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" @@ -12307,17 +12823,11 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, - "node_modules/eventemitter-asyncresource": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz", - "integrity": "sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==", - "dev": true, - "license": "MIT" - }, "node_modules/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", @@ -12336,19 +12846,20 @@ } }, "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", "dev": true, + "license": "MIT", "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", "strip-final-newline": "^2.0.0" }, "engines": { @@ -12358,6 +12869,13 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/execa/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, "node_modules/exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", @@ -12389,6 +12907,7 @@ "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "dev": true, + "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", @@ -12426,20 +12945,61 @@ "node": ">= 0.10.0" } }, + "node_modules/express/node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/express/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } }, + "node_modules/express/node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/express/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/express/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } }, "node_modules/extend": { "version": "3.0.2", @@ -12452,6 +13012,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, "license": "MIT", "dependencies": { "chardet": "^0.7.0", @@ -12466,6 +13027,7 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" @@ -12474,6 +13036,19 @@ "node": ">=0.10.0" } }, + "node_modules/external-editor/node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", @@ -12531,12 +13106,20 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", + "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==", + "dev": true, "license": "MIT" }, "node_modules/fastq": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", - "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, "license": "ISC", "dependencies": { @@ -12548,6 +13131,7 @@ "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", "dev": true, + "license": "Apache-2.0", "dependencies": { "websocket-driver": ">=0.5.1" }, @@ -12569,6 +13153,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, "license": "MIT", "dependencies": { "escape-string-regexp": "^1.0.5" @@ -12599,39 +13184,6 @@ "integrity": "sha512-Kg0lt+is9nOyi/VDms9miScNGot25jVFbjFccXuCL/shd2Q+rt70MALxHVkXllsX83JEBLiHQNjDPGd/6FIOoQ==", "license": "MIT" }, - "node_modules/filelist": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", - "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "minimatch": "^5.0.1" - } - }, - "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -12646,17 +13198,18 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", "dev": true, + "license": "MIT", "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "on-finished": "2.4.1", + "on-finished": "~2.3.0", "parseurl": "~1.3.3", - "statuses": "2.0.1", + "statuses": "~1.5.0", "unpipe": "~1.0.0" }, "engines": { @@ -12668,6 +13221,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -12676,7 +13230,21 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/finalhandler/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } }, "node_modules/find-cache-dir": { "version": "4.0.0", @@ -12696,17 +13264,20 @@ } }, "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "license": "MIT", "dependencies": { - "locate-path": "^5.0.0", + "locate-path": "^6.0.0", "path-exists": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/flat": { @@ -12734,10 +13305,27 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/flat-cache/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/flatted": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true, "license": "ISC" }, @@ -12773,9 +13361,9 @@ } }, "node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", "dev": true, "license": "ISC", "dependencies": { @@ -12789,19 +13377,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -12813,9 +13388,9 @@ } }, "node_modules/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", "dev": true, "license": "MIT", "dependencies": { @@ -12847,6 +13422,7 @@ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -12870,6 +13446,7 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -12882,18 +13459,18 @@ "license": "MIT" }, "node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": ">=6 <7 || >=8" + "node": ">=12" } }, "node_modules/fs-minipass": { @@ -12909,33 +13486,33 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/fs-minipass/node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/fs-monkey": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz", - "integrity": "sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==", - "dev": true, - "license": "Unlicense" - }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, "license": "ISC" }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -12970,26 +13547,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/gauge": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", - "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", - "dev": true, - "license": "ISC", - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -13010,14 +13567,28 @@ "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "node_modules/get-east-asian-width": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz", + "integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==", + "dev": true, "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", "hasown": "^2.0.0" @@ -13029,16 +13600,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/get-pkg-repo": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz", @@ -13058,6 +13619,22 @@ "node": ">=6.9.0" } }, + "node_modules/get-pkg-repo/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/get-pkg-repo/node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -13070,31 +13647,32 @@ "wrap-ansi": "^7.0.0" } }, - "node_modules/get-pkg-repo/node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "node_modules/get-pkg-repo/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">=10" + "node": ">=7.0.0" } }, - "node_modules/get-pkg-repo/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/get-pkg-repo/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } + "license": "MIT" + }, + "node_modules/get-pkg-repo/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" }, "node_modules/get-pkg-repo/node_modules/readable-stream": { "version": "2.3.8", @@ -13140,12 +13718,23 @@ "xtend": "~4.0.1" } }, - "node_modules/get-pkg-repo/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "node_modules/get-pkg-repo/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, - "license": "ISC" + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } }, "node_modules/get-pkg-repo/node_modules/yargs": { "version": "16.2.0", @@ -13166,23 +13755,17 @@ "node": ">=10" } }, - "node_modules/get-pkg-repo/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -13210,6 +13793,7 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz", "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==", + "dev": true, "license": "MIT", "dependencies": { "basic-ftp": "^5.0.2", @@ -13225,6 +13809,7 @@ "version": "11.2.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", @@ -13235,27 +13820,6 @@ "node": ">=14.14" } }, - "node_modules/get-uri/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/get-uri/node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, "node_modules/getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -13300,16 +13864,6 @@ "node": ">=4" } }, - "node_modules/git-remote-origin-url/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/git-semver-tags": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-4.1.1.tgz", @@ -13362,23 +13916,22 @@ "license": "MIT" }, "node_modules/glob": { - "version": "10.3.12", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", - "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "license": "ISC", "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.3.6", - "minimatch": "^9.0.1", - "minipass": "^7.0.4", - "path-scurry": "^1.10.2" - }, - "bin": { - "glob": "dist/esm/bin.mjs" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "*" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -13401,42 +13954,31 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true + "dev": true, + "license": "BSD-2-Clause" }, "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, "node_modules/glob/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" + "brace-expansion": "^1.1.7" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob/node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", - "dev": true, - "license": "ISC", "engines": { - "node": ">=16 || 14 >=14.17" + "node": "*" } }, "node_modules/globals": { @@ -13450,13 +13992,14 @@ } }, "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "dev": true, "license": "MIT", "dependencies": { - "define-properties": "^1.1.3" + "define-properties": "^1.2.1", + "gopd": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -13466,20 +14009,21 @@ } }, "node_modules/globby": { - "version": "13.2.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", - "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "license": "MIT", "dependencies": { + "array-union": "^2.1.0", "dir-glob": "^3.0.1", - "fast-glob": "^3.3.0", - "ignore": "^5.2.4", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", "merge2": "^1.4.1", - "slash": "^4.0.0" + "slash": "^3.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -13489,6 +14033,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, "license": "MIT", "dependencies": { "get-intrinsic": "^1.1.3" @@ -13501,6 +14046,7 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, "license": "ISC" }, "node_modules/gradle-to-js": { @@ -13523,19 +14069,6 @@ "dev": true, "license": "MIT" }, - "node_modules/guess-parser": { - "version": "0.4.22", - "resolved": "https://registry.npmjs.org/guess-parser/-/guess-parser-0.4.22.tgz", - "integrity": "sha512-KcUWZ5ACGaBM69SbqwVIuWGoSAgD+9iJnchR9j/IarVI1jHVeXv+bUXBIMeqVMSKt3zrn0Dgf9UpcOEpPBLbSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@wessberg/ts-evaluator": "0.0.27" - }, - "peerDependencies": { - "typescript": ">=3.7.5" - } - }, "node_modules/hammerjs": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz", @@ -13549,7 +14082,8 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/handlebars": { "version": "4.7.8", @@ -13597,6 +14131,7 @@ "version": "5.1.5", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", "dev": true, "license": "MIT", "dependencies": { @@ -13688,6 +14223,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" @@ -13700,6 +14236,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -13712,6 +14249,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -13736,17 +14274,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "dev": true, - "license": "ISC" - }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -13755,25 +14287,6 @@ "node": ">= 0.4" } }, - "node_modules/hdr-histogram-js": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz", - "integrity": "sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g==", - "dev": true, - "license": "BSD", - "dependencies": { - "@assemblyscript/loader": "^0.10.1", - "base64-js": "^1.2.0", - "pako": "^1.0.3" - } - }, - "node_modules/hdr-histogram-percentiles-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz", - "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==", - "dev": true, - "license": "MIT" - }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -13788,39 +14301,51 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/hosted-git-info": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", - "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", "dev": true, "license": "ISC", "dependencies": { - "lru-cache": "^7.5.1" + "lru-cache": "^6.0.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=10" } }, "node_modules/hosted-git-info/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, "engines": { - "node": ">=12" + "node": ">=10" } }, + "node_modules/hosted-git-info/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, "node_modules/hpack.js": { "version": "2.1.6", "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", "dev": true, + "license": "MIT", "dependencies": { "inherits": "^2.0.1", "obuf": "^1.0.0", @@ -13828,11 +14353,19 @@ "wbuf": "^1.1.0" } }, - "node_modules/hpack.js/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "node_modules/hpack.js/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, + "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -13847,28 +14380,17 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/hpack.js/node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", - "dev": true, "license": "MIT", "dependencies": { - "whatwg-encoding": "^1.0.5" - }, - "engines": { - "node": ">=10" + "safe-buffer": "~5.1.0" } }, "node_modules/html-entities": { @@ -13885,7 +14407,8 @@ "type": "patreon", "url": "https://patreon.com/mdevils" } - ] + ], + "license": "MIT" }, "node_modules/html-escaper": { "version": "2.0.2", @@ -13925,7 +14448,8 @@ "version": "1.2.7", "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/http-errors": { "version": "2.0.0", @@ -13944,11 +14468,22 @@ "node": ">= 0.8" } }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/http-parser-js": { "version": "0.5.8", "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/http-proxy": { "version": "1.18.1", @@ -13966,42 +14501,35 @@ } }, "node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "dev": true, "license": "MIT", "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" + "agent-base": "^7.1.0", + "debug": "^4.3.4" }, "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/http-proxy-middleware": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", - "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.0.tgz", + "integrity": "sha512-36AV1fIaI2cWRzHo+rbcxhe3M3jUDCNzc4D5zRl57sEWRAxdXYtw7FSQKYY6PDKssiAKjLYypbssHk+xs/kMXw==", "dev": true, + "license": "MIT", "dependencies": { - "@types/http-proxy": "^1.17.8", + "@types/http-proxy": "^1.17.10", + "debug": "^4.3.4", "http-proxy": "^1.18.1", "is-glob": "^4.0.1", "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" + "micromatch": "^4.0.5" }, "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "@types/express": "^4.17.13" - }, - "peerDependenciesMeta": { - "@types/express": { - "optional": true - } + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/http-signature": { @@ -14021,36 +14549,37 @@ } }, "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", "dev": true, "license": "MIT", "dependencies": { - "agent-base": "6", + "agent-base": "^7.0.2", "debug": "4" }, "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">=10.17.0" + "node": ">=8.12.0" } }, - "node_modules/humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "node_modules/hyperdyperid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", + "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", "dev": true, "license": "MIT", - "dependencies": { - "ms": "^2.0.0" + "engines": { + "node": ">=10.18" } }, "node_modules/iconv-lite": { @@ -14099,9 +14628,9 @@ "license": "BSD-3-Clause" }, "node_modules/ignore": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", "engines": { @@ -14116,9 +14645,9 @@ "license": "ISC" }, "node_modules/ignore-walk": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.4.tgz", - "integrity": "sha512-t7sv42WkwFkyKbivUCglsQW5YWMskWtbEf4MNKX5u/CCWHKSPzN4FtBQGsQZgCLbxOzpVlcbWVK5KB3auIOjSw==", + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.5.tgz", + "integrity": "sha512-VuuG0wCnjhnylG1ABXT3dAuIpTNDs/G8jlpmwXY03fXoXy/8ZK8/T+hMzt8L4WnrLCJgdybqgPagnF/f97cg3A==", "dev": true, "license": "ISC", "dependencies": { @@ -14128,32 +14657,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/ignore-walk/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/ignore-walk/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/image-size": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", @@ -14176,9 +14679,9 @@ "license": "MIT" }, "node_modules/immutable": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", - "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz", + "integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==", "dev": true, "license": "MIT" }, @@ -14199,20 +14702,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.8.19" @@ -14228,17 +14722,12 @@ "node": ">=8" } }, - "node_modules/infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "dev": true, - "license": "ISC" - }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, "license": "ISC", "dependencies": { "once": "^1.3.0", @@ -14252,9 +14741,9 @@ "license": "ISC" }, "node_modules/ini": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", - "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", + "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==", "dev": true, "license": "ISC", "engines": { @@ -14262,30 +14751,28 @@ } }, "node_modules/inquirer": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", - "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", + "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", "dev": true, "license": "MIT", "dependencies": { "ansi-escapes": "^4.2.1", - "chalk": "^4.1.1", + "chalk": "^4.1.0", "cli-cursor": "^3.1.0", "cli-width": "^3.0.0", "external-editor": "^3.0.3", "figures": "^3.0.0", - "lodash": "^4.17.21", + "lodash": "^4.17.19", "mute-stream": "0.0.8", - "ora": "^5.4.1", "run-async": "^2.4.0", - "rxjs": "^7.5.5", + "rxjs": "^6.6.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0", - "through": "^2.3.6", - "wrap-ansi": "^7.0.0" + "through": "^2.3.6" }, "engines": { - "node": ">=12.0.0" + "node": ">=8.0.0" } }, "node_modules/inquirer/node_modules/ansi-styles": { @@ -14321,6 +14808,16 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/inquirer/node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 10" + } + }, "node_modules/inquirer/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -14334,6 +14831,13 @@ "node": ">=7.0.0" } }, + "node_modules/inquirer/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, "node_modules/inquirer/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -14344,15 +14848,12 @@ "node": ">=8" } }, - "node_modules/inquirer/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "node_modules/inquirer/node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } + "license": "ISC" }, "node_modules/inquirer/node_modules/supports-color": { "version": "7.2.0", @@ -14404,6 +14905,7 @@ "version": "9.0.5", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dev": true, "license": "MIT", "dependencies": { "jsbn": "1.1.0", @@ -14413,23 +14915,12 @@ "node": ">= 12" } }, - "node_modules/ip-address/node_modules/jsbn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", - "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", - "license": "MIT" - }, - "node_modules/ip-address/node_modules/sprintf-js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "license": "BSD-3-Clause" - }, "node_modules/ipaddr.js": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10" } @@ -14501,22 +14992,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-builtin-module": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", - "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", - "dev": true, - "license": "MIT", - "dependencies": { - "builtin-modules": "^3.3.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", @@ -14531,13 +15006,16 @@ } }, "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", "dev": true, "license": "MIT", "dependencies": { - "hasown": "^2.0.0" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -14576,15 +15054,16 @@ } }, "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, "license": "MIT", "bin": { "is-docker": "cli.js" }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -14604,6 +15083,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -14622,6 +15102,25 @@ "node": ">=0.10.0" } }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-interactive": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", @@ -14651,6 +15150,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-network-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz", + "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -14688,13 +15200,13 @@ } }, "node_modules/is-path-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "integrity": "sha512-cnS56eR9SPAscL77ik76ATVqoPARTqPIVkMDVxRaWH06zT+6+CzIroYRJ0VVvm0Z1zfAvxvz9i/D3Ppjaqt5Nw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, "node_modules/is-path-in-cwd": { @@ -14738,6 +15250,7 @@ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -14758,13 +15271,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true, - "license": "MIT" - }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -14802,6 +15308,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -14875,6 +15382,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true, "license": "MIT" }, "node_modules/is-unicode-supported": { @@ -14910,22 +15418,27 @@ "license": "MIT" }, "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "dev": true, "license": "MIT", "dependencies": { - "is-docker": "^2.0.0" + "is-inside-container": "^1.0.0" }, "engines": { - "node": ">=8" + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT" + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" }, "node_modules/isbinaryfile": { "version": "4.0.10", @@ -14944,6 +15457,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, "license": "ISC" }, "node_modules/isobject": { @@ -14974,30 +15488,20 @@ } }, "node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" + "semver": "^7.5.4" }, "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "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" + "node": ">=10" } }, "node_modules/istanbul-lib-report": { @@ -15025,22 +15529,6 @@ "node": ">=8" } }, - "node_modules/istanbul-lib-report/node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/istanbul-lib-report/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -15080,9 +15568,9 @@ } }, "node_modules/istanbul-reports": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", - "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -15094,17 +15582,14 @@ } }, "node_modules/jackspeak": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", - "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" }, - "engines": { - "node": ">=14" - }, "funding": { "url": "https://github.com/sponsors/isaacs" }, @@ -15112,94 +15597,6 @@ "@pkgjs/parseargs": "^0.11.0" } }, - "node_modules/jake": { - "version": "10.8.7", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz", - "integrity": "sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "async": "^3.2.3", - "chalk": "^4.0.2", - "filelist": "^1.0.4", - "minimatch": "^3.1.2" - }, - "bin": { - "jake": "bin/cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jake/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jake/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jake/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jake/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/jake/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/jasmine": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz", @@ -15232,27 +15629,6 @@ "colors": "1.4.0" } }, - "node_modules/jasmine/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/jasmine/node_modules/jasmine-core": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz", @@ -15312,9 +15688,9 @@ } }, "node_modules/jiti": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", - "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "version": "1.21.6", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", + "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", "dev": true, "license": "MIT", "bin": { @@ -15329,23 +15705,22 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "license": "MIT", "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", "dev": true, "license": "MIT" }, @@ -15359,53 +15734,6 @@ "node": ">=12.0.0" } }, - "node_modules/jsdom": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", - "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", - "dev": true, - "license": "MIT", - "dependencies": { - "abab": "^2.0.5", - "acorn": "^8.2.4", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.3.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.1", - "domexception": "^2.0.1", - "escodegen": "^2.0.0", - "form-data": "^3.0.0", - "html-encoding-sniffer": "^2.0.1", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.5.0", - "ws": "^7.4.6", - "xml-name-validator": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "canvas": "^2.5.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -15434,11 +15762,14 @@ "license": "MIT" }, "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz", + "integrity": "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } }, "node_modules/json-schema": { "version": "0.4.0", @@ -15481,17 +15812,20 @@ } }, "node_modules/jsonc-parser": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", - "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", "license": "MIT" }, "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, "optionalDependencies": { "graceful-fs": "^4.1.6" } @@ -15552,6 +15886,13 @@ "setimmediate": "^1.0.5" } }, + "node_modules/jszip/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, "node_modules/jszip/node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", @@ -15586,9 +15927,9 @@ } }, "node_modules/karma": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.2.tgz", - "integrity": "sha512-C6SU/53LB31BEgRg+omznBEMY4SjHU3ricV6zBcAe1EeILKkeScr+fZXtaI5WyDbkVowJxxAI6h73NcFPmXolQ==", + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.4.tgz", + "integrity": "sha512-LrtUxbdvt1gOpo3gxG+VAJlJAEMhbWlM4YrFQgql98FwF7+K8K12LYO4hnDdUkNjeztYrOXEMqgTajSWgmtI/w==", "dev": true, "license": "MIT", "dependencies": { @@ -15611,7 +15952,7 @@ "qjobs": "^1.2.0", "range-parser": "^1.2.1", "rimraf": "^3.0.2", - "socket.io": "^4.4.1", + "socket.io": "^4.7.2", "source-map": "^0.6.1", "tmp": "^0.2.1", "ua-parser-js": "^0.7.30", @@ -15682,25 +16023,15 @@ "url": "https://github.com/sponsors/mattlewis92" } }, - "node_modules/karma-coverage-istanbul-reporter/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "node_modules/karma-coverage-istanbul-reporter/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, "node_modules/karma-coverage-istanbul-reporter/node_modules/istanbul-lib-source-maps": { @@ -15730,10 +16061,48 @@ "node": ">=6" } }, + "node_modules/karma-coverage-istanbul-reporter/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/karma-coverage-istanbul-reporter/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/karma-coverage-istanbul-reporter/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/karma-coverage-istanbul-reporter/node_modules/rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", "dependencies": { @@ -15743,16 +16112,77 @@ "rimraf": "bin.js" } }, - "node_modules/karma-coverage-istanbul-reporter/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/karma-coverage-istanbul-reporter/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, - "license": "BSD-3-Clause", + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/karma-coverage-istanbul-reporter/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, + "node_modules/karma-coverage/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/karma-coverage/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/karma-coverage/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/karma-coverage/node_modules/semver": { + "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" + } + }, "node_modules/karma-jasmine": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-5.1.0.tgz", @@ -15791,6 +16221,33 @@ "source-map-support": "^0.5.5" } }, + "node_modules/karma/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/karma/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/karma/node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -15803,51 +16260,54 @@ "wrap-ansi": "^7.0.0" } }, - "node_modules/karma/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "node_modules/karma/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "color-name": "~1.1.4" }, "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=7.0.0" } }, - "node_modules/karma/node_modules/mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "node_modules/karma/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true, - "license": "MIT", - "bin": { - "mime": "cli.js" + "license": "MIT" + }, + "node_modules/karma/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=4.0.0" + "node": "*" } }, - "node_modules/karma/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "node_modules/karma/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "minimist": "^1.2.6" + "glob": "^7.1.3" }, "bin": { - "mkdirp": "bin/cmd.js" + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/karma/node_modules/source-map": { @@ -15860,15 +16320,22 @@ "node": ">=0.10.0" } }, - "node_modules/karma/node_modules/tmp": { - "version": "0.2.1", + "node_modules/karma/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "license": "MIT", "dependencies": { - "rimraf": "^3.0.0" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=8.17.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/karma/node_modules/yargs": { @@ -15890,16 +16357,6 @@ "node": ">=10" } }, - "node_modules/karma/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -15930,21 +16387,12 @@ "node": ">=6" } }, - "node_modules/klona": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", - "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, "node_modules/launch-editor": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.8.1.tgz", "integrity": "sha512-elBx2l/tp9z99X5H/qev8uyDywVh0VXAwEbjk8kJhnc5grOFkGh7aW6q55me9xnYbss261XtnUrysZ+XvGbhQA==", "dev": true, + "license": "MIT", "dependencies": { "picocolors": "^1.0.0", "shell-quote": "^1.8.1" @@ -15954,6 +16402,7 @@ "version": "0.0.24", "resolved": "https://registry.npmjs.org/leek/-/leek-0.0.24.tgz", "integrity": "sha512-6PVFIYXxlYF0o6hrAsHtGpTmi06otkwNrMcmQ0K96SeSRHPREPa9J3nJZ1frliVH7XT0XFswoJFQoXsDukzGNQ==", + "dev": true, "license": "MIT", "dependencies": { "debug": "^2.1.0", @@ -15965,6 +16414,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, "license": "MIT", "dependencies": { "ms": "2.0.0" @@ -15974,13 +16424,15 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, "license": "MIT" }, "node_modules/less": { "version": "4.2.0", + "resolved": "https://registry.npmjs.org/less/-/less-4.2.0.tgz", + "integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==", "dev": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "copy-anything": "^2.0.1", "parse-node-version": "^1.0.1", @@ -16003,24 +16455,81 @@ } }, "node_modules/less-loader": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.1.0.tgz", - "integrity": "sha512-C+uDBV7kS7W5fJlUjq5mPBeBVhYpTIm5gB09APT9o3n/ILeaXVsiSFTbZpTJCJwQ/Crczfn3DmfQFwxYusWFug==", + "version": "12.2.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-12.2.0.tgz", + "integrity": "sha512-MYUxjSQSBUQmowc0l5nPieOYwMzGPUaTzB6inNW/bdPEG9zOL3eAAD1Qw5ZxSPk7we5dMojHwNODYMV1hq4EVg==", "dev": true, "license": "MIT", - "dependencies": { - "klona": "^2.0.4" - }, "engines": { - "node": ">= 14.15.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { + "@rspack/core": "0.x || 1.x", "less": "^3.5.0 || ^4.0.0", "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/less/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/less/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "license": "MIT", + "optional": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/less/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/less/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver" } }, "node_modules/less/node_modules/source-map": { @@ -16030,7 +16539,6 @@ "dev": true, "license": "BSD-3-Clause", "optional": true, - "peer": true, "engines": { "node": ">=0.10.0" } @@ -16084,37 +16592,180 @@ "dev": true, "license": "MIT" }, - "node_modules/load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", + "node_modules/listr2": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.3.tgz", + "integrity": "sha512-Lllokma2mtoniUOS94CcOErHWAug5iu7HOmDrvWgpw8jyQH2fomgB+7lZS4HWZxytUuQwkGOwe49FvwVaA85Xw==", "dev": true, "license": "MIT", "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.0.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" }, "engines": { - "node": ">=4" + "node": ">=18.0.0" } }, - "node_modules/load-json-file/node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "node_modules/listr2/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true, "license": "MIT", - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, "engines": { - "node": ">=4" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/load-json-file/node_modules/pify": { + "node_modules/listr2/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/listr2/node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "dev": true, + "license": "MIT" + }, + "node_modules/listr2/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true, + "license": "MIT" + }, + "node_modules/listr2/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/listr2/node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/lmdb": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-3.0.13.tgz", + "integrity": "sha512-UGe+BbaSUQtAMZobTb4nHvFMrmvuAQKSeaqAX2meTEQjfsbpl5sxdHD8T72OnwD4GU9uwNhYXIVe4QGs8N9Zyw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "msgpackr": "^1.10.2", + "node-addon-api": "^6.1.0", + "node-gyp-build-optional-packages": "5.2.2", + "ordered-binary": "^1.4.1", + "weak-lru-cache": "^1.2.2" + }, + "bin": { + "download-lmdb-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@lmdb/lmdb-darwin-arm64": "3.0.13", + "@lmdb/lmdb-darwin-x64": "3.0.13", + "@lmdb/lmdb-linux-arm": "3.0.13", + "@lmdb/lmdb-linux-arm64": "3.0.13", + "@lmdb/lmdb-linux-x64": "3.0.13", + "@lmdb/lmdb-win32-x64": "3.0.13" + } + }, + "node_modules/lmdb/node_modules/node-addon-api": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", + "dev": true, + "license": "MIT" + }, + "node_modules/load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/load-json-file/node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/load-json-file/node_modules/pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", @@ -16135,9 +16786,9 @@ } }, "node_modules/loader-utils": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", - "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.3.1.tgz", + "integrity": "sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==", "dev": true, "license": "MIT", "engines": { @@ -16145,22 +16796,26 @@ } }, "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "license": "MIT", "dependencies": { - "p-locate": "^4.1.0" + "p-locate": "^5.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, "license": "MIT" }, "node_modules/lodash-es": { @@ -16173,6 +16828,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", "integrity": "sha512-t3N26QR2IdSN+gqSy9Ds9pBu/J1EAFEshKlUHpJG3rvyJOYgcELIxcIeKKfZk7sjOz11cFfzJRsyFry/JyabJQ==", + "dev": true, "license": "MIT", "dependencies": { "lodash._basecopy": "^3.0.0", @@ -16183,18 +16839,21 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", "integrity": "sha512-rFR6Vpm4HeCK1WPGvjZSJ+7yik8d8PVUdCJx5rT2pogG4Ve/2ZS7kfmO5l5T2o5V2mqlNIfSF5MZlr1+xOoYQQ==", + "dev": true, "license": "MIT" }, "node_modules/lodash._bindcallback": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz", "integrity": "sha512-2wlI0JRAGX8WEf4Gm1p/mv/SZ+jLijpj0jyaE/AXeuQphzCgD8ZQW4oSpoN8JAopujOFGU3KMuq7qfHBWlGpjQ==", + "dev": true, "license": "MIT" }, "node_modules/lodash._createassigner": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz", "integrity": "sha512-LziVL7IDnJjQeeV95Wvhw6G28Z8Q6da87LWKOPWmzBLv4u6FAT/x5v00pyGW0u38UoogNF2JnD3bGgZZDaNEBw==", + "dev": true, "license": "MIT", "dependencies": { "lodash._bindcallback": "^3.0.0", @@ -16206,18 +16865,21 @@ "version": "3.9.1", "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", "integrity": "sha512-RrL9VxMEPyDMHOd9uFbvMe8X55X16/cGM5IgOKgRElQZutpX89iS6vwl64duTV1/16w5JY7tuFNXqoekmh1EmA==", + "dev": true, "license": "MIT" }, "node_modules/lodash._isiterateecall": { "version": "3.0.9", "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", "integrity": "sha512-De+ZbrMu6eThFti/CSzhRvTKMgQToLxbij58LMfM8JnYDNSOjkjTCIaa8ixglOeGh2nyPlakbt5bJWJ7gvpYlQ==", + "dev": true, "license": "MIT" }, "node_modules/lodash.assign": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-3.2.0.tgz", "integrity": "sha512-/VVxzgGBmbphasTg51FrztxQJ/VgAUpol6zmJuSVSGcNg4g7FA4z7rQV8Ovr9V3vFBNWZhvKWHfpAytjTVUfFA==", + "dev": true, "license": "MIT", "dependencies": { "lodash._baseassign": "^3.0.0", @@ -16236,12 +16898,14 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==", + "dev": true, "license": "MIT" }, "node_modules/lodash.isarray": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", "integrity": "sha512-JwObCrNJuT0Nnbuecmqr5DgtuBppuCvGD9lxjFpAzwnVtdGoDQ1zig+5W8k5/6Gcn0gZ3936HDAlGd28i7sOGQ==", + "dev": true, "license": "MIT" }, "node_modules/lodash.ismatch": { @@ -16255,6 +16919,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", "integrity": "sha512-CuBsapFjcubOGMn3VD+24HOAPxM79tH+V6ivJL3CHYjtrawauDJHUk//Yew9Hvc6e9rbCrURGk8z6PC+8WJBfQ==", + "dev": true, "license": "MIT", "dependencies": { "lodash._getnative": "^3.0.0", @@ -16273,6 +16938,7 @@ "version": "3.6.1", "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", "integrity": "sha512-L4/arjjuq4noiUJpt3yS6KIKDtJwNe2fIYgMqyYYKoeIfV1iEqvPwhCx23o+R9dzouGihDAPN1dTIRWa7zk8tw==", + "dev": true, "license": "MIT" }, "node_modules/log-symbols": { @@ -16334,6 +17000,12 @@ "node": ">=7.0.0" } }, + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, "node_modules/log-symbols/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -16355,311 +17027,306 @@ "node": ">=8" } }, - "node_modules/log4js": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.9.1.tgz", - "integrity": "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==", + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "date-format": "^4.0.14", - "debug": "^4.3.4", - "flatted": "^3.2.7", - "rfdc": "^1.3.0", - "streamroller": "^3.1.5" + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" }, "engines": { - "node": ">=8.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "node_modules/log-update/node_modules/ansi-escapes": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", + "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "yallist": "^3.0.2" + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/macos-release": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.5.1.tgz", - "integrity": "sha512-DXqXhEM7gW59OjZO8NIjBCz9AQ1BEMrfiOAl4AYByHCtVHRF4KoGNO8mqQeM8lRCtQe/UnJ4imO/d2HdkKsd+A==", + "node_modules/log-update/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, "license": "MIT", "engines": { - "node": ">=6" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/magic-string": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.1.tgz", - "integrity": "sha512-mbVKXPmS0z0G4XqFDCTllmDQ6coZzn94aMlb0o/A4HEHJCKcanlDZwYJgwnkmgD3jyWhUgj9VsPrfd972yPffA==", + "node_modules/log-update/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - }, "engines": { "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "node_modules/log-update/node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", "dev": true, "license": "MIT", "dependencies": { - "pify": "^4.0.1", - "semver": "^5.6.0" + "restore-cursor": "^5.0.0" }, "engines": { - "node": ">=6" - } - }, - "node_modules/make-dir/node_modules/semver": { - "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" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "node_modules/log-update/node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", "dev": true, - "license": "ISC" + "license": "MIT" }, - "node_modules/make-fetch-happen": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", - "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", + "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^16.1.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^2.0.3", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^9.0.0" + "get-east-asian-width": "^1.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-fetch-happen/node_modules/@npmcli/fs": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", - "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", + "node_modules/log-update/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "@gar/promisify": "^1.1.3", - "semver": "^7.3.5" + "mimic-function": "^5.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-fetch-happen/node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "node_modules/log-update/node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", "dev": true, "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, "engines": { - "node": ">= 10" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-fetch-happen/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", + "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/cacache": { - "version": "16.1.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", - "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/fs": "^2.1.0", - "@npmcli/move-file": "^2.0.0", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "glob": "^8.0.1", - "infer-owner": "^1.0.4", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "mkdirp": "^1.0.4", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^9.0.0", - "tar": "^6.1.11", - "unique-filename": "^2.0.0" + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "node_modules/make-fetch-happen/node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "node_modules/log-update/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "minipass": "^3.0.0" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">= 8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-fetch-happen/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "node_modules/log-update/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "ansi-regex": "^6.0.1" }, "engines": { "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/make-fetch-happen/node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", "dev": true, "license": "MIT", "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">= 6" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/make-fetch-happen/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "node_modules/log4js": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.9.1.tgz", + "integrity": "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==", "dev": true, - "license": "ISC", + "license": "Apache-2.0", + "dependencies": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "flatted": "^3.2.7", + "rfdc": "^1.3.0", + "streamroller": "^3.1.5" + }, "engines": { - "node": ">=12" + "node": ">=8.0" } }, - "node_modules/make-fetch-happen/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" + "yallist": "^3.0.2" } }, - "node_modules/make-fetch-happen/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "node_modules/macos-release": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.5.1.tgz", + "integrity": "sha512-DXqXhEM7gW59OjZO8NIjBCz9AQ1BEMrfiOAl4AYByHCtVHRF4KoGNO8mqQeM8lRCtQe/UnJ4imO/d2HdkKsd+A==", "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-fetch-happen/node_modules/ssri": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", - "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", + "node_modules/magic-string": { + "version": "0.30.11", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", + "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "minipass": "^3.1.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "@jridgewell/sourcemap-codec": "^1.5.0" } }, - "node_modules/make-fetch-happen/node_modules/unique-filename": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", - "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "unique-slug": "^3.0.0" + "semver": "^7.5.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-fetch-happen/node_modules/unique-slug": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", - "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/make-fetch-happen": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz", + "integrity": "sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==", "dev": true, "license": "ISC", "dependencies": { - "imurmurhash": "^0.1.4" + "@npmcli/agent": "^2.0.0", + "cacache": "^18.0.0", + "http-cache-semantics": "^4.1.1", + "is-lambda": "^1.0.1", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "proc-log": "^4.2.0", + "promise-retry": "^2.0.1", + "ssri": "^10.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/make-fetch-happen/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, "node_modules/map-obj": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", @@ -16684,16 +17351,23 @@ } }, "node_modules/memfs": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", - "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.11.1.tgz", + "integrity": "sha512-LZcMTBAgqUUKNXZagcZxvXXfgF1bHX7Y7nQ0QyEiNbRJgE29GhgPd8Yna1VQcLlPiHt/5RFJMWYN9Uv/VPNvjQ==", "dev": true, - "license": "Unlicense", + "license": "Apache-2.0", "dependencies": { - "fs-monkey": "^1.0.4" + "@jsonjoy.com/json-pack": "^1.0.3", + "@jsonjoy.com/util": "^1.3.0", + "tree-dump": "^1.0.1", + "tslib": "^2.0.0" }, "engines": { "node": ">= 4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" } }, "node_modules/meow": { @@ -16722,46 +17396,67 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/meow/node_modules/hosted-git-info": { + "node_modules/meow/node_modules/find-up": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/meow/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/meow/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true, - "license": "ISC", + "license": "ISC" + }, + "node_modules/meow/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" + "p-locate": "^4.1.0" }, "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/meow/node_modules/normalize-package-data": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "node_modules/meow/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" + "p-try": "^2.0.0" }, "engines": { - "node": ">=10" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" } }, "node_modules/meow/node_modules/read-pkg": { @@ -16808,13 +17503,6 @@ "node": ">=8" } }, - "node_modules/meow/node_modules/read-pkg/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true, - "license": "ISC" - }, "node_modules/meow/node_modules/read-pkg/node_modules/normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -16828,16 +17516,6 @@ "validate-npm-package-license": "^3.0.1" } }, - "node_modules/meow/node_modules/read-pkg/node_modules/semver": { - "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" - } - }, "node_modules/meow/node_modules/read-pkg/node_modules/type-fest": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", @@ -16848,6 +17526,16 @@ "node": ">=8" } }, + "node_modules/meow/node_modules/semver": { + "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" + } + }, "node_modules/meow/node_modules/type-fest": { "version": "0.18.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", @@ -16861,33 +17549,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/meow/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/meow/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, "license": "MIT" }, "node_modules/merge2": { @@ -16926,42 +17599,57 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { "node": ">=8.6" } }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "license": "MIT", - "bin": { - "mime": "cli.js" - }, "engines": { - "node": ">=4" - } - }, + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -16971,6 +17659,7 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, "license": "MIT", "dependencies": { "mime-db": "1.52.0" @@ -16988,6 +17677,19 @@ "node": ">=6" } }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/mimic-response": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", @@ -17012,13 +17714,14 @@ } }, "node_modules/mini-css-extract-plugin": { - "version": "2.7.6", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.6.tgz", - "integrity": "sha512-Qk7HcgaPkGG6eD77mLvZS1nmxlao3j+9PkrT9Uc7HAE1id3F41+DdBRYRYkbyfNRGzm8/YWtzhw7nVPmwhqTQw==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.0.tgz", + "integrity": "sha512-Zs1YsZVfemekSZG+44vBsYTLQORkPMwnlv+aehcxK/NLKC+EGhDB39/YePYYqx/sTk6NnYpuqikhSn7+JIevTA==", "dev": true, "license": "MIT", "dependencies": { - "schema-utils": "^4.0.0" + "schema-utils": "^4.0.0", + "tapable": "^2.2.1" }, "engines": { "node": ">= 12.13.0" @@ -17035,24 +17738,30 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -17084,85 +17793,46 @@ } }, "node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "license": "ISC", - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, "engines": { - "node": ">= 8" + "node": ">=16 || 14 >=14.17" } }, - "node_modules/minipass-collect/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "node_modules/minipass-collect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", "dev": true, "license": "ISC", "dependencies": { - "yallist": "^4.0.0" + "minipass": "^7.0.3" }, "engines": { - "node": ">=8" + "node": ">=16 || 14 >=14.17" } }, - "node_modules/minipass-collect/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, "node_modules/minipass-fetch": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", - "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.5.tgz", + "integrity": "sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg==", "dev": true, "license": "MIT", "dependencies": { - "minipass": "^3.1.6", + "minipass": "^7.0.3", "minipass-sized": "^1.0.3", "minizlib": "^2.1.2" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" }, "optionalDependencies": { "encoding": "^0.1.13" } }, - "node_modules/minipass-fetch/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-fetch/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, "node_modules/minipass-flush": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", @@ -17196,37 +17866,6 @@ "dev": true, "license": "ISC" }, - "node_modules/minipass-json-stream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", - "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", - "dev": true, - "license": "MIT", - "dependencies": { - "jsonparse": "^1.3.1", - "minipass": "^3.0.0" - } - }, - "node_modules/minipass-json-stream/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-json-stream/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, "node_modules/minipass-pipeline": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", @@ -17297,6 +17936,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, "license": "MIT", "dependencies": { "minipass": "^3.0.0", @@ -17310,6 +17950,7 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, "license": "ISC", "dependencies": { "yallist": "^4.0.0" @@ -17322,18 +17963,20 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, "license": "ISC" }, "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, "bin": { "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" } }, "node_modules/mkdirp-classic": { @@ -17354,9 +17997,9 @@ } }, "node_modules/mrmime": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", - "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", + "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", "dev": true, "license": "MIT", "engines": { @@ -17367,13 +18010,48 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, "license": "MIT" }, + "node_modules/msgpackr": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.0.tgz", + "integrity": "sha512-I8qXuuALqJe5laEBYoFykChhSXLikZmUhccjGsPuSJ/7uPip2TJ7lwdIQwWSAi0jGZDXv4WOP8Qg65QZRuXxXw==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "msgpackr-extract": "^3.0.2" + } + }, + "node_modules/msgpackr-extract": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz", + "integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build-optional-packages": "5.2.2" + }, + "bin": { + "download-msgpackr-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3" + } + }, "node_modules/multicast-dns": { "version": "7.2.5", "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", "dev": true, + "license": "MIT", "dependencies": { "dns-packet": "^5.2.2", "thunky": "^1.0.2" @@ -17383,10 +18061,14 @@ } }, "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "license": "ISC" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", + "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } }, "node_modules/nanoid": { "version": "3.3.7", @@ -17475,6 +18157,14 @@ "node": ">= 4.4.x" } }, + "node_modules/needle/node_modules/sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", + "dev": true, + "license": "ISC", + "optional": true + }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -17496,6 +18186,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4.0" @@ -17519,28 +18210,29 @@ } }, "node_modules/ngx-cookie-service": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/ngx-cookie-service/-/ngx-cookie-service-16.1.0.tgz", - "integrity": "sha512-FrzMjsGCHZCd2sEucigMaGyzImBL0l6gwWn6jmLBhcNVx0D7P8Yvtgk9aUptlqBrVKy4c2upglSa3Ogv3679bw==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/ngx-cookie-service/-/ngx-cookie-service-18.0.0.tgz", + "integrity": "sha512-hkkUckzZTXXWtFgvVkT2hg6mwYMLXioXDZWBsVCOy9gYkADjsj0N5VViO7eo2izQ0VcMPd/Etog1trf/T4oZMQ==", "license": "MIT", "dependencies": { - "tslib": "^2.0.0" + "tslib": "^2.6.2" }, "peerDependencies": { - "@angular/common": "^16.0.0", - "@angular/core": "^16.0.0" + "@angular/common": "^18.0.0-rc.0", + "@angular/core": "^18.0.0-rc.0" } }, "node_modules/ngx-device-detector": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/ngx-device-detector/-/ngx-device-detector-6.0.2.tgz", - "integrity": "sha512-+zaYUYGepNE4vMBA/6kyc1rhuUm5uU4cwbvFEEy0gAY4OarId15zwcb1iyvQbyrLCXhZW0DrPZTBoQxzp7dyVw==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/ngx-device-detector/-/ngx-device-detector-8.0.0.tgz", + "integrity": "sha512-ik6EwUKnlN+xwoWHzyJp5+V+QRWYrmpTqAvRwa16xBnAVd7/i3jElN7MZjs/InwcYz7AW3XcSNeu+XRvtHgb9w==", + "license": "MIT", "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { - "@angular/common": "^16.0.0", - "@angular/core": "^16.0.0" + "@angular/common": "^18.0.0", + "@angular/core": "^18.0.0" } }, "node_modules/ngx-spinner": { @@ -17557,10 +18249,26 @@ "@angular/core": ">=15.0.0" } }, + "node_modules/nice-napi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", + "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "!win32" + ], + "dependencies": { + "node-addon-api": "^3.0.0", + "node-gyp-build": "^4.2.2" + } + }, "node_modules/node-abi": { - "version": "3.65.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.65.0.tgz", - "integrity": "sha512-ThjYBfoDNr08AWx6hGaRbfPwxKV9kVzAzOzlLKbk2CuqXE2xnCh+cbAGnwM3t8Lq4v9rUB7VfondlkBckcJrVA==", + "version": "3.67.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.67.0.tgz", + "integrity": "sha512-bLn/fU/ALVBE9wj+p4Y21ZJWYFjUXLXPi/IewyLZkx3ApxKDNBWCKdReeKOtD8dWpOdDCeMyLh6ZewzcLsG2Nw==", "dev": true, "license": "MIT", "dependencies": { @@ -17575,7 +18283,8 @@ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/node-fetch": { "version": "2.7.0", @@ -17598,108 +18307,125 @@ } } }, - "node_modules/node-fetch/node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true, - "license": "MIT" - }, - "node_modules/node-fetch/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/node-fetch/node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "node_modules/node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", "dev": true, + "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { "node": ">= 6.13.0" } }, "node_modules/node-gyp": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.1.tgz", - "integrity": "sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.2.0.tgz", + "integrity": "sha512-sp3FonBAaFe4aYTcFdZUn2NYkbP7xroPGYvQmP4Nl5PxamznItBnNCgjrVTKrEfQynInMsJvZrdmqUnysCJ8rw==", "dev": true, "license": "MIT", "dependencies": { "env-paths": "^2.2.0", "exponential-backoff": "^3.1.1", - "glob": "^7.1.4", + "glob": "^10.3.10", "graceful-fs": "^4.2.6", - "make-fetch-happen": "^10.0.3", - "nopt": "^6.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", + "make-fetch-happen": "^13.0.0", + "nopt": "^7.0.0", + "proc-log": "^4.1.0", "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" + "tar": "^6.2.1", + "which": "^4.0.0" }, "bin": { "node-gyp": "bin/node-gyp.js" }, "engines": { - "node": "^12.13 || ^14.13 || >=16" + "node": "^16.14.0 || >=18.0.0" } }, "node_modules/node-gyp-build": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.0.tgz", - "integrity": "sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==", + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.2.tgz", + "integrity": "sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==", "dev": true, "license": "MIT", + "optional": true, "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", "node-gyp-build-test": "build-test.js" } }, + "node_modules/node-gyp-build-optional-packages": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", + "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.1" + }, + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" + } + }, "node_modules/node-gyp/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, "license": "ISC", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, - "engines": { - "node": "*" + "bin": { + "glob": "dist/esm/bin.mjs" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/node-html-parser": { - "version": "5.4.2", - "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-5.4.2.tgz", - "integrity": "sha512-RaBPP3+51hPne/OolXxcz89iYvQvKOydaqoePpOgXcrOKZhjVIzmpKZz+Hd/RBO2/zN2q6CNJhQzucVz+u3Jyw==", + "node_modules/node-gyp/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "dev": true, - "license": "MIT", - "dependencies": { - "css-select": "^4.2.1", - "he": "1.2.0" + "license": "ISC", + "engines": { + "node": ">=16" + } + }, + "node_modules/node-gyp/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/node-html-parser": { + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-5.4.2.tgz", + "integrity": "sha512-RaBPP3+51hPne/OolXxcz89iYvQvKOydaqoePpOgXcrOKZhjVIzmpKZz+Hd/RBO2/zN2q6CNJhQzucVz+u3Jyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-select": "^4.2.1", + "he": "1.2.0" } }, "node_modules/node-html-parser/node_modules/css-select": { @@ -17776,9 +18502,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", "dev": true, "license": "MIT" }, @@ -17811,6 +18537,17 @@ "url": "https://opencollective.com/nodemon" } }, + "node_modules/nodemon/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/nodemon/node_modules/debug": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", @@ -17821,6 +18558,19 @@ "ms": "^2.1.1" } }, + "node_modules/nodemon/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/nodemon/node_modules/semver": { "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", @@ -17832,35 +18582,35 @@ } }, "node_modules/nopt": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", - "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", + "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", "dev": true, "license": "ISC", "dependencies": { - "abbrev": "^1.0.0" + "abbrev": "^2.0.0" }, "bin": { "nopt": "bin/nopt.js" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/normalize-package-data": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-5.0.0.tgz", - "integrity": "sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "hosted-git-info": "^6.0.0", - "is-core-module": "^2.8.1", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4" + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=10" } }, "node_modules/normalize-path": { @@ -17884,9 +18634,9 @@ } }, "node_modules/npm-bundled": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.0.tgz", - "integrity": "sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.1.tgz", + "integrity": "sha512-+AvaheE/ww1JEwRHOrn4WHNzOxGtVp+adrg2AeZS/7KuxGUYFuBta98wYpfHBbJp6Tg6j1NKSEVHNcfZzJHQwQ==", "dev": true, "license": "ISC", "dependencies": { @@ -17920,163 +18670,95 @@ } }, "node_modules/npm-package-arg": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz", - "integrity": "sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==", + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.2.tgz", + "integrity": "sha512-IGN0IAwmhDJwy13Wc8k+4PEbTPhpJnMtfR53ZbOyjkvmEcLS4nCwp6mvMWjS5sUjeiW3mpx6cHmuhKEu9XmcQw==", "dev": true, "license": "ISC", "dependencies": { - "hosted-git-info": "^6.0.0", - "proc-log": "^3.0.0", + "hosted-git-info": "^7.0.0", + "proc-log": "^4.0.0", "semver": "^7.3.5", "validate-npm-package-name": "^5.0.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/npm-packlist": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-7.0.4.tgz", - "integrity": "sha512-d6RGEuRrNS5/N84iglPivjaJPxhDbZmlbTwTDX2IbcRHG5bZCdtysYMhwiPvcF4GisXHGn7xsxv+GQ7T/02M5Q==", + "node_modules/npm-package-arg/node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", "dev": true, "license": "ISC", "dependencies": { - "ignore-walk": "^6.0.0" + "lru-cache": "^10.0.1" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/npm-pick-manifest": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-8.0.1.tgz", - "integrity": "sha512-mRtvlBjTsJvfCCdmPtiu2bdlx8d/KXtF7yNXNWe7G0Z36qWA9Ny5zXsI2PfBZEv7SXgoxTmNaTzGSbbzDZChoA==", + "node_modules/npm-package-arg/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true, - "license": "ISC", - "dependencies": { - "npm-install-checks": "^6.0.0", - "npm-normalize-package-bin": "^3.0.0", - "npm-package-arg": "^10.0.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } + "license": "ISC" }, - "node_modules/npm-registry-fetch": { - "version": "14.0.5", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-14.0.5.tgz", - "integrity": "sha512-kIDMIo4aBm6xg7jOttupWZamsZRkAqMqwqqbVXnUqstY5+tapvv6bkH/qMR76jdgV+YljEUCyWx3hRYMrJiAgA==", + "node_modules/npm-packlist": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-8.0.2.tgz", + "integrity": "sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA==", "dev": true, "license": "ISC", "dependencies": { - "make-fetch-happen": "^11.0.0", - "minipass": "^5.0.0", - "minipass-fetch": "^3.0.0", - "minipass-json-stream": "^1.0.1", - "minizlib": "^2.1.2", - "npm-package-arg": "^10.0.0", - "proc-log": "^3.0.0" + "ignore-walk": "^6.0.4" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm-registry-fetch/node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 10" - } - }, - "node_modules/npm-registry-fetch/node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "node_modules/npm-pick-manifest": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.0.1.tgz", + "integrity": "sha512-Udm1f0l2nXb3wxDpKjfohwgdFUSV50UVwzEIpDXVsbDMXVIEF81a/i0UhuQbhrPMMmdiq3+YMFLFIRVLs3hxQw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^11.0.0", + "semver": "^7.3.5" }, "engines": { - "node": ">= 6" - } - }, - "node_modules/npm-registry-fetch/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/npm-registry-fetch/node_modules/make-fetch-happen": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", - "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", + "node_modules/npm-registry-fetch": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-17.1.0.tgz", + "integrity": "sha512-5+bKQRH0J1xG1uZ1zMNvxW0VEyoNWgJpY9UDuluPFLKDfJ9u2JmmjmTJV1srBGQOROfdBMiVvnH2Zvpbm+xkVA==", "dev": true, "license": "ISC", "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^17.0.0", - "http-cache-semantics": "^4.1.1", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^5.0.0", + "@npmcli/redact": "^2.0.0", + "jsonparse": "^1.3.1", + "make-fetch-happen": "^13.0.0", + "minipass": "^7.0.2", "minipass-fetch": "^3.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^10.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-registry-fetch/node_modules/minipass-fetch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", - "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", - "dev": true, - "license": "MIT", - "dependencies": { - "minipass": "^7.0.3", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "minizlib": "^2.1.2", + "npm-package-arg": "^11.0.0", + "proc-log": "^4.0.0" }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/npm-registry-fetch/node_modules/minipass-fetch/node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", - "dev": true, - "license": "ISC", "engines": { - "node": ">=16 || 14 >=14.17" + "node": "^16.14.0 || >=18.0.0" } }, "node_modules/npm-run-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.0.0" @@ -18099,22 +18781,6 @@ "npm-watch": "cli.js" } }, - "node_modules/npmlog": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", - "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", - "dev": true, - "license": "ISC", - "dependencies": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", - "set-blocking": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -18128,312 +18794,297 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, - "node_modules/nwsapi": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", - "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==", + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", "dev": true, - "license": "MIT" + "license": "Apache-2.0", + "engines": { + "node": "*" + } }, - "node_modules/nx": { - "version": "16.5.1", - "resolved": "https://registry.npmjs.org/nx/-/nx-16.5.1.tgz", - "integrity": "sha512-I3hJRE4hG7JWAtncWwDEO3GVeGPpN0TtM8xH5ArZXyDuVeTth/i3TtJzdDzqXO1HHtIoAQN0xeq4n9cLuMil5g==", + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true, - "hasInstallScript": true, "license": "MIT", - "dependencies": { - "@nrwl/tao": "16.5.1", - "@parcel/watcher": "2.0.4", - "@yarnpkg/lockfile": "^1.1.0", - "@yarnpkg/parsers": "3.0.0-rc.46", - "@zkochan/js-yaml": "0.0.6", - "axios": "^1.0.0", - "chalk": "^4.1.0", - "cli-cursor": "3.1.0", - "cli-spinners": "2.6.1", - "cliui": "^7.0.2", - "dotenv": "~10.0.0", - "enquirer": "~2.3.6", - "fast-glob": "3.2.7", - "figures": "3.2.0", - "flat": "^5.0.2", - "fs-extra": "^11.1.0", - "glob": "7.1.4", - "ignore": "^5.0.4", - "js-yaml": "4.1.0", - "jsonc-parser": "3.2.0", - "lines-and-columns": "~2.0.3", - "minimatch": "3.0.5", - "npm-run-path": "^4.0.1", - "open": "^8.4.0", - "semver": "7.5.3", - "string-width": "^4.2.3", - "strong-log-transformer": "^2.1.0", - "tar-stream": "~2.2.0", - "tmp": "~0.2.1", - "tsconfig-paths": "^4.1.2", - "tslib": "^2.3.0", - "v8-compile-cache": "2.3.0", - "yargs": "^17.6.2", - "yargs-parser": "21.1.1" - }, - "bin": { - "nx": "bin/nx.js" - }, - "optionalDependencies": { - "@nx/nx-darwin-arm64": "16.5.1", - "@nx/nx-darwin-x64": "16.5.1", - "@nx/nx-freebsd-x64": "16.5.1", - "@nx/nx-linux-arm-gnueabihf": "16.5.1", - "@nx/nx-linux-arm64-gnu": "16.5.1", - "@nx/nx-linux-arm64-musl": "16.5.1", - "@nx/nx-linux-x64-gnu": "16.5.1", - "@nx/nx-linux-x64-musl": "16.5.1", - "@nx/nx-win32-arm64-msvc": "16.5.1", - "@nx/nx-win32-x64-msvc": "16.5.1" - }, - "peerDependencies": { - "@swc-node/register": "^1.4.2", - "@swc/core": "^1.2.173" - }, - "peerDependenciesMeta": { - "@swc-node/register": { - "optional": true - }, - "@swc/core": { - "optional": true - } + "engines": { + "node": ">=0.10.0" } }, - "node_modules/nx/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", "dev": true, "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/nx/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true, - "license": "Python-2.0" + "license": "MIT", + "engines": { + "node": ">= 0.4" + } }, - "node_modules/nx/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/nx/node_modules/cli-spinners": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", - "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", "dev": true, "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, "engines": { - "node": ">=6" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/nx/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/nx/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", "dev": true, "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" }, "engines": { - "node": ">=7.0.0" + "node": ">= 0.4" } }, - "node_modules/nx/node_modules/fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "node_modules/object.values": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", "dev": true, "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/nx/node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true, + "license": "MIT" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dev": true, "license": "MIT", "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "ee-first": "1.1.1" }, "engines": { - "node": ">=14.14" + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" } }, - "node_modules/nx/node_modules/glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, "license": "ISC", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" }, "engines": { - "node": "*" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/nx/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/open": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", + "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", "dev": true, "license": "MIT", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^3.1.0" + }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/nx/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "license": "MIT", "dependencies": { - "argparse": "^2.0.1" + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/nx/node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true, - "license": "MIT" - }, - "node_modules/nx/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", "license": "MIT", "dependencies": { - "universalify": "^2.0.0" + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/nx/node_modules/lines-and-columns": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.4.tgz", - "integrity": "sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==", - "dev": true, + "node_modules/ora/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/nx/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "license": "ISC", + "node_modules/ora/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/nx/node_modules/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", - "dev": true, - "license": "ISC", + "node_modules/ora/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" + "color-name": "~1.1.4" }, "engines": { - "node": "*" + "node": ">=7.0.0" } }, - "node_modules/nx/node_modules/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, + "node_modules/ora/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/ora/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/nx/node_modules/supports-color": { + "node_modules/ora/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -18442,2686 +19093,3012 @@ "node": ">=8" } }, - "node_modules/nx/node_modules/tmp": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", - "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "node_modules/ordered-binary": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.5.1.tgz", + "integrity": "sha512-5VyHfHY3cd0iza71JepYG50My+YUbrFtGoUz2ooEydPyPM7Aai/JW098juLr+RG6+rDJuzNNTsEQu2DZa1A41A==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.14" - } + "license": "MIT" }, - "node_modules/nx/node_modules/tsconfig-paths": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", - "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "node_modules/os-name": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/os-name/-/os-name-4.0.1.tgz", + "integrity": "sha512-xl9MAoU97MH1Xt5K9ERft2YfCAoaO6msy1OBA0ozxEC0x0TmIoE6K3QvgJMMZA9yKGLmHXNY/YZoDbiGDj4zYw==", "dev": true, "license": "MIT", "dependencies": { - "json5": "^2.2.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" + "macos-release": "^2.5.0", + "windows-release": "^4.0.0" }, "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/nx/node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", "dev": true, "license": "MIT", "engines": { - "node": ">= 10.0.0" + "node": ">=0.10.0" } }, - "node_modules/nx/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "*" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "license": "MIT", + "node": ">=10" + }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, "engines": { - "node": ">= 0.4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/object-path": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.11.8.tgz", - "integrity": "sha512-YJjNZrlXJFM42wTBn6zgOJVar9KFJvzx6sTWDte8sWZF//cnjl0BxHNpfZx+ZffXX63A9q0b1zsFiBX4g4X5KA==", + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", "dev": true, "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, "engines": { - "node": ">= 10.12.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "node_modules/p-retry": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.0.tgz", + "integrity": "sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" + "@types/retry": "0.12.2", + "is-network-error": "^1.0.0", + "retry": "^0.13.1" }, "engines": { - "node": ">= 0.4" + "node": ">=16.17" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/object.fromentries": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", - "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "node_modules/p-retry/node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "dev": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 4" } }, - "node_modules/object.groupby": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", - "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2" - }, "engines": { - "node": ">= 0.4" + "node": ">=6" } }, - "node_modules/object.values": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", - "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", + "node_modules/pac-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.2.tgz", + "integrity": "sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.5", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.4" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 14" } }, - "node_modules/obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "node_modules/pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", "dev": true, "license": "MIT", "dependencies": { - "ee-first": "1.1.1" + "degenerator": "^5.0.0", + "netmask": "^2.0.2" }, "engines": { - "node": ">= 0.8" + "node": ">= 14" } }, - "node_modules/on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "node_modules/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", "dev": true, - "engines": { - "node": ">= 0.8" - } + "license": "BlueOak-1.0.0" }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "node_modules/pacote": { + "version": "18.0.6", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-18.0.6.tgz", + "integrity": "sha512-+eK3G27SMwsB8kLIuj4h1FUhHtwiEUo21Tw8wNjmvdlpOEr613edv+8FUsTj/4F/VN5ywGE19X18N7CC2EJk6A==", + "dev": true, "license": "ISC", "dependencies": { - "wrappy": "1" + "@npmcli/git": "^5.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/package-json": "^5.1.0", + "@npmcli/promise-spawn": "^7.0.0", + "@npmcli/run-script": "^8.0.0", + "cacache": "^18.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^11.0.0", + "npm-packlist": "^8.0.0", + "npm-pick-manifest": "^9.0.0", + "npm-registry-fetch": "^17.0.0", + "proc-log": "^4.0.0", + "promise-retry": "^2.0.1", + "sigstore": "^2.2.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "bin/index.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true, + "license": "(MIT AND Zlib)" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, "license": "MIT", "dependencies": { - "mimic-fn": "^2.1.0" + "callsites": "^3.0.0" }, "engines": { "node": ">=6" + } + }, + "node_modules/parse-imports": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/parse-imports/-/parse-imports-2.1.1.tgz", + "integrity": "sha512-TDT4HqzUiTMO1wJRwg/t/hYk8Wdp3iF/ToMIlAoVQfL1Xs/sTxq1dKWSMjMbQmIarfWKymOyly40+zmPHXMqCA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "es-module-lexer": "^1.5.3", + "slashes": "^3.0.12" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">= 18" } }, - "node_modules/open": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", - "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "license": "MIT", "dependencies": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" }, "engines": { - "node": ">=12" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "node_modules/parse-json/node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", "dev": true, "license": "MIT", - "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" - }, "engines": { - "node": ">= 0.8.0" + "node": ">= 0.10" } }, - "node_modules/ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "devOptional": true, "license": "MIT", "dependencies": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" + "entities": "^4.4.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/ora/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/parse5-html-rewriting-stream": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-7.0.0.tgz", + "integrity": "sha512-mazCyGWkmCRWDI15Zp+UiCqMp/0dgEmkZRvhlsqqKYr4SsVm/TvnSpD9fCvqCA2zoWJcfRym846ejWBBHRiYEg==", + "dev": true, "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" + "entities": "^4.3.0", + "parse5": "^7.0.0", + "parse5-sax-parser": "^7.0.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/ora/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/parse5-sax-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-7.0.0.tgz", + "integrity": "sha512-5A+v2SNsq8T6/mG3ahcz8ZtQ0OUFTatxPbeidoMB7tkJSGDY3tdfl4MHovtLQHkEn5CGxijNWRQHhRQ6IRpXKg==", + "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" + "parse5": "^7.0.0" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/ora/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, "engines": { - "node": ">=7.0.0" + "node": ">= 0.8" } }, - "node_modules/ora/node_modules/has-flag": { + "node_modules/path-exists": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/ora/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/os-name": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/os-name/-/os-name-4.0.1.tgz", - "integrity": "sha512-xl9MAoU97MH1Xt5K9ERft2YfCAoaO6msy1OBA0ozxEC0x0TmIoE6K3QvgJMMZA9yKGLmHXNY/YZoDbiGDj4zYw==", + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", + "dev": true, + "license": "(WTFPL OR MIT)" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "macos-release": "^2.5.0", - "windows-release": "^4.0.0" + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.18" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true, + "license": "MIT" + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, "engines": { - "node": ">=6" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "dev": true, "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", "dev": true, "license": "MIT", - "dependencies": { - "aggregate-error": "^3.0.0" - }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/p-retry": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", - "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", "dev": true, + "license": "MIT", "dependencies": { - "@types/retry": "0.12.0", - "retry": "^0.13.1" + "pinkie": "^2.0.0" }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/p-retry/node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "node_modules/piscina": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.6.1.tgz", + "integrity": "sha512-z30AwWGtQE+Apr+2WBZensP2lIvwoaMcOPkQlIEmSGMJNUvaYACylPYrQM6wSdUNJlnDVMSpLv7xTMJqlVshOA==", "dev": true, - "engines": { - "node": ">= 4" + "license": "MIT", + "optionalDependencies": { + "nice-napi": "^1.0.2" } }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "node_modules/pkg-dir": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", "dev": true, "license": "MIT", + "dependencies": { + "find-up": "^6.3.0" + }, "engines": { - "node": ">=6" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/pac-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.2.tgz", - "integrity": "sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==", + "node_modules/pkg-dir/node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "dev": true, "license": "MIT", "dependencies": { - "@tootallnate/quickjs-emscripten": "^0.23.0", - "agent-base": "^7.0.2", - "debug": "^4.3.4", - "get-uri": "^6.0.1", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.5", - "pac-resolver": "^7.0.1", - "socks-proxy-agent": "^8.0.4" + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" }, "engines": { - "node": ">= 14" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/pac-proxy-agent/node_modules/agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dev": true, "license": "MIT", "dependencies": { - "debug": "^4.3.4" + "p-locate": "^6.0.0" }, "engines": { - "node": ">= 14" - } + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/pac-proxy-agent/node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, "license": "MIT", "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" + "yocto-queue": "^1.0.0" }, "engines": { - "node": ">= 14" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/pac-proxy-agent/node_modules/https-proxy-agent": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", - "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dev": true, "license": "MIT", "dependencies": { - "agent-base": "^7.0.2", - "debug": "4" + "p-limit": "^4.0.0" }, "engines": { - "node": ">= 14" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/pac-proxy-agent/node_modules/socks-proxy-agent": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", - "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", + "node_modules/pkg-dir/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "dev": true, "license": "MIT", - "dependencies": { - "agent-base": "^7.1.1", - "debug": "^4.3.4", - "socks": "^2.8.3" - }, "engines": { - "node": ">= 14" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, - "node_modules/pac-resolver": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", - "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "node_modules/pkg-dir/node_modules/yocto-queue": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz", + "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", + "dev": true, "license": "MIT", - "dependencies": { - "degenerator": "^5.0.0", - "netmask": "^2.0.2" - }, "engines": { - "node": ">= 14" + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/pacote": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.2.0.tgz", - "integrity": "sha512-rJVZeIwHTUta23sIZgEIM62WYwbmGbThdbnkt81ravBplQv+HjyroqnLRNH2+sLJHcGZmLRmhPwACqhfTcOmnA==", + "node_modules/plist": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz", + "integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "@npmcli/git": "^4.0.0", - "@npmcli/installed-package-contents": "^2.0.1", - "@npmcli/promise-spawn": "^6.0.1", - "@npmcli/run-script": "^6.0.0", - "cacache": "^17.0.0", - "fs-minipass": "^3.0.0", - "minipass": "^5.0.0", - "npm-package-arg": "^10.0.0", - "npm-packlist": "^7.0.0", - "npm-pick-manifest": "^8.0.0", - "npm-registry-fetch": "^14.0.0", - "proc-log": "^3.0.0", - "promise-retry": "^2.0.1", - "read-package-json": "^6.0.0", - "read-package-json-fast": "^3.0.0", - "sigstore": "^1.3.0", - "ssri": "^10.0.0", - "tar": "^6.1.11" - }, - "bin": { - "pacote": "lib/bin.js" + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=10.4.0" } }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "node_modules/plist/node_modules/@xmldom/xmldom": { + "version": "0.8.10", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz", + "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==", "dev": true, - "license": "(MIT AND Zlib)" + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", "dev": true, "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, "engines": { - "node": ">=6" + "node": ">= 0.4" } }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "node_modules/postcss": { + "version": "8.4.41", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz", + "integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" + "nanoid": "^3.3.7", + "picocolors": "^1.0.1", + "source-map-js": "^1.2.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^10 || ^12 || >=14" } }, - "node_modules/parse-node-version": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", - "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "node_modules/postcss-loader": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-8.1.1.tgz", + "integrity": "sha512-0IeqyAsG6tYiDRCYKQJLAmgQr47DX6N7sFSWvQxt6AcupX8DIdmykuk/o/tx0Lze3ErGHJEp5OSRxrelC6+NdQ==", "dev": true, "license": "MIT", + "dependencies": { + "cosmiconfig": "^9.0.0", + "jiti": "^1.20.0", + "semver": "^7.5.4" + }, "engines": { - "node": ">= 0.10" + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } } }, - "node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "node_modules/postcss-media-query-parser": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", + "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", "dev": true, "license": "MIT" }, - "node_modules/parse5-html-rewriting-stream": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-7.0.0.tgz", - "integrity": "sha512-mazCyGWkmCRWDI15Zp+UiCqMp/0dgEmkZRvhlsqqKYr4SsVm/TvnSpD9fCvqCA2zoWJcfRym846ejWBBHRiYEg==", + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", "dev": true, - "license": "MIT", - "dependencies": { - "entities": "^4.3.0", - "parse5": "^7.0.0", - "parse5-sax-parser": "^7.0.0" + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/parse5-html-rewriting-stream/node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", + "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", "dev": true, "license": "MIT", "dependencies": { - "entities": "^4.4.0" + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/parse5-sax-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-7.0.0.tgz", - "integrity": "sha512-5A+v2SNsq8T6/mG3ahcz8ZtQ0OUFTatxPbeidoMB7tkJSGDY3tdfl4MHovtLQHkEn5CGxijNWRQHhRQ6IRpXKg==", + "node_modules/postcss-modules-scope": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", + "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "parse5": "^7.0.0" + "postcss-selector-parser": "^6.0.4" }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/parse5-sax-parser/node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "entities": "^4.4.0" + "icss-utils": "^5.0.0" }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "dev": true, "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, "engines": { - "node": ">= 0.8" + "node": ">=4" } }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "node_modules/prebuild-install": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz", + "integrity": "sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==", + "dev": true, "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, - "node_modules/path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", + "node_modules/prebuild-install/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", "dev": true, - "license": "(WTFPL OR MIT)" + "license": "ISC" }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "node_modules/prebuild-install/node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" - }, - "node_modules/path-scurry": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", - "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", + "node_modules/prebuild-install/node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" }, "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=6" } }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", - "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, - "license": "ISC", + "license": "MIT", "engines": { - "node": "14 || >=16.14" + "node": ">= 0.8.0" } }, - "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", - "dev": true - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", "dev": true, "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, "engines": { - "node": ">=8" + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "node_modules/proc-log": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", + "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", "dev": true, - "license": "MIT" + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true, "license": "MIT" }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", "dev": true, "license": "ISC" }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "devOptional": true, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, "license": "MIT", - "engines": { - "node": ">=8.6" + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "engines": { + "node": ">=10" } }, - "node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", "dev": true, "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, "engines": { - "node": ">=6" + "node": ">= 6" } }, - "node_modules/pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "node_modules/prompts/node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "node_modules/protractor": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/protractor/-/protractor-7.0.0.tgz", + "integrity": "sha512-UqkFjivi4GcvUQYzqGYNe0mLzfn5jiLmO8w9nMhQoJRLhy2grJonpga2IWhI6yJO30LibWXJJtA4MOIZD2GgZw==", + "deprecated": "We have news to share - Protractor is deprecated and will reach end-of-life by Summer 2023. To learn more and find out about other options please refer to this post on the Angular blog. Thank you for using and contributing to Protractor. https://goo.gle/state-of-e2e-in-angular", "dev": true, "license": "MIT", "dependencies": { - "pinkie": "^2.0.0" + "@types/q": "^0.0.32", + "@types/selenium-webdriver": "^3.0.0", + "blocking-proxy": "^1.0.0", + "browserstack": "^1.5.1", + "chalk": "^1.1.3", + "glob": "^7.0.3", + "jasmine": "2.8.0", + "jasminewd2": "^2.1.0", + "q": "1.4.1", + "saucelabs": "^1.5.0", + "selenium-webdriver": "3.6.0", + "source-map-support": "~0.4.0", + "webdriver-js-extender": "2.1.0", + "webdriver-manager": "^12.1.7", + "yargs": "^15.3.1" }, + "bin": { + "protractor": "bin/protractor", + "webdriver-manager": "bin/webdriver-manager" + }, + "engines": { + "node": ">=10.13.x" + } + }, + "node_modules/protractor/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/piscina": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.0.0.tgz", - "integrity": "sha512-641nAmJS4k4iqpNUqfggqUBUMmlw0ZoM5VZKdQkV2e970Inn3Tk9kroCc1wpsYLD07vCwpys5iY0d3xI/9WkTg==", + "node_modules/protractor/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true, "license": "MIT", - "dependencies": { - "eventemitter-asyncresource": "^1.0.0", - "hdr-histogram-js": "^2.0.1", - "hdr-histogram-percentiles-obj": "^3.0.0" - }, - "optionalDependencies": { - "nice-napi": "^1.0.2" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/pkg-dir": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", - "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", + "node_modules/protractor/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, "license": "MIT", "dependencies": { - "find-up": "^6.3.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" }, "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", - "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "node_modules/protractor/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "locate-path": "^7.1.0", - "path-exists": "^5.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" } }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", - "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "node_modules/protractor/node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", - "dependencies": { - "p-locate": "^6.0.0" - }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", - "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "node_modules/protractor/node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", "dependencies": { - "yocto-queue": "^1.0.0" + "ansi-regex": "^5.0.1" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", - "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "node_modules/protractor/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "license": "MIT", "dependencies": { - "p-limit": "^4.0.0" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "node_modules/pkg-dir/node_modules/path-exists": { + "node_modules/protractor/node_modules/locate-path": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", - "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=8" } }, - "node_modules/pkg-dir/node_modules/yocto-queue": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", - "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "node_modules/protractor/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, "engines": { - "node": ">=12.20" + "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/plist": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz", - "integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==", + "node_modules/protractor/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "license": "MIT", "dependencies": { - "@xmldom/xmldom": "^0.8.8", - "base64-js": "^1.5.1", - "xmlbuilder": "^15.1.1" + "p-limit": "^2.2.0" }, "engines": { - "node": ">=10.4.0" + "node": ">=8" } }, - "node_modules/plist/node_modules/@xmldom/xmldom": { - "version": "0.8.10", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz", - "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==", + "node_modules/protractor/node_modules/q": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", + "integrity": "sha512-/CdEdaw49VZVmyIDGUQKDDT53c7qBkO6g5CefWz91Ae+l4+cRtcDYwMTXh6me4O8TMldeGHG3N2Bl84V78Ywbg==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", "dev": true, "license": "MIT", "engines": { - "node": ">=10.0.0" + "node": ">=0.6.0", + "teleport": ">=0.2.0" } }, - "node_modules/plist/node_modules/xmlbuilder": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", - "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", + "node_modules/protractor/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", "engines": { - "node": ">=8.0" + "node": ">=0.10.0" } }, - "node_modules/possible-typed-array-names": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", - "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "node_modules/protractor/node_modules/source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.4" + "dependencies": { + "source-map": "^0.5.6" } }, - "node_modules/postcss": { - "version": "8.4.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", - "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", + "node_modules/protractor/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "ansi-regex": "^2.0.0" }, "engines": { - "node": "^10 || ^12 || >=14" + "node": ">=0.10.0" } }, - "node_modules/postcss-loader": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.3.3.tgz", - "integrity": "sha512-YgO/yhtevGO/vJePCQmTxiaEwER94LABZN0ZMT4A0vsak9TpO+RvKRs7EmJ8peIlB9xfXCsS7M8LjqncsUZ5HA==", + "node_modules/protractor/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true, "license": "MIT", - "dependencies": { - "cosmiconfig": "^8.2.0", - "jiti": "^1.18.2", - "semver": "^7.3.8" - }, "engines": { - "node": ">= 14.15.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "postcss": "^7.0.0 || ^8.0.1", - "webpack": "^5.0.0" + "node": ">=0.8.0" } }, - "node_modules/postcss-modules-extract-imports": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", - "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "node_modules/protractor/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", "dev": true, - "license": "ISC", - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } + "license": "ISC" }, - "node_modules/postcss-modules-local-by-default": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", - "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", + "node_modules/protractor/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "dev": true, "license": "MIT", "dependencies": { - "icss-utils": "^5.0.0", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.1.0" + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" }, "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" + "node": ">=8" } }, - "node_modules/postcss-modules-scope": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", - "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", + "node_modules/protractor/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "dev": true, "license": "ISC", "dependencies": { - "postcss-selector-parser": "^6.0.4" + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" }, "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" + "node": ">=6" } }, - "node_modules/postcss-modules-values": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "icss-utils": "^5.0.0" + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" }, "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" + "node": ">= 0.10" } }, - "node_modules/postcss-selector-parser": { - "version": "6.0.16", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz", - "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==", + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-agent": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz", + "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==", "dev": true, "license": "MIT", "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.3", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.0.1", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.2" }, "engines": { - "node": ">=4" + "node": ">= 14" } }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "node_modules/proxy-agent/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "dev": true, "license": "MIT" }, - "node_modules/prebuild-install": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz", - "integrity": "sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==", + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", "dev": true, "license": "MIT", - "dependencies": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, - "bin": { - "prebuild-install": "bin.js" - }, - "engines": { - "node": ">=10" - } + "optional": true }, - "node_modules/prebuild-install/node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", "dev": true, - "license": "ISC" + "license": "MIT" }, - "node_modules/prebuild-install/node_modules/tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, "license": "MIT", "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.8.0" + "node": ">=0.6.0", + "teleport": ">=0.2.0" } }, - "node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "node_modules/qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", "dev": true, "license": "MIT", - "bin": { - "prettier": "bin-prettier.js" - }, "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" + "node": ">=0.9" } }, - "node_modules/pretty-bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.4" + }, "engines": { - "node": ">=6" + "node": ">=0.6" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/proc-log": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", - "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "license": "MIT" }, - "node_modules/promise-inflight": { + "node_modules/queue-tick": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", "dev": true, - "license": "ISC" + "license": "MIT" }, - "node_modules/promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "node_modules/quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", "dev": true, "license": "MIT", - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, "license": "MIT", "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 6" + "node": ">= 0.6" } }, - "node_modules/prompts/node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dev": true, "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, "engines": { - "node": ">=6" + "node": ">= 0.8" } }, - "node_modules/protractor": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/protractor/-/protractor-7.0.0.tgz", - "integrity": "sha512-UqkFjivi4GcvUQYzqGYNe0mLzfn5jiLmO8w9nMhQoJRLhy2grJonpga2IWhI6yJO30LibWXJJtA4MOIZD2GgZw==", + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "license": "MIT", "dependencies": { - "@types/q": "^0.0.32", - "@types/selenium-webdriver": "^3.0.0", - "blocking-proxy": "^1.0.0", - "browserstack": "^1.5.1", - "chalk": "^1.1.3", - "glob": "^7.0.3", - "jasmine": "2.8.0", - "jasminewd2": "^2.1.0", - "q": "1.4.1", - "saucelabs": "^1.5.0", - "selenium-webdriver": "3.6.0", - "source-map-support": "~0.4.0", - "webdriver-js-extender": "2.1.0", - "webdriver-manager": "^12.1.7", - "yargs": "^15.3.1" - }, - "bin": { - "protractor": "bin/protractor", - "webdriver-manager": "bin/webdriver-manager" + "safer-buffer": ">= 2.1.2 < 3" }, "engines": { - "node": ">=10.13.x" + "node": ">=0.10.0" } }, - "node_modules/protractor/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" } }, - "node_modules/protractor/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "node_modules/rc/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/protractor/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "node_modules/read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/protractor/node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "node_modules/read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + }, + "engines": { + "node": ">=4" } }, - "node_modules/protractor/node_modules/cliui/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", "dev": true, "license": "MIT", + "dependencies": { + "locate-path": "^2.0.0" + }, "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/protractor/node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/read-pkg-up/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" }, "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/protractor/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/read-pkg-up/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", "dev": true, "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "p-try": "^1.0.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=4" } }, - "node_modules/protractor/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "node_modules/read-pkg-up/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "p-limit": "^1.1.0" }, "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=4" } }, - "node_modules/protractor/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "node_modules/read-pkg-up/node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/protractor/node_modules/source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "node_modules/read-pkg-up/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", "dev": true, "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true, + "license": "ISC" + }, + "node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "source-map": "^0.5.6" + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" } }, - "node_modules/protractor/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "node_modules/read-pkg/node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^2.0.0" + "pify": "^3.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/protractor/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "node_modules/read-pkg/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.8.0" + "node": ">=4" } }, - "node_modules/protractor/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "node_modules/read-pkg/node_modules/semver": { + "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" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, "engines": { - "node": ">=8" + "node": ">= 6" } }, - "node_modules/protractor/node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "devOptional": true, "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, "engines": { - "node": ">=8" + "node": ">=8.10.0" } }, - "node_modules/protractor/node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "devOptional": true, "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" + "node": ">=8.6" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/protractor/node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/protractor/node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "node_modules/reflect-metadata": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", "dev": true, - "license": "ISC" + "license": "Apache-2.0" }, - "node_modules/protractor/node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", "dev": true, "license": "MIT", "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" + "regenerate": "^1.4.2" }, "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/protractor/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "license": "MIT" + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regex-parser": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.3.0.tgz", + "integrity": "sha512-TVILVSz2jY5D47F4mA4MppkBrafEaiUWJO/TcZHEIuI13AqoZMkK1WMA4Om1YkYbTx+9Ki1/tSUXbceyr9saRg==", + "dev": true, + "license": "MIT" + }, + "node_modules/regexp-to-ast": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/regexp-to-ast/-/regexp-to-ast-0.5.0.tgz", + "integrity": "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==", + "dev": true, + "license": "MIT" + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" }, "engines": { - "node": ">=6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", "dev": true, + "license": "MIT", "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" }, "engines": { - "node": ">= 0.10" + "node": ">=4" } }, - "node_modules/proxy-addr/node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", "dev": true, - "engines": { - "node": ">= 0.10" + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" } }, - "node_modules/proxy-agent": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz", - "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==", + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/replace": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/replace/-/replace-1.2.2.tgz", + "integrity": "sha512-C4EDifm22XZM2b2JOYe6Mhn+lBsLBAvLbK8drfUQLTfD1KYl/n3VaW/CDju0Ny4w3xTtegBpg8YNSpFJPUDSjA==", + "dev": true, "license": "MIT", "dependencies": { - "agent-base": "^7.0.2", - "debug": "^4.3.4", - "http-proxy-agent": "^7.0.1", - "https-proxy-agent": "^7.0.3", - "lru-cache": "^7.14.1", - "pac-proxy-agent": "^7.0.1", - "proxy-from-env": "^1.1.0", - "socks-proxy-agent": "^8.0.2" + "chalk": "2.4.2", + "minimatch": "3.0.5", + "yargs": "^15.3.1" + }, + "bin": { + "replace": "bin/replace.js", + "search": "bin/search.js" }, "engines": { - "node": ">= 14" + "node": ">= 6" } }, - "node_modules/proxy-agent/node_modules/agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "node_modules/replace/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "license": "MIT", "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/proxy-agent/node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "node_modules/replace/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/replace/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, "license": "MIT", "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">= 14" + "node": ">=8" } }, - "node_modules/proxy-agent/node_modules/https-proxy-agent": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", - "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "node_modules/replace/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, "license": "MIT", "dependencies": { - "agent-base": "^7.0.2", - "debug": "4" + "p-locate": "^4.1.0" }, "engines": { - "node": ">= 14" + "node": ">=8" } }, - "node_modules/proxy-agent/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "node_modules/replace/node_modules/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", + "dev": true, "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">=12" + "node": "*" } }, - "node_modules/proxy-agent/node_modules/socks-proxy-agent": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", - "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", + "node_modules/replace/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, "license": "MIT", "dependencies": { - "agent-base": "^7.1.1", - "debug": "^4.3.4", - "socks": "^2.8.3" + "p-try": "^2.0.0" }, "engines": { - "node": ">= 14" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "license": "MIT" - }, - "node_modules/prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "node_modules/replace/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "license": "MIT", - "optional": true + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } }, - "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "node_modules/replace/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", "dev": true, - "license": "MIT" + "license": "ISC" }, - "node_modules/pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "node_modules/replace/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "dev": true, - "license": "MIT" - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "license": "MIT", "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" } }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "license": "MIT", + "node_modules/replace/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, "engines": { "node": ">=6" } }, - "node_modules/q": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", - "integrity": "sha512-/CdEdaw49VZVmyIDGUQKDDT53c7qBkO6g5CefWz91Ae+l4+cRtcDYwMTXh6me4O8TMldeGHG3N2Bl84V78Ywbg==", + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", "dev": true, - "license": "MIT", + "license": "Apache-2.0", + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" + "node": ">= 6" } }, - "node_modules/qjobs": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", - "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "node_modules/request/node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "dev": true, "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, "engines": { - "node": ">=0.9" + "node": ">= 0.12" } }, - "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "node_modules/request/node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "dev": true, "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.0.4" - }, "engines": { "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/queue-tick": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", - "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", - "dev": true, - "license": "MIT" - }, - "node_modules/quick-lru": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", - "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "node_modules/request/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", "dev": true, "license": "MIT", - "engines": { - "node": ">=8" + "bin": { + "uuid": "bin/uuid" } }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, "license": "MIT", - "dependencies": { - "safe-buffer": "^5.1.0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" } }, - "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true, + "license": "ISC" + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" }, - "engines": { - "node": ">= 0.8" + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/raw-body/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">=4" } }, - "node_modules/raw-body/node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "node_modules/resolve-url-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", + "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", "dev": true, "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "adjust-sourcemap-loader": "^4.0.0", + "convert-source-map": "^1.7.0", + "loader-utils": "^2.0.0", + "postcss": "^8.2.14", + "source-map": "0.6.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=12" } }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "node_modules/resolve-url-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "license": "MIT", "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" }, - "bin": { - "rc": "cli.js" + "engines": { + "node": ">=8.9.0" } }, - "node_modules/rc/node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true, - "license": "ISC" - }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "node_modules/resolve-url-loader/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, - "node_modules/read-package-json": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-6.0.4.tgz", - "integrity": "sha512-AEtWXYfopBj2z5N5PbkAOeNHRPUg5q+Nen7QLxV8M2zJq1ym6/lCz3fYNTCXe19puu2d06jfHhrP7v/S2PtMMw==", - "dev": true, - "license": "ISC", + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "license": "MIT", "dependencies": { - "glob": "^10.2.2", - "json-parse-even-better-errors": "^3.0.0", - "normalize-package-data": "^5.0.0", - "npm-normalize-package-bin": "^3.0.0" + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=8" } }, - "node_modules/read-package-json-fast": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", - "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", - "dev": true, - "license": "ISC", - "dependencies": { - "json-parse-even-better-errors": "^3.0.0", - "npm-normalize-package-bin": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" }, - "node_modules/read-package-json-fast/node_modules/json-parse-even-better-errors": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", - "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", "dev": true, "license": "MIT", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">= 4" } }, - "node_modules/read-package-json/node_modules/json-parse-even-better-errors": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", - "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true, "license": "MIT", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "iojs": ">=1.0.0", + "node": ">=0.10.0" } }, - "node_modules/read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", "dev": true, - "license": "MIT", + "license": "MIT" + }, + "node_modules/rimraf": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.1.tgz", + "integrity": "sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==", + "dev": true, + "license": "ISC", "dependencies": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" + "glob": "^9.2.0" + }, + "bin": { + "rimraf": "dist/cjs/src/bin.js" }, "engines": { - "node": ">=4" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/read-pkg-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", - "integrity": "sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw==", + "node_modules/rimraf/node_modules/glob": { + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", + "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "find-up": "^2.0.0", - "read-pkg": "^3.0.0" + "fs.realpath": "^1.0.0", + "minimatch": "^8.0.2", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" }, "engines": { - "node": ">=4" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/read-pkg-up/node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "node_modules/rimraf/node_modules/minimatch": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", + "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "locate-path": "^2.0.0" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=4" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/read-pkg-up/node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "node_modules/rimraf/node_modules/minipass": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", + "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, + "license": "ISC", "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/read-pkg-up/node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "node_modules/roboto-fontface": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/roboto-fontface/-/roboto-fontface-0.10.0.tgz", + "integrity": "sha512-OlwfYEgA2RdboZohpldlvJ1xngOins5d7ejqnIBWr9KaMxsnBqotpptRXTyfNRLnFpqzX6sTDt+X+a+6udnU8g==", + "license": "Apache-2.0" + }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", + "license": "Unlicense" + }, + "node_modules/rollup": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.21.2.tgz", + "integrity": "sha512-e3TapAgYf9xjdLvKQCkQTnbTKd4a6jwlpQSJJFokHGaX2IVjoEqkIIhiQfqsi0cdwlOD+tQGuOd5AJkc5RngBw==", "dev": true, "license": "MIT", "dependencies": { - "p-try": "^1.0.0" + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" }, "engines": { - "node": ">=4" + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.21.2", + "@rollup/rollup-android-arm64": "4.21.2", + "@rollup/rollup-darwin-arm64": "4.21.2", + "@rollup/rollup-darwin-x64": "4.21.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.21.2", + "@rollup/rollup-linux-arm-musleabihf": "4.21.2", + "@rollup/rollup-linux-arm64-gnu": "4.21.2", + "@rollup/rollup-linux-arm64-musl": "4.21.2", + "@rollup/rollup-linux-powerpc64le-gnu": "4.21.2", + "@rollup/rollup-linux-riscv64-gnu": "4.21.2", + "@rollup/rollup-linux-s390x-gnu": "4.21.2", + "@rollup/rollup-linux-x64-gnu": "4.21.2", + "@rollup/rollup-linux-x64-musl": "4.21.2", + "@rollup/rollup-win32-arm64-msvc": "4.21.2", + "@rollup/rollup-win32-ia32-msvc": "4.21.2", + "@rollup/rollup-win32-x64-msvc": "4.21.2", + "fsevents": "~2.3.2" } }, - "node_modules/read-pkg-up/node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "node_modules/rsvp": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-3.6.2.tgz", + "integrity": "sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw==", "dev": true, "license": "MIT", - "dependencies": { - "p-limit": "^1.1.0" - }, "engines": { - "node": ">=4" + "node": "0.12.* || 4.* || 6.* || >= 7.*" } }, - "node_modules/read-pkg-up/node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "node_modules/run-applescript": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", + "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", "dev": true, "license": "MIT", "engines": { - "node": ">=4" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/read-pkg-up/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=4" + "node": ">=0.12.0" } }, - "node_modules/read-pkg/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, - "license": "ISC" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } }, - "node_modules/read-pkg/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "license": "BSD-3-Clause" + }, + "node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "license": "Apache-2.0", "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" } }, - "node_modules/read-pkg/node_modules/path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "node_modules/rxjs/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", "dev": true, "license": "MIT", "dependencies": { - "pify": "^3.0.0" + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" }, "engines": { - "node": ">=4" + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/read-pkg/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", "dev": true, "license": "MIT", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + }, "engines": { - "node": ">=4" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/read-pkg/node_modules/semver": { - "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" - } + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" }, - "node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "node_modules/sass": { + "version": "1.77.6", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.6.tgz", + "integrity": "sha512-ByXE1oLD79GVq9Ht1PeHWCPMPB8XHpBuz1r85oByKHjZY6qV6rWnQovQzXJXuQ/XyE1Oj3iPk3lo28uzaRA2/Q==", + "dev": true, "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" }, "engines": { - "node": ">= 6" + "node": ">=14.0.0" } }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "devOptional": true, + "node_modules/sass-loader": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-16.0.0.tgz", + "integrity": "sha512-n13Z+3rU9A177dk4888czcVFiC8CL9dii4qpXWUg3YIIgZEvi9TCFKjOQcbK0kJM7DJu9VucrZFddvNfYCPwtw==", + "dev": true, "license": "MIT", "dependencies": { - "picomatch": "^2.2.1" + "neo-async": "^2.6.2" }, "engines": { - "node": ">=8.10.0" + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "webpack": { + "optional": true + } } }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "node_modules/saucelabs": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.5.0.tgz", + "integrity": "sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ==", "dev": true, - "license": "MIT", "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" + "https-proxy-agent": "^2.2.1" }, "engines": { - "node": ">=8" + "node": "*" } }, - "node_modules/reflect-metadata": { - "version": "0.1.14", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz", - "integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true, - "license": "MIT" - }, - "node_modules/regenerate-unicode-properties": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", - "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "node_modules/saucelabs/node_modules/agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", "dev": true, "license": "MIT", "dependencies": { - "regenerate": "^1.4.2" + "es6-promisify": "^5.0.0" }, "engines": { - "node": ">=4" + "node": ">= 4.0.0" } }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "license": "MIT" - }, - "node_modules/regenerator-transform": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", - "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "node_modules/saucelabs/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/runtime": "^7.8.4" + "ms": "^2.1.1" } }, - "node_modules/regex-parser": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.3.0.tgz", - "integrity": "sha512-TVILVSz2jY5D47F4mA4MppkBrafEaiUWJO/TcZHEIuI13AqoZMkK1WMA4Om1YkYbTx+9Ki1/tSUXbceyr9saRg==", + "node_modules/saucelabs/node_modules/https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "engines": { + "node": ">= 4.5.0" + } }, - "node_modules/regexp-to-ast": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/regexp-to-ast/-/regexp-to-ast-0.5.0.tgz", - "integrity": "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==", + "node_modules/sax": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.1.4.tgz", + "integrity": "sha512-5f3k2PbGGp+YtKJjOItpg3P99IMD84E4HOvcfleTb5joCHNXYLsR9yWFPOYGgaeMPDubQILTCMdsFb2OMeOjtg==", "dev": true, - "license": "MIT" + "license": "ISC" }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", - "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.6", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "set-function-name": "^2.0.1" + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" }, "engines": { - "node": ">= 0.4" + "node": ">= 12.13.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, - "node_modules/regexpu-core": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", - "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "node_modules/schema-utils/node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/regjsgen": "^0.8.0", - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsparser": "^0.9.1", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.1.0" + "ajv": "^8.0.0" }, - "engines": { - "node": ">=4" + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } } }, - "node_modules/regjsparser": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT" + }, + "node_modules/selenium-webdriver": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz", + "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "jsesc": "~0.5.0" + "jszip": "^3.1.3", + "rimraf": "^2.5.4", + "tmp": "0.0.30", + "xml2js": "^0.4.17" }, - "bin": { - "regjsparser": "bin/parser" + "engines": { + "node": ">= 6.9.0" } }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "node_modules/selenium-webdriver/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, "bin": { - "jsesc": "bin/jsesc" + "rimraf": "bin.js" } }, - "node_modules/replace": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/replace/-/replace-1.2.2.tgz", - "integrity": "sha512-C4EDifm22XZM2b2JOYe6Mhn+lBsLBAvLbK8drfUQLTfD1KYl/n3VaW/CDju0Ny4w3xTtegBpg8YNSpFJPUDSjA==", + "node_modules/selenium-webdriver/node_modules/tmp": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", + "integrity": "sha512-HXdTB7lvMwcb55XFfrTM8CPr/IYREk4hVBFaQ4b/6nInrluSL86hfHm7vu0luYKCfyBZp2trCjpc8caC3vVM3w==", "dev": true, "license": "MIT", "dependencies": { - "chalk": "2.4.2", - "minimatch": "3.0.5", - "yargs": "^15.3.1" - }, - "bin": { - "replace": "bin/replace.js", - "search": "bin/search.js" + "os-tmpdir": "~1.0.1" }, "engines": { - "node": ">= 6" + "node": ">=0.4.0" } }, - "node_modules/replace/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/selenium-webdriver/node_modules/xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", "dev": true, "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=4.0.0" } }, - "node_modules/replace/node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "node_modules/selenium-webdriver/node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" + "license": "MIT", + "engines": { + "node": ">=4.0" } }, - "node_modules/replace/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", "dev": true, "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "@types/node-forge": "^1.3.0", + "node-forge": "^1" }, "engines": { - "node": ">=7.0.0" + "node": ">=10" } }, - "node_modules/replace/node_modules/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": "*" + "node": ">=10" } }, - "node_modules/replace/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" }, "engines": { - "node": ">=8" + "node": ">= 0.8.0" } }, - "node_modules/replace/node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/replace/node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "license": "MIT", "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" + "ms": "2.0.0" } }, - "node_modules/replace/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, - "license": "ISC", - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } + "license": "MIT" }, - "node_modules/request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "node_modules/send/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" + "license": "MIT", + "bin": { + "mime": "cli.js" }, "engines": { - "node": ">= 6" + "node": ">=4" } }, - "node_modules/request/node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/send/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true, "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, "engines": { - "node": ">= 0.12" + "node": ">= 0.8" } }, - "node_modules/request/node_modules/qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, "license": "BSD-3-Clause", - "engines": { - "node": ">=0.6" + "dependencies": { + "randombytes": "^2.1.0" } }, - "node_modules/request/node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" }, "engines": { - "node": ">=0.8" + "node": ">= 0.8.0" } }, - "node_modules/request/node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "license": "MIT", - "bin": { - "uuid": "bin/uuid" + "dependencies": { + "ms": "2.0.0" } }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.6" } }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, "license": "MIT", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.6" } }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", "dev": true, "license": "ISC" }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, "license": "MIT" }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "dev": true, "license": "MIT", "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true, + "license": "ISC" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dev": true, "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" } }, - "node_modules/resolve-url-loader": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", - "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "dev": true, "license": "MIT", "dependencies": { - "adjust-sourcemap-loader": "^4.0.0", - "convert-source-map": "^1.7.0", - "loader-utils": "^2.0.0", - "postcss": "^8.2.14", - "source-map": "0.6.1" + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" }, "engines": { - "node": ">=12" + "node": ">= 0.4" } }, - "node_modules/resolve-url-loader/node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true, + "license": "MIT" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true, + "license": "ISC" + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", "dev": true, "license": "MIT", "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" + "kind-of": "^6.0.2" }, "engines": { - "node": ">=8.9.0" + "node": ">=8" } }, - "node_modules/resolve-url-loader/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/sharp": { + "version": "0.32.6", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.32.6.tgz", + "integrity": "sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==", "dev": true, - "license": "BSD-3-Clause", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.2", + "node-addon-api": "^6.1.0", + "prebuild-install": "^7.1.1", + "semver": "^7.5.4", + "simple-get": "^4.0.1", + "tar-fs": "^3.0.4", + "tunnel-agent": "^0.6.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=14.15.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "node_modules/sharp/node_modules/node-addon-api": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", + "dev": true, + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, "license": "MIT", "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" + "shebang-regex": "^3.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, "license": "MIT", "engines": { - "node": ">= 4" + "node": ">=8" } }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", "dev": true, "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/rfdc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", - "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dev": true, - "license": "MIT" - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "license": "ISC", + "license": "MIT", "dependencies": { - "glob": "^7.1.3" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" }, - "bin": { - "rimraf": "bin.js" + "engines": { + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, "engines": { - "node": "*" + "node": ">=14" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/roboto-fontface": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/roboto-fontface/-/roboto-fontface-0.10.0.tgz", - "integrity": "sha512-OlwfYEgA2RdboZohpldlvJ1xngOins5d7ejqnIBWr9KaMxsnBqotpptRXTyfNRLnFpqzX6sTDt+X+a+6udnU8g==", - "license": "Apache-2.0" - }, - "node_modules/robust-predicates": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", - "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", - "license": "Unlicense" - }, - "node_modules/rollup": { - "version": "3.29.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", - "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", + "node_modules/sigstore": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.3.1.tgz", + "integrity": "sha512-8G+/XDU8wNsJOQS5ysDVO0Etg9/2uA5gR9l4ZwijjlwxBcrU6RPfwi2+jJmbP+Ap1Hlp/nVAaEO4Fj22/SL2gQ==", "dev": true, - "license": "MIT", - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=14.18.0", - "npm": ">=8.0.0" + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^2.3.2", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.2", + "@sigstore/sign": "^2.3.2", + "@sigstore/tuf": "^2.3.4", + "@sigstore/verify": "^1.2.1" }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/rsvp": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-3.6.2.tgz", - "integrity": "sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw==", - "license": "MIT", - "engines": { - "node": "0.12.* || 4.* || 6.* || >= 7.*" - } - }, - "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "license": "MIT", "engines": { - "node": ">=0.12.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", "dev": true, "funding": [ { @@ -21137,65 +22114,13 @@ "url": "https://feross.org/support" } ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/rw": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", - "license": "BSD-3-Clause" - }, - "node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, - "node_modules/rxjs/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "license": "0BSD" - }, - "node_modules/safe-array-concat": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", - "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4", - "has-symbols": "^1.0.3", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-array-concat/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true, "license": "MIT" }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "dev": true, "funding": [ { "type": "github", @@ -21210,3091 +22135,2594 @@ "url": "https://feross.org/support" } ], - "license": "MIT" - }, - "node_modules/safe-regex-test": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", - "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", - "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-regex": "^1.1.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" } }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, - "node_modules/sass": { - "version": "1.64.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.64.1.tgz", - "integrity": "sha512-16rRACSOFEE8VN7SCgBu1MpYCyN7urj9At898tyzdXFhC+a+yOX5dXwAR7L8/IdPJ1NB8OYoXmD55DM30B2kEQ==", + "node_modules/simple-plist": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/simple-plist/-/simple-plist-1.3.1.tgz", + "integrity": "sha512-iMSw5i0XseMnrhtIzRb7XpQEXepa9xhWxGUojHBL43SIpQuDQkh3Wpy67ZbDzZVr6EKxvwVChnVpdl8hEVLDiw==", "dev": true, "license": "MIT", "dependencies": { - "chokidar": ">=3.0.0 <4.0.0", - "immutable": "^4.0.0", - "source-map-js": ">=0.6.2 <2.0.0" - }, - "bin": { - "sass": "sass.js" - }, - "engines": { - "node": ">=14.0.0" + "bplist-creator": "0.1.0", + "bplist-parser": "0.3.1", + "plist": "^3.0.5" } }, - "node_modules/sass-loader": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.2.tgz", - "integrity": "sha512-CQbKl57kdEv+KDLquhC+gE3pXt74LEAzm+tzywcA0/aHZuub8wTErbjAoNI57rPUWRYRNC5WUnNl8eGJNbDdwg==", + "node_modules/simple-plist/node_modules/bplist-parser": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.3.1.tgz", + "integrity": "sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA==", "dev": true, "license": "MIT", "dependencies": { - "neo-async": "^2.6.2" + "big-integer": "1.6.x" }, "engines": { - "node": ">= 14.15.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "fibers": ">= 3.1.0", - "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", - "sass": "^1.3.0", - "sass-embedded": "*", - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "fibers": { - "optional": true - }, - "node-sass": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - } + "node": ">= 5.10.0" } }, - "node_modules/saucelabs": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.5.0.tgz", - "integrity": "sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ==", + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", "dev": true, + "license": "MIT", "dependencies": { - "https-proxy-agent": "^2.2.1" - }, - "engines": { - "node": "*" + "is-arrayish": "^0.3.1" } }, - "node_modules/saucelabs/node_modules/agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/simple-update-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", + "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", "dev": true, "license": "MIT", "dependencies": { - "es6-promisify": "^5.0.0" + "semver": "~7.0.0" }, "engines": { - "node": ">= 4.0.0" + "node": ">=8.10.0" } }, - "node_modules/saucelabs/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/saucelabs/node_modules/https-proxy-agent": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, "license": "MIT", - "dependencies": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - }, "engines": { - "node": ">= 4.5.0" + "node": ">=8" } }, - "node_modules/sax": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", - "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==", + "node_modules/slashes": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/slashes/-/slashes-3.0.12.tgz", + "integrity": "sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA==", "dev": true, "license": "ISC" }, - "node_modules/saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "xmlchars": "^2.2.0" + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "node_modules/schema-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", - "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">= 12.13.0" + "node": ">=8" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", - "dev": true - }, - "node_modules/selenium-webdriver": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz", - "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==", + "node_modules/slice-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "jszip": "^3.1.3", - "rimraf": "^2.5.4", - "tmp": "0.0.30", - "xml2js": "^0.4.17" + "color-name": "~1.1.4" }, "engines": { - "node": ">= 6.9.0" + "node": ">=7.0.0" } }, - "node_modules/selenium-webdriver/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "node_modules/slice-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, + "license": "MIT" + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "license": "MIT", "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">= 6.0.0", + "npm": ">= 3.0.0" } }, - "node_modules/selenium-webdriver/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "node_modules/socket.io": { + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", + "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "glob": "^7.1.3" + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.5.2", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" }, - "bin": { - "rimraf": "bin.js" + "engines": { + "node": ">=10.2.0" } }, - "node_modules/selenium-webdriver/node_modules/tmp": { - "version": "0.0.30", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", - "integrity": "sha512-HXdTB7lvMwcb55XFfrTM8CPr/IYREk4hVBFaQ4b/6nInrluSL86hfHm7vu0luYKCfyBZp2trCjpc8caC3vVM3w==", + "node_modules/socket.io-adapter": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", + "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", "dev": true, "license": "MIT", "dependencies": { - "os-tmpdir": "~1.0.1" - }, - "engines": { - "node": ">=0.4.0" + "debug": "~4.3.4", + "ws": "~8.17.1" } }, - "node_modules/selfsigned": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", - "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", "dev": true, + "license": "MIT", "dependencies": { - "@types/node-forge": "^1.3.0", - "node-forge": "^1" + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" }, "engines": { - "node": ">=10" + "node": ">=10.0.0" } }, - "node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "license": "ISC", + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" - }, + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/sockjs/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "license": "MIT", "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" + "uuid": "dist/bin/uuid" } }, - "node_modules/semver/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "license": "ISC", + "node_modules/socks": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", + "dev": true, + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" }, "engines": { - "node": ">=10" + "node": ">= 10.0.0", + "npm": ">= 3.0.0" } }, - "node_modules/semver/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, - "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "node_modules/socks-proxy-agent": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", + "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", "dev": true, + "license": "MIT", "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" + "agent-base": "^7.1.1", + "debug": "^4.3.4", + "socks": "^2.8.3" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 14" } }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", "dev": true, - "dependencies": { - "ms": "2.0.0" + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" } }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", "dev": true, "license": "BSD-3-Clause", - "dependencies": { - "randombytes": "^2.1.0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "node_modules/source-map-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-5.0.0.tgz", + "integrity": "sha512-k2Dur7CbSLcAH73sBcIkV5xjPV4SzqO1NJ7+XaQl8if3VODDUj3FNchNGpqgJSKbvUfJuhVdv8K2Eu8/TNl2eA==", "dev": true, + "license": "MIT", "dependencies": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.2" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.72.1" } }, - "node_modules/serve-index/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, + "license": "MIT", "dependencies": { - "ms": "2.0.0" + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" } }, - "node_modules/serve-index/node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" } }, - "node_modules/serve-index/node_modules/http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "deprecated": "Please use @jridgewell/sourcemap-codec instead", + "license": "MIT" + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - }, - "engines": { - "node": ">= 0.6" + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" } }, - "node_modules/serve-index/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true - }, - "node_modules/serve-index/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "node_modules/spdx-correct/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } }, - "node_modules/serve-index/node_modules/setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" }, - "node_modules/serve-index/node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "node_modules/spdx-expression-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", "dev": true, - "engines": { - "node": ">= 0.6" + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, - "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "node_modules/spdx-license-ids": { + "version": "3.0.20", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.20.tgz", + "integrity": "sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", "dev": true, + "license": "MIT", "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">=6.0.0" } }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", "dev": true, - "license": "ISC" - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "license": "MIT", "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" } }, - "node_modules/set-function-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "node_modules/split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", "dev": true, "license": "MIT", "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" + "through": "2" }, "engines": { - "node": ">= 0.4" + "node": "*" } }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "node_modules/split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", "dev": true, - "license": "MIT" + "license": "ISC", + "dependencies": { + "readable-stream": "^3.0.0" + } }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", "dev": true, - "license": "ISC" + "license": "BSD-3-Clause" }, - "node_modules/shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "node_modules/ssh-config": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/ssh-config/-/ssh-config-1.1.6.tgz", + "integrity": "sha512-ZPO9rECxzs5JIQ6G/2EfL1I9ho/BVZkx9HRKn8+0af7QgwAmumQ7XBFP1ggMyPMo+/tUbmv0HFdv4qifdO/9JA==", + "dev": true, + "license": "MIT" + }, + "node_modules/sshpk": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", "dev": true, "license": "MIT", "dependencies": { - "kind-of": "^6.0.2" + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/sharp": { - "version": "0.32.6", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.32.6.tgz", - "integrity": "sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==", - "dev": true, - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "color": "^4.2.3", - "detect-libc": "^2.0.2", - "node-addon-api": "^6.1.0", - "prebuild-install": "^7.1.1", - "semver": "^7.5.4", - "simple-get": "^4.0.1", - "tar-fs": "^3.0.4", - "tunnel-agent": "^0.6.0" - }, - "engines": { - "node": ">=14.15.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/sharp/node_modules/node-addon-api": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", - "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", + "node_modules/sshpk/node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", "dev": true, "license": "MIT" }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "license": "MIT", + "node_modules/ssri": { + "version": "10.0.6", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz", + "integrity": "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==", + "dev": true, + "license": "ISC", "dependencies": { - "shebang-regex": "^3.0.0" + "minipass": "^7.0.3" }, "engines": { - "node": ">=8" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 0.6" } }, - "node_modules/shell-quote": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", - "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "node_modules/stream-buffers": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz", + "integrity": "sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==", "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "license": "Unlicense", + "engines": { + "node": ">= 0.10.0" } }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "node_modules/stream-combiner2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", + "integrity": "sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw==", + "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "duplexer2": "~0.1.0", + "readable-stream": "^2.0.2" } }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "license": "ISC" + "node_modules/stream-combiner2/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" }, - "node_modules/sigstore": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-1.9.0.tgz", - "integrity": "sha512-0Zjz0oe37d08VeOtBIuB6cRriqXse2e8w+7yIy2XSXjshRKxbc2KkhXjL229jXSxEm7UbcjS76wcJDGQddVI9A==", + "node_modules/stream-combiner2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@sigstore/bundle": "^1.1.0", - "@sigstore/protobuf-specs": "^0.2.0", - "@sigstore/sign": "^1.0.0", - "@sigstore/tuf": "^1.0.3", - "make-fetch-happen": "^11.0.1" - }, - "bin": { - "sigstore": "bin/sigstore.js" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "node_modules/sigstore/node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "node_modules/stream-combiner2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 10" - } + "license": "MIT" }, - "node_modules/sigstore/node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "node_modules/stream-combiner2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "license": "MIT", "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" + "safe-buffer": "~5.1.0" } }, - "node_modules/sigstore/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "node_modules/streamroller": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", + "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==", "dev": true, - "license": "ISC", + "license": "MIT", + "dependencies": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" + }, "engines": { - "node": ">=12" + "node": ">=8.0" } }, - "node_modules/sigstore/node_modules/make-fetch-happen": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", - "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", + "node_modules/streamroller/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^17.0.0", - "http-cache-semantics": "^4.1.1", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^5.0.0", - "minipass-fetch": "^3.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^10.0.0" + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=6 <7 || >=8" } }, - "node_modules/sigstore/node_modules/minipass-fetch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", - "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "node_modules/streamroller/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "dev": true, "license": "MIT", - "dependencies": { - "minipass": "^7.0.3", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - }, "optionalDependencies": { - "encoding": "^0.1.13" + "graceful-fs": "^4.1.6" } }, - "node_modules/sigstore/node_modules/minipass-fetch/node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "node_modules/streamroller/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true, - "license": "ISC", + "license": "MIT", "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">= 4.0.0" } }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "node_modules/streamx": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.19.0.tgz", + "integrity": "sha512-5z6CNR4gtkPbwlxyEqoDGDmWIzoNJqCBt4Eac1ICP9YaIT08ct712cFj0u1rx4F8luAuL+3Qc+RFIdI4OX00kg==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], "license": "MIT", "dependencies": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" + "fast-fifo": "^1.3.2", + "queue-tick": "^1.0.1", + "text-decoder": "^1.1.0" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" } }, - "node_modules/simple-plist": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/simple-plist/-/simple-plist-1.3.1.tgz", - "integrity": "sha512-iMSw5i0XseMnrhtIzRb7XpQEXepa9xhWxGUojHBL43SIpQuDQkh3Wpy67ZbDzZVr6EKxvwVChnVpdl8hEVLDiw==", - "dev": true, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "license": "MIT", "dependencies": { - "bplist-creator": "0.1.0", - "bplist-parser": "0.3.1", - "plist": "^3.0.5" + "safe-buffer": "~5.2.0" } }, - "node_modules/simple-plist/node_modules/bplist-parser": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.3.1.tgz", - "integrity": "sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA==", + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", "dependencies": { - "big-integer": "1.6.x" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">= 5.10.0" + "node": ">=8" } }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", "dependencies": { - "is-arrayish": "^0.3.1" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" } }, - "node_modules/simple-swizzle/node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/simple-update-notifier": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", - "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "node_modules/string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", "dev": true, "license": "MIT", "dependencies": { - "semver": "~7.0.0" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/simple-update-notifier/node_modules/semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true, - "license": "MIT" - }, - "node_modules/slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "node_modules/string.prototype.trimend": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=12" + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "ansi-regex": "^5.0.1" }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/slice-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=7.0.0" + "node": ">=8" } }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" + "node": ">=4" } }, - "node_modules/socket.io": { - "version": "4.7.3", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.3.tgz", - "integrity": "sha512-SE+UIQXBQE+GPG2oszWMlsEmWtHVqw/h1VrYJGK5/MC7CH5p58N448HwIrtREcvR4jfdOJAY4ieQfxMr55qbbw==", + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true, "license": "MIT", - "dependencies": { - "accepts": "~1.3.4", - "base64id": "~2.0.0", - "cors": "~2.8.5", - "debug": "~4.3.2", - "engine.io": "~6.5.2", - "socket.io-adapter": "~2.5.2", - "socket.io-parser": "~4.2.4" - }, "engines": { - "node": ">=10.2.0" + "node": ">=6" } }, - "node_modules/socket.io-adapter": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", - "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", "dev": true, "license": "MIT", "dependencies": { - "debug": "~4.3.4", - "ws": "~8.17.1" + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/socket.io-adapter/node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, "license": "MIT", "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" + "node": ">=8" }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/socket.io-parser": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", - "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "node_modules/superagent": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.1.2.tgz", + "integrity": "sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA==", + "deprecated": "Please upgrade to v9.0.0+ as we have fixed a public vulnerability with formidable dependency. Note that v9.0.0+ requires Node.js v14.18.0+. See https://github.com/ladjs/superagent/pull/1800 for insight. This project is supported and maintained by the team at Forward Email @ https://forwardemail.net", "dev": true, "license": "MIT", "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.1" + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.4", + "debug": "^4.3.4", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.0", + "formidable": "^2.1.2", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.11.0", + "semver": "^7.3.8" }, "engines": { - "node": ">=10.0.0" + "node": ">=6.4.0 <13 || >=14" } }, - "node_modules/sockjs": { - "version": "0.3.24", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", - "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "node_modules/superagent/node_modules/formidable": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz", + "integrity": "sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==", "dev": true, + "license": "MIT", "dependencies": { - "faye-websocket": "^0.11.3", - "uuid": "^8.3.2", - "websocket-driver": "^0.7.4" + "dezalgo": "^1.0.4", + "hexoid": "^1.0.0", + "once": "^1.4.0", + "qs": "^6.11.0" + }, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" } }, - "node_modules/sockjs/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/socks": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", - "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", "license": "MIT", "dependencies": { - "ip-address": "^9.0.5", - "smart-buffer": "^4.2.0" + "has-flag": "^3.0.0" }, "engines": { - "node": ">= 10.0.0", - "npm": ">= 3.0.0" + "node": ">=4" } }, - "node_modules/socks-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", - "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, "license": "MIT", - "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" - }, "engines": { - "node": ">= 10" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/swiper": { + "version": "11.1.11", + "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.1.11.tgz", + "integrity": "sha512-077Aw3OrlZpkkBRf/6+44bGh/HZY/vsLEyate2db2KkJgYUIR5TvDgvvhcJtW/puXzw79w5KBc30DauEX6GZYQ==", + "funding": [ + { + "type": "patreon", + "url": "https://www.patreon.com/swiperjs" + }, + { + "type": "open_collective", + "url": "http://opencollective.com/swiper" + } + ], + "license": "MIT", "engines": { - "node": ">= 8" + "node": ">= 4.7.0" } }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "node_modules/symbol-observable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", + "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=0.10" } }, - "node_modules/source-map-loader": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-4.0.1.tgz", - "integrity": "sha512-oqXpzDIByKONVY8g1NUPOTQhe0UTU5bWUl32GSkqK2LjJj0HmwTMVKxcUip0RgAYhY1mqgOxjbQM48a0mmeNfA==", + "node_modules/synckit": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.1.tgz", + "integrity": "sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==", "dev": true, "license": "MIT", "dependencies": { - "abab": "^2.0.6", - "iconv-lite": "^0.6.3", - "source-map-js": "^1.0.2" + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">= 14.15.0" + "node": "^14.18.0 || >=16.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.72.1" + "url": "https://opencollective.com/unts" } }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "dev": true, "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + "engines": { + "node": ">=6" } }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", "dev": true, - "license": "BSD-3-Clause", + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "license": "MIT" - }, - "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "node_modules/tar-fs": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.6.tgz", + "integrity": "sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^2.1.1", + "bare-path": "^2.1.0" } }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true, - "license": "CC-BY-3.0" - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", "dev": true, "license": "MIT", "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" } }, - "node_modules/spdx-license-ids": { - "version": "3.0.16", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", - "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", - "dev": true, - "license": "CC0-1.0" - }, - "node_modules/spdy": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", "dev": true, + "license": "ISC", "dependencies": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" + "minipass": "^3.0.0" }, "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/spdy-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", - "dev": true, - "dependencies": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" + "node": ">= 8" } }, - "node_modules/split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "through": "2" + "yallist": "^4.0.0" }, "engines": { - "node": "*" + "node": ">=8" } }, - "node_modules/split2": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", - "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, "license": "ISC", - "dependencies": { - "readable-stream": "^3.0.0" + "engines": { + "node": ">=8" } }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/ssh-config": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/ssh-config/-/ssh-config-1.1.6.tgz", - "integrity": "sha512-ZPO9rECxzs5JIQ6G/2EfL1I9ho/BVZkx9HRKn8+0af7QgwAmumQ7XBFP1ggMyPMo+/tUbmv0HFdv4qifdO/9JA==", - "license": "MIT" - }, - "node_modules/sshpk": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", - "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true, "license": "MIT", - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" + "mkdirp": "bin/cmd.js" }, "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, - "node_modules/ssri": { - "version": "10.0.5", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", - "integrity": "sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==", + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } + "license": "ISC" }, - "node_modules/ssri/node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "node_modules/temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", "dev": true, - "license": "ISC", + "license": "MIT", "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=8" } }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "node_modules/tempy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-1.0.1.tgz", + "integrity": "sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/stream-buffers": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz", - "integrity": "sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==", - "dev": true, - "license": "Unlicense", - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/stream-combiner2": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", - "integrity": "sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw==", - "license": "MIT", - "dependencies": { - "duplexer2": "~0.1.0", - "readable-stream": "^2.0.2" - } - }, - "node_modules/stream-combiner2/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/stream-combiner2/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/stream-combiner2/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/streamroller": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", - "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "date-format": "^4.0.14", - "debug": "^4.3.4", - "fs-extra": "^8.1.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/streamx": { - "version": "2.18.0", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.18.0.tgz", - "integrity": "sha512-LLUC1TWdjVdn1weXGcSxyTR3T4+acB6tVGXT95y0nGbca4t4o/ng1wKAGTljm9VicuCVLvRlqFYXYy5GwgM7sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-fifo": "^1.3.2", - "queue-tick": "^1.0.1", - "text-decoder": "^1.1.0" - }, - "optionalDependencies": { - "bare-events": "^2.2.0" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "del": "^6.0.0", + "is-stream": "^2.0.0", + "temp-dir": "^2.0.0", + "type-fest": "^0.16.0", + "unique-string": "^2.0.0" }, "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "node": ">=10" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/string.prototype.trim": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", - "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "node_modules/tempy/node_modules/type-fest": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", + "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.0", - "es-object-atoms": "^1.0.0" - }, + "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/string.prototype.trimend": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", - "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "node_modules/terser": { + "version": "5.31.6", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.6.tgz", + "integrity": "sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" } }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", - "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" }, "engines": { - "node": ">= 0.4" + "node": ">= 10.13.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" + "type": "opencollective", + "url": "https://opencollective.com/webpack" }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" + "peerDependencies": { + "webpack": "^5.1.0" }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "license": "MIT", - "engines": { - "node": ">=6" + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } } }, - "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "node_modules/terser-webpack-plugin/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", "dependencies": { - "min-indent": "^1.0.0" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" }, - "engines": { - "node": ">=8" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "ajv": "^6.9.1" } }, - "node_modules/strong-log-transformer": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz", - "integrity": "sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA==", + "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "duplexer": "^0.1.1", - "minimist": "^1.2.0", - "through": "^2.3.4" - }, - "bin": { - "sl-log-transformer": "bin/sl-log-transformer.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/superagent": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.1.2.tgz", - "integrity": "sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA==", - "deprecated": "Please upgrade to v9.0.0+ as we have fixed a public vulnerability with formidable dependency. Note that v9.0.0+ requires Node.js v14.18.0+. See https://github.com/ladjs/superagent/pull/1800 for insight. This project is supported and maintained by the team at Forward Email @ https://forwardemail.net", - "license": "MIT", - "dependencies": { - "component-emitter": "^1.3.0", - "cookiejar": "^2.1.4", - "debug": "^4.3.4", - "fast-safe-stringify": "^2.1.1", - "form-data": "^4.0.0", - "formidable": "^2.1.2", - "methods": "^1.1.2", - "mime": "2.6.0", - "qs": "^6.11.0", - "semver": "^7.3.8" - }, - "engines": { - "node": ">=6.4.0 <13 || >=14" - } + "license": "MIT" }, - "node_modules/superagent/node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, "license": "MIT", "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" }, "engines": { - "node": ">= 6" - } - }, - "node_modules/superagent/node_modules/formidable": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz", - "integrity": "sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==", - "license": "MIT", - "dependencies": { - "dezalgo": "^1.0.4", - "hexoid": "^1.0.0", - "once": "^1.4.0", - "qs": "^6.11.0" + "node": ">= 10.13.0" }, "funding": { - "url": "https://ko-fi.com/tunnckoCore/commissions" - } - }, - "node_modules/superagent/node_modules/mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4.0.0" + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } + "license": "MIT" }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "node_modules/text-decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.1.1.tgz", + "integrity": "sha512-8zll7REEv4GDD3x4/0pW+ppIxSNs7H1J10IKFZsuOMscumCdM2a+toDGLPA3T+1+fLBql4zbt5z83GEQGGV5VA==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/swiper": { - "version": "11.1.11", - "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.1.11.tgz", - "integrity": "sha512-077Aw3OrlZpkkBRf/6+44bGh/HZY/vsLEyate2db2KkJgYUIR5TvDgvvhcJtW/puXzw79w5KBc30DauEX6GZYQ==", - "funding": [ - { - "type": "patreon", - "url": "https://www.patreon.com/swiperjs" - }, - { - "type": "open_collective", - "url": "http://opencollective.com/swiper" - } - ], - "engines": { - "node": ">= 4.7.0" + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" } }, - "node_modules/symbol-observable": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", - "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", + "node_modules/text-extensions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", + "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", "dev": true, "license": "MIT", "engines": { "node": ">=0.10" } }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true, "license": "MIT" }, - "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/tar": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "license": "ISC", - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/tar-fs": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.6.tgz", - "integrity": "sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w==", + "node_modules/thingies": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", + "integrity": "sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==", "dev": true, - "license": "MIT", - "dependencies": { - "pump": "^3.0.0", - "tar-stream": "^3.1.5" - }, - "optionalDependencies": { - "bare-fs": "^2.1.1", - "bare-path": "^2.1.0" + "license": "Unlicense", + "engines": { + "node": ">=10.18" + }, + "peerDependencies": { + "tslib": "^2" } }, - "node_modules/tar-fs/node_modules/tar-stream": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", - "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", "dev": true, "license": "MIT", "dependencies": { - "b4a": "^1.6.4", - "fast-fifo": "^1.2.0", - "streamx": "^2.15.0" + "readable-stream": "3" } }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tmp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", "dev": true, "license": "MIT", - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, "engines": { - "node": ">=6" + "node": ">=14.14" } }, - "node_modules/tar/node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 8" + "node": ">=4" } }, - "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "license": "ISC", + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "devOptional": true, + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" + "is-number": "^7.0.0" }, "engines": { - "node": ">=8" + "node": ">=8.0" } }, - "node_modules/tar/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, - "node_modules/temp-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", - "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=0.6" } }, - "node_modules/tempy": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tempy/-/tempy-1.0.1.tgz", - "integrity": "sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w==", + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", "dev": true, - "license": "MIT", + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "del": "^6.0.0", - "is-stream": "^2.0.0", - "temp-dir": "^2.0.0", - "type-fest": "^0.16.0", - "unique-string": "^2.0.0" + "psl": "^1.1.28", + "punycode": "^2.1.1" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.8" } }, - "node_modules/tempy/node_modules/del": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", - "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", + "node_modules/tough-cookie/node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "license": "MIT", - "dependencies": { - "globby": "^11.0.1", - "graceful-fs": "^4.2.4", - "is-glob": "^4.0.1", - "is-path-cwd": "^2.2.0", - "is-path-inside": "^3.0.2", - "p-map": "^4.0.0", - "rimraf": "^3.0.2", - "slash": "^3.0.0" - }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6" } }, - "node_modules/tempy/node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "dev": true, - "license": "MIT", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, + "license": "MIT" + }, + "node_modules/tree-dump": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.2.tgz", + "integrity": "sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ==", + "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">=10" + "node": ">=10.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" } }, - "node_modules/tempy/node_modules/is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "dev": true, "license": "MIT", - "engines": { - "node": ">=6" + "bin": { + "tree-kill": "cli.js" } }, - "node_modules/tempy/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "node_modules/trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/tempy/node_modules/type-fest": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", - "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", "dev": true, - "license": "(MIT OR CC0-1.0)", + "license": "MIT", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/terser": { - "version": "5.29.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.29.1.tgz", - "integrity": "sha512-lZQ/fyaIGxsbGxApKmoPTODIzELy3++mXhS5hOqaAWZjQtpq/hFHAc+rm29NND1rYRxRWKcjuARNwULNXa5RtQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" + "node": ">=16" }, - "engines": { - "node": ">=10" + "peerDependencies": { + "typescript": ">=4.2.0" } }, - "node_modules/terser-webpack-plugin": { - "version": "5.3.10", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", - "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.20", - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.1", - "terser": "^5.26.0" - }, - "engines": { - "node": ">= 10.13.0" + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" }, "peerDependencies": { - "webpack": "^5.1.0" + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" }, "peerDependenciesMeta": { "@swc/core": { "optional": true }, - "esbuild": { - "optional": true - }, - "uglify-js": { + "@swc/wasm": { "optional": true } } }, - "node_modules/terser-webpack-plugin/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "ajv": "^6.9.1" + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" } }, - "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/terser-webpack-plugin/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" + "minimist": "^1.2.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "bin": { + "json5": "lib/cli.js" } }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true, - "license": "MIT" + "node_modules/tslib": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "license": "0BSD" }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "node_modules/tuf-js": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.2.1.tgz", + "integrity": "sha512-GwIJau9XaA8nLVbUXsN3IlFi7WmQ48gBUrl3FTkkL/XLu/POhBzfmX9hd33FNMX1qAsfl6ozO1iMmW9NC8YniA==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" + "@tufjs/models": "2.0.1", + "debug": "^4.3.4", + "make-fetch-happen": "^13.0.1" }, "engines": { - "node": ">=8" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/test-exclude/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, - "license": "ISC", + "license": "Apache-2.0", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "safe-buffer": "^5.0.1" }, "engines": { "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/text-decoder": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.1.0.tgz", - "integrity": "sha512-TmLJNj6UgX8xcUZo4UDStGQtDiTzF7BzWlzn9g7UWrjkpHr5uJTK1ld16wZ3LXb2vb6jH8qU89dW5whuMdXYdw==", + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "b4a": "^1.6.4" - } + "license": "Unlicense" }, - "node_modules/text-extensions": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", - "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, "engines": { - "node": ">=0.10" + "node": ">= 0.8.0" } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "license": "MIT" - }, - "node_modules/through2": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", - "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true, - "license": "MIT", - "dependencies": { - "readable-stream": "3" + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true - }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, "license": "MIT", "dependencies": { - "os-tmpdir": "~1.0.2" + "media-typer": "0.3.0", + "mime-types": "~2.1.24" }, "engines": { - "node": ">=0.6.0" + "node": ">= 0.6" } }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "devOptional": true, - "license": "MIT", "dependencies": { - "is-number": "^7.0.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" }, "engines": { - "node": ">=8.0" + "node": ">= 0.4" } }, - "node_modules/toidentifier": { + "node_modules/typed-array-byte-length": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", "dev": true, "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, "engines": { - "node": ">=0.6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/touch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", - "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", "dev": true, - "license": "ISC", - "bin": { - "nodetouch": "bin/nodetouch.js" + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/tough-cookie": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", - "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "node_modules/typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" }, "engines": { - "node": ">=6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/tough-cookie/node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "node_modules/typed-assert": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", + "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4.0.0" - } + "license": "MIT" }, - "node_modules/tr46": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", "dev": true, "license": "MIT", "dependencies": { - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=8" + "is-typedarray": "^1.0.0" } }, - "node_modules/tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "license": "MIT", + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "dev": true, + "license": "Apache-2.0", "bin": { - "tree-kill": "cli.js" + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" } }, - "node_modules/trim-newlines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", - "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "node_modules/typescript-strict-plugin": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/typescript-strict-plugin/-/typescript-strict-plugin-2.4.4.tgz", + "integrity": "sha512-OXcWHQk+pW9gqEL/Mb1eTgj/Yiqk1oHBERr9v4VInPOYN++p+cXejmQK/h/VlUPGD++FXQ8pgiqVMyEtxU4T6A==", "dev": true, "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "chalk": "^3.0.0", + "execa": "^4.0.0", + "minimatch": "^9.0.3", + "ora": "^5.4.1", + "yargs": "^16.2.0" + }, + "bin": { + "tsc-strict": "dist/cli/tsc-strict/index.js", + "update-strict-comments": "dist/cli/update-strict-comments/index.js" } }, - "node_modules/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "node_modules/typescript-strict-plugin/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=16" + "node": ">=8" }, - "peerDependencies": { - "typescript": ">=4.2.0" + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "node_modules/typescript-strict-plugin/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", "dev": true, "license": "MIT", "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } + "engines": { + "node": ">=8" } }, - "node_modules/tsconfig-paths": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "node_modules/typescript-strict-plugin/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "node_modules/typescript-strict-plugin/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "license": "MIT", "dependencies": { - "minimist": "^1.2.0" + "color-name": "~1.1.4" }, - "bin": { - "json5": "lib/cli.js" + "engines": { + "node": ">=7.0.0" } }, - "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "license": "0BSD" + "node_modules/typescript-strict-plugin/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "node_modules/typescript-strict-plugin/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "license": "MIT", - "dependencies": { - "tslib": "^1.8.1" - }, "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + "node": ">=8" } }, - "node_modules/tsutils/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true, - "license": "0BSD" - }, - "node_modules/tuf-js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-1.1.7.tgz", - "integrity": "sha512-i3P9Kgw3ytjELUfpuKVDNBJvk4u5bXL6gskv572mcevPbSKCV3zt3djhmlEQ65yERjIbOSncy7U4cQJaB1CBCg==", + "node_modules/typescript-strict-plugin/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "license": "MIT", "dependencies": { - "@tufjs/models": "1.0.4", - "debug": "^4.3.4", - "make-fetch-happen": "^11.1.1" + "has-flag": "^4.0.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=8" } }, - "node_modules/tuf-js/node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "node_modules/typescript-strict-plugin/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, "engines": { - "node": ">= 10" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/tuf-js/node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "node_modules/typescript-strict-plugin/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, "license": "MIT", "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" }, "engines": { - "node": ">= 6" + "node": ">=10" } }, - "node_modules/tuf-js/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "node_modules/ua-parser-js": { + "version": "0.7.38", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.38.tgz", + "integrity": "sha512-fYmIy7fKTSFAhG3fuPlubeGaMoAd6r0rSnfEsO5nEY55i26KSLt9EH7PLQiiqPUhNqYIJvSkTy1oArIcXAbPbA==", "dev": true, - "license": "ISC", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "license": "MIT", "engines": { - "node": ">=12" + "node": "*" } }, - "node_modules/tuf-js/node_modules/make-fetch-happen": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", - "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", - "dev": true, - "license": "ISC", - "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^17.0.0", - "http-cache-semantics": "^4.1.1", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^5.0.0", - "minipass-fetch": "^3.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^10.0.0" + "node_modules/uglify-js": { + "version": "3.19.2", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.2.tgz", + "integrity": "sha512-S8KA6DDI47nQXJSi2ctQ629YzwOVs+bQML6DAtvy0wgNdpi+0ySpQK0g2pxBq2xfF2z3YCscu7NNA8nXT9PlIQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=0.8.0" } }, - "node_modules/tuf-js/node_modules/minipass-fetch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", - "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "dev": true, "license": "MIT", "dependencies": { - "minipass": "^7.0.3", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" }, - "optionalDependencies": { - "encoding": "^0.1.13" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/tuf-js/node_modules/minipass-fetch/node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", "dev": true, - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } + "license": "MIT" }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } + "license": "MIT" }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", "dev": true, - "license": "Unlicense" + "license": "MIT", + "engines": { + "node": ">=4" + } }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "dev": true, "license": "MIT", "dependencies": { - "prelude-ls": "^1.2.1" + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">=4" } }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "license": "(MIT OR CC0-1.0)", + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=4" } }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", "dev": true, "license": "MIT", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, "engines": { - "node": ">= 0.6" + "node": ">=4" } }, - "node_modules/typed-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", - "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", "dev": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.13" - }, "engines": { - "node": ">= 0.4" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/typed-array-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", - "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "node_modules/unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" + "unique-slug": "^4.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", - "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "node_modules/unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" + "imurmurhash": "^0.1.4" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/typed-array-length": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", - "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0" + "crypto-random-string": "^2.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/typed-assert": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", - "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, - "license": "MIT" - }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", "license": "MIT", - "dependencies": { - "is-typedarray": "^1.0.0" + "engines": { + "node": ">= 10.0.0" } }, - "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, + "license": "MIT", "engines": { - "node": ">=4.2.0" + "node": ">= 0.8" } }, - "node_modules/typescript-strict-plugin": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/typescript-strict-plugin/-/typescript-strict-plugin-2.4.4.tgz", - "integrity": "sha512-OXcWHQk+pW9gqEL/Mb1eTgj/Yiqk1oHBERr9v4VInPOYN++p+cXejmQK/h/VlUPGD++FXQ8pgiqVMyEtxU4T6A==", + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", "dev": true, "license": "MIT", - "dependencies": { - "chalk": "^3.0.0", - "execa": "^4.0.0", - "minimatch": "^9.0.3", - "ora": "^5.4.1", - "yargs": "^16.2.0" - }, - "bin": { - "tsc-strict": "dist/cli/tsc-strict/index.js", - "update-strict-comments": "dist/cli/update-strict-comments/index.js" + "engines": { + "node": ">=8" } }, - "node_modules/typescript-strict-plugin/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "escalade": "^3.1.2", + "picocolors": "^1.0.1" }, - "engines": { - "node": ">=8" + "bin": { + "update-browserslist-db": "cli.js" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "peerDependencies": { + "browserslist": ">= 4.21.0" } }, - "node_modules/typescript-strict-plugin/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "license": "MIT", + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "license": "BSD-2-Clause", "dependencies": { - "balanced-match": "^1.0.0" + "punycode": "^2.1.0" } }, - "node_modules/typescript-strict-plugin/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, + "node_modules/uri-js/node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/typescript-strict-plugin/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" }, - "node_modules/typescript-strict-plugin/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "dev": true, "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, "engines": { - "node": ">=7.0.0" + "node": ">= 0.4.0" } }, - "node_modules/typescript-strict-plugin/node_modules/execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", - "dev": true, + "node_modules/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "bin": { + "uuid": "dist/bin/uuid" } }, - "node_modules/typescript-strict-plugin/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true, - "license": "MIT", + "license": "MIT" + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" } }, - "node_modules/typescript-strict-plugin/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, - "node_modules/typescript-strict-plugin/node_modules/human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "node_modules/validate-npm-package-name": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz", + "integrity": "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==", "dev": true, - "license": "Apache-2.0", + "license": "ISC", "engines": { - "node": ">=8.12.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/typescript-strict-plugin/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, + "license": "MIT", "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">= 0.8" } }, - "node_modules/typescript-strict-plugin/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", "dev": true, + "engines": [ + "node >=0.6.0" + ], "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" } }, - "node_modules/typescript-strict-plugin/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "node_modules/vite": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.0.tgz", + "integrity": "sha512-5xokfMX0PIiwCMCMb9ZJcMyh5wbBun0zUzKib+L65vAZ8GY9ePZMXxFrHbr/Kyll2+LSCY7xtERPpxkBDKngwg==", "dev": true, "license": "MIT", "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "esbuild": "^0.21.3", + "postcss": "^8.4.40", + "rollup": "^4.13.0" + }, + "bin": { + "vite": "bin/vite.js" }, "engines": { - "node": ">=10" + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } } }, - "node_modules/typescript-strict-plugin/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "node_modules/vite/node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], "dev": true, - "license": "ISC", + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": ">=10" + "node": ">=12" } }, - "node_modules/ua-parser-js": { - "version": "0.7.37", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.37.tgz", - "integrity": "sha512-xV8kqRKM+jhMvcHWUKthV9fNebIzrNy//2O9ZwWcfiBFR5f25XVZPLlEajk/sf3Ra15V92isyQqnIEXRDaZWEA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/ua-parser-js" - }, - { - "type": "paypal", - "url": "https://paypal.me/faisalman" - }, - { - "type": "github", - "url": "https://github.com/sponsors/faisalman" - } + "node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" ], + "dev": true, "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "*" + "node": ">=12" } }, - "node_modules/uglify-js": { - "version": "3.18.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.18.0.tgz", - "integrity": "sha512-SyVVbcNBCk0dzr9XL/R/ySrmYf0s372K6/hFklzgcp2lBFyXtw4I7BOdDjlLhE1aVqaI/SHWXWmYdlZxuyF38A==", + "node_modules/vite/node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "optional": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, + "os": [ + "android" + ], "engines": { - "node": ">=0.8.0" + "node": ">=12" } }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "node_modules/vite/node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" } }, - "node_modules/undefsafe": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", - "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", - "dev": true, - "license": "MIT" - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "license": "MIT" - }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=4" + "node": ">=12" } }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=4" + "node": ">=12" } }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=4" + "node": ">=12" } }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", - "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=4" + "node": ">=12" } }, - "node_modules/unique-filename": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", - "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "node_modules/vite/node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], "dev": true, - "license": "ISC", - "dependencies": { - "unique-slug": "^4.0.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=12" } }, - "node_modules/unique-slug": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", - "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "node_modules/vite/node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=12" } }, - "node_modules/unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "node_modules/vite/node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", - "dependencies": { - "crypto-random-string": "^2.0.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 4.0.0" + "node": ">=12" } }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.8" + "node": ">=12" } }, - "node_modules/untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } + "node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" ], + "dev": true, "license": "MIT", - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "node_modules/vite/node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], "dev": true, "license": "MIT", - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT" - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4.0" + "node": ">=12" } }, - "node_modules/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" + "node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" ], + "dev": true, "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" } }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true, - "license": "MIT" - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "node_modules/vite/node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], "dev": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" } }, - "node_modules/validate-npm-package-name": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", - "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", + "node_modules/vite/node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "builtins": "^5.0.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=12" } }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "node_modules/vite/node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">= 0.8" + "node": ">=12" } }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "dev": true, - "engines": [ - "node >=0.6.0" + "node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" ], + "dev": true, "license": "MIT", - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" } }, - "node_modules/vite": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.3.tgz", - "integrity": "sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==", + "node_modules/vite/node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, + "hasInstallScript": true, "license": "MIT", - "dependencies": { - "esbuild": "^0.18.10", - "postcss": "^8.4.27", - "rollup": "^3.27.1" - }, "bin": { - "vite": "bin/vite.js" + "esbuild": "bin/esbuild" }, "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" + "node": ">=12" }, "optionalDependencies": { - "fsevents": "~2.3.2" - }, - "peerDependencies": { - "@types/node": ">= 14", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" } }, "node_modules/void-elements": { @@ -24307,34 +24735,12 @@ "node": ">=0.10.0" } }, - "node_modules/w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "browser-process-hrtime": "^1.0.0" - } - }, - "node_modules/w3c-xmlserializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "xml-name-validator": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/watchpack": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", - "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", + "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", "dev": true, + "license": "MIT", "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" @@ -24348,6 +24754,7 @@ "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", "dev": true, + "license": "MIT", "dependencies": { "minimalistic-assert": "^1.0.0" } @@ -24361,6 +24768,13 @@ "defaults": "^1.0.3" } }, + "node_modules/weak-lru-cache": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz", + "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==", + "dev": true, + "license": "MIT" + }, "node_modules/webdriver-js-extender": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz", @@ -24421,6 +24835,19 @@ "node": ">=0.10.0" } }, + "node_modules/webdriver-manager/node_modules/array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-uniq": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/webdriver-manager/node_modules/chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", @@ -24438,25 +24865,41 @@ "node": ">=0.10.0" } }, - "node_modules/webdriver-manager/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "node_modules/webdriver-manager/node_modules/del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha512-Z4fzpbIRjOu7lO5jCETSWoqUDVe0IPOlfugBsF6suen2LKDlVb4QZpKEM9P+buNJ4KI1eN7I083w/pbKUpsrWQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "globby": "^5.0.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "rimraf": "^2.2.8" }, "engines": { - "node": "*" + "node": ">=0.10.0" + } + }, + "node_modules/webdriver-manager/node_modules/globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha512-HJRTIH2EeH44ka+LWig+EqT2ONSYpVlNfx6pyd592/VF1TbfljJ7elwie7oSwcViLGqOdWocSdu2txwBF9bjmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "engines": { + "node": ">=0.10.0" } }, "node_modules/webdriver-manager/node_modules/ini": { @@ -24466,10 +24909,21 @@ "dev": true, "license": "ISC" }, + "node_modules/webdriver-manager/node_modules/is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha512-cnS56eR9SPAscL77ik76ATVqoPARTqPIVkMDVxRaWH06zT+6+CzIroYRJ0VVvm0Z1zfAvxvz9i/D3Ppjaqt5Nw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/webdriver-manager/node_modules/rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", "dependencies": { @@ -24512,21 +24966,43 @@ "node": ">=0.8.0" } }, - "node_modules/webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "node_modules/webdriver-manager/node_modules/xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/webdriver-manager/node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=10.4" + "node": ">=4.0" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, "node_modules/webpack": { "version": "5.94.0", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz", "integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==", "dev": true, + "license": "MIT", "dependencies": { "@types/estree": "^1.0.5", "@webassemblyjs/ast": "^1.12.1", @@ -24569,20 +25045,21 @@ } }, "node_modules/webpack-dev-middleware": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.1.2.tgz", - "integrity": "sha512-Wu+EHmX326YPYUpQLKmKbTyZZJIB8/n6R09pTmB03kJmnMsVPTo9COzHZFr01txwaCAuZvfBJE4ZCHRcKs5JaQ==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.3.0.tgz", + "integrity": "sha512-xD2qnNew+F6KwOGZR7kWdbIou/ud7cVqLEXeK1q0nHcNsX/u7ul/fSdlOTX4ntSL5FNFy7ZJJXbf0piF591JYw==", "dev": true, "license": "MIT", "dependencies": { "colorette": "^2.0.10", - "memfs": "^3.4.12", + "memfs": "^4.6.0", "mime-types": "^2.1.31", + "on-finished": "^2.4.1", "range-parser": "^1.2.1", "schema-utils": "^4.0.0" }, "engines": { - "node": ">= 14.15.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", @@ -24598,54 +25075,55 @@ } }, "node_modules/webpack-dev-server": { - "version": "4.15.1", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", - "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", - "dev": true, - "dependencies": { - "@types/bonjour": "^3.5.9", - "@types/connect-history-api-fallback": "^1.3.5", - "@types/express": "^4.17.13", - "@types/serve-index": "^1.9.1", - "@types/serve-static": "^1.13.10", - "@types/sockjs": "^0.3.33", - "@types/ws": "^8.5.5", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.0.4.tgz", + "integrity": "sha512-dljXhUgx3HqKP2d8J/fUMvhxGhzjeNVarDLcbO/EWMSgRizDkxHQDZQaLFL5VJY9tRBj2Gz+rvCEYYvhbqPHNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/bonjour": "^3.5.13", + "@types/connect-history-api-fallback": "^1.5.4", + "@types/express": "^4.17.21", + "@types/serve-index": "^1.9.4", + "@types/serve-static": "^1.15.5", + "@types/sockjs": "^0.3.36", + "@types/ws": "^8.5.10", "ansi-html-community": "^0.0.8", - "bonjour-service": "^1.0.11", - "chokidar": "^3.5.3", + "bonjour-service": "^1.2.1", + "chokidar": "^3.6.0", "colorette": "^2.0.10", "compression": "^1.7.4", "connect-history-api-fallback": "^2.0.0", "default-gateway": "^6.0.3", "express": "^4.17.3", "graceful-fs": "^4.2.6", - "html-entities": "^2.3.2", + "html-entities": "^2.4.0", "http-proxy-middleware": "^2.0.3", - "ipaddr.js": "^2.0.1", - "launch-editor": "^2.6.0", - "open": "^8.0.9", - "p-retry": "^4.5.0", - "rimraf": "^3.0.2", - "schema-utils": "^4.0.0", - "selfsigned": "^2.1.1", + "ipaddr.js": "^2.1.0", + "launch-editor": "^2.6.1", + "open": "^10.0.3", + "p-retry": "^6.2.0", + "rimraf": "^5.0.5", + "schema-utils": "^4.2.0", + "selfsigned": "^2.4.1", "serve-index": "^1.9.1", "sockjs": "^0.3.24", "spdy": "^4.0.2", - "webpack-dev-middleware": "^5.3.1", - "ws": "^8.13.0" + "webpack-dev-middleware": "^7.1.0", + "ws": "^8.16.0" }, "bin": { "webpack-dev-server": "bin/webpack-dev-server.js" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "^4.37.0 || ^5.0.0" + "webpack": "^5.0.0" }, "peerDependenciesMeta": { "webpack": { @@ -24656,62 +25134,81 @@ } } }, - "node_modules/webpack-dev-server/node_modules/webpack-dev-middleware": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", - "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "node_modules/webpack-dev-server/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, + "license": "ISC", "dependencies": { - "colorette": "^2.0.10", - "memfs": "^3.4.3", - "mime-types": "^2.1.31", - "range-parser": "^1.2.1", - "schema-utils": "^4.0.0" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, - "engines": { - "node": ">= 12.13.0" + "bin": { + "glob": "dist/esm/bin.mjs" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/webpack-dev-server/node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "node_modules/webpack-dev-server/node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, "engines": { - "node": ">=10.0.0" + "node": ">=12.0.0" }, "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" + "@types/express": "^4.17.13" }, "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { + "@types/express": { "optional": true } } }, + "node_modules/webpack-dev-server/node_modules/rimraf": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", + "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/webpack-merge": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.9.0.tgz", - "integrity": "sha512-6NbRQw4+Sy50vYNTw7EyOn41OZItPiXB8GNv3INSoe3PSFaHJEz3SHTrYVaRm2LilNGnFUzh0FAwqPEmU/CwDg==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", + "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", "dev": true, "license": "MIT", "dependencies": { "clone-deep": "^4.0.1", - "wildcard": "^2.0.0" + "flat": "^5.0.2", + "wildcard": "^2.0.1" }, "engines": { - "node": ">=10.0.0" + "node": ">=18.0.0" } }, "node_modules/webpack-sources": { @@ -24773,6 +25270,37 @@ "ajv": "^6.9.1" } }, + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/webpack/node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, "node_modules/webpack/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -24804,6 +25332,7 @@ "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", @@ -24818,59 +25347,27 @@ "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=0.8.0" } }, - "node_modules/whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "dev": true, - "license": "MIT", - "dependencies": { - "iconv-lite": "0.4.24" - } - }, - "node_modules/whatwg-encoding/node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true, - "license": "MIT" - }, "node_modules/whatwg-url": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "dev": true, "license": "MIT", "dependencies": { - "lodash": "^4.7.0", - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" - }, - "engines": { - "node": ">=10" + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" } }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -24926,16 +25423,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, "node_modules/wildcard": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", @@ -24947,6 +25434,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-4.0.0.tgz", "integrity": "sha512-OxmV4wzDKB1x7AZaZgXMVsdJ1qER1ed83ZrTYd5Bwq2HfJVg3DJS8nqlAG4sMoJ7mu8cuRmLEYyU13BKwctRAg==", + "dev": true, "license": "MIT", "dependencies": { "execa": "^4.0.2" @@ -24958,51 +25446,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/windows-release/node_modules/execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/windows-release/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, "license": "MIT", - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/windows-release/node_modules/human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", - "license": "Apache-2.0", "engines": { - "node": ">=8.12.0" + "node": ">=0.10.0" } }, "node_modules/wordwrap": { @@ -25013,9 +25464,10 @@ "license": "MIT" }, "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -25023,10 +25475,7 @@ "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "node": ">=8" } }, "node_modules/wrap-ansi-cjs": { @@ -25077,10 +25526,18 @@ "node": ">=7.0.0" } }, + "node_modules/wrap-ansi-cjs/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, "node_modules/wrap-ansi/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -25096,6 +25553,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -25104,16 +25562,25 @@ "node": ">=7.0.0" } }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, "license": "ISC" }, "node_modules/write-file-atomic": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4", @@ -25122,18 +25589,25 @@ "typedarray-to-buffer": "^3.1.5" } }, + "node_modules/write-file-atomic/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, "node_modules/ws": { - "version": "7.5.10", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", - "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=8.3.0" + "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -25181,17 +25655,17 @@ "xml-js": "bin/cli.js" } }, - "node_modules/xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "node_modules/xml-js/node_modules/sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", "dev": true, - "license": "Apache-2.0" + "license": "ISC" }, "node_modules/xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", "dev": true, "license": "MIT", "dependencies": { @@ -25202,7 +25676,7 @@ "node": ">=4.0.0" } }, - "node_modules/xmlbuilder": { + "node_modules/xml2js/node_modules/xmlbuilder": { "version": "11.0.1", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", @@ -25212,12 +25686,15 @@ "node": ">=4.0" } }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "node_modules/xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=8.0" + } }, "node_modules/xpath": { "version": "0.0.32", @@ -25276,6 +25753,16 @@ } }, "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs/node_modules/yargs-parser": { "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", @@ -25319,14 +25806,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/zone.js": { - "version": "0.13.3", - "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.13.3.tgz", - "integrity": "sha512-MKPbmZie6fASC/ps4dkmIhaT5eonHkEt6eAy80K42tAm0G2W+AahLJjbfi6X9NPdciOE9GRFTTM8u2IiF6O3ww==", + "node_modules/yoctocolors-cjs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz", + "integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==", + "dev": true, "license": "MIT", - "dependencies": { - "tslib": "^2.3.0" + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zone.js": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.14.10.tgz", + "integrity": "sha512-YGAhaO7J5ywOXW6InXNlLmfU194F8lVgu7bRntUF3TiG8Y3nBK0x1UJJuHUP/e8IyihkjCYqhCScpSwnlaSRkQ==", + "license": "MIT" } } } diff --git a/ui/package.json b/ui/package.json index 15d2ea454e1..11ad80f8c00 100644 --- a/ui/package.json +++ b/ui/package.json @@ -4,33 +4,32 @@ "license": "AGPL-3.0", "private": true, "dependencies": { - "@angular/animations": "~16.2.12", - "@angular/common": "~16.2.12", - "@angular/core": "~16.2.12", - "@angular/forms": "~16.2.12", - "@angular/platform-browser": "~16.2.12", - "@angular/platform-browser-dynamic": "~16.2.12", - "@angular/router": "~16.2.12", - "@angular/service-worker": "~16.2.12", - "@capacitor-community/file-opener": "^1.0.5", - "@capacitor/android": "5.7.8", - "@capacitor/app": "^5.0.6", - "@capacitor/core": "5.7.8", - "@capacitor/filesystem": "^5.2.0", - "@capacitor/ios": "5.7.8", - "@capacitor/splash-screen": "^5.0.6", + "@angular/animations": "18.0.5", + "@angular/common": "18.0.5", + "@angular/core": "18.0.5", + "@angular/forms": "18.0.5", + "@angular/platform-browser": "18.0.5", + "@angular/platform-browser-dynamic": "18.0.5", + "@angular/router": "18.0.5", + "@angular/service-worker": "18.0.5", + "@capacitor-community/file-opener": "^6.0.0", + "@capacitor/android": "^6.0.0", + "@capacitor/app": "^6.0.0", + "@capacitor/core": "^6.0.0", + "@capacitor/filesystem": "^6.0.0", + "@capacitor/ios": "^6.0.0", + "@capacitor/splash-screen": "^6.0.0", "@ionic-native/core": "^5.36.0", "@ionic-native/file-opener": "^5.36.0", "@ionic/angular": "^6.7.5", - "@ionic/cli": "^7.1.6", "@ngx-formly/core": "^6.3.0", "@ngx-formly/ionic": "^6.3.6", "@ngx-formly/schematics": "^6.3.0", "@ngx-translate/core": "^15.0.0", "@nodro7/angular-mydatepicker": "^0.14.0", "capacitor-blob-writer": "^1.1.17", - "capacitor-ios-autofill-save-password": "^2.0.0", - "capacitor-secure-storage-plugin": "^0.9.0", + "capacitor-ios-autofill-save-password": "^3.0.0", + "capacitor-secure-storage-plugin": "^0.10.0", "chart.js": "^4.4.4", "chartjs-adapter-date-fns": "^3.0.0", "chartjs-plugin-annotation": "^3.0.1", @@ -42,39 +41,47 @@ "date-fns": "^2.30.0", "file-saver-es": "^2.0.5", "ng2-charts": "4.1.1", - "ngx-cookie-service": "^16.1.0", - "ngx-device-detector": "^6.0.2", + "ngx-cookie-service": "18.0.0", + "ngx-device-detector": "^8.0.0", "ngx-spinner": "^16.0.2", "roboto-fontface": "^0.10.0", "rxjs": "~6.6.7", "swiper": "11.1.11", "tslib": "^2.6.2", "uuid": "^10.0.0", - "zone.js": "~0.13.3" + "zone.js": "~0.14.7" }, "devDependencies": { - "@angular-devkit/build-angular": "^16.2.15", - "@angular-eslint/builder": "^16.3.1", - "@angular-eslint/eslint-plugin": "^16.3.1", - "@angular-eslint/eslint-plugin-template": "^16.3.1", - "@angular-eslint/template-parser": "^16.3.1", - "@angular/cli": "^16.2.13", - "@angular/compiler": "^16.2.12", - "@angular/compiler-cli": "^16.2.12", - "@angular/language-service": "^16.2.12", - "@capacitor/assets": "^3.0.0", + "@angular-devkit/build-angular": "^18.0.5", + "@angular-devkit/core": "18.0.5", + "@angular-devkit/schematics": "18.0.5", + "@angular-eslint/builder": "^18.1.0", + "@angular-eslint/eslint-plugin": "^18.1.0", + "@angular-eslint/eslint-plugin-template": "^18.1.0", + "@angular-eslint/template-parser": "^18.1.0", + "@angular/cli": "18.1.0", + "@angular/compiler": "18.0.5", + "@angular/compiler-cli": "18.0.5", + "@angular/language-service": "18.0.5", + "@capacitor/assets": "^3.0.5", "@capacitor/cli": "6.1.2", "@ionic/angular-toolkit": "^11.0.1", + "@ionic/cli": "^7.2.0", "@stylistic/eslint-plugin": "^2.7.2", "@types/jasmine": "~4.3.6", "@types/jasminewd2": "~2.0.13", + "@types/json-schema": "^7.0.15", "@types/node": "^20.12.6", + "@types/qs": "^6.9.15", + "@types/range-parser": "^1.2.7", + "@types/send": "^0.17.4", "@types/uuid": "^10.0.0", - "@typescript-eslint/eslint-plugin": "^6.21.0", - "@typescript-eslint/parser": "^6.21.0", + "@typescript-eslint/eslint-plugin": "^7.0.0", + "@typescript-eslint/parser": "^7.0.0", + "@typescript-eslint/types": "^7.0.0", "eslint": "^8.57.0", "eslint-plugin-import": "2.29.1", - "eslint-plugin-jsdoc": "48.2.3", + "eslint-plugin-jsdoc": "48.10.0", "eslint-plugin-prefer-arrow": "1.2.3", "eslint-plugin-unused-imports": "^4.1.3", "jasmine-core": "~4.5.0", @@ -87,7 +94,7 @@ "karma-jasmine-html-reporter": "^2.1.0", "protractor": "~7.0.0", "ts-node": "^10.9.2", - "typescript": "~4.9.5", + "typescript": "~5.4.5", "typescript-strict-plugin": "^2.4.4" }, "scripts": { diff --git a/ui/src/app/app-routing.module.ts b/ui/src/app/app-routing.module.ts index 40394041c80..b04097ce80b 100644 --- a/ui/src/app/app-routing.module.ts +++ b/ui/src/app/app-routing.module.ts @@ -1,148 +1,151 @@ -import { NgModule } from '@angular/core'; -import { PreloadAllModules, RouterModule, Routes } from '@angular/router'; -import { environment } from 'src/environments'; -import { ChangelogViewComponent } from './changelog/view/view'; -import { EdgeComponent } from './edge/edge.component'; -import { OverviewComponent as AutarchyChartOverviewComponent } from './edge/history/common/autarchy/overview/overview'; -import { DetailsOverviewComponent as ConsumptionDetailsOverviewComponent } from './edge/history/common/consumption/details/details.overview'; -import { OverviewComponent as ConsumptionChartOverviewComponent } from './edge/history/common/consumption/overview/overview'; -import { DetailsOverviewComponent as GridDetailsOverviewComponent } from './edge/history/common/grid/details/details.overview'; -import { OverviewComponent as GridChartOverviewComponent } from './edge/history/common/grid/overview/overview'; -import { DetailsOverviewComponent } from './edge/history/common/production/details/details.overview'; -import { OverviewComponent as ProductionChartOverviewComponent } from './edge/history/common/production/overview/overview'; -import { OverviewComponent as SelfconsumptionChartOverviewComponent } from './edge/history/common/selfconsumption/overview/overview'; -import { OverviewComponent as ChannelthresholdChartOverviewComponent } from './edge/history/Controller/ChannelThreshold/overview/overview'; -import { OverviewComponent as GridOptimizedChargeChartOverviewComponent } from './edge/history/Controller/Ess/GridoptimizedCharge/overview/overview'; -import { OverviewComponent as TimeOfUseTariffOverviewComponent } from './edge/history/Controller/Ess/TimeOfUseTariff/overview/overview'; -import { DelayedSellToGridChartOverviewComponent } from './edge/history/delayedselltogrid/symmetricpeakshavingchartoverview/delayedselltogridchartoverview.component'; -import { FixDigitalOutputChartOverviewComponent } from './edge/history/fixdigitaloutput/fixdigitaloutputchartoverview/fixdigitaloutputchartoverview.component'; -import { HeatingelementChartOverviewComponent } from './edge/history/heatingelement/heatingelementchartoverview/heatingelementchartoverview.component'; -import { HeatPumpChartOverviewComponent } from './edge/history/heatpump/heatpumpchartoverview/heatpumpchartoverview.component'; -import { HistoryComponent as EdgeHistoryComponent } from './edge/history/history.component'; -import { HistoryDataService } from './edge/history/historydataservice'; -import { HistoryParentComponent } from './edge/history/historyparent.component'; -import { AsymmetricPeakshavingChartOverviewComponent } from './edge/history/peakshaving/asymmetric/asymmetricpeakshavingchartoverview/asymmetricpeakshavingchartoverview.component'; -import { SymmetricPeakshavingChartOverviewComponent } from './edge/history/peakshaving/symmetric/symmetricpeakshavingchartoverview/symmetricpeakshavingchartoverview.component'; -import { TimeslotPeakshavingChartOverviewComponent } from './edge/history/peakshaving/timeslot/timeslotpeakshavingchartoverview/timeslotpeakshavingchartoverview.component'; -import { SinglethresholdChartOverviewComponent } from './edge/history/singlethreshold/singlethresholdchartoverview/singlethresholdchartoverview.component'; -import { StorageChartOverviewComponent } from './edge/history/storage/storagechartoverview/storagechartoverview.component'; -import { LiveComponent as EdgeLiveComponent } from './edge/live/live.component'; -import { LiveDataService } from './edge/live/livedataservice'; -import { AlertingComponent as EdgeSettingsAlerting } from './edge/settings/alerting/alerting.component'; -import { IndexComponent as EdgeSettingsAppIndex } from './edge/settings/app/index.component'; -import { InstallAppComponent as EdgeSettingsAppInstall } from './edge/settings/app/install.component'; -import { SingleAppComponent as EdgeSettingsAppSingle } from './edge/settings/app/single.component'; -import { UpdateAppComponent as EdgeSettingsAppUpdate } from './edge/settings/app/update.component'; -import { ChannelsComponent as EdgeSettingsChannelsComponent } from './edge/settings/channels/channels.component'; -import { IndexComponent as EdgeSettingsComponentInstallIndexComponentComponent } from './edge/settings/component/install/index.component'; -import { ComponentInstallComponent as EdgeSettingsComponentInstallComponentComponent } from './edge/settings/component/install/install.component'; -import { IndexComponent as EdgeSettingsComponentUpdateIndexComponentComponent } from './edge/settings/component/update/index.component'; -import { ComponentUpdateComponent as EdgeSettingsComponentUpdateComponentComponent } from './edge/settings/component/update/update.component'; -import { JsonrpcTestComponent } from './edge/settings/jsonrpctest/jsonrpctest'; -import { NetworkComponent as EdgeSettingsNetworkComponent } from './edge/settings/network/network.component'; -import { PowerAssistantComponent } from './edge/settings/powerassistant/powerassistant'; -import { AliasUpdateComponent } from './edge/settings/profile/aliasupdate.component'; -import { ProfileComponent as EdgeSettingsProfileComponent } from './edge/settings/profile/profile.component'; -import { SettingsComponent as EdgeSettingsComponent } from './edge/settings/settings.component'; -import { SystemComponent as EdgeSettingsSystemComponent } from './edge/settings/system/system.component'; -import { SystemExecuteComponent as EdgeSettingsSystemExecuteComponent } from './edge/settings/systemexecute/systemexecute.component'; -import { SystemLogComponent as EdgeSettingsSystemLogComponent } from './edge/settings/systemlog/systemlog.component'; -import { LoginComponent } from './index/login.component'; -import { OverViewComponent } from './index/overview/overview.component'; -import { LoadingScreenComponent } from './index/shared/loading-screen'; -import { CurrentAndVoltageOverviewComponent } from './shared/components/edge/meter/currentVoltage/currentVoltage.overview'; -import { DataService } from './shared/components/shared/dataservice'; -import { UserComponent } from './user/user.component'; +import { NgModule } from "@angular/core"; +import { PreloadAllModules, RouterModule, Routes } from "@angular/router"; +import { environment } from "src/environments"; +import { ChangelogViewComponent } from "./changelog/view/view"; +import { EdgeComponent } from "./edge/edge.component"; +import { OverviewComponent as AutarchyChartOverviewComponent } from "./edge/history/common/autarchy/overview/overview"; +import { DetailsOverviewComponent as ConsumptionDetailsOverviewComponent } from "./edge/history/common/consumption/details/details.overview"; +import { OverviewComponent as ConsumptionChartOverviewComponent } from "./edge/history/common/consumption/overview/overview"; +import { DetailsOverviewComponent as GridDetailsOverviewComponent } from "./edge/history/common/grid/details/details.overview"; +import { OverviewComponent as GridChartOverviewComponent } from "./edge/history/common/grid/overview/overview"; +import { DetailsOverviewComponent } from "./edge/history/common/production/details/details.overview"; +import { DetailsOverviewComponent as DigitalOutputDetailsOverviewComponent } from "./edge/history/Controller/Io/DigitalOutput/details/details.overview"; +import { OverviewComponent as ProductionChartOverviewComponent } from "./edge/history/common/production/overview/overview"; +import { OverviewComponent as SelfconsumptionChartOverviewComponent } from "./edge/history/common/selfconsumption/overview/overview"; +import { OverviewComponent as ChannelthresholdChartOverviewComponent } from "./edge/history/Controller/ChannelThreshold/overview/overview"; +import { OverviewComponent as GridOptimizedChargeChartOverviewComponent } from "./edge/history/Controller/Ess/GridoptimizedCharge/overview/overview"; +import { OverviewComponent as TimeOfUseTariffOverviewComponent } from "./edge/history/Controller/Ess/TimeOfUseTariff/overview/overview"; +import { DelayedSellToGridChartOverviewComponent } from "./edge/history/delayedselltogrid/symmetricpeakshavingchartoverview/delayedselltogridchartoverview.component"; +import { HeatingelementChartOverviewComponent } from "./edge/history/heatingelement/heatingelementchartoverview/heatingelementchartoverview.component"; +import { HeatPumpChartOverviewComponent } from "./edge/history/heatpump/heatpumpchartoverview/heatpumpchartoverview.component"; +import { HistoryComponent as EdgeHistoryComponent } from "./edge/history/history.component"; +import { HistoryDataService } from "./edge/history/historydataservice"; +import { HistoryParentComponent } from "./edge/history/historyparent.component"; +import { AsymmetricPeakshavingChartOverviewComponent } from "./edge/history/peakshaving/asymmetric/asymmetricpeakshavingchartoverview/asymmetricpeakshavingchartoverview.component"; +import { SymmetricPeakshavingChartOverviewComponent } from "./edge/history/peakshaving/symmetric/symmetricpeakshavingchartoverview/symmetricpeakshavingchartoverview.component"; +import { TimeslotPeakshavingChartOverviewComponent } from "./edge/history/peakshaving/timeslot/timeslotpeakshavingchartoverview/timeslotpeakshavingchartoverview.component"; +import { StorageChartOverviewComponent } from "./edge/history/storage/storagechartoverview/storagechartoverview.component"; +import { LiveComponent as EdgeLiveComponent } from "./edge/live/live.component"; +import { LiveDataService } from "./edge/live/livedataservice"; +import { AlertingComponent as EdgeSettingsAlerting } from "./edge/settings/alerting/alerting.component"; +import { IndexComponent as EdgeSettingsAppIndex } from "./edge/settings/app/index.component"; +import { InstallAppComponent as EdgeSettingsAppInstall } from "./edge/settings/app/install.component"; +import { SingleAppComponent as EdgeSettingsAppSingle } from "./edge/settings/app/single.component"; +import { UpdateAppComponent as EdgeSettingsAppUpdate } from "./edge/settings/app/update.component"; +import { ChannelsComponent as EdgeSettingsChannelsComponent } from "./edge/settings/channels/channels.component"; +import { IndexComponent as EdgeSettingsComponentInstallIndexComponentComponent } from "./edge/settings/component/install/index.component"; +import { ComponentInstallComponent as EdgeSettingsComponentInstallComponentComponent } from "./edge/settings/component/install/install.component"; +import { IndexComponent as EdgeSettingsComponentUpdateIndexComponentComponent } from "./edge/settings/component/update/index.component"; +import { ComponentUpdateComponent as EdgeSettingsComponentUpdateComponentComponent } from "./edge/settings/component/update/update.component"; +import { JsonrpcTestComponent } from "./edge/settings/jsonrpctest/jsonrpctest"; +import { NetworkComponent as EdgeSettingsNetworkComponent } from "./edge/settings/network/network.component"; +import { PowerAssistantComponent } from "./edge/settings/powerassistant/powerassistant"; +import { AliasUpdateComponent } from "./edge/settings/profile/aliasupdate.component"; +import { ProfileComponent as EdgeSettingsProfileComponent } from "./edge/settings/profile/profile.component"; +import { SettingsComponent as EdgeSettingsComponent } from "./edge/settings/settings.component"; +import { SystemComponent as EdgeSettingsSystemComponent } from "./edge/settings/system/system.component"; +import { SystemExecuteComponent as EdgeSettingsSystemExecuteComponent } from "./edge/settings/systemexecute/systemexecute.component"; +import { SystemLogComponent as EdgeSettingsSystemLogComponent } from "./edge/settings/systemlog/systemlog.component"; +import { LoginComponent } from "./index/login.component"; +import { OverViewComponent } from "./index/overview/overview.component"; +import { UserComponent } from "./user/user.component"; +import { LoadingScreenComponent } from "./index/shared/loading-screen"; +import { CurrentAndVoltageOverviewComponent } from "./shared/components/edge/meter/currentVoltage/currentVoltage.overview"; +import { DataService } from "./shared/components/shared/dataservice"; +import { hasEdgeRole } from "./shared/guards/functional-guards"; +import { Role } from "./shared/type/role"; +import { OverviewComponent as DigitalOutputChartOverviewComponent } from "./edge/history/Controller/Io/DigitalOutput/overview/overview"; + export const routes: Routes = [ // TODO should be removed in the future - { path: '', redirectTo: 'index', pathMatch: 'full' }, - { path: 'index', component: LoadingScreenComponent }, - { path: 'login', component: LoginComponent, data: { navbarTitle: environment.uiTitle } }, + { path: "", redirectTo: "index", pathMatch: "full" }, + { path: "index", component: LoadingScreenComponent }, + { path: "login", component: LoginComponent, data: { navbarTitle: environment.uiTitle } }, - { path: 'overview', component: OverViewComponent }, + { path: "overview", component: OverViewComponent }, - { path: 'user', component: UserComponent }, - { path: 'changelog', component: ChangelogViewComponent, data: { navbarTitleToBeTranslated: 'Menu.changelog' } }, + { path: "user", component: UserComponent, data: { navbarTitleToBeTranslated: "Menu.user" } }, + { path: "changelog", component: ChangelogViewComponent, data: { navbarTitleToBeTranslated: "Menu.changelog" } }, // Edge Pages { - path: 'device/:edgeId', component: EdgeComponent, children: [ - { path: '', redirectTo: 'live', pathMatch: 'full' }, + path: "device/:edgeId", component: EdgeComponent, children: [ + { path: "", redirectTo: "live", pathMatch: "full" }, { - path: 'live', data: { navbarTitle: environment.uiTitle }, providers: [{ + path: "live", data: { navbarTitle: environment.uiTitle }, providers: [{ useClass: LiveDataService, provide: DataService, }], component: EdgeLiveComponent, }, { - path: 'history', providers: [{ + path: "history", providers: [{ useClass: HistoryDataService, provide: DataService, }], component: HistoryParentComponent, children: [ - { path: '', component: EdgeHistoryComponent }, + { path: "", component: EdgeHistoryComponent }, // History Chart Pages - { path: ':componentId/asymmetricpeakshavingchart', component: AsymmetricPeakshavingChartOverviewComponent }, - { path: ':componentId/delayedselltogridchart', component: DelayedSellToGridChartOverviewComponent }, - { path: ':componentId/fixdigitaloutputchart', component: FixDigitalOutputChartOverviewComponent }, - { path: ':componentId/gridOptimizedChargeChart', component: GridOptimizedChargeChartOverviewComponent }, - { path: ':componentId/heatingelementchart', component: HeatingelementChartOverviewComponent }, - { path: ':componentId/heatpumpchart', component: HeatPumpChartOverviewComponent }, - { path: ':componentId/scheduleChart', component: TimeOfUseTariffOverviewComponent }, - { path: ':componentId/singlethresholdchart', component: SinglethresholdChartOverviewComponent }, - { path: ':componentId/symmetricpeakshavingchart', component: SymmetricPeakshavingChartOverviewComponent }, - { path: ':componentId/timeslotpeakshavingchart', component: TimeslotPeakshavingChartOverviewComponent }, - { path: 'autarchychart', component: AutarchyChartOverviewComponent }, - { path: 'consumptionchart', component: ConsumptionChartOverviewComponent }, - { path: 'consumptionchart/:componentId', component: ConsumptionDetailsOverviewComponent }, - { path: 'consumptionchart/:componentId/currentVoltage', component: CurrentAndVoltageOverviewComponent }, - { path: 'gridchart', component: GridChartOverviewComponent }, - { path: 'gridchart/:componentId', component: GridDetailsOverviewComponent }, - { path: 'gridchart/:componentId/currentVoltage', component: CurrentAndVoltageOverviewComponent }, - { path: 'productionchart', component: ProductionChartOverviewComponent }, - { path: 'productionchart/:componentId', component: DetailsOverviewComponent }, - { path: 'productionchart/:componentId/currentVoltage', component: CurrentAndVoltageOverviewComponent }, - { path: 'selfconsumptionchart', component: SelfconsumptionChartOverviewComponent }, - { path: 'storagechart', component: StorageChartOverviewComponent }, + { path: ":componentId/asymmetricpeakshavingchart", component: AsymmetricPeakshavingChartOverviewComponent }, + { path: ":componentId/delayedselltogridchart", component: DelayedSellToGridChartOverviewComponent }, + { path: ":componentId/gridOptimizedChargeChart", component: GridOptimizedChargeChartOverviewComponent }, + { path: ":componentId/heatingelementchart", component: HeatingelementChartOverviewComponent }, + { path: ":componentId/heatpumpchart", component: HeatPumpChartOverviewComponent }, + { path: ":componentId/scheduleChart", component: TimeOfUseTariffOverviewComponent }, + { path: ":componentId/symmetricpeakshavingchart", component: SymmetricPeakshavingChartOverviewComponent }, + { path: ":componentId/timeslotpeakshavingchart", component: TimeslotPeakshavingChartOverviewComponent }, + { path: "autarchychart", component: AutarchyChartOverviewComponent }, + { path: "consumptionchart", component: ConsumptionChartOverviewComponent }, + { path: "consumptionchart/:componentId", component: ConsumptionDetailsOverviewComponent }, + { path: "consumptionchart/:componentId/currentVoltage", component: CurrentAndVoltageOverviewComponent }, + { path: "gridchart", component: GridChartOverviewComponent }, + { path: "gridchart/:componentId", component: GridDetailsOverviewComponent }, + { path: "gridchart/:componentId/currentVoltage", component: CurrentAndVoltageOverviewComponent }, + { path: "productionchart", component: ProductionChartOverviewComponent }, + { path: "productionchart/:componentId", component: DetailsOverviewComponent }, + { path: "productionchart/:componentId/currentVoltage", component: CurrentAndVoltageOverviewComponent }, + { path: "selfconsumptionchart", component: SelfconsumptionChartOverviewComponent }, + { path: "storagechart", component: StorageChartOverviewComponent }, // Controllers - { path: 'channelthresholdchart', component: ChannelthresholdChartOverviewComponent }, + { path: "channelthresholdchart", component: ChannelthresholdChartOverviewComponent }, + { path: "digitaloutputchart", component: DigitalOutputChartOverviewComponent }, + { path: "digitaloutputchart/:componentId", component: DigitalOutputDetailsOverviewComponent }, ], }, - { path: 'settings', data: { navbarTitleToBeTranslated: 'Menu.edgeSettings' }, component: EdgeSettingsComponent }, - { path: 'settings/channels', component: EdgeSettingsChannelsComponent }, - { path: 'settings/component.install', component: EdgeSettingsComponentInstallIndexComponentComponent, data: { navbarTitleToBeTranslated: 'Edge.Config.Index.addComponents' } }, - { path: 'settings/component.install/:factoryId', component: EdgeSettingsComponentInstallComponentComponent, data: { navbarTitleToBeTranslated: 'Edge.Config.Index.addComponents' } }, - { path: 'settings/component.update', component: EdgeSettingsComponentUpdateIndexComponentComponent, data: { navbarTitleToBeTranslated: 'Edge.Config.Index.adjustComponents' } }, - { path: 'settings/component.update/:componentId', component: EdgeSettingsComponentUpdateComponentComponent, data: { navbarTitleToBeTranslated: 'Edge.Config.Index.adjustComponents' } }, - { path: 'settings/network', component: EdgeSettingsNetworkComponent, data: { navbarTitleToBeTranslated: 'Edge.Config.Index.networkConfiguration' } }, - { path: 'settings/profile', component: EdgeSettingsProfileComponent }, - { path: 'settings/profile/:componentId', component: AliasUpdateComponent }, - { path: 'settings/systemexecute', component: EdgeSettingsSystemExecuteComponent }, - { path: 'settings/systemlog', component: EdgeSettingsSystemLogComponent, data: { navbarTitleToBeTranslated: 'Edge.Config.Index.liveLog' } }, - { path: 'settings/system', component: EdgeSettingsSystemComponent, data: { navbarTitleToBeTranslated: 'Edge.Config.Index.SYSTEM' } }, - { 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 }, - { path: 'settings/alerting', component: EdgeSettingsAlerting }, - { path: 'settings/jsonrpctest', component: JsonrpcTestComponent }, - { path: 'settings/powerAssistant', component: PowerAssistantComponent, data: { navbarTitle: 'Power-Assistant' } }, + { path: "settings", data: { navbarTitleToBeTranslated: "Menu.edgeSettings" }, component: EdgeSettingsComponent }, + { path: "settings/channels", component: EdgeSettingsChannelsComponent, canActivate: [hasEdgeRole(Role.ADMIN)], data: { navbarTitle: "Channels" } }, + { path: "settings/component.install", component: EdgeSettingsComponentInstallIndexComponentComponent, canActivate: [hasEdgeRole(Role.ADMIN)], data: { navbarTitleToBeTranslated: "Edge.Config.Index.addComponents" } }, + { path: "settings/component.install/:factoryId", component: EdgeSettingsComponentInstallComponentComponent, canActivate: [hasEdgeRole(Role.ADMIN)], data: { navbarTitleToBeTranslated: "Edge.Config.Index.addComponents" } }, + { path: "settings/component.update", component: EdgeSettingsComponentUpdateIndexComponentComponent, canActivate: [hasEdgeRole(Role.ADMIN)], data: { navbarTitleToBeTranslated: "Edge.Config.Index.adjustComponents" } }, + { path: "settings/component.update/:componentId", component: EdgeSettingsComponentUpdateComponentComponent, canActivate: [hasEdgeRole(Role.ADMIN)], data: { navbarTitleToBeTranslated: "Edge.Config.Index.adjustComponents" } }, + { path: "settings/network", component: EdgeSettingsNetworkComponent, canActivate: [hasEdgeRole(Role.INSTALLER)], data: { navbarTitleToBeTranslated: "Edge.Config.Index.networkConfiguration" } }, + { path: "settings/profile", component: EdgeSettingsProfileComponent, data: { navbarTitleToBeTranslated: "Edge.Config.Index.systemProfile" } }, + { path: "settings/profile/:componentId", component: AliasUpdateComponent, data: { navbarTitleToBeTranslated: "Edge.Config.Index.renameComponents" } }, + { path: "settings/systemexecute", component: EdgeSettingsSystemExecuteComponent, canActivate: [hasEdgeRole(Role.ADMIN)], data: { navbarTitleToBeTranslated: "Edge.Config.Index.systemExecute" } }, + { path: "settings/systemlog", component: EdgeSettingsSystemLogComponent, canActivate: [hasEdgeRole(Role.OWNER)], data: { navbarTitleToBeTranslated: "Edge.Config.Index.liveLog" } }, + { path: "settings/system", component: EdgeSettingsSystemComponent, canActivate: [hasEdgeRole(Role.OWNER)], data: { navbarTitleToBeTranslated: "Edge.Config.Index.SYSTEM" } }, + { path: "settings/app", canActivate: [hasEdgeRole(Role.OWNER)], data: { navbarTitle: environment.edgeShortName + " Apps" }, component: EdgeSettingsAppIndex }, + { path: "settings/app/install/:appId", component: EdgeSettingsAppInstall, canActivate: [hasEdgeRole(Role.OWNER)] }, + { path: "settings/app/update/:appId", component: EdgeSettingsAppUpdate, canActivate: [hasEdgeRole(Role.OWNER)] }, + { path: "settings/app/single/:appId", component: EdgeSettingsAppSingle, canActivate: [hasEdgeRole(Role.OWNER)] }, + { path: "settings/alerting", component: EdgeSettingsAlerting, canActivate: [hasEdgeRole(Role.OWNER)], data: { navbarTitleToBeTranslated: "Edge.Config.Index.alerting" } }, + { path: "settings/jsonrpctest", component: JsonrpcTestComponent, data: { navbarTitle: "Jsonrpc Test" } }, + { path: "settings/powerAssistant", component: PowerAssistantComponent, canActivate: [hasEdgeRole(Role.ADMIN)], data: { navbarTitle: "Power-Assistant" } }, ], }, - { path: 'demo', component: LoginComponent }, + { path: "demo", component: LoginComponent }, // Fallback - { path: '**', pathMatch: 'full', redirectTo: 'index' }, + { path: "**", pathMatch: "full", redirectTo: "index" }, ]; export const appRoutingProviders: any[] = []; @NgModule({ imports: [ - RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules }), + RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules, paramsInheritanceStrategy: "always" }), ], exports: [RouterModule], }) diff --git a/ui/src/app/app.component.ts b/ui/src/app/app.component.ts index d4c4c458a00..bcab88af3be 100644 --- a/ui/src/app/app.component.ts +++ b/ui/src/app/app.component.ts @@ -1,25 +1,25 @@ // @ts-strict-ignore -import { Component, OnDestroy, OnInit } from '@angular/core'; -import { Meta, Title } from '@angular/platform-browser'; -import { NavigationEnd, Router } from '@angular/router'; -import { SplashScreen } from '@capacitor/splash-screen'; -import { MenuController, ModalController, Platform, ToastController } from '@ionic/angular'; -import { Subject, Subscription } from 'rxjs'; -import { filter, takeUntil } from 'rxjs/operators'; -import { environment } from '../environments'; -import { AppService } from './app.service'; -import { GlobalRouteChangeHandler } from './shared/service/globalRouteChangeHandler'; -import { Service, UserPermission, Websocket } from './shared/shared'; -import { Language } from './shared/type/language'; +import { Component, OnDestroy, OnInit } from "@angular/core"; +import { Meta, Title } from "@angular/platform-browser"; +import { NavigationEnd, Router } from "@angular/router"; +import { SplashScreen } from "@capacitor/splash-screen"; +import { MenuController, ModalController, Platform, ToastController } from "@ionic/angular"; +import { Subject, Subscription } from "rxjs"; +import { filter, takeUntil } from "rxjs/operators"; +import { environment } from "../environments"; +import { AppService } from "./app.service"; +import { GlobalRouteChangeHandler } from "./shared/service/globalRouteChangeHandler"; +import { Service, UserPermission, Websocket } from "./shared/shared"; +import { Language } from "./shared/type/language"; @Component({ - selector: 'app-root', - templateUrl: 'app.component.html', + selector: "app-root", + templateUrl: "app.component.html", }) export class AppComponent implements OnInit, OnDestroy { public environment = environment; - public backUrl: string | boolean = '/'; + public backUrl: string | boolean = "/"; public enableSideMenu: boolean; public isSystemLogEnabled: boolean = false; @@ -54,8 +54,8 @@ export class AppComponent implements OnInit, OnDestroy { this.subscription.add( this.router.events.pipe(filter(event => event instanceof NavigationEnd)).subscribe((e: NavigationEnd) => { // Hide footer for history detail views - const segments = e.url.split('/'); - this.isHistoryDetailView = segments.slice(0, -1).includes('history'); + const segments = e.url.split("/"); + this.isHistoryDetailView = segments.slice(0, -1).includes("history"); })); this.appService.listen(); @@ -78,12 +78,12 @@ export class AppComponent implements OnInit, OnDestroy { this.service.notificationEvent.pipe(takeUntil(this.ngUnsubscribe)).subscribe(async notification => { const toast = await this.toastController.create({ message: notification.message, - position: 'top', + position: "top", duration: 2000, buttons: [ { - text: 'Ok', - role: 'cancel', + text: "Ok", + role: "cancel", }, ], }); @@ -92,9 +92,9 @@ export class AppComponent implements OnInit, OnDestroy { this.platform.ready().then(() => { // OEM colors exist only after ionic is initialized, so the notch color has to be set here - const notchColor = getComputedStyle(document.documentElement).getPropertyValue('--ion-color-background'); + const notchColor = getComputedStyle(document.documentElement).getPropertyValue("--ion-color-background"); this.meta.updateTag( - { name: 'theme-color', content: notchColor }, + { name: "theme-color", content: notchColor }, ); this.service.deviceHeight = this.platform.height(); this.service.deviceWidth = this.platform.width(); diff --git a/ui/src/app/app.module.ts b/ui/src/app/app.module.ts index 3a7db60566a..8a191a18baa 100644 --- a/ui/src/app/app.module.ts +++ b/ui/src/app/app.module.ts @@ -1,34 +1,34 @@ -import { registerLocaleData } from '@angular/common'; -import { HttpClientModule } from '@angular/common/http'; -import localDE from '@angular/common/locales/de'; -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 { IonicModule, IonicRouteStrategy } from '@ionic/angular'; -import { FORMLY_CONFIG } from '@ngx-formly/core'; -import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core'; -import { AngularMyDatePickerModule } from '@nodro7/angular-mydatepicker'; -import { CookieService } from 'ngx-cookie-service'; -import { DeviceDetectorService } from 'ngx-device-detector'; -import { AppRoutingModule } from './app-routing.module'; -import { AppComponent } from './app.component'; -import { AppService } from './app.service'; -import { CheckForUpdateService } from './appupdateservice'; -import { ChangelogModule } from './changelog/changelog.module'; -import { EdgeModule } from './edge/edge.module'; -import { SettingsModule as EdgeSettingsModule } from './edge/settings/settings.module'; -import { SystemLogComponent } from './edge/settings/systemlog/systemlog.component'; -import { IndexModule } from './index/index.module'; -import { RegistrationModule } from './registration/registration.module'; -import { StatusSingleComponent } from './shared/components/status/single/status.component'; -import { ChartOptionsPopoverComponent } from './shared/legacy/chartoptions/popover/popover.component'; -import { MyErrorHandler } from './shared/service/myerrorhandler'; -import { Pagination } from './shared/service/pagination'; -import { SharedModule } from './shared/shared.module'; -import { registerTranslateExtension } from './shared/translate.extension'; -import { Language, MyTranslateLoader } from './shared/type/language'; -import { UserModule } from './user/user.module'; +import { registerLocaleData } from "@angular/common"; +import { HttpClientModule } from "@angular/common/http"; +import localDE from "@angular/common/locales/de"; +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 { IonicModule, IonicRouteStrategy } from "@ionic/angular"; +import { FORMLY_CONFIG } from "@ngx-formly/core"; +import { TranslateLoader, TranslateModule, TranslateService } from "@ngx-translate/core"; +import { AngularMyDatePickerModule } from "@nodro7/angular-mydatepicker"; +import { CookieService } from "ngx-cookie-service"; +import { DeviceDetectorService } from "ngx-device-detector"; +import { AppRoutingModule } from "./app-routing.module"; +import { AppComponent } from "./app.component"; +import { AppService } from "./app.service"; +import { CheckForUpdateService } from "./appupdateservice"; +import { ChangelogModule } from "./changelog/changelog.module"; +import { EdgeModule } from "./edge/edge.module"; +import { SettingsModule as EdgeSettingsModule } from "./edge/settings/settings.module"; +import { SystemLogComponent } from "./edge/settings/systemlog/systemlog.component"; +import { IndexModule } from "./index/index.module"; +import { RegistrationModule } from "./registration/registration.module"; +import { StatusSingleComponent } from "./shared/components/status/single/status.component"; +import { ChartOptionsPopoverComponent } from "./shared/legacy/chartoptions/popover/popover.component"; +import { MyErrorHandler } from "./shared/service/myerrorhandler"; +import { Pagination } from "./shared/service/pagination"; +import { SharedModule } from "./shared/shared.module"; +import { registerTranslateExtension } from "./shared/translate.extension"; +import { Language, MyTranslateLoader } from "./shared/type/language"; +import { UserModule } from "./user/user.module"; @NgModule({ declarations: [ diff --git a/ui/src/app/app.service.ts b/ui/src/app/app.service.ts index 5bff76b82b5..e544f51838a 100644 --- a/ui/src/app/app.service.ts +++ b/ui/src/app/app.service.ts @@ -1,16 +1,16 @@ // @ts-strict-ignore -import { Injectable } from '@angular/core'; -import { App } from '@capacitor/app'; -import { Capacitor } from '@capacitor/core'; -import { Directory, Encoding, Filesystem } from '@capacitor/filesystem'; -import { FileOpener } from '@ionic-native/file-opener'; -import { AlertController } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; -import { saveAs } from 'file-saver-es'; -import { DeviceDetectorService, DeviceInfo } from 'ngx-device-detector'; -import { BehaviorSubject, Subject } from 'rxjs'; -import { environment } from 'src/environments'; -import { JsonrpcRequest } from './shared/jsonrpc/base'; +import { Injectable } from "@angular/core"; +import { App } from "@capacitor/app"; +import { Capacitor } from "@capacitor/core"; +import { Directory, Encoding, Filesystem } from "@capacitor/filesystem"; +import { FileOpener } from "@ionic-native/file-opener"; +import { AlertController } from "@ionic/angular"; +import { TranslateService } from "@ngx-translate/core"; +import { saveAs } from "file-saver-es"; +import { DeviceDetectorService, DeviceInfo } from "ngx-device-detector"; +import { BehaviorSubject, Subject } from "rxjs"; +import { environment } from "src/environments"; +import { JsonrpcRequest } from "./shared/jsonrpc/base"; @Injectable() export class AppService { @@ -42,9 +42,9 @@ export class AppService { public static getAppStoreLink(): string | null { if (this.isMobile) { switch (AppService.deviceInfo.os) { - case 'iOS': + case "iOS": return environment.links.APP.IOS; - case 'Android': + case "Android": return environment.links.APP.ANDROID; default: return null; @@ -71,25 +71,25 @@ export class AppService { }); FileOpener.open(result.uri, data.type) - .then(() => console.log('File is opened')) - .catch(e => console.log('Error opening file', e)); + .then(() => console.log("File is opened")) + .catch(e => console.log("Error opening file", e)); - console.log('Wrote file', result.uri); + console.log("Wrote file", result.uri); } catch (e) { - console.error('Unable to write file', e); + console.error("Unable to write file", e); } }; } public listen() { // Don't use in web - if (AppService.platform === 'web') { + if (AppService.platform === "web") { return; } this.updateState(); - App.addListener('appStateChange', () => { + App.addListener("appStateChange", () => { this.updateState(); }); } @@ -128,7 +128,7 @@ export class AppService { encoding: Encoding.UTF8, }); - console.log('secrets:', contents); + console.log("secrets:", contents); }; await writeSecretFile(); @@ -146,16 +146,16 @@ export class AppService { header: header, message: message, buttons: [{ - text: this.translate.instant('INSTALLATION.BACK'), - role: 'cancel', + text: this.translate.instant("INSTALLATION.BACK"), + role: "cancel", }, { - text: this.translate.instant('INSTALLATION.FORWARD'), + text: this.translate.instant("INSTALLATION.FORWARD"), handler: () => { successCallback(); }, }], - cssClass: 'alertController', + cssClass: "alertController", }); (await alert).present(); } diff --git a/ui/src/app/appupdateservice.ts b/ui/src/app/appupdateservice.ts index 943f7fd254c..c7c02533b42 100644 --- a/ui/src/app/appupdateservice.ts +++ b/ui/src/app/appupdateservice.ts @@ -4,7 +4,7 @@ import { SwUpdate } from "@angular/service-worker"; import { Service } from "./shared/shared"; @Injectable({ - providedIn: 'root', + providedIn: "root", }) export class CheckForUpdateService { @@ -19,16 +19,18 @@ export class LogUpdateService { constructor(updates: SwUpdate) { updates.versionUpdates.subscribe(evt => { switch (evt.type) { - case 'VERSION_DETECTED': + case "VERSION_DETECTED": console.log(`Downloading new app version: ${evt.version.hash}`); break; - case 'VERSION_READY': + case "VERSION_READY": console.log(`Current app version: ${evt.currentVersion.hash}`); console.log(`New app version ready for use: ${evt.latestVersion.hash}`); break; - case 'VERSION_INSTALLATION_FAILED': + case "VERSION_INSTALLATION_FAILED": console.log(`Failed to install app version '${evt.version.hash}': ${evt.error}`); break; + default: + break; } }); } diff --git a/ui/src/app/changelog/changelog.module.ts b/ui/src/app/changelog/changelog.module.ts index f59ea5869f9..b6a7a5810ae 100644 --- a/ui/src/app/changelog/changelog.module.ts +++ b/ui/src/app/changelog/changelog.module.ts @@ -1,7 +1,7 @@ -import { NgModule } from '@angular/core'; -import { SharedModule } from './../shared/shared.module'; -import { ChangelogComponent } from './view/component/changelog.component'; -import { ChangelogViewComponent } from './view/view'; +import { NgModule } from "@angular/core"; +import { SharedModule } from "./../shared/shared.module"; +import { ChangelogComponent } from "./view/component/changelog.component"; +import { ChangelogViewComponent } from "./view/view"; @NgModule({ imports: [ diff --git a/ui/src/app/changelog/view/component/changelog.component.ts b/ui/src/app/changelog/view/component/changelog.component.ts index cb3e44f3df8..9bba2dcddae 100644 --- a/ui/src/app/changelog/view/component/changelog.component.ts +++ b/ui/src/app/changelog/view/component/changelog.component.ts @@ -1,14 +1,14 @@ -import { Component } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { TranslateService } from '@ngx-translate/core'; -import { environment } from 'src/environments'; -import { Service } from '../../../shared/shared'; -import { Role } from '../../../shared/type/role'; -import { Changelog } from './changelog.constants'; +import { Component } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { TranslateService } from "@ngx-translate/core"; +import { environment } from "src/environments"; +import { Service } from "../../../shared/shared"; +import { Role } from "../../../shared/type/role"; +import { Changelog } from "./changelog.constants"; @Component({ - selector: 'changelog', - templateUrl: './changelog.component.html', + selector: "changelog", + templateUrl: "./changelog.component.html", }) export class ChangelogComponent { @@ -21,9 +21,9 @@ export class ChangelogComponent { changes: Array }[] = [ { - version: 'x.y.z', + version: "x.y.z", changes: [ - Changelog.link("OpenEMS Releases", 'https://github.com/OpenEMS/openems/releases'), + Changelog.link("OpenEMS Releases", "https://github.com/OpenEMS/openems/releases"), ], }, ]; diff --git a/ui/src/app/changelog/view/component/changelog.constants.ts b/ui/src/app/changelog/view/component/changelog.constants.ts index fbd3bed9b24..0bef8c32fa2 100644 --- a/ui/src/app/changelog/view/component/changelog.constants.ts +++ b/ui/src/app/changelog/view/component/changelog.constants.ts @@ -5,7 +5,7 @@ export class Changelog { public static readonly UI_VERSION = "2024.9.0-SNAPSHOT"; public static product(...products: Product[]) { - return products.map(product => Changelog.link(product.name, product.url)).join(", ") + '. '; + return products.map(product => Changelog.link(product.name, product.url)).join(", ") + ". "; } public static app(app: App, ...names: string[]) { @@ -15,7 +15,7 @@ export class Changelog { } public static openems(version: string) { - return 'Update auf OpenEMS Version ' + version + '. Mehr Details auf ' + Changelog.link('Github', 'https://github.com/OpenEMS/openems/releases/tag/' + version); + return "Update auf OpenEMS Version " + version + ". Mehr Details auf " + Changelog.link("Github", "https://github.com/OpenEMS/openems/releases/tag/" + version); } public static openemsComponent(openemsComponent: OpenemsComponent, change: string) { @@ -23,18 +23,18 @@ export class Changelog { } public static library(...libraries: Library[]) { - return 'Aktualisierung externer Programmbibliotheken: ' + libraries.map(library => library.name).join(", "); + return "Aktualisierung externer Programmbibliotheken: " + libraries.map(library => library.name).join(", "); } public static link(title: string, url: string) { - return '' + title + ''; + return "" + title + ""; } } export class Product { - public static readonly OPENEMS_EDGE = new Product('OpenEMS Edge', 'https://github.com/OpenEMS/openems'); - public static readonly OPENEMS_UI = new Product('OpenEMS Edge', 'https://github.com/OpenEMS/openems'); - public static readonly OPENEMS_BACKEND = new Product('OpenEMS Edge', 'https://github.com/OpenEMS/openems'); + public static readonly OPENEMS_EDGE = new Product("OpenEMS Edge", "https://github.com/OpenEMS/openems"); + public static readonly OPENEMS_UI = new Product("OpenEMS Edge", "https://github.com/OpenEMS/openems"); + public static readonly OPENEMS_BACKEND = new Product("OpenEMS Edge", "https://github.com/OpenEMS/openems"); // private to disallow creating other instances of this type private constructor(public readonly name: string, public readonly url: string) { @@ -48,8 +48,8 @@ export class App { } export class OpenemsComponent { - public static readonly PQ_PLUS_ZAEHLER = new OpenemsComponent('PQ-Plus Zähler', 'https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.meter.pqplus'); - public static readonly SDM630_ZAEHLER = new OpenemsComponent('SDM 630 Zähler', 'https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.meter.microcare.sdm630'); + public static readonly PQ_PLUS_ZAEHLER = new OpenemsComponent("PQ-Plus Zähler", "https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.meter.pqplus"); + public static readonly SDM630_ZAEHLER = new OpenemsComponent("SDM 630 Zähler", "https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.meter.microcare.sdm630"); // private to disallow creating other instances of this type private constructor(public readonly name: string, public readonly url: string) { @@ -58,49 +58,49 @@ export class OpenemsComponent { export class Library { // Java - public static readonly APACHE_FELIX_FILEINSTALL = new Library('Apache Felix File Install', 'org.apache.felix..fileinstall'); - public static readonly APACHE_FELIX_FRAMEWORK = new Library('Apache Felix Framework', 'org.apache.felix.framework'); - public static readonly APACHE_FELIX_HTTP_JETTY = new Library('Apache Felix HTTP Jetty', 'org.apache.felix.http.jetty'); - public static readonly APACHE_FELIX_INVENTORY = new Library('Apache Felix Inventory', 'org.apache.felix.inventory'); - public static readonly APACHE_FELIX_METATYPE = new Library('Apache Felix MetaType', 'org.apache.felix.metatype'); - public static readonly APACHE_FELIX_SCR = new Library('Apache Felix SCR', 'org.apache.felix.scr'); - public static readonly APACHE_FELIX_WEBCONSOLE = new Library('Apache Felix Webconsole', 'org.apache.felix.webconsole'); - public static readonly APACHE_FELIX_CONFIGADMIN = new Library('Apache Felix Configuration Admin', 'org.apache.felix.configadmin'); - public static readonly CHARGETIME_OCPP = new Library('Open Charge Alliance Java OCPP', 'eu.chargetime.ocpp'); // https://github.com/ChargeTimeEU/Java-OCA-OCPP - public static readonly ECLIPSE_OSGI = new Library('Eclipse OSGi', 'org.eclipse.osgi'); - public static readonly FASTEXCEL = new Library('fastexcel', 'fastexcel'); - public static readonly GRADLE = new Library('Gradle', 'gradle'); - public static readonly GUAVA = new Library('Guava', 'com.google.guava'); - public static readonly GSON = new Library('GSON', 'com.google.gson'); - public static readonly HIKARI_CP = new Library('HikariCP', 'hikaricp'); - public static readonly INFLUXDB = new Library('influxdb-java', 'influxdb-java'); - public static readonly JNA = new Library('JNA', 'net.java.dev.jna'); - public static readonly JAVA_WEBSOCKET = new Library('Java-WebSocket', 'org.java-websocket'); - public static readonly RETROFIT = new Library('Retrofit', 'com.squareup.retrofit'); - public static readonly MOSHI = new Library('Moshi', 'com.squareup.moshi'); - public static readonly MSGPACK = new Library('MsgPack', 'org.msgpack'); - public static readonly PAX_LOGGING = new Library('PAX Logging', 'org.ops4j.pax.logging'); - public static readonly OSGI_UTIL_FUNCTION = new Library('org.osgi.util.function', 'org.osgi.util.function'); - public static readonly OSGI_UTIL_PROMISE = new Library('org.osgi.util.promise', 'org.osgi.util.promise'); - public static readonly OSGI_SERVICE_JDBC = new Library('org.osgi.service.jdbc', 'org.osgi.service.jdbc'); - public static readonly POSTGRESQL = new Library('Postgresql', 'org.postgresql'); - public static readonly SLF4J = new Library('SLF4j', 'org.slf4j'); - public static readonly RRD4J = new Library('RRD4j', 'org.rrd4j'); - public static readonly OKHTTP = new Library('OkHttp', 'com.squareup.okhttp3'); - public static readonly OKIO = new Library('Okio', 'com.squareup.okio'); + public static readonly APACHE_FELIX_FILEINSTALL = new Library("Apache Felix File Install", "org.apache.felix..fileinstall"); + public static readonly APACHE_FELIX_FRAMEWORK = new Library("Apache Felix Framework", "org.apache.felix.framework"); + public static readonly APACHE_FELIX_HTTP_JETTY = new Library("Apache Felix HTTP Jetty", "org.apache.felix.http.jetty"); + public static readonly APACHE_FELIX_INVENTORY = new Library("Apache Felix Inventory", "org.apache.felix.inventory"); + public static readonly APACHE_FELIX_METATYPE = new Library("Apache Felix MetaType", "org.apache.felix.metatype"); + public static readonly APACHE_FELIX_SCR = new Library("Apache Felix SCR", "org.apache.felix.scr"); + public static readonly APACHE_FELIX_WEBCONSOLE = new Library("Apache Felix Webconsole", "org.apache.felix.webconsole"); + public static readonly APACHE_FELIX_CONFIGADMIN = new Library("Apache Felix Configuration Admin", "org.apache.felix.configadmin"); + public static readonly CHARGETIME_OCPP = new Library("Open Charge Alliance Java OCPP", "eu.chargetime.ocpp"); // https://github.com/ChargeTimeEU/Java-OCA-OCPP + public static readonly ECLIPSE_OSGI = new Library("Eclipse OSGi", "org.eclipse.osgi"); + public static readonly FASTEXCEL = new Library("fastexcel", "fastexcel"); + public static readonly GRADLE = new Library("Gradle", "gradle"); + public static readonly GUAVA = new Library("Guava", "com.google.guava"); + public static readonly GSON = new Library("GSON", "com.google.gson"); + public static readonly HIKARI_CP = new Library("HikariCP", "hikaricp"); + public static readonly INFLUXDB = new Library("influxdb-java", "influxdb-java"); + public static readonly JNA = new Library("JNA", "net.java.dev.jna"); + public static readonly JAVA_WEBSOCKET = new Library("Java-WebSocket", "org.java-websocket"); + public static readonly RETROFIT = new Library("Retrofit", "com.squareup.retrofit"); + public static readonly MOSHI = new Library("Moshi", "com.squareup.moshi"); + public static readonly MSGPACK = new Library("MsgPack", "org.msgpack"); + public static readonly PAX_LOGGING = new Library("PAX Logging", "org.ops4j.pax.logging"); + public static readonly OSGI_UTIL_FUNCTION = new Library("org.osgi.util.function", "org.osgi.util.function"); + public static readonly OSGI_UTIL_PROMISE = new Library("org.osgi.util.promise", "org.osgi.util.promise"); + public static readonly OSGI_SERVICE_JDBC = new Library("org.osgi.service.jdbc", "org.osgi.service.jdbc"); + public static readonly POSTGRESQL = new Library("Postgresql", "org.postgresql"); + public static readonly SLF4J = new Library("SLF4j", "org.slf4j"); + public static readonly RRD4J = new Library("RRD4j", "org.rrd4j"); + public static readonly OKHTTP = new Library("OkHttp", "com.squareup.okhttp3"); + public static readonly OKIO = new Library("Okio", "com.squareup.okio"); // UI - public static readonly ANGULAR = new Library('Angular', 'angular'); - public static readonly D3 = new Library('d3', 'd3'); - public static readonly DATE_FNS = new Library('date-fns', 'date-fns'); // https://date-fns.org/ - public static readonly IONIC = new Library('Ionic', 'ionic'); - public static readonly MYDATEPICKER = new Library('MyDatePicker', 'mydatepicker'); - public static readonly NG2_CHARTS = new Library('ng2-charts', 'ng2-charts'); - public static readonly NGX_COOKIE_SERVICE = new Library('ngx-cookie-service', 'ngx-cookie-service'); - public static readonly NGX_FORMLY = new Library('ngx-formly', 'ngx-formly'); - public static readonly NGX_SPINNER = new Library('ngx-spinner', 'ngx-spinner'); - public static readonly RXJS = new Library('RxJs', 'rxjs'); - public static readonly UUID = new Library('UUID', 'uuid'); + public static readonly ANGULAR = new Library("Angular", "angular"); + public static readonly D3 = new Library("d3", "d3"); + public static readonly DATE_FNS = new Library("date-fns", "date-fns"); // https://date-fns.org/ + public static readonly IONIC = new Library("Ionic", "ionic"); + public static readonly MYDATEPICKER = new Library("MyDatePicker", "mydatepicker"); + public static readonly NG2_CHARTS = new Library("ng2-charts", "ng2-charts"); + public static readonly NGX_COOKIE_SERVICE = new Library("ngx-cookie-service", "ngx-cookie-service"); + public static readonly NGX_FORMLY = new Library("ngx-formly", "ngx-formly"); + public static readonly NGX_SPINNER = new Library("ngx-spinner", "ngx-spinner"); + public static readonly RXJS = new Library("RxJs", "rxjs"); + public static readonly UUID = new Library("UUID", "uuid"); // private to disallow creating other instances of this type private constructor(public readonly name: string, public readonly url: string) { diff --git a/ui/src/app/changelog/view/view.ts b/ui/src/app/changelog/view/view.ts index d196a7a4856..7a08765ad46 100644 --- a/ui/src/app/changelog/view/view.ts +++ b/ui/src/app/changelog/view/view.ts @@ -1,7 +1,7 @@ import { Component } from "@angular/core"; @Component({ - selector: 'changelogViewComponent', - templateUrl: './view.html', + selector: "changelogViewComponent", + templateUrl: "./view.html", }) export class ChangelogViewComponent { } diff --git a/ui/src/app/edge/edge.component.ts b/ui/src/app/edge/edge.component.ts index 6cc3aabb469..fdeeebc3a3c 100644 --- a/ui/src/app/edge/edge.component.ts +++ b/ui/src/app/edge/edge.component.ts @@ -30,7 +30,7 @@ export class EdgeComponent implements OnInit, OnDestroy { public ngOnInit(): void { this.activatedRoute.params.subscribe((params) => { // Set CurrentEdge in Metadata - const edgeId = params['edgeId']; + const edgeId = params["edgeId"]; this.service.updateCurrentEdge(edgeId).then((edge) => { this.edge = edge; @@ -39,12 +39,12 @@ export class EdgeComponent implements OnInit, OnDestroy { .then(() => { // Subscribe on these channels for the state in HeaderComponent - edge.subscribeChannels(this.websocket, '', [ - new ChannelAddress('_sum', 'State'), + edge.subscribeChannels(this.websocket, "", [ + new ChannelAddress("_sum", "State"), ]); }); }).catch(() => { - this.router.navigate(['index']); + this.router.navigate(["index"]); }); }); } diff --git a/ui/src/app/edge/edge.module.ts b/ui/src/app/edge/edge.module.ts index e88789f32af..38a9176e4a1 100644 --- a/ui/src/app/edge/edge.module.ts +++ b/ui/src/app/edge/edge.module.ts @@ -1,8 +1,8 @@ -import { NgModule } from '@angular/core'; -import { SharedModule } from './../shared/shared.module'; -import { EdgeComponent } from './edge.component'; -import { HistoryModule } from './history/history.module'; -import { LiveModule } from './live/live.module'; +import { NgModule } from "@angular/core"; +import { SharedModule } from "./../shared/shared.module"; +import { EdgeComponent } from "./edge.component"; +import { HistoryModule } from "./history/history.module"; +import { LiveModule } from "./live/live.module"; @NgModule({ declarations: [ diff --git a/ui/src/app/edge/history/Controller/ChannelThreshold/chart/totalchart.component.ts b/ui/src/app/edge/history/Controller/ChannelThreshold/chart/totalchart.component.ts index 56270897edd..29658f87838 100644 --- a/ui/src/app/edge/history/Controller/ChannelThreshold/chart/totalchart.component.ts +++ b/ui/src/app/edge/history/Controller/ChannelThreshold/chart/totalchart.component.ts @@ -1,13 +1,13 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { AbstractHistoryChart } from 'src/app/shared/components/chart/abstracthistorychart'; -import { QueryHistoricTimeseriesEnergyResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; -import { ChartAxis, HistoryUtils, Utils, YAxisTitle } from 'src/app/shared/service/utils'; -import { ChannelAddress, EdgeConfig } from 'src/app/shared/shared'; +import { Component } from "@angular/core"; +import { AbstractHistoryChart } from "src/app/shared/components/chart/abstracthistorychart"; +import { QueryHistoricTimeseriesEnergyResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse"; +import { ChartAxis, HistoryUtils, Utils, YAxisType } from "src/app/shared/service/utils"; +import { ChannelAddress, EdgeConfig } from "src/app/shared/shared"; @Component({ - selector: 'totalChart', - templateUrl: '../../../../../shared/components/chart/abstracthistorychart.html', + selector: "totalChart", + templateUrl: "../../../../../shared/components/chart/abstracthistorychart.html", }) export class TotalChartComponent extends AbstractHistoryChart { @@ -20,9 +20,9 @@ export class TotalChartComponent extends AbstractHistoryChart { const input: HistoryUtils.InputChannel[] = []; for (const controllerId of controller) { - const powerChannel = ChannelAddress.fromString(config.getComponentProperties(controllerId)['outputChannelAddress']); + const powerChannel = ChannelAddress.fromString(config.getComponentProperties(controllerId)["outputChannelAddress"]); components[controllerId] = powerChannel.channelId; - input.push({ name: controllerId, powerChannel: powerChannel, energyChannel: new ChannelAddress(controllerId, 'CumulatedActiveTime') }); + input.push({ name: controllerId, powerChannel: powerChannel, energyChannel: new ChannelAddress(controllerId, "CumulatedActiveTime") }); } return { @@ -31,14 +31,14 @@ export class TotalChartComponent extends AbstractHistoryChart { const output: HistoryUtils.DisplayValue[] = []; - const colors: string[] = ['rgb(0,0,139)', 'rgb(0,191,255)', 'rgb(0,0,56)', 'rgb(77,77,174)']; + const colors: string[] = ["rgb(0,0,139)", "rgb(0,191,255)", "rgb(0,0,56)", "rgb(77,77,174)"]; for (let i = 0; i < controller.length; i++) { const controllerId = controller[i]; output.push({ name: components[controllerId] ?? controllerId, nameSuffix: (energyQueryResponse: QueryHistoricTimeseriesEnergyResponse) => { - return energyQueryResponse?.result.data[controllerId + '/CumulatedActiveTime'] ?? null; + return energyQueryResponse?.result.data[controllerId + "/CumulatedActiveTime"] ?? null; }, converter: () => { @@ -54,11 +54,11 @@ export class TotalChartComponent extends AbstractHistoryChart { return output; }, tooltip: { - formatNumber: '1.0-0', + formatNumber: "1.0-0", }, yAxes: [{ - unit: YAxisTitle.RELAY, - position: 'left', + unit: YAxisType.RELAY, + position: "left", yAxisId: ChartAxis.LEFT, }], }; diff --git a/ui/src/app/edge/history/Controller/ChannelThreshold/flat/flat.ts b/ui/src/app/edge/history/Controller/ChannelThreshold/flat/flat.ts index e9c42616532..54403badbeb 100644 --- a/ui/src/app/edge/history/Controller/ChannelThreshold/flat/flat.ts +++ b/ui/src/app/edge/history/Controller/ChannelThreshold/flat/flat.ts @@ -1,13 +1,13 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; +import { Component } from "@angular/core"; -import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; -import { Converter } from 'src/app/shared/components/shared/converter'; -import { ChannelAddress, EdgeConfig } from 'src/app/shared/shared'; +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; +import { Converter } from "src/app/shared/components/shared/converter"; +import { ChannelAddress, EdgeConfig } from "src/app/shared/shared"; @Component({ - selector: 'channelthresholdWidget', - templateUrl: './flat.html', + selector: "channelthresholdWidget", + templateUrl: "./flat.html", }) export class FlatComponent extends AbstractFlatWidget { @@ -20,14 +20,14 @@ export class FlatComponent extends AbstractFlatWidget { protected override getChannelAddresses(): ChannelAddress[] { - this.controllers = this.config.getComponentsByFactory('Controller.ChannelThreshold').concat(this.config.getComponentsImplementingNature('io.openems.impl.controller.channelthreshold.ChannelThresholdController')); + this.controllers = this.config.getComponentsByFactory("Controller.ChannelThreshold").concat(this.config.getComponentsImplementingNature("io.openems.impl.controller.channelthreshold.ChannelThresholdController")); const channelAddresses: ChannelAddress[] = []; for (const controller of this.controllers) { - const output: ChannelAddress | null = ChannelAddress.fromString(controller.properties['outputChannelAddress']); + const output: ChannelAddress | null = ChannelAddress.fromString(controller.properties["outputChannelAddress"]); this.displayName.set(controller.id, this.getDisplayName(controller, output)); - channelAddresses.push(new ChannelAddress(controller.id, 'CumulatedActiveTime')); + channelAddresses.push(new ChannelAddress(controller.id, "CumulatedActiveTime")); } return channelAddresses; } diff --git a/ui/src/app/edge/history/Controller/ChannelThreshold/overview/overview.ts b/ui/src/app/edge/history/Controller/ChannelThreshold/overview/overview.ts index 8ff3f52f7cd..5d6f53c8e92 100644 --- a/ui/src/app/edge/history/Controller/ChannelThreshold/overview/overview.ts +++ b/ui/src/app/edge/history/Controller/ChannelThreshold/overview/overview.ts @@ -2,7 +2,7 @@ import { Component } from "@angular/core"; import { AbstractHistoryChartOverview } from "src/app/shared/components/chart/abstractHistoryChartOverview"; @Component({ - selector: 'overview', - templateUrl: './overview.html', + selector: "overview", + templateUrl: "./overview.html", }) export class OverviewComponent extends AbstractHistoryChartOverview { } diff --git a/ui/src/app/edge/history/Controller/Ess/GridoptimizedCharge/chart/chart.ts b/ui/src/app/edge/history/Controller/Ess/GridoptimizedCharge/chart/chart.ts index f016859e52f..88a6d60c838 100644 --- a/ui/src/app/edge/history/Controller/Ess/GridoptimizedCharge/chart/chart.ts +++ b/ui/src/app/edge/history/Controller/Ess/GridoptimizedCharge/chart/chart.ts @@ -1,86 +1,86 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { TranslateService } from '@ngx-translate/core'; -import { AbstractHistoryChart } from 'src/app/shared/components/chart/abstracthistorychart'; -import { ChartAxis, HistoryUtils, Utils, YAxisTitle } from 'src/app/shared/service/utils'; -import { ChannelAddress, EdgeConfig } from 'src/app/shared/shared'; +import { Component } from "@angular/core"; +import { TranslateService } from "@ngx-translate/core"; +import { AbstractHistoryChart } from "src/app/shared/components/chart/abstracthistorychart"; +import { ChartAxis, HistoryUtils, Utils, YAxisType } from "src/app/shared/service/utils"; +import { ChannelAddress, EdgeConfig } from "src/app/shared/shared"; @Component({ - selector: 'gridOptimizedChargeChart', - templateUrl: '../../../../../../shared/components/chart/abstracthistorychart.html', + selector: "gridOptimizedChargeChart", + templateUrl: "../../../../../../shared/components/chart/abstracthistorychart.html", }) export class GridOptimizedChargeChartComponent extends AbstractHistoryChart { public static getChartData(component: EdgeConfig.Component, translate: TranslateService): HistoryUtils.ChartData { return { input: [ { - name: 'DelayChargeMaximumChargeLimit', - powerChannel: new ChannelAddress(component.id, 'DelayChargeMaximumChargeLimit'), + name: "DelayChargeMaximumChargeLimit", + powerChannel: new ChannelAddress(component.id, "DelayChargeMaximumChargeLimit"), }, { - name: 'SellToGridLimitMinimumChargeLimit', - powerChannel: new ChannelAddress(component.id, 'SellToGridLimitMinimumChargeLimit'), + name: "SellToGridLimitMinimumChargeLimit", + powerChannel: new ChannelAddress(component.id, "SellToGridLimitMinimumChargeLimit"), converter: HistoryUtils.ValueConverter.NEGATIVE_AS_ZERO, }, { - name: 'ProductionDcActualPower', - powerChannel: new ChannelAddress('_sum', 'ProductionDcActualPower'), + name: "ProductionDcActualPower", + powerChannel: new ChannelAddress("_sum", "ProductionDcActualPower"), }, { - name: 'EssActivePower', - powerChannel: new ChannelAddress('_sum', 'EssActivePower'), + name: "EssActivePower", + powerChannel: new ChannelAddress("_sum", "EssActivePower"), }, { - name: 'EssSoc', - powerChannel: new ChannelAddress('_sum', 'EssSoc'), + name: "EssSoc", + powerChannel: new ChannelAddress("_sum", "EssSoc"), }, ], output: (data: HistoryUtils.ChannelData) => ([ { - name: translate.instant('Edge.Index.Widgets.GridOptimizedCharge.maximumCharge'), - converter: () => data['DelayChargeMaximumChargeLimit'], - color: 'rgb(253,197,7)', + name: translate.instant("Edge.Index.Widgets.GridOptimizedCharge.maximumCharge"), + converter: () => data["DelayChargeMaximumChargeLimit"], + color: "rgb(253,197,7)", borderDash: [3, 3], }, { - name: translate.instant('Edge.Index.Widgets.GridOptimizedCharge.minimumCharge'), - converter: () => data['SellToGridLimitMinimumChargeLimit'], - color: 'rgb(200,0,0)', + name: translate.instant("Edge.Index.Widgets.GridOptimizedCharge.minimumCharge"), + converter: () => data["SellToGridLimitMinimumChargeLimit"], + color: "rgb(200,0,0)", borderDash: [3, 3], }, { - name: translate.instant('General.chargePower'), + name: translate.instant("General.chargePower"), converter: () => - (data['ProductionDcActualPower'] + (data["ProductionDcActualPower"] ? - data['ProductionDcActualPower'].map((value, index) => { - return Utils.subtractSafely(data['EssActivePower'][index], value); + data["ProductionDcActualPower"].map((value, index) => { + return Utils.subtractSafely(data["EssActivePower"][index], value); }) : - data['EssActivePower'])?.map(val => HistoryUtils.ValueConverter.POSITIVE_AS_ZERO_AND_INVERT_NEGATIVE(val)) ?? null, - color: 'rgb(0,223,0)', + data["EssActivePower"])?.map(val => HistoryUtils.ValueConverter.POSITIVE_AS_ZERO_AND_INVERT_NEGATIVE(val)) ?? null, + color: "rgb(0,223,0)", }, { - name: translate.instant('General.soc'), - converter: () => data['EssSoc'].map(el => Utils.multiplySafely(el, 1000)), - color: 'rgb(189, 195, 199)', + name: translate.instant("General.soc"), + converter: () => data["EssSoc"].map(el => Utils.multiplySafely(el, 1000)), + color: "rgb(189, 195, 199)", borderDash: [10, 10], yAxisId: ChartAxis.RIGHT, custom: { - unit: YAxisTitle.PERCENTAGE, + unit: YAxisType.PERCENTAGE, }, }, ]), tooltip: { - formatNumber: '1.0-2', + formatNumber: "1.0-2", }, yAxes: [{ - unit: YAxisTitle.ENERGY, - position: 'left', + unit: YAxisType.ENERGY, + position: "left", yAxisId: ChartAxis.LEFT, }, { - unit: YAxisTitle.PERCENTAGE, - position: 'right', + unit: YAxisType.PERCENTAGE, + position: "right", yAxisId: ChartAxis.RIGHT, displayGrid: false, }], diff --git a/ui/src/app/edge/history/Controller/Ess/GridoptimizedCharge/chart/sellToGridLimitChart.component.ts b/ui/src/app/edge/history/Controller/Ess/GridoptimizedCharge/chart/sellToGridLimitChart.component.ts index c1ebb017450..77072343e95 100644 --- a/ui/src/app/edge/history/Controller/Ess/GridoptimizedCharge/chart/sellToGridLimitChart.component.ts +++ b/ui/src/app/edge/history/Controller/Ess/GridoptimizedCharge/chart/sellToGridLimitChart.component.ts @@ -1,13 +1,13 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { TranslateService } from '@ngx-translate/core'; -import { AbstractHistoryChart } from 'src/app/shared/components/chart/abstracthistorychart'; -import { ChartAxis, HistoryUtils, Utils, YAxisTitle } from 'src/app/shared/service/utils'; -import { ChannelAddress } from 'src/app/shared/shared'; +import { Component } from "@angular/core"; +import { TranslateService } from "@ngx-translate/core"; +import { AbstractHistoryChart } from "src/app/shared/components/chart/abstracthistorychart"; +import { ChartAxis, HistoryUtils, Utils, YAxisType } from "src/app/shared/service/utils"; +import { ChannelAddress } from "src/app/shared/shared"; @Component({ - selector: 'sellToGridLimitChart', - templateUrl: '../../../../../../shared/components/chart/abstracthistorychart.html', + selector: "sellToGridLimitChart", + templateUrl: "../../../../../../shared/components/chart/abstracthistorychart.html", }) export class SellToGridLimitChartComponent extends AbstractHistoryChart { @@ -15,56 +15,56 @@ export class SellToGridLimitChartComponent extends AbstractHistoryChart { return { input: [ { - name: 'ActivePower', - powerChannel: new ChannelAddress(gridmeterId, 'ActivePower'), + name: "ActivePower", + powerChannel: new ChannelAddress(gridmeterId, "ActivePower"), converter: HistoryUtils.ValueConverter.ONLY_NEGATIVE_AND_NEGATIVE_AS_POSITIVE, }, { - name: '_PropertyMaximumSellToGridPower', - powerChannel: new ChannelAddress(componentId, '_PropertyMaximumSellToGridPower'), + name: "_PropertyMaximumSellToGridPower", + powerChannel: new ChannelAddress(componentId, "_PropertyMaximumSellToGridPower"), }, { - name: 'ProductionActivePower', - powerChannel: new ChannelAddress('_sum', 'ProductionActivePower'), + name: "ProductionActivePower", + powerChannel: new ChannelAddress("_sum", "ProductionActivePower"), }, ], output: (data: HistoryUtils.ChannelData) => ([ { - name: translate.instant('General.gridSell'), - converter: () => data['ActivePower'], - color: 'rgb(0,0,200)', + name: translate.instant("General.gridSell"), + converter: () => data["ActivePower"], + color: "rgb(0,0,200)", }, { - name: translate.instant('Edge.Index.Widgets.GridOptimizedCharge.maximumGridFeedIn'), - converter: () => data['_PropertyMaximumSellToGridPower'], - color: 'rgb(0,0,0)', + name: translate.instant("Edge.Index.Widgets.GridOptimizedCharge.maximumGridFeedIn"), + converter: () => data["_PropertyMaximumSellToGridPower"], + color: "rgb(0,0,0)", borderDash: [3, 3], }, { - name: translate.instant('Edge.Index.Widgets.GridOptimizedCharge.MAXIMUM_GRIDSELL_WITH_CHARGE'), - converter: () => data['_PropertyMaximumSellToGridPower'].map(el => Utils.multiplySafely(el, 0.95)), - color: 'rgb(200,0,0)', + name: translate.instant("Edge.Index.Widgets.GridOptimizedCharge.MAXIMUM_GRIDSELL_WITH_CHARGE"), + converter: () => data["_PropertyMaximumSellToGridPower"].map(el => Utils.multiplySafely(el, 0.95)), + color: "rgb(200,0,0)", borderDash: [3, 3], }, { - name: translate.instant('General.production'), - converter: () => data['ProductionActivePower'], - color: 'rgb(45,143,171)', + name: translate.instant("General.production"), + converter: () => data["ProductionActivePower"], + color: "rgb(45,143,171)", }, ]), tooltip: { - formatNumber: '1.0-2', + formatNumber: "1.0-2", }, yAxes: [{ - unit: YAxisTitle.ENERGY, - position: 'left', + unit: YAxisType.ENERGY, + position: "left", yAxisId: ChartAxis.LEFT, }], }; } protected getChartData(): HistoryUtils.ChartData { - const gridMeterId = this.config.getComponentProperties(this.component.id)['meter.id']; + const gridMeterId = this.config.getComponentProperties(this.component.id)["meter.id"]; return SellToGridLimitChartComponent.getChartData(gridMeterId, this.component.id, this.translate); } diff --git a/ui/src/app/edge/history/Controller/Ess/GridoptimizedCharge/flat/flat.ts b/ui/src/app/edge/history/Controller/Ess/GridoptimizedCharge/flat/flat.ts index 60c63aa9d5a..67cd22d5d32 100644 --- a/ui/src/app/edge/history/Controller/Ess/GridoptimizedCharge/flat/flat.ts +++ b/ui/src/app/edge/history/Controller/Ess/GridoptimizedCharge/flat/flat.ts @@ -1,12 +1,12 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; -import { Converter } from 'src/app/shared/components/shared/converter'; -import { Filter } from 'src/app/shared/components/shared/filter'; +import { Component } from "@angular/core"; +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; +import { Converter } from "src/app/shared/components/shared/converter"; +import { Filter } from "src/app/shared/components/shared/filter"; @Component({ - selector: 'gridOptimizedChargeWidget', - templateUrl: './flat.html', + selector: "gridOptimizedChargeWidget", + templateUrl: "./flat.html", }) export class FlatComponent extends AbstractFlatWidget { protected FORMAT_SECONDS_TO_DURATION = Converter.FORMAT_SECONDS_TO_DURATION(this.translate.currentLang); diff --git a/ui/src/app/edge/history/Controller/Ess/GridoptimizedCharge/overview/overview.ts b/ui/src/app/edge/history/Controller/Ess/GridoptimizedCharge/overview/overview.ts index 0fdf540900f..f5e4cab17f3 100644 --- a/ui/src/app/edge/history/Controller/Ess/GridoptimizedCharge/overview/overview.ts +++ b/ui/src/app/edge/history/Controller/Ess/GridoptimizedCharge/overview/overview.ts @@ -1,9 +1,9 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { AbstractHistoryChartOverview } from 'src/app/shared/components/chart/abstractHistoryChartOverview'; +import { Component } from "@angular/core"; +import { AbstractHistoryChartOverview } from "src/app/shared/components/chart/abstractHistoryChartOverview"; @Component({ - selector: 'gridoptimizedcharge-chart-overview', - templateUrl: './overview.html', + selector: "gridoptimizedcharge-chart-overview", + templateUrl: "./overview.html", }) export class OverviewComponent extends AbstractHistoryChartOverview { } diff --git a/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/chart/chart.ts b/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/chart/chart.ts index 8bd48521984..6a7850fcafb 100644 --- a/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/chart/chart.ts +++ b/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/chart/chart.ts @@ -1,15 +1,15 @@ // @ts-strict-ignore -import { Component, Input } from '@angular/core'; -import * as Chart from 'chart.js'; -import { calculateResolution, ChronoUnit, Resolution } from 'src/app/edge/history/shared'; -import { AbstractHistoryChart } from 'src/app/shared/components/chart/abstracthistorychart'; -import { ChartAxis, HistoryUtils, TimeOfUseTariffUtils, Utils, YAxisTitle } from 'src/app/shared/service/utils'; +import { Component, Input } from "@angular/core"; +import * as Chart from "chart.js"; +import { calculateResolution, ChronoUnit, Resolution } from "src/app/edge/history/shared"; +import { AbstractHistoryChart } from "src/app/shared/components/chart/abstracthistorychart"; +import { ChartAxis, HistoryUtils, TimeOfUseTariffUtils, Utils, YAxisType } from "src/app/shared/service/utils"; import { ChannelAddress, Currency, EdgeConfig } from "src/app/shared/shared"; -import { ColorUtils } from 'src/app/shared/utils/color/color.utils'; +import { ColorUtils } from "src/app/shared/utils/color/color.utils"; @Component({ - selector: 'scheduleChart', - templateUrl: '../../../../../../shared/components/chart/abstracthistorychart.html', + selector: "scheduleChart", + templateUrl: "../../../../../../shared/components/chart/abstracthistorychart.html", }) export class ChartComponent extends AbstractHistoryChart { @@ -19,76 +19,76 @@ export class ChartComponent extends AbstractHistoryChart { protected override getChartData(): HistoryUtils.ChartData { // Assigning the component to be able to use the id. - const componentId: string = this.config.getComponentIdsByFactory('Controller.Ess.Time-Of-Use-Tariff')[0]; + const componentId: string = this.config.getComponentIdsByFactory("Controller.Ess.Time-Of-Use-Tariff")[0]; this.component = this.config.components[componentId]; - const currency = this.config.components['_meta'].properties.currency; + const currency = this.config.components["_meta"].properties.currency; this.currencyLabel = Currency.getCurrencyLabelByCurrency(currency); - this.chartType = 'bar'; + this.chartType = "bar"; return { input: [ { - name: 'QuarterlyPrice', - powerChannel: ChannelAddress.fromString(this.component.id + '/QuarterlyPrices'), + name: "QuarterlyPrice", + powerChannel: ChannelAddress.fromString(this.component.id + "/QuarterlyPrices"), }, { - name: 'StateMachine', - powerChannel: ChannelAddress.fromString(this.component.id + '/StateMachine'), + name: "StateMachine", + powerChannel: ChannelAddress.fromString(this.component.id + "/StateMachine"), }, { - name: 'Soc', - powerChannel: ChannelAddress.fromString('_sum/EssSoc'), + name: "Soc", + powerChannel: ChannelAddress.fromString("_sum/EssSoc"), }, { - name: 'GridBuy', - powerChannel: ChannelAddress.fromString('_sum/GridActivePower'), + name: "GridBuy", + powerChannel: ChannelAddress.fromString("_sum/GridActivePower"), converter: HistoryUtils.ValueConverter.NEGATIVE_AS_ZERO, }, ], output: (data: HistoryUtils.ChannelData) => { return [{ - name: this.translate.instant('Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.BALANCING'), + name: this.translate.instant("Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.BALANCING"), converter: () => this.getDataset(data, TimeOfUseTariffUtils.State.Balancing), - color: 'rgb(51,102,0)', + color: "rgb(51,102,0)", stack: 1, order: 1, }, { - name: this.translate.instant('Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.CHARGE_GRID'), + name: this.translate.instant("Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.CHARGE_GRID"), converter: () => this.getDataset(data, TimeOfUseTariffUtils.State.ChargeGrid), - color: 'rgb(0, 204, 204)', + color: "rgb(0, 204, 204)", stack: 1, order: 1, }, { - name: this.translate.instant('Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.DELAY_DISCHARGE'), + name: this.translate.instant("Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.DELAY_DISCHARGE"), converter: () => this.getDataset(data, TimeOfUseTariffUtils.State.DelayDischarge), - color: 'rgb(0,0,0)', + color: "rgb(0,0,0)", stack: 1, order: 1, }, { - name: this.translate.instant('General.soc'), - converter: () => data['Soc']?.map(value => Utils.multiplySafely(value, 1000)), - color: 'rgb(189, 195, 199)', + name: this.translate.instant("General.soc"), + converter: () => data["Soc"]?.map(value => Utils.multiplySafely(value, 1000)), + color: "rgb(189, 195, 199)", borderDash: [10, 10], yAxisId: ChartAxis.RIGHT, custom: { - type: 'line', - unit: YAxisTitle.PERCENTAGE, - formatNumber: '1.0-0', + type: "line", + unit: YAxisType.PERCENTAGE, + formatNumber: "1.0-0", }, order: 0, }, { - name: this.translate.instant('General.gridBuy'), - converter: () => data['GridBuy'], - color: 'rgb(0,0,0)', + name: this.translate.instant("General.gridBuy"), + converter: () => data["GridBuy"], + color: "rgb(0,0,0)", yAxisId: ChartAxis.RIGHT_2, custom: { - type: 'line', - formatNumber: '1.0-0', + type: "line", + formatNumber: "1.0-0", }, hiddenOnInit: true, order: 2, @@ -96,22 +96,22 @@ export class ChartComponent extends AbstractHistoryChart { ]; }, tooltip: { - formatNumber: '1.1-4', + formatNumber: "1.1-4", }, yAxes: [{ - unit: YAxisTitle.CURRENCY, - position: 'left', + unit: YAxisType.CURRENCY, + position: "left", yAxisId: ChartAxis.LEFT, }, { - unit: YAxisTitle.PERCENTAGE, - position: 'right', + unit: YAxisType.PERCENTAGE, + position: "right", yAxisId: ChartAxis.RIGHT, displayGrid: false, }, { - unit: YAxisTitle.POWER, - position: 'right', + unit: YAxisType.POWER, + position: "right", yAxisId: ChartAxis.RIGHT_2, displayGrid: false, }, @@ -126,7 +126,7 @@ export class ChartComponent extends AbstractHistoryChart { const unit: Resolution = { unit: ChronoUnit.Type.MINUTES, value: 15 }; this.queryHistoricTimeseriesData(this.service.historyPeriod.value.from, this.service.historyPeriod.value.to, unit) .then((dataResponse) => { - this.chartType = 'line'; + this.chartType = "line"; this.chartObject = this.getChartData(); const displayValues = AbstractHistoryChart.fillChart(this.chartType, this.chartObject, dataResponse); @@ -135,10 +135,10 @@ export class ChartComponent extends AbstractHistoryChart { this.labels = displayValues.labels; this.setChartLabel(); - this.options.scales.x['time'].unit = calculateResolution(this.service, this.service.historyPeriod.value.from, this.service.historyPeriod.value.to).timeFormat; - this.options.scales.x.ticks['source'] = 'auto'; + this.options.scales.x["time"].unit = calculateResolution(this.service, this.service.historyPeriod.value.from, this.service.historyPeriod.value.to).timeFormat; + this.options.scales.x.ticks["source"] = "auto"; this.options.scales.x.grid = { offset: false }; - this.options.plugins.tooltip.mode = 'index'; + this.options.plugins.tooltip.mode = "index"; this.options.scales.x.ticks.maxTicksLimit = 30; this.options.scales[ChartAxis.LEFT].min = this.getMinimumAxisValue(this.datasets); @@ -148,7 +148,7 @@ export class ChartComponent extends AbstractHistoryChart { backgroundColor: item.dataset.backgroundColor, }; }; - this.options.scales.x['bounds'] = 'ticks'; + this.options.scales.x["bounds"] = "ticks"; this.options.plugins.tooltip.callbacks.label = (item: Chart.TooltipItem) => { const label = item.dataset.label; @@ -157,17 +157,17 @@ export class ChartComponent extends AbstractHistoryChart { return TimeOfUseTariffUtils.getLabel(value, label, this.translate, this.currencyLabel); }; - this.options.scales[ChartAxis.LEFT]['title'].text = this.currencyLabel; + this.options.scales[ChartAxis.LEFT]["title"].text = this.currencyLabel; this.datasets = this.datasets.map((el) => { - const opacity = el.type === 'line' ? 0.2 : 0.5; + const opacity = el.type === "line" ? 0.2 : 0.5; el.backgroundColor = ColorUtils.changeOpacityFromRGBA(el.backgroundColor.toString(), opacity); el.borderColor = ColorUtils.changeOpacityFromRGBA(el.borderColor.toString(), 1); return el; }); - this.options.scales.x['offset'] = false; - this.options['animation'] = false; + this.options.scales.x["offset"] = false; + this.options["animation"] = false; }); } @@ -179,9 +179,9 @@ export class ChartComponent extends AbstractHistoryChart { * @returns the desired state array data. */ private getDataset(data: HistoryUtils.ChannelData, desiredState): any[] { - const prices = data['QuarterlyPrice'] + const prices = data["QuarterlyPrice"] .map(val => TimeOfUseTariffUtils.formatPrice(Utils.multiplySafely(val, 1000))); - const states = data['StateMachine'] + const states = data["StateMachine"] .map(val => Utils.multiplySafely(val, 1000)); const length = prices.length; const dataset = Array(length).fill(null); @@ -207,9 +207,9 @@ export class ChartComponent extends AbstractHistoryChart { private getMinimumAxisValue(datasets: Chart.ChartDataset[]): number { const labels = [ - this.translate.instant('Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.BALANCING'), - this.translate.instant('Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.CHARGE_GRID'), - this.translate.instant('Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.DELAY_DISCHARGE'), + this.translate.instant("Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.BALANCING"), + this.translate.instant("Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.CHARGE_GRID"), + this.translate.instant("Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.DELAY_DISCHARGE"), ]; const finalArray: number[] = labels diff --git a/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/flat/flat.ts b/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/flat/flat.ts index 3eb8b26a26f..126647bbd92 100644 --- a/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/flat/flat.ts +++ b/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/flat/flat.ts @@ -1,12 +1,12 @@ -import { Component, Input } from '@angular/core'; +import { Component, Input } from "@angular/core"; -import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; -import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; -import { ChannelAddress, CurrentData } from 'src/app/shared/shared'; +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; +import { DefaultTypes } from "src/app/shared/service/defaulttypes"; +import { ChannelAddress, CurrentData } from "src/app/shared/shared"; @Component({ - selector: 'timeOfUseTariffWidget', - templateUrl: './flat.html', + selector: "timeOfUseTariffWidget", + templateUrl: "./flat.html", }) export class FlatComponent extends AbstractFlatWidget { @@ -17,14 +17,14 @@ export class FlatComponent extends AbstractFlatWidget { override getChannelAddresses(): ChannelAddress[] { return [ - new ChannelAddress(this.componentId, 'DelayedTime'), - new ChannelAddress(this.componentId, 'ChargedTime'), + new ChannelAddress(this.componentId, "DelayedTime"), + new ChannelAddress(this.componentId, "ChargedTime"), ]; } protected override onCurrentData(currentData: CurrentData) { - this.delayedActiveTimeOverPeriod = currentData.allComponents[this.componentId + '/DelayedTime']; - this.chargedConsumptionActiveTimeOverPeriod = currentData.allComponents[this.componentId + '/ChargedTime']; + this.delayedActiveTimeOverPeriod = currentData.allComponents[this.componentId + "/DelayedTime"]; + this.chargedConsumptionActiveTimeOverPeriod = currentData.allComponents[this.componentId + "/ChargedTime"]; } } diff --git a/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/overview/overview.ts b/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/overview/overview.ts index a3f812c1a88..51ed8f95a67 100644 --- a/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/overview/overview.ts +++ b/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/overview/overview.ts @@ -1,7 +1,7 @@ -import { Component } from '@angular/core'; -import { AbstractHistoryChartOverview } from 'src/app/shared/components/chart/abstractHistoryChartOverview'; +import { Component } from "@angular/core"; +import { AbstractHistoryChartOverview } from "src/app/shared/components/chart/abstractHistoryChartOverview"; @Component({ - templateUrl: './overview.html', + templateUrl: "./overview.html", }) export class OverviewComponent extends AbstractHistoryChartOverview { } diff --git a/ui/src/app/edge/history/Controller/Ess/ess.module.ts b/ui/src/app/edge/history/Controller/Ess/ess.module.ts new file mode 100644 index 00000000000..feff7fa422d --- /dev/null +++ b/ui/src/app/edge/history/Controller/Ess/ess.module.ts @@ -0,0 +1,12 @@ +import { NgModule } from "@angular/core"; +import { TimeOfUseTariff } from "./TimeOfUseTariff/timeOfUseTariff.module"; + +@NgModule({ + imports: [ + TimeOfUseTariff, + ], + exports: [ + TimeOfUseTariff, + ], +}) +export class ControllerEss { } diff --git a/ui/src/app/edge/history/Controller/Io/DigitalOutput/chart/chart.ts b/ui/src/app/edge/history/Controller/Io/DigitalOutput/chart/chart.ts new file mode 100644 index 00000000000..9daf18f5179 --- /dev/null +++ b/ui/src/app/edge/history/Controller/Io/DigitalOutput/chart/chart.ts @@ -0,0 +1,68 @@ +import { Component } from "@angular/core"; + +import { AbstractHistoryChart } from "src/app/shared/components/chart/abstracthistorychart"; +import { Name } from "src/app/shared/components/shared/name"; +import { QueryHistoricTimeseriesEnergyResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse"; +import { ChartAxis, HistoryUtils, Utils, YAxisType } from "src/app/shared/service/utils"; +import { ChannelAddress, EdgeConfig } from "src/app/shared/shared"; + +@Component({ + selector: "totalChart", + templateUrl: "../../../../../../shared/components/chart/abstracthistorychart.html", +}) +export class TotalChartComponent extends AbstractHistoryChart { + + public static getChartData(config: EdgeConfig, chartType: "bar" | "line"): HistoryUtils.ChartData { + + const fixDigitalOutputControllers: EdgeConfig.Component[] = config.getComponentsByFactory("Controller.Io.FixDigitalOutput"); + const singleThresholdControllers: EdgeConfig.Component[] = config.getComponentsByFactory("Controller.IO.ChannelSingleThreshold"); + const controllers = [...fixDigitalOutputControllers, ...singleThresholdControllers]; + const input: HistoryUtils.InputChannel[] = []; + + for (const controller of controllers) { + const powerChannel = ChannelAddress.fromString(Array.isArray(config.getComponentProperties(controller.id)["outputChannelAddress"]) + ? config.getComponentProperties(controller.id)["outputChannelAddress"][0] + : config.getComponentProperties(controller.id)["outputChannelAddress"]); + input.push({ name: controller.id, powerChannel: powerChannel, energyChannel: new ChannelAddress(controller.id, "CumulatedActiveTime") }); + } + + return { + input: input, + output: (data: HistoryUtils.ChannelData) => { + const output: HistoryUtils.DisplayValue[] = []; + const colors: string[] = ["rgb(0,0,139)", "rgb(0,191,255)", "rgb(0,0,56)", "rgb(77,77,174)"]; + + for (let i = 0; i < controllers.length; i++) { + const controller = controllers[i]; + output.push({ + name: Name.METER_ALIAS_OR_ID(controller), + nameSuffix: (energyQueryResponse: QueryHistoricTimeseriesEnergyResponse) => { + return energyQueryResponse?.result.data[controller.id + "/CumulatedActiveTime"] ?? null; + }, + converter: () => { + + return data[controller.id] + // TODO add logic to not have to adjust non power data manually + .map(val => Utils.multiplySafely(val, 1000)); + }, + color: colors[i % colors.length], + stack: 0, + }); + } + return output; + }, + tooltip: { + formatNumber: "1.0-0", + }, + yAxes: [{ + unit: chartType === "line" ? YAxisType.RELAY : YAxisType.TIME, + position: "left", + yAxisId: ChartAxis.LEFT, + }], + }; + } + + protected override getChartData(): HistoryUtils.ChartData { + return TotalChartComponent.getChartData(this.config, this.chartType); + } +} diff --git a/ui/src/app/edge/history/Controller/Io/DigitalOutput/details/chart/chart.ts b/ui/src/app/edge/history/Controller/Io/DigitalOutput/details/chart/chart.ts new file mode 100644 index 00000000000..91c271d820a --- /dev/null +++ b/ui/src/app/edge/history/Controller/Io/DigitalOutput/details/chart/chart.ts @@ -0,0 +1,163 @@ +import { Component } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { TranslateService } from "@ngx-translate/core"; +import { AbstractHistoryChart } from "src/app/shared/components/chart/abstracthistorychart"; +import { Name } from "src/app/shared/components/shared/name"; +import { QueryHistoricTimeseriesEnergyResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse"; +import { ChartAxis, HistoryUtils, Utils, YAxisType } from "src/app/shared/service/utils"; +import { ChannelAddress, EdgeConfig } from "src/app/shared/shared"; + +@Component({ + selector: "detailChart", + templateUrl: "../../../../../../../shared/components/chart/abstracthistorychart.html", +}) +export class ChartComponent extends AbstractHistoryChart { + + public static getChartData(config: EdgeConfig, chartType: "line" | "bar", route: ActivatedRoute, translate: TranslateService): HistoryUtils.ChartData { + const controller: EdgeConfig.Component = config.getComponent(route.snapshot.params.componentId); + + const input: HistoryUtils.InputChannel[] = []; + let inputChannel: ChannelAddress | null = null; + const outputChannel = ChannelAddress.fromString(Array.isArray(config.getComponentProperties(controller.id)["outputChannelAddress"]) + ? config.getComponentProperties(controller.id)["outputChannelAddress"][0] + : config.getComponentProperties(controller.id)["outputChannelAddress"]); + + if (controller.factoryId === "Controller.IO.ChannelSingleThreshold") { + inputChannel = ChannelAddress.fromString(config.getComponentProperties(controller.id)["inputChannelAddress"]); + input.push({ + name: inputChannel.toString(), powerChannel: inputChannel, + }); + } + + input.push({ + name: controller.id + "output", powerChannel: outputChannel, energyChannel: new ChannelAddress(controller.id, "CumulatedActiveTime"), + }); + + return { + input: input, + output: (data: HistoryUtils.ChannelData) => { + const output: HistoryUtils.DisplayValue[] = []; + + output.push({ + name: Name.METER_ALIAS_OR_ID(controller), + nameSuffix: (energyQueryResponse: QueryHistoricTimeseriesEnergyResponse) => { + return energyQueryResponse?.result.data[controller.id + "/CumulatedActiveTime"] ?? null; + }, + converter: () => { + + if (chartType == "line") { + return data[controller.id + "output"]?.map(val => Utils.multiplySafely(1000, val)); + } + + return data[controller.id + "output"] + // TODO add logic to not have to adjust non power data manually + ?.map(val => Utils.multiplySafely(val, 1000)); + }, + color: "rgb(0,191,255)", + stack: 0, + }); + + if (inputChannel) { + output.push(ChartComponent.getDisplayValue(data, inputChannel, translate)); + } + + return output; + }, + tooltip: { + formatNumber: "1.0-0", + }, + yAxes: ChartComponent.getYAxes(inputChannel, chartType), + }; + } + protected static getInputChannelLabel(translate: TranslateService, channelAddress: ChannelAddress): string { + switch (channelAddress.channelId) { + case "GridActivePower": + return translate.instant("General.grid"); + case "ProductionActivePower": + return translate.instant("General.production"); + case "EssSoc": + return translate.instant("General.soc"); + default: + return translate.instant("Edge.Index.Widgets.Singlethreshold.other"); + } + } + + protected static getYAxes(inputChannel: ChannelAddress | null, chartType: "line" | "bar"): HistoryUtils.yAxes[] { + const leftYAxis: HistoryUtils.yAxes = { + unit: chartType === "line" ? YAxisType.RELAY : YAxisType.TIME, + position: "left", + yAxisId: ChartAxis.LEFT, + }; + const yAxes: HistoryUtils.yAxes[] = [leftYAxis]; + + if (!inputChannel) { + return yAxes; + } + + if (chartType !== "line") { + return yAxes; + } + + switch (inputChannel.channelId) { + case "EssSoc": + yAxes.push({ + unit: YAxisType.PERCENTAGE, + position: "right", + yAxisId: ChartAxis.RIGHT, + }); + break; + default: + yAxes.push({ + unit: YAxisType.ENERGY, + position: "right", + yAxisId: ChartAxis.RIGHT, + }); + break; + } + return yAxes; + } + + protected static getYAxisId(inputChannel: ChannelAddress): ChartAxis { + if (!inputChannel) { + return ChartAxis.LEFT; + } + + switch (inputChannel.channelId) { + case "EssSoc": + default: + return ChartAxis.RIGHT; + } + } + + protected static getColor(inputChannel: ChannelAddress): string { + if (!inputChannel || inputChannel.channelId != "EssSoc") { + return "rgb(0,0,0)"; + } + return "rgb(189,195,199)"; + } + + protected static getConverter(inputChannel: ChannelAddress, data: HistoryUtils.ChannelData): () => {} { + if (!inputChannel || inputChannel.channelId != "EssSoc") { + return () => data[inputChannel.toString()]; + } + + return () => data[inputChannel.toString()] + // TODO add logic to not have to adjust non power data manually + ?.map((val: number) => Utils.multiplySafely(val, 1000)); + } + + private static getDisplayValue(data: HistoryUtils.ChannelData, inputChannel: ChannelAddress, translate: TranslateService): HistoryUtils.DisplayValue { + return { + name: ChartComponent.getInputChannelLabel(translate, inputChannel), + converter: ChartComponent.getConverter(inputChannel, data), + color: ChartComponent.getColor(inputChannel), + yAxisId: ChartAxis.RIGHT, + stack: 1, + }; + } + protected override getChartData(): HistoryUtils.ChartData { + return ChartComponent.getChartData(this.config, this.chartType, this.route, this.translate); + } + + +} diff --git a/ui/src/app/edge/history/Controller/Io/DigitalOutput/details/details.overview.html b/ui/src/app/edge/history/Controller/Io/DigitalOutput/details/details.overview.html new file mode 100644 index 00000000000..546f5640513 --- /dev/null +++ b/ui/src/app/edge/history/Controller/Io/DigitalOutput/details/details.overview.html @@ -0,0 +1,4 @@ + + + + diff --git a/ui/src/app/edge/history/Controller/Io/DigitalOutput/details/details.overview.ts b/ui/src/app/edge/history/Controller/Io/DigitalOutput/details/details.overview.ts new file mode 100644 index 00000000000..df7cf0ec298 --- /dev/null +++ b/ui/src/app/edge/history/Controller/Io/DigitalOutput/details/details.overview.ts @@ -0,0 +1,7 @@ +import { Component } from "@angular/core"; +import { AbstractHistoryChartOverview } from "src/app/shared/components/chart/abstractHistoryChartOverview"; + +@Component({ + templateUrl: "./details.overview.html", +}) +export class DetailsOverviewComponent extends AbstractHistoryChartOverview { } diff --git a/ui/src/app/edge/history/Controller/Io/DigitalOutput/digitalOutput.module.ts b/ui/src/app/edge/history/Controller/Io/DigitalOutput/digitalOutput.module.ts new file mode 100644 index 00000000000..df92f38b353 --- /dev/null +++ b/ui/src/app/edge/history/Controller/Io/DigitalOutput/digitalOutput.module.ts @@ -0,0 +1,32 @@ +import { NgModule } from "@angular/core"; +import { BrowserModule } from "@angular/platform-browser"; +import { SharedModule } from "src/app/shared/shared.module"; +import { TotalChartComponent } from "./chart/chart"; +import { FlatComponent } from "./flat/flat"; +import { OverviewComponent } from "./overview/overview"; +import { ChartComponent } from "./details/chart/chart"; +import { DetailsOverviewComponent } from "./details/details.overview"; +import { FooterNavigationModule } from "src/app/shared/components/footer/subnavigation/footerNavigation.module"; + +@NgModule({ + imports: [ + BrowserModule, + SharedModule, + FooterNavigationModule, + ], + declarations: [ + FlatComponent, + OverviewComponent, + TotalChartComponent, + DetailsOverviewComponent, + ChartComponent, + ], + exports: [ + FlatComponent, + OverviewComponent, + TotalChartComponent, + DetailsOverviewComponent, + ChartComponent, + ], +}) +export class DigitalOutput { } diff --git a/ui/src/app/edge/history/Controller/Io/DigitalOutput/flat/flat.html b/ui/src/app/edge/history/Controller/Io/DigitalOutput/flat/flat.html new file mode 100644 index 00000000000..95886fc8abf --- /dev/null +++ b/ui/src/app/edge/history/Controller/Io/DigitalOutput/flat/flat.html @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + diff --git a/ui/src/app/edge/history/Controller/Io/DigitalOutput/flat/flat.ts b/ui/src/app/edge/history/Controller/Io/DigitalOutput/flat/flat.ts new file mode 100644 index 00000000000..36aba75e504 --- /dev/null +++ b/ui/src/app/edge/history/Controller/Io/DigitalOutput/flat/flat.ts @@ -0,0 +1,22 @@ +import { Component } from "@angular/core"; +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; +import { TextIndentation } from "src/app/shared/components/modal/modal-line/modal-line"; +import { Converter } from "src/app/shared/components/shared/converter"; +import { EdgeConfig } from "src/app/shared/shared"; + +@Component({ + selector: "DigitalOutputWidget", + templateUrl: "./flat.html", +}) +export class FlatComponent extends AbstractFlatWidget { + protected FORMAT_SECONDS_TO_DURATION = Converter.FORMAT_SECONDS_TO_DURATION(this.translate.currentLang); + protected fixDigitalOutputControllers: EdgeConfig.Component[] = []; + protected singleThresholdControllers: EdgeConfig.Component[] = []; + + protected readonly TextIndentation = TextIndentation; + + protected override afterIsInitialized(): void { + this.fixDigitalOutputControllers = this.config?.getComponentsByFactory("Controller.Io.FixDigitalOutput"); + this.singleThresholdControllers = this.config?.getComponentsByFactory("Controller.IO.ChannelSingleThreshold"); + } +} diff --git a/ui/src/app/edge/history/Controller/Io/DigitalOutput/overview/overview.html b/ui/src/app/edge/history/Controller/Io/DigitalOutput/overview/overview.html new file mode 100644 index 00000000000..4c3b034653b --- /dev/null +++ b/ui/src/app/edge/history/Controller/Io/DigitalOutput/overview/overview.html @@ -0,0 +1,5 @@ + + + + diff --git a/ui/src/app/edge/history/Controller/Io/DigitalOutput/overview/overview.ts b/ui/src/app/edge/history/Controller/Io/DigitalOutput/overview/overview.ts new file mode 100644 index 00000000000..c3eeec802be --- /dev/null +++ b/ui/src/app/edge/history/Controller/Io/DigitalOutput/overview/overview.ts @@ -0,0 +1,36 @@ +// @ts-strict-ignore +import { Component } from "@angular/core"; +import { ActivatedRoute, Router } from "@angular/router"; +import { ModalController } from "@ionic/angular"; +import { AbstractHistoryChartOverview } from "src/app/shared/components/chart/abstractHistoryChartOverview"; +import { NavigationOption } from "src/app/shared/components/footer/subnavigation/footerNavigation"; +import { ChannelAddress, EdgeConfig, Service } from "src/app/shared/shared"; + +@Component({ + selector: "overview", + templateUrl: "./overview.html", +}) +export class OverviewComponent extends AbstractHistoryChartOverview { + + protected navigationButtons: NavigationOption[] = []; + + constructor( + public override service: Service, + protected override route: ActivatedRoute, + public override modalCtrl: ModalController, + private router: Router, + ) { + super(service, route, modalCtrl); + } + + protected override getChannelAddresses(): ChannelAddress[] { + const fixDigitalOutputControllers: EdgeConfig.Component[] = this.config.getComponentsByFactory("Controller.Io.FixDigitalOutput"); + const singleThresholdControllers: EdgeConfig.Component[] = this.config.getComponentsByFactory("Controller.IO.ChannelSingleThreshold"); + const controllers = [...fixDigitalOutputControllers, ...singleThresholdControllers]; + + this.navigationButtons = controllers.map(el => ( + { id: el.id, alias: el.alias, callback: () => { this.router.navigate(["./" + el.id], { relativeTo: this.route }); } } + )); + return []; + } +} diff --git a/ui/src/app/edge/history/Controller/Io/Io.module.ts b/ui/src/app/edge/history/Controller/Io/Io.module.ts new file mode 100644 index 00000000000..caeda2b8417 --- /dev/null +++ b/ui/src/app/edge/history/Controller/Io/Io.module.ts @@ -0,0 +1,12 @@ +import { NgModule } from "@angular/core"; +import { DigitalOutput } from "./DigitalOutput/digitalOutput.module"; + +@NgModule({ + imports: [ + DigitalOutput, + ], + exports: [ + DigitalOutput, + ], +}) +export class ControllerIo { } diff --git a/ui/src/app/edge/history/Controller/controller.module.ts b/ui/src/app/edge/history/Controller/controller.module.ts index 4be2b267717..dec242649f6 100644 --- a/ui/src/app/edge/history/Controller/controller.module.ts +++ b/ui/src/app/edge/history/Controller/controller.module.ts @@ -1,16 +1,21 @@ import { NgModule } from "@angular/core"; - +import { ControllerEss } from "./Ess/ess.module"; +import { ControllerIo } from "./Io/Io.module"; import { ChannelThreshold } from "./ChannelThreshold/channelThreshold.module"; import { GridOptimizeCharge } from "./Ess/GridoptimizedCharge/gridOptimizeCharge.module"; import { TimeOfUseTariff } from "./Ess/TimeOfUseTariff/timeOfUseTariff.module"; @NgModule({ imports: [ + ControllerEss, + ControllerIo, ChannelThreshold, TimeOfUseTariff, GridOptimizeCharge, ], exports: [ + ControllerEss, + ControllerIo, ChannelThreshold, TimeOfUseTariff, GridOptimizeCharge, diff --git a/ui/src/app/edge/history/abstracthistorychart.ts b/ui/src/app/edge/history/abstracthistorychart.ts index f1587b43962..0891b3f453e 100644 --- a/ui/src/app/edge/history/abstracthistorychart.ts +++ b/ui/src/app/edge/history/abstracthistorychart.ts @@ -1,18 +1,18 @@ // @ts-strict-ignore -import { TranslateService } from '@ngx-translate/core'; -import * as Chart from 'chart.js'; -import { AbstractHistoryChart as NewAbstractHistoryChart } from 'src/app/shared/components/chart/abstracthistorychart'; -import { ChartConstants, XAxisType } from 'src/app/shared/components/chart/chart.constants'; -import { JsonrpcResponseError } from 'src/app/shared/jsonrpc/base'; +import { TranslateService } from "@ngx-translate/core"; +import * as Chart from "chart.js"; +import { AbstractHistoryChart as NewAbstractHistoryChart } from "src/app/shared/components/chart/abstracthistorychart"; +import { ChartConstants, XAxisType } from "src/app/shared/components/chart/chart.constants"; +import { JsonrpcResponseError } from "src/app/shared/jsonrpc/base"; import { QueryHistoricTimeseriesDataRequest } from "src/app/shared/jsonrpc/request/queryHistoricTimeseriesDataRequest"; -import { QueryHistoricTimeseriesEnergyPerPeriodRequest } from 'src/app/shared/jsonrpc/request/queryHistoricTimeseriesEnergyPerPeriodRequest'; +import { QueryHistoricTimeseriesEnergyPerPeriodRequest } from "src/app/shared/jsonrpc/request/queryHistoricTimeseriesEnergyPerPeriodRequest"; import { QueryHistoricTimeseriesDataResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesDataResponse"; -import { QueryHistoricTimeseriesEnergyPerPeriodResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyPerPeriodResponse'; -import { ChartAxis, HistoryUtils, Utils, YAxisTitle } from 'src/app/shared/service/utils'; -import { ChannelAddress, Edge, EdgeConfig, Service } from 'src/app/shared/shared'; -import { DateUtils } from 'src/app/shared/utils/date/dateutils'; -import { DateTimeUtils } from 'src/app/shared/utils/datetime/datetime-utils'; -import { calculateResolution, ChronoUnit, DEFAULT_TIME_CHART_OPTIONS, EMPTY_DATASET, Resolution, setLabelVisible } from './shared'; +import { QueryHistoricTimeseriesEnergyPerPeriodResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyPerPeriodResponse"; +import { ChartAxis, HistoryUtils, Utils, YAxisType } from "src/app/shared/service/utils"; +import { ChannelAddress, Edge, EdgeConfig, Service } from "src/app/shared/shared"; +import { DateUtils } from "src/app/shared/utils/date/dateutils"; +import { DateTimeUtils } from "src/app/shared/utils/datetime/datetime-utils"; +import { ChronoUnit, DEFAULT_TIME_CHART_OPTIONS, EMPTY_DATASET, Resolution, calculateResolution, setLabelVisible } from "./shared"; // NOTE: Auto-refresh of widgets is currently disabled to reduce server load export abstract class AbstractHistoryChart { @@ -37,26 +37,29 @@ export abstract class AbstractHistoryChart { protected hasSubscribed: boolean = false; /** @deprecated*/ - protected unit: YAxisTitle = YAxisTitle.ENERGY; + protected unit: YAxisType = YAxisType.ENERGY; /** @deprecated*/ - protected formatNumber: string = '1.0-2'; + protected formatNumber: string = "1.0-2"; /** @deprecated*/ protected xAxisType: XAxisType = XAxisType.TIMESERIES; // Colors for Phase 1-3 protected phase1Color = { - backgroundColor: 'rgba(255,127,80,0.05)', - borderColor: 'rgba(255,127,80,1)', + backgroundColor: "rgba(255,127,80,0.05)", + borderColor: "rgba(255,127,80,1)", }; protected phase2Color = { - backgroundColor: 'rgba(0,0,255,0.1)', - borderColor: 'rgba(0,0,255,1)', + backgroundColor: "rgba(0,0,255,0.1)", + borderColor: "rgba(0,0,255,1)", }; protected phase3Color = { - backgroundColor: 'rgba(128,128,0,0.1)', - borderColor: 'rgba(128,128,0,1)', + backgroundColor: "rgba(128,128,0,0.1)", + borderColor: "rgba(128,128,0,1)", }; + private activeQueryData: string; + private debounceTimeout: any | null = null; + constructor( public readonly spinnerId: string, protected service: Service, @@ -67,21 +70,21 @@ export abstract class AbstractHistoryChart { * Generates a Tooltip Title string from a 'fromDate' and 'toDate'. * * @param fromDate the From-Date - * @param toDate the To-Date + * @param toDate the To-Date * @param date Date from TooltipItem * @returns period for Tooltip Header */ protected static toTooltipTitle(fromDate: Date, toDate: Date, date: Date, service: Service): string { const unit = calculateResolution(service, fromDate, toDate).resolution.unit; if (unit == ChronoUnit.Type.MONTHS) { - return date.toLocaleDateString('default', { month: 'long' }); + return date.toLocaleDateString("default", { month: "long" }); } else if (unit == ChronoUnit.Type.DAYS) { - return date.toLocaleDateString('default', { day: '2-digit', month: 'long' }); + return date.toLocaleDateString("default", { day: "2-digit", month: "long" }); } else { // Default - return date.toLocaleString('default', { day: '2-digit', month: '2-digit', year: '2-digit' }) + ' ' + date.toLocaleTimeString('default', { hour12: false, hour: '2-digit', minute: '2-digit' }); + return date.toLocaleString("default", { day: "2-digit", month: "2-digit", year: "2-digit" }) + " " + date.toLocaleTimeString("default", { hour12: false, hour: "2-digit", minute: "2-digit" }); } } @@ -107,16 +110,16 @@ export abstract class AbstractHistoryChart { } /** - * - * Sets chart options - * - * @deprecated used for charts not using {@link NewAbstractHistoryChart} but {@link AbstractHistoryChart} - */ + * + * Sets chart options + * + * @deprecated used for charts not using {@link NewAbstractHistoryChart} but {@link AbstractHistoryChart} + */ public setOptions(options: Chart.ChartOptions): Promise { return new Promise((resolve) => { const locale = this.service.translate.currentLang; - const yAxis: HistoryUtils.yAxes = { position: 'left', unit: this.unit, yAxisId: ChartAxis.LEFT }; + const yAxis: HistoryUtils.yAxes = { position: "left", unit: this.unit, yAxisId: ChartAxis.LEFT }; const chartObject: HistoryUtils.ChartData = { input: [], output: () => [], @@ -134,7 +137,7 @@ export abstract class AbstractHistoryChart { options = NewAbstractHistoryChart.getDefaultOptions(this.xAxisType, this.service, this.labels); /** Hide default displayed yAxis */ - options.scales['y'] = { + options.scales["y"] = { display: false, }; @@ -152,7 +155,7 @@ export abstract class AbstractHistoryChart { const value = tooltipItem.dataset.data[tooltipItem.dataIndex]; const customUnit = tooltipItem.dataset.unit ?? null; - return label.split(":")[0] + ": " + NewAbstractHistoryChart.getToolTipsSuffix("", value, formatNumber, customUnit ?? unit, 'line', locale, translate, conf); + return label.split(":")[0] + ": " + NewAbstractHistoryChart.getToolTipsSuffix("", value, formatNumber, customUnit ?? unit, "line", locale, translate, conf); }; options.plugins.tooltip.callbacks.labelColor = (item: Chart.TooltipItem) => { @@ -186,10 +189,10 @@ export abstract class AbstractHistoryChart { text: dataset.label, datasetIndex: index, fillStyle: color.backgroundColor, - fontColor: getComputedStyle(document.documentElement).getPropertyValue('--ion-color-text'), + fontColor: getComputedStyle(document.documentElement).getPropertyValue("--ion-color-text"), hidden: !chart.isDatasetVisible(index), lineWidth: 2, - ...(dataset['borderDash'] && { lineDash: dataset['borderDash'] }), + ...(dataset["borderDash"] && { lineDash: dataset["borderDash"] }), strokeStyle: color.borderColor, }); }); @@ -220,29 +223,31 @@ export abstract class AbstractHistoryChart { }; const timeFormat = calculateResolution(this.service, this.service.historyPeriod.value.from, this.service.historyPeriod.value.to).timeFormat; - options.scales.x['time'].unit = timeFormat; + options.scales.x["time"].unit = timeFormat; switch (timeFormat) { - case 'hour': - options.scales.x.ticks['source'] = 'auto';//labels,auto + case "hour": + options.scales.x.ticks["source"] = "auto";//labels,auto options.scales.x.ticks.maxTicksLimit = 31; break; - case 'day': - case 'month': - options.scales.x.ticks['source'] = 'data'; + case "day": + case "month": + options.scales.x.ticks["source"] = "data"; + break; + default: break; } // Only one yAxis defined - options = NewAbstractHistoryChart.getYAxisOptions(options, yAxis, this.translate, 'line', locale, ChartConstants.EMPTY_DATASETS, false); + options = NewAbstractHistoryChart.getYAxisOptions(options, yAxis, this.translate, "line", locale, ChartConstants.EMPTY_DATASETS, false); - options.scales.x['stacked'] = true; - options.scales[ChartAxis.LEFT]['stacked'] = false; - options = NewAbstractHistoryChart.applyChartTypeSpecificOptionsChanges('line', options, this.service, chartObject); + options.scales.x["stacked"] = true; + options.scales[ChartAxis.LEFT]["stacked"] = false; + options = NewAbstractHistoryChart.applyChartTypeSpecificOptionsChanges("line", options, this.service, chartObject); /** Overwrite default yAxisId */ this.datasets = this.datasets .map(el => { - el['yAxisID'] = ChartAxis.LEFT; + el["yAxisID"] = ChartAxis.LEFT; return el; }); }).then(() => { @@ -267,34 +272,47 @@ export abstract class AbstractHistoryChart { this.errorResponse = null; - const result: Promise = new Promise((resolve, reject) => { - this.service.getCurrentEdge().then(edge => { - this.service.getConfig().then(config => { - this.setLabel(config); - this.getChannelAddresses(edge, config).then(channelAddresses => { - - const request = new QueryHistoricTimeseriesDataRequest(DateUtils.maxDate(fromDate, this.edge?.firstSetupProtocol), toDate, channelAddresses, resolution); - edge.sendRequest(this.service.websocket, request).then(response => { - resolve(response as QueryHistoricTimeseriesDataResponse); - }).catch(error => { - this.errorResponse = error; - resolve(new QueryHistoricTimeseriesDataResponse(error.id, { - timestamps: [null], data: { null: null }, - })); + if (this.debounceTimeout) { + clearTimeout(this.debounceTimeout); + } + + this.debounceTimeout = setTimeout(() => { + const result: Promise = new Promise((resolve, reject) => { + this.service.getCurrentEdge().then(edge => { + this.service.getConfig().then(config => { + this.setLabel(config); + this.getChannelAddresses(edge, config).then(channelAddresses => { + const request = new QueryHistoricTimeseriesDataRequest(DateUtils.maxDate(fromDate, this.edge?.firstSetupProtocol), toDate, channelAddresses, resolution); + edge.sendRequest(this.service.websocket, request).then(response => { + resolve(response as QueryHistoricTimeseriesDataResponse); + this.activeQueryData = request.id; + }).catch(error => { + this.errorResponse = error; + resolve(new QueryHistoricTimeseriesDataResponse(error.id, { + timestamps: [null], data: { null: null }, + })); + }); }); }); }); + }).then((response) => { + if (this.activeQueryData !== response.id) { + return; + } + if (Utils.isDataEmpty(response)) { + this.loading = false; + this.service.stopSpinner(this.spinnerId); + this.initializeChart(); + } + return DateTimeUtils.normalizeTimestamps(resolution.unit, response); }); - }).then((response) => { - if (Utils.isDataEmpty(response)) { - this.loading = false; - this.service.stopSpinner(this.spinnerId); - this.initializeChart(); - } - return DateTimeUtils.normalizeTimestamps(resolution.unit, response); - }); - return result; + return result; + }, ChartConstants.REQUEST_TIMEOUT); + + return new Promise((resolve) => { + resolve(new QueryHistoricTimeseriesDataResponse("", { timestamps: [], data: {} })); + }); } /** @@ -403,7 +421,7 @@ export abstract class AbstractHistoryChart { * @param spinnerSelector to stop spinner */ protected initializeChart() { - EMPTY_DATASET[0].label = this.translate.instant('Edge.History.noData'); + EMPTY_DATASET[0].label = this.translate.instant("Edge.History.noData"); this.datasets = EMPTY_DATASET; this.labels = []; this.loading = false; diff --git a/ui/src/app/edge/history/abstracthistorywidget.ts b/ui/src/app/edge/history/abstracthistorywidget.ts index 22459c5a240..2af3a49bc47 100644 --- a/ui/src/app/edge/history/abstracthistorywidget.ts +++ b/ui/src/app/edge/history/abstracthistorywidget.ts @@ -1,14 +1,17 @@ // @ts-strict-ignore -import { JsonrpcResponseError } from 'src/app/shared/jsonrpc/base'; -import { QueryHistoricTimeseriesDataRequest } from 'src/app/shared/jsonrpc/request/queryHistoricTimeseriesDataRequest'; -import { QueryHistoricTimeseriesDataResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesDataResponse'; -import { ChannelAddress, Edge, EdgeConfig, Service } from 'src/app/shared/shared'; -import { DateUtils } from 'src/app/shared/utils/date/dateutils'; -import { calculateResolution } from './shared'; +import { JsonrpcResponseError } from "src/app/shared/jsonrpc/base"; +import { QueryHistoricTimeseriesDataRequest } from "src/app/shared/jsonrpc/request/queryHistoricTimeseriesDataRequest"; +import { QueryHistoricTimeseriesDataResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesDataResponse"; +import { ChannelAddress, Edge, EdgeConfig, Service } from "src/app/shared/shared"; +import { DateUtils } from "src/app/shared/utils/date/dateutils"; +import { DateTimeUtils } from "src/app/shared/utils/datetime/datetime-utils"; +import { calculateResolution } from "./shared"; // NOTE: Auto-refresh of widgets is currently disabled to reduce server load export abstract class AbstractHistoryWidget { + private activeQueryData: string; + //observable is used to fetch new widget data every 5 minutes // private refreshWidgetData = interval(600000); @@ -52,13 +55,14 @@ export abstract class AbstractHistoryWidget { protected queryHistoricTimeseriesData(fromDate: Date, toDate: Date): Promise { const resolution = calculateResolution(this.service, fromDate, toDate).resolution; - return new Promise((resolve, reject) => { + const result: Promise = new Promise((resolve, reject) => { this.service.getCurrentEdge().then(edge => { this.service.getConfig().then(config => { this.getChannelAddresses(edge, config).then(channelAddresses => { const request = new QueryHistoricTimeseriesDataRequest(DateUtils.maxDate(fromDate, edge?.firstSetupProtocol), toDate, channelAddresses, resolution); edge.sendRequest(this.service.websocket, request).then(response => { const result = (response as QueryHistoricTimeseriesDataResponse).result; + this.activeQueryData = response.id; if (Object.keys(result.data).length != 0 && Object.keys(result.timestamps).length != 0) { resolve(response as QueryHistoricTimeseriesDataResponse); } else { @@ -68,7 +72,13 @@ export abstract class AbstractHistoryWidget { }).catch(reason => reject(reason)); }); }); + }).then((response) => { + if (this.activeQueryData !== response.id) { + return; + } + return DateTimeUtils.normalizeTimestamps(resolution.unit, response); }); + return result; } /** diff --git a/ui/src/app/edge/history/chpsoc/chart.component.ts b/ui/src/app/edge/history/chpsoc/chart.component.ts index 56cf7403401..89019ad7b87 100644 --- a/ui/src/app/edge/history/chpsoc/chart.component.ts +++ b/ui/src/app/edge/history/chpsoc/chart.component.ts @@ -1,15 +1,15 @@ // @ts-strict-ignore -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 { YAxisTitle } from 'src/app/shared/service/utils'; -import { ChannelAddress, Edge, EdgeConfig, Service } from '../../../shared/shared'; -import { AbstractHistoryChart } from '../abstracthistorychart'; +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 { YAxisType } from "src/app/shared/service/utils"; +import { ChannelAddress, Edge, EdgeConfig, Service } from "../../../shared/shared"; +import { AbstractHistoryChart } from "../abstracthistorychart"; @Component({ - selector: 'chpsocchart', - templateUrl: '../abstracthistorychart.html', + selector: "chpsocchart", + templateUrl: "../abstracthistorychart.html", }) export class ChpSocChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { @@ -30,7 +30,6 @@ export class ChpSocChartComponent extends AbstractHistoryChart implements OnInit ngOnInit() { this.startSpinner(); - this.service.setCurrentComponent('', this.route); } ngOnDestroy() { @@ -48,10 +47,10 @@ export class ChpSocChartComponent extends AbstractHistoryChart implements OnInit this.queryHistoricTimeseriesData(this.period.from, this.period.to).then(response => { this.service.getCurrentEdge().then(() => { this.service.getConfig().then(config => { - const outputChannel = config.getComponentProperties(this.componentId)['outputChannelAddress']; - const inputChannel = config.getComponentProperties(this.componentId)['inputChannelAddress']; - const lowThreshold = this.componentId + '/_PropertyLowThreshold'; - const highThreshold = this.componentId + '/_PropertyHighThreshold'; + const outputChannel = config.getComponentProperties(this.componentId)["outputChannelAddress"]; + const inputChannel = config.getComponentProperties(this.componentId)["inputChannelAddress"]; + const lowThreshold = this.componentId + "/_PropertyLowThreshold"; + const highThreshold = this.componentId + "/_PropertyHighThreshold"; const result = response.result; // convert labels const labels: Date[] = []; @@ -79,8 +78,8 @@ export class ChpSocChartComponent extends AbstractHistoryChart implements OnInit data: data, }); this.colors.push({ - backgroundColor: 'rgba(0,191,255,0.05)', - borderColor: 'rgba(0,191,255,1)', + backgroundColor: "rgba(0,191,255,0.05)", + borderColor: "rgba(0,191,255,1)", }); } else { const data = result.data[channel].map(value => { @@ -94,34 +93,34 @@ export class ChpSocChartComponent extends AbstractHistoryChart implements OnInit }); if (channel == inputChannel) { datasets.push({ - label: this.translate.instant('General.soc'), + label: this.translate.instant("General.soc"), data: data, }); this.colors.push({ - backgroundColor: 'rgba(0,0,0,0)', - borderColor: 'rgba(0,223,0,1)', + backgroundColor: "rgba(0,0,0,0)", + borderColor: "rgba(0,223,0,1)", }); } if (channel == lowThreshold) { datasets.push({ - label: this.translate.instant('Edge.Index.Widgets.CHP.lowThreshold'), + label: this.translate.instant("Edge.Index.Widgets.CHP.lowThreshold"), data: data, borderDash: [3, 3], }); this.colors.push({ - backgroundColor: 'rgba(0,0,0,0)', - borderColor: 'rgba(0,191,255,1)', + backgroundColor: "rgba(0,0,0,0)", + borderColor: "rgba(0,191,255,1)", }); } if (channel == highThreshold) { datasets.push({ - label: this.translate.instant('Edge.Index.Widgets.CHP.highThreshold'), + label: this.translate.instant("Edge.Index.Widgets.CHP.highThreshold"), data: data, borderDash: [3, 3], }); this.colors.push({ - backgroundColor: 'rgba(0,0,0,0)', - borderColor: 'rgba(0,191,255,1)', + backgroundColor: "rgba(0,0,0,0)", + borderColor: "rgba(0,191,255,1)", }); } } @@ -144,20 +143,20 @@ export class ChpSocChartComponent extends AbstractHistoryChart implements OnInit this.initializeChart(); return; }).finally(() => { - this.unit = YAxisTitle.PERCENTAGE; + this.unit = YAxisType.PERCENTAGE; this.setOptions(this.options); }); } protected getChannelAddresses(edge: Edge, config: EdgeConfig): Promise { return new Promise((resolve) => { - const outputChannel = ChannelAddress.fromString(config.getComponentProperties(this.componentId)['outputChannelAddress']); - const inputChannel = ChannelAddress.fromString(config.getComponentProperties(this.componentId)['inputChannelAddress']); + const outputChannel = ChannelAddress.fromString(config.getComponentProperties(this.componentId)["outputChannelAddress"]); + const inputChannel = ChannelAddress.fromString(config.getComponentProperties(this.componentId)["inputChannelAddress"]); const result: ChannelAddress[] = [ outputChannel, inputChannel, - new ChannelAddress(this.componentId, '_PropertyHighThreshold'), - new ChannelAddress(this.componentId, '_PropertyLowThreshold'), + new ChannelAddress(this.componentId, "_PropertyHighThreshold"), + new ChannelAddress(this.componentId, "_PropertyLowThreshold"), ]; resolve(result); }); diff --git a/ui/src/app/edge/history/chpsoc/chpsocchartoverview/chpsocchartoverview.component.ts b/ui/src/app/edge/history/chpsoc/chpsocchartoverview/chpsocchartoverview.component.ts index da9418c8c68..56db2b42f82 100644 --- a/ui/src/app/edge/history/chpsoc/chpsocchartoverview/chpsocchartoverview.component.ts +++ b/ui/src/app/edge/history/chpsoc/chpsocchartoverview/chpsocchartoverview.component.ts @@ -1,10 +1,10 @@ -import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { Edge, EdgeConfig, Service } from '../../../../shared/shared'; +import { Component, OnInit } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { Edge, EdgeConfig, Service } from "../../../../shared/shared"; @Component({ selector: ChpSocChartOverviewComponent.SELECTOR, - templateUrl: './chpsocchartoverview.component.html', + templateUrl: "./chpsocchartoverview.component.html", }) export class ChpSocChartOverviewComponent implements OnInit { @@ -19,7 +19,7 @@ export class ChpSocChartOverviewComponent implements OnInit { ) { } ngOnInit() { - this.service.setCurrentComponent('', this.route).then(edge => { + this.service.getCurrentEdge().then(edge => { this.service.getConfig().then(config => { this.edge = edge; this.config = config; diff --git a/ui/src/app/edge/history/chpsoc/widget.component.ts b/ui/src/app/edge/history/chpsoc/widget.component.ts index a72c4c2fb34..9056355309b 100644 --- a/ui/src/app/edge/history/chpsoc/widget.component.ts +++ b/ui/src/app/edge/history/chpsoc/widget.component.ts @@ -1,15 +1,15 @@ -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 { 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'; +import { ChannelAddress, Edge, EdgeConfig, Service } from "../../../shared/shared"; +import { AbstractHistoryWidget } from "../abstracthistorywidget"; +import { calculateActiveTimeOverPeriod } from "../shared"; @Component({ selector: ChpSocWidgetComponent.SELECTOR, - templateUrl: './widget.component.html', + templateUrl: "./widget.component.html", }) export class ChpSocWidgetComponent extends AbstractHistoryWidget implements OnInit, OnChanges, OnDestroy { @@ -29,8 +29,8 @@ export class ChpSocWidgetComponent extends AbstractHistoryWidget implements OnIn } ngOnInit() { - this.service.setCurrentComponent('', this.route).then(response => { - this.edge = response; + this.service.getCurrentEdge().then(edge => { + this.edge = edge; this.service.getConfig().then(config => { this.component = config.getComponent(this.componentId); }); @@ -50,7 +50,7 @@ export class ChpSocWidgetComponent extends AbstractHistoryWidget implements OnIn this.queryHistoricTimeseriesData(this.service.historyPeriod.value.from, this.service.historyPeriod.value.to).then(response => { this.service.getConfig().then(config => { const result = (response as QueryHistoricTimeseriesDataResponse).result; - const outputChannel = ChannelAddress.fromString(config.getComponentProperties(this.componentId)['outputChannelAddress']); + const outputChannel = ChannelAddress.fromString(config.getComponentProperties(this.componentId)["outputChannelAddress"]); this.activeSecondsOverPeriod = calculateActiveTimeOverPeriod(outputChannel, result); }); }); @@ -58,7 +58,7 @@ export class ChpSocWidgetComponent extends AbstractHistoryWidget implements OnIn protected getChannelAddresses(edge: Edge, config: EdgeConfig): Promise { return new Promise((resolve) => { - const outputChannel = ChannelAddress.fromString(config.getComponentProperties(this.componentId)['outputChannelAddress']); + const outputChannel = ChannelAddress.fromString(config.getComponentProperties(this.componentId)["outputChannelAddress"]); const channeladdresses = [outputChannel]; resolve(channeladdresses); }); diff --git a/ui/src/app/edge/history/common/autarchy/Autarchy.ts b/ui/src/app/edge/history/common/autarchy/Autarchy.ts index 6b01e6b18fa..cc35ac3c7ce 100644 --- a/ui/src/app/edge/history/common/autarchy/Autarchy.ts +++ b/ui/src/app/edge/history/common/autarchy/Autarchy.ts @@ -1,9 +1,9 @@ -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'; -import { OverviewComponent } from './overview/overview'; +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"; +import { OverviewComponent } from "./overview/overview"; @NgModule({ imports: [ 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 e7a0998880c..8a17580e381 100644 --- a/ui/src/app/edge/history/common/autarchy/chart/chart.ts +++ b/ui/src/app/edge/history/common/autarchy/chart/chart.ts @@ -1,52 +1,52 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { AbstractHistoryChart } from 'src/app/shared/components/chart/abstracthistorychart'; -import { QueryHistoricTimeseriesEnergyResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; -import { ChartAxis, HistoryUtils, YAxisTitle } from 'src/app/shared/service/utils'; -import { ChannelAddress, Utils } from 'src/app/shared/shared'; +import { Component } from "@angular/core"; +import { AbstractHistoryChart } from "src/app/shared/components/chart/abstracthistorychart"; +import { QueryHistoricTimeseriesEnergyResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse"; +import { ChartAxis, HistoryUtils, YAxisType } from "src/app/shared/service/utils"; +import { ChannelAddress, Utils } from "src/app/shared/shared"; @Component({ - selector: 'autarchychart', - templateUrl: '../../../../../shared/components/chart/abstracthistorychart.html', + selector: "autarchychart", + templateUrl: "../../../../../shared/components/chart/abstracthistorychart.html", }) export class ChartComponent extends AbstractHistoryChart { protected override getChartData(): HistoryUtils.ChartData { - this.spinnerId = 'autarchy-chart'; + this.spinnerId = "autarchy-chart"; return { input: [{ - name: 'Consumption', - powerChannel: ChannelAddress.fromString('_sum/ConsumptionActivePower'), - energyChannel: ChannelAddress.fromString('_sum/ConsumptionActiveEnergy'), + name: "Consumption", + powerChannel: ChannelAddress.fromString("_sum/ConsumptionActivePower"), + energyChannel: ChannelAddress.fromString("_sum/ConsumptionActiveEnergy"), }, { - name: 'GridBuy', - powerChannel: ChannelAddress.fromString('_sum/GridActivePower'), - energyChannel: ChannelAddress.fromString('_sum/GridBuyActiveEnergy'), + name: "GridBuy", + powerChannel: ChannelAddress.fromString("_sum/GridActivePower"), + energyChannel: ChannelAddress.fromString("_sum/GridBuyActiveEnergy"), converter: HistoryUtils.ValueConverter.NON_NULL_OR_NEGATIVE, }], output: (data: HistoryUtils.ChannelData) => { return [{ - name: this.translate.instant('General.autarchy'), + name: this.translate.instant("General.autarchy"), nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => { - return Utils.calculateAutarchy(energyValues?.result.data['_sum/GridBuyActiveEnergy'] ?? null, energyValues?.result.data['_sum/ConsumptionActiveEnergy'] ?? null); + return Utils.calculateAutarchy(energyValues?.result.data["_sum/GridBuyActiveEnergy"] ?? null, energyValues?.result.data["_sum/ConsumptionActiveEnergy"] ?? null); }, converter: () => { - return data['Consumption'] + return data["Consumption"] ?.map((value, index) => - Utils.calculateAutarchy(data['GridBuy'][index], value), + Utils.calculateAutarchy(data["GridBuy"][index], value), ); }, - color: 'rgb(0,152,204)', + color: "rgb(0,152,204)", }]; }, tooltip: { - formatNumber: '1.0-0', + formatNumber: "1.0-0", }, yAxes: [{ - unit: YAxisTitle.PERCENTAGE, - position: 'left', + unit: YAxisType.PERCENTAGE, + position: "left", yAxisId: ChartAxis.LEFT, }], }; diff --git a/ui/src/app/edge/history/common/autarchy/flat/flat.ts b/ui/src/app/edge/history/common/autarchy/flat/flat.ts index 748253a44bd..429cca30b54 100644 --- a/ui/src/app/edge/history/common/autarchy/flat/flat.ts +++ b/ui/src/app/edge/history/common/autarchy/flat/flat.ts @@ -1,11 +1,11 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; -import { ChannelAddress, CurrentData, Utils } from '../../../../../shared/shared'; +import { Component } from "@angular/core"; +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; +import { ChannelAddress, CurrentData, Utils } from "../../../../../shared/shared"; @Component({ - selector: 'autarchyWidget', - templateUrl: './flat.html', + selector: "autarchyWidget", + templateUrl: "./flat.html", }) export class FlatComponent extends AbstractFlatWidget { @@ -14,14 +14,14 @@ export class FlatComponent extends AbstractFlatWidget { protected override onCurrentData(currentData: CurrentData) { this.autarchyValue = Utils.calculateAutarchy( - currentData.allComponents['_sum/GridBuyActiveEnergy'] / 1000, - currentData.allComponents['_sum/ConsumptionActiveEnergy'] / 1000); + currentData.allComponents["_sum/GridBuyActiveEnergy"] / 1000, + currentData.allComponents["_sum/ConsumptionActiveEnergy"] / 1000); } protected override getChannelAddresses(): ChannelAddress[] { return [ - new ChannelAddress('_sum', 'GridBuyActiveEnergy'), - new ChannelAddress('_sum', 'ConsumptionActiveEnergy'), + new ChannelAddress("_sum", "GridBuyActiveEnergy"), + new ChannelAddress("_sum", "ConsumptionActiveEnergy"), ]; } } diff --git a/ui/src/app/edge/history/common/autarchy/overview/overview.ts b/ui/src/app/edge/history/common/autarchy/overview/overview.ts index a3f812c1a88..51ed8f95a67 100644 --- a/ui/src/app/edge/history/common/autarchy/overview/overview.ts +++ b/ui/src/app/edge/history/common/autarchy/overview/overview.ts @@ -1,7 +1,7 @@ -import { Component } from '@angular/core'; -import { AbstractHistoryChartOverview } from 'src/app/shared/components/chart/abstractHistoryChartOverview'; +import { Component } from "@angular/core"; +import { AbstractHistoryChartOverview } from "src/app/shared/components/chart/abstractHistoryChartOverview"; @Component({ - templateUrl: './overview.html', + templateUrl: "./overview.html", }) export class OverviewComponent extends AbstractHistoryChartOverview { } diff --git a/ui/src/app/edge/history/common/common.ts b/ui/src/app/edge/history/common/common.ts index c21e92b1a78..bdfda86d25d 100644 --- a/ui/src/app/edge/history/common/common.ts +++ b/ui/src/app/edge/history/common/common.ts @@ -1,10 +1,10 @@ -import { NgModule } from '@angular/core'; -import { Common_Autarchy } from './autarchy/Autarchy'; -import { Common_Consumption } from './consumption/Consumption'; -import { CommonEnergyMonitor } from './energy/energy'; -import { Common_Grid } from './grid/grid'; -import { Common_Production } from './production/production'; -import { Common_Selfconsumption } from './selfconsumption/SelfConsumption'; +import { NgModule } from "@angular/core"; +import { Common_Autarchy } from "./autarchy/Autarchy"; +import { Common_Consumption } from "./consumption/Consumption"; +import { CommonEnergyMonitor } from "./energy/energy"; +import { Common_Grid } from "./grid/grid"; +import { Common_Production } from "./production/production"; +import { Common_Selfconsumption } from "./selfconsumption/SelfConsumption"; @NgModule({ imports: [ diff --git a/ui/src/app/edge/history/common/consumption/Consumption.ts b/ui/src/app/edge/history/common/consumption/Consumption.ts index 4cc05a0454f..c36c786695d 100644 --- a/ui/src/app/edge/history/common/consumption/Consumption.ts +++ b/ui/src/app/edge/history/common/consumption/Consumption.ts @@ -1,16 +1,16 @@ -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; -import { FooterNavigationModule } from 'src/app/shared/components/footer/subnavigation/footerNavigation.module'; -import { SharedModule } from 'src/app/shared/shared.module'; +import { NgModule } from "@angular/core"; +import { BrowserModule } from "@angular/platform-browser"; +import { FooterNavigationModule } from "src/app/shared/components/footer/subnavigation/footerNavigation.module"; +import { SharedModule } from "src/app/shared/shared.module"; -import { CurrentVoltageModule } from 'src/app/shared/components/edge/meter/currentVoltage/currentVoltageModule'; -import { ChartComponent } from './chart/chart'; -import { ConsumptionMeterChartDetailsComponent } from './details/chart/consumptionMeter'; -import { EvcsChartDetailsComponent } from './details/chart/evcs'; -import { SumChartDetailsComponent } from './details/chart/sum'; -import { DetailsOverviewComponent } from './details/details.overview'; -import { FlatComponent } from './flat/flat'; -import { OverviewComponent } from './overview/overview'; +import { CurrentVoltageModule } from "src/app/shared/components/edge/meter/currentVoltage/currentVoltageModule"; +import { ChartComponent } from "./chart/chart"; +import { ConsumptionMeterChartDetailsComponent } from "./details/chart/consumptionMeter"; +import { EvcsChartDetailsComponent } from "./details/chart/evcs"; +import { SumChartDetailsComponent } from "./details/chart/sum"; +import { DetailsOverviewComponent } from "./details/details.overview"; +import { FlatComponent } from "./flat/flat"; +import { OverviewComponent } from "./overview/overview"; @NgModule({ imports: [ diff --git a/ui/src/app/edge/history/common/consumption/chart/channels.spec.ts b/ui/src/app/edge/history/common/consumption/chart/channels.spec.ts index fdb26cdf064..1b92f47b159 100644 --- a/ui/src/app/edge/history/common/consumption/chart/channels.spec.ts +++ b/ui/src/app/edge/history/common/consumption/chart/channels.spec.ts @@ -23,12 +23,12 @@ export namespace History { }), dataChannelWithValues: new QueryHistoricTimeseriesDataResponse("0", { data: { - '_sum/ConsumptionActivePower': [null, null, null, 565.8045977011494, 560.5148514851485, 561.425925925926, 573.2169811320755, 565.8080808080808, 587.9803921568628, 584.2389380530974, 607.4818181818182, 605.0275229357799, 595.6407766990292, 602.5294117647059, 578.1684210526316, 581.6813186813187, 649.5166666666667, 560.3, 567.0373831775701, 629.7672413793103, 568.8613861386139, 589.6039603960396, 634.5090909090909, 622.6633663366337, 617.7196261682243, 608.122641509434, 602.78, 650.8155339805825, 605.8877551020408, 594.3904761904762, 576.36, 565.066037735849, 587.495145631068, 626.375, 681.9428571428572, 650.4629629629629, 631.373831775701, 687.25, 560.2452830188679, 527.8952380952381, 620.2222222222222, 546.6355140186915, 587.8130841121496, 604, 616.295918367347, 578.940594059406, 594.3396226415094, 648.1078431372549, null, null, null, 565.2183908045977, 573.6481481481482, 536.5462962962963, 558.081081081081, 574.7543859649123, 574.3557692307693, 596.9047619047619, 654.072072072072, 615.21, 612.8045977011494, 636.11, 613.7948717948718, 538.8857142857142, 537.1157894736842, 551.1634615384615, 558.8809523809524, 559.1222222222223, 618.5576923076923, 654.3287671232877, 616.0574712643678, 588.9056603773585, 578.7096774193549, 583.0360360360361, 572.5700934579439, 595.2631578947369, 745.0888888888888, 820.7323943661971, 2651.1923076923076, 8063.131147540984, 6952.055555555556, 7413.41052631579, 6695.175, 6688.301075268817, 7135.544444444445, 6935.6125, 6768.398148148148, 6962.593220338983, 3449.51968503937, 677.4427860696518, 982.7305699481865, 858.2012987012987, 767.8924050632911, 761.950495049505, 682.1319796954315, 725.4198473282443, 702.1286549707602, 730.9484536082474, 739, 730.572864321608, 754.7467532467532, 657.373417721519, 640.9480519480519, 669.8156424581006, 787.6280991735537, 2931.229357798165, 1954.2808988764045, 777.5346534653465, 1098.538860103627, 1244.1524390243903, 2919.4913793103447, 2987.4188034188032, 3414.029411764706, 1355.2, 2714.2824427480914, 2657.8703703703704, 2873.892307692308, 6140.337078651685, 3966.560606060606, 3021.5789473684213, 1774.1875, 1076.46, 1426.8691588785048, 1261.0386740331492, 1019.3491124260355, 1194.960199004975, 1241.2878787878788, 3323, 3968.45625, 1468.0961538461538, 3630.4166666666665, 2269.5301204819275, 2554.391025641026, 1845.7888888888888, 1728.9767441860465, 2862.08, 2324.1241379310345, 1964.0169491525423, 1808.4, 3466.05035971223, 2297.4397590361446, 2530.0493827160494, 2439.3584905660377, 2007.9060773480662, 1751.5, 1416.3181818181818, 1429.2298850574712, 1452.0298507462687, 1489.720430107527, 1633.095238095238, 1826.2928571428572, 1610.1904761904761, 1680.9292929292928, 2881.743119266055, 3585.1634615384614, 3689.1666666666665, 3657.340277777778, 3643.5348837209303, 3714.8645833333335, 3731.375, 3744.79, 3636.2363636363634, 4273.113924050633, 3446.2, 3538.714285714286, 3790.6065573770493, 3527.675, 3467.671232876712, 3559.5, 3798.2, 5460.666666666667, 1309.4406779661017, 1535.7454545454545, 3423.8260869565215, 3382.3636363636365, 3400.6315789473683, 2950.75, 3386.731707317073, 2506, 1447.1666666666667, 1442.6, 946, 942.578947368421, 950.7142857142857, 947, 976.2857142857143, 1786.2857142857142, 1513.5777777777778, 1499.5625, 1338, 1327.8125, 1273.9175257731958, 1438.7457627118645, 1248.4186046511627, 1286.6693548387098, 1284.8934911242604, 1223.7952755905512, 748.09375, 871.7684210526315, 844.5338983050848, 791.675, 804.1932773109244, 730.3737373737374, 705.5024390243902, 687.2407407407408, 690.9939759036145, 751, 765.139344262295, 686.8717948717949, 669.7434210526316, 1767.8091603053435, 724.6764705882352, 748.2772277227723, 940.1142857142858, 750.368, 1366.0232558139535, 727.4137931034483, 710.719512195122, 689.8555555555556, 739.453488372093, 817.875, 730.4303797468355, 735.5890410958904, 738.2258064516129, 1906.9217391304348, 2290.785714285714, 1207.5072463768115, 1167.5890410958905, 1229.0208333333333, 1192.3777777777777, 1208.871794871795, 1367.715909090909, 1284.2233009708739, 1163.1739130434783, 1152.53, 1161.4545454545455, 1219.5681818181818, 1183.752808988764, 1197.778947368421, 1233.888888888889, 1275.070588235294, 1235.554054054054, 1207.83908045977, 1241.6184210526317, 1159.042735042735, 1138.2948717948718, 1106.9915966386554, 1171.4504504504505, 1223.822429906542, 1122.169642857143, 1018.8928571428571, 981.8285714285714, 998.8363636363637, 6056.572916666667, 7225.528846153846, 7193.834782608696, 7507.321100917431, 7588.695238095238, 7678.689189189189, 9469.633027522936, 10236.186046511628, 10106.608695652174, 9989.125, 9948.229357798165, 9796.030927835052, 9704.217391304348, 8454.028571428571, 6813.476190476191, 6706.782608695652, 6523.452173913043, 6661.553571428572, 5620.777777777777, 812.3142857142857, 809.5892857142857, 866.4786324786324, 877.8319327731092, 810.8141592920354, 815.7121212121212, 770.6470588235294, 763.3157894736842, 781.5151515151515, 807.5833333333334, 824.743119266055, 876.2151898734177, 882.424, 750.2213114754098, 675.9549549549549, 637.1222222222223], - '_sum/ConsumptionActivePowerL1': [null, null, null, 188.60153256704982, 186.83828382838283, 187.141975308642, 191.07232704402517, 188.60269360269362, 195.99346405228758, 194.7463126843658, 202.4939393939394, 201.6758409785933, 198.54692556634305, 200.84313725490196, 192.7228070175439, 193.89377289377288, 216.50555555555556, 186.76666666666665, 189.01246105919003, 209.92241379310346, 189.6204620462046, 196.53465346534654, 211.5030303030303, 207.55445544554456, 205.90654205607476, 202.7075471698113, 200.92666666666665, 216.93851132686083, 201.9625850340136, 198.13015873015874, 192.12, 188.35534591194968, 195.831715210356, 208.79166666666666, 227.31428571428572, 216.820987654321, 210.45794392523365, 229.08333333333334, 186.74842767295596, 175.9650793650794, 206.74074074074073, 182.21183800623052, 195.93769470404985, 201.33333333333334, 205.43197278911566, 192.98019801980197, 198.11320754716982, 216.0359477124183, null, null, null, 188.40613026819923, 191.21604938271605, 178.84876543209876, 186.027027027027, 191.58479532163744, 191.4519230769231, 198.96825396825398, 218.02402402402402, 205.07000000000002, 204.26819923371647, 212.03666666666666, 204.59829059829062, 179.6285714285714, 179.03859649122808, 183.72115384615384, 186.2936507936508, 186.3740740740741, 206.18589743589743, 218.1095890410959, 205.35249042145594, 196.30188679245282, 192.90322580645162, 194.34534534534535, 190.85669781931463, 198.42105263157896, 248.36296296296294, 273.57746478873236, 883.7307692307692, 2687.7103825136614, 2317.3518518518517, 2471.1368421052634, 2231.725, 2229.4336917562723, 2378.514814814815, 2311.8708333333334, 2256.1327160493825, 2320.864406779661, 1149.8398950131234, 225.81426202321725, 327.5768566493955, 286.06709956709955, 255.96413502109704, 253.983498349835, 227.37732656514382, 241.80661577608143, 234.04288499025338, 243.64948453608247, 246.33333333333334, 243.52428810720266, 251.58225108225108, 219.12447257383965, 213.64935064935062, 223.27188081936686, 262.5426997245179, 977.0764525993883, 651.4269662921348, 259.1782178217822, 366.1796200345423, 414.7174796747968, 973.1637931034483, 995.8062678062678, 1138.0098039215686, 451.73333333333335, 904.7608142493638, 885.9567901234568, 957.9641025641026, 2046.7790262172284, 1322.1868686868686, 1007.1929824561404, 591.3958333333334, 358.82, 475.6230529595016, 420.3462246777164, 339.78303747534517, 398.3200663349917, 413.76262626262627, 1107.6666666666667, 1322.8187500000001, 489.3653846153846, 1210.138888888889, 756.5100401606425, 851.4636752136753, 615.2629629629629, 576.3255813953489, 954.0266666666666, 774.7080459770115, 654.6723163841808, 602.8000000000001, 1155.3501199040768, 765.8132530120482, 843.3497942386831, 813.1194968553459, 669.3020257826887, 583.8333333333334, 472.10606060606057, 476.4099616858237, 484.00995024875624, 496.57347670250897, 544.3650793650794, 608.7642857142857, 536.7301587301587, 560.3097643097643, 960.5810397553518, 1195.054487179487, 1229.7222222222222, 1219.1134259259259, 1214.5116279069769, 1238.2881944444446, 1243.7916666666667, 1248.2633333333333, 1212.0787878787878, 1424.3713080168775, 1148.7333333333333, 1179.5714285714287, 1263.535519125683, 1175.8916666666667, 1155.890410958904, 1186.5, 1266.0666666666666, 1820.2222222222224, 436.48022598870057, 511.91515151515154, 1141.2753623188405, 1127.4545454545455, 1133.5438596491229, 983.5833333333334, 1128.910569105691, 835.3333333333334, 482.3888888888889, 480.8666666666666, 315.3333333333333, 314.1929824561403, 316.90476190476187, 315.6666666666667, 325.42857142857144, 595.4285714285714, 504.52592592592595, 499.8541666666667, 446, 442.6041666666667, 424.63917525773195, 479.5819209039548, 416.1395348837209, 428.8897849462366, 428.29783037475346, 407.93175853018374, 249.36458333333334, 290.58947368421053, 281.51129943502826, 263.89166666666665, 268.0644257703081, 243.45791245791247, 235.16747967479674, 229.08024691358025, 230.33132530120483, 250.33333333333334, 255.04644808743168, 228.95726495726498, 223.24780701754386, 589.2697201017812, 241.55882352941174, 249.42574257425744, 313.37142857142857, 250.12266666666667, 455.3410852713178, 242.47126436781608, 236.90650406504065, 229.95185185185187, 246.484496124031, 272.625, 243.47679324894514, 245.19634703196346, 246.07526881720432, 635.640579710145, 763.5952380952381, 402.50241545893715, 389.1963470319635, 409.6736111111111, 397.4592592592592, 402.95726495726495, 455.905303030303, 428.074433656958, 387.72463768115944, 384.1766666666667, 387.1515151515152, 406.52272727272725, 394.5842696629213, 399.25964912280705, 411.2962962962963, 425.0235294117647, 411.8513513513513, 402.61302681992333, 413.8728070175439, 386.34757834757835, 379.43162393162396, 368.99719887955183, 390.4834834834835, 407.94080996884736, 374.05654761904765, 339.63095238095235, 327.2761904761905, 332.94545454545454, 2018.857638888889, 2408.5096153846152, 2397.9449275362317, 2502.440366972477, 2529.5650793650793, 2559.563063063063, 3156.544342507645, 3412.062015503876, 3368.8695652173915, 3329.7083333333335, 3316.0764525993886, 3265.343642611684, 3234.7391304347825, 2818.0095238095237, 2271.15873015873, 2235.5942028985505, 2174.4840579710144, 2220.5178571428573, 1873.5925925925924, 270.77142857142854, 269.86309523809524, 288.8262108262108, 292.6106442577031, 270.27138643067843, 271.9040404040404, 256.88235294117646, 254.43859649122805, 260.5050505050505, 269.19444444444446, 274.914373088685, 292.07172995780587, 294.1413333333333, 250.0737704918033, 225.31831831831832, 212.3740740740741], - '_sum/ConsumptionActivePowerL2': [null, null, null, 188.60153256704982, 186.83828382838283, 187.141975308642, 191.07232704402517, 188.60269360269362, 195.99346405228758, 194.7463126843658, 202.4939393939394, 201.6758409785933, 198.54692556634305, 200.84313725490196, 192.7228070175439, 193.89377289377288, 216.50555555555556, 186.76666666666665, 189.01246105919003, 209.92241379310346, 189.6204620462046, 196.53465346534654, 211.5030303030303, 207.55445544554456, 205.90654205607476, 202.7075471698113, 200.92666666666665, 216.93851132686083, 201.9625850340136, 198.13015873015874, 192.12, 188.35534591194968, 195.831715210356, 208.79166666666666, 227.31428571428572, 216.820987654321, 210.45794392523365, 229.08333333333334, 186.74842767295596, 175.9650793650794, 206.74074074074073, 182.21183800623052, 195.93769470404985, 201.33333333333334, 205.43197278911566, 192.98019801980197, 198.11320754716982, 216.0359477124183, null, null, null, 188.40613026819923, 191.21604938271605, 178.84876543209876, 186.027027027027, 191.58479532163744, 191.4519230769231, 198.96825396825398, 218.02402402402402, 205.07000000000002, 204.26819923371647, 212.03666666666666, 204.59829059829062, 179.6285714285714, 179.03859649122808, 183.72115384615384, 186.2936507936508, 186.3740740740741, 206.18589743589743, 218.1095890410959, 205.35249042145594, 196.30188679245282, 192.90322580645162, 194.34534534534535, 190.85669781931463, 198.42105263157896, 248.36296296296294, 273.57746478873236, 883.7307692307692, 2687.7103825136614, 2317.3518518518517, 2471.1368421052634, 2231.725, 2229.4336917562723, 2378.514814814815, 2311.8708333333334, 2256.1327160493825, 2320.864406779661, 1149.8398950131234, 225.81426202321725, 327.5768566493955, 286.06709956709955, 255.96413502109704, 253.983498349835, 227.37732656514382, 241.80661577608143, 234.04288499025338, 243.64948453608247, 246.33333333333334, 243.52428810720266, 251.58225108225108, 219.12447257383965, 213.64935064935062, 223.27188081936686, 262.5426997245179, 977.0764525993883, 651.4269662921348, 259.1782178217822, 366.1796200345423, 414.7174796747968, 973.1637931034483, 995.8062678062678, 1138.0098039215686, 451.73333333333335, 904.7608142493638, 885.9567901234568, 957.9641025641026, 2046.7790262172284, 1322.1868686868686, 1007.1929824561404, 591.3958333333334, 358.82, 475.6230529595016, 420.3462246777164, 339.78303747534517, 398.3200663349917, 413.76262626262627, 1107.6666666666667, 1322.8187500000001, 489.3653846153846, 1210.138888888889, 756.5100401606425, 851.4636752136753, 615.2629629629629, 576.3255813953489, 954.0266666666666, 774.7080459770115, 654.6723163841808, 602.8000000000001, 1155.3501199040768, 765.8132530120482, 843.3497942386831, 813.1194968553459, 669.3020257826887, 583.8333333333334, 472.10606060606057, 476.4099616858237, 484.00995024875624, 496.57347670250897, 544.3650793650794, 608.7642857142857, 536.7301587301587, 560.3097643097643, 960.5810397553518, 1195.054487179487, 1229.7222222222222, 1219.1134259259259, 1214.5116279069769, 1238.2881944444446, 1243.7916666666667, 1248.2633333333333, 1212.0787878787878, 1424.3713080168775, 1148.7333333333333, 1179.5714285714287, 1263.535519125683, 1175.8916666666667, 1155.890410958904, 1186.5, 1266.0666666666666, 1820.2222222222224, 436.48022598870057, 511.91515151515154, 1141.2753623188405, 1127.4545454545455, 1133.5438596491229, 983.5833333333334, 1128.910569105691, 835.3333333333334, 482.3888888888889, 480.8666666666666, 315.3333333333333, 314.1929824561403, 316.90476190476187, 315.6666666666667, 325.42857142857144, 595.4285714285714, 504.52592592592595, 499.8541666666667, 446, 442.6041666666667, 424.63917525773195, 479.5819209039548, 416.1395348837209, 428.8897849462366, 428.29783037475346, 407.93175853018374, 249.36458333333334, 290.58947368421053, 281.51129943502826, 263.89166666666665, 268.0644257703081, 243.45791245791247, 235.16747967479674, 229.08024691358025, 230.33132530120483, 250.33333333333334, 255.04644808743168, 228.95726495726498, 223.24780701754386, 589.2697201017812, 241.55882352941174, 249.42574257425744, 313.37142857142857, 250.12266666666667, 455.3410852713178, 242.47126436781608, 236.90650406504065, 229.95185185185187, 246.484496124031, 272.625, 243.47679324894514, 245.19634703196346, 246.07526881720432, 635.640579710145, 763.5952380952381, 402.50241545893715, 389.1963470319635, 409.6736111111111, 397.4592592592592, 402.95726495726495, 455.905303030303, 428.074433656958, 387.72463768115944, 384.1766666666667, 387.1515151515152, 406.52272727272725, 394.5842696629213, 399.25964912280705, 411.2962962962963, 425.0235294117647, 411.8513513513513, 402.61302681992333, 413.8728070175439, 386.34757834757835, 379.43162393162396, 368.99719887955183, 390.4834834834835, 407.94080996884736, 374.05654761904765, 339.63095238095235, 327.2761904761905, 332.94545454545454, 2018.857638888889, 2408.5096153846152, 2397.9449275362317, 2502.440366972477, 2529.5650793650793, 2559.563063063063, 3156.544342507645, 3412.062015503876, 3368.8695652173915, 3329.7083333333335, 3316.0764525993886, 3265.343642611684, 3234.7391304347825, 2818.0095238095237, 2271.15873015873, 2235.5942028985505, 2174.4840579710144, 2220.5178571428573, 1873.5925925925924, 270.77142857142854, 269.86309523809524, 288.8262108262108, 292.6106442577031, 270.27138643067843, 271.9040404040404, 256.88235294117646, 254.43859649122805, 260.5050505050505, 269.19444444444446, 274.914373088685, 292.07172995780587, 294.1413333333333, 250.0737704918033, 225.31831831831832, 212.3740740740741], - '_sum/ConsumptionActivePowerL3': [null, null, null, 188.60153256704982, 186.83828382838283, 187.141975308642, 191.07232704402517, 188.60269360269362, 195.99346405228758, 194.7463126843658, 202.4939393939394, 201.6758409785933, 198.54692556634305, 200.84313725490196, 192.7228070175439, 193.89377289377288, 216.50555555555556, 186.76666666666665, 189.01246105919003, 209.92241379310346, 189.6204620462046, 196.53465346534654, 211.5030303030303, 207.55445544554456, 205.90654205607476, 202.7075471698113, 200.92666666666665, 216.93851132686083, 201.9625850340136, 198.13015873015874, 192.12, 188.35534591194968, 195.831715210356, 208.79166666666666, 227.31428571428572, 216.820987654321, 210.45794392523365, 229.08333333333334, 186.74842767295596, 175.9650793650794, 206.74074074074073, 182.21183800623052, 195.93769470404985, 201.33333333333334, 205.43197278911566, 192.98019801980197, 198.11320754716982, 216.0359477124183, null, null, null, 188.40613026819923, 191.21604938271605, 178.84876543209876, 186.027027027027, 191.58479532163744, 191.4519230769231, 198.96825396825398, 218.02402402402402, 205.07000000000002, 204.26819923371647, 212.03666666666666, 204.59829059829062, 179.6285714285714, 179.03859649122808, 183.72115384615384, 186.2936507936508, 186.3740740740741, 206.18589743589743, 218.1095890410959, 205.35249042145594, 196.30188679245282, 192.90322580645162, 194.34534534534535, 190.85669781931463, 198.42105263157896, 248.36296296296294, 273.57746478873236, 883.7307692307692, 2687.7103825136614, 2317.3518518518517, 2471.1368421052634, 2231.725, 2229.4336917562723, 2378.514814814815, 2311.8708333333334, 2256.1327160493825, 2320.864406779661, 1149.8398950131234, 225.81426202321725, 327.5768566493955, 286.06709956709955, 255.96413502109704, 253.983498349835, 227.37732656514382, 241.80661577608143, 234.04288499025338, 243.64948453608247, 246.33333333333334, 243.52428810720266, 251.58225108225108, 219.12447257383965, 213.64935064935062, 223.27188081936686, 262.5426997245179, 977.0764525993883, 651.4269662921348, 259.1782178217822, 366.1796200345423, 414.7174796747968, 973.1637931034483, 995.8062678062678, 1138.0098039215686, 451.73333333333335, 904.7608142493638, 885.9567901234568, 957.9641025641026, 2046.7790262172284, 1322.1868686868686, 1007.1929824561404, 591.3958333333334, 358.82, 475.6230529595016, 420.3462246777164, 339.78303747534517, 398.3200663349917, 413.76262626262627, 1107.6666666666667, 1322.8187500000001, 489.3653846153846, 1210.138888888889, 756.5100401606425, 851.4636752136753, 615.2629629629629, 576.3255813953489, 954.0266666666666, 774.7080459770115, 654.6723163841808, 602.8000000000001, 1155.3501199040768, 765.8132530120482, 843.3497942386831, 813.1194968553459, 669.3020257826887, 583.8333333333334, 472.10606060606057, 476.4099616858237, 484.00995024875624, 496.57347670250897, 544.3650793650794, 608.7642857142857, 536.7301587301587, 560.3097643097643, 960.5810397553518, 1195.054487179487, 1229.7222222222222, 1219.1134259259259, 1214.5116279069769, 1238.2881944444446, 1243.7916666666667, 1248.2633333333333, 1212.0787878787878, 1424.3713080168775, 1148.7333333333333, 1179.5714285714287, 1263.535519125683, 1175.8916666666667, 1155.890410958904, 1186.5, 1266.0666666666666, 1820.2222222222224, 436.48022598870057, 511.91515151515154, 1141.2753623188405, 1127.4545454545455, 1133.5438596491229, 983.5833333333334, 1128.910569105691, 835.3333333333334, 482.3888888888889, 480.8666666666666, 315.3333333333333, 314.1929824561403, 316.90476190476187, 315.6666666666667, 325.42857142857144, 595.4285714285714, 504.52592592592595, 499.8541666666667, 446, 442.6041666666667, 424.63917525773195, 479.5819209039548, 416.1395348837209, 428.8897849462366, 428.29783037475346, 407.93175853018374, 249.36458333333334, 290.58947368421053, 281.51129943502826, 263.89166666666665, 268.0644257703081, 243.45791245791247, 235.16747967479674, 229.08024691358025, 230.33132530120483, 250.33333333333334, 255.04644808743168, 228.95726495726498, 223.24780701754386, 589.2697201017812, 241.55882352941174, 249.42574257425744, 313.37142857142857, 250.12266666666667, 455.3410852713178, 242.47126436781608, 236.90650406504065, 229.95185185185187, 246.484496124031, 272.625, 243.47679324894514, 245.19634703196346, 246.07526881720432, 635.640579710145, 763.5952380952381, 402.50241545893715, 389.1963470319635, 409.6736111111111, 397.4592592592592, 402.95726495726495, 455.905303030303, 428.074433656958, 387.72463768115944, 384.1766666666667, 387.1515151515152, 406.52272727272725, 394.5842696629213, 399.25964912280705, 411.2962962962963, 425.0235294117647, 411.8513513513513, 402.61302681992333, 413.8728070175439, 386.34757834757835, 379.43162393162396, 368.99719887955183, 390.4834834834835, 407.94080996884736, 374.05654761904765, 339.63095238095235, 327.2761904761905, 332.94545454545454, 2018.857638888889, 2408.5096153846152, 2397.9449275362317, 2502.440366972477, 2529.5650793650793, 2559.563063063063, 3156.544342507645, 3412.062015503876, 3368.8695652173915, 3329.7083333333335, 3316.0764525993886, 3265.343642611684, 3234.7391304347825, 2818.0095238095237, 2271.15873015873, 2235.5942028985505, 2174.4840579710144, 2220.5178571428573, 1873.5925925925924, 270.77142857142854, 269.86309523809524, 288.8262108262108, 292.6106442577031, 270.27138643067843, 271.9040404040404, 256.88235294117646, 254.43859649122805, 260.5050505050505, 269.19444444444446, 274.914373088685, 292.07172995780587, 294.1413333333333, 250.0737704918033, 225.31831831831832, 212.3740740740741], - 'evcs0/ChargePower': [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, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, null, 0, 4104.142857142857, 5829.969696969697, 5806.212121212121, 6195.333333333333, 5777.333333333333, 5786.25, 5789.727272727273, 5789.571428571428, 5783.0526315789475, 5772.657142857143, 4864.8421052631575, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, null, null, 0, null, null, 0, 0, null, 0, 0, null, 0, 0, null, 0, 0, 0, 0, 0, 0, null, 0, null, null, 0, 0, null, null, 0, 0, 0, null, 0, null, null, 0, 0, null, 0, null, null, null, null, 0, null, 0, 0, null, null, null, null, null, 0, null, null, null, null, null, 0, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 0, 0, null, 0, null, 0, 0, 0, 0, 0, 0, null, null, 0, 0, null, 0, 0, 0, null, null, 0, 0, null, 0, 0, null, null, null, 0, null, null, null, null, null, null, 0, 0, 0, null, 0, 0, 0, 0, null, 0, null, 0, null, 0, 0, 0, null, 0, 0, 0, 0, 0, 5213.0952380952385, 5787.580645161291, 5789.484848484848, 5790.818181818182, 5807.34375, 5820.136363636364, 5798.862068965517, 5809.041666666667, 5805.5625, 5794.346153846154, 5798, 5740.214285714285, 5727.242424242424, 5742.542857142857, 5753.424242424242, 5752.4, 5731.966666666666, 5734.323529411765, 5335.586206896552, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null], - 'meter0/ActivePower': [124.28571428571429, 0, null, 0, 173.33333333333334, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 110, 113.33333333333333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 113.33333333333333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 113.33333333333333, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 140, null, null, null, 2126.875, 175, 176, null, 180, 180, 185, 180, null, 185, 190, 180, 180, 176.25, 175.83333333333334, 170, 175, 170, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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/ConsumptionActivePower": [null, null, null, 565.8045977011494, 560.5148514851485, 561.425925925926, 573.2169811320755, 565.8080808080808, 587.9803921568628, 584.2389380530974, 607.4818181818182, 605.0275229357799, 595.6407766990292, 602.5294117647059, 578.1684210526316, 581.6813186813187, 649.5166666666667, 560.3, 567.0373831775701, 629.7672413793103, 568.8613861386139, 589.6039603960396, 634.5090909090909, 622.6633663366337, 617.7196261682243, 608.122641509434, 602.78, 650.8155339805825, 605.8877551020408, 594.3904761904762, 576.36, 565.066037735849, 587.495145631068, 626.375, 681.9428571428572, 650.4629629629629, 631.373831775701, 687.25, 560.2452830188679, 527.8952380952381, 620.2222222222222, 546.6355140186915, 587.8130841121496, 604, 616.295918367347, 578.940594059406, 594.3396226415094, 648.1078431372549, null, null, null, 565.2183908045977, 573.6481481481482, 536.5462962962963, 558.081081081081, 574.7543859649123, 574.3557692307693, 596.9047619047619, 654.072072072072, 615.21, 612.8045977011494, 636.11, 613.7948717948718, 538.8857142857142, 537.1157894736842, 551.1634615384615, 558.8809523809524, 559.1222222222223, 618.5576923076923, 654.3287671232877, 616.0574712643678, 588.9056603773585, 578.7096774193549, 583.0360360360361, 572.5700934579439, 595.2631578947369, 745.0888888888888, 820.7323943661971, 2651.1923076923076, 8063.131147540984, 6952.055555555556, 7413.41052631579, 6695.175, 6688.301075268817, 7135.544444444445, 6935.6125, 6768.398148148148, 6962.593220338983, 3449.51968503937, 677.4427860696518, 982.7305699481865, 858.2012987012987, 767.8924050632911, 761.950495049505, 682.1319796954315, 725.4198473282443, 702.1286549707602, 730.9484536082474, 739, 730.572864321608, 754.7467532467532, 657.373417721519, 640.9480519480519, 669.8156424581006, 787.6280991735537, 2931.229357798165, 1954.2808988764045, 777.5346534653465, 1098.538860103627, 1244.1524390243903, 2919.4913793103447, 2987.4188034188032, 3414.029411764706, 1355.2, 2714.2824427480914, 2657.8703703703704, 2873.892307692308, 6140.337078651685, 3966.560606060606, 3021.5789473684213, 1774.1875, 1076.46, 1426.8691588785048, 1261.0386740331492, 1019.3491124260355, 1194.960199004975, 1241.2878787878788, 3323, 3968.45625, 1468.0961538461538, 3630.4166666666665, 2269.5301204819275, 2554.391025641026, 1845.7888888888888, 1728.9767441860465, 2862.08, 2324.1241379310345, 1964.0169491525423, 1808.4, 3466.05035971223, 2297.4397590361446, 2530.0493827160494, 2439.3584905660377, 2007.9060773480662, 1751.5, 1416.3181818181818, 1429.2298850574712, 1452.0298507462687, 1489.720430107527, 1633.095238095238, 1826.2928571428572, 1610.1904761904761, 1680.9292929292928, 2881.743119266055, 3585.1634615384614, 3689.1666666666665, 3657.340277777778, 3643.5348837209303, 3714.8645833333335, 3731.375, 3744.79, 3636.2363636363634, 4273.113924050633, 3446.2, 3538.714285714286, 3790.6065573770493, 3527.675, 3467.671232876712, 3559.5, 3798.2, 5460.666666666667, 1309.4406779661017, 1535.7454545454545, 3423.8260869565215, 3382.3636363636365, 3400.6315789473683, 2950.75, 3386.731707317073, 2506, 1447.1666666666667, 1442.6, 946, 942.578947368421, 950.7142857142857, 947, 976.2857142857143, 1786.2857142857142, 1513.5777777777778, 1499.5625, 1338, 1327.8125, 1273.9175257731958, 1438.7457627118645, 1248.4186046511627, 1286.6693548387098, 1284.8934911242604, 1223.7952755905512, 748.09375, 871.7684210526315, 844.5338983050848, 791.675, 804.1932773109244, 730.3737373737374, 705.5024390243902, 687.2407407407408, 690.9939759036145, 751, 765.139344262295, 686.8717948717949, 669.7434210526316, 1767.8091603053435, 724.6764705882352, 748.2772277227723, 940.1142857142858, 750.368, 1366.0232558139535, 727.4137931034483, 710.719512195122, 689.8555555555556, 739.453488372093, 817.875, 730.4303797468355, 735.5890410958904, 738.2258064516129, 1906.9217391304348, 2290.785714285714, 1207.5072463768115, 1167.5890410958905, 1229.0208333333333, 1192.3777777777777, 1208.871794871795, 1367.715909090909, 1284.2233009708739, 1163.1739130434783, 1152.53, 1161.4545454545455, 1219.5681818181818, 1183.752808988764, 1197.778947368421, 1233.888888888889, 1275.070588235294, 1235.554054054054, 1207.83908045977, 1241.6184210526317, 1159.042735042735, 1138.2948717948718, 1106.9915966386554, 1171.4504504504505, 1223.822429906542, 1122.169642857143, 1018.8928571428571, 981.8285714285714, 998.8363636363637, 6056.572916666667, 7225.528846153846, 7193.834782608696, 7507.321100917431, 7588.695238095238, 7678.689189189189, 9469.633027522936, 10236.186046511628, 10106.608695652174, 9989.125, 9948.229357798165, 9796.030927835052, 9704.217391304348, 8454.028571428571, 6813.476190476191, 6706.782608695652, 6523.452173913043, 6661.553571428572, 5620.777777777777, 812.3142857142857, 809.5892857142857, 866.4786324786324, 877.8319327731092, 810.8141592920354, 815.7121212121212, 770.6470588235294, 763.3157894736842, 781.5151515151515, 807.5833333333334, 824.743119266055, 876.2151898734177, 882.424, 750.2213114754098, 675.9549549549549, 637.1222222222223], + "_sum/ConsumptionActivePowerL1": [null, null, null, 188.60153256704982, 186.83828382838283, 187.141975308642, 191.07232704402517, 188.60269360269362, 195.99346405228758, 194.7463126843658, 202.4939393939394, 201.6758409785933, 198.54692556634305, 200.84313725490196, 192.7228070175439, 193.89377289377288, 216.50555555555556, 186.76666666666665, 189.01246105919003, 209.92241379310346, 189.6204620462046, 196.53465346534654, 211.5030303030303, 207.55445544554456, 205.90654205607476, 202.7075471698113, 200.92666666666665, 216.93851132686083, 201.9625850340136, 198.13015873015874, 192.12, 188.35534591194968, 195.831715210356, 208.79166666666666, 227.31428571428572, 216.820987654321, 210.45794392523365, 229.08333333333334, 186.74842767295596, 175.9650793650794, 206.74074074074073, 182.21183800623052, 195.93769470404985, 201.33333333333334, 205.43197278911566, 192.98019801980197, 198.11320754716982, 216.0359477124183, null, null, null, 188.40613026819923, 191.21604938271605, 178.84876543209876, 186.027027027027, 191.58479532163744, 191.4519230769231, 198.96825396825398, 218.02402402402402, 205.07000000000002, 204.26819923371647, 212.03666666666666, 204.59829059829062, 179.6285714285714, 179.03859649122808, 183.72115384615384, 186.2936507936508, 186.3740740740741, 206.18589743589743, 218.1095890410959, 205.35249042145594, 196.30188679245282, 192.90322580645162, 194.34534534534535, 190.85669781931463, 198.42105263157896, 248.36296296296294, 273.57746478873236, 883.7307692307692, 2687.7103825136614, 2317.3518518518517, 2471.1368421052634, 2231.725, 2229.4336917562723, 2378.514814814815, 2311.8708333333334, 2256.1327160493825, 2320.864406779661, 1149.8398950131234, 225.81426202321725, 327.5768566493955, 286.06709956709955, 255.96413502109704, 253.983498349835, 227.37732656514382, 241.80661577608143, 234.04288499025338, 243.64948453608247, 246.33333333333334, 243.52428810720266, 251.58225108225108, 219.12447257383965, 213.64935064935062, 223.27188081936686, 262.5426997245179, 977.0764525993883, 651.4269662921348, 259.1782178217822, 366.1796200345423, 414.7174796747968, 973.1637931034483, 995.8062678062678, 1138.0098039215686, 451.73333333333335, 904.7608142493638, 885.9567901234568, 957.9641025641026, 2046.7790262172284, 1322.1868686868686, 1007.1929824561404, 591.3958333333334, 358.82, 475.6230529595016, 420.3462246777164, 339.78303747534517, 398.3200663349917, 413.76262626262627, 1107.6666666666667, 1322.8187500000001, 489.3653846153846, 1210.138888888889, 756.5100401606425, 851.4636752136753, 615.2629629629629, 576.3255813953489, 954.0266666666666, 774.7080459770115, 654.6723163841808, 602.8000000000001, 1155.3501199040768, 765.8132530120482, 843.3497942386831, 813.1194968553459, 669.3020257826887, 583.8333333333334, 472.10606060606057, 476.4099616858237, 484.00995024875624, 496.57347670250897, 544.3650793650794, 608.7642857142857, 536.7301587301587, 560.3097643097643, 960.5810397553518, 1195.054487179487, 1229.7222222222222, 1219.1134259259259, 1214.5116279069769, 1238.2881944444446, 1243.7916666666667, 1248.2633333333333, 1212.0787878787878, 1424.3713080168775, 1148.7333333333333, 1179.5714285714287, 1263.535519125683, 1175.8916666666667, 1155.890410958904, 1186.5, 1266.0666666666666, 1820.2222222222224, 436.48022598870057, 511.91515151515154, 1141.2753623188405, 1127.4545454545455, 1133.5438596491229, 983.5833333333334, 1128.910569105691, 835.3333333333334, 482.3888888888889, 480.8666666666666, 315.3333333333333, 314.1929824561403, 316.90476190476187, 315.6666666666667, 325.42857142857144, 595.4285714285714, 504.52592592592595, 499.8541666666667, 446, 442.6041666666667, 424.63917525773195, 479.5819209039548, 416.1395348837209, 428.8897849462366, 428.29783037475346, 407.93175853018374, 249.36458333333334, 290.58947368421053, 281.51129943502826, 263.89166666666665, 268.0644257703081, 243.45791245791247, 235.16747967479674, 229.08024691358025, 230.33132530120483, 250.33333333333334, 255.04644808743168, 228.95726495726498, 223.24780701754386, 589.2697201017812, 241.55882352941174, 249.42574257425744, 313.37142857142857, 250.12266666666667, 455.3410852713178, 242.47126436781608, 236.90650406504065, 229.95185185185187, 246.484496124031, 272.625, 243.47679324894514, 245.19634703196346, 246.07526881720432, 635.640579710145, 763.5952380952381, 402.50241545893715, 389.1963470319635, 409.6736111111111, 397.4592592592592, 402.95726495726495, 455.905303030303, 428.074433656958, 387.72463768115944, 384.1766666666667, 387.1515151515152, 406.52272727272725, 394.5842696629213, 399.25964912280705, 411.2962962962963, 425.0235294117647, 411.8513513513513, 402.61302681992333, 413.8728070175439, 386.34757834757835, 379.43162393162396, 368.99719887955183, 390.4834834834835, 407.94080996884736, 374.05654761904765, 339.63095238095235, 327.2761904761905, 332.94545454545454, 2018.857638888889, 2408.5096153846152, 2397.9449275362317, 2502.440366972477, 2529.5650793650793, 2559.563063063063, 3156.544342507645, 3412.062015503876, 3368.8695652173915, 3329.7083333333335, 3316.0764525993886, 3265.343642611684, 3234.7391304347825, 2818.0095238095237, 2271.15873015873, 2235.5942028985505, 2174.4840579710144, 2220.5178571428573, 1873.5925925925924, 270.77142857142854, 269.86309523809524, 288.8262108262108, 292.6106442577031, 270.27138643067843, 271.9040404040404, 256.88235294117646, 254.43859649122805, 260.5050505050505, 269.19444444444446, 274.914373088685, 292.07172995780587, 294.1413333333333, 250.0737704918033, 225.31831831831832, 212.3740740740741], + "_sum/ConsumptionActivePowerL2": [null, null, null, 188.60153256704982, 186.83828382838283, 187.141975308642, 191.07232704402517, 188.60269360269362, 195.99346405228758, 194.7463126843658, 202.4939393939394, 201.6758409785933, 198.54692556634305, 200.84313725490196, 192.7228070175439, 193.89377289377288, 216.50555555555556, 186.76666666666665, 189.01246105919003, 209.92241379310346, 189.6204620462046, 196.53465346534654, 211.5030303030303, 207.55445544554456, 205.90654205607476, 202.7075471698113, 200.92666666666665, 216.93851132686083, 201.9625850340136, 198.13015873015874, 192.12, 188.35534591194968, 195.831715210356, 208.79166666666666, 227.31428571428572, 216.820987654321, 210.45794392523365, 229.08333333333334, 186.74842767295596, 175.9650793650794, 206.74074074074073, 182.21183800623052, 195.93769470404985, 201.33333333333334, 205.43197278911566, 192.98019801980197, 198.11320754716982, 216.0359477124183, null, null, null, 188.40613026819923, 191.21604938271605, 178.84876543209876, 186.027027027027, 191.58479532163744, 191.4519230769231, 198.96825396825398, 218.02402402402402, 205.07000000000002, 204.26819923371647, 212.03666666666666, 204.59829059829062, 179.6285714285714, 179.03859649122808, 183.72115384615384, 186.2936507936508, 186.3740740740741, 206.18589743589743, 218.1095890410959, 205.35249042145594, 196.30188679245282, 192.90322580645162, 194.34534534534535, 190.85669781931463, 198.42105263157896, 248.36296296296294, 273.57746478873236, 883.7307692307692, 2687.7103825136614, 2317.3518518518517, 2471.1368421052634, 2231.725, 2229.4336917562723, 2378.514814814815, 2311.8708333333334, 2256.1327160493825, 2320.864406779661, 1149.8398950131234, 225.81426202321725, 327.5768566493955, 286.06709956709955, 255.96413502109704, 253.983498349835, 227.37732656514382, 241.80661577608143, 234.04288499025338, 243.64948453608247, 246.33333333333334, 243.52428810720266, 251.58225108225108, 219.12447257383965, 213.64935064935062, 223.27188081936686, 262.5426997245179, 977.0764525993883, 651.4269662921348, 259.1782178217822, 366.1796200345423, 414.7174796747968, 973.1637931034483, 995.8062678062678, 1138.0098039215686, 451.73333333333335, 904.7608142493638, 885.9567901234568, 957.9641025641026, 2046.7790262172284, 1322.1868686868686, 1007.1929824561404, 591.3958333333334, 358.82, 475.6230529595016, 420.3462246777164, 339.78303747534517, 398.3200663349917, 413.76262626262627, 1107.6666666666667, 1322.8187500000001, 489.3653846153846, 1210.138888888889, 756.5100401606425, 851.4636752136753, 615.2629629629629, 576.3255813953489, 954.0266666666666, 774.7080459770115, 654.6723163841808, 602.8000000000001, 1155.3501199040768, 765.8132530120482, 843.3497942386831, 813.1194968553459, 669.3020257826887, 583.8333333333334, 472.10606060606057, 476.4099616858237, 484.00995024875624, 496.57347670250897, 544.3650793650794, 608.7642857142857, 536.7301587301587, 560.3097643097643, 960.5810397553518, 1195.054487179487, 1229.7222222222222, 1219.1134259259259, 1214.5116279069769, 1238.2881944444446, 1243.7916666666667, 1248.2633333333333, 1212.0787878787878, 1424.3713080168775, 1148.7333333333333, 1179.5714285714287, 1263.535519125683, 1175.8916666666667, 1155.890410958904, 1186.5, 1266.0666666666666, 1820.2222222222224, 436.48022598870057, 511.91515151515154, 1141.2753623188405, 1127.4545454545455, 1133.5438596491229, 983.5833333333334, 1128.910569105691, 835.3333333333334, 482.3888888888889, 480.8666666666666, 315.3333333333333, 314.1929824561403, 316.90476190476187, 315.6666666666667, 325.42857142857144, 595.4285714285714, 504.52592592592595, 499.8541666666667, 446, 442.6041666666667, 424.63917525773195, 479.5819209039548, 416.1395348837209, 428.8897849462366, 428.29783037475346, 407.93175853018374, 249.36458333333334, 290.58947368421053, 281.51129943502826, 263.89166666666665, 268.0644257703081, 243.45791245791247, 235.16747967479674, 229.08024691358025, 230.33132530120483, 250.33333333333334, 255.04644808743168, 228.95726495726498, 223.24780701754386, 589.2697201017812, 241.55882352941174, 249.42574257425744, 313.37142857142857, 250.12266666666667, 455.3410852713178, 242.47126436781608, 236.90650406504065, 229.95185185185187, 246.484496124031, 272.625, 243.47679324894514, 245.19634703196346, 246.07526881720432, 635.640579710145, 763.5952380952381, 402.50241545893715, 389.1963470319635, 409.6736111111111, 397.4592592592592, 402.95726495726495, 455.905303030303, 428.074433656958, 387.72463768115944, 384.1766666666667, 387.1515151515152, 406.52272727272725, 394.5842696629213, 399.25964912280705, 411.2962962962963, 425.0235294117647, 411.8513513513513, 402.61302681992333, 413.8728070175439, 386.34757834757835, 379.43162393162396, 368.99719887955183, 390.4834834834835, 407.94080996884736, 374.05654761904765, 339.63095238095235, 327.2761904761905, 332.94545454545454, 2018.857638888889, 2408.5096153846152, 2397.9449275362317, 2502.440366972477, 2529.5650793650793, 2559.563063063063, 3156.544342507645, 3412.062015503876, 3368.8695652173915, 3329.7083333333335, 3316.0764525993886, 3265.343642611684, 3234.7391304347825, 2818.0095238095237, 2271.15873015873, 2235.5942028985505, 2174.4840579710144, 2220.5178571428573, 1873.5925925925924, 270.77142857142854, 269.86309523809524, 288.8262108262108, 292.6106442577031, 270.27138643067843, 271.9040404040404, 256.88235294117646, 254.43859649122805, 260.5050505050505, 269.19444444444446, 274.914373088685, 292.07172995780587, 294.1413333333333, 250.0737704918033, 225.31831831831832, 212.3740740740741], + "_sum/ConsumptionActivePowerL3": [null, null, null, 188.60153256704982, 186.83828382838283, 187.141975308642, 191.07232704402517, 188.60269360269362, 195.99346405228758, 194.7463126843658, 202.4939393939394, 201.6758409785933, 198.54692556634305, 200.84313725490196, 192.7228070175439, 193.89377289377288, 216.50555555555556, 186.76666666666665, 189.01246105919003, 209.92241379310346, 189.6204620462046, 196.53465346534654, 211.5030303030303, 207.55445544554456, 205.90654205607476, 202.7075471698113, 200.92666666666665, 216.93851132686083, 201.9625850340136, 198.13015873015874, 192.12, 188.35534591194968, 195.831715210356, 208.79166666666666, 227.31428571428572, 216.820987654321, 210.45794392523365, 229.08333333333334, 186.74842767295596, 175.9650793650794, 206.74074074074073, 182.21183800623052, 195.93769470404985, 201.33333333333334, 205.43197278911566, 192.98019801980197, 198.11320754716982, 216.0359477124183, null, null, null, 188.40613026819923, 191.21604938271605, 178.84876543209876, 186.027027027027, 191.58479532163744, 191.4519230769231, 198.96825396825398, 218.02402402402402, 205.07000000000002, 204.26819923371647, 212.03666666666666, 204.59829059829062, 179.6285714285714, 179.03859649122808, 183.72115384615384, 186.2936507936508, 186.3740740740741, 206.18589743589743, 218.1095890410959, 205.35249042145594, 196.30188679245282, 192.90322580645162, 194.34534534534535, 190.85669781931463, 198.42105263157896, 248.36296296296294, 273.57746478873236, 883.7307692307692, 2687.7103825136614, 2317.3518518518517, 2471.1368421052634, 2231.725, 2229.4336917562723, 2378.514814814815, 2311.8708333333334, 2256.1327160493825, 2320.864406779661, 1149.8398950131234, 225.81426202321725, 327.5768566493955, 286.06709956709955, 255.96413502109704, 253.983498349835, 227.37732656514382, 241.80661577608143, 234.04288499025338, 243.64948453608247, 246.33333333333334, 243.52428810720266, 251.58225108225108, 219.12447257383965, 213.64935064935062, 223.27188081936686, 262.5426997245179, 977.0764525993883, 651.4269662921348, 259.1782178217822, 366.1796200345423, 414.7174796747968, 973.1637931034483, 995.8062678062678, 1138.0098039215686, 451.73333333333335, 904.7608142493638, 885.9567901234568, 957.9641025641026, 2046.7790262172284, 1322.1868686868686, 1007.1929824561404, 591.3958333333334, 358.82, 475.6230529595016, 420.3462246777164, 339.78303747534517, 398.3200663349917, 413.76262626262627, 1107.6666666666667, 1322.8187500000001, 489.3653846153846, 1210.138888888889, 756.5100401606425, 851.4636752136753, 615.2629629629629, 576.3255813953489, 954.0266666666666, 774.7080459770115, 654.6723163841808, 602.8000000000001, 1155.3501199040768, 765.8132530120482, 843.3497942386831, 813.1194968553459, 669.3020257826887, 583.8333333333334, 472.10606060606057, 476.4099616858237, 484.00995024875624, 496.57347670250897, 544.3650793650794, 608.7642857142857, 536.7301587301587, 560.3097643097643, 960.5810397553518, 1195.054487179487, 1229.7222222222222, 1219.1134259259259, 1214.5116279069769, 1238.2881944444446, 1243.7916666666667, 1248.2633333333333, 1212.0787878787878, 1424.3713080168775, 1148.7333333333333, 1179.5714285714287, 1263.535519125683, 1175.8916666666667, 1155.890410958904, 1186.5, 1266.0666666666666, 1820.2222222222224, 436.48022598870057, 511.91515151515154, 1141.2753623188405, 1127.4545454545455, 1133.5438596491229, 983.5833333333334, 1128.910569105691, 835.3333333333334, 482.3888888888889, 480.8666666666666, 315.3333333333333, 314.1929824561403, 316.90476190476187, 315.6666666666667, 325.42857142857144, 595.4285714285714, 504.52592592592595, 499.8541666666667, 446, 442.6041666666667, 424.63917525773195, 479.5819209039548, 416.1395348837209, 428.8897849462366, 428.29783037475346, 407.93175853018374, 249.36458333333334, 290.58947368421053, 281.51129943502826, 263.89166666666665, 268.0644257703081, 243.45791245791247, 235.16747967479674, 229.08024691358025, 230.33132530120483, 250.33333333333334, 255.04644808743168, 228.95726495726498, 223.24780701754386, 589.2697201017812, 241.55882352941174, 249.42574257425744, 313.37142857142857, 250.12266666666667, 455.3410852713178, 242.47126436781608, 236.90650406504065, 229.95185185185187, 246.484496124031, 272.625, 243.47679324894514, 245.19634703196346, 246.07526881720432, 635.640579710145, 763.5952380952381, 402.50241545893715, 389.1963470319635, 409.6736111111111, 397.4592592592592, 402.95726495726495, 455.905303030303, 428.074433656958, 387.72463768115944, 384.1766666666667, 387.1515151515152, 406.52272727272725, 394.5842696629213, 399.25964912280705, 411.2962962962963, 425.0235294117647, 411.8513513513513, 402.61302681992333, 413.8728070175439, 386.34757834757835, 379.43162393162396, 368.99719887955183, 390.4834834834835, 407.94080996884736, 374.05654761904765, 339.63095238095235, 327.2761904761905, 332.94545454545454, 2018.857638888889, 2408.5096153846152, 2397.9449275362317, 2502.440366972477, 2529.5650793650793, 2559.563063063063, 3156.544342507645, 3412.062015503876, 3368.8695652173915, 3329.7083333333335, 3316.0764525993886, 3265.343642611684, 3234.7391304347825, 2818.0095238095237, 2271.15873015873, 2235.5942028985505, 2174.4840579710144, 2220.5178571428573, 1873.5925925925924, 270.77142857142854, 269.86309523809524, 288.8262108262108, 292.6106442577031, 270.27138643067843, 271.9040404040404, 256.88235294117646, 254.43859649122805, 260.5050505050505, 269.19444444444446, 274.914373088685, 292.07172995780587, 294.1413333333333, 250.0737704918033, 225.31831831831832, 212.3740740740741], + "evcs0/ChargePower": [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, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, null, 0, 4104.142857142857, 5829.969696969697, 5806.212121212121, 6195.333333333333, 5777.333333333333, 5786.25, 5789.727272727273, 5789.571428571428, 5783.0526315789475, 5772.657142857143, 4864.8421052631575, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, null, null, 0, null, null, 0, 0, null, 0, 0, null, 0, 0, null, 0, 0, 0, 0, 0, 0, null, 0, null, null, 0, 0, null, null, 0, 0, 0, null, 0, null, null, 0, 0, null, 0, null, null, null, null, 0, null, 0, 0, null, null, null, null, null, 0, null, null, null, null, null, 0, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 0, 0, null, 0, null, 0, 0, 0, 0, 0, 0, null, null, 0, 0, null, 0, 0, 0, null, null, 0, 0, null, 0, 0, null, null, null, 0, null, null, null, null, null, null, 0, 0, 0, null, 0, 0, 0, 0, null, 0, null, 0, null, 0, 0, 0, null, 0, 0, 0, 0, 0, 5213.0952380952385, 5787.580645161291, 5789.484848484848, 5790.818181818182, 5807.34375, 5820.136363636364, 5798.862068965517, 5809.041666666667, 5805.5625, 5794.346153846154, 5798, 5740.214285714285, 5727.242424242424, 5742.542857142857, 5753.424242424242, 5752.4, 5731.966666666666, 5734.323529411765, 5335.586206896552, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null], + "meter0/ActivePower": [124.28571428571429, 0, null, 0, 173.33333333333334, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 110, 113.33333333333333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 113.33333333333333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 113.33333333333333, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 140, null, null, null, 2126.875, 175, 176, null, 180, 180, 185, 180, null, 185, 190, 180, 180, 176.25, 175.83333333333334, 170, 175, 170, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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"], }), @@ -47,9 +47,9 @@ export namespace History { }), dataChannelWithValues: new QueryHistoricTimeseriesDataResponse("0", { data: { - '_sum/ConsumptionActivePower': [663.9876181166504, 937.5188284518829, 761.5839462743844, 599.7653758542141, 989.6435035552682, 666.2890016920473, 1054.177495462795, 1042.9070871481858, 661.1515631183221, 734.2340980187696, 845.5174603174603, 969.5830886670582, 591.8473777253978, 1960.0339449541284, 919.7469512195122, 1232.6632911392405, 562.9648946840522, 786.2627471383975, 931.422932330827, 837.381753312946, 1112.3010184835912, 902.5108194395176, 807.5094273743017, 988.311229946524, 614.0189035916824, 868.6555377207062, 906.9389035667107, 673.3970826580227, 827.6491228070175, 851.9108776685869, 852.9105374823197, 867.4681647940075, 1303.01722614841, 950.6813929313929, 1124.7157794676807, 908.7814790139906, 1554.5020215633424, 4743.944086021505, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null], - 'evcs0/ChargePower': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4586.923076923077, 4846.2192982456145, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null], - 'meter0/ActivePower': [27.956773446545736, 27.93238434163701, 28.003065134099618, 27.952205882352942, 27.998854961832063, 28.116988416988416, 27.987117552334944, 28.404306220095695, 22.10508757297748, 24.58289572393098, 25.521831735889243, 33.94027565084227, 66.40016920473774, 74.85995085995086, 56.30216802168022, 40.562390158172235, 42.72727272727273, 41.85823488533704, 29.56647864625302, 26.93582887700535, 29.227223427331886, 31.081920903954803, 29.50079575596817, 29.29895178197065, 27.74064837905237, 27.340638930163447, 27.272103350827614, 27.199391171993913, 26.97577592732778, 26.88116057233704, 27.04352806414662, 26.709154929577466, 24.765209940017137, 20.726594301221166, 24.283930058284763, 27.086363636363636, 47.70666666666666, 53.07067510548523, 52.73466476462197, 54.75776892430279, 50.23135033050047, 41.280141843971634, 31.509341199606688, 26.471978392977718, 31.050412465627865, 29.384710234278668, 27.95327604726101, 28.357904496986556, 25.56408588158751, null, 26.944094488188977, 27.036082474226806, 26.367164179104478, 25.185562632696392, 26.994444444444444, 25.911782850092536, 13.431970713849909, 24.309846431797652, 25.234712230215827, 26.126705653021443, 60.64339781328848, 39.96433289299868, 37.667578659370726, 50.66542750929368, 41.89218523878437, 29.88109495295124, 26.93968253968254, 25.741935483870968, 28.64, 31.331460674157302, 30.017262638717632, 28.636402753872634, 28.408956692913385, 28.14567233384853, 28.25509028044564, 28.12612966601179, 28.175675675675677, 27.409126063418405, 27.54943984413054, 27.246363209760677, 22.96663244353183, 21.65732959850607, 22.306306306306308, 25.892307692307693, 51.8, 52.903225806451616, 59.02597402597402, 39.35110294117647, 33.87375113533152, 29.98160073597056, 26.481973434535103, 29.473684210526315, 28.432854465958776, 29.162214983713355, 28.663861386138613, 28.23558082859464, 28.460033305578683, 29.076231430805315, 28.803389830508475, 28.62062404870624, 28.578023655093475, 28.370570107858242, 27.46546431312356, 27.873293515358363, 25.733505154639175, 26.357802874743328, 27.692853246044734, 24.205128205128204, null, 26.746031746031747, 23.178571428571427, 26.16861826697892, 28.333646616541355, 26.758232235701907, 23.993934142114384, 24.71902131018153, 28.23051948051948, 28.74572127139364, 28.485825458588103, 28.22232263895165, 28.392755392755394, 28.338354151359294, 27.164207340143776, 26.949324324324323, 26.942610652663166, 27.8092203898051, 27.980593607305938, 28.26596758817922, 29.656794425087107, 25.145056246299585, 25.203214100570243, 28.82728749323227, 32.22576966932725, 31.200444197667963, 30.594259988745076, 43.34990059642147, 46.15876288659794, 33.40802469135802, 27.489320388349515, 25.818808777429467, 27.95967741935484, 28.96995139195758, 27.5499557913351, 28.341370558375633, 28.25076053889613, 27.812838360402164, 28.10333080999243, 27.840314136125656, 27.800384615384615, 27.97958397534669, 27.235769230769233, 26.924960505529224, 29.03847980997625, 27.93128390596745, 34.10349373764008, 32.7387339055794, 29.509929906542055, 37.00855745721272, 32.240085744908896, 27.701363636363638, 30.787037037037038, 25.786028602860284, 29.997148966500358, 32.89406099518459, 35.328729281767956, 25.65564738292011, 27.46238030095759, 28.27226647356988], + "_sum/ConsumptionActivePower": [663.9876181166504, 937.5188284518829, 761.5839462743844, 599.7653758542141, 989.6435035552682, 666.2890016920473, 1054.177495462795, 1042.9070871481858, 661.1515631183221, 734.2340980187696, 845.5174603174603, 969.5830886670582, 591.8473777253978, 1960.0339449541284, 919.7469512195122, 1232.6632911392405, 562.9648946840522, 786.2627471383975, 931.422932330827, 837.381753312946, 1112.3010184835912, 902.5108194395176, 807.5094273743017, 988.311229946524, 614.0189035916824, 868.6555377207062, 906.9389035667107, 673.3970826580227, 827.6491228070175, 851.9108776685869, 852.9105374823197, 867.4681647940075, 1303.01722614841, 950.6813929313929, 1124.7157794676807, 908.7814790139906, 1554.5020215633424, 4743.944086021505, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null], + "evcs0/ChargePower": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4586.923076923077, 4846.2192982456145, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null], + "meter0/ActivePower": [27.956773446545736, 27.93238434163701, 28.003065134099618, 27.952205882352942, 27.998854961832063, 28.116988416988416, 27.987117552334944, 28.404306220095695, 22.10508757297748, 24.58289572393098, 25.521831735889243, 33.94027565084227, 66.40016920473774, 74.85995085995086, 56.30216802168022, 40.562390158172235, 42.72727272727273, 41.85823488533704, 29.56647864625302, 26.93582887700535, 29.227223427331886, 31.081920903954803, 29.50079575596817, 29.29895178197065, 27.74064837905237, 27.340638930163447, 27.272103350827614, 27.199391171993913, 26.97577592732778, 26.88116057233704, 27.04352806414662, 26.709154929577466, 24.765209940017137, 20.726594301221166, 24.283930058284763, 27.086363636363636, 47.70666666666666, 53.07067510548523, 52.73466476462197, 54.75776892430279, 50.23135033050047, 41.280141843971634, 31.509341199606688, 26.471978392977718, 31.050412465627865, 29.384710234278668, 27.95327604726101, 28.357904496986556, 25.56408588158751, null, 26.944094488188977, 27.036082474226806, 26.367164179104478, 25.185562632696392, 26.994444444444444, 25.911782850092536, 13.431970713849909, 24.309846431797652, 25.234712230215827, 26.126705653021443, 60.64339781328848, 39.96433289299868, 37.667578659370726, 50.66542750929368, 41.89218523878437, 29.88109495295124, 26.93968253968254, 25.741935483870968, 28.64, 31.331460674157302, 30.017262638717632, 28.636402753872634, 28.408956692913385, 28.14567233384853, 28.25509028044564, 28.12612966601179, 28.175675675675677, 27.409126063418405, 27.54943984413054, 27.246363209760677, 22.96663244353183, 21.65732959850607, 22.306306306306308, 25.892307692307693, 51.8, 52.903225806451616, 59.02597402597402, 39.35110294117647, 33.87375113533152, 29.98160073597056, 26.481973434535103, 29.473684210526315, 28.432854465958776, 29.162214983713355, 28.663861386138613, 28.23558082859464, 28.460033305578683, 29.076231430805315, 28.803389830508475, 28.62062404870624, 28.578023655093475, 28.370570107858242, 27.46546431312356, 27.873293515358363, 25.733505154639175, 26.357802874743328, 27.692853246044734, 24.205128205128204, null, 26.746031746031747, 23.178571428571427, 26.16861826697892, 28.333646616541355, 26.758232235701907, 23.993934142114384, 24.71902131018153, 28.23051948051948, 28.74572127139364, 28.485825458588103, 28.22232263895165, 28.392755392755394, 28.338354151359294, 27.164207340143776, 26.949324324324323, 26.942610652663166, 27.8092203898051, 27.980593607305938, 28.26596758817922, 29.656794425087107, 25.145056246299585, 25.203214100570243, 28.82728749323227, 32.22576966932725, 31.200444197667963, 30.594259988745076, 43.34990059642147, 46.15876288659794, 33.40802469135802, 27.489320388349515, 25.818808777429467, 27.95967741935484, 28.96995139195758, 27.5499557913351, 28.341370558375633, 28.25076053889613, 27.812838360402164, 28.10333080999243, 27.840314136125656, 27.800384615384615, 27.97958397534669, 27.235769230769233, 26.924960505529224, 29.03847980997625, 27.93128390596745, 34.10349373764008, 32.7387339055794, 29.509929906542055, 37.00855745721272, 32.240085744908896, 27.701363636363638, 30.787037037037038, 25.786028602860284, 29.997148966500358, 32.89406099518459, 35.328729281767956, 25.65564738292011, 27.46238030095759, 28.27226647356988], }, 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"], }), @@ -60,7 +60,7 @@ export namespace History { export const MONTH: OeTester.Types.Channels = { energyChannelWithValues: new QueryHistoricTimeseriesEnergyResponse("0", { data: { - '_sum/ConsumptionActiveEnergy': 1033427, + "_sum/ConsumptionActiveEnergy": 1033427, "evcs0/ActiveConsumptionEnergy": 328451, "meter0/ActiveProductionEnergy": 21649, }, @@ -68,7 +68,7 @@ export namespace History { energyPerPeriodChannelWithValues: new QueryHistoricTimeseriesEnergyPerPeriodResponse("0", { data: { - '_sum/ConsumptionActiveEnergy': [1784.3478512581187, 955.1978135997077, 1604.9176251387696, 1821.5474663613152, 1204.011627189301, 1037.408900359932, 1287.891020875591, 1183.057735422114, 1027.8784377276404, 1412.783196754379, 737.2379614126091, 730.6143394985477, 1727.4568452231197, 2045.4827463867603, 1289.9867373938441, 1866.5731598778827, 896.448259060122, 1271.0485678635469, 1489.7323302960576, 1367.9696489029907, 2375.6092366846033, 2368.729102836224, 2686.60326649514, 1597.0390753045413, 972.6650191463931, 1774.233690168573, 2953.838257099637, 917.3087792235759, 1172.9800154902882, null, null], + "_sum/ConsumptionActiveEnergy": [1784.3478512581187, 955.1978135997077, 1604.9176251387696, 1821.5474663613152, 1204.011627189301, 1037.408900359932, 1287.891020875591, 1183.057735422114, 1027.8784377276404, 1412.783196754379, 737.2379614126091, 730.6143394985477, 1727.4568452231197, 2045.4827463867603, 1289.9867373938441, 1866.5731598778827, 896.448259060122, 1271.0485678635469, 1489.7323302960576, 1367.9696489029907, 2375.6092366846033, 2368.729102836224, 2686.60326649514, 1597.0390753045413, 972.6650191463931, 1774.233690168573, 2953.838257099637, 917.3087792235759, 1172.9800154902882, null, null], "evcs0/ActiveConsumptionEnergy": [598.058461158158, 0, 607.3861225965935, 891.3491768679577, 269.6236843407865, 0, 306.41009901340226, 220.51407209843148, 50.15525733301707, 356.42246970726825, 0, 0, 880.0942036863182, 977.4033026217928, 210.23831546417276, 787.0712558876392, 0, 165.50743075023163, 513.2605942604259, 149.06825174512016, 883.6100586172083, 1203.117101530366, 1467.2314708234808, 553.6230686820822, 0, 714.8486366912176, 1836.7765179313803, 0, 300.374916784946, null, null], "meter0/ActiveProductionEnergy": [15.53700680772126, 13.97856617670663, 16.22420643945345, 15.425155003970989, 16.41557086346929, 15.280936198647838, 15.028196655704793, 15.146427851947054, 15.567356482244767, 17.404197969735606, 17.635152684968116, 14.140394156739468, 16.107488806188936, 16.75001277671301, 15.512752420609466, 14.951999780788457, 13.733457057782298, 16.868671206682027, 14.770978996449593, 16.47697124898351, 16.772182319685665, 16.288562161254703, 15.417362341926745, 15.892028990939403, 13.811584043067414, 14.81782772305683, 14.165639305307824, 16.223347257543285, 14.495672387672808, null, null], }, @@ -81,23 +81,23 @@ export namespace History { export const YEAR: OeTester.Types.Channels = { energyChannelWithValues: new QueryHistoricTimeseriesEnergyResponse("0", { data: { - '_sum/ConsumptionActiveEnergy': 14863655, + "_sum/ConsumptionActiveEnergy": 14863655, "_sum/ConsumptionActiveEnergyL1": 4954551, "_sum/ConsumptionActiveEnergyL2": 4954551, "_sum/ConsumptionActiveEnergyL3": 4954551, - 'evcs0/ActiveConsumptionEnergy': 2071139, - 'meter0/ActiveProductionEnergy': 1908650, + "evcs0/ActiveConsumptionEnergy": 2071139, + "meter0/ActiveProductionEnergy": 1908650, }, }), energyPerPeriodChannelWithValues: new QueryHistoricTimeseriesEnergyPerPeriodResponse("0", { data: { - '_sum/ConsumptionActiveEnergy': [1682941, 1834729, 1805222, 1934144, 1757577, 1511352, 2306988, 2029933, 0, 0, 0, 0], - '_sum/ConsumptionActiveEnergyL1': [560980.3333333334, 611576.3333333334, 601740.6666666666, 644714.6666666666, 585859, 503784, 768996, 676644.3333333334, 0, 0, 0, 0], - '_sum/ConsumptionActiveEnergyL2': [560980.3333333334, 611576.3333333334, 601740.6666666666, 644714.6666666666, 585859, 503784, 768996, 676644.3333333334, 0, 0, 0, 0], - '_sum/ConsumptionActiveEnergyL3': [560980.3333333334, 611576.3333333334, 601740.6666666666, 644714.6666666666, 585859, 503784, 768996, 676644.3333333334, 0, 0, 0, 0], - 'evcs0/ActiveConsumptionEnergy': [69104, 131703, 25773, 51085, 169943, 332522, 748189, 540740, 0, 0, 0, 0], - 'meter0/ActiveProductionEnergy': [338070, 312380, 298930, 317700, 200210, 151160, 145880, 144280, 0, 0, 0, 0], + "_sum/ConsumptionActiveEnergy": [1682941, 1834729, 1805222, 1934144, 1757577, 1511352, 2306988, 2029933, 0, 0, 0, 0], + "_sum/ConsumptionActiveEnergyL1": [560980.3333333334, 611576.3333333334, 601740.6666666666, 644714.6666666666, 585859, 503784, 768996, 676644.3333333334, 0, 0, 0, 0], + "_sum/ConsumptionActiveEnergyL2": [560980.3333333334, 611576.3333333334, 601740.6666666666, 644714.6666666666, 585859, 503784, 768996, 676644.3333333334, 0, 0, 0, 0], + "_sum/ConsumptionActiveEnergyL3": [560980.3333333334, 611576.3333333334, 601740.6666666666, 644714.6666666666, 585859, 503784, 768996, 676644.3333333334, 0, 0, 0, 0], + "evcs0/ActiveConsumptionEnergy": [69104, 131703, 25773, 51085, 169943, 332522, 748189, 540740, 0, 0, 0, 0], + "meter0/ActiveProductionEnergy": [338070, 312380, 298930, 317700, 200210, 151160, 145880, 144280, 0, 0, 0, 0], }, 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"], }), diff --git a/ui/src/app/edge/history/common/consumption/chart/chart.constants.spec.ts b/ui/src/app/edge/history/common/consumption/chart/chart.constants.spec.ts index 4793ffc4ded..c9bc81b39a5 100644 --- a/ui/src/app/edge/history/common/consumption/chart/chart.constants.spec.ts +++ b/ui/src/app/edge/history/common/consumption/chart/chart.constants.spec.ts @@ -5,7 +5,7 @@ import { removeFunctions, TestContext } from "src/app/shared/components/shared/t import { EdgeConfig } from "src/app/shared/shared"; import { ChartComponent } from "./chart"; -export function expectView(config: EdgeConfig, testContext: TestContext, chartType: 'line' | 'bar', channels: OeTester.Types.Channels, view: OeChartTester.View): void { +export function expectView(config: EdgeConfig, testContext: TestContext, chartType: "line" | "bar", channels: OeTester.Types.Channels, view: OeChartTester.View): void { expect(removeFunctions(OeChartTester .apply(ChartComponent diff --git a/ui/src/app/edge/history/common/consumption/chart/chart.spec.ts b/ui/src/app/edge/history/common/consumption/chart/chart.spec.ts index 2ff4b493fe0..66697d1c191 100644 --- a/ui/src/app/edge/history/common/consumption/chart/chart.spec.ts +++ b/ui/src/app/edge/history/common/consumption/chart/chart.spec.ts @@ -7,7 +7,7 @@ import { DATA, LABELS } from "../../energy/chart/chart.constants.spec"; import { History } from "./channels.spec"; import { expectView } from "./chart.constants.spec"; -describe('History Consumption', () => { +describe("History Consumption", () => { const defaultEMS = DummyConfig.from( DummyConfig.Component.SOCOMEC_CONSUMPTION_METER("meter0", "Whirlpool"), DummyConfig.Component.EVCS_HARDY_BARTH("evcs0", "Charging Station"), @@ -18,21 +18,21 @@ describe('History Consumption', () => { TEST_CONTEXT = await sharedSetup(), ); - it('#getChartData()', () => { + it("#getChartData()", () => { { // Line-Chart, phases - expectView(defaultEMS, TEST_CONTEXT, 'line', History.DAY, + expectView(defaultEMS, TEST_CONTEXT, "line", History.DAY, { datasets: { data: [ - DATA('Gesamt: 93 kWh', [null, null, null, 0.5658045977011494, 0.5605148514851485, 0.561425925925926, 0.5732169811320755, 0.5658080808080809, 0.5879803921568627, 0.5842389380530973, 0.6074818181818182, 0.6050275229357799, 0.5956407766990292, 0.6025294117647059, 0.5781684210526317, 0.5816813186813187, 0.6495166666666666, 0.5602999999999999, 0.56703738317757, 0.6297672413793104, 0.5688613861386138, 0.5896039603960396, 0.6345090909090909, 0.6226633663366337, 0.6177196261682243, 0.608122641509434, 0.60278, 0.6508155339805825, 0.6058877551020408, 0.5943904761904762, 0.57636, 0.5650660377358491, 0.587495145631068, 0.626375, 0.6819428571428572, 0.6504629629629629, 0.6313738317757009, 0.68725, 0.5602452830188679, 0.5278952380952382, 0.6202222222222221, 0.5466355140186916, 0.5878130841121496, 0.604, 0.616295918367347, 0.5789405940594059, 0.5943396226415094, 0.6481078431372549, null, null, null, 0.5652183908045977, 0.5736481481481481, 0.5365462962962964, 0.558081081081081, 0.5747543859649124, 0.5743557692307693, 0.5969047619047619, 0.6540720720720721, 0.61521, 0.6128045977011494, 0.6361100000000001, 0.6137948717948718, 0.5388857142857142, 0.5371157894736842, 0.5511634615384615, 0.5588809523809524, 0.5591222222222223, 0.6185576923076923, 0.6543287671232877, 0.6160574712643678, 0.5889056603773585, 0.5787096774193549, 0.583036036036036, 0.572570093457944, 0.5952631578947368, 0.7450888888888888, 0.8207323943661972, 2.6511923076923076, 8.063131147540984, 6.952055555555556, 7.41341052631579, 6.695175, 6.688301075268817, 7.135544444444445, 6.9356125, 6.768398148148147, 6.962593220338983, 3.44951968503937, 0.6774427860696518, 0.9827305699481865, 0.8582012987012987, 0.7678924050632912, 0.761950495049505, 0.6821319796954315, 0.7254198473282443, 0.7021286549707602, 0.7309484536082475, 0.739, 0.730572864321608, 0.7547467532467532, 0.657373417721519, 0.6409480519480519, 0.6698156424581005, 0.7876280991735537, 2.931229357798165, 1.9542808988764044, 0.7775346534653466, 1.098538860103627, 1.2441524390243903, 2.9194913793103447, 2.9874188034188034, 3.4140294117647056, 1.3552, 2.7142824427480914, 2.6578703703703703, 2.8738923076923077, 6.140337078651685, 3.966560606060606, 3.0215789473684214, 1.7741875, 1.07646, 1.4268691588785047, 1.2610386740331492, 1.0193491124260354, 1.194960199004975, 1.2412878787878787, 3.323, 3.96845625, 1.4680961538461539, 3.6304166666666666, 2.2695301204819276, 2.554391025641026, 1.8457888888888887, 1.7289767441860464, 2.8620799999999997, 2.3241241379310345, 1.9640169491525423, 1.8084, 3.4660503597122303, 2.2974397590361444, 2.5300493827160495, 2.439358490566038, 2.0079060773480664, 1.7515, 1.4163181818181818, 1.4292298850574712, 1.4520298507462688, 1.4897204301075269, 1.6330952380952382, 1.8262928571428572, 1.6101904761904762, 1.680929292929293, 2.881743119266055, 3.5851634615384613, 3.6891666666666665, 3.6573402777777777, 3.6435348837209305, 3.7148645833333336, 3.731375, 3.74479, 3.6362363636363635, 4.273113924050633, 3.4461999999999997, 3.5387142857142857, 3.7906065573770493, 3.5276750000000003, 3.4676712328767123, 3.5595, 3.7982, 5.460666666666667, 1.3094406779661016, 1.5357454545454545, 3.4238260869565216, 3.3823636363636367, 3.4006315789473684, 2.95075, 3.386731707317073, 2.506, 1.4471666666666667, 1.4425999999999999, 0.946, 0.9425789473684211, 0.9507142857142856, 0.947, 0.9762857142857143, 1.7862857142857143, 1.5135777777777777, 1.4995625, 1.338, 1.3278125, 1.2739175257731958, 1.4387457627118645, 1.2484186046511627, 1.2866693548387098, 1.2848934911242604, 1.2237952755905512, 0.74809375, 0.8717684210526315, 0.8445338983050847, 0.7916749999999999, 0.8041932773109244, 0.7303737373737375, 0.7055024390243902, 0.6872407407407407, 0.6909939759036144, 0.751, 0.765139344262295, 0.686871794871795, 0.6697434210526315, 1.7678091603053436, 0.7246764705882353, 0.7482772277227723, 0.9401142857142858, 0.750368, 1.3660232558139536, 0.7274137931034482, 0.710719512195122, 0.6898555555555557, 0.739453488372093, 0.817875, 0.7304303797468354, 0.7355890410958904, 0.738225806451613, 1.906921739130435, 2.290785714285714, 1.2075072463768115, 1.1675890410958905, 1.2290208333333332, 1.1923777777777778, 1.2088717948717949, 1.367715909090909, 1.284223300970874, 1.1631739130434782, 1.15253, 1.1614545454545455, 1.2195681818181818, 1.183752808988764, 1.197778947368421, 1.2338888888888888, 1.275070588235294, 1.235554054054054, 1.20783908045977, 1.2416184210526318, 1.159042735042735, 1.1382948717948718, 1.1069915966386554, 1.1714504504504506, 1.223822429906542, 1.1221696428571428, 1.018892857142857, 0.9818285714285714, 0.9988363636363636, 6.056572916666667, 7.225528846153845, 7.193834782608696, 7.507321100917431, 7.588695238095238, 7.678689189189189, 9.469633027522935, 10.236186046511628, 10.106608695652174, 9.989125, 9.948229357798166, 9.796030927835051, 9.704217391304349, 8.454028571428571, 6.813476190476191, 6.706782608695652, 6.523452173913043, 6.661553571428572, 5.620777777777778, 0.8123142857142857, 0.8095892857142857, 0.8664786324786324, 0.8778319327731092, 0.8108141592920354, 0.8157121212121212, 0.7706470588235294, 0.7633157894736842, 0.7815151515151515, 0.8075833333333333, 0.824743119266055, 0.8762151898734176, 0.882424, 0.7502213114754098, 0.675954954954955, 0.6371222222222223]), - DATA('Charging Station: 13,7 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, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, null, 0, 4.104142857142857, 5.829969696969697, 5.806212121212121, 6.195333333333333, 5.777333333333333, 5.78625, 5.789727272727273, 5.789571428571429, 5.783052631578948, 5.772657142857144, 4.864842105263158, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, null, null, 0, null, null, 0, 0, null, 0, 0, null, 0, 0, null, 0, 0, 0, 0, 0, 0, null, 0, null, null, 0, 0, null, null, 0, 0, 0, null, 0, null, null, 0, 0, null, 0, null, null, null, null, 0, null, 0, 0, null, null, null, null, null, 0, null, null, null, null, null, 0, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 0, 0, null, 0, null, 0, 0, 0, 0, 0, 0, null, null, 0, 0, null, 0, 0, 0, null, null, 0, 0, null, 0, 0, null, null, null, 0, null, null, null, null, null, null, 0, 0, 0, null, 0, 0, 0, 0, null, 0, null, 0, null, 0, 0, 0, null, 0, 0, 0, 0, 0, 5.213095238095239, 5.787580645161291, 5.7894848484848485, 5.790818181818182, 5.80734375, 5.820136363636364, 5.7988620689655175, 5.809041666666667, 5.8055625, 5.7943461538461545, 5.798, 5.740214285714285, 5.727242424242424, 5.742542857142857, 5.753424242424242, 5.7524, 5.731966666666667, 5.734323529411765, 5.335586206896552, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null]), - DATA('Whirlpool: 15,9 kWh', [0.12428571428571429, 0, null, 0, 0.17333333333333334, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.11, 0.11333333333333333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.11333333333333333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.11333333333333333, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.13, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.14, null, null, null, 2.126875, 0.175, 0.176, null, 0.18, 0.18, 0.185, 0.18, null, 0.185, 0.19, 0.18, 0.18, 0.17625, 0.17583333333333334, 0.17, 0.175, 0.17, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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('Sonstiger: 63,3 kWh', [null, null, null, 0.5658045977011494, 0.3871815181518151, 0.561425925925926, 0.5732169811320755, 0.5658080808080809, 0.5879803921568627, 0.5842389380530973, 0.6074818181818182, 0.6050275229357799, 0.5956407766990292, 0.6025294117647059, 0.5781684210526317, 0.5816813186813187, 0.6495166666666666, 0.5602999999999999, 0.56703738317757, 0.6297672413793104, 0.5688613861386138, 0.5896039603960396, 0.5245090909090909, 0.5093300330033004, 0.6177196261682243, 0.608122641509434, 0.60278, 0.6508155339805825, 0.6058877551020408, 0.5943904761904762, 0.57636, 0.5650660377358491, 0.587495145631068, 0.626375, 0.6819428571428572, 0.6504629629629629, 0.6313738317757009, 0.68725, 0.5602452830188679, 0.5278952380952382, 0.6202222222222221, 0.4016355140186916, 0.5878130841121496, 0.604, 0.616295918367347, 0.5789405940594059, 0.5943396226415094, 0.6481078431372549, null, null, null, 0.5652183908045977, 0.5736481481481481, 0.5365462962962964, 0.558081081081081, 0.5747543859649124, 0.5743557692307693, 0.5969047619047619, 0.6540720720720721, 0.5018766666666667, 0.6128045977011494, 0.6361100000000001, 0.6137948717948718, 0.5388857142857142, 0.5371157894736842, 0.5511634615384615, 0.5588809523809524, 0.5591222222222223, 0.6185576923076923, 0.6543287671232877, 0.6160574712643678, 0.5889056603773585, 0.5787096774193549, 0.583036036036036, 0.572570093457944, 0.5952631578947368, 0.7450888888888888, 0.7073990610328639, -1.452950549450549, 2.233161450571287, 1.1458434343434352, 1.2180771929824568, 0.9178416666666669, 0.9020510752688171, 1.3458171717171723, 1.1460410714285718, 0.9853455165691996, 1.189936077481839, -1.4153224202237875, 0.6774427860696518, 0.9827305699481865, 0.8582012987012987, 0.7678924050632912, 0.761950495049505, 0.6821319796954315, 0.5954198473282443, 0.7021286549707602, 0.7309484536082475, 0.739, 0.730572864321608, 0.7547467532467532, 0.657373417721519, 0.6409480519480519, 0.6698156424581005, 0.7876280991735537, 2.931229357798165, 1.9542808988764044, 0.7775346534653466, 1.098538860103627, 1.2441524390243903, 2.9194913793103447, 2.9874188034188034, 3.4140294117647056, 1.2151999999999998, 2.7142824427480914, 2.6578703703703703, 2.8738923076923077, 4.013462078651685, 3.791560606060606, 2.845578947368421, 1.7741875, 0.89646, 1.2468691588785048, 1.0760386740331491, 0.8393491124260355, 1.194960199004975, 1.0562878787878787, 3.133, 3.78845625, 1.288096153846154, 3.4541666666666666, 2.0936967871485943, 2.384391025641026, 1.6707888888888887, 1.5589767441860465, 2.8620799999999997, 2.3241241379310345, 1.9640169491525423, 1.8084, 3.4660503597122303, 2.2974397590361444, 2.5300493827160495, 2.439358490566038, 2.0079060773480664, 1.7515, 1.4163181818181818, 1.4292298850574712, 1.4520298507462688, 1.4897204301075269, 1.6330952380952382, 1.8262928571428572, 1.6101904761904762, 1.680929292929293, 2.881743119266055, 3.5851634615384613, 3.6891666666666665, 3.6573402777777777, 3.6435348837209305, 3.7148645833333336, 3.731375, 3.74479, 3.6362363636363635, 4.273113924050633, 3.4461999999999997, 3.5387142857142857, 3.7906065573770493, 3.5276750000000003, 3.4676712328767123, 3.5595, 3.7982, 5.460666666666667, 1.3094406779661016, 1.5357454545454545, 3.4238260869565216, 3.3823636363636367, 3.4006315789473684, 2.95075, 3.386731707317073, 2.506, 1.4471666666666667, 1.4425999999999999, 0.946, 0.9425789473684211, 0.9507142857142856, 0.947, 0.9762857142857143, 1.7862857142857143, 1.5135777777777777, 1.4995625, 1.338, 1.3278125, 1.2739175257731958, 1.4387457627118645, 1.2484186046511627, 1.2866693548387098, 1.2848934911242604, 1.2237952755905512, 0.74809375, 0.8717684210526315, 0.8445338983050847, 0.7916749999999999, 0.8041932773109244, 0.7303737373737375, 0.7055024390243902, 0.6872407407407407, 0.6909939759036144, 0.751, 0.765139344262295, 0.686871794871795, 0.6697434210526315, 1.7678091603053436, 0.7246764705882353, 0.7482772277227723, 0.9401142857142858, 0.750368, 1.3660232558139536, 0.7274137931034482, 0.710719512195122, 0.6898555555555557, 0.739453488372093, 0.817875, 0.7304303797468354, 0.7355890410958904, 0.738225806451613, 1.906921739130435, 2.290785714285714, 1.2075072463768115, 1.1675890410958905, 1.2290208333333332, 1.1923777777777778, 1.2088717948717949, 1.367715909090909, 1.284223300970874, 1.1631739130434782, 1.15253, 1.1614545454545455, 1.2195681818181818, 1.183752808988764, 1.197778947368421, 1.2338888888888888, 1.275070588235294, 1.235554054054054, 1.20783908045977, 1.2416184210526318, 1.159042735042735, 1.1382948717948718, 1.1069915966386554, 1.1714504504504506, 1.223822429906542, 1.1221696428571428, 1.018892857142857, 0.9818285714285714, 0.9988363636363636, 0.8434776785714284, 1.4379482009925546, 1.4043499341238475, 1.7165029190992493, 1.781351488095238, 1.8585528255528247, 3.6707709585574175, 4.427144379844961, 4.301046195652174, 4.194778846153845, 4.150229357798166, 4.055816642120766, 3.976974967061925, 2.711485714285714, 1.0600519480519486, 0.954382608695652, 0.7914855072463762, 0.9272300420168067, 0.28519157088122604, 0.8123142857142857, 0.8095892857142857, 0.8664786324786324, 0.8778319327731092, 0.8108141592920354, 0.8157121212121212, 0.7706470588235294, 0.7633157894736842, 0.7815151515151515, 0.8075833333333333, 0.824743119266055, 0.8762151898734176, 0.882424, 0.7502213114754098, 0.675954954954955, 0.6371222222222223]), + DATA("Gesamt: 93 kWh", [null, null, null, 0.5658045977011494, 0.5605148514851485, 0.561425925925926, 0.5732169811320755, 0.5658080808080809, 0.5879803921568627, 0.5842389380530973, 0.6074818181818182, 0.6050275229357799, 0.5956407766990292, 0.6025294117647059, 0.5781684210526317, 0.5816813186813187, 0.6495166666666666, 0.5602999999999999, 0.56703738317757, 0.6297672413793104, 0.5688613861386138, 0.5896039603960396, 0.6345090909090909, 0.6226633663366337, 0.6177196261682243, 0.608122641509434, 0.60278, 0.6508155339805825, 0.6058877551020408, 0.5943904761904762, 0.57636, 0.5650660377358491, 0.587495145631068, 0.626375, 0.6819428571428572, 0.6504629629629629, 0.6313738317757009, 0.68725, 0.5602452830188679, 0.5278952380952382, 0.6202222222222221, 0.5466355140186916, 0.5878130841121496, 0.604, 0.616295918367347, 0.5789405940594059, 0.5943396226415094, 0.6481078431372549, null, null, null, 0.5652183908045977, 0.5736481481481481, 0.5365462962962964, 0.558081081081081, 0.5747543859649124, 0.5743557692307693, 0.5969047619047619, 0.6540720720720721, 0.61521, 0.6128045977011494, 0.6361100000000001, 0.6137948717948718, 0.5388857142857142, 0.5371157894736842, 0.5511634615384615, 0.5588809523809524, 0.5591222222222223, 0.6185576923076923, 0.6543287671232877, 0.6160574712643678, 0.5889056603773585, 0.5787096774193549, 0.583036036036036, 0.572570093457944, 0.5952631578947368, 0.7450888888888888, 0.8207323943661972, 2.6511923076923076, 8.063131147540984, 6.952055555555556, 7.41341052631579, 6.695175, 6.688301075268817, 7.135544444444445, 6.9356125, 6.768398148148147, 6.962593220338983, 3.44951968503937, 0.6774427860696518, 0.9827305699481865, 0.8582012987012987, 0.7678924050632912, 0.761950495049505, 0.6821319796954315, 0.7254198473282443, 0.7021286549707602, 0.7309484536082475, 0.739, 0.730572864321608, 0.7547467532467532, 0.657373417721519, 0.6409480519480519, 0.6698156424581005, 0.7876280991735537, 2.931229357798165, 1.9542808988764044, 0.7775346534653466, 1.098538860103627, 1.2441524390243903, 2.9194913793103447, 2.9874188034188034, 3.4140294117647056, 1.3552, 2.7142824427480914, 2.6578703703703703, 2.8738923076923077, 6.140337078651685, 3.966560606060606, 3.0215789473684214, 1.7741875, 1.07646, 1.4268691588785047, 1.2610386740331492, 1.0193491124260354, 1.194960199004975, 1.2412878787878787, 3.323, 3.96845625, 1.4680961538461539, 3.6304166666666666, 2.2695301204819276, 2.554391025641026, 1.8457888888888887, 1.7289767441860464, 2.8620799999999997, 2.3241241379310345, 1.9640169491525423, 1.8084, 3.4660503597122303, 2.2974397590361444, 2.5300493827160495, 2.439358490566038, 2.0079060773480664, 1.7515, 1.4163181818181818, 1.4292298850574712, 1.4520298507462688, 1.4897204301075269, 1.6330952380952382, 1.8262928571428572, 1.6101904761904762, 1.680929292929293, 2.881743119266055, 3.5851634615384613, 3.6891666666666665, 3.6573402777777777, 3.6435348837209305, 3.7148645833333336, 3.731375, 3.74479, 3.6362363636363635, 4.273113924050633, 3.4461999999999997, 3.5387142857142857, 3.7906065573770493, 3.5276750000000003, 3.4676712328767123, 3.5595, 3.7982, 5.460666666666667, 1.3094406779661016, 1.5357454545454545, 3.4238260869565216, 3.3823636363636367, 3.4006315789473684, 2.95075, 3.386731707317073, 2.506, 1.4471666666666667, 1.4425999999999999, 0.946, 0.9425789473684211, 0.9507142857142856, 0.947, 0.9762857142857143, 1.7862857142857143, 1.5135777777777777, 1.4995625, 1.338, 1.3278125, 1.2739175257731958, 1.4387457627118645, 1.2484186046511627, 1.2866693548387098, 1.2848934911242604, 1.2237952755905512, 0.74809375, 0.8717684210526315, 0.8445338983050847, 0.7916749999999999, 0.8041932773109244, 0.7303737373737375, 0.7055024390243902, 0.6872407407407407, 0.6909939759036144, 0.751, 0.765139344262295, 0.686871794871795, 0.6697434210526315, 1.7678091603053436, 0.7246764705882353, 0.7482772277227723, 0.9401142857142858, 0.750368, 1.3660232558139536, 0.7274137931034482, 0.710719512195122, 0.6898555555555557, 0.739453488372093, 0.817875, 0.7304303797468354, 0.7355890410958904, 0.738225806451613, 1.906921739130435, 2.290785714285714, 1.2075072463768115, 1.1675890410958905, 1.2290208333333332, 1.1923777777777778, 1.2088717948717949, 1.367715909090909, 1.284223300970874, 1.1631739130434782, 1.15253, 1.1614545454545455, 1.2195681818181818, 1.183752808988764, 1.197778947368421, 1.2338888888888888, 1.275070588235294, 1.235554054054054, 1.20783908045977, 1.2416184210526318, 1.159042735042735, 1.1382948717948718, 1.1069915966386554, 1.1714504504504506, 1.223822429906542, 1.1221696428571428, 1.018892857142857, 0.9818285714285714, 0.9988363636363636, 6.056572916666667, 7.225528846153845, 7.193834782608696, 7.507321100917431, 7.588695238095238, 7.678689189189189, 9.469633027522935, 10.236186046511628, 10.106608695652174, 9.989125, 9.948229357798166, 9.796030927835051, 9.704217391304349, 8.454028571428571, 6.813476190476191, 6.706782608695652, 6.523452173913043, 6.661553571428572, 5.620777777777778, 0.8123142857142857, 0.8095892857142857, 0.8664786324786324, 0.8778319327731092, 0.8108141592920354, 0.8157121212121212, 0.7706470588235294, 0.7633157894736842, 0.7815151515151515, 0.8075833333333333, 0.824743119266055, 0.8762151898734176, 0.882424, 0.7502213114754098, 0.675954954954955, 0.6371222222222223]), + DATA("Charging Station: 13,7 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, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, null, 0, 4.104142857142857, 5.829969696969697, 5.806212121212121, 6.195333333333333, 5.777333333333333, 5.78625, 5.789727272727273, 5.789571428571429, 5.783052631578948, 5.772657142857144, 4.864842105263158, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, null, null, 0, null, null, 0, 0, null, 0, 0, null, 0, 0, null, 0, 0, 0, 0, 0, 0, null, 0, null, null, 0, 0, null, null, 0, 0, 0, null, 0, null, null, 0, 0, null, 0, null, null, null, null, 0, null, 0, 0, null, null, null, null, null, 0, null, null, null, null, null, 0, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 0, 0, null, 0, null, 0, 0, 0, 0, 0, 0, null, null, 0, 0, null, 0, 0, 0, null, null, 0, 0, null, 0, 0, null, null, null, 0, null, null, null, null, null, null, 0, 0, 0, null, 0, 0, 0, 0, null, 0, null, 0, null, 0, 0, 0, null, 0, 0, 0, 0, 0, 5.213095238095239, 5.787580645161291, 5.7894848484848485, 5.790818181818182, 5.80734375, 5.820136363636364, 5.7988620689655175, 5.809041666666667, 5.8055625, 5.7943461538461545, 5.798, 5.740214285714285, 5.727242424242424, 5.742542857142857, 5.753424242424242, 5.7524, 5.731966666666667, 5.734323529411765, 5.335586206896552, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null]), + DATA("Whirlpool: 15,9 kWh", [0.12428571428571429, 0, null, 0, 0.17333333333333334, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.11, 0.11333333333333333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.11333333333333333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.11333333333333333, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.13, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.14, null, null, null, 2.126875, 0.175, 0.176, null, 0.18, 0.18, 0.185, 0.18, null, 0.185, 0.19, 0.18, 0.18, 0.17625, 0.17583333333333334, 0.17, 0.175, 0.17, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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("Sonstiger: 63,3 kWh", [null, null, null, 0.5658045977011494, 0.3871815181518151, 0.561425925925926, 0.5732169811320755, 0.5658080808080809, 0.5879803921568627, 0.5842389380530973, 0.6074818181818182, 0.6050275229357799, 0.5956407766990292, 0.6025294117647059, 0.5781684210526317, 0.5816813186813187, 0.6495166666666666, 0.5602999999999999, 0.56703738317757, 0.6297672413793104, 0.5688613861386138, 0.5896039603960396, 0.5245090909090909, 0.5093300330033004, 0.6177196261682243, 0.608122641509434, 0.60278, 0.6508155339805825, 0.6058877551020408, 0.5943904761904762, 0.57636, 0.5650660377358491, 0.587495145631068, 0.626375, 0.6819428571428572, 0.6504629629629629, 0.6313738317757009, 0.68725, 0.5602452830188679, 0.5278952380952382, 0.6202222222222221, 0.4016355140186916, 0.5878130841121496, 0.604, 0.616295918367347, 0.5789405940594059, 0.5943396226415094, 0.6481078431372549, null, null, null, 0.5652183908045977, 0.5736481481481481, 0.5365462962962964, 0.558081081081081, 0.5747543859649124, 0.5743557692307693, 0.5969047619047619, 0.6540720720720721, 0.5018766666666667, 0.6128045977011494, 0.6361100000000001, 0.6137948717948718, 0.5388857142857142, 0.5371157894736842, 0.5511634615384615, 0.5588809523809524, 0.5591222222222223, 0.6185576923076923, 0.6543287671232877, 0.6160574712643678, 0.5889056603773585, 0.5787096774193549, 0.583036036036036, 0.572570093457944, 0.5952631578947368, 0.7450888888888888, 0.7073990610328639, -1.452950549450549, 2.233161450571287, 1.1458434343434352, 1.2180771929824568, 0.9178416666666669, 0.9020510752688171, 1.3458171717171723, 1.1460410714285718, 0.9853455165691996, 1.189936077481839, -1.4153224202237875, 0.6774427860696518, 0.9827305699481865, 0.8582012987012987, 0.7678924050632912, 0.761950495049505, 0.6821319796954315, 0.5954198473282443, 0.7021286549707602, 0.7309484536082475, 0.739, 0.730572864321608, 0.7547467532467532, 0.657373417721519, 0.6409480519480519, 0.6698156424581005, 0.7876280991735537, 2.931229357798165, 1.9542808988764044, 0.7775346534653466, 1.098538860103627, 1.2441524390243903, 2.9194913793103447, 2.9874188034188034, 3.4140294117647056, 1.2151999999999998, 2.7142824427480914, 2.6578703703703703, 2.8738923076923077, 4.013462078651685, 3.791560606060606, 2.845578947368421, 1.7741875, 0.89646, 1.2468691588785048, 1.0760386740331491, 0.8393491124260355, 1.194960199004975, 1.0562878787878787, 3.133, 3.78845625, 1.288096153846154, 3.4541666666666666, 2.0936967871485943, 2.384391025641026, 1.6707888888888887, 1.5589767441860465, 2.8620799999999997, 2.3241241379310345, 1.9640169491525423, 1.8084, 3.4660503597122303, 2.2974397590361444, 2.5300493827160495, 2.439358490566038, 2.0079060773480664, 1.7515, 1.4163181818181818, 1.4292298850574712, 1.4520298507462688, 1.4897204301075269, 1.6330952380952382, 1.8262928571428572, 1.6101904761904762, 1.680929292929293, 2.881743119266055, 3.5851634615384613, 3.6891666666666665, 3.6573402777777777, 3.6435348837209305, 3.7148645833333336, 3.731375, 3.74479, 3.6362363636363635, 4.273113924050633, 3.4461999999999997, 3.5387142857142857, 3.7906065573770493, 3.5276750000000003, 3.4676712328767123, 3.5595, 3.7982, 5.460666666666667, 1.3094406779661016, 1.5357454545454545, 3.4238260869565216, 3.3823636363636367, 3.4006315789473684, 2.95075, 3.386731707317073, 2.506, 1.4471666666666667, 1.4425999999999999, 0.946, 0.9425789473684211, 0.9507142857142856, 0.947, 0.9762857142857143, 1.7862857142857143, 1.5135777777777777, 1.4995625, 1.338, 1.3278125, 1.2739175257731958, 1.4387457627118645, 1.2484186046511627, 1.2866693548387098, 1.2848934911242604, 1.2237952755905512, 0.74809375, 0.8717684210526315, 0.8445338983050847, 0.7916749999999999, 0.8041932773109244, 0.7303737373737375, 0.7055024390243902, 0.6872407407407407, 0.6909939759036144, 0.751, 0.765139344262295, 0.686871794871795, 0.6697434210526315, 1.7678091603053436, 0.7246764705882353, 0.7482772277227723, 0.9401142857142858, 0.750368, 1.3660232558139536, 0.7274137931034482, 0.710719512195122, 0.6898555555555557, 0.739453488372093, 0.817875, 0.7304303797468354, 0.7355890410958904, 0.738225806451613, 1.906921739130435, 2.290785714285714, 1.2075072463768115, 1.1675890410958905, 1.2290208333333332, 1.1923777777777778, 1.2088717948717949, 1.367715909090909, 1.284223300970874, 1.1631739130434782, 1.15253, 1.1614545454545455, 1.2195681818181818, 1.183752808988764, 1.197778947368421, 1.2338888888888888, 1.275070588235294, 1.235554054054054, 1.20783908045977, 1.2416184210526318, 1.159042735042735, 1.1382948717948718, 1.1069915966386554, 1.1714504504504506, 1.223822429906542, 1.1221696428571428, 1.018892857142857, 0.9818285714285714, 0.9988363636363636, 0.8434776785714284, 1.4379482009925546, 1.4043499341238475, 1.7165029190992493, 1.781351488095238, 1.8585528255528247, 3.6707709585574175, 4.427144379844961, 4.301046195652174, 4.194778846153845, 4.150229357798166, 4.055816642120766, 3.976974967061925, 2.711485714285714, 1.0600519480519486, 0.954382608695652, 0.7914855072463762, 0.9272300420168067, 0.28519157088122604, 0.8123142857142857, 0.8095892857142857, 0.8664786324786324, 0.8778319327731092, 0.8108141592920354, 0.8157121212121212, 0.7706470588235294, 0.7633157894736842, 0.7815151515151515, 0.8075833333333333, 0.824743119266055, 0.8762151898734176, 0.882424, 0.7502213114754098, 0.675954954954955, 0.6371222222222223]), ], labels: LABELS(History.DAY.dataChannelWithValues.result.timestamps), - options: OeTester.ChartOptions.LINE_CHART_OPTIONS('hour', 'line', {}, + options: OeTester.ChartOptions.LINE_CHART_OPTIONS("hour", "line", {}, ), }, }); @@ -40,51 +40,51 @@ describe('History Consumption', () => { { // Line-Chart, no phases, no phasecolors - expectView(defaultEMS, TEST_CONTEXT, 'line', History.WEEK, + expectView(defaultEMS, TEST_CONTEXT, "line", History.WEEK, { datasets: { data: [ - DATA('Gesamt: 354,1 kWh', [0.6639876181166504, 0.9375188284518828, 0.7615839462743844, 0.5997653758542141, 0.9896435035552682, 0.6662890016920473, 1.054177495462795, 1.0429070871481858, 0.6611515631183221, 0.7342340980187696, 0.8455174603174603, 0.9695830886670582, 0.5918473777253977, 1.9600339449541284, 0.9197469512195122, 1.2326632911392406, 0.5629648946840522, 0.7862627471383975, 0.9314229323308271, 0.837381753312946, 1.112301018483591, 0.9025108194395176, 0.8075094273743018, 0.988311229946524, 0.6140189035916823, 0.8686555377207063, 0.9069389035667107, 0.6733970826580227, 0.8276491228070175, 0.8519108776685869, 0.8529105374823197, 0.8674681647940076, 1.3030172261484099, 0.9506813929313929, 1.1247157794676808, 0.9087814790139906, 1.5545020215633425, 4.743944086021505, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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('Charging Station: 157 kWh', [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4.586923076923077, 4.8462192982456145, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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('Whirlpool: 100 kWh', [0.027956773446545735, 0.02793238434163701, 0.028003065134099617, 0.02795220588235294, 0.027998854961832062, 0.028116988416988415, 0.027987117552334944, 0.028404306220095696, 0.02210508757297748, 0.02458289572393098, 0.025521831735889244, 0.03394027565084227, 0.06640016920473774, 0.07485995085995086, 0.05630216802168022, 0.040562390158172236, 0.042727272727272725, 0.04185823488533704, 0.02956647864625302, 0.02693582887700535, 0.029227223427331885, 0.031081920903954802, 0.02950079575596817, 0.02929895178197065, 0.02774064837905237, 0.027340638930163447, 0.027272103350827612, 0.027199391171993912, 0.02697577592732778, 0.02688116057233704, 0.02704352806414662, 0.026709154929577466, 0.024765209940017137, 0.020726594301221167, 0.024283930058284765, 0.027086363636363638, 0.04770666666666666, 0.05307067510548523, 0.05273466476462197, 0.054757768924302785, 0.05023135033050047, 0.041280141843971635, 0.03150934119960669, 0.026471978392977717, 0.031050412465627866, 0.029384710234278667, 0.02795327604726101, 0.028357904496986556, 0.025564085881587508, null, 0.026944094488188977, 0.027036082474226807, 0.026367164179104476, 0.025185562632696393, 0.026994444444444442, 0.025911782850092536, 0.01343197071384991, 0.024309846431797653, 0.02523471223021583, 0.026126705653021443, 0.06064339781328848, 0.03996433289299867, 0.037667578659370725, 0.050665427509293676, 0.04189218523878437, 0.02988109495295124, 0.02693968253968254, 0.025741935483870968, 0.028640000000000002, 0.031331460674157305, 0.030017262638717634, 0.028636402753872633, 0.028408956692913385, 0.02814567233384853, 0.02825509028044564, 0.028126129666011787, 0.028175675675675676, 0.027409126063418405, 0.027549439844130538, 0.027246363209760677, 0.02296663244353183, 0.02165732959850607, 0.022306306306306308, 0.025892307692307694, 0.0518, 0.05290322580645162, 0.05902597402597402, 0.03935110294117647, 0.03387375113533152, 0.02998160073597056, 0.0264819734345351, 0.029473684210526315, 0.028432854465958775, 0.029162214983713356, 0.028663861386138613, 0.02823558082859464, 0.028460033305578683, 0.029076231430805316, 0.028803389830508477, 0.02862062404870624, 0.028578023655093474, 0.02837057010785824, 0.02746546431312356, 0.027873293515358364, 0.025733505154639177, 0.02635780287474333, 0.027692853246044733, 0.024205128205128205, null, 0.026746031746031747, 0.023178571428571427, 0.026168618266978923, 0.028333646616541353, 0.026758232235701906, 0.023993934142114384, 0.02471902131018153, 0.02823051948051948, 0.028745721271393642, 0.028485825458588104, 0.02822232263895165, 0.028392755392755393, 0.028338354151359293, 0.027164207340143777, 0.02694932432432432, 0.026942610652663165, 0.027809220389805097, 0.027980593607305936, 0.02826596758817922, 0.029656794425087108, 0.025145056246299584, 0.02520321410057024, 0.02882728749323227, 0.03222576966932725, 0.031200444197667963, 0.030594259988745078, 0.04334990059642147, 0.04615876288659794, 0.03340802469135802, 0.027489320388349517, 0.025818808777429467, 0.02795967741935484, 0.028969951391957578, 0.027549955791335103, 0.02834137055837563, 0.028250760538896132, 0.027812838360402166, 0.02810333080999243, 0.027840314136125657, 0.027800384615384616, 0.027979583975346688, 0.027235769230769234, 0.026924960505529224, 0.029038479809976248, 0.02793128390596745, 0.03410349373764008, 0.0327387339055794, 0.029509929906542054, 0.03700855745721272, 0.03224008574490889, 0.02770136363636364, 0.030787037037037036, 0.025786028602860285, 0.029997148966500357, 0.03289406099518459, 0.03532872928176795, 0.025655647382920112, 0.02746238030095759, 0.02827226647356988]), - DATA('Sonstiger: 97,1 kWh', [0.6360308446701046, 0.9095864441102458, 0.7335808811402847, 0.5718131699718612, 0.9616446485934361, 0.6381720132750589, 1.02619037791046, 1.0145027809280902, 0.6390464755453447, 0.7096512022948386, 0.819995628581571, 0.935642813016216, 0.5254472085206601, 1.8851739940941776, 0.863444783197832, 1.1921009009810684, 0.5202376219567795, 0.7444045122530605, 0.901856453684574, 0.8104459244359407, 1.0830737950562592, 0.8714288985355628, 0.7780086316183336, 0.9590122781645534, 0.58627825521263, 0.8413148987905428, 0.8796668002158831, 0.6461976914860288, 0.8006733468796897, 0.8250297170962498, 0.825867009418173, 0.8407590098644301, 1.2782520162083928, 0.9299547986301717, 1.100431849409396, 0.881695115377627, -3.0801277220264014, 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]), + DATA("Gesamt: 354,1 kWh", [0.6639876181166504, 0.9375188284518828, 0.7615839462743844, 0.5997653758542141, 0.9896435035552682, 0.6662890016920473, 1.054177495462795, 1.0429070871481858, 0.6611515631183221, 0.7342340980187696, 0.8455174603174603, 0.9695830886670582, 0.5918473777253977, 1.9600339449541284, 0.9197469512195122, 1.2326632911392406, 0.5629648946840522, 0.7862627471383975, 0.9314229323308271, 0.837381753312946, 1.112301018483591, 0.9025108194395176, 0.8075094273743018, 0.988311229946524, 0.6140189035916823, 0.8686555377207063, 0.9069389035667107, 0.6733970826580227, 0.8276491228070175, 0.8519108776685869, 0.8529105374823197, 0.8674681647940076, 1.3030172261484099, 0.9506813929313929, 1.1247157794676808, 0.9087814790139906, 1.5545020215633425, 4.743944086021505, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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("Charging Station: 157 kWh", [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4.586923076923077, 4.8462192982456145, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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("Whirlpool: 100 kWh", [0.027956773446545735, 0.02793238434163701, 0.028003065134099617, 0.02795220588235294, 0.027998854961832062, 0.028116988416988415, 0.027987117552334944, 0.028404306220095696, 0.02210508757297748, 0.02458289572393098, 0.025521831735889244, 0.03394027565084227, 0.06640016920473774, 0.07485995085995086, 0.05630216802168022, 0.040562390158172236, 0.042727272727272725, 0.04185823488533704, 0.02956647864625302, 0.02693582887700535, 0.029227223427331885, 0.031081920903954802, 0.02950079575596817, 0.02929895178197065, 0.02774064837905237, 0.027340638930163447, 0.027272103350827612, 0.027199391171993912, 0.02697577592732778, 0.02688116057233704, 0.02704352806414662, 0.026709154929577466, 0.024765209940017137, 0.020726594301221167, 0.024283930058284765, 0.027086363636363638, 0.04770666666666666, 0.05307067510548523, 0.05273466476462197, 0.054757768924302785, 0.05023135033050047, 0.041280141843971635, 0.03150934119960669, 0.026471978392977717, 0.031050412465627866, 0.029384710234278667, 0.02795327604726101, 0.028357904496986556, 0.025564085881587508, null, 0.026944094488188977, 0.027036082474226807, 0.026367164179104476, 0.025185562632696393, 0.026994444444444442, 0.025911782850092536, 0.01343197071384991, 0.024309846431797653, 0.02523471223021583, 0.026126705653021443, 0.06064339781328848, 0.03996433289299867, 0.037667578659370725, 0.050665427509293676, 0.04189218523878437, 0.02988109495295124, 0.02693968253968254, 0.025741935483870968, 0.028640000000000002, 0.031331460674157305, 0.030017262638717634, 0.028636402753872633, 0.028408956692913385, 0.02814567233384853, 0.02825509028044564, 0.028126129666011787, 0.028175675675675676, 0.027409126063418405, 0.027549439844130538, 0.027246363209760677, 0.02296663244353183, 0.02165732959850607, 0.022306306306306308, 0.025892307692307694, 0.0518, 0.05290322580645162, 0.05902597402597402, 0.03935110294117647, 0.03387375113533152, 0.02998160073597056, 0.0264819734345351, 0.029473684210526315, 0.028432854465958775, 0.029162214983713356, 0.028663861386138613, 0.02823558082859464, 0.028460033305578683, 0.029076231430805316, 0.028803389830508477, 0.02862062404870624, 0.028578023655093474, 0.02837057010785824, 0.02746546431312356, 0.027873293515358364, 0.025733505154639177, 0.02635780287474333, 0.027692853246044733, 0.024205128205128205, null, 0.026746031746031747, 0.023178571428571427, 0.026168618266978923, 0.028333646616541353, 0.026758232235701906, 0.023993934142114384, 0.02471902131018153, 0.02823051948051948, 0.028745721271393642, 0.028485825458588104, 0.02822232263895165, 0.028392755392755393, 0.028338354151359293, 0.027164207340143777, 0.02694932432432432, 0.026942610652663165, 0.027809220389805097, 0.027980593607305936, 0.02826596758817922, 0.029656794425087108, 0.025145056246299584, 0.02520321410057024, 0.02882728749323227, 0.03222576966932725, 0.031200444197667963, 0.030594259988745078, 0.04334990059642147, 0.04615876288659794, 0.03340802469135802, 0.027489320388349517, 0.025818808777429467, 0.02795967741935484, 0.028969951391957578, 0.027549955791335103, 0.02834137055837563, 0.028250760538896132, 0.027812838360402166, 0.02810333080999243, 0.027840314136125657, 0.027800384615384616, 0.027979583975346688, 0.027235769230769234, 0.026924960505529224, 0.029038479809976248, 0.02793128390596745, 0.03410349373764008, 0.0327387339055794, 0.029509929906542054, 0.03700855745721272, 0.03224008574490889, 0.02770136363636364, 0.030787037037037036, 0.025786028602860285, 0.029997148966500357, 0.03289406099518459, 0.03532872928176795, 0.025655647382920112, 0.02746238030095759, 0.02827226647356988]), + DATA("Sonstiger: 97,1 kWh", [0.6360308446701046, 0.9095864441102458, 0.7335808811402847, 0.5718131699718612, 0.9616446485934361, 0.6381720132750589, 1.02619037791046, 1.0145027809280902, 0.6390464755453447, 0.7096512022948386, 0.819995628581571, 0.935642813016216, 0.5254472085206601, 1.8851739940941776, 0.863444783197832, 1.1921009009810684, 0.5202376219567795, 0.7444045122530605, 0.901856453684574, 0.8104459244359407, 1.0830737950562592, 0.8714288985355628, 0.7780086316183336, 0.9590122781645534, 0.58627825521263, 0.8413148987905428, 0.8796668002158831, 0.6461976914860288, 0.8006733468796897, 0.8250297170962498, 0.825867009418173, 0.8407590098644301, 1.2782520162083928, 0.9299547986301717, 1.100431849409396, 0.881695115377627, -3.0801277220264014, 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]), ], labels: LABELS(History.WEEK.dataChannelWithValues.result.timestamps), - options: OeTester.ChartOptions.LINE_CHART_OPTIONS('day', 'line', {}), + options: OeTester.ChartOptions.LINE_CHART_OPTIONS("day", "line", {}), }, }); } { // Bar-Chart, no phases, no phasecolors - expectView(defaultEMS, TEST_CONTEXT, 'bar', History.MONTH, + expectView(defaultEMS, TEST_CONTEXT, "bar", History.MONTH, { datasets: { data: [ - DATA('Gesamt: 1.033,4 kWh', [1.7843478512581188, 0.9551978135997077, 1.6049176251387696, 1.8215474663613151, 1.2040116271893009, 1.037408900359932, 1.287891020875591, 1.1830577354221141, 1.0278784377276404, 1.4127831967543791, 0.7372379614126091, 0.7306143394985477, 1.7274568452231196, 2.04548274638676, 1.289986737393844, 1.8665731598778827, 0.896448259060122, 1.2710485678635468, 1.4897323302960577, 1.3679696489029907, 2.3756092366846033, 2.3687291028362236, 2.68660326649514, 1.5970390753045414, 0.9726650191463931, 1.7742336901685731, 2.953838257099637, 0.9173087792235759, 1.1729800154902883, null, null]), - DATA('Charging Station: 328,5 kWh', [0.598058461158158, 0, 0.6073861225965935, 0.8913491768679577, 0.2696236843407865, 0, 0.30641009901340227, 0.2205140720984315, 0.05015525733301707, 0.35642246970726826, 0, 0, 0.8800942036863182, 0.9774033026217929, 0.21023831546417276, 0.7870712558876392, 0, 0.16550743075023164, 0.5132605942604259, 0.14906825174512017, 0.8836100586172083, 1.2031171015303659, 1.4672314708234808, 0.5536230686820822, 0, 0.7148486366912177, 1.8367765179313804, 0, 0.300374916784946, null, null]), - DATA('Whirlpool: 21,6 kWh', [0.01553700680772126, 0.01397856617670663, 0.01622420643945345, 0.01542515500397099, 0.01641557086346929, 0.015280936198647838, 0.015028196655704793, 0.015146427851947055, 0.015567356482244768, 0.017404197969735604, 0.017635152684968115, 0.014140394156739467, 0.016107488806188935, 0.01675001277671301, 0.015512752420609467, 0.014951999780788457, 0.013733457057782297, 0.016868671206682027, 0.014770978996449592, 0.01647697124898351, 0.016772182319685667, 0.016288562161254704, 0.015417362341926746, 0.015892028990939402, 0.013811584043067414, 0.01481782772305683, 0.014165639305307825, 0.016223347257543284, 0.014495672387672808, null, null]), - DATA('Sonstiger: 683,3 kWh', [1.1707523832922395, 0.941219247423001, 0.9813072961027226, 0.9147731344893865, 0.9179723719850451, 1.0221279641612842, 0.9664527252064838, 0.9473972354717356, 0.9621558239123786, 1.0389565290773752, 0.719602808727641, 0.7164739453418082, 0.8312551527306125, 1.0513294309882544, 1.0642356695090618, 1.0645499042094553, 0.8827148020023398, 1.0886724659066331, 0.9617007570391821, 1.202424425908887, 1.4752269957477093, 1.149323439144603, 1.2039544333297325, 1.0275239776315197, 0.9588534351033258, 1.0445672257542986, 1.1028960998629487, 0.9010854319660326, 0.8581094263176695, null, null]), + DATA("Gesamt: 1.033,4 kWh", [1.7843478512581188, 0.9551978135997077, 1.6049176251387696, 1.8215474663613151, 1.2040116271893009, 1.037408900359932, 1.287891020875591, 1.1830577354221141, 1.0278784377276404, 1.4127831967543791, 0.7372379614126091, 0.7306143394985477, 1.7274568452231196, 2.04548274638676, 1.289986737393844, 1.8665731598778827, 0.896448259060122, 1.2710485678635468, 1.4897323302960577, 1.3679696489029907, 2.3756092366846033, 2.3687291028362236, 2.68660326649514, 1.5970390753045414, 0.9726650191463931, 1.7742336901685731, 2.953838257099637, 0.9173087792235759, 1.1729800154902883, null, null]), + DATA("Charging Station: 328,5 kWh", [0.598058461158158, 0, 0.6073861225965935, 0.8913491768679577, 0.2696236843407865, 0, 0.30641009901340227, 0.2205140720984315, 0.05015525733301707, 0.35642246970726826, 0, 0, 0.8800942036863182, 0.9774033026217929, 0.21023831546417276, 0.7870712558876392, 0, 0.16550743075023164, 0.5132605942604259, 0.14906825174512017, 0.8836100586172083, 1.2031171015303659, 1.4672314708234808, 0.5536230686820822, 0, 0.7148486366912177, 1.8367765179313804, 0, 0.300374916784946, null, null]), + DATA("Whirlpool: 21,6 kWh", [0.01553700680772126, 0.01397856617670663, 0.01622420643945345, 0.01542515500397099, 0.01641557086346929, 0.015280936198647838, 0.015028196655704793, 0.015146427851947055, 0.015567356482244768, 0.017404197969735604, 0.017635152684968115, 0.014140394156739467, 0.016107488806188935, 0.01675001277671301, 0.015512752420609467, 0.014951999780788457, 0.013733457057782297, 0.016868671206682027, 0.014770978996449592, 0.01647697124898351, 0.016772182319685667, 0.016288562161254704, 0.015417362341926746, 0.015892028990939402, 0.013811584043067414, 0.01481782772305683, 0.014165639305307825, 0.016223347257543284, 0.014495672387672808, null, null]), + DATA("Sonstiger: 683,3 kWh", [1.1707523832922395, 0.941219247423001, 0.9813072961027226, 0.9147731344893865, 0.9179723719850451, 1.0221279641612842, 0.9664527252064838, 0.9473972354717356, 0.9621558239123786, 1.0389565290773752, 0.719602808727641, 0.7164739453418082, 0.8312551527306125, 1.0513294309882544, 1.0642356695090618, 1.0645499042094553, 0.8827148020023398, 1.0886724659066331, 0.9617007570391821, 1.202424425908887, 1.4752269957477093, 1.149323439144603, 1.2039544333297325, 1.0275239776315197, 0.9588534351033258, 1.0445672257542986, 1.1028960998629487, 0.9010854319660326, 0.8581094263176695, null, null]), ], labels: LABELS(History.MONTH.energyPerPeriodChannelWithValues.result.timestamps), - options: OeTester.ChartOptions.BAR_CHART_OPTIONS('day', 'bar', {}), + options: OeTester.ChartOptions.BAR_CHART_OPTIONS("day", "bar", {}), }, }); } { // Bar-Chart, phases - expectView(defaultEMS, TEST_CONTEXT, 'bar', History.YEAR, + expectView(defaultEMS, TEST_CONTEXT, "bar", History.YEAR, { datasets: { data: [ - DATA('Gesamt: 14.863,7 kWh', [1682.941, 1834.729, 1805.222, 1934.144, 1757.577, 1511.352, 2306.988, 2029.933, 0, 0, 0, 0]), - DATA('Charging Station: 2.071,1 kWh', [69.104, 131.703, 25.773, 51.085, 169.943, 332.522, 748.189, 540.74, 0, 0, 0, 0]), - DATA('Whirlpool: 1.908,7 kWh', [338.07, 312.38, 298.93, 317.7, 200.21, 151.16, 145.88, 144.28, 0, 0, 0, 0]), - DATA('Sonstiger: 10.883,9 kWh', [1275.767, 1390.6460000000002, 1480.519, 1565.359, 1387.424, 1027.67, 1412.9189999999999, 1344.913, 0, 0, 0, 0]), + DATA("Gesamt: 14.863,7 kWh", [1682.941, 1834.729, 1805.222, 1934.144, 1757.577, 1511.352, 2306.988, 2029.933, 0, 0, 0, 0]), + DATA("Charging Station: 2.071,1 kWh", [69.104, 131.703, 25.773, 51.085, 169.943, 332.522, 748.189, 540.74, 0, 0, 0, 0]), + DATA("Whirlpool: 1.908,7 kWh", [338.07, 312.38, 298.93, 317.7, 200.21, 151.16, 145.88, 144.28, 0, 0, 0, 0]), + DATA("Sonstiger: 10.883,9 kWh", [1275.767, 1390.6460000000002, 1480.519, 1565.359, 1387.424, 1027.67, 1412.9189999999999, 1344.913, 0, 0, 0, 0]), ], labels: LABELS(History.YEAR.energyPerPeriodChannelWithValues.result.timestamps), - options: OeTester.ChartOptions.BAR_CHART_OPTIONS('month', 'bar', {}), + options: OeTester.ChartOptions.BAR_CHART_OPTIONS("month", "bar", {}), }, }); } diff --git a/ui/src/app/edge/history/common/consumption/chart/chart.ts b/ui/src/app/edge/history/common/consumption/chart/chart.ts index 2c5f3b436bb..bc5474bde75 100644 --- a/ui/src/app/edge/history/common/consumption/chart/chart.ts +++ b/ui/src/app/edge/history/common/consumption/chart/chart.ts @@ -1,47 +1,47 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { TranslateService } from '@ngx-translate/core'; -import { AbstractHistoryChart } from 'src/app/shared/components/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'; +import { Component } from "@angular/core"; +import { TranslateService } from "@ngx-translate/core"; +import { AbstractHistoryChart } from "src/app/shared/components/chart/abstracthistorychart"; +import { QueryHistoricTimeseriesEnergyResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse"; +import { ChartAxis, HistoryUtils, YAxisType } from "src/app/shared/service/utils"; +import { ChannelAddress, EdgeConfig, Utils } from "src/app/shared/shared"; @Component({ - selector: 'consumptionchart', - templateUrl: '../../../../../shared/components/chart/abstracthistorychart.html', + selector: "consumptionchart", + templateUrl: "../../../../../shared/components/chart/abstracthistorychart.html", }) export class ChartComponent extends AbstractHistoryChart { public static getChartData(config: EdgeConfig, translate: TranslateService): HistoryUtils.ChartData { const inputChannel: HistoryUtils.InputChannel[] = [{ - name: 'ConsumptionActivePower', - powerChannel: ChannelAddress.fromString('_sum/ConsumptionActivePower'), - energyChannel: ChannelAddress.fromString('_sum/ConsumptionActiveEnergy'), + name: "ConsumptionActivePower", + powerChannel: ChannelAddress.fromString("_sum/ConsumptionActivePower"), + energyChannel: ChannelAddress.fromString("_sum/ConsumptionActiveEnergy"), }]; const evcsComponents: EdgeConfig.Component[] = config.getComponentsImplementingNature("io.openems.edge.evcs.api.Evcs") .filter(component => !( - component.factoryId == 'Evcs.Cluster' || - component.factoryId == 'Evcs.Cluster.PeakShaving' || - component.factoryId == 'Evcs.Cluster.SelfConsumption')); + component.factoryId == "Evcs.Cluster" || + component.factoryId == "Evcs.Cluster.PeakShaving" || + component.factoryId == "Evcs.Cluster.SelfConsumption")); const consumptionMeters: EdgeConfig.Component[] = config.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") .filter(component => component.isEnabled && config.isTypeConsumptionMetered(component)); evcsComponents.forEach(component => { inputChannel.push({ - name: component.id + '/ChargePower', - powerChannel: ChannelAddress.fromString(component.id + '/ChargePower'), - energyChannel: ChannelAddress.fromString(component.id + '/ActiveConsumptionEnergy'), + name: component.id + "/ChargePower", + powerChannel: ChannelAddress.fromString(component.id + "/ChargePower"), + energyChannel: ChannelAddress.fromString(component.id + "/ActiveConsumptionEnergy"), }); }); consumptionMeters.forEach(meter => { inputChannel.push({ - name: meter.id + '/ActivePower', - powerChannel: ChannelAddress.fromString(meter.id + '/ActivePower'), - energyChannel: ChannelAddress.fromString(meter.id + '/ActiveProductionEnergy'), + name: meter.id + "/ActivePower", + powerChannel: ChannelAddress.fromString(meter.id + "/ActivePower"), + energyChannel: ChannelAddress.fromString(meter.id + "/ActiveProductionEnergy"), }); }); @@ -53,41 +53,41 @@ export class ChartComponent extends AbstractHistoryChart { output: (data: HistoryUtils.ChannelData) => { const datasets: HistoryUtils.DisplayValue[] = []; datasets.push({ - name: translate.instant('General.TOTAL'), + name: translate.instant("General.TOTAL"), nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => { - return energyValues?.result.data['_sum/ConsumptionActiveEnergy']; + return energyValues?.result.data["_sum/ConsumptionActiveEnergy"]; }, converter: () => { - return data['ConsumptionActivePower'] ?? null; + return data["ConsumptionActivePower"] ?? null; }, - color: 'rgb(253,197,7)', + color: "rgb(253,197,7)", stack: 0, }); - const evcsComponentColors: string[] = ['rgb(0,223,0)', 'rgb(0,178,0)', 'rgb(0,201,0)', 'rgb(0,134,0)', 'rgb(0,156,0)']; + const evcsComponentColors: string[] = ["rgb(0,223,0)", "rgb(0,178,0)", "rgb(0,201,0)", "rgb(0,134,0)", "rgb(0,156,0)"]; evcsComponents.forEach((component, index) => { datasets.push({ name: component.alias, nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => { - return energyValues?.result.data[component.id + '/ActiveConsumptionEnergy']; + return energyValues?.result.data[component.id + "/ActiveConsumptionEnergy"]; }, converter: () => { - return data[component.id + '/ChargePower'] ?? null; + return data[component.id + "/ChargePower"] ?? null; }, color: evcsComponentColors[Math.min(index, (evcsComponentColors.length - 1))], stack: 1, }); }); - const consumptionMeterColors: string[] = ['rgb(220,20,60)', 'rgb(202, 158, 6', 'rgb(228, 177, 6)', 'rgb(177, 138, 5)', 'rgb(152, 118, 4)']; + const consumptionMeterColors: string[] = ["rgb(220,20,60)", "rgb(202, 158, 6", "rgb(228, 177, 6)", "rgb(177, 138, 5)", "rgb(152, 118, 4)"]; consumptionMeters.forEach((meter, index) => { datasets.push({ name: meter.alias, nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => { - return energyValues?.result.data[meter.id + '/ActiveProductionEnergy']; + return energyValues?.result.data[meter.id + "/ActiveProductionEnergy"]; }, converter: () => { - return data[meter.id + '/ActivePower'] ?? null; + return data[meter.id + "/ActivePower"] ?? null; }, color: consumptionMeterColors[Math.min(index, (consumptionMeterColors.length - 1))], stack: 1, @@ -97,14 +97,14 @@ export class ChartComponent extends AbstractHistoryChart { // other consumption if (consumptionMeters.length > 0 || evcsComponents.length > 0) { datasets.push({ - name: translate.instant('General.otherConsumption'), + name: translate.instant("General.otherConsumption"), nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => { return Utils.calculateOtherConsumptionTotal(energyValues, evcsComponents, consumptionMeters); }, converter: () => { return Utils.calculateOtherConsumption(data, evcsComponents, consumptionMeters); }, - color: 'rgb(0,0,0)', + color: "rgb(0,0,0)", stack: 1, }); } @@ -112,12 +112,12 @@ export class ChartComponent extends AbstractHistoryChart { return datasets; }, tooltip: { - formatNumber: '1.0-2', + formatNumber: "1.0-2", }, yAxes: [ { - unit: YAxisTitle.ENERGY, - position: 'left', + unit: YAxisType.ENERGY, + position: "left", yAxisId: ChartAxis.LEFT, }], }; diff --git a/ui/src/app/edge/history/common/consumption/details/chart/channels.spec.ts b/ui/src/app/edge/history/common/consumption/details/chart/channels.spec.ts index 20defa63495..3f907efebad 100644 --- a/ui/src/app/edge/history/common/consumption/details/chart/channels.spec.ts +++ b/ui/src/app/edge/history/common/consumption/details/chart/channels.spec.ts @@ -21,15 +21,15 @@ export namespace History { }), dataChannelWithValues: new QueryHistoricTimeseriesDataResponse("0", { data: { - 'evcs0/ChargePower': [124, 0, null, 0, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 110, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 140, null, null, null, 2127, 175, 176, null, 180, 180, 185, 180, null, 185, 190, 180, 180, 176, 176, 170, 175, 170, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null], - 'meter0/ActivePower': [124, 0, null, 0, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 110, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 140, null, null, null, 2127, 175, 176, null, 180, 180, 185, 180, null, 185, 190, 180, 180, 176, 176, 170, 175, 170, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null], - 'meter0/ActivePowerL1': [41, 0, null, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 38, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 47, null, null, null, 709, 58, 59, null, 60, 60, 62, 60, null, 62, 63, 60, 60, 59, 59, 57, 58, 57, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null], - 'meter0/ActivePowerL2': [41, 0, null, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 38, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 47, null, null, null, 709, 58, 59, null, 60, 60, 62, 60, null, 62, 63, 60, 60, 59, 59, 57, 58, 57, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null], - 'meter0/ActivePowerL3': [41, 0, null, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 38, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 47, null, null, null, 709, 58, 59, null, 60, 60, 62, 60, null, 62, 63, 60, 60, 59, 59, 57, 58, 57, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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/ConsumptionActivePower': [124, 0, null, 0, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 110, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 140, null, null, null, 2127, 175, 176, null, 180, 180, 185, 180, null, 185, 190, 180, 180, 176, 176, 170, 175, 170, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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/ConsumptionActivePowerL1': [41, 0, null, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 38, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 47, null, null, null, 709, 58, 59, null, 60, 60, 62, 60, null, 62, 63, 60, 60, 59, 59, 57, 58, 57, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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/ConsumptionActivePowerL2': [41, 0, null, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 38, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 47, null, null, null, 709, 58, 59, null, 60, 60, 62, 60, null, 62, 63, 60, 60, 59, 59, 57, 58, 57, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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/ConsumptionActivePowerL3': [41, 0, null, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 38, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 47, null, null, null, 709, 58, 59, null, 60, 60, 62, 60, null, 62, 63, 60, 60, 59, 59, 57, 58, 57, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null], + "evcs0/ChargePower": [124, 0, null, 0, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 110, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 140, null, null, null, 2127, 175, 176, null, 180, 180, 185, 180, null, 185, 190, 180, 180, 176, 176, 170, 175, 170, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null], + "meter0/ActivePower": [124, 0, null, 0, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 110, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 140, null, null, null, 2127, 175, 176, null, 180, 180, 185, 180, null, 185, 190, 180, 180, 176, 176, 170, 175, 170, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null], + "meter0/ActivePowerL1": [41, 0, null, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 38, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 47, null, null, null, 709, 58, 59, null, 60, 60, 62, 60, null, 62, 63, 60, 60, 59, 59, 57, 58, 57, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null], + "meter0/ActivePowerL2": [41, 0, null, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 38, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 47, null, null, null, 709, 58, 59, null, 60, 60, 62, 60, null, 62, 63, 60, 60, 59, 59, 57, 58, 57, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null], + "meter0/ActivePowerL3": [41, 0, null, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 38, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 47, null, null, null, 709, 58, 59, null, 60, 60, 62, 60, null, 62, 63, 60, 60, 59, 59, 57, 58, 57, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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/ConsumptionActivePower": [124, 0, null, 0, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 110, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 140, null, null, null, 2127, 175, 176, null, 180, 180, 185, 180, null, 185, 190, 180, 180, 176, 176, 170, 175, 170, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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/ConsumptionActivePowerL1": [41, 0, null, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 38, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 47, null, null, null, 709, 58, 59, null, 60, 60, 62, 60, null, 62, 63, 60, 60, 59, 59, 57, 58, 57, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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/ConsumptionActivePowerL2": [41, 0, null, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 38, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 47, null, null, null, 709, 58, 59, null, 60, 60, 62, 60, null, 62, 63, 60, 60, 59, 59, 57, 58, 57, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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/ConsumptionActivePowerL3": [41, 0, null, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 38, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 47, null, null, null, 709, 58, 59, null, 60, 60, 62, 60, null, 62, 63, 60, 60, 59, 59, 57, 58, 57, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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"], diff --git a/ui/src/app/edge/history/common/consumption/details/chart/consumptionMeter.spec.ts b/ui/src/app/edge/history/common/consumption/details/chart/consumptionMeter.spec.ts index 27ef1645867..c73384cbce2 100644 --- a/ui/src/app/edge/history/common/consumption/details/chart/consumptionMeter.spec.ts +++ b/ui/src/app/edge/history/common/consumption/details/chart/consumptionMeter.spec.ts @@ -9,52 +9,52 @@ import { DATA, LABELS } from "../../../energy/chart/chart.constants.spec"; import { History } from "./channels.spec"; import { ConsumptionMeterChartDetailsComponent } from "./consumptionMeter"; -describe('History Consumption Details - consumptionMeters', () => { +describe("History Consumption Details - consumptionMeters", () => { const defaultEMS = DummyConfig.from( DummyConfig.Component.SOCOMEC_CONSUMPTION_METER("meter0"), ); let TEST_CONTEXT: TestContext & { route: ActivatedRoute }; beforeEach(async () => { - TEST_CONTEXT = await sharedSetupWithComponentIdRoute('meter0'); + TEST_CONTEXT = await sharedSetupWithComponentIdRoute("meter0"); }); - it('#getChartData()', () => { + it("#getChartData()", () => { { - expectView(defaultEMS, TEST_CONTEXT, 'line', History.DAY, + expectView(defaultEMS, TEST_CONTEXT, "line", History.DAY, { datasets: { data: [ - DATA('meter0: 15,9 kWh', [0.124, 0, null, 0, 0.173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.11, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.13, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.14, null, null, null, 2.127, 0.175, 0.176, null, 0.18, 0.18, 0.185, 0.18, null, 0.185, 0.19, 0.18, 0.18, 0.176, 0.176, 0.17, 0.175, 0.17, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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('Phase L1', [0.041, 0, null, 0, 0.058, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.037, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.048, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.038, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.043, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.047, null, null, null, 0.709, 0.058, 0.059, null, 0.06, 0.06, 0.062, 0.06, null, 0.062, 0.063, 0.06, 0.06, 0.059, 0.059, 0.057, 0.058, 0.057, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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('Phase L2', [0.041, 0, null, 0, 0.058, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.037, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.048, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.038, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.043, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.047, null, null, null, 0.709, 0.058, 0.059, null, 0.06, 0.06, 0.062, 0.06, null, 0.062, 0.063, 0.06, 0.06, 0.059, 0.059, 0.057, 0.058, 0.057, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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('Phase L3', [0.041, 0, null, 0, 0.058, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.037, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.048, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.038, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.043, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.047, null, null, null, 0.709, 0.058, 0.059, null, 0.06, 0.06, 0.062, 0.06, null, 0.062, 0.063, 0.06, 0.06, 0.059, 0.059, 0.057, 0.058, 0.057, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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("meter0: 15,9 kWh", [0.124, 0, null, 0, 0.173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.11, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.13, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.14, null, null, null, 2.127, 0.175, 0.176, null, 0.18, 0.18, 0.185, 0.18, null, 0.185, 0.19, 0.18, 0.18, 0.176, 0.176, 0.17, 0.175, 0.17, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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("Phase L1", [0.041, 0, null, 0, 0.058, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.037, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.048, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.038, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.043, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.047, null, null, null, 0.709, 0.058, 0.059, null, 0.06, 0.06, 0.062, 0.06, null, 0.062, 0.063, 0.06, 0.06, 0.059, 0.059, 0.057, 0.058, 0.057, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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("Phase L2", [0.041, 0, null, 0, 0.058, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.037, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.048, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.038, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.043, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.047, null, null, null, 0.709, 0.058, 0.059, null, 0.06, 0.06, 0.062, 0.06, null, 0.062, 0.063, 0.06, 0.06, 0.059, 0.059, 0.057, 0.058, 0.057, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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("Phase L3", [0.041, 0, null, 0, 0.058, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.037, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.048, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.038, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.043, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.047, null, null, null, 0.709, 0.058, 0.059, null, 0.06, 0.06, 0.062, 0.06, null, 0.062, 0.063, 0.06, 0.06, 0.059, 0.059, 0.057, 0.058, 0.057, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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: OeTester.ChartOptions.LINE_CHART_OPTIONS('hour', 'line', { 'left': { scale: { beginAtZero: true } } }, + options: OeTester.ChartOptions.LINE_CHART_OPTIONS("hour", "line", { "left": { scale: { beginAtZero: true } } }, ), }, }); } { - expectView(defaultEMS, TEST_CONTEXT, 'bar', History.MONTH, + expectView(defaultEMS, TEST_CONTEXT, "bar", History.MONTH, { datasets: { data: [ - DATA('meter0: 21,6 kWh', [0.016, 0.014, 0.016, 0.015, 0.016, 0.015, 0.015, 0.015, 0.016, 0.017, 0.018, 0.014, 0.016, 0.017, 0.016, 0.015, 0.014, 0.017, 0.015, 0.016, 0.017, 0.016, 0.015, 0.016, 0.014, 0.015, 0.014, 0.016, 0.014, null, null]), - DATA('Phase L1', [0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.006, 0.006, 0.005, 0.005, 0.006, 0.005, 0.005, 0.005, 0.006, 0.005, 0.005, 0.006, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, null, null]), - DATA('Phase L2', [0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.006, 0.006, 0.005, 0.005, 0.006, 0.005, 0.005, 0.005, 0.006, 0.005, 0.005, 0.006, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, null, null]), - DATA('Phase L3', [0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.006, 0.006, 0.005, 0.005, 0.006, 0.005, 0.005, 0.005, 0.006, 0.005, 0.005, 0.006, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, null, null]), + DATA("meter0: 21,6 kWh", [0.016, 0.014, 0.016, 0.015, 0.016, 0.015, 0.015, 0.015, 0.016, 0.017, 0.018, 0.014, 0.016, 0.017, 0.016, 0.015, 0.014, 0.017, 0.015, 0.016, 0.017, 0.016, 0.015, 0.016, 0.014, 0.015, 0.014, 0.016, 0.014, null, null]), + DATA("Phase L1", [0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.006, 0.006, 0.005, 0.005, 0.006, 0.005, 0.005, 0.005, 0.006, 0.005, 0.005, 0.006, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, null, null]), + DATA("Phase L2", [0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.006, 0.006, 0.005, 0.005, 0.006, 0.005, 0.005, 0.005, 0.006, 0.005, 0.005, 0.006, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, null, null]), + DATA("Phase L3", [0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.006, 0.006, 0.005, 0.005, 0.006, 0.005, 0.005, 0.005, 0.006, 0.005, 0.005, 0.006, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, null, null]), ], labels: LABELS(History.MONTH.energyPerPeriodChannelWithValues.result.timestamps), - options: OeTester.ChartOptions.BAR_CHART_OPTIONS('day', 'bar', {}), + options: OeTester.ChartOptions.BAR_CHART_OPTIONS("day", "bar", {}), }, }); } }); }); -export function expectView(config: EdgeConfig, testContext: TestContext & { route: ActivatedRoute }, chartType: 'line' | 'bar', channels: OeTester.Types.Channels, view: OeChartTester.View): void { +export function expectView(config: EdgeConfig, testContext: TestContext & { route: ActivatedRoute }, chartType: "line" | "bar", channels: OeTester.Types.Channels, view: OeChartTester.View): void { expect(removeFunctions(OeChartTester .apply(ConsumptionMeterChartDetailsComponent .getChartData( diff --git a/ui/src/app/edge/history/common/consumption/details/chart/consumptionMeter.ts b/ui/src/app/edge/history/common/consumption/details/chart/consumptionMeter.ts index fd696ec5368..7fd59547f17 100644 --- a/ui/src/app/edge/history/common/consumption/details/chart/consumptionMeter.ts +++ b/ui/src/app/edge/history/common/consumption/details/chart/consumptionMeter.ts @@ -1,15 +1,15 @@ -import { Component } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { TranslateService } from '@ngx-translate/core'; -import { AbstractHistoryChart } from 'src/app/shared/components/chart/abstracthistorychart'; -import { Phase } from 'src/app/shared/components/shared/phase'; -import { QueryHistoricTimeseriesEnergyResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; -import { ChartAxis, HistoryUtils, YAxisTitle } from 'src/app/shared/service/utils'; -import { ChannelAddress, EdgeConfig } from 'src/app/shared/shared'; +import { Component } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { TranslateService } from "@ngx-translate/core"; +import { AbstractHistoryChart } from "src/app/shared/components/chart/abstracthistorychart"; +import { Phase } from "src/app/shared/components/shared/phase"; +import { QueryHistoricTimeseriesEnergyResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse"; +import { ChartAxis, HistoryUtils, YAxisType } from "src/app/shared/service/utils"; +import { ChannelAddress, EdgeConfig } from "src/app/shared/shared"; @Component({ - selector: 'consumptionMeterChart', - templateUrl: '../../../../../../shared/components/chart/abstracthistorychart.html', + selector: "consumptionMeterChart", + templateUrl: "../../../../../../shared/components/chart/abstracthistorychart.html", }) export class ConsumptionMeterChartDetailsComponent extends AbstractHistoryChart { @@ -18,20 +18,20 @@ export class ConsumptionMeterChartDetailsComponent extends AbstractHistoryChart return { input: [{ name: component.id, - powerChannel: ChannelAddress.fromString(component.id + '/ActivePower'), - energyChannel: ChannelAddress.fromString(component.id + '/ActiveProductionEnergy'), + powerChannel: ChannelAddress.fromString(component.id + "/ActivePower"), + energyChannel: ChannelAddress.fromString(component.id + "/ActiveProductionEnergy"), }, ...Phase.THREE_PHASE.map(phase => ({ - name: 'ConsumptionActivePower' + phase, - powerChannel: ChannelAddress.fromString(component.id + '/ActivePower' + phase), - energyChannel: ChannelAddress.fromString(component.id + '/ActiveProductionEnergy' + phase), + name: "ConsumptionActivePower" + phase, + powerChannel: ChannelAddress.fromString(component.id + "/ActivePower" + phase), + energyChannel: ChannelAddress.fromString(component.id + "/ActiveProductionEnergy" + phase), }))], output: (data: HistoryUtils.ChannelData) => [ { name: component.alias, - nameSuffix: (energyQueryResponse: QueryHistoricTimeseriesEnergyResponse) => energyQueryResponse.result.data[component.id + '/ActiveProductionEnergy'], + nameSuffix: (energyQueryResponse: QueryHistoricTimeseriesEnergyResponse) => energyQueryResponse.result.data[component.id + "/ActiveProductionEnergy"], converter: () => data[component.id], - color: 'rgb(0,152,204)', + color: "rgb(0,152,204)", hiddenOnInit: false, stack: 2, }, @@ -39,18 +39,18 @@ export class ConsumptionMeterChartDetailsComponent extends AbstractHistoryChart ...Phase.THREE_PHASE.map((phase, i) => ({ name: "Phase " + phase, converter: () => - data['ConsumptionActivePower' + phase], - color: 'rgb(' + AbstractHistoryChart.phaseColors[i] + ')', + data["ConsumptionActivePower" + phase], + color: "rgb(" + AbstractHistoryChart.phaseColors[i] + ")", stack: 3, })), ], tooltip: { - formatNumber: '1.1-2', - afterTitle: translate.instant('General.TOTAL'), + formatNumber: "1.1-2", + afterTitle: translate.instant("General.TOTAL"), }, yAxes: [{ - unit: YAxisTitle.ENERGY, - position: 'left', + unit: YAxisType.ENERGY, + position: "left", yAxisId: ChartAxis.LEFT, }], }; diff --git a/ui/src/app/edge/history/common/consumption/details/chart/evcs.spec.ts b/ui/src/app/edge/history/common/consumption/details/chart/evcs.spec.ts index 9a45e639dee..75a40f7b0ba 100644 --- a/ui/src/app/edge/history/common/consumption/details/chart/evcs.spec.ts +++ b/ui/src/app/edge/history/common/consumption/details/chart/evcs.spec.ts @@ -9,46 +9,46 @@ import { DATA, LABELS } from "../../../energy/chart/chart.constants.spec"; import { History } from "./channels.spec"; import { EvcsChartDetailsComponent } from "./evcs"; -describe('History Consumption Details - evcs', () => { +describe("History Consumption Details - evcs", () => { const defaultEMS = DummyConfig.from( DummyConfig.Component.EVCS_KEBA_KECONTACT("evcs0", "Charging Station"), ); let TEST_CONTEXT: TestContext & { route: ActivatedRoute }; beforeEach(async () => { - TEST_CONTEXT = await sharedSetupWithComponentIdRoute('evcs0'); + TEST_CONTEXT = await sharedSetupWithComponentIdRoute("evcs0"); }); - it('#getChartData() - evcs', () => { + it("#getChartData() - evcs", () => { { - expectView(defaultEMS, TEST_CONTEXT, 'line', History.DAY, + expectView(defaultEMS, TEST_CONTEXT, "line", History.DAY, { datasets: { data: [ - DATA('Charging Station: 15,9 kWh', [0.124, 0, null, 0, 0.173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.11, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.13, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.14, null, null, null, 2.127, 0.175, 0.176, null, 0.18, 0.18, 0.185, 0.18, null, 0.185, 0.19, 0.18, 0.18, 0.176, 0.176, 0.17, 0.175, 0.17, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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("Charging Station: 15,9 kWh", [0.124, 0, null, 0, 0.173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.11, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.13, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.14, null, null, null, 2.127, 0.175, 0.176, null, 0.18, 0.18, 0.185, 0.18, null, 0.185, 0.19, 0.18, 0.18, 0.176, 0.176, 0.17, 0.175, 0.17, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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: OeTester.ChartOptions.LINE_CHART_OPTIONS('hour', 'line', { 'left': { scale: { beginAtZero: true } } }, + options: OeTester.ChartOptions.LINE_CHART_OPTIONS("hour", "line", { "left": { scale: { beginAtZero: true } } }, ), }, }); } { - expectView(defaultEMS, TEST_CONTEXT, 'bar', History.MONTH, + expectView(defaultEMS, TEST_CONTEXT, "bar", History.MONTH, { datasets: { data: [ - DATA('Charging Station: 21,6 kWh', [0.016, 0.014, 0.016, 0.015, 0.016, 0.015, 0.015, 0.015, 0.016, 0.017, 0.018, 0.014, 0.016, 0.017, 0.016, 0.015, 0.014, 0.017, 0.015, 0.016, 0.017, 0.016, 0.015, 0.016, 0.014, 0.015, 0.014, 0.016, 0.014, null, null]), + DATA("Charging Station: 21,6 kWh", [0.016, 0.014, 0.016, 0.015, 0.016, 0.015, 0.015, 0.015, 0.016, 0.017, 0.018, 0.014, 0.016, 0.017, 0.016, 0.015, 0.014, 0.017, 0.015, 0.016, 0.017, 0.016, 0.015, 0.016, 0.014, 0.015, 0.014, 0.016, 0.014, null, null]), ], labels: LABELS(History.MONTH.energyPerPeriodChannelWithValues.result.timestamps), - options: OeTester.ChartOptions.BAR_CHART_OPTIONS('day', 'bar', {}), + options: OeTester.ChartOptions.BAR_CHART_OPTIONS("day", "bar", {}), }, }); } }); }); -export function expectView(config: EdgeConfig, testContext: TestContext & { route: ActivatedRoute }, chartType: 'line' | 'bar', channels: OeTester.Types.Channels, view: OeChartTester.View): void { +export function expectView(config: EdgeConfig, testContext: TestContext & { route: ActivatedRoute }, chartType: "line" | "bar", channels: OeTester.Types.Channels, view: OeChartTester.View): void { expect(removeFunctions(OeChartTester .apply(EvcsChartDetailsComponent .getChartData( diff --git a/ui/src/app/edge/history/common/consumption/details/chart/evcs.ts b/ui/src/app/edge/history/common/consumption/details/chart/evcs.ts index 637343afb09..62e58482cfe 100644 --- a/ui/src/app/edge/history/common/consumption/details/chart/evcs.ts +++ b/ui/src/app/edge/history/common/consumption/details/chart/evcs.ts @@ -1,14 +1,14 @@ -import { Component } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { TranslateService } from '@ngx-translate/core'; -import { AbstractHistoryChart } from 'src/app/shared/components/chart/abstracthistorychart'; -import { QueryHistoricTimeseriesEnergyResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; -import { ChartAxis, HistoryUtils, YAxisTitle } from 'src/app/shared/service/utils'; -import { ChannelAddress, EdgeConfig } from 'src/app/shared/shared'; +import { Component } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { TranslateService } from "@ngx-translate/core"; +import { AbstractHistoryChart } from "src/app/shared/components/chart/abstracthistorychart"; +import { QueryHistoricTimeseriesEnergyResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse"; +import { ChartAxis, HistoryUtils, YAxisType } from "src/app/shared/service/utils"; +import { ChannelAddress, EdgeConfig } from "src/app/shared/shared"; @Component({ - selector: 'evcsChart', - templateUrl: '../../../../../../shared/components/chart/abstracthistorychart.html', + selector: "evcsChart", + templateUrl: "../../../../../../shared/components/chart/abstracthistorychart.html", }) export class EvcsChartDetailsComponent extends AbstractHistoryChart { @@ -18,24 +18,24 @@ export class EvcsChartDetailsComponent extends AbstractHistoryChart { return { input: [{ name: component.id, - powerChannel: ChannelAddress.fromString(component.id + '/ChargePower'), - energyChannel: ChannelAddress.fromString(component.id + '/ActiveConsumptionEnergy'), + powerChannel: ChannelAddress.fromString(component.id + "/ChargePower"), + energyChannel: ChannelAddress.fromString(component.id + "/ActiveConsumptionEnergy"), }], output: (data: HistoryUtils.ChannelData) => [{ name: component.alias, - nameSuffix: (energyQueryResponse: QueryHistoricTimeseriesEnergyResponse) => energyQueryResponse.result.data[component.id + '/ActiveConsumptionEnergy'], + nameSuffix: (energyQueryResponse: QueryHistoricTimeseriesEnergyResponse) => energyQueryResponse.result.data[component.id + "/ActiveConsumptionEnergy"], converter: () => data[component.id], - color: 'rgb(0,152,204)', + color: "rgb(0,152,204)", hiddenOnInit: false, stack: 2, }], tooltip: { - formatNumber: '1.1-2', - afterTitle: translate.instant('General.TOTAL'), + formatNumber: "1.1-2", + afterTitle: translate.instant("General.TOTAL"), }, yAxes: [{ - unit: YAxisTitle.ENERGY, - position: 'left', + unit: YAxisType.ENERGY, + position: "left", yAxisId: ChartAxis.LEFT, }], }; diff --git a/ui/src/app/edge/history/common/consumption/details/chart/sum.spec.ts b/ui/src/app/edge/history/common/consumption/details/chart/sum.spec.ts index a7e61affa4e..0192ff39015 100644 --- a/ui/src/app/edge/history/common/consumption/details/chart/sum.spec.ts +++ b/ui/src/app/edge/history/common/consumption/details/chart/sum.spec.ts @@ -9,49 +9,49 @@ import { DATA, LABELS } from "../../../energy/chart/chart.constants.spec"; import { History } from "./channels.spec"; import { SumChartDetailsComponent } from "./sum"; -describe('History Production Details - _sum', () => { +describe("History Production Details - _sum", () => { const defaultEMS = DummyConfig.from( DummyConfig.Component.SUM("_sum", "Gesamt"), ); let TEST_CONTEXT: TestContext & { route: ActivatedRoute }; beforeEach(async () => { - TEST_CONTEXT = await sharedSetupWithComponentIdRoute('_sum'); + TEST_CONTEXT = await sharedSetupWithComponentIdRoute("_sum"); }); - it('#getChartData()', () => { + it("#getChartData()", () => { { - expectView(defaultEMS, TEST_CONTEXT, 'line', History.DAY, + expectView(defaultEMS, TEST_CONTEXT, "line", History.DAY, { datasets: { data: [ - DATA('Gesamt: 15,9 kWh', [0.124, 0, null, 0, 0.173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.11, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.13, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.14, null, null, null, 2.127, 0.175, 0.176, null, 0.18, 0.18, 0.185, 0.18, null, 0.185, 0.19, 0.18, 0.18, 0.176, 0.176, 0.17, 0.175, 0.17, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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('Phase L1', [0.041, 0, null, 0, 0.058, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.037, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.048, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.038, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.043, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.047, null, null, null, 0.709, 0.058, 0.059, null, 0.06, 0.06, 0.062, 0.06, null, 0.062, 0.063, 0.06, 0.06, 0.059, 0.059, 0.057, 0.058, 0.057, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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('Phase L2', [0.041, 0, null, 0, 0.058, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.037, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.048, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.038, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.043, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.047, null, null, null, 0.709, 0.058, 0.059, null, 0.06, 0.06, 0.062, 0.06, null, 0.062, 0.063, 0.06, 0.06, 0.059, 0.059, 0.057, 0.058, 0.057, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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('Phase L3', [0.041, 0, null, 0, 0.058, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.037, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.048, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.038, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.043, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.047, null, null, null, 0.709, 0.058, 0.059, null, 0.06, 0.06, 0.062, 0.06, null, 0.062, 0.063, 0.06, 0.06, 0.059, 0.059, 0.057, 0.058, 0.057, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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("Gesamt: 15,9 kWh", [0.124, 0, null, 0, 0.173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.11, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.13, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.14, null, null, null, 2.127, 0.175, 0.176, null, 0.18, 0.18, 0.185, 0.18, null, 0.185, 0.19, 0.18, 0.18, 0.176, 0.176, 0.17, 0.175, 0.17, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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("Phase L1", [0.041, 0, null, 0, 0.058, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.037, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.048, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.038, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.043, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.047, null, null, null, 0.709, 0.058, 0.059, null, 0.06, 0.06, 0.062, 0.06, null, 0.062, 0.063, 0.06, 0.06, 0.059, 0.059, 0.057, 0.058, 0.057, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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("Phase L2", [0.041, 0, null, 0, 0.058, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.037, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.048, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.038, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.043, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.047, null, null, null, 0.709, 0.058, 0.059, null, 0.06, 0.06, 0.062, 0.06, null, 0.062, 0.063, 0.06, 0.06, 0.059, 0.059, 0.057, 0.058, 0.057, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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("Phase L3", [0.041, 0, null, 0, 0.058, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.037, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.048, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.038, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.043, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.047, null, null, null, 0.709, 0.058, 0.059, null, 0.06, 0.06, 0.062, 0.06, null, 0.062, 0.063, 0.06, 0.06, 0.059, 0.059, 0.057, 0.058, 0.057, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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: OeTester.ChartOptions.LINE_CHART_OPTIONS('hour', 'line', { 'left': { scale: { beginAtZero: true } } }, + options: OeTester.ChartOptions.LINE_CHART_OPTIONS("hour", "line", { "left": { scale: { beginAtZero: true } } }, ), }, }); } { - expectView(defaultEMS, TEST_CONTEXT, 'bar', History.MONTH, + expectView(defaultEMS, TEST_CONTEXT, "bar", History.MONTH, { datasets: { data: [ - DATA('Gesamt: 21,6 kWh', [0.016, 0.014, 0.016, 0.015, 0.016, 0.015, 0.015, 0.015, 0.016, 0.017, 0.018, 0.014, 0.016, 0.017, 0.016, 0.015, 0.014, 0.017, 0.015, 0.016, 0.017, 0.016, 0.015, 0.016, 0.014, 0.015, 0.014, 0.016, 0.014, null, null]), + DATA("Gesamt: 21,6 kWh", [0.016, 0.014, 0.016, 0.015, 0.016, 0.015, 0.015, 0.015, 0.016, 0.017, 0.018, 0.014, 0.016, 0.017, 0.016, 0.015, 0.014, 0.017, 0.015, 0.016, 0.017, 0.016, 0.015, 0.016, 0.014, 0.015, 0.014, 0.016, 0.014, null, null]), ], labels: LABELS(History.MONTH.energyPerPeriodChannelWithValues.result.timestamps), - options: OeTester.ChartOptions.BAR_CHART_OPTIONS('day', 'bar', {}), + options: OeTester.ChartOptions.BAR_CHART_OPTIONS("day", "bar", {}), }, }); } }); }); -export function expectView(config: EdgeConfig, testContext: TestContext & { route: ActivatedRoute }, chartType: 'line' | 'bar', channels: OeTester.Types.Channels, view: OeChartTester.View): void { +export function expectView(config: EdgeConfig, testContext: TestContext & { route: ActivatedRoute }, chartType: "line" | "bar", channels: OeTester.Types.Channels, view: OeChartTester.View): void { expect(removeFunctions(OeChartTester .apply(SumChartDetailsComponent .getChartData( diff --git a/ui/src/app/edge/history/common/consumption/details/chart/sum.ts b/ui/src/app/edge/history/common/consumption/details/chart/sum.ts index 273263dab12..cf25ef1a843 100644 --- a/ui/src/app/edge/history/common/consumption/details/chart/sum.ts +++ b/ui/src/app/edge/history/common/consumption/details/chart/sum.ts @@ -1,15 +1,15 @@ -import { Component } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { TranslateService } from '@ngx-translate/core'; -import { AbstractHistoryChart } from 'src/app/shared/components/chart/abstracthistorychart'; -import { Phase } from 'src/app/shared/components/shared/phase'; -import { QueryHistoricTimeseriesEnergyResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; -import { ChartAxis, HistoryUtils, YAxisTitle } from 'src/app/shared/service/utils'; -import { ChannelAddress, EdgeConfig } from 'src/app/shared/shared'; +import { Component } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { TranslateService } from "@ngx-translate/core"; +import { AbstractHistoryChart } from "src/app/shared/components/chart/abstracthistorychart"; +import { Phase } from "src/app/shared/components/shared/phase"; +import { QueryHistoricTimeseriesEnergyResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse"; +import { ChartAxis, HistoryUtils, YAxisType } from "src/app/shared/service/utils"; +import { ChannelAddress, EdgeConfig } from "src/app/shared/shared"; @Component({ - selector: 'sumChart', - templateUrl: '../../../../../../shared/components/chart/abstracthistorychart.html', + selector: "sumChart", + templateUrl: "../../../../../../shared/components/chart/abstracthistorychart.html", }) export class SumChartDetailsComponent extends AbstractHistoryChart { @@ -19,20 +19,20 @@ export class SumChartDetailsComponent extends AbstractHistoryChart { return { input: [{ name: component.id, - powerChannel: ChannelAddress.fromString(component.id + '/ConsumptionActivePower'), - energyChannel: ChannelAddress.fromString(component.id + '/ConsumptionActiveEnergy'), + powerChannel: ChannelAddress.fromString(component.id + "/ConsumptionActivePower"), + energyChannel: ChannelAddress.fromString(component.id + "/ConsumptionActiveEnergy"), }, ...Phase.THREE_PHASE.map(phase => ({ - name: 'ConsumptionActivePower' + phase, - powerChannel: ChannelAddress.fromString(component.id + '/ConsumptionActivePower' + phase), + name: "ConsumptionActivePower" + phase, + powerChannel: ChannelAddress.fromString(component.id + "/ConsumptionActivePower" + phase), }))], output: (data: HistoryUtils.ChannelData) => [{ name: component.alias, - nameSuffix: (energyQueryResponse: QueryHistoricTimeseriesEnergyResponse) => energyQueryResponse.result.data[component.id + '/ConsumptionActiveEnergy'], + nameSuffix: (energyQueryResponse: QueryHistoricTimeseriesEnergyResponse) => energyQueryResponse.result.data[component.id + "/ConsumptionActiveEnergy"], converter: () => data[component.id], - color: 'rgb(0,152,204)', + color: "rgb(0,152,204)", hiddenOnInit: false, stack: 2, }, @@ -40,17 +40,17 @@ export class SumChartDetailsComponent extends AbstractHistoryChart { ...Phase.THREE_PHASE.map((phase, i) => ({ name: "Phase " + phase, converter: () => - data['ConsumptionActivePower' + phase], - color: 'rgb(' + AbstractHistoryChart.phaseColors[i] + ')', + data["ConsumptionActivePower" + phase], + color: "rgb(" + AbstractHistoryChart.phaseColors[i] + ")", stack: 3, }))], tooltip: { - formatNumber: '1.1-2', - afterTitle: translate.instant('General.TOTAL'), + formatNumber: "1.1-2", + afterTitle: translate.instant("General.TOTAL"), }, yAxes: [{ - unit: YAxisTitle.ENERGY, - position: 'left', + unit: YAxisType.ENERGY, + position: "left", yAxisId: ChartAxis.LEFT, }], }; diff --git a/ui/src/app/edge/history/common/consumption/details/details.overview.html b/ui/src/app/edge/history/common/consumption/details/details.overview.html index 80ddb738d14..31819efc6fb 100644 --- a/ui/src/app/edge/history/common/consumption/details/details.overview.html +++ b/ui/src/app/edge/history/common/consumption/details/details.overview.html @@ -1,5 +1,5 @@ - + diff --git a/ui/src/app/edge/history/common/consumption/details/details.overview.ts b/ui/src/app/edge/history/common/consumption/details/details.overview.ts index 74647b30812..645fd4194dd 100644 --- a/ui/src/app/edge/history/common/consumption/details/details.overview.ts +++ b/ui/src/app/edge/history/common/consumption/details/details.overview.ts @@ -1,18 +1,18 @@ -import { Component } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; -import { ModalController } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; -import { AbstractHistoryChartOverview } from 'src/app/shared/components/chart/abstractHistoryChartOverview'; -import { NavigationOption } from 'src/app/shared/components/footer/subnavigation/footerNavigation'; -import { Service } from 'src/app/shared/shared'; -import { Role } from 'src/app/shared/type/role'; +import { Component } from "@angular/core"; +import { ActivatedRoute, Router } from "@angular/router"; +import { ModalController } from "@ionic/angular"; +import { TranslateService } from "@ngx-translate/core"; +import { AbstractHistoryChartOverview } from "src/app/shared/components/chart/abstractHistoryChartOverview"; +import { NavigationOption } from "src/app/shared/components/footer/subnavigation/footerNavigation"; +import { Service } from "src/app/shared/shared"; +import { Role } from "src/app/shared/type/role"; @Component({ - templateUrl: './details.overview.html', + templateUrl: "./details.overview.html", }) export class DetailsOverviewComponent extends AbstractHistoryChartOverview { protected navigationButtons: NavigationOption[] = []; - protected componentType: 'sum' | 'consumptionMeter' | 'evcs' | null = null; + protected componentType: "sum" | "consumptionMeter" | "evcs" | null = null; constructor( public override service: Service, @@ -36,13 +36,13 @@ export class DetailsOverviewComponent extends AbstractHistoryChartOverview { return; } - if (this.component.factoryId === 'Core.Sum') { - this.component.alias = this.translate.instant('General.TOTAL'); + if (this.component.factoryId === "Core.Sum") { + this.component.alias = this.translate.instant("General.TOTAL"); return; } this.navigationButtons = [ - { id: 'currentVoltage', isEnabled: edge.roleIsAtLeast(Role.INSTALLER), alias: this.translate.instant("Edge.History.CURRENT_AND_VOLTAGE"), callback: () => { this.router.navigate(['./currentVoltage'], { relativeTo: this.route }); } }]; + { id: "currentVoltage", isEnabled: edge.roleIsAtLeast(Role.INSTALLER), alias: this.translate.instant("Edge.History.CURRENT_AND_VOLTAGE"), callback: () => { this.router.navigate(["./currentVoltage"], { relativeTo: this.route }); } }]; }); } @@ -52,19 +52,19 @@ export class DetailsOverviewComponent extends AbstractHistoryChartOverview { } if (this.config?.hasComponentNature("io.openems.edge.evcs.api.Evcs", this.component.id) - && (this.component.factoryId !== 'Evcs.Cluster.SelfConsumption') - && this.component.factoryId !== 'Evcs.Cluster.PeakShaving' + && (this.component.factoryId !== "Evcs.Cluster.SelfConsumption") + && this.component.factoryId !== "Evcs.Cluster.PeakShaving" && this.component.isEnabled !== false) { - return 'evcs'; + return "evcs"; } if (this.config?.hasComponentNature("io.openems.edge.meter.api.ElectricityMeter", this.component.id) && this.config.isTypeConsumptionMetered(this.component) && this.component.isEnabled) { - return 'consumptionMeter'; + return "consumptionMeter"; } - if (this.component.factoryId === 'Core.Sum') { - return 'sum'; + if (this.component.factoryId === "Core.Sum") { + return "sum"; } return null; diff --git a/ui/src/app/edge/history/common/consumption/flat/flat.ts b/ui/src/app/edge/history/common/consumption/flat/flat.ts index 7431f592845..149521db911 100644 --- a/ui/src/app/edge/history/common/consumption/flat/flat.ts +++ b/ui/src/app/edge/history/common/consumption/flat/flat.ts @@ -1,11 +1,11 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; -import { ChannelAddress, CurrentData, EdgeConfig } from '../../../../../shared/shared'; +import { Component } from "@angular/core"; +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; +import { ChannelAddress, CurrentData, EdgeConfig } from "../../../../../shared/shared"; @Component({ - selector: 'consumptionWidget', - templateUrl: './flat.html', + selector: "consumptionWidget", + templateUrl: "./flat.html", }) export class FlatComponent extends AbstractFlatWidget { @@ -17,21 +17,21 @@ export class FlatComponent extends AbstractFlatWidget { this.evcsComponents = this.config?.getComponentsImplementingNature("io.openems.edge.evcs.api.Evcs") .filter(component => - !(component.factoryId === 'Evcs.Cluster.SelfConsumption') && - !(component.factoryId === 'Evcs.Cluster.PeakShaving') && + !(component.factoryId === "Evcs.Cluster.SelfConsumption") && + !(component.factoryId === "Evcs.Cluster.PeakShaving") && !component.isEnabled === false); this.consumptionMeterComponents = this.config?.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") .filter(component => component.isEnabled && this.config.isTypeConsumptionMetered(component)); - const channels: ChannelAddress[] = [new ChannelAddress('_sum', 'ConsumptionActiveEnergy')]; + const channels: ChannelAddress[] = [new ChannelAddress("_sum", "ConsumptionActiveEnergy")]; this.evcsComponents.forEach((component) => { - channels.push(new ChannelAddress(component.id, 'ActiveConsumptionEnergy')); + channels.push(new ChannelAddress(component.id, "ActiveConsumptionEnergy")); }); this.consumptionMeterComponents.forEach((component) => { - channels.push(new ChannelAddress(component.id, 'ActiveProductionEnergy')); + channels.push(new ChannelAddress(component.id, "ActiveProductionEnergy")); }); @@ -51,10 +51,10 @@ export class FlatComponent extends AbstractFlatWidget { private getTotalOtherEnergy(currentData: CurrentData): number { let otherEnergy: number = 0; this.evcsComponents.forEach(component => { - otherEnergy += currentData.allComponents[component.id + '/ActiveConsumptionEnergy'] ?? 0; + otherEnergy += currentData.allComponents[component.id + "/ActiveConsumptionEnergy"] ?? 0; }); this.consumptionMeterComponents.forEach(component => { - otherEnergy += currentData.allComponents[component.id + '/ActiveProductionEnergy'] ?? 0; + otherEnergy += currentData.allComponents[component.id + "/ActiveProductionEnergy"] ?? 0; }); return currentData.allComponents["_sum/ConsumptionActiveEnergy"] - otherEnergy; } diff --git a/ui/src/app/edge/history/common/consumption/overview/overview.ts b/ui/src/app/edge/history/common/consumption/overview/overview.ts index b67018fc4fb..cf75130de35 100644 --- a/ui/src/app/edge/history/common/consumption/overview/overview.ts +++ b/ui/src/app/edge/history/common/consumption/overview/overview.ts @@ -1,13 +1,13 @@ -import { Component } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; -import { ModalController } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; -import { AbstractHistoryChartOverview } from 'src/app/shared/components/chart/abstractHistoryChartOverview'; -import { NavigationOption } from 'src/app/shared/components/footer/subnavigation/footerNavigation'; -import { ChannelAddress, EdgeConfig, Service } from 'src/app/shared/shared'; +import { Component } from "@angular/core"; +import { ActivatedRoute, Router } from "@angular/router"; +import { ModalController } from "@ionic/angular"; +import { TranslateService } from "@ngx-translate/core"; +import { AbstractHistoryChartOverview } from "src/app/shared/components/chart/abstractHistoryChartOverview"; +import { NavigationOption } from "src/app/shared/components/footer/subnavigation/footerNavigation"; +import { ChannelAddress, EdgeConfig, Service } from "src/app/shared/shared"; @Component({ - templateUrl: './overview.html', + templateUrl: "./overview.html", }) export class OverviewComponent extends AbstractHistoryChartOverview { @@ -29,18 +29,18 @@ export class OverviewComponent extends AbstractHistoryChartOverview { this.evcsComponents = this.config?.getComponentsImplementingNature("io.openems.edge.evcs.api.Evcs") .filter(component => - !(component.factoryId === 'Evcs.Cluster.SelfConsumption') && - !(component.factoryId === 'Evcs.Cluster.PeakShaving') && + !(component.factoryId === "Evcs.Cluster.SelfConsumption") && + !(component.factoryId === "Evcs.Cluster.PeakShaving") && !component.isEnabled === false); this.consumptionMeterComponents = this.config?.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") .filter(component => component.isEnabled && this.config.isTypeConsumptionMetered(component)); - const sum: EdgeConfig.Component = this.config.getComponent('_sum'); - sum.alias = this.translate.instant('General.TOTAL'); + const sum: EdgeConfig.Component = this.config.getComponent("_sum"); + sum.alias = this.translate.instant("General.TOTAL"); this.navigationButtons = [sum, ...this.evcsComponents, ...this.consumptionMeterComponents].map(el => ( - { id: el.id, alias: el.alias, callback: () => { this.router.navigate(['./' + el.id], { relativeTo: this.route }); } } + { id: el.id, alias: el.alias, callback: () => { this.router.navigate(["./" + el.id], { relativeTo: this.route }); } } )); return []; 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 c6cf681d16e..2abfaee9aed 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 @@ -8,8 +8,8 @@ import { QueryHistoricTimeseriesEnergyResponse } from "src/app/shared/jsonrpc/re export namespace History { - export const LINE_CHART_OPTIONS = (period: string, chartType: 'line' | 'bar', options: { [key: string]: { scale: { min: number, max: number; } | null, ticks: { stepSize: number }; }; }): OeChartTester.Dataset.Option => ({ - type: 'option', + export const LINE_CHART_OPTIONS = (period: string, chartType: "line" | "bar", options: { [key: string]: { scale: { min: number, max: number; } | null, ticks: { stepSize: number }; }; }): OeChartTester.Dataset.Option => ({ + type: "option", options: { "responsive": true, "maintainAspectRatio": false, "elements": { "point": { "radius": 0, "hitRadius": 0, "hoverRadius": 0 }, "line": { "stepped": false, "fill": true } }, "datasets": { "bar": {}, "line": {} }, "plugins": { @@ -17,7 +17,7 @@ export namespace History { "enabled": false, }, "legend": { - "display": true, "position": "bottom", "labels": { "color": '' }, + "display": true, "position": "bottom", "labels": { "color": "" }, }, "tooltip": { "intersect": false, "mode": "index", "callbacks": {}, }, @@ -30,14 +30,14 @@ export namespace History { }, "scales": { "x": { "stacked": true, "offset": false, "type": "time", "ticks": { "source": "auto", "maxTicksLimit": 31 }, "bounds": "ticks", "adapters": { "date": { "locale": { "code": "de", "formatLong": {}, "localize": {}, "match": {}, "options": { "weekStartsOn": 1, "firstWeekContainsDate": 4 } } } }, "time": { "unit": period as TimeUnit, "displayFormats": { "datetime": "yyyy-MM-dd HH:mm:ss", "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" } } }, "left": { - ...options["left"]?.scale, ...(chartType === 'line' ? { stacked: false } : {}), "beginAtZero": true, "title": { "text": "kW", "display": true, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, - "ticks": { ...options["left"]?.ticks, "color": '', "padding": 5, "maxTicksLimit": ChartConstants.NUMBER_OF_Y_AXIS_TICKS }, + ...options["left"]?.scale, ...(chartType === "line" ? { stacked: false } : {}), "beginAtZero": true, "title": { "text": "kW", "display": true, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, + "ticks": { ...options["left"]?.ticks, "color": "", "padding": 5, "maxTicksLimit": ChartConstants.NUMBER_OF_Y_AXIS_TICKS }, }, "right": { - ...options["right"]?.scale, ...(chartType === 'line' ? { stacked: false } : {}), "beginAtZero": true, "max": 100, "min": 0, "type": "linear", "title": { "text": "%", "display": true, "font": { "size": 11 }, "padding": 5 }, "position": "right", "grid": { "display": false }, + ...options["right"]?.scale, ...(chartType === "line" ? { stacked: false } : {}), "beginAtZero": true, "max": 100, "min": 0, "type": "linear", "title": { "text": "%", "display": true, "font": { "size": 11 }, "padding": 5 }, "position": "right", "grid": { "display": false }, "ticks": { ...options["right"]?.ticks, - "color": '', + "color": "", "padding": 5, "maxTicksLimit": ChartConstants.NUMBER_OF_Y_AXIS_TICKS, }, @@ -45,8 +45,8 @@ export namespace History { }, }, }); - export const BAR_CHART_OPTIONS = (period: string, chartType: 'line' | 'bar', options: { [key: string]: { scale: { min?: number, max?: number; }, ticks: { stepSize?: number; }; }; }): OeChartTester.Dataset.Option => ({ - type: 'option', + export const BAR_CHART_OPTIONS = (period: string, chartType: "line" | "bar", options: { [key: string]: { scale: { min?: number, max?: number; }, ticks: { stepSize?: number; }; }; }): OeChartTester.Dataset.Option => ({ + type: "option", options: { "responsive": true, "maintainAspectRatio": false, "elements": { "point": { "radius": 0, "hitRadius": 0, "hoverRadius": 0 }, "line": { "stepped": false, "fill": true } }, "datasets": { "bar": { "barPercentage": 1 }, "line": {} }, "plugins": { @@ -54,7 +54,7 @@ export namespace History { "enabled": false, }, "legend": { - "display": true, "position": "bottom", "labels": { "color": '' }, + "display": true, "position": "bottom", "labels": { "color": "" }, }, "tooltip": { "intersect": false, "mode": "x", "callbacks": {}, }, @@ -67,10 +67,10 @@ export namespace History { }, "scales": { "x": { "stacked": true, "offset": true, "type": "time", "ticks": { "source": "auto", "maxTicksLimit": 31 }, "bounds": "ticks", "adapters": { "date": { "locale": { "code": "de", "formatLong": {}, "localize": {}, "match": {}, "options": { "weekStartsOn": 1, "firstWeekContainsDate": 4 } } } }, "time": { "unit": period as TimeUnit, "displayFormats": { "datetime": "yyyy-MM-dd HH:mm:ss", "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" } } }, "left": { - ...options["left"]?.scale, ...(chartType === 'line' ? { stacked: false } : {}), "beginAtZero": true, "title": { "text": "kWh", "display": true, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, + ...options["left"]?.scale, ...(chartType === "line" ? { stacked: false } : {}), "beginAtZero": true, "title": { "text": "kWh", "display": true, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, "ticks": { ...options["left"]?.ticks, - "color": '', + "color": "", "padding": 5, "maxTicksLimit": ChartConstants.NUMBER_OF_Y_AXIS_TICKS, }, @@ -87,17 +87,17 @@ export namespace History { export const DAY: OeTester.Types.Channels = ({ energyChannelWithValues: new QueryHistoricTimeseriesEnergyResponse("0", { data: { - '_sum/GridBuyActiveEnergy': 938, - '_sum/ConsumptionActiveEnergy': 24364, - '_sum/EssDcChargeEnergy': 15766, - '_sum/EssDcDischargeEnergy': 7209, - '_sum/GridSellActiveEnergy': 15615, - '_sum/ProductionActiveEnergy': 47597, + "_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, + "_sum/ConsumptionActivePower": [null, null, null, 112, @@ -385,9 +385,9 @@ export namespace History { 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], + "_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, + "_sum/EssSoc": [null, null, null, 80, @@ -675,7 +675,7 @@ export namespace History { null, null, null], - '_sum/EssActivePower': [null, + "_sum/EssActivePower": [null, null, null, 81, @@ -963,7 +963,7 @@ export namespace History { null, null, null], - '_sum/ProductionActivePower': [null, + "_sum/ProductionActivePower": [null, null, null, 0, @@ -1251,7 +1251,7 @@ export namespace History { null, null, null], - '_sum/ProductionDcActualPower': [null, + "_sum/ProductionDcActualPower": [null, null, null, 0, @@ -1839,17 +1839,17 @@ export namespace History { export const WEEK: OeTester.Types.Channels = { energyChannelWithValues: new QueryHistoricTimeseriesEnergyResponse("0", { data: { - '_sum/GridBuyActiveEnergy': 2368, - '_sum/ConsumptionActiveEnergy': 76690, - '_sum/EssDcChargeEnergy': 38671, - '_sum/EssDcDischargeEnergy': 31809, - '_sum/GridSellActiveEnergy': 119692, - '_sum/ProductionActiveEnergy': 200875, + "_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, + "_sum/ConsumptionActivePower": [160.22222222222223, 165.16666666666666, 149.91666666666666, 242.45454545454547, @@ -2017,7 +2017,7 @@ export namespace History { 444.625, 569.6, 131.5], - '_sum/GridActivePower': [-2.3333333333333335, + "_sum/GridActivePower": [-2.3333333333333335, 11.916666666666666, 16.333333333333332, 6.090909090909091, @@ -2186,7 +2186,7 @@ export namespace History { -9, -18.875], // 'GridSell': [6476, 6488, -1000, 0], - '_sum/EssSoc': [76.11111111111111, + "_sum/EssSoc": [76.11111111111111, 74.83333333333333, 73.75, 72.54545454545455, @@ -2354,7 +2354,7 @@ export namespace History { 85.875, 83.7, 80.5], - '_sum/EssActivePower': [162.55555555555554, + "_sum/EssActivePower": [162.55555555555554, 153.08333333333334, 133.58333333333334, 236.45454545454547, @@ -2522,7 +2522,7 @@ export namespace History { 439.375, 578.7, 150.375], - '_sum/ProductionActivePower': [0, + "_sum/ProductionActivePower": [0, 0, 0, 0, @@ -2690,7 +2690,7 @@ export namespace History { 61.5, 0.6, 0], - '_sum/ProductionDcActualPower': [0, + "_sum/ProductionDcActualPower": [0, 0, 0, 0, @@ -3037,18 +3037,18 @@ export namespace History { export const MONTH: OeTester.Types.Channels = { energyChannelWithValues: new QueryHistoricTimeseriesEnergyResponse("0", { data: { - '_sum/GridBuyActiveEnergy': 773000, - '_sum/ConsumptionActiveEnergy': 9976102, - '_sum/EssDcChargeEnergy': 3944328, - '_sum/EssDcDischargeEnergy': 3394430, - '_sum/GridSellActiveEnergy': 12738000, - '_sum/ProductionActiveEnergy': 22491000, + "_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, + "_sum/ConsumptionActiveEnergy": [320342, 346615, 341433, 333054, @@ -3279,18 +3279,18 @@ export namespace History { export const YEAR: OeTester.Types.Channels = { energyChannelWithValues: new QueryHistoricTimeseriesEnergyResponse("0", { data: { - '_sum/GridBuyActiveEnergy': 23209000, - '_sum/ConsumptionActiveEnergy': 58573394, - '_sum/EssDcChargeEnergy': 15296815, - '_sum/EssDcDischargeEnergy': 12898209, - '_sum/GridSellActiveEnergy': 30703000, - '_sum/ProductionActiveEnergy': 68466000, + "_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, + "_sum/ConsumptionActiveEnergy": [11634885, 8207927, 8976354, 8311835, 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 index abaa914fefe..0b7d24e89a5 100644 --- 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 @@ -5,7 +5,7 @@ import { EdgeConfig } from "src/app/shared/shared"; import { OeChartTester } from "../../../../../shared/components/shared/testing/tester"; import { ChartComponent } from "./chart"; -export function expectView(config: EdgeConfig, testContext: TestContext, chartType: 'line' | 'bar', channels: OeTester.Types.Channels, view: OeChartTester.View): void { +export function expectView(config: EdgeConfig, testContext: TestContext, chartType: "line" | "bar", channels: OeTester.Types.Channels, view: OeChartTester.View): void { expect(removeFunctions(OeChartTester .apply(ChartComponent .getChartData(DummyConfig.convertDummyEdgeConfigToRealEdgeConfig(config), chartType, testContext.translate), chartType, channels, testContext, config))) 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 312baba765b..cd1695a6c81 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 @@ -5,7 +5,7 @@ import { sharedSetup, TestContext } from "src/app/shared/components/shared/testi import { DATA, expectView, LABELS } from "./chart.constants.spec"; -describe('History EnergyMonitor', () => { +describe("History EnergyMonitor", () => { const defaultEMS = DummyConfig.from( DummyConfig.Component.SOCOMEC_GRID_METER("meter0", "Netzzähler"), DummyConfig.Component.ESS_GENERIC_MANAGEDSYMMETRIC("ess0"), @@ -17,24 +17,24 @@ describe('History EnergyMonitor', () => { TEST_CONTEXT = await sharedSetup(), ); - it('getChartData()', () => { + it("getChartData()", () => { { // Line - Chart - expectView(defaultEMS, TEST_CONTEXT, 'line', History.DAY, + expectView(defaultEMS, TEST_CONTEXT, "line", History.DAY, { datasets: { data: [ - 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('Einspeisung: 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('Bezug: 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('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("Einspeisung: 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("Bezug: 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("Ladezustand", History.DAY.dataChannelWithValues.result.data["_sum/EssSoc"]), ], labels: LABELS(History.DAY.dataChannelWithValues.result.timestamps), - options: History.LINE_CHART_OPTIONS('hour', 'line', { - ['right']: { ticks: { stepSize: 20 }, scale: null }, + options: History.LINE_CHART_OPTIONS("hour", "line", { + ["right"]: { ticks: { stepSize: 20 }, scale: null }, }), }, }); @@ -42,78 +42,78 @@ describe('History EnergyMonitor', () => { { // Line-Chart - expectView(defaultEMS, TEST_CONTEXT, 'line', History.WEEK, + expectView(defaultEMS, TEST_CONTEXT, "line", History.WEEK, { datasets: { data: [ - 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('Einspeisung: 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('Bezug: 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('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("Einspeisung: 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("Bezug: 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("Ladezustand", History.WEEK.dataChannelWithValues.result.data["_sum/EssSoc"]), ], labels: LABELS(History.WEEK.dataChannelWithValues.result.timestamps), - options: History.LINE_CHART_OPTIONS('day', 'line', { ['right']: { ticks: { stepSize: 20 }, scale: null } }), + options: History.LINE_CHART_OPTIONS("day", "line", { ["right"]: { ticks: { stepSize: 20 }, scale: null } }), }, }); } { // Bar-Chart Year - expectView(defaultEMS, TEST_CONTEXT, 'bar', History.MONTH, + 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]), + 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, null, 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, null, 360.727, 171.324, 206.255, null, 442.327, 225.59, 227.751, null]), - DATA('Direktverbrauch: 5.808,7 kWh', [191.524, 214.083, 198.811, 196.842, 184.218, 201.167, 175.916, null, 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, null, 360.727, 171.324, 206.255, null, 442.327, 225.59, 227.751, null]), - 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('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('Einspeisung: 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('Bezug: 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]), + DATA("Direktverbrauch: 5.808,7 kWh", [191.524, 214.083, 198.811, 196.842, 184.218, 201.167, 175.916, null, 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, null, 360.727, 171.324, 206.255, null, 442.327, 225.59, 227.751, null]), + DATA("Direktverbrauch: 5.808,7 kWh", [191.524, 214.083, 198.811, 196.842, 184.218, 201.167, 175.916, null, 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, null, 360.727, 171.324, 206.255, null, 442.327, 225.59, 227.751, null]), + 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("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("Einspeisung: 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("Bezug: 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', {}), + options: History.BAR_CHART_OPTIONS("day", "bar", {}), }, }); } { // Bar-Chart - Year - expectView(defaultEMS, TEST_CONTEXT, 'bar', History.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]), + 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, null, null, null, null, null]), - DATA('Direktverbrauch: 22.466,2 kWh', [1597.394, 2056.891, 3150.228, 3720.697, 5506.053, 5808.6720000000005, 546.405, null, null, null, null, null]), - 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('Einspeisung: 30.703 kWh', [20, 86, 677, 3657, 12839, 12738, 627, null, null, null, null, null]), - DATA('Bezug: 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]), + DATA("Direktverbrauch: 22.466,2 kWh", [1597.394, 2056.891, 3150.228, 3720.697, 5506.053, 5808.6720000000005, 546.405, null, null, null, null, null]), + DATA("Direktverbrauch: 22.466,2 kWh", [1597.394, 2056.891, 3150.228, 3720.697, 5506.053, 5808.6720000000005, 546.405, null, null, null, null, null]), + 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("Einspeisung: 30.703 kWh", [20, 86, 677, 3657, 12839, 12738, 627, null, null, null, null, null]), + DATA("Bezug: 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', {}), + options: History.BAR_CHART_OPTIONS("month", "bar", {}), }, }); } { // Bar-Chart: no config const EMS = DummyConfig.from(); - expectView(EMS, TEST_CONTEXT, 'bar', History.YEAR, + expectView(EMS, TEST_CONTEXT, "bar", History.YEAR, { datasets: { data: [], labels: LABELS(History.YEAR.energyPerPeriodChannelWithValues.result.timestamps), - options: History.BAR_CHART_OPTIONS('month', 'bar', { + options: History.BAR_CHART_OPTIONS("month", "bar", { }), }, }); @@ -125,19 +125,19 @@ describe('History EnergyMonitor', () => { DummyConfig.Component.ESS_GENERIC_MANAGEDSYMMETRIC("ess0"), ); - expectView(EMS, TEST_CONTEXT, 'bar', History.YEAR, + 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('Einspeisung: 30.703 kWh', [20, 86, 677, 3657, 12839, 12738, 627, null, null, null, null, null]), - DATA('Bezug: 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]), + 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("Einspeisung: 30.703 kWh", [20, 86, 677, 3657, 12839, 12738, 627, null, null, null, null, null]), + DATA("Bezug: 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', {}), + options: History.BAR_CHART_OPTIONS("month", "bar", {}), }, }); } @@ -148,16 +148,16 @@ describe('History EnergyMonitor', () => { DummyConfig.Component.SOCOMEC_GRID_METER("meter0", "Netzzähler"), ); - expectView(EMS, TEST_CONTEXT, 'bar', History.YEAR, + expectView(EMS, TEST_CONTEXT, "bar", History.YEAR, { datasets: { data: [ - DATA('Einspeisung: 30.703 kWh', [20, 86, 677, 3657, 12839, 12738, 627, null, null, null, null, null]), - DATA('Bezug: 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]), + DATA("Einspeisung: 30.703 kWh", [20, 86, 677, 3657, 12839, 12738, 627, null, null, null, null, null]), + DATA("Bezug: 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', {}), + options: History.BAR_CHART_OPTIONS("month", "bar", {}), }, }); } @@ -168,16 +168,16 @@ describe('History EnergyMonitor', () => { DummyConfig.Component.ESS_GENERIC_MANAGEDSYMMETRIC("ess0"), ); - expectView(EMS, TEST_CONTEXT, 'bar', History.YEAR, + 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]), + 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', 'bar', {}), + options: History.BAR_CHART_OPTIONS("month", "bar", {}), }, }); } 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 1fb80029716..dff22346d79 100644 --- a/ui/src/app/edge/history/common/energy/chart/chart.ts +++ b/ui/src/app/edge/history/common/energy/chart/chart.ts @@ -1,68 +1,68 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { TranslateService } from '@ngx-translate/core'; -import { AbstractHistoryChart } from 'src/app/shared/components/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'; +import { Component } from "@angular/core"; +import { TranslateService } from "@ngx-translate/core"; +import { AbstractHistoryChart } from "src/app/shared/components/chart/abstracthistorychart"; +import { QueryHistoricTimeseriesEnergyResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse"; +import { ChartAxis, HistoryUtils, YAxisType } from "src/app/shared/service/utils"; +import { ChannelAddress, EdgeConfig, Utils } from "src/app/shared/shared"; @Component({ - selector: 'energychart', - templateUrl: '../../../../../shared/components/chart/abstracthistorychart.html', + selector: "energychart", + templateUrl: "../../../../../shared/components/chart/abstracthistorychart.html", }) export class ChartComponent extends AbstractHistoryChart { - public static getChartData(config: EdgeConfig | null, chartType: 'line' | 'bar', translate: TranslateService): HistoryUtils.ChartData { + public static getChartData(config: EdgeConfig | null, chartType: "line" | "bar", translate: TranslateService): HistoryUtils.ChartData { const input: HistoryUtils.InputChannel[] = config?.widgets.classes.reduce((arr: HistoryUtils.InputChannel[], key) => { const newObj = []; switch (key) { - case 'Energymonitor': - case 'Consumption': + case "Energymonitor": + case "Consumption": newObj.push({ - name: 'Consumption', - powerChannel: new ChannelAddress('_sum', 'ConsumptionActivePower'), - energyChannel: new ChannelAddress('_sum', 'ConsumptionActiveEnergy'), + name: "Consumption", + powerChannel: new ChannelAddress("_sum", "ConsumptionActivePower"), + energyChannel: new ChannelAddress("_sum", "ConsumptionActiveEnergy"), }); break; - case 'Common_Autarchy': - case 'Grid': + 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: "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 }), + 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': + case "Storage": newObj.push({ - name: 'EssSoc', - powerChannel: new ChannelAddress('_sum', 'EssSoc'), + name: "EssSoc", + powerChannel: new ChannelAddress("_sum", "EssSoc"), }, { - name: 'EssCharge', - powerChannel: new ChannelAddress('_sum', 'EssActivePower'), - energyChannel: new ChannelAddress('_sum', 'EssDcChargeEnergy'), + name: "EssCharge", + powerChannel: new ChannelAddress("_sum", "EssActivePower"), + energyChannel: new ChannelAddress("_sum", "EssDcChargeEnergy"), }, { - name: 'EssDischarge', - powerChannel: new ChannelAddress('_sum', 'EssActivePower'), - energyChannel: new ChannelAddress('_sum', 'EssDcDischargeEnergy'), + name: "EssDischarge", + powerChannel: new ChannelAddress("_sum", "EssActivePower"), + energyChannel: new ChannelAddress("_sum", "EssDcDischargeEnergy"), }); break; - case 'Common_Selfconsumption': - case 'Common_Production': + case "Common_Selfconsumption": + case "Common_Production": newObj.push({ - name: 'ProductionActivePower', - powerChannel: new ChannelAddress('_sum', 'ProductionActivePower'), - energyChannel: new ChannelAddress('_sum', 'ProductionActiveEnergy'), + 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; } @@ -76,92 +76,92 @@ export class ChartComponent extends AbstractHistoryChart { output: (data: HistoryUtils.ChannelData) => { return [ { - name: translate.instant('General.production'), - nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => energyValues.result.data['_sum/ProductionActiveEnergy'], - converter: () => data['ProductionActivePower'], - color: 'rgb(45,143,171)', + name: translate.instant("General.production"), + nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => energyValues.result.data["_sum/ProductionActiveEnergy"], + converter: () => data["ProductionActivePower"], + color: "rgb(45,143,171)", stack: 0, - hiddenOnInit: chartType == 'line' ? false : true, + hiddenOnInit: chartType == "line" ? false : true, order: 1, }, // DirectConsumption, displayed in stack 1 & 2, only one legenItem - ...[chartType === 'bar' && { - name: translate.instant('General.directConsumption'), + ...[chartType === "bar" && { + name: translate.instant("General.directConsumption"), nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => { - return Utils.subtractSafely(energyValues.result.data['_sum/ProductionActiveEnergy'], energyValues.result.data['_sum/GridSellActiveEnergy'], energyValues.result.data['_sum/EssDcChargeEnergy']); + return Utils.subtractSafely(energyValues.result.data["_sum/ProductionActiveEnergy"], energyValues.result.data["_sum/GridSellActiveEnergy"], energyValues.result.data["_sum/EssDcChargeEnergy"]); }, converter: () => - data['ProductionActivePower']?.map((value, index) => Utils.subtractSafely(value, data['GridSell'][index], data['EssCharge'][index])) + data["ProductionActivePower"]?.map((value, index) => Utils.subtractSafely(value, data["GridSell"][index], data["EssCharge"][index])) ?.map(value => HistoryUtils.ValueConverter.NEGATIVE_AS_ZERO(value)), - color: 'rgb(244,164,96)', + color: "rgb(244,164,96)", stack: [1, 2], order: 2, }], // Charge Power { - name: translate.instant('General.chargePower'), - nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => energyValues.result.data['_sum/EssDcChargeEnergy'], - converter: () => chartType === 'line' // - ? 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)', + name: translate.instant("General.chargePower"), + nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => energyValues.result.data["_sum/EssDcChargeEnergy"], + converter: () => chartType === "line" // + ? 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)", stack: 1, - ...(chartType === 'line' && { order: 6 }), + ...(chartType === "line" && { order: 6 }), }, // Discharge Power { - name: translate.instant('General.dischargePower'), - nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => energyValues.result.data['_sum/EssDcDischargeEnergy'], + name: translate.instant("General.dischargePower"), + nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => energyValues.result.data["_sum/EssDcDischargeEnergy"], converter: () => { - return chartType === 'line' ? - data['EssDischarge']?.map((value, index) => { - return HistoryUtils.ValueConverter.NEGATIVE_AS_ZERO(Utils.subtractSafely(value, data['ProductionDcActual']?.[index])); - }) : data['EssDischarge']; + return chartType === "line" ? + data["EssDischarge"]?.map((value, index) => { + return HistoryUtils.ValueConverter.NEGATIVE_AS_ZERO(Utils.subtractSafely(value, data["ProductionDcActual"]?.[index])); + }) : data["EssDischarge"]; }, - color: 'rgb(200,0,0)', + color: "rgb(200,0,0)", stack: 2, - ...(chartType === 'line' && { order: 5 }), + ...(chartType === "line" && { order: 5 }), }, // Sell to grid { - name: translate.instant('General.gridSellAdvanced'), - nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => energyValues.result.data['_sum/GridSellActiveEnergy'], - converter: () => data['GridSell'], - color: 'rgb(0,0,200)', + name: translate.instant("General.gridSellAdvanced"), + nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => energyValues.result.data["_sum/GridSellActiveEnergy"], + converter: () => data["GridSell"], + color: "rgb(0,0,200)", stack: 1, - ...(chartType === 'line' && { order: 4 }), + ...(chartType === "line" && { order: 4 }), }, // Buy from Grid { - name: translate.instant('General.gridBuyAdvanced'), - nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => energyValues.result.data['_sum/GridBuyActiveEnergy'], - converter: () => data['GridBuy'], - color: 'rgb(0,0,0)', + name: translate.instant("General.gridBuyAdvanced"), + nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => energyValues.result.data["_sum/GridBuyActiveEnergy"], + converter: () => data["GridBuy"], + color: "rgb(0,0,0)", stack: 2, - ...(chartType === 'line' && { order: 2 }), + ...(chartType === "line" && { order: 2 }), }, // Consumption { - name: translate.instant('General.consumption'), - nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => energyValues.result.data['_sum/ConsumptionActiveEnergy'], - converter: () => data['Consumption'], - color: 'rgb(253,197,7)', + name: translate.instant("General.consumption"), + nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => energyValues.result.data["_sum/ConsumptionActiveEnergy"], + converter: () => data["Consumption"], + color: "rgb(253,197,7)", stack: 3, - hiddenOnInit: chartType == 'line' ? false : true, - ...(chartType === 'line' && { order: 0 }), + hiddenOnInit: chartType == "line" ? false : true, + ...(chartType === "line" && { order: 0 }), }, - ...[chartType === 'line' && + ...[chartType === "line" && { - name: translate.instant('General.soc'), - converter: () => data['EssSoc']?.map(value => Utils.multiplySafely(value, 1000)), - color: 'rgb(189, 195, 199)', + name: translate.instant("General.soc"), + converter: () => data["EssSoc"]?.map(value => Utils.multiplySafely(value, 1000)), + color: "rgb(189, 195, 199)", borderDash: [10, 10], yAxisId: ChartAxis.RIGHT, stack: 1, @@ -169,12 +169,15 @@ export class ChartComponent extends AbstractHistoryChart { ]; }, tooltip: { - formatNumber: '1.0-2', + formatNumber: "1.0-2", afterTitle: (stack: string) => { - if (stack === "1") { - return translate.instant('General.production'); - } else if (stack === "2") { - return translate.instant('General.consumption'); + + if (chartType === "bar") { + if (stack === "1") { + return translate.instant("General.production"); + } else if (stack === "2") { + return translate.instant("General.consumption"); + } } return null; }, @@ -183,16 +186,16 @@ export class ChartComponent extends AbstractHistoryChart { // Left YAxis { - unit: YAxisTitle.ENERGY, - position: 'left', + unit: YAxisType.ENERGY, + position: "left", yAxisId: ChartAxis.LEFT, }, // Right Yaxis, only shown for line-chart - (chartType === 'line' && { - unit: YAxisTitle.PERCENTAGE, - customTitle: '%', - position: 'right', + (chartType === "line" && { + unit: YAxisType.PERCENTAGE, + customTitle: "%", + position: "right", yAxisId: ChartAxis.RIGHT, displayGrid: false, }), diff --git a/ui/src/app/edge/history/common/energy/energy.ts b/ui/src/app/edge/history/common/energy/energy.ts index fe07c430784..95ac46ccad6 100644 --- a/ui/src/app/edge/history/common/energy/energy.ts +++ b/ui/src/app/edge/history/common/energy/energy.ts @@ -1,9 +1,9 @@ -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; -import { SharedModule } from 'src/app/shared/shared.module'; +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'; +import { ChartComponent } from "./chart/chart"; +import { FlatComponent } from "./flat/flat"; @NgModule({ imports: [ diff --git a/ui/src/app/edge/history/common/energy/flat/flat.ts b/ui/src/app/edge/history/common/energy/flat/flat.ts index 3e500cdd718..49db6041eb6 100644 --- a/ui/src/app/edge/history/common/energy/flat/flat.ts +++ b/ui/src/app/edge/history/common/energy/flat/flat.ts @@ -1,24 +1,24 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { format, isSameDay, isSameMonth, isSameYear } from 'date-fns'; -import { saveAs } from 'file-saver-es'; -import { AppService } from 'src/app/app.service'; -import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; -import { QueryHistoricTimeseriesExportXlxsRequest } from 'src/app/shared/jsonrpc/request/queryHistoricTimeseriesExportXlxs'; -import { Base64PayloadResponse } from 'src/app/shared/jsonrpc/response/base64PayloadResponse'; -import { ChannelAddress, CurrentData, Utils } from '../../../../../shared/shared'; +import { Component } from "@angular/core"; +import { format, isSameDay, isSameMonth, isSameYear } from "date-fns"; +import { saveAs } from "file-saver-es"; +import { AppService } from "src/app/app.service"; +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; +import { QueryHistoricTimeseriesExportXlxsRequest } from "src/app/shared/jsonrpc/request/queryHistoricTimeseriesExportXlxs"; +import { Base64PayloadResponse } from "src/app/shared/jsonrpc/response/base64PayloadResponse"; +import { ChannelAddress, CurrentData, Utils } from "../../../../../shared/shared"; @Component({ - selector: 'energy', - templateUrl: './flat.html', + selector: "energy", + templateUrl: "./flat.html", }) export class FlatComponent extends AbstractFlatWidget { - private static readonly EXCEL_TYPE = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8'; - private static readonly EXCEL_EXTENSION = '.xlsx'; + private static readonly EXCEL_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8"; + private static readonly EXCEL_EXTENSION = ".xlsx"; protected autarchyValue: number | null; protected readonly isSmartphoneResolution = this.service.isSmartphoneResolution; - protected readonly isApp: boolean = AppService.platform !== 'web'; + protected readonly isApp: boolean = AppService.platform !== "web"; public getChartHeight(): number { return this.service.deviceHeight / 2; @@ -27,14 +27,14 @@ export class FlatComponent extends AbstractFlatWidget { protected override onCurrentData(currentData: CurrentData) { this.autarchyValue = Utils.calculateAutarchy( - currentData.allComponents['_sum/GridBuyActiveEnergy'] / 1000, - currentData.allComponents['_sum/ConsumptionActiveEnergy'] / 1000); + currentData.allComponents["_sum/GridBuyActiveEnergy"] / 1000, + currentData.allComponents["_sum/ConsumptionActiveEnergy"] / 1000); } protected override getChannelAddresses(): ChannelAddress[] { return [ - new ChannelAddress('_sum', 'GridBuyActiveEnergy'), - new ChannelAddress('_sum', 'ConsumptionActiveEnergy'), + new ChannelAddress("_sum", "GridBuyActiveEnergy"), + new ChannelAddress("_sum", "ConsumptionActiveEnergy"), ]; } @@ -44,14 +44,14 @@ export class FlatComponent extends AbstractFlatWidget { protected exportToXlxs() { if (this.isApp) { - this.service.toast(this.translate.instant('APP.FUNCTIONALITY_TEMPORARILY_NOT_AVAILABLE'), "warning"); + this.service.toast(this.translate.instant("APP.FUNCTIONALITY_TEMPORARILY_NOT_AVAILABLE"), "warning"); return; } this.service.getCurrentEdge().then(edge => { edge.sendRequest(this.websocket, new QueryHistoricTimeseriesExportXlxsRequest(this.service.historyPeriod.value.from, this.service.historyPeriod.value.to)).then(response => { const r = response as Base64PayloadResponse; - const binary = atob(r.result.payload.replace(/\s/g, '')); + const binary = atob(r.result.payload.replace(/\s/g, "")); const len = binary.length; const buffer = new ArrayBuffer(len); const view = new Uint8Array(buffer); diff --git a/ui/src/app/edge/history/common/grid/chart/chart.constants.spec.ts b/ui/src/app/edge/history/common/grid/chart/chart.constants.spec.ts index 1c3156cb6e5..bba5418804d 100644 --- a/ui/src/app/edge/history/common/grid/chart/chart.constants.spec.ts +++ b/ui/src/app/edge/history/common/grid/chart/chart.constants.spec.ts @@ -6,7 +6,7 @@ import { EdgeConfig } from "src/app/shared/shared"; import { ChartComponent } from "./chart"; -export function expectView(config: EdgeConfig, testContext: TestContext, chartType: 'line' | 'bar', channels: OeTester.Types.Channels, view: OeChartTester.View, showPhases: boolean): void { +export function expectView(config: EdgeConfig, testContext: TestContext, chartType: "line" | "bar", channels: OeTester.Types.Channels, view: OeChartTester.View, showPhases: boolean): void { expect(removeFunctions(OeChartTester .apply(ChartComponent .getChartData(DummyConfig.convertDummyEdgeConfigToRealEdgeConfig(config), chartType, testContext.translate, showPhases), chartType, channels, testContext, config))) diff --git a/ui/src/app/edge/history/common/grid/chart/chart.spec.ts b/ui/src/app/edge/history/common/grid/chart/chart.spec.ts index f2bf6848a0a..64c0455cdf2 100644 --- a/ui/src/app/edge/history/common/grid/chart/chart.spec.ts +++ b/ui/src/app/edge/history/common/grid/chart/chart.spec.ts @@ -8,7 +8,7 @@ import { ChartAxis } from "src/app/shared/service/utils"; import { DATA, LABELS } from "../../energy/chart/chart.constants.spec"; import { expectView } from "./chart.constants.spec"; -describe('History Grid', () => { +describe("History Grid", () => { const edgeConfigWithOutController14a = DummyConfig.from( DummyConfig.Component.SOCOMEC_GRID_METER("meter0", "Netzzähler"), @@ -24,18 +24,18 @@ describe('History Grid', () => { TEST_CONTEXT = await sharedSetup(), ); - it('#getChartData()', () => { + it("#getChartData()", () => { { // Line - Chart - without Controller 14a - expectView(edgeConfigWithOutController14a, TEST_CONTEXT, 'line', History.DAY, + expectView(edgeConfigWithOutController14a, TEST_CONTEXT, "line", History.DAY, { datasets: { data: [ - DATA('Einspeisung: 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('Bezug: 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("Einspeisung: 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("Bezug: 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]), ], labels: LABELS(History.DAY.dataChannelWithValues.result.timestamps), - options: OeTester.ChartOptions.LINE_CHART_OPTIONS('hour', 'line', { + options: OeTester.ChartOptions.LINE_CHART_OPTIONS("hour", "line", { [ChartAxis.LEFT]: { scale: { beginAtZero: true } }, }), }, @@ -43,48 +43,48 @@ describe('History Grid', () => { } { // Line - Chart - expectView(edgeConfig, TEST_CONTEXT, 'line', History.DAY, + expectView(edgeConfig, TEST_CONTEXT, "line", History.DAY, { datasets: { data: [ - DATA('Einspeisung: 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('Bezug: 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("Einspeisung: 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("Bezug: 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]), ], labels: LABELS(History.DAY.dataChannelWithValues.result.timestamps), - options: OeTester.ChartOptions.MULTI_LINE_OPTIONS('hour', 'line', { - ['right']: { scale: { max: 1, min: 0 }, ticks: { stepSize: 1 } }, + options: OeTester.ChartOptions.MULTI_LINE_OPTIONS("hour", "line", { + ["right"]: { scale: { max: 1, min: 0 }, ticks: { stepSize: 1 } }, }), }, }, false); } { // Line - Chart - expectView(edgeConfig, TEST_CONTEXT, 'line', History.WEEK, + expectView(edgeConfig, TEST_CONTEXT, "line", History.WEEK, { datasets: { data: [ - DATA('Einspeisung: 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('Bezug: 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("Einspeisung: 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("Bezug: 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]), ], labels: LABELS(History.WEEK.dataChannelWithValues.result.timestamps), - options: OeTester.ChartOptions.MULTI_LINE_OPTIONS('day', 'line', { - ['right']: { scale: { max: 1, min: 0 }, ticks: { stepSize: 1 } }, + options: OeTester.ChartOptions.MULTI_LINE_OPTIONS("day", "line", { + ["right"]: { scale: { max: 1, min: 0 }, ticks: { stepSize: 1 } }, }), }, }, false); } { // Line - Chart - expectView(edgeConfig, TEST_CONTEXT, 'bar', History.MONTH, + expectView(edgeConfig, TEST_CONTEXT, "bar", History.MONTH, { datasets: { data: [ - DATA('Einspeisung: 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('Bezug: 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("Einspeisung: 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("Bezug: 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]), ], labels: LABELS(History.MONTH.energyPerPeriodChannelWithValues.result.timestamps), - options: OeTester.ChartOptions.MULTI_BAR_OPTIONS('day', 'bar', { - ['right']: { scale: {}, ticks: { stepSize: 1 } }, + options: OeTester.ChartOptions.MULTI_BAR_OPTIONS("day", "bar", { + ["right"]: { scale: {}, ticks: { stepSize: 1 } }, }), }, @@ -92,16 +92,16 @@ describe('History Grid', () => { } { // BAR - Chart - expectView(edgeConfig, TEST_CONTEXT, 'bar', History.YEAR, + expectView(edgeConfig, TEST_CONTEXT, "bar", History.YEAR, { datasets: { data: [ - DATA('Einspeisung: 30.703 kWh', [20, 86, 677, 3657, 12839, 12738, 627, null, null, null, null, null]), - DATA('Bezug: 23.209 kWh', [9829, 4812, 2915, 2036, 2712, 773, 94, null, null, null, null, null]), + DATA("Einspeisung: 30.703 kWh", [20, 86, 677, 3657, 12839, 12738, 627, null, null, null, null, null]), + DATA("Bezug: 23.209 kWh", [9829, 4812, 2915, 2036, 2712, 773, 94, null, null, null, null, null]), ], labels: LABELS(History.YEAR.energyPerPeriodChannelWithValues.result.timestamps), - options: OeTester.ChartOptions.MULTI_BAR_OPTIONS('month', 'bar', { - ['right']: { scale: {}, ticks: { stepSize: 1 } }, + options: OeTester.ChartOptions.MULTI_BAR_OPTIONS("month", "bar", { + ["right"]: { scale: {}, ticks: { stepSize: 1 } }, }), }, }, false); diff --git a/ui/src/app/edge/history/common/grid/chart/chart.ts b/ui/src/app/edge/history/common/grid/chart/chart.ts index 3198760bcb3..f195179022c 100644 --- a/ui/src/app/edge/history/common/grid/chart/chart.ts +++ b/ui/src/app/edge/history/common/grid/chart/chart.ts @@ -1,77 +1,77 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { TranslateService } from '@ngx-translate/core'; -import { BoxAnnotationOptions } from 'chartjs-plugin-annotation'; -import { GridSectionComponent } from 'src/app/edge/live/energymonitor/chart/section/grid.component'; -import { AbstractHistoryChart } from 'src/app/shared/components/chart/abstracthistorychart'; -import { QueryHistoricTimeseriesEnergyResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; -import { ChartAxis, HistoryUtils, YAxisTitle } from 'src/app/shared/service/utils'; -import { ChannelAddress, EdgeConfig } from 'src/app/shared/shared'; -import { ChartAnnotationState } from 'src/app/shared/type/general'; +import { Component } from "@angular/core"; +import { TranslateService } from "@ngx-translate/core"; +import { BoxAnnotationOptions } from "chartjs-plugin-annotation"; +import { GridSectionComponent } from "src/app/edge/live/energymonitor/chart/section/grid.component"; +import { AbstractHistoryChart } from "src/app/shared/components/chart/abstracthistorychart"; +import { QueryHistoricTimeseriesEnergyResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse"; +import { ChartAxis, HistoryUtils, YAxisType } from "src/app/shared/service/utils"; +import { ChannelAddress, EdgeConfig } from "src/app/shared/shared"; +import { ChartAnnotationState } from "src/app/shared/type/general"; @Component({ - selector: 'gridchart', - templateUrl: '../../../../../shared/components/chart/abstracthistorychart.html', + selector: "gridchart", + templateUrl: "../../../../../shared/components/chart/abstracthistorychart.html", }) export class ChartComponent extends AbstractHistoryChart { - public static getChartData(config: EdgeConfig, chartType: 'line' | 'bar', translate: TranslateService, showPhases: boolean): HistoryUtils.ChartData { + public static getChartData(config: EdgeConfig, chartType: "line" | "bar", translate: TranslateService, showPhases: boolean): HistoryUtils.ChartData { const input: HistoryUtils.InputChannel[] = [ { - name: 'GridSell', - powerChannel: ChannelAddress.fromString('_sum/GridActivePower'), - energyChannel: ChannelAddress.fromString('_sum/GridSellActiveEnergy'), - ...(chartType === 'line' && { converter: HistoryUtils.ValueConverter.ONLY_NEGATIVE_AND_NEGATIVE_AS_POSITIVE }), + name: "GridSell", + powerChannel: ChannelAddress.fromString("_sum/GridActivePower"), + energyChannel: ChannelAddress.fromString("_sum/GridSellActiveEnergy"), + ...(chartType === "line" && { converter: HistoryUtils.ValueConverter.ONLY_NEGATIVE_AND_NEGATIVE_AS_POSITIVE }), }, { - name: 'GridBuy', - powerChannel: ChannelAddress.fromString('_sum/GridActivePower'), - energyChannel: ChannelAddress.fromString('_sum/GridBuyActiveEnergy'), + name: "GridBuy", + powerChannel: ChannelAddress.fromString("_sum/GridActivePower"), + energyChannel: ChannelAddress.fromString("_sum/GridBuyActiveEnergy"), converter: HistoryUtils.ValueConverter.NEGATIVE_AS_ZERO, }, ]; if (GridSectionComponent.isControllerEnabled(config, "Controller.Ess.Limiter14a")) { input.push({ - name: 'Restriction', - powerChannel: ChannelAddress.fromString('ctrlEssLimiter14a0/RestrictionMode'), - energyChannel: ChannelAddress.fromString('ctrlEssLimiter14a0/CumulatedRestrictionTime'), + name: "Restriction", + powerChannel: ChannelAddress.fromString("ctrlEssLimiter14a0/RestrictionMode"), + energyChannel: ChannelAddress.fromString("ctrlEssLimiter14a0/CumulatedRestrictionTime"), }); input.push({ - name: 'OffGrid', - powerChannel: ChannelAddress.fromString('_sum/GridMode'), - energyChannel: ChannelAddress.fromString('_sum/GridModeOffGridTime'), + name: "OffGrid", + powerChannel: ChannelAddress.fromString("_sum/GridMode"), + energyChannel: ChannelAddress.fromString("_sum/GridModeOffGridTime"), }); } if (showPhases) { - ['L1', 'L2', 'L3'].forEach(phase => { + ["L1", "L2", "L3"].forEach(phase => { input.push({ - name: 'GridActivePower' + phase, - powerChannel: ChannelAddress.fromString('_sum/GridActivePower' + phase), + name: "GridActivePower" + phase, + powerChannel: ChannelAddress.fromString("_sum/GridActivePower" + phase), }); }); } const yAxes: HistoryUtils.yAxes[] = [{ - unit: YAxisTitle.ENERGY, - position: 'left', + unit: YAxisType.ENERGY, + position: "left", yAxisId: ChartAxis.LEFT, }]; if (GridSectionComponent.isControllerEnabled(config, "Controller.Ess.Limiter14a")) { - yAxes.push((chartType === 'bar' ? + yAxes.push((chartType === "bar" ? { - unit: YAxisTitle.TIME, - position: 'right', + unit: YAxisType.TIME, + position: "right", yAxisId: ChartAxis.RIGHT, displayGrid: false, } : { - unit: YAxisTitle.RELAY, - position: 'right', + unit: YAxisType.RELAY, + position: "right", yAxisId: ChartAxis.RIGHT, - customTitle: translate.instant('General.state'), + customTitle: translate.instant("General.state"), displayGrid: false, } )); @@ -84,46 +84,46 @@ export class ChartComponent extends AbstractHistoryChart { let restrictionData; let offGridData; - if (chartType === 'line') { + if (chartType === "line") { // Convert values > 0 to 1 (=on) - restrictionData = data['Restriction']?.map((value) => (value > 0 ? ChartAnnotationState.ON : ChartAnnotationState.OFF_HIDDEN)); + restrictionData = data["Restriction"]?.map((value) => (value > 0 ? ChartAnnotationState.ON : ChartAnnotationState.OFF_HIDDEN)); // Off-Grid (=2) to on (=1) - offGridData = data['OffGrid']?.map((value) => (value * 1000 > 1 ? ChartAnnotationState.ON : ChartAnnotationState.OFF_HIDDEN)); + offGridData = data["OffGrid"]?.map((value) => (value * 1000 > 1 ? ChartAnnotationState.ON : ChartAnnotationState.OFF_HIDDEN)); } else { - restrictionData = data['Restriction']?.map((value) => value * 1000); - offGridData = data['OffGrid']?.map((value) => value * 1000); + restrictionData = data["Restriction"]?.map((value) => value * 1000); + offGridData = data["OffGrid"]?.map((value) => value * 1000); } const datasets: HistoryUtils.DisplayValue[] = [ { - name: translate.instant('General.gridSellAdvanced'), - nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => energyValues?.result.data['_sum/GridSellActiveEnergy'] ?? null, - converter: () => data['GridSell'], - color: 'rgba(0,0,200)', + name: translate.instant("General.gridSellAdvanced"), + nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => energyValues?.result.data["_sum/GridSellActiveEnergy"] ?? null, + converter: () => data["GridSell"], + color: "rgba(0,0,200)", stack: 1, }, { - name: translate.instant('General.gridBuyAdvanced'), + name: translate.instant("General.gridBuyAdvanced"), nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => { - return energyValues?.result.data['_sum/GridBuyActiveEnergy'] ?? null; + return energyValues?.result.data["_sum/GridBuyActiveEnergy"] ?? null; }, - converter: () => data['GridBuy'], - color: 'rgb(0,0,0)', + converter: () => data["GridBuy"], + color: "rgb(0,0,0)", stack: 0, }, offGridData ? ({ - name: translate.instant('GRID_STATES.OFF_GRID'), - nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => energyValues?.result.data['_sum/GridModeOffGridTime'], + name: translate.instant("GRID_STATES.OFF_GRID"), + nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => energyValues?.result.data["_sum/GridModeOffGridTime"], converter: () => offGridData, - color: 'rgb(139,0,0)', + color: "rgb(139,0,0)", stack: 2, custom: ( - chartType === 'line' ? { - unit: YAxisTitle.RELAY, - pluginType: 'box', + chartType === "line" ? { + unit: YAxisType.RELAY, + pluginType: "box", annotations: getAnnotations(offGridData, labels), } : { - unit: YAxisTitle.TIME, + unit: YAxisType.TIME, } ), yAxisId: ChartAxis.RIGHT, @@ -133,17 +133,17 @@ export class ChartComponent extends AbstractHistoryChart { // Show the controller data only if the controller is enabled and there was at least one limitation set(=1) on the current day. GridSectionComponent.isControllerEnabled(config, "Controller.Ess.Limiter14a") ? ({ name: translate.instant("GRID_STATES.RESTRICTION"), - nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => energyValues?.result.data['ctrlEssLimiter14a0/CumulatedRestrictionTime'], + nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => energyValues?.result.data["ctrlEssLimiter14a0/CumulatedRestrictionTime"], converter: () => restrictionData, - color: 'rgb(255, 165, 0)', + color: "rgb(255, 165, 0)", stack: 2, custom: ( - chartType === 'line' ? { - unit: YAxisTitle.RELAY, - pluginType: 'box', + chartType === "line" ? { + unit: YAxisType.RELAY, + pluginType: "box", annotations: getAnnotations(restrictionData, labels), } : { - unit: YAxisTitle.TIME, + unit: YAxisType.TIME, } ), yAxisId: ChartAxis.RIGHT, @@ -155,11 +155,11 @@ export class ChartComponent extends AbstractHistoryChart { return datasets; } - ['L1', 'L2', 'L3'].forEach((phase, index) => { + ["L1", "L2", "L3"].forEach((phase, index) => { datasets.push({ - name: 'Phase ' + phase, - nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => energyValues?.result.data['_sum/GridActivePower' + phase], - converter: () => data['GridActivePower' + phase] ?? null, + name: "Phase " + phase, + nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => energyValues?.result.data["_sum/GridActivePower" + phase], + converter: () => data["GridActivePower" + phase] ?? null, color: AbstractHistoryChart.phaseColors[index], stack: 3, }); @@ -168,7 +168,7 @@ export class ChartComponent extends AbstractHistoryChart { return datasets; }, tooltip: { - formatNumber: '1.0-2', + formatNumber: "1.0-2", }, yAxes: yAxes, }; @@ -183,9 +183,9 @@ export class ChartComponent extends AbstractHistoryChart { if (data) { const limitationEpochs = getLimitationEpochs(data); const restrictionAnnotations = limitationEpochs.map(e => ({ - type: 'box', + type: "box", borderWidth: 1, - xScaleID: 'x', + xScaleID: "x", yMin: null, yMax: null, xMin: labels[e.start].toISOString(), diff --git a/ui/src/app/edge/history/common/grid/details/chart/channels.spec.ts b/ui/src/app/edge/history/common/grid/details/chart/channels.spec.ts index 1d89d965adf..dda556efe21 100644 --- a/ui/src/app/edge/history/common/grid/details/chart/channels.spec.ts +++ b/ui/src/app/edge/history/common/grid/details/chart/channels.spec.ts @@ -17,10 +17,10 @@ export namespace History { }), dataChannelWithValues: new QueryHistoricTimeseriesDataResponse("0", { data: { - '_sum/GridActivePower': [124, 0, null, 0, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 110, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 140, null, null, null, 2127, 175, 176, null, 180, 180, 185, 180, null, 185, 190, 180, 180, 176, 176, 170, 175, 170, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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/GridActivePowerL1': [41, 0, null, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 38, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 47, null, null, null, 709, 58, 59, null, 60, 60, 62, 60, null, 62, 63, 60, 60, 59, 59, 57, 58, 57, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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/GridActivePowerL2': [41, 0, null, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 38, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 47, null, null, null, 709, 58, 59, null, 60, 60, 62, 60, null, 62, 63, 60, 60, 59, 59, 57, 58, 57, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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/GridActivePowerL3': [41, 0, null, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 38, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 47, null, null, null, 709, 58, 59, null, 60, 60, 62, 60, null, 62, 63, 60, 60, 59, 59, 57, 58, 57, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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": [124, 0, null, 0, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 110, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 140, null, null, null, 2127, 175, 176, null, 180, 180, 185, 180, null, 185, 190, 180, 180, 176, 176, 170, 175, 170, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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/GridActivePowerL1": [41, 0, null, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 38, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 47, null, null, null, 709, 58, 59, null, 60, 60, 62, 60, null, 62, 63, 60, 60, 59, 59, 57, 58, 57, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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/GridActivePowerL2": [41, 0, null, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 38, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 47, null, null, null, 709, 58, 59, null, 60, 60, 62, 60, null, 62, 63, 60, 60, 59, 59, 57, 58, 57, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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/GridActivePowerL3": [41, 0, null, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 38, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 47, null, null, null, 709, 58, 59, null, 60, 60, 62, 60, null, 62, 63, 60, 60, 59, 59, 57, 58, 57, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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"], }), diff --git a/ui/src/app/edge/history/common/grid/details/chart/chart.spec.ts b/ui/src/app/edge/history/common/grid/details/chart/chart.spec.ts index 5866fa9f23d..286718266cf 100644 --- a/ui/src/app/edge/history/common/grid/details/chart/chart.spec.ts +++ b/ui/src/app/edge/history/common/grid/details/chart/chart.spec.ts @@ -9,47 +9,47 @@ import { DATA, LABELS } from "../../../energy/chart/chart.constants.spec"; import { History } from "./channels.spec"; import { ChartComponent } from "./chart"; -describe('History Grid Details - _sum', () => { +describe("History Grid Details - _sum", () => { const defaultEMS = DummyConfig.from( DummyConfig.Component.SUM("_sum"), ); let TEST_CONTEXT: TestContext & { route: ActivatedRoute }; beforeEach(async () => { - TEST_CONTEXT = await sharedSetupWithComponentIdRoute('_sum'); + TEST_CONTEXT = await sharedSetupWithComponentIdRoute("_sum"); }); - it('#getChartData()', () => { + it("#getChartData()", () => { { - expectView(defaultEMS, TEST_CONTEXT, 'line', History.DAY, + expectView(defaultEMS, TEST_CONTEXT, "line", History.DAY, { datasets: { data: [ - DATA('Gesamt', [0.124, 0, null, 0, 0.173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.11, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.13, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.14, null, null, null, 2.127, 0.175, 0.176, null, 0.18, 0.18, 0.185, 0.18, null, 0.185, 0.19, 0.18, 0.18, 0.176, 0.176, 0.17, 0.175, 0.17, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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('Phase L1', [0.041, 0, null, 0, 0.058, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.037, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.048, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.038, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.043, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.047, null, null, null, 0.709, 0.058, 0.059, null, 0.06, 0.06, 0.062, 0.06, null, 0.062, 0.063, 0.06, 0.06, 0.059, 0.059, 0.057, 0.058, 0.057, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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('Phase L2', [0.041, 0, null, 0, 0.058, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.037, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.048, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.038, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.043, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.047, null, null, null, 0.709, 0.058, 0.059, null, 0.06, 0.06, 0.062, 0.06, null, 0.062, 0.063, 0.06, 0.06, 0.059, 0.059, 0.057, 0.058, 0.057, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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('Phase L3', [0.041, 0, null, 0, 0.058, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.037, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.048, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.038, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.043, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.047, null, null, null, 0.709, 0.058, 0.059, null, 0.06, 0.06, 0.062, 0.06, null, 0.062, 0.063, 0.06, 0.06, 0.059, 0.059, 0.057, 0.058, 0.057, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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("Gesamt", [0.124, 0, null, 0, 0.173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.11, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.13, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.14, null, null, null, 2.127, 0.175, 0.176, null, 0.18, 0.18, 0.185, 0.18, null, 0.185, 0.19, 0.18, 0.18, 0.176, 0.176, 0.17, 0.175, 0.17, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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("Phase L1", [0.041, 0, null, 0, 0.058, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.037, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.048, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.038, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.043, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.047, null, null, null, 0.709, 0.058, 0.059, null, 0.06, 0.06, 0.062, 0.06, null, 0.062, 0.063, 0.06, 0.06, 0.059, 0.059, 0.057, 0.058, 0.057, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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("Phase L2", [0.041, 0, null, 0, 0.058, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.037, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.048, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.038, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.043, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.047, null, null, null, 0.709, 0.058, 0.059, null, 0.06, 0.06, 0.062, 0.06, null, 0.062, 0.063, 0.06, 0.06, 0.059, 0.059, 0.057, 0.058, 0.057, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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("Phase L3", [0.041, 0, null, 0, 0.058, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.037, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.048, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.038, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.043, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.047, null, null, null, 0.709, 0.058, 0.059, null, 0.06, 0.06, 0.062, 0.06, null, 0.062, 0.063, 0.06, 0.06, 0.059, 0.059, 0.057, 0.058, 0.057, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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: OeTester.ChartOptions.LINE_CHART_OPTIONS('hour', 'line', { 'left': { scale: { beginAtZero: true } } }, + options: OeTester.ChartOptions.LINE_CHART_OPTIONS("hour", "line", { "left": { scale: { beginAtZero: true } } }, ), }, }); } { - expectView(defaultEMS, TEST_CONTEXT, 'bar', History.MONTH, + expectView(defaultEMS, TEST_CONTEXT, "bar", History.MONTH, { datasets: { data: [], labels: LABELS(History.MONTH.energyPerPeriodChannelWithValues.result.timestamps), - options: OeTester.ChartOptions.BAR_CHART_OPTIONS('hour', 'bar', {}), + options: OeTester.ChartOptions.BAR_CHART_OPTIONS("hour", "bar", {}), }, }); } }); }); -export function expectView(config: EdgeConfig, testContext: TestContext & { route: ActivatedRoute }, chartType: 'line' | 'bar', channels: OeTester.Types.Channels, view: OeChartTester.View): void { +export function expectView(config: EdgeConfig, testContext: TestContext & { route: ActivatedRoute }, chartType: "line" | "bar", channels: OeTester.Types.Channels, view: OeChartTester.View): void { expect(removeFunctions(OeChartTester .apply(ChartComponent .getChartData( diff --git a/ui/src/app/edge/history/common/grid/details/chart/chart.ts b/ui/src/app/edge/history/common/grid/details/chart/chart.ts index 8368db9f96a..c941630eb8a 100644 --- a/ui/src/app/edge/history/common/grid/details/chart/chart.ts +++ b/ui/src/app/edge/history/common/grid/details/chart/chart.ts @@ -1,15 +1,15 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { TranslateService } from '@ngx-translate/core'; -import { AbstractHistoryChart } from 'src/app/shared/components/chart/abstracthistorychart'; -import { Phase } from 'src/app/shared/components/shared/phase'; -import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; -import { ChartAxis, HistoryUtils, YAxisTitle } from 'src/app/shared/service/utils'; -import { ChannelAddress } from 'src/app/shared/shared'; +import { Component } from "@angular/core"; +import { TranslateService } from "@ngx-translate/core"; +import { AbstractHistoryChart } from "src/app/shared/components/chart/abstracthistorychart"; +import { Phase } from "src/app/shared/components/shared/phase"; +import { DefaultTypes } from "src/app/shared/service/defaulttypes"; +import { ChartAxis, HistoryUtils, YAxisType } from "src/app/shared/service/utils"; +import { ChannelAddress } from "src/app/shared/shared"; @Component({ - selector: 'gridDetailsChart', - templateUrl: '../../../../../../shared/components/chart/abstracthistorychart.html', + selector: "gridDetailsChart", + templateUrl: "../../../../../../shared/components/chart/abstracthistorychart.html", }) export class ChartComponent extends AbstractHistoryChart { @@ -17,12 +17,12 @@ export class ChartComponent extends AbstractHistoryChart { return { input: [ { - name: 'GridActivePower', - powerChannel: ChannelAddress.fromString('_sum/GridActivePower'), + name: "GridActivePower", + powerChannel: ChannelAddress.fromString("_sum/GridActivePower"), }, ...Phase.THREE_PHASE.map((phase, index) => ({ - name: 'Phase' + phase, - powerChannel: ChannelAddress.fromString('_sum/GridActivePower' + phase), + name: "Phase" + phase, + powerChannel: ChannelAddress.fromString("_sum/GridActivePower" + phase), })), ], output: (data: DefaultTypes.History.ChannelData) => { @@ -30,17 +30,17 @@ export class ChartComponent extends AbstractHistoryChart { const datasets: DefaultTypes.History.DisplayValues[] = [ { - name: translate.instant('General.TOTAL'), + name: translate.instant("General.TOTAL"), converter: () => { - return data['GridActivePower']; + return data["GridActivePower"]; }, - color: 'rgba(0,0,200)', + color: "rgba(0,0,200)", stack: 1, }, ...Phase.THREE_PHASE.map((phase, index) => ({ - name: 'Phase ' + phase, + name: "Phase " + phase, converter: () => { - return data['Phase' + phase]; + return data["Phase" + phase]; }, color: AbstractHistoryChart.phaseColors[index], })), @@ -49,11 +49,11 @@ export class ChartComponent extends AbstractHistoryChart { return datasets; }, tooltip: { - formatNumber: '1.0-2', + formatNumber: "1.0-2", }, yAxes: [{ - unit: YAxisTitle.ENERGY, - position: 'left', + unit: YAxisType.ENERGY, + position: "left", yAxisId: ChartAxis.LEFT, }], }; diff --git a/ui/src/app/edge/history/common/grid/details/details.overview.ts b/ui/src/app/edge/history/common/grid/details/details.overview.ts index b85fb0f5970..179c6ca5ce5 100644 --- a/ui/src/app/edge/history/common/grid/details/details.overview.ts +++ b/ui/src/app/edge/history/common/grid/details/details.overview.ts @@ -1,14 +1,14 @@ -import { Component } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; -import { ModalController } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; -import { AbstractHistoryChartOverview } from 'src/app/shared/components/chart/abstractHistoryChartOverview'; -import { NavigationOption } from 'src/app/shared/components/footer/subnavigation/footerNavigation'; -import { Service } from 'src/app/shared/shared'; -import { Role } from 'src/app/shared/type/role'; +import { Component } from "@angular/core"; +import { ActivatedRoute, Router } from "@angular/router"; +import { ModalController } from "@ionic/angular"; +import { TranslateService } from "@ngx-translate/core"; +import { AbstractHistoryChartOverview } from "src/app/shared/components/chart/abstractHistoryChartOverview"; +import { NavigationOption } from "src/app/shared/components/footer/subnavigation/footerNavigation"; +import { Service } from "src/app/shared/shared"; +import { Role } from "src/app/shared/type/role"; @Component({ - templateUrl: './details.overview.html', + templateUrl: "./details.overview.html", }) export class DetailsOverviewComponent extends AbstractHistoryChartOverview { protected navigationButtons: NavigationOption[] = []; @@ -34,7 +34,7 @@ export class DetailsOverviewComponent extends AbstractHistoryChartOverview { } this.navigationButtons = [ - { id: 'currentVoltage', isEnabled: edge.roleIsAtLeast(Role.INSTALLER), alias: this.translate.instant("Edge.History.CURRENT_AND_VOLTAGE"), callback: () => { this.router.navigate([`../${gridMeter.id}/currentVoltage`], { relativeTo: this.route }); } }]; + { id: "currentVoltage", isEnabled: edge.roleIsAtLeast(Role.INSTALLER), alias: this.translate.instant("Edge.History.CURRENT_AND_VOLTAGE"), callback: () => { this.router.navigate([`../${gridMeter.id}/currentVoltage`], { relativeTo: this.route }); } }]; }); } } diff --git a/ui/src/app/edge/history/common/grid/flat/flat.ts b/ui/src/app/edge/history/common/grid/flat/flat.ts index 4d622e9ab7b..bb7d272b6cf 100644 --- a/ui/src/app/edge/history/common/grid/flat/flat.ts +++ b/ui/src/app/edge/history/common/grid/flat/flat.ts @@ -1,18 +1,18 @@ -import { Component } from '@angular/core'; -import { GridSectionComponent } from 'src/app/edge/live/energymonitor/chart/section/grid.component'; -import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; -import { ChannelAddress, CurrentData } from 'src/app/shared/shared'; -import { TimeUtils } from 'src/app/shared/utils/time/timeutils'; +import { Component } from "@angular/core"; +import { GridSectionComponent } from "src/app/edge/live/energymonitor/chart/section/grid.component"; +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; +import { ChannelAddress, CurrentData } from "src/app/shared/shared"; +import { TimeUtils } from "src/app/shared/utils/time/timeutils"; @Component({ - selector: 'gridWidget', - templateUrl: './flat.html', + selector: "gridWidget", + templateUrl: "./flat.html", }) export class FlatComponent extends AbstractFlatWidget { - private static readonly RESTRICTION_MODE: ChannelAddress = new ChannelAddress('ctrlEssLimiter14a0', 'RestrictionMode'); - private static readonly RESTRICTION_TIME: ChannelAddress = new ChannelAddress('ctrlEssLimiter14a0', 'CumulatedRestrictionTime'); - private static readonly OFF_GRID_TIME: ChannelAddress = new ChannelAddress('_sum', 'GridModeOffGridTime'); + private static readonly RESTRICTION_MODE: ChannelAddress = new ChannelAddress("ctrlEssLimiter14a0", "RestrictionMode"); + private static readonly RESTRICTION_TIME: ChannelAddress = new ChannelAddress("ctrlEssLimiter14a0", "CumulatedRestrictionTime"); + private static readonly OFF_GRID_TIME: ChannelAddress = new ChannelAddress("_sum", "GridModeOffGridTime"); protected restrictionTime: number | null = null; protected offGridTime: number | null = null; diff --git a/ui/src/app/edge/history/common/grid/grid.ts b/ui/src/app/edge/history/common/grid/grid.ts index 8e7d54bca35..2957572d7f9 100644 --- a/ui/src/app/edge/history/common/grid/grid.ts +++ b/ui/src/app/edge/history/common/grid/grid.ts @@ -1,12 +1,12 @@ -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; -import { FooterNavigationModule } from 'src/app/shared/components/footer/subnavigation/footerNavigation.module'; -import { SharedModule } from 'src/app/shared/shared.module'; -import { ChartComponent } from './chart/chart'; -import { ChartComponent as DetailsChartComponent } from './details/chart/chart'; -import { DetailsOverviewComponent } from './details/details.overview'; -import { FlatComponent } from './flat/flat'; -import { OverviewComponent } from './overview/overview'; +import { NgModule } from "@angular/core"; +import { BrowserModule } from "@angular/platform-browser"; +import { FooterNavigationModule } from "src/app/shared/components/footer/subnavigation/footerNavigation.module"; +import { SharedModule } from "src/app/shared/shared.module"; +import { ChartComponent } from "./chart/chart"; +import { ChartComponent as DetailsChartComponent } from "./details/chart/chart"; +import { DetailsOverviewComponent } from "./details/details.overview"; +import { FlatComponent } from "./flat/flat"; +import { OverviewComponent } from "./overview/overview"; @NgModule({ imports: [ diff --git a/ui/src/app/edge/history/common/grid/overview/overview.ts b/ui/src/app/edge/history/common/grid/overview/overview.ts index 736028491fc..b99f248ebf5 100644 --- a/ui/src/app/edge/history/common/grid/overview/overview.ts +++ b/ui/src/app/edge/history/common/grid/overview/overview.ts @@ -1,13 +1,13 @@ -import { Component } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; -import { ModalController } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; -import { AbstractHistoryChartOverview } from 'src/app/shared/components/chart/abstractHistoryChartOverview'; -import { NavigationOption } from 'src/app/shared/components/footer/subnavigation/footerNavigation'; -import { EdgeConfig, Service } from 'src/app/shared/shared'; +import { Component } from "@angular/core"; +import { ActivatedRoute, Router } from "@angular/router"; +import { ModalController } from "@ionic/angular"; +import { TranslateService } from "@ngx-translate/core"; +import { AbstractHistoryChartOverview } from "src/app/shared/components/chart/abstractHistoryChartOverview"; +import { NavigationOption } from "src/app/shared/components/footer/subnavigation/footerNavigation"; +import { EdgeConfig, Service } from "src/app/shared/shared"; @Component({ - templateUrl: './overview.html', + templateUrl: "./overview.html", }) export class OverviewComponent extends AbstractHistoryChartOverview { protected navigationButtons: NavigationOption[] = []; @@ -24,8 +24,8 @@ export class OverviewComponent extends AbstractHistoryChartOverview { protected override afterIsInitialized() { - const sum: EdgeConfig.Component = this.config.getComponent('_sum'); - sum.alias = this.translate.instant('General.TOTAL'); + const sum: EdgeConfig.Component = this.config.getComponent("_sum"); + sum.alias = this.translate.instant("General.TOTAL"); const navigationButtons: EdgeConfig.Component[] = []; const gridMeters = Object.values(this.config.components) .filter((component) => component.isEnabled && this.config.isTypeGrid(component)); @@ -41,7 +41,7 @@ export class OverviewComponent extends AbstractHistoryChartOverview { } this.navigationButtons = navigationButtons.map(el => ( - { id: el.id, alias: el.alias, callback: () => { this.router.navigate(['./' + el.id], { relativeTo: this.route }); } } + { id: el.id, alias: el.alias, callback: () => { this.router.navigate(["./" + el.id], { relativeTo: this.route }); } } )); } } 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 e4a1cfa5a17..3d65f4a0ce3 100644 --- a/ui/src/app/edge/history/common/production/chart/productionMeterChart.ts +++ b/ui/src/app/edge/history/common/production/chart/productionMeterChart.ts @@ -1,23 +1,23 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { AbstractHistoryChart } from 'src/app/shared/components/chart/abstracthistorychart'; -import { QueryHistoricTimeseriesEnergyResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; -import { ChartAxis, HistoryUtils, YAxisTitle } from 'src/app/shared/service/utils'; +import { Component } from "@angular/core"; +import { AbstractHistoryChart } from "src/app/shared/components/chart/abstracthistorychart"; +import { QueryHistoricTimeseriesEnergyResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse"; +import { ChartAxis, HistoryUtils, YAxisType } from "src/app/shared/service/utils"; -import { ChannelAddress } from '../../../../../shared/shared'; +import { ChannelAddress } from "../../../../../shared/shared"; /** Will be used in the Future again */ @Component({ - selector: 'productionMeterchart', - templateUrl: '../../../../../shared/components/chart/abstracthistorychart.html', + selector: "productionMeterchart", + templateUrl: "../../../../../shared/components/chart/abstracthistorychart.html", }) export class ProductionMeterChartComponent extends AbstractHistoryChart { protected override getChartData(): HistoryUtils.ChartData { const channels: HistoryUtils.InputChannel[] = [{ - name: 'ActivePower', - powerChannel: ChannelAddress.fromString(this.component.id + '/ActivePower'), - energyChannel: ChannelAddress.fromString(this.component.id + '/ActiveProductionEnergy'), + name: "ActivePower", + powerChannel: ChannelAddress.fromString(this.component.id + "/ActivePower"), + energyChannel: ChannelAddress.fromString(this.component.id + "/ActiveProductionEnergy"), converter: (data) => data != null ? data : null, }, ]; @@ -25,9 +25,9 @@ export class ProductionMeterChartComponent extends AbstractHistoryChart { // Phase 1 to 3 for (let i = 1; i < 4; i++) { channels.push({ - name: 'ActivePowerL' + i, - powerChannel: ChannelAddress.fromString(this.component.id + '/ActivePowerL' + i), - energyChannel: ChannelAddress.fromString(this.component.id + '/ActiveProductionEnergyL' + i), + name: "ActivePowerL" + i, + powerChannel: ChannelAddress.fromString(this.component.id + "/ActivePowerL" + i), + energyChannel: ChannelAddress.fromString(this.component.id + "/ActiveProductionEnergyL" + i), }); } return { @@ -35,14 +35,14 @@ export class ProductionMeterChartComponent extends AbstractHistoryChart { output: (data: HistoryUtils.ChannelData) => { const datasets: HistoryUtils.DisplayValue[] = []; datasets.push({ - name: this.translate.instant('General.production'), + name: this.translate.instant("General.production"), nameSuffix: (energyPeriodResponse: QueryHistoricTimeseriesEnergyResponse) => { - return energyPeriodResponse?.result.data[this.component.id + '/ActiveProductionEnergy'] ?? null; + return energyPeriodResponse?.result.data[this.component.id + "/ActiveProductionEnergy"] ?? null; }, converter: () => { - return data['ActivePower']; + return data["ActivePower"]; }, - color: 'rgb(0,152,204)', + color: "rgb(0,152,204)", }); if (this.showPhases) { @@ -51,7 +51,7 @@ export class ProductionMeterChartComponent extends AbstractHistoryChart { datasets.push({ name: "Erzeugung Phase L" + i, converter: () => { - return data['ActivePowerL' + i] ?? null; + return data["ActivePowerL" + i] ?? null; }, color: AbstractHistoryChart.phaseColors[i - 1], }); @@ -60,11 +60,11 @@ export class ProductionMeterChartComponent extends AbstractHistoryChart { return datasets; }, tooltip: { - formatNumber: '1.1-2', + formatNumber: "1.1-2", }, yAxes: [{ - unit: YAxisTitle.ENERGY, - position: 'left', + unit: YAxisType.ENERGY, + position: "left", yAxisId: ChartAxis.LEFT, }], }; 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 6b7c04b5277..9c54d688961 100644 --- a/ui/src/app/edge/history/common/production/chart/totalChart.ts +++ b/ui/src/app/edge/history/common/production/chart/totalChart.ts @@ -1,14 +1,14 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { AbstractHistoryChart } from 'src/app/shared/components/chart/abstracthistorychart'; -import { QueryHistoricTimeseriesEnergyResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; +import { Component } from "@angular/core"; +import { AbstractHistoryChart } from "src/app/shared/components/chart/abstracthistorychart"; +import { QueryHistoricTimeseriesEnergyResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse"; -import { ChartAxis, HistoryUtils, Utils, YAxisTitle } from '../../../../../shared/service/utils'; -import { ChannelAddress } from '../../../../../shared/shared'; +import { ChartAxis, HistoryUtils, Utils, YAxisType } from "../../../../../shared/service/utils"; +import { ChannelAddress } from "../../../../../shared/shared"; @Component({ - selector: 'productionTotalChart', - templateUrl: '../../../../../shared/components/chart/abstracthistorychart.html', + selector: "productionTotalChart", + templateUrl: "../../../../../shared/components/chart/abstracthistorychart.html", }) export class TotalChartComponent extends AbstractHistoryChart { @@ -26,17 +26,17 @@ export class TotalChartComponent extends AbstractHistoryChart { const chargerComponents = this.config.getComponentsImplementingNature("io.openems.edge.ess.dccharger.api.EssDcCharger"); const channels: HistoryUtils.InputChannel[] = [{ - name: 'ProductionActivePower', - powerChannel: ChannelAddress.fromString('_sum/ProductionActivePower'), - energyChannel: ChannelAddress.fromString('_sum/ProductionActiveEnergy'), + name: "ProductionActivePower", + powerChannel: ChannelAddress.fromString("_sum/ProductionActivePower"), + energyChannel: ChannelAddress.fromString("_sum/ProductionActiveEnergy"), }]; // If at least one charger if (chargerComponents.length > 0) { channels.push({ - name: 'ProductionDcActualPower', - powerChannel: ChannelAddress.fromString('_sum/ProductionDcActualPower'), - energyChannel: ChannelAddress.fromString('_sum/ProductionDcActiveEnergy'), + name: "ProductionDcActualPower", + powerChannel: ChannelAddress.fromString("_sum/ProductionDcActualPower"), + energyChannel: ChannelAddress.fromString("_sum/ProductionDcActiveEnergy"), }); } @@ -44,32 +44,32 @@ export class TotalChartComponent extends AbstractHistoryChart { if (this.showPhases) { channels.push( { - name: 'ProductionAcActivePowerL1', - powerChannel: ChannelAddress.fromString('_sum/ProductionAcActivePowerL1'), + name: "ProductionAcActivePowerL1", + powerChannel: ChannelAddress.fromString("_sum/ProductionAcActivePowerL1"), }, { - name: 'ProductionAcActivePowerL2', - powerChannel: ChannelAddress.fromString('_sum/ProductionAcActivePowerL2'), + name: "ProductionAcActivePowerL2", + powerChannel: ChannelAddress.fromString("_sum/ProductionAcActivePowerL2"), }, { - name: 'ProductionAcActivePowerL3', - powerChannel: ChannelAddress.fromString('_sum/ProductionAcActivePowerL3'), + name: "ProductionAcActivePowerL3", + powerChannel: ChannelAddress.fromString("_sum/ProductionAcActivePowerL3"), }); } for (const component of productionMeterComponents) { channels.push({ name: component.id, - powerChannel: ChannelAddress.fromString(component.id + '/ActivePower'), - energyChannel: ChannelAddress.fromString(component.id + '/ActiveProductionEnergy'), + powerChannel: ChannelAddress.fromString(component.id + "/ActivePower"), + energyChannel: ChannelAddress.fromString(component.id + "/ActiveProductionEnergy"), }); } for (const component of chargerComponents) { channels.push({ name: component.id, - powerChannel: ChannelAddress.fromString(component.id + '/ActualPower'), - energyChannel: ChannelAddress.fromString(component.id + '/ActualEnergy'), + powerChannel: ChannelAddress.fromString(component.id + "/ActualPower"), + energyChannel: ChannelAddress.fromString(component.id + "/ActualEnergy"), }); } @@ -78,14 +78,14 @@ export class TotalChartComponent extends AbstractHistoryChart { output: (data: HistoryUtils.ChannelData) => { const datasets: HistoryUtils.DisplayValue[] = []; datasets.push({ - name: this.showTotal == false ? this.translate.instant('General.production') : this.translate.instant('General.TOTAL'), + name: this.showTotal == false ? this.translate.instant("General.production") : this.translate.instant("General.TOTAL"), nameSuffix: (energyQueryResponse: QueryHistoricTimeseriesEnergyResponse) => { - return energyQueryResponse?.result.data['_sum/ProductionActiveEnergy'] ?? null; + return energyQueryResponse?.result.data["_sum/ProductionActiveEnergy"] ?? null; }, converter: () => { - return data['ProductionActivePower']; + return data["ProductionActivePower"]; }, - color: 'rgb(0,152,204)', + color: "rgb(0,152,204)", hiddenOnInit: true, stack: 2, }); @@ -98,7 +98,7 @@ export class TotalChartComponent extends AbstractHistoryChart { datasets.push({ name: "Phase L" + i, nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => { - return energyValues.result.data['_sum/ProductionAcActiveEnergyL' + i]; + return energyValues.result.data["_sum/ProductionAcActiveEnergyL" + i]; }, converter: () => { if (!this.showPhases) { @@ -108,27 +108,27 @@ export class TotalChartComponent extends AbstractHistoryChart { let effectiveProduction = []; if (this.config.getComponentsImplementingNature("io.openems.edge.ess.dccharger.api.EssDcCharger").length > 0) { - data['ProductionDcActualPower'].forEach((value, index) => { - effectiveProduction[index] = Utils.addSafely(data['ProductionAcActivePowerL' + i][index], value / 3); + data["ProductionDcActualPower"].forEach((value, index) => { + effectiveProduction[index] = Utils.addSafely(data["ProductionAcActivePowerL" + i][index], value / 3); }); } else if (this.config.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter").length > 0) { - effectiveProduction = data['ProductionAcActivePowerL' + i]; + effectiveProduction = data["ProductionAcActivePowerL" + i]; } return effectiveProduction; }, - color: 'rgb(' + AbstractHistoryChart.phaseColors[i - 1] + ')', + color: "rgb(" + AbstractHistoryChart.phaseColors[i - 1] + ")", stack: 3, }); } // ProductionMeters - const productionMeterColors: string[] = ['rgb(253,197,7)', 'rgb(202, 158, 6', 'rgb(228, 177, 6)', 'rgb(177, 138, 5)', 'rgb(152, 118, 4)']; + const productionMeterColors: string[] = ["rgb(253,197,7)", "rgb(202, 158, 6", "rgb(228, 177, 6)", "rgb(177, 138, 5)", "rgb(152, 118, 4)"]; for (let i = 0; i < productionMeterComponents.length; i++) { const component = productionMeterComponents[i]; datasets.push({ name: component.alias ?? component.id, nameSuffix: (energyResponse: QueryHistoricTimeseriesEnergyResponse) => { - return energyResponse.result.data[component.id + '/ActiveProductionEnergy'] ?? null; + return energyResponse.result.data[component.id + "/ActiveProductionEnergy"] ?? null; }, converter: () => { return data[component.id] ?? null; @@ -138,14 +138,14 @@ export class TotalChartComponent extends AbstractHistoryChart { }); } - const chargerColors: string[] = ['rgb(0,223,0)', 'rgb(0,178,0)', 'rgb(0,201,0)', 'rgb(0,134,0)', 'rgb(0,156,0)']; + const chargerColors: string[] = ["rgb(0,223,0)", "rgb(0,178,0)", "rgb(0,201,0)", "rgb(0,134,0)", "rgb(0,156,0)"]; // ChargerComponents for (let i = 0; i < chargerComponents.length; i++) { const component = chargerComponents[i]; datasets.push({ name: component.alias ?? component.id, nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => { - return energyValues.result.data[new ChannelAddress(component.id, 'ActualEnergy').toString()]; + return energyValues.result.data[new ChannelAddress(component.id, "ActualEnergy").toString()]; }, converter: () => { return data[component.id] ?? null; @@ -157,12 +157,12 @@ export class TotalChartComponent extends AbstractHistoryChart { return datasets; }, tooltip: { - formatNumber: '1.1-2', - afterTitle: this.translate.instant('General.TOTAL'), + formatNumber: "1.1-2", + afterTitle: this.translate.instant("General.TOTAL"), }, yAxes: [{ - unit: YAxisTitle.ENERGY, - position: 'left', + unit: YAxisType.ENERGY, + position: "left", yAxisId: ChartAxis.LEFT, }], }; diff --git a/ui/src/app/edge/history/common/production/details/chart/channels.spec.ts b/ui/src/app/edge/history/common/production/details/chart/channels.spec.ts index e12a4af205f..ec95a07e629 100644 --- a/ui/src/app/edge/history/common/production/details/chart/channels.spec.ts +++ b/ui/src/app/edge/history/common/production/details/chart/channels.spec.ts @@ -21,16 +21,16 @@ export namespace History { }), dataChannelWithValues: new QueryHistoricTimeseriesDataResponse("0", { data: { - 'meter0/ActivePower': [124, 0, null, 0, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 110, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 140, null, null, null, 2127, 175, 176, null, 180, 180, 185, 180, null, 185, 190, 180, 180, 176, 176, 170, 175, 170, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null], - 'meter0/ActivePowerL1': [41, 0, null, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 38, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 47, null, null, null, 709, 58, 59, null, 60, 60, 62, 60, null, 62, 63, 60, 60, 59, 59, 57, 58, 57, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null], - 'meter0/ActivePowerL2': [41, 0, null, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 38, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 47, null, null, null, 709, 58, 59, null, 60, 60, 62, 60, null, 62, 63, 60, 60, 59, 59, 57, 58, 57, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null], - 'meter0/ActivePowerL3': [41, 0, null, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 38, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 47, null, null, null, 709, 58, 59, null, 60, 60, 62, 60, null, 62, 63, 60, 60, 59, 59, 57, 58, 57, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null], - 'charger0/ActualPower': [124, 0, null, 0, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 110, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 140, null, null, null, 2127, 175, 176, null, 180, 180, 185, 180, null, 185, 190, 180, 180, 176, 176, 170, 175, 170, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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': [124, 0, null, 0, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 110, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 140, null, null, null, 2127, 175, 176, null, 180, 180, 185, 180, null, 185, 190, 180, 180, 176, 176, 170, 175, 170, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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/ProductionAcActivePowerL1': [41, 0, null, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 38, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 47, null, null, null, 709, 58, 59, null, 60, 60, 62, 60, null, 62, 63, 60, 60, 59, 59, 57, 58, 57, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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/ProductionAcActivePowerL2': [41, 0, null, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 38, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 47, null, null, null, 709, 58, 59, null, 60, 60, 62, 60, null, 62, 63, 60, 60, 59, 59, 57, 58, 57, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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/ProductionAcActivePowerL3': [41, 0, null, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 38, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 47, null, null, null, 709, 58, 59, null, 60, 60, 62, 60, null, 62, 63, 60, 60, 59, 59, 57, 58, 57, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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': [24, 0, null, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 110, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 140, null, null, null, 2127, 175, 176, null, 180, 180, 185, 180, null, 185, 190, 180, 180, 176, 176, 170, 175, 170, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null], + "meter0/ActivePower": [124, 0, null, 0, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 110, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 140, null, null, null, 2127, 175, 176, null, 180, 180, 185, 180, null, 185, 190, 180, 180, 176, 176, 170, 175, 170, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null], + "meter0/ActivePowerL1": [41, 0, null, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 38, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 47, null, null, null, 709, 58, 59, null, 60, 60, 62, 60, null, 62, 63, 60, 60, 59, 59, 57, 58, 57, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null], + "meter0/ActivePowerL2": [41, 0, null, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 38, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 47, null, null, null, 709, 58, 59, null, 60, 60, 62, 60, null, 62, 63, 60, 60, 59, 59, 57, 58, 57, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null], + "meter0/ActivePowerL3": [41, 0, null, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 38, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 47, null, null, null, 709, 58, 59, null, 60, 60, 62, 60, null, 62, 63, 60, 60, 59, 59, 57, 58, 57, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null], + "charger0/ActualPower": [124, 0, null, 0, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 110, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 140, null, null, null, 2127, 175, 176, null, 180, 180, 185, 180, null, 185, 190, 180, 180, 176, 176, 170, 175, 170, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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": [124, 0, null, 0, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 110, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 140, null, null, null, 2127, 175, 176, null, 180, 180, 185, 180, null, 185, 190, 180, 180, 176, 176, 170, 175, 170, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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/ProductionAcActivePowerL1": [41, 0, null, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 38, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 47, null, null, null, 709, 58, 59, null, 60, 60, 62, 60, null, 62, 63, 60, 60, 59, 59, 57, 58, 57, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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/ProductionAcActivePowerL2": [41, 0, null, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 38, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 47, null, null, null, 709, 58, 59, null, 60, 60, 62, 60, null, 62, 63, 60, 60, 59, 59, 57, 58, 57, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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/ProductionAcActivePowerL3": [41, 0, null, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 38, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 47, null, null, null, 709, 58, 59, null, 60, 60, 62, 60, null, 62, 63, 60, 60, 59, 59, 57, 58, 57, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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": [24, 0, null, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 110, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 140, null, null, null, 2127, 175, 176, null, 180, 180, 185, 180, null, 185, 190, 180, 180, 176, 176, 170, 175, 170, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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"], }), diff --git a/ui/src/app/edge/history/common/production/details/chart/charger.spec.ts b/ui/src/app/edge/history/common/production/details/chart/charger.spec.ts index 717ef36a8b0..08cfeb6e0b9 100644 --- a/ui/src/app/edge/history/common/production/details/chart/charger.spec.ts +++ b/ui/src/app/edge/history/common/production/details/chart/charger.spec.ts @@ -9,46 +9,46 @@ import { DATA, LABELS } from "../../../energy/chart/chart.constants.spec"; import { History } from "./channels.spec"; import { ChargerChartDetailsComponent } from "./charger"; -describe('History Production Details - chargers', () => { +describe("History Production Details - chargers", () => { const defaultEMS = DummyConfig.from( DummyConfig.Component.GOODWE_CHARGER_MPPT_TWO_STRING("charger0", "MPPT 1"), ); let TEST_CONTEXT: TestContext & { route: ActivatedRoute }; beforeEach(async () => { - TEST_CONTEXT = await sharedSetupWithComponentIdRoute('charger0'); + TEST_CONTEXT = await sharedSetupWithComponentIdRoute("charger0"); }); - it('#getChartData()', () => { + it("#getChartData()", () => { { - expectView(defaultEMS, TEST_CONTEXT, 'line', History.DAY, + expectView(defaultEMS, TEST_CONTEXT, "line", History.DAY, { datasets: { data: [ - DATA('MPPT 1: 15,9 kWh', [0.124, 0, null, 0, 0.173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.11, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.13, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.14, null, null, null, 2.127, 0.175, 0.176, null, 0.18, 0.18, 0.185, 0.18, null, 0.185, 0.19, 0.18, 0.18, 0.176, 0.176, 0.17, 0.175, 0.17, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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("MPPT 1: 15,9 kWh", [0.124, 0, null, 0, 0.173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.11, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.13, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.14, null, null, null, 2.127, 0.175, 0.176, null, 0.18, 0.18, 0.185, 0.18, null, 0.185, 0.19, 0.18, 0.18, 0.176, 0.176, 0.17, 0.175, 0.17, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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: OeTester.ChartOptions.LINE_CHART_OPTIONS('hour', 'line', { 'left': { scale: { beginAtZero: true } } }, + options: OeTester.ChartOptions.LINE_CHART_OPTIONS("hour", "line", { "left": { scale: { beginAtZero: true } } }, ), }, }); } { - expectView(defaultEMS, TEST_CONTEXT, 'bar', History.MONTH, + expectView(defaultEMS, TEST_CONTEXT, "bar", History.MONTH, { datasets: { data: [ - DATA('MPPT 1: 21,6 kWh', [0.016, 0.014, 0.016, 0.015, 0.016, 0.015, 0.015, 0.015, 0.016, 0.017, 0.018, 0.014, 0.016, 0.017, 0.016, 0.015, 0.014, 0.017, 0.015, 0.016, 0.017, 0.016, 0.015, 0.016, 0.014, 0.015, 0.014, 0.016, 0.014, null, null]), + DATA("MPPT 1: 21,6 kWh", [0.016, 0.014, 0.016, 0.015, 0.016, 0.015, 0.015, 0.015, 0.016, 0.017, 0.018, 0.014, 0.016, 0.017, 0.016, 0.015, 0.014, 0.017, 0.015, 0.016, 0.017, 0.016, 0.015, 0.016, 0.014, 0.015, 0.014, 0.016, 0.014, null, null]), ], labels: LABELS(History.MONTH.energyPerPeriodChannelWithValues.result.timestamps), - options: OeTester.ChartOptions.BAR_CHART_OPTIONS('day', 'bar', {}), + options: OeTester.ChartOptions.BAR_CHART_OPTIONS("day", "bar", {}), }, }); } }); }); -export function expectView(config: EdgeConfig, testContext: TestContext & { route: ActivatedRoute }, chartType: 'line' | 'bar', channels: OeTester.Types.Channels, view: OeChartTester.View): void { +export function expectView(config: EdgeConfig, testContext: TestContext & { route: ActivatedRoute }, chartType: "line" | "bar", channels: OeTester.Types.Channels, view: OeChartTester.View): void { expect(removeFunctions(OeChartTester .apply(ChargerChartDetailsComponent .getChartData( diff --git a/ui/src/app/edge/history/common/production/details/chart/charger.ts b/ui/src/app/edge/history/common/production/details/chart/charger.ts index a6b44d794c5..7673bac3ffd 100644 --- a/ui/src/app/edge/history/common/production/details/chart/charger.ts +++ b/ui/src/app/edge/history/common/production/details/chart/charger.ts @@ -1,14 +1,14 @@ -import { Component } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { TranslateService } from '@ngx-translate/core'; -import { AbstractHistoryChart } from 'src/app/shared/components/chart/abstracthistorychart'; -import { QueryHistoricTimeseriesEnergyResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; -import { ChartAxis, HistoryUtils, YAxisTitle } from 'src/app/shared/service/utils'; -import { ChannelAddress, EdgeConfig } from 'src/app/shared/shared'; +import { Component } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { TranslateService } from "@ngx-translate/core"; +import { AbstractHistoryChart } from "src/app/shared/components/chart/abstracthistorychart"; +import { QueryHistoricTimeseriesEnergyResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse"; +import { ChartAxis, HistoryUtils, YAxisType } from "src/app/shared/service/utils"; +import { ChannelAddress, EdgeConfig } from "src/app/shared/shared"; @Component({ - selector: 'chargerChart', - templateUrl: '../../../../../../shared/components/chart/abstracthistorychart.html', + selector: "chargerChart", + templateUrl: "../../../../../../shared/components/chart/abstracthistorychart.html", }) export class ChargerChartDetailsComponent extends AbstractHistoryChart { @@ -17,28 +17,28 @@ export class ChargerChartDetailsComponent extends AbstractHistoryChart { return { input: [{ name: component.id, - powerChannel: ChannelAddress.fromString(component.id + '/ActualPower'), - energyChannel: ChannelAddress.fromString(component.id + '/ActualEnergy'), + powerChannel: ChannelAddress.fromString(component.id + "/ActualPower"), + energyChannel: ChannelAddress.fromString(component.id + "/ActualEnergy"), }], output: (data: HistoryUtils.ChannelData) => [{ name: component.alias, nameSuffix: (energyQueryResponse: QueryHistoricTimeseriesEnergyResponse) => { - return energyQueryResponse.result.data[component.id + '/ActualEnergy']; + return energyQueryResponse.result.data[component.id + "/ActualEnergy"]; }, converter: () => { return data[component.id]; }, - color: 'rgb(0,152,204)', + color: "rgb(0,152,204)", hiddenOnInit: false, stack: 2, }], tooltip: { - formatNumber: '1.1-2', - afterTitle: translate.instant('General.TOTAL'), + formatNumber: "1.1-2", + afterTitle: translate.instant("General.TOTAL"), }, yAxes: [{ - unit: YAxisTitle.ENERGY, - position: 'left', + unit: YAxisType.ENERGY, + position: "left", yAxisId: ChartAxis.LEFT, }], }; diff --git a/ui/src/app/edge/history/common/production/details/chart/productionMeter.spec.ts b/ui/src/app/edge/history/common/production/details/chart/productionMeter.spec.ts index 5a4ab2d5393..d3cc8490cc1 100644 --- a/ui/src/app/edge/history/common/production/details/chart/productionMeter.spec.ts +++ b/ui/src/app/edge/history/common/production/details/chart/productionMeter.spec.ts @@ -9,50 +9,50 @@ import { DATA, LABELS } from "../../../energy/chart/chart.constants.spec"; import { History } from "./channels.spec"; import { ProductionMeterChartDetailsComponent } from "./productionMeter"; -describe('History Production Details - productionMeters', () => { +describe("History Production Details - productionMeters", () => { const defaultEMS = DummyConfig.from( DummyConfig.Component.SOLAR_EDGE_PV_INVERTER("meter0", "Whirlpool"), ); let TEST_CONTEXT: TestContext & { route: ActivatedRoute }; beforeEach(async () => { - TEST_CONTEXT = await sharedSetupWithComponentIdRoute('meter0'); + TEST_CONTEXT = await sharedSetupWithComponentIdRoute("meter0"); }); - it('#getChartData()', () => { + it("#getChartData()", () => { { - expectView(defaultEMS, TEST_CONTEXT, 'line', History.DAY, + expectView(defaultEMS, TEST_CONTEXT, "line", History.DAY, { datasets: { data: [ - DATA('Whirlpool: 15,9 kWh', [0.124, 0, null, 0, 0.173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.11, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.13, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.14, null, null, null, 2.127, 0.175, 0.176, null, 0.18, 0.18, 0.185, 0.18, null, 0.185, 0.19, 0.18, 0.18, 0.176, 0.176, 0.17, 0.175, 0.17, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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('Phase L1', [0.041, 0, null, 0, 0.058, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.037, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.048, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.038, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.043, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.047, null, null, null, 0.709, 0.058, 0.059, null, 0.06, 0.06, 0.062, 0.06, null, 0.062, 0.063, 0.06, 0.06, 0.059, 0.059, 0.057, 0.058, 0.057, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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('Phase L2', [0.041, 0, null, 0, 0.058, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.037, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.048, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.038, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.043, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.047, null, null, null, 0.709, 0.058, 0.059, null, 0.06, 0.06, 0.062, 0.06, null, 0.062, 0.063, 0.06, 0.06, 0.059, 0.059, 0.057, 0.058, 0.057, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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('Phase L3', [0.041, 0, null, 0, 0.058, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.037, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.048, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.038, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.043, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.047, null, null, null, 0.709, 0.058, 0.059, null, 0.06, 0.06, 0.062, 0.06, null, 0.062, 0.063, 0.06, 0.06, 0.059, 0.059, 0.057, 0.058, 0.057, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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("Whirlpool: 15,9 kWh", [0.124, 0, null, 0, 0.173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.11, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.13, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.14, null, null, null, 2.127, 0.175, 0.176, null, 0.18, 0.18, 0.185, 0.18, null, 0.185, 0.19, 0.18, 0.18, 0.176, 0.176, 0.17, 0.175, 0.17, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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("Phase L1", [0.041, 0, null, 0, 0.058, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.037, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.048, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.038, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.043, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.047, null, null, null, 0.709, 0.058, 0.059, null, 0.06, 0.06, 0.062, 0.06, null, 0.062, 0.063, 0.06, 0.06, 0.059, 0.059, 0.057, 0.058, 0.057, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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("Phase L2", [0.041, 0, null, 0, 0.058, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.037, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.048, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.038, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.043, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.047, null, null, null, 0.709, 0.058, 0.059, null, 0.06, 0.06, 0.062, 0.06, null, 0.062, 0.063, 0.06, 0.06, 0.059, 0.059, 0.057, 0.058, 0.057, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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("Phase L3", [0.041, 0, null, 0, 0.058, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.037, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.048, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.038, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.043, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.047, null, null, null, 0.709, 0.058, 0.059, null, 0.06, 0.06, 0.062, 0.06, null, 0.062, 0.063, 0.06, 0.06, 0.059, 0.059, 0.057, 0.058, 0.057, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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: OeTester.ChartOptions.LINE_CHART_OPTIONS('hour', 'line', { 'left': { scale: { beginAtZero: true } } }, + options: OeTester.ChartOptions.LINE_CHART_OPTIONS("hour", "line", { "left": { scale: { beginAtZero: true } } }, ), }, }); } { - expectView(defaultEMS, TEST_CONTEXT, 'bar', History.MONTH, + expectView(defaultEMS, TEST_CONTEXT, "bar", History.MONTH, { datasets: { data: [ - DATA('Whirlpool: 21,6 kWh', [0.016, 0.014, 0.016, 0.015, 0.016, 0.015, 0.015, 0.015, 0.016, 0.017, 0.018, 0.014, 0.016, 0.017, 0.016, 0.015, 0.014, 0.017, 0.015, 0.016, 0.017, 0.016, 0.015, 0.016, 0.014, 0.015, 0.014, 0.016, 0.014, null, null]), + DATA("Whirlpool: 21,6 kWh", [0.016, 0.014, 0.016, 0.015, 0.016, 0.015, 0.015, 0.015, 0.016, 0.017, 0.018, 0.014, 0.016, 0.017, 0.016, 0.015, 0.014, 0.017, 0.015, 0.016, 0.017, 0.016, 0.015, 0.016, 0.014, 0.015, 0.014, 0.016, 0.014, null, null]), ], labels: LABELS(History.MONTH.energyPerPeriodChannelWithValues.result.timestamps), - options: OeTester.ChartOptions.BAR_CHART_OPTIONS('day', 'bar', {}), + options: OeTester.ChartOptions.BAR_CHART_OPTIONS("day", "bar", {}), }, }); } }); }); -export function expectView(config: EdgeConfig, testContext: TestContext & { route: ActivatedRoute }, chartType: 'line' | 'bar', channels: OeTester.Types.Channels, view: OeChartTester.View): void { - sessionStorage.setItem("mapping to int", JSON.stringify(History.MONTH.energyPerPeriodChannelWithValues.result.data['meter0/ActiveProductionEnergy'].map(el => el != null ? Math.round(el) : null))); +export function expectView(config: EdgeConfig, testContext: TestContext & { route: ActivatedRoute }, chartType: "line" | "bar", channels: OeTester.Types.Channels, view: OeChartTester.View): void { + sessionStorage.setItem("mapping to int", JSON.stringify(History.MONTH.energyPerPeriodChannelWithValues.result.data["meter0/ActiveProductionEnergy"].map(el => el != null ? Math.round(el) : null))); sessionStorage.setItem("phase", JSON.stringify(OeChartTester .apply(ProductionMeterChartDetailsComponent .getChartData( diff --git a/ui/src/app/edge/history/common/production/details/chart/productionMeter.ts b/ui/src/app/edge/history/common/production/details/chart/productionMeter.ts index f7c7e682b3b..634398525b7 100644 --- a/ui/src/app/edge/history/common/production/details/chart/productionMeter.ts +++ b/ui/src/app/edge/history/common/production/details/chart/productionMeter.ts @@ -1,15 +1,15 @@ -import { Component } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { TranslateService } from '@ngx-translate/core'; -import { AbstractHistoryChart } from 'src/app/shared/components/chart/abstracthistorychart'; -import { Phase } from 'src/app/shared/components/shared/phase'; -import { QueryHistoricTimeseriesEnergyResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; -import { ChartAxis, HistoryUtils, YAxisTitle } from 'src/app/shared/service/utils'; -import { ChannelAddress, EdgeConfig } from 'src/app/shared/shared'; +import { Component } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { TranslateService } from "@ngx-translate/core"; +import { AbstractHistoryChart } from "src/app/shared/components/chart/abstracthistorychart"; +import { Phase } from "src/app/shared/components/shared/phase"; +import { QueryHistoricTimeseriesEnergyResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse"; +import { ChartAxis, HistoryUtils, YAxisType } from "src/app/shared/service/utils"; +import { ChannelAddress, EdgeConfig } from "src/app/shared/shared"; @Component({ - selector: 'productionMeterChart', - templateUrl: '../../../../../../shared/components/chart/abstracthistorychart.html', + selector: "productionMeterChart", + templateUrl: "../../../../../../shared/components/chart/abstracthistorychart.html", }) export class ProductionMeterChartDetailsComponent extends AbstractHistoryChart { @@ -18,12 +18,12 @@ export class ProductionMeterChartDetailsComponent extends AbstractHistoryChart { return { input: [{ name: component.id, - powerChannel: ChannelAddress.fromString(component.id + '/ActivePower'), - energyChannel: ChannelAddress.fromString(component.id + '/ActiveProductionEnergy'), + powerChannel: ChannelAddress.fromString(component.id + "/ActivePower"), + energyChannel: ChannelAddress.fromString(component.id + "/ActiveProductionEnergy"), }, ...Phase.THREE_PHASE.map(phase => ({ - name: 'ProductionAcActivePower' + phase, - powerChannel: ChannelAddress.fromString(component.id + '/ActivePower' + phase), + name: "ProductionAcActivePower" + phase, + powerChannel: ChannelAddress.fromString(component.id + "/ActivePower" + phase), }))], output: (data: HistoryUtils.ChannelData) => { @@ -31,12 +31,12 @@ export class ProductionMeterChartDetailsComponent extends AbstractHistoryChart { datasets.push({ name: component.alias, nameSuffix: (energyQueryResponse: QueryHistoricTimeseriesEnergyResponse) => { - return energyQueryResponse.result.data[component.id + '/ActiveProductionEnergy']; + return energyQueryResponse.result.data[component.id + "/ActiveProductionEnergy"]; }, converter: () => { return data[component.id]; }, - color: 'rgb(0,152,204)', + color: "rgb(0,152,204)", hiddenOnInit: false, stack: 2, }); @@ -44,20 +44,20 @@ export class ProductionMeterChartDetailsComponent extends AbstractHistoryChart { datasets.push(...Phase.THREE_PHASE.map((phase, i) => ({ name: "Phase " + phase, converter: () => - data['ProductionAcActivePower' + phase], - color: 'rgb(' + AbstractHistoryChart.phaseColors[i] + ')', + data["ProductionAcActivePower" + phase], + color: "rgb(" + AbstractHistoryChart.phaseColors[i] + ")", stack: 3, }))); return datasets; }, tooltip: { - formatNumber: '1.1-2', - afterTitle: translate.instant('General.TOTAL'), + formatNumber: "1.1-2", + afterTitle: translate.instant("General.TOTAL"), }, yAxes: [{ - unit: YAxisTitle.ENERGY, - position: 'left', + unit: YAxisType.ENERGY, + position: "left", yAxisId: ChartAxis.LEFT, }], }; diff --git a/ui/src/app/edge/history/common/production/details/chart/sum.spec.ts b/ui/src/app/edge/history/common/production/details/chart/sum.spec.ts index 511011732fd..286910ff833 100644 --- a/ui/src/app/edge/history/common/production/details/chart/sum.spec.ts +++ b/ui/src/app/edge/history/common/production/details/chart/sum.spec.ts @@ -9,7 +9,7 @@ import { DATA, LABELS } from "../../../energy/chart/chart.constants.spec"; import { History } from "./channels.spec"; import { SumChartDetailsComponent } from "./sum"; -describe('History Production Details - _sum', () => { +describe("History Production Details - _sum", () => { const defaultEMS = DummyConfig.from( DummyConfig.Component.SUM("_sum", "Gesamt"), DummyConfig.Component.SOLAR_EDGE_PV_INVERTER("meter0"), @@ -17,105 +17,105 @@ describe('History Production Details - _sum', () => { let TEST_CONTEXT: TestContext & { route: ActivatedRoute }; beforeEach(async () => { - TEST_CONTEXT = await sharedSetupWithComponentIdRoute('_sum'); + TEST_CONTEXT = await sharedSetupWithComponentIdRoute("_sum"); }); - it('#getChartData() - asymmetricMeter && no essDcCharger configured', () => { + it("#getChartData() - asymmetricMeter && no essDcCharger configured", () => { { - expectView(defaultEMS, TEST_CONTEXT, 'line', History.DAY, + expectView(defaultEMS, TEST_CONTEXT, "line", History.DAY, { datasets: { data: [ - DATA('Gesamt: 15,9 kWh', [0.124, 0, null, 0, 0.173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.11, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.13, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.14, null, null, null, 2.127, 0.175, 0.176, null, 0.18, 0.18, 0.185, 0.18, null, 0.185, 0.19, 0.18, 0.18, 0.176, 0.176, 0.17, 0.175, 0.17, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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('Phase L1', [0.041, 0, null, 0, 0.058, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.037, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.048, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.038, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.043, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.047, null, null, null, 0.709, 0.058, 0.059, null, 0.06, 0.06, 0.062, 0.06, null, 0.062, 0.063, 0.06, 0.06, 0.059, 0.059, 0.057, 0.058, 0.057, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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('Phase L2', [0.041, 0, null, 0, 0.058, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.037, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.048, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.038, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.043, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.047, null, null, null, 0.709, 0.058, 0.059, null, 0.06, 0.06, 0.062, 0.06, null, 0.062, 0.063, 0.06, 0.06, 0.059, 0.059, 0.057, 0.058, 0.057, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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('Phase L3', [0.041, 0, null, 0, 0.058, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.037, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.048, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.038, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.043, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.047, null, null, null, 0.709, 0.058, 0.059, null, 0.06, 0.06, 0.062, 0.06, null, 0.062, 0.063, 0.06, 0.06, 0.059, 0.059, 0.057, 0.058, 0.057, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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("Gesamt: 15,9 kWh", [0.124, 0, null, 0, 0.173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.11, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.13, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.14, null, null, null, 2.127, 0.175, 0.176, null, 0.18, 0.18, 0.185, 0.18, null, 0.185, 0.19, 0.18, 0.18, 0.176, 0.176, 0.17, 0.175, 0.17, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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("Phase L1", [0.041, 0, null, 0, 0.058, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.037, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.048, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.038, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.043, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.047, null, null, null, 0.709, 0.058, 0.059, null, 0.06, 0.06, 0.062, 0.06, null, 0.062, 0.063, 0.06, 0.06, 0.059, 0.059, 0.057, 0.058, 0.057, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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("Phase L2", [0.041, 0, null, 0, 0.058, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.037, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.048, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.038, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.043, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.047, null, null, null, 0.709, 0.058, 0.059, null, 0.06, 0.06, 0.062, 0.06, null, 0.062, 0.063, 0.06, 0.06, 0.059, 0.059, 0.057, 0.058, 0.057, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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("Phase L3", [0.041, 0, null, 0, 0.058, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.037, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.048, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.038, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.043, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.047, null, null, null, 0.709, 0.058, 0.059, null, 0.06, 0.06, 0.062, 0.06, null, 0.062, 0.063, 0.06, 0.06, 0.059, 0.059, 0.057, 0.058, 0.057, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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: OeTester.ChartOptions.LINE_CHART_OPTIONS('hour', 'line', { 'left': { scale: { beginAtZero: true } } }, + options: OeTester.ChartOptions.LINE_CHART_OPTIONS("hour", "line", { "left": { scale: { beginAtZero: true } } }, ), }, }); } { - expectView(defaultEMS, TEST_CONTEXT, 'bar', History.MONTH, + expectView(defaultEMS, TEST_CONTEXT, "bar", History.MONTH, { datasets: { data: [ - DATA('Gesamt: 21,6 kWh', [0.016, 0.014, 0.016, 0.015, 0.016, 0.015, 0.015, 0.015, 0.016, 0.017, 0.018, 0.014, 0.016, 0.017, 0.016, 0.015, 0.014, 0.017, 0.015, 0.016, 0.017, 0.016, 0.015, 0.016, 0.014, 0.015, 0.014, 0.016, 0.014, null, null]), + DATA("Gesamt: 21,6 kWh", [0.016, 0.014, 0.016, 0.015, 0.016, 0.015, 0.015, 0.015, 0.016, 0.017, 0.018, 0.014, 0.016, 0.017, 0.016, 0.015, 0.014, 0.017, 0.015, 0.016, 0.017, 0.016, 0.015, 0.016, 0.014, 0.015, 0.014, 0.016, 0.014, null, null]), ], labels: LABELS(History.MONTH.energyPerPeriodChannelWithValues.result.timestamps), - options: OeTester.ChartOptions.BAR_CHART_OPTIONS('day', 'bar', {}), + options: OeTester.ChartOptions.BAR_CHART_OPTIONS("day", "bar", {}), }, }); } }); - it('#getChartData() - essDcCharger configured', () => { + it("#getChartData() - essDcCharger configured", () => { { const defaultEMS = DummyConfig.from( DummyConfig.Component.SUM("_sum", "Gesamt"), DummyConfig.Component.GOODWE_CHARGER_MPPT_TWO_STRING("charger0"), ); - expectView(defaultEMS, TEST_CONTEXT, 'line', History.DAY, + expectView(defaultEMS, TEST_CONTEXT, "line", History.DAY, { datasets: { data: [ - DATA('Gesamt: 15,9 kWh', [0.124, 0, null, 0, 0.173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.11, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.13, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.14, null, null, null, 2.127, 0.175, 0.176, null, 0.18, 0.18, 0.185, 0.18, null, 0.185, 0.19, 0.18, 0.18, 0.176, 0.176, 0.17, 0.175, 0.17, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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('Phase L1', [0.049, 0, null, 0, 0.08233333333333334, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.07366666666666666, 0.07566666666666666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.09633333333333333, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.07566666666666666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.07566666666666666, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.08633333333333333, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.09366666666666668, null, null, null, 1.418, 0.11633333333333333, 0.11766666666666667, null, 0.12, 0.12, 0.12366666666666667, 0.12, null, 0.12366666666666667, 0.12633333333333335, 0.12, 0.12, 0.11766666666666667, 0.11766666666666667, 0.11366666666666667, 0.11633333333333333, 0.11366666666666667, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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('Phase L2', [0.049, 0, null, 0, 0.08233333333333334, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.07366666666666666, 0.07566666666666666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.09633333333333333, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.07566666666666666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.07566666666666666, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.08633333333333333, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.09366666666666668, null, null, null, 1.418, 0.11633333333333333, 0.11766666666666667, null, 0.12, 0.12, 0.12366666666666667, 0.12, null, 0.12366666666666667, 0.12633333333333335, 0.12, 0.12, 0.11766666666666667, 0.11766666666666667, 0.11366666666666667, 0.11633333333333333, 0.11366666666666667, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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('Phase L3', [0.049, 0, null, 0, 0.08233333333333334, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.07366666666666666, 0.07566666666666666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.09633333333333333, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.07566666666666666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.07566666666666666, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.08633333333333333, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.09366666666666668, null, null, null, 1.418, 0.11633333333333333, 0.11766666666666667, null, 0.12, 0.12, 0.12366666666666667, 0.12, null, 0.12366666666666667, 0.12633333333333335, 0.12, 0.12, 0.11766666666666667, 0.11766666666666667, 0.11366666666666667, 0.11633333333333333, 0.11366666666666667, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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("Gesamt: 15,9 kWh", [0.124, 0, null, 0, 0.173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.11, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.13, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.14, null, null, null, 2.127, 0.175, 0.176, null, 0.18, 0.18, 0.185, 0.18, null, 0.185, 0.19, 0.18, 0.18, 0.176, 0.176, 0.17, 0.175, 0.17, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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("Phase L1", [0.049, 0, null, 0, 0.08233333333333334, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.07366666666666666, 0.07566666666666666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.09633333333333333, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.07566666666666666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.07566666666666666, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.08633333333333333, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.09366666666666668, null, null, null, 1.418, 0.11633333333333333, 0.11766666666666667, null, 0.12, 0.12, 0.12366666666666667, 0.12, null, 0.12366666666666667, 0.12633333333333335, 0.12, 0.12, 0.11766666666666667, 0.11766666666666667, 0.11366666666666667, 0.11633333333333333, 0.11366666666666667, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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("Phase L2", [0.049, 0, null, 0, 0.08233333333333334, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.07366666666666666, 0.07566666666666666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.09633333333333333, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.07566666666666666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.07566666666666666, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.08633333333333333, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.09366666666666668, null, null, null, 1.418, 0.11633333333333333, 0.11766666666666667, null, 0.12, 0.12, 0.12366666666666667, 0.12, null, 0.12366666666666667, 0.12633333333333335, 0.12, 0.12, 0.11766666666666667, 0.11766666666666667, 0.11366666666666667, 0.11633333333333333, 0.11366666666666667, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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("Phase L3", [0.049, 0, null, 0, 0.08233333333333334, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.07366666666666666, 0.07566666666666666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.09633333333333333, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.07566666666666666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.07566666666666666, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.08633333333333333, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.09366666666666668, null, null, null, 1.418, 0.11633333333333333, 0.11766666666666667, null, 0.12, 0.12, 0.12366666666666667, 0.12, null, 0.12366666666666667, 0.12633333333333335, 0.12, 0.12, 0.11766666666666667, 0.11766666666666667, 0.11366666666666667, 0.11633333333333333, 0.11366666666666667, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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: OeTester.ChartOptions.LINE_CHART_OPTIONS('hour', 'line', { 'left': { scale: { beginAtZero: true } } }, + options: OeTester.ChartOptions.LINE_CHART_OPTIONS("hour", "line", { "left": { scale: { beginAtZero: true } } }, ), }, }); } { - expectView(defaultEMS, TEST_CONTEXT, 'bar', History.MONTH, + expectView(defaultEMS, TEST_CONTEXT, "bar", History.MONTH, { datasets: { data: [ - DATA('Gesamt: 21,6 kWh', [0.016, 0.014, 0.016, 0.015, 0.016, 0.015, 0.015, 0.015, 0.016, 0.017, 0.018, 0.014, 0.016, 0.017, 0.016, 0.015, 0.014, 0.017, 0.015, 0.016, 0.017, 0.016, 0.015, 0.016, 0.014, 0.015, 0.014, 0.016, 0.014, null, null]), + DATA("Gesamt: 21,6 kWh", [0.016, 0.014, 0.016, 0.015, 0.016, 0.015, 0.015, 0.015, 0.016, 0.017, 0.018, 0.014, 0.016, 0.017, 0.016, 0.015, 0.014, 0.017, 0.015, 0.016, 0.017, 0.016, 0.015, 0.016, 0.014, 0.015, 0.014, 0.016, 0.014, null, null]), ], labels: LABELS(History.MONTH.energyPerPeriodChannelWithValues.result.timestamps), - options: OeTester.ChartOptions.BAR_CHART_OPTIONS('day', 'bar', {}), + options: OeTester.ChartOptions.BAR_CHART_OPTIONS("day", "bar", {}), }, }); } }); - it('#getChartData() - no essDcCharger & no assymetric meter configured', () => { + it("#getChartData() - no essDcCharger & no assymetric meter configured", () => { { const defaultEMS = DummyConfig.from( DummyConfig.Component.SUM("_sum", "Gesamt"), ); - expectView(defaultEMS, TEST_CONTEXT, 'line', History.DAY, + expectView(defaultEMS, TEST_CONTEXT, "line", History.DAY, { datasets: { data: [ - DATA('Gesamt: 15,9 kWh', [0.124, 0, null, 0, 0.173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.11, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.13, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.14, null, null, null, 2.127, 0.175, 0.176, null, 0.18, 0.18, 0.185, 0.18, null, 0.185, 0.19, 0.18, 0.18, 0.176, 0.176, 0.17, 0.175, 0.17, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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("Gesamt: 15,9 kWh", [0.124, 0, null, 0, 0.173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0.11, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.145, 0, 0, 0, 0, 0, 0, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0.113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, null, 0.113, 0, 0, null, 0, 0, 0, 0, 0, 0, 0, null, 0, 0, 0, 0, 0, 0, 0.13, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, null, 0, null, 0.14, null, null, null, 2.127, 0.175, 0.176, null, 0.18, 0.18, 0.185, 0.18, null, 0.185, 0.19, 0.18, 0.18, 0.176, 0.176, 0.17, 0.175, 0.17, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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: OeTester.ChartOptions.LINE_CHART_OPTIONS('hour', 'line', { 'left': { scale: { beginAtZero: true } } }, + options: OeTester.ChartOptions.LINE_CHART_OPTIONS("hour", "line", { "left": { scale: { beginAtZero: true } } }, ), }, }); } { - expectView(defaultEMS, TEST_CONTEXT, 'bar', History.MONTH, + expectView(defaultEMS, TEST_CONTEXT, "bar", History.MONTH, { datasets: { data: [ - DATA('Gesamt: 21,6 kWh', [0.016, 0.014, 0.016, 0.015, 0.016, 0.015, 0.015, 0.015, 0.016, 0.017, 0.018, 0.014, 0.016, 0.017, 0.016, 0.015, 0.014, 0.017, 0.015, 0.016, 0.017, 0.016, 0.015, 0.016, 0.014, 0.015, 0.014, 0.016, 0.014, null, null]), + DATA("Gesamt: 21,6 kWh", [0.016, 0.014, 0.016, 0.015, 0.016, 0.015, 0.015, 0.015, 0.016, 0.017, 0.018, 0.014, 0.016, 0.017, 0.016, 0.015, 0.014, 0.017, 0.015, 0.016, 0.017, 0.016, 0.015, 0.016, 0.014, 0.015, 0.014, 0.016, 0.014, null, null]), ], labels: LABELS(History.MONTH.energyPerPeriodChannelWithValues.result.timestamps), - options: OeTester.ChartOptions.BAR_CHART_OPTIONS('day', 'bar', {}), + options: OeTester.ChartOptions.BAR_CHART_OPTIONS("day", "bar", {}), }, }); } }); }); -export function expectView(config: EdgeConfig, testContext: TestContext & { route: ActivatedRoute }, chartType: 'line' | 'bar', channels: OeTester.Types.Channels, view: OeChartTester.View): void { +export function expectView(config: EdgeConfig, testContext: TestContext & { route: ActivatedRoute }, chartType: "line" | "bar", channels: OeTester.Types.Channels, view: OeChartTester.View): void { expect(removeFunctions(OeChartTester .apply(SumChartDetailsComponent .getChartData( diff --git a/ui/src/app/edge/history/common/production/details/chart/sum.ts b/ui/src/app/edge/history/common/production/details/chart/sum.ts index e3d09200f9d..6c630946ae0 100644 --- a/ui/src/app/edge/history/common/production/details/chart/sum.ts +++ b/ui/src/app/edge/history/common/production/details/chart/sum.ts @@ -1,16 +1,16 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { TranslateService } from '@ngx-translate/core'; -import { AbstractHistoryChart } from 'src/app/shared/components/chart/abstracthistorychart'; -import { Phase } from 'src/app/shared/components/shared/phase'; -import { QueryHistoricTimeseriesEnergyResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; -import { ChartAxis, HistoryUtils, Utils, YAxisTitle } from 'src/app/shared/service/utils'; -import { ChannelAddress, EdgeConfig } from 'src/app/shared/shared'; +import { Component } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { TranslateService } from "@ngx-translate/core"; +import { AbstractHistoryChart } from "src/app/shared/components/chart/abstracthistorychart"; +import { Phase } from "src/app/shared/components/shared/phase"; +import { QueryHistoricTimeseriesEnergyResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse"; +import { ChartAxis, HistoryUtils, Utils, YAxisType } from "src/app/shared/service/utils"; +import { ChannelAddress, EdgeConfig } from "src/app/shared/shared"; @Component({ - selector: 'sumChart', - templateUrl: '../../../../../../shared/components/chart/abstracthistorychart.html', + selector: "sumChart", + templateUrl: "../../../../../../shared/components/chart/abstracthistorychart.html", }) export class SumChartDetailsComponent extends AbstractHistoryChart { @@ -23,8 +23,8 @@ export class SumChartDetailsComponent extends AbstractHistoryChart { const input: HistoryUtils.InputChannel[] = [ { name: component.id, - powerChannel: ChannelAddress.fromString(component.id + '/ProductionActivePower'), - energyChannel: ChannelAddress.fromString(component.id + '/ProductionActiveEnergy'), + powerChannel: ChannelAddress.fromString(component.id + "/ProductionActivePower"), + energyChannel: ChannelAddress.fromString(component.id + "/ProductionActiveEnergy"), }, ]; let converter: ((data: HistoryUtils.ChannelData, phase: string) => any) | null = null; @@ -32,23 +32,23 @@ export class SumChartDetailsComponent extends AbstractHistoryChart { if (hasCharger) { input.push({ name: component.id + "ActualPower", - powerChannel: ChannelAddress.fromString('_sum/ProductionDcActualPower'), + powerChannel: ChannelAddress.fromString("_sum/ProductionDcActualPower"), }); - converter = (data: HistoryUtils.ChannelData, phase: string) => data[component.id + 'ActualPower']?.reduce((arr, el, index) => { - arr.push(Utils.addSafely(Utils.divideSafely(el, 3), data['ProductionAcActivePower' + phase][index])); + converter = (data: HistoryUtils.ChannelData, phase: string) => data[component.id + "ActualPower"]?.reduce((arr, el, index) => { + arr.push(Utils.addSafely(Utils.divideSafely(el, 3), data["ProductionAcActivePower" + phase][index])); return arr; }, []); } if (hasAsymmetricMeters) { - converter = (data, phase) => data['ProductionAcActivePower' + phase]; + converter = (data, phase) => data["ProductionAcActivePower" + phase]; } if (hasAsymmetricMeters || hasCharger) { input.push(...Phase.THREE_PHASE.map(phase => ({ - name: 'ProductionAcActivePower' + phase, - powerChannel: ChannelAddress.fromString(component.id + '/ProductionAcActivePower' + phase), + name: "ProductionAcActivePower" + phase, + powerChannel: ChannelAddress.fromString(component.id + "/ProductionAcActivePower" + phase), }))); } @@ -56,7 +56,7 @@ export class SumChartDetailsComponent extends AbstractHistoryChart { converter ? (data) => Phase.THREE_PHASE.map((phase, i) => ({ name: "Phase " + phase, converter: () => converter(data, phase), - color: 'rgb(' + AbstractHistoryChart.phaseColors[i] + ')', + color: "rgb(" + AbstractHistoryChart.phaseColors[i] + ")", stack: 3, })) : () => []; @@ -64,22 +64,22 @@ export class SumChartDetailsComponent extends AbstractHistoryChart { input: input, output: (data: HistoryUtils.ChannelData) => [ { - name: translate.instant('General.TOTAL'), - nameSuffix: (energyQueryResponse: QueryHistoricTimeseriesEnergyResponse) => energyQueryResponse.result.data['_sum/ProductionActiveEnergy'], + name: translate.instant("General.TOTAL"), + nameSuffix: (energyQueryResponse: QueryHistoricTimeseriesEnergyResponse) => energyQueryResponse.result.data["_sum/ProductionActiveEnergy"], converter: () => data[component.id], - color: 'rgb(0,152,204)', + color: "rgb(0,152,204)", hiddenOnInit: false, stack: 2, }, ...phaseOutput(data), ], tooltip: { - formatNumber: '1.1-2', - afterTitle: translate.instant('General.TOTAL'), + formatNumber: "1.1-2", + afterTitle: translate.instant("General.TOTAL"), }, yAxes: [{ - unit: YAxisTitle.ENERGY, - position: 'left', + unit: YAxisType.ENERGY, + position: "left", yAxisId: ChartAxis.LEFT, }], }; diff --git a/ui/src/app/edge/history/common/production/details/details.overview.ts b/ui/src/app/edge/history/common/production/details/details.overview.ts index f9470110124..985d1698b2b 100644 --- a/ui/src/app/edge/history/common/production/details/details.overview.ts +++ b/ui/src/app/edge/history/common/production/details/details.overview.ts @@ -1,19 +1,19 @@ -import { Component } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; -import { ModalController } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; -import { AbstractHistoryChartOverview } from 'src/app/shared/components/chart/abstractHistoryChartOverview'; -import { NavigationOption } from 'src/app/shared/components/footer/subnavigation/footerNavigation'; -import { Service } from 'src/app/shared/shared'; -import { Role } from 'src/app/shared/type/role'; +import { Component } from "@angular/core"; +import { ActivatedRoute, Router } from "@angular/router"; +import { ModalController } from "@ionic/angular"; +import { TranslateService } from "@ngx-translate/core"; +import { AbstractHistoryChartOverview } from "src/app/shared/components/chart/abstractHistoryChartOverview"; +import { NavigationOption } from "src/app/shared/components/footer/subnavigation/footerNavigation"; +import { Service } from "src/app/shared/shared"; +import { Role } from "src/app/shared/type/role"; @Component({ - templateUrl: './details.overview.html', + templateUrl: "./details.overview.html", }) export class DetailsOverviewComponent extends AbstractHistoryChartOverview { protected navigationButtons: NavigationOption[] = []; - protected componentSome: { type: 'sum' | 'productionMeter' | 'charger', displayName: string } | null = null; + protected componentSome: { type: "sum" | "productionMeter" | "charger", displayName: string } | null = null; constructor( public override service: Service, @@ -31,12 +31,12 @@ export class DetailsOverviewComponent extends AbstractHistoryChartOverview { this.service.getCurrentEdge().then(edge => { // Hide current & voltage - if (this.component?.factoryId === 'Core.Sum') { + if (this.component?.factoryId === "Core.Sum") { return; } this.navigationButtons = [ - { id: 'currentVoltage', isEnabled: edge.roleIsAtLeast(Role.INSTALLER), alias: this.translate.instant("Edge.History.CURRENT_AND_VOLTAGE"), callback: () => { this.router.navigate(['./currentVoltage'], { relativeTo: this.route }); } }]; + { id: "currentVoltage", isEnabled: edge.roleIsAtLeast(Role.INSTALLER), alias: this.translate.instant("Edge.History.CURRENT_AND_VOLTAGE"), callback: () => { this.router.navigate(["./currentVoltage"], { relativeTo: this.route }); } }]; }); } @@ -46,15 +46,15 @@ export class DetailsOverviewComponent extends AbstractHistoryChartOverview { } if (this.config.hasComponentNature("io.openems.edge.ess.dccharger.api.EssDcCharger", this.component.id) && this.component.isEnabled) { - return { type: 'charger', displayName: this.component.alias }; + return { type: "charger", displayName: this.component.alias }; } if (this.config.isProducer(this.component) && this.component.isEnabled) { - return { type: 'productionMeter', displayName: this.component.alias }; + return { type: "productionMeter", displayName: this.component.alias }; } - if (this.component.factoryId === 'Core.Sum') { - return { type: 'sum', displayName: this.translate.instant('General.TOTAL') }; + if (this.component.factoryId === "Core.Sum") { + return { type: "sum", displayName: this.translate.instant("General.TOTAL") }; } return null; 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 f399e593d02..9b61575701d 100644 --- a/ui/src/app/edge/history/common/production/flat/flat.ts +++ b/ui/src/app/edge/history/common/production/flat/flat.ts @@ -1,11 +1,11 @@ -import { Component } from '@angular/core'; -import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; +import { Component } from "@angular/core"; +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; -import { ChannelAddress, EdgeConfig, Utils } from '../../../../../shared/shared'; +import { ChannelAddress, EdgeConfig, Utils } from "../../../../../shared/shared"; @Component({ - selector: 'productionWidget', - templateUrl: './flat.html', + selector: "productionWidget", + templateUrl: "./flat.html", }) export class FlatComponent extends AbstractFlatWidget { diff --git a/ui/src/app/edge/history/common/production/overview/overview.ts b/ui/src/app/edge/history/common/production/overview/overview.ts index 7b6f24fff11..e75c1e02ea0 100644 --- a/ui/src/app/edge/history/common/production/overview/overview.ts +++ b/ui/src/app/edge/history/common/production/overview/overview.ts @@ -1,13 +1,13 @@ -import { Component } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; -import { ModalController } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; -import { NavigationOption } from 'src/app/shared/components/footer/subnavigation/footerNavigation'; -import { AbstractHistoryChartOverview } from '../../../../../shared/components/chart/abstractHistoryChartOverview'; -import { ChannelAddress, EdgeConfig, Service } from '../../../../../shared/shared'; +import { Component } from "@angular/core"; +import { ActivatedRoute, Router } from "@angular/router"; +import { ModalController } from "@ionic/angular"; +import { TranslateService } from "@ngx-translate/core"; +import { NavigationOption } from "src/app/shared/components/footer/subnavigation/footerNavigation"; +import { AbstractHistoryChartOverview } from "../../../../../shared/components/chart/abstractHistoryChartOverview"; +import { ChannelAddress, EdgeConfig, Service } from "../../../../../shared/shared"; @Component({ - templateUrl: './overview.html', + templateUrl: "./overview.html", }) export class OverviewComponent extends AbstractHistoryChartOverview { protected chargerComponents: EdgeConfig.Component[] = []; @@ -35,11 +35,11 @@ export class OverviewComponent extends AbstractHistoryChartOverview { this.config.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") .filter(component => component.isEnabled && this.config.isProducer(component)); - const sum: EdgeConfig.Component = this.config.getComponent('_sum'); - sum.alias = this.translate.instant('General.TOTAL'); + const sum: EdgeConfig.Component = this.config.getComponent("_sum"); + sum.alias = this.translate.instant("General.TOTAL"); this.navigationButtons = [sum, ...this.chargerComponents, ...this.productionMeterComponents].map(el => ( - { id: el.id, alias: el.alias, callback: () => { this.router.navigate(['./' + el.id], { relativeTo: this.route }); } } + { id: el.id, alias: el.alias, callback: () => { this.router.navigate(["./" + el.id], { relativeTo: this.route }); } } )); return []; } diff --git a/ui/src/app/edge/history/common/production/production.ts b/ui/src/app/edge/history/common/production/production.ts index fbd0f922279..d4b7b9ce39c 100644 --- a/ui/src/app/edge/history/common/production/production.ts +++ b/ui/src/app/edge/history/common/production/production.ts @@ -1,16 +1,16 @@ -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; -import { FooterNavigationModule } from 'src/app/shared/components/footer/subnavigation/footerNavigation.module'; -import { SharedModule } from 'src/app/shared/shared.module'; +import { NgModule } from "@angular/core"; +import { BrowserModule } from "@angular/platform-browser"; +import { FooterNavigationModule } from "src/app/shared/components/footer/subnavigation/footerNavigation.module"; +import { SharedModule } from "src/app/shared/shared.module"; -import { CurrentVoltageModule } from 'src/app/shared/components/edge/meter/currentVoltage/currentVoltageModule'; -import { TotalChartComponent } from './chart/totalChart'; -import { ChargerChartDetailsComponent } from './details/chart/charger'; -import { ProductionMeterChartDetailsComponent } from './details/chart/productionMeter'; -import { SumChartDetailsComponent } from './details/chart/sum'; -import { DetailsOverviewComponent } from './details/details.overview'; -import { FlatComponent } from './flat/flat'; -import { OverviewComponent } from './overview/overview'; +import { CurrentVoltageModule } from "src/app/shared/components/edge/meter/currentVoltage/currentVoltageModule"; +import { TotalChartComponent } from "./chart/totalChart"; +import { ChargerChartDetailsComponent } from "./details/chart/charger"; +import { ProductionMeterChartDetailsComponent } from "./details/chart/productionMeter"; +import { SumChartDetailsComponent } from "./details/chart/sum"; +import { DetailsOverviewComponent } from "./details/details.overview"; +import { FlatComponent } from "./flat/flat"; +import { OverviewComponent } from "./overview/overview"; @NgModule({ imports: [ 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 a3854895d42..02c9e4f827f 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,52 +1,52 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { AbstractHistoryChart } from 'src/app/shared/components/chart/abstracthistorychart'; -import { QueryHistoricTimeseriesEnergyResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; -import { ChartAxis, HistoryUtils, Utils, YAxisTitle } from 'src/app/shared/service/utils'; -import { ChannelAddress } from 'src/app/shared/shared'; +import { Component } from "@angular/core"; +import { AbstractHistoryChart } from "src/app/shared/components/chart/abstracthistorychart"; +import { QueryHistoricTimeseriesEnergyResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse"; +import { ChartAxis, HistoryUtils, Utils, YAxisType } from "src/app/shared/service/utils"; +import { ChannelAddress } from "src/app/shared/shared"; @Component({ - selector: 'selfconsumptionChart', - templateUrl: '../../../../../shared/components/chart/abstracthistorychart.html', + selector: "selfconsumptionChart", + templateUrl: "../../../../../shared/components/chart/abstracthistorychart.html", }) export class ChartComponent extends AbstractHistoryChart { protected override getChartData(): HistoryUtils.ChartData { - this.spinnerId = 'selfconsumption-chart'; + this.spinnerId = "selfconsumption-chart"; return { input: [{ - name: 'GridSell', - powerChannel: ChannelAddress.fromString('_sum/GridActivePower'), - energyChannel: ChannelAddress.fromString('_sum/GridSellActiveEnergy'), - ...(this.chartType === 'line' && { converter: HistoryUtils.ValueConverter.POSITIVE_AS_ZERO_AND_INVERT_NEGATIVE }), + name: "GridSell", + powerChannel: ChannelAddress.fromString("_sum/GridActivePower"), + energyChannel: ChannelAddress.fromString("_sum/GridSellActiveEnergy"), + ...(this.chartType === "line" && { converter: HistoryUtils.ValueConverter.POSITIVE_AS_ZERO_AND_INVERT_NEGATIVE }), }, { - name: 'ProductionActivePower', - powerChannel: ChannelAddress.fromString('_sum/ProductionActivePower'), - energyChannel: ChannelAddress.fromString('_sum/ProductionActiveEnergy'), + name: "ProductionActivePower", + powerChannel: ChannelAddress.fromString("_sum/ProductionActivePower"), + energyChannel: ChannelAddress.fromString("_sum/ProductionActiveEnergy"), }], output: (data: HistoryUtils.ChannelData) => { return [{ - name: this.translate.instant('General.selfConsumption'), + name: this.translate.instant("General.selfConsumption"), nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => { - return Utils.calculateSelfConsumption(energyValues?.result.data['_sum/GridSellActiveEnergy'] ?? null, energyValues?.result.data['_sum/ProductionActiveEnergy'] ?? null); + return Utils.calculateSelfConsumption(energyValues?.result.data["_sum/GridSellActiveEnergy"] ?? null, energyValues?.result.data["_sum/ProductionActiveEnergy"] ?? null); }, converter: () => { - return data['GridSell'] + return data["GridSell"] ?.map((value, index) => - Utils.calculateSelfConsumption(value, data['ProductionActivePower'][index]), + Utils.calculateSelfConsumption(value, data["ProductionActivePower"][index]), ); }, - color: 'rgb(253,197,7)', + color: "rgb(253,197,7)", }]; }, tooltip: { - formatNumber: '1.0-0', + formatNumber: "1.0-0", }, yAxes: [{ - unit: YAxisTitle.PERCENTAGE, - position: 'left', + unit: YAxisType.PERCENTAGE, + position: "left", yAxisId: ChartAxis.LEFT, }], }; diff --git a/ui/src/app/edge/history/common/selfconsumption/flat/flat.ts b/ui/src/app/edge/history/common/selfconsumption/flat/flat.ts index 6d617da7808..4cc5d5fe127 100644 --- a/ui/src/app/edge/history/common/selfconsumption/flat/flat.ts +++ b/ui/src/app/edge/history/common/selfconsumption/flat/flat.ts @@ -1,11 +1,11 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; -import { ChannelAddress, CurrentData, Utils } from 'src/app/shared/shared'; +import { Component } from "@angular/core"; +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; +import { ChannelAddress, CurrentData, Utils } from "src/app/shared/shared"; @Component({ - selector: 'selfconsumptionWidget', - templateUrl: './flat.html', + selector: "selfconsumptionWidget", + templateUrl: "./flat.html", }) export class FlatComponent extends AbstractFlatWidget { @@ -13,15 +13,15 @@ export class FlatComponent extends AbstractFlatWidget { protected override onCurrentData(currentData: CurrentData) { this.selfconsumptionValue = Utils.calculateSelfConsumption( - currentData.allComponents['_sum/GridSellActiveEnergy'], - currentData.allComponents['_sum/ProductionActiveEnergy'], + currentData.allComponents["_sum/GridSellActiveEnergy"], + currentData.allComponents["_sum/ProductionActiveEnergy"], ); } protected override getChannelAddresses(): ChannelAddress[] { return [ - new ChannelAddress('_sum', 'GridSellActiveEnergy'), - new ChannelAddress('_sum', 'ProductionActiveEnergy'), + new ChannelAddress("_sum", "GridSellActiveEnergy"), + new ChannelAddress("_sum", "ProductionActiveEnergy"), ]; } } diff --git a/ui/src/app/edge/history/common/selfconsumption/overview/overview.ts b/ui/src/app/edge/history/common/selfconsumption/overview/overview.ts index a3f812c1a88..51ed8f95a67 100644 --- a/ui/src/app/edge/history/common/selfconsumption/overview/overview.ts +++ b/ui/src/app/edge/history/common/selfconsumption/overview/overview.ts @@ -1,7 +1,7 @@ -import { Component } from '@angular/core'; -import { AbstractHistoryChartOverview } from 'src/app/shared/components/chart/abstractHistoryChartOverview'; +import { Component } from "@angular/core"; +import { AbstractHistoryChartOverview } from "src/app/shared/components/chart/abstractHistoryChartOverview"; @Component({ - templateUrl: './overview.html', + templateUrl: "./overview.html", }) export class OverviewComponent extends AbstractHistoryChartOverview { } diff --git a/ui/src/app/edge/history/delayedselltogrid/chart.component.ts b/ui/src/app/edge/history/delayedselltogrid/chart.component.ts index 358aef34881..deb3efeec3c 100644 --- a/ui/src/app/edge/history/delayedselltogrid/chart.component.ts +++ b/ui/src/app/edge/history/delayedselltogrid/chart.component.ts @@ -1,16 +1,16 @@ // @ts-strict-ignore -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 { YAxisTitle } from 'src/app/shared/service/utils'; +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 { YAxisType } from "src/app/shared/service/utils"; -import { ChannelAddress, Edge, EdgeConfig, Service, Utils } from '../../../shared/shared'; -import { AbstractHistoryChart } from '../abstracthistorychart'; +import { ChannelAddress, Edge, EdgeConfig, Service, Utils } from "../../../shared/shared"; +import { AbstractHistoryChart } from "../abstracthistorychart"; @Component({ - selector: 'delayedselltogridgchart', - templateUrl: '../abstracthistorychart.html', + selector: "delayedselltogridgchart", + templateUrl: "../abstracthistorychart.html", }) export class DelayedSellToGridChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { @@ -32,7 +32,6 @@ export class DelayedSellToGridChartComponent extends AbstractHistoryChart implem ngOnInit() { this.startSpinner(); - this.service.setCurrentComponent('', this.route); } ngOnDestroy() { @@ -50,9 +49,9 @@ export class DelayedSellToGridChartComponent extends AbstractHistoryChart implem this.colors = []; this.queryHistoricTimeseriesData(this.period.from, this.period.to).then(response => { this.service.getConfig().then(config => { - const meterIdActivePower = config.getComponent(this.componentId).properties['meter.id'] + '/ActivePower'; - const sellToGridPowerLimit = this.componentId + '/_PropertySellToGridPowerLimit'; - const continuousSellToGridPower = this.componentId + '/_PropertyContinuousSellToGridPower'; + const meterIdActivePower = config.getComponent(this.componentId).properties["meter.id"] + "/ActivePower"; + const sellToGridPowerLimit = this.componentId + "/_PropertySellToGridPowerLimit"; + const continuousSellToGridPower = this.componentId + "/_PropertyContinuousSellToGridPower"; const result = response.result; // convert labels const labels: Date[] = []; @@ -75,13 +74,13 @@ export class DelayedSellToGridChartComponent extends AbstractHistoryChart implem } }); datasets.push({ - label: this.translate.instant('General.gridSell'), + label: this.translate.instant("General.gridSell"), data: data, hidden: false, }); this.colors.push({ - backgroundColor: 'rgba(0,0,0,0.05)', - borderColor: 'rgba(0,0,0,1)', + backgroundColor: "rgba(0,0,0,0.05)", + borderColor: "rgba(0,0,0,1)", }); } if (sellToGridPowerLimit in result.data) { @@ -95,14 +94,14 @@ export class DelayedSellToGridChartComponent extends AbstractHistoryChart implem } }); datasets.push({ - label: this.translate.instant('Edge.Index.Widgets.DelayedSellToGrid.sellToGridPowerLimit'), + label: this.translate.instant("Edge.Index.Widgets.DelayedSellToGrid.sellToGridPowerLimit"), data: data, hidden: false, borderDash: [3, 3], }); this.colors.push({ - backgroundColor: 'rgba(0,0,0,0)', - borderColor: 'rgba(0,223,0,1)', + backgroundColor: "rgba(0,0,0,0)", + borderColor: "rgba(0,223,0,1)", }); } if (continuousSellToGridPower in result.data) { @@ -116,27 +115,27 @@ export class DelayedSellToGridChartComponent extends AbstractHistoryChart implem } }); datasets.push({ - label: this.translate.instant('Edge.Index.Widgets.DelayedSellToGrid.continuousSellToGridPower'), + label: this.translate.instant("Edge.Index.Widgets.DelayedSellToGrid.continuousSellToGridPower"), data: data, hidden: false, borderDash: [3, 3], }); this.colors.push({ - backgroundColor: 'rgba(0,0,0,0)', - borderColor: 'rgba(200,0,0,1)', + backgroundColor: "rgba(0,0,0,0)", + borderColor: "rgba(200,0,0,1)", }); } - if ('_sum/EssActivePower' in result.data) { + 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); + 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']; + effectivePower = result.data["_sum/EssActivePower"]; } const chargeData = effectivePower.map(value => { if (value == null) { @@ -148,13 +147,13 @@ export class DelayedSellToGridChartComponent extends AbstractHistoryChart implem } }); datasets.push({ - label: this.translate.instant('General.chargePower'), + label: this.translate.instant("General.chargePower"), data: chargeData, borderDash: [10, 10], }); this.colors.push({ - backgroundColor: 'rgba(0,223,0,0.05)', - borderColor: 'rgba(0,223,0,1)', + backgroundColor: "rgba(0,223,0,0.05)", + borderColor: "rgba(0,223,0,1)", }); /* * Storage Discharge @@ -169,13 +168,13 @@ export class DelayedSellToGridChartComponent extends AbstractHistoryChart implem } }); datasets.push({ - label: this.translate.instant('General.dischargePower'), + label: this.translate.instant("General.dischargePower"), data: dischargeData, borderDash: [10, 10], }); this.colors.push({ - backgroundColor: 'rgba(200,0,0,0.05)', - borderColor: 'rgba(200,0,0,1)', + backgroundColor: "rgba(200,0,0,0.05)", + borderColor: "rgba(200,0,0,1)", }); } this.datasets = datasets; @@ -193,7 +192,7 @@ export class DelayedSellToGridChartComponent extends AbstractHistoryChart implem this.initializeChart(); return; }).finally(() => { - this.unit = YAxisTitle.ENERGY; + this.unit = YAxisType.ENERGY; this.setOptions(this.options); }); } @@ -201,11 +200,11 @@ export class DelayedSellToGridChartComponent extends AbstractHistoryChart implem protected getChannelAddresses(edge: Edge, config: EdgeConfig): Promise { return new Promise((resolve) => { const result: ChannelAddress[] = [ - new ChannelAddress(this.componentId, '_PropertySellToGridPowerLimit'), - new ChannelAddress(this.componentId, '_PropertyContinuousSellToGridPower'), - new ChannelAddress(config.getComponent(this.componentId).properties['meter.id'], 'ActivePower'), - new ChannelAddress('_sum', 'ProductionDcActualPower'), - new ChannelAddress('_sum', 'EssActivePower'), + new ChannelAddress(this.componentId, "_PropertySellToGridPowerLimit"), + new ChannelAddress(this.componentId, "_PropertyContinuousSellToGridPower"), + new ChannelAddress(config.getComponent(this.componentId).properties["meter.id"], "ActivePower"), + new ChannelAddress("_sum", "ProductionDcActualPower"), + new ChannelAddress("_sum", "EssActivePower"), ]; resolve(result); }); diff --git a/ui/src/app/edge/history/delayedselltogrid/symmetricpeakshavingchartoverview/delayedselltogridchartoverview.component.ts b/ui/src/app/edge/history/delayedselltogrid/symmetricpeakshavingchartoverview/delayedselltogridchartoverview.component.ts index c258d3f48df..b7b4f44eed3 100644 --- a/ui/src/app/edge/history/delayedselltogrid/symmetricpeakshavingchartoverview/delayedselltogridchartoverview.component.ts +++ b/ui/src/app/edge/history/delayedselltogrid/symmetricpeakshavingchartoverview/delayedselltogridchartoverview.component.ts @@ -1,10 +1,10 @@ -import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { Edge, EdgeConfig, Service } from '../../../../shared/shared'; +import { Component, OnInit } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { Edge, EdgeConfig, Service } from "../../../../shared/shared"; @Component({ selector: DelayedSellToGridChartOverviewComponent.SELECTOR, - templateUrl: './delayedselltogridchartoverview.component.html', + templateUrl: "./delayedselltogridchartoverview.component.html", }) export class DelayedSellToGridChartOverviewComponent implements OnInit { @@ -18,7 +18,7 @@ export class DelayedSellToGridChartOverviewComponent implements OnInit { ) { } ngOnInit() { - this.service.setCurrentComponent('', this.route).then(edge => { + this.service.getCurrentEdge().then(edge => { this.service.getConfig().then(config => { this.edge = edge; this.component = config.getComponent(this.route.snapshot.params.componentId); diff --git a/ui/src/app/edge/history/delayedselltogrid/widget.component.ts b/ui/src/app/edge/history/delayedselltogrid/widget.component.ts index a31ec5da133..7d618d15e6e 100644 --- a/ui/src/app/edge/history/delayedselltogrid/widget.component.ts +++ b/ui/src/app/edge/history/delayedselltogrid/widget.component.ts @@ -1,11 +1,11 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; -import { Edge, EdgeConfig, Service } from 'src/app/shared/shared'; +import { Component, Input, OnInit } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { DefaultTypes } from "src/app/shared/service/defaulttypes"; +import { Edge, EdgeConfig, Service } from "src/app/shared/shared"; @Component({ selector: DelayedSellToGridWidgetComponent.SELECTOR, - templateUrl: './widget.component.html', + templateUrl: "./widget.component.html", }) export class DelayedSellToGridWidgetComponent implements OnInit { @@ -22,7 +22,7 @@ export class DelayedSellToGridWidgetComponent implements OnInit { ) { } ngOnInit() { - this.service.setCurrentComponent('', this.route).then(edge => { + this.service.getCurrentEdge().then(edge => { this.edge = edge; this.service.getConfig().then(config => { this.component = config.getComponent(this.componentId); diff --git a/ui/src/app/edge/history/fixdigitaloutput/fixdigitaloutputchartoverview/fixdigitaloutputchartoverview.component.html b/ui/src/app/edge/history/fixdigitaloutput/fixdigitaloutputchartoverview/fixdigitaloutputchartoverview.component.html deleted file mode 100644 index e516087b8b3..00000000000 --- a/ui/src/app/edge/history/fixdigitaloutput/fixdigitaloutputchartoverview/fixdigitaloutputchartoverview.component.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - {{ component.alias }} - - - - - - - - - - - - - - - - - - - - - - -
      General.TOTAL
      - - -
      -
      - - - - - - -
      - - -
      -
      -
      -
      diff --git a/ui/src/app/edge/history/fixdigitaloutput/fixdigitaloutputchartoverview/fixdigitaloutputchartoverview.component.ts b/ui/src/app/edge/history/fixdigitaloutput/fixdigitaloutputchartoverview/fixdigitaloutputchartoverview.component.ts deleted file mode 100644 index 59d90f56e80..00000000000 --- a/ui/src/app/edge/history/fixdigitaloutput/fixdigitaloutputchartoverview/fixdigitaloutputchartoverview.component.ts +++ /dev/null @@ -1,49 +0,0 @@ -// @ts-strict-ignore -import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { Edge, EdgeConfig, Service, Utils } from '../../../../shared/shared'; - -@Component({ - selector: FixDigitalOutputChartOverviewComponent.SELECTOR, - templateUrl: './fixdigitaloutputchartoverview.component.html', -}) -export class FixDigitalOutputChartOverviewComponent implements OnInit { - - private static readonly SELECTOR = "fixdigitaloutput-chart-overview"; - - public edge: Edge | null = null; - public component: EdgeConfig.Component | null = null; - - public showTotal: boolean = false; - public fixDigitalOutputComponents: string[] = []; - - // reference to the Utils method to access via html - public isLastElement = Utils.isLastElement; - - constructor( - public service: Service, - private route: ActivatedRoute, - ) { } - - ngOnInit() { - this.service.setCurrentComponent('', this.route).then(edge => { - this.service.getConfig().then(config => { - this.edge = edge; - this.component = config.getComponent(this.route.snapshot.params.componentId); - config.getComponentsByFactory('Controller.Io.FixDigitalOutput').forEach(component => { - this.fixDigitalOutputComponents.push(component.id); - }); - if (this.fixDigitalOutputComponents.length > 1) { - this.showTotal = false; - } else if (this.fixDigitalOutputComponents.length == 1) { - this.showTotal = null; - } - }); - }); - - } - - onNotifyTotal(showTotal: boolean): void { - this.showTotal = showTotal; - } -} diff --git a/ui/src/app/edge/history/fixdigitaloutput/singlechart.component.ts b/ui/src/app/edge/history/fixdigitaloutput/singlechart.component.ts deleted file mode 100644 index bc55416a9c8..00000000000 --- a/ui/src/app/edge/history/fixdigitaloutput/singlechart.component.ts +++ /dev/null @@ -1,108 +0,0 @@ -// @ts-strict-ignore -import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { TranslateService } from '@ngx-translate/core'; -import * as Chart from 'chart.js'; -import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; -import { YAxisTitle } from 'src/app/shared/service/utils'; - -import { QueryHistoricTimeseriesDataResponse } from '../../../shared/jsonrpc/response/queryHistoricTimeseriesDataResponse'; -import { ChannelAddress, Edge, EdgeConfig, Service } from '../../../shared/shared'; -import { AbstractHistoryChart } from '../abstracthistorychart'; - -@Component({ - selector: 'fixDigitalOutputSingleChart', - templateUrl: '../abstracthistorychart.html', -}) -export class FixDigitalOutputSingleChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - - @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; - @Input({ required: true }) public componentId!: string; - - - constructor( - protected override service: Service, - protected override translate: TranslateService, - private route: ActivatedRoute, - ) { - super("fixdigitaloutput-single-chart", service, translate); - } - - ngOnChanges() { - this.updateChart(); - } - - ngOnInit() { - this.startSpinner(); - this.service.setCurrentComponent('', this.route); - } - - ngOnDestroy() { - this.unsubscribeChartRefresh(); - } - - public getChartHeight(): number { - return window.innerHeight / 1.3; - } - - protected updateChart() { - this.autoSubscribeChartRefresh(); - this.startSpinner(); - this.colors = []; - this.loading = true; - this.queryHistoricTimeseriesData(this.period.from, this.period.to).then(response => { - const result = (response as QueryHistoricTimeseriesDataResponse).result; - // convert labels - const labels: Date[] = []; - for (const timestamp of result.timestamps) { - labels.push(new Date(timestamp)); - } - this.labels = labels; - - // convert datasets - const datasets: Chart.ChartDataset[] = []; - for (const channel in result.data) { - const address = ChannelAddress.fromString(channel); - const data = result.data[channel].map(value => { - if (value == null) { - return null; - } else { - return value * 100; // convert to % [0,100] - } - }); - datasets.push({ - label: address.channelId, - data: data, - }); - this.colors.push({ - backgroundColor: 'rgba(0,191,255,0.05)', - borderColor: 'rgba(0,191,255,1)', - }); - } - this.datasets = datasets; - this.loading = false; - this.stopSpinner(); - }).catch(reason => { - console.error(reason); // TODO error message - this.initializeChart(); - return; - }).finally(async () => { - this.unit = YAxisTitle.PERCENTAGE; - await this.setOptions(this.options); - this.stopSpinner(); - }); - } - - protected getChannelAddresses(edge: Edge, config: EdgeConfig): Promise { - return new Promise((resolve) => { - const outputChannel = ChannelAddress.fromString(config.getComponentProperties(this.componentId)['outputChannelAddress']); - const channeladdresses = [outputChannel]; - resolve(channeladdresses); - }); - } - - protected setLabel() { - this.options = this.createDefaultChartOptions(); - } - -} diff --git a/ui/src/app/edge/history/fixdigitaloutput/totalchart.component.ts b/ui/src/app/edge/history/fixdigitaloutput/totalchart.component.ts deleted file mode 100644 index e675ed613c0..00000000000 --- a/ui/src/app/edge/history/fixdigitaloutput/totalchart.component.ts +++ /dev/null @@ -1,126 +0,0 @@ -// @ts-strict-ignore -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 { YAxisTitle } from 'src/app/shared/service/utils'; - -import { QueryHistoricTimeseriesDataResponse } from '../../../shared/jsonrpc/response/queryHistoricTimeseriesDataResponse'; -import { ChannelAddress, Service } from '../../../shared/shared'; -import { AbstractHistoryChart } from '../abstracthistorychart'; - -@Component({ - selector: 'fixDigitalOutputTotalChart', - templateUrl: '../abstracthistorychart.html', -}) -export class FixDigitalOutputTotalChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - - @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; - - constructor( - protected override service: Service, - protected override translate: TranslateService, - private route: ActivatedRoute, - ) { - super("fixdigitaloutput-total-chart", service, translate); - } - - ngOnChanges() { - this.updateChart(); - } - - ngOnInit() { - this.startSpinner(); - this.service.setCurrentComponent('', this.route); - } - - ngOnDestroy() { - this.unsubscribeChartRefresh(); - } - - public getChartHeight(): number { - return window.innerHeight / 1.3; - } - protected updateChart() { - this.autoSubscribeChartRefresh(); - this.startSpinner(); - this.colors = []; - this.loading = true; - this.queryHistoricTimeseriesData(this.period.from, this.period.to).then(response => { - const result = (response as QueryHistoricTimeseriesDataResponse).result; - // convert labels - const labels: Date[] = []; - for (const timestamp of result.timestamps) { - labels.push(new Date(timestamp)); - } - this.labels = labels; - - - const datasets = []; - // convert datasets - Object.keys(result.data).forEach((channel, index) => { - const address = ChannelAddress.fromString(channel); - const data = result.data[channel]?.map((value) => { - if (value == null) { - return null; - } else { - return value * 100; // convert to % [0,100] - } - }); - switch (index % 2) { - case 0: - datasets.push({ - label: address.channelId, - data: data, - }); - this.colors.push({ - backgroundColor: 'rgba(0,191,255,0.05)', - borderColor: 'rgba(0,191,255,1)', - }); - break; - case 1: - datasets.push({ - label: address.channelId, - data: data, - }); - this.colors.push({ - backgroundColor: 'rgba(0,0,139,0.05)', - borderColor: 'rgba(0,0,139,1)', - }); - break; - } - this.datasets = datasets; - this.loading = false; - this.stopSpinner(); - - }); - }).catch(reason => { - console.error(reason); // TODO error message - this.initializeChart(); - return; - }).finally(async () => { - this.unit = YAxisTitle.PERCENTAGE; - this.formatNumber = '1.0-0'; - await this.setOptions(this.options); - }); - } - - protected getChannelAddresses(): Promise { - return new Promise((resolve, reject) => { - this.service.getConfig().then(config => { - const channeladdresses = []; - // find all FixIoControllers - config.getComponentsByFactory('Controller.Io.FixDigitalOutput').forEach(component => { - const outputChannel = ChannelAddress.fromString(config.getComponentProperties(component.id)['outputChannelAddress']); - channeladdresses.push(outputChannel); - }); - resolve(channeladdresses); - }).catch(reason => reject(reason)); - }); - } - - protected setLabel() { - this.options = this.createDefaultChartOptions(); - } - -} diff --git a/ui/src/app/edge/history/fixdigitaloutput/widget.component.html b/ui/src/app/edge/history/fixdigitaloutput/widget.component.html deleted file mode 100644 index fb8bf4bc466..00000000000 --- a/ui/src/app/edge/history/fixdigitaloutput/widget.component.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - {{ component.alias }} - - - - - - - -
      - Edge.History.activeDuration - {{ activeSecondsOverPeriod | formatSecondsToDuration }} -
      -
      -
      diff --git a/ui/src/app/edge/history/fixdigitaloutput/widget.component.ts b/ui/src/app/edge/history/fixdigitaloutput/widget.component.ts deleted file mode 100644 index 7ca50fb8bf5..00000000000 --- a/ui/src/app/edge/history/fixdigitaloutput/widget.component.ts +++ /dev/null @@ -1,68 +0,0 @@ -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'; - -@Component({ - selector: FixDigitalOutputWidgetComponent.SELECTOR, - templateUrl: './widget.component.html', -}) -export class FixDigitalOutputWidgetComponent extends AbstractHistoryWidget implements OnInit, OnChanges, OnDestroy { - - private static readonly SELECTOR = "fixDigitalOutputWidget"; - @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; - @Input({ required: true }) public componentId!: string; - - public component: EdgeConfig.Component | null = null; - public activeSecondsOverPeriod: number | null = null; - public edge: Edge | null = null; - private config: EdgeConfig | null = null; - - constructor( - public override service: Service, - private route: ActivatedRoute, - ) { - super(service); - } - - ngOnInit() { - this.service.setCurrentComponent('', this.route).then(response => { - this.service.getConfig().then(config => { - this.edge = response; - this.config = config; - this.component = config.getComponent(this.componentId); - }); - }); - } - - ngOnDestroy() { - this.unsubscribeWidgetRefresh(); - } - - ngOnChanges() { - this.updateValues(); - } - - protected updateValues() { - // Gather result & timestamps to calculate effective active time in % - this.queryHistoricTimeseriesData(this.service.historyPeriod.value.from, this.service.historyPeriod.value.to).then(response => { - const result = (response as QueryHistoricTimeseriesDataResponse).result; - this.service.getConfig().then(config => { - const outputChannel = ChannelAddress.fromString(config.getComponentProperties(this.componentId)['outputChannelAddress']); - this.activeSecondsOverPeriod = calculateActiveTimeOverPeriod(outputChannel, result); - }); - }); - } - - protected getChannelAddresses(edge: Edge, config: EdgeConfig): Promise { - return new Promise((resolve) => { - const outputChannel = ChannelAddress.fromString(config.getComponentProperties(this.componentId)['outputChannelAddress']); - const channeladdresses = [outputChannel]; - resolve(channeladdresses); - }); - } -} diff --git a/ui/src/app/edge/history/heatingelement/chart.component.ts b/ui/src/app/edge/history/heatingelement/chart.component.ts index 298858a48eb..49dd46bf02c 100644 --- a/ui/src/app/edge/history/heatingelement/chart.component.ts +++ b/ui/src/app/edge/history/heatingelement/chart.component.ts @@ -1,19 +1,19 @@ // @ts-strict-ignore -import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { TranslateService } from '@ngx-translate/core'; +import { Component, Input, OnChanges, OnDestroy, OnInit } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { TranslateService } from "@ngx-translate/core"; -import type { ChartOptions } from 'chart.js'; -import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; -import { ChartAxis, YAxisTitle } from 'src/app/shared/service/utils'; +import type { ChartOptions } from "chart.js"; +import { DefaultTypes } from "src/app/shared/service/defaulttypes"; +import { ChartAxis, YAxisType } from "src/app/shared/service/utils"; -import { QueryHistoricTimeseriesDataResponse } from '../../../shared/jsonrpc/response/queryHistoricTimeseriesDataResponse'; -import { ChannelAddress, Edge, EdgeConfig, Service } from '../../../shared/shared'; -import { AbstractHistoryChart } from '../abstracthistorychart'; +import { QueryHistoricTimeseriesDataResponse } from "../../../shared/jsonrpc/response/queryHistoricTimeseriesDataResponse"; +import { ChannelAddress, Edge, EdgeConfig, Service } from "../../../shared/shared"; +import { AbstractHistoryChart } from "../abstracthistorychart"; @Component({ - selector: 'heatingelementChart', - templateUrl: '../abstracthistorychart.html', + selector: "heatingelementChart", + templateUrl: "../abstracthistorychart.html", }) export class HeatingelementChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { @@ -34,7 +34,6 @@ export class HeatingelementChartComponent extends AbstractHistoryChart implement ngOnInit() { this.startSpinner(); - this.service.setCurrentComponent('', this.route); this.setLabel(); } @@ -63,7 +62,7 @@ export class HeatingelementChartComponent extends AbstractHistoryChart implement // convert datasets const datasets = []; - const level = this.component.id + '/Level'; + const level = this.component.id + "/Level"; if (level in result.data) { const levelData = result.data[level].map(value => { @@ -74,12 +73,12 @@ export class HeatingelementChartComponent extends AbstractHistoryChart implement } }); datasets.push({ - label: 'Level', + label: "Level", data: levelData, }); this.colors.push({ - backgroundColor: 'rgba(200,0,0,0.05)', - borderColor: 'rgba(200,0,0,1)', + backgroundColor: "rgba(200,0,0,0.05)", + borderColor: "rgba(200,0,0,1)", }); } this.datasets = datasets; @@ -97,8 +96,8 @@ export class HeatingelementChartComponent extends AbstractHistoryChart implement this.initializeChart(); return; }).finally(async () => { - this.formatNumber = '1.0-1'; - this.unit = YAxisTitle.NONE; + this.formatNumber = "1.0-1"; + this.unit = YAxisType.NONE; await this.setOptions(this.options); this.applyControllerSpecificOptions(this.options); }); @@ -106,17 +105,17 @@ export class HeatingelementChartComponent extends AbstractHistoryChart implement protected getChannelAddresses(edge: Edge, config: EdgeConfig): Promise { return new Promise((resolve) => { - const levels = new ChannelAddress(this.component.id, 'Level'); + const levels = new ChannelAddress(this.component.id, "Level"); const channeladdresses = [levels]; resolve(channeladdresses); }); } protected applyControllerSpecificOptions(options: ChartOptions) { - options.scales[ChartAxis.LEFT]['title'].text = 'Level'; - options.scales[ChartAxis.LEFT]['beginAtZero'] = true; + options.scales[ChartAxis.LEFT]["title"].text = "Level"; + options.scales[ChartAxis.LEFT]["beginAtZero"] = true; options.scales[ChartAxis.LEFT].max = 3; - options.scales[ChartAxis.LEFT].ticks['stepSize'] = 1; + options.scales[ChartAxis.LEFT].ticks["stepSize"] = 1; this.options = options; } diff --git a/ui/src/app/edge/history/heatingelement/heatingelementchartoverview/heatingelementchartoverview.component.ts b/ui/src/app/edge/history/heatingelement/heatingelementchartoverview/heatingelementchartoverview.component.ts index 440eeb2c38b..f615818d7c3 100644 --- a/ui/src/app/edge/history/heatingelement/heatingelementchartoverview/heatingelementchartoverview.component.ts +++ b/ui/src/app/edge/history/heatingelement/heatingelementchartoverview/heatingelementchartoverview.component.ts @@ -1,10 +1,10 @@ -import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { Edge, EdgeConfig, Service } from '../../../../shared/shared'; +import { Component, OnInit } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { Edge, EdgeConfig, Service } from "../../../../shared/shared"; @Component({ selector: HeatingelementChartOverviewComponent.SELECTOR, - templateUrl: './heatingelementchartoverview.component.html', + templateUrl: "./heatingelementchartoverview.component.html", }) export class HeatingelementChartOverviewComponent implements OnInit { @@ -18,7 +18,7 @@ export class HeatingelementChartOverviewComponent implements OnInit { ) { } ngOnInit() { - this.service.setCurrentComponent('', this.route).then(edge => { + this.service.getCurrentEdge().then(edge => { this.service.getConfig().then(config => { this.component = config.getComponent(this.route.snapshot.params.componentId); this.service.getConfig().then(config => { diff --git a/ui/src/app/edge/history/heatingelement/widget.component.ts b/ui/src/app/edge/history/heatingelement/widget.component.ts index 5f39ae03bd0..262c025d23c 100644 --- a/ui/src/app/edge/history/heatingelement/widget.component.ts +++ b/ui/src/app/edge/history/heatingelement/widget.component.ts @@ -1,14 +1,14 @@ -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 { 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 { ChannelAddress, Edge, EdgeConfig, Service } from "../../../shared/shared"; +import { AbstractHistoryWidget } from "../abstracthistorywidget"; @Component({ selector: HeatingelementWidgetComponent.SELECTOR, - templateUrl: './widget.component.html', + templateUrl: "./widget.component.html", }) export class HeatingelementWidgetComponent extends AbstractHistoryWidget implements OnInit, OnChanges, OnDestroy { @@ -33,7 +33,7 @@ export class HeatingelementWidgetComponent extends AbstractHistoryWidget impleme } ngOnInit() { - this.service.setCurrentComponent('', this.route).then(edge => { + this.service.getCurrentEdge().then(edge => { this.edge = edge; this.service.getConfig().then(config => { this.component = config.getComponent(this.componentId); @@ -58,18 +58,18 @@ export class HeatingelementWidgetComponent extends AbstractHistoryWidget impleme protected updateValues() { this.queryHistoricTimeseriesData(this.service.historyPeriod.value.from, this.service.historyPeriod.value.to).then(response => { - this.activeTimeOverPeriodLevel1 = this.getCumulativeValue(this.componentId + '/Level1CumulatedTime', response); - this.activeTimeOverPeriodLevel2 = this.getCumulativeValue(this.componentId + '/Level2CumulatedTime', response); - this.activeTimeOverPeriodLevel3 = this.getCumulativeValue(this.componentId + '/Level3CumulatedTime', response); + this.activeTimeOverPeriodLevel1 = this.getCumulativeValue(this.componentId + "/Level1CumulatedTime", response); + this.activeTimeOverPeriodLevel2 = this.getCumulativeValue(this.componentId + "/Level2CumulatedTime", response); + this.activeTimeOverPeriodLevel3 = this.getCumulativeValue(this.componentId + "/Level3CumulatedTime", response); }); } protected getChannelAddresses(edge: Edge, config: EdgeConfig): Promise { return new Promise((resolve) => { const channeladdresses = [ - new ChannelAddress(this.componentId, 'Level1CumulatedTime'), - new ChannelAddress(this.componentId, 'Level2CumulatedTime'), - new ChannelAddress(this.componentId, 'Level3CumulatedTime'), + new ChannelAddress(this.componentId, "Level1CumulatedTime"), + new ChannelAddress(this.componentId, "Level2CumulatedTime"), + new ChannelAddress(this.componentId, "Level3CumulatedTime"), ]; resolve(channeladdresses); }); diff --git a/ui/src/app/edge/history/heatpump/chart.component.ts b/ui/src/app/edge/history/heatpump/chart.component.ts index 3a00779b838..4e39df05a3c 100644 --- a/ui/src/app/edge/history/heatpump/chart.component.ts +++ b/ui/src/app/edge/history/heatpump/chart.component.ts @@ -1,17 +1,17 @@ // @ts-strict-ignore -import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { TranslateService } from '@ngx-translate/core'; -import * as Chart from 'chart.js'; -import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; -import { ChartAxis } from 'src/app/shared/service/utils'; +import { Component, Input, OnChanges, OnDestroy, OnInit } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { TranslateService } from "@ngx-translate/core"; +import * as Chart from "chart.js"; +import { DefaultTypes } from "src/app/shared/service/defaulttypes"; +import { ChartAxis } from "src/app/shared/service/utils"; -import { ChannelAddress, EdgeConfig, Service } from '../../../shared/shared'; -import { AbstractHistoryChart } from '../abstracthistorychart'; +import { ChannelAddress, EdgeConfig, Service } from "../../../shared/shared"; +import { AbstractHistoryChart } from "../abstracthistorychart"; @Component({ - selector: 'heatpumpchart', - templateUrl: '../abstracthistorychart.html', + selector: "heatpumpchart", + templateUrl: "../abstracthistorychart.html", }) export class HeatPumpChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { @@ -33,7 +33,6 @@ export class HeatPumpChartComponent extends AbstractHistoryChart implements OnIn ngOnInit() { this.startSpinner(); - this.service.setCurrentComponent('', this.route); } ngOnDestroy() { @@ -61,9 +60,9 @@ export class HeatPumpChartComponent extends AbstractHistoryChart implements OnIn // convert datasets const datasets = []; - if (this.component.id + '/Status' in result.data) { + if (this.component.id + "/Status" in result.data) { - const stateTimeData = result.data[this.component.id + '/Status'].map(value => { + const stateTimeData = result.data[this.component.id + "/Status"].map(value => { if (value == null) { return null; } else { @@ -72,13 +71,13 @@ export class HeatPumpChartComponent extends AbstractHistoryChart implements OnIn }); datasets.push({ - label: this.translate.instant('General.state'), + label: this.translate.instant("General.state"), data: stateTimeData, hidden: false, }); this.colors.push({ - backgroundColor: 'rgba(200,0,0,0.05)', - borderColor: 'rgba(200,0,0,1)', + backgroundColor: "rgba(200,0,0,0.05)", + borderColor: "rgba(200,0,0,1)", }); } this.datasets = datasets; @@ -97,7 +96,7 @@ export class HeatPumpChartComponent extends AbstractHistoryChart implements OnIn protected getChannelAddresses(): Promise { return new Promise((resolve) => { - resolve([new ChannelAddress(this.component.id, 'Status')]); + resolve([new ChannelAddress(this.component.id, "Status")]); }); } @@ -107,19 +106,19 @@ export class HeatPumpChartComponent extends AbstractHistoryChart implements OnIn private applyControllerSpecificOptions(options: Chart.ChartOptions) { const translate = this.translate; - options.scales[ChartAxis.LEFT]['title'].text = this.translate.instant('General.state'); + options.scales[ChartAxis.LEFT]["title"].text = this.translate.instant("General.state"); options.scales[ChartAxis.LEFT].ticks.callback = function (label, index, labels) { switch (label) { case -1: - return translate.instant('Edge.Index.Widgets.HeatPump.undefined'); + return translate.instant("Edge.Index.Widgets.HeatPump.undefined"); case 0: - return translate.instant('Edge.Index.Widgets.HeatPump.lock'); + return translate.instant("Edge.Index.Widgets.HeatPump.lock"); case 1: - return translate.instant('Edge.Index.Widgets.HeatPump.normalOperationShort'); + return translate.instant("Edge.Index.Widgets.HeatPump.normalOperationShort"); case 2: - return translate.instant('Edge.Index.Widgets.HeatPump.switchOnRecShort'); + return translate.instant("Edge.Index.Widgets.HeatPump.switchOnRecShort"); case 3: - return translate.instant('Edge.Index.Widgets.HeatPump.switchOnComShort'); + return translate.instant("Edge.Index.Widgets.HeatPump.switchOnComShort"); } }; @@ -129,30 +128,30 @@ export class HeatPumpChartComponent extends AbstractHistoryChart implements OnIn let toolTipValue; switch (value) { case -1: - toolTipValue = translate.instant('Edge.Index.Widgets.HeatPump.undefined'); + toolTipValue = translate.instant("Edge.Index.Widgets.HeatPump.undefined"); break; case 0: - toolTipValue = translate.instant('Edge.Index.Widgets.HeatPump.lock'); + toolTipValue = translate.instant("Edge.Index.Widgets.HeatPump.lock"); break; case 1: - toolTipValue = translate.instant('Edge.Index.Widgets.HeatPump.normalOperation'); + toolTipValue = translate.instant("Edge.Index.Widgets.HeatPump.normalOperation"); break; case 2: - toolTipValue = translate.instant('Edge.Index.Widgets.HeatPump.switchOnRec'); + toolTipValue = translate.instant("Edge.Index.Widgets.HeatPump.switchOnRec"); break; case 3: - toolTipValue = translate.instant('Edge.Index.Widgets.HeatPump.switchOnCom'); + toolTipValue = translate.instant("Edge.Index.Widgets.HeatPump.switchOnCom"); break; default: - toolTipValue = ''; + toolTipValue = ""; break; } return label + ": " + toolTipValue; // TODO get locale dynamically }; options.scales[ChartAxis.LEFT].max = 3; - options.scales[ChartAxis.LEFT]['beginAtZero'] = true; + options.scales[ChartAxis.LEFT]["beginAtZero"] = true; this.options = options; } diff --git a/ui/src/app/edge/history/heatpump/heatpumpchartoverview/heatpumpchartoverview.component.ts b/ui/src/app/edge/history/heatpump/heatpumpchartoverview/heatpumpchartoverview.component.ts index 16b4085313c..e17887c4e55 100644 --- a/ui/src/app/edge/history/heatpump/heatpumpchartoverview/heatpumpchartoverview.component.ts +++ b/ui/src/app/edge/history/heatpump/heatpumpchartoverview/heatpumpchartoverview.component.ts @@ -1,11 +1,11 @@ -import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { ModalController } from '@ionic/angular'; -import { Edge, EdgeConfig, Service } from '../../../../shared/shared'; +import { Component, OnInit } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { ModalController } from "@ionic/angular"; +import { Edge, EdgeConfig, Service } from "../../../../shared/shared"; @Component({ selector: HeatPumpChartOverviewComponent.SELECTOR, - templateUrl: './heatpumpchartoverview.component.html', + templateUrl: "./heatpumpchartoverview.component.html", }) export class HeatPumpChartOverviewComponent implements OnInit { @@ -21,7 +21,7 @@ export class HeatPumpChartOverviewComponent implements OnInit { ) { } ngOnInit() { - this.service.setCurrentComponent('', this.route).then(edge => { + this.service.getCurrentEdge().then(edge => { this.service.getConfig().then(config => { this.component = config.getComponent(this.route.snapshot.params.componentId); this.service.getConfig().then(config => { diff --git a/ui/src/app/edge/history/heatpump/widget.component.ts b/ui/src/app/edge/history/heatpump/widget.component.ts index 30b91ac9062..90fc211cca5 100644 --- a/ui/src/app/edge/history/heatpump/widget.component.ts +++ b/ui/src/app/edge/history/heatpump/widget.component.ts @@ -1,15 +1,15 @@ // @ts-strict-ignore -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 { 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'; +import { ChannelAddress, Edge, EdgeConfig, Service } from "../../../shared/shared"; +import { AbstractHistoryWidget } from "../abstracthistorywidget"; @Component({ selector: HeatpumpWidgetComponent.SELECTOR, - templateUrl: './widget.component.html', + templateUrl: "./widget.component.html", }) export class HeatpumpWidgetComponent extends AbstractHistoryWidget implements OnInit, OnChanges, OnDestroy { @@ -35,7 +35,7 @@ export class HeatpumpWidgetComponent extends AbstractHistoryWidget implements On } ngOnInit() { - this.service.setCurrentComponent('', this.route).then(edge => { + this.service.getCurrentEdge().then(edge => { this.edge = edge; this.service.getConfig().then(config => { this.component = config.getComponent(this.componentId); @@ -56,17 +56,17 @@ export class HeatpumpWidgetComponent extends AbstractHistoryWidget implements On this.getChannelAddresses(this.edge, config).then(channels => { this.service.queryEnergy(this.period.from, this.period.to, channels).then(response => { const result = response.result; - if (this.componentId + '/ForceOnStateTime' in result.data) { - this.activeTimeOverPeriodForceOn = result.data[this.componentId + '/ForceOnStateTime']; + if (this.componentId + "/ForceOnStateTime" in result.data) { + this.activeTimeOverPeriodForceOn = result.data[this.componentId + "/ForceOnStateTime"]; } - if (this.componentId + '/RegularStateTime' in result.data) { - this.activeTimeOverPeriodRegular = result.data[this.componentId + '/RegularStateTime']; + if (this.componentId + "/RegularStateTime" in result.data) { + this.activeTimeOverPeriodRegular = result.data[this.componentId + "/RegularStateTime"]; } - if (this.componentId + '/RecommendationStateTime' in result.data) { - this.activeTimeOverPeriodRecommendation = result.data[this.componentId + '/RecommendationStateTime']; + if (this.componentId + "/RecommendationStateTime" in result.data) { + this.activeTimeOverPeriodRecommendation = result.data[this.componentId + "/RecommendationStateTime"]; } - if (this.componentId + '/LockStateTime' in result.data) { - this.activeTimeOverPeriodLock = result.data[this.componentId + '/LockStateTime']; + if (this.componentId + "/LockStateTime" in result.data) { + this.activeTimeOverPeriodLock = result.data[this.componentId + "/LockStateTime"]; } }); }); @@ -76,10 +76,10 @@ export class HeatpumpWidgetComponent extends AbstractHistoryWidget implements On protected getChannelAddresses(edge: Edge, config: EdgeConfig): Promise { return new Promise((resolve) => { const channels: ChannelAddress[] = [ - new ChannelAddress(this.componentId, 'ForceOnStateTime'), - new ChannelAddress(this.componentId, 'RegularStateTime'), - new ChannelAddress(this.componentId, 'RecommendationStateTime'), - new ChannelAddress(this.componentId, 'LockStateTime'), + new ChannelAddress(this.componentId, "ForceOnStateTime"), + new ChannelAddress(this.componentId, "RegularStateTime"), + new ChannelAddress(this.componentId, "RecommendationStateTime"), + new ChannelAddress(this.componentId, "LockStateTime"), ]; resolve(channels); }); diff --git a/ui/src/app/edge/history/history.component.html b/ui/src/app/edge/history/history.component.html index 28687881029..8774f678d1b 100644 --- a/ui/src/app/edge/history/history.component.html +++ b/ui/src/app/edge/history/history.component.html @@ -1,7 +1,7 @@

      - + diff --git a/ui/src/app/edge/history/history.component.ts b/ui/src/app/edge/history/history.component.ts index b0a4c35e4bf..719a287a158 100644 --- a/ui/src/app/edge/history/history.component.ts +++ b/ui/src/app/edge/history/history.component.ts @@ -1,16 +1,16 @@ // @ts-strict-ignore -import { Component, OnInit, ViewChild } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { TranslateService } from '@ngx-translate/core'; -import { AppService } from 'src/app/app.service'; -import { HeaderComponent } from 'src/app/shared/components/header/header.component'; -import { JsonrpcResponseError } from 'src/app/shared/jsonrpc/base'; -import { Edge, EdgeConfig, Service, Widgets } from 'src/app/shared/shared'; -import { environment } from 'src/environments'; +import { Component, OnInit, ViewChild } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { TranslateService } from "@ngx-translate/core"; +import { AppService } from "src/app/app.service"; +import { HeaderComponent } from "src/app/shared/components/header/header.component"; +import { JsonrpcResponseError } from "src/app/shared/jsonrpc/base"; +import { Edge, EdgeConfig, Service, Widgets } from "src/app/shared/shared"; +import { environment } from "src/environments"; @Component({ - selector: 'history', - templateUrl: './history.component.html', + selector: "history", + templateUrl: "./history.component.html", }) export class HistoryComponent implements OnInit { @@ -42,7 +42,6 @@ export class HistoryComponent implements OnInit { ) { } ngOnInit() { - this.service.setCurrentComponent('', this.route); this.service.currentEdge.subscribe((edge) => { this.edge = edge; }); @@ -57,8 +56,8 @@ export class HistoryComponent implements OnInit { config.hasStorage(); this.widgets = config.widgets; // Are we connected to OpenEMS Edge and is a timedata service available? - if (environment.backend == 'OpenEMS Edge' - && config.getComponentsImplementingNature('io.openems.edge.timedata.api.Timedata').filter(c => c.isEnabled).length == 0) { + if (environment.backend == "OpenEMS Edge" + && config.getComponentsImplementingNature("io.openems.edge.timedata.api.Timedata").filter(c => c.isEnabled).length == 0) { this.isTimedataAvailable = false; } }); diff --git a/ui/src/app/edge/history/history.module.ts b/ui/src/app/edge/history/history.module.ts index 9642a03adbf..9d45b5ba2df 100644 --- a/ui/src/app/edge/history/history.module.ts +++ b/ui/src/app/edge/history/history.module.ts @@ -1,45 +1,38 @@ -import { NgModule } from '@angular/core'; -import { HistoryDataErrorModule } from 'src/app/shared/components/history-data-error/history-data-error.module'; +import { NgModule } from "@angular/core"; +import { HistoryDataErrorModule } from "src/app/shared/components/history-data-error/history-data-error.module"; -import { SharedModule } from '../../shared/shared.module'; -import { ChpSocChartComponent } from './chpsoc/chart.component'; -import { ChpSocWidgetComponent } from './chpsoc/widget.component'; -import { Common } from './common/common'; -import { Controller } from './Controller/controller.module'; -import { DelayedSellToGridChartComponent } from './delayedselltogrid/chart.component'; -import { DelayedSellToGridChartOverviewComponent } from './delayedselltogrid/symmetricpeakshavingchartoverview/delayedselltogridchartoverview.component'; -import { DelayedSellToGridWidgetComponent } from './delayedselltogrid/widget.component'; -import { FixDigitalOutputChartOverviewComponent } from './fixdigitaloutput/fixdigitaloutputchartoverview/fixdigitaloutputchartoverview.component'; -import { FixDigitalOutputSingleChartComponent } from './fixdigitaloutput/singlechart.component'; -import { FixDigitalOutputTotalChartComponent } from './fixdigitaloutput/totalchart.component'; -import { FixDigitalOutputWidgetComponent } from './fixdigitaloutput/widget.component'; -import { HeatingelementChartComponent } from './heatingelement/chart.component'; -import { HeatingelementChartOverviewComponent } from './heatingelement/heatingelementchartoverview/heatingelementchartoverview.component'; -import { HeatingelementWidgetComponent } from './heatingelement/widget.component'; -import { HeatPumpChartComponent } from './heatpump/chart.component'; -import { HeatPumpChartOverviewComponent } from './heatpump/heatpumpchartoverview/heatpumpchartoverview.component'; -import { HeatpumpWidgetComponent } from './heatpump/widget.component'; -import { HistoryComponent } from './history.component'; -import { HistoryParentComponent } from './historyparent.component'; -import { AsymmetricPeakshavingChartOverviewComponent } from './peakshaving/asymmetric/asymmetricpeakshavingchartoverview/asymmetricpeakshavingchartoverview.component'; -import { AsymmetricPeakshavingChartComponent } from './peakshaving/asymmetric/chart.component'; -import { AsymmetricPeakshavingWidgetComponent } from './peakshaving/asymmetric/widget.component'; -import { SymmetricPeakshavingChartComponent } from './peakshaving/symmetric/chart.component'; -import { SymmetricPeakshavingChartOverviewComponent } from './peakshaving/symmetric/symmetricpeakshavingchartoverview/symmetricpeakshavingchartoverview.component'; -import { SymmetricPeakshavingWidgetComponent } from './peakshaving/symmetric/widget.component'; -import { TimeslotPeakshavingChartComponent } from './peakshaving/timeslot/chart.component'; -import { TimeslotPeakshavingChartOverviewComponent } from './peakshaving/timeslot/timeslotpeakshavingchartoverview/timeslotpeakshavingchartoverview.component'; -import { TimeslotPeakshavingWidgetComponent } from './peakshaving/timeslot/widget.component'; -import { SinglethresholdChartComponent } from './singlethreshold/chart.component'; -import { SinglethresholdChartOverviewComponent } from './singlethreshold/singlethresholdchartoverview/singlethresholdchartoverview.component'; -import { SinglethresholdWidgetComponent } from './singlethreshold/widget.component'; -import { StorageChargerChartComponent } from './storage/chargerchart.component'; -import { StorageESSChartComponent } from './storage/esschart.component'; -import { StorageSingleChartComponent } from './storage/singlechart.component'; -import { SocStorageChartComponent } from './storage/socchart.component'; -import { StorageChartOverviewComponent } from './storage/storagechartoverview/storagechartoverview.component'; -import { StorageTotalChartComponent } from './storage/totalchart.component'; -import { StorageComponent } from './storage/widget.component'; +import { SharedModule } from "../../shared/shared.module"; +import { ChpSocChartComponent } from "./chpsoc/chart.component"; +import { ChpSocWidgetComponent } from "./chpsoc/widget.component"; +import { Common } from "./common/common"; +import { Controller } from "./Controller/controller.module"; +import { DelayedSellToGridChartComponent } from "./delayedselltogrid/chart.component"; +import { DelayedSellToGridChartOverviewComponent } from "./delayedselltogrid/symmetricpeakshavingchartoverview/delayedselltogridchartoverview.component"; +import { DelayedSellToGridWidgetComponent } from "./delayedselltogrid/widget.component"; +import { HeatingelementChartComponent } from "./heatingelement/chart.component"; +import { HeatingelementChartOverviewComponent } from "./heatingelement/heatingelementchartoverview/heatingelementchartoverview.component"; +import { HeatingelementWidgetComponent } from "./heatingelement/widget.component"; +import { HeatPumpChartComponent } from "./heatpump/chart.component"; +import { HeatPumpChartOverviewComponent } from "./heatpump/heatpumpchartoverview/heatpumpchartoverview.component"; +import { HeatpumpWidgetComponent } from "./heatpump/widget.component"; +import { HistoryComponent } from "./history.component"; +import { HistoryParentComponent } from "./historyparent.component"; +import { AsymmetricPeakshavingChartOverviewComponent } from "./peakshaving/asymmetric/asymmetricpeakshavingchartoverview/asymmetricpeakshavingchartoverview.component"; +import { AsymmetricPeakshavingChartComponent } from "./peakshaving/asymmetric/chart.component"; +import { AsymmetricPeakshavingWidgetComponent } from "./peakshaving/asymmetric/widget.component"; +import { SymmetricPeakshavingChartComponent } from "./peakshaving/symmetric/chart.component"; +import { SymmetricPeakshavingChartOverviewComponent } from "./peakshaving/symmetric/symmetricpeakshavingchartoverview/symmetricpeakshavingchartoverview.component"; +import { SymmetricPeakshavingWidgetComponent } from "./peakshaving/symmetric/widget.component"; +import { TimeslotPeakshavingChartComponent } from "./peakshaving/timeslot/chart.component"; +import { TimeslotPeakshavingChartOverviewComponent } from "./peakshaving/timeslot/timeslotpeakshavingchartoverview/timeslotpeakshavingchartoverview.component"; +import { TimeslotPeakshavingWidgetComponent } from "./peakshaving/timeslot/widget.component"; +import { StorageChargerChartComponent } from "./storage/chargerchart.component"; +import { StorageESSChartComponent } from "./storage/esschart.component"; +import { StorageSingleChartComponent } from "./storage/singlechart.component"; +import { SocStorageChartComponent } from "./storage/socchart.component"; +import { StorageChartOverviewComponent } from "./storage/storagechartoverview/storagechartoverview.component"; +import { StorageTotalChartComponent } from "./storage/totalchart.component"; +import { StorageComponent } from "./storage/widget.component"; @NgModule({ imports: [ @@ -57,10 +50,6 @@ import { StorageComponent } from './storage/widget.component'; DelayedSellToGridChartComponent, DelayedSellToGridChartOverviewComponent, DelayedSellToGridWidgetComponent, - FixDigitalOutputChartOverviewComponent, - FixDigitalOutputSingleChartComponent, - FixDigitalOutputTotalChartComponent, - FixDigitalOutputWidgetComponent, HeatingelementChartComponent, HeatingelementChartOverviewComponent, HeatingelementWidgetComponent, @@ -68,9 +57,6 @@ import { StorageComponent } from './storage/widget.component'; HeatPumpChartOverviewComponent, HeatpumpWidgetComponent, HistoryComponent, - SinglethresholdChartComponent, - SinglethresholdChartOverviewComponent, - SinglethresholdWidgetComponent, SocStorageChartComponent, StorageChargerChartComponent, StorageChartOverviewComponent, diff --git a/ui/src/app/edge/history/historydataservice.ts b/ui/src/app/edge/history/historydataservice.ts index 97ac3e1f53b..5abba259cc0 100644 --- a/ui/src/app/edge/history/historydataservice.ts +++ b/ui/src/app/edge/history/historydataservice.ts @@ -2,6 +2,7 @@ import { Inject, Injectable } from "@angular/core"; import { RefresherCustomEvent } from "@ionic/angular"; +import { ChartConstants } from "src/app/shared/components/chart/chart.constants"; import { QueryHistoricTimeseriesEnergyRequest } from "src/app/shared/jsonrpc/request/queryHistoricTimeseriesEnergyRequest"; import { Service } from "src/app/shared/service/service"; import { Websocket } from "src/app/shared/service/websocket"; @@ -15,6 +16,7 @@ export class HistoryDataService extends DataService { public queryChannelsTimeout: ReturnType | null = null; protected override timestamps: string[] = []; + private activeQueryData: string; private channelAddresses: { [sourceId: string]: ChannelAddress } = {}; constructor( @@ -36,21 +38,36 @@ export class HistoryDataService extends DataService { if (Object.entries(this.channelAddresses).length > 0) { this.service.historyPeriod.subscribe(date => { - edge.sendRequest(this.websocket, new QueryHistoricTimeseriesEnergyRequest(DateUtils.maxDate(date.from, edge?.firstSetupProtocol), date.to, Object.values(this.channelAddresses))) + + const request = new QueryHistoricTimeseriesEnergyRequest( + DateUtils.maxDate(date.from, edge?.firstSetupProtocol), + date.to, + Object.values(this.channelAddresses), + ); + + this.activeQueryData = request.id; + + edge.sendRequest(this.websocket, request) .then((response) => { - const allComponents = {}; - const result = (response as QueryHistoricTimeseriesEnergyResponse).result; - for (const [key, value] of Object.entries(result.data)) { - allComponents[key] = value; + if (this.activeQueryData === response.id) { + const allComponents = {}; + const result = (response as QueryHistoricTimeseriesEnergyResponse).result; + + for (const [key, value] of Object.entries(result.data)) { + allComponents[key] = value; + } + + this.currentValue.next({ allComponents: allComponents }); + this.timestamps = response.result["timestamps"] ?? []; } - this.currentValue.next({ allComponents: allComponents }); - this.timestamps = response.result['timestamps'] ?? []; - }).catch(err => console.warn(err)) + }) + .catch(err => console.warn(err)) .finally(() => { + this.queryChannelsTimeout = null; }); }); } - }, 100); + }, ChartConstants.REQUEST_TIMEOUT); } } diff --git a/ui/src/app/edge/history/peakshaving/asymmetric/asymmetricpeakshavingchartoverview/asymmetricpeakshavingchartoverview.component.ts b/ui/src/app/edge/history/peakshaving/asymmetric/asymmetricpeakshavingchartoverview/asymmetricpeakshavingchartoverview.component.ts index 3cb22de5eca..0cac1b4d2f5 100644 --- a/ui/src/app/edge/history/peakshaving/asymmetric/asymmetricpeakshavingchartoverview/asymmetricpeakshavingchartoverview.component.ts +++ b/ui/src/app/edge/history/peakshaving/asymmetric/asymmetricpeakshavingchartoverview/asymmetricpeakshavingchartoverview.component.ts @@ -1,10 +1,10 @@ -import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { Edge, EdgeConfig, Service } from '../../../../../shared/shared'; +import { Component, OnInit } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { Edge, EdgeConfig, Service } from "../../../../../shared/shared"; @Component({ selector: AsymmetricPeakshavingChartOverviewComponent.SELECTOR, - templateUrl: './asymmetricpeakshavingchartoverview.component.html', + templateUrl: "./asymmetricpeakshavingchartoverview.component.html", }) export class AsymmetricPeakshavingChartOverviewComponent implements OnInit { @@ -18,7 +18,7 @@ export class AsymmetricPeakshavingChartOverviewComponent implements OnInit { ) { } ngOnInit() { - this.service.setCurrentComponent('', this.route).then(edge => { + this.service.getCurrentEdge().then(edge => { this.service.getConfig().then(config => { this.edge = edge; 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 a3ace71ad44..d9b4b4ae008 100644 --- a/ui/src/app/edge/history/peakshaving/asymmetric/chart.component.ts +++ b/ui/src/app/edge/history/peakshaving/asymmetric/chart.component.ts @@ -1,16 +1,16 @@ // @ts-strict-ignore -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 { YAxisTitle } from 'src/app/shared/service/utils'; +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 { YAxisType } from "src/app/shared/service/utils"; -import { ChannelAddress, Edge, EdgeConfig, Service, Utils } from '../../../../shared/shared'; -import { AbstractHistoryChart } from '../../abstracthistorychart'; +import { ChannelAddress, Edge, EdgeConfig, Service, Utils } from "../../../../shared/shared"; +import { AbstractHistoryChart } from "../../abstracthistorychart"; @Component({ - selector: 'asymmetricpeakshavingchart', - templateUrl: '../../abstracthistorychart.html', + selector: "asymmetricpeakshavingchart", + templateUrl: "../../abstracthistorychart.html", }) export class AsymmetricPeakshavingChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { @@ -31,7 +31,6 @@ export class AsymmetricPeakshavingChartComponent extends AbstractHistoryChart im ngOnInit() { this.startSpinner(); - this.service.setCurrentComponent('', this.route); } ngOnDestroy() { @@ -48,11 +47,11 @@ export class AsymmetricPeakshavingChartComponent extends AbstractHistoryChart im this.loading = true; this.colors = []; this.queryHistoricTimeseriesData(this.period.from, this.period.to).then(response => { - const meterIdActivePowerL1 = this.component.properties['meter.id'] + '/ActivePowerL1'; - const meterIdActivePowerL2 = this.component.properties['meter.id'] + '/ActivePowerL2'; - const meterIdActivePowerL3 = this.component.properties['meter.id'] + '/ActivePowerL3'; - const peakshavingPower = this.component.id + '/_PropertyPeakShavingPower'; - const rechargePower = this.component.id + '/_PropertyRechargePower'; + const meterIdActivePowerL1 = this.component.properties["meter.id"] + "/ActivePowerL1"; + const meterIdActivePowerL2 = this.component.properties["meter.id"] + "/ActivePowerL2"; + const meterIdActivePowerL3 = this.component.properties["meter.id"] + "/ActivePowerL3"; + const peakshavingPower = this.component.id + "/_PropertyPeakShavingPower"; + const rechargePower = this.component.id + "/_PropertyRechargePower"; const result = response.result; // convert labels const labels: Date[] = []; @@ -75,7 +74,7 @@ export class AsymmetricPeakshavingChartComponent extends AbstractHistoryChart im } }); datasets.push({ - label: this.translate.instant('General.phase') + ' ' + 'L1', + label: this.translate.instant("General.phase") + " " + "L1", data: data, hidden: false, }); @@ -92,7 +91,7 @@ export class AsymmetricPeakshavingChartComponent extends AbstractHistoryChart im } }); datasets.push({ - label: this.translate.instant('General.phase') + ' ' + 'L2', + label: this.translate.instant("General.phase") + " " + "L2", data: data, hidden: false, }); @@ -109,7 +108,7 @@ export class AsymmetricPeakshavingChartComponent extends AbstractHistoryChart im } }); datasets.push({ - label: this.translate.instant('General.phase') + ' ' + 'L3', + label: this.translate.instant("General.phase") + " " + "L3", data: data, hidden: false, }); @@ -126,14 +125,14 @@ export class AsymmetricPeakshavingChartComponent extends AbstractHistoryChart im } }); datasets.push({ - label: this.translate.instant('Edge.Index.Widgets.Peakshaving.rechargePower'), + label: this.translate.instant("Edge.Index.Widgets.Peakshaving.rechargePower"), data: data, hidden: false, borderDash: [3, 3], }); this.colors.push({ - backgroundColor: 'rgba(0,0,0,0)', - borderColor: 'rgba(0,223,0,1)', + backgroundColor: "rgba(0,0,0,0)", + borderColor: "rgba(0,223,0,1)", }); } if (peakshavingPower in result.data) { @@ -147,27 +146,27 @@ export class AsymmetricPeakshavingChartComponent extends AbstractHistoryChart im } }); datasets.push({ - label: this.translate.instant('Edge.Index.Widgets.Peakshaving.peakshavingPower'), + label: this.translate.instant("Edge.Index.Widgets.Peakshaving.peakshavingPower"), data: data, hidden: false, borderDash: [3, 3], }); this.colors.push({ - backgroundColor: 'rgba(0,0,0,0)', - borderColor: 'rgba(200,0,0,1)', + backgroundColor: "rgba(0,0,0,0)", + borderColor: "rgba(200,0,0,1)", }); } - if ('_sum/EssActivePower' in result.data) { + 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); + 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']; + effectivePower = result.data["_sum/EssActivePower"]; } const chargeData = effectivePower.map(value => { if (value == null) { @@ -179,12 +178,12 @@ export class AsymmetricPeakshavingChartComponent extends AbstractHistoryChart im } }); datasets.push({ - label: this.translate.instant('General.chargePower'), + label: this.translate.instant("General.chargePower"), data: chargeData, }); this.colors.push({ - backgroundColor: 'rgba(0,223,0,0.05)', - borderColor: 'rgba(0,223,0,1)', + backgroundColor: "rgba(0,223,0,0.05)", + borderColor: "rgba(0,223,0,1)", }); /* * Storage Discharge @@ -199,12 +198,12 @@ export class AsymmetricPeakshavingChartComponent extends AbstractHistoryChart im } }); datasets.push({ - label: this.translate.instant('General.dischargePower'), + label: this.translate.instant("General.dischargePower"), data: dischargeData, }); this.colors.push({ - backgroundColor: 'rgba(200,0,0,0.05)', - borderColor: 'rgba(200,0,0,1)', + backgroundColor: "rgba(200,0,0,0.05)", + borderColor: "rgba(200,0,0,1)", }); } this.datasets = datasets; @@ -216,7 +215,7 @@ export class AsymmetricPeakshavingChartComponent extends AbstractHistoryChart im this.initializeChart(); return; }).finally(async () => { - this.unit = YAxisTitle.ENERGY; + this.unit = YAxisType.ENERGY; await this.setOptions(this.options); this.stopSpinner(); }); @@ -225,13 +224,13 @@ export class AsymmetricPeakshavingChartComponent extends AbstractHistoryChart im protected getChannelAddresses(edge: Edge, config: EdgeConfig): Promise { return new Promise((resolve) => { const result: ChannelAddress[] = [ - new ChannelAddress(this.component.id, '_PropertyPeakShavingPower'), - new ChannelAddress(this.component.id, '_PropertyRechargePower'), - new ChannelAddress(this.component.properties['meter.id'], 'ActivePowerL1'), - new ChannelAddress(this.component.properties['meter.id'], 'ActivePowerL2'), - new ChannelAddress(this.component.properties['meter.id'], 'ActivePowerL3'), - new ChannelAddress('_sum', 'ProductionDcActualPower'), - new ChannelAddress('_sum', 'EssActivePower'), + new ChannelAddress(this.component.id, "_PropertyPeakShavingPower"), + new ChannelAddress(this.component.id, "_PropertyRechargePower"), + new ChannelAddress(this.component.properties["meter.id"], "ActivePowerL1"), + new ChannelAddress(this.component.properties["meter.id"], "ActivePowerL2"), + new ChannelAddress(this.component.properties["meter.id"], "ActivePowerL3"), + new ChannelAddress("_sum", "ProductionDcActualPower"), + new ChannelAddress("_sum", "EssActivePower"), ]; resolve(result); }); diff --git a/ui/src/app/edge/history/peakshaving/asymmetric/widget.component.ts b/ui/src/app/edge/history/peakshaving/asymmetric/widget.component.ts index befb0fa19ef..1d58538f990 100644 --- a/ui/src/app/edge/history/peakshaving/asymmetric/widget.component.ts +++ b/ui/src/app/edge/history/peakshaving/asymmetric/widget.component.ts @@ -1,11 +1,11 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; -import { Edge, EdgeConfig, Service } from 'src/app/shared/shared'; +import { Component, Input, OnInit } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { DefaultTypes } from "src/app/shared/service/defaulttypes"; +import { Edge, EdgeConfig, Service } from "src/app/shared/shared"; @Component({ selector: AsymmetricPeakshavingWidgetComponent.SELECTOR, - templateUrl: './widget.component.html', + templateUrl: "./widget.component.html", }) export class AsymmetricPeakshavingWidgetComponent implements OnInit { @@ -22,7 +22,7 @@ export class AsymmetricPeakshavingWidgetComponent implements OnInit { ) { } ngOnInit() { - this.service.setCurrentComponent('', this.route).then(edge => { + this.service.getCurrentEdge().then(edge => { this.edge = edge; this.service.getConfig().then(config => { this.component = config.getComponent(this.componentId); 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 4d9de7b5dec..4c9d97e725f 100644 --- a/ui/src/app/edge/history/peakshaving/symmetric/chart.component.ts +++ b/ui/src/app/edge/history/peakshaving/symmetric/chart.component.ts @@ -1,15 +1,15 @@ // @ts-strict-ignore -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 { 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 { ChannelAddress, Edge, EdgeConfig, Service, Utils } from "../../../../shared/shared"; +import { AbstractHistoryChart } from "../../abstracthistorychart"; @Component({ - selector: 'symmetricpeakshavingchart', - templateUrl: '../../abstracthistorychart.html', + selector: "symmetricpeakshavingchart", + templateUrl: "../../abstracthistorychart.html", }) export class SymmetricPeakshavingChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { @@ -30,7 +30,6 @@ export class SymmetricPeakshavingChartComponent extends AbstractHistoryChart imp ngOnInit() { this.startSpinner(); - this.service.setCurrentComponent('', this.route); } ngOnDestroy() { @@ -48,9 +47,9 @@ export class SymmetricPeakshavingChartComponent extends AbstractHistoryChart imp this.colors = []; this.queryHistoricTimeseriesData(this.period.from, this.period.to).then(response => { this.service.getConfig().then(config => { - const meterIdActivePower = config.getComponent(this.componentId).properties['meter.id'] + '/ActivePower'; - const peakshavingPower = this.componentId + '/_PropertyPeakShavingPower'; - const rechargePower = this.componentId + '/_PropertyRechargePower'; + const meterIdActivePower = config.getComponent(this.componentId).properties["meter.id"] + "/ActivePower"; + const peakshavingPower = this.componentId + "/_PropertyPeakShavingPower"; + const rechargePower = this.componentId + "/_PropertyRechargePower"; const result = response.result; // convert labels const labels: Date[] = []; @@ -73,13 +72,13 @@ export class SymmetricPeakshavingChartComponent extends AbstractHistoryChart imp } }); datasets.push({ - label: this.translate.instant('General.measuredValue'), + label: this.translate.instant("General.measuredValue"), data: data, hidden: false, }); this.colors.push({ - backgroundColor: 'rgba(0,0,0,0.05)', - borderColor: 'rgba(0,0,0,1)', + backgroundColor: "rgba(0,0,0,0.05)", + borderColor: "rgba(0,0,0,1)", }); } if (rechargePower in result.data) { @@ -93,14 +92,14 @@ export class SymmetricPeakshavingChartComponent extends AbstractHistoryChart imp } }); datasets.push({ - label: this.translate.instant('Edge.Index.Widgets.Peakshaving.rechargePower'), + label: this.translate.instant("Edge.Index.Widgets.Peakshaving.rechargePower"), data: data, hidden: false, borderDash: [3, 3], }); this.colors.push({ - backgroundColor: 'rgba(0,0,0,0)', - borderColor: 'rgba(0,223,0,1)', + backgroundColor: "rgba(0,0,0,0)", + borderColor: "rgba(0,223,0,1)", }); } if (peakshavingPower in result.data) { @@ -114,27 +113,27 @@ export class SymmetricPeakshavingChartComponent extends AbstractHistoryChart imp } }); datasets.push({ - label: this.translate.instant('Edge.Index.Widgets.Peakshaving.peakshavingPower'), + label: this.translate.instant("Edge.Index.Widgets.Peakshaving.peakshavingPower"), data: data, hidden: false, borderDash: [3, 3], }); this.colors.push({ - backgroundColor: 'rgba(0,0,0,0)', - borderColor: 'rgba(200,0,0,1)', + backgroundColor: "rgba(0,0,0,0)", + borderColor: "rgba(200,0,0,1)", }); } - if ('_sum/EssActivePower' in result.data) { + 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); + 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']; + effectivePower = result.data["_sum/EssActivePower"]; } const chargeData = effectivePower.map(value => { if (value == null) { @@ -146,13 +145,13 @@ export class SymmetricPeakshavingChartComponent extends AbstractHistoryChart imp } }); datasets.push({ - label: this.translate.instant('General.chargePower'), + label: this.translate.instant("General.chargePower"), data: chargeData, borderDash: [10, 10], }); this.colors.push({ - backgroundColor: 'rgba(0,223,0,0.05)', - borderColor: 'rgba(0,223,0,1)', + backgroundColor: "rgba(0,223,0,0.05)", + borderColor: "rgba(0,223,0,1)", }); /* * Storage Discharge @@ -167,13 +166,13 @@ export class SymmetricPeakshavingChartComponent extends AbstractHistoryChart imp } }); datasets.push({ - label: this.translate.instant('General.dischargePower'), + label: this.translate.instant("General.dischargePower"), data: dischargeData, borderDash: [10, 10], }); this.colors.push({ - backgroundColor: 'rgba(200,0,0,0.05)', - borderColor: 'rgba(200,0,0,1)', + backgroundColor: "rgba(200,0,0,0.05)", + borderColor: "rgba(200,0,0,1)", }); } this.datasets = datasets; @@ -198,11 +197,11 @@ export class SymmetricPeakshavingChartComponent extends AbstractHistoryChart imp protected getChannelAddresses(edge: Edge, config: EdgeConfig): Promise { return new Promise((resolve) => { const result: ChannelAddress[] = [ - new ChannelAddress(this.componentId, '_PropertyRechargePower'), - new ChannelAddress(this.componentId, '_PropertyPeakShavingPower'), - new ChannelAddress(config.getComponent(this.componentId).properties['meter.id'], 'ActivePower'), - new ChannelAddress('_sum', 'ProductionDcActualPower'), - new ChannelAddress('_sum', 'EssActivePower'), + new ChannelAddress(this.componentId, "_PropertyRechargePower"), + new ChannelAddress(this.componentId, "_PropertyPeakShavingPower"), + new ChannelAddress(config.getComponent(this.componentId).properties["meter.id"], "ActivePower"), + new ChannelAddress("_sum", "ProductionDcActualPower"), + new ChannelAddress("_sum", "EssActivePower"), ]; resolve(result); }); diff --git a/ui/src/app/edge/history/peakshaving/symmetric/symmetricpeakshavingchartoverview/symmetricpeakshavingchartoverview.component.ts b/ui/src/app/edge/history/peakshaving/symmetric/symmetricpeakshavingchartoverview/symmetricpeakshavingchartoverview.component.ts index 8e578e2b5fa..5734f7485cc 100644 --- a/ui/src/app/edge/history/peakshaving/symmetric/symmetricpeakshavingchartoverview/symmetricpeakshavingchartoverview.component.ts +++ b/ui/src/app/edge/history/peakshaving/symmetric/symmetricpeakshavingchartoverview/symmetricpeakshavingchartoverview.component.ts @@ -1,10 +1,10 @@ -import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { Edge, EdgeConfig, Service } from '../../../../../shared/shared'; +import { Component, OnInit } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { Edge, EdgeConfig, Service } from "../../../../../shared/shared"; @Component({ selector: SymmetricPeakshavingChartOverviewComponent.SELECTOR, - templateUrl: './symmetricpeakshavingchartoverview.component.html', + templateUrl: "./symmetricpeakshavingchartoverview.component.html", }) export class SymmetricPeakshavingChartOverviewComponent implements OnInit { @@ -19,7 +19,7 @@ export class SymmetricPeakshavingChartOverviewComponent implements OnInit { ) { } ngOnInit() { - this.service.setCurrentComponent('', this.route).then(edge => { + this.service.getCurrentEdge().then(edge => { this.service.getConfig().then(config => { this.edge = edge; this.component = config.getComponent(this.route.snapshot.params.componentId); diff --git a/ui/src/app/edge/history/peakshaving/symmetric/widget.component.ts b/ui/src/app/edge/history/peakshaving/symmetric/widget.component.ts index 2a4a3720976..62f86d76e86 100644 --- a/ui/src/app/edge/history/peakshaving/symmetric/widget.component.ts +++ b/ui/src/app/edge/history/peakshaving/symmetric/widget.component.ts @@ -1,11 +1,11 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; -import { Edge, EdgeConfig, Service } from 'src/app/shared/shared'; +import { Component, Input, OnInit } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { DefaultTypes } from "src/app/shared/service/defaulttypes"; +import { Edge, EdgeConfig, Service } from "src/app/shared/shared"; @Component({ selector: SymmetricPeakshavingWidgetComponent.SELECTOR, - templateUrl: './widget.component.html', + templateUrl: "./widget.component.html", }) export class SymmetricPeakshavingWidgetComponent implements OnInit { @@ -22,7 +22,7 @@ export class SymmetricPeakshavingWidgetComponent implements OnInit { ) { } ngOnInit() { - this.service.setCurrentComponent('', this.route).then(edge => { + this.service.getCurrentEdge().then(edge => { this.edge = edge; this.service.getConfig().then(config => { this.component = config.getComponent(this.componentId); 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 379d9d33986..4a62f084032 100644 --- a/ui/src/app/edge/history/peakshaving/timeslot/chart.component.ts +++ b/ui/src/app/edge/history/peakshaving/timeslot/chart.component.ts @@ -1,16 +1,16 @@ // @ts-strict-ignore -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 { YAxisTitle } from 'src/app/shared/service/utils'; +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 { YAxisType } from "src/app/shared/service/utils"; -import { ChannelAddress, Edge, EdgeConfig, Service, Utils } from '../../../../shared/shared'; -import { AbstractHistoryChart } from '../../abstracthistorychart'; +import { ChannelAddress, Edge, EdgeConfig, Service, Utils } from "../../../../shared/shared"; +import { AbstractHistoryChart } from "../../abstracthistorychart"; @Component({ - selector: 'timeslotpeakshavingchart', - templateUrl: '../../abstracthistorychart.html', + selector: "timeslotpeakshavingchart", + templateUrl: "../../abstracthistorychart.html", }) export class TimeslotPeakshavingChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { @@ -31,7 +31,6 @@ export class TimeslotPeakshavingChartComponent extends AbstractHistoryChart impl ngOnInit() { this.startSpinner(); - this.service.setCurrentComponent('', this.route); } ngOnDestroy() { @@ -49,10 +48,10 @@ export class TimeslotPeakshavingChartComponent extends AbstractHistoryChart impl this.colors = []; this.queryHistoricTimeseriesData(this.period.from, this.period.to).then(response => { this.service.getConfig().then(config => { - const meterIdActivePower = config.getComponent(this.componentId).properties['meter.id'] + '/ActivePower'; - const peakshavingPower = this.componentId + '/_PropertyPeakShavingPower'; - const rechargePower = this.componentId + '/_PropertyRechargePower'; - const stateMachine = this.componentId + '/StateMachine'; + const meterIdActivePower = config.getComponent(this.componentId).properties["meter.id"] + "/ActivePower"; + const peakshavingPower = this.componentId + "/_PropertyPeakShavingPower"; + const rechargePower = this.componentId + "/_PropertyRechargePower"; + const stateMachine = this.componentId + "/StateMachine"; const result = response.result; @@ -87,13 +86,13 @@ export class TimeslotPeakshavingChartComponent extends AbstractHistoryChart impl } }); datasets.push({ - label: this.translate.instant('General.measuredValue'), + label: this.translate.instant("General.measuredValue"), data: data, hidden: false, }); this.colors.push({ - backgroundColor: 'rgba(0,0,0,0.05)', - borderColor: 'rgba(0,0,0,1)', + backgroundColor: "rgba(0,0,0,0.05)", + borderColor: "rgba(0,0,0,1)", }); } if (rechargePower in result.data) { @@ -107,14 +106,14 @@ export class TimeslotPeakshavingChartComponent extends AbstractHistoryChart impl } }); datasets.push({ - label: this.translate.instant('Edge.Index.Widgets.Peakshaving.rechargePower'), + label: this.translate.instant("Edge.Index.Widgets.Peakshaving.rechargePower"), data: data, hidden: false, borderDash: [3, 3], }); this.colors.push({ - backgroundColor: 'rgba(0,0,0,0)', - borderColor: 'rgba(0,223,0,1)', + backgroundColor: "rgba(0,0,0,0)", + borderColor: "rgba(0,223,0,1)", }); } if (peakshavingPower in result.data) { @@ -128,27 +127,27 @@ export class TimeslotPeakshavingChartComponent extends AbstractHistoryChart impl } }); datasets.push({ - label: this.translate.instant('Edge.Index.Widgets.Peakshaving.peakshavingPower'), + label: this.translate.instant("Edge.Index.Widgets.Peakshaving.peakshavingPower"), data: data, hidden: false, borderDash: [3, 3], }); this.colors.push({ - backgroundColor: 'rgba(0,0,0,0)', - borderColor: 'rgba(200,0,0,1)', + backgroundColor: "rgba(0,0,0,0)", + borderColor: "rgba(200,0,0,1)", }); } - if ('_sum/EssActivePower' in result.data) { + 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); + 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']; + effectivePower = result.data["_sum/EssActivePower"]; } const chargeData = effectivePower.map(value => { if (value == null) { @@ -160,13 +159,13 @@ export class TimeslotPeakshavingChartComponent extends AbstractHistoryChart impl } }); datasets.push({ - label: this.translate.instant('General.chargePower'), + label: this.translate.instant("General.chargePower"), data: chargeData, borderDash: [10, 10], }); this.colors.push({ - backgroundColor: 'rgba(0,223,0,0.05)', - borderColor: 'rgba(0,223,0,1)', + backgroundColor: "rgba(0,223,0,0.05)", + borderColor: "rgba(0,223,0,1)", }); /* * Storage Discharge @@ -181,13 +180,13 @@ export class TimeslotPeakshavingChartComponent extends AbstractHistoryChart impl } }); datasets.push({ - label: this.translate.instant('General.dischargePower'), + label: this.translate.instant("General.dischargePower"), data: dischargeData, borderDash: [10, 10], }); this.colors.push({ - backgroundColor: 'rgba(200,0,0,0.05)', - borderColor: 'rgba(200,0,0,1)', + backgroundColor: "rgba(200,0,0,0.05)", + borderColor: "rgba(200,0,0,1)", }); } this.datasets = datasets; @@ -205,7 +204,7 @@ export class TimeslotPeakshavingChartComponent extends AbstractHistoryChart impl this.initializeChart(); return; }).finally(async () => { - this.unit = YAxisTitle.ENERGY; + this.unit = YAxisType.ENERGY; await this.setOptions(this.options); }); } @@ -213,12 +212,12 @@ export class TimeslotPeakshavingChartComponent extends AbstractHistoryChart impl protected getChannelAddresses(edge: Edge, config: EdgeConfig): Promise { return new Promise((resolve) => { const result: ChannelAddress[] = [ - new ChannelAddress(this.componentId, '_PropertyRechargePower'), - new ChannelAddress(this.componentId, '_PropertyPeakShavingPower'), - new ChannelAddress(this.componentId, 'StateMachine'), - new ChannelAddress(config.getComponent(this.componentId).properties['meter.id'], 'ActivePower'), - new ChannelAddress('_sum', 'ProductionDcActualPower'), - new ChannelAddress('_sum', 'EssActivePower'), + new ChannelAddress(this.componentId, "_PropertyRechargePower"), + new ChannelAddress(this.componentId, "_PropertyPeakShavingPower"), + new ChannelAddress(this.componentId, "StateMachine"), + new ChannelAddress(config.getComponent(this.componentId).properties["meter.id"], "ActivePower"), + new ChannelAddress("_sum", "ProductionDcActualPower"), + new ChannelAddress("_sum", "EssActivePower"), ]; resolve(result); }); diff --git a/ui/src/app/edge/history/peakshaving/timeslot/timeslotpeakshavingchartoverview/timeslotpeakshavingchartoverview.component.ts b/ui/src/app/edge/history/peakshaving/timeslot/timeslotpeakshavingchartoverview/timeslotpeakshavingchartoverview.component.ts index 9c83adacd26..c8c2ed8e7f3 100644 --- a/ui/src/app/edge/history/peakshaving/timeslot/timeslotpeakshavingchartoverview/timeslotpeakshavingchartoverview.component.ts +++ b/ui/src/app/edge/history/peakshaving/timeslot/timeslotpeakshavingchartoverview/timeslotpeakshavingchartoverview.component.ts @@ -1,10 +1,10 @@ -import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { Edge, EdgeConfig, Service } from '../../../../../shared/shared'; +import { Component, OnInit } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { Edge, EdgeConfig, Service } from "../../../../../shared/shared"; @Component({ selector: TimeslotPeakshavingChartOverviewComponent.SELECTOR, - templateUrl: './timeslotpeakshavingchartoverview.component.html', + templateUrl: "./timeslotpeakshavingchartoverview.component.html", }) export class TimeslotPeakshavingChartOverviewComponent implements OnInit { @@ -19,7 +19,7 @@ export class TimeslotPeakshavingChartOverviewComponent implements OnInit { ) { } ngOnInit() { - this.service.setCurrentComponent('', this.route).then(edge => { + this.service.getCurrentEdge().then(edge => { this.service.getConfig().then(config => { this.edge = edge; this.component = config.getComponent(this.route.snapshot.params.componentId); diff --git a/ui/src/app/edge/history/peakshaving/timeslot/widget.component.ts b/ui/src/app/edge/history/peakshaving/timeslot/widget.component.ts index a8748d264b0..7b23394df53 100644 --- a/ui/src/app/edge/history/peakshaving/timeslot/widget.component.ts +++ b/ui/src/app/edge/history/peakshaving/timeslot/widget.component.ts @@ -1,11 +1,11 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; -import { Edge, EdgeConfig, Service } from 'src/app/shared/shared'; +import { Component, Input, OnInit } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { DefaultTypes } from "src/app/shared/service/defaulttypes"; +import { Edge, EdgeConfig, Service } from "src/app/shared/shared"; @Component({ selector: TimeslotPeakshavingWidgetComponent.SELECTOR, - templateUrl: './widget.component.html', + templateUrl: "./widget.component.html", }) export class TimeslotPeakshavingWidgetComponent implements OnInit { @@ -22,7 +22,7 @@ export class TimeslotPeakshavingWidgetComponent implements OnInit { ) { } ngOnInit() { - this.service.setCurrentComponent('', this.route).then(edge => { + this.service.getCurrentEdge().then(edge => { this.edge = edge; this.service.getConfig().then(config => { this.component = config.getComponent(this.componentId); diff --git a/ui/src/app/edge/history/shared.ts b/ui/src/app/edge/history/shared.ts index ce039d3e05a..ac05ac3b66f 100644 --- a/ui/src/app/edge/history/shared.ts +++ b/ui/src/app/edge/history/shared.ts @@ -1,10 +1,10 @@ // @ts-strict-ignore -import * as Chart from 'chart.js'; -import { differenceInDays, differenceInMinutes, startOfDay } from 'date-fns'; -import { de } from 'date-fns/locale'; -import { QueryHistoricTimeseriesDataResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesDataResponse'; -import { ChannelAddress, Service } from 'src/app/shared/shared'; -import { DateUtils } from 'src/app/shared/utils/date/dateutils'; +import * as Chart from "chart.js"; +import { differenceInDays, differenceInMinutes, startOfDay } from "date-fns"; +import { de } from "date-fns/locale"; +import { QueryHistoricTimeseriesDataResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesDataResponse"; +import { ChannelAddress, Service } from "src/app/shared/shared"; +import { DateUtils } from "src/app/shared/utils/date/dateutils"; export interface Dataset { label: string; @@ -177,16 +177,16 @@ export const DEFAULT_TIME_CHART_OPTIONS = (): Chart.ChartOptions => ({ legend: { display: true, - position: 'bottom', + position: "bottom", labels: { - color: getComputedStyle(document.documentElement).getPropertyValue('--ion-color-primary'), + color: getComputedStyle(document.documentElement).getPropertyValue("--ion-color-primary"), generateLabels: (chart: Chart.Chart) => { return null; }, }, onClick: (event, legendItem, legend) => { }, }, tooltip: { intersect: false, - mode: 'index', + mode: "index", filter: function (item, data, test, some) { const value = item.dataset.data[item.dataIndex] as number; return !isNaN(value) && value !== null; @@ -203,10 +203,10 @@ export const DEFAULT_TIME_CHART_OPTIONS = (): Chart.ChartOptions => ({ x: { stacked: true, offset: false, - type: 'time', + type: "time", ticks: { }, - bounds: 'data', + bounds: "data", adapters: { date: { @@ -216,18 +216,18 @@ export const DEFAULT_TIME_CHART_OPTIONS = (): Chart.ChartOptions => ({ }, time: { // parser: 'MM/DD/YYYY HH:mm', - unit: 'hour', + unit: "hour", displayFormats: { - datetime: 'yyyy-MM-dd HH:mm:ss', - 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, + datetime: "yyyy-MM-dd HH:mm:ss", + 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, }, }, }, @@ -244,7 +244,7 @@ export const DEFAULT_TIME_CHART_OPTIONS_WITHOUT_PREDEFINED_Y_AXIS: ChartOptions maintainAspectRatio: false, legend: { labels: {}, - position: 'bottom', + position: "bottom", }, elements: { point: { @@ -261,7 +261,7 @@ export const DEFAULT_TIME_CHART_OPTIONS_WITHOUT_PREDEFINED_Y_AXIS: ChartOptions }, }, hover: { - mode: 'point', + mode: "point", intersect: true, }, scales: { @@ -269,27 +269,27 @@ export const DEFAULT_TIME_CHART_OPTIONS_WITHOUT_PREDEFINED_Y_AXIS: ChartOptions xAxes: [{ ticks: {}, stacked: false, - type: 'time', + type: "time", time: { - minUnit: 'hour', + 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, + 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', + mode: "index", intersect: false, - axis: 'x', + axis: "x", callbacks: { title(tooltipItems: Chart.TooltipItem[], data: Data): string { const date = DateUtils.stringToDate(tooltipItems[0]?.label); @@ -299,7 +299,7 @@ export const DEFAULT_TIME_CHART_OPTIONS_WITHOUT_PREDEFINED_Y_AXIS: ChartOptions }, }; -export function calculateActiveTimeOverPeriod(channel: ChannelAddress, queryResult: QueryHistoricTimeseriesDataResponse['result']) { +export function calculateActiveTimeOverPeriod(channel: ChannelAddress, queryResult: QueryHistoricTimeseriesDataResponse["result"]) { const startDate = startOfDay(new Date(queryResult.timestamps[0])); const endDate = new Date(queryResult.timestamps[queryResult.timestamps.length - 1]); let activeSum = 0; @@ -319,61 +319,61 @@ export function calculateActiveTimeOverPeriod(channel: ChannelAddress, queryResu * @param toDate the To-Date * @returns resolution and timeformat */ -export function calculateResolution(service: Service, fromDate: Date, toDate: Date): { resolution: Resolution, timeFormat: 'day' | 'month' | 'hour' | 'year' } { +export function calculateResolution(service: Service, fromDate: Date, toDate: Date): { resolution: Resolution, timeFormat: "day" | "month" | "hour" | "year" } { const days = Math.abs(differenceInDays(toDate, fromDate)); - let result: { resolution: Resolution, timeFormat: 'day' | 'month' | 'hour' | 'year' }; + let result: { resolution: Resolution, timeFormat: "day" | "month" | "hour" | "year" }; if (days <= 1) { if (service.isSmartphoneResolution) { - result = { resolution: { value: 15, unit: ChronoUnit.Type.MINUTES }, timeFormat: 'hour' }; // 1 Day + result = { resolution: { value: 15, unit: ChronoUnit.Type.MINUTES }, timeFormat: "hour" }; // 1 Day } else { - result = { resolution: { value: 5, unit: ChronoUnit.Type.MINUTES }, timeFormat: 'hour' }; // 5 Minutes + result = { resolution: { value: 5, unit: ChronoUnit.Type.MINUTES }, timeFormat: "hour" }; // 5 Minutes } } else if (days == 2) { if (service.isSmartphoneResolution) { - result = { resolution: { value: 1, unit: ChronoUnit.Type.DAYS }, timeFormat: 'hour' }; // 1 Day + result = { resolution: { value: 1, unit: ChronoUnit.Type.DAYS }, timeFormat: "hour" }; // 1 Day } else { - result = { resolution: { value: 10, unit: ChronoUnit.Type.MINUTES }, timeFormat: 'hour' }; // 1 Hour + result = { resolution: { value: 10, unit: ChronoUnit.Type.MINUTES }, timeFormat: "hour" }; // 1 Hour } } else if (days <= 4) { if (service.isSmartphoneResolution) { - result = { resolution: { value: 1, unit: ChronoUnit.Type.DAYS }, timeFormat: 'day' }; // 1 Day + result = { resolution: { value: 1, unit: ChronoUnit.Type.DAYS }, timeFormat: "day" }; // 1 Day } else { - result = { resolution: { value: 1, unit: ChronoUnit.Type.HOURS }, timeFormat: 'hour' }; // 1 Hour + result = { resolution: { value: 1, unit: ChronoUnit.Type.HOURS }, timeFormat: "hour" }; // 1 Hour } } else if (days <= 6) { if (service.isSmartphoneResolution) { - result = { resolution: { value: 8, unit: ChronoUnit.Type.HOURS }, timeFormat: 'day' }; // 1 Day + result = { resolution: { value: 8, unit: ChronoUnit.Type.HOURS }, timeFormat: "day" }; // 1 Day } else { // >> show Hours - result = { resolution: { value: 1, unit: ChronoUnit.Type.HOURS }, timeFormat: 'day' }; // 1 Day + result = { resolution: { value: 1, unit: ChronoUnit.Type.HOURS }, timeFormat: "day" }; // 1 Day } } else if (days <= 31 && service.isSmartphoneResolution) { // Smartphone-View: show 31 days in daily view - result = { resolution: { value: 1, unit: ChronoUnit.Type.DAYS }, timeFormat: 'day' }; // 1 Day + result = { resolution: { value: 1, unit: ChronoUnit.Type.DAYS }, timeFormat: "day" }; // 1 Day } else if (days <= 90) { - result = { resolution: { value: 1, unit: ChronoUnit.Type.DAYS }, timeFormat: 'day' }; // 1 Day + result = { resolution: { value: 1, unit: ChronoUnit.Type.DAYS }, timeFormat: "day" }; // 1 Day } else if (days <= 144) { // >> show Days if (service.isSmartphoneResolution == true) { - result = { resolution: { value: 1, unit: ChronoUnit.Type.MONTHS }, timeFormat: 'month' }; // 1 Month + result = { resolution: { value: 1, unit: ChronoUnit.Type.MONTHS }, timeFormat: "month" }; // 1 Month } else { - result = { resolution: { value: 1, unit: ChronoUnit.Type.DAYS }, timeFormat: 'day' }; // 1 Day + result = { resolution: { value: 1, unit: ChronoUnit.Type.DAYS }, timeFormat: "day" }; // 1 Day } } else if (days <= 365) { - result = { resolution: { value: 1, unit: ChronoUnit.Type.MONTHS }, timeFormat: 'month' }; // 1 Day + result = { resolution: { value: 1, unit: ChronoUnit.Type.MONTHS }, timeFormat: "month" }; // 1 Day } else { // >> show Years - result = { resolution: { value: 1, unit: ChronoUnit.Type.YEARS }, timeFormat: 'year' }; // 1 Month + result = { resolution: { value: 1, unit: ChronoUnit.Type.YEARS }, timeFormat: "year" }; // 1 Month } return result; @@ -394,7 +394,7 @@ export function isLabelVisible(label: string, orElse?: boolean): boolean { if (orElse != null && value == null) { return orElse; } else { - return value !== 'false'; + return value !== "false"; } } @@ -409,7 +409,7 @@ export function setLabelVisible(label: string, visible: boolean | null): void { return; } const labelWithoutUnit = "LABEL_" + label.split(":")[0]; - sessionStorage.setItem(labelWithoutUnit, visible ? 'true' : 'false'); + sessionStorage.setItem(labelWithoutUnit, visible ? "true" : "false"); } export type Resolution = { @@ -460,7 +460,7 @@ export type ChartData = { }[], tooltip: { /** Unit to be displayed as Tooltips unit */ - unit: '%' | 'kWh' | 'kW', + unit: "%" | "kWh" | "kW", /** Format of Number displayed */ formatNumber: string; }, @@ -493,16 +493,16 @@ export const DEFAULT_NUMBER_CHART_OPTIONS = (labels: (Date | string)[]): Chart.C legend: { display: true, - position: 'bottom', + position: "bottom", labels: { - color: getComputedStyle(document.documentElement).getPropertyValue('--ion-color-primary'), + color: getComputedStyle(document.documentElement).getPropertyValue("--ion-color-primary"), generateLabels: (chart: Chart.Chart) => { return null; }, }, onClick: (event, legendItem, legend) => { }, }, tooltip: { intersect: false, - mode: 'index', + mode: "index", filter: function (item, data, test, some) { const value = item.dataset.data[item.dataIndex] as number; return !isNaN(value) && value !== null; @@ -520,7 +520,7 @@ export const DEFAULT_NUMBER_CHART_OPTIONS = (labels: (Date | string)[]): Chart.C x: { stacked: true, offset: false, - type: 'category', + type: "category", ticks: { autoSkip: true, callback: function (value, index, ticks) { @@ -531,7 +531,7 @@ export const DEFAULT_NUMBER_CHART_OPTIONS = (labels: (Date | string)[]): Chart.C return labels[index].toString(); }, }, - bounds: 'data', + bounds: "data", }, }, }); diff --git a/ui/src/app/edge/history/singlethreshold/chart.component.ts b/ui/src/app/edge/history/singlethreshold/chart.component.ts deleted file mode 100644 index 3165adec062..00000000000 --- a/ui/src/app/edge/history/singlethreshold/chart.component.ts +++ /dev/null @@ -1,276 +0,0 @@ -// @ts-strict-ignore -import { formatNumber } from '@angular/common'; -import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { TranslateService } from '@ngx-translate/core'; -import * as Chart from 'chart.js'; -import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; -import { ChartAxis, YAxisTitle } from 'src/app/shared/service/utils'; - -import { QueryHistoricTimeseriesDataResponse } from '../../../shared/jsonrpc/response/queryHistoricTimeseriesDataResponse'; -import { ChannelAddress, Edge, EdgeConfig, Service } from '../../../shared/shared'; -import { AbstractHistoryChart } from '../abstracthistorychart'; - -@Component({ - selector: 'singlethresholdChart', - templateUrl: '../abstracthistorychart.html', -}) -export class SinglethresholdChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - - @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; - @Input({ required: true }) public componentId!: string; - @Input({ required: true }) public inputChannelUnit!: string; - - constructor( - protected override service: Service, - protected override translate: TranslateService, - private route: ActivatedRoute, - ) { - super("singlethreshold-chart", service, translate); - } - - ngOnInit() { - this.startSpinner(); - this.service.setCurrentComponent('', this.route); - } - - ngOnDestroy() { - this.unsubscribeChartRefresh(); - } - - ngOnChanges() { - this.updateChart(); - } - - public getChartHeight(): number { - return window.innerHeight / 1.3; - } - - protected updateChart() { - this.autoSubscribeChartRefresh(); - this.startSpinner(); - this.colors = []; - this.loading = true; - - this.queryHistoricTimeseriesData(this.period.from, this.period.to).then(response => { - this.service.getConfig().then(config => { - const outputChannel: string | string[] = config.getComponentProperties(this.componentId)['outputChannelAddress']; - const inputChannel = config.getComponentProperties(this.componentId)['inputChannelAddress']; - const result = (response as QueryHistoricTimeseriesDataResponse).result; - let yAxisID; - - // set yAxis for % values (if there are no other % values: use left yAxis, if there are: use right yAxis - for percent values) - if (result.data["_sum/EssSoc"]) { - yAxisID = "yAxis1"; - } else { - yAxisID = "yAxis2"; - } - - // convert labels - const labels: Date[] = []; - for (const timestamp of result.timestamps) { - labels.push(new Date(timestamp)); - } - this.labels = labels; - const datasets = []; - - // convert datasets - for (const channel in result.data) { - if ((typeof outputChannel === 'string' && channel == outputChannel) - || (typeof outputChannel !== 'string' && outputChannel.includes(channel))) { - const address = ChannelAddress.fromString(channel); - const data = result.data[channel].map(value => { - if (value == null) { - return null; - } else { - return value * 100; // convert to % [0,100] - } - }); - datasets.push({ - label: address.channelId, - data: data, - hidden: false, - yAxisID: yAxisID, - position: 'right', - }); - this.colors.push({ - backgroundColor: 'rgba(0,191,255,0.05)', - borderColor: 'rgba(0,191,255,1)', - }); - } - if (channel == inputChannel) { - let inputLabel: string | null = null; - const address = ChannelAddress.fromString(channel); - switch (address.channelId) { - case 'GridActivePower': - inputLabel = this.translate.instant('General.grid'); - break; - case 'ProductionActivePower': - inputLabel = this.translate.instant('General.production'); - break; - case 'EssSoc': - inputLabel = this.translate.instant('General.soc'); - break; - default: - inputLabel = this.translate.instant('Edge.Index.Widgets.Singlethreshold.other'); - break; - } - let data; - if (address.channelId == 'EssSoc') { - data = result.data[channel].map(value => { - if (value == null) { - return null; - } else if (value > 100 || value < 0) { - return null; - } else { - return value; - } - }); - } else if (address.channelId == 'ProductionActivePower' || address.channelId == 'GridActivePower') { - data = result.data[channel].map(value => { - if (value == null) { - return null; - } else { - return value / 1000; // convert to kW - } - }); - } else { - data = result.data[channel].map(value => { - if (value == null) { - return null; - } else { - return value; - } - }); - } - if (address.channelId == 'EssSoc') { - datasets.push({ - label: inputLabel, - data: data, - hidden: false, - yAxisID: yAxisID, - position: 'right', - unit: YAxisTitle.PERCENTAGE, - }); - - this.colors.push({ - backgroundColor: 'rgba(189, 195, 199,0.05)', - borderColor: 'rgba(189, 195, 199,1)', - }); - } else { - datasets.push({ - label: inputLabel, - data: data, - hidden: false, - yAxisID: 'yAxis1', - position: 'left', - }); - - this.colors.push({ - backgroundColor: 'rgba(0,0,0,0.05)', - borderColor: 'rgba(0,0,0,1)', - }); - } - } - } - this.datasets = datasets; - this.loading = false; - this.stopSpinner(); - - }).catch(reason => { - console.error(reason); // TODO error message - this.initializeChart(); - return; - }).finally(async () => { - this.unit = YAxisTitle.PERCENTAGE; - await this.setOptions(this.options); - this.addControllerSpecificOptions(this.options); - }); - }).catch(reason => { - console.error(reason); // TODO error message - this.initializeChart(); - return; - }); - } - - protected getChannelAddresses(edge: Edge, config: EdgeConfig): Promise { - return new Promise((resolve) => { - const inputChannel = ChannelAddress.fromString(config.getComponentProperties(this.componentId)['inputChannelAddress']); - const result: ChannelAddress[] = [inputChannel]; - const outputChannelAddress: string | string[] = config.getComponentProperties(this.componentId)['outputChannelAddress']; - if (typeof outputChannelAddress === 'string') { - result.push(ChannelAddress.fromString(outputChannelAddress)); - } else { - outputChannelAddress.forEach(c => result.push(ChannelAddress.fromString(c))); - } - resolve(result); - }); - } - - protected setLabel(config: EdgeConfig) { - this.options = this.createDefaultChartOptions(); - } - - protected addControllerSpecificOptions(options: Chart.ChartOptions) { - - this.service.getConfig().then(config => { - - const inputChannel = ChannelAddress.fromString(config.getComponentProperties(this.componentId)['inputChannelAddress']); - const outputChannelAddress: string | string[] = config.getComponentProperties(this.componentId)['outputChannelAddress']; - let outputChannel: ChannelAddress; - if (typeof outputChannelAddress === 'string') { - outputChannel = ChannelAddress.fromString(outputChannelAddress); - } else { - outputChannel = ChannelAddress.fromString(outputChannelAddress[0]); - } - - let labelString; - - if (inputChannel.channelId == 'EssSoc') { - labelString = '%'; - this.unit = YAxisTitle.PERCENTAGE; - options.scales[ChartAxis.LEFT]['title'].text = labelString; - } else if (inputChannel.channelId == 'GridActivePower' || inputChannel.channelId == 'ProductionActivePower') { - labelString = 'kW'; - this.unit = YAxisTitle.ENERGY; - options.scales[ChartAxis.LEFT]['title'].text = labelString; - } else { - labelString = this.inputChannelUnit; - options.scales[ChartAxis.LEFT]['title'].text = labelString; - } - - if (inputChannel.channelId != 'EssSoc') { - // adds second y-axis to chart - options.scales[ChartAxis.RIGHT] = { - max: 100, - position: 'right', - title: { - text: '%', - display: true, - }, - ticks: { - padding: -5, - stepSize: 20, - }, - }; - } - - const translate = this.translate; - options.plugins.tooltip.callbacks.label = function (item: Chart.TooltipItem) { - const label = item.dataset.label; - const value = item.dataset.data[item.dataIndex]; - if (label == outputChannel.channelId || label == translate.instant('General.soc')) { - return label + ": " + formatNumber(value, 'de', '1.0-0') + " %"; - } else if (label == translate.instant('General.grid') || label == translate.instant('General.production')) { - return label + ": " + formatNumber(value, 'de', '1.0-2') + " kW"; - } else { - return label + ": " + formatNumber(value, 'de', '1.0-2') + " " + labelString; - } - }; - - this.options = options; - }); - - } - -} diff --git a/ui/src/app/edge/history/singlethreshold/singlethresholdchartoverview/singlethresholdchartoverview.component.html b/ui/src/app/edge/history/singlethreshold/singlethresholdchartoverview/singlethresholdchartoverview.component.html deleted file mode 100644 index ebd9b564647..00000000000 --- a/ui/src/app/edge/history/singlethreshold/singlethresholdchartoverview/singlethresholdchartoverview.component.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - {{ component.alias }} - - - - - - - - - - - - - - - - - - - - - -
      - - -
      -
      - - - - - - - - Edge.Index.Widgets.twoWayInfoGrid - - - - - -
      -
      -
      diff --git a/ui/src/app/edge/history/singlethreshold/singlethresholdchartoverview/singlethresholdchartoverview.component.ts b/ui/src/app/edge/history/singlethreshold/singlethresholdchartoverview/singlethresholdchartoverview.component.ts deleted file mode 100644 index 752aafb63ea..00000000000 --- a/ui/src/app/edge/history/singlethreshold/singlethresholdchartoverview/singlethresholdchartoverview.component.ts +++ /dev/null @@ -1,51 +0,0 @@ -// @ts-strict-ignore -import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { ChannelAddress, Edge, EdgeConfig, Service, Utils, Websocket } from '../../../../shared/shared'; - -@Component({ - selector: SinglethresholdChartOverviewComponent.SELECTOR, - templateUrl: './singlethresholdchartoverview.component.html', -}) -export class SinglethresholdChartOverviewComponent implements OnInit { - - private static readonly SELECTOR = "channelthreshold-chart-overview"; - - public edge: Edge | null = null; - - public component: EdgeConfig.Component | null = null; - public inputChannel: string; - - // reference to the Utils method to access via html - public isLastElement = Utils.isLastElement; - - protected inputChannelUnit: string; - protected readonly spinnerid = SinglethresholdChartOverviewComponent.SELECTOR; - - - constructor( - public service: Service, - private route: ActivatedRoute, - private websocket: Websocket, - ) { } - - ngOnInit() { - this.service.startSpinner(this.spinnerid); - this.service.setCurrentComponent('', this.route).then(edge => { - this.service.getConfig().then(config => { - this.edge = edge; - this.component = config.getComponent(this.route.snapshot.params.componentId); - this.inputChannel = config.getComponentProperties(this.component.id)['inputChannelAddress']; - - this.edge.getChannel(this.websocket, ChannelAddress.fromString(this.inputChannel)).then(c => { - this.inputChannelUnit = c.unit; - }).catch(e => { - console.error(e); - this.inputChannelUnit = ''; - }).finally(() => { - this.service.stopSpinner(this.spinnerid); - }); - }); - }); - } -} diff --git a/ui/src/app/edge/history/singlethreshold/widget.component.html b/ui/src/app/edge/history/singlethreshold/widget.component.html deleted file mode 100644 index a0d04bc95ca..00000000000 --- a/ui/src/app/edge/history/singlethreshold/widget.component.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - {{ component.alias }} - - - - - - - -
      - Edge.History.activeDuration - {{ activeSecondsOverPeriod | formatSecondsToDuration }} -
      -
      -
      diff --git a/ui/src/app/edge/history/singlethreshold/widget.component.ts b/ui/src/app/edge/history/singlethreshold/widget.component.ts deleted file mode 100644 index c0ba1844e78..00000000000 --- a/ui/src/app/edge/history/singlethreshold/widget.component.ts +++ /dev/null @@ -1,74 +0,0 @@ -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'; - -@Component({ - selector: SinglethresholdWidgetComponent.SELECTOR, - templateUrl: './widget.component.html', -}) -export class SinglethresholdWidgetComponent extends AbstractHistoryWidget implements OnInit, OnChanges, OnDestroy { - - private static readonly SELECTOR = "singlethresholdWidget"; - - @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; - @Input({ required: true }) public componentId!: string; - - public activeSecondsOverPeriod: number | null = null; - public edge: Edge | null = null; - public component: EdgeConfig.Component | null = null; - - constructor( - public override service: Service, - private route: ActivatedRoute, - ) { - super(service); - } - - ngOnInit() { - this.service.setCurrentComponent('', this.route).then(response => { - this.edge = response; - this.service.getConfig().then(config => { - this.component = config.getComponent(this.componentId); - }); - }); - } - - ngOnDestroy() { - this.unsubscribeWidgetRefresh(); - } - - ngOnChanges() { - this.updateValues(); - } - - // Gather result & timestamps to calculate effective active time in % - protected updateValues() { - this.queryHistoricTimeseriesData(this.service.historyPeriod.value.from, this.service.historyPeriod.value.to).then(response => { - this.service.getConfig().then(config => { - const result = (response as QueryHistoricTimeseriesDataResponse).result; - let outputChannelAddress: string | string[] = config.getComponentProperties(this.componentId)['outputChannelAddress']; - if (typeof outputChannelAddress !== 'string') { - // Takes only the first output for simplicity reasons - outputChannelAddress = outputChannelAddress[0]; - } - this.activeSecondsOverPeriod = calculateActiveTimeOverPeriod(ChannelAddress.fromString(outputChannelAddress), result); - }); - }); - } - - protected getChannelAddresses(edge: Edge, config: EdgeConfig): Promise { - return new Promise((resolve) => { - const outputChannelAddress: string | string[] = config.getComponentProperties(this.componentId)['outputChannelAddress']; - if (typeof outputChannelAddress === 'string') { - resolve([ChannelAddress.fromString(outputChannelAddress)]); - } else { - resolve(outputChannelAddress.map(c => ChannelAddress.fromString(c))); - } - }); - } -} diff --git a/ui/src/app/edge/history/storage/chargerchart.component.ts b/ui/src/app/edge/history/storage/chargerchart.component.ts index 60c1ddedb19..44395de3842 100644 --- a/ui/src/app/edge/history/storage/chargerchart.component.ts +++ b/ui/src/app/edge/history/storage/chargerchart.component.ts @@ -1,15 +1,15 @@ // @ts-strict-ignore -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 { 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 { ChannelAddress, Edge, EdgeConfig, Service } from "../../../shared/shared"; +import { AbstractHistoryChart } from "../abstracthistorychart"; @Component({ - selector: 'storageChargerChart', - templateUrl: '../abstracthistorychart.html', + selector: "storageChargerChart", + templateUrl: "../abstracthistorychart.html", }) export class StorageChargerChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { @@ -32,7 +32,6 @@ export class StorageChargerChartComponent extends AbstractHistoryChart implement ngOnInit() { this.startSpinner(); - this.service.setCurrentComponent('', this.route); } ngOnDestroy() { @@ -71,13 +70,13 @@ export class StorageChargerChartComponent extends AbstractHistoryChart implement }); if (address.channelId == "ActualPower") { datasets.push({ - label: this.translate.instant('General.chargePower'), + label: this.translate.instant("General.chargePower"), data: chargerData, hidden: false, }); this.colors.push({ - backgroundColor: 'rgba(0,223,0,0.05)', - borderColor: 'rgba(0,223,0,1)', + backgroundColor: "rgba(0,223,0,0.05)", + borderColor: "rgba(0,223,0,1)", }); } }); @@ -97,7 +96,7 @@ export class StorageChargerChartComponent extends AbstractHistoryChart implement protected getChannelAddresses(edge: Edge, config: EdgeConfig): Promise { return new Promise((resolve) => { const result: ChannelAddress[] = [ - new ChannelAddress(this.componentId, 'ActualPower'), + new ChannelAddress(this.componentId, "ActualPower"), ]; resolve(result); }); diff --git a/ui/src/app/edge/history/storage/esschart.component.ts b/ui/src/app/edge/history/storage/esschart.component.ts index 45071d138f8..cd83e95a11f 100644 --- a/ui/src/app/edge/history/storage/esschart.component.ts +++ b/ui/src/app/edge/history/storage/esschart.component.ts @@ -1,15 +1,15 @@ // @ts-strict-ignore -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 { 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 { ChannelAddress, Edge, EdgeConfig, Service } from "../../../shared/shared"; +import { AbstractHistoryChart } from "../abstracthistorychart"; @Component({ - selector: 'storageESSChart', - templateUrl: '../abstracthistorychart.html', + selector: "storageESSChart", + templateUrl: "../abstracthistorychart.html", }) export class StorageESSChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { @@ -34,7 +34,6 @@ export class StorageESSChartComponent extends AbstractHistoryChart implements On ngOnInit() { this.startSpinner(); - this.service.setCurrentComponent('', this.route); this.setLabel(); } @@ -78,33 +77,33 @@ export class StorageESSChartComponent extends AbstractHistoryChart implements On } else { if (channelAddress.channelId == "ActivePower") { datasets.push({ - label: this.translate.instant('General.chargeDischarge'), + label: this.translate.instant("General.chargeDischarge"), data: data, hidden: false, }); this.colors.push({ - backgroundColor: 'rgba(0,223,0,0.05)', - borderColor: 'rgba(0,223,0,1)', + backgroundColor: "rgba(0,223,0,0.05)", + borderColor: "rgba(0,223,0,1)", }); } - if (this.componentId + '/ActivePowerL1' && this.componentId + '/ActivePowerL2' && this.componentId + '/ActivePowerL3' in result.data && this.showPhases == true) { - if (channelAddress.channelId == 'ActivePowerL1') { + if (this.componentId + "/ActivePowerL1" && this.componentId + "/ActivePowerL2" && this.componentId + "/ActivePowerL3" in result.data && this.showPhases == true) { + if (channelAddress.channelId == "ActivePowerL1") { datasets.push({ - label: this.translate.instant('General.phase') + ' ' + 'L1', + label: this.translate.instant("General.phase") + " " + "L1", data: data, }); this.colors.push(this.phase1Color); } - if (channelAddress.channelId == 'ActivePowerL2') { + if (channelAddress.channelId == "ActivePowerL2") { datasets.push({ - label: this.translate.instant('General.phase') + ' ' + 'L2', + label: this.translate.instant("General.phase") + " " + "L2", data: data, }); this.colors.push(this.phase2Color); } - if (channelAddress.channelId == 'ActivePowerL3') { + if (channelAddress.channelId == "ActivePowerL3") { datasets.push({ - label: this.translate.instant('General.phase') + ' ' + 'L3', + label: this.translate.instant("General.phase") + " " + "L3", data: data, }); this.colors.push(this.phase3Color); @@ -143,13 +142,13 @@ export class StorageESSChartComponent extends AbstractHistoryChart implements On const factory = config.factories[factoryID]; return new Promise((resolve, reject) => { const result: ChannelAddress[] = [ - new ChannelAddress(this.componentId, 'ActivePower'), + new ChannelAddress(this.componentId, "ActivePower"), ]; if ((factory.natureIds.includes("io.openems.edge.ess.api.AsymmetricEss"))) { result.push( - new ChannelAddress(component.id, 'ActivePowerL1'), - new ChannelAddress(component.id, 'ActivePowerL2'), - new ChannelAddress(component.id, 'ActivePowerL3'), + new ChannelAddress(component.id, "ActivePowerL1"), + new ChannelAddress(component.id, "ActivePowerL2"), + new ChannelAddress(component.id, "ActivePowerL3"), ); } resolve(result); diff --git a/ui/src/app/edge/history/storage/singlechart.component.ts b/ui/src/app/edge/history/storage/singlechart.component.ts index 3f670d816ee..4d987a4b2ee 100644 --- a/ui/src/app/edge/history/storage/singlechart.component.ts +++ b/ui/src/app/edge/history/storage/singlechart.component.ts @@ -1,18 +1,18 @@ // @ts-strict-ignore -import { formatNumber } from '@angular/common'; -import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { TranslateService } from '@ngx-translate/core'; -import * as Chart from 'chart.js'; -import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; -import { ChartAxis, YAxisTitle } from 'src/app/shared/service/utils'; +import { formatNumber } from "@angular/common"; +import { Component, Input, OnChanges, OnDestroy, OnInit } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { TranslateService } from "@ngx-translate/core"; +import * as Chart from "chart.js"; +import { DefaultTypes } from "src/app/shared/service/defaulttypes"; +import { ChartAxis, YAxisType } from "src/app/shared/service/utils"; -import { ChannelAddress, Edge, EdgeConfig, Service, Utils } from '../../../shared/shared'; -import { AbstractHistoryChart } from '../abstracthistorychart'; +import { ChannelAddress, Edge, EdgeConfig, Service, Utils } from "../../../shared/shared"; +import { AbstractHistoryChart } from "../abstracthistorychart"; @Component({ - selector: 'storageSingleChart', - templateUrl: '../abstracthistorychart.html', + selector: "storageSingleChart", + templateUrl: "../abstracthistorychart.html", }) export class StorageSingleChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { @@ -33,7 +33,6 @@ export class StorageSingleChartComponent extends AbstractHistoryChart implements ngOnInit() { this.startSpinner(); - this.service.setCurrentComponent('', this.route); } ngOnDestroy() { @@ -47,11 +46,11 @@ export class StorageSingleChartComponent extends AbstractHistoryChart implements protected getChannelAddresses(edge: Edge, config: EdgeConfig): Promise { return new Promise((resolve) => { const result: ChannelAddress[] = [ - new ChannelAddress('_sum', 'EssActivePower'), - new ChannelAddress('_sum', 'ProductionDcActualPower'), - new ChannelAddress('_sum', 'EssActivePowerL1'), - new ChannelAddress('_sum', 'EssActivePowerL2'), - new ChannelAddress('_sum', 'EssActivePowerL3'), + new ChannelAddress("_sum", "EssActivePower"), + new ChannelAddress("_sum", "ProductionDcActualPower"), + new ChannelAddress("_sum", "EssActivePowerL1"), + new ChannelAddress("_sum", "EssActivePowerL2"), + new ChannelAddress("_sum", "EssActivePowerL3"), ]; resolve(result); }); @@ -86,20 +85,20 @@ export class StorageSingleChartComponent extends AbstractHistoryChart implements let effectivePowerL2 = []; let effectivePowerL3 = []; - if (config.getComponentsImplementingNature('io.openems.edge.ess.dccharger.api.EssDcCharger').length > 0) { - result.data['_sum/ProductionDcActualPower'].forEach((value, index) => { - if (result.data['_sum/ProductionDcActualPower'][index] != null) { - effectivePower[index] = Utils.subtractSafely(result.data['_sum/EssActivePower'][index], value); - effectivePowerL1[index] = Utils.subtractSafely(result.data['_sum/EssActivePowerL1'][index], value / 3); - effectivePowerL2[index] = Utils.subtractSafely(result.data['_sum/EssActivePowerL2'][index], value / 3); - effectivePowerL3[index] = Utils.subtractSafely(result.data['_sum/EssActivePowerL3'][index], value / 3); + if (config.getComponentsImplementingNature("io.openems.edge.ess.dccharger.api.EssDcCharger").length > 0) { + result.data["_sum/ProductionDcActualPower"].forEach((value, index) => { + if (result.data["_sum/ProductionDcActualPower"][index] != null) { + effectivePower[index] = Utils.subtractSafely(result.data["_sum/EssActivePower"][index], value); + effectivePowerL1[index] = Utils.subtractSafely(result.data["_sum/EssActivePowerL1"][index], value / 3); + effectivePowerL2[index] = Utils.subtractSafely(result.data["_sum/EssActivePowerL2"][index], value / 3); + effectivePowerL3[index] = Utils.subtractSafely(result.data["_sum/EssActivePowerL3"][index], value / 3); } }); } else { - effectivePower = result.data['_sum/EssActivePower']; - effectivePowerL1 = result.data['_sum/EssActivePowerL1']; - effectivePowerL2 = result.data['_sum/EssActivePowerL2']; - effectivePowerL3 = result.data['_sum/EssActivePowerL3']; + effectivePower = result.data["_sum/EssActivePower"]; + effectivePowerL1 = result.data["_sum/EssActivePowerL1"]; + effectivePowerL2 = result.data["_sum/EssActivePowerL2"]; + effectivePowerL3 = result.data["_sum/EssActivePowerL3"]; } const totalData = effectivePower.map(value => { @@ -148,30 +147,30 @@ export class StorageSingleChartComponent extends AbstractHistoryChart implements } else { if (channelAddress.channelId == "EssActivePower") { datasets.push({ - label: this.translate.instant('General.chargeDischarge'), + label: this.translate.instant("General.chargeDischarge"), data: totalData, }); this.colors.push({ - backgroundColor: 'rgba(0,223,0,0.05)', - borderColor: 'rgba(0,223,0,1)', + backgroundColor: "rgba(0,223,0,0.05)", + borderColor: "rgba(0,223,0,1)", }); } - if ('_sum/EssActivePowerL1' && '_sum/EssActivePowerL2' && '_sum/EssActivePowerL3' in result.data && this.showPhases == true) { - if (channelAddress.channelId == 'EssActivePowerL1') { + if ("_sum/EssActivePowerL1" && "_sum/EssActivePowerL2" && "_sum/EssActivePowerL3" in result.data && this.showPhases == true) { + if (channelAddress.channelId == "EssActivePowerL1") { datasets.push({ - label: this.translate.instant('General.phase') + ' ' + 'L1', + label: this.translate.instant("General.phase") + " " + "L1", data: totalDataL1, }); this.colors.push(this.phase1Color); - } if (channelAddress.channelId == 'EssActivePowerL2') { + } if (channelAddress.channelId == "EssActivePowerL2") { datasets.push({ - label: this.translate.instant('General.phase') + ' ' + 'L2', + label: this.translate.instant("General.phase") + " " + "L2", data: totalDataL2, }); this.colors.push(this.phase2Color); - } if (channelAddress.channelId == 'EssActivePowerL3') { + } if (channelAddress.channelId == "EssActivePowerL3") { datasets.push({ - label: this.translate.instant('General.phase') + ' ' + 'L3', + label: this.translate.instant("General.phase") + " " + "L3", data: totalDataL3, }); this.colors.push(this.phase3Color); @@ -198,7 +197,7 @@ export class StorageSingleChartComponent extends AbstractHistoryChart implements this.initializeChart(); return; }).finally(async () => { - this.unit = YAxisTitle.ENERGY; + this.unit = YAxisType.ENERGY; await this.setOptions(this.options); this.applyControllerSpecificChartOptions(this.options); this.loading = false; @@ -216,24 +215,24 @@ export class StorageSingleChartComponent extends AbstractHistoryChart implements const value = tooltipItem.dataset.data[tooltipItem.dataIndex]; // 0.005 to prevent showing Charge or Discharge if value is e.g. 0.00232138 if (value < -0.005) { - if (label.includes(translate.instant('General.phase'))) { - label += ' ' + translate.instant('General.chargePower'); + if (label.includes(translate.instant("General.phase"))) { + label += " " + translate.instant("General.chargePower"); } else { - label = translate.instant('General.chargePower'); + label = translate.instant("General.chargePower"); } } else if (value > 0.005) { - if (label.includes(translate.instant('General.phase'))) { - label += ' ' + translate.instant('General.dischargePower'); + if (label.includes(translate.instant("General.phase"))) { + label += " " + translate.instant("General.dischargePower"); } else { - label = translate.instant('General.dischargePower'); + label = translate.instant("General.dischargePower"); } } - return label + ": " + formatNumber(value, 'de', '1.0-2') + " kW"; + return label + ": " + formatNumber(value, "de", "1.0-2") + " kW"; }; // Data doesnt have all datapoints for period // original logic has not been touched - options.scales.x.ticks['source'] = 'auto'; + options.scales.x.ticks["source"] = "auto"; this.options = options; } diff --git a/ui/src/app/edge/history/storage/socchart.component.ts b/ui/src/app/edge/history/storage/socchart.component.ts index 6e76644f311..bf127df1811 100644 --- a/ui/src/app/edge/history/storage/socchart.component.ts +++ b/ui/src/app/edge/history/storage/socchart.component.ts @@ -1,16 +1,16 @@ // @ts-strict-ignore -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 { YAxisTitle } from 'src/app/shared/service/utils'; +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 { YAxisType } from "src/app/shared/service/utils"; -import { ChannelAddress, Edge, EdgeConfig, Service } from '../../../shared/shared'; -import { AbstractHistoryChart } from '../abstracthistorychart'; +import { ChannelAddress, Edge, EdgeConfig, Service } from "../../../shared/shared"; +import { AbstractHistoryChart } from "../abstracthistorychart"; @Component({ - selector: 'socStorageChart', - templateUrl: '../abstracthistorychart.html', + selector: "socStorageChart", + templateUrl: "../abstracthistorychart.html", }) export class SocStorageChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { @@ -35,7 +35,6 @@ export class SocStorageChartComponent extends AbstractHistoryChart implements On public ngOnInit() { this.startSpinner(); - this.service.setCurrentComponent('', this.route); } public ngOnDestroy() { @@ -77,28 +76,28 @@ export class SocStorageChartComponent extends AbstractHistoryChart implements On if (!data) { return; } else { - if (channelAddress.channelId === 'EssSoc') { + if (channelAddress.channelId === "EssSoc") { datasets.push({ - label: (moreThanOneESS ? this.translate.instant('General.TOTAL') : this.translate.instant('General.soc')), + label: (moreThanOneESS ? this.translate.instant("General.TOTAL") : this.translate.instant("General.soc")), data: data, }); this.colors.push({ - backgroundColor: 'rgba(0,223,0,0.05)', - borderColor: 'rgba(0,223,0,1)', + backgroundColor: "rgba(0,223,0,0.05)", + borderColor: "rgba(0,223,0,1)", }); } - if (channelAddress.channelId === 'Soc' && moreThanOneESS) { + if (channelAddress.channelId === "Soc" && moreThanOneESS) { datasets.push({ label: (channelAddress.componentId == component.alias ? component.id : component.alias), data: data, }); this.colors.push({ - backgroundColor: 'rgba(128,128,128,0.05)', - borderColor: 'rgba(128,128,128,1)', + backgroundColor: "rgba(128,128,128,0.05)", + borderColor: "rgba(128,128,128,1)", }); } } - if (channelAddress.channelId === 'ActualReserveSoc') { + if (channelAddress.channelId === "ActualReserveSoc") { datasets.push({ label: this.emergencyCapacityReserveComponents.length > 1 ? component.alias : this.translate.instant("Edge.Index.EmergencyReserve.EMERGENCY_RESERVE"), @@ -107,8 +106,8 @@ export class SocStorageChartComponent extends AbstractHistoryChart implements On }); this.colors.push({ - backgroundColor: 'rgba(1, 1, 1,0)', - borderColor: 'rgba(1, 1, 1,1)', + backgroundColor: "rgba(1, 1, 1,0)", + borderColor: "rgba(1, 1, 1,1)", }); } }); @@ -117,8 +116,8 @@ export class SocStorageChartComponent extends AbstractHistoryChart implements On this.loading = false; this.stopSpinner(); }).finally(async () => { - this.unit = YAxisTitle.PERCENTAGE; - this.formatNumber = '1.0-0'; + this.unit = YAxisType.PERCENTAGE; + this.formatNumber = "1.0-0"; await this.setOptions(this.options); }); @@ -144,20 +143,20 @@ export class SocStorageChartComponent extends AbstractHistoryChart implements On protected getChannelAddresses(edge: Edge, config: EdgeConfig): Promise { return new Promise((resolve) => { const channeladdresses: ChannelAddress[] = []; - channeladdresses.push(new ChannelAddress('_sum', 'EssSoc')); + channeladdresses.push(new ChannelAddress("_sum", "EssSoc")); - this.emergencyCapacityReserveComponents = config.getComponentsByFactory('Controller.Ess.EmergencyCapacityReserve') + this.emergencyCapacityReserveComponents = config.getComponentsByFactory("Controller.Ess.EmergencyCapacityReserve") .filter(component => component.isEnabled); this.emergencyCapacityReserveComponents .forEach(component => - channeladdresses.push(new ChannelAddress(component.id, 'ActualReserveSoc')), + channeladdresses.push(new ChannelAddress(component.id, "ActualReserveSoc")), ); const ess = config.getComponentsImplementingNature("io.openems.edge.ess.api.SymmetricEss"); if (ess.length > 1) { - ess.filter(component => !(component.factoryId === 'Ess.Cluster')).forEach(component => { - channeladdresses.push(new ChannelAddress(component.id, 'Soc')); + ess.filter(component => !(component.factoryId === "Ess.Cluster")).forEach(component => { + channeladdresses.push(new ChannelAddress(component.id, "Soc")); }); } resolve(channeladdresses); diff --git a/ui/src/app/edge/history/storage/storagechartoverview/storagechartoverview.component.ts b/ui/src/app/edge/history/storage/storagechartoverview/storagechartoverview.component.ts index 84f1c456a1a..9562ad8825a 100644 --- a/ui/src/app/edge/history/storage/storagechartoverview/storagechartoverview.component.ts +++ b/ui/src/app/edge/history/storage/storagechartoverview/storagechartoverview.component.ts @@ -1,11 +1,11 @@ // @ts-strict-ignore -import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { Edge, EdgeConfig, Service, Utils } from '../../../../shared/shared'; +import { Component, OnInit } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { Edge, EdgeConfig, Service, Utils } from "../../../../shared/shared"; @Component({ selector: StorageChartOverviewComponent.SELECTOR, - templateUrl: './storagechartoverview.component.html', + templateUrl: "./storagechartoverview.component.html", }) export class StorageChartOverviewComponent implements OnInit { @@ -29,7 +29,7 @@ export class StorageChartOverviewComponent implements OnInit { ) { } ngOnInit() { - this.service.setCurrentComponent('', this.route).then(edge => { + this.service.getCurrentEdge().then(edge => { this.service.getConfig().then(config => { this.edge = edge; this.essComponents = config.getComponentsImplementingNature("io.openems.edge.ess.api.SymmetricEss").filter(component => !component.factoryId.includes("Ess.Cluster")); diff --git a/ui/src/app/edge/history/storage/totalchart.component.ts b/ui/src/app/edge/history/storage/totalchart.component.ts index fa75aaac305..13375ae97db 100644 --- a/ui/src/app/edge/history/storage/totalchart.component.ts +++ b/ui/src/app/edge/history/storage/totalchart.component.ts @@ -1,18 +1,18 @@ // @ts-strict-ignore -import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { TranslateService } from '@ngx-translate/core'; -import * as Chart from 'chart.js'; -import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; -import { ChartAxis, Utils, YAxisTitle } from 'src/app/shared/service/utils'; -import { ChannelAddress, Edge, EdgeConfig, Service } from 'src/app/shared/shared'; +import { Component, Input, OnChanges, OnDestroy, OnInit } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { TranslateService } from "@ngx-translate/core"; +import * as Chart from "chart.js"; +import { DefaultTypes } from "src/app/shared/service/defaulttypes"; +import { ChartAxis, Utils, YAxisType } from "src/app/shared/service/utils"; +import { ChannelAddress, Edge, EdgeConfig, Service } from "src/app/shared/shared"; -import { formatNumber } from '@angular/common'; -import { AbstractHistoryChart } from '../abstracthistorychart'; +import { formatNumber } from "@angular/common"; +import { AbstractHistoryChart } from "../abstracthistorychart"; @Component({ - selector: 'storageTotalChart', - templateUrl: '../abstracthistorychart.html', + selector: "storageTotalChart", + templateUrl: "../abstracthistorychart.html", }) export class StorageTotalChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { @@ -33,7 +33,6 @@ export class StorageTotalChartComponent extends AbstractHistoryChart implements ngOnInit() { this.startSpinner(); - this.service.setCurrentComponent('', this.route); } ngOnDestroy() { @@ -63,12 +62,12 @@ export class StorageTotalChartComponent extends AbstractHistoryChart implements // calculate total charge and discharge let effectivePower; - if (config.getComponentsImplementingNature('io.openems.edge.ess.dccharger.api.EssDcCharger').length > 0) { - effectivePower = result.data['_sum/ProductionDcActualPower'].map((value, index) => { - return Utils.subtractSafely(result.data['_sum/EssActivePower'][index], value); + if (config.getComponentsImplementingNature("io.openems.edge.ess.dccharger.api.EssDcCharger").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']; + effectivePower = result.data["_sum/EssActivePower"]; } const totalData = effectivePower.map(value => { if (value == null) { @@ -104,29 +103,29 @@ export class StorageTotalChartComponent extends AbstractHistoryChart implements if (channelAddress.channelId == "EssActivePower") { datasets.push({ - label: this.translate.instant('General.TOTAL'), + label: this.translate.instant("General.TOTAL"), data: totalData, }); this.colors.push({ - backgroundColor: 'rgba(0,223,0,0.05)', - borderColor: 'rgba(0,223,0,1)', + backgroundColor: "rgba(0,223,0,0.05)", + borderColor: "rgba(0,223,0,1)", }); - } if ('_sum/EssActivePowerL1' && '_sum/EssActivePowerL2' && '_sum/EssActivePowerL3' in result.data && this.showPhases == true) { - if (channelAddress.channelId == 'EssActivePowerL1') { + } if ("_sum/EssActivePowerL1" && "_sum/EssActivePowerL2" && "_sum/EssActivePowerL3" in result.data && this.showPhases == true) { + if (channelAddress.channelId == "EssActivePowerL1") { datasets.push({ - label: this.translate.instant('General.phase') + ' ' + 'L1', + label: this.translate.instant("General.phase") + " " + "L1", data: data, }); this.colors.push(this.phase1Color); - } if (channelAddress.channelId == 'EssActivePowerL2') { + } if (channelAddress.channelId == "EssActivePowerL2") { datasets.push({ - label: this.translate.instant('General.phase') + ' ' + 'L2', + label: this.translate.instant("General.phase") + " " + "L2", data: data, }); this.colors.push(this.phase2Color); - } if (channelAddress.channelId == 'EssActivePowerL3') { + } if (channelAddress.channelId == "EssActivePowerL3") { datasets.push({ - label: this.translate.instant('General.phase') + ' ' + 'L3', + label: this.translate.instant("General.phase") + " " + "L3", data: data, }); this.colors.push(this.phase3Color); @@ -139,28 +138,28 @@ export class StorageTotalChartComponent extends AbstractHistoryChart implements hidden: false, }); this.colors.push({ - backgroundColor: 'rgba(45,143,171,0.05)', - borderColor: 'rgba(45,143,171,1)', + backgroundColor: "rgba(45,143,171,0.05)", + borderColor: "rgba(45,143,171,1)", }); } - if (component.id + '/ActivePowerL1' && component.id + '/ActivePowerL2' && component.id + '/ActivePowerL3' in result.data && this.showPhases == true) { - if (channelAddress.channelId == 'ActivePowerL1') { + if (component.id + "/ActivePowerL1" && component.id + "/ActivePowerL2" && component.id + "/ActivePowerL3" in result.data && this.showPhases == true) { + if (channelAddress.channelId == "ActivePowerL1") { datasets.push({ - label: (channelAddress.componentId == component.alias ? ' (' + component.id + ')' : ' (' + component.alias + ')') + ' ' + this.translate.instant('General.phase') + ' ' + 'L1', + label: (channelAddress.componentId == component.alias ? " (" + component.id + ")" : " (" + component.alias + ")") + " " + this.translate.instant("General.phase") + " " + "L1", data: data, }); this.colors.push(this.phase1Color); } - if (channelAddress.channelId == 'ActivePowerL2') { + if (channelAddress.channelId == "ActivePowerL2") { datasets.push({ - label: (channelAddress.componentId == component.alias ? ' (' + component.id + ')' : ' (' + component.alias + ')') + ' ' + this.translate.instant('General.phase') + ' ' + 'L2', + label: (channelAddress.componentId == component.alias ? " (" + component.id + ")" : " (" + component.alias + ")") + " " + this.translate.instant("General.phase") + " " + "L2", data: data, }); this.colors.push(this.phase2Color); } - if (channelAddress.channelId == 'ActivePowerL3') { + if (channelAddress.channelId == "ActivePowerL3") { datasets.push({ - label: (channelAddress.componentId == component.alias ? ' (' + component.id + ')' : ' (' + component.alias + ')') + ' ' + this.translate.instant('General.phase') + ' ' + 'L3', + label: (channelAddress.componentId == component.alias ? " (" + component.id + ")" : " (" + component.alias + ")") + " " + this.translate.instant("General.phase") + " " + "L3", data: data, }); this.colors.push(this.phase3Color); @@ -173,14 +172,14 @@ export class StorageTotalChartComponent extends AbstractHistoryChart implements hidden: false, }); this.colors.push({ - backgroundColor: 'rgba(255,215,0,0.05)', - borderColor: 'rgba(255,215,0,1)', + backgroundColor: "rgba(255,215,0,0.05)", + borderColor: "rgba(255,215,0,1)", }); } }); }).finally(async () => { this.datasets = datasets; - this.unit = YAxisTitle.ENERGY; + this.unit = YAxisType.ENERGY; await this.setOptions(this.options); this.applyControllerSpecificChartOptions(this.options); this.stopSpinner(); @@ -209,23 +208,23 @@ export class StorageTotalChartComponent extends AbstractHistoryChart implements protected getChannelAddresses(edge: Edge, config: EdgeConfig): Promise { return new Promise((resolve) => { const result: ChannelAddress[] = [ - new ChannelAddress('_sum', 'EssActivePower'), - new ChannelAddress('_sum', 'ProductionDcActualPower'), - new ChannelAddress('_sum', 'EssActivePowerL1'), - new ChannelAddress('_sum', 'EssActivePowerL2'), - new ChannelAddress('_sum', 'EssActivePowerL3'), + new ChannelAddress("_sum", "EssActivePower"), + new ChannelAddress("_sum", "ProductionDcActualPower"), + new ChannelAddress("_sum", "EssActivePowerL1"), + new ChannelAddress("_sum", "EssActivePowerL2"), + new ChannelAddress("_sum", "EssActivePowerL3"), ]; config.getComponentsImplementingNature("io.openems.edge.ess.api.SymmetricEss") .filter(component => !component.factoryId.includes("Ess.Cluster")) .forEach(component => { const factoryID = component.factoryId; const factory = config.factories[factoryID]; - result.push(new ChannelAddress(component.id, 'ActivePower')); + result.push(new ChannelAddress(component.id, "ActivePower")); if ((factory.natureIds.includes("io.openems.edge.ess.api.AsymmetricEss"))) { result.push( - new ChannelAddress(component.id, 'ActivePowerL1'), - new ChannelAddress(component.id, 'ActivePowerL2'), - new ChannelAddress(component.id, 'ActivePowerL3'), + new ChannelAddress(component.id, "ActivePowerL1"), + new ChannelAddress(component.id, "ActivePowerL2"), + new ChannelAddress(component.id, "ActivePowerL3"), ); } }); @@ -233,7 +232,7 @@ export class StorageTotalChartComponent extends AbstractHistoryChart implements if (config.getComponentsImplementingNature("io.openems.edge.ess.api.SymmetricEss") .filter(component => !component.factoryId.includes("Ess.Cluster")).length != 1 && charger.length > 0) { charger.forEach(component => { - result.push(new ChannelAddress(component.id, 'ActualPower')); + result.push(new ChannelAddress(component.id, "ActualPower")); }); } resolve(result); @@ -253,11 +252,11 @@ export class StorageTotalChartComponent extends AbstractHistoryChart implements const value = tooltipItem.dataset.data[tooltipItem.dataIndex]; // 0.005 to prevent showing Charge or Discharge if value is e.g. 0.00232138 if (value < -0.005) { - label += ' ' + translate.instant('General.chargePower'); + label += " " + translate.instant("General.chargePower"); } else if (value > 0.005) { - label += ' ' + translate.instant('General.dischargePower'); + label += " " + translate.instant("General.dischargePower"); } - return label + ": " + formatNumber(value, 'de', '1.0-2') + " kW"; + return label + ": " + formatNumber(value, "de", "1.0-2") + " kW"; }; } } diff --git a/ui/src/app/edge/history/storage/widget.component.ts b/ui/src/app/edge/history/storage/widget.component.ts index 57987a5ca63..9e4b95790f8 100644 --- a/ui/src/app/edge/history/storage/widget.component.ts +++ b/ui/src/app/edge/history/storage/widget.component.ts @@ -1,14 +1,14 @@ // @ts-strict-ignore -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, Utils } from '../../../shared/shared'; -import { AbstractHistoryWidget } from '../abstracthistorywidget'; +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, Utils } from "../../../shared/shared"; +import { AbstractHistoryWidget } from "../abstracthistorywidget"; @Component({ selector: StorageComponent.SELECTOR, - templateUrl: './widget.component.html', + templateUrl: "./widget.component.html", }) export class StorageComponent extends AbstractHistoryWidget implements OnInit, OnChanges, OnDestroy { @@ -31,7 +31,7 @@ export class StorageComponent extends AbstractHistoryWidget implements OnInit, O } ngOnInit() { - this.service.setCurrentComponent('', this.route).then(response => { + this.service.getCurrentEdge().then(response => { this.edge = response; }); } @@ -60,8 +60,8 @@ export class StorageComponent extends AbstractHistoryWidget implements OnInit, O return new Promise((resolve) => { const channels: ChannelAddress[] = []; channels.push( - new ChannelAddress('_sum', 'EssDcChargeEnergy'), - new ChannelAddress('_sum', 'EssDcDischargeEnergy'), + new ChannelAddress("_sum", "EssDcChargeEnergy"), + new ChannelAddress("_sum", "EssDcDischargeEnergy"), ); resolve(channels); }); diff --git a/ui/src/app/edge/live/Controller/Channelthreshold/Channelthreshold.ts b/ui/src/app/edge/live/Controller/Channelthreshold/Channelthreshold.ts index f4e1909afe6..e33b705a5a7 100644 --- a/ui/src/app/edge/live/Controller/Channelthreshold/Channelthreshold.ts +++ b/ui/src/app/edge/live/Controller/Channelthreshold/Channelthreshold.ts @@ -1,26 +1,26 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; -import { Icon } from 'src/app/shared/type/widget'; +import { Component } from "@angular/core"; +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; +import { Icon } from "src/app/shared/type/widget"; -import { ChannelAddress, CurrentData } from '../../../../shared/shared'; +import { ChannelAddress, CurrentData } from "../../../../shared/shared"; @Component({ - selector: 'Controller_Channelthreshold', - templateUrl: './Channelthreshold.html', + selector: "Controller_Channelthreshold", + templateUrl: "./Channelthreshold.html", }) export class Controller_ChannelthresholdComponent extends AbstractFlatWidget { public outputChannel: ChannelAddress; public icon: Icon = { - name: '', - size: 'large', - color: 'dark', + name: "", + size: "large", + color: "dark", }; - public state: string = '?'; + public state: string = "?"; protected override getChannelAddresses() { - this.outputChannel = ChannelAddress.fromString(this.component.properties['outputChannelAddress']); + this.outputChannel = ChannelAddress.fromString(this.component.properties["outputChannelAddress"]); return [this.outputChannel]; } protected override onCurrentData(currentData: CurrentData) { @@ -28,13 +28,13 @@ export class Controller_ChannelthresholdComponent extends AbstractFlatWidget { if (channel != null) { if (channel == 1) { this.icon.name = "radio-button-on-outline"; - this.state = this.translate.instant('General.on'); + this.state = this.translate.instant("General.on"); } else if (channel == 0) { - this.icon.name = 'radio-button-off-outline'; - this.state = this.translate.instant('General.off'); + this.icon.name = "radio-button-off-outline"; + this.state = this.translate.instant("General.off"); } } else { - this.icon.name = 'help-outline'; + this.icon.name = "help-outline"; } } } diff --git a/ui/src/app/edge/live/Controller/ChpSoc/ChpSoc.ts b/ui/src/app/edge/live/Controller/ChpSoc/ChpSoc.ts index 9a56102cea6..48adf7600d5 100644 --- a/ui/src/app/edge/live/Controller/ChpSoc/ChpSoc.ts +++ b/ui/src/app/edge/live/Controller/ChpSoc/ChpSoc.ts @@ -1,18 +1,18 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; -import { Icon } from 'src/app/shared/type/widget'; +import { Component } from "@angular/core"; +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; +import { Icon } from "src/app/shared/type/widget"; -import { ChannelAddress, CurrentData } from '../../../../shared/shared'; -import { Controller_ChpSocModalComponent } from './modal/modal.component'; +import { ChannelAddress, CurrentData } from "../../../../shared/shared"; +import { Controller_ChpSocModalComponent } from "./modal/modal.component"; @Component({ - selector: 'Controller_ChpSocComponent', - templateUrl: './ChpSoc.html', + selector: "Controller_ChpSocComponent", + templateUrl: "./ChpSoc.html", }) export class Controller_ChpSocComponent extends AbstractFlatWidget { - private static PROPERTY_MODE: string = '_PropertyMode'; + private static PROPERTY_MODE: string = "_PropertyMode"; public inputChannel: ChannelAddress | null = null; public outputChannel: ChannelAddress | null = null; public propertyModeChannel: ChannelAddress | null = null; @@ -23,9 +23,9 @@ export class Controller_ChpSocComponent extends AbstractFlatWidget { public modeChannelValue: string; public inputChannelValue: number; public icon: Icon = { - name: '', - size: 'large', - color: 'primary', + name: "", + size: "large", + color: "primary", }; async presentModal() { @@ -43,16 +43,16 @@ export class Controller_ChpSocComponent extends AbstractFlatWidget { protected override getChannelAddresses() { this.outputChannel = ChannelAddress.fromString( - this.component.properties['outputChannelAddress']); + this.component.properties["outputChannelAddress"]); this.inputChannel = ChannelAddress.fromString( - this.component.properties['inputChannelAddress']); + this.component.properties["inputChannelAddress"]); this.propertyModeChannel = new ChannelAddress(this.component.id, Controller_ChpSocComponent.PROPERTY_MODE); return [ this.outputChannel, this.inputChannel, this.propertyModeChannel, - new ChannelAddress(this.component.id, '_PropertyHighThreshold'), - new ChannelAddress(this.component.id, '_PropertyLowThreshold'), + new ChannelAddress(this.component.id, "_PropertyHighThreshold"), + new ChannelAddress(this.component.id, "_PropertyLowThreshold"), ]; } @@ -61,31 +61,31 @@ export class Controller_ChpSocComponent extends AbstractFlatWidget { // Mode this.modeChannelValue = currentData.allComponents[this.propertyModeChannel.toString()]; switch (this.modeChannelValue) { - case 'ON': - this.mode = this.translate.instant('General.on'); + case "ON": + this.mode = this.translate.instant("General.on"); break; - case 'OFF': - this.mode = this.translate.instant('General.off'); + case "OFF": + this.mode = this.translate.instant("General.off"); break; - case 'AUTOMATIC': - this.mode = this.translate.instant('General.automatic'); + case "AUTOMATIC": + this.mode = this.translate.instant("General.automatic"); } const outputChannelValue = currentData.allComponents[this.outputChannel.toString()]; switch (outputChannelValue) { case 0: - this.state = this.translate.instant('General.inactive'); - this.icon.name == 'help-outline'; + this.state = this.translate.instant("General.inactive"); + this.icon.name == "help-outline"; break; case 1: - this.state = this.translate.instant('General.active'); + this.state = this.translate.instant("General.active"); break; } this.inputChannelValue = currentData.allComponents[this.inputChannel.toString()]; - this.highThresholdValue = currentData.allComponents[this.component.id + '/_PropertyHighThreshold']; - this.lowThresholdValue = currentData.allComponents[this.component.id + '/_PropertyLowThreshold']; + this.highThresholdValue = currentData.allComponents[this.component.id + "/_PropertyHighThreshold"]; + this.lowThresholdValue = currentData.allComponents[this.component.id + "/_PropertyLowThreshold"]; } } diff --git a/ui/src/app/edge/live/Controller/ChpSoc/modal/modal.component.ts b/ui/src/app/edge/live/Controller/ChpSoc/modal/modal.component.ts index 636e1265b75..0c557361d5a 100644 --- a/ui/src/app/edge/live/Controller/ChpSoc/modal/modal.component.ts +++ b/ui/src/app/edge/live/Controller/ChpSoc/modal/modal.component.ts @@ -1,17 +1,17 @@ // @ts-strict-ignore -import { Component, Input, OnInit } from '@angular/core'; -import { Router } from '@angular/router'; -import { ModalController } from '@ionic/angular'; -import { RangeValue } from '@ionic/core'; -import { TranslateService } from '@ngx-translate/core'; -import { ChannelAddress, Edge, EdgeConfig, Service, Websocket } from 'src/app/shared/shared'; +import { Component, Input, OnInit } from "@angular/core"; +import { Router } from "@angular/router"; +import { ModalController } from "@ionic/angular"; +import { RangeValue } from "@ionic/core"; +import { TranslateService } from "@ngx-translate/core"; +import { ChannelAddress, Edge, EdgeConfig, Service, Websocket } from "src/app/shared/shared"; -type mode = 'MANUAL_ON' | 'MANUAL_OFF' | 'AUTOMATIC'; +type mode = "MANUAL_ON" | "MANUAL_OFF" | "AUTOMATIC"; @Component({ selector: Controller_ChpSocModalComponent.SELECTOR, - templateUrl: './modal.component.html', + templateUrl: "./modal.component.html", }) export class Controller_ChpSocModalComponent implements OnInit { @@ -36,8 +36,8 @@ export class Controller_ChpSocModalComponent implements OnInit { ) { } ngOnInit() { - this.thresholds['lower'] = this.component.properties['lowThreshold']; - this.thresholds['upper'] = this.component.properties['highThreshold']; + this.thresholds["lower"] = this.component.properties["lowThreshold"]; + this.thresholds["upper"] = this.component.properties["highThreshold"]; } /** @@ -50,26 +50,26 @@ export class Controller_ChpSocModalComponent implements OnInit { let newMode: mode; switch (event.detail.value) { - case 'MANUAL_ON': - newMode = 'MANUAL_ON'; + case "MANUAL_ON": + newMode = "MANUAL_ON"; break; - case 'MANUAL_OFF': - newMode = 'MANUAL_OFF'; + case "MANUAL_OFF": + newMode = "MANUAL_OFF"; break; - case 'AUTOMATIC': - newMode = 'AUTOMATIC'; + case "AUTOMATIC": + newMode = "AUTOMATIC"; break; } if (this.edge != null) { this.edge.updateComponentConfig(this.websocket, this.component.id, [ - { name: 'mode', value: newMode }, + { name: "mode", value: newMode }, ]).then(() => { this.component.properties.mode = newMode; - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); + this.service.toast(this.translate.instant("General.changeAccepted"), "success"); }).catch(reason => { this.component.properties.mode = oldMode; - this.service.toast(this.translate.instant('General.changeFailed') + '\n' + reason.error.message, 'danger'); + this.service.toast(this.translate.instant("General.changeFailed") + "\n" + reason.error.message, "danger"); console.warn(reason); }); } @@ -81,25 +81,25 @@ export class Controller_ChpSocModalComponent implements OnInit { * @param event */ updateThresholds() { - const oldLowerThreshold = this.component.properties['lowThreshold']; - const oldUpperThreshold = this.component.properties['highThreshold']; + const oldLowerThreshold = this.component.properties["lowThreshold"]; + const oldUpperThreshold = this.component.properties["highThreshold"]; - const newLowerThreshold = this.thresholds['lower']; - const newUpperThreshold = this.thresholds['upper']; + const newLowerThreshold = this.thresholds["lower"]; + const newUpperThreshold = this.thresholds["upper"]; // prevents automatic update when no values have changed if (this.edge != null && (oldLowerThreshold != newLowerThreshold || oldUpperThreshold != newUpperThreshold)) { this.edge.updateComponentConfig(this.websocket, this.component.id, [ - { name: 'lowThreshold', value: newLowerThreshold }, - { name: 'highThreshold', value: newUpperThreshold }, + { name: "lowThreshold", value: newLowerThreshold }, + { name: "highThreshold", value: newUpperThreshold }, ]).then(() => { - this.component.properties['lowThreshold'] = newLowerThreshold; - this.component.properties['highThreshold'] = newUpperThreshold; - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); + this.component.properties["lowThreshold"] = newLowerThreshold; + this.component.properties["highThreshold"] = newUpperThreshold; + this.service.toast(this.translate.instant("General.changeAccepted"), "success"); }).catch(reason => { - this.component.properties['lowThreshold'] = oldLowerThreshold; - this.component.properties['highThreshold'] = oldUpperThreshold; - this.service.toast(this.translate.instant('General.changeFailed') + '\n' + reason.error.message, 'danger'); + this.component.properties["lowThreshold"] = oldLowerThreshold; + this.component.properties["highThreshold"] = oldUpperThreshold; + this.service.toast(this.translate.instant("General.changeFailed") + "\n" + reason.error.message, "danger"); console.warn(reason); }); } diff --git a/ui/src/app/edge/live/Controller/Ess/FixActivePower/Ess_FixActivePower.ts b/ui/src/app/edge/live/Controller/Ess/FixActivePower/Ess_FixActivePower.ts index 471d2ee863d..b22ff209e54 100644 --- a/ui/src/app/edge/live/Controller/Ess/FixActivePower/Ess_FixActivePower.ts +++ b/ui/src/app/edge/live/Controller/Ess/FixActivePower/Ess_FixActivePower.ts @@ -1,8 +1,8 @@ -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 { 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"; @NgModule({ imports: [ 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 fd80147f88a..73429cc8694 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 @@ -1,14 +1,14 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; -import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; -import { ChannelAddress, CurrentData, Utils } from 'src/app/shared/shared'; +import { Component } from "@angular/core"; +import { AbstractFlatWidget } from "src/app/shared/components/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'; +import { ModalComponent } from "../modal/modal"; @Component({ - selector: 'Controller_Ess_FixActivePower', - templateUrl: './flat.html', + selector: "Controller_Ess_FixActivePower", + templateUrl: "./flat.html", }) export class FlatComponent extends AbstractFlatWidget { @@ -39,8 +39,8 @@ export class FlatComponent extends AbstractFlatWidget { } protected override onCurrentData(currentData: CurrentData) { - this.chargeDischargePower = Utils.convertChargeDischargePower(this.translate, currentData.allComponents[this.component.id + '/_PropertyPower']); - this.propertyMode = currentData.allComponents[this.component.id + '/_PropertyMode']; + this.chargeDischargePower = Utils.convertChargeDischargePower(this.translate, currentData.allComponents[this.component.id + "/_PropertyPower"]); + this.propertyMode = currentData.allComponents[this.component.id + "/_PropertyMode"]; } } diff --git a/ui/src/app/edge/live/Controller/Ess/FixActivePower/modal/modal.ts b/ui/src/app/edge/live/Controller/Ess/FixActivePower/modal/modal.ts index 9653441e6e6..8e1c941963a 100644 --- a/ui/src/app/edge/live/Controller/Ess/FixActivePower/modal/modal.ts +++ b/ui/src/app/edge/live/Controller/Ess/FixActivePower/modal/modal.ts @@ -1,11 +1,11 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { FormControl, FormGroup } from '@angular/forms'; -import { AbstractModal } from 'src/app/shared/components/modal/abstractModal'; -import { ChannelAddress, CurrentData, Utils } from 'src/app/shared/shared'; +import { Component } from "@angular/core"; +import { FormControl, FormGroup } from "@angular/forms"; +import { AbstractModal } from "src/app/shared/components/modal/abstractModal"; +import { ChannelAddress, CurrentData, Utils } from "src/app/shared/shared"; @Component({ - templateUrl: './modal.html', + templateUrl: "./modal.html", }) export class ModalComponent extends AbstractModal { @@ -21,7 +21,7 @@ export class ModalComponent extends AbstractModal { } protected override onCurrentData(currentData: CurrentData) { - this.chargeDischargePower = Utils.convertChargeDischargePower(this.translate, currentData.allComponents[this.component.id + '/_PropertyPower']); + this.chargeDischargePower = Utils.convertChargeDischargePower(this.translate, currentData.allComponents[this.component.id + "/_PropertyPower"]); } protected override getFormGroup(): FormGroup { diff --git a/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/Ess_GridOptimizedCharge.ts b/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/Ess_GridOptimizedCharge.ts index 90c1bb531b7..71b80fdeab9 100644 --- a/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/Ess_GridOptimizedCharge.ts +++ b/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/Ess_GridOptimizedCharge.ts @@ -1,9 +1,9 @@ -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 { PredictionChartComponent } from './modal/predictionChart'; +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 { PredictionChartComponent } from "./modal/predictionChart"; @NgModule({ imports: [ 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 27f56312580..6ba344dd692 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 @@ -1,19 +1,19 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; -import { ChannelAddress, CurrentData, EdgeConfig, Utils } from 'src/app/shared/shared'; +import { Component } from "@angular/core"; +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; +import { ChannelAddress, CurrentData, EdgeConfig, Utils } from "src/app/shared/shared"; -import { ModalComponent } from '../modal/modal'; +import { ModalComponent } from "../modal/modal"; @Component({ - selector: 'Controller_Ess_GridOptimizedCharge', - templateUrl: './flat.html', + selector: "Controller_Ess_GridOptimizedCharge", + templateUrl: "./flat.html", }) export class FlatComponent extends AbstractFlatWidget { public override component: EdgeConfig.Component | null = null; - public mode: string = '-'; - public state: string = '-'; + public mode: string = "-"; + public state: string = "-"; public isSellToGridLimitAvoided: boolean = false; public sellToGridLimitMinimumChargeLimit: boolean = false; public delayChargeMaximumChargeLimit: number | null = null; @@ -40,46 +40,46 @@ export class FlatComponent extends AbstractFlatWidget { ]; } protected override onCurrentData(currentData: CurrentData) { - this.mode = currentData.allComponents[this.component.id + '/_PropertyMode']; + this.mode = currentData.allComponents[this.component.id + "/_PropertyMode"]; // Check if Grid feed in limitation is avoided - if (currentData.allComponents[this.component.id + '/SellToGridLimitState'] == 0 || - (currentData.allComponents[this.component.id + '/SellToGridLimitState'] == 3 - && currentData.allComponents[this.component.id + '/DelayChargeState'] != 0 - && currentData.allComponents[this.component.id + '/SellToGridLimitMinimumChargeLimit'] > 0)) { + if (currentData.allComponents[this.component.id + "/SellToGridLimitState"] == 0 || + (currentData.allComponents[this.component.id + "/SellToGridLimitState"] == 3 + && currentData.allComponents[this.component.id + "/DelayChargeState"] != 0 + && currentData.allComponents[this.component.id + "/SellToGridLimitMinimumChargeLimit"] > 0)) { this.isSellToGridLimitAvoided = true; } - this.sellToGridLimitMinimumChargeLimit = currentData.allComponents[this.component.id + '/SellToGridLimitMinimumChargeLimit']; + this.sellToGridLimitMinimumChargeLimit = currentData.allComponents[this.component.id + "/SellToGridLimitMinimumChargeLimit"]; - switch (currentData.allComponents[this.component.id + '/DelayChargeState']) { + switch (currentData.allComponents[this.component.id + "/DelayChargeState"]) { case -1: - this.state = this.translate.instant('Edge.Index.Widgets.GridOptimizedCharge.State.notDefined'); + this.state = this.translate.instant("Edge.Index.Widgets.GridOptimizedCharge.State.notDefined"); break; case 0: - this.state = this.translate.instant('Edge.Index.Widgets.GridOptimizedCharge.State.chargeLimitActive'); + this.state = this.translate.instant("Edge.Index.Widgets.GridOptimizedCharge.State.chargeLimitActive"); break; case 1: - this.state = this.translate.instant('Edge.Index.Widgets.GridOptimizedCharge.State.passedEndTime'); + this.state = this.translate.instant("Edge.Index.Widgets.GridOptimizedCharge.State.passedEndTime"); break; case 2: - this.state = this.translate.instant('Edge.Index.Widgets.GridOptimizedCharge.State.storageAlreadyFull'); + this.state = this.translate.instant("Edge.Index.Widgets.GridOptimizedCharge.State.storageAlreadyFull"); break; case 3: - this.state = this.translate.instant('Edge.Index.Widgets.GridOptimizedCharge.State.endTimeNotCalculated'); + this.state = this.translate.instant("Edge.Index.Widgets.GridOptimizedCharge.State.endTimeNotCalculated"); break; case 4: - this.state = this.translate.instant('Edge.Index.Widgets.GridOptimizedCharge.State.noLimitPossible'); + this.state = this.translate.instant("Edge.Index.Widgets.GridOptimizedCharge.State.noLimitPossible"); break; case 5: case 7: - this.state = this.translate.instant('Edge.Index.Widgets.GridOptimizedCharge.State.noLimitActive'); + this.state = this.translate.instant("Edge.Index.Widgets.GridOptimizedCharge.State.noLimitActive"); break; - case 8: this.state = this.translate.instant('Edge.Index.Widgets.GridOptimizedCharge.chargingDelayed'); + case 8: this.state = this.translate.instant("Edge.Index.Widgets.GridOptimizedCharge.chargingDelayed"); break; } - this.delayChargeMaximumChargeLimit = currentData.allComponents[this.component.id + '/DelayChargeMaximumChargeLimit']; + this.delayChargeMaximumChargeLimit = currentData.allComponents[this.component.id + "/DelayChargeMaximumChargeLimit"]; } } diff --git a/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/modal/modal.ts b/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/modal/modal.ts index 07343c6befa..c13073bbc2a 100644 --- a/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/modal/modal.ts +++ b/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/modal/modal.ts @@ -1,12 +1,12 @@ // @ts-strict-ignore -import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { FormControl, FormGroup, Validators } from '@angular/forms'; -import { AbstractModal } from 'src/app/shared/components/modal/abstractModal'; -import { ChannelAddress, CurrentData, Utils } from 'src/app/shared/shared'; -import { Role } from 'src/app/shared/type/role'; +import { ChangeDetectionStrategy, Component } from "@angular/core"; +import { FormControl, FormGroup, Validators } from "@angular/forms"; +import { AbstractModal } from "src/app/shared/components/modal/abstractModal"; +import { ChannelAddress, CurrentData, Utils } from "src/app/shared/shared"; +import { Role } from "src/app/shared/type/role"; @Component({ - templateUrl: './modal.html', + templateUrl: "./modal.html", changeDetection: ChangeDetectionStrategy.OnPush, }) export class ModalComponent extends AbstractModal { @@ -19,7 +19,7 @@ export class ModalComponent extends AbstractModal { public readonly CONVERT_MINUTE_TO_TIME_OF_DAY = Utils.CONVERT_MINUTE_TO_TIME_OF_DAY(this.translate); public readonly CONVERT_TO_WATTHOURS = Utils.CONVERT_TO_WATTHOURS; public readonly DelayChargeState = DelayChargeState; - public state: string = ''; + public state: string = ""; public chargeLimit: { name: string, value: number }; public delayChargeState: number | null = null; public maximumSellToGridPower: number | null = null; @@ -33,9 +33,9 @@ export class ModalComponent extends AbstractModal { const channels: ChannelAddress[] = []; if (this.edge.roleIsAtLeast(Role.ADMIN)) { this.isAtLeastAdmin = true; - if ('ess.id' in this.component.properties) { + if ("ess.id" in this.component.properties) { channels.push( - new ChannelAddress(this.component.properties['ess.id'], "Capacity"), + new ChannelAddress(this.component.properties["ess.id"], "Capacity"), ); } } @@ -56,60 +56,60 @@ export class ModalComponent extends AbstractModal { protected override onCurrentData(currentData: CurrentData) { // If the gridfeed in Limit is avoided - if (currentData.allComponents[this.component.id + '/SellToGridLimitState'] == SellToGridLimitState.ACTIVE_LIMIT_FIXED || - (currentData.allComponents[this.component.id + '/SellToGridLimitState'] == SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT && - currentData.allComponents[this.component.id + '/DelayChargeState'] != DelayChargeState.ACTIVE_LIMIT && - currentData.allComponents[this.component.id + '/SellToGridLimitMinimumChargeLimit'] > 0)) { + if (currentData.allComponents[this.component.id + "/SellToGridLimitState"] == SellToGridLimitState.ACTIVE_LIMIT_FIXED || + (currentData.allComponents[this.component.id + "/SellToGridLimitState"] == SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT && + currentData.allComponents[this.component.id + "/DelayChargeState"] != DelayChargeState.ACTIVE_LIMIT && + currentData.allComponents[this.component.id + "/SellToGridLimitMinimumChargeLimit"] > 0)) { this.chargeLimit = { - name: this.translate.instant('Edge.Index.Widgets.GridOptimizedCharge.minimumCharge'), - value: currentData.allComponents[this.component.id + '/SellToGridLimitMinimumChargeLimit'], + name: this.translate.instant("Edge.Index.Widgets.GridOptimizedCharge.minimumCharge"), + value: currentData.allComponents[this.component.id + "/SellToGridLimitMinimumChargeLimit"], }; - this.state = this.translate.instant('Edge.Index.Widgets.GridOptimizedCharge.State.gridFeedInLimitationIsAvoided'); + this.state = this.translate.instant("Edge.Index.Widgets.GridOptimizedCharge.State.gridFeedInLimitationIsAvoided"); } else { // DelayCharge State - switch (currentData.allComponents[this.component.id + '/DelayChargeState']) { - case -1: this.state = this.translate.instant('Edge.Index.Widgets.GridOptimizedCharge.State.notDefined'); + switch (currentData.allComponents[this.component.id + "/DelayChargeState"]) { + case -1: this.state = this.translate.instant("Edge.Index.Widgets.GridOptimizedCharge.State.notDefined"); break; - case 0: this.state = this.translate.instant('Edge.Index.Widgets.GridOptimizedCharge.State.chargeLimitActive'); + case 0: this.state = this.translate.instant("Edge.Index.Widgets.GridOptimizedCharge.State.chargeLimitActive"); break; - case 1: this.state = this.translate.instant('Edge.Index.Widgets.GridOptimizedCharge.State.passedEndTime'); + case 1: this.state = this.translate.instant("Edge.Index.Widgets.GridOptimizedCharge.State.passedEndTime"); break; - case 2: this.state = this.translate.instant('Edge.Index.Widgets.GridOptimizedCharge.State.storageAlreadyFull'); + case 2: this.state = this.translate.instant("Edge.Index.Widgets.GridOptimizedCharge.State.storageAlreadyFull"); break; - case 3: this.state = this.translate.instant('Edge.Index.Widgets.GridOptimizedCharge.State.endTimeNotCalculated'); + case 3: this.state = this.translate.instant("Edge.Index.Widgets.GridOptimizedCharge.State.endTimeNotCalculated"); break; - case 4: this.state = this.translate.instant('Edge.Index.Widgets.GridOptimizedCharge.State.noLimitPossible'); + case 4: this.state = this.translate.instant("Edge.Index.Widgets.GridOptimizedCharge.State.noLimitPossible"); break; case 5: // Case 6: 'DISABLED' hides 'state-line', so no Message needed - case 7: this.state = this.translate.instant('Edge.Index.Widgets.GridOptimizedCharge.State.noLimitActive'); + case 7: this.state = this.translate.instant("Edge.Index.Widgets.GridOptimizedCharge.State.noLimitActive"); break; - case 8: this.state = this.translate.instant('Edge.Index.Widgets.GridOptimizedCharge.chargingDelayed'); + case 8: this.state = this.translate.instant("Edge.Index.Widgets.GridOptimizedCharge.chargingDelayed"); break; } // DelayCharge Maximum Charge Limit - if (currentData.allComponents[this.component.id + '/DelayChargeMaximumChargeLimit'] != null) { + if (currentData.allComponents[this.component.id + "/DelayChargeMaximumChargeLimit"] != null) { this.chargeLimit = { - name: this.translate.instant('Edge.Index.Widgets.GridOptimizedCharge.maximumCharge'), - value: currentData.allComponents[this.component.id + '/DelayChargeMaximumChargeLimit'], + name: this.translate.instant("Edge.Index.Widgets.GridOptimizedCharge.maximumCharge"), + value: currentData.allComponents[this.component.id + "/DelayChargeMaximumChargeLimit"], }; } } - this.delayChargeState = currentData.allComponents[this.component.id + '/DelayChargeState']; + this.delayChargeState = currentData.allComponents[this.component.id + "/DelayChargeState"]; // Capacity (visible for admin only) - if (this.edge.roleIsAtLeast(Role.ADMIN) && 'ess.id' in this.component.properties) { - this.channelCapacity = currentData.allComponents[this.component.properties['ess.id'] + '/Capacity']; + if (this.edge.roleIsAtLeast(Role.ADMIN) && "ess.id" in this.component.properties) { + this.channelCapacity = currentData.allComponents[this.component.properties["ess.id"] + "/Capacity"]; } - this.maximumSellToGridPower = currentData.allComponents[this.component.id + '/_PropertyMaximumSellToGridPower']; - this.targetMinute = currentData.allComponents[this.component.id + '/TargetMinute']; - this.delayChargeMaximumChargeLimit = currentData.allComponents[this.component.id + '/DelayChargeMaximumChargeLimit']; - this.targetEpochSeconds = currentData.allComponents[this.component.id + '/TargetEpochSeconds']; - this.chargeStartEpochSeconds = currentData.allComponents[this.component.id + '/PredictedChargeStartEpochSeconds']; + this.maximumSellToGridPower = currentData.allComponents[this.component.id + "/_PropertyMaximumSellToGridPower"]; + this.targetMinute = currentData.allComponents[this.component.id + "/TargetMinute"]; + this.delayChargeMaximumChargeLimit = currentData.allComponents[this.component.id + "/DelayChargeMaximumChargeLimit"]; + this.targetEpochSeconds = currentData.allComponents[this.component.id + "/TargetEpochSeconds"]; + this.chargeStartEpochSeconds = currentData.allComponents[this.component.id + "/PredictedChargeStartEpochSeconds"]; } protected override getFormGroup(): FormGroup { @@ -117,7 +117,7 @@ export class ModalComponent extends AbstractModal { mode: new FormControl(this.component.properties.mode), sellToGridLimitEnabled: new FormControl(this.component.properties.sellToGridLimitEnabled), maximumSellToGridPower: new FormControl(this.component.properties.maximumSellToGridPower, Validators.compose([ - Validators.pattern('^(?:[1-9][0-9]*|0)$'), + Validators.pattern("^(?:[1-9][0-9]*|0)$"), Validators.required, ])), delayChargeRiskLevel: new FormControl(this.component.properties.delayChargeRiskLevel), 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 f058c8b2480..15ff02bd65f 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 @@ -1,17 +1,17 @@ // @ts-strict-ignore -import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { TranslateService } from '@ngx-translate/core'; -import * as Chart from 'chart.js'; -import { AbstractHistoryChart } from 'src/app/edge/history/abstracthistorychart'; -import { ChronoUnit, DEFAULT_TIME_CHART_OPTIONS } from 'src/app/edge/history/shared'; -import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; -import { ChartAxis, YAxisTitle } from 'src/app/shared/service/utils'; -import { ChannelAddress, Edge, EdgeConfig, Service, Utils } from 'src/app/shared/shared'; +import { Component, Input, OnChanges, OnDestroy, OnInit } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { TranslateService } from "@ngx-translate/core"; +import * as Chart from "chart.js"; +import { AbstractHistoryChart } from "src/app/edge/history/abstracthistorychart"; +import { ChronoUnit, DEFAULT_TIME_CHART_OPTIONS } from "src/app/edge/history/shared"; +import { DefaultTypes } from "src/app/shared/service/defaulttypes"; +import { ChartAxis, YAxisType } from "src/app/shared/service/utils"; +import { ChannelAddress, Edge, EdgeConfig, Service, Utils } from "src/app/shared/shared"; @Component({ - selector: 'predictionChart', - templateUrl: '../../../../../history/abstracthistorychart.html', + selector: "predictionChart", + templateUrl: "../../../../../history/abstracthistorychart.html", }) export class PredictionChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { @@ -37,7 +37,6 @@ export class PredictionChartComponent extends AbstractHistoryChart implements On ngOnInit() { this.service.startSpinner(this.spinnerId); - this.service.setCurrentComponent('', this.route); } ngOnDestroy() { @@ -69,9 +68,9 @@ export class PredictionChartComponent extends AbstractHistoryChart implements On startIndex = startIndex < 0 ? 0 : startIndex; // Calculate soc and predicted soc data - if ('_sum/EssSoc' in result.data) { + if ("_sum/EssSoc" in result.data) { - const socData = result.data['_sum/EssSoc'].map(value => { + const socData = result.data["_sum/EssSoc"].map(value => { if (value == null) { return null; } else if (value > 100 || value < 0) { @@ -152,7 +151,7 @@ export class PredictionChartComponent extends AbstractHistoryChart implements On const chartEndIndex = targetIndex + 12; // Remove unimportant values that are after the end index - if (chartEndIndex < result.data['_sum/EssSoc'].length - 1) { + if (chartEndIndex < result.data["_sum/EssSoc"].length - 1) { socData.splice(chartEndIndex + 1, socData.length); predictedSocData.splice(chartEndIndex + 1, predictedSocData.length); result.timestamps.splice(chartEndIndex + 1, result.timestamps.length); @@ -175,12 +174,12 @@ export class PredictionChartComponent extends AbstractHistoryChart implements On // Push the prepared data into the datasets datasets.push({ - label: this.translate.instant('General.soc'), + label: this.translate.instant("General.soc"), data: socData, hidden: false, yAxisID: ChartAxis.RIGHT, }, { - label: this.translate.instant('Edge.Index.Widgets.GridOptimizedCharge.expectedSoc'), + label: this.translate.instant("Edge.Index.Widgets.GridOptimizedCharge.expectedSoc"), data: predictedSocData, hidden: false, yAxisID: ChartAxis.RIGHT, @@ -188,19 +187,19 @@ export class PredictionChartComponent extends AbstractHistoryChart implements On // Push the depending colors this.colors.push({ - backgroundColor: 'rgba(189, 195, 199,0.05)', - borderColor: 'rgba(189, 195, 199,1)', + backgroundColor: "rgba(189, 195, 199,0.05)", + borderColor: "rgba(189, 195, 199,1)", }, { - backgroundColor: 'rgba(0,223,0,0)', - borderColor: 'rgba(0,223,0,1)', + backgroundColor: "rgba(0,223,0,0)", + borderColor: "rgba(0,223,0,1)", }); } this.datasets = datasets; this.loading = false; this.service.stopSpinner(this.spinnerId); - this.unit = YAxisTitle.PERCENTAGE; - this.formatNumber = '1.0-0'; + this.unit = YAxisType.PERCENTAGE; + this.formatNumber = "1.0-0"; await this.setOptions(this.options); this.applyControllerSpecificOptions(); @@ -219,22 +218,22 @@ export class PredictionChartComponent extends AbstractHistoryChart implements On return new Promise((resolve) => { const result: ChannelAddress[] = [ - new ChannelAddress('_sum', 'EssSoc'), + new ChannelAddress("_sum", "EssSoc"), ]; if (this.component != null && this.component.id) { - result.push(new ChannelAddress(this.component.id, 'DelayChargeMaximumChargeLimit')); + result.push(new ChannelAddress(this.component.id, "DelayChargeMaximumChargeLimit")); } resolve(result); }); } private applyControllerSpecificOptions() { - this.options.scales[ChartAxis.LEFT]['position'] = 'right'; + this.options.scales[ChartAxis.LEFT]["position"] = "right"; this.options.scales.x.ticks.callback = function (value, index, values) { const date = new Date(value); // Display the label only if the minutes are zero (full hour) - return date.getMinutes() === 0 ? date.getHours() + ':00' : ''; + return date.getMinutes() === 0 ? date.getHours() + ":00" : ""; }; } diff --git a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/Ess_TimeOfUseTariff.ts b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/Ess_TimeOfUseTariff.ts index 34ad15b24e1..6757a7d7489 100644 --- a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/Ess_TimeOfUseTariff.ts +++ b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/Ess_TimeOfUseTariff.ts @@ -37,8 +37,8 @@ export namespace Controller_Ess_TimeOfUseTariff { }; export enum ControlMode { - CHARGE_CONSUMPTION = 'CHARGE_CONSUMPTION', - DELAY_DISCHARGE = 'DELAY_DISCHARGE', + CHARGE_CONSUMPTION = "CHARGE_CONSUMPTION", + DELAY_DISCHARGE = "DELAY_DISCHARGE", } /** @@ -89,49 +89,49 @@ export namespace Controller_Ess_TimeOfUseTariff { // Set datasets datasets.push({ - type: 'bar', - label: translate.instant('Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.BALANCING'), + type: "bar", + label: translate.instant("Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.BALANCING"), data: barBalancing, order: 1, }); colors.push({ // Dark Green - backgroundColor: 'rgba(51,102,0,0.8)', - borderColor: 'rgba(51,102,0,1)', + backgroundColor: "rgba(51,102,0,0.8)", + borderColor: "rgba(51,102,0,1)", }); // Set dataset for ChargeGrid. if (!barChargeGrid.every(v => v === null) || controlMode == Controller_Ess_TimeOfUseTariff.ControlMode.CHARGE_CONSUMPTION) { datasets.push({ - type: 'bar', - label: translate.instant('Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.CHARGE_GRID'), + type: "bar", + label: translate.instant("Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.CHARGE_GRID"), data: barChargeGrid, order: 1, }); colors.push({ // Sky blue - backgroundColor: 'rgba(0, 204, 204,0.5)', - borderColor: 'rgba(0, 204, 204,0.7)', + backgroundColor: "rgba(0, 204, 204,0.5)", + borderColor: "rgba(0, 204, 204,0.7)", }); } // Set dataset for buy from grid datasets.push({ - type: 'bar', - label: translate.instant('Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.DELAY_DISCHARGE'), + type: "bar", + label: translate.instant("Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.DELAY_DISCHARGE"), data: barDelayDischarge, order: 1, }); colors.push({ // Black - backgroundColor: 'rgba(0,0,0,0.8)', - borderColor: 'rgba(0,0,0,0.9)', + backgroundColor: "rgba(0,0,0,0.8)", + borderColor: "rgba(0,0,0,0.9)", }); // State of charge data datasets.push({ - type: 'line', - label: translate.instant('General.soc'), + type: "line", + label: translate.instant("General.soc"), data: socArray, hidden: false, yAxisID: ChartAxis.RIGHT, @@ -139,21 +139,21 @@ export namespace Controller_Ess_TimeOfUseTariff { order: 0, }); colors.push({ - backgroundColor: 'rgba(189, 195, 199,0.2)', - borderColor: 'rgba(189, 195, 199,1)', + backgroundColor: "rgba(189, 195, 199,0.2)", + borderColor: "rgba(189, 195, 199,1)", }); datasets.push({ - type: 'line', - label: translate.instant('General.gridBuy'), + type: "line", + label: translate.instant("General.gridBuy"), data: gridBuy.map(v => Utils.divideSafely(v, 1000)), // [W] to [kW] hidden: true, yAxisID: ChartAxis.RIGHT_2, order: 2, }); colors.push({ - backgroundColor: 'rgba(0,0,0, 0.2)', - borderColor: 'rgba(0,0,0, 1)', + backgroundColor: "rgba(0,0,0, 0.2)", + borderColor: "rgba(0,0,0, 1)", }); const scheduleChartData: Controller_Ess_TimeOfUseTariff.ScheduleChartData = { diff --git a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/flat/flat.ts b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/flat/flat.ts index fc6f09c6b4b..66bbb03f543 100644 --- a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/flat/flat.ts +++ b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/flat/flat.ts @@ -1,12 +1,12 @@ -import { Component, OnInit } from '@angular/core'; -import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; -import { ChannelAddress, Currency, CurrentData, Utils } from 'src/app/shared/shared'; +import { Component, OnInit } from "@angular/core"; +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; +import { ChannelAddress, Currency, CurrentData, Utils } from "src/app/shared/shared"; -import { ModalComponent } from '../modal/modal'; +import { ModalComponent } from "../modal/modal"; @Component({ - selector: 'Controller_Ess_TimeOfUseTariff', - templateUrl: './flat.html', + selector: "Controller_Ess_TimeOfUseTariff", + templateUrl: "./flat.html", }) export class FlatComponent extends AbstractFlatWidget implements OnInit { @@ -27,12 +27,12 @@ export class FlatComponent extends AbstractFlatWidget implements OnInit { protected override getChannelAddresses(): ChannelAddress[] { return [ - new ChannelAddress(this.component.id, 'QuarterlyPrices'), + new ChannelAddress(this.component.id, "QuarterlyPrices"), ]; } protected override onCurrentData(currentData: CurrentData): void { - const quarterlyPrice = currentData.allComponents[this.component.id + '/QuarterlyPrices']; + const quarterlyPrice = currentData.allComponents[this.component.id + "/QuarterlyPrices"]; const currencyLabel: string = Currency.getCurrencyLabelByEdgeId(this.edge.id); this.priceWithCurrency = Utils.CONVERT_PRICE_TO_CENT_PER_KWH(2, currencyLabel)(quarterlyPrice); } diff --git a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/modal.ts b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/modal.ts index b4a182fd769..54ccfba47cb 100644 --- a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/modal.ts +++ b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/modal.ts @@ -1,12 +1,12 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { FormControl, FormGroup } from '@angular/forms'; -import { AbstractModal } from 'src/app/shared/components/modal/abstractModal'; -import { ChannelAddress, Currency, CurrentData } from 'src/app/shared/shared'; -import { Controller_Ess_TimeOfUseTariff } from '../Ess_TimeOfUseTariff'; +import { Component } from "@angular/core"; +import { FormControl, FormGroup } from "@angular/forms"; +import { AbstractModal } from "src/app/shared/components/modal/abstractModal"; +import { ChannelAddress, Currency, CurrentData } from "src/app/shared/shared"; +import { Controller_Ess_TimeOfUseTariff } from "../Ess_TimeOfUseTariff"; @Component({ - templateUrl: './modal.html', + templateUrl: "./modal.html", }) export class ModalComponent extends AbstractModal { @@ -23,25 +23,25 @@ export class ModalComponent extends AbstractModal { protected override getChannelAddresses(): ChannelAddress[] { return [ - new ChannelAddress(this.component.id, 'QuarterlyPrices'), + new ChannelAddress(this.component.id, "QuarterlyPrices"), ]; } protected override onIsInitialized(): void { this.subscription.add( - this.formGroup?.get('chargeConsumptionIsActive') + this.formGroup?.get("chargeConsumptionIsActive") .valueChanges .subscribe(isActive => { const controlMode: Controller_Ess_TimeOfUseTariff.ControlMode = isActive ? Controller_Ess_TimeOfUseTariff.ControlMode.CHARGE_CONSUMPTION : Controller_Ess_TimeOfUseTariff.ControlMode.DELAY_DISCHARGE; - this.formGroup.controls['controlMode'].setValue(controlMode); - this.formGroup.controls['controlMode'].markAsDirty(); + this.formGroup.controls["controlMode"].setValue(controlMode); + this.formGroup.controls["controlMode"].markAsDirty(); })); } protected override onCurrentData(currentData: CurrentData): void { - const quarterlyPrice = currentData.allComponents[this.component.id + '/QuarterlyPrices']; + const quarterlyPrice = currentData.allComponents[this.component.id + "/QuarterlyPrices"]; const currencyLabel: string = Currency.getCurrencyLabelByEdgeId(this.edge?.id); this.priceWithCurrency = this.Utils.CONVERT_PRICE_TO_CENT_PER_KWH(2, currencyLabel)(quarterlyPrice); } diff --git a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/powerSocChart.ts b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/powerSocChart.ts index f28a7ee3b36..61e457c6d86 100644 --- a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/powerSocChart.ts +++ b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/powerSocChart.ts @@ -1,20 +1,20 @@ // @ts-strict-ignore -import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { TranslateService } from '@ngx-translate/core'; -import * as Chart from 'chart.js'; -import { AbstractHistoryChart } from 'src/app/edge/history/abstracthistorychart'; -import { AbstractHistoryChart as NewAbstractHistoryChart } from 'src/app/shared/components/chart/abstracthistorychart'; -import { ChartConstants } from 'src/app/shared/components/chart/chart.constants'; -import { ComponentJsonApiRequest } from 'src/app/shared/jsonrpc/request/componentJsonApiRequest'; -import { ChartAxis, HistoryUtils, TimeOfUseTariffUtils, Utils, YAxisTitle } from 'src/app/shared/service/utils'; -import { ChannelAddress, Edge, EdgeConfig, Service, Websocket } from 'src/app/shared/shared'; -import { GetScheduleRequest } from '../../../../../../shared/jsonrpc/request/getScheduleRequest'; -import { GetScheduleResponse } from '../../../../../../shared/jsonrpc/response/getScheduleResponse'; +import { Component, Input, OnChanges, OnDestroy, OnInit } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { TranslateService } from "@ngx-translate/core"; +import * as Chart from "chart.js"; +import { AbstractHistoryChart } from "src/app/edge/history/abstracthistorychart"; +import { AbstractHistoryChart as NewAbstractHistoryChart } from "src/app/shared/components/chart/abstracthistorychart"; +import { ChartConstants } from "src/app/shared/components/chart/chart.constants"; +import { ComponentJsonApiRequest } from "src/app/shared/jsonrpc/request/componentJsonApiRequest"; +import { ChartAxis, HistoryUtils, TimeOfUseTariffUtils, Utils, YAxisType } from "src/app/shared/service/utils"; +import { ChannelAddress, Edge, EdgeConfig, Service, Websocket } from "src/app/shared/shared"; +import { GetScheduleRequest } from "../../../../../../shared/jsonrpc/request/getScheduleRequest"; +import { GetScheduleResponse } from "../../../../../../shared/jsonrpc/response/getScheduleResponse"; @Component({ - selector: 'powerSocChart', - templateUrl: '../../../../../history/abstracthistorychart.html', + selector: "powerSocChart", + templateUrl: "../../../../../history/abstracthistorychart.html", }) export class SchedulePowerAndSocChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { @@ -38,7 +38,6 @@ export class SchedulePowerAndSocChartComponent extends AbstractHistoryChart impl public ngOnInit() { this.service.startSpinner(this.spinnerId); - this.service.setCurrentComponent('', this.route); } public ngOnDestroy() { @@ -52,12 +51,18 @@ export class SchedulePowerAndSocChartComponent extends AbstractHistoryChart impl protected setLabel() { this.options = this.createDefaultChartOptions(); const translate = this.translate; - this.options.plugins.tooltip.callbacks.label = function (item: Chart.TooltipItem) { - - const label = item.dataset.label; - const value = item.dataset.data[item.dataIndex]; - - return TimeOfUseTariffUtils.getLabel(value, label, translate); + this.options.plugins = { + tooltip: { + callbacks: { + label: function (item: Chart.TooltipItem) { + + const label = item.dataset.label; + const value = item.dataset.data[item.dataIndex]; + + return TimeOfUseTariffUtils.getLabel(value, label, translate); + }, + }, + }, }; } @@ -92,93 +97,93 @@ export class SchedulePowerAndSocChartComponent extends AbstractHistoryChart impl }; datasets.push({ - type: 'line', - label: this.translate.instant('General.gridBuy'), + type: "line", + label: this.translate.instant("General.gridBuy"), data: gridBuyArray.map(v => Utils.divideSafely(v, 1000)), // [W] to [kW] hidden: true, order: 1, }); this.colors.push({ - backgroundColor: 'rgba(0,0,0, 0.2)', - borderColor: 'rgba(0,0,0, 1)', + backgroundColor: "rgba(0,0,0, 0.2)", + borderColor: "rgba(0,0,0, 1)", }); datasets.push({ - type: 'line', - label: this.translate.instant('General.gridSell'), + type: "line", + label: this.translate.instant("General.gridSell"), data: gridSellArray.map(v => Utils.divideSafely(v, 1000)), // [W] to [kW] hidden: true, order: 1, }); this.colors.push({ - backgroundColor: 'rgba(0,0,200, 0.2)', - borderColor: 'rgba(0,0,200, 1)', + backgroundColor: "rgba(0,0,200, 0.2)", + borderColor: "rgba(0,0,200, 1)", }); datasets.push({ - type: 'line', - label: this.translate.instant('General.production'), + type: "line", + label: this.translate.instant("General.production"), data: productionArray.map(v => Utils.divideSafely(v, 1000)), // [W] to [kW] hidden: false, order: 1, }); this.colors.push({ - backgroundColor: 'rgba(45,143,171, 0.2)', - borderColor: 'rgba(45,143,171, 1)', + backgroundColor: "rgba(45,143,171, 0.2)", + borderColor: "rgba(45,143,171, 1)", }); datasets.push({ - type: 'line', - label: this.translate.instant('General.consumption'), + type: "line", + label: this.translate.instant("General.consumption"), data: consumptionArray.map(v => Utils.divideSafely(v, 1000)), // [W] to [kW] hidden: false, order: 1, }); this.colors.push({ - backgroundColor: 'rgba(253,197,7,0.2)', - borderColor: 'rgba(253,197,7,1)', + backgroundColor: "rgba(253,197,7,0.2)", + borderColor: "rgba(253,197,7,1)", }); datasets.push({ - type: 'line', - label: this.translate.instant('General.chargePower'), + type: "line", + label: this.translate.instant("General.chargePower"), data: essChargeArray.map(v => Utils.divideSafely(v, 1000)), // [W] to [kW] hidden: true, order: 1, - unit: YAxisTitle.POWER, + unit: YAxisType.POWER, }); this.colors.push({ - backgroundColor: 'rgba(0,223,0, 0.2)', - borderColor: 'rgba(0,223,0, 1)', + backgroundColor: "rgba(0,223,0, 0.2)", + borderColor: "rgba(0,223,0, 1)", }); datasets.push({ - type: 'line', - label: this.translate.instant('General.dischargePower'), + type: "line", + label: this.translate.instant("General.dischargePower"), data: essDischargeArray.map(v => Utils.divideSafely(v, 1000)), // [W] to [kW] hidden: true, order: 1, - unit: YAxisTitle.POWER, + unit: YAxisType.POWER, }); this.colors.push({ - backgroundColor: 'rgba(200,0,0, 0.2)', - borderColor: 'rgba(200,0,0, 1)', + backgroundColor: "rgba(200,0,0, 0.2)", + borderColor: "rgba(200,0,0, 1)", }); // State of charge data datasets.push({ - type: 'line', - label: this.translate.instant('General.soc'), + type: "line", + label: this.translate.instant("General.soc"), data: socArray, hidden: false, yAxisID: ChartAxis.RIGHT, borderDash: [10, 10], order: 1, - unit: YAxisTitle.PERCENTAGE, + unit: YAxisType.PERCENTAGE, }); this.colors.push({ - backgroundColor: 'rgba(189, 195, 199,0.2)', - borderColor: 'rgba(189, 195, 199,1)', + backgroundColor: "rgba(189, 195, 199,0.2)", + borderColor: "rgba(189, 195, 199,1)", }); this.datasets = datasets; @@ -197,28 +202,28 @@ export class SchedulePowerAndSocChartComponent extends AbstractHistoryChart impl } private applyControllerSpecificOptions() { - const rightYAxis: HistoryUtils.yAxes = { position: 'right', unit: YAxisTitle.PERCENTAGE, yAxisId: ChartAxis.RIGHT }; - const leftYAxis: HistoryUtils.yAxes = { position: 'left', unit: YAxisTitle.POWER, yAxisId: ChartAxis.LEFT }; + const rightYAxis: HistoryUtils.yAxes = { position: "right", unit: YAxisType.PERCENTAGE, yAxisId: ChartAxis.RIGHT }; + const leftYAxis: HistoryUtils.yAxes = { position: "left", unit: YAxisType.POWER, yAxisId: ChartAxis.LEFT }; const locale = this.service.translate.currentLang; - this.options = NewAbstractHistoryChart.getYAxisOptions(this.options, rightYAxis, this.translate, 'line', locale, ChartConstants.EMPTY_DATASETS, true); - this.options = NewAbstractHistoryChart.getYAxisOptions(this.options, leftYAxis, this.translate, 'line', locale, ChartConstants.EMPTY_DATASETS, true); + this.options = NewAbstractHistoryChart.getYAxisOptions(this.options, rightYAxis, this.translate, "line", locale, ChartConstants.EMPTY_DATASETS, true); + this.options = NewAbstractHistoryChart.getYAxisOptions(this.options, leftYAxis, this.translate, "line", locale, ChartConstants.EMPTY_DATASETS, true); this.datasets = this.datasets.map((el: Chart.ChartDataset) => { // align particular dataset element to right yAxis - if (el.label === this.translate.instant('General.soc')) { - el['yAxisID'] = ChartAxis.RIGHT; + if (el.label === this.translate.instant("General.soc")) { + el["yAxisID"] = ChartAxis.RIGHT; } return el; }); - this.options.scales.x['ticks'] = { source: 'auto', autoSkip: false }; + this.options.scales.x["ticks"] = { source: "auto", autoSkip: false }; this.options.scales.x.ticks.callback = function (value, index, values) { const date = new Date(value); // Display the label only if the minutes are zero (full hour) - return date.getMinutes() === 0 ? date.getHours() + ':00' : ''; + return date.getMinutes() === 0 ? date.getHours() + ":00" : ""; }; this.options.scales[ChartAxis.RIGHT].grid.display = false; diff --git a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/statePriceChart.ts b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/statePriceChart.ts index a11644b8445..3e690c5828f 100644 --- a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/statePriceChart.ts +++ b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/statePriceChart.ts @@ -1,24 +1,24 @@ // @ts-strict-ignore -import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { TranslateService } from '@ngx-translate/core'; -import * as Chart from 'chart.js'; -import { AbstractHistoryChart } from 'src/app/edge/history/abstracthistorychart'; -import { AbstractHistoryChart as NewAbstractHistoryChart } from 'src/app/shared/components/chart/abstracthistorychart'; -import { ComponentJsonApiRequest } from 'src/app/shared/jsonrpc/request/componentJsonApiRequest'; -import { ChartAxis, HistoryUtils, TimeOfUseTariffUtils, YAxisTitle } from 'src/app/shared/service/utils'; -import { ChannelAddress, Currency, Edge, EdgeConfig, Service, Websocket } from 'src/app/shared/shared'; - -import { calculateResolution } from 'src/app/edge/history/shared'; -import { ChartConstants } from 'src/app/shared/components/chart/chart.constants'; -import { ColorUtils } from 'src/app/shared/utils/color/color.utils'; -import { GetScheduleRequest } from '../../../../../../shared/jsonrpc/request/getScheduleRequest'; -import { GetScheduleResponse } from '../../../../../../shared/jsonrpc/response/getScheduleResponse'; -import { Controller_Ess_TimeOfUseTariff } from '../Ess_TimeOfUseTariff'; +import { Component, Input, OnChanges, OnDestroy, OnInit } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { TranslateService } from "@ngx-translate/core"; +import * as Chart from "chart.js"; +import { AbstractHistoryChart } from "src/app/edge/history/abstracthistorychart"; +import { AbstractHistoryChart as NewAbstractHistoryChart } from "src/app/shared/components/chart/abstracthistorychart"; +import { ComponentJsonApiRequest } from "src/app/shared/jsonrpc/request/componentJsonApiRequest"; +import { ChartAxis, HistoryUtils, TimeOfUseTariffUtils, YAxisType } from "src/app/shared/service/utils"; +import { ChannelAddress, Currency, Edge, EdgeConfig, Service, Websocket } from "src/app/shared/shared"; + +import { calculateResolution } from "src/app/edge/history/shared"; +import { ChartConstants } from "src/app/shared/components/chart/chart.constants"; +import { ColorUtils } from "src/app/shared/utils/color/color.utils"; +import { GetScheduleRequest } from "../../../../../../shared/jsonrpc/request/getScheduleRequest"; +import { GetScheduleResponse } from "../../../../../../shared/jsonrpc/response/getScheduleResponse"; +import { Controller_Ess_TimeOfUseTariff } from "../Ess_TimeOfUseTariff"; @Component({ - selector: 'statePriceChart', - templateUrl: '../../../../../history/abstracthistorychart.html', + selector: "statePriceChart", + templateUrl: "../../../../../history/abstracthistorychart.html", }) export class ScheduleStateAndPriceChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { @@ -48,7 +48,6 @@ export class ScheduleStateAndPriceChartComponent extends AbstractHistoryChart im public ngOnInit() { this.service.startSpinner(this.spinnerId); - this.service.setCurrentComponent('', this.route); } public ngOnDestroy() { @@ -93,7 +92,7 @@ export class ScheduleStateAndPriceChartComponent extends AbstractHistoryChart im return; }).finally(async () => { - this.unit = YAxisTitle.CURRENCY; + this.unit = YAxisType.CURRENCY; await this.setOptions(this.options); this.applyControllerSpecificOptions(); }); @@ -109,25 +108,25 @@ export class ScheduleStateAndPriceChartComponent extends AbstractHistoryChart im private applyControllerSpecificOptions() { const locale = this.service.translate.currentLang; - const rightYaxisSoc: HistoryUtils.yAxes = { position: 'right', unit: YAxisTitle.PERCENTAGE, yAxisId: ChartAxis.RIGHT }; - this.options = NewAbstractHistoryChart.getYAxisOptions(this.options, rightYaxisSoc, this.translate, 'line', locale, ChartConstants.EMPTY_DATASETS); + const rightYaxisSoc: HistoryUtils.yAxes = { position: "right", unit: YAxisType.PERCENTAGE, yAxisId: ChartAxis.RIGHT }; + this.options = NewAbstractHistoryChart.getYAxisOptions(this.options, rightYaxisSoc, this.translate, "line", locale, ChartConstants.EMPTY_DATASETS); - const rightYAxisPower: HistoryUtils.yAxes = { position: 'right', unit: YAxisTitle.POWER, yAxisId: ChartAxis.RIGHT_2 }; - this.options = NewAbstractHistoryChart.getYAxisOptions(this.options, rightYAxisPower, this.translate, 'line', locale, ChartConstants.EMPTY_DATASETS); + const rightYAxisPower: HistoryUtils.yAxes = { position: "right", unit: YAxisType.POWER, yAxisId: ChartAxis.RIGHT_2 }; + this.options = NewAbstractHistoryChart.getYAxisOptions(this.options, rightYAxisPower, this.translate, "line", locale, ChartConstants.EMPTY_DATASETS); - this.options.scales.x['time'].unit = calculateResolution(this.service, this.service.historyPeriod.value.from, this.service.historyPeriod.value.to).timeFormat; - this.options.scales.x['ticks'] = { source: 'auto', autoSkip: false }; + this.options.scales.x["time"].unit = calculateResolution(this.service, this.service.historyPeriod.value.from, this.service.historyPeriod.value.to).timeFormat; + this.options.scales.x["ticks"] = { source: "auto", autoSkip: false }; this.options.scales.x.ticks.maxTicksLimit = 30; - this.options.scales.x['offset'] = false; + this.options.scales.x["offset"] = false; this.options.scales.x.ticks.callback = function (value) { const date = new Date(value); // Display the label only if the minutes are zero (full hour) - return date.getMinutes() === 0 ? date.getHours() + ':00' : ''; + return date.getMinutes() === 0 ? date.getHours() + ":00" : ""; }; // options.plugins. - this.options.plugins.tooltip.mode = 'index'; + this.options.plugins.tooltip.mode = "index"; this.options.plugins.tooltip.callbacks.labelColor = (item: Chart.TooltipItem) => { if (!item) { return; @@ -147,7 +146,7 @@ export class ScheduleStateAndPriceChartComponent extends AbstractHistoryChart im }; this.datasets = this.datasets.map((el) => { - const opacity = el.type === 'line' ? 0.2 : 0.5; + const opacity = el.type === "line" ? 0.2 : 0.5; if (el.backgroundColor && el.borderColor) { el.backgroundColor = ColorUtils.changeOpacityFromRGBA(el.backgroundColor.toString(), opacity); @@ -159,21 +158,21 @@ export class ScheduleStateAndPriceChartComponent extends AbstractHistoryChart im this.datasets = this.datasets.map((el: Chart.ChartDataset) => { // align particular dataset element to right yAxis - if (el.label == this.translate.instant('General.gridBuy')) { - el['yAxisID'] = ChartAxis.RIGHT_2; - } else if (el.label == this.translate.instant('General.soc')) { - el['yAxisID'] = ChartAxis.RIGHT; + if (el.label == this.translate.instant("General.gridBuy")) { + el["yAxisID"] = ChartAxis.RIGHT_2; + } else if (el.label == this.translate.instant("General.soc")) { + el["yAxisID"] = ChartAxis.RIGHT; } return el; }); - this.options.scales[ChartAxis.LEFT]['title'].text = this.currencyLabel; + this.options.scales[ChartAxis.LEFT]["title"].text = this.currencyLabel; this.options.scales[ChartAxis.RIGHT].grid.display = false; this.options.scales[ChartAxis.RIGHT_2].suggestedMin = 0; this.options.scales[ChartAxis.RIGHT_2].suggestedMax = 1; this.options.scales[ChartAxis.RIGHT_2].grid.display = false; - this.options['animation'] = false; + this.options["animation"] = false; } } diff --git a/ui/src/app/edge/live/Controller/Evcs/Evcs.ts b/ui/src/app/edge/live/Controller/Evcs/Evcs.ts index 6a2568a03c5..89fd473682e 100644 --- a/ui/src/app/edge/live/Controller/Evcs/Evcs.ts +++ b/ui/src/app/edge/live/Controller/Evcs/Evcs.ts @@ -1,9 +1,9 @@ -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'; +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: [ diff --git a/ui/src/app/edge/live/Controller/Evcs/administration/administration.component.ts b/ui/src/app/edge/live/Controller/Evcs/administration/administration.component.ts index 9b2d74b6c55..3e38be561f1 100644 --- a/ui/src/app/edge/live/Controller/Evcs/administration/administration.component.ts +++ b/ui/src/app/edge/live/Controller/Evcs/administration/administration.component.ts @@ -1,12 +1,12 @@ -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 { 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"; @Component({ selector: AdministrationComponent.SELECTOR, - templateUrl: './administration.component.html', + templateUrl: "./administration.component.html", }) export class AdministrationComponent implements OnInit { @@ -27,16 +27,16 @@ export class AdministrationComponent implements OnInit { ) { } ngOnInit() { - if (this.evcsComponent.properties['minHwCurrent'] == 6000) { + if (this.evcsComponent.properties["minHwCurrent"] == 6000) { this.isCheckedZoe = false; - } else if (this.evcsComponent.properties['minHwCurrent'] == 10000) { + } else if (this.evcsComponent.properties["minHwCurrent"] == 10000) { this.isCheckedZoe = true; } } updateZoeMode(event: CustomEvent) { - let newValue = this.evcsComponent.properties['minHwCurrent']; - const oldValue = this.evcsComponent.properties['minHwCurrent']; + let newValue = this.evcsComponent.properties["minHwCurrent"]; + const oldValue = this.evcsComponent.properties["minHwCurrent"]; if (event.detail.checked == true) { newValue = 10000; @@ -46,13 +46,13 @@ export class AdministrationComponent implements OnInit { if (this.edge != null && oldValue != newValue) { this.edge.updateComponentConfig(this.websocket, this.evcsComponent.id, [ - { name: 'minHwCurrent', value: newValue }, + { name: "minHwCurrent", value: newValue }, ]).then(() => { this.evcsComponent.properties.minHwCurrent = newValue; - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); + this.service.toast(this.translate.instant("General.changeAccepted"), "success"); }).catch(reason => { this.evcsComponent.properties.minHwCurrent = oldValue; - this.service.toast(this.translate.instant('General.changeFailed') + '\n' + reason, 'danger'); + this.service.toast(this.translate.instant("General.changeFailed") + "\n" + reason, "danger"); console.warn(reason); }); } diff --git a/ui/src/app/edge/live/Controller/Evcs/flat/flat.ts b/ui/src/app/edge/live/Controller/Evcs/flat/flat.ts index f4d3d8a38e9..ea589527b23 100644 --- a/ui/src/app/edge/live/Controller/Evcs/flat/flat.ts +++ b/ui/src/app/edge/live/Controller/Evcs/flat/flat.ts @@ -1,17 +1,17 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; -import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; -import { ChannelAddress, CurrentData, EdgeConfig, Utils } from 'src/app/shared/shared'; +import { Component } from "@angular/core"; +import { AbstractFlatWidget } from "src/app/shared/components/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'; +import { ModalComponent } from "../modal/modal"; -type ChargeMode = 'FORCE_CHARGE' | 'EXCESS_POWER' | 'OFF'; +type ChargeMode = "FORCE_CHARGE" | "EXCESS_POWER" | "OFF"; @Component({ - selector: 'Controller_Evcs', - templateUrl: './flat.html', + selector: "Controller_Evcs", + templateUrl: "./flat.html", }) export class FlatComponent extends AbstractFlatWidget { @@ -29,7 +29,7 @@ export class FlatComponent extends AbstractFlatWidget { protected phases: number; protected maxChargingValue: number; protected energySessionLimit: number; - protected state: string = ''; + protected state: string = ""; protected minChargePower: number; protected maxChargePower: number; protected forceChargeMinPower: string; @@ -61,16 +61,16 @@ export class FlatComponent extends AbstractFlatWidget { protected override getChannelAddresses(): ChannelAddress[] { const result = [ - 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, "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'), + new ChannelAddress(this.component.id, "MinimumHardwarePower"), + new ChannelAddress(this.component.id, "MaximumHardwarePower"), + new ChannelAddress(this.component.id, "SetChargePowerLimit"), ]; const controllers = this.config.getComponentsByFactory("Controller.Evcs"); @@ -78,7 +78,7 @@ export class FlatComponent extends AbstractFlatWidget { const properties = controller.properties; if ("evcs.id" in properties && properties["evcs.id"] === this.componentId) { this.controller = controller; - result.push(new ChannelAddress(controller.id, '_PropertyEnabledCharging')); + result.push(new ChannelAddress(controller.id, "_PropertyEnabledCharging")); } } return result; @@ -87,20 +87,20 @@ export class FlatComponent extends AbstractFlatWidget { protected override onCurrentData(currentData: CurrentData) { this.evcsComponent = this.config.getComponent(this.component.id); - this.isConnectionSuccessful = currentData.allComponents[this.component.id + '/State'] != 3 ? true : false; - this.status = this.getState(this.controller ? currentData.allComponents[this.controller.id + '/_PropertyEnabledCharging'] === 1 : null, currentData.allComponents[this.component.id + "/Status"], currentData.allComponents[this.component.id + "/Plug"]); + this.isConnectionSuccessful = currentData.allComponents[this.component.id + "/State"] != 3 ? true : false; + this.status = this.getState(this.controller ? currentData.allComponents[this.controller.id + "/_PropertyEnabledCharging"] === 1 : null, 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) { + 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'); + 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"); } } @@ -108,35 +108,35 @@ export class FlatComponent extends AbstractFlatWidget { if (this.controller) { // ChargeMode - this.chargeMode = this.controller.properties['chargeMode']; + this.chargeMode = this.controller.properties["chargeMode"]; // Check if Charging is enabled - this.isChargingEnabled = currentData.allComponents[this.controller.id + '/_PropertyEnabledCharging'] === 1 ? true : false; + this.isChargingEnabled = currentData.allComponents[this.controller.id + "/_PropertyEnabledCharging"] === 1 ? true : false; // DefaultChargeMinPower - this.defaultChargeMinPower = this.controller.properties['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() - : ''; + 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); + this.maxChargingValue = Utils.multiplySafely(this.controller.properties["forceChargeMinPower"], this.phases); } else { - this.maxChargingValue = Utils.multiplySafely(this.controller.properties['forceChargeMinPower'], 3); + this.maxChargingValue = Utils.multiplySafely(this.controller.properties["forceChargeMinPower"], 3); } // EnergySessionLimit - this.energySessionLimit = this.controller.properties['energySessionLimit']; + this.energySessionLimit = this.controller.properties["energySessionLimit"]; } // Phases - this.phases = currentData.allComponents[this.componentId + '/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.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"]; } @@ -149,34 +149,34 @@ export class FlatComponent extends AbstractFlatWidget { private getState(enabledCharging: boolean, state: number, plug: number): string { if (enabledCharging === false) { - return this.translate.instant('Edge.Index.Widgets.EVCS.chargingStationDeactivated'); + return this.translate.instant("Edge.Index.Widgets.EVCS.chargingStationDeactivated"); } if (plug == null) { if (state == null) { - return this.translate.instant('Edge.Index.Widgets.EVCS.notCharging'); + 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'); + return this.translate.instant("Edge.Index.Widgets.EVCS.cableNotConnected"); } switch (state) { case ChargeState.STARTING: - return this.translate.instant('Edge.Index.Widgets.EVCS.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'); + return this.translate.instant("Edge.Index.Widgets.EVCS.error"); case ChargeState.READY_FOR_CHARGING: - return this.translate.instant('Edge.Index.Widgets.EVCS.readyForCharging'); + return this.translate.instant("Edge.Index.Widgets.EVCS.readyForCharging"); case ChargeState.NOT_READY_FOR_CHARGING: - return this.translate.instant('Edge.Index.Widgets.EVCS.notReadyForCharging'); + return this.translate.instant("Edge.Index.Widgets.EVCS.notReadyForCharging"); case ChargeState.AUTHORIZATION_REJECTED: - return this.translate.instant('Edge.Index.Widgets.EVCS.notCharging'); + return this.translate.instant("Edge.Index.Widgets.EVCS.notCharging"); case ChargeState.CHARGING: - return this.translate.instant('Edge.Index.Widgets.EVCS.charging'); + return this.translate.instant("Edge.Index.Widgets.EVCS.charging"); case ChargeState.ENERGY_LIMIT_REACHED: - return this.translate.instant('Edge.Index.Widgets.EVCS.chargeLimitReached'); + return this.translate.instant("Edge.Index.Widgets.EVCS.chargeLimitReached"); case ChargeState.CHARGING_FINISHED: - return this.translate.instant('Edge.Index.Widgets.EVCS.carFull'); + return this.translate.instant("Edge.Index.Widgets.EVCS.carFull"); } } diff --git a/ui/src/app/edge/live/Controller/Evcs/modal/modal.ts b/ui/src/app/edge/live/Controller/Evcs/modal/modal.ts index 461ab9bdba5..0e92bbc6eda 100644 --- a/ui/src/app/edge/live/Controller/Evcs/modal/modal.ts +++ b/ui/src/app/edge/live/Controller/Evcs/modal/modal.ts @@ -1,18 +1,18 @@ // @ts-strict-ignore -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/components/modal/abstractModal'; -import { ChannelAddress, CurrentData, EdgeConfig, Service, Utils, Websocket } from 'src/app/shared/shared'; +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/components/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'; +import { AdministrationComponent } from "../administration/administration.component"; +import { PopoverComponent } from "../popover/popover"; -type ChargeMode = 'FORCE_CHARGE' | 'EXCESS_POWER'; +type ChargeMode = "FORCE_CHARGE" | "EXCESS_POWER"; @Component({ - templateUrl: './modal.html', + templateUrl: "./modal.html", }) export class ModalComponent extends AbstractModal { @@ -21,11 +21,11 @@ export class ModalComponent extends AbstractModal { protected controller: EdgeConfig.Component; protected evcsComponent: EdgeConfig.Component; protected isConnectionSuccessful: boolean = false; - protected readonly emptyValue: string = '-'; + protected readonly emptyValue: string = "-"; protected status: string; protected chargePowerLimit: string; protected chargePower: { name: string; value: number; }; - protected state: string = ''; + protected state: string = ""; protected energySession: string; protected minChargePower: number; protected maxChargePower: number; @@ -59,12 +59,12 @@ export class ModalComponent extends AbstractModal { 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'; + 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; } @@ -74,7 +74,7 @@ export class ModalComponent extends AbstractModal { const popover = await this.popoverctrl.create({ component: PopoverComponent, componentProps: { - chargeMode: this.formGroup.controls['chargeMode'].value, + chargeMode: this.formGroup.controls["chargeMode"].value, }, }); return await popover.present(); @@ -104,23 +104,23 @@ export class ModalComponent extends AbstractModal { 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'), - new ChannelAddress(this.controller?.id, '_PropertyDefaultChargeMinPower'), + 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"), + new ChannelAddress(this.controller?.id, "_PropertyDefaultChargeMinPower"), ]; } protected override onCurrentData(currentData: CurrentData) { - this.isConnectionSuccessful = currentData.allComponents[this.component.id + '/State'] !== 3 ? true : false; + 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(this.controller ? currentData.allComponents[this.controller.id + "/_PropertyEnabledCharging"] === 1 : null, currentData.allComponents[this.component.id + "/Status"], currentData.allComponents[this.component.id + "/Plug"]); @@ -128,58 +128,58 @@ export class ModalComponent extends AbstractModal { 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_WATTHOURS(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']; + 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"]; } } protected override onIsInitialized(): void { - this.subscription.add(this.formGroup?.controls['energyLimit']?.valueChanges.subscribe(isEnergyLimit => { + this.subscription.add(this.formGroup?.controls["energyLimit"]?.valueChanges.subscribe(isEnergyLimit => { if (isEnergyLimit) { - if (this.formGroup.controls['energySessionLimit']?.value === 0) { - this.formGroup.controls['energySessionLimit'].setValue(20000); - this.formGroup.controls['energySessionLimit'].markAsDirty(); + if (this.formGroup.controls["energySessionLimit"]?.value === 0) { + this.formGroup.controls["energySessionLimit"].setValue(20000); + this.formGroup.controls["energySessionLimit"].markAsDirty(); } else { // energySessionLimit is already valid -> do nothing } } else { - this.formGroup.controls['energySessionLimit'].setValue(0); - this.formGroup.controls['energySessionLimit'].markAsDirty(); + this.formGroup.controls["energySessionLimit"].setValue(0); + this.formGroup.controls["energySessionLimit"].markAsDirty(); } })); - this.subscription.add(this.formGroup?.get('chargeMode').valueChanges.subscribe(chargeMode => { - if (chargeMode === 'OFF') { - this.formGroup.get('enabledCharging').setValue(false); - this.formGroup.get('chargeMode').markAsPristine(); // do not send chargeMode=OFF to Edge + this.subscription.add(this.formGroup?.get("chargeMode").valueChanges.subscribe(chargeMode => { + if (chargeMode === "OFF") { + this.formGroup.get("enabledCharging").setValue(false); + this.formGroup.get("chargeMode").markAsPristine(); // do not send chargeMode=OFF to Edge } else { - this.formGroup.get('enabledCharging').setValue(true); + this.formGroup.get("enabledCharging").setValue(true); } - this.formGroup.get('enabledCharging').markAsDirty(); + this.formGroup.get("enabledCharging").markAsDirty(); })); - this.subscription.add(this.formGroup?.get('minGuarantee').valueChanges.subscribe(minGuarantee => { + this.subscription.add(this.formGroup?.get("minGuarantee").valueChanges.subscribe(minGuarantee => { if (minGuarantee) { - this.formGroup.controls['defaultChargeMinPower'].setValue(1400 /* approx min power per phase */ * this.numberOfPhases); + this.formGroup.controls["defaultChargeMinPower"].setValue(1400 /* approx min power per phase */ * this.numberOfPhases); } else { - this.formGroup.controls['defaultChargeMinPower'].setValue(0); + this.formGroup.controls["defaultChargeMinPower"].setValue(0); } - this.formGroup.controls['defaultChargeMinPower'].markAsDirty(); + this.formGroup.controls["defaultChargeMinPower"].markAsDirty(); })); // Convert FormGroup value in kWh to Wh for Component config - this.subscription.add(this.formGroup?.get('energySessionLimitKwh').valueChanges.subscribe((newValue) => { - this.formGroup.controls['energySessionLimit'].setValue(newValue * 1000); - this.formGroup.controls['energySessionLimit'].markAsDirty(); - this.formGroup.controls['energySessionLimitKwh'].markAsPristine(); + this.subscription.add(this.formGroup?.get("energySessionLimitKwh").valueChanges.subscribe((newValue) => { + this.formGroup.controls["energySessionLimit"].setValue(newValue * 1000); + this.formGroup.controls["energySessionLimit"].markAsDirty(); + this.formGroup.controls["energySessionLimitKwh"].markAsPristine(); })); } protected override getFormGroup(): FormGroup { return this.formBuilder.group({ - chargeMode: new FormControl(this.controller?.properties.enabledCharging == false ? 'OFF' : this.controller?.properties.chargeMode), + 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.controller?.properties.defaultChargeMinPower > 0), defaultChargeMinPower: new FormControl(this.controller?.properties.defaultChargeMinPower), @@ -201,15 +201,15 @@ export class ModalComponent extends AbstractModal { protected updateForceMinPower(event: CustomEvent, currentController: EdgeConfig.Component, numberOfPhases: number) { const newMinChargePower = event.detail.value / numberOfPhases; - this.formGroup.controls['forceChargeMinPower'].markAsDirty(); - this.formGroup.controls['forceChargeMinPower'].setValue(newMinChargePower); + 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.controller && this.evcsComponent.properties['minHwCurrent'] == 10000) { + if (this.controller && this.evcsComponent.properties["minHwCurrent"] == 10000) { const oldMinChargePower = this.controller.properties.forceChargeMinPower; const maxAllowedChargePower = 10 /* Ampere */ * 230; /* Volt */ @@ -218,7 +218,7 @@ export class ModalComponent extends AbstractModal { if (this.edge != null) { const newMinChargePower = maxAllowedChargePower; this.edge.updateComponentConfig(this.websocket, this.controller.id, [ - { name: 'forceChargeMinPower', value: newMinChargePower }, + { name: "forceChargeMinPower", value: newMinChargePower }, ]).then(() => { this.controller.properties.forceChargeMinPower = newMinChargePower; }).catch(reason => { @@ -245,34 +245,34 @@ export class ModalComponent extends AbstractModal { private getState(enabledCharging: boolean, state: number, plug: number): string { if (enabledCharging === false) { - return this.translate.instant('Edge.Index.Widgets.EVCS.chargingStationDeactivated'); + return this.translate.instant("Edge.Index.Widgets.EVCS.chargingStationDeactivated"); } if (plug == null) { if (state == null) { - return this.translate.instant('Edge.Index.Widgets.EVCS.notCharging'); + 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'); + return this.translate.instant("Edge.Index.Widgets.EVCS.cableNotConnected"); } switch (state) { case ChargeState.STARTING: - return this.translate.instant('Edge.Index.Widgets.EVCS.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'); + return this.translate.instant("Edge.Index.Widgets.EVCS.error"); case ChargeState.READY_FOR_CHARGING: - return this.translate.instant('Edge.Index.Widgets.EVCS.readyForCharging'); + return this.translate.instant("Edge.Index.Widgets.EVCS.readyForCharging"); case ChargeState.NOT_READY_FOR_CHARGING: - return this.translate.instant('Edge.Index.Widgets.EVCS.notReadyForCharging'); + return this.translate.instant("Edge.Index.Widgets.EVCS.notReadyForCharging"); case ChargeState.AUTHORIZATION_REJECTED: - return this.translate.instant('Edge.Index.Widgets.EVCS.notCharging'); + return this.translate.instant("Edge.Index.Widgets.EVCS.notCharging"); case ChargeState.CHARGING: - return this.translate.instant('Edge.Index.Widgets.EVCS.charging'); + return this.translate.instant("Edge.Index.Widgets.EVCS.charging"); case ChargeState.ENERGY_LIMIT_REACHED: - return this.translate.instant('Edge.Index.Widgets.EVCS.chargeLimitReached'); + return this.translate.instant("Edge.Index.Widgets.EVCS.chargeLimitReached"); case ChargeState.CHARGING_FINISHED: - return this.translate.instant('Edge.Index.Widgets.EVCS.carFull'); + return this.translate.instant("Edge.Index.Widgets.EVCS.carFull"); } } diff --git a/ui/src/app/edge/live/Controller/Evcs/popover/popover.ts b/ui/src/app/edge/live/Controller/Evcs/popover/popover.ts index 1d53c249443..718bdb5d868 100644 --- a/ui/src/app/edge/live/Controller/Evcs/popover/popover.ts +++ b/ui/src/app/edge/live/Controller/Evcs/popover/popover.ts @@ -1,10 +1,10 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { AbstractModal } from 'src/app/shared/components/modal/abstractModal'; +import { Component } from "@angular/core"; +import { AbstractModal } from "src/app/shared/components/modal/abstractModal"; -type ChargeMode = 'FORCE_CHARGE' | 'EXCESS_POWER' | 'OFF'; +type ChargeMode = "FORCE_CHARGE" | "EXCESS_POWER" | "OFF"; @Component({ - templateUrl: './popover.html', + templateUrl: "./popover.html", }) export class PopoverComponent extends AbstractModal { 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 452e7643dec..bbed2715a18 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,13 +1,13 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { AbstractFlatWidget } from 'src/app/shared/components/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'; +import { Component } from "@angular/core"; +import { AbstractFlatWidget } from "src/app/shared/components/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({ - selector: 'Controller_Io_ChannelSingleThresholdComponent', - templateUrl: './Io_ChannelSingleThreshold.html', + selector: "Controller_Io_ChannelSingleThresholdComponent", + templateUrl: "./Io_ChannelSingleThreshold.html", }) export class Controller_Io_ChannelSingleThresholdComponent extends AbstractFlatWidget { @@ -17,9 +17,9 @@ export class Controller_Io_ChannelSingleThresholdComponent extends AbstractFlatW public mode: string; public modeValue: string; public icon: Icon = { - name: '', - color: '', - size: '', + name: "", + color: "", + size: "", }; public dependendOn: string; public dependendOnValue: any; @@ -47,7 +47,7 @@ export class Controller_Io_ChannelSingleThresholdComponent extends AbstractFlatW protected override afterIsInitialized(): void { this.inputChannel = ChannelAddress.fromString( - this.component.properties['inputChannelAddress']); + this.component.properties["inputChannelAddress"]); this.edge.getChannel(this.websocket, this.inputChannel) .then(channel => { @@ -56,8 +56,8 @@ export class Controller_Io_ChannelSingleThresholdComponent extends AbstractFlatW } protected override getChannelAddresses() { - const outputChannelAddress: string | string[] = this.component.properties['outputChannelAddress']; - if (typeof outputChannelAddress === 'string') { + const outputChannelAddress: string | string[] = this.component.properties["outputChannelAddress"]; + if (typeof outputChannelAddress === "string") { this.outputChannel = ChannelAddress.fromString(outputChannelAddress); } else { // Takes only the first output for simplicity reasons @@ -66,37 +66,37 @@ export class Controller_Io_ChannelSingleThresholdComponent extends AbstractFlatW return [ this.outputChannel, this.inputChannel, - ChannelAddress.fromString(this.component.id + '/_PropertyMode')]; + ChannelAddress.fromString(this.component.id + "/_PropertyMode")]; } protected override onCurrentData(currentData: CurrentData) { - this.switchValue = this.component.properties['threshold']; + this.switchValue = this.component.properties["threshold"]; // Icon, State this.outputChannelValue = currentData.allComponents[this.outputChannel.toString()]; switch (this.outputChannelValue) { case 0: - this.icon.name = 'radio-button-off-outline'; - this.state = this.translate.instant('General.off'); + this.icon.name = "radio-button-off-outline"; + this.state = this.translate.instant("General.off"); break; case 1: - this.icon.name = 'aperture-outline'; - this.state = this.translate.instant('General.on'); + this.icon.name = "aperture-outline"; + this.state = this.translate.instant("General.on"); break; } // Mode - this.modeValue = currentData.allComponents[this.component.id + '/_PropertyMode']; + this.modeValue = currentData.allComponents[this.component.id + "/_PropertyMode"]; switch (this.modeValue) { - case 'ON': - this.mode = this.translate.instant('General.on'); + case "ON": + this.mode = this.translate.instant("General.on"); break; - case 'OFF': - this.mode = this.translate.instant('General.off'); + case "OFF": + this.mode = this.translate.instant("General.off"); break; - case 'AUTOMATIC': - this.mode = this.translate.instant('General.automatic'); + case "AUTOMATIC": + this.mode = this.translate.instant("General.automatic"); } @@ -105,45 +105,45 @@ export class Controller_Io_ChannelSingleThresholdComponent extends AbstractFlatW // Set dependendOn Value for different inputChannel && Set the switchConverter and switchValue switch (this.inputChannel.toString()) { - case '_sum/EssSoc': - this.dependendOn = this.translate.instant('General.soc'); + case "_sum/EssSoc": + this.dependendOn = this.translate.instant("General.soc"); this.switchConverter = Utils.CONVERT_TO_PERCENT; break; - case '_sum/ProductionActivePower': - this.dependendOn = this.translate.instant('General.production'); + case "_sum/ProductionActivePower": + this.dependendOn = this.translate.instant("General.production"); break; - case '_sum/GridActivePower': + case "_sum/GridActivePower": if (this.component.properties.threshold < 0) { if (this.outputChannelValue == 0) { - this.switchValue = this.component.properties['threshold'] * -1; + this.switchValue = this.component.properties["threshold"] * -1; } else if (this.outputChannelValue == 1) { - this.switchValue = this.component.properties['threshold'] * -1 - this.component.properties['switchedLoadPower']; + this.switchValue = this.component.properties["threshold"] * -1 - this.component.properties["switchedLoadPower"]; } - this.dependendOn = this.translate.instant('General.gridSell'); + this.dependendOn = this.translate.instant("General.gridSell"); } else if (this.component.properties.threshold > 0) { if (this.outputChannelValue == 1) { - this.switchValue = this.component.properties['threshold'] - this.component.properties['switchedLoadPower']; + this.switchValue = this.component.properties["threshold"] - this.component.properties["switchedLoadPower"]; } - this.dependendOn = this.translate.instant('General.gridBuy'); + this.dependendOn = this.translate.instant("General.gridBuy"); } break; default: if (this.component.properties.threshold < 0) { - this.switchValue = Utils.multiplySafely(this.component.properties['threshold'], -1) - + this.unitOfInputChannel !== '' ? this.unitOfInputChannel : ''; + this.switchValue = Utils.multiplySafely(this.component.properties["threshold"], -1) + + this.unitOfInputChannel !== "" ? this.unitOfInputChannel : ""; } else if (this.component.properties.threshold > 0) { - this.switchValue += this.unitOfInputChannel !== '' ? this.unitOfInputChannel : ''; + this.switchValue += this.unitOfInputChannel !== "" ? this.unitOfInputChannel : ""; } - this.dependendOn = this.translate.instant('Edge.Index.Widgets.Singlethreshold.other') - + ' (' + this.component.properties.inputChannelAddress + ')'; + this.dependendOn = this.translate.instant("Edge.Index.Widgets.Singlethreshold.other") + + " (" + this.component.properties.inputChannelAddress + ")"; break; } // True when InputAddress doesnt match any of the following channelIds - this.isOtherInputAddress = this.inputChannel.toString() != (null && '_sum/EssSoc' && '_sum/GridActivePower' && '_sum/ProductionActivePower') ? false : true; + this.isOtherInputAddress = this.inputChannel.toString() != (null && "_sum/EssSoc" && "_sum/GridActivePower" && "_sum/ProductionActivePower") ? false : true; // Switch ON / OFF && BELOW / ABOVE // Threshold greater 0 @@ -152,17 +152,17 @@ export class Controller_Io_ChannelSingleThresholdComponent extends AbstractFlatW // Check if invert is false if (!this.component.properties.invert) { if (this.outputChannelValue == 0) { - this.switchState = this.translate.instant('Edge.Index.Widgets.Singlethreshold.switchOnAbove'); + this.switchState = this.translate.instant("Edge.Index.Widgets.Singlethreshold.switchOnAbove"); } else if (this.outputChannelValue == 1) { - this.switchState = this.translate.instant('Edge.Index.Widgets.Singlethreshold.switchOffBelow'); + this.switchState = this.translate.instant("Edge.Index.Widgets.Singlethreshold.switchOffBelow"); } // Check if invert is true } else if (this.component.properties.invert) { if (this.outputChannelValue == 0) { - this.switchState = this.translate.instant('Edge.Index.Widgets.Singlethreshold.switchOnBelow'); + this.switchState = this.translate.instant("Edge.Index.Widgets.Singlethreshold.switchOnBelow"); } else if (this.outputChannelValue == 1) { - this.switchState = this.translate.instant('Edge.Index.Widgets.Singlethreshold.switchOffAbove'); + this.switchState = this.translate.instant("Edge.Index.Widgets.Singlethreshold.switchOffAbove"); } } @@ -171,17 +171,17 @@ export class Controller_Io_ChannelSingleThresholdComponent extends AbstractFlatW // Check if invert is false if (!this.component.properties.invert) { if (this.outputChannelValue == 0) { - this.switchState = this.translate.instant('Edge.Index.Widgets.Singlethreshold.switchOnBelow'); + this.switchState = this.translate.instant("Edge.Index.Widgets.Singlethreshold.switchOnBelow"); } else if (this.outputChannelValue == 1) { - this.switchState = this.translate.instant('Edge.Index.Widgets.Singlethreshold.switchOffAbove'); + this.switchState = this.translate.instant("Edge.Index.Widgets.Singlethreshold.switchOffAbove"); } // Check if invert is true } else if (this.component.properties.invert) { if (this.outputChannelValue == 0) { - this.switchState = this.translate.instant('Edge.Index.Widgets.Singlethreshold.switchOnAbove'); + this.switchState = this.translate.instant("Edge.Index.Widgets.Singlethreshold.switchOnAbove"); } else if (this.outputChannelValue == 1) { - this.switchState = this.translate.instant('Edge.Index.Widgets.Singlethreshold.switchOffBelow'); + this.switchState = this.translate.instant("Edge.Index.Widgets.Singlethreshold.switchOffBelow"); } } } diff --git a/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/modal/modal.component.ts b/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/modal/modal.component.ts index a17e536b72a..738b4c396bc 100644 --- a/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/modal/modal.component.ts +++ b/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/modal/modal.component.ts @@ -1,16 +1,16 @@ // @ts-strict-ignore -import { Component, Input, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; -import { ModalController } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; -import { ChannelAddress, Edge, EdgeConfig, Service, Websocket } from 'src/app/shared/shared'; +import { Component, Input, OnInit } from "@angular/core"; +import { FormBuilder, FormControl, FormGroup, Validators } from "@angular/forms"; +import { ModalController } from "@ionic/angular"; +import { TranslateService } from "@ngx-translate/core"; +import { ChannelAddress, Edge, EdgeConfig, Service, Websocket } from "src/app/shared/shared"; -type mode = 'ON' | 'AUTOMATIC' | 'OFF'; -type inputMode = 'SOC' | 'GRIDSELL' | 'GRIDBUY' | 'PRODUCTION' | 'OTHER'; +type mode = "ON" | "AUTOMATIC" | "OFF"; +type inputMode = "SOC" | "GRIDSELL" | "GRIDBUY" | "PRODUCTION" | "OTHER"; @Component({ - selector: 'Io_ChannelSingleThresholdModalComponent', - templateUrl: './modal.component.html', + selector: "Io_ChannelSingleThresholdModalComponent", + templateUrl: "./modal.component.html", }) export class Controller_Io_ChannelSingleThresholdModalComponent implements OnInit { @@ -44,26 +44,26 @@ export class Controller_Io_ChannelSingleThresholdModalComponent implements OnIni this.formGroup = this.formBuilder.group({ minimumSwitchingTime: new FormControl(this.component.properties.minimumSwitchingTime, Validators.compose([ Validators.min(5), - Validators.pattern('^[1-9][0-9]*$'), + Validators.pattern("^[1-9][0-9]*$"), Validators.required, ])), switchedLoadPower: new FormControl(this.component.properties.switchedLoadPower, Validators.compose([ - Validators.pattern('^(?:[1-9][0-9]*|0)$'), + Validators.pattern("^(?:[1-9][0-9]*|0)$"), Validators.required, ])), - threshold: new FormControl(this.getInputMode() == 'GRIDSELL' ? this.component.properties.threshold * -1 : this.component.properties.threshold, Validators.compose([ + threshold: new FormControl(this.getInputMode() == "GRIDSELL" ? this.component.properties.threshold * -1 : this.component.properties.threshold, Validators.compose([ Validators.min(1), - Validators.pattern('^[1-9][0-9]*$'), + Validators.pattern("^[1-9][0-9]*$"), Validators.required, ])), inputMode: new FormControl(this.getInputMode()), invert: new FormControl(this.component.properties.invert, Validators.requiredTrue), }); - this.minimumSwitchingTime = this.formGroup.controls['minimumSwitchingTime']; - this.threshold = this.formGroup.controls['threshold']; - this.switchedLoadPower = this.formGroup.controls['switchedLoadPower']; - this.inputMode = this.formGroup.controls['inputMode']; - this.invert = this.formGroup.controls['invert']; + this.minimumSwitchingTime = this.formGroup.controls["minimumSwitchingTime"]; + this.threshold = this.formGroup.controls["threshold"]; + this.switchedLoadPower = this.formGroup.controls["switchedLoadPower"]; + this.inputMode = this.formGroup.controls["inputMode"]; + this.invert = this.formGroup.controls["invert"]; } public updateInputMode(event: CustomEvent) { @@ -71,7 +71,7 @@ export class Controller_Io_ChannelSingleThresholdModalComponent implements OnIni switch (event.detail.value) { case "SOC": - this.inputMode.setValue('SOC'); + this.inputMode.setValue("SOC"); this.switchedLoadPower.setValue(0); this.switchedLoadPower.markAsDirty(); if (Math.abs(this.component.properties.threshold) < 0 || Math.abs(this.component.properties.threshold) > 100) { @@ -84,12 +84,12 @@ export class Controller_Io_ChannelSingleThresholdModalComponent implements OnIni } break; case "GRIDSELL": - this.inputMode.setValue('GRIDSELL'); + this.inputMode.setValue("GRIDSELL"); this.threshold.markAsDirty(); this.switchedLoadPower.markAsDirty(); break; case "GRIDBUY": - this.inputMode.setValue('GRIDBUY'); + this.inputMode.setValue("GRIDBUY"); this.switchedLoadPower.markAsDirty(); if (this.component.properties.threshold < 0) { newThreshold = this.formGroup.value.threshold; @@ -98,7 +98,7 @@ export class Controller_Io_ChannelSingleThresholdModalComponent implements OnIni } break; case "PRODUCTION": - this.inputMode.setValue('PRODUCTION'); + this.inputMode.setValue("PRODUCTION"); this.switchedLoadPower.setValue(0); this.switchedLoadPower.markAsDirty(); if (this.component.properties.threshold < 0) { @@ -115,26 +115,26 @@ export class Controller_Io_ChannelSingleThresholdModalComponent implements OnIni let newMode: mode; switch (event.detail.value) { - case 'ON': - newMode = 'ON'; + case "ON": + newMode = "ON"; break; - case 'OFF': - newMode = 'OFF'; + case "OFF": + newMode = "OFF"; break; - case 'AUTOMATIC': - newMode = 'AUTOMATIC'; + case "AUTOMATIC": + newMode = "AUTOMATIC"; break; } if (this.edge != null) { this.edge.updateComponentConfig(this.websocket, this.component.id, [ - { name: 'mode', value: newMode }, + { name: "mode", value: newMode }, ]).then(() => { this.component.properties.mode = newMode; - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); + this.service.toast(this.translate.instant("General.changeAccepted"), "success"); }).catch(reason => { this.component.properties.mode = oldMode; - this.service.toast(this.translate.instant('General.changeFailed') + '\n' + reason.error.message, 'danger'); + this.service.toast(this.translate.instant("General.changeFailed") + "\n" + reason.error.message, "danger"); console.warn(reason); }); } @@ -142,16 +142,16 @@ export class Controller_Io_ChannelSingleThresholdModalComponent implements OnIni public applyChanges(): void { if (this.edge != null) { - if (this.edge.roleIsAtLeast('owner')) { + if (this.edge.roleIsAtLeast("owner")) { if (this.minimumSwitchingTime.valid && this.threshold.valid && this.switchedLoadPower.valid) { if (this.threshold.value > this.switchedLoadPower.value) { const updateComponentArray = []; Object.keys(this.formGroup.controls).forEach((element, index) => { if (this.formGroup.controls[element].dirty) { // catch inputMode and convert it to inputChannelAddress - if (Object.keys(this.formGroup.controls)[index] == 'inputMode') { - updateComponentArray.push({ name: 'inputChannelAddress', value: this.convertToChannelAddress(this.formGroup.controls[element].value) }); - } else if (this.inputMode.value == 'GRIDSELL' && Object.keys(this.formGroup.controls)[index] == 'threshold') { + if (Object.keys(this.formGroup.controls)[index] == "inputMode") { + updateComponentArray.push({ name: "inputChannelAddress", value: this.convertToChannelAddress(this.formGroup.controls[element].value) }); + } else if (this.inputMode.value == "GRIDSELL" && Object.keys(this.formGroup.controls)[index] == "threshold") { this.formGroup.controls[element].setValue(this.formGroup.controls[element].value * -1); updateComponentArray.push({ name: Object.keys(this.formGroup.controls)[index], value: this.formGroup.controls[element].value }); } else { @@ -162,12 +162,12 @@ export class Controller_Io_ChannelSingleThresholdModalComponent implements OnIni this.loading = true; this.edge.updateComponentConfig(this.websocket, this.component.id, updateComponentArray).then(() => { this.component.properties.minimumSwitchingTime = this.minimumSwitchingTime.value; - this.component.properties.threshold = this.inputMode.value == 'GRIDSELL' ? this.threshold.value * -1 : this.threshold.value; + this.component.properties.threshold = this.inputMode.value == "GRIDSELL" ? this.threshold.value * -1 : this.threshold.value; this.component.properties.switchedLoadPower = this.switchedLoadPower.value; this.component.properties.inputChannelAddress = this.convertToChannelAddress(this.inputMode.value) != this.component.properties.inputChannelAddress ? this.convertToChannelAddress(this.inputMode.value) : this.component.properties.inputChannelAddress; this.component.properties.invert = this.invert.value; this.loading = false; - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); + this.service.toast(this.translate.instant("General.changeAccepted"), "success"); }).catch(reason => { this.loading = false; this.minimumSwitchingTime.setValue(this.component.properties.minimumSwitchingTime); @@ -176,65 +176,67 @@ export class Controller_Io_ChannelSingleThresholdModalComponent implements OnIni this.inputMode.setValue(this.convertToInputMode(this.component.properties.inputChannelAddress, this.component.properties.threshold)); this.invert.setValue(this.component.properties.invert); this.loading = false; - this.service.toast(this.translate.instant('General.changeFailed') + '\n' + reason.error.message, 'danger'); + this.service.toast(this.translate.instant("General.changeFailed") + "\n" + reason.error.message, "danger"); console.warn(reason); }); - if (this.inputMode.value == 'GRIDSELL') { + if (this.inputMode.value == "GRIDSELL") { if (this.inputMode.dirty || this.threshold.dirty) { this.threshold.setValue(this.threshold.value * -1); } } this.formGroup.markAsPristine(); } else { - this.service.toast(this.translate.instant('Edge.Index.Widgets.Singlethreshold.relationError'), 'danger'); + this.service.toast(this.translate.instant("Edge.Index.Widgets.Singlethreshold.relationError"), "danger"); } } else { - this.service.toast(this.translate.instant('General.inputNotValid'), 'danger'); + this.service.toast(this.translate.instant("General.inputNotValid"), "danger"); } } else { - this.service.toast(this.translate.instant('General.insufficientRights'), 'danger'); + this.service.toast(this.translate.instant("General.insufficientRights"), "danger"); } } } private getInputMode(): inputMode { - if (this.component.properties.inputChannelAddress == '_sum/GridActivePower' && this.component.properties.threshold < 0) { - return 'GRIDSELL'; - } else if (this.component.properties.inputChannelAddress == '_sum/GridActivePower' && this.component.properties.threshold > 0) { - return 'GRIDBUY'; - } else if (this.component.properties.inputChannelAddress == '_sum/ProductionActivePower') { - return 'PRODUCTION'; - } else if (this.component.properties.inputChannelAddress == '_sum/EssSoc') { - return 'SOC'; + if (this.component.properties.inputChannelAddress == "_sum/GridActivePower" && this.component.properties.threshold < 0) { + return "GRIDSELL"; + } else if (this.component.properties.inputChannelAddress == "_sum/GridActivePower" && this.component.properties.threshold > 0) { + return "GRIDBUY"; + } else if (this.component.properties.inputChannelAddress == "_sum/ProductionActivePower") { + return "PRODUCTION"; + } else if (this.component.properties.inputChannelAddress == "_sum/EssSoc") { + return "SOC"; } else if (this.component.properties.inputChannelAddress != null) { - return 'OTHER'; + return "OTHER"; } } - private convertToChannelAddress(inputMode: inputMode): string { + private convertToChannelAddress(inputMode: inputMode): string | null { switch (inputMode) { - case 'SOC': - return '_sum/EssSoc'; - case 'GRIDBUY': - return '_sum/GridActivePower'; - case 'GRIDSELL': - return '_sum/GridActivePower'; - case 'PRODUCTION': - return '_sum/ProductionActivePower'; + case "SOC": + return "_sum/EssSoc"; + case "GRIDBUY": + return "_sum/GridActivePower"; + case "GRIDSELL": + return "_sum/GridActivePower"; + case "PRODUCTION": + return "_sum/ProductionActivePower"; + default: + return null; } } private convertToInputMode(inputChannelAddress: string, threshold: number): inputMode { switch (inputChannelAddress) { - case '_sum/EssSoc': - return 'SOC'; - case '_sum/ProductionActivePower': - return 'PRODUCTION'; - case '_sum/GridActivePower': + case "_sum/EssSoc": + return "SOC"; + case "_sum/ProductionActivePower": + return "PRODUCTION"; + case "_sum/GridActivePower": if (threshold > 0) { - return 'GRIDBUY'; + return "GRIDBUY"; } else if (threshold < 0) { - return 'GRIDSELL'; + return "GRIDSELL"; } } } 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 82f0d1ef04c..b45630af970 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,17 +1,17 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; -import { ChannelAddress, CurrentData } from 'src/app/shared/shared'; +import { Component } from "@angular/core"; +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; +import { ChannelAddress, CurrentData } from "src/app/shared/shared"; -import { Controller_Io_FixDigitalOutputModalComponent } from './modal/modal.component'; +import { Controller_Io_FixDigitalOutputModalComponent } from "./modal/modal.component"; @Component({ - selector: 'Controller_Io_FixDigitalOutput', - templateUrl: './Io_FixDigitalOutput.html', + selector: "Controller_Io_FixDigitalOutput", + templateUrl: "./Io_FixDigitalOutput.html", }) export class Controller_Io_FixDigitalOutputComponent extends AbstractFlatWidget { - public state: string = '-'; + public state: string = "-"; public outputChannel: string; async presentModal() { @@ -29,7 +29,7 @@ export class Controller_Io_FixDigitalOutputComponent extends AbstractFlatWidget } protected override getChannelAddresses(): ChannelAddress[] { - this.outputChannel = this.component.properties['outputChannelAddress']; + this.outputChannel = this.component.properties["outputChannelAddress"]; return [ChannelAddress.fromString(this.outputChannel)]; } @@ -37,9 +37,9 @@ export class Controller_Io_FixDigitalOutputComponent extends AbstractFlatWidget const channel = currentData.allComponents[this.outputChannel]; if (channel != null) { if (channel == 1) { - this.state = this.translate.instant('General.on'); + this.state = this.translate.instant("General.on"); } else if (channel == 0) { - this.state = this.translate.instant('General.off'); + this.state = this.translate.instant("General.off"); } } } diff --git a/ui/src/app/edge/live/Controller/Io/FixDigitalOutput/modal/modal.component.ts b/ui/src/app/edge/live/Controller/Io/FixDigitalOutput/modal/modal.component.ts index b1564acb6da..ccc9dafd2b2 100644 --- a/ui/src/app/edge/live/Controller/Io/FixDigitalOutput/modal/modal.component.ts +++ b/ui/src/app/edge/live/Controller/Io/FixDigitalOutput/modal/modal.component.ts @@ -1,12 +1,12 @@ -import { Component, Input } from '@angular/core'; -import { Router } from '@angular/router'; -import { ModalController } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; -import { Edge, EdgeConfig, Service, Websocket } from 'src/app/shared/shared'; +import { Component, Input } from "@angular/core"; +import { Router } from "@angular/router"; +import { ModalController } from "@ionic/angular"; +import { TranslateService } from "@ngx-translate/core"; +import { Edge, EdgeConfig, Service, Websocket } from "src/app/shared/shared"; @Component({ - selector: 'fixdigitaloutput-modal', - templateUrl: './modal.component.html', + selector: "fixdigitaloutput-modal", + templateUrl: "./modal.component.html", }) export class Controller_Io_FixDigitalOutputModalComponent { @@ -32,16 +32,16 @@ export class Controller_Io_FixDigitalOutputModalComponent { // ion-segment button only supports string as type // https://ionicframework.com/docs/v4/api/segment-button - const newMode = (event.detail.value.toLowerCase() === 'true'); + const newMode = (event.detail.value.toLowerCase() === "true"); this.edge.updateComponentConfig(this.websocket, this.component.id, [ - { name: 'isOn', value: newMode }, + { name: "isOn", value: newMode }, ]).then(() => { this.component.properties.isOn = newMode; - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); + this.service.toast(this.translate.instant("General.changeAccepted"), "success"); }).catch(reason => { this.component.properties.isOn = oldMode; - this.service.toast(this.translate.instant('General.changeFailed') + '\n' + reason.error.message, 'danger'); + this.service.toast(this.translate.instant("General.changeFailed") + "\n" + reason.error.message, "danger"); console.warn(reason); }); } 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 1ae49e1b903..732c697cb1a 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 @@ -1,19 +1,19 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { BehaviorSubject } from 'rxjs'; -import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; -import { ChannelAddress, CurrentData, Utils } from 'src/app/shared/shared'; -import { WorkMode } from 'src/app/shared/type/general'; +import { Component } from "@angular/core"; +import { BehaviorSubject } from "rxjs"; +import { AbstractFlatWidget } from "src/app/shared/components/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'; +import { ModalComponent } from "../modal/modal"; @Component({ - selector: 'Controller_Io_HeatingElement', - templateUrl: './flat.html', + selector: "Controller_Io_HeatingElement", + templateUrl: "./flat.html", }) export class FlatComponent extends AbstractFlatWidget { - private static PROPERTY_MODE: string = '_PropertyMode'; + private static PROPERTY_MODE: string = "_PropertyMode"; protected activePhases: BehaviorSubject = new BehaviorSubject(0); protected mode: string; @@ -38,39 +38,39 @@ export class FlatComponent extends AbstractFlatWidget { this.outputChannelArray.push( ChannelAddress.fromString( - this.component.properties['outputChannelPhaseL1']), + this.component.properties["outputChannelPhaseL1"]), ChannelAddress.fromString( - this.component.properties['outputChannelPhaseL2']), + this.component.properties["outputChannelPhaseL2"]), ChannelAddress.fromString( - this.component.properties['outputChannelPhaseL3']), + this.component.properties["outputChannelPhaseL3"]), ); const channelAddresses: ChannelAddress[] = [ - new ChannelAddress(this.component.id, 'ForceStartAtSecondsOfDay'), + new ChannelAddress(this.component.id, "ForceStartAtSecondsOfDay"), ...this.outputChannelArray, - new ChannelAddress(this.component.id, 'Status'), + new ChannelAddress(this.component.id, "Status"), new ChannelAddress(this.component.id, FlatComponent.PROPERTY_MODE), - new ChannelAddress(this.component.id, '_PropertyWorkMode'), + new ChannelAddress(this.component.id, "_PropertyWorkMode"), ]; return channelAddresses; } protected override onCurrentData(currentData: CurrentData) { - this.workMode = currentData.allComponents[this.component.id + '/' + '_PropertyWorkMode']; + this.workMode = currentData.allComponents[this.component.id + "/" + "_PropertyWorkMode"]; // get current mode - switch (currentData.allComponents[this.component.id + '/' + FlatComponent.PROPERTY_MODE]) { - case 'MANUAL_ON': { - this.mode = 'General.on'; + switch (currentData.allComponents[this.component.id + "/" + FlatComponent.PROPERTY_MODE]) { + case "MANUAL_ON": { + this.mode = "General.on"; break; } - case 'MANUAL_OFF': { - this.mode = 'General.off'; + case "MANUAL_OFF": { + this.mode = "General.off"; break; } - case 'AUTOMATIC': { - this.mode = 'General.automatic'; + case "AUTOMATIC": { + this.mode = "General.automatic"; break; } } @@ -86,17 +86,17 @@ export class FlatComponent extends AbstractFlatWidget { // Get current state this.activePhases.next(value); if (this.activePhases.value > 0) { - this.state = 'General.active'; + this.state = "General.active"; // Check forced heat // TODO: Use only Status if edge version is latest [2022.8] - this.runState = currentData.allComponents[this.component.id + '/' + 'Status']; + this.runState = currentData.allComponents[this.component.id + "/" + "Status"]; if (this.runState == Status.ActiveForced) { - this.state = 'Edge.Index.Widgets.Heatingelement.activeForced'; + this.state = "Edge.Index.Widgets.Heatingelement.activeForced"; } } else if (this.activePhases.value == 0) { - this.state = 'General.inactive'; + this.state = "General.inactive"; } } diff --git a/ui/src/app/edge/live/Controller/Io/HeatingElement/modal/modal.ts b/ui/src/app/edge/live/Controller/Io/HeatingElement/modal/modal.ts index 193a683bf9b..8a9bd6ad535 100644 --- a/ui/src/app/edge/live/Controller/Io/HeatingElement/modal/modal.ts +++ b/ui/src/app/edge/live/Controller/Io/HeatingElement/modal/modal.ts @@ -1,18 +1,18 @@ // @ts-strict-ignore -import { Component, OnInit } from '@angular/core'; -import { FormControl, FormGroup } from '@angular/forms'; -import { BehaviorSubject } from 'rxjs'; -import { AbstractModal } from 'src/app/shared/components/modal/abstractModal'; -import { ChannelAddress, CurrentData } from 'src/app/shared/shared'; -import { Mode, WorkMode } from 'src/app/shared/type/general'; +import { Component, OnInit } from "@angular/core"; +import { FormControl, FormGroup } from "@angular/forms"; +import { BehaviorSubject } from "rxjs"; +import { AbstractModal } from "src/app/shared/components/modal/abstractModal"; +import { ChannelAddress, CurrentData } from "src/app/shared/shared"; +import { Mode, WorkMode } from "src/app/shared/type/general"; @Component({ - selector: 'heatingelement-modal', - templateUrl: './modal.html', + selector: "heatingelement-modal", + templateUrl: "./modal.html", }) export class ModalComponent extends AbstractModal implements OnInit { - private static PROPERTY_MODE: string = '_PropertyMode'; + private static PROPERTY_MODE: string = "_PropertyMode"; protected activePhases: BehaviorSubject = new BehaviorSubject(0); protected mode: string; protected state: string; @@ -25,30 +25,30 @@ export class ModalComponent extends AbstractModal implements OnInit { // TODO remove when outputting of event is errorless possible switchAllowMinimumHeating(event: CustomEvent) { if (event.detail.checked == true) { - this.formGroup.controls['workMode'].setValue('TIME'); - this.formGroup.controls['workMode'].markAsDirty(); + this.formGroup.controls["workMode"].setValue("TIME"); + this.formGroup.controls["workMode"].markAsDirty(); } else if (event.detail.checked == false) { - this.formGroup.controls['workMode'].setValue('NONE'); - this.formGroup.controls['workMode'].markAsDirty(); + this.formGroup.controls["workMode"].setValue("NONE"); + this.formGroup.controls["workMode"].markAsDirty(); } } protected override getChannelAddresses(): ChannelAddress[] { const outputChannelPhaseOne = ChannelAddress.fromString( - this.component.properties['outputChannelPhaseL1']); + this.component.properties["outputChannelPhaseL1"]); const outputChannelPhaseTwo = ChannelAddress.fromString( - this.component.properties['outputChannelPhaseL2']); + this.component.properties["outputChannelPhaseL2"]); const outputChannelPhaseThree = ChannelAddress.fromString( - this.component.properties['outputChannelPhaseL3']); + this.component.properties["outputChannelPhaseL3"]); this.outputChannelArray = [outputChannelPhaseOne, outputChannelPhaseTwo, outputChannelPhaseThree]; const channelAddresses: ChannelAddress[] = [ - new ChannelAddress(this.component.id, 'ForceStartAtSecondsOfDay'), + new ChannelAddress(this.component.id, "ForceStartAtSecondsOfDay"), outputChannelPhaseOne, outputChannelPhaseTwo, outputChannelPhaseThree, new ChannelAddress(this.component.id, ModalComponent.PROPERTY_MODE), - new ChannelAddress(this.component.id, '_PropertyWorkMode'), + new ChannelAddress(this.component.id, "_PropertyWorkMode"), ]; return channelAddresses; } @@ -56,7 +56,7 @@ export class ModalComponent extends AbstractModal implements OnInit { protected override onCurrentData(currentData: CurrentData) { // get current mode - this.mode = currentData.allComponents[this.component.id + '/' + ModalComponent.PROPERTY_MODE]; + this.mode = currentData.allComponents[this.component.id + "/" + ModalComponent.PROPERTY_MODE]; let value = 0; this.outputChannelArray.forEach(element => { @@ -68,9 +68,9 @@ export class ModalComponent extends AbstractModal implements OnInit { // Get current state this.activePhases.next(value); if (this.activePhases.value > 0) { - this.state = this.translate.instant('General.active'); + this.state = this.translate.instant("General.active"); } else if (this.activePhases.value == 0) { - this.state = this.translate.instant('General.inactive'); + this.state = this.translate.instant("General.inactive"); } } 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 2d8ec32c161..3962850c043 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,18 +1,18 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { BehaviorSubject } from 'rxjs'; -import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; -import { ChannelAddress, CurrentData, EdgeConfig } from 'src/app/shared/shared'; +import { Component } from "@angular/core"; +import { BehaviorSubject } from "rxjs"; +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; +import { ChannelAddress, CurrentData, EdgeConfig } from "src/app/shared/shared"; -import { Controller_Io_HeatpumpModalComponent } from './modal/modal.component'; +import { Controller_Io_HeatpumpModalComponent } from "./modal/modal.component"; @Component({ - selector: 'Controller_Io_Heatpump', - templateUrl: './Io_Heatpump.html', + selector: "Controller_Io_Heatpump", + templateUrl: "./Io_Heatpump.html", }) export class Controller_Io_HeatpumpComponent extends AbstractFlatWidget { - private static PROPERTY_MODE: string = '_PropertyMode'; + private static PROPERTY_MODE: string = "_PropertyMode"; public override component: EdgeConfig.Component | null = null; public status: BehaviorSubject<{ name: string }> = new BehaviorSubject(null); @@ -39,42 +39,42 @@ export class Controller_Io_HeatpumpComponent extends AbstractFlatWidget { protected override getChannelAddresses() { return [ - new ChannelAddress(this.component.id, 'Status'), - new ChannelAddress(this.component.id, 'State'), + new ChannelAddress(this.component.id, "Status"), + new ChannelAddress(this.component.id, "State"), new ChannelAddress(this.component.id, Controller_Io_HeatpumpComponent.PROPERTY_MODE), ]; } protected override onCurrentData(currentData: CurrentData) { - this.isConnectionSuccessful = currentData.allComponents[this.componentId + '/State'] != 3 ? true : false; + this.isConnectionSuccessful = currentData.allComponents[this.componentId + "/State"] != 3 ? true : false; // Status - switch (currentData.allComponents[this.componentId + '/Status']) { + switch (currentData.allComponents[this.componentId + "/Status"]) { case -1: - this.statusValue = this.translate.instant('Edge.Index.Widgets.HeatPump.undefined'); + this.statusValue = this.translate.instant("Edge.Index.Widgets.HeatPump.undefined"); break; case 0: - this.statusValue = this.translate.instant('Edge.Index.Widgets.HeatPump.lock'); + this.statusValue = this.translate.instant("Edge.Index.Widgets.HeatPump.lock"); break; case 1: - this.statusValue = this.translate.instant('Edge.Index.Widgets.HeatPump.normalOperation'); + this.statusValue = this.translate.instant("Edge.Index.Widgets.HeatPump.normalOperation"); break; case 2: - this.statusValue = this.translate.instant('Edge.Index.Widgets.HeatPump.switchOnRec'); + this.statusValue = this.translate.instant("Edge.Index.Widgets.HeatPump.switchOnRec"); break; case 3: - this.statusValue = this.translate.instant('Edge.Index.Widgets.HeatPump.switchOnCom'); + this.statusValue = this.translate.instant("Edge.Index.Widgets.HeatPump.switchOnCom"); break; } // Mode - switch (currentData.allComponents[this.component.id + '/' + Controller_Io_HeatpumpComponent.PROPERTY_MODE]) { - case 'AUTOMATIC': { - this.mode = this.translate.instant('General.automatic'); + switch (currentData.allComponents[this.component.id + "/" + Controller_Io_HeatpumpComponent.PROPERTY_MODE]) { + case "AUTOMATIC": { + this.mode = this.translate.instant("General.automatic"); break; } - case 'MANUAL': { - this.mode = this.translate.instant('General.manually'); + case "MANUAL": { + this.mode = this.translate.instant("General.manually"); break; } } diff --git a/ui/src/app/edge/live/Controller/Io/Heatpump/modal/modal.component.ts b/ui/src/app/edge/live/Controller/Io/Heatpump/modal/modal.component.ts index 0970982b294..d12d02ab21b 100644 --- a/ui/src/app/edge/live/Controller/Io/Heatpump/modal/modal.component.ts +++ b/ui/src/app/edge/live/Controller/Io/Heatpump/modal/modal.component.ts @@ -1,16 +1,16 @@ // @ts-strict-ignore -import { Component, Input, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup } from '@angular/forms'; -import { ModalController } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; -import { Edge, EdgeConfig, Service, Websocket } from 'src/app/shared/shared'; +import { Component, Input, OnInit } from "@angular/core"; +import { FormBuilder, FormControl, FormGroup } from "@angular/forms"; +import { ModalController } from "@ionic/angular"; +import { TranslateService } from "@ngx-translate/core"; +import { Edge, EdgeConfig, Service, Websocket } from "src/app/shared/shared"; -type ManualMode = 'FORCE_ON' | 'RECOMMENDATION' | 'REGULAR' | 'LOCK'; -type AutomaticEnableMode = 'automaticRecommendationCtrlEnabled' | 'automaticForceOnCtrlEnabled' | 'automaticLockCtrlEnabled'; +type ManualMode = "FORCE_ON" | "RECOMMENDATION" | "REGULAR" | "LOCK"; +type AutomaticEnableMode = "automaticRecommendationCtrlEnabled" | "automaticForceOnCtrlEnabled" | "automaticLockCtrlEnabled"; @Component({ - selector: 'heatpump-modal', - templateUrl: './modal.component.html', + selector: "heatpump-modal", + templateUrl: "./modal.component.html", }) export class Controller_Io_HeatpumpModalComponent implements OnInit { @@ -46,19 +46,19 @@ export class Controller_Io_HeatpumpModalComponent implements OnInit { } public updateControllerMode(event: CustomEvent) { - const oldMode = this.component.properties['mode']; + const oldMode = this.component.properties["mode"]; const newMode = event.detail.value; if (this.edge != null) { this.edge.updateComponentConfig(this.websocket, this.component.id, [ - { name: 'mode', value: newMode }, + { name: "mode", value: newMode }, ]).then(() => { this.component.properties.mode = newMode; this.formGroup.markAsPristine(); - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); + this.service.toast(this.translate.instant("General.changeAccepted"), "success"); }).catch(reason => { this.component.properties.mode = oldMode; - this.service.toast(this.translate.instant('General.changeFailed') + '\n' + reason.error.message, 'danger'); + this.service.toast(this.translate.instant("General.changeFailed") + "\n" + reason.error.message, "danger"); console.warn(reason); }); } @@ -70,14 +70,14 @@ export class Controller_Io_HeatpumpModalComponent implements OnInit { } public updateManualMode(state: ManualMode) { - this.formGroup.controls['manualState'].setValue(state); - this.formGroup.controls['manualState'].markAsDirty(); + this.formGroup.controls["manualState"].setValue(state); + this.formGroup.controls["manualState"].markAsDirty(); } public applyChanges() { if (this.edge != null) { - if (this.edge.roleIsAtLeast('owner')) { - if (this.formGroup.controls['automaticRecommendationSurplusPower'].value < this.formGroup.controls['automaticForceOnSurplusPower'].value) { + if (this.edge.roleIsAtLeast("owner")) { + if (this.formGroup.controls["automaticRecommendationSurplusPower"].value < this.formGroup.controls["automaticForceOnSurplusPower"].value) { const updateComponentArray = []; Object.keys(this.formGroup.controls).forEach((element, index) => { if (this.formGroup.controls[element].dirty) { @@ -87,20 +87,20 @@ export class Controller_Io_HeatpumpModalComponent implements OnInit { this.loading = true; this.edge.updateComponentConfig(this.websocket, this.component.id, updateComponentArray).then(() => { this.component.properties.manualState = this.formGroup.value.manualState; - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); + this.service.toast(this.translate.instant("General.changeAccepted"), "success"); this.loading = false; }).catch(reason => { - this.formGroup.controls['minTime'].setValue(this.component.properties.manualState); - this.service.toast(this.translate.instant('General.changeFailed') + '\n' + reason, 'danger'); + this.formGroup.controls["minTime"].setValue(this.component.properties.manualState); + this.service.toast(this.translate.instant("General.changeFailed") + "\n" + reason, "danger"); this.loading = false; console.warn(reason); }); this.formGroup.markAsPristine(); } else { - this.service.toast(this.translate.instant('Edge.Index.Widgets.HeatPump.relationError'), 'danger'); + this.service.toast(this.translate.instant("Edge.Index.Widgets.HeatPump.relationError"), "danger"); } } else { - this.service.toast(this.translate.instant('General.insufficientRights'), 'danger'); + this.service.toast(this.translate.instant("General.insufficientRights"), "danger"); } } } 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 59bf0a579b8..569e45069ed 100644 --- a/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/Asymmetric.ts +++ b/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/Asymmetric.ts @@ -1,14 +1,14 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { BehaviorSubject } from 'rxjs'; -import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; +import { Component } from "@angular/core"; +import { BehaviorSubject } from "rxjs"; +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; -import { ChannelAddress, CurrentData, Utils } from '../../../../../shared/shared'; -import { Controller_Asymmetric_PeakShavingModalComponent } from './modal/modal.component'; +import { ChannelAddress, CurrentData, Utils } from "../../../../../shared/shared"; +import { Controller_Asymmetric_PeakShavingModalComponent } from "./modal/modal.component"; @Component({ - selector: 'Controller_Asymmetric_PeakShaving', - templateUrl: './Asymmetric.html', + selector: "Controller_Asymmetric_PeakShaving", + templateUrl: "./Asymmetric.html", }) export class Controller_Asymmetric_PeakShavingComponent extends AbstractFlatWidget { @@ -31,24 +31,24 @@ export class Controller_Asymmetric_PeakShavingComponent extends AbstractFlatWidg } protected override getChannelAddresses() { - this.meterId = this.component.properties['meter.id']; + this.meterId = this.component.properties["meter.id"]; return [ - new ChannelAddress(this.meterId, 'ActivePower'), - new ChannelAddress(this.meterId, 'ActivePowerL1'), - new ChannelAddress(this.meterId, 'ActivePowerL2'), - new ChannelAddress(this.meterId, 'ActivePowerL3'), + new ChannelAddress(this.meterId, "ActivePower"), + new ChannelAddress(this.meterId, "ActivePowerL1"), + new ChannelAddress(this.meterId, "ActivePowerL2"), + new ChannelAddress(this.meterId, "ActivePowerL3"), ]; } protected override onCurrentData(currentData: CurrentData) { const activePowerArray: number[] = [ - currentData.allComponents[this.meterId + '/ActivePowerL1'], - currentData.allComponents[this.meterId + '/ActivePowerL2'], - currentData.allComponents[this.meterId + '/ActivePowerL3'], + currentData.allComponents[this.meterId + "/ActivePowerL1"], + currentData.allComponents[this.meterId + "/ActivePowerL2"], + currentData.allComponents[this.meterId + "/ActivePowerL3"], ]; - const name: string[] = ['L1', 'L2', 'L3']; + const name: string[] = ["L1", "L2", "L3"]; this.mostStressedPhase.next({ @@ -57,8 +57,8 @@ export class Controller_Asymmetric_PeakShavingComponent extends AbstractFlatWidg value: Math.max(...activePowerArray, 0), }); - this.peakShavingPower = this.component.properties['peakShavingPower']; - this.rechargePower = this.component.properties['rechargePower']; + this.peakShavingPower = this.component.properties["peakShavingPower"]; + this.rechargePower = this.component.properties["rechargePower"]; } } diff --git a/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/modal/modal.component.ts b/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/modal/modal.component.ts index 327a63386d6..d00c47f25d5 100644 --- a/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/modal/modal.component.ts +++ b/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/modal/modal.component.ts @@ -1,20 +1,20 @@ // @ts-strict-ignore -import { Component, Input, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; -import { ModalController } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; -import { Subject } from 'rxjs'; -import { Edge, EdgeConfig, Service, Websocket } from '../../../../../../shared/shared'; +import { Component, Input, OnInit } from "@angular/core"; +import { FormBuilder, FormControl, FormGroup, Validators } from "@angular/forms"; +import { ModalController } from "@ionic/angular"; +import { TranslateService } from "@ngx-translate/core"; +import { Subject } from "rxjs"; +import { Edge, EdgeConfig, Service, Websocket } from "../../../../../../shared/shared"; @Component({ - selector: 'asymmetricpeakshaving-modal', - templateUrl: './modal.component.html', + selector: "asymmetricpeakshaving-modal", + templateUrl: "./modal.component.html", }) export class Controller_Asymmetric_PeakShavingModalComponent implements OnInit { @Input({ required: true }) protected component!: EdgeConfig.Component; @Input({ required: true }) protected edge!: Edge; - @Input({ required: true }) protected mostStressedPhase!: Subject<{ name: 'L1' | 'L2' | 'L3' | '', value: number }>; + @Input({ required: true }) protected mostStressedPhase!: Subject<{ name: "L1" | "L2" | "L3" | "", value: number }>; public formGroup: FormGroup; public loading: boolean = false; @@ -30,11 +30,11 @@ export class Controller_Asymmetric_PeakShavingModalComponent implements OnInit { ngOnInit() { this.formGroup = this.formBuilder.group({ peakShavingPower: new FormControl(this.component.properties.peakShavingPower, Validators.compose([ - Validators.pattern('^(?:[1-9][0-9]*|0)$'), + Validators.pattern("^(?:[1-9][0-9]*|0)$"), Validators.required, ])), rechargePower: new FormControl(this.component.properties.rechargePower, Validators.compose([ - Validators.pattern('^(?:[1-9][0-9]*|0)$'), + Validators.pattern("^(?:[1-9][0-9]*|0)$"), Validators.required, ])), }); @@ -42,9 +42,9 @@ export class Controller_Asymmetric_PeakShavingModalComponent implements OnInit { applyChanges() { if (this.edge != null) { - if (this.edge.roleIsAtLeast('owner')) { - if (this.formGroup.controls['peakShavingPower'].valid && this.formGroup.controls['rechargePower'].valid) { - if (this.formGroup.controls['peakShavingPower'].value >= this.formGroup.controls['rechargePower'].value) { + if (this.edge.roleIsAtLeast("owner")) { + if (this.formGroup.controls["peakShavingPower"].valid && this.formGroup.controls["rechargePower"].valid) { + if (this.formGroup.controls["peakShavingPower"].value >= this.formGroup.controls["rechargePower"].value) { const updateComponentArray = []; Object.keys(this.formGroup.controls).forEach((element, index) => { if (this.formGroup.controls[element].dirty) { @@ -56,23 +56,23 @@ export class Controller_Asymmetric_PeakShavingModalComponent implements OnInit { this.component.properties.peakShavingPower = this.formGroup.value.peakShavingPower; this.component.properties.rechargePower = this.formGroup.value.rechargePower; this.loading = false; - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); + this.service.toast(this.translate.instant("General.changeAccepted"), "success"); }).catch(reason => { - this.formGroup.controls['peakShavingPower'].setValue(this.component.properties.peakShavingPower); - this.formGroup.controls['rechargePower'].setValue(this.component.properties.rechargePower); + this.formGroup.controls["peakShavingPower"].setValue(this.component.properties.peakShavingPower); + this.formGroup.controls["rechargePower"].setValue(this.component.properties.rechargePower); this.loading = false; - this.service.toast(this.translate.instant('General.changeFailed') + '\n' + reason.error.message, 'danger'); + this.service.toast(this.translate.instant("General.changeFailed") + "\n" + reason.error.message, "danger"); console.warn(reason); }); this.formGroup.markAsPristine(); } else { - this.service.toast(this.translate.instant('Edge.Index.Widgets.Peakshaving.relationError'), 'danger'); + this.service.toast(this.translate.instant("Edge.Index.Widgets.Peakshaving.relationError"), "danger"); } } else { - this.service.toast(this.translate.instant('General.inputNotValid'), 'danger'); + this.service.toast(this.translate.instant("General.inputNotValid"), "danger"); } } else { - this.service.toast(this.translate.instant('General.insufficientRights'), 'danger'); + this.service.toast(this.translate.instant("General.insufficientRights"), "danger"); } } } 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 3700366d4ad..330b0ed6a28 100644 --- a/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/Symmetric.ts +++ b/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/Symmetric.ts @@ -1,13 +1,13 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; +import { Component } from "@angular/core"; +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; -import { ChannelAddress, CurrentData, Utils } from '../../../../../shared/shared'; -import { Controller_Symmetric_PeakShavingModalComponent } from './modal/modal.component'; +import { ChannelAddress, CurrentData, Utils } from "../../../../../shared/shared"; +import { Controller_Symmetric_PeakShavingModalComponent } from "./modal/modal.component"; @Component({ - selector: 'Controller_Symmetric_PeakShaving', - templateUrl: './Symmetric.html', + selector: "Controller_Symmetric_PeakShaving", + templateUrl: "./Symmetric.html", }) export class Controller_Symmetric_PeakShavingComponent extends AbstractFlatWidget { @@ -29,19 +29,19 @@ export class Controller_Symmetric_PeakShavingComponent extends AbstractFlatWidge protected override getChannelAddresses() { return [ - new ChannelAddress(this.component.properties['meter.id'], 'ActivePower'), - new ChannelAddress(this.componentId, '_PropertyPeakShavingPower'), - new ChannelAddress(this.componentId, '_PropertyRechargePower'), + new ChannelAddress(this.component.properties["meter.id"], "ActivePower"), + new ChannelAddress(this.componentId, "_PropertyPeakShavingPower"), + new ChannelAddress(this.componentId, "_PropertyRechargePower"), ]; } protected override onCurrentData(currentData: CurrentData) { // Show 0 for negative activePower - this.activePower = currentData.allComponents[this.component.properties['meter.id'] + '/ActivePower'] >= 0 - ? currentData.allComponents[this.component.properties['meter.id'] + '/ActivePower'] : 0; - this.peakShavingPower = this.component.properties['peakShavingPower']; - this.rechargePower = this.component.properties['rechargePower']; + this.activePower = currentData.allComponents[this.component.properties["meter.id"] + "/ActivePower"] >= 0 + ? currentData.allComponents[this.component.properties["meter.id"] + "/ActivePower"] : 0; + this.peakShavingPower = this.component.properties["peakShavingPower"]; + this.rechargePower = this.component.properties["rechargePower"]; } } diff --git a/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/modal/modal.component.ts b/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/modal/modal.component.ts index b733e98f5b9..aa2f498dc60 100644 --- a/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/modal/modal.component.ts +++ b/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/modal/modal.component.ts @@ -1,13 +1,13 @@ // @ts-strict-ignore -import { Component, Input, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; -import { ModalController } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; -import { Edge, EdgeConfig, Service, Websocket } from '../../../../../../shared/shared'; +import { Component, Input, OnInit } from "@angular/core"; +import { FormBuilder, FormControl, FormGroup, Validators } from "@angular/forms"; +import { ModalController } from "@ionic/angular"; +import { TranslateService } from "@ngx-translate/core"; +import { Edge, EdgeConfig, Service, Websocket } from "../../../../../../shared/shared"; @Component({ - selector: 'symmetricpeakshaving-modal', - templateUrl: './modal.component.html', + selector: "symmetricpeakshaving-modal", + templateUrl: "./modal.component.html", }) export class Controller_Symmetric_PeakShavingModalComponent implements OnInit { @@ -29,11 +29,11 @@ export class Controller_Symmetric_PeakShavingModalComponent implements OnInit { ngOnInit() { this.formGroup = this.formBuilder.group({ peakShavingPower: new FormControl(this.component.properties.peakShavingPower, Validators.compose([ - Validators.pattern('^(?:[1-9][0-9]*|0)$'), + Validators.pattern("^(?:[1-9][0-9]*|0)$"), Validators.required, ])), rechargePower: new FormControl(this.component.properties.rechargePower, Validators.compose([ - Validators.pattern('^(?:[1-9][0-9]*|0)$'), + Validators.pattern("^(?:[1-9][0-9]*|0)$"), Validators.required, ])), }); @@ -41,9 +41,9 @@ export class Controller_Symmetric_PeakShavingModalComponent implements OnInit { applyChanges() { if (this.edge != null) { - if (this.edge.roleIsAtLeast('owner')) { - const peakShavingPower = this.formGroup.controls['peakShavingPower']; - const rechargePower = this.formGroup.controls['rechargePower']; + if (this.edge.roleIsAtLeast("owner")) { + const peakShavingPower = this.formGroup.controls["peakShavingPower"]; + const rechargePower = this.formGroup.controls["rechargePower"]; if (peakShavingPower.valid && rechargePower.valid) { if (peakShavingPower.value >= rechargePower.value) { const updateComponentArray = []; @@ -57,23 +57,23 @@ export class Controller_Symmetric_PeakShavingModalComponent implements OnInit { this.component.properties.peakShavingPower = peakShavingPower.value; this.component.properties.rechargePower = rechargePower.value; this.loading = false; - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); + this.service.toast(this.translate.instant("General.changeAccepted"), "success"); }).catch(reason => { peakShavingPower.setValue(this.component.properties.peakShavingPower); rechargePower.setValue(this.component.properties.rechargePower); this.loading = false; - this.service.toast(this.translate.instant('General.changeFailed') + '\n' + reason.error.message, 'danger'); + this.service.toast(this.translate.instant("General.changeFailed") + "\n" + reason.error.message, "danger"); console.warn(reason); }); this.formGroup.markAsPristine(); } else { - this.service.toast(this.translate.instant('Edge.Index.Widgets.Peakshaving.relationError'), 'danger'); + this.service.toast(this.translate.instant("Edge.Index.Widgets.Peakshaving.relationError"), "danger"); } } else { - this.service.toast(this.translate.instant('General.inputNotValid'), 'danger'); + this.service.toast(this.translate.instant("General.inputNotValid"), "danger"); } } else { - this.service.toast(this.translate.instant('General.insufficientRights'), 'danger'); + this.service.toast(this.translate.instant("General.insufficientRights"), "danger"); } } } 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 6d8ed6784c2..22c4eb19193 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,13 +1,13 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; +import { Component } from "@angular/core"; +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; -import { ChannelAddress, CurrentData, Utils } from '../../../../../shared/shared'; -import { Controller_Symmetric_TimeSlot_PeakShavingModalComponent } from './modal/modal.component'; +import { ChannelAddress, CurrentData, Utils } from "../../../../../shared/shared"; +import { Controller_Symmetric_TimeSlot_PeakShavingModalComponent } from "./modal/modal.component"; @Component({ - selector: 'Controller_Symmetric_TimeSlot_PeakShaving', - templateUrl: './Symmetric_TimeSlot.html', + selector: "Controller_Symmetric_TimeSlot_PeakShaving", + templateUrl: "./Symmetric_TimeSlot.html", }) export class Controller_Symmetric_TimeSlot_PeakShavingComponent extends AbstractFlatWidget { @@ -34,18 +34,18 @@ export class Controller_Symmetric_TimeSlot_PeakShavingComponent extends Abstract protected override getChannelAddresses() { return [ - new ChannelAddress(this.component.properties['meter.id'], 'ActivePower'), - new ChannelAddress(this.componentId, '_PropertyPeakShavingPower'), - new ChannelAddress(this.componentId, '_PropertyRechargePower'), + new ChannelAddress(this.component.properties["meter.id"], "ActivePower"), + new ChannelAddress(this.componentId, "_PropertyPeakShavingPower"), + new ChannelAddress(this.componentId, "_PropertyRechargePower"), ]; } protected override onCurrentData(currentData: CurrentData) { // activePower is 0 for negative Values - this.activePower = currentData.allComponents[this.component.properties['meter.id'] + '/ActivePower'] >= 0 - ? currentData.allComponents[this.component.properties['meter.id'] + '/ActivePower'] : 0; - this.peakShavingPower = this.component.properties['peakShavingPower']; - this.rechargePower = this.component.properties['rechargePower']; + this.activePower = currentData.allComponents[this.component.properties["meter.id"] + "/ActivePower"] >= 0 + ? currentData.allComponents[this.component.properties["meter.id"] + "/ActivePower"] : 0; + this.peakShavingPower = this.component.properties["peakShavingPower"]; + this.rechargePower = this.component.properties["rechargePower"]; } } diff --git a/ui/src/app/edge/live/Controller/PeakShaving/Symmetric_TimeSlot/modal/modal.component.ts b/ui/src/app/edge/live/Controller/PeakShaving/Symmetric_TimeSlot/modal/modal.component.ts index 3655790047f..21f16820d4b 100644 --- a/ui/src/app/edge/live/Controller/PeakShaving/Symmetric_TimeSlot/modal/modal.component.ts +++ b/ui/src/app/edge/live/Controller/PeakShaving/Symmetric_TimeSlot/modal/modal.component.ts @@ -1,13 +1,13 @@ // @ts-strict-ignore -import { Component, Input, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; -import { ModalController } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; -import { Edge, EdgeConfig, Service, Websocket } from '../../../../../../shared/shared'; +import { Component, Input, OnInit } from "@angular/core"; +import { FormBuilder, FormControl, FormGroup, Validators } from "@angular/forms"; +import { ModalController } from "@ionic/angular"; +import { TranslateService } from "@ngx-translate/core"; +import { Edge, EdgeConfig, Service, Websocket } from "../../../../../../shared/shared"; @Component({ - selector: 'timeslotpeakshaving-modal', - templateUrl: './modal.component.html', + selector: "timeslotpeakshaving-modal", + templateUrl: "./modal.component.html", }) export class Controller_Symmetric_TimeSlot_PeakShavingModalComponent implements OnInit { @@ -30,29 +30,29 @@ export class Controller_Symmetric_TimeSlot_PeakShavingModalComponent implements ngOnInit() { this.formGroup = this.formBuilder.group({ peakShavingPower: new FormControl(this.component.properties.peakShavingPower, Validators.compose([ - Validators.pattern('^(?:[1-9][0-9]*|0)$'), + Validators.pattern("^(?:[1-9][0-9]*|0)$"), Validators.required, ])), rechargePower: new FormControl(this.component.properties.rechargePower, Validators.compose([ - Validators.pattern('^(?:[1-9][0-9]*|0)$'), + Validators.pattern("^(?:[1-9][0-9]*|0)$"), Validators.required, ])), slowChargePower: new FormControl((this.component.properties.slowChargePower) * -1), slowChargeStartTime: new FormControl(this.component.properties.slowChargeStartTime, Validators.compose([ - Validators.pattern('^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$'), + Validators.pattern("^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$"), Validators.required, ])), startDate: new FormControl(this.component.properties.startDate, Validators.compose([ - Validators.pattern('^(0[1-9]|[12][0-9]|3[01])[.](0[1-9]|1[012])[.](19|20)[0-9]{2}$'), + Validators.pattern("^(0[1-9]|[12][0-9]|3[01])[.](0[1-9]|1[012])[.](19|20)[0-9]{2}$"), Validators.required, ])), startTime: new FormControl(this.component.properties.startTime, Validators.compose([ - Validators.pattern('^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$'), + Validators.pattern("^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$"), Validators.required, ])), endDate: new FormControl(this.component.properties.endDate), endTime: new FormControl(this.component.properties.endTime, Validators.compose([ - Validators.pattern('^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$'), + Validators.pattern("^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$"), Validators.required, ])), monday: new FormControl(this.component.properties.monday), @@ -67,15 +67,15 @@ export class Controller_Symmetric_TimeSlot_PeakShavingModalComponent implements applyChanges() { if (this.edge != null) { - if (this.edge.roleIsAtLeast('owner')) { - const peakShavingPower = this.formGroup.controls['peakShavingPower']; - const rechargePower = this.formGroup.controls['rechargePower']; + if (this.edge.roleIsAtLeast("owner")) { + const peakShavingPower = this.formGroup.controls["peakShavingPower"]; + const rechargePower = this.formGroup.controls["rechargePower"]; if (peakShavingPower.valid && rechargePower.valid) { if (peakShavingPower.value >= rechargePower.value) { const updateComponentArray = []; Object.keys(this.formGroup.controls).forEach((element, index) => { if (this.formGroup.controls[element].dirty) { - if (Object.keys(this.formGroup.controls)[index] == 'slowChargePower') { + if (Object.keys(this.formGroup.controls)[index] == "slowChargePower") { updateComponentArray.push({ name: Object.keys(this.formGroup.controls)[index], value: (this.formGroup.controls[element].value) * -1 }); } else { updateComponentArray.push({ name: Object.keys(this.formGroup.controls)[index], value: this.formGroup.controls[element].value }); @@ -87,23 +87,23 @@ export class Controller_Symmetric_TimeSlot_PeakShavingModalComponent implements this.component.properties.peakShavingPower = peakShavingPower.value; this.component.properties.rechargePower = rechargePower.value; this.loading = false; - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); + this.service.toast(this.translate.instant("General.changeAccepted"), "success"); }).catch(reason => { peakShavingPower.setValue(this.component.properties.peakShavingPower); rechargePower.setValue(this.component.properties.rechargePower); this.loading = false; - this.service.toast(this.translate.instant('General.changeFailed') + '\n' + reason.error.message, 'danger'); + this.service.toast(this.translate.instant("General.changeFailed") + "\n" + reason.error.message, "danger"); console.warn(reason); }); this.formGroup.markAsPristine(); } else { - this.service.toast(this.translate.instant('Edge.Index.Widgets.Peakshaving.relationError'), 'danger'); + this.service.toast(this.translate.instant("Edge.Index.Widgets.Peakshaving.relationError"), "danger"); } } else { - this.service.toast(this.translate.instant('General.inputNotValid'), 'danger'); + this.service.toast(this.translate.instant("General.inputNotValid"), "danger"); } } else { - this.service.toast(this.translate.instant('General.insufficientRights'), 'danger'); + this.service.toast(this.translate.instant("General.insufficientRights"), "danger"); } } } 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 0c64f49d90c..091f47eff6c 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,12 +1,12 @@ -import { Component } from '@angular/core'; -import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; -import { EdgeConfig } from 'src/app/shared/shared'; +import { Component } from "@angular/core"; +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; +import { EdgeConfig } from "src/app/shared/shared"; -import { Io_Api_DigitalInput_ModalComponent } from './modal/modal.component'; +import { Io_Api_DigitalInput_ModalComponent } from "./modal/modal.component"; @Component({ - selector: 'Io_Api_DigitalInput', - templateUrl: './Io_Api_DigitalInput.html', + selector: "Io_Api_DigitalInput", + templateUrl: "./Io_Api_DigitalInput.html", }) export class Io_Api_DigitalInputComponent extends AbstractFlatWidget { diff --git a/ui/src/app/edge/live/Io/Api_DigitalInput/modal/modal.component.ts b/ui/src/app/edge/live/Io/Api_DigitalInput/modal/modal.component.ts index fe0490cb871..199010f1217 100644 --- a/ui/src/app/edge/live/Io/Api_DigitalInput/modal/modal.component.ts +++ b/ui/src/app/edge/live/Io/Api_DigitalInput/modal/modal.component.ts @@ -1,14 +1,14 @@ // @ts-strict-ignore -import { Component, Input, OnDestroy, OnInit } from '@angular/core'; -import { ModalController } from '@ionic/angular'; -import { JsonrpcRequest, JsonrpcResponseSuccess } from 'src/app/shared/jsonrpc/base'; -import { ComponentJsonApiRequest } from 'src/app/shared/jsonrpc/request/componentJsonApiRequest'; -import { Channel } from 'src/app/shared/jsonrpc/response/getChannelsOfComponentResponse'; -import { ChannelAddress, Edge, EdgeConfig, EdgePermission, Service, Websocket } from '../../../../../shared/shared'; +import { Component, Input, OnDestroy, OnInit } from "@angular/core"; +import { ModalController } from "@ionic/angular"; +import { JsonrpcRequest, JsonrpcResponseSuccess } from "src/app/shared/jsonrpc/base"; +import { ComponentJsonApiRequest } from "src/app/shared/jsonrpc/request/componentJsonApiRequest"; +import { Channel } from "src/app/shared/jsonrpc/response/getChannelsOfComponentResponse"; +import { ChannelAddress, Edge, EdgeConfig, EdgePermission, Service, Websocket } from "../../../../../shared/shared"; @Component({ - selector: 'Io_Api_DigitalInputModal', - templateUrl: './modal.component.html', + selector: "Io_Api_DigitalInputModal", + templateUrl: "./modal.component.html", }) export class Io_Api_DigitalInput_ModalComponent implements OnInit, OnDestroy { private static readonly SELECTOR = "Io_Api_DigitalInput_ModalComponent"; @@ -46,13 +46,13 @@ export class Io_Api_DigitalInput_ModalComponent implements OnInit, OnDestroy { componentAlias: e.alias, channels: Object.entries(e.channels) .filter(([key, value]) => { - if (value.accessMode !== 'RO') { + if (value.accessMode !== "RO") { return false; } - if (value.type !== 'BOOLEAN') { + if (value.type !== "BOOLEAN") { return false; } - if (key === '_PropertyEnabled') { + if (key === "_PropertyEnabled") { return false; } return true; @@ -65,7 +65,7 @@ export class Io_Api_DigitalInput_ModalComponent implements OnInit, OnDestroy { } const response = await this.edge.sendRequest(this.websocket, new ComponentJsonApiRequest({ - componentId: '_componentManager', + componentId: "_componentManager", payload: new GetDigitalInputChannelsOfComponentsRequest({ componentIds: this.ioComponents.map(e => e.id) }), })); return response.result.channelsPerComponent.map(e => { 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 830159e6d27..0fa1fbf2ea2 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,13 +1,13 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; +import { Component } from "@angular/core"; +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; -import { ChannelAddress, CurrentData, EdgeConfig, Utils } from '../../../../shared/shared'; -import { Evcs_Api_ClusterModalComponent } from './modal/evcsCluster-modal.page'; +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', + selector: "Evcs_Api_Cluster", + templateUrl: "./Evcs_Api_Cluster.html", }) export class Evcs_Api_ClusterComponent extends AbstractFlatWidget { @@ -36,7 +36,7 @@ export class Evcs_Api_ClusterComponent extends AbstractFlatWidget { protected override getChannelAddresses() { this.evcsIdsInCluster = this.config.components[this.componentId].properties["evcs.ids"]; - const nature = 'io.openems.edge.evcs.api.Evcs'; + const nature = "io.openems.edge.evcs.api.Evcs"; for (const component of this.config.getComponentsImplementingNature(nature)) { if (this.evcsIdsInCluster.includes(component.id)) { @@ -45,14 +45,14 @@ export class Evcs_Api_ClusterComponent extends AbstractFlatWidget { } } this.channelAddresses.push( - 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'), - new ChannelAddress(this.componentId, 'MinimumHardwarePower'), - new ChannelAddress(this.componentId, 'MaximumHardwarePower'), + 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"), + new ChannelAddress(this.componentId, "MinimumHardwarePower"), + new ChannelAddress(this.componentId, "MaximumHardwarePower"), ); return this.channelAddresses; } @@ -60,8 +60,8 @@ export class Evcs_Api_ClusterComponent extends AbstractFlatWidget { 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'; - this.isConnectionSuccessful = currentData.allComponents[this.componentId + '/State'] != 3 ? true : false; + this.alias = this.config.components[this.componentId].properties.alias ?? "Edge.Index.Widgets.EVCS.chargingStationCluster"; + this.isConnectionSuccessful = currentData.allComponents[this.componentId + "/State"] != 3 ? true : false; // Initialise the Map with all evcss this.evcssInCluster.forEach(evcs => { @@ -72,8 +72,8 @@ export class Evcs_Api_ClusterComponent extends AbstractFlatWidget { // Adds the controllers to the each charging stations controllers.forEach(controller => { - if (this.evcsIdsInCluster.includes(controller.properties['evcs.id'])) { - this.evcsMap[controller.properties['evcs.id']] = controller; + if (this.evcsIdsInCluster.includes(controller.properties["evcs.id"])) { + this.evcsMap[controller.properties["evcs.id"]] = controller; } }); @@ -81,16 +81,16 @@ export class Evcs_Api_ClusterComponent extends AbstractFlatWidget { private fillChannelAddresses(componentId: string, channelAddresses: ChannelAddress[]) { channelAddresses.push( - new ChannelAddress(componentId, 'ChargePower'), - new ChannelAddress(componentId, 'MaximumHardwarePower'), - new ChannelAddress(componentId, 'MinimumHardwarePower'), - new ChannelAddress(componentId, 'MaximumPower'), - new ChannelAddress(componentId, 'Phases'), - new ChannelAddress(componentId, 'Plug'), - new ChannelAddress(componentId, 'Status'), - new ChannelAddress(componentId, 'State'), - new ChannelAddress(componentId, 'EnergySession'), - new ChannelAddress(componentId, 'Alias'), + new ChannelAddress(componentId, "ChargePower"), + new ChannelAddress(componentId, "MaximumHardwarePower"), + new ChannelAddress(componentId, "MinimumHardwarePower"), + new ChannelAddress(componentId, "MaximumPower"), + new ChannelAddress(componentId, "Phases"), + new ChannelAddress(componentId, "Plug"), + new ChannelAddress(componentId, "Status"), + new ChannelAddress(componentId, "State"), + new ChannelAddress(componentId, "EnergySession"), + new ChannelAddress(componentId, "Alias"), ); } diff --git a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcs-chart/evcs.chart.ts b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcs-chart/evcs.chart.ts index 426c5ad9ec5..f58fe7b24a2 100644 --- a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcs-chart/evcs.chart.ts +++ b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcs-chart/evcs.chart.ts @@ -1,15 +1,15 @@ // @ts-strict-ignore -import { Component, Input, OnChanges, OnInit } from '@angular/core'; -import { ModalController } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; -import * as Chart from 'chart.js'; -import { Data } from 'src/app/edge/history/shared'; -import { CurrentData } from 'src/app/shared/components/edge/currentdata'; -import { Edge, EdgeConfig } from 'src/app/shared/shared'; +import { Component, Input, OnChanges, OnInit } from "@angular/core"; +import { ModalController } from "@ionic/angular"; +import { TranslateService } from "@ngx-translate/core"; +import * as Chart from "chart.js"; +import { Data } from "src/app/edge/history/shared"; +import { CurrentData } from "src/app/shared/components/edge/currentdata"; +import { Edge, EdgeConfig } from "src/app/shared/shared"; @Component({ selector: EvcsChartComponent.SELECTOR, - templateUrl: './evcs.chart.html', + templateUrl: "./evcs.chart.html", }) export class EvcsChartComponent implements OnInit, OnChanges { @@ -34,8 +34,8 @@ export class EvcsChartComponent implements OnInit, OnChanges { getMaxPower() { const minPower = 22; - let maxHW = this.currentData[this.componentId + '/MaximumHardwarePower']; - let chargePower = this.currentData[this.componentId + '/ChargePower']; + let maxHW = this.currentData[this.componentId + "/MaximumHardwarePower"]; + let chargePower = this.currentData[this.componentId + "/ChargePower"]; maxHW = maxHW == null ? minPower : maxHW / 1000; chargePower = chargePower == null ? 0 : chargePower / 1000; @@ -47,9 +47,9 @@ export class EvcsChartComponent implements OnInit, OnChanges { this.options = DEFAULT_BAR_CHART_OPTIONS; this.options.scales.yAxes[0].ticks.max = this.getMaxPower(); - this.labels = ['Ladeleistung']; + this.labels = ["Ladeleistung"]; this.datasets = [ - { data: [], label: '' }, + { data: [], label: "" }, ]; } @@ -67,7 +67,7 @@ export class EvcsChartComponent implements OnInit, OnChanges { this.loading = true; let index = 0; for (const evcsId in this.evcsMap) { - const chargePower = this.edge.currentData.value.channel[evcsId + '/ChargePower']; + const chargePower = this.edge.currentData.value.channel[evcsId + "/ChargePower"]; const chargePowerKW = chargePower / 1000.0; const alias = this.evcsConfigMap[evcsId].properties.alias; if (this.datasets[index] == null) { @@ -91,7 +91,7 @@ export class EvcsChartComponent implements OnInit, OnChanges { export const DEFAULT_BAR_CHART_OPTIONS: BarChartOptions = { maintainAspectRatio: false, legend: { - position: 'bottom', + position: "bottom", }, elements: { point: { @@ -105,7 +105,7 @@ export const DEFAULT_BAR_CHART_OPTIONS: BarChartOptions = { }, }, hover: { - mode: 'point', + mode: "point", intersect: true, }, scales: { @@ -125,30 +125,30 @@ export const DEFAULT_BAR_CHART_OPTIONS: BarChartOptions = { }], }, tooltips: { - mode: 'index', + mode: "index", intersect: false, - axis: 'x', + axis: "x", title: "Ladeleistung", callbacks: { label(tooltipItems: BarChartTooltipItem, data: Data): string { let value: number = tooltipItems.yLabel; //.toFixed(2); value = parseFloat(value.toFixed(2)); const label = data.datasets[tooltipItems.datasetIndex].label; - return label + ": " + value.toLocaleString('de-DE') + " kW"; + return label + ": " + value.toLocaleString("de-DE") + " kW"; }, }, }, annotation: { annotations: [{ - type: 'line', - mode: 'horizontal', - yScaleID: 'y-axis-0', + type: "line", + mode: "horizontal", + yScaleID: "y-axis-0", value: 33, - borderColor: 'green', + borderColor: "green", borderWidth: 4, label: { enabled: true, - content: 'Test label', + content: "Test label", }, }], }, diff --git a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcsCluster-modal.page.ts b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcsCluster-modal.page.ts index 219e685ada7..3fbac0a50c9 100644 --- a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcsCluster-modal.page.ts +++ b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcsCluster-modal.page.ts @@ -1,16 +1,16 @@ // @ts-strict-ignore -import { Component, Input, OnInit, ViewChild } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; -import { IonReorderGroup, ModalController } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; -import { Edge, EdgeConfig, Service, Websocket } from 'src/app/shared/shared'; +import { Component, Input, OnInit, ViewChild } from "@angular/core"; +import { ActivatedRoute, Router } from "@angular/router"; +import { IonReorderGroup, ModalController } from "@ionic/angular"; +import { TranslateService } from "@ngx-translate/core"; +import { Edge, EdgeConfig, Service, Websocket } from "src/app/shared/shared"; -type ChargeMode = 'FORCE_CHARGE' | 'EXCESS_POWER'; -type Priority = 'CAR' | 'STORAGE'; +type ChargeMode = "FORCE_CHARGE" | "EXCESS_POWER"; +type Priority = "CAR" | "STORAGE"; @Component({ - selector: 'Evcs_Api_Cluster-modal', - templateUrl: './evcsCluster-modal.page.html', + selector: "Evcs_Api_Cluster-modal", + templateUrl: "./evcsCluster-modal.page.html", }) export class Evcs_Api_ClusterModalComponent implements OnInit { @@ -25,7 +25,7 @@ export class Evcs_Api_ClusterModalComponent implements OnInit { public swiperIndex: number = 0; public slideOpts = { noSwiping: true, - noSwipingClass: 'swiper-no-swiping', + noSwipingClass: "swiper-no-swiping", //noSwipingSelector: 'ion-range, ion-toggle', initialSlide: 0, speed: 1000, @@ -71,13 +71,13 @@ export class Evcs_Api_ClusterModalComponent implements OnInit { if (this.edge != null) { this.edge.updateComponentConfig(this.websocket, this.config.id, [ - { name: 'evcs.ids', value: newListOrder }, + { name: "evcs.ids", value: newListOrder }, ]).then(response => { this.config.properties.chargeMode = newListOrder; - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); + this.service.toast(this.translate.instant("General.changeAccepted"), "success"); }).catch(reason => { this.config.properties.chargeMode = oldListOrder; - this.service.toast(this.translate.instant('General.changeFailed') + '\n' + reason.error.message, 'danger'); + this.service.toast(this.translate.instant("General.changeFailed") + "\n" + reason.error.message, "danger"); console.warn(reason); }); } @@ -97,23 +97,23 @@ export class Evcs_Api_ClusterModalComponent implements OnInit { let newChargeMode: ChargeMode; switch (event.detail.value) { - case 'FORCE_CHARGE': - newChargeMode = 'FORCE_CHARGE'; + case "FORCE_CHARGE": + newChargeMode = "FORCE_CHARGE"; break; - case 'EXCESS_POWER': - newChargeMode = 'EXCESS_POWER'; + case "EXCESS_POWER": + newChargeMode = "EXCESS_POWER"; break; } if (this.edge != null) { this.edge.updateComponentConfig(this.websocket, currentController.id, [ - { name: 'chargeMode', value: newChargeMode }, + { name: "chargeMode", value: newChargeMode }, ]).then(response => { currentController.properties.chargeMode = newChargeMode; - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); + this.service.toast(this.translate.instant("General.changeAccepted"), "success"); }).catch(reason => { currentController.properties.chargeMode = oldChargeMode; - this.service.toast(this.translate.instant('General.changeFailed') + '\n' + reason.error.message, 'danger'); + this.service.toast(this.translate.instant("General.changeFailed") + "\n" + reason.error.message, "danger"); console.warn(reason); }); } @@ -126,23 +126,23 @@ export class Evcs_Api_ClusterModalComponent implements OnInit { let newPriority: Priority; switch (event.detail.value) { - case 'CAR': - newPriority = 'CAR'; + case "CAR": + newPriority = "CAR"; break; - case 'STORAGE': - newPriority = 'STORAGE'; + case "STORAGE": + newPriority = "STORAGE"; break; } if (this.edge != null) { this.edge.updateComponentConfig(this.websocket, currentController.id, [ - { name: 'priority', value: newPriority }, + { name: "priority", value: newPriority }, ]).then(response => { currentController.properties.priority = newPriority; - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); + 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'); + this.service.toast(this.translate.instant("General.changeFailed") + "\n" + reason.error.message, "danger"); console.warn(reason); }); } @@ -160,13 +160,13 @@ export class Evcs_Api_ClusterModalComponent implements OnInit { if (this.edge != null) { this.edge.updateComponentConfig(this.websocket, currentController.id, [ - { name: 'forceChargeMinPower', value: newMinChargePower }, + { name: "forceChargeMinPower", value: newMinChargePower }, ]).then(response => { currentController.properties.forceChargeMinPower = newMinChargePower; - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); + 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'); + this.service.toast(this.translate.instant("General.changeFailed") + "\n" + reason.error.message, "danger"); console.warn(reason); }); } @@ -183,13 +183,13 @@ export class Evcs_Api_ClusterModalComponent implements OnInit { if (this.edge != null) { this.edge.updateComponentConfig(this.websocket, currentController.id, [ - { name: 'defaultChargeMinPower', value: newMinChargePower }, + { name: "defaultChargeMinPower", value: newMinChargePower }, ]).then(response => { currentController.properties.defaultChargeMinPower = newMinChargePower; - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); + 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'); + this.service.toast(this.translate.instant("General.changeFailed") + "\n" + reason.error.message, "danger"); console.warn(reason); }); } @@ -215,13 +215,13 @@ export class Evcs_Api_ClusterModalComponent implements OnInit { } if (this.edge != null) { this.edge.updateComponentConfig(this.websocket, currentController.id, [ - { name: 'defaultChargeMinPower', value: newMinChargePower }, + { name: "defaultChargeMinPower", value: newMinChargePower }, ]).then(response => { currentController.properties.defaultChargeMinPower = newMinChargePower; - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); + 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'); + this.service.toast(this.translate.instant("General.changeFailed") + "\n" + reason.error.message, "danger"); console.warn(reason); }); } @@ -238,13 +238,13 @@ export class Evcs_Api_ClusterModalComponent implements OnInit { const newChargingState = !oldChargingState; if (this.edge != null) { this.edge.updateComponentConfig(this.websocket, currentController.id, [ - { name: 'enabledCharging', value: newChargingState }, + { name: "enabledCharging", value: newChargingState }, ]).then(response => { currentController.properties.enabledCharging = newChargingState; - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); + 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'); + this.service.toast(this.translate.instant("General.changeFailed") + "\n" + reason.error.message, "danger"); console.warn(reason); }); } @@ -259,7 +259,7 @@ export class Evcs_Api_ClusterModalComponent implements OnInit { getState(power: number, state: number, plug: number, currentController: EdgeConfig.Component) { if (currentController != null) { if (currentController.properties.enabledCharging != null && currentController.properties.enabledCharging == false) { - return this.translate.instant('Edge.Index.Widgets.EVCS.chargingStationDeactivated'); + return this.translate.instant("Edge.Index.Widgets.EVCS.chargingStationDeactivated"); } } if (power == null || power == 0) { @@ -269,31 +269,33 @@ export class Evcs_Api_ClusterModalComponent implements OnInit { if (this.chargePlug == null) { if (this.chargeState == null) { - return this.translate.instant('Edge.Index.Widgets.EVCS.notCharging'); + return this.translate.instant("Edge.Index.Widgets.EVCS.notCharging"); } } else if (this.chargePlug != ChargePlug.PLUGGED_ON_EVCS_AND_ON_EV_AND_LOCKED) { - return this.translate.instant('Edge.Index.Widgets.EVCS.cableNotConnected'); + return this.translate.instant("Edge.Index.Widgets.EVCS.cableNotConnected"); } switch (this.chargeState) { case ChargeState.STARTING: - return this.translate.instant('Edge.Index.Widgets.EVCS.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'); + return this.translate.instant("Edge.Index.Widgets.EVCS.error"); case ChargeState.READY_FOR_CHARGING: - return this.translate.instant('Edge.Index.Widgets.EVCS.readyForCharging'); + return this.translate.instant("Edge.Index.Widgets.EVCS.readyForCharging"); case ChargeState.NOT_READY_FOR_CHARGING: - return this.translate.instant('Edge.Index.Widgets.EVCS.notReadyForCharging'); + return this.translate.instant("Edge.Index.Widgets.EVCS.notReadyForCharging"); case ChargeState.AUTHORIZATION_REJECTED: - return this.translate.instant('Edge.Index.Widgets.EVCS.notCharging'); + return this.translate.instant("Edge.Index.Widgets.EVCS.notCharging"); case ChargeState.ENERGY_LIMIT_REACHED: - return this.translate.instant('Edge.Index.Widgets.EVCS.chargeLimitReached'); + return this.translate.instant("Edge.Index.Widgets.EVCS.chargeLimitReached"); case ChargeState.CHARGING_FINISHED: - return this.translate.instant('Edge.Index.Widgets.EVCS.carFull'); + return this.translate.instant("Edge.Index.Widgets.EVCS.carFull"); + default: + return this.translate.instant("Edge.Index.Widgets.EVCS.charging"); } } - return this.translate.instant('Edge.Index.Widgets.EVCS.charging'); + return this.translate.instant("Edge.Index.Widgets.EVCS.charging"); } /** diff --git a/ui/src/app/edge/live/common/autarchy/Common_Autarchy.ts b/ui/src/app/edge/live/common/autarchy/Common_Autarchy.ts index 8aa0d3022b4..e76088f26bf 100644 --- a/ui/src/app/edge/live/common/autarchy/Common_Autarchy.ts +++ b/ui/src/app/edge/live/common/autarchy/Common_Autarchy.ts @@ -1,8 +1,8 @@ -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 { 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"; @NgModule({ imports: [ diff --git a/ui/src/app/edge/live/common/autarchy/flat/flat.ts b/ui/src/app/edge/live/common/autarchy/flat/flat.ts index 085e4388119..e9620384f0e 100644 --- a/ui/src/app/edge/live/common/autarchy/flat/flat.ts +++ b/ui/src/app/edge/live/common/autarchy/flat/flat.ts @@ -1,12 +1,12 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; -import { ChannelAddress, CurrentData, Utils } from 'src/app/shared/shared'; -import { ModalComponent } from '../modal/modal'; +import { Component } from "@angular/core"; +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; +import { ChannelAddress, CurrentData, Utils } from "src/app/shared/shared"; +import { ModalComponent } from "../modal/modal"; @Component({ - selector: 'Common_Autarchy', - templateUrl: './flat.html', + selector: "Common_Autarchy", + templateUrl: "./flat.html", }) export class FlatComponent extends AbstractFlatWidget { @@ -21,15 +21,15 @@ export class FlatComponent extends AbstractFlatWidget { protected override getChannelAddresses(): ChannelAddress[] { return [ - new ChannelAddress('_sum', 'GridActivePower'), - new ChannelAddress('_sum', 'ConsumptionActivePower'), + new ChannelAddress("_sum", "GridActivePower"), + new ChannelAddress("_sum", "ConsumptionActivePower"), ]; } protected override onCurrentData(currentData: CurrentData) { this.percentageValue = Utils.calculateAutarchy( - currentData.allComponents['_sum/GridActivePower'], - currentData.allComponents['_sum/ConsumptionActivePower'], + currentData.allComponents["_sum/GridActivePower"], + currentData.allComponents["_sum/ConsumptionActivePower"], ); } diff --git a/ui/src/app/edge/live/common/autarchy/modal/modal.spec.ts b/ui/src/app/edge/live/common/autarchy/modal/modal.spec.ts index 4c8b585b195..d35e4c7ea81 100644 --- a/ui/src/app/edge/live/common/autarchy/modal/modal.spec.ts +++ b/ui/src/app/edge/live/common/autarchy/modal/modal.spec.ts @@ -12,11 +12,11 @@ export function expectView(testContext: TestContext, viewContext: OeFormlyViewTe expect(generatedView).toEqual(view); } -describe('Autarchy - Modal', () => { +describe("Autarchy - Modal", () => { let TEST_CONTEXT: TestContext; beforeEach(async () => TEST_CONTEXT = await sharedSetup()); - it('generateView()', () => { + it("generateView()", () => { { expectView(TEST_CONTEXT, VIEW_CONTEXT, { title: "Autarkie", diff --git a/ui/src/app/edge/live/common/autarchy/modal/modal.ts b/ui/src/app/edge/live/common/autarchy/modal/modal.ts index 8f9fa5aa219..15ed4d35841 100644 --- a/ui/src/app/edge/live/common/autarchy/modal/modal.ts +++ b/ui/src/app/edge/live/common/autarchy/modal/modal.ts @@ -1,19 +1,19 @@ -import { Component } from '@angular/core'; -import { TranslateService } from '@ngx-translate/core'; -import { AbstractFormlyComponent, OeFormlyView } from 'src/app/shared/components/shared/oe-formly-component'; -import { EdgeConfig } from 'src/app/shared/shared'; -import { Role } from 'src/app/shared/type/role'; +import { Component } from "@angular/core"; +import { TranslateService } from "@ngx-translate/core"; +import { AbstractFormlyComponent, OeFormlyView } from "src/app/shared/components/shared/oe-formly-component"; +import { EdgeConfig } from "src/app/shared/shared"; +import { Role } from "src/app/shared/type/role"; @Component({ - templateUrl: '../../../../../shared/components/formly/formly-field-modal/template.html', + templateUrl: "../../../../../shared/components/formly/formly-field-modal/template.html", }) export class ModalComponent extends AbstractFormlyComponent { public static generateView(translate: TranslateService): OeFormlyView { return { - title: translate.instant('General.autarchy'), + title: translate.instant("General.autarchy"), lines: [{ - type: 'info-line', + type: "info-line", name: translate.instant("Edge.Index.Widgets.autarchyInfo"), }], }; diff --git a/ui/src/app/edge/live/common/consumption/Common_Consumption.ts b/ui/src/app/edge/live/common/consumption/Common_Consumption.ts index f685ef859cf..9b1b800de3e 100644 --- a/ui/src/app/edge/live/common/consumption/Common_Consumption.ts +++ b/ui/src/app/edge/live/common/consumption/Common_Consumption.ts @@ -1,8 +1,8 @@ -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 { 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"; @NgModule({ imports: [ 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 bcc6602c7f0..85b0069083f 100644 --- a/ui/src/app/edge/live/common/consumption/flat/flat.ts +++ b/ui/src/app/edge/live/common/consumption/flat/flat.ts @@ -1,12 +1,12 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; -import { ChannelAddress, CurrentData, EdgeConfig, Utils } from 'src/app/shared/shared'; -import { ModalComponent } from '../modal/modal'; +import { Component } from "@angular/core"; +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; +import { ChannelAddress, CurrentData, EdgeConfig, Utils } from "src/app/shared/shared"; +import { ModalComponent } from "../modal/modal"; @Component({ - selector: 'consumption', - templateUrl: './flat.html', + selector: "consumption", + templateUrl: "./flat.html", }) export class FlatComponent extends AbstractFlatWidget { @@ -27,12 +27,12 @@ export class FlatComponent extends AbstractFlatWidget { protected override getChannelAddresses() { const channelAddresses: ChannelAddress[] = [ - new ChannelAddress('_sum', 'ConsumptionActivePower'), + new ChannelAddress("_sum", "ConsumptionActivePower"), // TODO should be moved to Modal - new ChannelAddress('_sum', 'ConsumptionActivePowerL1'), - new ChannelAddress('_sum', 'ConsumptionActivePowerL2'), - new ChannelAddress('_sum', 'ConsumptionActivePowerL3'), + new ChannelAddress("_sum", "ConsumptionActivePowerL1"), + new ChannelAddress("_sum", "ConsumptionActivePowerL2"), + new ChannelAddress("_sum", "ConsumptionActivePowerL3"), ]; // Get consumptionMeterComponents @@ -41,21 +41,21 @@ export class FlatComponent extends AbstractFlatWidget { for (const component of this.consumptionMeters) { channelAddresses.push( - new ChannelAddress(component.id, 'ActivePower'), - new ChannelAddress(component.id, 'ActivePowerL1'), - new ChannelAddress(component.id, 'ActivePowerL2'), - new ChannelAddress(component.id, 'ActivePowerL3'), + new ChannelAddress(component.id, "ActivePower"), + new ChannelAddress(component.id, "ActivePowerL1"), + new ChannelAddress(component.id, "ActivePowerL2"), + new ChannelAddress(component.id, "ActivePowerL3"), ); } // Get EVCSs this.evcss = this.config.getComponentsImplementingNature("io.openems.edge.evcs.api.Evcs") - .filter(component => !(component.factoryId == 'Evcs.Cluster.SelfConsumption') && - !(component.factoryId == 'Evcs.Cluster.PeakShaving') && !component.isEnabled == false); + .filter(component => !(component.factoryId == "Evcs.Cluster.SelfConsumption") && + !(component.factoryId == "Evcs.Cluster.PeakShaving") && !component.isEnabled == false); for (const component of this.evcss) { channelAddresses.push( - new ChannelAddress(component.id, 'ChargePower'), + new ChannelAddress(component.id, "ChargePower"), ); } return channelAddresses; @@ -65,20 +65,20 @@ export class FlatComponent extends AbstractFlatWidget { this.evcsSumOfChargePower = 0; let consumptionMetersSumOfActivePower: number = 0; - this.sumActivePower = currentData.allComponents['_sum/ConsumptionActivePower']; + this.sumActivePower = currentData.allComponents["_sum/ConsumptionActivePower"]; // TODO move sums to Model // Iterate over evcsComponents to get ChargePower for every component for (const component of this.evcss) { - if (currentData.allComponents[component.id + '/ChargePower']) { - this.evcsSumOfChargePower += currentData.allComponents[component.id + '/ChargePower']; + if (currentData.allComponents[component.id + "/ChargePower"]) { + this.evcsSumOfChargePower += currentData.allComponents[component.id + "/ChargePower"]; } } // Iterate over evcsComponents to get ChargePower for every component for (const component of this.consumptionMeters) { - if (currentData.allComponents[component.id + '/ActivePower']) { - consumptionMetersSumOfActivePower += currentData.allComponents[component.id + '/ActivePower']; + if (currentData.allComponents[component.id + "/ActivePower"]) { + consumptionMetersSumOfActivePower += currentData.allComponents[component.id + "/ActivePower"]; } } diff --git a/ui/src/app/edge/live/common/consumption/modal/modal.spec.ts b/ui/src/app/edge/live/common/consumption/modal/modal.spec.ts index a0daa57a406..d81a191bf67 100644 --- a/ui/src/app/edge/live/common/consumption/modal/modal.spec.ts +++ b/ui/src/app/edge/live/common/consumption/modal/modal.spec.ts @@ -6,19 +6,19 @@ import { sharedSetup } from "src/app/shared/components/shared/testing/utils.spec import { expectView } from "./modal.constants.spec"; -describe('Consumption - Modal', () => { +describe("Consumption - Modal", () => { let TEST_CONTEXT; beforeEach(async () => TEST_CONTEXT = await sharedSetup()); - it('generateView()', () => { + it("generateView()", () => { // No evcs and consumptionMeters and negative ConsumptionActivePower { const VIEW_CONTEXT: OeFormlyViewTester.Context = { - '_sum/ConsumptionActivePower': -1000, - '_sum/ConsumptionActivePowerL1': -1000, - '_sum/ConsumptionActivePowerL2': 1000, - '_sum/ConsumptionActivePowerL3': -1000, + "_sum/ConsumptionActivePower": -1000, + "_sum/ConsumptionActivePowerL1": -1000, + "_sum/ConsumptionActivePowerL2": 1000, + "_sum/ConsumptionActivePowerL3": -1000, }; const EMS = DummyConfig.from(); @@ -46,21 +46,21 @@ describe('Consumption - Modal', () => { DummyConfig.Component.EVCS_KEBA_KECONTACT("evcs2", "Evcs 3"), ); const VIEW_CONTEXT: OeFormlyViewTester.Context = { - '_sum/ConsumptionActivePower': 1000, - '_sum/ConsumptionActivePowerL1': 300, - '_sum/ConsumptionActivePowerL2': 350, - '_sum/ConsumptionActivePowerL3': 350, - 'meter0/ActivePower': 1000, - 'meter0/ActivePowerL1': 1000, - 'meter0/ActivePowerL2': -1000, - 'meter0/ActivePowerL3': 1000, - 'meter1/ActivePower': null, - 'meter1/ActivePowerL1': null, - 'meter1/ActivePowerL2': null, - 'meter1/ActivePowerL3': null, - 'evcs0/ChargePower': 1000, - 'evcs1/ChargePower': -1000, - 'evcs2/ChargePower': null, + "_sum/ConsumptionActivePower": 1000, + "_sum/ConsumptionActivePowerL1": 300, + "_sum/ConsumptionActivePowerL2": 350, + "_sum/ConsumptionActivePowerL3": 350, + "meter0/ActivePower": 1000, + "meter0/ActivePowerL1": 1000, + "meter0/ActivePowerL2": -1000, + "meter0/ActivePowerL3": 1000, + "meter1/ActivePower": null, + "meter1/ActivePowerL1": null, + "meter1/ActivePowerL2": null, + "meter1/ActivePowerL3": null, + "evcs0/ChargePower": 1000, + "evcs1/ChargePower": -1000, + "evcs2/ChargePower": null, }; expectView(EMS, VIEW_CONTEXT, TEST_CONTEXT, { @@ -99,11 +99,11 @@ describe('Consumption - Modal', () => { DummyConfig.Component.EVCS_KEBA_KECONTACT("evcs0", "Evcs"), ); const VIEW_CONTEXT: OeFormlyViewTester.Context = { - '_sum/ConsumptionActivePower': 1000, - '_sum/ConsumptionActivePowerL1': 300, - '_sum/ConsumptionActivePowerL2': 350, - '_sum/ConsumptionActivePowerL3': 350, - 'evcs0/ChargePower': 1000, + "_sum/ConsumptionActivePower": 1000, + "_sum/ConsumptionActivePowerL1": 300, + "_sum/ConsumptionActivePowerL2": 350, + "_sum/ConsumptionActivePowerL3": 350, + "evcs0/ChargePower": 1000, }; expectView(EMS, VIEW_CONTEXT, TEST_CONTEXT, { @@ -128,14 +128,14 @@ describe('Consumption - Modal', () => { DummyConfig.Component.SOCOMEC_CONSUMPTION_METER("meter0", "Waermepumpe"), ); const VIEW_CONTEXT: OeFormlyViewTester.Context = { - '_sum/ConsumptionActivePower': 1000, - '_sum/ConsumptionActivePowerL1': 300, - '_sum/ConsumptionActivePowerL2': 350, - '_sum/ConsumptionActivePowerL3': 350, - 'meter0/ActivePower': 1000, - 'meter0/ActivePowerL1': 1000, - 'meter0/ActivePowerL2': -1000, - 'meter0/ActivePowerL3': 1000, + "_sum/ConsumptionActivePower": 1000, + "_sum/ConsumptionActivePowerL1": 300, + "_sum/ConsumptionActivePowerL2": 350, + "_sum/ConsumptionActivePowerL3": 350, + "meter0/ActivePower": 1000, + "meter0/ActivePowerL1": 1000, + "meter0/ActivePowerL2": -1000, + "meter0/ActivePowerL3": 1000, }; expectView(EMS, VIEW_CONTEXT, TEST_CONTEXT, { diff --git a/ui/src/app/edge/live/common/consumption/modal/modal.ts b/ui/src/app/edge/live/common/consumption/modal/modal.ts index 3ed6bfdbded..ccdcd9af819 100644 --- a/ui/src/app/edge/live/common/consumption/modal/modal.ts +++ b/ui/src/app/edge/live/common/consumption/modal/modal.ts @@ -1,23 +1,23 @@ -import { Component } from '@angular/core'; -import { TranslateService } from '@ngx-translate/core'; -import { TextIndentation } from 'src/app/shared/components/modal/modal-line/modal-line'; -import { Converter } from 'src/app/shared/components/shared/converter'; -import { Name } from 'src/app/shared/components/shared/name'; -import { AbstractFormlyComponent, OeFormlyField, OeFormlyView } from 'src/app/shared/components/shared/oe-formly-component'; -import { Phase } from 'src/app/shared/components/shared/phase'; +import { Component } from "@angular/core"; +import { TranslateService } from "@ngx-translate/core"; +import { TextIndentation } from "src/app/shared/components/modal/modal-line/modal-line"; +import { Converter } from "src/app/shared/components/shared/converter"; +import { Name } from "src/app/shared/components/shared/name"; +import { AbstractFormlyComponent, OeFormlyField, OeFormlyView } from "src/app/shared/components/shared/oe-formly-component"; +import { Phase } from "src/app/shared/components/shared/phase"; -import { ChannelAddress, CurrentData, EdgeConfig } from '../../../../../shared/shared'; +import { ChannelAddress, CurrentData, EdgeConfig } from "../../../../../shared/shared"; @Component({ - templateUrl: '../../../../../shared/components/formly/formly-field-modal/template.html', + templateUrl: "../../../../../shared/components/formly/formly-field-modal/template.html", }) export class ModalComponent extends AbstractFormlyComponent { public static generateView(config: EdgeConfig, translate: TranslateService): OeFormlyView { const evcss: EdgeConfig.Component[] | null = config.getComponentsImplementingNature("io.openems.edge.evcs.api.Evcs") - .filter(component => !(component.factoryId == 'Evcs.Cluster.SelfConsumption') && - !(component.factoryId == 'Evcs.Cluster.PeakShaving') && !component.isEnabled == false); + .filter(component => !(component.factoryId == "Evcs.Cluster.SelfConsumption") && + !(component.factoryId == "Evcs.Cluster.PeakShaving") && !component.isEnabled == false); const consumptionMeters: EdgeConfig.Component[] | null = config.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") .filter(component => component.isEnabled && config.isTypeConsumptionMetered(component)); @@ -26,59 +26,59 @@ export class ModalComponent extends AbstractFormlyComponent { // Total lines.push({ - type: 'channel-line', - name: translate.instant('General.TOTAL'), - channel: '_sum/ConsumptionActivePower', + type: "channel-line", + name: translate.instant("General.TOTAL"), + channel: "_sum/ConsumptionActivePower", converter: Converter.ONLY_POSITIVE_POWER_AND_NEGATIVE_AS_ZERO, }); Phase.THREE_PHASE.forEach(phase => { lines.push({ - type: 'channel-line', - name: translate.instant('General.phase') + ' ' + phase, + type: "channel-line", + name: translate.instant("General.phase") + " " + phase, indentation: TextIndentation.SINGLE, - channel: '_sum/ConsumptionActivePower' + phase, + channel: "_sum/ConsumptionActivePower" + phase, converter: Converter.ONLY_POSITIVE_POWER_AND_NEGATIVE_AS_ZERO, }); }); if (evcss.length > 0) { lines.push({ - type: 'horizontal-line', + type: "horizontal-line", }); } // Evcss evcss.forEach((evcs, index) => { lines.push({ - type: 'channel-line', + type: "channel-line", name: Name.METER_ALIAS_OR_ID(evcs), - channel: evcs.id + '/ChargePower', + channel: evcs.id + "/ChargePower", converter: Converter.ONLY_POSITIVE_POWER_AND_NEGATIVE_AS_ZERO, }); if (index < (evcss.length - 1)) { - lines.push({ type: 'horizontal-line' }); + lines.push({ type: "horizontal-line" }); } }); if (consumptionMeters.length > 0) { - lines.push({ type: 'horizontal-line' }); + lines.push({ type: "horizontal-line" }); } // Consumptionmeters consumptionMeters.forEach((meter, index) => { lines.push({ - type: 'channel-line', + type: "channel-line", name: Name.METER_ALIAS_OR_ID(meter), - channel: meter.id + '/ActivePower', + channel: meter.id + "/ActivePower", converter: Converter.ONLY_POSITIVE_POWER_AND_NEGATIVE_AS_ZERO, }); Phase.THREE_PHASE.forEach(phase => { lines.push({ - type: 'channel-line', - name: 'Phase ' + phase, - channel: meter.id + '/ActivePower' + phase, + type: "channel-line", + name: "Phase " + phase, + channel: meter.id + "/ActivePower" + phase, indentation: TextIndentation.SINGLE, converter: Converter.ONLY_POSITIVE_POWER_AND_NEGATIVE_AS_ZERO, }); @@ -86,35 +86,35 @@ export class ModalComponent extends AbstractFormlyComponent { if (index < (consumptionMeters.length - 1)) { lines.push({ - type: 'horizontal-line', + type: "horizontal-line", }); } }); - lines.push({ type: 'horizontal-line' }); + lines.push({ type: "horizontal-line" }); // OtherPower - const channelsToSubscribe: ChannelAddress[] = [new ChannelAddress('_sum', 'ConsumptionActivePower')]; + const channelsToSubscribe: ChannelAddress[] = [new ChannelAddress("_sum", "ConsumptionActivePower")]; - evcss.forEach(evcs => channelsToSubscribe.push(new ChannelAddress(evcs.id, 'ChargePower'))); + evcss.forEach(evcs => channelsToSubscribe.push(new ChannelAddress(evcs.id, "ChargePower"))); consumptionMeters.forEach(meter => { - channelsToSubscribe.push(...[new ChannelAddress(meter.id, 'ActivePower')]); + channelsToSubscribe.push(...[new ChannelAddress(meter.id, "ActivePower")]); }); lines.push({ - type: 'value-from-channels-line', - name: translate.instant('General.otherConsumption'), + type: "value-from-channels-line", + name: translate.instant("General.otherConsumption"), value: (currentData: CurrentData) => Converter.ONLY_POSITIVE_POWER_AND_NEGATIVE_AS_ZERO(Converter.CALCULATE_CONSUMPTION_OTHER_POWER(evcss, consumptionMeters, currentData)), channelsToSubscribe: channelsToSubscribe, }); lines.push({ - type: 'info-line', - name: translate.instant('Edge.Index.Widgets.phasesInfo'), + type: "info-line", + name: translate.instant("Edge.Index.Widgets.phasesInfo"), }); return { - title: translate.instant('General.consumption'), + title: translate.instant("General.consumption"), lines: lines, }; } diff --git a/ui/src/app/edge/live/common/grid/Common_Grid.ts b/ui/src/app/edge/live/common/grid/Common_Grid.ts index b560e4725d4..f0383f18ff1 100644 --- a/ui/src/app/edge/live/common/grid/Common_Grid.ts +++ b/ui/src/app/edge/live/common/grid/Common_Grid.ts @@ -1,8 +1,8 @@ -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 { 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"; @NgModule({ imports: [ diff --git a/ui/src/app/edge/live/common/grid/flat/flat.ts b/ui/src/app/edge/live/common/grid/flat/flat.ts index f89da9ed307..64bc50f0ff6 100644 --- a/ui/src/app/edge/live/common/grid/flat/flat.ts +++ b/ui/src/app/edge/live/common/grid/flat/flat.ts @@ -1,21 +1,21 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; -import { Converter } from 'src/app/shared/components/shared/converter'; -import { ChannelAddress, CurrentData, GridMode, Utils } from 'src/app/shared/shared'; -import { Icon } from 'src/app/shared/type/widget'; -import { GridSectionComponent } from '../../../energymonitor/chart/section/grid.component'; -import { ModalComponent } from '../modal/modal'; +import { Component } from "@angular/core"; +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; +import { Converter } from "src/app/shared/components/shared/converter"; +import { ChannelAddress, CurrentData, GridMode, Utils } from "src/app/shared/shared"; +import { Icon } from "src/app/shared/type/widget"; +import { GridSectionComponent } from "../../../energymonitor/chart/section/grid.component"; +import { ModalComponent } from "../modal/modal"; @Component({ - selector: 'grid', - templateUrl: './flat.html', + selector: "grid", + templateUrl: "./flat.html", }) export class FlatComponent extends AbstractFlatWidget { - private static readonly RESTRICTION_MODE: ChannelAddress = new ChannelAddress('ctrlEssLimiter14a0', 'RestrictionMode'); - private static readonly GRID_ACTIVE_POWER: ChannelAddress = new ChannelAddress('_sum', 'GridActivePower'); - private static readonly GRID_MODE: ChannelAddress = new ChannelAddress('_sum', 'GridMode'); + private static readonly RESTRICTION_MODE: ChannelAddress = new ChannelAddress("ctrlEssLimiter14a0", "RestrictionMode"); + private static readonly GRID_ACTIVE_POWER: ChannelAddress = new ChannelAddress("_sum", "GridActivePower"); + private static readonly GRID_MODE: ChannelAddress = new ChannelAddress("_sum", "GridMode"); public readonly CONVERT_WATT_TO_KILOWATT = Utils.CONVERT_WATT_TO_KILOWATT; public readonly GridMode = GridMode; @@ -43,9 +43,9 @@ export class FlatComponent extends AbstractFlatWidget { FlatComponent.GRID_ACTIVE_POWER, FlatComponent.GRID_MODE, // TODO should be moved to Modal - new ChannelAddress('_sum', 'GridActivePowerL1'), - new ChannelAddress('_sum', 'GridActivePowerL2'), - new ChannelAddress('_sum', 'GridActivePowerL3'), + new ChannelAddress("_sum", "GridActivePowerL1"), + new ChannelAddress("_sum", "GridActivePowerL2"), + new ChannelAddress("_sum", "GridActivePowerL3"), ]; if (GridSectionComponent.isControllerEnabled(this.config, "Controller.Ess.Limiter14a")) { 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 e78fcf03a69..f886559ec80 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 @@ -17,11 +17,11 @@ const VIEW_CONTEXT = (properties?: {}): OeFormlyViewTester.Context => ({ ...properties, }); -describe('Grid - Modal', () => { +describe("Grid - Modal", () => { let TEST_CONTEXT: TestContext; beforeEach(async () => TEST_CONTEXT = await sharedSetup()); - it('generateView()', () => { + it("generateView()", () => { { // No Meters const EMS = DummyConfig.from(); @@ -71,7 +71,7 @@ describe('Grid - Modal', () => { }); // Offgrid - expectView(EMS, Role.ADMIN, VIEW_CONTEXT({ '_sum/GridMode': GridMode.OFF_GRID }), TEST_CONTEXT, { + expectView(EMS, Role.ADMIN, VIEW_CONTEXT({ "_sum/GridMode": GridMode.OFF_GRID }), TEST_CONTEXT, { title: "Netz", lines: [ { 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 1087a3a69f4..899d9f6642a 100644 --- a/ui/src/app/edge/live/common/grid/modal/modal.ts +++ b/ui/src/app/edge/live/common/grid/modal/modal.ts @@ -1,27 +1,27 @@ -import { Component } from '@angular/core'; -import { TranslateService } from '@ngx-translate/core'; -import { TextIndentation } from 'src/app/shared/components/modal/modal-line/modal-line'; -import { Converter } from 'src/app/shared/components/shared/converter'; -import { Filter } from 'src/app/shared/components/shared/filter'; -import { Name } from 'src/app/shared/components/shared/name'; -import { AbstractFormlyComponent, OeFormlyField, OeFormlyView } from 'src/app/shared/components/shared/oe-formly-component'; -import { ChannelAddress, CurrentData, EdgeConfig } from 'src/app/shared/shared'; -import { Role } from 'src/app/shared/type/role'; -import { GridSectionComponent } from '../../../energymonitor/chart/section/grid.component'; +import { Component } from "@angular/core"; +import { TranslateService } from "@ngx-translate/core"; +import { TextIndentation } from "src/app/shared/components/modal/modal-line/modal-line"; +import { Converter } from "src/app/shared/components/shared/converter"; +import { Filter } from "src/app/shared/components/shared/filter"; +import { Name } from "src/app/shared/components/shared/name"; +import { AbstractFormlyComponent, OeFormlyField, OeFormlyView } from "src/app/shared/components/shared/oe-formly-component"; +import { ChannelAddress, CurrentData, EdgeConfig } from "src/app/shared/shared"; +import { Role } from "src/app/shared/type/role"; +import { GridSectionComponent } from "../../../energymonitor/chart/section/grid.component"; @Component({ - templateUrl: '../../../../../shared/components/formly/formly-field-modal/template.html', + templateUrl: "../../../../../shared/components/formly/formly-field-modal/template.html", }) export class ModalComponent extends AbstractFormlyComponent { public static generateView(config: EdgeConfig, role: Role, translate: TranslateService): OeFormlyView { - const isActivated = GridSectionComponent.isControllerEnabled(config, 'Controller.Ess.Limiter14a'); + const isActivated = GridSectionComponent.isControllerEnabled(config, "Controller.Ess.Limiter14a"); // Grid-Mode const lines: OeFormlyField[] = [{ - type: 'channel-line', + type: "channel-line", name: translate.instant("General.offGrid"), - channel: '_sum/GridMode', + channel: "_sum/GridMode", filter: Filter.GRID_MODE_IS_OFF_GRID, converter: Converter.HIDE_VALUE, }]; @@ -32,7 +32,7 @@ export class ModalComponent extends AbstractFormlyComponent { if (gridMeters.length > 1) { if (isActivated) { lines.push({ - type: 'value-from-channels-line', + type: "value-from-channels-line", name: translate.instant("General.state"), value: (currentData: CurrentData) => Converter.GRID_STATE_TO_MESSAGE(translate, currentData), channelsToSubscribe: [ @@ -44,19 +44,19 @@ export class ModalComponent extends AbstractFormlyComponent { lines.push( { - type: 'channel-line', + type: "channel-line", name: translate.instant("General.gridSellAdvanced"), - channel: '_sum/GridActivePower', + channel: "_sum/GridActivePower", converter: Converter.GRID_SELL_POWER_OR_ZERO, }, { - type: 'channel-line', + type: "channel-line", name: translate.instant("General.gridBuyAdvanced"), - channel: '_sum/GridActivePower', + channel: "_sum/GridActivePower", converter: Converter.GRID_BUY_POWER_OR_ZERO, }, { - type: 'horizontal-line', + type: "horizontal-line", }, ); } @@ -68,7 +68,7 @@ export class ModalComponent extends AbstractFormlyComponent { // Two lines if there is only one meter (= same visualization as with Sum Channels) if (isActivated) { lines.push({ - type: 'value-from-channels-line', + type: "value-from-channels-line", name: translate.instant("General.state"), value: (currentData: CurrentData) => Converter.GRID_STATE_TO_MESSAGE(translate, currentData), channelsToSubscribe: [ @@ -80,15 +80,15 @@ export class ModalComponent extends AbstractFormlyComponent { lines.push( { - type: 'channel-line', + type: "channel-line", name: translate.instant("General.gridSellAdvanced"), - channel: meter.id + '/ActivePower', + channel: meter.id + "/ActivePower", converter: Converter.GRID_SELL_POWER_OR_ZERO, }, { - type: 'channel-line', + type: "channel-line", name: translate.instant("General.gridBuyAdvanced"), - channel: meter.id + '/ActivePower', + channel: meter.id + "/ActivePower", converter: Converter.GRID_BUY_POWER_OR_ZERO, }, ); @@ -96,9 +96,9 @@ export class ModalComponent extends AbstractFormlyComponent { } else { // More than one meter? Show only one line per meter. lines.push({ - type: 'channel-line', + type: "channel-line", name: Name.SUFFIX_FOR_GRID_SELL_OR_GRID_BUY(translate, meter.alias), - channel: meter.id + '/ActivePower', + channel: meter.id + "/ActivePower", converter: Converter.POWER_IN_WATT, }); } @@ -108,7 +108,7 @@ export class ModalComponent extends AbstractFormlyComponent { ...ModalComponent.generatePhasesView(meter, translate, role), { // Line separator - type: 'horizontal-line', + type: "horizontal-line", }, ); } @@ -116,24 +116,24 @@ export class ModalComponent extends AbstractFormlyComponent { if (gridMeters.length > 0) { // Technical info lines.push({ - type: 'info-line', + type: "info-line", name: translate.instant("Edge.Index.Widgets.phasesInfo"), }); } return { - title: translate.instant('General.grid'), + title: translate.instant("General.grid"), lines: lines, }; } private static generatePhasesView(component: EdgeConfig.Component, translate: TranslateService, role: Role): OeFormlyField[] { - return ['L1', 'L2', 'L3'] + return ["L1", "L2", "L3"] .map(phase => { - type: 'children-line', + 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), + 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), @@ -144,19 +144,19 @@ export class ModalComponent extends AbstractFormlyComponent { const children: OeFormlyField[] = []; if (Role.isAtLeast(role, Role.INSTALLER)) { children.push({ - type: 'item', - channel: component.id + '/Voltage' + phase, + type: "item", + channel: component.id + "/Voltage" + phase, converter: Converter.VOLTAGE_IN_MILLIVOLT_TO_VOLT, }, { - type: 'item', - channel: component.id + '/Current' + phase, + type: "item", + channel: component.id + "/Current" + phase, converter: Converter.CURRENT_IN_MILLIAMPERE_TO_AMPERE, }); } children.push({ - type: 'item', - channel: component.id + '/ActivePower' + phase, + type: "item", + channel: component.id + "/ActivePower" + phase, converter: Converter.POSITIVE_POWER, }); diff --git a/ui/src/app/edge/live/common/production/Common_Production.ts b/ui/src/app/edge/live/common/production/Common_Production.ts index ab5942cf712..6ca75abadc7 100644 --- a/ui/src/app/edge/live/common/production/Common_Production.ts +++ b/ui/src/app/edge/live/common/production/Common_Production.ts @@ -1,8 +1,8 @@ -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 { 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"; @NgModule({ imports: [ diff --git a/ui/src/app/edge/live/common/production/flat/flat.ts b/ui/src/app/edge/live/common/production/flat/flat.ts index 8141104ce0c..678ef3f8c87 100644 --- a/ui/src/app/edge/live/common/production/flat/flat.ts +++ b/ui/src/app/edge/live/common/production/flat/flat.ts @@ -1,11 +1,11 @@ -import { Component } from '@angular/core'; -import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; -import { EdgeConfig, Utils } from 'src/app/shared/shared'; -import { ModalComponent } from '../modal/modal'; +import { Component } from "@angular/core"; +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; +import { EdgeConfig, Utils } from "src/app/shared/shared"; +import { ModalComponent } from "../modal/modal"; @Component({ - selector: 'Common_Production', - templateUrl: './flat.html', + selector: "Common_Production", + templateUrl: "./flat.html", }) export class FlatComponent extends AbstractFlatWidget { diff --git a/ui/src/app/edge/live/common/production/modal/modal.ts b/ui/src/app/edge/live/common/production/modal/modal.ts index a631d288bef..013ab5b5307 100644 --- a/ui/src/app/edge/live/common/production/modal/modal.ts +++ b/ui/src/app/edge/live/common/production/modal/modal.ts @@ -1,9 +1,9 @@ -import { Component } from '@angular/core'; -import { AbstractModal } from 'src/app/shared/components/modal/abstractModal'; -import { ChannelAddress, EdgeConfig, Utils } from 'src/app/shared/shared'; +import { Component } from "@angular/core"; +import { AbstractModal } from "src/app/shared/components/modal/abstractModal"; +import { ChannelAddress, EdgeConfig, Utils } from "src/app/shared/shared"; @Component({ - templateUrl: './modal.html', + templateUrl: "./modal.html", }) export class ModalComponent extends AbstractModal { @@ -27,10 +27,10 @@ export class ModalComponent extends AbstractModal { this.config.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") .filter(component => component.isEnabled && this.config.isProducer(component)) .forEach(component => { - channelAddresses.push(new ChannelAddress(component.id, 'ActivePower')); - channelAddresses.push(new ChannelAddress(component.id, 'ActivePowerL1')); - channelAddresses.push(new ChannelAddress(component.id, 'ActivePowerL2')); - channelAddresses.push(new ChannelAddress(component.id, 'ActivePowerL3')); + channelAddresses.push(new ChannelAddress(component.id, "ActivePower")); + channelAddresses.push(new ChannelAddress(component.id, "ActivePowerL1")); + channelAddresses.push(new ChannelAddress(component.id, "ActivePowerL2")); + channelAddresses.push(new ChannelAddress(component.id, "ActivePowerL3")); this.productionMeters.push(component); }); diff --git a/ui/src/app/edge/live/common/selfconsumption/Common_Selfconsumption.ts b/ui/src/app/edge/live/common/selfconsumption/Common_Selfconsumption.ts index 6c49f7603a4..af8b2b70f3b 100644 --- a/ui/src/app/edge/live/common/selfconsumption/Common_Selfconsumption.ts +++ b/ui/src/app/edge/live/common/selfconsumption/Common_Selfconsumption.ts @@ -1,8 +1,8 @@ -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 { 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"; @NgModule({ imports: [ 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 60c4c13b999..f1bf518f2b2 100644 --- a/ui/src/app/edge/live/common/selfconsumption/flat/flat.ts +++ b/ui/src/app/edge/live/common/selfconsumption/flat/flat.ts @@ -1,13 +1,13 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; -import { ChannelAddress, CurrentData, Utils } from 'src/app/shared/shared'; +import { Component } from "@angular/core"; +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; +import { ChannelAddress, CurrentData, Utils } from "src/app/shared/shared"; -import { ModalComponent } from '../modal/modal'; +import { ModalComponent } from "../modal/modal"; @Component({ - selector: 'Common_Selfconsumption', - templateUrl: './flat.html', + selector: "Common_Selfconsumption", + templateUrl: "./flat.html", }) export class FlatComponent extends AbstractFlatWidget { @@ -22,18 +22,18 @@ export class FlatComponent extends AbstractFlatWidget { protected override getChannelAddresses() { return [ - new ChannelAddress('_sum', 'GridActivePower'), - new ChannelAddress('_sum', 'ProductionActivePower'), + new ChannelAddress("_sum", "GridActivePower"), + new ChannelAddress("_sum", "ProductionActivePower"), ]; } protected override onCurrentData(currentData: CurrentData) { this.calculatedSelfConsumption = Utils.calculateSelfConsumption( Utils.multiplySafely( - currentData.allComponents['_sum/GridActivePower'], + currentData.allComponents["_sum/GridActivePower"], -1, ), - currentData.allComponents['_sum/ProductionActivePower'], + currentData.allComponents["_sum/ProductionActivePower"], ); } diff --git a/ui/src/app/edge/live/common/selfconsumption/modal/modal.spec.ts b/ui/src/app/edge/live/common/selfconsumption/modal/modal.spec.ts index f640f899548..9571d751120 100644 --- a/ui/src/app/edge/live/common/selfconsumption/modal/modal.spec.ts +++ b/ui/src/app/edge/live/common/selfconsumption/modal/modal.spec.ts @@ -13,11 +13,11 @@ export function expectView(testContext: TestContext, viewContext: OeFormlyViewTe expect(generatedView).toEqual(view); } -describe('SelfConsumption - Modal', () => { +describe("SelfConsumption - Modal", () => { let TEST_CONTEXT: TestContext; beforeEach(async () => TEST_CONTEXT = await sharedSetup()); - it('generateView()', () => { + it("generateView()", () => { { expectView(TEST_CONTEXT, VIEW_CONTEXT, { title: "Eigenverbrauch", diff --git a/ui/src/app/edge/live/common/selfconsumption/modal/modal.ts b/ui/src/app/edge/live/common/selfconsumption/modal/modal.ts index 531b1b41123..81894e904dd 100644 --- a/ui/src/app/edge/live/common/selfconsumption/modal/modal.ts +++ b/ui/src/app/edge/live/common/selfconsumption/modal/modal.ts @@ -1,19 +1,19 @@ -import { Component } from '@angular/core'; -import { TranslateService } from '@ngx-translate/core'; -import { AbstractFormlyComponent, OeFormlyView } from 'src/app/shared/components/shared/oe-formly-component'; -import { EdgeConfig } from 'src/app/shared/shared'; -import { Role } from 'src/app/shared/type/role'; +import { Component } from "@angular/core"; +import { TranslateService } from "@ngx-translate/core"; +import { AbstractFormlyComponent, OeFormlyView } from "src/app/shared/components/shared/oe-formly-component"; +import { EdgeConfig } from "src/app/shared/shared"; +import { Role } from "src/app/shared/type/role"; @Component({ - templateUrl: '../../../../../shared/components/formly/formly-field-modal/template.html', + templateUrl: "../../../../../shared/components/formly/formly-field-modal/template.html", }) export class ModalComponent extends AbstractFormlyComponent { public static generateView(translate: TranslateService): OeFormlyView { return { - title: translate.instant('General.selfConsumption'), + title: translate.instant("General.selfConsumption"), lines: [{ - type: 'info-line', + type: "info-line", name: translate.instant("Edge.Index.Widgets.selfconsumptionInfo"), }], }; diff --git a/ui/src/app/edge/live/common/storage/modal/modal.component.ts b/ui/src/app/edge/live/common/storage/modal/modal.component.ts index e64da36eb1b..6ce266a1401 100644 --- a/ui/src/app/edge/live/common/storage/modal/modal.component.ts +++ b/ui/src/app/edge/live/common/storage/modal/modal.component.ts @@ -1,15 +1,15 @@ // @ts-strict-ignore -import { Component, Input, OnDestroy, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup } from '@angular/forms'; -import { ModalController } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; -import { isBefore } from 'date-fns'; -import { ChannelAddress, Edge, EdgeConfig, Service, Utils, Websocket } from 'src/app/shared/shared'; -import { Role } from 'src/app/shared/type/role'; +import { Component, Input, OnDestroy, OnInit } from "@angular/core"; +import { FormBuilder, FormControl, FormGroup } from "@angular/forms"; +import { ModalController } from "@ionic/angular"; +import { TranslateService } from "@ngx-translate/core"; +import { isBefore } from "date-fns"; +import { ChannelAddress, Edge, EdgeConfig, Service, Utils, Websocket } from "src/app/shared/shared"; +import { Role } from "src/app/shared/type/role"; @Component({ - selector: 'storage-modal', - templateUrl: './modal.component.html', + selector: "storage-modal", + templateUrl: "./modal.component.html", }) export class StorageModalComponent implements OnInit, OnDestroy { @@ -40,13 +40,13 @@ export class StorageModalComponent implements OnInit, OnDestroy { ngOnInit() { // Future Work: Remove when all ems are at least at this version - this.controllerIsRequiredEdgeVersion = this.edge.isVersionAtLeast('2023.2.5'); + this.controllerIsRequiredEdgeVersion = this.edge.isVersionAtLeast("2023.2.5"); this.isAtLeastInstaller = this.edge.roleIsAtLeast(Role.INSTALLER); - const emergencyReserveCtrl = this.config.getComponentsByFactory('Controller.Ess.EmergencyCapacityReserve'); + const emergencyReserveCtrl = this.config.getComponentsByFactory("Controller.Ess.EmergencyCapacityReserve"); const prepareBatteryExtensionCtrl = this.config.getComponentsByFactory("Controller.Ess.PrepareBatteryExtension"); const components = [...prepareBatteryExtensionCtrl, ...emergencyReserveCtrl].filter(component => component.isEnabled).reduce((result, component) => { - const essId = component.properties['ess.id']; + const essId = component.properties["ess.id"]; if (result[essId] == null) { result[essId] = []; } @@ -78,18 +78,18 @@ export class StorageModalComponent implements OnInit, OnDestroy { const controllerFrmGrp: FormGroup = new FormGroup({}); for (const controller of (controllers as EdgeConfig.Component[])) { - if (controller.factoryId == 'Controller.Ess.EmergencyCapacityReserve') { + if (controller.factoryId == "Controller.Ess.EmergencyCapacityReserve") { const reserveSoc = currentData.channel[controller.id + "/_PropertyReserveSoc"] ?? 20 /* default Reserve-Soc */; const isReserveSocEnabled = currentData.channel[controller.id + "/_PropertyIsReserveSocEnabled"] == 1; - controllerFrmGrp.addControl('emergencyReserveController', + controllerFrmGrp.addControl("emergencyReserveController", this.formBuilder.group({ - controllerId: new FormControl(controller['id']), + controllerId: new FormControl(controller["id"]), isReserveSocEnabled: new FormControl(isReserveSocEnabled), reserveSoc: new FormControl(reserveSoc), }), ); - } else if (controller.factoryId == 'Controller.Ess.PrepareBatteryExtension') { + } else if (controller.factoryId == "Controller.Ess.PrepareBatteryExtension") { const isRunning = currentData.channel[controller.id + "/_PropertyIsRunning"] == 1; @@ -124,7 +124,7 @@ export class StorageModalComponent implements OnInit, OnDestroy { this.isTargetTimeInValid.set(essId, false); } - controllerFrmGrp.addControl('prepareBatteryExtensionController', + controllerFrmGrp.addControl("prepareBatteryExtensionController", this.formBuilder.group({ controllerId: new FormControl(controller.id), isRunning: new FormControl(isRunning), @@ -155,26 +155,26 @@ export class StorageModalComponent implements OnInit, OnDestroy { for (const essId in this.formGroup.controls) { const essGroups = this.formGroup.controls[essId]; - const emergencyReserveController = (essGroups.get('emergencyReserveController') as FormGroup)?.controls ?? {}; + const emergencyReserveController = (essGroups.get("emergencyReserveController") as FormGroup)?.controls ?? {}; for (const essGroup of Object.keys(emergencyReserveController)) { if (emergencyReserveController[essGroup].dirty) { - if (updateArray.get(emergencyReserveController['controllerId'].value)) { - updateArray.get(emergencyReserveController['controllerId'].value).push(new Map().set(essGroup, emergencyReserveController[essGroup].value)); + if (updateArray.get(emergencyReserveController["controllerId"].value)) { + updateArray.get(emergencyReserveController["controllerId"].value).push(new Map().set(essGroup, emergencyReserveController[essGroup].value)); } else { - updateArray.set(emergencyReserveController['controllerId'].value, [new Map().set(essGroup, emergencyReserveController[essGroup].value)]); + updateArray.set(emergencyReserveController["controllerId"].value, [new Map().set(essGroup, emergencyReserveController[essGroup].value)]); } } } - const prepareBatteryExtensionController = (essGroups.get('prepareBatteryExtensionController') as FormGroup)?.controls ?? {}; + const prepareBatteryExtensionController = (essGroups.get("prepareBatteryExtensionController") as FormGroup)?.controls ?? {}; for (const essGroup of Object.keys(prepareBatteryExtensionController)) { if (prepareBatteryExtensionController[essGroup].dirty) { // For simplicity, split targetTimeSpecified in 2 for template formControlName - if (updateArray.get(prepareBatteryExtensionController['controllerId'].value)) { - updateArray.get(prepareBatteryExtensionController['controllerId'].value).push(new Map().set(essGroup, prepareBatteryExtensionController[essGroup].value)); + if (updateArray.get(prepareBatteryExtensionController["controllerId"].value)) { + updateArray.get(prepareBatteryExtensionController["controllerId"].value).push(new Map().set(essGroup, prepareBatteryExtensionController[essGroup].value)); } else { - updateArray.set(prepareBatteryExtensionController['controllerId'].value, [new Map().set(essGroup, prepareBatteryExtensionController[essGroup].value)]); + updateArray.set(prepareBatteryExtensionController["controllerId"].value, [new Map().set(essGroup, prepareBatteryExtensionController[essGroup].value)]); } } } @@ -193,10 +193,10 @@ export class StorageModalComponent implements OnInit, OnDestroy { }); this.edge.updateComponentConfig(this.websocket, controllerId, properties).then(() => { - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); + this.service.toast(this.translate.instant("General.changeAccepted"), "success"); this.formGroup.markAsPristine(); }).catch(reason => { - this.service.toast(this.translate.instant('General.changeFailed') + '\n' + reason, 'danger'); + this.service.toast(this.translate.instant("General.changeFailed") + "\n" + reason, "danger"); }); } } 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 98549f34bff..ca1846f220f 100644 --- a/ui/src/app/edge/live/common/storage/storage.component.ts +++ b/ui/src/app/edge/live/common/storage/storage.component.ts @@ -1,16 +1,16 @@ // @ts-strict-ignore -import { formatNumber } from '@angular/common'; -import { Component } from '@angular/core'; -import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; +import { formatNumber } from "@angular/common"; +import { Component } from "@angular/core"; +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; import { CurrentData } from "src/app/shared/shared"; -import { DateUtils } from 'src/app/shared/utils/date/dateutils'; +import { DateUtils } from "src/app/shared/utils/date/dateutils"; -import { ChannelAddress, EdgeConfig, Utils } from '../../../../shared/shared'; -import { StorageModalComponent } from './modal/modal.component'; +import { ChannelAddress, EdgeConfig, Utils } from "../../../../shared/shared"; +import { StorageModalComponent } from "./modal/modal.component"; @Component({ - selector: 'storage', - templateUrl: './storage.component.html', + selector: "storage", + templateUrl: "./storage.component.html", }) export class StorageComponent extends AbstractFlatWidget { @@ -52,21 +52,21 @@ export class StorageComponent extends AbstractFlatWidget { */ public convertPower(value: number, isCharge?: boolean) { if (value == null) { - return '-'; + return "-"; } const thisValue: number = (value / 1000); // Round thisValue to Integer when decimal place equals 0 if (thisValue > 0) { - return formatNumber(thisValue, 'de', '1.0-1') + " kW"; // TODO get locale dynamically + return formatNumber(thisValue, "de", "1.0-1") + " kW"; // TODO get locale dynamically } else if (thisValue == 0 && isCharge) { // if thisValue is 0, then show only when charge and not discharge - return '0 kW'; + return "0 kW"; } else { - return '-'; + return "-"; } } @@ -88,12 +88,12 @@ export class StorageComponent extends AbstractFlatWidget { protected override getChannelAddresses() { const channelAddresses: ChannelAddress[] = [ - new ChannelAddress('_sum', 'EssSoc'), + new ChannelAddress("_sum", "EssSoc"), // TODO should be moved to Modal - new ChannelAddress('_sum', 'EssActivePowerL1'), - new ChannelAddress('_sum', 'EssActivePowerL2'), - new ChannelAddress('_sum', 'EssActivePowerL3'), + new ChannelAddress("_sum", "EssActivePowerL1"), + new ChannelAddress("_sum", "EssActivePowerL2"), + new ChannelAddress("_sum", "EssActivePowerL3"), ]; this.prepareBatteryExtensionCtrl = this.config.getComponentsByFactory("Controller.Ess.PrepareBatteryExtension") @@ -101,7 +101,7 @@ export class StorageComponent extends AbstractFlatWidget { .reduce((result, component) => { return { ...result, - [component.properties['ess.id']]: component, + [component.properties["ess.id"]]: component, }; }, {}); @@ -113,26 +113,26 @@ export class StorageComponent extends AbstractFlatWidget { new ChannelAddress(controller.id, "CtrlIsChargingEss"), new ChannelAddress(controller.id, "CtrlIsDischargingEss"), new ChannelAddress(controller.id, "_PropertyIsRunning"), - new ChannelAddress(controller.id, '_PropertyTargetTimeSpecified'), - new ChannelAddress(controller.id, '_PropertyTargetTime'), + new ChannelAddress(controller.id, "_PropertyTargetTimeSpecified"), + new ChannelAddress(controller.id, "_PropertyTargetTime"), ); } // Get emergencyReserves this.emergencyReserveComponents = this.config - .getComponentsByFactory('Controller.Ess.EmergencyCapacityReserve') + .getComponentsByFactory("Controller.Ess.EmergencyCapacityReserve") .filter(component => component.isEnabled) .reduce((result, component) => { return { ...result, - [component.properties['ess.id']]: component, + [component.properties["ess.id"]]: component, }; }, {}); for (const component of Object.values(this.emergencyReserveComponents)) { channelAddresses.push( - new ChannelAddress(component.id, '_PropertyReserveSoc'), - new ChannelAddress(component.id, '_PropertyIsReserveSocEnabled'), + new ChannelAddress(component.id, "_PropertyReserveSoc"), + new ChannelAddress(component.id, "_PropertyIsReserveSocEnabled"), ); } // Get Chargers @@ -142,7 +142,7 @@ export class StorageComponent extends AbstractFlatWidget { .filter(component => component.isEnabled); for (const component of this.chargerComponents) { channelAddresses.push( - new ChannelAddress(component.id, 'ActualPower'), + new ChannelAddress(component.id, "ActualPower"), ); } @@ -165,14 +165,14 @@ export class StorageComponent extends AbstractFlatWidget { .includes("io.openems.edge.ess.api.HybridEss"); channelAddresses.push( - new ChannelAddress(component.id, 'Soc'), - new ChannelAddress(component.id, 'Capacity'), + new ChannelAddress(component.id, "Soc"), + new ChannelAddress(component.id, "Capacity"), ); if (this.config.factories[component.factoryId].natureIds.includes("io.openems.edge.ess.api.AsymmetricEss")) { channelAddresses.push( - new ChannelAddress(component.id, 'ActivePowerL1'), - new ChannelAddress(component.id, 'ActivePowerL2'), - new ChannelAddress(component.id, 'ActivePowerL3'), + new ChannelAddress(component.id, "ActivePowerL1"), + new ChannelAddress(component.id, "ActivePowerL2"), + new ChannelAddress(component.id, "ActivePowerL3"), ); } } @@ -187,22 +187,22 @@ export class StorageComponent extends AbstractFlatWidget { this.possibleBatteryExtensionMessage.set( essId, this.getBatteryCapacityExtensionStatus( - currentData.allComponents[controller.id + '/_PropertyIsRunning'] == 1, - currentData.allComponents[controller.id + '/CtrlIsBlockingEss'], - currentData.allComponents[controller.id + '/CtrlIsChargingEss'], - currentData.allComponents[controller.id + '/CtrlIsDischargingEss'], - currentData.allComponents[controller.id + '/_PropertyTargetTimeSpecified'], - currentData.allComponents[controller.id + '/_PropertyTargetTime'], + currentData.allComponents[controller.id + "/_PropertyIsRunning"] == 1, + currentData.allComponents[controller.id + "/CtrlIsBlockingEss"], + currentData.allComponents[controller.id + "/CtrlIsChargingEss"], + currentData.allComponents[controller.id + "/CtrlIsDischargingEss"], + currentData.allComponents[controller.id + "/_PropertyTargetTimeSpecified"], + currentData.allComponents[controller.id + "/_PropertyTargetTime"], )); } // Check total State_of_Charge for dynamical icon in widget-header - const soc = currentData.allComponents['_sum/EssSoc']; - this.storageIconStyle = 'storage-' + Utils.getStorageSocSegment(soc); + const soc = currentData.allComponents["_sum/EssSoc"]; + this.storageIconStyle = "storage-" + Utils.getStorageSocSegment(soc); for (const essId in this.emergencyReserveComponents) { const controller = this.emergencyReserveComponents[essId]; - controller['currentReserveSoc'] = currentData.allComponents[controller.id + '/_PropertyReserveSoc']; + controller["currentReserveSoc"] = currentData.allComponents[controller.id + "/_PropertyReserveSoc"]; this.isEmergencyReserveEnabled[essId] = currentData.allComponents[controller.id + "/_PropertyIsReserveSocEnabled"] == 1 ? true : false; } } @@ -217,7 +217,7 @@ export class StorageComponent extends AbstractFlatWidget { const date = DateUtils.stringToDate(targetDate.toString()); return { - color: 'green', text: this.translate.instant('Edge.Index.RETROFITTING.TARGET_TIME_SPECIFIED', { + color: "green", text: this.translate.instant("Edge.Index.RETROFITTING.TARGET_TIME_SPECIFIED", { targetDate: DateUtils.toLocaleDateString(date), targetTime: date.toLocaleTimeString(), }), @@ -226,12 +226,12 @@ export class StorageComponent extends AbstractFlatWidget { if (essIsBlocking != null && essIsBlocking == 1) { // If ess reached targetSoc - return { color: 'green', text: this.translate.instant('Edge.Index.RETROFITTING.REACHED_TARGET_SOC') }; + return { color: "green", text: this.translate.instant("Edge.Index.RETROFITTING.REACHED_TARGET_SOC") }; } else if ((essIsCharging != null && essIsCharging == 1) || (essIsDischarging != null && essIsDischarging == 1)) { // If Ess is charging to or discharging to the targetSoc - return { color: 'orange', text: this.translate.instant('Edge.Index.RETROFITTING.PREPARING') }; + return { color: "orange", text: this.translate.instant("Edge.Index.RETROFITTING.PREPARING") }; } else { return null; } diff --git a/ui/src/app/edge/live/delayedselltogrid/delayedselltogrid.component.ts b/ui/src/app/edge/live/delayedselltogrid/delayedselltogrid.component.ts index 13e4c3dd1b9..89febc1abd0 100644 --- a/ui/src/app/edge/live/delayedselltogrid/delayedselltogrid.component.ts +++ b/ui/src/app/edge/live/delayedselltogrid/delayedselltogrid.component.ts @@ -1,14 +1,14 @@ // @ts-strict-ignore -import { Component, Input, OnDestroy, 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 { DelayedSellToGridModalComponent } from './modal/modal.component'; +import { Component, Input, OnDestroy, 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 { DelayedSellToGridModalComponent } from "./modal/modal.component"; @Component({ selector: DelayedSellToGridComponent.SELECTOR, - templateUrl: './delayedselltogrid.component.html', + templateUrl: "./delayedselltogrid.component.html", }) export class DelayedSellToGridComponent implements OnInit, OnDestroy { @@ -29,7 +29,7 @@ export class DelayedSellToGridComponent implements OnInit, OnDestroy { ) { } ngOnInit() { - this.service.setCurrentComponent('', this.route).then(edge => { + this.service.getCurrentEdge().then(edge => { this.edge = edge; this.service.getConfig().then(config => { this.component = config.getComponent(this.componentId); diff --git a/ui/src/app/edge/live/delayedselltogrid/modal/modal.component.ts b/ui/src/app/edge/live/delayedselltogrid/modal/modal.component.ts index ef45722f679..b688531b982 100644 --- a/ui/src/app/edge/live/delayedselltogrid/modal/modal.component.ts +++ b/ui/src/app/edge/live/delayedselltogrid/modal/modal.component.ts @@ -1,13 +1,13 @@ // @ts-strict-ignore -import { Component, Input, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; -import { ModalController } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; -import { Edge, EdgeConfig, Service, Websocket } from '../../../../shared/shared'; +import { Component, Input, OnInit } from "@angular/core"; +import { FormBuilder, FormControl, FormGroup, Validators } from "@angular/forms"; +import { ModalController } from "@ionic/angular"; +import { TranslateService } from "@ngx-translate/core"; +import { Edge, EdgeConfig, Service, Websocket } from "../../../../shared/shared"; @Component({ selector: DelayedSellToGridModalComponent.SELECTOR, - templateUrl: './modal.component.html', + templateUrl: "./modal.component.html", }) export class DelayedSellToGridModalComponent implements OnInit { @@ -30,11 +30,11 @@ export class DelayedSellToGridModalComponent implements OnInit { ngOnInit() { this.formGroup = this.formBuilder.group({ continuousSellToGridPower: new FormControl(this.component.properties.continuousSellToGridPower, Validators.compose([ - Validators.pattern('^(?:[1-9][0-9]*|0)$'), + Validators.pattern("^(?:[1-9][0-9]*|0)$"), Validators.required, ])), sellToGridPowerLimit: new FormControl(this.component.properties.sellToGridPowerLimit, Validators.compose([ - Validators.pattern('^(?:[1-9][0-9]*|0)$'), + Validators.pattern("^(?:[1-9][0-9]*|0)$"), Validators.required, ])), }); @@ -42,9 +42,9 @@ export class DelayedSellToGridModalComponent implements OnInit { applyChanges() { if (this.edge != null) { - if (this.edge.roleIsAtLeast('owner')) { - const continuousSellToGridPower = this.formGroup.controls['continuousSellToGridPower']; - const sellToGridPowerLimit = this.formGroup.controls['sellToGridPowerLimit']; + if (this.edge.roleIsAtLeast("owner")) { + const continuousSellToGridPower = this.formGroup.controls["continuousSellToGridPower"]; + const sellToGridPowerLimit = this.formGroup.controls["sellToGridPowerLimit"]; if (continuousSellToGridPower.valid && sellToGridPowerLimit.valid) { if (sellToGridPowerLimit.value > continuousSellToGridPower.value) { const updateComponentArray = []; @@ -58,23 +58,23 @@ export class DelayedSellToGridModalComponent implements OnInit { this.component.properties.continuousSellToGridPower = continuousSellToGridPower.value; this.component.properties.sellToGridPowerLimit = sellToGridPowerLimit.value; this.loading = false; - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); + this.service.toast(this.translate.instant("General.changeAccepted"), "success"); }).catch(reason => { continuousSellToGridPower.setValue(this.component.properties.continuousSellToGridPower); sellToGridPowerLimit.setValue(this.component.properties.sellToGridPowerLimit); this.loading = false; - this.service.toast(this.translate.instant('General.changeFailed') + '\n' + reason.error.message, 'danger'); + this.service.toast(this.translate.instant("General.changeFailed") + "\n" + reason.error.message, "danger"); console.warn(reason); }); this.formGroup.markAsPristine(); } else { - this.service.toast(this.translate.instant('Edge.Index.Widgets.DelayedSellToGrid.relationError'), 'danger'); + this.service.toast(this.translate.instant("Edge.Index.Widgets.DelayedSellToGrid.relationError"), "danger"); } } else { - this.service.toast(this.translate.instant('General.inputNotValid'), 'danger'); + this.service.toast(this.translate.instant("General.inputNotValid"), "danger"); } } else { - this.service.toast(this.translate.instant('General.insufficientRights'), 'danger'); + this.service.toast(this.translate.instant("General.insufficientRights"), "danger"); } } } diff --git a/ui/src/app/edge/live/energymonitor/chart/chart.component.ts b/ui/src/app/edge/live/energymonitor/chart/chart.component.ts index 042fb641643..f0852e5d2f4 100644 --- a/ui/src/app/edge/live/energymonitor/chart/chart.component.ts +++ b/ui/src/app/edge/live/energymonitor/chart/chart.component.ts @@ -1,17 +1,17 @@ // @ts-strict-ignore -import { Component, ElementRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core'; -import { fromEvent, Subject } from 'rxjs'; -import { debounceTime, delay, takeUntil } from 'rxjs/operators'; -import { Service } from 'src/app/shared/shared'; -import { CurrentData } from '../../../../shared/components/edge/currentdata'; -import { ConsumptionSectionComponent } from './section/consumption.component'; -import { GridSectionComponent } from './section/grid.component'; -import { ProductionSectionComponent } from './section/production.component'; -import { StorageSectionComponent } from './section/storage.component'; +import { Component, ElementRef, Input, OnDestroy, OnInit, ViewChild } from "@angular/core"; +import { Subject, fromEvent } from "rxjs"; +import { debounceTime, delay, takeUntil } from "rxjs/operators"; +import { Service } from "src/app/shared/shared"; +import { CurrentData } from "../../../../shared/components/edge/currentdata"; +import { ConsumptionSectionComponent } from "./section/consumption.component"; +import { GridSectionComponent } from "./section/grid.component"; +import { ProductionSectionComponent } from "./section/production.component"; +import { StorageSectionComponent } from "./section/storage.component"; @Component({ - selector: 'energymonitor-chart', - templateUrl: './chart.component.html', + selector: "energymonitor-chart", + templateUrl: "./chart.component.html", }) export class EnergymonitorChartComponent implements OnInit, OnDestroy { @@ -27,7 +27,7 @@ export class EnergymonitorChartComponent implements OnInit, OnDestroy { @ViewChild(StorageSectionComponent, { static: true }) public storageSection: StorageSectionComponent; - @ViewChild('energymonitorChart', { static: true }) + @ViewChild("energymonitorChart", { static: true }) private chartDiv: ElementRef; public translation: string; @@ -39,8 +39,6 @@ export class EnergymonitorChartComponent implements OnInit, OnDestroy { private ngUnsubscribe: Subject = new Subject(); - - constructor( private service: Service, ) { } @@ -54,7 +52,7 @@ export class EnergymonitorChartComponent implements OnInit, OnDestroy { this.service.startSpinner(this.spinnerId); // make sure chart is redrawn in the beginning and on window resize setTimeout(() => this.updateOnWindowResize(), 500); - const source = fromEvent(window, 'resize', null, null); + const source = fromEvent(window, "resize", null, null); source.pipe(takeUntil(this.ngUnsubscribe), debounceTime(200), delay(100)).subscribe(e => { this.updateOnWindowResize(); }); diff --git a/ui/src/app/edge/live/energymonitor/chart/section/abstractsection.component.ts b/ui/src/app/edge/live/energymonitor/chart/section/abstractsection.component.ts index 047bdff0e4d..e254768d5ca 100644 --- a/ui/src/app/edge/live/energymonitor/chart/section/abstractsection.component.ts +++ b/ui/src/app/edge/live/energymonitor/chart/section/abstractsection.component.ts @@ -1,10 +1,10 @@ // @ts-strict-ignore -import { TranslateService } from '@ngx-translate/core'; -import * as d3 from 'd3'; -import { GridMode, Service } from 'src/app/shared/shared'; -import { DefaultTypes } from '../../../../../shared/service/defaulttypes'; +import { TranslateService } from "@ngx-translate/core"; +import * as d3 from "d3"; +import { GridMode, Service } from "src/app/shared/shared"; +import { DefaultTypes } from "../../../../../shared/service/defaulttypes"; -export type Ratio = 'Only Positive [0,1]' | 'Negative and Positive [-1,1]'; +export type Ratio = "Only Positive [0,1]" | "Negative and Positive [-1,1]"; export class SectionValue { public absolute: number; @@ -101,17 +101,17 @@ export class EnergyFlow { } public switchState() { - if (this.state == 'one') { - this.state = 'two'; - } else if (this.state == 'two') { - this.state = 'one'; + if (this.state == "one") { + this.state = "two"; + } else if (this.state == "two") { + this.state = "one"; } else { - this.state = 'one'; + this.state = "one"; } } public hide() { - this.state = 'three'; + this.state = "three"; } } diff --git a/ui/src/app/edge/live/energymonitor/chart/section/consumption.component.ts b/ui/src/app/edge/live/energymonitor/chart/section/consumption.component.ts index 642f1725a2d..440054a0768 100644 --- a/ui/src/app/edge/live/energymonitor/chart/section/consumption.component.ts +++ b/ui/src/app/edge/live/energymonitor/chart/section/consumption.component.ts @@ -1,27 +1,27 @@ // @ts-strict-ignore -import { animate, state, style, transition, trigger } from '@angular/animations'; -import { Component, OnDestroy, OnInit } from '@angular/core'; -import { TranslateService } from '@ngx-translate/core'; -import { UnitvaluePipe } from 'src/app/shared/pipe/unitvalue/unitvalue.pipe'; -import { DefaultTypes } from '../../../../../shared/service/defaulttypes'; -import { Service, Utils } from '../../../../../shared/shared'; -import { AbstractSection, EnergyFlow, Ratio, SvgEnergyFlow, SvgSquare, SvgSquarePosition } from './abstractsection.component'; +import { animate, state, style, transition, trigger } from "@angular/animations"; +import { Component, OnDestroy, OnInit } from "@angular/core"; +import { TranslateService } from "@ngx-translate/core"; +import { UnitvaluePipe } from "src/app/shared/pipe/unitvalue/unitvalue.pipe"; +import { DefaultTypes } from "../../../../../shared/service/defaulttypes"; +import { Service, Utils } from "../../../../../shared/shared"; +import { AbstractSection, EnergyFlow, Ratio, SvgEnergyFlow, SvgSquare, SvgSquarePosition } from "./abstractsection.component"; @Component({ - selector: '[consumptionsection]', - templateUrl: './consumption.component.html', + selector: "[consumptionsection]", + templateUrl: "./consumption.component.html", animations: [ - trigger('Consumption', [ - state('show', style({ + trigger("Consumption", [ + state("show", style({ opacity: 0.1, - transform: 'translateX(0%)', + transform: "translateX(0%)", })), - state('hide', style({ + state("hide", style({ opacity: 0.6, - transform: 'translateX(17%)', + transform: "translateX(17%)", })), - transition('show => hide', animate('650ms ease-out')), - transition('hide => show', animate('0ms ease-in')), + transition("show => hide", animate("650ms ease-out")), + transition("hide => show", animate("0ms ease-in")), ]), ], }) @@ -38,12 +38,12 @@ export class ConsumptionSectionComponent extends AbstractSection implements OnIn translate: TranslateService, service: Service, ) { - super('General.consumption', "right", "#FDC507", translate, service, "Consumption"); + super("General.consumption", "right", "#FDC507", translate, service, "Consumption"); this.unitpipe = unitpipe; } get stateName() { - return this.showAnimation ? 'show' : 'hide'; + return this.showAnimation ? "show" : "hide"; } ngOnInit() { @@ -70,7 +70,7 @@ export class ConsumptionSectionComponent extends AbstractSection implements OnIn } protected getRatioType(): Ratio { - return 'Only Positive [0,1]'; + return "Only Positive [0,1]"; } protected _updateCurrentData(sum: DefaultTypes.Summary): void { @@ -103,7 +103,7 @@ export class ConsumptionSectionComponent extends AbstractSection implements OnIn if (value == null || Number.isNaN(value)) { return ""; } - return this.unitpipe.transform(value, 'kW'); + return this.unitpipe.transform(value, "kW"); } protected initEnergyFlow(radius: number): EnergyFlow { diff --git a/ui/src/app/edge/live/energymonitor/chart/section/grid.component.ts b/ui/src/app/edge/live/energymonitor/chart/section/grid.component.ts index e5183e215c4..c0c61013161 100644 --- a/ui/src/app/edge/live/energymonitor/chart/section/grid.component.ts +++ b/ui/src/app/edge/live/energymonitor/chart/section/grid.component.ts @@ -1,40 +1,40 @@ // @ts-strict-ignore -import { animate, state, style, transition, trigger } from '@angular/animations'; -import { Component, OnDestroy, OnInit } from '@angular/core'; -import { TranslateService } from '@ngx-translate/core'; -import { UnitvaluePipe } from 'src/app/shared/pipe/unitvalue/unitvalue.pipe'; -import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; -import { Icon } from 'src/app/shared/type/widget'; -import { CurrentData, EdgeConfig, GridMode, Service, Utils } from '../../../../../shared/shared'; -import { AbstractSection, EnergyFlow, Ratio, SvgEnergyFlow, SvgSquare, SvgSquarePosition } from './abstractsection.component'; +import { animate, state, style, transition, trigger } from "@angular/animations"; +import { Component, OnDestroy, OnInit } from "@angular/core"; +import { TranslateService } from "@ngx-translate/core"; +import { UnitvaluePipe } from "src/app/shared/pipe/unitvalue/unitvalue.pipe"; +import { DefaultTypes } from "src/app/shared/service/defaulttypes"; +import { Icon } from "src/app/shared/type/widget"; +import { CurrentData, EdgeConfig, GridMode, Service, Utils } from "../../../../../shared/shared"; +import { AbstractSection, EnergyFlow, Ratio, SvgEnergyFlow, SvgSquare, SvgSquarePosition } from "./abstractsection.component"; @Component({ - selector: '[gridsection]', - templateUrl: './grid.component.html', + selector: "[gridsection]", + templateUrl: "./grid.component.html", animations: [ - trigger('GridBuy', [ - state('show', style({ + trigger("GridBuy", [ + state("show", style({ opacity: 0.4, - transform: 'translateX(0%)', + transform: "translateX(0%)", })), - state('hide', style({ + state("hide", style({ opacity: 0.1, - transform: 'translateX(17%)', + transform: "translateX(17%)", })), - transition('show => hide', animate('650ms')), - transition('hide => show', animate('0ms')), + transition("show => hide", animate("650ms")), + transition("hide => show", animate("0ms")), ]), - trigger('GridSell', [ - state('show', style({ + trigger("GridSell", [ + state("show", style({ opacity: 0.1, - transform: 'translateX(0%)', + transform: "translateX(0%)", })), - state('hide', style({ + state("hide", style({ opacity: 0.4, - transform: 'translateX(-17%)', + transform: "translateX(-17%)", })), - transition('show => hide', animate('650ms ease-out')), - transition('hide => show', animate('0ms ease-in')), + transition("show => hide", animate("650ms ease-out")), + transition("hide => show", animate("0ms ease-in")), ]), ], }) @@ -54,39 +54,39 @@ export class GridSectionComponent extends AbstractSection implements OnInit, OnD service: Service, unitpipe: UnitvaluePipe, ) { - super('General.grid', "left", "#1d1d1d", translate, service, "Grid"); + super("General.grid", "left", "#1d1d1d", translate, service, "Grid"); this.unitpipe = unitpipe; } get stateNameBuy() { - return this.showBuyAnimation ? 'show' : 'hide'; + return this.showBuyAnimation ? "show" : "hide"; } get stateNameSell() { - return this.showSellAnimation ? 'show' : 'hide'; + return this.showSellAnimation ? "show" : "hide"; } public static getCurrentGridIcon(currentData: CurrentData): Icon { - const gridMode = currentData.allComponents['_sum/GridMode']; - const restrictionMode = currentData.allComponents['ctrlEssLimiter14a0/RestrictionMode']; + const gridMode = currentData.allComponents["_sum/GridMode"]; + const restrictionMode = currentData.allComponents["ctrlEssLimiter14a0/RestrictionMode"]; if (gridMode === GridMode.OFF_GRID) { return { - color: 'dark', - name: 'oe-offgrid', - size: '', + color: "dark", + name: "oe-offgrid", + size: "", }; } if (restrictionMode === 1) { return { - color: 'dark', - name: 'oe-grid-restriction', - size: '', + color: "dark", + name: "oe-grid-restriction", + size: "", }; } return { - color: 'dark', - name: 'oe-grid', - size: '', + color: "dark", + name: "oe-grid", + size: "", }; } @@ -131,7 +131,7 @@ export class GridSectionComponent extends AbstractSection implements OnInit, OnD } else { arrowIndicate = 0; } - this.name = this.translate.instant('General.gridBuy'); + this.name = this.translate.instant("General.gridBuy"); super.updateSectionData( sum.grid.buyActivePower, sum.grid.powerRatio, @@ -147,13 +147,13 @@ export class GridSectionComponent extends AbstractSection implements OnInit, OnD } else { arrowIndicate = 0; } - this.name = this.translate.instant('General.gridSell'); + this.name = this.translate.instant("General.gridSell"); super.updateSectionData( sum.grid.sellActivePower, sum.grid.powerRatio, arrowIndicate); } else { - this.name = this.translate.instant('General.grid'); + this.name = this.translate.instant("General.grid"); super.updateSectionData(0, null, null); } @@ -173,7 +173,7 @@ export class GridSectionComponent extends AbstractSection implements OnInit, OnD } protected getRatioType(): Ratio { - return 'Negative and Positive [-1,1]'; + return "Negative and Positive [-1,1]"; } protected getSquarePosition(square: SvgSquare, innerRadius: number): SvgSquarePosition { @@ -195,7 +195,7 @@ export class GridSectionComponent extends AbstractSection implements OnInit, OnD if (value == null || Number.isNaN(value)) { return ""; } - return this.unitpipe.transform(value, 'kW'); + return this.unitpipe.transform(value, "kW"); } protected initEnergyFlow(radius: number): EnergyFlow { diff --git a/ui/src/app/edge/live/energymonitor/chart/section/production.component.ts b/ui/src/app/edge/live/energymonitor/chart/section/production.component.ts index e3615983827..a5efc3de02e 100644 --- a/ui/src/app/edge/live/energymonitor/chart/section/production.component.ts +++ b/ui/src/app/edge/live/energymonitor/chart/section/production.component.ts @@ -1,27 +1,27 @@ // @ts-strict-ignore -import { animate, state, style, transition, trigger } from '@angular/animations'; -import { Component, OnDestroy, OnInit } from '@angular/core'; -import { TranslateService } from '@ngx-translate/core'; -import { UnitvaluePipe } from 'src/app/shared/pipe/unitvalue/unitvalue.pipe'; -import { DefaultTypes } from '../../../../../shared/service/defaulttypes'; -import { Service, Utils } from '../../../../../shared/shared'; -import { AbstractSection, EnergyFlow, Ratio, SvgEnergyFlow, SvgSquare, SvgSquarePosition } from './abstractsection.component'; +import { animate, state, style, transition, trigger } from "@angular/animations"; +import { Component, OnDestroy, OnInit } from "@angular/core"; +import { TranslateService } from "@ngx-translate/core"; +import { UnitvaluePipe } from "src/app/shared/pipe/unitvalue/unitvalue.pipe"; +import { DefaultTypes } from "../../../../../shared/service/defaulttypes"; +import { Service, Utils } from "../../../../../shared/shared"; +import { AbstractSection, EnergyFlow, Ratio, SvgEnergyFlow, SvgSquare, SvgSquarePosition } from "./abstractsection.component"; @Component({ - selector: '[productionsection]', - templateUrl: './production.component.html', + selector: "[productionsection]", + templateUrl: "./production.component.html", animations: [ - trigger('Production', [ - state('show', style({ + trigger("Production", [ + state("show", style({ opacity: 0.4, - transform: 'translateY(0)', + transform: "translateY(0)", })), - state('hide', style({ + state("hide", style({ opacity: 0.1, - transform: 'translateY(17%)', + transform: "translateY(17%)", })), - transition('show => hide', animate('650ms ease-out')), - transition('hide => show', animate('0ms ease-in')), + transition("show => hide", animate("650ms ease-out")), + transition("hide => show", animate("0ms ease-in")), ]), ], }) @@ -38,12 +38,12 @@ export class ProductionSectionComponent extends AbstractSection implements OnIni service: Service, unitpipe: UnitvaluePipe, ) { - super('General.production', "up", "#36aed1", translate, service, "Common_Production"); + super("General.production", "up", "#36aed1", translate, service, "Common_Production"); this.unitpipe = unitpipe; } get stateName() { - return this.showAnimation ? 'show' : 'hide'; + return this.showAnimation ? "show" : "hide"; } ngOnInit() { @@ -70,7 +70,7 @@ export class ProductionSectionComponent extends AbstractSection implements OnIni } protected getRatioType(): Ratio { - return 'Only Positive [0,1]'; + return "Only Positive [0,1]"; } protected _updateCurrentData(sum: DefaultTypes.Summary): void { @@ -105,7 +105,7 @@ export class ProductionSectionComponent extends AbstractSection implements OnIni return ""; } - return this.unitpipe.transform(value, 'kW'); + return this.unitpipe.transform(value, "kW"); } protected initEnergyFlow(radius: number): EnergyFlow { diff --git a/ui/src/app/edge/live/energymonitor/chart/section/storage.component.ts b/ui/src/app/edge/live/energymonitor/chart/section/storage.component.ts index 62f95103b1a..e98c6d563cf 100644 --- a/ui/src/app/edge/live/energymonitor/chart/section/storage.component.ts +++ b/ui/src/app/edge/live/energymonitor/chart/section/storage.component.ts @@ -1,40 +1,40 @@ // @ts-strict-ignore -import { animate, state, style, transition, trigger } from '@angular/animations'; -import { Component, OnDestroy, OnInit } from '@angular/core'; -import { TranslateService } from '@ngx-translate/core'; -import { CurrentData } from 'src/app/shared/components/edge/currentdata'; -import { UnitvaluePipe } from 'src/app/shared/pipe/unitvalue/unitvalue.pipe'; -import { DefaultTypes } from '../../../../../shared/service/defaulttypes'; -import { Service, Utils } from '../../../../../shared/shared'; -import { AbstractSection, EnergyFlow, Ratio, SvgEnergyFlow, SvgSquare, SvgSquarePosition } from './abstractsection.component'; +import { animate, state, style, transition, trigger } from "@angular/animations"; +import { Component, OnDestroy, OnInit } from "@angular/core"; +import { TranslateService } from "@ngx-translate/core"; +import { CurrentData } from "src/app/shared/components/edge/currentdata"; +import { UnitvaluePipe } from "src/app/shared/pipe/unitvalue/unitvalue.pipe"; +import { DefaultTypes } from "../../../../../shared/service/defaulttypes"; +import { Service, Utils } from "../../../../../shared/shared"; +import { AbstractSection, EnergyFlow, Ratio, SvgEnergyFlow, SvgSquare, SvgSquarePosition } from "./abstractsection.component"; @Component({ - selector: '[storagesection]', - templateUrl: './storage.component.html', + selector: "[storagesection]", + templateUrl: "./storage.component.html", animations: [ - trigger('Discharge', [ - state('show', style({ + trigger("Discharge", [ + state("show", style({ opacity: 0.4, - transform: 'translateY(0)', + transform: "translateY(0)", })), - state('hide', style({ + state("hide", style({ opacity: 0.1, - transform: 'translateY(-17%)', + transform: "translateY(-17%)", })), - transition('show => hide', animate('650ms ease-out')), - transition('hide => show', animate('0ms ease-in')), + transition("show => hide", animate("650ms ease-out")), + transition("hide => show", animate("0ms ease-in")), ]), - trigger('Charge', [ - state('show', style({ + trigger("Charge", [ + state("show", style({ opacity: 0.1, - transform: 'translateY(0)', + transform: "translateY(0)", })), - state('hide', style({ + state("hide", style({ opacity: 0.4, - transform: 'translateY(17%)', + transform: "translateY(17%)", })), - transition('show => hide', animate('650ms ease-out')), - transition('hide => show', animate('0ms ease-out')), + transition("show => hide", animate("650ms ease-out")), + transition("hide => show", animate("0ms ease-out")), ]), ], }) @@ -55,16 +55,16 @@ export class StorageSectionComponent extends AbstractSection implements OnInit, protected override service: Service, unitpipe: UnitvaluePipe, ) { - super('Edge.Index.Energymonitor.storage', "down", "#009846", translate, service, "Storage"); + super("Edge.Index.Energymonitor.storage", "down", "#009846", translate, service, "Storage"); this.unitpipe = unitpipe; } get stateNameCharge() { - return this.showChargeAnimation ? 'show' : 'hide'; + return this.showChargeAnimation ? "show" : "hide"; } get stateNameDischarge() { - return this.showDischargeAnimation ? 'show' : 'hide'; + return this.showDischargeAnimation ? "show" : "hide"; } ngOnInit() { @@ -96,12 +96,12 @@ export class StorageSectionComponent extends AbstractSection implements OnInit, this.service.getCurrentEdge() .then(async edge => { edge.currentData.subscribe(curr => { - const maxApparentPower = edge.isVersionAtLeast('2024.2.2') - ? curr.channel['_sum/EssMaxDischargePower'] - : curr.channel['_sum/EssMaxApparentPower']; - const minDischargePower = edge.isVersionAtLeast('2024.2.2') - ? curr.channel['_sum/EssMinDischargePower'] - : curr.channel['_sum/EssMaxApparentPower']; + const maxApparentPower = edge.isVersionAtLeast("2024.2.2") + ? curr.channel["_sum/EssMaxDischargePower"] + : curr.channel["_sum/EssMaxApparentPower"]; + const minDischargePower = edge.isVersionAtLeast("2024.2.2") + ? curr.channel["_sum/EssMinDischargePower"] + : curr.channel["_sum/EssMaxApparentPower"]; sum.storage.powerRatio = CurrentData.getEssPowerRatio(maxApparentPower, minDischargePower, sum.storage.effectivePower); @@ -117,7 +117,7 @@ export class StorageSectionComponent extends AbstractSection implements OnInit, arrowIndicate = 0; } - this.name = this.translate.instant('Edge.Index.Energymonitor.storageCharge'); + this.name = this.translate.instant("Edge.Index.Energymonitor.storageCharge"); super.updateSectionData( sum.storage.effectiveChargePower, sum.storage.powerRatio, @@ -133,20 +133,20 @@ export class StorageSectionComponent extends AbstractSection implements OnInit, } else { arrowIndicate = 0; } - this.name = this.translate.instant('Edge.Index.Energymonitor.storageDischarge'); + this.name = this.translate.instant("Edge.Index.Energymonitor.storageDischarge"); super.updateSectionData( sum.storage.effectiveDischargePower, sum.storage.powerRatio, arrowIndicate); } else { - this.name = this.translate.instant('Edge.Index.Energymonitor.storage'); + this.name = this.translate.instant("Edge.Index.Energymonitor.storage"); super.updateSectionData(null, null, null); } this.socValue = sum.storage.soc; if (this.square) { this.square.image.image = "assets/img/" + this.getImagePath(); - this.svgStyle = 'storage-' + Utils.getStorageSocSegment(this.socValue); + this.svgStyle = "storage-" + Utils.getStorageSocSegment(this.socValue); } }); }); @@ -161,7 +161,7 @@ export class StorageSectionComponent extends AbstractSection implements OnInit, } protected getRatioType(): Ratio { - return 'Negative and Positive [-1,1]'; + return "Negative and Positive [-1,1]"; } protected getSquarePosition(square: SvgSquare, innerRadius: number): SvgSquarePosition { @@ -178,7 +178,7 @@ export class StorageSectionComponent extends AbstractSection implements OnInit, if (value == null || Number.isNaN(value)) { return ""; } - return this.unitpipe.transform(value, 'kW'); + return this.unitpipe.transform(value, "kW"); } protected initEnergyFlow(radius: number): EnergyFlow { diff --git a/ui/src/app/edge/live/energymonitor/energymonitor.component.ts b/ui/src/app/edge/live/energymonitor/energymonitor.component.ts index d696a7497ba..8e07bbd2b83 100644 --- a/ui/src/app/edge/live/energymonitor/energymonitor.component.ts +++ b/ui/src/app/edge/live/energymonitor/energymonitor.component.ts @@ -1,10 +1,10 @@ -import { Component, OnDestroy, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { ChannelAddress, Edge, Service, Websocket } from '../../../shared/shared'; +import { Component, OnDestroy, OnInit } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { ChannelAddress, Edge, Service, Websocket } from "../../../shared/shared"; @Component({ selector: EnergymonitorComponent.SELECTOR, - templateUrl: './energymonitor.component.html', + templateUrl: "./energymonitor.component.html", }) export class EnergymonitorComponent implements OnInit, OnDestroy { @@ -18,23 +18,23 @@ export class EnergymonitorComponent implements OnInit, OnDestroy { ) { } ngOnInit() { - this.service.setCurrentComponent('', this.route).then(edge => { + this.service.getCurrentEdge().then(edge => { this.edge = edge; - const essMinMaxChannels = this.edge.isVersionAtLeast('2024.2.2') - ? [new ChannelAddress('_sum', 'EssMinDischargePower'), new ChannelAddress('_sum', 'EssMaxDischargePower')] - : [new ChannelAddress('_sum', 'EssMaxApparentPower')]; + const essMinMaxChannels = this.edge.isVersionAtLeast("2024.2.2") + ? [new ChannelAddress("_sum", "EssMinDischargePower"), new ChannelAddress("_sum", "EssMaxDischargePower")] + : [new ChannelAddress("_sum", "EssMaxApparentPower")]; edge.subscribeChannels(this.websocket, EnergymonitorComponent.SELECTOR, [ // Ess - new ChannelAddress('_sum', 'EssSoc'), new ChannelAddress('_sum', 'EssActivePower'), + new ChannelAddress("_sum", "EssSoc"), new ChannelAddress("_sum", "EssActivePower"), ...essMinMaxChannels, // Grid - new ChannelAddress('_sum', 'GridActivePower'), new ChannelAddress('_sum', 'GridMinActivePower'), new ChannelAddress('_sum', 'GridMaxActivePower'), new ChannelAddress('_sum', 'GridMode'), + new ChannelAddress("_sum", "GridActivePower"), new ChannelAddress("_sum", "GridMinActivePower"), new ChannelAddress("_sum", "GridMaxActivePower"), new ChannelAddress("_sum", "GridMode"), // Production - new ChannelAddress('_sum', 'ProductionActivePower'), new ChannelAddress('_sum', 'ProductionDcActualPower'), new ChannelAddress('_sum', 'ProductionAcActivePower'), new ChannelAddress('_sum', 'ProductionMaxActivePower'), + new ChannelAddress("_sum", "ProductionActivePower"), new ChannelAddress("_sum", "ProductionDcActualPower"), new ChannelAddress("_sum", "ProductionAcActivePower"), new ChannelAddress("_sum", "ProductionMaxActivePower"), // Consumption - new ChannelAddress('_sum', 'ConsumptionActivePower'), new ChannelAddress('_sum', 'ConsumptionMaxActivePower'), + new ChannelAddress("_sum", "ConsumptionActivePower"), new ChannelAddress("_sum", "ConsumptionMaxActivePower"), ]); }); } diff --git a/ui/src/app/edge/live/energymonitor/energymonitor.module.ts b/ui/src/app/edge/live/energymonitor/energymonitor.module.ts index 1939bbf9d45..9da9e75aa96 100644 --- a/ui/src/app/edge/live/energymonitor/energymonitor.module.ts +++ b/ui/src/app/edge/live/energymonitor/energymonitor.module.ts @@ -1,13 +1,13 @@ -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { SharedModule } from './../../../shared/shared.module'; -import { EnergymonitorChartComponent } from './chart/chart.component'; -import { ConsumptionSectionComponent } from './chart/section/consumption.component'; -import { GridSectionComponent } from './chart/section/grid.component'; -import { ProductionSectionComponent } from './chart/section/production.component'; -import { StorageSectionComponent } from './chart/section/storage.component'; -import { EnergymonitorComponent } from './energymonitor.component'; +import { NgModule } from "@angular/core"; +import { BrowserModule } from "@angular/platform-browser"; +import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; +import { SharedModule } from "./../../../shared/shared.module"; +import { EnergymonitorChartComponent } from "./chart/chart.component"; +import { ConsumptionSectionComponent } from "./chart/section/consumption.component"; +import { GridSectionComponent } from "./chart/section/grid.component"; +import { ProductionSectionComponent } from "./chart/section/production.component"; +import { StorageSectionComponent } from "./chart/section/storage.component"; +import { EnergymonitorComponent } from "./energymonitor.component"; @NgModule({ imports: [ @@ -28,6 +28,3 @@ import { EnergymonitorComponent } from './energymonitor.component'; ], }) export class EnergymonitorModule { } - - - diff --git a/ui/src/app/edge/live/info/info.component.ts b/ui/src/app/edge/live/info/info.component.ts index bc48bcc65e9..92da7235422 100644 --- a/ui/src/app/edge/live/info/info.component.ts +++ b/ui/src/app/edge/live/info/info.component.ts @@ -1,7 +1,7 @@ -import { Component } from '@angular/core'; +import { Component } from "@angular/core"; @Component({ - selector: 'info', - templateUrl: './info.component.html', + selector: "info", + templateUrl: "./info.component.html", }) export class InfoComponent { } diff --git a/ui/src/app/edge/live/live.component.html b/ui/src/app/edge/live/live.component.html index bef5c983782..edf538ba7ab 100644 --- a/ui/src/app/edge/live/live.component.html +++ b/ui/src/app/edge/live/live.component.html @@ -1,7 +1,7 @@
      - + diff --git a/ui/src/app/edge/live/live.component.ts b/ui/src/app/edge/live/live.component.ts index 07ef40f7c93..e3e022542c6 100644 --- a/ui/src/app/edge/live/live.component.ts +++ b/ui/src/app/edge/live/live.component.ts @@ -1,13 +1,13 @@ -import { Component, OnDestroy, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { RefresherCustomEvent } from '@ionic/angular'; -import { Subject } from 'rxjs'; -import { DataService } from 'src/app/shared/components/shared/dataservice'; -import { Edge, EdgeConfig, Service, Utils, Websocket, Widgets } from 'src/app/shared/shared'; +import { Component, OnDestroy, OnInit } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { RefresherCustomEvent } from "@ionic/angular"; +import { Subject } from "rxjs"; +import { DataService } from "src/app/shared/components/shared/dataservice"; +import { Edge, EdgeConfig, Service, Utils, Websocket, Widgets } from "src/app/shared/shared"; @Component({ - selector: 'live', - templateUrl: './live.component.html', + selector: "live", + templateUrl: "./live.component.html", }) export class LiveComponent implements OnInit, OnDestroy { @@ -25,7 +25,6 @@ export class LiveComponent implements OnInit, OnDestroy { ) { } public ngOnInit() { - this.service.setCurrentComponent('', this.route); this.service.currentEdge.subscribe((edge) => { this.edge = edge; }); diff --git a/ui/src/app/edge/live/live.module.ts b/ui/src/app/edge/live/live.module.ts index a21b0b2caae..e3d7bbc0de3 100644 --- a/ui/src/app/edge/live/live.module.ts +++ b/ui/src/app/edge/live/live.module.ts @@ -1,46 +1,46 @@ -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { SharedModule } from './../../shared/shared.module'; -import { Common_Autarchy } from './common/autarchy/Common_Autarchy'; -import { Common_Consumption } from './common/consumption/Common_Consumption'; -import { Common_Grid } from './common/grid/Common_Grid'; -import { Common_Production } from './common/production/Common_Production'; -import { Common_Selfconsumption } from './common/selfconsumption/Common_Selfconsumption'; -import { StorageModalComponent } from './common/storage/modal/modal.component'; -import { StorageComponent } from './common/storage/storage.component'; -import { Controller_ChannelthresholdComponent } from './Controller/Channelthreshold/Channelthreshold'; -import { Controller_ChpSocComponent } from './Controller/ChpSoc/ChpSoc'; -import { Controller_ChpSocModalComponent } from './Controller/ChpSoc/modal/modal.component'; -import { Controller_Ess_FixActivePower } from './Controller/Ess/FixActivePower/Ess_FixActivePower'; -import { Controller_Ess_GridOptimizedCharge } from './Controller/Ess/GridOptimizedCharge/Ess_GridOptimizedCharge'; -import { Controller_Ess_TimeOfUseTariff } from './Controller/Ess/TimeOfUseTariff/Ess_TimeOfUseTariff'; -import { AdministrationComponent } from './Controller/Evcs/administration/administration.component'; -import { Controller_Evcs } from './Controller/Evcs/Evcs'; -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'; -import { Controller_Io_FixDigitalOutputModalComponent } from './Controller/Io/FixDigitalOutput/modal/modal.component'; -import { Controller_Io_HeatingElement } from './Controller/Io/HeatingElement/Io_HeatingElement'; -import { Controller_Io_HeatpumpComponent } from './Controller/Io/Heatpump/Io_Heatpump'; -import { Controller_Io_HeatpumpModalComponent } from './Controller/Io/Heatpump/modal/modal.component'; -import { Controller_Asymmetric_PeakShavingComponent } from './Controller/PeakShaving/Asymmetric/Asymmetric'; -import { Controller_Asymmetric_PeakShavingModalComponent } from './Controller/PeakShaving/Asymmetric/modal/modal.component'; -import { Controller_Symmetric_PeakShavingModalComponent } from './Controller/PeakShaving/Symmetric/modal/modal.component'; -import { Controller_Symmetric_PeakShavingComponent } from './Controller/PeakShaving/Symmetric/Symmetric'; -import { Controller_Symmetric_TimeSlot_PeakShavingModalComponent } from './Controller/PeakShaving/Symmetric_TimeSlot/modal/modal.component'; -import { Controller_Symmetric_TimeSlot_PeakShavingComponent } from './Controller/PeakShaving/Symmetric_TimeSlot/Symmetric_TimeSlot'; -import { DelayedSellToGridComponent } from './delayedselltogrid/delayedselltogrid.component'; -import { DelayedSellToGridModalComponent } from './delayedselltogrid/modal/modal.component'; -import { EnergymonitorModule } from './energymonitor/energymonitor.module'; -import { InfoComponent } from './info/info.component'; -import { Io_Api_DigitalInputComponent } from './Io/Api_DigitalInput/Io_Api_DigitalInput'; -import { Io_Api_DigitalInput_ModalComponent } from './Io/Api_DigitalInput/modal/modal.component'; -import { LiveComponent } from './live.component'; -import { Evcs_Api_ClusterComponent } from './Multiple/Evcs_Api_Cluster/Evcs_Api_Cluster'; -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 { NgModule } from "@angular/core"; +import { BrowserModule } from "@angular/platform-browser"; +import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; +import { SharedModule } from "./../../shared/shared.module"; +import { Common_Autarchy } from "./common/autarchy/Common_Autarchy"; +import { Common_Consumption } from "./common/consumption/Common_Consumption"; +import { Common_Grid } from "./common/grid/Common_Grid"; +import { Common_Production } from "./common/production/Common_Production"; +import { Common_Selfconsumption } from "./common/selfconsumption/Common_Selfconsumption"; +import { StorageModalComponent } from "./common/storage/modal/modal.component"; +import { StorageComponent } from "./common/storage/storage.component"; +import { Controller_ChannelthresholdComponent } from "./Controller/Channelthreshold/Channelthreshold"; +import { Controller_ChpSocComponent } from "./Controller/ChpSoc/ChpSoc"; +import { Controller_ChpSocModalComponent } from "./Controller/ChpSoc/modal/modal.component"; +import { Controller_Ess_FixActivePower } from "./Controller/Ess/FixActivePower/Ess_FixActivePower"; +import { Controller_Ess_GridOptimizedCharge } from "./Controller/Ess/GridOptimizedCharge/Ess_GridOptimizedCharge"; +import { Controller_Ess_TimeOfUseTariff } from "./Controller/Ess/TimeOfUseTariff/Ess_TimeOfUseTariff"; +import { AdministrationComponent } from "./Controller/Evcs/administration/administration.component"; +import { Controller_Evcs } from "./Controller/Evcs/Evcs"; +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"; +import { Controller_Io_FixDigitalOutputModalComponent } from "./Controller/Io/FixDigitalOutput/modal/modal.component"; +import { Controller_Io_HeatingElement } from "./Controller/Io/HeatingElement/Io_HeatingElement"; +import { Controller_Io_HeatpumpComponent } from "./Controller/Io/Heatpump/Io_Heatpump"; +import { Controller_Io_HeatpumpModalComponent } from "./Controller/Io/Heatpump/modal/modal.component"; +import { Controller_Asymmetric_PeakShavingComponent } from "./Controller/PeakShaving/Asymmetric/Asymmetric"; +import { Controller_Asymmetric_PeakShavingModalComponent } from "./Controller/PeakShaving/Asymmetric/modal/modal.component"; +import { Controller_Symmetric_PeakShavingModalComponent } from "./Controller/PeakShaving/Symmetric/modal/modal.component"; +import { Controller_Symmetric_PeakShavingComponent } from "./Controller/PeakShaving/Symmetric/Symmetric"; +import { Controller_Symmetric_TimeSlot_PeakShavingModalComponent } from "./Controller/PeakShaving/Symmetric_TimeSlot/modal/modal.component"; +import { Controller_Symmetric_TimeSlot_PeakShavingComponent } from "./Controller/PeakShaving/Symmetric_TimeSlot/Symmetric_TimeSlot"; +import { DelayedSellToGridComponent } from "./delayedselltogrid/delayedselltogrid.component"; +import { DelayedSellToGridModalComponent } from "./delayedselltogrid/modal/modal.component"; +import { EnergymonitorModule } from "./energymonitor/energymonitor.module"; +import { InfoComponent } from "./info/info.component"; +import { Io_Api_DigitalInputComponent } from "./Io/Api_DigitalInput/Io_Api_DigitalInput"; +import { Io_Api_DigitalInput_ModalComponent } from "./Io/Api_DigitalInput/modal/modal.component"; +import { LiveComponent } from "./live.component"; +import { Evcs_Api_ClusterComponent } from "./Multiple/Evcs_Api_Cluster/Evcs_Api_Cluster"; +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"; @NgModule({ imports: [ diff --git a/ui/src/app/edge/live/livedataservice.ts b/ui/src/app/edge/live/livedataservice.ts index 3bcde8edb9c..e4eda4ab642 100644 --- a/ui/src/app/edge/live/livedataservice.ts +++ b/ui/src/app/edge/live/livedataservice.ts @@ -2,7 +2,7 @@ import { Directive, Inject, OnDestroy } from "@angular/core"; import { RefresherCustomEvent } from "@ionic/angular"; import { takeUntil } from "rxjs/operators"; -import { v4 as uuidv4 } from 'uuid'; +import { v4 as uuidv4 } from "uuid"; import { DataService } from "../../shared/components/shared/dataservice"; import { ChannelAddress, Edge, Service, Websocket } from "../../shared/shared"; diff --git a/ui/src/app/edge/live/offline/offline.component.ts b/ui/src/app/edge/live/offline/offline.component.ts index b168aabffe6..5af0358d185 100644 --- a/ui/src/app/edge/live/offline/offline.component.ts +++ b/ui/src/app/edge/live/offline/offline.component.ts @@ -1,11 +1,11 @@ -import { Component, OnInit } from '@angular/core'; -import { Edge, Service, Utils } from 'src/app/shared/shared'; -import { DateUtils } from 'src/app/shared/utils/date/dateutils'; +import { Component, OnInit } from "@angular/core"; +import { Edge, Service, Utils } from "src/app/shared/shared"; +import { DateUtils } from "src/app/shared/utils/date/dateutils"; // TODO add translations when refactoring offline.component.html @Component({ - selector: 'offline', - templateUrl: './offline.component.html', + selector: "offline", + templateUrl: "./offline.component.html", }) export class OfflineComponent implements OnInit { diff --git a/ui/src/app/edge/settings/alerting/alerting.component.ts b/ui/src/app/edge/settings/alerting/alerting.component.ts index a9d378aa220..865420ec5bc 100644 --- a/ui/src/app/edge/settings/alerting/alerting.component.ts +++ b/ui/src/app/edge/settings/alerting/alerting.component.ts @@ -1,12 +1,12 @@ // @ts-strict-ignore -import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup } from '@angular/forms'; -import { ActivatedRoute } from '@angular/router'; -import { TranslateService } from '@ngx-translate/core'; -import { GetUserAlertingConfigsRequest } from 'src/app/shared/jsonrpc/request/getUserAlertingConfigsRequest'; -import { SetUserAlertingConfigsRequest, UserSettingRequest } from 'src/app/shared/jsonrpc/request/setUserAlertingConfigsRequest'; -import { AlertingSettingResponse, GetUserAlertingConfigsResponse } from 'src/app/shared/jsonrpc/response/getUserAlertingConfigsResponse'; -import { Edge, Service, Utils, Websocket } from 'src/app/shared/shared'; +import { Component, OnInit } from "@angular/core"; +import { FormBuilder, FormControl, FormGroup } from "@angular/forms"; +import { ActivatedRoute } from "@angular/router"; +import { TranslateService } from "@ngx-translate/core"; +import { GetUserAlertingConfigsRequest } from "src/app/shared/jsonrpc/request/getUserAlertingConfigsRequest"; +import { SetUserAlertingConfigsRequest, UserSettingRequest } from "src/app/shared/jsonrpc/request/setUserAlertingConfigsRequest"; +import { AlertingSettingResponse, GetUserAlertingConfigsResponse } from "src/app/shared/jsonrpc/response/getUserAlertingConfigsResponse"; +import { Edge, Service, Utils, Websocket } from "src/app/shared/shared"; export enum AlertingType { offline = 0, @@ -21,7 +21,7 @@ type DetailedAlertingSetting = AlertingSetting & { isOfflineActive: boolean, isF @Component({ selector: AlertingComponent.SELECTOR, - templateUrl: './alerting.component.html', + templateUrl: "./alerting.component.html", }) export class AlertingComponent implements OnInit { @@ -55,7 +55,7 @@ export class AlertingComponent implements OnInit { } public ngOnInit(): void { - this.service.setCurrentComponent({ languageKey: 'Edge.Config.Index.alerting' }, this.route).then(edge => { + this.service.getCurrentEdge().then(edge => { this.edge = edge; const request = new GetUserAlertingConfigsRequest({ edgeId: this.edge.id }); @@ -94,16 +94,16 @@ export class AlertingComponent implements OnInit { } if (delay >= 1440) { delay = delay / 1440; - return delay + ' ' + (delay == 1 + return delay + " " + (delay == 1 ? this.translate.instant("General.TIME.DAY") : this.translate.instant("General.TIME.DAYS")); } else if (delay >= 60) { delay = delay / 60; - return delay + ' ' + (delay == 1 + return delay + " " + (delay == 1 ? this.translate.instant("General.TIME.HOUR") : this.translate.instant("General.TIME.HOURS")); } else { - return delay + ' ' + (delay == 1 + return delay + " " + (delay == 1 ? this.translate.instant("General.TIME.MINUTE") : this.translate.instant("General.TIME.MINUTES")); } @@ -142,9 +142,9 @@ export class AlertingComponent implements OnInit { for (const user of this.otherUserInformation) { const control = this.otherUserForm.controls[user.userLogin]; if (control.dirty) { - const offlineEdgeDelay = control.value['offlineEdgeDelay']; - const faultEdgeDelay = control.value['faultEdgeDelay']; - const warningEdgeDelay = control.value['warningEdgeDelay']; + const offlineEdgeDelay = control.value["offlineEdgeDelay"]; + const faultEdgeDelay = control.value["faultEdgeDelay"]; + const warningEdgeDelay = control.value["warningEdgeDelay"]; //let isActivated = control.value['isActivated']; changedUserSettings.push({ userLogin: user.userLogin, @@ -228,8 +228,6 @@ export class AlertingComponent implements OnInit { return setting.faultEdgeDelay; case AlertingType.warning: return setting.warningEdgeDelay; - default: - return 0; } } @@ -252,7 +250,7 @@ export class AlertingComponent implements OnInit { private sortedAlphabetically(userSettings: AlertingSettingResponse[]): AlertingSettingResponse[] { return userSettings.sort((userA, userB) => { - return userA.userLogin.localeCompare(userB.userLogin, undefined, { sensitivity: 'accent' }); + return userA.userLogin.localeCompare(userB.userLogin, undefined, { sensitivity: "accent" }); }); } @@ -273,14 +271,14 @@ export class AlertingComponent implements OnInit { private sendRequestAndUpdate(request: GetUserAlertingConfigsRequest | SetUserAlertingConfigsRequest, formGroup: FormGroup[]) { this.sendRequest(request) .then(() => { - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); + this.service.toast(this.translate.instant("General.changeAccepted"), "success"); for (const group of formGroup.values()) { group.markAsPristine(); } }) .catch((response) => { const error = response.error; - this.errorToast(this.translate.instant('General.changeFailed'), error.message); + this.errorToast(this.translate.instant("General.changeFailed"), error.message); }); } @@ -297,7 +295,7 @@ export class AlertingComponent implements OnInit { }).catch(reason => { const error = reason.error; console.error(error); - this.errorToast(this.translate.instant('Edge.Config.ALERTING.TOAST.ERROR'), error.message); + this.errorToast(this.translate.instant("Edge.Config.ALERTING.TOAST.ERROR"), error.message); reject(reason); }).finally(() => { this.service.stopSpinner(this.spinnerId); @@ -306,6 +304,6 @@ export class AlertingComponent implements OnInit { } private errorToast(errorType: string, errorMsg: string) { - this.service.toast('[ ' + errorType + ' ]
      ' + errorMsg, 'danger'); + this.service.toast("[ " + errorType + " ]
      " + errorMsg, "danger"); } } diff --git a/ui/src/app/edge/settings/app/app.module.ts b/ui/src/app/edge/settings/app/app.module.ts index 932b021cfa7..80554dac42b 100644 --- a/ui/src/app/edge/settings/app/app.module.ts +++ b/ui/src/app/edge/settings/app/app.module.ts @@ -1,32 +1,32 @@ // @ts-strict-ignore -import { NgModule } from '@angular/core'; -import { FormControl, ValidationErrors } from '@angular/forms'; -import { FORMLY_CONFIG, FormlyModule } from '@ngx-formly/core'; -import { TranslateService } from '@ngx-translate/core'; -import { SharedModule } from 'src/app/shared/shared.module'; -import { FormlyTextComponent } from './formly/formly-text'; -import { FormlyInputWithUnitComponent } from './formly/input-with-unit'; -import { FormlyOptionGroupPickerComponent } from './formly/option-group-picker/formly-option-group-picker.component'; -import { FormlyReorderArrayComponent } from './formly/reorder-select/formly-reorder-array.component'; -import { FormlySafeInputModalComponent } from './formly/safe-input/formly-safe-input-modal.component'; -import { FormlySafeInputWrapperComponent } from './formly/safe-input/formly-safe-input.extended'; -import { IndexComponent } from './index.component'; -import { InstallAppComponent } from './install.component'; -import { KeyModalComponent } from './keypopup/modal.component'; -import { SingleAppComponent } from './single.component'; -import { UpdateAppComponent } from './update.component'; +import { NgModule } from "@angular/core"; +import { FormControl, ValidationErrors } from "@angular/forms"; +import { FORMLY_CONFIG, FormlyModule } from "@ngx-formly/core"; +import { TranslateService } from "@ngx-translate/core"; +import { SharedModule } from "src/app/shared/shared.module"; +import { FormlyTextComponent } from "./formly/formly-text"; +import { FormlyInputWithUnitComponent } from "./formly/input-with-unit"; +import { FormlyOptionGroupPickerComponent } from "./formly/option-group-picker/formly-option-group-picker.component"; +import { FormlyReorderArrayComponent } from "./formly/reorder-select/formly-reorder-array.component"; +import { FormlySafeInputModalComponent } from "./formly/safe-input/formly-safe-input-modal.component"; +import { FormlySafeInputWrapperComponent } from "./formly/safe-input/formly-safe-input.extended"; +import { IndexComponent } from "./index.component"; +import { InstallAppComponent } from "./install.component"; +import { KeyModalComponent } from "./keypopup/modal.component"; +import { SingleAppComponent } from "./single.component"; +import { UpdateAppComponent } from "./update.component"; export function KeyValidator(control: FormControl): ValidationErrors { - return /^(.{4}-){3}.{4}$/.test(control.value) ? null : { 'key': true }; + return /^(.{4}-){3}.{4}$/.test(control.value) ? null : { "key": true }; } export function registerTranslateExtension(translate: TranslateService) { return { validationMessages: [ { - name: 'key', + name: "key", message() { - return translate.stream('Edge.Config.App.Key.invalidPattern'); + return translate.stream("Edge.Config.App.Key.invalidPattern"); }, }, ], @@ -47,10 +47,10 @@ export function registerTranslateExtension(translate: TranslateService) { { name: "reorder-array", component: FormlyReorderArrayComponent }, ], validators: [ - { name: 'key', validation: KeyValidator }, + { name: "key", validation: KeyValidator }, ], validationMessages: [ - { name: 'key', message: "The key doesnt match the pattern!" }, + { name: "key", message: "The key doesnt match the pattern!" }, ], }), ], diff --git a/ui/src/app/edge/settings/app/formly/formly-text.ts b/ui/src/app/edge/settings/app/formly/formly-text.ts index ff08690c381..d8fe8a1c681 100644 --- a/ui/src/app/edge/settings/app/formly/formly-text.ts +++ b/ui/src/app/edge/settings/app/formly/formly-text.ts @@ -2,8 +2,8 @@ import { Component, ViewEncapsulation } from "@angular/core"; import { FieldType, FieldTypeConfig } from "@ngx-formly/core"; @Component({ - selector: 'formly-text', - styles: ['.warning {color: red}'], + selector: "formly-text", + styles: [".warning {color: red}"], template: ` diff --git a/ui/src/app/edge/settings/app/formly/input-with-unit.ts b/ui/src/app/edge/settings/app/formly/input-with-unit.ts index f36cdd12bdd..12852b9c35a 100644 --- a/ui/src/app/edge/settings/app/formly/input-with-unit.ts +++ b/ui/src/app/edge/settings/app/formly/input-with-unit.ts @@ -1,8 +1,8 @@ -import { Component } from '@angular/core'; -import { FieldWrapper } from '@ngx-formly/core'; +import { Component } from "@angular/core"; +import { FieldWrapper } from "@ngx-formly/core"; @Component({ - selector: 'formly-input-with-unit', + selector: "formly-input-with-unit", template: ` diff --git a/ui/src/app/edge/settings/app/formly/option-group-picker/formly-option-group-picker.component.ts b/ui/src/app/edge/settings/app/formly/option-group-picker/formly-option-group-picker.component.ts index ce5b702e4b1..0e0ec8e1f60 100644 --- a/ui/src/app/edge/settings/app/formly/option-group-picker/formly-option-group-picker.component.ts +++ b/ui/src/app/edge/settings/app/formly/option-group-picker/formly-option-group-picker.component.ts @@ -4,8 +4,8 @@ import { FieldType, FieldTypeConfig, FormlyFieldConfig } from "@ngx-formly/core" import { Option, OptionGroup, OptionGroupConfig, getTitleFromOptionConfig } from "./optionGroupPickerConfiguration"; @Component({ - selector: 'formly-option-group-picker', - templateUrl: './formly-option-group-picker.component.html', + selector: "formly-option-group-picker", + templateUrl: "./formly-option-group-picker.component.html", }) export class FormlyOptionGroupPickerComponent extends FieldType implements OnInit { diff --git a/ui/src/app/edge/settings/app/formly/reorder-select/formly-reorder-array.component.ts b/ui/src/app/edge/settings/app/formly/reorder-select/formly-reorder-array.component.ts index f9923d3a31b..808171892bb 100644 --- a/ui/src/app/edge/settings/app/formly/reorder-select/formly-reorder-array.component.ts +++ b/ui/src/app/edge/settings/app/formly/reorder-select/formly-reorder-array.component.ts @@ -4,8 +4,8 @@ import { ItemReorderEventDetail } from "@ionic/angular"; import { FieldType, FieldTypeConfig, FormlyFieldConfig, FormlyFieldProps } from "@ngx-formly/core"; @Component({ - selector: 'reorder-array', - templateUrl: './formly-reorder-array.component.html', + selector: "reorder-array", + templateUrl: "./formly-reorder-array.component.html", }) export class FormlyReorderArrayComponent extends FieldType { if (!event.data) { @@ -102,7 +102,7 @@ export class FormlySafeInputWrapperComponent extends FieldWrapper implements OnI } private getValueOfOptionGroup(): string { - const field = GetAppAssistant.findField(this.getFields(), this.pathToDisplayValue.split('.')); + const field = GetAppAssistant.findField(this.getFields(), this.pathToDisplayValue.split(".")); if (!field) { return null; } @@ -112,7 +112,7 @@ export class FormlySafeInputWrapperComponent extends FieldWrapper implements OnI if (Array.isArray(value)) { return (value as []).map(e => options.find(option => option.value === e)) .map(option => getTitleFromOptionConfig(option, this.field)) - .join(', '); + .join(", "); } else { const option = options.find(option => option.value === value); if (!option) { diff --git a/ui/src/app/edge/settings/app/index.component.ts b/ui/src/app/edge/settings/app/index.component.ts index 7540ea72633..e0b1966f563 100644 --- a/ui/src/app/edge/settings/app/index.component.ts +++ b/ui/src/app/edge/settings/app/index.component.ts @@ -1,52 +1,52 @@ // @ts-strict-ignore -import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; -import { ActivatedRoute, NavigationEnd, NavigationExtras, Router } from '@angular/router'; -import { IonPopover, ModalController } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; -import { Subject } from 'rxjs'; -import { filter, switchMap, takeUntil } from 'rxjs/operators'; -import { ComponentJsonApiRequest } from 'src/app/shared/jsonrpc/request/componentJsonApiRequest'; -import { Role } from 'src/app/shared/type/role'; -import { Environment, environment } from 'src/environments'; -import { Edge, Service, Websocket } from '../../../shared/shared'; -import { ExecuteSystemUpdate } from '../system/executeSystemUpdate'; -import { InstallAppComponent } from './install.component'; -import { Flags } from './jsonrpc/flag/flags'; -import { GetApps } from './jsonrpc/getApps'; -import { App } from './keypopup/app'; -import { AppCenter } from './keypopup/appCenter'; -import { AppCenterGetPossibleApps } from './keypopup/appCenterGetPossibleApps'; -import { AppCenterGetRegisteredKeys } from './keypopup/appCenterGetRegisteredKeys'; -import { Key } from './keypopup/key'; -import { KeyModalComponent, KeyValidationBehaviour } from './keypopup/modal.component'; -import { canEnterKey } from './permissions'; +import { Component, OnDestroy, OnInit, ViewChild } from "@angular/core"; +import { ActivatedRoute, NavigationEnd, NavigationExtras, Router } from "@angular/router"; +import { IonPopover, ModalController } from "@ionic/angular"; +import { TranslateService } from "@ngx-translate/core"; +import { Subject } from "rxjs"; +import { filter, switchMap, takeUntil } from "rxjs/operators"; +import { ComponentJsonApiRequest } from "src/app/shared/jsonrpc/request/componentJsonApiRequest"; +import { Role } from "src/app/shared/type/role"; +import { Environment, environment } from "src/environments"; +import { Edge, Service, Websocket } from "../../../shared/shared"; +import { ExecuteSystemUpdate } from "../system/executeSystemUpdate"; +import { InstallAppComponent } from "./install.component"; +import { Flags } from "./jsonrpc/flag/flags"; +import { GetApps } from "./jsonrpc/getApps"; +import { App } from "./keypopup/app"; +import { AppCenter } from "./keypopup/appCenter"; +import { AppCenterGetPossibleApps } from "./keypopup/appCenterGetPossibleApps"; +import { AppCenterGetRegisteredKeys } from "./keypopup/appCenterGetRegisteredKeys"; +import { Key } from "./keypopup/key"; +import { KeyModalComponent, KeyValidationBehaviour } from "./keypopup/modal.component"; +import { canEnterKey } from "./permissions"; @Component({ selector: IndexComponent.SELECTOR, - templateUrl: './index.component.html', + templateUrl: "./index.component.html", }) export class IndexComponent implements OnInit, OnDestroy { - private static readonly SELECTOR = 'app-index'; + private static readonly SELECTOR = "app-index"; /** * e. g. if more than 4 apps are in a list the apps are displayed in their categories */ private static readonly MAX_APPS_IN_LIST: number = 4; - @ViewChild('hasKeyPopover') private hasKeyPopover: IonPopover; + @ViewChild("hasKeyPopover") private hasKeyPopover: IonPopover; public readonly spinnerId: string = IndexComponent.SELECTOR; public apps: GetApps.App[] = []; public installedApps: AppList = { - name: 'Edge.Config.App.installed', appCategories: [] + name: "Edge.Config.App.installed", appCategories: [] , shouldBeShown: () => this.key === null, // only show installed apps when the user is not currently selecting an app from a key }; public availableApps: AppList = { - name: 'Edge.Config.App.available', appCategories: [] + name: "Edge.Config.App.available", appCategories: [] , shouldBeShown: () => true, // always show available apps }; public incompatibleApps: AppList = { - name: 'Edge.Config.App.incompatible', appCategories: [] + name: "Edge.Config.App.incompatible", appCategories: [] , shouldBeShown: () => this.edge.roleIsAtLeast(Role.ADMIN), // only show incompatible apps for admins }; @@ -131,11 +131,11 @@ export class IndexComponent implements OnInit, OnDestroy { sortedApps.forEach(a => { if (a.instanceIds.length > 0) { this.pushIntoCategory(a, this.installedApps); - if (a.cardinality === 'MULTIPLE' && a.status.name !== 'INCOMPATIBLE') { + if (a.cardinality === "MULTIPLE" && a.status.name !== "INCOMPATIBLE") { this.pushIntoCategory(a, this.availableApps); } } else { - if (a.status.name === 'INCOMPATIBLE') { + if (a.status.name === "INCOMPATIBLE") { this.pushIntoCategory(a, this.incompatibleApps); } else { this.pushIntoCategory(a, this.availableApps); @@ -163,7 +163,7 @@ export class IndexComponent implements OnInit, OnDestroy { behaviour: KeyValidationBehaviour.SELECT, knownApps: this.apps, }, - cssClass: 'auto-height', + cssClass: "auto-height", }); modal.onDidDismiss().then(data => { if (!data.data) { @@ -211,10 +211,10 @@ export class IndexComponent implements OnInit, OnDestroy { protected onAppClicked(app: GetApps.App): void { // navigate if (this.key != null || this.useMasterKey) { - this.router.navigate(['device/' + (this.edge.id) + '/settings/app/single/' + app.appId] + this.router.navigate(["device/" + (this.edge.id) + "/settings/app/single/" + app.appId] , { queryParams: { name: app.name }, state: { app: app, appKey: this.key.keyId, useMasterKey: this.useMasterKey } }); } else { - this.router.navigate(['device/' + (this.edge.id) + '/settings/app/single/' + app.appId], { queryParams: { name: app.name }, state: app }); + this.router.navigate(["device/" + (this.edge.id) + "/settings/app/single/" + app.appId], { queryParams: { name: app.name }, state: app }); } // reset keys this.key = null; @@ -231,7 +231,7 @@ export class IndexComponent implements OnInit, OnDestroy { edge: this.edge, behaviour: KeyValidationBehaviour.REGISTER, }, - cssClass: 'auto-height', + cssClass: "auto-height", }); return await modal.present(); @@ -251,8 +251,8 @@ export class IndexComponent implements OnInit, OnDestroy { this.hasSeenPopover = true; this.hasKeyPopover.event = { - type: 'willPresent', - target: document.querySelector('#redeemKeyCard'), + type: "willPresent", + target: document.querySelector("#redeemKeyCard"), }; this.showPopover = true; } @@ -282,7 +282,7 @@ export class IndexComponent implements OnInit, OnDestroy { }); this.service.setCurrentComponent({ - languageKey: 'Edge.Config.App.NAME_WITH_EDGE_NAME', + languageKey: "Edge.Config.App.NAME_WITH_EDGE_NAME", interpolateParams: { edgeShortName: environment.edgeShortName }, }, this.route).then(edge => { this.edge = edge; @@ -295,7 +295,7 @@ export class IndexComponent implements OnInit, OnDestroy { }); edge.sendRequest(this.websocket, new ComponentJsonApiRequest({ - componentId: '_appManager', + componentId: "_appManager", payload: new GetApps.Request(), })).then(response => { @@ -324,7 +324,7 @@ export class IndexComponent implements OnInit, OnDestroy { this.numberOfUnusedRegisteredKeys = result.keys.length; this.updateHasUnusedKeysPopover(); }).catch(this.service.handleError); - }).catch(InstallAppComponent.errorToast(this.service, error => 'Error while receiving available apps: ' + error)); + }).catch(InstallAppComponent.errorToast(this.service, error => "Error while receiving available apps: " + error)); const systemUpdate = new ExecuteSystemUpdate(edge, this.websocket); systemUpdate.systemUpdateStateChange = (updateState) => { diff --git a/ui/src/app/edge/settings/app/install.component.ts b/ui/src/app/edge/settings/app/install.component.ts index 49d5591524b..d41cb72f035 100644 --- a/ui/src/app/edge/settings/app/install.component.ts +++ b/ui/src/app/edge/settings/app/install.component.ts @@ -1,30 +1,30 @@ // @ts-strict-ignore -import { Component, OnDestroy, OnInit } from '@angular/core'; -import { FormGroup } from '@angular/forms'; -import { ActivatedRoute, Router } from '@angular/router'; -import { ModalController } from '@ionic/angular'; -import { FormlyFieldConfig } from '@ngx-formly/core'; -import { TranslateService } from '@ngx-translate/core'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; -import { JsonrpcRequest } from 'src/app/shared/jsonrpc/base'; -import { ComponentJsonApiRequest } from 'src/app/shared/jsonrpc/request/componentJsonApiRequest'; -import { Edge, Service, Utils, Websocket } from '../../../shared/shared'; -import { AddAppInstance } from './jsonrpc/addAppInstance'; -import { GetAppAssistant } from './jsonrpc/getAppAssistant'; -import { AppCenter } from './keypopup/appCenter'; -import { AppCenterInstallAppWithSuppliedKeyRequest } from './keypopup/appCenterInstallAppWithSuppliedKey'; -import { AppCenterIsAppFree } from './keypopup/appCenterIsAppFree'; -import { KeyModalComponent, KeyValidationBehaviour } from './keypopup/modal.component'; -import { hasPredefinedKey } from './permissions'; +import { Component, OnDestroy, OnInit } from "@angular/core"; +import { FormGroup } from "@angular/forms"; +import { ActivatedRoute, Router } from "@angular/router"; +import { ModalController } from "@ionic/angular"; +import { FormlyFieldConfig } from "@ngx-formly/core"; +import { TranslateService } from "@ngx-translate/core"; +import { Subject } from "rxjs"; +import { takeUntil } from "rxjs/operators"; +import { JsonrpcRequest } from "src/app/shared/jsonrpc/base"; +import { ComponentJsonApiRequest } from "src/app/shared/jsonrpc/request/componentJsonApiRequest"; +import { Edge, Service, Utils, Websocket } from "../../../shared/shared"; +import { AddAppInstance } from "./jsonrpc/addAppInstance"; +import { GetAppAssistant } from "./jsonrpc/getAppAssistant"; +import { AppCenter } from "./keypopup/appCenter"; +import { AppCenterInstallAppWithSuppliedKeyRequest } from "./keypopup/appCenterInstallAppWithSuppliedKey"; +import { AppCenterIsAppFree } from "./keypopup/appCenterIsAppFree"; +import { KeyModalComponent, KeyValidationBehaviour } from "./keypopup/modal.component"; +import { hasPredefinedKey } from "./permissions"; @Component({ selector: InstallAppComponent.SELECTOR, - templateUrl: './install.component.html', + templateUrl: "./install.component.html", }) export class InstallAppComponent implements OnInit, OnDestroy { - private static readonly SELECTOR = 'app-install'; + private static readonly SELECTOR = "app-install"; public readonly spinnerId: string = InstallAppComponent.SELECTOR; protected form: FormGroup | null = null; @@ -68,7 +68,7 @@ export class InstallAppComponent implements OnInit, OnDestroy { } } console.error(reason); - service.toast(messageBuilder(reason), 'danger'); + service.toast(messageBuilder(reason), "danger"); }; } @@ -76,15 +76,15 @@ export class InstallAppComponent implements OnInit, OnDestroy { this.service.startSpinner(this.spinnerId); const state = history?.state; if (state) { - if ('appKey' in state) { - this.key = state['appKey']; + if ("appKey" in state) { + this.key = state["appKey"]; } - if ('useMasterKey' in state) { - this.useMasterKey = state['useMasterKey']; + if ("useMasterKey" in state) { + this.useMasterKey = state["useMasterKey"]; } } - const appId = this.route.snapshot.params['appId']; - const appName = this.route.snapshot.queryParams['name']; + const appId = this.route.snapshot.params["appId"]; + const appName = this.route.snapshot.queryParams["name"]; this.appId = appId; this.service.setCurrentComponent(appName, this.route).then(edge => { this.edge = edge; @@ -109,7 +109,7 @@ export class InstallAppComponent implements OnInit, OnDestroy { }); edge.sendRequest(this.websocket, new ComponentJsonApiRequest({ - componentId: '_appManager', + componentId: "_appManager", payload: new GetAppAssistant.Request({ appId: appId }), })).then(response => { const appAssistant = GetAppAssistant.postprocess((response as GetAppAssistant.Response).result); @@ -139,16 +139,16 @@ export class InstallAppComponent implements OnInit, OnDestroy { this.obtainKey().then(key => { this.service.startSpinnerTransparentBackground(this.appId); // remove alias field from properties - const alias = this.form.value['ALIAS']; + const alias = this.form.value["ALIAS"]; const clonedFields = {}; for (const item in this.form.value) { - if (item !== 'ALIAS') { + if (item !== "ALIAS") { clonedFields[item] = this.form.value[item]; } } let request: JsonrpcRequest = new ComponentJsonApiRequest({ - componentId: '_appManager', + componentId: "_appManager", payload: new AddAppInstance.Request({ appId: this.appId, alias: alias, @@ -174,16 +174,16 @@ export class InstallAppComponent implements OnInit, OnDestroy { this.model = result.instance.properties; } if (result.warnings && result.warnings.length > 0) { - this.service.toast(result.warnings.join(';'), 'warning'); + this.service.toast(result.warnings.join(";"), "warning"); } else { - this.service.toast(this.translate.instant('Edge.Config.App.successInstall'), 'success'); + this.service.toast(this.translate.instant("Edge.Config.App.successInstall"), "success"); } this.form.markAsPristine(); const navigationExtras = { state: { appInstanceChange: true } }; - this.router.navigate(['device/' + (this.edge.id) + '/settings/app/'], navigationExtras); + this.router.navigate(["device/" + (this.edge.id) + "/settings/app/"], navigationExtras); }) - .catch(InstallAppComponent.errorToast(this.service, error => this.translate.instant('Edge.Config.App.failInstall', { error: error }))) + .catch(InstallAppComponent.errorToast(this.service, error => this.translate.instant("Edge.Config.App.failInstall", { error: error }))) .finally(() => { this.isInstalling = false; this.service.stopSpinner(this.appId); @@ -228,7 +228,7 @@ export class InstallAppComponent implements OnInit, OnDestroy { behaviour: KeyValidationBehaviour.SELECT, appName: this.appName, }, - cssClass: 'auto-height', + cssClass: "auto-height", }); const selectKeyPromise = new Promise((resolve, reject) => { diff --git a/ui/src/app/edge/settings/app/jsonrpc/flag/flags.ts b/ui/src/app/edge/settings/app/jsonrpc/flag/flags.ts index e3041790b9e..99d62ac7742 100644 --- a/ui/src/app/edge/settings/app/jsonrpc/flag/flags.ts +++ b/ui/src/app/edge/settings/app/jsonrpc/flag/flags.ts @@ -3,7 +3,7 @@ import { FlagType } from "./flagType"; export namespace Flags { - export const SHOW_AFTER_KEY_REDEEM: FlagType = { name: 'showAfterKeyRedeem' }; + export const SHOW_AFTER_KEY_REDEEM: FlagType = { name: "showAfterKeyRedeem" }; /** * Gets a flag by its type from an array of flags. diff --git a/ui/src/app/edge/settings/app/jsonrpc/getAppAssistant.spec.ts b/ui/src/app/edge/settings/app/jsonrpc/getAppAssistant.spec.ts index 28dbc11b1b0..588aa68cc5e 100644 --- a/ui/src/app/edge/settings/app/jsonrpc/getAppAssistant.spec.ts +++ b/ui/src/app/edge/settings/app/jsonrpc/getAppAssistant.spec.ts @@ -2,57 +2,57 @@ import { FormlyFieldConfig } from "@ngx-formly/core"; import { GetAppAssistant } from "./getAppAssistant"; -describe('GetAppAssistant', () => { +describe("GetAppAssistant", () => { let fields: FormlyFieldConfig[]; beforeEach(() => { fields = [ { - key: 'a', - type: 'input', + key: "a", + type: "input", props: { - type: 'text', + type: "text", }, fieldGroup: [ { - key: 'b', - type: 'input', + key: "b", + type: "input", props: { - type: 'number', + type: "number", }, }, ], }, { - key: 'c', - type: 'input', + key: "c", + type: "input", props: { - type: 'number', + type: "number", }, }, ]; }); - it('#findField should find a field by a path', () => { - expect(GetAppAssistant.findField(fields, ['a'])).toBeDefined(); - expect(GetAppAssistant.findField(fields, ['a', 'b'])).toBeDefined(); - expect(GetAppAssistant.findField(fields, ['c'])).toBeDefined(); + it("#findField should find a field by a path", () => { + expect(GetAppAssistant.findField(fields, ["a"])).toBeDefined(); + expect(GetAppAssistant.findField(fields, ["a", "b"])).toBeDefined(); + expect(GetAppAssistant.findField(fields, ["c"])).toBeDefined(); }); - it('#setInitialModel should set the initial model on every field', () => { - expect(GetAppAssistant.findField(fields, ['a'])['initialModel']).toBeUndefined(); - expect(GetAppAssistant.findField(fields, ['a', 'b'])['initialModel']).toBeUndefined(); - expect(GetAppAssistant.findField(fields, ['c'])['initialModel']).toBeUndefined(); + it("#setInitialModel should set the initial model on every field", () => { + expect(GetAppAssistant.findField(fields, ["a"])["initialModel"]).toBeUndefined(); + expect(GetAppAssistant.findField(fields, ["a", "b"])["initialModel"]).toBeUndefined(); + expect(GetAppAssistant.findField(fields, ["c"])["initialModel"]).toBeUndefined(); GetAppAssistant.setInitialModel(fields, {}); - expect(GetAppAssistant.findField(fields, ['a'])['initialModel']).toBeDefined(); - expect(GetAppAssistant.findField(fields, ['a', 'b'])['initialModel']).toBeDefined(); - expect(GetAppAssistant.findField(fields, ['c'])['initialModel']).toBeDefined(); + expect(GetAppAssistant.findField(fields, ["a"])["initialModel"]).toBeDefined(); + expect(GetAppAssistant.findField(fields, ["a", "b"])["initialModel"]).toBeDefined(); + expect(GetAppAssistant.findField(fields, ["c"])["initialModel"]).toBeDefined(); }); - it('#convertStringExpressions should parse number inputs to numbers', () => { - const expression = 'model.a < 1 || model.a.b < 1 && [1,2].every(i => i < initialModel.c)'; + it("#convertStringExpressions should parse number inputs to numbers", () => { + const expression = "model.a < 1 || model.a.b < 1 && [1,2].every(i => i < initialModel.c)"; const converted = GetAppAssistant.convertStringExpressions(fields, fields[0], expression); - expect(converted).toBe('model.a < 1 || +model.a.b < 1 && [1,2].every(i => i < +initialModel.c)'); + expect(converted).toBe("model.a < 1 || +model.a.b < 1 && [1,2].every(i => i < +initialModel.c)"); }); }); diff --git a/ui/src/app/edge/settings/app/jsonrpc/getAppAssistant.ts b/ui/src/app/edge/settings/app/jsonrpc/getAppAssistant.ts index a9d1bc58355..571b7c34205 100644 --- a/ui/src/app/edge/settings/app/jsonrpc/getAppAssistant.ts +++ b/ui/src/app/edge/settings/app/jsonrpc/getAppAssistant.ts @@ -75,7 +75,7 @@ export namespace GetAppAssistant { } if (!hasAliasField) { // insert alias field into appAssistant fields - const aliasField = { key: 'ALIAS', type: 'input', templateOptions: { label: 'Alias' }, defaultValue: appAssistant.alias }; + const aliasField = { key: "ALIAS", type: "input", templateOptions: { label: "Alias" }, defaultValue: appAssistant.alias }; appAssistant.fields.splice(0, 0, aliasField); } return appAssistant; @@ -87,7 +87,7 @@ export namespace GetAppAssistant { if (!field) { return; } - field['initialModel'] = structuredClone(model); + field["initialModel"] = structuredClone(model); [field.fieldGroup, field.templateOptions?.fields ?? field.props?.fields].forEach(fieldGroup => { if (!fieldGroup) { return; @@ -103,7 +103,7 @@ export namespace GetAppAssistant { } export function convertStringExpressions(rootFields: FormlyFieldConfig[], field: FormlyFieldConfig, expression: string): string { - return ['model.', 'initialModel.', 'control.value.'].reduce((p, c) => convertStringExpression(rootFields, field, p, c), expression); + return ["model.", "initialModel.", "control.value."].reduce((p, c) => convertStringExpression(rootFields, field, p, c), expression); } /** @@ -127,7 +127,7 @@ export namespace GetAppAssistant { return finalExpression; } - const smallestIndex = [' ', ')'].reduce((previous, current) => { + const smallestIndex = [" ", ")"].reduce((previous, current) => { const index = part.indexOf(current); if (index === -1) { return previous; @@ -148,14 +148,14 @@ export namespace GetAppAssistant { propertyName = part; } - const propertyPathNames = propertyName.split('.') - .map(i => ['(', ')'].reduce((p, c) => p.replace(c, ''), i)); + const propertyPathNames = propertyName.split(".") + .map(i => ["(", ")"].reduce((p, c) => p.replace(c, ""), i)); const f = GetAppAssistant.findField(rootFields, propertyPathNames); - const isNumericInput = !!f && (f.templateOptions?.type === 'number' || f.props?.type === 'number'); + const isNumericInput = !!f && (f.templateOptions?.type === "number" || f.props?.type === "number"); if (isNumericInput) { // parses the value to a number - finalExpression = finalExpression.concat('+'); + finalExpression = finalExpression.concat("+"); } finalExpression = finalExpression.concat(prefix, propertyName); if (smallestIndex != -1) { @@ -207,14 +207,14 @@ export namespace GetAppAssistant { */ function eachFieldRecursive(rootFields: FormlyFieldConfig[], field: FormlyFieldConfig) { // 'defaultValue' false for checkboxes - if (field.type === 'checkbox' && !('defaultValue' in field)) { - field['defaultValue'] = false; + if (field.type === "checkbox" && !("defaultValue" in field)) { + field["defaultValue"] = false; } // this is needed to still show the input as the default style defined by us - if (field.wrappers?.includes('formly-wrapper-default-of-cases') - || field.wrappers?.includes('formly-safe-input-wrapper') - || field.wrappers?.includes('input-with-unit')) { - field.wrappers?.push('form-field'); + if (field.wrappers?.includes("formly-wrapper-default-of-cases") + || field.wrappers?.includes("formly-safe-input-wrapper") + || field.wrappers?.includes("input-with-unit")) { + field.wrappers?.push("form-field"); } if (field.validators) { @@ -222,15 +222,15 @@ function eachFieldRecursive(rootFields: FormlyFieldConfig[], field: FormlyFieldC let expressionString: string = value["expressionString"]; if (expressionString) { expressionString = GetAppAssistant.convertStringExpressions(rootFields, field, expressionString); - const func = Function('model', 'formState', 'field', 'control', 'initialModel', `return ${expressionString};`); + const func = Function("model", "formState", "field", "control", "initialModel", `return ${expressionString};`); field.validators[key]["expression"] = (control: AbstractControl, f: FormlyFieldConfigWithInitialModel) => { return func(f.model, f.options.formState, f, control, f.initialModel); }; } - let messageExpressionString: string = value['messageString']; + let messageExpressionString: string = value["messageString"]; if (messageExpressionString) { messageExpressionString = GetAppAssistant.convertStringExpressions(rootFields, field, messageExpressionString); - const func = Function('model', 'formState', 'field', 'control', 'initialModel', `return ${messageExpressionString};`); + const func = Function("model", "formState", "field", "control", "initialModel", `return ${messageExpressionString};`); field.validators[key]["message"] = (error: any, f: FormlyFieldConfigWithInitialModel) => { return func(f.model, f.options.formState, f, f.formControl, f.initialModel); }; @@ -252,7 +252,7 @@ function eachFieldRecursive(rootFields: FormlyFieldConfig[], field: FormlyFieldC } } }); - if (field.key == 'ALIAS') { + if (field.key == "ALIAS") { return true; } return childHasAlias; @@ -290,14 +290,14 @@ function eachFieldRecursive(rootFields: FormlyFieldConfig[], field: FormlyFieldC * @param field the current field */ function convertFormlyOptionGroupPicker(rootFields: FormlyFieldConfig[], field: FormlyFieldConfig) { - if (field.type !== 'formly-option-group-picker') { + if (field.type !== "formly-option-group-picker") { return; } (field.templateOptions ?? field.props).options?.forEach((optionGroup) => { if (!optionGroup) { return; } - (optionGroup['options'] as any[]).forEach((option) => { + (optionGroup["options"] as any[]).forEach((option) => { for (const [key, value] of Object.entries(option?.expressions ?? {})) { if (!key.endsWith("String")) { continue; @@ -306,8 +306,8 @@ function convertFormlyOptionGroupPicker(rootFields: FormlyFieldConfig[], field: const expressionString: string = value as string; if (expressionString) { const convertedExpression = GetAppAssistant.convertStringExpressions(rootFields, field, expressionString); - const func = Function('model', 'formState', 'field', 'control', 'initialModel', `return ${convertedExpression};`); - option['expressions'][key.substring(0, key.indexOf("String"))] = (f: FormlyFieldConfigWithInitialModel) => { + const func = Function("model", "formState", "field", "control", "initialModel", `return ${convertedExpression};`); + option["expressions"][key.substring(0, key.indexOf("String"))] = (f: FormlyFieldConfigWithInitialModel) => { return func(f.model, f.options.formState, f, f.formControl, f.initialModel); }; } @@ -317,7 +317,7 @@ function convertFormlyOptionGroupPicker(rootFields: FormlyFieldConfig[], field: } function convertFormlyReorderArray(rootFields: FormlyFieldConfig[], field: FormlyFieldConfig) { - if (field.type !== 'reorder-array') { + if (field.type !== "reorder-array") { return; } (field.templateOptions ?? field.props).selectOptions?.forEach((selectOption) => { @@ -333,8 +333,8 @@ function convertFormlyReorderArray(rootFields: FormlyFieldConfig[], field: Forml const expressionString: string = value as string; if (expressionString) { const convertedExpression = GetAppAssistant.convertStringExpressions(rootFields, field, expressionString); - const func = Function('model', 'formState', 'field', 'control', 'initialModel', `return ${convertedExpression};`); - selectOption['expressions'][key.substring(0, key.indexOf("String"))] = (f: FormlyFieldConfigWithInitialModel) => { + const func = Function("model", "formState", "field", "control", "initialModel", `return ${convertedExpression};`); + selectOption["expressions"][key.substring(0, key.indexOf("String"))] = (f: FormlyFieldConfigWithInitialModel) => { return func(f.model, f.options.formState, f, f.formControl, f.initialModel); }; } diff --git a/ui/src/app/edge/settings/app/jsonrpc/getApps.ts b/ui/src/app/edge/settings/app/jsonrpc/getApps.ts index 5c90982b190..a95aa6ea12d 100644 --- a/ui/src/app/edge/settings/app/jsonrpc/getApps.ts +++ b/ui/src/app/edge/settings/app/jsonrpc/getApps.ts @@ -66,7 +66,7 @@ export namespace GetApps { export interface App { categorys: Category[], - cardinality: 'SINGLE' | 'SINGLE_IN_CATEGORY' | 'MULTIPLE', + cardinality: "SINGLE" | "SINGLE_IN_CATEGORY" | "MULTIPLE", appId: string, name: string, shortName?: string, @@ -78,7 +78,7 @@ export namespace GetApps { } export interface Status { - name: 'INCOMPATIBLE' | 'COMPATIBLE' | 'INSTALLABLE', + name: "INCOMPATIBLE" | "COMPATIBLE" | "INSTALLABLE", errorCompatibleMessages: string[], errorInstallableMessages: string[] } 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 e8a3e2847b4..be5889a230d 100644 --- a/ui/src/app/edge/settings/app/keypopup/modal.component.ts +++ b/ui/src/app/edge/settings/app/keypopup/modal.component.ts @@ -1,28 +1,28 @@ // @ts-strict-ignore -import { Component, Input, OnInit } from '@angular/core'; -import { FormGroup } from '@angular/forms'; -import { Router } from '@angular/router'; -import { ModalController } from '@ionic/angular'; -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'; -import { Flags } from '../jsonrpc/flag/flags'; -import { GetApps } from '../jsonrpc/getApps'; -import { hasPredefinedKey } from '../permissions'; -import { AppCenter } from './appCenter'; -import { AppCenterAddRegisterKeyHistory } from './appCenterAddRegisterKeyHistory'; -import { AppCenterGetRegisteredKeys } from './appCenterGetRegisteredKeys'; -import { AppCenterIsKeyApplicable } from './appCenterIsKeyApplicable'; -import { Key } from './key'; +import { Component, Input, OnInit } from "@angular/core"; +import { FormGroup } from "@angular/forms"; +import { Router } from "@angular/router"; +import { ModalController } from "@ionic/angular"; +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"; +import { Flags } from "../jsonrpc/flag/flags"; +import { GetApps } from "../jsonrpc/getApps"; +import { hasPredefinedKey } from "../permissions"; +import { AppCenter } from "./appCenter"; +import { AppCenterAddRegisterKeyHistory } from "./appCenterAddRegisterKeyHistory"; +import { AppCenterGetRegisteredKeys } from "./appCenterGetRegisteredKeys"; +import { AppCenterIsKeyApplicable } from "./appCenterIsKeyApplicable"; +import { Key } from "./key"; @Component({ selector: KeyModalComponent.SELECTOR, - templateUrl: './modal.component.html', + templateUrl: "./modal.component.html", }) export class KeyModalComponent implements OnInit { - private static readonly SELECTOR = 'key-modal'; + private static readonly SELECTOR = "key-modal"; @Input({ required: true }) public edge!: Edge; @Input() public appId: string | null = null; @@ -63,7 +63,7 @@ export class KeyModalComponent implements OnInit { */ private static transformInput(value: string): string { // remove spaces - let trimmed = value.replace(/\s+/g, ''); + let trimmed = value.replace(/\s+/g, ""); // trimm max length of input if (trimmed.length > 19) { @@ -72,29 +72,29 @@ export class KeyModalComponent implements OnInit { // remove last dash const hasDashAsLastChar = trimmed.substring(trimmed.length - 1, trimmed.length) == "-"; - trimmed = trimmed.replace(/-/g, ''); + trimmed = trimmed.replace(/-/g, ""); const numbers = []; // push single parts into array numbers.push(trimmed.substring(0, 4)); - if (trimmed.substring(4, 8) !== '') { + if (trimmed.substring(4, 8) !== "") { numbers.push(trimmed.substring(4, 8)); } - if (trimmed.substring(8, 12) != '') { + if (trimmed.substring(8, 12) != "") { numbers.push(trimmed.substring(8, 12)); } - if (trimmed.substring(12, 16) != '') { + if (trimmed.substring(12, 16) != "") { numbers.push(trimmed.substring(12, 16)); } // join parts so it matches 'XXXX-XXXX-XXXX-XXXX' - let modifiedValue = numbers.join('-'); + let modifiedValue = numbers.join("-"); // readd last if (hasDashAsLastChar) { - modifiedValue += '-'; + modifiedValue += "-"; } // if there was no change to the original value return null @@ -113,8 +113,8 @@ export class KeyModalComponent implements OnInit { }; this.model = { useRegisteredKeys: false, - registeredKey: '', - key: '', + registeredKey: "", + key: "", }; if (this.behaviour === KeyValidationBehaviour.REGISTER) { @@ -134,7 +134,7 @@ export class KeyModalComponent implements OnInit { this.model.useRegisteredKeys = true; this.model.registeredKey = this.registeredKeys[0].keyId; } - const selectRegisteredKey = this.fields.find(f => f.key === 'registeredKey'); + const selectRegisteredKey = this.fields.find(f => f.key === "registeredKey"); this.registeredKeys.forEach(key => { const desc = this.getDescription(key); (selectRegisteredKey.props.options as any[]).push({ @@ -145,7 +145,7 @@ export class KeyModalComponent implements OnInit { }); }).catch(reason => { this.fields = this.getFields(); - this.service.toast(this.translate.instant('Edge.Config.App.Key.failedLoadingRegisterKey'), 'danger'); + this.service.toast(this.translate.instant("Edge.Config.App.Key.failedLoadingRegisterKey"), "danger"); }).finally(() => { this.service.stopSpinner(this.spinnerId); }); @@ -169,7 +169,7 @@ export class KeyModalComponent implements OnInit { this.service.startSpinner(this.spinnerId); this.modalCtrl.dismiss({ key: this.getSelectedKey(), useMasterKey: this.model.useMasterKey }); // navigate to App install view and pass valid key - this.router.navigate(['device/' + (this.edge.id) + '/settings/app/install/' + this.appId] + this.router.navigate(["device/" + (this.edge.id) + "/settings/app/install/" + this.appId] , { queryParams: { name: this.appName }, state: { appKey: this.getRawAppKey(), useMasterKey: this.model.useMasterKey } }); this.service.stopSpinner(this.spinnerId); break; @@ -178,9 +178,9 @@ export class KeyModalComponent implements OnInit { // only register key for this app this.registerKey().then(() => { this.modalCtrl.dismiss({ key: this.getSelectedKey() }); - this.service.toast(this.translate.instant('Edge.Config.App.Key.successRegisterKey'), 'success'); + this.service.toast(this.translate.instant("Edge.Config.App.Key.successRegisterKey"), "success"); }).catch(() => { - this.service.toast(this.translate.instant('Edge.Config.App.Key.failedRegisterKey'), 'danger'); + this.service.toast(this.translate.instant("Edge.Config.App.Key.failedRegisterKey"), "danger"); }).finally(() => { this.service.stopSpinner(this.spinnerId); }); @@ -219,28 +219,28 @@ export class KeyModalComponent implements OnInit { return registration.edgeId !== this.edge.id; }); if (differentEdge) { - this.service.toast(this.translate.instant('Edge.Config.App.Key.alreadyRegisteredDifferentSystem'), 'warning'); + this.service.toast(this.translate.instant("Edge.Config.App.Key.alreadyRegisteredDifferentSystem"), "warning"); return; } const sameApp = result.additionalInfo.registrations.some(registration => { return registration.appId === this.appId && registration.edgeId === this.edge.id; }); if (!sameApp) { - this.service.toast(this.translate.instant('Edge.Config.App.Key.alreadyRegisteredDifferentApp'), 'warning'); + this.service.toast(this.translate.instant("Edge.Config.App.Key.alreadyRegisteredDifferentApp"), "warning"); return; } } - this.service.toast(this.translate.instant('Edge.Config.App.Key.valid'), 'success'); + this.service.toast(this.translate.instant("Edge.Config.App.Key.valid"), "success"); } else { - this.service.toast(this.translate.instant('Edge.Config.App.Key.invalid'), 'danger'); + this.service.toast(this.translate.instant("Edge.Config.App.Key.invalid"), "danger"); } }).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.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); + console.log("Failed to validate Key", reason); } }).finally(() => { this.service.stopSpinner(this.spinnerId); @@ -272,7 +272,7 @@ export class KeyModalComponent implements OnInit { return null; } - const appPrefix = environment.edgeShortName + ' App'; + const appPrefix = environment.edgeShortName + " App"; // map to multiple description fields const descriptionFields = []; for (const bundle of bundles) { @@ -305,7 +305,7 @@ export class KeyModalComponent implements OnInit { descriptionFields.push(app.name); } } - return descriptionFields.length === 0 ? null : descriptionFields.map(e => appPrefix + ' ' + e).join(", "); + return descriptionFields.length === 0 ? null : descriptionFields.map(e => appPrefix + " " + e).join(", "); } private getAppsByCategory(): { [key: string]: GetApps.App[]; } { @@ -333,45 +333,45 @@ export class KeyModalComponent implements OnInit { private getFields(): FormlyFieldConfig[] { const fields: FormlyFieldConfig[] = []; fields.push({ - key: 'useRegisteredKeys', - type: 'checkbox', + key: "useRegisteredKeys", + type: "checkbox", props: { - label: this.translate.instant('Edge.Config.App.Key.useRegisteredKey'), + label: this.translate.instant("Edge.Config.App.Key.useRegisteredKey"), }, hide: this.registeredKeys.length === 0, expressions: { - 'props.disabled': field => field.model.useMasterKey, + "props.disabled": field => field.model.useMasterKey, }, }); fields.push({ - key: 'registeredKey', - type: 'select', + key: "registeredKey", + type: "select", props: { - label: this.translate.instant('Edge.Config.App.Key.registeredKey'), + label: this.translate.instant("Edge.Config.App.Key.registeredKey"), required: true, options: [], }, expressions: { - 'hide': () => this.registeredKeys.length === 0, - 'props.disabled': field => !field.model.useRegisteredKeys || field.model.useMasterKey, + "hide": () => this.registeredKeys.length === 0, + "props.disabled": field => !field.model.useRegisteredKeys || field.model.useMasterKey, }, - wrappers: ['formly-select-extended-wrapper'], + wrappers: ["formly-select-extended-wrapper"], }); fields.push({ - key: 'key', - type: 'input', + key: "key", + type: "input", props: { - label: this.translate.instant('Edge.Config.App.Key.key'), + label: this.translate.instant("Edge.Config.App.Key.key"), required: true, - placeholder: 'XXXX-XXXX-XXXX-XXXX', + placeholder: "XXXX-XXXX-XXXX-XXXX", }, expressions: { - 'props.disabled': field => field.model.useRegisteredKeys || field.model.useMasterKey, + "props.disabled": field => field.model.useRegisteredKeys || field.model.useMasterKey, }, validators: { - validation: ['key'], + validation: ["key"], }, hooks: { onInit: (field) => { @@ -391,30 +391,30 @@ export class KeyModalComponent implements OnInit { this.model.useMasterKey = true; fields.push( { - key: 'useMasterKey', - type: 'checkbox', + key: "useMasterKey", + type: "checkbox", props: { - label: this.translate.instant('Edge.Config.App.Key.useMasterKey'), + label: this.translate.instant("Edge.Config.App.Key.useMasterKey"), }, }, { - type: 'text', + type: "text", props: { - description: this.translate.instant('Edge.Config.App.Key.MASTER_KEY_HINT'), + description: this.translate.instant("Edge.Config.App.Key.MASTER_KEY_HINT"), }, expressions: { - hide: '!model.useMasterKey', + hide: "!model.useMasterKey", }, }, ); } fields.push({ - type: 'text', + type: "text", props: { - description: this.translate.instant('Edge.Config.App.Key.KEY_TYPO_MESSAGE_HINT'), + description: this.translate.instant("Edge.Config.App.Key.KEY_TYPO_MESSAGE_HINT"), }, - hideExpression: '!formState.gotInvalidKeyResponse', + hideExpression: "!formState.gotInvalidKeyResponse", }); return fields; diff --git a/ui/src/app/edge/settings/app/permissions.ts b/ui/src/app/edge/settings/app/permissions.ts index 2c107a5c673..0fe3b58071b 100644 --- a/ui/src/app/edge/settings/app/permissions.ts +++ b/ui/src/app/edge/settings/app/permissions.ts @@ -29,5 +29,5 @@ export function hasPredefinedKey(edge: Edge, user: User): boolean { } export function hasKeyModel(edge: Edge): boolean { - return edge.isVersionAtLeast('2023.1.2'); + return edge.isVersionAtLeast("2023.1.2"); } diff --git a/ui/src/app/edge/settings/app/single.component.ts b/ui/src/app/edge/settings/app/single.component.ts index 10e07150acd..0051a69d016 100644 --- a/ui/src/app/edge/settings/app/single.component.ts +++ b/ui/src/app/edge/settings/app/single.component.ts @@ -1,32 +1,32 @@ // @ts-strict-ignore -import { Component, HostListener, OnDestroy, OnInit } from '@angular/core'; -import { FormGroup } from '@angular/forms'; -import { DomSanitizer } from '@angular/platform-browser'; -import { ActivatedRoute, Router } from '@angular/router'; -import { ModalController } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; -import { Subject } from 'rxjs'; -import { filter, takeUntil } from 'rxjs/operators'; -import { ComponentJsonApiRequest } from 'src/app/shared/jsonrpc/request/componentJsonApiRequest'; -import { environment } from 'src/environments'; -import { Edge, Service, Utils, Websocket } from '../../../shared/shared'; -import { InstallAppComponent } from './install.component'; -import { GetApp } from './jsonrpc/getApp'; -import { GetAppDescriptor } from './jsonrpc/getAppDescriptor'; -import { GetApps } from './jsonrpc/getApps'; -import { AppCenter } from './keypopup/appCenter'; -import { AppCenterGetPossibleApps } from './keypopup/appCenterGetPossibleApps'; -import { AppCenterIsAppFree } from './keypopup/appCenterIsAppFree'; -import { KeyModalComponent, KeyValidationBehaviour } from './keypopup/modal.component'; -import { canEnterKey, hasKeyModel, hasPredefinedKey } from './permissions'; +import { Component, HostListener, OnDestroy, OnInit } from "@angular/core"; +import { FormGroup } from "@angular/forms"; +import { DomSanitizer } from "@angular/platform-browser"; +import { ActivatedRoute, Router } from "@angular/router"; +import { ModalController } from "@ionic/angular"; +import { TranslateService } from "@ngx-translate/core"; +import { Subject } from "rxjs"; +import { filter, takeUntil } from "rxjs/operators"; +import { ComponentJsonApiRequest } from "src/app/shared/jsonrpc/request/componentJsonApiRequest"; +import { environment } from "src/environments"; +import { Edge, Service, Utils, Websocket } from "../../../shared/shared"; +import { InstallAppComponent } from "./install.component"; +import { GetApp } from "./jsonrpc/getApp"; +import { GetAppDescriptor } from "./jsonrpc/getAppDescriptor"; +import { GetApps } from "./jsonrpc/getApps"; +import { AppCenter } from "./keypopup/appCenter"; +import { AppCenterGetPossibleApps } from "./keypopup/appCenterGetPossibleApps"; +import { AppCenterIsAppFree } from "./keypopup/appCenterIsAppFree"; +import { KeyModalComponent, KeyValidationBehaviour } from "./keypopup/modal.component"; +import { canEnterKey, hasKeyModel, hasPredefinedKey } from "./permissions"; @Component({ selector: SingleAppComponent.SELECTOR, - templateUrl: './single.component.html', + templateUrl: "./single.component.html", }) export class SingleAppComponent implements OnInit, OnDestroy { - private static readonly SELECTOR = 'app-single'; + private static readonly SELECTOR = "app-single"; public readonly spinnerId: string = SingleAppComponent.SELECTOR; public form: FormGroup | null = null; @@ -63,7 +63,7 @@ export class SingleAppComponent implements OnInit, OnDestroy { ) { } - @HostListener('window:resize', ['$event']) + @HostListener("window:resize", ["$event"]) private onResize(event) { this.updateIsXL(); } @@ -72,8 +72,8 @@ export class SingleAppComponent implements OnInit, OnDestroy { this.service.startSpinner(this.spinnerId); this.updateIsXL(); - this.appId = this.route.snapshot.params['appId']; - this.appName = this.route.snapshot.queryParams['name']; + this.appId = this.route.snapshot.params["appId"]; + this.appName = this.route.snapshot.queryParams["name"]; const appId = this.appId; this.service.setCurrentComponent(this.appName, this.route).then(edge => { this.edge = edge; @@ -137,20 +137,20 @@ export class SingleAppComponent implements OnInit, OnDestroy { // set appname, image ... const state = history?.state; - if (state && 'app' in history.state) { - if ('app' in history.state) { + if (state && "app" in history.state) { + if ("app" in history.state) { this.setApp(history.state.app); } - if ('appKey' in history.state) { + if ("appKey" in history.state) { this.key = history.state.appKey; } - if ('useMasterKey' in history.state) { + if ("useMasterKey" in history.state) { this.useMasterKey = history.state.useMasterKey; } } else { edge.sendRequest(this.websocket, new ComponentJsonApiRequest({ - componentId: '_appManager', + componentId: "_appManager", payload: new GetApp.Request({ appId: appId }), })).then(response => { const app = (response as GetApp.Response).result.app; @@ -158,19 +158,19 @@ export class SingleAppComponent implements OnInit, OnDestroy { this.setApp(app); }).catch(reason => { console.error(reason.error); - this.service.toast('Error while receiving App[' + appId + ']: ' + reason.error.message, 'danger'); + this.service.toast("Error while receiving App[" + appId + "]: " + reason.error.message, "danger"); }); } // set app descriptor edge.sendRequest(this.websocket, new ComponentJsonApiRequest({ - componentId: '_appManager', + componentId: "_appManager", payload: new GetAppDescriptor.Request({ appId: appId }), })).then(response => { const descriptor = (response as GetAppDescriptor.Response).result; this.descriptor = GetAppDescriptor.postprocess(descriptor, this.sanitizer); }) - .catch(InstallAppComponent.errorToast(this.service, error => 'Error while receiving AppDescriptor for App[' + appId + ']: ' + error)) + .catch(InstallAppComponent.errorToast(this.service, error => "Error while receiving AppDescriptor for App[" + appId + "]: " + error)) .finally(() => { this.increaseReceivedResponse(); }); @@ -184,7 +184,7 @@ export class SingleAppComponent implements OnInit, OnDestroy { protected iFrameStyle() { const styles = { - 'height': (this.isXL) ? '100%' : window.innerHeight + 'px', + "height": (this.isXL) ? "100%" : window.innerHeight + "px", }; return styles; } @@ -193,13 +193,13 @@ export class SingleAppComponent implements OnInit, OnDestroy { if (this.key || this.useMasterKey) { // if key already set navigate directly to installation view const state = this.useMasterKey ? { useMasterKey: true } : { appKey: this.key }; - this.router.navigate(['device/' + (this.edge.id) + '/settings/app/install/' + this.appId] + this.router.navigate(["device/" + (this.edge.id) + "/settings/app/install/" + this.appId] , { queryParams: { name: this.appName }, state: state }); return; } // if the version is not high enough and the edge doesnt support installing apps via keys directly navigate to installation if (!hasKeyModel(this.edge) || this.isFreeApp) { - this.router.navigate(['device/' + (this.edge.id) + '/settings/app/install/' + this.appId] + this.router.navigate(["device/" + (this.edge.id) + "/settings/app/install/" + this.appId] , { queryParams: { name: this.appName } }); return; } @@ -239,7 +239,7 @@ export class SingleAppComponent implements OnInit, OnDestroy { behaviour: behaviour, appName: this.appName, }, - cssClass: 'auto-height', + cssClass: "auto-height", }); return await modal.present(); } diff --git a/ui/src/app/edge/settings/app/update.component.ts b/ui/src/app/edge/settings/app/update.component.ts index a5cb88b67ea..94c049bbcfb 100644 --- a/ui/src/app/edge/settings/app/update.component.ts +++ b/ui/src/app/edge/settings/app/update.component.ts @@ -1,16 +1,16 @@ // @ts-strict-ignore -import { Component, OnInit } from '@angular/core'; -import { FormGroup } from '@angular/forms'; -import { ActivatedRoute, Router } from '@angular/router'; -import { FormlyFieldConfig } from '@ngx-formly/core'; -import { TranslateService } from '@ngx-translate/core'; -import { ComponentJsonApiRequest } from 'src/app/shared/jsonrpc/request/componentJsonApiRequest'; -import { Edge, Service, Utils, Websocket } from '../../../shared/shared'; -import { InstallAppComponent } from './install.component'; -import { DeleteAppInstance } from './jsonrpc/deleteAppInstance'; -import { GetAppAssistant } from './jsonrpc/getAppAssistant'; -import { GetAppInstances } from './jsonrpc/getAppInstances'; -import { UpdateAppInstance } from './jsonrpc/updateAppInstance'; +import { Component, OnInit } from "@angular/core"; +import { FormGroup } from "@angular/forms"; +import { ActivatedRoute, Router } from "@angular/router"; +import { FormlyFieldConfig } from "@ngx-formly/core"; +import { TranslateService } from "@ngx-translate/core"; +import { ComponentJsonApiRequest } from "src/app/shared/jsonrpc/request/componentJsonApiRequest"; +import { Edge, Service, Utils, Websocket } from "../../../shared/shared"; +import { InstallAppComponent } from "./install.component"; +import { DeleteAppInstance } from "./jsonrpc/deleteAppInstance"; +import { GetAppAssistant } from "./jsonrpc/getAppAssistant"; +import { GetAppInstances } from "./jsonrpc/getAppInstances"; +import { UpdateAppInstance } from "./jsonrpc/updateAppInstance"; interface MyInstance { instanceId: string, // uuid @@ -23,11 +23,11 @@ interface MyInstance { @Component({ selector: UpdateAppComponent.SELECTOR, - templateUrl: './update.component.html', + templateUrl: "./update.component.html", }) export class UpdateAppComponent implements OnInit { - private static readonly SELECTOR = 'app-update'; + private static readonly SELECTOR = "app-update"; public readonly spinnerId: string = UpdateAppComponent.SELECTOR; protected instances: MyInstance[] = []; @@ -48,19 +48,19 @@ export class UpdateAppComponent implements OnInit { public ngOnInit() { this.service.startSpinner(this.spinnerId); const appId = this.route.snapshot.params["appId"]; - const appName = this.route.snapshot.queryParams['name']; + const appName = this.route.snapshot.queryParams["name"]; this.service.setCurrentComponent(appName, this.route).then(edge => { this.edge = edge; edge.sendRequest(this.websocket, new ComponentJsonApiRequest({ - componentId: '_appManager', + componentId: "_appManager", payload: new GetAppInstances.Request({ appId: appId }), })).then(getInstancesResponse => { const recInstances = (getInstancesResponse as GetAppInstances.Response).result.instances; edge.sendRequest(this.websocket, new ComponentJsonApiRequest({ - componentId: '_appManager', + componentId: "_appManager", payload: new GetAppAssistant.Request({ appId: appId }), })).then(getAppAssistantResponse => { const appAssistant = (getAppAssistantResponse as GetAppAssistant.Response).result; @@ -69,7 +69,7 @@ export class UpdateAppComponent implements OnInit { for (const instance of recInstances) { const form = new FormGroup({}); const model = { - 'ALIAS': instance.alias, + "ALIAS": instance.alias, ...instance.properties, }; this.instances.push({ @@ -83,8 +83,8 @@ export class UpdateAppComponent implements OnInit { } this.service.stopSpinner(this.spinnerId); - }).catch(InstallAppComponent.errorToast(this.service, error => 'Error while receiving App Assistant for [' + appId + ']: ' + error)); - }).catch(InstallAppComponent.errorToast(this.service, error => 'Error while receiving App-Instances for [' + appId + ']: ' + error)); + }).catch(InstallAppComponent.errorToast(this.service, error => "Error while receiving App Assistant for [" + appId + "]: " + error)); + }).catch(InstallAppComponent.errorToast(this.service, error => "Error while receiving App-Instances for [" + appId + "]: " + error)); }); } @@ -92,17 +92,17 @@ export class UpdateAppComponent implements OnInit { this.service.startSpinnerTransparentBackground(instance.instanceId); instance.isUpdating = true; // remove alias field from properties - const alias = instance.form.value['ALIAS']; + const alias = instance.form.value["ALIAS"]; const clonedFields = {}; for (const item in instance.form.value) { - if (item != 'ALIAS') { + if (item != "ALIAS") { clonedFields[item] = instance.form.value[item]; } } instance.form.markAsPristine(); this.edge.sendRequest(this.websocket, new ComponentJsonApiRequest({ - componentId: '_appManager', + componentId: "_appManager", payload: new UpdateAppInstance.Request({ instanceId: instance.instanceId, alias: alias, @@ -112,14 +112,14 @@ export class UpdateAppComponent implements OnInit { const result = (response as UpdateAppInstance.Response).result; if (result.warnings && result.warnings.length > 0) { - this.service.toast(result.warnings.join(';'), 'warning'); + this.service.toast(result.warnings.join(";"), "warning"); } else { - this.service.toast(this.translate.instant('Edge.Config.App.successUpdate'), 'success'); + this.service.toast(this.translate.instant("Edge.Config.App.successUpdate"), "success"); } instance.properties = result.instance.properties; - instance.properties['ALIAS'] = result.instance.alias; + instance.properties["ALIAS"] = result.instance.alias; }) - .catch(InstallAppComponent.errorToast(this.service, error => this.translate.instant('Edge.Config.App.failUpdate', { error: error }))) + .catch(InstallAppComponent.errorToast(this.service, error => this.translate.instant("Edge.Config.App.failUpdate", { error: error }))) .finally(() => { instance.isUpdating = false; this.service.stopSpinner(instance.instanceId); @@ -131,17 +131,17 @@ export class UpdateAppComponent implements OnInit { instance.isDeleting = true; this.edge.sendRequest(this.websocket, new ComponentJsonApiRequest({ - componentId: '_appManager', + componentId: "_appManager", payload: new DeleteAppInstance.Request({ instanceId: instance.instanceId, }), })).then(response => { this.instances.splice(this.instances.indexOf(instance), 1); - this.service.toast(this.translate.instant('Edge.Config.App.successDelete'), 'success'); + this.service.toast(this.translate.instant("Edge.Config.App.successDelete"), "success"); const navigationExtras = { state: { appInstanceChange: true } }; - this.router.navigate(['device/' + (this.edge.id) + '/settings/app/'], navigationExtras); + this.router.navigate(["device/" + (this.edge.id) + "/settings/app/"], navigationExtras); }) - .catch(InstallAppComponent.errorToast(this.service, error => this.translate.instant('Edge.Config.App.failDelete', { error: error }))) + .catch(InstallAppComponent.errorToast(this.service, error => this.translate.instant("Edge.Config.App.failDelete", { error: error }))) .finally(() => { instance.isDeleting = false; this.service.stopSpinner(instance.instanceId); diff --git a/ui/src/app/edge/settings/channels/channels.component.ts b/ui/src/app/edge/settings/channels/channels.component.ts index a6adc4dd12c..36ea1f7911c 100644 --- a/ui/src/app/edge/settings/channels/channels.component.ts +++ b/ui/src/app/edge/settings/channels/channels.component.ts @@ -1,26 +1,26 @@ // @ts-strict-ignore -import { Component } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; -import { TranslateService } from '@ngx-translate/core'; -import { PersistencePriority } from 'src/app/shared/components/edge/edgeconfig'; -import { SetChannelValueRequest } from 'src/app/shared/jsonrpc/request/setChannelValueRequest'; -import { environment } from 'src/environments'; - -import { ComponentJsonApiRequest } from 'src/app/shared/jsonrpc/request/componentJsonApiRequest'; -import { GetChannelsOfComponentRequest } from 'src/app/shared/jsonrpc/request/getChannelsOfComponentRequest'; -import { Channel, GetChannelsOfComponentResponse } from 'src/app/shared/jsonrpc/response/getChannelsOfComponentResponse'; -import { ChannelAddress, Edge, EdgeConfig, EdgePermission, Service, Websocket } from '../../../shared/shared'; +import { Component } from "@angular/core"; +import { ActivatedRoute, Router } from "@angular/router"; +import { TranslateService } from "@ngx-translate/core"; +import { PersistencePriority } from "src/app/shared/components/edge/edgeconfig"; +import { SetChannelValueRequest } from "src/app/shared/jsonrpc/request/setChannelValueRequest"; +import { environment } from "src/environments"; + +import { ComponentJsonApiRequest } from "src/app/shared/jsonrpc/request/componentJsonApiRequest"; +import { GetChannelsOfComponentRequest } from "src/app/shared/jsonrpc/request/getChannelsOfComponentRequest"; +import { Channel, GetChannelsOfComponentResponse } from "src/app/shared/jsonrpc/response/getChannelsOfComponentResponse"; +import { ChannelAddress, Edge, EdgeConfig, EdgePermission, Service, Websocket } from "../../../shared/shared"; @Component({ selector: ChannelsComponent.SELECTOR, - templateUrl: './channels.component.html', + templateUrl: "./channels.component.html", }) export class ChannelsComponent { private static readonly SELECTOR = "channels"; private static readonly URL_PREFIX = "channels"; public customAlertOptions: any = { - cssClass: 'wide-alert', + cssClass: "wide-alert", }; protected isAtLeastOneChannelExistingInEdgeConfig: boolean = false; @@ -45,19 +45,19 @@ export class ChannelsComponent { private static readonly ERROR_COMPONENT_COULD_NOT_BE_FOUND = (componentId: string) => `[ComponentId] ${componentId} doesn't exist on this edge`; ionViewWillEnter() { - this.service.setCurrentComponent("Channels", this.route).then(edge => { + this.service.getCurrentEdge().then(edge => { this.edge = edge; }); this.service.getConfig().then(config => { this.config = config; - this.persistencePriority = this.config.getComponentsByFactory("Controller.Api.Backend")?.[0]?.properties['persistencePriority'] ?? PersistencePriority.DEFAULT_GLOBAL_PRIORITY; + this.persistencePriority = this.config.getComponentsByFactory("Controller.Api.Backend")?.[0]?.properties["persistencePriority"] ?? PersistencePriority.DEFAULT_GLOBAL_PRIORITY; this.service.startSpinner(this.spinnerId); this.loadSavedChannels().then(message => { if (message) { - this.service.toast(message, 'success'); + this.service.toast(message, "success"); } }).catch(reason => { - this.service.toast(reason, 'danger'); + this.service.toast(reason, "danger"); this.selectedComponentChannels = new Map(); this.isAtLeastOneChannelExistingInEdgeConfig = true; }).finally(() => { @@ -91,7 +91,7 @@ export class ChannelsComponent { const channelData = await this.getChannel(componentId, channelId); channelEntry.showPersistencePriority = PersistencePriority.isLessThan(channelData.persistencePriority, this.persistencePriority); - if (channelData.accessMode != 'WO') { + if (channelData.accessMode != "WO") { const channelAddress = new ChannelAddress(componentId, channelId); this.subscribedChannels.set(channelAddress.toString(), channelAddress); if (this.edge) { @@ -136,7 +136,7 @@ export class ChannelsComponent { ).then(() => { this.service.toast("Successfully set " + componentId + "/" + channelId + " to [" + channelValue + "]", "success"); }).catch(() => { - this.service.toast("Error setting " + componentId + "/" + channelId + " to [" + channelValue + "]", 'danger'); + this.service.toast("Error setting " + componentId + "/" + channelId + " to [" + channelValue + "]", "danger"); }); } } @@ -161,17 +161,17 @@ export class ChannelsComponent { this.loadChannelsAndStore(componentId).then(() => { // ignore }).catch(reason => { - this.service.toast('Unable to load channels for ' + componentId + ': ' + reason, 'danger'); + this.service.toast("Unable to load channels for " + componentId + ": " + reason, "danger"); }); } private saveChannelsInUrl(): void { const selectedChannels = this.getSelectedChannelStrings(); if (selectedChannels && selectedChannels.length > 0) { - this.router.navigate(['device/' + (this.edge.id) + '/settings/channels/'], { queryParams: { save: selectedChannels.toString() } }); + this.router.navigate(["device/" + (this.edge.id) + "/settings/channels/"], { queryParams: { save: selectedChannels.toString() } }); this.isAtLeastOneChannelExistingInEdgeConfig = false; } else { - this.router.navigate(['device/' + (this.edge.id) + '/settings/channels/']); + this.router.navigate(["device/" + (this.edge.id) + "/settings/channels/"]); } } @@ -190,21 +190,21 @@ export class ChannelsComponent { } private async loadSavedChannels(): Promise { - const address = this.route.snapshot.queryParamMap.get('save'); + const address = this.route.snapshot.queryParamMap.get("save"); if (address) { - const channels = address.split(',')?.map(element => ChannelAddress.fromString(element)); + const channels = address.split(",")?.map(element => ChannelAddress.fromString(element)); try { const existingComponents = channels.filter(el => el.componentId in this.config.components); if (existingComponents.length > 1) { this.isAtLeastOneChannelExistingInEdgeConfig = true; - return 'No component matches this edges components'; + return "No component matches this edges components"; } await Promise.all(channels.map(el => this.subscribeChannel(el.componentId, el.channelId))); - return 'Successfully loaded saved channels from url'; + return "Successfully loaded saved channels from url"; } catch (reason) { - throw 'Some channels may not have been loaded from url: ' + reason; + throw "Some channels may not have been loaded from url: " + reason; } } @@ -213,9 +213,9 @@ export class ChannelsComponent { const savedData: ChannelAddress[] = JSON.parse(storedValue); try { await Promise.all(savedData.map(el => this.subscribeChannel(el.componentId, el.channelId))); - return 'Successfully loaded saved channels from session'; + return "Successfully loaded saved channels from session"; } catch (reason) { - throw 'Some channels may not have been loaded from session: ' + reason; + throw "Some channels may not have been loaded from session: " + reason; } } } @@ -229,7 +229,7 @@ export class ChannelsComponent { if (channel) { resolve(channel); } else { - reject(channelId + ' is not defined by component ' + componentId); + reject(channelId + " is not defined by component " + componentId); } return; } @@ -239,7 +239,7 @@ export class ChannelsComponent { if (channel) { resolve(channel); } else { - reject(channelId + ' is not defined by component ' + componentId); + reject(channelId + " is not defined by component " + componentId); } }).catch(reject); }); @@ -272,7 +272,7 @@ export class ChannelsComponent { } this.edge.sendRequest(this.websocket, new ComponentJsonApiRequest({ - componentId: '_componentManager', + componentId: "_componentManager", payload: new GetChannelsOfComponentRequest({ componentId: componentId }), })).then((response: GetChannelsOfComponentResponse) => { resolve(response.result.channels); diff --git a/ui/src/app/edge/settings/component/install/index.component.ts b/ui/src/app/edge/settings/component/install/index.component.ts index 5b5ec1ecf07..a31df0b6bf0 100644 --- a/ui/src/app/edge/settings/component/install/index.component.ts +++ b/ui/src/app/edge/settings/component/install/index.component.ts @@ -1,9 +1,9 @@ // @ts-strict-ignore -import { Component, OnInit } from '@angular/core'; -import { CategorizedFactories } from 'src/app/shared/components/edge/edgeconfig'; -import { JsonrpcRequest, JsonrpcResponseSuccess } from 'src/app/shared/jsonrpc/base'; -import { ComponentJsonApiRequest } from 'src/app/shared/jsonrpc/request/componentJsonApiRequest'; -import { Edge, EdgeConfig, EdgePermission, Service, Utils, Websocket } from '../../../../shared/shared'; +import { Component, OnInit } from "@angular/core"; +import { CategorizedFactories } from "src/app/shared/components/edge/edgeconfig"; +import { JsonrpcRequest, JsonrpcResponseSuccess } from "src/app/shared/jsonrpc/base"; +import { ComponentJsonApiRequest } from "src/app/shared/jsonrpc/request/componentJsonApiRequest"; +import { Edge, EdgeConfig, EdgePermission, Service, Utils, Websocket } from "../../../../shared/shared"; interface MyCategorizedFactories extends CategorizedFactories { isClicked?: boolean, @@ -12,7 +12,7 @@ interface MyCategorizedFactories extends CategorizedFactories { @Component({ selector: IndexComponent.SELECTOR, - templateUrl: './index.component.html', + templateUrl: "./index.component.html", }) export class IndexComponent implements OnInit { @@ -41,7 +41,7 @@ export class IndexComponent implements OnInit { updateFilter(completeFilter: string) { // take each space-separated string as an individual and-combined filter - const filters = completeFilter.toLowerCase().split(' '); + const filters = completeFilter.toLowerCase().split(" "); let countFilteredEntries = 0; for (const entry of this.list) { entry.filteredFactories = entry.factories.filter(entry => @@ -65,7 +65,7 @@ export class IndexComponent implements OnInit { private async getCategorizedFactories(): Promise { if (EdgePermission.hasReducedFactories(this.edge)) { const response = await this.edge.sendRequest(this.websocket, new ComponentJsonApiRequest({ - componentId: '_componentManager', + componentId: "_componentManager", payload: new GetAllComponentFactoriesRequest(), })); for (const [factoryId, factory] of Object.entries(response.result.factories)) { diff --git a/ui/src/app/edge/settings/component/install/install.component.ts b/ui/src/app/edge/settings/component/install/install.component.ts index 53be5a1fef2..965ac7d874e 100644 --- a/ui/src/app/edge/settings/component/install/install.component.ts +++ b/ui/src/app/edge/settings/component/install/install.component.ts @@ -1,13 +1,13 @@ // @ts-strict-ignore -import { Component, OnInit } from '@angular/core'; -import { FormGroup } from '@angular/forms'; -import { ActivatedRoute } from '@angular/router'; -import { FormlyFieldConfig } from '@ngx-formly/core'; -import { Edge, EdgeConfig, Service, Utils, Websocket } from '../../../../shared/shared'; +import { Component, OnInit } from "@angular/core"; +import { FormGroup } from "@angular/forms"; +import { ActivatedRoute } from "@angular/router"; +import { FormlyFieldConfig } from "@ngx-formly/core"; +import { Edge, EdgeConfig, Service, Utils, Websocket } from "../../../../shared/shared"; @Component({ selector: ComponentInstallComponent.SELECTOR, - templateUrl: './install.component.html', + templateUrl: "./install.component.html", }) export class ComponentInstallComponent implements OnInit { @@ -39,15 +39,15 @@ export class ComponentInstallComponent implements OnInit { const fields: FormlyFieldConfig[] = []; const model = {}; for (const property of properties) { - const property_id = property.id.replace('.', '_'); + const property_id = property.id.replace(".", "_"); let defaultValue = property.defaultValue; // if the type is an array and there is no defaultValue then set the defaultValue to an empty array - if (property.schema["type"] === 'repeat' && defaultValue === null) { + if (property.schema["type"] === "repeat" && defaultValue === null) { defaultValue = []; } const field: FormlyFieldConfig = { key: property_id, - type: 'input', + type: "input", templateOptions: { label: property.name, required: defaultValue === null, @@ -61,7 +61,7 @@ export class ComponentInstallComponent implements OnInit { model[property_id] = defaultValue; // Set the next free Component-ID as defaultValue - if (property_id == 'id' && property.schema["type"] !== 'repeat') { + if (property_id == "id" && property.schema["type"] !== "repeat") { const thisMatch = defaultValue.match(/^(.*)(\d+)$/); if (thisMatch) { const thisPrefix = thisMatch[1]; @@ -98,15 +98,15 @@ export class ComponentInstallComponent implements OnInit { // ignore 'null' values continue; } - const property_id = controlKey.replace('_', '.'); + const property_id = controlKey.replace("_", "."); properties.push({ name: property_id, value: control.value }); } this.edge.createComponentConfig(this.websocket, this.factoryId, properties).then(response => { this.form.markAsPristine(); - this.service.toast("Successfully created in instance of " + this.factoryId + ".", 'success'); + this.service.toast("Successfully created in instance of " + this.factoryId + ".", "success"); }).catch(reason => { - this.service.toast("Error creating an instance of " + this.factoryId + ":" + reason.error.message, 'danger'); + this.service.toast("Error creating an instance of " + this.factoryId + ":" + reason.error.message, "danger"); }); } diff --git a/ui/src/app/edge/settings/component/update/index.component.ts b/ui/src/app/edge/settings/component/update/index.component.ts index 05e6efe2b3f..d35810ed057 100644 --- a/ui/src/app/edge/settings/component/update/index.component.ts +++ b/ui/src/app/edge/settings/component/update/index.component.ts @@ -1,7 +1,7 @@ // @ts-strict-ignore -import { Component, OnInit } from '@angular/core'; -import { CategorizedComponents } from 'src/app/shared/components/edge/edgeconfig'; -import { EdgeConfig, Service, Utils } from '../../../../shared/shared'; +import { Component, OnInit } from "@angular/core"; +import { CategorizedComponents } from "src/app/shared/components/edge/edgeconfig"; +import { EdgeConfig, Service, Utils } from "../../../../shared/shared"; interface MyCategorizedComponents extends CategorizedComponents { isNatureClicked?: boolean, @@ -10,7 +10,7 @@ interface MyCategorizedComponents extends CategorizedComponents { @Component({ selector: IndexComponent.SELECTOR, - templateUrl: './index.component.html', + templateUrl: "./index.component.html", }) export class IndexComponent implements OnInit { @@ -41,7 +41,7 @@ export class IndexComponent implements OnInit { updateFilter(completeFilter: string) { // take each space-separated string as an individual and-combined filter - const filters = completeFilter.toLowerCase().split(' '); + const filters = completeFilter.toLowerCase().split(" "); let countFilteredEntries = 0; for (const entry of this.list) { entry.filteredComponents = entry.components.filter(entry => diff --git a/ui/src/app/edge/settings/component/update/update.component.ts b/ui/src/app/edge/settings/component/update/update.component.ts index e4177748d18..3c882e05473 100644 --- a/ui/src/app/edge/settings/component/update/update.component.ts +++ b/ui/src/app/edge/settings/component/update/update.component.ts @@ -1,13 +1,13 @@ // @ts-strict-ignore -import { Component, OnInit } from '@angular/core'; -import { FormGroup } from '@angular/forms'; -import { ActivatedRoute } from '@angular/router'; -import { FormlyFieldConfig } from '@ngx-formly/core'; -import { Edge, EdgeConfig, Service, Utils, Websocket } from '../../../../shared/shared'; +import { Component, OnInit } from "@angular/core"; +import { FormGroup } from "@angular/forms"; +import { ActivatedRoute } from "@angular/router"; +import { FormlyFieldConfig } from "@ngx-formly/core"; +import { Edge, EdgeConfig, Service, Utils, Websocket } from "../../../../shared/shared"; @Component({ selector: ComponentUpdateComponent.SELECTOR, - templateUrl: './update.component.html', + templateUrl: "./update.component.html", }) export class ComponentUpdateComponent implements OnInit { @@ -44,13 +44,13 @@ export class ComponentUpdateComponent implements OnInit { this.factory = factory; for (const property of properties) { - if (property.id === 'id') { + if (property.id === "id") { continue; // ignore Component-ID } - const property_id = property.id.replace('.', '_'); + const property_id = property.id.replace(".", "_"); const field: FormlyFieldConfig = { key: property_id, - type: 'input', + type: "input", templateOptions: { label: property.name, description: property.description, @@ -63,7 +63,7 @@ export class ComponentUpdateComponent implements OnInit { if (component.properties[property.id]) { // filter arrays with nested objects - if (Array.isArray(component.properties[property.id]) && component.properties[property.id]?.length > 0 && component.properties[property.id]?.every(element => typeof element === 'object')) { + if (Array.isArray(component.properties[property.id]) && component.properties[property.id]?.length > 0 && component.properties[property.id]?.every(element => typeof element === "object")) { // Stringify json for objects nested inside an array model[property_id] = JSON.stringify(component.properties[property.id]); @@ -82,24 +82,24 @@ export class ComponentUpdateComponent implements OnInit { for (const controlKey in this.form.controls) { const control = this.form.controls[controlKey]; if (control.dirty) { - const property_id = controlKey.replace('_', '.'); + const property_id = controlKey.replace("_", "."); properties.push({ name: property_id, value: control.value }); } } this.edge.updateComponentConfig(this.websocket, this.componentId, properties).then(() => { this.form.markAsPristine(); - this.service.toast("Successfully updated " + this.componentId + ".", 'success'); + this.service.toast("Successfully updated " + this.componentId + ".", "success"); }).catch(reason => { - this.service.toast("Error updating " + this.componentId + ":" + reason.error.message, 'danger'); + this.service.toast("Error updating " + this.componentId + ":" + reason.error.message, "danger"); }); } public delete() { this.edge.deleteComponentConfig(this.websocket, this.componentId).then(() => { this.form.markAsPristine(); - this.service.toast("Successfully deleted " + this.componentId + ".", 'success'); + this.service.toast("Successfully deleted " + this.componentId + ".", "success"); }).catch(reason => { - this.service.toast("Error deleting " + this.componentId + ":" + reason.error.message, 'danger'); + this.service.toast("Error deleting " + this.componentId + ":" + reason.error.message, "danger"); }); } diff --git a/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.module.ts b/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.module.ts index f5d2946018f..863a01664e4 100644 --- a/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.module.ts +++ b/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.module.ts @@ -1,6 +1,6 @@ -import { NgModule } from '@angular/core'; -import { SharedModule } from 'src/app/shared/shared.module'; -import { JsonrpcTestComponent } from './jsonrpctest'; +import { NgModule } from "@angular/core"; +import { SharedModule } from "src/app/shared/shared.module"; +import { JsonrpcTestComponent } from "./jsonrpctest"; @NgModule({ imports: [ diff --git a/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.ts b/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.ts index b604b231d24..8bab188a03f 100644 --- a/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.ts +++ b/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.ts @@ -1,14 +1,14 @@ // @ts-strict-ignore -import { Component, OnInit } from '@angular/core'; -import { FormGroup } from '@angular/forms'; -import { ActivatedRoute } from '@angular/router'; -import { JsonrpcRequest } from 'src/app/shared/jsonrpc/base'; -import { Edge, Service, Websocket } from 'src/app/shared/shared'; -import { environment } from 'src/environments'; +import { Component, OnInit } from "@angular/core"; +import { FormGroup } from "@angular/forms"; +import { ActivatedRoute } from "@angular/router"; +import { JsonrpcRequest } from "src/app/shared/jsonrpc/base"; +import { Edge, Service, Websocket } from "src/app/shared/shared"; +import { environment } from "src/environments"; @Component({ selector: JsonrpcTestComponent.SELECTOR, - templateUrl: './jsonrpctest.html', + templateUrl: "./jsonrpctest.html", }) export class JsonrpcTestComponent implements OnInit { @@ -26,19 +26,19 @@ export class JsonrpcTestComponent implements OnInit { } public ngOnInit(): void { - this.service.setCurrentComponent('Jsonrpc Test', this.route).then(edge => { + this.service.getCurrentEdge().then(edge => { this.edge = edge; edge.sendRequest(this.websocket, new JsonrpcRequest("routes", {})).then(response => { - this.endpoints = (response.result['endpoints'] as EndpointResponse[]).map(endpoint => { + this.endpoints = (response.result["endpoints"] as EndpointResponse[]).map(endpoint => { return { method: endpoint.method, - description: endpoint.description ? endpoint.description.replace('\n', '
      ') : null, + description: endpoint.description ? endpoint.description.replace("\n", "
      ") : null, tags: endpoint.tags, guards: endpoint.guards, request: endpoint.request, // JSON.stringify(endpoint.request.json, null, 2), response: endpoint.response, parent: endpoint.parent, - requestMethod: 'raw', + requestMethod: "raw", form: new FormGroup({}), model: {}, modelRaw: JSON.stringify(createDummyRequest(endpoint.request.json), null, 2), @@ -46,7 +46,7 @@ export class JsonrpcTestComponent implements OnInit { }); }); }).catch(e => { - this.service.toast(e, 'danger'); + this.service.toast(e, "danger"); }); } @@ -64,8 +64,8 @@ export class JsonrpcTestComponent implements OnInit { ); for (let i = endpoint.parent.length - 1; i >= 0; i--) { const parent = endpoint.parent[i]; - if (environment.backend === 'OpenEMS Backend') { - if (parent.method === 'authenticatedRpc') { + if (environment.backend === "OpenEMS Backend") { + if (parent.method === "authenticatedRpc") { break; } } @@ -88,7 +88,7 @@ export class JsonrpcTestComponent implements OnInit { } - (environment.backend === 'OpenEMS Edge' + (environment.backend === "OpenEMS Edge" ? this.websocket.sendRequest(request) : this.edge.sendRequest(this.websocket, request)) .then(response => { @@ -108,15 +108,15 @@ function createDummyRequest(endpointType?: EndpointType) { return undefined; } switch (endpointType.type) { - case 'object': { + case "object": { const obj = {}; for (const [key, value] of Object.entries(endpointType.properties)) { obj[key] = createDummyRequest(value); } return obj; } - case 'string': { - return 'string'; + case "string": { + return "string"; } } } @@ -153,11 +153,11 @@ type RequestExample = { type EndpointType = { - type: 'object', + type: "object", properties: { [key: string]: EndpointType } } | { - type: 'string', + type: "string", constraints: string[] }; diff --git a/ui/src/app/edge/settings/network/network.component.ts b/ui/src/app/edge/settings/network/network.component.ts index 1d94213534d..99b9af92671 100644 --- a/ui/src/app/edge/settings/network/network.component.ts +++ b/ui/src/app/edge/settings/network/network.component.ts @@ -1,25 +1,25 @@ -import { Component, OnInit } from '@angular/core'; -import { FormGroup } from '@angular/forms'; -import { FormlyFieldConfig, FormlyForm } from '@ngx-formly/core'; -import { TranslateService } from '@ngx-translate/core'; -import { ComponentJsonApiRequest } from 'src/app/shared/jsonrpc/request/componentJsonApiRequest'; -import { Role } from 'src/app/shared/type/role'; -import { Edge, Service, Websocket } from '../../../shared/shared'; -import { GetNetworkConfigRequest } from './getNetworkConfigRequest'; -import { GetNetworkConfigResponse } from './getNetworkConfigResponse'; -import { SetNetworkConfigRequest } from './setNetworkConfigRequest'; -import { InterfaceForm, InterfaceModel, IpAddress, NetworkConfig, NetworkInterface, NetworkUtils } from './shared'; +import { Component, OnInit } from "@angular/core"; +import { FormGroup } from "@angular/forms"; +import { FormlyFieldConfig, FormlyForm } from "@ngx-formly/core"; +import { TranslateService } from "@ngx-translate/core"; +import { ComponentJsonApiRequest } from "src/app/shared/jsonrpc/request/componentJsonApiRequest"; +import { Role } from "src/app/shared/type/role"; +import { Edge, Service, Websocket } from "../../../shared/shared"; +import { GetNetworkConfigRequest } from "./getNetworkConfigRequest"; +import { GetNetworkConfigResponse } from "./getNetworkConfigResponse"; +import { SetNetworkConfigRequest } from "./setNetworkConfigRequest"; +import { InterfaceForm, InterfaceModel, IpAddress, NetworkConfig, NetworkInterface, NetworkUtils } from "./shared"; @Component({ selector: NetworkComponent.SELECTOR, - templateUrl: './network.component.html', + templateUrl: "./network.component.html", }) export class NetworkComponent implements OnInit { - private static readonly SELECTOR: string = 'network'; - private static readonly ETH_0: string = 'eth0'; - private static readonly STATIC_LABEL: string = 'static'; - private static readonly NO_LABEL: string = ''; + private static readonly SELECTOR: string = "network"; + private static readonly ETH_0: string = "eth0"; + private static readonly STATIC_LABEL: string = "static"; + private static readonly NO_LABEL: string = ""; public edge: Edge | null = null; protected forms: InterfaceForm[] = []; @@ -37,7 +37,7 @@ export class NetworkComponent implements OnInit { public submit(iface: InterfaceForm): void { if (!iface.formGroup.valid) { - this.service.toast(this.translate.instant('Edge.Network.mandatoryFields'), 'danger'); + this.service.toast(this.translate.instant("Edge.Network.mandatoryFields"), "danger"); return; } @@ -57,9 +57,9 @@ export class NetworkComponent implements OnInit { */ protected hideOrShowFields(form: FormlyForm): void { - const addressField: FormlyFieldConfig | undefined = form.fields.find(element => element.key == 'addressesList'); - const linkLocalAddressField: FormlyFieldConfig | undefined = form.fields.find(element => element.key == 'linkLocalAddressing'); - const metric: FormlyFieldConfig | undefined = form.fields.find(element => element.key == 'metric'); + const addressField: FormlyFieldConfig | undefined = form.fields.find(element => element.key == "addressesList"); + const linkLocalAddressField: FormlyFieldConfig | undefined = form.fields.find(element => element.key == "linkLocalAddressing"); + const metric: FormlyFieldConfig | undefined = form.fields.find(element => element.key == "metric"); const advancedMode: boolean = form.model.advancedMode; if (addressField) { addressField.hide = !advancedMode; } @@ -71,11 +71,11 @@ export class NetworkComponent implements OnInit { try { this.edge = await this.service.getCurrentEdge(); if (this.edge) { - const response: GetNetworkConfigResponse = await this.edge.sendRequest(this.websocket, new ComponentJsonApiRequest({ componentId: '_host', payload: new GetNetworkConfigRequest() })) as GetNetworkConfigResponse; + const response: GetNetworkConfigResponse = await this.edge.sendRequest(this.websocket, new ComponentJsonApiRequest({ componentId: "_host", payload: new GetNetworkConfigRequest() })) as GetNetworkConfigResponse; this.handleNetworkConfigResponse(response); } } catch (reason: any) { - this.service.toast(this.translate.instant('Edge.Network.errorReading') + reason?.error?.message ?? 'Unknown error', 'danger'); + this.service.toast(this.translate.instant("Edge.Network.errorReading") + reason?.error?.message ?? "Unknown error", "danger"); } } @@ -119,10 +119,10 @@ export class NetworkComponent implements OnInit { if (iface.model.addressesList) { for (const addr of iface.model.addressesList) { if (!this.ipRegex.test(addr)) { - this.service.toast(this.translate.instant('Edge.Network.validAddressWarning'), 'danger'); + this.service.toast(this.translate.instant("Edge.Network.validAddressWarning"), "danger"); return []; } - const [address, subnet] = addr.split('/'); + const [address, subnet] = addr.split("/"); const subnetmask = NetworkUtils.getSubnetmaskAsString(Number.parseInt(subnet)); addressJson.push({ @@ -182,12 +182,12 @@ export class NetworkComponent implements OnInit { private async sendRequest(interfaceName: string, request: NetworkConfig): Promise { try { await this.edge?.sendRequest(this.websocket, new ComponentJsonApiRequest({ - componentId: '_host', + componentId: "_host", payload: new SetNetworkConfigRequest(request), })); - this.service.toast(this.translate.instant('Edge.Network.successUpdate') + `[${interfaceName}].`, 'success'); + this.service.toast(this.translate.instant("Edge.Network.successUpdate") + `[${interfaceName}].`, "success"); } catch (reason: any) { - this.service.toast(this.translate.instant('Edge.Network.errorUpdating') + `[${interfaceName}].` + reason?.error?.message ?? 'Unknown error', 'danger'); + this.service.toast(this.translate.instant("Edge.Network.errorUpdating") + `[${interfaceName}].` + reason?.error?.message ?? "Unknown error", "danger"); } } @@ -211,7 +211,7 @@ export class NetworkComponent implements OnInit { } else { // Converts ip:"192.168.1.50" and subnetmask:"255.255.255.0" -> ["192.168.1.50/24"] const cidr: number = NetworkUtils.getCidrFromSubnetmask(address.subnetmask); - const ip: string = address.address.concat('/' + cidr.toString()); + const ip: string = address.address.concat("/" + cidr.toString()); addressArray.push(ip); } } @@ -238,100 +238,100 @@ export class NetworkComponent implements OnInit { private fillFields(addressArray: string[]): FormlyFieldConfig[] { const fields: FormlyFieldConfig[] = [ { - key: 'dhcp', - type: 'checkbox', + key: "dhcp", + type: "checkbox", defaultValue: true, templateOptions: { - label: 'DHCP', + label: "DHCP", }, }, { - hideExpression: 'model.dhcp', - key: 'ip', - type: 'input', + hideExpression: "model.dhcp", + key: "ip", + type: "input", resetOnHide: false, templateOptions: { - label: this.translate.instant('Edge.Network.ipAddress'), - placeholder: 'z.B. 192.168.0.50', + label: this.translate.instant("Edge.Network.ipAddress"), + placeholder: "z.B. 192.168.0.50", required: true, }, validators: { - validation: ['ip'], + validation: ["ip"], }, }, { - hideExpression: 'model.dhcp', - key: 'subnetmask', - type: 'input', + hideExpression: "model.dhcp", + key: "subnetmask", + type: "input", resetOnHide: false, templateOptions: { - label: this.translate.instant('Edge.Network.subnetmask'), - placeholder: 'z.B. 255.255.255.0', + label: this.translate.instant("Edge.Network.subnetmask"), + placeholder: "z.B. 255.255.255.0", required: true, }, validators: { - validation: ['subnetmask'], + validation: ["subnetmask"], }, }, { - hideExpression: 'model.dhcp', - key: 'gateway', - type: 'input', + hideExpression: "model.dhcp", + key: "gateway", + type: "input", resetOnHide: false, templateOptions: { - label: 'Gateway', - placeholder: 'z.B. 192.168.0.1', + label: "Gateway", + placeholder: "z.B. 192.168.0.1", required: true, }, validators: { - validation: ['ip'], + validation: ["ip"], }, }, { - hideExpression: 'model.dhcp', - key: 'dns', - type: 'input', + hideExpression: "model.dhcp", + key: "dns", + type: "input", resetOnHide: false, templateOptions: { - label: 'DNS-Server', - placeholder: 'z.B. 192.168.0.1', + label: "DNS-Server", + placeholder: "z.B. 192.168.0.1", required: true, }, validators: { - validation: ['ip'], + validation: ["ip"], }, }, { - key: 'linkLocalAddressing', - type: 'checkbox', + key: "linkLocalAddressing", + type: "checkbox", resetOnHide: false, templateOptions: { - label: 'Link-Local Address (z. B. 169.254.XXX.XXX)', + label: "Link-Local Address (z. B. 169.254.XXX.XXX)", }, hide: true, }, { hide: true, - key: 'addressesList', - type: 'repeat', + key: "addressesList", + type: "repeat", resetOnHide: false, defaultValue: addressArray, templateOptions: { - label: this.translate.instant('Edge.Network.addIP'), + label: this.translate.instant("Edge.Network.addIP"), }, fieldArray: { - type: 'input', + type: "input", resetOnHide: false, }, }, { hide: true, - key: 'metric', - type: 'input', + key: "metric", + type: "input", resetOnHide: false, templateOptions: { - label: 'Metric', - placeholder: 'z.B. 512, 1024 ...', + label: "Metric", + placeholder: "z.B. 512, 1024 ...", }, defaultValue: 1024, parsers: [Number], diff --git a/ui/src/app/edge/settings/network/setNetworkConfigRequest.ts b/ui/src/app/edge/settings/network/setNetworkConfigRequest.ts index 71d4d613978..1d8f361de36 100644 --- a/ui/src/app/edge/settings/network/setNetworkConfigRequest.ts +++ b/ui/src/app/edge/settings/network/setNetworkConfigRequest.ts @@ -1,5 +1,5 @@ import { JsonrpcRequest } from "../../../shared/jsonrpc/base"; -import { NetworkConfig } from './shared'; +import { NetworkConfig } from "./shared"; /** * Represents a JSON-RPC Request for 'setNetworkConfig': Updates the current network configuration. diff --git a/ui/src/app/edge/settings/network/shared.ts b/ui/src/app/edge/settings/network/shared.ts index 911c82bc03b..059514e8ebc 100644 --- a/ui/src/app/edge/settings/network/shared.ts +++ b/ui/src/app/edge/settings/network/shared.ts @@ -56,7 +56,7 @@ export namespace NetworkUtils { octets.push(256 - Math.pow(2, 8 - bits)); cidr -= bits; } - return octets.join('.'); + return octets.join("."); } /** @@ -73,12 +73,12 @@ export namespace NetworkUtils { export function getCidrFromSubnetmask(subnetmask: string): number { // Split the subnet mask into its octets, convert them to binary, and join the binary strings const binaryString = subnetmask - .split('.') + .split(".") .map(Number) - .map(part => (part >>> 0).toString(2).padStart(8, '0')) // Ensure each part is represented as 8 bits - .join(''); + .map(part => (part >>> 0).toString(2).padStart(8, "0")) // Ensure each part is represented as 8 bits + .join(""); // return the number of '1's in the binary string to get the CIDR notation - return binaryString.split('1').length - 1; + return binaryString.split("1").length - 1; } } diff --git a/ui/src/app/edge/settings/powerassistant/powerassistant.ts b/ui/src/app/edge/settings/powerassistant/powerassistant.ts index 8dfaabf14dd..4dcc5708141 100644 --- a/ui/src/app/edge/settings/powerassistant/powerassistant.ts +++ b/ui/src/app/edge/settings/powerassistant/powerassistant.ts @@ -1,10 +1,10 @@ // @ts-strict-ignore -import { formatNumber } from '@angular/common'; -import { Component } from '@angular/core'; -import { AbstractFlatWidget } from 'src/app/shared/components/flat/abstract-flat-widget'; -import { DataService } from 'src/app/shared/components/shared/dataservice'; -import { ChannelAddress, CurrentData, EdgeConfig, Utils } from '../../../shared/shared'; -import { LiveDataService } from '../../live/livedataservice'; +import { formatNumber } from "@angular/common"; +import { Component } from "@angular/core"; +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; +import { DataService } from "src/app/shared/components/shared/dataservice"; +import { ChannelAddress, CurrentData, EdgeConfig, Utils } from "../../../shared/shared"; +import { LiveDataService } from "../../live/livedataservice"; type Channel = { title: string, @@ -28,8 +28,8 @@ type Entry = { }; @Component({ - selector: 'powerassistant', - templateUrl: './powerassistant.html', + selector: "powerassistant", + templateUrl: "./powerassistant.html", providers: [{ useClass: LiveDataService, provide: DataService, @@ -97,7 +97,7 @@ export class PowerAssistantComponent extends AbstractFlatWidget { if (ess.factoryId === "Ess.Generic.ManagedSymmetric") { // Create optional Battery Component const battery = this.config.components[ess.properties["battery.id"]]; - result['battery'] = { + result["battery"] = { id: battery.id, alias: battery.alias, factoryId: battery.factoryId, @@ -128,7 +128,7 @@ export class PowerAssistantComponent extends AbstractFlatWidget { }; // Create optional Battery-Inverter Component const batteryInverter = this.config.components[ess.properties["batteryInverter.id"]]; - result['batteryInverter'] = { + result["batteryInverter"] = { id: batteryInverter.id, alias: batteryInverter.alias, factoryId: batteryInverter.factoryId, @@ -222,9 +222,9 @@ export namespace Converter { export function unit(unit: string): (value: any) => string { return function (value: any): string { if (value == null) { - return '-'; + return "-"; } else if (value >= 0) { - return formatNumber(value, 'de', '1.0-0') + ' ' + unit; + return formatNumber(value, "de", "1.0-0") + " " + unit; } }; } @@ -232,7 +232,7 @@ export namespace Converter { export function enabled(): (value: any) => string { return function (value: any): string { if (value == null) { - return '-'; + return "-"; } else if (value == 1) { return "Enabled"; } else { diff --git a/ui/src/app/edge/settings/profile/aliasupdate.component.ts b/ui/src/app/edge/settings/profile/aliasupdate.component.ts index 528d653b9da..d0b91e080ca 100644 --- a/ui/src/app/edge/settings/profile/aliasupdate.component.ts +++ b/ui/src/app/edge/settings/profile/aliasupdate.component.ts @@ -1,13 +1,13 @@ // @ts-strict-ignore -import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup } from '@angular/forms'; -import { ActivatedRoute } from '@angular/router'; -import { TranslateService } from '@ngx-translate/core'; -import { Edge, EdgeConfig, Service, Websocket } from 'src/app/shared/shared'; +import { Component, OnInit } from "@angular/core"; +import { FormBuilder, FormControl, FormGroup } from "@angular/forms"; +import { ActivatedRoute } from "@angular/router"; +import { TranslateService } from "@ngx-translate/core"; +import { Edge, EdgeConfig, Service, Websocket } from "src/app/shared/shared"; @Component({ - selector: 'aliasupdate', - templateUrl: './aliasupdate.component.html', + selector: "aliasupdate", + templateUrl: "./aliasupdate.component.html", }) export class AliasUpdateComponent implements OnInit { @@ -28,7 +28,7 @@ export class AliasUpdateComponent implements OnInit { ) { } ngOnInit() { - this.service.setCurrentComponent({ languageKey: 'Edge.Config.Index.renameComponents' }, this.route).then(edge => { + this.service.getCurrentEdge().then(edge => { this.edge = edge; }); this.service.getConfig().then(config => { @@ -46,16 +46,16 @@ export class AliasUpdateComponent implements OnInit { const newAlias = alias; if (this.edge != null) { if (this.component.id == newAlias) { - this.service.toast(this.translate.instant('General.inputNotValid'), 'danger'); + this.service.toast(this.translate.instant("General.inputNotValid"), "danger"); } else { this.edge.updateComponentConfig(this.websocket, this.component.id, [ - { name: 'alias', value: newAlias }, + { name: "alias", value: newAlias }, ]).then(() => { this.formGroup.markAsPristine(); - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); + this.service.toast(this.translate.instant("General.changeAccepted"), "success"); }).catch(reason => { this.formGroup.markAsPristine(); - this.service.toast(this.translate.instant('General.changeFailed') + '\n' + reason.error.message, 'danger'); + this.service.toast(this.translate.instant("General.changeFailed") + "\n" + reason.error.message, "danger"); console.warn(reason); }); } diff --git a/ui/src/app/edge/settings/profile/channelexport/channelExportXlsxRequest.ts b/ui/src/app/edge/settings/profile/channelexport/channelExportXlsxRequest.ts index 215dfa96925..90475f77f87 100644 --- a/ui/src/app/edge/settings/profile/channelexport/channelExportXlsxRequest.ts +++ b/ui/src/app/edge/settings/profile/channelexport/channelExportXlsxRequest.ts @@ -1,4 +1,4 @@ -import { JsonrpcRequest } from '../../../../shared/jsonrpc/base'; +import { JsonrpcRequest } from "../../../../shared/jsonrpc/base"; /** * Exports Channels with current value and metadata to an Excel (xlsx) file. diff --git a/ui/src/app/edge/settings/profile/modbusapi/getModbusProtocolExportXlsxRequest.ts b/ui/src/app/edge/settings/profile/modbusapi/getModbusProtocolExportXlsxRequest.ts index c67d1cafc52..3c691621f86 100644 --- a/ui/src/app/edge/settings/profile/modbusapi/getModbusProtocolExportXlsxRequest.ts +++ b/ui/src/app/edge/settings/profile/modbusapi/getModbusProtocolExportXlsxRequest.ts @@ -1,4 +1,4 @@ -import { JsonrpcRequest } from '../../../../shared/jsonrpc/base'; +import { JsonrpcRequest } from "../../../../shared/jsonrpc/base"; /** * Wraps a JSON-RPC Request to query the Modbus Protocol from Modbus/TCP diff --git a/ui/src/app/edge/settings/profile/modbusapi/getModbusProtocolRequest.ts b/ui/src/app/edge/settings/profile/modbusapi/getModbusProtocolRequest.ts index b0dbbcc8cdf..bab6ea90dc1 100644 --- a/ui/src/app/edge/settings/profile/modbusapi/getModbusProtocolRequest.ts +++ b/ui/src/app/edge/settings/profile/modbusapi/getModbusProtocolRequest.ts @@ -1,4 +1,4 @@ -import { JsonrpcRequest } from '../../../../shared/jsonrpc/base'; +import { JsonrpcRequest } from "../../../../shared/jsonrpc/base"; /** * Wraps a JSON-RPC Request to query the Modbus Protocol from Modbus/TCP diff --git a/ui/src/app/edge/settings/profile/modbusapi/getModbusProtocolResponse.ts b/ui/src/app/edge/settings/profile/modbusapi/getModbusProtocolResponse.ts index cc25ca0bbb9..56cea28bb6b 100644 --- a/ui/src/app/edge/settings/profile/modbusapi/getModbusProtocolResponse.ts +++ b/ui/src/app/edge/settings/profile/modbusapi/getModbusProtocolResponse.ts @@ -1,4 +1,4 @@ -import { JsonrpcResponseSuccess } from '../../../../shared/jsonrpc/base'; +import { JsonrpcResponseSuccess } from "../../../../shared/jsonrpc/base"; /** * Wraps a JSON-RPC Response to "getModbusProtocol" Request diff --git a/ui/src/app/edge/settings/profile/profile.component.ts b/ui/src/app/edge/settings/profile/profile.component.ts index a6ca6b3a0f5..f33d018f26a 100644 --- a/ui/src/app/edge/settings/profile/profile.component.ts +++ b/ui/src/app/edge/settings/profile/profile.component.ts @@ -1,19 +1,19 @@ -import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { PopoverController } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; -import { CategorizedComponents } from 'src/app/shared/components/edge/edgeconfig'; -import { JsonrpcResponseError } from 'src/app/shared/jsonrpc/base'; -import { ComponentJsonApiRequest } from 'src/app/shared/jsonrpc/request/componentJsonApiRequest'; -import { Base64PayloadResponse } from 'src/app/shared/jsonrpc/response/base64PayloadResponse'; -import { environment } from '../../../../environments'; -import { ChannelAddress, Edge, EdgeConfig, Service, Utils } from '../../../shared/shared'; -import { ChannelExportXlsxRequest } from './channelexport/channelExportXlsxRequest'; -import { GetModbusProtocolExportXlsxRequest } from './modbusapi/getModbusProtocolExportXlsxRequest'; +import { Component, OnInit } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { PopoverController } from "@ionic/angular"; +import { TranslateService } from "@ngx-translate/core"; +import { CategorizedComponents } from "src/app/shared/components/edge/edgeconfig"; +import { JsonrpcResponseError } from "src/app/shared/jsonrpc/base"; +import { ComponentJsonApiRequest } from "src/app/shared/jsonrpc/request/componentJsonApiRequest"; +import { Base64PayloadResponse } from "src/app/shared/jsonrpc/response/base64PayloadResponse"; +import { environment } from "../../../../environments"; +import { ChannelAddress, Edge, EdgeConfig, Service, Utils } from "../../../shared/shared"; +import { ChannelExportXlsxRequest } from "./channelexport/channelExportXlsxRequest"; +import { GetModbusProtocolExportXlsxRequest } from "./modbusapi/getModbusProtocolExportXlsxRequest"; @Component({ selector: ProfileComponent.SELECTOR, - templateUrl: './profile.component.html', + templateUrl: "./profile.component.html", }) export class ProfileComponent implements OnInit { @@ -35,7 +35,7 @@ export class ProfileComponent implements OnInit { ) { } public ngOnInit() { - this.service.setCurrentComponent({ languageKey: 'Edge.Config.Index.systemProfile' }, this.route).then(edge => { + this.service.getCurrentEdge().then(edge => { this.edge = edge; this.service.getConfig().then(config => { this.config = config; @@ -51,14 +51,14 @@ export class ProfileComponent implements OnInit { edge.sendRequest(this.service.websocket, request).then(response => { Utils.downloadXlsx(response as Base64PayloadResponse, "Modbus-TCP-" + edge.id); }).catch(reason => { - this.service.toast(this.translate.instant('Edge.Config.PROFILE.ERROR_DOWNLOADING_MODBUS_PROTOCOL') + ": " + (reason as JsonrpcResponseError).error.message, 'danger'); + this.service.toast(this.translate.instant("Edge.Config.PROFILE.ERROR_DOWNLOADING_MODBUS_PROTOCOL") + ": " + (reason as JsonrpcResponseError).error.message, "danger"); }); }); } public getChannelExport(componentId: string) { this.service.getCurrentEdge().then(edge => { - const request = new ComponentJsonApiRequest({ componentId: '_componentManager', payload: new ChannelExportXlsxRequest({ componentId: componentId }) }); + const request = new ComponentJsonApiRequest({ componentId: "_componentManager", payload: new ChannelExportXlsxRequest({ componentId: componentId }) }); edge.sendRequest(this.service.websocket, request).then(response => { Utils.downloadXlsx(response as Base64PayloadResponse, "ChannelExport-" + edge.id + "-" + componentId); }).catch(reason => { diff --git a/ui/src/app/edge/settings/settings.component.ts b/ui/src/app/edge/settings/settings.component.ts index 58f3666e896..8c667833490 100644 --- a/ui/src/app/edge/settings/settings.component.ts +++ b/ui/src/app/edge/settings/settings.component.ts @@ -1,13 +1,13 @@ -import { Component, OnInit } from '@angular/core'; -import { TranslateService } from '@ngx-translate/core'; -import { Role } from 'src/app/shared/type/role'; -import { environment } from 'src/environments'; -import { Edge, Service, Utils } from '../../shared/shared'; -import { JsonrpcTestPermission } from './jsonrpctest/jsonrpctest.permission'; +import { Component, OnInit } from "@angular/core"; +import { TranslateService } from "@ngx-translate/core"; +import { Role } from "src/app/shared/type/role"; +import { environment } from "src/environments"; +import { Edge, Service, Utils } from "../../shared/shared"; +import { JsonrpcTestPermission } from "./jsonrpctest/jsonrpctest.permission"; @Component({ - selector: 'settings', - templateUrl: './settings.component.html', + selector: "settings", + templateUrl: "./settings.component.html", }) export class SettingsComponent implements OnInit { @@ -19,7 +19,7 @@ export class SettingsComponent implements OnInit { public isAtLeastAdmin: boolean = false; public canSeeJsonrpcTest: boolean = false; - protected isEdgeBackend: boolean = environment.backend === 'OpenEMS Edge'; + protected isEdgeBackend: boolean = environment.backend === "OpenEMS Edge"; constructor( protected utils: Utils, diff --git a/ui/src/app/edge/settings/settings.module.ts b/ui/src/app/edge/settings/settings.module.ts index a04474e871e..3e12f05e109 100644 --- a/ui/src/app/edge/settings/settings.module.ts +++ b/ui/src/app/edge/settings/settings.module.ts @@ -1,24 +1,24 @@ -import { NgModule } from '@angular/core'; -import { ChangelogModule } from 'src/app/changelog/changelog.module'; +import { NgModule } from "@angular/core"; +import { ChangelogModule } from "src/app/changelog/changelog.module"; -import { SharedModule } from './../../shared/shared.module'; -import { AlertingComponent } from './alerting/alerting.component'; -import { AppModule } from './app/app.module'; -import { ChannelsComponent } from './channels/channels.component'; -import { IndexComponent as ComponentInstallIndexComponent } from './component/install/index.component'; -import { ComponentInstallComponent } from './component/install/install.component'; -import { IndexComponent as ComponentUpdateIndexComponent } from './component/update/index.component'; -import { ComponentUpdateComponent } from './component/update/update.component'; -import { JsonrpcTestComponent } from './jsonrpctest/jsonrpctest'; -import { NetworkComponent } from './network/network.component'; -import { PowerAssistantModule } from './powerassistant/powerassistant.module'; -import { AliasUpdateComponent } from './profile/aliasupdate.component'; -import { ProfileComponent } from './profile/profile.component'; -import { SettingsComponent } from './settings.component'; -import { MaintenanceComponent } from './system/maintenance/maintenance'; -import { OeSystemUpdateComponent } from './system/oe-system-update.component'; -import { SystemComponent } from './system/system.component'; -import { SystemExecuteComponent } from './systemexecute/systemexecute.component'; +import { SharedModule } from "./../../shared/shared.module"; +import { AlertingComponent } from "./alerting/alerting.component"; +import { AppModule } from "./app/app.module"; +import { ChannelsComponent } from "./channels/channels.component"; +import { IndexComponent as ComponentInstallIndexComponent } from "./component/install/index.component"; +import { ComponentInstallComponent } from "./component/install/install.component"; +import { IndexComponent as ComponentUpdateIndexComponent } from "./component/update/index.component"; +import { ComponentUpdateComponent } from "./component/update/update.component"; +import { JsonrpcTestComponent } from "./jsonrpctest/jsonrpctest"; +import { NetworkComponent } from "./network/network.component"; +import { PowerAssistantModule } from "./powerassistant/powerassistant.module"; +import { AliasUpdateComponent } from "./profile/aliasupdate.component"; +import { ProfileComponent } from "./profile/profile.component"; +import { SettingsComponent } from "./settings.component"; +import { MaintenanceComponent } from "./system/maintenance/maintenance"; +import { OeSystemUpdateComponent } from "./system/oe-system-update.component"; +import { SystemComponent } from "./system/system.component"; +import { SystemExecuteComponent } from "./systemexecute/systemexecute.component"; @NgModule({ imports: [ diff --git a/ui/src/app/edge/settings/settings.spec.ts b/ui/src/app/edge/settings/settings.spec.ts index d46eb0e7ca5..e53b68e6ec4 100644 --- a/ui/src/app/edge/settings/settings.spec.ts +++ b/ui/src/app/edge/settings/settings.spec.ts @@ -1,7 +1,7 @@ // @ts-strict-ignore import { registerLocaleData } from "@angular/common"; -import localDE from '@angular/common/locales/de'; -import localeDeExtra from '@angular/common/locales/extra/de'; +import localDE from "@angular/common/locales/de"; +import localeDeExtra from "@angular/common/locales/extra/de"; import { LOCALE_ID } from "@angular/core"; import { TestBed } from "@angular/core/testing"; import { FORMLY_CONFIG } from "@ngx-formly/core"; @@ -14,11 +14,11 @@ import { Role } from "src/app/shared/type/role"; import { registerTranslateExtension } from "./app/app.module"; import { SettingsComponent } from "./settings.component"; -describe('Edge', () => { - const serviceSypObject = jasmine.createSpyObj('Service', ['getCurrentEdge'], { +describe("Edge", () => { + const serviceSypObject = jasmine.createSpyObj("Service", ["getCurrentEdge"], { metadata: new BehaviorSubject({ edges: null, - user: { globalRole: 'admin', hasMultipleEdges: true, id: '', language: Language.DE.key, name: 'test.user', settings: {} }, + user: { globalRole: "admin", hasMultipleEdges: true, id: "", language: Language.DE.key, name: "test.user", settings: {} }, }), }); @@ -37,15 +37,15 @@ describe('Edge', () => { ], }).compileComponents().then(() => { const translateService = TestBed.inject(TranslateService); - translateService.addLangs(['de']); - translateService.use('de'); - registerLocaleData(localDE, 'de', localeDeExtra); + translateService.addLangs(["de"]); + translateService.use("de"); + registerLocaleData(localDE, "de", localeDeExtra); settingsComponent = new SettingsComponent(Utils, serviceSypObject, translateService); }); }); - it('+ngOnInit - Role.ADMIN', async () => { + it("+ngOnInit - Role.ADMIN", async () => { const result = await expectNgOnInit(serviceSypObject, Role.ADMIN, settingsComponent); expect(result).toEqual({ isAtLeastOwner: true, @@ -53,7 +53,7 @@ describe('Edge', () => { isAtLeastAdmin: true, }); }); - it('+ngOnInit - Role.INSTALLER', async () => { + it("+ngOnInit - Role.INSTALLER", async () => { const result = await expectNgOnInit(serviceSypObject, Role.INSTALLER, settingsComponent); expect(result).toEqual({ isAtLeastOwner: true, @@ -61,7 +61,7 @@ describe('Edge', () => { isAtLeastAdmin: false, }); }); - it('+ngOnInit - Role.OWNER', async () => { + it("+ngOnInit - Role.OWNER", async () => { const result = await expectNgOnInit(serviceSypObject, Role.OWNER, settingsComponent); expect(result).toEqual({ isAtLeastOwner: true, @@ -76,7 +76,7 @@ export async function expectNgOnInit(serviceSypObject: jasmine.SpyObj, serviceSypObject.getCurrentEdge.and.resolveTo(edge); serviceSypObject.metadata.next({ edges: { [edge.id]: edge }, - user: { globalRole: 'admin', hasMultipleEdges: true, id: '', language: Language.DE.key, name: 'test.user', settings: {} }, + user: { globalRole: "admin", hasMultipleEdges: true, id: "", language: Language.DE.key, name: "test.user", settings: {} }, }); await settingsComponent.ngOnInit(); return { diff --git a/ui/src/app/edge/settings/system/executesystemupdate.component.ts b/ui/src/app/edge/settings/system/executesystemupdate.component.ts index 7aed9eef8b7..badb135f909 100644 --- a/ui/src/app/edge/settings/system/executesystemupdate.component.ts +++ b/ui/src/app/edge/settings/system/executesystemupdate.component.ts @@ -1,13 +1,13 @@ // @ts-strict-ignore -import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'; -import { Edge, Service, Websocket } from 'src/app/shared/shared'; -import { environment } from 'src/environments'; -import { ExecuteSystemUpdate } from './executeSystemUpdate'; -import { SystemUpdateState } from './getSystemUpdateStateResponse'; +import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from "@angular/core"; +import { Edge, Service, Websocket } from "src/app/shared/shared"; +import { environment } from "src/environments"; +import { ExecuteSystemUpdate } from "./executeSystemUpdate"; +import { SystemUpdateState } from "./getSystemUpdateStateResponse"; @Component({ selector: ExecuteSystemUpdateComponent.SELECTOR, - templateUrl: './executesystemupdate.component.html', + templateUrl: "./executesystemupdate.component.html", }) export class ExecuteSystemUpdateComponent implements OnInit, OnDestroy { diff --git a/ui/src/app/edge/settings/system/maintenance/maintenance.ts b/ui/src/app/edge/settings/system/maintenance/maintenance.ts index 6964d2461ec..cda8f1e81d6 100644 --- a/ui/src/app/edge/settings/system/maintenance/maintenance.ts +++ b/ui/src/app/edge/settings/system/maintenance/maintenance.ts @@ -1,15 +1,15 @@ // @ts-strict-ignore -import { Component, OnInit } from '@angular/core'; -import { AlertController } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; -import { BehaviorSubject, Subscription } from 'rxjs'; -import { skip } from 'rxjs/operators'; -import { ComponentJsonApiRequest } from 'src/app/shared/jsonrpc/request/componentJsonApiRequest'; -import { ExecuteSystemRestartRequest, Type } from 'src/app/shared/jsonrpc/request/executeSystemRestartRequest'; -import { Role } from 'src/app/shared/type/role'; -import { environment } from 'src/environments'; - -import { Edge, presentAlert, Service, Utils, Websocket } from '../../../../shared/shared'; +import { Component, OnInit } from "@angular/core"; +import { AlertController } from "@ionic/angular"; +import { TranslateService } from "@ngx-translate/core"; +import { BehaviorSubject, Subscription } from "rxjs"; +import { skip } from "rxjs/operators"; +import { ComponentJsonApiRequest } from "src/app/shared/jsonrpc/request/componentJsonApiRequest"; +import { ExecuteSystemRestartRequest, Type } from "src/app/shared/jsonrpc/request/executeSystemRestartRequest"; +import { Role } from "src/app/shared/type/role"; +import { environment } from "src/environments"; + +import { Edge, presentAlert, Service, Utils, Websocket } from "../../../../shared/shared"; enum SystemRestartState { INITIAL, // No restart @@ -20,10 +20,10 @@ enum SystemRestartState { @Component({ selector: MaintenanceComponent.SELECTOR, - templateUrl: './maintenance.html', + templateUrl: "./maintenance.html", styles: [` :host { - ion-card: { + :is(ion-card) { cursor: auto !important;; } } @@ -31,16 +31,16 @@ enum SystemRestartState { }) export class MaintenanceComponent implements OnInit { - private static readonly SELECTOR: string = 'oe-maintenance'; + private static readonly SELECTOR: string = "oe-maintenance"; private static readonly TIMEOUT: number = 3000; protected readonly environment = environment; protected edge: Edge | null = null; - protected options: { key: string, message: string, color: 'success' | 'warning' | null, info: string, roleIsAtLeast: Role, button: { disabled: boolean, label: string, callback: () => void } }[] = [ + protected options: { key: string, message: string, color: "success" | "warning" | null, info: string, roleIsAtLeast: Role, button: { disabled: boolean, label: string, callback: () => void } }[] = [ { - key: Type.HARD, message: null, color: null, info: this.translate.instant('SETTINGS.SYSTEM_UPDATE.RESTART_WARNING', { system: environment.edgeShortName }), roleIsAtLeast: Role.OWNER, button: { - callback: () => this.confirmationAlert(Type.HARD), disabled: false, label: this.translate.instant('SETTINGS.SYSTEM_UPDATE.EMS_RESTARTING', { edgeShortName: environment.edgeShortName }), + key: Type.HARD, message: null, color: null, info: this.translate.instant("SETTINGS.SYSTEM_UPDATE.RESTART_WARNING", { system: environment.edgeShortName }), roleIsAtLeast: Role.OWNER, button: { + callback: () => this.confirmationAlert(Type.HARD), disabled: false, label: this.translate.instant("SETTINGS.SYSTEM_UPDATE.EMS_RESTARTING", { edgeShortName: environment.edgeShortName }), }, }, ]; @@ -62,19 +62,19 @@ export class MaintenanceComponent implements OnInit { */ async presentAlert(type: Type) { const translate = this.translate; - const system = type === Type.HARD ? environment.edgeShortName : 'OpenEMS'; + const system = type === Type.HARD ? environment.edgeShortName : "OpenEMS"; const alert = this.alertCtrl.create({ - subHeader: translate.instant('SETTINGS.SYSTEM_UPDATE.RESTART_CONFIRMATION', { system: system }), - message: translate.instant('SETTINGS.SYSTEM_UPDATE.RESTART_WARNING', { system: system }), + subHeader: translate.instant("SETTINGS.SYSTEM_UPDATE.RESTART_CONFIRMATION", { system: system }), + message: translate.instant("SETTINGS.SYSTEM_UPDATE.RESTART_WARNING", { system: system }), buttons: [{ - text: translate.instant('General.cancel'), - role: 'cancel', + text: translate.instant("General.cancel"), + role: "cancel", }, { - text: translate.instant('General.RESTART'), + text: translate.instant("General.RESTART"), handler: () => this.execRestart(type), }], - cssClass: 'alertController', + cssClass: "alertController", }); (await alert).present(); } @@ -98,10 +98,10 @@ export class MaintenanceComponent implements OnInit { } protected confirmationAlert: (type: Type) => void = (type: Type) => presentAlert(this.alertCtrl, this.translate, { - message: this.translate.instant('SETTINGS.SYSTEM_UPDATE.RESTART_WARNING', { system: environment.edgeShortName }), - subHeader: this.translate.instant('SETTINGS.SYSTEM_UPDATE.RESTART_CONFIRMATION', { system: environment.edgeShortName }), + message: this.translate.instant("SETTINGS.SYSTEM_UPDATE.RESTART_WARNING", { system: environment.edgeShortName }), + subHeader: this.translate.instant("SETTINGS.SYSTEM_UPDATE.RESTART_CONFIRMATION", { system: environment.edgeShortName }), buttons: [{ - text: this.translate.instant('General.RESTART'), + text: this.translate.instant("General.RESTART"), handler: () => this.execRestart(type), }], }); @@ -115,13 +115,13 @@ export class MaintenanceComponent implements OnInit { let message: string | null = null; let disableButtons: boolean = false; let showInfo: boolean = false; - let color: 'warning' | 'success' | null = null; - const system = type === Type.HARD ? environment.edgeShortName : this.translate.instant('General.SYSTEM'); + let color: "warning" | "success" | null = null; + const system = type === Type.HARD ? environment.edgeShortName : this.translate.instant("General.SYSTEM"); switch (this.systemRestartState?.value?.state) { case SystemRestartState.FAILED: message = this.translate.instant("SETTINGS.SYSTEM_UPDATE.RESTART_FAILED", { system: system }); - color = 'warning'; + color = "warning"; disableButtons = false; showInfo = true; break; @@ -134,10 +134,13 @@ export class MaintenanceComponent implements OnInit { case SystemRestartState.RESTARTED: this.service.stopSpinner(this.spinnerId + type); disableButtons = false; - color = 'success'; + color = "success"; message = this.translate.instant("SETTINGS.SYSTEM_UPDATE.RESTARTED", { system: system }); showInfo = true; break; + default: + break; + } if (!message) { @@ -151,7 +154,7 @@ export class MaintenanceComponent implements OnInit { // Hide and show buttons option.button.disabled = disableButtons ? disableButtons : !this.edge.roleIsAtLeast(option.roleIsAtLeast); option.color = color; - option.info = showInfo ? this.translate.instant('SETTINGS.SYSTEM_UPDATE.RESTART_WARNING', { system: environment.edgeShortName }) : null; + option.info = showInfo ? this.translate.instant("SETTINGS.SYSTEM_UPDATE.RESTART_WARNING", { system: environment.edgeShortName }) : null; return option; }); } @@ -163,7 +166,7 @@ export class MaintenanceComponent implements OnInit { */ private execRestart(type: Type) { - const request = new ComponentJsonApiRequest({ componentId: '_host', payload: new ExecuteSystemRestartRequest({ type: type }) }); + const request = new ComponentJsonApiRequest({ componentId: "_host", payload: new ExecuteSystemRestartRequest({ type: type }) }); // Workaround, there could be no response this.edge.sendRequest(this.websocket, request).catch(() => { diff --git a/ui/src/app/edge/settings/system/oe-system-update.component.ts b/ui/src/app/edge/settings/system/oe-system-update.component.ts index 2e547e5a9a2..b721f60aa44 100644 --- a/ui/src/app/edge/settings/system/oe-system-update.component.ts +++ b/ui/src/app/edge/settings/system/oe-system-update.component.ts @@ -1,15 +1,15 @@ // @ts-strict-ignore -import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'; -import { AlertController } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; -import { Edge, presentAlert, Service, Websocket } from 'src/app/shared/shared'; -import { environment } from 'src/environments'; -import { ExecuteSystemUpdate } from './executeSystemUpdate'; -import { SystemUpdateState } from './getSystemUpdateStateResponse'; +import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from "@angular/core"; +import { AlertController } from "@ionic/angular"; +import { TranslateService } from "@ngx-translate/core"; +import { Edge, presentAlert, Service, Websocket } from "src/app/shared/shared"; +import { environment } from "src/environments"; +import { ExecuteSystemUpdate } from "./executeSystemUpdate"; +import { SystemUpdateState } from "./getSystemUpdateStateResponse"; @Component({ selector: OeSystemUpdateComponent.SELECTOR, - templateUrl: './oe-system-update.component.html', + templateUrl: "./oe-system-update.component.html", }) export class OeSystemUpdateComponent implements OnInit, OnDestroy { @@ -67,10 +67,10 @@ export class OeSystemUpdateComponent implements OnInit, OnDestroy { } protected confirmationAlert: () => void = () => presentAlert(this.alertCtrl, this.translate, { - message: this.translate.instant('SETTINGS.SYSTEM_UPDATE.WARNING', { system: environment.edgeShortName }), - subHeader: this.translate.instant('SETTINGS.SYSTEM_UPDATE.SUB_HEADER'), + message: this.translate.instant("SETTINGS.SYSTEM_UPDATE.WARNING", { system: environment.edgeShortName }), + subHeader: this.translate.instant("SETTINGS.SYSTEM_UPDATE.SUB_HEADER"), buttons: [{ - text: this.translate.instant('SETTINGS.SYSTEM_UPDATE.UPDATE_EXECUTE'), + text: this.translate.instant("SETTINGS.SYSTEM_UPDATE.UPDATE_EXECUTE"), handler: () => this.executeSystemUpdate(), }], }); diff --git a/ui/src/app/edge/settings/system/system.component.ts b/ui/src/app/edge/settings/system/system.component.ts index 11c23429957..e6398f41b90 100644 --- a/ui/src/app/edge/settings/system/system.component.ts +++ b/ui/src/app/edge/settings/system/system.component.ts @@ -1,12 +1,12 @@ // @ts-strict-ignore -import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { environment } from 'src/environments'; -import { Edge, Service, UserPermission, Utils } from '../../../shared/shared'; +import { Component, OnInit } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { environment } from "src/environments"; +import { Edge, Service, UserPermission, Utils } from "../../../shared/shared"; @Component({ selector: SystemComponent.SELECTOR, - templateUrl: './system.component.html', + templateUrl: "./system.component.html", }) export class SystemComponent implements OnInit { diff --git a/ui/src/app/edge/settings/systemexecute/systemexecute.component.ts b/ui/src/app/edge/settings/systemexecute/systemexecute.component.ts index 46f635743a7..174de06b640 100644 --- a/ui/src/app/edge/settings/systemexecute/systemexecute.component.ts +++ b/ui/src/app/edge/settings/systemexecute/systemexecute.component.ts @@ -1,24 +1,24 @@ // @ts-strict-ignore -import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup } from '@angular/forms'; -import { ActivatedRoute } from '@angular/router'; -import { FormlyFieldConfig, FormlyFormOptions } from '@ngx-formly/core'; -import { TranslateService } from '@ngx-translate/core'; -import { ComponentJsonApiRequest } from 'src/app/shared/jsonrpc/request/componentJsonApiRequest'; -import { ExecuteSystemCommandRequest } from 'src/app/shared/jsonrpc/request/executeCommandRequest'; -import { ExecuteSystemCommandResponse } from 'src/app/shared/jsonrpc/response/executeSystemCommandResponse'; -import { Service, Utils, Websocket } from '../../../shared/shared'; +import { Component, OnInit } from "@angular/core"; +import { FormBuilder, FormControl, FormGroup } from "@angular/forms"; +import { ActivatedRoute } from "@angular/router"; +import { FormlyFieldConfig, FormlyFormOptions } from "@ngx-formly/core"; +import { TranslateService } from "@ngx-translate/core"; +import { ComponentJsonApiRequest } from "src/app/shared/jsonrpc/request/componentJsonApiRequest"; +import { ExecuteSystemCommandRequest } from "src/app/shared/jsonrpc/request/executeCommandRequest"; +import { ExecuteSystemCommandResponse } from "src/app/shared/jsonrpc/response/executeSystemCommandResponse"; +import { Service, Utils, Websocket } from "../../../shared/shared"; type CommandFunction = (...args: (string | boolean | number)[]) => string; const COMMANDS: { [key: string]: CommandFunction; } = { - 'ping': (ip: string) => `ping -c4 ${ip}`, - 'openems-restart': () => "which at || DEBIAN_FRONTEND=noninteractive apt-get -y install at; echo 'systemctl restart openems' | at now", + "ping": (ip: string) => `ping -c4 ${ip}`, + "openems-restart": () => "which at || DEBIAN_FRONTEND=noninteractive apt-get -y install at; echo 'systemctl restart openems' | at now", }; @Component({ selector: SystemExecuteComponent.SELECTOR, - templateUrl: './systemexecute.component.html', + templateUrl: "./systemexecute.component.html", }) export class SystemExecuteComponent implements OnInit { @@ -34,17 +34,17 @@ export class SystemExecuteComponent implements OnInit { public model: any = {}; public options: FormlyFormOptions = {}; public fields: FormlyFieldConfig[] = [{ - key: 'predefined', - type: 'radio', - templateOptions: { options: [{ value: 'ping', label: 'Ping device in network' }] }, + key: "predefined", + type: "radio", + templateOptions: { options: [{ value: "ping", label: "Ping device in network" }] }, }, { - key: 'ping', - hideExpression: (model: any, formState: any) => this.model['predefined'] !== 'ping', + key: "ping", + hideExpression: (model: any, formState: any) => this.model["predefined"] !== "ping", fieldGroup: [{ - key: 'ip', - type: 'input', + key: "ip", + type: "input", templateOptions: { - label: 'IP-Address', placeholder: "192.168.0.1", required: true, pattern: /(\d{1,3}\.){3}\d{1,3}/, + label: "IP-Address", placeholder: "192.168.0.1", required: true, pattern: /(\d{1,3}\.){3}\d{1,3}/, }, validation: { messages: { @@ -53,11 +53,11 @@ export class SystemExecuteComponent implements OnInit { }, }], }, { - key: 'predefined', - type: 'radio', + key: "predefined", + type: "radio", templateOptions: { options: [ - { value: 'openems-restart', label: 'Restart OpenEMS Edge service' }, + { value: "openems-restart", label: "Restart OpenEMS Edge service" }, ], }, }]; @@ -73,7 +73,6 @@ export class SystemExecuteComponent implements OnInit { } ngOnInit() { - this.service.setCurrentComponent({ languageKey: 'Edge.Config.Index.systemExecute' }, this.route); this.form = this.formBuilder.group({ username: new FormControl("root"), password: new FormControl(""), @@ -99,15 +98,15 @@ export class SystemExecuteComponent implements OnInit { command = cmd(); } } - this.form.controls['command'].setValue(command); + this.form.controls["command"].setValue(command); } public submit() { - const username = this.form.controls['username']; - const password = this.form.controls['password']; - const timeoutSeconds = this.form.controls['timeoutSeconds']; - const runInBackground = this.form.controls['runInBackground']; - const command = this.form.controls['command']; + const username = this.form.controls["username"]; + const password = this.form.controls["password"]; + const timeoutSeconds = this.form.controls["timeoutSeconds"]; + const runInBackground = this.form.controls["runInBackground"]; + const command = this.form.controls["command"]; this.service.getCurrentEdge().then(edge => { this.loading = true; diff --git a/ui/src/app/edge/settings/systemlog/systemlog.component.ts b/ui/src/app/edge/settings/systemlog/systemlog.component.ts index 489f7c9bda2..8b2776a41a9 100644 --- a/ui/src/app/edge/settings/systemlog/systemlog.component.ts +++ b/ui/src/app/edge/settings/systemlog/systemlog.component.ts @@ -1,27 +1,27 @@ -import { Component, OnDestroy, OnInit } from '@angular/core'; -import { SelectCustomEvent } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; -import { parse } from 'date-fns'; -import { Subject } from 'rxjs'; -import { filter, take, takeUntil } from 'rxjs/operators'; -import { Filter } from 'src/app/index/filter/filter.component'; -import { Role } from 'src/app/shared/type/role'; -import { Service, Utils, Websocket } from '../../../shared/shared'; +import { Component, OnDestroy, OnInit } from "@angular/core"; +import { SelectCustomEvent } from "@ionic/angular"; +import { TranslateService } from "@ngx-translate/core"; +import { parse } from "date-fns"; +import { Subject } from "rxjs"; +import { filter, take, takeUntil } from "rxjs/operators"; +import { Filter } from "src/app/index/filter/filter.component"; +import { Role } from "src/app/shared/type/role"; +import { Service, Utils, Websocket } from "../../../shared/shared"; export const LOG_LEVEL_FILTER = (translate: TranslateService): Filter => ({ placeholder: translate.instant("Edge.Config.Log.level"), category: "level", options: [ { - name: 'Debug', + name: "Debug", value: "DEBUG", }, { - name: translate.instant('General.info'), + name: translate.instant("General.info"), value: "INFO", }, { - name: translate.instant('General.warning'), + name: translate.instant("General.warning"), value: "WARN", }, { @@ -33,12 +33,12 @@ export const LOG_LEVEL_FILTER = (translate: TranslateService): Filter => ({ @Component({ selector: SystemLogComponent.SELECTOR, - templateUrl: './systemlog.component.html', + templateUrl: "./systemlog.component.html", }) export class SystemLogComponent implements OnInit, OnDestroy { private static readonly SELECTOR = "systemLog"; - private static readonly DEBUG_LOG_CONTROLLER_ID = 'ctrlDebugLog0'; + private static readonly DEBUG_LOG_CONTROLLER_ID = "ctrlDebugLog0"; public isSubscribed: boolean = false; @@ -139,7 +139,7 @@ export class SystemLogComponent implements OnInit, OnDestroy { } public toggleSubscribe(event: CustomEvent) { - if (event.detail['checked']) { + if (event.detail["checked"]) { this.subscribe(); } else { this.unsubscribe(); @@ -159,11 +159,11 @@ export class SystemLogComponent implements OnInit, OnDestroy { this.service.currentEdge.pipe(filter(edge => !!edge), take(1)) .subscribe(edge => edge.updateComponentConfig(this.websocket, SystemLogComponent.DEBUG_LOG_CONTROLLER_ID, [{ - name: 'condensedOutput', value: event.detail['checked'], + name: "condensedOutput", value: event.detail["checked"], }]).then(() => { - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); + this.service.toast(this.translate.instant("General.changeAccepted"), "success"); }).catch((reason) => { - this.service.toast(this.translate.instant('General.changeFailed') + '\n' + reason.error.message, 'danger'); + this.service.toast(this.translate.instant("General.changeFailed") + "\n" + reason.error.message, "danger"); })); } @@ -181,18 +181,16 @@ export class SystemLogComponent implements OnInit, OnDestroy { this.filterLogs(); } - private getColor(level: 'INFO' | 'WARN' | 'DEBUG' | 'ERROR'): string { + private getColor(level: "INFO" | "WARN" | "DEBUG" | "ERROR"): string { switch (level) { - case 'INFO': - return 'green'; - case 'WARN': - return 'orange'; - case 'DEBUG': - return 'gray'; - case 'ERROR': - return 'red'; - default: - return 'black'; + case "INFO": + return "green"; + case "WARN": + return "orange"; + case "DEBUG": + return "gray"; + case "ERROR": + return "red"; } } @@ -216,7 +214,7 @@ export class SystemLogComponent implements OnInit, OnDestroy { return this._logLines; } - const message = el.message.split('
      ').filter(el => el.toLowerCase().includes(this.query!.toLowerCase())).join('
      '); + const message = el.message.split("
      ").filter(el => el.toLowerCase().includes(this.query!.toLowerCase())).join("
      "); if (message?.length > 0) { el.message = message; diff --git a/ui/src/app/index/filter/filter.component.ts b/ui/src/app/index/filter/filter.component.ts index 16cc1e4b1a4..336008c0ca3 100644 --- a/ui/src/app/index/filter/filter.component.ts +++ b/ui/src/app/index/filter/filter.component.ts @@ -7,14 +7,14 @@ import { environment } from "src/environments"; import { SUM_STATES } from "../shared/sumState"; @Component({ - selector: 'oe-filter', - templateUrl: './filter.component.html', + selector: "oe-filter", + templateUrl: "./filter.component.html", }) export class FilterComponent { - @Output() protected setSearchParams: EventEmitter> = new EventEmitter>(); + @Output() protected setSearchParams: EventEmitter> = new EventEmitter>(); protected filters: Filter[] = [environment.PRODUCT_TYPES(this.translate), SUM_STATES(this.translate)]; - protected searchParams: Map = new Map(); + protected searchParams: Map = new Map(); constructor(private translate: TranslateService) { } diff --git a/ui/src/app/index/index.module.ts b/ui/src/app/index/index.module.ts index 427fb34c7f5..17a07364ee1 100644 --- a/ui/src/app/index/index.module.ts +++ b/ui/src/app/index/index.module.ts @@ -1,11 +1,11 @@ -import { NgModule } from '@angular/core'; -import { RegistrationModule } from '../registration/registration.module'; -import { SharedModule } from './../shared/shared.module'; -import { FilterComponent } from './filter/filter.component'; -import { LoginComponent } from './login.component'; -import { OverViewComponent } from './overview/overview.component'; -import { LoadingScreenComponent } from './shared/loading-screen'; -import { SumStateComponent } from './shared/sumState'; +import { NgModule } from "@angular/core"; +import { RegistrationModule } from "../registration/registration.module"; +import { SharedModule } from "./../shared/shared.module"; +import { FilterComponent } from "./filter/filter.component"; +import { LoginComponent } from "./login.component"; +import { OverViewComponent } from "./overview/overview.component"; +import { LoadingScreenComponent } from "./shared/loading-screen"; +import { SumStateComponent } from "./shared/sumState"; @NgModule({ imports: [ diff --git a/ui/src/app/index/login.component.ts b/ui/src/app/index/login.component.ts index 50f327e1607..146cbd32166 100644 --- a/ui/src/app/index/login.component.ts +++ b/ui/src/app/index/login.component.ts @@ -1,26 +1,26 @@ // @ts-strict-ignore -import { AfterContentChecked, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; -import { FormGroup } from '@angular/forms'; -import { ActivatedRoute, Router } from '@angular/router'; -import { Subject } from 'rxjs'; -import { environment } from 'src/environments'; +import { AfterContentChecked, ChangeDetectorRef, Component, OnDestroy, OnInit } from "@angular/core"; +import { FormGroup } from "@angular/forms"; +import { ActivatedRoute, Router } from "@angular/router"; +import { Subject } from "rxjs"; +import { environment } from "src/environments"; -import { Capacitor } from '@capacitor/core'; -import { AppService } from '../app.service'; -import { AuthenticateWithPasswordRequest } from '../shared/jsonrpc/request/authenticateWithPasswordRequest'; -import { Edge, Service, Utils, Websocket } from '../shared/shared'; +import { Capacitor } from "@capacitor/core"; +import { AppService } from "../app.service"; +import { AuthenticateWithPasswordRequest } from "../shared/jsonrpc/request/authenticateWithPasswordRequest"; +import { Edge, Service, Utils, Websocket } from "../shared/shared"; @Component({ - selector: 'login', - templateUrl: './login.component.html', + selector: "login", + templateUrl: "./login.component.html", }) export class LoginComponent implements OnInit, AfterContentChecked, OnDestroy { public environment = environment; public form: FormGroup; protected formIsDisabled: boolean = false; - protected popoverActive: 'android' | 'ios' | null = null; + protected popoverActive: "android" | "ios" | null = null; protected readonly operatingSystem = AppService.deviceInfo.os; - protected readonly isApp: boolean = Capacitor.getPlatform() !== 'web'; + protected readonly isApp: boolean = Capacitor.getPlatform() !== "web"; private stopOnDestroy: Subject = new Subject(); private page = 0; @@ -55,35 +55,33 @@ export class LoginComponent implements OnInit, AfterContentChecked, OnDestroy { // TODO add websocket status observable const interval = setInterval(() => { - if (this.websocket.status === 'online') { - this.router.navigate(['/overview']); + if (this.websocket.status === "online") { + this.router.navigate(["/overview"]); clearInterval(interval); } }, 1000); - - this.service.setCurrentComponent('', this.route); } async ionViewWillEnter() { // Execute Login-Request if url path matches 'demo' - if (this.route.snapshot.routeConfig.path == 'demo') { + if (this.route.snapshot.routeConfig.path == "demo") { await new Promise((resolve) => setTimeout(() => { // Wait for Websocket - if (this.websocket.status == 'waiting for credentials') { - this.service.startSpinner('loginspinner'); - const lang = this.route.snapshot.queryParamMap.get('lang') ?? null; + if (this.websocket.status == "waiting for credentials") { + this.service.startSpinner("loginspinner"); + const lang = this.route.snapshot.queryParamMap.get("lang") ?? null; if (lang) { localStorage.DEMO_LANGUAGE = lang; } resolve( - this.doDemoLogin({ username: 'demo', password: 'demo' })); + this.doDemoLogin({ username: "demo", password: "demo" })); } - }, 2000)).then(() => { this.service.setCurrentComponent('', this.route); }); + }, 2000)); } else { - localStorage.removeItem('DEMO_LANGUAGE'); + localStorage.removeItem("DEMO_LANGUAGE"); } } @@ -120,7 +118,7 @@ export class LoginComponent implements OnInit, AfterContentChecked, OnDestroy { public doDemoLogin(param: { username?: string, password: string }) { this.websocket.login(new AuthenticateWithPasswordRequest(param)).then(() => { - this.service.stopSpinner('loginspinner'); + this.service.stopSpinner("loginspinner"); }); return new Promise((resolve, reject) => { @@ -128,14 +126,14 @@ export class LoginComponent implements OnInit, AfterContentChecked, OnDestroy { this.service.getEdges(this.page) .then((edges) => { setTimeout(() => { - this.router.navigate(['/device', edges[0].id]); + this.router.navigate(["/device", edges[0].id]); }, 100); resolve(edges); }).catch((err) => { reject(err); }); }).finally(() => { - this.service.stopSpinner('loginspinner'); + this.service.stopSpinner("loginspinner"); }, ); } @@ -145,10 +143,10 @@ export class LoginComponent implements OnInit, AfterContentChecked, OnDestroy { this.stopOnDestroy.complete(); } - protected async showPopoverOrRedirectToStore(operatingSystem: 'android' | 'ios') { + protected async showPopoverOrRedirectToStore(operatingSystem: "android" | "ios") { const link: string | null = AppService.getAppStoreLink(); if (link) { - window.open(link, '_blank'); + window.open(link, "_blank"); } else { this.popoverActive = operatingSystem; } diff --git a/ui/src/app/index/login.spec.ts b/ui/src/app/index/login.spec.ts index 06d83b9a264..dad874f51d4 100644 --- a/ui/src/app/index/login.spec.ts +++ b/ui/src/app/index/login.spec.ts @@ -2,7 +2,7 @@ import { TestBed } from "@angular/core/testing"; import { LoginComponent } from "./login.component"; -describe('Login', () => { +describe("Login", () => { const password = " password "; const username = " username "; @@ -12,7 +12,7 @@ describe('Login', () => { }).compileComponents(); }); - it('#trimCredentials should trim password and username', () => { + it("#trimCredentials should trim password and username", () => { { // Username and password - OpenEMS Backend expect(LoginComponent.trimCredentials(password, username)).toEqual({ password: "password", username: "username" }); diff --git a/ui/src/app/index/overview/overview.component.ts b/ui/src/app/index/overview/overview.component.ts index b52e924a4bf..f8a129eaa3a 100644 --- a/ui/src/app/index/overview/overview.component.ts +++ b/ui/src/app/index/overview/overview.component.ts @@ -3,9 +3,9 @@ import { Component, OnDestroy, OnInit } from "@angular/core"; import { FormGroup } from "@angular/forms"; import { ActivatedRoute, Router } from "@angular/router"; import { InfiniteScrollCustomEvent } from "@ionic/angular"; -import { TranslateService } from '@ngx-translate/core'; +import { TranslateService } from "@ngx-translate/core"; import { Subject } from "rxjs"; -import { filter, take } from 'rxjs/operators'; +import { filter, take } from "rxjs/operators"; import { Pagination } from "src/app/shared/service/pagination"; import { Edge, Service, Utils, Websocket } from "src/app/shared/shared"; import { Role } from "src/app/shared/type/role"; @@ -14,8 +14,8 @@ import { environment } from "src/environments"; import { ChosenFilter } from "../filter/filter.component"; @Component({ - selector: 'overview', - templateUrl: './overview.component.html', + selector: "overview", + templateUrl: "./overview.component.html", }) export class OverViewComponent implements OnInit, OnDestroy { public environment = environment; @@ -29,7 +29,7 @@ export class OverViewComponent implements OnInit, OnDestroy { public filteredEdges: Edge[] = []; protected loading: boolean = false; - protected searchParams: Map = new Map(); + protected searchParams: Map = new Map(); private stopOnDestroy: Subject = new Subject(); private page = 0; @@ -59,10 +59,6 @@ export class OverViewComponent implements OnInit, OnDestroy { }); } - ionViewWillEnter() { - this.service.setCurrentComponent('', this.route); - } - /** * Updates available edges on scroll-event * @@ -120,7 +116,7 @@ export class OverViewComponent implements OnInit, OnDestroy { * * @param event from template passed event */ - protected searchOnChange(searchParams?: Map) { + protected searchOnChange(searchParams?: Map) { if (searchParams) { this.searchParams = searchParams; @@ -151,10 +147,10 @@ export class OverViewComponent 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 (environment.backend == "OpenEMS Edge" || (!this.loggedInUserCanInstall && edgeIds.length == 1)) { const edge = metadata.edges[edgeIds[0]]; setTimeout(() => { - this.router.navigate(['/device', edge.id]); + this.router.navigate(["/device", edge.id]); }, 100); return; } diff --git a/ui/src/app/index/shared/loading-screen.ts b/ui/src/app/index/shared/loading-screen.ts index 8538a706089..14d5d7b43a5 100644 --- a/ui/src/app/index/shared/loading-screen.ts +++ b/ui/src/app/index/shared/loading-screen.ts @@ -1,12 +1,12 @@ // @ts-strict-ignore -import { Component, OnInit } from '@angular/core'; -import { Router } from '@angular/router'; +import { Component, OnInit } from "@angular/core"; +import { Router } from "@angular/router"; -import { Service, Websocket } from '../../shared/shared'; +import { Service, Websocket } from "../../shared/shared"; @Component({ - selector: 'index', - templateUrl: './loading-screen.html', + selector: "index", + templateUrl: "./loading-screen.html", }) export class LoadingScreenComponent implements OnInit { @@ -23,14 +23,14 @@ export class LoadingScreenComponent implements OnInit { // TODO add websocket status observable const interval = setInterval(() => { this.service.startSpinner(this.spinnerId); - if (this.websocket.status === 'online') { + if (this.websocket.status === "online") { this.service.stopSpinner(this.spinnerId); - this.router.navigate(['/overview']); + this.router.navigate(["/overview"]); clearInterval(interval); } - if (this.websocket.status === 'waiting for credentials') { + if (this.websocket.status === "waiting for credentials") { this.service.stopSpinner(this.spinnerId); - this.router.navigate(['/login']); + this.router.navigate(["/login"]); clearInterval(interval); } }, 1000); diff --git a/ui/src/app/index/shared/sumState.ts b/ui/src/app/index/shared/sumState.ts index a0a4dc504a0..38a892087d6 100644 --- a/ui/src/app/index/shared/sumState.ts +++ b/ui/src/app/index/shared/sumState.ts @@ -5,14 +5,14 @@ import { Role } from "src/app/shared/type/role"; import { Filter } from "../filter/filter.component"; export enum SumState { - OK = 'OK', - INFO = 'INFO', - WARNING = 'WARNING', - FAULT = 'FAULT', + OK = "OK", + INFO = "INFO", + WARNING = "WARNING", + FAULT = "FAULT", } @Component({ - selector: 'oe-sum-state', + selector: "oe-sum-state", template: ` @@ -65,15 +65,15 @@ export const SUM_STATES = (translate: TranslateService): Filter => ({ category: "sumState", options: [ { - name: 'Ok', + name: "Ok", value: "ok", }, { - name: translate.instant('General.info'), + name: translate.instant("General.info"), value: "Info", }, { - name: translate.instant('General.warning'), + name: translate.instant("General.warning"), value: "Warning", }, { @@ -82,7 +82,7 @@ export const SUM_STATES = (translate: TranslateService): Filter => ({ }, ], setAdditionalFilter: () => ({ - key: 'isOnline', + key: "isOnline", value: true, }), }); diff --git a/ui/src/app/registration/modal/modal.component.ts b/ui/src/app/registration/modal/modal.component.ts index a52284aa166..430f0d24d1f 100644 --- a/ui/src/app/registration/modal/modal.component.ts +++ b/ui/src/app/registration/modal/modal.component.ts @@ -1,16 +1,16 @@ // @ts-strict-ignore -import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; -import { ModalController } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; -import { RegisterUserRequest } from 'src/app/shared/jsonrpc/request/registerUserRequest'; -import { Service, Websocket } from 'src/app/shared/shared'; -import { COUNTRY_OPTIONS } from 'src/app/shared/type/country'; -import { environment } from 'src/environments'; +import { Component, OnInit } from "@angular/core"; +import { FormBuilder, FormControl, FormGroup, Validators } from "@angular/forms"; +import { ModalController } from "@ionic/angular"; +import { TranslateService } from "@ngx-translate/core"; +import { RegisterUserRequest } from "src/app/shared/jsonrpc/request/registerUserRequest"; +import { Service, Websocket } from "src/app/shared/shared"; +import { COUNTRY_OPTIONS } from "src/app/shared/type/country"; +import { environment } from "src/environments"; @Component({ - selector: 'registration-modal', - templateUrl: './modal.component.html', + selector: "registration-modal", + templateUrl: "./modal.component.html", }) export class RegistrationModalComponent implements OnInit { @@ -44,7 +44,7 @@ export class RegistrationModalComponent implements OnInit { */ onSubmit() { if (!this.formGroup.valid) { - this.service.toast(this.translate.instant("Register.errors.requiredFields"), 'danger'); + this.service.toast(this.translate.instant("Register.errors.requiredFields"), "danger"); return; } @@ -52,7 +52,7 @@ export class RegistrationModalComponent implements OnInit { const confirmPassword = this.formGroup.value.confirmPassword; if (password != confirmPassword) { - this.service.toast(this.translate.instant("Register.errors.passwordNotEqual"), 'danger'); + this.service.toast(this.translate.instant("Register.errors.passwordNotEqual"), "danger"); return; } @@ -60,7 +60,7 @@ export class RegistrationModalComponent implements OnInit { const confirmEmail = this.formGroup.value.confirmEmail; if (email != confirmEmail) { - this.service.toast(this.translate.instant("Register.errors.emailNotEqual"), 'danger'); + this.service.toast(this.translate.instant("Register.errors.emailNotEqual"), "danger"); return; } @@ -92,11 +92,11 @@ export class RegistrationModalComponent implements OnInit { this.websocket.sendRequest(request) .then(() => { - this.service.toast(this.translate.instant("Register.success"), 'success'); + this.service.toast(this.translate.instant("Register.success"), "success"); this.modalCtrl.dismiss(); }) .catch(reason => { - this.service.toast(reason.error.message, 'danger'); + this.service.toast(reason.error.message, "danger"); }); } @@ -105,7 +105,7 @@ export class RegistrationModalComponent implements OnInit { * If no role matches then the default (owner) from will be returnd. */ private getForm(role: string): FormGroup { - if (role === 'installer') { + if (role === "installer") { return this.formBuilder.group({ companyName: new FormControl("", Validators.required), firstname: new FormControl("", Validators.required), diff --git a/ui/src/app/registration/registration.component.ts b/ui/src/app/registration/registration.component.ts index ab87858095b..6ac8752cff7 100644 --- a/ui/src/app/registration/registration.component.ts +++ b/ui/src/app/registration/registration.component.ts @@ -1,10 +1,10 @@ -import { Component } from '@angular/core'; -import { ModalController } from '@ionic/angular'; -import { RegistrationModalComponent } from './modal/modal.component'; +import { Component } from "@angular/core"; +import { ModalController } from "@ionic/angular"; +import { RegistrationModalComponent } from "./modal/modal.component"; @Component({ - selector: 'registration', - templateUrl: './registration.component.html', + selector: "registration", + templateUrl: "./registration.component.html", }) export class RegistrationComponent { diff --git a/ui/src/app/registration/registration.module.ts b/ui/src/app/registration/registration.module.ts index d4afbd2bf5c..b5b2b42ee8f 100644 --- a/ui/src/app/registration/registration.module.ts +++ b/ui/src/app/registration/registration.module.ts @@ -1,8 +1,8 @@ -import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { SharedModule } from '../shared/shared.module'; -import { RegistrationModalComponent } from './modal/modal.component'; -import { RegistrationComponent } from './registration.component'; +import { CommonModule } from "@angular/common"; +import { NgModule } from "@angular/core"; +import { SharedModule } from "../shared/shared.module"; +import { RegistrationModalComponent } from "./modal/modal.component"; +import { RegistrationComponent } from "./registration.component"; @NgModule({ declarations: [ diff --git a/ui/src/app/shared/components/abstracthistorywidget.ts b/ui/src/app/shared/components/abstracthistorywidget.ts index 2c1bb5f9033..dfc48dffa2a 100644 --- a/ui/src/app/shared/components/abstracthistorywidget.ts +++ b/ui/src/app/shared/components/abstracthistorywidget.ts @@ -1,12 +1,12 @@ // @ts-strict-ignore -import { Directive, Inject, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { ModalController } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; -import { Subject } from 'rxjs'; -import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; -import { ChannelAddress, CurrentData, Edge, EdgeConfig, Service, Websocket } from 'src/app/shared/shared'; -import { v4 as uuidv4 } from 'uuid'; +import { Directive, Inject, Input, OnChanges, OnDestroy, OnInit } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { ModalController } from "@ionic/angular"; +import { TranslateService } from "@ngx-translate/core"; +import { Subject } from "rxjs"; +import { DefaultTypes } from "src/app/shared/service/defaulttypes"; +import { ChannelAddress, CurrentData, Edge, EdgeConfig, Service, Websocket } from "src/app/shared/shared"; +import { v4 as uuidv4 } from "uuid"; // NOTE: Auto-refresh of widgets is currently disabled to reduce server load @Directive() @@ -38,7 +38,7 @@ export abstract class AbstractHistoryWidget implements OnInit, OnChanges, OnDest ) { } public ngOnInit() { - this.service.setCurrentComponent('', this.route).then(edge => { + this.service.getCurrentEdge().then(edge => { this.service.getConfig().then(config => { // store important variables publically this.edge = edge; diff --git a/ui/src/app/shared/components/chart/abstractHistoryChartOverview.ts b/ui/src/app/shared/components/chart/abstractHistoryChartOverview.ts index 47410194515..6fe6813f36d 100644 --- a/ui/src/app/shared/components/chart/abstractHistoryChartOverview.ts +++ b/ui/src/app/shared/components/chart/abstractHistoryChartOverview.ts @@ -30,7 +30,7 @@ export abstract class AbstractHistoryChartOverview implements OnInit, OnChanges, ) { } public ngOnInit() { - this.service.setCurrentComponent('', this.route).then(edge => { + this.service.getCurrentEdge().then(edge => { this.service.getConfig().then(config => { // store important variables publically this.edge = edge; diff --git a/ui/src/app/shared/components/chart/abstracthistorychart.ts b/ui/src/app/shared/components/chart/abstracthistorychart.ts index feaadfa5623..97d491dc2f4 100644 --- a/ui/src/app/shared/components/chart/abstracthistorychart.ts +++ b/ui/src/app/shared/components/chart/abstracthistorychart.ts @@ -1,33 +1,33 @@ // @ts-strict-ignore -import { DecimalPipe, formatNumber } from '@angular/common'; -import { ChangeDetectorRef, Directive, Input, OnDestroy, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { TranslateService } from '@ngx-translate/core'; -import * as Chart from 'chart.js'; -import annotationPlugin from 'chartjs-plugin-annotation'; -import { calculateResolution, ChronoUnit, DEFAULT_NUMBER_CHART_OPTIONS, DEFAULT_TIME_CHART_OPTIONS, isLabelVisible, Resolution, setLabelVisible } from 'src/app/edge/history/shared'; -import { QueryHistoricTimeseriesEnergyPerPeriodResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyPerPeriodResponse'; -import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; -import { v4 as uuidv4 } from 'uuid'; - -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 { FormatSecondsToDurationPipe } from '../../pipe/formatSecondsToDuration/formatSecondsToDuration.pipe'; -import { ChartAxis, HistoryUtils, YAxisTitle } from '../../service/utils'; -import { ChannelAddress, Currency, Edge, EdgeConfig, Logger, Service, Utils } from '../../shared'; -import { Language } from '../../type/language'; -import { ColorUtils } from '../../utils/color/color.utils'; -import { DateUtils } from '../../utils/date/dateutils'; -import { DateTimeUtils } from '../../utils/datetime/datetime-utils'; -import { TimeUtils } from '../../utils/time/timeutils'; -import { Converter } from '../shared/converter'; -import { ChartConstants, XAxisType } from './chart.constants'; - -import 'chartjs-adapter-date-fns'; +import { DecimalPipe, formatNumber } from "@angular/common"; +import { ChangeDetectorRef, Directive, Input, OnDestroy, OnInit } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { TranslateService } from "@ngx-translate/core"; +import * as Chart from "chart.js"; +import annotationPlugin from "chartjs-plugin-annotation"; +import { calculateResolution, ChronoUnit, DEFAULT_NUMBER_CHART_OPTIONS, DEFAULT_TIME_CHART_OPTIONS, isLabelVisible, Resolution, setLabelVisible } from "src/app/edge/history/shared"; +import { QueryHistoricTimeseriesEnergyPerPeriodResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyPerPeriodResponse"; +import { DefaultTypes } from "src/app/shared/service/defaulttypes"; +import { v4 as uuidv4 } from "uuid"; + +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 { FormatSecondsToDurationPipe } from "../../pipe/formatSecondsToDuration/formatSecondsToDuration.pipe"; +import { ChartAxis, HistoryUtils, YAxisType } from "../../service/utils"; +import { ChannelAddress, Currency, Edge, EdgeConfig, Logger, Service, Utils } from "../../shared"; +import { Language } from "../../type/language"; +import { ColorUtils } from "../../utils/color/color.utils"; +import { DateUtils } from "../../utils/date/dateutils"; +import { DateTimeUtils } from "../../utils/datetime/datetime-utils"; +import { TimeUtils } from "../../utils/time/timeutils"; +import { Converter } from "../shared/converter"; +import { ChartConstants, XAxisType } from "./chart.constants"; + +import "chartjs-adapter-date-fns"; Chart.Chart.register(annotationPlugin); @@ -36,7 +36,7 @@ Chart.Chart.register(annotationPlugin); @Directive() export abstract class AbstractHistoryChart implements OnInit, OnDestroy { - protected static readonly phaseColors: string[] = ['rgb(255,127,80)', 'rgb(0,0,255)', 'rgb(128,128,0)']; + protected static readonly phaseColors: string[] = ["rgb(255,127,80)", "rgb(0,0,255)", "rgb(128,128,0)"]; /** Title for Chart, diplayed above the Chart */ @Input() public chartTitle: string = ""; @@ -57,12 +57,13 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { public chartObject: HistoryUtils.ChartData | null = null; protected spinnerId: string = uuidv4(); - protected chartType: 'line' | 'bar' = 'line'; + protected chartType: "line" | "bar" = "line"; protected isDataExisting: boolean = true; protected config: EdgeConfig = null; protected errorResponse: JsonrpcResponseError | null = null; protected legendOptions: { label: string, strokeThroughHidingStyle: boolean, hideLabelInLegend: boolean }[] = []; + protected debounceTimeout: any | null = null; private channelData: { data: { [name: string]: number[] } } = { data: {} }; constructor( @@ -83,7 +84,7 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { * @param energyPeriodResponse the response of a {@link QueryHistoricTimeseriesEnergyPerPeriodRequest} or {@link QueryHistoricTimeseriesDataResponse} * @param energyResponse the response of a {@link QueryHistoricTimeseriesEnergyResponse} */ - public static fillChart(chartType: 'line' | 'bar', chartObject: HistoryUtils.ChartData, energyPeriodResponse: QueryHistoricTimeseriesDataResponse | QueryHistoricTimeseriesEnergyPerPeriodResponse, + public static fillChart(chartType: "line" | "bar", chartObject: HistoryUtils.ChartData, energyPeriodResponse: QueryHistoricTimeseriesDataResponse | QueryHistoricTimeseriesEnergyPerPeriodResponse, energyResponse?: QueryHistoricTimeseriesEnergyResponse) { if (Utils.isDataEmpty(energyPeriodResponse)) { return { @@ -102,7 +103,7 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { chartObject.input.forEach(element => { let channelAddress: ChannelAddress | null = null; - if (chartType == 'bar' && element.energyChannel) { + if (chartType == "bar" && element.energyChannel) { channelAddress = element.energyChannel; } else { channelAddress = element.powerChannel; @@ -162,7 +163,7 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { }; } - public static fillData(element: HistoryUtils.DisplayValue, label: string, chartObject: HistoryUtils.ChartData, chartType: 'line' | 'bar', data: number[] | null): { datasets: Chart.ChartDataset[], legendOptions: { label: string, strokeThroughHidingStyle: boolean, hideLabelInLegend: boolean; }[]; } { + public static fillData(element: HistoryUtils.DisplayValue, label: string, chartObject: HistoryUtils.ChartData, chartType: "line" | "bar", data: number[] | null): { datasets: Chart.ChartDataset[], legendOptions: { label: string, strokeThroughHidingStyle: boolean, hideLabelInLegend: boolean; }[]; } { const legendOptions: { label: string, strokeThroughHidingStyle: boolean, hideLabelInLegend: boolean; }[] = []; const datasets: Chart.ChartDataset[] = []; @@ -204,10 +205,10 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { * @param color the color * @returns the backgroundColor and borderColor */ - public static getColors(color: string, chartType: 'line' | 'bar'): { backgroundColor: string, borderColor: string } { + 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)', + 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)", }; } @@ -217,12 +218,12 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { * @param chartType the chart type * @returns chart options */ - public static applyChartTypeSpecificOptionsChanges(chartType: 'bar' | 'line', options: Chart.ChartOptions, service: Service, chartObject: HistoryUtils.ChartData | null): Chart.ChartOptions { + public static applyChartTypeSpecificOptionsChanges(chartType: "bar" | "line", options: Chart.ChartOptions, service: Service, chartObject: HistoryUtils.ChartData | null): Chart.ChartOptions { switch (chartType) { - case 'bar': { - options.plugins.tooltip.mode = 'x'; - options.scales.x['offset'] = true; - options.scales.x.ticks['source'] = 'data'; + case "bar": { + options.plugins.tooltip.mode = "x"; + options.scales.x["offset"] = true; + options.scales.x.ticks["source"] = "data"; let barPercentage = 1; switch (service.periodString) { case DefaultTypes.PeriodString.CUSTOM: { @@ -245,6 +246,8 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { } break; } + default: + break; } options.datasets.bar = { @@ -253,14 +256,14 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { break; } - case 'line': - options.scales.x['offset'] = false; - options.scales.x.ticks['source'] = 'data'; - options.plugins.tooltip.mode = 'index'; + case "line": + options.scales.x["offset"] = false; + options.scales.x.ticks["source"] = "data"; + options.plugins.tooltip.mode = "index"; if (chartObject) { for (const yAxis of chartObject.yAxes) { - options.scales[yAxis.yAxisId]['stacked'] = false; + options.scales[yAxis.yAxisId]["stacked"] = false; } } break; @@ -278,7 +281,7 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { * @param stack the stack * @returns a dataset */ - public static getDataSet(element: HistoryUtils.DisplayValue, label: string, data: number[], stack: number, chartObject: HistoryUtils.ChartData, chartType: 'line' | 'bar'): Chart.ChartDataset { + public static getDataSet(element: HistoryUtils.DisplayValue, label: string, data: number[], stack: number, chartObject: HistoryUtils.ChartData, chartType: "line" | "bar"): Chart.ChartDataset { const dataset: Chart.ChartDataset = { label: label, data: data, @@ -296,32 +299,32 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { return dataset; } - public static getYAxisTitle(title: YAxisTitle, translate: TranslateService, chartType: 'bar' | 'line', customTitle?: string): string { + public static getYAxisType(title: YAxisType, translate: TranslateService, chartType: "bar" | "line", customTitle?: string): string { switch (title) { - case YAxisTitle.RELAY: - if (chartType === 'line') { + case YAxisType.RELAY: + if (chartType === "line") { // Hide YAxis title - return ''; + return ""; } - return translate.instant('Edge.Index.Widgets.Channeltreshold.ACTIVE_TIME_OVER_PERIOD'); - case YAxisTitle.TIME: - return translate.instant('Edge.Index.Widgets.Channeltreshold.ACTIVE_TIME_OVER_PERIOD'); - case YAxisTitle.PERCENTAGE: - return translate.instant('General.percentage'); - case YAxisTitle.ENERGY: - if (chartType == 'bar') { - return 'kWh'; + return translate.instant("Edge.Index.Widgets.Channeltreshold.ACTIVE_TIME_OVER_PERIOD"); + case YAxisType.TIME: + return translate.instant("Edge.Index.Widgets.Channeltreshold.ACTIVE_TIME_OVER_PERIOD"); + case YAxisType.PERCENTAGE: + return translate.instant("General.percentage"); + case YAxisType.ENERGY: + if (chartType == "bar") { + return "kWh"; } else { - return 'kW'; + return "kW"; } - case YAxisTitle.VOLTAGE: - return translate.instant('Edge.History.VOLTAGE'); - case YAxisTitle.CURRENT: - return translate.instant('Edge.History.CURRENT'); - case YAxisTitle.NONE: - return ''; + case YAxisType.VOLTAGE: + return translate.instant("Edge.History.VOLTAGE"); + case YAxisType.CURRENT: + return translate.instant("Edge.History.CURRENT"); + case YAxisType.NONE: + return ""; default: - return 'kW'; + return "kW"; } } @@ -338,7 +341,7 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { * @returns options */ public static getOptions( - chartObject: HistoryUtils.ChartData, chartType: 'line' | 'bar', service: Service, + chartObject: HistoryUtils.ChartData, chartType: "line" | "bar", service: Service, translate: TranslateService, legendOptions: { label: string, strokeThroughHidingStyle: boolean; }[], channelData: { data: { [name: string]: number[]; }; }, @@ -353,9 +356,9 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { let options: Chart.ChartOptions = Utils.deepCopy(Utils.deepCopy(AbstractHistoryChart.getDefaultOptions(chartOptionsType, service, labels))); const displayValues: HistoryUtils.DisplayValue[] = chartObject.output(channelData.data); - const showYAxisTitle: boolean = chartObject.yAxes.length > 1; + const showYAxisType: boolean = chartObject.yAxes.length > 1; chartObject.yAxes.forEach((element) => { - options = AbstractHistoryChart.getYAxisOptions(options, element, translate, chartType, locale, datasets, showYAxisTitle); + options = AbstractHistoryChart.getYAxisOptions(options, element, translate, chartType, locale, datasets, showYAxisType); }); options.plugins.tooltip.callbacks.title = (tooltipItems: Chart.TooltipItem[]): string => { @@ -403,7 +406,7 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { const legendItem = legendOptions?.find(element => element.label == dataset.label); //Remove duplicates like 'directConsumption' from legend - if (chartLegendLabelItems.filter(element => element['text'] == dataset.label).length > 0) { + if (chartLegendLabelItems.filter(element => element["text"] == dataset.label).length > 0) { return; } @@ -413,12 +416,12 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { chartLegendLabelItems.push({ text: dataset.label, datasetIndex: index, - fontColor: getComputedStyle(document.documentElement).getPropertyValue('--ion-color-text'), + fontColor: getComputedStyle(document.documentElement).getPropertyValue("--ion-color-text"), ...(dataset.backgroundColor != null && { fillStyle: dataset.backgroundColor.toString() }), hidden: isHidden != null ? isHidden : !chart.isDatasetVisible(index), lineWidth: 2, ...(dataset.borderColor != null && { strokeStyle: dataset.borderColor.toString() }), - ...(dataset['borderDash'] != null && { lineDash: dataset['borderDash'] }), + ...(dataset["borderDash"] != null && { lineDash: dataset["borderDash"] }), }); }); @@ -445,11 +448,11 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { return null; } - const afterTitle = typeof chartObject.tooltip?.afterTitle == 'function' ? chartObject.tooltip?.afterTitle(stack) : null; + const afterTitle = typeof chartObject.tooltip?.afterTitle == "function" ? chartObject.tooltip?.afterTitle(stack) : null; const totalValue = datasets.filter(el => el.stack == stack).reduce((_total, dataset) => Utils.addSafely(_total, Math.abs(dataset.data[datasetIndex])), 0); if (afterTitle) { - return afterTitle + ": " + formatNumber(totalValue, 'de', chartObject.tooltip.formatNumber) + ' ' + tooltipsLabel; + return afterTitle + ": " + formatNumber(totalValue, "de", chartObject.tooltip.formatNumber) + " " + tooltipsLabel; } return null; @@ -478,9 +481,9 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { chart.update(); }; - options.scales.x.ticks['source'] = 'auto'; + options.scales.x.ticks["source"] = "auto"; options.scales.x.ticks.maxTicksLimit = 31; - options.scales.x['bounds'] = 'ticks'; + options.scales.x["bounds"] = "ticks"; options; options = AbstractHistoryChart.getExternalPluginFeatures(displayValues, options, chartType); @@ -497,13 +500,13 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { * @param locale the current locale * @returns the chart options {@link Chart.ChartOptions} */ - public static getYAxisOptions(options: Chart.ChartOptions, element: HistoryUtils.yAxes, translate: TranslateService, chartType: 'line' | 'bar', locale: string, datasets: Chart.ChartDataset[], showYAxisTitle?: boolean): Chart.ChartOptions { + public static getYAxisOptions(options: Chart.ChartOptions, element: HistoryUtils.yAxes, translate: TranslateService, chartType: "line" | "bar", locale: string, datasets: Chart.ChartDataset[], showYAxisType?: boolean): Chart.ChartOptions { - const baseConfig = ChartConstants.DEFAULT_Y_SCALE_OPTIONS(element, translate, chartType, datasets, showYAxisTitle); + const baseConfig = ChartConstants.DEFAULT_Y_SCALE_OPTIONS(element, translate, chartType, datasets, showYAxisType); switch (element.unit) { - case YAxisTitle.RELAY: + case YAxisType.RELAY: options.scales[element.yAxisId] = { ...baseConfig, min: 0, @@ -520,14 +523,14 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { }, }; break; - case YAxisTitle.PERCENTAGE: + case YAxisType.PERCENTAGE: options.scales[element.yAxisId] = { ...baseConfig, stacked: true, beginAtZero: true, max: 100, min: 0, - type: 'linear', + type: "linear", ticks: { ...baseConfig.ticks, padding: 5, @@ -536,7 +539,7 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { }; break; - case YAxisTitle.TIME: + case YAxisType.TIME: options.scales[element.yAxisId] = { ...baseConfig, min: 0, @@ -544,26 +547,26 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { ...baseConfig.ticks, callback: function (value, index, values) { - if (typeof value === 'number') { + if (typeof value === "number") { return TimeUtils.formatSecondsToDuration(value, locale); } }, }, }; break; - case YAxisTitle.POWER: - case YAxisTitle.ENERGY: - case YAxisTitle.VOLTAGE: - case YAxisTitle.CURRENT: - case YAxisTitle.NONE: + case YAxisType.POWER: + case YAxisType.ENERGY: + case YAxisType.VOLTAGE: + case YAxisType.CURRENT: + case YAxisType.NONE: options.scales[element.yAxisId] = baseConfig; break; - case YAxisTitle.CURRENCY: + case YAxisType.CURRENCY: options.scales[element.yAxisId] = { ...baseConfig, beginAtZero: false, ticks: { - source: 'auto', + source: "auto", }, }; break; @@ -579,21 +582,23 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { * @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 { + public static getTooltipsLabelName(baseName: string, unit: YAxisType, suffix?: number | string): string { if (suffix != null) { - if (typeof suffix === 'string') { + if (typeof suffix === "string") { return 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") + " %"; - case YAxisTitle.RELAY: - case YAxisTitle.TIME: { + case YAxisType.ENERGY: + return baseName + ": " + formatNumber(suffix / 1000, "de", "1.0-1") + " kWh"; + case YAxisType.PERCENTAGE: + return baseName + ": " + formatNumber(suffix, "de", "1.0-1") + " %"; + case YAxisType.RELAY: + case YAxisType.TIME: { const pipe = new FormatSecondsToDurationPipe(new DecimalPipe(Language.DE.key)); return baseName + ": " + pipe.transform(suffix); } + default: + return baseName; } } } @@ -601,43 +606,43 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { } /** - * Gets the tooltips label, dependent on YAxisTitle + * Gets the tooltips label, dependent on YAxisType * - * @param title the YAxisTitle + * @param title the YAxisType * @returns the tooltips suffix */ - public static getToolTipsSuffix(label: any, value: number, format: string, title: YAxisTitle, chartType: 'bar' | 'line', language: string, translate: TranslateService, config: EdgeConfig): string { + public static getToolTipsSuffix(label: any, value: number, format: string, title: YAxisType, chartType: "bar" | "line", language: string, translate: TranslateService, config: EdgeConfig): string { let tooltipsLabel: string | null = null; switch (title) { - case YAxisTitle.RELAY: { + case YAxisType.RELAY: { return Converter.ON_OFF(translate)(value); } - case YAxisTitle.TIME: { + case YAxisType.TIME: { const pipe = new FormatSecondsToDurationPipe(new DecimalPipe(language)); return pipe.transform(value); } - case YAxisTitle.CURRENCY: { - const currency = config.components['_meta'].properties.currency; + case YAxisType.CURRENCY: { + const currency = config.components["_meta"].properties.currency; tooltipsLabel = Currency.getCurrencyLabelByCurrency(currency); break; } - case YAxisTitle.PERCENTAGE: + case YAxisType.PERCENTAGE: tooltipsLabel = AbstractHistoryChart.getToolTipsAfterTitleLabel(title, chartType, value, translate); break; - case YAxisTitle.VOLTAGE: - tooltipsLabel = 'V'; + case YAxisType.VOLTAGE: + tooltipsLabel = "V"; break; - case YAxisTitle.CURRENT: - tooltipsLabel = 'A'; + case YAxisType.CURRENT: + tooltipsLabel = "A"; break; - case YAxisTitle.POWER: - tooltipsLabel = 'W'; + case YAxisType.POWER: + tooltipsLabel = "W"; break; - case YAxisTitle.ENERGY: - if (chartType == 'bar') { - tooltipsLabel = 'kWh'; + case YAxisType.ENERGY: + if (chartType == "bar") { + tooltipsLabel = "kWh"; } else { - tooltipsLabel = 'kW'; + tooltipsLabel = "kW"; } break; default: @@ -645,7 +650,7 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { break; } - return formatNumber(value, 'de', format) + ' ' + tooltipsLabel; + return formatNumber(value, "de", format) + " " + tooltipsLabel; } public static getDefaultOptions(xAxisType: XAxisType, service: Service, labels: (Date | string)[]): Chart.ChartOptions { @@ -656,9 +661,8 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { options = DEFAULT_NUMBER_CHART_OPTIONS(labels); break; case XAxisType.TIMESERIES: - default: options = Utils.deepCopy(DEFAULT_TIME_CHART_OPTIONS()); - options.scales.x['time'].unit = calculateResolution(service, service.historyPeriod.value.from, service.historyPeriod.value.to).timeFormat; + options.scales.x["time"].unit = calculateResolution(service, service.historyPeriod.value.from, service.historyPeriod.value.to).timeFormat; break; } @@ -684,50 +688,50 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { switch (unit) { case ChronoUnit.Type.YEARS: - return date.toLocaleDateString('default', { year: 'numeric' }); + return date.toLocaleDateString("default", { year: "numeric" }); case ChronoUnit.Type.MONTHS: - return date.toLocaleDateString('default', { month: 'long' }); + return date.toLocaleDateString("default", { month: "long" }); case ChronoUnit.Type.DAYS: - return date.toLocaleDateString('default', { day: '2-digit', month: 'long' }); + return date.toLocaleDateString("default", { day: "2-digit", month: "long" }); default: - return date.toLocaleString('default', { day: '2-digit', month: '2-digit', year: '2-digit' }) + ' ' + date.toLocaleTimeString('default', { hour12: false, hour: '2-digit', minute: '2-digit' }); + return date.toLocaleString("default", { day: "2-digit", month: "2-digit", year: "2-digit" }) + " " + date.toLocaleTimeString("default", { hour12: false, hour: "2-digit", minute: "2-digit" }); } } protected static removeExternalPluginFeatures(options: Chart.ChartOptions): Chart.ChartOptions { - options.plugins['annotation'] = {}; - options.plugins['datalabels'] = { + options.plugins["annotation"] = {}; + options.plugins["datalabels"] = { display: false, }; return options; } /** - * Gets the tooltips label, dependent on YAxisTitle + * Gets the tooltips label, dependent on YAxisType * - * @param title the YAxisTitle + * @param title the YAxisType * @returns the tooltips title with the corresponding unit */ - protected static getToolTipsAfterTitleLabel(title: YAxisTitle | null, chartType: 'bar' | 'line', value: number | string | null, translate: TranslateService): string { + protected static getToolTipsAfterTitleLabel(title: YAxisType | null, chartType: "bar" | "line", value: number | string | null, translate: TranslateService): string { switch (title) { - case YAxisTitle.RELAY: + case YAxisType.RELAY: return Converter.ON_OFF(translate)(value); - case YAxisTitle.TIME: - return 'h'; - case YAxisTitle.PERCENTAGE: - return '%'; - case YAxisTitle.VOLTAGE: - return 'V'; - case YAxisTitle.CURRENT: - return 'A'; - case YAxisTitle.ENERGY: - if (chartType == 'bar') { - return 'kWh'; + case YAxisType.TIME: + return "h"; + case YAxisType.PERCENTAGE: + return "%"; + case YAxisType.VOLTAGE: + return "V"; + case YAxisType.CURRENT: + return "A"; + case YAxisType.ENERGY: + if (chartType == "bar") { + return "kWh"; } else { - return 'kW'; + return "kW"; } default: - return ''; + return ""; } } @@ -739,16 +743,16 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { * @param chartType the chartType * @returns plugin options */ - private static getExternalPluginFeatures(displayValues: (HistoryUtils.DisplayValue)[], options: Chart.ChartOptions, chartType: 'line' | 'bar'): Chart.ChartOptions { + private static getExternalPluginFeatures(displayValues: (HistoryUtils.DisplayValue)[], options: Chart.ChartOptions, chartType: "line" | "bar"): Chart.ChartOptions { displayValues.flatMap(el => { if (!el.custom) { return; } - switch (el.custom['pluginType']) { - case 'box': - options.plugins['annotation'] = { + switch (el.custom["pluginType"]) { + case "box": + options.plugins["annotation"] = { annotations: (el.custom as HistoryUtils.BoxCustomOptions).annotations.map(annotation => { return ({ ...AbstractHistoryChart.getColors(el.color, chartType), @@ -757,10 +761,10 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { }), }; break; - case 'datalabels': - options.plugins['datalabels'] = + case "datalabels": + options.plugins["datalabels"] = ChartConstants.Plugins.BAR_CHART_DATALABELS((el.custom as HistoryUtils.DataLabelsCustomOptions).datalabels.displayUnit, true); - Chart.Chart.register(ChartConstants.Plugins.BAR_CHART_DATALABELS('kWh', true).plugin); + Chart.Chart.register(ChartConstants.Plugins.BAR_CHART_DATALABELS("kWh", true).plugin); break; } }); @@ -791,7 +795,7 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { ngOnInit() { this.startSpinner(); - this.service.setCurrentComponent('', this.route).then(edge => { + this.service.getCurrentEdge().then(edge => { this.service.getConfig().then(config => { // store important variables publically this.edge = edge; @@ -835,7 +839,7 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { 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.chartType = 'bar'; + this.chartType = "bar"; this.chartObject = this.getChartData(); // TODO after chartjs migration, look for config @@ -859,7 +863,7 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { .then(([dataResponse, energyResponse]) => { dataResponse = DateTimeUtils.normalizeTimestamps(unit, dataResponse); - this.chartType = 'line'; + this.chartType = "line"; this.chartObject = this.getChartData(); const displayValues = AbstractHistoryChart.fillChart(this.chartType, this.chartObject, dataResponse, energyResponse); this.datasets = displayValues.datasets; @@ -885,39 +889,44 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { this.isDataExisting = true; const resolution = res ?? calculateResolution(this.service, fromDate, toDate).resolution; - const result: Promise = new Promise((resolve, reject) => { - this.service.getCurrentEdge().then(edge => { - this.service.getConfig().then(async () => { - const channelAddresses = (await this.getChannelAddresses()).powerChannels; - const request = new QueryHistoricTimeseriesDataRequest(DateUtils.maxDate(fromDate, this.edge?.firstSetupProtocol), toDate, channelAddresses, resolution); - edge.sendRequest(this.service.websocket, request).then(response => { - const result = (response as QueryHistoricTimeseriesDataResponse)?.result; - if (Object.keys(result).length != 0) { - resolve(response as QueryHistoricTimeseriesDataResponse); - } else { - this.errorResponse = new JsonrpcResponseError(request.id, { code: 1, message: "Empty Result" }); - resolve(new QueryHistoricTimeseriesDataResponse(response.id, { - timestamps: [null], data: { null: null }, - })); - } - }).catch((response) => { - this.errorResponse = response; - this.initializeChart(); - }); - }); - }); - }).then((response) => { - - // Check if channelAddresses are empty - if (Utils.isDataEmpty(response)) { + if (this.debounceTimeout) { + clearTimeout(this.debounceTimeout); + } - // load defaultchart - this.isDataExisting = false; - this.initializeChart(); - } - return response; + return new Promise((resolve, reject) => { + this.service.getCurrentEdge() + .then(edge => this.service.getConfig() + .then(async () => { + const channelAddresses = (await this.getChannelAddresses()).powerChannels; + const request = new QueryHistoricTimeseriesDataRequest(DateUtils.maxDate(fromDate, this.edge?.firstSetupProtocol), toDate, channelAddresses, resolution); + + this.debounceTimeout = setTimeout(() => { + edge.sendRequest(this.service.websocket, request) + .then(response => { + const result = (response as QueryHistoricTimeseriesDataResponse)?.result; + let responseToReturn: QueryHistoricTimeseriesDataResponse; + + if (Object.keys(result).length !== 0) { + responseToReturn = response as QueryHistoricTimeseriesDataResponse; + } else { + this.errorResponse = new JsonrpcResponseError(request.id, { code: 1, message: "Empty Result" }); + responseToReturn = new QueryHistoricTimeseriesDataResponse(response.id, { + timestamps: [null], + data: { null: null }, + }); + } + + if (Utils.isDataEmpty(responseToReturn)) { + this.isDataExisting = false; + this.initializeChart(); + } + resolve(responseToReturn); + }); + }, ChartConstants.REQUEST_TIMEOUT); + }), + ); }); - return result; + } /** @@ -1034,7 +1043,7 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { this.datasets = HistoryUtils.createEmptyDataset(this.translate); this.labels = []; this.loading = false; - this.options.scales['y'] = { + this.options.scales["y"] = { display: false, }; diff --git a/ui/src/app/shared/components/chart/chart.constants.spec.ts b/ui/src/app/shared/components/chart/chart.constants.spec.ts index 275330f89a6..2e38cb4cbe7 100644 --- a/ui/src/app/shared/components/chart/chart.constants.spec.ts +++ b/ui/src/app/shared/components/chart/chart.constants.spec.ts @@ -2,11 +2,11 @@ import { ChartDataset } from "chart.js"; import { History } from "src/app/edge/history/common/energy/chart/channels.spec"; -import { ChartAxis, HistoryUtils, YAxisTitle } from "../../service/utils"; +import { ChartAxis, HistoryUtils, YAxisType } from "../../service/utils"; import { ChartConstants } from "./chart.constants"; -describe('Chart constants', () => { - it('#calculateStepSize', () => { +describe("Chart constants", () => { + it("#calculateStepSize", () => { expect(ChartConstants.calculateStepSize(0, 10)).toEqual(2.5); expect(ChartConstants.calculateStepSize(0, null)).toEqual(null); expect(ChartConstants.calculateStepSize(-10, 0)).toEqual(2.5); @@ -16,12 +16,12 @@ describe('Chart constants', () => { expect(ChartConstants.calculateStepSize(10, 0)).toEqual(null); }); - it('#getScaleOptions', () => { - const yAxis: HistoryUtils.yAxes = { unit: YAxisTitle.ENERGY, position: 'left', yAxisId: ChartAxis.LEFT }; + it("#getScaleOptions", () => { + const yAxis: HistoryUtils.yAxes = { unit: YAxisType.ENERGY, position: "left", yAxisId: ChartAxis.LEFT }; const datasets: ChartDataset[] = [ { - data: History.DAY.dataChannelWithValues.result.data['_sum/ConsumptionActivePower'], - label: 'consumption', + data: History.DAY.dataChannelWithValues.result.data["_sum/ConsumptionActivePower"], + label: "consumption", yAxisID: ChartAxis.LEFT, }, ]; diff --git a/ui/src/app/shared/components/chart/chart.constants.ts b/ui/src/app/shared/components/chart/chart.constants.ts index 67f26bc778e..93bf4dc58e7 100644 --- a/ui/src/app/shared/components/chart/chart.constants.ts +++ b/ui/src/app/shared/components/chart/chart.constants.ts @@ -3,7 +3,7 @@ import { ChartComponentLike, ChartDataset } from "chart.js"; import { formatNumber } from "@angular/common"; import { TranslateService } from "@ngx-translate/core"; -import ChartDataLabels from 'chartjs-plugin-datalabels'; +import ChartDataLabels from "chartjs-plugin-datalabels"; import { HistoryUtils, Utils } from "../../service/utils"; import { ArrayUtils } from "../../utils/array/array.utils"; import { AbstractHistoryChart } from "./abstracthistorychart"; @@ -11,23 +11,24 @@ import { AbstractHistoryChart } from "./abstracthistorychart"; export class ChartConstants { public static readonly NUMBER_OF_Y_AXIS_TICKS: number = 6; public static readonly EMPTY_DATASETS: ChartDataset[] = []; + public static readonly REQUEST_TIMEOUT = 500; public static Plugins = class { public static readonly DEFAULT_EMPTY_SCREEN: (text: string) => ChartComponentLike = (text) => ({ - id: 'empty_chart', + id: "empty_chart", beforeDraw: (chart, args, options) => { const { ctx } = <{ ctx: CanvasRenderingContext2D }>chart; ctx.save(); - ctx.textAlign = 'center'; - ctx.fillStyle = 'grey'; + ctx.textAlign = "center"; + ctx.fillStyle = "grey"; ctx.font = "1.5em serif"; ctx.fillText(text, chart.width / 2, chart.height / 2, chart.width); ctx.restore(); }, defaults: { - color: 'none', + color: "none", }, }); @@ -40,10 +41,10 @@ export class ChartConstants { public static readonly BAR_CHART_DATALABELS = (unit: string, disable: boolean): any => ({ ...ChartDataLabels, formatter: (value, ctx) => { - return formatNumber(value, 'de', '1.0-0') + '\xa0' + unit ?? null; + return formatNumber(value, "de", "1.0-0") + "\xa0" + unit ?? null; }, ...{ - anchor: 'end', offset: -18, align: 'start', clip: false, clamp: true, + anchor: "end", offset: -18, align: "start", clip: false, clamp: true, }, plugin: ChartDataLabels, display: disable, @@ -59,12 +60,12 @@ export class ChartConstants { * @param datasets the chart datasets * @returns scale options */ - public static DEFAULT_Y_SCALE_OPTIONS = (element: HistoryUtils.yAxes, translate: TranslateService, chartType: 'line' | 'bar', datasets: ChartDataset[], showYAxisTitle?: boolean) => { + public static DEFAULT_Y_SCALE_OPTIONS = (element: HistoryUtils.yAxes, translate: TranslateService, chartType: "line" | "bar", datasets: ChartDataset[], showYAxisTitle?: boolean) => { const beginAtZero: boolean = ChartConstants.isDataSeriesPositive(datasets); return { title: { - text: element.customTitle ?? AbstractHistoryChart.getYAxisTitle(element.unit, translate, chartType), + text: element.customTitle ?? AbstractHistoryChart.getYAxisType(element.unit, translate, chartType), display: showYAxisTitle, padding: 5, font: { @@ -77,7 +78,7 @@ export class ChartConstants { display: element.displayGrid ?? true, }, ticks: { - color: getComputedStyle(document.documentElement).getPropertyValue('--ion-color-text'), + color: getComputedStyle(document.documentElement).getPropertyValue("--ion-color-text"), padding: 5, maxTicksLimit: ChartConstants.NUMBER_OF_Y_AXIS_TICKS, }, @@ -93,7 +94,7 @@ export class ChartConstants { */ public static getScaleOptions(datasets: ChartDataset[], yAxis: HistoryUtils.yAxes): { min: number; max: number; stepSize: number; } | null { - return datasets?.filter(el => el['yAxisID'] === yAxis.yAxisId) + return datasets?.filter(el => el["yAxisID"] === yAxis.yAxisId) .reduce((arr, dataset) => { const min = Math.floor(Math.min(arr.min, ArrayUtils.findSmallestNumber(dataset.data as number[]))) ?? null; const max = Math.ceil(Math.max(arr.max, ArrayUtils.findBiggestNumber(dataset.data as number[]))) ?? null; diff --git a/ui/src/app/shared/components/chart/chart.module.ts b/ui/src/app/shared/components/chart/chart.module.ts index 63344695849..f86efd0b7df 100644 --- a/ui/src/app/shared/components/chart/chart.module.ts +++ b/ui/src/app/shared/components/chart/chart.module.ts @@ -21,7 +21,7 @@ import { ChartComponent } from "./chart"; NgChartsModule, CommonModule, NgxSpinnerModule.forRoot({ - type: 'ball-clip-rotate-multiple', + type: "ball-clip-rotate-multiple", }), HistoryDataErrorModule, RouterModule, diff --git a/ui/src/app/shared/components/chart/chart.ts b/ui/src/app/shared/components/chart/chart.ts index ad4e7311a1d..d2633c16f14 100644 --- a/ui/src/app/shared/components/chart/chart.ts +++ b/ui/src/app/shared/components/chart/chart.ts @@ -9,12 +9,12 @@ import { DefaultTypes } from "../../service/defaulttypes"; import { Edge, Service } from "../../shared"; @Component({ - selector: 'oe-chart', - templateUrl: './chart.html', + selector: "oe-chart", + templateUrl: "./chart.html", }) export class ChartComponent implements OnInit, OnChanges { - @Input() public title: string = ''; + @Input() public title: string = ""; @Input() public showPhases: boolean | null = null; @Input() public showTotal: boolean | null = null; @Output() public setShowPhases: EventEmitter = new EventEmitter(); @@ -37,7 +37,7 @@ export class ChartComponent implements OnInit, OnChanges { ) { } ngOnInit() { - this.service.setCurrentComponent('', this.route).then(edge => { + this.service.getCurrentEdge().then(edge => { this.edge = edge; }); @@ -61,8 +61,8 @@ export class ChartComponent implements OnInit, OnChanges { await popover.present(); popover.onDidDismiss().then((data) => { - this.showPhases = data.role == 'Phases' ? data.data : this.showPhases; - this.showTotal = data.role == 'Total' ? data.data : this.showTotal; + this.showPhases = data.role == "Phases" ? data.data : this.showPhases; + this.showTotal = data.role == "Total" ? data.data : this.showTotal; this.setShowPhases.emit(this.showPhases); this.setShowTotal.emit(this.showTotal); }); diff --git a/ui/src/app/shared/components/components.module.ts b/ui/src/app/shared/components/components.module.ts index 70140d5549a..8e39c2dc74e 100644 --- a/ui/src/app/shared/components/components.module.ts +++ b/ui/src/app/shared/components/components.module.ts @@ -1,24 +1,24 @@ -import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; -import { ReactiveFormsModule } from '@angular/forms'; -import { BrowserModule } from '@angular/platform-browser'; -import { RouterModule } from '@angular/router'; -import { IonicModule } from '@ionic/angular'; -import { TranslateModule } from '@ngx-translate/core'; +import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from "@angular/core"; +import { ReactiveFormsModule } from "@angular/forms"; +import { BrowserModule } from "@angular/platform-browser"; +import { RouterModule } from "@angular/router"; +import { IonicModule } from "@ionic/angular"; +import { TranslateModule } from "@ngx-translate/core"; -import { PipeModule } from '../pipe/pipe'; -import { ChartModule } from './chart/chart.module'; -import { FlatWidgetComponent } from './flat/flat'; -import { FlatWidgetHorizontalLineComponent } from './flat/flat-widget-horizontal-line/flat-widget-horizontal-line'; -import { FlatWidgetLineDividerComponent } from './flat/flat-widget-line-divider/flat-widget-line-divider'; -import { FlatWidgetLineComponent } from './flat/flat-widget-line/flat-widget-line'; -import { FlatWidgetLineItemComponent } from './flat/flat-widget-line/flat-widget-line-item/flat-widget-line-item'; -import { FlatWidgetPercentagebarComponent } from './flat/flat-widget-percentagebar/flat-widget-percentagebar'; -import { FooterComponent } from './footer/footer'; -import { FooterNavigationModule } from './footer/subnavigation/footerNavigation.module'; -import { HistoryDataErrorModule } from './history-data-error/history-data-error.module'; -import { ModalModule } from './modal/modal.module'; -import { PickdateModule } from './pickdate/pickdate.module'; -import { NotificationComponent } from './shared/notification/notification'; +import { PipeModule } from "../pipe/pipe"; +import { ChartModule } from "./chart/chart.module"; +import { FlatWidgetComponent } from "./flat/flat"; +import { FlatWidgetHorizontalLineComponent } from "./flat/flat-widget-horizontal-line/flat-widget-horizontal-line"; +import { FlatWidgetLineDividerComponent } from "./flat/flat-widget-line-divider/flat-widget-line-divider"; +import { FlatWidgetLineComponent } from "./flat/flat-widget-line/flat-widget-line"; +import { FlatWidgetLineItemComponent } from "./flat/flat-widget-line/flat-widget-line-item/flat-widget-line-item"; +import { FlatWidgetPercentagebarComponent } from "./flat/flat-widget-percentagebar/flat-widget-percentagebar"; +import { FooterComponent } from "./footer/footer"; +import { FooterNavigationModule } from "./footer/subnavigation/footerNavigation.module"; +import { HistoryDataErrorModule } from "./history-data-error/history-data-error.module"; +import { ModalModule } from "./modal/modal.module"; +import { PickdateModule } from "./pickdate/pickdate.module"; +import { NotificationComponent } from "./shared/notification/notification"; @NgModule({ imports: [ diff --git a/ui/src/app/shared/components/edge/currentdata.spec.ts b/ui/src/app/shared/components/edge/currentdata.spec.ts index bb45316b2c0..feff8c76e70 100644 --- a/ui/src/app/shared/components/edge/currentdata.spec.ts +++ b/ui/src/app/shared/components/edge/currentdata.spec.ts @@ -1,55 +1,55 @@ -import { CurrentData } from './currentdata'; +import { CurrentData } from "./currentdata"; export function expectRatioToEqual(maxApparentPower: number | null, minDischargePower: number | null, effectivePower: number | null, result: number | null): void { expect(CurrentData.getEssPowerRatio(maxApparentPower, minDischargePower, effectivePower)).toEqual(result); } -describe('CurrentData', () => { - describe('#getEssPowerRatio', () => { +describe("CurrentData", () => { + describe("#getEssPowerRatio", () => { - it('should return the correct power ratio when effectivePower is positive', () => { + it("should return the correct power ratio when effectivePower is positive", () => { const maxApparentPower = 10000; const minDischargePower = -5000; expectRatioToEqual(maxApparentPower, minDischargePower, 2500, 0.25); }); - it('should return the correct power ratio when effectivePower is positive - different version', () => { + it("should return the correct power ratio when effectivePower is positive - different version", () => { const maxApparentPower = 10000; const minDischargePower = -3000; expectRatioToEqual(maxApparentPower, minDischargePower, 1000, 0.1); }); - it('should return 0 when effectivePower is null', () => { + it("should return 0 when effectivePower is null", () => { const maxApparentPower = 10000; const minDischargePower = -3000; expectRatioToEqual(maxApparentPower, minDischargePower, null, 0); }); - it('should return 0 when effectivePower is 0', () => { + it("should return 0 when effectivePower is 0", () => { const maxApparentPower = 10000; const minDischargePower = -3000; expectRatioToEqual(maxApparentPower, minDischargePower, 0, 0); }); - it('should handle negative effectivePower according to minDischargePower', () => { + it("should handle negative effectivePower according to minDischargePower", () => { const maxApparentPower = 10000; const minDischargePower = -5000; expectRatioToEqual(maxApparentPower, minDischargePower, -1000, -0.2); }); - it('should fall back to maxApparentPower if minDischargePower is not relevant', () => { + it("should fall back to maxApparentPower if minDischargePower is not relevant", () => { const maxApparentPower = 10000; const minDischargePower = 0; expectRatioToEqual(maxApparentPower, minDischargePower, -1000, 0); // Since minDischargePower is 0, we assume fall back to maxApparentPower }); - it('should return 0 when dividing by zero maxApparentPower', () => { + it("should return 0 when dividing by zero maxApparentPower", () => { const maxApparentPower = 0; const minDischargePower = -3000; expectRatioToEqual(maxApparentPower, minDischargePower, 1000, 0); }); - it('should return 0 when dividing by zero maxDischargePower with relevant edgeVersion', () => { + it("should return 0 when dividing by zero maxDischargePower with relevant edgeVersion", () => { const maxApparentPower = 10000; const minDischargePower = 0; expectRatioToEqual(maxApparentPower, minDischargePower, -1000, 0); diff --git a/ui/src/app/shared/components/edge/currentdata.ts b/ui/src/app/shared/components/edge/currentdata.ts index bdbd09b4be9..074b20ef8df 100644 --- a/ui/src/app/shared/components/edge/currentdata.ts +++ b/ui/src/app/shared/components/edge/currentdata.ts @@ -121,20 +121,20 @@ export class CurrentData { * > 0 => Buy from grid * < 0 => Sell to grid */ - const gridActivePower: number = c['_sum/GridActivePower']; - result.grid.activePowerL1 = c['_sum/GridActivePowerL1']; - result.grid.activePowerL2 = c['_sum/GridActivePowerL2']; - result.grid.activePowerL3 = c['_sum/GridActivePowerL3']; - result.grid.maxBuyActivePower = c['_sum/GridMaxActivePower']; + const gridActivePower: number = c["_sum/GridActivePower"]; + result.grid.activePowerL1 = c["_sum/GridActivePowerL1"]; + result.grid.activePowerL2 = c["_sum/GridActivePowerL2"]; + result.grid.activePowerL3 = c["_sum/GridActivePowerL3"]; + result.grid.maxBuyActivePower = c["_sum/GridMaxActivePower"]; if (!result.grid.maxBuyActivePower) { result.grid.maxBuyActivePower = 5000; } - result.grid.maxSellActivePower = c['_sum/GridMinActivePower'] * -1; + result.grid.maxSellActivePower = c["_sum/GridMinActivePower"] * -1; if (!result.grid.maxSellActivePower) { result.grid.maxSellActivePower = -5000; } - result.grid.gridMode = c['_sum/GridMode']; - result.grid.restrictionMode = c['ctrlEssLimiter14a0/RestrictionMode']; + result.grid.gridMode = c["_sum/GridMode"]; + result.grid.restrictionMode = c["ctrlEssLimiter14a0/RestrictionMode"]; if (gridActivePower > 0) { result.grid.sellActivePower = 0; result.grid.buyActivePower = gridActivePower; @@ -150,17 +150,17 @@ export class CurrentData { /* * Production */ - result.production.activePowerAc = c['_sum/ProductionAcActivePower']; - result.production.activePowerAcL1 = c['_sum/ProductionAcActivePowerL1']; - result.production.activePowerAcL2 = c['_sum/ProductionAcActivePowerL2']; - result.production.activePowerAcL3 = c['_sum/ProductionAcActivePowerL3']; - result.production.activePower = c['_sum/ProductionActivePower']; - result.production.maxActivePower = c['_sum/ProductionMaxActivePower']; + result.production.activePowerAc = c["_sum/ProductionAcActivePower"]; + result.production.activePowerAcL1 = c["_sum/ProductionAcActivePowerL1"]; + result.production.activePowerAcL2 = c["_sum/ProductionAcActivePowerL2"]; + result.production.activePowerAcL3 = c["_sum/ProductionAcActivePowerL3"]; + result.production.activePower = c["_sum/ProductionActivePower"]; + result.production.maxActivePower = c["_sum/ProductionMaxActivePower"]; if (!result.production.maxActivePower) { result.production.maxActivePower = 10000; } result.production.powerRatio = Utils.orElse(Utils.divideSafely(result.production.activePower, result.production.maxActivePower), 0); - result.production.activePowerDc = c['_sum/ProductionDcActualPower']; + result.production.activePowerDc = c["_sum/ProductionDcActualPower"]; } { @@ -169,18 +169,18 @@ export class CurrentData { * > 0 => Discharge * < 0 => Charge */ - result.storage.soc = c['_sum/EssSoc']; - result.storage.activePowerL1 = c['_sum/EssActivePowerL1']; - result.storage.activePowerL2 = c['_sum/EssActivePowerL2']; - result.storage.activePowerL3 = c['_sum/EssActivePowerL3']; - result.storage.maxApparentPower = c['_sum/EssMaxApparentPower']; - result.storage.capacity = c['_sum/EssCapacity']; - const essActivePower: number = c['_sum/EssActivePower']; + result.storage.soc = c["_sum/EssSoc"]; + result.storage.activePowerL1 = c["_sum/EssActivePowerL1"]; + result.storage.activePowerL2 = c["_sum/EssActivePowerL2"]; + result.storage.activePowerL3 = c["_sum/EssActivePowerL3"]; + result.storage.maxApparentPower = c["_sum/EssMaxApparentPower"]; + result.storage.capacity = c["_sum/EssCapacity"]; + const essActivePower: number = c["_sum/EssActivePower"]; if (!result.storage.maxApparentPower) { result.storage.maxApparentPower = 5000; } - result.storage.chargeActivePowerDc = c['_sum/ProductionDcActualPower']; + result.storage.chargeActivePowerDc = c["_sum/ProductionDcActualPower"]; if (essActivePower == null) { // keep 'null' } else if (essActivePower > 0) { @@ -240,11 +240,11 @@ export class CurrentData { /* * Consumption */ - result.consumption.activePower = c['_sum/ConsumptionActivePower']; - result.consumption.activePowerL1 = c['_sum/ConsumptionActivePowerL1']; - result.consumption.activePowerL2 = c['_sum/ConsumptionActivePowerL2']; - result.consumption.activePowerL3 = c['_sum/ConsumptionActivePowerL3']; - let consumptionMaxActivePower = c['_sum/ConsumptionMaxActivePower']; + result.consumption.activePower = c["_sum/ConsumptionActivePower"]; + result.consumption.activePowerL1 = c["_sum/ConsumptionActivePowerL1"]; + result.consumption.activePowerL2 = c["_sum/ConsumptionActivePowerL2"]; + result.consumption.activePowerL3 = c["_sum/ConsumptionActivePowerL3"]; + let consumptionMaxActivePower = c["_sum/ConsumptionMaxActivePower"]; if (!consumptionMaxActivePower) { consumptionMaxActivePower = 10000; } @@ -273,7 +273,7 @@ export class CurrentData { result.system.autarchy = CurrentData.calculateAutarchy(result.grid.buyActivePower, result.consumption.activePower); result.system.selfConsumption = Utils.calculateSelfConsumption(result.grid.sellActivePower, result.production.activePower); // State - result.system.state = c['_sum/State']; + result.system.state = c["_sum/State"]; } return result; } diff --git a/ui/src/app/shared/components/edge/edge.spec.ts b/ui/src/app/shared/components/edge/edge.spec.ts index c8433fb5cd0..4ec20ab0fe9 100644 --- a/ui/src/app/shared/components/edge/edge.spec.ts +++ b/ui/src/app/shared/components/edge/edge.spec.ts @@ -7,8 +7,8 @@ import { Websocket } from "../../shared"; import { EdgeConfig } from "./edgeconfig"; import { DummyConfig } from "./edgeconfig.spec"; -describe('Edge', () => { - const websocketSpyObject = jasmine.createSpyObj('Websocket', ['sendRequest']); +describe("Edge", () => { + const websocketSpyObject = jasmine.createSpyObj("Websocket", ["sendRequest"]); let websocket: Websocket; beforeEach(() => { @@ -20,13 +20,13 @@ describe('Edge', () => { websocket = TestBed.inject(Websocket); }); - it('#getFactoryPropertiesOldVersion', async () => { - const edge = DummyConfig.dummyEdge({ version: '2024.1.1' }); + it("#getFactoryPropertiesOldVersion", async () => { + const edge = DummyConfig.dummyEdge({ version: "2024.1.1" }); - const dummyConfig = DummyConfig.from(DummyConfig.Component.EVCS_KEBA_KECONTACT('evcs0')); + const dummyConfig = DummyConfig.from(DummyConfig.Component.EVCS_KEBA_KECONTACT("evcs0")); dummyConfig.factories[DummyConfig.Factory.EVCS_KEBA_KECONTACT.id].properties.push(new EdgeConfig.FactoryProperty()); - websocketSpyObject.sendRequest.and.resolveTo(new JsonrpcResponseSuccess('', { - payload: new GetEdgeConfigResponse('', dummyConfig), + websocketSpyObject.sendRequest.and.resolveTo(new JsonrpcResponseSuccess("", { + payload: new GetEdgeConfigResponse("", dummyConfig), })); const [factory, properties] = await edge.getFactoryProperties(websocket, DummyConfig.Factory.EVCS_KEBA_KECONTACT.id); @@ -34,20 +34,20 @@ describe('Edge', () => { expect(properties).toBe(dummyConfig.factories[DummyConfig.Factory.EVCS_KEBA_KECONTACT.id].properties); }); - it('#getFactoryPropertiesNewVersion', async () => { - const edge = DummyConfig.dummyEdge({ version: '2024.6.1' }); + it("#getFactoryPropertiesNewVersion", async () => { + const edge = DummyConfig.dummyEdge({ version: "2024.6.1" }); - const dummmyFactory = new EdgeConfig.Factory('dummy.factory.id', 'description'); + const dummmyFactory = new EdgeConfig.Factory("dummy.factory.id", "description"); const dummyProperties: EdgeConfig.FactoryProperty[] = [new EdgeConfig.FactoryProperty()]; - websocketSpyObject.sendRequest.and.resolveTo(new JsonrpcResponseSuccess('', { - payload: new GetPropertiesOfFactoryResponse('', { + websocketSpyObject.sendRequest.and.resolveTo(new JsonrpcResponseSuccess("", { + payload: new GetPropertiesOfFactoryResponse("", { factory: dummmyFactory, properties: dummyProperties, }), })); - const [factory, properties] = await edge.getFactoryProperties(websocket, 'dummy.factory.id'); + const [factory, properties] = await edge.getFactoryProperties(websocket, "dummy.factory.id"); expect(factory).toBe(dummmyFactory); expect(properties).toBe(dummyProperties); }); diff --git a/ui/src/app/shared/components/edge/edge.ts b/ui/src/app/shared/components/edge/edge.ts index 55ede05a5cf..babbb91da9e 100644 --- a/ui/src/app/shared/components/edge/edge.ts +++ b/ui/src/app/shared/components/edge/edge.ts @@ -1,32 +1,32 @@ // @ts-strict-ignore -import { compareVersions } from 'compare-versions'; -import { BehaviorSubject, Subject } from 'rxjs'; -import { filter, first } from 'rxjs/operators'; -import { SumState } from 'src/app/index/shared/sumState'; -import { JsonrpcRequest, JsonrpcResponseSuccess } from '../../jsonrpc/base'; -import { CurrentDataNotification } from '../../jsonrpc/notification/currentDataNotification'; -import { EdgeConfigNotification } from '../../jsonrpc/notification/edgeConfigNotification'; -import { SystemLogNotification } from '../../jsonrpc/notification/systemLogNotification'; -import { ComponentJsonApiRequest } from '../../jsonrpc/request/componentJsonApiRequest'; -import { CreateComponentConfigRequest } from '../../jsonrpc/request/createComponentConfigRequest'; -import { DeleteComponentConfigRequest } from '../../jsonrpc/request/deleteComponentConfigRequest'; -import { EdgeRpcRequest } from '../../jsonrpc/request/edgeRpcRequest'; -import { GetChannelRequest } from '../../jsonrpc/request/getChannelRequest'; -import { GetChannelsOfComponentRequest } from '../../jsonrpc/request/getChannelsOfComponentRequest'; -import { GetEdgeConfigRequest } from '../../jsonrpc/request/getEdgeConfigRequest'; -import { GetPropertiesOfFactoryRequest } from '../../jsonrpc/request/getPropertiesOfFactoryRequest'; -import { SubscribeChannelsRequest } from '../../jsonrpc/request/subscribeChannelsRequest'; -import { SubscribeSystemLogRequest } from '../../jsonrpc/request/subscribeSystemLogRequest'; -import { UpdateComponentConfigRequest } from '../../jsonrpc/request/updateComponentConfigRequest'; -import { GetChannelResponse } from '../../jsonrpc/response/getChannelResponse'; -import { Channel, GetChannelsOfComponentResponse } from '../../jsonrpc/response/getChannelsOfComponentResponse'; -import { GetEdgeConfigResponse } from '../../jsonrpc/response/getEdgeConfigResponse'; -import { GetPropertiesOfFactoryResponse } from '../../jsonrpc/response/getPropertiesOfFactoryResponse'; -import { ArrayUtils } from '../../service/arrayutils'; -import { ChannelAddress, EdgePermission, SystemLog, Websocket } from '../../shared'; -import { Role } from '../../type/role'; -import { CurrentData } from './currentdata'; -import { EdgeConfig } from './edgeconfig'; +import { compareVersions } from "compare-versions"; +import { BehaviorSubject, Subject } from "rxjs"; +import { filter, first } from "rxjs/operators"; +import { SumState } from "src/app/index/shared/sumState"; +import { JsonrpcRequest, JsonrpcResponseSuccess } from "../../jsonrpc/base"; +import { CurrentDataNotification } from "../../jsonrpc/notification/currentDataNotification"; +import { EdgeConfigNotification } from "../../jsonrpc/notification/edgeConfigNotification"; +import { SystemLogNotification } from "../../jsonrpc/notification/systemLogNotification"; +import { ComponentJsonApiRequest } from "../../jsonrpc/request/componentJsonApiRequest"; +import { CreateComponentConfigRequest } from "../../jsonrpc/request/createComponentConfigRequest"; +import { DeleteComponentConfigRequest } from "../../jsonrpc/request/deleteComponentConfigRequest"; +import { EdgeRpcRequest } from "../../jsonrpc/request/edgeRpcRequest"; +import { GetChannelRequest } from "../../jsonrpc/request/getChannelRequest"; +import { GetChannelsOfComponentRequest } from "../../jsonrpc/request/getChannelsOfComponentRequest"; +import { GetEdgeConfigRequest } from "../../jsonrpc/request/getEdgeConfigRequest"; +import { GetPropertiesOfFactoryRequest } from "../../jsonrpc/request/getPropertiesOfFactoryRequest"; +import { SubscribeChannelsRequest } from "../../jsonrpc/request/subscribeChannelsRequest"; +import { SubscribeSystemLogRequest } from "../../jsonrpc/request/subscribeSystemLogRequest"; +import { UpdateComponentConfigRequest } from "../../jsonrpc/request/updateComponentConfigRequest"; +import { GetChannelResponse } from "../../jsonrpc/response/getChannelResponse"; +import { Channel, GetChannelsOfComponentResponse } from "../../jsonrpc/response/getChannelsOfComponentResponse"; +import { GetEdgeConfigResponse } from "../../jsonrpc/response/getEdgeConfigResponse"; +import { GetPropertiesOfFactoryResponse } from "../../jsonrpc/response/getPropertiesOfFactoryResponse"; +import { ArrayUtils } from "../../service/arrayutils"; +import { ChannelAddress, EdgePermission, SystemLog, Websocket } from "../../shared"; +import { Role } from "../../type/role"; +import { CurrentData } from "./currentdata"; +import { EdgeConfig } from "./edgeconfig"; export class Edge { @@ -104,7 +104,7 @@ export class Edge { } const response = await this.sendRequest(websocket, new ComponentJsonApiRequest({ - componentId: '_componentManager', + componentId: "_componentManager", payload: new GetChannelRequest({ componentId: channel.componentId, channelId: channel.channelId, @@ -127,7 +127,7 @@ export class Edge { const config = await this.getFirstValidConfig(websocket); const component = config.components[componentId]; if (!component) { - throw new Error('Component not found'); + throw new Error("Component not found"); } return Object.entries(component.channels).reduce((p, c) => { return [...p, { id: c[0], ...c[1] }]; @@ -135,7 +135,7 @@ export class Edge { } const response = await this.sendRequest(websocket, new ComponentJsonApiRequest({ - componentId: '_componentManager', + componentId: "_componentManager", payload: new GetChannelsOfComponentRequest({ componentId: componentId }), })); @@ -145,7 +145,7 @@ export class Edge { public async getFactoryProperties(websocket: Websocket, factoryId: string): Promise<[EdgeConfig.Factory, EdgeConfig.FactoryProperty[]]> { if (EdgePermission.hasReducedFactories(this)) { const response = await this.sendRequest(websocket, new ComponentJsonApiRequest({ - componentId: '_componentManager', + componentId: "_componentManager", payload: new GetPropertiesOfFactoryRequest({ factoryId }), })); return [response.result.factory, response.result.properties]; @@ -317,7 +317,7 @@ export class Edge { const wrap = new EdgeRpcRequest({ edgeId: this.id, payload: request }); return new Promise((resolve, reject) => { ws.sendRequest(wrap).then(response => { - resolve(response['result']['payload']); + resolve(response["result"]["payload"]); }).catch(reason => { reject(reason); }); diff --git a/ui/src/app/shared/components/edge/edgeconfig.spec.ts b/ui/src/app/shared/components/edge/edgeconfig.spec.ts index 9e9545fb627..8921e4235d6 100644 --- a/ui/src/app/shared/components/edge/edgeconfig.spec.ts +++ b/ui/src/app/shared/components/edge/edgeconfig.spec.ts @@ -43,7 +43,7 @@ export namespace DummyConfig { return ({ ...acc, [c.id]: c }); }, {}), factories: components?.reduce((p, c) => { - p[c.factory.id] = new EdgeConfig.Factory(c.factory.id, '', c.factory.natureIds); + p[c.factory.id] = new EdgeConfig.Factory(c.factory.id, "", c.factory.natureIds); return p; }, {}), }); @@ -189,7 +189,7 @@ export namespace DummyConfig { export const EVCS_HARDY_BARTH = (id: string, alias?: string): Component => ({ id: id, alias: alias ?? id, - factoryId: 'Evcs.HardyBarth', + factoryId: "Evcs.HardyBarth", factory: Factory.EVCS_HARDY_BARTH, properties: { enabled: "true", @@ -200,7 +200,7 @@ export namespace DummyConfig { export const SOCOMEC_GRID_METER = (id: string, alias?: string): Component => ({ id: id, alias: alias ?? id, - factoryId: 'Meter.Socomec.Threephase', + factoryId: "Meter.Socomec.Threephase", factory: Factory.METER_SOCOMEC_THREEPHASE, properties: { invert: false, @@ -250,7 +250,7 @@ export namespace DummyConfig { export const SOLAR_EDGE_PV_INVERTER = (id: string, alias?: string): Component => ({ id: id, alias: alias ?? id, - factoryId: 'SolarEdge.PV-Inverter', + factoryId: "SolarEdge.PV-Inverter", factory: Factory.SOLAR_EDGE_PV_INVERTER, properties: { invert: false, @@ -263,7 +263,7 @@ export namespace DummyConfig { export const ESS_GENERIC_MANAGEDSYMMETRIC = (id: string, alias?: string): Component => ({ id: id, alias: alias ?? id, - factoryId: 'Ess.Generic.ManagedSymmetric', + factoryId: "Ess.Generic.ManagedSymmetric", factory: Factory.ESS_GENERIC_MANAGEDSYMMETRIC, properties: { invert: false, @@ -384,22 +384,22 @@ export const LINE_INFO = (text: string): OeFormlyViewTester.Field => ({ export namespace ChartConfig { - export const LINE_CHART_OPTIONS = (period: string, chartType: 'line' | 'bar', labelString?: string): OeChartTester.Dataset.Option => ({ - type: 'option', - options: { "responsive": true, "maintainAspectRatio": false, "elements": { "point": { "radius": 0, "hitRadius": 0, "hoverRadius": 0 }, "line": { "stepped": false, "fill": true } }, "datasets": { "bar": {}, "line": {} }, "plugins": { "colors": { "enabled": false }, "legend": { "display": true, "position": "bottom", "labels": { "color": '' } }, "tooltip": { "intersect": false, "mode": "index", "callbacks": {} } }, "scales": { "x": { "stacked": true, "offset": false, "type": "time", "ticks": { "source": "auto", "maxTicksLimit": 31 }, "bounds": "ticks", "adapters": { "date": { "locale": { "code": "de", "formatLong": {}, "localize": {}, "match": {}, "options": { "weekStartsOn": 1, "firstWeekContainsDate": 4 } } } }, "time": { "unit": period as TimeUnit, "displayFormats": { "datetime": "yyyy-MM-dd HH:mm:ss", "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" } } }, "left": { ...(chartType === 'line' ? { stacked: false } : {}), "title": { "text": "kW", "display": true, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, "ticks": {} } } }, + export const LINE_CHART_OPTIONS = (period: string, chartType: "line" | "bar", labelString?: string): OeChartTester.Dataset.Option => ({ + type: "option", + options: { "responsive": true, "maintainAspectRatio": false, "elements": { "point": { "radius": 0, "hitRadius": 0, "hoverRadius": 0 }, "line": { "stepped": false, "fill": true } }, "datasets": { "bar": {}, "line": {} }, "plugins": { "colors": { "enabled": false }, "legend": { "display": true, "position": "bottom", "labels": { "color": "" } }, "tooltip": { "intersect": false, "mode": "index", "callbacks": {} } }, "scales": { "x": { "stacked": true, "offset": false, "type": "time", "ticks": { "source": "auto", "maxTicksLimit": 31 }, "bounds": "ticks", "adapters": { "date": { "locale": { "code": "de", "formatLong": {}, "localize": {}, "match": {}, "options": { "weekStartsOn": 1, "firstWeekContainsDate": 4 } } } }, "time": { "unit": period as TimeUnit, "displayFormats": { "datetime": "yyyy-MM-dd HH:mm:ss", "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" } } }, "left": { ...(chartType === "line" ? { stacked: false } : {}), "title": { "text": "kW", "display": true, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, "ticks": {} } } }, }); - export const BAR_CHART_OPTIONS = (period: string, chartType: 'line' | 'bar', labelString?: string): OeChartTester.Dataset.Option => ({ - type: 'option', options: { - "responsive": true, "maintainAspectRatio": false, "elements": { "point": { "radius": 0, "hitRadius": 0, "hoverRadius": 0 }, "line": { "stepped": false, "fill": true } }, "datasets": { "bar": { "barPercentage": 1 }, "line": {} }, "plugins": { "colors": { "enabled": false }, "legend": { "display": true, "position": "bottom", "labels": { "color": '' } }, "tooltip": { "intersect": false, "mode": "x", "callbacks": {} } }, "scales": { - "x": { "stacked": true, "offset": true, "type": "time", "ticks": { "source": "auto", "maxTicksLimit": 31 }, "bounds": "ticks", "adapters": { "date": { "locale": { "code": "de", "formatLong": {}, "localize": {}, "match": {}, "options": { "weekStartsOn": 1, "firstWeekContainsDate": 4 } } } }, "time": { "unit": period as TimeUnit, "displayFormats": { "datetime": "yyyy-MM-dd HH:mm:ss", "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" } } }, "left": { ...(chartType === 'line' ? { stacked: false } : {}), "title": { "text": "kWh", "display": true, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, "ticks": {} }, + export const BAR_CHART_OPTIONS = (period: string, chartType: "line" | "bar", labelString?: string): OeChartTester.Dataset.Option => ({ + type: "option", options: { + "responsive": true, "maintainAspectRatio": false, "elements": { "point": { "radius": 0, "hitRadius": 0, "hoverRadius": 0 }, "line": { "stepped": false, "fill": true } }, "datasets": { "bar": { "barPercentage": 1 }, "line": {} }, "plugins": { "colors": { "enabled": false }, "legend": { "display": true, "position": "bottom", "labels": { "color": "" } }, "tooltip": { "intersect": false, "mode": "x", "callbacks": {} } }, "scales": { + "x": { "stacked": true, "offset": true, "type": "time", "ticks": { "source": "auto", "maxTicksLimit": 31 }, "bounds": "ticks", "adapters": { "date": { "locale": { "code": "de", "formatLong": {}, "localize": {}, "match": {}, "options": { "weekStartsOn": 1, "firstWeekContainsDate": 4 } } } }, "time": { "unit": period as TimeUnit, "displayFormats": { "datetime": "yyyy-MM-dd HH:mm:ss", "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" } } }, "left": { ...(chartType === "line" ? { stacked: false } : {}), "title": { "text": "kWh", "display": true, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, "ticks": {} }, }, }, }); } -describe('PersistencePriority', () => { - it('#isLessThan', () => { +describe("PersistencePriority", () => { + it("#isLessThan", () => { expect(PersistencePriority.isLessThan(PersistencePriority.LOW, PersistencePriority.HIGH)).toBe(true); expect(PersistencePriority.isLessThan(PersistencePriority.VERY_HIGH, PersistencePriority.HIGH)).toBe(false); expect(PersistencePriority.isLessThan(PersistencePriority.HIGH, PersistencePriority.HIGH)).toBe(false); diff --git a/ui/src/app/shared/components/edge/edgeconfig.ts b/ui/src/app/shared/components/edge/edgeconfig.ts index 020caa6d9eb..c06af3db4ac 100644 --- a/ui/src/app/shared/components/edge/edgeconfig.ts +++ b/ui/src/app/shared/components/edge/edgeconfig.ts @@ -1,5 +1,5 @@ -import { ChannelAddress, Widgets } from '../../shared'; -import { Edge } from './edge'; +import { ChannelAddress, Widgets } from "../../shared"; +import { Edge } from "./edge"; export interface CategorizedComponents { category: { @@ -49,8 +49,8 @@ export class EdgeConfig { for (const componentId in this.components) { const component = this.components[componentId]; component.id = componentId; - if ('enabled' in component.properties) { - component.isEnabled = component.properties['enabled']; + if ("enabled" in component.properties) { + component.isEnabled = component.properties["enabled"]; } else { component.isEnabled = true; } @@ -106,13 +106,13 @@ export class EdgeConfig { public static listAvailableFactories(factories: { [id: string]: EdgeConfig.Factory }): CategorizedFactories[] { const allFactories: CategorizedFactories[] = [ { - category: { title: 'Simulatoren', icon: 'flask-outline' }, + category: { title: "Simulatoren", icon: "flask-outline" }, factories: Object.entries(factories) - .filter(([factory]) => factory.startsWith('Simulator.')) + .filter(([factory]) => factory.startsWith("Simulator.")) .map(e => e[1]), }, { - category: { title: 'Zähler', icon: 'speedometer-outline' }, + category: { title: "Zähler", icon: "speedometer-outline" }, factories: [ EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.meter.api.SymmetricMeter"), // TODO replaced by ElectricityMeter EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.meter.api.ElectricityMeter"), @@ -120,7 +120,7 @@ export class EdgeConfig { ].flat(2), }, { - category: { title: 'Speichersysteme', icon: 'battery-charging-outline' }, + category: { title: "Speichersysteme", icon: "battery-charging-outline" }, factories: [ EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.ess.api.SymmetricEss"), EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.battery.api.Battery"), @@ -128,7 +128,7 @@ export class EdgeConfig { ].flat(2), }, { - category: { title: 'Speichersystem-Steuerung', icon: 'options-outline' }, + category: { title: "Speichersystem-Steuerung", icon: "options-outline" }, factories: [ EdgeConfig.getFactoriesByIdsPattern(factories, [ /Controller\.Asymmetric.*/, @@ -138,86 +138,86 @@ export class EdgeConfig { ].flat(2), }, { - category: { title: 'E-Auto-Ladestation', icon: 'car-outline' }, + category: { title: "E-Auto-Ladestation", icon: "car-outline" }, factories: [ EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.evcs.api.Evcs"), ].flat(2), }, { - category: { title: 'E-Auto-Ladestation-Steuerung', icon: 'options-outline' }, + category: { title: "E-Auto-Ladestation-Steuerung", icon: "options-outline" }, factories: [ EdgeConfig.getFactoriesByIds(factories, [ - 'Controller.Evcs', + "Controller.Evcs", ]), ].flat(2), }, { - category: { title: 'I/Os', icon: 'log-in-outline' }, + category: { title: "I/Os", icon: "log-in-outline" }, factories: [ EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.io.api.DigitalOutput"), EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.io.api.DigitalInput"), ].flat(2), }, { - category: { title: 'I/O-Steuerung', icon: 'options-outline' }, + category: { title: "I/O-Steuerung", icon: "options-outline" }, factories: [ EdgeConfig.getFactoriesByIds(factories, [ - 'Controller.IO.ChannelSingleThreshold', - 'Controller.Io.FixDigitalOutput', - 'Controller.IO.HeatingElement', - 'Controller.Io.HeatPump.SgReady', + "Controller.IO.ChannelSingleThreshold", + "Controller.Io.FixDigitalOutput", + "Controller.IO.HeatingElement", + "Controller.Io.HeatPump.SgReady", ]), ].flat(2), }, { - category: { title: 'Temperatursensoren', icon: 'thermometer-outline' }, + category: { title: "Temperatursensoren", icon: "thermometer-outline" }, factories: [ EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.thermometer.api.Thermometer"), ].flat(2), }, { - category: { title: 'Externe Schnittstellen', icon: 'megaphone-outline' }, + category: { title: "Externe Schnittstellen", icon: "megaphone-outline" }, factories: [ EdgeConfig.getFactoriesByIds(factories, [ - 'Controller.Api.Websocket', - 'Controller.Api.ModbusTcp', - 'Controller.Api.ModbusTcp.ReadOnly', - 'Controller.Api.ModbusTcp.ReadWrite', - 'Controller.Api.MQTT', - 'Controller.Api.Rest.ReadOnly', - 'Controller.Api.Rest.ReadWrite', + "Controller.Api.Websocket", + "Controller.Api.ModbusTcp", + "Controller.Api.ModbusTcp.ReadOnly", + "Controller.Api.ModbusTcp.ReadWrite", + "Controller.Api.MQTT", + "Controller.Api.Rest.ReadOnly", + "Controller.Api.Rest.ReadWrite", ]), ].flat(2), }, { - category: { title: 'Cloud-Schnittstellen', icon: 'cloud-outline' }, + category: { title: "Cloud-Schnittstellen", icon: "cloud-outline" }, factories: [ EdgeConfig.getFactoriesByIdsPattern(factories, [ /TimeOfUseTariff\.*/, ]), EdgeConfig.getFactoriesByIds(factories, [ - 'Controller.Api.Backend', + "Controller.Api.Backend", ]), ].flat(2), }, { - category: { title: 'Geräte-Schnittstellen', icon: 'swap-horizontal-outline' }, + category: { title: "Geräte-Schnittstellen", icon: "swap-horizontal-outline" }, factories: [ EdgeConfig.getFactoriesByIds(factories, [ - 'Bridge.Mbus', - 'Bridge.Onewire', - 'Bridge.Modbus.Serial', - 'Bridge.Modbus.Tcp', - 'Kaco.BlueplanetHybrid10.Core', + "Bridge.Mbus", + "Bridge.Onewire", + "Bridge.Modbus.Serial", + "Bridge.Modbus.Tcp", + "Kaco.BlueplanetHybrid10.Core", ]), ].flat(2), }, { - category: { title: 'Standard-Komponenten', icon: 'resize-outline' }, + category: { title: "Standard-Komponenten", icon: "resize-outline" }, factories: [ EdgeConfig.getFactoriesByIds(factories, [ - 'Controller.Debug.Log', - 'Controller.Debug.DetailedLog', + "Controller.Debug.Log", + "Controller.Debug.DetailedLog", ]), EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.timedata.api.Timedata"), EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.predictor.api.oneday.Predictor24Hours"), @@ -225,13 +225,13 @@ export class EdgeConfig { ].flat(2), }, { - category: { title: 'Spezial-Controller', icon: 'repeat-outline' }, + category: { title: "Spezial-Controller", icon: "repeat-outline" }, factories: [ EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.controller.api.Controller"), ].flat(2), }, { - category: { title: 'Weitere', icon: 'radio-button-off-outline' }, + category: { title: "Weitere", icon: "radio-button-off-outline" }, factories: Object.values(factories), }, ]; @@ -370,6 +370,21 @@ export class EdgeConfig { return result; } + /** + * Gets the Component Ids by the given Factories. + * + * @param factoryIds the Factory PIDs. + * @returns the component Ids + */ + public getComponentIdsByFactories(...factoryIds: string[]): string[] { + const componentIds: string[] = []; + + for (const factory of factoryIds) { + componentIds.push(...this.getComponentIdsByFactory(factory)); + } + return componentIds; + } + /** * Get Component-IDs of Components that implement the given Nature. * @@ -449,7 +464,7 @@ export class EdgeConfig { * Determines if Edge has a Storage device */ public hasStorage(): boolean { - if (this.getComponentIdsImplementingNature('io.openems.edge.ess.api.SymmetricEss').length > 0) { + if (this.getComponentIdsImplementingNature("io.openems.edge.ess.api.SymmetricEss").length > 0) { return true; } else { return false; @@ -460,7 +475,7 @@ export class EdgeConfig { * Determines if Edge has a Meter device */ public hasMeter(): boolean { - if (this.getComponentIdsImplementingNature('io.openems.edge.meter.api.ElectricityMeter').length > 0) { + if (this.getComponentIdsImplementingNature("io.openems.edge.meter.api.ElectricityMeter").length > 0) { return true; } else { return false; @@ -472,7 +487,7 @@ export class EdgeConfig { */ public hasProducer(): boolean { // Do we have a Ess DC Charger? - if (this.getComponentsImplementingNature('io.openems.edge.ess.dccharger.api.EssDcCharger').length > 0) { + if (this.getComponentsImplementingNature("io.openems.edge.ess.dccharger.api.EssDcCharger").length > 0) { return true; } // Do we have a Meter with type PRODUCTION? @@ -491,25 +506,25 @@ export class EdgeConfig { * @returns true for PRODUCTION */ public isProducer(component: EdgeConfig.Component) { - if (component.properties['type'] == "PRODUCTION") { + if (component.properties["type"] == "PRODUCTION") { return true; } // TODO properties in OSGi Component annotations are not transmitted correctly with Apache Felix SCR switch (component.factoryId) { - case 'Fenecon.Dess.PvMeter': - case 'Fenecon.Mini.PvMeter': - case 'Fenecon.Pro.PvMeter': - case 'Kaco.BlueplanetHybrid10.PvInverter': - case 'Kostal.Piko.Charger': - case 'PV-Inverter.Fronius': - case 'PV-Inverter.KACO.blueplanet': - case 'PV-Inverter.Kostal': - case 'PV-Inverter.SMA.SunnyTripower': - case 'PV-Inverter.Solarlog': - case 'PV-Inverter.SunSpec': - case 'Simulator.ProductionMeter.Acting': - case 'Simulator.PvInverter': - case 'SolarEdge.PV-Inverter': + case "Fenecon.Dess.PvMeter": + case "Fenecon.Mini.PvMeter": + case "Fenecon.Pro.PvMeter": + case "Kaco.BlueplanetHybrid10.PvInverter": + case "Kostal.Piko.Charger": + case "PV-Inverter.Fronius": + case "PV-Inverter.KACO.blueplanet": + case "PV-Inverter.Kostal": + case "PV-Inverter.SMA.SunnyTripower": + case "PV-Inverter.Solarlog": + case "PV-Inverter.SunSpec": + case "Simulator.ProductionMeter.Acting": + case "Simulator.PvInverter": + case "SolarEdge.PV-Inverter": return true; } @@ -523,11 +538,11 @@ export class EdgeConfig { * @returns true for CONSUMPTION_METERED */ public isTypeConsumptionMetered(component: EdgeConfig.Component) { - if (component.properties['type'] == "CONSUMPTION_METERED") { + if (component.properties["type"] == "CONSUMPTION_METERED") { return true; } else { switch (component.factoryId) { - case 'GoodWe.EmergencyPowerMeter': + case "GoodWe.EmergencyPowerMeter": return true; } } @@ -546,14 +561,14 @@ export class EdgeConfig { } switch (component.factoryId) { - case 'GoodWe.Grid-Meter': - case 'Kaco.BlueplanetHybrid10.GridMeter': - case 'Fenecon.Dess.GridMeter': - case 'Fenecon.Mini.GridMeter': - case 'Kostal.Piko.GridMeter': - case 'SolarEdge.Grid-Meter': - case 'Simulator.GridMeter.Acting': - case 'Simulator.GridMeter.Reacting': + case "GoodWe.Grid-Meter": + case "Kaco.BlueplanetHybrid10.GridMeter": + case "Fenecon.Dess.GridMeter": + case "Fenecon.Mini.GridMeter": + case "Kostal.Piko.GridMeter": + case "SolarEdge.Grid-Meter": + case "Simulator.GridMeter.Acting": + case "Simulator.GridMeter.Reacting": return true; } return false; @@ -688,7 +703,7 @@ export namespace PersistencePriority { * @returns true if prio1 is less than prio2 */ export function isLessThan(prio1: string, prio2: string): boolean { - if (typeof prio1 !== 'string' || typeof prio2 !== 'string') { + if (typeof prio1 !== "string" || typeof prio2 !== "string") { return false; } return Object.keys(PersistencePriority).indexOf(prio1) < Object.keys(PersistencePriority).indexOf(prio2); diff --git a/ui/src/app/shared/components/edge/meter/currentVoltage/chart/asymmetricMeter.ts b/ui/src/app/shared/components/edge/meter/currentVoltage/chart/asymmetricMeter.ts index d83646812eb..54d5f05ee5c 100644 --- a/ui/src/app/shared/components/edge/meter/currentVoltage/chart/asymmetricMeter.ts +++ b/ui/src/app/shared/components/edge/meter/currentVoltage/chart/asymmetricMeter.ts @@ -1,62 +1,62 @@ -import { Component } from '@angular/core'; -import { AbstractHistoryChart } from 'src/app/shared/components/chart/abstracthistorychart'; -import { Phase } from 'src/app/shared/components/shared/phase'; -import { ChartAxis, HistoryUtils, YAxisTitle } from 'src/app/shared/service/utils'; -import { ChannelAddress } from 'src/app/shared/shared'; +import { Component } from "@angular/core"; +import { AbstractHistoryChart } from "src/app/shared/components/chart/abstracthistorychart"; +import { Phase } from "src/app/shared/components/shared/phase"; +import { ChartAxis, HistoryUtils, YAxisType } from "src/app/shared/service/utils"; +import { ChannelAddress } from "src/app/shared/shared"; @Component({ - selector: 'currentVoltageAsymmetricChart', - templateUrl: '../../../../../components/chart/abstracthistorychart.html', + selector: "currentVoltageAsymmetricChart", + templateUrl: "../../../../../components/chart/abstracthistorychart.html", }) export class CurrentVoltageAsymmetricChartComponent extends AbstractHistoryChart { protected override getChartData(): HistoryUtils.ChartData { const component = this.config.getComponent(this.route.snapshot.params.componentId); - const currentPhasesColors: string[] = ['rgb(246, 180, 137)', 'rgb(238, 120, 42)', 'rgb(118, 52, 9)']; - const voltagePhasesColors: string[] = ['rgb(255, 0, 0)', 'rgb(133, 0, 0)', 'rgb(71, 0, 0)']; + const currentPhasesColors: string[] = ["rgb(246, 180, 137)", "rgb(238, 120, 42)", "rgb(118, 52, 9)"]; + const voltagePhasesColors: string[] = ["rgb(255, 0, 0)", "rgb(133, 0, 0)", "rgb(71, 0, 0)"]; const chartObject: HistoryUtils.ChartData = { input: [ ...Phase.THREE_PHASE.map((phase) => ({ - name: 'Current' + phase, - powerChannel: ChannelAddress.fromString(component.id + '/Current' + phase), + name: "Current" + phase, + powerChannel: ChannelAddress.fromString(component.id + "/Current" + phase), })), ...Phase.THREE_PHASE.map((phase) => ({ - name: 'Voltage' + phase, - powerChannel: ChannelAddress.fromString(component.id + '/Voltage' + phase), + name: "Voltage" + phase, + powerChannel: ChannelAddress.fromString(component.id + "/Voltage" + phase), })), ], output: (data: HistoryUtils.ChannelData) => [ ...Phase.THREE_PHASE.map((phase, index) => ({ - name: this.translate.instant('Edge.History.CURRENT') + " " + phase, + name: this.translate.instant("Edge.History.CURRENT") + " " + phase, converter: () => { - return data['Current' + phase]; + return data["Current" + phase]; }, hideShadow: true, color: currentPhasesColors[index], yAxisId: ChartAxis.RIGHT, })), ...Phase.THREE_PHASE.map((phase, index) => ({ - name: this.translate.instant('Edge.History.VOLTAGE') + " " + phase, + name: this.translate.instant("Edge.History.VOLTAGE") + " " + phase, converter: () => { - return data['Voltage' + phase]; + return data["Voltage" + phase]; }, hideShadow: true, color: voltagePhasesColors[index], })), ], tooltip: { - formatNumber: '1.1-2', - afterTitle: this.translate.instant('General.TOTAL'), + formatNumber: "1.1-2", + afterTitle: this.translate.instant("General.TOTAL"), }, yAxes: [{ - unit: YAxisTitle.VOLTAGE, - position: 'left', + unit: YAxisType.VOLTAGE, + position: "left", yAxisId: ChartAxis.LEFT, }, { - unit: YAxisTitle.CURRENT, - position: 'right', + unit: YAxisType.CURRENT, + position: "right", yAxisId: ChartAxis.RIGHT, }, ], diff --git a/ui/src/app/shared/components/edge/meter/currentVoltage/chart/symmetricMeter.ts b/ui/src/app/shared/components/edge/meter/currentVoltage/chart/symmetricMeter.ts index 24914ca30c1..e7998dda9f6 100644 --- a/ui/src/app/shared/components/edge/meter/currentVoltage/chart/symmetricMeter.ts +++ b/ui/src/app/shared/components/edge/meter/currentVoltage/chart/symmetricMeter.ts @@ -1,11 +1,11 @@ -import { Component } from '@angular/core'; -import { AbstractHistoryChart } from 'src/app/shared/components/chart/abstracthistorychart'; -import { ChartAxis, HistoryUtils, YAxisTitle } from 'src/app/shared/service/utils'; -import { ChannelAddress } from 'src/app/shared/shared'; +import { Component } from "@angular/core"; +import { AbstractHistoryChart } from "src/app/shared/components/chart/abstracthistorychart"; +import { ChartAxis, HistoryUtils, YAxisType } from "src/app/shared/service/utils"; +import { ChannelAddress } from "src/app/shared/shared"; @Component({ - selector: 'currentVoltageChart', - templateUrl: '../../../../../components/chart/abstracthistorychart.html', + selector: "currentVoltageChart", + templateUrl: "../../../../../components/chart/abstracthistorychart.html", }) export class CurrentVoltageSymmetricChartComponent extends AbstractHistoryChart { @@ -15,51 +15,51 @@ export class CurrentVoltageSymmetricChartComponent extends AbstractHistoryChart const chartObject: HistoryUtils.ChartData = { input: [ { - name: component.id + 'Current', - powerChannel: ChannelAddress.fromString(component.id + '/Current'), + name: component.id + "Current", + powerChannel: ChannelAddress.fromString(component.id + "/Current"), }, { - name: component.id + 'Voltage', - powerChannel: ChannelAddress.fromString(component.id + '/Voltage'), + name: component.id + "Voltage", + powerChannel: ChannelAddress.fromString(component.id + "/Voltage"), }, ], output: (data: HistoryUtils.ChannelData) => [ { - name: this.translate.instant('Edge.History.CURRENT'), + name: this.translate.instant("Edge.History.CURRENT"), converter: () => { - return data[component.id + 'Current']; + return data[component.id + "Current"]; }, - color: 'rgb(253,197,7)', + color: "rgb(253,197,7)", hiddenOnInit: false, stack: 1, yAxisId: ChartAxis.RIGHT, }, { - name: this.translate.instant('Edge.History.VOLTAGE'), + name: this.translate.instant("Edge.History.VOLTAGE"), converter: () => { - return data[component.id + 'Voltage']; + return data[component.id + "Voltage"]; }, - color: 'rgb(255,0,0)', + color: "rgb(255,0,0)", hiddenOnInit: false, stack: 1, yAxisId: ChartAxis.LEFT, }, ], tooltip: { - formatNumber: '1.1-2', - afterTitle: this.translate.instant('General.TOTAL'), + formatNumber: "1.1-2", + afterTitle: this.translate.instant("General.TOTAL"), }, yAxes: [{ - unit: YAxisTitle.VOLTAGE, - position: 'left', + unit: YAxisType.VOLTAGE, + position: "left", yAxisId: ChartAxis.LEFT, }, { - unit: YAxisTitle.CURRENT, - position: 'right', + unit: YAxisType.CURRENT, + position: "right", yAxisId: ChartAxis.RIGHT, }, ], diff --git a/ui/src/app/shared/components/edge/meter/currentVoltage/currentVoltage.overview.ts b/ui/src/app/shared/components/edge/meter/currentVoltage/currentVoltage.overview.ts index 7cd86d20236..698d2bc6966 100644 --- a/ui/src/app/shared/components/edge/meter/currentVoltage/currentVoltage.overview.ts +++ b/ui/src/app/shared/components/edge/meter/currentVoltage/currentVoltage.overview.ts @@ -1,8 +1,8 @@ -import { Component } from '@angular/core'; -import { AbstractHistoryChartOverview } from 'src/app/shared/components/chart/abstractHistoryChartOverview'; +import { Component } from "@angular/core"; +import { AbstractHistoryChartOverview } from "src/app/shared/components/chart/abstractHistoryChartOverview"; @Component({ - templateUrl: './currentVoltage.overview.html', + templateUrl: "./currentVoltage.overview.html", }) export class CurrentAndVoltageOverviewComponent extends AbstractHistoryChartOverview { diff --git a/ui/src/app/shared/components/edge/meter/currentVoltage/currentVoltageModule.ts b/ui/src/app/shared/components/edge/meter/currentVoltage/currentVoltageModule.ts index 8daaa2c37ac..8455ccf34b3 100644 --- a/ui/src/app/shared/components/edge/meter/currentVoltage/currentVoltageModule.ts +++ b/ui/src/app/shared/components/edge/meter/currentVoltage/currentVoltageModule.ts @@ -22,7 +22,7 @@ import { CurrentAndVoltageOverviewComponent } from "./currentVoltage.overview"; NgChartsModule, HistoryDataErrorModule, NgxSpinnerModule.forRoot({ - type: 'ball-clip-rotate-multiple', + type: "ball-clip-rotate-multiple", }), ChartModule, PickdateModule, diff --git a/ui/src/app/shared/components/edge/meter/electricity/modal.component.ts b/ui/src/app/shared/components/edge/meter/electricity/modal.component.ts index 7e41b9f447d..6e6d6e981a2 100644 --- a/ui/src/app/shared/components/edge/meter/electricity/modal.component.ts +++ b/ui/src/app/shared/components/edge/meter/electricity/modal.component.ts @@ -1,12 +1,12 @@ -import { Component, OnInit } from '@angular/core'; -import { AbstractModalLine } from 'src/app/shared/components/modal/abstract-modal-line'; -import { TextIndentation } from 'src/app/shared/components/modal/modal-line/modal-line'; -import { ChannelAddress, CurrentData, Utils } from 'src/app/shared/shared'; -import { Role } from 'src/app/shared/type/role'; +import { Component, OnInit } from "@angular/core"; +import { AbstractModalLine } from "src/app/shared/components/modal/abstract-modal-line"; +import { TextIndentation } from "src/app/shared/components/modal/modal-line/modal-line"; +import { ChannelAddress, CurrentData, Utils } from "src/app/shared/shared"; +import { Role } from "src/app/shared/type/role"; @Component({ - selector: 'oe-electricity-meter', - templateUrl: './modal.component.html', + selector: "oe-electricity-meter", + templateUrl: "./modal.component.html", }) export class ElectricityMeterComponent extends AbstractModalLine implements OnInit { @@ -24,9 +24,9 @@ export class ElectricityMeterComponent extends AbstractModalLine implements OnIn const channelAddresses: ChannelAddress[] = []; for (const phase of [1, 2, 3]) { channelAddresses.push( - new ChannelAddress(this.component.id, 'CurrentL' + phase), - new ChannelAddress(this.component.id, 'VoltageL' + phase), - new ChannelAddress(this.component.id, 'ActivePowerL' + phase), + new ChannelAddress(this.component.id, "CurrentL" + phase), + new ChannelAddress(this.component.id, "VoltageL" + phase), + new ChannelAddress(this.component.id, "ActivePowerL" + phase), ); } return channelAddresses; @@ -34,11 +34,11 @@ export class ElectricityMeterComponent extends AbstractModalLine implements OnIn protected override onCurrentData(currentData: CurrentData): void { this.phases.forEach((phase) => { - const power = currentData.allComponents[this.component.id + '/ActivePower' + phase.key]; + const power = currentData.allComponents[this.component.id + "/ActivePower" + phase.key]; phase.name = "Phase " + phase.key; phase.power = Utils.absSafely(power); - phase.current = currentData.allComponents[this.component.id + '/Current' + phase.key]; - phase.voltage = currentData.allComponents[this.component.id + '/Voltage' + phase.key]; + phase.current = currentData.allComponents[this.component.id + "/Current" + phase.key]; + phase.voltage = currentData.allComponents[this.component.id + "/Voltage" + phase.key]; }); } } diff --git a/ui/src/app/shared/components/edge/meter/esscharger/modal.component.ts b/ui/src/app/shared/components/edge/meter/esscharger/modal.component.ts index a2619bfaa54..f469c1420f2 100644 --- a/ui/src/app/shared/components/edge/meter/esscharger/modal.component.ts +++ b/ui/src/app/shared/components/edge/meter/esscharger/modal.component.ts @@ -1,12 +1,12 @@ -import { Component, Input } from '@angular/core'; -import { Converter } from 'src/app/shared/components/shared/converter'; -import { Utils } from 'src/app/shared/shared'; -import { Role } from 'src/app/shared/type/role'; -import { EdgeConfig } from '../../edgeconfig'; +import { Component, Input } from "@angular/core"; +import { Converter } from "src/app/shared/components/shared/converter"; +import { Utils } from "src/app/shared/shared"; +import { Role } from "src/app/shared/type/role"; +import { EdgeConfig } from "../../edgeconfig"; @Component({ - selector: 'oe-ess-charger', - templateUrl: './modal.component.html', + selector: "oe-ess-charger", + templateUrl: "./modal.component.html", }) export class EssChargerComponent { @Input({ required: true }) public component!: EdgeConfig.Component; diff --git a/ui/src/app/shared/components/edge/meter/meter.module.ts b/ui/src/app/shared/components/edge/meter/meter.module.ts index a8286187170..c3ffddae822 100644 --- a/ui/src/app/shared/components/edge/meter/meter.module.ts +++ b/ui/src/app/shared/components/edge/meter/meter.module.ts @@ -21,7 +21,7 @@ import { EssChargerComponent } from "./esscharger/modal.component"; NgChartsModule, CommonModule, NgxSpinnerModule.forRoot({ - type: 'ball-clip-rotate-multiple', + type: "ball-clip-rotate-multiple", }), HistoryDataErrorModule, ModalModule, diff --git a/ui/src/app/shared/components/flat/abstract-flat-widget-line.ts b/ui/src/app/shared/components/flat/abstract-flat-widget-line.ts index cb3ea6c980e..48738330c12 100644 --- a/ui/src/app/shared/components/flat/abstract-flat-widget-line.ts +++ b/ui/src/app/shared/components/flat/abstract-flat-widget-line.ts @@ -5,7 +5,7 @@ import { ModalController } from "@ionic/angular"; import { Subject } from "rxjs"; import { takeUntil } from "rxjs/operators"; import { ChannelAddress, Edge, Service, Websocket } from "src/app/shared/shared"; -import { v4 as uuidv4 } from 'uuid'; +import { v4 as uuidv4 } from "uuid"; import { DataService } from "../shared/dataservice"; import { Filter } from "../shared/filter"; @@ -86,7 +86,7 @@ export abstract class AbstractFlatWidgetLine implements OnChanges, OnDestroy { } protected subscribe(channelAddress: ChannelAddress) { - this.service.setCurrentComponent('', this.route).then(edge => { + this.service.getCurrentEdge().then(edge => { this.edge = edge; this.dataService.getValues([channelAddress], this.edge); diff --git a/ui/src/app/shared/components/flat/abstract-flat-widget.ts b/ui/src/app/shared/components/flat/abstract-flat-widget.ts index 1f0e6f2c2ce..bddb7f5283e 100644 --- a/ui/src/app/shared/components/flat/abstract-flat-widget.ts +++ b/ui/src/app/shared/components/flat/abstract-flat-widget.ts @@ -6,7 +6,7 @@ import { TranslateService } from "@ngx-translate/core"; import { Subject } from "rxjs"; import { takeUntil } from "rxjs/operators"; import { ChannelAddress, CurrentData, Edge, EdgeConfig, Utils } from "src/app/shared/shared"; -import { v4 as uuidv4 } from 'uuid'; +import { v4 as uuidv4 } from "uuid"; import { FormBuilder, FormGroup } from "@angular/forms"; import { Service } from "../../service/service"; diff --git a/ui/src/app/shared/components/flat/flat-widget-horizontal-line/flat-widget-horizontal-line.ts b/ui/src/app/shared/components/flat/flat-widget-horizontal-line/flat-widget-horizontal-line.ts index 0538ef06be6..514fbd0c68b 100644 --- a/ui/src/app/shared/components/flat/flat-widget-horizontal-line/flat-widget-horizontal-line.ts +++ b/ui/src/app/shared/components/flat/flat-widget-horizontal-line/flat-widget-horizontal-line.ts @@ -4,8 +4,8 @@ import { Component, Input } from "@angular/core"; * Shows a horizontal line on all but the last entry of a "flat-widget" or a "simple line" */ @Component({ - selector: 'oe-flat-widget-horizontal-line', - templateUrl: './flat-widget-horizontal-line.html', + selector: "oe-flat-widget-horizontal-line", + templateUrl: "./flat-widget-horizontal-line.html", }) export class FlatWidgetHorizontalLineComponent { /** Components-Array to iterate over */ diff --git a/ui/src/app/shared/components/flat/flat-widget-line-divider/flat-widget-line-divider.ts b/ui/src/app/shared/components/flat/flat-widget-line-divider/flat-widget-line-divider.ts index 6250b551b85..059b5e487fe 100644 --- a/ui/src/app/shared/components/flat/flat-widget-line-divider/flat-widget-line-divider.ts +++ b/ui/src/app/shared/components/flat/flat-widget-line-divider/flat-widget-line-divider.ts @@ -6,8 +6,8 @@ import { Icon } from "src/app/shared/type/widget"; * Inserts a transparent divider */ @Component({ - selector: 'oe-flat-widget-line-divider', - templateUrl: './flat-widget-line-divider.html', + selector: "oe-flat-widget-line-divider", + templateUrl: "./flat-widget-line-divider.html", }) export class FlatWidgetLineDividerComponent { diff --git a/ui/src/app/shared/components/flat/flat-widget-line/flat-widget-line.ts b/ui/src/app/shared/components/flat/flat-widget-line/flat-widget-line.ts index 78d3dcabd73..288f0f5aced 100644 --- a/ui/src/app/shared/components/flat/flat-widget-line/flat-widget-line.ts +++ b/ui/src/app/shared/components/flat/flat-widget-line/flat-widget-line.ts @@ -3,8 +3,8 @@ import { Component, Input } from "@angular/core"; import { AbstractFlatWidgetLine } from "../abstract-flat-widget-line"; @Component({ - selector: 'oe-flat-widget-line', - templateUrl: './flat-widget-line.html', + selector: "oe-flat-widget-line", + templateUrl: "./flat-widget-line.html", }) export class FlatWidgetLineComponent extends AbstractFlatWidgetLine { /** Name for parameter, displayed on the left side */ diff --git a/ui/src/app/shared/components/flat/flat-widget-percentagebar/flat-widget-percentagebar.ts b/ui/src/app/shared/components/flat/flat-widget-percentagebar/flat-widget-percentagebar.ts index f4cadb375fa..668caef9e60 100644 --- a/ui/src/app/shared/components/flat/flat-widget-percentagebar/flat-widget-percentagebar.ts +++ b/ui/src/app/shared/components/flat/flat-widget-percentagebar/flat-widget-percentagebar.ts @@ -2,7 +2,7 @@ import { Component } from "@angular/core"; import { AbstractFlatWidgetLine } from "../abstract-flat-widget-line"; @Component({ - selector: 'oe-flat-widget-percentagebar', - templateUrl: './flat-widget-percentagebar.html', + selector: "oe-flat-widget-percentagebar", + templateUrl: "./flat-widget-percentagebar.html", }) export class FlatWidgetPercentagebarComponent extends AbstractFlatWidgetLine { } diff --git a/ui/src/app/shared/components/flat/flat.ts b/ui/src/app/shared/components/flat/flat.ts index 5d651dd208f..a2642ad0b75 100644 --- a/ui/src/app/shared/components/flat/flat.ts +++ b/ui/src/app/shared/components/flat/flat.ts @@ -1,10 +1,10 @@ // @ts-strict-ignore -import { Component, Input } from '@angular/core'; -import { Icon } from 'src/app/shared/type/widget'; +import { Component, Input } from "@angular/core"; +import { Icon } from "src/app/shared/type/widget"; @Component({ - selector: 'oe-flat-widget', - templateUrl: './flat.html', + selector: "oe-flat-widget", + templateUrl: "./flat.html", }) export class FlatWidgetComponent { diff --git a/ui/src/app/shared/components/footer/footer.ts b/ui/src/app/shared/components/footer/footer.ts index a285d522f4e..2183f132dea 100644 --- a/ui/src/app/shared/components/footer/footer.ts +++ b/ui/src/app/shared/components/footer/footer.ts @@ -2,13 +2,13 @@ import { Component, HostBinding, OnInit } from "@angular/core"; import { Title } from "@angular/platform-browser"; import { filter } from "rxjs/operators"; -import { environment } from '../../../../environments'; +import { environment } from "../../../../environments"; import { User } from "../../jsonrpc/shared"; import { Edge, Service } from "../../shared"; import { Role } from "../../type/role"; @Component({ - selector: 'oe-footer', + selector: "oe-footer", styles: [` :host[data-isSmartPhone=true] { @@ -31,11 +31,11 @@ import { Role } from "../../type/role"; } } `], - templateUrl: 'footer.html', + templateUrl: "footer.html", }) export class FooterComponent implements OnInit { - @HostBinding('attr.data-isSmartPhone') + @HostBinding("attr.data-isSmartPhone") public isSmartPhone: boolean = this.service.isSmartphoneResolution; protected user: User | null = null; diff --git a/ui/src/app/shared/components/footer/subnavigation/footerNavigation.ts b/ui/src/app/shared/components/footer/subnavigation/footerNavigation.ts index aee0d8a859e..400fa6224f5 100644 --- a/ui/src/app/shared/components/footer/subnavigation/footerNavigation.ts +++ b/ui/src/app/shared/components/footer/subnavigation/footerNavigation.ts @@ -10,16 +10,16 @@ export type NavigationOption = { }; @Component({ - selector: 'oe-footer-subnavigation', - templateUrl: 'footerNavigation.html', + selector: "oe-footer-subnavigation", + templateUrl: "footerNavigation.html", }) export class FooterNavigationComponent implements AfterViewInit { private static readonly INTERVAL: number = 1000; - @ViewChildren('subnavigationbuttons', { read: ElementRef }) + @ViewChildren("subnavigationbuttons", { read: ElementRef }) public subnavigationbuttons!: QueryList; - @ViewChild('container', { read: ElementRef }) public container!: ElementRef; + @ViewChild("container", { read: ElementRef }) public container!: ElementRef; @Input() public backButton: boolean = false; protected areButtonsReadyToShow: boolean = false; @@ -40,7 +40,7 @@ export class FooterNavigationComponent implements AfterViewInit { this._buttons = nodes; this.buttons = nodes; } - @HostListener('window:resize', ['$event.target.innerWidth']) + @HostListener("window:resize", ["$event.target.innerWidth"]) private onResize(width: number) { this.initializeFooterSubnavigation(); } @@ -55,8 +55,6 @@ export class FooterNavigationComponent implements AfterViewInit { this.showPopover = false; } - - /** * Initializes sub-navigation */ diff --git a/ui/src/app/shared/components/formly/form-field-checkbox-hyperlink/form-field-checkbox-hyperlink.wrapper.ts b/ui/src/app/shared/components/formly/form-field-checkbox-hyperlink/form-field-checkbox-hyperlink.wrapper.ts index 84185208942..1846f9d4c4d 100644 --- a/ui/src/app/shared/components/formly/form-field-checkbox-hyperlink/form-field-checkbox-hyperlink.wrapper.ts +++ b/ui/src/app/shared/components/formly/form-field-checkbox-hyperlink/form-field-checkbox-hyperlink.wrapper.ts @@ -1,10 +1,10 @@ // @ts-strict-ignore -import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; -import { FieldWrapper } from '@ngx-formly/core'; +import { ChangeDetectionStrategy, Component, OnInit } from "@angular/core"; +import { FieldWrapper } from "@ngx-formly/core"; @Component({ - selector: 'form-field-checkbox-hyperlink', - templateUrl: './form-field-checkbox-hyperlink.wrapper.html', + selector: "form-field-checkbox-hyperlink", + templateUrl: "./form-field-checkbox-hyperlink.wrapper.html", changeDetection: ChangeDetectionStrategy.OnPush, }) export class FormlyCheckBoxHyperlinkWrapperComponent extends FieldWrapper implements OnInit { @@ -20,7 +20,7 @@ export class FormlyCheckBoxHyperlinkWrapperComponent extends FieldWrapper implem // Since its a custom wrapper, we are seperating label with checkbox. // mentioning required to true does not generate (*) to the label, so we are hard coding it. if (this.field.props.required) { - this.secondLabel = this.field.props.description + '*'; + this.secondLabel = this.field.props.description + "*"; } else { this.secondLabel = this.field.props.description; } diff --git a/ui/src/app/shared/components/formly/form-field-default-cases.wrapper.ts b/ui/src/app/shared/components/formly/form-field-default-cases.wrapper.ts index a50d3b32d6d..bd28f9a6023 100644 --- a/ui/src/app/shared/components/formly/form-field-default-cases.wrapper.ts +++ b/ui/src/app/shared/components/formly/form-field-default-cases.wrapper.ts @@ -1,11 +1,11 @@ // @ts-strict-ignore -import { Component, OnInit } from '@angular/core'; -import { AbstractControl } from '@angular/forms'; -import { FieldWrapper } from '@ngx-formly/core'; +import { Component, OnInit } from "@angular/core"; +import { AbstractControl } from "@angular/forms"; +import { FieldWrapper } from "@ngx-formly/core"; @Component({ - selector: 'formly-wrapper-default-of-cases', - template: ``, + selector: "formly-wrapper-default-of-cases", + template: "", }) export class FormlyWrapperDefaultValueWithCasesComponent extends FieldWrapper implements OnInit { diff --git a/ui/src/app/shared/components/formly/form-field.wrapper.ts b/ui/src/app/shared/components/formly/form-field.wrapper.ts index 64b6e3a1fd9..15d3c9a1b0d 100644 --- a/ui/src/app/shared/components/formly/form-field.wrapper.ts +++ b/ui/src/app/shared/components/formly/form-field.wrapper.ts @@ -1,9 +1,9 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { FieldWrapper } from '@ngx-formly/core'; +import { ChangeDetectionStrategy, Component } from "@angular/core"; +import { FieldWrapper } from "@ngx-formly/core"; @Component({ - selector: 'formly-wrapper-ion-form-field', - templateUrl: './form-field.wrapper.html', + selector: "formly-wrapper-ion-form-field", + templateUrl: "./form-field.wrapper.html", changeDetection: ChangeDetectionStrategy.OnPush, }) export class FormlyWrapperFormFieldComponent extends FieldWrapper { } diff --git a/ui/src/app/shared/components/formly/formly-field-checkbox-image/formly-field-checkbox-with-image.ts b/ui/src/app/shared/components/formly/formly-field-checkbox-image/formly-field-checkbox-with-image.ts index 55b598c2933..c00fdafb5a2 100644 --- a/ui/src/app/shared/components/formly/formly-field-checkbox-image/formly-field-checkbox-with-image.ts +++ b/ui/src/app/shared/components/formly/formly-field-checkbox-image/formly-field-checkbox-with-image.ts @@ -1,9 +1,9 @@ -import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; -import { FieldWrapper } from '@ngx-formly/core'; +import { ChangeDetectionStrategy, Component, OnInit } from "@angular/core"; +import { FieldWrapper } from "@ngx-formly/core"; @Component({ - selector: 'formly-field-checkbox-with-image', - templateUrl: './formly-field-checkbox-with-image.html', + selector: "formly-field-checkbox-with-image", + templateUrl: "./formly-field-checkbox-with-image.html", changeDetection: ChangeDetectionStrategy.OnPush, }) export class FormlyFieldCheckboxWithImageComponent extends FieldWrapper implements OnInit { diff --git a/ui/src/app/shared/components/formly/formly-field-modal/formlyfieldmodal.ts b/ui/src/app/shared/components/formly/formly-field-modal/formlyfieldmodal.ts index 9a418fec53b..2d934c9c8fa 100644 --- a/ui/src/app/shared/components/formly/formly-field-modal/formlyfieldmodal.ts +++ b/ui/src/app/shared/components/formly/formly-field-modal/formlyfieldmodal.ts @@ -2,7 +2,7 @@ import { Component } from "@angular/core"; import { FieldWrapper } from "@ngx-formly/core"; @Component({ - selector: 'formly-field-modal', - templateUrl: './formlyfieldmodal.html', + selector: "formly-field-modal", + templateUrl: "./formlyfieldmodal.html", }) export class FormlyFieldModalComponent extends FieldWrapper { } diff --git a/ui/src/app/shared/components/formly/formly-field-radio-with-image/formly-field-radio-with-image.ts b/ui/src/app/shared/components/formly/formly-field-radio-with-image/formly-field-radio-with-image.ts index c66a5c192e0..a104e13a949 100644 --- a/ui/src/app/shared/components/formly/formly-field-radio-with-image/formly-field-radio-with-image.ts +++ b/ui/src/app/shared/components/formly/formly-field-radio-with-image/formly-field-radio-with-image.ts @@ -1,9 +1,9 @@ -import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; -import { FieldWrapper } from '@ngx-formly/core'; +import { ChangeDetectionStrategy, Component, OnInit } from "@angular/core"; +import { FieldWrapper } from "@ngx-formly/core"; @Component({ - selector: 'formly-field-radio-with-image', - templateUrl: './formly-field-radio-with-image.html', + selector: "formly-field-radio-with-image", + templateUrl: "./formly-field-radio-with-image.html", changeDetection: ChangeDetectionStrategy.OnPush, }) export class FormlyFieldRadioWithImageComponent extends FieldWrapper implements OnInit { diff --git a/ui/src/app/shared/components/formly/formly-select-field-modal.component.ts b/ui/src/app/shared/components/formly/formly-select-field-modal.component.ts index 2ef2314fced..35bef389fd0 100644 --- a/ui/src/app/shared/components/formly/formly-select-field-modal.component.ts +++ b/ui/src/app/shared/components/formly/formly-select-field-modal.component.ts @@ -2,8 +2,8 @@ import { Component, Input, OnInit } from "@angular/core"; import { ModalController } from "@ionic/angular"; @Component({ - selector: 'formly-select-modal', - templateUrl: './formly-select-field-modal.component.html', + selector: "formly-select-modal", + templateUrl: "./formly-select-field-modal.component.html", }) export class FormlySelectFieldModalComponent implements OnInit { diff --git a/ui/src/app/shared/components/formly/formly-select-field.extended.ts b/ui/src/app/shared/components/formly/formly-select-field.extended.ts index dec0c0037e6..ffcdb6ada79 100644 --- a/ui/src/app/shared/components/formly/formly-select-field.extended.ts +++ b/ui/src/app/shared/components/formly/formly-select-field.extended.ts @@ -4,8 +4,8 @@ import { FieldWrapper } from "@ngx-formly/core"; import { FormlySelectFieldModalComponent } from "./formly-select-field-modal.component"; @Component({ - selector: 'formly-select-extended-wrapper', - templateUrl: './formly-select-field.extended.html', + selector: "formly-select-extended-wrapper", + templateUrl: "./formly-select-field.extended.html", }) export class FormlySelectFieldExtendedWrapperComponent extends FieldWrapper { @@ -33,7 +33,7 @@ export class FormlySelectFieldExtendedWrapperComponent extends FieldWrapper { options: this.props.options, initialSelectedValue: this.formControl.value, }, - cssClass: ['auto-height', 'full-width'], + cssClass: ["auto-height", "full-width"], }); modal.onDidDismiss().then(event => { if (!event.data) { diff --git a/ui/src/app/shared/components/formly/formly-skeleton-wrapper.ts b/ui/src/app/shared/components/formly/formly-skeleton-wrapper.ts index f0c2bb276dd..8dc332dcf29 100644 --- a/ui/src/app/shared/components/formly/formly-skeleton-wrapper.ts +++ b/ui/src/app/shared/components/formly/formly-skeleton-wrapper.ts @@ -1,6 +1,6 @@ -import { Component, Input } from '@angular/core'; -import { FormGroup } from '@angular/forms'; -import { FormlyFieldConfig } from '@ngx-formly/core'; +import { Component, Input } from "@angular/core"; +import { FormGroup } from "@angular/forms"; +import { FormlyFieldConfig } from "@ngx-formly/core"; /** This wrapper is used to display a loading animation for a line until the async call is finished, the @input show is true, respectively. @@ -10,7 +10,7 @@ import { FormlyFieldConfig } from '@ngx-formly/core'; * @input model the model */ @Component({ - selector: 'formly-skeleton-wrapper', + selector: "formly-skeleton-wrapper", template: `
      diff --git a/ui/src/app/shared/components/formly/input-serial-number-wrapper.ts b/ui/src/app/shared/components/formly/input-serial-number-wrapper.ts index 80d9142a7c7..0df1760de05 100644 --- a/ui/src/app/shared/components/formly/input-serial-number-wrapper.ts +++ b/ui/src/app/shared/components/formly/input-serial-number-wrapper.ts @@ -1,8 +1,8 @@ -import { Component } from '@angular/core'; -import { FieldWrapper } from '@ngx-formly/core'; +import { Component } from "@angular/core"; +import { FieldWrapper } from "@ngx-formly/core"; @Component({ - selector: 'formly-input-serial-number', - templateUrl: './input-serial-number-wrapper.html', + selector: "formly-input-serial-number", + templateUrl: "./input-serial-number-wrapper.html", }) export class FormlyInputSerialNumberWrapperComponent extends FieldWrapper { } diff --git a/ui/src/app/shared/components/formly/input.ts b/ui/src/app/shared/components/formly/input.ts index a6e218d99d6..3e547670e94 100644 --- a/ui/src/app/shared/components/formly/input.ts +++ b/ui/src/app/shared/components/formly/input.ts @@ -1,8 +1,8 @@ -import { Component } from '@angular/core'; -import { FieldType } from '@ngx-formly/core'; +import { Component } from "@angular/core"; +import { FieldType } from "@ngx-formly/core"; @Component({ - selector: 'formly-input-section', - templateUrl: './input.html', + selector: "formly-input-section", + templateUrl: "./input.html", }) export class InputTypeComponent extends FieldType { } diff --git a/ui/src/app/shared/components/formly/panel-wrapper.component.ts b/ui/src/app/shared/components/formly/panel-wrapper.component.ts index 170d9465cfe..5af73ea9d87 100644 --- a/ui/src/app/shared/components/formly/panel-wrapper.component.ts +++ b/ui/src/app/shared/components/formly/panel-wrapper.component.ts @@ -2,7 +2,7 @@ import { Component } from "@angular/core"; import { FieldWrapper } from "@ngx-formly/core"; @Component({ - selector: 'formly-wrapper-panel', + selector: "formly-wrapper-panel", template: ` diff --git a/ui/src/app/shared/components/formly/repeat.ts b/ui/src/app/shared/components/formly/repeat.ts index 5810421a7e3..5ec40c593a7 100644 --- a/ui/src/app/shared/components/formly/repeat.ts +++ b/ui/src/app/shared/components/formly/repeat.ts @@ -1,9 +1,9 @@ -import { Component } from '@angular/core'; -import { FieldArrayType } from '@ngx-formly/core'; +import { Component } from "@angular/core"; +import { FieldArrayType } from "@ngx-formly/core"; @Component({ - selector: 'formly-repeat-section', - templateUrl: './repeat.html', + selector: "formly-repeat-section", + templateUrl: "./repeat.html", }) export class RepeatTypeComponent extends FieldArrayType { // TODO: add explicit constructor diff --git a/ui/src/app/shared/components/header/header.component.ts b/ui/src/app/shared/components/header/header.component.ts index e76040f3175..0c192f21047 100644 --- a/ui/src/app/shared/components/header/header.component.ts +++ b/ui/src/app/shared/components/header/header.component.ts @@ -1,27 +1,27 @@ // @ts-strict-ignore -import { AfterViewChecked, ChangeDetectorRef, Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; -import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'; -import { MenuController, ModalController } from '@ionic/angular'; -import { Subject } from 'rxjs'; -import { filter, takeUntil } from 'rxjs/operators'; -import { environment } from 'src/environments'; +import { AfterViewChecked, ChangeDetectorRef, Component, OnDestroy, OnInit, ViewChild } from "@angular/core"; +import { ActivatedRoute, NavigationEnd, Router } from "@angular/router"; +import { MenuController, ModalController } from "@ionic/angular"; +import { Subject } from "rxjs"; +import { filter, takeUntil } from "rxjs/operators"; +import { environment } from "src/environments"; -import { Edge, Service, Websocket } from '../../shared'; -import { PickDateComponent } from '../pickdate/pickdate.component'; -import { StatusSingleComponent } from '../status/single/status.component'; +import { Edge, Service, Websocket } from "../../shared"; +import { PickDateComponent } from "../pickdate/pickdate.component"; +import { StatusSingleComponent } from "../status/single/status.component"; @Component({ - selector: 'header', - templateUrl: './header.component.html', + selector: "header", + templateUrl: "./header.component.html", }) export class HeaderComponent implements OnInit, OnDestroy, AfterViewChecked { @ViewChild(PickDateComponent, { static: false }) public PickDateComponent: PickDateComponent; public environment = environment; - public backUrl: string | boolean = '/'; + public backUrl: string | boolean = "/"; public enableSideMenu: boolean; - public currentPage: 'EdgeSettings' | 'Other' | 'IndexLive' | 'IndexHistory' = 'Other'; + public currentPage: "EdgeSettings" | "Other" | "IndexLive" | "IndexHistory" = "Other"; public isSystemLogEnabled: boolean = false; private ngUnsubscribe: Subject = new Subject(); @@ -60,10 +60,10 @@ export class HeaderComponent implements OnInit, OnDestroy, AfterViewChecked { } updateEnableSideMenu(url: string) { - const urlArray = url.split('/'); + const urlArray = url.split("/"); const file = urlArray.pop(); - if (file == 'user' || file == 'settings' || file == 'changelog' || file == 'login' || urlArray.length > 3) { + if (file == "user" || file == "settings" || file == "changelog" || file == "login" || urlArray.length > 3) { // disable side-menu; show back-button instead this.enableSideMenu = false; } else { @@ -75,7 +75,7 @@ export class HeaderComponent implements OnInit, OnDestroy, AfterViewChecked { updateBackUrl(url: string) { // disable backUrl & Segment Navigation on initial 'login' page - if (url === '/login' || url === '/overview') { + if (url === "/login" || url === "/overview") { this.backUrl = false; return; } @@ -83,77 +83,77 @@ export class HeaderComponent implements OnInit, OnDestroy, AfterViewChecked { // set backUrl for user when an Edge had been selected before const currentEdge: Edge = this.service.currentEdge.value; - if (url === '/user' && currentEdge != null) { - this.backUrl = '/device/' + currentEdge.id + "/live"; + if (url === "/user" && currentEdge != null) { + this.backUrl = "/device/" + currentEdge.id + "/live"; return; } // set backUrl for user if no edge had been selected - if (url === '/user') { - this.backUrl = '/overview'; + if (url === "/user") { + this.backUrl = "/overview"; return; } - if (url === '/changelog' && currentEdge != null) { + if (url === "/changelog" && currentEdge != null) { // TODO this does not work if Changelog was opened from /user - this.backUrl = '/device/' + currentEdge.id + "/settings/profile"; + this.backUrl = "/device/" + currentEdge.id + "/settings/profile"; return; } - const urlArray = url.split('/'); - let backUrl: string | boolean = '/'; + const urlArray = url.split("/"); + let backUrl: string | boolean = "/"; const file = urlArray.pop(); // disable backUrl for History & EdgeIndex Component ++ Enable Segment Navigation - if ((file == 'history' || file == 'live') && urlArray.length == 3) { + if ((file == "history" || file == "live") && urlArray.length == 3) { this.backUrl = false; return; } // disable backUrl to first 'index' page from Edge index if there is only one Edge in the system - if (file === 'live' && urlArray.length == 3 && this.environment.backend === "OpenEMS Edge") { + if (file === "live" && urlArray.length == 3 && this.environment.backend === "OpenEMS Edge") { this.backUrl = false; return; } // remove one part of the url for 'index' - if (file === 'live') { + if (file === "live") { urlArray.pop(); } // fix url for App "settings/app/install" and "settings/app/update" - if (urlArray.slice(-3, -1).join('/') === "settings/app") { + if (urlArray.slice(-3, -1).join("/") === "settings/app") { urlArray.pop(); } // re-join the url - backUrl = urlArray.join('/') || '/'; + backUrl = urlArray.join("/") || "/"; // correct path for '/device/[edgeId]/index' - if (backUrl === '/device') { - backUrl = '/'; + if (backUrl === "/device") { + backUrl = "/"; } this.backUrl = backUrl; } updateCurrentPage(url: string) { - const urlArray = url.split('/'); + const urlArray = url.split("/"); let file = urlArray.pop(); if (urlArray.length >= 4) { file = urlArray[3]; } // Enable Segment Navigation for Edge-Index-Page - if ((file == 'history' || file == 'live') && urlArray.length == 3) { - if (file == 'history') { - this.currentPage = 'IndexHistory'; + if ((file == "history" || file == "live") && urlArray.length == 3) { + if (file == "history") { + this.currentPage = "IndexHistory"; } else { - this.currentPage = 'IndexLive'; + this.currentPage = "IndexLive"; } - } else if (file == 'settings' && urlArray.length > 1) { - this.currentPage = 'EdgeSettings'; + } else if (file == "settings" && urlArray.length > 1) { + this.currentPage = "EdgeSettings"; } else { - this.currentPage = 'Other'; + this.currentPage = "Other"; } } @@ -165,7 +165,7 @@ export class HeaderComponent implements OnInit, OnDestroy, AfterViewChecked { if (event.detail.value == "IndexHistory") { /** Creates bug of being infinite forwarded betweeen live and history, if not relatively routed */ - this.router.navigate(['../history'], { relativeTo: this.route }); + this.router.navigate(["../history"], { relativeTo: this.route }); this.cdRef.detectChanges(); } } diff --git a/ui/src/app/shared/components/history-data-error/history-data-error.component.ts b/ui/src/app/shared/components/history-data-error/history-data-error.component.ts index 74df053ac50..de600575ce7 100644 --- a/ui/src/app/shared/components/history-data-error/history-data-error.component.ts +++ b/ui/src/app/shared/components/history-data-error/history-data-error.component.ts @@ -3,7 +3,7 @@ import { Component, Input } from "@angular/core"; import { JsonrpcResponseError } from "src/app/shared/jsonrpc/base"; @Component({ - selector: 'oe-history-data-error', + selector: "oe-history-data-error", template: ` @@ -25,7 +25,7 @@ export class HistoryDataErrorComponent { } } -type ErrorType = 'TEMPORARY' | 'TOO_LONG' | null; +type ErrorType = "TEMPORARY" | "TOO_LONG" | null; function toType(response: JsonrpcResponseError | null): ErrorType { const message = response?.error?.message; @@ -34,8 +34,8 @@ function toType(response: JsonrpcResponseError | null): ErrorType { } switch (message) { case "Die Anzeige und der Export von Daten über einen längeren Zeitraum ist derzeit leider nicht möglich": - return 'TOO_LONG'; + return "TOO_LONG"; default: - return 'TEMPORARY'; + return "TEMPORARY"; } } diff --git a/ui/src/app/shared/components/modal/abstract-modal-line.ts b/ui/src/app/shared/components/modal/abstract-modal-line.ts index 625dac513e5..f16f75a48f8 100644 --- a/ui/src/app/shared/components/modal/abstract-modal-line.ts +++ b/ui/src/app/shared/components/modal/abstract-modal-line.ts @@ -7,7 +7,7 @@ import { TranslateService } from "@ngx-translate/core"; 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 { v4 as uuidv4 } from "uuid"; import { Role } from "../../type/role"; import { Converter } from "../shared/converter"; @@ -83,7 +83,7 @@ export abstract class AbstractModalLine implements OnInit, OnDestroy, OnChanges /** Name for parameter, displayed on the left side*/ @Input() set name(value: string | { channel: ChannelAddress, converter: (value: any) => string }) { - if (typeof value === 'object') { + if (typeof value === "object") { this.subscribe(value.channel); this._name = value.converter; } else { @@ -104,7 +104,7 @@ export abstract class AbstractModalLine implements OnInit, OnDestroy, OnChanges } ngOnInit() { - this.service.setCurrentComponent('', this.route).then(edge => { + this.service.getCurrentEdge().then(edge => { this.service.getConfig().then(config => { // store important variables publically this.edge = edge; @@ -113,7 +113,7 @@ export abstract class AbstractModalLine implements OnInit, OnDestroy, OnChanges // get the channel addresses that should be subscribed const channelAddresses: ChannelAddress[] = [...this.getChannelAddresses()]; - if (typeof this.name == 'object') { + if (typeof this.name == "object") { channelAddresses.push(this.name.channel); } @@ -159,7 +159,7 @@ export abstract class AbstractModalLine implements OnInit, OnDestroy, OnChanges this.show = this.filter(value); } - if (typeof this._name == 'function') { + if (typeof this._name == "function") { this.displayName = this._name(value); } else { @@ -172,7 +172,7 @@ export abstract class AbstractModalLine implements OnInit, OnDestroy, OnChanges /** Subscribe on HTML passed Channels */ protected subscribe(channelAddress: ChannelAddress) { - this.service.setCurrentComponent('', this.route).then(edge => { + this.service.getCurrentEdge().then(edge => { this.edge = edge; // Check if user is allowed to see these channel-values diff --git a/ui/src/app/shared/components/modal/abstractModal.ts b/ui/src/app/shared/components/modal/abstractModal.ts index 78331d04b12..225cf314e76 100644 --- a/ui/src/app/shared/components/modal/abstractModal.ts +++ b/ui/src/app/shared/components/modal/abstractModal.ts @@ -7,7 +7,7 @@ import { TranslateService } from "@ngx-translate/core"; import { Subject, Subscription } 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 { v4 as uuidv4 } from "uuid"; import { Role } from "../../type/role"; import { Converter } from "../shared/converter"; @@ -64,7 +64,7 @@ export abstract class AbstractModal implements OnInit, OnDestroy { } public ngOnInit() { - this.service.setCurrentComponent('', this.route).then(edge => { + this.service.getCurrentEdge().then(edge => { this.service.getConfig().then(config => { // store important variables publically diff --git a/ui/src/app/shared/components/modal/help-button/help-button.ts b/ui/src/app/shared/components/modal/help-button/help-button.ts index 38d4a5025e6..86faa04d87f 100644 --- a/ui/src/app/shared/components/modal/help-button/help-button.ts +++ b/ui/src/app/shared/components/modal/help-button/help-button.ts @@ -1,11 +1,11 @@ // @ts-strict-ignore import { Component, Input } from "@angular/core"; import { Service } from "src/app/shared/shared"; -import { environment } from 'src/environments'; +import { environment } from "src/environments"; @Component({ - selector: 'oe-help-button', - templateUrl: './help-button.html', + selector: "oe-help-button", + templateUrl: "./help-button.html", }) export class HelpButtonComponent { diff --git a/ui/src/app/shared/components/modal/modal-button/modal-button.ts b/ui/src/app/shared/components/modal/modal-button/modal-button.ts index ffa19945c66..9b72038989c 100644 --- a/ui/src/app/shared/components/modal/modal-button/modal-button.ts +++ b/ui/src/app/shared/components/modal/modal-button/modal-button.ts @@ -3,8 +3,8 @@ import { Icon } from "src/app/shared/type/widget"; import { AbstractModalLine } from "../abstract-modal-line"; @Component({ - selector: 'oe-modal-buttons', - templateUrl: './modal-button.html', + selector: "oe-modal-buttons", + templateUrl: "./modal-button.html", }) export class ModalButtonsComponent extends AbstractModalLine { diff --git a/ui/src/app/shared/components/modal/modal-info-line/modal-info-line.ts b/ui/src/app/shared/components/modal/modal-info-line/modal-info-line.ts index 985d9c6e693..d19b17030fe 100644 --- a/ui/src/app/shared/components/modal/modal-info-line/modal-info-line.ts +++ b/ui/src/app/shared/components/modal/modal-info-line/modal-info-line.ts @@ -2,8 +2,8 @@ import { Component, Input } from "@angular/core"; import { Icon } from "src/app/shared/type/widget"; @Component({ - selector: 'oe-modal-info-line', - templateUrl: './modal-info-line.html', + selector: "oe-modal-info-line", + templateUrl: "./modal-info-line.html", }) export class ModalInfoLineComponent { diff --git a/ui/src/app/shared/components/modal/modal-line/modal-line.ts b/ui/src/app/shared/components/modal/modal-line/modal-line.ts index 552cf0e0a10..76e9e187946 100644 --- a/ui/src/app/shared/components/modal/modal-line/modal-line.ts +++ b/ui/src/app/shared/components/modal/modal-line/modal-line.ts @@ -3,8 +3,8 @@ import { AbstractModalLine } from "../abstract-modal-line"; import { ButtonLabel } from "../modal-button/modal-button"; @Component({ - selector: 'oe-modal-line', - templateUrl: './modal-line.html', + selector: "oe-modal-line", + templateUrl: "./modal-line.html", }) export class ModalLineComponent extends AbstractModalLine { @@ -17,19 +17,19 @@ export class ModalLineComponent extends AbstractModalLine { @Input() protected button: ButtonLabel | null = null; /** ControlName for Toggle Button */ @Input({ required: true }) protected control!: - { type: 'TOGGLE' } | - { type: 'INPUT', properties?: { unit: 'W' } } | + { type: "TOGGLE" } | + { type: "INPUT", properties?: { unit: "W" } } | /* the available select options*/ - { type: 'SELECT', options: { value: string, name: string }[] } | + { type: "SELECT", options: { value: string, name: string }[] } | /* the properties for range slider*/ - { type: 'RANGE', properties: { min: number, max: number, unit: 'H', step?: number } }; + { type: "RANGE", properties: { min: number, max: number, unit: "H", step?: number } }; /** Fixed indentation of the modal-line */ @Input() protected textIndent: TextIndentation = TextIndentation.NONE; } export enum TextIndentation { - NONE = '0%', - SINGLE = '5%', - DOUBLE = '10%', + NONE = "0%", + SINGLE = "5%", + DOUBLE = "10%", } diff --git a/ui/src/app/shared/components/modal/modal-phases/modal-phases.ts b/ui/src/app/shared/components/modal/modal-phases/modal-phases.ts index 805b9b4ec0e..8dfdd170ea4 100644 --- a/ui/src/app/shared/components/modal/modal-phases/modal-phases.ts +++ b/ui/src/app/shared/components/modal/modal-phases/modal-phases.ts @@ -26,7 +26,7 @@ export class ModalPhasesComponent extends AbstractModalLine { for (const phase of this.phases) { channelAddresses.push( - ChannelAddress.fromString(this.component.id + '/ActivePower' + phase.key), + ChannelAddress.fromString(this.component.id + "/ActivePower" + phase.key), ); } return channelAddresses; @@ -34,8 +34,8 @@ export class ModalPhasesComponent extends AbstractModalLine { protected override onCurrentData(currentData: CurrentData): void { for (const phase of this.phases) { - const powerPerPhase = currentData.allComponents[this.component.id + '/ActivePower' + phase.key]; - phase.name = this.translate.instant('General.phase') + " " + phase.key + this.setTranslatedName(powerPerPhase); + const powerPerPhase = currentData.allComponents[this.component.id + "/ActivePower" + phase.key]; + phase.name = this.translate.instant("General.phase") + " " + phase.key + this.setTranslatedName(powerPerPhase); } } @@ -48,6 +48,6 @@ export class ModalPhasesComponent extends AbstractModalLine { protected CONVERT_TO_POSITIVE_WATT = (value: number | null): string => { value = Utils.absSafely(value) ?? 0; - return formatNumber(value, 'de', '1.0-0') + ' W'; + return formatNumber(value, "de", "1.0-0") + " W"; }; } diff --git a/ui/src/app/shared/components/modal/modal-value-line/modal-value-line.ts b/ui/src/app/shared/components/modal/modal-value-line/modal-value-line.ts index 16edba720ae..992dd9261de 100644 --- a/ui/src/app/shared/components/modal/modal-value-line/modal-value-line.ts +++ b/ui/src/app/shared/components/modal/modal-value-line/modal-value-line.ts @@ -5,8 +5,8 @@ import { ChannelAddress, CurrentData } from "src/app/shared/shared"; import { AbstractModalLine } from "../abstract-modal-line"; @Component({ - selector: 'oe-modal-value-line', - templateUrl: './modal-value-line.html', + selector: "oe-modal-value-line", + templateUrl: "./modal-value-line.html", }) export class ModalValueLineComponent extends AbstractModalLine { @@ -34,7 +34,7 @@ export class ModalValueLineComponent extends AbstractModalLine { } export enum TextIndentation { - NONE = '0%', - SINGLE = '5%', - DOUBLE = '10%', + NONE = "0%", + SINGLE = "5%", + DOUBLE = "10%", } diff --git a/ui/src/app/shared/components/modal/modal.module.ts b/ui/src/app/shared/components/modal/modal.module.ts index cebaef4736e..57ecf5e89e0 100644 --- a/ui/src/app/shared/components/modal/modal.module.ts +++ b/ui/src/app/shared/components/modal/modal.module.ts @@ -1,20 +1,20 @@ -import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; -import { ReactiveFormsModule } from '@angular/forms'; -import { BrowserModule } from '@angular/platform-browser'; -import { RouterModule } from '@angular/router'; -import { IonicModule } from '@ionic/angular'; -import { TranslateModule } from '@ngx-translate/core'; +import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from "@angular/core"; +import { ReactiveFormsModule } from "@angular/forms"; +import { BrowserModule } from "@angular/platform-browser"; +import { RouterModule } from "@angular/router"; +import { IonicModule } from "@ionic/angular"; +import { TranslateModule } from "@ngx-translate/core"; -import { PipeModule } from '../../pipe/pipe'; -import { HelpButtonComponent } from './help-button/help-button'; -import { ModalComponent } from './modal'; -import { ModalButtonsComponent } from './modal-button/modal-button'; -import { ModalInfoLineComponent } from './modal-info-line/modal-info-line'; -import { ModalLineComponent } from './modal-line/modal-line'; -import { ModalLineItemComponent } from './modal-line/modal-line-item/modal-line-item'; -import { ModalPhasesComponent } from './modal-phases/modal-phases'; -import { ModalValueLineComponent } from './modal-value-line/modal-value-line'; -import { ModalHorizontalLineComponent } from './model-horizontal-line/modal-horizontal-line'; +import { PipeModule } from "../../pipe/pipe"; +import { HelpButtonComponent } from "./help-button/help-button"; +import { ModalComponent } from "./modal"; +import { ModalButtonsComponent } from "./modal-button/modal-button"; +import { ModalInfoLineComponent } from "./modal-info-line/modal-info-line"; +import { ModalLineComponent } from "./modal-line/modal-line"; +import { ModalLineItemComponent } from "./modal-line/modal-line-item/modal-line-item"; +import { ModalPhasesComponent } from "./modal-phases/modal-phases"; +import { ModalValueLineComponent } from "./modal-value-line/modal-value-line"; +import { ModalHorizontalLineComponent } from "./model-horizontal-line/modal-horizontal-line"; @NgModule({ imports: [ diff --git a/ui/src/app/shared/components/modal/modal.ts b/ui/src/app/shared/components/modal/modal.ts index d2365497540..601283c75df 100644 --- a/ui/src/app/shared/components/modal/modal.ts +++ b/ui/src/app/shared/components/modal/modal.ts @@ -14,8 +14,8 @@ export enum Status { } @Component({ - selector: 'oe-modal', - templateUrl: './modal.html', + selector: "oe-modal", + templateUrl: "./modal.html", styles: [` :host { height: 100%; @@ -53,7 +53,7 @@ export class ModalComponent { // Changes applied together public applyChanges() { const updateComponentArray: { name: string, value: any }[] = []; - this.service.startSpinner('spinner'); + this.service.startSpinner("spinner"); for (const key in this.formGroup.controls) { const control = this.formGroup.controls[key]; this.formGroup.controls[key]; @@ -72,10 +72,10 @@ export class ModalComponent { if (this.edge) { this.edge.updateComponentConfig(this.websocket, this.component.id, updateComponentArray) .then(() => { - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); + 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.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/components/modal/model-horizontal-line/modal-horizontal-line.ts b/ui/src/app/shared/components/modal/model-horizontal-line/modal-horizontal-line.ts index b6971de84de..98664ae0144 100644 --- a/ui/src/app/shared/components/modal/model-horizontal-line/modal-horizontal-line.ts +++ b/ui/src/app/shared/components/modal/model-horizontal-line/modal-horizontal-line.ts @@ -4,8 +4,8 @@ import { Component, Input } from "@angular/core"; * Shows a Horizontal Line for every but the last component or a simple Line. */ @Component({ - selector: 'oe-modal-horizontal-line', - templateUrl: './modal-horizontal-line.html', + selector: "oe-modal-horizontal-line", + templateUrl: "./modal-horizontal-line.html", }) export class ModalHorizontalLineComponent { diff --git a/ui/src/app/shared/components/percentagebar/percentagebar.component.ts b/ui/src/app/shared/components/percentagebar/percentagebar.component.ts index 221c1a837ad..0f636a02eba 100644 --- a/ui/src/app/shared/components/percentagebar/percentagebar.component.ts +++ b/ui/src/app/shared/components/percentagebar/percentagebar.component.ts @@ -1,8 +1,8 @@ -import { Component, Input } from '@angular/core'; +import { Component, Input } from "@angular/core"; @Component({ - selector: 'percentagebar', - templateUrl: './percentagebar.component.html', + selector: "percentagebar", + templateUrl: "./percentagebar.component.html", }) export class PercentageBarComponent { diff --git a/ui/src/app/shared/components/pickdate/pickdate.component.spec.ts b/ui/src/app/shared/components/pickdate/pickdate.component.spec.ts index 4e1201fd647..b2f9e4dec6f 100644 --- a/ui/src/app/shared/components/pickdate/pickdate.component.spec.ts +++ b/ui/src/app/shared/components/pickdate/pickdate.component.spec.ts @@ -12,38 +12,38 @@ export function expectNextPeriod(testContext: TestContext, expectToBe: boolean): expect(PickDateComponent.isNextPeriodAllowed(testContext.service)).toBe(expectToBe); } -describe('Pickdate', () => { +describe("Pickdate", () => { let TEST_CONTEXT: TestContext; beforeEach(async () => TEST_CONTEXT = await sharedSetup(), ); - it('#isPreviousPeriodAllowed && #isNextPeriodAllowed - Day-View: firstSetupProtocol = today', () => { + it("#isPreviousPeriodAllowed && #isNextPeriodAllowed - Day-View: firstSetupProtocol = today", () => { const firstSetupProtocol = new Date(); expectPreviousPeriod(TEST_CONTEXT, firstSetupProtocol, false); expectNextPeriod(TEST_CONTEXT, false); }); - it('#isPreviousPeriodAllowed && #isNextPeriodAllowed - Day-View: firstSetupProtocol = yesterday', () => { + it("#isPreviousPeriodAllowed && #isNextPeriodAllowed - Day-View: firstSetupProtocol = yesterday", () => { const firstSetupProtocol = startOfDay(subDays(new Date(), 1)); expectPreviousPeriod(TEST_CONTEXT, firstSetupProtocol, true); expectNextPeriod(TEST_CONTEXT, false); }); - it('#isPreviousPeriodAllowed && #isNextPeriodAllowed - Week-View: firstSetupProtocol = current week', () => { + it("#isPreviousPeriodAllowed && #isNextPeriodAllowed - Week-View: firstSetupProtocol = current week", () => { const firstSetupProtocol = new Date(); expectPreviousPeriod(TEST_CONTEXT, firstSetupProtocol, false); expectNextPeriod(TEST_CONTEXT, false); }); - it('#isPreviousPeriodAllowed && #isNextPeriodAllowed - Week-View: firstSetupProtocol = Start of previous week, current period = current week', () => { + it("#isPreviousPeriodAllowed && #isNextPeriodAllowed - Week-View: firstSetupProtocol = Start of previous week, current period = current week", () => { const firstSetupProtocol = startOfWeek(subWeeks(new Date(), 1), { weekStartsOn: 1 }); expectPreviousPeriod(TEST_CONTEXT, firstSetupProtocol, true); expectNextPeriod(TEST_CONTEXT, false); }); - it('#isPreviousPeriodAllowed && #isNextPeriodAllowed - Week-View: firstSetupProtocol = Today, current period = previous week', () => { + it("#isPreviousPeriodAllowed && #isNextPeriodAllowed - Week-View: firstSetupProtocol = Today, current period = previous week", () => { const firstSetupProtocol = new Date(); expectPreviousPeriod(TEST_CONTEXT, firstSetupProtocol, false); expectNextPeriod(TEST_CONTEXT, false); @@ -52,14 +52,14 @@ describe('Pickdate', () => { const previousWeekPeriod = new DefaultTypes.HistoryPeriod(startOfWeek(subWeeks(new Date(), 1), { weekStartsOn: 1 }), endOfWeek(subWeeks(new Date(), 1), { weekStartsOn: 1 })); const currentWeekPeriod = new DefaultTypes.HistoryPeriod(startOfWeek(new Date(), { weekStartsOn: 1 }), endOfWeek(new Date(), { weekStartsOn: 1 })); - it('#isPreviousPeriodAllowed && #isNextPeriodAllowed - Week-View: firstSetupProtocol = previous week, current period = previous week', () => { + it("#isPreviousPeriodAllowed && #isNextPeriodAllowed - Week-View: firstSetupProtocol = previous week, current period = previous week", () => { TEST_CONTEXT.service.historyPeriod.next(previousWeekPeriod); const firstSetupProtocol = startOfWeek(subWeeks(new Date(), 1), { weekStartsOn: 1 }); expectPreviousPeriod(TEST_CONTEXT, firstSetupProtocol, false); expectNextPeriod(TEST_CONTEXT, true); }); - it('#isPreviousPeriodAllowed && #isNextPeriodAllowed - Week-View: firstSetupProtocol = 2 weeks ago, current period = previous week', () => { + it("#isPreviousPeriodAllowed && #isNextPeriodAllowed - Week-View: firstSetupProtocol = 2 weeks ago, current period = previous week", () => { TEST_CONTEXT.service.historyPeriod.next(previousWeekPeriod); const firstSetupProtocol = startOfWeek(subWeeks(new Date(), 2), { weekStartsOn: 1 }); @@ -67,7 +67,7 @@ describe('Pickdate', () => { expectNextPeriod(TEST_CONTEXT, true); }); - it('#isPreviousPeriodAllowed && #isNextPeriodAllowed - Week-View: firstSetupProtocol = 2 weeks ago, current period = current week', () => { + it("#isPreviousPeriodAllowed && #isNextPeriodAllowed - Week-View: firstSetupProtocol = 2 weeks ago, current period = current week", () => { TEST_CONTEXT.service.historyPeriod.next(currentWeekPeriod); const firstSetupProtocol = startOfWeek(subWeeks(new Date(), 2), { weekStartsOn: 1 }); @@ -78,20 +78,20 @@ describe('Pickdate', () => { const previousMonthPeriod = new DefaultTypes.HistoryPeriod(startOfMonth(subMonths(new Date(), 1)), endOfMonth(subMonths(new Date(), 1))); const currentMonthPeriod = new DefaultTypes.HistoryPeriod(startOfMonth(new Date()), endOfMonth(new Date())); - it('#isPreviousPeriodAllowed && #isNextPeriodAllowed - Month-View: firstSetupProtocol = today, current period = current month', () => { + it("#isPreviousPeriodAllowed && #isNextPeriodAllowed - Month-View: firstSetupProtocol = today, current period = current month", () => { const firstSetupProtocol = new Date(); TEST_CONTEXT.service.historyPeriod.next(currentMonthPeriod); expectPreviousPeriod(TEST_CONTEXT, firstSetupProtocol, false); expectNextPeriod(TEST_CONTEXT, false); }); - it('#isPreviousPeriodAllowed && #isNextPeriodAllowed - Month-View: firstSetupProtocol = start of current month, current period = previous month', () => { + it("#isPreviousPeriodAllowed && #isNextPeriodAllowed - Month-View: firstSetupProtocol = start of current month, current period = previous month", () => { TEST_CONTEXT.service.historyPeriod.next(previousMonthPeriod); const firstSetupProtocol = startOfMonth(subMonths(new Date(), 1)); expectPreviousPeriod(TEST_CONTEXT, firstSetupProtocol, false); expectNextPeriod(TEST_CONTEXT, true); }); - it('#isPreviousPeriodAllowed && #isNextPeriodAllowed - Month-View: firstSetupProtocol = 2 months ago, current period = previous month', () => { + it("#isPreviousPeriodAllowed && #isNextPeriodAllowed - Month-View: firstSetupProtocol = 2 months ago, current period = previous month", () => { TEST_CONTEXT.service.historyPeriod.next(previousMonthPeriod); const firstSetupProtocol = startOfMonth(subMonths(new Date(), 2)); expectPreviousPeriod(TEST_CONTEXT, firstSetupProtocol, true); @@ -101,21 +101,21 @@ describe('Pickdate', () => { const previousYearPeriod = new DefaultTypes.HistoryPeriod(startOfYear(subYears(new Date(), 1)), endOfYear(subYears(new Date(), 1))); const currentYearPeriod = new DefaultTypes.HistoryPeriod(startOfYear(new Date()), endOfYear(new Date())); - it('#isPreviousPeriodAllowed && #isNextPeriodAllowed - Year-View: firstSetupProtocol = today, current period = current year', () => { + it("#isPreviousPeriodAllowed && #isNextPeriodAllowed - Year-View: firstSetupProtocol = today, current period = current year", () => { const firstSetupProtocol = new Date(); TEST_CONTEXT.service.historyPeriod.next(currentYearPeriod); expectPreviousPeriod(TEST_CONTEXT, firstSetupProtocol, false); expectNextPeriod(TEST_CONTEXT, false); }); - it('#isPreviousPeriodAllowed && #isNextPeriodAllowed - Year-View: firstSetupProtocol = previous year, current period = previous year', () => { + it("#isPreviousPeriodAllowed && #isNextPeriodAllowed - Year-View: firstSetupProtocol = previous year, current period = previous year", () => { TEST_CONTEXT.service.historyPeriod.next(previousYearPeriod); const firstSetupProtocol = startOfYear(subYears(new Date(), 1)); expectPreviousPeriod(TEST_CONTEXT, firstSetupProtocol, false); expectNextPeriod(TEST_CONTEXT, true); }); - it('#isPreviousPeriodAllowed && #isNextPeriodAllowed - Year-View: firstSetupProtocol = 2 years ago, current period = previous year', () => { + it("#isPreviousPeriodAllowed && #isNextPeriodAllowed - Year-View: firstSetupProtocol = 2 years ago, current period = previous year", () => { TEST_CONTEXT.service.historyPeriod.next(previousYearPeriod); const firstSetupProtocol = startOfYear(subYears(new Date(), 2)); @@ -123,7 +123,7 @@ describe('Pickdate', () => { expectNextPeriod(TEST_CONTEXT, true); }); - it('#isPreviousPeriodAllowed && #isNextPeriodAllowed - Year-View: firstSetupProtocol = 2 years ago, current period = this year', () => { + it("#isPreviousPeriodAllowed && #isNextPeriodAllowed - Year-View: firstSetupProtocol = 2 years ago, current period = this year", () => { TEST_CONTEXT.service.historyPeriod.next(currentYearPeriod); const firstSetupProtocol = startOfYear(subYears(new Date(), 2)); @@ -131,7 +131,7 @@ describe('Pickdate', () => { expectNextPeriod(TEST_CONTEXT, false); }); - it('#isPreviousPeriodAllowed && #isNextPeriodAllowed - Total-View', () => { + it("#isPreviousPeriodAllowed && #isNextPeriodAllowed - Total-View", () => { const firstSetupProtocol = startOfYear(subYears(new Date(), 2)); TEST_CONTEXT.service.historyPeriod.next(new DefaultTypes.HistoryPeriod(firstSetupProtocol, new Date())); TEST_CONTEXT.service.periodString = DefaultTypes.PeriodString.TOTAL; diff --git a/ui/src/app/shared/components/pickdate/pickdate.component.ts b/ui/src/app/shared/components/pickdate/pickdate.component.ts index 885544f107a..9d2e83fd813 100644 --- a/ui/src/app/shared/components/pickdate/pickdate.component.ts +++ b/ui/src/app/shared/components/pickdate/pickdate.component.ts @@ -1,18 +1,18 @@ // @ts-strict-ignore -import { Component, Input, OnDestroy, OnInit } from '@angular/core'; -import { PopoverController } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; -import { addMonths, addYears, differenceInDays, differenceInMilliseconds, endOfDay, endOfMonth, endOfYear, isAfter, isBefore, startOfDay, startOfMonth, startOfWeek, startOfYear, subMonths, subYears } from 'date-fns'; -import { addDays, addWeeks, endOfWeek, isFuture, subDays, subWeeks } from 'date-fns/esm'; +import { Component, Input, OnDestroy, OnInit } from "@angular/core"; +import { PopoverController } from "@ionic/angular"; +import { TranslateService } from "@ngx-translate/core"; +import { addMonths, addYears, differenceInDays, differenceInMilliseconds, endOfDay, endOfMonth, endOfYear, isAfter, isBefore, startOfDay, startOfMonth, startOfWeek, startOfYear, subMonths, subYears } from "date-fns"; +import { addDays, addWeeks, endOfWeek, isFuture, subDays, subWeeks } from "date-fns/esm"; -import { DefaultTypes } from '../../service/defaulttypes'; -import { Edge, Service } from '../../shared'; -import { DateUtils } from '../../utils/date/dateutils'; -import { PickDatePopoverComponent } from './popover/popover.component'; +import { DefaultTypes } from "../../service/defaulttypes"; +import { Edge, Service } from "../../shared"; +import { DateUtils } from "../../utils/date/dateutils"; +import { PickDatePopoverComponent } from "./popover/popover.component"; @Component({ - selector: 'pickdate', - templateUrl: './pickdate.component.html', + selector: "pickdate", + templateUrl: "./pickdate.component.html", }) export class PickDateComponent implements OnInit, OnDestroy { @@ -266,7 +266,7 @@ export class PickDateComponent implements OnInit, OnDestroy { } case DefaultTypes.PeriodString.TOTAL: { - this.setDateRange(new DefaultTypes.HistoryPeriod(this.edge?.firstSetupProtocol ?? DateUtils.stringToDate('03.11.2022 16:04:37'), endOfYear(addYears(this.service.historyPeriod.value.to, 1)))); + this.setDateRange(new DefaultTypes.HistoryPeriod(this.edge?.firstSetupProtocol ?? DateUtils.stringToDate("03.11.2022 16:04:37"), endOfYear(addYears(this.service.historyPeriod.value.to, 1)))); this.disableArrow = true; break; } @@ -329,6 +329,9 @@ export class PickDateComponent implements OnInit, OnDestroy { this.setDateRange(new DefaultTypes.HistoryPeriod(subDays(this.service.historyPeriod.value.from, dateDistance), subDays(this.service.historyPeriod.value.to, dateDistance))); break; } + default: + break; + } } @@ -337,7 +340,7 @@ export class PickDateComponent implements OnInit, OnDestroy { component: PickDatePopoverComponent, event: ev, translucent: false, - cssClass: 'pickdate-popover', + cssClass: "pickdate-popover", componentProps: { setDateRange: this.setDateRange, edge: this.edge, @@ -399,7 +402,7 @@ export class PickDateComponent implements OnInit, OnDestroy { * calculates the milliseconds until next period (Day|Week) will occour * is used to change date period */ - private millisecondsUntilnextPeriod(): number { + private millisecondsUntilnextPeriod(): number | null { // + 1000 to reach the next day switch (this.service.periodString) { case DefaultTypes.PeriodString.DAY: { @@ -422,6 +425,8 @@ export class PickDateComponent implements OnInit, OnDestroy { const endOfYearTime = endOfYear(currentDayTime); return differenceInMilliseconds(endOfYearTime, currentDayTime) + 1000; } + default: + return null; } } diff --git a/ui/src/app/shared/components/pickdate/pickdate.module.ts b/ui/src/app/shared/components/pickdate/pickdate.module.ts index c555a743cac..a094850a04c 100644 --- a/ui/src/app/shared/components/pickdate/pickdate.module.ts +++ b/ui/src/app/shared/components/pickdate/pickdate.module.ts @@ -1,11 +1,11 @@ -import { NgModule } from '@angular/core'; -import { ReactiveFormsModule } from '@angular/forms'; -import { BrowserModule } from '@angular/platform-browser'; -import { IonicModule } from '@ionic/angular'; -import { TranslateModule } from '@ngx-translate/core'; -import { AngularMyDatePickerModule } from '@nodro7/angular-mydatepicker'; -import { PickDateComponent } from './pickdate.component'; -import { PickDatePopoverComponent } from './popover/popover.component'; +import { NgModule } from "@angular/core"; +import { ReactiveFormsModule } from "@angular/forms"; +import { BrowserModule } from "@angular/platform-browser"; +import { IonicModule } from "@ionic/angular"; +import { TranslateModule } from "@ngx-translate/core"; +import { AngularMyDatePickerModule } from "@nodro7/angular-mydatepicker"; +import { PickDateComponent } from "./pickdate.component"; +import { PickDatePopoverComponent } from "./popover/popover.component"; @NgModule({ imports: [ diff --git a/ui/src/app/shared/components/pickdate/popover/popover.component.ts b/ui/src/app/shared/components/pickdate/popover/popover.component.ts index e13cf8bc139..a4586947d2f 100644 --- a/ui/src/app/shared/components/pickdate/popover/popover.component.ts +++ b/ui/src/app/shared/components/pickdate/popover/popover.component.ts @@ -1,18 +1,18 @@ // @ts-strict-ignore -import { Component, Input, OnInit } from '@angular/core'; -import { PopoverController } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; -import { CalAnimation, IAngularMyDpOptions, IMyDate, IMyDateRangeModel } from '@nodro7/angular-mydatepicker'; -import { endOfMonth, startOfMonth } from 'date-fns'; -import { addDays, endOfWeek, endOfYear, getDate, getMonth, getYear, startOfWeek, startOfYear } from 'date-fns/esm'; -import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; -import { EdgePermission, Service, Utils } from 'src/app/shared/shared'; +import { Component, Input, OnInit } from "@angular/core"; +import { PopoverController } from "@ionic/angular"; +import { TranslateService } from "@ngx-translate/core"; +import { CalAnimation, IAngularMyDpOptions, IMyDate, IMyDateRangeModel } from "@nodro7/angular-mydatepicker"; +import { endOfMonth, startOfMonth } from "date-fns"; +import { addDays, endOfWeek, endOfYear, getDate, getMonth, getYear, startOfWeek, startOfYear } from "date-fns/esm"; +import { DefaultTypes } from "src/app/shared/service/defaulttypes"; +import { EdgePermission, Service, Utils } from "src/app/shared/shared"; -import { Edge } from '../../edge/edge'; +import { Edge } from "../../edge/edge"; @Component({ - selector: 'pickdatepopover', - templateUrl: './popover.component.html', + selector: "pickdatepopover", + templateUrl: "./popover.component.html", }) export class PickDatePopoverComponent implements OnInit { @@ -20,14 +20,14 @@ export class PickDatePopoverComponent implements OnInit { @Input() public edge: Edge | null = null; @Input() public historyPeriods: DefaultTypes.PeriodStringValues[] = []; - public locale: string = 'de'; + public locale: string = "de"; public showCustomDate: boolean = false; protected periods: string[] = []; protected readonly TOMORROW = addDays(new Date(), 1); protected myDpOptions: IAngularMyDpOptions = { stylesData: { - selector: 'dp1', + selector: "dp1", styles: ` .dp1 .myDpMarkCurrDay, .dp1 .myDpMarkCurrMonth, @@ -38,13 +38,13 @@ export class PickDatePopoverComponent implements OnInit { `, }, calendarAnimation: { in: CalAnimation.FlipDiagonal, out: CalAnimation.ScaleCenter }, - dateFormat: 'dd.mm.yyyy', + dateFormat: "dd.mm.yyyy", dateRange: true, disableSince: this.toIMyDate(this.TOMORROW), disableUntil: { day: 1, month: 1, year: 2013 }, // TODO start with date since the edge is available inline: true, - selectorHeight: '225px', - selectorWidth: '251px', + selectorHeight: "225px", + selectorWidth: "251px", showWeekNumbers: true, }; protected readonly DefaultTypes = DefaultTypes; @@ -111,6 +111,8 @@ export class PickDatePopoverComponent implements OnInit { this.popoverCtrl.dismiss(); break; } + default: + break; } } diff --git a/ui/src/app/shared/components/pickdate/popover/popover.spec.ts b/ui/src/app/shared/components/pickdate/popover/popover.spec.ts index 05806ec3b2f..fd6a8f9463c 100644 --- a/ui/src/app/shared/components/pickdate/popover/popover.spec.ts +++ b/ui/src/app/shared/components/pickdate/popover/popover.spec.ts @@ -10,7 +10,7 @@ import { Language, MyTranslateLoader } from "src/app/shared/type/language"; import { PickdateModule } from "../pickdate.module"; import { PickDatePopoverComponent } from "./popover.component"; -describe('PickdatePopover', () => { +describe("PickdatePopover", () => { let fixture: ComponentFixture; let component: PickDatePopoverComponent; @@ -38,12 +38,12 @@ describe('PickdatePopover', () => { }); }); - it('is AngularMyDatePickerModule calendar opening on "other period" button', () => { + it("is AngularMyDatePickerModule calendar opening on \"other period\" button", () => { const { debugElement } = fixture; - const popoverBtn = debugElement.query(By.css('[testId="popover-button"]')); - popoverBtn.triggerEventHandler('click', null); + const popoverBtn = debugElement.query(By.css("[testId=\"popover-button\"]")); + popoverBtn.triggerEventHandler("click", null); fixture.detectChanges(); expect(component).toBeDefined(); - expect((debugElement?.nativeNode?.children as HTMLCollection)?.item(2)?.localName).toEqual('lib-angular-mydatepicker-calendar'); + expect((debugElement?.nativeNode?.children as HTMLCollection)?.item(2)?.localName).toEqual("lib-angular-mydatepicker-calendar"); }); }); diff --git a/ui/src/app/shared/components/shared/converter.ts b/ui/src/app/shared/components/shared/converter.ts index 94f0c2a7635..136ecff555b 100644 --- a/ui/src/app/shared/components/shared/converter.ts +++ b/ui/src/app/shared/components/shared/converter.ts @@ -22,21 +22,21 @@ export namespace Converter { }; export const IF_NUMBER = (value: number | string | null, callback: (number: number) => string) => { - if (typeof value === 'number') { + if (typeof value === "number") { return callback(value); } return "-"; // null or string }; export const IF_STRING = (value: number | string | null, callback: (text: string) => string) => { - if (typeof value === 'string') { + if (typeof value === "string") { return callback(value); } return "-"; // null or number }; export const IF_NUMBER_OR_STRING = (value: number | string | null, callback: (value: number | string) => string) => { - if (typeof value === 'number' || typeof value === 'string') { + if (typeof value === "number" || typeof value === "string") { return callback(value); } return "-"; // null or string @@ -153,13 +153,13 @@ export namespace Converter { const limitation = () => { switch (value) { case 1: - return '0'; + return "0"; case 2: - return '30'; + return "30"; case 4: - return '60'; + return "60"; case 8: - return '100'; + return "100"; default: return null; } @@ -180,7 +180,7 @@ export namespace Converter { * @returns always "" */ export const HIDE_VALUE: Converter = (ignore): string => { - return ''; + return ""; }; /** @@ -192,29 +192,29 @@ export namespace Converter { * @returns the otherPower */ export const CALCULATE_CONSUMPTION_OTHER_POWER = (evcss: EdgeConfig.Component[], consumptionMeters: EdgeConfig.Component[], currentData: CurrentData): number => { - const activePowerTotal = currentData.allComponents['_sum/ConsumptionActivePower'] ?? null; - const evcsChargePowerTotal = evcss?.map(evcs => currentData.allComponents[evcs.id + '/ChargePower'])?.reduce((prev, curr) => Utils.addSafely(prev, curr), 0) ?? null; - const consumptionMeterActivePowerTotal = consumptionMeters?.map(meter => currentData.allComponents[meter.id + '/ActivePower'])?.reduce((prev, curr) => Utils.addSafely(prev, curr), 0) ?? null; + const activePowerTotal = currentData.allComponents["_sum/ConsumptionActivePower"] ?? null; + const evcsChargePowerTotal = evcss?.map(evcs => currentData.allComponents[evcs.id + "/ChargePower"])?.reduce((prev, curr) => Utils.addSafely(prev, curr), 0) ?? null; + const consumptionMeterActivePowerTotal = consumptionMeters?.map(meter => currentData.allComponents[meter.id + "/ActivePower"])?.reduce((prev, curr) => Utils.addSafely(prev, curr), 0) ?? null; return Utils.subtractSafely(activePowerTotal, Utils.addSafely(evcsChargePowerTotal, consumptionMeterActivePowerTotal)); }; export const GRID_STATE_TO_MESSAGE = (translate: TranslateService, currentData: CurrentData): string => { - const gridMode = currentData.allComponents['_sum/GridMode']; - const restrictionMode = currentData.allComponents['ctrlEssLimiter14a0/RestrictionMode']; + const gridMode = currentData.allComponents["_sum/GridMode"]; + const restrictionMode = currentData.allComponents["ctrlEssLimiter14a0/RestrictionMode"]; if (gridMode === GridMode.OFF_GRID) { return translate.instant("GRID_STATES.OFF_GRID"); } if (restrictionMode === 1) { - return translate.instant('GRID_STATES.RESTRICTION'); + return translate.instant("GRID_STATES.RESTRICTION"); } return translate.instant("GRID_STATES.NO_EXTERNAL_LIMITATION"); }; export const ON_OFF = (translate: TranslateService) => { return (raw): string => { - return translate.instant(raw == 1 ? 'General.on' : 'General.off'); + return translate.instant(raw == 1 ? "General.on" : "General.off"); }; }; diff --git a/ui/src/app/shared/components/shared/formatter.ts b/ui/src/app/shared/components/shared/formatter.ts index e3bc42073fb..8f2d5df2c8d 100644 --- a/ui/src/app/shared/components/shared/formatter.ts +++ b/ui/src/app/shared/components/shared/formatter.ts @@ -4,31 +4,31 @@ import { Currency } from "../../shared"; export namespace Formatter { export const FORMAT_WATT = (value: number) => { // TODO apply correct locale - return formatNumber(value, 'de', '1.0-0') + " W"; + return formatNumber(value, "de", "1.0-0") + " W"; }; export const FORMAT_VOLT = (value: number) => { // TODO apply correct locale - return formatNumber(value, 'de', '1.0-0') + " V"; + return formatNumber(value, "de", "1.0-0") + " V"; }; export const FORMAT_AMPERE = (value: number) => { // TODO apply correct locale - return formatNumber(value, 'de', '1.1-1') + " A"; + return formatNumber(value, "de", "1.1-1") + " A"; }; export const FORMAT_CELSIUS = (value: number) => { // TODO apply correct locale - return formatNumber(value, 'de', '1.0-0') + " °C"; + return formatNumber(value, "de", "1.0-0") + " °C"; }; export const FORMAT_PERCENT = (value: number) => { // TODO apply correct locale - return formatNumber(value, 'de', '1.0-0') + " %"; + return formatNumber(value, "de", "1.0-0") + " %"; }; export const FORMAT_CURRENCY_PER_KWH = (value: number | string, currency: string = Currency.Unit.CENT) => { // TODO apply correct locale - return formatNumber(parseInt(value.toString()), 'de', '1.0-2') + " " + Currency.getCurrencyLabelByCurrency(currency); + return formatNumber(parseInt(value.toString()), "de", "1.0-2") + " " + Currency.getCurrencyLabelByCurrency(currency); }; } diff --git a/ui/src/app/shared/components/shared/name.ts b/ui/src/app/shared/components/shared/name.ts index 036f798d66f..f998a1fbf17 100644 --- a/ui/src/app/shared/components/shared/name.ts +++ b/ui/src/app/shared/components/shared/name.ts @@ -9,9 +9,9 @@ export namespace Name { (value): string => { if (typeof value === "number") { if (value < 0) { - return name + " " + translate.instant('General.gridSellAdvanced'); + return name + " " + translate.instant("General.gridSellAdvanced"); } else { - return name + " " + translate.instant('General.gridBuyAdvanced'); + return name + " " + translate.instant("General.gridBuyAdvanced"); } } return name; diff --git a/ui/src/app/shared/components/shared/notification/notification.ts b/ui/src/app/shared/components/shared/notification/notification.ts index 2c6c420f073..682dd9d33b4 100644 --- a/ui/src/app/shared/components/shared/notification/notification.ts +++ b/ui/src/app/shared/components/shared/notification/notification.ts @@ -2,12 +2,12 @@ import { Component, Input, OnChanges, OnInit } from "@angular/core"; import { ToastController } from "@ionic/angular"; @Component({ - selector: 'oe-notification', - template: '', + selector: "oe-notification", + template: "", }) export class NotificationComponent implements OnInit, OnChanges { - private static readonly PREFIX = 'hide-notification-'; + private static readonly PREFIX = "hide-notification-"; @Input() private text: string | null = null; @Input() private id: string | number | null = null; @@ -18,7 +18,7 @@ export class NotificationComponent implements OnInit, OnChanges { ngOnInit() { const note = localStorage.getItem(NotificationComponent.PREFIX + this.id); - this.hideMessage = note != null ? note === 'true' : false; + this.hideMessage = note != null ? note === "true" : false; this.createToast(); } @@ -47,16 +47,16 @@ export class NotificationComponent implements OnInit, OnChanges { const popover = await this.toastie.create({ translucent: false, message: this.text, - position: 'bottom', + position: "bottom", buttons: [ - { icon: 'close-outline', role: 'cancel' }, + { icon: "close-outline", role: "cancel" }, ], }); popover.present(); await popover.onDidDismiss().then(() => { - localStorage.setItem(NotificationComponent.PREFIX + this.id, 'true'); + localStorage.setItem(NotificationComponent.PREFIX + this.id, "true"); }); } } diff --git a/ui/src/app/shared/components/shared/oe-formly-component.ts b/ui/src/app/shared/components/shared/oe-formly-component.ts index a463642482f..c300ea59c69 100644 --- a/ui/src/app/shared/components/shared/oe-formly-component.ts +++ b/ui/src/app/shared/components/shared/oe-formly-component.ts @@ -1,5 +1,4 @@ import { FormGroup } from "@angular/forms"; -import { ActivatedRoute } from "@angular/router"; import { FormlyFieldConfig } from "@ngx-formly/core"; import { TranslateService } from "@ngx-translate/core"; import { filter } from "rxjs/operators"; @@ -17,10 +16,9 @@ export abstract class AbstractFormlyComponent { constructor() { const service = SharedModule.injector.get(Service); - const route = SharedModule.injector.get(ActivatedRoute); this.translate = SharedModule.injector.get(TranslateService); - service.setCurrentComponent('', route).then(edge => { + service.getCurrentEdge().then(edge => { edge.getConfig(service.websocket) .pipe(filter(config => !!config)) .subscribe((config) => { @@ -36,7 +34,7 @@ export abstract class AbstractFormlyComponent { required: true, options: [{ lines: view.lines }], }, - wrappers: ['formly-field-modal'], + wrappers: ["formly-field-modal"], }]; }); }); @@ -68,26 +66,26 @@ export type OeFormlyField = export namespace OeFormlyField { export type InfoLine = { - type: 'info-line', + type: "info-line", name: string }; export type Item = { - type: 'item', + type: "item", channel: string, filter?: (value: number | null) => boolean, converter?: (value: number | null) => string }; export type ChildrenLine = { - type: 'children-line', + type: "children-line", name: /* actual name string */ string | /* name string derived from channel value */ { channel: ChannelAddress, converter: Converter }, indentation?: TextIndentation, children: Item[], }; export type ChannelLine = { - type: 'channel-line', + type: "channel-line", name: /* actual name string */ string | /* name string derived from channel value */ Converter, channel: string, filter?: (value: number | null) => boolean, @@ -96,7 +94,7 @@ export namespace OeFormlyField { }; export type ValueFromChannelsLine = { - type: 'value-from-channels-line', + type: "value-from-channels-line", name: string, value: (data: CurrentData) => string, channelsToSubscribe: ChannelAddress[], @@ -105,6 +103,6 @@ export namespace OeFormlyField { }; export type HorizontalLine = { - type: 'horizontal-line', + type: "horizontal-line", }; } diff --git a/ui/src/app/shared/components/shared/phase.ts b/ui/src/app/shared/components/shared/phase.ts index b1c13e10994..6667a67627c 100644 --- a/ui/src/app/shared/components/shared/phase.ts +++ b/ui/src/app/shared/components/shared/phase.ts @@ -1,3 +1,3 @@ export namespace Phase { - export const THREE_PHASE: string[] = ['L1', 'L2', 'L3']; + export const THREE_PHASE: string[] = ["L1", "L2", "L3"]; } diff --git a/ui/src/app/shared/components/shared/testing/common.ts b/ui/src/app/shared/components/shared/testing/common.ts index f8104a42887..62f21fe345a 100644 --- a/ui/src/app/shared/components/shared/testing/common.ts +++ b/ui/src/app/shared/components/shared/testing/common.ts @@ -22,19 +22,19 @@ export namespace OeTester { } export namespace ChartOptions { - export const LINE_CHART_OPTIONS = (period: string, chartType: 'line' | 'bar', options: { [key: string]: { scale: { min?: number, max?: number, beginAtZero?: boolean }, ticks?: { stepSize: number; }; }; }, title?: string): OeChartTester.Dataset.Option => ({ - type: 'option', + export const LINE_CHART_OPTIONS = (period: string, chartType: "line" | "bar", options: { [key: string]: { scale: { min?: number, max?: number, beginAtZero?: boolean }, ticks?: { stepSize: number; }; }; }, title?: string): OeChartTester.Dataset.Option => ({ + type: "option", options: { "responsive": true, "maintainAspectRatio": false, "elements": { "point": { "radius": 0, "hitRadius": 0, "hoverRadius": 0 }, "line": { "stepped": false, "fill": true } }, "datasets": { "bar": {}, "line": {} }, "plugins": { - "colors": { "enabled": false }, "legend": { "display": true, "position": "bottom", "labels": { "color": '' } }, "tooltip": { "intersect": false, "mode": "index", "callbacks": {} }, "annotation": { "annotations": {} }, "datalabels": { + "colors": { "enabled": false }, "legend": { "display": true, "position": "bottom", "labels": { "color": "" } }, "tooltip": { "intersect": false, "mode": "index", "callbacks": {} }, "annotation": { "annotations": {} }, "datalabels": { display: false, }, }, "scales": { "x": { "stacked": true, "offset": false, "type": "time", "ticks": { "source": "auto", "maxTicksLimit": 31 }, "bounds": "ticks", "adapters": { "date": { "locale": { "code": "de", "formatLong": {}, "localize": {}, "match": {}, "options": { "weekStartsOn": 1, "firstWeekContainsDate": 4 } } } }, "time": { "unit": period as TimeUnit, "displayFormats": { "datetime": "yyyy-MM-dd HH:mm:ss", "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" } } }, "left": { - "beginAtZero": false, ...options["left"]?.scale, ...(chartType === 'line' ? { stacked: false } : {}), "title": { "text": "kW", "display": false, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, + "beginAtZero": false, ...options["left"]?.scale, ...(chartType === "line" ? { stacked: false } : {}), "title": { "text": "kW", "display": false, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, "ticks": { ...options["left"]?.ticks, - "color": '', + "color": "", "padding": 5, "maxTicksLimit": ChartConstants.NUMBER_OF_Y_AXIS_TICKS, }, @@ -42,20 +42,20 @@ export namespace OeTester { }, }, }); - export const BAR_CHART_OPTIONS = (period: string, chartType: 'line' | 'bar', options: { [key: string]: { scale: { min: number, max: number; }, ticks?: { stepSize: number; }; }; }, title?: string): OeChartTester.Dataset.Option => ({ - type: 'option', + export const BAR_CHART_OPTIONS = (period: string, chartType: "line" | "bar", options: { [key: string]: { scale: { min: number, max: number; }, ticks?: { stepSize: number; }; }; }, title?: string): OeChartTester.Dataset.Option => ({ + type: "option", options: { "responsive": true, "maintainAspectRatio": false, "elements": { "point": { "radius": 0, "hitRadius": 0, "hoverRadius": 0 }, "line": { "stepped": false, "fill": true } }, "datasets": { "bar": { "barPercentage": 1 }, "line": {} }, "plugins": { - "colors": { "enabled": false }, "legend": { "display": true, "position": "bottom", "labels": { "color": '' } }, "tooltip": { "intersect": false, "mode": "x", "callbacks": {} }, "annotation": { "annotations": {} }, "datalabels": { + "colors": { "enabled": false }, "legend": { "display": true, "position": "bottom", "labels": { "color": "" } }, "tooltip": { "intersect": false, "mode": "x", "callbacks": {} }, "annotation": { "annotations": {} }, "datalabels": { display: false, }, }, "scales": { "x": { "stacked": true, "offset": true, "type": "time", "ticks": { "source": "auto", "maxTicksLimit": 31 }, "bounds": "ticks", "adapters": { "date": { "locale": { "code": "de", "formatLong": {}, "localize": {}, "match": {}, "options": { "weekStartsOn": 1, "firstWeekContainsDate": 4 } } } }, "time": { "unit": period as TimeUnit, "displayFormats": { "datetime": "yyyy-MM-dd HH:mm:ss", "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" } } }, "left": { - ...options["left"]?.scale, ...(chartType === 'line' ? { stacked: false } : {}), "beginAtZero": true, "title": { "text": "kWh", "display": false, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, + ...options["left"]?.scale, ...(chartType === "line" ? { stacked: false } : {}), "beginAtZero": true, "title": { "text": "kWh", "display": false, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, "ticks": { ...options["left"]?.ticks, - "color": '', + "color": "", "padding": 5, "maxTicksLimit": ChartConstants.NUMBER_OF_Y_AXIS_TICKS, }, @@ -63,8 +63,8 @@ export namespace OeTester { }, }, }); - export const MULTI_LINE_OPTIONS = (period: string, chartType: 'line' | 'bar', options: { [key: string]: { scale: { min: number, max: number; }, ticks?: { stepSize: number; }; }; }, title?: string): OeChartTester.Dataset.Option => ({ - type: 'option', + export const MULTI_LINE_OPTIONS = (period: string, chartType: "line" | "bar", options: { [key: string]: { scale: { min: number, max: number; }, ticks?: { stepSize: number; }; }; }, title?: string): OeChartTester.Dataset.Option => ({ + type: "option", options: { "responsive": true, "maintainAspectRatio": false, "elements": { "point": { "radius": 0, "hitRadius": 0, "hoverRadius": 0 }, "line": { "stepped": false, "fill": true } }, "datasets": { "bar": {}, "line": {} }, "plugins": { @@ -72,7 +72,7 @@ export namespace OeTester { "enabled": false, }, "legend": { - "display": true, "position": "bottom", "labels": { "color": '' }, + "display": true, "position": "bottom", "labels": { "color": "" }, }, "tooltip": { "intersect": false, "mode": "index", "callbacks": {}, }, @@ -84,23 +84,23 @@ export namespace OeTester { }, }, "scales": { "x": { "stacked": true, "offset": false, "type": "time", "ticks": { "source": "auto", "maxTicksLimit": 31 }, "bounds": "ticks", "adapters": { "date": { "locale": { "code": "de", "formatLong": {}, "localize": {}, "match": {}, "options": { "weekStartsOn": 1, "firstWeekContainsDate": 4 } } } }, "time": { "unit": period as TimeUnit, "displayFormats": { "datetime": "yyyy-MM-dd HH:mm:ss", "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" } } }, "left": { - ...options["left"]?.scale, ...(chartType === 'line' ? { stacked: false } : {}), "beginAtZero": true, + ...options["left"]?.scale, ...(chartType === "line" ? { stacked: false } : {}), "beginAtZero": true, "title": { "text": "kW", "display": true, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, "ticks": { ...options["left"]?.ticks, - "color": '', + "color": "", "padding": 5, "maxTicksLimit": ChartConstants.NUMBER_OF_Y_AXIS_TICKS, }, }, "right": { - ...options["right"]?.scale, ...(chartType === 'line' ? { stacked: false } : {}), "beginAtZero": true, + ...options["right"]?.scale, ...(chartType === "line" ? { stacked: false } : {}), "beginAtZero": true, "title": { "text": "Zustand", "display": true, "padding": 5, "font": { "size": 11 } }, "position": "right", "grid": { "display": false }, "ticks": { ...options["right"]?.ticks, - "color": '', + "color": "", "padding": 5, "maxTicksLimit": ChartConstants.NUMBER_OF_Y_AXIS_TICKS, }, @@ -108,30 +108,30 @@ export namespace OeTester { }, }, }); - export const MULTI_BAR_OPTIONS = (period: string, chartType: 'line' | 'bar', options: { [key: string]: { scale: { min?: number, max?: number; }, ticks?: { stepSize: number; }; }; }, title?: string): OeChartTester.Dataset.Option => ({ - type: 'option', + export const MULTI_BAR_OPTIONS = (period: string, chartType: "line" | "bar", options: { [key: string]: { scale: { min?: number, max?: number; }, ticks?: { stepSize: number; }; }; }, title?: string): OeChartTester.Dataset.Option => ({ + type: "option", options: { "responsive": true, "maintainAspectRatio": false, "elements": { "point": { "radius": 0, "hitRadius": 0, "hoverRadius": 0 }, "line": { "stepped": false, "fill": true } }, "datasets": { "bar": { "barPercentage": 1 }, "line": {} }, "plugins": { - "colors": { "enabled": false }, "legend": { "display": true, "position": "bottom", "labels": { "color": '' } }, "tooltip": { "intersect": false, "mode": "x", "callbacks": {} }, "annotation": { "annotations": {} }, "datalabels": { + "colors": { "enabled": false }, "legend": { "display": true, "position": "bottom", "labels": { "color": "" } }, "tooltip": { "intersect": false, "mode": "x", "callbacks": {} }, "annotation": { "annotations": {} }, "datalabels": { display: false, }, }, "scales": { "x": { "stacked": true, "offset": true, "type": "time", "ticks": { "source": "auto", "maxTicksLimit": 31 }, "bounds": "ticks", "adapters": { "date": { "locale": { "code": "de", "formatLong": {}, "localize": {}, "match": {}, "options": { "weekStartsOn": 1, "firstWeekContainsDate": 4 } } } }, "time": { "unit": period as TimeUnit, "displayFormats": { "datetime": "yyyy-MM-dd HH:mm:ss", "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" } } }, "left": { - ...options["left"]?.scale, ...(chartType === 'line' ? { stacked: false } : {}), "beginAtZero": true, "title": { "text": "kWh", "display": true, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, + ...options["left"]?.scale, ...(chartType === "line" ? { stacked: false } : {}), "beginAtZero": true, "title": { "text": "kWh", "display": true, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, "ticks": { ...options["left"]?.ticks, - "color": '', + "color": "", "padding": 5, "maxTicksLimit": ChartConstants.NUMBER_OF_Y_AXIS_TICKS, }, }, "right": { - ...options["right"]?.scale, ...(chartType === 'line' ? { stacked: false } : { min: 0 }), "beginAtZero": true, + ...options["right"]?.scale, ...(chartType === "line" ? { stacked: false } : { min: 0 }), "beginAtZero": true, "title": { "text": "Aktive Zeit", "display": true, "padding": 5, "font": { "size": 11 } }, "position": "right", "grid": { "display": false }, "ticks": { - "color": '', + "color": "", "padding": 5, "maxTicksLimit": ChartConstants.NUMBER_OF_Y_AXIS_TICKS, }, diff --git a/ui/src/app/shared/components/shared/testing/tester.ts b/ui/src/app/shared/components/shared/testing/tester.ts index b9e29d6e3af..2e30117a4fa 100644 --- a/ui/src/app/shared/components/shared/testing/tester.ts +++ b/ui/src/app/shared/components/shared/testing/tester.ts @@ -30,7 +30,7 @@ export class OeFormlyViewTester { /** * OeFormlyField.Line */ - case 'children-line': { + case "children-line": { const tmp = OeFormlyViewTester.applyLineWithChildren(field, context); // Prepare result @@ -61,7 +61,7 @@ export class OeFormlyViewTester { // Read or generate name let name: string; - if (typeof (field.name) === 'function') { + if (typeof (field.name) === "function") { name = field.name(tmp.rawValue); } else { name = field.name; @@ -206,17 +206,17 @@ export namespace OeChartTester { export namespace Dataset { export type Data = { - type: 'data', + type: "data", label: string | Converter, value: (number | null)[] }; export type LegendLabel = { - type: 'label', + type: "label", timestamps: Date[] }; export type Option = { - type: 'option', + type: "option", options: Chart.ChartOptions }; } @@ -224,7 +224,7 @@ export namespace OeChartTester { export class OeChartTester { - public static apply(chartData: HistoryUtils.ChartData, chartType: 'line' | 'bar', channels: OeTester.Types.Channels, testContext: TestContext, config: EdgeConfig, xAxisScalingType: XAxisType = XAxisType.TIMESERIES): OeChartTester.View { + public static apply(chartData: HistoryUtils.ChartData, chartType: "line" | "bar", channels: OeTester.Types.Channels, testContext: TestContext, config: EdgeConfig, xAxisScalingType: XAxisType = XAxisType.TIMESERIES): OeChartTester.View { const channelData = OeChartTester.getChannelDataByCharttype(chartType, channels); @@ -258,7 +258,7 @@ export class OeChartTester { */ public static convertChartLabelsToLegendLabels(labels: Date[]): OeChartTester.Dataset.LegendLabel { return { - type: 'label', + type: "label", timestamps: labels, }; } @@ -275,7 +275,7 @@ export class OeChartTester { for (const dataset of datasets) { fields.push( { - type: 'data', + type: "data", label: dataset.label, value: dataset.data as number[], }); @@ -293,7 +293,7 @@ export class OeChartTester { * @param channels the channels * @returns dataset options */ - public static convertChartDataToOptions(chartData: HistoryUtils.ChartData, chartType: 'line' | 'bar', testContext: TestContext, channels: OeTester.Types.Channels, locale: string, config: EdgeConfig, datasets: Chart.ChartDataset[], xAxisType: XAxisType = XAxisType.TIMESERIES, labels: (Date | string)[] = []): OeChartTester.Dataset.Option { + public static convertChartDataToOptions(chartData: HistoryUtils.ChartData, chartType: "line" | "bar", testContext: TestContext, channels: OeTester.Types.Channels, locale: string, config: EdgeConfig, datasets: Chart.ChartDataset[], xAxisType: XAxisType = XAxisType.TIMESERIES, labels: (Date | string)[] = []): OeChartTester.Dataset.Option { const channelData: QueryHistoricTimeseriesDataResponse | QueryHistoricTimeseriesEnergyPerPeriodResponse = OeChartTester.getChannelDataByCharttype(chartType, channels); @@ -302,21 +302,21 @@ export class OeChartTester { displayValues.forEach(displayValue => { const yAxis = chartData.yAxes.find(yaxis => yaxis?.yAxisId == (displayValue?.yAxisId ?? chartData.yAxes[0].yAxisId)); - const label = AbstractHistoryChart.getTooltipsLabelName(displayValue.name, yAxis?.unit, typeof displayValue.nameSuffix == 'function' ? displayValue.nameSuffix(channels.energyChannelWithValues) : null); + const 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', + type: "option", options: AbstractHistoryChart.getOptions(chartData, chartType, testContext.service, testContext.translate, legendOptions, channelData.result, locale, config, datasets, xAxisType, labels), }; } - private static getChannelDataByCharttype(chartType: 'line' | 'bar', channels: OeTester.Types.Channels): QueryHistoricTimeseriesEnergyPerPeriodResponse | QueryHistoricTimeseriesDataResponse { + private static getChannelDataByCharttype(chartType: "line" | "bar", channels: OeTester.Types.Channels): QueryHistoricTimeseriesEnergyPerPeriodResponse | QueryHistoricTimeseriesDataResponse { switch (chartType) { - case 'line': + case "line": return channels.dataChannelWithValues; - case 'bar': + case "bar": return channels.energyPerPeriodChannelWithValues; } } @@ -342,38 +342,38 @@ export namespace OeFormlyViewTester { export namespace Field { export type InfoLine = { - type: 'info-line', + type: "info-line", name: string }; export type Item = { - type: 'item', + type: "item", value: string }; export type ChannelLine = { - type: 'channel-line', + type: "channel-line", name: string, value?: string, indentation?: TextIndentation, }; export type ValueLine = { - type: 'value-from-channels-line', + type: "value-from-channels-line", name: string, value?: string, indentation?: TextIndentation, }; export type ChildrenLine = { - type: 'children-line', + type: "children-line", name: string, indentation?: TextIndentation, children?: Field[] }; export type HorizontalLine = { - type: 'horizontal-line', + type: "horizontal-line", }; } @@ -383,12 +383,12 @@ export namespace OeFormlyViewTester { let value: string | null = null; let rawValue: number | null = null; - if (typeof field.name == 'object') { - rawValue = typeof field.name == 'object' ? (field.name.channel.toString() in context ? context[field.name.channel.toString()] : null) : null; + if (typeof field.name == "object") { + rawValue = typeof field.name == "object" ? (field.name.channel.toString() in context ? context[field.name.channel.toString()] : null) : null; value = field.name.converter(rawValue); } - if (typeof (field.name) === 'string') { + if (typeof (field.name) === "string") { value = field.name; } diff --git a/ui/src/app/shared/components/shared/testing/utils.spec.ts b/ui/src/app/shared/components/shared/testing/utils.spec.ts index 65444f5db9f..641d93f57cd 100644 --- a/ui/src/app/shared/components/shared/testing/utils.spec.ts +++ b/ui/src/app/shared/components/shared/testing/utils.spec.ts @@ -1,7 +1,7 @@ import { registerLocaleData } from "@angular/common"; -import localDE from '@angular/common/locales/de'; -import localeDeExtra from '@angular/common/locales/extra/de'; +import localDE from "@angular/common/locales/de"; +import localeDeExtra from "@angular/common/locales/extra/de"; import { LOCALE_ID } from "@angular/core"; import { TestBed, TestModuleMetadata } from "@angular/core/testing"; import { ActivatedRoute, RouterModule } from "@angular/router"; @@ -29,9 +29,9 @@ export const BASE_TEST_BED: TestModuleMetadata = { export function setTranslateParams(): void { const translateService = TestBed.inject(TranslateService); - translateService.addLangs(['de']); - translateService.use('de'); - registerLocaleData(localDE, 'de', localeDeExtra); + translateService.addLangs(["de"]); + translateService.use("de"); + registerLocaleData(localDE, "de", localeDeExtra); } export async function sharedSetup(): Promise { @@ -46,13 +46,13 @@ export async function sharedSetup(): Promise { } export function removeFunctions(obj: any): any { - if (typeof obj !== 'object' || obj === null) { + if (typeof obj !== "object" || obj === null) { return obj; } const result: any = {}; for (const key in obj) { - if (typeof obj[key] !== 'function') { + if (typeof obj[key] !== "function") { result[key] = removeFunctions(obj[key]); } } diff --git a/ui/src/app/shared/components/status/single/status.component.spec.ts b/ui/src/app/shared/components/status/single/status.component.spec.ts index 3894b66e66b..b6d83233d1b 100644 --- a/ui/src/app/shared/components/status/single/status.component.spec.ts +++ b/ui/src/app/shared/components/status/single/status.component.spec.ts @@ -8,7 +8,7 @@ import { EdgeConfig, PersistencePriority } from "../../edge/edgeconfig"; import { DummyModalController } from "../../shared/testing/DummyModalController"; import { StatusSingleComponent } from "./status.component"; -describe('StatusComponent', () => { +describe("StatusComponent", () => { const testComponent = new EdgeConfig.Component("test", {}, { "testChannel": { accessMode: "RO", @@ -20,12 +20,12 @@ describe('StatusComponent', () => { text: "", }, }); - testComponent.id = 'test0'; + testComponent.id = "test0"; let statusComponent: StatusSingleComponent; - const serviceSpy = jasmine.createSpyObj('Service', ['getConfig'], ['currentEdge']); - const edgeSpy = jasmine.createSpyObj('Edge', ['subscribeChannels', 'isVersionAtLeast', 'unsubscribeChannels']); - const edgeConfigSpy = jasmine.createSpyObj('EdgeConfig', ['listActiveComponents'], ['components']); + const serviceSpy = jasmine.createSpyObj("Service", ["getConfig"], ["currentEdge"]); + const edgeSpy = jasmine.createSpyObj("Edge", ["subscribeChannels", "isVersionAtLeast", "unsubscribeChannels"]); + const edgeConfigSpy = jasmine.createSpyObj("EdgeConfig", ["listActiveComponents"], ["components"]); // initialize variables only in beforeEach, beforeAll beforeEach((() => { TestBed.configureTestingModule({ @@ -44,22 +44,22 @@ describe('StatusComponent', () => { valueEdgeSpy.unsubscribeChannels.and.callThrough(); const valueServiceSpy = TestBed.inject(Service) as jasmine.SpyObj; - spyPropertyGetter(valueServiceSpy, 'currentEdge').and.returnValue(new BehaviorSubject(TestBed.inject(Edge))); + spyPropertyGetter(valueServiceSpy, "currentEdge").and.returnValue(new BehaviorSubject(TestBed.inject(Edge))); const valueEdgeConfigSpy = TestBed.inject(EdgeConfig) as jasmine.SpyObj; - valueEdgeConfigSpy.listActiveComponents.and.returnValue([{ category: { icon: '', title: 'title' }, components: [testComponent] }]); - spyPropertyGetter(valueEdgeConfigSpy, 'components').and.returnValue({ [testComponent.id]: testComponent }); + valueEdgeConfigSpy.listActiveComponents.and.returnValue([{ category: { icon: "", title: "title" }, components: [testComponent] }]); + spyPropertyGetter(valueEdgeConfigSpy, "components").and.returnValue({ [testComponent.id]: testComponent }); valueServiceSpy.getConfig.and.resolveTo(TestBed.inject(EdgeConfig)); statusComponent = TestBed.inject(StatusSingleComponent); })); - it('Test add Channels for subscription', async () => { + it("Test add Channels for subscription", async () => { await statusComponent.ngOnInit(); await statusComponent.subscribeInfoChannels(testComponent); expect(statusComponent.subscribedInfoChannels).toHaveSize(2); - expect(statusComponent.subscribedInfoChannels).toContain(new ChannelAddress(testComponent.id, 'State')); - expect(statusComponent.subscribedInfoChannels).toContain(new ChannelAddress(testComponent.id, 'testChannel')); + expect(statusComponent.subscribedInfoChannels).toContain(new ChannelAddress(testComponent.id, "State")); + expect(statusComponent.subscribedInfoChannels).toContain(new ChannelAddress(testComponent.id, "testChannel")); }); }); diff --git a/ui/src/app/shared/components/status/single/status.component.ts b/ui/src/app/shared/components/status/single/status.component.ts index 6f3343cb5d3..9d269b1ce59 100644 --- a/ui/src/app/shared/components/status/single/status.component.ts +++ b/ui/src/app/shared/components/status/single/status.component.ts @@ -1,19 +1,19 @@ // @ts-strict-ignore -import { Component, OnDestroy, OnInit } from '@angular/core'; -import { ModalController } from '@ionic/angular'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; -import { ComponentJsonApiRequest } from 'src/app/shared/jsonrpc/request/componentJsonApiRequest'; -import { GetStateChannelsOfComponentRequest } from 'src/app/shared/jsonrpc/request/getStateChannelsOfComponentRequest'; -import { GetChannelsOfComponentResponse } from 'src/app/shared/jsonrpc/response/getChannelsOfComponentResponse'; -import { ChannelAddress, EdgePermission, Service, Websocket } from 'src/app/shared/shared'; +import { Component, OnDestroy, OnInit } from "@angular/core"; +import { ModalController } from "@ionic/angular"; +import { Subject } from "rxjs"; +import { takeUntil } from "rxjs/operators"; +import { ComponentJsonApiRequest } from "src/app/shared/jsonrpc/request/componentJsonApiRequest"; +import { GetStateChannelsOfComponentRequest } from "src/app/shared/jsonrpc/request/getStateChannelsOfComponentRequest"; +import { GetChannelsOfComponentResponse } from "src/app/shared/jsonrpc/response/getChannelsOfComponentResponse"; +import { ChannelAddress, EdgePermission, Service, Websocket } from "src/app/shared/shared"; -import { Edge } from '../../edge/edge'; -import { CategorizedComponents, EdgeConfig } from '../../edge/edgeconfig'; +import { Edge } from "../../edge/edge"; +import { CategorizedComponents, EdgeConfig } from "../../edge/edgeconfig"; @Component({ selector: StatusSingleComponent.SELECTOR, - templateUrl: './status.component.html', + templateUrl: "./status.component.html", }) export class StatusSingleComponent implements OnInit, OnDestroy { private static readonly SELECTOR = "statussingle"; @@ -45,9 +45,9 @@ export class StatusSingleComponent implements OnInit, OnDestroy { this.components.forEach(categorizedComponent => { categorizedComponent.components.forEach(component => { // sets all arrow buttons to standard position (folded) - component['showProperties'] = false; + component["showProperties"] = false; this.subscribedInfoChannels.push( - new ChannelAddress(component.id, 'State'), + new ChannelAddress(component.id, "State"), ); }); }); @@ -84,10 +84,10 @@ export class StatusSingleComponent implements OnInit, OnDestroy { this.edge?.subscribeChannels(this.websocket, StatusSingleComponent.SELECTOR, this.subscribedInfoChannels); } - private getStateChannels(componentId: string): Promise { + private getStateChannels(componentId: string): Promise { return new Promise((resolve, reject) => { if (EdgePermission.hasChannelsInEdgeConfig(this.edge)) { - const channels: typeof this.channels['componentId'] = {}; + const channels: typeof this.channels["componentId"] = {}; for (const [key, value] of Object.entries(this.config.components[componentId].channels)) { // show only state channels @@ -102,10 +102,10 @@ export class StatusSingleComponent implements OnInit, OnDestroy { } this.edge.sendRequest(this.websocket, new ComponentJsonApiRequest({ - componentId: '_componentManager', + componentId: "_componentManager", payload: new GetStateChannelsOfComponentRequest({ componentId: componentId }), })).then((response: GetChannelsOfComponentResponse) => { - const channels: typeof this.channels['componentId'] = {}; + const channels: typeof this.channels["componentId"] = {}; for (const item of response.result.channels) { channels[item.id] = { text: item.text, level: item.level }; } diff --git a/ui/src/app/shared/directive/autofill.ts b/ui/src/app/shared/directive/autofill.ts index 8665630df5b..ef1dfc539f4 100644 --- a/ui/src/app/shared/directive/autofill.ts +++ b/ui/src/app/shared/directive/autofill.ts @@ -1,20 +1,20 @@ // @ts-strict-ignore -import { Directive, ElementRef, OnInit } from '@angular/core'; -import { Capacitor } from '@capacitor/core'; -import { Logger } from '../shared'; +import { Directive, ElementRef, OnInit } from "@angular/core"; +import { Capacitor } from "@capacitor/core"; +import { Logger } from "../shared"; @Directive({ - selector: '[appAutofill]', + selector: "[appAutofill]", }) export class AutofillDirective implements OnInit { constructor(private el: ElementRef, private logger: Logger) { } ngOnInit(): void { - if (Capacitor.getPlatform() !== 'ios') { return; } + if (Capacitor.getPlatform() !== "ios") { return; } setTimeout(() => { try { - this.el.nativeElement.children[0].addEventListener('change', (e) => { + this.el.nativeElement.children[0].addEventListener("change", (e) => { this.el.nativeElement.value = (e.target as any).value; }); } catch { diff --git a/ui/src/app/shared/directive/directive.ts b/ui/src/app/shared/directive/directive.ts index cd1e4561875..5dfbcd6368c 100644 --- a/ui/src/app/shared/directive/directive.ts +++ b/ui/src/app/shared/directive/directive.ts @@ -1,7 +1,7 @@ -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; -import { AutofillDirective } from './autofill'; -import { VarDirective } from './ngvar'; +import { NgModule } from "@angular/core"; +import { BrowserModule } from "@angular/platform-browser"; +import { AutofillDirective } from "./autofill"; +import { VarDirective } from "./ngvar"; @NgModule({ imports: [ diff --git a/ui/src/app/shared/directive/ngvar.ts b/ui/src/app/shared/directive/ngvar.ts index a4655449422..01923e9870a 100644 --- a/ui/src/app/shared/directive/ngvar.ts +++ b/ui/src/app/shared/directive/ngvar.ts @@ -1,7 +1,7 @@ -import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core'; +import { Directive, Input, TemplateRef, ViewContainerRef } from "@angular/core"; @Directive({ - selector: '[ngVar]', + selector: "[ngVar]", }) export class VarDirective { private context: { diff --git a/ui/src/app/shared/guards/functional-guards.ts b/ui/src/app/shared/guards/functional-guards.ts new file mode 100644 index 00000000000..ac3db77136f --- /dev/null +++ b/ui/src/app/shared/guards/functional-guards.ts @@ -0,0 +1,35 @@ +// @ts-strict-ignore +import { Location } from "@angular/common"; +import { inject } from "@angular/core"; +import { ActivatedRouteSnapshot, RouterStateSnapshot } from "@angular/router"; +import { filter, take } from "rxjs/operators"; +import { Service } from "../shared"; +import { Role } from "../type/role"; + +/** + * Determines if user is allowed to navigate to route, dependent on edge role + * + * @param route the route snapshot + * @param state the routerStateSnapshot + * @returns true, if edge.role equals requiredTole (provided in {@link Route.data} ) + */ +export const hasEdgeRole = (role: Role) => { + return (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => { + const location = inject(Location); + const service = inject(Service); + service.currentEdge.pipe(filter(edge => !!edge), take(1)).subscribe((edge) => { + if (edge) { + const roleIsAtLeast = Role.isAtLeast(edge.role, role); + + if (!roleIsAtLeast) { + console.warn(`Routing Failed. Reason: User not allowed to access [component:${route?.component["SELECTOR"] ?? state.url}]`); + location.back(); + } + return roleIsAtLeast; + } + return false; + }); + + return true; + }; +}; diff --git a/ui/src/app/shared/jsonrpc/base.ts b/ui/src/app/shared/jsonrpc/base.ts index 8fd40a1af96..709ade30497 100644 --- a/ui/src/app/shared/jsonrpc/base.ts +++ b/ui/src/app/shared/jsonrpc/base.ts @@ -1,4 +1,4 @@ -import { v4 as uuidv4 } from 'uuid'; +import { v4 as uuidv4 } from "uuid"; export abstract class JsonrpcMessage { public readonly jsonrpc: string = "2.0"; diff --git a/ui/src/app/shared/jsonrpc/notification/edgeConfigNotification.ts b/ui/src/app/shared/jsonrpc/notification/edgeConfigNotification.ts index 5fd4a0da61c..6e86011ebc2 100644 --- a/ui/src/app/shared/jsonrpc/notification/edgeConfigNotification.ts +++ b/ui/src/app/shared/jsonrpc/notification/edgeConfigNotification.ts @@ -1,4 +1,4 @@ -import { EdgeConfig } from '../../components/edge/edgeconfig'; +import { EdgeConfig } from "../../components/edge/edgeconfig"; import { JsonrpcNotification } from "../base"; /** diff --git a/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesDataRequest.ts b/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesDataRequest.ts index 170c5b8af7f..c96f00e5752 100644 --- a/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesDataRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesDataRequest.ts @@ -1,5 +1,5 @@ // @ts-strict-ignore -import { format } from 'date-fns'; +import { format } from "date-fns"; import { Resolution } from "src/app/edge/history/shared"; import { ChannelAddress } from "../../../shared/type/channeladdress"; import { JsonrpcRequest } from "../base"; @@ -34,8 +34,8 @@ export class QueryHistoricTimeseriesDataRequest extends JsonrpcRequest { ) { super(QueryHistoricTimeseriesDataRequest.METHOD, { timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, - fromDate: format(fromDate, 'yyyy-MM-dd'), - toDate: format(toDate, 'yyyy-MM-dd'), + fromDate: format(fromDate, "yyyy-MM-dd"), + toDate: format(toDate, "yyyy-MM-dd"), channels: JsonRpcUtils.channelsToStringArray(channels), resolution: resolution, }); diff --git a/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesEnergyPerPeriodRequest.ts b/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesEnergyPerPeriodRequest.ts index af0a86a679c..3c5bbde6911 100644 --- a/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesEnergyPerPeriodRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesEnergyPerPeriodRequest.ts @@ -1,5 +1,5 @@ // @ts-strict-ignore -import { format } from 'date-fns'; +import { format } from "date-fns"; import { Resolution } from "src/app/edge/history/shared"; import { ChannelAddress } from "../../type/channeladdress"; import { JsonrpcRequest } from "../base"; @@ -36,8 +36,8 @@ export class QueryHistoricTimeseriesEnergyPerPeriodRequest extends JsonrpcReques ) { super(QueryHistoricTimeseriesEnergyPerPeriodRequest.METHOD, { timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, - fromDate: format(fromDate, 'yyyy-MM-dd'), - toDate: format(toDate, 'yyyy-MM-dd'), + fromDate: format(fromDate, "yyyy-MM-dd"), + toDate: format(toDate, "yyyy-MM-dd"), channels: JsonRpcUtils.channelsToStringArray(channels), resolution: resolution, }); diff --git a/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesEnergyRequest.ts b/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesEnergyRequest.ts index 054c45038b6..b96874be72a 100644 --- a/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesEnergyRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesEnergyRequest.ts @@ -1,5 +1,5 @@ // @ts-strict-ignore -import { format } from 'date-fns'; +import { format } from "date-fns"; import { ChannelAddress } from "../../type/channeladdress"; import { JsonrpcRequest } from "../base"; import { JsonRpcUtils } from "../jsonrpcutils"; @@ -32,8 +32,8 @@ export class QueryHistoricTimeseriesEnergyRequest extends JsonrpcRequest { ) { super(QueryHistoricTimeseriesEnergyRequest.METHOD, { timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, - fromDate: format(fromDate, 'yyyy-MM-dd'), - toDate: format(toDate, 'yyyy-MM-dd'), + fromDate: format(fromDate, "yyyy-MM-dd"), + toDate: format(toDate, "yyyy-MM-dd"), channels: JsonRpcUtils.channelsToStringArray(channels), }); // delete local fields, otherwise they are sent with the JSON-RPC Request diff --git a/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesExportXlxs.ts b/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesExportXlxs.ts index eb67e868a7a..5aed2202ec7 100644 --- a/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesExportXlxs.ts +++ b/ui/src/app/shared/jsonrpc/request/queryHistoricTimeseriesExportXlxs.ts @@ -1,6 +1,6 @@ // @ts-strict-ignore -import { format } from 'date-fns'; -import { JsonrpcRequest } from '../base'; +import { format } from "date-fns"; +import { JsonrpcRequest } from "../base"; /** * Queries historic timeseries data; exports to Xlsx (Excel) file. @@ -28,8 +28,8 @@ export class QueryHistoricTimeseriesExportXlxsRequest extends JsonrpcRequest { ) { super(QueryHistoricTimeseriesExportXlxsRequest.METHOD, { timezone: new Date().getTimezoneOffset() * 60, - fromDate: format(fromDate, 'yyyy-MM-dd'), - toDate: format(toDate, 'yyyy-MM-dd'), + fromDate: format(fromDate, "yyyy-MM-dd"), + toDate: format(toDate, "yyyy-MM-dd"), }); // delete local fields, otherwise they are sent with the JSON-RPC Request delete this.fromDate; diff --git a/ui/src/app/shared/legacy/chartoptions/chartoptions.component.ts b/ui/src/app/shared/legacy/chartoptions/chartoptions.component.ts index b1042ea46e2..bb5399a749b 100644 --- a/ui/src/app/shared/legacy/chartoptions/chartoptions.component.ts +++ b/ui/src/app/shared/legacy/chartoptions/chartoptions.component.ts @@ -1,14 +1,14 @@ -import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { PopoverController } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; +import { Component, EventEmitter, Input, Output } from "@angular/core"; +import { PopoverController } from "@ionic/angular"; +import { TranslateService } from "@ngx-translate/core"; -import { Service } from '../../shared'; +import { Service } from "../../shared"; // @ts-strict-ignore -import { ChartOptionsPopoverComponent } from './popover/popover.component'; +import { ChartOptionsPopoverComponent } from "./popover/popover.component"; @Component({ - selector: 'chartOptions', - templateUrl: './chartoptions.component.html', + selector: "chartOptions", + templateUrl: "./chartoptions.component.html", }) export class ChartOptionsComponent { @@ -26,10 +26,10 @@ export class ChartOptionsComponent { async presentPopover(ev: any) { const componentProps = {}; if (this.showPhases !== null) { - componentProps['showPhases'] = this.showPhases; + componentProps["showPhases"] = this.showPhases; } if (this.showTotal !== null) { - componentProps['showTotal'] = this.showTotal; + componentProps["showTotal"] = this.showTotal; } const popover = await this.popoverCtrl.create({ component: ChartOptionsPopoverComponent, @@ -39,14 +39,14 @@ export class ChartOptionsComponent { }); await popover.present(); popover.onDidDismiss().then((data) => { - if (data['role'] == "Phases" && data['data'] == true) { + if (data["role"] == "Phases" && data["data"] == true) { this.setShowPhases.emit(true); - } else if (data['role'] == "Phases" && data['data'] == false) { + } else if (data["role"] == "Phases" && data["data"] == false) { this.setShowPhases.emit(false); } - if (data['role'] == "Total" && data['data'] == true) { + if (data["role"] == "Total" && data["data"] == true) { this.setShowTotal.emit(true); - } else if (data['role'] == "Total" && data['data'] == false) { + } else if (data["role"] == "Total" && data["data"] == false) { this.setShowTotal.emit(false); } }); diff --git a/ui/src/app/shared/legacy/chartoptions/popover/popover.component.ts b/ui/src/app/shared/legacy/chartoptions/popover/popover.component.ts index deb9d9c2e4d..5cddb86fbc6 100644 --- a/ui/src/app/shared/legacy/chartoptions/popover/popover.component.ts +++ b/ui/src/app/shared/legacy/chartoptions/popover/popover.component.ts @@ -1,11 +1,11 @@ -import { Component, Input } from '@angular/core'; -import { PopoverController } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; -import { Service } from 'src/app/shared/shared'; +import { Component, Input } from "@angular/core"; +import { PopoverController } from "@ionic/angular"; +import { TranslateService } from "@ngx-translate/core"; +import { Service } from "src/app/shared/shared"; @Component({ - selector: 'chartoptionspopover', - templateUrl: './popover.component.html', + selector: "chartoptionspopover", + templateUrl: "./popover.component.html", }) export class ChartOptionsPopoverComponent { @@ -24,7 +24,7 @@ export class ChartOptionsPopoverComponent { } else if (this.showPhases == false) { this.showPhases = true; } - this.popoverCtrl.dismiss(this.showPhases, 'Phases'); + this.popoverCtrl.dismiss(this.showPhases, "Phases"); } public setTotal() { @@ -33,7 +33,7 @@ export class ChartOptionsPopoverComponent { } else if (this.showTotal == false) { this.showTotal = true; } - this.popoverCtrl.dismiss(this.showTotal, 'Total'); + this.popoverCtrl.dismiss(this.showTotal, "Total"); } } diff --git a/ui/src/app/shared/pipe/classname/classname.pipe.ts b/ui/src/app/shared/pipe/classname/classname.pipe.ts index 7b966b8add5..dbc78248e44 100644 --- a/ui/src/app/shared/pipe/classname/classname.pipe.ts +++ b/ui/src/app/shared/pipe/classname/classname.pipe.ts @@ -1,8 +1,8 @@ // @ts-strict-ignore -import { Pipe, PipeTransform } from '@angular/core'; +import { Pipe, PipeTransform } from "@angular/core"; @Pipe({ - name: 'classname', + name: "classname", }) export class ClassnamePipe implements PipeTransform { transform(value, args: string[]): any { diff --git a/ui/src/app/shared/pipe/formatSecondsToDuration/formatSecondsToDuration.pipe.ts b/ui/src/app/shared/pipe/formatSecondsToDuration/formatSecondsToDuration.pipe.ts index 2e0b760fa81..85dcbb36b85 100644 --- a/ui/src/app/shared/pipe/formatSecondsToDuration/formatSecondsToDuration.pipe.ts +++ b/ui/src/app/shared/pipe/formatSecondsToDuration/formatSecondsToDuration.pipe.ts @@ -1,10 +1,10 @@ -import { DecimalPipe } from '@angular/common'; -import { Pipe, PipeTransform } from '@angular/core'; +import { DecimalPipe } from "@angular/common"; +import { Pipe, PipeTransform } from "@angular/core"; -import { Converter } from '../../components/shared/converter'; +import { Converter } from "../../components/shared/converter"; @Pipe({ - name: 'formatSecondsToDuration', + name: "formatSecondsToDuration", }) export class FormatSecondsToDurationPipe implements PipeTransform { @@ -17,9 +17,9 @@ export class FormatSecondsToDurationPipe implements PipeTransform { const hours = Math.floor(minutes / 60); minutes -= hours * 60; if (hours <= 23) { - return this.decimalPipe.transform(hours, '1.0-0') + 'h' + " " + this.decimalPipe.transform(minutes, '1.0-0') + 'm'; + return this.decimalPipe.transform(hours, "1.0-0") + "h" + " " + this.decimalPipe.transform(minutes, "1.0-0") + "m"; } else { - return this.decimalPipe.transform(hours, '1.0-0') + 'h'; + return this.decimalPipe.transform(hours, "1.0-0") + "h"; } }); } diff --git a/ui/src/app/shared/pipe/isclass/isclass.pipe.ts b/ui/src/app/shared/pipe/isclass/isclass.pipe.ts index 03e6012ae38..878c61e1d53 100644 --- a/ui/src/app/shared/pipe/isclass/isclass.pipe.ts +++ b/ui/src/app/shared/pipe/isclass/isclass.pipe.ts @@ -1,15 +1,15 @@ -import { Pipe, PipeTransform } from '@angular/core'; +import { Pipe, PipeTransform } from "@angular/core"; /** * Checks if an object has a property "class" and this property has the value of the given parameter. * Use like: *ngIf="bridge | isclass:'io.openems.impl.protocol.simulator.SimulatorBridge'" */ @Pipe({ - name: 'isclass', + name: "isclass", }) export class IsclassPipe implements PipeTransform { transform(object: any, classname: string): boolean { - if (object !== null && typeof object === 'object' && object["class"] && object.class == classname) { + if (object !== null && typeof object === "object" && object["class"] && object.class == classname) { return true; } else { return false; diff --git a/ui/src/app/shared/pipe/keys/keys.pipe.ts b/ui/src/app/shared/pipe/keys/keys.pipe.ts index 3d4eb68073d..41d220c89af 100644 --- a/ui/src/app/shared/pipe/keys/keys.pipe.ts +++ b/ui/src/app/shared/pipe/keys/keys.pipe.ts @@ -1,8 +1,8 @@ // @ts-strict-ignore -import { Pipe, PipeTransform } from '@angular/core'; +import { Pipe, PipeTransform } from "@angular/core"; @Pipe({ - name: 'keys', + name: "keys", }) export class KeysPipe implements PipeTransform { transform(value, args: string[]): any { diff --git a/ui/src/app/shared/pipe/pipe.ts b/ui/src/app/shared/pipe/pipe.ts index e2fef054ecf..ff8f05002e8 100644 --- a/ui/src/app/shared/pipe/pipe.ts +++ b/ui/src/app/shared/pipe/pipe.ts @@ -1,14 +1,14 @@ -import { DecimalPipe } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; -import { ClassnamePipe } from './classname/classname.pipe'; -import { FormatSecondsToDurationPipe } from './formatSecondsToDuration/formatSecondsToDuration.pipe'; -import { IsclassPipe } from './isclass/isclass.pipe'; -import { KeysPipe } from './keys/keys.pipe'; -import { SignPipe } from './sign/sign.pipe'; -import { TypeofPipe } from './typeof/typeof.pipe'; -import { UnitvaluePipe } from './unitvalue/unitvalue.pipe'; -import { VersionPipe } from './version/version.pipe'; +import { DecimalPipe } from "@angular/common"; +import { NgModule } from "@angular/core"; +import { BrowserModule } from "@angular/platform-browser"; +import { ClassnamePipe } from "./classname/classname.pipe"; +import { FormatSecondsToDurationPipe } from "./formatSecondsToDuration/formatSecondsToDuration.pipe"; +import { IsclassPipe } from "./isclass/isclass.pipe"; +import { KeysPipe } from "./keys/keys.pipe"; +import { SignPipe } from "./sign/sign.pipe"; +import { TypeofPipe } from "./typeof/typeof.pipe"; +import { UnitvaluePipe } from "./unitvalue/unitvalue.pipe"; +import { VersionPipe } from "./version/version.pipe"; @NgModule({ imports: [ diff --git a/ui/src/app/shared/pipe/sign/sign.pipe.ts b/ui/src/app/shared/pipe/sign/sign.pipe.ts index 614ff7c928b..3929ad4997c 100644 --- a/ui/src/app/shared/pipe/sign/sign.pipe.ts +++ b/ui/src/app/shared/pipe/sign/sign.pipe.ts @@ -1,8 +1,8 @@ // @ts-strict-ignore -import { Pipe, PipeTransform } from '@angular/core'; +import { Pipe, PipeTransform } from "@angular/core"; @Pipe({ - name: 'sign', + name: "sign", }) export class SignPipe implements PipeTransform { transform(value, args: string[]): any { diff --git a/ui/src/app/shared/pipe/typeof/typeof.pipe.ts b/ui/src/app/shared/pipe/typeof/typeof.pipe.ts index 7b5c74d4901..288d771169c 100644 --- a/ui/src/app/shared/pipe/typeof/typeof.pipe.ts +++ b/ui/src/app/shared/pipe/typeof/typeof.pipe.ts @@ -1,7 +1,7 @@ -import { Pipe, PipeTransform } from '@angular/core'; +import { Pipe, PipeTransform } from "@angular/core"; @Pipe({ - name: 'typeof', + name: "typeof", }) export class TypeofPipe implements PipeTransform { diff --git a/ui/src/app/shared/pipe/unitvalue/unitvalue.pipe.spec.ts b/ui/src/app/shared/pipe/unitvalue/unitvalue.pipe.spec.ts index d6c567b4fa1..5feee1061e0 100644 --- a/ui/src/app/shared/pipe/unitvalue/unitvalue.pipe.spec.ts +++ b/ui/src/app/shared/pipe/unitvalue/unitvalue.pipe.spec.ts @@ -1,36 +1,36 @@ import { DecimalPipe, registerLocaleData } from "@angular/common"; -import localDE from '@angular/common/locales/de'; +import localDE from "@angular/common/locales/de"; import { Language } from "../../type/language"; import { UnitvaluePipe } from "./unitvalue.pipe"; -describe('UnitvaluePipe', () => { +describe("UnitvaluePipe", () => { registerLocaleData(localDE); const pipe = new UnitvaluePipe(new DecimalPipe(Language.EN.key)); // TODO test for more i18n-locales // Note: "locale" value in DecimalPipe sets itself to default locale ('en-US') even though we specify our own locales. - it('transforms "1000 W" to "1.000 W"', () => { - expect(pipe.transform(1000, 'W')).toBe('1.000' + '\u00A0' + 'W'); + it("transforms \"1000 W\" to \"1.000 W\"", () => { + expect(pipe.transform(1000, "W")).toBe("1.000" + "\u00A0" + "W"); }); - it('transforms "null W" to "- "', () => { - expect(pipe.transform(null, 'W')).toBe('-' + '\u00A0'); + it("transforms \"null W\" to \"- \"", () => { + expect(pipe.transform(null, "W")).toBe("-" + "\u00A0"); }); - it('transforms "undefined W" to "- "', () => { - expect(pipe.transform(undefined, 'W')).toBe('-' + '\u00A0'); + it("transforms \"undefined W\" to \"- \"", () => { + expect(pipe.transform(undefined, "W")).toBe("-" + "\u00A0"); }); - it('transforms "abc W" to "- "', () => { - expect(pipe.transform("abc", 'W')).toBe('-' + '\u00A0'); + it("transforms \"abc W\" to \"- \"", () => { + expect(pipe.transform("abc", "W")).toBe("-" + "\u00A0"); }); - it('transforms non number to "-"', () => { - expect(pipe.transform(pipe, 'W')).toBe('-' + '\u00A0'); + it("transforms non number to \"-\"", () => { + expect(pipe.transform(pipe, "W")).toBe("-" + "\u00A0"); }); - it('transforms "100 a" to "100 a"', () => { - expect(pipe.transform(100, 'a')).toBe('100' + '\u00A0' + 'a'); + it("transforms \"100 a\" to \"100 a\"", () => { + expect(pipe.transform(100, "a")).toBe("100" + "\u00A0" + "a"); }); }); diff --git a/ui/src/app/shared/pipe/unitvalue/unitvalue.pipe.ts b/ui/src/app/shared/pipe/unitvalue/unitvalue.pipe.ts index dbe9bf0bd64..994ae841eaf 100644 --- a/ui/src/app/shared/pipe/unitvalue/unitvalue.pipe.ts +++ b/ui/src/app/shared/pipe/unitvalue/unitvalue.pipe.ts @@ -1,10 +1,10 @@ -import { DecimalPipe } from '@angular/common'; -import { Pipe, PipeTransform } from '@angular/core'; +import { DecimalPipe } from "@angular/common"; +import { Pipe, PipeTransform } from "@angular/core"; -import { Language } from '../../type/language'; +import { Language } from "../../type/language"; @Pipe({ - name: 'unitvalue', + name: "unitvalue", }) export class UnitvaluePipe implements PipeTransform { @@ -12,17 +12,17 @@ export class UnitvaluePipe implements PipeTransform { transform(value: any, unit: string): any { if (value == null || value == undefined - || (typeof value === 'string' && value.trim() === "") - || typeof value === 'boolean' || isNaN(value)) { - return '-' + '\u00A0'; + || (typeof value === "string" && value.trim() === "") + || typeof value === "boolean" || isNaN(value)) { + return "-" + "\u00A0"; } else { // Changes the number format based on the language selected. const locale: string = (Language.getByKey(localStorage.LANGUAGE) ?? Language.DEFAULT).i18nLocaleKey; - if (unit == 'kWh' || unit == 'kW') { - return this.decimalPipe.transform(value / 1000, '1.0-1', locale) + '\u00A0' + unit; + if (unit == "kWh" || unit == "kW") { + return this.decimalPipe.transform(value / 1000, "1.0-1", locale) + "\u00A0" + unit; } else { - return this.decimalPipe.transform(value, '1.0-0', locale) + '\u00A0' + unit; + return this.decimalPipe.transform(value, "1.0-0", locale) + "\u00A0" + unit; } } } diff --git a/ui/src/app/shared/pipe/version/version.pipe.spec.ts b/ui/src/app/shared/pipe/version/version.pipe.spec.ts index 42f5132b22f..af37851c466 100644 --- a/ui/src/app/shared/pipe/version/version.pipe.spec.ts +++ b/ui/src/app/shared/pipe/version/version.pipe.spec.ts @@ -1,23 +1,23 @@ import { Role } from "../../type/role"; import { VersionPipe } from "./version.pipe"; -describe('VersionPipe', () => { +describe("VersionPipe", () => { const pipe = new VersionPipe(); - it('transforms "2020.1.2-SNAPSHOT" to "2020.1.2" for guest Role', () => { + it("transforms \"2020.1.2-SNAPSHOT\" to \"2020.1.2\" for guest Role", () => { expect(pipe.transform("2020.1.2-SNAPSHOT", Role.GUEST)).toBe("2020.1.2"); }); - it('transforms "2020.1.2-SNAPSHOT" to "2020.1.2" for owner Role', () => { + it("transforms \"2020.1.2-SNAPSHOT\" to \"2020.1.2\" for owner Role", () => { expect(pipe.transform("2020.1.2-SNAPSHOT", "owner")).toBe("2020.1.2"); }); - it('keeps "2020.1.2-SNAPSHOT" for admin Role', () => { + it("keeps \"2020.1.2-SNAPSHOT\" for admin Role", () => { expect(pipe.transform("2020.1.2-SNAPSHOT", Role.ADMIN)).toBe("2020.1.2-SNAPSHOT"); }); - it('keeps "2020.1.2" for any Role', () => { + it("keeps \"2020.1.2\" for any Role", () => { expect(pipe.transform("2020.1.2", Role.GUEST)).toBe("2020.1.2"); expect(pipe.transform("2020.1.2", Role.ADMIN)).toBe("2020.1.2"); }); diff --git a/ui/src/app/shared/pipe/version/version.pipe.ts b/ui/src/app/shared/pipe/version/version.pipe.ts index 43d07019e82..01a7a757398 100644 --- a/ui/src/app/shared/pipe/version/version.pipe.ts +++ b/ui/src/app/shared/pipe/version/version.pipe.ts @@ -1,16 +1,16 @@ -import { Pipe, PipeTransform } from '@angular/core'; +import { Pipe, PipeTransform } from "@angular/core"; -import { Role } from '../../type/role'; +import { Role } from "../../type/role"; @Pipe({ - name: 'version', + name: "version", }) export class VersionPipe implements PipeTransform { constructor() { } transform(version: string, role: Role | string): string { - if (typeof role === 'string') { + if (typeof role === "string") { role = Role.getRole(role); } switch (role) { @@ -18,7 +18,7 @@ export class VersionPipe implements PipeTransform { case Role.GUEST: case Role.INSTALLER: if (version.includes("-")) { - return version.replace(/^(.*)-.*$/, '$1'); + return version.replace(/^(.*)-.*$/, "$1"); } return version; case Role.ADMIN: diff --git a/ui/src/app/shared/service/abstractservice.ts b/ui/src/app/shared/service/abstractservice.ts index 7deaebac604..0db82c0fb92 100644 --- a/ui/src/app/shared/service/abstractservice.ts +++ b/ui/src/app/shared/service/abstractservice.ts @@ -1,13 +1,13 @@ // @ts-strict-ignore -import { ErrorHandler } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { BehaviorSubject } from 'rxjs'; -import { Edge } from '../components/edge/edge'; -import { EdgeConfig } from '../components/edge/edgeconfig'; -import { QueryHistoricTimeseriesEnergyResponse } from '../jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; -import { ChannelAddress } from '../shared'; -import { Language } from '../type/language'; -import { DefaultTypes } from './defaulttypes'; +import { ErrorHandler } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { BehaviorSubject } from "rxjs"; +import { Edge } from "../components/edge/edge"; +import { EdgeConfig } from "../components/edge/edgeconfig"; +import { QueryHistoricTimeseriesEnergyResponse } from "../jsonrpc/response/queryHistoricTimeseriesEnergyResponse"; +import { ChannelAddress } from "../shared"; +import { Language } from "../type/language"; +import { DefaultTypes } from "./defaulttypes"; export abstract class AbstractService extends ErrorHandler { @@ -33,6 +33,8 @@ export abstract class AbstractService extends ErrorHandler { /** * Parses the route params and sets the current edge + * + * @deprecated use the angular routing module to set page title, getCurrentEdge for retrieving the edge */ abstract setCurrentComponent(currentPageTitle: string, activatedRoute: ActivatedRoute): Promise; @@ -98,6 +100,6 @@ export abstract class AbstractService extends ErrorHandler { */ abstract stopSpinner(selector: string); - abstract toast(message: string, level: 'success' | 'warning' | 'danger'); + abstract toast(message: string, level: "success" | "warning" | "danger"); } diff --git a/ui/src/app/shared/service/arrayutils.ts b/ui/src/app/shared/service/arrayutils.ts index f2bb14e9df2..5fc4e31b654 100644 --- a/ui/src/app/shared/service/arrayutils.ts +++ b/ui/src/app/shared/service/arrayutils.ts @@ -21,7 +21,7 @@ export namespace ArrayUtils { } else if (!bVal) { return -1; } - return aVal.localeCompare(bVal, undefined, { sensitivity: 'accent' }); + return aVal.localeCompare(bVal, undefined, { sensitivity: "accent" }); }); } } diff --git a/ui/src/app/shared/service/defaulttypes.ts b/ui/src/app/shared/service/defaulttypes.ts index a8edd55a54c..c2551ff2e0b 100644 --- a/ui/src/app/shared/service/defaulttypes.ts +++ b/ui/src/app/shared/service/defaulttypes.ts @@ -1,9 +1,9 @@ // @ts-strict-ignore -import { TranslateService } from '@ngx-translate/core'; -import { endOfMonth, endOfYear, format, getDay, getMonth, getYear, isSameDay, isSameMonth, isSameYear, startOfMonth, startOfYear, subDays } from 'date-fns'; +import { TranslateService } from "@ngx-translate/core"; +import { endOfMonth, endOfYear, format, getDay, getMonth, getYear, isSameDay, isSameMonth, isSameYear, startOfMonth, startOfYear, subDays } from "date-fns"; -import { QueryHistoricTimeseriesEnergyResponse } from '../jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; -import { ChannelAddress, Service } from '../shared'; +import { QueryHistoricTimeseriesEnergyResponse } from "../jsonrpc/response/queryHistoricTimeseriesEnergyResponse"; +import { ChannelAddress, Service } from "../shared"; export module DefaultTypes { @@ -13,7 +13,7 @@ export module DefaultTypes { [componentId: string]: string[]; } - export type ManualOnOff = 'MANUAL_ON' | 'MANUAL_OFF'; + export type ManualOnOff = "MANUAL_ON" | "MANUAL_OFF"; /** * CurrentData Summary @@ -94,14 +94,14 @@ export module DefaultTypes { params?: string[] } - export enum PeriodString { DAY = 'day', WEEK = 'week', MONTH = 'month', YEAR = 'year', TOTAL = 'total', CUSTOM = 'custom' } + export enum PeriodString { DAY = "day", WEEK = "week", MONTH = "month", YEAR = "year", TOTAL = "total", CUSTOM = "custom" } /** Values of {@link DefaultTypes.PeriodString} */ export type PeriodStringValues = Exclude<`${DefaultTypes.PeriodString}`, "custom">; export namespace History { - export enum YAxisTitle { + export enum YAxisType { PERCENTAGE, ENERGY, } @@ -146,7 +146,7 @@ export module DefaultTypes { afterTitle?: string }, /** Name to be displayed on the left y-axis, also the unit to be displayed in tooltips and legend */ - unit: YAxisTitle, + unit: YAxisType, }; } @@ -165,13 +165,13 @@ export module DefaultTypes { */ private static getTranslatedDayString(translate: TranslateService, date: Date): string { switch (getDay(date)) { - case 0: return translate.instant('General.Week.sunday'); - case 1: return translate.instant('General.Week.monday'); - case 2: return translate.instant('General.Week.tuesday'); - case 3: return translate.instant('General.Week.wednesday'); - case 4: return translate.instant('General.Week.thursday'); - case 5: return translate.instant('General.Week.friday'); - case 6: return translate.instant('General.Week.saturday'); + case 0: return translate.instant("General.Week.sunday"); + case 1: return translate.instant("General.Week.monday"); + case 2: return translate.instant("General.Week.tuesday"); + case 3: return translate.instant("General.Week.wednesday"); + case 4: return translate.instant("General.Week.thursday"); + case 5: return translate.instant("General.Week.friday"); + case 6: return translate.instant("General.Week.saturday"); } } @@ -183,40 +183,40 @@ export module DefaultTypes { */ private static getTranslatedMonthString(translate: TranslateService, date: Date): string { switch (getMonth(date) + 1) { - case 1: return translate.instant('General.Month.january'); - case 2: return translate.instant('General.Month.february'); - case 3: return translate.instant('General.Month.march'); - case 4: return translate.instant('General.Month.april'); - case 5: return translate.instant('General.Month.may'); - case 6: return translate.instant('General.Month.june'); - case 7: return translate.instant('General.Month.july'); - case 8: return translate.instant('General.Month.august'); - case 9: return translate.instant('General.Month.september'); - case 10: return translate.instant('General.Month.october'); - case 11: return translate.instant('General.Month.november'); - case 12: return translate.instant('General.Month.december'); + case 1: return translate.instant("General.Month.january"); + case 2: return translate.instant("General.Month.february"); + case 3: return translate.instant("General.Month.march"); + case 4: return translate.instant("General.Month.april"); + case 5: return translate.instant("General.Month.may"); + case 6: return translate.instant("General.Month.june"); + case 7: return translate.instant("General.Month.july"); + case 8: return translate.instant("General.Month.august"); + case 9: return translate.instant("General.Month.september"); + case 10: return translate.instant("General.Month.october"); + case 11: return translate.instant("General.Month.november"); + case 12: return translate.instant("General.Month.december"); } } public getText(translate: TranslateService, service: Service): string { if (service.periodString === DefaultTypes.PeriodString.TOTAL) { - return translate.instant('Edge.History.TOTAL'); + return translate.instant("Edge.History.TOTAL"); } if (isSameDay(this.from, this.to)) { if (isSameDay(this.from, new Date())) { // Selected TODAY - return translate.instant('Edge.History.today') + ", " + format(new Date(), translate.instant('General.dateFormat')); + return translate.instant("Edge.History.today") + ", " + format(new Date(), translate.instant("General.dateFormat")); } else if (isSameDay(this.from, subDays(new Date(), 1))) { // Selected YESTERDAY - return translate.instant('Edge.History.yesterday') + ", " + format(this.from, translate.instant('General.dateFormat')); + return translate.instant("Edge.History.yesterday") + ", " + format(this.from, translate.instant("General.dateFormat")); } else { // Selected one single day - return HistoryPeriod.getTranslatedDayString(translate, this.from) + ", " + translate.instant('Edge.History.selectedDay', { - value: format(this.from, translate.instant('General.dateFormat')), + return HistoryPeriod.getTranslatedDayString(translate, this.from) + ", " + translate.instant("Edge.History.selectedDay", { + value: format(this.from, translate.instant("General.dateFormat")), }); } } else if (isSameMonth(this.from, this.to) && isSameDay(this.from, startOfMonth(this.from)) && isSameDay(this.to, endOfMonth(this.to))) { @@ -230,9 +230,9 @@ export module DefaultTypes { else { return translate.instant( - 'General.periodFromTo', { - value1: format(this.from, translate.instant('General.dateFormat')), - value2: format(this.to, translate.instant('General.dateFormat')), + "General.periodFromTo", { + value1: format(this.from, translate.instant("General.dateFormat")), + value2: format(this.to, translate.instant("General.dateFormat")), }); } } diff --git a/ui/src/app/shared/service/globalRouteChangeHandler.ts b/ui/src/app/shared/service/globalRouteChangeHandler.ts index 2aa282842a4..17d628c4fa7 100644 --- a/ui/src/app/shared/service/globalRouteChangeHandler.ts +++ b/ui/src/app/shared/service/globalRouteChangeHandler.ts @@ -2,12 +2,12 @@ import { Injectable } from "@angular/core"; import { Router, RoutesRecognized } from "@angular/router"; import { TranslateService } from "@ngx-translate/core"; -import { filter, map } from 'rxjs/operators'; +import { filter, map } from "rxjs/operators"; import { Service } from "./service"; @Injectable({ - providedIn: 'root', + providedIn: "root", }) export class GlobalRouteChangeHandler { @@ -21,7 +21,7 @@ export class GlobalRouteChangeHandler { filter(event => event instanceof RoutesRecognized), map(event => { let data = null; - let route = event['state'].root; + let route = event["state"].root; while (route) { data = route.data || data; @@ -32,7 +32,7 @@ export class GlobalRouteChangeHandler { ).subscribe(e => { if (e.navbarTitle != null && e.navbarTitleToBeTranslated != null) { - throw new Error('Either use navbarTitle or navbarTitleToBeTranslated'); + throw new Error("Either use navbarTitle or navbarTitleToBeTranslated"); } this.service.currentPageTitle = e.navbarTitle ?? (e.navbarTitleToBeTranslated ? translate.instant(e.navbarTitleToBeTranslated) : null) ?? this.service.currentPageTitle; diff --git a/ui/src/app/shared/service/pagination.ts b/ui/src/app/shared/service/pagination.ts index 61d1f1aea1c..ed549837116 100644 --- a/ui/src/app/shared/service/pagination.ts +++ b/ui/src/app/shared/service/pagination.ts @@ -1,9 +1,9 @@ // @ts-strict-ignore -import { Directive } from '@angular/core'; -import { Router } from '@angular/router'; -import { SubscribeEdgesRequest } from '../jsonrpc/request/subscribeEdgesRequest'; -import { ChannelAddress, Edge } from '../shared'; -import { Service } from './service'; +import { Directive } from "@angular/core"; +import { Router } from "@angular/router"; +import { SubscribeEdgesRequest } from "../jsonrpc/request/subscribeEdgesRequest"; +import { ChannelAddress, Edge } from "../shared"; +import { Service } from "./service"; @Directive() export class Pagination { @@ -22,13 +22,13 @@ export class Pagination { this.edge = edge; this.service.websocket.sendRequest(new SubscribeEdgesRequest({ edges: [edge.id] })); }).then(() => { - this.edge.subscribeChannels(this.service.websocket, '', [ - new ChannelAddress('_sum', 'State'), + this.edge.subscribeChannels(this.service.websocket, "", [ + new ChannelAddress("_sum", "State"), ]); }) .finally(resolve) .catch(() => { - this.router.navigate(['index']); + this.router.navigate(["index"]); }); }); } diff --git a/ui/src/app/shared/service/service.ts b/ui/src/app/shared/service/service.ts index 1cd5bdfb98a..67ce8b1a64f 100644 --- a/ui/src/app/shared/service/service.ts +++ b/ui/src/app/shared/service/service.ts @@ -1,31 +1,32 @@ // @ts-strict-ignore -import { registerLocaleData } from '@angular/common'; -import { Injectable } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; -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 { ChosenFilter } from 'src/app/index/filter/filter.component'; -import { environment } from 'src/environments'; -import { Edge } from '../components/edge/edge'; -import { EdgeConfig } from '../components/edge/edgeconfig'; -import { JsonrpcResponseError } from '../jsonrpc/base'; -import { GetEdgeRequest } from '../jsonrpc/request/getEdgeRequest'; -import { GetEdgesRequest } from '../jsonrpc/request/getEdgesRequest'; -import { QueryHistoricTimeseriesEnergyRequest } from '../jsonrpc/request/queryHistoricTimeseriesEnergyRequest'; -import { GetEdgeResponse } from '../jsonrpc/response/getEdgeResponse'; -import { GetEdgesResponse } from '../jsonrpc/response/getEdgesResponse'; -import { QueryHistoricTimeseriesEnergyResponse } from '../jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; -import { User } from '../jsonrpc/shared'; -import { ChannelAddress } from '../shared'; -import { Language } from '../type/language'; -import { Role } from '../type/role'; -import { DateUtils } from '../utils/date/dateutils'; -import { AbstractService } from './abstractservice'; -import { DefaultTypes } from './defaulttypes'; -import { Websocket } from './websocket'; +import { registerLocaleData } from "@angular/common"; +import { Injectable } from "@angular/core"; +import { ActivatedRoute, Router } from "@angular/router"; +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 { ChosenFilter } from "src/app/index/filter/filter.component"; +import { environment } from "src/environments"; +import { ChartConstants } from "../components/chart/chart.constants"; +import { Edge } from "../components/edge/edge"; +import { EdgeConfig } from "../components/edge/edgeconfig"; +import { JsonrpcResponseError } from "../jsonrpc/base"; +import { GetEdgeRequest } from "../jsonrpc/request/getEdgeRequest"; +import { GetEdgesRequest } from "../jsonrpc/request/getEdgesRequest"; +import { QueryHistoricTimeseriesEnergyRequest } from "../jsonrpc/request/queryHistoricTimeseriesEnergyRequest"; +import { GetEdgeResponse } from "../jsonrpc/response/getEdgeResponse"; +import { GetEdgesResponse } from "../jsonrpc/response/getEdgesResponse"; +import { QueryHistoricTimeseriesEnergyResponse } from "../jsonrpc/response/queryHistoricTimeseriesEnergyResponse"; +import { User } from "../jsonrpc/shared"; +import { ChannelAddress } from "../shared"; +import { Language } from "../type/language"; +import { Role } from "../type/role"; +import { DateUtils } from "../utils/date/dateutils"; +import { AbstractService } from "./abstractservice"; +import { DefaultTypes } from "./defaulttypes"; +import { Websocket } from "./websocket"; @Injectable() export class Service extends AbstractService { @@ -54,6 +55,7 @@ export class Service extends AbstractService { public deviceWidth: number = 0; public isSmartphoneResolution: boolean = false; public isSmartphoneResolutionSubject: Subject = new Subject(); + public activeQueryData: string; /** * Holds the currenty selected Page Title. @@ -147,9 +149,9 @@ export class Service extends AbstractService { return new Promise((resolve, reject) => { // Set the currentPageTitle only once per ActivatedRoute if (this.currentActivatedRoute != activatedRoute) { - if (typeof currentPageTitle === 'string') { + if (typeof currentPageTitle === "string") { // Use given page title directly - if (currentPageTitle == null || currentPageTitle.trim() === '') { + if (currentPageTitle == null || currentPageTitle.trim() === "") { this.currentPageTitle = environment.uiTitle; } else { this.currentPageTitle = currentPageTitle; @@ -196,7 +198,7 @@ export class Service extends AbstractService { public onLogout() { this.currentEdge.next(null); this.metadata.next(null); - this.router.navigate(['/login']); + this.router.navigate(["/login"]); } public getChannelAddresses(edge: Edge, channels: ChannelAddress[]): Promise { @@ -214,22 +216,27 @@ export class Service extends AbstractService { promise.resolve = resolve; promise.reject = reject; }); - this.queryEnergyQueue.push( - { fromDate: fromDate, toDate: toDate, channels: channels, promises: [promise] }, - ); - // try to merge requests within 100 ms + this.queryEnergyQueue.push({ + fromDate: fromDate, + toDate: toDate, + channels: channels, + promises: [promise], + }); + if (this.queryEnergyTimeout == null) { this.queryEnergyTimeout = setTimeout(() => { - this.queryEnergyTimeout = null; - // merge requests const mergedRequests: { - fromDate: Date, toDate: Date, channels: ChannelAddress[], promises: { resolve, reject }[]; + fromDate: Date, + toDate: Date, + channels: ChannelAddress[], + promises: { resolve, reject }[]; }[] = []; + let request; while ((request = this.queryEnergyQueue.pop())) { - if (mergedRequests.length == 0) { + if (mergedRequests.length === 0) { mergedRequests.push(request); } else { let merged = false; @@ -239,14 +246,9 @@ export class Service extends AbstractService { // same date -> merge mergedRequest.promises = mergedRequest.promises.concat(request.promises); for (const newChannel of request.channels) { - let isAlreadyThere = false; - for (const existingChannel of mergedRequest.channels) { - if (existingChannel.channelId == newChannel.channelId && existingChannel.componentId == newChannel.componentId) { - isAlreadyThere = true; - break; - } - } - if (!isAlreadyThere) { + if (!mergedRequest.channels.some(existingChannel => + existingChannel.channelId === newChannel.channelId && + existingChannel.componentId === newChannel.componentId)) { mergedRequest.channels.push(newChannel); } } @@ -264,30 +266,44 @@ export class Service extends AbstractService { for (const source of mergedRequests) { // Jump to next request for empty channelAddresses - if (source.channels.length == 0) { + if (source.channels.length === 0) { continue; } - const request = new QueryHistoricTimeseriesEnergyRequest(DateUtils.maxDate(source.fromDate, edge?.firstSetupProtocol), source.toDate, source.channels); - edge.sendRequest(this.websocket, request).then(response => { - const result = (response as QueryHistoricTimeseriesEnergyResponse).result; - if (Object.keys(result.data).length != 0) { + const request = new QueryHistoricTimeseriesEnergyRequest( + DateUtils.maxDate(source.fromDate, edge?.firstSetupProtocol), + source.toDate, + source.channels, + ); + + this.activeQueryData = request.id; + edge.sendRequest(this.websocket, request) + .then(response => { + if (this.activeQueryData !== response.id) { + return; + } + + const result = (response as QueryHistoricTimeseriesEnergyResponse).result; + + if (Object.keys(result.data).length === 0) { + for (const promise of source.promises) { + promise.reject(new JsonrpcResponseError(response.id, { code: 0, message: "Result was empty" })); + } + return; + } + for (const promise of source.promises) { promise.resolve(response as QueryHistoricTimeseriesEnergyResponse); } - } else { + }) + .catch(async reason => { for (const promise of source.promises) { - promise.reject(new JsonrpcResponseError(response.id, { code: 0, message: "Result was empty" })); + promise.reject(new JsonrpcResponseError((await response).id, { code: 0, message: "Result was empty" })); } - } - }).catch(reason => { - for (const promise of source.promises) { - promise.reject(reason); - } - }); + }); } }); - }, 100); + }, ChartConstants.REQUEST_TIMEOUT); } return response; } @@ -300,7 +316,7 @@ export class Service extends AbstractService { * @param limit the number of edges to be retrieved * @returns a Promise */ - public getEdges(page: number, query?: string, limit?: number, searchParamsObj?: { [id: string]: ChosenFilter['value'] }): Promise { + public getEdges(page: number, query?: string, limit?: number, searchParamsObj?: { [id: string]: ChosenFilter["value"] }): Promise { return new Promise((resolve, reject) => { this.websocket.sendSafeRequest( new GetEdgesRequest({ @@ -398,12 +414,12 @@ export class Service extends AbstractService { this.spinner.hide(selector); } - public async toast(message: string, level: 'success' | 'warning' | 'danger', duration?: number) { + public async toast(message: string, level: "success" | "warning" | "danger", duration?: number) { const toast = await this.toaster.create({ message: message, color: level, duration: duration ?? 2000, - cssClass: 'container', + cssClass: "container", }); toast.present(); } diff --git a/ui/src/app/shared/service/utils.spec.ts b/ui/src/app/shared/service/utils.spec.ts index c42d551b244..3034ab95019 100644 --- a/ui/src/app/shared/service/utils.spec.ts +++ b/ui/src/app/shared/service/utils.spec.ts @@ -3,9 +3,9 @@ import { DummyConfig } from "../components/edge/edgeconfig.spec"; import { EdgeConfig } from "../shared"; import { HistoryUtils, Utils } from "./utils"; -describe('Utils', () => { +describe("Utils", () => { - it('#subtractSafely', () => { + it("#subtractSafely", () => { expect(Utils.subtractSafely(null, null)).toEqual(null); expect(Utils.subtractSafely(null, undefined)).toEqual(null); expect(Utils.subtractSafely(0, null)).toEqual(0); @@ -22,35 +22,35 @@ describe('Utils', () => { ); const channelData: HistoryUtils.ChannelData = { - 'ConsumptionActivePower': [null, null, null, 565, 560, 561, 573], - 'evcs0/ChargePower': [null, null, null, 0, 0, 0, 100], - 'evcs1/ChargePower': [null, null, null, 0, 0, 0, 0], - 'meter0/ActivePower': [124, 0, null, 0, 173, 0, 100], - 'meter1/ActivePower': [124, 0, null, 0, 173, 0, 0], + "ConsumptionActivePower": [null, null, null, 565, 560, 561, 573], + "evcs0/ChargePower": [null, null, null, 0, 0, 0, 100], + "evcs1/ChargePower": [null, null, null, 0, 0, 0, 0], + "meter0/ActivePower": [124, 0, null, 0, 173, 0, 100], + "meter1/ActivePower": [124, 0, null, 0, 173, 0, 0], }; const evcsComponents: EdgeConfig.Component[] = dummyConfig.getComponentsImplementingNature("io.openems.edge.evcs.api.Evcs") .filter(component => !( - component.factoryId == 'Evcs.Cluster' || - component.factoryId == 'Evcs.Cluster.PeakShaving' || - component.factoryId == 'Evcs.Cluster.SelfConsumption')); + component.factoryId == "Evcs.Cluster" || + component.factoryId == "Evcs.Cluster.PeakShaving" || + component.factoryId == "Evcs.Cluster.SelfConsumption")); const consumptionMeterComponents: EdgeConfig.Component[] = dummyConfig.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") .filter(component => component.isEnabled && dummyConfig.isTypeConsumptionMetered(component)); - it('+calculateOtherConsumption - evcs + consumptionMeters', () => { + it("+calculateOtherConsumption - evcs + consumptionMeters", () => { const expectedResult = [null, null, null, 565, 214, 561, 373]; expect(Utils.calculateOtherConsumption(channelData, evcsComponents, consumptionMeterComponents)).toEqual(expectedResult); }); - it('+calculateOtherConsumption - only consumptionMeters', () => { + it("+calculateOtherConsumption - only consumptionMeters", () => { const expectedResult2 = [null, null, null, 565, 214, 561, 473]; expect(Utils.calculateOtherConsumption(channelData, [], consumptionMeterComponents)).toEqual(expectedResult2); }); - it('+calculateOtherConsumption - only evcs', () => { + it("+calculateOtherConsumption - only evcs", () => { const expectedResult3 = [null, null, null, 565, 560, 561, 473]; expect(Utils.calculateOtherConsumption(channelData, evcsComponents, [])).toEqual(expectedResult3); }); - it('+calculateOtherConsumption - no evcs + no consumptionMeters', () => { + it("+calculateOtherConsumption - no evcs + no consumptionMeters", () => { const expectedResult4 = [null, null, null, 565, 560, 561, 573]; expect(Utils.calculateOtherConsumption(channelData, [], [])).toEqual(expectedResult4); }); diff --git a/ui/src/app/shared/service/utils.ts b/ui/src/app/shared/service/utils.ts index a5fc752c5fc..36f44a37d47 100644 --- a/ui/src/app/shared/service/utils.ts +++ b/ui/src/app/shared/service/utils.ts @@ -1,14 +1,14 @@ // @ts-strict-ignore -import { formatNumber } from '@angular/common'; -import { TranslateService } from '@ngx-translate/core'; -import { ChartDataset } from 'chart.js'; -import { saveAs } from 'file-saver-es'; -import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; +import { formatNumber } from "@angular/common"; +import { TranslateService } from "@ngx-translate/core"; +import { ChartDataset } from "chart.js"; +import { saveAs } from "file-saver-es"; +import { DefaultTypes } from "src/app/shared/service/defaulttypes"; -import { JsonrpcResponseSuccess } from '../jsonrpc/base'; -import { Base64PayloadResponse } from '../jsonrpc/response/base64PayloadResponse'; -import { QueryHistoricTimeseriesEnergyResponse } from '../jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; -import { ChannelAddress, Currency, EdgeConfig } from '../shared'; +import { JsonrpcResponseSuccess } from "../jsonrpc/base"; +import { Base64PayloadResponse } from "../jsonrpc/response/base64PayloadResponse"; +import { QueryHistoricTimeseriesEnergyResponse } from "../jsonrpc/response/queryHistoricTimeseriesEnergyResponse"; +import { ChannelAddress, Currency, EdgeConfig } from "../shared"; export class Utils { @@ -253,11 +253,11 @@ export class Utils { */ public static CONVERT_TO_WATT = (value: number | null): string => { if (value == null) { - return '-'; + return "-"; } else if (value >= 0) { - return formatNumber(value, 'de', '1.0-0') + ' W'; + return formatNumber(value, "de", "1.0-0") + " W"; } else { - return '0 W'; + return "0 W"; } }; @@ -269,14 +269,14 @@ export class Utils { */ public static CONVERT_WATT_TO_KILOWATT = (value: number | null): string => { if (value == null) { - return '-'; + return "-"; } const thisValue: number = (value / 1000); if (thisValue >= 0) { - return formatNumber(thisValue, 'de', '1.0-1') + ' kW'; + return formatNumber(thisValue, "de", "1.0-1") + " kW"; } else { - return '0 kW'; + return "0 kW"; } }; @@ -297,7 +297,7 @@ export class Utils { * @returns converted value */ public static CONVERT_TO_PERCENT = (value: any): string => { - return value + ' %'; + return value + " %"; }; /** @@ -307,7 +307,7 @@ export class Utils { * @returns converted value */ public static CONVERT_TO_WATTHOURS = (value: number): string => { - return formatNumber(value, 'de', '1.0-1') + ' Wh'; + return formatNumber(value, "de", "1.0-1") + " Wh"; }; /** @@ -317,7 +317,7 @@ export class Utils { * @returns converted value */ public static CONVERT_TO_KILO_WATTHOURS = (value: number): string => { - return formatNumber(Utils.divideSafely(value, 1000), 'de', '1.0-1') + ' kWh'; + return formatNumber(Utils.divideSafely(value, 1000), "de", "1.0-1") + " kWh"; }; /** @@ -328,12 +328,12 @@ export class Utils { */ public static CONVERT_MANUAL_ON_OFF = (translate: TranslateService) => { return (value: DefaultTypes.ManualOnOff): string => { - if (value === 'MANUAL_ON') { - return translate.instant('General.on'); - } else if (value === 'MANUAL_OFF') { - return translate.instant('General.off'); + if (value === "MANUAL_ON") { + return translate.instant("General.on"); + } else if (value === "MANUAL_OFF") { + return translate.instant("General.off"); } else { - return '-'; + return "-"; } }; }; @@ -347,9 +347,9 @@ export class Utils { */ public static convertChargeDischargePower(translate: TranslateService, power: number): { name: string, value: number } { if (power >= 0) { - return { name: translate.instant('General.dischargePower'), value: power }; + return { name: translate.instant("General.dischargePower"), value: power }; } else { - return { name: translate.instant('General.chargePower'), value: power * -1 }; + return { name: translate.instant("General.chargePower"), value: power * -1 }; } } @@ -362,14 +362,14 @@ export class Utils { */ public static CONVERT_MODE_TO_MANUAL_OFF_AUTOMATIC = (translate: TranslateService) => { return (value: any): string => { - if (value === 'MANUAL') { - return translate.instant('General.manually'); - } else if (value === 'OFF') { - return translate.instant('General.off'); - } else if (value === 'AUTOMATIC') { - return translate.instant('General.automatic'); + if (value === "MANUAL") { + return translate.instant("General.manually"); + } else if (value === "OFF") { + return translate.instant("General.off"); + } else if (value === "AUTOMATIC") { + return translate.instant("General.automatic"); } else { - return '-'; + return "-"; } }; }; @@ -384,7 +384,7 @@ export class Utils { const date: Date = new Date(); date.setHours(0, 0, 0, 0); date.setMinutes(value); - return date.toLocaleTimeString(translate.getBrowserCultureLang(), { hour: '2-digit', minute: '2-digit' }); + return date.toLocaleTimeString(translate.getBrowserCultureLang(), { hour: "2-digit", minute: "2-digit" }); }; }; @@ -397,7 +397,7 @@ export class Utils { */ public static CONVERT_PRICE_TO_CENT_PER_KWH = (decimal: number, label: string) => { return (value: number | null): string => - (!value ? "-" : formatNumber(value / 10, 'de', '1.0-' + decimal)) + ' ' + label; + (!value ? "-" : formatNumber(value / 10, "de", "1.0-" + decimal)) + " " + label; }; /** @@ -410,11 +410,11 @@ export class Utils { return (value: any): string => { switch (Math.round(value)) { case 0: - return translate.instant('Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.DELAY_DISCHARGE'); + return translate.instant("Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.DELAY_DISCHARGE"); case 3: - return translate.instant('Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.CHARGE_GRID'); + return translate.instant("Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.CHARGE_GRID"); default: // Usually "1" - return translate.instant('Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.BALANCING'); + return translate.instant("Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.BALANCING"); } }; }; @@ -427,17 +427,17 @@ export class Utils { */ public static getStorageSocSegment(soc: number | null): string { if (!soc || soc < 10) { - return '0'; + return "0"; } else if (soc < 30) { - return '20'; + return "20"; } else if (soc < 50) { - return '40'; + return "40"; } else if (soc < 70) { - return '60'; + return "60"; } else if (soc < 90) { - return '80'; + return "80"; } else { - return '100'; + return "100"; } } @@ -450,7 +450,7 @@ export class Utils { public static downloadXlsx(response: Base64PayloadResponse, filename: string) { // decode base64 string, remove space for IE compatibility // source: https://stackoverflow.com/questions/36036280/base64-representing-pdf-to-blob-javascript/45872086 - const binary = atob(response.result.payload.replace(/\s/g, '')); + const binary = atob(response.result.payload.replace(/\s/g, "")); const len = binary.length; const buffer = new ArrayBuffer(len); const view = new Uint8Array(buffer); @@ -458,10 +458,10 @@ export class Utils { view[i] = binary.charCodeAt(i); } const data: Blob = new Blob([view], { - type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8', + type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8", }); - saveAs(data, filename + '.xlsx'); + saveAs(data, filename + ".xlsx"); } /* @@ -553,7 +553,7 @@ export class Utils { } public static isDataEmpty(arg: JsonrpcResponseSuccess): boolean { - return Object.values(arg.result['data'])?.map(element => element as number[])?.every(element => element?.every(elem => elem == null) ?? true); + return Object.values(arg.result["data"])?.map(element => element as number[])?.every(element => element?.every(elem => elem == null) ?? true); } /** @@ -570,17 +570,17 @@ export class Utils { let totalEvcsConsumption: number = 0; let totalMeteredConsumption: number = 0; evcsComponents.forEach(component => { - totalEvcsConsumption = this.addSafely(totalEvcsConsumption, energyValues.result.data[component.id + '/ActiveConsumptionEnergy']); + totalEvcsConsumption = this.addSafely(totalEvcsConsumption, energyValues.result.data[component.id + "/ActiveConsumptionEnergy"]); }); consumptionMeterComponents.forEach(meter => { - totalMeteredConsumption = this.addSafely(totalMeteredConsumption, energyValues.result.data[meter.id + '/ActiveProductionEnergy']); + totalMeteredConsumption = this.addSafely(totalMeteredConsumption, energyValues.result.data[meter.id + "/ActiveProductionEnergy"]); }); return Utils.roundSlightlyNegativeValues( Utils.subtractSafely( Utils.subtractSafely( - energyValues.result.data['_sum/ConsumptionActiveEnergy'], totalEvcsConsumption), + energyValues.result.data["_sum/ConsumptionActiveEnergy"], totalEvcsConsumption), totalMeteredConsumption)); } @@ -600,18 +600,18 @@ export class Utils { const totalMeteredConsumption: number[] = []; evcsComponents.forEach(component => { - channelData[component.id + '/ChargePower']?.forEach((value, index) => { + channelData[component.id + "/ChargePower"]?.forEach((value, index) => { totalMeteredConsumption[index] = Utils.addSafely(totalMeteredConsumption[index], value); }); }); consumptionMeterComponents.forEach(meter => { - channelData[meter.id + '/ActivePower']?.forEach((value, index) => { + channelData[meter.id + "/ActivePower"]?.forEach((value, index) => { totalMeteredConsumption[index] = Utils.addSafely(totalMeteredConsumption[index], value); }); }); - return channelData['ConsumptionActivePower']?.map((value, index) => { + return channelData["ConsumptionActivePower"]?.map((value, index) => { if (value == null) { return null; @@ -625,7 +625,7 @@ export class Utils { } } -export enum YAxisTitle { +export enum YAxisType { NONE, POWER, PERCENTAGE, @@ -635,13 +635,12 @@ export enum YAxisTitle { CURRENT, TIME, CURRENCY, - NUMBER, } export enum ChartAxis { - LEFT = 'left', - RIGHT = 'right', - RIGHT_2 = 'right2', + LEFT = "left", + RIGHT = "right", + RIGHT_2 = "right2", } export namespace HistoryUtils { @@ -713,9 +712,9 @@ export namespace HistoryUtils { }; export interface CustomOptions { - unit?: YAxisTitle, + unit?: YAxisType, /** overrides global charttype */ - type?: 'line' | 'bar', + type?: "line" | "bar", /** overrides global formatNumber */ formatNumber?: string, } @@ -725,7 +724,7 @@ export namespace HistoryUtils { } export interface BoxCustomOptions extends PluginCustomOptions { - pluginType: 'box', + pluginType: "box", annotations: { /** Start date string in ISO-format */ xMin: string | number, @@ -739,7 +738,7 @@ export namespace HistoryUtils { } export interface DataLabelsCustomOptions extends PluginCustomOptions { - pluginType: 'datalabels', + pluginType: "datalabels", datalabels: { displayUnit: string, }, @@ -769,8 +768,8 @@ 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, - position: 'left' | 'right' | 'bottom' | 'top', + unit: YAxisType, + position: "left" | "right" | "bottom" | "top", yAxisId: ChartAxis, /** YAxis title -> {@link https://www.chartjs.org/docs/latest/samples/scale-options/titles.html Chartjs Title} */ customTitle?: string @@ -861,27 +860,27 @@ export namespace TimeOfUseTariffUtils { return; } - const socLabel = translate.instant('General.soc'); - const dischargeLabel = translate.instant('Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.DELAY_DISCHARGE'); - const chargeConsumptionLabel = translate.instant('Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.CHARGE_GRID'); - const balancingLabel = translate.instant('Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.BALANCING'); - const gridBuyLabel = translate.instant('General.gridBuy'); + const socLabel = translate.instant("General.soc"); + const dischargeLabel = translate.instant("Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.DELAY_DISCHARGE"); + const chargeConsumptionLabel = translate.instant("Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.CHARGE_GRID"); + const balancingLabel = translate.instant("Edge.Index.Widgets.TIME_OF_USE_TARIFF.STATE.BALANCING"); + const gridBuyLabel = translate.instant("General.gridBuy"); // Switch case to handle different labels switch (label) { case socLabel: - return label + ": " + formatNumber(value, 'de', '1.0-0') + " %"; + return label + ": " + formatNumber(value, "de", "1.0-0") + " %"; case dischargeLabel: case chargeConsumptionLabel: case balancingLabel: // Show floating point number for values between 0 and 1 - return label + ": " + formatNumber(value, 'de', '1.0-4') + " " + currencyLabel; + return label + ": " + formatNumber(value, "de", "1.0-4") + " " + currencyLabel; default: case gridBuyLabel: // Power values - return label + ": " + formatNumber(value, 'de', '1.0-2') + " kW"; + return label + ": " + formatNumber(value, "de", "1.0-2") + " kW"; } } diff --git a/ui/src/app/shared/service/websocket.ts b/ui/src/app/shared/service/websocket.ts index 4c6fc1424ce..a79deefeb77 100644 --- a/ui/src/app/shared/service/websocket.ts +++ b/ui/src/app/shared/service/websocket.ts @@ -1,42 +1,44 @@ // @ts-strict-ignore -import { Injectable } from '@angular/core'; -import { Router } from '@angular/router'; -import { TranslateService } from '@ngx-translate/core'; -import { CookieService } from 'ngx-cookie-service'; -import { delay, retryWhen } from 'rxjs/operators'; -import { webSocket, WebSocketSubject } from 'rxjs/webSocket'; +import { Injectable } from "@angular/core"; +import { Router } from "@angular/router"; +import { TranslateService } from "@ngx-translate/core"; +import { CookieService } from "ngx-cookie-service"; +import { delay, retryWhen } from "rxjs/operators"; +import { WebSocketSubject, webSocket } from "rxjs/webSocket"; import { environment } from "src/environments"; -import { JsonrpcMessage, JsonrpcNotification, JsonrpcRequest, JsonrpcResponse, JsonrpcResponseError, JsonrpcResponseSuccess } from '../jsonrpc/base'; -import { CurrentDataNotification } from '../jsonrpc/notification/currentDataNotification'; -import { EdgeConfigNotification } from '../jsonrpc/notification/edgeConfigNotification'; -import { EdgeRpcNotification } from '../jsonrpc/notification/edgeRpcNotification'; -import { SystemLogNotification } from '../jsonrpc/notification/systemLogNotification'; -import { AuthenticateWithPasswordRequest } from '../jsonrpc/request/authenticateWithPasswordRequest'; -import { AuthenticateWithTokenRequest } from '../jsonrpc/request/authenticateWithTokenRequest'; -import { EdgeRpcRequest } from '../jsonrpc/request/edgeRpcRequest'; -import { LogoutRequest } from '../jsonrpc/request/logoutRequest'; -import { RegisterUserRequest } from '../jsonrpc/request/registerUserRequest'; -import { AuthenticateResponse } from '../jsonrpc/response/authenticateResponse'; -import { Language } from '../type/language'; -import { Pagination } from './pagination'; -import { Service } from './service'; -import { WebsocketInterface } from './websocketInterface'; -import { WsData } from './wsdata'; +import { JsonrpcMessage, JsonrpcNotification, JsonrpcRequest, JsonrpcResponse, JsonrpcResponseError, JsonrpcResponseSuccess } from "../jsonrpc/base"; +import { CurrentDataNotification } from "../jsonrpc/notification/currentDataNotification"; +import { EdgeConfigNotification } from "../jsonrpc/notification/edgeConfigNotification"; +import { EdgeRpcNotification } from "../jsonrpc/notification/edgeRpcNotification"; +import { SystemLogNotification } from "../jsonrpc/notification/systemLogNotification"; +import { AuthenticateWithPasswordRequest } from "../jsonrpc/request/authenticateWithPasswordRequest"; +import { AuthenticateWithTokenRequest } from "../jsonrpc/request/authenticateWithTokenRequest"; +import { EdgeRpcRequest } from "../jsonrpc/request/edgeRpcRequest"; +import { LogoutRequest } from "../jsonrpc/request/logoutRequest"; +import { RegisterUserRequest } from "../jsonrpc/request/registerUserRequest"; +import { AuthenticateResponse } from "../jsonrpc/response/authenticateResponse"; +import { Language } from "../type/language"; +import { Pagination } from "./pagination"; +import { Service } from "./service"; +import { WebsocketInterface } from "./websocketInterface"; +import { WsData } from "./wsdata"; @Injectable() export class Websocket implements WebsocketInterface { + public static readonly REQUEST_TIMEOUT = 500; + private static readonly DEFAULT_EDGEID = 0; public status: - 'initial' // before first connection attempt - | 'connecting' // trying to connect to backend - | 'authenticating' // sent authentication request; waiting for response - | 'waiting for credentials' // login is required. Waiting for credentials input - | 'online' // logged in + normal operation - | 'failed' // connection failed - = 'initial'; + "initial" // before first connection attempt + | "connecting" // trying to connect to backend + | "authenticating" // sent authentication request; waiting for response + | "waiting for credentials" // login is required. Waiting for credentials input + | "online" // logged in + normal operation + | "failed" // connection failed + = "initial"; private readonly wsdata = new WsData(); @@ -71,10 +73,10 @@ export class Websocket implements WebsocketInterface { const language = Language.getByKey(localStorage.DEMO_LANGUAGE ?? authenticateResponse.user.language.toLocaleLowerCase()); localStorage.LANGUAGE = language.key; this.service.setLang(language); - this.status = 'online'; + this.status = "online"; // received login token -> save in cookie - this.cookieService.set('token', authenticateResponse.token, { expires: 365, path: '/', sameSite: 'Strict', secure: location.protocol === 'https:' }); + this.cookieService.set("token", authenticateResponse.token, { expires: 365, path: "/", sameSite: "Strict", secure: location.protocol === "https:" }); this.service.currentUser = authenticateResponse.user; @@ -123,7 +125,7 @@ export class Websocket implements WebsocketInterface { public sendRequest(request: JsonrpcRequest): Promise { if ( // logged in + normal operation - this.status == 'online' + this.status == "online" // otherwise only authentication request allowed || (request instanceof AuthenticateWithPasswordRequest || request instanceof AuthenticateWithTokenRequest || request instanceof RegisterUserRequest)) { @@ -131,7 +133,7 @@ export class Websocket implements WebsocketInterface { this.wsdata.sendRequest(this.socket, request).then(response => { if (environment.debugMode) { if (request instanceof EdgeRpcRequest) { - console.info("Response [" + request.params.payload.method + ":" + request.params.edgeId + "]", response.result['payload']['result']); + console.info("Response [" + request.params.payload.method + ":" + request.params.edgeId + "]", response.result["payload"]["result"]); } else { console.info("Response [" + request.method + "]", response.result); } @@ -174,13 +176,13 @@ export class Websocket implements WebsocketInterface { const interval = setInterval(() => { // TODO: Status should be Observable, furthermore status should be like state-machine - if (this.status == 'online') { + if (this.status == "online") { clearInterval(interval); this.sendRequest(request) .then((response) => resolve(response)) .catch((err) => reject(err)); } - }, 500); + }, Websocket.REQUEST_TIMEOUT); }); } @@ -190,7 +192,7 @@ export class Websocket implements WebsocketInterface { * @param notification the JSON-RPC Notification */ public sendNotification(notification: JsonrpcNotification): void { - if (this.status != 'online') { + if (this.status != "online") { console.warn("Websocket is not connected! Unable to send Notification", notification); } this.wsdata.sendNotification(this.socket, notification); @@ -200,11 +202,11 @@ export class Websocket implements WebsocketInterface { * Opens a connection using a stored token. Called once by constructor */ private connect() { - if (this.status != 'initial') { + if (this.status != "initial") { return; } // trying to connect - this.status = 'connecting'; + this.status = "connecting"; if (environment.debugMode) { console.info("Websocket connecting to URL [" + environment.url + "]"); @@ -222,17 +224,17 @@ export class Websocket implements WebsocketInterface { console.info("Websocket connection opened"); } - const token = this.cookieService.get('token'); + const token = this.cookieService.get("token"); if (token) { // Login with Session Token this.login(new AuthenticateWithTokenRequest({ token: token })); - this.status = 'authenticating'; + this.status = "authenticating"; } else { // No Token -> directly ask for Login credentials - this.status = 'waiting for credentials'; - this.router.navigate(['login']); + this.status = "waiting for credentials"; + this.router.navigate(["login"]); } }, }, @@ -243,7 +245,7 @@ export class Websocket implements WebsocketInterface { console.info("Websocket connection closed"); } // trying to connect - this.status = 'connecting'; + this.status = "connecting"; }, }, }); @@ -274,10 +276,10 @@ export class Websocket implements WebsocketInterface { } else if (message instanceof JsonrpcNotification) { // handle JSON-RPC Notification if (environment.debugMode) { - if (message.method == EdgeRpcNotification.METHOD && 'payload' in message.params) { + if (message.method == EdgeRpcNotification.METHOD && "payload" in message.params) { const m = message as EdgeRpcNotification; const payload = m.params.payload; - console.info("Notification [" + m.params.edgeId + "] [" + payload["method"] + "]", payload['params']); + console.info("Notification [" + m.params.edgeId + "] [" + payload["method"] + "]", payload["params"]); } else { console.info("Notification [" + message.method + "]", message.params); } @@ -289,7 +291,7 @@ export class Websocket implements WebsocketInterface { this.onError(error); }, () => { - this.status = 'failed'; + this.status = "failed"; this.onClose(); }); } @@ -299,12 +301,12 @@ export class Websocket implements WebsocketInterface { // TODO create global Errorhandler for any type of error switch (reason.error.code) { case 1003: - this.service.toast(this.translate.instant('Login.authenticationFailed'), 'danger'); + this.service.toast(this.translate.instant("Login.authenticationFailed"), "danger"); this.onLoggedOut(); break; case 1: this.service.toast(this.translate.instant("Login.REQUEST_TIMEOUT"), "danger"); - this.status = 'waiting for credentials'; + this.status = "waiting for credentials"; this.service.onLogout(); break; default: @@ -313,8 +315,8 @@ export class Websocket implements WebsocketInterface { } private onLoggedOut(): void { - this.status = 'waiting for credentials'; - this.cookieService.delete('token', '/'); + this.status = "waiting for credentials"; + this.cookieService.delete("token", "/"); this.service.onLogout(); } diff --git a/ui/src/app/shared/service/websocketInterface.ts b/ui/src/app/shared/service/websocketInterface.ts index 517799b1eb9..c4894b1cca6 100644 --- a/ui/src/app/shared/service/websocketInterface.ts +++ b/ui/src/app/shared/service/websocketInterface.ts @@ -1,7 +1,7 @@ // @ts-strict-ignore -import { JsonrpcNotification, JsonrpcRequest, JsonrpcResponseSuccess } from '../jsonrpc/base'; -import { AuthenticateWithPasswordRequest } from '../jsonrpc/request/authenticateWithPasswordRequest'; -import { AuthenticateWithTokenRequest } from '../jsonrpc/request/authenticateWithTokenRequest'; +import { JsonrpcNotification, JsonrpcRequest, JsonrpcResponseSuccess } from "../jsonrpc/base"; +import { AuthenticateWithPasswordRequest } from "../jsonrpc/request/authenticateWithPasswordRequest"; +import { AuthenticateWithTokenRequest } from "../jsonrpc/request/authenticateWithTokenRequest"; export interface WebsocketInterface { diff --git a/ui/src/app/shared/shared.module.ts b/ui/src/app/shared/shared.module.ts index de8f4e59542..1bf1507d696 100644 --- a/ui/src/app/shared/shared.module.ts +++ b/ui/src/app/shared/shared.module.ts @@ -1,48 +1,48 @@ // @ts-strict-ignore -import { CommonModule } from '@angular/common'; -import { Injector, NgModule } from '@angular/core'; -import { FormControl, FormsModule, ReactiveFormsModule, ValidationErrors } from '@angular/forms'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { RouterModule } from '@angular/router'; -import { IonicModule } from '@ionic/angular'; -import { FormlyFieldConfig, FormlyModule } from '@ngx-formly/core'; -import { FormlyIonicModule } from '@ngx-formly/ionic'; -import { TranslateModule } from '@ngx-translate/core'; -import { NgChartsModule } from 'ng2-charts'; +import { CommonModule } from "@angular/common"; +import { Injector, NgModule } from "@angular/core"; +import { FormControl, FormsModule, ReactiveFormsModule, ValidationErrors } from "@angular/forms"; +import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; +import { RouterModule } from "@angular/router"; +import { IonicModule } from "@ionic/angular"; +import { FormlyFieldConfig, FormlyModule } from "@ngx-formly/core"; +import { FormlyIonicModule } from "@ngx-formly/ionic"; +import { TranslateModule } from "@ngx-translate/core"; +import { NgChartsModule } from "ng2-charts"; import { NgxSpinnerModule } from "ngx-spinner"; -import { appRoutingProviders } from '../app-routing.module'; -import { ComponentsModule } from './components/components.module'; -import { MeterModule } from './components/edge/meter/meter.module'; -import { FormlyCheckBoxHyperlinkWrapperComponent } from './components/formly/form-field-checkbox-hyperlink/form-field-checkbox-hyperlink.wrapper'; -import { FormlyWrapperDefaultValueWithCasesComponent } from './components/formly/form-field-default-cases.wrapper'; -import { FormlyWrapperFormFieldComponent } from './components/formly/form-field.wrapper'; -import { FormlyFieldCheckboxWithImageComponent } from './components/formly/formly-field-checkbox-image/formly-field-checkbox-with-image'; -import { FormlyFieldModalComponent } from './components/formly/formly-field-modal/formlyfieldmodal'; -import { FormlyFieldRadioWithImageComponent } from './components/formly/formly-field-radio-with-image/formly-field-radio-with-image'; -import { FormlySelectFieldModalComponent } from './components/formly/formly-select-field-modal.component'; -import { FormlySelectFieldExtendedWrapperComponent } from './components/formly/formly-select-field.extended'; -import { FormlyFieldWithLoadingAnimationComponent } from './components/formly/formly-skeleton-wrapper'; -import { InputTypeComponent } from './components/formly/input'; -import { FormlyInputSerialNumberWrapperComponent as FormlyWrapperInputSerialNumber } from './components/formly/input-serial-number-wrapper'; -import { PanelWrapperComponent } from './components/formly/panel-wrapper.component'; -import { RepeatTypeComponent } from './components/formly/repeat'; -import { HeaderComponent } from './components/header/header.component'; -import { HistoryDataErrorModule } from './components/history-data-error/history-data-error.module'; -import { PercentageBarComponent } from './components/percentagebar/percentagebar.component'; -import { DirectiveModule } from './directive/directive'; -import { ChartOptionsComponent } from './legacy/chartoptions/chartoptions.component'; -import { PipeModule } from './pipe/pipe'; -import { Logger } from './service/logger'; -import { Service } from './service/service'; -import { Utils } from './service/utils'; -import { Websocket } from './shared'; +import { appRoutingProviders } from "../app-routing.module"; +import { ComponentsModule } from "./components/components.module"; +import { MeterModule } from "./components/edge/meter/meter.module"; +import { FormlyCheckBoxHyperlinkWrapperComponent } from "./components/formly/form-field-checkbox-hyperlink/form-field-checkbox-hyperlink.wrapper"; +import { FormlyWrapperDefaultValueWithCasesComponent } from "./components/formly/form-field-default-cases.wrapper"; +import { FormlyWrapperFormFieldComponent } from "./components/formly/form-field.wrapper"; +import { FormlyFieldCheckboxWithImageComponent } from "./components/formly/formly-field-checkbox-image/formly-field-checkbox-with-image"; +import { FormlyFieldModalComponent } from "./components/formly/formly-field-modal/formlyfieldmodal"; +import { FormlyFieldRadioWithImageComponent } from "./components/formly/formly-field-radio-with-image/formly-field-radio-with-image"; +import { FormlySelectFieldModalComponent } from "./components/formly/formly-select-field-modal.component"; +import { FormlySelectFieldExtendedWrapperComponent } from "./components/formly/formly-select-field.extended"; +import { FormlyFieldWithLoadingAnimationComponent } from "./components/formly/formly-skeleton-wrapper"; +import { InputTypeComponent } from "./components/formly/input"; +import { FormlyInputSerialNumberWrapperComponent as FormlyWrapperInputSerialNumber } from "./components/formly/input-serial-number-wrapper"; +import { PanelWrapperComponent } from "./components/formly/panel-wrapper.component"; +import { RepeatTypeComponent } from "./components/formly/repeat"; +import { HeaderComponent } from "./components/header/header.component"; +import { HistoryDataErrorModule } from "./components/history-data-error/history-data-error.module"; +import { PercentageBarComponent } from "./components/percentagebar/percentagebar.component"; +import { DirectiveModule } from "./directive/directive"; +import { ChartOptionsComponent } from "./legacy/chartoptions/chartoptions.component"; +import { PipeModule } from "./pipe/pipe"; +import { Logger } from "./service/logger"; +import { Service } from "./service/service"; +import { Utils } from "./service/utils"; +import { Websocket } from "./shared"; export function IpValidator(control: FormControl): ValidationErrors { - return /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(control.value) ? null : { 'ip': true }; + return /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(control.value) ? null : { "ip": true }; } export function SubnetmaskValidator(control: FormControl): ValidationErrors { - return /^(255)\.(0|128|192|224|240|248|252|254|255)\.(0|128|192|224|240|248|252|254|255)\.(0|128|192|224|240|248|252|254|255)/.test(control.value) ? null : { 'subnetmask': true }; + return /^(255)\.(0|128|192|224|240|248|252|254|255)\.(0|128|192|224|240|248|252|254|255)\.(0|128|192|224|240|248|252|254|255)/.test(control.value) ? null : { "subnetmask": true }; } export function IpValidatorMessage(err, field: FormlyFieldConfig) { @@ -63,33 +63,33 @@ export function SubnetmaskValidatorMessage(err, field: FormlyFieldConfig) { FormsModule, IonicModule, NgxSpinnerModule.forRoot({ - type: 'ball-clip-rotate-multiple', + type: "ball-clip-rotate-multiple", }), ReactiveFormsModule, RouterModule, FormlyModule.forRoot({ wrappers: [ - { name: 'form-field', component: FormlyWrapperFormFieldComponent }, + { name: "form-field", component: FormlyWrapperFormFieldComponent }, { name: "input-serial-number", component: FormlyWrapperInputSerialNumber }, - { name: 'formly-select-extended-wrapper', component: FormlySelectFieldExtendedWrapperComponent }, - { name: 'formly-field-radio-with-image', component: FormlyFieldRadioWithImageComponent }, - { name: 'form-field-checkbox-hyperlink', component: FormlyCheckBoxHyperlinkWrapperComponent }, - { name: 'formly-wrapper-default-of-cases', component: FormlyWrapperDefaultValueWithCasesComponent }, - { name: 'panel', component: PanelWrapperComponent }, - { name: 'formly-field-modal', component: FormlyFieldModalComponent }, - { name: 'formly-field-checkbox-with-image', component: FormlyFieldCheckboxWithImageComponent }, + { name: "formly-select-extended-wrapper", component: FormlySelectFieldExtendedWrapperComponent }, + { name: "formly-field-radio-with-image", component: FormlyFieldRadioWithImageComponent }, + { name: "form-field-checkbox-hyperlink", component: FormlyCheckBoxHyperlinkWrapperComponent }, + { name: "formly-wrapper-default-of-cases", component: FormlyWrapperDefaultValueWithCasesComponent }, + { name: "panel", component: PanelWrapperComponent }, + { name: "formly-field-modal", component: FormlyFieldModalComponent }, + { name: "formly-field-checkbox-with-image", component: FormlyFieldCheckboxWithImageComponent }, ], types: [ - { name: 'input', component: InputTypeComponent }, - { name: 'repeat', component: RepeatTypeComponent }, + { name: "input", component: InputTypeComponent }, + { name: "repeat", component: RepeatTypeComponent }, ], validators: [ - { name: 'ip', validation: IpValidator }, - { name: 'subnetmask', validation: SubnetmaskValidator }, + { name: "ip", validation: IpValidator }, + { name: "subnetmask", validation: SubnetmaskValidator }, ], validationMessages: [ - { name: 'ip', message: IpValidatorMessage }, - { name: 'subnetmask', message: SubnetmaskValidatorMessage }, + { name: "ip", message: IpValidatorMessage }, + { name: "subnetmask", message: SubnetmaskValidatorMessage }, ], }), PipeModule, diff --git a/ui/src/app/shared/shared.spec.ts b/ui/src/app/shared/shared.spec.ts index 82662b2ea1f..c9ea351e2b4 100644 --- a/ui/src/app/shared/shared.spec.ts +++ b/ui/src/app/shared/shared.spec.ts @@ -3,33 +3,33 @@ import { SumState } from "../index/shared/sumState"; import { Edge, EdgePermission } from "./shared"; import { Role } from "./type/role"; -describe('EdgePermission', () => { +describe("EdgePermission", () => { const edge = new Edge("", "", "", "2024.2.2", Role.ADMIN, true, new Date(), SumState.OK, null); - it('#getAllowedHistoryPeriods - no first ibn date', () => { - expect(EdgePermission.getAllowedHistoryPeriods(edge, ['day', 'week', 'month', 'year'])).toEqual(['day', 'week', 'month', 'year']); + it("#getAllowedHistoryPeriods - no first ibn date", () => { + expect(EdgePermission.getAllowedHistoryPeriods(edge, ["day", "week", "month", "year"])).toEqual(["day", "week", "month", "year"]); }); const edgeWithFirstIbnDate = new Edge("", "", "", "", Role.ADMIN, true, new Date(), SumState.OK, new Date()); - it('#getAllowedHistoryPeriods - first ibn date', () => { - expect(EdgePermission.getAllowedHistoryPeriods(edgeWithFirstIbnDate, ['day', 'week', 'month', 'year', 'total'])).toEqual(['day', 'week', 'month', 'year', 'total']); + it("#getAllowedHistoryPeriods - first ibn date", () => { + expect(EdgePermission.getAllowedHistoryPeriods(edgeWithFirstIbnDate, ["day", "week", "month", "year", "total"])).toEqual(["day", "week", "month", "year", "total"]); }); - it('#getAllowedHistoryPeriods - historyPeriods: []', () => { - expect(EdgePermission.getAllowedHistoryPeriods(edgeWithFirstIbnDate, [])).toEqual(['day', 'week', 'month', 'year', 'total', 'custom']); + it("#getAllowedHistoryPeriods - historyPeriods: []", () => { + expect(EdgePermission.getAllowedHistoryPeriods(edgeWithFirstIbnDate, [])).toEqual(["day", "week", "month", "year", "total", "custom"]); }); - it('#getAllowedHistoryPeriods - historyPeriod: null', () => { - expect(EdgePermission.getAllowedHistoryPeriods(edgeWithFirstIbnDate, null)).toEqual(['day', 'week', 'month', 'year', 'total', 'custom']); + it("#getAllowedHistoryPeriods - historyPeriod: null", () => { + expect(EdgePermission.getAllowedHistoryPeriods(edgeWithFirstIbnDate, null)).toEqual(["day", "week", "month", "year", "total", "custom"]); }); - it('#getAllowedHistoryPeriods - historyPeriod: undefined', () => { - expect(EdgePermission.getAllowedHistoryPeriods(edgeWithFirstIbnDate, undefined)).toEqual(['day', 'week', 'month', 'year', 'total', 'custom']); + it("#getAllowedHistoryPeriods - historyPeriod: undefined", () => { + expect(EdgePermission.getAllowedHistoryPeriods(edgeWithFirstIbnDate, undefined)).toEqual(["day", "week", "month", "year", "total", "custom"]); }); const edgeWithoutFirstIbnDate = new Edge("", "", "", "", Role.ADMIN, true, new Date(), SumState.OK, null); - it('#getAllowedHistoryPeriods - no first ibn date', () => { - expect(EdgePermission.getAllowedHistoryPeriods(edgeWithoutFirstIbnDate)).toEqual(['day', 'week', 'month', 'year', 'custom']); + it("#getAllowedHistoryPeriods - no first ibn date", () => { + expect(EdgePermission.getAllowedHistoryPeriods(edgeWithoutFirstIbnDate)).toEqual(["day", "week", "month", "year", "custom"]); }); }); diff --git a/ui/src/app/shared/shared.ts b/ui/src/app/shared/shared.ts index 178fe40332f..4175e96134d 100644 --- a/ui/src/app/shared/shared.ts +++ b/ui/src/app/shared/shared.ts @@ -13,21 +13,21 @@ export { Widget, WidgetFactory, WidgetNature, Widgets } from "./type/widget"; import { AlertController, AlertOptions } from "@ionic/angular"; import { TranslateService } from "@ngx-translate/core"; -import { addIcons } from 'ionicons'; +import { addIcons } from "ionicons"; import { Edge } from "./components/edge/edge"; import { User } from "./jsonrpc/shared"; import { DefaultTypes } from "./service/defaulttypes"; import { Role } from "./type/role"; addIcons({ - 'oe-consumption': 'assets/img/icon/consumption.svg', - 'oe-evcs': 'assets/img/icon/evcs.svg', - 'oe-grid': 'assets/img/icon/grid.svg', - 'oe-grid-storage': 'assets/img/icon/gridStorage.svg', - 'oe-grid-restriction': 'assets/img/icon/gridRestriction.svg', - 'oe-offgrid': 'assets/img/icon/offgrid.svg', - 'oe-production': 'assets/img/icon/production.svg', - 'oe-storage': 'assets/img/icon/storage.svg', + "oe-consumption": "assets/img/icon/consumption.svg", + "oe-evcs": "assets/img/icon/evcs.svg", + "oe-grid": "assets/img/icon/grid.svg", + "oe-grid-storage": "assets/img/icon/gridStorage.svg", + "oe-grid-restriction": "assets/img/icon/gridRestriction.svg", + "oe-offgrid": "assets/img/icon/offgrid.svg", + "oe-production": "assets/img/icon/production.svg", + "oe-storage": "assets/img/icon/storage.svg", }); export class EdgePermission { @@ -68,7 +68,7 @@ export class EdgePermission { * @returns true if the channels are included in the edgeconfig */ public static hasChannelsInEdgeConfig(edge: Edge): boolean { - return !edge.isVersionAtLeast('2024.6.1'); + return !edge.isVersionAtLeast("2024.6.1"); } /** @@ -81,7 +81,7 @@ export class EdgePermission { * @returns true if only the factories of the used components are in the edgeconfig */ public static hasReducedFactories(edge: Edge): boolean { - return edge.isVersionAtLeast('2024.6.1'); + return edge.isVersionAtLeast("2024.6.1"); } } @@ -113,7 +113,7 @@ export class UserPermission { * @returns true, if user is at least {@link Role.ADMIN} and edge version is at least 2024.2.2 */ public static isAllowedToSeeSystemRestart(user: User, edge: Edge) { - const isAllowed = edge?.isVersionAtLeast('2024.2.2'); + const isAllowed = edge?.isVersionAtLeast("2024.2.2"); return Role.isAtLeast(user?.globalRole, Role.OWNER) && isAllowed; } } @@ -141,7 +141,7 @@ export namespace Currency { */ export function getCurrencyLabelByCurrency(currency: string): Label { switch (currency) { - case 'SEK': + case "SEK": return Label.OERE_PER_KWH; default: return Label.CENT_PER_KWH; @@ -181,12 +181,12 @@ export async function presentAlert(alertController: AlertController, translate: const alert = alertController.create({ ...alertOptions, buttons: [{ - text: translate.instant('General.cancel'), - role: 'cancel', + text: translate.instant("General.cancel"), + role: "cancel", }, ...(alertOptions?.buttons ?? []), ], - cssClass: 'alertController', + cssClass: "alertController", }); (await alert).present(); } diff --git a/ui/src/app/shared/translate.extension.ts b/ui/src/app/shared/translate.extension.ts index e0d7675b9af..0b9bce010b0 100644 --- a/ui/src/app/shared/translate.extension.ts +++ b/ui/src/app/shared/translate.extension.ts @@ -1,6 +1,6 @@ // @ts-strict-ignore -import { FormlyExtension, FormlyFieldConfig } from '@ngx-formly/core'; -import { TranslateService } from '@ngx-translate/core'; +import { FormlyExtension, FormlyFieldConfig } from "@ngx-formly/core"; +import { TranslateService } from "@ngx-translate/core"; export class TranslateExtension implements FormlyExtension { constructor(private translate: TranslateService) { } @@ -13,7 +13,7 @@ export class TranslateExtension implements FormlyExtension { props._translated = true; field.expressions = { ...(field.expressions || {}), - 'props.label': this.translate.stream(props.label), + "props.label": this.translate.stream(props.label), }; } } @@ -23,7 +23,7 @@ export function registerTranslateExtension(translate: TranslateService) { validationMessages: [], extensions: [ { - name: 'translate', + name: "translate", extension: new TranslateExtension(translate), }, ], @@ -39,5 +39,5 @@ export function registerTranslateExtension(translate: TranslateService) { * @returns the validation error message. */ export function serialNumber(translate: TranslateService, field: FormlyFieldConfig, length: number) { - return translate.stream('INSTALLATION.FORM.BATTERY_SERIAL_NUMBER', { serialNumber: ((field.props.prefix ?? "") + field.formControl.value), length: length }); + return translate.stream("INSTALLATION.FORM.BATTERY_SERIAL_NUMBER", { serialNumber: ((field.props.prefix ?? "") + field.formControl.value), length: length }); } diff --git a/ui/src/app/shared/type/channeladdress.ts b/ui/src/app/shared/type/channeladdress.ts index ae633707993..e8ddbeb302a 100644 --- a/ui/src/app/shared/type/channeladdress.ts +++ b/ui/src/app/shared/type/channeladdress.ts @@ -11,7 +11,7 @@ export class ChannelAddress { * @param address in the form 'Component-ID/Channel-ID' */ public static fromString(address: string): ChannelAddress { - const array = address.split('/', 2); + const array = address.split("/", 2); return new ChannelAddress(array[0], array[1]); } diff --git a/ui/src/app/shared/type/country.ts b/ui/src/app/shared/type/country.ts index ce388ed2835..f69f28c850a 100644 --- a/ui/src/app/shared/type/country.ts +++ b/ui/src/app/shared/type/country.ts @@ -1,21 +1,21 @@ import { TranslateService } from "@ngx-translate/core"; export enum Country { - GERMANY = 'de', - AUSTRIA = 'at', - SWITZERLAND = 'ch', - SWEDEN = 'se', - CZECH_REPUBLIK = 'cz', - NETHERLANDS = 'nl', + GERMANY = "de", + AUSTRIA = "at", + SWITZERLAND = "ch", + SWEDEN = "se", + CZECH_REPUBLIK = "cz", + NETHERLANDS = "nl", } export const COUNTRY_OPTIONS = (translate: TranslateService) => { return [ - { value: Country.GERMANY, label: translate.instant('General.Country.germany') }, - { value: Country.AUSTRIA, label: translate.instant('General.Country.austria') }, - { value: Country.SWITZERLAND, label: translate.instant('General.Country.switzerland') }, - { value: Country.SWEDEN, label: translate.instant('General.Country.sweden') }, - { value: Country.NETHERLANDS, label: translate.instant('General.Country.netherlands') }, - { value: Country.CZECH_REPUBLIK, label: translate.instant('General.Country.czech') }, + { value: Country.GERMANY, label: translate.instant("General.Country.germany") }, + { value: Country.AUSTRIA, label: translate.instant("General.Country.austria") }, + { value: Country.SWITZERLAND, label: translate.instant("General.Country.switzerland") }, + { value: Country.SWEDEN, label: translate.instant("General.Country.sweden") }, + { value: Country.NETHERLANDS, label: translate.instant("General.Country.netherlands") }, + { value: Country.CZECH_REPUBLIK, label: translate.instant("General.Country.czech") }, ]; }; diff --git a/ui/src/app/shared/type/general.ts b/ui/src/app/shared/type/general.ts index c33d4e88d22..8394178bfce 100644 --- a/ui/src/app/shared/type/general.ts +++ b/ui/src/app/shared/type/general.ts @@ -4,9 +4,9 @@ export enum GridMode { OFF_GRID = 2, } export enum Mode { - MANUAL_ON = 'MANUAL_ON', - MANUAL_OFF = 'MANUAL_OFF', - AUTOMATIC = 'AUTOMATIC', + MANUAL_ON = "MANUAL_ON", + MANUAL_OFF = "MANUAL_OFF", + AUTOMATIC = "AUTOMATIC", } export const ChartAnnotationState = { ON: 1, @@ -14,6 +14,6 @@ export const ChartAnnotationState = { OFF_HIDDEN: null, }; export enum WorkMode { - TIME = 'TIME', - NONE = 'NONE', + TIME = "TIME", + NONE = "NONE", } diff --git a/ui/src/app/shared/type/language.spec.ts b/ui/src/app/shared/type/language.spec.ts index d3b078be851..177daccbb97 100644 --- a/ui/src/app/shared/type/language.spec.ts +++ b/ui/src/app/shared/type/language.spec.ts @@ -1,11 +1,11 @@ // @ts-strict-ignore import { Language } from "./language"; -describe('Language', () => { +describe("Language", () => { - it('#geti18nLocaleByKey', () => { - expect(Language.geti18nLocaleByKey('DE')).toBe('de'); - expect(Language.geti18nLocaleByKey('Zz')).toBe(Language.DEFAULT.i18nLocaleKey); + it("#geti18nLocaleByKey", () => { + expect(Language.geti18nLocaleByKey("DE")).toBe("de"); + expect(Language.geti18nLocaleByKey("Zz")).toBe(Language.DEFAULT.i18nLocaleKey); expect(Language.geti18nLocaleByKey(null)).toBe(Language.DEFAULT.i18nLocaleKey); expect(Language.geti18nLocaleByKey(undefined)).toBe(Language.DEFAULT.i18nLocaleKey); }); diff --git a/ui/src/app/shared/type/language.ts b/ui/src/app/shared/type/language.ts index 2a4f71af9c7..79a88549ab3 100644 --- a/ui/src/app/shared/type/language.ts +++ b/ui/src/app/shared/type/language.ts @@ -1,18 +1,18 @@ -import localDE from '@angular/common/locales/de'; -import localEN from '@angular/common/locales/en'; -import localES from '@angular/common/locales/es'; -import localFR from '@angular/common/locales/fr'; -import localJA from '@angular/common/locales/ja'; -import localNL from '@angular/common/locales/nl'; +import localDE from "@angular/common/locales/de"; +import localEN from "@angular/common/locales/en"; +import localES from "@angular/common/locales/es"; +import localFR from "@angular/common/locales/fr"; +import localJA from "@angular/common/locales/ja"; +import localNL from "@angular/common/locales/nl"; import { TranslateLoader } from "@ngx-translate/core"; -import { Observable, of } from 'rxjs'; -import cz from 'src/assets/i18n/cz.json'; -import de from 'src/assets/i18n/de.json'; -import en from 'src/assets/i18n/en.json'; -import es from 'src/assets/i18n/es.json'; -import fr from 'src/assets/i18n/fr.json'; -import ja from 'src/assets/i18n/ja.json'; -import nl from 'src/assets/i18n/nl.json'; +import { Observable, of } from "rxjs"; +import cz from "src/assets/i18n/cz.json"; +import de from "src/assets/i18n/de.json"; +import en from "src/assets/i18n/en.json"; +import es from "src/assets/i18n/es.json"; +import fr from "src/assets/i18n/fr.json"; +import ja from "src/assets/i18n/ja.json"; +import nl from "src/assets/i18n/nl.json"; interface Translation { [key: string]: string | Translation; diff --git a/ui/src/app/shared/type/role.ts b/ui/src/app/shared/type/role.ts index cf927a34f7d..5c985cb750a 100644 --- a/ui/src/app/shared/type/role.ts +++ b/ui/src/app/shared/type/role.ts @@ -35,10 +35,10 @@ export namespace Role { * @return true if "Role 1" is equal or more privileged than "Role 2" */ export function isAtLeast(role1: Role | string, role2: Role | string): boolean { - if (typeof role1 === 'string') { + if (typeof role1 === "string") { role1 = Role.getRole(role1); } - if (typeof role2 === 'string') { + if (typeof role2 === "string") { role2 = Role.getRole(role2); } return role1 <= role2; diff --git a/ui/src/app/shared/type/systemlog.ts b/ui/src/app/shared/type/systemlog.ts index d5a53572cf5..fa4a0a18734 100644 --- a/ui/src/app/shared/type/systemlog.ts +++ b/ui/src/app/shared/type/systemlog.ts @@ -1,6 +1,6 @@ export interface SystemLog { time: string, - level: 'ERROR' | 'WARN' | 'INFO', + level: "ERROR" | "WARN" | "INFO", source: string, message: string } diff --git a/ui/src/app/shared/type/widget.ts b/ui/src/app/shared/type/widget.ts index 367bc6fac51..bd838e1641b 100644 --- a/ui/src/app/shared/type/widget.ts +++ b/ui/src/app/shared/type/widget.ts @@ -1,41 +1,42 @@ // @ts-strict-ignore -import { Edge } from '../components/edge/edge'; -import { EdgeConfig } from '../components/edge/edgeconfig'; +import { Edge } from "../components/edge/edge"; +import { EdgeConfig } from "../components/edge/edgeconfig"; export enum WidgetClass { - 'Energymonitor', - 'Common_Autarchy', - 'Common_Selfconsumption', - 'Storage', - 'Grid', - 'Common_Production', - 'Consumption', - 'Controller_ChannelThreshold', + "Energymonitor", + "Common_Autarchy", + "Common_Selfconsumption", + "Storage", + "Grid", + "Common_Production", + "Consumption", + "Controller_ChannelThreshold", + "Controller_Io_Digital_Outputs", } export enum WidgetNature { - 'io.openems.edge.evcs.api.Evcs', - 'io.openems.impl.controller.channelthreshold.ChannelThresholdController', // TODO deprecated - 'io.openems.edge.io.api.DigitalInput', + "io.openems.edge.evcs.api.Evcs", + "io.openems.impl.controller.channelthreshold.ChannelThresholdController", // TODO deprecated + "io.openems.edge.io.api.DigitalInput", } export enum WidgetFactory { - 'Controller.Asymmetric.PeakShaving', - 'Controller.ChannelThreshold', - 'Controller.CHP.SoC', - 'Controller.Ess.DelayedSellToGrid', - 'Controller.Ess.FixActivePower', - 'Controller.Ess.GridOptimizedCharge', - 'Controller.Ess.Time-Of-Use-Tariff.Discharge', - 'Controller.Ess.Time-Of-Use-Tariff', - 'Controller.IO.ChannelSingleThreshold', - 'Controller.Io.FixDigitalOutput', - 'Controller.IO.HeatingElement', - 'Controller.Io.HeatPump.SgReady', - 'Controller.Symmetric.PeakShaving', - 'Controller.TimeslotPeakshaving', - 'Evcs.Cluster.PeakShaving', - 'Evcs.Cluster.SelfConsumption', + "Controller.Asymmetric.PeakShaving", + "Controller.ChannelThreshold", + "Controller.CHP.SoC", + "Controller.Ess.DelayedSellToGrid", + "Controller.Ess.FixActivePower", + "Controller.Ess.GridOptimizedCharge", + "Controller.Ess.Time-Of-Use-Tariff.Discharge", + "Controller.Ess.Time-Of-Use-Tariff", + "Controller.IO.ChannelSingleThreshold", + "Controller.Io.FixDigitalOutput", + "Controller.IO.HeatingElement", + "Controller.Io.HeatPump.SgReady", + "Controller.Symmetric.PeakShaving", + "Controller.TimeslotPeakshaving", + "Evcs.Cluster.PeakShaving", + "Evcs.Cluster.SelfConsumption", } export type Icon = { @@ -76,39 +77,42 @@ export class Widgets { public static parseWidgets(edge: Edge, config: EdgeConfig): Widgets { const classes: string[] = Object.values(WidgetClass) // - .filter(v => typeof v === 'string') + .filter(v => typeof v === "string") .filter(clazz => { - if (!edge.isVersionAtLeast('2018.8')) { + if (!edge.isVersionAtLeast("2018.8")) { // no filter for deprecated versions return true; } switch (clazz) { - case 'Common_Autarchy': - case 'Grid': + case "Common_Autarchy": + case "Grid": return config.hasMeter(); - case 'Energymonitor': - case 'Consumption': + case "Energymonitor": + case "Consumption": if (config.hasMeter() == true || config.hasProducer() == true || config.hasStorage() == true) { return true; } else { return false; } - case 'Storage': + case "Storage": return config.hasStorage(); - case 'Common_Production': - case 'Common_Selfconsumption': + case "Common_Production": + case "Common_Selfconsumption": return config.hasProducer(); - case 'Controller_ChannelThreshold': - return config.getComponentIdsByFactory('Controller.ChannelThreshold')?.length > 0; + case "Controller_ChannelThreshold": + return config.getComponentIdsByFactory("Controller.ChannelThreshold")?.length > 0; + case "Controller_Io_Digital_Outputs": + return config.getComponentIdsByFactories("Controller.Io.FixDigitalOutput", "Controller.IO.ChannelSingleThreshold")?.length > 0; + default: + return false; } - return false; }).map(clazz => clazz.toString()); const list: Widget[] = []; - for (const nature of Object.values(WidgetNature).filter(v => typeof v === 'string')) { + for (const nature of Object.values(WidgetNature).filter(v => typeof v === "string")) { for (const componentId of config.getComponentIdsImplementingNature(nature.toString())) { - if (nature === 'io.openems.edge.io.api.DigitalInput' && list.some(e => e.name === 'io.openems.edge.io.api.DigitalInput')) { + if (nature === "io.openems.edge.io.api.DigitalInput" && list.some(e => e.name === "io.openems.edge.io.api.DigitalInput")) { continue; } if (config.getComponent(componentId).isEnabled) { @@ -116,7 +120,7 @@ export class Widgets { } } } - for (const factory of Object.values(WidgetFactory).filter(v => typeof v === 'string')) { + for (const factory of Object.values(WidgetFactory).filter(v => typeof v === "string")) { for (const componentId of config.getComponentIdsByFactory(factory.toString())) { if (config.getComponent(componentId).isEnabled) { list.push({ name: factory, componentId: componentId }); @@ -126,14 +130,14 @@ export class Widgets { // explicitely sort ChannelThresholdControllers by their outputChannelAddress list.sort((w1, w2) => { - if (w1.name === 'Controller.IO.ChannelSingleThreshold' && w2.name === 'Controller.IO.ChannelSingleThreshold') { - let outputChannelAddress1: string | string[] = config.getComponentProperties(w1.componentId)['outputChannelAddress']; - if (typeof outputChannelAddress1 !== 'string') { + if (w1.name === "Controller.IO.ChannelSingleThreshold" && w2.name === "Controller.IO.ChannelSingleThreshold") { + let outputChannelAddress1: string | string[] = config.getComponentProperties(w1.componentId)["outputChannelAddress"]; + if (typeof outputChannelAddress1 !== "string") { // Takes only the first output for simplicity reasons outputChannelAddress1 = outputChannelAddress1[0]; } - let outputChannelAddress2: string | string[] = config.getComponentProperties(w2.componentId)['outputChannelAddress']; - if (typeof outputChannelAddress2 !== 'string') { + let outputChannelAddress2: string | string[] = config.getComponentProperties(w2.componentId)["outputChannelAddress"]; + if (typeof outputChannelAddress2 !== "string") { // Takes only the first output for simplicity reasons outputChannelAddress2 = outputChannelAddress2[0]; } diff --git a/ui/src/app/shared/utils/array/array.utils.spec.ts b/ui/src/app/shared/utils/array/array.utils.spec.ts index aab90e1edaa..a9298c0c205 100644 --- a/ui/src/app/shared/utils/array/array.utils.spec.ts +++ b/ui/src/app/shared/utils/array/array.utils.spec.ts @@ -1,23 +1,23 @@ // @ts-strict-ignore import { ArrayUtils } from "./array.utils"; -describe('Array-Utils', () => { - it('#findSmallestNumber', () => { +describe("Array-Utils", () => { + it("#findSmallestNumber", () => { expect(ArrayUtils.findSmallestNumber([])).toEqual(null); expect(ArrayUtils.findSmallestNumber([null, null])).toEqual(null); expect(ArrayUtils.findSmallestNumber([0, -1])).toEqual(-1); expect(ArrayUtils.findSmallestNumber([null, undefined])).toEqual(null); }); - it('#findBiggestNumber', () => { + it("#findBiggestNumber", () => { expect(ArrayUtils.findBiggestNumber([])).toEqual(null); expect(ArrayUtils.findBiggestNumber([null, null])).toEqual(null); expect(ArrayUtils.findBiggestNumber([0, -1])).toEqual(0); expect(ArrayUtils.findBiggestNumber([null, undefined])).toEqual(null); }); - it('#sortAlphabeticaly', () => { - const inputArr = ['A', null, 'C', undefined, 'B', 'a', '1']; - const sortedArr = ['1', 'A', 'a', 'B', 'C', null, undefined]; + it("#sortAlphabeticaly", () => { + const inputArr = ["A", null, "C", undefined, "B", "a", "1"]; + const sortedArr = ["1", "A", "a", "B", "C", null, undefined]; expect(ArrayUtils.sortedAlphabetically(inputArr, a => a)).toEqual(sortedArr); expect(ArrayUtils.sortedAlphabetically(inputArr, _a => null)).toEqual(inputArr); diff --git a/ui/src/app/shared/utils/array/array.utils.ts b/ui/src/app/shared/utils/array/array.utils.ts index d5403948bb5..6026afa4579 100644 --- a/ui/src/app/shared/utils/array/array.utils.ts +++ b/ui/src/app/shared/utils/array/array.utils.ts @@ -45,7 +45,7 @@ export namespace ArrayUtils { } else if (!bVal) { return -1; } - return aVal.localeCompare(bVal, undefined, { sensitivity: 'accent' }); + return aVal.localeCompare(bVal, undefined, { sensitivity: "accent" }); }); } } diff --git a/ui/src/app/shared/utils/color/color.utils.spec.ts b/ui/src/app/shared/utils/color/color.utils.spec.ts index d9ee75dd2a8..4ba93b95ff9 100644 --- a/ui/src/app/shared/utils/color/color.utils.spec.ts +++ b/ui/src/app/shared/utils/color/color.utils.spec.ts @@ -1,17 +1,17 @@ // @ts-strict-ignore import { ColorUtils } from "./color.utils"; -describe('Color-Utils', () => { - it('#rgbStringToRgba', () => { - expect(ColorUtils.rgbStringToRGBA('rgb(0,0,0)', 1)).toBe('rgba(0,0,0,1)'); - expect(ColorUtils.rgbStringToRGBA('rgb(0,0,0)', null)).toEqual('rgba(0,0,0,0)'); +describe("Color-Utils", () => { + it("#rgbStringToRgba", () => { + expect(ColorUtils.rgbStringToRGBA("rgb(0,0,0)", 1)).toBe("rgba(0,0,0,1)"); + expect(ColorUtils.rgbStringToRGBA("rgb(0,0,0)", null)).toEqual("rgba(0,0,0,0)"); expect(ColorUtils.rgbStringToRGBA(null, 1)).toEqual(null); expect(ColorUtils.rgbStringToRGBA(null, null)).toEqual(null); }); - it('#changeOpacityFromRGBA', () => { - expect(ColorUtils.changeOpacityFromRGBA('rgba(0,0,0,0.05)', 1)).toBe('rgba(0,0,0,1)'); - expect(ColorUtils.changeOpacityFromRGBA('rgba(0,0,0,0.05)', null)).toBe('rgba(0,0,0,0)'); + it("#changeOpacityFromRGBA", () => { + expect(ColorUtils.changeOpacityFromRGBA("rgba(0,0,0,0.05)", 1)).toBe("rgba(0,0,0,1)"); + expect(ColorUtils.changeOpacityFromRGBA("rgba(0,0,0,0.05)", null)).toBe("rgba(0,0,0,0)"); expect(ColorUtils.changeOpacityFromRGBA(null, 1)).toBe(null); expect(ColorUtils.changeOpacityFromRGBA(null, null)).toBe(null); }); diff --git a/ui/src/app/shared/utils/color/color.utils.ts b/ui/src/app/shared/utils/color/color.utils.ts index e8408861359..a561dc53eca 100644 --- a/ui/src/app/shared/utils/color/color.utils.ts +++ b/ui/src/app/shared/utils/color/color.utils.ts @@ -14,7 +14,7 @@ export namespace ColorUtils { return null; } - return 'rgba(' + color.split('(').pop().split(')')[0] + ',' + (opacity ?? 0) + ')'; + return "rgba(" + color.split("(").pop().split(")")[0] + "," + (opacity ?? 0) + ")"; } /** @@ -30,9 +30,9 @@ export namespace ColorUtils { return null; } - const rgba = color.split('(').pop().split(')')[0]; - const rgb = rgba.split(',').slice(0, -1).join(','); + const rgba = color.split("(").pop().split(")")[0]; + const rgb = rgba.split(",").slice(0, -1).join(","); - return 'rgba(' + rgb + ',' + (opacity ?? 0) + ')'; + return "rgba(" + rgb + "," + (opacity ?? 0) + ")"; } } diff --git a/ui/src/app/shared/utils/date/dateutils.spec.ts b/ui/src/app/shared/utils/date/dateutils.spec.ts index 05916c3bfdb..83e03852083 100644 --- a/ui/src/app/shared/utils/date/dateutils.spec.ts +++ b/ui/src/app/shared/utils/date/dateutils.spec.ts @@ -1,14 +1,14 @@ // @ts-strict-ignore import { DateUtils } from "./dateutils"; -describe('DateUtils', () => { +describe("DateUtils", () => { const dates: Date[] = [ new Date(Date.parse("2023-01-01")), new Date(Date.parse("2023-01-02")), ]; - it('#minDate - smallest date', () => { + it("#minDate - smallest date", () => { // valid params expect(DateUtils.minDate(...dates)).toEqual(dates[0]); @@ -20,7 +20,7 @@ describe('DateUtils', () => { expect(isNaN(DateUtils.minDate(null, null)?.getTime())).toBe(true); }); - it('#maxDate - biggest date', () => { + it("#maxDate - biggest date", () => { // valid params expect(DateUtils.maxDate(...dates)).toEqual(dates[1]); @@ -31,13 +31,13 @@ describe('DateUtils', () => { expect(isNaN(DateUtils.maxDate(null, null)?.getTime())).toBe(true); }); - it('#stringToDate - converts string to date', () => { - expect(DateUtils.stringToDate('2023-01-02')).toEqual(new Date(Date.parse('2023-01-02'))); - expect(DateUtils.stringToDate('wrong format')).toEqual(null); + it("#stringToDate - converts string to date", () => { + expect(DateUtils.stringToDate("2023-01-02")).toEqual(new Date(Date.parse("2023-01-02"))); + expect(DateUtils.stringToDate("wrong format")).toEqual(null); }); - it('#isDateBefore - checks if given date is before date to be compared to', () => { - const date: Date = DateUtils.stringToDate('2023-01-01') as Date; + it("#isDateBefore - checks if given date is before date to be compared to", () => { + const date: Date = DateUtils.stringToDate("2023-01-01") as Date; expect(DateUtils.isDateBefore(date, DateUtils.stringToDate("2023-01-31"))).toEqual(true); expect(DateUtils.isDateBefore(date, DateUtils.stringToDate("2022-12-31"))).toEqual(false); expect(DateUtils.isDateBefore(date, DateUtils.stringToDate("2023-01-01"))).toEqual(false); diff --git a/ui/src/app/shared/utils/date/dateutils.ts b/ui/src/app/shared/utils/date/dateutils.ts index 52de4321ed7..253e06cda38 100644 --- a/ui/src/app/shared/utils/date/dateutils.ts +++ b/ui/src/app/shared/utils/date/dateutils.ts @@ -106,6 +106,6 @@ export namespace DateUtils { if (!fromDate || !toDate) { return null; } - return format(fromDate, translate.instant('General.dateFormat')) + " - " + format(toDate, translate.instant('General.dateFormat')); + return format(fromDate, translate.instant("General.dateFormat")) + " - " + format(toDate, translate.instant("General.dateFormat")); } } diff --git a/ui/src/app/shared/utils/datetime/datetime-utils.ts b/ui/src/app/shared/utils/datetime/datetime-utils.ts index aec8bad6a21..70bb0b7cc58 100644 --- a/ui/src/app/shared/utils/datetime/datetime-utils.ts +++ b/ui/src/app/shared/utils/datetime/datetime-utils.ts @@ -23,7 +23,7 @@ export class DateTimeUtils { // Change first timestamp to start of month const formattedDate = startOfMonth(DateUtils.stringToDate(energyPerPeriodResponse.result.timestamps[0])); - energyPerPeriodResponse.result.timestamps[0] = format(formattedDate, 'yyyy-MM-dd HH:mm:ss', { locale: de })?.toString() ?? energyPerPeriodResponse.result.timestamps[0]; + energyPerPeriodResponse.result.timestamps[0] = format(formattedDate, "yyyy-MM-dd HH:mm:ss", { locale: de })?.toString() ?? energyPerPeriodResponse.result.timestamps[0]; // show 12 stacks, even if no data and timestamps const newTimestamps: string[] = []; @@ -40,7 +40,7 @@ export class DateTimeUtils { } energyPerPeriodResponse.result.timestamps = newTimestamps.concat(energyPerPeriodResponse.result.timestamps); - break; + return energyPerPeriodResponse; } case ChronoUnit.Type.YEARS: { @@ -48,11 +48,12 @@ export class DateTimeUtils { // Change dates to be first day of year const formattedDates = energyPerPeriodResponse.result.timestamps.map((timestamp) => startOfYear(DateUtils.stringToDate(timestamp))); - energyPerPeriodResponse.result.timestamps = formattedDates.map(date => format(date, 'yyyy-MM-dd HH:mm:ss', { locale: de })?.toString()); - break; + energyPerPeriodResponse.result.timestamps = formattedDates.map(date => format(date, "yyyy-MM-dd HH:mm:ss", { locale: de })?.toString()); + return energyPerPeriodResponse; } + default: + return energyPerPeriodResponse; } - return energyPerPeriodResponse; } } diff --git a/ui/src/app/shared/utils/time/timeutils.spec.ts b/ui/src/app/shared/utils/time/timeutils.spec.ts index 0916acd4b76..4286ef47110 100644 --- a/ui/src/app/shared/utils/time/timeutils.spec.ts +++ b/ui/src/app/shared/utils/time/timeutils.spec.ts @@ -1,11 +1,11 @@ // @ts-strict-ignore import { TimeUtils } from "./timeutils"; -describe('TimeUtils', () => { - it('#formatSecondsToDuration', () => { - expect(TimeUtils.formatSecondsToDuration(12000, 'de')).toEqual("3h 20m"); - expect(TimeUtils.formatSecondsToDuration(null, 'de')).toEqual(null); - expect(TimeUtils.formatSecondsToDuration(undefined, 'de')).toEqual(null); +describe("TimeUtils", () => { + it("#formatSecondsToDuration", () => { + expect(TimeUtils.formatSecondsToDuration(12000, "de")).toEqual("3h 20m"); + expect(TimeUtils.formatSecondsToDuration(null, "de")).toEqual(null); + expect(TimeUtils.formatSecondsToDuration(undefined, "de")).toEqual(null); expect(TimeUtils.formatSecondsToDuration(12000, null)).toEqual("3h 20m"); }); }); diff --git a/ui/src/app/shared/utils/time/timeutils.ts b/ui/src/app/shared/utils/time/timeutils.ts index 905f2128402..2998327d2ab 100644 --- a/ui/src/app/shared/utils/time/timeutils.ts +++ b/ui/src/app/shared/utils/time/timeutils.ts @@ -23,9 +23,9 @@ export class TimeUtils { minutes -= hours * 60; if (hours <= 23 && minutes > 0) { - return decimalPipe.transform(hours, '1.0-0') + 'h' + " " + decimalPipe.transform(minutes, '1.0-0') + 'm'; + return decimalPipe.transform(hours, "1.0-0") + "h" + " " + decimalPipe.transform(minutes, "1.0-0") + "m"; } else { - return decimalPipe.transform(hours, '1.0-0') + 'h'; + return decimalPipe.transform(hours, "1.0-0") + "h"; } } @@ -49,9 +49,9 @@ export class TimeUtils { const minutes = Math.floor(seconds / 60); if (minutes > 0) { - return decimalPipe.transform(minutes, '1.0-0') + ' min'; + return decimalPipe.transform(minutes, "1.0-0") + " min"; } else { - return decimalPipe.transform(seconds, '1.0-0') + ' s'; + return decimalPipe.transform(seconds, "1.0-0") + " s"; } } } diff --git a/ui/src/app/user/user.component.ts b/ui/src/app/user/user.component.ts index 363937cb827..b42945d1521 100644 --- a/ui/src/app/user/user.component.ts +++ b/ui/src/app/user/user.component.ts @@ -1,18 +1,18 @@ // @ts-strict-ignore -import { Component, OnInit } from '@angular/core'; -import { FormGroup, Validators } from '@angular/forms'; -import { ActivatedRoute } from '@angular/router'; -import { FormlyFieldConfig } from '@ngx-formly/core'; -import { TranslateService } from '@ngx-translate/core'; -import { Changelog } from 'src/app/changelog/view/component/changelog.constants'; -import { environment } from '../../environments'; -import { GetUserInformationRequest } from '../shared/jsonrpc/request/getUserInformationRequest'; -import { SetUserInformationRequest } from '../shared/jsonrpc/request/setUserInformationRequest'; -import { UpdateUserLanguageRequest } from '../shared/jsonrpc/request/updateUserLanguageRequest'; -import { GetUserInformationResponse } from '../shared/jsonrpc/response/getUserInformationResponse'; -import { Service, Websocket } from '../shared/shared'; -import { COUNTRY_OPTIONS } from '../shared/type/country'; -import { Language } from '../shared/type/language'; +import { Component, OnInit } from "@angular/core"; +import { FormGroup, Validators } from "@angular/forms"; +import { ActivatedRoute } from "@angular/router"; +import { FormlyFieldConfig } from "@ngx-formly/core"; +import { TranslateService } from "@ngx-translate/core"; +import { Changelog } from "src/app/changelog/view/component/changelog.constants"; +import { environment } from "../../environments"; +import { GetUserInformationRequest } from "../shared/jsonrpc/request/getUserInformationRequest"; +import { SetUserInformationRequest } from "../shared/jsonrpc/request/setUserInformationRequest"; +import { UpdateUserLanguageRequest } from "../shared/jsonrpc/request/updateUserLanguageRequest"; +import { GetUserInformationResponse } from "../shared/jsonrpc/response/getUserInformationResponse"; +import { Service, Websocket } from "../shared/shared"; +import { COUNTRY_OPTIONS } from "../shared/type/country"; +import { Language } from "../shared/type/language"; type CompanyUserInformation = UserInformation & { companyName: string }; @@ -28,7 +28,7 @@ type UserInformation = { }; @Component({ - templateUrl: './user.component.html', + templateUrl: "./user.component.html", }) export class UserComponent implements OnInit { @@ -67,7 +67,6 @@ export class UserComponent implements OnInit { ngOnInit() { // Set currentLanguage to this.currentLanguage = Language.getByKey(localStorage.LANGUAGE) ?? Language.DEFAULT; - this.service.setCurrentComponent({ languageKey: 'Menu.user' }, this.route); this.getUserInformation().then((userInformation) => { this.form = { formGroup: new FormGroup({}), @@ -127,13 +126,13 @@ export class UserComponent implements OnInit { }, }]; - if (Object.prototype.hasOwnProperty.call(userInformation, 'companyName')) { + if (Object.prototype.hasOwnProperty.call(userInformation, "companyName")) { this.companyInformationFields.push( { key: "companyName", type: "input", props: { - label: this.translate.instant('Register.Form.companyName'), + label: this.translate.instant("Register.Form.companyName"), disabled: true, }, }, @@ -152,7 +151,7 @@ export class UserComponent implements OnInit { public applyChanges() { - const params: SetUserInformationRequest['params'] = { + const params: SetUserInformationRequest["params"] = { user: { lastname: this.form.model.lastname, firstname: this.form.model.firstname, @@ -168,9 +167,9 @@ export class UserComponent implements OnInit { }; this.service.websocket.sendRequest(new SetUserInformationRequest(params)).then(() => { - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); + this.service.toast(this.translate.instant("General.changeAccepted"), "success"); }).catch((reason) => { - this.service.toast(this.translate.instant('General.changeFailed') + '\n' + reason.error.message, 'danger'); + this.service.toast(this.translate.instant("General.changeFailed") + "\n" + reason.error.message, "danger"); }); this.enableAndDisableFormFields(); this.form.formGroup.markAsPristine(); @@ -203,7 +202,7 @@ export class UserComponent implements OnInit { return new Promise(resolve => { const interval = setInterval(() => { - if (this.websocket.status == 'online') { + if (this.websocket.status == "online") { this.service.websocket.sendRequest(new GetUserInformationRequest()).then((response: GetUserInformationResponse) => { const user = response.result.user; @@ -246,8 +245,8 @@ export class UserComponent implements OnInit { } public toggleDebugMode(event: CustomEvent) { - localStorage.setItem("DEBUGMODE", event.detail['checked']); - this.environment.debugMode = event.detail['checked']; + localStorage.setItem("DEBUGMODE", event.detail["checked"]); + this.environment.debugMode = event.detail["checked"]; } public setLanguage(language: Language): void { @@ -256,9 +255,9 @@ export class UserComponent implements OnInit { this.service.setLang(language); this.websocket.sendRequest(new UpdateUserLanguageRequest({ language: language.key })).then(() => { - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); + this.service.toast(this.translate.instant("General.changeAccepted"), "success"); }).catch((reason) => { - this.service.toast(this.translate.instant('General.changeFailed') + '\n' + reason.error.message, 'danger'); + this.service.toast(this.translate.instant("General.changeFailed") + "\n" + reason.error.message, "danger"); }); this.currentLanguage = language; diff --git a/ui/src/app/user/user.module.ts b/ui/src/app/user/user.module.ts index 71081adaf79..a0352848700 100644 --- a/ui/src/app/user/user.module.ts +++ b/ui/src/app/user/user.module.ts @@ -1,6 +1,6 @@ -import { NgModule } from '@angular/core'; -import { SharedModule } from './../shared/shared.module'; -import { UserComponent } from './user.component'; +import { NgModule } from "@angular/core"; +import { SharedModule } from "./../shared/shared.module"; +import { UserComponent } from "./user.component"; @NgModule({ imports: [ diff --git a/ui/src/assets/i18n/de.json b/ui/src/assets/i18n/de.json index 3096991606a..5e45735b3cf 100644 --- a/ui/src/assets/i18n/de.json +++ b/ui/src/assets/i18n/de.json @@ -245,7 +245,14 @@ "CHART_TITLE": "Aktueller Fahrplan (BETA-Test)", "CHART_WARNING_NOTE": "Die Grafik zeigt die vergangenen drei Stunden, sowie die zukünftig geplante Betriebsweise für den Zeitraum, für den die dynamischen Netzbezugspreise zur Verfügung stehen. Bitte beachten Sie, dass der Fahrplan kontinuierlich neu berechnet wird und sich somit im Tagesverlauf ändern kann.", "POWER_SOC_CHART_TITLE": "Vorhersagen (Nur für Admins)" - } + }, + "SYSTEM": { + "INDUSTRIAL": { + "NOTE": "Startet oder stoppt das Gesamtsystem, inklusive Batteriewechselrichter und Batterien." + }, + "OVERALL_SYSTEM": "Gesamtsystem" + }, + "FIX_DIGITAL_OUTPUT": "Digitale Ausgangscontroller" }, "RETROFITTING": { "UPDATE_TO_NEW_VERSION": "Um die Kapazitätserweiterung nutzen zu können, ist ein Update auf die neueste Version erforderlich.", diff --git a/ui/src/assets/i18n/en.json b/ui/src/assets/i18n/en.json index 45f7388ab29..3c555925b24 100644 --- a/ui/src/assets/i18n/en.json +++ b/ui/src/assets/i18n/en.json @@ -246,7 +246,14 @@ "CHART_TITLE": "Planned Schedule (BETA test)", "CHART_WARNING_NOTE": "The graphic shows the past three hours as well as the future planned operating mode for the period for which the dynamic grid purchase prices are available. Please note that the planned schedule is subject to continuous recalculation and may change throughout the day.", "POWER_SOC_CHART_TITLE": "Forecasts (Only for Admins)" - } + }, + "SYSTEM": { + "INDUSTRIAL": { + "NOTE": "Starts or stops the entire system, including battery inverter and batteries." + }, + "OVERALL_SYSTEM": "Overall system" + }, + "FIX_DIGITAL_OUTPUT": "Digital Outputcontroller" }, "RETROFITTING": { "OPTIMAL": "Capacity expansion", diff --git a/ui/src/environments/index.ts b/ui/src/environments/index.ts index 0515cc35d5d..e10181d51ce 100644 --- a/ui/src/environments/index.ts +++ b/ui/src/environments/index.ts @@ -1,9 +1,9 @@ -import { TranslateService } from '@ngx-translate/core'; -import { Filter } from 'src/app/index/filter/filter.component'; -import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; -export { environment } from './dummy'; +import { TranslateService } from "@ngx-translate/core"; +import { Filter } from "src/app/index/filter/filter.component"; +import { DefaultTypes } from "src/app/shared/service/defaulttypes"; +export { environment } from "./dummy"; -export type Theme = 'OpenEMS'; +export type Theme = "OpenEMS"; export interface Environment { readonly theme: Theme; diff --git a/ui/src/global.scss b/ui/src/global.scss index e0007c5fbe7..59a24c31264 100644 --- a/ui/src/global.scss +++ b/ui/src/global.scss @@ -26,6 +26,13 @@ @import "node_modules/ngx-spinner/animations/ball-clip-rotate-multiple.css"; @import "variables"; +/* Live- and HistoryComponent*/ +ion-refresher-content { + ion-spinner { + left: 0 !important; + } +} + .custom-ion-popover { white-space: inherit; @@ -396,4 +403,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/main.ts b/ui/src/main.ts index 001a8fbd192..cb2219c75a6 100644 --- a/ui/src/main.ts +++ b/ui/src/main.ts @@ -1,7 +1,7 @@ -import { enableProdMode } from '@angular/core'; -import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; -import { AppModule } from 'src/app/app.module'; -import { environment } from 'src/environments'; +import { enableProdMode } from "@angular/core"; +import { platformBrowserDynamic } from "@angular/platform-browser-dynamic"; +import { AppModule } from "src/app/app.module"; +import { environment } from "src/environments"; if (environment.production) { enableProdMode(); diff --git a/ui/src/polyfills.ts b/ui/src/polyfills.ts index 9c6628376e2..1f1d0cedfd1 100644 --- a/ui/src/polyfills.ts +++ b/ui/src/polyfills.ts @@ -19,7 +19,7 @@ */ /** IE11 requires the following for NgClass support on SVG elements */ -import 'classlist.js'; // Run `npm install --save classlist.js`. +import "classlist.js"; // Run `npm install --save classlist.js`. /** * Web Animations `@angular/platform-browser/animations` @@ -52,12 +52,14 @@ import 'classlist.js'; // Run `npm install --save classlist.js`. * */ -import './zone-flags'; +import "./zone-flags"; /*************************************************************************************************** * Zone JS is required by default for Angular itself. */ -import 'zone.js/dist/zone'; // Included with Angular CLI. +import "zone.js"; + +// Included with Angular CLI. /*************************************************************************************************** diff --git a/ui/src/test.ts b/ui/src/test.ts index 2d851fa6be3..31342e27233 100644 --- a/ui/src/test.ts +++ b/ui/src/test.ts @@ -7,13 +7,13 @@ // This file is required by karma.conf.js and loads recursively all the .spec and framework files -import 'zone.js/testing'; +import "zone.js/testing"; -import { getTestBed } from '@angular/core/testing'; +import { getTestBed } from "@angular/core/testing"; import { BrowserDynamicTestingModule, platformBrowserDynamicTesting, -} from '@angular/platform-browser-dynamic/testing'; +} from "@angular/platform-browser-dynamic/testing"; // First, initialize the Angular testing environment. getTestBed().initTestEnvironment( diff --git a/ui/src/themes/openems/environments/backend-dev.ts b/ui/src/themes/openems/environments/backend-dev.ts index f48b00c5e42..a6726d2b8c5 100644 --- a/ui/src/themes/openems/environments/backend-dev.ts +++ b/ui/src/themes/openems/environments/backend-dev.ts @@ -4,7 +4,7 @@ import { theme } from "./theme"; export const environment: Environment = { ...theme, ...{ - backend: 'OpenEMS Backend', + backend: "OpenEMS Backend", url: "ws://" + location.hostname + ":8082", production: false, diff --git a/ui/src/themes/openems/environments/backend-docker.ts b/ui/src/themes/openems/environments/backend-docker.ts index f49468be729..078845ad97c 100644 --- a/ui/src/themes/openems/environments/backend-docker.ts +++ b/ui/src/themes/openems/environments/backend-docker.ts @@ -11,7 +11,7 @@ const window_env = (window as any).env as { [key: string]: string }; export const environment: Environment = { ...theme, ...{ - backend: 'OpenEMS Backend', + backend: "OpenEMS Backend", url: window_env.websocket, production: true, diff --git a/ui/src/themes/openems/environments/backend-prod.ts b/ui/src/themes/openems/environments/backend-prod.ts index ae5bb5eb32f..ebfe2b1ecf2 100644 --- a/ui/src/themes/openems/environments/backend-prod.ts +++ b/ui/src/themes/openems/environments/backend-prod.ts @@ -4,7 +4,7 @@ import { theme } from "./theme"; export const environment: Environment = { ...theme, ...{ - backend: 'OpenEMS Backend', + backend: "OpenEMS Backend", url: "ws://" + location.hostname + ":8082", production: true, diff --git a/ui/src/themes/openems/environments/edge-dev.ts b/ui/src/themes/openems/environments/edge-dev.ts index 164dd04f34e..b36d202ef27 100644 --- a/ui/src/themes/openems/environments/edge-dev.ts +++ b/ui/src/themes/openems/environments/edge-dev.ts @@ -4,7 +4,7 @@ import { theme } from "./theme"; export const environment: Environment = { ...theme, ...{ - backend: 'OpenEMS Edge', + backend: "OpenEMS Edge", url: "ws://" + location.hostname + ":8085", production: false, diff --git a/ui/src/themes/openems/environments/edge-docker.ts b/ui/src/themes/openems/environments/edge-docker.ts index 810acf2717a..59371199cdd 100644 --- a/ui/src/themes/openems/environments/edge-docker.ts +++ b/ui/src/themes/openems/environments/edge-docker.ts @@ -11,7 +11,7 @@ const window_env = (window as any).env as { [key: string]: string }; export const environment: Environment = { ...theme, ...{ - backend: 'OpenEMS Edge', + backend: "OpenEMS Edge", url: window_env.websocket, production: true, diff --git a/ui/src/themes/openems/environments/edge-prod.ts b/ui/src/themes/openems/environments/edge-prod.ts index bcaf40f6901..183a4f0fef9 100644 --- a/ui/src/themes/openems/environments/edge-prod.ts +++ b/ui/src/themes/openems/environments/edge-prod.ts @@ -4,7 +4,7 @@ import { theme } from "./theme"; export const environment: Environment = { ...theme, ...{ - backend: 'OpenEMS Edge', + backend: "OpenEMS Edge", url: "ws://" + location.hostname + ":8075", production: true, diff --git a/ui/src/themes/openems/environments/gitpod.ts b/ui/src/themes/openems/environments/gitpod.ts index 1ef2f8ca499..88de7c57cdc 100644 --- a/ui/src/themes/openems/environments/gitpod.ts +++ b/ui/src/themes/openems/environments/gitpod.ts @@ -4,7 +4,7 @@ import { theme } from "./theme"; export const environment: Environment = { ...theme, ...{ - backend: 'OpenEMS Backend', + backend: "OpenEMS Backend", // gitpod puts the port number in front of the hostname url: "wss://8082-" + location.hostname.substring(location.hostname.indexOf("-") + 1), diff --git a/ui/src/themes/openems/environments/theme.ts b/ui/src/themes/openems/environments/theme.ts index bf94176f4f7..d771eb259d7 100644 --- a/ui/src/themes/openems/environments/theme.ts +++ b/ui/src/themes/openems/environments/theme.ts @@ -1,4 +1,4 @@ -import { Theme } from 'src/environments'; +import { Theme } from "src/environments"; export const theme = { theme: "OpenEMS" as Theme, From 804ea56fce51b8cbde5d961025500d3b5c796469 Mon Sep 17 00:00:00 2001 From: Hannes Date: Sat, 31 Aug 2024 14:52:12 +0200 Subject: [PATCH 124/173] Docs: fix `./gradlew :io.openems.edge.io.shelly:test` (#2752) Fix the "clean" into "test" for starting a test --- doc/modules/ROOT/pages/edge/implement.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/modules/ROOT/pages/edge/implement.adoc b/doc/modules/ROOT/pages/edge/implement.adoc index 51890ce5a40..79904339734 100644 --- a/doc/modules/ROOT/pages/edge/implement.adoc +++ b/doc/modules/ROOT/pages/edge/implement.adoc @@ -584,5 +584,5 @@ Same applies to the OpenEMS Backend for dynamically loading devices. Before continuing with the development and implementation, it's important to ensure that your module's tests are passing. This helps in maintaining the quality and functionality of the module. To check the tests of your module, execute the following Gradle command in the root directory of OpenEMS: ---- -Run ./gradlew :io.openems.edge.io.shelly:clean in the root Directory to check the tests of your module. +Run ./gradlew :io.openems.edge.io.shelly:test in the root Directory to check the tests of your module. ---- From 67747a8b5e3b49f76d4bf2bec9cb0f8982ff301d Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Sat, 31 Aug 2024 15:04:23 +0200 Subject: [PATCH 125/173] Update to Gradle 8.10 --- .gradle-wrapper/gradle-wrapper.jar | Bin 43453 -> 43504 bytes .gradle-wrapper/gradle-wrapper.properties | 2 +- gradlew | 5 ++++- gradlew.bat | 2 ++ 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.gradle-wrapper/gradle-wrapper.jar b/.gradle-wrapper/gradle-wrapper.jar index e6441136f3d4ba8a0da8d277868979cfbc8ad796..2c3521197d7c4586c843d1d3e9090525f1898cde 100644 GIT binary patch delta 8703 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 Ojj7^59?Sdh$^Qpp*~F>< delta 8662 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 diff --git a/.gradle-wrapper/gradle-wrapper.properties b/.gradle-wrapper/gradle-wrapper.properties index 09523c0e549..9355b415575 100644 --- a/.gradle-wrapper/gradle-wrapper.properties +++ b/.gradle-wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 09d360f6284..951a127823d 100755 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -84,7 +86,8 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/gradlew.bat b/gradlew.bat index 922eb59f04f..237848b5ef1 100755 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## From d2ef52ac07af6fdb65885d3f789cb156e2c341fe Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Sat, 31 Aug 2024 15:10:46 +0200 Subject: [PATCH 126/173] Push version to 2024.9.0 --- .../src/io/openems/common/OpenemsConstants.java | 2 +- tools/common.sh | 5 ----- ui/package-lock.json | 4 ++-- ui/package.json | 2 +- ui/src/app/changelog/view/component/changelog.constants.ts | 2 +- 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/io.openems.common/src/io/openems/common/OpenemsConstants.java b/io.openems.common/src/io/openems/common/OpenemsConstants.java index 001ac36ce1c..69b49e779ee 100644 --- a/io.openems.common/src/io/openems/common/OpenemsConstants.java +++ b/io.openems.common/src/io/openems/common/OpenemsConstants.java @@ -36,7 +36,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/tools/common.sh b/tools/common.sh index d18b68f18be..ed3c536b323 100644 --- a/tools/common.sh +++ b/tools/common.sh @@ -8,7 +8,6 @@ common_initialize_environment() { SRC_PACKAGE_JSON="ui/package.json" SRC_PACKAGE_LOCK_JSON="ui/package-lock.json" SRC_CHANGELOG_CONSTANTS="ui/src/app/changelog/view/component/changelog.constants.ts" - SRC_ANDROID_GRADLE="ui/android/app/build.gradle" # Set environment variables THEME="${THEME:-openems}" @@ -62,10 +61,6 @@ common_update_version_in_code() { echo "## Update $SRC_CHANGELOG_CONSTANTS" sed --in-place "s#\(UI_VERSION = \"\).*\(\";\)#\1$VERSION\2#" $SRC_CHANGELOG_CONSTANTS - - echo "## Update $SRC_ANDROID_GRADLE" - sed --in-place "s#\(versionCode \).*\$#\1$(printf "%04d%02d%02d" $VERSION_MAJOR $VERSION_MINOR $VERSION_PATCH)#" $SRC_ANDROID_GRADLE - sed --in-place "s#\(versionName \).*\$#\1\"$VERSION\"#" $SRC_ANDROID_GRADLE } # Build OpenEMS Backend diff --git a/ui/package-lock.json b/ui/package-lock.json index eb23f05a996..edc7956ab67 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "openems-ui", - "version": "2024.9.0-SNAPSHOT", + "version": "2024.9.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "openems-ui", - "version": "2024.9.0-SNAPSHOT", + "version": "2024.9.0", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "18.0.5", diff --git a/ui/package.json b/ui/package.json index 11ad80f8c00..0e232477e3c 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,6 +1,6 @@ { "name": "openems-ui", - "version": "2024.9.0-SNAPSHOT", + "version": "2024.9.0", "license": "AGPL-3.0", "private": true, "dependencies": { diff --git a/ui/src/app/changelog/view/component/changelog.constants.ts b/ui/src/app/changelog/view/component/changelog.constants.ts index 0bef8c32fa2..99de881dd8b 100644 --- a/ui/src/app/changelog/view/component/changelog.constants.ts +++ b/ui/src/app/changelog/view/component/changelog.constants.ts @@ -2,7 +2,7 @@ import { Role } from "src/app/shared/type/role"; export class Changelog { - public static readonly UI_VERSION = "2024.9.0-SNAPSHOT"; + public static readonly UI_VERSION = "2024.9.0"; public static product(...products: Product[]) { return products.map(product => Changelog.link(product.name, product.url)).join(", ") + ". "; From af9aaea28b6cac8f0ef5f670bd0c413b6cc281d7 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Sat, 31 Aug 2024 15:15:06 +0200 Subject: [PATCH 127/173] Start development of version 2024.10.0-SNAPSHOT --- io.openems.common/src/io/openems/common/OpenemsConstants.java | 4 ++-- ui/package-lock.json | 4 ++-- ui/package.json | 2 +- ui/src/app/changelog/view/component/changelog.constants.ts | 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 69b49e779ee..cbfc12274fb 100644 --- a/io.openems.common/src/io/openems/common/OpenemsConstants.java +++ b/io.openems.common/src/io/openems/common/OpenemsConstants.java @@ -22,7 +22,7 @@ public class OpenemsConstants { *

      * This is the month of the release. */ - public static final short VERSION_MINOR = 9; + public static final short VERSION_MINOR = 10; /** * The patch version of OpenEMS. @@ -36,7 +36,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 edc7956ab67..57e8255f84d 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "openems-ui", - "version": "2024.9.0", + "version": "2024.10.0-SNAPSHOT", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "openems-ui", - "version": "2024.9.0", + "version": "2024.10.0-SNAPSHOT", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "18.0.5", diff --git a/ui/package.json b/ui/package.json index 0e232477e3c..8f0c436942f 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,6 +1,6 @@ { "name": "openems-ui", - "version": "2024.9.0", + "version": "2024.10.0-SNAPSHOT", "license": "AGPL-3.0", "private": true, "dependencies": { diff --git a/ui/src/app/changelog/view/component/changelog.constants.ts b/ui/src/app/changelog/view/component/changelog.constants.ts index 99de881dd8b..700da6a26cb 100644 --- a/ui/src/app/changelog/view/component/changelog.constants.ts +++ b/ui/src/app/changelog/view/component/changelog.constants.ts @@ -2,7 +2,7 @@ import { Role } from "src/app/shared/type/role"; export class Changelog { - public static readonly UI_VERSION = "2024.9.0"; + public static readonly UI_VERSION = "2024.10.0-SNAPSHOT"; public static product(...products: Product[]) { return products.map(product => Changelog.link(product.name, product.url)).join(", ") + ". "; From 6eb132474792e9df11bea45d192322b36050a140 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Mon, 2 Sep 2024 20:54:04 +0200 Subject: [PATCH 128/173] UI: modularize translation files & pageTitle fallback - Adding possibility to modularize translation files - add fallback for currentPageTitle Reviewed-by: Sagar Venu <32655208+venu-sagar@users.noreply.github.com> Reviewed-by: Stefan Feilmeier <3515268+sfeilmeier@users.noreply.github.com> Co-authored-by: Lukas Rieger <73471197+lukasrgr@users.noreply.github.com> Co-committed-by: Lukas Rieger <73471197+lukasrgr@users.noreply.github.com> --- ui/src/app/edge/edge.component.ts | 2 -- .../service/globalRouteChangeHandler.ts | 3 ++- ui/src/app/shared/type/language.ts | 23 ++++++++++++++++++- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/ui/src/app/edge/edge.component.ts b/ui/src/app/edge/edge.component.ts index fdeeebc3a3c..c0acc0aa952 100644 --- a/ui/src/app/edge/edge.component.ts +++ b/ui/src/app/edge/edge.component.ts @@ -10,8 +10,6 @@ import { ChannelAddress, Edge, Service, Websocket } from "src/app/shared/shared" template: ` - `, }) export class EdgeComponent implements OnInit, OnDestroy { diff --git a/ui/src/app/shared/service/globalRouteChangeHandler.ts b/ui/src/app/shared/service/globalRouteChangeHandler.ts index 17d628c4fa7..8992c77e7a4 100644 --- a/ui/src/app/shared/service/globalRouteChangeHandler.ts +++ b/ui/src/app/shared/service/globalRouteChangeHandler.ts @@ -4,6 +4,7 @@ import { Router, RoutesRecognized } from "@angular/router"; import { TranslateService } from "@ngx-translate/core"; import { filter, map } from "rxjs/operators"; +import { environment } from "src/environments"; import { Service } from "./service"; @Injectable({ @@ -35,7 +36,7 @@ export class GlobalRouteChangeHandler { throw new Error("Either use navbarTitle or navbarTitleToBeTranslated"); } - this.service.currentPageTitle = e.navbarTitle ?? (e.navbarTitleToBeTranslated ? translate.instant(e.navbarTitleToBeTranslated) : null) ?? this.service.currentPageTitle; + this.service.currentPageTitle = e.navbarTitle ?? (e.navbarTitleToBeTranslated ? translate.instant(e.navbarTitleToBeTranslated) : null) ?? this.service.currentPageTitle ?? environment.uiTitle; }); } } diff --git a/ui/src/app/shared/type/language.ts b/ui/src/app/shared/type/language.ts index 79a88549ab3..b76c3dd2d8b 100644 --- a/ui/src/app/shared/type/language.ts +++ b/ui/src/app/shared/type/language.ts @@ -13,8 +13,9 @@ import es from "src/assets/i18n/es.json"; import fr from "src/assets/i18n/fr.json"; import ja from "src/assets/i18n/ja.json"; import nl from "src/assets/i18n/nl.json"; +import { environment } from "src/environments"; -interface Translation { +export interface Translation { [key: string]: string | Translation; } @@ -107,4 +108,24 @@ export class Language { return lang?.i18nLocaleKey ?? Language.DEFAULT.i18nLocaleKey; } + + /** + * Sets a additional translation file + * + * e.g. AdvertismentModule + * + * @param translationFile the translation file + * @returns translations params + */ + public static setAdditionalTranslationFile(translationFile: any): { lang: string, translations: {}, shouldMerge?: boolean } { + let key = localStorage.LANGUAGE ?? Language.DEFAULT.key; + if (!(key in translationFile)) { + + if (environment.debugMode) { + console.warn(`[Advert] No translation available for Language ${key}. Implemented languages are: ${Object.keys(translationFile)}`); + } + key = Language.DEFAULT.key; + } + return { lang: key, translations: translationFile[key], shouldMerge: true }; + } } From 07075d137296c9e7520aa9a01395b104649a68b2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Sep 2024 14:43:47 +0200 Subject: [PATCH 129/173] Build(deps): Bump org.dhatim:fastexcel from 0.18.1 to 0.18.2 in /cnf (#2772) * Build(deps): Bump org.dhatim:fastexcel from 0.18.1 to 0.18.2 in /cnf Bumps [org.dhatim:fastexcel](https://github.com/dhatim/fastexcel) from 0.18.1 to 0.18.2. - [Release notes](https://github.com/dhatim/fastexcel/releases) - [Commits](https://github.com/dhatim/fastexcel/compare/0.18.1...0.18.2) --- updated-dependencies: - dependency-name: org.dhatim:fastexcel dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Build(deps): Bump org.dhatim:fastexcel-reader in /cnf Bumps [org.dhatim:fastexcel-reader](https://github.com/dhatim/fastexcel) from 0.18.1 to 0.18.2. - [Release notes](https://github.com/dhatim/fastexcel/releases) - [Commits](https://github.com/dhatim/fastexcel/compare/0.18.1...0.18.2) --- updated-dependencies: - dependency-name: org.dhatim:fastexcel-reader dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Update bndrun + dependabot.yml --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- .github/dependabot.yml | 4 ++++ cnf/pom.xml | 4 ++-- io.openems.backend.application/BackendApp.bndrun | 4 ++-- io.openems.edge.application/EdgeApp.bndrun | 4 ++-- io.openems.wrapper/bnd.bnd | 4 ++-- io.openems.wrapper/fastexcel.bnd | 6 +++--- 6 files changed, 15 insertions(+), 11 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index a7dddbfd65c..37fcbfbbc53 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -10,6 +10,10 @@ updates: influxdb: patterns: - "com.influxdb:*" + fastexcel: + patterns: + - "org.dhatim:fastexcel" + - "org.dhatim:fastexcel-reader" - package-ecosystem: npm directory: "/ui" diff --git a/cnf/pom.xml b/cnf/pom.xml index fe40c659af6..56115404f1b 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -260,12 +260,12 @@ org.dhatim fastexcel - 0.18.1 + 0.18.2 org.dhatim fastexcel-reader - 0.18.1 + 0.18.2 diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index 923ac4c24c1..8edfd8287e6 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -101,8 +101,8 @@ io.openems.wrapper.retrofit-converter-scalars;version=snapshot,\ io.openems.wrapper.retrofit2;version=snapshot,\ io.reactivex.rxjava3.rxjava;version='[3.1.9,3.1.10)',\ - org.apache.commons.commons-codec;version='[1.17.0,1.17.1)',\ - org.apache.commons.commons-compress;version='[1.26.2,1.26.3)',\ + org.apache.commons.commons-codec;version='[1.17.1,1.17.2)',\ + org.apache.commons.commons-compress;version='[1.27.1,1.27.2)',\ org.apache.commons.commons-csv;version='[1.11.0,1.11.1)',\ org.apache.commons.commons-io;version='[2.16.1,2.16.2)',\ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index c621ec4d944..1e489ec3546 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -396,8 +396,8 @@ io.reactivex.rxjava3.rxjava;version='[3.1.9,3.1.10)',\ javax.jmdns;version='[3.4.1,3.4.2)',\ javax.xml.soap-api;version='[1.4.0,1.4.1)',\ - org.apache.commons.commons-codec;version='[1.17.0,1.17.1)',\ - org.apache.commons.commons-compress;version='[1.26.2,1.26.3)',\ + org.apache.commons.commons-codec;version='[1.17.1,1.17.2)',\ + org.apache.commons.commons-compress;version='[1.27.1,1.27.2)',\ org.apache.commons.commons-csv;version='[1.11.0,1.11.1)',\ org.apache.commons.commons-io;version='[2.16.1,2.16.2)',\ org.apache.commons.math3;version='[3.6.1,3.6.2)',\ diff --git a/io.openems.wrapper/bnd.bnd b/io.openems.wrapper/bnd.bnd index 8bed7415c14..250390423e2 100644 --- a/io.openems.wrapper/bnd.bnd +++ b/io.openems.wrapper/bnd.bnd @@ -24,7 +24,7 @@ Bundle-Description: This wraps external java libraries that do not have OSGi hea com.google.gson;version='2.10.1',\ de.bytefish:pgbulkinsert;version='8.1.4',\ fr.turri:aXMLRPC;version='1.13.0',\ - org.dhatim:fastexcel;version='0.18.1',\ - org.dhatim:fastexcel-reader;version='0.18.1',\ + org.dhatim:fastexcel;version='0.18.2',\ + org.dhatim:fastexcel-reader;version='0.18.2',\ org.eclipse.paho.mqttv5.client;version='1.2.5',\ org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm;version='1.7.3',\ diff --git a/io.openems.wrapper/fastexcel.bnd b/io.openems.wrapper/fastexcel.bnd index e3fa142345c..5e05cab91ae 100644 --- a/io.openems.wrapper/fastexcel.bnd +++ b/io.openems.wrapper/fastexcel.bnd @@ -1,11 +1,11 @@ Bundle-Name: fastexcel Bundle-DocURL: https://github.com/dhatim/fastexcel Bundle-License: https://opensource.org/licenses/Apache-2.0 -Bundle-Version: 0.18.1 +Bundle-Version: 0.18.2 Include-Resource: \ - @fastexcel-0.18.1.jar,\ - @fastexcel-reader-0.18.1.jar,\ + @fastexcel-0.18.2.jar,\ + @fastexcel-reader-0.18.2.jar,\ -dsannotations: * From aeb561e9829a9bd6b38be4a60b75b38e33685e08 Mon Sep 17 00:00:00 2001 From: "Kai J." Date: Tue, 3 Sep 2024 14:45:13 +0200 Subject: [PATCH 130/173] Contribution Guidelines & Code of Conduct (#2780) Add: - .github/CONTRIBUTING.md - .github/CODE_OF_CONDUCT.md Update: - .github/ISSUE_TEMPLATE --- .github/CODE_OF_CONDUCT.md | 133 +++++++++++++++++++++ .github/CONTRIBUTING.md | 52 ++++++++ .github/ISSUE_TEMPLATE.md | 14 --- .github/ISSUE_TEMPLATE/bug-report.yml | 38 ++++++ .github/ISSUE_TEMPLATE/config.yml | 8 ++ .github/ISSUE_TEMPLATE/feature-request.yml | 29 +++++ .github/ISSUE_TEMPLATE/hacktober.yml | 70 +++++++++++ README.md | 1 + 8 files changed, 331 insertions(+), 14 deletions(-) create mode 100644 .github/CODE_OF_CONDUCT.md create mode 100644 .github/CONTRIBUTING.md delete mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/ISSUE_TEMPLATE/bug-report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/feature-request.yml create mode 100644 .github/ISSUE_TEMPLATE/hacktober.yml diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md new file mode 100644 index 00000000000..c56eb39bb9e --- /dev/null +++ b/.github/CODE_OF_CONDUCT.md @@ -0,0 +1,133 @@ + +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official email address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at office@openems.io. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations + diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 00000000000..16b23745dbb --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,52 @@ +# Contributing + +- [📜 Contributor License Agreement](#-contributor-license-agreement) +- [🤝 Contributor Code of Conduct](#-contributor-code-of-conduct) +- [🪲 Bug Reports, Issues and Questions](#-bug-reports-issues-and-questions) +- [💡 Feature Requests](#-feature-requests) +- [🖌️ Coding Style](#️-coding-style) +- [📁 Documentation](#-documentation) + +## 📜 Contributor License Agreement + +By contributing, you agree to the Licenses of this repository: + +- OpenEMS Edge und Backend + + [Eclipse Public License version 2.0](../LICENSE-EPL-2.0) + +- OpenEMS UI + + [GNU Affero General Public License version 3](../LICENSE-AGPL-3.0) + +## 🤝 Contributor Code of Conduct + +By contributing, you agree to respect the [Code of Conduct](CODE_OF_CONDUCT.md) of this repository. + +## 🪲 Bug Reports, Issues and Questions + +A great way to contribute to the project is to send a detailed report when you encounter an issue. We always appreciate a well-written, thorough bug report, and will thank you for it! + +To maintain clear and organized communication, all discussions should take place in the [OpenEMS Community forum](https://community.openems.io/). This helps keep everything together and ensures that conversations are streamlined and accessible to all contributors. + +⚠️ *Please refrain from opening empty pull requests solely for the purpose of discussing ideas. Instead, utilize the forum to share and refine your concepts before submitting any code changes.* + +## 💡 Feature Requests + +Similar to issue reports, feature requests should be submitted to the [OpenEMS Community forum](https://community.openems.io/) for discussion. This helps ensure that all ideas are properly reviewed and discussed by the community. + +When submitting a feature request, please be clear about the intended outcome and how it would relate to existing features. Providing detailed information helps in evaluating the request more effectively. + +⚠️ *Additionally, avoid submitting duplicate feature requests. Before posting, search for existing requests, and if you find a similar or identical one, please join that discussion instead of creating a new thread.* + +## 🖌️ Coding Style + +We welcome pull-requests! While we will consider all submissions, we cannot promise that every request will be accepted. + +To increase your changes of a merged pull-requests and help us review your code, please follow our [coding guidelines](https://openems.github.io/openems.io/openems/latest/contribute/coding-guidelines.html). + +## 📁 Documentation + +The documentation site for OpenEMS is hosted on [https://openems.github.io/openems.io/openems/latest](https://openems.github.io/openems.io/openems/latest). We greatly appreciate contributions that improve the quality and clarity of our documentation. + +If you would like to contribute by updating or adding a page, please refer to our [Contribute/Documentation](https://openems.github.io/openems.io/openems/latest/contribute/documentation.html) guide for detailed instructions on how to contribute effectively to the OpenEMS documentation. diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index e81592e5d45..00000000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,14 +0,0 @@ - -### Bug Report or Feature Request (mark with an `x`) -``` -- [ ] bug report -> please search issues before submitting -- [ ] feature request -``` - -### Bug description or desired functionality. - diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml new file mode 100644 index 00000000000..27690e4ce33 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -0,0 +1,38 @@ +name: Bug Report +description: Found something you weren't expecting? Report it here! +labels: ["type/bug"] +body: + - type: markdown + attributes: + value: | + 1. Please speak English, this is the language all maintainers can speak and write. + 2. Please ask questions or configuration/deploy problems on our [Community forum](https://community.openems.io/). + 3. Make sure you are using the latest release and + take a moment to check that your issue hasn't been reported before. + 4. It's really important to provide pertinent details and logs. + - type: textarea + id: description + attributes: + label: Description + description: | + Please provide a description of your issue here. + validations: + required: true + - type: textarea + id: screenshots + attributes: + label: Screenshots + description: Please provide one or more screenshots, if feasible. + - type: input + id: os-ver + attributes: + label: Operating System + description: The operating system you are running on. + - type: textarea + id: reproduce-info + attributes: + label: How to reproduce the Error? + description: | + Please provide step-by-step instructions on how to reproduce the error. + validations: + required: true \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000000..fe2aaeb311e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: OpenEMS.io + url: https://openems.io/ + about: News and general information are posted here. + - name: OpenEMS Community + url: https://community.openems.io/ + about: Please ask and answer questions here. diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml new file mode 100644 index 00000000000..c27dc9306d0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -0,0 +1,29 @@ +name: Feature Request +description: Got an idea for a feature that OpenEMS is still missing? Submit your idea here! +labels: ["type/enhancement"] +body: + - type: markdown + attributes: + value: | + 1. Please speak English, this is the language all maintainers can speak and write. + 2. Please ask questions or configuration/deploy problems on our [Community forum](https://community.openems.io/). + 3. Please take a moment to check that your feature hasn't already been suggested. + - type: dropdown + id: component + attributes: + label: Component + description: Select the relevant component for this feature request. + options: + - "Edge" + - "UI" + - "Backend" + validations: + required: true + - type: textarea + id: description + attributes: + label: Description + placeholder: | + What is the use case? + validations: + required: true \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/hacktober.yml b/.github/ISSUE_TEMPLATE/hacktober.yml new file mode 100644 index 00000000000..5a0bb4e6a4b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/hacktober.yml @@ -0,0 +1,70 @@ +name: Hacktoberfest +description: Perfect contribution for Hacktoberfest +labels: ["hacktoberfest"] +body: + - type: markdown + attributes: + value: | + 1. Please speak English, this is the language all maintainers can speak and write. + - type: dropdown + id: type + attributes: + label: Contribution Type + description: Select the relevant Contribution type. + options: + - "Feature" + - "Bug Fix" + - "Documentation" + validations: + required: true + - type: dropdown + id: component + attributes: + label: Component + description: Select the relevant component for this feature request. + options: + - "Edge" + - "UI" + - "Backend" + validations: + required: true + - type: dropdown + id: contributor-level + attributes: + label: Contributor Level + description: What OpenEMS knowledge level is required for the task? + options: + - "Newbie" + - "Casual" + - "Expert" + validations: + required: true + - type: textarea + id: description + attributes: + label: Description + placeholder: | + What purpose does the task serve? + validations: + required: true + - type: textarea + id: definition-of-done + attributes: + label: Definition of Done + placeholder: | + What result is expected? + validations: + required: true + - type: textarea + id: difficulties + attributes: + label: Difficulties + placeholder: | + What difficulties may occur? + - type: markdown + attributes: + value: | + --- + - *For questions and suggestions please interact with the [community](https://community.openems.io/).* + - *Do you need help getting started? Then please read the documentation [documentation](https://openems.github.io/openems.io/openems/latest/introduction.html).* + - *Also read our [contribution guidelines](https://github.com/OpenEMS/openems/blob/develop/.github/CONTRIBUTING.md) before submitting code suggestions.* \ No newline at end of file diff --git a/README.md b/README.md index 09bf75eeaac..519047007e3 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ OpenEMS is generally used in combination with external hardware and software com * Open up a [Live-Demo on Gitpod](https://gitpod.io/#https://github.com/OpenEMS/openems) * Follow the [Getting Started](https://openems.github.io/openems.io/openems/latest/gettingstarted.html) guide to setup OpenEMS on your own computer +* Please checkout our [contribution guidelines](CONTRIBUTING.md) before submitting code ## Documentation From b7b3847b2a3297be35aa5cec45f49df0ebe4f0bd Mon Sep 17 00:00:00 2001 From: luzpaz Date: Tue, 3 Sep 2024 09:46:25 -0400 Subject: [PATCH 131/173] Fix various typos (#2730) * Fix various typos Found via `codespell -q 3 -S "./.git,*.pdf,*.po,*.pot,*.ts" -L abl,addess,afe,als,atleast,ba,corrently,datas,ist,plattform,pres,repid,sie` --------- Co-authored-by: Stefan Feilmeier --- doc/modules/ROOT/pages/gettingstarted.adoc | 2 +- doc/modules/ROOT/pages/intellij.adoc | 2 +- io.openems.backend.timedata.aggregatedinflux/readme.adoc | 4 ++-- .../src/io/openems/common/websocket/MyDraft6455.java | 4 ++-- .../edge/battery/fenecon/home/BatteryFeneconHomeImpl.java | 2 +- .../com/dalsemi/onewire/adapter/MulticastListener.java | 2 +- .../src/com/dalsemi/onewire/adapter/RawSendPacket.java | 2 +- .../src/com/dalsemi/onewire/adapter/UAdapterState.java | 2 +- .../src/com/dalsemi/onewire/adapter/USerialAdapter.java | 2 +- .../src/com/dalsemi/onewire/application/file/OWFile.java | 2 +- .../onewire/application/file/OWFileInputStream.java | 2 +- .../onewire/application/file/OWFileOutputStream.java | 2 +- .../dalsemi/onewire/container/MemoryBankEEPROMstatus.java | 2 +- .../dalsemi/onewire/container/MemoryBankScratchSHAEE.java | 2 +- .../com/dalsemi/onewire/container/OneWireContainer33.java | 8 ++++---- .../com/dalsemi/onewire/container/OneWireContainer37.java | 2 +- .../com/dalsemi/onewire/container/OneWireContainer41.java | 2 +- .../ess/fixstateofcharge/ConfigFixStateOfCharge.java | 2 +- .../fixstateofcharge/ConfigPrepareBatteryExtension.java | 2 +- .../ess/fixstateofcharge/api/ConfigProperties.java | 2 +- .../io/openems/edge/controller/ess/limiter14a/Config.java | 2 +- .../src/io/openems/edge/core/appmanager/AppDef.java | 2 +- .../io/openems/edge/core/appmanager/AppManagerImpl.java | 4 ++-- .../edge/core/appmanager/translation_en.properties | 4 ++-- .../src/io/openems/edge/energy/optimizer/Params.java | 2 +- .../src/io/openems/edge/energy/optimizer/ParamsUtils.java | 2 +- .../ess/core/power/solver/nearequal/SolveNearEqual.java | 2 +- .../io/openems/edge/evcs/hypercharger/AvailableState.java | 2 +- io.openems.edge.evcs.cluster/readme.adoc | 2 +- .../edge/evcs/webasto/next/enums/EvseErrorCode.java | 2 +- .../src/io/openems/edge/io/gpio/linuxfs/Gpio.java | 2 +- .../src/com/ed/data/BatteryData.java | 2 +- io.openems.edge.katek.edcom/src/com/ed/data/History.java | 2 +- io.openems.edge.katek.edcom/src/com/ed/edcom/Client.java | 4 ++-- .../io/openems/edge/timedata/rrd4j/Rrd4jReadHandler.java | 2 +- ui/src/app/edge/history/history.component.ts | 4 ++-- 36 files changed, 45 insertions(+), 45 deletions(-) diff --git a/doc/modules/ROOT/pages/gettingstarted.adoc b/doc/modules/ROOT/pages/gettingstarted.adoc index 345571185fe..6ecd5effb4d 100644 --- a/doc/modules/ROOT/pages/gettingstarted.adoc +++ b/doc/modules/ROOT/pages/gettingstarted.adoc @@ -236,7 +236,7 @@ image::openems-ui-login.png[OpenEMS UI Login screen] .OpenEMS UI Energymonitor screen image::openems-ui-edge-overview.png[OpenEMS UI Energymonitor screen] -_Unfortunately the hosted version of OpenEMS UI is currently slightly outdated and incompatble with latest OpenEMS Edge. Follow the xref:ui/setup-ide.adoc[OpenEMS UI guide] to produce the following visualization. The language can be changed in the "burger menu" on top left -> btn:[admin] -> btn:[Allgemeine Einstellungen]._ +_Unfortunately the hosted version of OpenEMS UI is currently slightly outdated and incompatible with latest OpenEMS Edge. Follow the xref:ui/setup-ide.adoc[OpenEMS UI guide] to produce the following visualization. The language can be changed in the "burger menu" on top left -> btn:[admin] -> btn:[Allgemeine Einstellungen]._ .OpenEMS UI Energymonitor screen image::openems-ui-edge-overview2.png[OpenEMS UI Energymonitor screen] diff --git a/doc/modules/ROOT/pages/intellij.adoc b/doc/modules/ROOT/pages/intellij.adoc index de14e909977..e1ff0546267 100644 --- a/doc/modules/ROOT/pages/intellij.adoc +++ b/doc/modules/ROOT/pages/intellij.adoc @@ -36,7 +36,7 @@ image::intellij-import-bnd.png[] + .build.gradle image::intellij-build-gradle.png[] -.. or alternativly make an configuration "edit configuration" +.. or alternatively make an configuration "edit configuration" + .build gradle over configuration image::intellij-add-configuration.png[] diff --git a/io.openems.backend.timedata.aggregatedinflux/readme.adoc b/io.openems.backend.timedata.aggregatedinflux/readme.adoc index 077f29c83f5..b1cd9297cf3 100644 --- a/io.openems.backend.timedata.aggregatedinflux/readme.adoc +++ b/io.openems.backend.timedata.aggregatedinflux/readme.adoc @@ -45,7 +45,7 @@ This list must be adopted to a concrete usecase. It strongly depends on * your strategy to select component-IDs. * the components you are using within OpenEMS. -If you detect some widgets within your OpenEMS-UI which hava empty values, +If you detect some widgets within your OpenEMS-UI which have empty values, it may have to do with an incorrect hardcoded list. ==== @@ -57,7 +57,7 @@ the following configuration may provide a good start setup: *Create database and set retention policy:* -Before starting the OpenEMS backend and after intially setting up the influx servers, +Before starting the OpenEMS backend and after initially setting up the influx servers, you need to create the databases `influx0` and `aggregated0` and some retention policies: diff --git a/io.openems.common/src/io/openems/common/websocket/MyDraft6455.java b/io.openems.common/src/io/openems/common/websocket/MyDraft6455.java index a89e41b5d39..3f549c9cb49 100644 --- a/io.openems.common/src/io/openems/common/websocket/MyDraft6455.java +++ b/io.openems.common/src/io/openems/common/websocket/MyDraft6455.java @@ -920,8 +920,8 @@ public void processFrame(WebSocketImpl webSocketImpl, Framedata frame) throws In } else if (curop == Opcode.BINARY) { this.processFrameBinary(webSocketImpl, frame); } else { - this.log.error("non control or continious frame expected"); - throw new InvalidDataException(CloseFrame.PROTOCOL_ERROR, "non control or continious frame expected"); + this.log.error("non control or continuous frame expected"); + throw new InvalidDataException(CloseFrame.PROTOCOL_ERROR, "non control or continuous frame expected"); } } 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 c941c32eab6..efa68f7d43d 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 @@ -369,7 +369,7 @@ private void detectHardwareType() throws OpenemsException { /** * Get GoodWe hardware version from register value. * - * @param value Register value not formated with SCALE_FACTOR_MINUS_1 + * @param value Register value not formatted with SCALE_FACTOR_MINUS_1 * @return type as {@link GoodweHardwareType} or null */ public static BatteryFeneconHomeHardwareType parseHardwareTypeFromRegisterValue(int value) { diff --git a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/MulticastListener.java b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/MulticastListener.java index 73965b9d85c..1b509c0c834 100644 --- a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/MulticastListener.java +++ b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/MulticastListener.java @@ -34,7 +34,7 @@ import java.net.UnknownHostException; /** - * Generic Mulitcast broadcast listener. Listens for a specific message and, in + * Generic Multicast broadcast listener. Listens for a specific message and, in * response, gives the specified reply. Used by NetAdapterHost for automatic * discovery of host components for the network-based DSPortAdapter. * diff --git a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/RawSendPacket.java b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/RawSendPacket.java index 538990d1130..38877239788 100644 --- a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/RawSendPacket.java +++ b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/RawSendPacket.java @@ -57,7 +57,7 @@ class RawSendPacket { // -------- /** - * Construct and initiailize the raw send packet + * Construct and initialize the raw send packet */ public RawSendPacket() { this.buffer = new StringBuilder(); diff --git a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/UAdapterState.java b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/UAdapterState.java index 4aa06613e03..ed93664f6c5 100644 --- a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/UAdapterState.java +++ b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/UAdapterState.java @@ -148,7 +148,7 @@ class UAdapterState { /** * This is the current 'real' speed that the OneWire is operating at. This is - * used to represent the actual mode that the DS2480 is operting in. For example + * used to represent the actual mode that the DS2480 is operating in. For example * the logical speed might be USPEED_REGULAR but for RF emission reasons we may * put the actual DS2480 in SPEED_FLEX. *

      diff --git a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/USerialAdapter.java b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/USerialAdapter.java index 86062ea2a51..fae5e1ee211 100644 --- a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/USerialAdapter.java +++ b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/USerialAdapter.java @@ -2305,7 +2305,7 @@ private boolean uAdapterPresent() throws OneWireException { /** * Do a master reset on the DS2480. This reduces the baud rate to 9600 and - * peforms a break. A single timing byte is then sent. + * performs a break. A single timing byte is then sent. */ private void uMasterReset() { if (doDebugMessages) { diff --git a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/application/file/OWFile.java b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/application/file/OWFile.java index 2ecb30f573d..577852c3d06 100644 --- a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/application/file/OWFile.java +++ b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/application/file/OWFile.java @@ -145,7 +145,7 @@ *

    17. File/directory names are not case sensitive and will be automatically * changed to all-CAPS *
    18. Only files can have extensions - *
    19. Extensions are numberical in the range 0 to 125 + *
    20. Extensions are numerical in the range 0 to 125 *
    21. Extensions 100 to 125 are special purpose and not yet implemented or * allowed *
    22. Files can have the read-only attribute diff --git a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/application/file/OWFileInputStream.java b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/application/file/OWFileInputStream.java index cd5371b2015..4299e90101d 100644 --- a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/application/file/OWFileInputStream.java +++ b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/application/file/OWFileInputStream.java @@ -51,7 +51,7 @@ *
    23. File/directory names are not case sensitive and will be automatically * changed to all-CAPS *
    24. Only files can have extensions - *
    25. Extensions are numberical in the range 0 to 125 + *
    26. Extensions are numerical in the range 0 to 125 *
    27. Extensions 100 to 125 are special purpose and not yet implemented or * allowed *
    28. Files can have the read-only attribute diff --git a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/application/file/OWFileOutputStream.java b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/application/file/OWFileOutputStream.java index 3f0335b23fa..18ed1be8b88 100644 --- a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/application/file/OWFileOutputStream.java +++ b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/application/file/OWFileOutputStream.java @@ -70,7 +70,7 @@ *
    29. File/directory names are not case sensitive and will be automatically * changed to all-CAPS *
    30. Only files can have extensions - *
    31. Extensions are numberical in the range 0 to 125 + *
    32. Extensions are numerical in the range 0 to 125 *
    33. Extensions 100 to 125 are special purpose and not yet implemented or * allowed *
    34. Files can have the read-only attribute diff --git a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/MemoryBankEEPROMstatus.java b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/MemoryBankEEPROMstatus.java index f015e79cd1f..19d1cea33b7 100644 --- a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/MemoryBankEEPROMstatus.java +++ b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/MemoryBankEEPROMstatus.java @@ -704,7 +704,7 @@ public boolean writeScratchpad(int addr, byte[] out_buf, int offset, int len) } /** - * Copy all 8 bytes of the Sratch Pad to a certain address in memory. + * Copy all 8 bytes of the Scratch Pad to a certain address in memory. * * @param addr the address to copy the data to * @param auth byte[] containing write authorization diff --git a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/MemoryBankScratchSHAEE.java b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/MemoryBankScratchSHAEE.java index 512b7a2ba17..2b57f4167e7 100644 --- a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/MemoryBankScratchSHAEE.java +++ b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/MemoryBankScratchSHAEE.java @@ -467,7 +467,7 @@ public void copyScratchpad(int addr, byte[] scratchpad, int scratchpadOffset, by } /** - * Copy all 8 bytes of the Sratch Pad to a certain address in memory using the + * Copy all 8 bytes of the Scratch Pad to a certain address in memory using the * provided authorization MAC * * @param addr the address to copy the data to diff --git a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/OneWireContainer33.java b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/OneWireContainer33.java index e21c41885f8..541303b50e3 100644 --- a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/OneWireContainer33.java +++ b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/OneWireContainer33.java @@ -822,7 +822,7 @@ private void initmem() { this.memoryPages[0].pageCRC = true; this.memoryPages[0].checked = false; - // Set memory bank varialbes + // Set memory bank variables this.memoryPages[1] = new MemoryBankSHAEE(this, this.mbScratchpad); this.memoryPages[1].bankDescription = "Page One with EPROM mode and write protection."; this.memoryPages[1].generalPurposeMemory = true; @@ -836,7 +836,7 @@ private void initmem() { this.memoryPages[1].pageCRC = true; this.memoryPages[1].checked = false; - // Set memory bank varialbes + // Set memory bank variables this.memoryPages[2] = new MemoryBankSHAEE(this, this.mbScratchpad); this.memoryPages[2].bankDescription = "Page Two and Three with write protection."; this.memoryPages[2].generalPurposeMemory = true; @@ -1110,7 +1110,7 @@ public void readScratchpad(byte[] scratchpad, int offset, byte[] extraInfo) } /** - * Copy all 8 bytes of the Sratch Pad to a certain page and offset in memory. + * Copy all 8 bytes of the Scratch Pad to a certain page and offset in memory. * * @param targetPage the page to copy the data to * @param targetPageOffset the offset into the page to copy to @@ -1129,7 +1129,7 @@ public boolean copyScratchpad(int targetPage, int targetPageOffset, byte[] copy_ } /** - * Copy all 8 bytes of the Sratch Pad to a certain page and offset in memory. + * Copy all 8 bytes of the Scratch Pad to a certain page and offset in memory. * * The container secret must be set so that the container can produce the * correct MAC. diff --git a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/OneWireContainer37.java b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/OneWireContainer37.java index 693c0b021a0..26bbe4770ae 100644 --- a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/OneWireContainer37.java +++ b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/OneWireContainer37.java @@ -870,7 +870,7 @@ public boolean verifyPassword(byte[] password, int offset, int type) throws OneW // ***************************************************************************** // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Private initilizers +// Private initializers // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // ***************************************************************************** diff --git a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/OneWireContainer41.java b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/OneWireContainer41.java index 9267ff60c99..4c92bd471cd 100644 --- a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/OneWireContainer41.java +++ b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/OneWireContainer41.java @@ -4454,7 +4454,7 @@ private void setDate(int timeReg, int year, int month, int day, byte[] state) { // ***************************************************************************** // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Private initilizers +// Private initializers // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // ***************************************************************************** diff --git a/io.openems.edge.controller.ess.fixstateofcharge/src/io/openems/edge/controller/ess/fixstateofcharge/ConfigFixStateOfCharge.java b/io.openems.edge.controller.ess.fixstateofcharge/src/io/openems/edge/controller/ess/fixstateofcharge/ConfigFixStateOfCharge.java index 18d14258634..386c51b0d9d 100644 --- a/io.openems.edge.controller.ess.fixstateofcharge/src/io/openems/edge/controller/ess/fixstateofcharge/ConfigFixStateOfCharge.java +++ b/io.openems.edge.controller.ess.fixstateofcharge/src/io/openems/edge/controller/ess/fixstateofcharge/ConfigFixStateOfCharge.java @@ -43,7 +43,7 @@ @AttributeDefinition(name = "Terminate time buffer in min", description = "Terminate itself after this time buffer. If zero is given, it will terminate instantly.") int terminationBuffer() default 0; - @AttributeDefinition(name = "Terminates itself after separate conditon", description = "Terminate itself after separate end condition given by the property endCondition.") + @AttributeDefinition(name = "Terminates itself after separate condition", description = "Terminate itself after separate end condition given by the property endCondition.") boolean conditionalTermination() default false; @AttributeDefinition(name = "Condition for termination", description = "Terminates itself if the conditionalTermination is true and this end condition was fulfilled.") diff --git a/io.openems.edge.controller.ess.fixstateofcharge/src/io/openems/edge/controller/ess/fixstateofcharge/ConfigPrepareBatteryExtension.java b/io.openems.edge.controller.ess.fixstateofcharge/src/io/openems/edge/controller/ess/fixstateofcharge/ConfigPrepareBatteryExtension.java index 3df7ef6eb6c..fe9358fea52 100644 --- a/io.openems.edge.controller.ess.fixstateofcharge/src/io/openems/edge/controller/ess/fixstateofcharge/ConfigPrepareBatteryExtension.java +++ b/io.openems.edge.controller.ess.fixstateofcharge/src/io/openems/edge/controller/ess/fixstateofcharge/ConfigPrepareBatteryExtension.java @@ -43,7 +43,7 @@ @AttributeDefinition(name = "Terminate time buffer in min", description = "Terminate itself after this time buffer. If zero is given, it will terminate instantly.") int terminationBuffer() default 120; - @AttributeDefinition(name = "Terminates itself after separate conditon", description = "Terminate itself after separate end condition given by the property endCondition.") + @AttributeDefinition(name = "Terminates itself after separate condition", description = "Terminate itself after separate end condition given by the property endCondition.") boolean conditionalTermination() default true; @AttributeDefinition(name = "Condition for termination", description = "Terminates itself if the conditionalTermination is true and this end condition was fulfilled.") diff --git a/io.openems.edge.controller.ess.fixstateofcharge/src/io/openems/edge/controller/ess/fixstateofcharge/api/ConfigProperties.java b/io.openems.edge.controller.ess.fixstateofcharge/src/io/openems/edge/controller/ess/fixstateofcharge/api/ConfigProperties.java index b3ce96e3939..8b92801164d 100644 --- a/io.openems.edge.controller.ess.fixstateofcharge/src/io/openems/edge/controller/ess/fixstateofcharge/api/ConfigProperties.java +++ b/io.openems.edge.controller.ess.fixstateofcharge/src/io/openems/edge/controller/ess/fixstateofcharge/api/ConfigProperties.java @@ -23,7 +23,7 @@ public class ConfigProperties { // Terminate time buffer in min private final int terminationBuffer; - // Terminates itself after separate conditon + // Terminates itself after separate condition private final boolean conditionalTermination; // Condition for termination diff --git a/io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/Config.java b/io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/Config.java index 6a7c1da734c..69f598db15b 100644 --- a/io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/Config.java +++ b/io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/Config.java @@ -20,7 +20,7 @@ @AttributeDefinition(name = "Ess-ID", description = "ID of Ess.") String ess_id() default "ess0"; - @AttributeDefinition(name = "Input Channel", description = "When receiveing a signal, this channel triggers the execution of the limitation.") + @AttributeDefinition(name = "Input Channel", description = "When receiving a signal, this channel triggers the execution of the limitation.") String inputChannelAddress(); String webconsole_configurationFactory_nameHint() default "Controller Ess Limiter §14a [{id}]"; diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppDef.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppDef.java index 806e0c79a63..777c07abda9 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppDef.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppDef.java @@ -32,7 +32,7 @@ * * @param the type of the app * @param the type of the property - * @param the type of the paramters + * @param the type of the parameters */ public class AppDef getInstantiatedApps() { /** * formats the given apps into a JSON array string. * - * @param apps that should be formated - * @return formated apps string + * @param apps that should be formatted + * @return formatted apps string */ private static String getJsonAppsString(List apps) { return JsonUtils diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties index 3e1bbf49ec2..03cade10cfb 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties @@ -405,7 +405,7 @@ App.TimeOfUseTariff.Tibber.accessToken.label = Token App.TimeOfUseTariff.Tibber.accessToken.description = To link to your Tibber account you need a personal access token. You can create this under "developer.tibber.com/settings/access-token". App.TimeOfUseTariff.Tibber.filterForHome.label = Filter for Home App.TimeOfUseTariff.Tibber.filterForHome.description = For multiple 'Homes', add either an ID (format UUID) or 'appNickname' for unambiguous identification -App.TimeOfUseTariff.Tibber.multipleHomesCheck.label = Do you have more than one contract connected toyour Tibber account? +App.TimeOfUseTariff.Tibber.multipleHomesCheck.label = Do you have more than one contract connected to your Tibber account? # PvSelfConsumption App.PvSelfConsumption.GridOptimizedCharge.Name = Grid-optimized charge @@ -442,5 +442,5 @@ App.Ess.FixStateOfCharge.targetTime.label = Target time [YYYY-MM-DDTHH:mm:ssTZD App.Ess.FixStateOfCharge.targetTimeBuffer.label = Target time buffer App.Ess.FixStateOfCharge.selfTermination.label = Terminates itself at the end App.Ess.FixStateOfCharge.terminationBuffer.label = Terminate time buffer in min -App.Ess.FixStateOfCharge.conditionalTermination.label = Terminates itself after separate conditon +App.Ess.FixStateOfCharge.conditionalTermination.label = Terminates itself after separate condition App.Ess.FixStateOfCharge.isRunning.label = Controller active? diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Params.java b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Params.java index b13de0b8546..f49fe773eb9 100644 --- a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Params.java +++ b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Params.java @@ -23,7 +23,7 @@ public record Params(// int essTotalEnergy, // /** ESS Energy below a configured Minimum-SoC [Wh] */ int essMinSocEnergy, // - /** ESS Energy below a configured Maximium-SoC [Wh] */ + /** ESS Energy below a configured Maximum-SoC [Wh] */ int essMaxSocEnergy, // /** ESS Initially Available Energy (SoC in [Wh]) */ int essInitialEnergy, // diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/ParamsUtils.java b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/ParamsUtils.java index f350cf2ab44..cd1e73e75ec 100644 --- a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/ParamsUtils.java +++ b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/ParamsUtils.java @@ -32,7 +32,7 @@ private ParamsUtils() { * predicted consumption energy that cannot be supplied from production. * * @param essMinSocEnergy ESS energy below a configured minimum SoC [Wh] - * @param essMaxSocEnergy ESS energy below a configured maximium SoC [Wh] + * @param essMaxSocEnergy ESS energy below a configured maximum SoC [Wh] * @param productions Production predictions per period * @param consumptions Consumption predictions per period * @param prices Prices per period diff --git a/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/solver/nearequal/SolveNearEqual.java b/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/solver/nearequal/SolveNearEqual.java index 093dc19fab8..19e01b3e06a 100644 --- a/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/solver/nearequal/SolveNearEqual.java +++ b/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/solver/nearequal/SolveNearEqual.java @@ -30,7 +30,7 @@ public class SolveNearEqual { */ public PointValuePair solve(int totalVariables) { - // If the SetPower is greater than Sum of inidividual upper bound, then return + // If the SetPower is greater than Sum of individual upper bound, then return // the upper bound if (this.powerSetValue > Arrays.stream(this.upperBound).sum()) { return new PointValuePair(this.upperBound, 0.0); diff --git a/io.openems.edge.evcs.alpitronic.hypercharger/src/io/openems/edge/evcs/hypercharger/AvailableState.java b/io.openems.edge.evcs.alpitronic.hypercharger/src/io/openems/edge/evcs/hypercharger/AvailableState.java index 47a5baf3168..9ba99066d73 100644 --- a/io.openems.edge.evcs.alpitronic.hypercharger/src/io/openems/edge/evcs/hypercharger/AvailableState.java +++ b/io.openems.edge.evcs.alpitronic.hypercharger/src/io/openems/edge/evcs/hypercharger/AvailableState.java @@ -14,7 +14,7 @@ public enum AvailableState implements OptionsEnum { SUSPENDED_EV(4, "Suspended electric vehicle"), // SUSPENDED_EV_SE(5, "Suspended electric vehicle se"), // FINISHING(6, "Finishing"), // - RESERVED(7, "Reseved"), // + RESERVED(7, "Reserved"), // UNAVAILABLE(8, "Unavailable"), // UNAVAILABLE_FW_UPDATE(9, "Unavailable firmware update"), // FAULTED(10, "Faulted"), // diff --git a/io.openems.edge.evcs.cluster/readme.adoc b/io.openems.edge.evcs.cluster/readme.adoc index 81558b7e2e4..fcd9b961ce4 100644 --- a/io.openems.edge.evcs.cluster/readme.adoc +++ b/io.openems.edge.evcs.cluster/readme.adoc @@ -1,6 +1,6 @@ = EVCS Cluster -Distributes the charging power (Depending on the implementation) to the priorized charging stations. +Distributes the charging power (Depending on the implementation) to the prioritized charging stations. The implementations calculate the maximum power that can be used by all charging stations. Possible Cluster implementations: diff --git a/io.openems.edge.evcs.webasto.next/src/io/openems/edge/evcs/webasto/next/enums/EvseErrorCode.java b/io.openems.edge.evcs.webasto.next/src/io/openems/edge/evcs/webasto/next/enums/EvseErrorCode.java index b8656c5abd1..7bf947b82f8 100644 --- a/io.openems.edge.evcs.webasto.next/src/io/openems/edge/evcs/webasto/next/enums/EvseErrorCode.java +++ b/io.openems.edge.evcs.webasto.next/src/io/openems/edge/evcs/webasto/next/enums/EvseErrorCode.java @@ -10,7 +10,7 @@ public enum EvseErrorCode implements OptionsEnum { EV_COMMUNICATION_ERROR(3, "EV communication error"), // OVER_VOLTAGE(4, "Over Voltage"), // UNDER_VOLTAGE(5, "Under Voltage"), // - OVER_CURRENT_FALIURE(6, "Over current faliure"), // + OVER_CURRENT_FAILURE(6, "Over current failure"), // OTHER_ERROR(7, "Other error"), // GROUND_FAILURE(8, "Ground failure"), // RCD_MODULE_ERROR(9, "Error RCD modulel"), // diff --git a/io.openems.edge.io.gpio/src/io/openems/edge/io/gpio/linuxfs/Gpio.java b/io.openems.edge.io.gpio/src/io/openems/edge/io/gpio/linuxfs/Gpio.java index 7391d7c4a91..4f9f500d030 100644 --- a/io.openems.edge.io.gpio/src/io/openems/edge/io/gpio/linuxfs/Gpio.java +++ b/io.openems.edge.io.gpio/src/io/openems/edge/io/gpio/linuxfs/Gpio.java @@ -93,7 +93,7 @@ private synchronized void writeFile(String filename, String value) throws Openem } else if (msg.contains("busy")) { throw new OpenemsException("Skipping write to GPIO pin [" + this.pinNumber + "]: device is busy."); } else { - throw new OpenemsException("Unkown error writing GPIO file: " + msg); + throw new OpenemsException("Unknown error writing GPIO file: " + msg); } } } diff --git a/io.openems.edge.katek.edcom/src/com/ed/data/BatteryData.java b/io.openems.edge.katek.edcom/src/com/ed/data/BatteryData.java index 7760611ec65..c08f72d189b 100644 --- a/io.openems.edge.katek.edcom/src/com/ed/data/BatteryData.java +++ b/io.openems.edge.katek.edcom/src/com/ed/data/BatteryData.java @@ -69,7 +69,7 @@ public final class BatteryData implements DataSet { public final DspVar bms_u_cell_max_total; /** - * Battery mininum cell temperature [°C] + * Battery minimum cell temperature [°C] */ public final DspVar bms_Tmin_total; diff --git a/io.openems.edge.katek.edcom/src/com/ed/data/History.java b/io.openems.edge.katek.edcom/src/com/ed/data/History.java index 47beb589bef..596a56ecf33 100644 --- a/io.openems.edge.katek.edcom/src/com/ed/data/History.java +++ b/io.openems.edge.katek.edcom/src/com/ed/data/History.java @@ -408,7 +408,7 @@ public synchronized SortedMap> getHistoryDay() th *

      * All recorded performance values in per hour of the requested day * sorted by hour in ascending order. The values are stored in arrays of - * lenght 30 and 12. Arrays of length 30 represent 2 minute average + * length 30 and 12. Arrays of length 30 represent 2 minute average * values, arrays of 12 represent 5 minute average values. *

      *

      diff --git a/io.openems.edge.katek.edcom/src/com/ed/edcom/Client.java b/io.openems.edge.katek.edcom/src/com/ed/edcom/Client.java index 4b04490507d..3e39681b187 100644 --- a/io.openems.edge.katek.edcom/src/com/ed/edcom/Client.java +++ b/io.openems.edge.katek.edcom/src/com/ed/edcom/Client.java @@ -196,7 +196,7 @@ public byte getAccessFeedb() { /** * Check if ID is accepted by inverter * - * @return true - ID accepted, false - ID not accpeted. + * @return true - ID accepted, false - ID not accepted. */ public boolean isIdAccepted() { @@ -206,7 +206,7 @@ public boolean isIdAccepted() { /** * Check if user password is accepted by inverter * - * @return true - ID accepted, false - ID not accpeted. + * @return true - ID accepted, false - ID not accepted. */ public boolean isPasswordAccepted() { return this.accessBitTest(2); diff --git a/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/Rrd4jReadHandler.java b/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/Rrd4jReadHandler.java index 7ee00663374..e12637892de 100644 --- a/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/Rrd4jReadHandler.java +++ b/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/Rrd4jReadHandler.java @@ -150,7 +150,7 @@ private static Timeranges getTimerangesOfNotSendData(RrdDb db, long start) throw * @param rrdDbId the id of the rrdb * @param notSendChannel the channel with the timestamps where the data got * not send - * @param lastResendTimestamp the timstamp of the last resend + * @param lastResendTimestamp the timestamp of the last resend * @param debugMode if debugMode is active * @return the {@link Timeranges} * @throws OpenemsNamedException on error diff --git a/ui/src/app/edge/history/history.component.ts b/ui/src/app/edge/history/history.component.ts index 719a287a158..1e3672ca491 100644 --- a/ui/src/app/edge/history/history.component.ts +++ b/ui/src/app/edge/history/history.component.ts @@ -74,11 +74,11 @@ export class HistoryComponent implements OnInit { /* handle grid breakpoints */(window.innerWidth < 768 ? window.innerWidth - 150 : window.innerWidth - 400)); this.socChartHeight = /* minimum size */ Math.max(150, - /* maximium size */ Math.min(200, ref), + /* maximum size */ Math.min(200, ref), ) + "px"; this.energyChartHeight = /* minimum size */ Math.max(300, - /* maximium size */ Math.min(600, ref), + /* maximum size */ Math.min(600, ref), ) + "px"; } From e5160e40d03b01a591bb163cbd77e312f725ce5b Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Tue, 10 Sep 2024 14:12:31 +0200 Subject: [PATCH 132/173] FEMS Backports 2024-09 (#2788) - AppCenter: handle hardware specifics via hardware Apps - AppCenter: App for Phoenix Contact Meter EEM-MB370-24DC - AppCenter: App for PqPlus Meter UMD96 & UMD97 - Channels: allow translatable Channel descriptions - Controller.Api.ModbusTcp.ReadWrite: UI live and historic view - GoodWe: fix StateRegisters - Simulated Predictor - UI: track connection State & add backend not accessible info --------- Co-authored-by: Lukas Rieger <73471197+lukasrgr@users.noreply.github.com> Co-authored-by: Fabian Brandtner <10850256+fabian94533@users.noreply.github.com> Co-authored-by: Johann Kaufmann <165755282+johannk24@users.noreply.github.com> Co-authored-by: Sebastian Asen <47855186+sebastianasen@users.noreply.github.com> Co-authored-by: Michael Grill <59126309+michaelgrill@users.noreply.github.com> Co-authored-by: Stefan Feilmeier <3515268+sfeilmeier@users.noreply.github.com> --- .../common/oem/DummyOpenemsEdgeOem.java | 12 + .../io/openems/edge/common/channel/Doc.java | 19 +- .../common/channel/internal/AbstractDoc.java | 56 +- .../common/test/DummyComponentContext.java | 12 +- .../common/test/DummyComponentInstance.java | 59 + .../channel/ChannelTranslationTest.java | 51 + .../common/channel/translation_de.properties | 1 + .../common/channel/translation_en.properties | 2 + .../edge/controller/api/common/ApiWorker.java | 29 +- .../edge/controller/api/common/Status.java | 37 + .../controller/api/common/WriteObject.java | 7 + .../edge/controller/api/common/WritePojo.java | 5 + .../api/modbus/AbstractModbusTcpApi.java | 145 ++- .../controller/api/modbus/ModbusTcpApi.java | 2 +- .../ControllerApiModbusTcpReadOnlyImpl.java | 24 +- .../api/modbus/readwrite/Config.java | 7 + .../ControllerApiModbusTcpReadWrite.java | 47 + .../ControllerApiModbusTcpReadWriteImpl.java | 159 ++- ...ntrollerApiModbusTcpReadWriteImplTest.java | 21 +- .../api/modbus/readwrite/MyConfig.java | 27 + .../edge/app/common/props/RelayProps.java | 21 +- .../io/openems/edge/app/ess/Limiter14a.java | 178 +++ .../io/openems/edge/app/hardware/IoGpio.java | 141 +++ .../edge/app/heat/CombinedHeatAndPower.java | 3 +- .../io/openems/edge/app/heat/HeatPump.java | 3 +- .../openems/edge/app/heat/HeatingElement.java | 3 +- .../app/integratedsystem/FeneconHome.java | 34 +- .../app/integratedsystem/FeneconHome20.java | 24 +- .../app/integratedsystem/FeneconHome30.java | 23 +- .../FeneconHomeComponents.java | 60 + .../IntegratedSystemProps.java | 30 + .../commercial/FeneconCommercial92.java | 175 +++ .../FeneconCommercialComponents.java | 130 ++ .../app/loadcontrol/ManualRelayControl.java | 3 +- .../app/loadcontrol/ThresholdControl.java | 3 +- .../openems/edge/app/meter/JanitzaMeter.java | 9 +- .../edge/app/meter/PhoenixContactMeter.java | 169 +++ .../openems/edge/app/meter/PqPlusMeter.java | 279 +++++ .../app/openemshardware/BeagleBoneBlack.java | 121 ++ .../edge/app/openemshardware/Compulab.java | 121 ++ .../edge/app/openemshardware/TechbaseCm3.java | 132 ++ .../edge/app/openemshardware/TechbaseCm4.java | 121 ++ .../app/openemshardware/TechbaseCm4Max.java | 121 ++ .../app/openemshardware/TechbaseCm4s.java | 132 ++ .../app/openemshardware/TechbaseCm4sGen2.java | 137 +++ .../app/timeofusetariff/AwattarHourly.java | 3 +- .../edge/app/timeofusetariff/EntsoE.java | 3 +- .../edge/app/timeofusetariff/GroupeE.java | 3 +- .../edge/app/timeofusetariff/RabotCharge.java | 3 +- .../timeofusetariff/StadtwerkHassfurt.java | 3 +- .../timeofusetariff/StromdaoCorrently.java | 3 +- .../edge/app/timeofusetariff/Tibber.java | 3 +- .../edge/core/appmanager/AppManager.java | 37 +- .../edge/core/appmanager/AppManagerUtil.java | 9 + .../core/appmanager/AppManagerUtilImpl.java | 17 + .../core/appmanager/OpenemsAppCategory.java | 5 + .../appmanager/ResolveOpenemsHardware.java | 189 +++ .../dependency/AppManagerAppHelperImpl.java | 23 + ...edulerByCentralOrderAggregateTaskImpl.java | 1 + .../core/appmanager/translation_de.properties | 60 +- .../core/appmanager/translation_en.properties | 60 +- .../validator/CheckCommercial92.java | 51 + .../core/appmanager/validator/CheckHome.java | 13 +- .../core/appmanager/validator/CheckOr.java | 102 ++ .../validator/CheckableFactory.java | 130 ++ .../core/appmanager/validator/Checkables.java | 26 + .../appmanager/validator/ValidatorConfig.java | 11 + .../appmanager/validator/ValidatorImpl.java | 63 +- .../validator/translation_de.properties | 5 + .../validator/translation_en.properties | 5 + .../ComponentManagerImpl.java | 25 +- .../app/integratedsystem/TestFeneconHome.java | 107 +- .../edge/app/timeofusetariff/TestTibber.java | 27 +- .../AppManagerImpSynchronizationTest.java | 199 --- .../AppManagerImplSynchronizationTest.java | 128 ++ .../core/appmanager/AppManagerImplTest.java | 7 +- .../core/appmanager/AppManagerTestBundle.java | 290 +++-- .../io/openems/edge/core/appmanager/Apps.java | 124 +- .../edge/core/appmanager/DummyValidator.java | 46 +- .../ResolveOpenemsHardwareTest.java | 165 +++ .../core/appmanager/TestTranslations.java | 38 +- .../appmanager/validator/CheckHomeTest.java | 7 +- .../edge/ess/api/ManagedSymmetricEss.java | 4 +- .../edge/goodwe/common/AbstractGoodWe.java | 73 +- .../io/openems/edge/goodwe/common/GoodWe.java | 164 +-- io.openems.edge.simulator/bnd.bnd | 1 + .../openems/edge/simulator/DataContainer.java | 45 +- .../edge/simulator/app/SimulatorAppImpl.java | 6 + .../datasource/api/AbstractCsvDatasource.java | 15 + .../datasource/api/SimulatorDatasource.java | 17 +- .../edge/simulator/predictor/Config.java | 38 + .../predictor/SimulatorPredictor.java | 23 + .../predictor/SimulatorPredictorImpl.java | 102 ++ .../SimulatorDatasourceCsvDirectImplTest.java | 28 +- .../edge/simulator/predictor/MyConfig.java | 80 ++ .../predictor/SimulatorPredictorImplTest.java | 55 + ui/src/app/app-routing.module.ts | 9 +- ui/src/app/app.component.ts | 2 + ui/src/app/app.module.ts | 2 + .../ModbusTcpApi/chart/channels.spec.ts | 1070 +++++++++++++++++ .../Controller/ModbusTcpApi/chart/chart.ts | 89 ++ .../Controller/ModbusTcpApi/flat/flat.html | 5 + .../Controller/ModbusTcpApi/flat/flat.ts | 21 + .../ModbusTcpApi/modbusTcpApi.module.ts | 24 + .../ModbusTcpApi/overview/overview.html | 23 + .../ModbusTcpApi/overview/overview.ts | 7 + .../history/Controller/controller.module.ts | 3 + .../app/edge/history/history.component.html | 11 + ui/src/app/edge/history/history.component.ts | 4 +- .../Controller/ModbusTcpApi/flat/flat.html | 3 + .../live/Controller/ModbusTcpApi/flat/flat.ts | 51 + .../Controller/ModbusTcpApi/modal/modal.html | 23 + .../Controller/ModbusTcpApi/modal/modal.ts | 102 ++ .../ModbusTcpApi/modbusTcpApi.module.ts | 20 + ui/src/app/edge/live/live.component.html | 7 + ui/src/app/edge/live/live.component.ts | 4 +- ui/src/app/edge/live/live.module.ts | 32 +- ui/src/app/index/login.component.ts | 2 + ui/src/app/index/shared/loading-screen.html | 64 +- ui/src/app/index/shared/loading-screen.ts | 39 +- .../chart/abstracthistorychart.html | 2 + .../components/chart/abstracthistorychart.ts | 10 +- .../shared/components/edge/edgeconfig.spec.ts | 27 + .../components/header/header.component.ts | 4 +- .../shared/components/modal/modal.module.ts | 2 + .../app/shared/components/shared/converter.ts | 28 + .../app/shared/components/shared/formatter.ts | 5 + ui/src/app/shared/ngrx-store/states.ts | 110 ++ ui/src/app/shared/pipe/converter/converter.ts | 22 + ui/src/app/shared/pipe/pipe.ts | 3 + ui/src/app/shared/service/pagination.ts | 2 + .../shared/service/previousRouteService.ts | 29 + ui/src/app/shared/service/service.ts | 2 + ui/src/app/shared/service/utils.ts | 1 + ui/src/app/shared/service/websocket.ts | 13 +- ui/src/app/shared/shared.module.ts | 6 +- ui/src/app/shared/shared.ts | 13 + ui/src/app/shared/type/general.ts | 5 + ui/src/app/shared/type/language.ts | 16 +- ui/src/app/shared/type/widget.ts | 4 + ui/src/assets/i18n/de.json | 25 + ui/src/assets/i18n/en.json | 25 + ui/src/themes/openems/scss/variables.scss | 9 +- 143 files changed, 6740 insertions(+), 777 deletions(-) create mode 100644 io.openems.edge.common/src/io/openems/edge/common/test/DummyComponentInstance.java create mode 100644 io.openems.edge.common/test/io/openems/edge/common/channel/ChannelTranslationTest.java create mode 100644 io.openems.edge.common/test/io/openems/edge/common/channel/translation_de.properties create mode 100644 io.openems.edge.common/test/io/openems/edge/common/channel/translation_en.properties create mode 100644 io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/Status.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/ess/Limiter14a.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/hardware/IoGpio.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/integratedsystem/fenecon/commercial/FeneconCommercial92.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/integratedsystem/fenecon/commercial/FeneconCommercialComponents.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/meter/PhoenixContactMeter.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/meter/PqPlusMeter.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/openemshardware/BeagleBoneBlack.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/openemshardware/Compulab.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm3.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4Max.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4s.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4sGen2.java create mode 100644 io.openems.edge.core/src/io/openems/edge/core/appmanager/ResolveOpenemsHardware.java create mode 100644 io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckCommercial92.java create mode 100644 io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckOr.java create mode 100644 io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckableFactory.java delete mode 100644 io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerImpSynchronizationTest.java create mode 100644 io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerImplSynchronizationTest.java create mode 100644 io.openems.edge.core/test/io/openems/edge/core/appmanager/ResolveOpenemsHardwareTest.java create mode 100644 io.openems.edge.simulator/src/io/openems/edge/simulator/predictor/Config.java create mode 100644 io.openems.edge.simulator/src/io/openems/edge/simulator/predictor/SimulatorPredictor.java create mode 100644 io.openems.edge.simulator/src/io/openems/edge/simulator/predictor/SimulatorPredictorImpl.java create mode 100644 io.openems.edge.simulator/test/io/openems/edge/simulator/predictor/MyConfig.java create mode 100644 io.openems.edge.simulator/test/io/openems/edge/simulator/predictor/SimulatorPredictorImplTest.java create mode 100644 ui/src/app/edge/history/Controller/ModbusTcpApi/chart/channels.spec.ts create mode 100644 ui/src/app/edge/history/Controller/ModbusTcpApi/chart/chart.ts create mode 100644 ui/src/app/edge/history/Controller/ModbusTcpApi/flat/flat.html create mode 100644 ui/src/app/edge/history/Controller/ModbusTcpApi/flat/flat.ts create mode 100644 ui/src/app/edge/history/Controller/ModbusTcpApi/modbusTcpApi.module.ts create mode 100644 ui/src/app/edge/history/Controller/ModbusTcpApi/overview/overview.html create mode 100644 ui/src/app/edge/history/Controller/ModbusTcpApi/overview/overview.ts create mode 100644 ui/src/app/edge/live/Controller/ModbusTcpApi/flat/flat.html create mode 100644 ui/src/app/edge/live/Controller/ModbusTcpApi/flat/flat.ts create mode 100644 ui/src/app/edge/live/Controller/ModbusTcpApi/modal/modal.html create mode 100644 ui/src/app/edge/live/Controller/ModbusTcpApi/modal/modal.ts create mode 100644 ui/src/app/edge/live/Controller/ModbusTcpApi/modbusTcpApi.module.ts create mode 100644 ui/src/app/shared/ngrx-store/states.ts create mode 100644 ui/src/app/shared/pipe/converter/converter.ts create mode 100644 ui/src/app/shared/service/previousRouteService.ts diff --git a/io.openems.common/src/io/openems/common/oem/DummyOpenemsEdgeOem.java b/io.openems.common/src/io/openems/common/oem/DummyOpenemsEdgeOem.java index 4b0aabf35b8..cd0a08830ca 100644 --- a/io.openems.common/src/io/openems/common/oem/DummyOpenemsEdgeOem.java +++ b/io.openems.common/src/io/openems/common/oem/DummyOpenemsEdgeOem.java @@ -60,6 +60,8 @@ public SystemUpdateParams getSystemUpdateParams() { .put("App.FENECON.Home", "https://fenecon.de/fenecon-home-10/") // .put("App.FENECON.Home.20", "https://fenecon.de/fenecon-home-20-30/") // .put("App.FENECON.Home.30", "https://fenecon.de/fenecon-home-20-30/") // + .put("App.FENECON.Commercial.92", "https://fenecon.de/fenecon-commercial/") // + .put("App.FENECON.Industrial.L.ILK710", "https://fenecon.de/fenecon-industrial-l/") // .put("App.FENECON.Industrial.S.ISK010", "https://fenecon.de/fenecon-industrial-s/") // .put("App.FENECON.Industrial.S.ISK110", "https://fenecon.de/fenecon-industrial-s/") // .put("App.FENECON.Industrial.S.ISK011", "https://fenecon.de/fenecon-industrial-s/") // @@ -92,8 +94,17 @@ public SystemUpdateParams getSystemUpdateParams() { .put("App.LoadControl.ThresholdControl", "") // .put("App.Meter.Socomec", "") // .put("App.Meter.CarloGavazzi", "") // + .put("App.Meter.PqPlus", "") // .put("App.Meter.Janitza", "") // .put("App.Meter.Discovergy", "")// + .put("App.Meter.PhoenixContact", "")// + .put("App.OpenemsHardware.BeagleBoneBlack", "") // + .put("App.OpenemsHardware.Compulab", "") // + .put("App.OpenemsHardware.CM3", "") // + .put("App.OpenemsHardware.CM4", "") // + .put("App.OpenemsHardware.CM4Max", "") // + .put("App.OpenemsHardware.CM4S", "") // + .put("App.OpenemsHardware.CM4S.Gen2", "") // .put("App.PvInverter.Fronius", "") // .put("App.PvInverter.Kaco", "") // .put("App.PvInverter.Kostal", "") // @@ -105,6 +116,7 @@ public SystemUpdateParams getSystemUpdateParams() { .put("App.Ess.FixStateOfCharge", "") // .put("App.Ess.PowerPlantController", "") // .put("App.Ess.PrepareBatteryExtension", "") // + .put("App.Ess.Limiter14a", "") // .build(); // NOTE: this will certainly get refactored in future, but it's a good start to diff --git a/io.openems.edge.common/src/io/openems/edge/common/channel/Doc.java b/io.openems.edge.common/src/io/openems/edge/common/channel/Doc.java index 29257d4927c..8838ceff5fb 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/channel/Doc.java +++ b/io.openems.edge.common/src/io/openems/edge/common/channel/Doc.java @@ -5,6 +5,7 @@ import io.openems.common.channel.Level; import io.openems.common.channel.PersistencePriority; import io.openems.common.channel.Unit; +import io.openems.common.session.Language; import io.openems.common.types.OpenemsType; import io.openems.common.types.OptionsEnum; import io.openems.edge.common.channel.internal.AbstractDoc; @@ -135,6 +136,23 @@ public static StateChannelDoc of(Level level) { */ public String getText(); + /** + * Gets the translated text. Defaults to empty String. + * + * @param lang language to get translated text + * @return the text + */ + public String getText(Language lang); + + /** + * Sets the translation key. + * + * @param channelKey the translationKey of the channel + * @param clazz the class of the channel parent + * @return myself + */ + public Doc translationKey(Class clazz, String channelKey); + /** * Is the more verbose debug mode activated?. * @@ -153,5 +171,4 @@ public static StateChannelDoc of(Level level) { */ public > C createChannelInstance(OpenemsComponent component, io.openems.edge.common.channel.ChannelId channelId); - } diff --git a/io.openems.edge.common/src/io/openems/edge/common/channel/internal/AbstractDoc.java b/io.openems.edge.common/src/io/openems/edge/common/channel/internal/AbstractDoc.java index 1fe4388ba83..22c752983d4 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/channel/internal/AbstractDoc.java +++ b/io.openems.edge.common/src/io/openems/edge/common/channel/internal/AbstractDoc.java @@ -1,9 +1,12 @@ package io.openems.edge.common.channel.internal; import java.util.List; +import java.util.MissingResourceException; +import java.util.ResourceBundle; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.BiConsumer; import java.util.function.Consumer; +import java.util.function.Function; import io.openems.common.channel.AccessMode; import io.openems.common.channel.PersistencePriority; @@ -11,6 +14,7 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.function.ThrowingBiConsumer; import io.openems.common.function.ThrowingConsumer; +import io.openems.common.session.Language; import io.openems.common.types.OpenemsType; import io.openems.edge.common.channel.Channel; import io.openems.edge.common.channel.ChannelId; @@ -26,6 +30,8 @@ public abstract class AbstractDoc implements Doc { private final OpenemsType type; + private Function getTextFunction; + protected AbstractDoc(OpenemsType type) { this.type = type; } @@ -118,20 +124,56 @@ public T getInitialValue() { return this.initialValue; } - /* - * Description - */ - private String text = ""; - @Override public AbstractDoc text(String text) { - this.text = text; + this.getTextFunction = lang -> { + return text; + }; return this.self(); } @Override public String getText() { - return this.text; + return this.getText(Language.DEFAULT); + } + + @Override + public String getText(Language lang) { + if (this.getTextFunction == null) { + return ""; + } + return this.getTextFunction.apply(lang); + } + + @Override + public AbstractDoc translationKey(Class clazz, String channelKey) { + this.getTextFunction = lang -> { + var bundle = AbstractDoc.getResourceBundle(lang, clazz); + if (bundle != null && bundle.containsKey(channelKey)) { + var textTranslated = bundle.getString(channelKey); + return textTranslated; + } + if (lang != Language.EN) { + // TODO: Use Language.DEFAULT for default language + bundle = AbstractDoc.getResourceBundle(Language.EN, clazz); + if (bundle != null && bundle.containsKey(channelKey)) { + var textTranslated = bundle.getString(channelKey); + return textTranslated; + } + } + + return channelKey; + }; + return this; + } + + private static ResourceBundle getResourceBundle(Language lang, Class clazz) { + try { + return ResourceBundle.getBundle(clazz.getPackageName() + ".translation", lang.getLocal(), + clazz.getModule()); + } catch (MissingResourceException e) { + return null; + } } @Override diff --git a/io.openems.edge.common/src/io/openems/edge/common/test/DummyComponentContext.java b/io.openems.edge.common/src/io/openems/edge/common/test/DummyComponentContext.java index 7779c033683..71007da35d3 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/test/DummyComponentContext.java +++ b/io.openems.edge.common/src/io/openems/edge/common/test/DummyComponentContext.java @@ -33,9 +33,16 @@ public static DummyComponentContext from(AbstractComponentConfig configuration) } private final Dictionary properties; + private final ComponentInstance instance; - public DummyComponentContext(Dictionary properties) { + public DummyComponentContext(Dictionary properties, ComponentInstance instance) { + super(); this.properties = properties; + this.instance = instance; + } + + public DummyComponentContext(Dictionary properties) { + this(properties, null); } public DummyComponentContext() { @@ -85,8 +92,9 @@ public Bundle getUsingBundle() { } @Override + @SuppressWarnings("unchecked") public ComponentInstance getComponentInstance() { - return null; + return (ComponentInstance) this.instance; } @Override diff --git a/io.openems.edge.common/src/io/openems/edge/common/test/DummyComponentInstance.java b/io.openems.edge.common/src/io/openems/edge/common/test/DummyComponentInstance.java new file mode 100644 index 00000000000..16283c87c4e --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/test/DummyComponentInstance.java @@ -0,0 +1,59 @@ +package io.openems.edge.common.test; + +import org.osgi.service.component.ComponentInstance; + +import io.openems.common.utils.FunctionUtils; + +public class DummyComponentInstance implements ComponentInstance { + + public static class DummyComponentInstanceBuilder { + + private Runnable dispose; + private S instance; + + public DummyComponentInstanceBuilder setDispose(Runnable dispose) { + this.dispose = dispose; + return this; + } + + public DummyComponentInstanceBuilder setInstance(S instance) { + this.instance = instance; + return this; + } + + public DummyComponentInstance build() { + return new DummyComponentInstance<>(this.dispose, this.instance); + } + + } + + /** + * Creates a builder for a {@link DummyComponentInstance}. + * + * @param the type of the service + * @return the builder + */ + public static DummyComponentInstanceBuilder create() { + return new DummyComponentInstanceBuilder<>(); + } + + private final Runnable dispose; + private final S instance; + + public DummyComponentInstance(Runnable dispose, S instance) { + super(); + this.dispose = dispose != null ? dispose : FunctionUtils::doNothing; + this.instance = instance; + } + + @Override + public void dispose() { + this.dispose.run(); + } + + @Override + public S getInstance() { + return this.instance; + } + +} \ No newline at end of file diff --git a/io.openems.edge.common/test/io/openems/edge/common/channel/ChannelTranslationTest.java b/io.openems.edge.common/test/io/openems/edge/common/channel/ChannelTranslationTest.java new file mode 100644 index 00000000000..b4bc56abff8 --- /dev/null +++ b/io.openems.edge.common/test/io/openems/edge/common/channel/ChannelTranslationTest.java @@ -0,0 +1,51 @@ +package io.openems.edge.common.channel; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import io.openems.common.channel.Level; +import io.openems.common.session.Language; + +public class ChannelTranslationTest { + + public enum ChannelId implements io.openems.edge.common.channel.ChannelId { + TEST_CHANNEL(Doc.of(Level.WARNING) // + .translationKey(ChannelTranslationTest.class, "Test.TestChannel")), // + ONLY_ENGLISH(Doc.of(Level.INFO) // + .translationKey(ChannelTranslationTest.class, "Test.OnlyEnglish")), // + NO_TRANSLATION(Doc.of(Level.OK) // + .text("No Translation")),; + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } + + @Test + public void testTranslatedGermanChannelText() { + assertEquals("German Test", ChannelTranslationTest.ChannelId.TEST_CHANNEL.doc().getText(Language.DE)); + } + + @Test + public void testTranslatedEnglishChannelText() { + assertEquals("English Test", ChannelTranslationTest.ChannelId.TEST_CHANNEL.doc().getText(Language.EN)); + } + + @Test + public void testOnlyEnglishTranslationTest() { + assertEquals("Only English", ChannelTranslationTest.ChannelId.ONLY_ENGLISH.doc().getText(Language.DE)); + } + + @Test + public void testNoTranslation() { + assertEquals("No Translation", ChannelTranslationTest.ChannelId.NO_TRANSLATION.doc().getText(Language.DE)); + } +} diff --git a/io.openems.edge.common/test/io/openems/edge/common/channel/translation_de.properties b/io.openems.edge.common/test/io/openems/edge/common/channel/translation_de.properties new file mode 100644 index 00000000000..7762fa376ab --- /dev/null +++ b/io.openems.edge.common/test/io/openems/edge/common/channel/translation_de.properties @@ -0,0 +1 @@ +Test.TestChannel = German Test \ No newline at end of file diff --git a/io.openems.edge.common/test/io/openems/edge/common/channel/translation_en.properties b/io.openems.edge.common/test/io/openems/edge/common/channel/translation_en.properties new file mode 100644 index 00000000000..a0778bfbcd4 --- /dev/null +++ b/io.openems.edge.common/test/io/openems/edge/common/channel/translation_en.properties @@ -0,0 +1,2 @@ +Test.TestChannel = English Test +Test.OnlyEnglish = Only English \ No newline at end of file diff --git a/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/ApiWorker.java b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/ApiWorker.java index 7ad767546d7..4e15cd6d476 100644 --- a/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/ApiWorker.java +++ b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/ApiWorker.java @@ -10,6 +10,7 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,10 +21,12 @@ import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; import io.openems.common.jsonrpc.request.SetChannelValueRequest; import io.openems.common.types.OpenemsType; +import io.openems.common.utils.FunctionUtils; import io.openems.common.utils.JsonUtils; import io.openems.edge.common.channel.Channel; import io.openems.edge.common.channel.StringReadChannel; import io.openems.edge.common.channel.WriteChannel; +import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.user.User; @@ -40,7 +43,7 @@ public class ApiWorker { private final Logger log = LoggerFactory.getLogger(ApiWorker.class); - private final OpenemsComponent parent; + private final AbstractOpenemsComponent parent; /** * Debug information about writes to channels is sent to this channel. @@ -58,8 +61,24 @@ public class ApiWorker { private int timeoutSeconds = DEFAULT_TIMEOUT_SECONDS; - public ApiWorker(OpenemsComponent parent) { + /** + * Handles write-only channel overriding. + */ + public record WriteHandler(Consumer, WriteObject>> handleWrites, // + Consumer setOverrideStatus, // + Runnable handleTimeout) { + } + + private WriteHandler writeHandler; + + public ApiWorker(AbstractOpenemsComponent parent) { + this(parent, new WriteHandler(FunctionUtils::doNothing, // + FunctionUtils::doNothing, FunctionUtils::doNothing)); + } + + public ApiWorker(AbstractOpenemsComponent parent, WriteHandler writeHandler) { // this.parent = parent; + this.writeHandler = writeHandler; this.executor = Executors.newSingleThreadScheduledExecutor(); } @@ -150,6 +169,8 @@ private synchronized void resetTimeout() { + entry.getKey().address() + "] after [" + this.timeoutSeconds + "s]"); entry.getValue().notifyTimeout(); } + this.writeHandler.setOverrideStatus.accept(Status.INACTIVE); + this.writeHandler.handleTimeout.run(); this.values.clear(); } }, this.timeoutSeconds, TimeUnit.SECONDS); @@ -186,7 +207,11 @@ public void run() throws OpenemsNamedException { "Set Channel [" + channel.address() + "] to Value [" + writeObject.valueToString() + "]"); writeObject.setNextWriteValue(channel); writeObject.notifySuccess(); + logs.add(channel.address() + ":" + writeObject.valueToString()); + + this.writeHandler.handleWrites.accept(entry); + this.writeHandler.setOverrideStatus.accept(Status.ACTIVE); } catch (OpenemsException e) { OpenemsComponent.logError(this.parent, this.log, "Unable to set Channel [" + channel.address() + "] to Value [" + writeObject.valueToString() + "]: " + e.getMessage()); diff --git a/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/Status.java b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/Status.java new file mode 100644 index 00000000000..14c18bde3e8 --- /dev/null +++ b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/Status.java @@ -0,0 +1,37 @@ +package io.openems.edge.controller.api.common; + +import io.openems.common.types.OptionsEnum; + +public enum Status implements OptionsEnum { + + ACTIVE(0, "Active"), // + + INACTIVE(1, "Inactive"), // + + ERROR(2, "Error"); // + + + private final int value; + private final String name; + + private Status(int value, String name) { + this.value = value; + this.name = name; + } + + @Override + public int getValue() { + return this.value; + } + + @Override + public String getName() { + return this.name; + } + + @Override + public OptionsEnum getUndefined() { + return INACTIVE; + } + +} diff --git a/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/WriteObject.java b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/WriteObject.java index 25d3b9f8297..02c4533867d 100644 --- a/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/WriteObject.java +++ b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/WriteObject.java @@ -118,6 +118,13 @@ public void notifyTimeout() { * @return the value as String */ public abstract String valueToString(); + + /** + * Gets the value of the current object. + * + * @return the value as the corresponding type + */ + public abstract Object value(); /** * Is there a defined value?. diff --git a/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/WritePojo.java b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/WritePojo.java index c6d390c5eed..5a71dc9a94f 100644 --- a/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/WritePojo.java +++ b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/WritePojo.java @@ -29,4 +29,9 @@ public boolean isNull() { return this.value == null; } + @Override + public Object value() { + return this.value; + } + } diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusTcpApi.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusTcpApi.java index d862b6c7177..52e5f67deae 100644 --- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusTcpApi.java +++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusTcpApi.java @@ -1,8 +1,11 @@ package io.openems.edge.controller.api.modbus; +import java.util.Arrays; import java.util.List; +import java.util.Map.Entry; import java.util.TreeMap; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.Consumer; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentContext; @@ -35,6 +38,9 @@ import io.openems.edge.common.modbusslave.ModbusSlaveNatureTable; import io.openems.edge.controller.api.Controller; import io.openems.edge.controller.api.common.ApiWorker; +import io.openems.edge.controller.api.common.ApiWorker.WriteHandler; +import io.openems.edge.controller.api.common.Status; +import io.openems.edge.controller.api.common.WriteObject; import io.openems.edge.controller.api.common.WritePojo; import io.openems.edge.controller.api.modbus.jsonrpc.GetModbusProtocolExportXlsxRequest; import io.openems.edge.controller.api.modbus.jsonrpc.GetModbusProtocolExportXlsxResponse; @@ -48,16 +54,15 @@ public abstract class AbstractModbusTcpApi extends AbstractOpenemsComponent public static final int DEFAULT_PORT = 502; public static final int DEFAULT_MAX_CONCURRENT_CONNECTIONS = 5; - protected final ApiWorker apiWorker = new ApiWorker(this); - - private final Logger log = LoggerFactory.getLogger(AbstractModbusTcpApi.class); - private final MyProcessImage processImage; - private final String implementationName; - /** * Holds the link between Modbus address and ModbusRecord. */ protected final TreeMap records = new TreeMap<>(); + protected final ApiWorker apiWorker = new ApiWorker(this, + new WriteHandler(this.handleWrites(), this::setOverrideStatus, this.handleTimeouts())); + private final Logger log = LoggerFactory.getLogger(AbstractModbusTcpApi.class); + private final MyProcessImage processImage; + private final String implementationName; /** * Holds the link between Modbus start address of a Component and the @@ -66,10 +71,12 @@ public abstract class AbstractModbusTcpApi extends AbstractOpenemsComponent private final TreeMap components = new TreeMap<>(); private ConfigRecord config; + private List invalidComponents = new CopyOnWriteArrayList<>(); protected synchronized void addComponent(OpenemsComponent component) { if (!(component instanceof ModbusSlave)) { this.logError(this.log, "Component [" + component.id() + "] does not implement ModbusSlave"); + this.invalidComponents.add(component); this._setComponentNoModbusApiFault(true); return; } @@ -77,8 +84,20 @@ protected synchronized void addComponent(OpenemsComponent component) { this.updateComponents(); } + protected abstract Consumer, WriteObject>> handleWrites(); + + protected abstract void setOverrideStatus(Status status); + + protected abstract Runnable handleTimeouts(); + protected synchronized void removeComponent(OpenemsComponent component) { - this._components.remove(component); + if (this.invalidComponents.remove(component)) { + if (this.invalidComponents.isEmpty()) { + this._setComponentNoModbusApiFault(false); + } + this._components.remove(component); + return; + } this.updateComponents(); } @@ -92,19 +111,39 @@ public AbstractModbusTcpApi(String implementationName, this.processImage = new MyProcessImage(this); } - protected void activate(ComponentContext context, String id, String alias, boolean enabled, ConfigurationAdmin cm, - ConfigRecord config) throws OpenemsException { - super.activate(context, id, alias, enabled); + protected void activate(ComponentContext context, ConfigurationAdmin cm, ConfigRecord config) + throws OpenemsException { + super.activate(context, config.id(), config.alias(), config.enabled()); + this.handleActivate(config, cm, config.id()); + } - // configuration settings - this.config = config; + protected void modified(ComponentContext context, ConfigurationAdmin cm, ConfigRecord config) + throws OpenemsException { + super.modified(context, config.id(), config.alias(), config.enabled()); // update filter for 'Components'; allow disable components final var filter = ConfigUtils.generateReferenceTargetFilter(this.servicePid(), false, config.componentIds); - if (OpenemsComponent.updateReferenceFilterRaw(cm, this.servicePid(), "Component", filter)) { + OpenemsComponent.updateReferenceFilterRaw(cm, this.servicePid(), "Component", filter); + + // Config (relevant for API) was not modified + if (this.config.equals(config)) { return; } + ModbusSlaveFactory.close(); + + // Activate with new config + this.handleModified(config, cm, config.id()); + } + + private void handleActivate(ConfigRecord config, ConfigurationAdmin cm, String id) { + // configuration settings + this.config = config; + + // update filter for 'Components'; allow disable components + final var filter = ConfigUtils.generateReferenceTargetFilter(this.servicePid(), false, config.componentIds); + OpenemsComponent.updateReferenceFilterRaw(cm, this.servicePid(), "Component", filter); + this.apiWorker.setTimeoutSeconds(config.apiTimeout); if (!this.isEnabled()) { @@ -118,6 +157,24 @@ protected void activate(ComponentContext context, String id, String alias, boole this.updateComponents(); } + private void handleModified(ConfigRecord config, ConfigurationAdmin cm, String id) { + // configuration settings + this.config = config; + + this.apiWorker.setTimeoutSeconds(config.apiTimeout); + + if (!this.isEnabled()) { + // abort if disabled + this.startApiWorker.deactivate(); + return; + } + + // Modify Modbus-Server + this.startApiWorker.modified(id); + + this.updateComponents(); + } + /** * Called by addComponent/removeComponent. Initializes the ModbusRecords, once * all Components are available. Fault-State otherwise. @@ -142,6 +199,7 @@ private synchronized void updateComponents() { @Override protected void deactivate() { + this.startApiWorker.deactivate(); ModbusSlaveFactory.close(); super.deactivate(); @@ -171,10 +229,11 @@ protected void forever() { this.slave = ModbusSlaveFactory.createTCPSlave(port, AbstractModbusTcpApi.this.config.maxConcurrentConnections); this.slave.addProcessImage(UNIT_ID, AbstractModbusTcpApi.this.processImage); - this.slave.open(); - AbstractModbusTcpApi.this.logInfo(this.log, AbstractModbusTcpApi.this.implementationName + if (isEnabled()) { + this.slave.open(); + AbstractModbusTcpApi.this.logInfo(this.log, AbstractModbusTcpApi.this.implementationName + " started on port [" + port + "] with UnitId [" + AbstractModbusTcpApi.UNIT_ID + "]."); - + } } catch (ModbusException e) { ModbusSlaveFactory.close(); AbstractModbusTcpApi.this.logError(this.log, @@ -431,21 +490,45 @@ protected ModbusSlave getPossiblyDisabledComponent(String componentId) { .orElse(null); } - protected static class ConfigRecord { - public final Meta metaComponent; - public final String[] componentIds; - public final int apiTimeout; - public final int port; - public final int maxConcurrentConnections; - - public ConfigRecord(Meta metaComponent, String[] componentIds, int apiTimeout, int port, - int maxConcurrentConnections) { - super(); - this.metaComponent = metaComponent; - this.componentIds = componentIds; - this.apiTimeout = apiTimeout; - this.port = port; - this.maxConcurrentConnections = maxConcurrentConnections; + public static record ConfigRecord(String id, String alias, boolean enabled, Meta metaComponent, + String[] componentIds, int apiTimeout, int port, int maxConcurrentConnections) { + + @Override + public boolean equals(Object other) { + + if (this == other) { + return true; + } + if (other == null) { + return false; + } + if (!(other instanceof ConfigRecord)) { + return false; + } + ConfigRecord config = (ConfigRecord) other; + + if (config.id.equals(this.id) && config.alias.equals(this.alias) // + && config.enabled == this.enabled && config.metaComponent.equals(this.metaComponent) // + && Arrays.equals(config.componentIds, this.componentIds) // + && config.apiTimeout == this.apiTimeout && config.port == this.port // + && config.maxConcurrentConnections == this.maxConcurrentConnections) { + return true; + } + + return false; + } } + + ; + + /** + * Format a given channelAddress to a ChannelId. + * + * @param channel WriteChannel + * @return component_channelId as String + */ + public static String formatChannelName(WriteChannel channel) { + return channel.getComponent().alias() + "_" + channel.channelId().name(); + } } diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/ModbusTcpApi.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/ModbusTcpApi.java index 21d232a7911..da838a2d947 100644 --- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/ModbusTcpApi.java +++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/ModbusTcpApi.java @@ -18,7 +18,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { .debounce(10, Debounce.TRUE_VALUES_IN_A_ROW_TO_SET_TRUE) // .text("A configured Component is not available")), // PROCESS_IMAGE_FAULT(Doc.of(Level.FAULT) // - .debounce(50, Debounce.FALSE_VALUES_IN_A_ROW_TO_SET_FALSE) // + .debounce(10, Debounce.FALSE_VALUES_IN_A_ROW_TO_SET_FALSE) // .text("Invalid Modbus Function call. Only FC3, FC4, FC6 and FC16 are supported")); private final Doc doc; diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/ControllerApiModbusTcpReadOnlyImpl.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/ControllerApiModbusTcpReadOnlyImpl.java index b983cbd8df4..01c6e47638a 100644 --- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/ControllerApiModbusTcpReadOnlyImpl.java +++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/ControllerApiModbusTcpReadOnlyImpl.java @@ -1,5 +1,8 @@ package io.openems.edge.controller.api.modbus.readonly; +import java.util.Map.Entry; +import java.util.function.Consumer; + import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.annotations.Activate; @@ -16,10 +19,13 @@ import io.openems.common.channel.AccessMode; import io.openems.common.exceptions.OpenemsException; +import io.openems.edge.common.channel.WriteChannel; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.jsonapi.ComponentJsonApi; import io.openems.edge.common.meta.Meta; import io.openems.edge.controller.api.Controller; +import io.openems.edge.controller.api.common.Status; +import io.openems.edge.controller.api.common.WriteObject; import io.openems.edge.controller.api.modbus.AbstractModbusTcpApi; import io.openems.edge.controller.api.modbus.ModbusTcpApi; @@ -59,8 +65,8 @@ public ControllerApiModbusTcpReadOnlyImpl() { @Activate private void activate(ComponentContext context, Config config) throws ModbusException, OpenemsException { - super.activate(context, config.id(), config.alias(), config.enabled(), this.cm, - new ConfigRecord(this.metaComponent, config.component_ids(), 0 /* no timeout */, config.port(), + super.activate(context, this.cm, + new ConfigRecord(config.id(), config.alias(), config.enabled(),this.metaComponent, config.component_ids(), 0 /* no timeout */, config.port(), config.maxConcurrentConnections())); } @@ -74,4 +80,18 @@ protected void deactivate() { protected AccessMode getAccessMode() { return AccessMode.READ_ONLY; } + + @Override + protected Consumer, WriteObject>> handleWrites() { + return entry -> { }; + } + + @Override + protected void setOverrideStatus(Status status) { + } + + @Override + protected Runnable handleTimeouts() { + return () -> { }; + } } diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/Config.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/Config.java index 744d65b22bf..0614487de2f 100644 --- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/Config.java +++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/Config.java @@ -25,6 +25,13 @@ @AttributeDefinition(name = "Component-IDs", description = "Components that should be made available via Modbus.") String[] component_ids() default { "_sum" }; + // TODO: Currently unused + @AttributeDefinition(name = "Read Channel-IDs", description = "Contains the channelnames of all read channels.") + String[] readChannels() default { }; + + @AttributeDefinition(name = "Write Channel-IDs", description = "Contains the channelnames of all overridden channels.") + String[] writeChannels(); + @AttributeDefinition(name = "Api-Timeout", description = "Sets the timeout in seconds for updates on Channels set by this Api.") int apiTimeout() default 60; diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWrite.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWrite.java index 78c23fcc525..8a18a1aada2 100644 --- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWrite.java +++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWrite.java @@ -1,13 +1,33 @@ package io.openems.edge.controller.api.modbus.readwrite; +import static io.openems.common.channel.PersistencePriority.HIGH; +import static io.openems.common.channel.Unit.CUMULATED_SECONDS; +import static io.openems.common.types.OpenemsType.LONG; + +import io.openems.common.channel.PersistencePriority; import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.Channel; import io.openems.edge.common.channel.Doc; import io.openems.edge.common.channel.StringReadChannel; +import io.openems.edge.common.channel.value.Value; import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.controller.api.common.Status; public interface ControllerApiModbusTcpReadWrite extends OpenemsComponent { public enum ChannelId implements io.openems.edge.common.channel.ChannelId { + + OVERRIDE_STATUS(Doc.of(Status.values()) // + .persistencePriority(PersistencePriority.HIGH)), // + + CUMULATED_ACTIVE_TIME(Doc.of(LONG)// + .unit(CUMULATED_SECONDS) // + .persistencePriority(HIGH)), // + + CUMULATED_INACTIVE_TIME(Doc.of(LONG)// + .unit(CUMULATED_SECONDS) // + .persistencePriority(HIGH)), // + API_WORKER_LOG(Doc.of(OpenemsType.STRING) // .text("Logs Write-Commands via ApiWorker")); // @@ -32,4 +52,31 @@ public default StringReadChannel getApiWorkerLogChannel() { return this.channel(ChannelId.API_WORKER_LOG); } + /** + * Gets the Channel for {@link ChannelId#OVERRIDE_STATUS}. + * + * @return the Channel + */ + public default Channel getOverrideStatusChannel() { + return this.channel(ChannelId.OVERRIDE_STATUS); + } + + /** + * Gets the Status. See {@link ChannelId#OVERRIDE_STATUS}. + * + * @return the Channel {@link Value} + */ + public default Status getOverrideStatus() { + return this.getOverrideStatusChannel().value().asEnum(); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#OVERRIDE_STATUS} Channel. + * + * @param value the next value + */ + public default void _setOverrideStatus(Status value) { + this.getOverrideStatusChannel().setNextValue(value); + } + } diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImpl.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImpl.java index af51ee0b092..74055d005b1 100644 --- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImpl.java +++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImpl.java @@ -1,27 +1,49 @@ package io.openems.edge.controller.api.modbus.readwrite; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map.Entry; +import java.util.function.Consumer; + +import org.osgi.service.cm.Configuration; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.ConfigurationPolicy; import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Modified; import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.ReferenceCardinality; import org.osgi.service.component.annotations.ReferencePolicy; import org.osgi.service.component.annotations.ReferencePolicyOption; import org.osgi.service.metatype.annotations.Designate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.ghgande.j2mod.modbus.ModbusException; import io.openems.common.channel.AccessMode; +import io.openems.common.channel.PersistencePriority; +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; +import io.openems.common.types.OpenemsType; +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.component.OpenemsComponent; import io.openems.edge.common.jsonapi.ComponentJsonApi; import io.openems.edge.common.meta.Meta; import io.openems.edge.controller.api.Controller; +import io.openems.edge.controller.api.common.Status; +import io.openems.edge.controller.api.common.WriteObject; import io.openems.edge.controller.api.modbus.AbstractModbusTcpApi; import io.openems.edge.controller.api.modbus.ModbusTcpApi; +import io.openems.edge.timedata.api.Timedata; +import io.openems.edge.timedata.api.TimedataProvider; +import io.openems.edge.timedata.api.utils.CalculateActiveTime; @Designate(ocd = Config.class, factory = true) @Component(// @@ -30,7 +52,22 @@ configurationPolicy = ConfigurationPolicy.REQUIRE // ) public class ControllerApiModbusTcpReadWriteImpl extends AbstractModbusTcpApi - implements ControllerApiModbusTcpReadWrite, ModbusTcpApi, Controller, OpenemsComponent, ComponentJsonApi { + implements ControllerApiModbusTcpReadWrite, ModbusTcpApi, Controller, OpenemsComponent, ComponentJsonApi, TimedataProvider { + + private final Logger log = LoggerFactory.getLogger(ControllerApiModbusTcpReadWriteImpl.class); + + private final CalculateActiveTime calculateCumulatedActiveTime = new CalculateActiveTime(this, + ControllerApiModbusTcpReadWrite.ChannelId.CUMULATED_ACTIVE_TIME); + + private final CalculateActiveTime calculateCumulatedInactiveTime = new CalculateActiveTime(this, + ControllerApiModbusTcpReadWrite.ChannelId.CUMULATED_INACTIVE_TIME); + + private List writeChannels; + + private boolean isActive = false; + + @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) + private volatile Timedata timedata = null; @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) private Meta metaComponent = null; @@ -39,7 +76,11 @@ public class ControllerApiModbusTcpReadWriteImpl extends AbstractModbusTcpApi private ConfigurationAdmin cm; @Override - @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MULTIPLE) + @Reference(// + policy = ReferencePolicy.DYNAMIC, // + policyOption = ReferencePolicyOption.GREEDY, // + cardinality = ReferenceCardinality.MULTIPLE // + ) protected void addComponent(OpenemsComponent component) { super.addComponent(component); } @@ -60,9 +101,24 @@ public ControllerApiModbusTcpReadWriteImpl() { @Activate private void activate(ComponentContext context, Config config) throws ModbusException, OpenemsException { - super.activate(context, config.id(), config.alias(), config.enabled(), this.cm, - new ConfigRecord(this.metaComponent, config.component_ids(), config.apiTimeout(), config.port(), - config.maxConcurrentConnections())); + super.activate(context, this.cm, + new ConfigRecord(config.id(), config.alias(), config.enabled(), this.metaComponent, + config.component_ids(), config.apiTimeout(), config.port(), config.maxConcurrentConnections())); + this.applyConfig(config); + this.handleTimeDataChannels(); + } + + @Modified + private void modified(ComponentContext context, Config config) throws OpenemsNamedException { + super.modified(context, this.cm, + new ConfigRecord(config.id(), config.alias(), config.enabled(), this.metaComponent, + config.component_ids(), config.apiTimeout(), config.port(), config.maxConcurrentConnections())); + this.applyConfig(config); + this.handleTimeDataChannels(); + } + + private void applyConfig(Config config) { + this.writeChannels = new ArrayList<>(Arrays.asList(config.writeChannels())); } @Override @@ -70,9 +126,102 @@ private void activate(ComponentContext context, Config config) throws ModbusExce protected void deactivate() { super.deactivate(); } + + @Override + public void run() throws OpenemsNamedException { + this.isActive = false; + super.run(); + + this.calculateCumulatedActiveTime.update(this.isActive); + this.calculateCumulatedInactiveTime.update(!this.isActive); + } @Override protected AccessMode getAccessMode() { return AccessMode.READ_WRITE; } + + /** + * Updating the configuration property to given value. + * + * @param targetProperty Property that should be changed + * @param requiredValue Value that should be set + */ + private void configUpdate(String targetProperty, String requiredValue) { + Configuration c; + try { + var pid = this.servicePid(); + if (pid.isEmpty()) { + this.logInfo(this.log, "PID of " + this.id() + " is Empty"); + return; + } + c = this.cm.getConfiguration(pid, "?"); + var properties = c.getProperties(); + if (!this.writeChannels.contains(requiredValue)) { + this.writeChannels.add(requiredValue); + properties.put(targetProperty, this.writeChannels.toArray(String[]::new)); + c.update(properties); + } + } catch (IOException | SecurityException e) { + this.logError(this.log, "ERROR: " + e.getMessage()); + } + } + + @Override + protected Consumer, WriteObject>> handleWrites() { + return entry -> { + this.isActive = true; + WriteChannel channel = entry.getKey(); + var writeObject = entry.getValue(); + + String channelName = formatChannelName(channel); + var currentChannel = new ChannelIdImpl(channelName, + Doc.of(channel.getType()).persistencePriority(PersistencePriority.HIGH)); + if (!channels().stream().anyMatch(p -> p.channelId().name().equals(currentChannel.name()))) { + addChannel(currentChannel).setNextValue(writeObject.value()); + } else { + channel(currentChannel).setNextValue(writeObject.value()); + } + this.configUpdate("writeChannels", channel(currentChannel).channelId().id()); + }; + } + + @Override + protected void setOverrideStatus(Status status) { + this._setOverrideStatus(status); + } + + @Override + protected Runnable handleTimeouts() { + return () -> { + this.writeChannels.forEach(c -> { + channels().stream().filter(channel -> channel.channelId().id().equals(c)).findFirst() + .ifPresent(channel -> channel.setNextValue(null)); + }); + }; + } + + @Override + public Timedata getTimedata() { + return this.timedata; + } + + /** + * Checks, if timedata channels are already set. + * If not, they will be created and added to current channels. + */ + protected void handleTimeDataChannels() { + var activeTimeChannel = new ChannelIdImpl("CUMULATED_ACTIVE_TIME", // + Doc.of(OpenemsType.DOUBLE).persistencePriority(PersistencePriority.HIGH)); + var inactiveTimeChannel = new ChannelIdImpl("CUMULATED_INACTIVE_TIME", // + Doc.of(OpenemsType.DOUBLE).persistencePriority(PersistencePriority.HIGH)); + + List timeChannels = Arrays.asList(activeTimeChannel, inactiveTimeChannel); + timeChannels.forEach(channel -> { + if (channels().stream().noneMatch(ch -> ch.channelId().id().equals(channel.id()))) { + addChannel(channel); + } + }); + } + } diff --git a/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImplTest.java b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImplTest.java index 5da230c70a8..58ea9ca90c5 100644 --- a/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImplTest.java +++ b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImplTest.java @@ -1,9 +1,11 @@ package io.openems.edge.controller.api.modbus.readwrite; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import org.junit.Test; - import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyConfigurationAdmin; +import io.openems.edge.common.test.DummyCycle; import io.openems.edge.controller.api.modbus.AbstractModbusTcpApi; import io.openems.edge.controller.test.ControllerTest; @@ -26,4 +28,21 @@ public void test() throws Exception { .next(new TestCase()) // ; } + + @Test + public void testTimedataChannels() throws Exception { + var controller = new ControllerApiModbusTcpReadWriteImpl(); // + boolean channelNotFound = controller.channels().stream().noneMatch(// + ch -> ch.channelId().id().equals("CumulatedActiveTime") // + || ch.channelId().id().equals("CumulatedInactiveTime")); // + assertFalse(channelNotFound); + } + + @Test + public void testAddFalseComponents() throws Exception { + var controller = new ControllerApiModbusTcpReadWriteImpl(); // + controller.addComponent(new DummyCycle(1000)); // + controller.getComponentNoModbusApiFaultChannel().nextProcessImage(); // + assertTrue(controller.getComponentNoModbusApiFault().get()); // + } } diff --git a/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/MyConfig.java b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/MyConfig.java index 54489b1473a..5c06b078554 100644 --- a/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/MyConfig.java +++ b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/MyConfig.java @@ -1,7 +1,12 @@ package io.openems.edge.controller.api.modbus.readwrite; +import java.nio.channels.Channels; + import io.openems.common.test.AbstractComponentConfig; +import io.openems.common.types.EdgeConfig.Component.Channel; import io.openems.common.utils.ConfigUtils; +import io.openems.edge.common.channel.ChannelId; +import io.openems.edge.common.channel.ChannelId.ChannelIdImpl; @SuppressWarnings("all") public class MyConfig extends AbstractComponentConfig implements Config { @@ -13,9 +18,21 @@ protected static class Builder { private String[] componentIds; private int maxConcurrentConnections; private int apiTimeout; + private String[] writeChannels = {}; + private String[] readChannels = {}; private Builder() { } + + public Builder setWriteChannels(String... writeChannels) { + this.writeChannels = writeChannels; + return this; + } + + public Builder setReadChannels(String... readChannels) { + this.readChannels = readChannels; + return this; + } public Builder setId(String id) { this.id = id; @@ -98,4 +115,14 @@ public int apiTimeout() { return this.builder.apiTimeout; } + @Override + public String[] readChannels() { + return this.builder.readChannels; + } + + @Override + public String[] writeChannels() { + return this.builder.writeChannels; + } + } \ No newline at end of file diff --git a/io.openems.edge.core/src/io/openems/edge/app/common/props/RelayProps.java b/io.openems.edge.core/src/io/openems/edge/app/common/props/RelayProps.java index 479a34f8fc3..f8275bd4fc8 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/common/props/RelayProps.java +++ b/io.openems.edge.core/src/io/openems/edge/app/common/props/RelayProps.java @@ -21,6 +21,7 @@ import io.openems.common.session.Language; import io.openems.common.utils.JsonUtils; +import io.openems.edge.app.hardware.IoGpio; import io.openems.edge.common.channel.BooleanWriteChannel; import io.openems.edge.core.appmanager.AbstractOpenemsApp; import io.openems.edge.core.appmanager.AppDef; @@ -91,13 +92,19 @@ public static RelayContactInformation createPhaseInformation(// final List preferredRelays // ) { final var relayInfos = util.getAllRelayInfos(ComponentUtil.CORE_COMPONENT_IDS, // - component -> filter.stream().allMatch(t -> t.componentFilter().test(component)), // + component -> filter.stream() // + .map(RelayContactFilter::componentFilter) // + .filter(Objects::nonNull) // + .allMatch(t -> t.test(component)), // component -> filter.stream() // .map(RelayContactFilter::componentAliasMapper) // .filter(Objects::nonNull) // .map(t -> t.apply(component)) // .findAny().orElse(component.alias()), // - (component, channel) -> filter.stream().allMatch(t -> t.channelFilter().test(component, channel)), // + (component, channel) -> filter.stream() // + .map(RelayContactFilter::channelFilter) // + .filter(Objects::nonNull) // + .allMatch(t -> t.test(component, channel)), // (component, channel) -> filter.stream() // .map(RelayContactFilter::channelAliasMapper) // .filter(Objects::nonNull) // @@ -105,6 +112,7 @@ public static RelayContactInformation createPhaseInformation(// .findAny().orElse(channel.address().toString()), // (component, channel) -> filter.stream() // .map(RelayContactFilter::disabledReasons) // + .filter(Objects::nonNull) // .map(t -> t.apply(component, channel)) // .flatMap(Collection::stream) // .toList()); @@ -171,6 +179,15 @@ public static RelayContactFilter feneconHomeFilter(// ); } + /** + * Creates a {@link RelayContactFilter} for {@link IoGpio} components. + * + * @return the {@link RelayContactFilter} + */ + public static RelayContactFilter gpioFilter() { + return new RelayContactFilter(t -> !t.serviceFactoryPid().equals("IO.Gpio"), null, null, null, null); + } + /** * Creates the {@link PreferredRelay} if a Home 20/30 relay board is installed. * diff --git a/io.openems.edge.core/src/io/openems/edge/app/ess/Limiter14a.java b/io.openems.edge.core/src/io/openems/edge/app/ess/Limiter14a.java new file mode 100644 index 00000000000..8856960f7d7 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/ess/Limiter14a.java @@ -0,0 +1,178 @@ +package io.openems.edge.app.ess; + +import static io.openems.edge.app.common.props.CommonProps.alias; +import static java.util.Collections.emptyList; + +import java.util.List; +import java.util.Map; +import java.util.ResourceBundle; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.common.types.EdgeConfig; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.app.common.props.ComponentProps; +import io.openems.edge.app.common.props.RelayProps; +import io.openems.edge.app.common.props.RelayProps.RelayContactInformation; +import io.openems.edge.app.common.props.RelayProps.RelayContactInformationProvider; +import io.openems.edge.app.ess.Limiter14a.Limiter14aBundle; +import io.openems.edge.app.ess.Limiter14a.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter.BundleProvider; +import io.openems.edge.core.appmanager.dependency.DependencyDeclaration; +import io.openems.edge.core.appmanager.dependency.DependencyUtil; +import io.openems.edge.core.appmanager.dependency.Tasks; +import io.openems.edge.core.appmanager.dependency.aggregatetask.SchedulerByCentralOrderConfiguration.SchedulerComponent; + +@Component(name = "App.Ess.Limiter14a") +public class Limiter14a extends AbstractOpenemsAppWithProps + implements OpenemsApp { + + public record Limiter14aBundle(// + ResourceBundle bundle, // + RelayContactInformation relayContactInformation // + ) implements BundleProvider, RelayContactInformationProvider { + + } + + public static enum Property implements Type { + CTRL_ESS_LIMITER_14A_ID(AppDef.componentId("ctrlEssLimiter14a0")), // + + ALIAS(alias()), // + ESS_ID(ComponentProps.pickManagedSymmetricEssId()), // + INPUT_CHANNEL_ADDRESS(RelayProps.relayContactDef(1)), // + ; + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, Limiter14aBundle> getParamter() { + return t -> new Limiter14aBundle(// + createResourceBundle(t.language), // + RelayProps.createPhaseInformation(t.app.componentUtil, 1, emptyList(), emptyList()) // + ); + } + + } + + @Activate + public Limiter14a(// + @Reference ComponentManager componentManager, // + ComponentContext componentContext, // + @Reference ConfigurationAdmin cm, // + @Reference ComponentUtil componentUtil // + ) { + super(componentManager, componentContext, cm, componentUtil); + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.ESS }; + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.SINGLE; + } + + @Override + protected Limiter14a getApp() { + return this; + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + + final var id = this.getId(t, p, Property.CTRL_ESS_LIMITER_14A_ID); + + final var alias = this.getString(p, Property.ALIAS); + final var essId = this.getString(p, Property.ESS_ID); + final var inputAddress = this.getString(p, Property.INPUT_CHANNEL_ADDRESS); + + final var components = List.of(// + new EdgeConfig.Component(id, alias, "Controller.Ess.Limiter14a", // + JsonUtils.buildJsonObject() // + .addProperty("ess.id", essId) // + .addProperty("inputChannelAddress", inputAddress) // + .build())); + + final var componentIdOfRelay = inputAddress.substring(0, inputAddress.indexOf('/')); + final var appIdOfRelay = DependencyUtil.getInstanceIdOfAppWhichHasComponent(this.componentManager, + componentIdOfRelay); + + return AppConfiguration.create() // + .addTask(Tasks.component(components)) // + .addTask(Tasks.schedulerByCentralOrder( + new SchedulerComponent(id, "Controller.Ess.Limiter14a", this.getAppId()))) // + .onlyIf(appIdOfRelay != null, c -> c.addDependency(new DependencyDeclaration("RELAY", // + DependencyDeclaration.CreatePolicy.NEVER, // + DependencyDeclaration.UpdatePolicy.NEVER, // + DependencyDeclaration.DeletePolicy.NEVER, // + DependencyDeclaration.DependencyUpdatePolicy.ALLOW_ALL, // + DependencyDeclaration.DependencyDeletePolicy.NOT_ALLOWED, // + DependencyDeclaration.AppDependencyConfig.create() // + .setSpecificInstanceId(appIdOfRelay) // + .build())))// + .build(); + }; + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create() // + .setCanSee(Role.ADMIN) // + .setCanDelete(Role.ADMIN) // + .build(); + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/hardware/IoGpio.java b/io.openems.edge.core/src/io/openems/edge/app/hardware/IoGpio.java new file mode 100644 index 00000000000..19720a1e148 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/hardware/IoGpio.java @@ -0,0 +1,141 @@ +package io.openems.edge.app.hardware; + +import static io.openems.edge.app.common.props.CommonProps.alias; + +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.common.types.EdgeConfig; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.app.hardware.IoGpio.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter; +import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; +import io.openems.edge.core.appmanager.dependency.Tasks; + +@Component(name = "App.Hardware.IoGpio") +public class IoGpio extends AbstractOpenemsAppWithProps + implements OpenemsApp { + + public enum Property implements Type { + // TODO default value should start at 0 but for integrated systems and hardware + // apps to work properly this one starts at 1 + IO_ID(AppDef.componentId("io1")), // + + ALIAS(alias()), // + ; + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, BundleParameter> getParamter() { + return Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + + } + + @Activate + public IoGpio(// + @Reference ComponentManager componentManager, // + ComponentContext componentContext, // + @Reference ConfigurationAdmin cm, // + @Reference ComponentUtil componentUtil // + ) { + super(componentManager, componentContext, cm, componentUtil); + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .build(); + } + + @Override + public OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.HARDWARE }; + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.SINGLE; + } + + @Override + protected IoGpio getApp() { + return this; + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + final var id = this.getId(t, p, Property.IO_ID); + + final var alias = this.getString(p, Property.ALIAS); + + final var components = List.of(// + new EdgeConfig.Component(id, alias, "IO.Gpio", JsonUtils.buildJsonObject() // + .addProperty("enabled", true) // + .addProperty("gpioPath", "/sys/class") // + .addProperty("hardwareType", "MODBERRY_X500_M40804_WB") // + .build())); + + return AppConfiguration.create() // + .addTask(Tasks.component(components)) // + .build(); + }; + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create() // + .setCanSee(Role.ADMIN) // + .setCanDelete(Role.ADMIN) // + .build(); + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/heat/CombinedHeatAndPower.java b/io.openems.edge.core/src/io/openems/edge/app/heat/CombinedHeatAndPower.java index cf84a43bc4f..3f1ca372b13 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/heat/CombinedHeatAndPower.java +++ b/io.openems.edge.core/src/io/openems/edge/app/heat/CombinedHeatAndPower.java @@ -122,7 +122,8 @@ public Function, CombinedHeatAndPowerPa return new CombinedHeatAndPowerParameter(// createResourceBundle(t.language), // createPhaseInformation(t.app.componentUtil, 1, // - List.of(RelayProps.feneconHomeFilter(t.language, isHomeInstalled, false)), // + List.of(RelayProps.feneconHomeFilter(t.language, isHomeInstalled, false), + RelayProps.gpioFilter()), // List.of(RelayProps.feneconHome2030PreferredRelays(isHomeInstalled, new int[] { 5 }), // PreferredRelay.of(4, new int[] { 1 }), // PreferredRelay.of(8, new int[] { 1 }))) // diff --git a/io.openems.edge.core/src/io/openems/edge/app/heat/HeatPump.java b/io.openems.edge.core/src/io/openems/edge/app/heat/HeatPump.java index 3800b3065c6..1a7c9bcb76b 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/heat/HeatPump.java +++ b/io.openems.edge.core/src/io/openems/edge/app/heat/HeatPump.java @@ -121,7 +121,8 @@ public Function, HeatPumpParameter> getParamter() { return new HeatPumpParameter(// createResourceBundle(t.language), // createPhaseInformation(t.app.componentUtil, 2, // - List.of(RelayProps.feneconHomeFilter(t.language, isHomeInstalled, false)), // + List.of(RelayProps.feneconHomeFilter(t.language, isHomeInstalled, false), + RelayProps.gpioFilter()), // List.of(RelayProps.feneconHome2030PreferredRelays(isHomeInstalled, new int[] { 5, 6 }), // PreferredRelay.of(4, new int[] { 2, 3 }), // PreferredRelay.of(8, new int[] { 2, 3 }))) // diff --git a/io.openems.edge.core/src/io/openems/edge/app/heat/HeatingElement.java b/io.openems.edge.core/src/io/openems/edge/app/heat/HeatingElement.java index d816f514ce9..d483ac7ef6b 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/heat/HeatingElement.java +++ b/io.openems.edge.core/src/io/openems/edge/app/heat/HeatingElement.java @@ -156,7 +156,8 @@ public Function, HeatingElementParameter> get return new HeatingElementParameter(// createResourceBundle(t.language), // createPhaseInformation(t.app.componentUtil, 3, // - List.of(RelayProps.feneconHomeFilter(t.language, isHomeInstalled, true)), // + List.of(RelayProps.feneconHomeFilter(t.language, isHomeInstalled, true), + RelayProps.gpioFilter()), // List.of(RelayProps.feneconHome2030PreferredRelays(isHomeInstalled, new int[] { 1, 2, 3 }), // PreferredRelay.of(4, new int[] { 1, 2, 3 }), // diff --git a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome.java b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome.java index 833c1a2d55c..790bcc230fb 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome.java +++ b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome.java @@ -3,6 +3,7 @@ import static io.openems.edge.app.common.props.CommonProps.alias; import static io.openems.edge.app.common.props.CommonProps.defaultDef; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.batteryInverter; +import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.essLimiter14aToHardware; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.gridOptimizedCharge; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.predictor; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.prepareBatteryExtension; @@ -14,6 +15,7 @@ import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.feedInType; import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.hasAcMeter; import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.hasEmergencyReserve; +import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.hasEssLimiter14a; import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.maxFeedInPower; import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.safetyCountry; import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.shadowManagementDisabled; @@ -54,6 +56,8 @@ import io.openems.edge.core.appmanager.AppConfiguration; import io.openems.edge.core.appmanager.AppDef; import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.AppManagerUtil; +import io.openems.edge.core.appmanager.AppManagerUtilSupplier; import io.openems.edge.core.appmanager.ComponentUtil; import io.openems.edge.core.appmanager.ConfigurationTarget; import io.openems.edge.core.appmanager.OpenemsApp; @@ -118,7 +122,7 @@ */ @Component(name = "App.FENECON.Home") public class FeneconHome extends AbstractOpenemsAppWithProps - implements OpenemsApp { + implements OpenemsApp, AppManagerUtilSupplier { public record FeneconHomeParameter(// ResourceBundle bundle, // @@ -162,7 +166,7 @@ public static enum Property implements Type { return new JsonPrimitive(parameter.defaultValues().feedInSetting()); }))), // - + HAS_ESS_LIMITER_14A(hasEssLimiter14a()), // // External AC PV HAS_AC_METER(AppDef.copyOfGeneric(hasAcMeter(), def -> def // .setDefaultValue((app, property, l, parameter) -> { @@ -248,10 +252,18 @@ public Function, FeneconHomeParameter> getParamt } } + private final AppManagerUtil appManagerUtil; + @Activate - public FeneconHome(@Reference ComponentManager componentManager, ComponentContext context, - @Reference ConfigurationAdmin cm, @Reference ComponentUtil componentUtil) { + public FeneconHome(// + @Reference final ComponentManager componentManager, // + final ComponentContext context, // + @Reference final ConfigurationAdmin cm, // + @Reference final ComponentUtil componentUtil, // + @Reference final AppManagerUtil appManagerUtil // + ) { super(componentManager, context, cm, componentUtil); + this.appManagerUtil = appManagerUtil; } @Override @@ -280,6 +292,8 @@ AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { : 0; final var shadowManagmentDisabled = this.getBoolean(p, Property.SHADOW_MANAGEMENT_DISABLED); + + final var hasEssLimiter14a = this.getBoolean(p, Property.HAS_ESS_LIMITER_14A); final var hasAcMeter = this.getBoolean(p, Property.HAS_AC_METER); // for older versions this property is undefined final var acType = this.getEnum(p, AcMeterType.class, Property.AC_METER_TYPE); @@ -420,6 +434,13 @@ AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { dependencies.add(acType.getDependency(modbusIdExternal)); } + if (hasEssLimiter14a) { + final var dependency = essLimiter14aToHardware(this.appManagerUtil); + if (dependency != null) { + dependencies.add(dependency); + } + } + final var schedulerComponents = new ArrayList(); if (hasEmergencyReserve) { schedulerComponents.add(new SchedulerComponent("ctrlEmergencyCapacityReserve0", @@ -539,4 +560,9 @@ private static Optional getBatteryInverter(ComponentManage return batteryInverter; } + @Override + public AppManagerUtil getAppManagerUtil() { + return this.appManagerUtil; + } + } diff --git a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome20.java b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome20.java index 083bd11673b..e557fd7ebb4 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome20.java +++ b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome20.java @@ -10,6 +10,7 @@ import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.ctrlEssSurplusFeedToGrid; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.emergencyMeter; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.ess; +import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.essLimiter14aToHardware; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.gridMeter; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.gridOptimizedCharge; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.io; @@ -29,6 +30,7 @@ import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.gridMeterType; import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.hasAcMeter; import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.hasEmergencyReserve; +import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.hasEssLimiter14a; import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.maxFeedInPower; import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.safetyCountry; import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.shadowManagementDisabled; @@ -66,6 +68,8 @@ import io.openems.edge.core.appmanager.AppConfiguration; import io.openems.edge.core.appmanager.AppDef; import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.AppManagerUtil; +import io.openems.edge.core.appmanager.AppManagerUtilSupplier; import io.openems.edge.core.appmanager.ComponentUtil; import io.openems.edge.core.appmanager.ConfigurationTarget; import io.openems.edge.core.appmanager.OpenemsApp; @@ -134,7 +138,7 @@ */ @Component(name = "App.FENECON.Home.20") public class FeneconHome20 extends AbstractOpenemsAppWithProps - implements OpenemsApp { + implements OpenemsApp, AppManagerUtilSupplier { public enum Property implements PropertyParent { ALIAS(alias()), // @@ -149,6 +153,8 @@ public enum Property implements PropertyParent { GRID_METER_CATEGORY(gridMeterType()), // CT_RATIO_FIRST(ctRatioFirst(GRID_METER_CATEGORY)), // + HAS_ESS_LIMITER_14A(hasEssLimiter14a()), // + HAS_AC_METER(hasAcMeter()), // AC_METER_TYPE(acMeterType(HAS_AC_METER)), // @@ -194,15 +200,18 @@ public Type self() { private static final IntFunction MPPT_ALIAS = value -> "ALIAS_MPPT_" + (value + 1); private final Map pvDefs = new TreeMap<>(); + private final AppManagerUtil appManagerUtil; @Activate public FeneconHome20(// @Reference final ComponentManager componentManager, // final ComponentContext componentContext, // @Reference final ConfigurationAdmin cm, // - @Reference final ComponentUtil componentUtil // + @Reference final ComponentUtil componentUtil, // + @Reference final AppManagerUtil appManagerUtil // ) { super(componentManager, componentContext, cm, componentUtil); + this.appManagerUtil = appManagerUtil; BooleanExpression anyOldPvSelected = null; for (int i = 0; i < MAX_NUMBER_OF_PV; i++) { @@ -287,6 +296,7 @@ protected ThrowingTriFunction(); if (hasEmergencyReserve) { schedulerComponents.add(new SchedulerComponent("ctrlEmergencyCapacityReserve0", @@ -421,6 +436,11 @@ protected PropertyParent[] propertyValues() { return builder.build().toArray(PropertyParent[]::new); } + @Override + public AppManagerUtil getAppManagerUtil() { + return this.appManagerUtil; + } + public static interface PropertyParent extends Type { } diff --git a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome30.java b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome30.java index 34d2c672789..019e73af9c2 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome30.java +++ b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome30.java @@ -10,6 +10,7 @@ import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.ctrlEssSurplusFeedToGrid; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.emergencyMeter; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.ess; +import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.essLimiter14aToHardware; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.gridMeter; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.gridOptimizedCharge; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.io; @@ -29,6 +30,7 @@ import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.gridMeterType; import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.hasAcMeter; import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.hasEmergencyReserve; +import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.hasEssLimiter14a; import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.maxFeedInPower; import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.safetyCountry; import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.shadowManagementDisabled; @@ -66,6 +68,8 @@ import io.openems.edge.core.appmanager.AppConfiguration; import io.openems.edge.core.appmanager.AppDef; import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.AppManagerUtil; +import io.openems.edge.core.appmanager.AppManagerUtilSupplier; import io.openems.edge.core.appmanager.ComponentUtil; import io.openems.edge.core.appmanager.ConfigurationTarget; import io.openems.edge.core.appmanager.OpenemsApp; @@ -134,7 +138,7 @@ */ @Component(name = "App.FENECON.Home.30") public class FeneconHome30 extends AbstractOpenemsAppWithProps - implements OpenemsApp { + implements OpenemsApp, AppManagerUtilSupplier { public enum Property implements PropertyParent { ALIAS(alias()), // @@ -149,6 +153,8 @@ public enum Property implements PropertyParent { GRID_METER_CATEGORY(gridMeterType()), // CT_RATIO_FIRST(ctRatioFirst(GRID_METER_CATEGORY)), // + HAS_ESS_LIMITER_14A(hasEssLimiter14a()), // + HAS_AC_METER(hasAcMeter()), // AC_METER_TYPE(acMeterType(HAS_AC_METER)), // @@ -194,15 +200,18 @@ public Type self() { private static final IntFunction MPPT_ALIAS = value -> "ALIAS_MPPT_" + (value + 1); private final Map pvDefs = new TreeMap<>(); + private final AppManagerUtil appManagerUtil; @Activate public FeneconHome30(// @Reference final ComponentManager componentManager, // final ComponentContext componentContext, // @Reference final ConfigurationAdmin cm, // - @Reference final ComponentUtil componentUtil // + @Reference final ComponentUtil componentUtil, // + @Reference final AppManagerUtil appManagerUtil // ) { super(componentManager, componentContext, cm, componentUtil); + this.appManagerUtil = appManagerUtil; BooleanExpression anyOldPvSelected = null; for (int i = 0; i < MAX_NUMBER_OF_PV; i++) { @@ -288,6 +297,7 @@ protected ThrowingTriFunction(); if (hasEmergencyReserve) { schedulerComponents.add(new SchedulerComponent("ctrlEmergencyCapacityReserve0", @@ -423,6 +437,11 @@ protected PropertyParent[] propertyValues() { return builder.build().toArray(PropertyParent[]::new); } + @Override + public AppManagerUtil getAppManagerUtil() { + return this.appManagerUtil; + } + public static interface PropertyParent extends Type { } diff --git a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHomeComponents.java b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHomeComponents.java index 3a0b44135d9..72f62c234ba 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHomeComponents.java +++ b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHomeComponents.java @@ -2,16 +2,22 @@ import java.util.ResourceBundle; +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.exceptions.OpenemsException; import io.openems.common.types.EdgeConfig; import io.openems.common.types.EdgeConfig.Component; import io.openems.common.utils.JsonUtils; import io.openems.edge.app.enums.FeedInType; import io.openems.edge.app.enums.Parity; import io.openems.edge.app.enums.SafetyCountry; +import io.openems.edge.app.ess.Limiter14a; import io.openems.edge.app.ess.PrepareBatteryExtension; +import io.openems.edge.app.hardware.IoGpio; import io.openems.edge.app.pvselfconsumption.GridOptimizedCharge; import io.openems.edge.app.pvselfconsumption.SelfConsumptionOptimization; +import io.openems.edge.core.appmanager.AppManagerUtil; import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.OpenemsAppCategory; import io.openems.edge.core.appmanager.TranslationUtil; import io.openems.edge.core.appmanager.dependency.DependencyDeclaration; @@ -480,6 +486,60 @@ public static DependencyDeclaration prepareBatteryExtension() { .build()); } + /** + * Creates a default essLimiter14a dependency for a FENECON Home. + * + * @param ioId the id of the input component + * @return the {@link DependencyDeclaration} + */ + public static DependencyDeclaration essLimiter14a(// + final String ioId // + ) { + return new DependencyDeclaration("ESS_LIMITER_14A", // + DependencyDeclaration.CreatePolicy.IF_NOT_EXISTING, // + DependencyDeclaration.UpdatePolicy.NEVER, // + DependencyDeclaration.DeletePolicy.IF_MINE, // + DependencyDeclaration.DependencyUpdatePolicy.ALLOW_ONLY_UNCONFIGURED_PROPERTIES, // + DependencyDeclaration.DependencyDeletePolicy.NOT_ALLOWED, // + DependencyDeclaration.AppDependencyConfig.create() // + .setAppId("App.Ess.Limiter14a") // + .setProperties(JsonUtils.buildJsonObject() // + .addProperty(Limiter14a.Property.ESS_ID.name(), "ess0") // + .addProperty(Limiter14a.Property.INPUT_CHANNEL_ADDRESS.name(), ioId + "/DigitalInput1") // + .build()) // + .build()); + } + + /** + * Creates a default essLimiter14a dependency for a FENECON Home which can be + * different depending on the hardware type. + * + * @param appManagerUtil the {@link AppManagerUtil} to get the hardware type + * @return the {@link DependencyDeclaration} of the specific hardware or null if + * not specified for the current hardware + * @throws OpenemsNamedException on error + */ + public static DependencyDeclaration essLimiter14aToHardware(AppManagerUtil appManagerUtil) + throws OpenemsNamedException { + final var deviceHardware = appManagerUtil + .getInstantiatedAppsByCategories(OpenemsAppCategory.OPENEMS_DEVICE_HARDWARE); + final var app = deviceHardware.stream().findAny().orElse(null); + switch (app == null ? "" : app.appId) { + case "App.OpenemsHardware.CM3", "App.OpenemsHardware.CM4S" -> { + for (var dependency : app.dependencies) { + if (!"IO_GPIO".equals(dependency.key)) { + continue; + } + final var instance = appManagerUtil.findInstanceByIdOrError(dependency.instanceId); + final var ioId = instance.properties.get(IoGpio.Property.IO_ID.name()).getAsString(); + return essLimiter14a(ioId); + } + } + } + throw new OpenemsException( + "Hardware " + (app == null ? "UNDEFINED" : app.appId) + " not supported for ess limiter 14a."); + } + private FeneconHomeComponents() { } diff --git a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/IntegratedSystemProps.java b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/IntegratedSystemProps.java index d5610be64fd..4170c49226b 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/IntegratedSystemProps.java +++ b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/IntegratedSystemProps.java @@ -12,8 +12,10 @@ import io.openems.edge.app.enums.OptionsFactory; import io.openems.edge.app.enums.SafetyCountry; import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppManagerUtilSupplier; import io.openems.edge.core.appmanager.Nameable; import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCategory; import io.openems.edge.core.appmanager.Type.Parameter.BundleProvider; import io.openems.edge.core.appmanager.formly.Exp; import io.openems.edge.core.appmanager.formly.JsonFormlyUtil; @@ -271,6 +273,34 @@ public static final AppDef acMeterType(// })); } + /** + * Creates a {@link AppDef} for selecting if the system has a ess limiter for + * 14a. + * + * @param the type of the app + * @return the created {@link AppDef} + */ + public static final // + AppDef hasEssLimiter14a() { + return AppDef.copyOfGeneric(defaultDef(), def -> def // + .setTranslatedLabel("App.IntegratedSystem.hasEssLimiter14a.label") // + .setDefaultValue(false) // + .setField(JsonFormlyUtil::buildCheckboxFromNameable, (app, property, l, parameter, field) -> { + final var hardwareTypes = app.getAppManagerUtil() + .getInstantiatedAppsByCategories(OpenemsAppCategory.OPENEMS_DEVICE_HARDWARE); + + final var isSupported = hardwareTypes.stream()// + .anyMatch(t -> switch (t.appId) { + case "App.OpenemsHardware.CM3", "App.OpenemsHardware.CM4S" -> true; + default -> false; + }); + + if (!isSupported) { + field.disabled(true); + } + })); + } + private IntegratedSystemProps() { } diff --git a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/fenecon/commercial/FeneconCommercial92.java b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/fenecon/commercial/FeneconCommercial92.java new file mode 100644 index 00000000000..0bc05c28b03 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/fenecon/commercial/FeneconCommercial92.java @@ -0,0 +1,175 @@ +package io.openems.edge.app.integratedsystem.fenecon.commercial; + +import static io.openems.edge.app.common.props.CommonProps.alias; +import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.feedInType; +import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.maxFeedInPower; +import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.safetyCountry; + +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.common.collect.Lists; +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.edge.app.enums.FeedInType; +import io.openems.edge.app.integratedsystem.FeneconHomeComponents; +import io.openems.edge.app.integratedsystem.fenecon.commercial.FeneconCommercial92.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.InterfaceConfiguration; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter; +import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; +import io.openems.edge.core.appmanager.dependency.Tasks; + +@Component(name = "App.FENECON.Commercial.92") +public class FeneconCommercial92 extends + AbstractOpenemsAppWithProps implements OpenemsApp { + + public enum Property implements Type { + ALIAS(alias()), // + + SAFETY_COUNTRY(AppDef.copyOfGeneric(safetyCountry(), def -> def // + .setRequired(true))), // + + FEED_IN_TYPE(feedInType(FeedInType.EXTERNAL_LIMITATION)), // + MAX_FEED_IN_POWER(maxFeedInPower(FEED_IN_TYPE)), // + ; + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, BundleParameter> getParamter() { + return Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + + } + + @Activate + public FeneconCommercial92(// + @Reference final ComponentManager componentManager, // + final ComponentContext componentContext, // + @Reference final ConfigurationAdmin cm, // + @Reference final ComponentUtil componentUtil // + ) { + super(componentManager, componentContext, cm, componentUtil); + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.INTEGRATED_SYSTEM }; + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.SINGLE_IN_CATEGORY; + } + + @Override + protected FeneconCommercial92 getApp() { + return this; + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + final var bundle = AbstractOpenemsApp.getTranslationBundle(l); + + final var batteryId = "battery0"; + final var batteryInverterId = "batteryInverter0"; + final var modbusToBatteryId = "modbus0"; + final var modbusToBatteryInverterId = "modbus1"; + final var modbusToGridMeterId = "modbus2"; + final var modbusToExternalDevicesId = "modbus3"; + final var gridMeterId = "meter0"; + final var essId = "ess0"; + + final var feedInType = this.getEnum(p, FeedInType.class, Property.FEED_IN_TYPE); + final var maxFeedInPower = feedInType == FeedInType.DYNAMIC_LIMITATION + ? this.getInt(p, Property.MAX_FEED_IN_POWER) + : 0; + + final var components = Lists.newArrayList(// + FeneconHomeComponents.battery(bundle, batteryId, modbusToBatteryId), // + FeneconCommercialComponents.batteryInverter(bundle, batteryInverterId, modbusToBatteryInverterId), // + FeneconHomeComponents.ess(bundle, essId, batteryId, batteryInverterId), // + FeneconHomeComponents.io(bundle, modbusToBatteryId), // + FeneconHomeComponents.modbusInternal(bundle, t, modbusToBatteryId), // + FeneconHomeComponents.predictor(bundle, t), // + FeneconCommercialComponents.modbusToBatteryInverter(bundle, t, modbusToBatteryInverterId), // + FeneconCommercialComponents.modbusToGridMeter(bundle, t, modbusToGridMeterId), // + FeneconHomeComponents.modbusForExternalMeters(bundle, t, modbusToExternalDevicesId) // + ); + + final var dependencies = Lists.newArrayList(// + FeneconHomeComponents.selfConsumptionOptimization(t, essId, gridMeterId), // + FeneconHomeComponents.gridOptimizedCharge(t, feedInType, maxFeedInPower), // + FeneconHomeComponents.prepareBatteryExtension(), // + FeneconCommercialComponents.gridMeter(bundle, gridMeterId, modbusToGridMeterId) // + ); + + return AppConfiguration.create() // + .addTask(Tasks.component(components)) // + .addTask(Tasks.staticIp(new InterfaceConfiguration("eth1") // + .addIp("BatteryInverter", "172.16.0.99/24"))) + .addDependencies(dependencies) // + .build(); + }; + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create() // + .setCanDelete(Role.INSTALLER) // + .setCanSee(Role.INSTALLER) // + .build(); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/fenecon/commercial/FeneconCommercialComponents.java b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/fenecon/commercial/FeneconCommercialComponents.java new file mode 100644 index 00000000000..f4857fd1153 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/fenecon/commercial/FeneconCommercialComponents.java @@ -0,0 +1,130 @@ +package io.openems.edge.app.integratedsystem.fenecon.commercial; + +import static io.openems.edge.core.appmanager.TranslationUtil.translate; + +import java.util.ResourceBundle; + +import io.openems.common.types.EdgeConfig; +import io.openems.common.types.EdgeConfig.Component; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.app.enums.MeterType; +import io.openems.edge.app.enums.Parity; +import io.openems.edge.app.meter.KdkMeter; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.dependency.DependencyDeclaration; + +public final class FeneconCommercialComponents { + + /** + * Creates a default battery inverter component for a FENECON Commercial 92. + * + * @param bundle the translation bundle + * @param batteryInverterId the id of the battery inverter + * @param modbusId the id of the modbus bridge + * @return the {@link Component} + */ + public static EdgeConfig.Component batteryInverter(// + final ResourceBundle bundle, // + final String batteryInverterId, // + final String modbusId // + ) { + return new EdgeConfig.Component(batteryInverterId, + translate(bundle, "App.IntegratedSystem.batteryInverter0.alias"), + "Battery-Inverter.Kaco.BlueplanetGridsave", // + JsonUtils.buildJsonObject() // + .addProperty("enabled", true) // + .addProperty("modbus.id", modbusId) // + .addProperty("startStop", "AUTO") // + .build()); + } + + /** + * Creates a default modbus bridge component to the battery inverter for a + * FENECON Commercial 92. + * + * @param bundle the translation bundle + * @param t the current {@link ConfigurationTarget} + * @param modbusId the id of the modbus bridge + * @return the {@link Component} + */ + public static EdgeConfig.Component modbusToBatteryInverter(// + final ResourceBundle bundle, // + final ConfigurationTarget t, // + final String modbusId // + ) { + return new EdgeConfig.Component(modbusId, translate(bundle, "App.IntegratedSystem.modbus1.alias"), + "Bridge.Modbus.Tcp", // + JsonUtils.buildJsonObject() // + .addProperty("enabled", true) // + .addProperty("ip", "172.16.0.100") // + .addProperty("port", 502) // + .onlyIf(t == ConfigurationTarget.ADD, b -> b// + .addProperty("invalidateElementsAfterReadErrors", 1) // + .addProperty("logVerbosity", "NONE")) + .build()); + } + + /** + * Creates a default modbus bridge component to the grid meter for a FENECON + * Commercial 92. + * + * @param bundle the translation bundle + * @param t the current {@link ConfigurationTarget} + * @param modbusId the id of the external modbus bridge + * @return the {@link Component} + */ + public static EdgeConfig.Component modbusToGridMeter(// + final ResourceBundle bundle, // + final ConfigurationTarget t, // + final String modbusId // + ) { + return new EdgeConfig.Component(modbusId, translate(bundle, "App.IntegratedSystem.modbusToGridMeter.alias"), + "Bridge.Modbus.Serial", // + JsonUtils.buildJsonObject() // + .addProperty("enabled", true) // + .addProperty("baudRate", 9600) // + .addProperty("databits", 8) // + .addProperty("parity", Parity.NONE) // + .addProperty("portName", "/dev/busUSB2") // + .addProperty("stopbits", "ONE") // + .onlyIf(t == ConfigurationTarget.ADD, b -> b// + .addProperty("invalidateElementsAfterReadErrors", 1) // + .addProperty("logVerbosity", "NONE")) + .build()); + } + + /** + * Creates a default gridMeter dependency for a FENECON Commercial 92. + * + * @param bundle the translation bundle + * @param gridMeterId the id of the grid meter + * @param modbusId the id of the modbus bridge + * @return the {@link DependencyDeclaration} + */ + public static DependencyDeclaration gridMeter(// + final ResourceBundle bundle, // + final String gridMeterId, // + final String modbusId // + ) { + return new DependencyDeclaration("GRID_METER", // + DependencyDeclaration.CreatePolicy.IF_NOT_EXISTING, // + DependencyDeclaration.UpdatePolicy.ALWAYS, // + DependencyDeclaration.DeletePolicy.IF_MINE, // + DependencyDeclaration.DependencyUpdatePolicy.ALLOW_ONLY_UNCONFIGURED_PROPERTIES, // + DependencyDeclaration.DependencyDeletePolicy.NOT_ALLOWED, // + DependencyDeclaration.AppDependencyConfig.create() // + .setAppId("App.Meter.Kdk") // + .setAlias(translate(bundle, "App.Meter.gridMeter")) // + .setProperties(JsonUtils.buildJsonObject() // + .addProperty(KdkMeter.Property.METER_ID.name(), gridMeterId) // + .addProperty(KdkMeter.Property.MODBUS_ID.name(), modbusId) // + .addProperty(KdkMeter.Property.MODBUS_UNIT_ID.name(), 5) // + .addProperty(KdkMeter.Property.TYPE.name(), MeterType.GRID) // + .build()) + .build()); + } + + private FeneconCommercialComponents() { + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/loadcontrol/ManualRelayControl.java b/io.openems.edge.core/src/io/openems/edge/app/loadcontrol/ManualRelayControl.java index b10ae500aae..eac82b5b982 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/loadcontrol/ManualRelayControl.java +++ b/io.openems.edge.core/src/io/openems/edge/app/loadcontrol/ManualRelayControl.java @@ -114,7 +114,8 @@ public Function, ManualRelayControlParame return new ManualRelayControlParameter(// createResourceBundle(t.language), // createPhaseInformation(t.app.componentUtil, 2, // - List.of(RelayProps.feneconHomeFilter(t.language, isHomeInstalled, true)), // + List.of(RelayProps.feneconHomeFilter(t.language, isHomeInstalled, true), + RelayProps.gpioFilter()), // List.of(PreferredRelay.of(4, new int[] { 1 }), // PreferredRelay.of(8, new int[] { 1 }))) // ); diff --git a/io.openems.edge.core/src/io/openems/edge/app/loadcontrol/ThresholdControl.java b/io.openems.edge.core/src/io/openems/edge/app/loadcontrol/ThresholdControl.java index 00b93cd7aba..23e3d80be1c 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/loadcontrol/ThresholdControl.java +++ b/io.openems.edge.core/src/io/openems/edge/app/loadcontrol/ThresholdControl.java @@ -115,7 +115,8 @@ public Function, ThresholdControlControlPar return new ThresholdControlControlParameter(// createResourceBundle(t.language), // createPhaseInformation(t.app.componentUtil, 2, // - List.of(RelayProps.feneconHomeFilter(t.language, isHomeInstalled, true)), // + List.of(RelayProps.feneconHomeFilter(t.language, isHomeInstalled, true), + RelayProps.gpioFilter()), // List.of(PreferredRelay.of(4, new int[] { 1 }), // PreferredRelay.of(8, new int[] { 1 }))) // ); diff --git a/io.openems.edge.core/src/io/openems/edge/app/meter/JanitzaMeter.java b/io.openems.edge.core/src/io/openems/edge/app/meter/JanitzaMeter.java index ac824238ce5..98b14f0e69b 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/meter/JanitzaMeter.java +++ b/io.openems.edge.core/src/io/openems/edge/app/meter/JanitzaMeter.java @@ -43,6 +43,7 @@ import io.openems.edge.core.appmanager.OpenemsApp; import io.openems.edge.core.appmanager.OpenemsAppCardinality; import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.TranslationUtil; import io.openems.edge.core.appmanager.Type; import io.openems.edge.core.appmanager.Type.Parameter; import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; @@ -168,7 +169,7 @@ protected ThrowingTriFunction, L final var meterId = this.getId(t, p, Property.METER_ID, "meter1"); final var alias = this.getString(p, l, Property.ALIAS); - final var factorieId = this.getString(p, Property.MODEL); + final var factoryId = this.getString(p, Property.MODEL); final var type = this.getEnum(p, MeterType.class, Property.TYPE); final var modbusUnitId = this.getInt(p, Property.MODBUS_UNIT_ID); final var integrationType = this.getEnum(p, ModbusType.class, Property.INTEGRATION_TYPE); @@ -182,7 +183,9 @@ protected ThrowingTriFunction, L final var port = this.getInt(p, Property.PORT); final var tcpModbusId = this.getId(t, p, Property.MODBUS_ID); - components.add(new EdgeConfig.Component(tcpModbusId, "bridge", "Bridge.Modbus.Tcp", // + components.add(new EdgeConfig.Component(tcpModbusId, + TranslationUtil.translate(AbstractOpenemsApp.getTranslationBundle(l), "App.Meter.alias"), + "Bridge.Modbus.Tcp", // JsonUtils.buildJsonObject() // .addProperty("ip", ip) // .addProperty("port", port) // @@ -192,7 +195,7 @@ protected ThrowingTriFunction, L } }; - components.add(new EdgeConfig.Component(meterId, alias, factorieId, // + components.add(new EdgeConfig.Component(meterId, alias, factoryId, // JsonUtils.buildJsonObject() // .addProperty("modbus.id", modbusId) // .addProperty("modbusUnitId", modbusUnitId) // diff --git a/io.openems.edge.core/src/io/openems/edge/app/meter/PhoenixContactMeter.java b/io.openems.edge.core/src/io/openems/edge/app/meter/PhoenixContactMeter.java new file mode 100644 index 00000000000..82fd0866bd1 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/meter/PhoenixContactMeter.java @@ -0,0 +1,169 @@ +package io.openems.edge.app.meter; + +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.common.collect.Lists; +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.common.types.EdgeConfig; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.app.common.props.CommonProps; +import io.openems.edge.app.enums.MeterType; +import io.openems.edge.app.meter.PhoenixContactMeter.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.TranslationUtil; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter; +import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; +import io.openems.edge.core.appmanager.dependency.Tasks; + +/** + * Describes a App for a PhoenixContact meter. + */ +@Component(name = "App.Meter.PhoenixContact") +public class PhoenixContactMeter extends + AbstractOpenemsAppWithProps implements OpenemsApp { + + public enum Property implements Type { + // Component-IDs + METER_ID(AppDef.componentId("meter1")), // + MODBUS_ID(AppDef.componentId("modbus2")), // + // Properties + ALIAS(CommonProps.alias()), // + TYPE(AppDef.copyOfGeneric(MeterProps.type(MeterType.GRID), def -> def // + .setRequired(true))), // + IP(MeterProps.ip() // + .setRequired(true)), // + PORT(MeterProps.port() // + .setRequired(true)), // + MODBUS_UNIT_ID(AppDef.copyOfGeneric(MeterProps.modbusUnitId(), def -> def // + .setRequired(true) // + .setDefaultValue(1))), // + ; + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, BundleParameter> getParamter() { + return Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + } + + @Activate + public PhoenixContactMeter(// + @Reference final ComponentManager componentManager, // + final ComponentContext componentContext, // + @Reference final ConfigurationAdmin cm, // + @Reference final ComponentUtil componentUtil // + ) { + super(componentManager, componentContext, cm, componentUtil); + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + final var meterId = this.getId(t, p, Property.METER_ID); + + final var alias = this.getString(p, l, Property.ALIAS); + final var type = this.getEnum(p, MeterType.class, Property.TYPE); + final var modbusUnitId = this.getInt(p, Property.MODBUS_UNIT_ID); + + final var ip = this.getString(p, Property.IP); + final var port = this.getInt(p, Property.PORT); + final var modbusId = this.getId(t, p, Property.MODBUS_ID); + + final var components = Lists.newArrayList(// + new EdgeConfig.Component(modbusId, + TranslationUtil.translate(AbstractOpenemsApp.getTranslationBundle(l), "App.Meter.alias"), + "Bridge.Modbus.Tcp", // + JsonUtils.buildJsonObject() // + .addProperty("ip", ip) // + .addProperty("port", port) // + .build()), // + new EdgeConfig.Component(meterId, alias, "Meter.PhoenixContact", // + JsonUtils.buildJsonObject() // + .addProperty("modbus.id", modbusId) // + .addProperty("modbusUnitId", modbusUnitId) // + .addProperty("type", type) // + .build()) // + ); + + return AppConfiguration.create() // + .addTask(Tasks.component(components)) // + .build(); + }; + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public final OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.METER }; + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.MULTIPLE; + } + + @Override + protected PhoenixContactMeter getApp() { + return this; + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create()// + .setCanSee(Role.ADMIN)// + .setCanDelete(Role.ADMIN) // + .build(); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/meter/PqPlusMeter.java b/io.openems.edge.core/src/io/openems/edge/app/meter/PqPlusMeter.java new file mode 100644 index 00000000000..064eef6f63a --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/meter/PqPlusMeter.java @@ -0,0 +1,279 @@ +package io.openems.edge.app.meter; + +import static io.openems.edge.app.common.props.CommonProps.defaultDef; +import static io.openems.edge.core.appmanager.TranslationUtil.translate; + +import java.util.ArrayList; +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.common.types.EdgeConfig; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.app.common.props.CommonProps; +import io.openems.edge.app.common.props.CommunicationProps; +import io.openems.edge.app.common.props.ComponentProps; +import io.openems.edge.app.common.props.PropsUtil; +import io.openems.edge.app.enums.MeterType; +import io.openems.edge.app.enums.ModbusType; +import io.openems.edge.app.enums.OptionsFactory; +import io.openems.edge.app.enums.TranslatableEnum; +import io.openems.edge.app.meter.PqPlusMeter.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.AppManagerUtil; +import io.openems.edge.core.appmanager.AppManagerUtilSupplier; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ComponentUtilSupplier; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.TranslationUtil; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter; +import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; +import io.openems.edge.core.appmanager.dependency.Tasks; +import io.openems.edge.core.appmanager.formly.Exp; +import io.openems.edge.core.appmanager.formly.JsonFormlyUtil; + +/** + * Describes a App for a PQ-Plus meter. + * + *

      +  {
      +    "appId":"App.Meter.PqPlus",
      +    "alias":"PQ-Plus Meter",
      +    "instanceId": UUID,
      +    "image": base64,
      +    "properties":{
      +    	"METER_ID": "meter1",
      +    	"TYPE": "PRODUCTION",
      +    	"MODBUS_ID": "modbus1",
      +    	"MODBUS_UNIT_ID": 6
      +    },
      +    "appDescriptor": {
      +    	"websiteUrl": {@link AppDescriptor#getWebsiteUrl()}
      +    }
      +  }
      + * 
      + */ +@Component(name = "App.Meter.PqPlus") +public class PqPlusMeter extends AbstractOpenemsAppWithProps + implements OpenemsApp, ComponentUtilSupplier, AppManagerUtilSupplier { + + public enum Property implements Type { + // Component-IDs + METER_ID(AppDef.componentId("meter1")), // + MODBUS_ID(AppDef.componentId("modbus2")), // + // Properties + ALIAS(CommonProps.alias()), // + TYPE(AppDef.copyOfGeneric(MeterProps.type(MeterType.GRID), def -> def // + .setRequired(true))), // + INTEGRATION_TYPE(CommunicationProps.modbusType() // + .setRequired(true)), // + IP(MeterProps.ip() // + .setDefaultValue("10.4.0.12") // + .setRequired(true) // + .wrapField((app, property, l, parameter, field) -> { + field.onlyShowIf((Exp.currentModelValue(INTEGRATION_TYPE) // + .equal(Exp.staticValue(ModbusType.TCP)))); + })), // + PORT(MeterProps.port() // + .setRequired(true) // + .wrapField((app, property, l, parameter, field) -> { + field.onlyShowIf((Exp.currentModelValue(INTEGRATION_TYPE) // + .equal(Exp.staticValue(ModbusType.TCP)))); + })), // + SELECTED_MODBUS_ID(AppDef.copyOfGeneric(ComponentProps.pickSerialModbusId(), def -> def // + .setRequired(true) // + .wrapField((app, property, l, parameter, field) -> { + if (PropsUtil.isHomeInstalled(app.getAppManagerUtil())) { + field.readonly(true); + } + field.onlyShowIf(Exp.currentModelValue(INTEGRATION_TYPE) // + .equal(Exp.staticValue(ModbusType.RTU))); + })) // + .setAutoGenerateField(false)), // + MODEL(AppDef.copyOfGeneric(defaultDef(), def -> def // + .setTranslatedLabelWithAppPrefix(".productModel") // + .setDefaultValue(PqPlusModel.UMD_96.getValue()) // + .setRequired(true) // + .setField(JsonFormlyUtil::buildSelect, (app, property, l, parameter, field) -> { + field.setOptions(OptionsFactory.of(PqPlusModel.class), l); + }))), // + MODBUS_UNIT_ID(AppDef.copyOfGeneric(MeterProps.modbusUnitId(), def -> def // + .setRequired(true) // + .setAutoGenerateField(false) // + .setDefaultValue(6))), // + MODBUS_GROUP(CommunicationProps.modbusGroup(// + SELECTED_MODBUS_ID, SELECTED_MODBUS_ID.def(), // + MODBUS_UNIT_ID, MODBUS_UNIT_ID.def(), INTEGRATION_TYPE)), // + ; + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, BundleParameter> getParamter() { + return Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + } + + private final AppManagerUtil appManagerUtil; + + @Activate + public PqPlusMeter(// + @Reference final ComponentManager componentManager, // + final ComponentContext componentContext, // + @Reference final ConfigurationAdmin cm, // + @Reference final ComponentUtil componentUtil, // + @Reference final AppManagerUtil appManagerUtil // + ) { + super(componentManager, componentContext, cm, componentUtil); + this.appManagerUtil = appManagerUtil; + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + final var meterId = this.getId(t, p, Property.METER_ID); + + final var alias = this.getString(p, l, Property.ALIAS); + final var factoryId = this.getString(p, Property.MODEL); + final var type = this.getEnum(p, MeterType.class, Property.TYPE); + final var modbusUnitId = this.getInt(p, Property.MODBUS_UNIT_ID); + final var integrationType = this.getEnum(p, ModbusType.class, Property.INTEGRATION_TYPE); + + final var components = new ArrayList(); + + final var modbusId = switch (integrationType) { + case RTU -> this.getString(p, Property.SELECTED_MODBUS_ID); + case TCP -> { + final var ip = this.getString(p, Property.IP); + final var port = this.getInt(p, Property.PORT); + final var tcpModbusId = this.getId(t, p, Property.MODBUS_ID); + + components.add(new EdgeConfig.Component(tcpModbusId, + TranslationUtil.translate(AbstractOpenemsApp.getTranslationBundle(l), "App.Meter.alias"), + "Bridge.Modbus.Tcp", // + JsonUtils.buildJsonObject() // + .addProperty("ip", ip) // + .addProperty("port", port) // + .build())); + + yield tcpModbusId; + } + }; + + components.add(// + new EdgeConfig.Component(meterId, alias, factoryId, // + JsonUtils.buildJsonObject() // + .addProperty("modbus.id", modbusId) // + .addProperty("modbusUnitId", modbusUnitId) // + .addProperty("type", type) // + .build()) // + ); + + return AppConfiguration.create() // + .addTask(Tasks.component(components)) // + .build(); + }; + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public final OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.METER }; + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + + @Override + public AppManagerUtil getAppManagerUtil() { + return this.appManagerUtil; + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.MULTIPLE; + } + + @Override + protected PqPlusMeter getApp() { + return this; + } + + public enum PqPlusModel implements TranslatableEnum { + UMD_96("Meter.PqPlus.UMD96", "App.Meter.PqPlus.UMD96"), // + UMD_97("Meter.PqPlus.UMD97", "App.Meter.PqPlus.UMD97"), // + ; + + private final String value; + private final String translation; + + private PqPlusModel(String value, String translation) { + this.value = value; + this.translation = translation; + } + + @Override + public String getTranslation(Language language) { + return translate(getTranslationBundle(language), this.translation); + } + + @Override + public String getValue() { + return this.value; + } + + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create()// + .setCanSee(Role.ADMIN)// + .setCanDelete(Role.ADMIN) // + .build(); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/openemshardware/BeagleBoneBlack.java b/io.openems.edge.core/src/io/openems/edge/app/openemshardware/BeagleBoneBlack.java new file mode 100644 index 00000000000..19c4f155acd --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/openemshardware/BeagleBoneBlack.java @@ -0,0 +1,121 @@ +package io.openems.edge.app.openemshardware; + +import static io.openems.edge.app.common.props.CommonProps.alias; + +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.edge.app.openemshardware.BeagleBoneBlack.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter; +import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; + +@Component(name = "App.OpenemsHardware.BeagleBoneBlack") +public class BeagleBoneBlack extends AbstractOpenemsAppWithProps + implements OpenemsApp { + + public static enum Property implements Type { + // Properties + ALIAS(alias()), // + ; + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, BundleParameter> getParamter() { + return Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + } + + @Activate + public BeagleBoneBlack(// + @Reference ComponentManager componentManager, // + ComponentContext context, // + @Reference ConfigurationAdmin cm, // + @Reference ComponentUtil componentUtil // + ) { + super(componentManager, context, cm, componentUtil); + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + return AppConfiguration.empty(); + }; + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.OPENEMS_DEVICE_HARDWARE }; + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + + @Override + protected BeagleBoneBlack getApp() { + return this; + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.SINGLE_IN_CATEGORY; + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create() // + .setCanDelete(Role.ADMIN) // + .setCanSee(Role.ADMIN) // + .build(); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/openemshardware/Compulab.java b/io.openems.edge.core/src/io/openems/edge/app/openemshardware/Compulab.java new file mode 100644 index 00000000000..dde30d24c6e --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/openemshardware/Compulab.java @@ -0,0 +1,121 @@ +package io.openems.edge.app.openemshardware; + +import static io.openems.edge.app.common.props.CommonProps.alias; + +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.edge.app.openemshardware.Compulab.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter; +import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; + +@Component(name = "App.OpenemsHardware.Compulab") +public class Compulab extends AbstractOpenemsAppWithProps + implements OpenemsApp { + + public static enum Property implements Type { + // Properties + ALIAS(alias()), // + ; + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, BundleParameter> getParamter() { + return Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + } + + @Activate + public Compulab(// + @Reference ComponentManager componentManager, // + ComponentContext context, // + @Reference ConfigurationAdmin cm, // + @Reference ComponentUtil componentUtil // + ) { + super(componentManager, context, cm, componentUtil); + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + return AppConfiguration.empty(); + }; + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.OPENEMS_DEVICE_HARDWARE }; + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + + @Override + protected Compulab getApp() { + return this; + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.SINGLE_IN_CATEGORY; + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create() // + .setCanDelete(Role.ADMIN) // + .setCanSee(Role.ADMIN) // + .build(); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm3.java b/io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm3.java new file mode 100644 index 00000000000..d89f0430bb1 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm3.java @@ -0,0 +1,132 @@ +package io.openems.edge.app.openemshardware; + +import static io.openems.edge.app.common.props.CommonProps.alias; + +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.edge.app.openemshardware.TechbaseCm3.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter; +import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; +import io.openems.edge.core.appmanager.dependency.DependencyDeclaration; + +@Component(name = "App.OpenemsHardware.CM3") +public class TechbaseCm3 extends AbstractOpenemsAppWithProps + implements OpenemsApp { + + public static enum Property implements Type { + // Properties + ALIAS(alias()), // + ; + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, BundleParameter> getParamter() { + return Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + } + + @Activate + public TechbaseCm3(// + @Reference ComponentManager componentManager, // + ComponentContext context, // + @Reference ConfigurationAdmin cm, // + @Reference ComponentUtil componentUtil // + ) { + super(componentManager, context, cm, componentUtil); + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + return AppConfiguration.create() // + .addDependencies(new DependencyDeclaration("IO_GPIO", // + DependencyDeclaration.CreatePolicy.IF_NOT_EXISTING, // + DependencyDeclaration.UpdatePolicy.NEVER, // + DependencyDeclaration.DeletePolicy.ALWAYS, // + DependencyDeclaration.DependencyUpdatePolicy.ALLOW_ONLY_UNCONFIGURED_PROPERTIES, // + DependencyDeclaration.DependencyDeletePolicy.NOT_ALLOWED, // + DependencyDeclaration.AppDependencyConfig.create() // + .setAppId("App.Hardware.IoGpio") // + .build())) + .build(); + }; + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.OPENEMS_DEVICE_HARDWARE }; + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + + @Override + protected TechbaseCm3 getApp() { + return this; + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.SINGLE_IN_CATEGORY; + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create() // + .setCanDelete(Role.ADMIN) // TODO maybe only system + .setCanSee(Role.ADMIN) // + .build(); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4.java b/io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4.java new file mode 100644 index 00000000000..f0a35bdc8fe --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4.java @@ -0,0 +1,121 @@ +package io.openems.edge.app.openemshardware; + +import static io.openems.edge.app.common.props.CommonProps.alias; + +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.edge.app.openemshardware.TechbaseCm4.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter; +import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; + +@Component(name = "App.OpenemsHardware.CM4") +public class TechbaseCm4 extends AbstractOpenemsAppWithProps + implements OpenemsApp { + + public static enum Property implements Type { + // Properties + ALIAS(alias()), // + ; + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, BundleParameter> getParamter() { + return Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + } + + @Activate + public TechbaseCm4(// + @Reference ComponentManager componentManager, // + ComponentContext context, // + @Reference ConfigurationAdmin cm, // + @Reference ComponentUtil componentUtil // + ) { + super(componentManager, context, cm, componentUtil); + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + return AppConfiguration.empty(); + }; + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.OPENEMS_DEVICE_HARDWARE }; + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + + @Override + protected TechbaseCm4 getApp() { + return this; + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.SINGLE_IN_CATEGORY; + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create() // + .setCanDelete(Role.ADMIN) // + .setCanSee(Role.ADMIN) // + .build(); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4Max.java b/io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4Max.java new file mode 100644 index 00000000000..a67442790bb --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4Max.java @@ -0,0 +1,121 @@ +package io.openems.edge.app.openemshardware; + +import static io.openems.edge.app.common.props.CommonProps.alias; + +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.edge.app.openemshardware.TechbaseCm4Max.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter; +import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; + +@Component(name = "App.OpenemsHardware.CM4Max") +public class TechbaseCm4Max extends AbstractOpenemsAppWithProps + implements OpenemsApp { + + public static enum Property implements Type { + // Properties + ALIAS(alias()), // + ; + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, BundleParameter> getParamter() { + return Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + } + + @Activate + public TechbaseCm4Max(// + @Reference ComponentManager componentManager, // + ComponentContext context, // + @Reference ConfigurationAdmin cm, // + @Reference ComponentUtil componentUtil // + ) { + super(componentManager, context, cm, componentUtil); + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + return AppConfiguration.empty(); + }; + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.OPENEMS_DEVICE_HARDWARE }; + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + + @Override + protected TechbaseCm4Max getApp() { + return this; + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.SINGLE_IN_CATEGORY; + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create() // + .setCanDelete(Role.ADMIN) // + .setCanSee(Role.ADMIN) // + .build(); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4s.java b/io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4s.java new file mode 100644 index 00000000000..8ce06dcb343 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4s.java @@ -0,0 +1,132 @@ +package io.openems.edge.app.openemshardware; + +import static io.openems.edge.app.common.props.CommonProps.alias; + +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.edge.app.openemshardware.TechbaseCm4s.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter; +import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; +import io.openems.edge.core.appmanager.dependency.DependencyDeclaration; + +@Component(name = "App.OpenemsHardware.CM4S") +public class TechbaseCm4s extends AbstractOpenemsAppWithProps + implements OpenemsApp { + + public static enum Property implements Type { + // Properties + ALIAS(alias()), // + ; + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, BundleParameter> getParamter() { + return Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + } + + @Activate + public TechbaseCm4s(// + @Reference ComponentManager componentManager, // + ComponentContext context, // + @Reference ConfigurationAdmin cm, // + @Reference ComponentUtil componentUtil // + ) { + super(componentManager, context, cm, componentUtil); + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + return AppConfiguration.create() // + .addDependencies(new DependencyDeclaration("IO_GPIO", // + DependencyDeclaration.CreatePolicy.IF_NOT_EXISTING, // + DependencyDeclaration.UpdatePolicy.NEVER, // + DependencyDeclaration.DeletePolicy.ALWAYS, // + DependencyDeclaration.DependencyUpdatePolicy.ALLOW_ONLY_UNCONFIGURED_PROPERTIES, // + DependencyDeclaration.DependencyDeletePolicy.NOT_ALLOWED, // + DependencyDeclaration.AppDependencyConfig.create() // + .setAppId("App.Hardware.IoGpio") // + .build())) + .build(); + }; + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.OPENEMS_DEVICE_HARDWARE }; + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + + @Override + protected TechbaseCm4s getApp() { + return this; + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.SINGLE_IN_CATEGORY; + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create() // + .setCanDelete(Role.ADMIN) // + .setCanSee(Role.ADMIN) // + .build(); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4sGen2.java b/io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4sGen2.java new file mode 100644 index 00000000000..dd6b6df3c02 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4sGen2.java @@ -0,0 +1,137 @@ +package io.openems.edge.app.openemshardware; + +import static io.openems.edge.app.common.props.CommonProps.alias; + +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.app.hardware.IoGpio; +import io.openems.edge.app.openemshardware.TechbaseCm4sGen2.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter; +import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; +import io.openems.edge.core.appmanager.dependency.DependencyDeclaration; + +@Component(name = "App.OpenemsHardware.CM4S.Gen2") +public class TechbaseCm4sGen2 extends AbstractOpenemsAppWithProps + implements OpenemsApp { + + public static enum Property implements Type { + // Properties + ALIAS(alias()), // + ; + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, BundleParameter> getParamter() { + return Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + } + + @Activate + public TechbaseCm4sGen2(// + @Reference ComponentManager componentManager, // + ComponentContext context, // + @Reference ConfigurationAdmin cm, // + @Reference ComponentUtil componentUtil // + ) { + super(componentManager, context, cm, componentUtil); + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + return AppConfiguration.create() // + .addDependencies(new DependencyDeclaration("IO_GPIO", // + DependencyDeclaration.CreatePolicy.IF_NOT_EXISTING, // + DependencyDeclaration.UpdatePolicy.NEVER, // + DependencyDeclaration.DeletePolicy.ALWAYS, // + DependencyDeclaration.DependencyUpdatePolicy.ALLOW_ONLY_UNCONFIGURED_PROPERTIES, // + DependencyDeclaration.DependencyDeletePolicy.NOT_ALLOWED, // + DependencyDeclaration.AppDependencyConfig.create() // + .setAppId("App.Hardware.IoGpio") // + .setInitialProperties(JsonUtils.buildJsonObject() // + .addProperty(IoGpio.Property.IO_ID.name(), "io1") // + .build()) + .build())) + .build(); + }; + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.OPENEMS_DEVICE_HARDWARE }; + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + + @Override + protected TechbaseCm4sGen2 getApp() { + return this; + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.SINGLE_IN_CATEGORY; + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create() // + .setCanDelete(Role.ADMIN) // + .setCanSee(Role.ADMIN) // + .build(); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/AwattarHourly.java b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/AwattarHourly.java index 2a239b4579a..31200d39881 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/AwattarHourly.java +++ b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/AwattarHourly.java @@ -2,6 +2,7 @@ import static io.openems.edge.app.common.props.CommonProps.alias; import static io.openems.edge.app.common.props.CommonProps.defaultDef; +import static io.openems.edge.core.appmanager.validator.Checkables.checkCommercial92; import static io.openems.edge.core.appmanager.validator.Checkables.checkHome; import java.util.Map; @@ -168,7 +169,7 @@ public OpenemsAppCardinality getCardinality() { @Override protected ValidatorConfig.Builder getValidateBuilder() { return ValidatorConfig.create() // - .setCompatibleCheckableConfigs(checkHome()); + .setCompatibleCheckableConfigs(checkHome().or(checkCommercial92())); } @Override diff --git a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/EntsoE.java b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/EntsoE.java index 417b2e8a67b..0c2f6d2f10d 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/EntsoE.java +++ b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/EntsoE.java @@ -1,5 +1,6 @@ package io.openems.edge.app.timeofusetariff; +import static io.openems.edge.core.appmanager.validator.Checkables.checkCommercial92; import static io.openems.edge.core.appmanager.validator.Checkables.checkHome; import java.util.Map; @@ -167,7 +168,7 @@ public OpenemsAppCardinality getCardinality() { @Override protected ValidatorConfig.Builder getValidateBuilder() { return ValidatorConfig.create() // - .setCompatibleCheckableConfigs(checkHome()); + .setCompatibleCheckableConfigs(checkHome().or(checkCommercial92())); } @Override diff --git a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/GroupeE.java b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/GroupeE.java index 1415ce3636b..b466c39ff10 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/GroupeE.java +++ b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/GroupeE.java @@ -1,5 +1,6 @@ package io.openems.edge.app.timeofusetariff; +import static io.openems.edge.core.appmanager.validator.Checkables.checkCommercial92; import static io.openems.edge.core.appmanager.validator.Checkables.checkHome; import java.util.Map; @@ -150,7 +151,7 @@ public OpenemsAppCardinality getCardinality() { @Override protected ValidatorConfig.Builder getValidateBuilder() { return ValidatorConfig.create() // - .setCompatibleCheckableConfigs(checkHome()); + .setCompatibleCheckableConfigs(checkHome().or(checkCommercial92())); } @Override diff --git a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/RabotCharge.java b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/RabotCharge.java index c423c7bbcb9..de9a446a214 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/RabotCharge.java +++ b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/RabotCharge.java @@ -1,6 +1,7 @@ package io.openems.edge.app.timeofusetariff; import static io.openems.edge.core.appmanager.formly.enums.InputType.PASSWORD; +import static io.openems.edge.core.appmanager.validator.Checkables.checkCommercial92; import static io.openems.edge.core.appmanager.validator.Checkables.checkHome; import java.util.Map; @@ -177,7 +178,7 @@ public OpenemsAppCardinality getCardinality() { @Override protected ValidatorConfig.Builder getValidateBuilder() { return ValidatorConfig.create() // - .setCompatibleCheckableConfigs(checkHome()); + .setCompatibleCheckableConfigs(checkHome().or(checkCommercial92())); } @Override diff --git a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StadtwerkHassfurt.java b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StadtwerkHassfurt.java index e013386d2dc..8bf099ba335 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StadtwerkHassfurt.java +++ b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StadtwerkHassfurt.java @@ -1,6 +1,7 @@ package io.openems.edge.app.timeofusetariff; import static io.openems.edge.app.common.props.CommonProps.defaultDef; +import static io.openems.edge.core.appmanager.validator.Checkables.checkCommercial92; import static io.openems.edge.core.appmanager.validator.Checkables.checkHome; import java.util.Map; @@ -166,7 +167,7 @@ public OpenemsAppCardinality getCardinality() { @Override protected ValidatorConfig.Builder getValidateBuilder() { return ValidatorConfig.create() // - .setCompatibleCheckableConfigs(checkHome()); + .setCompatibleCheckableConfigs(checkHome().or(checkCommercial92())); } @Override diff --git a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StromdaoCorrently.java b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StromdaoCorrently.java index 603fb81f5ba..fbbeb951333 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StromdaoCorrently.java +++ b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StromdaoCorrently.java @@ -1,5 +1,6 @@ package io.openems.edge.app.timeofusetariff; +import static io.openems.edge.core.appmanager.validator.Checkables.checkCommercial92; import static io.openems.edge.core.appmanager.validator.Checkables.checkHome; import java.util.Map; @@ -163,7 +164,7 @@ public OpenemsAppCardinality getCardinality() { @Override protected ValidatorConfig.Builder getValidateBuilder() { return ValidatorConfig.create() // - .setCompatibleCheckableConfigs(checkHome()); + .setCompatibleCheckableConfigs(checkHome().or(checkCommercial92())); } @Override diff --git a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/Tibber.java b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/Tibber.java index 38b7b7b8b8b..3eeeb094bab 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/Tibber.java +++ b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/Tibber.java @@ -1,6 +1,7 @@ package io.openems.edge.app.timeofusetariff; import static io.openems.edge.core.appmanager.formly.enums.InputType.PASSWORD; +import static io.openems.edge.core.appmanager.validator.Checkables.checkCommercial92; import static io.openems.edge.core.appmanager.validator.Checkables.checkHome; import java.util.Map; @@ -196,7 +197,7 @@ public OpenemsAppCardinality getCardinality() { @Override protected ValidatorConfig.Builder getValidateBuilder() { return ValidatorConfig.create() // - .setCompatibleCheckableConfigs(checkHome()); + .setCompatibleCheckableConfigs(checkHome().or(checkCommercial92())); } @Override diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManager.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManager.java index 73749f40d64..4a999860bc9 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManager.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManager.java @@ -13,12 +13,14 @@ public interface AppManager extends OpenemsComponent { public enum ChannelId implements io.openems.edge.common.channel.ChannelId { WRONG_APP_CONFIGURATION(Doc.of(Level.WARNING) // - .text("App-Manager configuration is wrong")), // + .translationKey(AppManager.class, "AppManager.WrongAppConfiguration")), // DEFECTIVE_APP(Doc.of(Level.INFO) // // TODO should be a WARNING eventually - .text("Defective App detected")), // + .translationKey(AppManager.class, "AppManager.DefectiveApp")), // APPS_NOT_SYNCED_WITH_BACKEND(Doc.of(Level.INFO) // - .text("The currently installed apps are not the same as logged in the backend")), // + .translationKey(AppManager.class, "AppManager.AppsNotSynced")), // + HARDWARE_MISSMATCH(Doc.of(Level.INFO) // + .text("The current installed hardware app is not the same as defined in 'hardware.conf'")), // ; private final Doc doc; @@ -67,6 +69,16 @@ public default void _setAppsNotSyncedWithBackend(boolean value) { this.getAppsNotSyncedWithBackendChannel().setNextValue(value); } + /** + * Internal method to set the 'nextValue' on + * {@link ChannelId#HARDWARE_MISSMATCH} Channel. + * + * @param value the next value + */ + public default void _setHardwareMissmatch(boolean value) { + this.getHardwareMissmatchChannel().setNextValue(value); + } + /** * Gets the Defective-App Warning State. See {@link ChannelId#DEFECTIVE_APP}. * @@ -123,4 +135,23 @@ public default StateChannel getAppsNotSyncedWithBackendChannel() { return this.channel(ChannelId.APPS_NOT_SYNCED_WITH_BACKEND); } + /** + * Gets the Hardware-Missmatch info State. See + * {@link ChannelId#HARDWARE_MISSMATCH}. + * + * @return the Channel {@link Value} + */ + public default Value getHardwareMissmatch() { + return this.getAppsNotSyncedWithBackendChannel().value(); + } + + /** + * Gets the channel for {@link ChannelId#HARDWARE_MISSMATCH}. + * + * @return the Channel + */ + public default StateChannel getHardwareMissmatchChannel() { + return this.channel(ChannelId.HARDWARE_MISSMATCH); + } + } diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManagerUtil.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManagerUtil.java index 22649215c26..e1e7d3f1fe1 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManagerUtil.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManagerUtil.java @@ -51,6 +51,15 @@ public default List getInstantiatedAppsOf(String... appIds) .toList(); } + /** + * Gets the installed apps which match any of the provided + * {@link OpenemsAppCategory OpenemsAppCategories}. + * + * @param categories the {@link OpenemsAppCategory} to be contained by the app + * @return the found {@link OpenemsAppInstance OpenemsAppInstances} + */ + public List getInstantiatedAppsByCategories(OpenemsAppCategory... categories); + /** * Finds the {@link OpenemsApp} with the given id. * diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManagerUtilImpl.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManagerUtilImpl.java index 188b47f064b..3337a884e12 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManagerUtilImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManagerUtilImpl.java @@ -6,6 +6,7 @@ import java.util.Optional; import java.util.UUID; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; @@ -46,6 +47,22 @@ public Optional findInstanceById(UUID id) { .flatMap(t -> t.findInstanceById(id)); } + @Override + public List getInstantiatedAppsByCategories(OpenemsAppCategory... categories) { + return this.getInstantiatedApps().stream() // + .filter(t -> { + final var app = this.findAppById(t.appId).orElse(null); + + if (app == null) { + return false; + } + + return Stream.of(app.getCategories()) // + .anyMatch(c1 -> Stream.of(categories) // + .anyMatch(c2 -> c1 == c2)); + }).toList(); + } + @Override public AppConfiguration getAppConfiguration(ConfigurationTarget target, OpenemsApp app, String alias, JsonObject properties, Language language) throws OpenemsNamedException { diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/OpenemsAppCategory.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/OpenemsAppCategory.java index 3e287c25f9b..9f11f6825c7 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/OpenemsAppCategory.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/OpenemsAppCategory.java @@ -44,6 +44,11 @@ public enum OpenemsAppCategory { */ HARDWARE("hardware"), + /** + * The hardware on which the OpenEMS software runs. + */ + OPENEMS_DEVICE_HARDWARE("openemsDeviceHardware"), + /** * Peak-Shaving. */ diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/ResolveOpenemsHardware.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/ResolveOpenemsHardware.java new file mode 100644 index 00000000000..be8d1cee003 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/ResolveOpenemsHardware.java @@ -0,0 +1,189 @@ +package io.openems.edge.core.appmanager; + +import static java.util.Collections.emptyMap; +import static java.util.stream.Collectors.toMap; + +import java.io.File; +import java.nio.file.Files; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; + +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.component.annotations.ServiceScope; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.openems.common.utils.JsonUtils; +import io.openems.edge.core.appmanager.jsonrpc.AddAppInstance; + +@Component(immediate = true, scope = ServiceScope.SINGLETON) +public class ResolveOpenemsHardware implements Runnable { + + public static final String OPENEMS_HARDWARE_FILE_NAME = "hardware.conf"; + public static final String OPENEMS_HARDWARE_APP_KEY = "appId"; + + private final Logger log = LoggerFactory.getLogger(ResolveOpenemsHardware.class); + + private final ComponentContext context; + private final AppManagerImpl appManagerImpl; + private final AppManagerUtil appManagerUtil; + private final String requireApp; + private CompletableFuture task; + private final Executor delayedExecutor; + + /** + * Binds a {@link OpenemsApp}. + * + * @param app the {@link OpenemsApp} to bind + */ + @Reference(// + cardinality = ReferenceCardinality.MULTIPLE, // + policy = ReferencePolicy.DYNAMIC, // + policyOption = ReferencePolicyOption.GREEDY // + ) + public void bindApp(OpenemsApp app) { + this.trigger(); + } + + /** + * Unbinds a {@link OpenemsApp}. + * + * @param app the {@link OpenemsApp} to unbind + */ + public void unbindApp(OpenemsApp app) { + // empty + } + + public ResolveOpenemsHardware(// + ComponentContext context, // + AppManager appManagerImpl, // + AppManagerUtil appManagerUtil, // + Executor delayedExecutor // + ) { + super(); + this.context = context; + this.appManagerImpl = (AppManagerImpl) appManagerImpl; + this.appManagerUtil = appManagerUtil; + this.delayedExecutor = delayedExecutor; + + final var hardwareProperties = this.getHardwareProperties(); + this.requireApp = hardwareProperties.get(OPENEMS_HARDWARE_APP_KEY); + + this.trigger(); + } + + @Activate + public ResolveOpenemsHardware(// + ComponentContext context, // + @Reference AppManager appManagerImpl, // + @Reference AppManagerUtil appManagerUtil // + ) { + this(context, appManagerImpl, appManagerUtil, CompletableFuture.delayedExecutor(5, TimeUnit.SECONDS)); + } + + @Deactivate + private void deactivate() { + final var task = this.task; + if (task != null) { + task.cancel(false); + } + } + + private synchronized void trigger() { + if (this.requireApp == null) { + this.task = CompletableFuture.runAsync(this.context.getComponentInstance()::dispose); + return; + } + + final var activeTask = this.task; + if (activeTask != null) { + activeTask.cancel(false); + } + + // waits 5 seconds until every app is activated + this.task = CompletableFuture.runAsync(() -> { + try { + this.run(); + } finally { + this.context.getComponentInstance().dispose(); + } + }, this.delayedExecutor); + } + + @Override + public void run() { + // currently its ignored if the app of an installed hardware app is not yet + // active or available after a 5 seconds delay from the last activated app and + // would therefore not be returned by the following method which could result in + // 2 hardware apps being installed + final var hardwareApps = this.appManagerUtil + .getInstantiatedAppsByCategories(OpenemsAppCategory.OPENEMS_DEVICE_HARDWARE); + + if (hardwareApps.size() >= 1) { + // validate + if (hardwareApps.size() > 1) { + // more than 1 installed => impossible + this.appManagerImpl._setHardwareMissmatch(true); + return; + } + + final var installedHardwareApp = hardwareApps.get(0); + if (installedHardwareApp.appId.equals(this.requireApp)) { + // installed hardware app matches the on in the properties file + this.appManagerImpl._setHardwareMissmatch(false); + return; + } + + this.appManagerImpl._setHardwareMissmatch(true); + return; + } + + this.log.trace("Try to install '" + this.requireApp + "'"); + try { + this.appManagerImpl.handleAddAppInstanceRequest(null, + new AddAppInstance.Request(this.requireApp, null, null, JsonUtils.buildJsonObject() // + .build()), + true); + + this.log.trace("Installed '" + this.requireApp + "' successfully"); + this.appManagerImpl._setHardwareMissmatch(false); + } catch (Exception e) { + this.log.error("Installation of '" + this.requireApp + "' failed", e); + this.appManagerImpl._setHardwareMissmatch(true); + } + + } + + private Map getHardwareProperties() { + final var configDir = System.getProperty("felix.cm.dir"); + if (configDir == null) { + return emptyMap(); + } + final var hardwareFile = new File(configDir, OPENEMS_HARDWARE_FILE_NAME); + + if (!hardwareFile.exists()) { + return emptyMap(); + } + + try { + return Files.lines(hardwareFile.toPath()) // + .map(t -> t.split("=", 2)) // + .filter(t -> t.length == 2) // + .collect(toMap(t -> t[0], t -> t[1])); + + } catch (Exception e) { + this.log.error("Unable to read hardware info file", e); + return emptyMap(); + } + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/AppManagerAppHelperImpl.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/AppManagerAppHelperImpl.java index b6b13ef0916..7ce7533c0f2 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/AppManagerAppHelperImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/AppManagerAppHelperImpl.java @@ -30,6 +30,7 @@ import org.osgi.service.component.annotations.ReferencePolicy; import org.osgi.service.component.annotations.ReferencePolicyOption; import org.osgi.service.component.annotations.ServiceScope; +import org.osgi.service.condition.Condition; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -57,6 +58,11 @@ import io.openems.edge.core.appmanager.TranslationUtil; import io.openems.edge.core.appmanager.dependency.DependencyDeclaration.AppDependencyConfig; import io.openems.edge.core.appmanager.dependency.aggregatetask.AggregateTask; +import io.openems.edge.core.appmanager.dependency.aggregatetask.ComponentAggregateTask; +import io.openems.edge.core.appmanager.dependency.aggregatetask.PersistencePredictorAggregateTask; +import io.openems.edge.core.appmanager.dependency.aggregatetask.SchedulerAggregateTask; +import io.openems.edge.core.appmanager.dependency.aggregatetask.SchedulerByCentralOrderAggregateTask; +import io.openems.edge.core.appmanager.dependency.aggregatetask.StaticIpAggregateTask; @Component(// immediate = true, // @@ -66,6 +72,23 @@ public class AppManagerAppHelperImpl implements AppManagerAppHelper { private final Logger log = LoggerFactory.getLogger(this.getClass()); + @Component(service = { StartTarget.class }) + public static class StartTarget implements Condition { + @Reference + private ComponentAggregateTask componentAggregateTask; + @Reference + private PersistencePredictorAggregateTask persistencePredictorAggregateTask; + @Reference + private SchedulerAggregateTask schedulerAggregateTask; + @Reference + private SchedulerByCentralOrderAggregateTask schedulerByCentralOrderAggregateTask; + @Reference + private StaticIpAggregateTask staticIpAggregateTask; + } + + @Reference + private StartTarget startCondition; + @Reference(// policy = ReferencePolicy.DYNAMIC, // policyOption = ReferencePolicyOption.GREEDY, // diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/SchedulerByCentralOrderAggregateTaskImpl.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/SchedulerByCentralOrderAggregateTaskImpl.java index 639fad889a4..c7b69815ce1 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/SchedulerByCentralOrderAggregateTaskImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/SchedulerByCentralOrderAggregateTaskImpl.java @@ -62,6 +62,7 @@ public ProductionSchedulerOrderDefinition() { .thenByFactoryId("Controller.Ess.FixActivePower") // .thenByFactoryId("Controller.Ess.FixStateOfCharge")// .thenByFactoryId("Controller.Ess.EmergencyCapacityReserve") // + .thenByFactoryId("Controller.Ess.Limiter14a") // .thenBy(new SchedulerOrderDefinition() // .filterByFactoryId("Controller.Api.ModbusTcp.ReadWrite") // .thenByCreatedAppId("App.Ess.GeneratingPlantController") // diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties index 78905f75ed7..b0e860ca53e 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties @@ -11,6 +11,7 @@ meter = Erzeugungs- und Verbrauchszähler peakShaving = Lastspitzenkappung und atypische Netznutzung api = Schnittstellen ess = Speichersystemsteuerung +openemsDeviceHardware = OpenEMS Geräte Hardware timedata = Timedata test = Test @@ -172,6 +173,30 @@ App.Hardware.KMtronic8Channel.Name = FEMS Relaisboard 8-Kanal TCP App.Hardware.KMtronic8Channel.Name.short = FEMS Relaisboard 8-Kanal TCP App.Hardware.KMtronic8Channel.ip.description = Die IP-Adresse des Relaisboards App.Hardware.KMtronic8Channel.installationHint = Hinweis: Stellen Sie vor der Installation sicher, dass das Relaisboard elektrisch als auch netzwerkseitig korrekt angeschlossen wurde. Andernfalls können Fehlermeldungen im Online-Monitoring auftreten. +App.Hardware.IoGpio.Name = IO GPIO +App.Hardware.IoGpio.Name.short = IO GPIO + +# Openems device hardware +App.OpenemsHardware.BeagleBoneBlack.Name = BeagleBoneBlack +App.OpenemsHardware.BeagleBoneBlack.Name.short = BeagleBoneBlack + +App.OpenemsHardware.Compulab.Name = Compulab +App.OpenemsHardware.Compulab.Name.short = Compulab + +App.OpenemsHardware.CM3.Name = Techbase Compute Module 3 +App.OpenemsHardware.CM3.Name.short = Techbase CM3 + +App.OpenemsHardware.CM4.Name = Techbase Compute Module 4 +App.OpenemsHardware.CM4.Name.short = Techbase CM4 + +App.OpenemsHardware.CM4S.Name = Techbase Compute Module 4S +App.OpenemsHardware.CM4S.Name.short = Techbase CM4S + +App.OpenemsHardware.CM4S.Gen2.Name = Techbase Compute Module 4S Gen 2 +App.OpenemsHardware.CM4S.Gen2.Name.short = Techbase CM4S Gen 2 + +App.OpenemsHardware.CM4Max.Name = Techbase Compute Module 4 Max +App.OpenemsHardware.CM4Max.Name.short = Techbase CM4 Max # Heat App.Heat.CHP.Name = Blockheizkraftwerk (BHKW) @@ -219,12 +244,14 @@ App.IntegratedSystem.gridMeterType.option.commercialMeter = Home 3-Phasensensor App.IntegratedSystem.ctRatioFirst.label = Wandler-Primärstrom (200A - 5000A/5A) App.IntegratedSystem.shadowManagementDisabled.label = Schattenmanagement deaktivieren App.IntegratedSystem.shadowManagementDisabled.description = Nur wenn Optimierer verbaut sind, muss das Schattenmanagement deaktiviert werden +App.IntegratedSystem.hasEssLimiter14a.label = Hat Limitierer für §14a App.IntegratedSystem.modbus0.alias = Kommunikation mit der Batterie App.IntegratedSystem.modbus0N.alias = Kommunikation mit den Batterien App.IntegratedSystem.modbus1.alias = Kommunikation mit dem Batterie-Wechselrichter App.IntegratedSystem.modbus1N.alias = Kommunikation mit dem Batterie-Wechselrichter {0} App.IntegratedSystem.modbus2.alias = externe RS485 Schnittstelle +App.IntegratedSystem.modbusToGridMeter.alias = Kommunikation mit dem Netzzähler App.IntegratedSystem.io0.alias = EMS Box Relais App.IntegratedSystem.battery0.alias = Batterie App.IntegratedSystem.batteryN.alias = Batterie {0} @@ -282,6 +309,19 @@ App.FENECON.Home.30.Name.short = FENECON Home 30 App.FENECON.Home.20.Name = FENECON Home 20 App.FENECON.Home.20.Name.short = FENECON Home 20 +App.FENECON.Commercial.92.Name = FENECON Commercial +App.FENECON.Commercial.92.Name.short = FENECON Commercial +App.FENECON.Industrial.L.io0 = Relais +App.FENECON.Industrial.L.Name = FENECON Industrial L +App.FENECON.Industrial.L.Name.short = FENECON Industrial L +App.FENECON.Industrial.L.modbus0.alias = Kommunikation mit dem Klimagerät +App.FENECON.Industrial.L.essN.alias = Batteriespeicher {0} + +App.FENECON.Industrial.L.ILK710.Name = FENECON Industrial L ILK710 +App.FENECON.Industrial.L.ILK710.Name.short = ILK710 +App.FENECON.Industrial.L.ILK710.batteryProtectionType.label = Battery Protection Typ +App.FENECON.Industrial.L.ILK710.batteryFirmwareVersion.label = Battery Firmware Version + App.FENECON.Industrial.S.io0 = Relais App.FENECON.Industrial.S.ess0.alias = Batteriespeicher App.FENECON.Industrial.S.essN.alias = Batteriespeicher {0} @@ -298,6 +338,7 @@ App.FENECON.Industrial.S.ISK011.Name = FENECON Industrial S ISK011 App.FENECON.Industrial.S.ISK011.Name.short = ISK011 # Meter +App.Meter.alias = Kommunikation mit dem Zähler App.Meter.mountType.label = Verwendungsart App.Meter.modbusUnitId.description = Modbus Unit-ID des Zählers App.Meter.ip.description = IP-Adresse des Zählers @@ -311,6 +352,11 @@ App.Meter.CarloGavazzi.Name.short = CARLO GAVAZZI App.Meter.Janitza.Name = Janitza Zähler App.Meter.Janitza.Name.short = Janitza App.Meter.Janitza.productModel = Gerätemodell +App.Meter.PqPlus.UMD96 = PQ-Plus Zähler UMD96 +App.Meter.PqPlus.UMD97 = PQ-Plus Zähler UMD97 +App.Meter.PqPlus.Name = PQ-Plus Zähler +App.Meter.PqPlus.Name.short = PQ-Plus +App.Meter.PqPlus.productModel = Gerätemodell App.Meter.Socomec.Name = SOCOMEC Zähler App.Meter.Socomec.Name.short = SOCOMEC App.Meter.Kdk.Name = KDK Zähler @@ -330,7 +376,8 @@ App.Meter.Discovergy.fullSerialNumber.label = Discovergy Komplette Seriennummer App.Meter.Discovergy.meterId.label = Discovergy MeterId App.Meter.Discovergy.meterId.description = Interne Zähler Id. Dieser is ein Hex String mit Länge 32. App.Meter.Discovergy.serialType.label = Typ der Seriennummer - +App.Meter.PhoenixContact.Name = PhoenixContact Zähler +App.Meter.PhoenixContact.Name.short = PhoenixContact # PeakShaving App.PeakShaving.power.label = Maximale Netzbezugsleistung @@ -443,6 +490,13 @@ App.Ess.FixStateOfCharge.targetSoc.label = Ziel-SoC App.Ess.FixStateOfCharge.targetTime.label = Zielzeit App.Ess.FixStateOfCharge.targetTimeBuffer.label = Zielzeitpuffer App.Ess.FixStateOfCharge.selfTermination.label = Beendet sich selbst am Ende -App.Ess.FixStateOfCharge.terminationBuffer.label = Zeitpuffer zum Beenden +App.Ess.FixStateOfCharge.terminationBuffer.label = Zeitpuffer zum Beenden App.Ess.FixStateOfCharge.conditionalTermination.label = Beendet sich selbst nach separater Bedingung -App.Ess.FixStateOfCharge.isRunning.label = Kontroller aktiv? \ No newline at end of file +App.Ess.FixStateOfCharge.isRunning.label = Kontroller aktiv? + +App.Ess.Limiter14a.Name = ESS Limiter für §14a +App.Ess.Limiter14a.Name.short = ESS Limiter §14a + +AppManager.DefectiveApp = Defekte App erkannt +AppManager.WrongAppConfiguration = App-Manager Konfiguration ist falsch +AppManager.AppsNotSynced = Die aktuell installierten Apps sind nicht dieselben wie im Backend hinterlegt diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties index 03cade10cfb..460116c4f56 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties @@ -11,6 +11,7 @@ meter = Production and consumption meter peakShaving = Peak shaving and atypical grid usage api = Interfaces ess = Energy Storage controller +openemsDeviceHardware = OpenEMS Device Hardware timedata = Timedata test = Test @@ -172,6 +173,30 @@ App.Hardware.KMtronic8Channel.Name = FEMS Relay board 8-channel TCP App.Hardware.KMtronic8Channel.Name.short = FEMS Relay board 8-channel TCP App.Hardware.KMtronic8Channel.ip.description = The IP address of the relay board App.Hardware.KMtronic8Channel.installationHint = Note: Before installing the relay board please make sure that it is connected correctly both electrically and to the network. Otherwise error messages in the Online-Monitoring may occur. +App.Hardware.IoGpio.Name = IO GPIO +App.Hardware.IoGpio.Name.short = IO GPIO + +# Openems device hardware +App.OpenemsHardware.BeagleBoneBlack.Name = BeagleBoneBlack +App.OpenemsHardware.BeagleBoneBlack.Name.short = BeagleBoneBlack + +App.OpenemsHardware.Compulab.Name = Compulab +App.OpenemsHardware.Compulab.Name.short = Compulab + +App.OpenemsHardware.CM3.Name = Techbase Compute Module 3 +App.OpenemsHardware.CM3.Name.short = Techbase CM3 + +App.OpenemsHardware.CM4.Name = Techbase Compute Module 4 +App.OpenemsHardware.CM4.Name.short = Techbase CM4 + +App.OpenemsHardware.CM4S.Name = Techbase Compute Module 4S +App.OpenemsHardware.CM4S.Name.short = Techbase CM4S + +App.OpenemsHardware.CM4S.Gen2.Name = Techbase Compute Module 4S Gen 2 +App.OpenemsHardware.CM4S.Gen2.Name.short = Techbase CM4S Gen 2 + +App.OpenemsHardware.CM4Max.Name = Techbase Compute Module 4 Max +App.OpenemsHardware.CM4Max.Name.short = Techbase CM4 Max # Heat App.Heat.CHP.Name = Combined heat and power plant (CHP) @@ -219,12 +244,14 @@ App.IntegratedSystem.gridMeterType.option.commercialMeter = Home 3-phase sensor App.IntegratedSystem.ctRatioFirst.label = CT-Ratio (200A - 5000A/5A) App.IntegratedSystem.shadowManagementDisabled.label = Deactivate shadow management App.IntegratedSystem.shadowManagementDisabled.description = Only if optimisers are installed, shadow management must be deactivated +App.IntegratedSystem.hasEssLimiter14a.label = Has limiter for §14a App.IntegratedSystem.modbus0.alias = Communication with the battery App.IntegratedSystem.modbus0N.alias = Communication with the batteries App.IntegratedSystem.modbus1.alias = Communication with the battery inverter App.IntegratedSystem.modbus1N.alias = Communication with the battery inverter {0} App.IntegratedSystem.modbus2.alias = external RS485 interface +App.IntegratedSystem.modbusToGridMeter.alias = Communication with the Grid-Meter App.IntegratedSystem.io0.alias = EMS Box Relay App.IntegratedSystem.battery0.alias = battery App.IntegratedSystem.batteryN.alias = battery {0} @@ -282,6 +309,19 @@ App.FENECON.Home.30.Name.short = FENECON Home 30 App.FENECON.Home.20.Name = FENECON Home 20 App.FENECON.Home.20.Name.short = FENECON Home 20 +App.FENECON.Commercial.92.Name = FENECON Commercial +App.FENECON.Commercial.92.Name.short = FENECON Commercial +App.FENECON.Industrial.L.io0 = Relay +App.FENECON.Industrial.L.Name = FENECON Industrial L +App.FENECON.Industrial.L.Name.short = FENECON Industrial L +App.FENECON.Industrial.L.modbus0.alias = Communication with Cooling Unit +App.FENECON.Industrial.L.essN.alias = Battery Storage {0} + +App.FENECON.Industrial.L.ILK710.Name = FENECON Industrial L ILK710 +App.FENECON.Industrial.L.ILK710.Name.short = ILK710 +App.FENECON.Industrial.L.ILK710.batteryProtectionType.label = Battery Protection Typ +App.FENECON.Industrial.L.ILK710.batteryFirmwareVersion.label = Battery Firmware Version + App.FENECON.Industrial.S.io0 = Relay App.FENECON.Industrial.S.ess0.alias = Battery Storage App.FENECON.Industrial.S.essN.alias = Battery Storage {0} @@ -298,6 +338,7 @@ App.FENECON.Industrial.S.ISK011.Name = FENECON Industrial S ISK011 App.FENECON.Industrial.S.ISK011.Name.short = ISK011 # Meter +App.Meter.alias = Communication with the Meter App.Meter.mountType.label = Mount Type App.Meter.modbusUnitId.description = Modbus Unit-ID of the Meter App.Meter.ip.description = IP address of the Meter @@ -311,6 +352,11 @@ App.Meter.CarloGavazzi.Name.short = CARLO GAVAZZI App.Meter.Janitza.Name = Janitza meter App.Meter.Janitza.Name.short = Janitza App.Meter.Janitza.productModel = Device model +App.Meter.PqPlus.UMD96 = PQ-Plus meter UMD96 +App.Meter.PqPlus.UMD97 = PQ-Plus meter UMD97 +App.Meter.PqPlus.Name = PQ-Plus meter +App.Meter.PqPlus.Name.short = PQ-Plus +App.Meter.PqPlus.productModel = Device model App.Meter.Socomec.Name = SOCOMEC meter App.Meter.Socomec.Name.short = SOCOMEC App.Meter.Kdk.Name = KDK meter @@ -330,6 +376,8 @@ App.Meter.Discovergy.fullSerialNumber.label = Discovergy Full Serial-Number App.Meter.Discovergy.meterId.label = Discovergy MeterId App.Meter.Discovergy.meterId.description = Internal MeterId. This is a hex string with length 32. App.Meter.Discovergy.serialType.label = Type of the serial number +App.Meter.PhoenixContact.Name = PhoenixContact Meter +App.Meter.PhoenixContact.Name.short = PhoenixContact # PeakShaving App.PeakShaving.power.label = Peak-Shaving power @@ -351,6 +399,7 @@ App.PeakShaving.PhaseAccuratePeakShaving.Name.short = Phase accurate peak shavin # PV inverter App.PvInverter.ip.description = IP address of the PV inverter. App.PvInverter.port.description = Port of the PV inverter. +App.PvInverter.modbusUnitId.description = Modbus Unit-ID of the PV inverter. App.PvInverter.phase.label = Phase App.PvInverter.phase.description = Connected phase(s) of the inverter @@ -366,7 +415,7 @@ App.PvInverter.Sma.modbusUnitId.description = The Unit-ID of the Modbus device. App.PvInverter.SolarEdge.Name = SolarEdge PV inverter App.PvInverter.SolarEdge.Name.short = SolarEdge -# Time of use Tarif +# Time of use Tariff App.TimeOfUseTariff.Awattar.Name = Time-of-Use Tariff (Awattar HOURLY) App.TimeOfUseTariff.Awattar.Name.short = Awattar HOURLY App.TimeOfUseTariff.Awattar.zone.label = Zone @@ -441,6 +490,13 @@ App.Ess.FixStateOfCharge.targetSoc.label = Target SoC App.Ess.FixStateOfCharge.targetTime.label = Target time [YYYY-MM-DDTHH:mm:ssTZD eg. 2023-12-15T13:47:20+01:00] App.Ess.FixStateOfCharge.targetTimeBuffer.label = Target time buffer App.Ess.FixStateOfCharge.selfTermination.label = Terminates itself at the end -App.Ess.FixStateOfCharge.terminationBuffer.label = Terminate time buffer in min +App.Ess.FixStateOfCharge.terminationBuffer.label = Terminate time buffer in min App.Ess.FixStateOfCharge.conditionalTermination.label = Terminates itself after separate condition App.Ess.FixStateOfCharge.isRunning.label = Controller active? + +App.Ess.Limiter14a.Name = ESS limiter for §14a +App.Ess.Limiter14a.Name.short = ESS limiter §14a + +AppManager.DefectiveApp = Defective App detected +AppManager.WrongAppConfiguration = App-Manager configuration is wrong +AppManager.AppsNotSynced = The currently installed apps are not the same as logged in the backend diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckCommercial92.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckCommercial92.java new file mode 100644 index 00000000000..2db34ca6fc4 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckCommercial92.java @@ -0,0 +1,51 @@ +package io.openems.edge.core.appmanager.validator; + +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ServiceScope; + +import io.openems.common.OpenemsConstants; +import io.openems.common.session.Language; + +@Component(// + name = CheckCommercial92.COMPONENT_NAME, // + scope = ServiceScope.PROTOTYPE // +) +public class CheckCommercial92 extends AbstractCheckable implements Checkable { + + public static final String COMPONENT_NAME = "Validator.Checkable.CheckCommercial92"; + + private final Checkable checkAppsNotInstalled; + + @Activate + public CheckCommercial92(// + ComponentContext componentContext, // + @Reference(target = "(" + OpenemsConstants.PROPERTY_OSGI_COMPONENT_NAME + "=" + + CheckAppsNotInstalled.COMPONENT_NAME + ")") Checkable checkAppsNotInstalled // + ) { + super(componentContext); + this.checkAppsNotInstalled = checkAppsNotInstalled; + } + + @Override + public boolean check() { + this.checkAppsNotInstalled.setProperties(Checkables.checkAppsNotInstalled(// + "App.FENECON.Commercial.92" // + ).properties()); + + return !this.checkAppsNotInstalled.check(); + } + + @Override + public String getErrorMessage(Language language) { + return AbstractCheckable.getTranslation(language, "Validator.Checkable.CheckCommercial92.Message"); + } + + @Override + public String getInvertedErrorMessage(Language language) { + return AbstractCheckable.getTranslation(language, "Validator.Checkable.CheckCommercial92.Message.Inverted"); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckHome.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckHome.java index 8d58d508b08..45dcf2223e4 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckHome.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckHome.java @@ -8,7 +8,6 @@ import io.openems.common.OpenemsConstants; import io.openems.common.session.Language; -import io.openems.edge.common.component.ComponentManager; @Component(// name = CheckHome.COMPONENT_NAME, // @@ -18,37 +17,27 @@ public class CheckHome extends AbstractCheckable implements Checkable { public static final String COMPONENT_NAME = "Validator.Checkable.CheckHome"; - private final ComponentManager componentManager; private final Checkable checkAppsNotInstalled; @Activate public CheckHome(// - @Reference ComponentManager componentManager, // ComponentContext componentContext, // @Reference(target = "(" + OpenemsConstants.PROPERTY_OSGI_COMPONENT_NAME + "=" + CheckAppsNotInstalled.COMPONENT_NAME + ")") Checkable checkAppsNotInstalled // ) { super(componentContext); - this.componentManager = componentManager; this.checkAppsNotInstalled = checkAppsNotInstalled; } @Override public boolean check() { - var batteries = this.componentManager.getEdgeConfig().getComponentsByFactory("Battery.Fenecon.Home"); this.checkAppsNotInstalled.setProperties(Checkables.checkAppsNotInstalled(// "App.FENECON.Home", // "App.FENECON.Home.20", // "App.FENECON.Home.30" // ).properties()); - // TODO remove check for batteries - // not every home has the home app installed but if a batterie of an home is - // installed its probably a home and so the app can be used. - // later there should only be checked if the home app is installed because if - // the configuration is wrong there may be no home battery installed and so the - // app wouldn't be available even though it is a home - return !batteries.isEmpty() || !this.checkAppsNotInstalled.check(); + return !this.checkAppsNotInstalled.check(); } @Override diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckOr.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckOr.java new file mode 100644 index 00000000000..eb277678027 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckOr.java @@ -0,0 +1,102 @@ +package io.openems.edge.core.appmanager.validator; + +import java.util.Map; +import java.util.Objects; + +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ServiceScope; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.openems.common.session.Language; +import io.openems.edge.core.appmanager.validator.CheckableFactory.ClosableCheckable; +import io.openems.edge.core.appmanager.validator.ValidatorConfig.CheckableConfig; + +@Component(// + name = CheckOr.COMPONENT_NAME, // + scope = ServiceScope.PROTOTYPE // +) +public class CheckOr extends AbstractCheckable implements Checkable { + + public static final String COMPONENT_NAME = "Validator.Checkable.CheckOr"; + + private final Logger log = LoggerFactory.getLogger(CheckOr.class); + + private final CheckableFactory checkableFactory; + + private CheckableConfig check1Config; + private ClosableCheckable check1; + private CheckableConfig check2Config; + private ClosableCheckable check2; + + @Activate + public CheckOr(// + ComponentContext componentContext, // + @Reference CheckableFactory checkableFactory // + ) { + super(componentContext); + this.checkableFactory = checkableFactory; + } + + @Deactivate + private void deactivate() { + try { + this.check1.close(); + } catch (Exception e) { + this.log.error("Unable to close checkable " + this.check1Config.checkableComponentName(), e); + } + try { + this.check2.close(); + } catch (Exception e) { + this.log.error("Unable to close checkable " + this.check2Config.checkableComponentName(), e); + } + } + + @Override + public void setProperties(Map properties) { + this.check1Config = Objects.requireNonNull((CheckableConfig) properties.get("check1"), + "First check must not be null"); + this.check2Config = Objects.requireNonNull((CheckableConfig) properties.get("check2"), + "Second check must not be null"); + } + + @Override + public boolean check() { + this.check1 = this.checkableFactory.useCheckable(this.check1Config.checkableComponentName()); + this.check1.setProperties(this.check1Config.properties()); + this.check2 = this.checkableFactory.useCheckable(this.check2Config.checkableComponentName()); + this.check2.setProperties(this.check2Config.properties()); + + final var check1Failed = this.check1.check() == this.check1Config.invertResult(); + final var check2Failed = this.check2.check() == this.check2Config.invertResult(); + return !(check1Failed && check2Failed); + } + + @Override + public String getErrorMessage(Language language) { + return AbstractCheckable.getTranslation(language, "Validator.Checkable.CheckOr.Message", + this.getCheck1ErrorMessage(language), this.getCheck2ErrorMessage(language)); + } + + @Override + public String getInvertedErrorMessage(Language language) { + throw new UnsupportedOperationException(); + } + + private String getCheck1ErrorMessage(Language language) { + return this.check1Config.invertResult() // + ? this.check1.getInvertedErrorMessage(language) + : this.check1.getErrorMessage(language); + } + + private String getCheck2ErrorMessage(Language language) { + return this.check2Config.invertResult() // + ? this.check2.getInvertedErrorMessage(language) + : this.check2.getErrorMessage(language); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckableFactory.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckableFactory.java new file mode 100644 index 00000000000..d96603c3d3f --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckableFactory.java @@ -0,0 +1,130 @@ +package io.openems.edge.core.appmanager.validator; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Consumer; + +import org.osgi.service.component.ComponentServiceObjects; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.component.annotations.ReferenceScope; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.openems.common.OpenemsConstants; +import io.openems.common.session.Language; + +@Component(// + service = CheckableFactory.class // +) +public class CheckableFactory { + + private final Logger log = LoggerFactory.getLogger(CheckableFactory.class); + + private final Map> checkableFactories = new HashMap<>(); + + /** + * Binds a {@link Checkable} {@link ComponentServiceObjects}. + * + * @param cso the cso to bind + */ + @Reference(// + cardinality = ReferenceCardinality.MULTIPLE, // + policy = ReferencePolicy.DYNAMIC, // + policyOption = ReferencePolicyOption.GREEDY, // + // requires prototype for thread safety + scope = ReferenceScope.PROTOTYPE_REQUIRED // + ) + public void bindCso(ComponentServiceObjects cso) { + var sr = cso.getServiceReference(); + var srName = (String) sr.getProperty(OpenemsConstants.PROPERTY_OSGI_COMPONENT_NAME); + this.checkableFactories.put(srName, cso); + } + + /** + * Unbinds a {@link Checkable} {@link ComponentServiceObjects}. + * + * @param cso the cso to unbind + */ + public void unbindCso(ComponentServiceObjects cso) { + var sr = cso.getServiceReference(); + var srName = (String) sr.getProperty(OpenemsConstants.PROPERTY_OSGI_COMPONENT_NAME); + this.checkableFactories.remove(srName); + } + + @Activate + public CheckableFactory() { + } + + /** + * Gets a {@link Checkable} which component name matches the provided name. + * + * @param checkableComponentName the component name to search for + * @return a found {@link Checkable} service or null if not found + */ + public ClosableCheckable useCheckable(String checkableComponentName) { + final var cso = this.checkableFactories.get(checkableComponentName); + if (cso == null) { + this.log.warn("Unable to find checkable with name '" + checkableComponentName + "'."); + return null; + } + + final var service = cso.getService(); + if (service == null) { + this.log.warn("Unable to create checkable with name '" + checkableComponentName + "'."); + return null; + } + + return new ClosableCheckable(service, t -> { + cso.ungetService(service); + }); + } + + public static class ClosableCheckable implements Checkable, AutoCloseable { + + private final Checkable checkable; + private final Consumer onClose; + + private ClosableCheckable(Checkable checkable, Consumer onClose) { + super(); + this.checkable = checkable; + this.onClose = onClose; + } + + @Override + public String getComponentName() { + return this.checkable.getComponentName(); + } + + @Override + public void setProperties(Map properties) { + this.checkable.setProperties(properties); + } + + @Override + public boolean check() { + return this.checkable.check(); + } + + @Override + public String getErrorMessage(Language language) { + return this.checkable.getErrorMessage(language); + } + + @Override + public String getInvertedErrorMessage(Language language) { + return this.checkable.getInvertedErrorMessage(language); + } + + @Override + public void close() throws Exception { + this.onClose.accept(this.checkable); + } + + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/Checkables.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/Checkables.java index 65b03fa36c4..32783117bed 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/Checkables.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/Checkables.java @@ -19,6 +19,32 @@ public static CheckableConfig checkHome() { return empty(CheckHome.COMPONENT_NAME); } + /** + * Creates a {@link CheckableConfig} which checks if the installed system is a + * Home. + * + * @return the {@link CheckableConfig} + */ + public static CheckableConfig checkCommercial92() { + return empty(CheckCommercial92.COMPONENT_NAME); + } + + /** + * Creates a {@link CheckableConfig} which checks if atleast one of the checks + * are successful. + * + * @param check1 the first check + * @param check2 the second check + * @return the {@link CheckableConfig} + */ + public static CheckableConfig checkOr(CheckableConfig check1, CheckableConfig check2) { + return new ValidatorConfig.CheckableConfig(CheckOr.COMPONENT_NAME, + new ValidatorConfig.MapBuilder<>(new TreeMap()) // + .put("check1", check1) // + .put("check2", check2) // + .build()); + } + /** * Creates a {@link CheckableConfig} which checks if the relay with the given * name has at least the given amount of ports available. diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/ValidatorConfig.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/ValidatorConfig.java index 8c7c05745a0..9598943b060 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/ValidatorConfig.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/ValidatorConfig.java @@ -74,6 +74,17 @@ public CheckableConfig invert() { ); } + /** + * Creates a {@link CheckableConfig} which checks if the current check is + * successful or the other check. + * + * @param other the other check + * @return the {@link CheckableConfig} + */ + public CheckableConfig or(CheckableConfig other) { + return Checkables.checkOr(this, other); + } + @Override public boolean equals(Object obj) { if (this == obj) { diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/ValidatorImpl.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/ValidatorImpl.java index d8868d85b75..77b03ae4253 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/ValidatorImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/ValidatorImpl.java @@ -5,70 +5,44 @@ import java.util.ArrayList; import java.util.List; -import org.osgi.service.component.ComponentServiceObjects; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; -import org.osgi.service.component.annotations.ReferenceCardinality; -import org.osgi.service.component.annotations.ReferencePolicy; -import org.osgi.service.component.annotations.ReferencePolicyOption; -import org.osgi.service.component.annotations.ReferenceScope; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.openems.common.OpenemsConstants; import io.openems.common.session.Language; import io.openems.edge.core.appmanager.validator.ValidatorConfig.CheckableConfig; @Component public class ValidatorImpl implements Validator { - private static final Logger LOG = LoggerFactory.getLogger(ValidatorImpl.class); + private final Logger log = LoggerFactory.getLogger(ValidatorImpl.class); - @Reference(// - cardinality = ReferenceCardinality.MULTIPLE, // - policy = ReferencePolicy.DYNAMIC, // - policyOption = ReferencePolicyOption.GREEDY, // - // requires prototype for thread safety - scope = ReferenceScope.PROTOTYPE_REQUIRED // - ) - private volatile List> checkableFactories; + private final CheckableFactory checkableFactory; @Activate - public ValidatorImpl() { + public ValidatorImpl(@Reference CheckableFactory checkableFactory) { + this.checkableFactory = checkableFactory; } @Override - public List getErrorMessages(List checkableConfigs, Language language, - boolean returnImmediate) { + public List getErrorMessages(// + final List checkableConfigs, // + final Language language, // + final boolean returnImmediate // + ) { if (checkableConfigs.isEmpty()) { return emptyList(); } final var errorMessages = new ArrayList(checkableConfigs.size()); for (var config : checkableConfigs) { - // find the componentServiceObjects base on the given configuration name - final var cso = this.checkableFactories.stream()// - .filter(csoCheckable -> { - var sr = csoCheckable.getServiceReference(); - var srName = (String) sr.getProperty(OpenemsConstants.PROPERTY_OSGI_COMPONENT_NAME); - return srName.equals(config.checkableComponentName()); - }).findAny().orElse(null); - - if (cso == null) { - LOG.info("Unable to get Checkable '" + config.checkableComponentName() + "'!"); - continue; - } - - // get the service from the cso - final var checkable = cso.getService(); - - if (checkable == null) { - LOG.info("Unable to get Checkable '" + config.checkableComponentName() + "'!"); - continue; - } + try (final var checkable = this.checkableFactory.useCheckable(config.checkableComponentName())) { + if (checkable == null) { + continue; + } - try { // validate checkable checkable.setProperties(config.properties()); var result = checkable.check(); @@ -78,8 +52,10 @@ public List getErrorMessages(List checkableConfigs, Lan errorMessage = config.invertResult() ? checkable.getInvertedErrorMessage(language) : checkable.getErrorMessage(language); } catch (UnsupportedOperationException e) { - LOG.error("Missing implementation for getting " + (config.invertResult() ? "inverted " : "") - + "error message for check \"" + config.checkableComponentName() + "\"!", e); + this.log.error( + "Missing implementation for getting " + (config.invertResult() ? "inverted " : "") + + "error message for check \"" + config.checkableComponentName() + "\"!", + e); errorMessage = "Check \"" + config.checkableComponentName() + "\" failed."; } errorMessages.add(errorMessage); @@ -87,9 +63,8 @@ public List getErrorMessages(List checkableConfigs, Lan return errorMessages; } } - } finally { - // free checkable from cso - cso.ungetService(checkable); + } catch (Exception e) { + this.log.error("Error while using checkable " + config.checkableComponentName() + "!", e); } } return errorMessages; diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/translation_de.properties b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/translation_de.properties index b43cee111a9..d5edecc681e 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/translation_de.properties +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/translation_de.properties @@ -6,6 +6,9 @@ Validator.Checkable.CheckCardinality.Message.Single = Es ist bereits eine App "{ Validator.Checkable.CheckHome.Message = Diese App benötigt ein Home System. Validator.Checkable.CheckHome.Message.Inverted = Diese App ist nicht für Home Systeme verfügbar. +Validator.Checkable.CheckCommercial92.Message = Diese App benötigt ein Commercial System. +Validator.Checkable.CheckCommercial92.Message.Inverted = Diese App ist nicht für Commercial System verfügbar. + Validator.Checkable.CheckHost.NotReachable = Gerät mit der IP "{0}" ist nicht erreichbar! Validator.Checkable.CheckHost.WrongIp = IP "{0}" ist keine valide IP-Adresse! @@ -13,3 +16,5 @@ Validator.Checkable.CheckNoComponentInstalledOfFactorieId.Message = Komponenten Validator.Checkable.CheckRelayCount.Message = Es sind nicht genug freie Digital-/Relaisausgänge verfügbar.

      Benötigt: {0}
      Verfügbar: {1} Validator.Checkable.CheckRelayCount.Message.AdditionalRelay =

      {1} für weitere Ausgänge erwerben. + +Validator.Checkable.CheckOr.Message = {0} - oder - {1} \ No newline at end of file diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/translation_en.properties b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/translation_en.properties index aa0657e25cd..204566bcbd8 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/translation_en.properties +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/translation_en.properties @@ -6,6 +6,9 @@ Validator.Checkable.CheckCardinality.Message.Single = There is already an app "{ Validator.Checkable.CheckHome.Message = This App requires a Home System. Validator.Checkable.CheckHome.Message.Inverted = This App is not available for Home systems. +Validator.Checkable.CheckCommercial92.Message = This App requires a Commercial System. +Validator.Checkable.CheckCommercial92.Message.Inverted = This App is not available for Commercial System. + Validator.Checkable.CheckHost.NotReachable = Device with IP "{0}" is not reachable! Validator.Checkable.CheckHost.WrongIp = IP "{0}" is not a valid IP-Address! @@ -13,3 +16,5 @@ Validator.Checkable.CheckNoComponentInstalledOfFactorieId.Message = Components w Validator.Checkable.CheckRelayCount.Message = There are not enough Digital-/Relay ports available.

      Required: {0}
      Available: {1} Validator.Checkable.CheckRelayCount.Message.AdditionalRelay =

      Buy {1} for more outputs. + +Validator.Checkable.CheckOr.Message = {0} - or - {1} \ No newline at end of file diff --git a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java index 2dd6105f73c..3029e0d6a04 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java @@ -49,6 +49,7 @@ import io.openems.common.jsonrpc.request.UpdateComponentConfigRequest; import io.openems.common.jsonrpc.request.UpdateComponentConfigRequest.Property; import io.openems.common.jsonrpc.response.GetEdgeConfigResponse; +import io.openems.common.session.Language; import io.openems.common.session.Role; import io.openems.common.types.ChannelAddress; import io.openems.common.types.EdgeConfig; @@ -368,12 +369,12 @@ public void buildJsonApiRoutes(JsonApiBuilder builder) { Handles a GetStateChannelsOfComponent. """); }, call -> { - // TODO could be used for translating channel texts - // final var user = call.get(EdgeKeys.USER_KEY); + final var user = call.get(EdgeKeys.USER_KEY); + final var lang = user.getLanguage(); final var channels = this.getPossiblyDisabledComponent(call.getRequest().componentId()).channels().stream() // .filter(t -> t.channelDoc().getChannelCategory() == ChannelCategory.STATE) // - .map(ComponentManagerImpl::toChannelRecord) // + .map(channel -> ComponentManagerImpl.toChannelRecord(channel, lang)) // .toList(); return new GetStateChannelsOfComponent.Response(channels); @@ -384,10 +385,12 @@ public void buildJsonApiRoutes(JsonApiBuilder builder) { Handles a GetStateChannelsOfComponent. """); }, call -> { + + final var user = call.get(EdgeKeys.USER_KEY); + final var lang = user.getLanguage(); final var channels = this.getPossiblyDisabledComponent(call.getRequest().componentId()).channels().stream() // - .map(ComponentManagerImpl::toChannelRecord) // + .map(channel -> ComponentManagerImpl.toChannelRecord(channel, lang)) // .toList(); - return new GetChannelsOfComponent.Response(channels); }); @@ -399,7 +402,9 @@ public void buildJsonApiRoutes(JsonApiBuilder builder) { final var request = call.getRequest(); final var channel = this.getChannel(new ChannelAddress(request.componentId(), request.channelId())); - return new GetChannel.Response(toChannelRecord(channel)); + final var user = call.get(EdgeKeys.USER_KEY); + final var lang = user.getLanguage(); + return new GetChannel.Response(toChannelRecord(channel, lang)); }); builder.handleRequest(new GetDigitalInputChannelsOfComponents(), endpoint -> { @@ -408,10 +413,12 @@ public void buildJsonApiRoutes(JsonApiBuilder builder) { """); }, call -> { + final var user = call.get(EdgeKeys.USER_KEY); + final var lang = user.getLanguage(); final var result = this.getEnabledComponentsOfType(DigitalInput.class).stream() // .filter(t -> call.getRequest().componentIds().contains(t.id())) // .collect(toMap(OpenemsComponent::id, t -> Arrays.stream(t.digitalInputChannels()) // - .map(ComponentManagerImpl::toChannelRecord) // + .map(channel -> ComponentManagerImpl.toChannelRecord(channel, lang)) // .toList())); return new GetDigitalInputChannelsOfComponents.Response(result); @@ -450,12 +457,12 @@ public void buildJsonApiRoutes(JsonApiBuilder builder) { }); } - private static ChannelRecord toChannelRecord(Channel channel) { + private static ChannelRecord toChannelRecord(Channel channel, Language language) { return new GetChannelsOfComponent.ChannelRecord(// channel.channelId().id(), // channel.channelDoc().getAccessMode(), // channel.channelDoc().getPersistencePriority(), // - channel.channelDoc().getText(), // + channel.channelDoc().getText(language), // channel.channelDoc().getType(), // channel.channelDoc().getUnit(), // channel.channelDoc().getChannelCategory(), // diff --git a/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome.java b/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome.java index f95d671afdf..91ea3e5a532 100644 --- a/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome.java +++ b/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome.java @@ -2,9 +2,12 @@ import static io.openems.edge.common.test.DummyUser.DUMMY_ADMIN; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import com.google.gson.JsonObject; @@ -31,7 +34,8 @@ public void beforeEach() throws Exception { Apps::gridOptimizedCharge, // Apps::selfConsumptionOptimization, // Apps::socomecMeter, // - Apps::prepareBatteryExtension // + Apps::prepareBatteryExtension, // + Apps::limiter14a // ); }, null, new PseudoComponentManagerFactory()); @@ -46,52 +50,25 @@ public void testCreateHomeFullSettings() throws Exception { @Test public void testCreateAndUpdateHomeFullSettings() throws Exception { - var fullConfig = JsonUtils.buildJsonObject() // - .addProperty("SAFETY_COUNTRY", "GERMANY") // - .addProperty("RIPPLE_CONTROL_RECEIVER_ACTIV", false) // - .addProperty("MAX_FEED_IN_POWER", 1000) // - .addProperty("FEED_IN_SETTING", "LAGGING_0_95") // - .addProperty("HAS_AC_METER", true) // - .addProperty("HAS_DC_PV1", true) // - .addProperty("DC_PV1_ALIAS", "alias pv 1") // - .addProperty("HAS_DC_PV2", true) // - .addProperty("DC_PV2_ALIAS", "alias pv 2") // - .addProperty("HAS_EMERGENCY_RESERVE", true) // - .addProperty("EMERGENCY_RESERVE_ENABLED", true) // - .addProperty("EMERGENCY_RESERVE_SOC", 15) // - .addProperty("SHADOW_MANAGEMENT_DISABLED", false) // - .build(); var homeInstance = this.createFullHome(); this.appManagerTestBundle.sut.handleUpdateAppInstanceRequest(DUMMY_ADMIN, - new UpdateAppInstance.Request(homeInstance.instanceId, "aliasrename", fullConfig)); + new UpdateAppInstance.Request(homeInstance.instanceId, "aliasrename", fullSettings())); // expect the same as before // make sure every dependency got installed - assertEquals(this.appManagerTestBundle.sut.getInstantiatedApps().size(), 5); + assertEquals(5, this.appManagerTestBundle.sut.getInstantiatedApps().size()); // check properties of created apps for (var instance : this.appManagerTestBundle.sut.getInstantiatedApps()) { - int expectedDependencies; - switch (instance.appId) { - case "App.FENECON.Home": - expectedDependencies = 4; - break; - case "App.PvSelfConsumption.GridOptimizedCharge": - expectedDependencies = 0; - break; - case "App.PvSelfConsumption.SelfConsumptionOptimization": - expectedDependencies = 0; - break; - case "App.Meter.Socomec": - expectedDependencies = 0; - break; - case "App.Ess.PrepareBatteryExtension": - expectedDependencies = 0; - break; - default: - throw new Exception("App with ID[" + instance.appId + "] should not have been created!"); - } + final var expectedDependencies = switch (instance.appId) { + case "App.FENECON.Home" -> 4; + case "App.PvSelfConsumption.GridOptimizedCharge" -> 0; + case "App.PvSelfConsumption.SelfConsumptionOptimization" -> 0; + case "App.Meter.Socomec" -> 0; + case "App.Ess.PrepareBatteryExtension" -> 0; + default -> throw new Exception("App with ID[" + instance.appId + "] should not have been created!"); + }; if (expectedDependencies == 0 && instance.dependencies == null) { continue; } @@ -108,6 +85,7 @@ public void testRemoveAcMeter() throws Exception { .addProperty("RIPPLE_CONTROL_RECEIVER_ACTIV", false) // .addProperty("MAX_FEED_IN_POWER", 1000) // .addProperty("FEED_IN_SETTING", "LAGGING_0_95") // + .addProperty("HAS_ESS_LIMITER_14A", false) // .addProperty("HAS_AC_METER", false) // .addProperty("HAS_DC_PV1", true) // .addProperty("DC_PV1_ALIAS", "alias pv 1") // @@ -123,27 +101,17 @@ public void testRemoveAcMeter() throws Exception { new UpdateAppInstance.Request(homeInstance.instanceId, "aliasrename", configNoMeter)); // expect the same as before // make sure every dependency got installed - assertEquals(this.appManagerTestBundle.sut.getInstantiatedApps().size(), 4); + assertEquals(4, this.appManagerTestBundle.sut.getInstantiatedApps().size()); // check properties of created apps for (var instance : this.appManagerTestBundle.sut.getInstantiatedApps()) { - int expectedDependencies; - switch (instance.appId) { - case "App.FENECON.Home": - expectedDependencies = 3; - break; - case "App.PvSelfConsumption.GridOptimizedCharge": - expectedDependencies = 0; - break; - case "App.PvSelfConsumption.SelfConsumptionOptimization": - expectedDependencies = 0; - break; - case "App.Ess.PrepareBatteryExtension": - expectedDependencies = 0; - break; - default: - throw new Exception("App with ID[" + instance.appId + "] should not have been created!"); - } + final var expectedDependencies = switch (instance.appId) { + case "App.FENECON.Home" -> 3; + case "App.PvSelfConsumption.GridOptimizedCharge" -> 0; + case "App.PvSelfConsumption.SelfConsumptionOptimization" -> 0; + case "App.Ess.PrepareBatteryExtension" -> 0; + default -> throw new Exception("App with ID[" + instance.appId + "] should not have been created!"); + }; if (expectedDependencies == 0 && instance.dependencies == null) { continue; } @@ -194,6 +162,30 @@ public void testFeedInTypeNoLimitation() throws Exception { assertEquals("DISABLE", batteryInverterProps.get("rcrEnable")); } + @Test + @Ignore + public void testEnableLimiter14a() throws Exception { + final var createSettings = fullSettings(); + createSettings.addProperty(FeneconHome.Property.HAS_ESS_LIMITER_14A.name(), false); + + final var createResponse = this.appManagerTestBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, + new AddAppInstance.Request("App.FENECON.Home", "key", "alias", createSettings)); + + assertEquals(4, createResponse.instance().dependencies.size()); + assertFalse(this.appManagerTestBundle.sut.getInstantiatedApps().stream() + .anyMatch(a -> a.appId.equals("App.Ess.Limiter14a"))); + + final var updateSettings = fullSettings(); + createSettings.addProperty(FeneconHome.Property.HAS_ESS_LIMITER_14A.name(), true); + final var updateResponse = this.appManagerTestBundle.sut.handleUpdateAppInstanceRequest(DUMMY_ADMIN, + new UpdateAppInstance.Request(createResponse.instance().instanceId, "alias", updateSettings)); + + assertEquals(5, updateResponse.instance().dependencies.size()); + assertTrue(this.appManagerTestBundle.sut.getInstantiatedApps().stream() + .anyMatch(a -> a.appId.equals("App.Ess.Limiter14a"))); + + } + private final OpenemsAppInstance createFullHome() throws Exception { return createFullHome(this.appManagerTestBundle, DUMMY_ADMIN); } @@ -216,7 +208,7 @@ public static final OpenemsAppInstance createFullHome(AppManagerTestBundle appMa assertEquals(4, response.instance().dependencies.size()); // make sure every dependency got installed - assertEquals(appManagerTestBundle.sut.getInstantiatedApps().size(), 5); + assertEquals(5, appManagerTestBundle.sut.getInstantiatedApps().size()); // check properties of created apps for (var instance : appManagerTestBundle.sut.getInstantiatedApps()) { @@ -252,6 +244,7 @@ public static final JsonObject fullSettings() { .addProperty("RIPPLE_CONTROL_RECEIVER_ACTIV", false) // .addProperty("MAX_FEED_IN_POWER", 1000) // .addProperty("FEED_IN_SETTING", "LAGGING_0_95") // + .addProperty("HAS_ESS_LIMITER_14A", false) // .addProperty("HAS_AC_METER", true) // .addProperty("HAS_DC_PV1", true) // .addProperty("DC_PV1_ALIAS", "alias pv 1") // diff --git a/io.openems.edge.core/test/io/openems/edge/app/timeofusetariff/TestTibber.java b/io.openems.edge.core/test/io/openems/edge/app/timeofusetariff/TestTibber.java index da9a0d9deec..cb4227e2309 100644 --- a/io.openems.edge.core/test/io/openems/edge/app/timeofusetariff/TestTibber.java +++ b/io.openems.edge.core/test/io/openems/edge/app/timeofusetariff/TestTibber.java @@ -11,7 +11,6 @@ import java.util.List; import java.util.Optional; import java.util.Set; -import java.util.concurrent.ExecutionException; import java.util.stream.Stream; import org.junit.Before; @@ -25,11 +24,13 @@ import io.openems.common.jsonrpc.request.CreateComponentConfigRequest; import io.openems.common.jsonrpc.request.UpdateComponentConfigRequest; import io.openems.common.utils.JsonUtils; -import io.openems.edge.app.integratedsystem.TestFeneconHome; import io.openems.edge.core.appmanager.AppManagerTestBundle; import io.openems.edge.core.appmanager.AppManagerTestBundle.PseudoComponentManagerFactory; import io.openems.edge.core.appmanager.Apps; import io.openems.edge.core.appmanager.jsonrpc.AddAppInstance; +import io.openems.edge.core.appmanager.validator.CheckAppsNotInstalled; +import io.openems.edge.core.appmanager.validator.CheckCommercial92; +import io.openems.edge.core.appmanager.validator.CheckHome; public class TestTibber { @@ -40,8 +41,7 @@ public class TestTibber { public void beforeEach() throws Exception { this.appManagerTestBundle = new AppManagerTestBundle(null, null, t -> { return ImmutableList.of(// - this.tibber = Apps.tibber(t), // - Apps.feneconHome(t) // + this.tibber = Apps.tibber(t) // ); }, null, new PseudoComponentManagerFactory()); @@ -52,8 +52,6 @@ public void beforeEach() throws Exception { @Test public void testRemoveAccessToken() throws Exception { - this.installHome(); - final var properties = JsonUtils.buildJsonObject() // .addProperty("ACCESS_TOKEN", "g78aw9ht2n112nb453") // .build(); @@ -83,7 +81,6 @@ public void testRemoveAccessToken() throws Exception { @Test public void testAddChannelToPredictor() throws Exception { this.createPredictor(); - this.installHome(); final var properties = JsonUtils.buildJsonObject() // .addProperty("ACCESS_TOKEN", "g78aw9ht2n112nb453") // @@ -95,7 +92,14 @@ public void testAddChannelToPredictor() throws Exception { } @Test(expected = OpenemsNamedException.class) - public void testOnlyCompatibleWithHome() throws Exception { + public void testOnlyCompatibleWithHomeOrCommercial() throws Exception { + this.appManagerTestBundle.addCheckable(CheckHome.COMPONENT_NAME, + t -> new CheckHome(t, new CheckAppsNotInstalled(this.appManagerTestBundle.sut, + AppManagerTestBundle.getComponentContext(CheckAppsNotInstalled.COMPONENT_NAME)))); + this.appManagerTestBundle.addCheckable(CheckCommercial92.COMPONENT_NAME, + t -> new CheckCommercial92(t, new CheckAppsNotInstalled(this.appManagerTestBundle.sut, + AppManagerTestBundle.getComponentContext(CheckAppsNotInstalled.COMPONENT_NAME)))); + final var properties = JsonUtils.buildJsonObject() // .addProperty("ACCESS_TOKEN", "g78aw9ht2n112nb453") // .build(); @@ -105,7 +109,6 @@ public void testOnlyCompatibleWithHome() throws Exception { @Test public void testSetTokenValue() throws Exception { - this.installHome(); final var properties = JsonUtils.buildJsonObject() // .addProperty("ACCESS_TOKEN", "g78aw9ht2n112nb453") // .build(); @@ -131,7 +134,6 @@ public void testSetTokenValue() throws Exception { @Test public void testUnsetFilterValue() throws Exception { - this.installHome(); final var properties = JsonUtils.buildJsonObject() // .addProperty(Tibber.Property.ACCESS_TOKEN.name(), "g78aw9ht2n112nb453") // .addProperty(Tibber.Property.MULTIPLE_HOMES_CHECK.name(), true) // @@ -170,11 +172,6 @@ private void createPredictor() throws Exception { ))); } - private void installHome() throws InterruptedException, ExecutionException, OpenemsNamedException { - this.appManagerTestBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, - new AddAppInstance.Request("App.FENECON.Home", "key", "alias", TestFeneconHome.minSettings())); - } - private void assertChannelsInPredictor(String... channels) throws OpenemsNamedException { final var existingAddresses = this.getChannelsInPredictor(); final var expectedChannels = Stream.of(channels).collect(toSet()); diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerImpSynchronizationTest.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerImpSynchronizationTest.java deleted file mode 100644 index 9b79d51b330..00000000000 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerImpSynchronizationTest.java +++ /dev/null @@ -1,199 +0,0 @@ -package io.openems.edge.core.appmanager; - -import static io.openems.edge.common.test.DummyUser.DUMMY_ADMIN; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; - -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; - -import com.google.common.collect.Lists; - -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.utils.JsonUtils; -import io.openems.common.utils.ReflectionUtils; -import io.openems.edge.app.evcs.KebaEvcs; -import io.openems.edge.common.test.ComponentTest; -import io.openems.edge.common.test.DummyComponentContext; -import io.openems.edge.common.test.DummyComponentManager; -import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.core.appmanager.AppManagerTestBundle.CheckablesBundle; -import io.openems.edge.core.appmanager.DummyValidator.TestCheckable; -import io.openems.edge.core.appmanager.dependency.AppManagerAppHelper; -import io.openems.edge.core.appmanager.jsonrpc.AddAppInstance; -import io.openems.edge.core.appmanager.jsonrpc.DeleteAppInstance; -import io.openems.edge.core.appmanager.validator.CheckAppsNotInstalled; -import io.openems.edge.core.appmanager.validator.CheckCardinality; -import io.openems.edge.core.appmanager.validator.CheckHome; -import io.openems.edge.core.appmanager.validator.relaycount.CheckRelayCount; - -public class AppManagerImpSynchronizationTest { - - private AppManagerImpl appManager; - - @Before - public void before() throws Exception { - this.appManager = new AppManagerImpl(); - ReflectionUtils.setAttribute(AppManagerImpl.class, this.appManager, "appValidateWorker", - new AppValidateWorker()); - assertTrue(this.appManager.lockModifyingApps.tryLock()); - this.appManager.lockModifyingApps.unlock(); - assertFalse(this.appManager.waitingForModified); - - final var cm = new DummyConfigurationAdmin(); - final var componentManager = new DummyComponentManager(); - componentManager.setConfigJson(JsonUtils.buildJsonObject() // - .add("components", JsonUtils.buildJsonObject() // - .add("scheduler0", JsonUtils.buildJsonObject() // - .addProperty("factoryId", "Scheduler.AllAlphabetically") // - .add("properties", JsonUtils.buildJsonObject() // - .addProperty("enabled", true) // - .add("controllers.ids", JsonUtils.buildJsonArray() // - .build()) // - .build()) // - .build()) - .build()) - .add("factories", JsonUtils.buildJsonObject() // - .build()) - .build()); - componentManager.setConfigurationAdmin(cm); - - // create config for scheduler - cm.getOrCreateEmptyConfiguration(componentManager.getEdgeConfig().getComponent("scheduler0").get().getPid()); - final var componentUtil = new ComponentUtilImpl(componentManager); - final var appManagerUtil = new AppManagerUtilImpl(componentManager); - final var validator = new DummyValidator(); - - final var checkablesBundle = new CheckablesBundle(// - new TestCheckable(), // - new CheckCardinality(this.appManager, appManagerUtil, - AppManagerTestBundle.getComponentContext(CheckCardinality.COMPONENT_NAME)), // - new CheckRelayCount(componentUtil, - AppManagerTestBundle.getComponentContext(CheckRelayCount.COMPONENT_NAME), null), // - new CheckAppsNotInstalled(this.appManager, - AppManagerTestBundle.getComponentContext(CheckAppsNotInstalled.COMPONENT_NAME)), // - new CheckHome(this.appManager.componentManager, - AppManagerTestBundle.getComponentContext(CheckHome.COMPONENT_NAME), - new CheckAppsNotInstalled(this.appManager, - AppManagerTestBundle.getComponentContext(CheckAppsNotInstalled.COMPONENT_NAME))) // - ); - - validator.setCheckables(checkablesBundle.all()); - - new ComponentTest(this.appManager) // - .addReference("cm", cm) // - .addReference("componentManager", componentManager) // - .addReference("csoAppManagerAppHelper", - AppManagerTestBundle.cso( - new DummyAppManagerAppHelper(componentManager, componentUtil, appManagerUtil))) // - .addReference("validator", validator) // - .addReference("backendUtil", new DummyAppCenterBackendUtil()) // - .addReference("availableApps", Lists.newArrayList(// - new KebaEvcs(componentManager, - AppManagerTestBundle.getComponentContext("App.PvInverter.SolarEdge"), cm, componentUtil) // - )) // - .activate(MyConfig.create() // - .setApps("[]") // - .build()); - - assertTrue(this.appManager.lockModifyingApps.tryLock()); - this.appManager.lockModifyingApps.unlock(); - assertFalse(this.appManager.waitingForModified); - } - - @Test - public void testInstallationOfNotAvailableApp() throws Exception { - try { - this.appManager.handleAddAppInstanceRequest(DUMMY_ADMIN, - new AddAppInstance.Request("someAppId", "key", "alias", JsonUtils.buildJsonObject() // - .build())); - } catch (OpenemsNamedException e) { - // expected - } - - // if app is not existing no need to modify - assertTrue(this.appManager.lockModifyingApps.tryLock()); - this.appManager.lockModifyingApps.unlock(); - assertFalse(this.appManager.waitingForModified); - } - - @Test - public void testRemoveOfNotAvailableInstance() throws Exception { - try { - this.appManager.handleDeleteAppInstanceRequest(DUMMY_ADMIN, - new DeleteAppInstance.Request(UUID.randomUUID())); - } catch (OpenemsNamedException e) { - // expected - } - - // if instance is not existing no need to modify - assertTrue(this.appManager.lockModifyingApps.tryLock()); - this.appManager.lockModifyingApps.unlock(); - assertFalse(this.appManager.waitingForModified); - } - - @Test - public void testSimulateAfterInstallaion() throws Exception { - this.appManager.handleAddAppInstanceRequest(DUMMY_ADMIN, - new AddAppInstance.Request("App.PvInverter.SolarEdge", "key", "alias", JsonUtils.buildJsonObject() // - .build())); - - assertTrue(this.appManager.lockModifyingApps.tryLock()); - assertTrue(this.appManager.waitingForModified); - assertFalse(this.appManager.waitingForModifiedCondition.await(1, TimeUnit.MILLISECONDS)); - this.appManager.lockModifyingApps.unlock(); - } - - @Test - @Ignore - public void testSimulateLockWaitingForModification() throws Exception { - this.appManager.handleAddAppInstanceRequest(DUMMY_ADMIN, - new AddAppInstance.Request("App.PvInverter.SolarEdge", "key", "alias", JsonUtils.buildJsonObject() // - .build())); - - assertTrue(this.appManager.waitingForModified); - - final var second = CompletableFuture.supplyAsync(() -> { - try { - return this.appManager.handleAddAppInstanceRequest(DUMMY_ADMIN, - new AddAppInstance.Request("App.PvInverter.SolarEdge", "key", "alias", - JsonUtils.buildJsonObject() // - .build())); - } catch (OpenemsNamedException e) { - throw new RuntimeException(e); - } - }); - - Thread.sleep(5000); - assertFalse(second.isDone()); - - this.appManager.modified(new DummyComponentContext(), MyConfig.create() // - .setApps("[]") // - .build()); - - Thread.sleep(5000); - assertTrue(second.isDone()); - } - - @Test - public void testSimulateBeforeModified() throws Exception { - // simulate after an instance got created and the configuration was requested to - // update - assertTrue(this.appManager.lockModifyingApps.tryLock()); - this.appManager.waitingForModified = true; - this.appManager.lockModifyingApps.unlock(); - - this.appManager.modified(new DummyComponentContext(), MyConfig.create() // - .setApps("[]") // - .build()); - - assertTrue(this.appManager.lockModifyingApps.tryLock()); - assertFalse(this.appManager.waitingForModified); - } - -} diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerImplSynchronizationTest.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerImplSynchronizationTest.java new file mode 100644 index 00000000000..f5f69288d0c --- /dev/null +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerImplSynchronizationTest.java @@ -0,0 +1,128 @@ +package io.openems.edge.core.appmanager; + +import static io.openems.edge.common.test.DummyUser.DUMMY_ADMIN; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import com.google.common.collect.ImmutableList; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.common.test.DummyComponentContext; +import io.openems.edge.core.appmanager.AppManagerTestBundle.PseudoComponentManagerFactory; +import io.openems.edge.core.appmanager.jsonrpc.AddAppInstance; +import io.openems.edge.core.appmanager.jsonrpc.DeleteAppInstance; + +public class AppManagerImplSynchronizationTest { + + private AppManagerImpl appManager; + + @Before + public void before() throws Exception { + final var appManagerTestBundle = new AppManagerTestBundle(null, null, t -> { + return ImmutableList.of(// + Apps.kebaEvcs(t), // + Apps.solarEdgePvInverter(t) // + ); + }, null, new PseudoComponentManagerFactory(), new AppManagerImpl()); + + this.appManager = appManagerTestBundle.sut; + + assertTrue(this.appManager.lockModifyingApps.tryLock()); + this.appManager.lockModifyingApps.unlock(); + assertFalse(this.appManager.waitingForModified); + } + + @Test + public void testInstallationOfNotAvailableApp() throws Exception { + assertThrows(OpenemsNamedException.class, () -> { + this.appManager.handleAddAppInstanceRequest(DUMMY_ADMIN, + new AddAppInstance.Request("someAppId", "key", "alias", JsonUtils.buildJsonObject() // + .build())); + }); + + // if app is not existing no need to modify + assertTrue(this.appManager.lockModifyingApps.tryLock()); + this.appManager.lockModifyingApps.unlock(); + assertFalse(this.appManager.waitingForModified); + } + + @Test + public void testRemoveOfNotAvailableInstance() throws Exception { + this.appManager.handleDeleteAppInstanceRequest(DUMMY_ADMIN, new DeleteAppInstance.Request(UUID.randomUUID())); + + // if instance is not existing no need to modify + assertTrue(this.appManager.lockModifyingApps.tryLock()); + this.appManager.lockModifyingApps.unlock(); + assertFalse(this.appManager.waitingForModified); + } + + @Test + public void testSimulateAfterInstallation() throws Exception { + assertTrue(this.appManager.lockModifyingApps.tryLock()); + this.appManager.handleAddAppInstanceRequest(DUMMY_ADMIN, + new AddAppInstance.Request("App.PvInverter.SolarEdge", "key", "alias", JsonUtils.buildJsonObject() // + .build())); + + assertTrue(this.appManager.waitingForModified); + assertFalse(this.appManager.waitingForModifiedCondition.await(1, TimeUnit.MILLISECONDS)); + this.appManager.lockModifyingApps.unlock(); + } + + @Test + @Ignore + public void testSimulateLockWaitingForModification() throws Exception { + this.appManager.handleAddAppInstanceRequest(DUMMY_ADMIN, + new AddAppInstance.Request("App.PvInverter.SolarEdge", "key", "alias", JsonUtils.buildJsonObject() // + .build())); + + assertTrue(this.appManager.waitingForModified); + + final var second = CompletableFuture.supplyAsync(() -> { + try { + return this.appManager.handleAddAppInstanceRequest(DUMMY_ADMIN, + new AddAppInstance.Request("App.PvInverter.SolarEdge", "key", "alias", + JsonUtils.buildJsonObject() // + .build())); + } catch (OpenemsNamedException e) { + throw new RuntimeException(e); + } + }); + + Thread.sleep(5000); + assertFalse(second.isDone()); + + this.appManager.modified(new DummyComponentContext(), MyConfig.create() // + .setApps("[]") // + .build()); + + Thread.sleep(5000); + assertTrue(second.isDone()); + } + + @Test + public void testSimulateBeforeModified() throws Exception { + // simulate after an instance got created and the configuration was requested to + // update + assertTrue(this.appManager.lockModifyingApps.tryLock()); + this.appManager.waitingForModified = true; + this.appManager.lockModifyingApps.unlock(); + + this.appManager.modified(new DummyComponentContext(), MyConfig.create() // + .setApps("[]") // + .build()); + + assertTrue(this.appManager.lockModifyingApps.tryLock()); + assertFalse(this.appManager.waitingForModified); + } + +} diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerImplTest.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerImplTest.java index 3e74b994890..ca463981dd4 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerImplTest.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerImplTest.java @@ -323,7 +323,7 @@ public void testFindAppById() { @Test public void testCheckCardinalitySingle() throws Exception { - var checkable = this.appManagerTestBundle.checkablesBundle.checkCardinality(); + var checkable = this.appManagerTestBundle.getCheckCardinality(); checkable.setProperties(new ValidatorConfig.MapBuilder<>(new TreeMap()) // .put("openemsApp", this.homeApp) // .build()); @@ -337,7 +337,7 @@ public void testCheckCardinalityMultiple() throws Exception { UUID.randomUUID(), JsonUtils.buildJsonObject().build(), null)); this.appManagerTestBundle.sut.instantiatedApps.add(new OpenemsAppInstance(this.kebaEvcsApp.getAppId(), "alias", UUID.randomUUID(), JsonUtils.buildJsonObject().build(), null)); - var checkable = this.appManagerTestBundle.checkablesBundle.checkCardinality(); + var checkable = this.appManagerTestBundle.getCheckCardinality(); checkable.setProperties(new ValidatorConfig.MapBuilder<>(new TreeMap()) // .put("openemsApp", this.kebaEvcsApp) // .build()); @@ -349,12 +349,11 @@ public void testCheckCardinalityMultiple() throws Exception { public void testCheckCardinalitySingleInCategorie() throws Exception { this.appManagerTestBundle.sut.instantiatedApps.add(new OpenemsAppInstance(this.awattarApp.getAppId(), "alias", UUID.randomUUID(), JsonUtils.buildJsonObject().build(), null)); - var checkable = this.appManagerTestBundle.checkablesBundle.checkCardinality(); + var checkable = this.appManagerTestBundle.getCheckCardinality(); checkable.setProperties(new ValidatorConfig.MapBuilder<>(new TreeMap()) // .put("openemsApp", this.stromdao) // .build()); assertFalse(checkable.check()); assertNotNull(checkable.getErrorMessage(Language.DEFAULT)); } - } diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerTestBundle.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerTestBundle.java index abcc772227d..1252dc6b574 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerTestBundle.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerTestBundle.java @@ -8,10 +8,12 @@ import java.util.Dictionary; import java.util.Hashtable; import java.util.List; +import java.util.Map; import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; +import org.osgi.framework.Bundle; import org.osgi.framework.ServiceReference; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentConstants; @@ -21,11 +23,12 @@ import org.osgi.service.component.annotations.Deactivate; import org.osgi.service.component.annotations.Modified; -import com.google.common.collect.Lists; +import com.google.common.collect.ImmutableMap; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; +import io.openems.common.OpenemsConstants; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; import io.openems.common.types.EdgeConfig; @@ -57,12 +60,12 @@ import io.openems.edge.core.appmanager.jsonrpc.AddAppInstance.Request; import io.openems.edge.core.appmanager.jsonrpc.DeleteAppInstance; import io.openems.edge.core.appmanager.jsonrpc.UpdateAppInstance; -import io.openems.edge.core.appmanager.validator.CheckAppsNotInstalled; import io.openems.edge.core.appmanager.validator.CheckCardinality; -import io.openems.edge.core.appmanager.validator.CheckHome; +import io.openems.edge.core.appmanager.validator.CheckOr; import io.openems.edge.core.appmanager.validator.Checkable; +import io.openems.edge.core.appmanager.validator.CheckableFactory; import io.openems.edge.core.appmanager.validator.Validator; -import io.openems.edge.core.appmanager.validator.relaycount.CheckRelayCount; +import io.openems.edge.core.appmanager.validator.ValidatorImpl; public class AppManagerTestBundle { @@ -78,12 +81,16 @@ public class AppManagerTestBundle { private final AppValidateWorker appValidateWorker; - public final CheckablesBundle checkablesBundle; - public final TestScheduler scheduler; - public AppManagerTestBundle(JsonObject initialComponentConfig, MyConfig initialAppManagerConfig, - Function> availableAppsSupplier) throws Exception { + private final CheckableFactory checkableFactory = new CheckableFactory(); + private final CheckCardinality checkCardinality; + + public AppManagerTestBundle(// + JsonObject initialComponentConfig, // + MyConfig initialAppManagerConfig, // + Function> availableAppsSupplier // + ) throws Exception { this(initialComponentConfig, initialAppManagerConfig, availableAppsSupplier, null, new DefaultComponentManagerFactory()); } @@ -94,6 +101,18 @@ public AppManagerTestBundle(// Function> availableAppsSupplier, // Consumer additionalComponentConfig, // ComponentManagerFactory componentManagerFactory // + ) throws Exception { + this(initialComponentConfig, initialAppManagerConfig, availableAppsSupplier, additionalComponentConfig, + componentManagerFactory, new AppManagerImplAutoUpdateOnConfigChange()); + } + + public AppManagerTestBundle(// + JsonObject initialComponentConfig, // + MyConfig initialAppManagerConfig, // + Function> availableAppsSupplier, // + Consumer additionalComponentConfig, // + ComponentManagerFactory componentManagerFactory, // + AppManagerImpl impl // ) throws Exception { if (initialComponentConfig == null) { initialComponentConfig = JsonUtils.buildJsonObject() // @@ -158,87 +177,20 @@ public AppManagerTestBundle(// this.componentUtil = new ComponentUtilImpl(this.componentManger); - this.sut = new AppManagerImpl() { - - @Activate - @Override - protected void activate(ComponentContext componentContext, Config config) { - super.activate(componentContext, config); - } - - @Modified - @Override - protected void modified(ComponentContext componentContext, Config config) throws OpenemsNamedException { - super.modified(componentContext, config); - } - - @Deactivate - @Override - protected void deactivate() { - super.deactivate(); - } - - @Override - public AddAppInstance.Response handleAddAppInstanceRequest(User user, Request request, - boolean ignoreBackend) throws OpenemsNamedException { - final var response = super.handleAddAppInstanceRequest(user, request, ignoreBackend); - this.modifyWithCurrentConfig(); - return response; - } - - @Override - public DeleteAppInstance.Response handleDeleteAppInstanceRequest(User user, - DeleteAppInstance.Request request) throws OpenemsNamedException { - final var response = super.handleDeleteAppInstanceRequest(user, request); - this.modifyWithCurrentConfig(); - return response; - } - - @Override - public UpdateAppInstance.Response handleUpdateAppInstanceRequest(User user, - UpdateAppInstance.Request request) throws OpenemsNamedException { - final var response = super.handleUpdateAppInstanceRequest(user, request); - this.modifyWithCurrentConfig(); - return response; - } + this.sut = impl; - private final void modifyWithCurrentConfig() throws OpenemsNamedException { - final var config = MyConfig.create() // - .setApps(this.instantiatedApps.stream() // - .map(OpenemsAppInstance::toJsonObject) // - .collect(JsonUtils.toJsonArray()) // - .toString()) - .setKey("0000-0000-0000-0000") // - .build(); - DummyComponentContext context; - try { - context = DummyComponentContext.from(config); - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - throw new OpenemsException(e); - } - this.modified(context, config); - } - - }; componentManagerFactory.afterInit(this.sut, this.cm); this.appManagerUtil = new AppManagerUtilImpl(this.componentManger); this.appCenterBackendUtil = new DummyAppCenterBackendUtil(); ReflectionUtils.setAttribute(this.appManagerUtil.getClass(), this.appManagerUtil, "appManager", this.sut); - this.checkablesBundle = new CheckablesBundle(// - new TestCheckable(), // - new CheckCardinality(this.sut, this.appManagerUtil, - getComponentContext(CheckCardinality.COMPONENT_NAME)), // - new CheckRelayCount(this.componentUtil, getComponentContext(CheckRelayCount.COMPONENT_NAME), null), // - new CheckAppsNotInstalled(this.sut, getComponentContext(CheckAppsNotInstalled.COMPONENT_NAME)), // - new CheckHome(this.componentManger, getComponentContext(CheckHome.COMPONENT_NAME), - new CheckAppsNotInstalled(this.sut, getComponentContext(CheckAppsNotInstalled.COMPONENT_NAME))) // - ); + this.addCheckable(TestCheckable.COMPONENT_NAME, t -> new TestCheckable()); + this.addCheckable(CheckOr.COMPONENT_NAME, t -> new CheckOr(t, this.checkableFactory)); + this.checkCardinality = this.addCheckable(CheckCardinality.COMPONENT_NAME, + t -> new CheckCardinality(this.sut, this.appManagerUtil, t)); - var dummyValidator = new DummyValidator(); - dummyValidator.setCheckables(this.checkablesBundle.all()); - this.validator = dummyValidator; + this.validator = new ValidatorImpl(this.checkableFactory); this.appHelper = new DummyAppManagerAppHelper(this.componentManger, this.componentUtil, this.appManagerUtil); final var csoAppManagerAppHelper = cso((AppManagerAppHelper) this.appHelper); @@ -274,6 +226,27 @@ private final void modifyWithCurrentConfig() throws OpenemsNamedException { this.scheduler = new TestScheduler(this.componentManger); } + /** + * Adds a checkable to the current test bundle. + * + * @param the type of the checkable to add + * @param componentName the component name of the checkable + * @param checkableFactory the factory to get a instance of the checkable + * @return the created checkable + */ + public T addCheckable(// + final String componentName, // + final Function checkableFactory // + ) { + final var checkable = checkableFactory.apply(getComponentContext(componentName)); + this.checkableFactory.bindCso(cso(componentName, checkable)); + return checkable; + } + + public CheckCardinality getCheckCardinality() { + return this.checkCardinality; + } + /** * Calls the modified method. * @@ -449,30 +422,6 @@ public PersistencePredictorAggregateTask addPersistencePredictorAggregateTask() return persistencePredictorAggregateTaskImpl; } - public record CheckablesBundle(// - DummyValidator.TestCheckable checkTest, // - CheckCardinality checkCardinality, // - CheckRelayCount checkRelayCount, // - CheckAppsNotInstalled checkAppsNotInstalled, // - CheckHome checkHome // - ) { - - /** - * Gets all {@link Checkable}. - * - * @return the {@link Checkable} - */ - public final List all() { - return Lists.newArrayList(// - this.checkTest(), // - this.checkCardinality(), // - this.checkRelayCount(), // - this.checkAppsNotInstalled(), // - this.checkHome() // - ); - } - } - /** * Gets the {@link ComponentContext} for an {@link OpenemsApp} of the given * appId. @@ -575,6 +524,65 @@ public void afterInit(AppManagerImpl impl, ConfigurationAdmin cm) { * @return the {@link ComponentServiceObjects} */ public static ComponentServiceObjects cso(T service) { + return cso(null, service); + } + + /** + * Creates a {@link ComponentServiceObjects} of a service. + * + * @param the type of the service + * @param componentName the name of the component + * @param service the service + * @return the {@link ComponentServiceObjects} + */ + public static ComponentServiceObjects cso(String componentName, T service) { + final var sr = new ServiceReference() { + + private final Map properties = ImmutableMap.builder() // + .put(OpenemsConstants.PROPERTY_OSGI_COMPONENT_NAME, + componentName != null ? componentName : service.getClass().getCanonicalName()) // + .build(); + + @Override + public Object getProperty(String key) { + return this.properties.get(key); + } + + @Override + public String[] getPropertyKeys() { + return this.properties.keySet().toArray(String[]::new); + } + + @Override + public Bundle getBundle() { + return null; + } + + @Override + public Bundle[] getUsingBundles() { + return null; + } + + @Override + public boolean isAssignableTo(Bundle bundle, String className) { + return false; + } + + @Override + public int compareTo(Object reference) { + return 0; + } + + @Override + public Dictionary getProperties() { + return null; + } + + @Override + public A adapt(Class type) { + return null; + } + }; return new ComponentServiceObjects() { @Override @@ -589,11 +597,79 @@ public void ungetService(T service) { @Override public ServiceReference getServiceReference() { - // not needed for test - return null; + return sr; } }; } + /** + * This implementation is used to automatically update the call the modified + * method when a changes happens thru a app change. + */ + private static class AppManagerImplAutoUpdateOnConfigChange extends AppManagerImpl { + + /** + * activate, modified, deactivate need to be overwritten because of reflection + * usage in tests. + */ + + @Activate + @Override + protected void activate(ComponentContext componentContext, Config config) { + super.activate(componentContext, config); + } + + @Modified + @Override + protected void modified(ComponentContext componentContext, Config config) throws OpenemsNamedException { + super.modified(componentContext, config); + } + + @Deactivate + @Override + protected void deactivate() { + super.deactivate(); + } + + @Override + public AddAppInstance.Response handleAddAppInstanceRequest(User user, Request request, boolean ignoreBackend) + throws OpenemsNamedException { + final var response = super.handleAddAppInstanceRequest(user, request, ignoreBackend); + this.modifyWithCurrentConfig(); + return response; + } + + @Override + public DeleteAppInstance.Response handleDeleteAppInstanceRequest(User user, DeleteAppInstance.Request request) + throws OpenemsNamedException { + final var response = super.handleDeleteAppInstanceRequest(user, request); + this.modifyWithCurrentConfig(); + return response; + } + + @Override + public UpdateAppInstance.Response handleUpdateAppInstanceRequest(User user, UpdateAppInstance.Request request) + throws OpenemsNamedException { + final var response = super.handleUpdateAppInstanceRequest(user, request); + this.modifyWithCurrentConfig(); + return response; + } + + private final void modifyWithCurrentConfig() throws OpenemsNamedException { + final var config = MyConfig.create() // + .setApps(this.instantiatedApps.stream() // + .map(OpenemsAppInstance::toJsonObject) // + .collect(JsonUtils.toJsonArray()) // + .toString()) + .setKey("0000-0000-0000-0000") // + .build(); + try { + this.modified(DummyComponentContext.from(config), config); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + throw new OpenemsException(e); + } + } + } + } diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/Apps.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/Apps.java index ca6f501674b..4fa625f043d 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/Apps.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/Apps.java @@ -19,6 +19,7 @@ import io.openems.edge.app.api.TimedataInfluxDb; import io.openems.edge.app.ess.FixActivePower; import io.openems.edge.app.ess.FixStateOfCharge; +import io.openems.edge.app.ess.Limiter14a; import io.openems.edge.app.ess.PowerPlantController; import io.openems.edge.app.ess.PrepareBatteryExtension; import io.openems.edge.app.evcs.AlpitronicEvcs; @@ -34,13 +35,23 @@ import io.openems.edge.app.integratedsystem.FeneconHome; import io.openems.edge.app.integratedsystem.FeneconHome20; import io.openems.edge.app.integratedsystem.FeneconHome30; +import io.openems.edge.app.integratedsystem.fenecon.commercial.FeneconCommercial92; import io.openems.edge.app.loadcontrol.ManualRelayControl; import io.openems.edge.app.loadcontrol.ThresholdControl; import io.openems.edge.app.meter.CarloGavazziMeter; import io.openems.edge.app.meter.DiscovergyMeter; import io.openems.edge.app.meter.JanitzaMeter; import io.openems.edge.app.meter.MicrocareSdm630Meter; +import io.openems.edge.app.meter.PhoenixContactMeter; +import io.openems.edge.app.meter.PqPlusMeter; import io.openems.edge.app.meter.SocomecMeter; +import io.openems.edge.app.openemshardware.BeagleBoneBlack; +import io.openems.edge.app.openemshardware.Compulab; +import io.openems.edge.app.openemshardware.TechbaseCm3; +import io.openems.edge.app.openemshardware.TechbaseCm4; +import io.openems.edge.app.openemshardware.TechbaseCm4Max; +import io.openems.edge.app.openemshardware.TechbaseCm4s; +import io.openems.edge.app.openemshardware.TechbaseCm4sGen2; import io.openems.edge.app.peakshaving.PeakShaving; import io.openems.edge.app.peakshaving.PhaseAccuratePeakShaving; import io.openems.edge.app.pvinverter.FroniusPvInverter; @@ -59,10 +70,9 @@ import io.openems.edge.app.timeofusetariff.Tibber; import io.openems.edge.common.component.ComponentManager; -public class Apps { +public final class Apps { private Apps() { - super(); } /** @@ -113,6 +123,16 @@ public static final FeneconHome30 feneconHome30(AppManagerTestBundle t) { return app(t, FeneconHome30::new, "App.FENECON.Home.30"); } + /** + * Test method for creating a {@link FeneconCommercial92}. + * + * @param t the {@link AppManagerTestBundle} + * @return the {@link OpenemsApp} instance + */ + public static final FeneconCommercial92 feneconCommercial92(AppManagerTestBundle t) { + return app(t, FeneconCommercial92::new, "App.FENECON.Commercial.92"); + } + // TimeOfUseTariff /** @@ -185,6 +205,76 @@ public static final Tibber tibber(AppManagerTestBundle t) { return app(t, Tibber::new, "App.TimeOfUseTariff.Tibber"); } + /** + * Test method for creating a {@link BeagleBoneBlack}. + * + * @param t the {@link AppManagerTestBundle} + * @return the {@link OpenemsApp} instance + */ + public static final BeagleBoneBlack beagleBoneBlack(AppManagerTestBundle t) { + return app(t, BeagleBoneBlack::new, "App.OpenemsHardware.BeagleBoneBlack"); + } + + /** + * Test method for creating a {@link Compulab}. + * + * @param t the {@link AppManagerTestBundle} + * @return the {@link OpenemsApp} instance + */ + public static final Compulab compulab(AppManagerTestBundle t) { + return app(t, Compulab::new, "App.OpenemsHardware.Compulab"); + } + + /** + * Test method for creating a {@link TechbaseCm3}. + * + * @param t the {@link AppManagerTestBundle} + * @return the {@link OpenemsApp} instance + */ + public static final TechbaseCm3 techbaseCm3(AppManagerTestBundle t) { + return app(t, TechbaseCm3::new, "App.OpenemsHardware.CM3"); + } + + /** + * Test method for creating a {@link TechbaseCm4}. + * + * @param t the {@link AppManagerTestBundle} + * @return the {@link OpenemsApp} instance + */ + public static final TechbaseCm4 techbaseCm4(AppManagerTestBundle t) { + return app(t, TechbaseCm4::new, "App.OpenemsHardware.CM4"); + } + + /** + * Test method for creating a {@link TechbaseCm4Max}. + * + * @param t the {@link AppManagerTestBundle} + * @return the {@link OpenemsApp} instance + */ + public static final TechbaseCm4Max techbaseCm4Max(AppManagerTestBundle t) { + return app(t, TechbaseCm4Max::new, "App.OpenemsHardware.CM4Max"); + } + + /** + * Test method for creating a {@link TechbaseCm4s}. + * + * @param t the {@link AppManagerTestBundle} + * @return the {@link OpenemsApp} instance + */ + public static final TechbaseCm4s techbaseCm4s(AppManagerTestBundle t) { + return app(t, TechbaseCm4s::new, "App.OpenemsHardware.CM4S"); + } + + /** + * Test method for creating a {@link TechbaseCm4sGen2}. + * + * @param t the {@link AppManagerTestBundle} + * @return the {@link OpenemsApp} instance + */ + public static final TechbaseCm4sGen2 techbaseCm4sGen2(AppManagerTestBundle t) { + return app(t, TechbaseCm4sGen2::new, "App.OpenemsHardware.CM4S.Gen2"); + } + // Test /** @@ -469,6 +559,16 @@ public static final JanitzaMeter janitzaMeter(AppManagerTestBundle t) { return app(t, JanitzaMeter::new, "App.Meter.Janitza"); } + /** + * Test method for creating a {@link PqPlusMeter}. + * + * @param t the {@link AppManagerTestBundle} + * @return the {@link OpenemsApp} instance + */ + public static final PqPlusMeter pqPlusMeter(AppManagerTestBundle t) { + return app(t, PqPlusMeter::new, "App.Meter.PqPlus"); + } + /** * Test method for creating a {@link MicrocareSdm630Meter}. * @@ -479,6 +579,16 @@ public static final MicrocareSdm630Meter microcareSdm630Meter(AppManagerTestBund return app(t, MicrocareSdm630Meter::new, "App.Meter.Microcare.Sdm630"); } + /** + * Test method for creating a {@link PhoenixContactMeter}. + * + * @param t the {@link AppManagerTestBundle} + * @return the {@link OpenemsApp} instance + */ + public static final PhoenixContactMeter phoenixContactMeter(AppManagerTestBundle t) { + return app(t, PhoenixContactMeter::new, "App.Meter.PhoenixContact"); + } + // PV-Inverter /** @@ -595,6 +705,16 @@ public static final PowerPlantController powerPlantController(AppManagerTestBund return app(t, PowerPlantController::new, "App.Ess.PowerPlantController"); } + /** + * Test method for creating a {@link Limiter14a}. + * + * @param t the {@link AppManagerTestBundle} + * @return the {@link OpenemsApp} instance + */ + public static final Limiter14a limiter14a(AppManagerTestBundle t) { + return app(t, Limiter14a::new, "App.Ess.Limiter14a"); + } + private static final T app(AppManagerTestBundle t, DefaultAppConstructor constructor, String appId) { return constructor.create(t.componentManger, AppManagerTestBundle.getComponentContext(appId), t.cm, t.componentUtil); diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/DummyValidator.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/DummyValidator.java index 1297c42b946..03f2548953a 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/DummyValidator.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/DummyValidator.java @@ -1,53 +1,17 @@ package io.openems.edge.core.appmanager; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.function.Supplier; +import org.osgi.service.component.annotations.Component; + import io.openems.common.session.Language; import io.openems.edge.core.appmanager.validator.Checkable; -import io.openems.edge.core.appmanager.validator.Validator; import io.openems.edge.core.appmanager.validator.ValidatorConfig.CheckableConfig; -public class DummyValidator implements Validator { - - private List checkables; - - @Override - public List getErrorMessages(List checkableConfigs, Language language, - boolean returnImmediate) { - var errors = new ArrayList(); - for (var check : checkableConfigs) { - var checkable = this.findCheckableByName(check.checkableComponentName()); - checkable.setProperties(check.properties()); - if (checkable.check() == check.invertResult()) { - errors.add(check.invertResult() ? checkable.getInvertedErrorMessage(language) - : checkable.getErrorMessage(language)); - if (returnImmediate) { - return errors; - } - } - - } - return errors; - } - - private Checkable findCheckableByName(String name) { - return this.checkables.stream() // - .filter(c -> c.getComponentName().equals(name)) // - .findAny().get(); - } - - public void setCheckables(List checkables) { - this.checkables = checkables; - } - - public List getCheckables() { - return this.checkables; - } +public final class DummyValidator { /** * Creates a {@link CheckableConfig} for a test check. @@ -105,6 +69,7 @@ public static CheckableConfig testCheckable(// return testCheckable(check, (String) null, (String) null); } + @Component(name = TestCheckable.COMPONENT_NAME) public static class TestCheckable implements Checkable { public static final String COMPONENT_NAME = "Test.Validator.Checkable.TestCheckable"; @@ -152,4 +117,7 @@ public String getInvertedErrorMessage(Language language) { } + private DummyValidator() { + } + } diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/ResolveOpenemsHardwareTest.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/ResolveOpenemsHardwareTest.java new file mode 100644 index 00000000000..fc535d9695d --- /dev/null +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/ResolveOpenemsHardwareTest.java @@ -0,0 +1,165 @@ +package io.openems.edge.core.appmanager; + +import static io.openems.edge.common.test.DummyUser.DUMMY_ADMIN; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.FileWriter; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import com.google.common.collect.ImmutableList; +import com.google.gson.JsonObject; + +import io.openems.edge.common.test.DummyComponentContext; +import io.openems.edge.common.test.DummyComponentInstance; +import io.openems.edge.core.appmanager.jsonrpc.AddAppInstance; + +public class ResolveOpenemsHardwareTest { + + @Rule + public TemporaryFolder folder = TemporaryFolder.builder() // + .assureDeletion() // + .build(); + + private AppManagerTestBundle appManagerTestBundle; + private OpenemsApp dummyHardwareApp; + private OpenemsApp dummyHardwareApp2; + + @Before + public void setUp() throws Exception { + this.appManagerTestBundle = new AppManagerTestBundle(null, null, t -> { + return ImmutableList.of(// + this.dummyHardwareApp = Apps.techbaseCm4(t), // + this.dummyHardwareApp2 = Apps.techbaseCm3(t) // + ); + }); + System.setProperty("felix.cm.dir", this.folder.getRoot().getPath()); + } + + @Test + public void testSuccessfulInstallation() throws Exception { + this.setHardwareApp(this.dummyHardwareApp.getAppId()); + + final var completed = new CompletableFuture(); + final var context = new DummyComponentContext(new Hashtable(), DummyComponentInstance.create() // + .setDispose(() -> completed.complete(null)) // + .build()); + + final var testExecutor = new TestExecutor(); + final var resolver = new ResolveOpenemsHardware(context, this.appManagerTestBundle.sut, + this.appManagerTestBundle.appManagerUtil, testExecutor); + + resolver.bindApp(this.dummyHardwareApp); + resolver.bindApp(this.dummyHardwareApp2); + testExecutor.runAll(); + + completed.join(); + + assertEquals(1, this.appManagerTestBundle.sut.getInstantiatedApps().size()); + assertFalse(this.appManagerTestBundle.sut.getHardwareMissmatchChannel().getNextValue().get()); + } + + @Test + public void testNotExistingAppId() throws Exception { + this.setHardwareApp("Random.App.Id"); + + final var completed = new CompletableFuture(); + final var context = new DummyComponentContext(new Hashtable(), DummyComponentInstance.create() // + .setDispose(() -> completed.complete(null)) // + .build()); + + final var testExecutor = new TestExecutor(); + final var resolver = new ResolveOpenemsHardware(context, this.appManagerTestBundle.sut, + this.appManagerTestBundle.appManagerUtil, testExecutor); + + resolver.bindApp(this.dummyHardwareApp); + resolver.bindApp(this.dummyHardwareApp2); + testExecutor.runAll(); + + completed.join(); + + assertEquals(0, this.appManagerTestBundle.sut.getInstantiatedApps().size()); + assertTrue(this.appManagerTestBundle.sut.getHardwareMissmatchChannel().getNextValue().get()); + } + + @Test + public void testAppIdNotSet() throws Exception { + final var completed = new CompletableFuture(); + final var context = new DummyComponentContext(new Hashtable(), DummyComponentInstance.create() // + .setDispose(() -> completed.complete(null)) // + .build()); + + final var testExecutor = new TestExecutor(); + final var resolver = new ResolveOpenemsHardware(context, this.appManagerTestBundle.sut, + this.appManagerTestBundle.appManagerUtil, testExecutor); + + resolver.bindApp(this.dummyHardwareApp); + resolver.bindApp(this.dummyHardwareApp2); + testExecutor.runAll(); + + completed.join(); + + assertEquals(0, this.appManagerTestBundle.sut.getInstantiatedApps().size()); + assertFalse(this.appManagerTestBundle.sut.getHardwareMissmatchChannel().getNextValue().get()); + } + + @Test + public void testWrongHardwareAppInstalled() throws Exception { + this.appManagerTestBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, + new AddAppInstance.Request(this.dummyHardwareApp2.getAppId(), "key", null, new JsonObject())); + + this.setHardwareApp(this.dummyHardwareApp.getAppId()); + + final var completed = new CompletableFuture(); + final var context = new DummyComponentContext(new Hashtable(), DummyComponentInstance.create() // + .setDispose(() -> completed.complete(null)) // + .build()); + + final var testExecutor = new TestExecutor(); + final var resolver = new ResolveOpenemsHardware(context, this.appManagerTestBundle.sut, + this.appManagerTestBundle.appManagerUtil, testExecutor); + + resolver.bindApp(this.dummyHardwareApp); + resolver.bindApp(this.dummyHardwareApp2); + testExecutor.runAll(); + + completed.join(); + + assertEquals(1, this.appManagerTestBundle.sut.getInstantiatedApps().size()); + assertTrue(this.appManagerTestBundle.sut.getHardwareMissmatchChannel().getNextValue().get()); + } + + private void setHardwareApp(String appId) throws Exception { + final var hardwareInfoFile = this.folder.newFile(ResolveOpenemsHardware.OPENEMS_HARDWARE_FILE_NAME); + try (final var fw = new FileWriter(hardwareInfoFile)) { + fw.write(ResolveOpenemsHardware.OPENEMS_HARDWARE_APP_KEY + "=" + appId); + } + } + + private static class TestExecutor implements Executor { + + private final List tasks = new ArrayList<>(); + + @Override + public void execute(Runnable command) { + this.tasks.add(command); + } + + public void runAll() { + this.tasks.forEach(Runnable::run); + this.tasks.clear(); + } + + } + +} diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestTranslations.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestTranslations.java index 1e5ae260b70..c14160b59af 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestTranslations.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestTranslations.java @@ -34,6 +34,7 @@ public void beforeEach() throws Exception { this.apps.add(new TestTranslation(Apps.feneconHome(t), true, TestFeneconHome.fullSettings())); this.apps.add(new TestTranslation(Apps.feneconHome20(t), true, TestFeneconHome20.fullSettings())); this.apps.add(new TestTranslation(Apps.feneconHome30(t), true, TestFeneconHome30.fullSettings())); + this.apps.add(new TestTranslation(Apps.feneconCommercial92(t), true, new JsonObject())); this.apps.add(new TestTranslation(Apps.awattarHourly(t), true, new JsonObject())); this.apps.add(new TestTranslation(Apps.entsoE(t), true, JsonUtils.buildJsonObject() // .addProperty("BIDDING_ZONE", "GERMANY") // @@ -51,6 +52,13 @@ public void beforeEach() throws Exception { this.apps.add(new TestTranslation(Apps.tibber(t), true, JsonUtils.buildJsonObject() // .addProperty("ACCESS_TOKEN", "123456789") // .build())); + this.apps.add(new TestTranslation(Apps.beagleBoneBlack(t), true, new JsonObject())); + this.apps.add(new TestTranslation(Apps.compulab(t), true, new JsonObject())); + this.apps.add(new TestTranslation(Apps.techbaseCm3(t), true, new JsonObject())); + this.apps.add(new TestTranslation(Apps.techbaseCm4(t), true, new JsonObject())); + this.apps.add(new TestTranslation(Apps.techbaseCm4Max(t), true, new JsonObject())); + this.apps.add(new TestTranslation(Apps.techbaseCm4s(t), true, new JsonObject())); + this.apps.add(new TestTranslation(Apps.techbaseCm4sGen2(t), true, new JsonObject())); this.apps.add(new TestTranslation(Apps.modbusTcpApiReadOnly(t), true, new JsonObject())); this.apps.add(new TestTranslation(Apps.modbusTcpApiReadWrite(t), true, JsonUtils.buildJsonObject() // .addProperty("API_TIMEOUT", 60) // @@ -71,14 +79,14 @@ public void beforeEach() throws Exception { this.apps.add(new TestTranslation(Apps.webastoNext(t), true, new JsonObject())); this.apps.add(new TestTranslation(Apps.webastoUnite(t), true, new JsonObject())); this.apps.add(new TestTranslation(Apps.evcsCluster(t), true, new JsonObject())); - this.apps.add(new TestTranslation(Apps.heatPump(t), false, JsonUtils.buildJsonObject() // + this.apps.add(new TestTranslation(Apps.heatPump(t), true, JsonUtils.buildJsonObject() // .addProperty("OUTPUT_CHANNEL_1", "io0/Relay1") // .addProperty("OUTPUT_CHANNEL_2", "io0/Relay2") // .build())); - this.apps.add(new TestTranslation(Apps.combinedHeatAndPower(t), false, JsonUtils.buildJsonObject() // + this.apps.add(new TestTranslation(Apps.combinedHeatAndPower(t), true, JsonUtils.buildJsonObject() // .addProperty("OUTPUT_CHANNEL", "io0/Relay1") // .build())); - this.apps.add(new TestTranslation(Apps.heatingElement(t), false, JsonUtils.buildJsonObject() // + this.apps.add(new TestTranslation(Apps.heatingElement(t), true, JsonUtils.buildJsonObject() // .addProperty("OUTPUT_CHANNEL_PHASE_L1", "io0/Relay1") // .addProperty("OUTPUT_CHANNEL_PHASE_L2", "io0/Relay2") // .addProperty("OUTPUT_CHANNEL_PHASE_L3", "io0/Relay3") // @@ -90,44 +98,46 @@ public void beforeEach() throws Exception { .addProperty("ESS_ID", "ess0") // .addProperty("METER_ID", "meter0") // .build())); - this.apps.add(new TestTranslation(Apps.manualRelayControl(t), false, JsonUtils.buildJsonObject() // + this.apps.add(new TestTranslation(Apps.manualRelayControl(t), true, JsonUtils.buildJsonObject() // .addProperty("OUTPUT_CHANNEL", "io0/Relay1") // .build())); - this.apps.add(new TestTranslation(Apps.thresholdControl(t), false, JsonUtils.buildJsonObject() // + this.apps.add(new TestTranslation(Apps.thresholdControl(t), true, JsonUtils.buildJsonObject() // .add("OUTPUT_CHANNELS", JsonUtils.buildJsonArray().add("io0/Relay1").build()) // .build())); this.apps.add(new TestTranslation(Apps.discovergyMeter(t), false, JsonUtils.buildJsonObject() // .addProperty("EMAIL", "test@test.test") // .addProperty("PASSWORD", "xxxx") // .build())); - this.apps.add(new TestTranslation(Apps.socomecMeter(t), false, JsonUtils.buildJsonObject() // + this.apps.add(new TestTranslation(Apps.socomecMeter(t), true, JsonUtils.buildJsonObject() // .addProperty("MODBUS_ID", "modbus0") // .build())); - this.apps.add(new TestTranslation(Apps.carloGavazziMeter(t), false, JsonUtils.buildJsonObject() // + this.apps.add(new TestTranslation(Apps.carloGavazziMeter(t), true, JsonUtils.buildJsonObject() // .addProperty("MODBUS_ID", "modbus0") // .addProperty("MODBUS_UNIT_ID", 5) // .build())); - this.apps.add(new TestTranslation(Apps.janitzaMeter(t), false, JsonUtils.buildJsonObject() // + this.apps.add(new TestTranslation(Apps.janitzaMeter(t), true, JsonUtils.buildJsonObject() // .addProperty("MODBUS_ID", "modbus0") // .build())); + this.apps.add(new TestTranslation(Apps.pqPlusMeter(t), false, new JsonObject())); + this.apps.add(new TestTranslation(Apps.phoenixContactMeter(t), true, new JsonObject())); this.apps.add(new TestTranslation(Apps.froniusPvInverter(t), false, JsonUtils.buildJsonObject() // .addProperty("MODBUS_ID", "modbus0") // .addProperty("PORT", 502) // .addProperty("MODBUS_UNIT_ID", 1) // .build())); - this.apps.add(new TestTranslation(Apps.kacoPvInverter(t), false, JsonUtils.buildJsonObject() // + this.apps.add(new TestTranslation(Apps.kacoPvInverter(t), true, JsonUtils.buildJsonObject() // .addProperty("MODBUS_ID", "modbus0") // .addProperty("PORT", 502) // .build())); - this.apps.add(new TestTranslation(Apps.kostalPvInverter(t), false, JsonUtils.buildJsonObject() // + this.apps.add(new TestTranslation(Apps.kostalPvInverter(t), true, JsonUtils.buildJsonObject() // .addProperty("MODBUS_ID", "modbus0") // .addProperty("PORT", 502) // .addProperty("MODBUS_UNIT_ID", 1) // .build())); - this.apps.add(new TestTranslation(Apps.smaPvInverter(t), false, JsonUtils.buildJsonObject() // + this.apps.add(new TestTranslation(Apps.smaPvInverter(t), true, JsonUtils.buildJsonObject() // .addProperty("MODBUS_ID", "modbus0") // .build())); - this.apps.add(new TestTranslation(Apps.solarEdgePvInverter(t), false, JsonUtils.buildJsonObject() // + this.apps.add(new TestTranslation(Apps.solarEdgePvInverter(t), true, JsonUtils.buildJsonObject() // .addProperty("MODBUS_ID", "modbus0") // .addProperty("PORT", 502) // .build())); @@ -147,6 +157,10 @@ public void beforeEach() throws Exception { .build())); this.apps.add(new TestTranslation(Apps.powerPlantController(t), true, new JsonObject())); this.apps.add(new TestTranslation(Apps.prepareBatteryExtension(t), true, new JsonObject())); + this.apps.add(new TestTranslation(Apps.limiter14a(t), true, JsonUtils.buildJsonObject() // + .addProperty("ESS_ID", "ess0") // + .addProperty("INPUT_CHANNEL_ADDRESS", "io0/Relay1") // + .build())); return this.apps.stream().map(TestTranslation::app).toList(); }); } diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/validator/CheckHomeTest.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/validator/CheckHomeTest.java index 6174b2d811d..54504dd2026 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/validator/CheckHomeTest.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/validator/CheckHomeTest.java @@ -35,13 +35,14 @@ public void setUp() throws Exception { Apps.feneconHome30(t) // ); }, null, new PseudoComponentManagerFactory()); - this.checkHome = this.appManagerTestBundle.checkablesBundle.checkHome(); + this.checkHome = this.appManagerTestBundle.addCheckable(CheckHome.COMPONENT_NAME, + t -> new CheckHome(t, new CheckAppsNotInstalled(this.appManagerTestBundle.sut, + AppManagerTestBundle.getComponentContext(CheckAppsNotInstalled.COMPONENT_NAME)))); } @Test public void testCheck() { - final var checkHome = this.appManagerTestBundle.checkablesBundle.checkHome(); - assertFalse(checkHome.check()); + assertFalse(this.checkHome.check()); assertFalse(PropsUtil.isHomeInstalled(this.appManagerTestBundle.appManagerUtil)); } diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ManagedSymmetricEss.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ManagedSymmetricEss.java index 159f8c054ca..616c112b519 100644 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ManagedSymmetricEss.java +++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ManagedSymmetricEss.java @@ -163,7 +163,7 @@ public void accept(ManagedSymmetricEss ess, Integer value) throws OpenemsNamedEx * */ SET_REACTIVE_POWER_LESS_OR_EQUALS(new IntegerDoc() // - .unit(Unit.VOLT_AMPERE) // + .unit(Unit.VOLT_AMPERE_REACTIVE) // .accessMode(AccessMode.WRITE_ONLY) // .onChannelSetNextWrite(new PowerConstraint("SetReactivePowerLessOrEquals", Phase.ALL, Pwr.REACTIVE, Relationship.LESS_OR_EQUALS))), // @@ -178,7 +178,7 @@ public void accept(ManagedSymmetricEss ess, Integer value) throws OpenemsNamedEx * */ SET_REACTIVE_POWER_GREATER_OR_EQUALS(new IntegerDoc() // - .unit(Unit.WATT) // + .unit(Unit.VOLT_AMPERE_REACTIVE) // .accessMode(AccessMode.WRITE_ONLY) // .onChannelSetNextWrite(new PowerConstraint("SetReactivePowerGreaterOrEquals", Phase.ALL, Pwr.REACTIVE, Relationship.GREATER_OR_EQUALS))), // diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/AbstractGoodWe.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/AbstractGoodWe.java index 134e6f5561c..3fcfec14317 100644 --- a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/AbstractGoodWe.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/AbstractGoodWe.java @@ -287,7 +287,22 @@ protected final ModbusProtocol defineModbusProtocol() { ), new FC3ReadRegistersTask(35250, Priority.LOW, // - m(new BitsWordElement(35250, this) // + + /* + * Table 8-30 Grid Detailed WARNING (35250 - 35253, U64) + */ + new DummyRegisterElement(35250, 35251), // + m(new BitsWordElement(35252, this) // + .bit(0, GoodWe.ChannelId.STATE_86) // + .bit(1, GoodWe.ChannelId.STATE_87) // + .bit(2, GoodWe.ChannelId.STATE_88) // + .bit(3, GoodWe.ChannelId.STATE_89) // + .bit(4, GoodWe.ChannelId.STATE_90) // + .bit(5, GoodWe.ChannelId.STATE_91) // + .bit(6, GoodWe.ChannelId.STATE_92) // + .bit(7, GoodWe.ChannelId.STATE_93) // + ), // + m(new BitsWordElement(35253, this) // .bit(0, GoodWe.ChannelId.STATE_70) // .bit(1, GoodWe.ChannelId.STATE_71) // .bit(2, GoodWe.ChannelId.STATE_72) // @@ -304,18 +319,21 @@ protected final ModbusProtocol defineModbusProtocol() { .bit(13, GoodWe.ChannelId.STATE_83) // .bit(14, GoodWe.ChannelId.STATE_84) // .bit(15, GoodWe.ChannelId.STATE_85)), // - m(new BitsWordElement(35251, this) // - .bit(0, GoodWe.ChannelId.STATE_86) // - .bit(1, GoodWe.ChannelId.STATE_87) // - .bit(2, GoodWe.ChannelId.STATE_88) // - .bit(3, GoodWe.ChannelId.STATE_89) // - .bit(4, GoodWe.ChannelId.STATE_90) // - .bit(5, GoodWe.ChannelId.STATE_91) // - .bit(6, GoodWe.ChannelId.STATE_92) // - .bit(7, GoodWe.ChannelId.STATE_93) // + + /* + * Table 8-31 Inverter detailed error (35254 - 35257, U64) + */ + new DummyRegisterElement(35254, 35255), // + m(new BitsWordElement(35256, this) // + .bit(0, GoodWe.ChannelId.STATE_110) // + .bit(1, GoodWe.ChannelId.STATE_111) // + .bit(2, GoodWe.ChannelId.STATE_112) // + .bit(3, GoodWe.ChannelId.STATE_113) // + .bit(4, GoodWe.ChannelId.STATE_114) // + .bit(5, GoodWe.ChannelId.STATE_115) // + .bit(6, GoodWe.ChannelId.STATE_116) // ), // - new DummyRegisterElement(35252, 35253), // - m(new BitsWordElement(35254, this) // + m(new BitsWordElement(35257, this) // .bit(0, GoodWe.ChannelId.STATE_94) // .bit(1, GoodWe.ChannelId.STATE_95) // .bit(2, GoodWe.ChannelId.STATE_96) // @@ -332,17 +350,19 @@ protected final ModbusProtocol defineModbusProtocol() { .bit(13, GoodWe.ChannelId.STATE_107) // .bit(14, GoodWe.ChannelId.STATE_108) // .bit(15, GoodWe.ChannelId.STATE_109)), // - m(new BitsWordElement(35255, this) // - .bit(0, GoodWe.ChannelId.STATE_110) // - .bit(1, GoodWe.ChannelId.STATE_111) // - .bit(2, GoodWe.ChannelId.STATE_112) // - .bit(3, GoodWe.ChannelId.STATE_113) // - .bit(4, GoodWe.ChannelId.STATE_114) // - .bit(5, GoodWe.ChannelId.STATE_115) // - .bit(6, GoodWe.ChannelId.STATE_116) // + + /* + * Table 8-32 Inverter detailed status (35258 - 35261, U64) + */ + new DummyRegisterElement(35258, 35259), // + m(new BitsWordElement(35260, this) // + .bit(0, GoodWe.ChannelId.STATE_133) // + .bit(1, GoodWe.ChannelId.STATE_134) // + .bit(2, GoodWe.ChannelId.STATE_135) // + .bit(3, GoodWe.ChannelId.STATE_136) // + .bit(4, GoodWe.ChannelId.STATE_137) // ), // - new DummyRegisterElement(35256, 35257), // - m(new BitsWordElement(35258, this) // + m(new BitsWordElement(35261, this) // .bit(0, GoodWe.ChannelId.STATE_117) // .bit(1, GoodWe.ChannelId.STATE_118) // .bit(2, GoodWe.ChannelId.STATE_119) // @@ -359,14 +379,7 @@ protected final ModbusProtocol defineModbusProtocol() { .bit(13, GoodWe.ChannelId.STATE_130) // .bit(14, GoodWe.ChannelId.STATE_131) // .bit(15, GoodWe.ChannelId.STATE_132)), // - m(new BitsWordElement(35259, this) // - .bit(0, GoodWe.ChannelId.STATE_133) // - .bit(1, GoodWe.ChannelId.STATE_134) // - .bit(2, GoodWe.ChannelId.STATE_135) // - .bit(3, GoodWe.ChannelId.STATE_136) // - .bit(4, GoodWe.ChannelId.STATE_137) // - ), // - new DummyRegisterElement(35260, 35267), // + new DummyRegisterElement(35262, 35267), // m(GoodWe.ChannelId.MAX_GRID_FREQ_WITHIN_1_MINUTE, new UnsignedWordElement(35268), SCALE_FACTOR_MINUS_2), // m(GoodWe.ChannelId.MIN_GRID_FREQ_WITHIN_1_MINUTE, new UnsignedWordElement(35269), diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/GoodWe.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/GoodWe.java index c8e8d372118..aa090eaa2b3 100644 --- a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/GoodWe.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/GoodWe.java @@ -525,92 +525,92 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId STATE_57(Doc.of(Level.INFO).text("Charging under voltage 3")), // // Table 8-8 BMS Warning Code - STATE_58(Doc.of(Level.WARNING).text("Charging over voltage 1 ")), // - STATE_59(Doc.of(Level.WARNING).text("Discharging under voltage 1 ")), // - STATE_60(Doc.of(Level.WARNING).text("Cell high temperature 1 ")), // - STATE_61(Doc.of(Level.WARNING).text("Cell low temperature 1 ")), // - STATE_62(Doc.of(Level.WARNING).text("Charging over current 1 ")), // - STATE_63(Doc.of(Level.WARNING).text("Discharging over current 1 ")), // - STATE_64(Doc.of(Level.WARNING).text("Communication failure 1 ")), // - STATE_65(Doc.of(Level.WARNING).text("System reboot ")), // - STATE_66(Doc.of(Level.WARNING).text("Cell imbalance")), // - STATE_67(Doc.of(Level.WARNING).text("System low temperature 1 ")), // - STATE_68(Doc.of(Level.WARNING).text("System low temperature 1 ")), // - STATE_69(Doc.of(Level.WARNING).text("System high temperature")), // - - // Table 8-30 Grid Detailed Fault - STATE_70(Doc.of(Level.FAULT).text("Power outage")), // - STATE_71(Doc.of(Level.FAULT).text("Grid undervoltage first level fault")), // - STATE_72(Doc.of(Level.FAULT).text("Grid undervoltage second level fault")), // - STATE_73(Doc.of(Level.FAULT).text("Grid undervoltage third level fault")), // - STATE_74(Doc.of(Level.FAULT).text("Grid overvoltage first level fault")), // - STATE_75(Doc.of(Level.FAULT).text("Grid overvoltage second level fault")), // - STATE_76(Doc.of(Level.FAULT).text("Grid overvoltage third level fault")), // - STATE_77(Doc.of(Level.FAULT).text("Grid average voltage high fault")), // - STATE_78(Doc.of(Level.FAULT).text("Grid underfrequency first level fault")), // - STATE_79(Doc.of(Level.FAULT).text("Grid underfrequency second level fault")), // - STATE_80(Doc.of(Level.FAULT).text("Islanding protection underfrequency fault")), // - STATE_81(Doc.of(Level.FAULT).text("Grid overfrequency first level fault")), // - STATE_82(Doc.of(Level.FAULT).text("Grid overfrequency second level fault")), // - STATE_83(Doc.of(Level.FAULT).text("Islanding protection overfrequency fault")), // - STATE_84(Doc.of(Level.FAULT).text("Grid frequency shift fault")), // - STATE_85(Doc.of(Level.FAULT).text("Grid waveform check fault")), // - STATE_86(Doc.of(Level.FAULT).text("Grid line voltage fault flag")), // - STATE_87(Doc.of(Level.FAULT).text("Grid low voltage ride-through flag")), // - STATE_88(Doc.of(Level.FAULT).text("Grid high voltage ride-through flag")), // - STATE_89(Doc.of(Level.FAULT).text("Grid voltage exceeds the upper sampling limit")), // - STATE_90(Doc.of(Level.FAULT).text("Grid connection voltage high")), // - STATE_91(Doc.of(Level.FAULT).text("Grid connection voltage low")), // - STATE_92(Doc.of(Level.FAULT).text("Grid connection frequency high")), // - STATE_93(Doc.of(Level.FAULT).text("Grid connection frequency low")), // + STATE_58(Doc.of(OpenemsType.BOOLEAN).text("Charging over voltage 1 ")), // + STATE_59(Doc.of(OpenemsType.BOOLEAN).text("Discharging under voltage 1 ")), // + STATE_60(Doc.of(OpenemsType.BOOLEAN).text("Cell high temperature 1 ")), // + STATE_61(Doc.of(OpenemsType.BOOLEAN).text("Cell low temperature 1 ")), // + STATE_62(Doc.of(OpenemsType.BOOLEAN).text("Charging over current 1 ")), // + STATE_63(Doc.of(OpenemsType.BOOLEAN).text("Discharging over current 1 ")), // + STATE_64(Doc.of(OpenemsType.BOOLEAN).text("Communication failure 1 ")), // + STATE_65(Doc.of(OpenemsType.BOOLEAN).text("System reboot ")), // + STATE_66(Doc.of(OpenemsType.BOOLEAN).text("Cell imbalance")), // + STATE_67(Doc.of(OpenemsType.BOOLEAN).text("System low temperature 1 ")), // + STATE_68(Doc.of(OpenemsType.BOOLEAN).text("System low temperature 1 ")), // + STATE_69(Doc.of(OpenemsType.BOOLEAN).text("System high temperature")), // + + // Table 8-30 Grid Detailed WARNING + STATE_70(Doc.of(OpenemsType.BOOLEAN).text("Power outage")), // + STATE_71(Doc.of(OpenemsType.BOOLEAN).text("Grid undervoltage first level WARNING")), // + STATE_72(Doc.of(OpenemsType.BOOLEAN).text("Grid undervoltage second level WARNING")), // + STATE_73(Doc.of(OpenemsType.BOOLEAN).text("Grid undervoltage third level WARNING")), // + STATE_74(Doc.of(OpenemsType.BOOLEAN).text("Grid overvoltage first level WARNING")), // + STATE_75(Doc.of(OpenemsType.BOOLEAN).text("Grid overvoltage second level WARNING")), // + STATE_76(Doc.of(OpenemsType.BOOLEAN).text("Grid overvoltage third level WARNING")), // + STATE_77(Doc.of(OpenemsType.BOOLEAN).text("Grid average voltage high WARNING")), // + STATE_78(Doc.of(OpenemsType.BOOLEAN).text("Grid underfrequency first level WARNING")), // + STATE_79(Doc.of(OpenemsType.BOOLEAN).text("Grid underfrequency second level WARNING")), // + STATE_80(Doc.of(OpenemsType.BOOLEAN).text("Islanding protection underfrequency WARNING")), // + STATE_81(Doc.of(OpenemsType.BOOLEAN).text("Grid overfrequency first level WARNING")), // + STATE_82(Doc.of(OpenemsType.BOOLEAN).text("Grid overfrequency second level WARNING")), // + STATE_83(Doc.of(OpenemsType.BOOLEAN).text("Islanding protection overfrequency WARNING")), // + STATE_84(Doc.of(OpenemsType.BOOLEAN).text("Grid frequency shift WARNING")), // + STATE_85(Doc.of(OpenemsType.BOOLEAN).text("Grid waveform check WARNING")), // + STATE_86(Doc.of(OpenemsType.BOOLEAN).text("Grid line voltage WARNING flag")), // + STATE_87(Doc.of(OpenemsType.BOOLEAN).text("Grid low voltage ride-through flag")), // + STATE_88(Doc.of(OpenemsType.BOOLEAN).text("Grid high voltage ride-through flag")), // + STATE_89(Doc.of(OpenemsType.BOOLEAN).text("Grid voltage exceeds the upper sampling limit")), // + STATE_90(Doc.of(OpenemsType.BOOLEAN).text("Grid connection voltage high")), // + STATE_91(Doc.of(OpenemsType.BOOLEAN).text("Grid connection voltage low")), // + STATE_92(Doc.of(OpenemsType.BOOLEAN).text("Grid connection frequency high")), // + STATE_93(Doc.of(OpenemsType.BOOLEAN).text("Grid connection frequency low")), // // Table 8-31 Inverter detailed error - STATE_94(Doc.of(Level.FAULT).text("LLC hardware over current")), // - STATE_95(Doc.of(Level.FAULT).text("Battery boost hardware over current")), // - STATE_96(Doc.of(Level.FAULT).text("Battery boost software over current")), // - STATE_97(Doc.of(Level.FAULT).text("Battery bms fault")), // - STATE_98(Doc.of(Level.FAULT).text("Battery bms discharge disable")), // - STATE_99(Doc.of(Level.FAULT).text("Battery current rms over current")), // - STATE_100(Doc.of(Level.FAULT).text("Off-grid mode exceeds bms current limit")), // - STATE_101(Doc.of(Level.FAULT).text("Bus voltage soft start failed")), // - STATE_102(Doc.of(Level.FAULT).text("Bus voltage is too low")), // - STATE_103(Doc.of(Level.FAULT).text("Bus voltage is too high")), // - STATE_104(Doc.of(Level.FAULT).text("Inverter hardware over current")), // - STATE_105(Doc.of(Level.FAULT).text("Inverter software over current")), // - STATE_106(Doc.of(Level.FAULT).text("Pv boost hardware over current")), // - STATE_107(Doc.of(Level.FAULT).text("Pv boost software over current")), // - STATE_108(Doc.of(Level.FAULT).text("Grid back flow")), // - STATE_109(Doc.of(Level.FAULT).text("Off-grid mode battery voltage is too low")), // - STATE_110(Doc.of(Level.FAULT).text("Off-grid mode AC voltage is too low")), // - STATE_111(Doc.of(Level.FAULT).text("Off-grid mode AC voltage is too high")), // - STATE_112(Doc.of(Level.FAULT).text("Backup over load")), // - STATE_113(Doc.of(Level.FAULT).text("Off-grid zero error")), // - STATE_114(Doc.of(Level.FAULT).text("Power fast retrack error")), // - STATE_115(Doc.of(Level.FAULT).text("Bypass relay switch error")), // - STATE_116(Doc.of(Level.FAULT).text("Backup load relay switch error")), // + STATE_94(Doc.of(OpenemsType.BOOLEAN).text("LLC hardware over current")), // + STATE_95(Doc.of(OpenemsType.BOOLEAN).text("Battery boost hardware over current")), // + STATE_96(Doc.of(OpenemsType.BOOLEAN).text("Battery boost software over current")), // + STATE_97(Doc.of(OpenemsType.BOOLEAN).text("Battery bms WARNING")), // + STATE_98(Doc.of(OpenemsType.BOOLEAN).text("Battery bms discharge disable")), // + STATE_99(Doc.of(OpenemsType.BOOLEAN).text("Battery current rms over current")), // + STATE_100(Doc.of(OpenemsType.BOOLEAN).text("Off-grid mode exceeds bms current limit")), // + STATE_101(Doc.of(OpenemsType.BOOLEAN).text("Bus voltage soft start failed")), // + STATE_102(Doc.of(OpenemsType.BOOLEAN).text("Bus voltage is too low")), // + STATE_103(Doc.of(OpenemsType.BOOLEAN).text("Bus voltage is too high")), // + STATE_104(Doc.of(OpenemsType.BOOLEAN).text("Inverter hardware over current")), // + STATE_105(Doc.of(OpenemsType.BOOLEAN).text("Inverter software over current")), // + STATE_106(Doc.of(OpenemsType.BOOLEAN).text("Pv boost hardware over current")), // + STATE_107(Doc.of(OpenemsType.BOOLEAN).text("Pv boost software over current")), // + STATE_108(Doc.of(OpenemsType.BOOLEAN).text("Grid back flow")), // + STATE_109(Doc.of(OpenemsType.BOOLEAN).text("Off-grid mode battery voltage is too low")), // + STATE_110(Doc.of(OpenemsType.BOOLEAN).text("Off-grid mode AC voltage is too low")), // + STATE_111(Doc.of(OpenemsType.BOOLEAN).text("Off-grid mode AC voltage is too high")), // + STATE_112(Doc.of(OpenemsType.BOOLEAN).text("Backup over load")), // + STATE_113(Doc.of(OpenemsType.BOOLEAN).text("Off-grid zero error")), // + STATE_114(Doc.of(OpenemsType.BOOLEAN).text("Power fast retrack error")), // + STATE_115(Doc.of(OpenemsType.BOOLEAN).text("Bypass relay switch error")), // + STATE_116(Doc.of(OpenemsType.BOOLEAN).text("Backup load relay switch error")), // // Table 8-32 Inverter detailed status - STATE_117(Doc.of(Level.INFO).text("Over frequency curve running")), // - STATE_118(Doc.of(Level.INFO).text("Under frequency curve running")), // - STATE_119(Doc.of(Level.INFO).text("Frequency curve exiting recovery")), // - STATE_120(Doc.of(Level.INFO).text("PU over voltage curve running")), // - STATE_121(Doc.of(Level.INFO).text("PU under voltage curve running")), // - STATE_122(Doc.of(Level.INFO).text("QU curve running")), // - STATE_123(Doc.of(Level.INFO).text("PF curve running")), // - STATE_124(Doc.of(Level.INFO).text("Fixed PF is set")), // - STATE_125(Doc.of(Level.INFO).text("Fixed reactive power is set")), // - STATE_126(Doc.of(Level.INFO).text("Inverter over temp,derating curve operation")), // - STATE_127(Doc.of(Level.INFO).text("Australian DRED electricity sale status")), // - STATE_128(Doc.of(Level.INFO).text("Australian DRED purchase status")), // - STATE_129(Doc.of(Level.INFO).text("Active power limit set")), // - STATE_130(Doc.of(Level.INFO).text("70 percent derating (Germany) has been opened")), // - STATE_131(Doc.of(Level.INFO).text("CEI021 selftest running")), // - STATE_132(Doc.of(Level.INFO).text("Inverter first level over voltage derate")), // - STATE_133(Doc.of(Level.INFO).text("Force off grid flag")), // - STATE_134(Doc.of(Level.INFO).text("Force stop mode flag")), // - STATE_135(Doc.of(Level.INFO).text("Pv charge, off backup output flag")), // - STATE_136(Doc.of(Level.INFO).text("QU curve over voltage flag")), // - STATE_137(Doc.of(Level.INFO).text("QU curve under voltage flag")), // + STATE_117(Doc.of(OpenemsType.BOOLEAN).text("Over frequency curve running")), // + STATE_118(Doc.of(OpenemsType.BOOLEAN).text("Under frequency curve running")), // + STATE_119(Doc.of(OpenemsType.BOOLEAN).text("Frequency curve exiting recovery")), // + STATE_120(Doc.of(OpenemsType.BOOLEAN).text("PU over voltage curve running")), // + STATE_121(Doc.of(OpenemsType.BOOLEAN).text("PU under voltage curve running")), // + STATE_122(Doc.of(OpenemsType.BOOLEAN).text("QU curve running")), // + STATE_123(Doc.of(OpenemsType.BOOLEAN).text("PF curve running")), // + STATE_124(Doc.of(OpenemsType.BOOLEAN).text("Fixed PF is set")), // + STATE_125(Doc.of(OpenemsType.BOOLEAN).text("Fixed reactive power is set")), // + STATE_126(Doc.of(OpenemsType.BOOLEAN).text("Inverter over temp,derating curve operation")), // + STATE_127(Doc.of(OpenemsType.BOOLEAN).text("Australian DRED electricity sale status")), // + STATE_128(Doc.of(OpenemsType.BOOLEAN).text("Australian DRED purchase status")), // + STATE_129(Doc.of(OpenemsType.BOOLEAN).text("Active power limit set")), // + STATE_130(Doc.of(OpenemsType.BOOLEAN).text("70 percent derating (Germany) has been opened")), // + STATE_131(Doc.of(OpenemsType.BOOLEAN).text("CEI021 selftest running")), // + STATE_132(Doc.of(OpenemsType.BOOLEAN).text("Inverter first level over voltage derate")), // + STATE_133(Doc.of(OpenemsType.BOOLEAN).text("Force off grid flag")), // + STATE_134(Doc.of(OpenemsType.BOOLEAN).text("Force stop mode flag")), // + STATE_135(Doc.of(OpenemsType.BOOLEAN).text("Pv charge, off backup output flag")), // + STATE_136(Doc.of(OpenemsType.BOOLEAN).text("QU curve over voltage flag")), // + STATE_137(Doc.of(OpenemsType.BOOLEAN).text("QU curve under voltage flag")), // // BMS Information BATTERY_PROTOCOL(Doc.of(BatteryProtocol.values())), // diff --git a/io.openems.edge.simulator/bnd.bnd b/io.openems.edge.simulator/bnd.bnd index dbc46e64278..f674ba8c3a9 100644 --- a/io.openems.edge.simulator/bnd.bnd +++ b/io.openems.edge.simulator/bnd.bnd @@ -13,6 +13,7 @@ Bundle-Version: 1.0.0.${tstamp} io.openems.edge.evcs.api,\ io.openems.edge.io.api,\ io.openems.edge.meter.api,\ + io.openems.edge.predictor.api,\ io.openems.edge.pvinverter.api,\ io.openems.edge.thermometer.api,\ io.openems.edge.timedata.api,\ diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/DataContainer.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/DataContainer.java index b0bf32fbe4c..02b08f55252 100644 --- a/io.openems.edge.simulator/src/io/openems/edge/simulator/DataContainer.java +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/DataContainer.java @@ -53,6 +53,22 @@ public Float[] getCurrentRecord() { return this.records.get(this.currentIndex); } + /** + * Gets all values for the key. If no keys exist, get the value of all records. + * + * @param key the Channel-Id + * @return the record values + */ + public List getValues(String key) { + var index = this.getIndex(key); + if (index == null) { + return List.of(); + } + return this.records.stream() // + .map(a -> a[index]) // + .toList(); + } + /** * Gets the value for the key from the current record. If no keys exist, get the * first value of the record. @@ -61,16 +77,9 @@ public Float[] getCurrentRecord() { * @return the record value */ public Optional getValue(String key) { - Integer index; - if (this.keys.isEmpty()) { - // no keys -> first value - index = 0; - } else { - // find index of key - index = this.keys.get(key); - if (index == null) { - return Optional.empty(); - } + var index = this.getIndex(key); + if (index == null) { + return Optional.empty(); } var record = this.getCurrentRecord(); if (index < record.length) { @@ -79,6 +88,22 @@ var record = this.getCurrentRecord(); return Optional.empty(); } + /** + * Gets the index of the kex. + * + * @param key the Channel-Id + * @return the index; possibly null + */ + private Integer getIndex(String key) { + if (this.keys.isEmpty()) { + // no keys -> first value + return 0; + } else { + // find index of key + return this.keys.get(key); + } + } + /** * Switch to the next row of values. */ diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/app/SimulatorAppImpl.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/app/SimulatorAppImpl.java index a1bce438a71..e646771b004 100644 --- a/io.openems.edge.simulator/src/io/openems/edge/simulator/app/SimulatorAppImpl.java +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/app/SimulatorAppImpl.java @@ -473,6 +473,12 @@ public int getTimeDelta() { return -1; } + @Override + public List getValues(OpenemsType type, ChannelAddress channelAddress) { + // TODO Auto-generated method stub + return List.of(); + } + @Override public T getValue(OpenemsType type, ChannelAddress channelAddress) { if (this.currentSimulation == null) { diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/datasource/api/AbstractCsvDatasource.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/datasource/api/AbstractCsvDatasource.java index 82997c7a8c2..33aae79cab5 100644 --- a/io.openems.edge.simulator/src/io/openems/edge/simulator/datasource/api/AbstractCsvDatasource.java +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/datasource/api/AbstractCsvDatasource.java @@ -3,6 +3,7 @@ import java.io.IOException; import java.time.Duration; import java.time.LocalDateTime; +import java.util.List; import java.util.Set; import org.osgi.service.component.ComponentContext; @@ -59,6 +60,20 @@ public void handleEvent(Event event) { } } + @SuppressWarnings("unchecked") + @Override + public List getValues(OpenemsType type, ChannelAddress channelAddress) { + // First: try full ChannelAddress + var values = this.data.getValues(channelAddress.toString()); + if (values.isEmpty()) { + // Not found: try Channel-ID only (without Component-ID) + values = this.data.getValues(channelAddress.getChannelId()); + } + return values.stream() // + .map(v -> (T) TypeUtils.getAsType(type, v)) // + .toList(); + } + @Override public T getValue(OpenemsType type, ChannelAddress channelAddress) { // First: try full ChannelAddress diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/datasource/api/SimulatorDatasource.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/datasource/api/SimulatorDatasource.java index cac3c09485d..f5d1411d896 100644 --- a/io.openems.edge.simulator/src/io/openems/edge/simulator/datasource/api/SimulatorDatasource.java +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/datasource/api/SimulatorDatasource.java @@ -1,5 +1,6 @@ package io.openems.edge.simulator.datasource.api; +import java.util.List; import java.util.Set; import io.openems.common.types.ChannelAddress; @@ -12,14 +13,24 @@ public interface SimulatorDatasource { * * @return the Channel-Id */ - Set getKeys(); + public Set getKeys(); /** * Returns the delta between two values in seconds. * * @return the delta in seconds */ - int getTimeDelta(); + public int getTimeDelta(); + + /** + * Gets all values for the given key (channelId) in the given type. + * + * @param the type + * @param type the expected type + * @param channelAddress the Channel-Address + * @return the values, possibly empty + */ + public List getValues(OpenemsType type, ChannelAddress channelAddress); /** * Gets the value for the given key (channelId) in the given type. @@ -29,6 +40,6 @@ public interface SimulatorDatasource { * @param channelAddress the Channel-Address * @return the value, possibly null */ - T getValue(OpenemsType type, ChannelAddress channelAddress); + public T getValue(OpenemsType type, ChannelAddress channelAddress); } diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/predictor/Config.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/predictor/Config.java new file mode 100644 index 00000000000..3498f4b97cb --- /dev/null +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/predictor/Config.java @@ -0,0 +1,38 @@ +package io.openems.edge.simulator.predictor; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +import io.openems.edge.predictor.api.prediction.LogVerbosity; + +@ObjectClassDefinition(// + name = "Simulator Predictor", // + description = "This Predictor simulates predictions from a DataSource") +@interface Config { + + @AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component") + String id() default "timedata0"; + + @AttributeDefinition(name = "Alias", description = "Human-readable name of this Component; defaults to Component-ID") + String alias() default ""; + + @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?") + boolean enabled() default true; + + @AttributeDefinition(name = "Channel-Addresses", description = "List of Channel-Addresses this Predictor is used for, e.g. '*/ActivePower', '*/ActualPower'") + String[] channelAddresses() default { // + "_sum/ProductionActivePower", // + "_sum/UnmanagedConsumptionActivePower", // + "_sum/ConsumptionActivePower" }; + + @AttributeDefinition(name = "Datasource-ID", description = "ID of Simulator Datasource.") + String datasource_id() default "datasource0"; + + @AttributeDefinition(name = "Datasource target filter", description = "This is auto-generated by 'Datasource-ID'.") + String datasource_target() default "(enabled=true)"; + + @AttributeDefinition(name = "Log-Verbosity", description = "The log verbosity.") + LogVerbosity logVerbosity() default LogVerbosity.NONE; + + String webconsole_configurationFactory_nameHint() default "Simulator Predictor [{id}]"; +} \ No newline at end of file diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/predictor/SimulatorPredictor.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/predictor/SimulatorPredictor.java new file mode 100644 index 00000000000..0a80bff172b --- /dev/null +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/predictor/SimulatorPredictor.java @@ -0,0 +1,23 @@ +package io.openems.edge.simulator.predictor; + +import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.predictor.api.prediction.Predictor; + +public interface SimulatorPredictor extends Predictor, OpenemsComponent { + + public enum ChannelId implements io.openems.edge.common.channel.ChannelId { + ; + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } +} diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/predictor/SimulatorPredictorImpl.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/predictor/SimulatorPredictorImpl.java new file mode 100644 index 00000000000..59fc9590f53 --- /dev/null +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/predictor/SimulatorPredictorImpl.java @@ -0,0 +1,102 @@ +package io.openems.edge.simulator.predictor; + +import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; +import java.util.LinkedList; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.event.propertytypes.EventTopics; +import org.osgi.service.metatype.annotations.Designate; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.types.ChannelAddress; +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.component.ClockProvider; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.event.EdgeEventConstants; +import io.openems.edge.common.type.TypeUtils; +import io.openems.edge.predictor.api.prediction.AbstractPredictor; +import io.openems.edge.predictor.api.prediction.Prediction; +import io.openems.edge.predictor.api.prediction.Predictor; +import io.openems.edge.simulator.datasource.api.SimulatorDatasource; + +@Designate(ocd = Config.class, factory = true) +@Component(// + name = "Simulator.Predictor", // + immediate = true, // + configurationPolicy = ConfigurationPolicy.REQUIRE // +) +@EventTopics({ // + EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE // +}) +public class SimulatorPredictorImpl extends AbstractPredictor + implements SimulatorPredictor, Predictor, OpenemsComponent { + + @Reference + private ComponentManager componentManager; + + @Reference + private ConfigurationAdmin cm; + + @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) + private SimulatorDatasource datasource; + + public SimulatorPredictorImpl() { + super(// + OpenemsComponent.ChannelId.values(), // + SimulatorPredictor.ChannelId.values() // + ); + } + + @Activate + private void activate(ComponentContext context, Config config) throws OpenemsNamedException { + super.activate(context, config.id(), config.alias(), config.enabled(), config.channelAddresses(), + config.logVerbosity()); + + // update filter for 'datasource' + if (OpenemsComponent.updateReferenceFilter(this.cm, this.servicePid(), "datasource", config.datasource_id())) { + return; + } + } + + @Override + @Deactivate + protected void deactivate() { + super.deactivate(); + } + + @Override + protected ClockProvider getClockProvider() { + return this.componentManager; + } + + @Override + protected Prediction createNewPrediction(ChannelAddress channelAddress) { + var source = this.datasource.getValues(OpenemsType.INTEGER, channelAddress); + if (source.isEmpty()) { + return Prediction.EMPTY_PREDICTION; + } + // Fill 48 hours starting from midnight; assume Datasource provides one vale per + // 5 minutes + var values = new Integer[48 /* hours */ * 4 /* quarters per hour */]; + var cache = new LinkedList(); + for (var i = 0; i < values.length; i++) { + while (cache.size() < 3) { + cache.addAll(source); + } + values[i] = TypeUtils.averageInt(cache.poll(), cache.poll(), cache.poll()); + } + var today = ZonedDateTime.now(this.componentManager.getClock()).truncatedTo(ChronoUnit.DAYS); + return Prediction.from(today, values); + } +} diff --git a/io.openems.edge.simulator/test/io/openems/edge/simulator/datasource/csv/direct/SimulatorDatasourceCsvDirectImplTest.java b/io.openems.edge.simulator/test/io/openems/edge/simulator/datasource/csv/direct/SimulatorDatasourceCsvDirectImplTest.java index 22f4942d5de..347a36a4535 100644 --- a/io.openems.edge.simulator/test/io/openems/edge/simulator/datasource/csv/direct/SimulatorDatasourceCsvDirectImplTest.java +++ b/io.openems.edge.simulator/test/io/openems/edge/simulator/datasource/csv/direct/SimulatorDatasourceCsvDirectImplTest.java @@ -11,17 +11,33 @@ public class SimulatorDatasourceCsvDirectImplTest { private static final String COMPONENT_ID = "datasource0"; - @Test - public void test() throws Exception { - new ComponentTest(new SimulatorDatasourceCsvDirectImpl()) // + private static ComponentTest createTest(String componentId, String source) throws Exception { + return new ComponentTest(new SimulatorDatasourceCsvDirectImpl()) // .addReference("componentManager", new DummyComponentManager()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // + .setId(componentId) // .setFactor(1) // .setFormat(CsvFormat.ENGLISH) // - .setSource("") // + .setSource(source) // .setTimeDelta(0) // - .build()) // + .build()); // + } + + /** + * Creates and activates a {@link SimulatorDatasourceCsvDirectImpl}. + * + * @param componentId the Component-ID + * @param source the data + * @return a {@link SimulatorDatasourceCsvDirectImpl} object + * @throws Exception on error + */ + public static SimulatorDatasourceCsvDirectImpl create(String componentId, String source) throws Exception { + return (SimulatorDatasourceCsvDirectImpl) createTest(componentId, source).getSut(); + } + + @Test + public void test() throws Exception { + createTest(COMPONENT_ID, "") // .next(new TestCase()) // ; } diff --git a/io.openems.edge.simulator/test/io/openems/edge/simulator/predictor/MyConfig.java b/io.openems.edge.simulator/test/io/openems/edge/simulator/predictor/MyConfig.java new file mode 100644 index 00000000000..4d2583743ae --- /dev/null +++ b/io.openems.edge.simulator/test/io/openems/edge/simulator/predictor/MyConfig.java @@ -0,0 +1,80 @@ +package io.openems.edge.simulator.predictor; + +import io.openems.common.test.AbstractComponentConfig; +import io.openems.common.utils.ConfigUtils; +import io.openems.edge.predictor.api.prediction.LogVerbosity; + +@SuppressWarnings("all") +public class MyConfig extends AbstractComponentConfig implements Config { + + protected static class Builder { + private String id; + private String datasourceId; + private String[] channelAddresses; + private LogVerbosity logVerbosity; + + private Builder() { + } + + public Builder setId(String id) { + this.id = id; + return this; + } + + public Builder setDatasourceId(String datasourceId) { + this.datasourceId = datasourceId; + return this; + } + + public Builder setChannelAddresses(String... channelAddresses) { + this.channelAddresses = channelAddresses; + return this; + } + + public Builder setLogVerbosity(LogVerbosity logVerbosity) { + this.logVerbosity = logVerbosity; + return this; + } + + public MyConfig build() { + return new MyConfig(this); + } + } + + /** + * Create a Config builder. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new Builder(); + } + + private final Builder builder; + + private MyConfig(Builder builder) { + super(Config.class, builder.id); + this.builder = builder; + } + + @Override + public String[] channelAddresses() { + return this.builder.channelAddresses; + } + + @Override + public String datasource_id() { + return this.builder.datasourceId; + } + + @Override + public String datasource_target() { + return ConfigUtils.generateReferenceTargetFilter(this.id(), this.datasource_id()); + } + + @Override + public LogVerbosity logVerbosity() { + return this.builder.logVerbosity; + } + +} \ No newline at end of file diff --git a/io.openems.edge.simulator/test/io/openems/edge/simulator/predictor/SimulatorPredictorImplTest.java b/io.openems.edge.simulator/test/io/openems/edge/simulator/predictor/SimulatorPredictorImplTest.java new file mode 100644 index 00000000000..cb52b93658c --- /dev/null +++ b/io.openems.edge.simulator/test/io/openems/edge/simulator/predictor/SimulatorPredictorImplTest.java @@ -0,0 +1,55 @@ +package io.openems.edge.simulator.predictor; + +import static org.junit.Assert.assertEquals; + +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; + +import org.junit.Test; + +import io.openems.common.exceptions.OpenemsException; +import io.openems.common.test.TimeLeapClock; +import io.openems.common.types.ChannelAddress; +import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.common.test.DummyComponentManager; +import io.openems.edge.common.test.DummyConfigurationAdmin; +import io.openems.edge.predictor.api.prediction.LogVerbosity; +import io.openems.edge.simulator.datasource.csv.direct.SimulatorDatasourceCsvDirectImplTest; + +public class SimulatorPredictorImplTest { + + private static final TimeLeapClock CLOCK = new TimeLeapClock(Instant.ofEpochSecond(946684800), ZoneId.of("UTC")); + private static final String COMPONENT_ID = "predictor0"; + private static final String DATASOURCE_ID = "datasource0"; + private static final ChannelAddress SUM_PRODUCTION = new ChannelAddress("_sum", "ProductionActivePower"); + + @Test + public void test() throws OpenemsException, Exception { + final var datasource = SimulatorDatasourceCsvDirectImplTest.create(DATASOURCE_ID, """ + 10 + 20 + 30 + 40 + """); + final var sut = new SimulatorPredictorImpl(); + new ComponentTest(sut) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("datasource", datasource) // + .addReference("componentManager", new DummyComponentManager(CLOCK)) // + .activate(MyConfig.create() // + .setId(COMPONENT_ID) // + .setDatasourceId(DATASOURCE_ID) // + .setChannelAddresses(SUM_PRODUCTION.toString()) // + .setLogVerbosity(LogVerbosity.REQUESTED_PREDICTIONS) // + .build()); // + + var p = sut.createNewPrediction(SUM_PRODUCTION); + assertEquals(192, p.asArray().length); + assertEquals(Integer.valueOf(20), p.asArray()[0]); + assertEquals(Integer.valueOf(23), p.asArray()[1]); + assertEquals(Integer.valueOf(27), p.asArray()[2]); + assertEquals(ZonedDateTime.of(2000, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC")), p.valuePerQuarter.firstKey()); + } + +} diff --git a/ui/src/app/app-routing.module.ts b/ui/src/app/app-routing.module.ts index b04097ce80b..f84be2e897f 100644 --- a/ui/src/app/app-routing.module.ts +++ b/ui/src/app/app-routing.module.ts @@ -9,12 +9,14 @@ import { OverviewComponent as ConsumptionChartOverviewComponent } from "./edge/h import { DetailsOverviewComponent as GridDetailsOverviewComponent } from "./edge/history/common/grid/details/details.overview"; import { OverviewComponent as GridChartOverviewComponent } from "./edge/history/common/grid/overview/overview"; import { DetailsOverviewComponent } from "./edge/history/common/production/details/details.overview"; -import { DetailsOverviewComponent as DigitalOutputDetailsOverviewComponent } from "./edge/history/Controller/Io/DigitalOutput/details/details.overview"; import { OverviewComponent as ProductionChartOverviewComponent } from "./edge/history/common/production/overview/overview"; import { OverviewComponent as SelfconsumptionChartOverviewComponent } from "./edge/history/common/selfconsumption/overview/overview"; import { OverviewComponent as ChannelthresholdChartOverviewComponent } from "./edge/history/Controller/ChannelThreshold/overview/overview"; import { OverviewComponent as GridOptimizedChargeChartOverviewComponent } from "./edge/history/Controller/Ess/GridoptimizedCharge/overview/overview"; import { OverviewComponent as TimeOfUseTariffOverviewComponent } from "./edge/history/Controller/Ess/TimeOfUseTariff/overview/overview"; +import { DetailsOverviewComponent as DigitalOutputDetailsOverviewComponent } from "./edge/history/Controller/Io/DigitalOutput/details/details.overview"; +import { OverviewComponent as DigitalOutputChartOverviewComponent } from "./edge/history/Controller/Io/DigitalOutput/overview/overview"; +import { OverviewComponent as ModbusTcpApiOverviewComponent } from "./edge/history/Controller/ModbusTcpApi/overview/overview"; import { DelayedSellToGridChartOverviewComponent } from "./edge/history/delayedselltogrid/symmetricpeakshavingchartoverview/delayedselltogridchartoverview.component"; import { HeatingelementChartOverviewComponent } from "./edge/history/heatingelement/heatingelementchartoverview/heatingelementchartoverview.component"; import { HeatPumpChartOverviewComponent } from "./edge/history/heatpump/heatpumpchartoverview/heatpumpchartoverview.component"; @@ -48,14 +50,12 @@ import { SystemExecuteComponent as EdgeSettingsSystemExecuteComponent } from "./ import { SystemLogComponent as EdgeSettingsSystemLogComponent } from "./edge/settings/systemlog/systemlog.component"; import { LoginComponent } from "./index/login.component"; import { OverViewComponent } from "./index/overview/overview.component"; -import { UserComponent } from "./user/user.component"; import { LoadingScreenComponent } from "./index/shared/loading-screen"; import { CurrentAndVoltageOverviewComponent } from "./shared/components/edge/meter/currentVoltage/currentVoltage.overview"; import { DataService } from "./shared/components/shared/dataservice"; import { hasEdgeRole } from "./shared/guards/functional-guards"; import { Role } from "./shared/type/role"; -import { OverviewComponent as DigitalOutputChartOverviewComponent } from "./edge/history/Controller/Io/DigitalOutput/overview/overview"; - +import { UserComponent } from "./user/user.component"; export const routes: Routes = [ @@ -101,6 +101,7 @@ export const routes: Routes = [ { path: "gridchart", component: GridChartOverviewComponent }, { path: "gridchart/:componentId", component: GridDetailsOverviewComponent }, { path: "gridchart/:componentId/currentVoltage", component: CurrentAndVoltageOverviewComponent }, + { path: ":componentId/modbusTcpApi", component: ModbusTcpApiOverviewComponent }, { path: "productionchart", component: ProductionChartOverviewComponent }, { path: "productionchart/:componentId", component: DetailsOverviewComponent }, { path: "productionchart/:componentId/currentVoltage", component: CurrentAndVoltageOverviewComponent }, diff --git a/ui/src/app/app.component.ts b/ui/src/app/app.component.ts index bcab88af3be..27d05b4410d 100644 --- a/ui/src/app/app.component.ts +++ b/ui/src/app/app.component.ts @@ -8,6 +8,7 @@ import { Subject, Subscription } from "rxjs"; import { filter, takeUntil } from "rxjs/operators"; import { environment } from "../environments"; import { AppService } from "./app.service"; +import { AppStateTracker } from "./shared/ngrx-store/states"; import { GlobalRouteChangeHandler } from "./shared/service/globalRouteChangeHandler"; import { Service, UserPermission, Websocket } from "./shared/shared"; import { Language } from "./shared/type/language"; @@ -42,6 +43,7 @@ export class AppComponent implements OnInit, OnDestroy { private meta: Meta, private appService: AppService, private title: Title, + private stateService: AppStateTracker, ) { 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 8a191a18baa..e8ad40d998a 100644 --- a/ui/src/app/app.module.ts +++ b/ui/src/app/app.module.ts @@ -23,6 +23,7 @@ import { IndexModule } from "./index/index.module"; import { RegistrationModule } from "./registration/registration.module"; import { StatusSingleComponent } from "./shared/components/status/single/status.component"; import { ChartOptionsPopoverComponent } from "./shared/legacy/chartoptions/popover/popover.component"; +import { AppStateTracker } from "./shared/ngrx-store/states"; import { MyErrorHandler } from "./shared/service/myerrorhandler"; import { Pagination } from "./shared/service/pagination"; import { SharedModule } from "./shared/shared.module"; @@ -64,6 +65,7 @@ import { UserModule } from "./user/user.module"; Pagination, CheckForUpdateService, AppService, + AppStateTracker, ], bootstrap: [AppComponent], }) diff --git a/ui/src/app/edge/history/Controller/ModbusTcpApi/chart/channels.spec.ts b/ui/src/app/edge/history/Controller/ModbusTcpApi/chart/channels.spec.ts new file mode 100644 index 00000000000..d96d89c0015 --- /dev/null +++ b/ui/src/app/edge/history/Controller/ModbusTcpApi/chart/channels.spec.ts @@ -0,0 +1,1070 @@ +import { TimeUnit } from "chart.js"; +import { ChartConstants } from "src/app/shared/components/chart/chart.constants"; +import { OeTester } from "src/app/shared/components/shared/testing/common"; +import { OeChartTester } from "src/app/shared/components/shared/testing/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, chartType: "line" | "bar", options: { [key: string]: { scale: { min: number, max: number; }, ticks: { stepSize: number; }; }; }): OeChartTester.Dataset.Option => ({ + type: "option", + options: { + "responsive": true, "maintainAspectRatio": false, "elements": { "point": { "radius": 0, "hitRadius": 0, "hoverRadius": 0 }, "line": { "stepped": false, "fill": true } }, "datasets": { "bar": {}, "line": {} }, "plugins": { "colors": { "enabled": false }, "legend": { "display": true, "position": "bottom", "labels": { "color": "" } }, "tooltip": { "intersect": false, "mode": "index", "callbacks": {} } }, "scales": { + "x": { "stacked": true, "offset": false, "type": "time", "ticks": { "source": "auto", "maxTicksLimit": 31 }, "bounds": "ticks", "adapters": { "date": { "locale": { "code": "de", "formatLong": {}, "localize": {}, "match": {}, "options": { "weekStartsOn": 1, "firstWeekContainsDate": 4 } } } }, "time": { "unit": period as TimeUnit, "displayFormats": { "datetime": "yyyy-MM-dd HH:mm:ss", "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" } } }, + "left": { + ...options["right"]?.scale, ...(chartType === "line" ? { stacked: false } : {}), "beginAtZero": true, "max": 100, "min": 0, "type": "linear", "title": { "text": "%", "display": true, "font": { "size": 11 }, "padding": 5 }, "position": "right", "grid": { "display": false }, + "ticks": { + ...options["right"]?.ticks, + "color": "", + "padding": 5, + "maxTicksLimit": ChartConstants.NUMBER_OF_Y_AXIS_TICKS, + }, + }, + }, + }, + }); + export const BAR_CHART_OPTIONS = (period: string, chartType: "line" | "bar", options: { [key: string]: { scale: { min?: number, max?: number; }, ticks: { stepSize?: number; }; }; }): OeChartTester.Dataset.Option => ({ + type: "option", + options: { + "responsive": true, "maintainAspectRatio": false, "elements": { "point": { "radius": 0, "hitRadius": 0, "hoverRadius": 0 }, "line": { "stepped": false, "fill": true } }, "datasets": { "bar": { "barPercentage": 1 }, "line": {} }, "plugins": { "colors": { "enabled": false }, "legend": { "display": true, "position": "bottom", "labels": { "color": "" } }, "tooltip": { "intersect": false, "mode": "x", "callbacks": {} } }, "scales": { + "x": { "stacked": true, "offset": true, "type": "time", "ticks": { "source": "auto", "maxTicksLimit": 31 }, "bounds": "ticks", "adapters": { "date": { "locale": { "code": "de", "formatLong": {}, "localize": {}, "match": {}, "options": { "weekStartsOn": 1, "firstWeekContainsDate": 4 } } } }, "time": { "unit": period as TimeUnit, "displayFormats": { "datetime": "yyyy-MM-dd HH:mm:ss", "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" } } }, + "left": { + ...options["left"]?.scale, ...(chartType === "line" ? { stacked: false } : {}), "title": { "text": "kWh", "display": true, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, + "ticks": { + ...options["left"]?.ticks, + "color": "", + "padding": 5, + "maxTicksLimit": ChartConstants.NUMBER_OF_Y_AXIS_TICKS, + }, + }, + }, + }, + }); + + /** + * up to 288 datapoints (5 min aggregated values) from a + * + * {@link Day.energyPerPeriodChannelWithValues} and {@link Day.dataChannelWithValues} + * */ + export const DAY: OeTester.Types.Channels = ({ + energyChannelWithValues: new QueryHistoricTimeseriesEnergyResponse("0", { + data: {}, + }), + dataChannelWithValues: new QueryHistoricTimeseriesDataResponse("0", { + data: { + "ctrlApiModbusTcp0/Ess0SetActivePowerEquals": [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], + }, + 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: OeTester.Types.Channels = ({ + energyChannelWithValues: new QueryHistoricTimeseriesEnergyResponse("0", { + data: {}, + }), + dataChannelWithValues: new QueryHistoricTimeseriesDataResponse("0", { + data: { + "ctrlApiModbusTcp0/Ess0SetActivePowerEquals": [ + 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, + ], + }, + timestamps: [ + "2023-07-01T00:00:00Z", + "2023-07-02T00:00:00Z", + "2023-07-03T00:00:00Z", + "2023-07-04T00:00:00Z", + "2023-07-05T00:00:00Z", + "2023-07-06T00:00:00Z", + "2023-07-07T00:00:00Z", + "2023-07-08T00:00:00Z", + "2023-07-09T00:00:00Z", + "2023-07-10T00:00:00Z", + "2023-07-11T00:00:00Z", + "2023-07-12T00:00:00Z", + "2023-07-13T00:00:00Z", + "2023-07-14T00:00:00Z", + "2023-07-15T00:00:00Z", + "2023-07-16T00:00:00Z", + "2023-07-17T00:00:00Z", + "2023-07-18T00:00:00Z", + "2023-07-19T00:00:00Z", + "2023-07-20T00:00:00Z", + "2023-07-21T00:00:00Z", + "2023-07-22T00:00:00Z", + "2023-07-23T00:00:00Z", + "2023-07-24T00:00:00Z", + "2023-07-25T00:00:00Z", + "2023-07-26T00:00:00Z", + "2023-07-27T00:00:00Z", + "2023-07-28T00:00:00Z", + "2023-07-29T00:00:00Z", + "2023-07-30T00:00:00Z", + "2023-07-31T00:00:00Z", + ], + }), + }); + + + /** + * up to 31 datapoints(1 day values) from a {@link Day.energyPerPeriodChannelWithValues} and {@link Day.dataChannelWithValues}*/ + export const MONTH: OeTester.Types.Channels = { + 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: OeTester.Types.Channels = { + 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", + ], + }), + }; +} diff --git a/ui/src/app/edge/history/Controller/ModbusTcpApi/chart/chart.ts b/ui/src/app/edge/history/Controller/ModbusTcpApi/chart/chart.ts new file mode 100644 index 00000000000..987109ea767 --- /dev/null +++ b/ui/src/app/edge/history/Controller/ModbusTcpApi/chart/chart.ts @@ -0,0 +1,89 @@ +// @ts-strict-ignore +import { Component } from "@angular/core"; +import { TranslateService } from "@ngx-translate/core"; +import { AbstractHistoryChart } from "src/app/shared/components/chart/abstracthistorychart"; +import { ChartAxis, HistoryUtils, YAxisType } from "src/app/shared/service/utils"; +import { ChannelAddress, EdgeConfig } from "src/app/shared/shared"; + +@Component({ + selector: "modbusTcpApiChart", + templateUrl: "../../../../../shared/components/chart/abstracthistorychart.html", +}) +export class ChartComponent extends AbstractHistoryChart { + + public static getChartData(component: EdgeConfig.Component, config: EdgeConfig, chartType: "line" | "bar", translate: TranslateService, showPhases: boolean): HistoryUtils.ChartData { + let writeChannels: string[] = []; + + const colors: string[] = [ + "rgb(191, 144, 33)", + "rgb(162, 191, 33)", + "rgb(86, 191, 33)", + "rgb(33, 191, 165)", + "rgb(33, 115, 191)", + ]; + + const input: HistoryUtils.InputChannel[] = + [{ + name: "SetActivePowerEquals", + powerChannel: ChannelAddress.fromString(component.id + "/Ess0SetActivePowerEquals"), + }]; + + if (component.properties.writeChannels) { + writeChannels = component.properties.writeChannels.filter(c => !c.includes("Ess0SetActivePowerEquals")); + writeChannels.forEach(c => { + input.push({ + name: c, + powerChannel: ChannelAddress.fromString(component.id + `/${c}`), + }); + }); + } + + return { + input, + output: (data: HistoryUtils.ChannelData) => { + const values: HistoryUtils.DisplayValue[] = [{ + name: translate.instant("MODBUS_TCP_API_READ_WRITE.SET_ACTIVE_POWER_EQUALS"), + converter: () => data["SetActivePowerEquals"], + color: "rgb(214, 28, 28)", + }]; + if (writeChannels) { + writeChannels.forEach((c: string, index: number) => { + const name: string = c; + // Add translations for active power channels of ess0 + if (c.includes("Ess0SetActive")) { + const channelName = c.replace("Ess0", ""); + switch (channelName) { + case "SetActivePowerEquals": + return translate.instant("MODBUS_TCP_API_READ_WRITE.SET_ACTIVE_POWER_EQUALS"); + case "SetActivePowerGreaterOrEquals": + return translate.instant("MODBUS_TCP_API_READ_WRITE.SET_ACTIVE_POWER_GREATER_OR_EQUALS"); + case "SetActivePowerLessOrEquals": + return translate.instant("MODBUS_TCP_API_READ_WRITE.SET_ACTIVE_POWER_LESS_OR_EQUALS"); + } + } + + values.push({ + name: name, + converter: () => data[c], + color: colors[index], + }); + }); + } + return values; + }, + tooltip: { + formatNumber: "1.1-2", + }, + yAxes: [{ + unit: YAxisType.ENERGY, + position: "left", + yAxisId: ChartAxis.LEFT, + }, + ], + }; + } + + public override getChartData() { + return ChartComponent.getChartData(this.component, this.config, this.chartType, this.translate, this.showPhases); + } +} diff --git a/ui/src/app/edge/history/Controller/ModbusTcpApi/flat/flat.html b/ui/src/app/edge/history/Controller/ModbusTcpApi/flat/flat.html new file mode 100644 index 00000000000..e7a0c6ad6a6 --- /dev/null +++ b/ui/src/app/edge/history/Controller/ModbusTcpApi/flat/flat.html @@ -0,0 +1,5 @@ + + + + diff --git a/ui/src/app/edge/history/Controller/ModbusTcpApi/flat/flat.ts b/ui/src/app/edge/history/Controller/ModbusTcpApi/flat/flat.ts new file mode 100644 index 00000000000..9a857c71826 --- /dev/null +++ b/ui/src/app/edge/history/Controller/ModbusTcpApi/flat/flat.ts @@ -0,0 +1,21 @@ +import { Component } from "@angular/core"; + +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; +import { ChannelAddress } from "src/app/shared/shared"; + +@Component({ + selector: "modbusTcpApiWidget", + templateUrl: "./flat.html", +}) +export class FlatComponent extends AbstractFlatWidget { + + protected TIME_CONVERTER = this.Converter.FORMAT_SECONDS_TO_DURATION("de"); + + protected override getChannelAddresses(): ChannelAddress[] { + + return [ + new ChannelAddress(this.component.id, "CumulatedInactiveTime"), + new ChannelAddress(this.component.id, "CumulatedActiveTime"), + ]; + } +} diff --git a/ui/src/app/edge/history/Controller/ModbusTcpApi/modbusTcpApi.module.ts b/ui/src/app/edge/history/Controller/ModbusTcpApi/modbusTcpApi.module.ts new file mode 100644 index 00000000000..aef372d5a35 --- /dev/null +++ b/ui/src/app/edge/history/Controller/ModbusTcpApi/modbusTcpApi.module.ts @@ -0,0 +1,24 @@ +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 { OverviewComponent } from "./overview/overview"; +import { ChartComponent } from "./chart/chart"; + +@NgModule({ + imports: [ + BrowserModule, + SharedModule, + ], + declarations: [ + FlatComponent, + OverviewComponent, + ChartComponent, + ], + exports: [ + FlatComponent, + OverviewComponent, + ChartComponent, + ], +}) +export class ModbusTcpApi { } diff --git a/ui/src/app/edge/history/Controller/ModbusTcpApi/overview/overview.html b/ui/src/app/edge/history/Controller/ModbusTcpApi/overview/overview.html new file mode 100644 index 00000000000..c08da36f604 --- /dev/null +++ b/ui/src/app/edge/history/Controller/ModbusTcpApi/overview/overview.html @@ -0,0 +1,23 @@ + + +
      + + + + + + + Edge.Index.Widgets.InfoStorageForCharge + + + + + Edge.Index.Widgets.InfoStorageForDischarge + + + + + +
      +
      +
      diff --git a/ui/src/app/edge/history/Controller/ModbusTcpApi/overview/overview.ts b/ui/src/app/edge/history/Controller/ModbusTcpApi/overview/overview.ts new file mode 100644 index 00000000000..51ed8f95a67 --- /dev/null +++ b/ui/src/app/edge/history/Controller/ModbusTcpApi/overview/overview.ts @@ -0,0 +1,7 @@ +import { Component } from "@angular/core"; +import { AbstractHistoryChartOverview } from "src/app/shared/components/chart/abstractHistoryChartOverview"; + +@Component({ + templateUrl: "./overview.html", +}) +export class OverviewComponent extends AbstractHistoryChartOverview { } diff --git a/ui/src/app/edge/history/Controller/controller.module.ts b/ui/src/app/edge/history/Controller/controller.module.ts index dec242649f6..e009e41d838 100644 --- a/ui/src/app/edge/history/Controller/controller.module.ts +++ b/ui/src/app/edge/history/Controller/controller.module.ts @@ -4,6 +4,7 @@ import { ControllerIo } from "./Io/Io.module"; import { ChannelThreshold } from "./ChannelThreshold/channelThreshold.module"; import { GridOptimizeCharge } from "./Ess/GridoptimizedCharge/gridOptimizeCharge.module"; import { TimeOfUseTariff } from "./Ess/TimeOfUseTariff/timeOfUseTariff.module"; +import { ModbusTcpApi } from "./ModbusTcpApi/modbusTcpApi.module"; @NgModule({ imports: [ @@ -11,6 +12,7 @@ import { TimeOfUseTariff } from "./Ess/TimeOfUseTariff/timeOfUseTariff.module"; ControllerIo, ChannelThreshold, TimeOfUseTariff, + ModbusTcpApi, GridOptimizeCharge, ], exports: [ @@ -18,6 +20,7 @@ import { TimeOfUseTariff } from "./Ess/TimeOfUseTariff/timeOfUseTariff.module"; ControllerIo, ChannelThreshold, TimeOfUseTariff, + ModbusTcpApi, GridOptimizeCharge, ], }) diff --git a/ui/src/app/edge/history/history.component.html b/ui/src/app/edge/history/history.component.html index 8774f678d1b..bd86a09bf04 100644 --- a/ui/src/app/edge/history/history.component.html +++ b/ui/src/app/edge/history/history.component.html @@ -38,6 +38,10 @@ + + + + @@ -72,6 +76,13 @@ + + + + + + + diff --git a/ui/src/app/edge/history/history.component.ts b/ui/src/app/edge/history/history.component.ts index 1e3672ca491..e2349530d0d 100644 --- a/ui/src/app/edge/history/history.component.ts +++ b/ui/src/app/edge/history/history.component.ts @@ -5,7 +5,7 @@ import { TranslateService } from "@ngx-translate/core"; import { AppService } from "src/app/app.service"; import { HeaderComponent } from "src/app/shared/components/header/header.component"; import { JsonrpcResponseError } from "src/app/shared/jsonrpc/base"; -import { Edge, EdgeConfig, Service, Widgets } from "src/app/shared/shared"; +import { Edge, EdgeConfig, EdgePermission, Service, Widgets } from "src/app/shared/shared"; import { environment } from "src/environments"; @Component({ @@ -34,6 +34,7 @@ export class HistoryComponent implements OnInit { public config: EdgeConfig | null = null; protected errorResponse: JsonrpcResponseError | null = null; + protected isModbusTcpWidgetAllowed: boolean = false; constructor( public service: Service, @@ -44,6 +45,7 @@ export class HistoryComponent implements OnInit { ngOnInit() { this.service.currentEdge.subscribe((edge) => { this.edge = edge; + this.isModbusTcpWidgetAllowed = EdgePermission.isModbusTcpApiWidgetAllowed(edge); }); this.service.getConfig().then(config => { // gather ControllerIds of Channelthreshold Components diff --git a/ui/src/app/edge/live/Controller/ModbusTcpApi/flat/flat.html b/ui/src/app/edge/live/Controller/ModbusTcpApi/flat/flat.html new file mode 100644 index 00000000000..9df8ac9fb01 --- /dev/null +++ b/ui/src/app/edge/live/Controller/ModbusTcpApi/flat/flat.html @@ -0,0 +1,3 @@ + + + diff --git a/ui/src/app/edge/live/Controller/ModbusTcpApi/flat/flat.ts b/ui/src/app/edge/live/Controller/ModbusTcpApi/flat/flat.ts new file mode 100644 index 00000000000..89b23b86751 --- /dev/null +++ b/ui/src/app/edge/live/Controller/ModbusTcpApi/flat/flat.ts @@ -0,0 +1,51 @@ +import { Component } from "@angular/core"; +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; +import { ChannelAddress, CurrentData } from "src/app/shared/shared"; +import { OverrideStatus } from "src/app/shared/type/general"; +import { ModalComponent } from "../modal/modal"; + +@Component({ + selector: "Controller_Api_ModbusTcp", + templateUrl: "./flat.html", +}) +export class FlatComponent extends AbstractFlatWidget { + + protected overrideStatus: OverrideStatus | null = null; + + async presentModal() { + if (!this.isInitialized) { + return; + } + const modal = await this.modalController.create({ + component: ModalComponent, + componentProps: { + component: this.component, + }, + }); + return await modal.present(); + } + + + protected override getChannelAddresses(): ChannelAddress[] { + + return [ + new ChannelAddress(this.component.id, "OverrideStatus"), + ]; + } + + protected override onCurrentData(currentData: CurrentData) { + this.overrideStatus = this.getTranslatedState(currentData.allComponents[this.component.id + "/OverrideStatus"]); + } + + private getTranslatedState(state: OverrideStatus) { + switch (state) { + case OverrideStatus.ACTIVE: + return this.translate.instant("MODBUS_TCP_API_READ_WRITE.OVERRIDING"); + case OverrideStatus.ERROR: + return this.translate.instant("EVCS.error"); + default: + return this.translate.instant("MODBUS_TCP_API_READ_WRITE.NOT_OVERRIDING"); + } + } + +} diff --git a/ui/src/app/edge/live/Controller/ModbusTcpApi/modal/modal.html b/ui/src/app/edge/live/Controller/ModbusTcpApi/modal/modal.html new file mode 100644 index 00000000000..b8468f22958 --- /dev/null +++ b/ui/src/app/edge/live/Controller/ModbusTcpApi/modal/modal.html @@ -0,0 +1,23 @@ + + + + + + + + + + + + +
      + +
      + +
      + +
      + {{ 'MODBUS_TCP_API_READ_WRITE.DOWNLOAD_PROTOCOL' | translate }} +
      + +
      diff --git a/ui/src/app/edge/live/Controller/ModbusTcpApi/modal/modal.ts b/ui/src/app/edge/live/Controller/ModbusTcpApi/modal/modal.ts new file mode 100644 index 00000000000..ae11a7a121a --- /dev/null +++ b/ui/src/app/edge/live/Controller/ModbusTcpApi/modal/modal.ts @@ -0,0 +1,102 @@ +// @ts-strict-ignore +import { Component } from "@angular/core"; +import { ProfileComponent } from "src/app/edge/settings/profile/profile.component"; +import { AbstractModal } from "src/app/shared/components/modal/abstractModal"; +import { Converter } from "src/app/shared/components/shared/converter"; +import { ChannelAddress, ChannelRegister, CurrentData } from "src/app/shared/shared"; +import { OverrideStatus } from "src/app/shared/type/general"; + +@Component({ + templateUrl: "./modal.html", +}) +export class ModalComponent extends AbstractModal { + + protected readonly CONVERT_TO_WATT = Converter.POWER_IN_WATT; + + protected writeChannelValues: number[] | null = []; + protected writeChannels: ChannelAddress[] | null = []; + protected overrideStatus: string | null = null; + protected formattedWriteChannels: string[] | null = null; + + protected activePowerEqualsChannel: ChannelAddress | null = null; + protected activePowerEqualsValue: number | null = null; + protected channelRegisters = ChannelRegister; + + private profile = new ProfileComponent(this.service, this.route, null, this.translate); + + protected override getChannelAddresses(): ChannelAddress[] { + this.activePowerEqualsChannel = new ChannelAddress(this.component.id, "Ess0SetActivePowerEquals"); + const writeChannelIds = this.config.components[this.component.id]?.properties.writeChannels || []; + this.writeChannels = writeChannelIds.map(channelId => new ChannelAddress(this.component.id, channelId)); + return [ + ...this.writeChannels, + this.activePowerEqualsChannel, + new ChannelAddress(this.component.id, "OverrideStatus"), + ]; + } + + protected override onIsInitialized(): void { + this.edge.getConfig(this.websocket).subscribe((config) => { + const newChannels = (config.components[this.component.id]?.properties?.writeChannels || []) + .map(channelId => new ChannelAddress(this.component.id, channelId)); + + this.writeChannels = newChannels.filter(channel => !channel.channelId.includes("Ess0SetActivePowerEquals")); + this.getFormatChannelNames(); + this.edge.subscribeChannels(this.websocket, this.component.id, this.writeChannels); + }); + } + + protected getModbusProtocol(componentId: string) { + return this.profile.getModbusProtocol(componentId); + } + + protected override onCurrentData(currentData: CurrentData) { + this.activePowerEqualsValue = this.edge.currentData.value.channel[this.activePowerEqualsChannel!.toString()]; + this.writeChannelValues = this.writeChannels?.map(channel => + this.edge.currentData.value.channel[channel.toString()], + ) || []; + this.overrideStatus = this.getTranslatedState(currentData.allComponents[this.component.id + "/OverrideStatus"]); + } + + protected getTranslatedChannel(channel: ChannelAddress): string { + if (channel.channelId.includes("Ess0SetActive")) { + const channelName = channel.channelId.replace("Ess0", ""); + switch (channelName) { + case "SetActivePowerEquals": + return this.translate.instant("MODBUS_TCP_API_READ_WRITE.SET_ACTIVE_POWER_EQUALS"); + case "SetActivePowerGreaterOrEquals": + return this.translate.instant("MODBUS_TCP_API_READ_WRITE.SET_ACTIVE_POWER_GREATER_OR_EQUALS"); + case "SetActivePowerLessOrEquals": + return this.translate.instant("MODBUS_TCP_API_READ_WRITE.SET_ACTIVE_POWER_LESS_OR_EQUALS"); + } + } + } + + private getTranslatedState(state: OverrideStatus) { + switch (state) { + case OverrideStatus.ACTIVE: + return this.translate.instant("MODBUS_TCP_API_READ_WRITE.OVERRIDING"); + case OverrideStatus.ERROR: + return this.translate.instant("EVCS.error"); + default: + return this.translate.instant("MODBUS_TCP_API_READ_WRITE.NOT_OVERRIDING"); + } + } + + /** + * This method adds the name and register number of the corresponding channel to + * the modal view. It has to be done dynamically since channels can be overwritten in any order. + */ + private getFormatChannelNames(): void { + this.formattedWriteChannels = []; + this.writeChannels.forEach(channel => { + for (const registerName in ChannelRegister) { + if (channel.channelId.includes(registerName)) { + // If channelId is included in ChannelRegister, get key/value e.g. SetActivePowerEquals/706 + const formattedString = `(${registerName}/${ChannelRegister[registerName]})`; + this.formattedWriteChannels.push(formattedString); + } + } + }); + } +} diff --git a/ui/src/app/edge/live/Controller/ModbusTcpApi/modbusTcpApi.module.ts b/ui/src/app/edge/live/Controller/ModbusTcpApi/modbusTcpApi.module.ts new file mode 100644 index 00000000000..69104d3973c --- /dev/null +++ b/ui/src/app/edge/live/Controller/ModbusTcpApi/modbusTcpApi.module.ts @@ -0,0 +1,20 @@ +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"; + +@NgModule({ + imports: [ + BrowserModule, + SharedModule, + ], + declarations: [ + FlatComponent, + ModalComponent, + ], + exports: [ + FlatComponent, + ], +}) +export class Controller_Api_ModbusTcp { } diff --git a/ui/src/app/edge/live/live.component.html b/ui/src/app/edge/live/live.component.html index edf538ba7ab..88a68dd2777 100644 --- a/ui/src/app/edge/live/live.component.html +++ b/ui/src/app/edge/live/live.component.html @@ -81,6 +81,13 @@
      + + + + + + diff --git a/ui/src/app/edge/live/live.component.ts b/ui/src/app/edge/live/live.component.ts index e3e022542c6..335b7d1fa62 100644 --- a/ui/src/app/edge/live/live.component.ts +++ b/ui/src/app/edge/live/live.component.ts @@ -3,7 +3,7 @@ import { ActivatedRoute } from "@angular/router"; import { RefresherCustomEvent } from "@ionic/angular"; import { Subject } from "rxjs"; import { DataService } from "src/app/shared/components/shared/dataservice"; -import { Edge, EdgeConfig, Service, Utils, Websocket, Widgets } from "src/app/shared/shared"; +import { Edge, EdgeConfig, EdgePermission, Service, Utils, Websocket, Widgets } from "src/app/shared/shared"; @Component({ selector: "live", @@ -14,6 +14,7 @@ export class LiveComponent implements OnInit, OnDestroy { public edge: Edge | null = null; public config: EdgeConfig | null = null; public widgets: Widgets | null = null; + protected isModbusTcpWidgetAllowed: boolean = false; private stopOnDestroy: Subject = new Subject(); constructor( @@ -27,6 +28,7 @@ export class LiveComponent implements OnInit, OnDestroy { public ngOnInit() { this.service.currentEdge.subscribe((edge) => { this.edge = edge; + this.isModbusTcpWidgetAllowed = EdgePermission.isModbusTcpApiWidgetAllowed(edge); }); this.service.getConfig().then(config => { this.config = config; diff --git a/ui/src/app/edge/live/live.module.ts b/ui/src/app/edge/live/live.module.ts index e3d7bbc0de3..944e2240b03 100644 --- a/ui/src/app/edge/live/live.module.ts +++ b/ui/src/app/edge/live/live.module.ts @@ -2,21 +2,14 @@ import { NgModule } from "@angular/core"; import { BrowserModule } from "@angular/platform-browser"; import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; import { SharedModule } from "./../../shared/shared.module"; -import { Common_Autarchy } from "./common/autarchy/Common_Autarchy"; -import { Common_Consumption } from "./common/consumption/Common_Consumption"; -import { Common_Grid } from "./common/grid/Common_Grid"; -import { Common_Production } from "./common/production/Common_Production"; -import { Common_Selfconsumption } from "./common/selfconsumption/Common_Selfconsumption"; -import { StorageModalComponent } from "./common/storage/modal/modal.component"; -import { StorageComponent } from "./common/storage/storage.component"; import { Controller_ChannelthresholdComponent } from "./Controller/Channelthreshold/Channelthreshold"; import { Controller_ChpSocComponent } from "./Controller/ChpSoc/ChpSoc"; import { Controller_ChpSocModalComponent } from "./Controller/ChpSoc/modal/modal.component"; import { Controller_Ess_FixActivePower } from "./Controller/Ess/FixActivePower/Ess_FixActivePower"; import { Controller_Ess_GridOptimizedCharge } from "./Controller/Ess/GridOptimizedCharge/Ess_GridOptimizedCharge"; import { Controller_Ess_TimeOfUseTariff } from "./Controller/Ess/TimeOfUseTariff/Ess_TimeOfUseTariff"; -import { AdministrationComponent } from "./Controller/Evcs/administration/administration.component"; import { Controller_Evcs } from "./Controller/Evcs/Evcs"; +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"; @@ -24,22 +17,30 @@ import { Controller_Io_FixDigitalOutputModalComponent } from "./Controller/Io/Fi import { Controller_Io_HeatingElement } from "./Controller/Io/HeatingElement/Io_HeatingElement"; import { Controller_Io_HeatpumpComponent } from "./Controller/Io/Heatpump/Io_Heatpump"; import { Controller_Io_HeatpumpModalComponent } from "./Controller/Io/Heatpump/modal/modal.component"; +import { Controller_Api_ModbusTcp } from "./Controller/ModbusTcpApi/modbusTcpApi.module"; import { Controller_Asymmetric_PeakShavingComponent } from "./Controller/PeakShaving/Asymmetric/Asymmetric"; import { Controller_Asymmetric_PeakShavingModalComponent } from "./Controller/PeakShaving/Asymmetric/modal/modal.component"; -import { Controller_Symmetric_PeakShavingModalComponent } from "./Controller/PeakShaving/Symmetric/modal/modal.component"; import { Controller_Symmetric_PeakShavingComponent } from "./Controller/PeakShaving/Symmetric/Symmetric"; -import { Controller_Symmetric_TimeSlot_PeakShavingModalComponent } from "./Controller/PeakShaving/Symmetric_TimeSlot/modal/modal.component"; +import { Controller_Symmetric_PeakShavingModalComponent } from "./Controller/PeakShaving/Symmetric/modal/modal.component"; import { Controller_Symmetric_TimeSlot_PeakShavingComponent } from "./Controller/PeakShaving/Symmetric_TimeSlot/Symmetric_TimeSlot"; -import { DelayedSellToGridComponent } from "./delayedselltogrid/delayedselltogrid.component"; -import { DelayedSellToGridModalComponent } from "./delayedselltogrid/modal/modal.component"; -import { EnergymonitorModule } from "./energymonitor/energymonitor.module"; -import { InfoComponent } from "./info/info.component"; +import { Controller_Symmetric_TimeSlot_PeakShavingModalComponent } from "./Controller/PeakShaving/Symmetric_TimeSlot/modal/modal.component"; import { Io_Api_DigitalInputComponent } from "./Io/Api_DigitalInput/Io_Api_DigitalInput"; import { Io_Api_DigitalInput_ModalComponent } from "./Io/Api_DigitalInput/modal/modal.component"; -import { LiveComponent } from "./live.component"; import { Evcs_Api_ClusterComponent } from "./Multiple/Evcs_Api_Cluster/Evcs_Api_Cluster"; 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 { Common_Autarchy } from "./common/autarchy/Common_Autarchy"; +import { Common_Consumption } from "./common/consumption/Common_Consumption"; +import { Common_Grid } from "./common/grid/Common_Grid"; +import { Common_Production } from "./common/production/Common_Production"; +import { Common_Selfconsumption } from "./common/selfconsumption/Common_Selfconsumption"; +import { StorageModalComponent } from "./common/storage/modal/modal.component"; +import { StorageComponent } from "./common/storage/storage.component"; +import { DelayedSellToGridComponent } from "./delayedselltogrid/delayedselltogrid.component"; +import { DelayedSellToGridModalComponent } from "./delayedselltogrid/modal/modal.component"; +import { EnergymonitorModule } from "./energymonitor/energymonitor.module"; +import { InfoComponent } from "./info/info.component"; +import { LiveComponent } from "./live.component"; import { OfflineComponent } from "./offline/offline.component"; @NgModule({ @@ -56,6 +57,7 @@ import { OfflineComponent } from "./offline/offline.component"; Controller_Ess_FixActivePower, Controller_Ess_GridOptimizedCharge, Controller_Io_HeatingElement, + Controller_Api_ModbusTcp, EnergymonitorModule, SharedModule, Controller_Evcs, diff --git a/ui/src/app/index/login.component.ts b/ui/src/app/index/login.component.ts index 146cbd32166..4fa20f9aeff 100644 --- a/ui/src/app/index/login.component.ts +++ b/ui/src/app/index/login.component.ts @@ -8,6 +8,7 @@ import { environment } from "src/environments"; import { Capacitor } from "@capacitor/core"; import { AppService } from "../app.service"; import { AuthenticateWithPasswordRequest } from "../shared/jsonrpc/request/authenticateWithPasswordRequest"; +import { States } from "../shared/ngrx-store/states"; import { Edge, Service, Utils, Websocket } from "../shared/shared"; @Component({ @@ -93,6 +94,7 @@ export class LoginComponent implements OnInit, AfterContentChecked, OnDestroy { */ public doLogin(param: { username?: string, password: string }) { + this.websocket.state.set(States.AUTHENTICATION_WITH_CREDENTIALS); param = LoginComponent.trimCredentials(param.password, param.username); // Prevent that user submits via keyevent 'enter' multiple times diff --git a/ui/src/app/index/shared/loading-screen.html b/ui/src/app/index/shared/loading-screen.html index 2001205da68..481d1773885 100644 --- a/ui/src/app/index/shared/loading-screen.html +++ b/ui/src/app/index/shared/loading-screen.html @@ -1,5 +1,63 @@ - -

      Loading...

      -
      + + + +

      + LOADING_SCREEN.LOADING + + ... +

      +
      + + + +
      + + + + + + + + + + + +
      + +
      +
      + + + + + + + LOADING_SCREEN.SERVER_NOT_ACCESSIBLE + + + + + + + + LOADING_SCREEN.SERVER_NOT_ACCESSIBLE_DESCRIPTION + + + + + + + + + + LOADING_SCREEN.SERVER_NOT_ACCESSIBLE_TRY_RELOADING + + + + + + diff --git a/ui/src/app/index/shared/loading-screen.ts b/ui/src/app/index/shared/loading-screen.ts index 14d5d7b43a5..05322949c51 100644 --- a/ui/src/app/index/shared/loading-screen.ts +++ b/ui/src/app/index/shared/loading-screen.ts @@ -1,38 +1,41 @@ // @ts-strict-ignore -import { Component, OnInit } from "@angular/core"; +import { Component, effect } from "@angular/core"; import { Router } from "@angular/router"; +import { AppStateTracker } from "src/app/shared/ngrx-store/states"; +import { Environment, environment } from "src/environments"; import { Service, Websocket } from "../../shared/shared"; @Component({ selector: "index", templateUrl: "./loading-screen.html", }) -export class LoadingScreenComponent implements OnInit { +export class LoadingScreenComponent { protected readonly spinnerId: string = "IndexComponent"; + protected readonly environment: Environment = environment; + protected backendState: "loading" | "failed" | "authenticated" = "loading"; constructor( public service: Service, public websocket: Websocket, private router: Router, - ) { } + private appStateTracker: AppStateTracker, + ) { - ngOnInit() { - - // TODO add websocket status observable - const interval = setInterval(() => { - this.service.startSpinner(this.spinnerId); - if (this.websocket.status === "online") { - this.service.stopSpinner(this.spinnerId); - this.router.navigate(["/overview"]); - clearInterval(interval); - } - if (this.websocket.status === "waiting for credentials") { - this.service.stopSpinner(this.spinnerId); - this.router.navigate(["/login"]); - clearInterval(interval); + effect(() => { + this.backendState = this.appStateTracker.loadingState(); + switch (this.backendState) { + case "loading": + this.service.startSpinner(this.spinnerId); + break; + case "failed": + this.service.stopSpinner(this.spinnerId); + break; + case "authenticated": + this.appStateTracker.navigateAfterAuthentication(); + break; } - }, 1000); + }); } } diff --git a/ui/src/app/shared/components/chart/abstracthistorychart.html b/ui/src/app/shared/components/chart/abstracthistorychart.html index 0c1225b56f0..a727e42f4dc 100644 --- a/ui/src/app/shared/components/chart/abstracthistorychart.html +++ b/ui/src/app/shared/components/chart/abstracthistorychart.html @@ -11,3 +11,5 @@ [type]="chartType">
    35. + + diff --git a/ui/src/app/shared/components/chart/abstracthistorychart.ts b/ui/src/app/shared/components/chart/abstracthistorychart.ts index 97d491dc2f4..b30e69af4b8 100644 --- a/ui/src/app/shared/components/chart/abstracthistorychart.ts +++ b/ui/src/app/shared/components/chart/abstracthistorychart.ts @@ -5,7 +5,7 @@ import { ActivatedRoute } from "@angular/router"; import { TranslateService } from "@ngx-translate/core"; import * as Chart from "chart.js"; import annotationPlugin from "chartjs-plugin-annotation"; -import { calculateResolution, ChronoUnit, DEFAULT_NUMBER_CHART_OPTIONS, DEFAULT_TIME_CHART_OPTIONS, isLabelVisible, Resolution, setLabelVisible } from "src/app/edge/history/shared"; +import { ChronoUnit, DEFAULT_NUMBER_CHART_OPTIONS, DEFAULT_TIME_CHART_OPTIONS, Resolution, calculateResolution, isLabelVisible, setLabelVisible } from "src/app/edge/history/shared"; import { QueryHistoricTimeseriesEnergyPerPeriodResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyPerPeriodResponse"; import { DefaultTypes } from "src/app/shared/service/defaulttypes"; import { v4 as uuidv4 } from "uuid"; @@ -311,6 +311,8 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { return translate.instant("Edge.Index.Widgets.Channeltreshold.ACTIVE_TIME_OVER_PERIOD"); case YAxisType.PERCENTAGE: return translate.instant("General.percentage"); + case YAxisType.REACTIVE: + return "var"; case YAxisType.ENERGY: if (chartType == "bar") { return "kWh"; @@ -556,6 +558,7 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { break; case YAxisType.POWER: case YAxisType.ENERGY: + case YAxisType.REACTIVE: case YAxisType.VOLTAGE: case YAxisType.CURRENT: case YAxisType.NONE: @@ -645,6 +648,9 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { tooltipsLabel = "kW"; } break; + case YAxisType.REACTIVE: + tooltipsLabel = "var"; + break; default: tooltipsLabel = ""; break; @@ -724,6 +730,8 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { return "V"; case YAxisType.CURRENT: return "A"; + case YAxisType.REACTIVE: + return "var"; case YAxisType.ENERGY: if (chartType == "bar") { return "kWh"; diff --git a/ui/src/app/shared/components/edge/edgeconfig.spec.ts b/ui/src/app/shared/components/edge/edgeconfig.spec.ts index 8921e4235d6..ec7d23d4a2c 100644 --- a/ui/src/app/shared/components/edge/edgeconfig.spec.ts +++ b/ui/src/app/shared/components/edge/edgeconfig.spec.ts @@ -172,6 +172,18 @@ export namespace DummyConfig { "io.openems.edge.evcs.api.Evcs", ], }; + + export const MODBUS_TCP_READWRITE = { + id: "Controller.Api.ModbusTcp.ReadWrite", + natureIds: [ + "io.openems.edge.common.jsonapi.JsonApi", + "io.openems.edge.common.component.OpenemsComponent", + "io.openems.edge.controller.api.modbus.ModbusTcpApi", + "io.openems.edge.controller.api.modbus.readwrite.ControllerApiModbusTcpReadWrite", + "io.openems.edge.controller.api.Controller", + "io.openems.edge.timedata.api.TimedataProvider", + ], + }; } export namespace Component { @@ -295,6 +307,21 @@ export namespace DummyConfig { }, channels: {}, }); + + export const MODBUS_TCP_READWRITE = (id: string, alias?: string): Component => ({ + id: id, + alias: alias ?? id, + factory: Factory.MODBUS_TCP_READWRITE, + properties: { + invert: false, + modbusUnitId: 5, + type: "PRODUCTION", + writeChannels: [ + "Ess0SetActivePowerEquals", + ], + }, + channels: {}, + }); } } diff --git a/ui/src/app/shared/components/header/header.component.ts b/ui/src/app/shared/components/header/header.component.ts index 0c192f21047..fc97026c4e6 100644 --- a/ui/src/app/shared/components/header/header.component.ts +++ b/ui/src/app/shared/components/header/header.component.ts @@ -63,7 +63,7 @@ export class HeaderComponent implements OnInit, OnDestroy, AfterViewChecked { const urlArray = url.split("/"); const file = urlArray.pop(); - if (file == "user" || file == "settings" || file == "changelog" || file == "login" || urlArray.length > 3) { + if (file == "user" || file == "settings" || file == "changelog" || file == "login" || file == "index" || urlArray.length > 3) { // disable side-menu; show back-button instead this.enableSideMenu = false; } else { @@ -75,7 +75,7 @@ export class HeaderComponent implements OnInit, OnDestroy, AfterViewChecked { updateBackUrl(url: string) { // disable backUrl & Segment Navigation on initial 'login' page - if (url === "/login" || url === "/overview") { + if (url === "/login" || url === "/overview" || url === "/index") { this.backUrl = false; return; } diff --git a/ui/src/app/shared/components/modal/modal.module.ts b/ui/src/app/shared/components/modal/modal.module.ts index 57ecf5e89e0..9f6c54a7b5a 100644 --- a/ui/src/app/shared/components/modal/modal.module.ts +++ b/ui/src/app/shared/components/modal/modal.module.ts @@ -26,6 +26,7 @@ import { ModalHorizontalLineComponent } from "./model-horizontal-line/modal-hori PipeModule, ], declarations: [ + HelpButtonComponent, ModalButtonsComponent, ModalInfoLineComponent, ModalLineComponent, @@ -37,6 +38,7 @@ import { ModalHorizontalLineComponent } from "./model-horizontal-line/modal-hori HelpButtonComponent, ], exports: [ + HelpButtonComponent, ModalButtonsComponent, ModalInfoLineComponent, ModalLineComponent, diff --git a/ui/src/app/shared/components/shared/converter.ts b/ui/src/app/shared/components/shared/converter.ts index 136ecff555b..b76ad1ace3f 100644 --- a/ui/src/app/shared/components/shared/converter.ts +++ b/ui/src/app/shared/components/shared/converter.ts @@ -93,6 +93,34 @@ export namespace Converter { Formatter.FORMAT_WATT(value)); }; + /** + * Formats a Energy value as Kilo watt hours [kWh]. + * + * Value 1000 -> "1,00 kWh". + * Value null -> "-". + * + * @param value the power value + * @returns formatted value; '-' for null + */ + export const WATT_HOURS_IN_KILO_WATT_HOURS: Converter = (raw) => { + return IF_NUMBER(raw, value => + Formatter.FORMAT_KILO_WATT_HOURS(value / 1000)); + }; + + /** + * Formats a Energy value as Kilo watt hours [kWh]. + * + * Value 1000 -> "1000 kWh". + * Value null -> "-". + * + * @param value the power value + * @returns formatted value; '-' for null + */ + export const TO_KILO_WATT_HOURS: Converter = (raw) => { + return IF_NUMBER(raw, value => + Formatter.FORMAT_KILO_WATT_HOURS(value)); + }; + export const STATE_IN_PERCENT: Converter = (raw) => { return IF_NUMBER(raw, value => Formatter.FORMAT_PERCENT(value)); diff --git a/ui/src/app/shared/components/shared/formatter.ts b/ui/src/app/shared/components/shared/formatter.ts index 8f2d5df2c8d..798818e17b6 100644 --- a/ui/src/app/shared/components/shared/formatter.ts +++ b/ui/src/app/shared/components/shared/formatter.ts @@ -7,6 +7,11 @@ export namespace Formatter { return formatNumber(value, "de", "1.0-0") + " W"; }; + export const FORMAT_KILO_WATT_HOURS = (value: number) => { + // TODO apply correct locale + return formatNumber(value, "de", "1.0-0") + " kWh"; + }; + export const FORMAT_VOLT = (value: number) => { // TODO apply correct locale return formatNumber(value, "de", "1.0-0") + " V"; diff --git a/ui/src/app/shared/ngrx-store/states.ts b/ui/src/app/shared/ngrx-store/states.ts new file mode 100644 index 00000000000..33d8f0aeb0d --- /dev/null +++ b/ui/src/app/shared/ngrx-store/states.ts @@ -0,0 +1,110 @@ +import { Injectable, WritableSignal, effect, signal } from "@angular/core"; +import { Router } from "@angular/router"; + +import { differenceInSeconds } from "date-fns"; +import { environment } from "src/environments"; +import { Pagination } from "../service/pagination"; +import { PreviousRouteService } from "../service/previousRouteService"; +import { Websocket } from "../shared"; + +export enum States { + WEBSOCKET_CONNECTION_CLOSED, + WEBSOCKET_NOT_YET_CONNECTED, + WEBSOCKET_CONNECTING, + WEBSOCKET_CONNECTED, + + // TODO substates + NOT_AUTHENTICATED, + AUTHENTICATING_WITH_TOKEN, + AUTHENTICATION_WITH_CREDENTIALS, + AUTHENTICATED, + EDGE_SELECTED, +} + +@Injectable({ + providedIn: "root", +}) +export class AppStateTracker { + private static readonly LOG_PREFIX: string = "AppState"; + private static readonly TIME_TILL_TIMEOUT: number = 10; + private static readonly ENABLE_ROUTING: boolean = true; + public loadingState: WritableSignal<"failed" | "loading" | "authenticated"> = signal("loading"); + private lastTimeStamp: Date | null = null; + + constructor( + protected router: Router, + protected pagination: Pagination, + private websocket: Websocket, + private previousRouteService: PreviousRouteService, + ) { + if (!localStorage.getItem("AppState")) { + console.log(`${AppStateTracker.LOG_PREFIX} Log deactivated`); + } + + if (!AppStateTracker.ENABLE_ROUTING) { + console.log(`${AppStateTracker.LOG_PREFIX} Routing deactivated`); + } + + effect(() => { + const state = this.websocket.state(); + this.startStateHandler(state); + }, { allowSignalWrites: true }); + } + + /** + * Handles navigation after authentication + */ + public navigateAfterAuthentication() { + const segments = this.router.routerState.snapshot.url.split("/"); + const previousUrl: string = this.previousRouteService.getPreviousUrl(); + + if ((previousUrl === segments[segments.length - 1]) || previousUrl === "/") { + this.router.navigate(["./overview"]); + return; + } + + this.router.navigate(previousUrl.split("/")); + } + + private startStateHandler(state: States): void { + + if (environment.debugMode && localStorage.getItem("AppState")) { + console.log(`${AppStateTracker.LOG_PREFIX} [${States[this.websocket.state()]}]`); + } + + if (!AppStateTracker.ENABLE_ROUTING) { + return; + } + + switch (state) { + case States.WEBSOCKET_CONNECTING: + this.lastTimeStamp = this.handleWebSocketConnecting(this.lastTimeStamp); + break; + case States.WEBSOCKET_CONNECTION_CLOSED: + break; + case States.AUTHENTICATED: + this.loadingState.set("authenticated"); + break; + default: + this.lastTimeStamp = null; + break; + } + } + + + private handleWebSocketConnecting(lastTimeStamp: Date | null): Date | null { + const now = new Date(); + if (lastTimeStamp === null) { + return now; + } + + if (differenceInSeconds(now, lastTimeStamp) > AppStateTracker.TIME_TILL_TIMEOUT) { + console.warn(`Websocket connection couldnt be established in ${AppStateTracker.TIME_TILL_TIMEOUT}s`); + this.loadingState.set("failed"); + this.router.navigate(["index"]); + return null; + } + + return lastTimeStamp; + } +} diff --git a/ui/src/app/shared/pipe/converter/converter.ts b/ui/src/app/shared/pipe/converter/converter.ts new file mode 100644 index 00000000000..34cc2fc6649 --- /dev/null +++ b/ui/src/app/shared/pipe/converter/converter.ts @@ -0,0 +1,22 @@ +import { Pipe, PipeTransform } from "@angular/core"; + +import { Converter } from "../../components/shared/converter"; + +@Pipe({ + name: "converter", +}) +export class ConverterPipe implements PipeTransform { + + constructor() { } + + /** + * Transforms the value with a given converter + * + * @param value the passed value + * @param converter the passed converter + * @returns the result of the converter as a string + */ + transform(value: number, converter: Converter): string { + return converter(value); + } +} diff --git a/ui/src/app/shared/pipe/pipe.ts b/ui/src/app/shared/pipe/pipe.ts index ff8f05002e8..dba4d592001 100644 --- a/ui/src/app/shared/pipe/pipe.ts +++ b/ui/src/app/shared/pipe/pipe.ts @@ -2,6 +2,7 @@ import { DecimalPipe } from "@angular/common"; import { NgModule } from "@angular/core"; import { BrowserModule } from "@angular/platform-browser"; import { ClassnamePipe } from "./classname/classname.pipe"; +import { ConverterPipe } from "./converter/converter"; import { FormatSecondsToDurationPipe } from "./formatSecondsToDuration/formatSecondsToDuration.pipe"; import { IsclassPipe } from "./isclass/isclass.pipe"; import { KeysPipe } from "./keys/keys.pipe"; @@ -23,6 +24,7 @@ import { VersionPipe } from "./version/version.pipe"; ClassnamePipe, VersionPipe, TypeofPipe, + ConverterPipe, ], exports: [ UnitvaluePipe, @@ -33,6 +35,7 @@ import { VersionPipe } from "./version/version.pipe"; ClassnamePipe, VersionPipe, TypeofPipe, + ConverterPipe, ], providers: [ DecimalPipe, diff --git a/ui/src/app/shared/service/pagination.ts b/ui/src/app/shared/service/pagination.ts index ed549837116..f75a43c2f71 100644 --- a/ui/src/app/shared/service/pagination.ts +++ b/ui/src/app/shared/service/pagination.ts @@ -4,6 +4,7 @@ import { Router } from "@angular/router"; import { SubscribeEdgesRequest } from "../jsonrpc/request/subscribeEdgesRequest"; import { ChannelAddress, Edge } from "../shared"; import { Service } from "./service"; +import { States } from "../ngrx-store/states"; @Directive() export class Pagination { @@ -22,6 +23,7 @@ export class Pagination { this.edge = edge; this.service.websocket.sendRequest(new SubscribeEdgesRequest({ edges: [edge.id] })); }).then(() => { + this.service.websocket.state.set(States.EDGE_SELECTED); this.edge.subscribeChannels(this.service.websocket, "", [ new ChannelAddress("_sum", "State"), ]); diff --git a/ui/src/app/shared/service/previousRouteService.ts b/ui/src/app/shared/service/previousRouteService.ts new file mode 100644 index 00000000000..f6087a0ea2c --- /dev/null +++ b/ui/src/app/shared/service/previousRouteService.ts @@ -0,0 +1,29 @@ +import { Injectable } from "@angular/core"; +import { NavigationEnd, Router } from "@angular/router"; + +@Injectable() +export class PreviousRouteService { + + private previousUrl: string; + private currentUrl: string; + + constructor(private router: Router) { + this.currentUrl = this.router.url; + this.previousUrl = this.currentUrl; + router.events.subscribe(event => { + if (event instanceof NavigationEnd) { + this.previousUrl = this.currentUrl; + this.currentUrl = event.url; + } + }); + } + + /** + * Gets the previous url, active before this url + * + * @returns the previous url + */ + public getPreviousUrl() { + return this.previousUrl; + } +} diff --git a/ui/src/app/shared/service/service.ts b/ui/src/app/shared/service/service.ts index 67ce8b1a64f..e25fa22fac3 100644 --- a/ui/src/app/shared/service/service.ts +++ b/ui/src/app/shared/service/service.ts @@ -20,6 +20,7 @@ import { GetEdgeResponse } from "../jsonrpc/response/getEdgeResponse"; import { GetEdgesResponse } from "../jsonrpc/response/getEdgesResponse"; import { QueryHistoricTimeseriesEnergyResponse } from "../jsonrpc/response/queryHistoricTimeseriesEnergyResponse"; import { User } from "../jsonrpc/shared"; +import { States } from "../ngrx-store/states"; import { ChannelAddress } from "../shared"; import { Language } from "../type/language"; import { Role } from "../type/role"; @@ -198,6 +199,7 @@ export class Service extends AbstractService { public onLogout() { this.currentEdge.next(null); this.metadata.next(null); + this.websocket.state.set(States.NOT_AUTHENTICATED); this.router.navigate(["/login"]); } diff --git a/ui/src/app/shared/service/utils.ts b/ui/src/app/shared/service/utils.ts index 36f44a37d47..9e237060345 100644 --- a/ui/src/app/shared/service/utils.ts +++ b/ui/src/app/shared/service/utils.ts @@ -632,6 +632,7 @@ export enum YAxisType { RELAY, ENERGY, VOLTAGE, + REACTIVE, CURRENT, TIME, CURRENCY, diff --git a/ui/src/app/shared/service/websocket.ts b/ui/src/app/shared/service/websocket.ts index a79deefeb77..6df2b0d368b 100644 --- a/ui/src/app/shared/service/websocket.ts +++ b/ui/src/app/shared/service/websocket.ts @@ -1,5 +1,5 @@ // @ts-strict-ignore -import { Injectable } from "@angular/core"; +import { Injectable, WritableSignal, signal } from "@angular/core"; import { Router } from "@angular/router"; import { TranslateService } from "@ngx-translate/core"; import { CookieService } from "ngx-cookie-service"; @@ -18,6 +18,7 @@ import { EdgeRpcRequest } from "../jsonrpc/request/edgeRpcRequest"; import { LogoutRequest } from "../jsonrpc/request/logoutRequest"; import { RegisterUserRequest } from "../jsonrpc/request/registerUserRequest"; import { AuthenticateResponse } from "../jsonrpc/response/authenticateResponse"; +import { States } from "../ngrx-store/states"; import { Language } from "../type/language"; import { Pagination } from "./pagination"; import { Service } from "./service"; @@ -40,6 +41,8 @@ export class Websocket implements WebsocketInterface { | "failed" // connection failed = "initial"; + public state: WritableSignal = signal(States.WEBSOCKET_NOT_YET_CONNECTED); + private readonly wsdata = new WsData(); private socket: WebSocketSubject; @@ -68,6 +71,7 @@ export class Websocket implements WebsocketInterface { public login(request: AuthenticateWithPasswordRequest | AuthenticateWithTokenRequest): Promise { return new Promise((resolve) => { this.sendRequest(request).then(r => { + this.state.set(States.AUTHENTICATED); const authenticateResponse = (r as AuthenticateResponse).result; const language = Language.getByKey(localStorage.DEMO_LANGUAGE ?? authenticateResponse.user.language.toLocaleLowerCase()); @@ -202,10 +206,12 @@ export class Websocket implements WebsocketInterface { * Opens a connection using a stored token. Called once by constructor */ private connect() { + this.state.set(States.WEBSOCKET_NOT_YET_CONNECTED); if (this.status != "initial") { return; } // trying to connect + this.state.set(States.WEBSOCKET_CONNECTING); this.status = "connecting"; if (environment.debugMode) { @@ -219,6 +225,7 @@ export class Websocket implements WebsocketInterface { url: environment.url, openObserver: { next: (value) => { + this.state.set(States.WEBSOCKET_NOT_YET_CONNECTED); // Websocket connection is open if (environment.debugMode) { console.info("Websocket connection opened"); @@ -226,6 +233,7 @@ export class Websocket implements WebsocketInterface { const token = this.cookieService.get("token"); if (token) { + this.state.set(States.AUTHENTICATING_WITH_TOKEN); // Login with Session Token this.login(new AuthenticateWithTokenRequest({ token: token })); @@ -233,6 +241,7 @@ export class Websocket implements WebsocketInterface { } else { // No Token -> directly ask for Login credentials + this.state.set(States.NOT_AUTHENTICATED); this.status = "waiting for credentials"; this.router.navigate(["login"]); } @@ -241,10 +250,12 @@ export class Websocket implements WebsocketInterface { closeObserver: { next: (value) => { // Websocket connection is closed. Auto-Reconnect starts. + this.state.set(States.WEBSOCKET_CONNECTION_CLOSED); if (environment.debugMode) { console.info("Websocket connection closed"); } // trying to connect + this.state.set(States.WEBSOCKET_CONNECTING); this.status = "connecting"; }, }, diff --git a/ui/src/app/shared/shared.module.ts b/ui/src/app/shared/shared.module.ts index 1bf1507d696..2ff830daf99 100644 --- a/ui/src/app/shared/shared.module.ts +++ b/ui/src/app/shared/shared.module.ts @@ -31,8 +31,10 @@ import { HistoryDataErrorModule } from "./components/history-data-error/history- import { PercentageBarComponent } from "./components/percentagebar/percentagebar.component"; import { DirectiveModule } from "./directive/directive"; import { ChartOptionsComponent } from "./legacy/chartoptions/chartoptions.component"; +import { AppStateTracker } from "./ngrx-store/states"; import { PipeModule } from "./pipe/pipe"; import { Logger } from "./service/logger"; +import { PreviousRouteService } from "./service/previousRouteService"; import { Service } from "./service/service"; import { Utils } from "./service/utils"; import { Websocket } from "./shared"; @@ -143,11 +145,13 @@ export function SubnetmaskValidatorMessage(err, field: FormlyFieldConfig) { FormlyFieldWithLoadingAnimationComponent, ], providers: [ + AppStateTracker, appRoutingProviders, + Logger, + PreviousRouteService, Service, Utils, Websocket, - Logger, ], }) diff --git a/ui/src/app/shared/shared.ts b/ui/src/app/shared/shared.ts index 4175e96134d..6cf1168edc6 100644 --- a/ui/src/app/shared/shared.ts +++ b/ui/src/app/shared/shared.ts @@ -58,6 +58,10 @@ export class EdgePermission { }, []); } + public static isModbusTcpApiWidgetAllowed(edge: Edge): boolean { + return edge?.isVersionAtLeast("2024.9.1"); + } + /** * Determines if the edge has its channels in the edgeconfig * or if they should be obtained with a separate request. @@ -169,6 +173,15 @@ export enum EssStateMachine { ERROR = 30, } +export enum ChannelRegister { + "SetActivePowerEquals" = 706, + "SetReactivePowerEquals" = 708, + "SetActivePowerLessOrEquals" = 710, + "SetReactivePowerLessOrEquals" = 712, + "SetActivePowerGreaterOrEquals" = 714, + "SetReactivePowerGreaterOrEquals" = 716, +} + /** * Presents a simple */ diff --git a/ui/src/app/shared/type/general.ts b/ui/src/app/shared/type/general.ts index 8394178bfce..8d1d82a528c 100644 --- a/ui/src/app/shared/type/general.ts +++ b/ui/src/app/shared/type/general.ts @@ -17,3 +17,8 @@ export enum WorkMode { TIME = "TIME", NONE = "NONE", } +export enum OverrideStatus { + ACTIVE = 0, + INACTIVE = 1, + ERROR = 2, +} diff --git a/ui/src/app/shared/type/language.ts b/ui/src/app/shared/type/language.ts index b76c3dd2d8b..4858ceca062 100644 --- a/ui/src/app/shared/type/language.ts +++ b/ui/src/app/shared/type/language.ts @@ -4,8 +4,9 @@ import localES from "@angular/common/locales/es"; import localFR from "@angular/common/locales/fr"; import localJA from "@angular/common/locales/ja"; import localNL from "@angular/common/locales/nl"; -import { TranslateLoader } from "@ngx-translate/core"; +import { TranslateLoader, TranslateService } from "@ngx-translate/core"; import { Observable, of } from "rxjs"; +import { filter, take } from "rxjs/operators"; import cz from "src/assets/i18n/cz.json"; import de from "src/assets/i18n/de.json"; import en from "src/assets/i18n/en.json"; @@ -117,15 +118,16 @@ export class Language { * @param translationFile the translation file * @returns translations params */ - public static setAdditionalTranslationFile(translationFile: any): { lang: string, translations: {}, shouldMerge?: boolean } { - let key = localStorage.LANGUAGE ?? Language.DEFAULT.key; - if (!(key in translationFile)) { + public static async setAdditionalTranslationFile(translationFile: any, translate: TranslateService): Promise<{ lang: string; translations: {}; shouldMerge?: boolean; }> { + const lang = (await translate.onLangChange.pipe(filter(lang => !!lang), take(1)).toPromise()).lang; + let translationKey: string = lang; + if (!(lang in translationFile)) { if (environment.debugMode) { - console.warn(`[Advert] No translation available for Language ${key}. Implemented languages are: ${Object.keys(translationFile)}`); + console.warn(`[Advert] No translation available for Language ${lang}. Implemented languages are: ${Object.keys(translationFile)}`); } - key = Language.DEFAULT.key; + translationKey = Language.EN.key; } - return { lang: key, translations: translationFile[key], shouldMerge: true }; + return { lang: lang, translations: translationFile[translationKey], shouldMerge: true }; } } diff --git a/ui/src/app/shared/type/widget.ts b/ui/src/app/shared/type/widget.ts index bd838e1641b..5f72e25e0ce 100644 --- a/ui/src/app/shared/type/widget.ts +++ b/ui/src/app/shared/type/widget.ts @@ -1,6 +1,7 @@ // @ts-strict-ignore import { Edge } from "../components/edge/edge"; import { EdgeConfig } from "../components/edge/edgeconfig"; +import { EdgePermission } from "../shared"; export enum WidgetClass { "Energymonitor", @@ -21,6 +22,7 @@ export enum WidgetNature { } export enum WidgetFactory { + "Controller.Api.ModbusTcp.ReadWrite", "Controller.Asymmetric.PeakShaving", "Controller.ChannelThreshold", "Controller.CHP.SoC", @@ -104,6 +106,8 @@ export class Widgets { return config.getComponentIdsByFactory("Controller.ChannelThreshold")?.length > 0; case "Controller_Io_Digital_Outputs": return config.getComponentIdsByFactories("Controller.Io.FixDigitalOutput", "Controller.IO.ChannelSingleThreshold")?.length > 0; + case "Controller.Api.ModbusTcp.ReadWrite": + return EdgePermission.isModbusTcpApiWidgetAllowed(edge); default: return false; } diff --git a/ui/src/assets/i18n/de.json b/ui/src/assets/i18n/de.json index 5e45735b3cf..457f5cb15ab 100644 --- a/ui/src/assets/i18n/de.json +++ b/ui/src/assets/i18n/de.json @@ -858,6 +858,13 @@ }, "CONFIGURATION_MPPT_SELECTION_NOTE": "Weitere Erzeuger können im Anschluss über das App Center konfiguriert werden." }, + "LOADING_SCREEN": { + "LOADING": "Wird geladen", + "SERVER_NOT_ACCESSIBLE": "Server nicht erreichbar", + "SERVER_NOT_ACCESSIBLE_TRY_RELOADING": "Probieren Sie bitte in 10 Minuten den Browser neu zu laden.", + "SERVER_NOT_ACCESSIBLE_ACCESS_LOCALLY": "Lokal zugreifen", + "SERVER_NOT_ACCESSIBLE_DESCRIPTION": "Der Onlinezugriff auf das Speichersystem ist aktuell nicht möglich. Die Daten werden lokal gespeichert und gehen nicht verloren." + }, "Login": { "title": "Login", "preamble": "Bitte geben Sie Ihr Passwort ein oder bestätigen Sie die Voreingabe um sich als Gast anzumelden.", @@ -972,6 +979,24 @@ "MORE_CHANNELS": "Weitere Kanäle hinzufügen", "CHANNEL": "Kanal" }, + "MODBUS_TCP_API_READ_WRITE": { + "CURRENT_STATE": "Aktueller Status", + "CUMULATED_ACTIVE_TIME": "Externe Vorgaben berücksichtigt", + "CUMULATED_INACTIVE_TIME": "Keine externe Vorgabe vorhanden", + "NO_OVERRIDDEN_CHANNELS": "Es wurden noch keine Kanäle überschrieben.", + "NOT_OVERRIDING": "Keine externe Vorgabe vorhanden", + "OVERRIDING": "Externe Vorgabe wird berücksichtigt", + "LAST_COMMAND": "Letzter Schreibbefehl", + "ACTIVE_POWER_LIMITATIONS": "Wirkleistungsvorgabe", + "REGISTER": "Register", + "LIMITATION": "Vorgabe", + "ACTUAL_VALUE": "Tatsächlicher Wert", + "INFO_TEXT": "Tatsächlicher Wert kann von der Vorgabe abweichen. Negative Werte entsprechen Speicherbeladung - postive Speicherentladung. Eine detaillierte Erklärung finden Sie in der Anleitung.", + "SET_ACTIVE_POWER_EQUALS": "Vorgabe Be- bzw. Entladeleistung", + "SET_ACTIVE_POWER_GREATER_OR_EQUALS": "Minimale Beladeleistung", + "SET_ACTIVE_POWER_LESS_OR_EQUALS": "Maximale Beladeleistung", + "DOWNLOAD_PROTOCOL": "Protokoll Herunterladen" + }, "GRID_STATES": { "OFF_GRID": "Netzausfall", "NO_EXTERNAL_LIMITATION": "keine externe Limitierung", diff --git a/ui/src/assets/i18n/en.json b/ui/src/assets/i18n/en.json index 3c555925b24..b3f33f87876 100644 --- a/ui/src/assets/i18n/en.json +++ b/ui/src/assets/i18n/en.json @@ -860,6 +860,13 @@ }, "CONFIGURATION_MPPT_SELECTION_NOTE": "Additional generators can then be configured via the App Center." }, + "LOADING_SCREEN": { + "LOADING": "Loading", + "SERVER_NOT_ACCESSIBLE": "Server not accessible", + "SERVER_NOT_ACCESSIBLE_DESCRIPTION": "Online view of the storage system is currently not possible. The data is saved locally and will not be lost.", + "SERVER_NOT_ACCESSIBLE_TRY_RELOADING": "Please try reloading the browser in 10 minutes.", + "SERVER_NOT_ACCESSIBLE_ACCESS_LOCALLY": "Access locally" + }, "Login": { "title": "Login", "preamble": "Please enter your password or submit the default value to login as a guest.", @@ -975,6 +982,24 @@ "MORE_CHANNELS": "Add More Channels", "CHANNEL": "Channel" }, + "MODBUS_TCP_API_READ_WRITE": { + "CURRENT_STATE": "Current state", + "CUMULATED_ACTIVE_TIME": "External commands considered", + "CUMULATED_INACTIVE_TIME": "No external commands present", + "NO_OVERRIDDEN_CHANNELS": "No channels have been overridden yet.", + "NOT_OVERRIDING": "No external commands present", + "OVERRIDING": "External command is being considered", + "LAST_COMMAND": "Last override", + "ACTIVE_POWER_LIMITATIONS": "Active power limitations", + "REGISTER": "Register", + "LIMITATION": "Limitation", + "ACTUAL_VALUE": "Actual value", + "INFO_TEXT": "Actual value may deviate from the specification. Negative values correspond to storage loading - positive storage discharging. A detailed explanation can be found in the instructions.", + "SET_ACTIVE_POWER_EQUALS": "Limitation charing/discharging power", + "SET_ACTIVE_POWER_GREATER_OR_EQUALS": "Minimum charging power", + "SET_ACTIVE_POWER_LESS_OR_EQUALS": "Maximum charging power", + "DOWNLOAD_PROTOCOL": "Download Protocol" + }, "GRID_STATES": { "OFF_GRID": "Power outage", "NO_EXTERNAL_LIMITATION": "No external limitation", diff --git a/ui/src/themes/openems/scss/variables.scss b/ui/src/themes/openems/scss/variables.scss index 936fd07be47..abf1541b28c 100644 --- a/ui/src/themes/openems/scss/variables.scss +++ b/ui/src/themes/openems/scss/variables.scss @@ -15,6 +15,7 @@ $font-family: var(--ion-font-family); --ion-color-primary-contrast: #000000; --ion-color-primary-contrast-rgb: 0, 0, 0; --ion-color-primary-shade: #cc995d; + --ion-color-primary-shade-rgb: rgb(204, 153, 93); --ion-color-primary-tint: #eab679; /** secondary **/ @@ -106,9 +107,13 @@ $font-family: var(--ion-font-family); } --ion-color-production: #36aed1; - --ion-color-production-rgb: 54, 174, 209; + --ion-color-production-rgb: 54, + 174, + 209; --ion-color-production-contrast: #fff; - --ion-color-production-contrast-rgb: 255, 255, 255; + --ion-color-production-contrast-rgb: 255, + 255, + 255; --ion-color-production-shade: #226e84; --ion-color-production-tint: #41d4ff; From b5f385b704dc345bb53d4583127668accd633d26 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Tue, 10 Sep 2024 14:23:39 +0200 Subject: [PATCH 133/173] Update Gradle to 8.10.1 See https://github.com/gradle/gradle/releases/tag/v8.10.1 --- .gradle-wrapper/gradle-wrapper.jar | Bin 43504 -> 43583 bytes .gradle-wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/.gradle-wrapper/gradle-wrapper.jar b/.gradle-wrapper/gradle-wrapper.jar index 2c3521197d7c4586c843d1d3e9090525f1898cde..a4b76b9530d66f5e68d973ea569d8e19de379189 100644 GIT binary patch delta 3990 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 diff --git a/.gradle-wrapper/gradle-wrapper.properties b/.gradle-wrapper/gradle-wrapper.properties index 9355b415575..0aaefbcaf0f 100644 --- a/.gradle-wrapper/gradle-wrapper.properties +++ b/.gradle-wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From b162f2c31e4f0c85fe9f7cbf16227daecd6cdc92 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Sep 2024 11:09:51 +0200 Subject: [PATCH 134/173] Build(deps): Bump org.apache.felix:org.apache.felix.http.jetty from 5.1.24 to 5.1.26 in /cnf (#2798) * Build(deps): Bump org.apache.felix:org.apache.felix.http.jetty in /cnf Bumps org.apache.felix:org.apache.felix.http.jetty from 5.1.24 to 5.1.26. --- updated-dependencies: - dependency-name: org.apache.felix:org.apache.felix.http.jetty 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 56115404f1b..3ae7771b07e 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -203,7 +203,7 @@ org.apache.felix org.apache.felix.http.jetty - 5.1.24 + 5.1.26 diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index 8edfd8287e6..6d374f9dfb8 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -108,7 +108,7 @@ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ org.apache.felix.eventadmin;version='[1.6.4,1.6.5)',\ org.apache.felix.fileinstall;version='[3.7.4,3.7.5)',\ - org.apache.felix.http.jetty;version='[5.1.24,5.1.25)',\ + org.apache.felix.http.jetty;version='[5.1.26,5.1.27)',\ org.apache.felix.http.servlet-api;version='[3.0.0,3.0.1)',\ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index 1e489ec3546..a6ac193b88b 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -404,7 +404,7 @@ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ org.apache.felix.eventadmin;version='[1.6.4,1.6.5)',\ org.apache.felix.fileinstall;version='[3.7.4,3.7.5)',\ - org.apache.felix.http.jetty;version='[5.1.24,5.1.25)',\ + org.apache.felix.http.jetty;version='[5.1.26,5.1.27)',\ org.apache.felix.http.servlet-api;version='[3.0.0,3.0.1)',\ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ From c1f5106c81ec7c33a06e24252c7ee5e4496ba197 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Sep 2024 11:13:31 +0200 Subject: [PATCH 135/173] Build(deps): Bump net.java.dev.jna:jna from 5.14.0 to 5.15.0 in /cnf (#2799) * Build(deps): Bump net.java.dev.jna:jna from 5.14.0 to 5.15.0 in /cnf Bumps [net.java.dev.jna:jna](https://github.com/java-native-access/jna) from 5.14.0 to 5.15.0. - [Changelog](https://github.com/java-native-access/jna/blob/master/CHANGES.md) - [Commits](https://github.com/java-native-access/jna/compare/5.14.0...5.15.0) --- updated-dependencies: - dependency-name: net.java.dev.jna:jna 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.edge.application/EdgeApp.bndrun | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cnf/pom.xml b/cnf/pom.xml index 3ae7771b07e..7842bce4836 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -162,7 +162,7 @@ net.java.dev.jna jna - 5.14.0 + 5.15.0 diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index a6ac193b88b..2c447433861 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -203,7 +203,7 @@ com.google.guava;version='[33.3.0,33.3.1)',\ com.google.guava.failureaccess;version='[1.0.2,1.0.3)',\ com.squareup.okio;version='[3.9.0,3.9.1)',\ - com.sun.jna;version='[5.14.0,5.14.1)',\ + com.sun.jna;version='[5.15.0,5.15.1)',\ io.openems.common;version=snapshot,\ io.openems.edge.application;version=snapshot,\ io.openems.edge.battery.api;version=snapshot,\ From 29eb8df73a41fc92abb6e4778c6101b738eb6dc4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Sep 2024 11:28:14 +0200 Subject: [PATCH 136/173] Build(deps): Bump org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm from 1.8.1 to 1.9.0 in /cnf (#2796) * Build(deps): Bump org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm Bumps [org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm](https://github.com/Kotlin/kotlinx.coroutines) from 1.8.1 to 1.9.0. - [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.8.1...1.9.0) --- updated-dependencies: - dependency-name: org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Update bnd --------- 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/bnd.bnd | 2 +- io.openems.wrapper/kotlinx-coroutines-core-jvm.bnd | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cnf/pom.xml b/cnf/pom.xml index 7842bce4836..cd3d228f653 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -306,7 +306,7 @@ org.jetbrains.kotlinx kotlinx-coroutines-core-jvm - 1.8.1 + 1.9.0 diff --git a/io.openems.wrapper/bnd.bnd b/io.openems.wrapper/bnd.bnd index 250390423e2..c709d538e36 100644 --- a/io.openems.wrapper/bnd.bnd +++ b/io.openems.wrapper/bnd.bnd @@ -27,4 +27,4 @@ Bundle-Description: This wraps external java libraries that do not have OSGi hea org.dhatim:fastexcel;version='0.18.2',\ org.dhatim:fastexcel-reader;version='0.18.2',\ org.eclipse.paho.mqttv5.client;version='1.2.5',\ - org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm;version='1.7.3',\ + org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm;version='1.9.0',\ diff --git a/io.openems.wrapper/kotlinx-coroutines-core-jvm.bnd b/io.openems.wrapper/kotlinx-coroutines-core-jvm.bnd index eaafb47be8d..3b276e9c952 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.8.1 +Bundle-Version: 1.9.0 Include-Resource: \ - @kotlinx-coroutines-core-jvm-1.8.1.jar,\ + @kotlinx-coroutines-core-jvm-1.9.0.jar,\ Export-Package: \ kotlinx.coroutines,\ From c9463a438a0eedd929a601488e6853a0cf60c860 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Sep 2024 14:47:58 +0200 Subject: [PATCH 137/173] Build(deps): Bump com.squareup.okio:okio-jvm from 3.9.0 to 3.9.1 in /cnf (#2797) * Build(deps): Bump com.squareup.okio:okio-jvm from 3.9.0 to 3.9.1 in /cnf Bumps [com.squareup.okio:okio-jvm](https://github.com/square/okio) from 3.9.0 to 3.9.1. - [Release notes](https://github.com/square/okio/releases) - [Changelog](https://github.com/square/okio/blob/master/CHANGELOG.md) - [Commits](https://github.com/square/okio/compare/parent-3.9.0...3.9.1) --- updated-dependencies: - dependency-name: com.squareup.okio:okio-jvm 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 cd3d228f653..c94a6d272ec 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -61,7 +61,7 @@ com.squareup.okio okio-jvm - 3.9.0 + 3.9.1 diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index 6d374f9dfb8..ae6fa899385 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -64,7 +64,7 @@ com.google.gson;version='[2.11.0,2.11.1)',\ com.google.guava;version='[33.3.0,33.3.1)',\ com.google.guava.failureaccess;version='[1.0.2,1.0.3)',\ - com.squareup.okio;version='[3.9.0,3.9.1)',\ + com.squareup.okio;version='[3.9.1,3.9.2)',\ com.zaxxer.HikariCP;version='[5.1.0,5.1.1)',\ 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 2c447433861..66c4b4ce7b4 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -202,7 +202,7 @@ com.google.gson;version='[2.11.0,2.11.1)',\ com.google.guava;version='[33.3.0,33.3.1)',\ com.google.guava.failureaccess;version='[1.0.2,1.0.3)',\ - com.squareup.okio;version='[3.9.0,3.9.1)',\ + com.squareup.okio;version='[3.9.1,3.9.2)',\ com.sun.jna;version='[5.15.0,5.15.1)',\ io.openems.common;version=snapshot,\ io.openems.edge.application;version=snapshot,\ From 2cc60e15835c5e934af5b14b6a9fecc731d6ac52 Mon Sep 17 00:00:00 2001 From: "Kai J." Date: Fri, 20 Sep 2024 15:49:16 +0200 Subject: [PATCH 138/173] Codecov: Set flags and components (#2810) --- .github/workflows/build.yml | 2 ++ codecov.yml | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6f1d4022ad0..b03b5287e16 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -43,6 +43,7 @@ jobs: - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v4 with: + flags: java token: ${{ secrets.CODECOV_TOKEN }} build-ui: @@ -77,5 +78,6 @@ jobs: - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v4 with: + flags: ui directory: ./ui/ token: ${{ secrets.CODECOV_TOKEN }} diff --git a/codecov.yml b/codecov.yml index 00b2350eb74..49e61532bad 100644 --- a/codecov.yml +++ b/codecov.yml @@ -14,3 +14,32 @@ comment: require_base: false require_head: true hide_project_coverage: true + +component_management: + default_rules: + statuses: + - type: project + target: auto + branches: + - "!main" + individual_components: + - component_id: openems_backend + name: "OpenEMS Backend" + paths: + - io.openems.backend.*/** + - io.openems.common/** + - io.openems.oem.*/** + - io.openems.shared.*/** + - io.openems.wrapper/** + - component_id: openems_edge + name: "OpenEMS Edge" + paths: + - io.openems.edge.*/** + - io.openems.common/** + - io.openems.oem.*/** + - io.openems.shared.*/** + - io.openems.wrapper/** + - component_id: openems_ui + name: "OpenEMS UI" + paths: + - ui/** \ No newline at end of file From 3b9c941e05e54a9bb19295d85c7fbcbaf4355fe0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 10:00:34 +0200 Subject: [PATCH 139/173] Build(deps): Bump org.apache.felix:org.apache.felix.webconsole from 5.0.6 to 5.0.8 in /cnf (#2818) * Build(deps): Bump org.apache.felix:org.apache.felix.webconsole in /cnf Bumps org.apache.felix:org.apache.felix.webconsole from 5.0.6 to 5.0.8. --- updated-dependencies: - dependency-name: org.apache.felix:org.apache.felix.webconsole 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 c94a6d272ec..fa62c20f2a7 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -237,7 +237,7 @@ org.apache.felix org.apache.felix.webconsole - 5.0.6 + 5.0.8 diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index ae6fa899385..ec5126eef1b 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -113,7 +113,7 @@ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ org.apache.felix.scr;version='[2.2.12,2.2.13)',\ - org.apache.felix.webconsole;version='[5.0.6,5.0.7)',\ + org.apache.felix.webconsole;version='[5.0.8,5.0.9)',\ org.apache.felix.webconsole.plugins.ds;version='[2.3.0,2.3.1)',\ org.jetbrains.kotlin.osgi-bundle;version='[2.0.20,2.0.21)',\ org.jsr-305;version='[3.0.2,3.0.3)',\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index 66c4b4ce7b4..bfccd5b97b6 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -409,7 +409,7 @@ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ org.apache.felix.scr;version='[2.2.12,2.2.13)',\ - org.apache.felix.webconsole;version='[5.0.6,5.0.7)',\ + org.apache.felix.webconsole;version='[5.0.8,5.0.9)',\ org.apache.felix.webconsole.plugins.ds;version='[2.3.0,2.3.1)',\ org.eclipse.jetty.client;version='[9.4.28,9.4.29)',\ org.eclipse.jetty.http;version='[9.4.28,9.4.29)',\ From c6fed129cabca97b55a534f42520dcc7b58a2d17 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 10:29:54 +0200 Subject: [PATCH 140/173] Build(deps): Bump com.google.guava:guava from 33.3.0-jre to 33.3.1-jre in /cnf (#2815) * Build(deps): Bump com.google.guava:guava in /cnf Bumps [com.google.guava:guava](https://github.com/google/guava) from 33.3.0-jre to 33.3.1-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 | 2 +- cnf/pom.xml | 2 +- io.openems.backend.application/BackendApp.bndrun | 2 +- io.openems.edge.application/EdgeApp.bndrun | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cnf/build.bnd b/cnf/build.bnd index 3a846baa49b..00cba399ba6 100644 --- a/cnf/build.bnd +++ b/cnf/build.bnd @@ -40,7 +40,7 @@ buildpath: \ org.osgi.service.metatype;version='1.4.1',\ org.osgi.service.metatype.annotations;version='1.4.1',\ org.osgi.util.promise;version='1.2.0',\ - com.google.guava;version='33.3.0.jre',\ + com.google.guava;version='33.3.1.jre',\ com.google.gson;version='2.11.0',\ testpath: \ diff --git a/cnf/pom.xml b/cnf/pom.xml index fa62c20f2a7..916c49e9d61 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -38,7 +38,7 @@ com.google.guava guava - 33.3.0-jre + 33.3.1-jre com.google.guava diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index ec5126eef1b..91d486066c1 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -62,7 +62,7 @@ Java-WebSocket;version='[1.5.4,1.5.5)',\ com.fasterxml.aalto-xml;version='[1.3.3,1.3.4)',\ com.google.gson;version='[2.11.0,2.11.1)',\ - com.google.guava;version='[33.3.0,33.3.1)',\ + com.google.guava;version='[33.3.1,33.3.2)',\ com.google.guava.failureaccess;version='[1.0.2,1.0.3)',\ com.squareup.okio;version='[3.9.1,3.9.2)',\ com.zaxxer.HikariCP;version='[5.1.0,5.1.1)',\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index bfccd5b97b6..11442b68bce 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -200,7 +200,7 @@ com.fazecast.jSerialComm;version='[2.10.4,2.10.5)',\ com.ghgande.j2mod;version='[3.2.1,3.2.2)',\ com.google.gson;version='[2.11.0,2.11.1)',\ - com.google.guava;version='[33.3.0,33.3.1)',\ + com.google.guava;version='[33.3.1,33.3.2)',\ com.google.guava.failureaccess;version='[1.0.2,1.0.3)',\ com.squareup.okio;version='[3.9.1,3.9.2)',\ com.sun.jna;version='[5.15.0,5.15.1)',\ From 3b885899d26cecc06d11c0aefa22732caf2b8e7e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 12:28:48 +0200 Subject: [PATCH 141/173] Build(deps): Bump the fastexcel group across 1 directory with 2 updates (#2816) * Build(deps): Bump the fastexcel group across 1 directory with 2 updates Bumps the fastexcel group with 2 updates in the /cnf directory: [org.dhatim:fastexcel](https://github.com/dhatim/fastexcel) and [org.dhatim:fastexcel-reader](https://github.com/dhatim/fastexcel). Updates `org.dhatim:fastexcel` from 0.18.2 to 0.18.4 - [Release notes](https://github.com/dhatim/fastexcel/releases) - [Commits](https://github.com/dhatim/fastexcel/compare/0.18.2...0.18.4) Updates `org.dhatim:fastexcel-reader` from 0.18.2 to 0.18.4 - [Release notes](https://github.com/dhatim/fastexcel/releases) - [Commits](https://github.com/dhatim/fastexcel/compare/0.18.2...0.18.4) --- updated-dependencies: - dependency-name: org.dhatim:fastexcel dependency-type: direct:production update-type: version-update:semver-patch dependency-group: fastexcel - dependency-name: org.dhatim:fastexcel-reader dependency-type: direct:production update-type: version-update:semver-patch dependency-group: fastexcel ... Signed-off-by: dependabot[bot] * Update bnd --------- 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 | 4 ++-- io.openems.wrapper/bnd.bnd | 4 ++-- io.openems.wrapper/fastexcel.bnd | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cnf/pom.xml b/cnf/pom.xml index 916c49e9d61..666096bbac7 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -260,12 +260,12 @@ org.dhatim fastexcel - 0.18.2 + 0.18.4 org.dhatim fastexcel-reader - 0.18.2 + 0.18.4 diff --git a/io.openems.wrapper/bnd.bnd b/io.openems.wrapper/bnd.bnd index c709d538e36..d024f94a589 100644 --- a/io.openems.wrapper/bnd.bnd +++ b/io.openems.wrapper/bnd.bnd @@ -24,7 +24,7 @@ Bundle-Description: This wraps external java libraries that do not have OSGi hea com.google.gson;version='2.10.1',\ de.bytefish:pgbulkinsert;version='8.1.4',\ fr.turri:aXMLRPC;version='1.13.0',\ - org.dhatim:fastexcel;version='0.18.2',\ - org.dhatim:fastexcel-reader;version='0.18.2',\ + org.dhatim:fastexcel;version='0.18.4',\ + org.dhatim:fastexcel-reader;version='0.18.4',\ org.eclipse.paho.mqttv5.client;version='1.2.5',\ org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm;version='1.9.0',\ diff --git a/io.openems.wrapper/fastexcel.bnd b/io.openems.wrapper/fastexcel.bnd index 5e05cab91ae..68c2302413d 100644 --- a/io.openems.wrapper/fastexcel.bnd +++ b/io.openems.wrapper/fastexcel.bnd @@ -1,11 +1,11 @@ Bundle-Name: fastexcel Bundle-DocURL: https://github.com/dhatim/fastexcel Bundle-License: https://opensource.org/licenses/Apache-2.0 -Bundle-Version: 0.18.2 +Bundle-Version: 0.18.4 Include-Resource: \ - @fastexcel-0.18.2.jar,\ - @fastexcel-reader-0.18.2.jar,\ + @fastexcel-0.18.4.jar,\ + @fastexcel-reader-0.18.4.jar,\ -dsannotations: * From 94f1cc69dc8395b8d019734fc75592032a0583c9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 12:35:35 +0200 Subject: [PATCH 142/173] Build(deps): Bump com.zaxxer:HikariCP from 5.1.0 to 6.0.0 in /cnf (#2817) * Build(deps): Bump com.zaxxer:HikariCP from 5.1.0 to 6.0.0 in /cnf Bumps [com.zaxxer:HikariCP](https://github.com/brettwooldridge/HikariCP) from 5.1.0 to 6.0.0. - [Changelog](https://github.com/brettwooldridge/HikariCP/blob/dev/CHANGES) - [Commits](https://github.com/brettwooldridge/HikariCP/compare/HikariCP-5.1.0...HikariCP-6.0.0) --- updated-dependencies: - dependency-name: com.zaxxer:HikariCP dependency-type: direct:production update-type: version-update:semver-major ... 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 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cnf/pom.xml b/cnf/pom.xml index 666096bbac7..83b8c69ddd9 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -97,7 +97,7 @@ com.zaxxer HikariCP - 5.1.0 + 6.0.0 diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index 91d486066c1..e210938f4fd 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -65,7 +65,7 @@ com.google.guava;version='[33.3.1,33.3.2)',\ com.google.guava.failureaccess;version='[1.0.2,1.0.3)',\ com.squareup.okio;version='[3.9.1,3.9.2)',\ - com.zaxxer.HikariCP;version='[5.1.0,5.1.1)',\ + com.zaxxer.HikariCP;version='[6.0.0,6.0.1)',\ io.openems.backend.alerting;version=snapshot,\ io.openems.backend.application;version=snapshot,\ io.openems.backend.b2brest;version=snapshot,\ From 2f62829b27d69d01cfb447e8d90be4ab166208e8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 12:39:12 +0200 Subject: [PATCH 143/173] Build(deps): Bump swiper from 11.1.11 to 11.1.14 in /ui (#2802) Bumps [swiper](https://github.com/nolimits4web/Swiper) from 11.1.11 to 11.1.14. - [Release notes](https://github.com/nolimits4web/Swiper/releases) - [Changelog](https://github.com/nolimits4web/swiper/blob/master/CHANGELOG.md) - [Commits](https://github.com/nolimits4web/Swiper/compare/v11.1.11...v11.1.14) --- updated-dependencies: - dependency-name: swiper dependency-type: direct:production update-type: version-update:semver-patch ... 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 | 9 ++++----- ui/package.json | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 57e8255f84d..2c5bd5dfaaa 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -51,7 +51,7 @@ "ngx-spinner": "^16.0.2", "roboto-fontface": "^0.10.0", "rxjs": "~6.6.7", - "swiper": "11.1.11", + "swiper": "11.1.14", "tslib": "^2.6.2", "uuid": "^10.0.0", "zone.js": "~0.14.7" @@ -22989,9 +22989,9 @@ } }, "node_modules/swiper": { - "version": "11.1.11", - "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.1.11.tgz", - "integrity": "sha512-077Aw3OrlZpkkBRf/6+44bGh/HZY/vsLEyate2db2KkJgYUIR5TvDgvvhcJtW/puXzw79w5KBc30DauEX6GZYQ==", + "version": "11.1.14", + "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.1.14.tgz", + "integrity": "sha512-VbQLQXC04io6AoAjIUWuZwW4MSYozkcP9KjLdrsG/00Q/yiwvhz9RQyt0nHXV10hi9NVnDNy1/wv7Dzq1lkOCQ==", "funding": [ { "type": "patreon", @@ -23002,7 +23002,6 @@ "url": "http://opencollective.com/swiper" } ], - "license": "MIT", "engines": { "node": ">= 4.7.0" } diff --git a/ui/package.json b/ui/package.json index 8f0c436942f..8bdb4be1912 100644 --- a/ui/package.json +++ b/ui/package.json @@ -46,7 +46,7 @@ "ngx-spinner": "^16.0.2", "roboto-fontface": "^0.10.0", "rxjs": "~6.6.7", - "swiper": "11.1.11", + "swiper": "11.1.14", "tslib": "^2.6.2", "uuid": "^10.0.0", "zone.js": "~0.14.7" From c1660e610709da3d56b4350bf86ee05a2d83c9ea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 12:55:28 +0200 Subject: [PATCH 144/173] Build(deps): Bump @capacitor-community/file-opener in /ui (#2787) Bumps [@capacitor-community/file-opener](https://github.com/capacitor-community/file-opener) from 6.0.0 to 6.0.1. - [Release notes](https://github.com/capacitor-community/file-opener/releases) - [Changelog](https://github.com/capacitor-community/file-opener/blob/master/CHANGELOG.md) - [Commits](https://github.com/capacitor-community/file-opener/compare/v6.0.0...v6.0.1) --- updated-dependencies: - dependency-name: "@capacitor-community/file-opener" dependency-type: direct:production update-type: version-update:semver-patch ... 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 | 9 ++++----- ui/package.json | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 2c5bd5dfaaa..482e41f096d 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -17,7 +17,7 @@ "@angular/platform-browser-dynamic": "18.0.5", "@angular/router": "18.0.5", "@angular/service-worker": "18.0.5", - "@capacitor-community/file-opener": "^6.0.0", + "@capacitor-community/file-opener": "^6.0.1", "@capacitor/android": "^6.0.0", "@capacitor/app": "^6.0.0", "@capacitor/core": "^6.0.0", @@ -3315,10 +3315,9 @@ } }, "node_modules/@capacitor-community/file-opener": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@capacitor-community/file-opener/-/file-opener-6.0.0.tgz", - "integrity": "sha512-nJ9S5rCqnVDBKfqdjDhrYOIO9JLeScFkRfKLs2G+d6Df73vrJMes8dr+dGSEvKiPhyjRhICW5imDJEbzaD8KpA==", - "license": "MIT", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@capacitor-community/file-opener/-/file-opener-6.0.1.tgz", + "integrity": "sha512-6DMcCVZPWnx1ewlCcciDGQ9n+hZt7ixLuSMv5U2epyZJ44vdLXEKjZvwU+Wpdpmsq5p0pT9jExDODFdc+DNCsw==", "engines": { "node": ">=16.0.0", "npm": ">=8.0.0" diff --git a/ui/package.json b/ui/package.json index 8bdb4be1912..54462d2b155 100644 --- a/ui/package.json +++ b/ui/package.json @@ -12,7 +12,7 @@ "@angular/platform-browser-dynamic": "18.0.5", "@angular/router": "18.0.5", "@angular/service-worker": "18.0.5", - "@capacitor-community/file-opener": "^6.0.0", + "@capacitor-community/file-opener": "^6.0.1", "@capacitor/android": "^6.0.0", "@capacitor/app": "^6.0.0", "@capacitor/core": "^6.0.0", From 9c1b60052d3f5d505f784ae855c51fa9dde43cf0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 15:42:01 +0200 Subject: [PATCH 145/173] Build(deps): Bump serve-static and express in /ui (#2805) Bumps [serve-static](https://github.com/expressjs/serve-static) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together. Updates `serve-static` from 1.15.0 to 1.16.2 - [Release notes](https://github.com/expressjs/serve-static/releases) - [Changelog](https://github.com/expressjs/serve-static/blob/v1.16.2/HISTORY.md) - [Commits](https://github.com/expressjs/serve-static/compare/v1.15.0...v1.16.2) Updates `express` from 4.19.2 to 4.21.0 - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/4.21.0/History.md) - [Commits](https://github.com/expressjs/express/compare/4.19.2...4.21.0) --- updated-dependencies: - dependency-name: serve-static dependency-type: indirect - dependency-name: express dependency-type: indirect ... 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 | 121 ++++++++++++++++++++++--------------------- 1 file changed, 62 insertions(+), 59 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 482e41f096d..c76483c8702 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -8855,11 +8855,10 @@ } }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, - "license": "MIT", "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", @@ -8869,7 +8868,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -12822,7 +12821,6 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -12902,38 +12900,37 @@ "license": "Apache-2.0" }, "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", + "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", "dev": true, - "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -12959,20 +12956,27 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } }, + "node_modules/express/node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/express/node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dev": true, - "license": "MIT", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -12987,15 +12991,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/express/node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -13445,7 +13447,6 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -17549,11 +17550,13 @@ } }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", "dev": true, - "license": "MIT" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/merge-stream": { "version": "2.0.0", @@ -19475,11 +19478,10 @@ "license": "ISC" }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", - "dev": true, - "license": "MIT" + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", + "dev": true }, "node_modules/path-type": { "version": "4.0.0", @@ -20394,13 +20396,12 @@ } }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -21739,11 +21740,10 @@ } }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, - "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -21768,7 +21768,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -21777,15 +21776,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/send/node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, - "license": "MIT", "bin": { "mime": "cli.js" }, @@ -21797,15 +21794,13 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/send/node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -21897,21 +21892,29 @@ "license": "ISC" }, "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dev": true, - "license": "MIT", "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" } }, + "node_modules/serve-static/node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", From 4b8aeb778bed2c0d2aa612656ff6cac7001a42a5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 16:18:00 +0200 Subject: [PATCH 146/173] Build(deps): Bump vite and @angular-devkit/build-angular in /ui (#2808) Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) to 5.4.6 and updates ancestor dependency [@angular-devkit/build-angular](https://github.com/angular/angular-cli). These dependencies need to be updated together. Updates `vite` from 5.4.0 to 5.4.6 - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/v5.4.6/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v5.4.6/packages/vite) Updates `@angular-devkit/build-angular` from 18.2.2 to 18.2.5 - [Release notes](https://github.com/angular/angular-cli/releases) - [Changelog](https://github.com/angular/angular-cli/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular-cli/compare/18.2.2...18.2.5) --- updated-dependencies: - dependency-name: vite dependency-type: indirect - dependency-name: "@angular-devkit/build-angular" dependency-type: direct:development ... 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 | 587 ++++++++++++++----------------------------- ui/package.json | 2 +- 2 files changed, 185 insertions(+), 404 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index c76483c8702..0241d54a2c3 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -57,7 +57,7 @@ "zone.js": "~0.14.7" }, "devDependencies": { - "@angular-devkit/build-angular": "^18.0.5", + "@angular-devkit/build-angular": "^18.2.5", "@angular-devkit/core": "18.0.5", "@angular-devkit/schematics": "18.0.5", "@angular-eslint/builder": "^18.1.0", @@ -118,13 +118,12 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.1802.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1802.2.tgz", - "integrity": "sha512-LPRl9jhcf0NgshaL6RoUy1uL/cAyNt7oxctoZ9EHUu8eh5E9W/jZGhVowjOLpirwqYhmEzKJJIeS49Ssqs3RQg==", + "version": "0.1802.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1802.5.tgz", + "integrity": "sha512-c7sVoW85Yqj7IYvNKxtNSGS5I7gWpORorg/xxLZX3OkHWXDrwYbb5LN/2p5/Aytxyb0aXl4o5fFOu6CUwcaLUw==", "dev": true, - "license": "MIT", "dependencies": { - "@angular-devkit/core": "18.2.2", + "@angular-devkit/core": "18.2.5", "rxjs": "7.8.1" }, "engines": { @@ -134,11 +133,10 @@ } }, "node_modules/@angular-devkit/architect/node_modules/@angular-devkit/core": { - "version": "18.2.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.2.tgz", - "integrity": "sha512-Zz0tGptI/QQnUBDdp+1G5wGwQWMjpfe2oO+UohkrDVgFS71yVj4VDnOy51kMTxBvzw+36evTgthPpmzqPIfxBw==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.5.tgz", + "integrity": "sha512-r9TumPlJ8PvA2+yz4sp+bUHgtznaVKzhvXTN5qL1k4YP8LJ7iZWMR2FOP+HjukHZOTsenzmV9pszbogabqwoZQ==", "dev": true, - "license": "MIT", "dependencies": { "ajv": "8.17.1", "ajv-formats": "3.0.1", @@ -166,7 +164,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, - "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -183,23 +180,21 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, - "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@angular-devkit/build-angular": { - "version": "18.2.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-18.2.2.tgz", - "integrity": "sha512-7HEnTN2T1jnjuItXKcApOsoYGgfou4+POju3ZbwIQukDZ3B2COskvQkVTxqPNrQ0ZjT2mxZYoVlmGW9M+7N25g==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-18.2.5.tgz", + "integrity": "sha512-dIvb0AHoRIMM6tLuG4t6lDDslSAYP77wqytodsN317UzFOuuCPernXbO8NJs+QHxj09nPsem1T5vnvpO2E/PVQ==", "dev": true, - "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1802.2", - "@angular-devkit/build-webpack": "0.1802.2", - "@angular-devkit/core": "18.2.2", - "@angular/build": "18.2.2", + "@angular-devkit/architect": "0.1802.5", + "@angular-devkit/build-webpack": "0.1802.5", + "@angular-devkit/core": "18.2.5", + "@angular/build": "18.2.5", "@babel/core": "7.25.2", "@babel/generator": "7.25.0", "@babel/helper-annotate-as-pure": "7.24.7", @@ -210,7 +205,7 @@ "@babel/preset-env": "7.25.3", "@babel/runtime": "7.25.0", "@discoveryjs/json-ext": "0.6.1", - "@ngtools/webpack": "18.2.2", + "@ngtools/webpack": "18.2.5", "@vitejs/plugin-basic-ssl": "1.1.0", "ansi-colors": "4.1.3", "autoprefixer": "10.4.20", @@ -250,10 +245,10 @@ "terser": "5.31.6", "tree-kill": "1.2.2", "tslib": "2.6.3", - "vite": "5.4.0", + "vite": "5.4.6", "watchpack": "2.4.1", "webpack": "5.94.0", - "webpack-dev-middleware": "7.3.0", + "webpack-dev-middleware": "7.4.2", "webpack-dev-server": "5.0.4", "webpack-merge": "6.0.1", "webpack-subresource-integrity": "5.1.0" @@ -318,11 +313,10 @@ } }, "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core": { - "version": "18.2.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.2.tgz", - "integrity": "sha512-Zz0tGptI/QQnUBDdp+1G5wGwQWMjpfe2oO+UohkrDVgFS71yVj4VDnOy51kMTxBvzw+36evTgthPpmzqPIfxBw==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.5.tgz", + "integrity": "sha512-r9TumPlJ8PvA2+yz4sp+bUHgtznaVKzhvXTN5qL1k4YP8LJ7iZWMR2FOP+HjukHZOTsenzmV9pszbogabqwoZQ==", "dev": true, - "license": "MIT", "dependencies": { "ajv": "8.17.1", "ajv-formats": "3.0.1", @@ -346,14 +340,13 @@ } }, "node_modules/@angular-devkit/build-angular/node_modules/@angular/build": { - "version": "18.2.2", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-18.2.2.tgz", - "integrity": "sha512-okaDdTMXnDhvnnnih6rPQnexL6htfEAPr19bB1Ci9d31gEjVuKZCjlcw2sPZ6BUyilwC9nZlCI5vbH1Ljf6mzA==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-18.2.5.tgz", + "integrity": "sha512-XWkmjzgeUga0SJ0lYSYcTuYOWTyqcln2mNfBp7Ae/GZ+/7+APbedsIZEiZGZwveOIyOpTM5wguNSoe9khDl5Ig==", "dev": true, - "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1802.2", + "@angular-devkit/architect": "0.1802.5", "@babel/core": "7.25.2", "@babel/helper-annotate-as-pure": "7.24.7", "@babel/helper-split-export-declaration": "7.24.7", @@ -375,7 +368,7 @@ "rollup": "4.20.0", "sass": "1.77.6", "semver": "7.6.3", - "vite": "5.4.0", + "vite": "5.4.6", "watchpack": "2.4.1" }, "engines": { @@ -422,7 +415,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -436,7 +428,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -450,7 +441,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -464,7 +454,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -478,7 +467,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -492,7 +480,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -506,7 +493,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -520,7 +506,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -534,7 +519,6 @@ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -548,7 +532,6 @@ "riscv64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -562,7 +545,6 @@ "s390x" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -576,7 +558,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -590,7 +571,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -604,7 +584,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -618,7 +597,6 @@ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -632,7 +610,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -643,7 +620,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, - "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -656,11 +632,10 @@ } }, "node_modules/@angular-devkit/build-angular/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -673,7 +648,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -685,22 +659,19 @@ "version": "10.4.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@angular-devkit/build-angular/node_modules/eventemitter3": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@angular-devkit/build-angular/node_modules/listr2": { "version": "8.2.4", "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.4.tgz", "integrity": "sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g==", "dev": true, - "license": "MIT", "dependencies": { "cli-truncate": "^4.0.0", "colorette": "^2.0.20", @@ -718,7 +689,6 @@ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.20.0.tgz", "integrity": "sha512-6rbWBChcnSGzIlXeIdNIZTopKYad8ZG8ajhl78lGRLsI2rX8IkaotQhVas2Ma+GPxJav19wrSzvRvuiv0YKzWw==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree": "1.0.5" }, @@ -754,7 +724,6 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, - "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -764,7 +733,6 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, - "license": "MIT", "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", @@ -782,7 +750,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, - "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -797,15 +764,13 @@ "version": "2.6.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", - "dev": true, - "license": "0BSD" + "dev": true }, "node_modules/@angular-devkit/build-angular/node_modules/wrap-ansi": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", @@ -819,13 +784,12 @@ } }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.1802.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1802.2.tgz", - "integrity": "sha512-Pj+YmKh0nJOKl6QAsqYh3SqfuVJrFqjyp5WrG9BgfsMD9GCMD+5teMHNYJlp+vG/C8e7VdZp4rqOon8K9Xn4Mw==", + "version": "0.1802.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1802.5.tgz", + "integrity": "sha512-6qkcrWBdkxojCVHGWcdJaz4G+7QTjFvmc+3g8xvLc9sYvJq1I059gfXhDnC0FxiA0MT4cY/26ECYWUHTD5CJLQ==", "dev": true, - "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.1802.2", + "@angular-devkit/architect": "0.1802.5", "rxjs": "7.8.1" }, "engines": { @@ -843,7 +807,6 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, - "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -1793,7 +1756,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.24.7" }, @@ -3700,7 +3662,6 @@ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "aix" @@ -3717,7 +3678,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -3734,7 +3694,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -3751,7 +3710,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -3768,7 +3726,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -3785,7 +3742,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -3802,7 +3758,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -3819,7 +3774,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -3836,7 +3790,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -3853,7 +3806,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -3870,7 +3822,6 @@ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -3887,7 +3838,6 @@ "loong64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -3904,7 +3854,6 @@ "mips64el" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -3921,7 +3870,6 @@ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -3938,7 +3886,6 @@ "riscv64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -3955,7 +3902,6 @@ "s390x" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -3972,7 +3918,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -3989,7 +3934,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "netbsd" @@ -4006,7 +3950,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "openbsd" @@ -4023,7 +3966,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "openbsd" @@ -4040,7 +3982,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "sunos" @@ -4057,7 +3998,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -4074,7 +4014,6 @@ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -4091,7 +4030,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -5687,7 +5625,6 @@ "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=10.0" }, @@ -5704,7 +5641,6 @@ "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.1.0.tgz", "integrity": "sha512-zlQONA+msXPPwHWZMKFVS78ewFczIll5lXiVPwFPCZUsrOKdxc2AvxU1HoNBmMRhqDZUR9HkC3UOm+6pME6Xsg==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@jsonjoy.com/base64": "^1.1.1", "@jsonjoy.com/util": "^1.1.2", @@ -5727,7 +5663,6 @@ "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.3.0.tgz", "integrity": "sha512-Cebt4Vk7k1xHy87kHY7KSPLT77A7Ev7IfOblyLZhtYEhrdQ6fX4EoLq3xOQ3O/DRMEh2ok5nyC180E+ABS8Wmw==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=10.0" }, @@ -5749,8 +5684,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@listr2/prompt-adapter-inquirer": { "version": "2.0.13", @@ -5776,7 +5710,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -5790,7 +5723,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -5804,7 +5736,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -5818,7 +5749,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -5832,7 +5762,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -5846,7 +5775,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -5860,7 +5788,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -5874,7 +5801,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -5888,7 +5814,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -5902,7 +5827,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -5916,7 +5840,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -5930,18 +5853,16 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@ngtools/webpack": { - "version": "18.2.2", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.2.2.tgz", - "integrity": "sha512-YhADmc+lVjLt3kze07A+yLry2yzcghdclu+7D3EDfa6fG2Pk33HK3MY2I0Z0BO+Ivoq7cV7yxm+naR+Od0Y5ng==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.2.5.tgz", + "integrity": "sha512-L0n4eHObeqEOYRfSP+e4SeF/dmwxOIFy9xYvYCOUwOLrW4b3+a1+kkT30pqyfL72LFtpf0cmUwaWEFIcWl5PCg==", "dev": true, - "license": "MIT", "engines": { "node": "^18.19.1 || ^20.11.1 || >=22.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", @@ -6491,224 +6412,208 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.2.tgz", - "integrity": "sha512-fSuPrt0ZO8uXeS+xP3b+yYTCBUd05MoSp2N/MFOgjhhUhMmchXlpTQrTpI8T+YAwAQuK7MafsCOxW7VrPMrJcg==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.0.tgz", + "integrity": "sha512-/IZQvg6ZR0tAkEi4tdXOraQoWeJy9gbQ/cx4I7k9dJaCk9qrXEcdouxRVz5kZXt5C2bQ9pILoAA+KB4C/d3pfw==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.2.tgz", - "integrity": "sha512-xGU5ZQmPlsjQS6tzTTGwMsnKUtu0WVbl0hYpTPauvbRAnmIvpInhJtgjj3mcuJpEiuUw4v1s4BimkdfDWlh7gA==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.0.tgz", + "integrity": "sha512-ETHi4bxrYnvOtXeM7d4V4kZWixib2jddFacJjsOjwbgYSRsyXYtZHC4ht134OsslPIcnkqT+TKV4eU8rNBKyyQ==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.2.tgz", - "integrity": "sha512-99AhQ3/ZMxU7jw34Sq8brzXqWH/bMnf7ZVhvLk9QU2cOepbQSVTns6qoErJmSiAvU3InRqC2RRZ5ovh1KN0d0Q==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.0.tgz", + "integrity": "sha512-ZWgARzhSKE+gVUX7QWaECoRQsPwaD8ZR0Oxb3aUpzdErTvlEadfQpORPXkKSdKbFci9v8MJfkTtoEHnnW9Ulng==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.2.tgz", - "integrity": "sha512-ZbRaUvw2iN/y37x6dY50D8m2BnDbBjlnMPotDi/qITMJ4sIxNY33HArjikDyakhSv0+ybdUxhWxE6kTI4oX26w==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.0.tgz", + "integrity": "sha512-h0ZAtOfHyio8Az6cwIGS+nHUfRMWBDO5jXB8PQCARVF6Na/G6XS2SFxDl8Oem+S5ZsHQgtsI7RT4JQnI1qrlaw==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.2.tgz", - "integrity": "sha512-ztRJJMiE8nnU1YFcdbd9BcH6bGWG1z+jP+IPW2oDUAPxPjo9dverIOyXz76m6IPA6udEL12reYeLojzW2cYL7w==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.0.tgz", + "integrity": "sha512-9pxQJSPwFsVi0ttOmqLY4JJ9pg9t1gKhK0JDbV1yUEETSx55fdyCjt39eBQ54OQCzAF0nVGO6LfEH1KnCPvelA==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.2.tgz", - "integrity": "sha512-flOcGHDZajGKYpLV0JNc0VFH361M7rnV1ee+NTeC/BQQ1/0pllYcFmxpagltANYt8FYf9+kL6RSk80Ziwyhr7w==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.0.tgz", + "integrity": "sha512-YJ5Ku5BmNJZb58A4qSEo3JlIG4d3G2lWyBi13ABlXzO41SsdnUKi3HQHe83VpwBVG4jHFTW65jOQb8qyoR+qzg==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.2.tgz", - "integrity": "sha512-69CF19Kp3TdMopyteO/LJbWufOzqqXzkrv4L2sP8kfMaAQ6iwky7NoXTp7bD6/irKgknDKM0P9E/1l5XxVQAhw==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.0.tgz", + "integrity": "sha512-U4G4u7f+QCqHlVg1Nlx+qapZy+QoG+NV6ux+upo/T7arNGwKvKP2kmGM4W5QTbdewWFgudQxi3kDNST9GT1/mg==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.2.tgz", - "integrity": "sha512-48pD/fJkTiHAZTnZwR0VzHrao70/4MlzJrq0ZsILjLW/Ab/1XlVUStYyGt7tdyIiVSlGZbnliqmult/QGA2O2w==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.0.tgz", + "integrity": "sha512-aQpNlKmx3amwkA3a5J6nlXSahE1ijl0L9KuIjVOUhfOh7uw2S4piR3mtpxpRtbnK809SBtyPsM9q15CPTsY7HQ==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.2.tgz", - "integrity": "sha512-cZdyuInj0ofc7mAQpKcPR2a2iu4YM4FQfuUzCVA2u4HI95lCwzjoPtdWjdpDKyHxI0UO82bLDoOaLfpZ/wviyQ==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.0.tgz", + "integrity": "sha512-9fx6Zj/7vve/Fp4iexUFRKb5+RjLCff6YTRQl4CoDhdMfDoobWmhAxQWV3NfShMzQk1Q/iCnageFyGfqnsmeqQ==", "cpu": [ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.2.tgz", - "integrity": "sha512-RL56JMT6NwQ0lXIQmMIWr1SW28z4E4pOhRRNqwWZeXpRlykRIlEpSWdsgNWJbYBEWD84eocjSGDu/XxbYeCmwg==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.0.tgz", + "integrity": "sha512-VWQiCcN7zBgZYLjndIEh5tamtnKg5TGxyZPWcN9zBtXBwfcGSZ5cHSdQZfQH/GB4uRxk0D3VYbOEe/chJhPGLQ==", "cpu": [ "riscv64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.2.tgz", - "integrity": "sha512-PMxkrWS9z38bCr3rWvDFVGD6sFeZJw4iQlhrup7ReGmfn7Oukrr/zweLhYX6v2/8J6Cep9IEA/SmjXjCmSbrMQ==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.0.tgz", + "integrity": "sha512-EHmPnPWvyYqncObwqrosb/CpH3GOjE76vWVs0g4hWsDRUVhg61hBmlVg5TPXqF+g+PvIbqkC7i3h8wbn4Gp2Fg==", "cpu": [ "s390x" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.2.tgz", - "integrity": "sha512-B90tYAUoLhU22olrafY3JQCFLnT3NglazdwkHyxNDYF/zAxJt5fJUB/yBoWFoIQ7SQj+KLe3iL4BhOMa9fzgpw==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.0.tgz", + "integrity": "sha512-tsSWy3YQzmpjDKnQ1Vcpy3p9Z+kMFbSIesCdMNgLizDWFhrLZIoN21JSq01g+MZMDFF+Y1+4zxgrlqPjid5ohg==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.2.tgz", - "integrity": "sha512-7twFizNXudESmC9oneLGIUmoHiiLppz/Xs5uJQ4ShvE6234K0VB1/aJYU3f/4g7PhssLGKBVCC37uRkkOi8wjg==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.0.tgz", + "integrity": "sha512-anr1Y11uPOQrpuU8XOikY5lH4Qu94oS6j0xrulHk3NkLDq19MlX8Ng/pVipjxBJ9a2l3+F39REZYyWQFkZ4/fw==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.2.tgz", - "integrity": "sha512-9rRero0E7qTeYf6+rFh3AErTNU1VCQg2mn7CQcI44vNUWM9Ze7MSRS/9RFuSsox+vstRt97+x3sOhEey024FRQ==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.0.tgz", + "integrity": "sha512-7LB+Bh+Ut7cfmO0m244/asvtIGQr5pG5Rvjz/l1Rnz1kDzM02pSX9jPaS0p+90H5I1x4d1FkCew+B7MOnoatNw==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.2.tgz", - "integrity": "sha512-5rA4vjlqgrpbFVVHX3qkrCo/fZTj1q0Xxpg+Z7yIo3J2AilW7t2+n6Q8Jrx+4MrYpAnjttTYF8rr7bP46BPzRw==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.0.tgz", + "integrity": "sha512-+3qZ4rer7t/QsC5JwMpcvCVPRcJt1cJrYS/TMJZzXIJbxWFQEVhrIc26IhB+5Z9fT9umfVc+Es2mOZgl+7jdJQ==", "cpu": [ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.2.tgz", - "integrity": "sha512-6UUxd0+SKomjdzuAcp+HAmxw1FlGBnl1v2yEPSabtx4lBfdXHDVsW7+lQkgz9cNFJGY3AWR7+V8P5BqkD9L9nA==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.0.tgz", + "integrity": "sha512-YdicNOSJONVx/vuPkgPTyRoAPx3GbknBZRCOUkK84FJ/YTfs/F0vl/YsMscrB6Y177d+yDRcj+JWMPMCgshwrA==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -7089,7 +6994,6 @@ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", "dev": true, - "license": "MIT", "dependencies": { "@types/connect": "*", "@types/node": "*" @@ -7100,7 +7004,6 @@ "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -7110,7 +7013,6 @@ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -7120,7 +7022,6 @@ "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", "dev": true, - "license": "MIT", "dependencies": { "@types/express-serve-static-core": "*", "@types/node": "*" @@ -7172,7 +7073,6 @@ "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", @@ -7185,7 +7085,6 @@ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -7207,8 +7106,7 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/http-proxy": { "version": "1.17.15", @@ -7290,7 +7188,6 @@ "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -7327,8 +7224,7 @@ "version": "0.12.2", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/selenium-webdriver": { "version": "3.0.26", @@ -7353,7 +7249,6 @@ "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", "dev": true, - "license": "MIT", "dependencies": { "@types/express": "*" } @@ -7363,7 +7258,6 @@ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", "dev": true, - "license": "MIT", "dependencies": { "@types/http-errors": "*", "@types/node": "*", @@ -7382,7 +7276,6 @@ "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -7406,7 +7299,6 @@ "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", "integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -7767,7 +7659,6 @@ "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.1.0.tgz", "integrity": "sha512-wO4Dk/rm8u7RNhOf95ZzcEmC9rYOncYgvq4z3duaJrCgjN8BxAnDVyndanfcJZ0O6XZzHz6Q0hTimxTg8Y9g/A==", "dev": true, - "license": "MIT", "engines": { "node": ">=14.6.0" }, @@ -8202,7 +8093,6 @@ "engines": [ "node >= 0.8.0" ], - "license": "Apache-2.0", "bin": { "ansi-html": "bin/ansi-html" } @@ -8311,8 +8201,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/array-ify": { "version": "1.0.0", @@ -8781,8 +8670,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/bcrypt-pbkdf": { "version": "1.0.2", @@ -8913,7 +8801,6 @@ "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", "dev": true, - "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "multicast-dns": "^7.2.5" @@ -9098,7 +8985,6 @@ "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", "dev": true, - "license": "MIT", "dependencies": { "run-applescript": "^7.0.0" }, @@ -9822,7 +9708,6 @@ "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", "dev": true, - "license": "MIT", "dependencies": { "mime-db": ">= 1.43.0 < 2" }, @@ -9835,7 +9720,6 @@ "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", "dev": true, - "license": "MIT", "dependencies": { "accepts": "~1.3.5", "bytes": "3.0.0", @@ -9854,7 +9738,6 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -9864,7 +9747,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -9873,15 +9755,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/compression/node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/concat-map": { "version": "0.0.1", @@ -9911,7 +9791,6 @@ "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.8" } @@ -9938,7 +9817,6 @@ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "dev": true, - "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" }, @@ -10226,8 +10104,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/cookiejar": { "version": "2.1.4", @@ -10408,7 +10285,6 @@ "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.24.tgz", "integrity": "sha512-Oyqew0FGM0wYUSNqR0L6AteO5MpMoUU0rhKRieXeiKs+PmRTxiJMyaunYB2KF6fQ3dzChXKCpbFOEJx3OQ1v/Q==", "dev": true, - "license": "Apache-2.0", "dependencies": { "chalk": "^4.1.0", "css-select": "^5.1.0", @@ -10424,7 +10300,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -10440,7 +10315,6 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -10457,7 +10331,6 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -10469,15 +10342,13 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/critters/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -10487,7 +10358,6 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -10571,7 +10441,6 @@ "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", @@ -11242,7 +11111,6 @@ "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", "dev": true, - "license": "MIT", "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" @@ -11259,7 +11127,6 @@ "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" }, @@ -11272,7 +11139,6 @@ "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "execa": "^5.0.0" }, @@ -11285,7 +11151,6 @@ "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, - "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -11309,7 +11174,6 @@ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" }, @@ -11322,7 +11186,6 @@ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=10.17.0" } @@ -11331,8 +11194,7 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/defaults": { "version": "1.0.4", @@ -11369,7 +11231,6 @@ "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -11514,8 +11375,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/dezalgo": { "version": "1.0.4", @@ -11563,7 +11423,6 @@ "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", "dev": true, - "license": "MIT", "dependencies": { "@leichtgewicht/ip-codec": "^2.0.1" }, @@ -11602,7 +11461,6 @@ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "dev": true, - "license": "MIT", "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", @@ -11630,7 +11488,6 @@ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "domelementtype": "^2.3.0" }, @@ -11646,7 +11503,6 @@ "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", @@ -12115,7 +11971,6 @@ "integrity": "sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==", "dev": true, "hasInstallScript": true, - "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -12946,7 +12801,6 @@ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -13114,8 +12968,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/fastq": { "version": "1.17.1", @@ -13132,7 +12985,6 @@ "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", "dev": true, - "license": "Apache-2.0", "dependencies": { "websocket-driver": ">=0.5.1" }, @@ -13423,7 +13275,6 @@ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -14082,8 +13933,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/handlebars": { "version": "4.7.8", @@ -14345,7 +14195,6 @@ "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", "dev": true, - "license": "MIT", "dependencies": { "inherits": "^2.0.1", "obuf": "^1.0.0", @@ -14357,15 +14206,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/hpack.js/node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, - "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -14380,15 +14227,13 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/hpack.js/node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" } @@ -14407,8 +14252,7 @@ "type": "patreon", "url": "https://patreon.com/mdevils" } - ], - "license": "MIT" + ] }, "node_modules/html-escaper": { "version": "2.0.2", @@ -14429,7 +14273,6 @@ "url": "https://github.com/sponsors/fb55" } ], - "license": "MIT", "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", @@ -14448,8 +14291,7 @@ "version": "1.2.7", "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/http-errors": { "version": "2.0.0", @@ -14482,8 +14324,7 @@ "version": "0.5.8", "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/http-proxy": { "version": "1.18.1", @@ -14577,7 +14418,6 @@ "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", "dev": true, - "license": "MIT", "engines": { "node": ">=10.18" } @@ -14920,7 +14760,6 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 10" } @@ -15058,7 +14897,6 @@ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", "dev": true, - "license": "MIT", "bin": { "is-docker": "cli.js" }, @@ -15107,7 +14945,6 @@ "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", "dev": true, - "license": "MIT", "dependencies": { "is-docker": "^3.0.0" }, @@ -15155,7 +14992,6 @@ "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz", "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==", "dev": true, - "license": "MIT", "engines": { "node": ">=16" }, @@ -15422,7 +15258,6 @@ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", "dev": true, - "license": "MIT", "dependencies": { "is-inside-container": "^1.0.0" }, @@ -16388,11 +16223,10 @@ } }, "node_modules/launch-editor": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.8.1.tgz", - "integrity": "sha512-elBx2l/tp9z99X5H/qev8uyDywVh0VXAwEbjk8kJhnc5grOFkGh7aW6q55me9xnYbss261XtnUrysZ+XvGbhQA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.9.1.tgz", + "integrity": "sha512-Gcnl4Bd+hRO9P9icCP/RVVT2o8SFlPXofuCxvA2SaZuH45whSvf5p8x5oih5ftLiVhEI4sp5xDY+R+b3zJBh5w==", "dev": true, - "license": "MIT", "dependencies": { "picocolors": "^1.0.0", "shell-quote": "^1.8.1" @@ -16708,7 +16542,6 @@ "integrity": "sha512-UGe+BbaSUQtAMZobTb4nHvFMrmvuAQKSeaqAX2meTEQjfsbpl5sxdHD8T72OnwD4GU9uwNhYXIVe4QGs8N9Zyw==", "dev": true, "hasInstallScript": true, - "license": "MIT", "dependencies": { "msgpackr": "^1.10.2", "node-addon-api": "^6.1.0", @@ -16732,8 +16565,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/load-json-file": { "version": "4.0.0", @@ -17275,7 +17107,6 @@ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", "dev": true, - "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } @@ -17351,11 +17182,10 @@ } }, "node_modules/memfs": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.11.1.tgz", - "integrity": "sha512-LZcMTBAgqUUKNXZagcZxvXXfgF1bHX7Y7nQ0QyEiNbRJgE29GhgPd8Yna1VQcLlPiHt/5RFJMWYN9Uv/VPNvjQ==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.12.0.tgz", + "integrity": "sha512-74wDsex5tQDSClVkeK1vtxqYCAgCoXxx+K4NSHzgU/muYVYByFqa+0RnrPO9NM6naWm1+G9JmZ0p6QHhXmeYfA==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@jsonjoy.com/json-pack": "^1.0.3", "@jsonjoy.com/util": "^1.3.0", @@ -17740,8 +17570,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/minimatch": { "version": "9.0.5", @@ -18003,7 +17832,6 @@ "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" } @@ -18020,7 +17848,6 @@ "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.0.tgz", "integrity": "sha512-I8qXuuALqJe5laEBYoFykChhSXLikZmUhccjGsPuSJ/7uPip2TJ7lwdIQwWSAi0jGZDXv4WOP8Qg65QZRuXxXw==", "dev": true, - "license": "MIT", "optionalDependencies": { "msgpackr-extract": "^3.0.2" } @@ -18031,7 +17858,6 @@ "integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==", "dev": true, "hasInstallScript": true, - "license": "MIT", "optional": true, "dependencies": { "node-gyp-build-optional-packages": "5.2.2" @@ -18053,7 +17879,6 @@ "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", "dev": true, - "license": "MIT", "dependencies": { "dns-packet": "^5.2.2", "thunky": "^1.0.2" @@ -18257,7 +18082,6 @@ "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", "dev": true, "hasInstallScript": true, - "license": "MIT", "optional": true, "os": [ "!win32" @@ -18285,7 +18109,6 @@ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", "dev": true, - "license": "MIT", "optional": true }, "node_modules/node-fetch": { @@ -18314,7 +18137,6 @@ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", "dev": true, - "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { "node": ">= 6.13.0" } @@ -18349,7 +18171,6 @@ "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.2.tgz", "integrity": "sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==", "dev": true, - "license": "MIT", "optional": true, "bin": { "node-gyp-build": "bin.js", @@ -18362,7 +18183,6 @@ "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==", "dev": true, - "license": "MIT", "dependencies": { "detect-libc": "^2.0.1" }, @@ -18914,8 +18734,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/on-finished": { "version": "2.4.1", @@ -18935,7 +18754,6 @@ "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -18970,7 +18788,6 @@ "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", "dev": true, - "license": "MIT", "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", @@ -19099,8 +18916,7 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.5.1.tgz", "integrity": "sha512-5VyHfHY3cd0iza71JepYG50My+YUbrFtGoUz2ooEydPyPM7Aai/JW098juLr+RG6+rDJuzNNTsEQu2DZa1A41A==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/os-name": { "version": "4.0.1", @@ -19182,7 +18998,6 @@ "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.0.tgz", "integrity": "sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA==", "dev": true, - "license": "MIT", "dependencies": { "@types/retry": "0.12.2", "is-network-error": "^1.0.0", @@ -19200,7 +19015,6 @@ "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 4" } @@ -19376,7 +19190,6 @@ "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-7.0.0.tgz", "integrity": "sha512-mazCyGWkmCRWDI15Zp+UiCqMp/0dgEmkZRvhlsqqKYr4SsVm/TvnSpD9fCvqCA2zoWJcfRym846ejWBBHRiYEg==", "dev": true, - "license": "MIT", "dependencies": { "entities": "^4.3.0", "parse5": "^7.0.0", @@ -19391,7 +19204,6 @@ "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-7.0.0.tgz", "integrity": "sha512-5A+v2SNsq8T6/mG3ahcz8ZtQ0OUFTatxPbeidoMB7tkJSGDY3tdfl4MHovtLQHkEn5CGxijNWRQHhRQ6IRpXKg==", "dev": true, - "license": "MIT", "dependencies": { "parse5": "^7.0.0" }, @@ -19508,11 +19320,10 @@ "license": "MIT" }, "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", - "dev": true, - "license": "ISC" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", + "dev": true }, "node_modules/picomatch": { "version": "4.0.2", @@ -19565,7 +19376,6 @@ "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.6.1.tgz", "integrity": "sha512-z30AwWGtQE+Apr+2WBZensP2lIvwoaMcOPkQlIEmSGMJNUvaYACylPYrQM6wSdUNJlnDVMSpLv7xTMJqlVshOA==", "dev": true, - "license": "MIT", "optionalDependencies": { "nice-napi": "^1.0.2" } @@ -19774,8 +19584,7 @@ "version": "0.2.3", "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/postcss-modules-extract-imports": { "version": "3.1.0", @@ -20277,7 +20086,6 @@ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "dev": true, - "license": "MIT", "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -20291,7 +20099,6 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.10" } @@ -21306,11 +21113,10 @@ "license": "Unlicense" }, "node_modules/rollup": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.21.2.tgz", - "integrity": "sha512-e3TapAgYf9xjdLvKQCkQTnbTKd4a6jwlpQSJJFokHGaX2IVjoEqkIIhiQfqsi0cdwlOD+tQGuOd5AJkc5RngBw==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.0.tgz", + "integrity": "sha512-W21MUIFPZ4+O2Je/EU+GP3iz7PH4pVPUXSbEZdatQnxo29+3rsUjgrJmzuAZU24z7yRAnFN6ukxeAhZh/c7hzg==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree": "1.0.5" }, @@ -21322,22 +21128,22 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.21.2", - "@rollup/rollup-android-arm64": "4.21.2", - "@rollup/rollup-darwin-arm64": "4.21.2", - "@rollup/rollup-darwin-x64": "4.21.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.21.2", - "@rollup/rollup-linux-arm-musleabihf": "4.21.2", - "@rollup/rollup-linux-arm64-gnu": "4.21.2", - "@rollup/rollup-linux-arm64-musl": "4.21.2", - "@rollup/rollup-linux-powerpc64le-gnu": "4.21.2", - "@rollup/rollup-linux-riscv64-gnu": "4.21.2", - "@rollup/rollup-linux-s390x-gnu": "4.21.2", - "@rollup/rollup-linux-x64-gnu": "4.21.2", - "@rollup/rollup-linux-x64-musl": "4.21.2", - "@rollup/rollup-win32-arm64-msvc": "4.21.2", - "@rollup/rollup-win32-ia32-msvc": "4.21.2", - "@rollup/rollup-win32-x64-msvc": "4.21.2", + "@rollup/rollup-android-arm-eabi": "4.22.0", + "@rollup/rollup-android-arm64": "4.22.0", + "@rollup/rollup-darwin-arm64": "4.22.0", + "@rollup/rollup-darwin-x64": "4.22.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.22.0", + "@rollup/rollup-linux-arm-musleabihf": "4.22.0", + "@rollup/rollup-linux-arm64-gnu": "4.22.0", + "@rollup/rollup-linux-arm64-musl": "4.22.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.22.0", + "@rollup/rollup-linux-riscv64-gnu": "4.22.0", + "@rollup/rollup-linux-s390x-gnu": "4.22.0", + "@rollup/rollup-linux-x64-gnu": "4.22.0", + "@rollup/rollup-linux-x64-musl": "4.22.0", + "@rollup/rollup-win32-arm64-msvc": "4.22.0", + "@rollup/rollup-win32-ia32-msvc": "4.22.0", + "@rollup/rollup-win32-x64-msvc": "4.22.0", "fsevents": "~2.3.2" } }, @@ -21356,7 +21162,6 @@ "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" }, @@ -21642,8 +21447,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/selenium-webdriver": { "version": "3.6.0", @@ -21717,7 +21521,6 @@ "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", "dev": true, - "license": "MIT", "dependencies": { "@types/node-forge": "^1.3.0", "node-forge": "^1" @@ -21820,7 +21623,6 @@ "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", "dev": true, - "license": "MIT", "dependencies": { "accepts": "~1.3.4", "batch": "0.6.1", @@ -21839,7 +21641,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -21849,7 +21650,6 @@ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -21859,7 +21659,6 @@ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", "dev": true, - "license": "MIT", "dependencies": { "depd": "~1.1.2", "inherits": "2.0.3", @@ -21874,22 +21673,19 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/serve-index/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/serve-index/node_modules/setprototypeof": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/serve-static": { "version": "1.16.2", @@ -22042,7 +21838,6 @@ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", "dev": true, - "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -22347,7 +22142,6 @@ "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", "dev": true, - "license": "MIT", "dependencies": { "faye-websocket": "^0.11.3", "uuid": "^8.3.2", @@ -22359,7 +22153,6 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true, - "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } @@ -22405,11 +22198,10 @@ } }, "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, - "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -22515,7 +22307,6 @@ "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", "dev": true, - "license": "MIT", "dependencies": { "debug": "^4.1.0", "handle-thing": "^2.0.0", @@ -22532,7 +22323,6 @@ "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", "dev": true, - "license": "MIT", "dependencies": { "debug": "^4.1.0", "detect-node": "^2.0.4", @@ -23335,7 +23125,6 @@ "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", "integrity": "sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==", "dev": true, - "license": "Unlicense", "engines": { "node": ">=10.18" }, @@ -23364,8 +23153,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/tmp": { "version": "0.2.3", @@ -23456,7 +23244,6 @@ "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.2.tgz", "integrity": "sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=10.0" }, @@ -24237,15 +24024,14 @@ } }, "node_modules/vite": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.0.tgz", - "integrity": "sha512-5xokfMX0PIiwCMCMb9ZJcMyh5wbBun0zUzKib+L65vAZ8GY9ePZMXxFrHbr/Kyll2+LSCY7xtERPpxkBDKngwg==", + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.6.tgz", + "integrity": "sha512-IeL5f8OO5nylsgzd9tq4qD2QqI0k2CQLGrWD0rCN0EQJZpBK5vJAx0I+GDkMOXxQX/OfFHMuLIx6ddAxGX/k+Q==", "dev": true, - "license": "MIT", "dependencies": { "esbuild": "^0.21.3", - "postcss": "^8.4.40", - "rollup": "^4.13.0" + "postcss": "^8.4.43", + "rollup": "^4.20.0" }, "bin": { "vite": "bin/vite.js" @@ -24304,7 +24090,6 @@ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "aix" @@ -24321,7 +24106,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -24338,7 +24122,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -24355,7 +24138,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -24372,7 +24154,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -24389,7 +24170,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -24406,7 +24186,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -24423,7 +24202,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -24440,7 +24218,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -24457,7 +24234,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -24474,7 +24250,6 @@ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -24491,7 +24266,6 @@ "loong64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -24508,7 +24282,6 @@ "mips64el" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -24525,7 +24298,6 @@ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -24542,7 +24314,6 @@ "riscv64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -24559,7 +24330,6 @@ "s390x" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -24576,7 +24346,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -24593,7 +24362,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "netbsd" @@ -24610,7 +24378,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "openbsd" @@ -24627,7 +24394,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "sunos" @@ -24644,7 +24410,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -24661,7 +24426,6 @@ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -24678,7 +24442,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -24693,7 +24456,6 @@ "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, - "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -24726,6 +24488,34 @@ "@esbuild/win32-x64": "0.21.5" } }, + "node_modules/vite/node_modules/postcss": { + "version": "8.4.47", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", + "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.0", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, "node_modules/void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", @@ -24755,7 +24545,6 @@ "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", "dev": true, - "license": "MIT", "dependencies": { "minimalistic-assert": "^1.0.0" } @@ -24773,8 +24562,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz", "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/webdriver-js-extender": { "version": "2.1.0", @@ -25046,11 +24834,10 @@ } }, "node_modules/webpack-dev-middleware": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.3.0.tgz", - "integrity": "sha512-xD2qnNew+F6KwOGZR7kWdbIou/ud7cVqLEXeK1q0nHcNsX/u7ul/fSdlOTX4ntSL5FNFy7ZJJXbf0piF591JYw==", + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.4.2.tgz", + "integrity": "sha512-xOO8n6eggxnwYpy1NlzUKpvrjfJTvae5/D6WOK0S2LSo7vjmo5gCM1DbLUmFqrMTJP+W/0YZNctm7jasWvLuBA==", "dev": true, - "license": "MIT", "dependencies": { "colorette": "^2.0.10", "memfs": "^4.6.0", @@ -25080,7 +24867,6 @@ "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.0.4.tgz", "integrity": "sha512-dljXhUgx3HqKP2d8J/fUMvhxGhzjeNVarDLcbO/EWMSgRizDkxHQDZQaLFL5VJY9tRBj2Gz+rvCEYYvhbqPHNA==", "dev": true, - "license": "MIT", "dependencies": { "@types/bonjour": "^3.5.13", "@types/connect-history-api-fallback": "^1.5.4", @@ -25140,7 +24926,6 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, - "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", @@ -25161,7 +24946,6 @@ "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", "dev": true, - "license": "MIT", "dependencies": { "@types/http-proxy": "^1.17.8", "http-proxy": "^1.18.1", @@ -25186,7 +24970,6 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", "dev": true, - "license": "ISC", "dependencies": { "glob": "^10.3.7" }, @@ -25333,7 +25116,6 @@ "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", "dev": true, - "license": "Apache-2.0", "dependencies": { "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", @@ -25348,7 +25130,6 @@ "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=0.8.0" } diff --git a/ui/package.json b/ui/package.json index 54462d2b155..36600afc57b 100644 --- a/ui/package.json +++ b/ui/package.json @@ -52,7 +52,7 @@ "zone.js": "~0.14.7" }, "devDependencies": { - "@angular-devkit/build-angular": "^18.0.5", + "@angular-devkit/build-angular": "^18.2.5", "@angular-devkit/core": "18.0.5", "@angular-devkit/schematics": "18.0.5", "@angular-eslint/builder": "^18.1.0", From 6261b09333141c1a53aede44d4085e1be43efe2a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 16:27:47 +0200 Subject: [PATCH 147/173] Build(deps-dev): Bump the eslint group across 1 directory with 3 updates (#2812) Bumps the eslint group with 3 updates in the /ui directory: [@stylistic/eslint-plugin](https://github.com/eslint-stylistic/eslint-stylistic/tree/HEAD/packages/eslint-plugin), [@typescript-eslint/types](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/types) and [eslint-plugin-unused-imports](https://github.com/sweepline/eslint-plugin-unused-imports). Updates `@stylistic/eslint-plugin` from 2.7.2 to 2.8.0 - [Release notes](https://github.com/eslint-stylistic/eslint-stylistic/releases) - [Changelog](https://github.com/eslint-stylistic/eslint-stylistic/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint-stylistic/eslint-stylistic/commits/v2.8.0/packages/eslint-plugin) Updates `@typescript-eslint/types` from 7.18.0 to 8.7.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/types/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.7.0/packages/types) Updates `eslint-plugin-unused-imports` from 4.1.3 to 4.1.4 - [Commits](https://github.com/sweepline/eslint-plugin-unused-imports/compare/v4.1.3...v4.1.4) --- updated-dependencies: - dependency-name: "@stylistic/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: eslint - dependency-name: "@typescript-eslint/types" dependency-type: direct:development update-type: version-update:semver-major dependency-group: eslint - dependency-name: eslint-plugin-unused-imports dependency-type: direct:development update-type: version-update:semver-patch dependency-group: eslint ... 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 | 180 +++++++++++++++++++++++++++---------------- ui/package.json | 6 +- 2 files changed, 115 insertions(+), 71 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 0241d54a2c3..3fe21c36406 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -72,7 +72,7 @@ "@capacitor/cli": "6.1.2", "@ionic/angular-toolkit": "^11.0.1", "@ionic/cli": "^7.2.0", - "@stylistic/eslint-plugin": "^2.7.2", + "@stylistic/eslint-plugin": "^2.8.0", "@types/jasmine": "~4.3.6", "@types/jasminewd2": "~2.0.13", "@types/json-schema": "^7.0.15", @@ -83,12 +83,12 @@ "@types/uuid": "^10.0.0", "@typescript-eslint/eslint-plugin": "^7.0.0", "@typescript-eslint/parser": "^7.0.0", - "@typescript-eslint/types": "^7.0.0", + "@typescript-eslint/types": "^8.7.0", "eslint": "^8.57.0", "eslint-plugin-import": "2.29.1", "eslint-plugin-jsdoc": "48.10.0", "eslint-plugin-prefer-arrow": "1.2.3", - "eslint-plugin-unused-imports": "^4.1.3", + "eslint-plugin-unused-imports": "^4.1.4", "jasmine-core": "~4.5.0", "jasmine-spec-reporter": "~7.0.0", "karma": "~6.4.2", @@ -6834,14 +6834,12 @@ } }, "node_modules/@stylistic/eslint-plugin": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.7.2.tgz", - "integrity": "sha512-3DVLU5HEuk2pQoBmXJlzvrxbKNpu2mJ0SRqz5O/CJjyNCr12ZiPcYMEtuArTyPOk5i7bsAU44nywh1rGfe3gKQ==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.8.0.tgz", + "integrity": "sha512-Ufvk7hP+bf+pD35R/QfunF793XlSRIC7USr3/EdgduK9j13i2JjmsM0LUz3/foS+jDYp2fzyWZA9N44CPur0Ow==", "dev": true, - "license": "MIT", "dependencies": { - "@types/eslint": "^9.6.1", - "@typescript-eslint/utils": "^8.3.0", + "@typescript-eslint/utils": "^8.4.0", "eslint-visitor-keys": "^4.0.0", "espree": "^10.1.0", "estraverse": "^5.3.0", @@ -7050,17 +7048,6 @@ "@types/node": "*" } }, - "node_modules/@types/eslint": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", - "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, "node_modules/@types/estree": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", @@ -7337,6 +7324,19 @@ } } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { "version": "7.18.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", @@ -7389,6 +7389,19 @@ } } }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/scope-manager": { "version": "7.18.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", @@ -7407,6 +7420,19 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/scope-manager/node_modules/@typescript-eslint/types": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/type-utils": { "version": "7.18.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", @@ -7435,6 +7461,19 @@ } } }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { "version": "7.18.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", @@ -7459,13 +7498,12 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", - "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.7.0.tgz", + "integrity": "sha512-LLt4BLHFwSfASHSF2K29SZ+ZCsbQOM+LuarPjRUuHm+Qd09hSe3GCeaQbcCr+Mik+0QFRmep/FyZBO6fJ64U3w==", "dev": true, - "license": "MIT", "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -7501,38 +7539,29 @@ } } }, - "node_modules/@typescript-eslint/utils": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.3.0.tgz", - "integrity": "sha512-F77WwqxIi/qGkIGOGXNBLV7nykwfjLsdauRB/DOFPdv6LTF3BHHkBpq81/b5iMPSF055oO2BiivDJV4ChvNtXA==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/types": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.3.0", - "@typescript-eslint/types": "8.3.0", - "@typescript-eslint/typescript-estree": "8.3.0" - }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.3.0.tgz", - "integrity": "sha512-mz2X8WcN2nVu5Hodku+IR8GgCOl4C0G/Z1ruaWN4dgec64kDBabuXyPAr+/RgJtumv8EEkqIzf3X2U5DUKB2eg==", + "node_modules/@typescript-eslint/utils": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.7.0.tgz", + "integrity": "sha512-ZbdUdwsl2X/s3CiyAu3gOlfQzpbuG3nTWKPoIvAu1pu5r8viiJvv2NPN2AqArL35NCYtw/lrPPfM4gxrMLNLPw==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.3.0", - "@typescript-eslint/visitor-keys": "8.3.0" + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.7.0", + "@typescript-eslint/types": "8.7.0", + "@typescript-eslint/typescript-estree": "8.7.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7540,14 +7569,20 @@ "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.3.0.tgz", - "integrity": "sha512-y6sSEeK+facMaAyixM36dQ5NVXTnKWunfD1Ft4xraYqxP0lC0POJmIaL/mw72CUMqjY9qfyVfXafMeaUj0noWw==", + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.7.0.tgz", + "integrity": "sha512-87rC0k3ZlDOuz82zzXRtQ7Akv3GKhHs0ti4YcbAJtaomllXoSO8hi7Ix3ccEvCd824dy9aIX+j3d2UMAfCtVpg==", "dev": true, - "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.7.0", + "@typescript-eslint/visitor-keys": "8.7.0" + }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -7557,14 +7592,13 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.3.0.tgz", - "integrity": "sha512-Mq7FTHl0R36EmWlCJWojIC1qn/ZWo2YiWYc1XVtasJ7FIgjo0MVv9rZWXEE7IK2CGrtwe1dVOxWwqXUdNgfRCA==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.7.0.tgz", + "integrity": "sha512-MC8nmcGHsmfAKxwnluTQpNqceniT8SteVwd2voYlmiSWGOtjvGXdPl17dYu2797GVscK30Z04WRM28CrKS9WOg==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "8.3.0", - "@typescript-eslint/visitor-keys": "8.3.0", + "@typescript-eslint/types": "8.7.0", + "@typescript-eslint/visitor-keys": "8.7.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -7586,13 +7620,12 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.3.0.tgz", - "integrity": "sha512-RmZwrTbQ9QveF15m/Cl28n0LXD6ea2CjkhH5rQ55ewz3H24w+AMCJHPVYaZ8/0HoG8Z3cLLFFycRXxeO2tz9FA==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.7.0.tgz", + "integrity": "sha512-b1tx0orFCCh/THWPQa2ZwWzvOeyzzp36vkJYOpVg0u8UVOIsfVrnuC9FqAw9gRKn+rG2VmWQ/zDJZzkxUnj/XQ==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.3.0", + "@typescript-eslint/types": "8.7.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -7608,7 +7641,6 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -7634,6 +7666,19 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/@typescript-eslint/types": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", @@ -12321,11 +12366,10 @@ } }, "node_modules/eslint-plugin-unused-imports": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.1.3.tgz", - "integrity": "sha512-lqrNZIZjFMUr7P06eoKtQLwyVRibvG7N+LtfKtObYGizAAGrcqLkc3tDx+iAik2z7q0j/XI3ihjupIqxhFabFA==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.1.4.tgz", + "integrity": "sha512-YptD6IzQjDardkl0POxnnRBhU1OEePMV0nd6siHaRBbd+lyh6NAhFEobiznKU7kTsSsDeSD62Pe7kAM1b7dAZQ==", "dev": true, - "license": "MIT", "peerDependencies": { "@typescript-eslint/eslint-plugin": "^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0", "eslint": "^9.0.0 || ^8.0.0" diff --git a/ui/package.json b/ui/package.json index 36600afc57b..62d980810ac 100644 --- a/ui/package.json +++ b/ui/package.json @@ -67,7 +67,7 @@ "@capacitor/cli": "6.1.2", "@ionic/angular-toolkit": "^11.0.1", "@ionic/cli": "^7.2.0", - "@stylistic/eslint-plugin": "^2.7.2", + "@stylistic/eslint-plugin": "^2.8.0", "@types/jasmine": "~4.3.6", "@types/jasminewd2": "~2.0.13", "@types/json-schema": "^7.0.15", @@ -78,12 +78,12 @@ "@types/uuid": "^10.0.0", "@typescript-eslint/eslint-plugin": "^7.0.0", "@typescript-eslint/parser": "^7.0.0", - "@typescript-eslint/types": "^7.0.0", + "@typescript-eslint/types": "^8.7.0", "eslint": "^8.57.0", "eslint-plugin-import": "2.29.1", "eslint-plugin-jsdoc": "48.10.0", "eslint-plugin-prefer-arrow": "1.2.3", - "eslint-plugin-unused-imports": "^4.1.3", + "eslint-plugin-unused-imports": "^4.1.4", "jasmine-core": "~4.5.0", "jasmine-spec-reporter": "~7.0.0", "karma": "~6.4.2", From 4ae1012da6894dcacf215f357f55a0671308d539 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 17:06:24 +0200 Subject: [PATCH 148/173] Build(deps): Bump @angular/common from 18.0.5 to 18.2.5 in /ui in the angular group across 1 directory (#2811) * Build(deps): Bump @angular/common Bumps the angular group with 1 update in the /ui directory: [@angular/common](https://github.com/angular/angular/tree/HEAD/packages/common). Updates `@angular/common` from 18.0.5 to 18.2.5 - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/18.2.5/packages/common) --- updated-dependencies: - dependency-name: "@angular/common" dependency-type: direct:production update-type: version-update:semver-minor dependency-group: angular ... Signed-off-by: dependabot[bot] * Build(deps-dev): Bump @angular-devkit/core from 18.0.5 to 18.2.5 in /ui Bumps [@angular-devkit/core](https://github.com/angular/angular-cli) from 18.0.5 to 18.2.5. - [Release notes](https://github.com/angular/angular-cli/releases) - [Changelog](https://github.com/angular/angular-cli/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular-cli/compare/18.0.5...18.2.5) --- updated-dependencies: - dependency-name: "@angular-devkit/core" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Build(deps-dev): Bump @angular-devkit/schematics in /ui Bumps [@angular-devkit/schematics](https://github.com/angular/angular-cli) from 18.0.5 to 18.2.5. - [Release notes](https://github.com/angular/angular-cli/releases) - [Changelog](https://github.com/angular/angular-cli/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular-cli/compare/18.0.5...18.2.5) --- updated-dependencies: - dependency-name: "@angular-devkit/schematics" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- .github/dependabot.yml | 3 +- ui/package-lock.json | 1909 +++++++---------- ui/package.json | 64 +- .../app/shared/components/edge/edgeconfig.ts | 2 +- ui/src/app/shared/service/defaulttypes.ts | 2 +- 5 files changed, 871 insertions(+), 1109 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 37fcbfbbc53..fe2414bdf30 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -25,6 +25,8 @@ updates: angular: patterns: - "@angular/*" + - "@angular-devkit/*" + - "@angular-eslint/*" capacitor: patterns: - "@capacitor/*" @@ -40,7 +42,6 @@ updates: - "karma" eslint: patterns: - - "@angular-eslint/*" - "@stylistic/eslint-plugin" - "@typescript-eslint/*" - "eslint-*" diff --git a/ui/package-lock.json b/ui/package-lock.json index 3fe21c36406..f0ac38c3c72 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -9,27 +9,27 @@ "version": "2024.10.0-SNAPSHOT", "license": "AGPL-3.0", "dependencies": { - "@angular/animations": "18.0.5", - "@angular/common": "18.0.5", - "@angular/core": "18.0.5", - "@angular/forms": "18.0.5", - "@angular/platform-browser": "18.0.5", - "@angular/platform-browser-dynamic": "18.0.5", - "@angular/router": "18.0.5", - "@angular/service-worker": "18.0.5", + "@angular/animations": "18.2.5", + "@angular/common": "18.2.5", + "@angular/core": "18.2.5", + "@angular/forms": "18.2.5", + "@angular/platform-browser": "18.2.5", + "@angular/platform-browser-dynamic": "18.2.5", + "@angular/router": "18.2.5", + "@angular/service-worker": "18.2.5", "@capacitor-community/file-opener": "^6.0.1", - "@capacitor/android": "^6.0.0", - "@capacitor/app": "^6.0.0", - "@capacitor/core": "^6.0.0", - "@capacitor/filesystem": "^6.0.0", - "@capacitor/ios": "^6.0.0", - "@capacitor/splash-screen": "^6.0.0", + "@capacitor/android": "^6.1.2", + "@capacitor/app": "^6.0.1", + "@capacitor/core": "^6.1.2", + "@capacitor/filesystem": "^6.0.1", + "@capacitor/ios": "^6.1.2", + "@capacitor/splash-screen": "^6.0.2", "@ionic-native/core": "^5.36.0", "@ionic-native/file-opener": "^5.36.0", "@ionic/angular": "^6.7.5", - "@ngx-formly/core": "^6.3.0", - "@ngx-formly/ionic": "^6.3.6", - "@ngx-formly/schematics": "^6.3.0", + "@ngx-formly/core": "^6.3.7", + "@ngx-formly/ionic": "^6.3.7", + "@ngx-formly/schematics": "^6.3.7", "@ngx-translate/core": "^15.0.0", "@nodro7/angular-mydatepicker": "^0.14.0", "capacitor-blob-writer": "^1.1.17", @@ -58,16 +58,16 @@ }, "devDependencies": { "@angular-devkit/build-angular": "^18.2.5", - "@angular-devkit/core": "18.0.5", - "@angular-devkit/schematics": "18.0.5", - "@angular-eslint/builder": "^18.1.0", - "@angular-eslint/eslint-plugin": "^18.1.0", - "@angular-eslint/eslint-plugin-template": "^18.1.0", - "@angular-eslint/template-parser": "^18.1.0", - "@angular/cli": "18.1.0", - "@angular/compiler": "18.0.5", - "@angular/compiler-cli": "18.0.5", - "@angular/language-service": "18.0.5", + "@angular-devkit/core": "18.2.5", + "@angular-devkit/schematics": "18.2.5", + "@angular-eslint/builder": "^18.3.1", + "@angular-eslint/eslint-plugin": "^18.3.1", + "@angular-eslint/eslint-plugin-template": "^18.3.1", + "@angular-eslint/template-parser": "^18.3.1", + "@angular/cli": "18.2.5", + "@angular/compiler": "18.2.5", + "@angular/compiler-cli": "18.2.5", + "@angular/language-service": "18.2.5", "@capacitor/assets": "^3.0.5", "@capacitor/cli": "6.1.2", "@ionic/angular-toolkit": "^11.0.1", @@ -77,7 +77,7 @@ "@types/jasminewd2": "~2.0.13", "@types/json-schema": "^7.0.15", "@types/node": "^20.12.6", - "@types/qs": "^6.9.15", + "@types/qs": "^6.9.16", "@types/range-parser": "^1.2.7", "@types/send": "^0.17.4", "@types/uuid": "^10.0.0", @@ -85,13 +85,13 @@ "@typescript-eslint/parser": "^7.0.0", "@typescript-eslint/types": "^8.7.0", "eslint": "^8.57.0", - "eslint-plugin-import": "2.29.1", - "eslint-plugin-jsdoc": "48.10.0", + "eslint-plugin-import": "2.30.0", + "eslint-plugin-jsdoc": "50.2.4", "eslint-plugin-prefer-arrow": "1.2.3", "eslint-plugin-unused-imports": "^4.1.4", - "jasmine-core": "~4.5.0", + "jasmine-core": "~5.3.0", "jasmine-spec-reporter": "~7.0.0", - "karma": "~6.4.2", + "karma": "~6.4.4", "karma-chrome-launcher": "~3.2.0", "karma-coverage": "~2.2.1", "karma-coverage-istanbul-reporter": "~3.0.3", @@ -132,49 +132,6 @@ "yarn": ">= 1.13.0" } }, - "node_modules/@angular-devkit/architect/node_modules/@angular-devkit/core": { - "version": "18.2.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.5.tgz", - "integrity": "sha512-r9TumPlJ8PvA2+yz4sp+bUHgtznaVKzhvXTN5qL1k4YP8LJ7iZWMR2FOP+HjukHZOTsenzmV9pszbogabqwoZQ==", - "dev": true, - "dependencies": { - "ajv": "8.17.1", - "ajv-formats": "3.0.1", - "jsonc-parser": "3.3.1", - "picomatch": "4.0.2", - "rxjs": "7.8.1", - "source-map": "0.7.4" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^3.5.2" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/@angular-devkit/architect/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/@angular-devkit/architect/node_modules/rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", @@ -312,7 +269,50 @@ } } }, - "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core": { + "node_modules/@angular-devkit/build-angular/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, + "node_modules/@angular-devkit/build-webpack": { + "version": "0.1802.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1802.5.tgz", + "integrity": "sha512-6qkcrWBdkxojCVHGWcdJaz4G+7QTjFvmc+3g8xvLc9sYvJq1I059gfXhDnC0FxiA0MT4cY/26ECYWUHTD5CJLQ==", + "dev": true, + "dependencies": { + "@angular-devkit/architect": "0.1802.5", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "webpack": "^5.30.0", + "webpack-dev-server": "^5.0.2" + } + }, + "node_modules/@angular-devkit/build-webpack/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@angular-devkit/core": { "version": "18.2.5", "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.5.tgz", "integrity": "sha512-r9TumPlJ8PvA2+yz4sp+bUHgtznaVKzhvXTN5qL1k4YP8LJ7iZWMR2FOP+HjukHZOTsenzmV9pszbogabqwoZQ==", @@ -339,11 +339,147 @@ } } }, - "node_modules/@angular-devkit/build-angular/node_modules/@angular/build": { + "node_modules/@angular-devkit/core/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@angular-devkit/schematics": { + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.2.5.tgz", + "integrity": "sha512-NUmz2UQ1Xl4cf4j1AgkwIfsCjBzAPgfeC3IBrD29hSOBE1Y3j6auqjBkvw50v6mbSPxESND995Xy13HpK1Xflw==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "18.2.5", + "jsonc-parser": "3.3.1", + "magic-string": "0.30.11", + "ora": "5.4.1", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/schematics/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@angular-eslint/builder": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-18.3.1.tgz", + "integrity": "sha512-cPc7Ye9zDs5M4i+feL6vob+mh7yX5vxvOS5KQIhneUrp5e9D+IGuNFMmBLlOPpmklSc9XJBtuvI5Zjuh4z1ETw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" + } + }, + "node_modules/@angular-eslint/bundled-angular-compiler": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-18.3.1.tgz", + "integrity": "sha512-sikmkjfsXPpPTku1aQkQ1MNNEKGBgGGRvUN/WeNS9dhCJ4dxU3O7dZctt1aQWj+W3nbuUtDiimAWF5fZHGFE2Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@angular-eslint/eslint-plugin": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-18.3.1.tgz", + "integrity": "sha512-MP4Nm+SHboF8KdnN0KpPEGAaTTzDLPm3+S/4W3Mg8onqWCyadyd4mActh9mK/pvCj8TVlb/SW1zeTtdMYhwonw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-eslint/bundled-angular-compiler": "18.3.1", + "@angular-eslint/utils": "18.3.1" + }, + "peerDependencies": { + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" + } + }, + "node_modules/@angular-eslint/eslint-plugin-template": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-18.3.1.tgz", + "integrity": "sha512-hBJ3+f7VSidvrtYaXH7Vp0sWvblA9jLK2c6uQzhYGWdEDUcTg7g7VI9ThW39WvMbHqkyzNE4PPOynK69cBEDGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-eslint/bundled-angular-compiler": "18.3.1", + "@angular-eslint/utils": "18.3.1", + "aria-query": "5.3.0", + "axobject-query": "4.1.0" + }, + "peerDependencies": { + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" + } + }, + "node_modules/@angular-eslint/template-parser": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-18.3.1.tgz", + "integrity": "sha512-JUUkfWH1G+u/Uk85ZYvJSt/qwN/Ko+jlXFtzBEcknJZsTWTwBcp36v77gPZe5FmKSziJZpyPUd+7Kiy6tuSCTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-eslint/bundled-angular-compiler": "18.3.1", + "eslint-scope": "^8.0.2" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" + } + }, + "node_modules/@angular-eslint/utils": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-18.3.1.tgz", + "integrity": "sha512-sd9niZI7h9H2FQ7OLiQsLFBhjhRQTASh+Q0+4+hyjv9idbSHBJli8Gsi2fqj9zhtMKpAZFTrWzuLUpubJ9UYbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-eslint/bundled-angular-compiler": "18.3.1" + }, + "peerDependencies": { + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" + } + }, + "node_modules/@angular/animations": { + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-18.2.5.tgz", + "integrity": "sha512-IlXtW/Nj48ZzjHUzH1TykZcSR64ScJx39T3IHnjV2z/bVATzZ36JGoadQHdqpJNKBodYJNgtJCGLCbgAvGWY2g==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + }, + "peerDependencies": { + "@angular/core": "18.2.5" + } + }, + "node_modules/@angular/build": { "version": "18.2.5", "resolved": "https://registry.npmjs.org/@angular/build/-/build-18.2.5.tgz", "integrity": "sha512-XWkmjzgeUga0SJ0lYSYcTuYOWTyqcln2mNfBp7Ae/GZ+/7+APbedsIZEiZGZwveOIyOpTM5wguNSoe9khDl5Ig==", "dev": true, + "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", "@angular-devkit/architect": "0.1802.5", @@ -407,7 +543,7 @@ } } }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-android-arm-eabi": { + "node_modules/@angular/build/node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.20.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.20.0.tgz", "integrity": "sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA==", @@ -415,12 +551,13 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ] }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-android-arm64": { + "node_modules/@angular/build/node_modules/@rollup/rollup-android-arm64": { "version": "4.20.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.20.0.tgz", "integrity": "sha512-u00Ro/nok7oGzVuh/FMYfNoGqxU5CPWz1mxV85S2w9LxHR8OoMQBuSk+3BKVIDYgkpeOET5yXkx90OYFc+ytpQ==", @@ -428,12 +565,13 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ] }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-darwin-arm64": { + "node_modules/@angular/build/node_modules/@rollup/rollup-darwin-arm64": { "version": "4.20.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.20.0.tgz", "integrity": "sha512-uFVfvzvsdGtlSLuL0ZlvPJvl6ZmrH4CBwLGEFPe7hUmf7htGAN+aXo43R/V6LATyxlKVC/m6UsLb7jbG+LG39Q==", @@ -441,12 +579,13 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-darwin-x64": { + "node_modules/@angular/build/node_modules/@rollup/rollup-darwin-x64": { "version": "4.20.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.20.0.tgz", "integrity": "sha512-xbrMDdlev53vNXexEa6l0LffojxhqDTBeL+VUxuuIXys4x6xyvbKq5XqTXBCEUA8ty8iEJblHvFaWRJTk/icAQ==", @@ -454,12 +593,13 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-arm-gnueabihf": { "version": "4.20.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.20.0.tgz", "integrity": "sha512-jMYvxZwGmoHFBTbr12Xc6wOdc2xA5tF5F2q6t7Rcfab68TT0n+r7dgawD4qhPEvasDsVpQi+MgDzj2faOLsZjA==", @@ -467,12 +607,13 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-arm-musleabihf": { + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-arm-musleabihf": { "version": "4.20.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.20.0.tgz", "integrity": "sha512-1asSTl4HKuIHIB1GcdFHNNZhxAYEdqML/MW4QmPS4G0ivbEcBr1JKlFLKsIRqjSwOBkdItn3/ZDlyvZ/N6KPlw==", @@ -480,12 +621,13 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-arm64-gnu": { + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-arm64-gnu": { "version": "4.20.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.20.0.tgz", "integrity": "sha512-COBb8Bkx56KldOYJfMf6wKeYJrtJ9vEgBRAOkfw6Ens0tnmzPqvlpjZiLgkhg6cA3DGzCmLmmd319pmHvKWWlQ==", @@ -493,12 +635,13 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-arm64-musl": { + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-arm64-musl": { "version": "4.20.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.20.0.tgz", "integrity": "sha512-+it+mBSyMslVQa8wSPvBx53fYuZK/oLTu5RJoXogjk6x7Q7sz1GNRsXWjn6SwyJm8E/oMjNVwPhmNdIjwP135Q==", @@ -506,12 +649,13 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-powerpc64le-gnu": { "version": "4.20.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.20.0.tgz", "integrity": "sha512-yAMvqhPfGKsAxHN8I4+jE0CpLWD8cv4z7CK7BMmhjDuz606Q2tFKkWRY8bHR9JQXYcoLfopo5TTqzxgPUjUMfw==", @@ -519,12 +663,13 @@ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-riscv64-gnu": { + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-riscv64-gnu": { "version": "4.20.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.20.0.tgz", "integrity": "sha512-qmuxFpfmi/2SUkAw95TtNq/w/I7Gpjurx609OOOV7U4vhvUhBcftcmXwl3rqAek+ADBwSjIC4IVNLiszoj3dPA==", @@ -532,12 +677,13 @@ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-s390x-gnu": { + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-s390x-gnu": { "version": "4.20.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.20.0.tgz", "integrity": "sha512-I0BtGXddHSHjV1mqTNkgUZLnS3WtsqebAXv11D5BZE/gfw5KoyXSAXVqyJximQXNvNzUo4GKlCK/dIwXlz+jlg==", @@ -545,12 +691,13 @@ "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-x64-gnu": { + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.20.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.20.0.tgz", "integrity": "sha512-y+eoL2I3iphUg9tN9GB6ku1FA8kOfmF4oUEWhztDJ4KXJy1agk/9+pejOuZkNFhRwHAOxMsBPLbXPd6mJiCwew==", @@ -558,445 +705,102 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.20.0.tgz", - "integrity": "sha512-hM3nhW40kBNYUkZb/r9k2FKK+/MnKglX7UYd4ZUy5DJs8/sMsIbqWK2piZtVGE3kcXVNj3B2IrUYROJMMCikNg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.20.0.tgz", - "integrity": "sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.20.0.tgz", - "integrity": "sha512-GabekH3w4lgAJpVxkk7hUzUf2hICSQO0a/BLFA11/RMxQT92MabKAqyubzDZmMOC/hcJNlc+rrypzNzYl4Dx7A==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.20.0.tgz", - "integrity": "sha512-aJ1EJSuTdGnM6qbVC4B5DSmozPTqIag9fSzXRNNo+humQLG89XpPgdt16Ia56ORD7s+H8Pmyx44uczDQ0yDzpg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@angular-devkit/build-angular/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/emoji-regex": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", - "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", - "dev": true - }, - "node_modules/@angular-devkit/build-angular/node_modules/eventemitter3": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "dev": true - }, - "node_modules/@angular-devkit/build-angular/node_modules/listr2": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.4.tgz", - "integrity": "sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g==", - "dev": true, - "dependencies": { - "cli-truncate": "^4.0.0", - "colorette": "^2.0.20", - "eventemitter3": "^5.0.1", - "log-update": "^6.1.0", - "rfdc": "^1.4.1", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/rollup": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.20.0.tgz", - "integrity": "sha512-6rbWBChcnSGzIlXeIdNIZTopKYad8ZG8ajhl78lGRLsI2rX8IkaotQhVas2Ma+GPxJav19wrSzvRvuiv0YKzWw==", - "dev": true, - "dependencies": { - "@types/estree": "1.0.5" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.20.0", - "@rollup/rollup-android-arm64": "4.20.0", - "@rollup/rollup-darwin-arm64": "4.20.0", - "@rollup/rollup-darwin-x64": "4.20.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.20.0", - "@rollup/rollup-linux-arm-musleabihf": "4.20.0", - "@rollup/rollup-linux-arm64-gnu": "4.20.0", - "@rollup/rollup-linux-arm64-musl": "4.20.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.20.0", - "@rollup/rollup-linux-riscv64-gnu": "4.20.0", - "@rollup/rollup-linux-s390x-gnu": "4.20.0", - "@rollup/rollup-linux-x64-gnu": "4.20.0", - "@rollup/rollup-linux-x64-musl": "4.20.0", - "@rollup/rollup-win32-arm64-msvc": "4.20.0", - "@rollup/rollup-win32-ia32-msvc": "4.20.0", - "@rollup/rollup-win32-x64-msvc": "4.20.0", - "fsevents": "~2.3.2" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", - "dev": true - }, - "node_modules/@angular-devkit/build-angular/node_modules/wrap-ansi": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", - "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/@angular-devkit/build-webpack": { - "version": "0.1802.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1802.5.tgz", - "integrity": "sha512-6qkcrWBdkxojCVHGWcdJaz4G+7QTjFvmc+3g8xvLc9sYvJq1I059gfXhDnC0FxiA0MT4cY/26ECYWUHTD5CJLQ==", - "dev": true, - "dependencies": { - "@angular-devkit/architect": "0.1802.5", - "rxjs": "7.8.1" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "webpack": "^5.30.0", - "webpack-dev-server": "^5.0.2" - } - }, - "node_modules/@angular-devkit/build-webpack/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/@angular-devkit/core": { - "version": "18.0.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.0.5.tgz", - "integrity": "sha512-sGtrS0SqkcBvyuv0QkIfyadwPgDhMroz1r51lMh1hwzJaJ0LNuVMLviEeYIybeBnvAdp9YvYC8I1WgB/FUEFBw==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "8.13.0", - "ajv-formats": "3.0.1", - "jsonc-parser": "3.2.1", - "picomatch": "4.0.2", - "rxjs": "7.8.1", - "source-map": "0.7.4" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^3.5.2" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/@angular-devkit/core/node_modules/jsonc-parser": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", - "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@angular-devkit/core/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/@angular-devkit/schematics": { - "version": "18.0.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.0.5.tgz", - "integrity": "sha512-hZwAq3hwuJzCuh7uqO/7T9IMERhYVxz+ganJlEykpyr58o0IjUM1Q4ZSH5UOYlGRPdBCZJbfiafZ0Sg5w5xBww==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-devkit/core": "18.0.5", - "jsonc-parser": "3.2.1", - "magic-string": "0.30.10", - "ora": "5.4.1", - "rxjs": "7.8.1" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@angular-devkit/schematics/node_modules/jsonc-parser": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", - "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@angular-devkit/schematics/node_modules/magic-string": { - "version": "0.30.10", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", - "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - } - }, - "node_modules/@angular-devkit/schematics/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/@angular-eslint/builder": { - "version": "18.3.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-18.3.0.tgz", - "integrity": "sha512-httEQyqyBw3+0CRtAa7muFxHrauRfkEfk/jmrh5fn2Eiu+I53hAqFPgrwVi1V6AP/kj2zbAiWhd5xM3pMJdoRQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": "*" - } - }, - "node_modules/@angular-eslint/bundled-angular-compiler": { - "version": "18.3.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-18.3.0.tgz", - "integrity": "sha512-v/59FxUKnMzymVce99gV43huxoqXWMb85aKvzlNvLN+ScDu6ZE4YMiTQNpfapVL2lkxhs0uwB3jH17EYd5TcsA==", + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.20.0.tgz", + "integrity": "sha512-hM3nhW40kBNYUkZb/r9k2FKK+/MnKglX7UYd4ZUy5DJs8/sMsIbqWK2piZtVGE3kcXVNj3B2IrUYROJMMCikNg==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@angular-eslint/eslint-plugin": { - "version": "18.3.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-18.3.0.tgz", - "integrity": "sha512-Vl7gfPMXxvtHTjYdlzR161aj5xrqW6T57wd8ToQ7Gqzm0qHGfY6kE4SQobUa2LCYckTNSlv+zXe48C4ah/dSjw==", + "node_modules/@angular/build/node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.20.0.tgz", + "integrity": "sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@angular-eslint/bundled-angular-compiler": "18.3.0", - "@angular-eslint/utils": "18.3.0" - }, - "peerDependencies": { - "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": "*" - } + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@angular-eslint/eslint-plugin-template": { - "version": "18.3.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-18.3.0.tgz", - "integrity": "sha512-ddR/qwYbUeq9IpyVKrPbfZyRBTy6V8uc5I0JcBKttQ4CZ4joXhqsVgWFsI+JAMi8E66uNj1VC7NuKCOjDINv2Q==", + "node_modules/@angular/build/node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.20.0.tgz", + "integrity": "sha512-GabekH3w4lgAJpVxkk7hUzUf2hICSQO0a/BLFA11/RMxQT92MabKAqyubzDZmMOC/hcJNlc+rrypzNzYl4Dx7A==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", - "dependencies": { - "@angular-eslint/bundled-angular-compiler": "18.3.0", - "@angular-eslint/utils": "18.3.0", - "aria-query": "5.3.0", - "axobject-query": "4.1.0" - }, - "peerDependencies": { - "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": "*" - } + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@angular-eslint/template-parser": { - "version": "18.3.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-18.3.0.tgz", - "integrity": "sha512-1mUquqcnugI4qsoxcYZKZ6WMi6RPelDcJZg2YqGyuaIuhWmi3ZqJZLErSSpjP60+TbYZu7wM8Kchqa1bwJtEaQ==", + "node_modules/@angular/build/node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.20.0.tgz", + "integrity": "sha512-aJ1EJSuTdGnM6qbVC4B5DSmozPTqIag9fSzXRNNo+humQLG89XpPgdt16Ia56ORD7s+H8Pmyx44uczDQ0yDzpg==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@angular-eslint/bundled-angular-compiler": "18.3.0", - "eslint-scope": "^8.0.2" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": "*" - } + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@angular-eslint/utils": { - "version": "18.3.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-18.3.0.tgz", - "integrity": "sha512-sCrkHkpxBJZLuCikdboZoawCfc2UgbJv+T14tu2uQCv+Vwzeadnu04vkeY2vTkA8GeBdBij/G9/N/nvwmwVw3g==", + "node_modules/@angular/build/node_modules/rollup": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.20.0.tgz", + "integrity": "sha512-6rbWBChcnSGzIlXeIdNIZTopKYad8ZG8ajhl78lGRLsI2rX8IkaotQhVas2Ma+GPxJav19wrSzvRvuiv0YKzWw==", "dev": true, "license": "MIT", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "18.3.0" + "@types/estree": "1.0.5" }, - "peerDependencies": { - "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": "*" - } - }, - "node_modules/@angular/animations": { - "version": "18.0.5", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-18.0.5.tgz", - "integrity": "sha512-RYwlS+4I33beAWdzFFmaDPqXZN+r66qPzzMOk9LQguwF76eBJbykHniODalSLvjrY6Iz7CULavByYNpzq2TT7A==", - "license": "MIT", - "dependencies": { - "tslib": "^2.3.0" + "bin": { + "rollup": "dist/bin/rollup" }, "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + "node": ">=18.0.0", + "npm": ">=8.0.0" }, - "peerDependencies": { - "@angular/core": "18.0.5" + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.20.0", + "@rollup/rollup-android-arm64": "4.20.0", + "@rollup/rollup-darwin-arm64": "4.20.0", + "@rollup/rollup-darwin-x64": "4.20.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.20.0", + "@rollup/rollup-linux-arm-musleabihf": "4.20.0", + "@rollup/rollup-linux-arm64-gnu": "4.20.0", + "@rollup/rollup-linux-arm64-musl": "4.20.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.20.0", + "@rollup/rollup-linux-riscv64-gnu": "4.20.0", + "@rollup/rollup-linux-s390x-gnu": "4.20.0", + "@rollup/rollup-linux-x64-gnu": "4.20.0", + "@rollup/rollup-linux-x64-musl": "4.20.0", + "@rollup/rollup-win32-arm64-msvc": "4.20.0", + "@rollup/rollup-win32-ia32-msvc": "4.20.0", + "@rollup/rollup-win32-x64-msvc": "4.20.0", + "fsevents": "~2.3.2" } }, "node_modules/@angular/cdk": { @@ -1018,27 +822,27 @@ } }, "node_modules/@angular/cli": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-18.1.0.tgz", - "integrity": "sha512-2E+b7S/736AOmxf5je9OWoPpgPY240TfJfFXwQiVvq/4KyC+ZR9lBrqRx72Xghn8nu3z8Q2BPZIXVGZppl0USQ==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-18.2.5.tgz", + "integrity": "sha512-97uNs0HsOdnMaTlNJKFjIBUXw0wz43uYvSSKmIpBt7eq1LaPLju1G/qpDIHx2YwhMClPrXXrW2H/xdvqZiIw+w==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.1801.0", - "@angular-devkit/core": "18.1.0", - "@angular-devkit/schematics": "18.1.0", - "@inquirer/prompts": "5.0.7", - "@listr2/prompt-adapter-inquirer": "2.0.13", - "@schematics/angular": "18.1.0", + "@angular-devkit/architect": "0.1802.5", + "@angular-devkit/core": "18.2.5", + "@angular-devkit/schematics": "18.2.5", + "@inquirer/prompts": "5.3.8", + "@listr2/prompt-adapter-inquirer": "2.0.15", + "@schematics/angular": "18.2.5", "@yarnpkg/lockfile": "1.1.0", "ini": "4.1.3", "jsonc-parser": "3.3.1", - "listr2": "8.2.3", - "npm-package-arg": "11.0.2", - "npm-pick-manifest": "9.0.1", + "listr2": "8.2.4", + "npm-package-arg": "11.0.3", + "npm-pick-manifest": "9.1.0", "pacote": "18.0.6", "resolve": "1.22.8", - "semver": "7.6.2", + "semver": "7.6.3", "symbol-observable": "4.0.0", "yargs": "17.7.2" }, @@ -1051,124 +855,10 @@ "yarn": ">= 1.13.0" } }, - "node_modules/@angular/cli/node_modules/@angular-devkit/architect": { - "version": "0.1801.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1801.0.tgz", - "integrity": "sha512-iZa3J3CrZT6MKiHPw8ijgVwMyCMewCsP4xc75SetUwF/yuqRUHygALs5jJVZQFQjSFUrkg9gqXa1cCjFDwpT8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-devkit/core": "18.1.0", - "rxjs": "7.8.1" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@angular/cli/node_modules/@angular-devkit/core": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.1.0.tgz", - "integrity": "sha512-6eXQDzHZCbpSMLv9Ohl+1QyLVDmGEXpuuHz3y64LfUTP0aEiBaxk96FjLXIxzJ4f2pbbW2XHzc+yuboGToRA0w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "8.16.0", - "ajv-formats": "3.0.1", - "jsonc-parser": "3.3.1", - "picomatch": "4.0.2", - "rxjs": "7.8.1", - "source-map": "0.7.4" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^3.5.2" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/@angular/cli/node_modules/@angular-devkit/schematics": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.1.0.tgz", - "integrity": "sha512-BjrYutLfYFiPOSEcLBWCj3ENkwDn8gMfBSJesaBz7OrZBZGK5j0dVgBLIsGTP96TKo4o4vszJQOvS4AtV6xMGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-devkit/core": "18.1.0", - "jsonc-parser": "3.3.1", - "magic-string": "0.30.10", - "ora": "5.4.1", - "rxjs": "7.8.1" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@angular/cli/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@angular/cli/node_modules/magic-string": { - "version": "0.30.10", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", - "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - } - }, - "node_modules/@angular/cli/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/@angular/cli/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@angular/common": { - "version": "18.0.5", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-18.0.5.tgz", - "integrity": "sha512-yItVQSu+Rx8gthWJDTOHwbzItY8/lqmmmYA1RMex0u3GkJoX3/3TZSGXbbBXl8GH8vmQOfp9yj3C02JmlwldRg==", - "license": "MIT", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-18.2.5.tgz", + "integrity": "sha512-m+KJrtbFXTE36jP/po6UAMeUR/enQxRHpVGLCRcIcE7VWVH1ZcOvoW1yqh2A6k+KxWXeajlq/Z04nnMhcoxMRw==", "dependencies": { "tslib": "^2.3.0" }, @@ -1176,14 +866,14 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "18.0.5", + "@angular/core": "18.2.5", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "18.0.5", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-18.0.5.tgz", - "integrity": "sha512-U1/qjNDjxMukXwQrJZjmr87KVxQmHbD7fxVlg0+qafHLe+YDuCtyOfQSGEZrWhwktxvAYZbl3FK+m3Hnk/D3Nw==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-18.2.5.tgz", + "integrity": "sha512-vcqe9x4dGGAnMfPhEpcZyiSVgAiqJeK80LqP1vWoAmBR+HeOqAilSv6SflcLAtuTzwgzMMAvD2T+SMCgUvaqww==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -1192,7 +882,7 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "18.0.5" + "@angular/core": "18.2.5" }, "peerDependenciesMeta": { "@angular/core": { @@ -1201,13 +891,13 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "18.0.5", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-18.0.5.tgz", - "integrity": "sha512-aFKDDTsRmc691EkNRj9OkrKNXDOaHdXB42MyUrj3WwJIJFMnSY/UDf6h+CRVF0U+CITszFyWhmeHQRA/3mJWNg==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-18.2.5.tgz", + "integrity": "sha512-CCCtZobUTUfId/RTYtuDCw5R1oK0w65hdAUMRP1MdGmd8bb8DKJA86u1QCWwozL3rbXlIIX4ognQ6urQ43k/Gw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "7.24.7", + "@babel/core": "7.25.2", "@jridgewell/sourcemap-codec": "^1.4.14", "chokidar": "^3.0.0", "convert-source-map": "^1.5.1", @@ -1225,62 +915,14 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/compiler": "18.0.5", - "typescript": ">=5.4 <5.5" - } - }, - "node_modules/@angular/compiler-cli/node_modules/@babel/core": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.7.tgz", - "integrity": "sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helpers": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/semver": { - "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" + "@angular/compiler": "18.2.5", + "typescript": ">=5.4 <5.6" } }, "node_modules/@angular/core": { - "version": "18.0.5", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-18.0.5.tgz", - "integrity": "sha512-0UuL+aMMWGYksz09YBsiHq1li7GmL8obB3IC3T5MwDqnn7FGRUBfBUOZEkM6B+pwgg+RAtNdJkbCfbh1z74bFQ==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-18.2.5.tgz", + "integrity": "sha512-5BLVc5gXxzanQkADNS9WPsor3vNF5nQcyIHBi5VScErwM5vVZ7ATH1iZwaOg1ykDEVTFVhKDwD0X1aaqGDbhmQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -1290,13 +932,13 @@ }, "peerDependencies": { "rxjs": "^6.5.3 || ^7.4.0", - "zone.js": "~0.14.0" + "zone.js": "~0.14.10" } }, "node_modules/@angular/forms": { - "version": "18.0.5", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-18.0.5.tgz", - "integrity": "sha512-nO7bN+nO2/czgKSvPx6ewqpfb8xXOyns06uovWpAXSH4jYoiZ6CHTHhOKrOL/3SRkhUV9u+EUXTTAOSBkS+OBA==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-18.2.5.tgz", + "integrity": "sha512-ohKeH+EZCCIyGSiFYlraWLzssGAZc13P92cuYpXB62322PkcA5u0IT72mML9JWGKRqF2zteVsw4koWHVxXM5mA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -1305,16 +947,16 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.0.5", - "@angular/core": "18.0.5", - "@angular/platform-browser": "18.0.5", + "@angular/common": "18.2.5", + "@angular/core": "18.2.5", + "@angular/platform-browser": "18.2.5", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/language-service": { - "version": "18.0.5", - "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-18.0.5.tgz", - "integrity": "sha512-ahZnsUk8q/4k+okP9hBcfWRiOiMximSAI7Vq5M/fe9cezykt8cWEzxgRoduTvDKoQPqcRl0nHlDYju2zkXcU6g==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-18.2.5.tgz", + "integrity": "sha512-JE6ck4UWXayiG8ptJJtkrKCjy+5Ftktgsoj4QGdQzMhbpia7Wge5XDj28o+bwEFndRnP6ihRtud63IvOz9aKFQ==", "dev": true, "license": "MIT", "engines": { @@ -1322,9 +964,9 @@ } }, "node_modules/@angular/platform-browser": { - "version": "18.0.5", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-18.0.5.tgz", - "integrity": "sha512-hBKaGz7dhsjNhD0aWB8G2/YZQ/MaBhzFIQSAZMPs2ccAqH1Jx772/Y11k57seA3VaPpnL8WZ1apOSJgALUJ//w==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-18.2.5.tgz", + "integrity": "sha512-PoX9idwnOpTJBlujzZ2nFGOsmCnZzOH7uNSWIR7trdoq0b1AFXfrxlCQ36qWamk7bbhJI4H28L8YTmKew/nXDA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -1333,9 +975,9 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/animations": "18.0.5", - "@angular/common": "18.0.5", - "@angular/core": "18.0.5" + "@angular/animations": "18.2.5", + "@angular/common": "18.2.5", + "@angular/core": "18.2.5" }, "peerDependenciesMeta": { "@angular/animations": { @@ -1344,9 +986,9 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "18.0.5", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-18.0.5.tgz", - "integrity": "sha512-i8CXojKcjsKzD2JR2clIisqavlHCW1jw+F2hJVrf/JR9iu6kVpGpZOqb3yYHoQCsPa7hUzQnn0ewYwBvlWsDmw==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-18.2.5.tgz", + "integrity": "sha512-5u0IuAt1r5e2u2vSKhp3phnaf6hH89B/q7GErfPse1sdDfNI6wHVppxai28PAfAj9gwooJun6MjFWhJFLzS44A==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -1355,16 +997,16 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.0.5", - "@angular/compiler": "18.0.5", - "@angular/core": "18.0.5", - "@angular/platform-browser": "18.0.5" + "@angular/common": "18.2.5", + "@angular/compiler": "18.2.5", + "@angular/core": "18.2.5", + "@angular/platform-browser": "18.2.5" } }, "node_modules/@angular/router": { - "version": "18.0.5", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-18.0.5.tgz", - "integrity": "sha512-GmdzD5FZYPKCGP6mV3AZraAU6czfGcjjCym6mIsdJr3DyMwnQSwaaHAu8qlQbPDVfsP+gKVSPh1JxI1lzzarLA==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-18.2.5.tgz", + "integrity": "sha512-OjZV1PTiSwT0ytmR0ykveLYzs4uQWf0EuIclZmWqM/bb8Q4P+gJl7/sya05nGnZsj6nHGOL0e/LhSZ3N+5p6qg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -1373,16 +1015,16 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.0.5", - "@angular/core": "18.0.5", - "@angular/platform-browser": "18.0.5", + "@angular/common": "18.2.5", + "@angular/core": "18.2.5", + "@angular/platform-browser": "18.2.5", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/service-worker": { - "version": "18.0.5", - "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-18.0.5.tgz", - "integrity": "sha512-Uz3rKHY0pBOvAfxhaGI9X8glS8oaPv03e3GsucZhzuDCijQGHQb1Plaz56NntIGvGaghLMq3zwV7YLPnquarvw==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-18.2.5.tgz", + "integrity": "sha512-MoF2n7z/X+yqK89mIRHQutVHIBTyEUo/fDEL8LcuBP4KOZmX9cRoCEt+vqH49BkArsgOM0jNFMYCM8yt0jg7pw==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -1394,8 +1036,8 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.0.5", - "@angular/core": "18.0.5" + "@angular/common": "18.2.5", + "@angular/core": "18.2.5" } }, "node_modules/@babel/code-frame": { @@ -3640,15 +3282,15 @@ } }, "node_modules/@es-joy/jsdoccomment": { - "version": "0.46.0", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.46.0.tgz", - "integrity": "sha512-C3Axuq1xd/9VqFZpW4YAzOx5O9q/LP46uIQy/iNDpHG3fmPa6TBtvfglMCs3RBiBxAIi0Go97r8+jvTt55XMyQ==", + "version": "0.48.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.48.0.tgz", + "integrity": "sha512-G6QUWIcC+KvSwXNsJyDTHvqUdNoAVJPPgkc3+Uk4WBKqZvoXhlvazOgm9aL0HwihJLQf0l+tOE2UFzXBqCqgDw==", "dev": true, "license": "MIT", "dependencies": { "comment-parser": "1.4.1", "esquery": "^1.6.0", - "jsdoc-type-pratt-parser": "~4.0.0" + "jsdoc-type-pratt-parser": "~4.1.0" }, "engines": { "node": ">=16" @@ -4292,15 +3934,15 @@ } }, "node_modules/@inquirer/checkbox": { - "version": "2.4.7", - "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-2.4.7.tgz", - "integrity": "sha512-5YwCySyV1UEgqzz34gNsC38eKxRBtlRDpJLlKcRtTjlYA/yDKuc1rfw+hjw+2WJxbAZtaDPsRl5Zk7J14SBoBw==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-2.5.0.tgz", + "integrity": "sha512-sMgdETOfi2dUHT8r7TT1BTKOwNvdDGFDXYWtQ2J69SvlYNntk9I/gJe7r5yvMwwsuKnYbuRs3pNhx4tgNck5aA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^9.0.10", + "@inquirer/core": "^9.1.0", "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.2", + "@inquirer/type": "^1.5.3", "ansi-escapes": "^4.3.2", "yoctocolors-cjs": "^2.1.2" }, @@ -4323,19 +3965,18 @@ } }, "node_modules/@inquirer/core": { - "version": "9.0.10", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.10.tgz", - "integrity": "sha512-TdESOKSVwf6+YWDz8GhS6nKscwzkIyakEzCLJ5Vh6O3Co2ClhCJ0A4MG909MUWfaWdpJm7DE45ii51/2Kat9tA==", + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.2.1.tgz", + "integrity": "sha512-F2VBt7W/mwqEU4bL0RnHNZmC/OxzNx9cOYxHqnXX3MP6ruYvZUZAW9imgN9+h/uBT/oP8Gh888J2OZSbjSeWcg==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.2", + "@inquirer/figures": "^1.0.6", + "@inquirer/type": "^2.0.0", "@types/mute-stream": "^0.0.4", - "@types/node": "^22.1.0", + "@types/node": "^22.5.5", "@types/wrap-ansi": "^3.0.0", "ansi-escapes": "^4.3.2", - "cli-spinners": "^2.9.2", "cli-width": "^4.1.0", "mute-stream": "^1.0.0", "signal-exit": "^4.1.0", @@ -4347,10 +3988,23 @@ "node": ">=18" } }, + "node_modules/@inquirer/core/node_modules/@inquirer/type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-2.0.0.tgz", + "integrity": "sha512-XvJRx+2KR3YXyYtPUUy+qd9i7p+GO9Ko6VIIpWlBrpWwXDv8WLFeHTxz35CfQFUiBMLXlGHhGzys7lqit9gWag==", + "dev": true, + "license": "MIT", + "dependencies": { + "mute-stream": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@inquirer/core/node_modules/@types/node": { - "version": "22.5.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.0.tgz", - "integrity": "sha512-DkFrJOe+rfdHTqqMg0bSNlGlQ85hSoh2TPzZyhHsXnMtligRWpxUySiyw8FY14ITt24HVCiQPWxS3KO/QlGmWg==", + "version": "22.6.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.6.1.tgz", + "integrity": "sha512-V48tCfcKb/e6cVUigLAaJDAILdMP0fUW6BidkPK4GpGjXcfbnoHasCZDwz3N3yVt5we2RHm4XTQCpv0KJz9zqw==", "dev": true, "license": "MIT", "dependencies": { @@ -4358,14 +4012,14 @@ } }, "node_modules/@inquirer/editor": { - "version": "2.1.22", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-2.1.22.tgz", - "integrity": "sha512-K1QwTu7GCK+nKOVRBp5HY9jt3DXOfPGPr6WRDrPImkcJRelG9UTx2cAtK1liXmibRrzJlTWOwqgWT3k2XnS62w==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-2.2.0.tgz", + "integrity": "sha512-9KHOpJ+dIL5SZli8lJ6xdaYLPPzB8xB9GZItg39MBybzhxA16vxmszmQFrRwbOA918WA2rvu8xhDEg/p6LXKbw==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^9.0.10", - "@inquirer/type": "^1.5.2", + "@inquirer/core": "^9.1.0", + "@inquirer/type": "^1.5.3", "external-editor": "^3.1.0" }, "engines": { @@ -4373,14 +4027,14 @@ } }, "node_modules/@inquirer/expand": { - "version": "2.1.22", - "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-2.1.22.tgz", - "integrity": "sha512-wTZOBkzH+ItPuZ3ZPa9lynBsdMp6kQ9zbjVPYEtSBG7UulGjg2kQiAnUjgyG4SlntpTce5bOmXAPvE4sguXjpA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-2.3.0.tgz", + "integrity": "sha512-qnJsUcOGCSG1e5DTOErmv2BPQqrtT6uzqn1vI/aYGiPKq+FgslGZmtdnXbhuI7IlT7OByDoEEqdnhUnVR2hhLw==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^9.0.10", - "@inquirer/type": "^1.5.2", + "@inquirer/core": "^9.1.0", + "@inquirer/type": "^1.5.3", "yoctocolors-cjs": "^2.1.2" }, "engines": { @@ -4388,9 +4042,9 @@ } }, "node_modules/@inquirer/figures": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.5.tgz", - "integrity": "sha512-79hP/VWdZ2UVc9bFGJnoQ/lQMpL74mGgzSYX1xUqCVk7/v73vJCMw1VuyWN1jGkZ9B3z7THAbySqGbCNefcjfA==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.6.tgz", + "integrity": "sha512-yfZzps3Cso2UbM7WlxKwZQh2Hs6plrbjs1QnzQDZhK2DgyCo6D8AaHps9olkNcUFlcYERMqU3uJSp1gmy3s/qQ==", "dev": true, "license": "MIT", "engines": { @@ -4398,28 +4052,42 @@ } }, "node_modules/@inquirer/input": { - "version": "2.2.9", - "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-2.2.9.tgz", - "integrity": "sha512-7Z6N+uzkWM7+xsE+3rJdhdG/+mQgejOVqspoW+w0AbSZnL6nq5tGMEVASaYVWbkoSzecABWwmludO2evU3d31g==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-2.3.0.tgz", + "integrity": "sha512-XfnpCStx2xgh1LIRqPXrTNEEByqQWoxsWYzNRSEUxJ5c6EQlhMogJ3vHKu8aXuTacebtaZzMAHwEL0kAflKOBw==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^9.0.10", - "@inquirer/type": "^1.5.2" + "@inquirer/core": "^9.1.0", + "@inquirer/type": "^1.5.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/number": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-1.1.0.tgz", + "integrity": "sha512-ilUnia/GZUtfSZy3YEErXLJ2Sljo/mf9fiKc08n18DdwdmDbOzRcTv65H1jjDvlsAuvdFXf4Sa/aL7iw/NanVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^9.1.0", + "@inquirer/type": "^1.5.3" }, "engines": { "node": ">=18" } }, "node_modules/@inquirer/password": { - "version": "2.1.22", - "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-2.1.22.tgz", - "integrity": "sha512-5Fxt1L9vh3rAKqjYwqsjU4DZsEvY/2Gll+QkqR4yEpy6wvzLxdSgFhUcxfDAOtO4BEoTreWoznC0phagwLU5Kw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-2.2.0.tgz", + "integrity": "sha512-5otqIpgsPYIshqhgtEwSspBQE40etouR8VIxzpJkv9i0dVHIpyhiivbkH9/dGiMLdyamT54YRdGJLfl8TFnLHg==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^9.0.10", - "@inquirer/type": "^1.5.2", + "@inquirer/core": "^9.1.0", + "@inquirer/type": "^1.5.3", "ansi-escapes": "^4.3.2" }, "engines": { @@ -4427,34 +4095,52 @@ } }, "node_modules/@inquirer/prompts": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-5.0.7.tgz", - "integrity": "sha512-GFcigCxJTKCH3aECzMIu4FhgLJWnFvMXzpI4CCSoELWFtkOOU2P+goYA61+OKpGrB8fPE7q6n8zAXBSlZRrHjQ==", + "version": "5.3.8", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-5.3.8.tgz", + "integrity": "sha512-b2BudQY/Si4Y2a0PdZZL6BeJtl8llgeZa7U2j47aaJSCeAl1e4UI7y8a9bSkO3o/ZbZrgT5muy/34JbsjfIWxA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/checkbox": "^2.3.7", - "@inquirer/confirm": "^3.1.11", - "@inquirer/editor": "^2.1.11", - "@inquirer/expand": "^2.1.11", - "@inquirer/input": "^2.1.11", - "@inquirer/password": "^2.1.11", - "@inquirer/rawlist": "^2.1.11", - "@inquirer/select": "^2.3.7" + "@inquirer/checkbox": "^2.4.7", + "@inquirer/confirm": "^3.1.22", + "@inquirer/editor": "^2.1.22", + "@inquirer/expand": "^2.1.22", + "@inquirer/input": "^2.2.9", + "@inquirer/number": "^1.0.10", + "@inquirer/password": "^2.1.22", + "@inquirer/rawlist": "^2.2.4", + "@inquirer/search": "^1.0.7", + "@inquirer/select": "^2.4.7" }, "engines": { "node": ">=18" } }, "node_modules/@inquirer/rawlist": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-2.2.4.tgz", - "integrity": "sha512-pb6w9pWrm7EfnYDgQObOurh2d2YH07+eDo3xQBsNAM2GRhliz6wFXGi1thKQ4bN6B0xDd6C3tBsjdr3obsCl3Q==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-2.3.0.tgz", + "integrity": "sha512-zzfNuINhFF7OLAtGHfhwOW2TlYJyli7lOUoJUXw/uyklcwalV6WRXBXtFIicN8rTRK1XTiPWB4UY+YuW8dsnLQ==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^9.0.10", - "@inquirer/type": "^1.5.2", + "@inquirer/core": "^9.1.0", + "@inquirer/type": "^1.5.3", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/search": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-1.1.0.tgz", + "integrity": "sha512-h+/5LSj51dx7hp5xOn4QFnUaKeARwUCLs6mIhtkJ0JYPBLmEYjdHSYh7I6GrLg9LwpJ3xeX0FZgAG1q0QdCpVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^9.1.0", + "@inquirer/figures": "^1.0.5", + "@inquirer/type": "^1.5.3", "yoctocolors-cjs": "^2.1.2" }, "engines": { @@ -4462,15 +4148,15 @@ } }, "node_modules/@inquirer/select": { - "version": "2.4.7", - "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-2.4.7.tgz", - "integrity": "sha512-JH7XqPEkBpNWp3gPCqWqY8ECbyMoFcCZANlL6pV9hf59qK6dGmkOlx1ydyhY+KZ0c5X74+W6Mtp+nm2QX0/MAQ==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-2.5.0.tgz", + "integrity": "sha512-YmDobTItPP3WcEI86GvPo+T2sRHkxxOq/kXmsBjHS5BVXUgvgZ5AfJjkvQvZr03T81NnI3KrrRuMzeuYUQRFOA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^9.0.10", + "@inquirer/core": "^9.1.0", "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.2", + "@inquirer/type": "^1.5.3", "ansi-escapes": "^4.3.2", "yoctocolors-cjs": "^2.1.2" }, @@ -4479,9 +4165,9 @@ } }, "node_modules/@inquirer/type": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-1.5.2.tgz", - "integrity": "sha512-w9qFkumYDCNyDZmNQjf/n6qQuvQ4dMC3BJesY4oF+yr0CxR5vxujflAVeIcS6U336uzi9GM0kAfZlLrZ9UTkpA==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-1.5.5.tgz", + "integrity": "sha512-MzICLu4yS7V8AA61sANROZ9vT1H3ooca5dSmI1FjZkzq7o/koMsRfQSzRtFo+F3Ao4Sf1C0bpLKejpKB/+j6MA==", "dev": true, "license": "MIT", "dependencies": { @@ -5687,13 +5373,13 @@ "dev": true }, "node_modules/@listr2/prompt-adapter-inquirer": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-2.0.13.tgz", - "integrity": "sha512-nAl6teTt7EWSjttNavAnv3uFR3w3vPP3OTYmHyPNHzKhAj2NoBDHmbS3MGpvvO8KXXPASnHjEGrrKrdKTMKPnQ==", + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-2.0.15.tgz", + "integrity": "sha512-MZrGem/Ujjd4cPTLYDfCZK2iKKeiO/8OX13S6jqxldLs0Prf2aGqVlJ77nMBqMv7fzqgXEgjrNHLXcKR8l9lOg==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/type": "^1.3.3" + "@inquirer/type": "^1.5.1" }, "engines": { "node": ">=18.0.0" @@ -5710,6 +5396,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -5723,6 +5410,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -5736,6 +5424,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -5749,6 +5438,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -5762,6 +5452,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -5775,6 +5466,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -5788,6 +5480,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -5801,6 +5494,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -5814,6 +5508,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -5827,6 +5522,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -5840,6 +5536,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -5853,6 +5550,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -5863,6 +5561,7 @@ "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.2.5.tgz", "integrity": "sha512-L0n4eHObeqEOYRfSP+e4SeF/dmwxOIFy9xYvYCOUwOLrW4b3+a1+kkT30pqyfL72LFtpf0cmUwaWEFIcWl5PCg==", "dev": true, + "license": "MIT", "engines": { "node": "^18.19.1 || ^20.11.1 || >=22.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", @@ -5875,9 +5574,9 @@ } }, "node_modules/@ngx-formly/core": { - "version": "6.3.6", - "resolved": "https://registry.npmjs.org/@ngx-formly/core/-/core-6.3.6.tgz", - "integrity": "sha512-0GDllrb9fFBTKG+yT+iQf96N3/CN+qRXIYsSX3uft12+c28qKVfMTsWTPYQsmKfGcrqtOZkMVTc+jGGD2JLZLg==", + "version": "6.3.7", + "resolved": "https://registry.npmjs.org/@ngx-formly/core/-/core-6.3.7.tgz", + "integrity": "sha512-To2mH09YSm3nyThABNHIameIJCPA9C+x3/JFxFtBWek+UbYeW9DYOqNHRCc7P1ToqLqNEuwrmzjB2YSA8pO9Pw==", "license": "MIT", "dependencies": { "tslib": "^2.0.0" @@ -5888,22 +5587,22 @@ } }, "node_modules/@ngx-formly/ionic": { - "version": "6.3.6", - "resolved": "https://registry.npmjs.org/@ngx-formly/ionic/-/ionic-6.3.6.tgz", - "integrity": "sha512-GaZav6bGGuQ3BqEVYK9DV+QsdM92jjfPmKbN9qz5s+kXH4ahjGfMqcq6Rm4SP49vvl5Am3mJZbZU4g9XrJI5tQ==", + "version": "6.3.7", + "resolved": "https://registry.npmjs.org/@ngx-formly/ionic/-/ionic-6.3.7.tgz", + "integrity": "sha512-j3jiv51CVNeJGY02bZgizarO24DF5AdzL5HJ7SAtJqBIxJNR++AkQZZvgMYtPYTrvhdOIiZrhkBWh0x+rfQMJQ==", "license": "MIT", "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@ionic/angular": "^6.0.0 || ^7.0.0", - "@ngx-formly/core": "6.3.6" + "@ngx-formly/core": "6.3.7" } }, "node_modules/@ngx-formly/schematics": { - "version": "6.3.6", - "resolved": "https://registry.npmjs.org/@ngx-formly/schematics/-/schematics-6.3.6.tgz", - "integrity": "sha512-QdrvdL4YrfhU9AxIXczSyzbZHWq7uuDtsIeEZ3lC0dFyvA0YyTxZRWfNyyMwCXCRXvn70WGlaU8UpeahTXsoAg==", + "version": "6.3.7", + "resolved": "https://registry.npmjs.org/@ngx-formly/schematics/-/schematics-6.3.7.tgz", + "integrity": "sha512-e1Y7RNa6AGK+YEIzNXNX5lvA8MrFQ9UEL/Pj8zwGdotKI8CnNyRVHneQ/1F+QZBo1mLXUtXJnejPoOMkGfo7VQ==", "license": "MIT", "dependencies": { "@angular-devkit/core": "^13.0.3", @@ -6619,63 +6318,23 @@ "win32" ] }, - "node_modules/@schematics/angular": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-18.1.0.tgz", - "integrity": "sha512-k9Dy6JD7hqvCzDqnMjDm7J8H/P6m5mLuX2yEgQWKRAJ/YMINtBQAaKA1T9qXk97kEX6RNLpHMuDIsrIfK/H31Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-devkit/core": "18.1.0", - "@angular-devkit/schematics": "18.1.0", - "jsonc-parser": "3.3.1" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@schematics/angular/node_modules/@angular-devkit/core": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.1.0.tgz", - "integrity": "sha512-6eXQDzHZCbpSMLv9Ohl+1QyLVDmGEXpuuHz3y64LfUTP0aEiBaxk96FjLXIxzJ4f2pbbW2XHzc+yuboGToRA0w==", + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "8.16.0", - "ajv-formats": "3.0.1", - "jsonc-parser": "3.3.1", - "picomatch": "4.0.2", - "rxjs": "7.8.1", - "source-map": "0.7.4" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^3.5.2" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } + "license": "MIT" }, - "node_modules/@schematics/angular/node_modules/@angular-devkit/schematics": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.1.0.tgz", - "integrity": "sha512-BjrYutLfYFiPOSEcLBWCj3ENkwDn8gMfBSJesaBz7OrZBZGK5j0dVgBLIsGTP96TKo4o4vszJQOvS4AtV6xMGg==", + "node_modules/@schematics/angular": { + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-18.2.5.tgz", + "integrity": "sha512-tBXhk9OGT4U6VsBNbuCNl2ITDOF3NYdGrEieIHU+lHSkpJNGZUIGxCgXCETXkmXDq1pe4wFZSKelWjeqYDfX0g==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "18.1.0", - "jsonc-parser": "3.3.1", - "magic-string": "0.30.10", - "ora": "5.4.1", - "rxjs": "7.8.1" + "@angular-devkit/core": "18.2.5", + "@angular-devkit/schematics": "18.2.5", + "jsonc-parser": "3.3.1" }, "engines": { "node": "^18.19.1 || ^20.11.1 || >=22.0.0", @@ -6683,43 +6342,6 @@ "yarn": ">= 1.13.0" } }, - "node_modules/@schematics/angular/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@schematics/angular/node_modules/magic-string": { - "version": "0.30.10", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", - "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - } - }, - "node_modules/@schematics/angular/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/@sigstore/bundle": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.3.2.tgz", @@ -7194,9 +6816,9 @@ "license": "MIT" }, "node_modules/@types/qs": { - "version": "6.9.15", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", - "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", + "version": "6.9.16", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz", + "integrity": "sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==", "dev": true, "license": "MIT" }, @@ -7324,17 +6946,65 @@ } } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", + "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { "version": "7.18.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", + "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, "engines": { "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { @@ -7360,6 +7030,37 @@ "eslint": "^8.56.0" } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", + "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@typescript-eslint/parser": { "version": "7.18.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", @@ -7367,11 +7068,75 @@ "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", + "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", + "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/typescript-estree": "7.18.0", "@typescript-eslint/visitor-keys": "7.18.0", - "debug": "^4.3.4" + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -7380,20 +7145,22 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependencies": { - "eslint": "^8.56.0" - }, "peerDependenciesMeta": { "typescript": { "optional": true } } }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", - "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", + "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "eslint-visitor-keys": "^3.4.3" + }, "engines": { "node": "^18.18.0 || >=20.0.0" }, @@ -7402,31 +7169,31 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", - "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", + "node_modules/@typescript-eslint/parser/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0" - }, + "license": "Apache-2.0", "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://opencollective.com/eslint" } }, - "node_modules/@typescript-eslint/scope-manager/node_modules/@typescript-eslint/types": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", - "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.7.0.tgz", + "integrity": "sha512-87rC0k3ZlDOuz82zzXRtQ7Akv3GKhHs0ti4YcbAJtaomllXoSO8hi7Ix3ccEvCd824dy9aIX+j3d2UMAfCtVpg==", "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.7.0", + "@typescript-eslint/visitor-keys": "8.7.0" + }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -7461,30 +7228,15 @@ } } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", - "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", - "dev": true, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/scope-manager": { "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", - "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", + "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.18.0", "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/typescript-estree": "7.18.0" + "@typescript-eslint/visitor-keys": "7.18.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -7492,25 +7244,23 @@ "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" } }, - "node_modules/@typescript-eslint/types": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.7.0.tgz", - "integrity": "sha512-LLt4BLHFwSfASHSF2K29SZ+ZCsbQOM+LuarPjRUuHm+Qd09hSe3GCeaQbcCr+Mik+0QFRmep/FyZBO6fJ64U3w==", + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", "dev": true, + "license": "MIT", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/typescript-estree": { + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { "version": "7.18.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", @@ -7539,50 +7289,65 @@ } } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/types": { + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", - "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", + "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0" + }, "engines": { "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" } }, - "node_modules/@typescript-eslint/utils": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.7.0.tgz", - "integrity": "sha512-ZbdUdwsl2X/s3CiyAu3gOlfQzpbuG3nTWKPoIvAu1pu5r8viiJvv2NPN2AqArL35NCYtw/lrPPfM4gxrMLNLPw==", + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", + "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", "dev": true, + "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.7.0", - "@typescript-eslint/types": "8.7.0", - "@typescript-eslint/typescript-estree": "8.7.0" + "@typescript-eslint/types": "7.18.0", + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { + "node_modules/@typescript-eslint/types": { "version": "8.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.7.0.tgz", - "integrity": "sha512-87rC0k3ZlDOuz82zzXRtQ7Akv3GKhHs0ti4YcbAJtaomllXoSO8hi7Ix3ccEvCd824dy9aIX+j3d2UMAfCtVpg==", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.7.0.tgz", + "integrity": "sha512-LLt4BLHFwSfASHSF2K29SZ+ZCsbQOM+LuarPjRUuHm+Qd09hSe3GCeaQbcCr+Mik+0QFRmep/FyZBO6fJ64U3w==", "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.7.0", - "@typescript-eslint/visitor-keys": "8.7.0" - }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -7591,11 +7356,12 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { + "node_modules/@typescript-eslint/typescript-estree": { "version": "8.7.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.7.0.tgz", "integrity": "sha512-MC8nmcGHsmfAKxwnluTQpNqceniT8SteVwd2voYlmiSWGOtjvGXdPl17dYu2797GVscK30Z04WRM28CrKS9WOg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/types": "8.7.0", "@typescript-eslint/visitor-keys": "8.7.0", @@ -7619,14 +7385,16 @@ } } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { + "node_modules/@typescript-eslint/utils": { "version": "8.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.7.0.tgz", - "integrity": "sha512-b1tx0orFCCh/THWPQa2ZwWzvOeyzzp36vkJYOpVg0u8UVOIsfVrnuC9FqAw9gRKn+rG2VmWQ/zDJZzkxUnj/XQ==", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.7.0.tgz", + "integrity": "sha512-ZbdUdwsl2X/s3CiyAu3gOlfQzpbuG3nTWKPoIvAu1pu5r8viiJvv2NPN2AqArL35NCYtw/lrPPfM4gxrMLNLPw==", "dev": true, "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.7.0", "@typescript-eslint/types": "8.7.0", - "eslint-visitor-keys": "^3.4.3" + "@typescript-eslint/typescript-estree": "8.7.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7634,45 +7402,23 @@ "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", - "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.7.0.tgz", + "integrity": "sha512-b1tx0orFCCh/THWPQa2ZwWzvOeyzzp36vkJYOpVg0u8UVOIsfVrnuC9FqAw9gRKn+rG2VmWQ/zDJZzkxUnj/XQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/types": "8.7.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/@typescript-eslint/types": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", - "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", - "dev": true, - "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -8057,16 +7803,15 @@ } }, "node_modules/ajv": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz", - "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, - "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -9403,9 +9148,9 @@ } }, "node_modules/cli-truncate/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, "license": "MIT", "engines": { @@ -9429,9 +9174,9 @@ } }, "node_modules/cli-truncate/node_modules/emoji-regex": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", - "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", "dev": true, "license": "MIT" }, @@ -12201,9 +11946,9 @@ } }, "node_modules/eslint-module-utils": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.2.tgz", - "integrity": "sha512-3XnC5fDyc8M4J2E8pt8pmSVRX2M+5yWMCfI/kDZwauQeFgzQOuhcRBFKjTeJagqgk4sFKxe1mvNVnaWwImx/Tg==", + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.11.1.tgz", + "integrity": "sha512-EwcbfLOhwVMAfatfqLecR2yv3dE5+kQ8kx+Rrt0DvDXEVwW86KQ/xbMDQhtp5l42VXukD5SOF8mQQHbaNtO0CQ==", "dev": true, "license": "MIT", "dependencies": { @@ -12229,27 +11974,28 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", - "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.30.0.tgz", + "integrity": "sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw==", "dev": true, "license": "MIT", "dependencies": { - "array-includes": "^3.1.7", - "array.prototype.findlastindex": "^1.2.3", + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.8", + "array.prototype.findlastindex": "^1.2.5", "array.prototype.flat": "^1.3.2", "array.prototype.flatmap": "^1.3.2", "debug": "^3.2.7", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.8.0", - "hasown": "^2.0.0", - "is-core-module": "^2.13.1", + "eslint-module-utils": "^2.9.0", + "hasown": "^2.0.2", + "is-core-module": "^2.15.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.fromentries": "^2.0.7", - "object.groupby": "^1.0.1", - "object.values": "^1.1.7", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.0", "semver": "^6.3.1", "tsconfig-paths": "^3.15.0" }, @@ -12318,17 +12064,18 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "48.10.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.10.0.tgz", - "integrity": "sha512-BEli0k8E0dzhJairAllwlkGnyYDZVKNn4WDmyKy+v6J5qGNuofjzxwNUi+55BOGmyO9mKBhqaidwGy+dxndn/Q==", + "version": "50.2.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.2.4.tgz", + "integrity": "sha512-020jA+dXaXdb+TML3ZJBvpPmzwbNROjnYuTYi/g6A5QEmEjhptz4oPJDKkOGMIByNxsPpdTLzSU1HYVqebOX1w==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "@es-joy/jsdoccomment": "~0.46.0", + "@es-joy/jsdoccomment": "~0.48.0", "are-docs-informative": "^0.0.2", "comment-parser": "1.4.1", - "debug": "^4.3.5", + "debug": "^4.3.6", "escape-string-regexp": "^4.0.0", + "espree": "^10.1.0", "esquery": "^1.6.0", "parse-imports": "^2.1.1", "semver": "^7.6.3", @@ -15492,9 +15239,9 @@ } }, "node_modules/jasmine-core": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.5.0.tgz", - "integrity": "sha512-9PMzyvhtocxb3aXJVOPqBDswdgyAeSB81QnLop4npOpbqnheaTEwPc9ZloQeVswugPManznQBjD8kWDTjlnHuw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.3.0.tgz", + "integrity": "sha512-zsOmeBKESky4toybvWEikRiZ0jHoBEu79wNArLfMdSnlLMZx3Xcp6CSm2sUcYyoJC+Uyj8LBJap/MUbVSfJ27g==", "dev": true, "license": "MIT" }, @@ -15604,9 +15351,9 @@ "license": "MIT" }, "node_modules/jsdoc-type-pratt-parser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", - "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.1.0.tgz", + "integrity": "sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==", "dev": true, "license": "MIT", "engines": { @@ -16090,6 +15837,13 @@ "karma-jasmine": "^5.0.0" } }, + "node_modules/karma-jasmine/node_modules/jasmine-core": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.6.1.tgz", + "integrity": "sha512-VYz/BjjmC3klLJlLwA4Kw8ytk0zDSmbbDLNs794VnWmkcCB7I9aAL/D48VNQtmITyPvea2C3jdUMfc3kAoy0PQ==", + "dev": true, + "license": "MIT" + }, "node_modules/karma-source-map-support": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", @@ -16471,16 +16225,16 @@ "license": "MIT" }, "node_modules/listr2": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.3.tgz", - "integrity": "sha512-Lllokma2mtoniUOS94CcOErHWAug5iu7HOmDrvWgpw8jyQH2fomgB+7lZS4HWZxytUuQwkGOwe49FvwVaA85Xw==", + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.4.tgz", + "integrity": "sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g==", "dev": true, "license": "MIT", "dependencies": { "cli-truncate": "^4.0.0", "colorette": "^2.0.20", "eventemitter3": "^5.0.1", - "log-update": "^6.0.0", + "log-update": "^6.1.0", "rfdc": "^1.4.1", "wrap-ansi": "^9.0.0" }, @@ -16489,9 +16243,9 @@ } }, "node_modules/listr2/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, "license": "MIT", "engines": { @@ -16515,9 +16269,9 @@ } }, "node_modules/listr2/node_modules/emoji-regex": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", - "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", "dev": true, "license": "MIT" }, @@ -16586,6 +16340,7 @@ "integrity": "sha512-UGe+BbaSUQtAMZobTb4nHvFMrmvuAQKSeaqAX2meTEQjfsbpl5sxdHD8T72OnwD4GU9uwNhYXIVe4QGs8N9Zyw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "dependencies": { "msgpackr": "^1.10.2", "node-addon-api": "^6.1.0", @@ -16609,7 +16364,8 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/load-json-file": { "version": "4.0.0", @@ -16940,9 +16696,9 @@ } }, "node_modules/log-update/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, "license": "MIT", "engines": { @@ -16982,9 +16738,9 @@ } }, "node_modules/log-update/node_modules/emoji-regex": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", - "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", "dev": true, "license": "MIT" }, @@ -17892,6 +17648,7 @@ "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.0.tgz", "integrity": "sha512-I8qXuuALqJe5laEBYoFykChhSXLikZmUhccjGsPuSJ/7uPip2TJ7lwdIQwWSAi0jGZDXv4WOP8Qg65QZRuXxXw==", "dev": true, + "license": "MIT", "optionalDependencies": { "msgpackr-extract": "^3.0.2" } @@ -17902,6 +17659,7 @@ "integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "dependencies": { "node-gyp-build-optional-packages": "5.2.2" @@ -18227,6 +17985,7 @@ "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==", "dev": true, + "license": "MIT", "dependencies": { "detect-libc": "^2.0.1" }, @@ -18536,9 +18295,9 @@ } }, "node_modules/npm-package-arg": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.2.tgz", - "integrity": "sha512-IGN0IAwmhDJwy13Wc8k+4PEbTPhpJnMtfR53ZbOyjkvmEcLS4nCwp6mvMWjS5sUjeiW3mpx6cHmuhKEu9XmcQw==", + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.3.tgz", + "integrity": "sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw==", "dev": true, "license": "ISC", "dependencies": { @@ -18585,9 +18344,9 @@ } }, "node_modules/npm-pick-manifest": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.0.1.tgz", - "integrity": "sha512-Udm1f0l2nXb3wxDpKjfohwgdFUSV50UVwzEIpDXVsbDMXVIEF81a/i0UhuQbhrPMMmdiq3+YMFLFIRVLs3hxQw==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.1.0.tgz", + "integrity": "sha512-nkc+3pIIhqHVQr085X9d2JzPzLyjzQS96zbruppqC9aZRm/x8xx6xhI98gHtsfELP2bE+loHq8ZaHFHhe+NauA==", "dev": true, "license": "ISC", "dependencies": { @@ -18960,7 +18719,8 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.5.1.tgz", "integrity": "sha512-5VyHfHY3cd0iza71JepYG50My+YUbrFtGoUz2ooEydPyPM7Aai/JW098juLr+RG6+rDJuzNNTsEQu2DZa1A41A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/os-name": { "version": "4.0.1", @@ -24606,7 +24366,8 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz", "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/webdriver-js-extender": { "version": "2.1.0", diff --git a/ui/package.json b/ui/package.json index 62d980810ac..2e1c9fe4481 100644 --- a/ui/package.json +++ b/ui/package.json @@ -4,27 +4,27 @@ "license": "AGPL-3.0", "private": true, "dependencies": { - "@angular/animations": "18.0.5", - "@angular/common": "18.0.5", - "@angular/core": "18.0.5", - "@angular/forms": "18.0.5", - "@angular/platform-browser": "18.0.5", - "@angular/platform-browser-dynamic": "18.0.5", - "@angular/router": "18.0.5", - "@angular/service-worker": "18.0.5", + "@angular/animations": "18.2.5", + "@angular/common": "18.2.5", + "@angular/core": "18.2.5", + "@angular/forms": "18.2.5", + "@angular/platform-browser": "18.2.5", + "@angular/platform-browser-dynamic": "18.2.5", + "@angular/router": "18.2.5", + "@angular/service-worker": "18.2.5", "@capacitor-community/file-opener": "^6.0.1", - "@capacitor/android": "^6.0.0", - "@capacitor/app": "^6.0.0", - "@capacitor/core": "^6.0.0", - "@capacitor/filesystem": "^6.0.0", - "@capacitor/ios": "^6.0.0", - "@capacitor/splash-screen": "^6.0.0", + "@capacitor/android": "^6.1.2", + "@capacitor/app": "^6.0.1", + "@capacitor/core": "^6.1.2", + "@capacitor/filesystem": "^6.0.1", + "@capacitor/ios": "^6.1.2", + "@capacitor/splash-screen": "^6.0.2", "@ionic-native/core": "^5.36.0", "@ionic-native/file-opener": "^5.36.0", "@ionic/angular": "^6.7.5", - "@ngx-formly/core": "^6.3.0", - "@ngx-formly/ionic": "^6.3.6", - "@ngx-formly/schematics": "^6.3.0", + "@ngx-formly/core": "^6.3.7", + "@ngx-formly/ionic": "^6.3.7", + "@ngx-formly/schematics": "^6.3.7", "@ngx-translate/core": "^15.0.0", "@nodro7/angular-mydatepicker": "^0.14.0", "capacitor-blob-writer": "^1.1.17", @@ -53,16 +53,16 @@ }, "devDependencies": { "@angular-devkit/build-angular": "^18.2.5", - "@angular-devkit/core": "18.0.5", - "@angular-devkit/schematics": "18.0.5", - "@angular-eslint/builder": "^18.1.0", - "@angular-eslint/eslint-plugin": "^18.1.0", - "@angular-eslint/eslint-plugin-template": "^18.1.0", - "@angular-eslint/template-parser": "^18.1.0", - "@angular/cli": "18.1.0", - "@angular/compiler": "18.0.5", - "@angular/compiler-cli": "18.0.5", - "@angular/language-service": "18.0.5", + "@angular-devkit/core": "18.2.5", + "@angular-devkit/schematics": "18.2.5", + "@angular-eslint/builder": "^18.3.1", + "@angular-eslint/eslint-plugin": "^18.3.1", + "@angular-eslint/eslint-plugin-template": "^18.3.1", + "@angular-eslint/template-parser": "^18.3.1", + "@angular/cli": "18.2.5", + "@angular/compiler": "18.2.5", + "@angular/compiler-cli": "18.2.5", + "@angular/language-service": "18.2.5", "@capacitor/assets": "^3.0.5", "@capacitor/cli": "6.1.2", "@ionic/angular-toolkit": "^11.0.1", @@ -72,7 +72,7 @@ "@types/jasminewd2": "~2.0.13", "@types/json-schema": "^7.0.15", "@types/node": "^20.12.6", - "@types/qs": "^6.9.15", + "@types/qs": "^6.9.16", "@types/range-parser": "^1.2.7", "@types/send": "^0.17.4", "@types/uuid": "^10.0.0", @@ -80,13 +80,13 @@ "@typescript-eslint/parser": "^7.0.0", "@typescript-eslint/types": "^8.7.0", "eslint": "^8.57.0", - "eslint-plugin-import": "2.29.1", - "eslint-plugin-jsdoc": "48.10.0", + "eslint-plugin-import": "2.30.0", + "eslint-plugin-jsdoc": "50.2.4", "eslint-plugin-prefer-arrow": "1.2.3", "eslint-plugin-unused-imports": "^4.1.4", - "jasmine-core": "~4.5.0", + "jasmine-core": "~5.3.0", "jasmine-spec-reporter": "~7.0.0", - "karma": "~6.4.2", + "karma": "~6.4.4", "karma-chrome-launcher": "~3.2.0", "karma-coverage": "~2.2.1", "karma-coverage-istanbul-reporter": "~3.0.3", diff --git a/ui/src/app/shared/components/edge/edgeconfig.ts b/ui/src/app/shared/components/edge/edgeconfig.ts index c06af3db4ac..4b12b73aed2 100644 --- a/ui/src/app/shared/components/edge/edgeconfig.ts +++ b/ui/src/app/shared/components/edge/edgeconfig.ts @@ -710,7 +710,7 @@ export namespace PersistencePriority { } } -export module EdgeConfig { +export namespace EdgeConfig { export class ComponentChannel { public readonly type!: "BOOLEAN" | "SHORT" | "INTEGER" | "LONG" | "FLOAT" | "DOUBLE" | "STRING"; public readonly accessMode!: "RO" | "RW" | "WO"; diff --git a/ui/src/app/shared/service/defaulttypes.ts b/ui/src/app/shared/service/defaulttypes.ts index c2551ff2e0b..b01b9875627 100644 --- a/ui/src/app/shared/service/defaulttypes.ts +++ b/ui/src/app/shared/service/defaulttypes.ts @@ -5,7 +5,7 @@ import { endOfMonth, endOfYear, format, getDay, getMonth, getYear, isSameDay, is import { QueryHistoricTimeseriesEnergyResponse } from "../jsonrpc/response/queryHistoricTimeseriesEnergyResponse"; import { ChannelAddress, Service } from "../shared"; -export module DefaultTypes { +export namespace DefaultTypes { export type Backend = "OpenEMS Backend" | "OpenEMS Edge"; From a479107eb12a93f7e2e047e9d6ee6aa31b0e4dfb Mon Sep 17 00:00:00 2001 From: Hiromasa Ihara Date: Mon, 30 Sep 2024 06:25:33 +0900 Subject: [PATCH 149/173] UI: add @stylistic to style rules (#2779) --- ui/.eslintrc.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/.eslintrc.json b/ui/.eslintrc.json index c3095af0cf3..8a3902ecddb 100644 --- a/ui/.eslintrc.json +++ b/ui/.eslintrc.json @@ -89,8 +89,8 @@ } ], "@typescript-eslint/member-ordering": "error", - "no-multiple-empty-lines": "error", - "quotes": [ + "@stylistic/no-multiple-empty-lines": "error", + "@stylistic/quotes": [ "error", "double" ], From 472e8eafbd3618517d0321d0211613b56c394f00 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Tue, 1 Oct 2024 11:45:23 +0200 Subject: [PATCH 150/173] Push version to 2024.10.0 --- .../io/openems/common/OpenemsConstants.java | 2 +- ui/package-lock.json | 1078 +++++++++++------ ui/package.json | 2 +- .../view/component/changelog.constants.ts | 2 +- 4 files changed, 700 insertions(+), 384 deletions(-) diff --git a/io.openems.common/src/io/openems/common/OpenemsConstants.java b/io.openems.common/src/io/openems/common/OpenemsConstants.java index cbfc12274fb..9b7384aae62 100644 --- a/io.openems.common/src/io/openems/common/OpenemsConstants.java +++ b/io.openems.common/src/io/openems/common/OpenemsConstants.java @@ -36,7 +36,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 f0ac38c3c72..fca2ca8fb74 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "openems-ui", - "version": "2024.10.0-SNAPSHOT", + "version": "2024.10.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "openems-ui", - "version": "2024.10.0-SNAPSHOT", + "version": "2024.10.0", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "18.2.5", @@ -142,16 +142,17 @@ } }, "node_modules/@angular-devkit/build-angular": { - "version": "18.2.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-18.2.5.tgz", - "integrity": "sha512-dIvb0AHoRIMM6tLuG4t6lDDslSAYP77wqytodsN317UzFOuuCPernXbO8NJs+QHxj09nPsem1T5vnvpO2E/PVQ==", + "version": "18.2.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-18.2.6.tgz", + "integrity": "sha512-u12cJZttgs5j7gICHWSmcaTCu0EFXEzKqI8nkYCwq2MtuJlAXiMQSXYuEP9OU3Go4vMAPtQh2kShyOWCX5b4EQ==", "dev": true, + "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1802.5", - "@angular-devkit/build-webpack": "0.1802.5", - "@angular-devkit/core": "18.2.5", - "@angular/build": "18.2.5", + "@angular-devkit/architect": "0.1802.6", + "@angular-devkit/build-webpack": "0.1802.6", + "@angular-devkit/core": "18.2.6", + "@angular/build": "18.2.6", "@babel/core": "7.25.2", "@babel/generator": "7.25.0", "@babel/helper-annotate-as-pure": "7.24.7", @@ -162,7 +163,7 @@ "@babel/preset-env": "7.25.3", "@babel/runtime": "7.25.0", "@discoveryjs/json-ext": "0.6.1", - "@ngtools/webpack": "18.2.5", + "@ngtools/webpack": "18.2.6", "@vitejs/plugin-basic-ssl": "1.1.0", "ansi-colors": "4.1.3", "autoprefixer": "10.4.20", @@ -269,54 +270,28 @@ } } }, - "node_modules/@angular-devkit/build-angular/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", - "dev": true - }, - "node_modules/@angular-devkit/build-webpack": { - "version": "0.1802.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1802.5.tgz", - "integrity": "sha512-6qkcrWBdkxojCVHGWcdJaz4G+7QTjFvmc+3g8xvLc9sYvJq1I059gfXhDnC0FxiA0MT4cY/26ECYWUHTD5CJLQ==", + "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/architect": { + "version": "0.1802.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1802.6.tgz", + "integrity": "sha512-oF7cPFdTLxeuvXkK/opSdIxZ1E4LrBbmuytQ/nCoAGOaKBWdqvwagRZ6jVhaI0Gwu48rkcV7Zhesg/ESNnROdw==", "dev": true, + "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.1802.5", + "@angular-devkit/core": "18.2.6", "rxjs": "7.8.1" }, "engines": { "node": "^18.19.1 || ^20.11.1 || >=22.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "webpack": "^5.30.0", - "webpack-dev-server": "^5.0.2" - } - }, - "node_modules/@angular-devkit/build-webpack/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "dependencies": { - "tslib": "^2.1.0" } }, - "node_modules/@angular-devkit/core": { - "version": "18.2.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.5.tgz", - "integrity": "sha512-r9TumPlJ8PvA2+yz4sp+bUHgtznaVKzhvXTN5qL1k4YP8LJ7iZWMR2FOP+HjukHZOTsenzmV9pszbogabqwoZQ==", + "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core": { + "version": "18.2.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.6.tgz", + "integrity": "sha512-la4CFvs5PcRWSkQ/H7TB5cPZirFVA9GoWk5LzIk8si6VjWBJRm8b3keKJoC9LlNeABRUIR5z0ocYkyQQUhdMfg==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "8.17.1", "ajv-formats": "3.0.1", @@ -339,150 +314,15 @@ } } }, - "node_modules/@angular-devkit/core/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/@angular-devkit/schematics": { - "version": "18.2.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.2.5.tgz", - "integrity": "sha512-NUmz2UQ1Xl4cf4j1AgkwIfsCjBzAPgfeC3IBrD29hSOBE1Y3j6auqjBkvw50v6mbSPxESND995Xy13HpK1Xflw==", - "dev": true, - "dependencies": { - "@angular-devkit/core": "18.2.5", - "jsonc-parser": "3.3.1", - "magic-string": "0.30.11", - "ora": "5.4.1", - "rxjs": "7.8.1" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@angular-devkit/schematics/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/@angular-eslint/builder": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-18.3.1.tgz", - "integrity": "sha512-cPc7Ye9zDs5M4i+feL6vob+mh7yX5vxvOS5KQIhneUrp5e9D+IGuNFMmBLlOPpmklSc9XJBtuvI5Zjuh4z1ETw==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": "*" - } - }, - "node_modules/@angular-eslint/bundled-angular-compiler": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-18.3.1.tgz", - "integrity": "sha512-sikmkjfsXPpPTku1aQkQ1MNNEKGBgGGRvUN/WeNS9dhCJ4dxU3O7dZctt1aQWj+W3nbuUtDiimAWF5fZHGFE2Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/@angular-eslint/eslint-plugin": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-18.3.1.tgz", - "integrity": "sha512-MP4Nm+SHboF8KdnN0KpPEGAaTTzDLPm3+S/4W3Mg8onqWCyadyd4mActh9mK/pvCj8TVlb/SW1zeTtdMYhwonw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-eslint/bundled-angular-compiler": "18.3.1", - "@angular-eslint/utils": "18.3.1" - }, - "peerDependencies": { - "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": "*" - } - }, - "node_modules/@angular-eslint/eslint-plugin-template": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-18.3.1.tgz", - "integrity": "sha512-hBJ3+f7VSidvrtYaXH7Vp0sWvblA9jLK2c6uQzhYGWdEDUcTg7g7VI9ThW39WvMbHqkyzNE4PPOynK69cBEDGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-eslint/bundled-angular-compiler": "18.3.1", - "@angular-eslint/utils": "18.3.1", - "aria-query": "5.3.0", - "axobject-query": "4.1.0" - }, - "peerDependencies": { - "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": "*" - } - }, - "node_modules/@angular-eslint/template-parser": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-18.3.1.tgz", - "integrity": "sha512-JUUkfWH1G+u/Uk85ZYvJSt/qwN/Ko+jlXFtzBEcknJZsTWTwBcp36v77gPZe5FmKSziJZpyPUd+7Kiy6tuSCTw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-eslint/bundled-angular-compiler": "18.3.1", - "eslint-scope": "^8.0.2" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": "*" - } - }, - "node_modules/@angular-eslint/utils": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-18.3.1.tgz", - "integrity": "sha512-sd9niZI7h9H2FQ7OLiQsLFBhjhRQTASh+Q0+4+hyjv9idbSHBJli8Gsi2fqj9zhtMKpAZFTrWzuLUpubJ9UYbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-eslint/bundled-angular-compiler": "18.3.1" - }, - "peerDependencies": { - "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": "*" - } - }, - "node_modules/@angular/animations": { - "version": "18.2.5", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-18.2.5.tgz", - "integrity": "sha512-IlXtW/Nj48ZzjHUzH1TykZcSR64ScJx39T3IHnjV2z/bVATzZ36JGoadQHdqpJNKBodYJNgtJCGLCbgAvGWY2g==", - "license": "MIT", - "dependencies": { - "tslib": "^2.3.0" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0" - }, - "peerDependencies": { - "@angular/core": "18.2.5" - } - }, - "node_modules/@angular/build": { - "version": "18.2.5", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-18.2.5.tgz", - "integrity": "sha512-XWkmjzgeUga0SJ0lYSYcTuYOWTyqcln2mNfBp7Ae/GZ+/7+APbedsIZEiZGZwveOIyOpTM5wguNSoe9khDl5Ig==", + "node_modules/@angular-devkit/build-angular/node_modules/@angular/build": { + "version": "18.2.6", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-18.2.6.tgz", + "integrity": "sha512-TQzX6Mi7uXFvmz7+OVl4Za7WawYPcx+B5Ewm6IY/DdMyB9P/Z4tbKb1LO+ynWUXYwm7avXo6XQQ4m5ArDY5F/A==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1802.5", + "@angular-devkit/architect": "0.1802.6", "@babel/core": "7.25.2", "@babel/helper-annotate-as-pure": "7.24.7", "@babel/helper-split-export-declaration": "7.24.7", @@ -501,7 +341,7 @@ "parse5-html-rewriting-stream": "7.0.0", "picomatch": "4.0.2", "piscina": "4.6.1", - "rollup": "4.20.0", + "rollup": "4.22.4", "sass": "1.77.6", "semver": "7.6.3", "vite": "5.4.6", @@ -543,10 +383,10 @@ } } }, - "node_modules/@angular/build/node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.20.0.tgz", - "integrity": "sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.4.tgz", + "integrity": "sha512-Fxamp4aEZnfPOcGA8KSNEohV8hX7zVHOemC8jVBoBUHu5zpJK/Eu3uJwt6BMgy9fkvzxDaurgj96F/NiLukF2w==", "cpu": [ "arm" ], @@ -557,10 +397,10 @@ "android" ] }, - "node_modules/@angular/build/node_modules/@rollup/rollup-android-arm64": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.20.0.tgz", - "integrity": "sha512-u00Ro/nok7oGzVuh/FMYfNoGqxU5CPWz1mxV85S2w9LxHR8OoMQBuSk+3BKVIDYgkpeOET5yXkx90OYFc+ytpQ==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-android-arm64": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.4.tgz", + "integrity": "sha512-VXoK5UMrgECLYaMuGuVTOx5kcuap1Jm8g/M83RnCHBKOqvPPmROFJGQaZhGccnsFtfXQ3XYa4/jMCJvZnbJBdA==", "cpu": [ "arm64" ], @@ -571,10 +411,10 @@ "android" ] }, - "node_modules/@angular/build/node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.20.0.tgz", - "integrity": "sha512-uFVfvzvsdGtlSLuL0ZlvPJvl6ZmrH4CBwLGEFPe7hUmf7htGAN+aXo43R/V6LATyxlKVC/m6UsLb7jbG+LG39Q==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.4.tgz", + "integrity": "sha512-xMM9ORBqu81jyMKCDP+SZDhnX2QEVQzTcC6G18KlTQEzWK8r/oNZtKuZaCcHhnsa6fEeOBionoyl5JsAbE/36Q==", "cpu": [ "arm64" ], @@ -585,10 +425,10 @@ "darwin" ] }, - "node_modules/@angular/build/node_modules/@rollup/rollup-darwin-x64": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.20.0.tgz", - "integrity": "sha512-xbrMDdlev53vNXexEa6l0LffojxhqDTBeL+VUxuuIXys4x6xyvbKq5XqTXBCEUA8ty8iEJblHvFaWRJTk/icAQ==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-darwin-x64": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.4.tgz", + "integrity": "sha512-aJJyYKQwbHuhTUrjWjxEvGnNNBCnmpHDvrb8JFDbeSH3m2XdHcxDd3jthAzvmoI8w/kSjd2y0udT+4okADsZIw==", "cpu": [ "x64" ], @@ -599,10 +439,10 @@ "darwin" ] }, - "node_modules/@angular/build/node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.20.0.tgz", - "integrity": "sha512-jMYvxZwGmoHFBTbr12Xc6wOdc2xA5tF5F2q6t7Rcfab68TT0n+r7dgawD4qhPEvasDsVpQi+MgDzj2faOLsZjA==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.4.tgz", + "integrity": "sha512-j63YtCIRAzbO+gC2L9dWXRh5BFetsv0j0va0Wi9epXDgU/XUi5dJKo4USTttVyK7fGw2nPWK0PbAvyliz50SCQ==", "cpu": [ "arm" ], @@ -613,10 +453,10 @@ "linux" ] }, - "node_modules/@angular/build/node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.20.0.tgz", - "integrity": "sha512-1asSTl4HKuIHIB1GcdFHNNZhxAYEdqML/MW4QmPS4G0ivbEcBr1JKlFLKsIRqjSwOBkdItn3/ZDlyvZ/N6KPlw==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.4.tgz", + "integrity": "sha512-dJnWUgwWBX1YBRsuKKMOlXCzh2Wu1mlHzv20TpqEsfdZLb3WoJW2kIEsGwLkroYf24IrPAvOT/ZQ2OYMV6vlrg==", "cpu": [ "arm" ], @@ -627,10 +467,10 @@ "linux" ] }, - "node_modules/@angular/build/node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.20.0.tgz", - "integrity": "sha512-COBb8Bkx56KldOYJfMf6wKeYJrtJ9vEgBRAOkfw6Ens0tnmzPqvlpjZiLgkhg6cA3DGzCmLmmd319pmHvKWWlQ==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.4.tgz", + "integrity": "sha512-AdPRoNi3NKVLolCN/Sp4F4N1d98c4SBnHMKoLuiG6RXgoZ4sllseuGioszumnPGmPM2O7qaAX/IJdeDU8f26Aw==", "cpu": [ "arm64" ], @@ -641,10 +481,10 @@ "linux" ] }, - "node_modules/@angular/build/node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.20.0.tgz", - "integrity": "sha512-+it+mBSyMslVQa8wSPvBx53fYuZK/oLTu5RJoXogjk6x7Q7sz1GNRsXWjn6SwyJm8E/oMjNVwPhmNdIjwP135Q==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.4.tgz", + "integrity": "sha512-Gl0AxBtDg8uoAn5CCqQDMqAx22Wx22pjDOjBdmG0VIWX3qUBHzYmOKh8KXHL4UpogfJ14G4wk16EQogF+v8hmA==", "cpu": [ "arm64" ], @@ -655,10 +495,10 @@ "linux" ] }, - "node_modules/@angular/build/node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.20.0.tgz", - "integrity": "sha512-yAMvqhPfGKsAxHN8I4+jE0CpLWD8cv4z7CK7BMmhjDuz606Q2tFKkWRY8bHR9JQXYcoLfopo5TTqzxgPUjUMfw==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.4.tgz", + "integrity": "sha512-3aVCK9xfWW1oGQpTsYJJPF6bfpWfhbRnhdlyhak2ZiyFLDaayz0EP5j9V1RVLAAxlmWKTDfS9wyRyY3hvhPoOg==", "cpu": [ "ppc64" ], @@ -669,10 +509,10 @@ "linux" ] }, - "node_modules/@angular/build/node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.20.0.tgz", - "integrity": "sha512-qmuxFpfmi/2SUkAw95TtNq/w/I7Gpjurx609OOOV7U4vhvUhBcftcmXwl3rqAek+ADBwSjIC4IVNLiszoj3dPA==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.4.tgz", + "integrity": "sha512-ePYIir6VYnhgv2C5Xe9u+ico4t8sZWXschR6fMgoPUK31yQu7hTEJb7bCqivHECwIClJfKgE7zYsh1qTP3WHUA==", "cpu": [ "riscv64" ], @@ -683,10 +523,10 @@ "linux" ] }, - "node_modules/@angular/build/node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.20.0.tgz", - "integrity": "sha512-I0BtGXddHSHjV1mqTNkgUZLnS3WtsqebAXv11D5BZE/gfw5KoyXSAXVqyJximQXNvNzUo4GKlCK/dIwXlz+jlg==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.4.tgz", + "integrity": "sha512-GqFJ9wLlbB9daxhVlrTe61vJtEY99/xB3C8e4ULVsVfflcpmR6c8UZXjtkMA6FhNONhj2eA5Tk9uAVw5orEs4Q==", "cpu": [ "s390x" ], @@ -697,10 +537,10 @@ "linux" ] }, - "node_modules/@angular/build/node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.20.0.tgz", - "integrity": "sha512-y+eoL2I3iphUg9tN9GB6ku1FA8kOfmF4oUEWhztDJ4KXJy1agk/9+pejOuZkNFhRwHAOxMsBPLbXPd6mJiCwew==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.4.tgz", + "integrity": "sha512-87v0ol2sH9GE3cLQLNEy0K/R0pz1nvg76o8M5nhMR0+Q+BBGLnb35P0fVz4CQxHYXaAOhE8HhlkaZfsdUOlHwg==", "cpu": [ "x64" ], @@ -711,10 +551,10 @@ "linux" ] }, - "node_modules/@angular/build/node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.20.0.tgz", - "integrity": "sha512-hM3nhW40kBNYUkZb/r9k2FKK+/MnKglX7UYd4ZUy5DJs8/sMsIbqWK2piZtVGE3kcXVNj3B2IrUYROJMMCikNg==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.4.tgz", + "integrity": "sha512-UV6FZMUgePDZrFjrNGIWzDo/vABebuXBhJEqrHxrGiU6HikPy0Z3LfdtciIttEUQfuDdCn8fqh7wiFJjCNwO+g==", "cpu": [ "x64" ], @@ -725,10 +565,10 @@ "linux" ] }, - "node_modules/@angular/build/node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.20.0.tgz", - "integrity": "sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.4.tgz", + "integrity": "sha512-BjI+NVVEGAXjGWYHz/vv0pBqfGoUH0IGZ0cICTn7kB9PyjrATSkX+8WkguNjWoj2qSr1im/+tTGRaY+4/PdcQw==", "cpu": [ "arm64" ], @@ -739,10 +579,10 @@ "win32" ] }, - "node_modules/@angular/build/node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.20.0.tgz", - "integrity": "sha512-GabekH3w4lgAJpVxkk7hUzUf2hICSQO0a/BLFA11/RMxQT92MabKAqyubzDZmMOC/hcJNlc+rrypzNzYl4Dx7A==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.4.tgz", + "integrity": "sha512-SiWG/1TuUdPvYmzmYnmd3IEifzR61Tragkbx9D3+R8mzQqDBz8v+BvZNDlkiTtI9T15KYZhP0ehn3Dld4n9J5g==", "cpu": [ "ia32" ], @@ -753,10 +593,10 @@ "win32" ] }, - "node_modules/@angular/build/node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.20.0.tgz", - "integrity": "sha512-aJ1EJSuTdGnM6qbVC4B5DSmozPTqIag9fSzXRNNo+humQLG89XpPgdt16Ia56ORD7s+H8Pmyx44uczDQ0yDzpg==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.4.tgz", + "integrity": "sha512-j8pPKp53/lq9lMXN57S8cFz0MynJk8OWNuUnXct/9KCpKU7DgU3bYMJhwWmcqC0UU29p8Lr0/7KEVcaM6bf47Q==", "cpu": [ "x64" ], @@ -767,10 +607,17 @@ "win32" ] }, - "node_modules/@angular/build/node_modules/rollup": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.20.0.tgz", - "integrity": "sha512-6rbWBChcnSGzIlXeIdNIZTopKYad8ZG8ajhl78lGRLsI2rX8IkaotQhVas2Ma+GPxJav19wrSzvRvuiv0YKzWw==", + "node_modules/@angular-devkit/build-angular/node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@angular-devkit/build-angular/node_modules/rollup": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.4.tgz", + "integrity": "sha512-vD8HJ5raRcWOyymsR6Z3o6+RzfEPCnVLMFJ6vRslO1jt4LO6dUo5Qnpg7y4RkZFM2DMe3WUirkI5c16onjrc6A==", "dev": true, "license": "MIT", "dependencies": { @@ -784,25 +631,276 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.20.0", - "@rollup/rollup-android-arm64": "4.20.0", - "@rollup/rollup-darwin-arm64": "4.20.0", - "@rollup/rollup-darwin-x64": "4.20.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.20.0", - "@rollup/rollup-linux-arm-musleabihf": "4.20.0", - "@rollup/rollup-linux-arm64-gnu": "4.20.0", - "@rollup/rollup-linux-arm64-musl": "4.20.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.20.0", - "@rollup/rollup-linux-riscv64-gnu": "4.20.0", - "@rollup/rollup-linux-s390x-gnu": "4.20.0", - "@rollup/rollup-linux-x64-gnu": "4.20.0", - "@rollup/rollup-linux-x64-musl": "4.20.0", - "@rollup/rollup-win32-arm64-msvc": "4.20.0", - "@rollup/rollup-win32-ia32-msvc": "4.20.0", - "@rollup/rollup-win32-x64-msvc": "4.20.0", + "@rollup/rollup-android-arm-eabi": "4.22.4", + "@rollup/rollup-android-arm64": "4.22.4", + "@rollup/rollup-darwin-arm64": "4.22.4", + "@rollup/rollup-darwin-x64": "4.22.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.22.4", + "@rollup/rollup-linux-arm-musleabihf": "4.22.4", + "@rollup/rollup-linux-arm64-gnu": "4.22.4", + "@rollup/rollup-linux-arm64-musl": "4.22.4", + "@rollup/rollup-linux-powerpc64le-gnu": "4.22.4", + "@rollup/rollup-linux-riscv64-gnu": "4.22.4", + "@rollup/rollup-linux-s390x-gnu": "4.22.4", + "@rollup/rollup-linux-x64-gnu": "4.22.4", + "@rollup/rollup-linux-x64-musl": "4.22.4", + "@rollup/rollup-win32-arm64-msvc": "4.22.4", + "@rollup/rollup-win32-ia32-msvc": "4.22.4", + "@rollup/rollup-win32-x64-msvc": "4.22.4", "fsevents": "~2.3.2" } }, + "node_modules/@angular-devkit/build-angular/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, + "node_modules/@angular-devkit/build-webpack": { + "version": "0.1802.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1802.6.tgz", + "integrity": "sha512-JMLcXFaitJplwZMKkqhbYirINCRD6eOPZuIGaIOVynXYGWgvJkLT9t5C2wm9HqSLtp1K7NcYG2Y7PtTVR4krnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/architect": "0.1802.6", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "webpack": "^5.30.0", + "webpack-dev-server": "^5.0.2" + } + }, + "node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/architect": { + "version": "0.1802.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1802.6.tgz", + "integrity": "sha512-oF7cPFdTLxeuvXkK/opSdIxZ1E4LrBbmuytQ/nCoAGOaKBWdqvwagRZ6jVhaI0Gwu48rkcV7Zhesg/ESNnROdw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "18.2.6", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/core": { + "version": "18.2.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.6.tgz", + "integrity": "sha512-la4CFvs5PcRWSkQ/H7TB5cPZirFVA9GoWk5LzIk8si6VjWBJRm8b3keKJoC9LlNeABRUIR5z0ocYkyQQUhdMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "8.17.1", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.2", + "rxjs": "7.8.1", + "source-map": "0.7.4" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-webpack/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@angular-devkit/core": { + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.5.tgz", + "integrity": "sha512-r9TumPlJ8PvA2+yz4sp+bUHgtznaVKzhvXTN5qL1k4YP8LJ7iZWMR2FOP+HjukHZOTsenzmV9pszbogabqwoZQ==", + "dev": true, + "dependencies": { + "ajv": "8.17.1", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.2", + "rxjs": "7.8.1", + "source-map": "0.7.4" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/core/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@angular-devkit/schematics": { + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.2.5.tgz", + "integrity": "sha512-NUmz2UQ1Xl4cf4j1AgkwIfsCjBzAPgfeC3IBrD29hSOBE1Y3j6auqjBkvw50v6mbSPxESND995Xy13HpK1Xflw==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "18.2.5", + "jsonc-parser": "3.3.1", + "magic-string": "0.30.11", + "ora": "5.4.1", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/schematics/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@angular-eslint/builder": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-18.3.1.tgz", + "integrity": "sha512-cPc7Ye9zDs5M4i+feL6vob+mh7yX5vxvOS5KQIhneUrp5e9D+IGuNFMmBLlOPpmklSc9XJBtuvI5Zjuh4z1ETw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" + } + }, + "node_modules/@angular-eslint/bundled-angular-compiler": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-18.3.1.tgz", + "integrity": "sha512-sikmkjfsXPpPTku1aQkQ1MNNEKGBgGGRvUN/WeNS9dhCJ4dxU3O7dZctt1aQWj+W3nbuUtDiimAWF5fZHGFE2Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@angular-eslint/eslint-plugin": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-18.3.1.tgz", + "integrity": "sha512-MP4Nm+SHboF8KdnN0KpPEGAaTTzDLPm3+S/4W3Mg8onqWCyadyd4mActh9mK/pvCj8TVlb/SW1zeTtdMYhwonw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-eslint/bundled-angular-compiler": "18.3.1", + "@angular-eslint/utils": "18.3.1" + }, + "peerDependencies": { + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" + } + }, + "node_modules/@angular-eslint/eslint-plugin-template": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-18.3.1.tgz", + "integrity": "sha512-hBJ3+f7VSidvrtYaXH7Vp0sWvblA9jLK2c6uQzhYGWdEDUcTg7g7VI9ThW39WvMbHqkyzNE4PPOynK69cBEDGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-eslint/bundled-angular-compiler": "18.3.1", + "@angular-eslint/utils": "18.3.1", + "aria-query": "5.3.0", + "axobject-query": "4.1.0" + }, + "peerDependencies": { + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" + } + }, + "node_modules/@angular-eslint/template-parser": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-18.3.1.tgz", + "integrity": "sha512-JUUkfWH1G+u/Uk85ZYvJSt/qwN/Ko+jlXFtzBEcknJZsTWTwBcp36v77gPZe5FmKSziJZpyPUd+7Kiy6tuSCTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-eslint/bundled-angular-compiler": "18.3.1", + "eslint-scope": "^8.0.2" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" + } + }, + "node_modules/@angular-eslint/utils": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-18.3.1.tgz", + "integrity": "sha512-sd9niZI7h9H2FQ7OLiQsLFBhjhRQTASh+Q0+4+hyjv9idbSHBJli8Gsi2fqj9zhtMKpAZFTrWzuLUpubJ9UYbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-eslint/bundled-angular-compiler": "18.3.1" + }, + "peerDependencies": { + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" + } + }, + "node_modules/@angular/animations": { + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-18.2.5.tgz", + "integrity": "sha512-IlXtW/Nj48ZzjHUzH1TykZcSR64ScJx39T3IHnjV2z/bVATzZ36JGoadQHdqpJNKBodYJNgtJCGLCbgAvGWY2g==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + }, + "peerDependencies": { + "@angular/core": "18.2.5" + } + }, "node_modules/@angular/cdk": { "version": "18.2.1", "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-18.2.1.tgz", @@ -1398,6 +1496,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.24.7" }, @@ -3304,6 +3403,7 @@ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "aix" @@ -3320,6 +3420,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -3336,6 +3437,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -3352,6 +3454,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -3368,6 +3471,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -3384,6 +3488,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -3400,6 +3505,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -3416,6 +3522,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -3432,6 +3539,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -3448,6 +3556,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -3464,6 +3573,7 @@ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -3480,6 +3590,7 @@ "loong64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -3496,6 +3607,7 @@ "mips64el" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -3512,6 +3624,7 @@ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -3528,6 +3641,7 @@ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -3544,6 +3658,7 @@ "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -3560,6 +3675,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -3576,6 +3692,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "netbsd" @@ -3592,6 +3709,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "openbsd" @@ -3608,6 +3726,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "openbsd" @@ -3624,6 +3743,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "sunos" @@ -3640,6 +3760,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -3656,6 +3777,7 @@ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -3672,6 +3794,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -5311,6 +5434,7 @@ "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=10.0" }, @@ -5327,6 +5451,7 @@ "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.1.0.tgz", "integrity": "sha512-zlQONA+msXPPwHWZMKFVS78ewFczIll5lXiVPwFPCZUsrOKdxc2AvxU1HoNBmMRhqDZUR9HkC3UOm+6pME6Xsg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@jsonjoy.com/base64": "^1.1.1", "@jsonjoy.com/util": "^1.1.2", @@ -5349,6 +5474,7 @@ "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.3.0.tgz", "integrity": "sha512-Cebt4Vk7k1xHy87kHY7KSPLT77A7Ev7IfOblyLZhtYEhrdQ6fX4EoLq3xOQ3O/DRMEh2ok5nyC180E+ABS8Wmw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=10.0" }, @@ -5370,7 +5496,8 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@listr2/prompt-adapter-inquirer": { "version": "2.0.15", @@ -5557,9 +5684,9 @@ ] }, "node_modules/@ngtools/webpack": { - "version": "18.2.5", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.2.5.tgz", - "integrity": "sha512-L0n4eHObeqEOYRfSP+e4SeF/dmwxOIFy9xYvYCOUwOLrW4b3+a1+kkT30pqyfL72LFtpf0cmUwaWEFIcWl5PCg==", + "version": "18.2.6", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.2.6.tgz", + "integrity": "sha512-7HwOPE1EOgcHnpt4brSiT8G2CcXB50G0+CbCBaKGy4LYCG3Y3mrlzF5Fup9HvMJ6Tzqd62RqzpKKYBiGUT7hxg==", "dev": true, "license": "MIT", "engines": { @@ -6111,208 +6238,224 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.0.tgz", - "integrity": "sha512-/IZQvg6ZR0tAkEi4tdXOraQoWeJy9gbQ/cx4I7k9dJaCk9qrXEcdouxRVz5kZXt5C2bQ9pILoAA+KB4C/d3pfw==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.23.0.tgz", + "integrity": "sha512-8OR+Ok3SGEMsAZispLx8jruuXw0HVF16k+ub2eNXKHDmdxL4cf9NlNpAzhlOhNyXzKDEJuFeq0nZm+XlNb1IFw==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.0.tgz", - "integrity": "sha512-ETHi4bxrYnvOtXeM7d4V4kZWixib2jddFacJjsOjwbgYSRsyXYtZHC4ht134OsslPIcnkqT+TKV4eU8rNBKyyQ==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.23.0.tgz", + "integrity": "sha512-rEFtX1nP8gqmLmPZsXRMoLVNB5JBwOzIAk/XAcEPuKrPa2nPJ+DuGGpfQUR0XjRm8KjHfTZLpWbKXkA5BoFL3w==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.0.tgz", - "integrity": "sha512-ZWgARzhSKE+gVUX7QWaECoRQsPwaD8ZR0Oxb3aUpzdErTvlEadfQpORPXkKSdKbFci9v8MJfkTtoEHnnW9Ulng==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.23.0.tgz", + "integrity": "sha512-ZbqlMkJRMMPeapfaU4drYHns7Q5MIxjM/QeOO62qQZGPh9XWziap+NF9fsqPHT0KzEL6HaPspC7sOwpgyA3J9g==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.0.tgz", - "integrity": "sha512-h0ZAtOfHyio8Az6cwIGS+nHUfRMWBDO5jXB8PQCARVF6Na/G6XS2SFxDl8Oem+S5ZsHQgtsI7RT4JQnI1qrlaw==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.23.0.tgz", + "integrity": "sha512-PfmgQp78xx5rBCgn2oYPQ1rQTtOaQCna0kRaBlc5w7RlA3TDGGo7m3XaptgitUZ54US9915i7KeVPHoy3/W8tA==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.0.tgz", - "integrity": "sha512-9pxQJSPwFsVi0ttOmqLY4JJ9pg9t1gKhK0JDbV1yUEETSx55fdyCjt39eBQ54OQCzAF0nVGO6LfEH1KnCPvelA==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.23.0.tgz", + "integrity": "sha512-WAeZfAAPus56eQgBioezXRRzArAjWJGjNo/M+BHZygUcs9EePIuGI1Wfc6U/Ki+tMW17FFGvhCfYnfcKPh18SA==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.0.tgz", - "integrity": "sha512-YJ5Ku5BmNJZb58A4qSEo3JlIG4d3G2lWyBi13ABlXzO41SsdnUKi3HQHe83VpwBVG4jHFTW65jOQb8qyoR+qzg==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.23.0.tgz", + "integrity": "sha512-v7PGcp1O5XKZxKX8phTXtmJDVpE20Ub1eF6w9iMmI3qrrPak6yR9/5eeq7ziLMrMTjppkkskXyxnmm00HdtXjA==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.0.tgz", - "integrity": "sha512-U4G4u7f+QCqHlVg1Nlx+qapZy+QoG+NV6ux+upo/T7arNGwKvKP2kmGM4W5QTbdewWFgudQxi3kDNST9GT1/mg==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.23.0.tgz", + "integrity": "sha512-nAbWsDZ9UkU6xQiXEyXBNHAKbzSAi95H3gTStJq9UGiS1v+YVXwRHcQOQEF/3CHuhX5BVhShKoeOf6Q/1M+Zhg==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.0.tgz", - "integrity": "sha512-aQpNlKmx3amwkA3a5J6nlXSahE1ijl0L9KuIjVOUhfOh7uw2S4piR3mtpxpRtbnK809SBtyPsM9q15CPTsY7HQ==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.23.0.tgz", + "integrity": "sha512-5QT/Di5FbGNPaVw8hHO1wETunwkPuZBIu6W+5GNArlKHD9fkMHy7vS8zGHJk38oObXfWdsuLMogD4sBySLJ54g==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.0.tgz", - "integrity": "sha512-9fx6Zj/7vve/Fp4iexUFRKb5+RjLCff6YTRQl4CoDhdMfDoobWmhAxQWV3NfShMzQk1Q/iCnageFyGfqnsmeqQ==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.23.0.tgz", + "integrity": "sha512-Sefl6vPyn5axzCsO13r1sHLcmPuiSOrKIImnq34CBurntcJ+lkQgAaTt/9JkgGmaZJ+OkaHmAJl4Bfd0DmdtOQ==", "cpu": [ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.0.tgz", - "integrity": "sha512-VWQiCcN7zBgZYLjndIEh5tamtnKg5TGxyZPWcN9zBtXBwfcGSZ5cHSdQZfQH/GB4uRxk0D3VYbOEe/chJhPGLQ==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.23.0.tgz", + "integrity": "sha512-o4QI2KU/QbP7ZExMse6ULotdV3oJUYMrdx3rBZCgUF3ur3gJPfe8Fuasn6tia16c5kZBBw0aTmaUygad6VB/hQ==", "cpu": [ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.0.tgz", - "integrity": "sha512-EHmPnPWvyYqncObwqrosb/CpH3GOjE76vWVs0g4hWsDRUVhg61hBmlVg5TPXqF+g+PvIbqkC7i3h8wbn4Gp2Fg==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.23.0.tgz", + "integrity": "sha512-+bxqx+V/D4FGrpXzPGKp/SEZIZ8cIW3K7wOtcJAoCrmXvzRtmdUhYNbgd+RztLzfDEfA2WtKj5F4tcbNPuqgeg==", "cpu": [ "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.0.tgz", - "integrity": "sha512-tsSWy3YQzmpjDKnQ1Vcpy3p9Z+kMFbSIesCdMNgLizDWFhrLZIoN21JSq01g+MZMDFF+Y1+4zxgrlqPjid5ohg==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.23.0.tgz", + "integrity": "sha512-I/eXsdVoCKtSgK9OwyQKPAfricWKUMNCwJKtatRYMmDo5N859tbO3UsBw5kT3dU1n6ZcM1JDzPRSGhAUkxfLxw==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.0.tgz", - "integrity": "sha512-anr1Y11uPOQrpuU8XOikY5lH4Qu94oS6j0xrulHk3NkLDq19MlX8Ng/pVipjxBJ9a2l3+F39REZYyWQFkZ4/fw==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.23.0.tgz", + "integrity": "sha512-4ZoDZy5ShLbbe1KPSafbFh1vbl0asTVfkABC7eWqIs01+66ncM82YJxV2VtV3YVJTqq2P8HMx3DCoRSWB/N3rw==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.0.tgz", - "integrity": "sha512-7LB+Bh+Ut7cfmO0m244/asvtIGQr5pG5Rvjz/l1Rnz1kDzM02pSX9jPaS0p+90H5I1x4d1FkCew+B7MOnoatNw==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.23.0.tgz", + "integrity": "sha512-+5Ky8dhft4STaOEbZu3/NU4QIyYssKO+r1cD3FzuusA0vO5gso15on7qGzKdNXnc1gOrsgCqZjRw1w+zL4y4hQ==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.0.tgz", - "integrity": "sha512-+3qZ4rer7t/QsC5JwMpcvCVPRcJt1cJrYS/TMJZzXIJbxWFQEVhrIc26IhB+5Z9fT9umfVc+Es2mOZgl+7jdJQ==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.23.0.tgz", + "integrity": "sha512-0SPJk4cPZQhq9qA1UhIRumSE3+JJIBBjtlGl5PNC///BoaByckNZd53rOYD0glpTkYFBQSt7AkMeLVPfx65+BQ==", "cpu": [ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.0.tgz", - "integrity": "sha512-YdicNOSJONVx/vuPkgPTyRoAPx3GbknBZRCOUkK84FJ/YTfs/F0vl/YsMscrB6Y177d+yDRcj+JWMPMCgshwrA==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.23.0.tgz", + "integrity": "sha512-lqCK5GQC8fNo0+JvTSxcG7YB1UKYp8yrNLhsArlvPWN+16ovSZgoehlVHg6X0sSWPUkpjRBR5TuR12ZugowZ4g==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -6614,6 +6757,7 @@ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", "dev": true, + "license": "MIT", "dependencies": { "@types/connect": "*", "@types/node": "*" @@ -6624,6 +6768,7 @@ "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -6633,6 +6778,7 @@ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -6642,6 +6788,7 @@ "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", "dev": true, + "license": "MIT", "dependencies": { "@types/express-serve-static-core": "*", "@types/node": "*" @@ -6671,9 +6818,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", "dev": true, "license": "MIT" }, @@ -6682,6 +6829,7 @@ "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", @@ -6690,10 +6838,24 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.19.5", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", - "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.0.tgz", + "integrity": "sha512-AbXMTZGt40T+KON9/Fdxx0B2WK5hsgxcfXJLr5bFpZ7b4JCex2WyQPTEKdXqfHiY5nKKBScZ7yCoO6Pvgxfvnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/express/node_modules/@types/express-serve-static-core": { + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", + "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -6715,7 +6877,8 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/http-proxy": { "version": "1.17.15", @@ -6797,6 +6960,7 @@ "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -6833,7 +6997,8 @@ "version": "0.12.2", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/selenium-webdriver": { "version": "3.0.26", @@ -6858,6 +7023,7 @@ "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", "dev": true, + "license": "MIT", "dependencies": { "@types/express": "*" } @@ -6867,6 +7033,7 @@ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", "dev": true, + "license": "MIT", "dependencies": { "@types/http-errors": "*", "@types/node": "*", @@ -6885,6 +7052,7 @@ "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -6908,6 +7076,7 @@ "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", "integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -7450,6 +7619,7 @@ "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.1.0.tgz", "integrity": "sha512-wO4Dk/rm8u7RNhOf95ZzcEmC9rYOncYgvq4z3duaJrCgjN8BxAnDVyndanfcJZ0O6XZzHz6Q0hTimxTg8Y9g/A==", "dev": true, + "license": "MIT", "engines": { "node": ">=14.6.0" }, @@ -7883,6 +8053,7 @@ "engines": [ "node >= 0.8.0" ], + "license": "Apache-2.0", "bin": { "ansi-html": "bin/ansi-html" } @@ -7991,7 +8162,8 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/array-ify": { "version": "1.0.0", @@ -8460,7 +8632,8 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/bcrypt-pbkdf": { "version": "1.0.2", @@ -8591,6 +8764,7 @@ "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "multicast-dns": "^7.2.5" @@ -8775,6 +8949,7 @@ "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", "dev": true, + "license": "MIT", "dependencies": { "run-applescript": "^7.0.0" }, @@ -9498,6 +9673,7 @@ "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", "dev": true, + "license": "MIT", "dependencies": { "mime-db": ">= 1.43.0 < 2" }, @@ -9510,6 +9686,7 @@ "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", "dev": true, + "license": "MIT", "dependencies": { "accepts": "~1.3.5", "bytes": "3.0.0", @@ -9528,6 +9705,7 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -9537,6 +9715,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -9545,13 +9724,15 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/compression/node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/concat-map": { "version": "0.0.1", @@ -9581,6 +9762,7 @@ "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8" } @@ -9607,6 +9789,7 @@ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" }, @@ -9894,7 +10077,8 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cookiejar": { "version": "2.1.4", @@ -10075,6 +10259,7 @@ "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.24.tgz", "integrity": "sha512-Oyqew0FGM0wYUSNqR0L6AteO5MpMoUU0rhKRieXeiKs+PmRTxiJMyaunYB2KF6fQ3dzChXKCpbFOEJx3OQ1v/Q==", "dev": true, + "license": "Apache-2.0", "dependencies": { "chalk": "^4.1.0", "css-select": "^5.1.0", @@ -10090,6 +10275,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -10105,6 +10291,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -10121,6 +10308,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -10132,13 +10320,15 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/critters/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -10148,6 +10338,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -10231,6 +10422,7 @@ "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", @@ -10901,6 +11093,7 @@ "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", "dev": true, + "license": "MIT", "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" @@ -10917,6 +11110,7 @@ "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", "dev": true, + "license": "MIT", "engines": { "node": ">=18" }, @@ -10929,6 +11123,7 @@ "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "execa": "^5.0.0" }, @@ -10941,6 +11136,7 @@ "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, + "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -10964,6 +11160,7 @@ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -10976,6 +11173,7 @@ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=10.17.0" } @@ -10984,7 +11182,8 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/defaults": { "version": "1.0.4", @@ -11021,6 +11220,7 @@ "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -11165,7 +11365,8 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/dezalgo": { "version": "1.0.4", @@ -11213,6 +11414,7 @@ "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", "dev": true, + "license": "MIT", "dependencies": { "@leichtgewicht/ip-codec": "^2.0.1" }, @@ -11251,6 +11453,7 @@ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "dev": true, + "license": "MIT", "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", @@ -11278,6 +11481,7 @@ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "domelementtype": "^2.3.0" }, @@ -11293,6 +11497,7 @@ "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", @@ -11761,6 +11966,7 @@ "integrity": "sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==", "dev": true, "hasInstallScript": true, + "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -12467,6 +12673,7 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -12550,6 +12757,7 @@ "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", "dev": true, + "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", @@ -12592,6 +12800,7 @@ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -12601,6 +12810,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -12610,6 +12820,7 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -12619,6 +12830,7 @@ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dev": true, + "license": "MIT", "dependencies": { "debug": "2.6.9", "encodeurl": "~2.0.0", @@ -12636,13 +12848,15 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/express/node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -12776,6 +12990,7 @@ "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", "dev": true, + "license": "Apache-2.0", "dependencies": { "websocket-driver": ">=0.5.1" }, @@ -13066,6 +13281,7 @@ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -13089,6 +13305,7 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -13724,7 +13941,8 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/handlebars": { "version": "4.7.8", @@ -13986,6 +14204,7 @@ "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", "dev": true, + "license": "MIT", "dependencies": { "inherits": "^2.0.1", "obuf": "^1.0.0", @@ -13997,13 +14216,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/hpack.js/node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, + "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -14018,13 +14239,15 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/hpack.js/node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" } @@ -14043,7 +14266,8 @@ "type": "patreon", "url": "https://patreon.com/mdevils" } - ] + ], + "license": "MIT" }, "node_modules/html-escaper": { "version": "2.0.2", @@ -14064,6 +14288,7 @@ "url": "https://github.com/sponsors/fb55" } ], + "license": "MIT", "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", @@ -14082,7 +14307,8 @@ "version": "1.2.7", "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/http-errors": { "version": "2.0.0", @@ -14115,7 +14341,8 @@ "version": "0.5.8", "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/http-proxy": { "version": "1.18.1", @@ -14209,6 +14436,7 @@ "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.18" } @@ -14551,6 +14779,7 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10" } @@ -14688,6 +14917,7 @@ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", "dev": true, + "license": "MIT", "bin": { "is-docker": "cli.js" }, @@ -14736,6 +14966,7 @@ "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", "dev": true, + "license": "MIT", "dependencies": { "is-docker": "^3.0.0" }, @@ -14783,6 +15014,7 @@ "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz", "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==", "dev": true, + "license": "MIT", "engines": { "node": ">=16" }, @@ -15049,6 +15281,7 @@ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", "dev": true, + "license": "MIT", "dependencies": { "is-inside-container": "^1.0.0" }, @@ -16025,6 +16258,7 @@ "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.9.1.tgz", "integrity": "sha512-Gcnl4Bd+hRO9P9icCP/RVVT2o8SFlPXofuCxvA2SaZuH45whSvf5p8x5oih5ftLiVhEI4sp5xDY+R+b3zJBh5w==", "dev": true, + "license": "MIT", "dependencies": { "picocolors": "^1.0.0", "shell-quote": "^1.8.1" @@ -16986,6 +17220,7 @@ "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.12.0.tgz", "integrity": "sha512-74wDsex5tQDSClVkeK1vtxqYCAgCoXxx+K4NSHzgU/muYVYByFqa+0RnrPO9NM6naWm1+G9JmZ0p6QHhXmeYfA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@jsonjoy.com/json-pack": "^1.0.3", "@jsonjoy.com/util": "^1.3.0", @@ -17184,6 +17419,7 @@ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/sindresorhus" } @@ -17370,7 +17606,8 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/minimatch": { "version": "9.0.5", @@ -17632,6 +17869,7 @@ "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" } @@ -17681,6 +17919,7 @@ "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", "dev": true, + "license": "MIT", "dependencies": { "dns-packet": "^5.2.2", "thunky": "^1.0.2" @@ -17884,6 +18123,7 @@ "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "!win32" @@ -17911,6 +18151,7 @@ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", "dev": true, + "license": "MIT", "optional": true }, "node_modules/node-fetch": { @@ -17939,6 +18180,7 @@ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", "dev": true, + "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { "node": ">= 6.13.0" } @@ -17973,6 +18215,7 @@ "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.2.tgz", "integrity": "sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==", "dev": true, + "license": "MIT", "optional": true, "bin": { "node-gyp-build": "bin.js", @@ -18537,7 +18780,8 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/on-finished": { "version": "2.4.1", @@ -18557,6 +18801,7 @@ "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -18591,6 +18836,7 @@ "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", "dev": true, + "license": "MIT", "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", @@ -18716,9 +18962,9 @@ } }, "node_modules/ordered-binary": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.5.1.tgz", - "integrity": "sha512-5VyHfHY3cd0iza71JepYG50My+YUbrFtGoUz2ooEydPyPM7Aai/JW098juLr+RG6+rDJuzNNTsEQu2DZa1A41A==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.5.2.tgz", + "integrity": "sha512-JTo+4+4Fw7FreyAvlSLjb1BBVaxEQAacmjD3jjuyPZclpbEghTvQZbXBb2qPd2LeIMxiHwXBZUcpmG2Gl/mDEA==", "dev": true, "license": "MIT" }, @@ -18802,6 +19048,7 @@ "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.0.tgz", "integrity": "sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA==", "dev": true, + "license": "MIT", "dependencies": { "@types/retry": "0.12.2", "is-network-error": "^1.0.0", @@ -18819,6 +19066,7 @@ "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } @@ -18994,6 +19242,7 @@ "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-7.0.0.tgz", "integrity": "sha512-mazCyGWkmCRWDI15Zp+UiCqMp/0dgEmkZRvhlsqqKYr4SsVm/TvnSpD9fCvqCA2zoWJcfRym846ejWBBHRiYEg==", "dev": true, + "license": "MIT", "dependencies": { "entities": "^4.3.0", "parse5": "^7.0.0", @@ -19008,6 +19257,7 @@ "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-7.0.0.tgz", "integrity": "sha512-5A+v2SNsq8T6/mG3ahcz8ZtQ0OUFTatxPbeidoMB7tkJSGDY3tdfl4MHovtLQHkEn5CGxijNWRQHhRQ6IRpXKg==", "dev": true, + "license": "MIT", "dependencies": { "parse5": "^7.0.0" }, @@ -19097,7 +19347,8 @@ "version": "0.1.10", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/path-type": { "version": "4.0.0", @@ -19180,6 +19431,7 @@ "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.6.1.tgz", "integrity": "sha512-z30AwWGtQE+Apr+2WBZensP2lIvwoaMcOPkQlIEmSGMJNUvaYACylPYrQM6wSdUNJlnDVMSpLv7xTMJqlVshOA==", "dev": true, + "license": "MIT", "optionalDependencies": { "nice-napi": "^1.0.2" } @@ -19388,7 +19640,8 @@ "version": "0.2.3", "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/postcss-modules-extract-imports": { "version": "3.1.0", @@ -19890,6 +20143,7 @@ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "dev": true, + "license": "MIT", "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -19903,6 +20157,7 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.10" } @@ -20917,12 +21172,13 @@ "license": "Unlicense" }, "node_modules/rollup": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.0.tgz", - "integrity": "sha512-W21MUIFPZ4+O2Je/EU+GP3iz7PH4pVPUXSbEZdatQnxo29+3rsUjgrJmzuAZU24z7yRAnFN6ukxeAhZh/c7hzg==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.23.0.tgz", + "integrity": "sha512-vXB4IT9/KLDrS2WRXmY22sVB2wTsTwkpxjB8Q3mnakTENcYw3FRmfdYDy/acNmls+lHmDazgrRjK/yQ6hQAtwA==", "dev": true, + "license": "MIT", "dependencies": { - "@types/estree": "1.0.5" + "@types/estree": "1.0.6" }, "bin": { "rollup": "dist/bin/rollup" @@ -20932,22 +21188,22 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.22.0", - "@rollup/rollup-android-arm64": "4.22.0", - "@rollup/rollup-darwin-arm64": "4.22.0", - "@rollup/rollup-darwin-x64": "4.22.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.22.0", - "@rollup/rollup-linux-arm-musleabihf": "4.22.0", - "@rollup/rollup-linux-arm64-gnu": "4.22.0", - "@rollup/rollup-linux-arm64-musl": "4.22.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.22.0", - "@rollup/rollup-linux-riscv64-gnu": "4.22.0", - "@rollup/rollup-linux-s390x-gnu": "4.22.0", - "@rollup/rollup-linux-x64-gnu": "4.22.0", - "@rollup/rollup-linux-x64-musl": "4.22.0", - "@rollup/rollup-win32-arm64-msvc": "4.22.0", - "@rollup/rollup-win32-ia32-msvc": "4.22.0", - "@rollup/rollup-win32-x64-msvc": "4.22.0", + "@rollup/rollup-android-arm-eabi": "4.23.0", + "@rollup/rollup-android-arm64": "4.23.0", + "@rollup/rollup-darwin-arm64": "4.23.0", + "@rollup/rollup-darwin-x64": "4.23.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.23.0", + "@rollup/rollup-linux-arm-musleabihf": "4.23.0", + "@rollup/rollup-linux-arm64-gnu": "4.23.0", + "@rollup/rollup-linux-arm64-musl": "4.23.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.23.0", + "@rollup/rollup-linux-riscv64-gnu": "4.23.0", + "@rollup/rollup-linux-s390x-gnu": "4.23.0", + "@rollup/rollup-linux-x64-gnu": "4.23.0", + "@rollup/rollup-linux-x64-musl": "4.23.0", + "@rollup/rollup-win32-arm64-msvc": "4.23.0", + "@rollup/rollup-win32-ia32-msvc": "4.23.0", + "@rollup/rollup-win32-x64-msvc": "4.23.0", "fsevents": "~2.3.2" } }, @@ -20966,6 +21222,7 @@ "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=18" }, @@ -21251,7 +21508,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/selenium-webdriver": { "version": "3.6.0", @@ -21325,6 +21583,7 @@ "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", "dev": true, + "license": "MIT", "dependencies": { "@types/node-forge": "^1.3.0", "node-forge": "^1" @@ -21351,6 +21610,7 @@ "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, + "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -21375,6 +21635,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -21383,13 +21644,15 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/send/node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, + "license": "MIT", "bin": { "mime": "cli.js" }, @@ -21401,13 +21664,15 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/send/node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -21427,6 +21692,7 @@ "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", "dev": true, + "license": "MIT", "dependencies": { "accepts": "~1.3.4", "batch": "0.6.1", @@ -21445,6 +21711,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -21454,6 +21721,7 @@ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -21463,6 +21731,7 @@ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", "dev": true, + "license": "MIT", "dependencies": { "depd": "~1.1.2", "inherits": "2.0.3", @@ -21477,25 +21746,29 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/serve-index/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/serve-index/node_modules/setprototypeof": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/serve-static": { "version": "1.16.2", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dev": true, + "license": "MIT", "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", @@ -21511,6 +21784,7 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -21642,6 +21916,7 @@ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -21946,6 +22221,7 @@ "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", "dev": true, + "license": "MIT", "dependencies": { "faye-websocket": "^0.11.3", "uuid": "^8.3.2", @@ -21957,6 +22233,7 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true, + "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } @@ -22111,6 +22388,7 @@ "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^4.1.0", "handle-thing": "^2.0.0", @@ -22127,6 +22405,7 @@ "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^4.1.0", "detect-node": "^2.0.4", @@ -22929,6 +23208,7 @@ "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", "integrity": "sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==", "dev": true, + "license": "Unlicense", "engines": { "node": ">=10.18" }, @@ -22957,7 +23237,8 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/tmp": { "version": "0.2.3", @@ -23048,6 +23329,7 @@ "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.2.tgz", "integrity": "sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=10.0" }, @@ -23832,6 +24114,7 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.6.tgz", "integrity": "sha512-IeL5f8OO5nylsgzd9tq4qD2QqI0k2CQLGrWD0rCN0EQJZpBK5vJAx0I+GDkMOXxQX/OfFHMuLIx6ddAxGX/k+Q==", "dev": true, + "license": "MIT", "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", @@ -23894,6 +24177,7 @@ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "aix" @@ -23910,6 +24194,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -23926,6 +24211,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -23942,6 +24228,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -23958,6 +24245,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -23974,6 +24262,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -23990,6 +24279,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -24006,6 +24296,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -24022,6 +24313,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -24038,6 +24330,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -24054,6 +24347,7 @@ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -24070,6 +24364,7 @@ "loong64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -24086,6 +24381,7 @@ "mips64el" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -24102,6 +24398,7 @@ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -24118,6 +24415,7 @@ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -24134,6 +24432,7 @@ "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -24150,6 +24449,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -24166,6 +24466,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "netbsd" @@ -24182,6 +24483,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "openbsd" @@ -24198,6 +24500,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "sunos" @@ -24214,6 +24517,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -24230,6 +24534,7 @@ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -24246,6 +24551,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -24260,6 +24566,7 @@ "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -24311,6 +24618,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.1.0", @@ -24349,6 +24657,7 @@ "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", "dev": true, + "license": "MIT", "dependencies": { "minimalistic-assert": "^1.0.0" } @@ -24643,6 +24952,7 @@ "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.4.2.tgz", "integrity": "sha512-xOO8n6eggxnwYpy1NlzUKpvrjfJTvae5/D6WOK0S2LSo7vjmo5gCM1DbLUmFqrMTJP+W/0YZNctm7jasWvLuBA==", "dev": true, + "license": "MIT", "dependencies": { "colorette": "^2.0.10", "memfs": "^4.6.0", @@ -24672,6 +24982,7 @@ "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.0.4.tgz", "integrity": "sha512-dljXhUgx3HqKP2d8J/fUMvhxGhzjeNVarDLcbO/EWMSgRizDkxHQDZQaLFL5VJY9tRBj2Gz+rvCEYYvhbqPHNA==", "dev": true, + "license": "MIT", "dependencies": { "@types/bonjour": "^3.5.13", "@types/connect-history-api-fallback": "^1.5.4", @@ -24731,6 +25042,7 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, + "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", @@ -24751,6 +25063,7 @@ "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", "dev": true, + "license": "MIT", "dependencies": { "@types/http-proxy": "^1.17.8", "http-proxy": "^1.18.1", @@ -24775,6 +25088,7 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", "dev": true, + "license": "ISC", "dependencies": { "glob": "^10.3.7" }, @@ -24921,6 +25235,7 @@ "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", @@ -24935,6 +25250,7 @@ "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=0.8.0" } diff --git a/ui/package.json b/ui/package.json index 2e1c9fe4481..fdacf2654a7 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,6 +1,6 @@ { "name": "openems-ui", - "version": "2024.10.0-SNAPSHOT", + "version": "2024.10.0", "license": "AGPL-3.0", "private": true, "dependencies": { diff --git a/ui/src/app/changelog/view/component/changelog.constants.ts b/ui/src/app/changelog/view/component/changelog.constants.ts index 700da6a26cb..99abdf46dd4 100644 --- a/ui/src/app/changelog/view/component/changelog.constants.ts +++ b/ui/src/app/changelog/view/component/changelog.constants.ts @@ -2,7 +2,7 @@ import { Role } from "src/app/shared/type/role"; export class Changelog { - public static readonly UI_VERSION = "2024.10.0-SNAPSHOT"; + public static readonly UI_VERSION = "2024.10.0"; public static product(...products: Product[]) { return products.map(product => Changelog.link(product.name, product.url)).join(", ") + ". "; From 8c8cba5df483ef7773bc822e97b5cb175a015a8c Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Tue, 1 Oct 2024 11:49:08 +0200 Subject: [PATCH 151/173] Start development of version 2024.11.0-SNAPSHOT --- io.openems.common/src/io/openems/common/OpenemsConstants.java | 4 ++-- ui/package-lock.json | 4 ++-- ui/package.json | 2 +- ui/src/app/changelog/view/component/changelog.constants.ts | 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 9b7384aae62..b27257da16a 100644 --- a/io.openems.common/src/io/openems/common/OpenemsConstants.java +++ b/io.openems.common/src/io/openems/common/OpenemsConstants.java @@ -22,7 +22,7 @@ public class OpenemsConstants { *

      * This is the month of the release. */ - public static final short VERSION_MINOR = 10; + public static final short VERSION_MINOR = 11; /** * The patch version of OpenEMS. @@ -36,7 +36,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 fca2ca8fb74..2dd132f8d58 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "openems-ui", - "version": "2024.10.0", + "version": "2024.11.0-SNAPSHOT", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "openems-ui", - "version": "2024.10.0", + "version": "2024.11.0-SNAPSHOT", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "18.2.5", diff --git a/ui/package.json b/ui/package.json index fdacf2654a7..d1e7e5250b9 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,6 +1,6 @@ { "name": "openems-ui", - "version": "2024.10.0", + "version": "2024.11.0-SNAPSHOT", "license": "AGPL-3.0", "private": true, "dependencies": { diff --git a/ui/src/app/changelog/view/component/changelog.constants.ts b/ui/src/app/changelog/view/component/changelog.constants.ts index 99abdf46dd4..054d54208cc 100644 --- a/ui/src/app/changelog/view/component/changelog.constants.ts +++ b/ui/src/app/changelog/view/component/changelog.constants.ts @@ -2,7 +2,7 @@ import { Role } from "src/app/shared/type/role"; export class Changelog { - public static readonly UI_VERSION = "2024.10.0"; + public static readonly UI_VERSION = "2024.11.0-SNAPSHOT"; public static product(...products: Product[]) { return products.map(product => Changelog.link(product.name, product.url)).join(", ") + ". "; From 4e6597baa91f17fc05c56e033e6c2133b2d1116e Mon Sep 17 00:00:00 2001 From: "Kai J." Date: Mon, 7 Oct 2024 20:56:38 +0200 Subject: [PATCH 152/173] Docs: add docker deploy documentation (#2829) --- .../deploy-docker-backend-check-version.png | Bin 0 -> 8163 bytes .../assets/images/deploy-docker-backend.png | Bin 0 -> 11314 bytes .../deploy-docker-edge-check-version.png | Bin 0 -> 4834 bytes .../ROOT/assets/images/deploy-docker-edge.png | Bin 0 -> 8516 bytes .../ROOT/assets/images/deploy-docker-ssh.png | Bin 0 -> 3581 bytes doc/modules/ROOT/pages/backend/deploy.adoc | 89 +++++++++++++++++- doc/modules/ROOT/pages/edge/deploy.adoc | 75 ++++++++++++++- 7 files changed, 159 insertions(+), 5 deletions(-) create mode 100644 doc/modules/ROOT/assets/images/deploy-docker-backend-check-version.png create mode 100644 doc/modules/ROOT/assets/images/deploy-docker-backend.png create mode 100644 doc/modules/ROOT/assets/images/deploy-docker-edge-check-version.png create mode 100644 doc/modules/ROOT/assets/images/deploy-docker-edge.png create mode 100644 doc/modules/ROOT/assets/images/deploy-docker-ssh.png diff --git a/doc/modules/ROOT/assets/images/deploy-docker-backend-check-version.png b/doc/modules/ROOT/assets/images/deploy-docker-backend-check-version.png new file mode 100644 index 0000000000000000000000000000000000000000..351a863a1977de79f5430427b124bff0012e1ce9 GIT binary patch literal 8163 zcmai(Wl&sC(C%?}32wn%gG+D?usDRE!QFRp*WinW;2KEc92^|BvXYz@92^2F>|F{C1$Or&ahQWW;61by zW#DS2DGy;CBpc}u(r|F~iI~sk$gn=TtCFDy930NTzYBiErTjA-91T!ePFe?Oa`Fu` ziTGDmFz&$QIRSw7EiTAble!Quojg^WMVLW6@tXmLT4xo4hGSq+W5Z+;z5x8KNKYmap9 zPFBliie?^Wf?luw2r5!}>3jna$-~-3#bsh_Aq%YG=;Hi0Vi(MY`rnAa`!vLVCIIsM z@sR&aur(p?0q&*8NfSBRMDlhum-r8HIEnewB6qhwO(!j_*(FINrs6%lX{M=^-Qjly3~s&^m__p z8#}5~`^tONRZC{5Ojh~RLVNXVBA@2VuYvex;lK>p!#;AETvpDnCYIec>N(F%c1sYs z1K|UsCui9gv2l$Iu1}K(Qc#e`B=5+*KAU2T^SZGy5hH6};A6!~gH;?zzaT!=IwW=Sr1ym?PnE zUcZaS!h4WuVyG!v;&9YsjD8sY``W%WdIvoqXtX&#J9(g)`Y3g1CmCqj-BD(l$iEH%fOmke4+pxuEcA@5sF^LP zNrR@~yyEQ)nF1c1E{FBiT-}| zOlOnR)Xd~Gt|J|K-Nn+TV31K@$;0jr>ucIy^GiK~l*cfEKvl-LI-r6_X4Fs0Q8B42 z4)!Fb&dyyUWsJZy{3{;IKTb2}-1oC$lINJUyk8K5-kJW0k9F}b>l454d^x#eJG4T5 zv5brit8{85@$(=+iyChBja*u8hXy%O9JFn;y%*04CS{^jAnj-1x_)$U3fsIrb8OAK zdaZm~euT!@M6eKZV5!B5pH~G8-@U}WLFZ;O8G6HQ}0%4%>WS6w4Ij1 z?RG|sw)h78okw|>EL>SxyHt&Lwb_aP>cFq-V!wZE-c*pPJ@7_5iMwXX9LvZ}h#?aaE&Q znYxLUEnBWyAh@;bZo_Yy;e+HSw;^IK({S#9L)BNq3F*sAp`M5Mwuk+%FO}Ga?Vc4A zm1O+ZI^t4oiI?t26?*x|294J7jc9UdA5Lu$EHYagC>fO7(y#G@F0GgA%uD_5PEVzt zU++hxyxp9to2sj;UwojQ_)flt1ya+3?|T|gKO8&GWDOUb*e%9ilAnnl_ve$&YU&t5 z1@`Z&8?BO$jl;q!|K8kndgQy=%`d%54GJQtp1e?;yqMM{M4sFFon+iDPro*w2~u)h zR5iqt5aL-8yp6XJ{=&nhc3f*8OfucK`P)@*S?c$)L-QozVhD4mpK8Gr-IF6Y%l>#% zFgi4xgt*q?)#I?q>vT)?mime73wBf_A?6TWrOvOD>r;}sNPU&=CUeq&vu)ru&Crkp zOXPF|=Zfd)+RDPOUs+UQ-mU&evjt(GyLF!r zy1HpAU4AVf*c1UYoKZcmH?`LN;pkkPfQz2z%ZX0|Gk)=pQZvusOVHo?k?bWCzbV!? z;Vl7A-u$jx@A-k}W><5n+*zMGydNaRS@OF4?!51|ai~N;i+cYhHB1j<;9N>&*6@aq zl>|R6)_giXt*ogLe0jPPvdIONf?(cw>G(*497X(x>hvLdNxN($YS+I9T2pCB{ zFukUKwsf1%J5ppk7((M4t;QzaG~8p`=UWHmrO0dP+!RQXj%MC{-LX|tDToiqrC_Ub z6R#W14O)$KNyFWd-6cX{EL*?(a(Ew<>j2GP8hA6`alKRd2pZv7x#N_Qs-~~z%5A>* zjBc|CPT?*#++mCtR&0xmYjFM?VSC-naleoB263Ol^GIYItLsuid%ivjssZY?cz@;s z3*PEz^A2S~$}>2ObU40x*Y_sCZRDlpU0hh`T@sl!&YlI1zG@hB+0erlqG+To@3>Xc^RvQqkL=9#e-=5TWy?j?_Z?{tscS3*`&S5LYKM%g*B0UBQSh$5n=3PY z65{`Rl&F?hfAZAuuJv)V+co_`Ajqo52U>eqHy&pBlV5I5C z=0j-F+*O>xpayQi`w*Qor)S#Dm$q5rMS9?YJHuG`*%5w_#saY3PcGm}+Wxr2n?qz! z{~(>%pef9W?K{g8_zd*H>hCB~lk1A>ylRB)yi=uGDXhRo!C%arOa0m!62DkJJl&pL z%@}dZv!hsf2hb( z#=>MuUsOW%W(?T6Qe^rgT*$9Q{c^=NFGd*mXJ0iwv=r#KmP8^zY5c|oTKZ|(HSsb% zN9~cT(1Jr}cjGqg@w|-`zL0Jwln4T^gKf8XFBBfqOvt;+dHA|1f3b6>p9S7^$g`pd zyuVIpOWbhJgiK^~6b)A331IcP^5AC-s7(TI#?#m_Md^-u@^=m0IEz2Gyghw~vV8Yonc%h@ua}dc{hLfTwdOe4eIkJ) zw`PP<+^V_SF17GfF)=2R)s4dl_FDO0huDxhCLc{-i%zCyJV!L7d|^q20ikQo z{DjS=*PSqewIHXXCv3yG&VJI-Z%LCE=RC>ARZ9j_YW zCE@W3r6*d+U6WfIpu;8BeBOr0d{lLv+U|q+vU0ME7Qs`%}0Db z$5~^)8I^fQ|HD=5`J=P8Tya-_m!BC^%xB`}x2uulBOsBCHyA85G}V{s8=jKpRbtli zZIihc1k(iM#7w*hy93wO^Y7_@=Xg(9I!X%bQA5JZp`kSuX~Gs%XgHi^dS!I#-|xZn zQp!=2isr)hGr1D#0JC=pmX9Fq1o!p17+suY^dxjIwfB~9$tOl*>rob*?h+>L^~Z5N zXoE$lRpw_s5*yGQf!^sKjiPtOxtnVP7N}O<@y3bZ%r$ZhW95Xil+a@mvZwyk#EZVm z5%GAgj5qArph!uMadG2v7BO{*QpjjS=4+yr#n?9K(mZ^Y6WLl}!QfCvn#TNq$APNY zPZ_EO`;DV0RE#fWiU28;K;Y#)KDMgxL`>D1@B&cyB06+~Ng}~L!IY_FS;4f5%+9Qh z82oq=u5SVwqS}o_+w;}I)vAek5M{+;&9|+)r6Tko`Vu#fsSu;&U~XG&CXrNt3}V)h zqLQdB5rHuK5u23+r>b8v*OoARXp{WsgF%Ge-;X>IObmP|)9&)=OA#3zKPRRfc8o>r zJgS1Ukowxtz4+#(1e9Br{bR=OnqS@Lw&pbGoPf&74VJ&3Mwmw5=1xwQjr83!c9rZS z#7aYB65ko&(~WxV(|(38wG5Ytmjynj55KK}H|sP~ds0Kg3Z+>b9f&1%1pdTZ=?V5L z1UFiYB*!3{7txwoBxvImlT6~t5lsQ4Cka6`Se!h?ctR_hu=KDZ50DN&Zn#K;q^ez$ z=(!^#{W$n4vSE+=QWe~MHWBc_EuZ%tzeIu4?W)74Dzg@e-E##cC(&g;gE?Tf*9a&O zKy*GaCzngIu`pa6T8A<8ioD^{Z&Ac}Ds|q2UE7B3h2Xb_r#GeJM|mg`DF93tu?=c8 zCtRx9l%<=<4k!E3mvH5wG5{4`G`4?PzOJ9tC~y1jmTiBJ5;j$|Wi72cvU>2lwY~M% z@68t{O0I@7ec%IW8aM65-fOdFAlw$1KWq-SHQ}5q6 z4Kwv_`8iv)-s#v&YzW(zDFV6DH9fDs&`A{N81w!RiRpEaZh8@_8qYW1c)o8M!b_e~ zH^Nzs*c$YNo&umVpF+^yU0LRo~!Js{68U$6$)bnC(Cy?P*iGO|-c$?pW$5*_u*)rvcx{8=%GWl0)ga{5d)czX^!cV98zS>m7T~P2 zo1!98cTxGkeAXtsG-~kOv9|HmsAFITKSdx^!22(2uX=)0wTCHnRsCI63)JiOGBmQr zH>Jz^YTL|gmouUf73@x^H*VJAqOjuNzFYSKVl-KdKdnVm2a z(8r20$y=>iN!haTMa1?FyIomKOh{RiOvP->+q8+AD zLFvyxA+J=UtcqgB@=lOdrp2Np?D~_n5d?jS_wI}%tXoqQ*A&3}vrWY)W=BQtsiqaaa%N^P ze~^?hOMSb7&*NNJ`0zQjBaIbFNI9obe5 zf(Xx{`is<$vq_EzOGaln;Op-eNi1tyUfhhM7M)N#$J4WJ#w43SlmQEm8g~wQ?9@_Y z8atvAN|vEMn`{UoU^|hEH8yD^Dg#C(<}_XN5K9C!QI=8rPml{@|G|wp8NffbVZD?W z1j#96QSp$EBL06k#OQzLBGH?Yh5$A=iX#83ubToAzSp)t#1dIm>TLrw+2kt?s(Yz7 z9ZA|9SNPU%zDEp<0ATRq&-8;y=qa#Fhy3=z#^I03Xokgc*dQ-f-bZyrnx37HNQqLf zKrS&-wyCJl@xJPojiWrO$bdQ3_1GV4cr!4$*nSpL=|0<{cVMU zS{hT#`>*R$I|*AYOPBv(Dc-^e$AtLB-dB{lSt7!js-$b{Z>3G=0BXsTkLV9tjsa-w zsF$o3-SA0~Dy3bdldFV+Y z{KAZ#yw??O%93km-s9K(%4}|xR$5i=iI`O^8U0revc*#ZZY;hL#0*kCqQSt;tBNwq z^xq~x=8xfUa+i4v59oEx{6P)c!zbDL^RsAO=vopT|po9~kFwA0kH1HX$(z((I)_e+cI@!{9&;hnI1l%6^wM zHAd^a;NYv(2XucuAHePKkc8$i3T*(38t)7K%wFI{lrbjxtW2k>6mu$P4m~Qv7G!a? z_;qffXM(F^k_sfbjYcKv>8c1O{;W{JU^K22p67eS>JzwVXwzm%YC@T6$m8txTji@o9f1@9Z_>+|@X4KC_MM4*ApCi*yQ@UzsLJXpQFj>koGln}qdNw<57| zQuF#~9yE+l4m6AsTEi%MO{OsyUr|o09o8EjgA5i`w^03YLmd&WYt!t_@#SngN9g05aLnX zddEY0$|nz~b0>m^hOgpBFcq1=tx=i&Lr>wa!Q5gTr$sm zhfT`UJEfd_4oo!uD&kSfPGNqZE*4>6To1}9&4CBWB3ta>yy4CL+2!Yx5h=dX;Zqy5 zC{UbrouUYehu0pab!e25!7ZsTas4Sz(&pRhdt#qur7 zAlkf1m+ynVIL|K6UT++x`h7k^0V|(rh+M=E;hGPbJbmBzy$KdGM;XF_yhKH$n(s@@ zx5d%A_F91|()64}&g5Mut1U}W121W{L?VG!u_9!6K&ER#Cth3w`S^fiCZ z4WuReNCD5cM(^HdhaMK%1jE_J7DLp`6nMJOV+gI{{I|1MIw8*fS!q}lf{v~u7D?vf zzG|TNl4{>Xf2H-IQUiN?eE0gpo6X45FZ)TkW9{ECRO2ca1Zun3DTUhQQ}Z5DlI1Zf zL;STs>F<<}I2kUMbY8>`i&NK+Q3YK54%cO2q@TyZtTjn<$5kLQ-3UkyQY8u*_(#gIPM zYaU(@3ecq^f^jLkI_@@uda58DC3w0f#m?3eH1ymoVV-a-+UAhRCKQTqRZ46JjVU&E zN=7cKHyNd`F~4Y?4wwibv}oBl+|(WhIu-^WF#r_a`6048+^q&YoWw<>=MA&bZQLsJ z#@+sHVk$Wp(y~NYQP{GshIH7{25@6Z{q0`I&+JhZa*umm<~y>|19JebIdG#)k}0Sc z%VGx#gB8Q+KY6ax&j+437BvW1#0)I)Hug{nvz>chynQ~|jlvMrdVR_MR5U*QT73?L zRgFL-uS8r`HpLgSTL|M+h;4X{c92(YXW{bBmECBv_F5>C51;Utsb1 zOi4xPxqQJFD^LCw-br}Egzqrv;@m8ZT^2*F6D8vOA*DL;StV5hBcy6O2!!tidKx+9dO{5CFz6OT zwq_Bmy~uZpW0geaMvM^`*9uwkAG9<9L_CQRBj{K8ln@T=J^0;`Yc!Rt`)KzFcclle zyG(o14c3bieLZ!DBrTCka&>lQ2zcqg_#+)#9c1xt)Lv4{0up>d$h%$l&Amd7Sb>k0 zvl9-9#f`n`Vc_xRcs)7BTTLa-!`5XA9s_Mx_x}sQ>jKJiM; zYRze~OE%<4``~IF_K>|@-Vw^(gxDxFha+p%&oI(_YT)eQpTywaopQ-x*Y!brb71h7 zR6SlkY4k5zVKU}$AeCV!CL=F zI@?{d3Yn?$JT{^|nCEj1fN}gGiB5JcS=o{kKZ`%PY%W7?T3;oXvAV_X$d4%Eh{k*t z@TGx#lt3ZfAw%UYBzTaoIkEW}R=arAml#FjJ&F3kXu^gbOw6v=YKeD9?4|*JC|-7R z*m=MFnVjiF7+KnP9ZOmcFdD9n&JaXuWTq5yP0Yu8@J*6Dl4Sz!Ou}J1wKNA3kA^{1 z%n&LgD3OwNG1T9&^)25(6L)7EUh~Zkx#tm;4B57^k_anfXH~D35;GiV@ZM1*MoUgH zf$}f`kQ!0)fBD1sLXGXNoYxfa`8U&46}Pbtx0{X_1OIAG?SGWmUbqk?g@v& zA~hyi?~B|cmv%y{5OIPi!@rc0$ch&}Uq~$h1-VnEf|iFc;@^zirVjG2!ChS%c8^K$ z;dFW&sAp)D-2PRG7-J1*J?QJlW16|feX}GxY^wU#hkgY739^Ou{7nzAzgYnS!*`Jia2r?0E)Cg8^^A1GY zzRVKX<8as#OS?xMnkqoNyNwG)!;tbj>TvYh&LFfipJZY!lVZpDRyxd)FJ!wlBWVtH z4EK2@-e9Z6_S6|;`Yr&3!!7`=zhkG1H#y7K9MZWO&0)Xxafj6k>^tpOwqY@x7-vJC zGWt+_$?;#pl=`Up5&Gu-$w^azC2v&vHYMLVpOgWB^Lue|@wFpp1I-t{%CJmx8!aiL z9;P)tMyPxi*s;w8T{avAoqm7zy*oWI!RjZ!`sn5LBThJr1T`%hVgp0aK1{ag6pa|$ z>oCD%y;Sq*b)9;0XP;VtrQ3wbmF6N}28OX0bd$C)cZ23aO$9i1l#Cx>eA{{H*tp?y zOwgS<>FRdGm~Y^v{Bxa7Ne&i`pGbwR8N$Nj8X*fDCY{TlNK(=p$5NR)c={p8JL6hf25btQ(LKeC<3s4a z;euy5*I=XOXlSe3?oo>aBNVS3Fe>T>3JQitH(}M=yT}Gm?emACfz&kZ~Xw7qfk9fP6sv&Bw(OEQZ zIQNK$WT>1;Ab1mcCli2<8-k}H8n8gWFMzM{naA(O@`bju>L@HpZkjpGMj2-A`*p$e z_oHIBt5hI*Ugt_rP>(8MV5;V*h=)6C6<`nJs~ITu*Jj&t$>WG~s6(ZIOa9t+ zykf8~epQR|hMyK}YbFyLk=}xI32b2;K1d&pPkdhpS8j%!+lFpGd!e}UgsL7Cr`hA*k2i{ z-FBAgmUUw_IRl0_W1ENNH?sZqvBtZ8Lkr-nlk2Hg%*nJ9`JW9=WPD){ z;s1ScZ(v0B$x%Iob*?TdL7$b0b66DMr@G1k(^d4j28(+~@f@<1<-vS3R=j zIktp^@Nx^WJ#|nv9(`Jo>0^Xz%o7;X+Lh(ERy%hfIqVKk^Vh2~yvcBDnHhuw0QFHl zyS0mZ|J~^E#aI?4w!i-D#W(=*F$jQ$j+0#jyj^?i`zl4{WtW%Imlh~tr}4#3hnX33 zUXPeAHn4|_b&F{Yy^ECWfrVF$o|xjRW`OU|BJ027oY#C&GKxJfSk-wPHu(MK6e|y2 z7OWoXu#!7d9c%+!aAsX?LN>y%;cvOGvTQds`%(hix}Z1kn+?$x&!DS=+N=3dD_0-v z`GEJ{{1p6TnEdbX#bA56Hhy}*6!Exl-LH#K-*P)Cw=E^qP`YpOY#VRc1SZq$>KZaX z(jAM$SnSq@JB6JmonX)Wp_Q%?r1lsKbV0Wkwit6omAp)Lk%ijF)}LNEyH0=n+Otu`p-bGM?7u}dR5`@jUy zD)w~oq19W54jR+&A(|v|R++keDE6ukS(kZM&@*TM5IV|wX@tFzIUB~7kFsBHrLVTG zz5g9_cka(j<;~fY6?8tDNxTEP0JaiNplLa+E~~Hi+-NY&1JCPHks<5mW1x5#(u!S|ZQXikkp0KCaaRU9oPKkc(|?3r?p>SG@re2!ZhB9L z-RjpEz$?+R4VA;n3X($C^_Sbl^X6{NYbGV8OC~>FPSCD1ww`NZzukfYV>xygpxB$R z<3-P5B_;P;=x{KDwn7uSUvO{69`0g3!}51x#l;+%MzNcr>C_h~-oXhwEAVmHLa4M> zd#{|+@9+ud#51hU{Gb-pT+(h>ACvZh`f8MNTgT%Z)3?wtn`5-ieoM9EFe~)oi0b)q zh$pY>cjjj3GfF4ZAKYA2van_9#qZF5oo4v8`YyE3gG0EB9zRQt`iyI1V%eOuR!Gym z`#mq&`R`VEfB5%^pR+?JoBNoRhq7MheBkzvtw&DB#UF3QQa5_6J#pi4o2mE}%_=K$ z;l@tp2D|p&nS{tLVoq!42ht>O+z4Q&3VU^(>`K1l!j?_bjh(#!pFgI{x$z^ttw%!& zeq>I|YVQH(?UXDX%V{4*TkQr}79HDq7c1>!_jO13`4FHKi}i(oGYig1^co_d>3xby z+;#ocUSl)sSdH7F@)^qMQBv36B}>K~Y^eiQ#sKK z(JyAcOt8af218%k4W_RJo>sz7VEU5J*kkNEVa$?qd-IJqSiIUf19;$Dr$Pc!hC0b1 zxjY+NjurDj+Rrj*^<)u?ZLI-L$SO6|z!bJg8!p5&(IX0T8#83+|FnqTx{-@NN;VdD z<;B7LPYj?NMT~F;ng@I$V$|^(6BF3ipKLvo9uOgWguGaj_L4K5q)B=y4`Mcw4R-HG zCsxHPTzY!WpX<1~@BcYZ_S?C__K7yzXk_mUJeHh`e*xEhwcR$2UBhPX>$6?fUk#d@ z&!;Xnw(ozlB80t6E?pIO9Lu-lKAL+|PKw()XWeDpcy@HzVo0DeZg}0%Y>&o7i{qU- zLWnVD48uw*RY%Wu#a&lry!$+7OE0AfGU@}fM3KKyg2;b#!4!!3N&xU)fuj+;aW z5~WRF5Qyr4YCRs&rm*r^J%+lKP}5J9faikTLrwmIMJwoMqFX%8A1675S7rCcZPX9e9`bVrcq36!?b!$`tHAP+TFz3Hem5T;!#s+4ki)o?P*4m2aS9x6<;KB6-f2L&T9b!<&XX$-Sr$zInkzs6w-Ky0pW^Eac z+fbMndzp(^Pe5+#{=UI3Q=ZK(syfgX^Q|Zw-F?{vIr5Emc#|lZ8?fJe=DU(LZbHkfAgUG@YEgkt* z^(q^2iMhR#m9_}X#`;Z?!gW7bU_XztVqH;m2o`7+c(JzE1HiaAyN|;URe;Tx5!v8!_piuIl1#`LMN3nge2X37$uSs>GWE3*}T`Of9 z)rN}@($3J{$)GnqF)q^#;&ZnRYbcz%7n=Q8J7~|gHbw@@MqCX2LrRdKM?uDOwxPzL zt4;}bhRB*!XW4W)9ZV?X^9fm3Yl#GXZ}20}_49qVmWx8aOBg|y7+t^HH8Pq$W0`EG_7$q zGtgXD;mY=;if8kna~0NRLKaQQE^~^%4uN8DtL%jByvn9CjBu^1T|33XCvCRcDFyI{ zPviQ@RVV*<8XrUdI~05*E4S`au)PB>2GnAQ-0X%jXA<-~*koNZ&1+pP3YT5NWQO>j zB=S;WcV}zQx(bjE%et8MOT}Y+mxsn$~HZNR}#ZME5Q9fFKpG3~)d+i+v(d=4od4o9ot{~GS8_}oh zr*`+P%xjzvPil4R)r--=f1KwVCgyRS!#ujT^1>>>+aN$RveGaH7tRLO?u zkt|fvZXlHqKkZ4t@#bi@+6HE|FJWQ+^8=mhN})~`o&jm6Nh#@MI1~d}OvnodcaqEU z7_jyoX|ZzN5fkMwYvlsSWqB`kg!a)YX}Sa33M9nT)G(hZ1HK6z;YQ0Y@73$F&@>a< zvXY$OW{BP*R4CIeu;GSl?!~F<7n9TL8$y`F49UN3{HP&d$)eJ6b2#>|-7?lwcA91X zq3m3(6p9;T^$iQ`-EAch^}51Zytnlm!+*y|$9xG|cBVs?1L3gz6b1n{s!;snRZIWF zU#q1QXNp>nh+(>4G7l>0U2!T9%TFM32Kqz~m%@clPkVTPkH?g<*gLEDO9Zlhr+>oy z_ZWEeg?`!`vx_tzKeIC98aT_9_|=PDqJ&Q01N&1(`*(_=v|u$Vd9<&$$@z*mu3nbC zML&xAz8mw9a#ppr)(W55Zf5K$hcVf@exJdB94o&%{9F9Z)fq3iIVXh>aI1C;|OSC7bk5QCmhpI6UxjYqfQ^00471>L4@PQ&G0p!#egqAB$9tf5D-- z24VtAzpnmw_EctkipoyDKZIBB>c=a?X0nqfns0J$SR%?b!XCJLeR)x4xtsFoXLbvT z_!@6)s=ExTsrg}ldTqf>QVxl(lZ4XaAbbURF_d85W6)^VU9R;|%KCKGye^i>$CuqqTs*DJ1&G|gp^nd>B|ncO3L`f< zXJ6Zsj@F{ZU z=q}8dEo<-g+iyJ%u3OPfz$F2+yN7zGlg4E^X;fX`JbYVE!0nvv5C&WZJ~ zo#i>@S|=bnRapB?GedqWRV{}RjME#J*p(PV;%wQxeiLh5TEnkh{2}FA)M%(m5EbRA zGl6pb21F9Q%-u>^W=ADU$Ed)Y2r<-PwLeW-djuH>qK5d*)?`Rr=(bP|d(Ai^=*&7y zf47l!{OXHAK5)iu- zb(yzB{)1>ZW1*$}e`tjNp$n)akID1yH|g3k0l7^?adM&|T-9;2azn7O{s0KJQc<5C z3W$n64gT{^-kLryY_Y zI_n0OUG(?#c%f^FVG8IRE6|z8L7SjUu&n(M8#GZCZpYSl)IY zR9fQ6LB_ty4k1D{Ih%;SOoDKQ0gT5ch$B($^nxbmbz`MucHcKc+I5qaczlc$`V#Cr zfXVeJ_E^^v9~}2PCiqze3@>pkm{NIDr0GBnI?TIQ8S=vz z`t+P>cj=d^jv2ES_c7*bzcG}Qv0>J=ad7@!CwX(s%DPky&e>RJdG~XU&M*-GT>S9L zqkkpAKsim3zlS?kaXDGkY7Y>7{-w1}&g%i;c)PwdFpEr326A#gdBEv<%MD_hzagG{ zj(xO|xw0R>TjDb#R`J`qvP!8-X?RvOUeS|8YFG=#v?TgRn$RNpbkuqiL3CUJLR|BM zL|e{tGZY~nokX`u5{>%h$fE^GfwzJdmnh*lo$N?eV~Y85AdXu5oPZ2G&f~lorqbth zW=MXwmh{4oV~K+Xp~sPaEq+P3icWfA>9|EDs(@F5eb-LF$g_wt;O!JxK3MA9J3m~( zGy?C^PehqYSgjfuawO}$P#E2W!0y{U-fKG2U!)jQj%AfC&9RWV#1U&h)e8NrV|iZu z2JV#fV_w&AD8->q`|y|_YRBN0T2?YHfdmWtMjD|21+#smFLLmSTX*xZtFpef%()^$TOv2mA|N zUd`paLAbtJXNSW{U6F+T_kmwK)GznV3Cn2Etj$5BoL_{Q+hH$8JWrzGG# zA9-PEHRfsez}`D&nLJpRddtcbP9QZY#7Vb?;4=wkcBN$R-b$o)e~FWQ=zI$ILL*&! zqc3wrg1Q+(%pZQ3*UDU%2|>{6m*P~tta4tPag+*5H2n@-dtGuJ^Xr2d^RxzvOZ&*U zK)V?VHo4y%zMDDO2d|SH<@E-)8@l{D!^qRto`*by@&Wo7fvvW8bnO&FbF0+jVUC^K zJY_AH-xbd0Ja54L0!{}S4kn^swAZUE3|C`iC=vO^^A5*~jwCzWkPb~h3x?=YWN#(V z&0#i*NnSOf^uCn*tw*gprHxH`U0=B6Il(w3-YkeApujWH{%v!Rhbe=2Mgt2J4v5ZDztn9MY~y z;1+uSf-5jq`O?AQ{rH1^O7QJPh*hYseuI0shq@ss$WI*2Y(ck1U#wdoWK#NS>t?0` z6a`KQ<^M8h0Awxu>Xm&yFsxAK~Nxg7fvF7D5KxDTy@ zm_D@FE&QHcWKq~G5)7n}Mwg7T))gr`qM}T^KR&cz`8x+at}2reyod5DFv%vp`;vO7 zDln_2OKq3{8s<(0nth&NuS6aeI9=IB6)0im^f>q>A<3UK`|QI&#glQPK-*B5V7iB% z(IjWz@$uIJp?y`NZ%zIiBsV$bTLo^jHG_*to8Kg#)(9O+^6hmL>ni5FNhR$D4v;<1 zn7<9o9dT%Bn>2`(5Xh?@>leTd!n4IO;USo(uCMr>tL{(^7i1zm;t7_hMBt8m<^r-w zm1U#724CMzm0Ij*-DQ%dX222RkrZ2+{T*(drO!ScwA=t5leD39X+)9wvYui^|1GAz zo>r6oTt29j1Cm26J-yEq$^&fX`yAa)hNkbQ4W?TK7u)vb0JEii@y|fBQ6(Otd9-&h zR@H&@TX#?r%R+%G9I`m4xViPN3#u`?Tqs|Ucy`aHy+0l|v%KJmK7q4#kzuvq98rYr zQ=Vhj2r4l>LqalFU%>IpO=gL~C$W6XXd0sCcour1YXP>l9M@X0%H~G)&nJUMGGL;g+SFM2o!+#7J5`|q6 z$u7*BeF&ka?++DYg)X>+b>SXAURDc0d?Rr({_5C)j;NIvRuxbAv;QMd)9WcU-xK+r zABmcV7>AMkW*F>5OWshFQ1WaM+L|J1#~aT{*kUT9#%e(r&GvTHEKl}(4WlCt{_Ji9 z#)x@w9yfCkA@N;&gNUTlmWT5`wfL)1x7Kq(LuRRpJ6qK|6d`#RaVfXVtTT^35=4t< z5lo8P_tu>VWO=P;D=CcLAK8q~eNsk1Gsxw31r+p-O zp=ter3^f0SY?Da2X)kP6%Sa#|U*qkg7rvq_^ZD~=U;eOS$!d$y6Z&QC zDB_|7eCwMmX@Yt)I#BvM6sZ{DIqlP6N|Deo_gT{VghIl2L z@WHT3C{?#s0^qhQ^A>GH-j~OX!0wQy@&@v;>FB(R8-7Z}hdHr|aE|qY(F$PLe_|Ty zG?yq^pUhZb97#Ff!*o?CWXI3}y5!2O3y|#gT(U^8u85_Qm6G};t zhZ{5SX(U>H{rV=+(R2|a;>29JUDEryp+s%Wk<>d)2C6dm1XZ!hExOCXOdHv;{ZQ&e zjr)jYhR+CmX~gjs87lrU^L6G=#p?deaubTERp!WJLI)J?z|PUV=~pkN9{XN!^u@FB;^98W`Pvm41Q#^?%WlM5`#=45hILzn=ipHbRq!#9`P?vJ~2T_`iMI7OviIVKN zK+7j2Nmlf)lL+W8f)w=RAns%9l=<_8{7?L{VFmmo#jJcrqL&{rap5nkDoRxa!_ymJ zRuErxq>s}*HonNHn!vUABH9YuNQ&DjWIV(_$2g*z&J$f48;Nl{Bc0_k%rLox!vz{1 zIe2P5|8{^0Xk~rU!2~NmGW5+)p`I=-ZRp?6TCie{aH(~V9IybBb$(SZn};!XI&^J^ ziZiwM+A|YXnh7DSfl(j^1Hg^fa)($0CC>lMZGUbAP1}>iAqz~PoGfIJ@pNxq;T}rS zsqwCi-R6JtwB2}J$$LydP17Rh{|`7Z%$K^}eHq;^9mLKppke1ng@H3wtn=h+eJpz7 zZ{_)m11v&@GextPi6>OH&c$3kg(AONetPO&W**R zI>5!;9oLqN_0=tYF|S8dHaP4epVDNsNUR&7MsSi#DYJ#)v3+pg`B8f+r48bv-6+sW zx$LBJNEGXx_7$W%&-IU?x93)tYQUMLW;(p$lrm!9>*VBc6vNIErH>=BOG(Jd?M|-? z^qMg1R~G1{IfTBNfJyfno9Q`pcs9;WF(N@mJ}q>#F>J86{SNM3ZcHXsLq7b|sjJ2& zdB}m2JWRRY{bYNh1>Bx=x7+DG=maH&Q~s2vEfzJ-Y5U^t4bu(YJO05TDkiG58{%)e zr3TgYlzU<-sbgo|TIb;!PK|WO>>iPCcsFfL=kIX$WKt1p?%txqvC2t7FFY45kWuQB z>qsgV>9fDEYya4R(t%MfC}V~^&n-u(kWAciYm>r93f%<728wo0OTTh9>;F`l4BgGM z*`i<`+>{CvRFY_mBhR_FMJ(|>PV4=uMBe-3x%0#=;%GpH#!_1lK6&8$-^8*G=-{p< zUk`z&qWh?0bp8=8^Wh=*qSRSzjQLT!s3YHj)6x2%QjdhwvhFYYCx8C>afb^vE*Ve` zk^RwC&vZNYJ)R}QF{wlapFa+%uDMNrdB$h z^Sp%e3EG**a42mnX#ZswM&$30B^OED72+nTPX_w!`-3F%R_OI*yAvnwKT0guu!}(c zMcdB6&75%Gj;N$zO>eWf_ioeWIp1KP!6ES&VFz^hqCK<6mb_V_51#!a?-pXQ07=KQ_QHsOk#$xt@1Ekjjd_w|4SmM+hcn3DVLOWn(%@YZTg&1@AL+v z{5+Le%dQbXx)<&SAdykWLlg(q;MHF0vT*lW`(ch+_m%E!eFsC70-LmZ*#6AN7;gw}~biY*G%Z z9c*-cq7Ce$T~iGV>#pzSv<*+AUT!~=U3lNwsQJh!>|Vu_ykRVn(_%}&UiFma5!OKc zC10yhD4n_qqL=HpCCr~Cz>x1Jx?b0UL9@@EUg|_vWo zk3)@Y9BN#IVcr7c+0^0zD6~LAsgF^CFdi9^T{PlLJVbAPbdzt+2rRv;S$wILAVSV^ z6P$@m=632zcz?K{;jrq2TyUYQo@e>qE7>h>yA`9Tn|+eF;C)wBWz^FB7d<8rmz8MQ zU@!?YtF(jUq}(pT`-Mj>g~4+bv&93{uRfsQqAS6D@PixYztbdC8Mc21vO=v~|N>L?2HyT&iS{i|+8{-XTd~Fg}aOTsQ#NZ#EiheS21du66C>Xdd?X8uU_YYNE^4eL5 zi~;^{swfaNCKSg>vP7BVO6zQwbvKiVp(B-Vc~CojhU-U?iYhr zxnfS7YKm4Iavqy*~UplV7j(R@vQ=@eNBaX4qneE zPVeh6-yq*wOm1@eIKSp6%y702vB@vAfBvRGiNS`Iu7k7)LbXx88$%3Kc3OyEGdXGQ z^As;24J6KuUAPzDQ(ClMUH9Dm6~%# z@VK0TOK`uv`qfWIMm!&W6JG;62wgJGHCZ?G)hJW52zdbK`9fpdT{e(UtUf$cPvdZ4 zv6CbdPcQuQdPz2ivx`|%{};`Hk>p$E!sf`5k3b6br>0C-Q4GRw-_icFs_qT_$)@U7 zB9D~KyhXZ_*T;FQcIk?;%Wx#$!e~#;(lnSEUCF9-boVWUE3b-l)5elT*vZ!6-<|bj z){-u#`oZ5N8I7^gQo07V)D7X(bC{QUNmb8BMV``Ul;^A2F;9pfnK6Gk=_C5}4|y~) zGTsecQiQ8*Q!L8SS6|&U#tTA+Rg@^%WpJIUlKW}%d^~aC`M?1ydAzL9%s+D8InH#O zpSVlq_b(C&HESMP?r@N>E#XK0Bx7IH^M6!hs}%n8&Ev_(Pw9B|G70EBQWvOjdBv5v z$EhgW@!-0+yG<&c8B4d<9;gX+vmw*Bs44qn7yMIYSVX=ZpLgy*5WOb|IJ%BkT>s%6 zSG%{?=)9(>{H8=ZO-T*C3+)XnZF!d^ z;v&@bEq6gjgg|9el~cb3ABj_W?l(pji=ue-Xn-12K-8r{4EU9n$-ar_CCJNE@JQ49 zu9QnoVRJ+dw10d}vFcK5S(vKUOW{T0sXq51bw$4#(uXl8-X66mRPNG0E&FiTmxb&` zVnlH1L6}(O*l)trj}BqooL}yx$~dhv-cDX9R{lYDh#%P@5Sbt|BtFtzZxmPdM~!N| znu^31S0dFN9ma%tS~wVUr-w=N5y*S9f-f=_Xu_48`KzCk4~-8_e}`VqALP_-)H6yv zZSpWMqMNkNb8g<0!vEG(b@C+GWF2SNw4%M9TlyIib_C_tIqZ0FKrVT83ODb)>r?qm zCAj;uH_Bk9rZGbdB2rj^D>iVf@U6OG7m%5C^DY*D!xRuSLHb6lV@PW&-V$h?7GS@B zjOkZ#Zj3h4@ME45BfNi%8cY?30ZS~If~jHt$w6WnzbeS=s!Z(;kC6tvB4l}2<2&emtLD1-+}@5GB~koggY2E3QF=+QZ>*b`ufmX`VcpBj#8xijpoZcr)S VO}5=8uFePx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D5_d^NK~#8N?VSs( z6~!5V=bU>l7cLPLP|+4pAyhz$EeI8%AgM+kDgq|eDp5g96d{d@QL993G^LuxM@+PU zR3k_NR9gXG6O$?YYGqrBP4B>D%9FFoO>F*s5hr?0EIAQK^I2_FYC(IoVhoc#gY$1;Le;p2o z!%?mzCtujr|Lbr#9FB6unOPjiJg1GAC))KK@4Fn1@}%IxyyDk#JKJ|egzH+|mizVP zNb;v%o;6oWu}oXE=^`qskM~{qGi=x}(Wg%z-xVLHoN|h~x1(vG4DY}H{(_WcAt<;o zuNo^G?qJ^$kz_9+DlhQ%xq@J9akIBo{mv7XrA*~zUY<2q;waO&XxYA(ICaniqN?U( zaa^Ziv1#X5UU{V$J$kh7ijPT?CaHTnnufuH2aACN2daHJP|{|W!_NwFaGJM|3PQZ) zU!@SgL5Reu{;{D#R6i<(Ni!CfrA|I&8Yc+yu9vUz9Ynbsf{1JLx@9Ch#$CKh$Bm+=6jV)c!_K1 z&6!-wG)_+XxpDp~2*!B5hb=={A_uqft|5y4X7A#nhnlNF4 z@61f)a8C#(PW0TVZBj5UZLDEo4`mn)wI9o$8oB?#6QI0dFSi?f9(ld zP0cI*AIXt_de@s^Hc6Zyum3?_KTQ5_?cL+hy>kDJ?m`(LzOV^{@XXj51%X$+unV|KN}6~stm{B^UpsQ)z#H%fA76AQ+*~+o-BqBA1+$A zZY}oi-78kFUftk4=yZ4MCM$qs`}XbP#TQ=`bLY-g?&;H~i%y+7iHQ>@DmOOtnKNgK z@4x?EJow;)V(Zqe>i9L+Tq8z}8YMb(=#Vxn?sNY6=ZnpoH;ZZ0riuIRyRRWQka|Y*_;hm^55|`Q>8d$dUe$_|m2A;FJY?^wCFR@#4h|>e`AGEBt>#EMLC7 zQCUG)nG&BiZQ6)Ed-jO_{rf9_I&QkG;>21rM<^Y7!fWJgN8k1uw5j3J$Ps1-|LFNS z@{(-i9sH9%2#X^!pBQTMzjmYNH`ztrPYO+q4o7te8K4tDfFM*3T<3*VAv+5VaYN8l zKj7{4q+9JL@|IyBRKWRor%Keg}5^MTc?xH)cOlP=D&Wh+zA0XwV3T88c=mfw6SyQqitmJO8W)LWo8`d-iPQ=b?ulQjMEy zH3;S#Z@f|L-o0B~am5wNAA%e~kPcIj-*U?>b;5zT5FWzF42xqL1kNLmJfb=V1m35g zeyTbQ1X3~BuwjEZ^UO1Smq+j3z149|TK9{AAj7iQgV)sPB|Sm zWeR=!_7(g0?^m4?VNo}(zWQqaY`i2>sg(aW9Iau(5vj4EfhK$V2PD{}kFKishY(C{ z^8TA}UJteNv7I6mw8n@ANLYzho*P`k`zs@_ApHiu)=;yhEWJ{MOlOHh4k}Z-{E7EE?dyZX+#LdAWT^HzG18AGxLL*O;K0pLNz*%D)ET z&T&nl(nVh5FRG?&Q>H*Y=Keq!Y?N~$Ncwv#s^sXd<-^{FCKm(^PaN?67aKI?M2*xm z!qC7CAXY|@Sf&T&i(OuSY|t(}!KO|_mnwMB-z+IIxV zlrEEOemIvr%llu^%kF-K0O9+;mA5O~HiCQO3zv#Rdp3y!J2!~0mdf5c5B6?-TkKdj zR|@ot{Uc2ac6M7Bv0#P@4(T(oZQC~S-h1f_E#C<~G-W#8;D!)oOLs2a>W~jV{IE`| zMJvZ0MlR_>kP`=1sSrl@?%l<#S+g3A7RnK8Va~)B6PajgnP4Ifvqp2nChZyo9p(ll z@TCSDy2f7SSC|c1`5|w8m^4nwdn=o_u@!2$pX!`^Q;RaONOveU>B<7b@pPEl_kkVj z#HLp#if@)rQUCL$_HcBYF~j*VLA-0%E;SKm!ZoHAjvrgCjuFekg$u>FapM};i~*bb zfddDW{n*^n3D8mkO_~mhNnlJaTC>)~oi2nu<_`orqkyQ-1=y5nQ)4a68ETt?8Z$x= z1Rj%s+PuJoX0Ai+d|_hLgw+1|IKKNh zWparEHc_-XEr{ua^a=_M+9TQ~f(qDkjj2^KE*&hh-Q3^5n&3?aobHa0o~me27Yd$ldKYrJa_yljb1UYr5@vbLcs zo3pp%IAa(#X&0?zI9JujyZR5(&niz#H^KB%b#=WTR)qxpATaSmc-Y`;H+Y)227C44 zzezun>cguXA>(z1??GadE*n1@mU7a8u#zVoVd;uerrHJ_W{b{;?H@cL1$htgvn$>f ztvdW%oP5shN;BW|s?5{~Jo)64N*kL$f4&mP*o1>CAP~F=r+e@&q`?UspGo2-H9y3EJ@XkB$s5uDs zLE=hRO-+qjC8h77%R*050>WOOr(u9(V29wb3MdRBX$%DTpl0%Nb?!?Jb47%=1DEzjT;F zubd#?m;|QdO1B!OT+^k=_n{$&qZF_GlqbiOW?pPCRg_ytq9;{@<|LDHOqava+&HE*^I}tu0uLdcO^|~VEzUtGF9v*<;DL~e_7IS?our`-B-2snD2bX*yC|C*>WaGw-k(ZcJ7xnu+ z(uEZjEok#y3Ydww>vOhpXFaqg)2mz4!5V5F*0J?pD6*ABSRDf!KeqLUd}fI#%OH#0 zzHG1-<`g!rT7PgwoY@(zEL z9exY->e{%7WM&~@WHKA?Zzdxc?m3D_u?0DN_uY4@A<}5r_|O0!Yd~0Q&}?+wVY~b8 zyVdcPD_5$$ExZ<$un;)$0;tn)W$&>%Hh2!24L)W~ZB zbp87EYOgbkLTip+RACqvEJ*hyl+5V2$z`);lYeo%l<3x5Z&i5^wNs!TMZG2;Fdtx| zq%3&-D)pKUEh=HQd#_!lLoQ|V66U6GgXa206|Qk#La~E%(-^V| zScD1lFZqDo9c>W75ce{@rht0Qhlz^;Bf~gMOEzseYP+z(rjCXA$yR@K-e|2{D_h0- zMyf4&33F{;(JNeRh+>;7r7x-=eB75%vO_sBgnsI&r!qEh8VJIKSI6cHVW92q+_^LI z#|0eu6QwPiWNQ~;*wir_KM+=bOsyQU-K!MHOPHT`-g!!6)f%eJ*EjHEs~s|2W8$O~ zzNq59gpwT^5H@;jqUMMt2>G{m?b@vIpyNWb%C`fH>ps+1?i1&zhO)@Ca-+}?ZmxpZ z#HKCB*)DAAm~B1G24-D415+zU0pWNllU(xBEB;@5bR%K%j4!Ec=xxKkzJcig$ZQST zn!Y9og^oZk_7_zsR2qT%5=vu;Gp3WU21NMek*V#ZgXbRjAOK6lOvp<{DZxCZp#?iv z$aJ5m+;!Jo>OSmqg}CdoARpMwNleO@bdMPt@O!X)299`Sg=5}Zr!?W^i6umpEYaND0iunxOnu~)biI}_MMp_6U+i+YGTqvCL8T)^rqPFj}dG0zx>M1w}#73zP9cn2$gH zc-?vKLnG8siOqXPh48XHaT!N^u#uw`nD*3Q9#R?g7gbDx_X{hFboop<(^;WC*}_Cp zI+zS&(-5DNPC6;H40OEH)gAI@$dDlo@|YDAW;mK`_p!}GAWVkbj3{z>IEj2_vQu}+ zq!`l3P5FcM=`3I4wQ_FHuvlY}mdC~*$9F|*DR7V}ZGXUbaJh@+M}gtcV|YZo@@ zvZ-S>er)THjx%LJ+A_8IQX(;V%GA`{IkSCdJWyG%r-wcAk9NQ$iZ0Y#p+c3?7ggej z4|&tvzJvnA$0i=6KU@Bh#}HO`!tP^(?!=kL$oF1hb%XOPLyfDfvV}+9K)z`Lo3|G)D z{zpIG|Mk1B=S|*qXmw?l+OIwUqDOrN4`VgL6++<&`cD4n8qgQ~_zr z?|_i9C)cQfhKn7)6Qj6*n-70)EQb79PTPoM=@oUT|BZ9$tNi@DCsF@~AEO8Pf2XMx zzkdaNIlQBl(J%v*^e}fX`tKGFohXpNLS^vK%0>a}rOTe-){P%v^rka+z=ua4QWUJ5 zWl!WD14YuWcaZXn*ulWI?gq@=%)Vv!O#V$+$dt6iNS47w`)OSfK)4x@A&4(`pLv^5 z!FTW8qTR6F%jKp%vaE-FWp%m;VczJ+`P#zW*}j={B0EC^#Br@vwe!K>DjNGtJ*RC( zjKHR#LDA<<|NKbu96q*GMEg&rDMWWz=>YGBU79RVn|{z}UC#S37PHwXETHB4ec#N3 z9$aMe$x2{xOiq9$!#z|6EoYy0c5rY#4O!8nm<9cZOJR!IfQ0y^>0u!&ei2dY6^j)) zgiAoF)p0;7NDsJ&jsc@}tcd)c_n7|jrSuU#k{uJGJ4v;u?zZr^%LAYM6&o;VHTvLx zwV-H=R;QTW{tsR?UeOCivaI{`6IY0^b!9KYu;WG;ZyOX~_nU+f{PZom79BlX74qgrjU!QZ3ea(~a zb-j8e0@A*TTm;X^yg+w<>F*R_nq%qO_b!J*Fsq=UVKgzAgz>30r-1Z_g{-#yjEAs` z6;ceWq^;g3Y^cni&^VX#;$H~n7!wM9lf2W_`Mr)MO(T7~%BkIi4UIZg?Su^~?-DE+KUNDy8O3!=9_lAx( z#wssB=^X@q@=Clm1g-ot{Nz|pkc3~LgD|pNl9qen&AZR<3z#oWX{Q3)&L~wF!ahtn zFY0i$GoR`2wc3BZPqZa};kH-sO4uFG$Ybcv{PAZMiCl_$E= zBI$^NI^i~0&shPE%oz%JfUoPr50_aRIt%|rDBdpkMms`_O?+v8W{{iG8Jml-zz+!cpL$NAOEPF_U)OCWs({o z^U{&NbPc<$O_dE+wn3V+JOFFA0n;Ewc>%N+%~j+D(PRvVnJfp@@!- zlEML`+Gy8i5xOq0r`P^tuw5p8r%alKVmJK(th=`_^|L2M?4Q7zPa=}BuWwpOcF#~7 z9321)_^{OrQjsuEMlQ-6x4$3O2DWePO>PL`H0iIK(RJH{JaK+VM(~NVumF%8k#jYX zu?I<)^e8<$8w!}8yQ>vlKkG=YSEM00`_sAR27h-If>}99b;^+O{YfY3Zm&s!L)3JM z;M}FHAIKCN`Z<8|m@+%gs^5@cy{9_t`{FI_&Px6hX@Eb)C5%E#nSLeaVp&M{wlWu< zAI8Pbkr`9|p6TzP;2m_c4|-1AiT)dwa_Qd*Wt#bv_-Q}0dokx#ciZnZFFr6>?$UZA z%bn2k0ab1T>VvrgD?eRdq8c!c%mI&)0i)y^0ZDTo{J~L;;VhWzlpya6Jm>_?O6_|- z8PkAZlJSUm73`M6_9GH)(?*I1#VTDJ2b<4NY5rER8egB0G06Se0bj#6wB&%4{s%oa zYi*gW0s#<@V2L&M)Za1`QGt&KsxqD-;#g4m#DO3v#PV=sWb)myV1~nA0J7c+r<)N3 zr4zD_V8XEHe7EYJ`JgI&2^7a=NFQrNJtyfq9{J}?B=3Z?so&OINof)p2GnW&a}1wb6%_4#&fO0 zJ#IY~uDM9%!6#l!97&$+kS4U)&}ql<3g@)>{$Yym;18&mq8v8=iEV*)VMB1mzCVT6 zcCMmj1c~)=M3%D>_{d_T{$OJ}0KKtwI5pvV!|4i7a6f;m^tnOwtP~JlmLgxSYguZw>w<_nB(p4JL?oHueKAjh=A4xO48MF28_hL z_r7EsF8Eug>D0vc{&oYtq}2+^2QIV)746{X-gbF4P>CBkt??55HCbk4Fz#T1DVAM1G63SH81u~ zVFKj~?|(0k*LOMw8eAl5%QpCWS;bx=oCocC?$v|2o}FnjLj4#+cq;1i)?hIVVi{xF zaxI94yzpEj1u%&ijGs%KwCitCsBfA{Q1F+3{@Cd>C2_0U`9BwUfFirTPuo)axqk(v z5Z%d+;8p95qbSUgXGUmxDveMp9LB6yb8LT_3oECh()H-7$bIXgM53wY9-IwXU4 z#^7%Axj4zj<^Z#Lph0Lvf4Etk!)Lpl~tG}PuH@O4iKZP2&c6i;v`5I9O)>Iq4 zAaOMOVt4n3id;SYuDG~M8k{m#{H4$x@WI-kDClvTRhy$~0>FL^r2jANz~kb?cuMo} zyzKzvP~vb_I9nXF#&znqJ8nMgAp}V9*0QI^Ocq!1_4J0&>3?kt$HW2#H>~uHKR~=LFXBf zgRz`z5zvyLrJ%eK^vtJy`ge=3*VxL2BoEjvzW5Fm7e@uW;J+Au-e7bWqCI#f=Oa?p zpW&*F6`DV$|gtf@}B<%l1V=Fu?T|z z66Q|wqFbP10sGDe-Ap$Rv$_8xZmNfkuwc*5;VdnX#)fF%=^l5g)|2h(m-C}(g9yMNo17t+>eP!4b)O=yv|-er1_MjYtG#>J z5HC4aypyC4hirA0PRPAX$>JR1b8856ZHedVEbul>*m^}HR#Dn#R6?Y9G{>pwx;n%3NNx=(OttWz-kJH)4`q^?+(k5c@4q+6-A^!SbT4U1jYg@K;Zboebm74~P(IshkV#21fDO0`Nyrr=y&-S3W1}XWidrh6y@>i#& zopGcTzf1>}wzN(n`R@jh-HEN%W!NB$Bd1Hkar{Zm`(IIAsjunb4r_(&(F7_1Qer6> zRbfnU18CitE|&*&VP1bZa=1D6SEt9Ph?OD0dG_ZZLfB!HOJ_14RXsqh7OD`u%QFDuzGQ1JS;n{NqAa-73m z<|IvWs7Dm+-{g#}-eY(^?sTb|ZdIdM5`Y;kb0-%?;!+$V7+lN14mkXeOMp66RBZs0UuE@gEk`wRWSR04+u%Zv;U-$*tFPTXF3GZ~>9&O}*h=Jn)4Y#h7%|e`d%8Gnm-9ne z9$BoJX&Z-^49*DOBISP>mVz_a+f2D#2tDk2EOT*!jzebj9}LO4#<@ut;;N2edBs4z z+wzVVlmgk#WSDuRG4g$}GdvT!Zslssdooc7{a?D6-r7_afLX~>YB>U>qqFngG{6jv ziES7F`;#WFKgzFShM)TJ2@k6IZhkkuZ}t8l!Z*ml{BiknD1&POAwgjZ4QrpK_t8=! z%&5k8y2AXdYmrmKke;Qn%wg4kA&5Bd=6R}?y@Va+ekUW21i-`XTw1S}2cbWC(Bo?! zHR{w?`dj#%+mXxlHc6N@y&YO@8mnR-DRnLs{X-L2QsRF`yK;@j4lukzBNG9shwxU zpw*kRhX;pVhbu-uN|*6Her1R%-VnC&An34y{G?UngJTn^RLguiNT}a% zQe1Is-E&e7{PB@WruJ2qzH8FeJh!p3ehW5;am~awvTFA;ES1lORWg!~^_Cf%PnV+8 z9}3K6KhbX{JQ>&1{xOxv=ebh7O1>if(SOjjXM4>%*kuYE=y4^! z{yxgd!E5$p`fNQ1<%jfpX7%fcV}rycP(hQ|RB~Dw8nvprskqwP!SgqAvJiU_+nD{ zX>!i1?jFU(Wi5~E$xX3$R&Uh$m^(0U;KepIl~PX0Uhl`vB5*AF#_g7V$){qv<3VBM zyAgHrhzP+Rn;!iu*y8ND23ANskZswIhrHAAM(Vq77e*EtvV6N^6dN6!GthO~DT zGfX2GC{k|llestFIh!x^NKB3OsKs5*UlqvDeC;w)&F?8-K#A1&3rxieW=2|Y;1+j6AJ5@GIJQ5Jr_*LP^X5<#|pVrMH5O{`8lAo5^$sn{Lj(%qYx5K)Gz0?v(-z zv%(mTDwr5@I8tg68epr8Els#B_VC>BLr5g@3(G)D)7e^PeiMdUFQ=sPYhA&moBQ_n z>d~?{!OT(|q_uql$AZpMC(SoJYIMWCl&ESmozjTO^m6&tuZNuWemMe`FKrl=axjKJ zM0kFw{-2(bfloxid>J=#;_{Zt2LYw?430ikk`bG8Pn08I7`SuC_m(}s4VKxx|a@usi?iJA=BB9r^<||%u3=ovRxmRDGY{*LVjD; zF*$79tC}MI;8%%dD1GC~DGukI^oukWkneLc5+z!Dg;3yDuVGE@t_|_xLW|A3_j1gJ zV+6XXq*5;>mV1y;imhTj?`E)?uofb!h4oU#hunU!gEq7`5irYyj_Tk`F*Nf?-rU-% zW_e!Ik@)oPqN&%M$8l3gr)Vmho25OAqJe>-@Yfm)_tp1tsR!&fZu8Y(OP#M1K@Lz- zCv1Gt=_%s-UH3e){!u{|$%d?-42M}n8Z^j;`Dg#L6k7zt`1vasT-`Ls zfj3z*duN5T$EH9gD=l12w(m5N#L1r9dl{41{fc^cTo~oWLme4CCp!JG$~+=9#eY=Z zw15=Q`3oQ;`|-H9X_UF5VU51VV|y~iX#jChw6{$Ah*z%McBw0Jq;74juO5S?&UMb5 zcsb{s+5vr|-$f5na**-xTG?T?{d^8i zF9%Z2qG|ZGocFb(qN4)m&TR)XY{pvLmX&;E;GHa;JbW#Oy27>tX}f%n#dygG-;oSY z7+Nry^#ZuD{=_aPp4ckP0As@_SYS_B+^xDI?*H`SQWwLlJX_qEtsBbnJDz?n3#D2? zGmw8QHViMHbt_c~hX9_P(B*}1knH1xF$_IbMM@LHXpqK`lkR4SJPb*7o!WY7Vk210D!a#)n(T;=w| zm@VkFnY|ZqrB+n;{KU@2twNTcUv~AY82N1I!7)#Cr;>B6Z2G$EnEN}F!{A4bFqhf~ z7|H;pp6gGfd>bkG(v{6#6%@wsgw1cO--^})Q;x8#ZyHTPfcyE&V}-EaAMhe)n!GAC zN#+35(#D;mFK8FwWIC)+9H?1`QJqURov7oRLzMNCKhkMsG;efG*R#D~e)S4_m!`{$U*7HBB&w*zRc4t%F!LHc07B+`L^8$D zNGM)nA%pBkq7Dh*LSXsVHDvaOoNN;kzYclrk`)zVRJut=3$^qLd0sf}i_5rr&z;}# zl0}KluOpVjvbB96?y$WP^`}Ib{uYIB@^Wy{Ss&$B+Fq${AJ!Z%lwVy;_z;$ol`-#` z5{~xW-~it4dT_I01H&~m9-0<9D9x7Zmt9r*^UrT?>d{<>gT>4rIBk;nS+m$Y%;?KUzx!;3h+wQY^ePQ> z#2_l8;FIj_=#)w)l4AbkTTm*vKTkT{Cz!i$v?sOsGg5)(4g&b6N)gNnmljyruj)x7 zlTu;h^=pMoncpmKb1eoeq&f99GeRpj=xX-;(@~^H=7-*SuAsZxqG%kfChOW z4a96o%D_J&^UHv5dBZvyoTi1OxU+U!YNc&{oSzqTE3eZTbG2x)I^@2*AGMNw7ney* zt%kpc0FXR{Wrlg*e(kA(;_XHvtvBNm?kQw>clQVoyN9MW&pM{Qx}1CCDl@6k_rxMw z#mGZ^rFXd4ygbikT;Vc%J2<6sUO9jDTeqX)!cSX#{#u{5h@!%sd0%w76j=~z*;&wB zKsK1A532rdV+b@PLz5la17v+%&Wg3k5D5mO-4j+!DUL#dodjW#3Ah z4QeOqV2AI-N3S$#SVPm-;aK^^G`RX19ishlp-luc$x2u8vn7XPzem|BGUxft6d)FR zX*UZ@*3?*^DQAWeTr%EgOOS(k-wAo>rqVRV&Jw|WK*I)r=f!&bR|6y(PIE+t;YtV{y*|Zv7t3J}a{^Q!Zy-OHo z(Xy)cBw?)?i?n^Eyw$>!QQs&KC(B{Twow;K^Jvm)Fs}?V5t*bPe$jJ_a)wKn^V1;J zAK0r6vi4_Nej>(j$1HrV_2FcWW#ooqp8jRJ9qju$UirIA3j2xW<)`cj!R2o?P>>+~uEbASQ}QQ6~}__VdMXme`8ZU#s}Z2(0uq&n~OVQe{khqB4KRVqUTxc~$_> zM#90aoGbBy5eZ(g(yjG0YBS3xRcs*(>~<`Dcf(QjmY;3S*=P&#EZ1&b1!%7a>Hmme zX<6#z@QyEj&4J!{{LRKqBUp`K?!h0R_kEoPQumRf_Lc%8*2+)X8Gf+P&kqeJSmX3} zL^r7E@`%aI-Zcv#lObP~8+KDDta;a0!s9MnFeTl?b@A-Vp4(hL>ElvlF@04kXQg*- zdW*{>|J>G^QnXZs{+GG}eQQKK=sN>};X3Ewu9O&sKlVwKd{YRScxH3=GR?sCLBxCM z(}iGB7?IgWj<6eiCBj7J)9f~a84lVZE~^<8Rx?9u`XN2U`vWF4k@x5IoB+6J0j_+R zS<_D`vb{+4wgu15ICiktvQ<&jhn0SrYDW6R7#l^3Jxy&`mLF!`aU-vj3cy<+0rPTK zNO}v^Y;;-X6#;+bV)RFQ;&RC}l>whn(*6<(&RJjbw+oYd$odfhWS4s>ZPC>kQrgVd z+YC9|kXE@S+>PrOMRpY=)FDsdV5a8th_?R?9(>LXyxBW?#?g|8x4`}|AzFJra!C2Pk>#(kQ09V7 zfAi_RcA@LD%Zw#G09tuPtT-m0gY{YdnQe@kPu z`OLUnE-LS^pld4tL=DMN=xw-Xc9UJ8l4`tOB2 z|Ci3FB-wUVVZ%(FVq`S(R_DdOvfxm2BPY7_*h^>3rVc^fyH>kuMZY=^5Kl64EsPp+ r-;1Cc46KMBN&ipU9Hp|lW|6nw6}9Y@R>J=C0Y_C)>s7_ecc1HZ1$8Z1QQ(P(h%bxLQ9>Y#|#-;jAh=v5^p>vmM*hMWTPIo1*laq<} z(_#_lm+MCw&mJ*koeMWljtT0w4Jl%M$Yb9$=6z|Pp(7$XzQUTO1j~PB2iJ1w+j^y0 z?EQi_x0VhmdXabfl-k+_;5H>&{>g#Nhd+PrzAy{djAQVv4DhZD2E9V zLkg%lJ5fJX7_k;eFwt2?8pq$FD$!@HY~&m}kVHtkQkPi3z&5`K+LTIRk~Xuy{5cqMX!uc!=u>n?u*RY>vNu*0uD$_TH_TQ_AUwLm7Jq2WbEkGqb|lT0dR6(p8mK+_dw;x3Ghi ze$=SDJQt5LmVY5IJ157Gg>KKo!=t^omv)Ct%uIRgR%crseje8Ac6GrP4yEj?akAlf z)XcZMyzGuf8!2mTY;LyKyuo@kXrpQ;ovN*)PWSisEo^M)>TH>aWSK_}ej0zj<@~VD zR+>*UtjRNbanU6$J-z#nI+XEVj{sVp%f#ILeu$nxKIUpQI}Jc2Cw=;4gyo^B{F-=n zc2*|RFzMOT9!W#^y19T;bwwZv7B4F*%%D633tGlbVFj!-2ZM4_WZyE|1}Ss(^NVX$ zlb(h2x-zSo7&R%k)qy-90=(wcXi)Rr;an&6LdDzY2M>mahbf5U7Rd|92Aljb+!fOt zGyP9ijm0Cca$2oXyq7O)!=VUMQzpOPTI9wC8fcrJcS@V6bRcp7FK?E+?Ay{c6RU&PV!OAWrnDs(Qq2Cf>05(YJP?6Y`1rSI8xk>8OVx1LL_1}X&)ho07w`>yx9~v4;mr1Wz#CrSo?GE3lCFPk0Ke3%7HC0sr2;7~G{^*8B z2x^P7_Dtp6>2(zxv0=$D>eNYimGX%|z{eW*!L57j#_} zdlEwM_;A#`=yx({$>zOgbf+^TGjmZ*4O=WTEQt$#r^3Gd%NO>k>1hh5$$B<(Lqj^? zWofCHQN6!vUX^`iSs9BLcI8pn`uhvX?M?tN)AaD5+>TdQ1@U3}X?8Z(amaNzW8~3X zILxf{n(M$KXoQfhHys?sJYT&{<~QoRu|KAij;GG0--|B?9VG{6;;`!_ODgxskz`_6 zbnr#y;oo0h|9wx7+T5$IHTv?qzrUYQRz@4v3cFj$2@Y_<*!hw`pwKIltAOUK`qNAG z(R=9Y>k~%T3l|lP8?L2(j9OT5CNND;O|`)p8;L|#Mry(s+I2rKCr1YkWj{j*rlf7G z`!>8BU5Bfv(1Dt3@dGbRIE0!$`u^Cs4aC{RJXGg%W+|!3O*0UVLkJ=XFB= ziOgU=l)Zqx4ZFx@$k$STY@VwgDtAxf^%XL{oMyDJ*seDxSTo`G0D0OBE^CZDADBgv zQIfp(CG@*U0YA5=KYUvS!{C{LFcb>aGB!3&o3E>@)Acft0)fnTGHXVWmL5-fa@Y&N zEI&+dgE>6?!P|Uoh6keG!T;0co39EQjgF#N4dB-mdoEQ*p2S&0lZXXH6kYOmts!%}R%2 z*{Yp8sTYXA_qE}oR{`at0da{m2Ps1Oa5y}o?!ng%bX{Rlk3yi(W_ANNzFHF|f*I7}Yh5aEu z)9<}5SI_hh-2JwC{!e-<`SI6xcHgrD7_J9cIfpC?R4|^Y?TjdpajymN{{H^R9Hzc% zk5N&eca5+%)&!I46NEBWOzpThIPk8luGVgh`>M2B&L>aVH{v9UaeFfr)7yF;9ugov zNl8fr-FkD@=ZKXh!|MgiV8y)nLo`o4lvT{!F{$u9wag{GR-k#A$bZR$jZ*i z$xvn@aJNrCaeP%c252KTn@jf zB#JQ4^mt=+1sVeuG9!r|IW;u~tz0Im#nSe%p&@>gor8k|q}r>~n!8f^VEh#)+PWbY{Iu_$mcf%Tqnv%Jm6{O)%avuZdfF68meIWZW%D_`6T!k!-cfQn}cT>*>M74saoY$opK;SDj+Kf7Rh zJ3&QzH1=XwRFaIL;Un(yV6=3!a&vQE%&-3Z<8;Ishm*(H$*eMZDRTFaNUm0844b3^ zhfB9v4)*uqnwrUdnX-vtD_FTt{l4-|c8^`hHJ}ASaeKkcazC87TCKdhxMSGZKaC3= z7EER_J;#lra`N-}vP?wFEG3nBAkG2uP)2bH2?~;rg*ZE$>!}=*hP*swVmIEEl%)OE z%GJ}85naaxx?J=0`vqY(AKmc1X~gkzW4jYehH7nXtp}{fp{dD^XV(S|`kQ@TS*G0g zD&vLNPSy{(+uPd{VB>I`S^gQ(eZ2;xYB3;T+FK$at*k^nO>_lW>+NMc=URBdyFpqbho6|8g_K*; z=b4GUT2}rW#UP(5Bylb^n<8G1(T8(xJ{1J>1mpss>RB&dux_x?Qd-#BCd|&>U06@l z;(unT@=Ix1ShAFiAx+la2m4C&BOjjFot+(&*g3d~M?J_weDf){QpVf+GOHh+2N>Mv zQBY7Ifc@iN%&9fobW?K`hTI6dW2X+L+=Tbk-mUL}D?TIl=|@d7y`Ja^(bLnzm6SL| z!cO;>__ + +==== Setup docker + +To setup docker follow the instuctions from https://docs.docker.com/engine/install/[docs.docker.com]. + +=== Create a Docker compose + +Paste content into a `docker-compose.yml` +---- +services: + openems_backend: + image: openems/backend:latest + container_name: openems_backend + hostname: openems_backend + restart: unless-stopped + volumes: + - openems-backend-conf:/var/opt/openems/config:rw + - openems-backend-data:/var/opt/openems/data:rw + ports: + - 8079:8079 # Apache-Felix + - 8081:8081 # Edge-Websocket + - 8082:8082 # UI-Websocket + + openems-ui: + image: openems/ui-backend:latest + container_name: openems_ui + hostname: openems_ui + restart: unless-stopped + volumes: + - openems-ui-conf:/etc/nginx:rw + - openems-ui-log:/var/log/nginx:rw + environment: + - UI_WEBSOCKET=ws://:8082 # Change to your actual hostname or ip + ports: + - 80:80 + - 443:443 + +volumes: + openems-backend-conf: + openems-backend-data: + openems-ui-conf: + openems-ui-log: +---- + +=== Run compose file + +To start the previously created `docker-compose.yml` run the command: +---- +docker compose up -d +---- + +=== Check logs + +To check if the container is up and running, check `docker ps`: + +image::deploy-docker-backend.png[docker ps] + +or read its logs with: +---- +docker logs openems_backend +---- + +NOTE: If you want to run the backand with an InfluxDB instance as well, see: https://github.com/OpenEMS/openems/tree/develop/tools/docker/backend. \ No newline at end of file diff --git a/doc/modules/ROOT/pages/edge/deploy.adoc b/doc/modules/ROOT/pages/edge/deploy.adoc index 58059b150a3..631099c92c2 100644 --- a/doc/modules/ROOT/pages/edge/deploy.adoc +++ b/doc/modules/ROOT/pages/edge/deploy.adoc @@ -8,6 +8,8 @@ :icons: font :imagesdir: ../../assets/images +== Debian Linux + This chapter explains how OpenEMS can be deployed on a Debian Linux Internet-of-Things Gateway. Similar techniques will work for other operating systems as well. This guide covers a simple, manual approach. For productive systems it is required to automate deployment to IoT devices. Good approaches include a Debian package repository that provides *.deb-files and third-party tools like http://www.eclipse.org/hawkbit/[Eclipse Hawkbit]. This is out-of-scope for this small guide. @@ -19,7 +21,7 @@ Prerequisites: * Setup an SSH client to connect to the Linux console, e.g. http://www.9bis.net/kitty/[KiTTY] * Setup an SCP client to copy the JAR file via SSH, e.g. https://winscp.net/eng/docs/lang:de[WinSCP] -== Connect via SSH and SCP +=== Connect via SSH and SCP . Connect via SSH using KiTTY .. Open KiTTY and connect to the target device. @@ -132,3 +134,74 @@ The command restarts the service (_systemctl restart openems_) while not waiting + .OpenEMS Edge start-up image::deploy-openems-start.png[OpenEMS Edge start-up] + + +== Docker + +This chapter explains how OpenEMS can be deployed using our official https://hub.docker.com/r/openems/edge[Docker image]. + +Prerequisites: + +* A amd64 or arm64 device running Linux. You need the IP address and SSH access. +* A working docker environment. To setup follow instruction from https://docs.docker.com/engine/install/[docs.docker.com]. + +=== Prepare system + +==== Connect to the device + +image::deploy-docker-ssh.png[SSH into device] + +==== Check docker installation + +image::deploy-docker-edge-check-version.png[Check docker installation] + +__if not already installed, follow <>__ + +==== Setup docker + +To setup docker follow the instuctions from https://docs.docker.com/engine/install/[docs.docker.com]. + +=== Start Container + +==== Create a Docker compose + +Paste content into a `docker-compose.yml` +---- +services: + openems-edge: + image: openems/edge:latest + container_name: openems_edge + hostname: openems_edge + restart: unless-stopped + volumes: + - openems-edge-conf:/var/opt/openems/config:rw + - openems-edge-data:/var/opt/openems/data:rw + ports: + - 8080:8080 # Apache-Felix + +volumes: + openems-edge-conf: + openems-edge-data: +---- + +==== Run compose file + +To start the previously created `docker-compose.yml` run the command: +---- +docker compose up -d +---- + +==== Check logs + +To check if the container is up and running, check `docker ps`: + +image::deploy-docker-edge.png[docker ps] + +or read its logs with: +---- +docker logs openems_edge +---- + +--- + +NOTE: If you want to start a UI instance as well, see: https://github.com/OpenEMS/openems/tree/develop/tools/docker/edge. \ No newline at end of file From a98d38c42969b782d93db720204829b258026e10 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Fri, 11 Oct 2024 22:39:42 +0200 Subject: [PATCH 153/173] FEMS Backports 2024-10 (#2835) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - FFR: Fast Frequency Response Controller - Includes: - 1. Fast Frequency request controller. - 2. Junit test cases. - 3. Step Response Tester changes in the simulated meter. To test FFR with the simulator meter's frequency. - EVCS HardyBarth: set "No meter values available" as WARN + translate - Changed StateChannel "METER_NOT_AVAILABE" of the HardyBarth component to level WARNING - Added translation files for bundle and channel - Batteries/Battery-Inverters: downgrade FAULT states to WARNING - Downgrade of all possible FAULT states to WARNING states - Whenever one of these states would be true, the EssGeneric will stop the battery and the inverter. If this is necessary, it must be specifically mentioned and the state should have a proper description of the fault. - UI: fix non refactored charts - Display of non refactored charts did not work, because of latest `debounce` change, e.g. Storage history - EVCS KEBA: downgrade fault for Dip Switch 2.6, because it is now used for §14a - ModbusBridge: invalidate Elements on removeProtocol() - Invalidate (i.e. set UNDEFINED/null) Elements on `removeProtocol()` - JUnit test shows behaviour. REGISTER_100 is null after `removeProtocol()` - ModbusTcpApi: improvements - Fixes error taking alias (of ess) instead of Component ID. This will fix dynamically generating channel addresses. - ActivePowerLimit and ReactivePowerLimit result in NaN if null - Improved reusability of code through methods - Removed constant strings - KACO Battery Inverter: fix state transition ERROR to UNDEFINED, Frequency channel - Return from Error Handling to Undefined - Fix Hz channel name - Updates for FENECON Home battery - Adjust modbus task priority level - Reduce number of tasks - Improve stopping process - Improve contains task check in Modbus Bridge - EVCS: Hystereses with info in UI - Hystereses for Charging stations two config values are now shown in the ui for the evcs controller - UI: add role is at least admin for DebugMode - UI: fix timeOfUsePrice zero bug: 0 != null - UI: Username to lowerCase & eslintRule - eslint-rule to prevent getting fdescribe or xdescribe into production - lowercasing username - Generic-ESS state machine improvement - The main approach is to have a statemachine which can be run all our current systems and avoiding retry start process. - Related to any 'Error Handling' topic should be improved or implemented seperately and required a defined generic 'Error handling' concept, which can be applied for all systems. - Instead of maximum start or stop time attempts, starting or stopping timeouts are taken care of and shown in UI as an failure. By doing this, its aimed to let the service or engineers to analyze the failure, and forbid to harm the battery by taking an action without know-how knowledge. - KACO BatteryInverter: component activate improvements + ModbusSlave - Removed second activate annotation - always set configuration in activate - EssPower: handle Exceptions in handleEvent() - UI: style improvements - allow disabling tooltips in charts - remove non existent fixDigitalOutputWidget from history template - break title into multiple lines if overflowing - Fix critical race condition in Modbus Bridge - Modbus-Bridge: **fix criticial race condition! If ON_EXECUTE_WRITE was called before ON_BEFORE_PROCESS_IMAGE, the forever()-loop could get stuck forever, because `cycleTasks` was never initialized.** - A usual cycle looks like this: ON_BEFORE_PROCESS_IMAGE -> _other events_ -> ON_EXEUCTE_WRITE -> _long wait_ -> ON_BEFORE_PROCESS_IMAGE -> ... - The time between ON_BEFORE_PROCESS_IMAGE and ON_EXEUCTE_WRITE is typically very short, especially before all Controllers are activated. This applies for the time when usually a Modbus Bridge gets activated, because this happens before all Devices and Controllers. As a result it was very unlikely, that Modbus-Bridge would receive ON_EXEUCTE_WRITE before ON_BEFORE_PROCESS_IMAGE. During activating and modifying of many components at the same time after initial setup (IBN via App Center) it seems it was much more likely for this race condition to happen. - In this very unlikely case, unfortunately the `CycleTasksManager` would get stuck, as can be seen in this log: ``` [modbus1] State: FINISHED -> WRITE (onExecuteWrite) [modbus1] WRITE -> WRITE (onExecuteWrite) [modbus1] WRITE unchanged (in onBeforeProcessImage) Delay [0] (time is invalid) [modbus1] WRITE -> WRITE (onExecuteWrite) [modbus1] WRITE unchanged (in onBeforeProcessImage) Delay [0] (time is invalid) ... ``` - This problem was solved by initializing `this.cycleTasks` from `tasksSupplier`. - New behaviour is proven to work in `CycleTasksManagerTest.java`, `testExecuteWriteBeforeNextProcessImage()` which would fail with previous code. - Modbus-Bridge: - ignore events before activate - renew logging to show Component-ID everywhere - RRD4j: reduce log warnings; remove stacktrace; add channelAddress - WsData: - reduce logging noise - Instead of `[ctrlBackend0] [BackendApi.WsData []] Unable to send message:` - Only: `[ctrlBackend0] Unable to send message:` - Extend payload from 100 to 200 chars - EnergyScheduler: - remove unnecessary log message - add log verbosity - cleanup config - AbstractWorker: - synchronized activate/modified code - before calling activate twice would result in an error - it's still not possible to stop and restart a worker (e.g. when enabling/disabling a component that uses a worker) - AbstractOpenemsModbusComponent: - combine common code of activate() and modified() - removeProtocol and retryModbusCommunication are handled internally by ModbusBridge - fix modbusReference in modified() - Home Battery: - wait for activate to set hardware type default - ComponentManager is required; otherwise ClockProvider is null during init - Ess.Power: - fix ArrayIndexOutOfBoundsException - fix ConcurrentModificationException when ESS are added/removed - GoodWe Battery-Inverter: fix handleEvent called before activate. Possible NPE. - UI: Style adjustments: currentVoltageChart - Switch left and right YAxis - Remove beginAtZero from current and voltage chart - hide gridLines for right yAxis - Voltage - change order of labels, now first consumptionMeters then chargers - UI: round slightly negative values - Round negative `QueryHistoricQuery` -Data around a defined threshold to 0 - GridOptimized charge requires a production power to run properly - Avoid exception and inform user about unexpected behaviour of controller --------- Co-authored-by: Pooran Chandrashekaraiah <46567310+pooran-c@users.noreply.github.com> Co-authored-by: Johann Kaufmann <165755282+johannk24@users.noreply.github.com> Co-authored-by: Hueseyin Sahutoglu <34771592+huseyinsaht@users.noreply.github.com> Co-authored-by: Sebastian Asen <47855186+sebastianasen@users.noreply.github.com> Co-authored-by: Lukas Rieger <73471197+lukasrgr@users.noreply.github.com> Co-authored-by: Stefan Feilmeier <3515268+sfeilmeier@users.noreply.github.com> Co-authored-by: Fabian Brandtner <10850256+fabian94533@users.noreply.github.com> Co-authored-by: Michael Grill <59126309+michaelgrill@users.noreply.github.com> --- cnf/pom.xml | 34 +- .../backend/edge/application/TestClient.java | 7 +- .../openems/backend/b2bwebsocket/WsData.java | 8 +- .../backend/b2bwebsocket/TestClient.java | 7 +- .../backend/b2bwebsocket/WsDataTest.java | 35 + .../openems/backend/edgewebsocket/WsData.java | 9 +- .../backend/edgewebsocket/WsDataTest.java | 37 + .../backend/uiwebsocket/impl/WsData.java | 17 +- .../backend/uiwebsocket/impl/WsDataTest.java | 35 + .../src/io/openems/common/channel/Unit.java | 9 +- .../io/openems/common/timedata/Timeout.java | 55 + .../common/websocket/AbstractWebsocket.java | 16 +- .../websocket/DummyWebsocketServer.java | 7 +- .../common/websocket/WebsocketUtils.java | 10 +- .../io/openems/common/websocket/WsData.java | 11 +- .../openems/common/worker/AbstractWorker.java | 11 +- .../openems/common/timedata/TimeoutTest.java | 27 + .../ClientReconnectorWorkerTest.java | 19 +- .../websocket/DummyWebsocketServerTest.java | 15 + .../common/websocket/WebsocketUtilsTest.java | 15 + .../openems/common/websocket/WsDataTest.java | 17 + io.openems.edge.application/EdgeApp.bndrun | 8 +- .../BydBatteryBoxCommercialC130.java | 140 +- .../fenecon/home/BatteryFeneconHome.java | 2 +- .../fenecon/home/BatteryFeneconHomeImpl.java | 16 +- .../battery/fenecon/home/ModbusHelper.java | 12 +- .../fenecon/home/statemachine/Context.java | 4 - .../home/statemachine/GoStoppedHandler.java | 36 +- .../BatterySoltaroClusterVersionB.java | 68 +- .../soltaro/cluster/versionb/SingleRack.java | 46 +- .../BatterySoltaroClusterVersionC.java | 70 +- .../soltaro/cluster/versionc/RackChannel.java | 22 +- .../BatterySoltaroSingleRackVersionA.java | 22 +- .../BatterySoltaroSingleRackVersionB.java | 6 +- .../BatterySoltaroSingleRackVersionC.java | 30 +- ...BatteryInverterKacoBlueplanetGridsave.java | 33 +- ...eryInverterKacoBlueplanetGridsaveImpl.java | 19 +- .../blueplanetgridsave/KacoSunSpecModel.java | 4 +- .../statemachine/ErrorHandler.java | 11 +- .../refu88k/BatteryInverterRefuStore88k.java | 50 +- .../sinexcel/BatteryInverterSinexcel.java | 4 +- .../bridge/modbus/BridgeModbusSerialImpl.java | 9 +- .../bridge/modbus/BridgeModbusTcpImpl.java | 9 +- .../modbus/api/AbstractModbusBridge.java | 57 +- .../api/AbstractOpenemsModbusComponent.java | 45 +- .../edge/bridge/modbus/api/Config.java | 60 + .../bridge/modbus/api/ModbusComponent.java | 8 +- .../modbus/api/worker/ModbusWorker.java | 19 +- .../worker/internal/CycleTasksManager.java | 79 +- .../worker/internal/DefectiveComponents.java | 49 +- .../worker/internal/TasksSupplierImpl.java | 66 +- .../bridge/modbus/test/DummyModbusBridge.java | 3 +- .../modbus/BridgeModbusTcpImplTest.java | 29 +- .../internal/CycleTasksManagerTest.java | 49 +- .../internal/DefectiveComponentsTest.java | 7 +- .../internal/TasksSupplierImplTest.java | 16 +- .../src/io/openems/edge/common/meta/Meta.java | 16 +- .../modbusslave/ModbusRecordChannel.java | 7 + .../modbusslave/ModbusRecordConstant.java | 43 + .../modbusslave/ModbusRecordCycleValue.java | 23 +- .../modbusslave/ModbusRecordFloat32.java | 2 +- .../modbusslave/ModbusRecordFloat64.java | 2 +- .../modbusslave/ModbusRecordString16.java | 5 +- .../modbusslave/ModbusRecordUint16.java | 3 +- .../ModbusRecordUint16BlockLength.java | 5 +- .../modbusslave/ModbusRecordUint16Hash.java | 4 +- .../modbusslave/ModbusRecordUint32.java | 3 +- .../modbusslave/ModbusRecordUint64.java | 59 + .../ModbusRecordUint64Reserved.java | 14 + .../modbusslave/ModbusSlaveNatureTable.java | 34 +- .../edge/common/modbusslave/ModbusType.java | 1 + .../src/io/openems/edge/common/sum/Sum.java | 2 + .../modbusslave/ModbusRecordFloat32Test.java | 30 + .../modbusslave/ModbusRecordFloat64Test.java | 30 + .../modbusslave/ModbusRecordString16Test.java | 42 + .../modbusslave/ModbusRecordUint16Test.java | 52 + .../modbusslave/ModbusRecordUint32Test.java | 40 + .../modbusslave/ModbusRecordUint64Test.java | 40 + .../api/backend/WebsocketClient.java | 1 + .../edge/controller/api/backend/WsData.java | 16 - io.openems.edge.controller.api.modbus/bnd.bnd | 1 + .../api/modbus/AbstractModbusTcpApi.java | 2 +- .../GetModbusProtocolExportXlsxResponse.java | 28 +- .../ControllerApiModbusTcpReadWriteImpl.java | 105 +- ...ntrollerApiModbusTcpReadWriteImplTest.java | 30 +- io.openems.edge.controller.api.mqtt/bnd.bnd | 4 +- .../edge/controller/api/websocket/WsData.java | 17 +- .../.classpath | 12 + .../.gitignore | 2 + .../.project | 23 + .../org.eclipse.core.resources.prefs | 2 + .../bnd.bnd | 16 + .../doc/statemachine.md | 18 + .../readme.adoc | 333 ++++ .../ess/fastfrequencyreserve/Config.java | 54 + .../ControllerFastFrequencyReserve.java | 283 ++++ .../ControllerFastFrequencyReserveImpl.java | 312 ++++ .../enums/ActivationTime.java | 30 + .../enums/ControlMode.java | 32 + .../enums/SupportDuration.java | 32 + .../SetActivateFastFreqReserveRequest.java | 228 +++ .../statemachine/ActivationTimeHandler.java | 106 ++ .../BufferedTimeBeforeRecoveryHandler.java | 103 ++ .../statemachine/Context.java | 64 + .../statemachine/DeactivationTimeHandler.java | 81 + .../statemachine/PreActivationHandler.java | 53 + .../statemachine/RecoveryTimeHandler.java | 29 + .../statemachine/StateMachine.java | 62 + .../SupportDurationTimeHandler.java | 64 + .../statemachine/UndefinedHandler.java | 40 + .../test/.gitignore | 0 .../ess/fastfrequencyreserve/JsonRpcTest.java | 68 + .../ess/fastfrequencyreserve/MyConfig.java | 107 ++ .../MyControllerTest.java | 295 ++++ .../MyControllerTest2.java | 185 +++ .../ess/fastfrequencyreserve/TestClient.java | 122 ++ .../ControllerEssGridOptimizedCharge.java | 25 + .../ControllerEssGridOptimizedChargeImpl.java | 7 + .../translation_de.properties | 2 + .../translation_en.properties | 2 + ...trollerEssGridOptimizedChargeImplTest.java | 37 + .../openems/edge/controller/evcs/Config.java | 6 + .../edge/controller/evcs/ControllerEvcs.java | 10 +- .../controller/evcs/ControllerEvcsImpl.java | 96 ++ .../evcs/ControllerEvcsImplTest.java | 83 + .../edge/controller/evcs/MyConfig.java | 22 + .../FeneconHomeComponents.java | 23 +- .../app/timeofusetariff/AwattarHourly.java | 3 +- .../edge/app/timeofusetariff/EntsoE.java | 3 +- .../edge/app/timeofusetariff/GroupeE.java | 3 +- .../edge/app/timeofusetariff/RabotCharge.java | 3 +- .../timeofusetariff/StadtwerkHassfurt.java | 3 +- .../timeofusetariff/StromdaoCorrently.java | 3 +- .../edge/app/timeofusetariff/Tibber.java | 3 +- .../ComponentAggregateTaskImpl.java | 32 +- .../core/appmanager/translation_de.properties | 7 +- .../core/appmanager/translation_en.properties | 7 +- .../core/appmanager/validator/Checkables.java | 20 +- .../io/openems/edge/core/meta/MetaImpl.java | 17 + .../src/io/openems/edge/core/sum/SumImpl.java | 1 - .../edge2edge/common/AbstractEdge2Edge.java | 22 +- .../src/io/openems/edge/energy/Config.java | 3 + .../edge/energy/EnergySchedulerImpl.java | 60 +- .../io/openems/edge/energy/LogVerbosity.java | 13 + .../edge/energy/optimizer/Optimizer.java | 21 +- .../edge/energy/EnergySchedulerImplTest.java | 6 +- .../test/io/openems/edge/energy/MyConfig.java | 29 +- .../io/openems/edge/ess/api/HybridEss.java | 2 + .../edge/ess/api/ManagedSymmetricEss.java | 2 +- .../io/openems/edge/ess/api/SymmetricEss.java | 1 + .../io/openems/edge/ess/core/power/Data.java | 4 +- .../edge/ess/core/power/EssPowerImpl.java | 20 +- .../ess/core/power/data/LinearSolverUtil.java | 44 +- .../core/power/data/LinearSolverUtilTest.java | 44 + .../common/AbstractGenericManagedEss.java | 22 +- .../ess/generic/common/GenericManagedEss.java | 144 +- .../generic/offgrid/EssGenericOffGrid.java | 2 +- .../symmetric/EssGenericManagedSymmetric.java | 49 + .../EssGenericManagedSymmetricImpl.java | 12 +- .../symmetric/statemachine/Context.java | 47 +- .../symmetric/statemachine/ErrorHandler.java | 50 +- .../statemachine/StartBatteryHandler.java | 42 +- .../StartBatteryInverterHandler.java | 46 +- .../statemachine/StartedHandler.java | 16 +- .../statemachine/StopBatteryHandler.java | 46 +- .../StopBatteryInverterHandler.java | 43 +- .../statemachine/StoppedHandler.java | 16 +- .../statemachine/UndefinedHandler.java | 34 +- .../EssGenericManagedSymmetricImplTest.java | 32 + .../edge/evcs/hardybarth/EvcsHardyBarth.java | 4 +- .../evcs/hardybarth/translation_de.properties | 1 + .../evcs/hardybarth/translation_en.properties | 1 + .../keba/kecontact/EvcsKebaKeContact.java | 3 +- .../GoodWeBatteryInverter.java | 2 +- .../GoodWeBatteryInverterImpl.java | 4 +- .../io/openems/edge/goodwe/common/GoodWe.java | 44 +- .../simulator/meter/grid/acting/Config.java | 7 + .../grid/acting/SimulatorGridMeterActing.java | 36 + .../acting/SimulatorGridMeterActingImpl.java | 65 + .../simulator/meter/grid/acting/State.java | 33 + .../grid/acting/StepResponseHandler.java | 57 + .../simulator/meter/grid/acting/MyConfig.java | 22 + .../SimulatorGridMeterActingImplTest.java | 23 + .../edge/timedata/rrd4j/Rrd4jReadHandler.java | 3 +- .../edge/timedata/rrd4j/Rrd4jSupplier.java | 2 +- io.openems.wrapper/bnd.bnd | 4 + io.openems.wrapper/helins-linux-i2c.bnd | 20 + ui/.eslintrc.json | 11 + ui/angular.json | 15 +- ui/package-lock.json | 1444 +++++++++-------- ui/package.json | 4 +- ui/src/app/app-routing.module.ts | 3 +- .../app/edge/history/abstracthistorychart.ts | 62 +- .../consumption/details/details.overview.html | 2 +- .../common/energy/chart/channels.spec.ts | 4 +- .../edge/history/common/energy/chart/chart.ts | 1 + .../common/grid/details/details.overview.html | 4 +- .../common/grid/details/details.overview.ts | 19 +- .../common/grid/overview/overview.html | 2 +- .../history/common/grid/overview/overview.ts | 20 +- .../production/details/details.overview.html | 2 +- .../common/production/overview/overview.ts | 4 +- .../app/edge/history/history.component.html | 4 - .../TimeOfUseTariff/modal/statePriceChart.ts | 5 +- .../live/Controller/Evcs/modal/modal.html | 12 + .../edge/live/Controller/Evcs/modal/modal.ts | 3 + ui/src/app/edge/live/live.module.ts | 16 +- ui/src/app/index/login.component.ts | 18 +- ui/src/app/index/login.spec.ts | 16 +- .../components/chart/abstracthistorychart.ts | 23 +- .../components/chart/chart.constants.ts | 4 +- ui/src/app/shared/components/chart/chart.html | 3 +- .../currentVoltage/chart/asymmetricMeter.ts | 12 +- .../currentVoltage/chart/symmetricMeter.ts | 13 +- .../currentVoltage.overview.html | 3 +- .../edge/offline/offline.component.html | 6 + .../edge}/offline/offline.component.ts | 12 +- .../components/edge/offline/offline.module.ts | 18 + .../flat/abstract-flat-widget-line.ts | 19 + .../flat-widget-line-item.html | 5 +- .../flat-widget-line/flat-widget-line.html | 4 +- .../flat/flat-widget-line/flat-widget-line.ts | 3 - .../form-field-multi-step.html | 66 + .../form-field-multi-step.ts | 70 + .../formly-field-checkbox-with-image.html | 11 +- .../formly-field-checkbox-with-image.ts | 19 +- .../components/header/header.component.ts | 17 +- .../app/shared/components/shared/converter.ts | 14 + .../app/shared/components/shared/formatter.ts | 29 +- .../components/shared/testing/common.ts | 7 +- .../components/shared/testing/tester.ts | 1 + .../app/shared/jsonrpc/jsonrpcutils.spec.ts | 10 + ui/src/app/shared/jsonrpc/jsonrpcutils.ts | 20 + ui/src/app/shared/service/defaulttypes.ts | 12 +- ui/src/app/shared/service/service.ts | 20 +- ui/src/app/shared/service/utils.spec.ts | 10 +- ui/src/app/shared/service/utils.ts | 10 +- ui/src/app/shared/shared.module.ts | 3 + ui/src/app/user/user.component.html | 11 +- ui/src/app/user/user.component.ts | 8 + ui/src/assets/i18n/de.json | 5 +- ui/src/assets/i18n/en.json | 7 +- ui/src/global-ion-custom.scss | 11 + ui/src/global.scss | 14 +- 244 files changed, 6793 insertions(+), 1925 deletions(-) create mode 100644 io.openems.backend.b2bwebsocket/test/io/openems/backend/b2bwebsocket/WsDataTest.java create mode 100644 io.openems.backend.edgewebsocket/test/io/openems/backend/edgewebsocket/WsDataTest.java create mode 100644 io.openems.backend.uiwebsocket/test/io/openems/backend/uiwebsocket/impl/WsDataTest.java create mode 100644 io.openems.common/src/io/openems/common/timedata/Timeout.java create mode 100644 io.openems.common/test/io/openems/common/timedata/TimeoutTest.java create mode 100644 io.openems.common/test/io/openems/common/websocket/DummyWebsocketServerTest.java create mode 100644 io.openems.common/test/io/openems/common/websocket/WebsocketUtilsTest.java create mode 100644 io.openems.common/test/io/openems/common/websocket/WsDataTest.java create mode 100644 io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/Config.java create mode 100644 io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordUint64.java create mode 100644 io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordUint64Reserved.java create mode 100644 io.openems.edge.common/test/io/openems/edge/common/modbusslave/ModbusRecordFloat32Test.java create mode 100644 io.openems.edge.common/test/io/openems/edge/common/modbusslave/ModbusRecordFloat64Test.java create mode 100644 io.openems.edge.common/test/io/openems/edge/common/modbusslave/ModbusRecordString16Test.java create mode 100644 io.openems.edge.common/test/io/openems/edge/common/modbusslave/ModbusRecordUint16Test.java create mode 100644 io.openems.edge.common/test/io/openems/edge/common/modbusslave/ModbusRecordUint32Test.java create mode 100644 io.openems.edge.common/test/io/openems/edge/common/modbusslave/ModbusRecordUint64Test.java delete mode 100644 io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/WsData.java create mode 100644 io.openems.edge.controller.ess.fastfrequencyreserve/.classpath create mode 100644 io.openems.edge.controller.ess.fastfrequencyreserve/.gitignore create mode 100644 io.openems.edge.controller.ess.fastfrequencyreserve/.project create mode 100644 io.openems.edge.controller.ess.fastfrequencyreserve/.settings/org.eclipse.core.resources.prefs create mode 100644 io.openems.edge.controller.ess.fastfrequencyreserve/bnd.bnd create mode 100644 io.openems.edge.controller.ess.fastfrequencyreserve/doc/statemachine.md create mode 100644 io.openems.edge.controller.ess.fastfrequencyreserve/readme.adoc create mode 100644 io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/Config.java create mode 100644 io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/ControllerFastFrequencyReserve.java create mode 100644 io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/ControllerFastFrequencyReserveImpl.java create mode 100644 io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/enums/ActivationTime.java create mode 100644 io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/enums/ControlMode.java create mode 100644 io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/enums/SupportDuration.java create mode 100644 io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/jsonrpc/SetActivateFastFreqReserveRequest.java create mode 100644 io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/ActivationTimeHandler.java create mode 100644 io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/BufferedTimeBeforeRecoveryHandler.java create mode 100644 io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/Context.java create mode 100644 io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/DeactivationTimeHandler.java create mode 100644 io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/PreActivationHandler.java create mode 100644 io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/RecoveryTimeHandler.java create mode 100644 io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/StateMachine.java create mode 100644 io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/SupportDurationTimeHandler.java create mode 100644 io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/UndefinedHandler.java create mode 100644 io.openems.edge.controller.ess.fastfrequencyreserve/test/.gitignore create mode 100644 io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/JsonRpcTest.java create mode 100644 io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/MyConfig.java create mode 100644 io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/MyControllerTest.java create mode 100644 io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/MyControllerTest2.java create mode 100644 io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/TestClient.java create mode 100644 io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/translation_de.properties create mode 100644 io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/translation_en.properties create mode 100644 io.openems.edge.energy/src/io/openems/edge/energy/LogVerbosity.java create mode 100644 io.openems.edge.ess.core/test/io/openems/edge/ess/core/power/data/LinearSolverUtilTest.java create mode 100644 io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/translation_de.properties create mode 100644 io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/translation_en.properties create mode 100644 io.openems.edge.simulator/src/io/openems/edge/simulator/meter/grid/acting/State.java create mode 100644 io.openems.edge.simulator/src/io/openems/edge/simulator/meter/grid/acting/StepResponseHandler.java create mode 100644 io.openems.wrapper/helins-linux-i2c.bnd create mode 100644 ui/src/app/shared/components/edge/offline/offline.component.html rename ui/src/app/{edge/live => shared/components/edge}/offline/offline.component.ts (78%) create mode 100644 ui/src/app/shared/components/edge/offline/offline.module.ts create mode 100644 ui/src/app/shared/components/formly/form-field-multi-step/form-field-multi-step.html create mode 100644 ui/src/app/shared/components/formly/form-field-multi-step/form-field-multi-step.ts create mode 100644 ui/src/app/shared/jsonrpc/jsonrpcutils.spec.ts create mode 100644 ui/src/global-ion-custom.scss diff --git a/cnf/pom.xml b/cnf/pom.xml index 83b8c69ddd9..dca7896bc3f 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -139,6 +139,34 @@ 1.5 + + + + io.helins + linux-common + 0.1.4 + + + + + io.helins + linux-i2c + 1.0.2 + + + + + io.helins + linux-io + 0.0.4 + + + + + io.helins + linux-errno + 1.0.2 + io.reactivex.rxjava3 rxjava @@ -254,8 +282,8 @@ org.bouncycastle - bcpkix-jdk15on - 1.70 + bcpkix-jdk15to18 + 1.77 org.dhatim @@ -414,4 +442,4 @@ 3.9 - + \ No newline at end of file diff --git a/io.openems.backend.application/test/io/openems/backend/edge/application/TestClient.java b/io.openems.backend.application/test/io/openems/backend/edge/application/TestClient.java index c6030384134..12c4a97ac8a 100644 --- a/io.openems.backend.application/test/io/openems/backend/edge/application/TestClient.java +++ b/io.openems.backend.application/test/io/openems/backend/edge/application/TestClient.java @@ -92,12 +92,7 @@ public void setOnNotification(OnNotification onNotification) { @Override protected WsData createWsData(WebSocket ws) { - return new WsData(ws) { - @Override - public String toString() { - return "TestClient.WsData []"; - } - }; + return new WsData(ws); } @Override diff --git a/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/WsData.java b/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/WsData.java index 24298d8c0f2..9276a41a2c1 100644 --- a/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/WsData.java +++ b/io.openems.backend.b2bwebsocket/src/io/openems/backend/b2bwebsocket/WsData.java @@ -65,7 +65,11 @@ public SubscribedEdgesChannelsWorker getSubscribedChannelsWorker() { } @Override - public String toString() { - return "B2bWebsocket.WsData [user=" + this.user.getNow(null) + "]"; + public String toLogString() { + var user = this.user.getNow(null); + var userId = user == null // + ? "UNDEFINED" // + : user.getId(); + return "B2bWebsocket.WsData [user=" + userId + "]"; } } diff --git a/io.openems.backend.b2bwebsocket/test/io/openems/backend/b2bwebsocket/TestClient.java b/io.openems.backend.b2bwebsocket/test/io/openems/backend/b2bwebsocket/TestClient.java index 3f313d2c93b..1e04b149df7 100644 --- a/io.openems.backend.b2bwebsocket/test/io/openems/backend/b2bwebsocket/TestClient.java +++ b/io.openems.backend.b2bwebsocket/test/io/openems/backend/b2bwebsocket/TestClient.java @@ -93,12 +93,7 @@ public void setOnNotification(OnNotification onNotification) { @Override protected WsData createWsData(WebSocket ws) { - return new WsData(ws) { - @Override - public String toString() { - return "TestClient.WsData []"; - } - }; + return new WsData(ws); } @Override diff --git a/io.openems.backend.b2bwebsocket/test/io/openems/backend/b2bwebsocket/WsDataTest.java b/io.openems.backend.b2bwebsocket/test/io/openems/backend/b2bwebsocket/WsDataTest.java new file mode 100644 index 00000000000..eeedb52b567 --- /dev/null +++ b/io.openems.backend.b2bwebsocket/test/io/openems/backend/b2bwebsocket/WsDataTest.java @@ -0,0 +1,35 @@ +package io.openems.backend.b2bwebsocket; + +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThrows; + +import java.util.Optional; + +import org.junit.Test; + +import io.openems.backend.common.metadata.User; +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; + +public class WsDataTest { + + @Test + public void test() throws OpenemsNamedException { + var sut = new WsData(null, null); + assertEquals("B2bWebsocket.WsData [user=UNDEFINED]", sut.toLogString()); + assertEquals(Optional.empty(), sut.getUserOpt()); + assertThrows(OpenemsNamedException.class, () -> sut.getUserWithTimeout(1, MILLISECONDS)); + assertEquals(null, sut.getUser().getNow(null)); + + var user = new User("foo", null, null, null, null, false, null); + sut.setUser(user); + assertEquals("B2bWebsocket.WsData [user=foo]", sut.toLogString()); + assertEquals(Optional.of(user), sut.getUserOpt()); + assertEquals(user, sut.getUserWithTimeout(1, MILLISECONDS)); + assertNotNull(sut.getSubscribedChannelsWorker()); + + sut.dispose(); + } + +} diff --git a/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/WsData.java b/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/WsData.java index 180eaca7c5a..6ff6bab290d 100644 --- a/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/WsData.java +++ b/io.openems.backend.edgewebsocket/src/io/openems/backend/edgewebsocket/WsData.java @@ -76,10 +76,11 @@ public synchronized Optional getEdgeId() { } @Override - public String toString() { - return "EdgeWebsocket.WsData [" // - + "edgeId=" + this.edgeId.orElse("UNKNOWN") // - + "]"; + protected String toLogString() { + return new StringBuilder("EdgeWebsocket.WsData [edgeId=") // + .append(this.edgeId.orElse("UNKNOWN")) // + .append("]") // + .toString(); } } diff --git a/io.openems.backend.edgewebsocket/test/io/openems/backend/edgewebsocket/WsDataTest.java b/io.openems.backend.edgewebsocket/test/io/openems/backend/edgewebsocket/WsDataTest.java new file mode 100644 index 00000000000..707168f40e3 --- /dev/null +++ b/io.openems.backend.edgewebsocket/test/io/openems/backend/edgewebsocket/WsDataTest.java @@ -0,0 +1,37 @@ +package io.openems.backend.edgewebsocket; + +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; + +import java.util.Optional; + +import org.junit.Test; + +import com.google.gson.JsonObject; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.exceptions.OpenemsException; +import io.openems.common.jsonrpc.base.GenericJsonrpcNotification; +import io.openems.common.jsonrpc.base.JsonrpcMessage; + +public class WsDataTest { + + private static final String EDGE_ID = "edge0"; + private static final JsonrpcMessage JMSG = new GenericJsonrpcNotification("foo", new JsonObject()); + + @Test + public void test() throws OpenemsException { + var sut = new WsData(null); + assertEquals("EdgeWebsocket.WsData [edgeId=UNKNOWN]", sut.toLogString()); + assertThrows(OpenemsNamedException.class, () -> sut.assertEdgeId(JMSG)); + assertThrows(OpenemsNamedException.class, () -> sut.assertEdgeIdWithTimeout(JMSG, 1, MILLISECONDS)); + + sut.setEdgeId(EDGE_ID); + assertEquals("EdgeWebsocket.WsData [edgeId=edge0]", sut.toLogString()); + sut.assertEdgeId(null); + sut.assertEdgeIdWithTimeout(JMSG, 1, MILLISECONDS); + assertEquals(Optional.of(EDGE_ID), sut.getEdgeId()); + } + +} diff --git a/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/WsData.java b/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/WsData.java index c60424b0d3d..b2bfdca34ef 100644 --- a/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/WsData.java +++ b/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/WsData.java @@ -154,14 +154,15 @@ public String assertToken() throws OpenemsNamedException { } @Override - public String toString() { - String tokenString; - if (this.token.isPresent()) { - tokenString = this.token.get().toString(); - } else { - tokenString = "UNKNOWN"; - } - return "UiWebsocket.WsData [userId=" + this.userId.orElse("UNKNOWN") + ", token=" + tokenString + "]"; + protected String toLogString() { + return new StringBuilder("UiWebsocket.WsData [userId=") // + .append(this.userId.orElse("UNKNOWN")) // + .append(", token=") // + .append(this.token.isPresent() // + ? this.token.get().toString() // + : "UNKNOWN") // + .append("]") // + .toString(); } /** diff --git a/io.openems.backend.uiwebsocket/test/io/openems/backend/uiwebsocket/impl/WsDataTest.java b/io.openems.backend.uiwebsocket/test/io/openems/backend/uiwebsocket/impl/WsDataTest.java new file mode 100644 index 00000000000..8832a3c6dfd --- /dev/null +++ b/io.openems.backend.uiwebsocket/test/io/openems/backend/uiwebsocket/impl/WsDataTest.java @@ -0,0 +1,35 @@ +package io.openems.backend.uiwebsocket.impl; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; + +import java.util.Optional; + +import org.junit.Test; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; + +public class WsDataTest { + + private static final String USER_ID = "user0"; + private static final String TOKEN = "token"; + + @Test + public void test() throws OpenemsNamedException { + var sut = new WsData(null); + assertEquals(Optional.empty(), sut.getUser(null)); + assertThrows(OpenemsNamedException.class, () -> sut.assertToken()); + assertEquals("UiWebsocket.WsData [userId=UNKNOWN, token=UNKNOWN]", sut.toLogString()); + + sut.setUserId(USER_ID); + sut.setToken(TOKEN); + + assertEquals(Optional.of(USER_ID), sut.getUserId()); + assertEquals(Optional.of(TOKEN), sut.getToken()); + assertEquals(TOKEN, sut.assertToken()); + assertEquals("UiWebsocket.WsData [userId=user0, token=token]", sut.toLogString()); + + sut.logout(); + } + +} 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 466ea4fbef6..2bcc50113fd 100644 --- a/io.openems.common/src/io/openems/common/channel/Unit.java +++ b/io.openems.common/src/io/openems/common/channel/Unit.java @@ -284,7 +284,12 @@ public enum Unit { /** * Unit of Pressure [bar]. */ - BAR("bar"); + BAR("bar"), + + /** + * Unit of Pressure [mbar]. + */ + MILLIBAR("mbar", BAR, -3); public final String symbol; public final Unit baseUnit; @@ -363,7 +368,7 @@ public String format(Object value, OpenemsType type) { MILLIWATT, WATT_HOURS, OHM, KILOOHM, SECONDS, AMPERE_HOURS, HOUR, CUMULATED_SECONDS, KILOAMPERE_HOURS, KILOVOLT_AMPERE, KILOVOLT_AMPERE_REACTIVE, KILOVOLT_AMPERE_REACTIVE_HOURS, KILOWATT_HOURS, MICROOHM, MILLIAMPERE_HOURS, MILLIOHM, MILLISECONDS, MINUTE, THOUSANDTH, VOLT_AMPERE_HOURS, - VOLT_AMPERE_REACTIVE_HOURS, WATT_HOURS_BY_WATT_PEAK, CUMULATED_WATT_HOURS, BAR -> // + VOLT_AMPERE_REACTIVE_HOURS, WATT_HOURS_BY_WATT_PEAK, CUMULATED_WATT_HOURS, BAR, MILLIBAR -> // value + " " + this.symbol; case ON_OFF -> // diff --git a/io.openems.common/src/io/openems/common/timedata/Timeout.java b/io.openems.common/src/io/openems/common/timedata/Timeout.java new file mode 100644 index 00000000000..bb489594998 --- /dev/null +++ b/io.openems.common/src/io/openems/common/timedata/Timeout.java @@ -0,0 +1,55 @@ +package io.openems.common.timedata; + +import java.time.Clock; +import java.time.Duration; +import java.time.Instant; + +public class Timeout { + + private Instant entryTime = Instant.MIN; + private Duration timeout; + + private Timeout(Duration duration) { + this.timeout = duration; + } + + /** + * Get the {@link Timeout} of seconds. + * + * @param timeout the amount seconds + * @return the {@link Timeout} + */ + public static Timeout ofSeconds(int timeout) { + return new Timeout(Duration.ofSeconds(timeout)); + } + + /** + * Get the {@link Timeout} of minutes. + * + * @param timeout the amount minutes + * @return the {@link Timeout} + */ + public static Timeout ofMinutes(int timeout) { + return new Timeout(Duration.ofMinutes(timeout)); + } + + /** + * Sets the entry time. + * + * @param clock the {@link Clock} + */ + public void start(Clock clock) { + this.entryTime = Instant.now(clock); + } + + /** + * Checks the whether time elapsed. + * + * @param clock the {@link Clock} + * @return true if time is elapsed + */ + public boolean elapsed(Clock clock) { + return Instant.now(clock).isAfter(this.entryTime.plus(this.timeout)); + } + +} diff --git a/io.openems.common/src/io/openems/common/websocket/AbstractWebsocket.java b/io.openems.common/src/io/openems/common/websocket/AbstractWebsocket.java index c76b34dd560..f313c175896 100644 --- a/io.openems.common/src/io/openems/common/websocket/AbstractWebsocket.java +++ b/io.openems.common/src/io/openems/common/websocket/AbstractWebsocket.java @@ -128,11 +128,17 @@ protected final boolean sendMessage(WebSocket ws, JsonrpcMessage message) { } private void sendMessageFailedLog(WebSocket ws, JsonrpcMessage message) { - this.logWarn(this.log, new StringBuilder() // - .append("[").append(generateWsDataString(ws)) // - .append("] Unable to send message: Connection is closed. ") // - .append(toShortString(simplifyJsonrpcMessage(message), 100)) // - .toString()); + final var b = new StringBuilder(); + + var wsDataString = generateWsDataString(ws); + if (!wsDataString.isEmpty()) { + b.append("[").append(generateWsDataString(ws)).append("] "); + } + + this.logWarn(this.log, // + b.append("Unable to send message: Connection is closed. ") // + .append(toShortString(simplifyJsonrpcMessage(message), 200)) // + .toString()); } /** diff --git a/io.openems.common/src/io/openems/common/websocket/DummyWebsocketServer.java b/io.openems.common/src/io/openems/common/websocket/DummyWebsocketServer.java index b815deeb71c..f4b2b6cf916 100644 --- a/io.openems.common/src/io/openems/common/websocket/DummyWebsocketServer.java +++ b/io.openems.common/src/io/openems/common/websocket/DummyWebsocketServer.java @@ -93,12 +93,7 @@ private DummyWebsocketServer(DummyWebsocketServer.Builder builder) { @Override protected WsData createWsData(WebSocket ws) { - return new WsData(ws) { - @Override - public String toString() { - return "DummyWebsocketServer.WsData []"; - } - }; + return new WsData(ws); } @Override diff --git a/io.openems.common/src/io/openems/common/websocket/WebsocketUtils.java b/io.openems.common/src/io/openems/common/websocket/WebsocketUtils.java index e9f51ae5b04..cb80dc12b69 100644 --- a/io.openems.common/src/io/openems/common/websocket/WebsocketUtils.java +++ b/io.openems.common/src/io/openems/common/websocket/WebsocketUtils.java @@ -53,11 +53,11 @@ public static String parseRemoteIdentifier(WebSocket ws, Handshakedata handshake } /** - * Gets the toString() content of the WsData attachment of the WebSocket; or + * Gets the toLogString() content of the WsData attachment of the WebSocket; or * empty string if not available. * * @param ws the WebSocket - * @return the {@link WsData#toString()} content + * @return the {@link WsData#toLogString()} content */ public static String generateWsDataString(WebSocket ws) { if (ws == null) { @@ -67,6 +67,10 @@ public static String generateWsDataString(WebSocket ws) { if (wsData == null) { return ""; } - return wsData.toString(); + var logString = wsData.toLogString(); + if (logString == null) { + return ""; + } + return logString; } } diff --git a/io.openems.common/src/io/openems/common/websocket/WsData.java b/io.openems.common/src/io/openems/common/websocket/WsData.java index b43aedad7f7..852b4290125 100644 --- a/io.openems.common/src/io/openems/common/websocket/WsData.java +++ b/io.openems.common/src/io/openems/common/websocket/WsData.java @@ -21,14 +21,14 @@ * Objects of this class are used to store additional data with websocket * connections of WebSocketClient and WebSocketServer. */ -public abstract class WsData { +public class WsData { /** * Holds the WebSocket. */ private final WebSocket websocket; - protected WsData(WebSocket ws) { + public WsData(WebSocket ws) { this.websocket = ws; } @@ -138,10 +138,11 @@ public void handleJsonrpcResponse(JsonrpcResponse response) throws OpenemsNamedE } /** - * Provides a specific toString method. + * Provides a specific log string. * * @return a specific string for this instance */ - @Override - public abstract String toString(); + protected String toLogString() { + return ""; + } } diff --git a/io.openems.common/src/io/openems/common/worker/AbstractWorker.java b/io.openems.common/src/io/openems/common/worker/AbstractWorker.java index 29b371fd99b..c78b265fb2b 100644 --- a/io.openems.common/src/io/openems/common/worker/AbstractWorker.java +++ b/io.openems.common/src/io/openems/common/worker/AbstractWorker.java @@ -65,9 +65,7 @@ public void activate(String name) { * false */ public void modified(String name, boolean initiallyTriggerNextRun) { - if (!this.thread.isAlive() && !this.thread.isInterrupted() && !this.isStopped.get()) { - this.startWorker(name, initiallyTriggerNextRun); - } + this.startWorker(name, initiallyTriggerNextRun); } /** @@ -79,12 +77,13 @@ public void modified(String name) { this.modified(name, true); } - private void startWorker(String name, boolean autoTriggerNextRun) { + private synchronized void startWorker(String name, boolean autoTriggerNextRun) { if (name != null) { this.thread.setName(name); } - this.thread.start(); - + if (!this.thread.isAlive() && !this.thread.isInterrupted() && !this.isStopped.get()) { + this.thread.start(); + } if (autoTriggerNextRun) { this.triggerNextRun(); } diff --git a/io.openems.common/test/io/openems/common/timedata/TimeoutTest.java b/io.openems.common/test/io/openems/common/timedata/TimeoutTest.java new file mode 100644 index 00000000000..15ef3d8b49d --- /dev/null +++ b/io.openems.common/test/io/openems/common/timedata/TimeoutTest.java @@ -0,0 +1,27 @@ +package io.openems.common.timedata; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.time.temporal.ChronoUnit; + +import org.junit.Test; + +import io.openems.common.test.TimeLeapClock; + +public class TimeoutTest { + + @Test + public void test() { + final var timeout = Timeout.ofSeconds(120); + final var timeLeap = new TimeLeapClock(); + timeout.start(timeLeap); + + timeLeap.leap(20, ChronoUnit.SECONDS); + assertFalse(timeout.elapsed(timeLeap)); + + timeLeap.leap(121, ChronoUnit.SECONDS); + assertTrue(timeout.elapsed(timeLeap)); + } + +} diff --git a/io.openems.common/test/io/openems/common/websocket/ClientReconnectorWorkerTest.java b/io.openems.common/test/io/openems/common/websocket/ClientReconnectorWorkerTest.java index 3eb4161bd07..62373bfe85a 100644 --- a/io.openems.common/test/io/openems/common/websocket/ClientReconnectorWorkerTest.java +++ b/io.openems.common/test/io/openems/common/websocket/ClientReconnectorWorkerTest.java @@ -9,28 +9,15 @@ public class ClientReconnectorWorkerTest { - private static class MyWsData extends WsData { - - public MyWsData(WebSocket ws) { - super(ws); - } - - @Override - public String toString() { - return ""; - } - - } - - private static class MyWebsocketClient extends AbstractWebsocketClient { + private static class MyWebsocketClient extends AbstractWebsocketClient { public MyWebsocketClient(String name, URI serverUri) { super(name, serverUri); } @Override - protected MyWsData createWsData(WebSocket ws) { - return new MyWsData(ws); + protected WsData createWsData(WebSocket ws) { + return new WsData(ws); } @Override diff --git a/io.openems.common/test/io/openems/common/websocket/DummyWebsocketServerTest.java b/io.openems.common/test/io/openems/common/websocket/DummyWebsocketServerTest.java new file mode 100644 index 00000000000..172d3516be5 --- /dev/null +++ b/io.openems.common/test/io/openems/common/websocket/DummyWebsocketServerTest.java @@ -0,0 +1,15 @@ +package io.openems.common.websocket; + +import org.junit.Test; + +public class DummyWebsocketServerTest { + + @Test + public void test() { + var sut = DummyWebsocketServer.create() // + .build(); + sut.createWsData(null); + sut.stop(); + } + +} diff --git a/io.openems.common/test/io/openems/common/websocket/WebsocketUtilsTest.java b/io.openems.common/test/io/openems/common/websocket/WebsocketUtilsTest.java new file mode 100644 index 00000000000..25febb897d4 --- /dev/null +++ b/io.openems.common/test/io/openems/common/websocket/WebsocketUtilsTest.java @@ -0,0 +1,15 @@ +package io.openems.common.websocket; + +import static io.openems.common.websocket.WebsocketUtils.generateWsDataString; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class WebsocketUtilsTest { + + @Test + public void test() { + assertEquals("", generateWsDataString(null)); + } + +} diff --git a/io.openems.common/test/io/openems/common/websocket/WsDataTest.java b/io.openems.common/test/io/openems/common/websocket/WsDataTest.java new file mode 100644 index 00000000000..5dd1a7aad2f --- /dev/null +++ b/io.openems.common/test/io/openems/common/websocket/WsDataTest.java @@ -0,0 +1,17 @@ +package io.openems.common.websocket; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class WsDataTest { + + @Test + public void test() { + var sut = new WsData(null); + assertEquals("", sut.toLogString()); + + sut.dispose(); + } + +} diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index 11442b68bce..fe957a9b082 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -74,6 +74,7 @@ bnd.identity;id='io.openems.edge.controller.ess.delaycharge',\ bnd.identity;id='io.openems.edge.controller.ess.delayedselltogrid',\ bnd.identity;id='io.openems.edge.controller.ess.emergencycapacityreserve',\ + bnd.identity;id='io.openems.edge.controller.ess.fastfrequencyreserve',\ bnd.identity;id='io.openems.edge.controller.ess.fixactivepower',\ bnd.identity;id='io.openems.edge.controller.ess.fixstateofcharge',\ bnd.identity;id='io.openems.edge.controller.ess.gridoptimizedcharge',\ @@ -193,9 +194,9 @@ -runbundles: \ Java-WebSocket;version='[1.5.4,1.5.5)',\ - bcpkix;version='[1.70.0,1.70.1)',\ - bcprov;version='[1.70.0,1.70.1)',\ - bcutil;version='[1.70.0,1.70.1)',\ + bcpkix;version='[1.77.0,1.77.1)',\ + bcprov;version='[1.77.0,1.77.1)',\ + bcutil;version='[1.77.0,1.77.1)',\ com.fasterxml.aalto-xml;version='[1.3.3,1.3.4)',\ com.fazecast.jSerialComm;version='[2.10.4,2.10.5)',\ com.ghgande.j2mod;version='[3.2.1,3.2.2)',\ @@ -245,6 +246,7 @@ io.openems.edge.controller.ess.delaycharge;version=snapshot,\ io.openems.edge.controller.ess.delayedselltogrid;version=snapshot,\ io.openems.edge.controller.ess.emergencycapacityreserve;version=snapshot,\ + io.openems.edge.controller.ess.fastfrequencyreserve;version=snapshot,\ io.openems.edge.controller.ess.fixactivepower;version=snapshot,\ io.openems.edge.controller.ess.fixstateofcharge;version=snapshot,\ io.openems.edge.controller.ess.gridoptimizedcharge;version=snapshot,\ diff --git a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/BydBatteryBoxCommercialC130.java b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/BydBatteryBoxCommercialC130.java index 2dedfc9f26a..72d31daa444 100644 --- a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/BydBatteryBoxCommercialC130.java +++ b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/BydBatteryBoxCommercialC130.java @@ -787,27 +787,27 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { LEVEL1_CHARGE_CURRENT_HIGH(Doc.of(Level.WARNING) // .text("Cluster 2 Charge Current High Alarm Level 2")), // - LEVEL2_CELL_VOLTAGE_HIGH(Doc.of(Level.FAULT) // + LEVEL2_CELL_VOLTAGE_HIGH(Doc.of(Level.WARNING) // .text("Cluster 3 Cell Voltage High Alarm Level 3")), // - LEVEL2_CELL_VOLTAGE_LOW(Doc.of(Level.FAULT) // + LEVEL2_CELL_VOLTAGE_LOW(Doc.of(Level.WARNING) // .text("Cluster 3 Cell Voltage Low Alarm Level 3")), // - LEVEL2_CELL_VOLTAGE_DIFF_TOO_BIG(Doc.of(Level.FAULT) // + LEVEL2_CELL_VOLTAGE_DIFF_TOO_BIG(Doc.of(Level.WARNING) // .text("Alarm Level 3 Battery Cells Unbalanced")), // - LEVEL2_DISCHARGE_TEMP_HIGH(Doc.of(Level.FAULT) // + LEVEL2_DISCHARGE_TEMP_HIGH(Doc.of(Level.WARNING) // .text("Cluster 3 Cell Discharge Temperature High Alarm Level 3")), // - LEVEL2_DISCHARGE_TEMP_LOW(Doc.of(Level.FAULT) // + LEVEL2_DISCHARGE_TEMP_LOW(Doc.of(Level.WARNING) // .text("Cluster 3 Cell Discharge Temperature Low Alarm Level 3")), // - LEVEL2_CHARGE_TEMP_HIGH(Doc.of(Level.FAULT) // + LEVEL2_CHARGE_TEMP_HIGH(Doc.of(Level.WARNING) // .text("Cluster 3 Cell Charge Temperature High Alarm Level 3")), // - LEVEL2_CHARGE_TEMP_LOW(Doc.of(Level.FAULT) // + LEVEL2_CHARGE_TEMP_LOW(Doc.of(Level.WARNING) // .text("Cluster 3 Cell Charge Temperature Low Alarm Level 3")), // - LEVEL2_TEMP_DIFF_TOO_BIG(Doc.of(Level.FAULT) // + LEVEL2_TEMP_DIFF_TOO_BIG(Doc.of(Level.WARNING) // .text("Cluster 3 Cell Temperature Diff High Alarm Level 3")), // - LEVEL2_POWER_POLE_HIGH(Doc.of(Level.FAULT) // + LEVEL2_POWER_POLE_HIGH(Doc.of(Level.WARNING) // .text("Cluster 3 Cell Temperature High Alarm Level 3")), // - LEVEL2_DISCHARGE_CURRENT_HIGH(Doc.of(Level.FAULT) // + LEVEL2_DISCHARGE_CURRENT_HIGH(Doc.of(Level.WARNING) // .text("Cluster 3 Discharge Current High Alarm Level 3")), // - LEVEL2_CHARGE_CURRENT_HIGH(Doc.of(Level.FAULT) // + LEVEL2_CHARGE_CURRENT_HIGH(Doc.of(Level.WARNING) // .text("Cluster 3 Charge Current High Alarm Level 3")), // ALARM_LEVEL_1_TOTAL_VOLTAGE_DIFF_HIGH(Doc.of(Level.WARNING) // @@ -822,69 +822,69 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { .text("Cluster 1 Total Voltage Low Alarm Level 1")), // ALARM_LEVEL_1_TOTAL_VOLTAGE_HIGH(Doc.of(Level.WARNING) // .text("Cluster 1 Total Voltage High Alarm Level 1")), // - ALARM_FUSE(Doc.of(Level.FAULT) // + ALARM_FUSE(Doc.of(Level.WARNING) // .text(" Fuse Alarm")), // SHIELDED_SWITCH_STATE(Doc.of(Level.WARNING) // .text("Shielded switch state")), // ALARM_BAU_COMMUNICATION(Doc.of(Level.WARNING) // .text("BAU Communication Alarm")), // - ALARM_INSULATION_CHECK(Doc.of(Level.FAULT) // + ALARM_INSULATION_CHECK(Doc.of(Level.WARNING) // .text("Inuslation Resistance Alarm")), // ALARM_CURRENT_SENSOR(Doc.of(Level.WARNING) // .text("Current Sensor Alarm")), // ALARM_BCU_BMU_COMMUNICATION(Doc.of(Level.WARNING) // .text("BCU BMU Communication Alarm")), // - ALARM_CONTACTOR_ADHESION(Doc.of(Level.FAULT)// + ALARM_CONTACTOR_ADHESION(Doc.of(Level.WARNING)// .text("Contactor Adhesion Alarm ")), // ALARM_BCU_NTC(Doc.of(Level.WARNING) // .text("BCU NTC Alarm")), // ALARM_SLAVE_CONTROL_SUMMARY(Doc.of(Level.WARNING) // .text("Slave Control Summary Alarm")), // - FAILURE_INITIALIZATION(Doc.of(Level.FAULT) // + FAILURE_INITIALIZATION(Doc.of(Level.WARNING) // .text("Initialization failure")), // - FAILURE_EEPROM(Doc.of(Level.FAULT) // + FAILURE_EEPROM(Doc.of(Level.WARNING) // .text("EEPROM fault")), // - FAILURE_EEPROM2(Doc.of(Level.FAULT) // + FAILURE_EEPROM2(Doc.of(Level.WARNING) // .text("EEPROM2 fault")), // - FAILURE_INTRANET_COMMUNICATION(Doc.of(Level.FAULT) // + FAILURE_INTRANET_COMMUNICATION(Doc.of(Level.WARNING) // .text("Intranet communication fault")), // - FAILURE_TEMP_SAMPLING_LINE(Doc.of(Level.FAULT) // + FAILURE_TEMP_SAMPLING_LINE(Doc.of(Level.WARNING) // .text("Temperature sampling line fault")), // - FAILURE_BALANCING_MODULE(Doc.of(Level.FAULT) // + FAILURE_BALANCING_MODULE(Doc.of(Level.WARNING) // .text("Balancing module fault")), // - FAILURE_TEMP_SENSOR(Doc.of(Level.FAULT) // + FAILURE_TEMP_SENSOR(Doc.of(Level.WARNING) // .text("Temperature sensor fault")), // - FAILURE_TEMP_SAMPLING(Doc.of(Level.FAULT) // + FAILURE_TEMP_SAMPLING(Doc.of(Level.WARNING) // .text("Temperature sampling fault")), // - FAILURE_VOLTAGE_SAMPLING(Doc.of(Level.FAULT) // + FAILURE_VOLTAGE_SAMPLING(Doc.of(Level.WARNING) // .text("Voltage sampling fault")), // - FAILURE_VOLTAGE_SAMPLING_LINE(Doc.of(Level.FAULT) // + FAILURE_VOLTAGE_SAMPLING_LINE(Doc.of(Level.WARNING) // .text("Voltage sampling Line fault")), // - FAILURE_SLAVE_UNIT_INITIALIZATION(Doc.of(Level.FAULT) // + FAILURE_SLAVE_UNIT_INITIALIZATION(Doc.of(Level.WARNING) // .text("Failure Slave Unit Initialization")), - FAILURE_CONNECTING_LINE(Doc.of(Level.FAULT) // + FAILURE_CONNECTING_LINE(Doc.of(Level.WARNING) // .text("Connecting Line Failure")), // - FAILURE_SAMPLING_CHIP(Doc.of(Level.FAULT) // + FAILURE_SAMPLING_CHIP(Doc.of(Level.WARNING) // .text("Sampling Chip Failure")), // - FAILURE_CONTACTOR(Doc.of(Level.FAULT) // + FAILURE_CONTACTOR(Doc.of(Level.WARNING) // .text("Contactor Failure")), // - FAILURE_PASSIVE_BALANCE(Doc.of(Level.FAULT) // + FAILURE_PASSIVE_BALANCE(Doc.of(Level.WARNING) // .text("Passive Balance Failure")), // - FAILURE_PASSIVE_BALANCE_TEMP(Doc.of(Level.FAULT) // + FAILURE_PASSIVE_BALANCE_TEMP(Doc.of(Level.WARNING) // .text("Passive Balance Temp Failure")), // - FAILURE_ACTIVE_BALANCE(Doc.of(Level.FAULT) // + FAILURE_ACTIVE_BALANCE(Doc.of(Level.WARNING) // .text("Active Balance Failure")), // - FAILURE_LTC6803(Doc.of(Level.FAULT) // + FAILURE_LTC6803(Doc.of(Level.WARNING) // .text("LTC6803 sfault")), // - FAILURE_CONNECTOR_WIRE(Doc.of(Level.FAULT) // + FAILURE_CONNECTOR_WIRE(Doc.of(Level.WARNING) // .text("connector wire fault")), // - FAILURE_SAMPLING_WIRE(Doc.of(Level.FAULT) // + FAILURE_SAMPLING_WIRE(Doc.of(Level.WARNING) // .text("sampling wire fault")), // - PRECHARGE_TAKING_TOO_LONG(Doc.of(Level.FAULT) // + PRECHARGE_TAKING_TOO_LONG(Doc.of(Level.WARNING) // .text("precharge time was too long")), // NEED_CHARGE(Doc.of(Level.WARNING) // .text("Battery Need Charge")), // - FAULT(Doc.of(Level.FAULT) // + FAULT(Doc.of(Level.WARNING) // .text("battery fault state")), // STATE_MACHINE(Doc.of(State.values()) // .text("Current State of State-Machine")), // @@ -928,76 +928,76 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { .text("ALARM LEVEL 2 SOH LOWER")), // LEVEL1_PACK_TEMP_HIGH(Doc.of(Level.WARNING) // .text("ALARM LEVEL 2 PACK TEMP HIGH")), // - LEVEL2_SYSTEM_VOLTAGE_HIGH(Doc.of(Level.FAULT) // + LEVEL2_SYSTEM_VOLTAGE_HIGH(Doc.of(Level.WARNING) // .text("ALARM LEVEL 3 SYSTEM VOLTAGE HIGH")), // - LEVEL2_SYSTEM_VOLTAGE_LOW(Doc.of(Level.FAULT) // + LEVEL2_SYSTEM_VOLTAGE_LOW(Doc.of(Level.WARNING) // .text("ALARM LEVEL 3 SYSTEM VOLTAGE LOW")), // - LEVEL2_SYSTEM_VOLTAGE_UNBALANCED(Doc.of(Level.FAULT) // + LEVEL2_SYSTEM_VOLTAGE_UNBALANCED(Doc.of(Level.WARNING) // .text("ALARM LEVEL 3 SYSTEM VOLTAGE UNBALANCED")), // - LEVEL2_INSULATION_RESISTANCE_LOWER(Doc.of(Level.FAULT) // + LEVEL2_INSULATION_RESISTANCE_LOWER(Doc.of(Level.WARNING) // .text("ALARM LEVEL 3 INSULATION RESISTANCE LOWER")), // - LEVEL2_POS_INSULATION_RESISTANCE_LOWER(Doc.of(Level.FAULT) // + LEVEL2_POS_INSULATION_RESISTANCE_LOWER(Doc.of(Level.WARNING) // .text("ALARM LEVEL 3 POS INSULATION RESISTANCE LOWER")), // - LEVEL2_NEG_INSULATION_RESISTANCE_LOWER(Doc.of(Level.FAULT) // + LEVEL2_NEG_INSULATION_RESISTANCE_LOWER(Doc.of(Level.WARNING) // .text("ALARM LEVEL 3 NEG INSULATION RESISTANCE LOWER")), // - LEVEL2_SYSTEM_SOC_LOWER(Doc.of(Level.FAULT) // + LEVEL2_SYSTEM_SOC_LOWER(Doc.of(Level.WARNING) // .text("ALARM LEVEL 3 SYSTEM SOC LOWER")), // - LEVEL2_SYSTEM_SOC_HIGH(Doc.of(Level.FAULT) // + LEVEL2_SYSTEM_SOC_HIGH(Doc.of(Level.WARNING) // .text("ALARM LEVEL 3 SYSTEM SOC HIGH")), // LEVEL2_SOH_LOWER(Doc.of(Level.WARNING) // .text("ALARM LEVEL 3 SOH LOWER")), // - LEVEL2_PACK_TEMP_HIGH(Doc.of(Level.FAULT) // + LEVEL2_PACK_TEMP_HIGH(Doc.of(Level.WARNING) // .text("ALARM LEVEL 3 PACK TEMP HIGH")), // - SLAVE_11_COMMUNICATION_ERROR(Doc.of(Level.FAULT)// + SLAVE_11_COMMUNICATION_ERROR(Doc.of(Level.WARNING)// .text("Master control and Slave control Communication Fault 1 SLAVE_CTRL_11")), // - SLAVE_12_COMMUNICATION_ERROR(Doc.of(Level.FAULT)// + SLAVE_12_COMMUNICATION_ERROR(Doc.of(Level.WARNING)// .text("Master control and Slave control Communication Fault 1 SLAVE_CTRL_12")), // - SLAVE_13_COMMUNICATION_ERROR(Doc.of(Level.FAULT)// + SLAVE_13_COMMUNICATION_ERROR(Doc.of(Level.WARNING)// .text("Master control and Slave control Communication Fault 1 SLAVE_CTRL_13")), // - SLAVE_14_COMMUNICATION_ERROR(Doc.of(Level.FAULT)// + SLAVE_14_COMMUNICATION_ERROR(Doc.of(Level.WARNING)// .text("Master control and Slave control Communication Fault 1 SLAVE_CTRL_14")), // - SLAVE_15_COMMUNICATION_ERROR(Doc.of(Level.FAULT)// + SLAVE_15_COMMUNICATION_ERROR(Doc.of(Level.WARNING)// .text("Master control and Slave control Communication Fault 1 SLAVE_CTRL_15")), // - SLAVE_16_COMMUNICATION_ERROR(Doc.of(Level.FAULT)// + SLAVE_16_COMMUNICATION_ERROR(Doc.of(Level.WARNING)// .text("Master control and Slave control Communication Fault 1 SLAVE_CTRL_16")), // - SLAVE_17_COMMUNICATION_ERROR(Doc.of(Level.FAULT)// + SLAVE_17_COMMUNICATION_ERROR(Doc.of(Level.WARNING)// .text("Master control and Slave control Communication Fault 1 SLAVE_CTRL_17")), // - SLAVE_18_COMMUNICATION_ERROR(Doc.of(Level.FAULT) // + SLAVE_18_COMMUNICATION_ERROR(Doc.of(Level.WARNING) // .text("Master control and Slave control Communication Fault 2 SLAVE_CTRL_18")), // - SLAVE_19_COMMUNICATION_ERROR(Doc.of(Level.FAULT) // + SLAVE_19_COMMUNICATION_ERROR(Doc.of(Level.WARNING) // .text("Master control and Slave control Communication Fault 2 SLAVE_CTRL_19")), // - SLAVE_20_COMMUNICATION_ERROR(Doc.of(Level.FAULT) // + SLAVE_20_COMMUNICATION_ERROR(Doc.of(Level.WARNING) // .text("Master control and Slave control Communication Fault 2 SLAVE_CTRL_20")), // - SLAVE_21_COMMUNICATION_ERROR(Doc.of(Level.FAULT) // + SLAVE_21_COMMUNICATION_ERROR(Doc.of(Level.WARNING) // .text("Master control and Slave control Communication Fault 2 SLAVE_CTRL_21")), // - SLAVE_22_COMMUNICATION_ERROR(Doc.of(Level.FAULT) // + SLAVE_22_COMMUNICATION_ERROR(Doc.of(Level.WARNING) // .text("Master control and Slave control Communication Fault 2 SLAVE_CTRL_22")), // - SLAVE_23_COMMUNICATION_ERROR(Doc.of(Level.FAULT) // + SLAVE_23_COMMUNICATION_ERROR(Doc.of(Level.WARNING) // .text("Master control and Slave control Communication Fault 2 SLAVE_CTRL_23")), // - SLAVE_24_COMMUNICATION_ERROR(Doc.of(Level.FAULT) // + SLAVE_24_COMMUNICATION_ERROR(Doc.of(Level.WARNING) // .text("Master control and Slave control Communication Fault 2 SLAVE_CTRL_24")), // - SLAVE_25_COMMUNICATION_ERROR(Doc.of(Level.FAULT) // + SLAVE_25_COMMUNICATION_ERROR(Doc.of(Level.WARNING) // .text("Master control and Slave control Communication Fault 2 SLAVE_CTRL_25")), // - SLAVE_26_COMMUNICATION_ERROR(Doc.of(Level.FAULT) // + SLAVE_26_COMMUNICATION_ERROR(Doc.of(Level.WARNING) // .text("Master control and Slave control Communication Fault 2 SLAVE_CTRL_26")), // - SLAVE_27_COMMUNICATION_ERROR(Doc.of(Level.FAULT) // + SLAVE_27_COMMUNICATION_ERROR(Doc.of(Level.WARNING) // .text("Master control and Slave control Communication Fault 2 SLAVE_CTRL_27")), // - SLAVE_28_COMMUNICATION_ERROR(Doc.of(Level.FAULT) // + SLAVE_28_COMMUNICATION_ERROR(Doc.of(Level.WARNING) // .text("Master control and Slave control Communication Fault 2 SLAVE_CTRL_28")), // - SLAVE_29_COMMUNICATION_ERROR(Doc.of(Level.FAULT) // + SLAVE_29_COMMUNICATION_ERROR(Doc.of(Level.WARNING) // .text("Master control and Slave control Communication Fault 2 SLAVE_CTRL_29")), // - SLAVE_30_COMMUNICATION_ERROR(Doc.of(Level.FAULT) // + SLAVE_30_COMMUNICATION_ERROR(Doc.of(Level.WARNING) // .text("Master control and Slave control Communication Fault 2 SLAVE_CTRL_30")), // - SLAVE_31_COMMUNICATION_ERROR(Doc.of(Level.FAULT) // + SLAVE_31_COMMUNICATION_ERROR(Doc.of(Level.WARNING) // .text("Master control and Slave control Communication Fault 2 SLAVE_CTRL_31")), // - SLAVE_32_COMMUNICATION_ERROR(Doc.of(Level.FAULT) // + SLAVE_32_COMMUNICATION_ERROR(Doc.of(Level.WARNING) // .text("Master control and Slave control Communication Fault 2 SLAVE_CTRL_31")), // // OpenEMS Faults - RUN_FAILED(Doc.of(Level.FAULT) // + RUN_FAILED(Doc.of(Level.WARNING) // .text("Running the Logic failed")), // - MAX_START_ATTEMPTS(Doc.of(Level.FAULT) // + MAX_START_ATTEMPTS(Doc.of(Level.WARNING) // .text("The maximum number of start attempts failed")), // - MAX_STOP_ATTEMPTS(Doc.of(Level.FAULT) // + MAX_STOP_ATTEMPTS(Doc.of(Level.WARNING) // .text("The maximum number of stop attempts failed")), // ; diff --git a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/BatteryFeneconHome.java b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/BatteryFeneconHome.java index 0ea7cc798ae..d4298dde150 100644 --- a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/BatteryFeneconHome.java +++ b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/BatteryFeneconHome.java @@ -673,7 +673,7 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId STATE_MACHINE(Doc.of(State.values()) // .text("Current State of State-Machine")), // - RUN_FAILED(Doc.of(Level.FAULT) // + RUN_FAILED(Doc.of(Level.WARNING) // .text("Running the Logic failed")), // LOW_MIN_VOLTAGE_WARNING(Doc.of(Level.WARNING) // .text("Low min voltage warning " 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 efa68f7d43d..e9d933bc5e0 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 @@ -117,17 +117,12 @@ public BatteryFeneconHomeImpl() { BatteryProtection.ChannelId.values(), // BatteryFeneconHome.ChannelId.values() // ); - this.updateHardwareType(BatteryFeneconHomeHardwareType.DEFAULT); } @Activate private void activate(ComponentContext context, Config config) throws OpenemsException { this.config = config; - - // Predefine BatteryProtection. Later adapted to the hardware type. - this.batteryProtection = BatteryProtection.create(this) // - .applyBatteryProtectionDefinition(new FeneconHomeBatteryProtection52(), this.componentManager) // - .build(); + this.updateHardwareType(BatteryFeneconHomeHardwareType.DEFAULT); // initialize to default if (super.activate(context, config.id(), config.alias(), config.enabled(), config.modbusUnitId(), this.cm, "Modbus", config.modbus_id())) { @@ -194,7 +189,7 @@ private void handleStateMachine() { @Override protected ModbusProtocol defineModbusProtocol() { return new ModbusProtocol(this, // - new FC3ReadRegistersTask(500, Priority.LOW, // + new FC3ReadRegistersTask(500, Priority.HIGH, // m(new BitsWordElement(500, this) // .bit(0, BatteryFeneconHome.ChannelId.RACK_PRE_ALARM_CELL_OVER_VOLTAGE) // .bit(1, BatteryFeneconHome.ChannelId.RACK_PRE_ALARM_CELL_UNDER_VOLTAGE) // @@ -271,10 +266,7 @@ protected ModbusProtocol defineModbusProtocol() { .bit(6, BatteryFeneconHome.ChannelId.FAULT_POSITION_BCU_7) // .bit(7, BatteryFeneconHome.ChannelId.FAULT_POSITION_BCU_8) // .bit(8, BatteryFeneconHome.ChannelId.FAULT_POSITION_BCU_9) // - .bit(9, BatteryFeneconHome.ChannelId.FAULT_POSITION_BCU_10))// - ), // - - new FC3ReadRegistersTask(506, Priority.LOW, // + .bit(9, BatteryFeneconHome.ChannelId.FAULT_POSITION_BCU_10)), // m(Battery.ChannelId.VOLTAGE, new UnsignedWordElement(506), SCALE_FACTOR_MINUS_1), // [V] m(Battery.ChannelId.CURRENT, new SignedWordElement(507), SCALE_FACTOR_MINUS_1), // [A] m(Battery.ChannelId.SOC, new UnsignedWordElement(508), SCALE_FACTOR_MINUS_1), // [%] @@ -1066,7 +1058,7 @@ public BridgeModbus getModbus() { } @Override - public ModbusProtocol getDefinedModbusProtocol() throws OpenemsException { + public ModbusProtocol getDefinedModbusProtocol() { return this.getModbusProtocol(); } diff --git a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/ModbusHelper.java b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/ModbusHelper.java index b072d1ebdc4..4f95aa64a66 100644 --- a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/ModbusHelper.java +++ b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/ModbusHelper.java @@ -1,24 +1,22 @@ package io.openems.edge.battery.fenecon.home; -import io.openems.common.exceptions.OpenemsException; import io.openems.edge.bridge.modbus.api.BridgeModbus; import io.openems.edge.bridge.modbus.api.ModbusProtocol; public interface ModbusHelper { /** - * Get modbus bridge. + * Get the {@link BridgeModbus}. * - * @return modbus bridge. + * @return the {@link BridgeModbus} */ public BridgeModbus getModbus(); /** - * Get defined modbus protocol. + * Get defined {@link ModbusProtocol}. * - * @return modbus protocol - * @throws OpenemsException on error + * @return the {@link ModbusProtocol} */ - public ModbusProtocol getDefinedModbusProtocol() throws OpenemsException; + public ModbusProtocol getDefinedModbusProtocol(); } diff --git a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/Context.java b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/Context.java index a2828143f76..6cb49490bb6 100644 --- a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/Context.java +++ b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/Context.java @@ -32,8 +32,4 @@ public Context(BatteryFeneconHome parent, Clock clock, Boolean batteryStartUpRel this.modbusCommunicationFailed = modbusCommunicationFailed; this.retryModbusCommunication = retryModbusCommunication; } - - protected void retryModbusCommunication() { - this.getParent().retryModbusCommunication(); - } } \ No newline at end of file diff --git a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/GoStoppedHandler.java b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/GoStoppedHandler.java index a41a0bf4837..d539b27df30 100644 --- a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/GoStoppedHandler.java +++ b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/GoStoppedHandler.java @@ -12,26 +12,25 @@ public class GoStoppedHandler extends StateHandler { private static int TIMEOUT = 2100; // [35 minutes in seconds] private Instant timeAtEntry = Instant.MIN; - private boolean didProtocolAdd = false; + private boolean isProtocolAdded = false; @Override - protected void onEntry(Context context) throws OpenemsNamedException { - final var battery = context.getParent(); - final var modbus = battery.getModbus(); - modbus.removeProtocol(battery.id()); - this.didProtocolAdd = false; + protected void onEntry(Context context) { + // Remove the protocol to trigger BMS timeout + this.removeProtocol(context); + this.timeAtEntry = Instant.now(context.clock); } @Override public State runAndGetNextState(Context context) throws OpenemsException { - final var battery = context.getParent(); var now = Instant.now(context.clock); - if (Duration.between(this.timeAtEntry, now).getSeconds() > TIMEOUT && !this.didProtocolAdd) { - this.addAndRetryModbusProtocol(context); + if (Duration.between(this.timeAtEntry, now).getSeconds() > TIMEOUT && !this.isProtocolAdded) { + this.addProtocol(context); return State.GO_STOPPED; } + final var battery = context.getParent(); if (battery.getModbusCommunicationFailed()) { return State.STOPPED; } @@ -40,12 +39,25 @@ public State runAndGetNextState(Context context) throws OpenemsException { return State.GO_STOPPED; } - private void addAndRetryModbusProtocol(Context context) throws OpenemsException { + @Override + protected void onExit(Context context) throws OpenemsNamedException { + // Make sure to leave this GoStoppedHandler with added protocol + if (!this.isProtocolAdded) { + this.addProtocol(context); + } + } + + private void addProtocol(Context context) { final var battery = context.getParent(); final var modbus = battery.getModbus(); + this.isProtocolAdded = true; modbus.addProtocol(battery.id(), battery.getDefinedModbusProtocol()); - modbus.retryModbusCommunication(battery.id()); - this.didProtocolAdd = true; } + private void removeProtocol(Context context) { + final var battery = context.getParent(); + final var modbus = battery.getModbus(); + this.isProtocolAdded = false; + modbus.removeProtocol(battery.id()); + } } diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionb/BatterySoltaroClusterVersionB.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionb/BatterySoltaroClusterVersionB.java index 1276244de00..867c5b99a9f 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionb/BatterySoltaroClusterVersionB.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionb/BatterySoltaroClusterVersionB.java @@ -52,80 +52,80 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { .accessMode(AccessMode.READ_WRITE)), // // StateChannels - MASTER_ALARM_COMMUNICATION_ERROR_WITH_SUBMASTER(Doc.of(Level.FAULT) // + MASTER_ALARM_COMMUNICATION_ERROR_WITH_SUBMASTER(Doc.of(Level.WARNING) // .text("Communication error with submaster")), - MASTER_ALARM_PCS_EMS_COMMUNICATION_FAILURE(Doc.of(Level.FAULT) // + MASTER_ALARM_PCS_EMS_COMMUNICATION_FAILURE(Doc.of(Level.WARNING) // .text("PCS/EMS communication failure alarm")), - MASTER_ALARM_PCS_EMS_CONTROL_FAIL(Doc.of(Level.FAULT) // + MASTER_ALARM_PCS_EMS_CONTROL_FAIL(Doc.of(Level.WARNING) // .text("PCS/EMS control fail alarm")), MASTER_ALARM_LEVEL_1_INSULATION(Doc.of(Level.WARNING) // .text("System insulation alarm level 1")), - MASTER_ALARM_LEVEL_2_INSULATION(Doc.of(Level.FAULT) // + MASTER_ALARM_LEVEL_2_INSULATION(Doc.of(Level.WARNING) // .text("System insulation alarm level 2")), - RACK_1_LEVEL_2_ALARM(Doc.of(Level.FAULT) // + RACK_1_LEVEL_2_ALARM(Doc.of(Level.WARNING) // .text("Rack 1 Level 2 Alarm")), - RACK_1_PCS_CONTROL_FAULT(Doc.of(Level.FAULT) // + RACK_1_PCS_CONTROL_FAULT(Doc.of(Level.WARNING) // .text("Rack 1 PCS control fault")), - RACK_1_COMMUNICATION_WITH_MASTER_ERROR(Doc.of(Level.FAULT) // + RACK_1_COMMUNICATION_WITH_MASTER_ERROR(Doc.of(Level.WARNING) // .text("Rack 1 Communication with master error")), - RACK_1_DEVICE_ERROR(Doc.of(Level.FAULT) // + RACK_1_DEVICE_ERROR(Doc.of(Level.WARNING) // .text("Rack 1 Device error")), - RACK_1_CYCLE_OVER_CURRENT(Doc.of(Level.FAULT) // + RACK_1_CYCLE_OVER_CURRENT(Doc.of(Level.WARNING) // .text("Rack 1 Cycle over current")), - RACK_1_VOLTAGE_DIFFERENCE(Doc.of(Level.FAULT) // + RACK_1_VOLTAGE_DIFFERENCE(Doc.of(Level.WARNING) // .text("Rack 1 Voltage difference")), - RACK_2_LEVEL_2_ALARM(Doc.of(Level.FAULT) // + RACK_2_LEVEL_2_ALARM(Doc.of(Level.WARNING) // .text("Rack 2 Level 2 Alarm")), - RACK_2_PCS_CONTROL_FAULT(Doc.of(Level.FAULT) // + RACK_2_PCS_CONTROL_FAULT(Doc.of(Level.WARNING) // .text("Rack 2 PCS control fault")), - RACK_2_COMMUNICATION_WITH_MASTER_ERROR(Doc.of(Level.FAULT) // + RACK_2_COMMUNICATION_WITH_MASTER_ERROR(Doc.of(Level.WARNING) // .text("Rack 2 Communication with master error")), - RACK_2_DEVICE_ERROR(Doc.of(Level.FAULT) // + RACK_2_DEVICE_ERROR(Doc.of(Level.WARNING) // .text("Rack 2 Device error")), - RACK_2_CYCLE_OVER_CURRENT(Doc.of(Level.FAULT) // + RACK_2_CYCLE_OVER_CURRENT(Doc.of(Level.WARNING) // .text("Rack 1 Cycle over current")), - RACK_2_VOLTAGE_DIFFERENCE(Doc.of(Level.FAULT) // + RACK_2_VOLTAGE_DIFFERENCE(Doc.of(Level.WARNING) // .text("Rack 1 Voltage difference")), - RACK_3_LEVEL_2_ALARM(Doc.of(Level.FAULT) // + RACK_3_LEVEL_2_ALARM(Doc.of(Level.WARNING) // .text("Rack 3 Level 2 Alarm")), - RACK_3_PCS_CONTROL_FAULT(Doc.of(Level.FAULT) // + RACK_3_PCS_CONTROL_FAULT(Doc.of(Level.WARNING) // .text("Rack 3 PCS control fault")), - RACK_3_COMMUNICATION_WITH_MASTER_ERROR(Doc.of(Level.FAULT) // + RACK_3_COMMUNICATION_WITH_MASTER_ERROR(Doc.of(Level.WARNING) // .text("Rack 3 Communication with master error")), - RACK_3_DEVICE_ERROR(Doc.of(Level.FAULT) // + RACK_3_DEVICE_ERROR(Doc.of(Level.WARNING) // .text("Rack 3 Device error")), - RACK_3_CYCLE_OVER_CURRENT(Doc.of(Level.FAULT) // + RACK_3_CYCLE_OVER_CURRENT(Doc.of(Level.WARNING) // .text("Rack 1 Cycle over current")), - RACK_3_VOLTAGE_DIFFERENCE(Doc.of(Level.FAULT) // + RACK_3_VOLTAGE_DIFFERENCE(Doc.of(Level.WARNING) // .text("Rack 1 Voltage difference")), - RACK_4_LEVEL_2_ALARM(Doc.of(Level.FAULT) // + RACK_4_LEVEL_2_ALARM(Doc.of(Level.WARNING) // .text("Rack 4 Level 2 Alarm")), - RACK_4_PCS_CONTROL_FAULT(Doc.of(Level.FAULT) // + RACK_4_PCS_CONTROL_FAULT(Doc.of(Level.WARNING) // .text("Rack 4 PCS control fault")), - RACK_4_COMMUNICATION_WITH_MASTER_ERROR(Doc.of(Level.FAULT) // + RACK_4_COMMUNICATION_WITH_MASTER_ERROR(Doc.of(Level.WARNING) // .text("Rack 4 Communication with master error")), - RACK_4_DEVICE_ERROR(Doc.of(Level.FAULT) // + RACK_4_DEVICE_ERROR(Doc.of(Level.WARNING) // .text("Rack 4 Device error")), - RACK_4_CYCLE_OVER_CURRENT(Doc.of(Level.FAULT) // + RACK_4_CYCLE_OVER_CURRENT(Doc.of(Level.WARNING) // .text("Rack 1 Cycle over current")), - RACK_4_VOLTAGE_DIFFERENCE(Doc.of(Level.FAULT) // + RACK_4_VOLTAGE_DIFFERENCE(Doc.of(Level.WARNING) // .text("Rack 1 Voltage difference")), - RACK_5_LEVEL_2_ALARM(Doc.of(Level.FAULT) // + RACK_5_LEVEL_2_ALARM(Doc.of(Level.WARNING) // .text("Rack 5 Level 2 Alarm")), - RACK_5_PCS_CONTROL_FAULT(Doc.of(Level.FAULT) // + RACK_5_PCS_CONTROL_FAULT(Doc.of(Level.WARNING) // .text("Rack 5 PCS control fault")), - RACK_5_COMMUNICATION_WITH_MASTER_ERROR(Doc.of(Level.FAULT) // + RACK_5_COMMUNICATION_WITH_MASTER_ERROR(Doc.of(Level.WARNING) // .text("Rack 5 Communication with master error")), - RACK_5_DEVICE_ERROR(Doc.of(Level.FAULT) // + RACK_5_DEVICE_ERROR(Doc.of(Level.WARNING) // .text("Rack 5 Device error")), - RACK_5_CYCLE_OVER_CURRENT(Doc.of(Level.FAULT) // + RACK_5_CYCLE_OVER_CURRENT(Doc.of(Level.WARNING) // .text("Rack 1 Cycle over current")), - RACK_5_VOLTAGE_DIFFERENCE(Doc.of(Level.FAULT) // + RACK_5_VOLTAGE_DIFFERENCE(Doc.of(Level.WARNING) // .text("Rack 1 Voltage difference")),; private final Doc doc; diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionb/SingleRack.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionb/SingleRack.java index 45d65c88cfb..02835194b33 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionb/SingleRack.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionb/SingleRack.java @@ -439,28 +439,28 @@ private Map createChannelIdMap() { this.addEntry(map, KEY_MAX_CELL_TEMPERATURE, new IntegerDoc().unit(Unit.DEZIDEGREE_CELSIUS)); this.addEntry(map, KEY_MIN_CELL_TEMPERATURE_ID, new IntegerDoc().unit(Unit.NONE)); this.addEntry(map, KEY_MIN_CELL_TEMPERATURE, new IntegerDoc().unit(Unit.DEZIDEGREE_CELSIUS)); - this.addEntry(map, KEY_ALARM_LEVEL_2_CELL_DISCHA_TEMP_LOW, Doc.of(Level.FAULT) + this.addEntry(map, KEY_ALARM_LEVEL_2_CELL_DISCHA_TEMP_LOW, Doc.of(Level.WARNING) .text("Rack" + this.rackNumber + " Cell Discharge Temperature Low Alarm Level 2")); /* Bit 15 */ - this.addEntry(map, KEY_ALARM_LEVEL_2_CELL_DISCHA_TEMP_HIGH, Doc.of(Level.FAULT) + this.addEntry(map, KEY_ALARM_LEVEL_2_CELL_DISCHA_TEMP_HIGH, Doc.of(Level.WARNING) .text("Rack" + this.rackNumber + " Cell Discharge Temperature High Alarm Level 2")); /* Bit 14 */ this.addEntry(map, KEY_ALARM_LEVEL_2_GR_TEMPERATURE_HIGH, - Doc.of(Level.FAULT).text("Rack" + this.rackNumber + " GR Temperature High Alarm Level 2")); /* Bit 10 */ - this.addEntry(map, KEY_ALARM_LEVEL_2_CELL_CHA_TEMP_LOW, Doc.of(Level.FAULT) + Doc.of(Level.WARNING).text("Rack" + this.rackNumber + " GR Temperature High Alarm Level 2")); /* Bit 10 */ + this.addEntry(map, KEY_ALARM_LEVEL_2_CELL_CHA_TEMP_LOW, Doc.of(Level.WARNING) .text("Rack" + this.rackNumber + " Cell Charge Temperature Low Alarm Level 2")); /* Bit 7 */ - this.addEntry(map, KEY_ALARM_LEVEL_2_CELL_CHA_TEMP_HIGH, Doc.of(Level.FAULT) + this.addEntry(map, KEY_ALARM_LEVEL_2_CELL_CHA_TEMP_HIGH, Doc.of(Level.WARNING) .text("Rack" + this.rackNumber + " Cell Charge Temperature High Alarm Level 2")); /* Bit 6 */ - this.addEntry(map, KEY_ALARM_LEVEL_2_DISCHA_CURRENT_HIGH, Doc.of(Level.FAULT) + this.addEntry(map, KEY_ALARM_LEVEL_2_DISCHA_CURRENT_HIGH, Doc.of(Level.WARNING) .text("Rack" + this.rackNumber + " Discharge Current High Alarm Level 2")); /* Bit 5 */ this.addEntry(map, KEY_ALARM_LEVEL_2_TOTAL_VOLTAGE_LOW, - Doc.of(Level.FAULT).text("Rack" + this.rackNumber + " Total Voltage Low Alarm Level 2")); /* Bit 4 */ + Doc.of(Level.WARNING).text("Rack" + this.rackNumber + " Total Voltage Low Alarm Level 2")); /* Bit 4 */ this.addEntry(map, KEY_ALARM_LEVEL_2_CELL_VOLTAGE_LOW, - Doc.of(Level.FAULT).text("Cluster 1 Cell Voltage Low Alarm Level 2")); /* Bit 3 */ + Doc.of(Level.WARNING).text("Cluster 1 Cell Voltage Low Alarm Level 2")); /* Bit 3 */ this.addEntry(map, KEY_ALARM_LEVEL_2_CHA_CURRENT_HIGH, - Doc.of(Level.FAULT).text("Rack" + this.rackNumber + " Charge Current High Alarm Level 2")); /* Bit 2 */ + Doc.of(Level.WARNING).text("Rack" + this.rackNumber + " Charge Current High Alarm Level 2")); /* Bit 2 */ this.addEntry(map, KEY_ALARM_LEVEL_2_TOTAL_VOLTAGE_HIGH, - Doc.of(Level.FAULT).text("Rack" + this.rackNumber + " Total Voltage High Alarm Level 2")); /* Bit 1 */ + Doc.of(Level.WARNING).text("Rack" + this.rackNumber + " Total Voltage High Alarm Level 2")); /* Bit 1 */ this.addEntry(map, KEY_ALARM_LEVEL_2_CELL_VOLTAGE_HIGH, - Doc.of(Level.FAULT).text("Rack" + this.rackNumber + " Cell Voltage High Alarm Level 2")); /* Bit 0 */ + Doc.of(Level.WARNING).text("Rack" + this.rackNumber + " Cell Voltage High Alarm Level 2")); /* Bit 0 */ this.addEntry(map, KEY_ALARM_LEVEL_1_CELL_DISCHA_TEMP_LOW, Doc.of(Level.WARNING) .text("Rack" + this.rackNumber + " Cell Discharge Temperature Low Alarm Level 1")); /* Bit 15 */ this.addEntry(map, KEY_ALARM_LEVEL_1_CELL_DISCHA_TEMP_HIGH, Doc.of(Level.WARNING) @@ -492,23 +492,23 @@ private Map createChannelIdMap() { this.addEntry(map, KEY_ALARM_LEVEL_1_CELL_VOLTAGE_HIGH, Doc.of(Level.WARNING).text("Rack" + this.rackNumber + " Cell Voltage High Alarm Level 1")); /* Bit 0 */ this.addEntry(map, KEY_RUN_STATE, Doc.of(Enums.ClusterRunState.values())); // - this.addEntry(map, KEY_FAILURE_INITIALIZATION, Doc.of(Level.FAULT).text("Initialization failure")); /* Bit */ - this.addEntry(map, KEY_FAILURE_EEPROM, Doc.of(Level.FAULT).text("EEPROM fault")); /* Bit 11 */ + this.addEntry(map, KEY_FAILURE_INITIALIZATION, Doc.of(Level.WARNING).text("Initialization failure")); /* Bit */ + this.addEntry(map, KEY_FAILURE_EEPROM, Doc.of(Level.WARNING).text("EEPROM fault")); /* Bit 11 */ this.addEntry(map, KEY_FAILURE_INTRANET_COMMUNICATION, - Doc.of(Level.FAULT).text("Internal communication fault")); /* Bit 10 */ + Doc.of(Level.WARNING).text("Internal communication fault")); /* Bit 10 */ this.addEntry(map, KEY_FAILURE_TEMPERATURE_SENSOR_CABLE, - Doc.of(Level.FAULT).text("Temperature sensor cable fault")); /* Bit 9 */ + Doc.of(Level.WARNING).text("Temperature sensor cable fault")); /* Bit 9 */ this.addEntry(map, KEY_FAILURE_BALANCING_MODULE, Doc.of(Level.OK).text("Balancing module fault")); /* Bit 8 */ - this.addEntry(map, KEY_FAILURE_TEMPERATURE_PCB, Doc.of(Level.FAULT).text("Temperature PCB error")); /* Bit 7 */ - this.addEntry(map, KEY_FAILURE_GR_TEMPERATURE, Doc.of(Level.FAULT).text("GR Temperature error")); /* Bit 6 */ - this.addEntry(map, KEY_FAILURE_TEMP_SENSOR, Doc.of(Level.FAULT).text("Temperature sensor fault")); /* Bit 5 */ + this.addEntry(map, KEY_FAILURE_TEMPERATURE_PCB, Doc.of(Level.WARNING).text("Temperature PCB error")); /* Bit 7 */ + this.addEntry(map, KEY_FAILURE_GR_TEMPERATURE, Doc.of(Level.WARNING).text("GR Temperature error")); /* Bit 6 */ + this.addEntry(map, KEY_FAILURE_TEMP_SENSOR, Doc.of(Level.WARNING).text("Temperature sensor fault")); /* Bit 5 */ this.addEntry(map, KEY_FAILURE_TEMP_SAMPLING, - Doc.of(Level.FAULT).text("Temperature sampling fault")); /* Bit 4 */ + Doc.of(Level.WARNING).text("Temperature sampling fault")); /* Bit 4 */ this.addEntry(map, KEY_FAILURE_VOLTAGE_SAMPLING, - Doc.of(Level.FAULT).text("Voltage sampling fault")); /* Bit 3 */ - this.addEntry(map, KEY_FAILURE_LTC6803, Doc.of(Level.FAULT).text("LTC6803 fault")); /* Bit 2 */ - this.addEntry(map, KEY_FAILURE_CONNECTOR_WIRE, Doc.of(Level.FAULT).text("connector wire fault")); /* Bit 1 */ - this.addEntry(map, KEY_FAILURE_SAMPLING_WIRE, Doc.of(Level.FAULT).text("sampling wire fault")); /* Bit 0 */ + Doc.of(Level.WARNING).text("Voltage sampling fault")); /* Bit 3 */ + this.addEntry(map, KEY_FAILURE_LTC6803, Doc.of(Level.WARNING).text("LTC6803 fault")); /* Bit 2 */ + this.addEntry(map, KEY_FAILURE_CONNECTOR_WIRE, Doc.of(Level.WARNING).text("connector wire fault")); /* Bit 1 */ + this.addEntry(map, KEY_FAILURE_SAMPLING_WIRE, Doc.of(Level.WARNING).text("sampling wire fault")); /* Bit 0 */ this.addEntry(map, KEY_SLEEP, Doc.of(OpenemsType.INTEGER).accessMode(AccessMode.READ_WRITE)); this.addEntry(map, KEY_RESET, Doc.of(OpenemsType.INTEGER).accessMode(AccessMode.READ_WRITE)); diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/BatterySoltaroClusterVersionC.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/BatterySoltaroClusterVersionC.java index 99f8fea4c9f..cec303bdbf7 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/BatterySoltaroClusterVersionC.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/BatterySoltaroClusterVersionC.java @@ -265,82 +265,82 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId // Master BMS Alarm Registers MASTER_EMS_COMMUNICATION_FAILURE(Doc.of(Level.WARNING) // .text("Master EMS Communication Failure")), - MASTER_PCS_CONTROL_FAILURE(Doc.of(Level.FAULT) // + MASTER_PCS_CONTROL_FAILURE(Doc.of(Level.WARNING) // .text("Master PCS Control Failure")), - MASTER_PCS_COMMUNICATION_FAILURE(Doc.of(Level.FAULT) // + MASTER_PCS_COMMUNICATION_FAILURE(Doc.of(Level.WARNING) // .text("Master PCS Communication Failure")), // Rack #1 cannot be paralleled to DC Bus reasons - RACK_1_LEVEL_2_ALARM(Doc.of(Level.FAULT) // + RACK_1_LEVEL_2_ALARM(Doc.of(Level.WARNING) // .text("Rack 1 Level 2 Alarm")), - RACK_1_PCS_CONTROL_FAILURE(Doc.of(Level.FAULT) // + RACK_1_PCS_CONTROL_FAILURE(Doc.of(Level.WARNING) // .text("Rack 1 PCS Control Failure")), - RACK_1_COMMUNICATION_TO_MASTER_FAILURE(Doc.of(Level.FAULT) // + RACK_1_COMMUNICATION_TO_MASTER_FAILURE(Doc.of(Level.WARNING) // .text("Rack 1 Communication to Master BMS Failure")), - RACK_1_HARDWARE_FAILURE(Doc.of(Level.FAULT) // + RACK_1_HARDWARE_FAILURE(Doc.of(Level.WARNING) // .text("Rack 1 Hardware Failure")), - RACK_1_OVER_CURRENT(Doc.of(Level.FAULT) // + RACK_1_OVER_CURRENT(Doc.of(Level.WARNING) // .text("Rack 1 Too big circulating Current among clusters (>4A)")), - RACK_1_VOLTAGE_DIFFERENCE(Doc.of(Level.FAULT) // + RACK_1_VOLTAGE_DIFFERENCE(Doc.of(Level.WARNING) // .text("Rack 1 Too big boltage difference among clusters (>50V)")), // Rack #2 cannot be paralleled to DC Bus reasons - RACK_2_LEVEL_2_ALARM(Doc.of(Level.FAULT) // + RACK_2_LEVEL_2_ALARM(Doc.of(Level.WARNING) // .text("Rack 2 Level 2 Alarm")), - RACK_2_PCS_CONTROL_FAILURE(Doc.of(Level.FAULT) // + RACK_2_PCS_CONTROL_FAILURE(Doc.of(Level.WARNING) // .text("Rack 2 PCS Control Failure")), - RACK_2_COMMUNICATION_TO_MASTER_FAILURE(Doc.of(Level.FAULT) // + RACK_2_COMMUNICATION_TO_MASTER_FAILURE(Doc.of(Level.WARNING) // .text("Rack 2 Communication to Master BMS Failure")), - RACK_2_HARDWARE_FAILURE(Doc.of(Level.FAULT) // + RACK_2_HARDWARE_FAILURE(Doc.of(Level.WARNING) // .text("Rack 2 Hardware Failure")), - RACK_2_OVER_CURRENT(Doc.of(Level.FAULT) // + RACK_2_OVER_CURRENT(Doc.of(Level.WARNING) // .text("Rack 2 Too big circulating Current among clusters (>4A)")), - RACK_2_VOLTAGE_DIFFERENCE(Doc.of(Level.FAULT) // + RACK_2_VOLTAGE_DIFFERENCE(Doc.of(Level.WARNING) // .text("Rack 2 Too big boltage difference among clusters (>50V)")), // Rack #3 cannot be paralleled to DC Bus reasons - RACK_3_LEVEL_2_ALARM(Doc.of(Level.FAULT) // + RACK_3_LEVEL_2_ALARM(Doc.of(Level.WARNING) // .text("Rack 3 Level 2 Alarm")), - RACK_3_PCS_CONTROL_FAILURE(Doc.of(Level.FAULT) // + RACK_3_PCS_CONTROL_FAILURE(Doc.of(Level.WARNING) // .text("Rack 3 PCS Control Failure")), - RACK_3_COMMUNICATION_TO_MASTER_FAILURE(Doc.of(Level.FAULT) // + RACK_3_COMMUNICATION_TO_MASTER_FAILURE(Doc.of(Level.WARNING) // .text("Rack 3 Communication to Master BMS Failure")), - RACK_3_HARDWARE_FAILURE(Doc.of(Level.FAULT) // + RACK_3_HARDWARE_FAILURE(Doc.of(Level.WARNING) // .text("Rack 3 Hardware Failure")), - RACK_3_OVER_CURRENT(Doc.of(Level.FAULT) // + RACK_3_OVER_CURRENT(Doc.of(Level.WARNING) // .text("Rack 3 Too big circulating Current among clusters (>4A)")), - RACK_3_VOLTAGE_DIFFERENCE(Doc.of(Level.FAULT) // + RACK_3_VOLTAGE_DIFFERENCE(Doc.of(Level.WARNING) // .text("Rack 3 Too big boltage difference among clusters (>50V)")), // Rack #4 cannot be paralleled to DC Bus reasons - RACK_4_LEVEL_2_ALARM(Doc.of(Level.FAULT) // + RACK_4_LEVEL_2_ALARM(Doc.of(Level.WARNING) // .text("Rack 4 Level 2 Alarm")), - RACK_4_PCS_CONTROL_FAILURE(Doc.of(Level.FAULT) // + RACK_4_PCS_CONTROL_FAILURE(Doc.of(Level.WARNING) // .text("Rack 4 PCS Control Failure")), - RACK_4_COMMUNICATION_TO_MASTER_FAILURE(Doc.of(Level.FAULT) // + RACK_4_COMMUNICATION_TO_MASTER_FAILURE(Doc.of(Level.WARNING) // .text("Rack 4 Communication to Master BMS Failure")), - RACK_4_HARDWARE_FAILURE(Doc.of(Level.FAULT) // + RACK_4_HARDWARE_FAILURE(Doc.of(Level.WARNING) // .text("Rack 4 Hardware Failure")), - RACK_4_OVER_CURRENT(Doc.of(Level.FAULT) // + RACK_4_OVER_CURRENT(Doc.of(Level.WARNING) // .text("Rack 4 Too big circulating Current among clusters (>4A)")), - RACK_4_VOLTAGE_DIFFERENCE(Doc.of(Level.FAULT) // + RACK_4_VOLTAGE_DIFFERENCE(Doc.of(Level.WARNING) // .text("Rack 4 Too big boltage difference among clusters (>50V)")), // Rack #5 cannot be paralleled to DC Bus reasons - RACK_5_LEVEL_2_ALARM(Doc.of(Level.FAULT) // + RACK_5_LEVEL_2_ALARM(Doc.of(Level.WARNING) // .text("Rack 5 Level 2 Alarm")), - RACK_5_PCS_CONTROL_FAILURE(Doc.of(Level.FAULT) // + RACK_5_PCS_CONTROL_FAILURE(Doc.of(Level.WARNING) // .text("Rack 5 PCS Control Failure")), - RACK_5_COMMUNICATION_TO_MASTER_FAILURE(Doc.of(Level.FAULT) // + RACK_5_COMMUNICATION_TO_MASTER_FAILURE(Doc.of(Level.WARNING) // .text("Rack 5 Communication to Master BMS Failure")), - RACK_5_HARDWARE_FAILURE(Doc.of(Level.FAULT) // + RACK_5_HARDWARE_FAILURE(Doc.of(Level.WARNING) // .text("Rack 5 Hardware Failure")), - RACK_5_OVER_CURRENT(Doc.of(Level.FAULT) // + RACK_5_OVER_CURRENT(Doc.of(Level.WARNING) // .text("Rack 5 Too big circulating Current among clusters (>4A)")), - RACK_5_VOLTAGE_DIFFERENCE(Doc.of(Level.FAULT) // + RACK_5_VOLTAGE_DIFFERENCE(Doc.of(Level.WARNING) // .text("Rack 5 Too big boltage difference among clusters (>50V)")), // OpenEMS Faults - RUN_FAILED(Doc.of(Level.FAULT) // + RUN_FAILED(Doc.of(Level.WARNING) // .text("Running the Logic failed")), // - MAX_START_ATTEMPTS(Doc.of(Level.FAULT) // + MAX_START_ATTEMPTS(Doc.of(Level.WARNING) // .text("The maximum number of start attempts failed")), // - MAX_STOP_ATTEMPTS(Doc.of(Level.FAULT) // + MAX_STOP_ATTEMPTS(Doc.of(Level.WARNING) // .text("The maximum number of stop attempts failed")), // NUMBER_OF_MODULES_PER_TOWER(Doc.of(OpenemsType.INTEGER) // .persistencePriority(PersistencePriority.HIGH) // diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/RackChannel.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/RackChannel.java index ec13258ac7c..daee5253fa6 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/RackChannel.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/RackChannel.java @@ -463,27 +463,27 @@ public enum RackChannel { LEVEL1_TOTAL_VOLTAGE_HIGH(Doc.of(Level.WARNING) // .text("Total Voltage High Alarm Level 1")), // // Alarm Level 2 - LEVEL2_DISCHARGE_TEMP_LOW(Doc.of(Level.FAULT) // + LEVEL2_DISCHARGE_TEMP_LOW(Doc.of(Level.WARNING) // .text("Discharge Temperature Low Alarm Level 2")), // - LEVEL2_DISCHARGE_TEMP_HIGH(Doc.of(Level.FAULT) // + LEVEL2_DISCHARGE_TEMP_HIGH(Doc.of(Level.WARNING) // .text("Discharge Temperature High Alarm Level 2")), // - LEVEL2_INSULATION_VALUE(Doc.of(Level.FAULT) // + LEVEL2_INSULATION_VALUE(Doc.of(Level.WARNING) // .text("Insulation Value Failure Alarm Level 2")), // - LEVEL2_POWER_POLE_TEMP_HIGH(Doc.of(Level.FAULT) // + LEVEL2_POWER_POLE_TEMP_HIGH(Doc.of(Level.WARNING) // .text("Power Pole temperature too high Alarm Level 2")), // - LEVEL2_CHARGE_TEMP_LOW(Doc.of(Level.FAULT) // + LEVEL2_CHARGE_TEMP_LOW(Doc.of(Level.WARNING) // .text("Cell Charge Temperature Low Alarm Level 2")), // - LEVEL2_CHARGE_TEMP_HIGH(Doc.of(Level.FAULT) // + LEVEL2_CHARGE_TEMP_HIGH(Doc.of(Level.WARNING) // .text("Charge Temperature High Alarm Level 2")), // - LEVEL2_DISCHARGE_CURRENT_HIGH(Doc.of(Level.FAULT) // + LEVEL2_DISCHARGE_CURRENT_HIGH(Doc.of(Level.WARNING) // .text("Discharge Current High Alarm Level 2")), // - LEVEL2_TOTAL_VOLTAGE_LOW(Doc.of(Level.FAULT) // + LEVEL2_TOTAL_VOLTAGE_LOW(Doc.of(Level.WARNING) // .text("Total Voltage Low Alarm Level 2")), // - LEVEL2_CELL_VOLTAGE_LOW(Doc.of(Level.FAULT) // + LEVEL2_CELL_VOLTAGE_LOW(Doc.of(Level.WARNING) // .text("Cell Voltage Low Alarm Level 2")), // - LEVEL2_CHARGE_CURRENT_HIGH(Doc.of(Level.FAULT) // + LEVEL2_CHARGE_CURRENT_HIGH(Doc.of(Level.WARNING) // .text("Charge Current High Alarm Level 2")), // - LEVEL2_TOTAL_VOLTAGE_HIGH(Doc.of(Level.FAULT) // + LEVEL2_TOTAL_VOLTAGE_HIGH(Doc.of(Level.WARNING) // .text("Total Voltage High Alarm Level 2")), // LEVEL2_CELL_VOLTAGE_HIGH(Doc.of(Level.INFO) // .text("Cell Voltage High Alarm Level 2")), // diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versiona/BatterySoltaroSingleRackVersionA.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versiona/BatterySoltaroSingleRackVersionA.java index 9ee4f1c6abf..7d65c2aacd1 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versiona/BatterySoltaroSingleRackVersionA.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versiona/BatterySoltaroSingleRackVersionA.java @@ -681,29 +681,29 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { .text("Cluster 1 Total Voltage High Alarm Level 1")), // ALARM_LEVEL_1_CELL_VOLTAGE_HIGH(Doc.of(Level.WARNING) // .text("Cluster 1 Cell Voltage High Alarm Level 1")), // - FAILURE_INITIALIZATION(Doc.of(Level.FAULT) // + FAILURE_INITIALIZATION(Doc.of(Level.WARNING) // .text("Initialization failure")), // - FAILURE_EEPROM(Doc.of(Level.FAULT) // + FAILURE_EEPROM(Doc.of(Level.WARNING) // .text("EEPROM fault")), // - FAILURE_INTRANET_COMMUNICATION(Doc.of(Level.FAULT) // + FAILURE_INTRANET_COMMUNICATION(Doc.of(Level.WARNING) // .text("Intranet communication fault")), // - FAILURE_TEMP_SAMPLING_LINE(Doc.of(Level.FAULT) // + FAILURE_TEMP_SAMPLING_LINE(Doc.of(Level.WARNING) // .text("Temperature sampling line fault")), // - FAILURE_BALANCING_MODULE(Doc.of(Level.FAULT) // + FAILURE_BALANCING_MODULE(Doc.of(Level.WARNING) // .text("Balancing module fault")), // - FAILURE_TEMP_SENSOR(Doc.of(Level.FAULT) // + FAILURE_TEMP_SENSOR(Doc.of(Level.WARNING) // .text("Temperature sensor fault")), // - FAILURE_TEMP_SAMPLING(Doc.of(Level.FAULT) // + FAILURE_TEMP_SAMPLING(Doc.of(Level.WARNING) // .text("Temperature sampling fault")), // - FAILURE_VOLTAGE_SAMPLING(Doc.of(Level.FAULT) // + FAILURE_VOLTAGE_SAMPLING(Doc.of(Level.WARNING) // .text("Voltage sampling fault")), // - FAILURE_LTC6803(Doc.of(Level.FAULT) // + FAILURE_LTC6803(Doc.of(Level.WARNING) // .text("LTC6803 fault")), // FAILURE_CONNECTOR_WIRE(Doc.of(Level.WARNING) // .text("connector wire fault")), // - FAILURE_SAMPLING_WIRE(Doc.of(Level.FAULT) // + FAILURE_SAMPLING_WIRE(Doc.of(Level.WARNING) // .text("sampling wire fault")), // - PRECHARGE_TAKING_TOO_LONG(Doc.of(Level.FAULT) // + PRECHARGE_TAKING_TOO_LONG(Doc.of(Level.WARNING) // .text("precharge time was too long")), // STATE_MACHINE(Doc.of(State.values()) // .text("Current State of State-Machine")), // diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/BatterySoltaroSingleRackVersionB.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/BatterySoltaroSingleRackVersionB.java index ecc741e2cc2..8434481d85c 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/BatterySoltaroSingleRackVersionB.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/BatterySoltaroSingleRackVersionB.java @@ -995,11 +995,11 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId .text("precharge time was too long")), // OpenEMS Faults - RUN_FAILED(Doc.of(Level.FAULT) // + RUN_FAILED(Doc.of(Level.WARNING) // .text("Running the Logic failed")), // - MAX_START_ATTEMPTS(Doc.of(Level.FAULT) // + MAX_START_ATTEMPTS(Doc.of(Level.WARNING) // .text("The maximum number of start attempts failed")), // - MAX_STOP_ATTEMPTS(Doc.of(Level.FAULT) // + MAX_STOP_ATTEMPTS(Doc.of(Level.WARNING) // .text("The maximum number of stop attempts failed")), // ; diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/BatterySoltaroSingleRackVersionC.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/BatterySoltaroSingleRackVersionC.java index 28a54d5b9af..1f57a137c60 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/BatterySoltaroSingleRackVersionC.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/BatterySoltaroSingleRackVersionC.java @@ -514,29 +514,29 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId // Faults and warnings // Alarm Level 2 - LEVEL2_DISCHARGE_TEMP_LOW(Doc.of(Level.FAULT) // + LEVEL2_DISCHARGE_TEMP_LOW(Doc.of(Level.WARNING) // .text("Discharge Temperature Low Alarm Level 2")), // - LEVEL2_DISCHARGE_TEMP_HIGH(Doc.of(Level.FAULT) // + LEVEL2_DISCHARGE_TEMP_HIGH(Doc.of(Level.WARNING) // .text("Discharge Temperature High Alarm Level 2")), // - LEVEL2_INSULATION_VALUE(Doc.of(Level.FAULT) // + LEVEL2_INSULATION_VALUE(Doc.of(Level.WARNING) // .text("Insulation Value Failure Alarm Level 2")), // - LEVEL2_POWER_POLE_TEMP_HIGH(Doc.of(Level.FAULT) // + LEVEL2_POWER_POLE_TEMP_HIGH(Doc.of(Level.WARNING) // .text("Power Pole temperature too high Alarm Level 2")), // - LEVEL2_CHARGE_TEMP_LOW(Doc.of(Level.FAULT) // + LEVEL2_CHARGE_TEMP_LOW(Doc.of(Level.WARNING) // .text("Cell Charge Temperature Low Alarm Level 2")), // - LEVEL2_CHARGE_TEMP_HIGH(Doc.of(Level.FAULT) // + LEVEL2_CHARGE_TEMP_HIGH(Doc.of(Level.WARNING) // .text("Charge Temperature High Alarm Level 2")), // - LEVEL2_DISCHARGE_CURRENT_HIGH(Doc.of(Level.FAULT) // + LEVEL2_DISCHARGE_CURRENT_HIGH(Doc.of(Level.WARNING) // .text("Discharge Current High Alarm Level 2")), // - LEVEL2_TOTAL_VOLTAGE_LOW(Doc.of(Level.FAULT) // + LEVEL2_TOTAL_VOLTAGE_LOW(Doc.of(Level.WARNING) // .text("Total Voltage Low Alarm Level 2")), // - LEVEL2_CELL_VOLTAGE_LOW(Doc.of(Level.FAULT) // + LEVEL2_CELL_VOLTAGE_LOW(Doc.of(Level.WARNING) // .text("Cell Voltage Low Alarm Level 2")), // - LEVEL2_CHARGE_CURRENT_HIGH(Doc.of(Level.FAULT) // + LEVEL2_CHARGE_CURRENT_HIGH(Doc.of(Level.WARNING) // .text("Charge Current High Alarm Level 2")), // - LEVEL2_TOTAL_VOLTAGE_HIGH(Doc.of(Level.FAULT) // + LEVEL2_TOTAL_VOLTAGE_HIGH(Doc.of(Level.WARNING) // .text("Total Voltage High Alarm Level 2")), // - LEVEL2_CELL_VOLTAGE_HIGH(Doc.of(Level.FAULT) // + LEVEL2_CELL_VOLTAGE_HIGH(Doc.of(Level.WARNING) // .text("Cell Voltage High Alarm Level 2")), // // Alarm Level 1 @@ -672,11 +672,11 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId .text("Slave 20 communication error")), // // OpenEMS Faults - RUN_FAILED(Doc.of(Level.FAULT) // + RUN_FAILED(Doc.of(Level.WARNING) // .text("Running the Logic failed")), // - MAX_START_ATTEMPTS(Doc.of(Level.FAULT) // + MAX_START_ATTEMPTS(Doc.of(Level.WARNING) // .text("The maximum number of start attempts failed")), // - MAX_STOP_ATTEMPTS(Doc.of(Level.FAULT) // + MAX_STOP_ATTEMPTS(Doc.of(Level.WARNING) // .text("The maximum number of stop attempts failed")), // ; diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsave.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsave.java index d9124765b01..b32ba021cd3 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsave.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsave.java @@ -33,29 +33,40 @@ public interface BatteryInverterKacoBlueplanetGridsave extends ManagedSymmetricB public static final int WATCHDOG_TRIGGER_SECONDS = 10; public enum ChannelId implements io.openems.edge.common.channel.ChannelId { + + /* + * Whenever one of these states would be Level.FAULT, the EssGeneric will stop + * the battery and the inverter. If this is necessary, it must be specifically + * mentioned and the state should have a proper description of the fault. + */ + STATE_MACHINE(Doc.of(State.values()) // .text("Current State of State-Machine")), // - RUN_FAILED(Doc.of(Level.FAULT) // + RUN_FAILED(Doc.of(Level.WARNING) // .text("Running the Logic failed")), // - MAX_START_TIMEOUT(Doc.of(Level.FAULT) // + MAX_START_TIMEOUT(Doc.of(Level.WARNING) // .text("Max start time is exceeded")), // - MAX_STOP_TIMEOUT(Doc.of(Level.FAULT) // + MAX_STOP_TIMEOUT(Doc.of(Level.WARNING) // .text("Max stop time is exceeded")), // - INVERTER_CURRENT_STATE_FAULT(Doc.of(Level.FAULT) // + + /** + * Internal StateMachine from KACO. + */ + INVERTER_CURRENT_STATE_FAULT(Doc.of(Level.WARNING) // .text("The 'CurrentState' is invalid")), // - GRID_DISCONNECTION(Doc.of(Level.FAULT) // + GRID_DISCONNECTION(Doc.of(Level.WARNING) // .text("External grid protection disconnection (17)")), // - GRID_FAILURE_LINE_TO_LINE(Doc.of(Level.FAULT) // + GRID_FAILURE_LINE_TO_LINE(Doc.of(Level.WARNING) // .text("Grid failure phase-to-phase voltage (47)")), // - LINE_FAILURE_UNDER_FREQ(Doc.of(Level.FAULT) // + LINE_FAILURE_UNDER_FREQ(Doc.of(Level.WARNING) // .text("Line failure: Grid frequency is too low (48)")), // - LINE_FAILURE_OVER_FREQ(Doc.of(Level.FAULT) // + LINE_FAILURE_OVER_FREQ(Doc.of(Level.WARNING) // .text("Line failure: Grid frequency is too high (49)")), // - PROTECTION_SHUTDOWN_LINE_1(Doc.of(Level.FAULT) // + PROTECTION_SHUTDOWN_LINE_1(Doc.of(Level.WARNING) // .text("Grid Failure: grid voltage L1 protection (81)")), // - PROTECTION_SHUTDOWN_LINE_2(Doc.of(Level.FAULT) // + PROTECTION_SHUTDOWN_LINE_2(Doc.of(Level.WARNING) // .text("Grid Failure: grid voltage L2 protection (82)")), // - PROTECTION_SHUTDOWN_LINE_3(Doc.of(Level.FAULT) // + PROTECTION_SHUTDOWN_LINE_3(Doc.of(Level.WARNING) // .text("Grid Failure: grid voltage L3 protection (83)")), // ; 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 84ec0153305..9b5a3cefef3 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 @@ -28,6 +28,7 @@ import com.google.common.base.Objects; import com.google.common.collect.ImmutableMap; +import io.openems.common.channel.AccessMode; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; import io.openems.common.types.OptionsEnum; @@ -57,6 +58,9 @@ import io.openems.edge.common.channel.value.Value; import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.modbusslave.ModbusSlave; +import io.openems.edge.common.modbusslave.ModbusSlaveNatureTable; +import io.openems.edge.common.modbusslave.ModbusSlaveTable; import io.openems.edge.common.startstop.StartStop; import io.openems.edge.common.startstop.StartStoppable; import io.openems.edge.common.taskmanager.Priority; @@ -75,7 +79,7 @@ ) public class BatteryInverterKacoBlueplanetGridsaveImpl extends AbstractSunSpecBatteryInverter implements BatteryInverterKacoBlueplanetGridsave, ManagedSymmetricBatteryInverter, SymmetricBatteryInverter, - ModbusComponent, OpenemsComponent, TimedataProvider, StartStoppable { + ModbusComponent, ModbusSlave, OpenemsComponent, TimedataProvider, StartStoppable { private static final int UNIT_ID = 1; private static final int READ_FROM_MODBUS_BLOCK = 1; @@ -140,7 +144,6 @@ protected void setModbus(BridgeModbus modbus) { // .put(SunSpecModel.S_136, Priority.LOW) // // .put(SunSpecModel.S_160, Priority.LOW) // - @Activate public BatteryInverterKacoBlueplanetGridsaveImpl() { super(// ACTIVE_MODELS, // @@ -158,11 +161,11 @@ public BatteryInverterKacoBlueplanetGridsaveImpl() { @Activate private void activate(ComponentContext context, Config config) throws OpenemsException { + this.config = config; if (super.activate(context, config.id(), config.alias(), config.enabled(), UNIT_ID, this.cm, "Modbus", config.modbus_id(), READ_FROM_MODBUS_BLOCK)) { return; } - this.config = config; } @Override @@ -279,6 +282,16 @@ private void handleGridDisconnection() { }); } + @Override + public ModbusSlaveTable getModbusSlaveTable(AccessMode accessMode) { + return new ModbusSlaveTable(// + OpenemsComponent.getModbusSlaveNatureTable(accessMode), // + SymmetricBatteryInverter.getModbusSlaveNatureTable(accessMode), // + ManagedSymmetricBatteryInverter.getModbusSlaveNatureTable(accessMode), // + ModbusSlaveNatureTable.of(BatteryInverterKacoBlueplanetGridsave.class, accessMode, 100) // + .build()); + } + @Override public BatteryInverterConstraint[] getStaticConstraints() throws OpenemsException { if (this.stateMachine.getCurrentState() == State.RUNNING) { diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/KacoSunSpecModel.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/KacoSunSpecModel.java index 2757dbf6616..88974aeedf0 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/KacoSunSpecModel.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/KacoSunSpecModel.java @@ -106,7 +106,8 @@ public static enum S64201 implements SunSpecPoint { V_AR(new ScaledValuePoint("S64201_V_AR", "AC Reactive Power", "", // ValuePoint.Type.INT16, true, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "V_AR_SF")), // HZ(new ScaledValuePoint("S64201_HZ", "Line Frequency", "", // - ValuePoint.Type.INT16, true, AccessMode.READ_ONLY, Unit.MILLIHERTZ, "mHZ_SF")), // + ValuePoint.Type.UINT16, true, AccessMode.READ_ONLY, Unit.HERTZ, "Hz_SF") + ), // RESERVED_36(new ReservedPoint("S64201_RESERVED_36")), // RESERVED_37(new ReservedPoint("S64201_RESERVED_37")), // RESERVED_38(new ReservedPoint("S64201_RESERVED_38")), // @@ -271,6 +272,7 @@ public static enum S64201StVnd implements OptionsEnum { LINE_FAILURE_OVERVOLTAGE_3(46, "Line failure overvoltage L3 The voltage of a grid phase is too low; the grid cannot be fed into. The phase experiencing failure is displayed."), // GRID_FAILURE_PHASETOPHASE(47, "Grid failure phase-to-phase voltage"), // + LINE_FAILURE_UNDERFREQ(48, "Line failure: underfreq. Grid frequency is too low. This fault may be gridrelated."), // LINE_FAILURE_OVERFREQ(49, diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/ErrorHandler.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/ErrorHandler.java index 8dc242a57b6..1424879da21 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/ErrorHandler.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/statemachine/ErrorHandler.java @@ -14,11 +14,18 @@ protected void onEntry(Context context) throws OpenemsNamedException { } @Override - public State runAndGetNextState(Context context) throws OpenemsNamedException { + public State runAndGetNextState(Context context) { final var inverter = context.getParent(); if (!inverter.hasFailure()) { - return State.GO_STOPPED; + return State.UNDEFINED; } return State.ERROR; } + + @Override + protected void onExit(Context context) { + final var inverter = context.getParent(); + inverter._setMaxStartTimeout(false); + inverter._setMaxStopTimeout(false); + } } 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 2a9e69ceb53..64a0473325d 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 @@ -43,16 +43,22 @@ public interface BatteryInverterRefuStore88k */ public static int RETRY_COMMAND_MAX_ATTEMPTS = 30; + /* + * Whenever one of these states would be Level.FAULT, the EssGeneric will stop + * the battery and the inverter. If this is necessary, it must be specifically + * mentioned and the state should have a proper description of the fault. + */ + public enum ChannelId implements io.openems.edge.common.channel.ChannelId { STATE_MACHINE(Doc.of(State.values()) // .text("Current State of State-Machine")), // - RUN_FAILED(Doc.of(Level.FAULT) // + RUN_FAILED(Doc.of(Level.WARNING) // .text("Running the Logic failed")), // - MAX_START_ATTEMPTS(Doc.of(Level.FAULT) // + MAX_START_ATTEMPTS(Doc.of(Level.WARNING) // .text("The maximum number of start attempts failed")), // - MAX_STOP_ATTEMPTS(Doc.of(Level.FAULT) // + MAX_STOP_ATTEMPTS(Doc.of(Level.WARNING) // .text("The maximum number of stop attempts failed")), // - INVERTER_CURRENT_STATE_FAULT(Doc.of(Level.FAULT) // + INVERTER_CURRENT_STATE_FAULT(Doc.of(Level.WARNING) // .text("The 'CurrentState' is invalid")), // /* @@ -106,41 +112,41 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { ST(Doc.of(OperatingState.values())), // ST_VND(Doc.of(VendorOperatingState.values())), // // Evt1 Alarms and Warnings - GROUND_FAULT(Doc.of(Level.FAULT) // + GROUND_FAULT(Doc.of(Level.WARNING) // .text("Ground fault")), // - DC_OVER_VOLTAGE(Doc.of(Level.FAULT) // + DC_OVER_VOLTAGE(Doc.of(Level.WARNING) // .text("Dc over voltage")), // - AC_DISCONNECT(Doc.of(Level.FAULT) // + AC_DISCONNECT(Doc.of(Level.WARNING) // .text("AC disconnect open")), // - DC_DISCONNECT(Doc.of(Level.FAULT) // + DC_DISCONNECT(Doc.of(Level.WARNING) // .text("DC disconnect open")), // - GRID_DISCONNECT(Doc.of(Level.FAULT) // + GRID_DISCONNECT(Doc.of(Level.WARNING) // .text("Grid shutdown")), // - CABINET_OPEN(Doc.of(Level.FAULT) // + CABINET_OPEN(Doc.of(Level.WARNING) // .text("Cabinet open")), // - MANUAL_SHUTDOWN(Doc.of(Level.FAULT) // + MANUAL_SHUTDOWN(Doc.of(Level.WARNING) // .text("Manual shutdown")), // - OVER_TEMP(Doc.of(Level.FAULT) // + OVER_TEMP(Doc.of(Level.WARNING) // .text("Over temperature")), // - OVER_FREQUENCY(Doc.of(Level.FAULT) // + OVER_FREQUENCY(Doc.of(Level.WARNING) // .text("Frequency above limit")), // - UNDER_FREQUENCY(Doc.of(Level.FAULT) // + UNDER_FREQUENCY(Doc.of(Level.WARNING) // .text("Frequency under limit")), // - AC_OVER_VOLT(Doc.of(Level.FAULT) // + AC_OVER_VOLT(Doc.of(Level.WARNING) // .text("AC Voltage above limit")), // - AC_UNDER_VOLT(Doc.of(Level.FAULT) // + AC_UNDER_VOLT(Doc.of(Level.WARNING) // .text("AC Voltage under limit")), // - BLOWN_STRING_FUSE(Doc.of(Level.FAULT) // + BLOWN_STRING_FUSE(Doc.of(Level.WARNING) // .text("Blown String fuse on input")), // - UNDER_TEMP(Doc.of(Level.FAULT) // + UNDER_TEMP(Doc.of(Level.WARNING) // .text("Under temperature")), // - MEMORY_LOSS(Doc.of(Level.FAULT) // + MEMORY_LOSS(Doc.of(Level.WARNING) // .text("Generic Memory or Communication error (internal)")), // - HW_TEST_FAILURE(Doc.of(Level.FAULT) // + HW_TEST_FAILURE(Doc.of(Level.WARNING) // .text("Hardware test failure")), // - OTHER_ALARM(Doc.of(Level.FAULT) // + OTHER_ALARM(Doc.of(Level.WARNING) // .text("Other alarm")), // - OTHER_WARNING(Doc.of(Level.FAULT) // + OTHER_WARNING(Doc.of(Level.WARNING) // .text("Other warning")), // EVT_2(Doc.of(OpenemsType.INTEGER).unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // EVT_VND_1(Doc.of(OpenemsType.INTEGER).unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // diff --git a/io.openems.edge.batteryinverter.sinexcel/src/io/openems/edge/batteryinverter/sinexcel/BatteryInverterSinexcel.java b/io.openems.edge.batteryinverter.sinexcel/src/io/openems/edge/batteryinverter/sinexcel/BatteryInverterSinexcel.java index daa20ac5029..d54e8bbe2d1 100644 --- a/io.openems.edge.batteryinverter.sinexcel/src/io/openems/edge/batteryinverter/sinexcel/BatteryInverterSinexcel.java +++ b/io.openems.edge.batteryinverter.sinexcel/src/io/openems/edge/batteryinverter/sinexcel/BatteryInverterSinexcel.java @@ -44,7 +44,7 @@ public interface BatteryInverterSinexcel extends OffGridBatteryInverter, Managed public enum ChannelId implements io.openems.edge.common.channel.ChannelId { STATE_MACHINE(Doc.of(State.values()) // .text("Current State of State-Machine")), // - RUN_FAILED(Doc.of(Level.FAULT) // + RUN_FAILED(Doc.of(Level.WARNING) // .text("Running the Logic failed")), // SET_ACTIVE_POWER(Doc.of(OpenemsType.INTEGER) // .accessMode(AccessMode.READ_WRITE)// @@ -96,7 +96,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { SERIAL_NUMBER(Doc.of(OpenemsType.STRING) // .persistencePriority(PersistencePriority.HIGH) // .accessMode(AccessMode.READ_ONLY)), // - FAULT_STATUS(Doc.of(Level.FAULT) // + FAULT_STATUS(Doc.of(Level.WARNING) // .accessMode(AccessMode.READ_ONLY)), // ALERT_STATUS(Doc.of(Level.WARNING) // .accessMode(AccessMode.READ_ONLY)), // diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/BridgeModbusSerialImpl.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/BridgeModbusSerialImpl.java index d36835f41f8..3c5c5d64c19 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/BridgeModbusSerialImpl.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/BridgeModbusSerialImpl.java @@ -24,6 +24,7 @@ import io.openems.edge.bridge.modbus.api.AbstractModbusBridge; import io.openems.edge.bridge.modbus.api.BridgeModbus; import io.openems.edge.bridge.modbus.api.BridgeModbusSerial; +import io.openems.edge.bridge.modbus.api.Config; import io.openems.edge.bridge.modbus.api.Parity; import io.openems.edge.bridge.modbus.api.Stopbit; import io.openems.edge.common.component.OpenemsComponent; @@ -86,15 +87,15 @@ public BridgeModbusSerialImpl() { @Activate private void activate(ComponentContext context, ConfigSerial config) { - super.activate(context, config.id(), config.alias(), config.enabled(), config.logVerbosity(), - config.invalidateElementsAfterReadErrors()); + super.activate(context, new Config(config.id(), config.alias(), config.enabled(), config.logVerbosity(), + config.invalidateElementsAfterReadErrors())); this.applyConfig(config); } @Modified private void modified(ComponentContext context, ConfigSerial config) { - super.modified(context, config.id(), config.alias(), config.enabled(), config.logVerbosity(), - config.invalidateElementsAfterReadErrors()); + super.modified(context, new Config(config.id(), config.alias(), config.enabled(), config.logVerbosity(), + config.invalidateElementsAfterReadErrors())); this.applyConfig(config); this.closeModbusConnection(); } diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/BridgeModbusTcpImpl.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/BridgeModbusTcpImpl.java index 9cd9cd3dff3..aacd72d89fd 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/BridgeModbusTcpImpl.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/BridgeModbusTcpImpl.java @@ -22,6 +22,7 @@ import io.openems.edge.bridge.modbus.api.AbstractModbusBridge; import io.openems.edge.bridge.modbus.api.BridgeModbus; import io.openems.edge.bridge.modbus.api.BridgeModbusTcp; +import io.openems.edge.bridge.modbus.api.Config; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.event.EdgeEventConstants; @@ -56,15 +57,15 @@ public BridgeModbusTcpImpl() { @Activate private void activate(ComponentContext context, ConfigTcp config) throws UnknownHostException { - super.activate(context, config.id(), config.alias(), config.enabled(), config.logVerbosity(), - config.invalidateElementsAfterReadErrors()); + super.activate(context, new Config(config.id(), config.alias(), config.enabled(), config.logVerbosity(), + config.invalidateElementsAfterReadErrors())); this.applyConfig(config); } @Modified private void modified(ComponentContext context, ConfigTcp config) throws UnknownHostException { - super.modified(context, config.id(), config.alias(), config.enabled(), config.logVerbosity(), - config.invalidateElementsAfterReadErrors()); + super.modified(context, new Config(config.id(), config.alias(), config.enabled(), config.logVerbosity(), + config.invalidateElementsAfterReadErrors())); this.applyConfig(config); this.closeModbusConnection(); } diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/AbstractModbusBridge.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/AbstractModbusBridge.java index 52087943576..2410fbaf055 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/AbstractModbusBridge.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/AbstractModbusBridge.java @@ -1,6 +1,5 @@ package io.openems.edge.bridge.modbus.api; -import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Stream; import org.osgi.service.component.ComponentContext; @@ -35,8 +34,7 @@ public abstract class AbstractModbusBridge extends AbstractOpenemsComponent impl */ protected static final int DEFAULT_RETRIES = 1; - private final AtomicReference logVerbosity = new AtomicReference<>(LogVerbosity.NONE); - private int invalidateElementsAfterReadErrors = 1; + private Config config = null; protected final ModbusWorker worker = new ModbusWorker( // Execute Task @@ -47,8 +45,8 @@ public abstract class AbstractModbusBridge extends AbstractOpenemsComponent impl state -> this._setCycleTimeIsTooShort(state), // Set ChannelId.CYCLE_DELAY cycleDelay -> this._setCycleDelay(cycleDelay), - // LogVerbosity - this.logVerbosity // + // LogHandler + () -> this.config.log // ); protected AbstractModbusBridge(io.openems.edge.common.channel.ChannelId[] firstInitialChannelIds, @@ -62,12 +60,11 @@ protected void activate(ComponentContext context, String id, String alias, boole throw new IllegalArgumentException("Use the other activate() method."); } - protected void activate(ComponentContext context, String id, String alias, boolean enabled, - LogVerbosity logVerbosity, int invalidateElementsAfterReadErrors) { - super.activate(context, id, alias, enabled); - this.applyConfig(logVerbosity, invalidateElementsAfterReadErrors); - if (enabled) { - this.worker.activate(id); + protected void activate(ComponentContext context, Config config) { + super.activate(context, config.id, config.alias, config.enabled); + this.applyConfig(config); + if (config.enabled) { + this.worker.activate(config.id); } } @@ -84,20 +81,18 @@ protected void modified(ComponentContext context, String id, String alias, boole throw new IllegalArgumentException("Use the other modified() method."); } - protected void modified(ComponentContext context, String id, String alias, boolean enabled, - LogVerbosity logVerbosity, int invalidateElementsAfterReadErrors) { - super.modified(context, id, alias, enabled); - this.applyConfig(logVerbosity, invalidateElementsAfterReadErrors); - if (enabled) { - this.worker.modified(id); + protected void modified(ComponentContext context, Config config) { + super.modified(context, config.id, config.alias, config.enabled); + this.applyConfig(config); + if (config.enabled) { + this.worker.modified(config.id); } else { this.worker.deactivate(); } } - private void applyConfig(LogVerbosity logVerbosity, int invalidateElementsAfterReadErrors) { - this.logVerbosity.set(logVerbosity); - this.invalidateElementsAfterReadErrors = invalidateElementsAfterReadErrors; + private void applyConfig(Config config) { + this.config = config; } /** @@ -124,22 +119,24 @@ public void removeProtocol(String sourceId) { @Override public void handleEvent(Event event) { - if (!this.isEnabled()) { + if (this.config == null || !this.isEnabled()) { return; } switch (event.getTopic()) { - case EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE: - this.worker.onBeforeProcessImage(); - break; - case EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE: - this.worker.onExecuteWrite(); - break; + case EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE // + -> this.worker.onBeforeProcessImage(); + + case EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE // + -> this.worker.onExecuteWrite(); } } @Override public String debugLog() { - return switch (this.logVerbosity.get()) { + if (this.config == null) { + return null; + } + return switch (this.config.log.verbosity) { case NONE -> // null; case DEBUG_LOG, READS_AND_WRITES, READS_AND_WRITES_DURATION, READS_AND_WRITES_VERBOSE, @@ -167,7 +164,7 @@ public String debugLog() { * @return {@link LogVerbosity} */ public LogVerbosity getLogVerbosity() { - return this.logVerbosity.get(); + return this.config.log.verbosity; } /** @@ -177,7 +174,7 @@ public LogVerbosity getLogVerbosity() { * @return value */ public int invalidateElementsAfterReadErrors() { - return this.invalidateElementsAfterReadErrors; + return this.config.invalidateElementsAfterReadErrors; } @Override diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/AbstractOpenemsModbusComponent.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/AbstractOpenemsModbusComponent.java index 7bf6e9e249d..80c29c5f234 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/AbstractOpenemsModbusComponent.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/AbstractOpenemsModbusComponent.java @@ -110,17 +110,7 @@ protected void activate(String id) { protected boolean activate(ComponentContext context, String id, String alias, boolean enabled, int unitId, ConfigurationAdmin cm, String modbusReference, String modbusId) throws OpenemsException { super.activate(context, id, alias, enabled); - // update filter for 'Modbus' - if (OpenemsComponent.updateReferenceFilter(cm, this.servicePid(), "Modbus", modbusId)) { - return true; - } - this.unitId = unitId; - var modbus = this.modbus.get(); - if (this.isEnabled() && modbus != null) { - modbus.addProtocol(this.id(), this.getModbusProtocol()); - modbus.retryModbusCommunication(this.id()); - } - return false; + return this.activateOrModified(unitId, cm, modbusReference, modbusId); } @Override @@ -147,19 +137,41 @@ protected void activate(ComponentContext context, String id, String alias, boole * @param modbusId The ID of the Modbus bridge. Typically * 'config.modbus_id()' * @return true if the target filter was updated. You may use it to abort the - * activate() method. + * modified() method. * @throws OpenemsException on error */ protected boolean modified(ComponentContext context, String id, String alias, boolean enabled, int unitId, ConfigurationAdmin cm, String modbusReference, String modbusId) throws OpenemsException { super.modified(context, id, alias, enabled); + return this.activateOrModified(unitId, cm, modbusReference, modbusId); + } + + @Override + protected void modified(ComponentContext context, String id, String alias, boolean enabled) { + throw new IllegalArgumentException("Use the other modified() for Modbus components!"); + } + + /** + * Common tasks for @Activate and @Modified. + * + * @param unitId Unit-ID of the Modbus target + * @param cm An instance of ConfigurationAdmin. Receive it + * using @Reference + * @param modbusReference The name of the @Reference setter method for the + * Modbus bridge - e.g. 'Modbus' if you have a + * setModbus()-method + * @param modbusId The ID of the Modbus bridge. Typically + * 'config.modbus_id()' + * @return true if the target filter was updated. You may use it to abort the + * activate() or modified() method. + */ + private boolean activateOrModified(int unitId, ConfigurationAdmin cm, String modbusReference, String modbusId) { // update filter for 'Modbus' - if (OpenemsComponent.updateReferenceFilter(cm, this.servicePid(), "Modbus", modbusId)) { + if (OpenemsComponent.updateReferenceFilter(cm, this.servicePid(), modbusReference, modbusId)) { return true; } this.unitId = unitId; var modbus = this.modbus.get(); - modbus.removeProtocol(this.id()); if (this.isEnabled() && modbus != null) { modbus.addProtocol(this.id(), this.getModbusProtocol()); modbus.retryModbusCommunication(this.id()); @@ -167,11 +179,6 @@ protected boolean modified(ComponentContext context, String id, String alias, bo return false; } - @Override - protected void modified(ComponentContext context, String id, String alias, boolean enabled) { - throw new IllegalArgumentException("Use the other activate() for Modbus components!"); - } - @Override protected void deactivate() { super.deactivate(); diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/Config.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/Config.java new file mode 100644 index 00000000000..9f6e98b6d45 --- /dev/null +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/Config.java @@ -0,0 +1,60 @@ +package io.openems.edge.bridge.modbus.api; + +import java.util.function.Supplier; + +import org.slf4j.Logger; + +public class Config { + + public final String id; + public final String alias; + public final boolean enabled; + public final int invalidateElementsAfterReadErrors; + public final LogHandler log; + + public Config(String id, String alias, boolean enabled, LogVerbosity logVerbosity, + int invalidateElementsAfterReadErrors) { + this.id = id; + this.alias = alias; + this.enabled = enabled; + this.invalidateElementsAfterReadErrors = invalidateElementsAfterReadErrors; + this.log = new LogHandler(this, logVerbosity); + } + + public static class LogHandler { + public final LogVerbosity verbosity; + + private final Config config; + + private LogHandler(Config config, LogVerbosity logVerbosity) { + this.config = config; + this.verbosity = logVerbosity; + } + + /** + * Logs messages for + * {@link LogVerbosity#READS_AND_WRITES_DURATION_TRACE_EVENTS}. + * + * @param logger the {@link Logger} + * @param message the String message + */ + public void trace(Logger logger, Supplier message) { + if (this.isTrace()) { + logger.info("[" + this.config.id + "] " + message.get()); + } + } + + /** + * Return true if {@link LogVerbosity#READS_AND_WRITES_DURATION_TRACE_EVENTS} is + * active. + * + * @return true for trace-log + */ + public boolean isTrace() { + return switch (this.verbosity) { + case NONE, DEBUG_LOG, READS_AND_WRITES, READS_AND_WRITES_DURATION, READS_AND_WRITES_VERBOSE -> false; + case READS_AND_WRITES_DURATION_TRACE_EVENTS -> true; + }; + } + } +} \ No newline at end of file diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/ModbusComponent.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/ModbusComponent.java index ace3a2c4da4..c2b284dd80f 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/ModbusComponent.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/ModbusComponent.java @@ -20,7 +20,13 @@ public interface ModbusComponent extends OpenemsComponent { public enum ChannelId implements io.openems.edge.common.channel.ChannelId { - MODBUS_COMMUNICATION_FAILED(Doc.of(Level.FAULT) // + + /* + * If ModbusCommunicationFault would be a FaultState, check it explicitly in + * Generic Ess ErrorHandler, as the battery could still have a communication + * fault while starting the battery + */ + MODBUS_COMMUNICATION_FAILED(Doc.of(Level.WARNING) // .debounce(10, Debounce.SAME_VALUES_IN_A_ROW_TO_CHANGE) // .text("Modbus Communication failed")) // ; diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/worker/ModbusWorker.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/worker/ModbusWorker.java index 68aed664b5d..2558852fc4d 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/worker/ModbusWorker.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/worker/ModbusWorker.java @@ -1,12 +1,12 @@ package io.openems.edge.bridge.modbus.api.worker; -import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.Supplier; import io.openems.common.worker.AbstractImmediateWorker; import io.openems.edge.bridge.modbus.api.BridgeModbus; -import io.openems.edge.bridge.modbus.api.LogVerbosity; +import io.openems.edge.bridge.modbus.api.Config.LogHandler; import io.openems.edge.bridge.modbus.api.ModbusComponent; import io.openems.edge.bridge.modbus.api.ModbusProtocol; import io.openems.edge.bridge.modbus.api.element.ModbusElement; @@ -52,18 +52,19 @@ public class ModbusWorker extends AbstractImmediateWorker { * @param cycleDelayChannel sets the * {@link BridgeModbus.ChannelId#CYCLE_DELAY} * channel - * @param logVerbosity the configured {@link LogVerbosity} + * @param logHandler a {@link Supplier} for the + * {@link LogHandler} */ public ModbusWorker(Function execute, Consumer invalidate, Consumer cycleTimeIsTooShortChannel, Consumer cycleDelayChannel, - AtomicReference logVerbosity) { + Supplier logHandler) { this.execute = execute; this.invalidate = invalidate; - this.defectiveComponents = new DefectiveComponents(logVerbosity); - this.tasksSupplier = new TasksSupplierImpl(); + this.defectiveComponents = new DefectiveComponents(logHandler); + this.tasksSupplier = new TasksSupplierImpl(logHandler); this.cycleTasksManager = new CycleTasksManager(this.tasksSupplier, this.defectiveComponents, - cycleTimeIsTooShortChannel, cycleDelayChannel, logVerbosity); + cycleTimeIsTooShortChannel, cycleDelayChannel, logHandler); } @Override @@ -123,7 +124,7 @@ private void markComponentAsDefective(ModbusComponent component, boolean isDefec * @param protocol the ModbusProtocol */ public void addProtocol(String sourceId, ModbusProtocol protocol) { - this.tasksSupplier.addProtocol(sourceId, protocol); + this.tasksSupplier.addProtocol(sourceId, protocol, this.invalidate); this.defectiveComponents.remove(sourceId); // Cleanup } @@ -133,7 +134,7 @@ public void addProtocol(String sourceId, ModbusProtocol protocol) { * @param sourceId Component-ID of the source */ public void removeProtocol(String sourceId) { - this.tasksSupplier.removeProtocol(sourceId); + this.tasksSupplier.removeProtocol(sourceId, this.invalidate); this.defectiveComponents.remove(sourceId); // Cleanup } diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/worker/internal/CycleTasksManager.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/worker/internal/CycleTasksManager.java index fbee14394ac..03222a82a04 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/worker/internal/CycleTasksManager.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/worker/internal/CycleTasksManager.java @@ -1,12 +1,12 @@ package io.openems.edge.bridge.modbus.api.worker.internal; -import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; +import java.util.function.Supplier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.openems.edge.bridge.modbus.api.LogVerbosity; +import io.openems.edge.bridge.modbus.api.Config.LogHandler; import io.openems.edge.bridge.modbus.api.task.Task; import io.openems.edge.bridge.modbus.api.task.WaitTask; import io.openems.edge.bridge.modbus.api.worker.ModbusWorker; @@ -26,7 +26,7 @@ public class CycleTasksManager { private final TasksSupplier tasksSupplier; private final DefectiveComponents defectiveComponents; private final Consumer cycleTimeIsTooShortChannel; - private final AtomicReference logVerbosity; + private final Supplier logHandler; private final WaitDelayHandler waitDelayHandler; private final WaitTask.Mutex waitMutexTask = new WaitTask.Mutex(); @@ -35,22 +35,15 @@ public class CycleTasksManager { public CycleTasksManager(TasksSupplier tasksSupplier, DefectiveComponents defectiveComponents, Consumer cycleTimeIsTooShortChannel, Consumer cycleDelayChannel, - AtomicReference logVerbosity) { + Supplier logHandler) { this.tasksSupplier = tasksSupplier; this.defectiveComponents = defectiveComponents; this.cycleTimeIsTooShortChannel = cycleTimeIsTooShortChannel; - this.logVerbosity = logVerbosity; - + this.logHandler = logHandler; this.waitDelayHandler = new WaitDelayHandler(() -> this.onWaitDelayTaskFinished(), cycleDelayChannel); } - protected CycleTasksManager(TasksSupplier tasksSupplier, DefectiveComponents defectiveComponents, - Consumer cycleTimeIsTooShortChannel, Consumer cycleDelayChannel) { - this(tasksSupplier, defectiveComponents, cycleTimeIsTooShortChannel, cycleDelayChannel, - new AtomicReference<>(LogVerbosity.NONE)); - } - - private static enum StateMachine { + protected static enum StateMachine { INITIAL_WAIT, // READ_BEFORE_WRITE, // WAIT_FOR_WRITE, // @@ -62,24 +55,31 @@ private static enum StateMachine { private StateMachine state = StateMachine.FINISHED; + /** + * Gets the current state. + * + * @return the {@link StateMachine} + */ + protected StateMachine getState() { + return this.state; + } + /** * Called on BEFORE_PROCESS_IMAGE event. */ public synchronized void onBeforeProcessImage() { // Calculate Delay - var waitDelayHandlerLog = this.waitDelayHandler.onBeforeProcessImage(this.isTraceLog()); + final var waitDelayHandlerLog = this.waitDelayHandler.onBeforeProcessImage(this.logHandler.get().isTrace()); // Evaluate Cycle-Time-Is-Too-Short, invalidate time measurement and stop early var cycleTimeIsTooShort = this.state != StateMachine.FINISHED; this.cycleTimeIsTooShortChannel.accept(cycleTimeIsTooShort); if (cycleTimeIsTooShort) { this.waitDelayHandler.timeIsInvalid(); - if (this.isTraceLog()) { - this.log.info("State: " + this.state + " unchanged" // - + " (in onBeforeProcessImage)" // - + " Delay [" + this.waitDelayHandler.getWaitDelayTask().initialDelay + "] " // - + waitDelayHandlerLog); - } + this.traceLog(() -> "State: " + this.state + " unchanged" // + + " (in onBeforeProcessImage)" // + + " Delay [" + this.waitDelayHandler.getWaitDelayTask().initialDelay + "] " // + + waitDelayHandlerLog); return; } @@ -90,18 +90,19 @@ public synchronized void onBeforeProcessImage() { this.cycleTasks = this.tasksSupplier.getCycleTasks(this.defectiveComponents); // On defectiveComponents invalidate time measurement - if (this.cycleTasks.containsDefectiveComponent(this.defectiveComponents)) { + final var containsDefectiveComponents = this.cycleTasks.containsDefectiveComponent(this.defectiveComponents); + if (containsDefectiveComponents) { this.waitDelayHandler.timeIsInvalid(); - waitDelayHandlerLog += " DEFECTIVE_COMPONENT"; } // Initialize next Cycle - if (this.isTraceLog()) { - this.log.info("State: " + this.state + " -> " + StateMachine.INITIAL_WAIT // - + " (in onBeforeProcessImage)" // - + " Delay [" + this.waitDelayHandler.getWaitDelayTask().initialDelay + "] " // - + waitDelayHandlerLog); - } + this.traceLog(() -> "State: " + this.state + " -> " + StateMachine.INITIAL_WAIT // + + " (in onBeforeProcessImage)" // + + " Delay [" + this.waitDelayHandler.getWaitDelayTask().initialDelay + "] " // + + waitDelayHandlerLog // + + (containsDefectiveComponents // + ? " DEFECTIVE_COMPONENT" + : "")); this.state = StateMachine.INITIAL_WAIT; // Interrupt wait @@ -112,9 +113,7 @@ public synchronized void onBeforeProcessImage() { * Called on EXECUTE_WRITE event. */ public synchronized void onExecuteWrite() { - if (this.isTraceLog()) { - this.log.info("State: " + this.state + " -> " + StateMachine.WRITE + " (onExecuteWrite)"); - } + this.traceLog(() -> "State: " + this.state + " -> " + StateMachine.WRITE + " (onExecuteWrite)"); this.state = StateMachine.WRITE; this.waitMutexTask.release(); @@ -128,7 +127,8 @@ public synchronized void onExecuteWrite() { */ public Task getNextTask() { if (this.cycleTasks == null) { - return this.waitMutexTask; + // Fallback to avoid NPE on race condition + this.cycleTasks = this.tasksSupplier.getCycleTasks(this.defectiveComponents); } var previousState = this.state; // drop before release @@ -187,8 +187,8 @@ public Task getNextTask() { } }; - if (this.state != previousState && this.isTraceLog()) { - this.log.info("State: " + previousState + " -> " + this.state + " (getNextTask)"); + if (this.state != previousState) { + this.traceLog(() -> "State: " + previousState + " -> " + this.state + " (getNextTask)"); } return nextTask; } @@ -207,16 +207,11 @@ private synchronized void onWaitDelayTaskFinished() { }; if (this.state != previousState) { - if (this.isTraceLog()) { - this.log.info("State: " + previousState + " -> " + this.state + " (onWaitDelayTaskFinished)"); - } + this.traceLog(() -> "State: " + previousState + " -> " + this.state + " (onWaitDelayTaskFinished)"); } } - private boolean isTraceLog() { - return switch (this.logVerbosity.get()) { - case READS_AND_WRITES_DURATION_TRACE_EVENTS -> true; - case NONE, DEBUG_LOG, READS_AND_WRITES, READS_AND_WRITES_DURATION, READS_AND_WRITES_VERBOSE -> false; - }; + private void traceLog(Supplier message) { + this.logHandler.get().trace(this.log, message); } } \ No newline at end of file diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/worker/internal/DefectiveComponents.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/worker/internal/DefectiveComponents.java index 6fa218f805f..80cb95937df 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/worker/internal/DefectiveComponents.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/worker/internal/DefectiveComponents.java @@ -4,12 +4,12 @@ import java.time.Instant; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.openems.edge.bridge.modbus.api.LogVerbosity; +import io.openems.edge.bridge.modbus.api.Config.LogHandler; import io.openems.edge.common.type.TypeUtils; public class DefectiveComponents { @@ -23,24 +23,16 @@ private static record NextTry(Instant timestamp, int count) { } private final Clock clock; - private final AtomicReference logVerbosity; + private final Supplier logHandler; private final Map nextTries = new HashMap<>(); - public DefectiveComponents(AtomicReference logVerbosity) { - this(Clock.systemDefaultZone(), logVerbosity); + public DefectiveComponents(Supplier logHandler) { + this(Clock.systemDefaultZone(), logHandler); } - protected DefectiveComponents() { - this(Clock.systemDefaultZone(), new AtomicReference<>(LogVerbosity.READS_AND_WRITES_DURATION_TRACE_EVENTS)); - } - - protected DefectiveComponents(Clock clock) { - this(clock, new AtomicReference<>(LogVerbosity.READS_AND_WRITES_DURATION_TRACE_EVENTS)); - } - - protected DefectiveComponents(Clock clock, AtomicReference logVerbosity) { + protected DefectiveComponents(Clock clock, Supplier logHandler) { this.clock = clock; - this.logVerbosity = logVerbosity; + this.logHandler = logHandler; } /** @@ -54,15 +46,11 @@ public synchronized void add(String componentId) { this.nextTries.compute(componentId, (k, v) -> { var count = (v == null) ? 1 : v.count + 1; var wait = Math.min(INCREASE_WAIT_SECONDS * count, MAX_WAIT_SECONDS); - if (this.isTraceLog()) { - final String log; - if (count == 1) { - log = "Add [" + componentId + "] to defective Components."; - } else { - log = "Increase wait for defective Component [" + componentId + "]."; - } - this.log.info(log + " Wait [" + wait + "s]" + " Count [" + count + "]"); - } + this.traceLog(() -> // + (count == 1 // + ? "Add [" + componentId + "] to defective Components." // + : "Increase wait for defective Component [" + componentId + "].") + " Wait [" + wait + "s]" + + " Count [" + count + "]"); return new NextTry(Instant.now(this.clock).plusSeconds(wait), count); }); } @@ -74,8 +62,8 @@ public synchronized void add(String componentId) { */ public synchronized void remove(String componentId) { TypeUtils.assertNull("DefectiveComponents remove() takes no null values", componentId); - if (this.nextTries.remove(componentId) != null && this.isTraceLog()) { - this.log.info("Remove [" + componentId + "] from defective Components."); + if (this.nextTries.remove(componentId) != null) { + this.traceLog(() -> "Remove [" + componentId + "] from defective Components."); } } @@ -105,12 +93,7 @@ public synchronized Boolean isDueForNextTry(String componentId) { return now.isAfter(nextTry.timestamp); } - private boolean isTraceLog() { - return switch (this.logVerbosity.get()) { - case READS_AND_WRITES, READS_AND_WRITES_DURATION, READS_AND_WRITES_VERBOSE, - READS_AND_WRITES_DURATION_TRACE_EVENTS -> - true; - case NONE, DEBUG_LOG -> false; - }; + private void traceLog(Supplier message) { + this.logHandler.get().trace(this.log, message); } } \ No newline at end of file diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/worker/internal/TasksSupplierImpl.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/worker/internal/TasksSupplierImpl.java index e7c6a4bcb02..2f836ee0c14 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/worker/internal/TasksSupplierImpl.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/worker/internal/TasksSupplierImpl.java @@ -5,9 +5,16 @@ import java.util.LinkedList; import java.util.Map; import java.util.Queue; +import java.util.function.Consumer; +import java.util.function.Supplier; import java.util.stream.Collectors; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.openems.edge.bridge.modbus.api.Config.LogHandler; import io.openems.edge.bridge.modbus.api.ModbusProtocol; +import io.openems.edge.bridge.modbus.api.element.ModbusElement; import io.openems.edge.bridge.modbus.api.task.ReadTask; import io.openems.edge.bridge.modbus.api.task.Task; import io.openems.edge.bridge.modbus.api.task.WriteTask; @@ -20,6 +27,13 @@ */ public class TasksSupplierImpl implements TasksSupplier { + private final Logger log = LoggerFactory.getLogger(TasksSupplierImpl.class); + private final Supplier logHandler; + + public TasksSupplierImpl(Supplier logHandler) { + this.logHandler = logHandler; + } + /** * Source-ID -> TasksManager for {@link Task}s. */ @@ -31,22 +45,45 @@ public class TasksSupplierImpl implements TasksSupplier { private final Queue> nextLowPriorityTasks = new LinkedList<>(); /** - * Adds the protocol. - * - * @param sourceId Component-ID of the source - * @param protocol the ModbusProtocol + * Adds (or replaces) the protocol identified by its sourceId. + * + *

      + * If a protocol with the same sourceId existed before, + * {@link #removeProtocol(String, Consumer)} is called internally first. + * + * @param sourceId Component-ID of the source + * @param protocol the ModbusProtocol + * @param invalidate invalidates the given {@link ModbusElement}s after read + * errors */ - public synchronized void addProtocol(String sourceId, ModbusProtocol protocol) { + public synchronized void addProtocol(String sourceId, ModbusProtocol protocol, + Consumer invalidate) { + this.removeProtocol(sourceId, invalidate); // remove if sourceId exists + + this.traceLog(() -> "Add Protocol for " // + + "[" + sourceId + "] with " // + + "[" + protocol.getTaskManager().countTasks() + "] tasks"); this.taskManagers.put(sourceId, protocol.getTaskManager()); } /** - * Removes the protocol. + * Removes the protocol and invalidates all {@link ModbusElement}s. * - * @param sourceId Component-ID of the source + * @param sourceId Component-ID of the source + * @param invalidate invalidates the given {@link ModbusElement}s after read + * errors */ - public synchronized void removeProtocol(String sourceId) { - this.taskManagers.remove(sourceId); + public synchronized void removeProtocol(String sourceId, Consumer invalidate) { + var taskManager = this.taskManagers.remove(sourceId); + if (taskManager == null) { + return; + } + + this.traceLog(() -> "Remove Protocol for " // + + "[" + sourceId + "] with " // + + "[" + taskManager.countTasks() + "] tasks"); + taskManager.getTasks() // + .forEach(t -> invalidate.accept(t.getElements())); this.nextLowPriorityTasks.removeIf(t -> t.a() == sourceId); } @@ -84,7 +121,7 @@ public synchronized CycleTasks getCycleTasks(DefectiveComponents defectiveCompon componentTasks.clear(); } }); - return new CycleTasks(// + var result = new CycleTasks(// tasks.values().stream().flatMap(LinkedList::stream) // .filter(ReadTask.class::isInstance).map(ReadTask.class::cast) // // Sort HIGH priority to the end @@ -93,6 +130,11 @@ public synchronized CycleTasks getCycleTasks(DefectiveComponents defectiveCompon tasks.values().stream().flatMap(LinkedList::stream) // .filter(WriteTask.class::isInstance).map(WriteTask.class::cast) // .collect(Collectors.toCollection(LinkedList::new))); + + this.traceLog(() -> "Getting " // + + "[" + result.reads().size() + "] read and " // + + "[" + result.writes().size() + "] write tasks for this Cycle"); + return result; } /** @@ -128,4 +170,8 @@ public synchronized int getTotalNumberOfTasks() { .mapToInt(m -> m.countTasks()) // .sum(); } + + private void traceLog(Supplier message) { + this.logHandler.get().trace(this.log, message); + } } 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 1d508bb9363..017e7e7bd6f 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 @@ -11,6 +11,7 @@ import io.openems.edge.bridge.modbus.api.AbstractModbusBridge; import io.openems.edge.bridge.modbus.api.BridgeModbus; import io.openems.edge.bridge.modbus.api.BridgeModbusTcp; +import io.openems.edge.bridge.modbus.api.Config; import io.openems.edge.bridge.modbus.api.LogVerbosity; import io.openems.edge.bridge.modbus.api.ModbusProtocol; import io.openems.edge.common.channel.Channel; @@ -35,7 +36,7 @@ public DummyModbusBridge(String id, LogVerbosity logVerbosity) { for (Channel channel : this.channels()) { channel.nextProcessImage(); } - super.activate(null, id, "", true, logVerbosity, 2); + super.activate(null, new Config(id, "", true, logVerbosity, 2)); } /** diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/BridgeModbusTcpImplTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/BridgeModbusTcpImplTest.java index 276dc8dcce6..e9400baf670 100644 --- a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/BridgeModbusTcpImplTest.java +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/BridgeModbusTcpImplTest.java @@ -1,6 +1,5 @@ package io.openems.edge.bridge.modbus; -import org.junit.Ignore; import org.junit.Test; import com.ghgande.j2mod.modbus.procimg.Register; @@ -35,7 +34,6 @@ public class BridgeModbusTcpImplTest { private static final ChannelAddress MODBUS_COMMUNICATION_FAILED = new ChannelAddress(DEVICE_ID, "ModbusCommunicationFailed"); - @Ignore @Test public void test() throws Exception { final ThrowingRunnable sleep = () -> Thread.sleep(CYCLE_TIME); @@ -57,9 +55,7 @@ public void test() throws Exception { * Instantiate Modbus-Bridge */ var sut = new BridgeModbusTcpImpl(); - var device = new MyModbusComponent(DEVICE_ID, sut, UNIT_ID); var test = new ComponentTest(sut) // - .addComponent(device) // .activate(MyConfigTcp.create() // .setId(MODBUS_ID) // .setIp("127.0.0.1") // @@ -67,6 +63,7 @@ public void test() throws Exception { .setInvalidateElementsAfterReadErrors(1) // .setLogVerbosity(LogVerbosity.NONE) // .build()); + test.addComponent(new MyModbusComponent(DEVICE_ID, sut, UNIT_ID)); /* * Successfully read Register @@ -80,30 +77,18 @@ public void test() throws Exception { .output(MODBUS_COMMUNICATION_FAILED, false)); // /* - * Reading Register fails after debounce of 10 + * Remove Protocol and unset channel values */ - processImage.removeRegister(register100); - for (var i = 0; i < 9; i++) { - test.next(new TestCase() // - .onAfterProcessImage(sleep)); - } - test // - .next(new TestCase() // - .onAfterProcessImage(sleep) // - .output(MODBUS_COMMUNICATION_FAILED, false)) // - .next(new TestCase() // - .onAfterProcessImage(sleep) // - .output(MODBUS_COMMUNICATION_FAILED, true)); + sut.removeProtocol(DEVICE_ID); - /* - * Successfully read Register - */ - processImage.addRegister(100, register100); test // + .next(new TestCase() // + .onAfterProcessImage(sleep)) // .next(new TestCase() // .onAfterProcessImage(sleep) // - .output(REGISTER_100, 123) // + .output(REGISTER_100, null) // .output(MODBUS_COMMUNICATION_FAILED, false)); // + } finally { if (slave != null) { slave.close(); diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/internal/CycleTasksManagerTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/internal/CycleTasksManagerTest.java index 0d764fdecef..e57a4b32917 100644 --- a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/internal/CycleTasksManagerTest.java +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/internal/CycleTasksManagerTest.java @@ -1,15 +1,21 @@ package io.openems.edge.bridge.modbus.api.worker.internal; +import static io.openems.edge.bridge.modbus.api.worker.internal.CycleTasksManager.StateMachine.FINISHED; +import static io.openems.edge.bridge.modbus.api.worker.internal.CycleTasksManager.StateMachine.WAIT_BEFORE_READ; +import static io.openems.edge.bridge.modbus.api.worker.internal.CycleTasksManager.StateMachine.WRITE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.util.function.Consumer; +import java.util.function.Supplier; import org.junit.Before; import org.junit.Test; import io.openems.common.exceptions.OpenemsException; import io.openems.edge.bridge.modbus.DummyModbusComponent; +import io.openems.edge.bridge.modbus.api.Config; +import io.openems.edge.bridge.modbus.api.LogVerbosity; import io.openems.edge.bridge.modbus.api.task.WaitTask; import io.openems.edge.bridge.modbus.api.worker.DummyReadTask; import io.openems.edge.bridge.modbus.api.worker.DummyWriteTask; @@ -21,6 +27,8 @@ public class CycleTasksManagerTest { }; public static final Consumer CYCLE_DELAY = (cycleDelay) -> { }; + private static final Config CONFIG = new Config("foo", "bar", true, LogVerbosity.NONE, 1); + public static final Supplier LOG_HANDLER = () -> CONFIG.log; private static DummyReadTask RT_H_1; private static DummyReadTask RT_H_2; @@ -48,9 +56,10 @@ public void testIdealConditions() throws OpenemsException, InterruptedException .writes(WT_1) // .build(); var tasksSupplier = new DummyTasksSupplier(cycle1, cycle2); - var defectiveComponents = new DefectiveComponents(); + var defectiveComponents = new DefectiveComponents(LOG_HANDLER); - var sut = new CycleTasksManager(tasksSupplier, defectiveComponents, CYCLE_TIME_IS_TOO_SHORT, CYCLE_DELAY); + var sut = new CycleTasksManager(tasksSupplier, defectiveComponents, // + CYCLE_TIME_IS_TOO_SHORT, CYCLE_DELAY, LOG_HANDLER); // Cycle 1 sut.onBeforeProcessImage(); @@ -117,6 +126,32 @@ public void testIdealConditions() throws OpenemsException, InterruptedException // task.execute(null); -> this would block in single-threaded JUnit test } + @Test + public void testExecuteWriteBeforeNextProcessImage() throws OpenemsException, InterruptedException { + var cycle1 = CycleTasks.create() // + .reads(RT_L_1, RT_H_1, RT_H_2) // + .writes(WT_1) // + .build(); + var cycle2 = CycleTasks.create() // + .reads(RT_L_2, RT_H_1, RT_H_2) // + .writes(WT_1) // + .build(); + var tasksSupplier = new DummyTasksSupplier(cycle1, cycle2); + var defectiveComponents = new DefectiveComponents(LOG_HANDLER); + + var sut = new CycleTasksManager(tasksSupplier, defectiveComponents, // + CYCLE_TIME_IS_TOO_SHORT, CYCLE_DELAY, LOG_HANDLER); + + sut.getNextTask(); + assertEquals(FINISHED, sut.getState()); + sut.onExecuteWrite(); + sut.getNextTask(); + assertEquals(WRITE, sut.getState()); + sut.onBeforeProcessImage(); + sut.getNextTask(); + assertEquals(WAIT_BEFORE_READ, sut.getState()); + } + @Test public void testDefective() throws OpenemsException, InterruptedException { var component = new DummyModbusComponent(); @@ -131,10 +166,11 @@ public void testDefective() throws OpenemsException, InterruptedException { .writes(WT_1) // .build(); var tasksSupplier = new DummyTasksSupplier(cycle1, cycle2); - var defectiveComponents = new DefectiveComponents(); + var defectiveComponents = new DefectiveComponents(LOG_HANDLER); defectiveComponents.add(component.id()); - var sut = new CycleTasksManager(tasksSupplier, defectiveComponents, CYCLE_TIME_IS_TOO_SHORT, CYCLE_DELAY); + var sut = new CycleTasksManager(tasksSupplier, defectiveComponents, // + CYCLE_TIME_IS_TOO_SHORT, CYCLE_DELAY, LOG_HANDLER); // Cycle 1 sut.onBeforeProcessImage(); @@ -162,9 +198,10 @@ public void testNoTasks() throws OpenemsException, InterruptedException { var cycle1 = CycleTasks.create() // .build(); var tasksSupplier = new DummyTasksSupplier(cycle1); - var defectiveComponents = new DefectiveComponents(); + var defectiveComponents = new DefectiveComponents(LOG_HANDLER); - var sut = new CycleTasksManager(tasksSupplier, defectiveComponents, CYCLE_TIME_IS_TOO_SHORT, CYCLE_DELAY); + var sut = new CycleTasksManager(tasksSupplier, defectiveComponents, // + CYCLE_TIME_IS_TOO_SHORT, CYCLE_DELAY, LOG_HANDLER); // Cycle 1 sut.onBeforeProcessImage(); diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/internal/DefectiveComponentsTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/internal/DefectiveComponentsTest.java index 3f8d57ea014..615037eb9de 100644 --- a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/internal/DefectiveComponentsTest.java +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/internal/DefectiveComponentsTest.java @@ -1,5 +1,6 @@ package io.openems.edge.bridge.modbus.api.worker.internal; +import static io.openems.edge.bridge.modbus.api.worker.internal.CycleTasksManagerTest.LOG_HANDLER; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -17,7 +18,7 @@ public class DefectiveComponentsTest { @Test public void testIsDueForNextTry() { var clock = new TimeLeapClock(); - var sut = new DefectiveComponents(clock); + var sut = new DefectiveComponents(clock, LOG_HANDLER); assertNull(sut.isDueForNextTry(CMP)); sut.add(CMP); @@ -29,7 +30,7 @@ public void testIsDueForNextTry() { @Test public void testAddRemove() { var clock = new TimeLeapClock(); - var sut = new DefectiveComponents(clock); + var sut = new DefectiveComponents(clock, LOG_HANDLER); sut.add(CMP); clock.leap(30_001, ChronoUnit.MILLIS); @@ -40,7 +41,7 @@ public void testAddRemove() { @Test public void testIsKnownw() { - var sut = new DefectiveComponents(); + var sut = new DefectiveComponents(LOG_HANDLER); sut.add(CMP); assertTrue(sut.isKnown(CMP)); diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/internal/TasksSupplierImplTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/internal/TasksSupplierImplTest.java index 0af815bda47..1b016400acf 100644 --- a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/internal/TasksSupplierImplTest.java +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/internal/TasksSupplierImplTest.java @@ -1,5 +1,6 @@ package io.openems.edge.bridge.modbus.api.worker.internal; +import static io.openems.edge.bridge.modbus.api.worker.internal.CycleTasksManagerTest.LOG_HANDLER; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -11,6 +12,7 @@ import io.openems.common.exceptions.OpenemsException; import io.openems.common.test.TimeLeapClock; +import io.openems.common.utils.FunctionUtils; import io.openems.edge.bridge.modbus.DummyModbusComponent; import io.openems.edge.bridge.modbus.api.worker.DummyReadTask; import io.openems.edge.bridge.modbus.api.worker.DummyWriteTask; @@ -36,13 +38,13 @@ public void before() { @Test public void testFull() throws OpenemsException { var clock = new TimeLeapClock(); - var defectiveComponents = new DefectiveComponents(clock); - var sut = new TasksSupplierImpl(); + var defectiveComponents = new DefectiveComponents(clock, LOG_HANDLER); + var sut = new TasksSupplierImpl(LOG_HANDLER); var component = new DummyModbusComponent(); var protocol = component.getModbusProtocol(); protocol.addTasks(RT_H_1, RT_H_2, RT_L_1, RT_L_2, WT_1); - sut.addProtocol(component.id(), protocol); + sut.addProtocol(component.id(), protocol, FunctionUtils::doNothing); // 1st Cycle var tasks = sut.getCycleTasks(defectiveComponents); @@ -82,19 +84,19 @@ public void testFull() throws OpenemsException { assertEquals(4, tasks.reads().size() + tasks.writes().size()); // Finish - sut.removeProtocol(component.id()); + sut.removeProtocol(component.id(), FunctionUtils::doNothing); } @Test public void testHighOnly() throws OpenemsException { var clock = new TimeLeapClock(); - var defectiveComponents = new DefectiveComponents(clock); - var sut = new TasksSupplierImpl(); + var defectiveComponents = new DefectiveComponents(clock, LOG_HANDLER); + var sut = new TasksSupplierImpl(LOG_HANDLER); var component = new DummyModbusComponent(); var protocol = component.getModbusProtocol(); protocol.addTasks(RT_H_1, RT_H_2, WT_1); - sut.addProtocol(component.id(), protocol); + sut.addProtocol(component.id(), protocol, FunctionUtils::doNothing); var tasks = sut.getCycleTasks(defectiveComponents); assertEquals(3, tasks.reads().size() + tasks.writes().size()); diff --git a/io.openems.edge.common/src/io/openems/edge/common/meta/Meta.java b/io.openems.edge.common/src/io/openems/edge/common/meta/Meta.java index c10ee0d08f2..aa31e104d1f 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/meta/Meta.java +++ b/io.openems.edge.common/src/io/openems/edge/common/meta/Meta.java @@ -3,6 +3,7 @@ import io.openems.common.OpenemsConstants; import io.openems.common.channel.AccessMode; import io.openems.common.channel.PersistencePriority; +import io.openems.common.channel.Unit; import io.openems.common.oem.OpenemsEdgeOem; import io.openems.common.types.OpenemsType; import io.openems.edge.common.channel.Doc; @@ -12,6 +13,7 @@ import io.openems.edge.common.modbusslave.ModbusSlave; import io.openems.edge.common.modbusslave.ModbusSlaveNatureTable; import io.openems.edge.common.modbusslave.ModbusSlaveTable; +import io.openems.edge.common.modbusslave.ModbusType; public interface Meta extends ModbusSlave { @@ -29,7 +31,18 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ VERSION(Doc.of(OpenemsType.STRING) // .persistencePriority(PersistencePriority.HIGH)), - + /** + * System Time: seconds since 1st January 1970 00:00:00 UTC. + * + *

      + */ + SYSTEM_TIME_UTC(Doc.of(OpenemsType.LONG) // + .unit(Unit.SECONDS) // + .text("System Time: seconds since 1st January 1970 00:00:00 UTC") // + .persistencePriority(PersistencePriority.VERY_LOW)), /** * Edge currency. * @@ -73,6 +86,7 @@ public static ModbusSlaveTable getModbusSlaveTable(AccessMode accessMode, Openem .string16(51, "Manufacturer Version", oem.getManufacturerVersion()) // .string16(67, "Manufacturer Serial Number", oem.getManufacturerSerialNumber()) // .string16(83, "Manufacturer EMS Serial Number", oem.getManufacturerEmsSerialNumber()) // + .channel(99, ChannelId.SYSTEM_TIME_UTC, ModbusType.UINT64) // .build()); } diff --git a/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordChannel.java b/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordChannel.java index 670a58a3ebc..0a8f7239042 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordChannel.java +++ b/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordChannel.java @@ -41,6 +41,7 @@ public ModbusRecordChannel(int offset, ModbusType type, ChannelId channelId, Acc case STRING16 -> ModbusRecordString16.BYTE_LENGTH; case ENUM16, UINT16 -> ModbusRecordUint16.BYTE_LENGTH; case UINT32 -> ModbusRecordUint32.BYTE_LENGTH; + case UINT64 -> ModbusRecordUint64.BYTE_LENGTH; }; this.writeValueBuffer = new Byte[byteLength]; } @@ -140,6 +141,11 @@ public byte[] getValue(OpenemsComponent component) { case READ_ONLY, READ_WRITE -> ModbusRecordUint32.toByteArray(value); case WRITE_ONLY -> ModbusRecordUint32.UNDEFINED_VALUE; }; + case UINT64 -> // + switch (this.accessMode) { + case READ_ONLY, READ_WRITE -> ModbusRecordUint64.toByteArray(value); + case WRITE_ONLY -> ModbusRecordUint64.UNDEFINED_VALUE; + }; }; } @@ -190,6 +196,7 @@ public void writeValue(int index, byte byte1, byte byte2) { case STRING16 -> ""; // TODO implement String conversion case ENUM16, UINT16 -> buff.getShort(); case UINT32 -> buff.getInt(); + case UINT64 -> buff.getLong(); }; // Forward Value to ApiWorker diff --git a/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordConstant.java b/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordConstant.java index 7158dd50e88..9a5b376f6c3 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordConstant.java +++ b/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordConstant.java @@ -1,5 +1,8 @@ package io.openems.edge.common.modbusslave; +import java.util.function.Consumer; +import java.util.function.Function; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,4 +52,44 @@ public AccessMode getAccessMode() { return AccessMode.READ_ONLY; } + /** + * Generates a common toString() method for implementations of + * {@link ModbusRecordConstant}. + * + * @param the type of the value + * @param name the name of the implementation class + * @param callback a {@link StringBuilder} callback + * @param value the actual value + * @param toHexString the toHexString() method + * @return a {@link String} + */ + protected String generateToString(String name, Consumer callback, T value, + Function toHexString) { + var b = new StringBuilder() // + .append(name) // + .append(" ["); + if (callback != null) { + callback.accept(b); + } + b.append("value="); + if (value != null) { + b.append(value); + if (toHexString != null) { + b.append("/0x").append(toHexString.apply(value)); + } + } else { + b.append("UNDEFINED"); + } + return b.append(", type=").append(this.getType()) // + .append("]") // + .toString(); + } + + protected String generateToString(String name, T value, Function toHexString) { + return this.generateToString(name, null, value, toHexString); + } + + protected String generateToString(String name, T value) { + return this.generateToString(name, null, value, null); + } } diff --git a/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordCycleValue.java b/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordCycleValue.java index 11a846349de..47cfe30253d 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordCycleValue.java +++ b/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordCycleValue.java @@ -64,21 +64,14 @@ public void updateValue(T component) { @Override public byte[] getValue(OpenemsComponent component) { - switch (this.getType()) { - case FLOAT32: - return ModbusRecordFloat32.toByteArray(this.value); - case FLOAT64: - return ModbusRecordFloat64.toByteArray(this.value); - case STRING16: - return ModbusRecordString16.toByteArray(this.value); - case ENUM16: - case UINT16: - return ModbusRecordUint16.toByteArray(this.value); - case UINT32: - return ModbusRecordUint32.toByteArray(this.value); - } - assert true; - return new byte[0]; + return switch (this.getType()) { + case FLOAT32 -> ModbusRecordFloat32.toByteArray(this.value); + case FLOAT64 -> ModbusRecordFloat64.toByteArray(this.value); + case STRING16 -> ModbusRecordString16.toByteArray(this.value); + case ENUM16, UINT16 -> ModbusRecordUint16.toByteArray(this.value); + case UINT32 -> ModbusRecordUint32.toByteArray(this.value); + case UINT64 -> ModbusRecordUint64.toByteArray(this.value); + }; } @Override diff --git a/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordFloat32.java b/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordFloat32.java index 591bfbd7d9f..61cdce90776 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordFloat32.java +++ b/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordFloat32.java @@ -20,7 +20,7 @@ public ModbusRecordFloat32(int offset, String name, Float value) { @Override public String toString() { - return "ModbusRecordFloat32 [value=" + this.value + ", type=" + this.getType() + "]"; + return this.generateToString("ModbusRecordFloat32", this.value); } /** diff --git a/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordFloat64.java b/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordFloat64.java index 6cb32c747cf..34613a120c0 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordFloat64.java +++ b/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordFloat64.java @@ -21,7 +21,7 @@ public ModbusRecordFloat64(int offset, String name, Double value) { @Override public String toString() { - return "ModbusRecordFloat64 [value=" + this.value + ", type=" + this.getType() + "]"; + return this.generateToString("ModbusRecordFloat64", this.value); } /** diff --git a/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordString16.java b/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordString16.java index 532e9e07c28..f5cdfb6466b 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordString16.java +++ b/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordString16.java @@ -20,7 +20,7 @@ public ModbusRecordString16(int offset, String name, String value) { @Override public String toString() { - return "ModbusRecordString16 [value=" + this.value + ", type=" + this.getType() + "]"; + return this.generateToString("ModbusRecordString16", this.value); } /** @@ -30,6 +30,9 @@ public String toString() { * @return the byte array */ public static byte[] toByteArray(String value) { + if (value == null) { + return UNDEFINED_VALUE; + } var result = new byte[BYTE_LENGTH]; var converted = value.getBytes(StandardCharsets.US_ASCII); System.arraycopy(converted, 0, result, 0, Math.min(BYTE_LENGTH, converted.length)); diff --git a/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordUint16.java b/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordUint16.java index dc92046984c..3e2e751cde0 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordUint16.java +++ b/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordUint16.java @@ -20,8 +20,7 @@ public ModbusRecordUint16(int offset, String name, Short value) { @Override public String toString() { - return "ModbusRecordUInt16 [value=" + this.value + "/0x" + Integer.toHexString(this.value) + ", type=" - + this.getType() + "]"; + return generateToString("ModbusRecordUInt16", this.value, v -> Integer.toHexString(v)); } /** diff --git a/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordUint16BlockLength.java b/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordUint16BlockLength.java index 03fb4a11ecf..e66ceb2641e 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordUint16BlockLength.java +++ b/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordUint16BlockLength.java @@ -11,8 +11,9 @@ public ModbusRecordUint16BlockLength(int offset, String blockName, short length) @Override public String toString() { - return "ModbusRecordUint16BlockLength [blockName=" + this.blockName + ", value=" + this.value + "/0x" - + Integer.toHexString(this.value) + ", type=" + this.getType() + "]"; + return generateToString("ModbusRecordUint16BlockLength", + b -> b.append("blockName=").append(this.blockName).append(", "), this.value, + v -> Integer.toHexString(v)); } } diff --git a/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordUint16Hash.java b/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordUint16Hash.java index 14780d4fc35..e1e093c1280 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordUint16Hash.java +++ b/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordUint16Hash.java @@ -11,8 +11,8 @@ public ModbusRecordUint16Hash(int offset, String text) { @Override public String toString() { - return "ModbusRecordUint16Hash [text=" + this.text + ", value=" + this.value + "/0x" - + Integer.toHexString(this.value) + ", type=" + this.getType() + "]"; + return generateToString("ModbusRecordUint16Hash", b -> b.append("text=").append(this.text).append(", "), + this.value, v -> Integer.toHexString(v & 0xffff)); } @Override diff --git a/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordUint32.java b/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordUint32.java index 0e0a9b05e4a..23bae440c32 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordUint32.java +++ b/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordUint32.java @@ -20,8 +20,7 @@ public ModbusRecordUint32(int offset, String name, Integer value) { @Override public String toString() { - return "ModbusRecordUInt32 [value=" + this.value + "/0x" + Integer.toHexString(this.value) + ", type=" - + this.getType() + "]"; + return generateToString("ModbusRecordUInt32", this.value, Integer::toHexString); } /** diff --git a/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordUint64.java b/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordUint64.java new file mode 100644 index 00000000000..87ccc8e779d --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordUint64.java @@ -0,0 +1,59 @@ +package io.openems.edge.common.modbusslave; + +import java.nio.ByteBuffer; + +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.type.TypeUtils; + +public class ModbusRecordUint64 extends ModbusRecordConstant { + + public static final byte[] UNDEFINED_VALUE = { // + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, // + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF }; + + public static final int BYTE_LENGTH = 8; + + protected final Long value; + + public ModbusRecordUint64(int offset, String name, Long value) { + super(offset, name, ModbusType.UINT64, toByteArray(value)); + this.value = value; + } + + @Override + public String toString() { + return this.generateToString("ModbusRecordUInt64", this.value, Long::toHexString); + } + + /** + * Convert to byte array. + * + * @param value the value + * @return the byte array + */ + public static byte[] toByteArray(long value) { + return ByteBuffer.allocate(BYTE_LENGTH).putLong(value).array(); + } + + /** + * Convert to byte array. + * + * @param value the value + * @return the byte array + */ + public static byte[] toByteArray(Object value) { + if (value == null || value instanceof io.openems.common.types.OptionsEnum + && ((io.openems.common.types.OptionsEnum) value).isUndefined()) { + return UNDEFINED_VALUE; + } + return toByteArray((long) TypeUtils.getAsType(OpenemsType.LONG, value)); + } + + @Override + public String getValueDescription() { + return this.value != null // + ? "\"" + Long.toString(this.value) + "\"" // + : ""; + } + +} diff --git a/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordUint64Reserved.java b/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordUint64Reserved.java new file mode 100644 index 00000000000..d6018217403 --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusRecordUint64Reserved.java @@ -0,0 +1,14 @@ +package io.openems.edge.common.modbusslave; + +public class ModbusRecordUint64Reserved extends ModbusRecordUint64 { + + public ModbusRecordUint64Reserved(int offset) { + super(offset, "Reserved", null); + } + + @Override + public String toString() { + return "ModbusRecordUint64Reserved [type=" + this.getType() + "]"; + } + +} diff --git a/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusSlaveNatureTable.java b/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusSlaveNatureTable.java index da1d57c03af..f358ad8511b 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusSlaveNatureTable.java +++ b/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusSlaveNatureTable.java @@ -63,22 +63,12 @@ public Builder channel(int offset, ChannelId channelId, ModbusType type) { } else { // Channel did not pass filter -> show as Reserved switch (type) { - case FLOAT32: - this.float32Reserved(offset); - break; - case FLOAT64: - this.float64Reserved(offset); - break; - case STRING16: - this.string16Reserved(offset); - break; - case ENUM16: - case UINT16: - this.uint16Reserved(offset); - break; - case UINT32: - this.uint32Reserved(offset); - break; + case FLOAT32 -> this.float32Reserved(offset); + case FLOAT64 -> this.float64Reserved(offset); + case STRING16 -> this.string16Reserved(offset); + case ENUM16, UINT16 -> this.uint16Reserved(offset); + case UINT32 -> this.uint32Reserved(offset); + case UINT64 -> this.uint64Reserved(offset); } } return this; @@ -158,6 +148,18 @@ public Builder uint32Reserved(int offset) { return this; } + /** + * Add a Unsigned Int 64 Reserved value to the {@link ModbusSlaveNatureTable} + * {@link Builder}. + * + * @param offset the address offset + * @return myself + */ + public Builder uint64Reserved(int offset) { + this.add(new ModbusRecordUint64Reserved(offset)); + return this; + } + /** * Add a Float 32 value to the {@link ModbusSlaveNatureTable} {@link Builder}. * diff --git a/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusType.java b/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusType.java index 5da35991871..df071d14fdc 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusType.java +++ b/io.openems.edge.common/src/io/openems/edge/common/modbusslave/ModbusType.java @@ -4,6 +4,7 @@ public enum ModbusType { ENUM16(1, "enum16"), // UINT16(1, "uint16"), // UINT32(2, "uint32"), // + UINT64(4, "uint64"), // FLOAT32(2, "float32"), // FLOAT64(4, "float64"), // STRING16(16, "string16"); diff --git a/io.openems.edge.common/src/io/openems/edge/common/sum/Sum.java b/io.openems.edge.common/src/io/openems/edge/common/sum/Sum.java index c6a903df67c..b065cb50c18 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/sum/Sum.java +++ b/io.openems.edge.common/src/io/openems/edge/common/sum/Sum.java @@ -629,6 +629,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { CONSUMPTION_ACTIVE_ENERGY(Doc.of(OpenemsType.LONG) // .unit(Unit.CUMULATED_WATT_HOURS) // .persistencePriority(PersistencePriority.VERY_HIGH)), // + /** * Is there any Component Info/Warning/Fault that is getting ignored/hidden * because of the 'ignoreStateComponents' configuration setting?. @@ -716,6 +717,7 @@ public static ModbusSlaveNatureTable getModbusSlaveNatureTable(AccessMode access .channel(113, ChannelId.ESS_DISCHARGE_POWER, ModbusType.FLOAT32) // .channel(115, ChannelId.GRID_MODE, ModbusType.ENUM16) // .channel(116, ChannelId.GRID_MODE_OFF_GRID_TIME, ModbusType.FLOAT32) // + .channel(118, ChannelId.ESS_CAPACITY, ModbusType.FLOAT32) // .build(); } diff --git a/io.openems.edge.common/test/io/openems/edge/common/modbusslave/ModbusRecordFloat32Test.java b/io.openems.edge.common/test/io/openems/edge/common/modbusslave/ModbusRecordFloat32Test.java new file mode 100644 index 00000000000..197fbff8dcf --- /dev/null +++ b/io.openems.edge.common/test/io/openems/edge/common/modbusslave/ModbusRecordFloat32Test.java @@ -0,0 +1,30 @@ +package io.openems.edge.common.modbusslave; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class ModbusRecordFloat32Test { + + @Test + public void testValue() { + var sut = new ModbusRecordFloat32(0, "foo", 1234567.89F); + assertEquals("ModbusRecordFloat32 [value=1234567.9, type=float32]", sut.toString()); + assertEquals("\"1234567.9\"", sut.getValueDescription()); + } + + @Test + public void testNull() { + var sut = new ModbusRecordFloat32(0, "bar", null); + assertEquals("ModbusRecordFloat32 [value=UNDEFINED, type=float32]", sut.toString()); + assertEquals("", sut.getValueDescription()); + } + + @Test + public void testReserved() { + var sut = new ModbusRecordFloat32Reserved(0); + assertEquals("ModbusRecordFloat32Reserved [type=float32]", sut.toString()); + assertEquals("", sut.getValueDescription()); + } + +} diff --git a/io.openems.edge.common/test/io/openems/edge/common/modbusslave/ModbusRecordFloat64Test.java b/io.openems.edge.common/test/io/openems/edge/common/modbusslave/ModbusRecordFloat64Test.java new file mode 100644 index 00000000000..70a21900022 --- /dev/null +++ b/io.openems.edge.common/test/io/openems/edge/common/modbusslave/ModbusRecordFloat64Test.java @@ -0,0 +1,30 @@ +package io.openems.edge.common.modbusslave; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class ModbusRecordFloat64Test { + + @Test + public void testValue() { + var sut = new ModbusRecordFloat64(0, "foo", 1234567.89); + assertEquals("ModbusRecordFloat64 [value=1234567.89, type=float64]", sut.toString()); + assertEquals("\"1234567.89\"", sut.getValueDescription()); + } + + @Test + public void testNull() { + var sut = new ModbusRecordFloat64(0, "bar", null); + assertEquals("ModbusRecordFloat64 [value=UNDEFINED, type=float64]", sut.toString()); + assertEquals("", sut.getValueDescription()); + } + + @Test + public void testReserved() { + var sut = new ModbusRecordFloat64Reserved(0); + assertEquals("ModbusRecordFloat64Reserved [type=float64]", sut.toString()); + assertEquals("", sut.getValueDescription()); + } + +} diff --git a/io.openems.edge.common/test/io/openems/edge/common/modbusslave/ModbusRecordString16Test.java b/io.openems.edge.common/test/io/openems/edge/common/modbusslave/ModbusRecordString16Test.java new file mode 100644 index 00000000000..d6bea0edd02 --- /dev/null +++ b/io.openems.edge.common/test/io/openems/edge/common/modbusslave/ModbusRecordString16Test.java @@ -0,0 +1,42 @@ +package io.openems.edge.common.modbusslave; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; + +import org.junit.Test; + +public class ModbusRecordString16Test { + + @Test + public void testValue() { + var sut = new ModbusRecordString16(0, "foo", "bar"); + assertEquals("ModbusRecordString16 [value=bar, type=string16]", sut.toString()); + assertEquals("\"bar\"", sut.getValueDescription()); + } + + @Test + public void testNull() { + var sut = new ModbusRecordString16(0, "bar", null); + assertEquals("ModbusRecordString16 [value=UNDEFINED, type=string16]", sut.toString()); + assertEquals("", sut.getValueDescription()); + } + + @Test + public void testReserved() { + var sut = new ModbusRecordString16Reserved(0); + assertEquals("ModbusRecordString16Reserved [type=string16]", sut.toString()); + assertEquals("", sut.getValueDescription()); + } + + @Test + public void testToByteArray() { + assertEquals("[72, 101, 108, 108, 111, "// + + "32, " // + + "87, 111, 114, 108, 100, " // + + "0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", + Arrays.toString(ModbusRecordString16.toByteArray((Object) "Hello World"))); + assertEquals("[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", + Arrays.toString(ModbusRecordString16.toByteArray((Object) null))); + } +} diff --git a/io.openems.edge.common/test/io/openems/edge/common/modbusslave/ModbusRecordUint16Test.java b/io.openems.edge.common/test/io/openems/edge/common/modbusslave/ModbusRecordUint16Test.java new file mode 100644 index 00000000000..7752f124cd2 --- /dev/null +++ b/io.openems.edge.common/test/io/openems/edge/common/modbusslave/ModbusRecordUint16Test.java @@ -0,0 +1,52 @@ +package io.openems.edge.common.modbusslave; + +import static io.openems.common.test.DummyOptionsEnum.UNDEFINED; +import static io.openems.common.test.DummyOptionsEnum.VALUE_1; +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; + +import org.junit.Test; + +public class ModbusRecordUint16Test { + + @Test + public void testValue() { + var sut = new ModbusRecordUint16(0, "foo", (short) 12345); + assertEquals("ModbusRecordUInt16 [value=12345/0x3039, type=uint16]", sut.toString()); + assertEquals("\"12345\"", sut.getValueDescription()); + } + + @Test + public void testNull() { + var sut = new ModbusRecordUint16(0, "bar", null); + assertEquals("ModbusRecordUInt16 [value=UNDEFINED, type=uint16]", sut.toString()); + assertEquals("", sut.getValueDescription()); + } + + @Test + public void testOptionsEnum() { + assertEquals("[-1, -1]", Arrays.toString(ModbusRecordUint16.toByteArray(UNDEFINED))); + assertEquals("[0, 1]", Arrays.toString(ModbusRecordUint16.toByteArray(VALUE_1))); + } + + @Test + public void testReserved() { + var sut = new ModbusRecordUint16Reserved(0); + assertEquals("ModbusRecordUint16Reserved [type=uint16]", sut.toString()); + assertEquals("", sut.getValueDescription()); + } + + @Test + public void testBlockLength() { + assertEquals("ModbusRecordUint16BlockLength [blockName=block, value=12345/0x3039, type=uint16]", + new ModbusRecordUint16BlockLength(0, "block", (short) 12345).toString()); + } + + @Test + public void testHash() { + var sut = new ModbusRecordUint16Hash(0, "hash"); + assertEquals("ModbusRecordUint16Hash [text=hash, value=-16114/0xc10e, type=uint16]", sut.toString()); + assertEquals("\"0xc10e\"", sut.getValueDescription()); + } +} diff --git a/io.openems.edge.common/test/io/openems/edge/common/modbusslave/ModbusRecordUint32Test.java b/io.openems.edge.common/test/io/openems/edge/common/modbusslave/ModbusRecordUint32Test.java new file mode 100644 index 00000000000..0f5504bf857 --- /dev/null +++ b/io.openems.edge.common/test/io/openems/edge/common/modbusslave/ModbusRecordUint32Test.java @@ -0,0 +1,40 @@ +package io.openems.edge.common.modbusslave; + +import static io.openems.common.test.DummyOptionsEnum.UNDEFINED; +import static io.openems.common.test.DummyOptionsEnum.VALUE_1; +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; + +import org.junit.Test; + +public class ModbusRecordUint32Test { + + @Test + public void testValue() { + var sut = new ModbusRecordUint32(0, "foo", 123456789); + assertEquals("ModbusRecordUInt32 [value=123456789/0x75bcd15, type=uint32]", sut.toString()); + assertEquals("\"123456789\"", sut.getValueDescription()); + } + + @Test + public void testNull() { + var sut = new ModbusRecordUint32(0, "bar", null); + assertEquals("ModbusRecordUInt32 [value=UNDEFINED, type=uint32]", sut.toString()); + assertEquals("", sut.getValueDescription()); + } + + @Test + public void testOptionsEnum() { + assertEquals("[-1, -1, -1, -1]", Arrays.toString(ModbusRecordUint32.toByteArray(UNDEFINED))); + assertEquals("[0, 0, 0, 1]", Arrays.toString(ModbusRecordUint32.toByteArray(VALUE_1))); + } + + @Test + public void testReserved() { + var sut = new ModbusRecordUint32Reserved(0); + assertEquals("ModbusRecordUint32Reserved [type=uint32]", sut.toString()); + assertEquals("", sut.getValueDescription()); + } + +} diff --git a/io.openems.edge.common/test/io/openems/edge/common/modbusslave/ModbusRecordUint64Test.java b/io.openems.edge.common/test/io/openems/edge/common/modbusslave/ModbusRecordUint64Test.java new file mode 100644 index 00000000000..903a5139236 --- /dev/null +++ b/io.openems.edge.common/test/io/openems/edge/common/modbusslave/ModbusRecordUint64Test.java @@ -0,0 +1,40 @@ +package io.openems.edge.common.modbusslave; + +import static io.openems.common.test.DummyOptionsEnum.UNDEFINED; +import static io.openems.common.test.DummyOptionsEnum.VALUE_1; +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; + +import org.junit.Test; + +public class ModbusRecordUint64Test { + + @Test + public void testValue() { + var sut = new ModbusRecordUint64(0, "foo", 123456789L); + assertEquals("ModbusRecordUInt64 [value=123456789/0x75bcd15, type=uint64]", sut.toString()); + assertEquals("\"123456789\"", sut.getValueDescription()); + } + + @Test + public void testNull() { + var sut = new ModbusRecordUint64(0, "bar", null); + assertEquals("ModbusRecordUInt64 [value=UNDEFINED, type=uint64]", sut.toString()); + assertEquals("", sut.getValueDescription()); + } + + @Test + public void testOptionsEnum() { + assertEquals("[-1, -1, -1, -1, -1, -1, -1, -1]", Arrays.toString(ModbusRecordUint64.toByteArray(UNDEFINED))); + assertEquals("[0, 0, 0, 0, 0, 0, 0, 1]", Arrays.toString(ModbusRecordUint64.toByteArray(VALUE_1))); + } + + @Test + public void testReserved() { + var sut = new ModbusRecordUint64Reserved(0); + assertEquals("ModbusRecordUint64Reserved [type=uint64]", sut.toString()); + assertEquals("", sut.getValueDescription()); + } + +} diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/WebsocketClient.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/WebsocketClient.java index aeb2e73a5ba..10b7a380eab 100644 --- a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/WebsocketClient.java +++ b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/WebsocketClient.java @@ -13,6 +13,7 @@ import io.openems.common.websocket.AbstractWebsocketClient; import io.openems.common.websocket.OnClose; +import io.openems.common.websocket.WsData; public class WebsocketClient extends AbstractWebsocketClient { diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/WsData.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/WsData.java deleted file mode 100644 index 2dfdd355c5b..00000000000 --- a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/WsData.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.openems.edge.controller.api.backend; - -import org.java_websocket.WebSocket; - -public class WsData extends io.openems.common.websocket.WsData { - - public WsData(WebSocket ws) { - super(ws); - } - - @Override - public String toString() { - return "BackendApi.WsData []"; - } - -} diff --git a/io.openems.edge.controller.api.modbus/bnd.bnd b/io.openems.edge.controller.api.modbus/bnd.bnd index 420b544a143..87fd5d5a4a8 100644 --- a/io.openems.edge.controller.api.modbus/bnd.bnd +++ b/io.openems.edge.controller.api.modbus/bnd.bnd @@ -10,6 +10,7 @@ Bundle-Version: 1.0.0.${tstamp} io.openems.edge.common,\ io.openems.edge.controller.api,\ io.openems.edge.controller.api.common,\ + io.openems.edge.ess.api,\ io.openems.edge.timedata.api,\ io.openems.wrapper.fastexcel diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusTcpApi.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusTcpApi.java index 52e5f67deae..435021672eb 100644 --- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusTcpApi.java +++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusTcpApi.java @@ -529,6 +529,6 @@ public boolean equals(Object other) { * @return component_channelId as String */ public static String formatChannelName(WriteChannel channel) { - return channel.getComponent().alias() + "_" + channel.channelId().name(); + return channel.getComponent().id() + "_" + channel.channelId().name(); } } diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/jsonrpc/GetModbusProtocolExportXlsxResponse.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/jsonrpc/GetModbusProtocolExportXlsxResponse.java index 21f2447965c..b86d0a983bd 100644 --- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/jsonrpc/GetModbusProtocolExportXlsxResponse.java +++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/jsonrpc/GetModbusProtocolExportXlsxResponse.java @@ -19,6 +19,7 @@ import io.openems.edge.common.modbusslave.ModbusRecordString16; import io.openems.edge.common.modbusslave.ModbusRecordUint16; import io.openems.edge.common.modbusslave.ModbusRecordUint32; +import io.openems.edge.common.modbusslave.ModbusRecordUint64; import io.openems.edge.common.modbusslave.ModbusType; /** @@ -148,25 +149,14 @@ private static void addUndefinedSheet(Workbook wb) { var nextRow = 2; for (ModbusType modbusType : ModbusType.values()) { - byte[] value = {}; - switch (modbusType) { - case FLOAT32: - value = ModbusRecordFloat32.UNDEFINED_VALUE; - break; - case FLOAT64: - value = ModbusRecordFloat64.UNDEFINED_VALUE; - break; - case STRING16: - value = ModbusRecordString16.UNDEFINED_VALUE; - break; - case ENUM16: - case UINT16: - value = ModbusRecordUint16.UNDEFINED_VALUE; - break; - case UINT32: - value = ModbusRecordUint32.UNDEFINED_VALUE; - break; - } + byte[] value = switch (modbusType) { + case FLOAT32 -> ModbusRecordFloat32.UNDEFINED_VALUE; + case FLOAT64 -> ModbusRecordFloat64.UNDEFINED_VALUE; + case STRING16 -> ModbusRecordString16.UNDEFINED_VALUE; + case ENUM16, UINT16 -> ModbusRecordUint16.UNDEFINED_VALUE; + case UINT32 -> ModbusRecordUint32.UNDEFINED_VALUE; + case UINT64 -> ModbusRecordUint64.UNDEFINED_VALUE; + }; nextRow++; ws.value(nextRow, 0, modbusType.toString()); ws.value(nextRow, 1, byteArrayToString(value)); diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImpl.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImpl.java index 74055d005b1..6f1a47ad49c 100644 --- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImpl.java +++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImpl.java @@ -1,5 +1,8 @@ package io.openems.edge.controller.api.modbus.readwrite; +import static io.openems.edge.common.channel.ChannelId.channelIdCamelToUpper; +import static io.openems.edge.common.channel.ChannelId.channelIdUpperToCamel; + import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; @@ -27,20 +30,26 @@ import io.openems.common.channel.AccessMode; import io.openems.common.channel.PersistencePriority; +import io.openems.common.channel.Unit; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; -import io.openems.common.types.OpenemsType; import io.openems.edge.common.channel.ChannelId.ChannelIdImpl; import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.channel.IntegerReadChannel; import io.openems.edge.common.channel.WriteChannel; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.jsonapi.ComponentJsonApi; import io.openems.edge.common.meta.Meta; +import io.openems.edge.common.modbusslave.ModbusSlave; +import io.openems.edge.common.modbusslave.ModbusSlaveNatureTable; +import io.openems.edge.common.modbusslave.ModbusSlaveTable; +import io.openems.edge.common.modbusslave.ModbusType; import io.openems.edge.controller.api.Controller; import io.openems.edge.controller.api.common.Status; import io.openems.edge.controller.api.common.WriteObject; import io.openems.edge.controller.api.modbus.AbstractModbusTcpApi; import io.openems.edge.controller.api.modbus.ModbusTcpApi; +import io.openems.edge.ess.api.ManagedSymmetricEss; import io.openems.edge.timedata.api.Timedata; import io.openems.edge.timedata.api.TimedataProvider; import io.openems.edge.timedata.api.utils.CalculateActiveTime; @@ -52,20 +61,23 @@ configurationPolicy = ConfigurationPolicy.REQUIRE // ) public class ControllerApiModbusTcpReadWriteImpl extends AbstractModbusTcpApi - implements ControllerApiModbusTcpReadWrite, ModbusTcpApi, Controller, OpenemsComponent, ComponentJsonApi, TimedataProvider { + implements ControllerApiModbusTcpReadWrite, ModbusTcpApi, Controller, OpenemsComponent, ComponentJsonApi, + TimedataProvider, ModbusSlave { private final Logger log = LoggerFactory.getLogger(ControllerApiModbusTcpReadWriteImpl.class); - + private final CalculateActiveTime calculateCumulatedActiveTime = new CalculateActiveTime(this, ControllerApiModbusTcpReadWrite.ChannelId.CUMULATED_ACTIVE_TIME); - + private final CalculateActiveTime calculateCumulatedInactiveTime = new CalculateActiveTime(this, ControllerApiModbusTcpReadWrite.ChannelId.CUMULATED_INACTIVE_TIME); - + private List writeChannels; - + + private List components = new ArrayList<>(); + private boolean isActive = false; - + @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) private volatile Timedata timedata = null; @@ -83,10 +95,12 @@ public class ControllerApiModbusTcpReadWriteImpl extends AbstractModbusTcpApi ) protected void addComponent(OpenemsComponent component) { super.addComponent(component); + this.components.add(component); } protected void removeComponent(OpenemsComponent component) { super.removeComponent(component); + this.components.remove(component); } public ControllerApiModbusTcpReadWriteImpl() { @@ -105,7 +119,6 @@ private void activate(ComponentContext context, Config config) throws ModbusExce new ConfigRecord(config.id(), config.alias(), config.enabled(), this.metaComponent, config.component_ids(), config.apiTimeout(), config.port(), config.maxConcurrentConnections())); this.applyConfig(config); - this.handleTimeDataChannels(); } @Modified @@ -114,7 +127,6 @@ private void modified(ComponentContext context, Config config) throws OpenemsNam new ConfigRecord(config.id(), config.alias(), config.enabled(), this.metaComponent, config.component_ids(), config.apiTimeout(), config.port(), config.maxConcurrentConnections())); this.applyConfig(config); - this.handleTimeDataChannels(); } private void applyConfig(Config config) { @@ -126,12 +138,12 @@ private void applyConfig(Config config) { protected void deactivate() { super.deactivate(); } - + @Override public void run() throws OpenemsNamedException { this.isActive = false; super.run(); - + this.calculateCumulatedActiveTime.update(this.isActive); this.calculateCumulatedInactiveTime.update(!this.isActive); } @@ -166,7 +178,17 @@ private void configUpdate(String targetProperty, String requiredValue) { this.logError(this.log, "ERROR: " + e.getMessage()); } } - + + protected static String getChannelNameUpper(String componentId, + io.openems.edge.common.channel.ChannelId channelId) { + return channelIdCamelToUpper(componentId) + "_" + channelId.name(); + } + + protected static String getChannelNameCamel(String componentId, + io.openems.edge.common.channel.ChannelId channelId) { + return channelIdUpperToCamel(getChannelNameUpper(componentId, channelId)); + } + @Override protected Consumer, WriteObject>> handleWrites() { return entry -> { @@ -174,15 +196,19 @@ protected Consumer, WriteObject>> handleWrites() { WriteChannel channel = entry.getKey(); var writeObject = entry.getValue(); - String channelName = formatChannelName(channel); - var currentChannel = new ChannelIdImpl(channelName, - Doc.of(channel.getType()).persistencePriority(PersistencePriority.HIGH)); - if (!channels().stream().anyMatch(p -> p.channelId().name().equals(currentChannel.name()))) { - addChannel(currentChannel).setNextValue(writeObject.value()); - } else { - channel(currentChannel).setNextValue(writeObject.value()); + var channelNameCamel = getChannelNameCamel(channel.getComponent().id(), channel.channelId()); + + @SuppressWarnings("deprecation") + var logChannel = this._channel(channelNameCamel); + if (logChannel == null) { + var channelNameUpper = getChannelNameUpper(channel.getComponent().id(), channel.channelId()); + var currentChannel = new ChannelIdImpl(channelNameUpper, + Doc.of(channel.getType()).persistencePriority(PersistencePriority.HIGH)); + addChannel(currentChannel); + logChannel = channel(currentChannel); } - this.configUpdate("writeChannels", channel(currentChannel).channelId().id()); + logChannel.setNextValue(writeObject.value()); + this.configUpdate("writeChannels", logChannel.channelId().id()); }; } @@ -205,23 +231,28 @@ protected Runnable handleTimeouts() { public Timedata getTimedata() { return this.timedata; } - - /** - * Checks, if timedata channels are already set. - * If not, they will be created and added to current channels. - */ - protected void handleTimeDataChannels() { - var activeTimeChannel = new ChannelIdImpl("CUMULATED_ACTIVE_TIME", // - Doc.of(OpenemsType.DOUBLE).persistencePriority(PersistencePriority.HIGH)); - var inactiveTimeChannel = new ChannelIdImpl("CUMULATED_INACTIVE_TIME", // - Doc.of(OpenemsType.DOUBLE).persistencePriority(PersistencePriority.HIGH)); - - List timeChannels = Arrays.asList(activeTimeChannel, inactiveTimeChannel); - timeChannels.forEach(channel -> { - if (channels().stream().noneMatch(ch -> ch.channelId().id().equals(channel.id()))) { - addChannel(channel); - } - }); + + protected Integer getChannelValue(String componentId, io.openems.edge.common.channel.ChannelId channelId) { + @SuppressWarnings("deprecation") + var channel = this._channel(getChannelNameCamel(componentId, channelId)); + if (channel == null) { + return null; + } + return ((IntegerReadChannel) channel).value().get(); + } + + @Override + public ModbusSlaveTable getModbusSlaveTable(AccessMode accessMode) { + return new ModbusSlaveTable(// + OpenemsComponent.getModbusSlaveNatureTable(AccessMode.READ_ONLY), + ModbusSlaveNatureTable.of(ControllerApiModbusTcpReadWriteImpl.class, AccessMode.READ_ONLY, 300) + .cycleValue(0, this.id() + "/ Ess0ActivePowerLimit", Unit.WATT, "", ModbusType.FLOAT32, + t -> this.getChannelValue("ess0", + ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_EQUALS)) + .cycleValue(2, this.id() + "/Ess0ReactivePowerLimit", Unit.WATT, "", ModbusType.FLOAT32, + t -> this.getChannelValue("ess0", + ManagedSymmetricEss.ChannelId.SET_REACTIVE_POWER_EQUALS)) + .build()); } } diff --git a/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImplTest.java b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImplTest.java index 58ea9ca90c5..e3b97b5cb79 100644 --- a/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImplTest.java +++ b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImplTest.java @@ -1,13 +1,19 @@ package io.openems.edge.controller.api.modbus.readwrite; +import static io.openems.edge.controller.api.modbus.readwrite.ControllerApiModbusTcpReadWriteImpl.getChannelNameCamel; +import static io.openems.edge.controller.api.modbus.readwrite.ControllerApiModbusTcpReadWriteImpl.getChannelNameUpper; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; + import org.junit.Test; + import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyConfigurationAdmin; import io.openems.edge.common.test.DummyCycle; import io.openems.edge.controller.api.modbus.AbstractModbusTcpApi; import io.openems.edge.controller.test.ControllerTest; +import io.openems.edge.ess.api.ManagedSymmetricEss; public class ControllerApiModbusTcpReadWriteImplTest { @@ -28,16 +34,16 @@ public void test() throws Exception { .next(new TestCase()) // ; } - + @Test public void testTimedataChannels() throws Exception { var controller = new ControllerApiModbusTcpReadWriteImpl(); // boolean channelNotFound = controller.channels().stream().noneMatch(// ch -> ch.channelId().id().equals("CumulatedActiveTime") // - || ch.channelId().id().equals("CumulatedInactiveTime")); // - assertFalse(channelNotFound); + || ch.channelId().id().equals("CumulatedInactiveTime")); // + assertFalse(channelNotFound); } - + @Test public void testAddFalseComponents() throws Exception { var controller = new ControllerApiModbusTcpReadWriteImpl(); // @@ -45,4 +51,20 @@ public void testAddFalseComponents() throws Exception { controller.getComponentNoModbusApiFaultChannel().nextProcessImage(); // assertTrue(controller.getComponentNoModbusApiFault().get()); // } + + @Test + public void testGetChannelNameUpper() { + assertEquals("ESS0_SET_ACTIVE_POWER_EQUALS", + getChannelNameUpper("ess0", ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_EQUALS)); + assertEquals("ESS0_SET_ACTIVE_POWER_EQUALS", + getChannelNameUpper("Ess0", ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_EQUALS)); + } + + @Test + public void testGetChannelNameCamel() { + assertEquals("Ess0SetActivePowerEquals", + getChannelNameCamel("ess0", ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_EQUALS)); + assertEquals("Ess0SetActivePowerEquals", + getChannelNameCamel("Ess0", ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_EQUALS)); + } } diff --git a/io.openems.edge.controller.api.mqtt/bnd.bnd b/io.openems.edge.controller.api.mqtt/bnd.bnd index ae32a25bd42..816ceaf6133 100644 --- a/io.openems.edge.controller.api.mqtt/bnd.bnd +++ b/io.openems.edge.controller.api.mqtt/bnd.bnd @@ -5,8 +5,8 @@ Bundle-Version: 1.0.0.${tstamp} -buildpath: \ ${buildpath},\ - bcpkix;version='1.70',\ - bcprov;version='1.70',\ + bcpkix;version='1.77',\ + bcprov;version='1.77',\ io.openems.common,\ io.openems.edge.common,\ io.openems.edge.controller.api,\ diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WsData.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WsData.java index a92eca5bba8..d70d2299659 100644 --- a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WsData.java +++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WsData.java @@ -142,14 +142,15 @@ public Optional getUser() { } @Override - public String toString() { - String tokenString; - if (this.sessionToken != null) { - tokenString = this.sessionToken.toString(); - } else { - tokenString = "UNKNOWN"; - } - return "WebsocketApi.WsData [sessionToken=" + tokenString + ", user=" + this.user + "]"; + public String toLogString() { + return new StringBuilder("WebsocketApi.WsData [sessionToken=") // + .append(this.sessionToken != null // + ? this.sessionToken.toString() // + : "UNKNOWN") // + .append(", user=") // + .append(this.user) // + .append("]") // + .toString(); } /** diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/.classpath b/io.openems.edge.controller.ess.fastfrequencyreserve/.classpath new file mode 100644 index 00000000000..bbfbdbe40e7 --- /dev/null +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/.classpath @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/.gitignore b/io.openems.edge.controller.ess.fastfrequencyreserve/.gitignore new file mode 100644 index 00000000000..c2b941a96de --- /dev/null +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/.gitignore @@ -0,0 +1,2 @@ +/bin_test/ +/generated/ diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/.project b/io.openems.edge.controller.ess.fastfrequencyreserve/.project new file mode 100644 index 00000000000..0140daa493d --- /dev/null +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/.project @@ -0,0 +1,23 @@ + + + io.openems.edge.controller.ess.fastfrequencyreserve + + + + + + org.eclipse.jdt.core.javabuilder + + + + + bndtools.core.bndbuilder + + + + + + org.eclipse.jdt.core.javanature + bndtools.core.bndnature + + diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/.settings/org.eclipse.core.resources.prefs b/io.openems.edge.controller.ess.fastfrequencyreserve/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 00000000000..896a9a53a53 --- /dev/null +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 \ No newline at end of file diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/bnd.bnd b/io.openems.edge.controller.ess.fastfrequencyreserve/bnd.bnd new file mode 100644 index 00000000000..bee07090a70 --- /dev/null +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/bnd.bnd @@ -0,0 +1,16 @@ +Bundle-Name: OpenEMS Edge Controller Fast Frequency Reserve +Bundle-Vendor: FENECON GmbH +Bundle-License: https://opensource.org/licenses/EPL-2.0 +Bundle-Version: 1.0.0.${tstamp} + +-buildpath: \ + ${buildpath},\ + Java-WebSocket,\ + io.openems.common,\ + io.openems.edge.common,\ + io.openems.edge.controller.api,\ + io.openems.edge.ess.api,\ + io.openems.edge.meter.api,\ + +-testpath: \ + ${testpath} \ No newline at end of file diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/doc/statemachine.md b/io.openems.edge.controller.ess.fastfrequencyreserve/doc/statemachine.md new file mode 100644 index 00000000000..23c71c2221a --- /dev/null +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/doc/statemachine.md @@ -0,0 +1,18 @@ +# State-Machine + +```mermaid +graph TD +start --> Undefined +Undefined --> |condition: Inside set time, task : Charge to maintain soc| PreActivateState +PreActivateState --> |condition: Outside set time, task : do nothing| Undefined +PreActivateState --> |condition: grid freq > freqlimit, task : setpower 0Watt| ActivationTime +ActivationTime --> |condition: 1.7 sec, task : discharge setActivepower| SupportDuration +SupportDuration --> |condition: 30 sec, task : discharge setActivepower| DeactivationTime +DeactivationTime -->|condition: 1.7 sec, task : setpower 0Watt| BufferedTime +BufferedTime --> |condition: 10 sec, task : setpower for 0Watt| BufferedSupportTime +BufferedSupportTime --> |condition: 15 min, Charge to maintain soc| RecoveryTime +RecoveryTime --> PreActivateState +RecoveryTime -->|condition: Outside set time, task : do nothing| Undefined +``` + +View using Mermaid, e.g. https://mermaid-js.github.io/mermaid-live-editor \ No newline at end of file diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/readme.adoc b/io.openems.edge.controller.ess.fastfrequencyreserve/readme.adoc new file mode 100644 index 00000000000..028257dcea9 --- /dev/null +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/readme.adoc @@ -0,0 +1,333 @@ += ESS Fast Frequency Reserve + +== 1.1 Introduction + +In electricity networks, the Fast Frequency Reserve (FFR) controller is providing power available to the system operator within a short interval to meet demand in case of a frequency drop, i.e. in case a generator goes down or there is another disruption to the supply. More details on link:https://en.wikipedia.org/wiki/Operating_reserve[Wikipedia]. + +This controller helps the Energy Storage System (ESS) to provide power, essentially battery discharge, when the measured "Grid frequency" is lower than that of a defined "Frequency limit". + +== 1.2 Controller Parameters + +- **mode**: mode of the controller, On or Off? +- **id**: the id for the controller +- **alias**: Alias for the controller +- **enabled**: enabled or not? +- **meterId**: the id of the meter +- **essId**: the id of the Ess +- **batteryInverterId**: the id of the battery inverter +- **preActivationTime**: A time before the activation time for charging the system(min). +- **schedule**: scheduling of the controller, via JSON see below for the example + +=== 1.2.1 The Example Schedule-JSON + +[source,json] +---- +[ + { + "startTimestamp": 1684792800, + "duration": 86400, + "dischargePowerSetPoint": 92000, + "frequencyLimit": 50000, + "activationRunTime": "LONG_ACTIVATION_RUN", + "supportDuration": "LONG_SUPPORT_DURATION" + }, + { + "startTimestamp": 1684879200, + "duration": 86400, + "dischargePowerSetPoint": 6000, + "frequencyLimit": 50000, + "activationRunTime": "LONG_ACTIVATION_RUN", + "supportDuration": "LONG_SUPPORT_DURATION" + } +] +---- + +=== 1.2.2 JSON Element details + +- `StartTimeStamp`: When the controller should be activated. +- `Duration`: How long is the controller to be activated? +- `frequency limit`: The controller continuously monitors and checks whether a Frequency limit or threshold is less than the +measured grid frequency. +- `DischargePower`: The Ess discharges from the batteries when generating capacity. +- `activationRunTime`: The time in milliseconds required for the reserve to fully activate. Short(700 ms) or Medium(1000 ms) or Long(1300 ms) activation Time. +- `supportDuration`: The time in milliseconds for which the reserve should continue providing support after the frequency has stabilized. Short(5 seconds) or Long(30 seconds) support duration. + +=== 1.2.3 Explanation of the Schedule +The Schedule JSON activates FFR for a full day (86400 seconds or 24 hours) with the following parameters: + +1. Schedule for 23rd May 2023 00:00:00 to 24th May: + - *Threshold frequency:* 49700 mHz + - *Discharge power:* 92000 W + - *Long activation time:* 1.3 seconds + - *Support duration:* 30 seconds + +2. Following Schedule for 24th May 2023 00:00:00 to 25th May: + - *Threshold frequency:* 49700 mHz + - *Discharge power:* 52000 W + - *Long activation time:* 1.3 seconds + - *Support duration:* 30 seconds + + +== 2.1 REST API for updating Fast Frequency Reserve controllers schedule locally + +note : The controller/ App should be activated to update the schedule, which can be done using online monitoring or apache felix. + +== 2.1.1 Overview + +This REST API allows you to update FFR schedule for the specified edge device. The API endpoint takes a JSON payload that specifies the schedule, including the start time, duration, discharge power set point, frequency limit, activation runtime, and support duration. + +== 2.1.2 Endpoint + +- *URL*: http://:8084/jsonrpc +- *Method*: POST +- *Content-Type*: application/json +- *Authorization*: Basic Authentication, username: x, password: owner + +== 2.1.3 Body + +The request body must be a JSON object with the following structure: + +[source,json] +---- +{ + "method": "componentJsonApi", + "params": { + "componentId": "ctrlFastFreqReserve0", + "payload": { + "method": "setActivateFastFreqReserve", + "params": { + "id": "edge0", + "schedule": [ + { + "startTimestamp": 1701871562, + "duration": 999, + "dischargePowerSetPoint": 6000, + "frequencyLimit": 502000, + "activationRunTime": "LONG_ACTIVATION_RUN", + "supportDuration": "LONG_SUPPORT_DURATION" + } + ] + } + } + } +} +---- + +== 2.1.4 Request Parameters + +The request body for this REST API call is a JSON object with the following parameters: + +- *method*: The specific method to call within the component. In this case, it is `componentJsonApi`. +- *params*: The parameters associated with the method call. +- *componentId*: The unique identifier of the component that is receiving the request. +- *payload*: The specific data being sent to the component. See below + +=== 2.1.5 Payload Parameters + +Within the payload parameter, there is another JSON object that specifies the details of the activation request: + +- *method*: The method to call within the component to handle the activation request. In this case, it is `setActivateFastFreqReserve`. +- *params*: The parameters associated with the `setActivateFastFreqReserve` method. +- *id*: The unique identifier of the edge device for which the activation is being requested, locally is always `edge0`. +- *schedule*: An array of schedule items that define the activation pattern for the reserve. + +=== 2.1.6 Schedule Item Parameters + +Each schedule item within the schedule array specifies a specific activation period: + +- *startTimestamp*: The unix time stamp when the FFR should start activating. +- *duration*: The duration in milliseconds for which the reserve should remain active. +- *dischargePowerSetPoint*: The maximum power in kilowatts that the reserve should discharge during activation. +- *frequencyLimit*: The frequency threshold below which the reserve should be activated. +- *activationRunTime*: The time in milliseconds required for the reserve to fully activate. +- *supportDuration*: The time in milliseconds for which the reserve should continue providing support after the frequency has stabilized. + +=== 2.1.7 Example Python code + +[source,python] +---- +import requests +import json +from requests.auth import HTTPBasicAuth + +# API URL +url = 'http://10.0.10.178:8084/jsonrpc' + +# Authentication +auth = HTTPBasicAuth('x', 'owner') + +# Request headers +headers = { + 'Content-Type': 'application/json', +} + +# Request payload +payload = { + 'jsonrpc': '2.0', + 'id': '00000000-0000-0000-0000-000000000000', + 'method': 'componentJsonApi', + 'params': { + 'componentId': 'ctrlFastFreqReserve0', + 'payload': { + 'method': 'setActivateFastFreqReserve', + 'params': { + 'id': 'edge0', + 'schedule': [ + { + 'startTimestamp': 1701871562, + 'duration': 999, + 'dischargePowerSetPoint': 6000, + 'frequencyLimit': 502000, + 'activationRunTime': 'LONG_ACTIVATION_RUN', + 'supportDuration': 'LONG_SUPPORT_DURATION' + } + ] + } + } + } +} + +# Make the request +response = requests.post(url, auth=auth, headers=headers, json=payload) + +# Print the response +print(response.json()) +---- + + +== 3.1 REST API for Activating Fast Frequency Reserve controllers schedule using Backend +note : The controller/ App should be activated to update the schedule, which can be done using online monitoring or apache felix. + +== 3.1.1 Overview + +This REST API allows you to update FFR for a specific edge device. The API endpoint takes a JSON payload that updates activation schedule, including the start time, duration, discharge power set point, frequency limit, activation runtime, and support duration. + +== 3.1.2 Endpoint + +- *URL*: https://femecon.de/fems/rest/jsonrpc +- *Method*: POST +- *Content-Type*: application/json +- *Authorization*: Basic Authentication, username:foo.com, password:**** + +== 3.1.3 Body + +The request body must be a JSON object with the following structure: + +[source,json] +---- +{ + "method": "edgeRpc", + "params": { + "edgeId": "fems3734", + "payload": { + "method": "componentJsonApi", + "params": { + "componentId": "ctrlFastFreqReserve0", + "payload": { + "method": "setActivateFastFreqReserve", + "params": { + "id": "edge3734", + "schedule": [ + { + "startTimestamp": "1701767477", + "duration": "11000", + "dischargePowerSetPoint": "6000", + "frequencyLimit": "52000", + "activationRunTime": "LONG_ACTIVATION_RUN", + "supportDuration": "LONG_SUPPORT_DURATION" + } + ] + } + } + } + } + } +} +---- + +== 3.1.4 Request Parameters + +- *method*: The JSONRPC method to call. In this case, it is `edgeRpc`. +- *params*: The JSONRPC parameters. +- *edgeId*: The ID of the edge device for which to activate the FFR. +- *payload*: The JSONRPC payload. + +== 3.1.5 Payload Parameters + +Within the payload parameter, there is another JSON object that specifies the details of the activation request: + +- *method*: The JSONRPC method to call within the component. In this case, it is `componentJsonApi`. +- *params*: The JSONRPC parameters for the `componentJsonApi` method. +- *componentId*: The ID of the component within which to call the method. In this case, it is `ctrlFastFreqReserve0`. +- *payload*: The JSONRPC payload for the method. + +== 3.1.6 Schedule Item Parameters + +Each schedule item within the schedule array specifies a specific activation period: + +- *startTimestamp*: The unix time stamp in milliseconds when the FFR should start activating. +- *duration*: The duration in milliseconds for which the reserve should remain active. +- *dischargePowerSetPoint*: The maximum power in kilowatts that the reserve should discharge during activation. +- *frequencyLimit*: The frequency threshold below which the reserve should be activated. +- *activationRunTime*: The time in milliseconds required for the reserve to fully activate. +- *supportDuration*: The time in milliseconds for which the reserve should continue providing support after the frequency has stabilized. + +== 3.1.7 Example Python code: + +[source,python] +---- +import requests +import json +from requests.auth import HTTPBasicAuth +import base64 +import os + +url = "https://fenecon.de/fems/rest/jsonrpc" + +username = os.getenv("FENECON_USERNAME") +password = os.getenv("FENECON_PASSWORD") + +headers = { + "Content-Type": "application/json", + "Authorization": "Basic " + base64.b64encode(f"{username}:{password}".encode("utf-8")).decode("utf-8") +} + +body = { + "method": "edgeRpc", + "params": { + "edgeId": "fems3734", + "payload": { + "method": "componentJsonApi", + "params": { + "componentId": "ctrlFastFreqReserve0", + "payload": { + "method": "setActivateFastFreqReserve", + "params": { + "id": "edge3734", + "schedule": [ + { + "startTimestamp": "1701767477", + "duration": "11000", + "dischargePowerSetPoint": "6000", + "frequencyLimit": "52000", + "activationRunTime": "LONG_ACTIVATION_RUN", + "supportDuration": "LONG_SUPPORT_DURATION" + } + ] + } + } + } + } + } +} + +response = requests.post(url, headers=headers, data=json.dumps(body)) + +if response.status_code == 200: + print("Fast Frequency Reserve activated successfully") +else: + print("Error activating Fast Frequency Reserve:", response.text) +---- + + +https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.controller.ess.fastfrequencyreserve[Source Code icon:github[]] \ No newline at end of file diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/Config.java b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/Config.java new file mode 100644 index 00000000000..2ca1b8b52f3 --- /dev/null +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/Config.java @@ -0,0 +1,54 @@ +package io.openems.edge.controller.ess.fastfrequencyreserve; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +import io.openems.edge.controller.ess.fastfrequencyreserve.enums.ControlMode; + +@ObjectClassDefinition(// + name = "Controller Ess Fast Frequency Reserve", // + description = "This Controller helps the energy storage system (ESS) generate capacity, essentially battery discharge. When the measured\n" + + "\"Grid frequency\" is lower than the predefined \"Frequency limit\".") // +@interface Config { + + @AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component") + String id() default "ctrlFastFreqReserve0"; + + @AttributeDefinition(name = "Alias", description = "Human-readable name of this Component; defaults to Component-ID") + String alias() default ""; + + @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?") + boolean enabled() default true; + + @AttributeDefinition(name = "Control Mode", description = "Set the type of control mode.") + ControlMode controlMode() default ControlMode.MANUAL_OFF; + + @AttributeDefinition(name = "Activation Schdule", description = "Schedule for the activation.") + String activationScheduleJson() default "[\n" // + + " {\n" // + + " \"startTimestamp\": 1684879200,\n" // + + " \"duration\": 86400,\n" // + + " \"dischargePowerSetPoint\": 92000,\n" // + + " \"frequencyLimit\": 49500,\n" // + + " \"activationRunTime\": \"LONG_ACTIVATION_RUN\",\n" // + + " \"supportDuration\": \"LONG_SUPPORT_DURATION\"\n" // + + " }\n" // + + "]"; // + + @AttributeDefinition(name = "Ess-ID", description = "ID of Ess device.") + String ess_id(); + + @AttributeDefinition(name = "Grid-Meter-Id", description = "ID of the Grid-Meter.") + String meter_id(); + + @AttributeDefinition(name = "Pre activation time", description = "A time before the activation time for charging the system(min).") + int preActivationTime() default 0; + + @AttributeDefinition(name = "Ess target filter", description = "This is auto-generated by 'Ess-ID'.") + String ess_target() default "(enabled=true)"; + + @AttributeDefinition(name = "Meter target filter", description = "This is auto-generated by 'Grid-Meter-ID'.") + String meter_target() default "(enabled=true)"; + + String webconsole_configurationFactory_nameHint() default "Controller Ess Fast Frequency Reserve [{id}]"; +} \ No newline at end of file diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/ControllerFastFrequencyReserve.java b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/ControllerFastFrequencyReserve.java new file mode 100644 index 00000000000..efff694c2ee --- /dev/null +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/ControllerFastFrequencyReserve.java @@ -0,0 +1,283 @@ +package io.openems.edge.controller.ess.fastfrequencyreserve; + +import io.openems.common.channel.AccessMode; +import io.openems.common.channel.Level; +import io.openems.common.channel.PersistencePriority; +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.Channel; +import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.channel.StateChannel; +import io.openems.edge.common.channel.WriteChannel; +import io.openems.edge.common.channel.value.Value; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.controller.api.Controller; +import io.openems.edge.controller.ess.fastfrequencyreserve.enums.ActivationTime; +import io.openems.edge.controller.ess.fastfrequencyreserve.enums.ControlMode; +import io.openems.edge.controller.ess.fastfrequencyreserve.enums.SupportDuration; +import io.openems.edge.controller.ess.fastfrequencyreserve.statemachine.StateMachine.State; + +public interface ControllerFastFrequencyReserve extends Controller, OpenemsComponent { + + public enum ChannelId implements io.openems.edge.common.channel.ChannelId { + CONTROL_MODE(Doc.of(ControlMode.values()) // + .initialValue(ControlMode.MANUAL_OFF) // + .text("Configured Control Mode")), // + STATE_MACHINE(Doc.of(State.values()) // + .persistencePriority(PersistencePriority.HIGH)// + .text("Current State of State-Machine")), // + SCHEDULE_PARSE_FAILED(Doc.of(Level.FAULT) // + .text("Unable to parse Schedule")), // + NO_ACTIVE_SETPOINT(Doc.of(OpenemsType.BOOLEAN) // + .text("No active Set-Point given")), // + DISCHARGE_POWER_SET_POINT(Doc.of(OpenemsType.INTEGER) // + .persistencePriority(PersistencePriority.HIGH)// + .accessMode(AccessMode.READ_WRITE)), + NO_FREQUENCY_LIMIT(Doc.of(OpenemsType.BOOLEAN) // + .text("No Frequency limit is given")), // + FREQUENCY_LIMIT(Doc.of(OpenemsType.INTEGER) // + .persistencePriority(PersistencePriority.HIGH)// + .accessMode(AccessMode.READ_WRITE)), // + NO_START_TIMESTAMP(Doc.of(OpenemsType.BOOLEAN) // + .text("No start timestamp")), // + START_TIMESTAMP(Doc.of(OpenemsType.LONG) // + .persistencePriority(PersistencePriority.HIGH)// + .accessMode(AccessMode.READ_WRITE)), // + NO_DURATION(Doc.of(OpenemsType.BOOLEAN) // + .text("No duration")), // + DURATION(Doc.of(OpenemsType.INTEGER) // + .persistencePriority(PersistencePriority.HIGH)// + .accessMode(AccessMode.READ_WRITE)), // + ACTIVATION_TIME(Doc.of(ActivationTime.values())// + .accessMode(AccessMode.READ_WRITE)), // + SUPPORT_DURATIN(Doc.of(SupportDuration.values())// + .accessMode(AccessMode.READ_WRITE)), + LAST_TRIGGERED_TIME(Doc.of(OpenemsType.STRING) // + .persistencePriority(PersistencePriority.HIGH)// + .accessMode(AccessMode.READ_WRITE) // + .text("Last Triggered time in Human readable form")// + + ); + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } + + /** + * Gets the Channel for {@link ChannelId#SUPPORT_DURATIN}. + * + * @return the Channel + */ + public default Channel getSupportDurationChannel() { + return this.channel(ChannelId.SUPPORT_DURATIN); + } + + /** + * Gets the SupportDuration, see {@link ChannelId#SUPPORT_DURATIN}. + * + * @return the Channel {@link Value} + */ + public default SupportDuration getSupportDuration() { + return this.getSupportDurationChannel().value().asEnum(); + } + + /** + * Gets the Channel for {@link ChannelId#ACTIVATION_TIME}. + * + * @return the Channel + */ + public default Channel getActivationTimeChannel() { + return this.channel(ChannelId.ACTIVATION_TIME); + } + + /** + * Gets the ActivationTime, see {@link ChannelId#ACTIVATION_TIME}. + * + * @return the Channel {@link Value} + */ + public default ActivationTime getActivationTime() { + return this.getActivationTimeChannel().value().asEnum(); + } + + /** + * Gets the WriteChannel {@link ChannelId#LAST_TRIGGERED_TIME}. + * + * @return the WriteChannel + */ + public default WriteChannel getLastTriggeredTimeChannel() { + return this.channel(ChannelId.LAST_TRIGGERED_TIME); + } + + /** + * Gets the getLastTriggeredTime, see {@link ChannelId#LAST_TRIGGERED_TIME}. + * + * @return the Channel {@link Value} + */ + public default Value getLastTriggeredTime() { + return this.getLastTriggeredTimeChannel().value(); + } + + /** + * Sets the LastTriggeredTimseStamp, see {@link ChannelId#LAST_TRIGGERED_TIME}. + * + * @param value the value to be set + */ + public default void setLastTriggeredTime(String value) { + this.getLastTriggeredTimeChannel().setNextValue(value); + } + + /** + * Gets the Channel {@link ChannelId#SCHEDULE_PARSE_FAILED}. + * + * @return the Channel + */ + public default StateChannel getScheduleParseFailedChannel() { + return this.channel(ChannelId.SCHEDULE_PARSE_FAILED); + } + + /** + * Internal method to set the 'nextValue' on + * {@link ChannelId#SCHEDULE_PARSE_FAILED} Channel. + * + * @param value the next value + */ + public default void _setScheduleParseFailed(boolean value) { + this.getScheduleParseFailedChannel().setNextValue(value); + } + + /** + * Gets the Channel {@link ChannelId#DISCHARGE_POWER_SET_POINT}. + * + * @return the Channel + */ + public default WriteChannel getDischargePowerSetPointChannel() { + return this.channel(ChannelId.DISCHARGE_POWER_SET_POINT); + } + + /** + * Gets the getDischargeActivePowerSetPoint, see + * {@link ChannelId#DISCHARGE_POWER_SET_POINT}. + * + * @return the Channel {@link Value} + */ + public default Value getDischargePowerSetPoint() { + return this.getDischargePowerSetPointChannel().value(); + } + + /** + * Gets the WriteChannel {@link ChannelId#FREQUENCY_LIMIT}. + * + * @return the WriteChannel + */ + public default WriteChannel getFrequencyLimitChannel() { + return this.channel(ChannelId.FREQUENCY_LIMIT); + } + + /** + * Gets the getFrequencyLimit, see {@link ChannelId#FREQUENCY_LIMIT}. + * + * @return the Channel {@link Value} + */ + public default Value getFrequencyLimit() { + return this.getFrequencyLimitChannel().value(); + } + + /** + * Gets the WriteChannel {@link ChannelId#DURATION}. + * + * @return the WriteChannel + */ + public default WriteChannel getDurationChannel() { + return this.channel(ChannelId.DURATION); + } + + /* + * Gets the getDuration, see {@link ChannelId#DURATION}. + * + * @return the Channel {@link Value} + */ + public default Value getDuration() { + return this.getDurationChannel().value(); + } + + /** + * Gets the WriteChannel {@link ChannelId#START_TIMESTAMP}. + * + * @return the WriteChannel + */ + public default WriteChannel getStartTimestampChannel() { + return this.channel(ChannelId.START_TIMESTAMP); + } + + /** + * Gets the getStartTimestamp, see {@link ChannelId#START_TIMESTAMP}. + * + * @return the Channel {@link Value} + */ + public default Value getStartTimestamp() { + return this.getStartTimestampChannel().value(); + } + + /** + * Gets the Channel for {@link ChannelId#STATE_MACHINE}. + * + * @return the Channel + */ + public default Channel getStateMachineChannel() { + return this.channel(ChannelId.STATE_MACHINE); + } + + /** + * Gets the {@link StateChannel} for {@link ChannelId#STATE_MACHINE}. + * + * @return the Channel {@link Value} + */ + public default Value getStateMachine() { + return this.getStateMachineChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#STATE_MACHINE} + * Channel. + * + * @param value the next value + */ + public default void _setStateMachine(State value) { + this.getStateMachineChannel().setNextValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#CONTROL_MODE}. + * + * @return the Channel + */ + public default Channel getControlModeChannel() { + return this.channel(ChannelId.CONTROL_MODE); + } + + /** + * Gets the {@link StateChannel} for {@link ChannelId#CONTROL_MODE}. + * + * @return the Channel {@link Value} + */ + public default Value getControlMode() { + return this.getControlModeChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#CONTROL_MODE} + * Channel. + * + * @param value the next value + */ + public default void _setControlMode(ControlMode value) { + this.getControlModeChannel().setNextValue(value); + } +} diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/ControllerFastFrequencyReserveImpl.java b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/ControllerFastFrequencyReserveImpl.java new file mode 100644 index 00000000000..5e9bf35f124 --- /dev/null +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/ControllerFastFrequencyReserveImpl.java @@ -0,0 +1,312 @@ +package io.openems.edge.controller.ess.fastfrequencyreserve; + +import java.time.Instant; +import java.time.ZoneId; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.Function; +import java.util.stream.Stream; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.metatype.annotations.Designate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonArray; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.jsonrpc.base.GenericJsonrpcResponseSuccess; +import io.openems.common.session.Role; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.common.channel.WriteChannel; +import io.openems.edge.common.channel.value.Value; +import io.openems.edge.common.component.AbstractOpenemsComponent; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.jsonapi.ComponentJsonApi; +import io.openems.edge.common.jsonapi.EdgeGuards; +import io.openems.edge.common.jsonapi.JsonApiBuilder; +import io.openems.edge.controller.api.Controller; +import io.openems.edge.controller.ess.fastfrequencyreserve.enums.ActivationTime; +import io.openems.edge.controller.ess.fastfrequencyreserve.enums.SupportDuration; +import io.openems.edge.controller.ess.fastfrequencyreserve.jsonrpc.SetActivateFastFreqReserveRequest; +import io.openems.edge.controller.ess.fastfrequencyreserve.jsonrpc.SetActivateFastFreqReserveRequest.ActivateFastFreqReserveSchedule; +import io.openems.edge.controller.ess.fastfrequencyreserve.statemachine.Context; +import io.openems.edge.controller.ess.fastfrequencyreserve.statemachine.StateMachine; +import io.openems.edge.controller.ess.fastfrequencyreserve.statemachine.StateMachine.State; +import io.openems.edge.ess.api.ManagedSymmetricEss; +import io.openems.edge.meter.api.ElectricityMeter; + +@Designate(ocd = Config.class, factory = true) +@Component(// + name = "Controller.Ess.FastFrequencyReserve", // + immediate = true, // + configurationPolicy = ConfigurationPolicy.REQUIRE // +) +public class ControllerFastFrequencyReserveImpl extends AbstractOpenemsComponent + implements ControllerFastFrequencyReserve, Controller, OpenemsComponent, ComponentJsonApi { + + private final Logger log = LoggerFactory.getLogger(ControllerFastFrequencyReserveImpl.class); + private final StateMachine stateMachine = new StateMachine(State.UNDEFINED); + + private Config config = null; + private List schedule = new CopyOnWriteArrayList<>(); + + private static final Function OBTAIN_DICHARGE_POWER = ActivateFastFreqReserveSchedule::dischargePowerSetPoint; + private static final Function OBTAIN_FREQ_LIMIT = ActivateFastFreqReserveSchedule::frequencyLimit; + private static final Function OBTAIN_STARTTIME_STAMP = ActivateFastFreqReserveSchedule::startTimestamp; + private static final Function OBTAIN_DURATION = ActivateFastFreqReserveSchedule::duration; + private static final Function OBTAIN_ACTIVATION_TIME = ActivateFastFreqReserveSchedule::activationRunTime; + private static final Function OBTAIN_SUPPORT_DURATION = ActivateFastFreqReserveSchedule::supportDuration; + + @Reference + private ConfigurationAdmin cm; + + @Reference + private ComponentManager componentManager; + + @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) + private ManagedSymmetricEss ess; + + @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) + private ElectricityMeter meter; + + public ControllerFastFrequencyReserveImpl() { + super(// + OpenemsComponent.ChannelId.values(), // + Controller.ChannelId.values(), // + ControllerFastFrequencyReserve.ChannelId.values() // + ); + } + + @Activate + private void activate(ComponentContext context, Config config) throws OpenemsNamedException { + this.config = config; + super.activate(context, config.id(), config.alias(), config.enabled()); + this.updateConfig(); + } + + @Override + public void buildJsonApiRoutes(JsonApiBuilder builder) { + builder.handleRequest(SetActivateFastFreqReserveRequest.METHOD, // + endpoint -> { + endpoint.setGuards(EdgeGuards.roleIsAtleast(Role.OWNER)); + }, call -> { + this.handleSetActivateFastFreqReserveRequest( + SetActivateFastFreqReserveRequest.from(call.getRequest())); + + return new GenericJsonrpcResponseSuccess(call.getRequest().getId(), JsonUtils.buildJsonObject() // + .addProperty("startTimestamp", "recieved") // + .build()); + }); + } + + /** + * Updates the configuration for the component, setting control mode, + * references, and activation schedule. + * + * @throws OpenemsNamedException On Exception. + */ + private void updateConfig() throws OpenemsNamedException { + this._setControlMode(this.config.controlMode()); + + if (OpenemsComponent.updateReferenceFilter(this.cm, this.servicePid(), "ess", // + this.config.ess_id())) { + return; + } + if (OpenemsComponent.updateReferenceFilter(this.cm, this.servicePid(), "meter", // + this.config.meter_id())) { + return; + } + try { + if (!this.config.activationScheduleJson().trim().isEmpty()) { + final var scheduleElement = JsonUtils.parse(this.config.activationScheduleJson()); + final var scheduleArray = JsonUtils.getAsJsonArray(scheduleElement); + this.applySchedule(scheduleArray); + this._setScheduleParseFailed(false); + } + } catch (IllegalStateException | OpenemsNamedException e) { + this._setScheduleParseFailed(true); + this.logError(this.log, "Unable to parse Schedule: " + e.getMessage()); + } + } + + /** + * Updates the configuration for activating fast frequency reserve based on the + * provided request. + * + * @param request The request containing the schedule information. + */ + private void updateConfig(SetActivateFastFreqReserveRequest request) { + var scheduleString = SetActivateFastFreqReserveRequest.listToString(request.getSchedule()); + OpenemsComponent.updateConfigurationProperty(this.cm, this.servicePid(), "activationScheduleJson", + scheduleString); + } + + private void applySchedule(JsonArray jsonArray) throws OpenemsNamedException { + this.schedule = SetActivateFastFreqReserveRequest.ActivateFastFreqReserveSchedule.from(jsonArray); + } + + @Deactivate + protected void deactivate() { + super.deactivate(); + } + + @Override + public void run() throws OpenemsNamedException { + switch (this.config.controlMode()) { + case MANUAL_ON -> { + this.getConfigParams(); + this.handleStatemachine(); + } + case MANUAL_OFF -> { + // Do nothing + } + } + this._setControlMode(this.config.controlMode()); + } + + private void getConfigParams() { + + this.setChannelValueIfNeeded(ControllerFastFrequencyReserve.ChannelId.DISCHARGE_POWER_SET_POINT, + OBTAIN_DICHARGE_POWER); + final var channelValue = this.getDischargePowerSetPoint(); + + // Avoid calling + if (!channelValue.isDefined()) { + return; + } + this.setChannelValueIfNeeded(ControllerFastFrequencyReserve.ChannelId.FREQUENCY_LIMIT, // + OBTAIN_FREQ_LIMIT); + this.setChannelValueIfNeeded(ControllerFastFrequencyReserve.ChannelId.DURATION, // + OBTAIN_DURATION); + this.setChannelValueIfNeeded(ControllerFastFrequencyReserve.ChannelId.START_TIMESTAMP, // + OBTAIN_STARTTIME_STAMP); + // TODO get it for the activation time and support time, But currently this + // tested for long activation time and long support time, other enums are for + // future + this.setChannelValueIfNeeded(ControllerFastFrequencyReserve.ChannelId.ACTIVATION_TIME, // + OBTAIN_ACTIVATION_TIME); + this.setChannelValueIfNeeded(ControllerFastFrequencyReserve.ChannelId.SUPPORT_DURATIN, // + OBTAIN_SUPPORT_DURATION); + } + + /** + * Sets the value for the specified {@code FastFrequencyReserve.ChannelId} based + * on the provided {@code Function}, only if needed. + * + * @param channelId The channel to set the value for. + * @param obtainFunction A {@code Function} to retrieve the corresponding value + * based on the provided schedule entry. + */ + private void setChannelValueIfNeeded(ControllerFastFrequencyReserve.ChannelId channelId, + Function obtainFunction) { + WriteChannel channel = this.channel(channelId); + var setPointFromChannel = channel.value(); + if (setPointFromChannel.isDefined()) { + return; + } + + var currentTime = this.componentManager.getClock().withZone(ZoneId.systemDefault()); + var now = Instant.now(currentTime).getEpochSecond(); + + for (var scheduleEntry : this.schedule) { + var endTime = scheduleEntry.startTimestamp() + scheduleEntry.duration(); + + // Configurable minutes, and convert into seconds + var preActivationTimeBeforeStartTime = this.config.preActivationTime() * 60; + if (now >= scheduleEntry.startTimestamp() - preActivationTimeBeforeStartTime && now <= endTime) { + channel.setNextValue(obtainFunction.apply(scheduleEntry)); + return; + } + } + channel.setNextValue(null); + return; + } + + private void handleStatemachine() { + if (this.checkGridMode()) { + return; + } + + var state = this.stateMachine.getCurrentState(); + this._setStateMachine(state); + + if (!this.areChannelsDefined()) { + return; + } + + var context = new Context(this, // + this.componentManager.getClock(), // + this.ess, // + this.meter, // + this.getStartTimestamp().get(), // + this.getDuration().get(), // + this.getDischargePowerSetPoint().get(), // + this.getFrequencyLimit().get(), // + // TODO if other version of FFR needed, need to test first with the Inverter + // Capabilities + this.getActivationTime(), // + this.getSupportDuration()); + + try { + this.stateMachine.run(context); + } catch (OpenemsNamedException e) { + this.logError(this.log, "StateMachine failed: " + e.getMessage()); + } + } + + /** + * Checks the grid mode and returns a boolean value based on the grid mode + * state. If the grid mode is "ON_GRID" or "UNDEFINED," it returns false and + * logs a warning message when the grid mode is "UNDEFINED." If the grid mode is + * "OFF_GRID," it returns true. + * + * @return true if the grid mode is "OFF_GRID," false otherwise. + */ + private boolean checkGridMode() { + return switch (this.ess.getGridMode()) { + case ON_GRID -> false; + case UNDEFINED -> { + this.logWarn(this.log, "Grid-Mode is [UNDEFINED]"); + yield false; + } + case OFF_GRID -> true; + }; + } + + private boolean areChannelsDefined() { + return Stream.of(// + this.getDischargePowerSetPoint(), // + this.getFrequencyLimit(), // + this.getDuration(), // + this.getStartTimestamp())// + .allMatch(Value::isDefined); + } + + private void handleSetActivateFastFreqReserveRequest(SetActivateFastFreqReserveRequest request) + throws OpenemsNamedException { + this.schedule = request.getSchedule(); + + // get current schedule + var currentSchedule = (String) this.getComponentContext()// + .getProperties()// + .get("activationScheduleJson"); + var currentScheduleArray = JsonUtils.getAsJsonArray(JsonUtils.parse(currentSchedule).getAsJsonArray()); + var currentScheduleList = ActivateFastFreqReserveSchedule.from(currentScheduleArray); + + if (this.schedule.size() == currentScheduleArray.size() && currentScheduleList.equals(this.schedule)) { + return; + } + this.updateConfig(request); + } +} diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/enums/ActivationTime.java b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/enums/ActivationTime.java new file mode 100644 index 00000000000..5d483a3ef44 --- /dev/null +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/enums/ActivationTime.java @@ -0,0 +1,30 @@ +package io.openems.edge.controller.ess.fastfrequencyreserve.enums; + +import io.openems.common.types.OptionsEnum; + +public enum ActivationTime implements OptionsEnum { + SHORT_ACTIVATION_RUN(700, "Short activation time run, 700 in milliseconds"), // + MEDIUM_ACTIVATION_RUN(1000, "Medium activation time run, 1000 in milliseconds"), // + LONG_ACTIVATION_RUN(1300, "Long activation time run, 1300 in milliseconds"); + + private final int value; + private final String name; + + private ActivationTime(int value, String name) { + this.value = value; + this.name = name; + } + + public int getValue() { + return this.value; + } + + public String getName() { + return this.name; + } + + @Override + public OptionsEnum getUndefined() { + return LONG_ACTIVATION_RUN; + } +} diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/enums/ControlMode.java b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/enums/ControlMode.java new file mode 100644 index 00000000000..e203ad4afdd --- /dev/null +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/enums/ControlMode.java @@ -0,0 +1,32 @@ +package io.openems.edge.controller.ess.fastfrequencyreserve.enums; + +import io.openems.common.types.OptionsEnum; + +public enum ControlMode implements OptionsEnum { + MANUAL_ON(0, "Manual control for the ON signal, FFR is swtiched on"), // + MANUAL_OFF(1, "Manual control for the OFF signal, FFR is swtiched off") // + ; // + + private final int value; + private final String name; + + private ControlMode(int value, String name) { + this.value = value; + this.name = name; + } + + @Override + public int getValue() { + return this.value; + } + + @Override + public String getName() { + return this.name; + } + + @Override + public OptionsEnum getUndefined() { + return MANUAL_OFF; + } +} diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/enums/SupportDuration.java b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/enums/SupportDuration.java new file mode 100644 index 00000000000..040806aa262 --- /dev/null +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/enums/SupportDuration.java @@ -0,0 +1,32 @@ +package io.openems.edge.controller.ess.fastfrequencyreserve.enums; + +import io.openems.common.types.OptionsEnum; + +public enum SupportDuration implements OptionsEnum { + SHORT_SUPPORT_DURATION(5, "long support duration 5 seconds"), + LONG_SUPPORT_DURATION(30, "long support duration 30 seconds"); + + private final int value; + private final String name; + + private SupportDuration(int value, String name) { + this.value = value; + this.name = name; + } + + @Override + public int getValue() { + return this.value; + } + + @Override + public String getName() { + return this.name; + } + + @Override + public OptionsEnum getUndefined() { + return LONG_SUPPORT_DURATION; + } + +} diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/jsonrpc/SetActivateFastFreqReserveRequest.java b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/jsonrpc/SetActivateFastFreqReserveRequest.java new file mode 100644 index 00000000000..4c422a365bc --- /dev/null +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/jsonrpc/SetActivateFastFreqReserveRequest.java @@ -0,0 +1,228 @@ +package io.openems.edge.controller.ess.fastfrequencyreserve.jsonrpc; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.jsonrpc.base.JsonrpcRequest; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.controller.ess.fastfrequencyreserve.enums.ActivationTime; +import io.openems.edge.controller.ess.fastfrequencyreserve.enums.SupportDuration; + +/** + * Represents a JSON-RPC Request for 'setActivateFastFreqReserve'. + * + *
      + {
      + 	"jsonrpc": "2.0",
      + 	"id": "UUID",
      + 	"method": "setActivateFastFreqReserve",
      + 	"params": { 		
      + 		"schedule": [{
      + 			"startTimestamp": 1542464697,
      + 			"duration": 900,
      + 			"dischargeActivePowerSetPoint": 92000,
      + 			"frequencyLimit": 49500
      + 			"activationRunTime": "LONG_ACTIVATION_RUN",
      + 			"supportDuration": "LONG_SUPPORT_DURATION"
      + 		}]
      + 	}
      + }
      + * 
      + */ +public class SetActivateFastFreqReserveRequest extends JsonrpcRequest { + + /** + * Create {@link SetActivateFastFreqReserveRequest} from a template + * {@link JsonrpcRequest}. + * + * @param request the template {@link JsonrpcRequest} + * @return the {@link SetActivateFastFreqReserveRequest} + * @throws OpenemsNamedException on parse error + */ + public static SetActivateFastFreqReserveRequest from(JsonrpcRequest request) throws OpenemsNamedException { + final var params = request.getParams(); + final var edgeId = JsonUtils.getAsString(params, "id"); + final var scheduleArray = JsonUtils.getAsJsonArray(params, "schedule"); + final var schedule = ActivateFastFreqReserveSchedule.from(scheduleArray); + return new SetActivateFastFreqReserveRequest(request, edgeId, schedule); + } + + public static final String METHOD = "setActivateFastFreqReserve"; + + private final String edgeId; + private final List schedule; + + public SetActivateFastFreqReserveRequest(String edgeId) { + this(edgeId, new ArrayList<>()); + } + + private SetActivateFastFreqReserveRequest(String edgeId, List schedule) { + super(SetActivateFastFreqReserveRequest.METHOD); + this.edgeId = edgeId; + this.schedule = schedule; + } + + private SetActivateFastFreqReserveRequest(JsonrpcRequest request, String edgeId, + List schedule) { + super(request, SetActivateFastFreqReserveRequest.METHOD); + this.edgeId = edgeId; + this.schedule = schedule; + } + + /** + * Adds a new schedule entry for activating Fast Frequency Reserve. + * + * @param scheduleEntry The schedule entry to be added. + */ + public void addScheduleEntry(ActivateFastFreqReserveSchedule scheduleEntry) { + this.schedule.add(scheduleEntry); + } + + @Override + public JsonObject getParams() { + var schedule = new JsonArray(); + for (var se : this.schedule) { + schedule.add(se.toJson()); + } + return JsonUtils.buildJsonObject() // + .addProperty("id", this.getEdgeId()) // + .add("schedule", schedule) // + .build(); + } + + /** + * Gets the Edge-ID. + * + * @return Edge-ID + */ + public String getEdgeId() { + return this.edgeId; + } + + public List getSchedule() { + return this.schedule; + } + + /** + * Converts a list of ActivateFastFreqReserveSchedule objects to a formatted + * string. + * + * @param scheduleList The list of ActivateFastFreqReserveSchedule objects to + * convert. + * @return A string representation of the schedule list. + * @see ActivateFastFreqReserveSchedule#toString() + */ + public static String listToString(List scheduleList) { + return "["// + + scheduleList.stream()// + .map(ActivateFastFreqReserveSchedule::toString)// + .collect(Collectors.joining(", "))// + + "]"; + } + + public record ActivateFastFreqReserveSchedule(long startTimestamp, int duration, int dischargePowerSetPoint, + int frequencyLimit, ActivationTime activationRunTime, SupportDuration supportDuration) { + + /** + * Builds a list of ActivateFastFreqReserveSchedule from a JsonArray. + * + * @param jsonArray JsonArray + * @return list of {@link ActivateFastFreqReserveSchedule} + * @throws OpenemsNamedException on error + */ + public static List from(JsonArray jsonArray) throws OpenemsNamedException { + List schedule = new ArrayList<>(); + for (var jsonElement : jsonArray) { + var newSchedule = new ActivateFastFreqReserveSchedule( + JsonUtils.getAsLong(jsonElement, "startTimestamp"), // + JsonUtils.getAsInt(jsonElement, "duration"), + JsonUtils.getAsInt(jsonElement, "dischargePowerSetPoint"), + JsonUtils.getAsInt(jsonElement, "frequencyLimit"), + JsonUtils.getAsEnum(ActivationTime.class, jsonElement, "activationRunTime"), + JsonUtils.getAsEnum(SupportDuration.class, jsonElement, "supportDuration")); + + // Check for overlap with existing schedules before adding + if (!overlapsExistingSchedule(schedule, newSchedule)) { + schedule.add(newSchedule); + } + } + + schedule.sort(Comparator.comparing(ActivateFastFreqReserveSchedule::startTimestamp)); + return schedule; + } + + /** + * Checks whether a new schedule overlaps with existing schedules or is an exact + * duplicate. + * + * @param schedule List of existing schedules to compare against + * @param newSchedule The new schedule to check for overlap or duplication + * @return {@code true} if the new schedule overlaps with existing schedules or + * is an exact duplicate, {@code false} otherwise + */ + private static boolean overlapsExistingSchedule(List schedule, + ActivateFastFreqReserveSchedule newSchedule) { + for (ActivateFastFreqReserveSchedule existingSchedule : schedule) { + if (newSchedule.equals(existingSchedule)) { + // duplicate found + return true; + } + // Check for overlap + if (newSchedule.startTimestamp < (existingSchedule.startTimestamp + existingSchedule.duration) + && (newSchedule.startTimestamp + newSchedule.duration) > existingSchedule.startTimestamp) { + return true; + } + } + // No overlap or exact duplicate found + return false; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + var that = (ActivateFastFreqReserveSchedule) o; + return this.startTimestamp == that.startTimestamp // + && this.duration == that.duration // + && this.dischargePowerSetPoint == that.dischargePowerSetPoint // + && this.frequencyLimit == that.frequencyLimit // + && this.activationRunTime.equals(that.activationRunTime) // + && this.supportDuration.equals(that.supportDuration); + } + + @Override + public String toString() { + return String.format( + "{\"startTimestamp\":%d, \"duration\":%d, \"dischargePowerSetPoint\":%d, \"frequencyLimit\":%d, \"activationRunTime\":\"%s\", \"supportDuration\":\"%s\"}", + this.startTimestamp, this.duration, this.dischargePowerSetPoint, this.frequencyLimit, + this.activationRunTime, this.supportDuration); + } + + /** + * Converts this ActivateFastFreqReserveSchedule object to a JsonObject. + * + * @return A JsonObject representing this schedule, where each field is mapped + * to a corresponding property with its value. + */ + public JsonObject toJson() { + return JsonUtils.buildJsonObject() // + .addProperty("startTimestamp", this.startTimestamp()) // + .addProperty("duration", this.duration()) // + .addProperty("dischargeActivePowerSetPoint", this.dischargePowerSetPoint()) // + .addProperty("frequencyLimit", this.frequencyLimit()) // + .addProperty("activationRunTime", this.activationRunTime()) // + .addProperty("supportDuration", this.supportDuration()) // + .build(); + } + } +} diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/ActivationTimeHandler.java b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/ActivationTimeHandler.java new file mode 100644 index 00000000000..bdf301e2827 --- /dev/null +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/ActivationTimeHandler.java @@ -0,0 +1,106 @@ +package io.openems.edge.controller.ess.fastfrequencyreserve.statemachine; + +import java.time.Duration; +import java.time.Instant; + +import io.openems.common.exceptions.OpenemsException; +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.utils.EnumUtils; +import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.controller.ess.fastfrequencyreserve.statemachine.StateMachine.State; + +public class ActivationTimeHandler extends StateHandler { + + private static final int ZERO_WATT_POWER = 0; // [0 W] + + protected Instant dipDetectedStartTime; + protected ActivationTimeState activationTimeState; + + private static enum SubState { + INSIDE_TIME_FRAME, // + HANDLE_WAITING_FREQ_DIP, // + HANDLE_FREQ_DIP, // + FINISH_ACTIVATION + } + + protected static record ActivationTimeState(SubState subState, Instant lastChange) { + } + + @Override + protected void onEntry(Context context) throws OpenemsNamedException { + context.ess.setActivePowerEquals(ZERO_WATT_POWER); + this.activationTimeState = new ActivationTimeState(SubState.INSIDE_TIME_FRAME, Instant.now(context.clock)); + } + + @Override + protected State runAndGetNextState(Context context) throws OpenemsNamedException { + final var nextSubState = this.getNextSubState(context); + if (nextSubState != this.activationTimeState.subState) { + this.activationTimeState = new ActivationTimeState(nextSubState, Instant.now(context.clock)); + } + if (nextSubState == SubState.FINISH_ACTIVATION) { + return State.SUPPORT_DURATION; + } + + return State.ACTIVATION_TIME; + } + + private SubState getNextSubState(Context context) throws OpenemsNamedException { + return switch (this.activationTimeState.subState) { + case INSIDE_TIME_FRAME -> + this.isInsideTimeFrame(context) ? SubState.FINISH_ACTIVATION : SubState.HANDLE_WAITING_FREQ_DIP; + case HANDLE_WAITING_FREQ_DIP -> { + if (this.isFrequencyDipped(context)) { + context.ess.setActivePowerEquals(context.dischargePower); + var time = Instant.now(context.clock); + this.clockActivationTime(context, time); + this.dipDetectedStartTime = time; + yield SubState.HANDLE_FREQ_DIP; + } + context.ess.setActivePowerEquals(ZERO_WATT_POWER); + yield SubState.HANDLE_WAITING_FREQ_DIP; + } + case HANDLE_FREQ_DIP -> { + context.ess.setActivePowerEquals(context.dischargePower); + var activationExpirationTime = Duration.between(this.dipDetectedStartTime, Instant.now(context.clock))// + .toMillis(); // + if (activationExpirationTime >= context.activationRunTime.getValue()) { + yield SubState.FINISH_ACTIVATION; + } + yield SubState.HANDLE_FREQ_DIP; + } + case FINISH_ACTIVATION -> SubState.FINISH_ACTIVATION; + }; + } + + /** + * Clocks the activation time and sets it in the context. + * + * @param context the context. + * @param time time in instant + */ + private void clockActivationTime(Context context, Instant time) { + context.setCycleStart(time); + } + + private boolean isFrequencyDipped(Context context) throws OpenemsException { + var meterFrequency = context.meter.getFrequency(); + if (!meterFrequency.isDefined()) { + throw new OpenemsException("meter has no frequency channel defined."); + } + return (meterFrequency.get() < context.freqLimit); + } + + private boolean isInsideTimeFrame(Context context) { + final var now = Instant.now(context.clock).getEpochSecond(); + final var startTimestamp = context.startTimestamp; + final var duration = context.duration; + return now >= startTimestamp + duration; + } + + @Override + protected String debugLog() { + return State.ACTIVATION_TIME.asCamelCase() + "-" + + EnumUtils.nameAsCamelCase(this.activationTimeState.subState()); + } +} diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/BufferedTimeBeforeRecoveryHandler.java b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/BufferedTimeBeforeRecoveryHandler.java new file mode 100644 index 00000000000..23d9ae25b3d --- /dev/null +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/BufferedTimeBeforeRecoveryHandler.java @@ -0,0 +1,103 @@ +package io.openems.edge.controller.ess.fastfrequencyreserve.statemachine; + +import java.time.Duration; +import java.time.Instant; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.utils.EnumUtils; +import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.controller.ess.fastfrequencyreserve.statemachine.StateMachine.State; +import io.openems.edge.ess.api.ManagedSymmetricEss; +import io.openems.edge.ess.power.api.Phase; +import io.openems.edge.ess.power.api.Pwr; + +public class BufferedTimeBeforeRecoveryHandler extends StateHandler { + + private static final int ZERO_WATT_POWER = 0; + private static final int BUFFER_DURATION_THRESHOLD_SECONDS = 15; // [s] + private static final int RECOVERY_DURATION_THRESHOLD_MINUTES = 4; // [minute] + private static final double EIGHTEENX_PERCENT_OF_MAX_POWER = 0.18; // [%] + + protected Instant bufferedTimeBeforeRecoveryStartTime = Instant.MIN; + + protected static record BufferedTimeBeforeRecoveryState(SubState subState, Instant lastChange) { + } + + protected BufferedTimeBeforeRecoveryState bufferedTimeBeforeRecoveryState; + + private static enum SubState { + HOLD_BUFFERED_TIME_BEFORE_RECOVERY, // + BUFFERED_TIME_RECOVERY, // + FINISH_BUFFERED_TIME_BEFORE_RECOVERY + } + + @Override + protected void onEntry(Context context) throws OpenemsNamedException { + context.ess.setActivePowerEquals(ZERO_WATT_POWER); + final var now = Instant.now(context.clock); + this.bufferedTimeBeforeRecoveryStartTime = now; + this.bufferedTimeBeforeRecoveryState = new BufferedTimeBeforeRecoveryState( + SubState.HOLD_BUFFERED_TIME_BEFORE_RECOVERY, now); + + } + + @Override + protected State runAndGetNextState(Context context) throws OpenemsNamedException { + final var nextSubState = this.getNextSubState(context); + + if (nextSubState != this.bufferedTimeBeforeRecoveryState.subState) { + this.bufferedTimeBeforeRecoveryState = new BufferedTimeBeforeRecoveryState(nextSubState, + Instant.now(context.clock)); + } + + if (nextSubState == SubState.FINISH_BUFFERED_TIME_BEFORE_RECOVERY) { + return State.RECOVERY_TIME; + } + + return State.BUFFERED_TIME_BEFORE_RECOVERY; + } + + private SubState getNextSubState(Context context) throws OpenemsNamedException { + return switch (this.bufferedTimeBeforeRecoveryState.subState) { + case HOLD_BUFFERED_TIME_BEFORE_RECOVERY -> { + context.ess.setActivePowerEquals(ZERO_WATT_POWER); + var bufferedDurationExpiration = this.calculateBufferedDurationExpiration(context); + if (bufferedDurationExpiration >= BUFFER_DURATION_THRESHOLD_SECONDS) { + yield SubState.BUFFERED_TIME_RECOVERY; + } + yield SubState.HOLD_BUFFERED_TIME_BEFORE_RECOVERY; + } + case BUFFERED_TIME_RECOVERY -> { + var minPowerEss = this.calculateMinPower(context.ess); + context.ess.setActivePowerEquals(minPowerEss); + var bufferedRecoveryExpiration = this.calculateBufferedRecoveryExpiration(context); + if (bufferedRecoveryExpiration >= RECOVERY_DURATION_THRESHOLD_MINUTES) { + yield SubState.FINISH_BUFFERED_TIME_BEFORE_RECOVERY; + } + yield SubState.BUFFERED_TIME_RECOVERY; + } + case FINISH_BUFFERED_TIME_BEFORE_RECOVERY -> SubState.FINISH_BUFFERED_TIME_BEFORE_RECOVERY; + }; + } + + private long calculateBufferedDurationExpiration(Context context) { + return Duration.between(this.bufferedTimeBeforeRecoveryStartTime, Instant.now(context.clock))// + .toSeconds(); + } + + private long calculateBufferedRecoveryExpiration(Context context) { + return Duration// + .between(context.getCycleStart(), Instant.now(context.clock))// + .toMinutes(); + } + + private int calculateMinPower(ManagedSymmetricEss ess) { + return (int) (ess.getPower().getMinPower(ess, Phase.ALL, Pwr.ACTIVE) * EIGHTEENX_PERCENT_OF_MAX_POWER); + } + + @Override + protected String debugLog() { + return State.BUFFERED_TIME_BEFORE_RECOVERY.asCamelCase() + "-" + + EnumUtils.nameAsCamelCase(this.bufferedTimeBeforeRecoveryState.subState()); + } +} diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/Context.java b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/Context.java new file mode 100644 index 00000000000..cbae7c9ec6e --- /dev/null +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/Context.java @@ -0,0 +1,64 @@ +package io.openems.edge.controller.ess.fastfrequencyreserve.statemachine; + +import java.time.Clock; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; + +import io.openems.edge.common.statemachine.AbstractContext; +import io.openems.edge.controller.ess.fastfrequencyreserve.ControllerFastFrequencyReserve; +import io.openems.edge.controller.ess.fastfrequencyreserve.ControllerFastFrequencyReserveImpl; +import io.openems.edge.controller.ess.fastfrequencyreserve.enums.ActivationTime; +import io.openems.edge.controller.ess.fastfrequencyreserve.enums.SupportDuration; +import io.openems.edge.ess.api.ManagedSymmetricEss; +import io.openems.edge.meter.api.ElectricityMeter; + +public class Context extends AbstractContext { + + protected final Clock clock; + protected final int dischargePower; + protected final long startTimestamp; + protected final int duration; + protected final int freqLimit; + protected final ActivationTime activationRunTime; + protected final SupportDuration supportDuration; + protected final ControllerFastFrequencyReserve parentController; + protected final ManagedSymmetricEss ess; + protected final ElectricityMeter meter; + + protected static Instant _cycleStart; + + public Context(ControllerFastFrequencyReserve fastFrequencyReserve, // + Clock clock, // + ManagedSymmetricEss ess, // + ElectricityMeter meter, // + long startTimestamp, // + int duration, // + int dischargePower, // + int freqLimit, // + ActivationTime activationRunTime, // + SupportDuration supportDuration) { + this.clock = clock; + this.parentController = fastFrequencyReserve; + this.startTimestamp = startTimestamp; + this.duration = duration; + this.dischargePower = dischargePower; + this.freqLimit = freqLimit; + this.ess = ess; + this.meter = meter; + this.activationRunTime = activationRunTime; + this.supportDuration = supportDuration; + } + + public Instant getCycleStart() { + return _cycleStart; + } + + public void setCycleStart(Instant cycleStart) { + LocalDateTime lastTriggered = LocalDateTime.ofInstant(cycleStart, ZoneId.systemDefault()); + String formattedDateTime = lastTriggered.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + this.parentController.setLastTriggeredTime(formattedDateTime); + _cycleStart = cycleStart; + } +} diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/DeactivationTimeHandler.java b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/DeactivationTimeHandler.java new file mode 100644 index 00000000000..aa01cbddbbb --- /dev/null +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/DeactivationTimeHandler.java @@ -0,0 +1,81 @@ +package io.openems.edge.controller.ess.fastfrequencyreserve.statemachine; + +import java.time.Duration; +import java.time.Instant; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.utils.EnumUtils; +import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.controller.ess.fastfrequencyreserve.statemachine.StateMachine.State; + +public class DeactivationTimeHandler extends StateHandler { + + private static final int ZERO_WATT_POWER = 0; //[0 W] + protected Instant deactivationStateStartTime; + + private static enum SubState { + HOLD_DEACTIVATION, // + FINISH_DEACTIVATION_DURATION + } + + protected static record DeactivationTimeState(SubState subState, Instant lastChange) { + } + + protected DeactivationTimeState deactivationTimeState; + + @Override + protected void onEntry(Context context) throws OpenemsNamedException { + context.ess.setActivePowerEquals(ZERO_WATT_POWER); + this.deactivationStateStartTime = Instant.now(context.clock); + this.deactivationTimeState = new DeactivationTimeState(SubState.HOLD_DEACTIVATION, Instant.now(context.clock)); + } + + @Override + protected State runAndGetNextState(Context context) throws OpenemsNamedException { + var nextSubState = this.getNextSubState(context); + if (nextSubState != this.deactivationTimeState.subState) { + this.deactivationTimeState = new DeactivationTimeState(nextSubState, Instant.now(context.clock)); + } + if (nextSubState == SubState.FINISH_DEACTIVATION_DURATION) { + return State.BUFFERED_TIME_BEFORE_RECOVERY; + } + return State.DEACTIVATION_TIME; + } + + private SubState getNextSubState(Context context) throws OpenemsNamedException { + return switch (this.deactivationTimeState.subState) { + + case HOLD_DEACTIVATION -> { + context.ess.setActivePowerEquals(ZERO_WATT_POWER); + var deactivationDurationExpiration = this.calculateDeactivationDurationExpiration(context); + if (deactivationDurationExpiration >= context.activationRunTime.getValue()) { + yield SubState.FINISH_DEACTIVATION_DURATION; + } + yield SubState.HOLD_DEACTIVATION; + } + case FINISH_DEACTIVATION_DURATION -> SubState.FINISH_DEACTIVATION_DURATION; + }; + } + + /** + * Calculates the expiration duration for the deactivation state. The expiration + * duration is the time elapsed between the deactivation state start time and + * the current time, measured in milliseconds. + * + * @param context the Context + * @return The expiration duration in milliseconds. + */ + private long calculateDeactivationDurationExpiration(Context context) { + return Duration.between(// + this.deactivationStateStartTime, // + Instant.now(context.clock))// + .toMillis(); + } + + @Override + protected String debugLog() { + return State.DEACTIVATION_TIME.asCamelCase() + "-" + + EnumUtils.nameAsCamelCase(this.deactivationTimeState.subState()); + } + +} diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/PreActivationHandler.java b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/PreActivationHandler.java new file mode 100644 index 00000000000..86b9d62083e --- /dev/null +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/PreActivationHandler.java @@ -0,0 +1,53 @@ +package io.openems.edge.controller.ess.fastfrequencyreserve.statemachine; + +import java.time.ZonedDateTime; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.controller.ess.fastfrequencyreserve.statemachine.StateMachine.State; +import io.openems.edge.ess.api.ManagedSymmetricEss; +import io.openems.edge.ess.power.api.Phase; +import io.openems.edge.ess.power.api.Pwr; + +public class PreActivationHandler extends StateHandler { + + private static final double EIGHTEENX_PERCENT_OF_MAX_POWER = 0.18; // [%] + + @Override + protected State runAndGetNextState(Context context) throws OpenemsNamedException { + var ess = context.ess; + int minPowerEss = this.calculateMinPower(ess); + + if (this.isActivationTime(context)) { + return State.ACTIVATION_TIME; + } else { + ess.setActivePowerEquals(minPowerEss); + return State.PRE_ACTIVATION_STATE; + } + } + + /** + * Calculates 18% of the minimum power of the given ess. + * + * @param ess The managed symmetric ess. + * @return 18% of the minimum power of the ess. + */ + private int calculateMinPower(ManagedSymmetricEss ess) { + return (int) (ess.getPower().getMinPower(ess, Phase.ALL, Pwr.ACTIVE) * EIGHTEENX_PERCENT_OF_MAX_POWER); + } + + /** + * Checks if the current time, as adjusted by the component manager's clock, is + * within the activation time window. + * + * + * @param context the context + * @return {@code true} if the current time is within the activation time + * window, {@code false} otherwise. + */ + private boolean isActivationTime(Context context) { + var currentEpochSecond = ZonedDateTime.now(context.clock).toEpochSecond(); + return currentEpochSecond >= context.startTimestamp + && currentEpochSecond <= context.startTimestamp + context.duration; + } +} \ No newline at end of file diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/RecoveryTimeHandler.java b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/RecoveryTimeHandler.java new file mode 100644 index 00000000000..d073c55f9cf --- /dev/null +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/RecoveryTimeHandler.java @@ -0,0 +1,29 @@ +package io.openems.edge.controller.ess.fastfrequencyreserve.statemachine; + +import java.time.Duration; +import java.time.Instant; +import java.time.ZonedDateTime; + +import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.controller.ess.fastfrequencyreserve.statemachine.StateMachine.State; + +public class RecoveryTimeHandler extends StateHandler { + + public static final int RECOVERY_DURATION_SECONDS = 15 * 60; + + @Override + protected State runAndGetNextState(Context context) { + if (this.isItWithinDuration(context)) { + return State.ACTIVATION_TIME; + } + return State.RECOVERY_TIME; + } + + private boolean isItWithinDuration(Context context) { + var now = Instant.now(context.clock).getEpochSecond(); + var expiration = Duration// + .between(context.getCycleStart(), ZonedDateTime.now(context.clock))// + .toSeconds(); + return expiration > RECOVERY_DURATION_SECONDS || now >= context.startTimestamp + context.duration; + } +} \ No newline at end of file diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/StateMachine.java b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/StateMachine.java new file mode 100644 index 00000000000..c044760a26f --- /dev/null +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/StateMachine.java @@ -0,0 +1,62 @@ +package io.openems.edge.controller.ess.fastfrequencyreserve.statemachine; + +import io.openems.common.types.OptionsEnum; +import io.openems.edge.common.statemachine.AbstractStateMachine; +import io.openems.edge.common.statemachine.StateHandler; + +public class StateMachine extends AbstractStateMachine { + + public enum State implements io.openems.edge.common.statemachine.State, OptionsEnum { + UNDEFINED(-1), // + PRE_ACTIVATION_STATE(10), // + ACTIVATION_TIME(20), // + SUPPORT_DURATION(30), // + DEACTIVATION_TIME(40), // + BUFFERED_TIME_BEFORE_RECOVERY(50), // + RECOVERY_TIME(60);// + + private final int value; + + private State(int value) { + this.value = value; + } + + @Override + public int getValue() { + return this.value; + } + + @Override + public OptionsEnum getUndefined() { + return UNDEFINED; + } + + @Override + public String getName() { + return this.name(); + } + + @Override + public State[] getStates() { + return State.values(); + } + + } + + public StateMachine(State initialState) { + super(initialState); + } + + @Override + public StateHandler getStateHandler(State state) { + return switch (state) { + case ACTIVATION_TIME -> new ActivationTimeHandler(); + case BUFFERED_TIME_BEFORE_RECOVERY -> new BufferedTimeBeforeRecoveryHandler(); + case DEACTIVATION_TIME -> new DeactivationTimeHandler(); + case PRE_ACTIVATION_STATE -> new PreActivationHandler(); + case RECOVERY_TIME -> new RecoveryTimeHandler(); + case SUPPORT_DURATION -> new SupportDurationTimeHandler(); + case UNDEFINED -> new UndefinedHandler(); + }; + } +} \ No newline at end of file diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/SupportDurationTimeHandler.java b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/SupportDurationTimeHandler.java new file mode 100644 index 00000000000..a5d5131c8e0 --- /dev/null +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/SupportDurationTimeHandler.java @@ -0,0 +1,64 @@ +package io.openems.edge.controller.ess.fastfrequencyreserve.statemachine; + +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDateTime; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.controller.ess.fastfrequencyreserve.statemachine.StateMachine.State; + +public class SupportDurationTimeHandler extends StateHandler { + + protected LocalDateTime supportDurationStartTime; + + private static enum SubState { + HOLD_SUPPORT, // + FINISH_SUPPORT_DURATION + } + + protected static record SupportDurationTimeState(SubState subState, Instant lastChange) { + } + + protected SupportDurationTimeState supportDurationTimeState; + + @Override + protected void onEntry(Context context) throws OpenemsNamedException { + context.ess.setActivePowerEquals(context.dischargePower); + this.supportDurationStartTime = LocalDateTime.now(context.clock); + this.supportDurationTimeState = new SupportDurationTimeState(SubState.HOLD_SUPPORT, Instant.now(context.clock)); + } + + @Override + protected State runAndGetNextState(Context context) throws OpenemsNamedException { + final var nextSubState = this.getNextSubState(context); + if (nextSubState != this.supportDurationTimeState.subState) { + this.supportDurationTimeState = new SupportDurationTimeState(nextSubState, Instant.now(context.clock)); + } + if (nextSubState == SubState.FINISH_SUPPORT_DURATION) { + return State.DEACTIVATION_TIME; + } + return State.SUPPORT_DURATION; + } + + private SubState getNextSubState(Context context) throws OpenemsNamedException { + return switch (this.supportDurationTimeState.subState) { + case HOLD_SUPPORT -> { + context.ess.setActivePowerEquals(context.dischargePower); + var supportDurationExpiration = this.calculateSupportDurationExpiration(context); + if (supportDurationExpiration >= context.supportDuration.getValue()) { + yield SubState.FINISH_SUPPORT_DURATION; + } + yield SubState.HOLD_SUPPORT; + } + case FINISH_SUPPORT_DURATION -> SubState.FINISH_SUPPORT_DURATION; + }; + } + + private long calculateSupportDurationExpiration(Context context) { + return Duration.between(// + this.supportDurationStartTime, // + LocalDateTime.now(context.clock))// + .getSeconds(); + } +} diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/UndefinedHandler.java b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/UndefinedHandler.java new file mode 100644 index 00000000000..513a119914a --- /dev/null +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/UndefinedHandler.java @@ -0,0 +1,40 @@ +package io.openems.edge.controller.ess.fastfrequencyreserve.statemachine; + +import java.time.ZonedDateTime; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.controller.ess.fastfrequencyreserve.statemachine.StateMachine.State; + +public class UndefinedHandler extends StateHandler { + + public static final int FIFTEEN_MINUTES_IN_SECONDS = 15 * 60; // 15 minutes in seconds + + @Override + protected State runAndGetNextState(Context context) throws OpenemsNamedException { + if (this.isPreActivationTime(context)) { + return State.PRE_ACTIVATION_STATE; + } else { + return State.UNDEFINED; + } + } + + /** + * Checks if the current time, as adjusted by the component manager's clock, is + * within the pre-activation time window. pre-activation time window is 15 + * minutes before the start time. + * + * @param context the context + * @return {@code true} if the current time is within the activation time + * window, {@code false} otherwise. + */ + private boolean isPreActivationTime(Context context) { + var currentDateTime = ZonedDateTime.now(context.clock); + var currentEpochSecond = currentDateTime.toEpochSecond(); + if (currentEpochSecond >= context.startTimestamp - FIFTEEN_MINUTES_IN_SECONDS + && currentEpochSecond <= context.startTimestamp + context.duration) { + return true; + } + return false; + } +} diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/test/.gitignore b/io.openems.edge.controller.ess.fastfrequencyreserve/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/JsonRpcTest.java b/io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/JsonRpcTest.java new file mode 100644 index 00000000000..c0db3e9a28d --- /dev/null +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/JsonRpcTest.java @@ -0,0 +1,68 @@ +package io.openems.edge.controller.ess.fastfrequencyreserve; + +import java.net.URI; +//import org.junit.Test; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +import io.openems.edge.controller.ess.fastfrequencyreserve.enums.ActivationTime; +import io.openems.edge.controller.ess.fastfrequencyreserve.enums.SupportDuration; +import io.openems.edge.controller.ess.fastfrequencyreserve.jsonrpc.SetActivateFastFreqReserveRequest; +import io.openems.edge.controller.ess.fastfrequencyreserve.jsonrpc.SetActivateFastFreqReserveRequest.ActivateFastFreqReserveSchedule; + +/** + * This Test demonstrates the usage of the OpenEMS Backend-to-Backend API + * interface. To start the tests make sure to start OpenEMS Backend and activate + * the B2bWebsocket component via Apache Felix. Afterwards uncomment the "@Test" + * annotations below and execute the Tests. + */ +public class JsonRpcTest { + + private static final String URI = "ws://localhost:8076"; + private static final String USERNAME = "user"; + private static final String PASSWORD = "password"; + + private static TestClient prepareTestClient() throws URISyntaxException, InterruptedException { + Map httpHeaders = new HashMap<>(); + var auth = new String( + Base64.getEncoder().encode((JsonRpcTest.USERNAME + ":" + JsonRpcTest.PASSWORD).getBytes()), + StandardCharsets.UTF_8); + httpHeaders.put("Authorization", "Basic " + auth); + var client = new TestClient(new URI(JsonRpcTest.URI), httpHeaders); + client.startBlocking(); + return client; + } + + /** + * Tests the activation of Fast Frequency Reserve schedule. + * + * @throws URISyntaxException String could not be parsed as a URI reference. + * @throws InterruptedException interrupted exception. + */ + // @Test + public void testActivateFastFreqReserveSchedule() throws URISyntaxException, InterruptedException { + var client = JsonRpcTest.prepareTestClient(); + + var request = new SetActivateFastFreqReserveRequest("edge0"); + var now = System.currentTimeMillis() / 1000; + ActivateFastFreqReserveSchedule newEntry = new ActivateFastFreqReserveSchedule(// + now, // + 1000, // + 92000, // + 50000, // + ActivationTime.LONG_ACTIVATION_RUN, // + SupportDuration.LONG_SUPPORT_DURATION); + request.addScheduleEntry(newEntry); + + try { + var responseFuture = client.sendRequest(request); + System.out.println(responseFuture.get().toString()); + } catch (Exception e) { + System.out.println(e.getMessage()); + } + } + +} diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/MyConfig.java b/io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/MyConfig.java new file mode 100644 index 00000000000..efc5087e1f3 --- /dev/null +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/MyConfig.java @@ -0,0 +1,107 @@ +package io.openems.edge.controller.ess.fastfrequencyreserve; + +import io.openems.common.test.AbstractComponentConfig; +import io.openems.common.utils.ConfigUtils; +import io.openems.edge.controller.ess.fastfrequencyreserve.enums.ActivationTime; +import io.openems.edge.controller.ess.fastfrequencyreserve.enums.ControlMode; +import io.openems.edge.controller.ess.fastfrequencyreserve.enums.SupportDuration; + +@SuppressWarnings("all") +public class MyConfig extends AbstractComponentConfig implements Config { + + protected static class Builder { + private String id; + private String essId; + private String meterId; + private ControlMode mode; + private String activationScheduleJson; + private int preActivationTime; + + public Builder setId(String id) { + this.id = id; + return this; + } + + public Builder setEssId(String essId) { + this.essId = essId; + return this; + } + + public Builder setMeterId(String meterId) { + this.meterId = meterId; + return this; + } + + public Builder setMode(ControlMode mode) { + this.mode = mode; + return this; + } + + public Builder setactivationScheduleJson(String schedule) { + this.activationScheduleJson = schedule; + return this; + } + + public Builder setPreActivationTime(int preActivationTime) { + this.preActivationTime = preActivationTime; + return this; + } + + public MyConfig build() { + return new MyConfig(this); + } + + } + + /** + * Create a Config builder. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new Builder(); + } + + private final Builder builder; + + private MyConfig(Builder builder) { + super(Config.class, builder.id); + this.builder = builder; + } + + @Override + public String ess_id() { + return this.builder.essId; + } + + @Override + public String meter_id() { + return this.builder.meterId; + } + + @Override + public String ess_target() { + return ConfigUtils.generateReferenceTargetFilter(this.id(), this.ess_id()); + } + + @Override + public String meter_target() { + return ConfigUtils.generateReferenceTargetFilter(this.id(), this.meter_id()); + } + + @Override + public ControlMode controlMode() { + return this.builder.mode; + } + + @Override + public String activationScheduleJson() { + return this.builder.activationScheduleJson; + } + + @Override + public int preActivationTime() { + return this.builder.preActivationTime; + } + +} diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/MyControllerTest.java b/io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/MyControllerTest.java new file mode 100644 index 00000000000..942975af03b --- /dev/null +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/MyControllerTest.java @@ -0,0 +1,295 @@ +package io.openems.edge.controller.ess.fastfrequencyreserve; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.temporal.ChronoUnit; +import java.util.List; + +import org.junit.Test; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.test.TimeLeapClock; +import io.openems.common.types.ChannelAddress; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.common.sum.GridMode; +import io.openems.edge.common.test.AbstractComponentTest.TestCase; +import io.openems.edge.common.test.DummyComponentManager; +import io.openems.edge.common.test.DummyConfigurationAdmin; +import io.openems.edge.controller.ess.fastfrequencyreserve.enums.ActivationTime; +import io.openems.edge.controller.ess.fastfrequencyreserve.enums.ControlMode; +import io.openems.edge.controller.ess.fastfrequencyreserve.enums.SupportDuration; +import io.openems.edge.controller.ess.fastfrequencyreserve.jsonrpc.SetActivateFastFreqReserveRequest.ActivateFastFreqReserveSchedule; +import io.openems.edge.controller.ess.fastfrequencyreserve.statemachine.StateMachine.State; +import io.openems.edge.controller.test.ControllerTest; +import io.openems.edge.ess.test.DummyManagedSymmetricEss; +import io.openems.edge.meter.test.DummyElectricityMeter; + +public class MyControllerTest { + + private static final String CTRL_ID = "ctrl0"; + private static final String ESS_ID = "ess0"; + private static final String METER_ID = "meter0"; + + private static final DummyManagedSymmetricEss ESS = new DummyManagedSymmetricEss(ESS_ID); + private static final DummyElectricityMeter METER = new DummyElectricityMeter(METER_ID); + + private static final ChannelAddress METER_FREQUENCY = new ChannelAddress(METER_ID, "Frequency"); + private static final ChannelAddress STATE_MACHINE = new ChannelAddress(CTRL_ID, "StateMachine"); + private static final ChannelAddress ESS_ACTIVE_POWER = new ChannelAddress(ESS_ID, "SetActivePowerEquals"); + + @Test + public void testFfrController() throws Exception { + final var clock = new TimeLeapClock(Instant.parse("2023-07-13T08:45:00.00Z"), ZoneOffset.UTC); + + final var cm = new DummyComponentManager(clock); + + new ControllerTest(new ControllerFastFrequencyReserveImpl()) // + + .addReference("componentManager", cm) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("ess", ESS // + .withGridMode(GridMode.ON_GRID)// + .withMaxApparentPower(92000)// + .withAllowedChargePower(-92000)// + .withAllowedDischargePower(92000)) // + .addReference("meter", METER) // + .activate(MyConfig.create() // + .setEssId(ESS_ID) // + .setId(CTRL_ID) // + .setMeterId(METER_ID) // + .setMode(ControlMode.MANUAL_ON) // + .setPreActivationTime(15)// + .setactivationScheduleJson(JsonUtils.buildJsonArray() // + .add(JsonUtils.buildJsonObject() // + .addProperty("startTimestamp", 1689242400) // Thu Jul 13 2023 10:00:00 GMT+0000 + .addProperty("duration", 86400) // + .addProperty("dischargePowerSetPoint", 92000) // + .addProperty("frequencyLimit", 49500) // + .addProperty("activationRunTime", ActivationTime.LONG_ACTIVATION_RUN) // + .addProperty("supportDuration", SupportDuration.LONG_SUPPORT_DURATION) // + .build()) + .add(JsonUtils.buildJsonObject() // + .addProperty("startTimestamp", 1689331500) // Fri Jul 14 2023 10:45:00 GMT+0000 + .addProperty("duration", 86400) // + .addProperty("dischargePowerSetPoint", 92000) // + .addProperty("frequencyLimit", 49500) // + .addProperty("activationRunTime", ActivationTime.LONG_ACTIVATION_RUN) // + .addProperty("supportDuration", SupportDuration.LONG_SUPPORT_DURATION) // + .build()) + .build()// + .toString())// + .build()) + .next(new TestCase("1") // + .input(METER_FREQUENCY, 50000)// + .output(STATE_MACHINE, State.UNDEFINED) // + .output(ESS_ACTIVE_POWER, null))// + .next(new TestCase("2") // + .input(METER_FREQUENCY, 50000)// + .output(STATE_MACHINE, State.UNDEFINED) // + .output(ESS_ACTIVE_POWER, null))// + .next(new TestCase("3") // + .timeleap(clock, 1, ChronoUnit.HOURS) // + .input(METER_FREQUENCY, 50000))// + .next(new TestCase("4"))// + .next(new TestCase("5") // + .output(STATE_MACHINE, State.UNDEFINED)) + .next(new TestCase("6") // + .timeleap(clock, 10, ChronoUnit.MINUTES)// + .output(STATE_MACHINE, State.PRE_ACTIVATION_STATE)) + .next(new TestCase("7") // + .timeleap(clock, 10, ChronoUnit.MINUTES)) + .next(new TestCase("8") // + .output(STATE_MACHINE, State.ACTIVATION_TIME)// + .output(ESS_ACTIVE_POWER, 0)) + .next(new TestCase("9") // + .input(METER_FREQUENCY, 50000)// + .output(STATE_MACHINE, State.ACTIVATION_TIME)// + .output(ESS_ACTIVE_POWER, 0)) + .next(new TestCase("10") // + .input(METER_FREQUENCY, 49400)// + .output(STATE_MACHINE, State.ACTIVATION_TIME)// + .output(ESS_ACTIVE_POWER, 92000)) + .next(new TestCase("11") // + .timeleap(clock, ActivationTime.LONG_ACTIVATION_RUN.getValue(), ChronoUnit.MILLIS)) // + .next(new TestCase("12") // + .output(STATE_MACHINE, State.SUPPORT_DURATION)// + .output(ESS_ACTIVE_POWER, 92000)) // + .next(new TestCase("13") // + .timeleap(clock, SupportDuration.LONG_SUPPORT_DURATION.getValue(), ChronoUnit.SECONDS) // + .output(STATE_MACHINE, State.SUPPORT_DURATION)) + .next(new TestCase("14") // + .output(STATE_MACHINE, State.DEACTIVATION_TIME).output(ESS_ACTIVE_POWER, 0)) + .next(new TestCase("15") // + .timeleap(clock, ActivationTime.LONG_ACTIVATION_RUN.getValue(), ChronoUnit.MILLIS)) // + .next(new TestCase("16") // + .output(STATE_MACHINE, State.BUFFERED_TIME_BEFORE_RECOVERY) // + .output(ESS_ACTIVE_POWER, 0)) + .next(new TestCase("17") // + .timeleap(clock, 16, ChronoUnit.SECONDS) // + .output(STATE_MACHINE, State.BUFFERED_TIME_BEFORE_RECOVERY)) + .next(new TestCase("18") // + .timeleap(clock, 12, ChronoUnit.MINUTES)) // + .next(new TestCase("19") // + .output(STATE_MACHINE, State.RECOVERY_TIME) // + .output(ESS_ACTIVE_POWER, -16560)) + .next(new TestCase("20") // + .output(STATE_MACHINE, State.RECOVERY_TIME)) + .next(new TestCase("21") // + .output(STATE_MACHINE, State.RECOVERY_TIME)) + .next(new TestCase("22") // + .timeleap(clock, SupportDuration.LONG_SUPPORT_DURATION.getValue(), ChronoUnit.MINUTES)) + .next(new TestCase("23") // + .input(METER_FREQUENCY, 50000)// + .output(STATE_MACHINE, State.ACTIVATION_TIME)) + .next(new TestCase("24") // + .timeleap(clock, 1, ChronoUnit.DAYS)) // + .next(new TestCase("25") // + .output(STATE_MACHINE, State.ACTIVATION_TIME)) + .next(new TestCase("26") // + .timeleap(clock, 4, ChronoUnit.HOURS)) // + .next(new TestCase("27") // + .output(STATE_MACHINE, State.ACTIVATION_TIME)) + .next(new TestCase("28")// + .input(METER_FREQUENCY, 49400)) + .next(new TestCase("29") // + .timeleap(clock, ActivationTime.LONG_ACTIVATION_RUN.getValue(), ChronoUnit.MILLIS)) // + .next(new TestCase("30") // + .output(STATE_MACHINE, State.SUPPORT_DURATION)// + .output(ESS_ACTIVE_POWER, 92000)) // + .next(new TestCase("31") // + .timeleap(clock, ActivationTime.LONG_ACTIVATION_RUN.getValue(), ChronoUnit.MILLIS)) // + .next(new TestCase("32") // + .output(STATE_MACHINE, State.SUPPORT_DURATION)// + .output(ESS_ACTIVE_POWER, 92000)) // + .next(new TestCase("33") // + .timeleap(clock, SupportDuration.LONG_SUPPORT_DURATION.getValue(), ChronoUnit.SECONDS) // + .output(STATE_MACHINE, State.SUPPORT_DURATION)) + .next(new TestCase("34") // + .output(STATE_MACHINE, State.DEACTIVATION_TIME).output(ESS_ACTIVE_POWER, 0)) + .next(new TestCase("35") // + .timeleap(clock, ActivationTime.LONG_ACTIVATION_RUN.getValue(), ChronoUnit.MILLIS)) // + .next(new TestCase("36") // + .output(STATE_MACHINE, State.BUFFERED_TIME_BEFORE_RECOVERY) // + .output(ESS_ACTIVE_POWER, 0)) + .next(new TestCase("37") // + .output(STATE_MACHINE, State.BUFFERED_TIME_BEFORE_RECOVERY)) + .next(new TestCase("38") // + .output(STATE_MACHINE, State.BUFFERED_TIME_BEFORE_RECOVERY)) + .next(new TestCase("39") // + .timeleap(clock, SupportDuration.LONG_SUPPORT_DURATION.getValue(), ChronoUnit.MINUTES)) + .next(new TestCase("40") // + .input(METER_FREQUENCY, 50000)// + .output(STATE_MACHINE, State.BUFFERED_TIME_BEFORE_RECOVERY)) + .next(new TestCase("41") // + .input(METER_FREQUENCY, 50000)// + .output(STATE_MACHINE, State.RECOVERY_TIME)) + .next(new TestCase("42") // + .timeleap(clock, 1, ChronoUnit.DAYS)); + } + + @Test + public void testInvalidJsonSchedule() throws Exception { + final var clock = new TimeLeapClock(Instant.parse("2023-07-13T08:45:00.00Z"), ZoneOffset.UTC); + + final var cm = new DummyComponentManager(clock); + + new ControllerTest(new ControllerFastFrequencyReserveImpl()) // + .addReference("componentManager", cm) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("ess", ESS // + .withGridMode(GridMode.ON_GRID)// + .withMaxApparentPower(92000)// + .withAllowedChargePower(-92000)// + .withAllowedDischargePower(92000)) // + .addReference("meter", METER) // + .activate(MyConfig.create() // + .setEssId(ESS_ID) // + .setId(CTRL_ID) // + .setMeterId(METER_ID) // + .setMode(ControlMode.MANUAL_ON) // + .setPreActivationTime(15)// + .setactivationScheduleJson("foo")// + .build()); + } + + @Test + public void testInvalidJsonSchedule1() throws Exception { + final var clock = new TimeLeapClock(Instant.parse("2023-07-13T08:45:00.00Z"), ZoneOffset.UTC); + + final var cm = new DummyComponentManager(clock); + + new ControllerTest(new ControllerFastFrequencyReserveImpl()) // + .addReference("componentManager", cm) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("ess", ESS // + .withGridMode(GridMode.ON_GRID)// + .withMaxApparentPower(92000)// + .withAllowedChargePower(-92000)// + .withAllowedDischargePower(92000)) // + .addReference("meter", METER) // + .activate(MyConfig.create() // + .setEssId(ESS_ID) // + .setId(CTRL_ID) // + .setMeterId(METER_ID) // + .setMode(ControlMode.MANUAL_ON) // + .setPreActivationTime(15)// + .setactivationScheduleJson("[foo]")// + .build()); + + } + + public static final String myJson = "[\r\n" + " " // + + "{\r\n" + " " // + + "\"startTimestamp\": \"1701738000\",\r\n"// + + " \"duration\": \"10800\",\r\n" // + + " \"dischargePowerSetPoint\": \"92000\",\r\n"// + + " \"frequencyLimit\": \"50000\",\r\n"// + + " \"activationRunTime\": \"LONG_ACTIVATION_RUN\",\r\n"// + + " \"supportDuration\": \"LONG_SUPPORT_DURATION\"\r\n" // + + " },\r\n" // + + "{\r\n" + " " // + + "\"startTimestamp\": \"1701738000\",\r\n"// + + " \"duration\": \"10800\",\r\n" // + + " \"dischargePowerSetPoint\": \"92000\",\r\n"// + + " \"frequencyLimit\": \"50000\",\r\n"// + + " \"activationRunTime\": \"LONG_ACTIVATION_RUN\",\r\n"// + + " \"supportDuration\": \"LONG_SUPPORT_DURATION\"\r\n" // + + " },\r\n" // + + " {\r\n"// + + " \"startTimestamp\": \"1701752400\",\r\n"// + + " \"duration\": \"10800\",\r\n"// + + " \"dischargePowerSetPoint\": \"92000\",\r\n"// + + " \"frequencyLimit\": \"50000\",\r\n"// + + " \"activationRunTime\": \"LONG_ACTIVATION_RUN\",\r\n"// + + " \"supportDuration\": \"LONG_SUPPORT_DURATION\"\r\n" // + + " },\r\n" // + + " {\r\n"// + + " \"startTimestamp\": \"1701777600\",\r\n"// + + " \"duration\": \"10800\",\r\n"// + + " \"dischargePowerSetPoint\": \"92000\",\r\n"// + + " \"frequencyLimit\": \"50000\",\r\n"// + + " \"activationRunTime\": \"LONG_ACTIVATION_RUN\",\r\n"// + + " \"supportDuration\": \"LONG_SUPPORT_DURATION\"\r\n" // + + " }\r\n" + "]";// + + @Test + public void testFromMethod() throws OpenemsNamedException { + + var scheduleElement = JsonUtils.parse(myJson); + var scheduleArray = JsonUtils.getAsJsonArray(scheduleElement); + + try { + List scheduleList = ActivateFastFreqReserveSchedule.from(scheduleArray); + + assertEquals(3, scheduleList.size()); + assertTrue(scheduleList.get(0).startTimestamp() <= scheduleList.get(1).startTimestamp()); + assertTrue(scheduleList.get(1).startTimestamp() <= scheduleList.get(2).startTimestamp()); + + } catch (OpenemsNamedException e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/MyControllerTest2.java b/io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/MyControllerTest2.java new file mode 100644 index 00000000000..69fc5e7e463 --- /dev/null +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/MyControllerTest2.java @@ -0,0 +1,185 @@ +package io.openems.edge.controller.ess.fastfrequencyreserve; + +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.temporal.ChronoUnit; + +import org.junit.Test; + +import io.openems.common.test.TimeLeapClock; +import io.openems.common.types.ChannelAddress; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.common.sum.GridMode; +import io.openems.edge.common.test.AbstractComponentTest.TestCase; +import io.openems.edge.common.test.DummyComponentManager; +import io.openems.edge.common.test.DummyConfigurationAdmin; +import io.openems.edge.controller.ess.fastfrequencyreserve.enums.ActivationTime; +import io.openems.edge.controller.ess.fastfrequencyreserve.enums.ControlMode; +import io.openems.edge.controller.ess.fastfrequencyreserve.enums.SupportDuration; +import io.openems.edge.controller.ess.fastfrequencyreserve.statemachine.StateMachine.State; +import io.openems.edge.controller.test.ControllerTest; +import io.openems.edge.ess.test.DummyManagedSymmetricEss; +import io.openems.edge.meter.test.DummyElectricityMeter; + +public class MyControllerTest2 { + + private static final String CTRL_ID = "ctrl0"; + private static final String ESS_ID = "ess0"; + private static final String METER_ID = "meter0"; + + private static final DummyManagedSymmetricEss ESS = new DummyManagedSymmetricEss(ESS_ID); + private static final DummyElectricityMeter METER = new DummyElectricityMeter(METER_ID); + + private static final ChannelAddress METER_FREQUENCY = new ChannelAddress(METER_ID, "Frequency"); + private static final ChannelAddress STATE_MACHINE = new ChannelAddress(CTRL_ID, "StateMachine"); + private static final ChannelAddress ESS_ACTIVE_POWER = new ChannelAddress(ESS_ID, "SetActivePowerEquals"); + + @Test + public void test1() throws Exception { + final var clock = new TimeLeapClock(Instant.parse("2023-07-13T08:45:00.00Z"), ZoneOffset.UTC); + final var cm = new DummyComponentManager(clock); + + new ControllerTest(new ControllerFastFrequencyReserveImpl()) // + .addReference("componentManager", cm) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("ess", ESS // + .withGridMode(GridMode.ON_GRID)// + .withMaxApparentPower(92000)// + .withAllowedChargePower(-92000)// + .withAllowedDischargePower(92000)) // + .addReference("meter", METER) // + .activate(MyConfig.create() // + .setEssId(ESS_ID) // + .setId(CTRL_ID) // + .setMeterId(METER_ID) // + .setMode(ControlMode.MANUAL_ON) // + .setPreActivationTime(15)// + .setactivationScheduleJson(JsonUtils.buildJsonArray() // + .add(JsonUtils.buildJsonObject() // + .addProperty("startTimestamp", 1689242400) // Thu Jul 13 2023 10:00:00 GMT+0000 + .addProperty("duration", 86400) // + .addProperty("dischargePowerSetPoint", 92000) // + .addProperty("frequencyLimit", 49500) // + .addProperty("activationRunTime", ActivationTime.LONG_ACTIVATION_RUN) // + .addProperty("supportDuration", SupportDuration.LONG_SUPPORT_DURATION) // + .build()) + .add(JsonUtils.buildJsonObject() // + .addProperty("startTimestamp", 1689331500) // Fri Jul 14 2023 10:45:00 GMT+0000 + .addProperty("duration", 86400) // + .addProperty("dischargePowerSetPoint", 92000) // + .addProperty("frequencyLimit", 49500) // + .addProperty("activationRunTime", ActivationTime.LONG_ACTIVATION_RUN) // + .addProperty("supportDuration", SupportDuration.LONG_SUPPORT_DURATION) // + .build()) + .build()// + .toString())// + .build()) + .next(new TestCase("1") // + .input(METER_FREQUENCY, 50000)// + .output(STATE_MACHINE, State.UNDEFINED) // + .output(ESS_ACTIVE_POWER, null))// + .next(new TestCase("2") // + .input(METER_FREQUENCY, 50000)// + .output(STATE_MACHINE, State.UNDEFINED) // + .output(ESS_ACTIVE_POWER, null))// + .next(new TestCase("3") // + .timeleap(clock, 1, ChronoUnit.HOURS) // + .input(METER_FREQUENCY, 50000))// + .next(new TestCase("4"))// + .next(new TestCase("5") // + .output(STATE_MACHINE, State.UNDEFINED)) + .next(new TestCase("6") // + .timeleap(clock, 10, ChronoUnit.MINUTES)// + .output(STATE_MACHINE, State.PRE_ACTIVATION_STATE)) + .next(new TestCase("7") // + .timeleap(clock, 10, ChronoUnit.MINUTES)) + .next(new TestCase("8") // + .output(STATE_MACHINE, State.ACTIVATION_TIME)// + .output(ESS_ACTIVE_POWER, 0)) + .next(new TestCase("9") // + .input(METER_FREQUENCY, 50000)// + .output(STATE_MACHINE, State.ACTIVATION_TIME)// + .output(ESS_ACTIVE_POWER, 0)) + .next(new TestCase("10") // + .input(METER_FREQUENCY, 49400)// + .output(STATE_MACHINE, State.ACTIVATION_TIME)// + .output(ESS_ACTIVE_POWER, 92000)) + .next(new TestCase("11") // + .timeleap(clock, ActivationTime.LONG_ACTIVATION_RUN.getValue(), ChronoUnit.MILLIS)) // + .next(new TestCase("12") // + .output(STATE_MACHINE, State.SUPPORT_DURATION)// + .output(ESS_ACTIVE_POWER, 92000)) // + .next(new TestCase("13") // + .timeleap(clock, SupportDuration.LONG_SUPPORT_DURATION.getValue(), ChronoUnit.SECONDS) // + .output(STATE_MACHINE, State.SUPPORT_DURATION)) + .next(new TestCase("14") // + .output(STATE_MACHINE, State.DEACTIVATION_TIME).output(ESS_ACTIVE_POWER, 0)) + .next(new TestCase("15") // + .timeleap(clock, ActivationTime.LONG_ACTIVATION_RUN.getValue(), ChronoUnit.MILLIS)) // + .next(new TestCase("16") // + .output(STATE_MACHINE, State.BUFFERED_TIME_BEFORE_RECOVERY) // + .output(ESS_ACTIVE_POWER, 0)) + .next(new TestCase("17") // + .timeleap(clock, 16, ChronoUnit.SECONDS) // + .output(STATE_MACHINE, State.BUFFERED_TIME_BEFORE_RECOVERY)) + .next(new TestCase("18") // + .timeleap(clock, 12, ChronoUnit.MINUTES)) // + .next(new TestCase("19") // + .output(STATE_MACHINE, State.RECOVERY_TIME) // + .output(ESS_ACTIVE_POWER, -16560)) + .next(new TestCase("20") // + .output(STATE_MACHINE, State.RECOVERY_TIME)) + .next(new TestCase("21") // + .output(STATE_MACHINE, State.RECOVERY_TIME)) + .next(new TestCase("22") // + .timeleap(clock, SupportDuration.LONG_SUPPORT_DURATION.getValue(), ChronoUnit.MINUTES)) + .next(new TestCase("23") // + .input(METER_FREQUENCY, 50000)// + .output(STATE_MACHINE, State.ACTIVATION_TIME)) + .next(new TestCase("24") // + .timeleap(clock, 1, ChronoUnit.DAYS)) // + .next(new TestCase("25") // + .output(STATE_MACHINE, State.ACTIVATION_TIME)) + .next(new TestCase("26") // + .timeleap(clock, 4, ChronoUnit.HOURS)) // + .next(new TestCase("27") // + .output(STATE_MACHINE, State.ACTIVATION_TIME)) + .next(new TestCase("28")// + .input(METER_FREQUENCY, 49400)) + .next(new TestCase("29") // + .timeleap(clock, ActivationTime.LONG_ACTIVATION_RUN.getValue(), ChronoUnit.MILLIS)) // + .next(new TestCase("30") // + .output(STATE_MACHINE, State.SUPPORT_DURATION)// + .output(ESS_ACTIVE_POWER, 92000)) // + .next(new TestCase("31") // + .timeleap(clock, ActivationTime.LONG_ACTIVATION_RUN.getValue(), ChronoUnit.MILLIS)) // + .next(new TestCase("32") // + .output(STATE_MACHINE, State.SUPPORT_DURATION)// + .output(ESS_ACTIVE_POWER, 92000)) // + .next(new TestCase("33") // + .timeleap(clock, SupportDuration.LONG_SUPPORT_DURATION.getValue(), ChronoUnit.SECONDS) // + .output(STATE_MACHINE, State.SUPPORT_DURATION)) + .next(new TestCase("34") // + .output(STATE_MACHINE, State.DEACTIVATION_TIME).output(ESS_ACTIVE_POWER, 0)) + .next(new TestCase("35") // + .timeleap(clock, ActivationTime.LONG_ACTIVATION_RUN.getValue(), ChronoUnit.MILLIS)) // + .next(new TestCase("36") // + .output(STATE_MACHINE, State.BUFFERED_TIME_BEFORE_RECOVERY) // + .output(ESS_ACTIVE_POWER, 0)) + .next(new TestCase("37") // + .output(STATE_MACHINE, State.BUFFERED_TIME_BEFORE_RECOVERY)) + .next(new TestCase("38") // + .output(STATE_MACHINE, State.BUFFERED_TIME_BEFORE_RECOVERY)) + .next(new TestCase("39") // + .timeleap(clock, SupportDuration.LONG_SUPPORT_DURATION.getValue(), ChronoUnit.MINUTES)) + .next(new TestCase("40") // + .input(METER_FREQUENCY, 50000)// + .output(STATE_MACHINE, State.BUFFERED_TIME_BEFORE_RECOVERY)) + .next(new TestCase("41") // + .input(METER_FREQUENCY, 50000)// + .output(STATE_MACHINE, State.RECOVERY_TIME)) + .next(new TestCase("42") // + .timeleap(clock, 1, ChronoUnit.DAYS)); + } + +} diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/TestClient.java b/io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/TestClient.java new file mode 100644 index 00000000000..991887efda7 --- /dev/null +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/TestClient.java @@ -0,0 +1,122 @@ +package io.openems.edge.controller.ess.fastfrequencyreserve; + +import java.net.URI; +import java.util.Map; + +import org.java_websocket.WebSocket; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.openems.common.websocket.AbstractWebsocketClient; +import io.openems.common.websocket.OnClose; +import io.openems.common.websocket.OnError; +import io.openems.common.websocket.OnNotification; +import io.openems.common.websocket.OnOpen; +import io.openems.common.websocket.OnRequest; +import io.openems.common.websocket.WsData; + +public class TestClient extends AbstractWebsocketClient { + + private final Logger log = LoggerFactory.getLogger(TestClient.class); + + private OnOpen onOpen; + private OnRequest onRequest; + private OnNotification onNotification; + private OnError onError; + private OnClose onClose; + + protected TestClient(URI serverUri, Map httpHeaders) { + super("JsonTest.Unittest", serverUri, httpHeaders); + this.onOpen = (ws, handshake) -> { + return null; + }; + this.onRequest = (ws, request) -> { + this.log.info("OnRequest: " + request); + return null; + }; + this.onNotification = (ws, notification) -> { + this.log.info("OnNotification: " + notification); + }; + this.onError = (ws, ex) -> { + this.log.info("onError: " + ex.getMessage()); + }; + this.onClose = (ws, code, reason, remote) -> { + this.log.info("onClose: " + reason); + }; + } + + @Override + public OnOpen getOnOpen() { + return this.onOpen; + } + + public void setOnOpen(OnOpen onOpen) { + this.onOpen = onOpen; + } + + @Override + public OnRequest getOnRequest() { + return this.onRequest; + } + + public void setOnRequest(OnRequest onRequest) { + this.onRequest = onRequest; + } + + @Override + public OnError getOnError() { + return this.onError; + } + + public void setOnError(OnError onError) { + this.onError = onError; + } + + @Override + public OnClose getOnClose() { + return this.onClose; + } + + public void setOnClose(OnClose onClose) { + this.onClose = onClose; + } + + @Override + protected OnNotification getOnNotification() { + return this.onNotification; + } + + public void setOnNotification(OnNotification onNotification) { + this.onNotification = onNotification; + } + + @Override + protected WsData createWsData(WebSocket ws) { + return new WsData(ws) { + @Override + public String toString() { + return "TestClient.WsData []"; + } + }; + } + + @Override + protected void logInfo(Logger log, String message) { + log.info(message); + } + + @Override + protected void logWarn(Logger log, String message) { + log.warn(message); + } + + @Override + protected void logError(Logger log, String message) { + log.error(message); + } + + @Override + protected void execute(Runnable command) { + command.run(); + } +} diff --git a/io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedCharge.java b/io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedCharge.java index 2ee38fba17a..05dc14dc251 100644 --- a/io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedCharge.java +++ b/io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedCharge.java @@ -192,6 +192,12 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { CONFIGURED_ESS_IS_NOT_MANAGED(Doc.of(Level.FAULT) // .text("The Energy Storage System is in read-only mode and does not allow to be controlled.")), // + /** + * Production values for prediction not available. + */ + NO_VALID_PRODUCTION_PREDICTION(Doc.of(Level.WARNING) // + .translationKey(ControllerEssGridOptimizedCharge.class, "noValidProductionPrediction")), // + /** * Cumulated seconds of the state delay charge. */ @@ -696,6 +702,25 @@ public default void _setConfiguredEssIsNotManaged(Boolean value) { this.getConfiguredEssIsNotManagedChannel().setNextValue(value); } + /** + * Gets the Channel for {@link ChannelId#NO_VALID_PRODUCTION_PREDICTION}. + * + * @return the Channel + */ + public default StateChannel noValidProductionPredictionChannel() { + return this.channel(ChannelId.NO_VALID_PRODUCTION_PREDICTION); + } + + /** + * Internal method to set the 'nextValue' on + * {@link ChannelId#NO_VALID_PRODUCTION_PREDICTION} Channel. + * + * @param value the next value + */ + public default void _setNoValidProductionPredictionChannel(Boolean value) { + this.noValidProductionPredictionChannel().setNextValue(value); + } + /** * Gets the Channel for {@link ChannelId#DELAY_CHARGE_TIME}. * diff --git a/io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedChargeImpl.java b/io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedChargeImpl.java index aa727e503b4..cb1ffc764a6 100644 --- a/io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedChargeImpl.java +++ b/io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedChargeImpl.java @@ -145,12 +145,19 @@ private void updateConfig(Config config) { @Override public void run() throws OpenemsNamedException { + if (!this.ess.isManaged() && this.config.mode() != Mode.OFF) { this._setConfiguredEssIsNotManaged(true); return; } this._setConfiguredEssIsNotManaged(false); + if (!this.sum.getProductionActivePower().isDefined()) { + this._setNoValidProductionPredictionChannel(true); + return; + } + this._setNoValidProductionPredictionChannel(false); + // Updates the time channels. this.calculateTime(); diff --git a/io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/translation_de.properties b/io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/translation_de.properties new file mode 100644 index 00000000000..2660bc97b77 --- /dev/null +++ b/io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/translation_de.properties @@ -0,0 +1,2 @@ +# ControllerEssGridOptimizedCharge +noValidProductionPrediction = Keine Erzeugungsprognose möglich. Bitte erfassen Sie die Erzeugung Ihrer Anlage über eine App oder wählen Sie in der netzdienlichen Beladung den Modus 'AUS'. diff --git a/io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/translation_en.properties b/io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/translation_en.properties new file mode 100644 index 00000000000..e2195067037 --- /dev/null +++ b/io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/translation_en.properties @@ -0,0 +1,2 @@ +# ControllerEssGridOptimizedCharge +noValidProductionPrediction = No production forecast available. Please log the production via an app or set the grid-optimized charge mode to 'OFF'. diff --git a/io.openems.edge.controller.ess.gridoptimizedcharge/test/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedChargeImplTest.java b/io.openems.edge.controller.ess.gridoptimizedcharge/test/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedChargeImplTest.java index 03f197139e3..009f2fb33f2 100644 --- a/io.openems.edge.controller.ess.gridoptimizedcharge/test/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedChargeImplTest.java +++ b/io.openems.edge.controller.ess.gridoptimizedcharge/test/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedChargeImplTest.java @@ -184,6 +184,7 @@ public void automatic_default_predictions_at_midnight_test() throws Exception { .setManualTargetTime("") // .build()) // .next(new TestCase() // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(METER_ACTIVE_POWER, 0) // .input(ESS_ACTIVE_POWER, 0) // .input(ESS_CAPACITY, 10_000) // @@ -233,6 +234,7 @@ public void automatic_default_predictions_at_midday_test() throws Exception { .setManualTargetTime("") // .build()) // .next(new TestCase() // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(METER_ACTIVE_POWER, 0) // .input(ESS_ACTIVE_POWER, 0) // .input(ESS_CAPACITY, 10_000) // @@ -290,6 +292,7 @@ public void automatic_default_predictions_at_midday_averaged_test() throws Excep .build()) // .next(new TestCase() // .onAfterProcessImage(sleep) // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(METER_ACTIVE_POWER, 0) // .input(ESS_ACTIVE_POWER, 0) // .input(ESS_CAPACITY, 10_000) // @@ -305,6 +308,7 @@ public void automatic_default_predictions_at_midday_averaged_test() throws Excep .output(RAW_DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, 2700)) // .next(new TestCase() // .onAfterProcessImage(sleep) // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(ESS_SOC, 21) // .input(START_EPOCH_SECONDS, 1630566000) // .output(DELAY_CHARGE_STATE, DelayChargeState.ACTIVE_LIMIT) // @@ -312,14 +316,17 @@ public void automatic_default_predictions_at_midday_averaged_test() throws Excep .output(RAW_DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, 2666)) // .next(new TestCase() // .onAfterProcessImage(sleep) // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .output(DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, 2677) // .output(RAW_DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, 2666)) // .next(new TestCase() // .onAfterProcessImage(sleep) // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .output(DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, 2675) // .output(RAW_DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, 2666)) // .next(new TestCase() // .onAfterProcessImage(sleep) // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .output(DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, 2673) // .output(RAW_DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, 2666)) // ; @@ -360,6 +367,7 @@ public void automatic_default_predictions_at_evening_test() throws Exception { .setManualTargetTime("") // .build()) // .next(new TestCase() // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(METER_ACTIVE_POWER, 0) // .input(ESS_ACTIVE_POWER, 0) // .input(ESS_CAPACITY, 10_000) // @@ -373,6 +381,7 @@ public void automatic_default_predictions_at_evening_test() throws Exception { // Value increases steadily by 0.25% of max apparent power 10_000 .output(DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, 2025)) .next(new TestCase() // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(PREDICTED_TARGET_MINUTE, /* QuarterHour */ 68 * 15) // .input(PREDICTED_TARGET_MINUTE_ADJUSTED, /* QuarterHour */ 68 * 15 - 120) // .input(START_EPOCH_SECONDS, 1630566000) // @@ -383,6 +392,7 @@ public void automatic_default_predictions_at_evening_test() throws Exception { .output(RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT, 6650) // .output(DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, 2050)) .next(new TestCase() // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(PREDICTED_TARGET_MINUTE, /* QuarterHour */ 68 * 15) // .input(PREDICTED_TARGET_MINUTE_ADJUSTED, /* QuarterHour */ 68 * 15 - 120) // .input(START_EPOCH_SECONDS, 1630566000) // @@ -421,6 +431,7 @@ public void automatic_no_predictions_test() throws Exception { .setManualTargetTime("") // .build()) // .next(new TestCase() // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(METER_ACTIVE_POWER, 0) // .input(ESS_ACTIVE_POWER, 0) // .input(ESS_CAPACITY, 10_000) // @@ -459,6 +470,7 @@ public void automatic_sell_to_grid_limit_test() throws Exception { .setManualTargetTime("") // .build()) // .next(new TestCase() // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(METER_ACTIVE_POWER, -7500) // .input(ESS_CAPACITY, 10_000) // .input(ESS_SOC, 20) // @@ -472,6 +484,7 @@ public void automatic_sell_to_grid_limit_test() throws Exception { .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 850) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // .next(new TestCase() // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(METER_ACTIVE_POWER, -12000) // .input(ESS_ACTIVE_POWER, -850) // .input(START_EPOCH_SECONDS, 1630566000) // @@ -480,6 +493,7 @@ public void automatic_sell_to_grid_limit_test() throws Exception { .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 6200) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // .next(new TestCase() // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(METER_ACTIVE_POWER, -7000) // .input(ESS_ACTIVE_POWER, -6200) // .input(START_EPOCH_SECONDS, 1630566000) // @@ -488,6 +502,7 @@ public void automatic_sell_to_grid_limit_test() throws Exception { .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 6550) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // .next(new TestCase() // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(METER_ACTIVE_POWER, -5000) // .input(ESS_ACTIVE_POWER, -6550) // .input(START_EPOCH_SECONDS, 1630566000) // @@ -496,6 +511,7 @@ public void automatic_sell_to_grid_limit_test() throws Exception { .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 6050) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // .next(new TestCase() // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(METER_ACTIVE_POWER, -8000) // .input(ESS_ACTIVE_POWER, -6050) // .input(START_EPOCH_SECONDS, 1630566000) // @@ -506,6 +522,7 @@ public void automatic_sell_to_grid_limit_test() throws Exception { .next(new TestCase() // // Difference between last limit and current lower than the ramp - ramp is not // applied + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(METER_ACTIVE_POWER, -7000) // .input(ESS_ACTIVE_POWER, -7400) // .input(START_EPOCH_SECONDS, 1630566000) // @@ -514,6 +531,7 @@ public void automatic_sell_to_grid_limit_test() throws Exception { .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 7750) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // .next(new TestCase() // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(METER_ACTIVE_POWER, -6000) // .input(ESS_ACTIVE_POWER, -7750) // .input(START_EPOCH_SECONDS, 1630566000) // @@ -551,6 +569,7 @@ public void automatic_sell_to_grid_limit_test_with_full_ess() throws Exception { .build()) // .next(new TestCase() // .input(METER_ACTIVE_POWER, -7500) // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(ESS_CAPACITY, 10_000) // .input(ESS_SOC, 100) // .input(ESS_MAX_APPARENT_POWER, 10_000) // @@ -564,6 +583,7 @@ public void automatic_sell_to_grid_limit_test_with_full_ess() throws Exception { .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // .next(new TestCase() // .input(METER_ACTIVE_POWER, -12000) // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(ESS_ACTIVE_POWER, -1000) // .input(ESS_SOC, 100) // .input(START_EPOCH_SECONDS, 1630566000) // @@ -573,6 +593,7 @@ public void automatic_sell_to_grid_limit_test_with_full_ess() throws Exception { .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // .next(new TestCase() // .input(METER_ACTIVE_POWER, -7000) // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(ESS_ACTIVE_POWER, -6000) // .input(ESS_SOC, 100) // .input(START_EPOCH_SECONDS, 1630566000) // @@ -582,6 +603,7 @@ public void automatic_sell_to_grid_limit_test_with_full_ess() throws Exception { .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // .next(new TestCase() // .input(METER_ACTIVE_POWER, -5000) // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(ESS_ACTIVE_POWER, -6000) // .input(ESS_SOC, 100) // .output(ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS, -5500) // @@ -590,6 +612,7 @@ public void automatic_sell_to_grid_limit_test_with_full_ess() throws Exception { .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // .next(new TestCase() // .input(METER_ACTIVE_POWER, -8000) // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(ESS_ACTIVE_POWER, -5500) // .input(ESS_SOC, 100) // .output(ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS, -6500) // @@ -600,6 +623,7 @@ public void automatic_sell_to_grid_limit_test_with_full_ess() throws Exception { // Difference between last limit and current lower than the ramp - ramp is not // applied .input(METER_ACTIVE_POWER, -7000) // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(ESS_ACTIVE_POWER, -6300) // .input(ESS_SOC, 100) // .output(ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS, -6300) // @@ -607,6 +631,7 @@ public void automatic_sell_to_grid_limit_test_with_full_ess() throws Exception { .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 6300) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // .next(new TestCase() // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(METER_ACTIVE_POWER, -6000) // .input(ESS_ACTIVE_POWER, -6000) // .input(ESS_SOC, 100) // @@ -643,6 +668,7 @@ public void automatic_sell_to_grid_limit_buffer_test() throws Exception { .setManualTargetTime("") // .build()) // .next(new TestCase() // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(METER_ACTIVE_POWER, -7500) // .input(ESS_CAPACITY, 10_000) // .input(ESS_SOC, 20) // @@ -656,6 +682,7 @@ public void automatic_sell_to_grid_limit_buffer_test() throws Exception { .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 850) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // .next(new TestCase() // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(METER_ACTIVE_POWER, -12000) // .input(ESS_ACTIVE_POWER, -1000) // .input(START_EPOCH_SECONDS, 1630566000) // @@ -664,6 +691,7 @@ public void automatic_sell_to_grid_limit_buffer_test() throws Exception { .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 6350) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // .next(new TestCase() // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(METER_ACTIVE_POWER, -7000) // .input(ESS_ACTIVE_POWER, -6000) // .input(START_EPOCH_SECONDS, 1630566000) // @@ -672,6 +700,7 @@ public void automatic_sell_to_grid_limit_buffer_test() throws Exception { .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 6350) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // .next(new TestCase() // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(METER_ACTIVE_POWER, -5000) // .input(ESS_ACTIVE_POWER, -6000) // .input(START_EPOCH_SECONDS, 1630566000) // @@ -680,6 +709,7 @@ public void automatic_sell_to_grid_limit_buffer_test() throws Exception { .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 5850) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // .next(new TestCase() // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(METER_ACTIVE_POWER, -8000) // .input(ESS_ACTIVE_POWER, -5500) // .input(START_EPOCH_SECONDS, 1630566000) // @@ -690,6 +720,7 @@ public void automatic_sell_to_grid_limit_buffer_test() throws Exception { .next(new TestCase() // // Difference between last limit and current lower than the ramp - ramp is not // applied + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(METER_ACTIVE_POWER, -7000) // .input(ESS_ACTIVE_POWER, -6300) // .input(START_EPOCH_SECONDS, 1630566000) // @@ -698,6 +729,7 @@ public void automatic_sell_to_grid_limit_buffer_test() throws Exception { .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 6650) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // .next(new TestCase() // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(METER_ACTIVE_POWER, -6000) // .input(ESS_ACTIVE_POWER, -6000) // .input(START_EPOCH_SECONDS, 1630566000) // @@ -749,6 +781,7 @@ public void manual_midnight_test() throws Exception { .input(START_EPOCH_SECONDS, 1630566000) // .input(ESS_MAX_APPARENT_POWER, 10_000)) // .next(new TestCase() // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(START_EPOCH_SECONDS, 1630566000) // .output(TARGET_MINUTE, /* QuarterHour */ 1020) // .output(DELAY_CHARGE_STATE, DelayChargeState.AVOID_LOW_CHARGING) // @@ -792,6 +825,7 @@ public void manual_midday_test() throws Exception { .setSellToGridLimitRampPercentage(5) // .build()) // .next(new TestCase() // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(METER_ACTIVE_POWER, 0) // .input(ESS_ACTIVE_POWER, 0) // .input(ESS_CAPACITY, 10_000) // @@ -840,6 +874,7 @@ public void hybridEss_manual_midday_test() throws Exception { .setSellToGridLimitRampPercentage(5) // .build()) // .next(new TestCase() // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(METER_ACTIVE_POWER, 0) // .input(ESS_ACTIVE_POWER, 0) // .input(ESS_CAPACITY, 10_000) // @@ -890,6 +925,7 @@ public void mode_off_test() throws Exception { .setManualTargetTime("") // .build()) // .next(new TestCase() // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(METER_ACTIVE_POWER, -7500) // .input(ESS_MAX_APPARENT_POWER, 10_000) // .input(ESS_ACTIVE_POWER, 0) // @@ -938,6 +974,7 @@ public void no_capacity_left_test() throws Exception { .build()) // .next(new TestCase() // .input(METER_ACTIVE_POWER, 0) // + .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(ESS_ACTIVE_POWER, 0) // .input(ESS_CAPACITY, 10_000) // .input(ESS_SOC, 99) // diff --git a/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/Config.java b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/Config.java index bfda174afa0..9edecbc6394 100644 --- a/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/Config.java +++ b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/Config.java @@ -43,6 +43,12 @@ @AttributeDefinition(name = "Energy limit in this session in [Wh]", description = "Set the Energylimit in this Session in Wh. The charging station will only charge till this limit; '0' is no limit.") int energySessionLimit() default 0; + @AttributeDefinition(name = "Minimum charging time while charging with excess power", description = "Minimum time (Seconds) is applied to avoid continuous switching between charging and not charging") + int excessChargeHystersis() default 120; + + @AttributeDefinition(name = "Minimum pause time while charging with excess power", description = "Minimum time (Seconds) is applied to avoid continuous switching between charging and not charging") + int excessChargePauseHysteresis() default 30; + @AttributeDefinition(name = "Evcs target filter", description = "This is auto-generated by 'Evcs-ID'.") String evcs_target() default "(enabled=true)"; diff --git a/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/ControllerEvcs.java b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/ControllerEvcs.java index 5a4a779dd4f..54bbb5e0be5 100644 --- a/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/ControllerEvcs.java +++ b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/ControllerEvcs.java @@ -1,13 +1,17 @@ package io.openems.edge.controller.evcs; -import io.openems.common.types.OpenemsType; +import static io.openems.common.channel.PersistencePriority.HIGH; +import static io.openems.common.types.OpenemsType.BOOLEAN; + import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.component.OpenemsComponent; -public interface ControllerEvcs { +public interface ControllerEvcs extends OpenemsComponent { public enum ChannelId implements io.openems.edge.common.channel.ChannelId { - AWAITING_HYSTERESIS(Doc.of(OpenemsType.BOOLEAN)) // + AWAITING_HYSTERESIS(Doc.of(BOOLEAN) // + .persistencePriority(HIGH)) // ; // private final Doc doc; diff --git a/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/ControllerEvcsImpl.java b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/ControllerEvcsImpl.java index a4aeb209438..69e67eae105 100644 --- a/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/ControllerEvcsImpl.java +++ b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/ControllerEvcsImpl.java @@ -2,6 +2,8 @@ import java.io.IOException; import java.time.Clock; +import java.time.Duration; +import java.time.Instant; import org.osgi.service.cm.Configuration; import org.osgi.service.cm.ConfigurationAdmin; @@ -25,6 +27,8 @@ import io.openems.edge.common.modbusslave.ModbusSlaveTable; import io.openems.edge.common.sum.Sum; import io.openems.edge.controller.api.Controller; +import io.openems.edge.evcs.api.ChargeMode; +import io.openems.edge.evcs.api.ChargeState; import io.openems.edge.evcs.api.ManagedEvcs; @Designate(ocd = Config.class, factory = true) @@ -40,6 +44,16 @@ public class ControllerEvcsImpl extends AbstractOpenemsComponent implements Cont private final Logger log = LoggerFactory.getLogger(ControllerEvcsImpl.class); private final ChargingLowerThanTargetHandler chargingLowerThanTargetHandler; + private final Clock clock; + + // Time of last charge power change, used for the hysteresis + private Instant lastInitialCharge = Instant.MIN; + + // Time of last charge pause, used for the hysteresis + private Instant lastChargePause = Instant.MIN; + + // Last charge power, used for the hysteresis + private int lastChargePower = 0; @Reference private ConfigurationAdmin cm; @@ -62,6 +76,7 @@ protected ControllerEvcsImpl(Clock clock) { Controller.ChannelId.values(), // ControllerEvcs.ChannelId.values() // ); + this.clock = clock; this.chargingLowerThanTargetHandler = new ChargingLowerThanTargetHandler(clock); } @@ -205,6 +220,11 @@ public void run() throws OpenemsNamedException { } } + if (this.config.chargeMode().equals(ChargeMode.EXCESS_POWER)) { + // Apply hysteresis + nextChargePower = this.applyHysteresis(nextChargePower); + } + if (isClustered) { this.evcs.setChargePowerRequest(nextChargePower); } else { @@ -275,6 +295,82 @@ private static int calculateExcessPowerAfterEss(Sum sum, ManagedEvcs evcs) { return result > 0 ? result : 0; } + /** + * Applies the hysteresis to avoid too quick changes between a charge process + * and a pause. + * + * @param nextChargePower the next charge power limit + * @return next charge power or the last power if hysteresis is active + */ + private int applyHysteresis(int nextChargePower) { + int targetChargePower = nextChargePower; + boolean showWarning = false; + var now = Instant.now(this.clock); + + // Wait at least the EVCS-specific response time, required to increase and + // decrease the charging power + if (awaitLastChanges(this.evcs.getChargeState().asEnum())) { + // Still waiting for increasing, decreasing the power or undefined + return this.lastChargePower; + } + // TODO: Show info, test and check if bellow logic still needed or need to be + // different (Change only when we would change for xSeconds) + + // New charge power limit + if (this.lastChargePower <= 0 && nextChargePower > 0) { + var hysteresis = Duration.ofSeconds(this.config.excessChargePauseHysteresis()); + if (this.lastChargePause.plus(hysteresis).isBefore(now)) { + + // Start charing + this.lastInitialCharge = now; + } else { + // Wait for hysteresis + showWarning = true; + targetChargePower = this.lastChargePower; + } + } + + // Pause charging by limiting to zero + if (this.lastChargePower > 0 && nextChargePower <= 0) { + var hysteresis = Duration.ofSeconds(this.config.excessChargeHystersis()); + if (this.lastInitialCharge.plus(hysteresis).isBefore(now)) { + + // Pause charing + targetChargePower = 0; + this.lastChargePause = now; + } else { + // Wait for hysteresis + showWarning = true; + targetChargePower = this.lastChargePower; + } + } + + // Apply results + this.lastChargePower = targetChargePower; + this.channel(ControllerEvcs.ChannelId.AWAITING_HYSTERESIS).setNextValue(showWarning); + + return targetChargePower; + } + + /** + * Check if the evcs should wait for last changes. + * + *

      + * Since the charging stations and each car have their own response time until + * they charge at the set power, the controller waits until everything runs + * normally. + * + * @param chargeState current evcs charge state + * @return The cvcs should await or not + */ + private static boolean awaitLastChanges(ChargeState chargeState) { + if (chargeState.equals(ChargeState.INCREASING) || chargeState.equals(ChargeState.INCREASING)) { + // Still waiting for increasing, decreasing the power + return true; + } + return false; + } + @Override public ModbusSlaveTable getModbusSlaveTable(AccessMode accessMode) { return new ModbusSlaveTable(// diff --git a/io.openems.edge.controller.evcs/test/io/openems/edge/controller/evcs/ControllerEvcsImplTest.java b/io.openems.edge.controller.evcs/test/io/openems/edge/controller/evcs/ControllerEvcsImplTest.java index 1c4f620d146..960a2c5789c 100644 --- a/io.openems.edge.controller.evcs/test/io/openems/edge/controller/evcs/ControllerEvcsImplTest.java +++ b/io.openems.edge.controller.evcs/test/io/openems/edge/controller/evcs/ControllerEvcsImplTest.java @@ -4,6 +4,7 @@ import java.time.Instant; import java.time.ZoneOffset; +import java.time.temporal.ChronoUnit; import org.junit.Test; @@ -15,6 +16,7 @@ import io.openems.edge.common.test.DummyConfigurationAdmin; import io.openems.edge.controller.test.ControllerTest; import io.openems.edge.evcs.api.ChargeMode; +import io.openems.edge.evcs.api.Evcs; import io.openems.edge.evcs.api.Status; import io.openems.edge.evcs.test.DummyEvcsPower; import io.openems.edge.evcs.test.DummyManagedEvcs; @@ -42,6 +44,9 @@ public class ControllerEvcsImplTest { private static ChannelAddress evcs0SetPowerRequest = new ChannelAddress("evcs0", "SetChargePowerRequest"); private static ChannelAddress evcs0Status = new ChannelAddress("evcs0", "Status"); private static ChannelAddress evcs0MaximumHardwarePower = new ChannelAddress("evcs0", "MaximumHardwarePower"); + private static ChannelAddress evcs0MinimumHardwarePower = new ChannelAddress("evcs0", "MinimumHardwarePower"); + private static ChannelAddress evcsController0AwaitingHysteresis = new ChannelAddress("ctrlEvcs0", + "AwaitingHysteresis"); @Test public void excessChargeTest1() throws Exception { @@ -267,4 +272,82 @@ public void clusterTestDisabledCharging() throws Exception { .output(evcs0MaximumPower, null)) // ; } + + @Test + public void hysteresisTest() throws Exception { + + final var clock = new TimeLeapClock(Instant.ofEpochSecond(1577836800) /* starts at 1. January 2020 00:00:00 */, + ZoneOffset.UTC); + + new ControllerTest(new ControllerEvcsImpl(clock)) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("sum", new DummySum()) // + .addReference("evcs", EVCS) // + .activate(MyConfig.create() // + .setId("ctrlEvcs0") // + .setEvcsId(EVCS_ID) // + .setEnableCharging(DEFAULT_ENABLE_CHARGING) // + .setChargeMode(DEFAULT_CHARGE_MODE) // + .setForceChargeMinPower(DEFAULT_FORCE_CHARGE_MIN_POWER) // + .setDefaultChargeMinPower(DEFAULT_CHARGE_MIN_POWER) // + .setPriority(DEFAULT_PRIORITY) // + .setEnergySessionLimit(DEFAULT_ENERGY_SESSION_LIMIT) // + .setExcessChargeHystersis(120) // + .setExcessChargePauseHysteresis(30) // + .build()) // + .next(new TestCase() // + .input(sumEssDischargePower, 0) // + .input(evcs0IsClustered, false) // + .input(sumGridActivePower, -6_000) // + .input(evcs0ChargePower, 0) // + .output(evcs0SetChargePowerLimit, 6_000)) // + .next(new TestCase() // + .input(sumEssDischargePower, 0) // + .input(sumGridActivePower, -200) // + .input(evcs0ChargePower, 5800) // + .output(evcs0SetChargePowerLimit, 6_000)) // + .next(new TestCase() // + .input(sumEssDischargePower, 0) // + .input(sumGridActivePower, 500) // + .input(evcs0ChargePower, 5800) // + .input(evcs0MinimumHardwarePower, Evcs.DEFAULT_MINIMUM_HARDWARE_POWER) + .output(evcs0SetChargePowerLimit, 5300)) + + // Active hysteresis + .next(new TestCase() // + .input(sumEssDischargePower, 0) // + .input(sumGridActivePower, 1000) // + .input(evcs0ChargePower, 5000) // + .output(evcs0SetChargePowerLimit, 5_300) // + .output(evcsController0AwaitingHysteresis, true)) // + .next(new TestCase() // + .timeleap(clock, 6, ChronoUnit.MINUTES)) // + + // Passed hysteresis + .next(new TestCase() // + .input(sumEssDischargePower, 0) // + .input(sumGridActivePower, 1000) // + .input(evcs0ChargePower, 5000) // + .output(evcs0SetChargePowerLimit, 0) // + .output(evcsController0AwaitingHysteresis, false)) // + + // Active hysteresis + .next(new TestCase() // + .input(sumEssDischargePower, 0) // + .input(sumGridActivePower, -5000) // + .input(evcs0ChargePower, 0) // + .output(evcs0SetChargePowerLimit, 0) // + .output(evcsController0AwaitingHysteresis, true)) + + .next(new TestCase() // + .timeleap(clock, 1, ChronoUnit.MINUTES)) // + + // New charge process starting after another 30 seconds + .next(new TestCase() // + .input(sumEssDischargePower, 0) // + .input(sumGridActivePower, -5000) // + .input(evcs0ChargePower, 0) // + .output(evcs0SetChargePowerLimit, 5000) // + .output(evcsController0AwaitingHysteresis, false)); // + } } diff --git a/io.openems.edge.controller.evcs/test/io/openems/edge/controller/evcs/MyConfig.java b/io.openems.edge.controller.evcs/test/io/openems/edge/controller/evcs/MyConfig.java index 5e8533f1b41..cf509aca506 100644 --- a/io.openems.edge.controller.evcs/test/io/openems/edge/controller/evcs/MyConfig.java +++ b/io.openems.edge.controller.evcs/test/io/openems/edge/controller/evcs/MyConfig.java @@ -17,6 +17,8 @@ protected static class Builder { private int defaultChargeMinPower = 0; private Priority priority = Priority.CAR; private int energySessionLimit = 0; + private int excessChargeHystersis = 120; + private int excessChargePauseHysteresis = 30; private Builder() { } @@ -71,6 +73,16 @@ public Builder setEnergySessionLimit(int energySessionLimit) { return this; } + public Builder setExcessChargeHystersis(int excessChargeHystersis) { + this.excessChargeHystersis = excessChargeHystersis; + return this; + } + + public Builder setExcessChargePauseHysteresis(int excessChargePauseHysteresis) { + this.excessChargePauseHysteresis = excessChargePauseHysteresis; + return this; + } + public MyConfig build() { return new MyConfig(this); } @@ -137,6 +149,16 @@ public boolean debugMode() { return this.builder.debugMode; } + @Override + public int excessChargeHystersis() { + return this.builder.excessChargeHystersis; + } + + @Override + public int excessChargePauseHysteresis() { + return this.builder.excessChargePauseHysteresis; + } + @Override public String evcs_target() { return "(&(enabled=true)(!(service.pid=ctrlEvcs0))(|(id=" + this.evcs_id() + ")))"; diff --git a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHomeComponents.java b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHomeComponents.java index 72f62c234ba..a70a3242f1e 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHomeComponents.java +++ b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHomeComponents.java @@ -35,6 +35,24 @@ public static EdgeConfig.Component battery(// final ResourceBundle bundle, // final String batteryId, // final String modbusIdInternal // + ) { + return battery(bundle, batteryId, modbusIdInternal, "AUTO"); + } + + /** + * Creates a default battery component for a FENECON Home. + * + * @param bundle the translation bundle + * @param batteryId the id of the battery + * @param modbusIdInternal the id of the internal modbus bridge + * @param batteryStartStop the startStop target of the bridge + * @return the {@link Component} + */ + public static EdgeConfig.Component battery(// + final ResourceBundle bundle, // + final String batteryId, // + final String modbusIdInternal, // + final String batteryStartStop // ) { return new EdgeConfig.Component(batteryId, TranslationUtil.getTranslation(bundle, "App.IntegratedSystem.battery0.alias"), "Battery.Fenecon.Home", // @@ -43,7 +61,7 @@ public static EdgeConfig.Component battery(// .addProperty("batteryStartUpRelay", "io0/Relay4") // .addProperty("modbus.id", modbusIdInternal) // .addProperty("modbusUnitId", 1) // - .addProperty("startStop", "AUTO") // + .addProperty("startStop", batteryStartStop) // .build()); } @@ -181,7 +199,8 @@ public static EdgeConfig.Component modbusInternal(// final String modbusIdInternal // ) { return new EdgeConfig.Component(modbusIdInternal, - TranslationUtil.getTranslation(bundle, "App.IntegratedSystem.modbus0.alias"), "Bridge.Modbus.Serial", // + TranslationUtil.getTranslation(bundle, "App.IntegratedSystem.modbusToBattery.alias"), + "Bridge.Modbus.Serial", // JsonUtils.buildJsonObject() // .addProperty("enabled", true) // .addProperty("baudRate", 19200) // diff --git a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/AwattarHourly.java b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/AwattarHourly.java index 31200d39881..9e0ee9fdeed 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/AwattarHourly.java +++ b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/AwattarHourly.java @@ -4,6 +4,7 @@ import static io.openems.edge.app.common.props.CommonProps.defaultDef; import static io.openems.edge.core.appmanager.validator.Checkables.checkCommercial92; import static io.openems.edge.core.appmanager.validator.Checkables.checkHome; +import static io.openems.edge.core.appmanager.validator.Checkables.checkOr; import java.util.Map; import java.util.function.Function; @@ -169,7 +170,7 @@ public OpenemsAppCardinality getCardinality() { @Override protected ValidatorConfig.Builder getValidateBuilder() { return ValidatorConfig.create() // - .setCompatibleCheckableConfigs(checkHome().or(checkCommercial92())); + .setCompatibleCheckableConfigs(checkOr(checkHome(), checkCommercial92())); } @Override diff --git a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/EntsoE.java b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/EntsoE.java index 0c2f6d2f10d..5c91317ae73 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/EntsoE.java +++ b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/EntsoE.java @@ -2,6 +2,7 @@ import static io.openems.edge.core.appmanager.validator.Checkables.checkCommercial92; import static io.openems.edge.core.appmanager.validator.Checkables.checkHome; +import static io.openems.edge.core.appmanager.validator.Checkables.checkOr; import java.util.Map; import java.util.function.Function; @@ -168,7 +169,7 @@ public OpenemsAppCardinality getCardinality() { @Override protected ValidatorConfig.Builder getValidateBuilder() { return ValidatorConfig.create() // - .setCompatibleCheckableConfigs(checkHome().or(checkCommercial92())); + .setCompatibleCheckableConfigs(checkOr(checkHome(), checkCommercial92())); } @Override diff --git a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/GroupeE.java b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/GroupeE.java index b466c39ff10..7a868a62d1c 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/GroupeE.java +++ b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/GroupeE.java @@ -2,6 +2,7 @@ import static io.openems.edge.core.appmanager.validator.Checkables.checkCommercial92; import static io.openems.edge.core.appmanager.validator.Checkables.checkHome; +import static io.openems.edge.core.appmanager.validator.Checkables.checkOr; import java.util.Map; import java.util.function.Function; @@ -151,7 +152,7 @@ public OpenemsAppCardinality getCardinality() { @Override protected ValidatorConfig.Builder getValidateBuilder() { return ValidatorConfig.create() // - .setCompatibleCheckableConfigs(checkHome().or(checkCommercial92())); + .setCompatibleCheckableConfigs(checkOr(checkHome(), checkCommercial92())); } @Override diff --git a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/RabotCharge.java b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/RabotCharge.java index de9a446a214..3ad6b7df740 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/RabotCharge.java +++ b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/RabotCharge.java @@ -3,6 +3,7 @@ import static io.openems.edge.core.appmanager.formly.enums.InputType.PASSWORD; import static io.openems.edge.core.appmanager.validator.Checkables.checkCommercial92; import static io.openems.edge.core.appmanager.validator.Checkables.checkHome; +import static io.openems.edge.core.appmanager.validator.Checkables.checkOr; import java.util.Map; import java.util.function.Function; @@ -178,7 +179,7 @@ public OpenemsAppCardinality getCardinality() { @Override protected ValidatorConfig.Builder getValidateBuilder() { return ValidatorConfig.create() // - .setCompatibleCheckableConfigs(checkHome().or(checkCommercial92())); + .setCompatibleCheckableConfigs(checkOr(checkHome(), checkCommercial92())); } @Override diff --git a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StadtwerkHassfurt.java b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StadtwerkHassfurt.java index 8bf099ba335..09cd81281b6 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StadtwerkHassfurt.java +++ b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StadtwerkHassfurt.java @@ -3,6 +3,7 @@ import static io.openems.edge.app.common.props.CommonProps.defaultDef; import static io.openems.edge.core.appmanager.validator.Checkables.checkCommercial92; import static io.openems.edge.core.appmanager.validator.Checkables.checkHome; +import static io.openems.edge.core.appmanager.validator.Checkables.checkOr; import java.util.Map; import java.util.function.Function; @@ -167,7 +168,7 @@ public OpenemsAppCardinality getCardinality() { @Override protected ValidatorConfig.Builder getValidateBuilder() { return ValidatorConfig.create() // - .setCompatibleCheckableConfigs(checkHome().or(checkCommercial92())); + .setCompatibleCheckableConfigs(checkOr(checkHome(), checkCommercial92())); } @Override diff --git a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StromdaoCorrently.java b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StromdaoCorrently.java index fbbeb951333..7c4c5f96b7b 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StromdaoCorrently.java +++ b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StromdaoCorrently.java @@ -2,6 +2,7 @@ import static io.openems.edge.core.appmanager.validator.Checkables.checkCommercial92; import static io.openems.edge.core.appmanager.validator.Checkables.checkHome; +import static io.openems.edge.core.appmanager.validator.Checkables.checkOr; import java.util.Map; import java.util.function.Function; @@ -164,7 +165,7 @@ public OpenemsAppCardinality getCardinality() { @Override protected ValidatorConfig.Builder getValidateBuilder() { return ValidatorConfig.create() // - .setCompatibleCheckableConfigs(checkHome().or(checkCommercial92())); + .setCompatibleCheckableConfigs(checkOr(checkHome(), checkCommercial92())); } @Override diff --git a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/Tibber.java b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/Tibber.java index 3eeeb094bab..608b2a4ec4b 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/Tibber.java +++ b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/Tibber.java @@ -3,6 +3,7 @@ import static io.openems.edge.core.appmanager.formly.enums.InputType.PASSWORD; import static io.openems.edge.core.appmanager.validator.Checkables.checkCommercial92; import static io.openems.edge.core.appmanager.validator.Checkables.checkHome; +import static io.openems.edge.core.appmanager.validator.Checkables.checkOr; import java.util.Map; import java.util.function.Function; @@ -197,7 +198,7 @@ public OpenemsAppCardinality getCardinality() { @Override protected ValidatorConfig.Builder getValidateBuilder() { return ValidatorConfig.create() // - .setCompatibleCheckableConfigs(checkHome().or(checkCommercial92())); + .setCompatibleCheckableConfigs(checkOr(checkHome(), checkCommercial92())); } @Override diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/ComponentAggregateTaskImpl.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/ComponentAggregateTaskImpl.java index b7c8349e4ed..87fad0519b6 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/ComponentAggregateTaskImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/ComponentAggregateTaskImpl.java @@ -69,7 +69,10 @@ public void aggregate(ComponentConfiguration config, ComponentConfiguration oldC if (oldConfig != null) { var componentDiff = new ArrayList<>(oldConfig.components()); if (config != null) { - componentDiff.removeIf(t -> config.components().stream().anyMatch(c -> c.getId().equals(t.getId()))); + componentDiff.removeIf(t -> config.components().stream().anyMatch(c -> { + return c.getId().equals(t.getId()) // + && c.getFactoryId().equals(t.getFactoryId()); + })); } this.components2Delete.addAll(componentDiff); } @@ -94,8 +97,24 @@ public void create(User user, List otherAppConfigurations) thr if (foundComponentWithSameId != null) { // check if the found component has the same factory id if (!foundComponentWithSameId.getFactoryId().equals(comp.getFactoryId())) { - errors.add("Configuration of component with id '" + foundComponentWithSameId.getId() - + "' can not be rewritten. Because the component has a different factoryId."); + if (this.components2Delete.stream().anyMatch(t -> t.getId().equals(comp.getId()))) { + // if the component was intended to be deleted anyway delete it directly and + // create the new component directly afterwards + try { + this.deleteComponent(user, comp); + this.deletedComponents.add(comp.getId()); + this.components2Delete.removeIf(t -> t.getId().equals(comp.getId())); + this.createComponent(user, comp); + this.createdComponents.add(comp); + } catch (OpenemsNamedException e) { + final var error = "Component[" + comp.getFactoryId() + "] cant be created!"; + errors.add(error); + errors.add(e.getMessage()); + } + } else { + errors.add("Configuration of component with id '" + foundComponentWithSameId.getId() + + "' can not be rewritten. Because the component has a different factoryId."); + } continue; } @@ -179,8 +198,7 @@ public void delete(User user, List otherAppConfigurations) thr } try { - this.componentManager.handleDeleteComponentConfigRequest(user, - new DeleteComponentConfigRequest(comp.getId())); + this.deleteComponent(user, comp); this.deletedComponents.add(comp.getId()); } catch (OpenemsNamedException e) { errors.add(e.toString()); @@ -235,6 +253,10 @@ private final boolean anyChanges() { || !this.components2Delete.isEmpty(); } + private void deleteComponent(User user, EdgeConfig.Component comp) throws OpenemsNamedException { + this.componentManager.handleDeleteComponentConfigRequest(user, new DeleteComponentConfigRequest(comp.getId())); + } + private void createComponent(User user, EdgeConfig.Component comp) throws OpenemsNamedException { List properties = comp.getProperties().entrySet().stream() .map(t -> new Property(t.getKey(), t.getValue())).collect(Collectors.toList()); diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties index b0e860ca53e..16414b2d0d5 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties @@ -246,8 +246,9 @@ App.IntegratedSystem.shadowManagementDisabled.label = Schattenmanagement deaktiv App.IntegratedSystem.shadowManagementDisabled.description = Nur wenn Optimierer verbaut sind, muss das Schattenmanagement deaktiviert werden App.IntegratedSystem.hasEssLimiter14a.label = Hat Limitierer für §14a -App.IntegratedSystem.modbus0.alias = Kommunikation mit der Batterie -App.IntegratedSystem.modbus0N.alias = Kommunikation mit den Batterien +App.IntegratedSystem.modbusToBattery.alias = Kommunikation mit der Batterie +App.IntegratedSystem.modbusToBatteryN.alias = Kommunikation mit den Batterien +App.IntegratedSystem.modbusToBattery0.alias = Kommunikation mit der Batterie {0} App.IntegratedSystem.modbus1.alias = Kommunikation mit dem Batterie-Wechselrichter App.IntegratedSystem.modbus1N.alias = Kommunikation mit dem Batterie-Wechselrichter {0} App.IntegratedSystem.modbus2.alias = externe RS485 Schnittstelle @@ -260,6 +261,7 @@ App.IntegratedSystem.batteryParallelClusterN.alias = Parallel-Cluster {0} App.IntegratedSystem.batteryInverter0.alias = Batterie-Wechselrichter App.IntegratedSystem.batteryInverterN.alias = Batterie-Wechselrichter {0} App.IntegratedSystem.ess0.alias = Speichersystem +App.IntegratedSystem.essCluster0.alias = Batteriespeicher-Cluster App.IntegratedSystem.predictor0.alias = Prognose App.IntegratedSystem.ctrlEssSurplusFeedToGrid0.alias = Überschusseinspeisung App.IntegratedSystem.emergencyMeter.alias = Notstromverbraucher @@ -325,7 +327,6 @@ App.FENECON.Industrial.L.ILK710.batteryFirmwareVersion.label = Battery Firmware App.FENECON.Industrial.S.io0 = Relais App.FENECON.Industrial.S.ess0.alias = Batteriespeicher App.FENECON.Industrial.S.essN.alias = Batteriespeicher {0} -App.FENECON.Industrial.S.essCluster0.alias = Batteriespeicher-Cluster App.FENECON.Industrial.S.hasGridMeter.label = Hat Netzzähler App.FENECON.Industrial.S.hasSelfConsumptionOptimization.label = Hat Eigenverbrauchsoptimierung App.FENECON.Industrial.S.modbusToGridMeter.alias = Kommunikation mit den Netzzähler diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties index 460116c4f56..2566a3fa36a 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties @@ -246,8 +246,9 @@ App.IntegratedSystem.shadowManagementDisabled.label = Deactivate shadow manageme App.IntegratedSystem.shadowManagementDisabled.description = Only if optimisers are installed, shadow management must be deactivated App.IntegratedSystem.hasEssLimiter14a.label = Has limiter for §14a -App.IntegratedSystem.modbus0.alias = Communication with the battery -App.IntegratedSystem.modbus0N.alias = Communication with the batteries +App.IntegratedSystem.modbusToBattery.alias = Communication with the battery +App.IntegratedSystem.modbusToBatteryN.alias = Communication with the batteries +App.IntegratedSystem.modbusToBattery0.alias = Communication with the battery {0} App.IntegratedSystem.modbus1.alias = Communication with the battery inverter App.IntegratedSystem.modbus1N.alias = Communication with the battery inverter {0} App.IntegratedSystem.modbus2.alias = external RS485 interface @@ -260,6 +261,7 @@ App.IntegratedSystem.batteryParallelClusterN.alias = parallel-cluster {0} App.IntegratedSystem.batteryInverter0.alias = battery inverter App.IntegratedSystem.batteryInverterN.alias = battery inverter {0} App.IntegratedSystem.ess0.alias = Storage system +App.IntegratedSystem.essCluster0.alias = Storage system-Cluster App.IntegratedSystem.predictor0.alias = Forecast App.IntegratedSystem.ctrlEssSurplusFeedToGrid0.alias = Excess feed-in App.IntegratedSystem.emergencyMeter.alias = Emergency power consumers @@ -325,7 +327,6 @@ App.FENECON.Industrial.L.ILK710.batteryFirmwareVersion.label = Battery Firmware App.FENECON.Industrial.S.io0 = Relay App.FENECON.Industrial.S.ess0.alias = Battery Storage App.FENECON.Industrial.S.essN.alias = Battery Storage {0} -App.FENECON.Industrial.S.essCluster0.alias = Battery Storage-Cluster App.FENECON.Industrial.S.hasGridMeter.label = Has Grid-Meter App.FENECON.Industrial.S.hasSelfConsumptionOptimization.label = Has Self-consumption optimisation App.FENECON.Industrial.S.modbusToGridMeter.alias = Communication with the Grid-Meter diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/Checkables.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/Checkables.java index 32783117bed..993cc7d84d3 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/Checkables.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/Checkables.java @@ -1,6 +1,7 @@ package io.openems.edge.core.appmanager.validator; import java.util.Collections; +import java.util.Objects; import java.util.TreeMap; import io.openems.edge.core.appmanager.validator.ValidatorConfig.CheckableConfig; @@ -35,14 +36,25 @@ public static CheckableConfig checkCommercial92() { * * @param check1 the first check * @param check2 the second check + * @param other the additional checks to combine with 'or' operator * @return the {@link CheckableConfig} */ - public static CheckableConfig checkOr(CheckableConfig check1, CheckableConfig check2) { - return new ValidatorConfig.CheckableConfig(CheckOr.COMPONENT_NAME, + public static CheckableConfig checkOr(// + CheckableConfig check1, // + CheckableConfig check2, // + CheckableConfig... other // + ) { + var config = new ValidatorConfig.CheckableConfig(CheckOr.COMPONENT_NAME, new ValidatorConfig.MapBuilder<>(new TreeMap()) // - .put("check1", check1) // - .put("check2", check2) // + .put("check1", Objects.requireNonNull(check1)) // + .put("check2", Objects.requireNonNull(check2)) // .build()); + if (other != null && other.length > 0) { + for (var check : other) { + config = config.or(check); + } + } + return config; } /** diff --git a/io.openems.edge.core/src/io/openems/edge/core/meta/MetaImpl.java b/io.openems.edge.core/src/io/openems/edge/core/meta/MetaImpl.java index 8ae2c8457f9..27843503c1e 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/meta/MetaImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/meta/MetaImpl.java @@ -1,5 +1,12 @@ package io.openems.edge.core.meta; +import static io.openems.common.utils.ThreadPoolUtils.shutdownAndAwaitTermination; + +import java.time.Instant; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.annotations.Activate; @@ -12,6 +19,7 @@ import io.openems.common.OpenemsConstants; import io.openems.common.channel.AccessMode; import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.edge.common.channel.LongReadChannel; import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.meta.Meta; @@ -27,6 +35,8 @@ }) public class MetaImpl extends AbstractOpenemsComponent implements Meta, OpenemsComponent, ModbusSlave { + private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); + @Reference private ConfigurationAdmin cm; @@ -45,6 +55,12 @@ public MetaImpl() { private void activate(ComponentContext context, Config config) { super.activate(context, SINGLETON_COMPONENT_ID, Meta.SINGLETON_SERVICE_PID, true); + // Update the Channel _meta/SystemTimeUtc after every second + final var systemTimeUtcChannel = this.channel(Meta.ChannelId.SYSTEM_TIME_UTC); + this.executor.scheduleAtFixedRate(() -> { + systemTimeUtcChannel.setNextValue(Instant.now().getEpochSecond()); + }, 0, 1000, TimeUnit.MILLISECONDS); + this.applyConfig(config); if (OpenemsComponent.validateSingleton(this.cm, Meta.SINGLETON_SERVICE_PID, SINGLETON_COMPONENT_ID)) { return; @@ -64,6 +80,7 @@ private void modified(ComponentContext context, Config config) { @Override @Deactivate protected void deactivate() { + shutdownAndAwaitTermination(this.executor, 0); super.deactivate(); } diff --git a/io.openems.edge.core/src/io/openems/edge/core/sum/SumImpl.java b/io.openems.edge.core/src/io/openems/edge/core/sum/SumImpl.java index 6bf8c875d46..ea45fc4a94a 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/sum/SumImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/sum/SumImpl.java @@ -464,7 +464,6 @@ private void calculateState() { highestLevel = Level.INFO; } } - this.getStateChannel().setNextValue(highestLevel); } diff --git a/io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/common/AbstractEdge2Edge.java b/io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/common/AbstractEdge2Edge.java index 9dae53bdbeb..581576f2275 100644 --- a/io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/common/AbstractEdge2Edge.java +++ b/io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/common/AbstractEdge2Edge.java @@ -344,20 +344,14 @@ protected abstract io.openems.edge.common.channel.ChannelId getWriteChannelId( * @return the {@link AbstractModbusElement} */ private static ModbusElement generateModbusElement(ModbusType type, int address) { - switch (type) { - case ENUM16: - case UINT16: - return new UnsignedWordElement(address); - case UINT32: - return new UnsignedDoublewordElement(address); - case FLOAT32: - return new FloatDoublewordElement(address); - case FLOAT64: - return new UnsignedQuadruplewordElement(address); - case STRING16: - return new StringWordElement(address, 16); - } - return null; + return switch (type) { + case ENUM16, UINT16 -> new UnsignedWordElement(address); + case UINT32 -> new UnsignedDoublewordElement(address); + case UINT64 -> new UnsignedQuadruplewordElement(address); + case FLOAT32 -> new FloatDoublewordElement(address); + case FLOAT64 -> new UnsignedQuadruplewordElement(address); + case STRING16 -> new StringWordElement(address, 16); + }; } /** diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/Config.java b/io.openems.edge.energy/src/io/openems/edge/energy/Config.java index 5b1344d5a72..dad00cde174 100644 --- a/io.openems.edge.energy/src/io/openems/edge/energy/Config.java +++ b/io.openems.edge.energy/src/io/openems/edge/energy/Config.java @@ -11,5 +11,8 @@ @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?") boolean enabled() default true; + @AttributeDefinition(name = "Log-Verbosity", description = "The log verbosity") + LogVerbosity logVerbosity() default LogVerbosity.DEBUG_LOG; + String webconsole_configurationFactory_nameHint() default "Core Energy Scheduler"; } \ No newline at end of file diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/EnergySchedulerImpl.java b/io.openems.edge.energy/src/io/openems/edge/energy/EnergySchedulerImpl.java index 1f0e892b447..88da0a70170 100644 --- a/io.openems.edge.energy/src/io/openems/edge/energy/EnergySchedulerImpl.java +++ b/io.openems.edge.energy/src/io/openems/edge/energy/EnergySchedulerImpl.java @@ -73,35 +73,39 @@ public class EnergySchedulerImpl extends AbstractOpenemsComponent @Reference(policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) private volatile Timedata timedata; + private Config config; + public EnergySchedulerImpl() { super(// OpenemsComponent.ChannelId.values(), // EnergyScheduler.ChannelId.values() // ); // Prepare Optimizer and Context - this.optimizer = new Optimizer(() -> { - if (this.timeOfUseTariff == null) { - throw new OpenemsException("TimeOfUseTariff is not available"); - } - var ctrl = this.schedulables.stream() // - .filter(TimeOfUseTariffControllerImpl.class::isInstance) // - .map(TimeOfUseTariffControllerImpl.class::cast) // - .findFirst().orElse(null); - if (ctrl == null) { - throw new OpenemsException("TimeOfUseTariffController is not available"); - } - var esh = ctrl.getEnergyScheduleHandler(); - // NOTE: This is a workaround while we refactor TimeOfUseTariffController - // This code assumes that the `EnergySchedulable` is a - // `TimeOfUseTariffController` - return GlobalContext.create() // - .setClock(this.componentManager.getClock()) // - .setEnergyScheduleHandler(esh) // - .setSum(this.sum) // - .setPredictorManager(this.predictorManager) // - .setTimeOfUseTariff(this.timeOfUseTariff) // - .build(); - }); + this.optimizer = new Optimizer(// + () -> this.config.logVerbosity(), // + () -> { + if (this.timeOfUseTariff == null) { + throw new OpenemsException("TimeOfUseTariff is not available"); + } + var ctrl = this.schedulables.stream() // + .filter(TimeOfUseTariffControllerImpl.class::isInstance) // + .map(TimeOfUseTariffControllerImpl.class::cast) // + .findFirst().orElse(null); + if (ctrl == null) { + throw new OpenemsException("TimeOfUseTariffController is not available"); + } + var esh = ctrl.getEnergyScheduleHandler(); + // NOTE: This is a workaround while we refactor TimeOfUseTariffController + // This code assumes that the `EnergySchedulable` is a + // `TimeOfUseTariffController` + return GlobalContext.create() // + .setClock(this.componentManager.getClock()) // + .setEnergyScheduleHandler(esh) // + .setSum(this.sum) // + .setPredictorManager(this.predictorManager) // + .setTimeOfUseTariff(this.timeOfUseTariff) // + .build(); + }); } @Activate @@ -121,6 +125,7 @@ private void modified(ComponentContext context, Config config) throws OpenemsNam } private synchronized boolean applyConfig(Config config) { + this.config = config; if (OpenemsComponent.validateSingleton(this.cm, SINGLETON_SERVICE_PID, SINGLETON_COMPONENT_ID)) { return false; } @@ -140,6 +145,15 @@ protected void deactivate() { super.deactivate(); } + @Override + public String debugLog() { + if (this.config == null || this.config.logVerbosity() == LogVerbosity.NONE) { + return null; + } + // TODO add debug log + return null; + } + @Override public void buildJsonApiRoutes(JsonApiBuilder builder) { builder.handleRequest(GetScheduleRequest.METHOD, call -> handleGetScheduleRequest(// diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/LogVerbosity.java b/io.openems.edge.energy/src/io/openems/edge/energy/LogVerbosity.java new file mode 100644 index 00000000000..130bd15e512 --- /dev/null +++ b/io.openems.edge.energy/src/io/openems/edge/energy/LogVerbosity.java @@ -0,0 +1,13 @@ +package io.openems.edge.energy; + +public enum LogVerbosity { + NONE, + /** + * Show basic information in Controller.Debug.Log. + */ + DEBUG_LOG, + /** + * Trace. + */ + TRACE; +} \ No newline at end of file diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Optimizer.java b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Optimizer.java index 030b0c3e4dc..3188e15f364 100644 --- a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Optimizer.java +++ b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Optimizer.java @@ -15,6 +15,7 @@ import java.time.ZonedDateTime; import java.util.Map.Entry; import java.util.TreeMap; +import java.util.function.Supplier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -24,7 +25,9 @@ import io.openems.common.exceptions.OpenemsException; import io.openems.common.function.ThrowingSupplier; import io.openems.common.test.TimeLeapClock; +import io.openems.common.utils.FunctionUtils; import io.openems.common.worker.AbstractImmediateWorker; +import io.openems.edge.energy.LogVerbosity; import io.openems.edge.energy.api.EnergyScheduleHandler; import io.openems.edge.energy.optimizer.Simulator.Period; @@ -36,12 +39,15 @@ public class Optimizer extends AbstractImmediateWorker { private final Logger log = LoggerFactory.getLogger(Optimizer.class); + private final Supplier logVerbosity; private final ThrowingSupplier globalContext; private final TreeMap schedule = new TreeMap<>(); private Params params = null; - public Optimizer(ThrowingSupplier globalContext) { + public Optimizer(Supplier logVerbosity, + ThrowingSupplier globalContext) { + this.logVerbosity = logVerbosity; this.globalContext = globalContext; initializeRandomRegistryForProduction(); @@ -51,7 +57,7 @@ public Optimizer(ThrowingSupplier globalContext @Override public void forever() throws InterruptedException, OpenemsException { - this.log.info("# Start next run of Optimizer"); + this.traceLog(() -> "Start next run of Optimizer"); this.createParams(); // this possibly takes forever @@ -89,7 +95,7 @@ public void forever() throws InterruptedException, OpenemsException { var remainingExecutionLimit = Duration .between(Instant.now(globalContext.clock()), start.plusSeconds(executionLimitSeconds)).getSeconds(); if (remainingExecutionLimit > 0) { - this.log.info("Sleep [" + remainingExecutionLimit + "s] till next run of Optimizer"); + this.traceLog(() -> "Sleep [" + remainingExecutionLimit + "s] till next run of Optimizer"); sleep(remainingExecutionLimit * 1000); } } @@ -113,7 +119,7 @@ private void createParams() throws InterruptedException { } } catch (OpenemsException e) { - this.log.info("# Stuck trying to get Params. " + e.getMessage()); + this.traceLog(() -> "Stuck trying to get Params. " + e.getMessage()); this.params = null; synchronized (this.schedule) { this.schedule.clear(); @@ -142,4 +148,11 @@ public ImmutableSortedMap getSchedule() { return ImmutableSortedMap.copyOf(this.schedule); } } + + private void traceLog(Supplier message) { + switch (this.logVerbosity.get()) { + case NONE, DEBUG_LOG -> FunctionUtils.doNothing(); + case TRACE -> this.log.info("OPTIMIZER " + message.get()); + } + } } diff --git a/io.openems.edge.energy/test/io/openems/edge/energy/EnergySchedulerImplTest.java b/io.openems.edge.energy/test/io/openems/edge/energy/EnergySchedulerImplTest.java index 10331208f63..bacd9a10260 100644 --- a/io.openems.edge.energy/test/io/openems/edge/energy/EnergySchedulerImplTest.java +++ b/io.openems.edge.energy/test/io/openems/edge/energy/EnergySchedulerImplTest.java @@ -1,6 +1,7 @@ package io.openems.edge.energy; import static io.openems.common.utils.DateUtils.roundDownToQuarter; +import static io.openems.edge.energy.LogVerbosity.TRACE; import static io.openems.edge.energy.TestData.CONSUMPTION_PREDICTION_QUARTERLY; import static io.openems.edge.energy.TestData.HOURLY_PRICES_SUMMER; import static io.openems.edge.energy.TestData.PRODUCTION_PREDICTION_QUARTERLY; @@ -74,10 +75,7 @@ public static EnergySchedulerImpl create(Clock clock) throws Exception { .activate(MyConfig.create() // .setId(CTRL_ID) // .setEnabled(false) // - .setEssId("ess0") // - .setEssMaxChargePower(5000) // - .setMaxChargePowerFromGrid(10000) // - .setLimitChargePowerFor14aEnWG(false) // + .setLogVerbosity(TRACE) // .build()) // .next(new TestCase()); return sut; diff --git a/io.openems.edge.energy/test/io/openems/edge/energy/MyConfig.java b/io.openems.edge.energy/test/io/openems/edge/energy/MyConfig.java index 2aeb9dc7bd3..1fbea17e506 100644 --- a/io.openems.edge.energy/test/io/openems/edge/energy/MyConfig.java +++ b/io.openems.edge.energy/test/io/openems/edge/energy/MyConfig.java @@ -8,10 +8,7 @@ public class MyConfig extends AbstractComponentConfig implements Config { protected static class Builder { private String id; private boolean enabled; - private String essId; - private int essMaxChargePower; - private int maxChargePowerFromGrid; - private boolean limitChargePowerFor14aEnWG; + private LogVerbosity logVerbosity; private Builder() { } @@ -26,23 +23,8 @@ public Builder setEnabled(boolean enabled) { return this; } - public Builder setEssId(String essId) { - this.essId = essId; - return this; - } - - public Builder setEssMaxChargePower(int essMaxChargePower) { - this.essMaxChargePower = essMaxChargePower; - return this; - } - - public Builder setMaxChargePowerFromGrid(int maxChargePowerFromGrid) { - this.maxChargePowerFromGrid = maxChargePowerFromGrid; - return this; - } - - public Builder setLimitChargePowerFor14aEnWG(boolean limitChargePowerFor14aEnWG) { - this.limitChargePowerFor14aEnWG = limitChargePowerFor14aEnWG; + public Builder setLogVerbosity(LogVerbosity logVerbosity) { + this.logVerbosity = logVerbosity; return this; } @@ -71,4 +53,9 @@ private MyConfig(Builder builder) { public boolean enabled() { return this.builder.enabled; } + + @Override + public LogVerbosity logVerbosity() { + return this.builder.logVerbosity; + } } \ No newline at end of file diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/HybridEss.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/HybridEss.java index 3cf5e8d2e5b..cdeb54a7736 100644 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/HybridEss.java +++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/HybridEss.java @@ -209,6 +209,8 @@ public default void _setDcDischargeEnergy(long value) { public static ModbusSlaveNatureTable getModbusSlaveNatureTable(AccessMode accessMode) { return ModbusSlaveNatureTable.of(HybridEss.class, accessMode, 100) // .channel(0, ChannelId.DC_DISCHARGE_POWER, ModbusType.UINT16) // + .channel(1, ChannelId.DC_CHARGE_ENERGY, ModbusType.FLOAT64) // + .channel(5, ChannelId.DC_DISCHARGE_ENERGY, ModbusType.FLOAT64) // .build(); } } diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ManagedSymmetricEss.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ManagedSymmetricEss.java index 616c112b519..36565ec140f 100644 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ManagedSymmetricEss.java +++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ManagedSymmetricEss.java @@ -223,7 +223,7 @@ public void accept(ManagedSymmetricEss ess, Integer value) throws OpenemsNamedEx * failed. * */ - APPLY_POWER_FAILED(Doc.of(Level.FAULT) // + APPLY_POWER_FAILED(Doc.of(Level.WARNING) // .persistencePriority(PersistencePriority.HIGH) // .text("Applying the Active/Reactive Power failed")); diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/SymmetricEss.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/SymmetricEss.java index 4c8c476ec44..4f14108fd5e 100644 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/SymmetricEss.java +++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/SymmetricEss.java @@ -215,6 +215,7 @@ public static ModbusSlaveNatureTable getModbusSlaveNatureTable(AccessMode access .channel(8, ChannelId.MAX_CELL_VOLTAGE, ModbusType.FLOAT32) // .channel(10, ChannelId.MIN_CELL_TEMPERATURE, ModbusType.FLOAT32) // .channel(12, ChannelId.MAX_CELL_TEMPERATURE, ModbusType.FLOAT32) // + .channel(14, ChannelId.CAPACITY, ModbusType.FLOAT32) // .build(); } diff --git a/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/Data.java b/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/Data.java index f0d1830e97b..8b99b973c60 100644 --- a/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/Data.java +++ b/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/Data.java @@ -30,12 +30,12 @@ public class Data { /** * Holds all Inverters, always roughly sorted by weight. */ - private final List inverters = new ArrayList<>(); + private final List inverters = new CopyOnWriteArrayList<>(); /** * Holds all Ess. */ - private final List esss = new ArrayList<>(); + private final List esss = new CopyOnWriteArrayList<>(); private final List constraints = new CopyOnWriteArrayList<>(); private final Coefficients coefficients = new Coefficients(); diff --git a/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/EssPowerImpl.java b/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/EssPowerImpl.java index 3f8a079d10f..3cea0e39de1 100644 --- a/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/EssPowerImpl.java +++ b/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/EssPowerImpl.java @@ -216,13 +216,19 @@ private int getActivePowerExtrema(ManagedSymmetricEss ess, Phase phase, Pwr pwr, @Override public void handleEvent(Event event) { - switch (event.getTopic()) { - case EdgeEventConstants.TOPIC_CYCLE_BEFORE_WRITE: - this.solver.solve(this.config.strategy()); - break; - case EdgeEventConstants.TOPIC_CYCLE_AFTER_WRITE: - this.data.initializeCycle(); - break; + try { + switch (event.getTopic()) { + case EdgeEventConstants.TOPIC_CYCLE_BEFORE_WRITE // + -> this.solver.solve(this.config.strategy()); + + case EdgeEventConstants.TOPIC_CYCLE_AFTER_WRITE // + -> this.data.initializeCycle(); + } + + } catch (Exception e) { + this.logError(this.log, + "Error during handleEvent(). " + e.getClass().getSimpleName() + ": " + e.getMessage()); + e.printStackTrace(); } } diff --git a/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/data/LinearSolverUtil.java b/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/data/LinearSolverUtil.java index 3bc672205eb..12d5182f1b9 100644 --- a/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/data/LinearSolverUtil.java +++ b/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/data/LinearSolverUtil.java @@ -1,5 +1,9 @@ package io.openems.edge.ess.core.power.data; +import static org.apache.commons.math3.optim.linear.Relationship.EQ; +import static org.apache.commons.math3.optim.linear.Relationship.GEQ; +import static org.apache.commons.math3.optim.linear.Relationship.LEQ; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -9,7 +13,6 @@ import io.openems.edge.ess.power.api.Coefficients; import io.openems.edge.ess.power.api.Constraint; -import io.openems.edge.ess.power.api.LinearCoefficient; public class LinearSolverUtil { @@ -22,28 +25,29 @@ public class LinearSolverUtil { */ public static List convertToLinearConstraints(Coefficients coefficients, List constraints) { - List result = new ArrayList<>(); + final var result = new ArrayList(); for (Constraint c : constraints) { - if (c.getValue().isPresent()) { - var cos = generateEmptyCoefficientsArray(coefficients.getNoOfCoefficients()); - for (LinearCoefficient co : c.getCoefficients()) { - // TODO verify, that ESS is enabled - cos[co.getCoefficient().getIndex()] = co.getValue(); - } - org.apache.commons.math3.optim.linear.Relationship relationship = null; - switch (c.getRelationship()) { - case EQUALS: - relationship = org.apache.commons.math3.optim.linear.Relationship.EQ; - break; - case GREATER_OR_EQUALS: - relationship = org.apache.commons.math3.optim.linear.Relationship.GEQ; - break; - case LESS_OR_EQUALS: - relationship = org.apache.commons.math3.optim.linear.Relationship.LEQ; - break; + final var value = c.getValue(); + if (value.isEmpty()) { + continue; + } + + final var cos = generateEmptyCoefficientsArray(coefficients.getNoOfCoefficients()); + for (var co : c.getCoefficients()) { + var index = co.getCoefficient().getIndex(); + if (index >= cos.length) { // check for race conditions + continue; } - result.add(new LinearConstraint(cos, relationship, c.getValue().get())); + cos[index] = co.getValue(); } + + final var relationship = switch (c.getRelationship()) { + case EQUALS -> EQ; + case GREATER_OR_EQUALS -> GEQ; + case LESS_OR_EQUALS -> LEQ; + }; + + result.add(new LinearConstraint(cos, relationship, value.get())); } return result; } diff --git a/io.openems.edge.ess.core/test/io/openems/edge/ess/core/power/data/LinearSolverUtilTest.java b/io.openems.edge.ess.core/test/io/openems/edge/ess/core/power/data/LinearSolverUtilTest.java new file mode 100644 index 00000000000..4f45a67fb89 --- /dev/null +++ b/io.openems.edge.ess.core/test/io/openems/edge/ess/core/power/data/LinearSolverUtilTest.java @@ -0,0 +1,44 @@ +package io.openems.edge.ess.core.power.data; + +import static io.openems.edge.ess.core.power.data.ConstraintUtil.createSimpleConstraint; +import static io.openems.edge.ess.power.api.Relationship.EQUALS; +import static io.openems.edge.ess.power.api.Relationship.GREATER_OR_EQUALS; +import static io.openems.edge.ess.power.api.Relationship.LESS_OR_EQUALS; + +import java.util.List; +import java.util.Set; + +import org.junit.Test; + +import io.openems.common.exceptions.OpenemsException; +import io.openems.edge.ess.power.api.Coefficients; +import io.openems.edge.ess.power.api.Constraint; +import io.openems.edge.ess.power.api.LinearCoefficient; +import io.openems.edge.ess.power.api.Phase; +import io.openems.edge.ess.power.api.Pwr; +import io.openems.edge.ess.power.api.Relationship; + +public class LinearSolverUtilTest { + + @Test(expected = OpenemsException.class) + public void testCoefficientOfThrowsException() throws OpenemsException { + createSimpleConstraint(new Coefficients(), // + "Dummy#1", "ess0", Phase.ALL, Pwr.ACTIVE, EQUALS, 0); + } + + @Test + public void testConvertToLinearConstraints() throws OpenemsException { + final var coefficients = new Coefficients(); + coefficients.initialize(false, Set.of("ess0")); + var constraints = List.of(// + createSimpleConstraint(coefficients, // + "Dummy EQUALS", "ess0", Phase.ALL, Pwr.ACTIVE, EQUALS, 0), // + createSimpleConstraint(coefficients, // + "Dummy GREATER_OR_EQUALS", "ess0", Phase.ALL, Pwr.ACTIVE, GREATER_OR_EQUALS, 0), // + createSimpleConstraint(coefficients, // + "Dummy LESS_OR_EQUALS", "ess0", Phase.ALL, Pwr.ACTIVE, LESS_OR_EQUALS, 0), // + new Constraint("Dummy empty value", new LinearCoefficient[0], Relationship.EQUALS)); + LinearSolverUtil.convertToLinearConstraints(coefficients, constraints); + } + +} 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 8f8c44bf659..669ceaa08f0 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 @@ -211,22 +211,10 @@ public ModbusSlaveTable getModbusSlaveTable(AccessMode accessMode) { @Override public StartStop getStartStopTarget() { - switch (this.startStopConfig) { - case AUTO: - // read StartStop-Channel - return this.startStopTarget.get(); - - case START: - // force START - return StartStop.START; - - case STOP: - // force STOP - return StartStop.STOP; - } - - assert false; - return StartStop.UNDEFINED; // can never happen + return switch (this.startStopConfig) { + case AUTO -> this.startStopTarget.get(); + case START -> StartStop.START; + case STOP -> StartStop.STOP; + }; } - } diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/GenericManagedEss.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/GenericManagedEss.java index 83035585f53..62ba61395fe 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/GenericManagedEss.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/GenericManagedEss.java @@ -29,14 +29,28 @@ public interface GenericManagedEss extends ManagedSymmetricEss, StartStoppable, */ public static int RETRY_COMMAND_MAX_ATTEMPTS = 30; + /** + * Retry set-command after x Seconds, e.g. for starting battery or + * battery-inverter. + */ + public static int TIMEOUT = 300; + public enum ChannelId implements io.openems.edge.common.channel.ChannelId { - MAX_BATTERY_START_ATTEMPTS_FAULT(Doc.of(Level.FAULT) // + TIMEOUT_START_BATTERY(Doc.of(Level.FAULT) // + .text("Start battery timeout passed!")), // + TIMEOUT_START_BATTERY_INVERTER(Doc.of(Level.FAULT) // + .text("Start battery inverter timeout passed!")), // + TIMEOUT_STOP_BATTERY(Doc.of(Level.FAULT) // + .text("Stop battery timeout passed!")), // + TIMEOUT_STOP_BATTERY_INVERTER(Doc.of(Level.FAULT) // + .text("Stop battery inverter timeout passed!")), // + MAX_BATTERY_START_ATTEMPTS_FAULT(Doc.of(Level.WARNING) // .text("The maximum number of Battery start attempts failed")), // - MAX_BATTERY_STOP_ATTEMPTS_FAULT(Doc.of(Level.FAULT) // + MAX_BATTERY_STOP_ATTEMPTS_FAULT(Doc.of(Level.WARNING) // .text("The maximum number of Battery stop attempts failed")), // - MAX_BATTERY_INVERTER_START_ATTEMPTS_FAULT(Doc.of(Level.FAULT) // + MAX_BATTERY_INVERTER_START_ATTEMPTS_FAULT(Doc.of(Level.WARNING) // .text("The maximum number of Battery-Inverter start attempts failed")), // - MAX_BATTERY_INVERTER_STOP_ATTEMPTS_FAULT(Doc.of(Level.FAULT) // + MAX_BATTERY_INVERTER_STOP_ATTEMPTS_FAULT(Doc.of(Level.WARNING) // .text("The maximum number of Battery-Inverter stop attempts failed")); // private final Doc doc; @@ -68,7 +82,7 @@ public default StateChannel getMaxBatteryStartAttemptsFaultChannel() { } /** - * Gets the {@link StateChannel} for + * Gets the StateChannel value for * {@link ChannelId#MAX_BATTERY_START_ATTEMPTS_FAULT}. * * @return the Channel {@link Value} @@ -97,7 +111,7 @@ public default StateChannel getMaxBatteryStopAttemptsFaultChannel() { } /** - * Gets the {@link StateChannel} for + * Gets the StateChannel value for * {@link ChannelId#MAX_BATTERY_STOP_ATTEMPTS_FAULT}. * * @return the Channel {@link Value} @@ -127,7 +141,7 @@ public default StateChannel getMaxBatteryInverterStartAttemptsFaultChannel() { } /** - * Gets the {@link StateChannel} for + * Gets the StateChannel value for * {@link ChannelId#MAX_BATTERY_INVERTER_START_ATTEMPTS_FAULT}. * * @return the Channel {@link Value} @@ -157,7 +171,7 @@ public default StateChannel getMaxBatteryInverterStopAttemptsFaultChannel() { } /** - * Gets the {@link StateChannel} for + * Gets the StateChannel value for * {@link ChannelId#MAX_BATTERY_INVERTER_STOP_ATTEMPTS_FAULT}. * * @return the Channel {@link Value} @@ -176,4 +190,118 @@ public default void _setMaxBatteryInverterStopAttemptsFault(boolean value) { this.getMaxBatteryInverterStopAttemptsFaultChannel().setNextValue(value); } + /** + * Gets the Channel for {@link ChannelId#TIMEOUT_START_BATTERY}. + * + * @return the Channel + */ + public default StateChannel getTimeoutStartBatteryChannel() { + return this.channel(ChannelId.TIMEOUT_START_BATTERY); + } + + /** + * Gets the StateChannel value for {@link ChannelId#TIMEOUT_START_BATTERY}. + * + * @return the Channel {@link Value} + */ + public default Value getTimeoutStartBattery() { + return this.getTimeoutStartBatteryChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on + * {@link ChannelId#TIMEOUT_START_BATTERY} Channel. + * + * @param value the next value + */ + public default void _setTimeoutStartBattery(boolean value) { + this.getTimeoutStartBatteryChannel().setNextValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#TIMEOUT_START_BATTERY_INVERTER}. + * + * @return the Channel + */ + public default StateChannel getTimeoutStartBatteryInverterhannel() { + return this.channel(ChannelId.TIMEOUT_START_BATTERY_INVERTER); + } + + /** + * Gets the StateChannel value for + * {@link ChannelId#TIMEOUT_START_BATTERY_INVERTER}. + * + * @return the Channel {@link Value} + */ + public default Value getTimeoutStartBatteryInverter() { + return this.getTimeoutStartBatteryInverterhannel().value(); + } + + /** + * Internal method to set the 'nextValue' on + * {@link ChannelId#TIMEOUT_START_BATTERY_INVERTER} Channel. + * + * @param value the next value + */ + public default void _setTimeoutStartBatteryInverter(boolean value) { + this.getTimeoutStartBatteryInverterhannel().setNextValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#TIMEOUT_STOP_BATTERY_INVERTER}. + * + * @return the Channel + */ + public default StateChannel getTimeoutStopBatteryInverterChannel() { + return this.channel(ChannelId.TIMEOUT_STOP_BATTERY_INVERTER); + } + + /** + * Gets the StateChannel value for + * {@link ChannelId#TIMEOUT_STOP_BATTERY_INVERTER}. + * + * @return the Channel {@link Value} + */ + public default Value getTimeoutStopBatteryInverter() { + return this.getTimeoutStopBatteryInverterChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on + * {@link ChannelId#TIMEOUT_STOP_BATTERY_INVERTER} Channel. + * + * @param value the next value + */ + public default void _setTimeoutStopBatteryInverter(boolean value) { + this.getTimeoutStopBatteryInverterChannel().setNextValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#TIMEOUT_STOP_BATTERY}. + * + * @return the Channel + */ + public default StateChannel getTimeoutStopBatteryChannel() { + return this.channel(ChannelId.TIMEOUT_STOP_BATTERY); + } + + /** + * Gets the StateChannel value for {@link ChannelId#TIMEOUT_STOP_BATTERY}. + * + * @return the Channel {@link Value} + */ + public default Value getTimeoutStopBattery() { + return this.getTimeoutStopBatteryChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on + * {@link ChannelId#TIMEOUT_STOP_BATTERY} Channel. + * + * @param value the next value + */ + public default void _setTimeoutStopBattery(boolean value) { + this.getTimeoutStopBatteryChannel().setNextValue(value); + } + } diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/offgrid/EssGenericOffGrid.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/offgrid/EssGenericOffGrid.java index a3492209db6..06a66872089 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/offgrid/EssGenericOffGrid.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/offgrid/EssGenericOffGrid.java @@ -24,7 +24,7 @@ public interface EssGenericOffGrid extends GenericManagedEss, OffGridEss, Manage public enum ChannelId implements io.openems.edge.common.channel.ChannelId { STATE_MACHINE(Doc.of(StateMachine.OffGridState.values()) // .text("Current State of State-Machine")), // - RUN_FAILED(Doc.of(Level.FAULT) // + RUN_FAILED(Doc.of(Level.WARNING) // .text("Running the Logic failed")), // ; diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/EssGenericManagedSymmetric.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/EssGenericManagedSymmetric.java index 7fe3be0fe45..7cef132c384 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/EssGenericManagedSymmetric.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/EssGenericManagedSymmetric.java @@ -4,7 +4,9 @@ import io.openems.common.channel.AccessMode; import io.openems.common.channel.Level; +import io.openems.edge.common.channel.Channel; import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.channel.value.Value; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.modbusslave.ModbusSlave; import io.openems.edge.common.modbusslave.ModbusSlaveNatureTable; @@ -40,6 +42,53 @@ public Doc doc() { } } + /** + * Gets the Channel for {@link ChannelId#STATE_MACHINE}. + * + * @return the Channel + */ + public default Channel getStateMachineChannel() { + return this.channel(ChannelId.STATE_MACHINE); + } + + /** + * Gets the StateMachine channel value for {@link ChannelId#STATE_MACHINE}. + * + * @return the Channel {@link Value} + */ + public default Value getStateMachine() { + return this.getStateMachineChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#STATE_MACHINE} + * Channel. + * + * @param value the next value + */ + public default void _setStateMachine(State value) { + this.getStateMachineChannel().setNextValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#RUN_FAILED}. + * + * @return the Channel + */ + public default Channel getRunFailedChannel() { + return this.channel(ChannelId.RUN_FAILED); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#RUN_FAILED} + * Channel. + * + * @param value the next value + */ + public default void _setRunFailed(boolean value) { + this.getRunFailedChannel().setNextValue(value); + } + @Override public default ModbusSlaveTable getModbusSlaveTable(AccessMode accessMode) { return new ModbusSlaveTable(// 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 40a3a6371af..b3d5ffaf083 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 @@ -105,23 +105,20 @@ protected void deactivate() { @Override protected void handleStateMachine() { // Store the current State - this.channel(EssGenericManagedSymmetric.ChannelId.STATE_MACHINE) - .setNextValue(this.stateMachine.getCurrentState()); + this._setStateMachine(this.stateMachine.getCurrentState()); // Initialize 'Start-Stop' Channel this._setStartStop(StartStop.UNDEFINED); // Prepare Context - var context = new Context(this, this.getBattery(), this.getBatteryInverter()); + var context = new Context(this, this.getBattery(), this.getBatteryInverter(), this.componentManager.getClock()); // Call the StateMachine try { this.stateMachine.run(context); - - this.channel(EssGenericManagedSymmetric.ChannelId.RUN_FAILED).setNextValue(false); - + this._setRunFailed(false); } catch (OpenemsNamedException e) { - this.channel(EssGenericManagedSymmetric.ChannelId.RUN_FAILED).setNextValue(true); + this._setRunFailed(true); this.logError(this.log, "StateMachine failed: " + e.getMessage()); } } @@ -179,7 +176,6 @@ public boolean isManaged() { @Override public void setStartStop(StartStop value) { if (this.startStopTarget.getAndSet(value) != value) { - // Set only if value changed this.stateMachine.forceNextState(UNDEFINED); } } diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/Context.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/Context.java index eed94199380..5a25ded906e 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/Context.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/Context.java @@ -1,5 +1,7 @@ package io.openems.edge.ess.generic.symmetric.statemachine; +import java.time.Clock; + import io.openems.edge.battery.api.Battery; import io.openems.edge.batteryinverter.api.ManagedSymmetricBatteryInverter; import io.openems.edge.common.statemachine.AbstractContext; @@ -9,10 +11,51 @@ public class Context extends AbstractContext { protected final Battery battery; protected final ManagedSymmetricBatteryInverter batteryInverter; + protected final Clock clock; - public Context(GenericManagedEss parent, Battery battery, ManagedSymmetricBatteryInverter batteryInverter) { + public Context(GenericManagedEss parent, Battery battery, ManagedSymmetricBatteryInverter batteryInverter, + Clock clock) { super(parent); this.battery = battery; this.batteryInverter = batteryInverter; + this.clock = clock; + } + + /** + * Generic ess has faults. + * + *

      + * Check for any faults in the generic ess and its dependent battery or battery + * inverter. + * + * @return true on any failure + */ + public boolean hasEssFaults() { + return this.getParent().hasFaults() || this.battery.hasFaults() || this.batteryInverter.hasFaults(); + } + + /** + * Is generic ess started. + * + *

      + * Generic ess is started when battery and battery-inverter started. + * + * @return true if battery and battery-inverter started + */ + public boolean isEssStarted() { + return this.battery.isStarted() && this.batteryInverter.isStarted(); + } + + /** + * Is generic ess stopped. + * + *

      + * Generic ess is stopped when at least the battery stopped. In many cases the + * BatteryInverter is not able to not stop. + * + * @return true if the system stopped. + */ + public boolean isEssStopped() { + return this.battery.isStopped(); } -} \ No newline at end of file +} diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/ErrorHandler.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/ErrorHandler.java index 6a2dda3271f..c64884874d3 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/ErrorHandler.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/ErrorHandler.java @@ -1,48 +1,44 @@ package io.openems.edge.ess.generic.symmetric.statemachine; -import java.time.Duration; -import java.time.Instant; - import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.edge.common.startstop.StartStop; import io.openems.edge.common.statemachine.StateHandler; import io.openems.edge.ess.generic.symmetric.statemachine.StateMachine.State; public class ErrorHandler extends StateHandler { - private static final int WAIT_TIME_IN_SECONDS = 120; - - private Instant entryAt = Instant.MIN; - private int startAttemptCounter = 0; - @Override protected void onEntry(Context context) throws OpenemsNamedException { - this.entryAt = Instant.now(); - this.startAttemptCounter++; - // Try to stop systems - context.battery.setStartStop(StartStop.STOP); - context.batteryInverter.setStartStop(StartStop.STOP); - } - - @Override - protected void onExit(Context context) throws OpenemsNamedException { - var ess = context.getParent(); - - ess._setMaxBatteryStartAttemptsFault(false); - ess._setMaxBatteryStopAttemptsFault(false); - ess._setMaxBatteryInverterStartAttemptsFault(false); - ess._setMaxBatteryInverterStopAttemptsFault(false); + context.batteryInverter.stop(); + context.battery.stop(); } @Override public State runAndGetNextState(Context context) { - if (Duration.between(this.entryAt, Instant.now()).getSeconds() > WAIT_TIME_IN_SECONDS - * Math.pow(16, this.startAttemptCounter)) { - // Try again + final var ess = context.getParent(); + final var battery = context.battery; + final var batteryInverter = context.batteryInverter; + // TODO error handling + + /* + * Wait at least for stopping the battery and check for ess, battery, + * battery-inverter faults + * + * If ModbusCommunicationFault would be a FaultState, check it explicitly. The + * battery could still have a communication fault while starting the battery. + */ + if (!ess.hasFaults() && !batteryInverter.hasFaults() && !battery.hasFaults() && context.battery.isStopped()) { return State.UNDEFINED; } return State.ERROR; } + @Override + protected void onExit(Context context) throws OpenemsNamedException { + final var ess = context.getParent(); + ess._setTimeoutStartBattery(false); + ess._setTimeoutStopBattery(false); + ess._setTimeoutStartBatteryInverter(false); + ess._setTimeoutStopBatteryInverter(false); + } } diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StartBatteryHandler.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StartBatteryHandler.java index f1f881f1163..3b12dcea87e 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StartBatteryHandler.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StartBatteryHandler.java @@ -1,54 +1,36 @@ package io.openems.edge.ess.generic.symmetric.statemachine; -import java.time.Duration; -import java.time.Instant; - import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.timedata.Timeout; import io.openems.edge.common.statemachine.StateHandler; import io.openems.edge.ess.generic.common.GenericManagedEss; import io.openems.edge.ess.generic.symmetric.statemachine.StateMachine.State; public class StartBatteryHandler extends StateHandler { - private Instant lastAttempt = Instant.MIN; - private int attemptCounter = 0; + private final Timeout timeout = Timeout.ofSeconds(GenericManagedEss.TIMEOUT); @Override protected void onEntry(Context context) throws OpenemsNamedException { - this.lastAttempt = Instant.MIN; - this.attemptCounter = 0; - var ess = context.getParent(); - ess._setMaxBatteryStartAttemptsFault(false); + this.timeout.start(context.clock); } @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - var ess = context.getParent(); + final var ess = context.getParent(); + final var battery = context.battery; - if (context.battery.isStarted()) { + if (battery.isStarted()) { return State.START_BATTERY_INVERTER; } - var isMaxStartTimePassed = Duration.between(this.lastAttempt, Instant.now()) - .getSeconds() > GenericManagedEss.RETRY_COMMAND_SECONDS; - if (!isMaxStartTimePassed) { - // Still waiting... - return State.START_BATTERY; + // Is max allowed start time passed ? + if (this.timeout.elapsed(context.clock)) { + ess._setTimeoutStartBattery(true); + return State.ERROR; } - if (this.attemptCounter > GenericManagedEss.RETRY_COMMAND_MAX_ATTEMPTS) { - // Too many tries - ess._setMaxBatteryStartAttemptsFault(true); - return State.UNDEFINED; - - } else { - // Trying to start Battery - context.battery.start(); - - this.lastAttempt = Instant.now(); - this.attemptCounter++; - return State.START_BATTERY; - } + battery.start(); + return State.START_BATTERY; } - } diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StartBatteryInverterHandler.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StartBatteryInverterHandler.java index 5b394a9f5de..128ab668d21 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StartBatteryInverterHandler.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StartBatteryInverterHandler.java @@ -1,54 +1,40 @@ package io.openems.edge.ess.generic.symmetric.statemachine; -import java.time.Duration; -import java.time.Instant; - import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.timedata.Timeout; import io.openems.edge.common.statemachine.StateHandler; import io.openems.edge.ess.generic.common.GenericManagedEss; import io.openems.edge.ess.generic.symmetric.statemachine.StateMachine.State; public class StartBatteryInverterHandler extends StateHandler { - private Instant lastAttempt = Instant.MIN; - private int attemptCounter = 0; + private final Timeout timeout = Timeout.ofSeconds(GenericManagedEss.TIMEOUT); @Override protected void onEntry(Context context) throws OpenemsNamedException { - this.lastAttempt = Instant.MIN; - this.attemptCounter = 0; - var ess = context.getParent(); - ess._setMaxBatteryInverterStartAttemptsFault(false); + this.timeout.start(context.clock); } @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - var ess = context.getParent(); + final var ess = context.getParent(); + final var inverter = context.batteryInverter; - if (context.batteryInverter.isStarted()) { - return State.STARTED; + if (context.hasEssFaults()) { + return State.ERROR; } - var isMaxStartTimePassed = Duration.between(this.lastAttempt, Instant.now()) - .getSeconds() > GenericManagedEss.RETRY_COMMAND_SECONDS; - if (!isMaxStartTimePassed) { - // Still waiting... - return State.START_BATTERY_INVERTER; + if (inverter.isStarted()) { + return State.STARTED; } - if (this.attemptCounter > GenericManagedEss.RETRY_COMMAND_MAX_ATTEMPTS) { - // Too many tries - ess._setMaxBatteryInverterStartAttemptsFault(true); - return State.UNDEFINED; - - } else { - // Trying to start Battery - context.batteryInverter.start(); - - this.lastAttempt = Instant.now(); - this.attemptCounter++; - return State.START_BATTERY_INVERTER; + // Is max allowed start time passed ? + if (this.timeout.elapsed(context.clock)) { + ess._setTimeoutStartBatteryInverter(true); + return State.ERROR; } - } + inverter.start(); + return State.START_BATTERY_INVERTER; + } } diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StartedHandler.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StartedHandler.java index 57ee53a0f41..e356b41c160 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StartedHandler.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StartedHandler.java @@ -8,24 +8,18 @@ public class StartedHandler extends StateHandler { @Override public State runAndGetNextState(Context context) { - var ess = context.getParent(); + final var ess = context.getParent(); - if (ess.hasFaults()) { - return State.UNDEFINED; + if (context.hasEssFaults()) { + return State.ERROR; } - if (!context.battery.isStarted()) { - return State.UNDEFINED; - } - - if (!context.batteryInverter.isStarted()) { - return State.UNDEFINED; + if (!context.isEssStarted()) { + return State.ERROR; } // Mark as started ess._setStartStop(StartStop.START); - return State.STARTED; } - } diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StopBatteryHandler.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StopBatteryHandler.java index 4dc84ac8898..d1e40a2ca3f 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StopBatteryHandler.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StopBatteryHandler.java @@ -1,54 +1,40 @@ package io.openems.edge.ess.generic.symmetric.statemachine; -import java.time.Duration; -import java.time.Instant; - import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.timedata.Timeout; import io.openems.edge.common.statemachine.StateHandler; import io.openems.edge.ess.generic.common.GenericManagedEss; import io.openems.edge.ess.generic.symmetric.statemachine.StateMachine.State; public class StopBatteryHandler extends StateHandler { - private Instant lastAttempt = Instant.MIN; - private int attemptCounter = 0; + private final Timeout timeout = Timeout.ofSeconds(GenericManagedEss.TIMEOUT); @Override protected void onEntry(Context context) throws OpenemsNamedException { - this.lastAttempt = Instant.MIN; - this.attemptCounter = 0; - var ess = context.getParent(); - ess._setMaxBatteryStopAttemptsFault(false); + this.timeout.start(context.clock); } @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - var ess = context.getParent(); + final var ess = context.getParent(); + final var battery = context.battery; - if (context.battery.isStopped()) { - return State.STOPPED; + if (context.hasEssFaults()) { + return State.ERROR; } - var isMaxStartTimePassed = Duration.between(this.lastAttempt, Instant.now()) - .getSeconds() > GenericManagedEss.RETRY_COMMAND_SECONDS; - if (!isMaxStartTimePassed) { - // Still waiting... - return State.STOP_BATTERY; + if (battery.isStopped()) { + return State.STOPPED; } - if (this.attemptCounter > GenericManagedEss.RETRY_COMMAND_MAX_ATTEMPTS) { - // Too many tries - ess._setMaxBatteryStopAttemptsFault(true); - return State.UNDEFINED; - - } else { - // Trying to stop Battery - context.battery.stop(); - - this.lastAttempt = Instant.now(); - this.attemptCounter++; - return State.STOP_BATTERY; + // Is max allowed start time passed ? + if (this.timeout.elapsed(context.clock)) { + ess._setTimeoutStopBattery(true); + return State.ERROR; } - } + battery.stop(); + return State.STOP_BATTERY; + } } diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StopBatteryInverterHandler.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StopBatteryInverterHandler.java index b6747fc14b6..e426221f92b 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StopBatteryInverterHandler.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StopBatteryInverterHandler.java @@ -1,54 +1,39 @@ package io.openems.edge.ess.generic.symmetric.statemachine; -import java.time.Duration; -import java.time.Instant; - import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.timedata.Timeout; import io.openems.edge.common.statemachine.StateHandler; import io.openems.edge.ess.generic.common.GenericManagedEss; import io.openems.edge.ess.generic.symmetric.statemachine.StateMachine.State; public class StopBatteryInverterHandler extends StateHandler { - private Instant lastAttempt = Instant.MIN; - private int attemptCounter = 0; + private final Timeout timeout = Timeout.ofSeconds(GenericManagedEss.TIMEOUT); @Override protected void onEntry(Context context) throws OpenemsNamedException { - this.lastAttempt = Instant.MIN; - this.attemptCounter = 0; - var ess = context.getParent(); - ess._setMaxBatteryInverterStopAttemptsFault(false); + this.timeout.start(context.clock); } @Override public State runAndGetNextState(Context context) throws OpenemsNamedException { - var ess = context.getParent(); + final var ess = context.getParent(); + + if (context.hasEssFaults()) { + return State.ERROR; + } if (context.batteryInverter.isStopped()) { return State.STOP_BATTERY; } - var isMaxStartTimePassed = Duration.between(this.lastAttempt, Instant.now()) - .getSeconds() > GenericManagedEss.RETRY_COMMAND_SECONDS; - if (!isMaxStartTimePassed) { - // Still waiting... - return State.STOP_BATTERY_INVERTER; + // Is max allowed start time passed ? + if (this.timeout.elapsed(context.clock)) { + ess._setTimeoutStopBatteryInverter(true); + return State.ERROR; } - if (this.attemptCounter > GenericManagedEss.RETRY_COMMAND_MAX_ATTEMPTS) { - // Too many tries - ess._setMaxBatteryInverterStopAttemptsFault(true); - return State.UNDEFINED; - - } else { - // Trying to stop Battery Inverter - context.batteryInverter.stop(); - this.lastAttempt = Instant.now(); - this.attemptCounter++; - return State.STOP_BATTERY_INVERTER; - - } + context.batteryInverter.stop(); + return State.STOP_BATTERY_INVERTER; } - } diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StoppedHandler.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StoppedHandler.java index f098749f006..867a9bbe7c5 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StoppedHandler.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StoppedHandler.java @@ -8,23 +8,17 @@ public class StoppedHandler extends StateHandler { @Override public State runAndGetNextState(Context context) { - var ess = context.getParent(); + final var ess = context.getParent(); - if (ess.hasFaults()) { - return State.UNDEFINED; + if (context.hasEssFaults()) { + return State.ERROR; } - if (!context.battery.isStopped()) { - return State.UNDEFINED; + if (!context.isEssStopped()) { + return State.ERROR; } - if (!context.batteryInverter.isStopped()) { - return State.UNDEFINED; - } - - // Mark as stopped ess._setStartStop(StartStop.STOP); - return State.STOPPED; } diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/UndefinedHandler.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/UndefinedHandler.java index 2075544f3ed..44d8c454b91 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/UndefinedHandler.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/UndefinedHandler.java @@ -7,33 +7,17 @@ public class UndefinedHandler extends StateHandler { @Override public State runAndGetNextState(Context context) { - var ess = context.getParent(); - switch (ess.getStartStopTarget()) { - case UNDEFINED: - // Stuck in UNDEFINED State - return State.UNDEFINED; - - case START: - // force START - if (ess.hasFaults()) { - // TODO should we consider also Battery-Inverter and Battery Faults? - // TODO should the Modbus-Device also be on error, when then Modbus-Bridge is on - // error? - - // Has Faults -> error handling - return State.ERROR; - } else { - // No Faults -> start - return State.START_BATTERY; + final var ess = context.getParent(); + return switch (ess.getStartStopTarget()) { + case UNDEFINED -> State.UNDEFINED; + case START -> { + if (ess.hasFaults() || context.batteryInverter.hasFaults()) { + yield State.ERROR; } - - case STOP: - // force STOP - return State.STOP_BATTERY_INVERTER; + yield State.START_BATTERY; } - - assert false; - return State.UNDEFINED; // can never happen + case STOP -> State.STOP_BATTERY_INVERTER; + }; } } diff --git a/io.openems.edge.ess.generic/test/io/openems/edge/ess/generic/symmetric/EssGenericManagedSymmetricImplTest.java b/io.openems.edge.ess.generic/test/io/openems/edge/ess/generic/symmetric/EssGenericManagedSymmetricImplTest.java index ac2258c43ba..10a90e7e888 100644 --- a/io.openems.edge.ess.generic/test/io/openems/edge/ess/generic/symmetric/EssGenericManagedSymmetricImplTest.java +++ b/io.openems.edge.ess.generic/test/io/openems/edge/ess/generic/symmetric/EssGenericManagedSymmetricImplTest.java @@ -133,4 +133,36 @@ public void testDebugLog() throws Exception { assertEquals("Started|SoC:60 %|L:0 W|Allowed:-56000;46550", sut.debugLog()); } + @Test + public void testTimeout() throws Exception { + final var clock = new TimeLeapClock(Instant.parse("2020-01-01T01:00:00.00Z"), ZoneOffset.UTC); + new ComponentTest(new EssGenericManagedSymmetricImpl()) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("componentManager", new DummyComponentManager(clock)) // + .addReference("batteryInverter", new DummyManagedSymmetricBatteryInverter(BATTERY_INVERTER_ID)) // + .addReference("battery", new DummyBattery(BATTERY_ID)) // + .activate(MyConfig.create() // + .setId(ESS_ID) // + .setStartStopConfig(StartStopConfig.START) // + .setBatteryInverterId(BATTERY_INVERTER_ID) // + .setBatteryId(BATTERY_ID) // + .build()) // + .next(new TestCase() // + .output(ESS_STATE_MACHINE, State.UNDEFINED)) // + .next(new TestCase() // + .output(ESS_STATE_MACHINE, State.START_BATTERY)) // + .next(new TestCase("Start the Battery") // + .input(BATTERY_START_STOP, StartStop.START)) // + .next(new TestCase() // + .output(ESS_STATE_MACHINE, State.START_BATTERY_INVERTER)) // + .next(new TestCase()// + .input(BATTERY_INVERTER_START_STOP, StartStop.STOP)// + .timeleap(clock, 350, ChronoUnit.SECONDS)// + )// + .next(new TestCase() // + .output(ESS_STATE_MACHINE, State.ERROR)) // + .next(new TestCase() // + .output(ESS_STATE_MACHINE, State.ERROR)) // + ; + } } diff --git a/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/EvcsHardyBarth.java b/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/EvcsHardyBarth.java index 4029d0495fd..60b9b2b7623 100644 --- a/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/EvcsHardyBarth.java +++ b/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/EvcsHardyBarth.java @@ -66,8 +66,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { RAW_METER_SERIALNUMBER(Doc.of(OpenemsType.STRING), "secc", "port0", "metering", "meter", "serialnumber"), // RAW_METER_TYPE(Doc.of(OpenemsType.STRING), "secc", "port0", "metering", "meter", "type"), // - METER_NOT_AVAILABLE(Doc.of(Level.INFO) // - .text("No meter values available. The communication cable of the internal meter may be loose.")), // + METER_NOT_AVAILABLE(Doc.of(Level.WARNING) // + .translationKey(EvcsHardyBarth.class, "noMeterAvailable")), // RAW_METER_AVAILABLE(new BooleanDoc()// .onChannelSetNextValue((hardyBarth, value) -> { var notAvailable = value.get() == null ? null : !value.get(); diff --git a/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/translation_de.properties b/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/translation_de.properties new file mode 100644 index 00000000000..8c5792bf010 --- /dev/null +++ b/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/translation_de.properties @@ -0,0 +1 @@ +noMeterAvailable = Keine Zhlerwerte verfgbar. Das Kommunikationskabel des (internen) Zhlers ist mglicherweise lose. \ No newline at end of file diff --git a/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/translation_en.properties b/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/translation_en.properties new file mode 100644 index 00000000000..4263f535f21 --- /dev/null +++ b/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/translation_en.properties @@ -0,0 +1 @@ +noMeterAvailable = No meter values available. The communication cable of the (internal) meter may be loose. \ No newline at end of file diff --git a/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/EvcsKebaKeContact.java b/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/EvcsKebaKeContact.java index e392f6cec85..1b4e637e250 100644 --- a/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/EvcsKebaKeContact.java +++ b/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/EvcsKebaKeContact.java @@ -119,8 +119,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { DIP_SWITCH_ERROR_2_6_NOT_SET_FOR_STATIC_IP(Doc.of(Level.FAULT) // .debounce(5, Debounce.TRUE_VALUES_IN_A_ROW_TO_SET_TRUE) // .text("A static ip is configured. The Dip-Switch 2.6. must be on")), // - DIP_SWITCH_ERROR_2_6_SET_FOR_DYNAMIC_IP(Doc.of(Level.FAULT) // - .debounce(5, Debounce.TRUE_VALUES_IN_A_ROW_TO_SET_TRUE) // + DIP_SWITCH_ERROR_2_6_SET_FOR_DYNAMIC_IP(Doc.of(OpenemsType.BOOLEAN) // .text("A dynamic ip is configured. Either the Dip-Switch 2.6. must be off or a static ip has to be configured")), // DIP_SWITCH_INFO_2_5_SET_FOR_MASTER_SLAVE_COMM(Doc.of(Level.INFO) // .debounce(5, Debounce.TRUE_VALUES_IN_A_ROW_TO_SET_TRUE) // diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverter.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverter.java index fd50c862023..c8e725dca44 100644 --- a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverter.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverter.java @@ -16,7 +16,7 @@ public interface GoodWeBatteryInverter public static enum ChannelId implements io.openems.edge.common.channel.ChannelId { STATE_MACHINE(Doc.of(State.values()) // .text("Current State of State-Machine")), // - RUN_FAILED(Doc.of(Level.FAULT) // + RUN_FAILED(Doc.of(Level.WARNING) // .text("Running the Logic failed")); // private final Doc doc; diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverterImpl.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverterImpl.java index 57f17030ddd..1b40ca0444b 100644 --- a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverterImpl.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverterImpl.java @@ -115,7 +115,7 @@ protected void setModbus(BridgeModbus modbus) { protected static record BatteryData(Integer chargeMaxCurrent, Integer voltage) { } - private Config config; + private Config config = null; public GoodWeBatteryInverterImpl() throws OpenemsNamedException { super(// @@ -167,7 +167,7 @@ protected void deactivate() { @Override public void handleEvent(Event event) { - if (!this.isEnabled()) { + if (this.config == null || !this.isEnabled()) { return; } super.handleEvent(event); diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/GoodWe.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/GoodWe.java index aa090eaa2b3..8fd557e1ffc 100644 --- a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/GoodWe.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/GoodWe.java @@ -254,12 +254,12 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId .unit(Unit.KILOWATT_HOURS)), // // Error Message 35189 - STATE_0(Doc.of(Level.FAULT) // + STATE_0(Doc.of(Level.WARNING) // .text("The Ground Fault Circuit Interrupter (GFCI) detecting circuit is abnormal " // + "| Interne Fehlerstrom-Schutzeinrichtung (RCD Einheit) wurde ausgelöst " // + "| Bitte überprüfen Sie den Netzanschluss sowie ggf. Backup-Lasten")), // - STATE_1(Doc.of(Level.FAULT) // + STATE_1(Doc.of(Level.WARNING) // .text("The output current sensor is abnormal " // + "| Der Ausgangs-Stromsensor liefert unplausible Werte " // + "| Bitte überprüfen Sie die Installation")), // @@ -269,12 +269,12 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId STATE_2(Doc.of(Level.WARNING) // .text("Warning Code 1")), // - STATE_3(Doc.of(Level.FAULT) // + STATE_3(Doc.of(Level.WARNING) // .text("DCI Consistency Failure " // + "| Werte der Impedanzmessung (DCI Einheit) sind widersprüchlich/unplausibel " // + "| Bitte überprüfen Sie den Netzanschluss")), // - STATE_4(Doc.of(Level.FAULT) // + STATE_4(Doc.of(Level.WARNING) // .text("Ground Fault Circuit Interrupter (GFCI) Consistency Failure " // + "| Werte der internen Fehlerstrom-Schutzeinrichtung (RCD) sind widersprüchlich/unplausibel " // + "| Bitte überprüfen Sie den Netzanschluss")), // @@ -284,29 +284,29 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId STATE_5(Doc.of(Level.WARNING) // .text("Warning Code 2")), // - STATE_6(Doc.of(Level.FAULT) // + STATE_6(Doc.of(Level.WARNING) // .text("Ground Fault Circuit Interrupter (GFCI) Device Failure " // + "| Interne Fehlerstrom-Schutzeinrichtung (RCD Einheit) befindet sich im Fehlerzustand " // + "| Bitte führen Sie einen Geräteneustart aus")), // - STATE_7(Doc.of(Level.FAULT) // + STATE_7(Doc.of(Level.WARNING) // .text("Relay Device Failure " // + "| Interne Relais befinden sich im Fehlerzustand " // + "| Bitte führen Sie einen Geräteneustart aus")), // - STATE_8(Doc.of(Level.FAULT) // + STATE_8(Doc.of(Level.WARNING) // .text("AC HCT Failure " // + "| Die HCT Einheit befindet sich im Fehlerzustand " // + "| Bitte führen Sie einen Geräteneustart aus")), // - STATE_9(Doc.of(Level.FAULT) // + STATE_9(Doc.of(Level.WARNING) // .text("Utility Loss " // + "| Netzausfall wurde erkannt " // + "| Bitte überprüfen Sie ob das Kommunikationsmodul richtig gesteckt ist")), // // TODO: Use new-lines or html-lists when the UI and edge log are able to handle // them - STATE_10(Doc.of(Level.FAULT) // + STATE_10(Doc.of(Level.WARNING) // .text("Ground I Failure " // + "| Erdungsfehler " // + "| Ggf. N und PE Leiter sind nicht richtig mit dem Netzanschluss des Wechselrichters verbunden. " // @@ -320,7 +320,7 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId + "| Ggf. übersteigt die Leerlauf- oder Betriebsspannung der PV-Module den für diesen Wechselrichter zulässigen Bereich. " // + "Ggf. liegt ein PV-Kriechstrom zur Erde an")), // - STATE_12(Doc.of(Level.FAULT) // + STATE_12(Doc.of(Level.WARNING) // .text("Internal Fan Failure " // + "| Der interne Lüfter meldet einen Defekt")), // @@ -331,13 +331,13 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId + "Ggf. Luftstrom durch den Kühlkörper für Normalbetrieb unzureichend (Aufstellbedingungen beachten!). " + "Ggf. Behinderung des Luftstroms, z.B. Kühlkörper wurde abgedeckt")), // - STATE_14(Doc.of(Level.FAULT) // + STATE_14(Doc.of(Level.WARNING) // .text("Utility Phase Failure " // + "| Phasenfehler " // + "| Überprüfen Sie das Drehfeld am Wechselrichter. " // + "Ggf. Kommunikationsadapter (ET+) nicht (richtig) gesteckt")), // - STATE_15(Doc.of(Level.FAULT) // + STATE_15(Doc.of(Level.WARNING) // .text("PV Over Voltage " // + "| Überspannung PV " // + "| Bitte überprüfen Sie die Installation")), // @@ -346,13 +346,13 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId .text("External Fan Failure " // + "| Externer Lüfter befindet sich im Fehlerzustand")), // - STATE_17(Doc.of(Level.FAULT) // + STATE_17(Doc.of(Level.WARNING) // .text("Vac Failure " // + "| Spannungsfehler " // + "| Die anliegende Spannung am \"On-Grid\" Anschluss befindet sich außerhalb der gültigen Parameter (für DE siehe VDE AR N 4105). " // + "Ggf. Kommunikationsmodul nicht (richtig) gesteckt")), // - STATE_18(Doc.of(Level.FAULT) // + STATE_18(Doc.of(Level.WARNING) // .text("Isolation resistance of PV-plant too low " // + "| Isolationsfehler auf PV-Strings " // + "| Bitte überprüfen Sie die Installation")), // @@ -362,7 +362,7 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId + "| DC-Strom Einspeisung auf \"On-Grid\" Seite ist zu hoch " // + "| Bitte überprüfen Sie die Installation und angeschlossene Verbraucher bzw. Erzeuger")), // - STATE_20(Doc.of(Level.FAULT) // + STATE_20(Doc.of(Level.WARNING) // .text("Back-Up Over Load " // + "| Überlastung Backup-Anschluss " // + "| Bitte beachten Sie die im Datenblatt angegebenen Maximal-Lasten")), // @@ -372,12 +372,12 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId STATE_21(Doc.of(Level.WARNING) // .text("Warning Code 3")), // - STATE_22(Doc.of(Level.FAULT) // + STATE_22(Doc.of(Level.WARNING) // .text("Difference between Master and Slave frequency too high " // + "| Frequenz zwischen Master und Slave weicht zu stark ab " // + "| Bitte führen Sie einen Geräteneustart aus")), // - STATE_23(Doc.of(Level.FAULT) // + STATE_23(Doc.of(Level.WARNING) // .text("Difference between Master and Slave voltage too high " // + "| Spannung zwischen Master und Slave weicht zu stark ab " // + "| Bitte führen Sie einen Geräteneustart aus")), // @@ -387,7 +387,7 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId STATE_24(Doc.of(Level.WARNING) // .text("Warning Code 4")), // - STATE_25(Doc.of(Level.FAULT) // + STATE_25(Doc.of(Level.WARNING) // .text("Relay Check Failure " // + "| Selbsttest der Relais ist Fehlgeschlagen " // + "| Ggf. sind N und PE-Leiter nicht richtig mit den Anschlussklemmen des Wechselrichters verbunden. " // @@ -409,17 +409,17 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId + "| Kommunikation zwischen der ARM und DSP Einheit ist fehlgeschlagen " // + "| Bitte führen Sie einen Geräteneustart aus")), // - STATE_29(Doc.of(Level.FAULT) // + STATE_29(Doc.of(Level.WARNING) // .text("The grid frequency is out of tolerable range " // + "| Die Netz-Frequenz befindet sich außerhalb der zulässigen Parameter " // + "| Bitte überprüfen Sie die Installation und führen anschließend einen Geräteneustart aus")), // - STATE_30(Doc.of(Level.FAULT) // + STATE_30(Doc.of(Level.WARNING) // .text("EEPROM cannot be read or written " // + "| EEPROM kann nicht gelesen oder geschrieben werden " // + "| Bitte führen Sie einen Geräteneustart aus")), // - STATE_31(Doc.of(Level.FAULT) // + STATE_31(Doc.of(Level.WARNING) // .text("Communication failure between microcontrollers " // + "| Die Kommunikation zwischen den einzelnen Microkontrollern ist fehlerhaft " // + "| Bitte führen Sie einen Geräteneustart aus")), // @@ -1642,7 +1642,7 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId .text("SMART mode does not work correctly with active PID filter")), NO_SMART_METER_DETECTED(Doc.of(Level.WARNING) // .text("No GoodWe Smart Meter detected. Only REMOTE mode can work correctly")), - IMPOSSIBLE_FENECON_HOME_COMBINATION(Doc.of(Level.FAULT) // + IMPOSSIBLE_FENECON_HOME_COMBINATION(Doc.of(Level.WARNING) // .text("The installed inverter and battery combination is not authorised. Operation could cause hardware damages, so charging and discharging is blocked. Please install a complete Home 10, Home 20 or Home 30 system.")), // IGNORE_IMPOSSIBLE_P_BATTERY_VALUE(Doc.of(OpenemsType.BOOLEAN) // .text("Ignore impossible battery power")) // diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/meter/grid/acting/Config.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/meter/grid/acting/Config.java index 0c62512f586..abaa040ae8f 100644 --- a/io.openems.edge.simulator/src/io/openems/edge/simulator/meter/grid/acting/Config.java +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/meter/grid/acting/Config.java @@ -20,6 +20,13 @@ @AttributeDefinition(name = "Datasource-ID", description = "ID of Simulator Datasource.") String datasource_id() default "datasource0"; + @AttributeDefinition(name = "Need frequency Step response?", description = "Need frequency Step response?") + boolean needFrequencyStepResponse() default false; + + @AttributeDefinition(name = "Start Time for frequency step response", description = "Time to Start(format: 2024-01-29 20:12:00). " + + "if the time specified is not in future or start time is not entered, Current time is used instead .") + String startTime() default "2024-01-29 20:12:00"; + @AttributeDefinition(name = "Datasource target filter", description = "This is auto-generated by 'Datasource-ID'.") String datasource_target() default "(enabled=true)"; diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/meter/grid/acting/SimulatorGridMeterActing.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/meter/grid/acting/SimulatorGridMeterActing.java index 578f38db722..c7b5b733618 100644 --- a/io.openems.edge.simulator/src/io/openems/edge/simulator/meter/grid/acting/SimulatorGridMeterActing.java +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/meter/grid/acting/SimulatorGridMeterActing.java @@ -2,9 +2,13 @@ import org.osgi.service.event.EventHandler; +import io.openems.common.channel.PersistencePriority; import io.openems.common.channel.Unit; import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.Channel; import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.channel.StateChannel; +import io.openems.edge.common.channel.value.Value; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.meter.api.ElectricityMeter; import io.openems.edge.timedata.api.TimedataProvider; @@ -12,6 +16,10 @@ public interface SimulatorGridMeterActing extends ElectricityMeter, OpenemsComponent, TimedataProvider, EventHandler { public enum ChannelId implements io.openems.edge.common.channel.ChannelId { + STATE_MACHINE(Doc.of(State.values()) // + .persistencePriority(PersistencePriority.HIGH)// + .text("Current State of State-Machine")), + SIMULATED_ACTIVE_POWER(Doc.of(OpenemsType.INTEGER) // .unit(Unit.WATT)); @@ -26,4 +34,32 @@ public Doc doc() { return this.doc; } } + + /** + * Gets the Channel for {@link ChannelId#STATE_MACHINE}. + * + * @return the Channel + */ + public default Channel getStateMachineChannel() { + return this.channel(ChannelId.STATE_MACHINE); + } + + /** + * Gets the {@link StateChannel} for {@link ChannelId#STATE_MACHINE}. + * + * @return the Channel {@link Value} + */ + public default Value getStateMachine() { + return this.getStateMachineChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#STATE_MACHINE} + * Channel. + * + * @param value the next value + */ + public default void _setStateMachine(State value) { + this.getStateMachineChannel().setNextValue(value); + } } diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/meter/grid/acting/SimulatorGridMeterActingImpl.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/meter/grid/acting/SimulatorGridMeterActingImpl.java index 1a60a481d58..215d25ac505 100644 --- a/io.openems.edge.simulator/src/io/openems/edge/simulator/meter/grid/acting/SimulatorGridMeterActingImpl.java +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/meter/grid/acting/SimulatorGridMeterActingImpl.java @@ -1,6 +1,11 @@ package io.openems.edge.simulator.meter.grid.acting; import java.io.IOException; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @@ -22,6 +27,7 @@ import io.openems.common.types.ChannelAddress; import io.openems.common.types.OpenemsType; import io.openems.edge.common.component.AbstractOpenemsComponent; +import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.event.EdgeEventConstants; import io.openems.edge.common.type.TypeUtils; @@ -33,6 +39,8 @@ import io.openems.edge.timedata.api.Timedata; import io.openems.edge.timedata.api.TimedataProvider; import io.openems.edge.timedata.api.utils.CalculateEnergyFromPower; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; @Designate(ocd = Config.class, factory = true) @Component(// @@ -49,11 +57,18 @@ public class SimulatorGridMeterActingImpl extends AbstractOpenemsComponent implements SimulatorGridMeterActing, ElectricityMeter, OpenemsComponent, TimedataProvider, EventHandler { + private final Logger log = LoggerFactory.getLogger(SimulatorGridMeterActingImpl.class); private final CalculateEnergyFromPower calculateProductionEnergy = new CalculateEnergyFromPower(this, ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY); private final CalculateEnergyFromPower calculateConsumptionEnergy = new CalculateEnergyFromPower(this, ElectricityMeter.ChannelId.ACTIVE_CONSUMPTION_ENERGY); + private StepResponseHandler stepResponseHandler; + private Config config = null; + + @Reference + private ComponentManager componentManager; + @Reference private ConfigurationAdmin cm; @@ -72,16 +87,23 @@ public SimulatorGridMeterActingImpl() { ElectricityMeter.ChannelId.values(), // SimulatorGridMeterActing.ChannelId.values() // ); + } @Activate private void activate(ComponentContext context, Config config) throws IOException { + this.config = config; super.activate(context, config.id(), config.alias(), config.enabled()); // update filter for 'datasource' if (OpenemsComponent.updateReferenceFilter(this.cm, this.servicePid(), "datasource", config.datasource_id())) { return; } + + if (this.config.needFrequencyStepResponse()) { + Instant startTime = this.convertTime(this.config.startTime()); + this.stepResponseHandler = new StepResponseHandler(this, startTime); + } } @Override @@ -103,6 +125,9 @@ public void handleEvent(Event event) { switch (event.getTopic()) { case EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE: this.updateChannels(); + if (this.config.needFrequencyStepResponse()) { + this.stepResponseHandler.doStepResponse(); + } break; case EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE: this.calculateEnergy(); @@ -168,4 +193,44 @@ public Timedata getTimedata() { return this.timedata; } + /** + * Converts a string representation of time to an Instant object. + *

      + * If the input time is null or empty, the current time is returned. If the + * input time is successfully parsed, it is converted to an Instant object. If + * the parsed time is in the past, and the current time is returned. If there's + * an error parsing the input time, and the current time is returned. + *

      + * + * @param inputTime the string representation of time to be converted + * @return an Instant converted time + */ + public Instant convertTime(String inputTime) { + + Instant currentTime = this.getCurrentTime(); + if (inputTime == null || inputTime.isEmpty()) { + return currentTime; + } + try { + LocalDateTime localDateTime = LocalDateTime.parse(inputTime, + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + Instant futureTime = localDateTime.atZone(ZoneId.systemDefault()).toInstant(); + return currentTime.isAfter(futureTime) ? currentTime : futureTime; + } catch (DateTimeParseException e) { + this.log.error( + "Error parsing input time: " + inputTime + " instead current time: " + currentTime + " is taken."); + return currentTime; + } + } + + /** + * Retrieves the current time component manager. + * + * @return An Instant representing the current time. + */ + public Instant getCurrentTime() { + var currentTime = this.componentManager.getClock().withZone(ZoneId.systemDefault()); + return Instant.now(currentTime); + } + } diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/meter/grid/acting/State.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/meter/grid/acting/State.java new file mode 100644 index 00000000000..e5c26f2332c --- /dev/null +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/meter/grid/acting/State.java @@ -0,0 +1,33 @@ +package io.openems.edge.simulator.meter.grid.acting; + +import io.openems.common.types.OptionsEnum; + +public enum State implements OptionsEnum { + UNDEFINED(-1), // + INITIAL_FREQ(1), // + FIRST_STEPDOWN_FREQUENCY(2), // + SECOND_STEPDOWN_FREQUENCY(3), // + FINISH(4); + + private final int value; + + private State(int value) { + this.value = value; + } + + @Override + public int getValue() { + return this.value; + } + + @Override + public OptionsEnum getUndefined() { + return UNDEFINED; + } + + @Override + public String getName() { + return this.name(); + } + +} diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/meter/grid/acting/StepResponseHandler.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/meter/grid/acting/StepResponseHandler.java new file mode 100644 index 00000000000..5a75825775e --- /dev/null +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/meter/grid/acting/StepResponseHandler.java @@ -0,0 +1,57 @@ +package io.openems.edge.simulator.meter.grid.acting; + +import java.time.Duration; +import java.time.Instant; + +public class StepResponseHandler { + + private State state; + private int repetitionCounter; + private SimulatorGridMeterActingImpl meter; + private Instant startTime; + + private static int TIME_THRESHOLD_SECONDS = 120; // [120 seconds in each step] + + public StepResponseHandler(SimulatorGridMeterActingImpl meter, Instant startTime) { + this.state = State.UNDEFINED; + // repeats atleast once + this.repetitionCounter = 1; + this.meter = meter; + this.startTime = startTime; + } + + /** + * State Machine for frequency step response. + */ + public void doStepResponse() { + switch (this.state) { + case UNDEFINED -> this.state = State.INITIAL_FREQ; + case INITIAL_FREQ -> this.handleStateTransition(50000, State.FIRST_STEPDOWN_FREQUENCY); + case FIRST_STEPDOWN_FREQUENCY -> this.handleStateTransition(49750, State.SECOND_STEPDOWN_FREQUENCY); + case SECOND_STEPDOWN_FREQUENCY -> this.handleStateTransition(49650, State.FINISH); + case FINISH -> { + if (this.repetitionCounter <= 1) { + this.handleFinishTransition(50000, State.FINISH); + } else { + this.repetitionCounter--; + this.handleFinishTransition(50000, State.INITIAL_FREQ); + } + } + } + this.meter._setStateMachine(this.state); + } + + private void handleStateTransition(int frequency, State nextState) { + var now = this.meter.getCurrentTime(); + this.meter._setFrequency(frequency); + if (Duration.between(this.startTime, now).getSeconds() > TIME_THRESHOLD_SECONDS) { + this.startTime = now; + this.state = nextState; + } + } + + private void handleFinishTransition(int frequency, State nextState) { + this.meter._setFrequency(frequency); + this.state = nextState; + } +} diff --git a/io.openems.edge.simulator/test/io/openems/edge/simulator/meter/grid/acting/MyConfig.java b/io.openems.edge.simulator/test/io/openems/edge/simulator/meter/grid/acting/MyConfig.java index 6367e673ebd..04a1c548104 100644 --- a/io.openems.edge.simulator/test/io/openems/edge/simulator/meter/grid/acting/MyConfig.java +++ b/io.openems.edge.simulator/test/io/openems/edge/simulator/meter/grid/acting/MyConfig.java @@ -9,6 +9,8 @@ public class MyConfig extends AbstractComponentConfig implements Config { protected static class Builder { private String id; private String datasourceId; + private String startTime; + private boolean needFrequencyStepResponse; private Builder() { } @@ -23,6 +25,16 @@ public Builder setDatasourceId(String datasourceId) { return this; } + public Builder setStartTime(String startTime) { + this.startTime = startTime; + return this; + } + + public Builder needFrequencyStepResponse(boolean needFrequencyStepResponse) { + this.needFrequencyStepResponse = needFrequencyStepResponse; + return this; + } + public MyConfig build() { return new MyConfig(this); } @@ -54,4 +66,14 @@ public String datasource_target() { return ConfigUtils.generateReferenceTargetFilter(this.id(), this.datasource_id()); } + @Override + public boolean needFrequencyStepResponse() { + return this.builder.needFrequencyStepResponse; + } + + @Override + public String startTime() { + return this.builder.startTime; + } + } \ No newline at end of file diff --git a/io.openems.edge.simulator/test/io/openems/edge/simulator/meter/grid/acting/SimulatorGridMeterActingImplTest.java b/io.openems.edge.simulator/test/io/openems/edge/simulator/meter/grid/acting/SimulatorGridMeterActingImplTest.java index 32fa540b54c..59d29433d83 100644 --- a/io.openems.edge.simulator/test/io/openems/edge/simulator/meter/grid/acting/SimulatorGridMeterActingImplTest.java +++ b/io.openems.edge.simulator/test/io/openems/edge/simulator/meter/grid/acting/SimulatorGridMeterActingImplTest.java @@ -1,9 +1,14 @@ package io.openems.edge.simulator.meter.grid.acting; +import java.time.Instant; +import java.time.ZoneOffset; + import org.junit.Test; import io.openems.common.exceptions.OpenemsException; +import io.openems.common.test.TimeLeapClock; import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.common.test.DummyConfigurationAdmin; import io.openems.edge.simulator.datasource.csv.direct.SimulatorDatasourceCsvDirectImpl; @@ -19,6 +24,24 @@ public void test() throws OpenemsException, Exception { .addReference("datasource", new SimulatorDatasourceCsvDirectImpl()) // .activate(MyConfig.create() // .setId(COMPONENT_ID) // + .setStartTime("")// + .needFrequencyStepResponse(false)// + .setDatasourceId(DATASOURCE_ID) // + .build()); // + // .next(new TestCase()); // TODO requires DummyDatasource + } + + @Test + public void test1() throws OpenemsException, Exception { + final var clock = new TimeLeapClock(Instant.parse("2024-01-29T19:05:00Z"), ZoneOffset.UTC); + new ComponentTest(new SimulatorGridMeterActingImpl()) // + .addReference("componentManager", new DummyComponentManager(clock)) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("datasource", new SimulatorDatasourceCsvDirectImpl()) // + .activate(MyConfig.create() // + .setId(COMPONENT_ID) // + .setStartTime("")// + .needFrequencyStepResponse(true)// .setDatasourceId(DATASOURCE_ID) // .build()); // // .next(new TestCase()); // TODO requires DummyDatasource diff --git a/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/Rrd4jReadHandler.java b/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/Rrd4jReadHandler.java index e12637892de..0be558ae28e 100644 --- a/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/Rrd4jReadHandler.java +++ b/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/Rrd4jReadHandler.java @@ -552,8 +552,7 @@ public CompletableFuture> getLatestValue(// try { channel = this.componentManager.getChannel(channelAddress); } catch (Exception e) { - // unable to get channel - this.log.warn("Unable to query RRD4j", e); + this.log.warn("Unable to query [" + channelAddress + "] from RRD4j: " + e.getMessage()); return Optional.empty(); } diff --git a/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/Rrd4jSupplier.java b/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/Rrd4jSupplier.java index fc0d4f2b50b..06c62d9e289 100644 --- a/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/Rrd4jSupplier.java +++ b/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/Rrd4jSupplier.java @@ -143,7 +143,7 @@ public static ChannelDef getDsDefForChannel(final Unit channelUnit) { MICROVOLT, MILLIAMPERE_HOURS, MILLIAMPERE, MILLIHERTZ, MILLIOHM, MILLISECONDS, MILLIVOLT, MILLIWATT, MINUTE, NONE, WATT, VOLT, VOLT_AMPERE, VOLT_AMPERE_REACTIVE, WATT_HOURS_BY_WATT_PEAK, OHM, SECONDS, THOUSANDTH, WATT_HOURS, KILOWATT_HOURS, VOLT_AMPERE_HOURS, VOLT_AMPERE_REACTIVE_HOURS, - KILOVOLT_AMPERE_REACTIVE_HOURS, BAR -> + KILOVOLT_AMPERE_REACTIVE_HOURS, BAR, MILLIBAR -> new ChannelDef(DsType.GAUGE, Double.NaN, Double.NaN, ConsolFun.AVERAGE); case PERCENT -> new ChannelDef(DsType.GAUGE, 0, 100, ConsolFun.AVERAGE); case ON_OFF -> new ChannelDef(DsType.GAUGE, 0, 1, ConsolFun.AVERAGE); diff --git a/io.openems.wrapper/bnd.bnd b/io.openems.wrapper/bnd.bnd index d024f94a589..c1d497e0a9f 100644 --- a/io.openems.wrapper/bnd.bnd +++ b/io.openems.wrapper/bnd.bnd @@ -18,6 +18,10 @@ Bundle-Description: This wraps external java libraries that do not have OSGi hea eu.chargetime.ocpp:OCPP-J;version='1.0.2',\ eu.chargetime.ocpp:common;version='1.0.2',\ eu.chargetime.ocpp:v1_6;version='1.1.0',\ + io.helins:linux-common;version='0.1.4',\ + io.helins:linux-errno;version='1.0.2',\ + io.helins:linux-i2c;version='1.0.2',\ + io.helins:linux-io;version='0.0.4',\ io.jenetics:jenetics;version='7.2.0',\ info.faljse:SDNotify;version='1.5.0',\ io.reactivex.rxjava3.rxjava;version='3.1.8',\ diff --git a/io.openems.wrapper/helins-linux-i2c.bnd b/io.openems.wrapper/helins-linux-i2c.bnd new file mode 100644 index 00000000000..1bda4835a21 --- /dev/null +++ b/io.openems.wrapper/helins-linux-i2c.bnd @@ -0,0 +1,20 @@ +Bundle-Name: Helins linux-i2c lib +Bundle-SymbolicName: io.openems.wrapper.helins-linux-i2c +Bundle-DocURL: https://github.com/helins/linux-i2c.jav +Bundle-License: https://opensource.org/license/mpl-2-0 +Bundle-Version: 1.0.2 + +Include-Resource: \ + @linux-i2c-1.0.2.jar,\ + @linux-common-0.1.4.jar,\ + @linux-errno-1.0.2.jar,\ + @linux-io-0.0.4.jar,\ + +-dsannotations: * + +-metatypeannotations: * + +Export-Package: \ + io.helins.linux.i2c,\ + +-sources: false \ No newline at end of file diff --git a/ui/.eslintrc.json b/ui/.eslintrc.json index 8a3902ecddb..0c5b77ab6af 100644 --- a/ui/.eslintrc.json +++ b/ui/.eslintrc.json @@ -99,6 +99,17 @@ { "allowDefaultCaseForExhaustiveSwitch": false } + ], + "no-restricted-syntax": [ + "error", + { + "selector": "CallExpression[callee.name='fdescribe']", + "message": "Using 'fdescribe' is not allowed." + }, + { + "selector": "CallExpression[callee.name='xdescribe']", + "message": "Using 'xdescribe' is not allowed." + } ] } }, diff --git a/ui/angular.json b/ui/angular.json index e1fba2f0688..11947ebaaeb 100644 --- a/ui/angular.json +++ b/ui/angular.json @@ -70,7 +70,8 @@ }, "styles": [ "src/themes/openems/scss/variables.scss", - "src/global.scss" + "src/global.scss", + "src/global-ion-custom.scss" ] }, "openems-backend-dev": { @@ -162,23 +163,23 @@ "serve": { "builder": "@angular-devkit/build-angular:dev-server", "options": { - "browserTarget": "app:build:openems,openems-edge-dev" + "buildTarget": "app:build:openems,openems-edge-dev" }, "configurations": { "openems-backend-dev": { - "browserTarget": "app:build:openems,openems-backend-dev" + "buildTarget": "app:build:openems,openems-backend-dev" }, "openems-edge-dev": { - "browserTarget": "app:build:openems,openems-edge-dev" + "buildTarget": "app:build:openems,openems-edge-dev" }, "openems-backend-prod": { - "browserTarget": "app:build:openems,openems-backend-prod,prod" + "buildTarget": "app:build:openems,openems-backend-prod,prod" }, "openems-edge-prod": { - "browserTarget": "app:build:openems,openems-edge-prod,prod" + "buildTarget": "app:build:openems,openems-edge-prod,prod" }, "openems-gitpod": { - "browserTarget": "app:build:openems,openems-gitpod" + "buildTarget": "app:build:openems,openems-gitpod" } } }, diff --git a/ui/package-lock.json b/ui/package-lock.json index 2dd132f8d58..4641fa8ea1b 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -57,7 +57,7 @@ "zone.js": "~0.14.7" }, "devDependencies": { - "@angular-devkit/build-angular": "^18.2.5", + "@angular-devkit/build-angular": "^18.2.8", "@angular-devkit/core": "18.2.5", "@angular-devkit/schematics": "18.2.5", "@angular-eslint/builder": "^18.3.1", @@ -97,7 +97,7 @@ "karma-coverage-istanbul-reporter": "~3.0.3", "karma-jasmine": "~5.1.0", "karma-jasmine-html-reporter": "^2.1.0", - "protractor": "~7.0.0", + "protractor": "^7.0.0", "ts-node": "^10.9.2", "typescript": "~5.4.5", "typescript-strict-plugin": "^2.4.4" @@ -142,17 +142,17 @@ } }, "node_modules/@angular-devkit/build-angular": { - "version": "18.2.6", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-18.2.6.tgz", - "integrity": "sha512-u12cJZttgs5j7gICHWSmcaTCu0EFXEzKqI8nkYCwq2MtuJlAXiMQSXYuEP9OU3Go4vMAPtQh2kShyOWCX5b4EQ==", + "version": "18.2.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-18.2.8.tgz", + "integrity": "sha512-qK/iLk7A8vQp1CyiJV4DpwfLjPKoiOlTtFqoO5vD8Tyxmc+R06FQp6GJTsZ7JtrTLYSiH+QAWiY6NgF/Rj/hHg==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1802.6", - "@angular-devkit/build-webpack": "0.1802.6", - "@angular-devkit/core": "18.2.6", - "@angular/build": "18.2.6", + "@angular-devkit/architect": "0.1802.8", + "@angular-devkit/build-webpack": "0.1802.8", + "@angular-devkit/core": "18.2.8", + "@angular/build": "18.2.8", "@babel/core": "7.25.2", "@babel/generator": "7.25.0", "@babel/helper-annotate-as-pure": "7.24.7", @@ -163,7 +163,7 @@ "@babel/preset-env": "7.25.3", "@babel/runtime": "7.25.0", "@discoveryjs/json-ext": "0.6.1", - "@ngtools/webpack": "18.2.6", + "@ngtools/webpack": "18.2.8", "@vitejs/plugin-basic-ssl": "1.1.0", "ansi-colors": "4.1.3", "autoprefixer": "10.4.20", @@ -271,13 +271,13 @@ } }, "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/architect": { - "version": "0.1802.6", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1802.6.tgz", - "integrity": "sha512-oF7cPFdTLxeuvXkK/opSdIxZ1E4LrBbmuytQ/nCoAGOaKBWdqvwagRZ6jVhaI0Gwu48rkcV7Zhesg/ESNnROdw==", + "version": "0.1802.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1802.8.tgz", + "integrity": "sha512-/rtFQEKgS7LlB9oHr4NCBSdKnvP5kr8L5Hbd3Vl8hZOYK9QWjxKPEXnryA2d5+PCE98bBzZswCNXqELZCPTgIQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "18.2.6", + "@angular-devkit/core": "18.2.8", "rxjs": "7.8.1" }, "engines": { @@ -287,9 +287,9 @@ } }, "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core": { - "version": "18.2.6", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.6.tgz", - "integrity": "sha512-la4CFvs5PcRWSkQ/H7TB5cPZirFVA9GoWk5LzIk8si6VjWBJRm8b3keKJoC9LlNeABRUIR5z0ocYkyQQUhdMfg==", + "version": "18.2.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.8.tgz", + "integrity": "sha512-4o2T6wsmXGE/v53+F8L7kGoN2+qzt03C9rtjLVQpOljzpJVttQ8bhvfWxyYLWwcl04RWqRa+82fpIZtBkOlZJw==", "dev": true, "license": "MIT", "dependencies": { @@ -315,14 +315,14 @@ } }, "node_modules/@angular-devkit/build-angular/node_modules/@angular/build": { - "version": "18.2.6", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-18.2.6.tgz", - "integrity": "sha512-TQzX6Mi7uXFvmz7+OVl4Za7WawYPcx+B5Ewm6IY/DdMyB9P/Z4tbKb1LO+ynWUXYwm7avXo6XQQ4m5ArDY5F/A==", + "version": "18.2.8", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-18.2.8.tgz", + "integrity": "sha512-ufuA4vHJSrL9SQW7bKV61DOoN1mm0t0ILTHaxSoCG3YF70cZJOX7+HNp3cK2uoldRMwbTOKSvCWBw54KKDRd5Q==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1802.6", + "@angular-devkit/architect": "0.1802.8", "@babel/core": "7.25.2", "@babel/helper-annotate-as-pure": "7.24.7", "@babel/helper-split-export-declaration": "7.24.7", @@ -383,6 +383,38 @@ } } }, + "node_modules/@angular-devkit/build-angular/node_modules/@babel/generator": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz", + "integrity": "sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz", + "integrity": "sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.22.4", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.4.tgz", @@ -614,6 +646,19 @@ "dev": true, "license": "MIT" }, + "node_modules/@angular-devkit/build-angular/node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@angular-devkit/build-angular/node_modules/rollup": { "version": "4.22.4", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.4.tgz", @@ -655,6 +700,7 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -663,16 +709,17 @@ "version": "2.6.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", - "dev": true + "dev": true, + "license": "0BSD" }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.1802.6", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1802.6.tgz", - "integrity": "sha512-JMLcXFaitJplwZMKkqhbYirINCRD6eOPZuIGaIOVynXYGWgvJkLT9t5C2wm9HqSLtp1K7NcYG2Y7PtTVR4krnQ==", + "version": "0.1802.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1802.8.tgz", + "integrity": "sha512-uPpopkXkO66SSdjtVr7xCyQCPs/x6KUC76xkDc4j0b8EEHifTbi/fNpbkcZ6wBmoAfjKLWXfKvtkh0TqKK5Hkw==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.1802.6", + "@angular-devkit/architect": "0.1802.8", "rxjs": "7.8.1" }, "engines": { @@ -686,13 +733,13 @@ } }, "node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/architect": { - "version": "0.1802.6", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1802.6.tgz", - "integrity": "sha512-oF7cPFdTLxeuvXkK/opSdIxZ1E4LrBbmuytQ/nCoAGOaKBWdqvwagRZ6jVhaI0Gwu48rkcV7Zhesg/ESNnROdw==", + "version": "0.1802.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1802.8.tgz", + "integrity": "sha512-/rtFQEKgS7LlB9oHr4NCBSdKnvP5kr8L5Hbd3Vl8hZOYK9QWjxKPEXnryA2d5+PCE98bBzZswCNXqELZCPTgIQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "18.2.6", + "@angular-devkit/core": "18.2.8", "rxjs": "7.8.1" }, "engines": { @@ -702,9 +749,9 @@ } }, "node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/core": { - "version": "18.2.6", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.6.tgz", - "integrity": "sha512-la4CFvs5PcRWSkQ/H7TB5cPZirFVA9GoWk5LzIk8si6VjWBJRm8b3keKJoC9LlNeABRUIR5z0ocYkyQQUhdMfg==", + "version": "18.2.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.8.tgz", + "integrity": "sha512-4o2T6wsmXGE/v53+F8L7kGoN2+qzt03C9rtjLVQpOljzpJVttQ8bhvfWxyYLWwcl04RWqRa+82fpIZtBkOlZJw==", "dev": true, "license": "MIT", "dependencies": { @@ -1139,13 +1186,13 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.7.tgz", + "integrity": "sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/highlight": "^7.24.7", + "@babel/highlight": "^7.25.7", "picocolors": "^1.0.0" }, "engines": { @@ -1153,9 +1200,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.4.tgz", - "integrity": "sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.8.tgz", + "integrity": "sha512-ZsysZyXY4Tlx+Q53XdnOFmqwfB9QDTHYxaZYajWRoBLuLEAwI2UIbtxOjWh/cFaa9IKUlcB+DDuoskLuKu56JA==", "dev": true, "license": "MIT", "engines": { @@ -1211,16 +1258,16 @@ } }, "node_modules/@babel/generator": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz", - "integrity": "sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.7.tgz", + "integrity": "sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.25.0", + "@babel/types": "^7.25.7", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" + "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" @@ -1240,29 +1287,29 @@ } }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz", - "integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.25.7.tgz", + "integrity": "sha512-12xfNeKNH7jubQNm7PAkzlLwEmCs1tfuX3UjIw6vP6QXi+leKh6+LyC/+Ed4EIQermwd58wsyh070yjDHFlNGg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", - "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.7.tgz", + "integrity": "sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.25.2", - "@babel/helper-validator-option": "^7.24.8", - "browserslist": "^4.23.1", + "@babel/compat-data": "^7.25.7", + "@babel/helper-validator-option": "^7.25.7", + "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -1281,18 +1328,18 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.4.tgz", - "integrity": "sha512-ro/bFs3/84MDgDmMwbcHgDa8/E6J3QKNTk4xJJnVeFtGE+tL0K26E3pNxhYz2b67fJpt7Aphw5XcploKXuCvCQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.7.tgz", + "integrity": "sha512-bD4WQhbkx80mAyj/WCm4ZHcF4rDxkoLFO6ph8/5/mQ3z4vAzltQXAmbc7GvVJx5H+lk5Mi5EmbTeox5nMGCsbw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-member-expression-to-functions": "^7.24.8", - "@babel/helper-optimise-call-expression": "^7.24.7", - "@babel/helper-replace-supers": "^7.25.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/traverse": "^7.25.4", + "@babel/helper-annotate-as-pure": "^7.25.7", + "@babel/helper-member-expression-to-functions": "^7.25.7", + "@babel/helper-optimise-call-expression": "^7.25.7", + "@babel/helper-replace-supers": "^7.25.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7", + "@babel/traverse": "^7.25.7", "semver": "^6.3.1" }, "engines": { @@ -1302,6 +1349,19 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/helper-annotate-as-pure": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.7.tgz", + "integrity": "sha512-4xwU8StnqnlIhhioZf1tqnVWeQ9pvH/ujS8hRfw/WOza+/a+1qv69BWNy+oY231maTCWgKWhfBU7kDpsds6zAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -1313,14 +1373,14 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.2.tgz", - "integrity": "sha512-+wqVGP+DFmqwFD3EH6TMTfUNeqDehV3E/dl+Sd54eaXqm17tEUNbEIn4sVivVowbvUpOtIGxdo3GoXyDH9N/9g==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.7.tgz", + "integrity": "sha512-byHhumTj/X47wJ6C6eLpK7wW/WBEcnUeb7D0FNc/jFQnQVw7DOso3Zz5u9x/zLrFVkHa89ZGDbkAa1D54NdrCQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "regexpu-core": "^5.3.1", + "@babel/helper-annotate-as-pure": "^7.25.7", + "regexpu-core": "^6.1.1", "semver": "^6.3.1" }, "engines": { @@ -1330,6 +1390,19 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/@babel/helper-annotate-as-pure": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.7.tgz", + "integrity": "sha512-4xwU8StnqnlIhhioZf1tqnVWeQ9pvH/ujS8hRfw/WOza+/a+1qv69BWNy+oY231maTCWgKWhfBU7kDpsds6zAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -1358,44 +1431,44 @@ } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", - "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.7.tgz", + "integrity": "sha512-O31Ssjd5K6lPbTX9AAYpSKrZmLeagt9uwschJd+Ixo6QiRyfpvgtVQp8qrDR9UNFjZ8+DO34ZkdrN+BnPXemeA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.8", - "@babel/types": "^7.24.8" + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", - "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz", + "integrity": "sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", - "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.7.tgz", + "integrity": "sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-simple-access": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7", - "@babel/traverse": "^7.25.2" + "@babel/helper-module-imports": "^7.25.7", + "@babel/helper-simple-access": "^7.25.7", + "@babel/helper-validator-identifier": "^7.25.7", + "@babel/traverse": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1405,22 +1478,22 @@ } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", - "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.7.tgz", + "integrity": "sha512-VAwcwuYhv/AT+Vfr28c9y6SHzTan1ryqrydSTFGjU0uDJHw3uZ+PduI8plCLkRsDnqK2DMEDmwrOQRsK/Ykjng==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.24.7" + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", - "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.7.tgz", + "integrity": "sha512-eaPZai0PiqCi09pPs3pAFfl/zYgGaE6IdXtYvmf0qlcDTd3WCtO7JWCcRd64e0EQrcYgiHibEZnOGsSY4QSgaw==", "dev": true, "license": "MIT", "engines": { @@ -1428,15 +1501,15 @@ } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.0.tgz", - "integrity": "sha512-NhavI2eWEIz/H9dbrG0TuOicDhNexze43i5z7lEqwYm0WEZVTwnPpA0EafUTP7+6/W79HWIP2cTe3Z5NiSTVpw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.7.tgz", + "integrity": "sha512-kRGE89hLnPfcz6fTrlNU+uhgcwv0mBE4Gv3P9Ke9kLVJYpi4AMVVEElXvB5CabrPZW4nCM8P8UyyjrzCM0O2sw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-wrap-function": "^7.25.0", - "@babel/traverse": "^7.25.0" + "@babel/helper-annotate-as-pure": "^7.25.7", + "@babel/helper-wrap-function": "^7.25.7", + "@babel/traverse": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1445,16 +1518,29 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/helper-remap-async-to-generator/node_modules/@babel/helper-annotate-as-pure": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.7.tgz", + "integrity": "sha512-4xwU8StnqnlIhhioZf1tqnVWeQ9pvH/ujS8hRfw/WOza+/a+1qv69BWNy+oY231maTCWgKWhfBU7kDpsds6zAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-replace-supers": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.0.tgz", - "integrity": "sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.7.tgz", + "integrity": "sha512-iy8JhqlUW9PtZkd4pHM96v6BdJ66Ba9yWSE4z0W4TvSZwLBPkyDsiIU3ENe4SmrzRBs76F7rQXTy1lYC49n6Lw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.24.8", - "@babel/helper-optimise-call-expression": "^7.24.7", - "@babel/traverse": "^7.25.0" + "@babel/helper-member-expression-to-functions": "^7.25.7", + "@babel/helper-optimise-call-expression": "^7.25.7", + "@babel/traverse": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1464,28 +1550,28 @@ } }, "node_modules/@babel/helper-simple-access": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", - "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.7.tgz", + "integrity": "sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", - "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.7.tgz", + "integrity": "sha512-pPbNbchZBkPMD50K0p3JGcFMNLVUCuU/ABybm/PGNj4JiHrpmNyqqCphBk4i19xXtNV0JhldQJJtbSW5aUvbyA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1505,9 +1591,9 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", - "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz", + "integrity": "sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==", "dev": true, "license": "MIT", "engines": { @@ -1515,9 +1601,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz", + "integrity": "sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==", "dev": true, "license": "MIT", "engines": { @@ -1525,9 +1611,9 @@ } }, "node_modules/@babel/helper-validator-option": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", - "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.7.tgz", + "integrity": "sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ==", "dev": true, "license": "MIT", "engines": { @@ -1535,15 +1621,15 @@ } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.0.tgz", - "integrity": "sha512-s6Q1ebqutSiZnEjaofc/UKDyC4SbzV5n5SrA2Gq8UawLycr3i04f1dX4OzoQVnexm6aOCh37SQNYlJ/8Ku+PMQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.7.tgz", + "integrity": "sha512-MA0roW3JF2bD1ptAaJnvcabsVlNQShUaThyJbCDD4bCp8NEgiFvpoqRI2YS22hHlc2thjO/fTg2ShLMC3jygAg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.25.0", - "@babel/traverse": "^7.25.0", - "@babel/types": "^7.25.0" + "@babel/template": "^7.25.7", + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1564,13 +1650,13 @@ } }, "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.7.tgz", + "integrity": "sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", + "@babel/helper-validator-identifier": "^7.25.7", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" @@ -1580,13 +1666,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.4.tgz", - "integrity": "sha512-nq+eWrOgdtu3jG5Os4TQP3x3cLA8hR8TvJNjD8vnPa20WGycimcparWnLK4jJhElTK6SDyuJo1weMKO/5LpmLA==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.8.tgz", + "integrity": "sha512-HcttkxzdPucv3nNFmfOOMfFf64KgdJVqm1KaCm25dPGMLElo9nsLvXeJECQg8UzPuBGLyTSA0ZzqCtDSzKTEoQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.25.4" + "@babel/types": "^7.25.8" }, "bin": { "parser": "bin/babel-parser.js" @@ -1596,14 +1682,14 @@ } }, "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.25.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.3.tgz", - "integrity": "sha512-wUrcsxZg6rqBXG05HG1FPYgsP6EvwF4WpBbxIpWIIYnH8wG0gzx3yZY3dtEHas4sTAOGkbTsc9EGPxwff8lRoA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.7.tgz", + "integrity": "sha512-UV9Lg53zyebzD1DwQoT9mzkEKa922LNUp5YkTJ6Uta0RbyXaQNUgcvSt7qIu1PpPzVb6rd10OVNTzkyBGeVmxQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/traverse": "^7.25.3" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/traverse": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1613,13 +1699,13 @@ } }, "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.0.tgz", - "integrity": "sha512-Bm4bH2qsX880b/3ziJ8KD711LT7z4u8CFudmjqle65AZj/HNUFhEf90dqYv6O86buWvSBmeQDjv0Tn2aF/bIBA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.7.tgz", + "integrity": "sha512-GDDWeVLNxRIkQTnJn2pDOM1pkCgYdSqPeT1a9vh9yIqu2uzzgw1zcqEb+IJOhy+dTBMlNdThrDIksr2o09qrrQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1629,13 +1715,13 @@ } }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.0.tgz", - "integrity": "sha512-lXwdNZtTmeVOOFtwM/WDe7yg1PL8sYhRk/XH0FzbR2HDQ0xC+EnQ/JHeoMYSavtU115tnUk0q9CDyq8si+LMAA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.7.tgz", + "integrity": "sha512-wxyWg2RYaSUYgmd9MR0FyRGyeOMQE/Uzr1wzd/g5cf5bwi9A4v6HFdDm7y1MgDtod/fLOSTZY6jDgV0xU9d5bA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1645,15 +1731,15 @@ } }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz", - "integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.7.tgz", + "integrity": "sha512-Xwg6tZpLxc4iQjorYsyGMyfJE7nP5MV8t/Ka58BgiA7Jw0fRqQNcANlLfdJ/yvBt9z9LD2We+BEkT7vLqZRWng==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/plugin-transform-optional-chaining": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7", + "@babel/plugin-transform-optional-chaining": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1663,14 +1749,14 @@ } }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.0.tgz", - "integrity": "sha512-tggFrk1AIShG/RUQbEwt2Tr/E+ObkfwrPjR6BjbRvsx24+PSjK8zrq0GWPNCjo8qpRx4DuJzlcvWJqlm+0h3kw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.7.tgz", + "integrity": "sha512-UVATLMidXrnH+GMUIuxq55nejlj02HP7F5ETyBONzP6G87fPBogG4CH6kxrSrdIuAjdwNO9VzyaYsrZPscWUrw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/traverse": "^7.25.0" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/traverse": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1761,13 +1847,13 @@ } }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz", - "integrity": "sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.25.7.tgz", + "integrity": "sha512-ZvZQRmME0zfJnDQnVBKYzHxXT7lYBB3Revz1GuS7oLXWMgqUPX4G+DDbT30ICClht9WKV34QVrZhSw6WdklwZQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1777,13 +1863,13 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz", - "integrity": "sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.7.tgz", + "integrity": "sha512-AqVo+dguCgmpi/3mYBdu9lkngOBlQ2w2vnNpa6gfiCxQZLzV4ZbhsXitJ2Yblkoe1VQwtHSaNmIaGll/26YWRw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1946,13 +2032,13 @@ } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz", - "integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.7.tgz", + "integrity": "sha512-EJN2mKxDwfOUCPxMO6MUI58RN3ganiRAG/MS/S3HfB6QFNjroAMelQo/gybyYq97WerCBAZoyrAoW8Tzdq2jWg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1999,13 +2085,13 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz", - "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.7.tgz", + "integrity": "sha512-xHttvIM9fvqW+0a3tZlYcZYSBpSWzGBFIt/sYG3tcdSzBB8ZeVgz2gBP7Df+sM0N1850jrviYSSeUuc+135dmQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2015,13 +2101,13 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.0.tgz", - "integrity": "sha512-yBQjYoOjXlFv9nlXb3f1casSHOZkWr29NX+zChVanLg5Nc157CrbEX9D7hxxtTpuFy7Q0YzmmWfJxzvps4kXrQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.7.tgz", + "integrity": "sha512-ZEPJSkVZaeTFG/m2PARwLZQ+OG0vFIhPlKHK/JdIMy8DbRJ/htz6LRrTFtdzxi9EHmcwbNPAKDnadpNSIW+Aow==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2031,14 +2117,14 @@ } }, "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.4.tgz", - "integrity": "sha512-nZeZHyCWPfjkdU5pA/uHiTaDAFUEqkpzf1YoQT2NeSynCGYq9rxfyI3XpQbfx/a0hSnFH6TGlEXvae5Vi7GD8g==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.7.tgz", + "integrity": "sha512-mhyfEW4gufjIqYFo9krXHJ3ElbFLIze5IDp+wQTxoPd+mwFb1NxatNAwmv8Q8Iuxv7Zc+q8EkiMQwc9IhyGf4g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.25.4", - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-create-class-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2048,15 +2134,14 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz", - "integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.25.8.tgz", + "integrity": "sha512-e82gl3TCorath6YLf9xUwFehVvjvfqFhdOo4+0iVIVju+6XOi5XHkqB3P2AXnSwoeTX0HBoXq5gJFtvotJzFnQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-class-static-block": "^7.14.5" + "@babel/helper-create-class-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2066,17 +2151,17 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.4.tgz", - "integrity": "sha512-oexUfaQle2pF/b6E0dwsxQtAol9TLSO88kQvym6HHBWFliV2lGdrPieX+WgMRLSJDVzdYywk7jXbLPuO2KLTLg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.7.tgz", + "integrity": "sha512-9j9rnl+YCQY0IGoeipXvnk3niWicIB6kCsWRGLwX241qSXpbA4MKxtp/EdvFxsc4zI5vqfLxzOd0twIJ7I99zg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-compilation-targets": "^7.25.2", - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-replace-supers": "^7.25.0", - "@babel/traverse": "^7.25.4", + "@babel/helper-annotate-as-pure": "^7.25.7", + "@babel/helper-compilation-targets": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-replace-supers": "^7.25.7", + "@babel/traverse": "^7.25.7", "globals": "^11.1.0" }, "engines": { @@ -2086,15 +2171,28 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-classes/node_modules/@babel/helper-annotate-as-pure": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.7.tgz", + "integrity": "sha512-4xwU8StnqnlIhhioZf1tqnVWeQ9pvH/ujS8hRfw/WOza+/a+1qv69BWNy+oY231maTCWgKWhfBU7kDpsds6zAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", - "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.7.tgz", + "integrity": "sha512-QIv+imtM+EtNxg/XBKL3hiWjgdLjMOmZ+XzQwSgmBfKbfxUjBzGgVPklUuE55eq5/uVoh8gg3dqlrwR/jw3ZeA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/template": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/template": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2104,13 +2202,13 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.8.tgz", - "integrity": "sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.7.tgz", + "integrity": "sha512-xKcfLTlJYUczdaM1+epcdh1UGewJqr9zATgrNHcLBcV2QmfvPPEixo/sK/syql9cEmbr7ulu5HMFG5vbbt/sEA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2120,14 +2218,14 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz", - "integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.7.tgz", + "integrity": "sha512-kXzXMMRzAtJdDEgQBLF4oaiT6ZCU3oWHgpARnTKDAqPkDJ+bs3NrZb310YYevR5QlRo3Kn7dzzIdHbZm1VzJdQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2137,13 +2235,13 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz", - "integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.7.tgz", + "integrity": "sha512-by+v2CjoL3aMnWDOyCIg+yxU9KXSRa9tN6MbqggH5xvymmr9p4AMjYkNlQy4brMceBnUyHZ9G8RnpvT8wP7Cfg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2153,14 +2251,14 @@ } }, "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.0.tgz", - "integrity": "sha512-YLpb4LlYSc3sCUa35un84poXoraOiQucUTTu8X1j18JV+gNa8E0nyUf/CjZ171IRGr4jEguF+vzJU66QZhn29g==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.7.tgz", + "integrity": "sha512-HvS6JF66xSS5rNKXLqkk7L9c/jZ/cdIVIcoPVrnl8IsVpLggTjXs8OWekbLHs/VtYDDh5WXnQyeE3PPUGm22MA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.0", - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-create-regexp-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2170,14 +2268,13 @@ } }, "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", - "integrity": "sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.8.tgz", + "integrity": "sha512-gznWY+mr4ZQL/EWPcbBQUP3BXS5FwZp8RUOw06BaRn8tQLzN4XLIxXejpHN9Qo8x8jjBmAAKp6FoS51AgkSA/A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2187,14 +2284,14 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz", - "integrity": "sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.25.7.tgz", + "integrity": "sha512-yjqtpstPfZ0h/y40fAXRv2snciYr0OAoMXY/0ClC7tm4C/nG5NJKmIItlaYlLbIVAWNfrYuy9dq1bE0SbX0PEg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2204,14 +2301,13 @@ } }, "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz", - "integrity": "sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.8.tgz", + "integrity": "sha512-sPtYrduWINTQTW7FtOy99VCTWp4H23UX7vYcut7S4CIMEXU+54zKX9uCoGkLsWXteyaMXzVHgzWbLfQ1w4GZgw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2221,14 +2317,14 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz", - "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.7.tgz", + "integrity": "sha512-n/TaiBGJxYFWvpJDfsxSj9lEEE44BFM1EPGz4KEiTipTgkoFVVcCmzAL3qA7fdQU96dpo4gGf5HBx/KnDvqiHw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2238,15 +2334,15 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.25.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.1.tgz", - "integrity": "sha512-TVVJVdW9RKMNgJJlLtHsKDTydjZAbwIsn6ySBPQaEAUU5+gVvlJt/9nRmqVbsV/IBanRjzWoaAQKLoamWVOUuA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.7.tgz", + "integrity": "sha512-5MCTNcjCMxQ63Tdu9rxyN6cAWurqfrDZ76qvVPrGYdBxIj+EawuuxTu/+dgJlhK5eRz3v1gLwp6XwS8XaX2NiQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.24.8", - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/traverse": "^7.25.1" + "@babel/helper-compilation-targets": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/traverse": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2256,14 +2352,13 @@ } }, "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz", - "integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.8.tgz", + "integrity": "sha512-4OMNv7eHTmJ2YXs3tvxAfa/I43di+VcF+M4Wt66c88EAED1RoGaf1D64cL5FkRpNL+Vx9Hds84lksWvd/wMIdA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-json-strings": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2273,13 +2368,13 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.2.tgz", - "integrity": "sha512-HQI+HcTbm9ur3Z2DkO+jgESMAMcYLuN/A7NRw9juzxAezN9AvqvUTnpKP/9kkYANz6u7dFlAyOu44ejuGySlfw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.7.tgz", + "integrity": "sha512-fwzkLrSu2fESR/cm4t6vqd7ebNIopz2QHGtjoU+dswQo/P6lwAG04Q98lliE3jkz/XqnbGFLnUcE0q0CVUf92w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2289,14 +2384,13 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz", - "integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.8.tgz", + "integrity": "sha512-f5W0AhSbbI+yY6VakT04jmxdxz+WsID0neG7+kQZbCOjuyJNdL5Nn4WIBm4hRpKnUcO9lP0eipUhFN12JpoH8g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2306,13 +2400,13 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz", - "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.7.tgz", + "integrity": "sha512-Std3kXwpXfRV0QtQy5JJcRpkqP8/wG4XL7hSKZmGlxPlDqmpXtEPRmhF7ztnlTCtUN3eXRUJp+sBEZjaIBVYaw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2322,14 +2416,14 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz", - "integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.7.tgz", + "integrity": "sha512-CgselSGCGzjQvKzghCvDTxKHP3iooenLpJDO842ehn5D2G5fJB222ptnDwQho0WjEvg7zyoxb9P+wiYxiJX5yA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2339,15 +2433,15 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz", - "integrity": "sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.25.7.tgz", + "integrity": "sha512-L9Gcahi0kKFYXvweO6n0wc3ZG1ChpSFdgG+eV1WYZ3/dGbJK7vvk91FgGgak8YwRgrCuihF8tE/Xg07EkL5COg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.24.8", - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-simple-access": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-simple-access": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2357,16 +2451,16 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.0.tgz", - "integrity": "sha512-YPJfjQPDXxyQWg/0+jHKj1llnY5f/R6a0p/vP4lPymxLu7Lvl4k2WMitqi08yxwQcCVUUdG9LCUj4TNEgAp3Jw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.7.tgz", + "integrity": "sha512-t9jZIvBmOXJsiuyOwhrIGs8dVcD6jDyg2icw1VL4A/g+FnWyJKwUfSSU2nwJuMV2Zqui856El9u+ElB+j9fV1g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.25.0", - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-validator-identifier": "^7.24.7", - "@babel/traverse": "^7.25.0" + "@babel/helper-module-transforms": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-validator-identifier": "^7.25.7", + "@babel/traverse": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2376,14 +2470,14 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz", - "integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.7.tgz", + "integrity": "sha512-p88Jg6QqsaPh+EB7I9GJrIqi1Zt4ZBHUQtjw3z1bzEXcLh6GfPqzZJ6G+G1HBGKUNukT58MnKG7EN7zXQBCODw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2393,14 +2487,14 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz", - "integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.7.tgz", + "integrity": "sha512-BtAT9LzCISKG3Dsdw5uso4oV1+v2NlVXIIomKJgQybotJY3OwCwJmkongjHgwGKoZXd0qG5UZ12JUlDQ07W6Ow==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2410,13 +2504,13 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz", - "integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.7.tgz", + "integrity": "sha512-CfCS2jDsbcZaVYxRFo2qtavW8SpdzmBXC2LOI4oO0rP+JSRDxxF3inF4GcPsLgfb5FjkhXG5/yR/lxuRs2pySA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2426,14 +2520,13 @@ } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz", - "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.8.tgz", + "integrity": "sha512-Z7WJJWdQc8yCWgAmjI3hyC+5PXIubH9yRKzkl9ZEG647O9szl9zvmKLzpbItlijBnVhTUf1cpyWBsZ3+2wjWPQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2443,14 +2536,13 @@ } }, "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz", - "integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.8.tgz", + "integrity": "sha512-rm9a5iEFPS4iMIy+/A/PiS0QN0UyjPIeVvbU5EMZFKJZHt8vQnasbpo3T3EFcxzCeYO0BHfc4RqooCZc51J86Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2460,16 +2552,15 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz", - "integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.8.tgz", + "integrity": "sha512-LkUu0O2hnUKHKE7/zYOIjByMa4VRaV2CD/cdGz0AxU9we+VA3kDDggKEzI0Oz1IroG+6gUP6UmWEHBMWZU316g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.24.7" + "@babel/helper-compilation-targets": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/plugin-transform-parameters": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2479,14 +2570,14 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz", - "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.7.tgz", + "integrity": "sha512-pWT6UXCEW3u1t2tcAGtE15ornCBvopHj9Bps9D2DsH15APgNVOTwwczGckX+WkAvBmuoYKRCFa4DK+jM8vh5AA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-replace-supers": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-replace-supers": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2496,14 +2587,13 @@ } }, "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz", - "integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.8.tgz", + "integrity": "sha512-EbQYweoMAHOn7iJ9GgZo14ghhb9tTjgOc88xFgYngifx7Z9u580cENCV159M4xDh3q/irbhSjZVpuhpC2gKBbg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2513,15 +2603,14 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz", - "integrity": "sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.8.tgz", + "integrity": "sha512-q05Bk7gXOxpTHoQ8RSzGSh/LHVB9JEIkKnk3myAWwZHnYiTGYtbdrYkIsS8Xyh4ltKf7GNUSgzs/6P2bJtBAQg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2531,13 +2620,13 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz", - "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.7.tgz", + "integrity": "sha512-FYiTvku63me9+1Nz7TOx4YMtW3tWXzfANZtrzHhUZrz4d47EEtMQhzFoZWESfXuAMMT5mwzD4+y1N8ONAX6lMQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2547,14 +2636,14 @@ } }, "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.4.tgz", - "integrity": "sha512-ao8BG7E2b/URaUQGqN3Tlsg+M3KlHY6rJ1O1gXAEUnZoyNQnvKyH87Kfg+FoxSeyWUB8ISZZsC91C44ZuBFytw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.7.tgz", + "integrity": "sha512-KY0hh2FluNxMLwOCHbxVOKfdB5sjWG4M183885FmaqWWiGMhRZq4DQRKH6mHdEucbJnyDyYiZNwNG424RymJjA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.25.4", - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-create-class-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2564,16 +2653,15 @@ } }, "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz", - "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.8.tgz", + "integrity": "sha512-8Uh966svuB4V8RHHg0QJOB32QK287NBksJOByoKmHMp1TAobNniNalIkI2i5IPj5+S9NYCG4VIjbEuiSN8r+ow==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + "@babel/helper-annotate-as-pure": "^7.25.7", + "@babel/helper-create-class-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2582,14 +2670,27 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-private-property-in-object/node_modules/@babel/helper-annotate-as-pure": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.7.tgz", + "integrity": "sha512-4xwU8StnqnlIhhioZf1tqnVWeQ9pvH/ujS8hRfw/WOza+/a+1qv69BWNy+oY231maTCWgKWhfBU7kDpsds6zAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz", - "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.7.tgz", + "integrity": "sha512-lQEeetGKfFi0wHbt8ClQrUSUMfEeI3MMm74Z73T9/kuz990yYVtfofjf3NuA42Jy3auFOpbjDyCSiIkTs1VIYw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2599,13 +2700,13 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz", - "integrity": "sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.7.tgz", + "integrity": "sha512-mgDoQCRjrY3XK95UuV60tZlFCQGXEtMg8H+IsW72ldw1ih1jZhzYXbJvghmAEpg5UVhhnCeia1CkGttUvCkiMQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-plugin-utils": "^7.25.7", "regenerator-transform": "^0.15.2" }, "engines": { @@ -2616,13 +2717,13 @@ } }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz", - "integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.7.tgz", + "integrity": "sha512-3OfyfRRqiGeOvIWSagcwUTVk2hXBsr/ww7bLn6TRTuXnexA+Udov2icFOxFX9abaj4l96ooYkcNN1qi2Zvqwng==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2663,13 +2764,13 @@ } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz", - "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.7.tgz", + "integrity": "sha512-uBbxNwimHi5Bv3hUccmOFlUy3ATO6WagTApenHz9KzoIdn0XeACdB12ZJ4cjhuB2WSi80Ez2FWzJnarccriJeA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2679,14 +2780,14 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz", - "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.7.tgz", + "integrity": "sha512-Mm6aeymI0PBh44xNIv/qvo8nmbkpZze1KvR8MkEqbIREDxoiWTi18Zr2jryfRMwDfVZF9foKh060fWgni44luw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2696,13 +2797,13 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz", - "integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.7.tgz", + "integrity": "sha512-ZFAeNkpGuLnAQ/NCsXJ6xik7Id+tHuS+NT+ue/2+rn/31zcdnupCdmunOizEaP0JsUmTFSTOPoQY7PkK2pttXw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2712,13 +2813,13 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", - "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.7.tgz", + "integrity": "sha512-SI274k0nUsFFmyQupiO7+wKATAmMFf8iFgq2O+vVFXZ0SV9lNfT1NGzBEhjquFmD8I9sqHLguH+gZVN3vww2AA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2728,13 +2829,13 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz", - "integrity": "sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.7.tgz", + "integrity": "sha512-OmWmQtTHnO8RSUbL0NTdtpbZHeNTnm68Gj5pA4Y2blFNh+V4iZR68V1qL9cI37J21ZN7AaCnkfdHtLExQPf2uA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2744,13 +2845,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz", - "integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.7.tgz", + "integrity": "sha512-BN87D7KpbdiABA+t3HbVqHzKWUDN3dymLaTnPFAMyc8lV+KN3+YzNhVRNdinaCPA4AUqx7ubXbQ9shRjYBl3SQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2760,14 +2861,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz", - "integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.7.tgz", + "integrity": "sha512-IWfR89zcEPQGB/iB408uGtSPlQd3Jpq11Im86vUgcmSTcoWAiQMCTOa2K2yNNqFJEBVICKhayctee65Ka8OB0w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2777,14 +2878,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz", - "integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.7.tgz", + "integrity": "sha512-8JKfg/hiuA3qXnlLx8qtv5HWRbgyFx2hMMtpDDuU2rTckpKkGu4ycK5yYHwuEa16/quXfoxHBIApEsNyMWnt0g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2794,14 +2895,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.4.tgz", - "integrity": "sha512-qesBxiWkgN1Q+31xUE9RcMk79eOXXDCv6tfyGMRSs4RGlioSg2WVyQAm07k726cSE56pa+Kb0y9epX2qaXzTvA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.7.tgz", + "integrity": "sha512-YRW8o9vzImwmh4Q3Rffd09bH5/hvY0pxg+1H1i0f7APoUeg12G7+HhLj9ZFNIrYkgBXhIijPJ+IXypN0hLTIbw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.2", - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-create-regexp-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2933,13 +3034,6 @@ "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@babel/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", - "dev": true, - "license": "MIT" - }, "node_modules/@babel/runtime": { "version": "7.25.0", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz", @@ -2953,32 +3047,32 @@ } }, "node_modules/@babel/template": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", - "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.7.tgz", + "integrity": "sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.25.0", - "@babel/types": "^7.25.0" + "@babel/code-frame": "^7.25.7", + "@babel/parser": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.4.tgz", - "integrity": "sha512-VJ4XsrD+nOvlXyLzmLzUs/0qjFS4sK30te5yEFlvbbUNEgKaVb2BHZUpAL+ttLPQAHNrsI3zZisbfha5Cvr8vg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.7.tgz", + "integrity": "sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.25.4", - "@babel/parser": "^7.25.4", - "@babel/template": "^7.25.0", - "@babel/types": "^7.25.4", + "@babel/code-frame": "^7.25.7", + "@babel/generator": "^7.25.7", + "@babel/parser": "^7.25.7", + "@babel/template": "^7.25.7", + "@babel/types": "^7.25.7", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -2986,31 +3080,15 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/traverse/node_modules/@babel/generator": { - "version": "7.25.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.5.tgz", - "integrity": "sha512-abd43wyLfbWoxC6ahM8xTkqLpGB2iWBVyuKC9/srhFunCd1SDNrV1s72bBpK4hLj8KLzHBBcOblvLQZBNw9r3w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.25.4", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/types": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.4.tgz", - "integrity": "sha512-zQ1ijeeCXVEh+aNL0RlmkPkG8HUiDcU2pzQQFjtbntgAczRASFzj4H+6+bV+dy1ntKR14I/DypeuRG1uma98iQ==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.8.tgz", + "integrity": "sha512-JWtuCu8VQsMladxVz/P4HzHUGCAwpuqacmowgXFs5XjxIgKuNjnLokQzuVjlTvIzODaDmpjT3oxcC48vyk9EWg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.24.8", - "@babel/helper-validator-identifier": "^7.24.7", + "@babel/helper-string-parser": "^7.25.7", + "@babel/helper-validator-identifier": "^7.25.7", "to-fast-properties": "^2.0.0" }, "engines": { @@ -3145,35 +3223,6 @@ "node": ">=8" } }, - "node_modules/@capacitor/assets/node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, - "license": "MIT", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@capacitor/assets/node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/@capacitor/assets/node_modules/open": { "version": "8.4.2", "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", @@ -3253,35 +3302,6 @@ "node": ">=8" } }, - "node_modules/@capacitor/cli/node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, - "license": "MIT", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@capacitor/cli/node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/@capacitor/cli/node_modules/open": { "version": "8.4.2", "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", @@ -4793,35 +4813,6 @@ "node": ">=8" } }, - "node_modules/@ionic/cli/node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, - "license": "MIT", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@ionic/cli/node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/@ionic/cli/node_modules/open": { "version": "7.4.2", "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", @@ -5470,9 +5461,9 @@ } }, "node_modules/@jsonjoy.com/util": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.3.0.tgz", - "integrity": "sha512-Cebt4Vk7k1xHy87kHY7KSPLT77A7Ev7IfOblyLZhtYEhrdQ6fX4EoLq3xOQ3O/DRMEh2ok5nyC180E+ABS8Wmw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.5.0.tgz", + "integrity": "sha512-ojoNsrIuPI9g6o8UxhraZQSyF2ByJanAY4cTFbc8Mf2AXEF4aQRGY1dJxyJpuyav8r9FGflEt/Ff3u5Nt6YMPA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -5684,9 +5675,9 @@ ] }, "node_modules/@ngtools/webpack": { - "version": "18.2.6", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.2.6.tgz", - "integrity": "sha512-7HwOPE1EOgcHnpt4brSiT8G2CcXB50G0+CbCBaKGy4LYCG3Y3mrlzF5Fup9HvMJ6Tzqd62RqzpKKYBiGUT7hxg==", + "version": "18.2.8", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.2.8.tgz", + "integrity": "sha512-sq0kI8gEen4QlM6X8XqOYy7j4B8iLCYNo+iKxatV36ts4AXH0MuVkP56+oMaoH5oZNoSqd0RlfnotEHfvJAr8A==", "dev": true, "license": "MIT", "engines": { @@ -6238,9 +6229,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.23.0.tgz", - "integrity": "sha512-8OR+Ok3SGEMsAZispLx8jruuXw0HVF16k+ub2eNXKHDmdxL4cf9NlNpAzhlOhNyXzKDEJuFeq0nZm+XlNb1IFw==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz", + "integrity": "sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==", "cpu": [ "arm" ], @@ -6252,9 +6243,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.23.0.tgz", - "integrity": "sha512-rEFtX1nP8gqmLmPZsXRMoLVNB5JBwOzIAk/XAcEPuKrPa2nPJ+DuGGpfQUR0XjRm8KjHfTZLpWbKXkA5BoFL3w==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz", + "integrity": "sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==", "cpu": [ "arm64" ], @@ -6266,9 +6257,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.23.0.tgz", - "integrity": "sha512-ZbqlMkJRMMPeapfaU4drYHns7Q5MIxjM/QeOO62qQZGPh9XWziap+NF9fsqPHT0KzEL6HaPspC7sOwpgyA3J9g==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz", + "integrity": "sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==", "cpu": [ "arm64" ], @@ -6280,9 +6271,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.23.0.tgz", - "integrity": "sha512-PfmgQp78xx5rBCgn2oYPQ1rQTtOaQCna0kRaBlc5w7RlA3TDGGo7m3XaptgitUZ54US9915i7KeVPHoy3/W8tA==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz", + "integrity": "sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==", "cpu": [ "x64" ], @@ -6294,9 +6285,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.23.0.tgz", - "integrity": "sha512-WAeZfAAPus56eQgBioezXRRzArAjWJGjNo/M+BHZygUcs9EePIuGI1Wfc6U/Ki+tMW17FFGvhCfYnfcKPh18SA==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz", + "integrity": "sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==", "cpu": [ "arm" ], @@ -6308,9 +6299,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.23.0.tgz", - "integrity": "sha512-v7PGcp1O5XKZxKX8phTXtmJDVpE20Ub1eF6w9iMmI3qrrPak6yR9/5eeq7ziLMrMTjppkkskXyxnmm00HdtXjA==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz", + "integrity": "sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==", "cpu": [ "arm" ], @@ -6322,9 +6313,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.23.0.tgz", - "integrity": "sha512-nAbWsDZ9UkU6xQiXEyXBNHAKbzSAi95H3gTStJq9UGiS1v+YVXwRHcQOQEF/3CHuhX5BVhShKoeOf6Q/1M+Zhg==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz", + "integrity": "sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==", "cpu": [ "arm64" ], @@ -6336,9 +6327,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.23.0.tgz", - "integrity": "sha512-5QT/Di5FbGNPaVw8hHO1wETunwkPuZBIu6W+5GNArlKHD9fkMHy7vS8zGHJk38oObXfWdsuLMogD4sBySLJ54g==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz", + "integrity": "sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==", "cpu": [ "arm64" ], @@ -6350,9 +6341,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.23.0.tgz", - "integrity": "sha512-Sefl6vPyn5axzCsO13r1sHLcmPuiSOrKIImnq34CBurntcJ+lkQgAaTt/9JkgGmaZJ+OkaHmAJl4Bfd0DmdtOQ==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz", + "integrity": "sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==", "cpu": [ "ppc64" ], @@ -6364,9 +6355,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.23.0.tgz", - "integrity": "sha512-o4QI2KU/QbP7ZExMse6ULotdV3oJUYMrdx3rBZCgUF3ur3gJPfe8Fuasn6tia16c5kZBBw0aTmaUygad6VB/hQ==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz", + "integrity": "sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==", "cpu": [ "riscv64" ], @@ -6378,9 +6369,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.23.0.tgz", - "integrity": "sha512-+bxqx+V/D4FGrpXzPGKp/SEZIZ8cIW3K7wOtcJAoCrmXvzRtmdUhYNbgd+RztLzfDEfA2WtKj5F4tcbNPuqgeg==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz", + "integrity": "sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==", "cpu": [ "s390x" ], @@ -6392,9 +6383,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.23.0.tgz", - "integrity": "sha512-I/eXsdVoCKtSgK9OwyQKPAfricWKUMNCwJKtatRYMmDo5N859tbO3UsBw5kT3dU1n6ZcM1JDzPRSGhAUkxfLxw==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz", + "integrity": "sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==", "cpu": [ "x64" ], @@ -6406,9 +6397,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.23.0.tgz", - "integrity": "sha512-4ZoDZy5ShLbbe1KPSafbFh1vbl0asTVfkABC7eWqIs01+66ncM82YJxV2VtV3YVJTqq2P8HMx3DCoRSWB/N3rw==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz", + "integrity": "sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==", "cpu": [ "x64" ], @@ -6420,9 +6411,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.23.0.tgz", - "integrity": "sha512-+5Ky8dhft4STaOEbZu3/NU4QIyYssKO+r1cD3FzuusA0vO5gso15on7qGzKdNXnc1gOrsgCqZjRw1w+zL4y4hQ==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz", + "integrity": "sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==", "cpu": [ "arm64" ], @@ -6434,9 +6425,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.23.0.tgz", - "integrity": "sha512-0SPJk4cPZQhq9qA1UhIRumSE3+JJIBBjtlGl5PNC///BoaByckNZd53rOYD0glpTkYFBQSt7AkMeLVPfx65+BQ==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz", + "integrity": "sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==", "cpu": [ "ia32" ], @@ -6448,9 +6439,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.23.0.tgz", - "integrity": "sha512-lqCK5GQC8fNo0+JvTSxcG7YB1UKYp8yrNLhsArlvPWN+16ovSZgoehlVHg6X0sSWPUkpjRBR5TuR12ZugowZ4g==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz", + "integrity": "sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==", "cpu": [ "x64" ], @@ -7936,9 +7927,9 @@ } }, "node_modules/adm-zip": { - "version": "0.5.15", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.15.tgz", - "integrity": "sha512-jYPWSeOA8EFoZnucrKCNihqBjoEGQSU4HKgHYQgKNEQ0pQF9a/DYuo/+fAxY76k4qe75LUlLWpAM1QWcBMTOKw==", + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.16.tgz", + "integrity": "sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==", "dev": true, "license": "MIT", "engines": { @@ -8437,9 +8428,9 @@ } }, "node_modules/aws4": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.1.tgz", - "integrity": "sha512-u5w79Rd7SU4JaIlA/zFqG+gOiuq25q5VLyZ8E+ijJeILuTxVzZgp2CaGw/UTw6pXYN9XMO9yiqj/nEHmhTG5CA==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz", + "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==", "dev": true, "license": "MIT" }, @@ -8824,9 +8815,9 @@ } }, "node_modules/browserslist": { - "version": "4.23.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", - "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", + "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", "dev": true, "funding": [ { @@ -8844,8 +8835,8 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001646", - "electron-to-chromium": "^1.5.4", + "caniuse-lite": "^1.0.30001663", + "electron-to-chromium": "^1.5.28", "node-releases": "^2.0.18", "update-browserslist-db": "^1.1.0" }, @@ -9081,9 +9072,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001653", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001653.tgz", - "integrity": "sha512-XGWQVB8wFQ2+9NZwZ10GxTYC5hk0Fa+q8cSkr0tgvMhYhMHP/QC+WTgrePMDBWiWc/pV+1ik82Al20XOK25Gcw==", + "version": "1.0.30001668", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001668.tgz", + "integrity": "sha512-nWLrdxqCdblixUO+27JtGJJE/txpJlyUy5YN1u53wLZkP0emYCo5zgS6QYft7VUYR42LGgi/S5hdLZTrnyIddw==", "dev": true, "funding": [ { @@ -10064,9 +10055,9 @@ "license": "MIT" }, "node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "dev": true, "license": "MIT", "engines": { @@ -11603,9 +11594,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.13", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz", - "integrity": "sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==", + "version": "1.5.36", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.36.tgz", + "integrity": "sha512-HYTX8tKge/VNp6FGO+f/uVDmUkq+cEfcxYhKf15Akc4M5yxt5YmorwlAitKWjWhWQnKcDRBAQKXkhqqXMqcrjw==", "dev": true, "license": "ISC" }, @@ -11671,9 +11662,9 @@ } }, "node_modules/engine.io": { - "version": "6.5.5", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz", - "integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==", + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.2.tgz", + "integrity": "sha512-gmNvsYi9C8iErnZdVcJnvCpSKbWTt1E8+JZo8b+daLninywUWi5NQ5STSHZ9rFjFO7imNcvb8Pc5pe/wMR5xEw==", "dev": true, "license": "MIT", "dependencies": { @@ -11682,7 +11673,7 @@ "@types/node": ">=10.0.0", "accepts": "~1.3.4", "base64id": "2.0.0", - "cookie": "~0.4.1", + "cookie": "~0.7.2", "cors": "~2.8.5", "debug": "~4.3.1", "engine.io-parser": "~5.2.1", @@ -12753,9 +12744,9 @@ "license": "Apache-2.0" }, "node_modules/express": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", - "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", "dev": true, "license": "MIT", "dependencies": { @@ -12764,7 +12755,7 @@ "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -12796,9 +12787,9 @@ } }, "node_modules/express/node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "dev": true, "license": "MIT", "engines": { @@ -14391,6 +14382,19 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/http-proxy-middleware/node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -14913,16 +14917,16 @@ } }, "node_modules/is-docker": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", - "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "dev": true, "license": "MIT", "bin": { "is-docker": "cli.js" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -14980,6 +14984,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-inside-container/node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-interactive": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", @@ -15105,16 +15125,13 @@ } }, "node_modules/is-plain-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", "dev": true, "license": "MIT", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, "node_modules/is-plain-object": { @@ -15277,19 +15294,16 @@ "license": "MIT" }, "node_modules/is-wsl": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", - "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "dev": true, "license": "MIT", "dependencies": { - "is-inside-container": "^1.0.0" + "is-docker": "^2.0.0" }, "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, "node_modules/isarray": { @@ -15594,16 +15608,16 @@ } }, "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/json-buffer": { @@ -17216,9 +17230,9 @@ } }, "node_modules/memfs": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.12.0.tgz", - "integrity": "sha512-74wDsex5tQDSClVkeK1vtxqYCAgCoXxx+K4NSHzgU/muYVYByFqa+0RnrPO9NM6naWm1+G9JmZ0p6QHhXmeYfA==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.13.0.tgz", + "integrity": "sha512-dIs5KGy24fbdDhIAg0RxXpFqQp3RwL6wgSMRF9OSuphL/Uc9a4u2/SDJKPLj/zUgtOGKuHrRMrj563+IErj4Cg==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -17650,16 +17664,6 @@ "node": ">= 6" } }, - "node_modules/minimist-options/node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/minipass": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", @@ -18850,6 +18854,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/open/node_modules/is-wsl": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -20620,9 +20640,9 @@ "license": "MIT" }, "node_modules/regenerate-unicode-properties": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", - "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", "dev": true, "license": "MIT", "dependencies": { @@ -20682,16 +20702,16 @@ } }, "node_modules/regexpu-core": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", - "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.1.1.tgz", + "integrity": "sha512-k67Nb9jvwJcJmVpw0jPttR1/zVfnKf8Km0IPatrU/zJ5XeG3+Slx0xLXs9HByJSzXzrlz5EDvN6yLNMDc2qdnw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/regjsgen": "^0.8.0", "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsparser": "^0.9.1", + "regenerate-unicode-properties": "^10.2.0", + "regjsgen": "^0.8.0", + "regjsparser": "^0.11.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.1.0" }, @@ -20699,28 +20719,26 @@ "node": ">=4" } }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true, + "license": "MIT" + }, "node_modules/regjsparser": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.11.1.tgz", + "integrity": "sha512-1DHODs4B8p/mQHU9kr+jv8+wIC9mtG4eBHxWxIq5mhjE3D5oORhCc6deRKzTjs9DcfRFmj9BHSDguZklqCGFWQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "jsesc": "~0.5.0" + "jsesc": "~3.0.2" }, "bin": { "regjsparser": "bin/parser" } }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - } - }, "node_modules/replace": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/replace/-/replace-1.2.2.tgz", @@ -21172,9 +21190,9 @@ "license": "Unlicense" }, "node_modules/rollup": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.23.0.tgz", - "integrity": "sha512-vXB4IT9/KLDrS2WRXmY22sVB2wTsTwkpxjB8Q3mnakTENcYw3FRmfdYDy/acNmls+lHmDazgrRjK/yQ6hQAtwA==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.0.tgz", + "integrity": "sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==", "dev": true, "license": "MIT", "dependencies": { @@ -21188,22 +21206,22 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.23.0", - "@rollup/rollup-android-arm64": "4.23.0", - "@rollup/rollup-darwin-arm64": "4.23.0", - "@rollup/rollup-darwin-x64": "4.23.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.23.0", - "@rollup/rollup-linux-arm-musleabihf": "4.23.0", - "@rollup/rollup-linux-arm64-gnu": "4.23.0", - "@rollup/rollup-linux-arm64-musl": "4.23.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.23.0", - "@rollup/rollup-linux-riscv64-gnu": "4.23.0", - "@rollup/rollup-linux-s390x-gnu": "4.23.0", - "@rollup/rollup-linux-x64-gnu": "4.23.0", - "@rollup/rollup-linux-x64-musl": "4.23.0", - "@rollup/rollup-win32-arm64-msvc": "4.23.0", - "@rollup/rollup-win32-ia32-msvc": "4.23.0", - "@rollup/rollup-win32-x64-msvc": "4.23.0", + "@rollup/rollup-android-arm-eabi": "4.24.0", + "@rollup/rollup-android-arm64": "4.24.0", + "@rollup/rollup-darwin-arm64": "4.24.0", + "@rollup/rollup-darwin-x64": "4.24.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.24.0", + "@rollup/rollup-linux-arm-musleabihf": "4.24.0", + "@rollup/rollup-linux-arm64-gnu": "4.24.0", + "@rollup/rollup-linux-arm64-musl": "4.24.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.24.0", + "@rollup/rollup-linux-riscv64-gnu": "4.24.0", + "@rollup/rollup-linux-s390x-gnu": "4.24.0", + "@rollup/rollup-linux-x64-gnu": "4.24.0", + "@rollup/rollup-linux-x64-musl": "4.24.0", + "@rollup/rollup-win32-arm64-msvc": "4.24.0", + "@rollup/rollup-win32-ia32-msvc": "4.24.0", + "@rollup/rollup-win32-x64-msvc": "4.24.0", "fsevents": "~2.3.2" } }, @@ -22173,9 +22191,9 @@ } }, "node_modules/socket.io": { - "version": "4.7.5", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", - "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==", + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.0.tgz", + "integrity": "sha512-8U6BEgGjQOfGz3HHTYaC/L1GaxDCJ/KM0XTkJly0EhZ5U/du9uNEZy4ZgYzEzIqlx2CMm25CrCqr1ck899eLNA==", "dev": true, "license": "MIT", "dependencies": { @@ -22183,7 +22201,7 @@ "base64id": "~2.0.0", "cors": "~2.8.5", "debug": "~4.3.2", - "engine.io": "~6.5.2", + "engine.io": "~6.6.0", "socket.io-adapter": "~2.5.2", "socket.io-parser": "~4.2.4" }, @@ -22283,6 +22301,7 @@ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -23842,9 +23861,9 @@ "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", "dev": true, "license": "MIT", "engines": { @@ -23866,9 +23885,9 @@ } }, "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", "dev": true, "license": "MIT", "engines": { @@ -25059,9 +25078,9 @@ } }, "node_modules/webpack-dev-server/node_modules/http-proxy-middleware": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", - "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz", + "integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==", "dev": true, "license": "MIT", "dependencies": { @@ -25083,6 +25102,19 @@ } } }, + "node_modules/webpack-dev-server/node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/webpack-dev-server/node_modules/rimraf": { "version": "5.0.10", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", diff --git a/ui/package.json b/ui/package.json index d1e7e5250b9..65e20fe3d95 100644 --- a/ui/package.json +++ b/ui/package.json @@ -52,7 +52,7 @@ "zone.js": "~0.14.7" }, "devDependencies": { - "@angular-devkit/build-angular": "^18.2.5", + "@angular-devkit/build-angular": "^18.2.8", "@angular-devkit/core": "18.2.5", "@angular-devkit/schematics": "18.2.5", "@angular-eslint/builder": "^18.3.1", @@ -92,7 +92,7 @@ "karma-coverage-istanbul-reporter": "~3.0.3", "karma-jasmine": "~5.1.0", "karma-jasmine-html-reporter": "^2.1.0", - "protractor": "~7.0.0", + "protractor": "^7.0.0", "ts-node": "^10.9.2", "typescript": "~5.4.5", "typescript-strict-plugin": "^2.4.4" diff --git a/ui/src/app/app-routing.module.ts b/ui/src/app/app-routing.module.ts index f84be2e897f..a6324b0d68b 100644 --- a/ui/src/app/app-routing.module.ts +++ b/ui/src/app/app-routing.module.ts @@ -91,6 +91,7 @@ export const routes: Routes = [ { path: ":componentId/gridOptimizedChargeChart", component: GridOptimizedChargeChartOverviewComponent }, { path: ":componentId/heatingelementchart", component: HeatingelementChartOverviewComponent }, { path: ":componentId/heatpumpchart", component: HeatPumpChartOverviewComponent }, + { path: ":componentId/modbusTcpApi", component: ModbusTcpApiOverviewComponent }, { path: ":componentId/scheduleChart", component: TimeOfUseTariffOverviewComponent }, { path: ":componentId/symmetricpeakshavingchart", component: SymmetricPeakshavingChartOverviewComponent }, { path: ":componentId/timeslotpeakshavingchart", component: TimeslotPeakshavingChartOverviewComponent }, @@ -101,7 +102,6 @@ export const routes: Routes = [ { path: "gridchart", component: GridChartOverviewComponent }, { path: "gridchart/:componentId", component: GridDetailsOverviewComponent }, { path: "gridchart/:componentId/currentVoltage", component: CurrentAndVoltageOverviewComponent }, - { path: ":componentId/modbusTcpApi", component: ModbusTcpApiOverviewComponent }, { path: "productionchart", component: ProductionChartOverviewComponent }, { path: "productionchart/:componentId", component: DetailsOverviewComponent }, { path: "productionchart/:componentId/currentVoltage", component: CurrentAndVoltageOverviewComponent }, @@ -134,6 +134,7 @@ export const routes: Routes = [ { path: "settings/alerting", component: EdgeSettingsAlerting, canActivate: [hasEdgeRole(Role.OWNER)], data: { navbarTitleToBeTranslated: "Edge.Config.Index.alerting" } }, { path: "settings/jsonrpctest", component: JsonrpcTestComponent, data: { navbarTitle: "Jsonrpc Test" } }, { path: "settings/powerAssistant", component: PowerAssistantComponent, canActivate: [hasEdgeRole(Role.ADMIN)], data: { navbarTitle: "Power-Assistant" } }, + { path: "settings/app", data: { navbarTitle: environment.edgeShortName + "Apps" }, component: EdgeSettingsAppIndex }, ], }, diff --git a/ui/src/app/edge/history/abstracthistorychart.ts b/ui/src/app/edge/history/abstracthistorychart.ts index 0891b3f453e..7c8c70ec7bb 100644 --- a/ui/src/app/edge/history/abstracthistorychart.ts +++ b/ui/src/app/edge/history/abstracthistorychart.ts @@ -57,9 +57,6 @@ export abstract class AbstractHistoryChart { borderColor: "rgba(128,128,0,1)", }; - private activeQueryData: string; - private debounceTimeout: any | null = null; - constructor( public readonly spinnerId: string, protected service: Service, @@ -271,48 +268,33 @@ export abstract class AbstractHistoryChart { const resolution = res ?? calculateResolution(this.service, fromDate, toDate).resolution; this.errorResponse = null; - - if (this.debounceTimeout) { - clearTimeout(this.debounceTimeout); - } - - this.debounceTimeout = setTimeout(() => { - const result: Promise = new Promise((resolve, reject) => { - this.service.getCurrentEdge().then(edge => { - this.service.getConfig().then(config => { - this.setLabel(config); - this.getChannelAddresses(edge, config).then(channelAddresses => { - const request = new QueryHistoricTimeseriesDataRequest(DateUtils.maxDate(fromDate, this.edge?.firstSetupProtocol), toDate, channelAddresses, resolution); - edge.sendRequest(this.service.websocket, request).then(response => { - resolve(response as QueryHistoricTimeseriesDataResponse); - this.activeQueryData = request.id; - }).catch(error => { - this.errorResponse = error; - resolve(new QueryHistoricTimeseriesDataResponse(error.id, { - timestamps: [null], data: { null: null }, - })); - }); + const result: Promise = new Promise((resolve, reject) => { + this.service.getCurrentEdge().then(edge => { + this.service.getConfig().then(config => { + this.setLabel(config); + this.getChannelAddresses(edge, config).then(channelAddresses => { + const request = new QueryHistoricTimeseriesDataRequest(DateUtils.maxDate(fromDate, this.edge?.firstSetupProtocol), toDate, channelAddresses, resolution); + edge.sendRequest(this.service.websocket, request).then(response => { + resolve(response as QueryHistoricTimeseriesDataResponse); + }).catch(error => { + this.errorResponse = error; + resolve(new QueryHistoricTimeseriesDataResponse(error.id, { + timestamps: [null], data: { null: null }, + })); }); }); }); - }).then((response) => { - if (this.activeQueryData !== response.id) { - return; - } - if (Utils.isDataEmpty(response)) { - this.loading = false; - this.service.stopSpinner(this.spinnerId); - this.initializeChart(); - } - return DateTimeUtils.normalizeTimestamps(resolution.unit, response); }); - - return result; - }, ChartConstants.REQUEST_TIMEOUT); - - return new Promise((resolve) => { - resolve(new QueryHistoricTimeseriesDataResponse("", { timestamps: [], data: {} })); + }).then((response) => { + if (Utils.isDataEmpty(response)) { + this.loading = false; + this.service.stopSpinner(this.spinnerId); + this.initializeChart(); + } + return DateTimeUtils.normalizeTimestamps(resolution.unit, response); }); + + return result; } /** diff --git a/ui/src/app/edge/history/common/consumption/details/details.overview.html b/ui/src/app/edge/history/common/consumption/details/details.overview.html index 31819efc6fb..bf708560a45 100644 --- a/ui/src/app/edge/history/common/consumption/details/details.overview.html +++ b/ui/src/app/edge/history/common/consumption/details/details.overview.html @@ -1,4 +1,4 @@ - + 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 2abfaee9aed..fe2dbeb853b 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 @@ -19,7 +19,7 @@ export namespace History { "legend": { "display": true, "position": "bottom", "labels": { "color": "" }, }, "tooltip": { - "intersect": false, "mode": "index", "callbacks": {}, + "intersect": false, "mode": "index", "callbacks": {}, "enabled": true, }, "annotation": { annotations: {}, @@ -56,7 +56,7 @@ export namespace History { "legend": { "display": true, "position": "bottom", "labels": { "color": "" }, }, "tooltip": { - "intersect": false, "mode": "x", "callbacks": {}, + "intersect": false, "mode": "x", "callbacks": {}, "enabled": true, }, "annotation": { annotations: {}, 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 dff22346d79..9598a1615a0 100644 --- a/ui/src/app/edge/history/common/energy/chart/chart.ts +++ b/ui/src/app/edge/history/common/energy/chart/chart.ts @@ -200,6 +200,7 @@ export class ChartComponent extends AbstractHistoryChart { displayGrid: false, }), ], + normalizeOutputData: true, }; } diff --git a/ui/src/app/edge/history/common/grid/details/details.overview.html b/ui/src/app/edge/history/common/grid/details/details.overview.html index 1bba13ab767..506e8390f44 100644 --- a/ui/src/app/edge/history/common/grid/details/details.overview.html +++ b/ui/src/app/edge/history/common/grid/details/details.overview.html @@ -1,6 +1,8 @@ - + { - const gridMeter = Object.values(this.config.components) - .find((component) => component.isEnabled && this.config.isTypeGrid(component)) ?? null; + if (!this.component) { + return; + } + const gridMeter = this.config.isTypeGrid(this.component) ?? null; if (!gridMeter) { return; } + const gridMeters = Object.values(this.config.components) + .filter((comp) => comp.isEnabled && this.config.isTypeGrid(comp)) ?? null; + + if (gridMeters?.length == 1) { + this.title = this.translate.instant("General.grid"); + } + this.navigationButtons = [ - { id: "currentVoltage", isEnabled: edge.roleIsAtLeast(Role.INSTALLER), alias: this.translate.instant("Edge.History.CURRENT_AND_VOLTAGE"), callback: () => { this.router.navigate([`../${gridMeter.id}/currentVoltage`], { relativeTo: this.route }); } }]; + { id: "currentVoltage", isEnabled: edge.roleIsAtLeast(Role.INSTALLER), alias: this.translate.instant("Edge.History.CURRENT_AND_VOLTAGE"), callback: () => { this.router.navigate(["./currentVoltage"], { relativeTo: this.route }); } }]; }); } } diff --git a/ui/src/app/edge/history/common/grid/overview/overview.html b/ui/src/app/edge/history/common/grid/overview/overview.html index 71e464fef64..51b01128edf 100644 --- a/ui/src/app/edge/history/common/grid/overview/overview.html +++ b/ui/src/app/edge/history/common/grid/overview/overview.html @@ -3,4 +3,4 @@ - + diff --git a/ui/src/app/edge/history/common/grid/overview/overview.ts b/ui/src/app/edge/history/common/grid/overview/overview.ts index b99f248ebf5..20982339233 100644 --- a/ui/src/app/edge/history/common/grid/overview/overview.ts +++ b/ui/src/app/edge/history/common/grid/overview/overview.ts @@ -2,15 +2,18 @@ import { Component } from "@angular/core"; import { ActivatedRoute, Router } from "@angular/router"; import { ModalController } from "@ionic/angular"; import { TranslateService } from "@ngx-translate/core"; +import { filter, takeUntil } from "rxjs/operators"; import { AbstractHistoryChartOverview } from "src/app/shared/components/chart/abstractHistoryChartOverview"; import { NavigationOption } from "src/app/shared/components/footer/subnavigation/footerNavigation"; import { EdgeConfig, Service } from "src/app/shared/shared"; + @Component({ templateUrl: "./overview.html", }) export class OverviewComponent extends AbstractHistoryChartOverview { protected navigationButtons: NavigationOption[] = []; + protected isAllowed: boolean = false; constructor( public override service: Service, @@ -24,24 +27,23 @@ export class OverviewComponent extends AbstractHistoryChartOverview { protected override afterIsInitialized() { - const sum: EdgeConfig.Component = this.config.getComponent("_sum"); - sum.alias = this.translate.instant("General.TOTAL"); + this.service.historyPeriod.pipe(takeUntil(this.stopOnDestroy), filter(period => !!period)) + .subscribe((period) => { + this.isAllowed = period.isWeekOrDay(); + }); + const navigationButtons: EdgeConfig.Component[] = []; const gridMeters = Object.values(this.config.components) .filter((component) => component.isEnabled && this.config.isTypeGrid(component)); if (!gridMeters) { - navigationButtons.push(sum); + return; } - if (gridMeters?.length <= 1) { - navigationButtons.push(sum); - } else { - navigationButtons.push(...gridMeters); - } + navigationButtons.push(...gridMeters); this.navigationButtons = navigationButtons.map(el => ( - { id: el.id, alias: el.alias, callback: () => { this.router.navigate(["./" + el.id], { relativeTo: this.route }); } } + { id: el.id, alias: navigationButtons.length === 1 ? this.translate.instant("Edge.History.PHASE_ACCURATE") : el.alias, callback: () => { this.router.navigate(["./" + el.id], { relativeTo: this.route }); } } )); } } diff --git a/ui/src/app/edge/history/common/production/details/details.overview.html b/ui/src/app/edge/history/common/production/details/details.overview.html index 1884e99ef81..0e69bd49bec 100644 --- a/ui/src/app/edge/history/common/production/details/details.overview.html +++ b/ui/src/app/edge/history/common/production/details/details.overview.html @@ -1,4 +1,4 @@ - diff --git a/ui/src/app/edge/history/common/production/overview/overview.ts b/ui/src/app/edge/history/common/production/overview/overview.ts index e75c1e02ea0..6f44c4fe37a 100644 --- a/ui/src/app/edge/history/common/production/overview/overview.ts +++ b/ui/src/app/edge/history/common/production/overview/overview.ts @@ -35,10 +35,8 @@ export class OverviewComponent extends AbstractHistoryChartOverview { this.config.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") .filter(component => component.isEnabled && this.config.isProducer(component)); - const sum: EdgeConfig.Component = this.config.getComponent("_sum"); - sum.alias = this.translate.instant("General.TOTAL"); - this.navigationButtons = [sum, ...this.chargerComponents, ...this.productionMeterComponents].map(el => ( + this.navigationButtons = [...this.productionMeterComponents, ...this.chargerComponents].map(el => ( { id: el.id, alias: el.alias, callback: () => { this.router.navigate(["./" + el.id], { relativeTo: this.route }); } } )); return []; diff --git a/ui/src/app/edge/history/history.component.html b/ui/src/app/edge/history/history.component.html index bd86a09bf04..0b7e40f54f2 100644 --- a/ui/src/app/edge/history/history.component.html +++ b/ui/src/app/edge/history/history.component.html @@ -46,10 +46,6 @@ - - - - diff --git a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/statePriceChart.ts b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/statePriceChart.ts index 3e690c5828f..63aaa9ac05b 100644 --- a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/statePriceChart.ts +++ b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/statePriceChart.ts @@ -4,13 +4,12 @@ import { ActivatedRoute } from "@angular/router"; import { TranslateService } from "@ngx-translate/core"; import * as Chart from "chart.js"; import { AbstractHistoryChart } from "src/app/edge/history/abstracthistorychart"; +import { calculateResolution } from "src/app/edge/history/shared"; import { AbstractHistoryChart as NewAbstractHistoryChart } from "src/app/shared/components/chart/abstracthistorychart"; +import { ChartConstants } from "src/app/shared/components/chart/chart.constants"; import { ComponentJsonApiRequest } from "src/app/shared/jsonrpc/request/componentJsonApiRequest"; import { ChartAxis, HistoryUtils, TimeOfUseTariffUtils, YAxisType } from "src/app/shared/service/utils"; import { ChannelAddress, Currency, Edge, EdgeConfig, Service, Websocket } from "src/app/shared/shared"; - -import { calculateResolution } from "src/app/edge/history/shared"; -import { ChartConstants } from "src/app/shared/components/chart/chart.constants"; import { ColorUtils } from "src/app/shared/utils/color/color.utils"; import { GetScheduleRequest } from "../../../../../../shared/jsonrpc/request/getScheduleRequest"; import { GetScheduleResponse } from "../../../../../../shared/jsonrpc/response/getScheduleResponse"; diff --git a/ui/src/app/edge/live/Controller/Evcs/modal/modal.html b/ui/src/app/edge/live/Controller/Evcs/modal/modal.html index da7866b9130..0820cf1130a 100644 --- a/ui/src/app/edge/live/Controller/Evcs/modal/modal.html +++ b/ui/src/app/edge/live/Controller/Evcs/modal/modal.html @@ -32,6 +32,18 @@ [name]="'Edge.Index.Widgets.EVCS.energySinceBeginning' | translate" [value]="energySession"> + + + + + + + + + + + diff --git a/ui/src/app/edge/live/Controller/Evcs/modal/modal.ts b/ui/src/app/edge/live/Controller/Evcs/modal/modal.ts index 0e92bbc6eda..0b2e5053bc9 100644 --- a/ui/src/app/edge/live/Controller/Evcs/modal/modal.ts +++ b/ui/src/app/edge/live/Controller/Evcs/modal/modal.ts @@ -37,6 +37,7 @@ export class ModalComponent extends AbstractModal { protected isChargingEnabled: boolean = false; protected sessionLimit: number; protected helpKey: string; + protected awaitingHysteresis: boolean; constructor( @Inject(Websocket) protected override websocket: Websocket, @@ -116,11 +117,13 @@ export class ModalComponent extends AbstractModal { new ChannelAddress(this.controller?.id, "_PropertyChargeMode"), new ChannelAddress(this.controller?.id, "_PropertyEnabledCharging"), new ChannelAddress(this.controller?.id, "_PropertyDefaultChargeMinPower"), + new ChannelAddress(this.controller?.id, "AwaitingHysteresis"), ]; } protected override onCurrentData(currentData: CurrentData) { this.isConnectionSuccessful = currentData.allComponents[this.component.id + "/State"] !== 3 ? true : false; + this.awaitingHysteresis = currentData.allComponents[this.controller?.id + "/AwaitingHysteresis"]; // Do not change values after touching formControls if (this.formGroup?.pristine) { this.status = this.getState(this.controller ? currentData.allComponents[this.controller.id + "/_PropertyEnabledCharging"] === 1 : null, currentData.allComponents[this.component.id + "/Status"], currentData.allComponents[this.component.id + "/Plug"]); diff --git a/ui/src/app/edge/live/live.module.ts b/ui/src/app/edge/live/live.module.ts index 944e2240b03..ccd88577618 100644 --- a/ui/src/app/edge/live/live.module.ts +++ b/ui/src/app/edge/live/live.module.ts @@ -1,6 +1,7 @@ import { NgModule } from "@angular/core"; import { BrowserModule } from "@angular/platform-browser"; import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; +import { EdgeOfflineModule } from "src/app/shared/components/edge/offline/offline.module"; import { SharedModule } from "./../../shared/shared.module"; import { Controller_ChannelthresholdComponent } from "./Controller/Channelthreshold/Channelthreshold"; import { Controller_ChpSocComponent } from "./Controller/ChpSoc/ChpSoc"; @@ -41,27 +42,25 @@ import { DelayedSellToGridModalComponent } from "./delayedselltogrid/modal/modal import { EnergymonitorModule } from "./energymonitor/energymonitor.module"; import { InfoComponent } from "./info/info.component"; import { LiveComponent } from "./live.component"; -import { OfflineComponent } from "./offline/offline.component"; @NgModule({ imports: [ BrowserAnimationsModule, BrowserModule, - // Common Common_Autarchy, - Common_Production, - Common_Selfconsumption, Common_Consumption, Common_Grid, - // Controller + Common_Production, + Common_Selfconsumption, + Controller_Api_ModbusTcp, Controller_Ess_FixActivePower, Controller_Ess_GridOptimizedCharge, + Controller_Ess_TimeOfUseTariff, + Controller_Evcs, Controller_Io_HeatingElement, - Controller_Api_ModbusTcp, + EdgeOfflineModule, EnergymonitorModule, SharedModule, - Controller_Evcs, - Controller_Ess_TimeOfUseTariff, ], declarations: [ AdministrationComponent, @@ -90,7 +89,6 @@ import { OfflineComponent } from "./offline/offline.component"; Io_Api_DigitalInput_ModalComponent, Io_Api_DigitalInputComponent, LiveComponent, - OfflineComponent, StorageComponent, StorageModalComponent, ], diff --git a/ui/src/app/index/login.component.ts b/ui/src/app/index/login.component.ts index 4fa20f9aeff..26a38d7e767 100644 --- a/ui/src/app/index/login.component.ts +++ b/ui/src/app/index/login.component.ts @@ -35,16 +35,16 @@ export class LoginComponent implements OnInit, AfterContentChecked, OnDestroy { ) { } /** - * Trims credentials - * - * @param password the password - * @param username the username - * @returns trimmed credentials - */ - public static trimCredentials(password: string, username?: string): { password: string, username?: string } { + * Preprocesses the credentials + * + * @param password the password + * @param username the username + * @returns trimmed credentials + */ + public static preprocessCredentials(password: string, username?: string): { password: string, username?: string } { return { password: password?.trim(), - ...(username && { username: username?.trim() }), + ...(username && { username: username?.trim().toLowerCase() }), }; } @@ -95,7 +95,7 @@ export class LoginComponent implements OnInit, AfterContentChecked, OnDestroy { public doLogin(param: { username?: string, password: string }) { this.websocket.state.set(States.AUTHENTICATION_WITH_CREDENTIALS); - param = LoginComponent.trimCredentials(param.password, param.username); + param = LoginComponent.preprocessCredentials(param.password, param.username); // Prevent that user submits via keyevent 'enter' multiple times if (this.formIsDisabled) { diff --git a/ui/src/app/index/login.spec.ts b/ui/src/app/index/login.spec.ts index dad874f51d4..9feea8aa9ce 100644 --- a/ui/src/app/index/login.spec.ts +++ b/ui/src/app/index/login.spec.ts @@ -12,26 +12,30 @@ describe("Login", () => { }).compileComponents(); }); - it("#trimCredentials should trim password and username", () => { + it("#preprocessCredentials should trim password and username and should lowerCase username", () => { { // Username and password - OpenEMS Backend - expect(LoginComponent.trimCredentials(password, username)).toEqual({ password: "password", username: "username" }); + expect(LoginComponent.preprocessCredentials(password, username)).toEqual({ password: "password", username: "username" }); } { // Only Password - OpenEMS Edge - expect(LoginComponent.trimCredentials(password)).toEqual({ password: "password" }); + expect(LoginComponent.preprocessCredentials(password)).toEqual({ password: "password" }); } { // Password is null - expect(LoginComponent.trimCredentials(null)).toEqual({ password: undefined }); + expect(LoginComponent.preprocessCredentials(null)).toEqual({ password: undefined }); } { // Username is null - expect(LoginComponent.trimCredentials(password, null)).toEqual({ password: "password" }); + expect(LoginComponent.preprocessCredentials(password, null)).toEqual({ password: "password" }); } { // Username and password are null - expect(LoginComponent.trimCredentials(null, null)).toEqual({ password: undefined }); + expect(LoginComponent.preprocessCredentials(null, null)).toEqual({ password: undefined }); + } + { + // Username in Upper case + expect(LoginComponent.preprocessCredentials(password, username.toUpperCase())).toEqual({ password: "password", username: "username" }); } }); }); diff --git a/ui/src/app/shared/components/chart/abstracthistorychart.ts b/ui/src/app/shared/components/chart/abstracthistorychart.ts index b30e69af4b8..2e7d88b2fa3 100644 --- a/ui/src/app/shared/components/chart/abstracthistorychart.ts +++ b/ui/src/app/shared/components/chart/abstracthistorychart.ts @@ -28,6 +28,7 @@ import { Converter } from "../shared/converter"; import { ChartConstants, XAxisType } from "./chart.constants"; import "chartjs-adapter-date-fns"; +import { JsonRpcUtils } from "../../jsonrpc/jsonrpcutils"; Chart.Chart.register(annotationPlugin); @@ -166,15 +167,20 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { public static fillData(element: HistoryUtils.DisplayValue, label: string, chartObject: HistoryUtils.ChartData, chartType: "line" | "bar", data: number[] | null): { datasets: Chart.ChartDataset[], legendOptions: { label: string, strokeThroughHidingStyle: boolean, hideLabelInLegend: boolean; }[]; } { const legendOptions: { label: string, strokeThroughHidingStyle: boolean, hideLabelInLegend: boolean; }[] = []; const datasets: Chart.ChartDataset[] = []; + let normalizedData: (number | null)[] = data; + + if (chartObject.normalizeOutputData == true) { + normalizedData = JsonRpcUtils.normalizeQueryData(data); + } // Enable one dataset to be displayed in multiple stacks if (Array.isArray(element.stack)) { for (const stack of element.stack) { - datasets.push(AbstractHistoryChart.getDataSet(element, label, data, stack, chartObject, element.custom?.type ?? chartType)); + datasets.push(AbstractHistoryChart.getDataSet(element, label, normalizedData, stack, chartObject, element.custom?.type ?? chartType)); legendOptions.push(AbstractHistoryChart.getLegendOptions(label, element)); } } else { - datasets.push(AbstractHistoryChart.getDataSet(element, label, data, element.stack, chartObject, element.custom?.type ?? chartType)); + datasets.push(AbstractHistoryChart.getDataSet(element, label, normalizedData, element.stack, chartObject, element.custom?.type ?? chartType)); legendOptions.push(AbstractHistoryChart.getLegendOptions(label, element)); } @@ -460,6 +466,8 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { return null; }; + options.plugins.tooltip.enabled = chartObject.tooltip.enabled ?? true; + // Remove duplicates from legend, if legendItem with two or more occurrences in legend, use one legendItem to trigger them both options.plugins.legend.onClick = function (event: Chart.ChartEvent, legendItem: Chart.LegendItem, legend) { const chart: Chart.Chart = this.chart; @@ -556,11 +564,17 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { }, }; break; + case YAxisType.VOLTAGE: + case YAxisType.CURRENT: + options.scales[element.yAxisId] = { + ...baseConfig, + beginAtZero: false, + }; + break; + case YAxisType.POWER: case YAxisType.ENERGY: case YAxisType.REACTIVE: - case YAxisType.VOLTAGE: - case YAxisType.CURRENT: case YAxisType.NONE: options.scales[element.yAxisId] = baseConfig; break; @@ -869,7 +883,6 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { this.queryHistoricTimeseriesEnergy(this.service.historyPeriod.value.from, this.service.historyPeriod.value.to), ]) .then(([dataResponse, energyResponse]) => { - dataResponse = DateTimeUtils.normalizeTimestamps(unit, dataResponse); this.chartType = "line"; this.chartObject = this.getChartData(); diff --git a/ui/src/app/shared/components/chart/chart.constants.ts b/ui/src/app/shared/components/chart/chart.constants.ts index 93bf4dc58e7..fa8ccf10a71 100644 --- a/ui/src/app/shared/components/chart/chart.constants.ts +++ b/ui/src/app/shared/components/chart/chart.constants.ts @@ -5,6 +5,7 @@ import { formatNumber } from "@angular/common"; import { TranslateService } from "@ngx-translate/core"; import ChartDataLabels from "chartjs-plugin-datalabels"; import { HistoryUtils, Utils } from "../../service/utils"; +import { Language } from "../../type/language"; import { ArrayUtils } from "../../utils/array/array.utils"; import { AbstractHistoryChart } from "./abstracthistorychart"; @@ -41,7 +42,8 @@ export class ChartConstants { public static readonly BAR_CHART_DATALABELS = (unit: string, disable: boolean): any => ({ ...ChartDataLabels, formatter: (value, ctx) => { - return formatNumber(value, "de", "1.0-0") + "\xa0" + unit ?? null; + const locale: string = (Language.getByKey(localStorage.LANGUAGE) ?? Language.DEFAULT).i18nLocaleKey; + return formatNumber(value, locale, "1.0-0") + "\xa0" + unit ?? null; }, ...{ anchor: "end", offset: -18, align: "start", clip: false, clamp: true, diff --git a/ui/src/app/shared/components/chart/chart.html b/ui/src/app/shared/components/chart/chart.html index 075411661cb..0bed497b52d 100644 --- a/ui/src/app/shared/components/chart/chart.html +++ b/ui/src/app/shared/components/chart/chart.html @@ -15,7 +15,8 @@ - +
      +
      diff --git a/ui/src/app/shared/components/edge/meter/currentVoltage/chart/asymmetricMeter.ts b/ui/src/app/shared/components/edge/meter/currentVoltage/chart/asymmetricMeter.ts index 54d5f05ee5c..f187ea50ccc 100644 --- a/ui/src/app/shared/components/edge/meter/currentVoltage/chart/asymmetricMeter.ts +++ b/ui/src/app/shared/components/edge/meter/currentVoltage/chart/asymmetricMeter.ts @@ -34,7 +34,7 @@ export class CurrentVoltageAsymmetricChartComponent extends AbstractHistoryChart }, hideShadow: true, color: currentPhasesColors[index], - yAxisId: ChartAxis.RIGHT, + yAxisId: ChartAxis.LEFT, })), ...Phase.THREE_PHASE.map((phase, index) => ({ name: this.translate.instant("Edge.History.VOLTAGE") + " " + phase, @@ -43,6 +43,7 @@ export class CurrentVoltageAsymmetricChartComponent extends AbstractHistoryChart }, hideShadow: true, color: voltagePhasesColors[index], + yAxisId: ChartAxis.RIGHT, })), ], tooltip: { @@ -51,13 +52,14 @@ export class CurrentVoltageAsymmetricChartComponent extends AbstractHistoryChart }, yAxes: [{ unit: YAxisType.VOLTAGE, - position: "left", - yAxisId: ChartAxis.LEFT, + position: "right", + yAxisId: ChartAxis.RIGHT, + displayGrid: false, }, { unit: YAxisType.CURRENT, - position: "right", - yAxisId: ChartAxis.RIGHT, + position: "left", + yAxisId: ChartAxis.LEFT, }, ], }; diff --git a/ui/src/app/shared/components/edge/meter/currentVoltage/chart/symmetricMeter.ts b/ui/src/app/shared/components/edge/meter/currentVoltage/chart/symmetricMeter.ts index e7998dda9f6..d3ad8c86502 100644 --- a/ui/src/app/shared/components/edge/meter/currentVoltage/chart/symmetricMeter.ts +++ b/ui/src/app/shared/components/edge/meter/currentVoltage/chart/symmetricMeter.ts @@ -35,7 +35,7 @@ export class CurrentVoltageSymmetricChartComponent extends AbstractHistoryChart hiddenOnInit: false, stack: 1, - yAxisId: ChartAxis.RIGHT, + yAxisId: ChartAxis.LEFT, }, { name: this.translate.instant("Edge.History.VOLTAGE"), @@ -45,7 +45,7 @@ export class CurrentVoltageSymmetricChartComponent extends AbstractHistoryChart color: "rgb(255,0,0)", hiddenOnInit: false, stack: 1, - yAxisId: ChartAxis.LEFT, + yAxisId: ChartAxis.RIGHT, }, ], tooltip: { @@ -54,13 +54,14 @@ export class CurrentVoltageSymmetricChartComponent extends AbstractHistoryChart }, yAxes: [{ unit: YAxisType.VOLTAGE, - position: "left", - yAxisId: ChartAxis.LEFT, + position: "right", + yAxisId: ChartAxis.RIGHT, + displayGrid: false, }, { unit: YAxisType.CURRENT, - position: "right", - yAxisId: ChartAxis.RIGHT, + position: "left", + yAxisId: ChartAxis.LEFT, }, ], }; diff --git a/ui/src/app/shared/components/edge/meter/currentVoltage/currentVoltage.overview.html b/ui/src/app/shared/components/edge/meter/currentVoltage/currentVoltage.overview.html index 71727e415e6..0f1ff84692e 100644 --- a/ui/src/app/shared/components/edge/meter/currentVoltage/currentVoltage.overview.html +++ b/ui/src/app/shared/components/edge/meter/currentVoltage/currentVoltage.overview.html @@ -1,7 +1,8 @@ - + diff --git a/ui/src/app/shared/components/edge/offline/offline.component.html b/ui/src/app/shared/components/edge/offline/offline.component.html new file mode 100644 index 00000000000..4517b57f3c8 --- /dev/null +++ b/ui/src/app/shared/components/edge/offline/offline.component.html @@ -0,0 +1,6 @@ + + + + {{environment.edgeShortName}} ist offline + + diff --git a/ui/src/app/edge/live/offline/offline.component.ts b/ui/src/app/shared/components/edge/offline/offline.component.ts similarity index 78% rename from ui/src/app/edge/live/offline/offline.component.ts rename to ui/src/app/shared/components/edge/offline/offline.component.ts index 5af0358d185..2f9af23442a 100644 --- a/ui/src/app/edge/live/offline/offline.component.ts +++ b/ui/src/app/shared/components/edge/offline/offline.component.ts @@ -1,16 +1,25 @@ import { Component, OnInit } from "@angular/core"; import { Edge, Service, Utils } from "src/app/shared/shared"; +import { Role } from "src/app/shared/type/role"; import { DateUtils } from "src/app/shared/utils/date/dateutils"; +import { environment } from "src/environments"; // TODO add translations when refactoring offline.component.html @Component({ selector: "offline", templateUrl: "./offline.component.html", + styles: [` + ion-item > ion-label > h3 { + font-weight: bolder; + } + `], }) export class OfflineComponent implements OnInit { protected edge: Edge | null = null; protected timeSinceOffline: string | null = null; + protected isAtLeastInstaller: boolean = false; + protected readonly environment = environment; constructor( public service: Service, @@ -45,7 +54,8 @@ export class OfflineComponent implements OnInit { ngOnInit() { this.service.getCurrentEdge().then(edge => { this.edge = edge; - this.timeSinceOffline = OfflineComponent.formatSecondsToFullMinutes(edge.lastmessage.toString()); + this.isAtLeastInstaller = this.edge.roleIsAtLeast(Role.INSTALLER); + this.timeSinceOffline = OfflineComponent.formatSecondsToFullMinutes(edge.lastmessage?.toString()); }); } } diff --git a/ui/src/app/shared/components/edge/offline/offline.module.ts b/ui/src/app/shared/components/edge/offline/offline.module.ts new file mode 100644 index 00000000000..5c500e85c32 --- /dev/null +++ b/ui/src/app/shared/components/edge/offline/offline.module.ts @@ -0,0 +1,18 @@ +import { NgModule } from "@angular/core"; +import { BrowserModule } from "@angular/platform-browser"; +import { IonicModule } from "@ionic/angular"; +import { OfflineComponent } from "./offline.component"; + +@NgModule({ + imports: [ + BrowserModule, + IonicModule, + ], + declarations: [ + OfflineComponent, + ], + exports: [ + OfflineComponent, + ], +}) +export class EdgeOfflineModule { } diff --git a/ui/src/app/shared/components/flat/abstract-flat-widget-line.ts b/ui/src/app/shared/components/flat/abstract-flat-widget-line.ts index 48738330c12..2d697a6a6e0 100644 --- a/ui/src/app/shared/components/flat/abstract-flat-widget-line.ts +++ b/ui/src/app/shared/components/flat/abstract-flat-widget-line.ts @@ -30,7 +30,10 @@ export abstract class AbstractFlatWidgetLine implements OnChanges, OnDestroy { */ public displayValue: string | null = null; + protected displayName: string = null; protected show: boolean = true; + + private _name: string | ((value: any) => string); private _channelAddress: ChannelAddress | null = null; /** @@ -48,6 +51,15 @@ export abstract class AbstractFlatWidgetLine implements OnChanges, OnDestroy { @Inject(DataService) private dataService: DataService, ) { } + @Input() set name(value: string | { channel: ChannelAddress, converter: (value: any) => string }) { + if (typeof value === "object") { + this.subscribe(value.channel); + this._name = value.converter; + } else { + this._name = value; + } + } + /** Channel defines the channel, you need for this line */ @Input() set channelAddress(channelAddress: string) { @@ -79,7 +91,14 @@ export abstract class AbstractFlatWidgetLine implements OnChanges, OnDestroy { } protected setValue(value: any) { + if (typeof this._name == "function") { + this.displayName = this._name(value); + + } else { + this.displayName = this._name; + } this.displayValue = this.converter(value); + if (this.filter) { this.show = this.filter(value); } diff --git a/ui/src/app/shared/components/flat/flat-widget-line/flat-widget-line-item/flat-widget-line-item.html b/ui/src/app/shared/components/flat/flat-widget-line/flat-widget-line-item/flat-widget-line-item.html index 7ac84753d40..a33df0902d6 100644 --- a/ui/src/app/shared/components/flat/flat-widget-line/flat-widget-line-item/flat-widget-line-item.html +++ b/ui/src/app/shared/components/flat/flat-widget-line/flat-widget-line-item/flat-widget-line-item.html @@ -1,4 +1,5 @@ -
      diff --git a/ui/src/app/shared/components/flat/flat-widget-line/flat-widget-line.html b/ui/src/app/shared/components/flat/flat-widget-line/flat-widget-line.html index 46424574ca4..4be476c385b 100644 --- a/ui/src/app/shared/components/flat/flat-widget-line/flat-widget-line.html +++ b/ui/src/app/shared/components/flat/flat-widget-line/flat-widget-line.html @@ -2,10 +2,10 @@ - diff --git a/ui/src/app/shared/components/flat/flat-widget-line/flat-widget-line.ts b/ui/src/app/shared/components/flat/flat-widget-line/flat-widget-line.ts index 288f0f5aced..e9d3d45fdc3 100644 --- a/ui/src/app/shared/components/flat/flat-widget-line/flat-widget-line.ts +++ b/ui/src/app/shared/components/flat/flat-widget-line/flat-widget-line.ts @@ -7,9 +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({ required: true }) - public name!: string; /** Width of left Column, right Column is (100 - width of left Column) */ @Input() diff --git a/ui/src/app/shared/components/formly/form-field-multi-step/form-field-multi-step.html b/ui/src/app/shared/components/formly/form-field-multi-step/form-field-multi-step.html new file mode 100644 index 00000000000..07dbace6ba8 --- /dev/null +++ b/ui/src/app/shared/components/formly/form-field-multi-step/form-field-multi-step.html @@ -0,0 +1,66 @@ + + + + + + {{props.label}} + + + + + + + {{props.description}} + + + + + + + + + + +
      + {{props.attributes?.infoLine }} +
      +
      +
      + + + + {{step.label}} + + + + + + + + + + {{step.description}} + + + + + + + + + +
      + + + + + + +
      +
      +
      +
      +
      diff --git a/ui/src/app/shared/components/formly/form-field-multi-step/form-field-multi-step.ts b/ui/src/app/shared/components/formly/form-field-multi-step/form-field-multi-step.ts new file mode 100644 index 00000000000..b9705f87493 --- /dev/null +++ b/ui/src/app/shared/components/formly/form-field-multi-step/form-field-multi-step.ts @@ -0,0 +1,70 @@ +import { Component, OnInit } from "@angular/core"; +import { FieldType } from "@ngx-formly/core"; + +@Component({ + selector: "form-field-multi-step", + templateUrl: "./form-field-multi-step.html", +}) +export class FormlyFieldMultiStepComponent extends FieldType implements OnInit { + + public currentStep: number = 0; + + protected get steps() { + return this.props.steps || []; + } + + public ngOnInit() { + // Ensure the model has an array to track steps + const stepArray = this.formControl.value; + + if (!Array.isArray(stepArray)) { + this.formControl.setValue(Array(this.steps.length).fill(false)); + } + + // Listen to status changes to reset steps if disabled + this.formControl.statusChanges.subscribe(status => { + if (status === "DISABLED") { + this.resetSteps(); + } + }); + + // Determine the current step based on the array of steps + const lastFalseIndex = stepArray.lastIndexOf(false); + const lastTrueIndex = stepArray.lastIndexOf(true); + + if (lastFalseIndex === -1) { + // All steps are true, show the final step + this.currentStep = this.steps.length - 1; + } else if (lastTrueIndex === -1) { + // No true steps, show the first step + this.currentStep = 0; + } else { + // Show the last true step + this.currentStep = lastTrueIndex; + } + } + + + protected nextStep() { + if (this.currentStep < this.steps.length - 1) { + this.currentStep++; + } + } + + protected prevStep() { + if (this.currentStep > 0) { + this.currentStep--; + } + } + + protected onCheckboxChange(event: any, index: number) { + const updatedValue = this.formControl.value; + updatedValue[index] = event.detail.checked; + this.formControl.setValue(updatedValue); + } + + private resetSteps() { + this.formControl.setValue(Array(this.steps.length).fill(false)); + this.currentStep = 0; + } +} diff --git a/ui/src/app/shared/components/formly/formly-field-checkbox-image/formly-field-checkbox-with-image.html b/ui/src/app/shared/components/formly/formly-field-checkbox-image/formly-field-checkbox-with-image.html index bd1c0ab4da9..64274e6732d 100644 --- a/ui/src/app/shared/components/formly/formly-field-checkbox-image/formly-field-checkbox-with-image.html +++ b/ui/src/app/shared/components/formly/formly-field-checkbox-image/formly-field-checkbox-with-image.html @@ -4,13 +4,20 @@ {{props.label}} - - + + + + {{props.description}} + + + + diff --git a/ui/src/app/shared/components/formly/formly-field-checkbox-image/formly-field-checkbox-with-image.ts b/ui/src/app/shared/components/formly/formly-field-checkbox-image/formly-field-checkbox-with-image.ts index c00fdafb5a2..b182f88a0c7 100644 --- a/ui/src/app/shared/components/formly/formly-field-checkbox-image/formly-field-checkbox-with-image.ts +++ b/ui/src/app/shared/components/formly/formly-field-checkbox-image/formly-field-checkbox-with-image.ts @@ -12,7 +12,15 @@ export class FormlyFieldCheckboxWithImageComponent extends FieldWrapper implemen public ngOnInit() { // If the default value is not set in beginning. - this.value = this.field.defaultValue; + this.value = this.formControl.value ?? this.field.defaultValue; + + // Listen to form control status changes to reset steps if disabled + this.formControl.statusChanges.subscribe(status => { + if (status === "DISABLED" && this.value !== false) { + this.value = false; + this.formControl.setValue(this.value); + } + }); } /** @@ -23,4 +31,13 @@ export class FormlyFieldCheckboxWithImageComponent extends FieldWrapper implemen this.formControl.setValue(this.value); } + /** + * Returns the show/hide value based on the properties. + * + * @returns boolean value representing "show" or "hide". + */ + protected showContent() { + return (!this.field.props?.disabled && !this.value) && this.field.props?.url !== undefined; + } + } diff --git a/ui/src/app/shared/components/header/header.component.ts b/ui/src/app/shared/components/header/header.component.ts index fc97026c4e6..27c51f4732d 100644 --- a/ui/src/app/shared/components/header/header.component.ts +++ b/ui/src/app/shared/components/header/header.component.ts @@ -1,5 +1,5 @@ // @ts-strict-ignore -import { AfterViewChecked, ChangeDetectorRef, Component, OnDestroy, OnInit, ViewChild } from "@angular/core"; +import { AfterViewChecked, ChangeDetectorRef, Component, Input, OnDestroy, OnInit, ViewChild } from "@angular/core"; import { ActivatedRoute, NavigationEnd, Router } from "@angular/router"; import { MenuController, ModalController } from "@ionic/angular"; import { Subject } from "rxjs"; @@ -24,6 +24,8 @@ export class HeaderComponent implements OnInit, OnDestroy, AfterViewChecked { public currentPage: "EdgeSettings" | "Other" | "IndexLive" | "IndexHistory" = "Other"; public isSystemLogEnabled: boolean = false; private ngUnsubscribe: Subject = new Subject(); + private _customBackUrl: string | null = null; + constructor( private cdRef: ChangeDetectorRef, @@ -35,6 +37,14 @@ export class HeaderComponent implements OnInit, OnDestroy, AfterViewChecked { private route: ActivatedRoute, ) { } + @Input() public set customBackUrl(url: string | null) { + if (!url) { + return; + } + this._customBackUrl = url; + this.updateBackUrl(url); + } + ngOnInit() { // set inital URL this.updateUrl(this.router.routerState.snapshot.url); @@ -74,6 +84,11 @@ export class HeaderComponent implements OnInit, OnDestroy, AfterViewChecked { updateBackUrl(url: string) { + if (this._customBackUrl) { + this.backUrl = this._customBackUrl; + return; + } + // disable backUrl & Segment Navigation on initial 'login' page if (url === "/login" || url === "/overview" || url === "/index") { this.backUrl = false; diff --git a/ui/src/app/shared/components/shared/converter.ts b/ui/src/app/shared/components/shared/converter.ts index b76ad1ace3f..6791bf9166e 100644 --- a/ui/src/app/shared/components/shared/converter.ts +++ b/ui/src/app/shared/components/shared/converter.ts @@ -93,6 +93,20 @@ export namespace Converter { Formatter.FORMAT_WATT(value)); }; + /** + * Formats a Power value as Watt [W]. + * + * Value 1000 -> "1.000 W". + * Value null -> "-". + * + * @param value the power value + * @returns formatted value; '-' for null + */ + export const POWER_IN_KILO_WATT: Converter = (raw) => { + return IF_NUMBER(raw, value => + Formatter.FORMAT_KILO_WATT(Utils.divideSafely(value, 1000))); + }; + /** * Formats a Energy value as Kilo watt hours [kWh]. * diff --git a/ui/src/app/shared/components/shared/formatter.ts b/ui/src/app/shared/components/shared/formatter.ts index 798818e17b6..8cfba6bba0b 100644 --- a/ui/src/app/shared/components/shared/formatter.ts +++ b/ui/src/app/shared/components/shared/formatter.ts @@ -1,39 +1,54 @@ import { formatNumber } from "@angular/common"; import { Currency } from "../../shared"; +import { Language } from "../../type/language"; export namespace Formatter { + + // Changes the number format based on the language selected. + const locale: string = (Language.getByKey(localStorage.LANGUAGE) ?? Language.DEFAULT).i18nLocaleKey; + export const FORMAT_WATT = (value: number) => { // TODO apply correct locale - return formatNumber(value, "de", "1.0-0") + " W"; + return formatNumber(value, locale, "1.0-0") + " W"; + }; + + export const FORMAT_KILO_WATT = (value: number) => { + // TODO apply correct locale + return formatNumber(value, locale, "1.0-2") + " kW"; }; export const FORMAT_KILO_WATT_HOURS = (value: number) => { // TODO apply correct locale - return formatNumber(value, "de", "1.0-0") + " kWh"; + return formatNumber(value, locale, "1.0-0") + " kWh"; }; export const FORMAT_VOLT = (value: number) => { // TODO apply correct locale - return formatNumber(value, "de", "1.0-0") + " V"; + return formatNumber(value, locale, "1.0-0") + " V"; }; export const FORMAT_AMPERE = (value: number) => { // TODO apply correct locale - return formatNumber(value, "de", "1.1-1") + " A"; + return formatNumber(value, locale, "1.1-1") + " A"; }; export const FORMAT_CELSIUS = (value: number) => { // TODO apply correct locale - return formatNumber(value, "de", "1.0-0") + " °C"; + return formatNumber(value, locale, "1.0-0") + " °C"; }; export const FORMAT_PERCENT = (value: number) => { // TODO apply correct locale - return formatNumber(value, "de", "1.0-0") + " %"; + return formatNumber(value, locale, "1.0-0") + " %"; + }; + + export const FORMAT_BAR = (value: number) => { + // TODO apply correct locale + return formatNumber(value, locale, "1.1-1") + " mbar"; }; export const FORMAT_CURRENCY_PER_KWH = (value: number | string, currency: string = Currency.Unit.CENT) => { // TODO apply correct locale - return formatNumber(parseInt(value.toString()), "de", "1.0-2") + " " + Currency.getCurrencyLabelByCurrency(currency); + return formatNumber(parseInt(value.toString()), locale, "1.0-2") + " " + Currency.getCurrencyLabelByCurrency(currency); }; } diff --git a/ui/src/app/shared/components/shared/testing/common.ts b/ui/src/app/shared/components/shared/testing/common.ts index 62f21fe345a..59e22834a1c 100644 --- a/ui/src/app/shared/components/shared/testing/common.ts +++ b/ui/src/app/shared/components/shared/testing/common.ts @@ -26,7 +26,7 @@ export namespace OeTester { type: "option", options: { "responsive": true, "maintainAspectRatio": false, "elements": { "point": { "radius": 0, "hitRadius": 0, "hoverRadius": 0 }, "line": { "stepped": false, "fill": true } }, "datasets": { "bar": {}, "line": {} }, "plugins": { - "colors": { "enabled": false }, "legend": { "display": true, "position": "bottom", "labels": { "color": "" } }, "tooltip": { "intersect": false, "mode": "index", "callbacks": {} }, "annotation": { "annotations": {} }, "datalabels": { + "colors": { "enabled": false }, "legend": { "display": true, "position": "bottom", "labels": { "color": "" } }, "tooltip": { "intersect": false, "mode": "index", "callbacks": {}, "enabled": true }, "annotation": { "annotations": {} }, "datalabels": { display: false, }, }, "scales": { @@ -46,7 +46,7 @@ export namespace OeTester { type: "option", options: { "responsive": true, "maintainAspectRatio": false, "elements": { "point": { "radius": 0, "hitRadius": 0, "hoverRadius": 0 }, "line": { "stepped": false, "fill": true } }, "datasets": { "bar": { "barPercentage": 1 }, "line": {} }, "plugins": { - "colors": { "enabled": false }, "legend": { "display": true, "position": "bottom", "labels": { "color": "" } }, "tooltip": { "intersect": false, "mode": "x", "callbacks": {} }, "annotation": { "annotations": {} }, "datalabels": { + "colors": { "enabled": false }, "legend": { "display": true, "position": "bottom", "labels": { "color": "" } }, "tooltip": { "intersect": false, "mode": "x", "callbacks": {}, "enabled": true }, "annotation": { "annotations": {} }, "datalabels": { display: false, }, }, "scales": { @@ -75,6 +75,7 @@ export namespace OeTester { "display": true, "position": "bottom", "labels": { "color": "" }, }, "tooltip": { "intersect": false, "mode": "index", "callbacks": {}, + "enabled": true, }, "annotation": { "annotations": {}, @@ -112,7 +113,7 @@ export namespace OeTester { type: "option", options: { "responsive": true, "maintainAspectRatio": false, "elements": { "point": { "radius": 0, "hitRadius": 0, "hoverRadius": 0 }, "line": { "stepped": false, "fill": true } }, "datasets": { "bar": { "barPercentage": 1 }, "line": {} }, "plugins": { - "colors": { "enabled": false }, "legend": { "display": true, "position": "bottom", "labels": { "color": "" } }, "tooltip": { "intersect": false, "mode": "x", "callbacks": {} }, "annotation": { "annotations": {} }, "datalabels": { + "colors": { "enabled": false }, "legend": { "display": true, "position": "bottom", "labels": { "color": "" } }, "tooltip": { "intersect": false, "mode": "x", "callbacks": {}, "enabled": true }, "annotation": { "annotations": {} }, "datalabels": { display: false, }, }, "scales": { diff --git a/ui/src/app/shared/components/shared/testing/tester.ts b/ui/src/app/shared/components/shared/testing/tester.ts index 2e30117a4fa..7b2e9c7c662 100644 --- a/ui/src/app/shared/components/shared/testing/tester.ts +++ b/ui/src/app/shared/components/shared/testing/tester.ts @@ -233,6 +233,7 @@ export class OeChartTester { 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, testContext.service), + isWeekOrDay: () => testContext.service.historyPeriod.value.isWeekOrDay(), }); // Fill Data diff --git a/ui/src/app/shared/jsonrpc/jsonrpcutils.spec.ts b/ui/src/app/shared/jsonrpc/jsonrpcutils.spec.ts new file mode 100644 index 00000000000..0133cd573ed --- /dev/null +++ b/ui/src/app/shared/jsonrpc/jsonrpcutils.spec.ts @@ -0,0 +1,10 @@ +import { JsonRpcUtils } from "./jsonrpcutils"; + +describe("JsonRpcUtils", () => { + + const productionActivePowerData = [-0.01, -0.1, -0.49, -0.50, -1, null]; + const expectedOutput = [0, 0, 0, -0.5, -1, null]; + it("#normalizeQueryData", () => { + expect(JsonRpcUtils.normalizeQueryData(productionActivePowerData)).toEqual(expectedOutput); + }); +}); diff --git a/ui/src/app/shared/jsonrpc/jsonrpcutils.ts b/ui/src/app/shared/jsonrpc/jsonrpcutils.ts index 642ffee60c6..979d7be8b53 100644 --- a/ui/src/app/shared/jsonrpc/jsonrpcutils.ts +++ b/ui/src/app/shared/jsonrpc/jsonrpcutils.ts @@ -2,6 +2,26 @@ import { ChannelAddress } from "../type/channeladdress"; export class JsonRpcUtils { + private static THRESHOLD: number = -0.50; + + public static normalizeQueryData(data: (number | null)[]): (number | null)[] { + return data.map(el => JsonRpcUtils.roundSlightlyNegativeValues(el)); + } + + /** + * Rounds values between 0 and -1kW to 0 + * + * @param value the value to convert + */ + public static roundSlightlyNegativeValues(value: number | null): number | null { + if (value == null) { + return null; + } + + return (value > JsonRpcUtils.THRESHOLD && value < 0) ? 0 : value; + } + + /** * Converts an array of ChannelAddresses to a string array with unique values. */ diff --git a/ui/src/app/shared/service/defaulttypes.ts b/ui/src/app/shared/service/defaulttypes.ts index b01b9875627..08b2419b983 100644 --- a/ui/src/app/shared/service/defaulttypes.ts +++ b/ui/src/app/shared/service/defaulttypes.ts @@ -1,6 +1,6 @@ // @ts-strict-ignore import { TranslateService } from "@ngx-translate/core"; -import { endOfMonth, endOfYear, format, getDay, getMonth, getYear, isSameDay, isSameMonth, isSameYear, startOfMonth, startOfYear, subDays } from "date-fns"; +import { differenceInDays, endOfMonth, endOfYear, format, getDay, getMonth, getYear, isSameDay, isSameMonth, isSameYear, startOfMonth, startOfYear, subDays } from "date-fns"; import { QueryHistoricTimeseriesEnergyResponse } from "../jsonrpc/response/queryHistoricTimeseriesEnergyResponse"; import { ChannelAddress, Service } from "../shared"; @@ -157,6 +157,7 @@ export namespace DefaultTypes { public to: Date = new Date(), ) { } + /** * Returns a translated weekday name. * @@ -236,6 +237,15 @@ export namespace DefaultTypes { }); } } + + /** + * Checks if current period is week or day + * + * @returns true if period is week or day, false if not + */ + public isWeekOrDay(): boolean { + return Math.abs(differenceInDays(this.to, this.from)) <= 6; + } } } diff --git a/ui/src/app/shared/service/service.ts b/ui/src/app/shared/service/service.ts index e25fa22fac3..cc997a4d76b 100644 --- a/ui/src/app/shared/service/service.ts +++ b/ui/src/app/shared/service/service.ts @@ -6,7 +6,7 @@ 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 { filter, first, map, take } from "rxjs/operators"; import { ChosenFilter } from "src/app/index/filter/filter.component"; import { environment } from "src/environments"; import { ChartConstants } from "../components/chart/chart.constants"; @@ -186,6 +186,24 @@ export class Service extends AbstractService { }); } + /** + * Gets the current user + * + * @returns a Promise of the user + */ + public getCurrentUser(): Promise { + return new Promise((resolve) => { + this.metadata.pipe( + filter(metadata => metadata != null && metadata.user != null), + map(metadata => metadata.user), + first(), + ).toPromise().then(resolve); + if (this.currentUser) { + resolve(this.currentUser); + } + }); + } + public getConfig(): Promise { return new Promise((resolve, reject) => { this.getCurrentEdge().then(edge => { diff --git a/ui/src/app/shared/service/utils.spec.ts b/ui/src/app/shared/service/utils.spec.ts index 3034ab95019..8315e541078 100644 --- a/ui/src/app/shared/service/utils.spec.ts +++ b/ui/src/app/shared/service/utils.spec.ts @@ -1,6 +1,6 @@ // @ts-strict-ignore import { DummyConfig } from "../components/edge/edgeconfig.spec"; -import { EdgeConfig } from "../shared"; +import { Currency, EdgeConfig } from "../shared"; import { HistoryUtils, Utils } from "./utils"; describe("Utils", () => { @@ -54,4 +54,12 @@ describe("Utils", () => { const expectedResult4 = [null, null, null, 565, 560, 561, 573]; expect(Utils.calculateOtherConsumption(channelData, [], [])).toEqual(expectedResult4); }); + + it("+CONVERT_PRICE_TO_CENT_PER_KWH", () => { + const currencyLabel: string = Currency.getCurrencyLabelByEdgeId("0"); + expect(Utils.CONVERT_PRICE_TO_CENT_PER_KWH(2, currencyLabel)(0)).toEqual("0 Cent/kWh"); + expect(Utils.CONVERT_PRICE_TO_CENT_PER_KWH(2, currencyLabel)(null)).toEqual("- Cent/kWh"); + expect(Utils.CONVERT_PRICE_TO_CENT_PER_KWH(2, currencyLabel)(undefined)).toEqual("- Cent/kWh"); + expect(Utils.CONVERT_PRICE_TO_CENT_PER_KWH(2, currencyLabel)(1)).toEqual("0,1 Cent/kWh"); + }); }); diff --git a/ui/src/app/shared/service/utils.ts b/ui/src/app/shared/service/utils.ts index 9e237060345..0d5f686b21a 100644 --- a/ui/src/app/shared/service/utils.ts +++ b/ui/src/app/shared/service/utils.ts @@ -396,8 +396,8 @@ export class Utils { * @returns converted value */ public static CONVERT_PRICE_TO_CENT_PER_KWH = (decimal: number, label: string) => { - return (value: number | null): string => - (!value ? "-" : formatNumber(value / 10, "de", "1.0-" + decimal)) + " " + label; + return (value: number | null | undefined): string => + (value == null ? "-" : formatNumber(value / 10, "de", "1.0-" + decimal)) + " " + label; }; /** @@ -522,7 +522,7 @@ export class Utils { * * @param value the value to convert */ - public static roundSlightlyNegativeValues(value: number) { + public static roundSlightlyNegativeValues(value: number | null): number | null { return (value > -0.49 && value < 0) ? 0 : value; } @@ -763,8 +763,12 @@ export namespace HistoryUtils { /** Format of Number displayed */ formatNumber: string, afterTitle?: (stack: string) => string, + /** Defaults to true */ + enabled?: boolean, }, yAxes: yAxes[], + /** Rounds slightly negative values, defaults to false */ + normalizeOutputData?: boolean, }; export type yAxes = { diff --git a/ui/src/app/shared/shared.module.ts b/ui/src/app/shared/shared.module.ts index 2ff830daf99..d85cf25b0e5 100644 --- a/ui/src/app/shared/shared.module.ts +++ b/ui/src/app/shared/shared.module.ts @@ -15,6 +15,7 @@ import { ComponentsModule } from "./components/components.module"; import { MeterModule } from "./components/edge/meter/meter.module"; import { FormlyCheckBoxHyperlinkWrapperComponent } from "./components/formly/form-field-checkbox-hyperlink/form-field-checkbox-hyperlink.wrapper"; import { FormlyWrapperDefaultValueWithCasesComponent } from "./components/formly/form-field-default-cases.wrapper"; +import { FormlyFieldMultiStepComponent } from "./components/formly/form-field-multi-step/form-field-multi-step"; import { FormlyWrapperFormFieldComponent } from "./components/formly/form-field.wrapper"; import { FormlyFieldCheckboxWithImageComponent } from "./components/formly/formly-field-checkbox-image/formly-field-checkbox-with-image"; import { FormlyFieldModalComponent } from "./components/formly/formly-field-modal/formlyfieldmodal"; @@ -84,6 +85,7 @@ export function SubnetmaskValidatorMessage(err, field: FormlyFieldConfig) { types: [ { name: "input", component: InputTypeComponent }, { name: "repeat", component: RepeatTypeComponent }, + { name: "multi-step", component: FormlyFieldMultiStepComponent }, ], validators: [ { name: "ip", validation: IpValidator }, @@ -119,6 +121,7 @@ export function SubnetmaskValidatorMessage(err, field: FormlyFieldConfig) { PanelWrapperComponent, FormlyFieldWithLoadingAnimationComponent, FormlyFieldCheckboxWithImageComponent, + FormlyFieldMultiStepComponent, ], exports: [ // modules diff --git a/ui/src/app/user/user.component.html b/ui/src/app/user/user.component.html index bc5370ebca3..08f52cc3ffc 100644 --- a/ui/src/app/user/user.component.html +++ b/ui/src/app/user/user.component.html @@ -139,11 +139,6 @@

      - - - - Debug-Mode - @@ -166,6 +161,12 @@ The language can not be changed permanently in the local online-monitoring for technical reasons. + + + + + Debug-Mode + diff --git a/ui/src/app/user/user.component.ts b/ui/src/app/user/user.component.ts index b42945d1521..694549cf3b6 100644 --- a/ui/src/app/user/user.component.ts +++ b/ui/src/app/user/user.component.ts @@ -13,6 +13,7 @@ import { GetUserInformationResponse } from "../shared/jsonrpc/response/getUserIn import { Service, Websocket } from "../shared/shared"; import { COUNTRY_OPTIONS } from "../shared/type/country"; import { Language } from "../shared/type/language"; +import { Role } from "../shared/type/role"; type CompanyUserInformation = UserInformation & { companyName: string }; @@ -57,6 +58,8 @@ export class UserComponent implements OnInit { }]; protected readonly companyInformationFields: FormlyFieldConfig[] = []; + protected isAtLeastAdmin: boolean = false; + constructor( public translate: TranslateService, public service: Service, @@ -67,6 +70,11 @@ export class UserComponent implements OnInit { ngOnInit() { // Set currentLanguage to this.currentLanguage = Language.getByKey(localStorage.LANGUAGE) ?? Language.DEFAULT; + + this.service.getCurrentUser().then(user => { + this.isAtLeastAdmin = Role.isAtLeast(user.globalRole, Role.ADMIN); + }); + this.getUserInformation().then((userInformation) => { this.form = { formGroup: new FormGroup({}), diff --git a/ui/src/assets/i18n/de.json b/ui/src/assets/i18n/de.json index 457f5cb15ab..e105762966d 100644 --- a/ui/src/assets/i18n/de.json +++ b/ui/src/assets/i18n/de.json @@ -200,7 +200,9 @@ "name": "Erzwungene Beladung", "shortName": "Manuell" }, - "Uncontrollable": "Diese Ladesäule kann nicht gesteuert werden." + "Uncontrollable": "Diese Ladesäule kann nicht gesteuert werden.", + "HYSTERESIS": "Mindestumschaltzeit der Ladestation aktiv", + "HYSTERESIS_INFO": "Um Ladeabbrüche aufgrund zu häufigen Startens/Pausierens des Ladevorgangs zu verhindern, wird der aktuell eingestellte Lademodus für die nächsten Minuten fortgesetzt." }, "Heatingelement": { "activeForced": "Aktiv (Mindestlaufzeit)", @@ -271,6 +273,7 @@ "SYSTEMUPDATE": "Systemupdate" }, "History": { + "PHASE_ACCURATE": "Phasengenau", "CURRENT_AND_VOLTAGE": "Strom & Spannung", "beginDate": "Startdatum wählen", "day": "Tag", diff --git a/ui/src/assets/i18n/en.json b/ui/src/assets/i18n/en.json index b3f33f87876..58ca563831c 100644 --- a/ui/src/assets/i18n/en.json +++ b/ui/src/assets/i18n/en.json @@ -201,7 +201,9 @@ "name": "Force charging", "shortName": "Manually" }, - "Uncontrollable": "This charging station can not be controlled." + "Uncontrollable": "This charging station can not be controlled.", + "HYSTERESIS": "Minimum switching time of the charging station active", + "HYSTERESIS_INFO": "For preventing charging interruptions due to frequent starting/pausing of the charing process, the charging mode currently selected will continue for the next few minutes." }, "Heatingelement": { "activeForced": "Active (Minimum runtime)", @@ -314,7 +316,8 @@ "activeDuration": "active duration", "CURRENT_AND_VOLTAGE": "Current & Voltage", "CURRENT": "Current", - "VOLTAGE": "Voltage" + "VOLTAGE": "Voltage", + "PHASE_ACCURATE": "Phasengenau" }, "Config": { "Index": { diff --git a/ui/src/global-ion-custom.scss b/ui/src/global-ion-custom.scss new file mode 100644 index 00000000000..95979a5ee40 --- /dev/null +++ b/ui/src/global-ion-custom.scss @@ -0,0 +1,11 @@ +.ion-font-size-medium { + font-size: medium !important; +} + +.ion-font-size-smaller { + font-size: small !important; +} + +.ion-font-weight-bolder { + font-weight: bolder; +} diff --git a/ui/src/global.scss b/ui/src/global.scss index 59a24c31264..50d881926b2 100644 --- a/ui/src/global.scss +++ b/ui/src/global.scss @@ -25,6 +25,7 @@ /* ngx-spinner */ @import "node_modules/ngx-spinner/animations/ball-clip-rotate-multiple.css"; @import "variables"; +@import "./global-ion-custom.scss"; /* Live- and HistoryComponent*/ ion-refresher-content { @@ -54,6 +55,13 @@ ion-refresher-content { } +.disabled { + color: gray; + pointer-events: none; + opacity: 0.5; + /* Makes it semi-transparent */ +} + formly-wrapper-ion-form-field, formly-input-serial-number, formly-field-ion-radio { @@ -403,4 +411,8 @@ ion-modal.full-width { --storage-segment-2: block; --storage-segment-3: block; --storage-segment-4: block; -} \ No newline at end of file +} + +.card-with-primary-border { + border: 2px solid $primary-color; +} From fd713534073f24ceb941225f24564f815cde32aa Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Sun, 13 Oct 2024 14:27:04 +0200 Subject: [PATCH 154/173] UI: add import order rule to eslint (#2838) * npm install -D eslint-import-resolver-typescript eslint-plugin-import * add import rules * fix: add ignore comment for eslint-plugin-import bug. cf. import-js/eslint-plugin-import#1479 * eslint src/ --fix Co-authored-by: Hiromasa Ihara --- ui/.eslintrc.json | 16 +++- ui/package-lock.json | 82 ++++++++++++++++++- ui/package.json | 3 +- ui/src/app/app.service.ts | 2 +- .../Io/DigitalOutput/digitalOutput.module.ts | 6 +- .../ModbusTcpApi/modbusTcpApi.module.ts | 2 +- .../history/Controller/controller.module.ts | 4 +- .../history/common/consumption/Consumption.ts | 2 +- .../history/common/production/production.ts | 2 +- ui/src/app/edge/history/shared.ts | 3 + .../history/storage/totalchart.component.ts | 2 +- .../live/common/storage/storage.component.ts | 3 +- ui/src/app/edge/live/live.module.ts | 30 +++---- .../settings/channels/channels.component.ts | 4 +- ui/src/app/index/login.component.ts | 2 +- .../components/abstracthistorywidget.ts | 2 +- .../components/chart/abstracthistorychart.ts | 8 +- .../components/chart/chart.constants.ts | 2 +- .../shared/components/components.module.ts | 2 +- .../flat/abstract-flat-widget-line.ts | 2 +- .../components/flat/abstract-flat-widget.ts | 4 +- .../components/modal/abstract-modal-line.ts | 2 +- .../shared/components/modal/abstractModal.ts | 2 +- ui/src/app/shared/service/pagination.ts | 2 +- .../shared/utils/datetime/datetime-utils.ts | 3 + 25 files changed, 145 insertions(+), 47 deletions(-) diff --git a/ui/.eslintrc.json b/ui/.eslintrc.json index 0c5b77ab6af..9cfb0059ab9 100644 --- a/ui/.eslintrc.json +++ b/ui/.eslintrc.json @@ -20,6 +20,7 @@ "createDefaultProgram": true }, "plugins": [ + "import", "unused-imports", "@stylistic" ], @@ -27,11 +28,19 @@ "eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:@angular-eslint/recommended", - "plugin:@angular-eslint/template/process-inline-templates" + "plugin:@angular-eslint/template/process-inline-templates", + "plugin:import/recommended" ], "rules": { "curly": "error", "unused-imports/no-unused-imports": "error", + "import/order": [ + "error", + { + "groups": ["builtin", "external", "internal", "parent", "sibling", "index"], + "alphabetize": { "order": "asc", "caseInsensitive": true } + } + ], "@typescript-eslint/explicit-member-accessibility": [ "error", { @@ -111,6 +120,11 @@ "message": "Using 'xdescribe' is not allowed." } ] + }, + "settings": { + "import/resolver": { + "typescript": {} + } } }, { diff --git a/ui/package-lock.json b/ui/package-lock.json index 4641fa8ea1b..241ae35ba69 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -85,7 +85,8 @@ "@typescript-eslint/parser": "^7.0.0", "@typescript-eslint/types": "^8.7.0", "eslint": "^8.57.0", - "eslint-plugin-import": "2.30.0", + "eslint-import-resolver-typescript": "^3.6.3", + "eslint-plugin-import": "^2.30.0", "eslint-plugin-jsdoc": "50.2.4", "eslint-plugin-prefer-arrow": "1.2.3", "eslint-plugin-unused-imports": "^4.1.4", @@ -5907,6 +5908,16 @@ "tslib": "^2.0.0" } }, + "node_modules/@nolyfill/is-core-module": { + "version": "1.0.39", + "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", + "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.4.0" + } + }, "node_modules/@npmcli/agent": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz", @@ -12142,6 +12153,42 @@ "ms": "^2.1.1" } }, + "node_modules/eslint-import-resolver-typescript": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.3.tgz", + "integrity": "sha512-ud9aw4szY9cCT1EWWdGv1L1XR6hh2PaRWif0j2QjQ0pgTY/69iw+W0Z4qZv5wHahOl8isEr+k/JnyAqNQkLkIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@nolyfill/is-core-module": "1.0.39", + "debug": "^4.3.5", + "enhanced-resolve": "^5.15.0", + "eslint-module-utils": "^2.8.1", + "fast-glob": "^3.3.2", + "get-tsconfig": "^4.7.5", + "is-bun-module": "^1.0.2", + "is-glob": "^4.0.3" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*", + "eslint-plugin-import-x": "*" + }, + "peerDependenciesMeta": { + "eslint-plugin-import": { + "optional": true + }, + "eslint-plugin-import-x": { + "optional": true + } + } + }, "node_modules/eslint-module-utils": { "version": "2.11.1", "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.11.1.tgz", @@ -13639,6 +13686,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-tsconfig": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.1.tgz", + "integrity": "sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/get-uri": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz", @@ -14855,6 +14915,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-bun-module": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-1.2.1.tgz", + "integrity": "sha512-AmidtEM6D6NmUiLOvvU7+IePxjEjOzra2h0pSrsfSAcXwl/83zLLXDByafUJy9k/rKK0pvXMLdwKwGHlX2Ke6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.6.3" + } + }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", @@ -21024,6 +21094,16 @@ "node": ">=4" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/resolve-url-loader": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", diff --git a/ui/package.json b/ui/package.json index 65e20fe3d95..30f406fc93d 100644 --- a/ui/package.json +++ b/ui/package.json @@ -80,7 +80,8 @@ "@typescript-eslint/parser": "^7.0.0", "@typescript-eslint/types": "^8.7.0", "eslint": "^8.57.0", - "eslint-plugin-import": "2.30.0", + "eslint-import-resolver-typescript": "^3.6.3", + "eslint-plugin-import": "^2.30.0", "eslint-plugin-jsdoc": "50.2.4", "eslint-plugin-prefer-arrow": "1.2.3", "eslint-plugin-unused-imports": "^4.1.4", diff --git a/ui/src/app/app.service.ts b/ui/src/app/app.service.ts index e544f51838a..4d5bddec5ab 100644 --- a/ui/src/app/app.service.ts +++ b/ui/src/app/app.service.ts @@ -3,8 +3,8 @@ import { Injectable } from "@angular/core"; import { App } from "@capacitor/app"; import { Capacitor } from "@capacitor/core"; import { Directory, Encoding, Filesystem } from "@capacitor/filesystem"; -import { FileOpener } from "@ionic-native/file-opener"; import { AlertController } from "@ionic/angular"; +import { FileOpener } from "@ionic-native/file-opener"; import { TranslateService } from "@ngx-translate/core"; import { saveAs } from "file-saver-es"; import { DeviceDetectorService, DeviceInfo } from "ngx-device-detector"; diff --git a/ui/src/app/edge/history/Controller/Io/DigitalOutput/digitalOutput.module.ts b/ui/src/app/edge/history/Controller/Io/DigitalOutput/digitalOutput.module.ts index df92f38b353..cc060d3d5a8 100644 --- a/ui/src/app/edge/history/Controller/Io/DigitalOutput/digitalOutput.module.ts +++ b/ui/src/app/edge/history/Controller/Io/DigitalOutput/digitalOutput.module.ts @@ -1,12 +1,12 @@ import { NgModule } from "@angular/core"; import { BrowserModule } from "@angular/platform-browser"; +import { FooterNavigationModule } from "src/app/shared/components/footer/subnavigation/footerNavigation.module"; import { SharedModule } from "src/app/shared/shared.module"; import { TotalChartComponent } from "./chart/chart"; -import { FlatComponent } from "./flat/flat"; -import { OverviewComponent } from "./overview/overview"; import { ChartComponent } from "./details/chart/chart"; import { DetailsOverviewComponent } from "./details/details.overview"; -import { FooterNavigationModule } from "src/app/shared/components/footer/subnavigation/footerNavigation.module"; +import { FlatComponent } from "./flat/flat"; +import { OverviewComponent } from "./overview/overview"; @NgModule({ imports: [ diff --git a/ui/src/app/edge/history/Controller/ModbusTcpApi/modbusTcpApi.module.ts b/ui/src/app/edge/history/Controller/ModbusTcpApi/modbusTcpApi.module.ts index aef372d5a35..b0ca5fb3021 100644 --- a/ui/src/app/edge/history/Controller/ModbusTcpApi/modbusTcpApi.module.ts +++ b/ui/src/app/edge/history/Controller/ModbusTcpApi/modbusTcpApi.module.ts @@ -1,9 +1,9 @@ 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"; import { OverviewComponent } from "./overview/overview"; -import { ChartComponent } from "./chart/chart"; @NgModule({ imports: [ diff --git a/ui/src/app/edge/history/Controller/controller.module.ts b/ui/src/app/edge/history/Controller/controller.module.ts index e009e41d838..773e4d92f97 100644 --- a/ui/src/app/edge/history/Controller/controller.module.ts +++ b/ui/src/app/edge/history/Controller/controller.module.ts @@ -1,9 +1,9 @@ import { NgModule } from "@angular/core"; -import { ControllerEss } from "./Ess/ess.module"; -import { ControllerIo } from "./Io/Io.module"; import { ChannelThreshold } from "./ChannelThreshold/channelThreshold.module"; +import { ControllerEss } from "./Ess/ess.module"; import { GridOptimizeCharge } from "./Ess/GridoptimizedCharge/gridOptimizeCharge.module"; import { TimeOfUseTariff } from "./Ess/TimeOfUseTariff/timeOfUseTariff.module"; +import { ControllerIo } from "./Io/Io.module"; import { ModbusTcpApi } from "./ModbusTcpApi/modbusTcpApi.module"; @NgModule({ diff --git a/ui/src/app/edge/history/common/consumption/Consumption.ts b/ui/src/app/edge/history/common/consumption/Consumption.ts index c36c786695d..9b957fb4e03 100644 --- a/ui/src/app/edge/history/common/consumption/Consumption.ts +++ b/ui/src/app/edge/history/common/consumption/Consumption.ts @@ -1,9 +1,9 @@ import { NgModule } from "@angular/core"; import { BrowserModule } from "@angular/platform-browser"; +import { CurrentVoltageModule } from "src/app/shared/components/edge/meter/currentVoltage/currentVoltageModule"; import { FooterNavigationModule } from "src/app/shared/components/footer/subnavigation/footerNavigation.module"; import { SharedModule } from "src/app/shared/shared.module"; -import { CurrentVoltageModule } from "src/app/shared/components/edge/meter/currentVoltage/currentVoltageModule"; import { ChartComponent } from "./chart/chart"; import { ConsumptionMeterChartDetailsComponent } from "./details/chart/consumptionMeter"; import { EvcsChartDetailsComponent } from "./details/chart/evcs"; diff --git a/ui/src/app/edge/history/common/production/production.ts b/ui/src/app/edge/history/common/production/production.ts index d4b7b9ce39c..b78789fc8de 100644 --- a/ui/src/app/edge/history/common/production/production.ts +++ b/ui/src/app/edge/history/common/production/production.ts @@ -1,9 +1,9 @@ import { NgModule } from "@angular/core"; import { BrowserModule } from "@angular/platform-browser"; +import { CurrentVoltageModule } from "src/app/shared/components/edge/meter/currentVoltage/currentVoltageModule"; import { FooterNavigationModule } from "src/app/shared/components/footer/subnavigation/footerNavigation.module"; import { SharedModule } from "src/app/shared/shared.module"; -import { CurrentVoltageModule } from "src/app/shared/components/edge/meter/currentVoltage/currentVoltageModule"; import { TotalChartComponent } from "./chart/totalChart"; import { ChargerChartDetailsComponent } from "./details/chart/charger"; import { ProductionMeterChartDetailsComponent } from "./details/chart/productionMeter"; diff --git a/ui/src/app/edge/history/shared.ts b/ui/src/app/edge/history/shared.ts index ac05ac3b66f..8f997b3ceb7 100644 --- a/ui/src/app/edge/history/shared.ts +++ b/ui/src/app/edge/history/shared.ts @@ -1,7 +1,10 @@ // @ts-strict-ignore import * as Chart from "chart.js"; +/* eslint-disable import/no-duplicates */ +// cf. https://github.com/import-js/eslint-plugin-import/issues/1479 import { differenceInDays, differenceInMinutes, startOfDay } from "date-fns"; import { de } from "date-fns/locale"; +/* eslint-enable import/no-duplicates */ import { QueryHistoricTimeseriesDataResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesDataResponse"; import { ChannelAddress, Service } from "src/app/shared/shared"; import { DateUtils } from "src/app/shared/utils/date/dateutils"; diff --git a/ui/src/app/edge/history/storage/totalchart.component.ts b/ui/src/app/edge/history/storage/totalchart.component.ts index 13375ae97db..c774c6139ef 100644 --- a/ui/src/app/edge/history/storage/totalchart.component.ts +++ b/ui/src/app/edge/history/storage/totalchart.component.ts @@ -1,4 +1,5 @@ // @ts-strict-ignore +import { formatNumber } from "@angular/common"; import { Component, Input, OnChanges, OnDestroy, OnInit } from "@angular/core"; import { ActivatedRoute } from "@angular/router"; import { TranslateService } from "@ngx-translate/core"; @@ -7,7 +8,6 @@ import { DefaultTypes } from "src/app/shared/service/defaulttypes"; import { ChartAxis, Utils, YAxisType } from "src/app/shared/service/utils"; import { ChannelAddress, Edge, EdgeConfig, Service } from "src/app/shared/shared"; -import { formatNumber } from "@angular/common"; import { AbstractHistoryChart } from "../abstracthistorychart"; @Component({ 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 ca1846f220f..8114c49b3b3 100644 --- a/ui/src/app/edge/live/common/storage/storage.component.ts +++ b/ui/src/app/edge/live/common/storage/storage.component.ts @@ -2,10 +2,9 @@ import { formatNumber } from "@angular/common"; import { Component } from "@angular/core"; import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; -import { CurrentData } from "src/app/shared/shared"; +import { CurrentData , ChannelAddress, EdgeConfig, Utils } from "src/app/shared/shared"; import { DateUtils } from "src/app/shared/utils/date/dateutils"; -import { ChannelAddress, EdgeConfig, Utils } from "../../../../shared/shared"; import { StorageModalComponent } from "./modal/modal.component"; @Component({ diff --git a/ui/src/app/edge/live/live.module.ts b/ui/src/app/edge/live/live.module.ts index ccd88577618..ffec734d90c 100644 --- a/ui/src/app/edge/live/live.module.ts +++ b/ui/src/app/edge/live/live.module.ts @@ -3,14 +3,21 @@ import { BrowserModule } from "@angular/platform-browser"; import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; import { EdgeOfflineModule } from "src/app/shared/components/edge/offline/offline.module"; import { SharedModule } from "./../../shared/shared.module"; +import { Common_Autarchy } from "./common/autarchy/Common_Autarchy"; +import { Common_Consumption } from "./common/consumption/Common_Consumption"; +import { Common_Grid } from "./common/grid/Common_Grid"; +import { Common_Production } from "./common/production/Common_Production"; +import { Common_Selfconsumption } from "./common/selfconsumption/Common_Selfconsumption"; +import { StorageModalComponent } from "./common/storage/modal/modal.component"; +import { StorageComponent } from "./common/storage/storage.component"; import { Controller_ChannelthresholdComponent } from "./Controller/Channelthreshold/Channelthreshold"; import { Controller_ChpSocComponent } from "./Controller/ChpSoc/ChpSoc"; import { Controller_ChpSocModalComponent } from "./Controller/ChpSoc/modal/modal.component"; import { Controller_Ess_FixActivePower } from "./Controller/Ess/FixActivePower/Ess_FixActivePower"; import { Controller_Ess_GridOptimizedCharge } from "./Controller/Ess/GridOptimizedCharge/Ess_GridOptimizedCharge"; import { Controller_Ess_TimeOfUseTariff } from "./Controller/Ess/TimeOfUseTariff/Ess_TimeOfUseTariff"; -import { Controller_Evcs } from "./Controller/Evcs/Evcs"; import { AdministrationComponent } from "./Controller/Evcs/administration/administration.component"; +import { Controller_Evcs } from "./Controller/Evcs/Evcs"; 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"; @@ -21,27 +28,20 @@ import { Controller_Io_HeatpumpModalComponent } from "./Controller/Io/Heatpump/m import { Controller_Api_ModbusTcp } from "./Controller/ModbusTcpApi/modbusTcpApi.module"; import { Controller_Asymmetric_PeakShavingComponent } from "./Controller/PeakShaving/Asymmetric/Asymmetric"; import { Controller_Asymmetric_PeakShavingModalComponent } from "./Controller/PeakShaving/Asymmetric/modal/modal.component"; -import { Controller_Symmetric_PeakShavingComponent } from "./Controller/PeakShaving/Symmetric/Symmetric"; import { Controller_Symmetric_PeakShavingModalComponent } from "./Controller/PeakShaving/Symmetric/modal/modal.component"; -import { Controller_Symmetric_TimeSlot_PeakShavingComponent } from "./Controller/PeakShaving/Symmetric_TimeSlot/Symmetric_TimeSlot"; +import { Controller_Symmetric_PeakShavingComponent } from "./Controller/PeakShaving/Symmetric/Symmetric"; import { Controller_Symmetric_TimeSlot_PeakShavingModalComponent } from "./Controller/PeakShaving/Symmetric_TimeSlot/modal/modal.component"; -import { Io_Api_DigitalInputComponent } from "./Io/Api_DigitalInput/Io_Api_DigitalInput"; -import { Io_Api_DigitalInput_ModalComponent } from "./Io/Api_DigitalInput/modal/modal.component"; -import { Evcs_Api_ClusterComponent } from "./Multiple/Evcs_Api_Cluster/Evcs_Api_Cluster"; -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 { Common_Autarchy } from "./common/autarchy/Common_Autarchy"; -import { Common_Consumption } from "./common/consumption/Common_Consumption"; -import { Common_Grid } from "./common/grid/Common_Grid"; -import { Common_Production } from "./common/production/Common_Production"; -import { Common_Selfconsumption } from "./common/selfconsumption/Common_Selfconsumption"; -import { StorageModalComponent } from "./common/storage/modal/modal.component"; -import { StorageComponent } from "./common/storage/storage.component"; +import { Controller_Symmetric_TimeSlot_PeakShavingComponent } from "./Controller/PeakShaving/Symmetric_TimeSlot/Symmetric_TimeSlot"; import { DelayedSellToGridComponent } from "./delayedselltogrid/delayedselltogrid.component"; import { DelayedSellToGridModalComponent } from "./delayedselltogrid/modal/modal.component"; import { EnergymonitorModule } from "./energymonitor/energymonitor.module"; import { InfoComponent } from "./info/info.component"; +import { Io_Api_DigitalInputComponent } from "./Io/Api_DigitalInput/Io_Api_DigitalInput"; +import { Io_Api_DigitalInput_ModalComponent } from "./Io/Api_DigitalInput/modal/modal.component"; import { LiveComponent } from "./live.component"; +import { Evcs_Api_ClusterComponent } from "./Multiple/Evcs_Api_Cluster/Evcs_Api_Cluster"; +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"; @NgModule({ imports: [ diff --git a/ui/src/app/edge/settings/channels/channels.component.ts b/ui/src/app/edge/settings/channels/channels.component.ts index 36ea1f7911c..e8f2411c1f0 100644 --- a/ui/src/app/edge/settings/channels/channels.component.ts +++ b/ui/src/app/edge/settings/channels/channels.component.ts @@ -3,12 +3,12 @@ import { Component } from "@angular/core"; import { ActivatedRoute, Router } from "@angular/router"; import { TranslateService } from "@ngx-translate/core"; import { PersistencePriority } from "src/app/shared/components/edge/edgeconfig"; -import { SetChannelValueRequest } from "src/app/shared/jsonrpc/request/setChannelValueRequest"; -import { environment } from "src/environments"; import { ComponentJsonApiRequest } from "src/app/shared/jsonrpc/request/componentJsonApiRequest"; import { GetChannelsOfComponentRequest } from "src/app/shared/jsonrpc/request/getChannelsOfComponentRequest"; +import { SetChannelValueRequest } from "src/app/shared/jsonrpc/request/setChannelValueRequest"; import { Channel, GetChannelsOfComponentResponse } from "src/app/shared/jsonrpc/response/getChannelsOfComponentResponse"; +import { environment } from "src/environments"; import { ChannelAddress, Edge, EdgeConfig, EdgePermission, Service, Websocket } from "../../../shared/shared"; @Component({ diff --git a/ui/src/app/index/login.component.ts b/ui/src/app/index/login.component.ts index 26a38d7e767..7b2f876f623 100644 --- a/ui/src/app/index/login.component.ts +++ b/ui/src/app/index/login.component.ts @@ -2,10 +2,10 @@ import { AfterContentChecked, ChangeDetectorRef, Component, OnDestroy, OnInit } from "@angular/core"; import { FormGroup } from "@angular/forms"; import { ActivatedRoute, Router } from "@angular/router"; +import { Capacitor } from "@capacitor/core"; import { Subject } from "rxjs"; import { environment } from "src/environments"; -import { Capacitor } from "@capacitor/core"; import { AppService } from "../app.service"; import { AuthenticateWithPasswordRequest } from "../shared/jsonrpc/request/authenticateWithPasswordRequest"; import { States } from "../shared/ngrx-store/states"; diff --git a/ui/src/app/shared/components/abstracthistorywidget.ts b/ui/src/app/shared/components/abstracthistorywidget.ts index dfc48dffa2a..76204d7e133 100644 --- a/ui/src/app/shared/components/abstracthistorywidget.ts +++ b/ui/src/app/shared/components/abstracthistorywidget.ts @@ -4,9 +4,9 @@ import { ActivatedRoute } from "@angular/router"; import { ModalController } from "@ionic/angular"; import { TranslateService } from "@ngx-translate/core"; import { Subject } from "rxjs"; +import { v4 as uuidv4 } from "uuid"; import { DefaultTypes } from "src/app/shared/service/defaulttypes"; import { ChannelAddress, CurrentData, Edge, EdgeConfig, Service, Websocket } from "src/app/shared/shared"; -import { v4 as uuidv4 } from "uuid"; // NOTE: Auto-refresh of widgets is currently disabled to reduce server load @Directive() diff --git a/ui/src/app/shared/components/chart/abstracthistorychart.ts b/ui/src/app/shared/components/chart/abstracthistorychart.ts index 2e7d88b2fa3..3fdc02b231b 100644 --- a/ui/src/app/shared/components/chart/abstracthistorychart.ts +++ b/ui/src/app/shared/components/chart/abstracthistorychart.ts @@ -4,13 +4,14 @@ import { ChangeDetectorRef, Directive, Input, OnDestroy, OnInit } from "@angular import { ActivatedRoute } from "@angular/router"; import { TranslateService } from "@ngx-translate/core"; import * as Chart from "chart.js"; +import "chartjs-adapter-date-fns"; import annotationPlugin from "chartjs-plugin-annotation"; +import { v4 as uuidv4 } from "uuid"; import { ChronoUnit, DEFAULT_NUMBER_CHART_OPTIONS, DEFAULT_TIME_CHART_OPTIONS, Resolution, calculateResolution, isLabelVisible, setLabelVisible } from "src/app/edge/history/shared"; import { QueryHistoricTimeseriesEnergyPerPeriodResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyPerPeriodResponse"; import { DefaultTypes } from "src/app/shared/service/defaulttypes"; -import { v4 as uuidv4 } from "uuid"; - import { JsonrpcResponseError } from "../../jsonrpc/base"; +import { JsonRpcUtils } from "../../jsonrpc/jsonrpcutils"; import { QueryHistoricTimeseriesDataRequest } from "../../jsonrpc/request/queryHistoricTimeseriesDataRequest"; import { QueryHistoricTimeseriesEnergyPerPeriodRequest } from "../../jsonrpc/request/queryHistoricTimeseriesEnergyPerPeriodRequest"; import { QueryHistoricTimeseriesEnergyRequest } from "../../jsonrpc/request/queryHistoricTimeseriesEnergyRequest"; @@ -27,9 +28,6 @@ import { TimeUtils } from "../../utils/time/timeutils"; import { Converter } from "../shared/converter"; import { ChartConstants, XAxisType } from "./chart.constants"; -import "chartjs-adapter-date-fns"; -import { JsonRpcUtils } from "../../jsonrpc/jsonrpcutils"; - Chart.Chart.register(annotationPlugin); // NOTE: Auto-refresh of widgets is currently disabled to reduce server load diff --git a/ui/src/app/shared/components/chart/chart.constants.ts b/ui/src/app/shared/components/chart/chart.constants.ts index fa8ccf10a71..2adc960c541 100644 --- a/ui/src/app/shared/components/chart/chart.constants.ts +++ b/ui/src/app/shared/components/chart/chart.constants.ts @@ -1,8 +1,8 @@ // @ts-strict-ignore -import { ChartComponentLike, ChartDataset } from "chart.js"; import { formatNumber } from "@angular/common"; import { TranslateService } from "@ngx-translate/core"; +import { ChartComponentLike, ChartDataset } from "chart.js"; import ChartDataLabels from "chartjs-plugin-datalabels"; import { HistoryUtils, Utils } from "../../service/utils"; import { Language } from "../../type/language"; diff --git a/ui/src/app/shared/components/components.module.ts b/ui/src/app/shared/components/components.module.ts index 8e39c2dc74e..cb3b444a6fb 100644 --- a/ui/src/app/shared/components/components.module.ts +++ b/ui/src/app/shared/components/components.module.ts @@ -9,9 +9,9 @@ import { PipeModule } from "../pipe/pipe"; import { ChartModule } from "./chart/chart.module"; import { FlatWidgetComponent } from "./flat/flat"; import { FlatWidgetHorizontalLineComponent } from "./flat/flat-widget-horizontal-line/flat-widget-horizontal-line"; -import { FlatWidgetLineDividerComponent } from "./flat/flat-widget-line-divider/flat-widget-line-divider"; import { FlatWidgetLineComponent } from "./flat/flat-widget-line/flat-widget-line"; import { FlatWidgetLineItemComponent } from "./flat/flat-widget-line/flat-widget-line-item/flat-widget-line-item"; +import { FlatWidgetLineDividerComponent } from "./flat/flat-widget-line-divider/flat-widget-line-divider"; import { FlatWidgetPercentagebarComponent } from "./flat/flat-widget-percentagebar/flat-widget-percentagebar"; import { FooterComponent } from "./footer/footer"; import { FooterNavigationModule } from "./footer/subnavigation/footerNavigation.module"; diff --git a/ui/src/app/shared/components/flat/abstract-flat-widget-line.ts b/ui/src/app/shared/components/flat/abstract-flat-widget-line.ts index 2d697a6a6e0..04821ded125 100644 --- a/ui/src/app/shared/components/flat/abstract-flat-widget-line.ts +++ b/ui/src/app/shared/components/flat/abstract-flat-widget-line.ts @@ -4,8 +4,8 @@ import { ActivatedRoute } from "@angular/router"; import { ModalController } from "@ionic/angular"; import { Subject } from "rxjs"; import { takeUntil } from "rxjs/operators"; -import { ChannelAddress, Edge, Service, Websocket } from "src/app/shared/shared"; import { v4 as uuidv4 } from "uuid"; +import { ChannelAddress, Edge, Service, Websocket } from "src/app/shared/shared"; import { DataService } from "../shared/dataservice"; import { Filter } from "../shared/filter"; diff --git a/ui/src/app/shared/components/flat/abstract-flat-widget.ts b/ui/src/app/shared/components/flat/abstract-flat-widget.ts index bddb7f5283e..a8a1e654f82 100644 --- a/ui/src/app/shared/components/flat/abstract-flat-widget.ts +++ b/ui/src/app/shared/components/flat/abstract-flat-widget.ts @@ -1,14 +1,14 @@ // @ts-strict-ignore import { Directive, Inject, Input, OnDestroy, OnInit } from "@angular/core"; +import { FormBuilder, FormGroup } from "@angular/forms"; import { ActivatedRoute, Router } from "@angular/router"; import { ModalController } from "@ionic/angular"; import { TranslateService } from "@ngx-translate/core"; import { Subject } from "rxjs"; import { takeUntil } from "rxjs/operators"; -import { ChannelAddress, CurrentData, Edge, EdgeConfig, Utils } from "src/app/shared/shared"; import { v4 as uuidv4 } from "uuid"; +import { ChannelAddress, CurrentData, Edge, EdgeConfig, Utils } from "src/app/shared/shared"; -import { FormBuilder, FormGroup } from "@angular/forms"; import { Service } from "../../service/service"; import { Websocket } from "../../service/websocket"; import { Converter } from "../shared/converter"; diff --git a/ui/src/app/shared/components/modal/abstract-modal-line.ts b/ui/src/app/shared/components/modal/abstract-modal-line.ts index f16f75a48f8..0db855672ea 100644 --- a/ui/src/app/shared/components/modal/abstract-modal-line.ts +++ b/ui/src/app/shared/components/modal/abstract-modal-line.ts @@ -6,8 +6,8 @@ import { ModalController } from "@ionic/angular"; import { TranslateService } from "@ngx-translate/core"; 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 { ChannelAddress, CurrentData, Edge, EdgeConfig, Service, Utils, Websocket } from "src/app/shared/shared"; import { Role } from "../../type/role"; import { Converter } from "../shared/converter"; diff --git a/ui/src/app/shared/components/modal/abstractModal.ts b/ui/src/app/shared/components/modal/abstractModal.ts index 225cf314e76..b6520994122 100644 --- a/ui/src/app/shared/components/modal/abstractModal.ts +++ b/ui/src/app/shared/components/modal/abstractModal.ts @@ -6,8 +6,8 @@ import { ModalController } from "@ionic/angular"; import { TranslateService } from "@ngx-translate/core"; import { Subject, Subscription } 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 { ChannelAddress, CurrentData, Edge, EdgeConfig, Service, Utils, Websocket } from "src/app/shared/shared"; import { Role } from "../../type/role"; import { Converter } from "../shared/converter"; diff --git a/ui/src/app/shared/service/pagination.ts b/ui/src/app/shared/service/pagination.ts index f75a43c2f71..bef8d9d1e77 100644 --- a/ui/src/app/shared/service/pagination.ts +++ b/ui/src/app/shared/service/pagination.ts @@ -2,9 +2,9 @@ import { Directive } from "@angular/core"; import { Router } from "@angular/router"; import { SubscribeEdgesRequest } from "../jsonrpc/request/subscribeEdgesRequest"; +import { States } from "../ngrx-store/states"; import { ChannelAddress, Edge } from "../shared"; import { Service } from "./service"; -import { States } from "../ngrx-store/states"; @Directive() export class Pagination { diff --git a/ui/src/app/shared/utils/datetime/datetime-utils.ts b/ui/src/app/shared/utils/datetime/datetime-utils.ts index 70bb0b7cc58..83cec0673be 100644 --- a/ui/src/app/shared/utils/datetime/datetime-utils.ts +++ b/ui/src/app/shared/utils/datetime/datetime-utils.ts @@ -1,6 +1,9 @@ // @ts-strict-ignore +/* eslint-disable import/no-duplicates */ +// cf. https://github.com/import-js/eslint-plugin-import/issues/1479 import { format, startOfMonth, startOfYear } from "date-fns"; import { de } from "date-fns/locale"; +/* eslint-enable import/no-duplicates */ import { ChronoUnit } from "src/app/edge/history/shared"; import { QueryHistoricTimeseriesDataResponse } from "../../jsonrpc/response/queryHistoricTimeseriesDataResponse"; From 864d7ce2a89af8dbe4031e390436be1ef96e872a Mon Sep 17 00:00:00 2001 From: "Kai J." Date: Sun, 13 Oct 2024 14:55:00 +0200 Subject: [PATCH 155/173] UI: fix display error + percentagebar calculation (#2837) * fix reserve bar * fix energy chart cutoff * fix percentbar warning * fix on reserve soc --- ui/src/app/edge/live/common/storage/storage.component.html | 7 +++---- .../app/edge/live/energymonitor/chart/chart.component.html | 2 +- .../flat-widget-percentagebar.html | 6 +++--- .../flat-widget-percentagebar/flat-widget-percentagebar.ts | 6 +++++- 4 files changed, 12 insertions(+), 9 deletions(-) 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 d7ffcb21081..6f8c5db2bb1 100644 --- a/ui/src/app/edge/live/common/storage/storage.component.html +++ b/ui/src/app/edge/live/common/storage/storage.component.html @@ -15,10 +15,9 @@ - - + + diff --git a/ui/src/app/edge/live/energymonitor/chart/chart.component.html b/ui/src/app/edge/live/energymonitor/chart/chart.component.html index c2eddea61c8..d27b5bac185 100644 --- a/ui/src/app/edge/live/energymonitor/chart/chart.component.html +++ b/ui/src/app/edge/live/energymonitor/chart/chart.component.html @@ -1,7 +1,7 @@
      - + diff --git a/ui/src/app/shared/components/flat/flat-widget-percentagebar/flat-widget-percentagebar.html b/ui/src/app/shared/components/flat/flat-widget-percentagebar/flat-widget-percentagebar.html index 5570abc71b8..4e42eb338d3 100644 --- a/ui/src/app/shared/components/flat/flat-widget-percentagebar/flat-widget-percentagebar.html +++ b/ui/src/app/shared/components/flat/flat-widget-percentagebar/flat-widget-percentagebar.html @@ -1,10 +1,10 @@ - + - {{ displayValue | unitvalue: '%' }} + {{ displayPercent | unitvalue: '%' }} diff --git a/ui/src/app/shared/components/flat/flat-widget-percentagebar/flat-widget-percentagebar.ts b/ui/src/app/shared/components/flat/flat-widget-percentagebar/flat-widget-percentagebar.ts index 668caef9e60..3faf1948a9f 100644 --- a/ui/src/app/shared/components/flat/flat-widget-percentagebar/flat-widget-percentagebar.ts +++ b/ui/src/app/shared/components/flat/flat-widget-percentagebar/flat-widget-percentagebar.ts @@ -5,4 +5,8 @@ import { AbstractFlatWidgetLine } from "../abstract-flat-widget-line"; selector: "oe-flat-widget-percentagebar", templateUrl: "./flat-widget-percentagebar.html", }) -export class FlatWidgetPercentagebarComponent extends AbstractFlatWidgetLine { } +export class FlatWidgetPercentagebarComponent extends AbstractFlatWidgetLine { + protected get displayPercent(): number { + return Math.round(Number.parseFloat(this.displayValue)); + } +} From 1b18fa05789469a829c0e06f96e239e86ffd2334 Mon Sep 17 00:00:00 2001 From: j-eissler <57557568+j-eissler@users.noreply.github.com> Date: Sun, 13 Oct 2024 15:14:13 +0200 Subject: [PATCH 156/173] Docs: add hint to README to fix an error with building a Docker image (#2833) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jan Eißler --- tools/docker/backend/README.md | 6 ++++++ tools/docker/edge/README.md | 9 ++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/tools/docker/backend/README.md b/tools/docker/backend/README.md index 259f8b5c14d..a785852113b 100644 --- a/tools/docker/backend/README.md +++ b/tools/docker/backend/README.md @@ -78,3 +78,9 @@ ``` *for UI Image see [ui/README.md](../ui/README.md)* + +# Common Problems and Solutions +``` +ERROR: failed to solve: error from sender: context canceled +``` +When building the Docker image this error may occur because another program is accessing the project files. Try closing these programs (e.g. Eclipse IDE) and run the build command again. \ No newline at end of file diff --git a/tools/docker/edge/README.md b/tools/docker/edge/README.md index 441b234c9a4..2cce0d4d245 100644 --- a/tools/docker/edge/README.md +++ b/tools/docker/edge/README.md @@ -35,4 +35,11 @@ docker build . -t openems_edge -f tools/docker/edge/Dockerfile ``` - *for UI Image see [ui/README.md](../ui/README.md)* \ No newline at end of file + *for UI Image see [ui/README.md](../ui/README.md)* + +# Common Problems and Solutions +``` +ERROR: failed to solve: error from sender: context canceled +``` +When building the Docker image this error may occur because another program is accessing the project files. Try closing these programs (e.g. Eclipse IDE) and run the build command again. + From 0b2071c9b8db7441019f18f8bdf7ae13e4d36fa2 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Sat, 19 Oct 2024 00:22:55 +0200 Subject: [PATCH 157/173] FEMS Backports 2024-10 (2) (#2846) - EVCS HardyBarth: communicate via HTTP-Bridge - Implemented BridgeHttp in Impl of HardyBarthEvcs - All Api Calls now flow through that Bridge - Api Calls (esp. setHeartBeat that previously was synchronous) are now asynchronous - Add JUnit tests - EVCS: implement ElectricityMeter - Migrate all EVCS to ElectricityMeter Nature - Add `DeprecatedEvcs` Nature to mark EVCS that have to be migrated and still support old Channels ChargePower and ActiveConsumptionEnergy - Implement generic `evaluatePhaseCount()` method - UI: Mix Evcs & ElectricityMeter (live != history) - Live: use ElectricityMeter if its already available (e.g. for power of individual phases) - History: use Evcs to ensure availability of historic data - Implement configurable PhaseRotation in configuration and Apps (copied and adjusted from #2047) - Fix AbstractManagedEvcs deactivate() - UI: Performance improvements - Navigation for users with at most Role `OWNER` with one fems assigned, get directly routed to `device/edgeId/live` - Navigation for users with at least Role `INSTALLER` -> `/overview` - Removed flickering of headerComponent. Issue results from creating header component for each view - Sum: do not ignore ExtremeEverValues in EdgeConfig - Update gradle to 8.10.2 - https://github.com/gradle/gradle/releases/tag/v8.10.2 - UI: Refactor heating element history - Refactoring HeatingElement and using the new ```Cumulated[Level 1 -3]ActiveTime``` - UI: Adjust Chart-axis generation - Multiple yAxis: Increase chart canvas by putting y axis labels into ticks, the most upper tick gets replaced by axis title - Extend export to Excel file - Added detailed data for the excel export of historic data - UI: fix header in history charts and add enable rescaling in history charts - Rescaling of charts was not possible due to not ignoring hidden values - Header was shown in the chart views - Introduce `` and keep `
      ` as single navigation point header - Java JUnit tests: improve framework + cleanup - Improve OpenEMS JUnit test framework - Apply best practices to JUnit tests --------- Co-authored-by: Lukas Rieger <73471197+lukasrgr@users.noreply.github.com> Co-authored-by: Sebastian Asen <47855186+sebastianasen@users.noreply.github.com> Co-authored-by: Stefan Feilmeier <3515268+sfeilmeier@users.noreply.github.com> Co-authored-by: Johann Kaufmann <165755282+johannk24@users.noreply.github.com> --- .gradle-wrapper/gradle-wrapper.properties | 2 +- .../EdgeRpcRequestHandler.java | 45 +- .../$basePackageDir$/MyControllerTest.java | 9 +- .../$basePackageDir$/MyModbusDeviceTest.java | 14 +- .../$basePackageDir$/MyDeviceTest.java | 9 +- ...yHistoricTimeseriesExportXlsxResponse.java | 274 +++++- .../response/translation_de.properties | 7 +- .../response/translation_en.properties | 7 +- .../timedata/CommonTimedataService.java | 36 - .../common/timedata/XlsxExportDetailData.java | 37 + .../common/timedata/XlsxExportUtil.java | 112 +++ .../common/timedata/XlsxWorksheetWrapper.java | 46 + .../openems/common/types/CurrencyConfig.java | 49 ++ .../io/openems/common/types/EdgeConfig.java | 42 +- .../openems/common/websocket/MyDraft6455.java | 1 + .../jsonrpc/response/CreateXlxsTest.java | 248 ++++++ .../protection/BatteryProtectionTest.java | 250 +++--- .../edge/battery/bmw/BmwBatteryImplTest.java | 18 +- .../BydBatteryBoxCommercialC130ImplTest.java | 20 +- .../BatteryFeneconCommercialImplTest.java | 94 +-- .../DynamicChannelsAndSerialNumbersTest.java | 34 +- .../home/FeneconHomeBatteryProtection64.java | 6 +- .../home/BatteryFeneconHomeImplTest.java | 375 ++++----- .../fenecon/home/TowersAndModulesTest.java | 25 +- ...BatterySoltaroClusterVersionBImplTest.java | 28 +- ...BatterySoltaroClusterVersionCImplTest.java | 9 +- ...terySoltaroSingleRackVersionAImplTest.java | 9 +- ...terySoltaroSingleRackVersionBImplTest.java | 9 +- ...terySoltaroSingleRackVersionCImplTest.java | 9 +- ...nverterKacoBlueplanetGridsaveImplTest.java | 62 +- .../BatteryInverterRefuStore88kImplTest.java | 9 +- .../BatteryInverterSinexcelImplTest.java | 34 +- .../http/dummy/DummyBridgeHttpBundle.java | 7 +- .../http/dummy/DummyBridgeHttpExecutor.java | 10 + .../http/dummy/DummyBridgeHttpFactory.java | 25 + .../bridge/http/api/BridgeHttpCycleTest.java | 3 +- .../edge/bridge/http/api/BridgeHttpTest.java | 5 +- .../bridge/http/api/BridgeHttpTimeTest.java | 3 +- .../modbus/BridgeModbusSerialImplTest.java | 4 +- .../modbus/BridgeModbusTcpImplTest.java | 23 +- .../internal/DefectiveComponentsTest.java | 7 +- .../internal/TasksSupplierImplTest.java | 3 +- .../onewire/impl/BridgeOnewireImplTest.java | 4 +- .../edge/common/currency/Currency.java | 15 + .../edge/common/currency/CurrencyConfig.java | 38 - .../common/test/AbstractComponentTest.java | 256 +++++- .../common/test/DummyComponentManager.java | 4 +- .../openems/edge/common/test/TestUtils.java | 11 + .../backend/ControllerApiBackendImplTest.java | 4 +- .../common/handler/QueryRequestHandler.java | 45 +- ...ontrollerApiModbusTcpReadOnlyImplTest.java | 11 +- ...ntrollerApiModbusTcpReadWriteImplTest.java | 23 +- .../api/modbus/readwrite/MyConfig.java | 5 - .../api/mqtt/ControllerApiMqttImplTest.java | 8 +- .../ControllerApiRestReadOnlyImplTest.java | 7 +- .../ControllerApiRestReadWriteImplTest.java | 18 +- .../ControllerApiWebsocketImplTest.java | 10 +- ...llerAsymmetricBalancingCosPhiImplTest.java | 18 +- ...lerAsymmetricFixReactivePowerImplTest.java | 13 +- ...ntrollerAsymmetricPeakShavingImplTest.java | 172 ++-- ...rAsymmetricPhaseRectificationImplTest.java | 18 +- .../ControllerChannelThresholdImplTest.java | 11 +- .../controller/channelthreshold/MyConfig.java | 9 +- .../chp/soc/ControllerChpSocImplTest.java | 59 +- .../ControllerDebugDetailedLogImplTest.java | 7 +- .../debuglog/ControllerDebugLogImplTest.java | 56 +- .../edge/controller/debuglog/MyConfig.java | 4 +- .../ControllerEssAcIslandImplTest.java | 19 +- .../CharacteristicImplTest.java | 63 +- .../ess/balancing/BalancingImplTest.java | 110 ++- .../ess/cycle/ControllerEssCycleImplTest.java | 94 +-- .../ControllerEssDelayChargeImplTest.java | 42 +- ...ontrollerEssDelayedSellToGridImplTest.java | 84 +- ...erEssEmergencyCapacityReserveImplTest.java | 340 ++++---- .../statemachine/ActivationTimeHandler.java | 2 +- ...ntrollerFastFrequencyReserveImplTest.java} | 247 +++--- ...trollerFastFrequencyReserveImplTest2.java} | 141 ++-- .../ess/fastfrequencyreserve/MyConfig.java | 2 - .../ControllerEssFixActivePowerImplTest.java | 28 +- ...ControllerEssFixStateOfChargeImplTest.java | 792 +++++++++--------- ...trollerEssGridOptimizedChargeImplTest.java | 529 ++++++------ ...lerEssHybridSurplusFeedToGridImplTest.java | 32 +- .../ControllerEssLimiter14aImpl.java | 1 + .../ControllerEssLimiter14aTest.java | 42 +- ...trollerEssLimitTotalDischargeImplTest.java | 49 +- .../ControllerEssLinearPowerBandImplTest.java | 49 +- ...ollerEssMinimumDischargePowerImplTest.java | 11 +- ...ivePowerVoltageCharacteristicImplTest.java | 106 ++- .../ControllerEssSellToGridLimitImplTest.java | 40 +- .../standby/ControllerEssStandbyImplTest.java | 141 ++-- .../TimeOfUseTariffControllerImplTest.java | 14 +- .../bnd.bnd | 3 +- .../ControllerEvcsFixActivePowerImplTest.java | 11 +- io.openems.edge.controller.evcs/bnd.bnd | 3 +- .../evcs/ChargingLowerThanTargetHandler.java | 2 +- .../controller/evcs/ControllerEvcsImpl.java | 12 +- .../evcs/ControllerEvcsImplTest.java | 359 ++++---- .../ControllerGenericJsonLogicImplTest.java | 31 +- .../ControllerGenericJsonLogicImplTest2.java | 84 +- .../ControllerHighLoadTimeslotImplTest.java | 16 +- .../io/alarm/ControllerIoAlarmImplTest.java | 51 +- .../io/analog/MyControllerTest.java | 100 +-- ...ollerIoChannelSingleThresholdImplTest.java | 35 +- .../ControllerIoFixDigitalOutputImplTest.java | 18 +- .../ControllerHeatingElementImplTest4.java | 57 +- .../ControllerIoHeatingElementImplTest.java | 236 +++--- .../ControllerIoHeatingElementImplTest2.java | 158 ++-- .../ControllerIoHeatingElementImplTest3.java | 60 +- .../ControllerIoHeatPumpSgReadyImplTest.java | 334 ++++---- ...rollerPvInverterFixPowerLimitImplTest.java | 11 +- ...llerPvInverterSellToGridLimitImplTest.java | 199 +++-- ...ontrollerEssBalancingScheduleImplTest.java | 88 +- ...ControllerEssFixReactivePowerImplTest.java | 11 +- ...ControllerEssLimitActivePowerImplTest.java | 11 +- .../ControllerEssPeakShavingImplTest.java | 110 ++- .../ControllerEssRandomPowerImplTest.java | 10 +- ...trollerEssTimeslotPeakshavingImplTest.java | 80 +- .../io/openems/edge/app/evcs/EvcsProps.java | 24 +- .../openems/edge/app/evcs/HardyBarthEvcs.java | 5 + .../io/openems/edge/app/evcs/KebaEvcs.java | 6 +- .../core/appmanager/translation_de.properties | 2 + .../core/appmanager/translation_en.properties | 2 + .../componentmanager/EdgeConfigWorker.java | 2 +- .../src/io/openems/edge/core/meta/Config.java | 2 +- .../io/openems/edge/core/meta/MetaImpl.java | 3 +- .../src/io/openems/edge/core/sum/SumImpl.java | 3 +- .../TestFeneconHome30DefaultRelays.java | 6 +- .../TestFeneconHomeDefaultRelays.java | 6 +- .../openems/edge/core/meta/MetaImplTest.java | 2 +- .../io/openems/edge/core/meta/MyConfig.java | 2 +- .../PredictorManagerImplTest.java | 6 +- .../edge/core/sum/ExtremeEverValuesTest.java | 17 +- .../io/openems/edge/core/sum/SumImplTest.java | 12 +- .../edge2edge/ess/Edge2EdgeEssImplTest.java | 11 +- .../meter/Edge2EdgeEssMeterImplTest.java | 16 +- .../edge/energy/EnergySchedulerImplTest.java | 4 +- .../edge/energy/optimizer/UtilsTest.java | 17 +- .../EssFeneconBydContainerImplTest.java | 19 +- ...ydContainerWatchdogControllerImplTest.java | 81 -- .../byd/container/watchdog/MyEssConfig.java | 101 --- .../container/watchdog/MyWatchdogConfig.java | 51 -- .../edge/ess/cluster/EssClusterImplTest.java | 184 ++-- .../ess/core/power/PowerComponentTest.java | 171 ++-- .../ess/core/power/PowerComponentTest2.java | 22 +- .../EssFeneconCommercial40ImplTest.java | 9 +- .../EssFeneconCommercial40Pv1ImplTest.java | 18 +- .../EssFeneconCommercial40Pv2ImplTest.java | 18 +- .../AllowedChargeDischargeHandlerTest.java | 29 +- .../offgrid/EssGenericOffGridImplTest.java | 26 +- .../EssGenericManagedSymmetricImplTest.java | 110 ++- .../generic/symmetric/EssProtectionTest.java | 656 +++++++-------- .../EssSmaSunnyIslandImplTest.java | 9 +- .../bnd.bnd | 1 + .../EvcsAlpitronicHyperchargerImpl.java | 77 +- .../EvcsAlpitronicHyperchargerImplTest.java | 9 +- io.openems.edge.evcs.api/bnd.bnd | 2 +- .../api/AbstractManagedEvcsComponent.java | 18 +- .../openems/edge/evcs/api/DeprecatedEvcs.java | 58 ++ .../src/io/openems/edge/evcs/api/Evcs.java | 160 +--- .../openems/edge/evcs/api/MeasuringEvcs.java | 39 +- .../openems/edge/evcs/api/PhaseRotation.java | 77 ++ .../openems/edge/evcs/api/WriteHandler.java | 11 +- .../edge/evcs/test/DummyManagedEvcs.java | 8 +- .../evcs/api/AbstractManagedEvcsTest.java | 541 ++++++------ .../cluster/EvcsClusterPeakShavingImpl.java | 51 +- .../EvcsClusterPeakShavingImplTest.java | 766 ++++++++--------- .../openems/edge/evcs/cluster/MyConfig.java | 14 +- io.openems.edge.evcs.dezony/bnd.bnd | 3 +- .../edge/evcs/dezony/DezonyReadWorker.java | 89 +- .../edge/evcs/dezony/EvcsDezonyImpl.java | 26 +- .../edge/evcs/dezony/EvcsDezonyImplTest.java | 4 +- io.openems.edge.evcs.goe.chargerhome/bnd.bnd | 3 +- .../goe/chargerhome/EvcsGoeChargerHome.java | 10 +- .../chargerhome/EvcsGoeChargerHomeImpl.java | 58 +- .../EvcsGoeChargerHomeImplTest.java | 4 +- io.openems.edge.evcs.hardybarth/bnd.bnd | 4 +- .../openems/edge/evcs/hardybarth/Config.java | 5 + .../edge/evcs/hardybarth/EvcsHardyBarth.java | 199 +++-- .../evcs/hardybarth/EvcsHardyBarthImpl.java | 186 ++-- .../edge/evcs/hardybarth/HardyBarthApi.java | 154 ---- .../evcs/hardybarth/HardyBarthReadUtils.java | 272 ++++++ .../evcs/hardybarth/HardyBarthReadWorker.java | 318 ------- .../hardybarth/HardyBarthWriteHandler.java | 31 + .../hardybarth/EvcsHardyBarthImplTest.java | 267 +++++- .../edge/evcs/hardybarth/MyConfig.java | 12 + io.openems.edge.evcs.keba.kecontact/bnd.bnd | 3 +- .../edge/evcs/keba/kecontact/Config.java | 5 + .../keba/kecontact/EvcsKebaKeContact.java | 44 +- .../keba/kecontact/EvcsKebaKeContactImpl.java | 20 +- .../edge/evcs/keba/kecontact/ReadHandler.java | 508 +++++------ .../kecontact/EvcsKebaKeContactImplTest.java | 126 ++- .../edge/evcs/keba/kecontact/MyConfig.java | 14 +- .../edge/evcs/ocpp/abl/EvcsOcppAbl.java | 4 +- .../edge/evcs/ocpp/abl/EvcsOcppAblImpl.java | 5 +- .../evcs/ocpp/abl/EvcsOcppAblImplTest.java | 4 +- .../AbstractManagedOcppEvcsComponent.java | 54 +- .../evcs/ocpp/common/OcppInformations.java | 8 +- .../singleccs/EvcsOcppIesKeywattSingle.java | 3 +- .../EvcsOcppIesKeywattSingleImpl.java | 7 +- .../EvcsOcppIesKeywattSingleImplTest.java | 4 +- io.openems.edge.evcs.ocpp.server/bnd.bnd | 1 + .../ocpp/server/CoreEventHandlerImpl.java | 39 +- io.openems.edge.evcs.spelsberg/bnd.bnd | 1 + .../spelsberg/smart/EvcsSpelsbergSmart.java | 78 -- .../smart/EvcsSpelsbergSmartImpl.java | 41 +- .../smart/EvcsSpelsbergSmartImplTest.java | 9 +- io.openems.edge.evcs.webasto.next/bnd.bnd | 1 + .../evcs/webasto/next/EvcsWebastoNext.java | 75 -- .../webasto/next/EvcsWebastoNextImpl.java | 49 +- .../webasto/next/EvcsWebastoNextImplTest.java | 9 +- io.openems.edge.evcs.webasto.unite/bnd.bnd | 1 + .../evcs/webasto/unite/EvcsWebastoUnite.java | 110 +-- .../webasto/unite/EvcsWebastoUniteImpl.java | 24 +- .../webasto/unite/WebastoReadHandler.java | 56 +- .../unite/EvcsWebastoUniteImplTest.java | 9 +- .../dess/charger/FeneconDessCharger1Test.java | 16 +- .../dess/charger/FeneconDessCharger2Test.java | 16 +- .../dess/ess/FeneconDessEssImplTest.java | 9 +- .../FeneconDessGridMeterImplTest.java | 9 +- .../pvmeter/FeneconDessPvMeterImplTest.java | 9 +- .../mini/ess/FeneconMiniEssImplTest.java | 125 ++- .../FeneconMiniGridMeterImplTest.java | 9 +- .../pvmeter/FeneconMiniPvMeterImplTest.java | 9 +- .../pro/ess/FeneconProEssImplTest.java | 9 +- .../pvmeter/FeneconProPvMeterImplTest.java | 9 +- .../GoodWeBatteryInverterImplTest.java | 409 ++++----- .../GoodWeChargerMpptTwoStringImplTest.java | 191 ++--- .../singlestring/GoodWeChargerPv1Test.java | 12 +- .../singlestring/GoodWeChargerPv2Test.java | 12 +- .../GoodWeChargerTwoStringImplTest.java | 7 +- .../GoodWeEmergencyPowerMeterTest.java | 10 +- .../edge/goodwe/ess/GoodWeEssImplTest.java | 33 +- .../gridmeter/GoodWeGridMeterImplTest.java | 85 +- .../edge/io/test/DummyCustomInputOutput.java | 57 ++ .../edge/io/test/DummyInputOutput.java | 59 +- .../analog/mr/IoFilipowskiMrAo1ImplTest.java | 9 +- .../openems/edge/io/gpio/ModberryCM4Test.java | 89 +- .../eight/IoKmtronicRelay8PortImplTest.java | 9 +- .../four/IoKmtronicRelay4PortImplTest.java | 9 +- .../IoOffGridSwitchImplTest.java | 26 +- .../IoRevolutionPiDigitalIoImplTest.java | 2 - .../shelly/shellypro3em/IoShellyPro3Em.java | 2 +- .../shelly/shelly25/IoShelly25ImplTest.java | 9 +- .../shelly/shelly3em/IoShelly3EmImplTest.java | 13 +- .../shellyplug/IoShellyPlugImplTest.java | 13 +- .../IoShellyPlus1PmImplTest.java | 39 +- .../shellyplusplugs/IoShellyPlugImplTest.java | 39 +- .../io/shelly/shellyplusplugs/MyConfig.java | 1 - .../shellypro3/IoShellyPro3ImplTest.java | 4 +- .../shellypro3em/IoShelly3EmImplTest.java | 4 +- .../io/openems/edge/wago/IoWagoImplTest.java | 13 +- .../IoWeidmuellerUr20ImplTest.java | 9 +- .../KacoBlueplanetHybrid10CoreImplTest.java | 4 +- .../KacoBlueplanetHybrid10EssImplTest.java | 10 +- ...KacoBlueplanetHybrid10ChargerImplTest.java | 7 +- ...oBlueplanetHybrid10PvInverterImplTest.java | 7 +- ...coBlueplanetHybrid10GridMeterImplTest.java | 7 +- .../charger/KostalPikoChargerImplTest.java | 4 +- .../core/impl/KostalPikoCoreImplTest.java | 4 +- .../piko/ess/KostalPikoEssImplTest.java | 4 +- .../KostalPikoGridMeterImplTest.java | 4 +- .../artemes/am2/MeterArtemesAM2ImplTest.java | 14 +- .../em300/MeterBControlEM300ImplTest.java | 14 +- .../aplus/MeterCamillebauerAplusImplTest.java | 16 +- .../em300/MeterCarloGavazziEm300ImplTest.java | 14 +- .../discovergy/MeterDiscovergyImplTest.java | 9 +- .../sdm120/MeterEastronSdm120ImplTest.java | 18 +- .../sdm630/MeterEastronSdm630ImplTest.java | 14 +- .../umg511/MeterJanitzaUmg511ImplTest.java | 14 +- .../umg604/MeterJanitzaUmg604ImplTest.java | 14 +- .../MeterJanitzaUmg96rmeImplTest.java | 14 +- .../kdk/puct2/MeterKdk2puctImplTest.java | 14 +- .../PhoenixContactMeterImplTest.java | 14 +- .../MeterPlexlogDataloggerImplTest.java | 14 +- .../umd96/MeterPqplusUmd96ImplTest.java | 14 +- .../umd97/MeterPqplusUmd97ImplTest.java | 14 +- .../MeterSchneiderActi9SmartlinkImplTest.java | 14 +- .../pac1600/MeterSiemensPac1600ImplTest.java | 14 +- .../pac2200/MeterSiemensPac2200ImplTest.java | 14 +- .../sma/shm20/MeterSmaShm20ImplTest.java | 14 +- .../MeterSocomecSinglephaseImplTest.java | 18 +- .../MeterSocomecThreephaseImplTest.java | 14 +- .../virtual/add/MeterVirtualAddImplTest.java | 106 +-- .../VirtualSubtractMeterImplTest.java | 62 +- .../MeterWeidmueller525ImplTest.java | 14 +- .../MeterZiehlEfr4001IpImplTest.java | 14 +- .../PredictorPersistenceModelImplTest.java | 39 +- .../PredictorSimilardayModelImplTest.java | 7 +- .../cluster/PvInverterClusterImplTest.java | 4 +- .../fronius/PvInverterFroniusImplTest.java | 9 +- .../PvInverterKacoBlueplanetImplTest.java | 9 +- .../kostal/PvInverterKostalImplTest.java | 9 +- .../PvInverterSmaSunnyTripowerImplTest.java | 14 +- .../solarlog/PvInverterSolarlogImplTest.java | 9 +- .../SchedulerAllAlphabeticallyImplTest.java | 26 +- .../daily/SchedulerDailyImplTest.java | 59 +- .../SchedulerFixedOrderImplTest.java | 3 +- .../datasource/api/DummyDatasource.java | 38 + .../edge/simulator/evcs/SimulatorEvcs.java | 25 +- .../simulator/evcs/SimulatorEvcsImpl.java | 14 +- .../acting/SimulatorGridMeterActingImpl.java | 4 +- .../battery/SimulatorBatteryImplTest.java | 4 +- ...ulatorDatasourceCsvPredefinedImplTest.java | 4 +- ...mulatorDatasourceSingleDirectImplTest.java | 4 +- .../simulator/evcs/SimulatorEvcsImplTest.java | 4 +- ...SimulatorIoDigitalInputOutputImplTest.java | 4 +- .../SimulatorGridMeterActingImplTest.java | 27 +- .../SimulatorGridMeterReactingImplTest.java | 4 +- .../modbus/SimulatorModbusImplTest.java | 4 +- .../SimulatorPvInverterImplTest.java | 7 +- .../SimulatorThermometerImplTest.java | 4 +- .../timedata/SimulatorTimedataImplTest.java | 4 +- .../gridmeter/SolarEdgeGridMeterImplTest.java | 14 +- .../SolarEdgePvInverterImplTest.java | 14 +- .../influxdb/TimedataInfluxDbImplTest.java | 13 +- .../timedata/rrd4j/TimedataRrd4jImplTest.java | 8 +- .../TimeOfUseTariffAwattarImplTest.java | 7 +- .../TimeOfUseTariffCorrentlyImplTest.java | 4 +- .../timeofusetariff/entsoe/TouEntsoeTest.java | 4 +- .../groupe/TimeOfUseTariffGroupeImplTest.java | 13 +- .../TimeOfUseTariffHassfurtImplTest.java | 16 +- .../TimeOfUseTariffRabotChargeImplTest.java | 17 +- .../tibber/TimeOfUseTariffTibberImplTest.java | 7 +- package-lock.json | 6 + ui/.project | 11 + ui/README.md | 5 +- ui/src/app/app-routing.module.ts | 2 +- ui/src/app/app.component.html | 82 +- ui/src/app/changelog/view/view.html | 1 - .../edge/history/Controller/Io/Io.module.ts | 3 + .../Io/heatingelement/chart/chart.ts | 82 ++ .../Io/heatingelement/flat/flat.html | 8 + .../Controller/Io/heatingelement/flat/flat.ts | 10 + .../heatingelement/heatingelement.module.ts | 24 + .../Io/heatingelement/overview/overview.html | 4 + .../Io/heatingelement/overview/overview.ts | 8 + .../history/common/consumption/chart/chart.ts | 8 +- .../history/common/consumption/flat/flat.ts | 11 +- .../common/consumption/overview/overview.ts | 3 +- .../common/energy/chart/channels.spec.ts | 12 +- .../history/common/energy/chart/chart.spec.ts | 4 +- .../history/common/grid/chart/chart.spec.ts | 17 +- .../details/chart/productionMeter.spec.ts | 7 - .../history/heatingelement/chart.component.ts | 126 --- ...heatingelementchartoverview.component.html | 23 - .../heatingelementchartoverview.component.ts | 31 - .../heatingelement/widget.component.html | 37 - .../heatingelement/widget.component.ts | 77 -- .../app/edge/history/history.component.html | 5 +- ui/src/app/edge/history/history.component.ts | 11 +- ui/src/app/edge/history/history.module.ts | 11 +- .../edge/live/common/consumption/flat/flat.ts | 7 +- .../live/common/consumption/modal/modal.ts | 7 +- ui/src/app/edge/live/live.component.html | 1 - .../settings/alerting/alerting.component.html | 2 +- .../edge/settings/app/index.component.html | 2 +- .../edge/settings/app/install.component.html | 1 - .../edge/settings/app/single.component.html | 1 - .../edge/settings/app/update.component.html | 1 - .../settings/channels/channels.component.html | 1 - .../component/install/index.component.html | 1 - .../component/install/install.component.html | 1 - .../component/update/index.component.html | 1 - .../component/update/update.component.html | 1 - .../settings/jsonrpctest/jsonrpctest.html | 1 - .../settings/network/network.component.html | 1 - .../powerassistant/powerassistant.html | 2 +- .../profile/aliasupdate.component.html | 1 - .../settings/profile/profile.component.html | 1 - .../app/edge/settings/settings.component.html | 1 - ui/src/app/edge/settings/settings.module.ts | 1 - .../settings/system/system.component.html | 1 - .../systemexecute.component.html | 1 - .../systemlog/systemlog.component.html | 1 - ui/src/app/index/login.component.ts | 11 +- .../index/overview/overview.component.html | 1 - .../app/index/overview/overview.component.ts | 10 +- .../components/chart/abstracthistorychart.ts | 37 +- .../components/chart/chart.constants.spec.ts | 12 +- .../components/chart/chart.constants.ts | 60 +- ui/src/app/shared/components/edge/edge.ts | 2 +- .../app/shared/components/edge/edgeconfig.ts | 48 +- .../flat-widget-percentagebar.ts | 7 +- .../shared/components/header/app-header.ts | 222 +++++ .../components/header/header.component.html | 9 +- .../components/header/header.component.ts | 11 +- .../components/shared/testing/common.ts | 21 +- .../components/shared/testing/tester.ts | 11 +- ui/src/app/shared/ngrx-store/states.ts | 19 +- ui/src/app/shared/service/arrayutils.ts | 27 - .../app/shared/service/defaulttypes.spec.ts | 17 + ui/src/app/shared/service/defaulttypes.ts | 25 + ui/src/app/shared/service/utils.ts | 14 +- ui/src/app/shared/shared.module.ts | 72 +- ui/src/app/shared/utils/array/array.utils.ts | 19 +- .../app/shared/utils/object/object.utils.ts | 8 + ui/src/app/user/user.component.html | 1 - ui/src/assets/i18n/de.json | 5 +- ui/src/assets/i18n/en.json | 7 +- 399 files changed, 8998 insertions(+), 9086 deletions(-) create mode 100644 io.openems.common/src/io/openems/common/timedata/XlsxExportDetailData.java create mode 100644 io.openems.common/src/io/openems/common/timedata/XlsxExportUtil.java create mode 100644 io.openems.common/src/io/openems/common/timedata/XlsxWorksheetWrapper.java create mode 100644 io.openems.common/src/io/openems/common/types/CurrencyConfig.java create mode 100644 io.openems.common/test/io/openems/common/jsonrpc/response/CreateXlxsTest.java delete mode 100644 io.openems.edge.common/src/io/openems/edge/common/currency/CurrencyConfig.java rename io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/{MyControllerTest.java => ControllerFastFrequencyReserveImplTest.java} (51%) rename io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/{MyControllerTest2.java => ControllerFastFrequencyReserveImplTest2.java} (53%) delete mode 100644 io.openems.edge.ess.byd.container/test/io/openems/edge/ess/byd/container/watchdog/EssFeneconBydContainerWatchdogControllerImplTest.java delete mode 100644 io.openems.edge.ess.byd.container/test/io/openems/edge/ess/byd/container/watchdog/MyEssConfig.java delete mode 100644 io.openems.edge.ess.byd.container/test/io/openems/edge/ess/byd/container/watchdog/MyWatchdogConfig.java create mode 100644 io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/DeprecatedEvcs.java create mode 100644 io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/PhaseRotation.java delete mode 100644 io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/HardyBarthApi.java create mode 100644 io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/HardyBarthReadUtils.java delete mode 100644 io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/HardyBarthReadWorker.java create mode 100644 io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/HardyBarthWriteHandler.java create mode 100644 io.openems.edge.io.api/src/io/openems/edge/io/test/DummyCustomInputOutput.java create mode 100644 io.openems.edge.simulator/src/io/openems/edge/simulator/datasource/api/DummyDatasource.java create mode 100644 package-lock.json create mode 100644 ui/.project create mode 100644 ui/src/app/edge/history/Controller/Io/heatingelement/chart/chart.ts create mode 100644 ui/src/app/edge/history/Controller/Io/heatingelement/flat/flat.html create mode 100644 ui/src/app/edge/history/Controller/Io/heatingelement/flat/flat.ts create mode 100644 ui/src/app/edge/history/Controller/Io/heatingelement/heatingelement.module.ts create mode 100644 ui/src/app/edge/history/Controller/Io/heatingelement/overview/overview.html create mode 100644 ui/src/app/edge/history/Controller/Io/heatingelement/overview/overview.ts delete mode 100644 ui/src/app/edge/history/heatingelement/chart.component.ts delete mode 100644 ui/src/app/edge/history/heatingelement/heatingelementchartoverview/heatingelementchartoverview.component.html delete mode 100644 ui/src/app/edge/history/heatingelement/heatingelementchartoverview/heatingelementchartoverview.component.ts delete mode 100644 ui/src/app/edge/history/heatingelement/widget.component.html delete mode 100644 ui/src/app/edge/history/heatingelement/widget.component.ts create mode 100644 ui/src/app/shared/components/header/app-header.ts delete mode 100644 ui/src/app/shared/service/arrayutils.ts create mode 100644 ui/src/app/shared/service/defaulttypes.spec.ts create mode 100644 ui/src/app/shared/utils/object/object.utils.ts diff --git a/.gradle-wrapper/gradle-wrapper.properties b/.gradle-wrapper/gradle-wrapper.properties index 0aaefbcaf0f..df97d72b8b9 100644 --- a/.gradle-wrapper/gradle-wrapper.properties +++ b/.gradle-wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/io.openems.backend.core/src/io/openems/backend/core/jsonrpcrequesthandler/EdgeRpcRequestHandler.java b/io.openems.backend.core/src/io/openems/backend/core/jsonrpcrequesthandler/EdgeRpcRequestHandler.java index c98e855c17d..5c4e6ef0109 100644 --- a/io.openems.backend.core/src/io/openems/backend/core/jsonrpcrequesthandler/EdgeRpcRequestHandler.java +++ b/io.openems.backend.core/src/io/openems/backend/core/jsonrpcrequesthandler/EdgeRpcRequestHandler.java @@ -5,8 +5,12 @@ import static io.openems.common.utils.JsonUtils.getAsString; import static java.util.Collections.emptyMap; +import java.io.IOException; +import java.time.temporal.ChronoUnit; +import java.util.Collections; import java.util.Map; import java.util.Optional; +import java.util.TreeSet; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -15,6 +19,7 @@ import io.openems.backend.common.metadata.User; import io.openems.common.exceptions.OpenemsError; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.exceptions.OpenemsException; import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; import io.openems.common.jsonrpc.request.AppCenterRequest; import io.openems.common.jsonrpc.request.ComponentJsonApiRequest; @@ -29,7 +34,13 @@ import io.openems.common.jsonrpc.response.QueryHistoricTimeseriesDataResponse; import io.openems.common.jsonrpc.response.QueryHistoricTimeseriesEnergyPerPeriodResponse; import io.openems.common.jsonrpc.response.QueryHistoricTimeseriesEnergyResponse; +import io.openems.common.jsonrpc.response.QueryHistoricTimeseriesExportXlsxResponse; +import io.openems.common.session.Language; import io.openems.common.session.Role; +import io.openems.common.timedata.Resolution; +import io.openems.common.timedata.XlsxExportDetailData.XlsxExportDataEntry.HistoricTimedataSaveType; +import io.openems.common.timedata.XlsxExportUtil; +import io.openems.common.types.ChannelAddress; public class EdgeRpcRequestHandler { @@ -265,8 +276,38 @@ private CompletableFuture handleQueryHistoricEnergyPerPe */ private CompletableFuture handleQueryHistoricTimeseriesExportXlxsRequest(String edgeId, User user, QueryHistoricTimeseriesExportXlxsRequest request) throws OpenemsNamedException { - return CompletableFuture.completedFuture(this.parent.timedataManager - .handleQueryHistoricTimeseriesExportXlxsRequest(edgeId, request, user.getLanguage())); + return CompletableFuture.completedFuture( + this.handleQueryHistoricTimeseriesExportXlxsRequest(edgeId, request, user.getLanguage())); + } + + private QueryHistoricTimeseriesExportXlsxResponse handleQueryHistoricTimeseriesExportXlxsRequest(String edgeId, + QueryHistoricTimeseriesExportXlxsRequest request, Language language) throws OpenemsNamedException { + final var powerChannels = new TreeSet(QueryHistoricTimeseriesExportXlsxResponse.POWER_CHANNELS); + final var energyChannels = new TreeSet( + QueryHistoricTimeseriesExportXlsxResponse.ENERGY_CHANNELS); + + final var edge = this.parent.metadata.edge().getEdgeConfig(edgeId); + + final var detailData = XlsxExportUtil.getDetailData(edge); + final var channelsByType = detailData.getChannelsBySaveType(); + powerChannels.addAll(channelsByType.getOrDefault(HistoricTimedataSaveType.POWER, Collections.emptyList())); + energyChannels.addAll(channelsByType.getOrDefault(HistoricTimedataSaveType.ENERGY, Collections.emptyList())); + + var powerData = this.parent.timedataManager.queryHistoricData(edgeId, request.getFromDate(), + request.getToDate(), powerChannels, new Resolution(15, ChronoUnit.MINUTES)); + + var energyData = this.parent.timedataManager.queryHistoricEnergy(edgeId, request.getFromDate(), + request.getToDate(), energyChannels); + if (powerData == null || energyData == null) { + return null; + } + try { + return new QueryHistoricTimeseriesExportXlsxResponse(request.getId(), edgeId, request.getFromDate(), + request.getToDate(), powerData, energyData, language, detailData); + + } catch (IOException e) { + throw new OpenemsException("QueryHistoricTimeseriesExportXlxsRequest failed: " + e.getMessage()); + } } /** diff --git a/io.openems.common/resources/templates/controller/$testSrcDir$/$basePackageDir$/MyControllerTest.java b/io.openems.common/resources/templates/controller/$testSrcDir$/$basePackageDir$/MyControllerTest.java index 2205624e13f..41b5f380e43 100644 --- a/io.openems.common/resources/templates/controller/$testSrcDir$/$basePackageDir$/MyControllerTest.java +++ b/io.openems.common/resources/templates/controller/$testSrcDir$/$basePackageDir$/MyControllerTest.java @@ -7,15 +7,14 @@ public class MyControllerTest { - private static final String CTRL_ID = "ctrl0"; - @Test public void test() throws Exception { new ControllerTest(new MyControllerImpl()) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .build()) - .next(new TestCase()); + .setId("ctrl0") // + .build()) // + .next(new TestCase()) // + .deactivate(); } } diff --git a/io.openems.common/resources/templates/device-modbus/$testSrcDir$/$basePackageDir$/MyModbusDeviceTest.java b/io.openems.common/resources/templates/device-modbus/$testSrcDir$/$basePackageDir$/MyModbusDeviceTest.java index c9961ad3a77..eb60ad3df76 100644 --- a/io.openems.common/resources/templates/device-modbus/$testSrcDir$/$basePackageDir$/MyModbusDeviceTest.java +++ b/io.openems.common/resources/templates/device-modbus/$testSrcDir$/$basePackageDir$/MyModbusDeviceTest.java @@ -9,19 +9,17 @@ public class MyModbusDeviceTest { - private static final String COMPONENT_ID = "component0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new MyModbusDeviceImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // - .setModbusId(MODBUS_ID) // - .build()) - .next(new TestCase()); + .setId("component0") // + .setModbusId("modbus0") // + .build()) // + .next(new TestCase()) // + .deactivate(); } } diff --git a/io.openems.common/resources/templates/device/$testSrcDir$/$basePackageDir$/MyDeviceTest.java b/io.openems.common/resources/templates/device/$testSrcDir$/$basePackageDir$/MyDeviceTest.java index d5cb74df7c9..f02eed1d7f9 100644 --- a/io.openems.common/resources/templates/device/$testSrcDir$/$basePackageDir$/MyDeviceTest.java +++ b/io.openems.common/resources/templates/device/$testSrcDir$/$basePackageDir$/MyDeviceTest.java @@ -7,15 +7,14 @@ public class MyDeviceTest { - private static final String COMPONENT_ID = "component0"; - @Test public void test() throws Exception { new ComponentTest(new MyDeviceImpl()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // - .build()) - .next(new TestCase()); + .setId("component0") // + .build()) // + .next(new TestCase()) // + .deactivate(); } } diff --git a/io.openems.common/src/io/openems/common/jsonrpc/response/QueryHistoricTimeseriesExportXlsxResponse.java b/io.openems.common/src/io/openems/common/jsonrpc/response/QueryHistoricTimeseriesExportXlsxResponse.java index 6158477f132..acf64aba840 100644 --- a/io.openems.common/src/io/openems/common/jsonrpc/response/QueryHistoricTimeseriesExportXlsxResponse.java +++ b/io.openems.common/src/io/openems/common/jsonrpc/response/QueryHistoricTimeseriesExportXlsxResponse.java @@ -6,15 +6,19 @@ import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.util.HashSet; +import java.util.List; import java.util.Locale; import java.util.Map.Entry; import java.util.ResourceBundle; import java.util.Set; import java.util.SortedMap; import java.util.UUID; +import java.util.function.BiFunction; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.dhatim.fastexcel.BorderSide; +import org.dhatim.fastexcel.BorderStyle; import org.dhatim.fastexcel.Workbook; import org.dhatim.fastexcel.Worksheet; @@ -22,6 +26,10 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.session.Language; +import io.openems.common.timedata.XlsxExportDetailData; +import io.openems.common.timedata.XlsxExportDetailData.XlsxExportCategory; +import io.openems.common.timedata.XlsxExportDetailData.XlsxExportDataEntry; +import io.openems.common.timedata.XlsxWorksheetWrapper; import io.openems.common.types.ChannelAddress; import io.openems.common.utils.JsonUtils; @@ -60,6 +68,11 @@ protected static class Channel { public static final ChannelAddress ESS_SOC = new ChannelAddress("_sum", "EssSoc"); } + private static final String BLUE = "44B3E1"; + private static final String LIGHT_GREY = "BFBFBF"; + private static final String DARK_GREY = "D9D9D9"; + private static final String FONT_NAME = "Calibri"; + /** * All Power Channels, i.e. Channels that are exported per channel and * timestamp. @@ -91,21 +104,24 @@ protected static class Channel { * While constructing, the actual Excel file is generated as payload of the * JSON-RPC Response. * - * @param id the JSON-RPC ID - * @param edgeId the Edge-ID - * @param fromDate the start date of the export - * @param toDate the end date of the export - * @param historicData the power data per channel and timestamp - * @param historicEnergy the energy data, one value per channel - * @param language the {@link Language} + * @param id the JSON-RPC ID + * @param edgeId the Edge-ID + * @param fromDate the start date of the export + * @param toDate the end date of the export + * @param historicData the power data per channel and timestamp + * @param historicEnergy the energy data, one value per channel + * @param language the {@link Language} + * @param detailComponents the components for the detail view * @throws IOException on error * @throws OpenemsNamedException on error */ public QueryHistoricTimeseriesExportXlsxResponse(UUID id, String edgeId, ZonedDateTime fromDate, ZonedDateTime toDate, SortedMap> historicData, - SortedMap historicEnergy, Language language) - throws IOException, OpenemsNamedException { - super(id, XlsxUtils.generatePayload(edgeId, fromDate, toDate, historicData, historicEnergy, language)); + SortedMap historicEnergy, Language language, + XlsxExportDetailData detailComponents) throws IOException, OpenemsNamedException { + + super(id, XlsxUtils.generatePayload(edgeId, fromDate, toDate, historicData, historicEnergy, language, + detailComponents)); } protected static class XlsxUtils { @@ -118,20 +134,21 @@ protected static class XlsxUtils { * Generates the Payload for a * {@link QueryHistoricTimeseriesExportXlsxResponse}. * - * @param edgeId the Edge-Id - * @param fromDate the start date of the export - * @param toDate the end date of the export - * @param powerData the power data per channel and timestamp - * @param energyData the energy data, one value per channel - * @param language the {@link Language} + * @param edgeId the Edge-Id + * @param fromDate the start date of the export + * @param toDate the end date of the export + * @param powerData the power data per channel and timestamp + * @param energyData the energy data, one value per channel + * @param language the {@link Language} + * @param detailComponents the components for the detail view * @return the Excel file as byte-array. * @throws IOException on error * @throws OpenemsNamedException on error */ private static byte[] generatePayload(String edgeId, ZonedDateTime fromDate, ZonedDateTime toDate, SortedMap> powerData, - SortedMap energyData, Language language) - throws IOException, OpenemsNamedException { + SortedMap energyData, Language language, + XlsxExportDetailData detailComponents) throws IOException, OpenemsNamedException { byte[] payload = {}; try (// var os = new ByteArrayOutputStream(); @@ -146,8 +163,54 @@ private static byte[] generatePayload(String edgeId, ZonedDateTime fromDate, Zon XlsxUtils.addBasicInfo(ws, edgeId, fromDate, toDate, translationBundle); XlsxUtils.addEnergyData(ws, energyData, translationBundle); - XlsxUtils.addPowerData(ws, powerData, translationBundle); + var rowCount = XlsxUtils.addPowerData(ws, powerData, translationBundle); + + final var worksheetWrapper = new XlsxWorksheetWrapper(ws); + + // Box for Total Overview + worksheetWrapper.setForRange(9, 0, 9, 7, t -> t.style().borderStyle(BorderSide.TOP, BorderStyle.THIN)); + worksheetWrapper.setForRange(9, 0, rowCount, 0, + t -> t.style().borderStyle(BorderSide.LEFT, BorderStyle.THIN)); + worksheetWrapper.setForRange(rowCount, 0, rowCount, 7, + t -> t.style().borderStyle(BorderSide.BOTTOM, BorderStyle.THIN)); + worksheetWrapper.setForRange(9, 7, rowCount, 7, + t -> t.style().borderStyle(BorderSide.RIGHT, BorderStyle.THIN)); + + if (detailComponents.data().values().stream().anyMatch(de -> !de.isEmpty())) { // + var rightestColumns = XlsxUtils.addDetailData(ws, powerData, detailComponents, translationBundle, + energyData); + + final var colProd = rightestColumns.get(0) - 1; + final var colCons = rightestColumns.get(1) - 1; + final var colTou = rightestColumns.get(2) - 1; + + // Set Box for detail Timerange data + worksheetWrapper.setForRange(9, 10, 9, colTou, + t -> t.style().borderStyle(BorderSide.TOP, BorderStyle.THIN)); + worksheetWrapper.setForRange(9, 10, rowCount, 10, + t -> t.style().borderStyle(BorderSide.LEFT, BorderStyle.THIN)); + worksheetWrapper.setForRange(rowCount, 10, rowCount, colTou, + t -> t.style().borderStyle(BorderSide.BOTTOM, BorderStyle.THIN)); + worksheetWrapper.setForRange(9, colTou, rowCount, colTou, + t -> t.style().borderStyle(BorderSide.RIGHT, BorderStyle.THIN)); + + // Set Separators between prod, cons and tou + worksheetWrapper.setForRange(9, colProd, rowCount, colProd, + t -> t.style().borderStyle(BorderSide.RIGHT, BorderStyle.THIN)); + worksheetWrapper.setForRange(9, colCons, rowCount, colCons, + t -> t.style().borderStyle(BorderSide.RIGHT, BorderStyle.THIN)); + + // Set "blue" Separator between detailed Overview and total Overview + worksheetWrapper.setForRange(0, 8, rowCount, 8, t -> t.style()// + .borderStyle(BorderSide.LEFT, BorderStyle.MEDIUM)// + .borderStyle(BorderSide.RIGHT, BorderStyle.MEDIUM)// + .fillColor(BLUE)); + worksheetWrapper.getCellWrapper(0, 8).style().borderStyle(BorderSide.TOP, BorderStyle.MEDIUM); + worksheetWrapper.getCellWrapper(rowCount, 8).style().borderStyle(BorderSide.BOTTOM, + BorderStyle.MEDIUM); + } + worksheetWrapper.setAll(); wb.finish(); os.flush(); payload = os.toByteArray(); @@ -199,29 +262,35 @@ protected static void addBasicInfo(Worksheet ws, String edgeId, ZonedDateTime fr */ protected static void addEnergyData(Worksheet ws, SortedMap data, ResourceBundle translationBundle) throws OpenemsNamedException { + ws.range(4, 1, 4, 6).merge(); + ws.value(4, 1, translationBundle.getString("totalOverview")); + ws.range(4, 1, 4, 6).style().fontName(FONT_NAME).fontSize(12).horizontalAlignment("center") + .verticalAlignment("center").bold().fillColor(BLUE).set(); + ws.range(5, 1, 5, 6).style().bold().fillColor(LIGHT_GREY).set(); + ws.range(6, 1, 6, 6).style().fillColor(DARK_GREY).set(); // Grid buy energy - XlsxUtils.addStringValueBold(ws, 4, 1, translationBundle.getString("gridBuy") + " [kWh]"); - XlsxUtils.addKwhValueIfnotNull(ws, 5, 1, data.get(Channel.GRID_BUY_ACTIVE_ENERGY), translationBundle); + XlsxUtils.addStringValueBold(ws, 5, 1, translationBundle.getString("gridBuy") + " [kWh]"); + XlsxUtils.addKwhValueIfnotNull(ws, 6, 1, data.get(Channel.GRID_BUY_ACTIVE_ENERGY), translationBundle); // Grid sell energy - XlsxUtils.addStringValueBold(ws, 4, 2, translationBundle.getString("gridFeedIn") + " [kWh]"); - XlsxUtils.addKwhValueIfnotNull(ws, 5, 2, data.get(Channel.GRID_SELL_ACTIVE_ENERGY), translationBundle); + XlsxUtils.addStringValueBold(ws, 5, 2, translationBundle.getString("gridFeedIn") + " [kWh]"); + XlsxUtils.addKwhValueIfnotNull(ws, 6, 2, data.get(Channel.GRID_SELL_ACTIVE_ENERGY), translationBundle); // Production energy - XlsxUtils.addStringValueBold(ws, 4, 3, translationBundle.getString("production") + " [kWh]"); - XlsxUtils.addKwhValueIfnotNull(ws, 5, 3, data.get(Channel.PRODUCTION_ACTIVE_ENERGY), translationBundle); + XlsxUtils.addStringValueBold(ws, 5, 3, translationBundle.getString("production") + " [kWh]"); + XlsxUtils.addKwhValueIfnotNull(ws, 6, 3, data.get(Channel.PRODUCTION_ACTIVE_ENERGY), translationBundle); // Charge energy - XlsxUtils.addStringValueBold(ws, 4, 4, translationBundle.getString("storageCharging") + " [kWh]"); - XlsxUtils.addKwhValueIfnotNull(ws, 5, 4, data.get(Channel.ESS_DC_CHARGE_ENERGY), translationBundle); + XlsxUtils.addStringValueBold(ws, 5, 4, translationBundle.getString("storageCharging") + " [kWh]"); + XlsxUtils.addKwhValueIfnotNull(ws, 6, 4, data.get(Channel.ESS_DC_CHARGE_ENERGY), translationBundle); // Charge energy - XlsxUtils.addStringValueBold(ws, 4, 5, translationBundle.getString("storageDischarging") + " [kWh]"); - XlsxUtils.addKwhValueIfnotNull(ws, 5, 5, data.get(Channel.ESS_DC_DISCHARGE_ENERGY), translationBundle); + XlsxUtils.addStringValueBold(ws, 5, 5, translationBundle.getString("storageDischarging") + " [kWh]"); + XlsxUtils.addKwhValueIfnotNull(ws, 6, 5, data.get(Channel.ESS_DC_DISCHARGE_ENERGY), translationBundle); // Consumption energy - XlsxUtils.addStringValueBold(ws, 4, 6, translationBundle.getString("consumption") + " [kWh]"); - XlsxUtils.addKwhValueIfnotNull(ws, 5, 6, data.get(Channel.CONSUMPTION_ACTIVE_ENERGY), translationBundle); + XlsxUtils.addStringValueBold(ws, 5, 6, translationBundle.getString("consumption") + " [kWh]"); + XlsxUtils.addKwhValueIfnotNull(ws, 6, 6, data.get(Channel.CONSUMPTION_ACTIVE_ENERGY), translationBundle); } /** @@ -230,22 +299,24 @@ protected static void addEnergyData(Worksheet ws, SortedMap> data, ResourceBundle translationBundle) throws OpenemsNamedException { // Adding the headers - XlsxUtils.addStringValueBold(ws, 7, 0, translationBundle.getString("date/time")); - XlsxUtils.addStringValueBold(ws, 7, 1, translationBundle.getString("gridBuy") + " [W]"); - XlsxUtils.addStringValueBold(ws, 7, 2, translationBundle.getString("gridFeedIn") + " [W]"); - XlsxUtils.addStringValueBold(ws, 7, 3, translationBundle.getString("production") + " [W]"); - XlsxUtils.addStringValueBold(ws, 7, 4, translationBundle.getString("storageCharging") + " [W]"); - XlsxUtils.addStringValueBold(ws, 7, 5, translationBundle.getString("storageDischarging") + " [W]"); - XlsxUtils.addStringValueBold(ws, 7, 6, translationBundle.getString("consumption") + " [W]"); - XlsxUtils.addStringValueBold(ws, 7, 7, translationBundle.getString("stateOfCharge") + " [%]"); - - var rowCount = 8; + XlsxUtils.addStringValueBold(ws, 9, 0, translationBundle.getString("date/time")); + XlsxUtils.addStringValueBold(ws, 9, 1, translationBundle.getString("gridBuy") + " [W]"); + XlsxUtils.addStringValueBold(ws, 9, 2, translationBundle.getString("gridFeedIn") + " [W]"); + XlsxUtils.addStringValueBold(ws, 9, 3, translationBundle.getString("production") + " [W]"); + XlsxUtils.addStringValueBold(ws, 9, 4, translationBundle.getString("storageCharging") + " [W]"); + XlsxUtils.addStringValueBold(ws, 9, 5, translationBundle.getString("storageDischarging") + " [W]"); + XlsxUtils.addStringValueBold(ws, 9, 6, translationBundle.getString("consumption") + " [W]"); + XlsxUtils.addStringValueBold(ws, 9, 7, translationBundle.getString("stateOfCharge") + " [%]"); + XlsxUtils.addStringValueBold(ws, 8, 1, translationBundle.getString("generalData")); + + var rowCount = 10; for (Entry> row : data.entrySet()) { var values = row.getValue(); @@ -267,12 +338,17 @@ protected static void addPowerData(Worksheet ws, // Grid sell power XlsxUtils.addFloatValue(ws, rowCount, 2, gridActivePower / -1); } + } else { + XlsxUtils.addStringValue(ws, rowCount, 1, "-"); + XlsxUtils.addStringValue(ws, rowCount, 2, "-"); } // Production power if (XlsxUtils.isNotNull(values.get(Channel.PRODUCTION_ACTIVE_POWER))) { XlsxUtils.addFloatValue(ws, rowCount, 3, JsonUtils.getAsFloat(values.get(Channel.PRODUCTION_ACTIVE_POWER))); + } else { + XlsxUtils.addStringValue(ws, rowCount, 3, "-"); } if (XlsxUtils.isNotNull(values.get(Channel.ESS_DISCHARGE_POWER))) { @@ -284,19 +360,120 @@ protected static void addPowerData(Worksheet ws, XlsxUtils.addFloatValue(ws, rowCount, 4, essDischargePower / -1); XlsxUtils.addFloatValue(ws, rowCount, 5, 0); } + } else { + XlsxUtils.addStringValue(ws, rowCount, 4, "-"); + XlsxUtils.addStringValue(ws, rowCount, 5, "-"); } // Consumption power if (XlsxUtils.isNotNull(values.get(Channel.CONSUMPTION_ACTIVE_POWER))) { XlsxUtils.addFloatValue(ws, rowCount, 6, JsonUtils.getAsFloat(values.get(Channel.CONSUMPTION_ACTIVE_POWER))); + } else { + XlsxUtils.addStringValue(ws, rowCount, 6, "-"); } // State of charge if (XlsxUtils.isNotNull(values.get(Channel.ESS_SOC))) { XlsxUtils.addFloatValue(ws, rowCount, 7, JsonUtils.getAsFloat(values.get(Channel.ESS_SOC))); + } else { + XlsxUtils.addStringValue(ws, rowCount, 7, "-"); } rowCount++; } + rowCount--; + return rowCount; + } + + protected static List addDetailData(Worksheet ws, + SortedMap> data, + XlsxExportDetailData detailComponents, ResourceBundle translationBundle, + SortedMap energyData) throws OpenemsNamedException { + ws.width(8, 4); + ws.width(9, 4); + ws.width(10, 25); + ws.width(11, 25); + ws.width(12, 25); + ws.width(13, 25); + ws.width(14, 25); + ws.width(15, 25); + + ws.range(4, 10, 4, 15).merge(); + ws.range(4, 10, 4, 15).style().fontName(FONT_NAME).fontSize(12).bold().fillColor(BLUE).set(); + ws.value(4, 10, translationBundle.getString("detailData")); + ws.range(5, 10, 5, 15).merge(); + ws.range(5, 10, 5, 15).style().fillColor(LIGHT_GREY).set(); + ws.value(5, 10, translationBundle.getString("detailHint")); + var rightestColumn1 = addProductionData(ws, data, detailComponents, translationBundle); + var rightestColumn2 = addConsumptionData(ws, data, detailComponents, rightestColumn1, translationBundle); + var rightestColumn3 = addTimeOfUseTariffData(ws, data, detailComponents, rightestColumn2, + translationBundle); + ws.width(rightestColumn3, 35); + return List.of(rightestColumn1, rightestColumn2, rightestColumn3); + } + + protected static int addProductionData(Worksheet ws, + SortedMap> data, + XlsxExportDetailData detailComponents, ResourceBundle translationBundle) throws OpenemsNamedException { + return XlsxUtils.addGenericData(ws, data, detailComponents, 10, translationBundle, + XlsxExportCategory.PRODUCTION, "production", (t, d) -> t.alias() + " [W]", 1); + } + + protected static int addConsumptionData(Worksheet ws, + SortedMap> data, + XlsxExportDetailData detailComponents, int righestColumn, ResourceBundle translationBundle) + throws OpenemsNamedException { + return XlsxUtils.addGenericData(ws, data, detailComponents, righestColumn, translationBundle, + XlsxExportCategory.CONSUMPTION, "consumption", (t, d) -> t.alias() + " [W]", 1); + } + + protected static int addTimeOfUseTariffData(Worksheet ws, + SortedMap> data, + XlsxExportDetailData detailComponents, int righestColumn, ResourceBundle translationBundle) + throws OpenemsNamedException { + final var unit = "[" + detailComponents.currency().getUnderPart() + "/kWh]"; + return XlsxUtils.addGenericData(ws, data, detailComponents, righestColumn, translationBundle, + XlsxExportCategory.TIME_OF_USE_TARIFF, "timeOfUse", (t, d) -> t.alias() + " " + unit, + 1000f / detailComponents.currency().getRatio()); + } + + protected static int addGenericData(// + Worksheet ws, // + SortedMap> data, // + XlsxExportDetailData detailComponents, // + int righestColumn, // + ResourceBundle translationBundle, // + XlsxExportDetailData.XlsxExportCategory category, // + String translationKey, // + BiFunction aliasBuilder, // + float ratio) // + throws OpenemsNamedException { + + final var righestColumnOld = righestColumn; + + for (var item : detailComponents.data().get(category)) { + ws.value(8, righestColumnOld, translationBundle.getString(translationKey)); + ws.style(8, righestColumnOld).bold().set(); + + ws.value(9, righestColumn, aliasBuilder.apply(item, detailComponents)); + ws.style(9, righestColumn).bold().set(); + + var rowCount = 10; + for (final var row : data.entrySet()) { + final var values = row.getValue(); + final var channelAddress = item.channel(); + + if (XlsxUtils.isNotNull(values.get(channelAddress))) { + XlsxUtils.addFloatValueNotRounded(ws, rowCount, righestColumn, + JsonUtils.getAsFloat(values.get(channelAddress)) / ratio); + } else { + XlsxUtils.addStringValue(ws, rowCount, righestColumn, "-"); + } + rowCount++; + } + righestColumn++; + } + + return righestColumn; } /** @@ -385,6 +562,19 @@ protected static void addFloatValue(Worksheet ws, int row, int col, float value) ws.value(row, col, Math.round(value)); } + /** + * Helper method to add the value to the excel sheet. The float value is + * mathematically rounded. + * + * @param ws the {@link Worksheet} + * @param row row number + * @param col column number + * @param value actual value in the sheet + */ + protected static void addFloatValueNotRounded(Worksheet ws, int row, int col, float value) { + ws.value(row, col, value); + } + /** * Simple helper method to check for null values. * diff --git a/io.openems.common/src/io/openems/common/jsonrpc/response/translation_de.properties b/io.openems.common/src/io/openems/common/jsonrpc/response/translation_de.properties index 1ac1c7f1860..4fdcc640291 100644 --- a/io.openems.common/src/io/openems/common/jsonrpc/response/translation_de.properties +++ b/io.openems.common/src/io/openems/common/jsonrpc/response/translation_de.properties @@ -8,4 +8,9 @@ storageDischarging = Speicher Entladung consumption = Verbrauch stateOfCharge = Ladezustand date/time = Datum / Uhrzeit -notAvailable = nicht vorhanden \ No newline at end of file +notAvailable = nicht vorhanden +detailData = Detaillierte Auswertung der Erzeuger, Verbraucher und Apps +detailHint = * Bitte beachten Sie, dass diese Werte bereits in den Leistungsdaten in Ihrer Gesamtbersicht enthalten sind. +timeOfUse = Dynamischer Stromtarif +totalOverview = Gesamtbersicht +generalData = Allgemeine Daten \ No newline at end of file diff --git a/io.openems.common/src/io/openems/common/jsonrpc/response/translation_en.properties b/io.openems.common/src/io/openems/common/jsonrpc/response/translation_en.properties index 4da846d76c2..40f8fc4d09a 100644 --- a/io.openems.common/src/io/openems/common/jsonrpc/response/translation_en.properties +++ b/io.openems.common/src/io/openems/common/jsonrpc/response/translation_en.properties @@ -8,4 +8,9 @@ storageDischarging = Storage Discharging consumption = Consumption stateOfCharge = State of Charge date/time = Date / Time -notAvailable = not available \ No newline at end of file +notAvailable = not available +detailData = Detailed evaluation of the producer, consumer and apps +detailHint = * Please note that these values are already included in the performance data in your Total Overview. +timeOfUse = Time of Use Tariff +totalOverview = Total Overview +generalData = General Data \ No newline at end of file diff --git a/io.openems.common/src/io/openems/common/timedata/CommonTimedataService.java b/io.openems.common/src/io/openems/common/timedata/CommonTimedataService.java index fdebd1f183c..097f7c5aad9 100644 --- a/io.openems.common/src/io/openems/common/timedata/CommonTimedataService.java +++ b/io.openems.common/src/io/openems/common/timedata/CommonTimedataService.java @@ -1,6 +1,5 @@ package io.openems.common.timedata; -import java.io.IOException; import java.time.Period; import java.time.ZonedDateTime; import java.time.temporal.ChronoUnit; @@ -10,46 +9,11 @@ import com.google.gson.JsonElement; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.exceptions.OpenemsException; import io.openems.common.jsonrpc.request.QueryHistoricTimeseriesDataRequest; -import io.openems.common.jsonrpc.request.QueryHistoricTimeseriesExportXlxsRequest; -import io.openems.common.jsonrpc.response.QueryHistoricTimeseriesExportXlsxResponse; -import io.openems.common.session.Language; import io.openems.common.types.ChannelAddress; public interface CommonTimedataService { - /** - * Handles a {@link QueryHistoricTimeseriesExportXlxsRequest}. Exports historic - * data to an Excel file. - * - * @param edgeId the Edge-ID - * @param request the {@link QueryHistoricTimeseriesExportXlxsRequest} request - * @param language the {@link Language} - * @return the {@link QueryHistoricTimeseriesExportXlsxResponse} - * @throws OpenemsNamedException on error - */ - public default QueryHistoricTimeseriesExportXlsxResponse handleQueryHistoricTimeseriesExportXlxsRequest( - String edgeId, QueryHistoricTimeseriesExportXlxsRequest request, Language language) - throws OpenemsNamedException { - var powerData = this.queryHistoricData(edgeId, request.getFromDate(), request.getToDate(), - QueryHistoricTimeseriesExportXlsxResponse.POWER_CHANNELS, new Resolution(15, ChronoUnit.MINUTES)); - - var energyData = this.queryHistoricEnergy(edgeId, request.getFromDate(), request.getToDate(), - QueryHistoricTimeseriesExportXlsxResponse.ENERGY_CHANNELS); - - if (powerData == null || energyData == null) { - return null; - } - - try { - return new QueryHistoricTimeseriesExportXlsxResponse(request.getId(), edgeId, request.getFromDate(), - request.getToDate(), powerData, energyData, language); - } catch (IOException e) { - throw new OpenemsException("QueryHistoricTimeseriesExportXlxsRequest failed: " + e.getMessage()); - } - } - /** * Calculates the time {@link Resolution} for the period. * diff --git a/io.openems.common/src/io/openems/common/timedata/XlsxExportDetailData.java b/io.openems.common/src/io/openems/common/timedata/XlsxExportDetailData.java new file mode 100644 index 00000000000..199bc345846 --- /dev/null +++ b/io.openems.common/src/io/openems/common/timedata/XlsxExportDetailData.java @@ -0,0 +1,37 @@ +package io.openems.common.timedata; + +import java.util.EnumMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import io.openems.common.timedata.XlsxExportDetailData.XlsxExportDataEntry.HistoricTimedataSaveType; +import io.openems.common.types.ChannelAddress; +import io.openems.common.types.CurrencyConfig; + +public record XlsxExportDetailData(// + EnumMap> data, // + CurrencyConfig currency +) { + + public Map> getChannelsBySaveType() { + return this.data().values().stream().flatMap(List::stream).collect(Collectors.groupingBy( + XlsxExportDataEntry::type, Collectors.mapping(XlsxExportDataEntry::channel, Collectors.toList()))); + } + + public enum XlsxExportCategory { + CONSUMPTION, PRODUCTION, TIME_OF_USE_TARIFF + } + + public record XlsxExportDataEntry(// + String alias, ChannelAddress channel, // + HistoricTimedataSaveType type // + ) { + + public enum HistoricTimedataSaveType { + POWER, ENERGY + } + + } + +} diff --git a/io.openems.common/src/io/openems/common/timedata/XlsxExportUtil.java b/io.openems.common/src/io/openems/common/timedata/XlsxExportUtil.java new file mode 100644 index 00000000000..a1f290bf48b --- /dev/null +++ b/io.openems.common/src/io/openems/common/timedata/XlsxExportUtil.java @@ -0,0 +1,112 @@ +package io.openems.common.timedata; + +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; +import java.util.Set; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.timedata.XlsxExportDetailData.XlsxExportCategory; +import io.openems.common.timedata.XlsxExportDetailData.XlsxExportDataEntry; +import io.openems.common.types.ChannelAddress; +import io.openems.common.types.CurrencyConfig; +import io.openems.common.types.EdgeConfig; +import io.openems.common.utils.JsonUtils; + +public class XlsxExportUtil { + + /** + * Gathers the detail data for excel export. + * + * @param edge the edge + * @return the currency represented as a CurrencyConfig + * @throws OpenemsNamedException if component isnt found + */ + private static CurrencyConfig getCurrency(EdgeConfig edge) throws OpenemsNamedException { + return edge.getComponent("_meta") // + .flatMap(t -> t.getProperty("currency")) // + .flatMap(t -> JsonUtils.getAsOptionalEnum(CurrencyConfig.class, t)) // + .orElse(CurrencyConfig.EUR); + } + + /** + * Gathers the detail data for excel export. + * + * @param edge the edge + * @return the detailData + * @throws OpenemsNamedException if component isnt found + */ + public static XlsxExportDetailData getDetailData(EdgeConfig edge) throws OpenemsNamedException { + final var enumMap = new EnumMap>(XlsxExportCategory.class); + final var consumption = new ArrayList(); + final var production = new ArrayList(); + final var tou = new ArrayList(); + + enumMap.put(XlsxExportCategory.PRODUCTION, production); + enumMap.put(XlsxExportCategory.CONSUMPTION, consumption); + enumMap.put(XlsxExportCategory.TIME_OF_USE_TARIFF, tou); + + for (var component : edge.getComponents().values()) { + final var natures = edge.getFactories().get(component.getFactoryId()).getNatureIds(); + for (var nature : natures) { + // Electricity meter + switch (nature) { + case Natures.METER -> { + final var props = component.getProperties(); + if (props.keySet().contains("type")) { + if (props.get("type").getAsString().equals("PRODUCTION")) { + production.add(new XlsxExportDataEntry(component.getAlias(), + new ChannelAddress(component.getId(), "ActivePower"), + XlsxExportDataEntry.HistoricTimedataSaveType.POWER)); + } else if (props.get("type").getAsString().equals("CONSUMPTION_NOT_METERED") + || props.get("type").getAsString().equals("CONSUMPTION_METERED")) { + consumption.add(new XlsxExportDataEntry(component.getAlias(), + new ChannelAddress(component.getId(), "ActivePower"), + XlsxExportDataEntry.HistoricTimedataSaveType.POWER)); + } + continue; + } + final var type = getActivePowerType(component.getFactoryId()); + if (type == null) { + continue; + } + enumMap.get(type) + .add(new XlsxExportDataEntry(component.getAlias(), + new ChannelAddress(component.getId(), "ActivePower"), + XlsxExportDataEntry.HistoricTimedataSaveType.POWER)); + } + case Natures.TIME_OF_USE_TARIFF -> { + tou.add(new XlsxExportDataEntry(component.getAlias(), new ChannelAddress("_sum", "GridBuyPrice"), + XlsxExportDataEntry.HistoricTimedataSaveType.POWER)); + } + } + } + } + return new XlsxExportDetailData(enumMap, XlsxExportUtil.getCurrency(edge)); + } + + private static XlsxExportCategory getActivePowerType(String factoryId) { + if (Natures.PRODUCTION_NATURES.contains(factoryId)) { + return XlsxExportCategory.PRODUCTION; + } else if (Natures.CONSUMPTION_NATURES.contains(factoryId)) { + return XlsxExportCategory.CONSUMPTION; + } + return null; + } + + private static final class Natures { + public static final String METER = "io.openems.edge.meter.api.ElectricityMeter"; + public static final String TIME_OF_USE_TARIFF = "io.openems.edge.timeofusetariff.api.TimeOfUseTariff"; + public static final Set PRODUCTION_NATURES = Set.of("Simulator.PvInverter", "Fenecon.Dess.PvMeter", + "Fenecon.Mini.PvMeter", "Kaco.BlueplanetHybrid10.PvInverter", "PvInverter.Cluster", + "PV-Inverter.Fronius", "PV-Inverter.KACO.blueplanet", "PV-Inverter.SMA.SunnyTripower", + "PV-Inverter.Kostal", "PV-Inverter.Solarlog", "Simulator.ProductionMeter.Acting", + "SolarEdge.PV-Inverter"); + + public static final Set CONSUMPTION_NATURES = Set.of("GoodWe.EmergencyPowerMeter", + "Simulator.NRCMeter.Acting", "Evcs.AlpitronicHypercharger", "Evcs.Dezony", "Evcs.Goe.ChargerHome", + "Evcs.HardyBarth", "Evcs.Keba.KeContact", "Evcs.Ocpp.Abl", "Evcs.Ocpp.IesKeywattSingle", + "Evcs.Spelsberg.SMART", "Evcs.Webasto.Next","Evcs.Webasto.Unite"); + } + +} diff --git a/io.openems.common/src/io/openems/common/timedata/XlsxWorksheetWrapper.java b/io.openems.common/src/io/openems/common/timedata/XlsxWorksheetWrapper.java new file mode 100644 index 00000000000..faec99a684a --- /dev/null +++ b/io.openems.common/src/io/openems/common/timedata/XlsxWorksheetWrapper.java @@ -0,0 +1,46 @@ +package io.openems.common.timedata; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Consumer; + +import org.dhatim.fastexcel.StyleSetter; +import org.dhatim.fastexcel.Worksheet; + +public class XlsxWorksheetWrapper { + public record XlsxCellWrapper(int c, int r, StyleSetter style) { + } + + private final Map> cellMap = new HashMap<>(); + private final Worksheet ws; + + public XlsxWorksheetWrapper(Worksheet ws) { + this.ws = ws; + } + + /** + * Gets a CellWrapper if exists; otherwise creates a new one and returns that. + * + * @param r row of the cell + * @param c column of the cell + * @return the XlsxCellWrapper + */ + public XlsxCellWrapper getCellWrapper(int r, int c) { + final var columns = this.cellMap.computeIfAbsent(r, row -> new HashMap<>()); + return columns.computeIfAbsent(c, col -> new XlsxCellWrapper(r, c, this.ws.style(r, c))); + } + + public void setAll() { + this.cellMap.values().stream().flatMap(map -> map.values().stream()).forEach(val -> val.style().set()); + } + + public void setForRange(int r1, int c1, int r2, int c2, Consumer styleSetterFunc) { + for (int row = r1; row <= r2; row++) { + for (int col = c1; col <= c2; col++) { + var cell = this.getCellWrapper(row, col); + styleSetterFunc.accept(cell);; + } + } + } + +} \ No newline at end of file diff --git a/io.openems.common/src/io/openems/common/types/CurrencyConfig.java b/io.openems.common/src/io/openems/common/types/CurrencyConfig.java new file mode 100644 index 00000000000..8c401aefda3 --- /dev/null +++ b/io.openems.common/src/io/openems/common/types/CurrencyConfig.java @@ -0,0 +1,49 @@ +package io.openems.common.types; + +import java.util.Currency; + +/** + * The {@link ChannelId#CURRENCY} mandates the selection of the 'currency' + * configuration property of this specific type. Subsequently, this selected + * property is transformed into the corresponding {@link Currency} type before + * being written through {@link Meta#_setCurrency(Currency)}. + */ +public enum CurrencyConfig { + /** + * Euro. + */ + EUR("€", "Cent", 100f), + /** + * Swedish Krona. + */ + SEK("kr", "Öre", 100f), + /** + * Swiss Francs. + */ + CHF("Fr", "Rappen", 100f); + + private final String symbol; + + private final String underPart; + + private final float ratio; + + private CurrencyConfig(String symbol, String underPart, float ratio) { + this.symbol = symbol; + this.underPart = underPart; + this.ratio = ratio; + } + + public String getSymbol() { + return this.symbol; + } + + public String getUnderPart() { + return this.underPart; + } + + public float getRatio() { + return this.ratio; + } + +} diff --git a/io.openems.common/src/io/openems/common/types/EdgeConfig.java b/io.openems.common/src/io/openems/common/types/EdgeConfig.java index 1a7ad131b23..ce24afa90ed 100644 --- a/io.openems.common/src/io/openems/common/types/EdgeConfig.java +++ b/io.openems.common/src/io/openems/common/types/EdgeConfig.java @@ -588,8 +588,7 @@ public static Component fromJson(String componentId, JsonElement json) throws Op var jPropertiesOpt = JsonUtils.getAsOptionalJsonObject(json, "properties"); if (jPropertiesOpt.isPresent()) { for (Entry entry : jPropertiesOpt.get().entrySet()) { - if (!ignorePropertyKey(entry.getKey()) - && !ignoreComponentPropertyKey(componentId, entry.getKey())) { + if (!ignorePropertyKey(entry.getKey())) { properties.put(entry.getKey(), entry.getValue()); } } @@ -1171,9 +1170,9 @@ public TreeMap getFactories() { } /** - * Builds the {@link ActualEdgeConfig}. + * Builds the ActualEdgeConfig. * - * @return {@link ActualEdgeConfig} + * @return ActualEdgeConfig */ public ActualEdgeConfig build() { return new ActualEdgeConfig(ImmutableSortedMap.copyOf(this.getComponents()), @@ -1191,9 +1190,9 @@ public EdgeConfig buildEdgeConfig() { } /** - * Creates an empty {@link ActualEdgeConfig}. + * Creates an empty ActualEdgeConfig. * - * @return {@link ActualEdgeConfig} + * @return ActualEdgeConfig */ public static ActualEdgeConfig empty() { return ActualEdgeConfig.create().build(); @@ -1248,9 +1247,9 @@ public static EdgeConfig fromJson(JsonObject json) { private volatile JsonObject _json = null; /** - * Build from {@link ActualEdgeConfig}. + * Build from ActualEdgeConfig. * - * @param actual the {@link ActualEdgeConfig} + * @param actual the ActualEdgeConfig */ private EdgeConfig(ActualEdgeConfig actual) { this._actual = actual; @@ -1261,10 +1260,10 @@ private EdgeConfig(JsonObject json) { } /** - * Gets the {@link ActualEdgeConfig}. Either by parsing it from {@link #json} or - * by returning from cache. + * Gets the ActualEdgeConfig. Either by parsing it from {@link #json} or by + * returning from cache. * - * @return {@link ActualEdgeConfig}; empty on JSON parse error + * @return ActualEdgeConfig; empty on JSON parse error */ private synchronized ActualEdgeConfig getActual() { if (this._actual != null) { @@ -1465,25 +1464,4 @@ public static boolean ignorePropertyKey(String key) { default -> false; }; } - - /** - * Internal Method to decide whether a configuration property should be ignored. - * - * @param componentId the Component-ID - * @param key the property key - * @return true if it should get ignored - */ - public static boolean ignoreComponentPropertyKey(String componentId, String key) { - return switch (componentId) { - // Filter for _sum component - case "_sum" -> switch (key) { - case "productionMaxActivePower", "consumptionMaxActivePower", "gridMinActivePower", "gridMaxActivePower" -> - true; - - default -> false; - }; - - default -> false; - }; - } } diff --git a/io.openems.common/src/io/openems/common/websocket/MyDraft6455.java b/io.openems.common/src/io/openems/common/websocket/MyDraft6455.java index 3f549c9cb49..4c4968114c6 100644 --- a/io.openems.common/src/io/openems/common/websocket/MyDraft6455.java +++ b/io.openems.common/src/io/openems/common/websocket/MyDraft6455.java @@ -23,6 +23,7 @@ import org.java_websocket.enums.Opcode; import org.java_websocket.enums.ReadyState; import org.java_websocket.enums.Role; +import org.java_websocket.exceptions.IncompleteException; import org.java_websocket.exceptions.InvalidDataException; import org.java_websocket.exceptions.InvalidFrameException; import org.java_websocket.exceptions.InvalidHandshakeException; diff --git a/io.openems.common/test/io/openems/common/jsonrpc/response/CreateXlxsTest.java b/io.openems.common/test/io/openems/common/jsonrpc/response/CreateXlxsTest.java new file mode 100644 index 00000000000..f855b102bee --- /dev/null +++ b/io.openems.common/test/io/openems/common/jsonrpc/response/CreateXlxsTest.java @@ -0,0 +1,248 @@ +package io.openems.common.jsonrpc.response; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.Base64; +import java.util.EnumMap; +import java.util.List; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.UUID; +import java.util.function.Consumer; + +import com.google.common.collect.ImmutableSortedMap; +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.jsonrpc.response.QueryHistoricTimeseriesExportXlsxResponse.Channel; +import io.openems.common.session.Language; +import io.openems.common.timedata.XlsxExportDetailData; +import io.openems.common.timedata.XlsxExportDetailData.XlsxExportCategory; +import io.openems.common.timedata.XlsxExportDetailData.XlsxExportDataEntry; +import io.openems.common.timedata.XlsxExportDetailData.XlsxExportDataEntry.HistoricTimedataSaveType; +import io.openems.common.types.ChannelAddress; +import io.openems.common.types.CurrencyConfig; + +public class CreateXlxsTest { + + private static SortedMap getMockedEnergyData() { + return ImmutableSortedMap.naturalOrder() // + .put(Channel.GRID_BUY_ACTIVE_ENERGY, new JsonPrimitive(500)) // + .put(Channel.GRID_SELL_ACTIVE_ENERGY, new JsonPrimitive(0)) // + .put(Channel.PRODUCTION_ACTIVE_ENERGY, new JsonPrimitive(300)) // + .put(Channel.CONSUMPTION_ACTIVE_ENERGY, new JsonPrimitive(700)) // + .put(Channel.ESS_DC_CHARGE_ENERGY, new JsonPrimitive(100)) // + .put(Channel.ESS_DC_DISCHARGE_ENERGY, new JsonPrimitive(80)) // + .build(); + } + + private static SortedMap> getMockedPowerData() { + + SortedMap values = new TreeMap<>(); + values.put(Channel.GRID_ACTIVE_POWER, new JsonPrimitive(50)); + values.put(Channel.PRODUCTION_ACTIVE_POWER, new JsonPrimitive(50)); + values.put(Channel.CONSUMPTION_ACTIVE_POWER, new JsonPrimitive(50)); + values.put(Channel.ESS_DISCHARGE_POWER, new JsonPrimitive(50)); + values.put(Channel.ESS_SOC, new JsonPrimitive(50)); + values.put(new ChannelAddress("meter0", "ActivePower"), new JsonPrimitive(100)); + values.put(new ChannelAddress("meter1", "ActivePower"), new JsonPrimitive(412)); + values.put(new ChannelAddress("evcs0", "ChargePower"), new JsonPrimitive(75)); + values.put(new ChannelAddress("meter2", "ActivePower"), new JsonPrimitive(10)); + values.put(new ChannelAddress("_sum", "GridBuyPower"), new JsonPrimitive(292.5)); + + return ImmutableSortedMap.>naturalOrder() + .put(ZonedDateTime.of(2020, 07, 01, 0, 15, 0, 0, ZoneId.systemDefault()).plusMinutes(15), values) // + .put(ZonedDateTime.of(2020, 07, 01, 0, 30, 0, 0, ZoneId.systemDefault()).plusMinutes(15), values) // + .put(ZonedDateTime.of(2020, 07, 01, 0, 45, 0, 0, ZoneId.systemDefault()).plusMinutes(15), values) // + .put(ZonedDateTime.of(2020, 07, 01, 1, 0, 0, 0, ZoneId.systemDefault()).plusMinutes(15), values) // + .put(ZonedDateTime.of(2020, 07, 01, 1, 15, 0, 0, ZoneId.systemDefault()).plusMinutes(15), values) // + .put(ZonedDateTime.of(2020, 07, 01, 1, 30, 0, 0, ZoneId.systemDefault()).plusMinutes(15), values) // + .build(); + } + + private static XlsxExportDetailData getMockedDetailData() { + final var enumMap = new EnumMap>(XlsxExportCategory.class); + final var consumption = new ArrayList(); + final var production = new ArrayList(); + final var tou = new ArrayList(); + + enumMap.put(XlsxExportCategory.PRODUCTION, production); + enumMap.put(XlsxExportCategory.CONSUMPTION, consumption); + enumMap.put(XlsxExportCategory.TIME_OF_USE_TARIFF, tou); + + production.add(new XlsxExportDataEntry("PV-Dach", new ChannelAddress("meter0", "ActivePower"), + HistoricTimedataSaveType.POWER)); + production.add(new XlsxExportDataEntry("PV-Alm", new ChannelAddress("meter1", "ActivePower"), + HistoricTimedataSaveType.POWER)); + consumption.add(new XlsxExportDataEntry("Consumption Meter", new ChannelAddress("meter2", "ActivePower"), + HistoricTimedataSaveType.POWER)); + consumption.add(new XlsxExportDataEntry("Wallbox Garage", new ChannelAddress("evcs0", "ChargePower"), + HistoricTimedataSaveType.POWER)); + tou.add(new XlsxExportDataEntry("Dynamisch Gut", new ChannelAddress("_sum", "GridBuyPower"), + HistoricTimedataSaveType.POWER)); + + return new XlsxExportDetailData(enumMap, CurrencyConfig.EUR); + } + + /** + * Main Method for creating a excel export with mocked data. + * + * @param args not used + * @throws IOException if file cant be written + * @throws OpenemsNamedException requests fails + */ + public static void main(String[] args) throws IOException, OpenemsNamedException { + createFullXlsx(); + createHalfXlsx(); + createConsumptionOnlyXlsx(); + createProductionOnlyXlsx(); + createTouOnlyXlsx(); + createProductionAndTouXlsx(); + createConsumptionAndTouXlsx(); + createnSingleOfAllXlsx(); + } + + private static void createFullXlsx() throws IOException, OpenemsNamedException { + var fromDate = ZonedDateTime.of(2020, 07, 01, 0, 0, 0, 0, ZoneId.systemDefault()); + var toDate = ZonedDateTime.of(2020, 07, 02, 0, 0, 0, 0, ZoneId.systemDefault()); + + var powerData = CreateXlxsTest.getMockedPowerData(); + var energyData = CreateXlxsTest.getMockedEnergyData(); + var detailData = CreateXlxsTest.getMockedDetailData(); + + final var request = new QueryHistoricTimeseriesExportXlsxResponse(UUID.randomUUID(), "edge0", fromDate, toDate, + powerData, energyData, Language.EN, detailData); + + var payload = request.getPayload(); + + byte[] excelData = Base64.getDecoder().decode(payload); + + String filePath = ".\\..\\build\\fullTestPrint.xlsx"; + + try (FileOutputStream fos = new FileOutputStream(filePath)) { + fos.write(excelData); + System.out.println("Testfile created under: " + filePath); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private static void createHalfXlsx() throws IOException, OpenemsNamedException { + createTestPrint(".\\..\\build\\emptyTestPrint.xlsx", null, null, null); + } + + private static void createTestPrint(String filePath, Consumer> consProd, + Consumer> consCons, Consumer> consTou) + throws IOException, OpenemsNamedException { + final var enumMap = new EnumMap>(XlsxExportCategory.class); + final var consumption = new ArrayList(); + final var production = new ArrayList(); + final var tou = new ArrayList(); + + if (consProd != null) { + consProd.accept(production); + } + + if (consCons != null) { + consCons.accept(consumption); + } + + if (consTou != null) { + consTou.accept(tou); + } + + enumMap.put(XlsxExportCategory.PRODUCTION, production); + enumMap.put(XlsxExportCategory.CONSUMPTION, consumption); + enumMap.put(XlsxExportCategory.TIME_OF_USE_TARIFF, tou); + + var detailData = new XlsxExportDetailData(enumMap, CurrencyConfig.EUR); + + var fromDate = ZonedDateTime.of(2020, 07, 01, 0, 0, 0, 0, ZoneId.systemDefault()); + var toDate = ZonedDateTime.of(2020, 07, 02, 0, 0, 0, 0, ZoneId.systemDefault()); + + var powerData = CreateXlxsTest.getMockedPowerData(); + var energyData = CreateXlxsTest.getMockedEnergyData(); + + final var request = new QueryHistoricTimeseriesExportXlsxResponse(UUID.randomUUID(), "edge0", fromDate, toDate, + powerData, energyData, Language.EN, detailData); + + var payload = request.getPayload(); + + byte[] excelData = Base64.getDecoder().decode(payload); + + try (FileOutputStream fos = new FileOutputStream(filePath)) { + fos.write(excelData); + System.out.println("Testfile created under: " + filePath); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private static void createProductionOnlyXlsx() throws IOException, OpenemsNamedException { + createTestPrint(".\\..\\build\\prodTestPrint.xlsx", production -> { + production.add(new XlsxExportDataEntry("PV-Dach", new ChannelAddress("meter0", "ActivePower"), + HistoricTimedataSaveType.POWER)); + production.add(new XlsxExportDataEntry("PV-Alm", new ChannelAddress("meter1", "ActivePower"), + HistoricTimedataSaveType.POWER)); + }, null, null); + } + + private static void createConsumptionOnlyXlsx() throws IOException, OpenemsNamedException { + createTestPrint(".\\..\\build\\consTestPrint.xlsx", null, consumption -> { + consumption.add(new XlsxExportDataEntry("Consumption Meter", new ChannelAddress("meter2", "ActivePower"), + HistoricTimedataSaveType.POWER)); + consumption.add(new XlsxExportDataEntry("Wallbox Garage", new ChannelAddress("evcs0", "ChargePower"), + HistoricTimedataSaveType.POWER)); + }, null); + } + + private static void createTouOnlyXlsx() throws IOException, OpenemsNamedException { + createTestPrint(".\\..\\build\\touPrint.xlsx", null, null, tou -> { + tou.add(new XlsxExportDataEntry("Dynamisch Gut", new ChannelAddress("_sum", "GridBuyPower"), + HistoricTimedataSaveType.POWER)); + }); + } + + private static void createProductionAndTouXlsx() throws IOException, OpenemsNamedException { + createTestPrint(".\\..\\build\\prodAndTouPrint.xlsx", production -> { + production.add(new XlsxExportDataEntry("PV-Dach", new ChannelAddress("meter0", "ActivePower"), + HistoricTimedataSaveType.POWER)); + production.add(new XlsxExportDataEntry("PV-Alm", new ChannelAddress("meter1", "ActivePower"), + HistoricTimedataSaveType.POWER)); + }, null, tou -> { + tou.add(new XlsxExportDataEntry("Dynamisch Gut", new ChannelAddress("_sum", "GridBuyPower"), + HistoricTimedataSaveType.POWER)); + }); + + } + + private static void createConsumptionAndTouXlsx() throws IOException, OpenemsNamedException { + createTestPrint(".\\..\\build\\consAndTouPrint.xlsx", null, consumption -> { + consumption.add(new XlsxExportDataEntry("Consumption Meter", new ChannelAddress("meter2", "ActivePower"), + HistoricTimedataSaveType.POWER)); + consumption.add(new XlsxExportDataEntry("Wallbox Garage", new ChannelAddress("evcs0", "ChargePower"), + HistoricTimedataSaveType.POWER)); + }, tou -> { + tou.add(new XlsxExportDataEntry("Dynamisch Gut", new ChannelAddress("_sum", "GridBuyPower"), + HistoricTimedataSaveType.POWER)); + }); + } + + private static void createnSingleOfAllXlsx() throws IOException, OpenemsNamedException { + createTestPrint(".\\..\\build\\singleOfAllPrint.xlsx", production -> { + production.add(new XlsxExportDataEntry("PV-Alm", new ChannelAddress("meter1", "ActivePower"), + HistoricTimedataSaveType.POWER)); + }, consumption -> { + consumption.add(new XlsxExportDataEntry("Wallbox Garage", new ChannelAddress("evcs0", "ChargePower"), + HistoricTimedataSaveType.POWER)); + }, tou -> { + tou.add(new XlsxExportDataEntry("Dynamisch Gut", new ChannelAddress("_sum", "GridBuyPower"), + HistoricTimedataSaveType.POWER)); + }); + + } +} diff --git a/io.openems.edge.battery.api/test/io/openems/edge/battery/protection/BatteryProtectionTest.java b/io.openems.edge.battery.api/test/io/openems/edge/battery/protection/BatteryProtectionTest.java index de029ad3ba5..74b3d0f4895 100644 --- a/io.openems.edge.battery.api/test/io/openems/edge/battery/protection/BatteryProtectionTest.java +++ b/io.openems.edge.battery.api/test/io/openems/edge/battery/protection/BatteryProtectionTest.java @@ -1,14 +1,24 @@ package io.openems.edge.battery.protection; +import static io.openems.edge.battery.api.Battery.ChannelId.CHARGE_MAX_CURRENT; +import static io.openems.edge.battery.api.Battery.ChannelId.DISCHARGE_MAX_CURRENT; +import static io.openems.edge.battery.api.Battery.ChannelId.MAX_CELL_TEMPERATURE; +import static io.openems.edge.battery.api.Battery.ChannelId.MAX_CELL_VOLTAGE; +import static io.openems.edge.battery.api.Battery.ChannelId.MIN_CELL_TEMPERATURE; +import static io.openems.edge.battery.api.Battery.ChannelId.MIN_CELL_VOLTAGE; +import static io.openems.edge.battery.protection.BatteryProtection.ChannelId.BP_CHARGE_BMS; +import static io.openems.edge.battery.protection.BatteryProtection.ChannelId.BP_DISCHARGE_BMS; +import static io.openems.edge.common.startstop.StartStoppable.ChannelId.START_STOP; +import static java.time.temporal.ChronoUnit.MINUTES; +import static java.time.temporal.ChronoUnit.SECONDS; + import java.time.Instant; import java.time.ZoneOffset; -import java.time.temporal.ChronoUnit; import org.junit.Test; import io.openems.common.channel.Unit; import io.openems.common.test.TimeLeapClock; -import io.openems.common.types.ChannelAddress; import io.openems.common.types.OpenemsType; import io.openems.edge.battery.protection.currenthandler.ChargeMaxCurrentHandler; import io.openems.edge.battery.protection.currenthandler.DischargeMaxCurrentHandler; @@ -18,7 +28,6 @@ import io.openems.edge.common.channel.Doc; import io.openems.edge.common.linecharacteristic.PolyLine; import io.openems.edge.common.startstop.StartStop; -import io.openems.edge.common.startstop.StartStoppable; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyComponentManager; @@ -102,22 +111,6 @@ public Doc doc() { private static final String BATTERY_ID = "battery0"; - private static final ChannelAddress BATTERY_START_STOP = new ChannelAddress(BATTERY_ID, - StartStoppable.ChannelId.START_STOP.id()); - private static final ChannelAddress BATTERY_BP_CHARGE_BMS = new ChannelAddress(BATTERY_ID, - BatteryProtection.ChannelId.BP_CHARGE_BMS.id()); - private static final ChannelAddress BATTERY_BP_DISCHARGE_BMS = new ChannelAddress(BATTERY_ID, - BatteryProtection.ChannelId.BP_DISCHARGE_BMS.id()); - private static final ChannelAddress BATTERY_MIN_CELL_VOLTAGE = new ChannelAddress(BATTERY_ID, "MinCellVoltage"); - private static final ChannelAddress BATTERY_MAX_CELL_VOLTAGE = new ChannelAddress(BATTERY_ID, "MaxCellVoltage"); - private static final ChannelAddress BATTERY_MIN_CELL_TEMPERATURE = new ChannelAddress(BATTERY_ID, - "MinCellTemperature"); - private static final ChannelAddress BATTERY_MAX_CELL_TEMPERATURE = new ChannelAddress(BATTERY_ID, - "MaxCellTemperature"); - private static final ChannelAddress BATTERY_CHARGE_MAX_CURRENT = new ChannelAddress(BATTERY_ID, "ChargeMaxCurrent"); - private static final ChannelAddress BATTERY_DISCHARGE_MAX_CURRENT = new ChannelAddress(BATTERY_ID, - "DischargeMaxCurrent"); - @Test public void test() throws Exception { final var battery = new DummyBattery(BATTERY_ID); @@ -137,169 +130,168 @@ public void test() throws Exception { .setForceCharge(FORCE_CHARGE) // .build()) // .build(); - new ComponentTest(new DummyBattery(BATTERY_ID)) // - .addComponent(battery) // + new ComponentTest(battery) // .next(new TestCase() // - .input(BATTERY_START_STOP, StartStop.START) // - .input(BATTERY_BP_CHARGE_BMS, 80) // - .input(BATTERY_BP_DISCHARGE_BMS, 80) // - .input(BATTERY_MIN_CELL_VOLTAGE, 2950) // - .input(BATTERY_MAX_CELL_VOLTAGE, 3300) // - .input(BATTERY_MIN_CELL_TEMPERATURE, 16) // - .input(BATTERY_MAX_CELL_TEMPERATURE, 17) // + .input(START_STOP, StartStop.START) // + .input(BP_CHARGE_BMS, 80) // + .input(BP_DISCHARGE_BMS, 80) // + .input(MIN_CELL_VOLTAGE, 2950) // + .input(MAX_CELL_VOLTAGE, 3300) // + .input(MIN_CELL_TEMPERATURE, 16) // + .input(MAX_CELL_TEMPERATURE, 17) // .onAfterProcessImage(() -> sut.apply()) // - .output(BATTERY_CHARGE_MAX_CURRENT, 0) // - .output(BATTERY_DISCHARGE_MAX_CURRENT, 0)) // + .output(CHARGE_MAX_CURRENT, 0) // + .output(DISCHARGE_MAX_CURRENT, 0)) // .next(new TestCase("open, but maxIncreaseAmpereLimit") // - .timeleap(clock, 2, ChronoUnit.SECONDS) // - .input(BATTERY_MIN_CELL_VOLTAGE, 3000) // + .timeleap(clock, 2, SECONDS) // + .input(MIN_CELL_VOLTAGE, 3000) // .onAfterProcessImage(() -> sut.apply()) // - .output(BATTERY_CHARGE_MAX_CURRENT, 1) // - .output(BATTERY_DISCHARGE_MAX_CURRENT, 1)) // + .output(CHARGE_MAX_CURRENT, 1) // + .output(DISCHARGE_MAX_CURRENT, 1)) // .next(new TestCase() // - .timeleap(clock, 2, ChronoUnit.SECONDS) // - .input(BATTERY_MIN_CELL_VOLTAGE, 3050) // + .timeleap(clock, 2, SECONDS) // + .input(MIN_CELL_VOLTAGE, 3050) // .onAfterProcessImage(() -> sut.apply()) // - .output(BATTERY_CHARGE_MAX_CURRENT, 2) // - .output(BATTERY_DISCHARGE_MAX_CURRENT, 2)) // + .output(CHARGE_MAX_CURRENT, 2) // + .output(DISCHARGE_MAX_CURRENT, 2)) // .next(new TestCase() // - .timeleap(clock, 10, ChronoUnit.SECONDS) // + .timeleap(clock, 10, SECONDS) // .onAfterProcessImage(() -> sut.apply()) // - .output(BATTERY_CHARGE_MAX_CURRENT, 7) // - .output(BATTERY_DISCHARGE_MAX_CURRENT, 7)) // + .output(CHARGE_MAX_CURRENT, 7) // + .output(DISCHARGE_MAX_CURRENT, 7)) // .next(new TestCase() // - .timeleap(clock, 10, ChronoUnit.MINUTES) // - .input(BATTERY_MAX_CELL_VOLTAGE, 3300) // + .timeleap(clock, 10, MINUTES) // + .input(MAX_CELL_VOLTAGE, 3300) // .onAfterProcessImage(() -> sut.apply()) // - .output(BATTERY_CHARGE_MAX_CURRENT, 80) // - .output(BATTERY_DISCHARGE_MAX_CURRENT, 80)) // + .output(CHARGE_MAX_CURRENT, 80) // + .output(DISCHARGE_MAX_CURRENT, 80)) // .next(new TestCase() // - .timeleap(clock, 10, ChronoUnit.MINUTES) // - .input(BATTERY_MAX_CELL_VOLTAGE, 3499) // + .timeleap(clock, 10, MINUTES) // + .input(MAX_CELL_VOLTAGE, 3499) // .onAfterProcessImage(() -> sut.apply()) // - .output(BATTERY_CHARGE_MAX_CURRENT, 54) // - .output(BATTERY_DISCHARGE_MAX_CURRENT, 80)) // + .output(CHARGE_MAX_CURRENT, 54) // + .output(DISCHARGE_MAX_CURRENT, 80)) // .next(new TestCase() // - .timeleap(clock, 10, ChronoUnit.MINUTES) // - .input(BATTERY_MAX_CELL_VOLTAGE, 3649) // + .timeleap(clock, 10, MINUTES) // + .input(MAX_CELL_VOLTAGE, 3649) // .onAfterProcessImage(() -> sut.apply()) // - .output(BATTERY_CHARGE_MAX_CURRENT, 2) // - .output(BATTERY_DISCHARGE_MAX_CURRENT, 80)) // + .output(CHARGE_MAX_CURRENT, 2) // + .output(DISCHARGE_MAX_CURRENT, 80)) // .next(new TestCase() // - .timeleap(clock, 10, ChronoUnit.MINUTES) // - .input(BATTERY_MAX_CELL_VOLTAGE, 3649) // + .timeleap(clock, 10, MINUTES) // + .input(MAX_CELL_VOLTAGE, 3649) // .onAfterProcessImage(() -> sut.apply()) // - .output(BATTERY_CHARGE_MAX_CURRENT, 2) // - .output(BATTERY_DISCHARGE_MAX_CURRENT, 80)) // + .output(CHARGE_MAX_CURRENT, 2) // + .output(DISCHARGE_MAX_CURRENT, 80)) // .next(new TestCase() // - .timeleap(clock, 10, ChronoUnit.MINUTES) // - .input(BATTERY_MAX_CELL_VOLTAGE, 3650) // + .timeleap(clock, 10, MINUTES) // + .input(MAX_CELL_VOLTAGE, 3650) // .onAfterProcessImage(() -> sut.apply()) // - .output(BATTERY_CHARGE_MAX_CURRENT, 0) // - .output(BATTERY_DISCHARGE_MAX_CURRENT, 80)) // + .output(CHARGE_MAX_CURRENT, 0) // + .output(DISCHARGE_MAX_CURRENT, 80)) // .next(new TestCase("Start Force-Discharge: wait 60 seconds") // - .timeleap(clock, 1, ChronoUnit.SECONDS) // - .input(BATTERY_MAX_CELL_VOLTAGE, 3660) // + .timeleap(clock, 1, SECONDS) // + .input(MAX_CELL_VOLTAGE, 3660) // .onAfterProcessImage(() -> sut.apply()) // - .output(BATTERY_CHARGE_MAX_CURRENT, 0) // - .output(BATTERY_DISCHARGE_MAX_CURRENT, 80)) // + .output(CHARGE_MAX_CURRENT, 0) // + .output(DISCHARGE_MAX_CURRENT, 80)) // .next(new TestCase("Start Force-Discharge") // - .timeleap(clock, 60, ChronoUnit.SECONDS) // - .input(BATTERY_MAX_CELL_VOLTAGE, 3660) // + .timeleap(clock, 60, SECONDS) // + .input(MAX_CELL_VOLTAGE, 3660) // .onAfterProcessImage(() -> sut.apply()) // - .output(BATTERY_CHARGE_MAX_CURRENT, -2) // - .output(BATTERY_DISCHARGE_MAX_CURRENT, 80)) // + .output(CHARGE_MAX_CURRENT, -2) // + .output(DISCHARGE_MAX_CURRENT, 80)) // .next(new TestCase("Force-Discharge") // - .timeleap(clock, 1, ChronoUnit.SECONDS) // - .input(BATTERY_MAX_CELL_VOLTAGE, 3640) // + .timeleap(clock, 1, SECONDS) // + .input(MAX_CELL_VOLTAGE, 3640) // .onAfterProcessImage(() -> sut.apply()) // - .output(BATTERY_CHARGE_MAX_CURRENT, -2) // - .output(BATTERY_DISCHARGE_MAX_CURRENT, 80)) // + .output(CHARGE_MAX_CURRENT, -2) // + .output(DISCHARGE_MAX_CURRENT, 80)) // .next(new TestCase("Block Charge #1") // - .timeleap(clock, 1, ChronoUnit.SECONDS) // - .input(BATTERY_MAX_CELL_VOLTAGE, 3639) // + .timeleap(clock, 1, SECONDS) // + .input(MAX_CELL_VOLTAGE, 3639) // .onAfterProcessImage(() -> sut.apply()) // - .output(BATTERY_CHARGE_MAX_CURRENT, -1) // - .output(BATTERY_DISCHARGE_MAX_CURRENT, 80)) // + .output(CHARGE_MAX_CURRENT, -1) // + .output(DISCHARGE_MAX_CURRENT, 80)) // .next(new TestCase("Block Charge #1 still reduce by 1") // - .timeleap(clock, 1, ChronoUnit.SECONDS) // - .input(BATTERY_MAX_CELL_VOLTAGE, 3638) // + .timeleap(clock, 1, SECONDS) // + .input(MAX_CELL_VOLTAGE, 3638) // .onAfterProcessImage(() -> sut.apply()) // - .output(BATTERY_CHARGE_MAX_CURRENT, -1) // - .output(BATTERY_DISCHARGE_MAX_CURRENT, 80)) // + .output(CHARGE_MAX_CURRENT, -1) // + .output(DISCHARGE_MAX_CURRENT, 80)) // .next(new TestCase("Block Charge #1 still reduce by 1") // - .timeleap(clock, 1, ChronoUnit.SECONDS) // - .input(BATTERY_MAX_CELL_VOLTAGE, 3610) // + .timeleap(clock, 1, SECONDS) // + .input(MAX_CELL_VOLTAGE, 3610) // .onAfterProcessImage(() -> sut.apply()) // - .output(BATTERY_CHARGE_MAX_CURRENT, 0) // - .output(BATTERY_DISCHARGE_MAX_CURRENT, 80)) // + .output(CHARGE_MAX_CURRENT, 0) // + .output(DISCHARGE_MAX_CURRENT, 80)) // .next(new TestCase("Block Charge #2") // - .timeleap(clock, 1, ChronoUnit.SECONDS) // - .input(BATTERY_MAX_CELL_VOLTAGE, 3600) // + .timeleap(clock, 1, SECONDS) // + .input(MAX_CELL_VOLTAGE, 3600) // .onAfterProcessImage(() -> sut.apply()) // - .output(BATTERY_CHARGE_MAX_CURRENT, 0) // - .output(BATTERY_DISCHARGE_MAX_CURRENT, 80)) // + .output(CHARGE_MAX_CURRENT, 0) // + .output(DISCHARGE_MAX_CURRENT, 80)) // .next(new TestCase("Start Force-Discharge again") // - .timeleap(clock, 1, ChronoUnit.SECONDS) // - .input(BATTERY_MAX_CELL_VOLTAGE, 3660) // + .timeleap(clock, 1, SECONDS) // + .input(MAX_CELL_VOLTAGE, 3660) // .onAfterProcessImage(() -> sut.apply()) // - .output(BATTERY_CHARGE_MAX_CURRENT, -2) // - .output(BATTERY_DISCHARGE_MAX_CURRENT, 80)) // + .output(CHARGE_MAX_CURRENT, -2) // + .output(DISCHARGE_MAX_CURRENT, 80)) // .next(new TestCase("Force-Discharge") // - .timeleap(clock, 1, ChronoUnit.SECONDS) // - .input(BATTERY_MAX_CELL_VOLTAGE, 3640) // + .timeleap(clock, 1, SECONDS) // + .input(MAX_CELL_VOLTAGE, 3640) // .onAfterProcessImage(() -> sut.apply()) // - .output(BATTERY_CHARGE_MAX_CURRENT, -2) // - .output(BATTERY_DISCHARGE_MAX_CURRENT, 80)) // + .output(CHARGE_MAX_CURRENT, -2) // + .output(DISCHARGE_MAX_CURRENT, 80)) // .next(new TestCase("Block Charge #1") // - .timeleap(clock, 1, ChronoUnit.SECONDS) // - .input(BATTERY_MAX_CELL_VOLTAGE, 3639) // + .timeleap(clock, 1, SECONDS) // + .input(MAX_CELL_VOLTAGE, 3639) // .onAfterProcessImage(() -> sut.apply()) // - .output(BATTERY_CHARGE_MAX_CURRENT, -1) // - .output(BATTERY_DISCHARGE_MAX_CURRENT, 80)) // + .output(CHARGE_MAX_CURRENT, -1) // + .output(DISCHARGE_MAX_CURRENT, 80)) // .next(new TestCase("Block Charge #1 still reduce by 1") // - .timeleap(clock, 1, ChronoUnit.SECONDS) // - .input(BATTERY_MAX_CELL_VOLTAGE, 3638) // + .timeleap(clock, 1, SECONDS) // + .input(MAX_CELL_VOLTAGE, 3638) // .onAfterProcessImage(() -> sut.apply()) // - .output(BATTERY_CHARGE_MAX_CURRENT, -1) // - .output(BATTERY_DISCHARGE_MAX_CURRENT, 80)) // + .output(CHARGE_MAX_CURRENT, -1) // + .output(DISCHARGE_MAX_CURRENT, 80)) // .next(new TestCase("Block Charge #1 still reduce by 1") // - .timeleap(clock, 1, ChronoUnit.SECONDS) // - .input(BATTERY_MAX_CELL_VOLTAGE, 3637) // + .timeleap(clock, 1, SECONDS) // + .input(MAX_CELL_VOLTAGE, 3637) // .onAfterProcessImage(() -> sut.apply()) // - .output(BATTERY_CHARGE_MAX_CURRENT, 0) // - .output(BATTERY_DISCHARGE_MAX_CURRENT, 80)) // + .output(CHARGE_MAX_CURRENT, 0) // + .output(DISCHARGE_MAX_CURRENT, 80)) // .next(new TestCase("Block Charge #2") // - .timeleap(clock, 1, ChronoUnit.SECONDS) // - .input(BATTERY_MAX_CELL_VOLTAGE, 3600) // + .timeleap(clock, 1, SECONDS) // + .input(MAX_CELL_VOLTAGE, 3600) // .onAfterProcessImage(() -> sut.apply()) // - .output(BATTERY_CHARGE_MAX_CURRENT, 0) // - .output(BATTERY_DISCHARGE_MAX_CURRENT, 80)) // + .output(CHARGE_MAX_CURRENT, 0) // + .output(DISCHARGE_MAX_CURRENT, 80)) // .next(new TestCase("Block Charge #3") // - .timeleap(clock, 1, ChronoUnit.SECONDS) // - .input(BATTERY_MAX_CELL_VOLTAGE, 3450) // + .timeleap(clock, 1, SECONDS) // + .input(MAX_CELL_VOLTAGE, 3450) // .onAfterProcessImage(() -> sut.apply()) // - .output(BATTERY_CHARGE_MAX_CURRENT, 0) // - .output(BATTERY_DISCHARGE_MAX_CURRENT, 80)) // + .output(CHARGE_MAX_CURRENT, 0) // + .output(DISCHARGE_MAX_CURRENT, 80)) // .next(new TestCase("Finish Force-Discharge") // - .timeleap(clock, 1, ChronoUnit.SECONDS) // - .input(BATTERY_MAX_CELL_VOLTAGE, 3449) // + .timeleap(clock, 1, SECONDS) // + .input(MAX_CELL_VOLTAGE, 3449) // .onAfterProcessImage(() -> sut.apply()) // - .output(BATTERY_CHARGE_MAX_CURRENT, 0) // - .output(BATTERY_DISCHARGE_MAX_CURRENT, 80)) // + .output(CHARGE_MAX_CURRENT, 0) // + .output(DISCHARGE_MAX_CURRENT, 80)) // .next(new TestCase() // - .timeleap(clock, 1, ChronoUnit.SECONDS) // - .input(BATTERY_MAX_CELL_VOLTAGE, 3400) // + .timeleap(clock, 1, SECONDS) // + .input(MAX_CELL_VOLTAGE, 3400) // .onAfterProcessImage(() -> sut.apply()) // - .output(BATTERY_CHARGE_MAX_CURRENT, 0) // - .output(BATTERY_DISCHARGE_MAX_CURRENT, 80)) // + .output(CHARGE_MAX_CURRENT, 0) // + .output(DISCHARGE_MAX_CURRENT, 80)) // .next(new TestCase("Allow Charge") // - .timeleap(clock, 1, ChronoUnit.SECONDS) // - .input(BATTERY_MAX_CELL_VOLTAGE, 3350) // + .timeleap(clock, 1, SECONDS) // + .input(MAX_CELL_VOLTAGE, 3350) // .onAfterProcessImage(() -> sut.apply()) // - .output(BATTERY_CHARGE_MAX_CURRENT, 1) // - .output(BATTERY_DISCHARGE_MAX_CURRENT, 80)) // + .output(CHARGE_MAX_CURRENT, 1) // + .output(DISCHARGE_MAX_CURRENT, 80)) // ; } diff --git a/io.openems.edge.battery.bmw/test/io/openems/edge/battery/bmw/BmwBatteryImplTest.java b/io.openems.edge.battery.bmw/test/io/openems/edge/battery/bmw/BmwBatteryImplTest.java index fd5aa8847db..8ded6b2514c 100644 --- a/io.openems.edge.battery.bmw/test/io/openems/edge/battery/bmw/BmwBatteryImplTest.java +++ b/io.openems.edge.battery.bmw/test/io/openems/edge/battery/bmw/BmwBatteryImplTest.java @@ -1,33 +1,33 @@ package io.openems.edge.battery.bmw; +import static io.openems.edge.battery.bmw.enums.BatteryState.DEFAULT; + import org.junit.Test; -import io.openems.edge.battery.bmw.enums.BatteryState; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; +import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; public class BmwBatteryImplTest { - private static final String BATTERY_ID = "battery0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new BmwBatteryImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(BATTERY_ID) // - .setModbusId(MODBUS_ID) // - .setBatteryState(BatteryState.DEFAULT) // + .setId("battery0") // + .setModbusId("modbus0") // + .setBatteryState(DEFAULT) // .setErrorDelay(0) // .setMaxStartAttempts(0) // .setMaxStartTime(0) // .setPendingTolerance(0) // .setStartUnsuccessfulDelay(0) // .build()) // - ; + .next(new TestCase()) // + .deactivate(); } } diff --git a/io.openems.edge.battery.bydcommercial/test/io/openems/edge/battery/bydcommercial/BydBatteryBoxCommercialC130ImplTest.java b/io.openems.edge.battery.bydcommercial/test/io/openems/edge/battery/bydcommercial/BydBatteryBoxCommercialC130ImplTest.java index 91d0b85e1c1..1b87571c888 100644 --- a/io.openems.edge.battery.bydcommercial/test/io/openems/edge/battery/bydcommercial/BydBatteryBoxCommercialC130ImplTest.java +++ b/io.openems.edge.battery.bydcommercial/test/io/openems/edge/battery/bydcommercial/BydBatteryBoxCommercialC130ImplTest.java @@ -1,28 +1,30 @@ package io.openems.edge.battery.bydcommercial; +import static io.openems.edge.common.startstop.StartStopConfig.AUTO; + import org.junit.Test; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; -import io.openems.edge.common.startstop.StartStopConfig; +import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.common.test.DummyConfigurationAdmin; public class BydBatteryBoxCommercialC130ImplTest { - private static final String BATTERY_ID = "battery0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new BydBatteryBoxCommercialC130Impl()) // + .addReference("componentManager", new DummyComponentManager()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(BATTERY_ID) // - .setModbusId(MODBUS_ID) // - .setStartStop(StartStopConfig.AUTO) // + .setId("battery0") // + .setModbusId("modbus0") // + .setStartStop(AUTO) // .build()) // - ; + .next(new TestCase()) // + .deactivate(); } } diff --git a/io.openems.edge.battery.fenecon.commercial/test/io/openems/edge/battery/fenecon/commercial/BatteryFeneconCommercialImplTest.java b/io.openems.edge.battery.fenecon.commercial/test/io/openems/edge/battery/fenecon/commercial/BatteryFeneconCommercialImplTest.java index 1226ccc9ffc..8fec9839f16 100644 --- a/io.openems.edge.battery.fenecon.commercial/test/io/openems/edge/battery/fenecon/commercial/BatteryFeneconCommercialImplTest.java +++ b/io.openems.edge.battery.fenecon.commercial/test/io/openems/edge/battery/fenecon/commercial/BatteryFeneconCommercialImplTest.java @@ -1,17 +1,20 @@ package io.openems.edge.battery.fenecon.commercial; -import java.time.Instant; -import java.time.ZoneOffset; +import static io.openems.edge.battery.api.Battery.ChannelId.CHARGE_MAX_CURRENT; +import static io.openems.edge.battery.api.Battery.ChannelId.DISCHARGE_MAX_CURRENT; +import static io.openems.edge.battery.api.Battery.ChannelId.SOC; +import static io.openems.edge.battery.fenecon.commercial.BatteryFeneconCommercial.ChannelId.BATTERY_SOC; +import static io.openems.edge.battery.fenecon.commercial.BatteryFeneconCommercial.ChannelId.RUNNING; +import static io.openems.edge.battery.fenecon.commercial.BatteryFeneconCommercial.ChannelId.STATE_MACHINE; +import static io.openems.edge.common.startstop.StartStoppable.ChannelId.START_STOP; +import static io.openems.edge.common.test.TestUtils.createDummyClock; +import static io.openems.edge.io.test.DummyInputOutput.ChannelId.INPUT_OUTPUT7; import org.junit.Test; -import io.openems.common.test.TimeLeapClock; -import io.openems.common.types.ChannelAddress; -import io.openems.edge.battery.api.Battery; import io.openems.edge.battery.fenecon.commercial.statemachine.StateMachine; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.startstop.StartStopConfig; -import io.openems.edge.common.startstop.StartStoppable; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyComponentManager; @@ -20,42 +23,23 @@ public class BatteryFeneconCommercialImplTest { - private static final String BATTERY_ID = "battery0"; - private static final String MODBUS_ID = "modbus0"; - private static final String IO_ID = "io0"; - - private static final ChannelAddress STATE_MACHINE = new ChannelAddress(BATTERY_ID, - BatteryFeneconCommercial.ChannelId.STATE_MACHINE.id()); - private static final ChannelAddress RUNNING = new ChannelAddress(BATTERY_ID, - BatteryFeneconCommercial.ChannelId.RUNNING.id()); - private static final ChannelAddress BATTERY_RELAY = new ChannelAddress(IO_ID, "InputOutput7"); - private static final ChannelAddress START_STOP = new ChannelAddress(BATTERY_ID, - StartStoppable.ChannelId.START_STOP.id()); - private static final ChannelAddress BATTERY_SOC = new ChannelAddress(BATTERY_ID, - BatteryFeneconCommercial.ChannelId.BATTERY_SOC.id()); - private static final ChannelAddress BATTERY_MAX_DISCHARGE_CURRENT = new ChannelAddress(BATTERY_ID, - Battery.ChannelId.DISCHARGE_MAX_CURRENT.id()); - private static final ChannelAddress BATTERY_MAX_CHARGE_CURRENT = new ChannelAddress(BATTERY_ID, - Battery.ChannelId.CHARGE_MAX_CURRENT.id()); - private static final ChannelAddress SOC = new ChannelAddress(BATTERY_ID, Battery.ChannelId.SOC.id()); - @Test public void startBattery() throws Exception { - final var clock = new TimeLeapClock(Instant.parse("2020-01-01T01:00:00.00Z"), ZoneOffset.UTC); + final var clock = createDummyClock(); new ComponentTest(new BatteryFeneconCommercialImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager(clock)) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // - .addComponent(new DummyInputOutput(IO_ID))// + .addReference("setModbus", new DummyModbusBridge("modbus0")) // + .addComponent(new DummyInputOutput("io0"))// .activate(MyConfig.create() // - .setId(BATTERY_ID) // - .setModbusId(MODBUS_ID) // + .setId("battery0") // + .setModbusId("modbus0") // .setModbusUnitId(1) // .setStartStop(StartStopConfig.START) // .setBatteryStartStopRelay("io0/InputOutput7")// .build())// .next(new TestCase("Battery Relay false, starting") // - .input(BATTERY_RELAY, false)// + .input("io0", INPUT_OUTPUT7, false)// .input(RUNNING, false)// Switched Off .output(STATE_MACHINE, StateMachine.State.UNDEFINED))// .next(new TestCase() // @@ -63,18 +47,18 @@ public void startBattery() throws Exception { .next(new TestCase()// .output(STATE_MACHINE, StateMachine.State.GO_RUNNING))// .next(new TestCase()// - .input(BATTERY_RELAY, true))// + .input("io0", INPUT_OUTPUT7, true))// .next(new TestCase() // .output(STATE_MACHINE, StateMachine.State.GO_RUNNING))// .next(new TestCase()// .input(RUNNING, true)// - .input(BATTERY_RELAY, false))// + .input("io0", INPUT_OUTPUT7, false))// .next(new TestCase() // .output(STATE_MACHINE, StateMachine.State.GO_RUNNING))// .next(new TestCase("Battery Running")// .output(STATE_MACHINE, StateMachine.State.RUNNING))// .next(new TestCase("Battery Running")// - .output(BATTERY_RELAY, false)// + .output("io0", INPUT_OUTPUT7, false)// .output(RUNNING, true) // .output(STATE_MACHINE, StateMachine.State.RUNNING))// @@ -83,21 +67,21 @@ public void startBattery() throws Exception { @Test public void stopBattery() throws Exception { - final var clock = new TimeLeapClock(Instant.parse("2020-01-01T01:00:00.00Z"), ZoneOffset.UTC); + final var clock = createDummyClock(); new ComponentTest(new BatteryFeneconCommercialImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager(clock)) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // - .addComponent(new DummyInputOutput(IO_ID))// + .addReference("setModbus", new DummyModbusBridge("modbus0")) // + .addComponent(new DummyInputOutput("io0"))// .activate(MyConfig.create() // - .setId(BATTERY_ID) // - .setModbusId(MODBUS_ID) // + .setId("battery0") // + .setModbusId("modbus0") // .setModbusUnitId(1) // .setStartStop(StartStopConfig.STOP) // .setBatteryStartStopRelay("io0/InputOutput7")// .build())// .next(new TestCase("Battery Running")// - .input(BATTERY_RELAY, false)// + .input("io0", INPUT_OUTPUT7, false)// .input(RUNNING, true) // .input(STATE_MACHINE, StateMachine.State.RUNNING))// .next(new TestCase("Stopping") // @@ -105,7 +89,7 @@ public void stopBattery() throws Exception { .next(new TestCase()// .output(STATE_MACHINE, StateMachine.State.GO_STOPPED))// .next(new TestCase()// - .input(BATTERY_RELAY, true)) // + .input("io0", INPUT_OUTPUT7, true)) // .next(new TestCase()// .output(STATE_MACHINE, StateMachine.State.STOPPED))// @@ -114,15 +98,15 @@ public void stopBattery() throws Exception { @Test public void socManipulationMin() throws Exception { - final var clock = new TimeLeapClock(Instant.parse("2020-01-01T01:00:00.00Z"), ZoneOffset.UTC); + final var clock = createDummyClock(); new ComponentTest(new BatteryFeneconCommercialImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager(clock)) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // - .addComponent(new DummyInputOutput(IO_ID))// + .addReference("setModbus", new DummyModbusBridge("modbus0")) // + .addComponent(new DummyInputOutput("io0"))// .activate(MyConfig.create() // - .setId(BATTERY_ID) // - .setModbusId(MODBUS_ID) // + .setId("battery0") // + .setModbusId("modbus0") // .setModbusUnitId(1) // .setStartStop(StartStopConfig.START) // .setBatteryStartStopRelay("io0/InputOutput7")// @@ -130,22 +114,22 @@ public void socManipulationMin() throws Exception { .next(new TestCase("Soc")// .input(RUNNING, true) // .input(BATTERY_SOC, 10) // - .input(BATTERY_MAX_DISCHARGE_CURRENT, 0) // - .input(BATTERY_MAX_CHARGE_CURRENT, 10000) // + .input(DISCHARGE_MAX_CURRENT, 0) // + .input(CHARGE_MAX_CURRENT, 10000) // .output(SOC, 10)); } @Test public void socManipulationMax() throws Exception { - final var clock = new TimeLeapClock(Instant.parse("2020-01-01T01:00:00.00Z"), ZoneOffset.UTC); + final var clock = createDummyClock(); new ComponentTest(new BatteryFeneconCommercialImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager(clock)) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // - .addComponent(new DummyInputOutput(IO_ID))// + .addReference("setModbus", new DummyModbusBridge("modbus0")) // + .addComponent(new DummyInputOutput("io0"))// .activate(MyConfig.create() // - .setId(BATTERY_ID) // - .setModbusId(MODBUS_ID) // + .setId("battery0") // + .setModbusId("modbus0") // .setModbusUnitId(1) // .setStartStop(StartStopConfig.START) // .setBatteryStartStopRelay("io0/InputOutput7")// @@ -153,8 +137,8 @@ public void socManipulationMax() throws Exception { .next(new TestCase("Soc")// .input(RUNNING, true) // .input(BATTERY_SOC, 98) // - .input(BATTERY_MAX_DISCHARGE_CURRENT, 100000) // - .input(BATTERY_MAX_CHARGE_CURRENT, 0) // + .input(DISCHARGE_MAX_CURRENT, 100000) // + .input(CHARGE_MAX_CURRENT, 0) // .output(SOC, 100)); } } diff --git a/io.openems.edge.battery.fenecon.commercial/test/io/openems/edge/battery/fenecon/commercial/DynamicChannelsAndSerialNumbersTest.java b/io.openems.edge.battery.fenecon.commercial/test/io/openems/edge/battery/fenecon/commercial/DynamicChannelsAndSerialNumbersTest.java index b28b1513542..a9db6249dc3 100644 --- a/io.openems.edge.battery.fenecon.commercial/test/io/openems/edge/battery/fenecon/commercial/DynamicChannelsAndSerialNumbersTest.java +++ b/io.openems.edge.battery.fenecon.commercial/test/io/openems/edge/battery/fenecon/commercial/DynamicChannelsAndSerialNumbersTest.java @@ -1,10 +1,14 @@ package io.openems.edge.battery.fenecon.commercial; +import static io.openems.edge.battery.fenecon.commercial.BatteryFeneconCommercial.ChannelId.MASTER_MCU_HARDWARE_VERSION; +import static io.openems.edge.battery.fenecon.commercial.BatteryFeneconCommercial.ChannelId.NUMBER_OF_CELLS_PER_MODULE; +import static io.openems.edge.battery.fenecon.commercial.BatteryFeneconCommercial.ChannelId.NUMBER_OF_MODULES_PER_TOWER; +import static io.openems.edge.battery.fenecon.commercial.BatteryFeneconCommercial.ChannelId.NUMBER_OF_TOWERS; +import static io.openems.edge.battery.fenecon.commercial.BatteryFeneconCommercialImpl.VERSION_CONVERTER; import static org.junit.Assert.assertEquals; import org.junit.Test; -import io.openems.common.types.ChannelAddress; import io.openems.edge.battery.api.Battery; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.startstop.StartStopConfig; @@ -16,24 +20,10 @@ public class DynamicChannelsAndSerialNumbersTest { - private static final String BATTERY_ID = "battery0"; - private static final String MODBUS_ID = "modbus0"; - private static final String IO_ID = "io0"; - private static final int TOWERS = 1; private static final int MODULES = 10; private static final int CELLS = 120;/* Read from register as cells*modules */ - private static final ChannelAddress NUMBER_OF_MODULES_PER_TOWER = new ChannelAddress(BATTERY_ID, - "NumberOfModulesPerTower"); - private static final ChannelAddress NUMBER_OF_TOWERS = new ChannelAddress(BATTERY_ID, "NumberOfTowers"); - private static final ChannelAddress NUMBER_OF_CELLS_PER_MODULE = new ChannelAddress(BATTERY_ID, - "NumberOfCellsPerModule"); - private static final ChannelAddress SUB_MASTER_HARDWARE_VERSION = new ChannelAddress(BATTERY_ID, - "Tower0SubMasterHardwareVersion"); - private static final ChannelAddress MASTER_MCU_HARDWARE_VERSION = new ChannelAddress(BATTERY_ID, - "MasterMcuHardwareVersion"); - @Test public void testSerialNum() throws Exception { var battery = new BatteryFeneconCommercialImpl(); @@ -41,11 +31,11 @@ public void testSerialNum() throws Exception { var componentTest = new ComponentTest(battery) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // - .addComponent(new DummyInputOutput(IO_ID))// + .addReference("setModbus", new DummyModbusBridge("modbus0")) // + .addComponent(new DummyInputOutput("io0"))// .activate(MyConfig.create() // - .setId(BATTERY_ID) // - .setModbusId(MODBUS_ID) // + .setId("battery0") // + .setModbusId("modbus0") // .setModbusUnitId(0) // .setBatteryStartStopRelay("io0/InputOutput0")// .setStartStop(StartStopConfig.AUTO) // @@ -56,10 +46,10 @@ public void testSerialNum() throws Exception { .input(NUMBER_OF_TOWERS, TOWERS) // .input(NUMBER_OF_MODULES_PER_TOWER, MODULES) // .input(NUMBER_OF_CELLS_PER_MODULE, CELLS) // - .input(SUB_MASTER_HARDWARE_VERSION, "109101BM60")); + .input("battery0", "Tower0SubMasterHardwareVersion", "109101BM60")); checkDynamicChannels(battery, TOWERS, MODULES, CELLS / MODULES); - assertEquals("011910MB06", BatteryFeneconCommercialImpl.VERSION_CONVERTER.elementToChannel("109101BM60")); + assertEquals("011910MB06", VERSION_CONVERTER.elementToChannel("109101BM60")); componentTest.next(new TestCase()); componentTest.next(new TestCase()); @@ -72,7 +62,7 @@ public void testSerialNum() throws Exception { .input(NUMBER_OF_CELLS_PER_MODULE, CELLS) // .input(MASTER_MCU_HARDWARE_VERSION, "100201MS50")); - assertEquals("012010SM05", BatteryFeneconCommercialImpl.VERSION_CONVERTER.elementToChannel("100201MS50")); + assertEquals("012010SM05", VERSION_CONVERTER.elementToChannel("100201MS50")); } /** diff --git a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/FeneconHomeBatteryProtection64.java b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/FeneconHomeBatteryProtection64.java index bbad1e67bde..65dec26fc83 100644 --- a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/FeneconHomeBatteryProtection64.java +++ b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/FeneconHomeBatteryProtection64.java @@ -25,8 +25,8 @@ public PolyLine getChargeVoltageToPercent() { .addPoint(Math.nextUp(3000), 1) // .addPoint(3450, 1) // .addPoint(3540, 0.08) // - .addPoint(Math.nextDown(3550), 0.08) // - .addPoint(3550, 0) // + .addPoint(Math.nextDown(3580), 0.08) // + .addPoint(3580, 0) // .build(); } @@ -70,7 +70,7 @@ public PolyLine getDischargeSocToPercent() { @Override public ForceDischarge.Params getForceDischargeParams() { - return new ForceDischarge.Params(3600, 3540, 3450); + return new ForceDischarge.Params(3630, 3540, 3450); } @Override diff --git a/io.openems.edge.battery.fenecon.home/test/io/openems/edge/battery/fenecon/home/BatteryFeneconHomeImplTest.java b/io.openems.edge.battery.fenecon.home/test/io/openems/edge/battery/fenecon/home/BatteryFeneconHomeImplTest.java index 432eccdcb6e..de0aa103841 100644 --- a/io.openems.edge.battery.fenecon.home/test/io/openems/edge/battery/fenecon/home/BatteryFeneconHomeImplTest.java +++ b/io.openems.edge.battery.fenecon.home/test/io/openems/edge/battery/fenecon/home/BatteryFeneconHomeImplTest.java @@ -1,21 +1,38 @@ package io.openems.edge.battery.fenecon.home; +import static io.openems.edge.battery.api.Battery.ChannelId.CHARGE_MAX_CURRENT; +import static io.openems.edge.battery.api.Battery.ChannelId.CURRENT; +import static io.openems.edge.battery.api.Battery.ChannelId.MAX_CELL_VOLTAGE; +import static io.openems.edge.battery.api.Battery.ChannelId.MIN_CELL_VOLTAGE; +import static io.openems.edge.battery.api.Battery.ChannelId.SOC; +import static io.openems.edge.battery.fenecon.home.BatteryFeneconHome.ChannelId.BMS_CONTROL; +import static io.openems.edge.battery.fenecon.home.BatteryFeneconHome.ChannelId.LOW_MIN_VOLTAGE_FAULT; +import static io.openems.edge.battery.fenecon.home.BatteryFeneconHome.ChannelId.LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED; +import static io.openems.edge.battery.fenecon.home.BatteryFeneconHome.ChannelId.LOW_MIN_VOLTAGE_WARNING; +import static io.openems.edge.battery.fenecon.home.BatteryFeneconHome.ChannelId.NUMBER_OF_MODULES_PER_TOWER; +import static io.openems.edge.battery.fenecon.home.BatteryFeneconHome.ChannelId.NUMBER_OF_TOWERS; +import static io.openems.edge.battery.fenecon.home.BatteryFeneconHome.ChannelId.STATE_MACHINE; +import static io.openems.edge.battery.fenecon.home.BatteryFeneconHome.ChannelId.TOWER_0_BMS_SOFTWARE_VERSION; +import static io.openems.edge.battery.fenecon.home.BatteryFeneconHome.ChannelId.TOWER_1_BMS_SOFTWARE_VERSION; +import static io.openems.edge.battery.fenecon.home.BatteryFeneconHome.ChannelId.TOWER_2_BMS_SOFTWARE_VERSION; +import static io.openems.edge.battery.fenecon.home.BatteryFeneconHome.ChannelId.TOWER_3_BMS_SOFTWARE_VERSION; +import static io.openems.edge.battery.fenecon.home.BatteryFeneconHome.ChannelId.TOWER_4_BMS_SOFTWARE_VERSION; +import static io.openems.edge.battery.fenecon.home.BatteryFeneconHomeImpl.DEFAULT_CRITICAL_MIN_VOLTAGE; +import static io.openems.edge.battery.fenecon.home.BatteryFeneconHomeImpl.TIMEOUT; +import static io.openems.edge.battery.protection.BatteryProtection.ChannelId.BP_CHARGE_BMS; +import static io.openems.edge.battery.protection.BatteryProtection.ChannelId.BP_CHARGE_MAX_SOC; +import static io.openems.edge.bridge.modbus.api.ModbusComponent.ChannelId.MODBUS_COMMUNICATION_FAILED; +import static io.openems.edge.common.test.TestUtils.createDummyClock; +import static io.openems.edge.io.test.DummyInputOutput.ChannelId.INPUT_OUTPUT4; +import static java.lang.Math.round; +import static java.time.temporal.ChronoUnit.SECONDS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; -import java.time.Instant; -import java.time.ZoneOffset; -import java.time.temporal.ChronoUnit; - import org.junit.Test; import io.openems.common.function.ThrowingRunnable; -import io.openems.common.test.TimeLeapClock; -import io.openems.common.types.ChannelAddress; -import io.openems.edge.battery.api.Battery; -import io.openems.edge.battery.fenecon.home.statemachine.StateMachine; -import io.openems.edge.battery.protection.BatteryProtection; -import io.openems.edge.bridge.modbus.api.ModbusComponent; +import io.openems.edge.battery.fenecon.home.statemachine.StateMachine.State; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.startstop.StartStopConfig; import io.openems.edge.common.test.AbstractComponentTest.TestCase; @@ -26,51 +43,6 @@ public class BatteryFeneconHomeImplTest { - private static final String BATTERY_ID = "battery0"; - private static final String MODBUS_ID = "modbus0"; - private static final String IO_ID = "io0"; - - private static final ChannelAddress STATE_MACHINE = new ChannelAddress(BATTERY_ID, - BatteryFeneconHome.ChannelId.STATE_MACHINE.id()); - private static final ChannelAddress LOW_MIN_VOLTAGE_WARNING = new ChannelAddress(BATTERY_ID, - BatteryFeneconHome.ChannelId.LOW_MIN_VOLTAGE_WARNING.id()); - private static final ChannelAddress LOW_MIN_VOLTAGE_FAULT = new ChannelAddress(BATTERY_ID, - BatteryFeneconHome.ChannelId.LOW_MIN_VOLTAGE_FAULT.id()); - private static final ChannelAddress LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED = new ChannelAddress(BATTERY_ID, - BatteryFeneconHome.ChannelId.LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED.id()); - private static final ChannelAddress MODBUS_COMMUNICATION_FAILED = new ChannelAddress(BATTERY_ID, - ModbusComponent.ChannelId.MODBUS_COMMUNICATION_FAILED.id()); - private static final ChannelAddress BMS_CONTROL = new ChannelAddress(BATTERY_ID, - BatteryFeneconHome.ChannelId.BMS_CONTROL.id()); - private static final ChannelAddress BP_CHARGE_BMS = new ChannelAddress(BATTERY_ID, - BatteryProtection.ChannelId.BP_CHARGE_BMS.id()); - private static final ChannelAddress MAX_CELL_VOLTAGE = new ChannelAddress(BATTERY_ID, - Battery.ChannelId.MAX_CELL_VOLTAGE.id()); - private static final ChannelAddress CHARGE_MAX_CURRENT = new ChannelAddress(BATTERY_ID, - Battery.ChannelId.CHARGE_MAX_CURRENT.id()); - private static final ChannelAddress CURRENT = new ChannelAddress(BATTERY_ID, Battery.ChannelId.CURRENT.id()); - private static final ChannelAddress MIN_CELL_VOLTAGE = new ChannelAddress(BATTERY_ID, - Battery.ChannelId.MIN_CELL_VOLTAGE.id()); - private static final ChannelAddress TOWER_0_BMS_SOFTWARE_VERSION = new ChannelAddress(BATTERY_ID, - BatteryFeneconHome.ChannelId.TOWER_0_BMS_SOFTWARE_VERSION.id()); - private static final ChannelAddress TOWER_1_BMS_SOFTWARE_VERSION = new ChannelAddress(BATTERY_ID, - BatteryFeneconHome.ChannelId.TOWER_1_BMS_SOFTWARE_VERSION.id()); - private static final ChannelAddress TOWER_2_BMS_SOFTWARE_VERSION = new ChannelAddress(BATTERY_ID, - BatteryFeneconHome.ChannelId.TOWER_2_BMS_SOFTWARE_VERSION.id()); - private static final ChannelAddress TOWER_3_BMS_SOFTWARE_VERSION = new ChannelAddress(BATTERY_ID, - BatteryFeneconHome.ChannelId.TOWER_3_BMS_SOFTWARE_VERSION.id()); - private static final ChannelAddress TOWER_4_BMS_SOFTWARE_VERSION = new ChannelAddress(BATTERY_ID, - BatteryFeneconHome.ChannelId.TOWER_4_BMS_SOFTWARE_VERSION.id()); - private static final ChannelAddress NUMBER_OF_TOWERS = new ChannelAddress(BATTERY_ID, - BatteryFeneconHome.ChannelId.NUMBER_OF_TOWERS.id()); - private static final ChannelAddress NUMBER_OF_MODULES_PER_TOWER = new ChannelAddress(BATTERY_ID, - BatteryFeneconHome.ChannelId.NUMBER_OF_MODULES_PER_TOWER.id()); - private static final ChannelAddress BP_CHARGE_MAX_SOC = new ChannelAddress(BATTERY_ID, - BatteryProtection.ChannelId.BP_CHARGE_MAX_SOC.id()); - private static final ChannelAddress SOC = new ChannelAddress(BATTERY_ID, Battery.ChannelId.SOC.id()); - - private static final ChannelAddress BATTERY_RELAY = new ChannelAddress(IO_ID, "InputOutput4"); - private static ThrowingRunnable assertLog(BatteryFeneconHomeImpl sut, String message) { return () -> assertEquals(message, sut.stateMachine.debugLog()); } @@ -82,41 +54,41 @@ private static ThrowingRunnable assertLog(BatteryFeneconHomeImpl sut, */ @Test public void test() throws Exception { - final var clock = new TimeLeapClock(Instant.parse("2020-01-01T01:00:00.00Z"), ZoneOffset.UTC); + final var clock = createDummyClock(); var sut = new BatteryFeneconHomeImpl(); new ComponentTest(sut) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager(clock)) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // - .addComponent(new DummyInputOutput(IO_ID))// + .addReference("setModbus", new DummyModbusBridge("modbus0")) // + .addComponent(new DummyInputOutput("io0"))// .activate(MyConfig.create() // - .setId(BATTERY_ID) // - .setModbusId(MODBUS_ID) // + .setId("battery0") // + .setModbusId("modbus0") // .setModbusUnitId(0) // .setStartStop(StartStopConfig.START) // .setBatteryStartUpRelay("io0/InputOutput4")// .build())// .next(new TestCase() // .inputForce(MODBUS_COMMUNICATION_FAILED, true) // - .input(BATTERY_RELAY, false) // Switch OFF + .input("io0", INPUT_OUTPUT4, false) // Switch OFF .input(BMS_CONTROL, false) // Switched OFF .onBeforeProcessImage(assertLog(sut, "Undefined")) // - .output(STATE_MACHINE, StateMachine.State.UNDEFINED)) // + .output(STATE_MACHINE, State.UNDEFINED)) // .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-Undefined")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .output(STATE_MACHINE, State.GO_RUNNING)) // .next(new TestCase()// .onBeforeProcessImage(assertLog(sut, "GoRunning-StartUpRelayOn"))) // .next(new TestCase()// - .input(BATTERY_RELAY, true) // Switch ON + .input("io0", INPUT_OUTPUT4, true) // Switch ON .onBeforeProcessImage(assertLog(sut, "GoRunning-StartUpRelayOn"))) // .next(new TestCase()// - .input(BATTERY_RELAY, true) // Switch ON + .input("io0", INPUT_OUTPUT4, true) // Switch ON .onBeforeProcessImage(assertLog(sut, "GoRunning-StartUpRelayHold")) - .onAfterProcessImage(() -> clock.leap(11, ChronoUnit.SECONDS))) // + .onAfterProcessImage(() -> clock.leap(11, SECONDS))) // .next(new TestCase() // - .input(BATTERY_RELAY, false) // Switch OFF + .input("io0", INPUT_OUTPUT4, false) // Switch OFF .onBeforeProcessImage(assertLog(sut, "GoRunning-StartUpRelayOff"))) // .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-RetryModbusCommunication"))) // @@ -129,17 +101,17 @@ public void test() throws Exception { .next(new TestCase()// .onBeforeProcessImage(assertLog(sut, "Running")) // - .output(STATE_MACHINE, StateMachine.State.RUNNING)) // + .output(STATE_MACHINE, State.RUNNING)) // // Ramp-Up ChargeMaxCurrent (0.1 A / Second) .next(new TestCase() // .input(BP_CHARGE_BMS, 40) // .input(MAX_CELL_VOLTAGE, 3000)) // .next(new TestCase("Ramp up") // - .timeleap(clock, 100, ChronoUnit.SECONDS) // + .timeleap(clock, 100, SECONDS) // .output(CHARGE_MAX_CURRENT, 10)) // .next(new TestCase() // - .timeleap(clock, 300, ChronoUnit.SECONDS) // + .timeleap(clock, 300, SECONDS) // .output(CHARGE_MAX_CURRENT, 40)) // Full Battery @@ -151,7 +123,7 @@ public void test() throws Exception { .next(new TestCase() // .input(BP_CHARGE_BMS, 40)) // .next(new TestCase() // - .timeleap(clock, 100, ChronoUnit.SECONDS) // + .timeleap(clock, 100, SECONDS) // .output(CHARGE_MAX_CURRENT, 25)) // ; } @@ -163,54 +135,54 @@ public void test() throws Exception { */ @Test public void test2() throws Exception { - final var clock = new TimeLeapClock(Instant.parse("2020-01-01T01:00:00.00Z"), ZoneOffset.UTC); + final var clock = createDummyClock(); var sut = new BatteryFeneconHomeImpl(); new ComponentTest(sut) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager(clock)) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // - .addComponent(new DummyInputOutput(IO_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // + .addComponent(new DummyInputOutput("io0")) // .activate(MyConfig.create() // - .setId(BATTERY_ID) // - .setModbusId(MODBUS_ID) // + .setId("battery0") // + .setModbusId("modbus0") // .setModbusUnitId(0) // .setStartStop(StartStopConfig.START) // .setBatteryStartUpRelay("io0/InputOutput4")// .build())// .next(new TestCase()// - .input(BATTERY_RELAY, true) // + .input("io0", INPUT_OUTPUT4, true) // .input(BMS_CONTROL, false) // Switched Off - .output(STATE_MACHINE, StateMachine.State.UNDEFINED))// + .output(STATE_MACHINE, State.UNDEFINED))// .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-Undefined")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .output(STATE_MACHINE, State.GO_RUNNING)) // .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-StartUpRelayOn")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING))// + .output(STATE_MACHINE, State.GO_RUNNING))// .next(new TestCase()// - .input(BATTERY_RELAY, true) // Switch ON + .input("io0", INPUT_OUTPUT4, true) // Switch ON .onBeforeProcessImage(assertLog(sut, "GoRunning-StartUpRelayHold")) - .onAfterProcessImage(() -> clock.leap(11, ChronoUnit.SECONDS))) // + .onAfterProcessImage(() -> clock.leap(11, SECONDS))) // .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-StartUpRelayOff")) // .input(BMS_CONTROL, true) // Switched On - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .output(STATE_MACHINE, State.GO_RUNNING)) // .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-StartUpRelayOff")) // - .input(BATTERY_RELAY, false) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .input("io0", INPUT_OUTPUT4, false) // + .output(STATE_MACHINE, State.GO_RUNNING)) // .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-RetryModbusCommunication")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .output(STATE_MACHINE, State.GO_RUNNING)) // .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-WaitForBmsControl")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .output(STATE_MACHINE, State.GO_RUNNING)) // .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-WaitForModbusCommunication")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .output(STATE_MACHINE, State.GO_RUNNING)) // .next(new TestCase() // - .output(STATE_MACHINE, StateMachine.State.RUNNING)); + .output(STATE_MACHINE, State.RUNNING)); } /** @@ -225,37 +197,37 @@ public void test3() throws Exception { new ComponentTest(sut) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // - .addComponent(new DummyInputOutput(IO_ID))// + .addReference("setModbus", new DummyModbusBridge("modbus0")) // + .addComponent(new DummyInputOutput("io0"))// .activate(MyConfig.create() // - .setId(BATTERY_ID) // - .setModbusId(MODBUS_ID) // + .setId("battery0") // + .setModbusId("modbus0") // .setModbusUnitId(0) // .setStartStop(StartStopConfig.START) // .setBatteryStartUpRelay("io0/InputOutput4")// .build()) // .next(new TestCase() // - .input(BATTERY_RELAY, false) // + .input("io0", INPUT_OUTPUT4, false) // .input(BMS_CONTROL, true) // Switched On - .output(STATE_MACHINE, StateMachine.State.UNDEFINED))// + .output(STATE_MACHINE, State.UNDEFINED))// .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-Undefined")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .output(STATE_MACHINE, State.GO_RUNNING)) // .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-StartUpRelayOff")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING))// + .output(STATE_MACHINE, State.GO_RUNNING))// .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-RetryModbusCommunication")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING))// + .output(STATE_MACHINE, State.GO_RUNNING))// .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-WaitForBmsControl")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .output(STATE_MACHINE, State.GO_RUNNING)) // .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-WaitForModbusCommunication")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .output(STATE_MACHINE, State.GO_RUNNING)) // .next(new TestCase() // - .output(STATE_MACHINE, StateMachine.State.RUNNING)); + .output(STATE_MACHINE, State.RUNNING)); } /** @@ -265,53 +237,53 @@ public void test3() throws Exception { */ @Test public void test4() throws Exception { - final var clock = new TimeLeapClock(Instant.parse("2020-01-01T01:00:00.00Z"), ZoneOffset.UTC); + final var clock = createDummyClock(); var sut = new BatteryFeneconHomeImpl(); new ComponentTest(sut) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager(clock)) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // - .addComponent(new DummyInputOutput(IO_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // + .addComponent(new DummyInputOutput("io0")) // .activate(MyConfig.create() // - .setId(BATTERY_ID) // - .setModbusId(MODBUS_ID) // + .setId("battery0") // + .setModbusId("modbus0") // .setModbusUnitId(0) // .setStartStop(StartStopConfig.START) // .setBatteryStartUpRelay("io0/InputOutput4") // .build()) // .next(new TestCase() // - .input(BATTERY_RELAY, false) // + .input("io0", INPUT_OUTPUT4, false) // .input(BMS_CONTROL, false) // Switched Off - .output(STATE_MACHINE, StateMachine.State.UNDEFINED)) // + .output(STATE_MACHINE, State.UNDEFINED)) // .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-Undefined")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .output(STATE_MACHINE, State.GO_RUNNING)) // .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-StartUpRelayOn")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .output(STATE_MACHINE, State.GO_RUNNING)) // .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-StartUpRelayOn")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .output(STATE_MACHINE, State.GO_RUNNING)) // // Ex; after long time if hard switch turned on.... .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-StartUpRelayOn")) // .input(BMS_CONTROL, true) // Switched On - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .output(STATE_MACHINE, State.GO_RUNNING)) // .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-StartUpRelayOn")) // - .input(BATTERY_RELAY, true) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .input("io0", INPUT_OUTPUT4, true) // + .output(STATE_MACHINE, State.GO_RUNNING)) // .next(new TestCase()// - .input(BATTERY_RELAY, true) // Switch ON + .input("io0", INPUT_OUTPUT4, true) // Switch ON .onBeforeProcessImage(assertLog(sut, "GoRunning-StartUpRelayHold")) - .onAfterProcessImage(() -> clock.leap(11, ChronoUnit.SECONDS))) // + .onAfterProcessImage(() -> clock.leap(11, SECONDS))) // .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-StartUpRelayOff")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING))// + .output(STATE_MACHINE, State.GO_RUNNING))// .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-StartUpRelayOff")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)); // + .output(STATE_MACHINE, State.GO_RUNNING)); // } @Test @@ -334,224 +306,221 @@ public void testGetHardwareTypeFromRegisterValue() { @Test public void testMinVoltageGoStopped() throws Exception { - final var clock = new TimeLeapClock(Instant.parse("2020-01-01T01:00:00.00Z"), ZoneOffset.UTC); + final var clock = createDummyClock(); var sut = new BatteryFeneconHomeImpl(); new ComponentTest(sut) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager(clock)) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // - .addComponent(new DummyInputOutput(IO_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // + .addComponent(new DummyInputOutput("io0")) // .activate(MyConfig.create() // - .setId(BATTERY_ID) // - .setModbusId(MODBUS_ID) // + .setId("battery0") // + .setModbusId("modbus0") // .setModbusUnitId(0) // .setStartStop(StartStopConfig.START) // .setBatteryStartUpRelay("io0/InputOutput4")// .build())// .next(new TestCase() // - .input(BATTERY_RELAY, false) // + .input("io0", INPUT_OUTPUT4, false) // .input(BMS_CONTROL, true) // Switched On - .output(STATE_MACHINE, StateMachine.State.UNDEFINED))// + .output(STATE_MACHINE, State.UNDEFINED))// .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-Undefined")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .output(STATE_MACHINE, State.GO_RUNNING)) // .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-StartUpRelayOff")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING))// + .output(STATE_MACHINE, State.GO_RUNNING))// .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-RetryModbusCommunication")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING))// + .output(STATE_MACHINE, State.GO_RUNNING))// .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-WaitForBmsControl")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .output(STATE_MACHINE, State.GO_RUNNING)) // .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-WaitForModbusCommunication")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .output(STATE_MACHINE, State.GO_RUNNING)) // .next(new TestCase() // - .output(STATE_MACHINE, StateMachine.State.RUNNING)) + .output(STATE_MACHINE, State.RUNNING)) /* * Critical min voltage */ .next(new TestCase("MinCellVoltage below critical value") // - .input(MIN_CELL_VOLTAGE, (BatteryFeneconHomeImpl.DEFAULT_CRITICAL_MIN_VOLTAGE - 100)) // + .input(MIN_CELL_VOLTAGE, (DEFAULT_CRITICAL_MIN_VOLTAGE - 100)) // .input(CURRENT, 0) // .output(LOW_MIN_VOLTAGE_WARNING, true) // .output(LOW_MIN_VOLTAGE_FAULT, false) // - .output(STATE_MACHINE, StateMachine.State.RUNNING) // + .output(STATE_MACHINE, State.RUNNING) // .output(LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED, false) // - .onAfterControllersCallbacks( - () -> clock.leap(BatteryFeneconHomeImpl.TIMEOUT - 10, ChronoUnit.SECONDS))) // + .onAfterControllersCallbacks(() -> clock.leap(TIMEOUT - 10, SECONDS))) // .next(new TestCase("MinCellVoltage below critical value - charging resets time") // - .input(MIN_CELL_VOLTAGE, (BatteryFeneconHomeImpl.DEFAULT_CRITICAL_MIN_VOLTAGE - 100)) // + .input(MIN_CELL_VOLTAGE, (DEFAULT_CRITICAL_MIN_VOLTAGE - 100)) // .input(CURRENT, -300) // .output(LOW_MIN_VOLTAGE_WARNING, true) // .output(LOW_MIN_VOLTAGE_FAULT, false) // .output(LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED, false)) // .next(new TestCase("MinCellVoltage below critical value - timer starts again") // .input(CURRENT, 0) // - .input(MIN_CELL_VOLTAGE, (BatteryFeneconHomeImpl.DEFAULT_CRITICAL_MIN_VOLTAGE - 100)) // + .input(MIN_CELL_VOLTAGE, (DEFAULT_CRITICAL_MIN_VOLTAGE - 100)) // .output(LOW_MIN_VOLTAGE_WARNING, true) // .output(LOW_MIN_VOLTAGE_FAULT, false) // .output(LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED, false) // - .onAfterControllersCallbacks( - () -> clock.leap(BatteryFeneconHomeImpl.TIMEOUT - 10, ChronoUnit.SECONDS))) // + .onAfterControllersCallbacks(() -> clock.leap(TIMEOUT - 10, SECONDS))) // .next(new TestCase("MinCellVoltage below critical value - time not passed") // .input(CURRENT, 0) // - .input(MIN_CELL_VOLTAGE, (BatteryFeneconHomeImpl.DEFAULT_CRITICAL_MIN_VOLTAGE - 100)) // + .input(MIN_CELL_VOLTAGE, (DEFAULT_CRITICAL_MIN_VOLTAGE - 100)) // .output(LOW_MIN_VOLTAGE_WARNING, true) // .output(LOW_MIN_VOLTAGE_FAULT, false) // .output(LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED, false) // - .onAfterControllersCallbacks(() -> clock.leap(15, ChronoUnit.SECONDS))) // + .onAfterControllersCallbacks(() -> clock.leap(15, SECONDS))) // .next(new TestCase("MinCellVoltage below critical value - time passed") // .input(CURRENT, 0) // - .input(MIN_CELL_VOLTAGE, (BatteryFeneconHomeImpl.DEFAULT_CRITICAL_MIN_VOLTAGE - 100)) // + .input(MIN_CELL_VOLTAGE, (DEFAULT_CRITICAL_MIN_VOLTAGE - 100)) // .output(LOW_MIN_VOLTAGE_FAULT, true) // .output(LOW_MIN_VOLTAGE_WARNING, false) // .output(LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED, false) // - .output(STATE_MACHINE, StateMachine.State.RUNNING)) // + .output(STATE_MACHINE, State.RUNNING)) // .next(new TestCase("MinCellVoltage below critical value - error") // .input(LOW_MIN_VOLTAGE_FAULT, true) // .input(CURRENT, 0) // - .input(MIN_CELL_VOLTAGE, (BatteryFeneconHomeImpl.DEFAULT_CRITICAL_MIN_VOLTAGE - 100)) // + .input(MIN_CELL_VOLTAGE, (DEFAULT_CRITICAL_MIN_VOLTAGE - 100)) // .output(LOW_MIN_VOLTAGE_FAULT, true) // .output(LOW_MIN_VOLTAGE_WARNING, false) // .output(LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED, false)) // .next(new TestCase() // - .output(STATE_MACHINE, StateMachine.State.ERROR)) // + .output(STATE_MACHINE, State.ERROR)) // .next(new TestCase("MinCellVoltage below critical value - go stopped") // .input(LOW_MIN_VOLTAGE_FAULT, true) // .input(CURRENT, 0) // // MinCellVoltage would be null, but there is not DummyTimedata for not to test // "getPastValues" - .input(MIN_CELL_VOLTAGE, (BatteryFeneconHomeImpl.DEFAULT_CRITICAL_MIN_VOLTAGE - 100)) // + .input(MIN_CELL_VOLTAGE, (DEFAULT_CRITICAL_MIN_VOLTAGE - 100)) // .output(LOW_MIN_VOLTAGE_FAULT, true) // .output(LOW_MIN_VOLTAGE_WARNING, false) // .output(LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED, false) // - .output(STATE_MACHINE, StateMachine.State.GO_STOPPED) // - .onAfterControllersCallbacks(() -> clock.leap(2_100, ChronoUnit.SECONDS))) // 35 minutes + .output(STATE_MACHINE, State.GO_STOPPED) // + .onAfterControllersCallbacks(() -> clock.leap(2_100, SECONDS))) // 35 minutes .next(new TestCase() // .input(MODBUS_COMMUNICATION_FAILED, true) // ) // .next(new TestCase("MinCellVoltage below critical value - stopped") // .input(CURRENT, 0) // .input(MODBUS_COMMUNICATION_FAILED, true) // - .input(MIN_CELL_VOLTAGE, (BatteryFeneconHomeImpl.DEFAULT_CRITICAL_MIN_VOLTAGE - 100)) // + .input(MIN_CELL_VOLTAGE, (DEFAULT_CRITICAL_MIN_VOLTAGE - 100)) // .output(LOW_MIN_VOLTAGE_WARNING, false) // .output(LOW_MIN_VOLTAGE_FAULT, false) // .output(LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED, true) // - .output(STATE_MACHINE, StateMachine.State.STOPPED) // + .output(STATE_MACHINE, State.STOPPED) // ); } @Test public void testMinVoltageCharging() throws Exception { - final var clock = new TimeLeapClock(Instant.parse("2020-01-01T01:00:00.00Z"), ZoneOffset.UTC); + final var clock = createDummyClock(); var sut = new BatteryFeneconHomeImpl(); new ComponentTest(sut) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager(clock)) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // - .addComponent(new DummyInputOutput(IO_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // + .addComponent(new DummyInputOutput("io0")) // .activate(MyConfig.create() // - .setId(BATTERY_ID) // - .setModbusId(MODBUS_ID) // + .setId("battery0") // + .setModbusId("modbus0") // .setModbusUnitId(0) // .setStartStop(StartStopConfig.START) // .setBatteryStartUpRelay("io0/InputOutput4")// .build())// .next(new TestCase() // - .input(BATTERY_RELAY, false) // + .input("io0", INPUT_OUTPUT4, false) // .input(BMS_CONTROL, true) // Switched On - .output(STATE_MACHINE, StateMachine.State.UNDEFINED))// + .output(STATE_MACHINE, State.UNDEFINED))// .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-Undefined")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .output(STATE_MACHINE, State.GO_RUNNING)) // .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-StartUpRelayOff")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING))// + .output(STATE_MACHINE, State.GO_RUNNING))// .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-RetryModbusCommunication")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING))// + .output(STATE_MACHINE, State.GO_RUNNING))// .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-WaitForBmsControl")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .output(STATE_MACHINE, State.GO_RUNNING)) // .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-WaitForModbusCommunication")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .output(STATE_MACHINE, State.GO_RUNNING)) // .next(new TestCase() // - .output(STATE_MACHINE, StateMachine.State.RUNNING)) + .output(STATE_MACHINE, State.RUNNING)) /* * Critical min voltage */ .next(new TestCase("MinCellVoltage below critical value") // - .input(MIN_CELL_VOLTAGE, (BatteryFeneconHomeImpl.DEFAULT_CRITICAL_MIN_VOLTAGE - 100)) // + .input(MIN_CELL_VOLTAGE, (DEFAULT_CRITICAL_MIN_VOLTAGE - 100)) // .input(CURRENT, 0) // .output(LOW_MIN_VOLTAGE_WARNING, true) // .output(LOW_MIN_VOLTAGE_FAULT, false) // - .output(STATE_MACHINE, StateMachine.State.RUNNING) // + .output(STATE_MACHINE, State.RUNNING) // .output(LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED, false) // - .onAfterControllersCallbacks( - () -> clock.leap(BatteryFeneconHomeImpl.TIMEOUT - 10, ChronoUnit.SECONDS))) // + .onAfterControllersCallbacks(() -> clock.leap(TIMEOUT - 10, SECONDS))) // .next(new TestCase("MinCellVoltage below critical value - charging resets time") // - .input(MIN_CELL_VOLTAGE, (BatteryFeneconHomeImpl.DEFAULT_CRITICAL_MIN_VOLTAGE - 100)) // + .input(MIN_CELL_VOLTAGE, (DEFAULT_CRITICAL_MIN_VOLTAGE - 100)) // .input(CURRENT, -300) // .output(LOW_MIN_VOLTAGE_WARNING, true) // .output(LOW_MIN_VOLTAGE_FAULT, false) // - .output(STATE_MACHINE, StateMachine.State.RUNNING) // + .output(STATE_MACHINE, State.RUNNING) // .output(LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED, false)) // .next(new TestCase("MinCellVoltage below critical value - charging") // .input(CURRENT, -2000) // - .input(MIN_CELL_VOLTAGE, (BatteryFeneconHomeImpl.DEFAULT_CRITICAL_MIN_VOLTAGE + 50)) // + .input(MIN_CELL_VOLTAGE, (DEFAULT_CRITICAL_MIN_VOLTAGE + 50)) // .output(LOW_MIN_VOLTAGE_WARNING, false) // .output(LOW_MIN_VOLTAGE_FAULT, false) // - .output(STATE_MACHINE, StateMachine.State.RUNNING) // + .output(STATE_MACHINE, State.RUNNING) // .output(LOW_MIN_VOLTAGE_FAULT_BATTERY_STOPPED, false) // ); } @Test public void testNumberOfTowers() throws Exception { - final var clock = new TimeLeapClock(Instant.parse("2020-01-01T01:00:00.00Z"), ZoneOffset.UTC); + final var clock = createDummyClock(); var sut = new BatteryFeneconHomeImpl(); new ComponentTest(sut) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager(clock)) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // - .addComponent(new DummyInputOutput(IO_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // + .addComponent(new DummyInputOutput("io0")) // .activate(MyConfig.create() // - .setId(BATTERY_ID) // - .setModbusId(MODBUS_ID) // + .setId("battery0") // + .setModbusId("modbus0") // .setModbusUnitId(0) // .setStartStop(StartStopConfig.START) // - .setBatteryStartUpRelay("io0/InputOutput4")// - .build())// + .setBatteryStartUpRelay("io0/InputOutput4") // + .build()) // .next(new TestCase() // - .input(BATTERY_RELAY, false) // + .input("io0", INPUT_OUTPUT4, false) // .input(BMS_CONTROL, true) // Switched On - .output(STATE_MACHINE, StateMachine.State.UNDEFINED))// + .output(STATE_MACHINE, State.UNDEFINED))// .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-Undefined")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .output(STATE_MACHINE, State.GO_RUNNING)) // .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-StartUpRelayOff")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING))// + .output(STATE_MACHINE, State.GO_RUNNING))// .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-RetryModbusCommunication")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING))// + .output(STATE_MACHINE, State.GO_RUNNING))// .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-WaitForBmsControl")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .output(STATE_MACHINE, State.GO_RUNNING)) // .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-WaitForModbusCommunication")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .output(STATE_MACHINE, State.GO_RUNNING)) // .next(new TestCase() // - .output(STATE_MACHINE, StateMachine.State.RUNNING)) + .output(STATE_MACHINE, State.RUNNING)) .next(new TestCase() // .output(NUMBER_OF_TOWERS, null)) .next(new TestCase() // @@ -610,37 +579,37 @@ public void testBatteryProtectionSocLimitations() throws Exception { new ComponentTest(sut) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // - .addComponent(new DummyInputOutput(IO_ID))// + .addReference("setModbus", new DummyModbusBridge("modbus0")) // + .addComponent(new DummyInputOutput("io0"))// .activate(MyConfig.create() // - .setId(BATTERY_ID) // - .setModbusId(MODBUS_ID) // + .setId("battery0") // + .setModbusId("modbus0") // .setModbusUnitId(0) // .setStartStop(StartStopConfig.START) // .setBatteryStartUpRelay("io0/InputOutput4")// .build()) // .next(new TestCase() // - .input(BATTERY_RELAY, false) // + .input("io0", INPUT_OUTPUT4, false) // .input(BMS_CONTROL, true) // Switched On - .output(STATE_MACHINE, StateMachine.State.UNDEFINED))// + .output(STATE_MACHINE, State.UNDEFINED))// .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-Undefined")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .output(STATE_MACHINE, State.GO_RUNNING)) // .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-StartUpRelayOff")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING))// + .output(STATE_MACHINE, State.GO_RUNNING))// .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-RetryModbusCommunication")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING))// + .output(STATE_MACHINE, State.GO_RUNNING))// .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-WaitForBmsControl")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .output(STATE_MACHINE, State.GO_RUNNING)) // .next(new TestCase() // .onBeforeProcessImage(assertLog(sut, "GoRunning-WaitForModbusCommunication")) // - .output(STATE_MACHINE, StateMachine.State.GO_RUNNING)) // + .output(STATE_MACHINE, State.GO_RUNNING)) // .next(new TestCase() // - .output(STATE_MACHINE, StateMachine.State.RUNNING)) // + .output(STATE_MACHINE, State.RUNNING)) // .next(new TestCase() // .output(BP_CHARGE_MAX_SOC, 40)) // @@ -648,23 +617,23 @@ public void testBatteryProtectionSocLimitations() throws Exception { .input(SOC, 97) // .output(SOC, 97)) // .next(new TestCase() // - .output(BP_CHARGE_MAX_SOC, (int) Math.round(40 * 0.625))) // + .output(BP_CHARGE_MAX_SOC, round(40 * 0.625F))) // .next(new TestCase() // .input(SOC, 98)) // .next(new TestCase() // - .output(BP_CHARGE_MAX_SOC, (int) Math.round(40 * 0.4))) // + .output(BP_CHARGE_MAX_SOC, round(40 * 0.4F))) // .next(new TestCase() // .input(SOC, 99)) // .next(new TestCase() // - .output(BP_CHARGE_MAX_SOC, (int) Math.round(40 * 0.2))) // + .output(BP_CHARGE_MAX_SOC, round(40 * 0.2F))) // .next(new TestCase() // .input(SOC, 100)) // .next(new TestCase() // - .output(BP_CHARGE_MAX_SOC, (int) Math.round(40 * 0.05))) // + .output(BP_CHARGE_MAX_SOC, round(40 * 0.05F))) // .next(new TestCase() // .input(SOC, 99)) // .next(new TestCase() // - .output(BP_CHARGE_MAX_SOC, (int) Math.round(40 * 0.2)) // + .output(BP_CHARGE_MAX_SOC, round(40 * 0.2F)) // ); } } diff --git a/io.openems.edge.battery.fenecon.home/test/io/openems/edge/battery/fenecon/home/TowersAndModulesTest.java b/io.openems.edge.battery.fenecon.home/test/io/openems/edge/battery/fenecon/home/TowersAndModulesTest.java index ff8b7353731..9fff171c345 100644 --- a/io.openems.edge.battery.fenecon.home/test/io/openems/edge/battery/fenecon/home/TowersAndModulesTest.java +++ b/io.openems.edge.battery.fenecon.home/test/io/openems/edge/battery/fenecon/home/TowersAndModulesTest.java @@ -1,11 +1,15 @@ package io.openems.edge.battery.fenecon.home; +import static io.openems.edge.battery.fenecon.home.BatteryFeneconHome.ChannelId.BATTERY_HARDWARE_TYPE; +import static io.openems.edge.battery.fenecon.home.BatteryFeneconHome.ChannelId.NUMBER_OF_MODULES_PER_TOWER; +import static io.openems.edge.battery.fenecon.home.BatteryFeneconHome.ChannelId.TOWER_0_BMS_SOFTWARE_VERSION; +import static io.openems.edge.battery.fenecon.home.BatteryFeneconHome.ChannelId.TOWER_1_BMS_SOFTWARE_VERSION; +import static io.openems.edge.battery.fenecon.home.BatteryFeneconHome.ChannelId.TOWER_2_BMS_SOFTWARE_VERSION; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import org.junit.Test; -import io.openems.common.types.ChannelAddress; import io.openems.edge.battery.api.Battery; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.channel.ChannelId; @@ -17,19 +21,6 @@ public class TowersAndModulesTest { - private static final String BATTERY_ID = "battery0"; - private static final String MODBUS_ID = "modbus0"; - - private static final ChannelAddress NUMBER_OF_MODULES_PER_TOWER = new ChannelAddress(BATTERY_ID, - "NumberOfModulesPerTower"); - private static final ChannelAddress TOWER_0_BMS_SOFTWARE_VERSION = new ChannelAddress(BATTERY_ID, - "Tower0BmsSoftwareVersion"); - private static final ChannelAddress TOWER_1_BMS_SOFTWARE_VERSION = new ChannelAddress(BATTERY_ID, - "Tower1BmsSoftwareVersion"); - private static final ChannelAddress TOWER_2_BMS_SOFTWARE_VERSION = new ChannelAddress(BATTERY_ID, - "Tower2BmsSoftwareVersion"); - private static final ChannelAddress BATTERY_HARDWARE_TYPE = new ChannelAddress(BATTERY_ID, "BatteryHardwareType"); - private static final int TOWERS = 1; private static final int MODULES = 5; private static final int CELLS = 14; @@ -40,10 +31,10 @@ public void testChannelsCreatedDynamically() throws Exception { var componentTest = new ComponentTest(battery) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(BATTERY_ID) // - .setModbusId(MODBUS_ID) // + .setId("battery0") // + .setModbusId("modbus0") // .setModbusUnitId(0) // .setBatteryStartUpRelay("io0/Relay4") // .setStartStop(StartStopConfig.AUTO) // diff --git a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/cluster/versionb/BatterySoltaroClusterVersionBImplTest.java b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/cluster/versionb/BatterySoltaroClusterVersionBImplTest.java index eda7ce07667..be7f6db76ce 100644 --- a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/cluster/versionb/BatterySoltaroClusterVersionBImplTest.java +++ b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/cluster/versionb/BatterySoltaroClusterVersionBImplTest.java @@ -1,9 +1,13 @@ package io.openems.edge.battery.soltaro.cluster.versionb; +import static io.openems.edge.battery.soltaro.cluster.SoltaroCluster.ChannelId.SUB_MASTER_1_COMMUNICATION_FAILURE; +import static io.openems.edge.battery.soltaro.cluster.SoltaroCluster.ChannelId.SUB_MASTER_2_COMMUNICATION_FAILURE; +import static io.openems.edge.battery.soltaro.cluster.SoltaroCluster.ChannelId.SUB_MASTER_3_COMMUNICATION_FAILURE; +import static io.openems.edge.battery.soltaro.cluster.SoltaroCluster.ChannelId.SUB_MASTER_4_COMMUNICATION_FAILURE; +import static io.openems.edge.battery.soltaro.cluster.SoltaroCluster.ChannelId.SUB_MASTER_5_COMMUNICATION_FAILURE; + import org.junit.Test; -import io.openems.common.types.ChannelAddress; -import io.openems.edge.battery.soltaro.cluster.SoltaroCluster; import io.openems.edge.battery.soltaro.common.enums.BatteryState; import io.openems.edge.battery.soltaro.common.enums.ModuleType; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; @@ -14,30 +18,16 @@ public class BatterySoltaroClusterVersionBImplTest { - private static final String BATTERY_ID = "battery0"; - private static final String MODBUS_ID = "modbus0"; - - private static final ChannelAddress SUB_MASTER_1_COMMUNICATION_FAILURE = new ChannelAddress(BATTERY_ID, - SoltaroCluster.ChannelId.SUB_MASTER_1_COMMUNICATION_FAILURE.id()); - private static final ChannelAddress SUB_MASTER_2_COMMUNICATION_FAILURE = new ChannelAddress(BATTERY_ID, - SoltaroCluster.ChannelId.SUB_MASTER_2_COMMUNICATION_FAILURE.id()); - private static final ChannelAddress SUB_MASTER_3_COMMUNICATION_FAILURE = new ChannelAddress(BATTERY_ID, - SoltaroCluster.ChannelId.SUB_MASTER_3_COMMUNICATION_FAILURE.id()); - private static final ChannelAddress SUB_MASTER_4_COMMUNICATION_FAILURE = new ChannelAddress(BATTERY_ID, - SoltaroCluster.ChannelId.SUB_MASTER_4_COMMUNICATION_FAILURE.id()); - private static final ChannelAddress SUB_MASTER_5_COMMUNICATION_FAILURE = new ChannelAddress(BATTERY_ID, - SoltaroCluster.ChannelId.SUB_MASTER_5_COMMUNICATION_FAILURE.id()); - @Test public void test() throws Exception { var sut = new BatterySoltaroClusterVersionBImpl(); new ComponentTest(sut) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(BATTERY_ID) // - .setModbusId(MODBUS_ID) // + .setId("battery0") // + .setModbusId("modbus0") // .setModbusUnitId(0) // .setNumberOfSlaves(0) // .setModuleType(ModuleType.MODULE_3_5_KWH) // diff --git a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/cluster/versionc/BatterySoltaroClusterVersionCImplTest.java b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/cluster/versionc/BatterySoltaroClusterVersionCImplTest.java index aaffbc2cc9e..ebcb21122ce 100644 --- a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/cluster/versionc/BatterySoltaroClusterVersionCImplTest.java +++ b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/cluster/versionc/BatterySoltaroClusterVersionCImplTest.java @@ -9,17 +9,14 @@ public class BatterySoltaroClusterVersionCImplTest { - private static final String BATTERY_ID = "battery0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new BatterySoltaroClusterVersionCImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(BATTERY_ID) // - .setModbusId(MODBUS_ID) // + .setId("battery0") // + .setModbusId("modbus0") // .setStartStop(StartStopConfig.AUTO) // .build()) // ; diff --git a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/single/versiona/BatterySoltaroSingleRackVersionAImplTest.java b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/single/versiona/BatterySoltaroSingleRackVersionAImplTest.java index 443dbce24c9..daccfa35f66 100644 --- a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/single/versiona/BatterySoltaroSingleRackVersionAImplTest.java +++ b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/single/versiona/BatterySoltaroSingleRackVersionAImplTest.java @@ -9,17 +9,14 @@ public class BatterySoltaroSingleRackVersionAImplTest { - private static final String BATTERY_ID = "battery0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new BatterySoltaroSingleRackVersionAImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(BATTERY_ID) // - .setModbusId(MODBUS_ID) // + .setId("battery0") // + .setModbusId("modbus0") // .setModbusUnitId(0) // .setErrorLevel2Delay(0) // .setMaxStartTime(0) // diff --git a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/single/versionb/BatterySoltaroSingleRackVersionBImplTest.java b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/single/versionb/BatterySoltaroSingleRackVersionBImplTest.java index b2b33ff92fb..3fce33da342 100644 --- a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/single/versionb/BatterySoltaroSingleRackVersionBImplTest.java +++ b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/single/versionb/BatterySoltaroSingleRackVersionBImplTest.java @@ -11,18 +11,15 @@ public class BatterySoltaroSingleRackVersionBImplTest { - private static final String BATTERY_ID = "battery0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new BatterySoltaroSingleRackVersionBImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(BATTERY_ID) // - .setModbusId(MODBUS_ID) // + .setId("battery0") // + .setModbusId("modbus0") // .setModbusUnitId(0) // .setErrorLevel2Delay(0) // .setMaxStartTime(0) // diff --git a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/single/versionc/BatterySoltaroSingleRackVersionCImplTest.java b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/single/versionc/BatterySoltaroSingleRackVersionCImplTest.java index 82e9a8c75d9..504d8d66b2a 100644 --- a/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/single/versionc/BatterySoltaroSingleRackVersionCImplTest.java +++ b/io.openems.edge.battery.soltaro/test/io/openems/edge/battery/soltaro/single/versionc/BatterySoltaroSingleRackVersionCImplTest.java @@ -9,17 +9,14 @@ public class BatterySoltaroSingleRackVersionCImplTest { - private static final String BATTERY_ID = "battery0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new BatterySoltaroSingleRackVersionCImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(BATTERY_ID) // - .setModbusId(MODBUS_ID) // + .setId("battery0") // + .setModbusId("modbus0") // .setModbusUnitId(0) // .setStartStop(StartStopConfig.AUTO) // .build()) // diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/test/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsaveImplTest.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/test/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsaveImplTest.java index 4bc316e97c5..fc68eda27ec 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/test/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsaveImplTest.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/test/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsaveImplTest.java @@ -1,15 +1,18 @@ package io.openems.edge.batteryinverter.kaco.blueplanetgridsave; -import java.time.Instant; -import java.time.ZoneOffset; -import java.time.temporal.ChronoUnit; +import static io.openems.edge.batteryinverter.api.SymmetricBatteryInverter.ChannelId.MAX_APPARENT_POWER; +import static io.openems.edge.batteryinverter.kaco.blueplanetgridsave.BatteryInverterKacoBlueplanetGridsave.WATCHDOG_TIMEOUT_SECONDS; +import static io.openems.edge.batteryinverter.kaco.blueplanetgridsave.BatteryInverterKacoBlueplanetGridsave.WATCHDOG_TRIGGER_SECONDS; +import static io.openems.edge.batteryinverter.kaco.blueplanetgridsave.BatteryInverterKacoBlueplanetGridsave.ChannelId.STATE_MACHINE; +import static io.openems.edge.batteryinverter.kaco.blueplanetgridsave.KacoSunSpecModel.S64201.CURRENT_STATE; +import static io.openems.edge.batteryinverter.kaco.blueplanetgridsave.KacoSunSpecModel.S64201.WATCHDOG; +import static java.time.temporal.ChronoUnit.SECONDS; import org.junit.Before; import org.junit.Test; import io.openems.common.exceptions.OpenemsException; import io.openems.common.test.TimeLeapClock; -import io.openems.common.types.ChannelAddress; import io.openems.edge.battery.api.Battery; import io.openems.edge.battery.test.DummyBattery; import io.openems.edge.batteryinverter.kaco.blueplanetgridsave.KacoSunSpecModel.S64201.S64201CurrentState; @@ -24,25 +27,13 @@ import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.common.test.DummyConfigurationAdmin; +import io.openems.edge.common.test.TestUtils; public class BatteryInverterKacoBlueplanetGridsaveImplTest { - private static final String BATTERY_INVERTER_ID = "batteryInverter0"; - private static final String BATTERY_ID = "battery0"; - private static final String MODBUS_ID = "modbus0"; - - private static final ChannelAddress STATE_MACHINE = new ChannelAddress(BATTERY_INVERTER_ID, "StateMachine"); - - private static final ChannelAddress MAX_APPARENT_POWER = new ChannelAddress(BATTERY_INVERTER_ID, - "MaxApparentPower"); - private static final ChannelAddress CURRENT_STATE = new ChannelAddress(BATTERY_INVERTER_ID, - KacoSunSpecModel.S64201.CURRENT_STATE.getChannelId().id()); - private static final ChannelAddress WATCHDOG = new ChannelAddress(BATTERY_INVERTER_ID, - KacoSunSpecModel.S64201.WATCHDOG.getChannelId().id()); - private static class MyComponentTest extends ComponentTest { - private final Battery battery = new DummyBattery(BATTERY_ID); + private final Battery battery = new DummyBattery("battery0"); public MyComponentTest(OpenemsComponent sut) throws OpenemsException { super(sut); @@ -63,15 +54,13 @@ protected void handleEvent(String topic) throws Exception { @Before public void prepareTest() throws Exception { - final var start = 1577836800L; - clock = new TimeLeapClock(Instant.ofEpochSecond(start) /* starts at 1. January 2020 00:00:00 */, - ZoneOffset.UTC); + clock = TestUtils.createDummyClock(); var sut = new BatteryInverterKacoBlueplanetGridsaveImpl(); test = new MyComponentTest(sut) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager(clock)) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)); + .addReference("setModbus", new DummyModbusBridge("modbus0")); // TODO implement proper Dummy-Modbus-Bridge with SunSpec support. Till then... test.addReference("isSunSpecInitializationCompleted", true); // @@ -86,16 +75,16 @@ public void prepareTest() throws Exception { addChannel.invoke(sut, KacoSunSpecModel.S64202.CHA_MAX_A_0.getChannelId()); addChannel.invoke(sut, KacoSunSpecModel.S64202.EN_LIMIT_0.getChannelId()); addChannel.invoke(sut, KacoSunSpecModel.S64201.REQUESTED_STATE.getChannelId()); - addChannel.invoke(sut, KacoSunSpecModel.S64201.CURRENT_STATE.getChannelId()); - addChannel.invoke(sut, KacoSunSpecModel.S64201.WATCHDOG.getChannelId()); + addChannel.invoke(sut, CURRENT_STATE.getChannelId()); + addChannel.invoke(sut, WATCHDOG.getChannelId()); addChannel.invoke(sut, KacoSunSpecModel.S64201.W_SET_PCT.getChannelId()); addChannel.invoke(sut, KacoSunSpecModel.S64201.WPARAM_RMP_TMS.getChannelId()); addChannel.invoke(sut, KacoSunSpecModel.S64201.ST_VND.getChannelId()); test.activate(MyConfig.create() // - .setId(BATTERY_INVERTER_ID) // + .setId("batteryInverter0") // .setStartStopConfig(StartStopConfig.START) // - .setModbusId(MODBUS_ID) // + .setModbusId("modbus0") // .setActivateWatchdog(true) // .build()); // } @@ -104,16 +93,16 @@ public void prepareTest() throws Exception { public void testStart() throws Exception { test // .next(new TestCase() // - .input(CURRENT_STATE, S64201CurrentState.STANDBY) // + .input(CURRENT_STATE.getChannelId(), S64201CurrentState.STANDBY) // .input(MAX_APPARENT_POWER, 50_000) // .output(STATE_MACHINE, State.UNDEFINED)) // .next(new TestCase() // - .timeleap(clock, 4, ChronoUnit.SECONDS) // + .timeleap(clock, 4, SECONDS) // .output(STATE_MACHINE, State.GO_RUNNING)) // .next(new TestCase() // - .timeleap(clock, 1, ChronoUnit.SECONDS) // - .input(CURRENT_STATE, S64201CurrentState.GRID_CONNECTED) // - .output(WATCHDOG, BatteryInverterKacoBlueplanetGridsave.WATCHDOG_TIMEOUT_SECONDS)) // + .timeleap(clock, 1, SECONDS) // + .input(CURRENT_STATE.getChannelId(), S64201CurrentState.GRID_CONNECTED) // + .output(WATCHDOG.getChannelId(), WATCHDOG_TIMEOUT_SECONDS)) // .next(new TestCase() // .output(STATE_MACHINE, State.RUNNING)) // ; @@ -123,14 +112,13 @@ public void testStart() throws Exception { public void testWatchdog() throws Exception { test // .next(new TestCase() // - .output(WATCHDOG, BatteryInverterKacoBlueplanetGridsave.WATCHDOG_TIMEOUT_SECONDS)) // + .output(WATCHDOG.getChannelId(), WATCHDOG_TIMEOUT_SECONDS)) // .next(new TestCase() // - .timeleap(clock, BatteryInverterKacoBlueplanetGridsave.WATCHDOG_TRIGGER_SECONDS - 1, - ChronoUnit.SECONDS) // - .output(WATCHDOG, null /* waiting till next watchdog trigger */)) // + .timeleap(clock, WATCHDOG_TRIGGER_SECONDS - 1, SECONDS) // + .output(WATCHDOG.getChannelId(), null /* waiting till next watchdog trigger */)) // .next(new TestCase() // - .timeleap(clock, 1, ChronoUnit.SECONDS) // - .output(WATCHDOG, BatteryInverterKacoBlueplanetGridsave.WATCHDOG_TIMEOUT_SECONDS)) // + .timeleap(clock, 1, SECONDS) // + .output(WATCHDOG.getChannelId(), WATCHDOG_TIMEOUT_SECONDS)) // ; } } diff --git a/io.openems.edge.batteryinverter.refu88k/test/io/openems/edge/batteryinverter/refu88k/BatteryInverterRefuStore88kImplTest.java b/io.openems.edge.batteryinverter.refu88k/test/io/openems/edge/batteryinverter/refu88k/BatteryInverterRefuStore88kImplTest.java index 08316f856cf..560aa3bb4f3 100644 --- a/io.openems.edge.batteryinverter.refu88k/test/io/openems/edge/batteryinverter/refu88k/BatteryInverterRefuStore88kImplTest.java +++ b/io.openems.edge.batteryinverter.refu88k/test/io/openems/edge/batteryinverter/refu88k/BatteryInverterRefuStore88kImplTest.java @@ -9,17 +9,14 @@ public class BatteryInverterRefuStore88kImplTest { - private static final String BATTERY_INVERTER_ID = "batteryInverter0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new BatteryInverterRefuStore88kImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(BATTERY_INVERTER_ID) // - .setModbusId(MODBUS_ID) // + .setId("batteryInverter0") // + .setModbusId("modbus0") // .setStartStop(StartStopConfig.AUTO) // .setTimeLimitNoPower(0) // .setWatchdoginterval(0) // diff --git a/io.openems.edge.batteryinverter.sinexcel/test/io/openems/edge/batteryinverter/sinexcel/BatteryInverterSinexcelImplTest.java b/io.openems.edge.batteryinverter.sinexcel/test/io/openems/edge/batteryinverter/sinexcel/BatteryInverterSinexcelImplTest.java index 6092ebde7d6..abf144c927e 100644 --- a/io.openems.edge.batteryinverter.sinexcel/test/io/openems/edge/batteryinverter/sinexcel/BatteryInverterSinexcelImplTest.java +++ b/io.openems.edge.batteryinverter.sinexcel/test/io/openems/edge/batteryinverter/sinexcel/BatteryInverterSinexcelImplTest.java @@ -1,5 +1,11 @@ package io.openems.edge.batteryinverter.sinexcel; +import static io.openems.edge.batteryinverter.api.OffGridBatteryInverter.ChannelId.INVERTER_STATE; +import static io.openems.edge.batteryinverter.api.SymmetricBatteryInverter.ChannelId.MAX_APPARENT_POWER; +import static io.openems.edge.batteryinverter.sinexcel.BatteryInverterSinexcel.ChannelId.SET_OFF_GRID_MODE; +import static io.openems.edge.batteryinverter.sinexcel.BatteryInverterSinexcel.ChannelId.SET_ON_GRID_MODE; +import static io.openems.edge.batteryinverter.sinexcel.BatteryInverterSinexcel.ChannelId.STATE_MACHINE; + import java.time.Instant; import java.time.ZoneOffset; import java.time.temporal.ChronoUnit; @@ -8,10 +14,8 @@ import io.openems.common.exceptions.OpenemsException; import io.openems.common.test.TimeLeapClock; -import io.openems.common.types.ChannelAddress; import io.openems.edge.battery.api.Battery; import io.openems.edge.battery.test.DummyBattery; -import io.openems.edge.batteryinverter.api.OffGridBatteryInverter; import io.openems.edge.batteryinverter.api.OffGridBatteryInverter.TargetGridMode; import io.openems.edge.batteryinverter.sinexcel.enums.CountryCode; import io.openems.edge.batteryinverter.sinexcel.enums.EnableDisable; @@ -27,21 +31,9 @@ public class BatteryInverterSinexcelImplTest { - private static final String BATTERY_INVERTER_ID = "batteryInverter0"; - private static final String BATTERY_ID = "battery0"; - private static final String MODBUS_ID = "modbus0"; - private static final ChannelAddress STATE_MACHINE = new ChannelAddress(BATTERY_INVERTER_ID, "StateMachine"); - private static final ChannelAddress SET_ON_GRID_MODE = new ChannelAddress(BATTERY_INVERTER_ID, "SetOnGridMode"); - private static final ChannelAddress SET_OFF_GRID_MODE = new ChannelAddress(BATTERY_INVERTER_ID, "SetOffGridMode"); - private static final ChannelAddress MAX_APPARENT_POWER = new ChannelAddress(BATTERY_INVERTER_ID, // - "MaxApparentPower"); - - private static final ChannelAddress INVERTER_STATE = new ChannelAddress(BATTERY_INVERTER_ID, // - OffGridBatteryInverter.ChannelId.INVERTER_STATE.id()); - private static class MyComponentTest extends ComponentTest { - private final Battery battery = new DummyBattery(BATTERY_ID); + private final Battery battery = new DummyBattery("battery0"); public MyComponentTest(OpenemsComponent sut) throws OpenemsException { super(sut); @@ -64,11 +56,11 @@ public void testStart() throws Exception { new MyComponentTest(new BatteryInverterSinexcelImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager(clock)) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(BATTERY_INVERTER_ID) // + .setId("batteryInverter0") // .setStartStopConfig(StartStopConfig.START) // - .setModbusId(MODBUS_ID) // + .setModbusId("modbus0") // .setCountryCode(CountryCode.GERMANY)// .setEmergencyPower(EnableDisable.DISABLE)// .build()) // @@ -100,11 +92,11 @@ public void testOffGrid() throws Exception { new MyComponentTest(sut) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager(clock)) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(BATTERY_INVERTER_ID) // + .setId("batteryInverter0") // .setStartStopConfig(StartStopConfig.START) // - .setModbusId(MODBUS_ID) // + .setModbusId("modbus0") // .setCountryCode(CountryCode.GERMANY)// .setEmergencyPower(EnableDisable.DISABLE)// .build()) // diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpBundle.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpBundle.java index befb0e1ebca..fcd0d24b56d 100644 --- a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpBundle.java +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpBundle.java @@ -1,5 +1,6 @@ package io.openems.edge.bridge.http.dummy; +import static io.openems.edge.bridge.http.dummy.DummyBridgeHttpFactory.dummyEndpointFetcher; import static java.util.Collections.emptyMap; import java.util.concurrent.CompletableFuture; @@ -7,7 +8,6 @@ import org.osgi.service.event.Event; -import io.openems.common.test.TimeLeapClock; import io.openems.edge.bridge.http.api.BridgeHttp.Endpoint; import io.openems.edge.bridge.http.api.BridgeHttpFactory; import io.openems.edge.bridge.http.api.CycleSubscriber; @@ -17,9 +17,8 @@ public class DummyBridgeHttpBundle { - private final DummyEndpointFetcher fetcher = DummyBridgeHttpFactory.dummyEndpointFetcher(); - private final DummyBridgeHttpExecutor pool = DummyBridgeHttpFactory.dummyBridgeHttpExecutor(new TimeLeapClock(), - true); + private final DummyEndpointFetcher fetcher = dummyEndpointFetcher(); + private final DummyBridgeHttpExecutor pool = DummyBridgeHttpFactory.dummyBridgeHttpExecutor(true); private final CycleSubscriber cycleSubscriber = DummyBridgeHttpFactory.cycleSubscriber(); private final DummyBridgeHttpFactory bridgeFactory = DummyBridgeHttpFactory.ofBridgeImpl(() -> this.cycleSubscriber, () -> this.fetcher, () -> this.pool); diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpExecutor.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpExecutor.java index 2a74f1c7ea0..cf1d07df092 100644 --- a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpExecutor.java +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpExecutor.java @@ -1,5 +1,7 @@ package io.openems.edge.bridge.http.dummy; +import static io.openems.edge.common.test.TestUtils.createDummyClock; + import java.time.Clock; import java.time.Duration; import java.time.Instant; @@ -110,10 +112,18 @@ public DummyBridgeHttpExecutor(Clock clock, boolean handleTasksImmediately) { this.taskExecutor = handleTasksImmediately ? new ImmediateTaskExecutor() : new DelayedTaskExecutor(); } + public DummyBridgeHttpExecutor(boolean handleTasksImmediately) { + this(createDummyClock(), handleTasksImmediately); + } + public DummyBridgeHttpExecutor(Clock clock) { this(clock, false); } + public DummyBridgeHttpExecutor() { + this(false); + } + @Override public ScheduledFuture schedule(Runnable task, Delay.DurationDelay durationDelay) { if (this.isShutdown()) { diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpFactory.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpFactory.java index 635b56ad885..01f1f169e83 100644 --- a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpFactory.java +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpFactory.java @@ -124,6 +124,21 @@ public static DummyBridgeHttpExecutor dummyBridgeHttpExecutor(// return new DummyBridgeHttpExecutor(clock, handleTasksImmediately); } + /** + * Creates a {@link DummyBridgeHttpExecutor} to handle the execution of the + * requests to fetch an {@link Endpoint}. + * + * @param handleTasksImmediately true if all tasks which are not scheduled + * should be executed immediately in the same + * thread; false if only executed during the + * {@link DummyBridgeHttpExecutor#update()} + * method. + * @return the created {@link DummyBridgeHttpExecutor} + */ + public static DummyBridgeHttpExecutor dummyBridgeHttpExecutor(boolean handleTasksImmediately) { + return new DummyBridgeHttpExecutor(handleTasksImmediately); + } + /** * Creates a {@link DummyBridgeHttpExecutor} to handle the execution of the * requests to fetch an {@link Endpoint}. @@ -136,6 +151,16 @@ public static DummyBridgeHttpExecutor dummyBridgeHttpExecutor(Clock clock) { return new DummyBridgeHttpExecutor(clock); } + /** + * Creates a {@link DummyBridgeHttpExecutor} to handle the execution of the + * requests to fetch an {@link Endpoint}. + * + * @return the created {@link DummyBridgeHttpExecutor} + */ + public static DummyBridgeHttpExecutor dummyBridgeHttpExecutor() { + return new DummyBridgeHttpExecutor(); + } + private DummyBridgeHttpFactory(Supplier supplier) { super(new DummyBridgeHttpCso(supplier)); } diff --git a/io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/api/BridgeHttpCycleTest.java b/io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/api/BridgeHttpCycleTest.java index 0e4ca875adc..ca2a7d82130 100644 --- a/io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/api/BridgeHttpCycleTest.java +++ b/io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/api/BridgeHttpCycleTest.java @@ -13,7 +13,6 @@ import org.junit.Test; import org.osgi.service.event.Event; -import io.openems.common.test.TimeLeapClock; import io.openems.common.utils.FunctionUtils; import io.openems.edge.bridge.http.BridgeHttpImpl; import io.openems.edge.bridge.http.api.BridgeHttp.Endpoint; @@ -33,7 +32,7 @@ public class BridgeHttpCycleTest { public void before() throws Exception { this.cycleSubscriber = new CycleSubscriber(); this.fetcher = new DummyEndpointFetcher(); - this.pool = new DummyBridgeHttpExecutor(new TimeLeapClock()); + this.pool = new DummyBridgeHttpExecutor(); this.bridgeHttp = new BridgeHttpImpl(// this.cycleSubscriber, // this.fetcher, // diff --git a/io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/api/BridgeHttpTest.java b/io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/api/BridgeHttpTest.java index 013e2ddc067..253668672e1 100644 --- a/io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/api/BridgeHttpTest.java +++ b/io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/api/BridgeHttpTest.java @@ -1,5 +1,6 @@ package io.openems.edge.bridge.http.api; +import static io.openems.edge.bridge.http.dummy.DummyBridgeHttpFactory.dummyBridgeHttpExecutor; import static java.util.Collections.emptyMap; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -14,7 +15,6 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.function.ThrowingFunction; -import io.openems.common.test.TimeLeapClock; import io.openems.common.utils.JsonUtils; import io.openems.edge.bridge.http.BridgeHttpImpl; import io.openems.edge.bridge.http.api.BridgeHttp.Endpoint; @@ -31,8 +31,7 @@ public class BridgeHttpTest { public void before() throws Exception { this.cycleSubscriber = DummyBridgeHttpFactory.cycleSubscriber(); this.fetcher = DummyBridgeHttpFactory.dummyEndpointFetcher(); - this.bridgeHttp = new BridgeHttpImpl(this.cycleSubscriber, this.fetcher, - DummyBridgeHttpFactory.dummyBridgeHttpExecutor(new TimeLeapClock(), true)); + this.bridgeHttp = new BridgeHttpImpl(this.cycleSubscriber, this.fetcher, dummyBridgeHttpExecutor(true)); } @After diff --git a/io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/api/BridgeHttpTimeTest.java b/io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/api/BridgeHttpTimeTest.java index 74f89ade961..db098dab702 100644 --- a/io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/api/BridgeHttpTimeTest.java +++ b/io.openems.edge.bridge.http/test/io/openems/edge/bridge/http/api/BridgeHttpTimeTest.java @@ -1,6 +1,7 @@ package io.openems.edge.bridge.http.api; import static io.openems.edge.bridge.http.time.DelayTimeProviderChain.fixedDelay; +import static io.openems.edge.common.test.TestUtils.createDummyClock; import static org.junit.Assert.assertEquals; import java.time.Duration; @@ -35,7 +36,7 @@ public void before() throws Exception { }; }); - this.pool = new DummyBridgeHttpExecutor(this.clock = new TimeLeapClock()); + this.pool = new DummyBridgeHttpExecutor(this.clock = createDummyClock()); this.bridgeHttp = new BridgeHttpImpl(cycleSubscriber, fetcher, this.pool); } diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/BridgeModbusSerialImplTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/BridgeModbusSerialImplTest.java index 3645d2d6fdf..1d6d1e780ba 100644 --- a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/BridgeModbusSerialImplTest.java +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/BridgeModbusSerialImplTest.java @@ -9,13 +9,11 @@ public class BridgeModbusSerialImplTest { - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new BridgeModbusSerialImpl()) // .activate(MyConfigSerial.create() // - .setId(MODBUS_ID) // + .setId("modbus0") // .setPortName("/etc/ttyUSB0") // .setBaudRate(9600) // .setDatabits(8) // diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/BridgeModbusTcpImplTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/BridgeModbusTcpImplTest.java index e9400baf670..33c3496c644 100644 --- a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/BridgeModbusTcpImplTest.java +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/BridgeModbusTcpImplTest.java @@ -1,5 +1,7 @@ package io.openems.edge.bridge.modbus; +import static io.openems.edge.bridge.modbus.api.ModbusComponent.ChannelId.MODBUS_COMMUNICATION_FAILED; + import org.junit.Test; import com.ghgande.j2mod.modbus.procimg.Register; @@ -10,7 +12,6 @@ import io.openems.common.exceptions.OpenemsException; import io.openems.common.function.ThrowingRunnable; -import io.openems.common.types.ChannelAddress; import io.openems.common.types.OpenemsType; import io.openems.edge.bridge.modbus.api.AbstractModbusBridge; import io.openems.edge.bridge.modbus.api.LogVerbosity; @@ -25,15 +26,9 @@ public class BridgeModbusTcpImplTest { - private static final String MODBUS_ID = "modbus0"; - private static final String DEVICE_ID = "device0"; private static final int UNIT_ID = 1; private static final int CYCLE_TIME = 100; - private static final ChannelAddress REGISTER_100 = new ChannelAddress(DEVICE_ID, "Register100"); - private static final ChannelAddress MODBUS_COMMUNICATION_FAILED = new ChannelAddress(DEVICE_ID, - "ModbusCommunicationFailed"); - @Test public void test() throws Exception { final ThrowingRunnable sleep = () -> Thread.sleep(CYCLE_TIME); @@ -57,13 +52,13 @@ public void test() throws Exception { var sut = new BridgeModbusTcpImpl(); var test = new ComponentTest(sut) // .activate(MyConfigTcp.create() // - .setId(MODBUS_ID) // + .setId("modbus0") // .setIp("127.0.0.1") // .setPort(port) // .setInvalidateElementsAfterReadErrors(1) // .setLogVerbosity(LogVerbosity.NONE) // .build()); - test.addComponent(new MyModbusComponent(DEVICE_ID, sut, UNIT_ID)); + test.addComponent(new MyModbusComponent("device0", sut, UNIT_ID)); /* * Successfully read Register @@ -73,21 +68,21 @@ public void test() throws Exception { .onAfterProcessImage(sleep)) // .next(new TestCase() // .onAfterProcessImage(sleep) // - .output(REGISTER_100, 123) // - .output(MODBUS_COMMUNICATION_FAILED, false)); // + .output("device0", MyModbusComponent.ChannelId.REGISTER_100, 123) // + .output("device0", MODBUS_COMMUNICATION_FAILED, false)); // /* * Remove Protocol and unset channel values */ - sut.removeProtocol(DEVICE_ID); + sut.removeProtocol("device0"); test // .next(new TestCase() // .onAfterProcessImage(sleep)) // .next(new TestCase() // .onAfterProcessImage(sleep) // - .output(REGISTER_100, null) // - .output(MODBUS_COMMUNICATION_FAILED, false)); // + .output("device0", MyModbusComponent.ChannelId.REGISTER_100, null) // + .output("device0", MODBUS_COMMUNICATION_FAILED, false)); // } finally { if (slave != null) { diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/internal/DefectiveComponentsTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/internal/DefectiveComponentsTest.java index 615037eb9de..ce0b9f97068 100644 --- a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/internal/DefectiveComponentsTest.java +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/internal/DefectiveComponentsTest.java @@ -1,6 +1,7 @@ package io.openems.edge.bridge.modbus.api.worker.internal; import static io.openems.edge.bridge.modbus.api.worker.internal.CycleTasksManagerTest.LOG_HANDLER; +import static io.openems.edge.common.test.TestUtils.createDummyClock; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -9,15 +10,13 @@ import org.junit.Test; -import io.openems.common.test.TimeLeapClock; - public class DefectiveComponentsTest { private static final String CMP = "foo"; @Test public void testIsDueForNextTry() { - var clock = new TimeLeapClock(); + final var clock = createDummyClock(); var sut = new DefectiveComponents(clock, LOG_HANDLER); assertNull(sut.isDueForNextTry(CMP)); @@ -29,7 +28,7 @@ public void testIsDueForNextTry() { @Test public void testAddRemove() { - var clock = new TimeLeapClock(); + final var clock = createDummyClock(); var sut = new DefectiveComponents(clock, LOG_HANDLER); sut.add(CMP); diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/internal/TasksSupplierImplTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/internal/TasksSupplierImplTest.java index 1b016400acf..77e3d8b8f3f 100644 --- a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/internal/TasksSupplierImplTest.java +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/internal/TasksSupplierImplTest.java @@ -1,6 +1,7 @@ package io.openems.edge.bridge.modbus.api.worker.internal; import static io.openems.edge.bridge.modbus.api.worker.internal.CycleTasksManagerTest.LOG_HANDLER; +import static io.openems.edge.common.test.TestUtils.createDummyClock; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -37,7 +38,7 @@ public void before() { @Test public void testFull() throws OpenemsException { - var clock = new TimeLeapClock(); + final var clock = createDummyClock(); var defectiveComponents = new DefectiveComponents(clock, LOG_HANDLER); var sut = new TasksSupplierImpl(LOG_HANDLER); diff --git a/io.openems.edge.bridge.onewire/test/io/openems/edge/bridge/onewire/impl/BridgeOnewireImplTest.java b/io.openems.edge.bridge.onewire/test/io/openems/edge/bridge/onewire/impl/BridgeOnewireImplTest.java index 744192de7c8..c81a5ca33c2 100644 --- a/io.openems.edge.bridge.onewire/test/io/openems/edge/bridge/onewire/impl/BridgeOnewireImplTest.java +++ b/io.openems.edge.bridge.onewire/test/io/openems/edge/bridge/onewire/impl/BridgeOnewireImplTest.java @@ -6,13 +6,11 @@ public class BridgeOnewireImplTest { - private static final String BRIDGE_ID = "onewire0"; - @Test public void test() throws Exception { new ComponentTest(new BridgeOnewireImpl()) // .activate(MyConfig.create() // - .setId(BRIDGE_ID) // + .setId("onewire0") // .setPort("USB1") // .build()) // ; diff --git a/io.openems.edge.common/src/io/openems/edge/common/currency/Currency.java b/io.openems.edge.common/src/io/openems/edge/common/currency/Currency.java index 1aaa95601f7..52337d0c78f 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/currency/Currency.java +++ b/io.openems.edge.common/src/io/openems/edge/common/currency/Currency.java @@ -1,5 +1,6 @@ package io.openems.edge.common.currency; +import io.openems.common.types.CurrencyConfig; import io.openems.common.types.OptionsEnum; public enum Currency implements OptionsEnum { @@ -30,4 +31,18 @@ public OptionsEnum getUndefined() { return Currency.UNDEFINED; } + /** + * Converts the {@link CurrencyConfig} to the {@link Currency}. + * + * @param config currencyConfig to be transformed + * @return The {@link Currency}. + */ + public static Currency fromCurrencyConfig(CurrencyConfig config) { + return switch (config) { + case EUR -> Currency.EUR; + case SEK -> Currency.SEK; + case CHF -> Currency.CHF; + }; + } + } diff --git a/io.openems.edge.common/src/io/openems/edge/common/currency/CurrencyConfig.java b/io.openems.edge.common/src/io/openems/edge/common/currency/CurrencyConfig.java deleted file mode 100644 index 2448ff5b004..00000000000 --- a/io.openems.edge.common/src/io/openems/edge/common/currency/CurrencyConfig.java +++ /dev/null @@ -1,38 +0,0 @@ -package io.openems.edge.common.currency; - -import io.openems.edge.common.meta.Meta; -import io.openems.edge.common.meta.Meta.ChannelId; - -/** - * The {@link ChannelId#CURRENCY} mandates the selection of the 'currency' - * configuration property of this specific type. Subsequently, this selected - * property is transformed into the corresponding {@link Currency} type before - * being written through {@link Meta#_setCurrency(Currency)}. - */ -public enum CurrencyConfig { - /** - * Euro. - */ - EUR, - /** - * Swedish Krona. - */ - SEK, - /** - * Swiss Francs. - */ - CHF; - - /** - * Converts the {@link CurrencyConfig} to the {@link Currency}. - * - * @return The {@link Currency}. - */ - public Currency toCurrency() { - return switch (this) { - case EUR -> Currency.EUR; - case SEK -> Currency.SEK; - case CHF -> Currency.CHF; - }; - } -} diff --git a/io.openems.edge.common/src/io/openems/edge/common/test/AbstractComponentTest.java b/io.openems.edge.common/src/io/openems/edge/common/test/AbstractComponentTest.java index f714fb70658..e09c9fc0b4d 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/test/AbstractComponentTest.java +++ b/io.openems.edge.common/src/io/openems/edge/common/test/AbstractComponentTest.java @@ -42,6 +42,10 @@ import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.event.EdgeEventConstants; +import io.openems.edge.common.sum.Sum; +import io.openems.edge.common.test.AbstractComponentTest.ChannelValue.ChannelAddressValue; +import io.openems.edge.common.test.AbstractComponentTest.ChannelValue.ChannelIdValue; +import io.openems.edge.common.test.AbstractComponentTest.ChannelValue.ComponentChannelIdValue; import io.openems.edge.common.type.TypeUtils; /** @@ -49,10 +53,42 @@ */ public abstract class AbstractComponentTest, SUT extends OpenemsComponent> { - public record ChannelValue(ChannelAddress address, Object value, boolean force) { - @Override - public String toString() { - return this.address.toString() + ":" + this.value; + public sealed interface ChannelValue { + + /** + * Gets the value. + * + * @return the value + */ + public Object value(); + + /** + * Is the value enforced?. + * + * @return true for force + */ + public boolean force(); + + public record ChannelAddressValue(ChannelAddress address, Object value, boolean force) implements ChannelValue { + @Override + public String toString() { + return this.address.toString() + ":" + this.value; + } + } + + public record ChannelIdValue(ChannelId channelId, Object value, boolean force) implements ChannelValue { + @Override + public String toString() { + return this.channelId.id() + ":" + this.value; + } + } + + public record ComponentChannelIdValue(String componentId, ChannelId channelId, Object value, boolean force) + implements ChannelValue { + @Override + public String toString() { + return this.componentId + "/" + this.channelId.id() + ":" + this.value; + } } } @@ -109,19 +145,59 @@ public TestCase(String description) { } /** - * Adds an input value for a Channel. + * Adds an input value for a {@link ChannelAddress}. * * @param address the {@link ChannelAddress} * @param value the value {@link Object} * @return myself */ public TestCase input(ChannelAddress address, Object value) { - this.inputs.add(new ChannelValue(address, value, false)); + this.inputs.add(new ChannelAddressValue(address, value, false)); return this; } /** - * Enforces an input value for a Channel. + * Adds an input value for a ChannelId of the given Component. + * + * @param componentId the Component-ID + * @param channelId the Channel-ID in CamelCase + * @param value the value {@link Object} + * @return myself + */ + public TestCase input(String componentId, String channelId, Object value) { + return this.input(new ChannelAddress(componentId, channelId), value); + } + + /** + * Adds an input value for a {@link ChannelId} of the given Component. + * + * @param componentId the Component-ID + * @param channelId the {@link ChannelId} + * @param value the value {@link Object} + * @return myself + */ + public TestCase input(String componentId, ChannelId channelId, Object value) { + this.inputs.add(new ComponentChannelIdValue(componentId, channelId, value, false)); + return this; + } + + /** + * Adds an input value for a {@link ChannelId} of the system-under-test. + * + * @param channelId the {@link ChannelId} + * @param value the value {@link Object} + * @return myself + */ + public TestCase input(ChannelId channelId, Object value) { + if (channelId instanceof Sum.ChannelId) { + return this.input("_sum", channelId, value); + } + this.inputs.add(new ChannelIdValue(channelId, value, false)); + return this; + } + + /** + * Enforces an input value for a {@link ChannelAddress}. * *

      * Use this method if you want to be sure, that the Channel actually applies the @@ -132,19 +208,102 @@ public TestCase input(ChannelAddress address, Object value) { * @return myself */ public TestCase inputForce(ChannelAddress address, Object value) { - this.inputs.add(new ChannelValue(address, value, true)); + this.inputs.add(new ChannelAddressValue(address, value, true)); return this; } /** - * Adds an expected output value for a Channel. + * Enforces an input value for a {@link ChannelAddress}. + * + *

      + * Use this method if you want to be sure, that the Channel actually applies the + * value, e.g. to override a {@link Debounce} setting. + * + * @param componentId the Component-ID + * @param channelId the Channel-ID + * @param value the value {@link Object} + * @return myself + */ + public TestCase inputForce(String componentId, String channelId, Object value) { + return this.inputForce(new ChannelAddress(componentId, channelId), value); + } + + /** + * Enforces an input value for a {@link ChannelId} of the given Component. + * + * @param componentId the Component-ID + * @param channelId the {@link ChannelId} + * @param value the value {@link Object} + * @return myself + */ + public TestCase inputForce(String componentId, ChannelId channelId, Object value) { + this.inputs.add(new ComponentChannelIdValue(componentId, channelId, value, true)); + return this; + } + + /** + * Enforces an input value for a {@link ChannelId} of the system-under-test. + * + *

      + * Use this method if you want to be sure, that the Channel actually applies the + * value, e.g. to override a {@link Debounce} setting. + * + * @param channelId the {@link ChannelId} + * @param value the value {@link Object} + * @return myself + */ + public TestCase inputForce(ChannelId channelId, Object value) { + this.inputs.add(new ChannelIdValue(channelId, value, true)); + return this; + } + + /** + * Adds an expected output value for a {@link ChannelAddress}. * * @param address the {@link ChannelAddress} * @param value the value {@link Object} * @return myself */ public TestCase output(ChannelAddress address, Object value) { - this.outputs.add(new ChannelValue(address, value, false)); + this.outputs.add(new ChannelAddressValue(address, value, false)); + return this; + } + + /** + * Adds an expected output value for a {@link ChannelAddress}. + * + * @param componentId the Component-ID + * @param channelId the Channel-ID in CamelCase + * @param value the value {@link Object} + * @return myself + */ + public TestCase output(String componentId, String channelId, Object value) { + return this.output(new ChannelAddress(componentId, channelId), value); + } + + /** + * Adds an expected output value for a {@link ChannelId} of the given Component. + * + * @param componentId the Component-ID + * @param channelId the {@link ChannelId} + * @param value the value {@link Object} + * @return myself + */ + public TestCase output(String componentId, ChannelId channelId, Object value) { + this.outputs.add(new ComponentChannelIdValue(componentId, channelId, value, true)); + return this; + } + + /** + * Adds an expected output value for a {@link ChannelId} of the + * system-under-test. + * + * @param channelId the {@link ChannelId} + * @param value the value {@link Object} + * @return myself + */ + public TestCase output(ChannelId channelId, Object value) { + this.outputs.add(new ChannelIdValue(channelId, value, false)); return this; } @@ -286,20 +445,14 @@ public void applyTimeLeap() { /** * Applies the values for input channels. * - * @param components Referenced components + * @param act the {@link AbstractComponentTest} * @throws OpenemsNamedException on error * @throws IllegalArgumentException on error */ - protected void applyInputs(Map components) + protected void applyInputs(AbstractComponentTest act) throws IllegalArgumentException, OpenemsNamedException { for (var input : this.inputs) { - var component = components.get(input.address.getComponentId()); - if (component == null) { - throw new IllegalArgumentException("On TestCase [" + this.description + "]: " // - + "the component [" + input.address.getComponentId() + "] " // - + "was not added to the OpenEMS Component test framework!"); - } - var channel = component.channel(input.address.getChannelId()); + final Channel channel = this.getChannel(act, input); // (Force) set the Read-Value do { @@ -317,38 +470,72 @@ protected void applyInputs(Map components) /** * Validates the output values. * - * @param components Referenced components + * @param act the {@link AbstractComponentTest} * @throws Exception on validation failure */ - protected void validateOutputs(Map components) throws Exception { + @SuppressWarnings("unchecked") + protected void validateOutputs(AbstractComponentTest act) throws Exception { for (var output : this.outputs) { - var expected = output.value; - var channel = components.get(output.address.getComponentId()).channel(output.address.getChannelId()); + final Channel channel = this.getChannel(act, output); + Object got; - if (channel instanceof WriteChannel) { - got = ((WriteChannel) channel).getNextWriteValueAndReset().orElse(null); + if (channel instanceof WriteChannel wc) { + got = wc.getNextWriteValueAndReset().orElse(null); } else { var value = channel.getNextValue(); got = value.orElse(null); } - // Try to parse an Enum if (channel.channelDoc() instanceof EnumDoc) { var enumDoc = (EnumDoc) channel.channelDoc(); var intGot = TypeUtils.getAsType(OpenemsType.INTEGER, got); got = enumDoc.getOption(intGot); } - if (!Objects.equals(expected, got)) { + if (!Objects.equals(output.value(), got)) { throw new Exception("On TestCase [" + this.description + "]: " // - + "expected [" + output.value + "] " // + + "expected [" + output.value() + "] " // + "got [" + got + "] " // - + "for Channel [" + output.address.toString() + "] " // + + "for Channel [" + output.toString() + "] " // + "on Inputs [" + this.inputs + "]"); } } } + + private OpenemsComponent getComponent(Map components, String componentId) { + var component = components.get(componentId); + if (component != null) { + return component; + } + throw new IllegalArgumentException("On TestCase [" + this.description + "]: " // + + "the component [" + componentId + "] " // + + "was not added to the OpenEMS Component test framework!"); + } + + private Channel getChannel(AbstractComponentTest act, ChannelValue cv) + throws IllegalArgumentException { + if (cv instanceof ChannelAddressValue cav) { + var component = this.getComponent(act.components, cav.address.getComponentId()); + return component.channel(cav.address.getChannelId()); + } + + if (cv instanceof ChannelIdValue civ) { + return act.sut.channel(civ.channelId); + } + + if (cv instanceof ComponentChannelIdValue cciv) { + var component = this.getComponent(act.components, cciv.componentId()); + return component.channel(cciv.channelId()); + } + + throw new IllegalArgumentException("Unhandled subtype of ChannelValue"); + } } + /** + * The {@link OpenemsComponent} to be tested. "sut" is for system-under-test. + */ + public final SUT sut; + /** * References added by {@link #addReference()}. */ @@ -359,11 +546,6 @@ protected void validateOutputs(Map components) throws */ private final Map components = new HashMap<>(); - /** - * The {@link OpenemsComponent} to be tested. "sut" is for system-under-test. - */ - private final SUT sut; - /** * Constructs the Component-Test and validates the implemented Channel-IDs. * @@ -670,7 +852,7 @@ public SELF next(TestCase testCase) throws Exception { for (Channel channel : this.getSut().channels()) { channel.nextProcessImage(); } - testCase.applyInputs(this.components); + testCase.applyInputs(this); this.onAfterProcessImage(); executeCallbacks(testCase.onAfterProcessImageCallbacks); this.handleEvent(EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE); @@ -691,7 +873,7 @@ public SELF next(TestCase testCase) throws Exception { this.onAfterWrite(); executeCallbacks(testCase.onAfterWriteCallbacks); this.handleEvent(EdgeEventConstants.TOPIC_CYCLE_AFTER_WRITE); - testCase.validateOutputs(this.components); + testCase.validateOutputs(this); return this.self(); } @@ -802,7 +984,5 @@ protected void onExecuteWrite() throws OpenemsNamedException { * @throws OpenemsNamedException on error */ protected void onAfterWrite() throws OpenemsNamedException { - } - } diff --git a/io.openems.edge.common/src/io/openems/edge/common/test/DummyComponentManager.java b/io.openems.edge.common/src/io/openems/edge/common/test/DummyComponentManager.java index a3a43bbe07f..db5ebb96825 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/test/DummyComponentManager.java +++ b/io.openems.edge.common/src/io/openems/edge/common/test/DummyComponentManager.java @@ -1,5 +1,7 @@ package io.openems.edge.common.test; +import static io.openems.edge.common.test.TestUtils.createDummyClock; + import java.io.IOException; import java.time.Clock; import java.util.ArrayList; @@ -47,7 +49,7 @@ public class DummyComponentManager implements ComponentManager, ComponentJsonApi private ConfigurationAdmin configurationAdmin = null; public DummyComponentManager() { - this(Clock.systemDefaultZone()); + this(createDummyClock()); } public DummyComponentManager(Clock clock) { diff --git a/io.openems.edge.common/src/io/openems/edge/common/test/TestUtils.java b/io.openems.edge.common/src/io/openems/edge/common/test/TestUtils.java index d58c7dbf484..f8f0e2e7a10 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/test/TestUtils.java +++ b/io.openems.edge.common/src/io/openems/edge/common/test/TestUtils.java @@ -2,7 +2,9 @@ import java.io.IOException; import java.net.ServerSocket; +import java.time.Instant; +import io.openems.common.test.TimeLeapClock; import io.openems.edge.common.channel.Channel; import io.openems.edge.common.channel.ChannelId; import io.openems.edge.common.component.OpenemsComponent; @@ -13,6 +15,15 @@ private TestUtils() { } + /** + * Creates a {@link TimeLeapClock} for 1st January 2000 00:00. + * + * @return the {@link TimeLeapClock} + */ + public static TimeLeapClock createDummyClock() { + return new TimeLeapClock(Instant.ofEpochSecond(1577836800) /* starts at 1. January 2020 00:00:00 */); + } + /** * Finds and returns an open port. * diff --git a/io.openems.edge.controller.api.backend/test/io/openems/edge/controller/api/backend/ControllerApiBackendImplTest.java b/io.openems.edge.controller.api.backend/test/io/openems/edge/controller/api/backend/ControllerApiBackendImplTest.java index 9d594615157..d99ef35e3bf 100644 --- a/io.openems.edge.controller.api.backend/test/io/openems/edge/controller/api/backend/ControllerApiBackendImplTest.java +++ b/io.openems.edge.controller.api.backend/test/io/openems/edge/controller/api/backend/ControllerApiBackendImplTest.java @@ -17,8 +17,6 @@ public class ControllerApiBackendImplTest { - private static final String CTRL_ID = "ctrl0"; - @Test public void test() throws Exception { @@ -44,7 +42,7 @@ public void test() throws Exception { .addReference("oem", new DummyOpenemsEdgeOem()) // .addComponent(new DummySum()) // .activate(MyConfig.create() // - .setId(CTRL_ID) // + .setId("ctrl0") // .setUri("ws://localhost:" + port) // .setApikey("12345") // .setProxyType(Type.DIRECT) // diff --git a/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/handler/QueryRequestHandler.java b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/handler/QueryRequestHandler.java index 9bed397860b..64496f773cc 100644 --- a/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/handler/QueryRequestHandler.java +++ b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/handler/QueryRequestHandler.java @@ -1,11 +1,17 @@ package io.openems.edge.controller.api.common.handler; +import java.io.IOException; +import java.time.temporal.ChronoUnit; +import java.util.Collections; +import java.util.TreeSet; + import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.ReferenceCardinality; import org.osgi.service.component.annotations.ReferencePolicy; import org.osgi.service.component.annotations.ReferencePolicyOption; +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; import io.openems.common.jsonrpc.request.QueryHistoricTimeseriesDataRequest; import io.openems.common.jsonrpc.request.QueryHistoricTimeseriesEnergyPerPeriodRequest; @@ -14,6 +20,13 @@ import io.openems.common.jsonrpc.response.QueryHistoricTimeseriesDataResponse; import io.openems.common.jsonrpc.response.QueryHistoricTimeseriesEnergyPerPeriodResponse; import io.openems.common.jsonrpc.response.QueryHistoricTimeseriesEnergyResponse; +import io.openems.common.jsonrpc.response.QueryHistoricTimeseriesExportXlsxResponse; +import io.openems.common.session.Language; +import io.openems.common.timedata.Resolution; +import io.openems.common.timedata.XlsxExportDetailData.XlsxExportDataEntry.HistoricTimedataSaveType; +import io.openems.common.timedata.XlsxExportUtil; +import io.openems.common.types.ChannelAddress; +import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.jsonapi.EdgeKeys; import io.openems.edge.common.jsonapi.JsonApi; import io.openems.edge.common.jsonapi.JsonApiBuilder; @@ -29,6 +42,9 @@ public class QueryRequestHandler implements JsonApi { ) private volatile Timedata timedata; + @Reference + private ComponentManager componentManager; + @Override public void buildJsonApiRoutes(JsonApiBuilder builder) { builder.handleRequest(QueryHistoricTimeseriesDataRequest.METHOD, call -> { @@ -54,14 +70,39 @@ public void buildJsonApiRoutes(JsonApiBuilder builder) { request.getFromDate(), request.getToDate(), request.getChannels(), request.getResolution()); return new QueryHistoricTimeseriesEnergyPerPeriodResponse(request.getId(), data); }); - builder.handleRequest(QueryHistoricTimeseriesExportXlxsRequest.METHOD, call -> { final var request = QueryHistoricTimeseriesExportXlxsRequest.from(call.getRequest()); - return this.getTimedata().handleQueryHistoricTimeseriesExportXlxsRequest(null /* ignore Edge-ID */, request, + return this.handleQueryHistoricTimeseriesExportXlxsRequest(request, call.get(EdgeKeys.USER_KEY).getLanguage()); }); } + private QueryHistoricTimeseriesExportXlsxResponse handleQueryHistoricTimeseriesExportXlxsRequest( + QueryHistoricTimeseriesExportXlxsRequest request, Language language) throws OpenemsNamedException { + final var powerChannels = new TreeSet(QueryHistoricTimeseriesExportXlsxResponse.POWER_CHANNELS); + final var energyChannels = new TreeSet( + QueryHistoricTimeseriesExportXlsxResponse.ENERGY_CHANNELS); + final var detailData = XlsxExportUtil.getDetailData(this.componentManager.getEdgeConfig()); + final var channelsByType = detailData.getChannelsBySaveType(); + powerChannels.addAll(channelsByType.getOrDefault(HistoricTimedataSaveType.POWER, Collections.emptyList())); + energyChannels.addAll(channelsByType.getOrDefault(HistoricTimedataSaveType.ENERGY, Collections.emptyList())); + var powerData = this.timedata.queryHistoricData(null, request.getFromDate(), request.getToDate(), + powerChannels, new Resolution(15, ChronoUnit.MINUTES)); + + var energyData = this.timedata.queryHistoricEnergy(null, request.getFromDate(), request.getToDate(), + energyChannels); + if (powerData == null || energyData == null) { + return null; + } + try { + return new QueryHistoricTimeseriesExportXlsxResponse(request.getId(), null, request.getFromDate(), + request.getToDate(), powerData, energyData, language, detailData); + + } catch (IOException e) { + throw new OpenemsException("QueryHistoricTimeseriesExportXlxsRequest failed: " + e.getMessage()); + } + } + private final Timedata getTimedata() throws OpenemsException { final var currentTimedata = this.timedata; if (currentTimedata == null) { diff --git a/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readonly/ControllerApiModbusTcpReadOnlyImplTest.java b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readonly/ControllerApiModbusTcpReadOnlyImplTest.java index a39ef6c3555..6248a9b4e41 100644 --- a/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readonly/ControllerApiModbusTcpReadOnlyImplTest.java +++ b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readonly/ControllerApiModbusTcpReadOnlyImplTest.java @@ -1,28 +1,27 @@ package io.openems.edge.controller.api.modbus.readonly; +import static io.openems.edge.controller.api.modbus.AbstractModbusTcpApi.DEFAULT_PORT; + import org.junit.Test; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.controller.api.modbus.AbstractModbusTcpApi; import io.openems.edge.controller.test.ControllerTest; public class ControllerApiModbusTcpReadOnlyImplTest { - private static final String CTRL_ID = "ctrl0"; - @Test public void test() throws Exception { new ControllerTest(new ControllerApiModbusTcpReadOnlyImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .activate(MyConfig.create() // - .setId(CTRL_ID) // + .setId("ctrl0") // .setEnabled(false) // do not actually start server .setComponentIds() // .setMaxConcurrentConnections(5) // - .setPort(AbstractModbusTcpApi.DEFAULT_PORT) // + .setPort(DEFAULT_PORT) // .build()) // .next(new TestCase()) // - ; + .deactivate(); } } diff --git a/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImplTest.java b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImplTest.java index e3b97b5cb79..f87124a5295 100644 --- a/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImplTest.java +++ b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImplTest.java @@ -1,7 +1,9 @@ package io.openems.edge.controller.api.modbus.readwrite; +import static io.openems.edge.controller.api.modbus.AbstractModbusTcpApi.DEFAULT_PORT; import static io.openems.edge.controller.api.modbus.readwrite.ControllerApiModbusTcpReadWriteImpl.getChannelNameCamel; import static io.openems.edge.controller.api.modbus.readwrite.ControllerApiModbusTcpReadWriteImpl.getChannelNameUpper; +import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_EQUALS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -11,27 +13,24 @@ import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyConfigurationAdmin; import io.openems.edge.common.test.DummyCycle; -import io.openems.edge.controller.api.modbus.AbstractModbusTcpApi; import io.openems.edge.controller.test.ControllerTest; -import io.openems.edge.ess.api.ManagedSymmetricEss; public class ControllerApiModbusTcpReadWriteImplTest { - private static final String CTRL_ID = "ctrl0"; - @Test public void test() throws Exception { new ControllerTest(new ControllerApiModbusTcpReadWriteImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .activate(MyConfig.create() // - .setId(CTRL_ID) // + .setId("ctrl0") // .setEnabled(false) // do not actually start server .setComponentIds() // .setMaxConcurrentConnections(5) // - .setPort(AbstractModbusTcpApi.DEFAULT_PORT) // + .setPort(DEFAULT_PORT) // .setApiTimeout(60) // .build()) // .next(new TestCase()) // + .deactivate(); ; } @@ -54,17 +53,13 @@ public void testAddFalseComponents() throws Exception { @Test public void testGetChannelNameUpper() { - assertEquals("ESS0_SET_ACTIVE_POWER_EQUALS", - getChannelNameUpper("ess0", ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_EQUALS)); - assertEquals("ESS0_SET_ACTIVE_POWER_EQUALS", - getChannelNameUpper("Ess0", ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_EQUALS)); + assertEquals("ESS0_SET_ACTIVE_POWER_EQUALS", getChannelNameUpper("ess0", SET_ACTIVE_POWER_EQUALS)); + assertEquals("ESS0_SET_ACTIVE_POWER_EQUALS", getChannelNameUpper("Ess0", SET_ACTIVE_POWER_EQUALS)); } @Test public void testGetChannelNameCamel() { - assertEquals("Ess0SetActivePowerEquals", - getChannelNameCamel("ess0", ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_EQUALS)); - assertEquals("Ess0SetActivePowerEquals", - getChannelNameCamel("Ess0", ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_EQUALS)); + assertEquals("Ess0SetActivePowerEquals", getChannelNameCamel("ess0", SET_ACTIVE_POWER_EQUALS)); + assertEquals("Ess0SetActivePowerEquals", getChannelNameCamel("Ess0", SET_ACTIVE_POWER_EQUALS)); } } diff --git a/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/MyConfig.java b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/MyConfig.java index 5c06b078554..dfbd3ea52b8 100644 --- a/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/MyConfig.java +++ b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/MyConfig.java @@ -1,12 +1,7 @@ package io.openems.edge.controller.api.modbus.readwrite; -import java.nio.channels.Channels; - import io.openems.common.test.AbstractComponentConfig; -import io.openems.common.types.EdgeConfig.Component.Channel; import io.openems.common.utils.ConfigUtils; -import io.openems.edge.common.channel.ChannelId; -import io.openems.edge.common.channel.ChannelId.ChannelIdImpl; @SuppressWarnings("all") public class MyConfig extends AbstractComponentConfig implements Config { diff --git a/io.openems.edge.controller.api.mqtt/test/io/openems/edge/controller/api/mqtt/ControllerApiMqttImplTest.java b/io.openems.edge.controller.api.mqtt/test/io/openems/edge/controller/api/mqtt/ControllerApiMqttImplTest.java index 10981834b04..89486aa7d0b 100644 --- a/io.openems.edge.controller.api.mqtt/test/io/openems/edge/controller/api/mqtt/ControllerApiMqttImplTest.java +++ b/io.openems.edge.controller.api.mqtt/test/io/openems/edge/controller/api/mqtt/ControllerApiMqttImplTest.java @@ -1,5 +1,6 @@ package io.openems.edge.controller.api.mqtt; +import static io.openems.common.channel.PersistencePriority.VERY_LOW; import static io.openems.edge.controller.api.mqtt.ControllerApiMqttImpl.createTopicPrefix; import static org.junit.Assert.assertEquals; @@ -8,7 +9,6 @@ import org.junit.Test; -import io.openems.common.channel.PersistencePriority; import io.openems.common.test.TimeLeapClock; import io.openems.edge.common.sum.DummySum; import io.openems.edge.common.test.ComponentTest; @@ -16,8 +16,6 @@ public class ControllerApiMqttImplTest { - private static final String CTRL_ID = "ctrl0"; - @Test public void test() throws Exception { final var clock = new TimeLeapClock(Instant.ofEpochSecond(1577836800L) /* starts at 1. January 2020 00:00:00 */, @@ -26,13 +24,13 @@ public void test() throws Exception { .addReference("componentManager", new DummyComponentManager(clock)) // .addComponent(new DummySum()) // .activate(MyConfig.create() // - .setId(CTRL_ID) // + .setId("ctrl0") // .setClientId("edge0") // .setTopicPrefix("") // .setUsername("guest") // .setPassword("guest") // .setUri("ws://localhost:1883") // - .setPersistencePriority(PersistencePriority.VERY_LOW) // + .setPersistencePriority(VERY_LOW) // .setDebugMode(true) // .setCertPem("") // .setPrivateKeyPem("") // diff --git a/io.openems.edge.controller.api.rest/test/io/openems/edge/controller/api/rest/readonly/ControllerApiRestReadOnlyImplTest.java b/io.openems.edge.controller.api.rest/test/io/openems/edge/controller/api/rest/readonly/ControllerApiRestReadOnlyImplTest.java index e7bc5a974ef..04c9d124dd6 100644 --- a/io.openems.edge.controller.api.rest/test/io/openems/edge/controller/api/rest/readonly/ControllerApiRestReadOnlyImplTest.java +++ b/io.openems.edge.controller.api.rest/test/io/openems/edge/controller/api/rest/readonly/ControllerApiRestReadOnlyImplTest.java @@ -12,8 +12,6 @@ public class ControllerApiRestReadOnlyImplTest { - private static final String CTRL_ID = "ctrlApiRest0"; - @Test public void test() throws OpenemsException, Exception { final var port = TestUtils.findRandomOpenPortOnAllLocalInterfaces(); @@ -23,11 +21,12 @@ public void test() throws OpenemsException, Exception { .addReference("userService", new DummyUserService()) // .addReference("restHandlerFactory", new DummyJsonRpcRestHandlerFactory(JsonRpcRestHandler::new)) // .activate(MyConfig.create() // - .setId(CTRL_ID) // + .setId("ctrlApiRest0") // .setEnabled(false) // do not actually start server .setConnectionlimit(5) // .setDebugMode(false) // .setPort(port) // - .build()); + .build()) // + .deactivate(); } } diff --git a/io.openems.edge.controller.api.rest/test/io/openems/edge/controller/api/rest/readwrite/ControllerApiRestReadWriteImplTest.java b/io.openems.edge.controller.api.rest/test/io/openems/edge/controller/api/rest/readwrite/ControllerApiRestReadWriteImplTest.java index 6baf712a911..0dd9165587a 100644 --- a/io.openems.edge.controller.api.rest/test/io/openems/edge/controller/api/rest/readwrite/ControllerApiRestReadWriteImplTest.java +++ b/io.openems.edge.controller.api.rest/test/io/openems/edge/controller/api/rest/readwrite/ControllerApiRestReadWriteImplTest.java @@ -1,9 +1,11 @@ package io.openems.edge.controller.api.rest.readwrite; +import static io.openems.common.utils.JsonUtils.getAsJsonObject; import static io.openems.edge.common.test.DummyUser.DUMMY_ADMIN; import static io.openems.edge.common.test.DummyUser.DUMMY_GUEST; import static io.openems.edge.common.test.DummyUser.DUMMY_INSTALLER; import static io.openems.edge.common.test.DummyUser.DUMMY_OWNER; +import static io.openems.edge.controller.api.rest.readwrite.ControllerApiRestReadWrite.ChannelId.API_WORKER_LOG; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -27,7 +29,6 @@ import io.openems.common.exceptions.OpenemsException; import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; import io.openems.common.jsonrpc.request.GetEdgeConfigRequest; -import io.openems.common.types.ChannelAddress; import io.openems.common.types.OpenemsType; import io.openems.common.utils.JsonUtils; import io.openems.edge.common.channel.Doc; @@ -51,9 +52,6 @@ public class ControllerApiRestReadWriteImplTest { - private static final String CTRL_ID = "ctrlApiRest0"; - private static final String DUMMY_ID = "dummy0"; - @Test public void test() throws OpenemsException, Exception { final var port = TestUtils.findRandomOpenPortOnAllLocalInterfaces(); @@ -81,10 +79,10 @@ public void test() throws OpenemsException, Exception { .addReference("userService", new DummyUserService(// DUMMY_GUEST, DUMMY_OWNER, DUMMY_INSTALLER, DUMMY_ADMIN)) // .addReference("restHandlerFactory", factory) // - .addComponent(new DummyComponent(DUMMY_ID) // + .addComponent(new DummyComponent("dummy0") // .withReadChannel(1234)) // .activate(MyConfig.create() // - .setId(CTRL_ID) // + .setId("ctrlApiRest0") // .setApiTimeout(60) // .setConnectionlimit(5) // .setDebugMode(false) // @@ -98,7 +96,7 @@ public void test() throws OpenemsException, Exception { var channelGet = sendGetRequest(port, DUMMY_GUEST.password, "/rest/channel/dummy0/ReadChannel"); assertEquals(JsonUtils.buildJsonObject() // .addProperty("address", "dummy0/ReadChannel") // - .addProperty("type", "INTEGER") // + .addProperty("type", "INTEGER") // s .addProperty("accessMode", "RO") // .addProperty("text", "This is a Read-Channel") // .addProperty("unit", "W") // @@ -113,8 +111,8 @@ public void test() throws OpenemsException, Exception { assertEquals(new JsonObject(), channelPost); test // .next(new TestCase() // - .output(new ChannelAddress("dummy0", "WriteChannel"), 4321) // - .output(new ChannelAddress(CTRL_ID, "ApiWorkerLog"), "dummy0/WriteChannel:4321")); + .output("dummy0", DummyComponent.ChannelId.WRITE_CHANNEL, 4321) // + .output(API_WORKER_LOG, "dummy0/WriteChannel:4321")); // POST fails as GUEST try { @@ -132,7 +130,7 @@ public void test() throws OpenemsException, Exception { // POST successful as OWNER var request = new GetEdgeConfigRequest().toJsonObject(); JsonrpcResponseSuccess.from(// - JsonUtils.getAsJsonObject(// + getAsJsonObject(// sendPostRequest(port, DUMMY_OWNER.password, "/jsonrpc", request))); // POST fails as GUEST diff --git a/io.openems.edge.controller.api.websocket/test/io/openems/edge/controller/api/websocket/ControllerApiWebsocketImplTest.java b/io.openems.edge.controller.api.websocket/test/io/openems/edge/controller/api/websocket/ControllerApiWebsocketImplTest.java index b37f1fb4929..f2321dcc2cf 100644 --- a/io.openems.edge.controller.api.websocket/test/io/openems/edge/controller/api/websocket/ControllerApiWebsocketImplTest.java +++ b/io.openems.edge.controller.api.websocket/test/io/openems/edge/controller/api/websocket/ControllerApiWebsocketImplTest.java @@ -1,5 +1,7 @@ package io.openems.edge.controller.api.websocket; +import static io.openems.edge.controller.api.websocket.ControllerApiWebsocket.DEFAULT_PORT; + import org.junit.Test; import io.openems.edge.common.test.AbstractComponentTest.TestCase; @@ -8,20 +10,18 @@ public class ControllerApiWebsocketImplTest { - private static final String CTRL_ID = "ctrl0"; - @Test public void test() throws Exception { new ControllerTest(new ControllerApiWebsocketImpl()) // .addReference("componentManager", new DummyComponentManager()) // .addReference("onRequestFactory", new DummyOnRequestFactory()) // .activate(MyConfig.create() // - .setId(CTRL_ID) // + .setId("ctrl0") // .setApiTimeout(60) // - .setPort(ControllerApiWebsocket.DEFAULT_PORT) // + .setPort(DEFAULT_PORT) // .build()) // .next(new TestCase()) // - ; + .deactivate(); } } diff --git a/io.openems.edge.controller.asymmetric.balancingcosphi/test/io/openems/edge/controller/asymmetric/balancingcosphi/ControllerAsymmetricBalancingCosPhiImplTest.java b/io.openems.edge.controller.asymmetric.balancingcosphi/test/io/openems/edge/controller/asymmetric/balancingcosphi/ControllerAsymmetricBalancingCosPhiImplTest.java index 8f59d84837e..8f8fee699d0 100644 --- a/io.openems.edge.controller.asymmetric.balancingcosphi/test/io/openems/edge/controller/asymmetric/balancingcosphi/ControllerAsymmetricBalancingCosPhiImplTest.java +++ b/io.openems.edge.controller.asymmetric.balancingcosphi/test/io/openems/edge/controller/asymmetric/balancingcosphi/ControllerAsymmetricBalancingCosPhiImplTest.java @@ -9,24 +9,20 @@ public class ControllerAsymmetricBalancingCosPhiImplTest { - private static final String CTRL_ID = "ctrl0"; - private static final String ESS_ID = "ess0"; - private static final String METER_ID = "meter0"; - @Test public void test() throws Exception { new ControllerTest(new ControllerAsymmetricBalancingCosPhiImpl()) // - .addComponent(new DummyManagedAsymmetricEss(ESS_ID)) // - .addComponent(new DummyElectricityMeter(METER_ID)) // + .addComponent(new DummyManagedAsymmetricEss("ess0")) // + .addComponent(new DummyElectricityMeter("meter0")) // .addReference("componentManager", new DummyComponentManager()) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // - .setMeterId(METER_ID) // + .setId("ctrl0") // + .setEssId("ess0") // + .setMeterId("meter0") // .setCosPhi(0.9) // .setDirection(CosPhiDirection.CAPACITIVE) // - .build()); // - ; + .build()) // + .deactivate(); } } diff --git a/io.openems.edge.controller.asymmetric.fixreactivepower/test/io/openems/edge/controller/asymmetric/fixreactivepower/ControllerAsymmetricFixReactivePowerImplTest.java b/io.openems.edge.controller.asymmetric.fixreactivepower/test/io/openems/edge/controller/asymmetric/fixreactivepower/ControllerAsymmetricFixReactivePowerImplTest.java index 53a2d3a18c1..f0c26cb202d 100644 --- a/io.openems.edge.controller.asymmetric.fixreactivepower/test/io/openems/edge/controller/asymmetric/fixreactivepower/ControllerAsymmetricFixReactivePowerImplTest.java +++ b/io.openems.edge.controller.asymmetric.fixreactivepower/test/io/openems/edge/controller/asymmetric/fixreactivepower/ControllerAsymmetricFixReactivePowerImplTest.java @@ -9,23 +9,20 @@ public class ControllerAsymmetricFixReactivePowerImplTest { - private static final String CTRL_ID = "ctrl0"; - private static final String ESS_ID = "ess0"; - @Test public void test() throws Exception { new ControllerTest(new ControllerAsymmetricFixReactivePowerImpl()) // - .addComponent(new DummyManagedAsymmetricEss(ESS_ID)) // + .addComponent(new DummyManagedAsymmetricEss("ess0")) // .addReference("componentManager", new DummyComponentManager()) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setPowerL1(0) // .setPowerL2(0) // .setPowerL3(0) // .build()) // - .next(new TestCase()); // - ; + .next(new TestCase()) // + .deactivate(); } } diff --git a/io.openems.edge.controller.asymmetric.peakshaving/test/io/openems/edge/controller/asymmetric/peakshaving/ControllerAsymmetricPeakShavingImplTest.java b/io.openems.edge.controller.asymmetric.peakshaving/test/io/openems/edge/controller/asymmetric/peakshaving/ControllerAsymmetricPeakShavingImplTest.java index e8090feb15a..7d59fb27424 100644 --- a/io.openems.edge.controller.asymmetric.peakshaving/test/io/openems/edge/controller/asymmetric/peakshaving/ControllerAsymmetricPeakShavingImplTest.java +++ b/io.openems.edge.controller.asymmetric.peakshaving/test/io/openems/edge/controller/asymmetric/peakshaving/ControllerAsymmetricPeakShavingImplTest.java @@ -1,8 +1,13 @@ package io.openems.edge.controller.asymmetric.peakshaving; +import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_EQUALS; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.ACTIVE_POWER; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.ACTIVE_POWER_L1; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.ACTIVE_POWER_L2; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.ACTIVE_POWER_L3; + import org.junit.Test; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.controller.test.ControllerTest; @@ -12,128 +17,117 @@ public class ControllerAsymmetricPeakShavingImplTest { - private static final String CTRL_ID = "ctrl0"; - - private static final String METER_ID = "meter0"; - private static final ChannelAddress GRID_ACTIVE_POWER = new ChannelAddress(METER_ID, "ActivePower"); - private static final ChannelAddress GRID_ACTIVE_POWER_L1 = new ChannelAddress(METER_ID, "ActivePowerL1"); - private static final ChannelAddress GRID_ACTIVE_POWER_L2 = new ChannelAddress(METER_ID, "ActivePowerL2"); - private static final ChannelAddress GRID_ACTIVE_POWER_L3 = new ChannelAddress(METER_ID, "ActivePowerL3"); - - private static final String ESS_ID = "ess0"; - private static final ChannelAddress ESS_ACTIVE_POWER = new ChannelAddress(ESS_ID, "ActivePower"); - private static final ChannelAddress ESS_SET_ACTIVE_POWER_EQUALS = new ChannelAddress(ESS_ID, - "SetActivePowerEquals"); - @Test public void symmetricMeterTest() throws Exception { new ControllerTest(new ControllerAsymmetricPeakShavingImpl()) // .addReference("componentManager", new DummyComponentManager()) // - .addComponent(new DummyElectricityMeter(METER_ID)) // - .addComponent(new DummyManagedSymmetricEss(ESS_ID) // + .addComponent(new DummyElectricityMeter("meter0")) // + .addComponent(new DummyManagedSymmetricEss("ess0") // .setPower(new DummyPower(0.3, 0.3, 0.1))) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setMeterId(METER_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setMeterId("meter0") // + .setEssId("ess0") // .setPeakShavingPower(33333) // .setRechargePower(16666) // .build()) .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 0) // - .input(GRID_ACTIVE_POWER, 120000) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 6000)) // + .input("ess0", ACTIVE_POWER, 0) // + .input("meter0", ACTIVE_POWER, 120000) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 6000)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 0) // - .input(GRID_ACTIVE_POWER, 120000) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 12001)) // + .input("ess0", ACTIVE_POWER, 0) // + .input("meter0", ACTIVE_POWER, 120000) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 12001)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 3793) // - .input(GRID_ACTIVE_POWER, 120000 - 3793) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 16484)) // + .input("ess0", ACTIVE_POWER, 3793) // + .input("meter0", ACTIVE_POWER, 120000 - 3793) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 16484)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 8981) // - .input(GRID_ACTIVE_POWER, 120000 - 8981) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 19650)) // + .input("ess0", ACTIVE_POWER, 8981) // + .input("meter0", ACTIVE_POWER, 120000 - 8981) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 19650)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 13723) // - .input(GRID_ACTIVE_POWER, 120000 - 13723) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 21578)) // + .input("ess0", ACTIVE_POWER, 13723) // + .input("meter0", ACTIVE_POWER, 120000 - 13723) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 21578)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 17469) // - .input(GRID_ACTIVE_POWER, 120000 - 17469) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 22437)) // + .input("ess0", ACTIVE_POWER, 17469) // + .input("meter0", ACTIVE_POWER, 120000 - 17469) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 22437)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 20066) // - .input(GRID_ACTIVE_POWER, 120000 - 20066) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 22533)) // + .input("ess0", ACTIVE_POWER, 20066) // + .input("meter0", ACTIVE_POWER, 120000 - 20066) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 22533)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 21564) // - .input(GRID_ACTIVE_POWER, 120000 - 21564) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 22174)) // + .input("ess0", ACTIVE_POWER, 21564) // + .input("meter0", ACTIVE_POWER, 120000 - 21564) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 22174)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 22175) // - .input(GRID_ACTIVE_POWER, 120000 - 22175) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 21610)) // + .input("ess0", ACTIVE_POWER, 22175) // + .input("meter0", ACTIVE_POWER, 120000 - 22175) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 21610)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 22173) // - .input(GRID_ACTIVE_POWER, 120000 - 22173) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 21020)) // + .input("ess0", ACTIVE_POWER, 22173) // + .input("meter0", ACTIVE_POWER, 120000 - 22173) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 21020)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 21816) // - .input(GRID_ACTIVE_POWER, 120000 - 21816) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 20511)) // + .input("ess0", ACTIVE_POWER, 21816) // + .input("meter0", ACTIVE_POWER, 120000 - 21816) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 20511)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 21311) // - .input(GRID_ACTIVE_POWER, 120000 - 21311) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 20133)) // + .input("ess0", ACTIVE_POWER, 21311) // + .input("meter0", ACTIVE_POWER, 120000 - 21311) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 20133)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 20803) // - .input(GRID_ACTIVE_POWER, 120000 - 20803) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 19893)) // + .input("ess0", ACTIVE_POWER, 20803) // + .input("meter0", ACTIVE_POWER, 120000 - 20803) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 19893)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 20377) // - .input(GRID_ACTIVE_POWER, 120000 - 20377) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 19772)); // + .input("ess0", ACTIVE_POWER, 20377) // + .input("meter0", ACTIVE_POWER, 120000 - 20377) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 19772)) // + .deactivate(); } @Test public void asymmetricMeterTest() throws Exception { new ControllerTest(new ControllerAsymmetricPeakShavingImpl()) // .addReference("componentManager", new DummyComponentManager()) // - .addComponent(new DummyElectricityMeter(METER_ID)) // - .addComponent(new DummyManagedSymmetricEss(ESS_ID) // + .addComponent(new DummyElectricityMeter("meter0")) // + .addComponent(new DummyManagedSymmetricEss("ess0") // .setPower(new DummyPower(0.3, 0.3, 0.1))) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setMeterId(METER_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setMeterId("meter0") // + .setEssId("ess0") // .setPeakShavingPower(33333) // .setRechargePower(16666) // .build()) .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 0) // - .input(GRID_ACTIVE_POWER_L1, 20000) // - .input(GRID_ACTIVE_POWER_L2, 40000) // - .input(GRID_ACTIVE_POWER_L3, 10000) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 6000)) // - .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 0) // - .input(GRID_ACTIVE_POWER_L1, 20000) // - .input(GRID_ACTIVE_POWER_L2, 40000) // - .input(GRID_ACTIVE_POWER_L3, 10000) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 12001)) // - .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 3793) // - .input(GRID_ACTIVE_POWER_L1, 20000 - 3793 / 3) // - .input(GRID_ACTIVE_POWER_L2, 40000 - 3793 / 3) // - .input(GRID_ACTIVE_POWER_L3, 10000 - 3793 / 3) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 16484)) // - .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 8981) // - .input(GRID_ACTIVE_POWER_L1, 20000 - 8981 / 3) // - .input(GRID_ACTIVE_POWER_L2, 40000 - 8981 / 3) // - .input(GRID_ACTIVE_POWER_L3, 10000 - 8981 / 3) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 19651)); // + .input("ess0", ACTIVE_POWER, 0) // + .input("meter0", ACTIVE_POWER_L1, 20000) // + .input("meter0", ACTIVE_POWER_L2, 40000) // + .input("meter0", ACTIVE_POWER_L3, 10000) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 6000)) // + .next(new TestCase() // + .input("ess0", ACTIVE_POWER, 0) // + .input("meter0", ACTIVE_POWER_L1, 20000) // + .input("meter0", ACTIVE_POWER_L2, 40000) // + .input("meter0", ACTIVE_POWER_L3, 10000) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 12001)) // + .next(new TestCase() // + .input("ess0", ACTIVE_POWER, 3793) // + .input("meter0", ACTIVE_POWER_L1, 20000 - 3793 / 3) // + .input("meter0", ACTIVE_POWER_L2, 40000 - 3793 / 3) // + .input("meter0", ACTIVE_POWER_L3, 10000 - 3793 / 3) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 16484)) // + .next(new TestCase() // + .input("ess0", ACTIVE_POWER, 8981) // + .input("meter0", ACTIVE_POWER_L1, 20000 - 8981 / 3) // + .input("meter0", ACTIVE_POWER_L2, 40000 - 8981 / 3) // + .input("meter0", ACTIVE_POWER_L3, 10000 - 8981 / 3) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 19651)) // + .deactivate(); } } diff --git a/io.openems.edge.controller.asymmetric.phaserectification/test/io/openems/edge/controller/asymmetric/phaserectification/ControllerAsymmetricPhaseRectificationImplTest.java b/io.openems.edge.controller.asymmetric.phaserectification/test/io/openems/edge/controller/asymmetric/phaserectification/ControllerAsymmetricPhaseRectificationImplTest.java index f18c8669b3a..882d083baed 100644 --- a/io.openems.edge.controller.asymmetric.phaserectification/test/io/openems/edge/controller/asymmetric/phaserectification/ControllerAsymmetricPhaseRectificationImplTest.java +++ b/io.openems.edge.controller.asymmetric.phaserectification/test/io/openems/edge/controller/asymmetric/phaserectification/ControllerAsymmetricPhaseRectificationImplTest.java @@ -9,22 +9,18 @@ public class ControllerAsymmetricPhaseRectificationImplTest { - private static final String CTRL_ID = "ctrl0"; - private static final String METER_ID = "meter0"; - private static final String ESS_ID = "ess0"; - @Test public void test() throws Exception { new ControllerTest(new ControllerAsymmetricPhaseRectificationImpl()) // - .addComponent(new DummyManagedAsymmetricEss(ESS_ID)) // - .addComponent(new DummyElectricityMeter(METER_ID)) // + .addComponent(new DummyManagedAsymmetricEss("ess0")) // + .addComponent(new DummyElectricityMeter("meter0")) // .addReference("componentManager", new DummyComponentManager()) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // - .setMeterId(METER_ID) // - .build()); // - ; + .setId("ctrl0") // + .setEssId("ess0") // + .setMeterId("meter0") // + .build()) // + .deactivate(); } } diff --git a/io.openems.edge.controller.channelthreshold/test/io/openems/edge/controller/channelthreshold/ControllerChannelThresholdImplTest.java b/io.openems.edge.controller.channelthreshold/test/io/openems/edge/controller/channelthreshold/ControllerChannelThresholdImplTest.java index b5418c94413..5c2501c8981 100644 --- a/io.openems.edge.controller.channelthreshold/test/io/openems/edge/controller/channelthreshold/ControllerChannelThresholdImplTest.java +++ b/io.openems.edge.controller.channelthreshold/test/io/openems/edge/controller/channelthreshold/ControllerChannelThresholdImplTest.java @@ -8,7 +8,6 @@ public class ControllerChannelThresholdImplTest { - private static final String CTRL_ID = "ctrl0"; private static final ChannelAddress IO0_INPUT = new ChannelAddress("io0", "Input0"); private static final ChannelAddress IO0_OUTPUT = new ChannelAddress("io0", "Output0"); @@ -17,12 +16,12 @@ public void test() throws Exception { new ControllerTest(new ControllerChannelThresholdImpl()) // .addReference("componentManager", new DummyComponentManager()) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setInputChannelAddress(IO0_INPUT.toString()) // - .setOutputChannelAddress(IO0_OUTPUT.toString()) // + .setId("ctrl0") // + .setInputChannelAddress(IO0_INPUT) // + .setOutputChannelAddress(IO0_OUTPUT) // .setLowThreshold(40) // .setHighThreshold(80) // - .build()); // + .build()) // + .deactivate(); } - } diff --git a/io.openems.edge.controller.channelthreshold/test/io/openems/edge/controller/channelthreshold/MyConfig.java b/io.openems.edge.controller.channelthreshold/test/io/openems/edge/controller/channelthreshold/MyConfig.java index ab9677f984e..7bb1199c7bc 100644 --- a/io.openems.edge.controller.channelthreshold/test/io/openems/edge/controller/channelthreshold/MyConfig.java +++ b/io.openems.edge.controller.channelthreshold/test/io/openems/edge/controller/channelthreshold/MyConfig.java @@ -1,6 +1,7 @@ package io.openems.edge.controller.channelthreshold; import io.openems.common.test.AbstractComponentConfig; +import io.openems.common.types.ChannelAddress; @SuppressWarnings("all") public class MyConfig extends AbstractComponentConfig implements Config { @@ -22,13 +23,13 @@ public Builder setId(String id) { return this; } - public Builder setInputChannelAddress(String inputChannelAddress) { - this.inputChannelAddress = inputChannelAddress; + public Builder setInputChannelAddress(ChannelAddress inputChannelAddress) { + this.inputChannelAddress = inputChannelAddress.toString(); return this; } - public Builder setOutputChannelAddress(String outputChannelAddress) { - this.outputChannelAddress = outputChannelAddress; + public Builder setOutputChannelAddress(ChannelAddress outputChannelAddress) { + this.outputChannelAddress = outputChannelAddress.toString(); return this; } diff --git a/io.openems.edge.controller.chp.soc/test/io/openems/edge/controller/chp/soc/ControllerChpSocImplTest.java b/io.openems.edge.controller.chp.soc/test/io/openems/edge/controller/chp/soc/ControllerChpSocImplTest.java index 8937f49f4ce..a469e21f2bd 100644 --- a/io.openems.edge.controller.chp.soc/test/io/openems/edge/controller/chp/soc/ControllerChpSocImplTest.java +++ b/io.openems.edge.controller.chp.soc/test/io/openems/edge/controller/chp/soc/ControllerChpSocImplTest.java @@ -1,8 +1,10 @@ package io.openems.edge.controller.chp.soc; +import static io.openems.edge.ess.api.SymmetricEss.ChannelId.SOC; +import static io.openems.edge.io.test.DummyInputOutput.ChannelId.INPUT_OUTPUT0; + import org.junit.Test; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.controller.test.ControllerTest; @@ -11,56 +13,49 @@ public class ControllerChpSocImplTest { - private static final String CTRL_ID = "ctrl0"; - - private static final String ESS_ID = "ess0"; - private static final ChannelAddress ESS_SOC = new ChannelAddress(ESS_ID, "Soc"); - - private static final String IO_ID = "io0"; - private static final ChannelAddress IO_OUTPUT0 = new ChannelAddress(IO_ID, "InputOutput0"); - @Test public void test() throws Exception { new ControllerTest(new ControllerChpSocImpl()) // .addReference("componentManager", new DummyComponentManager()) // - .addComponent(new DummyManagedSymmetricEss(ESS_ID)) // - .addComponent(new DummyInputOutput(IO_ID)) // + .addComponent(new DummyManagedSymmetricEss("ess0")) // + .addComponent(new DummyInputOutput("io0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setInputChannelAddress(ESS_SOC.toString()) // - .setOutputChannelAddress(IO_OUTPUT0.toString()) // + .setId("ctrl0") // + .setInputChannelAddress("ess0/Soc") // + .setOutputChannelAddress("io0/InputOutput0") // .setLowThreshold(15) // .setHighThreshold(85) // .setMode(Mode.AUTOMATIC) // .setInvert(false) // .build()) .next(new TestCase() // - .input(ESS_SOC, 14) // - .output(IO_OUTPUT0, true)) // + .input("ess0", SOC, 14) // + .output("io0", INPUT_OUTPUT0, true)) // .next(new TestCase() // - .input(ESS_SOC, 50) // - .output(IO_OUTPUT0, null)) // + .input("ess0", SOC, 50) // + .output("io0", INPUT_OUTPUT0, null)) // .next(new TestCase() // - .input(ESS_SOC, 90) // - .output(IO_OUTPUT0, false)) // + .input("ess0", SOC, 90) // + .output("io0", INPUT_OUTPUT0, false)) // .next(new TestCase() // - .input(ESS_SOC, 50) // - .output(IO_OUTPUT0, null)) // + .input("ess0", SOC, 50) // + .output("io0", INPUT_OUTPUT0, null)) // .next(new TestCase() // - .input(ESS_SOC, 15) // - .output(IO_OUTPUT0, true)) // + .input("ess0", SOC, 15) // + .output("io0", INPUT_OUTPUT0, true)) // .next(new TestCase() // - .input(ESS_SOC, 85) // - .output(IO_OUTPUT0, false)) // + .input("ess0", SOC, 85) // + .output("io0", INPUT_OUTPUT0, false)) // .next(new TestCase() // - .input(ESS_SOC, 86) // - .output(IO_OUTPUT0, false)) // + .input("ess0", SOC, 86) // + .output("io0", INPUT_OUTPUT0, false)) // .next(new TestCase() // - .input(ESS_SOC, 14) // - .output(IO_OUTPUT0, true)) // + .input("ess0", SOC, 14) // + .output("io0", INPUT_OUTPUT0, true)) // .next(new TestCase() // - .input(ESS_SOC, 45) // - .output(IO_OUTPUT0, null)); + .input("ess0", SOC, 45) // + .output("io0", INPUT_OUTPUT0, null)) // + .deactivate(); } } \ No newline at end of file diff --git a/io.openems.edge.controller.debug.detailedlog/test/io/openems/edge/controller/debug/detailedlog/ControllerDebugDetailedLogImplTest.java b/io.openems.edge.controller.debug.detailedlog/test/io/openems/edge/controller/debug/detailedlog/ControllerDebugDetailedLogImplTest.java index ed138710c30..0ae17386d3d 100644 --- a/io.openems.edge.controller.debug.detailedlog/test/io/openems/edge/controller/debug/detailedlog/ControllerDebugDetailedLogImplTest.java +++ b/io.openems.edge.controller.debug.detailedlog/test/io/openems/edge/controller/debug/detailedlog/ControllerDebugDetailedLogImplTest.java @@ -7,16 +7,15 @@ public class ControllerDebugDetailedLogImplTest { - private static final String CTRL_ID = "ctrl0"; - @Test public void test() throws Exception { new ControllerTest(new ControllerDebugDetailedLogImpl()) // .addReference("componentManager", new DummyComponentManager()) // .activate(MyConfig.create() // - .setId(CTRL_ID) // + .setId("ctrl0") // .setComponentIds() // - .build()); // + .build()) // + .deactivate(); } } diff --git a/io.openems.edge.controller.debug.log/test/io/openems/edge/controller/debuglog/ControllerDebugLogImplTest.java b/io.openems.edge.controller.debug.log/test/io/openems/edge/controller/debuglog/ControllerDebugLogImplTest.java index 0f0d97848c6..beabd1ba311 100644 --- a/io.openems.edge.controller.debug.log/test/io/openems/edge/controller/debuglog/ControllerDebugLogImplTest.java +++ b/io.openems.edge.controller.debug.log/test/io/openems/edge/controller/debuglog/ControllerDebugLogImplTest.java @@ -1,5 +1,6 @@ package io.openems.edge.controller.debuglog; +import static io.openems.edge.common.sum.Sum.ChannelId.ESS_SOC; import static org.junit.Assert.assertEquals; import java.util.ArrayList; @@ -7,7 +8,6 @@ import org.junit.Test; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.sum.DummySum; import io.openems.edge.common.test.AbstractComponentTest.TestCase; @@ -16,20 +16,6 @@ public class ControllerDebugLogImplTest { - private static final String CTRL_ID = "ctrl0"; - - private static final String DUMMY0_ID = "dummy0"; - private static final String DUMMY1_ID = "dummy1"; - private static final String DUMMY1_ALIAS = "This is Dummy1"; - private static final String DUMMY2_ID = "dummy2"; - private static final String DUMMY2_ALIAS = DUMMY2_ID; - private static final String DUMMY10_ID = "dummy10"; - - private static final String ANY_DUMMY = "dummy*"; - - private static final ChannelAddress SUM_ESS_SOC = new ChannelAddress("_sum", "EssSoc"); - private static final ChannelAddress SUM_FOO_BAR = new ChannelAddress("_sum", "FooBar"); - @Test public void test() throws Exception { List components = new ArrayList<>(); @@ -39,25 +25,26 @@ public String debugLog() { return "foo:bar"; } }); - components.add(new DummyController(DUMMY0_ID) { + components.add(new DummyController("dummy0") { @Override public String debugLog() { return "abc:xyz"; } }); - components.add(new DummyController(DUMMY1_ID, DUMMY1_ALIAS) { + components.add(new DummyController("dummy1", "This is Dummy1") { + @Override public String debugLog() { return "def:uvw"; } }); - components.add(new DummyController(DUMMY2_ID, DUMMY2_ALIAS) { + components.add(new DummyController("dummy2", "dummy2") { @Override public String debugLog() { return "ghi:rst"; } }); - components.add(new DummyController(DUMMY10_ID) { + components.add(new DummyController("dummy10") { @Override public String debugLog() { return "jkl:opq"; @@ -68,19 +55,14 @@ public String debugLog() { new ControllerTest(sut) // .addReference("components", components) // .activate(MyConfig.create() // - .setId(CTRL_ID) // + .setId("ctrl0") // .setShowAlias(true) // .setCondensedOutput(true) // - .setAdditionalChannels(new String[] { // - SUM_ESS_SOC.toString(), // - SUM_FOO_BAR.toString() // - }) // - .setIgnoreComponents(new String[] { // - DUMMY0_ID // - }) // + .setAdditionalChannels("_sum/EssSoc", "_sum/FooBar") // + .setIgnoreComponents("dummy0") // .build()) // .next(new TestCase() // - .input(SUM_ESS_SOC, 50)); + .input(ESS_SOC, 50)); assertEquals( "_sum[Core.Sum|foo:bar|EssSoc:50 %|FooBar:CHANNEL_IS_NOT_DEFINED] dummy1[This is Dummy1|def:uvw] dummy2[ghi:rst] dummy10[jkl:opq]", @@ -97,13 +79,14 @@ public String debugLog() { return "foo:bar"; } }); - components.add(new DummyController(DUMMY0_ID) { + components.add(new DummyController("dummy0") { @Override public String debugLog() { return "abc:xyz"; } }); - components.add(new DummyController(DUMMY1_ID) { + components.add(new DummyController("dummy1") { + @Override public String debugLog() { return "def:uvw"; @@ -116,17 +99,14 @@ public String debugLog() { .addComponent(components.get(0)) // .addComponent(components.get(1)) // .activate(MyConfig.create() // - .setId(CTRL_ID) // + .setId("ctrl0") // .setCondensedOutput(true) // - .setAdditionalChannels(new String[] { // - SUM_ESS_SOC.toString() // - }) // - .setIgnoreComponents(new String[] { // - ANY_DUMMY // - }) // + .setAdditionalChannels("_sum/EssSoc") // + .setIgnoreComponents("dummy*") // .build()) // .next(new TestCase() // - .input(SUM_ESS_SOC, 50)); + .input(ESS_SOC, 50)) // + .deactivate(); assertEquals("_sum[foo:bar|EssSoc:50 %]", sut.getLogMessage()); diff --git a/io.openems.edge.controller.debug.log/test/io/openems/edge/controller/debuglog/MyConfig.java b/io.openems.edge.controller.debug.log/test/io/openems/edge/controller/debuglog/MyConfig.java index f23d1d89e1a..b8edc931126 100644 --- a/io.openems.edge.controller.debug.log/test/io/openems/edge/controller/debuglog/MyConfig.java +++ b/io.openems.edge.controller.debug.log/test/io/openems/edge/controller/debuglog/MyConfig.java @@ -25,12 +25,12 @@ public Builder setShowAlias(boolean showAlias) { return this; } - public Builder setAdditionalChannels(String[] additionalChannels) { + public Builder setAdditionalChannels(String... additionalChannels) { this.additionalChannels = additionalChannels; return this; } - public Builder setIgnoreComponents(String[] ignoreComponents) { + public Builder setIgnoreComponents(String... ignoreComponents) { this.ignoreComponents = ignoreComponents; return this; } diff --git a/io.openems.edge.controller.ess.acisland/test/io/openems/edge/controller/ess/acisland/ControllerEssAcIslandImplTest.java b/io.openems.edge.controller.ess.acisland/test/io/openems/edge/controller/ess/acisland/ControllerEssAcIslandImplTest.java index 1a25df66607..7208178a501 100644 --- a/io.openems.edge.controller.ess.acisland/test/io/openems/edge/controller/ess/acisland/ControllerEssAcIslandImplTest.java +++ b/io.openems.edge.controller.ess.acisland/test/io/openems/edge/controller/ess/acisland/ControllerEssAcIslandImplTest.java @@ -2,35 +2,26 @@ import org.junit.Test; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.controller.test.ControllerTest; public class ControllerEssAcIslandImplTest { - private static final String CTRL_ID = "ctrl0"; - - private static final String ESS_ID = "ess0"; - - private static final String IO_ID = "io0"; - private static final ChannelAddress IO_OUTPUT0 = new ChannelAddress(IO_ID, "Output0"); - private static final ChannelAddress IO_OUTPUT1 = new ChannelAddress(IO_ID, "Output1"); - @Test public void test() throws Exception { new ControllerTest(new ControllerEssAcIslandImpl()) // .addReference("componentManager", new DummyComponentManager()) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setInvertOffGridOutput(false) // .setInvertOnGridOutput(false) // .setMaxSoc(90) // .setMinSoc(4) // - .setOffGridOutputChannelAddress(IO_OUTPUT0.toString()) // - .setOnGridOutputChannelAddress(IO_OUTPUT1.toString()) // + .setOffGridOutputChannelAddress("io0/Output0") // + .setOnGridOutputChannelAddress("io0/Output1") // .build()) // - ; + .deactivate(); } } diff --git a/io.openems.edge.controller.ess.activepowervoltagecharacteristic/test/io/openems/edge/controller/ess/activepowervoltagecharacteristic/CharacteristicImplTest.java b/io.openems.edge.controller.ess.activepowervoltagecharacteristic/test/io/openems/edge/controller/ess/activepowervoltagecharacteristic/CharacteristicImplTest.java index 26f3eb8d98f..1c1cdea75dc 100644 --- a/io.openems.edge.controller.ess.activepowervoltagecharacteristic/test/io/openems/edge/controller/ess/activepowervoltagecharacteristic/CharacteristicImplTest.java +++ b/io.openems.edge.controller.ess.activepowervoltagecharacteristic/test/io/openems/edge/controller/ess/activepowervoltagecharacteristic/CharacteristicImplTest.java @@ -1,5 +1,9 @@ package io.openems.edge.controller.ess.activepowervoltagecharacteristic; +import static io.openems.common.utils.JsonUtils.buildJsonArray; +import static io.openems.common.utils.JsonUtils.buildJsonObject; +import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_EQUALS; + import java.time.Instant; import java.time.ZoneOffset; import java.time.temporal.ChronoUnit; @@ -8,7 +12,6 @@ import io.openems.common.test.TimeLeapClock; import io.openems.common.types.ChannelAddress; -import io.openems.common.utils.JsonUtils; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.common.test.DummyConfigurationAdmin; @@ -18,11 +21,7 @@ public class CharacteristicImplTest { - private static final String CTRL_ID = "ctrlActivePowerVoltageCharacteristic0"; - private static final String ESS_ID = "ess1"; - private static final String METER_ID = "meter0"; - private static final ChannelAddress ESS_ACTIVE_POWER = new ChannelAddress(ESS_ID, "SetActivePowerEquals"); - private static final ChannelAddress METER_VOLTAGE = new ChannelAddress(METER_ID, "Voltage"); + private static final ChannelAddress METER_VOLTAGE = new ChannelAddress("meter0", "Voltage"); @Test public void test() throws Exception { @@ -30,36 +29,36 @@ public void test() throws Exception { new ControllerTest(new ControllerEssActivePowerVoltageCharacteristicImpl())// .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager(clock)) // - .addReference("meter", new DummyElectricityMeter(METER_ID)) // - .addReference("ess", new DummyManagedSymmetricEss(ESS_ID)) // + .addReference("meter", new DummyElectricityMeter("meter0")) // + .addReference("ess", new DummyManagedSymmetricEss("ess1")) // .activate(MyConfig.create()// - .setId(CTRL_ID)// - .setEssId(ESS_ID)// - .setMeterId(METER_ID)// + .setId("ctrlActivePowerVoltageCharacteristic0")// + .setEssId("ess1")// + .setMeterId("meter0")// .setNominalVoltage(240)// .setWaitForHysteresis(5)// - .setPowerVoltConfig(JsonUtils.buildJsonArray()// - .add(JsonUtils.buildJsonObject()// + .setPowerVoltConfig(buildJsonArray()// + .add(buildJsonObject()// .addProperty("voltageRatio", 0.95) // .addProperty("power", 4000) // .build()) // - .add(JsonUtils.buildJsonObject()// + .add(buildJsonObject()// .addProperty("voltageRatio", 0.98) // .addProperty("power", 1000) // .build()) // - .add(JsonUtils.buildJsonObject()// + .add(buildJsonObject()// .addProperty("voltageRatio", 0.98001) // .addProperty("power", 0) // .build()) // - .add(JsonUtils.buildJsonObject()// + .add(buildJsonObject()// .addProperty("voltageRatio", 1.02999) // .addProperty("power", 0) // .build()) // - .add(JsonUtils.buildJsonObject()// + .add(buildJsonObject()// .addProperty("voltageRatio", 1.03) // .addProperty("power", -1000) // .build()) // - .add(JsonUtils.buildJsonObject()// + .add(buildJsonObject()// .addProperty("voltageRatio", 1.05) // .addProperty("power", -4000) // .build() // @@ -67,52 +66,52 @@ public void test() throws Exception { ).build()) // .next(new TestCase("First Input") // .input(METER_VOLTAGE, 250_000) // [mV] - .output(ESS_ACTIVE_POWER, -2749)) // + .output("ess1", SET_ACTIVE_POWER_EQUALS, -2749)) // .next(new TestCase("Second Input, \"Power: -1500 \"") // .timeleap(clock, 5, ChronoUnit.SECONDS) // .input(METER_VOLTAGE, 248_000) // [mV] - .output(ESS_ACTIVE_POWER, -1499))// + .output("ess1", SET_ACTIVE_POWER_EQUALS, -1499))// .next(new TestCase() // .input(METER_VOLTAGE, 240_200) // [mV] - .output(ESS_ACTIVE_POWER, null)) // + .output("ess1", SET_ACTIVE_POWER_EQUALS, null)) // .next(new TestCase("Third Input, \"Power: 0 \"") // .timeleap(clock, 5, ChronoUnit.SECONDS) // .input(METER_VOLTAGE, 238_100) // [mV] - .output(ESS_ACTIVE_POWER, 0)) // + .output("ess1", SET_ACTIVE_POWER_EQUALS, 0)) // .next(new TestCase() // .input(METER_VOLTAGE, 240_000) // [mV] - .output(ESS_ACTIVE_POWER, null)) // + .output("ess1", SET_ACTIVE_POWER_EQUALS, null)) // .next(new TestCase() // .input(METER_VOLTAGE, 238_800)// [mV] - .output(ESS_ACTIVE_POWER, null)) // + .output("ess1", SET_ACTIVE_POWER_EQUALS, null)) // .next(new TestCase("Fourth Input, \"Power: 0 \"") // .timeleap(clock, 5, ChronoUnit.SECONDS) // .input(METER_VOLTAGE, 235_200) // [mV] - .output(ESS_ACTIVE_POWER, 998)) // + .output("ess1", SET_ACTIVE_POWER_EQUALS, 998)) // .next(new TestCase() // .timeleap(clock, 2, ChronoUnit.SECONDS) // .input(METER_VOLTAGE, 235_600) // [mV] - .output(ESS_ACTIVE_POWER, null)) // + .output("ess1", SET_ACTIVE_POWER_EQUALS, null)) // .next(new TestCase() // .timeleap(clock, 2, ChronoUnit.SECONDS) // .input(METER_VOLTAGE, 234_000) // [mV] - .output(ESS_ACTIVE_POWER, null)) // + .output("ess1", SET_ACTIVE_POWER_EQUALS, null)) // .next(new TestCase("Fifth Input, \"Power: 1625 \"") // .timeleap(clock, 1, ChronoUnit.SECONDS) // .input(METER_VOLTAGE, 233_700) // [mV] - .output(ESS_ACTIVE_POWER, 1625)) // + .output("ess1", SET_ACTIVE_POWER_EQUALS, 1625)) // .next(new TestCase("Fourth Input, \"Power: 0 \"") // .timeleap(clock, 5, ChronoUnit.SECONDS) // .input(METER_VOLTAGE, 225_000) // [mV] - .output(ESS_ACTIVE_POWER, 4000)) // + .output("ess1", SET_ACTIVE_POWER_EQUALS, 4000)) // .next(new TestCase("Smaller then Min Key, \"Power: 0 \"") // .timeleap(clock, 5, ChronoUnit.SECONDS) // .input(METER_VOLTAGE, 255_000) // [mV] - .output(ESS_ACTIVE_POWER, -4000)) // + .output("ess1", SET_ACTIVE_POWER_EQUALS, -4000)) // .next(new TestCase("Bigger than Max Key, \"Power: 0 \"") // .timeleap(clock, 5, ChronoUnit.SECONDS) // .input(METER_VOLTAGE, 270_000) // [mV] - .output(ESS_ACTIVE_POWER, -4000)) // - ; + .output("ess1", SET_ACTIVE_POWER_EQUALS, -4000)) // + .deactivate(); } } diff --git a/io.openems.edge.controller.ess.balancing/test/io/openems/edge/controller/ess/balancing/BalancingImplTest.java b/io.openems.edge.controller.ess.balancing/test/io/openems/edge/controller/ess/balancing/BalancingImplTest.java index e6a320f6733..4cab4cf6d5a 100644 --- a/io.openems.edge.controller.ess.balancing/test/io/openems/edge/controller/ess/balancing/BalancingImplTest.java +++ b/io.openems.edge.controller.ess.balancing/test/io/openems/edge/controller/ess/balancing/BalancingImplTest.java @@ -1,96 +1,90 @@ package io.openems.edge.controller.ess.balancing; +import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_EQUALS; + import org.junit.Test; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyConfigurationAdmin; import io.openems.edge.controller.test.ControllerTest; +import io.openems.edge.ess.api.SymmetricEss; import io.openems.edge.ess.test.DummyManagedSymmetricEss; import io.openems.edge.ess.test.DummyPower; +import io.openems.edge.meter.api.ElectricityMeter; import io.openems.edge.meter.test.DummyElectricityMeter; public class BalancingImplTest { - private static final String CTRL_ID = "ctrl0"; - - private static final String ESS_ID = "ess0"; - private static final ChannelAddress ESS_ACTIVE_POWER = new ChannelAddress(ESS_ID, "ActivePower"); - private static final ChannelAddress ESS_SET_ACTIVE_POWER_EQUALS = new ChannelAddress(ESS_ID, - "SetActivePowerEquals"); - - private static final String METER_ID = "meter0"; - private static final ChannelAddress METER_ACTIVE_POWER = new ChannelAddress(METER_ID, "ActivePower"); - @Test public void test() throws Exception { new ControllerTest(new ControllerEssBalancingImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("ess", new DummyManagedSymmetricEss(ESS_ID) // + .addReference("ess", new DummyManagedSymmetricEss("ess0") // .setPower(new DummyPower(0.3, 0.3, 0.1))) // - .addReference("meter", new DummyElectricityMeter(METER_ID)) // + .addReference("meter", new DummyElectricityMeter("meter0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // - .setMeterId(METER_ID) // + .setId("ctrl0") // + .setEssId("ess0") // + .setMeterId("meter0") // .setTargetGridSetpoint(0) // .build()) .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 0) // - .input(METER_ACTIVE_POWER, 20000) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 6000)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 0) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 20000) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 6000)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 0) // - .input(METER_ACTIVE_POWER, 20000) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 12000)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 0) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 20000) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 12000)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 3793) // - .input(METER_ACTIVE_POWER, 20000 - 3793) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 16483)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 3793) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 20000 - 3793) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 16483)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 8981) // - .input(METER_ACTIVE_POWER, 20000 - 8981) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 19649)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 8981) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 20000 - 8981) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 19649)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 13723) // - .input(METER_ACTIVE_POWER, 20000 - 13723) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 21577)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 13723) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 20000 - 13723) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 21577)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 17469) // - .input(METER_ACTIVE_POWER, 20000 - 17469) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 22436)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 17469) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 20000 - 17469) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 22436)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 20066) // - .input(METER_ACTIVE_POWER, 20000 - 20066) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 22531)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 20066) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 20000 - 20066) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 22531)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 21564) // - .input(METER_ACTIVE_POWER, 20000 - 21564) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 22171)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 21564) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 20000 - 21564) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 22171)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 22175) // - .input(METER_ACTIVE_POWER, 20000 - 22175) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 21608)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 22175) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 20000 - 22175) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 21608)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 22173) // - .input(METER_ACTIVE_POWER, 20000 - 22173) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 21017)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 22173) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 20000 - 22173) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 21017)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 21816) // - .input(METER_ACTIVE_POWER, 20000 - 21816) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 20508)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 21816) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 20000 - 21816) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 20508)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 21311) // - .input(METER_ACTIVE_POWER, 20000 - 21311) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 20129)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 21311) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 20000 - 21311) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 20129)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 20803) // - .input(METER_ACTIVE_POWER, 20000 - 20803) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 19889)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 20803) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 20000 - 20803) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 19889)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 20377) // - .input(METER_ACTIVE_POWER, 20000 - 20377) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 19767)); + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 20377) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 20000 - 20377) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 19767)) // + .deactivate(); } } diff --git a/io.openems.edge.controller.ess.cycle/test/io/openems/edge/controller/ess/cycle/ControllerEssCycleImplTest.java b/io.openems.edge.controller.ess.cycle/test/io/openems/edge/controller/ess/cycle/ControllerEssCycleImplTest.java index 3018b8a775c..93c3db68b5e 100644 --- a/io.openems.edge.controller.ess.cycle/test/io/openems/edge/controller/ess/cycle/ControllerEssCycleImplTest.java +++ b/io.openems.edge.controller.ess.cycle/test/io/openems/edge/controller/ess/cycle/ControllerEssCycleImplTest.java @@ -1,5 +1,15 @@ package io.openems.edge.controller.ess.cycle; +import static io.openems.edge.controller.ess.cycle.ControllerEssCycle.ChannelId.COMPLETED_CYCLES; +import static io.openems.edge.controller.ess.cycle.ControllerEssCycle.ChannelId.STATE_MACHINE; +import static io.openems.edge.controller.ess.cycle.CycleOrder.START_WITH_DISCHARGE; +import static io.openems.edge.controller.ess.cycle.HybridEssMode.TARGET_AC; +import static io.openems.edge.controller.ess.cycle.Mode.MANUAL_ON; +import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.ALLOWED_CHARGE_POWER; +import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.ALLOWED_DISCHARGE_POWER; +import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_EQUALS; +import static io.openems.edge.ess.api.SymmetricEss.ChannelId.SOC; + import java.time.Instant; import java.time.ZoneOffset; import java.time.temporal.ChronoUnit; @@ -7,7 +17,6 @@ import org.junit.Test; import io.openems.common.test.TimeLeapClock; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.common.test.DummyConfigurationAdmin; @@ -18,74 +27,61 @@ public class ControllerEssCycleImplTest { - private static final String CTRL_ID = "ctrl0"; - private static final String ESS_ID = "ess0"; - - private static final ChannelAddress STATE_MACHINE = new ChannelAddress(CTRL_ID, - ControllerEssCycle.ChannelId.STATE_MACHINE.id()); - - private static final ChannelAddress ESS_SOC = new ChannelAddress(ESS_ID, "Soc"); - private static final ChannelAddress MAX_CHARGE_POWER = new ChannelAddress(ESS_ID, "AllowedChargePower"); - private static final ChannelAddress MAX_DISCHARGE_POWER = new ChannelAddress(ESS_ID, "AllowedDischargePower"); - private static final ChannelAddress SET_ACTIVE_POWER_EQUALS = new ChannelAddress(ESS_ID, "SetActivePowerEquals"); - - private static final ChannelAddress COMPLETED_CYCLES = new ChannelAddress(CTRL_ID, "CompletedCycles"); - @Test public void test() throws Exception { final var clock = new TimeLeapClock(Instant.parse("2000-01-01T01:00:00.00Z"), ZoneOffset.UTC); final var power = new DummyPower(10_000); - final var ess = new DummyManagedSymmetricEss(ESS_ID) // + final var ess = new DummyManagedSymmetricEss("ess0") // .setPower(power); final var test = new ControllerTest(new ControllerEssCycleImpl()) // .addReference("componentManager", new DummyComponentManager(clock)) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("ess", ess) // .activate(MyConfig.create()// - .setId(CTRL_ID) // - .setEssId(ESS_ID) // - .setCycleOrder(CycleOrder.START_WITH_DISCHARGE) // + .setId("ctrl0") // + .setEssId("ess0") // + .setCycleOrder(START_WITH_DISCHARGE) // .setStandbyTime(10)// .setStartTime("2000-01-01 01:00")// .setMaxSoc(100)// .setMinSoc(0)// .setPower(10000)// - .setMode(Mode.MANUAL_ON)// - .setHybridEssMode(HybridEssMode.TARGET_AC)// + .setMode(MANUAL_ON)// + .setHybridEssMode(TARGET_AC)// .setTotalCycleNumber(3)// .setFinalSoc(50)// .build()); power.addEss(ess); test.next(new TestCase()// .input(STATE_MACHINE, State.UNDEFINED)// - .input(MAX_CHARGE_POWER, -10_000)// - .input(MAX_DISCHARGE_POWER, 10_000)// - .input(SET_ACTIVE_POWER_EQUALS, 10_000) // - .input(ESS_SOC, 50)) // + .input("ess0", ALLOWED_CHARGE_POWER, -10_000)// + .input("ess0", ALLOWED_DISCHARGE_POWER, 10_000)// + .input("ess0", SET_ACTIVE_POWER_EQUALS, 10_000) // + .input("ess0", SOC, 50)) // .next(new TestCase("First Discharge") // .output(STATE_MACHINE, State.START_DISCHARGE))// .next(new TestCase()// - .input(MAX_CHARGE_POWER, -10_000)// - .input(MAX_DISCHARGE_POWER, 1000))// + .input("ess0", ALLOWED_CHARGE_POWER, -10_000)// + .input("ess0", ALLOWED_DISCHARGE_POWER, 1000))// .next(new TestCase()// .timeleap(clock, 10, ChronoUnit.MINUTES))// .next(new TestCase()// .output(STATE_MACHINE, State.START_DISCHARGE))// .next(new TestCase()// - .input(MAX_CHARGE_POWER, -10_000)// - .input(MAX_DISCHARGE_POWER, 0))// + .input("ess0", ALLOWED_CHARGE_POWER, -10_000)// + .input("ess0", ALLOWED_DISCHARGE_POWER, 0))// .next(new TestCase()// .timeleap(clock, 11, ChronoUnit.MINUTES))// .next(new TestCase("First Charge")// .output(STATE_MACHINE, State.CONTINUE_WITH_CHARGE))// .next(new TestCase()// - .input(MAX_CHARGE_POWER, -1000)// - .input(MAX_DISCHARGE_POWER, 10_000))// + .input("ess0", ALLOWED_CHARGE_POWER, -1000)// + .input("ess0", ALLOWED_DISCHARGE_POWER, 10_000))// .next(new TestCase()// .output(STATE_MACHINE, State.CONTINUE_WITH_CHARGE))// .next(new TestCase()// - .input(MAX_CHARGE_POWER, 0)// - .input(MAX_DISCHARGE_POWER, 10_000))// + .input("ess0", ALLOWED_CHARGE_POWER, 0)// + .input("ess0", ALLOWED_DISCHARGE_POWER, 10_000))// .next(new TestCase()// .timeleap(clock, 11, ChronoUnit.MINUTES))// .next(new TestCase() // @@ -94,17 +90,17 @@ public void test() throws Exception { .output(COMPLETED_CYCLES, 1)// .output(STATE_MACHINE, State.START_DISCHARGE))// .next(new TestCase("Second Discharge")// - .input(ESS_SOC, 0)// - .input(MAX_CHARGE_POWER, -10_000)// - .input(MAX_DISCHARGE_POWER, 0))// + .input("ess0", SOC, 0)// + .input("ess0", ALLOWED_CHARGE_POWER, -10_000)// + .input("ess0", ALLOWED_DISCHARGE_POWER, 0))// .next(new TestCase()// .timeleap(clock, 11, ChronoUnit.MINUTES))// .next(new TestCase()// .output(STATE_MACHINE, State.CONTINUE_WITH_CHARGE))// .next(new TestCase("Second Charge")// - .input(ESS_SOC, 100)// - .input(MAX_CHARGE_POWER, 0)// - .input(MAX_DISCHARGE_POWER, 10_000))// + .input("ess0", SOC, 100)// + .input("ess0", ALLOWED_CHARGE_POWER, 0)// + .input("ess0", ALLOWED_DISCHARGE_POWER, 10_000))// .next(new TestCase()// .timeleap(clock, 11, ChronoUnit.MINUTES))// .next(new TestCase("Second completed cycle") // @@ -113,17 +109,17 @@ public void test() throws Exception { .output(COMPLETED_CYCLES, 2)// .output(STATE_MACHINE, State.START_DISCHARGE))// .next(new TestCase("Third Discharge")// - .input(ESS_SOC, 0)// - .input(MAX_CHARGE_POWER, -10_000)// - .input(MAX_DISCHARGE_POWER, 0))// + .input("ess0", SOC, 0)// + .input("ess0", ALLOWED_CHARGE_POWER, -10_000)// + .input("ess0", ALLOWED_DISCHARGE_POWER, 0))// .next(new TestCase()// .timeleap(clock, 11, ChronoUnit.MINUTES))// .next(new TestCase()// .output(STATE_MACHINE, State.CONTINUE_WITH_CHARGE))// .next(new TestCase("Third Charge")// - .input(ESS_SOC, 100)// - .input(MAX_CHARGE_POWER, 0)// - .input(MAX_DISCHARGE_POWER, 10_000))// + .input("ess0", SOC, 100)// + .input("ess0", ALLOWED_CHARGE_POWER, 0)// + .input("ess0", ALLOWED_DISCHARGE_POWER, 10_000))// .next(new TestCase()// .timeleap(clock, 11, ChronoUnit.MINUTES))// .next(new TestCase("Cycle Number 3 Test")// @@ -132,11 +128,11 @@ public void test() throws Exception { .next(new TestCase()// .output(STATE_MACHINE, State.FINAL_SOC))// .next(new TestCase()// - .input(ESS_SOC, 50)// - .input(MAX_CHARGE_POWER, -10_000)// - .input(MAX_DISCHARGE_POWER, 10_000))// + .input("ess0", SOC, 50)// + .input("ess0", ALLOWED_CHARGE_POWER, -10_000)// + .input("ess0", ALLOWED_DISCHARGE_POWER, 10_000))// .next(new TestCase() // - .output(STATE_MACHINE, State.FINISHED))// - ; // + .output(STATE_MACHINE, State.FINISHED)) // + .deactivate(); } } diff --git a/io.openems.edge.controller.ess.delaycharge/test/io/openems/edge/controller/ess/delaycharge/ControllerEssDelayChargeImplTest.java b/io.openems.edge.controller.ess.delaycharge/test/io/openems/edge/controller/ess/delaycharge/ControllerEssDelayChargeImplTest.java index 4c495a15a52..7f8dc9e62c8 100644 --- a/io.openems.edge.controller.ess.delaycharge/test/io/openems/edge/controller/ess/delaycharge/ControllerEssDelayChargeImplTest.java +++ b/io.openems.edge.controller.ess.delaycharge/test/io/openems/edge/controller/ess/delaycharge/ControllerEssDelayChargeImplTest.java @@ -1,13 +1,14 @@ package io.openems.edge.controller.ess.delaycharge; +import static io.openems.edge.controller.ess.delaycharge.ControllerEssDelayCharge.ChannelId.CHARGE_POWER_LIMIT; +import static java.time.temporal.ChronoUnit.HOURS; + import java.time.Instant; import java.time.ZoneId; -import java.time.temporal.ChronoUnit; import org.junit.Test; import io.openems.common.test.TimeLeapClock; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.controller.test.ControllerTest; @@ -15,11 +16,6 @@ public class ControllerEssDelayChargeImplTest { - private static final String CTRL_ID = "ctrl0"; - private static final ChannelAddress CTRL_CHARGE_POWER_LIMIT = new ChannelAddress(CTRL_ID, "ChargePowerLimit"); - - private static final String ESS_ID = "ess0"; - @Test public void test() throws Exception { // Initialize mocked Clock @@ -27,32 +23,32 @@ public void test() throws Exception { Instant.ofEpochMilli(1546300800000L /* Tuesday, 1. January 2019 00:00:00 */), ZoneId.of("UTC")); new ControllerTest(new ControllerEssDelayChargeImpl()) // .addReference("componentManager", new DummyComponentManager(clock)) // - .addComponent(new DummyManagedSymmetricEss(ESS_ID) // + .addComponent(new DummyManagedSymmetricEss("ess0") // .withSoc(20) // .withCapacity(9000)) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setTargetHour(15) // .build()) .next(new TestCase() // - .timeleap(clock, 6, ChronoUnit.HOURS) // = 6 am - .output(CTRL_CHARGE_POWER_LIMIT, 800)) + .timeleap(clock, 6, HOURS) // = 6 am + .output(CHARGE_POWER_LIMIT, 800)) .next(new TestCase() // - .timeleap(clock, 2, ChronoUnit.HOURS) // = 8 am - .output(CTRL_CHARGE_POWER_LIMIT, 1028)) + .timeleap(clock, 2, HOURS) // = 8 am + .output(CHARGE_POWER_LIMIT, 1028)) .next(new TestCase() // - .timeleap(clock, 2, ChronoUnit.HOURS) // = 10 am - .output(CTRL_CHARGE_POWER_LIMIT, 1440)) + .timeleap(clock, 2, HOURS) // = 10 am + .output(CHARGE_POWER_LIMIT, 1440)) .next(new TestCase() // - .timeleap(clock, 2, ChronoUnit.HOURS) // = 12 am - .output(CTRL_CHARGE_POWER_LIMIT, 2400)) + .timeleap(clock, 2, HOURS) // = 12 am + .output(CHARGE_POWER_LIMIT, 2400)) .next(new TestCase() // - .timeleap(clock, 2, ChronoUnit.HOURS) // = 14 am - .output(CTRL_CHARGE_POWER_LIMIT, 7200)) + .timeleap(clock, 2, HOURS) // = 14 am + .output(CHARGE_POWER_LIMIT, 7200)) .next(new TestCase() // - .timeleap(clock, 3, ChronoUnit.HOURS) // = 16 am - .output(CTRL_CHARGE_POWER_LIMIT, 0)); + .timeleap(clock, 3, HOURS) // = 16 am + .output(CHARGE_POWER_LIMIT, 0)) // + .deactivate(); } - } diff --git a/io.openems.edge.controller.ess.delayedselltogrid/test/io/openems/edge/controller/ess/delayedselltogrid/ControllerEssDelayedSellToGridImplTest.java b/io.openems.edge.controller.ess.delayedselltogrid/test/io/openems/edge/controller/ess/delayedselltogrid/ControllerEssDelayedSellToGridImplTest.java index 3d258054b4f..6843f1ca737 100644 --- a/io.openems.edge.controller.ess.delayedselltogrid/test/io/openems/edge/controller/ess/delayedselltogrid/ControllerEssDelayedSellToGridImplTest.java +++ b/io.openems.edge.controller.ess.delayedselltogrid/test/io/openems/edge/controller/ess/delayedselltogrid/ControllerEssDelayedSellToGridImplTest.java @@ -1,76 +1,70 @@ package io.openems.edge.controller.ess.delayedselltogrid; +import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_EQUALS; + import org.junit.Test; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyConfigurationAdmin; import io.openems.edge.controller.test.ControllerTest; +import io.openems.edge.ess.api.SymmetricEss; import io.openems.edge.ess.test.DummyManagedSymmetricEss; import io.openems.edge.meter.test.DummyElectricityMeter; public class ControllerEssDelayedSellToGridImplTest { - private static final String CTRL_ID = "ctrlDelayedSellToGrid0"; - private static final String ESS_ID = "ess0"; - private static final String METER_ID = "meter0"; - private static final ChannelAddress ESS_ACTIVE_POWER = new ChannelAddress(ESS_ID, "ActivePower"); - private static final ChannelAddress ESS_SET_ACTIVE_POWER_EQUALS = new ChannelAddress(ESS_ID, - "SetActivePowerEquals"); - private static final ChannelAddress METER_ACTIVE_POWER = new ChannelAddress(METER_ID, "ActivePower"); - @Test public void test() throws Exception { new ControllerTest(new ControllerEssDelayedSellToGridImpl())// .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("meter", new DummyElectricityMeter(METER_ID)) // - .addReference("ess", new DummyManagedSymmetricEss(ESS_ID)) // + .addReference("meter", new DummyElectricityMeter("meter0")) // + .addReference("ess", new DummyManagedSymmetricEss("ess0")) // .activate(MyConfig.create()// - .setId(CTRL_ID)// - .setEssId(ESS_ID)// - .setMeterId(METER_ID)// + .setId("ctrlDelayedSellToGrid0")// + .setEssId("ess0")// + .setMeterId("meter0")// .setSellToGridPowerLimit(12_500_000)// .setContinuousSellToGridPower(500_000).build())// .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 0) // - .input(METER_ACTIVE_POWER, 0) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 500_000)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 0) // + .input("meter0", SymmetricEss.ChannelId.ACTIVE_POWER, 0) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 500_000)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 0) // - .input(METER_ACTIVE_POWER, -30_000)// - .output(ESS_SET_ACTIVE_POWER_EQUALS, 470_000)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 0) // + .input("meter0", SymmetricEss.ChannelId.ACTIVE_POWER, -30_000)// + .output("ess0", SET_ACTIVE_POWER_EQUALS, 470_000)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 500_000) // - .input(METER_ACTIVE_POWER, -500_000)// - .output(ESS_SET_ACTIVE_POWER_EQUALS, 500_000)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 500_000) // + .input("meter0", SymmetricEss.ChannelId.ACTIVE_POWER, -500_000)// + .output("ess0", SET_ACTIVE_POWER_EQUALS, 500_000)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 50_000) // - .input(METER_ACTIVE_POWER, -500_000)// - .output(ESS_SET_ACTIVE_POWER_EQUALS, 50_000)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 50_000) // + .input("meter0", SymmetricEss.ChannelId.ACTIVE_POWER, -500_000)// + .output("ess0", SET_ACTIVE_POWER_EQUALS, 50_000)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, -50_000) // - .input(METER_ACTIVE_POWER, -500_000)// - .output(ESS_SET_ACTIVE_POWER_EQUALS, 0)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, -50_000) // + .input("meter0", SymmetricEss.ChannelId.ACTIVE_POWER, -500_000)// + .output("ess0", SET_ACTIVE_POWER_EQUALS, 0)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 150_000) // - .input(METER_ACTIVE_POWER, -500_000)// - .output(ESS_SET_ACTIVE_POWER_EQUALS, 150_000)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 150_000) // + .input("meter0", SymmetricEss.ChannelId.ACTIVE_POWER, -500_000)// + .output("ess0", SET_ACTIVE_POWER_EQUALS, 150_000)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 0) // - .input(METER_ACTIVE_POWER, -1_500_000)// - .output(ESS_SET_ACTIVE_POWER_EQUALS, 0)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 0) // + .input("meter0", SymmetricEss.ChannelId.ACTIVE_POWER, -1_500_000)// + .output("ess0", SET_ACTIVE_POWER_EQUALS, 0)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, -100_000) // - .input(METER_ACTIVE_POWER, -15_000_000)// - .output(ESS_SET_ACTIVE_POWER_EQUALS, -2_600_000)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, -100_000) // + .input("meter0", SymmetricEss.ChannelId.ACTIVE_POWER, -15_000_000)// + .output("ess0", SET_ACTIVE_POWER_EQUALS, -2_600_000)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, -1_000_000) // - .input(METER_ACTIVE_POWER, -16_000_000)// - .output(ESS_SET_ACTIVE_POWER_EQUALS, -4_500_000)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, -1_000_000) // + .input("meter0", SymmetricEss.ChannelId.ACTIVE_POWER, -16_000_000)// + .output("ess0", SET_ACTIVE_POWER_EQUALS, -4_500_000)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 0) // - .input(METER_ACTIVE_POWER, -16_000_000)// - .output(ESS_SET_ACTIVE_POWER_EQUALS, -3_500_000)) // - ; + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 0) // + .input("meter0", SymmetricEss.ChannelId.ACTIVE_POWER, -16_000_000)// + .output("ess0", SET_ACTIVE_POWER_EQUALS, -3_500_000)) // + .deactivate(); } } diff --git a/io.openems.edge.controller.ess.emergencycapacityreserve/test/io/openems/edge/controller/ess/emergencycapacityreserve/ControllerEssEmergencyCapacityReserveImplTest.java b/io.openems.edge.controller.ess.emergencycapacityreserve/test/io/openems/edge/controller/ess/emergencycapacityreserve/ControllerEssEmergencyCapacityReserveImplTest.java index 127acdc997d..4b8e05a2819 100644 --- a/io.openems.edge.controller.ess.emergencycapacityreserve/test/io/openems/edge/controller/ess/emergencycapacityreserve/ControllerEssEmergencyCapacityReserveImplTest.java +++ b/io.openems.edge.controller.ess.emergencycapacityreserve/test/io/openems/edge/controller/ess/emergencycapacityreserve/ControllerEssEmergencyCapacityReserveImplTest.java @@ -1,9 +1,19 @@ package io.openems.edge.controller.ess.emergencycapacityreserve; +import static io.openems.edge.common.sum.Sum.ChannelId.PRODUCTION_AC_ACTIVE_POWER; +import static io.openems.edge.common.sum.Sum.ChannelId.PRODUCTION_DC_ACTUAL_POWER; +import static io.openems.edge.controller.ess.emergencycapacityreserve.ControllerEssEmergencyCapacityReserve.ChannelId.DEBUG_RAMP_POWER; +import static io.openems.edge.controller.ess.emergencycapacityreserve.ControllerEssEmergencyCapacityReserve.ChannelId.DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS; +import static io.openems.edge.controller.ess.emergencycapacityreserve.ControllerEssEmergencyCapacityReserve.ChannelId.DEBUG_TARGET_POWER; +import static io.openems.edge.controller.ess.emergencycapacityreserve.ControllerEssEmergencyCapacityReserve.ChannelId.RANGE_OF_RESERVE_SOC_OUTSIDE_ALLOWED_VALUE; +import static io.openems.edge.controller.ess.emergencycapacityreserve.ControllerEssEmergencyCapacityReserve.ChannelId.STATE_MACHINE; +import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_LESS_OR_EQUALS; +import static io.openems.edge.ess.api.SymmetricEss.ChannelId.MAX_APPARENT_POWER; +import static io.openems.edge.ess.api.SymmetricEss.ChannelId.SOC; + import org.junit.Test; import io.openems.common.function.ThrowingRunnable; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.sum.DummySum; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; @@ -14,100 +24,82 @@ public class ControllerEssEmergencyCapacityReserveImplTest { - private static final String CTRL_ID = "ctrlEmergencyCapacityReserve0"; - private static final String ESS_ID = "ess0"; - private static final String SUM_ID = "_sum"; - - private static final ChannelAddress STATE_MACHINE = new ChannelAddress(CTRL_ID, "StateMachine"); - private static final ChannelAddress DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS = new ChannelAddress(CTRL_ID, - "DebugSetActivePowerLessOrEquals"); - private static final ChannelAddress DEBUG_TARGET_POWER = new ChannelAddress(CTRL_ID, "DebugTargetPower"); - private static final ChannelAddress DEBUG_RAMP_POWER = new ChannelAddress(CTRL_ID, "DebugRampPower"); - - private static final ChannelAddress RANGE_OF_RESERVE_SOC_OUTSIDE_ALLOWED_VALUE = new ChannelAddress(CTRL_ID, - "RangeOfReserveSocOutsideAllowedValue"); - - private static final ChannelAddress ESS_MAX_APPARENT_POWER = new ChannelAddress(ESS_ID, "MaxApparentPower"); - private static final ChannelAddress ESS_SOC = new ChannelAddress(ESS_ID, "Soc"); - private static final ChannelAddress SET_ACTIVE_POWER_LESS_OR_EQUALS = new ChannelAddress(ESS_ID, - "SetActivePowerLessOrEquals"); - - private static final ChannelAddress PRODUCTION_DC_ACTUAL_POWER = new ChannelAddress(SUM_ID, - "ProductionDcActualPower"); - private static final ChannelAddress PRODUCTION_AC_ACTIVE_POWER = new ChannelAddress(SUM_ID, - "ProductionAcActivePower"); - @Test public void testReserveSocRange() throws Exception { new ControllerTest(new ControllerEssEmergencyCapacityReserveImpl()) // .addReference("componentManager", new DummyComponentManager()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // - .addReference("ess", new DummyManagedSymmetricEss(ESS_ID)) // + .addReference("ess", new DummyManagedSymmetricEss("ess0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setReserveSoc(20) // .setReserveSocEnabled(true) // .build()) // .next(new TestCase() // - .output(RANGE_OF_RESERVE_SOC_OUTSIDE_ALLOWED_VALUE, false)); + .output(RANGE_OF_RESERVE_SOC_OUTSIDE_ALLOWED_VALUE, false)) // + .deactivate(); new ControllerTest(new ControllerEssEmergencyCapacityReserveImpl()) // .addReference("componentManager", new DummyComponentManager()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // - .addReference("ess", new DummyManagedSymmetricEss(ESS_ID)) // + .addReference("ess", new DummyManagedSymmetricEss("ess0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setReserveSoc(5) // .setReserveSocEnabled(true) // .build()) // .next(new TestCase() // - .output(RANGE_OF_RESERVE_SOC_OUTSIDE_ALLOWED_VALUE, false)); + .output(RANGE_OF_RESERVE_SOC_OUTSIDE_ALLOWED_VALUE, false)) // + .deactivate(); new ControllerTest(new ControllerEssEmergencyCapacityReserveImpl()) // .addReference("componentManager", new DummyComponentManager()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // - .addReference("ess", new DummyManagedSymmetricEss(ESS_ID)) // + .addReference("ess", new DummyManagedSymmetricEss("ess0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setReserveSoc(4) // .setReserveSocEnabled(true) // .build()) // .next(new TestCase() // - .output(RANGE_OF_RESERVE_SOC_OUTSIDE_ALLOWED_VALUE, true)); + .output(RANGE_OF_RESERVE_SOC_OUTSIDE_ALLOWED_VALUE, true)) // + .deactivate(); new ControllerTest(new ControllerEssEmergencyCapacityReserveImpl()) // .addReference("componentManager", new DummyComponentManager()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // - .addReference("ess", new DummyManagedSymmetricEss(ESS_ID)) // + .addReference("ess", new DummyManagedSymmetricEss("ess0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setReserveSoc(100) // .setReserveSocEnabled(true) // .build()) // .next(new TestCase() // - .output(RANGE_OF_RESERVE_SOC_OUTSIDE_ALLOWED_VALUE, false)); + .output(RANGE_OF_RESERVE_SOC_OUTSIDE_ALLOWED_VALUE, false)) // + .deactivate(); new ControllerTest(new ControllerEssEmergencyCapacityReserveImpl()) // .addReference("componentManager", new DummyComponentManager()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // - .addReference("ess", new DummyManagedSymmetricEss(ESS_ID)) // + .addReference("ess", new DummyManagedSymmetricEss("ess0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setReserveSoc(101) // .setReserveSocEnabled(true) // .build()) // .next(new TestCase() // - .output(RANGE_OF_RESERVE_SOC_OUTSIDE_ALLOWED_VALUE, true)); + .output(RANGE_OF_RESERVE_SOC_OUTSIDE_ALLOWED_VALUE, true)) // + .deactivate(); } @Test @@ -116,19 +108,19 @@ public void testReachTargetPower() throws Exception { .addReference("componentManager", new DummyComponentManager()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // - .addReference("ess", new DummyManagedSymmetricEss(ESS_ID)) // + .addReference("ess", new DummyManagedSymmetricEss("ess0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setReserveSoc(20) // .setReserveSocEnabled(true) // .build()) // .next(new TestCase() // - .input(ESS_SOC, 22) // - .input(ESS_MAX_APPARENT_POWER, 10000) // + .input("ess0", SOC, 22) // + .input("ess0", MAX_APPARENT_POWER, 10000) // .output(STATE_MACHINE, State.NO_LIMIT)) // .next(new TestCase() // - .input(ESS_SOC, 21) // + .input("ess0", SOC, 21) // .output(STATE_MACHINE, State.NO_LIMIT)); // var maxApparentPower = 10000; @@ -141,14 +133,16 @@ public void testReachTargetPower() throws Exception { result -= rampPower; } - controllerTest.next(new TestCase().input(ESS_SOC, 21) // + controllerTest.next(new TestCase().input("ess0", SOC, 21) // .input(PRODUCTION_DC_ACTUAL_POWER, 0) // .output(STATE_MACHINE, State.ABOVE_RESERVE_SOC) // - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, result) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, result) // .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, result) // .output(DEBUG_TARGET_POWER, targetPower.floatValue()) // ); } + + controllerTest.deactivate(); } @Test @@ -157,41 +151,42 @@ public void testAllStates() throws Exception { .addReference("componentManager", new DummyComponentManager()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // - .addReference("ess", new DummyManagedSymmetricEss(ESS_ID)) // + .addReference("ess", new DummyManagedSymmetricEss("ess0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setReserveSoc(20) // .setReserveSocEnabled(true) // .build()) .next(new TestCase() // - .input(ESS_SOC, 22) // - .input(ESS_MAX_APPARENT_POWER, 10000) // + .input("ess0", SOC, 22) // + .input("ess0", MAX_APPARENT_POWER, 10000) // .output(STATE_MACHINE, State.NO_LIMIT)) // .next(new TestCase() // - .input(ESS_SOC, 21) // + .input("ess0", SOC, 21) // .output(STATE_MACHINE, State.NO_LIMIT)) // .next(new TestCase() // - .input(ESS_SOC, 20) // + .input("ess0", SOC, 20) // .output(STATE_MACHINE, State.ABOVE_RESERVE_SOC)) // .next(new TestCase() // - .input(ESS_SOC, 19) // + .input("ess0", SOC, 19) // .output(STATE_MACHINE, State.AT_RESERVE_SOC)) // .next(new TestCase() // - .input(ESS_SOC, 16) // + .input("ess0", SOC, 16) // .output(STATE_MACHINE, State.BELOW_RESERVE_SOC)) // .next(new TestCase() // - .input(ESS_SOC, 20) // + .input("ess0", SOC, 20) // .output(STATE_MACHINE, State.FORCE_CHARGE)) // .next(new TestCase() // - .input(ESS_SOC, 21) // + .input("ess0", SOC, 21) // .output(STATE_MACHINE, State.AT_RESERVE_SOC)) // .next(new TestCase() // - .input(ESS_SOC, 22) // + .input("ess0", SOC, 22) // .output(STATE_MACHINE, State.ABOVE_RESERVE_SOC)) // .next(new TestCase() // - .input(ESS_SOC, 22) // - .output(STATE_MACHINE, State.NO_LIMIT)); + .input("ess0", SOC, 22) // + .output(STATE_MACHINE, State.NO_LIMIT)) // + .deactivate(); } @Test @@ -200,23 +195,24 @@ public void testIncreaseRampByNoLimitState() throws Exception { .addReference("componentManager", new DummyComponentManager()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // - .addReference("ess", new DummyManagedSymmetricEss(ESS_ID)) // + .addReference("ess", new DummyManagedSymmetricEss("ess0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setReserveSoc(20) // .setReserveSocEnabled(true) // .build()) // .next(new TestCase() // - .input(ESS_SOC, 80)) // + .input("ess0", SOC, 80)) // .next(new TestCase() // - .input(ESS_SOC, 80) // - .input(ESS_MAX_APPARENT_POWER, 10000) // + .input("ess0", SOC, 80) // + .input("ess0", MAX_APPARENT_POWER, 10000) // .output(STATE_MACHINE, State.NO_LIMIT) // - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, null) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, null) // .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, null) // .output(DEBUG_TARGET_POWER, 10000f) // - .output(DEBUG_RAMP_POWER, 100f)); + .output(DEBUG_RAMP_POWER, 100f)) // + .deactivate(); } @Test @@ -225,65 +221,66 @@ public void testDecreaseRampByAboveReserveSocState() throws Exception { .addReference("componentManager", new DummyComponentManager()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // - .addReference("ess", new DummyManagedSymmetricEss(ESS_ID)) // + .addReference("ess", new DummyManagedSymmetricEss("ess0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setReserveSoc(20) // .setReserveSocEnabled(true) // .build()) // .next(new TestCase() // - .input(ESS_SOC, 22) // - .input(ESS_MAX_APPARENT_POWER, 10000) // + .input("ess0", SOC, 22) // + .input("ess0", MAX_APPARENT_POWER, 10000) // .output(STATE_MACHINE, State.NO_LIMIT)) // .next(new TestCase() // - .input(ESS_SOC, 21) // + .input("ess0", SOC, 21) // .output(STATE_MACHINE, State.NO_LIMIT)// - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, null) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, null) // .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, null)) // // to reach 50% of maxApparentPower .next(new TestCase() // - .input(ESS_SOC, 21) // + .input("ess0", SOC, 21) // .input(PRODUCTION_DC_ACTUAL_POWER, 0) // .output(STATE_MACHINE, State.ABOVE_RESERVE_SOC)// - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, 9900)// + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 9900)// .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9900)) // .next(new TestCase() // - .input(ESS_SOC, 21) // - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, 9800)// + .input("ess0", SOC, 21) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 9800)// .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9800)) // .next(new TestCase() // - .input(ESS_SOC, 21) // - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, 9700)// + .input("ess0", SOC, 21) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 9700)// .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9700)) // // to reach is DC-PV .next(new TestCase() // - .input(ESS_SOC, 21) // + .input("ess0", SOC, 21) // .input(PRODUCTION_DC_ACTUAL_POWER, 6000) // - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, 9600)// + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 9600)// .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9600)) .next(new TestCase() // - .input(ESS_SOC, 21) // + .input("ess0", SOC, 21) // .input(PRODUCTION_DC_ACTUAL_POWER, 10000) // - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, 9700)// + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 9700)// .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9700)) .next(new TestCase() // - .input(ESS_SOC, 21) // + .input("ess0", SOC, 21) // .input(PRODUCTION_DC_ACTUAL_POWER, 10000) // - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, 9800)// + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 9800)// .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9800)) .next(new TestCase() // - .input(ESS_SOC, 21) // + .input("ess0", SOC, 21) // .input(PRODUCTION_DC_ACTUAL_POWER, 6000) // - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, 9700)// + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 9700)// .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9700)) .next(new TestCase() // - .input(ESS_SOC, 21) // + .input("ess0", SOC, 21) // .input(PRODUCTION_DC_ACTUAL_POWER, 6000) // - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, 9600)// - .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9600)); + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 9600)// + .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9600)) // + .deactivate(); } @Test @@ -292,41 +289,42 @@ public void testDecreaseRampByAtReserveSocState() throws Exception { .addReference("componentManager", new DummyComponentManager()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // - .addReference("ess", new DummyManagedSymmetricEss(ESS_ID)) // + .addReference("ess", new DummyManagedSymmetricEss("ess0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setReserveSoc(20) // .setReserveSocEnabled(true) // .build()) // .next(new TestCase() // - .input(ESS_SOC, 22) // - .input(ESS_MAX_APPARENT_POWER, 10000) // + .input("ess0", SOC, 22) // + .input("ess0", MAX_APPARENT_POWER, 10000) // .output(STATE_MACHINE, State.NO_LIMIT)) // .next(new TestCase() // - .input(ESS_SOC, 20) // + .input("ess0", SOC, 20) // .output(STATE_MACHINE, State.NO_LIMIT)// - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, null)// + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, null)// .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, null)) // .next(new TestCase() // - .input(ESS_SOC, 20) // + .input("ess0", SOC, 20) // .output(STATE_MACHINE, State.ABOVE_RESERVE_SOC)// - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, 9900)// + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 9900)// .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9900)) // .next(new TestCase() // - .input(ESS_SOC, 20) // + .input("ess0", SOC, 20) // .input(PRODUCTION_DC_ACTUAL_POWER, 0) // .output(STATE_MACHINE, State.AT_RESERVE_SOC)// - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, 9800)// + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 9800)// .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9800)) // .next(new TestCase() // - .input(ESS_SOC, 20) // - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, 9700)// + .input("ess0", SOC, 20) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 9700)// .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9700)) // .next(new TestCase() // - .input(ESS_SOC, 20) // - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, 9600)// - .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9600)); + .input("ess0", SOC, 20) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 9600)// + .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9600)) // + .deactivate(); } @Test @@ -335,45 +333,46 @@ public void testDecreaseRampByUnderReserveSocState() throws Exception { .addReference("componentManager", new DummyComponentManager()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // - .addReference("ess", new DummyManagedSymmetricEss(ESS_ID)) // + .addReference("ess", new DummyManagedSymmetricEss("ess0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setReserveSoc(20) // .setReserveSocEnabled(true) // .build()) // .next(new TestCase() // - .input(ESS_SOC, 22) // - .input(ESS_MAX_APPARENT_POWER, 10000) // + .input("ess0", SOC, 22) // + .input("ess0", MAX_APPARENT_POWER, 10000) // .output(STATE_MACHINE, State.NO_LIMIT)) // .next(new TestCase() // - .input(ESS_SOC, 19) // + .input("ess0", SOC, 19) // .output(STATE_MACHINE, State.NO_LIMIT)// - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, null)// + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, null)// .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, null)) // .next(new TestCase() // - .input(ESS_SOC, 19) // + .input("ess0", SOC, 19) // .output(STATE_MACHINE, State.ABOVE_RESERVE_SOC)// - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, 9900)// + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 9900)// .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9900)) // .next(new TestCase() // - .input(ESS_SOC, 19) // + .input("ess0", SOC, 19) // .output(STATE_MACHINE, State.AT_RESERVE_SOC)// - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, 9800)// + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 9800)// .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9800)) // .next(new TestCase() // - .input(ESS_SOC, 19) // + .input("ess0", SOC, 19) // .output(STATE_MACHINE, State.BELOW_RESERVE_SOC)// - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, 9300)// + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 9300)// .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9300)) // .next(new TestCase() // - .input(ESS_SOC, 19) // - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, 8800)// + .input("ess0", SOC, 19) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 8800)// .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 8800)) // .next(new TestCase() // - .input(ESS_SOC, 19) // - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, 8300)// - .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 8300)); + .input("ess0", SOC, 19) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 8300)// + .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 8300)) // + .deactivate(); } @Test @@ -382,62 +381,63 @@ public void testDecreaseRampByForceStartChargeState() throws Exception { .addReference("componentManager", new DummyComponentManager()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // - .addReference("ess", new DummyManagedSymmetricEss(ESS_ID)) // + .addReference("ess", new DummyManagedSymmetricEss("ess0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setReserveSoc(20) // .setReserveSocEnabled(true) // .build()) // .next(new TestCase() // - .input(ESS_SOC, 22) // - .input(ESS_MAX_APPARENT_POWER, 10000) // + .input("ess0", SOC, 22) // + .input("ess0", MAX_APPARENT_POWER, 10000) // .output(STATE_MACHINE, State.NO_LIMIT)) // .next(new TestCase() // - .input(ESS_SOC, 16) // + .input("ess0", SOC, 16) // .output(STATE_MACHINE, State.NO_LIMIT)// - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, null)// + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, null)// .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, null)) // .next(new TestCase() // - .input(ESS_SOC, 16) // + .input("ess0", SOC, 16) // .output(STATE_MACHINE, State.ABOVE_RESERVE_SOC)// - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, 9900)// + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 9900)// .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9900)) // .next(new TestCase() // - .input(ESS_SOC, 16) // + .input("ess0", SOC, 16) // .output(STATE_MACHINE, State.AT_RESERVE_SOC)// - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, 9800)// + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 9800)// .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9800)) // .next(new TestCase() // - .input(ESS_SOC, 16) // + .input("ess0", SOC, 16) // .output(STATE_MACHINE, State.BELOW_RESERVE_SOC)// - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, 9300)// + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 9300)// .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9300)) // .next(new TestCase() // - .input(ESS_SOC, 16) // + .input("ess0", SOC, 16) // .input(PRODUCTION_AC_ACTIVE_POWER, 100) // .output(STATE_MACHINE, State.FORCE_CHARGE)// - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, 9200)// + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 9200)// .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9200)) // .next(new TestCase() // - .input(ESS_SOC, 19) // - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, 9100)// + .input("ess0", SOC, 19) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 9100)// .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9100)) // .next(new TestCase() // - .input(ESS_SOC, 21) // + .input("ess0", SOC, 21) // .output(STATE_MACHINE, State.FORCE_CHARGE) // - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, 9000) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 9000) // .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9000)) // .next(new TestCase() // - .input(ESS_SOC, 21) // + .input("ess0", SOC, 21) // .output(STATE_MACHINE, State.AT_RESERVE_SOC) // - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, 8900) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 8900) // .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 8900)) // .next(new TestCase() // - .input(ESS_SOC, 21) // + .input("ess0", SOC, 21) // .output(STATE_MACHINE, State.ABOVE_RESERVE_SOC) // - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, 8800)// - .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 8800)); + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 8800)// + .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 8800)) // + .deactivate(); } @Test @@ -451,11 +451,11 @@ public void testUndefinedSoc() throws Exception { .addReference("componentManager", new DummyComponentManager()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // - .addReference("ess", new DummyManagedSymmetricEss(ESS_ID) // + .addReference("ess", new DummyManagedSymmetricEss("ess0") // .withMaxApparentPower(10000)) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setReserveSoc(20) // .setReserveSocEnabled(true) // .build()) // @@ -464,16 +464,17 @@ public void testUndefinedSoc() throws Exception { .output(STATE_MACHINE, State.NO_LIMIT)) // .next(new TestCase() // .onAfterProcessImage(sleep) // - .input(ESS_SOC, 16)) // + .input("ess0", SOC, 16)) // .next(new TestCase() // .onAfterProcessImage(sleep) // .output(STATE_MACHINE, State.ABOVE_RESERVE_SOC))// .next(new TestCase() // .onAfterProcessImage(sleep) // - .input(ESS_SOC, null)) // + .input("ess0", SOC, null)) // .next(new TestCase() // .onAfterProcessImage(sleep) // - .output(STATE_MACHINE, State.BELOW_RESERVE_SOC)); + .output(STATE_MACHINE, State.BELOW_RESERVE_SOC)) // + .deactivate(); } @Test @@ -482,18 +483,18 @@ public void testIncreaseRampToMaxApparentPower() throws Exception { .addReference("componentManager", new DummyComponentManager()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // - .addReference("ess", new DummyManagedSymmetricEss(ESS_ID) // + .addReference("ess", new DummyManagedSymmetricEss("ess0") // .withMaxApparentPower(10000)) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setReserveSoc(20) // .setReserveSocEnabled(true) // .build()) // .next(new TestCase() // .output(STATE_MACHINE, State.NO_LIMIT)) // .next(new TestCase() // - .input(ESS_SOC, 21)) // + .input("ess0", SOC, 21)) // .next(new TestCase() // .output(STATE_MACHINE, State.ABOVE_RESERVE_SOC) // .output(DEBUG_TARGET_POWER, 5000f) // @@ -510,7 +511,7 @@ public void testIncreaseRampToMaxApparentPower() throws Exception { .output(DEBUG_RAMP_POWER, 100f) // .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9700)) // .next(new TestCase() // - .input(ESS_SOC, 22)) // + .input("ess0", SOC, 22)) // .next(new TestCase() // .output(STATE_MACHINE, State.NO_LIMIT) // .output(DEBUG_TARGET_POWER, 10000f) // @@ -531,13 +532,14 @@ public void testIncreaseRampToMaxApparentPower() throws Exception { .output(DEBUG_TARGET_POWER, 10000f) // .output(DEBUG_RAMP_POWER, 100f) // .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, null) // - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, null)) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, null)) // .next(new TestCase() // .output(STATE_MACHINE, State.NO_LIMIT) // .output(DEBUG_TARGET_POWER, 10000f) // .output(DEBUG_RAMP_POWER, 100f) // .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, null) // - .output(SET_ACTIVE_POWER_LESS_OR_EQUALS, null)); + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, null)) // + .deactivate(); } } diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/ActivationTimeHandler.java b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/ActivationTimeHandler.java index bdf301e2827..57af0c89ba9 100644 --- a/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/ActivationTimeHandler.java +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/ActivationTimeHandler.java @@ -3,8 +3,8 @@ import java.time.Duration; import java.time.Instant; -import io.openems.common.exceptions.OpenemsException; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.exceptions.OpenemsException; import io.openems.common.utils.EnumUtils; import io.openems.edge.common.statemachine.StateHandler; import io.openems.edge.controller.ess.fastfrequencyreserve.statemachine.StateMachine.State; diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/MyControllerTest.java b/io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/ControllerFastFrequencyReserveImplTest.java similarity index 51% rename from io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/MyControllerTest.java rename to io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/ControllerFastFrequencyReserveImplTest.java index 942975af03b..e704c552b50 100644 --- a/io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/MyControllerTest.java +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/ControllerFastFrequencyReserveImplTest.java @@ -1,65 +1,57 @@ package io.openems.edge.controller.ess.fastfrequencyreserve; +import static io.openems.edge.common.test.TestUtils.createDummyClock; +import static io.openems.edge.controller.ess.fastfrequencyreserve.ControllerFastFrequencyReserve.ChannelId.STATE_MACHINE; +import static io.openems.edge.controller.ess.fastfrequencyreserve.enums.ActivationTime.LONG_ACTIVATION_RUN; +import static io.openems.edge.controller.ess.fastfrequencyreserve.enums.SupportDuration.LONG_SUPPORT_DURATION; +import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_EQUALS; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.FREQUENCY; +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.HOURS; +import static java.time.temporal.ChronoUnit.MILLIS; +import static java.time.temporal.ChronoUnit.MINUTES; +import static java.time.temporal.ChronoUnit.SECONDS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.time.Instant; import java.time.ZoneOffset; -import java.time.temporal.ChronoUnit; import java.util.List; import org.junit.Test; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.test.TimeLeapClock; -import io.openems.common.types.ChannelAddress; import io.openems.common.utils.JsonUtils; import io.openems.edge.common.sum.GridMode; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.controller.ess.fastfrequencyreserve.enums.ActivationTime; import io.openems.edge.controller.ess.fastfrequencyreserve.enums.ControlMode; -import io.openems.edge.controller.ess.fastfrequencyreserve.enums.SupportDuration; import io.openems.edge.controller.ess.fastfrequencyreserve.jsonrpc.SetActivateFastFreqReserveRequest.ActivateFastFreqReserveSchedule; import io.openems.edge.controller.ess.fastfrequencyreserve.statemachine.StateMachine.State; import io.openems.edge.controller.test.ControllerTest; import io.openems.edge.ess.test.DummyManagedSymmetricEss; import io.openems.edge.meter.test.DummyElectricityMeter; -public class MyControllerTest { - - private static final String CTRL_ID = "ctrl0"; - private static final String ESS_ID = "ess0"; - private static final String METER_ID = "meter0"; - - private static final DummyManagedSymmetricEss ESS = new DummyManagedSymmetricEss(ESS_ID); - private static final DummyElectricityMeter METER = new DummyElectricityMeter(METER_ID); - - private static final ChannelAddress METER_FREQUENCY = new ChannelAddress(METER_ID, "Frequency"); - private static final ChannelAddress STATE_MACHINE = new ChannelAddress(CTRL_ID, "StateMachine"); - private static final ChannelAddress ESS_ACTIVE_POWER = new ChannelAddress(ESS_ID, "SetActivePowerEquals"); +public class ControllerFastFrequencyReserveImplTest { @Test public void testFfrController() throws Exception { final var clock = new TimeLeapClock(Instant.parse("2023-07-13T08:45:00.00Z"), ZoneOffset.UTC); - - final var cm = new DummyComponentManager(clock); - new ControllerTest(new ControllerFastFrequencyReserveImpl()) // - - .addReference("componentManager", cm) // + .addReference("componentManager", new DummyComponentManager(clock)) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("ess", ESS // + .addReference("ess", new DummyManagedSymmetricEss("ess0") // .withGridMode(GridMode.ON_GRID)// .withMaxApparentPower(92000)// .withAllowedChargePower(-92000)// .withAllowedDischargePower(92000)) // - .addReference("meter", METER) // + .addReference("meter", new DummyElectricityMeter("meter0")) // .activate(MyConfig.create() // - .setEssId(ESS_ID) // - .setId(CTRL_ID) // - .setMeterId(METER_ID) // + .setEssId("ess0") // + .setId("ctrl0") // + .setMeterId("meter0") // .setMode(ControlMode.MANUAL_ON) // .setPreActivationTime(15)// .setactivationScheduleJson(JsonUtils.buildJsonArray() // @@ -68,219 +60,216 @@ public void testFfrController() throws Exception { .addProperty("duration", 86400) // .addProperty("dischargePowerSetPoint", 92000) // .addProperty("frequencyLimit", 49500) // - .addProperty("activationRunTime", ActivationTime.LONG_ACTIVATION_RUN) // - .addProperty("supportDuration", SupportDuration.LONG_SUPPORT_DURATION) // + .addProperty("activationRunTime", LONG_ACTIVATION_RUN) // + .addProperty("supportDuration", LONG_SUPPORT_DURATION) // .build()) .add(JsonUtils.buildJsonObject() // .addProperty("startTimestamp", 1689331500) // Fri Jul 14 2023 10:45:00 GMT+0000 .addProperty("duration", 86400) // .addProperty("dischargePowerSetPoint", 92000) // .addProperty("frequencyLimit", 49500) // - .addProperty("activationRunTime", ActivationTime.LONG_ACTIVATION_RUN) // - .addProperty("supportDuration", SupportDuration.LONG_SUPPORT_DURATION) // + .addProperty("activationRunTime", LONG_ACTIVATION_RUN) // + .addProperty("supportDuration", LONG_SUPPORT_DURATION) // .build()) .build()// .toString())// .build()) .next(new TestCase("1") // - .input(METER_FREQUENCY, 50000)// + .input("meter0", FREQUENCY, 50000)// .output(STATE_MACHINE, State.UNDEFINED) // - .output(ESS_ACTIVE_POWER, null))// + .output("ess0", SET_ACTIVE_POWER_EQUALS, null))// .next(new TestCase("2") // - .input(METER_FREQUENCY, 50000)// + .input("meter0", FREQUENCY, 50000)// .output(STATE_MACHINE, State.UNDEFINED) // - .output(ESS_ACTIVE_POWER, null))// + .output("ess0", SET_ACTIVE_POWER_EQUALS, null))// .next(new TestCase("3") // - .timeleap(clock, 1, ChronoUnit.HOURS) // - .input(METER_FREQUENCY, 50000))// + .timeleap(clock, 1, HOURS) // + .input("meter0", FREQUENCY, 50000))// .next(new TestCase("4"))// .next(new TestCase("5") // .output(STATE_MACHINE, State.UNDEFINED)) .next(new TestCase("6") // - .timeleap(clock, 10, ChronoUnit.MINUTES)// + .timeleap(clock, 10, MINUTES)// .output(STATE_MACHINE, State.PRE_ACTIVATION_STATE)) .next(new TestCase("7") // - .timeleap(clock, 10, ChronoUnit.MINUTES)) + .timeleap(clock, 10, MINUTES)) .next(new TestCase("8") // .output(STATE_MACHINE, State.ACTIVATION_TIME)// - .output(ESS_ACTIVE_POWER, 0)) + .output("ess0", SET_ACTIVE_POWER_EQUALS, 0)) .next(new TestCase("9") // - .input(METER_FREQUENCY, 50000)// + .input("meter0", FREQUENCY, 50000)// .output(STATE_MACHINE, State.ACTIVATION_TIME)// - .output(ESS_ACTIVE_POWER, 0)) + .output("ess0", SET_ACTIVE_POWER_EQUALS, 0)) .next(new TestCase("10") // - .input(METER_FREQUENCY, 49400)// + .input("meter0", FREQUENCY, 49400)// .output(STATE_MACHINE, State.ACTIVATION_TIME)// - .output(ESS_ACTIVE_POWER, 92000)) + .output("ess0", SET_ACTIVE_POWER_EQUALS, 92000)) .next(new TestCase("11") // - .timeleap(clock, ActivationTime.LONG_ACTIVATION_RUN.getValue(), ChronoUnit.MILLIS)) // + .timeleap(clock, LONG_ACTIVATION_RUN.getValue(), MILLIS)) // .next(new TestCase("12") // .output(STATE_MACHINE, State.SUPPORT_DURATION)// - .output(ESS_ACTIVE_POWER, 92000)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 92000)) // .next(new TestCase("13") // - .timeleap(clock, SupportDuration.LONG_SUPPORT_DURATION.getValue(), ChronoUnit.SECONDS) // + .timeleap(clock, LONG_SUPPORT_DURATION.getValue(), SECONDS) // .output(STATE_MACHINE, State.SUPPORT_DURATION)) .next(new TestCase("14") // - .output(STATE_MACHINE, State.DEACTIVATION_TIME).output(ESS_ACTIVE_POWER, 0)) + .output(STATE_MACHINE, State.DEACTIVATION_TIME) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 0)) .next(new TestCase("15") // - .timeleap(clock, ActivationTime.LONG_ACTIVATION_RUN.getValue(), ChronoUnit.MILLIS)) // + .timeleap(clock, LONG_ACTIVATION_RUN.getValue(), MILLIS)) // .next(new TestCase("16") // .output(STATE_MACHINE, State.BUFFERED_TIME_BEFORE_RECOVERY) // - .output(ESS_ACTIVE_POWER, 0)) + .output("ess0", SET_ACTIVE_POWER_EQUALS, 0)) .next(new TestCase("17") // - .timeleap(clock, 16, ChronoUnit.SECONDS) // + .timeleap(clock, 16, SECONDS) // .output(STATE_MACHINE, State.BUFFERED_TIME_BEFORE_RECOVERY)) .next(new TestCase("18") // - .timeleap(clock, 12, ChronoUnit.MINUTES)) // + .timeleap(clock, 12, MINUTES)) // .next(new TestCase("19") // .output(STATE_MACHINE, State.RECOVERY_TIME) // - .output(ESS_ACTIVE_POWER, -16560)) + .output("ess0", SET_ACTIVE_POWER_EQUALS, -16560)) .next(new TestCase("20") // .output(STATE_MACHINE, State.RECOVERY_TIME)) .next(new TestCase("21") // .output(STATE_MACHINE, State.RECOVERY_TIME)) .next(new TestCase("22") // - .timeleap(clock, SupportDuration.LONG_SUPPORT_DURATION.getValue(), ChronoUnit.MINUTES)) + .timeleap(clock, LONG_SUPPORT_DURATION.getValue(), MINUTES)) .next(new TestCase("23") // - .input(METER_FREQUENCY, 50000)// + .input("meter0", FREQUENCY, 50000)// .output(STATE_MACHINE, State.ACTIVATION_TIME)) .next(new TestCase("24") // - .timeleap(clock, 1, ChronoUnit.DAYS)) // + .timeleap(clock, 1, DAYS)) // .next(new TestCase("25") // .output(STATE_MACHINE, State.ACTIVATION_TIME)) .next(new TestCase("26") // - .timeleap(clock, 4, ChronoUnit.HOURS)) // + .timeleap(clock, 4, HOURS)) // .next(new TestCase("27") // .output(STATE_MACHINE, State.ACTIVATION_TIME)) .next(new TestCase("28")// - .input(METER_FREQUENCY, 49400)) + .input("meter0", FREQUENCY, 49400)) .next(new TestCase("29") // - .timeleap(clock, ActivationTime.LONG_ACTIVATION_RUN.getValue(), ChronoUnit.MILLIS)) // + .timeleap(clock, LONG_ACTIVATION_RUN.getValue(), MILLIS)) // .next(new TestCase("30") // .output(STATE_MACHINE, State.SUPPORT_DURATION)// - .output(ESS_ACTIVE_POWER, 92000)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 92000)) // .next(new TestCase("31") // - .timeleap(clock, ActivationTime.LONG_ACTIVATION_RUN.getValue(), ChronoUnit.MILLIS)) // + .timeleap(clock, LONG_ACTIVATION_RUN.getValue(), MILLIS)) // .next(new TestCase("32") // .output(STATE_MACHINE, State.SUPPORT_DURATION)// - .output(ESS_ACTIVE_POWER, 92000)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 92000)) // .next(new TestCase("33") // - .timeleap(clock, SupportDuration.LONG_SUPPORT_DURATION.getValue(), ChronoUnit.SECONDS) // + .timeleap(clock, LONG_SUPPORT_DURATION.getValue(), SECONDS) // .output(STATE_MACHINE, State.SUPPORT_DURATION)) .next(new TestCase("34") // - .output(STATE_MACHINE, State.DEACTIVATION_TIME).output(ESS_ACTIVE_POWER, 0)) + .output(STATE_MACHINE, State.DEACTIVATION_TIME).output("ess0", SET_ACTIVE_POWER_EQUALS, 0)) .next(new TestCase("35") // - .timeleap(clock, ActivationTime.LONG_ACTIVATION_RUN.getValue(), ChronoUnit.MILLIS)) // + .timeleap(clock, LONG_ACTIVATION_RUN.getValue(), MILLIS)) // .next(new TestCase("36") // .output(STATE_MACHINE, State.BUFFERED_TIME_BEFORE_RECOVERY) // - .output(ESS_ACTIVE_POWER, 0)) + .output("ess0", SET_ACTIVE_POWER_EQUALS, 0)) .next(new TestCase("37") // .output(STATE_MACHINE, State.BUFFERED_TIME_BEFORE_RECOVERY)) .next(new TestCase("38") // .output(STATE_MACHINE, State.BUFFERED_TIME_BEFORE_RECOVERY)) .next(new TestCase("39") // - .timeleap(clock, SupportDuration.LONG_SUPPORT_DURATION.getValue(), ChronoUnit.MINUTES)) + .timeleap(clock, LONG_SUPPORT_DURATION.getValue(), MINUTES)) .next(new TestCase("40") // - .input(METER_FREQUENCY, 50000)// + .input("meter0", FREQUENCY, 50000)// .output(STATE_MACHINE, State.BUFFERED_TIME_BEFORE_RECOVERY)) .next(new TestCase("41") // - .input(METER_FREQUENCY, 50000)// + .input("meter0", FREQUENCY, 50000)// .output(STATE_MACHINE, State.RECOVERY_TIME)) .next(new TestCase("42") // - .timeleap(clock, 1, ChronoUnit.DAYS)); + .timeleap(clock, 1, DAYS)) // + .deactivate(); } @Test public void testInvalidJsonSchedule() throws Exception { - final var clock = new TimeLeapClock(Instant.parse("2023-07-13T08:45:00.00Z"), ZoneOffset.UTC); - - final var cm = new DummyComponentManager(clock); - + final var clock = createDummyClock(); new ControllerTest(new ControllerFastFrequencyReserveImpl()) // - .addReference("componentManager", cm) // + .addReference("componentManager", new DummyComponentManager(clock)) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("ess", ESS // + .addReference("ess", new DummyManagedSymmetricEss("ess0") // .withGridMode(GridMode.ON_GRID)// .withMaxApparentPower(92000)// .withAllowedChargePower(-92000)// .withAllowedDischargePower(92000)) // - .addReference("meter", METER) // + .addReference("meter", new DummyElectricityMeter("meter0")) // .activate(MyConfig.create() // - .setEssId(ESS_ID) // - .setId(CTRL_ID) // - .setMeterId(METER_ID) // + .setEssId("ess0") // + .setId("ctrl0") // + .setMeterId("meter0") // .setMode(ControlMode.MANUAL_ON) // .setPreActivationTime(15)// .setactivationScheduleJson("foo")// - .build()); + .build()) // + .deactivate(); } @Test public void testInvalidJsonSchedule1() throws Exception { - final var clock = new TimeLeapClock(Instant.parse("2023-07-13T08:45:00.00Z"), ZoneOffset.UTC); - - final var cm = new DummyComponentManager(clock); - + final var clock = createDummyClock(); new ControllerTest(new ControllerFastFrequencyReserveImpl()) // - .addReference("componentManager", cm) // + .addReference("componentManager", new DummyComponentManager(clock)) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("ess", ESS // + .addReference("ess", new DummyManagedSymmetricEss("ess0") // .withGridMode(GridMode.ON_GRID)// .withMaxApparentPower(92000)// .withAllowedChargePower(-92000)// .withAllowedDischargePower(92000)) // - .addReference("meter", METER) // + .addReference("meter", new DummyElectricityMeter("meter0")) // .activate(MyConfig.create() // - .setEssId(ESS_ID) // - .setId(CTRL_ID) // - .setMeterId(METER_ID) // + .setEssId("ess0") // + .setId("ctrl0") // + .setMeterId("meter0") // .setMode(ControlMode.MANUAL_ON) // .setPreActivationTime(15)// .setactivationScheduleJson("[foo]")// - .build()); - + .build()) // + .deactivate(); } - public static final String myJson = "[\r\n" + " " // - + "{\r\n" + " " // - + "\"startTimestamp\": \"1701738000\",\r\n"// - + " \"duration\": \"10800\",\r\n" // - + " \"dischargePowerSetPoint\": \"92000\",\r\n"// - + " \"frequencyLimit\": \"50000\",\r\n"// - + " \"activationRunTime\": \"LONG_ACTIVATION_RUN\",\r\n"// - + " \"supportDuration\": \"LONG_SUPPORT_DURATION\"\r\n" // - + " },\r\n" // - + "{\r\n" + " " // - + "\"startTimestamp\": \"1701738000\",\r\n"// - + " \"duration\": \"10800\",\r\n" // - + " \"dischargePowerSetPoint\": \"92000\",\r\n"// - + " \"frequencyLimit\": \"50000\",\r\n"// - + " \"activationRunTime\": \"LONG_ACTIVATION_RUN\",\r\n"// - + " \"supportDuration\": \"LONG_SUPPORT_DURATION\"\r\n" // - + " },\r\n" // - + " {\r\n"// - + " \"startTimestamp\": \"1701752400\",\r\n"// - + " \"duration\": \"10800\",\r\n"// - + " \"dischargePowerSetPoint\": \"92000\",\r\n"// - + " \"frequencyLimit\": \"50000\",\r\n"// - + " \"activationRunTime\": \"LONG_ACTIVATION_RUN\",\r\n"// - + " \"supportDuration\": \"LONG_SUPPORT_DURATION\"\r\n" // - + " },\r\n" // - + " {\r\n"// - + " \"startTimestamp\": \"1701777600\",\r\n"// - + " \"duration\": \"10800\",\r\n"// - + " \"dischargePowerSetPoint\": \"92000\",\r\n"// - + " \"frequencyLimit\": \"50000\",\r\n"// - + " \"activationRunTime\": \"LONG_ACTIVATION_RUN\",\r\n"// - + " \"supportDuration\": \"LONG_SUPPORT_DURATION\"\r\n" // - + " }\r\n" + "]";// + public static final String MY_JSON = """ + [ + { + "startTimestamp":"1701738000", + "duration":"10800", + "dischargePowerSetPoint":"92000", + "frequencyLimit":"50000", + "activationRunTime":"LONG_ACTIVATION_RUN", + "supportDuration":"LONG_SUPPORT_DURATION" + }, + { + "startTimestamp":"1701738000", + "duration":"10800", + "dischargePowerSetPoint":"92000", + "frequencyLimit":"50000", + "activationRunTime":"LONG_ACTIVATION_RUN", + "supportDuration":"LONG_SUPPORT_DURATION" + }, + { + "startTimestamp":"1701752400", + "duration":"10800", + "dischargePowerSetPoint":"92000", + "frequencyLimit":"50000", + "activationRunTime":"LONG_ACTIVATION_RUN", + "supportDuration":"LONG_SUPPORT_DURATION" + }, + { + "startTimestamp":"1701777600", + "duration":"10800", + "dischargePowerSetPoint":"92000", + "frequencyLimit":"50000", + "activationRunTime":"LONG_ACTIVATION_RUN", + "supportDuration":"LONG_SUPPORT_DURATION" + } + ] + """; @Test public void testFromMethod() throws OpenemsNamedException { - - var scheduleElement = JsonUtils.parse(myJson); - var scheduleArray = JsonUtils.getAsJsonArray(scheduleElement); - + var scheduleArray = JsonUtils.parseToJsonArray(MY_JSON); try { List scheduleList = ActivateFastFreqReserveSchedule.from(scheduleArray); diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/MyControllerTest2.java b/io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/ControllerFastFrequencyReserveImplTest2.java similarity index 53% rename from io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/MyControllerTest2.java rename to io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/ControllerFastFrequencyReserveImplTest2.java index 69fc5e7e463..d1bbb7c9da1 100644 --- a/io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/MyControllerTest2.java +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/ControllerFastFrequencyReserveImplTest2.java @@ -1,185 +1,182 @@ package io.openems.edge.controller.ess.fastfrequencyreserve; +import static io.openems.common.utils.JsonUtils.buildJsonArray; +import static io.openems.common.utils.JsonUtils.buildJsonObject; +import static io.openems.edge.controller.ess.fastfrequencyreserve.ControllerFastFrequencyReserve.ChannelId.STATE_MACHINE; +import static io.openems.edge.controller.ess.fastfrequencyreserve.enums.ActivationTime.LONG_ACTIVATION_RUN; +import static io.openems.edge.controller.ess.fastfrequencyreserve.enums.SupportDuration.LONG_SUPPORT_DURATION; +import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_EQUALS; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.FREQUENCY; +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.HOURS; +import static java.time.temporal.ChronoUnit.MILLIS; +import static java.time.temporal.ChronoUnit.MINUTES; +import static java.time.temporal.ChronoUnit.SECONDS; + import java.time.Instant; import java.time.ZoneOffset; -import java.time.temporal.ChronoUnit; import org.junit.Test; import io.openems.common.test.TimeLeapClock; -import io.openems.common.types.ChannelAddress; -import io.openems.common.utils.JsonUtils; import io.openems.edge.common.sum.GridMode; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.controller.ess.fastfrequencyreserve.enums.ActivationTime; import io.openems.edge.controller.ess.fastfrequencyreserve.enums.ControlMode; -import io.openems.edge.controller.ess.fastfrequencyreserve.enums.SupportDuration; import io.openems.edge.controller.ess.fastfrequencyreserve.statemachine.StateMachine.State; import io.openems.edge.controller.test.ControllerTest; import io.openems.edge.ess.test.DummyManagedSymmetricEss; import io.openems.edge.meter.test.DummyElectricityMeter; -public class MyControllerTest2 { - - private static final String CTRL_ID = "ctrl0"; - private static final String ESS_ID = "ess0"; - private static final String METER_ID = "meter0"; - - private static final DummyManagedSymmetricEss ESS = new DummyManagedSymmetricEss(ESS_ID); - private static final DummyElectricityMeter METER = new DummyElectricityMeter(METER_ID); - - private static final ChannelAddress METER_FREQUENCY = new ChannelAddress(METER_ID, "Frequency"); - private static final ChannelAddress STATE_MACHINE = new ChannelAddress(CTRL_ID, "StateMachine"); - private static final ChannelAddress ESS_ACTIVE_POWER = new ChannelAddress(ESS_ID, "SetActivePowerEquals"); +public class ControllerFastFrequencyReserveImplTest2 { @Test public void test1() throws Exception { final var clock = new TimeLeapClock(Instant.parse("2023-07-13T08:45:00.00Z"), ZoneOffset.UTC); - final var cm = new DummyComponentManager(clock); - new ControllerTest(new ControllerFastFrequencyReserveImpl()) // - .addReference("componentManager", cm) // + .addReference("componentManager", new DummyComponentManager(clock)) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("ess", ESS // + .addReference("ess", new DummyManagedSymmetricEss("ess0") // .withGridMode(GridMode.ON_GRID)// .withMaxApparentPower(92000)// .withAllowedChargePower(-92000)// .withAllowedDischargePower(92000)) // - .addReference("meter", METER) // + .addReference("meter", new DummyElectricityMeter("meter0")) // .activate(MyConfig.create() // - .setEssId(ESS_ID) // - .setId(CTRL_ID) // - .setMeterId(METER_ID) // + .setEssId("ess0") // + .setId("ctrl0") // + .setMeterId("meter0") // .setMode(ControlMode.MANUAL_ON) // .setPreActivationTime(15)// - .setactivationScheduleJson(JsonUtils.buildJsonArray() // - .add(JsonUtils.buildJsonObject() // + .setactivationScheduleJson(buildJsonArray() // + .add(buildJsonObject() // .addProperty("startTimestamp", 1689242400) // Thu Jul 13 2023 10:00:00 GMT+0000 .addProperty("duration", 86400) // .addProperty("dischargePowerSetPoint", 92000) // .addProperty("frequencyLimit", 49500) // - .addProperty("activationRunTime", ActivationTime.LONG_ACTIVATION_RUN) // - .addProperty("supportDuration", SupportDuration.LONG_SUPPORT_DURATION) // + .addProperty("activationRunTime", LONG_ACTIVATION_RUN) // + .addProperty("supportDuration", LONG_SUPPORT_DURATION) // .build()) - .add(JsonUtils.buildJsonObject() // + .add(buildJsonObject() // .addProperty("startTimestamp", 1689331500) // Fri Jul 14 2023 10:45:00 GMT+0000 .addProperty("duration", 86400) // .addProperty("dischargePowerSetPoint", 92000) // .addProperty("frequencyLimit", 49500) // - .addProperty("activationRunTime", ActivationTime.LONG_ACTIVATION_RUN) // - .addProperty("supportDuration", SupportDuration.LONG_SUPPORT_DURATION) // + .addProperty("activationRunTime", LONG_ACTIVATION_RUN) // + .addProperty("supportDuration", LONG_SUPPORT_DURATION) // .build()) .build()// .toString())// .build()) .next(new TestCase("1") // - .input(METER_FREQUENCY, 50000)// - .output(STATE_MACHINE, State.UNDEFINED) // - .output(ESS_ACTIVE_POWER, null))// + .input("meter0", FREQUENCY, 50000)// + .output(ControllerFastFrequencyReserve.ChannelId.STATE_MACHINE, State.UNDEFINED) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, null))// .next(new TestCase("2") // - .input(METER_FREQUENCY, 50000)// + .input("meter0", FREQUENCY, 50000)// .output(STATE_MACHINE, State.UNDEFINED) // - .output(ESS_ACTIVE_POWER, null))// + .output("ess0", SET_ACTIVE_POWER_EQUALS, null))// .next(new TestCase("3") // - .timeleap(clock, 1, ChronoUnit.HOURS) // - .input(METER_FREQUENCY, 50000))// + .timeleap(clock, 1, HOURS) // + .input("meter0", FREQUENCY, 50000))// .next(new TestCase("4"))// .next(new TestCase("5") // .output(STATE_MACHINE, State.UNDEFINED)) .next(new TestCase("6") // - .timeleap(clock, 10, ChronoUnit.MINUTES)// + .timeleap(clock, 10, MINUTES)// .output(STATE_MACHINE, State.PRE_ACTIVATION_STATE)) .next(new TestCase("7") // - .timeleap(clock, 10, ChronoUnit.MINUTES)) + .timeleap(clock, 10, MINUTES)) .next(new TestCase("8") // .output(STATE_MACHINE, State.ACTIVATION_TIME)// - .output(ESS_ACTIVE_POWER, 0)) + .output("ess0", SET_ACTIVE_POWER_EQUALS, 0)) .next(new TestCase("9") // - .input(METER_FREQUENCY, 50000)// + .input("meter0", FREQUENCY, 50000)// .output(STATE_MACHINE, State.ACTIVATION_TIME)// - .output(ESS_ACTIVE_POWER, 0)) + .output("ess0", SET_ACTIVE_POWER_EQUALS, 0)) .next(new TestCase("10") // - .input(METER_FREQUENCY, 49400)// + .input("meter0", FREQUENCY, 49400)// .output(STATE_MACHINE, State.ACTIVATION_TIME)// - .output(ESS_ACTIVE_POWER, 92000)) + .output("ess0", SET_ACTIVE_POWER_EQUALS, 92000)) .next(new TestCase("11") // - .timeleap(clock, ActivationTime.LONG_ACTIVATION_RUN.getValue(), ChronoUnit.MILLIS)) // + .timeleap(clock, LONG_ACTIVATION_RUN.getValue(), MILLIS)) // .next(new TestCase("12") // .output(STATE_MACHINE, State.SUPPORT_DURATION)// - .output(ESS_ACTIVE_POWER, 92000)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 92000)) // .next(new TestCase("13") // - .timeleap(clock, SupportDuration.LONG_SUPPORT_DURATION.getValue(), ChronoUnit.SECONDS) // + .timeleap(clock, LONG_SUPPORT_DURATION.getValue(), SECONDS) // .output(STATE_MACHINE, State.SUPPORT_DURATION)) .next(new TestCase("14") // - .output(STATE_MACHINE, State.DEACTIVATION_TIME).output(ESS_ACTIVE_POWER, 0)) + .output(STATE_MACHINE, State.DEACTIVATION_TIME).output("ess0", SET_ACTIVE_POWER_EQUALS, 0)) .next(new TestCase("15") // - .timeleap(clock, ActivationTime.LONG_ACTIVATION_RUN.getValue(), ChronoUnit.MILLIS)) // + .timeleap(clock, LONG_ACTIVATION_RUN.getValue(), MILLIS)) // .next(new TestCase("16") // .output(STATE_MACHINE, State.BUFFERED_TIME_BEFORE_RECOVERY) // - .output(ESS_ACTIVE_POWER, 0)) + .output("ess0", SET_ACTIVE_POWER_EQUALS, 0)) .next(new TestCase("17") // - .timeleap(clock, 16, ChronoUnit.SECONDS) // + .timeleap(clock, 16, SECONDS) // .output(STATE_MACHINE, State.BUFFERED_TIME_BEFORE_RECOVERY)) .next(new TestCase("18") // - .timeleap(clock, 12, ChronoUnit.MINUTES)) // + .timeleap(clock, 12, MINUTES)) // .next(new TestCase("19") // .output(STATE_MACHINE, State.RECOVERY_TIME) // - .output(ESS_ACTIVE_POWER, -16560)) + .output("ess0", SET_ACTIVE_POWER_EQUALS, -16560)) .next(new TestCase("20") // .output(STATE_MACHINE, State.RECOVERY_TIME)) .next(new TestCase("21") // .output(STATE_MACHINE, State.RECOVERY_TIME)) .next(new TestCase("22") // - .timeleap(clock, SupportDuration.LONG_SUPPORT_DURATION.getValue(), ChronoUnit.MINUTES)) + .timeleap(clock, LONG_SUPPORT_DURATION.getValue(), MINUTES)) .next(new TestCase("23") // - .input(METER_FREQUENCY, 50000)// + .input("meter0", FREQUENCY, 50000)// .output(STATE_MACHINE, State.ACTIVATION_TIME)) .next(new TestCase("24") // - .timeleap(clock, 1, ChronoUnit.DAYS)) // + .timeleap(clock, 1, DAYS)) // .next(new TestCase("25") // .output(STATE_MACHINE, State.ACTIVATION_TIME)) .next(new TestCase("26") // - .timeleap(clock, 4, ChronoUnit.HOURS)) // + .timeleap(clock, 4, HOURS)) // .next(new TestCase("27") // .output(STATE_MACHINE, State.ACTIVATION_TIME)) .next(new TestCase("28")// - .input(METER_FREQUENCY, 49400)) + .input("meter0", FREQUENCY, 49400)) .next(new TestCase("29") // - .timeleap(clock, ActivationTime.LONG_ACTIVATION_RUN.getValue(), ChronoUnit.MILLIS)) // + .timeleap(clock, LONG_ACTIVATION_RUN.getValue(), MILLIS)) // .next(new TestCase("30") // .output(STATE_MACHINE, State.SUPPORT_DURATION)// - .output(ESS_ACTIVE_POWER, 92000)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 92000)) // .next(new TestCase("31") // - .timeleap(clock, ActivationTime.LONG_ACTIVATION_RUN.getValue(), ChronoUnit.MILLIS)) // + .timeleap(clock, LONG_ACTIVATION_RUN.getValue(), MILLIS)) // .next(new TestCase("32") // .output(STATE_MACHINE, State.SUPPORT_DURATION)// - .output(ESS_ACTIVE_POWER, 92000)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 92000)) // .next(new TestCase("33") // - .timeleap(clock, SupportDuration.LONG_SUPPORT_DURATION.getValue(), ChronoUnit.SECONDS) // + .timeleap(clock, LONG_SUPPORT_DURATION.getValue(), SECONDS) // .output(STATE_MACHINE, State.SUPPORT_DURATION)) .next(new TestCase("34") // - .output(STATE_MACHINE, State.DEACTIVATION_TIME).output(ESS_ACTIVE_POWER, 0)) + .output(STATE_MACHINE, State.DEACTIVATION_TIME) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 0)) .next(new TestCase("35") // - .timeleap(clock, ActivationTime.LONG_ACTIVATION_RUN.getValue(), ChronoUnit.MILLIS)) // + .timeleap(clock, LONG_ACTIVATION_RUN.getValue(), MILLIS)) // .next(new TestCase("36") // .output(STATE_MACHINE, State.BUFFERED_TIME_BEFORE_RECOVERY) // - .output(ESS_ACTIVE_POWER, 0)) + .output("ess0", SET_ACTIVE_POWER_EQUALS, 0)) .next(new TestCase("37") // .output(STATE_MACHINE, State.BUFFERED_TIME_BEFORE_RECOVERY)) .next(new TestCase("38") // .output(STATE_MACHINE, State.BUFFERED_TIME_BEFORE_RECOVERY)) .next(new TestCase("39") // - .timeleap(clock, SupportDuration.LONG_SUPPORT_DURATION.getValue(), ChronoUnit.MINUTES)) + .timeleap(clock, LONG_SUPPORT_DURATION.getValue(), MINUTES)) .next(new TestCase("40") // - .input(METER_FREQUENCY, 50000)// + .input("meter0", FREQUENCY, 50000)// .output(STATE_MACHINE, State.BUFFERED_TIME_BEFORE_RECOVERY)) .next(new TestCase("41") // - .input(METER_FREQUENCY, 50000)// + .input("meter0", FREQUENCY, 50000)// .output(STATE_MACHINE, State.RECOVERY_TIME)) .next(new TestCase("42") // - .timeleap(clock, 1, ChronoUnit.DAYS)); + .timeleap(clock, 1, DAYS)) // + .deactivate(); } } diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/MyConfig.java b/io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/MyConfig.java index efc5087e1f3..948d3e0fb3a 100644 --- a/io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/MyConfig.java +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/MyConfig.java @@ -2,9 +2,7 @@ import io.openems.common.test.AbstractComponentConfig; import io.openems.common.utils.ConfigUtils; -import io.openems.edge.controller.ess.fastfrequencyreserve.enums.ActivationTime; import io.openems.edge.controller.ess.fastfrequencyreserve.enums.ControlMode; -import io.openems.edge.controller.ess.fastfrequencyreserve.enums.SupportDuration; @SuppressWarnings("all") public class MyConfig extends AbstractComponentConfig implements Config { diff --git a/io.openems.edge.controller.ess.fixactivepower/test/io/openems/edge/controller/ess/fixactivepower/ControllerEssFixActivePowerImplTest.java b/io.openems.edge.controller.ess.fixactivepower/test/io/openems/edge/controller/ess/fixactivepower/ControllerEssFixActivePowerImplTest.java index d26fa505e44..ebcde754b1d 100644 --- a/io.openems.edge.controller.ess.fixactivepower/test/io/openems/edge/controller/ess/fixactivepower/ControllerEssFixActivePowerImplTest.java +++ b/io.openems.edge.controller.ess.fixactivepower/test/io/openems/edge/controller/ess/fixactivepower/ControllerEssFixActivePowerImplTest.java @@ -1,5 +1,6 @@ package io.openems.edge.controller.ess.fixactivepower; +import static io.openems.edge.controller.ess.fixactivepower.ControllerEssFixActivePowerImpl.getAcPower; import static org.junit.Assert.assertEquals; import org.junit.Test; @@ -14,45 +15,44 @@ public class ControllerEssFixActivePowerImplTest { - private static final String CTRL_ID = "ctrl0"; - private static final String ESS_ID = "ess0"; - @Test public void testOn() throws OpenemsException, Exception { - final var ess = new DummyManagedAsymmetricEss(ESS_ID); + final var ess = new DummyManagedAsymmetricEss("ess0"); new ControllerTest(new ControllerEssFixActivePowerImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("ess", ess) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setMode(Mode.MANUAL_ON) // .setHybridEssMode(HybridEssMode.TARGET_DC) // .setPower(1234) // .setPhase(Phase.ALL) // .setRelationship(Relationship.EQUALS) // - .build()); // + .build()) // + .deactivate(); } @Test public void testOff() throws OpenemsException, Exception { new ControllerTest(new ControllerEssFixActivePowerImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("ess", new DummyManagedAsymmetricEss(ESS_ID)) // + .addReference("ess", new DummyManagedAsymmetricEss("ess0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setMode(Mode.MANUAL_OFF) // .setHybridEssMode(HybridEssMode.TARGET_DC) // .setPower(1234) // .setPhase(Phase.ALL) // .setRelationship(Relationship.EQUALS) // - .build()); // + .build()) // + .deactivate(); } @Test public void testGetAcPower() throws OpenemsException, Exception { - var hybridEss = new DummyHybridEss(ESS_ID) // + var hybridEss = new DummyHybridEss("ess0") // .withActivePower(7000) // .withMaxApparentPower(10000) // .withAllowedChargePower(-5000) // @@ -60,9 +60,9 @@ public void testGetAcPower() throws OpenemsException, Exception { .withDcDischargePower(3000); // assertEquals(Integer.valueOf(5000), // - ControllerEssFixActivePowerImpl.getAcPower(hybridEss, HybridEssMode.TARGET_AC, 5000)); + getAcPower(hybridEss, HybridEssMode.TARGET_AC, 5000)); assertEquals(Integer.valueOf(9000), // - ControllerEssFixActivePowerImpl.getAcPower(hybridEss, HybridEssMode.TARGET_DC, 5000)); + getAcPower(hybridEss, HybridEssMode.TARGET_DC, 5000)); } } diff --git a/io.openems.edge.controller.ess.fixstateofcharge/test/io/openems/edge/controller/ess/fixstateofcharge/ControllerEssFixStateOfChargeImplTest.java b/io.openems.edge.controller.ess.fixstateofcharge/test/io/openems/edge/controller/ess/fixstateofcharge/ControllerEssFixStateOfChargeImplTest.java index 48553f06491..70d0b636428 100644 --- a/io.openems.edge.controller.ess.fixstateofcharge/test/io/openems/edge/controller/ess/fixstateofcharge/ControllerEssFixStateOfChargeImplTest.java +++ b/io.openems.edge.controller.ess.fixstateofcharge/test/io/openems/edge/controller/ess/fixstateofcharge/ControllerEssFixStateOfChargeImplTest.java @@ -1,10 +1,23 @@ package io.openems.edge.controller.ess.fixstateofcharge; +import static io.openems.edge.controller.ess.fixstateofcharge.api.AbstractFixStateOfCharge.DEFAULT_POWER_FACTOR; +import static io.openems.edge.controller.ess.fixstateofcharge.api.EndCondition.CAPACITY_CHANGED; +import static io.openems.edge.controller.ess.fixstateofcharge.api.FixStateOfCharge.ChannelId.DEBUG_SET_ACTIVE_POWER; +import static io.openems.edge.controller.ess.fixstateofcharge.api.FixStateOfCharge.ChannelId.DEBUG_SET_ACTIVE_POWER_RAW; +import static io.openems.edge.controller.ess.fixstateofcharge.api.FixStateOfCharge.ChannelId.STATE_MACHINE; +import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_EQUALS; +import static io.openems.edge.ess.api.SymmetricEss.ChannelId.CAPACITY; +import static io.openems.edge.ess.api.SymmetricEss.ChannelId.MAX_APPARENT_POWER; +import static io.openems.edge.ess.api.SymmetricEss.ChannelId.SOC; +import static java.lang.Math.min; +import static java.lang.Math.round; +import static java.time.temporal.ChronoUnit.HOURS; +import static java.time.temporal.ChronoUnit.MINUTES; + import java.time.Instant; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; -import java.time.temporal.ChronoUnit; import org.junit.Test; @@ -14,54 +27,30 @@ import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.controller.ess.fixstateofcharge.api.AbstractFixStateOfCharge; -import io.openems.edge.controller.ess.fixstateofcharge.api.EndCondition; -import io.openems.edge.controller.ess.fixstateofcharge.statemachine.StateMachine; +import io.openems.edge.controller.ess.fixstateofcharge.statemachine.StateMachine.State; import io.openems.edge.controller.test.ControllerTest; import io.openems.edge.ess.test.DummyManagedSymmetricEss; import io.openems.edge.timedata.test.DummyTimedata; public class ControllerEssFixStateOfChargeImplTest { - // Ids - private static final String CTRL_ID = "ctrlFixStateOfCharge0"; - private static final String ESS_ID = "ess0"; - - // Components - private static final DummyManagedSymmetricEss ESS = new DummyManagedSymmetricEss(ESS_ID) // + private static final DummyManagedSymmetricEss ESS = new DummyManagedSymmetricEss("ess0") // .withMaxApparentPower(10_000); - - // Defaults private static final String DEFAULT_TARGET_TIME = "2022-10-27T10:30:00+01:00"; - - // Ess channels - private static final ChannelAddress ESS_CAPACITY = new ChannelAddress(ESS_ID, "Capacity"); - private static final ChannelAddress ESS_SOC = new ChannelAddress(ESS_ID, "Soc"); - private static final ChannelAddress ESS_MAX_APPARENT_POWER = new ChannelAddress(ESS_ID, "MaxApparentPower"); - private static final ChannelAddress ESS_SET_ACTIVE_POWER_EQUALS = new ChannelAddress(ESS_ID, - "SetActivePowerEquals"); - - // Controller channels - private static final ChannelAddress STATE_MACHINE = new ChannelAddress(CTRL_ID, "StateMachine"); - private static final ChannelAddress DEBUG_SET_ACTIVE_POWER = new ChannelAddress(CTRL_ID, "DebugSetActivePower"); - private static final ChannelAddress DEBUG_SET_ACTIVE_POWER_RAW = new ChannelAddress(CTRL_ID, - "DebugSetActivePowerRaw"); - private static final ChannelAddress CTRL_ESS_CAPACITY = new ChannelAddress(CTRL_ID, "EssCapacity"); + private static final ChannelAddress CTRL_ESS_CAPACITY = new ChannelAddress("ctrl0", "EssCapacity"); @Test public void testNotRunning() throws Exception { final var clock = new TimeLeapClock(Instant.parse("2022-01-01T08:00:00.00Z"), ZoneOffset.UTC); - final var componentManager = new DummyComponentManager(clock); - new ControllerTest(new ControllerEssFixStateOfChargeImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("componentManager", componentManager) // + .addReference("componentManager", new DummyComponentManager(clock)) // .addReference("timedata", new DummyTimedata("timedata0")) // .addReference("sum", new DummySum()) // .addReference("ess", ESS) // .activate(FixStateOfChargeConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setRunning(false) // .setTargetSoc(30) // .setSpecifyTargetTime(true) // @@ -69,29 +58,30 @@ public void testNotRunning() throws Exception { .setSelfTermination(false) // .setTerminationBuffer(720) // .setConditionalTermination(false) // - .setEndCondition(EndCondition.CAPACITY_CHANGED) // + .setEndCondition(CAPACITY_CHANGED) // .build()) .next(new TestCase()) // .next(new TestCase() // - .output(ESS_SET_ACTIVE_POWER_EQUALS, null) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, null) // .output(DEBUG_SET_ACTIVE_POWER, null) // .output(DEBUG_SET_ACTIVE_POWER_RAW, null) // - .output(STATE_MACHINE, StateMachine.State.IDLE) // - ); + .output(STATE_MACHINE, State.IDLE)) // + .deactivate(); } @Test public void testAllStates() throws Exception { + final var clock = new TimeLeapClock(Instant.parse("2023-01-01T08:00:00.00Z"), ZoneOffset.UTC); new ControllerTest(new ControllerEssFixStateOfChargeImpl()) // - .addReference("componentManager", new DummyComponentManager()) // + .addReference("componentManager", new DummyComponentManager(clock)) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // .addReference("timedata", new DummyTimedata("timedata0")) // - .addReference("ess", new DummyManagedSymmetricEss(ESS_ID)) // + .addReference("ess", new DummyManagedSymmetricEss("ess0")) // .activate(FixStateOfChargeConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setRunning(true) // .setTargetSoc(30) // .setSpecifyTargetTime(true) // @@ -99,39 +89,39 @@ public void testAllStates() throws Exception { .setSelfTermination(false) // .setTerminationBuffer(720) // .setConditionalTermination(true) // - .setEndCondition(EndCondition.CAPACITY_CHANGED) // + .setEndCondition(CAPACITY_CHANGED) // .build()) .next(new TestCase() // - .input(ESS_SOC, 22) // - .input(ESS_MAX_APPARENT_POWER, 10000) // - .output(STATE_MACHINE, StateMachine.State.IDLE)) // + .input("ess0", SOC, 22) // + .input("ess0", MAX_APPARENT_POWER, 10000) // + .output(STATE_MACHINE, State.IDLE)) // .next(new TestCase() // - .input(ESS_SOC, 22) // - .input(ESS_MAX_APPARENT_POWER, 10000) // - .output(STATE_MACHINE, StateMachine.State.IDLE)) // + .input("ess0", SOC, 22) // + .input("ess0", MAX_APPARENT_POWER, 10000) // + .output(STATE_MACHINE, State.IDLE)) // .next(new TestCase() // - .input(ESS_SOC, 21) // - .output(STATE_MACHINE, StateMachine.State.NOT_STARTED)) // + .input("ess0", SOC, 21) // + .output(STATE_MACHINE, State.NOT_STARTED)) // .next(new TestCase() // - .input(ESS_SOC, 20) // - .output(STATE_MACHINE, StateMachine.State.BELOW_TARGET_SOC)) // + .input("ess0", SOC, 20) // + .output(STATE_MACHINE, State.BELOW_TARGET_SOC)) // .next(new TestCase() // - .input(ESS_SOC, 25) // - .output(STATE_MACHINE, StateMachine.State.BELOW_TARGET_SOC)) // + .input("ess0", SOC, 25) // + .output(STATE_MACHINE, State.BELOW_TARGET_SOC)) // .next(new TestCase() // - .input(ESS_SOC, 30)) // + .input("ess0", SOC, 30)) // .next(new TestCase() // - .input(ESS_SOC, 30) /// - .output(STATE_MACHINE, StateMachine.State.AT_TARGET_SOC)) // + .input("ess0", SOC, 30) /// + .output(STATE_MACHINE, State.AT_TARGET_SOC)) // .next(new TestCase() // - .input(ESS_SOC, 30) // - .output(STATE_MACHINE, StateMachine.State.AT_TARGET_SOC)) // - ; + .input("ess0", SOC, 30) // + .output(STATE_MACHINE, State.AT_TARGET_SOC)) // + .deactivate(); } @Test public void testCapacityCondition() throws Exception { - + final var clock = new TimeLeapClock(Instant.parse("2023-01-01T08:00:00.00Z"), ZoneOffset.UTC); var timedata = new DummyTimedata("timedata0"); var start = ZonedDateTime.of(2022, 05, 05, 0, 0, 0, 0, ZoneId.of("UTC")); @@ -139,15 +129,15 @@ public void testCapacityCondition() throws Exception { timedata.add(start.plusMinutes(60), CTRL_ESS_CAPACITY, 8_000); timedata.add(start.plusMinutes(90), CTRL_ESS_CAPACITY, 8_000); - var test = new ControllerTest(new ControllerEssFixStateOfChargeImpl()) // - .addReference("componentManager", new DummyComponentManager()) // + new ControllerTest(new ControllerEssFixStateOfChargeImpl()) // + .addReference("componentManager", new DummyComponentManager(clock)) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // .addReference("timedata", timedata) // - .addReference("ess", new DummyManagedSymmetricEss(ESS_ID)) // + .addReference("ess", new DummyManagedSymmetricEss("ess0")) // .activate(FixStateOfChargeConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setRunning(true) // .setTargetSoc(30) // .setSpecifyTargetTime(true) // @@ -155,70 +145,66 @@ public void testCapacityCondition() throws Exception { .setSelfTermination(false) // .setTerminationBuffer(720) // .setConditionalTermination(true) // - .setEndCondition(EndCondition.CAPACITY_CHANGED) // + .setEndCondition(CAPACITY_CHANGED) // .build()) .next(new TestCase() // - .input(ESS_SOC, 22) // - .input(ESS_MAX_APPARENT_POWER, 10000) // - .output(STATE_MACHINE, StateMachine.State.IDLE)) // + .input("ess0", SOC, 22) // + .input("ess0", MAX_APPARENT_POWER, 10000) // + .output(STATE_MACHINE, State.IDLE)) // .next(new TestCase() // - .input(ESS_SOC, 22) // - .input(ESS_MAX_APPARENT_POWER, 10000) // - .output(STATE_MACHINE, StateMachine.State.IDLE)) // + .input("ess0", SOC, 22) // + .input("ess0", MAX_APPARENT_POWER, 10000) // + .output(STATE_MACHINE, State.IDLE)) // .next(new TestCase() // - .input(ESS_SOC, 21) // - .output(STATE_MACHINE, StateMachine.State.NOT_STARTED)) // + .input("ess0", SOC, 21) // + .output(STATE_MACHINE, State.NOT_STARTED)) // .next(new TestCase() // - .input(ESS_SOC, 20) // - .output(STATE_MACHINE, StateMachine.State.BELOW_TARGET_SOC)) // + .input("ess0", SOC, 20) // + .output(STATE_MACHINE, State.BELOW_TARGET_SOC)) // .next(new TestCase() // - .input(ESS_SOC, 25) // + .input("ess0", SOC, 25) // .input(CTRL_ESS_CAPACITY, 8_000) // - .input(ESS_CAPACITY, 8_000) // + .input("ess0", CAPACITY, 8_000) // .output(CTRL_ESS_CAPACITY, 8_000) // - .output(STATE_MACHINE, StateMachine.State.BELOW_TARGET_SOC)) // + .output(STATE_MACHINE, State.BELOW_TARGET_SOC)) // .next(new TestCase() // - .input(ESS_CAPACITY, 8_000) // - .input(ESS_SOC, 30) // + .input("ess0", CAPACITY, 8_000) // + .input("ess0", SOC, 30) // .output(CTRL_ESS_CAPACITY, 8_000)) // .next(new TestCase() // - .input(ESS_SOC, 30) /// - .input(ESS_CAPACITY, 8_000) // + .input("ess0", SOC, 30) /// + .input("ess0", CAPACITY, 8_000) // .output(CTRL_ESS_CAPACITY, 8_000) // - .output(STATE_MACHINE, StateMachine.State.AT_TARGET_SOC)) // - ; + .output(STATE_MACHINE, State.AT_TARGET_SOC)) // - // EMS restart - test.next(new TestCase() // - .input(ESS_CAPACITY, null) // - .input(CTRL_ESS_CAPACITY, null) // - .output(CTRL_ESS_CAPACITY, null)); // + .next(new TestCase("EMS restart") // + .input("ess0", CAPACITY, null) // + .input(CTRL_ESS_CAPACITY, null) // + .output(CTRL_ESS_CAPACITY, null)) // - // New Ess.Capacity (Ctrl is taking the last one from timedata) - test.next(new TestCase() // - .input(ESS_CAPACITY, 10_000) // - .input(CTRL_ESS_CAPACITY, null) // - .output(CTRL_ESS_CAPACITY, 8_000)); // + .next(new TestCase("New Ess.Capacity (Ctrl is taking the last one from timedata)") // + .input("ess0", CAPACITY, 10_000) // + .input(CTRL_ESS_CAPACITY, null) // + .output(CTRL_ESS_CAPACITY, 8_000)) // - test.next(new TestCase() // - .output(STATE_MACHINE, StateMachine.State.IDLE)) // - ; + .next(new TestCase() // + .output(STATE_MACHINE, State.IDLE)) // + + .deactivate(); } @Test public void testAboveLimit() throws Exception { final var clock = new TimeLeapClock(Instant.parse("2022-01-01T08:00:00.00Z"), ZoneOffset.UTC); - final var componentManager = new DummyComponentManager(clock); - new ControllerTest(new ControllerEssFixStateOfChargeImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("componentManager", componentManager) // + .addReference("componentManager", new DummyComponentManager(clock)) // .addReference("sum", new DummySum()) // .addReference("timedata", new DummyTimedata("timedata0")) // .addReference("ess", ESS) // .activate(FixStateOfChargeConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setRunning(true) // .setTargetSoc(30) // .setSpecifyTargetTime(false) // @@ -226,44 +212,42 @@ public void testAboveLimit() throws Exception { .setSelfTermination(false) // .setTerminationBuffer(720) // .setConditionalTermination(false) // - .setEndCondition(EndCondition.CAPACITY_CHANGED) // + .setEndCondition(CAPACITY_CHANGED) // .build()) .next(new TestCase() // - .input(ESS_SOC, 50) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(STATE_MACHINE, StateMachine.State.IDLE)) // + .input("ess0", SOC, 50) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output(STATE_MACHINE, State.IDLE)) // .next(new TestCase() // - .input(ESS_SOC, 50) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(STATE_MACHINE, StateMachine.State.IDLE)) // + .input("ess0", SOC, 50) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output(STATE_MACHINE, State.IDLE)) // .next(new TestCase() // - .input(ESS_SOC, 50) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(STATE_MACHINE, StateMachine.State.NOT_STARTED)) // + .input("ess0", SOC, 50) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output(STATE_MACHINE, State.NOT_STARTED)) // .next(new TestCase() // - .input(ESS_SOC, 50) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(STATE_MACHINE, StateMachine.State.ABOVE_TARGET_SOC) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 500) // + .input("ess0", SOC, 50) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output(STATE_MACHINE, State.ABOVE_TARGET_SOC) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 500) // .output(DEBUG_SET_ACTIVE_POWER_RAW, 500) // - .output(DEBUG_SET_ACTIVE_POWER, 500) // Would increase till 10_000 - ); + .output(DEBUG_SET_ACTIVE_POWER, 500)) // Would increase till 10_000 + .deactivate(); } @Test public void testBelowLimit() throws Exception { final var clock = new TimeLeapClock(Instant.parse("2022-01-01T08:00:00.00Z"), ZoneOffset.UTC); - final var componentManager = new DummyComponentManager(clock); - new ControllerTest(new ControllerEssFixStateOfChargeImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("componentManager", componentManager) // + .addReference("componentManager", new DummyComponentManager(clock)) // .addReference("sum", new DummySum()) // .addReference("timedata", new DummyTimedata("timedata0")) // .addReference("ess", ESS) // .activate(FixStateOfChargeConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setRunning(true) // .setTargetSoc(30) // .setSpecifyTargetTime(false) // @@ -271,44 +255,42 @@ public void testBelowLimit() throws Exception { .setSelfTermination(false) // .setTerminationBuffer(720) // .setConditionalTermination(false) // - .setEndCondition(EndCondition.CAPACITY_CHANGED) // + .setEndCondition(CAPACITY_CHANGED) // .build()) .next(new TestCase() // - .input(ESS_SOC, 10) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(STATE_MACHINE, StateMachine.State.IDLE)) // + .input("ess0", SOC, 10) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output(STATE_MACHINE, State.IDLE)) // .next(new TestCase() // - .input(ESS_SOC, 10) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(STATE_MACHINE, StateMachine.State.IDLE)) // + .input("ess0", SOC, 10) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output(STATE_MACHINE, State.IDLE)) // .next(new TestCase() // - .input(ESS_SOC, 10) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(STATE_MACHINE, StateMachine.State.NOT_STARTED)) // + .input("ess0", SOC, 10) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output(STATE_MACHINE, State.NOT_STARTED)) // .next(new TestCase() // - .input(ESS_SOC, 10) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(STATE_MACHINE, StateMachine.State.BELOW_TARGET_SOC) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -500) // + .input("ess0", SOC, 10) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output(STATE_MACHINE, State.BELOW_TARGET_SOC) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -500) // .output(DEBUG_SET_ACTIVE_POWER_RAW, -500) // - .output(DEBUG_SET_ACTIVE_POWER, -500) // Would increase till 10_000 - ); + .output(DEBUG_SET_ACTIVE_POWER, -500)) // Would increase till 10_000 + .deactivate(); } @Test public void testAtLimit() throws Exception { final var clock = new TimeLeapClock(Instant.parse("2022-10-27T08:00:00.00Z"), ZoneOffset.UTC); - final var componentManager = new DummyComponentManager(clock); - new ControllerTest(new ControllerEssFixStateOfChargeImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("componentManager", componentManager) // + .addReference("componentManager", new DummyComponentManager(clock)) // .addReference("sum", new DummySum()) // .addReference("timedata", new DummyTimedata("timedata0")) // .addReference("ess", ESS) // .activate(FixStateOfChargeConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setRunning(true) // .setTargetSoc(30) // .setSpecifyTargetTime(false) // @@ -316,85 +298,85 @@ public void testAtLimit() throws Exception { .setSelfTermination(false) // .setTerminationBuffer(720) // .setConditionalTermination(false) // - .setEndCondition(EndCondition.CAPACITY_CHANGED) // + .setEndCondition(CAPACITY_CHANGED) // .build()) .next(new TestCase() // - .input(ESS_SOC, 10) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(STATE_MACHINE, StateMachine.State.IDLE)) // + .input("ess0", SOC, 10) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output(STATE_MACHINE, State.IDLE)) // .next(new TestCase() // - .input(ESS_SOC, 10) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(STATE_MACHINE, StateMachine.State.IDLE)) // + .input("ess0", SOC, 10) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output(STATE_MACHINE, State.IDLE)) // .next(new TestCase() // - .input(ESS_SOC, 10) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(STATE_MACHINE, StateMachine.State.NOT_STARTED)) // + .input("ess0", SOC, 10) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output(STATE_MACHINE, State.NOT_STARTED)) // .next(new TestCase() // - .input(ESS_SOC, 10) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(STATE_MACHINE, StateMachine.State.BELOW_TARGET_SOC) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -500) // + .input("ess0", SOC, 10) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output(STATE_MACHINE, State.BELOW_TARGET_SOC) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -500) // .output(DEBUG_SET_ACTIVE_POWER_RAW, -500) // .output(DEBUG_SET_ACTIVE_POWER, -500)) // .next(new TestCase() // - .input(ESS_SOC, 10) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -1000)) // + .input("ess0", SOC, 10) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -1000)) // .next(new TestCase() // - .input(ESS_SOC, 10) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -1500)) // + .input("ess0", SOC, 10) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -1500)) // .next(new TestCase() // - .input(ESS_SOC, 10) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -2000)) // + .input("ess0", SOC, 10) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -2000)) // .next(new TestCase() // - .input(ESS_SOC, 10) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -2500)) // + .input("ess0", SOC, 10) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -2500)) // .next(new TestCase() // - .input(ESS_SOC, 10) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -3000)) // + .input("ess0", SOC, 10) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -3000)) // .next(new TestCase() // - .input(ESS_SOC, 10) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -3500)) // + .input("ess0", SOC, 10) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -3500)) // .next(new TestCase() // - .input(ESS_SOC, 10) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -4000)) // + .input("ess0", SOC, 10) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -4000)) // .next(new TestCase()) // .next(new TestCase() // - .input(ESS_SOC, 10) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -5000)) // + .input("ess0", SOC, 10) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -5000)) // .next(new TestCase()) // .next(new TestCase() // - .input(ESS_SOC, 10) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -6000)) // + .input("ess0", SOC, 10) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -6000)) // .next(new TestCase()) // .next(new TestCase() // - .input(ESS_SOC, 10) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -7000)) // + .input("ess0", SOC, 10) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -7000)) // .next(new TestCase()) // .next(new TestCase() // - .input(ESS_SOC, 10) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -8000)) // + .input("ess0", SOC, 10) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -8000)) // .next(new TestCase()) // .next(new TestCase() // - .input(ESS_SOC, 10) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -9000)) // + .input("ess0", SOC, 10) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -9000)) // .next(new TestCase()) // .next(new TestCase() // - .input(ESS_SOC, 10) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -10000)) // + .input("ess0", SOC, 10) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -10000)) // .next(new TestCase() // - .input(ESS_SOC, 30) // - .input(ESS_MAX_APPARENT_POWER, 10_000)) // + .input("ess0", SOC, 30) // + .input("ess0", MAX_APPARENT_POWER, 10_000)) // .next(new TestCase() // - .input(ESS_SOC, 30) // - .output(STATE_MACHINE, StateMachine.State.AT_TARGET_SOC) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -9000)) // + .input("ess0", SOC, 30) // + .output(STATE_MACHINE, State.AT_TARGET_SOC) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -9000)) // .next(new TestCase() // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -8000)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -8000)) // .next(new TestCase()) // .next(new TestCase()) // .next(new TestCase()) // @@ -402,26 +384,24 @@ public void testAtLimit() throws Exception { .next(new TestCase()) // .next(new TestCase()) // .next(new TestCase() // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -1000)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -1000)) // .next(new TestCase() // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 0)) // - ; + .output("ess0", SET_ACTIVE_POWER_EQUALS, 0)) // + .deactivate(); } @Test public void testAtLimitDeadBand() throws Exception { final var clock = new TimeLeapClock(Instant.parse("2022-10-27T08:00:00.00Z"), ZoneOffset.UTC); - final var componentManager = new DummyComponentManager(clock); - new ControllerTest(new ControllerEssFixStateOfChargeImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("componentManager", componentManager) // + .addReference("componentManager", new DummyComponentManager(clock)) // .addReference("sum", new DummySum()) // .addReference("timedata", new DummyTimedata("timedata0")) // .addReference("ess", ESS) // .activate(FixStateOfChargeConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setRunning(true) // .setTargetSoc(30) // .setSpecifyTargetTime(false) // @@ -429,78 +409,76 @@ public void testAtLimitDeadBand() throws Exception { .setSelfTermination(false) // .setTerminationBuffer(720) // .setConditionalTermination(false) // - .setEndCondition(EndCondition.CAPACITY_CHANGED) // + .setEndCondition(CAPACITY_CHANGED) // .build()) .next(new TestCase() // - .input(ESS_SOC, 30) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .input(ESS_CAPACITY, 10_000) // - .output(STATE_MACHINE, StateMachine.State.IDLE)) // + .input("ess0", SOC, 30) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .input("ess0", CAPACITY, 10_000) // + .output(STATE_MACHINE, State.IDLE)) // .next(new TestCase() // - .input(ESS_SOC, 30) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(STATE_MACHINE, StateMachine.State.IDLE)) // + .input("ess0", SOC, 30) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output(STATE_MACHINE, State.IDLE)) // .next(new TestCase() // - .input(ESS_SOC, 30) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(STATE_MACHINE, StateMachine.State.NOT_STARTED)) // + .input("ess0", SOC, 30) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output(STATE_MACHINE, State.NOT_STARTED)) // .next(new TestCase() // - .input(ESS_SOC, 30) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(STATE_MACHINE, StateMachine.State.AT_TARGET_SOC) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 0) // + .input("ess0", SOC, 30) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output(STATE_MACHINE, State.AT_TARGET_SOC) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 0) // .output(DEBUG_SET_ACTIVE_POWER_RAW, 0) // .output(DEBUG_SET_ACTIVE_POWER, 0)) // .next(new TestCase() // - .input(ESS_SOC, 30) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 0)) // + .input("ess0", SOC, 30) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 0)) // .next(new TestCase() // - .input(ESS_SOC, 31) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 0)) // + .input("ess0", SOC, 31) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 0)) // .next(new TestCase() // - .input(ESS_SOC, 29) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 0)) // + .input("ess0", SOC, 29) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 0)) // .next(new TestCase() // - .input(ESS_SOC, 28)) // + .input("ess0", SOC, 28)) // .next(new TestCase() // - .input(ESS_SOC, 28) // - .output(STATE_MACHINE, StateMachine.State.WITHIN_LOWER_TARGET_SOC_BOUNDARIES) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -500)) // + .input("ess0", SOC, 28) // + .output(STATE_MACHINE, State.WITHIN_LOWER_TARGET_SOC_BOUNDARIES) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -500)) // .next(new TestCase() // - .input(ESS_SOC, 28) // - .output(STATE_MACHINE, StateMachine.State.WITHIN_LOWER_TARGET_SOC_BOUNDARIES) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -1000)) // + .input("ess0", SOC, 28) // + .output(STATE_MACHINE, State.WITHIN_LOWER_TARGET_SOC_BOUNDARIES) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -1000)) // .next(new TestCase() // - .input(ESS_SOC, 28) // - .output(STATE_MACHINE, StateMachine.State.WITHIN_LOWER_TARGET_SOC_BOUNDARIES) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -1500)) // + .input("ess0", SOC, 28) // + .output(STATE_MACHINE, State.WITHIN_LOWER_TARGET_SOC_BOUNDARIES) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -1500)) // .next(new TestCase() // - .input(ESS_SOC, 28) // - .output(STATE_MACHINE, StateMachine.State.WITHIN_LOWER_TARGET_SOC_BOUNDARIES) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -1 * Math.round(// - Math.min(10_000/* maxApparentPower */ * AbstractFixStateOfCharge.DEFAULT_POWER_FACTOR, + .input("ess0", SOC, 28) // + .output(STATE_MACHINE, State.WITHIN_LOWER_TARGET_SOC_BOUNDARIES) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -1 * round(// + min(10_000/* maxApparentPower */ * DEFAULT_POWER_FACTOR, 10_000 /* capacity */ * (1f / 6f))) // 1467 - ))// - ; + )) // + .deactivate(); } @Test public void testBoundaries() throws Exception { final var clock = new TimeLeapClock(Instant.parse("2022-10-27T08:00:00.00Z"), ZoneOffset.UTC); - final var componentManager = new DummyComponentManager(clock); - /* * Below target SoC */ new ControllerTest(new ControllerEssFixStateOfChargeImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("componentManager", componentManager) // + .addReference("componentManager", new DummyComponentManager(clock)) // .addReference("sum", new DummySum()) // .addReference("timedata", new DummyTimedata("timedata0")) // .addReference("ess", ESS) // .activate(FixStateOfChargeConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setRunning(true) // .setTargetSoc(30) // .setSpecifyTargetTime(false) // @@ -508,67 +486,67 @@ public void testBoundaries() throws Exception { .setSelfTermination(false) // .setTerminationBuffer(720) // .setConditionalTermination(false) // - .setEndCondition(EndCondition.CAPACITY_CHANGED) // + .setEndCondition(CAPACITY_CHANGED) // .build()) .next(new TestCase() // - .input(ESS_SOC, 20) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(STATE_MACHINE, StateMachine.State.IDLE)) // + .input("ess0", SOC, 20) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output(STATE_MACHINE, State.IDLE)) // .next(new TestCase() // - .input(ESS_SOC, 20) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(STATE_MACHINE, StateMachine.State.IDLE)) // + .input("ess0", SOC, 20) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output(STATE_MACHINE, State.IDLE)) // .next(new TestCase() // - .input(ESS_SOC, 20) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(STATE_MACHINE, StateMachine.State.NOT_STARTED)) // + .input("ess0", SOC, 20) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output(STATE_MACHINE, State.NOT_STARTED)) // .next(new TestCase() // - .input(ESS_SOC, 20) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .input(ESS_CAPACITY, 10_000) // - .output(STATE_MACHINE, StateMachine.State.BELOW_TARGET_SOC) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -500) // + .input("ess0", SOC, 20) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .input("ess0", CAPACITY, 10_000) // + .output(STATE_MACHINE, State.BELOW_TARGET_SOC) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -500) // .output(DEBUG_SET_ACTIVE_POWER_RAW, -500) // .output(DEBUG_SET_ACTIVE_POWER, -500)) // .next(new TestCase() // - .input(ESS_SOC, 22) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -1000)) // + .input("ess0", SOC, 22) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -1000)) // // Skip Ramp .next(new TestCase(), 17) // .next(new TestCase() // - .input(ESS_SOC, 27) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -10000)) // + .input("ess0", SOC, 27) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -10000)) // .next(new TestCase() // - .input(ESS_SOC, 28)) // + .input("ess0", SOC, 28)) // .next(new TestCase() // - .input(ESS_SOC, 28) // - .output(STATE_MACHINE, StateMachine.State.WITHIN_LOWER_TARGET_SOC_BOUNDARIES) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -9500)) // + .input("ess0", SOC, 28) // + .output(STATE_MACHINE, State.WITHIN_LOWER_TARGET_SOC_BOUNDARIES) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -9500)) // .next(new TestCase() // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -9000)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -9000)) // // Skip ramp .next(new TestCase(), 13) // .next(new TestCase() // - .input(ESS_SOC, 29) // - .output(STATE_MACHINE, StateMachine.State.WITHIN_LOWER_TARGET_SOC_BOUNDARIES) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -2000)) // + .input("ess0", SOC, 29) // + .output(STATE_MACHINE, State.WITHIN_LOWER_TARGET_SOC_BOUNDARIES) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -2000)) // .next(new TestCase() // - .input(ESS_SOC, 29) // - .output(STATE_MACHINE, StateMachine.State.WITHIN_LOWER_TARGET_SOC_BOUNDARIES) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -1 * Math.round(// - Math.min(10_000/* maxApparentPower */ * AbstractFixStateOfCharge.DEFAULT_POWER_FACTOR, + .input("ess0", SOC, 29) // + .output(STATE_MACHINE, State.WITHIN_LOWER_TARGET_SOC_BOUNDARIES) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -1 * round(// + min(10_000/* maxApparentPower */ * DEFAULT_POWER_FACTOR, 10_000 /* capacity */ * (1f / 6f))) // ))// 1667 .next(new TestCase() // - .input(ESS_SOC, 30)) // + .input("ess0", SOC, 30)) // .next(new TestCase() // - .input(ESS_SOC, 30) // - .output(STATE_MACHINE, StateMachine.State.AT_TARGET_SOC) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -667)) // + .input("ess0", SOC, 30) // + .output(STATE_MACHINE, State.AT_TARGET_SOC) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -667)) // .next(new TestCase() // - .input(ESS_SOC, 30) // - .output(STATE_MACHINE, StateMachine.State.AT_TARGET_SOC) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 0)) // + .input("ess0", SOC, 30) // + .output(STATE_MACHINE, State.AT_TARGET_SOC) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 0)) // ; /* @@ -576,13 +554,13 @@ public void testBoundaries() throws Exception { */ new ControllerTest(new ControllerEssFixStateOfChargeImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("componentManager", componentManager) // + .addReference("componentManager", new DummyComponentManager(clock)) // .addReference("sum", new DummySum()) // .addReference("timedata", new DummyTimedata("timedata0")) // .addReference("ess", ESS) // .activate(FixStateOfChargeConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setRunning(true) // .setTargetSoc(30) // .setSpecifyTargetTime(false) // @@ -590,66 +568,66 @@ public void testBoundaries() throws Exception { .setSelfTermination(false) // .setTerminationBuffer(720) // .setConditionalTermination(false) // - .setEndCondition(EndCondition.CAPACITY_CHANGED) // + .setEndCondition(CAPACITY_CHANGED) // .build()) .next(new TestCase() // - .input(ESS_SOC, 40) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(STATE_MACHINE, StateMachine.State.IDLE)) // + .input("ess0", SOC, 40) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output(STATE_MACHINE, State.IDLE)) // .next(new TestCase() // - .input(ESS_SOC, 40) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(STATE_MACHINE, StateMachine.State.IDLE)) // + .input("ess0", SOC, 40) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output(STATE_MACHINE, State.IDLE)) // .next(new TestCase() // - .input(ESS_SOC, 40) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(STATE_MACHINE, StateMachine.State.NOT_STARTED)) // + .input("ess0", SOC, 40) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output(STATE_MACHINE, State.NOT_STARTED)) // .next(new TestCase() // - .input(ESS_SOC, 40) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(STATE_MACHINE, StateMachine.State.ABOVE_TARGET_SOC) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 500) // + .input("ess0", SOC, 40) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output(STATE_MACHINE, State.ABOVE_TARGET_SOC) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 500) // .output(DEBUG_SET_ACTIVE_POWER_RAW, 500) // .output(DEBUG_SET_ACTIVE_POWER, 500)) // .next(new TestCase() // - .input(ESS_SOC, 40) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 1000)) // + .input("ess0", SOC, 40) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 1000)) // // Skip ramp .next(new TestCase(), 18) // .next(new TestCase() // - .input(ESS_SOC, 33)) // + .input("ess0", SOC, 33)) // .next(new TestCase() // - .input(ESS_SOC, 32)) // + .input("ess0", SOC, 32)) // .next(new TestCase() // - .input(ESS_SOC, 32) // - .output(STATE_MACHINE, StateMachine.State.WITHIN_UPPER_TARGET_SOC_BOUNDARIES) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 9500)) // + .input("ess0", SOC, 32) // + .output(STATE_MACHINE, State.WITHIN_UPPER_TARGET_SOC_BOUNDARIES) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 9500)) // .next(new TestCase() // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 9000)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 9000)) // // Skip ramp .next(new TestCase(), 13) // .next(new TestCase() // - .input(ESS_SOC, 31) // - .output(STATE_MACHINE, StateMachine.State.WITHIN_UPPER_TARGET_SOC_BOUNDARIES) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 2000)) // + .input("ess0", SOC, 31) // + .output(STATE_MACHINE, State.WITHIN_UPPER_TARGET_SOC_BOUNDARIES) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 2000)) // .next(new TestCase() // - .input(ESS_SOC, 31) // - .output(STATE_MACHINE, StateMachine.State.WITHIN_UPPER_TARGET_SOC_BOUNDARIES) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, Math.round(// - Math.min(10_000/* maxApparentPower */ * AbstractFixStateOfCharge.DEFAULT_POWER_FACTOR, + .input("ess0", SOC, 31) // + .output(STATE_MACHINE, State.WITHIN_UPPER_TARGET_SOC_BOUNDARIES) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, round(// + min(10_000/* maxApparentPower */ * DEFAULT_POWER_FACTOR, 10_000 /* capacity */ * (1f / 6f))) // ))// 1667 .next(new TestCase() // - .input(ESS_SOC, 30)) // + .input("ess0", SOC, 30)) // .next(new TestCase() // - .input(ESS_SOC, 30) // - .output(STATE_MACHINE, StateMachine.State.AT_TARGET_SOC) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 667)) // + .input("ess0", SOC, 30) // + .output(STATE_MACHINE, State.AT_TARGET_SOC) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 667)) // .next(new TestCase() // - .input(ESS_SOC, 30) // - .output(STATE_MACHINE, StateMachine.State.AT_TARGET_SOC) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 0)) // - ; + .input("ess0", SOC, 30) // + .output(STATE_MACHINE, State.AT_TARGET_SOC) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 0)) // + .deactivate(); } @Test @@ -665,8 +643,8 @@ public void testLimitWithSpecifiedTimeBelowLimit() throws Exception { .addReference("timedata", new DummyTimedata("timedata0")) // .addReference("ess", ESS) // .activate(FixStateOfChargeConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setRunning(true) // .setTargetSoc(30) // .setSpecifyTargetTime(true) // @@ -674,35 +652,35 @@ public void testLimitWithSpecifiedTimeBelowLimit() throws Exception { .setSelfTermination(false) // .setTerminationBuffer(720) // .setConditionalTermination(false) // - .setEndCondition(EndCondition.CAPACITY_CHANGED) // + .setEndCondition(CAPACITY_CHANGED) // .build()) .next(new TestCase() // - .input(ESS_SOC, 10) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(STATE_MACHINE, StateMachine.State.IDLE)) // + .input("ess0", SOC, 10) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output(STATE_MACHINE, State.IDLE)) // .next(new TestCase() // - .input(ESS_SOC, 10) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(STATE_MACHINE, StateMachine.State.IDLE)) // + .input("ess0", SOC, 10) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output(STATE_MACHINE, State.IDLE)) // .next(new TestCase() // - .input(ESS_SOC, 10) // - .input(ESS_CAPACITY, 30_000) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(STATE_MACHINE, StateMachine.State.NOT_STARTED)) // + .input("ess0", SOC, 10) // + .input("ess0", CAPACITY, 30_000) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output(STATE_MACHINE, State.NOT_STARTED)) // // Start time = 2022-10-27T09:14:24+01:00, Current: 2022-10-27T09:00:00+01:00 .next(new TestCase() // - .input(ESS_SOC, 10) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .input(ESS_CAPACITY, 30_000) // - .output(STATE_MACHINE, StateMachine.State.NOT_STARTED) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, null) // + .input("ess0", SOC, 10) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .input("ess0", CAPACITY, 30_000) // + .output(STATE_MACHINE, State.NOT_STARTED) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, null) // .output(DEBUG_SET_ACTIVE_POWER_RAW, null) // .output(DEBUG_SET_ACTIVE_POWER, null)) // .next(new TestCase() // - .timeleap(clock, 15, ChronoUnit.MINUTES))// + .timeleap(clock, 15, MINUTES))// .next(new TestCase() // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -500)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -500)) // .next(new TestCase()) // .next(new TestCase()) // .next(new TestCase()) // @@ -712,33 +690,33 @@ public void testLimitWithSpecifiedTimeBelowLimit() throws Exception { .next(new TestCase()) // .next(new TestCase()) // .next(new TestCase() // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -5000)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -5000)) // .next(new TestCase() // - .input(ESS_SOC, 10) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .input(ESS_CAPACITY, 30_000) // - .output(STATE_MACHINE, StateMachine.State.BELOW_TARGET_SOC) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -5040) // + .input("ess0", SOC, 10) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .input("ess0", CAPACITY, 30_000) // + .output(STATE_MACHINE, State.BELOW_TARGET_SOC) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -5040) // .output(DEBUG_SET_ACTIVE_POWER_RAW, -5040) // .output(DEBUG_SET_ACTIVE_POWER, -5040)) // .next(new TestCase() // - .input(ESS_SOC, 30) // - .input(ESS_MAX_APPARENT_POWER, 10_000)) // + .input("ess0", SOC, 30) // + .input("ess0", MAX_APPARENT_POWER, 10_000)) // .next(new TestCase() // - .input(ESS_SOC, 30) // - .output(STATE_MACHINE, StateMachine.State.AT_TARGET_SOC) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -4040)) // + .input("ess0", SOC, 30) // + .output(STATE_MACHINE, State.AT_TARGET_SOC) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -4040)) // .next(new TestCase() // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -3040)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -3040)) // .next(new TestCase() // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -2040)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -2040)) // .next(new TestCase() // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -1040)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -1040)) // .next(new TestCase() // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -40)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -40)) // .next(new TestCase() // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 0)) // - ; + .output("ess0", SET_ACTIVE_POWER_EQUALS, 0)) // + .deactivate(); } @Test @@ -753,8 +731,8 @@ public void testLimitWithSpecifiedTimeAboveLimit() throws Exception { .addReference("timedata", new DummyTimedata("timedata0")) // .addReference("ess", ESS) // .activate(FixStateOfChargeConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setRunning(true) // .setTargetSoc(30) // .setSpecifyTargetTime(true) // @@ -763,85 +741,85 @@ public void testLimitWithSpecifiedTimeAboveLimit() throws Exception { .setSelfTermination(false) // .setTerminationBuffer(720) // .setConditionalTermination(false) // - .setEndCondition(EndCondition.CAPACITY_CHANGED) // + .setEndCondition(CAPACITY_CHANGED) // .build()) .next(new TestCase() // - .input(ESS_SOC, 80) // - .input(ESS_CAPACITY, 30_000) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(STATE_MACHINE, StateMachine.State.IDLE)) // + .input("ess0", SOC, 80) // + .input("ess0", CAPACITY, 30_000) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output(STATE_MACHINE, State.IDLE)) // .next(new TestCase() // - .input(ESS_SOC, 80) // - .input(ESS_CAPACITY, 30_000) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(STATE_MACHINE, StateMachine.State.IDLE)) // + .input("ess0", SOC, 80) // + .input("ess0", CAPACITY, 30_000) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output(STATE_MACHINE, State.IDLE)) // .next(new TestCase() // - .input(ESS_SOC, 80) // - .input(ESS_CAPACITY, 30_000) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(STATE_MACHINE, StateMachine.State.NOT_STARTED)) // + .input("ess0", SOC, 80) // + .input("ess0", CAPACITY, 30_000) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output(STATE_MACHINE, State.NOT_STARTED)) // // Start time = 2022-10-27T06:26:24, Current: 2022-10-26T23:00 .next(new TestCase() // - .input(ESS_SOC, 80) // - .input(ESS_CAPACITY, 30_000) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(STATE_MACHINE, StateMachine.State.NOT_STARTED) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, null) // + .input("ess0", SOC, 80) // + .input("ess0", CAPACITY, 30_000) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output(STATE_MACHINE, State.NOT_STARTED) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, null) // .output(DEBUG_SET_ACTIVE_POWER_RAW, null) // .output(DEBUG_SET_ACTIVE_POWER, null)) // .next(new TestCase() // - .timeleap(clock, 7, ChronoUnit.HOURS)) // + .timeleap(clock, 7, HOURS)) // .next(new TestCase() // - .timeleap(clock, 31, ChronoUnit.MINUTES)) // + .timeleap(clock, 31, MINUTES)) // .next(new TestCase() // - .input(ESS_SOC, 80) // - .input(ESS_CAPACITY, 30_000) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .output(STATE_MACHINE, StateMachine.State.ABOVE_TARGET_SOC) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 500) // + .input("ess0", SOC, 80) // + .input("ess0", CAPACITY, 30_000) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .output(STATE_MACHINE, State.ABOVE_TARGET_SOC) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 500) // .output(DEBUG_SET_ACTIVE_POWER_RAW, 500) // .output(DEBUG_SET_ACTIVE_POWER, 500)) // .next(new TestCase() // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 1000)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 1000)) // .next(new TestCase()) // .next(new TestCase() // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 2000)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 2000)) // .next(new TestCase()) // .next(new TestCase() // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 3000)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 3000)) // .next(new TestCase()) // .next(new TestCase() // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 4000)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 4000)) // .next(new TestCase()) // .next(new TestCase() // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 5000)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 5000)) // .next(new TestCase()) // .next(new TestCase() // - .input(ESS_SOC, 80) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .input(ESS_CAPACITY, 30_000) // - .output(STATE_MACHINE, StateMachine.State.ABOVE_TARGET_SOC) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 5128) // + .input("ess0", SOC, 80) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .input("ess0", CAPACITY, 30_000) // + .output(STATE_MACHINE, State.ABOVE_TARGET_SOC) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 5128) // .output(DEBUG_SET_ACTIVE_POWER_RAW, 5128) // .output(DEBUG_SET_ACTIVE_POWER, 5128)) // .next(new TestCase() // - .input(ESS_SOC, 30) // - .input(ESS_MAX_APPARENT_POWER, 10_000)) // + .input("ess0", SOC, 30) // + .input("ess0", MAX_APPARENT_POWER, 10_000)) // .next(new TestCase() // - .input(ESS_SOC, 30) // - .output(STATE_MACHINE, StateMachine.State.AT_TARGET_SOC) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 4128)) // + .input("ess0", SOC, 30) // + .output(STATE_MACHINE, State.AT_TARGET_SOC) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 4128)) // .next(new TestCase() // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 3128)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 3128)) // .next(new TestCase() // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 2128)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 2128)) // .next(new TestCase() // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 1128)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 1128)) // .next(new TestCase() // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 128)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 128)) // .next(new TestCase() // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 0)) // - ; + .output("ess0", SET_ACTIVE_POWER_EQUALS, 0)) // + .deactivate(); } } diff --git a/io.openems.edge.controller.ess.gridoptimizedcharge/test/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedChargeImplTest.java b/io.openems.edge.controller.ess.gridoptimizedcharge/test/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedChargeImplTest.java index 009f2fb33f2..7ac9440a6ba 100644 --- a/io.openems.edge.controller.ess.gridoptimizedcharge/test/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedChargeImplTest.java +++ b/io.openems.edge.controller.ess.gridoptimizedcharge/test/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedChargeImplTest.java @@ -1,5 +1,20 @@ package io.openems.edge.controller.ess.gridoptimizedcharge; +import static io.openems.edge.common.sum.Sum.ChannelId.PRODUCTION_DC_ACTUAL_POWER; +import static io.openems.edge.controller.ess.gridoptimizedcharge.ControllerEssGridOptimizedCharge.ChannelId.DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT; +import static io.openems.edge.controller.ess.gridoptimizedcharge.ControllerEssGridOptimizedCharge.ChannelId.DELAY_CHARGE_STATE; +import static io.openems.edge.controller.ess.gridoptimizedcharge.ControllerEssGridOptimizedCharge.ChannelId.PREDICTED_TARGET_MINUTE; +import static io.openems.edge.controller.ess.gridoptimizedcharge.ControllerEssGridOptimizedCharge.ChannelId.PREDICTED_TARGET_MINUTE_ADJUSTED; +import static io.openems.edge.controller.ess.gridoptimizedcharge.ControllerEssGridOptimizedCharge.ChannelId.RAW_DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT; +import static io.openems.edge.controller.ess.gridoptimizedcharge.ControllerEssGridOptimizedCharge.ChannelId.RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT; +import static io.openems.edge.controller.ess.gridoptimizedcharge.ControllerEssGridOptimizedCharge.ChannelId.SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT; +import static io.openems.edge.controller.ess.gridoptimizedcharge.ControllerEssGridOptimizedCharge.ChannelId.SELL_TO_GRID_LIMIT_STATE; +import static io.openems.edge.controller.ess.gridoptimizedcharge.ControllerEssGridOptimizedCharge.ChannelId.START_EPOCH_SECONDS; +import static io.openems.edge.controller.ess.gridoptimizedcharge.ControllerEssGridOptimizedCharge.ChannelId.TARGET_MINUTE; +import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_LESS_OR_EQUALS; +import static io.openems.edge.ess.api.SymmetricEss.ChannelId.CAPACITY; +import static io.openems.edge.ess.api.SymmetricEss.ChannelId.MAX_APPARENT_POWER; +import static io.openems.edge.ess.api.SymmetricEss.ChannelId.SOC; import static io.openems.edge.predictor.api.prediction.Prediction.EMPTY_PREDICTION; import static java.time.temporal.ChronoUnit.DAYS; import static org.junit.Assert.assertEquals; @@ -34,8 +49,10 @@ import io.openems.edge.common.test.Plot.AxisFormat; import io.openems.edge.common.test.Plot.Data; import io.openems.edge.controller.test.ControllerTest; +import io.openems.edge.ess.api.SymmetricEss; import io.openems.edge.ess.test.DummyHybridEss; import io.openems.edge.ess.test.DummyManagedSymmetricEss; +import io.openems.edge.meter.api.ElectricityMeter; import io.openems.edge.meter.test.DummyElectricityMeter; import io.openems.edge.predictor.api.prediction.Prediction; import io.openems.edge.predictor.api.test.DummyPredictor; @@ -43,50 +60,13 @@ public class ControllerEssGridOptimizedChargeImplTest { - // Ids - private static final String CTRL_ID = "ctrlGridOptimizedCharge0"; - private static final String PREDICTOR_ID = "predictor0"; - private static final String ESS_ID = "ess0"; - private static final String METER_ID = "meter0"; - // Components - private static final DummyManagedSymmetricEss ESS = new DummyManagedSymmetricEss(ESS_ID); - private static final DummyElectricityMeter METER = new DummyElectricityMeter(METER_ID); - private static final DummyHybridEss HYBRID_ESS = new DummyHybridEss(ESS_ID); - private static final DummyManagedSymmetricEss ESS_WITH_NONE_APPARENT_POWER = new DummyManagedSymmetricEss(ESS_ID) // + private static final DummyManagedSymmetricEss ESS = new DummyManagedSymmetricEss("ess0"); + private static final DummyElectricityMeter METER = new DummyElectricityMeter("meter0"); + private static final DummyHybridEss HYBRID_ESS = new DummyHybridEss("ess0"); + private static final DummyManagedSymmetricEss ESS_WITH_NONE_APPARENT_POWER = new DummyManagedSymmetricEss("ess0") // .withMaxApparentPower(0); - // Ess channels - private static final ChannelAddress ESS_CAPACITY = new ChannelAddress(ESS_ID, "Capacity"); - private static final ChannelAddress ESS_SOC = new ChannelAddress(ESS_ID, "Soc"); - private static final ChannelAddress ESS_MAX_APPARENT_POWER = new ChannelAddress(ESS_ID, "MaxApparentPower"); - private static final ChannelAddress ESS_ACTIVE_POWER = new ChannelAddress(ESS_ID, "ActivePower"); - private static final ChannelAddress ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS = new ChannelAddress(ESS_ID, - "SetActivePowerLessOrEquals"); - - // Meter channels - private static final ChannelAddress METER_ACTIVE_POWER = new ChannelAddress(METER_ID, "ActivePower"); - - // Controller channels - private static final ChannelAddress PREDICTED_TARGET_MINUTE = new ChannelAddress(CTRL_ID, "PredictedTargetMinute"); - private static final ChannelAddress PREDICTED_TARGET_MINUTE_ADJUSTED = new ChannelAddress(CTRL_ID, - "PredictedTargetMinuteAdjusted"); - private static final ChannelAddress TARGET_MINUTE = new ChannelAddress(CTRL_ID, "TargetMinute"); - private static final ChannelAddress DELAY_CHARGE_STATE = new ChannelAddress(CTRL_ID, "DelayChargeState"); - private static final ChannelAddress SELL_TO_GRID_LIMIT_STATE = new ChannelAddress(CTRL_ID, "SellToGridLimitState"); - private static final ChannelAddress DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT = new ChannelAddress(CTRL_ID, - "DelayChargeMaximumChargeLimit"); - private static final ChannelAddress RAW_DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT = new ChannelAddress(CTRL_ID, - "RawDelayChargeMaximumChargeLimit"); - private static final ChannelAddress SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT = new ChannelAddress(CTRL_ID, - "SellToGridLimitMinimumChargeLimit"); - private static final ChannelAddress RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT = new ChannelAddress(CTRL_ID, - "RawSellToGridLimitChargeLimit"); - private static final ChannelAddress START_EPOCH_SECONDS = new ChannelAddress(CTRL_ID, "StartEpochSeconds"); - - // Sum channels - private static final ChannelAddress SUM_PRODUCTION_DC_ACTUAL_POWER = new ChannelAddress("_sum", - "ProductionDcActualPower"); private static final ChannelAddress SUM_PRODUCTION_ACTIVE_POWER = new ChannelAddress("_sum", "ProductionActivePower"); private static final ChannelAddress SUM_CONSUMPTION_ACTIVE_POWER = new ChannelAddress("_sum", @@ -157,11 +137,11 @@ public void automatic_default_predictions_at_midnight_test() throws Exception { final var sum = new DummySum(); final var predictorManager = new DummyPredictorManager( // Production - new DummyPredictor(PREDICTOR_ID, cm, + new DummyPredictor("predictor0", cm, Prediction.from(sum, SUM_PRODUCTION_ACTIVE_POWER, now, DEFAULT_PRODUCTION_PREDICTION), SUM_PRODUCTION_ACTIVE_POWER), // Consumption - new DummyPredictor(PREDICTOR_ID, cm, + new DummyPredictor("predictor0", cm, Prediction.from(sum, SUM_CONSUMPTION_ACTIVE_POWER, now, DEFAULT_CONSUMPTION_PREDICTION), SUM_CONSUMPTION_ACTIVE_POWER)); @@ -173,10 +153,10 @@ public void automatic_default_predictions_at_midnight_test() throws Exception { .addReference("meter", METER) // .addReference("sum", new DummySum()) // .activate(MyConfig.create() // - .setEssId(ESS_ID) // - .setId(CTRL_ID) // + .setEssId("ess0") // + .setId("ctrlGridOptimizedCharge0") // .setMaximumSellToGridPower(7_000) // - .setMeterId(METER_ID) // + .setMeterId("meter0") // .setDelayChargeRiskLevel(DelayChargeRiskLevel.MEDIUM) // .setMode(Mode.AUTOMATIC) // .setSellToGridLimitEnabled(true) // @@ -185,18 +165,19 @@ public void automatic_default_predictions_at_midnight_test() throws Exception { .build()) // .next(new TestCase() // .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // - .input(METER_ACTIVE_POWER, 0) // - .input(ESS_ACTIVE_POWER, 0) // - .input(ESS_CAPACITY, 10_000) // - .input(ESS_SOC, 20) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 0) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 0) // + .input("ess0", CAPACITY, 10_000) // + .input("ess0", SOC, 20) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // .input(START_EPOCH_SECONDS, 1630566000) // .output(PREDICTED_TARGET_MINUTE, /* QuarterHour */ 68 * 15) // .output(PREDICTED_TARGET_MINUTE_ADJUSTED, /* QuarterHour */ 68 * 15 - 120) // .output(DELAY_CHARGE_STATE, DelayChargeState.AVOID_LOW_CHARGING) // .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, -6650) // .output(RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT, 6650) // - .output(DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, 0)); // Avoid low charge power + .output(DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, 0)) // Avoid low charge power + .deactivate(); } @Test @@ -207,11 +188,11 @@ public void automatic_default_predictions_at_midday_test() throws Exception { final var sum = new DummySum(); final var predictorManager = new DummyPredictorManager( // Production - new DummyPredictor(PREDICTOR_ID, cm, + new DummyPredictor("predictor0", cm, Prediction.from(sum, SUM_PRODUCTION_ACTIVE_POWER, midnight, DEFAULT_PRODUCTION_PREDICTION), SUM_PRODUCTION_ACTIVE_POWER), // Consumption - new DummyPredictor(PREDICTOR_ID, cm, + new DummyPredictor("predictor0", cm, Prediction.from(sum, SUM_CONSUMPTION_ACTIVE_POWER, midnight, DEFAULT_CONSUMPTION_PREDICTION), SUM_CONSUMPTION_ACTIVE_POWER)); @@ -223,10 +204,10 @@ public void automatic_default_predictions_at_midday_test() throws Exception { .addReference("meter", METER) // .addReference("sum", new DummySum()) // .activate(MyConfig.create() // - .setEssId(ESS_ID) // - .setId(CTRL_ID) // + .setEssId("ess0") // + .setId("ctrlGridOptimizedCharge0") // .setMaximumSellToGridPower(7_000) // - .setMeterId(METER_ID) // + .setMeterId("meter0") // .setDelayChargeRiskLevel(DelayChargeRiskLevel.MEDIUM) // .setMode(Mode.AUTOMATIC) // .setSellToGridLimitEnabled(true) // @@ -235,11 +216,11 @@ public void automatic_default_predictions_at_midday_test() throws Exception { .build()) // .next(new TestCase() // .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // - .input(METER_ACTIVE_POWER, 0) // - .input(ESS_ACTIVE_POWER, 0) // - .input(ESS_CAPACITY, 10_000) // - .input(ESS_SOC, 20) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 0) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 0) // + .input("ess0", CAPACITY, 10_000) // + .input("ess0", SOC, 20) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // .input(START_EPOCH_SECONDS, 1630566000) // .output(PREDICTED_TARGET_MINUTE, /* QuarterHour */ 68 * 15) // .output(PREDICTED_TARGET_MINUTE_ADJUSTED, /* QuarterHour */ 68 * 15 - 120) // @@ -248,7 +229,8 @@ public void automatic_default_predictions_at_midday_test() throws Exception { .output(RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT, 6650) // // If Energy calculation would be applied on medium risk level - Predicted // available Energy is not enough to reach 100% - .output(DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, 2700)); + .output(DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, 2700)) // + .deactivate(); } @Test @@ -264,11 +246,11 @@ public void automatic_default_predictions_at_midday_averaged_test() throws Excep final var sum = new DummySum(); final var predictorManager = new DummyPredictorManager( // Production - new DummyPredictor(PREDICTOR_ID, cm, + new DummyPredictor("predictor0", cm, Prediction.from(sum, SUM_PRODUCTION_ACTIVE_POWER, midnight, DEFAULT_PRODUCTION_PREDICTION), SUM_PRODUCTION_ACTIVE_POWER), // Consumption - new DummyPredictor(PREDICTOR_ID, cm, + new DummyPredictor("predictor0", cm, Prediction.from(sum, SUM_CONSUMPTION_ACTIVE_POWER, midnight, DEFAULT_CONSUMPTION_PREDICTION), SUM_CONSUMPTION_ACTIVE_POWER)); @@ -280,10 +262,10 @@ public void automatic_default_predictions_at_midday_averaged_test() throws Excep .addReference("meter", METER) // .addReference("sum", new DummySum()) // .activate(MyConfig.create() // - .setEssId(ESS_ID) // - .setId(CTRL_ID) // + .setEssId("ess0") // + .setId("ctrlGridOptimizedCharge0") // .setMaximumSellToGridPower(7_000) // - .setMeterId(METER_ID) // + .setMeterId("meter0") // .setDelayChargeRiskLevel(DelayChargeRiskLevel.MEDIUM) // .setMode(Mode.AUTOMATIC) // .setSellToGridLimitEnabled(true) // @@ -293,11 +275,11 @@ public void automatic_default_predictions_at_midday_averaged_test() throws Excep .next(new TestCase() // .onAfterProcessImage(sleep) // .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // - .input(METER_ACTIVE_POWER, 0) // - .input(ESS_ACTIVE_POWER, 0) // - .input(ESS_CAPACITY, 10_000) // - .input(ESS_SOC, 20) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 0) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 0) // + .input("ess0", CAPACITY, 10_000) // + .input("ess0", SOC, 20) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // .input(START_EPOCH_SECONDS, 1630566000) // .output(PREDICTED_TARGET_MINUTE, /* QuarterHour */ 68 * 15) // .output(PREDICTED_TARGET_MINUTE_ADJUSTED, /* QuarterHour */ 68 * 15 - 120) // @@ -309,7 +291,7 @@ public void automatic_default_predictions_at_midday_averaged_test() throws Excep .next(new TestCase() // .onAfterProcessImage(sleep) // .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // - .input(ESS_SOC, 21) // + .input("ess0", SOC, 21) // .input(START_EPOCH_SECONDS, 1630566000) // .output(DELAY_CHARGE_STATE, DelayChargeState.ACTIVE_LIMIT) // .output(DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, 2683) // @@ -329,6 +311,7 @@ public void automatic_default_predictions_at_midday_averaged_test() throws Excep .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .output(DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, 2673) // .output(RAW_DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, 2666)) // + .deactivate(); ; } @@ -340,11 +323,11 @@ public void automatic_default_predictions_at_evening_test() throws Exception { final var sum = new DummySum(); final var predictorManager = new DummyPredictorManager( // Production - new DummyPredictor(PREDICTOR_ID, cm, + new DummyPredictor("predictor0", cm, Prediction.from(sum, SUM_PRODUCTION_ACTIVE_POWER, now, DEFAULT_PRODUCTION_PREDICTION), SUM_PRODUCTION_ACTIVE_POWER), // Consumption - new DummyPredictor(PREDICTOR_ID, cm, + new DummyPredictor("predictor0", cm, Prediction.from(sum, SUM_CONSUMPTION_ACTIVE_POWER, now, DEFAULT_CONSUMPTION_PREDICTION), SUM_CONSUMPTION_ACTIVE_POWER)); @@ -356,10 +339,10 @@ public void automatic_default_predictions_at_evening_test() throws Exception { .addReference("meter", METER) // .addReference("sum", new DummySum()) // .activate(MyConfig.create() // - .setEssId(ESS_ID) // - .setId(CTRL_ID) // + .setEssId("ess0") // + .setId("ctrlGridOptimizedCharge0") // .setMaximumSellToGridPower(7_000) // - .setMeterId(METER_ID) // + .setMeterId("meter0") // .setDelayChargeRiskLevel(DelayChargeRiskLevel.MEDIUM) // .setMode(Mode.AUTOMATIC) // .setSellToGridLimitEnabled(true) // @@ -368,11 +351,11 @@ public void automatic_default_predictions_at_evening_test() throws Exception { .build()) // .next(new TestCase() // .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // - .input(METER_ACTIVE_POWER, 0) // - .input(ESS_ACTIVE_POWER, 0) // - .input(ESS_CAPACITY, 10_000) // - .input(ESS_SOC, 20) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 0) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 0) // + .input("ess0", CAPACITY, 10_000) // + .input("ess0", SOC, 20) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // .input(PREDICTED_TARGET_MINUTE, /* QuarterHour */ 68 * 15) // .input(START_EPOCH_SECONDS, 1630566000) // .input(PREDICTED_TARGET_MINUTE_ADJUSTED, /* QuarterHour */ 68 * 15 - 120) // @@ -401,7 +384,8 @@ public void automatic_default_predictions_at_evening_test() throws Exception { .output(DELAY_CHARGE_STATE, DelayChargeState.ACTIVE_LIMIT) // .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, -6650) // .output(RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT, 6650) // - .output(DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, 2075)); + .output(DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, 2075)) // + .deactivate(); } @Test @@ -409,8 +393,8 @@ public void automatic_no_predictions_test() throws Exception { final var clock = new TimeLeapClock(Instant.parse("2020-01-01T00:00:00.00Z"), ZoneOffset.UTC); final var cm = new DummyComponentManager(clock); final var predictorManager = new DummyPredictorManager( - new DummyPredictor(PREDICTOR_ID, cm, EMPTY_PREDICTION, SUM_PRODUCTION_ACTIVE_POWER), // - new DummyPredictor(PREDICTOR_ID, cm, EMPTY_PREDICTION, SUM_CONSUMPTION_ACTIVE_POWER)); + new DummyPredictor("predictor0", cm, EMPTY_PREDICTION, SUM_PRODUCTION_ACTIVE_POWER), // + new DummyPredictor("predictor0", cm, EMPTY_PREDICTION, SUM_CONSUMPTION_ACTIVE_POWER)); new ControllerTest(new ControllerEssGridOptimizedChargeImpl()) // .addReference("predictorManager", predictorManager) // @@ -420,10 +404,10 @@ public void automatic_no_predictions_test() throws Exception { .addReference("meter", METER) // .addReference("sum", new DummySum()) // .activate(MyConfig.create() // - .setEssId(ESS_ID) // - .setId(CTRL_ID) // + .setEssId("ess0") // + .setId("ctrlGridOptimizedCharge0") // .setMaximumSellToGridPower(7_000) // - .setMeterId(METER_ID) // + .setMeterId("meter0") // .setDelayChargeRiskLevel(DelayChargeRiskLevel.MEDIUM) // .setMode(Mode.AUTOMATIC) // .setSellToGridLimitEnabled(true) // @@ -432,15 +416,16 @@ public void automatic_no_predictions_test() throws Exception { .build()) // .next(new TestCase() // .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // - .input(METER_ACTIVE_POWER, 0) // - .input(ESS_ACTIVE_POWER, 0) // - .input(ESS_CAPACITY, 10_000) // - .input(ESS_SOC, 20) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 0) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 0) // + .input("ess0", CAPACITY, 10_000) // + .input("ess0", SOC, 20) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // .input(START_EPOCH_SECONDS, 1630566000) // .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, -6650) // .output(RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT, 6650) // - .output(DELAY_CHARGE_STATE, DelayChargeState.TARGET_MINUTE_NOT_CALCULATED)); + .output(DELAY_CHARGE_STATE, DelayChargeState.TARGET_MINUTE_NOT_CALCULATED)) // + .deactivate(); } @Test @@ -448,8 +433,8 @@ public void automatic_sell_to_grid_limit_test() throws Exception { final var clock = new TimeLeapClock(Instant.parse("2020-01-01T00:00:00.00Z"), ZoneOffset.UTC); final var cm = new DummyComponentManager(clock); final var predictorManager = new DummyPredictorManager( - new DummyPredictor(PREDICTOR_ID, cm, EMPTY_PREDICTION, SUM_PRODUCTION_ACTIVE_POWER), // - new DummyPredictor(PREDICTOR_ID, cm, EMPTY_PREDICTION, SUM_CONSUMPTION_ACTIVE_POWER)); + new DummyPredictor("predictor0", cm, EMPTY_PREDICTION, SUM_PRODUCTION_ACTIVE_POWER), // + new DummyPredictor("predictor0", cm, EMPTY_PREDICTION, SUM_CONSUMPTION_ACTIVE_POWER)); new ControllerTest(new ControllerEssGridOptimizedChargeImpl()) // .addReference("predictorManager", predictorManager) // @@ -459,10 +444,10 @@ public void automatic_sell_to_grid_limit_test() throws Exception { .addReference("meter", METER) // .addReference("sum", new DummySum()) // .activate(MyConfig.create() // - .setEssId(ESS_ID) // - .setId(CTRL_ID) // + .setEssId("ess0") // + .setId("ctrlGridOptimizedCharge0") // .setMaximumSellToGridPower(7_000) // - .setMeterId(METER_ID) // + .setMeterId("meter0") // .setDelayChargeRiskLevel(DelayChargeRiskLevel.MEDIUM) // .setMode(Mode.AUTOMATIC) // .setSellToGridLimitEnabled(true) // @@ -471,51 +456,51 @@ public void automatic_sell_to_grid_limit_test() throws Exception { .build()) // .next(new TestCase() // .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // - .input(METER_ACTIVE_POWER, -7500) // - .input(ESS_CAPACITY, 10_000) // - .input(ESS_SOC, 20) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .input(ESS_ACTIVE_POWER, 0) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, -7500) // + .input("ess0", CAPACITY, 10_000) // + .input("ess0", SOC, 20) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 0) // .input(START_EPOCH_SECONDS, 1630566000) // .output(DELAY_CHARGE_STATE, DelayChargeState.TARGET_MINUTE_NOT_CALCULATED) // .output(DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, null) // - .output(ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS, -850) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, -850) // .output(RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT, -850) // .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 850) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // .next(new TestCase() // .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // - .input(METER_ACTIVE_POWER, -12000) // - .input(ESS_ACTIVE_POWER, -850) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, -12000) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, -850) // .input(START_EPOCH_SECONDS, 1630566000) // - .output(ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS, -6200) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, -6200) // .output(RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT, -6200) // .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 6200) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // .next(new TestCase() // .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // - .input(METER_ACTIVE_POWER, -7000) // - .input(ESS_ACTIVE_POWER, -6200) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, -7000) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, -6200) // .input(START_EPOCH_SECONDS, 1630566000) // - .output(ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS, -6550) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, -6550) // .output(RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT, -6550) // .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 6550) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // .next(new TestCase() // .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // - .input(METER_ACTIVE_POWER, -5000) // - .input(ESS_ACTIVE_POWER, -6550) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, -5000) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, -6550) // .input(START_EPOCH_SECONDS, 1630566000) // - .output(ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS, -6050) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, -6050) // .output(RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT, -6050) // .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 6050) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // .next(new TestCase() // .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // - .input(METER_ACTIVE_POWER, -8000) // - .input(ESS_ACTIVE_POWER, -6050) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, -8000) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, -6050) // .input(START_EPOCH_SECONDS, 1630566000) // - .output(ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS, -7400) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, -7400) // .output(RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT, -7400) // .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 7400) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // @@ -523,22 +508,23 @@ public void automatic_sell_to_grid_limit_test() throws Exception { // Difference between last limit and current lower than the ramp - ramp is not // applied .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // - .input(METER_ACTIVE_POWER, -7000) // - .input(ESS_ACTIVE_POWER, -7400) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, -7000) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, -7400) // .input(START_EPOCH_SECONDS, 1630566000) // - .output(ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS, -7750) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, -7750) // .output(RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT, -7750) // .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 7750) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // .next(new TestCase() // .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // - .input(METER_ACTIVE_POWER, -6000) // - .input(ESS_ACTIVE_POWER, -7750) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, -6000) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, -7750) // .input(START_EPOCH_SECONDS, 1630566000) // - .output(ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS, -7250) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, -7250) // .output(RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT, -7250) // .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 7250) // - .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)); + .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // + .deactivate(); } @Test @@ -546,8 +532,8 @@ public void automatic_sell_to_grid_limit_test_with_full_ess() throws Exception { final var clock = new TimeLeapClock(Instant.parse("2020-01-01T00:00:00.00Z"), ZoneOffset.UTC); final var cm = new DummyComponentManager(clock); final var predictorManager = new DummyPredictorManager( - new DummyPredictor(PREDICTOR_ID, cm, EMPTY_PREDICTION, SUM_PRODUCTION_ACTIVE_POWER), // - new DummyPredictor(PREDICTOR_ID, cm, EMPTY_PREDICTION, SUM_CONSUMPTION_ACTIVE_POWER)); + new DummyPredictor("predictor0", cm, EMPTY_PREDICTION, SUM_PRODUCTION_ACTIVE_POWER), // + new DummyPredictor("predictor0", cm, EMPTY_PREDICTION, SUM_CONSUMPTION_ACTIVE_POWER)); new ControllerTest(new ControllerEssGridOptimizedChargeImpl()) // .addReference("predictorManager", predictorManager) // @@ -557,10 +543,10 @@ public void automatic_sell_to_grid_limit_test_with_full_ess() throws Exception { .addReference("meter", METER) // .addReference("sum", new DummySum()) // .activate(MyConfig.create() // - .setEssId(ESS_ID) // - .setId(CTRL_ID) // + .setEssId("ess0") // + .setId("ctrlGridOptimizedCharge0") // .setMaximumSellToGridPower(7_000) // - .setMeterId(METER_ID) // + .setMeterId("meter0") // .setDelayChargeRiskLevel(DelayChargeRiskLevel.MEDIUM) // .setMode(Mode.AUTOMATIC) // .setSellToGridLimitEnabled(true) // @@ -568,77 +554,78 @@ public void automatic_sell_to_grid_limit_test_with_full_ess() throws Exception { .setManualTargetTime("") // .build()) // .next(new TestCase() // - .input(METER_ACTIVE_POWER, -7500) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, -7500) // .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // - .input(ESS_CAPACITY, 10_000) // - .input(ESS_SOC, 100) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .input(ESS_ACTIVE_POWER, 0) // + .input("ess0", CAPACITY, 10_000) // + .input("ess0", SOC, 100) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 0) // .input(START_EPOCH_SECONDS, 1630566000) // .output(DELAY_CHARGE_STATE, DelayChargeState.TARGET_MINUTE_NOT_CALCULATED) // .output(DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, null) // - .output(ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS, -500) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, -500) // .output(RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT, -500) // .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 500) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // .next(new TestCase() // - .input(METER_ACTIVE_POWER, -12000) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, -12000) // .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // - .input(ESS_ACTIVE_POWER, -1000) // - .input(ESS_SOC, 100) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, -1000) // + .input("ess0", SOC, 100) // .input(START_EPOCH_SECONDS, 1630566000) // - .output(ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS, -6000) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, -6000) // .output(RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT, -6000) // .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 6000) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // .next(new TestCase() // - .input(METER_ACTIVE_POWER, -7000) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, -7000) // .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // - .input(ESS_ACTIVE_POWER, -6000) // - .input(ESS_SOC, 100) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, -6000) // + .input("ess0", SOC, 100) // .input(START_EPOCH_SECONDS, 1630566000) // - .output(ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS, -6000) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, -6000) // .output(RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT, -6000) // .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 6000) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // .next(new TestCase() // - .input(METER_ACTIVE_POWER, -5000) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, -5000) // .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // - .input(ESS_ACTIVE_POWER, -6000) // - .input(ESS_SOC, 100) // - .output(ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS, -5500) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, -6000) // + .input("ess0", SOC, 100) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, -5500) // .output(RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT, -5500) // .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 5500) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // .next(new TestCase() // - .input(METER_ACTIVE_POWER, -8000) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, -8000) // .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // - .input(ESS_ACTIVE_POWER, -5500) // - .input(ESS_SOC, 100) // - .output(ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS, -6500) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, -5500) // + .input("ess0", SOC, 100) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, -6500) // .output(RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT, -6500) // .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 6500) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // .next(new TestCase() // // Difference between last limit and current lower than the ramp - ramp is not // applied - .input(METER_ACTIVE_POWER, -7000) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, -7000) // .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // - .input(ESS_ACTIVE_POWER, -6300) // - .input(ESS_SOC, 100) // - .output(ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS, -6300) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, -6300) // + .input("ess0", SOC, 100) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, -6300) // .output(RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT, -6300) // .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 6300) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // .next(new TestCase() // .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // - .input(METER_ACTIVE_POWER, -6000) // - .input(ESS_ACTIVE_POWER, -6000) // - .input(ESS_SOC, 100) // - .output(ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS, -5800) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, -6000) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, -6000) // + .input("ess0", SOC, 100) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, -5800) // .output(RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT, -5800) // .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 5800) // - .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)); + .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // + .deactivate(); } @Test @@ -646,8 +633,8 @@ public void automatic_sell_to_grid_limit_buffer_test() throws Exception { final var clock = new TimeLeapClock(Instant.parse("2020-01-01T00:00:00.00Z"), ZoneOffset.UTC); final var cm = new DummyComponentManager(clock); final var predictorManager = new DummyPredictorManager( - new DummyPredictor(PREDICTOR_ID, cm, EMPTY_PREDICTION, SUM_PRODUCTION_ACTIVE_POWER), // - new DummyPredictor(PREDICTOR_ID, cm, EMPTY_PREDICTION, SUM_CONSUMPTION_ACTIVE_POWER)); + new DummyPredictor("predictor0", cm, EMPTY_PREDICTION, SUM_PRODUCTION_ACTIVE_POWER), // + new DummyPredictor("predictor0", cm, EMPTY_PREDICTION, SUM_CONSUMPTION_ACTIVE_POWER)); new ControllerTest(new ControllerEssGridOptimizedChargeImpl()) // .addReference("predictorManager", predictorManager) // @@ -657,10 +644,10 @@ public void automatic_sell_to_grid_limit_buffer_test() throws Exception { .addReference("meter", METER) // .addReference("sum", new DummySum()) // .activate(MyConfig.create() // - .setEssId(ESS_ID) // - .setId(CTRL_ID) // + .setEssId("ess0") // + .setId("ctrlGridOptimizedCharge0") // .setMaximumSellToGridPower(7_000) // - .setMeterId(METER_ID) // + .setMeterId("meter0") // .setDelayChargeRiskLevel(DelayChargeRiskLevel.MEDIUM) // .setMode(Mode.AUTOMATIC) // .setSellToGridLimitEnabled(true) // @@ -669,51 +656,51 @@ public void automatic_sell_to_grid_limit_buffer_test() throws Exception { .build()) // .next(new TestCase() // .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // - .input(METER_ACTIVE_POWER, -7500) // - .input(ESS_CAPACITY, 10_000) // - .input(ESS_SOC, 20) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .input(ESS_ACTIVE_POWER, 0) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, -7500) // + .input("ess0", CAPACITY, 10_000) // + .input("ess0", SOC, 20) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 0) // .input(START_EPOCH_SECONDS, 1630566000) // .output(DELAY_CHARGE_STATE, DelayChargeState.TARGET_MINUTE_NOT_CALCULATED) // .output(DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, null) // - .output(ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS, -850) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, -850) // .output(RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT, -850) // .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 850) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // .next(new TestCase() // .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // - .input(METER_ACTIVE_POWER, -12000) // - .input(ESS_ACTIVE_POWER, -1000) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, -12000) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, -1000) // .input(START_EPOCH_SECONDS, 1630566000) // - .output(ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS, -6350) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, -6350) // .output(RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT, -6350) // .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 6350) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // .next(new TestCase() // .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // - .input(METER_ACTIVE_POWER, -7000) // - .input(ESS_ACTIVE_POWER, -6000) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, -7000) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, -6000) // .input(START_EPOCH_SECONDS, 1630566000) // - .output(ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS, -6350) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, -6350) // .output(RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT, -6350) // .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 6350) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // .next(new TestCase() // .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // - .input(METER_ACTIVE_POWER, -5000) // - .input(ESS_ACTIVE_POWER, -6000) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, -5000) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, -6000) // .input(START_EPOCH_SECONDS, 1630566000) // - .output(ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS, -5850) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, -5850) // .output(RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT, -5850) // .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 5850) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // .next(new TestCase() // .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // - .input(METER_ACTIVE_POWER, -8000) // - .input(ESS_ACTIVE_POWER, -5500) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, -8000) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, -5500) // .input(START_EPOCH_SECONDS, 1630566000) // - .output(ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS, -6850) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, -6850) // .output(RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT, -6850) // .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 6850) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // @@ -721,22 +708,23 @@ public void automatic_sell_to_grid_limit_buffer_test() throws Exception { // Difference between last limit and current lower than the ramp - ramp is not // applied .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // - .input(METER_ACTIVE_POWER, -7000) // - .input(ESS_ACTIVE_POWER, -6300) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, -7000) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, -6300) // .input(START_EPOCH_SECONDS, 1630566000) // - .output(ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS, -6650) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, -6650) // .output(RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT, -6650) // .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 6650) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // .next(new TestCase() // .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // - .input(METER_ACTIVE_POWER, -6000) // - .input(ESS_ACTIVE_POWER, -6000) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, -6000) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, -6000) // .input(START_EPOCH_SECONDS, 1630566000) // - .output(ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS, -6150) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, -6150) // .output(RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT, -6150) // .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 6150) // - .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)); + .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT)) // + .deactivate(); } @Test @@ -747,11 +735,11 @@ public void manual_midnight_test() throws Exception { final var sum = new DummySum(); final var predictorManager = new DummyPredictorManager( // Production - new DummyPredictor(PREDICTOR_ID, cm, + new DummyPredictor("predictor0", cm, Prediction.from(sum, SUM_PRODUCTION_ACTIVE_POWER, now, DEFAULT_PRODUCTION_PREDICTION), SUM_PRODUCTION_ACTIVE_POWER), // Consumption - new DummyPredictor(PREDICTOR_ID, cm, + new DummyPredictor("predictor0", cm, Prediction.from(sum, SUM_CONSUMPTION_ACTIVE_POWER, now, DEFAULT_CONSUMPTION_PREDICTION), SUM_CONSUMPTION_ACTIVE_POWER)); @@ -763,10 +751,10 @@ public void manual_midnight_test() throws Exception { .addReference("meter", METER) // .addReference("sum", new DummySum()) // .activate(MyConfig.create() // - .setEssId(ESS_ID) // - .setId(CTRL_ID) // + .setEssId("ess0") // + .setId("ctrlGridOptimizedCharge0") // .setMaximumSellToGridPower(7_000) // - .setMeterId(METER_ID) // + .setMeterId("meter0") // .setDelayChargeRiskLevel(DelayChargeRiskLevel.MEDIUM) // .setMode(Mode.MANUAL) // .setSellToGridLimitEnabled(true) // @@ -774,12 +762,12 @@ public void manual_midnight_test() throws Exception { .setSellToGridLimitRampPercentage(5) // .build()) // .next(new TestCase() // - .input(METER_ACTIVE_POWER, 0) // - .input(ESS_ACTIVE_POWER, 0) // - .input(ESS_CAPACITY, 10_000) // - .input(ESS_SOC, 20) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 0) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 0) // + .input("ess0", CAPACITY, 10_000) // + .input("ess0", SOC, 20) // .input(START_EPOCH_SECONDS, 1630566000) // - .input(ESS_MAX_APPARENT_POWER, 10_000)) // + .input("ess0", MAX_APPARENT_POWER, 10_000)) // .next(new TestCase() // .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // .input(START_EPOCH_SECONDS, 1630566000) // @@ -787,7 +775,8 @@ public void manual_midnight_test() throws Exception { .output(DELAY_CHARGE_STATE, DelayChargeState.AVOID_LOW_CHARGING) // .output(RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT, 6650) // .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, -6650) // - .output(DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, 0)); // 476 W below minimum + .output(DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, 0)) // 476 W below minimum + .deactivate(); } @Test @@ -798,11 +787,11 @@ public void manual_midday_test() throws Exception { final var sum = new DummySum(); final var predictorManager = new DummyPredictorManager( // Production - new DummyPredictor(PREDICTOR_ID, cm, + new DummyPredictor("predictor0", cm, Prediction.from(sum, SUM_PRODUCTION_ACTIVE_POWER, now, DEFAULT_PRODUCTION_PREDICTION), SUM_PRODUCTION_ACTIVE_POWER), // Consumption - new DummyPredictor(PREDICTOR_ID, cm, + new DummyPredictor("predictor0", cm, Prediction.from(sum, SUM_CONSUMPTION_ACTIVE_POWER, now, DEFAULT_CONSUMPTION_PREDICTION), SUM_CONSUMPTION_ACTIVE_POWER)); @@ -814,10 +803,10 @@ public void manual_midday_test() throws Exception { .addReference("meter", METER) // .addReference("sum", new DummySum()) // .activate(MyConfig.create() // - .setEssId(ESS_ID) // - .setId(CTRL_ID) // + .setEssId("ess0") // + .setId("ctrlGridOptimizedCharge0") // .setMaximumSellToGridPower(7_000) // - .setMeterId(METER_ID) // + .setMeterId("meter0") // .setDelayChargeRiskLevel(DelayChargeRiskLevel.MEDIUM) // .setMode(Mode.MANUAL) // .setSellToGridLimitEnabled(true) // @@ -826,17 +815,18 @@ public void manual_midday_test() throws Exception { .build()) // .next(new TestCase() // .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // - .input(METER_ACTIVE_POWER, 0) // - .input(ESS_ACTIVE_POWER, 0) // - .input(ESS_CAPACITY, 10_000) // - .input(ESS_SOC, 20) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 0) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 0) // + .input("ess0", CAPACITY, 10_000) // + .input("ess0", SOC, 20) // .input(START_EPOCH_SECONDS, 1630566000) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // .output(TARGET_MINUTE, /* QuarterHour */ 1020) // .output(DELAY_CHARGE_STATE, DelayChargeState.ACTIVE_LIMIT) // .output(RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT, 6650) // .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, -6650) // - .output(DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, 1620)); + .output(DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, 1620)) // + .deactivate(); } @Test @@ -847,11 +837,11 @@ public void hybridEss_manual_midday_test() throws Exception { final var sum = new DummySum(); final var predictorManager = new DummyPredictorManager( // Production - new DummyPredictor(PREDICTOR_ID, cm, + new DummyPredictor("predictor0", cm, Prediction.from(sum, SUM_PRODUCTION_ACTIVE_POWER, now, DEFAULT_PRODUCTION_PREDICTION), SUM_PRODUCTION_ACTIVE_POWER), // Consumption - new DummyPredictor(PREDICTOR_ID, cm, + new DummyPredictor("predictor0", cm, Prediction.from(sum, SUM_CONSUMPTION_ACTIVE_POWER, now, DEFAULT_CONSUMPTION_PREDICTION), SUM_CONSUMPTION_ACTIVE_POWER)); @@ -863,10 +853,10 @@ public void hybridEss_manual_midday_test() throws Exception { .addReference("meter", METER) // .addReference("sum", new DummySum()) // .activate(MyConfig.create() // - .setEssId(ESS_ID) // - .setId(CTRL_ID) // + .setEssId("ess0") // + .setId("ctrlGridOptimizedCharge0") // .setMaximumSellToGridPower(7_000) // - .setMeterId(METER_ID) // + .setMeterId("meter0") // .setDelayChargeRiskLevel(DelayChargeRiskLevel.MEDIUM) // .setMode(Mode.MANUAL) // .setSellToGridLimitEnabled(true) // @@ -875,18 +865,20 @@ public void hybridEss_manual_midday_test() throws Exception { .build()) // .next(new TestCase() // .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // - .input(METER_ACTIVE_POWER, 0) // - .input(ESS_ACTIVE_POWER, 0) // - .input(ESS_CAPACITY, 10_000) // - .input(ESS_SOC, 20) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 0) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 0) // + .input("ess0", CAPACITY, 10_000) // + .input("ess0", SOC, 20) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // .input(START_EPOCH_SECONDS, 1630566000) // - .input(SUM_PRODUCTION_DC_ACTUAL_POWER, 10_000).output(TARGET_MINUTE, /* QuarterHour */ 1020) // + .input(PRODUCTION_DC_ACTUAL_POWER, 10_000) // + .output(TARGET_MINUTE, /* QuarterHour */ 1020) // .output(DELAY_CHARGE_STATE, DelayChargeState.NO_CHARGE_LIMIT) // .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 3350) // .output(RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT, 6650) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_FIXED) // - .output(DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, null)); + .output(DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, null)) // + .deactivate(); } @@ -898,11 +890,11 @@ public void mode_off_test() throws Exception { final var sum = new DummySum(); final var predictorManager = new DummyPredictorManager( // Production - new DummyPredictor(PREDICTOR_ID, cm, + new DummyPredictor("predictor0", cm, Prediction.from(sum, SUM_PRODUCTION_ACTIVE_POWER, now, DEFAULT_PRODUCTION_PREDICTION), SUM_PRODUCTION_ACTIVE_POWER), // Consumption - new DummyPredictor(PREDICTOR_ID, cm, + new DummyPredictor("predictor0", cm, Prediction.from(sum, SUM_CONSUMPTION_ACTIVE_POWER, now, DEFAULT_CONSUMPTION_PREDICTION), SUM_CONSUMPTION_ACTIVE_POWER)); @@ -914,10 +906,10 @@ public void mode_off_test() throws Exception { .addReference("meter", METER) // .addReference("sum", new DummySum()) // .activate(MyConfig.create() // - .setEssId(ESS_ID) // - .setId(CTRL_ID) // + .setEssId("ess0") // + .setId("ctrlGridOptimizedCharge0") // .setMaximumSellToGridPower(7_000) // - .setMeterId(METER_ID) // + .setMeterId("meter0") // .setDelayChargeRiskLevel(DelayChargeRiskLevel.MEDIUM) // .setMode(Mode.OFF) // .setSellToGridLimitEnabled(true) // @@ -926,16 +918,17 @@ public void mode_off_test() throws Exception { .build()) // .next(new TestCase() // .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // - .input(METER_ACTIVE_POWER, -7500) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // - .input(ESS_ACTIVE_POWER, 0) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, -7500) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 0) // .input(START_EPOCH_SECONDS, 1630566000) // .output(DELAY_CHARGE_STATE, DelayChargeState.DISABLED) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.ACTIVE_LIMIT_CONSTRAINT) // .output(DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, null) // - .output(ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS, -850) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, -850) // .output(RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT, -850) // - .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 850)); // + .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, 850)) // + .deactivate(); } @Test @@ -946,11 +939,11 @@ public void no_capacity_left_test() throws Exception { final var sum = new DummySum(); final var predictorManager = new DummyPredictorManager( // Production - new DummyPredictor(PREDICTOR_ID, cm, + new DummyPredictor("predictor0", cm, Prediction.from(sum, SUM_PRODUCTION_ACTIVE_POWER, now, DEFAULT_PRODUCTION_PREDICTION), SUM_PRODUCTION_ACTIVE_POWER), // Consumption - new DummyPredictor(PREDICTOR_ID, cm, + new DummyPredictor("predictor0", cm, Prediction.from(sum, SUM_CONSUMPTION_ACTIVE_POWER, now, DEFAULT_CONSUMPTION_PREDICTION), SUM_CONSUMPTION_ACTIVE_POWER)); @@ -962,10 +955,10 @@ public void no_capacity_left_test() throws Exception { .addReference("meter", METER) // .addReference("sum", new DummySum()) // .activate(MyConfig.create() // - .setEssId(ESS_ID) // - .setId(CTRL_ID) // + .setEssId("ess0") // + .setId("ctrlGridOptimizedCharge0") // .setMaximumSellToGridPower(7_000) // - .setMeterId(METER_ID) // + .setMeterId("meter0") // .setDelayChargeRiskLevel(DelayChargeRiskLevel.MEDIUM) // .setMode(Mode.AUTOMATIC) // .setSellToGridLimitEnabled(true) // @@ -973,19 +966,20 @@ public void no_capacity_left_test() throws Exception { .setManualTargetTime("") // .build()) // .next(new TestCase() // - .input(METER_ACTIVE_POWER, 0) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 0) // .input(SUM_PRODUCTION_ACTIVE_POWER, 0) // - .input(ESS_ACTIVE_POWER, 0) // - .input(ESS_CAPACITY, 10_000) // - .input(ESS_SOC, 99) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 0) // + .input("ess0", CAPACITY, 10_000) // + .input("ess0", SOC, 99) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // .input(START_EPOCH_SECONDS, 1630566000) // // ess.getPower().getMinPower() (Maximum allowed charge power) is '0' because // the referenced // DummyManagedSymmetricEss has an apparent power of zero. .output(DELAY_CHARGE_STATE, DelayChargeState.NO_REMAINING_CAPACITY) // - .output(DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, null)); // + .output(DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, null)) // + .deactivate(); } @Test @@ -1001,11 +995,11 @@ public void start_production_not_enough_test() throws Exception { final var sum = new DummySum(); final var predictorManager = new DummyPredictorManager( // Production - new DummyPredictor(PREDICTOR_ID, cm, + new DummyPredictor("predictor0", cm, Prediction.from(sum, SUM_PRODUCTION_ACTIVE_POWER, now, DEFAULT_PRODUCTION_PREDICTION), SUM_PRODUCTION_ACTIVE_POWER), // Consumption - new DummyPredictor(PREDICTOR_ID, cm, + new DummyPredictor("predictor0", cm, Prediction.from(sum, SUM_CONSUMPTION_ACTIVE_POWER, now, DEFAULT_CONSUMPTION_PREDICTION), SUM_CONSUMPTION_ACTIVE_POWER)); @@ -1017,10 +1011,10 @@ public void start_production_not_enough_test() throws Exception { .addReference("meter", METER) // .addReference("sum", new DummySum()) // .activate(MyConfig.create() // - .setEssId(ESS_ID) // - .setId(CTRL_ID) // + .setEssId("ess0") // + .setId("ctrlGridOptimizedCharge0") // .setMaximumSellToGridPower(7_000) // - .setMeterId(METER_ID) // + .setMeterId("meter0") // .setDelayChargeRiskLevel(DelayChargeRiskLevel.MEDIUM) // .setMode(Mode.OFF) // .setSellToGridLimitEnabled(true) // @@ -1047,7 +1041,8 @@ public void start_production_not_enough_test() throws Exception { .input(SUM_CONSUMPTION_ACTIVE_POWER, 6000) // .output(DELAY_CHARGE_STATE, DelayChargeState.NOT_STARTED) // .output(SELL_TO_GRID_LIMIT_STATE, SellToGridLimitState.NOT_STARTED) // - .output(START_EPOCH_SECONDS, null)); // + .output(START_EPOCH_SECONDS, null)) // + .deactivate(); } @Test @@ -1063,11 +1058,11 @@ public void start_production_average_test() throws Exception { final var sum = new DummySum(); final var predictorManager = new DummyPredictorManager( // Production - new DummyPredictor(PREDICTOR_ID, cm, + new DummyPredictor("predictor0", cm, Prediction.from(sum, SUM_PRODUCTION_ACTIVE_POWER, now, DEFAULT_PRODUCTION_PREDICTION), SUM_PRODUCTION_ACTIVE_POWER), // Consumption - new DummyPredictor(PREDICTOR_ID, cm, + new DummyPredictor("predictor0", cm, Prediction.from(sum, SUM_CONSUMPTION_ACTIVE_POWER, now, DEFAULT_CONSUMPTION_PREDICTION), SUM_CONSUMPTION_ACTIVE_POWER)); @@ -1079,10 +1074,10 @@ public void start_production_average_test() throws Exception { .addReference("meter", METER) // .addReference("sum", new DummySum()) // .activate(MyConfig.create() // - .setEssId(ESS_ID) // - .setId(CTRL_ID) // + .setEssId("ess0") // + .setId("ctrlGridOptimizedCharge0") // .setMaximumSellToGridPower(7_000) // - .setMeterId(METER_ID) // + .setMeterId("meter0") // .setDelayChargeRiskLevel(DelayChargeRiskLevel.MEDIUM) // .setMode(Mode.MANUAL) // .setSellToGridLimitEnabled(true) // @@ -1188,11 +1183,11 @@ public void start_production_average_test() throws Exception { .input(SUM_PRODUCTION_ACTIVE_POWER, 2000) // Avg: 1166 .input(SUM_CONSUMPTION_ACTIVE_POWER, 1000) // .input(START_EPOCH_SECONDS, null) // - .input(METER_ACTIVE_POWER, 0) // - .input(ESS_ACTIVE_POWER, 0) // - .input(ESS_CAPACITY, 10_000) // - .input(ESS_SOC, 20) // - .input(ESS_MAX_APPARENT_POWER, 10_000) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 0) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 0) // + .input("ess0", CAPACITY, 10_000) // + .input("ess0", SOC, 20) // + .input("ess0", MAX_APPARENT_POWER, 10_000) // // Epoch seconds at 2020-01-01 00:00:00: 1577836800 (Clock is not updated) .output(START_EPOCH_SECONDS, 1577836800L) // @@ -1200,12 +1195,12 @@ public void start_production_average_test() throws Exception { .output(DELAY_CHARGE_STATE, DelayChargeState.AVOID_LOW_CHARGING) // .output(RAW_SELL_TO_GRID_LIMIT_CHARGE_LIMIT, 6650) // .output(SELL_TO_GRID_LIMIT_MINIMUM_CHARGE_LIMIT, -6650) // - .output(DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, 0)); // 506 W is not efficient + .output(DELAY_CHARGE_MAXIMUM_CHARGE_LIMIT, 0)) // 506 W is not efficient + .deactivate(); } @Test public void getCalculatedPowerLimit_middayTest() throws Exception { - /* * Initial values */ @@ -1671,11 +1666,11 @@ public void calculateAvailEnergy_test() throws Exception { final var sum = new DummySum(); final var predictorManager = new DummyPredictorManager( // Production - new DummyPredictor(PREDICTOR_ID, cm, + new DummyPredictor("predictor0", cm, Prediction.from(sum, SUM_PRODUCTION_ACTIVE_POWER, midnight, DEFAULT_PRODUCTION_PREDICTION), SUM_PRODUCTION_ACTIVE_POWER), // Consumption - new DummyPredictor(PREDICTOR_ID, cm, + new DummyPredictor("predictor0", cm, Prediction.from(sum, SUM_CONSUMPTION_ACTIVE_POWER, midnight, DEFAULT_CONSUMPTION_PREDICTION), SUM_CONSUMPTION_ACTIVE_POWER)); diff --git a/io.openems.edge.controller.ess.hybrid.surplusfeedtogrid/test/io/openems/edge/controller/ess/hybrid/surplusfeedtogrid/ControllerEssHybridSurplusFeedToGridImplTest.java b/io.openems.edge.controller.ess.hybrid.surplusfeedtogrid/test/io/openems/edge/controller/ess/hybrid/surplusfeedtogrid/ControllerEssHybridSurplusFeedToGridImplTest.java index de89c02eda6..94d0e84fbb1 100644 --- a/io.openems.edge.controller.ess.hybrid.surplusfeedtogrid/test/io/openems/edge/controller/ess/hybrid/surplusfeedtogrid/ControllerEssHybridSurplusFeedToGridImplTest.java +++ b/io.openems.edge.controller.ess.hybrid.surplusfeedtogrid/test/io/openems/edge/controller/ess/hybrid/surplusfeedtogrid/ControllerEssHybridSurplusFeedToGridImplTest.java @@ -1,8 +1,10 @@ package io.openems.edge.controller.ess.hybrid.surplusfeedtogrid; +import static io.openems.edge.controller.ess.hybrid.surplusfeedtogrid.ControllerEssHybridSurplusFeedToGrid.ChannelId.SURPLUS_FEED_TO_GRID_IS_LIMITED; +import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_GREATER_OR_EQUALS; + import org.junit.Test; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyConfigurationAdmin; import io.openems.edge.controller.test.ControllerTest; @@ -10,41 +12,33 @@ public class ControllerEssHybridSurplusFeedToGridImplTest { - private static final String CTRL_ID = "ctrl0"; - - private static final ChannelAddress CTRL_SURPLUS_FEED_TO_GRID_IS_LIMITED = new ChannelAddress(CTRL_ID, - "SurplusFeedToGridIsLimited"); - - private static final String ESS_ID = "ess0"; - - private static final ChannelAddress ESS_SET_ACTIVE_POWER_GREATER_OR_EQUALS = new ChannelAddress(ESS_ID, - "SetActivePowerGreaterOrEquals"); - @Test public void test() throws Exception { - final var ess = new DummyHybridEss(ESS_ID); + final var ess = new DummyHybridEss("ess0"); final var test = new ControllerTest(new ControllerEssHybridSurplusFeedToGridImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("ess", ess) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .build()); ess.withSurplusPower(null); test.next(new TestCase() // - .output(ESS_SET_ACTIVE_POWER_GREATER_OR_EQUALS, null)); + .output("ess0", SET_ACTIVE_POWER_GREATER_OR_EQUALS, null)); ess.withSurplusPower(5000); ess.withMaxApparentPower(10000); test.next(new TestCase() // - .output(CTRL_SURPLUS_FEED_TO_GRID_IS_LIMITED, false) // - .output(ESS_SET_ACTIVE_POWER_GREATER_OR_EQUALS, 5000)); + .output(SURPLUS_FEED_TO_GRID_IS_LIMITED, false) // + .output("ess0", SET_ACTIVE_POWER_GREATER_OR_EQUALS, 5000)); ess.withSurplusPower(5000); ess.withMaxApparentPower(2000); test.next(new TestCase() // - .output(CTRL_SURPLUS_FEED_TO_GRID_IS_LIMITED, true) // - .output(ESS_SET_ACTIVE_POWER_GREATER_OR_EQUALS, 2000)); + .output(SURPLUS_FEED_TO_GRID_IS_LIMITED, true) // + .output("ess0", SET_ACTIVE_POWER_GREATER_OR_EQUALS, 2000)) // + + .deactivate(); } } \ No newline at end of file diff --git a/io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/ControllerEssLimiter14aImpl.java b/io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/ControllerEssLimiter14aImpl.java index a9c1082637f..f9ccb3b36ea 100644 --- a/io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/ControllerEssLimiter14aImpl.java +++ b/io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/ControllerEssLimiter14aImpl.java @@ -11,6 +11,7 @@ import org.osgi.service.component.annotations.ReferencePolicy; import org.osgi.service.component.annotations.ReferencePolicyOption; import org.osgi.service.metatype.annotations.Designate; + import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.types.ChannelAddress; import io.openems.edge.common.channel.BooleanReadChannel; diff --git a/io.openems.edge.controller.ess.limiter14a/test/io/openems/edge/controller/ess/limiter14a/ControllerEssLimiter14aTest.java b/io.openems.edge.controller.ess.limiter14a/test/io/openems/edge/controller/ess/limiter14a/ControllerEssLimiter14aTest.java index 22405060dc7..b7d9cae4a52 100644 --- a/io.openems.edge.controller.ess.limiter14a/test/io/openems/edge/controller/ess/limiter14a/ControllerEssLimiter14aTest.java +++ b/io.openems.edge.controller.ess.limiter14a/test/io/openems/edge/controller/ess/limiter14a/ControllerEssLimiter14aTest.java @@ -1,61 +1,57 @@ package io.openems.edge.controller.ess.limiter14a; +import static io.openems.edge.common.sum.Sum.ChannelId.GRID_MODE; +import static io.openems.edge.controller.ess.limiter14a.ControllerEssLimiter14a.ChannelId.RESTRICTION_MODE; +import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_GREATER_OR_EQUALS; +import static io.openems.edge.io.test.DummyInputOutput.ChannelId.INPUT_OUTPUT0; + import org.junit.Test; import io.openems.common.exceptions.OpenemsException; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.sum.DummySum; import io.openems.edge.common.sum.GridMode; +import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.controller.test.ControllerTest; import io.openems.edge.ess.test.DummyManagedSymmetricEss; -import io.openems.edge.timedata.test.DummyTimedata; import io.openems.edge.io.test.DummyInputOutput; +import io.openems.edge.timedata.test.DummyTimedata; public class ControllerEssLimiter14aTest { - private static final String ESS_ID = "ess0"; - private static final String CTRL_ID = "ctrlEssLimiter14a0"; - - private static final ChannelAddress RESTRICTION_MODE = new ChannelAddress(CTRL_ID, "RestrictionMode"); - private static final ChannelAddress GPIO = new ChannelAddress("io0", "InputOutput0"); - private static final ChannelAddress LIMITATION = new ChannelAddress(ESS_ID, "SetActivePowerGreaterOrEquals"); - private static final ChannelAddress GRID_MODE = new ChannelAddress("_sum", "GridMode"); - @Test public void testController() throws OpenemsException, Exception { new ControllerTest(new ControllerEssLimiter14aImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // .addReference("timedata", new DummyTimedata("timedata0")) // - .addReference("ess", new DummyManagedSymmetricEss(ESS_ID)) // + .addReference("ess", new DummyManagedSymmetricEss("ess0")) // .addReference("sum", new DummySum()) // .addComponent(new DummyInputOutput("io0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID)// + .setId("ctrl0") // + .setEssId("ess0")// .setInputChannelAddress("io0/InputOutput0")// .build()) .next(new TestCase() // // Since logic is reversed - .input(GPIO, false) // - .input(GRID_MODE, GridMode.ON_GRID) - .output(LIMITATION, -4200) + .input("io0", INPUT_OUTPUT0, false) // + .input(GRID_MODE, GridMode.ON_GRID) // + .output("ess0", SET_ACTIVE_POWER_GREATER_OR_EQUALS, -4200) // .output(RESTRICTION_MODE, RestrictionMode.ON)) // .next(new TestCase() // - .input(GPIO, null) // - .output(LIMITATION, null)) // + .input("io0", INPUT_OUTPUT0, null) // + .output("ess0", SET_ACTIVE_POWER_GREATER_OR_EQUALS, null)) // .next(new TestCase() // - .input(GPIO, 1) // + .input("io0", INPUT_OUTPUT0, 1) // .input(GRID_MODE, GridMode.OFF_GRID) // .output(RESTRICTION_MODE, RestrictionMode.OFF)) // .next(new TestCase() // - .input(GPIO, false) // + .input("io0", INPUT_OUTPUT0, false) // .input(GRID_MODE, GridMode.OFF_GRID) // - .output(LIMITATION, null)) // - ; + .output("ess0", SET_ACTIVE_POWER_GREATER_OR_EQUALS, null)) // + .deactivate(); } } diff --git a/io.openems.edge.controller.ess.limittotaldischarge/test/io/openems/edge/controller/ess/limittotaldischarge/ControllerEssLimitTotalDischargeImplTest.java b/io.openems.edge.controller.ess.limittotaldischarge/test/io/openems/edge/controller/ess/limittotaldischarge/ControllerEssLimitTotalDischargeImplTest.java index d86836ed672..f240abc3ed9 100644 --- a/io.openems.edge.controller.ess.limittotaldischarge/test/io/openems/edge/controller/ess/limittotaldischarge/ControllerEssLimitTotalDischargeImplTest.java +++ b/io.openems.edge.controller.ess.limittotaldischarge/test/io/openems/edge/controller/ess/limittotaldischarge/ControllerEssLimitTotalDischargeImplTest.java @@ -1,11 +1,14 @@ package io.openems.edge.controller.ess.limittotaldischarge; +import static io.openems.edge.common.test.TestUtils.createDummyClock; +import static io.openems.edge.controller.ess.limittotaldischarge.ControllerEssLimitTotalDischarge.ChannelId.AWAITING_HYSTERESIS; +import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_LESS_OR_EQUALS; +import static io.openems.edge.ess.api.SymmetricEss.ChannelId.SOC; + import java.time.temporal.ChronoUnit; import org.junit.Test; -import io.openems.common.test.TimeLeapClock; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.controller.test.ControllerTest; @@ -13,47 +16,39 @@ public class ControllerEssLimitTotalDischargeImplTest { - private static final String CTRL_ID = "ctrl0"; - private static final ChannelAddress CTRL_AWAITING_HYSTERESIS = new ChannelAddress(CTRL_ID, "AwaitingHysteresis"); - - private static final String ESS_ID = "ess0"; - private static final ChannelAddress ESS_SOC = new ChannelAddress(ESS_ID, "Soc"); - private static final ChannelAddress ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS = new ChannelAddress(ESS_ID, - "SetActivePowerLessOrEquals"); - @Test public void test() throws Exception { - // Initialize mocked Clock - final var clock = new TimeLeapClock(); + final var clock = createDummyClock(); new ControllerTest(new ControllerEssLimitTotalDischargeImpl()) // .addReference("componentManager", new DummyComponentManager(clock)) // - .addComponent(new DummyManagedSymmetricEss(ESS_ID) // + .addComponent(new DummyManagedSymmetricEss("ess0") // .withSoc(20) // .withCapacity(9000)) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setMinSoc(15) // .setForceChargeSoc(10) // .setForceChargePower(1000) // .build()) .next(new TestCase() // - .input(ESS_SOC, 20) // - .output(ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS, null)// - .output(CTRL_AWAITING_HYSTERESIS, false)) // + .input("ess0", SOC, 20) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, null)// + .output(AWAITING_HYSTERESIS, false)) // .next(new TestCase() // - .input(ESS_SOC, 15) // - .output(ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS, 0) // - .output(CTRL_AWAITING_HYSTERESIS, false)) // + .input("ess0", SOC, 15) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 0) // + .output(AWAITING_HYSTERESIS, false)) // .next(new TestCase() // - .input(ESS_SOC, 16) // - .output(ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS, 0) // - .output(CTRL_AWAITING_HYSTERESIS, true)) // + .input("ess0", SOC, 16) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 0) // + .output(AWAITING_HYSTERESIS, true)) // .next(new TestCase() // .timeleap(clock, 6, ChronoUnit.MINUTES) // - .input(ESS_SOC, 16) // - .output(ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS, null) // - .output(CTRL_AWAITING_HYSTERESIS, false)); + .input("ess0", SOC, 16) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, null) // + .output(AWAITING_HYSTERESIS, false)) // + .deactivate(); } } diff --git a/io.openems.edge.controller.ess.linearpowerband/test/io/openems/edge/controller/ess/linearpowerband/ControllerEssLinearPowerBandImplTest.java b/io.openems.edge.controller.ess.linearpowerband/test/io/openems/edge/controller/ess/linearpowerband/ControllerEssLinearPowerBandImplTest.java index 676304b3b6e..6e85c146ed7 100644 --- a/io.openems.edge.controller.ess.linearpowerband/test/io/openems/edge/controller/ess/linearpowerband/ControllerEssLinearPowerBandImplTest.java +++ b/io.openems.edge.controller.ess.linearpowerband/test/io/openems/edge/controller/ess/linearpowerband/ControllerEssLinearPowerBandImplTest.java @@ -1,8 +1,10 @@ package io.openems.edge.controller.ess.linearpowerband; +import static io.openems.edge.controller.ess.linearpowerband.ControllerEssLinearPowerBand.ChannelId.STATE_MACHINE; +import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_EQUALS; + import org.junit.Test; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyConfigurationAdmin; import io.openems.edge.controller.test.ControllerTest; @@ -10,21 +12,14 @@ public class ControllerEssLinearPowerBandImplTest { - private static final String CTRL_ID = "ctrl0"; - private static final String ESS_ID = "ess0"; - - private static final ChannelAddress STATE_MACHINE = new ChannelAddress(CTRL_ID, "StateMachine"); - private static final ChannelAddress ESS_SET_ACTIVE_POWER_EQUALS = new ChannelAddress(ESS_ID, - "SetActivePowerEquals"); - @Test public void test() throws Exception { new ControllerTest(new ControllerEssLinearPowerBandImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("ess", new DummyManagedSymmetricEss(ESS_ID)) // + .addReference("ess", new DummyManagedSymmetricEss("ess0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setMinPower(-1000) // .setMaxPower(1000) // .setAdjustPower(300) // @@ -32,49 +27,49 @@ public void test() throws Exception { .build()) // .next(new TestCase() // .output(STATE_MACHINE, State.DOWNWARDS) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -300)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -300)) // .next(new TestCase() // .output(STATE_MACHINE, State.DOWNWARDS) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -600)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -600)) // .next(new TestCase() // .output(STATE_MACHINE, State.DOWNWARDS) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -900)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -900)) // .next(new TestCase() // .output(STATE_MACHINE, State.DOWNWARDS) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -1000)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -1000)) // .next(new TestCase() // .output(STATE_MACHINE, State.UPWARDS) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -700)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -700)) // .next(new TestCase() // .output(STATE_MACHINE, State.UPWARDS) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -400)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -400)) // .next(new TestCase() // .output(STATE_MACHINE, State.UPWARDS) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -100)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -100)) // .next(new TestCase() // .output(STATE_MACHINE, State.UPWARDS) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 200)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 200)) // .next(new TestCase() // .output(STATE_MACHINE, State.UPWARDS) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 500)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 500)) // .next(new TestCase() // .output(STATE_MACHINE, State.UPWARDS) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 800)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 800)) // .next(new TestCase() // .output(STATE_MACHINE, State.UPWARDS) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 1000)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 1000)) // .next(new TestCase() // .output(STATE_MACHINE, State.DOWNWARDS) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 700)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 700)) // .next(new TestCase() // .output(STATE_MACHINE, State.DOWNWARDS) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 400)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 400)) // .next(new TestCase() // .output(STATE_MACHINE, State.DOWNWARDS) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 100)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 100)) // .next(new TestCase() // .output(STATE_MACHINE, State.DOWNWARDS) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -200)) // - ; + .output("ess0", SET_ACTIVE_POWER_EQUALS, -200)) // + .deactivate(); } } diff --git a/io.openems.edge.controller.ess.mindischargeperiod/test/io/openems/edge/controller/ess/mindischargeperiod/ControllerEssMinimumDischargePowerImplTest.java b/io.openems.edge.controller.ess.mindischargeperiod/test/io/openems/edge/controller/ess/mindischargeperiod/ControllerEssMinimumDischargePowerImplTest.java index e2a90e1983b..53afa7614c7 100644 --- a/io.openems.edge.controller.ess.mindischargeperiod/test/io/openems/edge/controller/ess/mindischargeperiod/ControllerEssMinimumDischargePowerImplTest.java +++ b/io.openems.edge.controller.ess.mindischargeperiod/test/io/openems/edge/controller/ess/mindischargeperiod/ControllerEssMinimumDischargePowerImplTest.java @@ -7,21 +7,18 @@ public class ControllerEssMinimumDischargePowerImplTest { - private static final String CTRL_ID = "ctrl0"; - private static final String ESS_ID = "ess0"; - @Test public void test() throws Exception { new ControllerTest(new ControllerEssMinimumDischargePowerImpl()) // .addReference("componentManager", new DummyComponentManager()) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setActivateDischargePower(0) // .setDischargeTime(0) // .setMinDischargePower(0) // - .build()); // - ; + .build()) // + .deactivate(); } } diff --git a/io.openems.edge.controller.ess.reactivepowervoltagecharacteristic/test/io/openems/edge/controller/ess/reactivepowervoltagecharacteristic/ControllerEssReactivePowerVoltageCharacteristicImplTest.java b/io.openems.edge.controller.ess.reactivepowervoltagecharacteristic/test/io/openems/edge/controller/ess/reactivepowervoltagecharacteristic/ControllerEssReactivePowerVoltageCharacteristicImplTest.java index 1b4492ede55..442be9ddfa2 100644 --- a/io.openems.edge.controller.ess.reactivepowervoltagecharacteristic/test/io/openems/edge/controller/ess/reactivepowervoltagecharacteristic/ControllerEssReactivePowerVoltageCharacteristicImplTest.java +++ b/io.openems.edge.controller.ess.reactivepowervoltagecharacteristic/test/io/openems/edge/controller/ess/reactivepowervoltagecharacteristic/ControllerEssReactivePowerVoltageCharacteristicImplTest.java @@ -1,14 +1,15 @@ package io.openems.edge.controller.ess.reactivepowervoltagecharacteristic; -import java.time.Instant; -import java.time.ZoneOffset; -import java.time.temporal.ChronoUnit; +import static io.openems.common.utils.JsonUtils.buildJsonArray; +import static io.openems.common.utils.JsonUtils.buildJsonObject; +import static io.openems.edge.common.test.TestUtils.createDummyClock; +import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.SET_REACTIVE_POWER_EQUALS; +import static io.openems.edge.ess.api.SymmetricEss.ChannelId.MAX_APPARENT_POWER; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.VOLTAGE; +import static java.time.temporal.ChronoUnit.SECONDS; import org.junit.Test; -import io.openems.common.test.TimeLeapClock; -import io.openems.common.types.ChannelAddress; -import io.openems.common.utils.JsonUtils; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.common.test.DummyConfigurationAdmin; @@ -18,86 +19,79 @@ public class ControllerEssReactivePowerVoltageCharacteristicImplTest { - private static final String CTRL_ID = "ctrlReactivePowerVoltageCharacteristic0"; - private static final String ESS_ID = "ess0"; - private static final String METER_ID = "meter0"; - private static final ChannelAddress ESS_REACTIVE_POWER = new ChannelAddress(ESS_ID, "SetReactivePowerEquals"); - private static final ChannelAddress METER_VOLTAGE = new ChannelAddress(METER_ID, "Voltage"); - private static final ChannelAddress MAX_APPARENT_POWER = new ChannelAddress(ESS_ID, "MaxApparentPower"); - @Test public void test() throws Exception { - final var clock = new TimeLeapClock(Instant.parse("2020-10-05T14:00:00.00Z"), ZoneOffset.UTC); + final var clock = createDummyClock(); new ControllerTest(new ControllerEssReactivePowerVoltageCharacteristicImpl())// .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager(clock)) // - .addReference("meter", new DummyElectricityMeter(METER_ID)) // - .addReference("ess", new DummyManagedSymmetricEss(ESS_ID)) // + .addReference("meter", new DummyElectricityMeter("meter0")) // + .addReference("ess", new DummyManagedSymmetricEss("ess0")) // .activate(MyConfig.create()// - .setId(CTRL_ID)// - .setEssId(ESS_ID)// - .setMeterId(METER_ID)// + .setId("ctrl0")// + .setEssId("ess0")// + .setMeterId("meter0")// .setNominalVoltage(240)// .setWaitForHysteresis(5)// - .setPowerVoltConfig(JsonUtils.buildJsonArray()// - .add(JsonUtils.buildJsonObject()// + .setPowerVoltConfig(buildJsonArray()// + .add(buildJsonObject()// .addProperty("voltageRatio", 0.9) // .addProperty("percent", 60) // .build()) // - .add(JsonUtils.buildJsonObject()// + .add(buildJsonObject()// .addProperty("voltageRatio", 0.93) // .addProperty("percent", 0) // .build()) // - .add(JsonUtils.buildJsonObject()// + .add(buildJsonObject()// .addProperty("voltageRatio", 1.07) // .addProperty("percent", 0) // .build()) // - .add(JsonUtils.buildJsonObject()// + .add(buildJsonObject()// .addProperty("voltageRatio", 1.1) // .addProperty("percent", -60) // .build() // ).build().toString() // ).build()) // .next(new TestCase("First Input") // - .input(METER_VOLTAGE, 240_000) // [mV] - .input(MAX_APPARENT_POWER, 10_000)) // [VA] + .input("meter0", VOLTAGE, 240_000) // [mV] + .input("ess0", MAX_APPARENT_POWER, 10_000)) // [VA] .next(new TestCase() // - .output(ESS_REACTIVE_POWER, 0))// + .output("ess0", SET_REACTIVE_POWER_EQUALS, 0))// .next(new TestCase("Second Input") // - .timeleap(clock, 5, ChronoUnit.SECONDS)// - .input(METER_VOLTAGE, 216_000) // [mV] - .input(MAX_APPARENT_POWER, 10_000) // [VA] - .output(ESS_REACTIVE_POWER, 6000))// + .timeleap(clock, 5, SECONDS)// + .input("meter0", VOLTAGE, 216_000) // [mV] + .input("ess0", MAX_APPARENT_POWER, 10_000) // [VA] + .output("ess0", SET_REACTIVE_POWER_EQUALS, 6000))// .next(new TestCase("Third Input")// - .timeleap(clock, 5, ChronoUnit.SECONDS)// - .input(METER_VOLTAGE, 220_000) // [mV] - .input(MAX_APPARENT_POWER, 10_000) // [VA] - .output(ESS_REACTIVE_POWER, 2600))// + .timeleap(clock, 5, SECONDS)// + .input("meter0", VOLTAGE, 220_000) // [mV] + .input("ess0", MAX_APPARENT_POWER, 10_000) // [VA] + .output("ess0", SET_REACTIVE_POWER_EQUALS, 2600))// .next(new TestCase()// - .timeleap(clock, 5, ChronoUnit.SECONDS)// - .input(METER_VOLTAGE, 223_000) // [mV] - .input(MAX_APPARENT_POWER, 10_000) // [VA] - .output(ESS_REACTIVE_POWER, 100))// + .timeleap(clock, 5, SECONDS)// + .input("meter0", VOLTAGE, 223_000) // [mV] + .input("ess0", MAX_APPARENT_POWER, 10_000) // [VA] + .output("ess0", SET_REACTIVE_POWER_EQUALS, 100))// .next(new TestCase()// - .timeleap(clock, 5, ChronoUnit.SECONDS)// - .input(METER_VOLTAGE, 223_200) // [mV] - .input(MAX_APPARENT_POWER, 10_000) // [VA] - .output(ESS_REACTIVE_POWER, 0))// + .timeleap(clock, 5, SECONDS)// + .input("meter0", VOLTAGE, 223_200) // [mV] + .input("ess0", MAX_APPARENT_POWER, 10_000) // [VA] + .output("ess0", SET_REACTIVE_POWER_EQUALS, 0))// .next(new TestCase()// - .timeleap(clock, 5, ChronoUnit.SECONDS)// - .input(METER_VOLTAGE, 256_800) // [mV] - .input(MAX_APPARENT_POWER, 10_000) // [VA] - .output(ESS_REACTIVE_POWER, 0))// + .timeleap(clock, 5, SECONDS)// + .input("meter0", VOLTAGE, 256_800) // [mV] + .input("ess0", MAX_APPARENT_POWER, 10_000) // [VA] + .output("ess0", SET_REACTIVE_POWER_EQUALS, 0))// .next(new TestCase()// - .timeleap(clock, 5, ChronoUnit.SECONDS)// - .input(METER_VOLTAGE, 260_000) // [mV] - .input(MAX_APPARENT_POWER, 10_000) // [VA] - .output(ESS_REACTIVE_POWER, -2600))// + .timeleap(clock, 5, SECONDS)// + .input("meter0", VOLTAGE, 260_000) // [mV] + .input("ess0", MAX_APPARENT_POWER, 10_000) // [VA] + .output("ess0", SET_REACTIVE_POWER_EQUALS, -2600))// .next(new TestCase()// - .timeleap(clock, 5, ChronoUnit.SECONDS)// - .input(METER_VOLTAGE, 264_000) // [mV] - .input(MAX_APPARENT_POWER, 10_000) // [VA] - .output(ESS_REACTIVE_POWER, -6000))// - ; + .timeleap(clock, 5, SECONDS)// + .input("meter0", VOLTAGE, 264_000) // [mV] + .input("ess0", MAX_APPARENT_POWER, 10_000) // [VA] + .output("ess0", SET_REACTIVE_POWER_EQUALS, -6000)) // + .deactivate(); } } diff --git a/io.openems.edge.controller.ess.selltogridlimit/test/io/openems/edge/controller/symmetric/selltogridlimit/ControllerEssSellToGridLimitImplTest.java b/io.openems.edge.controller.ess.selltogridlimit/test/io/openems/edge/controller/symmetric/selltogridlimit/ControllerEssSellToGridLimitImplTest.java index 5c191d0c4f5..0870799ee2a 100644 --- a/io.openems.edge.controller.ess.selltogridlimit/test/io/openems/edge/controller/symmetric/selltogridlimit/ControllerEssSellToGridLimitImplTest.java +++ b/io.openems.edge.controller.ess.selltogridlimit/test/io/openems/edge/controller/symmetric/selltogridlimit/ControllerEssSellToGridLimitImplTest.java @@ -1,47 +1,39 @@ package io.openems.edge.controller.symmetric.selltogridlimit; +import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_LESS_OR_EQUALS; + import org.junit.Test; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyConfigurationAdmin; import io.openems.edge.controller.test.ControllerTest; +import io.openems.edge.ess.api.SymmetricEss; import io.openems.edge.ess.test.DummyManagedSymmetricEss; +import io.openems.edge.meter.api.ElectricityMeter; import io.openems.edge.meter.test.DummyElectricityMeter; public class ControllerEssSellToGridLimitImplTest { - private static final String CTRL_ID = "ctrl0"; - - private static final String ESS_ID = "ess0"; - - private static final ChannelAddress ESS_ACTIVE_POWER = new ChannelAddress(ESS_ID, "ActivePower"); - private static final ChannelAddress ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS = new ChannelAddress(ESS_ID, - "SetActivePowerLessOrEquals"); - - private static final String METER_ID = "meter00"; - - private static final ChannelAddress METER_ACTIVE_POWER = new ChannelAddress(METER_ID, "ActivePower"); - @Test public void test() throws Exception { new ControllerTest(new ControllerEssSellToGridLimitImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("ess", new DummyManagedSymmetricEss(ESS_ID)) // - .addReference("meter", new DummyElectricityMeter(METER_ID)) // + .addReference("ess", new DummyManagedSymmetricEss("ess0")) // + .addReference("meter", new DummyElectricityMeter("meter0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // - .setMeterId(METER_ID) // + .setId("ctrl0") // + .setEssId("ess0") // + .setMeterId("meter0") // .setMaximumSellToGridPower(5000) // .build()) // .next(new TestCase() // - .input(METER_ACTIVE_POWER, -5000) // - .input(ESS_ACTIVE_POWER, 3000) // - .output(ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS, null)) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, -5000) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 3000) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, null)) // .next(new TestCase() // - .input(METER_ACTIVE_POWER, -6000) // - .input(ESS_ACTIVE_POWER, 3000) // - .output(ESS_SET_ACTIVE_POWER_LESS_OR_EQUALS, 2000)); + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, -6000) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 3000) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 2000)) // + .deactivate(); } } \ No newline at end of file diff --git a/io.openems.edge.controller.ess.standby/test/io/openems/edge/controller/ess/standby/ControllerEssStandbyImplTest.java b/io.openems.edge.controller.ess.standby/test/io/openems/edge/controller/ess/standby/ControllerEssStandbyImplTest.java index 6f3053a0b16..ac45a6cbb7e 100644 --- a/io.openems.edge.controller.ess.standby/test/io/openems/edge/controller/ess/standby/ControllerEssStandbyImplTest.java +++ b/io.openems.edge.controller.ess.standby/test/io/openems/edge/controller/ess/standby/ControllerEssStandbyImplTest.java @@ -1,5 +1,15 @@ package io.openems.edge.controller.ess.standby; +import static io.openems.edge.common.sum.Sum.ChannelId.CONSUMPTION_ACTIVE_POWER; +import static io.openems.edge.common.sum.Sum.ChannelId.GRID_ACTIVE_POWER; +import static io.openems.edge.common.sum.Sum.ChannelId.PRODUCTION_ACTIVE_POWER; +import static io.openems.edge.controller.ess.standby.ControllerEssStandby.ChannelId.STATE_MACHINE; +import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.ALLOWED_CHARGE_POWER; +import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_EQUALS; +import static io.openems.edge.ess.api.SymmetricEss.ChannelId.ACTIVE_POWER; +import static java.time.temporal.ChronoUnit.HOURS; +import static java.time.temporal.ChronoUnit.MINUTES; + import java.time.DayOfWeek; import java.time.ZoneId; import java.time.ZonedDateTime; @@ -9,10 +19,8 @@ import org.junit.Test; import io.openems.common.test.TimeLeapClock; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.sum.DummySum; import io.openems.edge.common.sum.GridMode; -import io.openems.edge.common.sum.Sum; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.controller.ess.standby.statemachine.StateMachine.State; @@ -23,23 +31,6 @@ public class ControllerEssStandbyImplTest { private static final int MAX_APPARENT_POWER = 50_000; // [W] - private static final String CTRL_ID = "ctrlEssStandby0"; - private static final ChannelAddress STATE_MACHINE = new ChannelAddress(CTRL_ID, "StateMachine"); - - private static final String SUM_ID = Sum.SINGLETON_COMPONENT_ID; - private static final ChannelAddress SUM_GRID_ACTIVE_POWER = new ChannelAddress(SUM_ID, "GridActivePower"); - private static final ChannelAddress SUM_PRODUCTION_ACTIVE_POWER = new ChannelAddress(SUM_ID, - "ProductionActivePower"); - private static final ChannelAddress SUM_CONSUMPTION_ACTIVE_POWER = new ChannelAddress(SUM_ID, - "ConsumptionActivePower"); - - private static final String ESS_ID = "ess0"; - private static final ChannelAddress ESS_ACTIVE_POWER = new ChannelAddress(ESS_ID, "ActivePower"); - private static final ChannelAddress ESS_SET_ACTIVE_POWER_EQUALS = new ChannelAddress(ESS_ID, - "SetActivePowerEquals"); - private static final ChannelAddress ESS_ALLOWED_CHARGE_POWER = new ChannelAddress(ESS_ID, "AllowedChargePower"); - - // Initialize mocked Clock private static TimeLeapClock clock; @Before @@ -49,7 +40,7 @@ public void initialize() { private static ControllerTest tillDischarge() throws Exception { // Initialize ESS - final var ess = new DummyManagedSymmetricEss(ESS_ID) // + final var ess = new DummyManagedSymmetricEss("ess0") // .withGridMode(GridMode.ON_GRID) // .withMaxApparentPower(MAX_APPARENT_POWER) // .withSoc(70); @@ -59,8 +50,8 @@ private static ControllerTest tillDischarge() throws Exception { .addReference("sum", new DummySum()) // .addComponent(ess) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setStartDate("01.02.2020") // .setEndDate("01.03.2020") // .setDayOfWeek(DayOfWeek.SUNDAY) // @@ -68,7 +59,7 @@ private static ControllerTest tillDischarge() throws Exception { .next(new TestCase() // .output(STATE_MACHINE, State.UNDEFINED)) // .next(new TestCase("1 second before midnight (friday) before 01.02.2020") // - .timeleap(clock, 10, ChronoUnit.MINUTES) // + .timeleap(clock, 10, MINUTES) // .output(STATE_MACHINE, State.UNDEFINED)) // .next(new TestCase("midnight (saturday)") // .timeleap(clock, 1, ChronoUnit.SECONDS) // @@ -80,113 +71,117 @@ private static ControllerTest tillDischarge() throws Exception { * DISCHARGE */ .next(new TestCase("sunday -> switch to DISCHARGE") // - .input(SUM_GRID_ACTIVE_POWER, 10_000 /* buy from grid */) // - .input(ESS_ACTIVE_POWER, 100 /* discharge */) // + .input(GRID_ACTIVE_POWER, 10_000 /* buy from grid */) // + .input("ess0", ACTIVE_POWER, 100 /* discharge */) // .output(STATE_MACHINE, State.DISCHARGE) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 10_100)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 10_100)) // .next(new TestCase("discharge > 70 % of maxApparentPower") // - .timeleap(clock, 30, ChronoUnit.MINUTES) // - .input(SUM_GRID_ACTIVE_POWER, 29_900 /* buy from grid */) // - .input(ESS_ACTIVE_POWER, 10_100 /* discharge */) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 40_000)) // + .timeleap(clock, 30, MINUTES) // + .input(GRID_ACTIVE_POWER, 29_900 /* buy from grid */) // + .input("ess0", ACTIVE_POWER, 10_100 /* discharge */) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 40_000)) // .next(new TestCase("discharge > 70 % of maxApparentPower - 9 minutes") // - .timeleap(clock, 9, ChronoUnit.MINUTES) // - .input(SUM_GRID_ACTIVE_POWER, 0 /* buy from grid */) // - .input(ESS_ACTIVE_POWER, 40_000 /* discharge */) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 40_000)) // + .timeleap(clock, 9, MINUTES) // + .input(GRID_ACTIVE_POWER, 0 /* buy from grid */) // + .input("ess0", ACTIVE_POWER, 40_000 /* discharge */) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 40_000)) // .next(new TestCase("discharge > 70 % of maxApparentPower - 10 minutes: reduce to 50 %") // - .timeleap(clock, 1, ChronoUnit.MINUTES) // - .input(SUM_GRID_ACTIVE_POWER, 0 /* buy from grid */) // - .input(ESS_ACTIVE_POWER, 40_000 /* discharge */) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, (int) (MAX_APPARENT_POWER * 0.5))) + .timeleap(clock, 1, MINUTES) // + .input(GRID_ACTIVE_POWER, 0 /* buy from grid */) // + .input("ess0", ACTIVE_POWER, 40_000 /* discharge */) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, (int) (MAX_APPARENT_POWER * 0.5))) .next(new TestCase("do not charge") // - .timeleap(clock, 1, ChronoUnit.MINUTES) // - .input(SUM_GRID_ACTIVE_POWER, -100 /* buy from grid */) // - .input(ESS_ACTIVE_POWER, 0 /* discharge */) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 0)); + .timeleap(clock, 1, MINUTES) // + .input(GRID_ACTIVE_POWER, -100 /* buy from grid */) // + .input("ess0", ACTIVE_POWER, 0 /* discharge */) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 0)) // + .deactivate(); } private static ControllerTest tillSlowCharge1_1() throws Exception { return tillDischarge() // .next(new TestCase("production > consumption") // - .input(SUM_GRID_ACTIVE_POWER, 0 /* buy from grid */) // - .input(SUM_PRODUCTION_ACTIVE_POWER, 1000) // - .input(SUM_CONSUMPTION_ACTIVE_POWER, 999) // - .input(ESS_ACTIVE_POWER, 10_000 /* discharge */) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 10_000)) // + .input(GRID_ACTIVE_POWER, 0 /* buy from grid */) // + .input(PRODUCTION_ACTIVE_POWER, 1000) // + .input(CONSUMPTION_ACTIVE_POWER, 999) // + .input("ess0", ACTIVE_POWER, 10_000 /* discharge */) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 10_000)) // .next(new TestCase("production > consumption: more than 1 minute -> SLOW_CHARGE") // - .timeleap(clock, 1, ChronoUnit.MINUTES) // - .input(SUM_GRID_ACTIVE_POWER, 0 /* buy from grid */) // - .input(SUM_PRODUCTION_ACTIVE_POWER, 1000) // - .input(SUM_CONSUMPTION_ACTIVE_POWER, 999)) // + .timeleap(clock, 1, MINUTES) // + .input(GRID_ACTIVE_POWER, 0 /* buy from grid */) // + .input(PRODUCTION_ACTIVE_POWER, 1000) // + .input(CONSUMPTION_ACTIVE_POWER, 999)) // /* * SLOW_CHARGE */ .next(new TestCase("SLOW_CHARGE") // - .output(STATE_MACHINE, State.SLOW_CHARGE_1)); // + .output(STATE_MACHINE, State.SLOW_CHARGE_1)) // + .deactivate(); } private static ControllerTest tillSlowCharge1_2() throws Exception { return tillDischarge() // .next(new TestCase("latest at 12 -> SLOW_CHARGE") // - .timeleap(clock, 12, ChronoUnit.HOURS)) // + .timeleap(clock, 12, HOURS)) // /* * SLOW_CHARGE */ .next(new TestCase("SLOW_CHARGE") // - .output(STATE_MACHINE, State.SLOW_CHARGE_1)); // + .output(STATE_MACHINE, State.SLOW_CHARGE_1)) // + .deactivate(); } private static ControllerTest tillSlowCharge2_1() throws Exception { return tillSlowCharge1_2() // .next(new TestCase("") // - .input(ESS_ACTIVE_POWER, 0) // - .input(SUM_GRID_ACTIVE_POWER, -20_000 /* sell to grid */) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -20_000)) // + .input("ess0", ACTIVE_POWER, 0) // + .input(GRID_ACTIVE_POWER, -20_000 /* sell to grid */) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -20_000)) // .next(new TestCase("Charge with minimum 20 %") // - .input(ESS_ACTIVE_POWER, 0) // - .input(SUM_GRID_ACTIVE_POWER, (int) (MAX_APPARENT_POWER * -0.19) /* sell to grid */) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, (int) (MAX_APPARENT_POWER * -0.20))) // + .input("ess0", ACTIVE_POWER, 0) // + .input(GRID_ACTIVE_POWER, (int) (MAX_APPARENT_POWER * -0.19)) // sell to grid + .output("ess0", SET_ACTIVE_POWER_EQUALS, (int) (MAX_APPARENT_POWER * -0.20))) // .next(new TestCase("Charge with maximum 50 %") // - .input(ESS_ACTIVE_POWER, 0) // - .input(SUM_GRID_ACTIVE_POWER, (int) (MAX_APPARENT_POWER * -0.51) /* sell to grid */) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, (int) (MAX_APPARENT_POWER * -0.50))) // + .input("ess0", ACTIVE_POWER, 0) // + .input(GRID_ACTIVE_POWER, (int) (MAX_APPARENT_POWER * -0.51)) // sell to grid + .output("ess0", SET_ACTIVE_POWER_EQUALS, (int) (MAX_APPARENT_POWER * -0.50))) // .next(new TestCase("after 30 minutes -> FAST_CHARGE") // - .timeleap(clock, 30, ChronoUnit.MINUTES)) // + .timeleap(clock, 30, MINUTES)) // /* * FAST_CHARGE */ .next(new TestCase("FAST_CHARGE with max power") // .output(STATE_MACHINE, State.FAST_CHARGE) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, MAX_APPARENT_POWER * -1)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, MAX_APPARENT_POWER * -1)) // .next(new TestCase("after 10 minutes -> SLOW_CHARGE_2") // - .timeleap(clock, 10, ChronoUnit.MINUTES)) // + .timeleap(clock, 10, MINUTES)) // /* * SLOW_CHARGE_2 */ .next(new TestCase("SLOW_CHARGE_2") // - .input(ESS_ACTIVE_POWER, 0) // - .input(ESS_ALLOWED_CHARGE_POWER, -60_000) // - .input(SUM_GRID_ACTIVE_POWER, -20_000 /* sell to grid */) // + .input("ess0", ACTIVE_POWER, 0) // + .input("ess0", ALLOWED_CHARGE_POWER, -60_000) // + .input(GRID_ACTIVE_POWER, -20_000 /* sell to grid */) // .output(STATE_MACHINE, State.SLOW_CHARGE_2) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -20_000)) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -20_000)) // /* * FINISHED */ .next(new TestCase("no more charging allowed -> FINISHED") // - .input(ESS_ALLOWED_CHARGE_POWER, 0)) // + .input("ess0", ALLOWED_CHARGE_POWER, 0)) // .next(new TestCase("FINISHED") // .output(STATE_MACHINE, State.FINISHED)) // /* * UNDEFINED */ .next(new TestCase("on day change -> UNDEFINED") // - .timeleap(clock, 11, ChronoUnit.HOURS)) // + .timeleap(clock, 11, HOURS)) // .next(new TestCase("UNDEFINED") // .output(STATE_MACHINE, State.UNDEFINED)) // .next(new TestCase("After test period") // .timeleap(clock, 30, ChronoUnit.DAYS) // - .output(STATE_MACHINE, State.UNDEFINED)); // + .output(STATE_MACHINE, State.UNDEFINED)) // + .deactivate(); } @Test diff --git a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImplTest.java b/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImplTest.java index d3f32289678..a0623215e0f 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImplTest.java +++ b/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImplTest.java @@ -1,16 +1,14 @@ package io.openems.edge.controller.ess.timeofusetariff; +import static io.openems.edge.common.test.TestUtils.createDummyClock; import static io.openems.edge.controller.ess.timeofusetariff.ControlMode.CHARGE_CONSUMPTION; import static io.openems.edge.controller.ess.timeofusetariff.Mode.AUTOMATIC; import static io.openems.edge.controller.ess.timeofusetariff.RiskLevel.MEDIUM; import java.time.Clock; -import java.time.Instant; -import java.time.ZoneOffset; import org.junit.Test; -import io.openems.common.test.TimeLeapClock; import io.openems.edge.common.sum.DummySum; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; @@ -22,13 +20,11 @@ public class TimeOfUseTariffControllerImplTest { - public static final Clock CLOCK = new TimeLeapClock(Instant.parse("2020-03-04T14:19:00.00Z"), ZoneOffset.UTC); - - private static final String CTRL_ID = "ctrl0"; - @Test public void test() throws Exception { - create(CLOCK); + final var clock = createDummyClock(); + create(clock) // + .deactivate(); } /** @@ -54,7 +50,7 @@ public static TimeOfUseTariffControllerImpl create(Clock clock) throws Exception .withSoc(60) // .withCapacity(10000)) // .activate(MyConfig.create() // - .setId(CTRL_ID) // + .setId("ctrl0") // .setEnabled(false) // .setEssId("ess0") // .setMode(AUTOMATIC) // diff --git a/io.openems.edge.controller.evcs.fixactivepower/bnd.bnd b/io.openems.edge.controller.evcs.fixactivepower/bnd.bnd index 98e4180dcd7..ba83284def5 100644 --- a/io.openems.edge.controller.evcs.fixactivepower/bnd.bnd +++ b/io.openems.edge.controller.evcs.fixactivepower/bnd.bnd @@ -8,7 +8,8 @@ Bundle-Version: 1.0.0.${tstamp} io.openems.common,\ io.openems.edge.common,\ io.openems.edge.controller.api,\ - io.openems.edge.evcs.api + io.openems.edge.evcs.api,\ + io.openems.edge.meter.api,\ -testpath: \ ${testpath} diff --git a/io.openems.edge.controller.evcs.fixactivepower/test/io/openems/edge/controller/evcs/fixactivepower/ControllerEvcsFixActivePowerImplTest.java b/io.openems.edge.controller.evcs.fixactivepower/test/io/openems/edge/controller/evcs/fixactivepower/ControllerEvcsFixActivePowerImplTest.java index e3f8ed55368..85c46e49269 100644 --- a/io.openems.edge.controller.evcs.fixactivepower/test/io/openems/edge/controller/evcs/fixactivepower/ControllerEvcsFixActivePowerImplTest.java +++ b/io.openems.edge.controller.evcs.fixactivepower/test/io/openems/edge/controller/evcs/fixactivepower/ControllerEvcsFixActivePowerImplTest.java @@ -7,19 +7,16 @@ public class ControllerEvcsFixActivePowerImplTest { - private static final String CTRL_ID = "ctrl0"; - private static final String EVCS_ID = "evcs0"; - @Test public void test() throws Exception { new ControllerTest(new ControllerEvcsFixActivePowerImpl()) // .addReference("componentManager", new DummyComponentManager()) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEvcsId(EVCS_ID) // + .setId("ctrl0") // + .setEvcsId("evcs0") // .setPower(0) // .setUpdateFrequency(1) // - .build()); // - ; + .build()) // + .deactivate(); } } diff --git a/io.openems.edge.controller.evcs/bnd.bnd b/io.openems.edge.controller.evcs/bnd.bnd index c3a69ba9f20..e0be766da07 100644 --- a/io.openems.edge.controller.evcs/bnd.bnd +++ b/io.openems.edge.controller.evcs/bnd.bnd @@ -9,7 +9,8 @@ Bundle-Version: 1.0.0.${tstamp} io.openems.edge.common,\ io.openems.edge.controller.api,\ io.openems.edge.ess.api,\ - io.openems.edge.evcs.api + io.openems.edge.evcs.api,\ + io.openems.edge.meter.api,\ -testpath: \ ${testpath} diff --git a/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/ChargingLowerThanTargetHandler.java b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/ChargingLowerThanTargetHandler.java index 418c50c5e0d..f052d2615bd 100644 --- a/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/ChargingLowerThanTargetHandler.java +++ b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/ChargingLowerThanTargetHandler.java @@ -64,7 +64,7 @@ protected boolean isLower(ManagedEvcs evcs) throws InvalidValueException { * @throws InvalidValueException invalidValueException */ protected boolean isChargingLowerThanTarget(ManagedEvcs evcs) throws InvalidValueException { - int chargePower = evcs.getChargePower().orElse(0); + int chargePower = evcs.getActivePower().orElse(0); int chargePowerTarget = evcs.getSetChargePowerLimit().orElse(evcs.getMaximumHardwarePower().getOrError()); if (chargePowerTarget - chargePower > chargePowerTarget * CHARGING_TARGET_MAX_DIFFERENCE_PERCENT) { diff --git a/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/ControllerEvcsImpl.java b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/ControllerEvcsImpl.java index 69e67eae105..4a1d1dd5653 100644 --- a/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/ControllerEvcsImpl.java +++ b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/ControllerEvcsImpl.java @@ -193,7 +193,7 @@ public void run() throws OpenemsNamedException { */ if (nextChargePower != 0) { - int chargePower = this.evcs.getChargePower().orElse(0); + int activePower = this.evcs.getActivePower().orElse(0); /** * Check the difference of the current charge power and the previous charging @@ -211,10 +211,10 @@ public void run() throws OpenemsNamedException { int currMax = this.evcs.getMaximumPower().orElse(0); /** - * If the charge power would increases again above the current maximum power, it - * resets the maximum Power. + * If the power would increases again above the current maximum power, it resets + * the maximum Power. */ - if (chargePower > currMax * (1 + DEFAULT_UPPER_TARGET_DIFFERENCE_PERCENT)) { + if (activePower > currMax * (1 + DEFAULT_UPPER_TARGET_DIFFERENCE_PERCENT)) { this.evcs._setMaximumPower(null); } } @@ -271,7 +271,7 @@ private void adaptConfigToHardwareLimits() { private static int calculateChargePowerFromExcessPower(Sum sum, ManagedEvcs evcs) throws OpenemsNamedException { int buyFromGrid = sum.getGridActivePower().orElse(0); int essDischarge = sum.getEssDischargePower().orElse(0); - int evcsCharge = evcs.getChargePower().orElse(0); + int evcsCharge = evcs.getActivePower().orElse(0); return evcsCharge - buyFromGrid - essDischarge; } @@ -285,7 +285,7 @@ private static int calculateChargePowerFromExcessPower(Sum sum, ManagedEvcs evcs */ private static int calculateExcessPowerAfterEss(Sum sum, ManagedEvcs evcs) { int buyFromGrid = sum.getGridActivePower().orElse(0); - int evcsCharge = evcs.getChargePower().orElse(0); + int evcsCharge = evcs.getActivePower().orElse(0); var result = evcsCharge - buyFromGrid; diff --git a/io.openems.edge.controller.evcs/test/io/openems/edge/controller/evcs/ControllerEvcsImplTest.java b/io.openems.edge.controller.evcs/test/io/openems/edge/controller/evcs/ControllerEvcsImplTest.java index 960a2c5789c..b946f3090e8 100644 --- a/io.openems.edge.controller.evcs/test/io/openems/edge/controller/evcs/ControllerEvcsImplTest.java +++ b/io.openems.edge.controller.evcs/test/io/openems/edge/controller/evcs/ControllerEvcsImplTest.java @@ -1,21 +1,30 @@ package io.openems.edge.controller.evcs; +import static io.openems.edge.common.sum.Sum.ChannelId.ESS_DISCHARGE_POWER; +import static io.openems.edge.common.sum.Sum.ChannelId.ESS_SOC; +import static io.openems.edge.common.sum.Sum.ChannelId.GRID_ACTIVE_POWER; +import static io.openems.edge.common.test.TestUtils.createDummyClock; +import static io.openems.edge.controller.evcs.ControllerEvcs.ChannelId.AWAITING_HYSTERESIS; +import static io.openems.edge.controller.evcs.Priority.CAR; +import static io.openems.edge.evcs.api.ChargeMode.EXCESS_POWER; +import static io.openems.edge.evcs.api.ChargeMode.FORCE_CHARGE; +import static io.openems.edge.evcs.api.Evcs.ChannelId.MAXIMUM_HARDWARE_POWER; +import static io.openems.edge.evcs.api.Evcs.ChannelId.MAXIMUM_POWER; +import static io.openems.edge.evcs.api.Evcs.ChannelId.STATUS; +import static io.openems.edge.evcs.api.ManagedEvcs.ChannelId.IS_CLUSTERED; +import static io.openems.edge.evcs.api.ManagedEvcs.ChannelId.SET_CHARGE_POWER_LIMIT; +import static io.openems.edge.evcs.api.ManagedEvcs.ChannelId.SET_CHARGE_POWER_REQUEST; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.ACTIVE_POWER; +import static java.time.temporal.ChronoUnit.MINUTES; import static org.junit.Assert.assertEquals; -import java.time.Instant; -import java.time.ZoneOffset; -import java.time.temporal.ChronoUnit; - import org.junit.Test; -import io.openems.common.test.TimeLeapClock; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.filter.DisabledRampFilter; import io.openems.edge.common.sum.DummySum; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyConfigurationAdmin; import io.openems.edge.controller.test.ControllerTest; -import io.openems.edge.evcs.api.ChargeMode; import io.openems.edge.evcs.api.Evcs; import io.openems.edge.evcs.api.Status; import io.openems.edge.evcs.test.DummyEvcsPower; @@ -26,131 +35,109 @@ public class ControllerEvcsImplTest { private static final DummyEvcsPower EVCS_POWER = new DummyEvcsPower(new DisabledRampFilter()); private static final DummyManagedEvcs EVCS = new DummyManagedEvcs("evcs0", EVCS_POWER); - private static final String EVCS_ID = EVCS.id(); - private static final boolean DEFAULT_ENABLE_CHARGING = true; - private static final ChargeMode DEFAULT_CHARGE_MODE = ChargeMode.EXCESS_POWER; private static final int DEFAULT_FORCE_CHARGE_MIN_POWER = 7360; private static final int DEFAULT_CHARGE_MIN_POWER = 0; - private static final Priority DEFAULT_PRIORITY = Priority.CAR; - private static final int DEFAULT_ENERGY_SESSION_LIMIT = 0; - - private static ChannelAddress sumGridActivePower = new ChannelAddress("_sum", "GridActivePower"); - private static ChannelAddress sumEssDischargePower = new ChannelAddress("_sum", "EssDischargePower"); - private static ChannelAddress sumEssSoc = new ChannelAddress("_sum", "EssSoc"); - private static ChannelAddress evcs0ChargePower = new ChannelAddress("evcs0", "ChargePower"); - private static ChannelAddress evcs0SetChargePowerLimit = new ChannelAddress("evcs0", "SetChargePowerLimit"); - private static ChannelAddress evcs0MaximumPower = new ChannelAddress("evcs0", "MaximumPower"); - private static ChannelAddress evcs0IsClustered = new ChannelAddress("evcs0", "IsClustered"); - private static ChannelAddress evcs0SetPowerRequest = new ChannelAddress("evcs0", "SetChargePowerRequest"); - private static ChannelAddress evcs0Status = new ChannelAddress("evcs0", "Status"); - private static ChannelAddress evcs0MaximumHardwarePower = new ChannelAddress("evcs0", "MaximumHardwarePower"); - private static ChannelAddress evcs0MinimumHardwarePower = new ChannelAddress("evcs0", "MinimumHardwarePower"); - private static ChannelAddress evcsController0AwaitingHysteresis = new ChannelAddress("ctrlEvcs0", - "AwaitingHysteresis"); @Test public void excessChargeTest1() throws Exception { - new ControllerTest(new ControllerEvcsImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // .addReference("evcs", EVCS) // .activate(MyConfig.create() // .setId("ctrlEvcs0") // - .setEvcsId(EVCS_ID) // - .setEnableCharging(DEFAULT_ENABLE_CHARGING) // - .setChargeMode(DEFAULT_CHARGE_MODE) // + .setEvcsId("evcs0") // + .setEnableCharging(true) // + .setChargeMode(EXCESS_POWER) // .setForceChargeMinPower(DEFAULT_FORCE_CHARGE_MIN_POWER) // .setDefaultChargeMinPower(DEFAULT_CHARGE_MIN_POWER) // - .setPriority(DEFAULT_PRIORITY) // - .setEnergySessionLimit(DEFAULT_ENERGY_SESSION_LIMIT) // + .setPriority(CAR) // + .setEnergySessionLimit(0) // .build()) // .next(new TestCase() // - .input(sumEssDischargePower, -6000) // - .input(evcs0IsClustered, false) // - .input(sumGridActivePower, 0) // - .input(evcs0ChargePower, 0) // - .output(evcs0SetChargePowerLimit, 6000)) // - ; + .input(ESS_DISCHARGE_POWER, -6000) // + .input("evcs0", IS_CLUSTERED, false) // + .input(GRID_ACTIVE_POWER, 0) // + .input("evcs0", ACTIVE_POWER, 0) // + .output("evcs0", SET_CHARGE_POWER_LIMIT, 6000)) // + .deactivate(); } @Test public void excessChargeTest2() throws Exception { - - final var test = new ControllerTest(new ControllerEvcsImpl()) // + new ControllerTest(new ControllerEvcsImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // .addReference("evcs", EVCS) // .activate(MyConfig.create() // .setId("ctrlEvcs0") // - .setEvcsId(EVCS_ID) // - .setEnableCharging(DEFAULT_ENABLE_CHARGING) // - .setChargeMode(DEFAULT_CHARGE_MODE) // + .setEvcsId("evcs0") // + .setEnableCharging(true) // + .setChargeMode(EXCESS_POWER) // .setForceChargeMinPower(DEFAULT_FORCE_CHARGE_MIN_POWER) // .setDefaultChargeMinPower(DEFAULT_CHARGE_MIN_POWER) // .setPriority(Priority.STORAGE) // - .setEnergySessionLimit(DEFAULT_ENERGY_SESSION_LIMIT) // - .build()); // - - test.next(new TestCase() // - .input(sumEssSoc, 50) // - .input(sumEssDischargePower, -5000) // - .input(evcs0IsClustered, false) // - .input(sumGridActivePower, -40000) // - .input(evcs0ChargePower, 5000) // - .input(evcs0MaximumHardwarePower, 22080) // - .output(evcs0SetChargePowerLimit, 44800)); + .setEnergySessionLimit(0) // + .build()) // + .next(new TestCase() // + .input(ESS_SOC, 50) // + .input(ESS_DISCHARGE_POWER, -5000) // + .input("evcs0", IS_CLUSTERED, false) // + .input(GRID_ACTIVE_POWER, -40000) // + .input("evcs0", ACTIVE_POWER, 5000) // + .input("evcs0", MAXIMUM_HARDWARE_POWER, 22080) // + .output("evcs0", SET_CHARGE_POWER_LIMIT, 44800)) // + .deactivate(); } @Test public void forceChargeTest() throws Exception { - new ControllerTest(new ControllerEvcsImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // .addReference("evcs", EVCS) // .activate(MyConfig.create() // .setId("ctrlEvcs0") // - .setEvcsId(EVCS_ID) // - .setEnableCharging(DEFAULT_ENABLE_CHARGING) // - .setChargeMode(ChargeMode.FORCE_CHARGE) // + .setEvcsId("evcs0") // + .setEnableCharging(true) // + .setChargeMode(FORCE_CHARGE) // .setForceChargeMinPower(DEFAULT_FORCE_CHARGE_MIN_POWER) // .setDefaultChargeMinPower(DEFAULT_CHARGE_MIN_POWER) // - .setPriority(DEFAULT_PRIORITY) // - .setEnergySessionLimit(DEFAULT_ENERGY_SESSION_LIMIT) // + .setPriority(CAR) // s + .setEnergySessionLimit(0) // .build()) // .next(new TestCase() // - .input(sumEssDischargePower, -5000) // - .input(evcs0IsClustered, false) // - .input(sumGridActivePower, -40000) // - .input(evcs0ChargePower, 5000) // - .output(evcs0SetChargePowerLimit, 22080)); + .input(ESS_DISCHARGE_POWER, -5000) // + .input("evcs0", IS_CLUSTERED, false) // + .input(GRID_ACTIVE_POWER, -40000) // + .input("evcs0", ACTIVE_POWER, 5000) // + .output("evcs0", SET_CHARGE_POWER_LIMIT, 22080)) // + .deactivate(); } @Test public void chargingDisabledTest() throws Exception { - new ControllerTest(new ControllerEvcsImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // .addReference("evcs", EVCS) // .activate(MyConfig.create() // .setId("ctrlEvcs0") // - .setEvcsId(EVCS_ID) // + .setEvcsId("evcs0") // .setEnableCharging(false) // - .setChargeMode(DEFAULT_CHARGE_MODE) // + .setChargeMode(EXCESS_POWER) // .setForceChargeMinPower(DEFAULT_FORCE_CHARGE_MIN_POWER) // .setDefaultChargeMinPower(DEFAULT_CHARGE_MIN_POWER) // - .setPriority(DEFAULT_PRIORITY) // - .setEnergySessionLimit(DEFAULT_ENERGY_SESSION_LIMIT) // + .setPriority(CAR) // + .setEnergySessionLimit(0) // .build()) // .next(new TestCase() // - .output(evcs0SetChargePowerLimit, 0)); + .output("evcs0", SET_CHARGE_POWER_LIMIT, 0)) // + .deactivate(); } @Test public void wrongConfigParametersTest() throws Exception { - var cm = new DummyConfigurationAdmin(); new ControllerTest(new ControllerEvcsImpl()) // .addReference("cm", cm) // @@ -158,16 +145,17 @@ public void wrongConfigParametersTest() throws Exception { .addReference("evcs", EVCS) // .activate(MyConfig.create() // .setId("ctrlEvcs0") // - .setEvcsId(EVCS_ID) // - .setEnableCharging(DEFAULT_ENABLE_CHARGING) // - .setChargeMode(DEFAULT_CHARGE_MODE) // + .setEvcsId("evcs0") // + .setEnableCharging(true) // + .setChargeMode(EXCESS_POWER) // .setForceChargeMinPower(30_000) // .setDefaultChargeMinPower(30_000) // - .setPriority(DEFAULT_PRIORITY) // - .setEnergySessionLimit(DEFAULT_ENERGY_SESSION_LIMIT) // + .setPriority(CAR) // + .setEnergySessionLimit(0) // .build()) // .next(new TestCase() // - .input(evcs0MaximumHardwarePower, 12000)); + .input("evcs0", MAXIMUM_HARDWARE_POWER, 12000)) // + .deactivate(); assertEquals(12000, (int) (Integer) cm.getConfiguration("ctrlEvcs0").getProperties().get("defaultChargeMinPower")); @@ -175,179 +163,174 @@ public void wrongConfigParametersTest() throws Exception { @Test public void clusterTest() throws Exception { - final var clock = new TimeLeapClock(Instant.ofEpochSecond(1577836800) /* starts at 1. January 2020 00:00:00 */, - ZoneOffset.UTC); - + final var clock = createDummyClock(); new ControllerTest(new ControllerEvcsImpl(clock)) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // .addReference("evcs", EVCS) // .activate(MyConfig.create() // .setId("ctrlEvcs0") // - .setEvcsId(EVCS_ID) // - .setEnableCharging(DEFAULT_ENABLE_CHARGING) // - .setChargeMode(DEFAULT_CHARGE_MODE) // + .setEvcsId("evcs0") // + .setEnableCharging(true) // + .setChargeMode(EXCESS_POWER) // .setForceChargeMinPower(3_333) // .setDefaultChargeMinPower(DEFAULT_CHARGE_MIN_POWER) // - .setPriority(DEFAULT_PRIORITY) // - .setEnergySessionLimit(DEFAULT_ENERGY_SESSION_LIMIT) // + .setPriority(CAR) // + .setEnergySessionLimit(0) // .build()) // .next(new TestCase() // - .input(sumEssDischargePower, -10000) // - .input(evcs0IsClustered, true) // - .input(sumGridActivePower, 0) // - .input(evcs0ChargePower, 0) // - .input(evcs0Status, Status.CHARGING) // - .output(evcs0SetPowerRequest, 10000)) + .input(ESS_DISCHARGE_POWER, -10000) // + .input("evcs0", IS_CLUSTERED, true) // + .input(GRID_ACTIVE_POWER, 0) // + .input("evcs0", ACTIVE_POWER, 0) // + .input("evcs0", STATUS, Status.CHARGING) // + .output("evcs0", SET_CHARGE_POWER_REQUEST, 10000)) .next(new TestCase() // - .input(sumEssDischargePower, -6000) // - .input(evcs0IsClustered, true) // - .input(sumGridActivePower, 0) // - .input(evcs0ChargePower, 0) // - .input(evcs0Status, Status.NOT_READY_FOR_CHARGING) // - .output(evcs0SetPowerRequest, 0)) // + .input(ESS_DISCHARGE_POWER, -6000) // + .input("evcs0", IS_CLUSTERED, true) // + .input(GRID_ACTIVE_POWER, 0) // + .input("evcs0", ACTIVE_POWER, 0) // + .input("evcs0", STATUS, Status.NOT_READY_FOR_CHARGING) // + .output("evcs0", SET_CHARGE_POWER_REQUEST, 0)) // f .next(new TestCase() // - .input(sumEssDischargePower, -6000) // - .input(evcs0IsClustered, true) // - .input(sumGridActivePower, 0) // - .input(evcs0ChargePower, 0) // - .input(evcs0Status, null) // - .output(evcs0SetPowerRequest, 0)) // + .input(ESS_DISCHARGE_POWER, -6000) // + .input("evcs0", IS_CLUSTERED, true) // + .input(GRID_ACTIVE_POWER, 0) // + .input("evcs0", ACTIVE_POWER, 0) // + .input("evcs0", STATUS, null) // + .output("evcs0", SET_CHARGE_POWER_REQUEST, 0)) // .next(new TestCase() // - .input(sumEssDischargePower, -6000) // - .input(evcs0IsClustered, true) // - .input(sumGridActivePower, 0) // - .input(evcs0ChargePower, 0) // - .input(evcs0Status, Status.CHARGING_REJECTED) // - .output(evcs0SetPowerRequest, 6000) // - .output(evcs0MaximumPower, null)) // - ; + .input(ESS_DISCHARGE_POWER, -6000) // + .input("evcs0", IS_CLUSTERED, true) // + .input(GRID_ACTIVE_POWER, 0) // + .input("evcs0", ACTIVE_POWER, 0) // + .input("evcs0", STATUS, Status.CHARGING_REJECTED) // + .output("evcs0", SET_CHARGE_POWER_REQUEST, 6000) // + .output("evcs0", MAXIMUM_POWER, null)) // + .deactivate(); } @Test public void clusterTestDisabledCharging() throws Exception { - new ControllerTest(new ControllerEvcsImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // .addReference("evcs", EVCS) // .activate(MyConfig.create() // .setId("ctrlEvcs0") // - .setEvcsId(EVCS_ID) // + .setEvcsId("evcs0") // .setEnableCharging(false) // - .setChargeMode(DEFAULT_CHARGE_MODE) // + .setChargeMode(EXCESS_POWER) // .setForceChargeMinPower(3_333) // .setDefaultChargeMinPower(DEFAULT_CHARGE_MIN_POWER) // - .setPriority(DEFAULT_PRIORITY) // - .setEnergySessionLimit(DEFAULT_ENERGY_SESSION_LIMIT) // + .setPriority(CAR) // + .setEnergySessionLimit(0) // .build()) // .next(new TestCase() // - .input(sumEssDischargePower, -10000) // - .input(evcs0IsClustered, true) // - .input(sumGridActivePower, 0) // - .input(evcs0ChargePower, 0) // - .input(evcs0Status, Status.CHARGING) // - .output(evcs0SetChargePowerLimit, 0)) + .input(ESS_DISCHARGE_POWER, -10000) // + .input("evcs0", IS_CLUSTERED, true) // + .input(GRID_ACTIVE_POWER, 0) // + .input("evcs0", ACTIVE_POWER, 0) // + .input("evcs0", STATUS, Status.CHARGING) // + .output("evcs0", SET_CHARGE_POWER_LIMIT, 0)) .next(new TestCase() // - .input(sumEssDischargePower, -6000) // - .input(evcs0IsClustered, true) // - .input(sumGridActivePower, 0) // - .input(evcs0ChargePower, 0) // - .input(evcs0Status, Status.NOT_READY_FOR_CHARGING) // - .output(evcs0SetChargePowerLimit, 0)) // + .input(ESS_DISCHARGE_POWER, -6000) // + .input("evcs0", IS_CLUSTERED, true) // + .input(GRID_ACTIVE_POWER, 0) // + .input("evcs0", ACTIVE_POWER, 0) // + .input("evcs0", STATUS, Status.NOT_READY_FOR_CHARGING) // + .output("evcs0", SET_CHARGE_POWER_LIMIT, 0)) // .next(new TestCase() // - .input(sumEssDischargePower, -6000) // - .input(evcs0IsClustered, true) // - .input(sumGridActivePower, 0) // - .input(evcs0ChargePower, 0) // - .input(evcs0Status, null) // - .output(evcs0SetChargePowerLimit, 0)) // + .input(ESS_DISCHARGE_POWER, -6000) // + .input("evcs0", IS_CLUSTERED, true) // + .input(GRID_ACTIVE_POWER, 0) // + .input("evcs0", ACTIVE_POWER, 0) // + .input("evcs0", STATUS, null) // + .output("evcs0", SET_CHARGE_POWER_LIMIT, 0)) // .next(new TestCase() // - .input(sumEssDischargePower, -6000) // - .input(evcs0IsClustered, true) // - .input(sumGridActivePower, 0) // - .input(evcs0ChargePower, 0) // - .input(evcs0Status, Status.CHARGING_REJECTED) // - .output(evcs0SetChargePowerLimit, 0) // - .output(evcs0MaximumPower, null)) // - ; + .input(ESS_DISCHARGE_POWER, -6000) // + .input("evcs0", IS_CLUSTERED, true) // + .input(GRID_ACTIVE_POWER, 0) // + .input("evcs0", ACTIVE_POWER, 0) // + .input("evcs0", STATUS, Status.CHARGING_REJECTED) // + .output("evcs0", SET_CHARGE_POWER_LIMIT, 0) // + .output("evcs0", MAXIMUM_POWER, null)) // + .deactivate(); } @Test public void hysteresisTest() throws Exception { - - final var clock = new TimeLeapClock(Instant.ofEpochSecond(1577836800) /* starts at 1. January 2020 00:00:00 */, - ZoneOffset.UTC); - + final var clock = createDummyClock(); new ControllerTest(new ControllerEvcsImpl(clock)) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // .addReference("evcs", EVCS) // .activate(MyConfig.create() // .setId("ctrlEvcs0") // - .setEvcsId(EVCS_ID) // - .setEnableCharging(DEFAULT_ENABLE_CHARGING) // - .setChargeMode(DEFAULT_CHARGE_MODE) // + .setEvcsId("evcs0") // + .setEnableCharging(true) // + .setChargeMode(EXCESS_POWER) // .setForceChargeMinPower(DEFAULT_FORCE_CHARGE_MIN_POWER) // .setDefaultChargeMinPower(DEFAULT_CHARGE_MIN_POWER) // - .setPriority(DEFAULT_PRIORITY) // - .setEnergySessionLimit(DEFAULT_ENERGY_SESSION_LIMIT) // + .setPriority(CAR) // + .setEnergySessionLimit(0) // .setExcessChargeHystersis(120) // .setExcessChargePauseHysteresis(30) // .build()) // .next(new TestCase() // - .input(sumEssDischargePower, 0) // - .input(evcs0IsClustered, false) // - .input(sumGridActivePower, -6_000) // - .input(evcs0ChargePower, 0) // - .output(evcs0SetChargePowerLimit, 6_000)) // + .input(ESS_DISCHARGE_POWER, 0) // + .input("evcs0", IS_CLUSTERED, false) // + .input(GRID_ACTIVE_POWER, -6_000) // + .input("evcs0", ACTIVE_POWER, 0) // + .output("evcs0", SET_CHARGE_POWER_LIMIT, 6_000)) // .next(new TestCase() // - .input(sumEssDischargePower, 0) // - .input(sumGridActivePower, -200) // - .input(evcs0ChargePower, 5800) // - .output(evcs0SetChargePowerLimit, 6_000)) // + .input(ESS_DISCHARGE_POWER, 0) // + .input(GRID_ACTIVE_POWER, -200) // + .input("evcs0", ACTIVE_POWER, 5800) // + .output("evcs0", SET_CHARGE_POWER_LIMIT, 6_000)) // .next(new TestCase() // - .input(sumEssDischargePower, 0) // - .input(sumGridActivePower, 500) // - .input(evcs0ChargePower, 5800) // - .input(evcs0MinimumHardwarePower, Evcs.DEFAULT_MINIMUM_HARDWARE_POWER) - .output(evcs0SetChargePowerLimit, 5300)) + .input(ESS_DISCHARGE_POWER, 0) // + .input(GRID_ACTIVE_POWER, 500) // + .input("evcs0", ACTIVE_POWER, 5800) // + .input("evcs0", Evcs.ChannelId.MINIMUM_HARDWARE_POWER, Evcs.DEFAULT_MINIMUM_HARDWARE_POWER) + .output("evcs0", SET_CHARGE_POWER_LIMIT, 5300)) // Active hysteresis .next(new TestCase() // - .input(sumEssDischargePower, 0) // - .input(sumGridActivePower, 1000) // - .input(evcs0ChargePower, 5000) // - .output(evcs0SetChargePowerLimit, 5_300) // - .output(evcsController0AwaitingHysteresis, true)) // + .input(ESS_DISCHARGE_POWER, 0) // + .input(GRID_ACTIVE_POWER, 1000) // + .input("evcs0", ACTIVE_POWER, 5000) // + .output("evcs0", SET_CHARGE_POWER_LIMIT, 5_300) // + .output(AWAITING_HYSTERESIS, true)) // .next(new TestCase() // - .timeleap(clock, 6, ChronoUnit.MINUTES)) // + .timeleap(clock, 6, MINUTES)) // // Passed hysteresis .next(new TestCase() // - .input(sumEssDischargePower, 0) // - .input(sumGridActivePower, 1000) // - .input(evcs0ChargePower, 5000) // - .output(evcs0SetChargePowerLimit, 0) // - .output(evcsController0AwaitingHysteresis, false)) // + .input(ESS_DISCHARGE_POWER, 0) // + .input(GRID_ACTIVE_POWER, 1000) // + .input("evcs0", ACTIVE_POWER, 5000) // + .output("evcs0", SET_CHARGE_POWER_LIMIT, 0) // + .output(AWAITING_HYSTERESIS, false)) // // Active hysteresis .next(new TestCase() // - .input(sumEssDischargePower, 0) // - .input(sumGridActivePower, -5000) // - .input(evcs0ChargePower, 0) // - .output(evcs0SetChargePowerLimit, 0) // - .output(evcsController0AwaitingHysteresis, true)) + .input(ESS_DISCHARGE_POWER, 0) // + .input(GRID_ACTIVE_POWER, -5000) // + .input("evcs0", ACTIVE_POWER, 0) // + .output("evcs0", SET_CHARGE_POWER_LIMIT, 0) // + .output(AWAITING_HYSTERESIS, true)) .next(new TestCase() // - .timeleap(clock, 1, ChronoUnit.MINUTES)) // + .timeleap(clock, 1, MINUTES)) // // New charge process starting after another 30 seconds .next(new TestCase() // - .input(sumEssDischargePower, 0) // - .input(sumGridActivePower, -5000) // - .input(evcs0ChargePower, 0) // - .output(evcs0SetChargePowerLimit, 5000) // - .output(evcsController0AwaitingHysteresis, false)); // + .input(ESS_DISCHARGE_POWER, 0) // + .input(GRID_ACTIVE_POWER, -5000) // + .input("evcs0", ACTIVE_POWER, 0) // + .output("evcs0", SET_CHARGE_POWER_LIMIT, 5000) // + .output(AWAITING_HYSTERESIS, false)) // + .deactivate(); } } diff --git a/io.openems.edge.controller.generic.jsonlogic/test/io/openems/edge/controller/generic/jsonlogic/ControllerGenericJsonLogicImplTest.java b/io.openems.edge.controller.generic.jsonlogic/test/io/openems/edge/controller/generic/jsonlogic/ControllerGenericJsonLogicImplTest.java index 943591e76dd..f0153a6af4e 100644 --- a/io.openems.edge.controller.generic.jsonlogic/test/io/openems/edge/controller/generic/jsonlogic/ControllerGenericJsonLogicImplTest.java +++ b/io.openems.edge.controller.generic.jsonlogic/test/io/openems/edge/controller/generic/jsonlogic/ControllerGenericJsonLogicImplTest.java @@ -1,10 +1,11 @@ package io.openems.edge.controller.generic.jsonlogic; +import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_EQUALS; +import static io.openems.edge.ess.api.SymmetricEss.ChannelId.SOC; + import org.junit.Test; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.sum.DummySum; -import io.openems.edge.common.sum.Sum; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.controller.test.ControllerTest; @@ -12,40 +13,32 @@ public class ControllerGenericJsonLogicImplTest { - private static final ChannelAddress ESS_SOC = new ChannelAddress(Sum.SINGLETON_COMPONENT_ID, - Sum.ChannelId.ESS_SOC.id()); - - private static final String ESS_ID = "ess0"; - - private static final ChannelAddress ESS_SET_ACTIVE_POWER_EQUALS = new ChannelAddress(ESS_ID, - "SetActivePowerEquals"); - @Test public void test() throws Exception { new ControllerTest(new ControllerGenericJsonLogicImpl()) // .addReference("componentManager", new DummyComponentManager()) // .addComponent(new DummySum()) // - .addComponent(new DummyManagedSymmetricEss(ESS_ID)) // + .addComponent(new DummyManagedSymmetricEss("ess0")) // .activate(MyConfig.create() // .setRule("{" // + " \"if\":["// + " {"// + " \"<\": ["// + " {"// - + " \"var\": \"" + ESS_SOC + "\""// + + " \"var\": \"ess0/Soc\""// + " },"// + " 50"// + " ]"// + " },"// + " ["// + " ["// - + " \"" + ESS_SET_ACTIVE_POWER_EQUALS + "\","// + + " \"ess0/SetActivePowerEquals\","// + " 5000"// + " ]"// + " ],"// + " ["// + " ["// - + " \"" + ESS_SET_ACTIVE_POWER_EQUALS + "\","// + + " \"ess0/SetActivePowerEquals\","// + " -2000"// + " ]"// + " ]"// @@ -53,12 +46,12 @@ public void test() throws Exception { + "}") // .build()) .next(new TestCase() // - .input(ESS_SOC, 40) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 5000)) // + .input("ess0", SOC, 40) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 5000)) // .next(new TestCase() // - .input(ESS_SOC, 60) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, -2000) // - ); + .input("ess0", SOC, 60) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, -2000)) // + .deactivate(); } } diff --git a/io.openems.edge.controller.generic.jsonlogic/test/io/openems/edge/controller/generic/jsonlogic/ControllerGenericJsonLogicImplTest2.java b/io.openems.edge.controller.generic.jsonlogic/test/io/openems/edge/controller/generic/jsonlogic/ControllerGenericJsonLogicImplTest2.java index d12b3dc936c..61d21f86d56 100644 --- a/io.openems.edge.controller.generic.jsonlogic/test/io/openems/edge/controller/generic/jsonlogic/ControllerGenericJsonLogicImplTest2.java +++ b/io.openems.edge.controller.generic.jsonlogic/test/io/openems/edge/controller/generic/jsonlogic/ControllerGenericJsonLogicImplTest2.java @@ -1,10 +1,14 @@ package io.openems.edge.controller.generic.jsonlogic; +import static io.openems.edge.common.sum.Sum.ChannelId.ESS_SOC; +import static io.openems.edge.common.sum.Sum.ChannelId.PRODUCTION_ACTIVE_POWER; +import static io.openems.edge.io.test.DummyInputOutput.ChannelId.INPUT_OUTPUT0; +import static io.openems.edge.io.test.DummyInputOutput.ChannelId.INPUT_OUTPUT1; +import static io.openems.edge.io.test.DummyInputOutput.ChannelId.INPUT_OUTPUT2; + import org.junit.Test; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.sum.DummySum; -import io.openems.edge.common.sum.Sum; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.controller.test.ControllerTest; @@ -12,29 +16,19 @@ public class ControllerGenericJsonLogicImplTest2 { - private static final ChannelAddress SUM_PRODUCTION_POWER = new ChannelAddress(Sum.SINGLETON_COMPONENT_ID, - Sum.ChannelId.PRODUCTION_ACTIVE_POWER.id()); - private static final ChannelAddress SUM_SOC = new ChannelAddress(Sum.SINGLETON_COMPONENT_ID, - Sum.ChannelId.ESS_SOC.id()); - - private static final String IO_ID = "io0"; - private static final ChannelAddress INPUT0 = new ChannelAddress(IO_ID, "InputOutput0"); - private static final ChannelAddress OUTPUT0 = new ChannelAddress(IO_ID, "InputOutput1"); - private static final ChannelAddress OUTPUT1 = new ChannelAddress(IO_ID, "InputOutput2"); - @Test public void test() throws Exception { new ControllerTest(new ControllerGenericJsonLogicImpl()) // .addReference("componentManager", new DummyComponentManager()) // .addComponent(new DummySum()) // - .addComponent(new DummyInputOutput(IO_ID)) // + .addComponent(new DummyInputOutput("io0")) // .activate(MyConfig.create() // .setRule("{"// + " \"if\": ["// + " {"// + " \">\": ["// + " {"// - + " \"var\": \"" + SUM_PRODUCTION_POWER + "\""// + + " \"var\": \"_sum/ProductionActivePower\""// + " },"// + " 2000"// + " ]"// @@ -44,7 +38,7 @@ public void test() throws Exception { + " {"// + " \">\": ["// + " {"// - + " \"var\": \"" + SUM_SOC + "\""// + + " \"var\": \"_sum/EssSoc\""// + " },"// + " 70"// + " ]"// @@ -52,24 +46,24 @@ public void test() throws Exception { + " {"// + " \"if\": ["// + " {"// - + " \"var\": \"" + INPUT0 + "\""// + + " \"var\": \"io0/InputOutput0\""// + " },"// + " ["// + " ],"// + " {"// + " \"if\": ["// + " {"// - + " \"var\": \"" + OUTPUT0 + "\""// + + " \"var\": \"io0/InputOutput1\""// + " },"// + " ["// + " ["// - + " \"" + OUTPUT0 + "\","// + + " \"io0/InputOutput1\","// + " false"// + " ]"// + " ],"// + " ["// + " ["// - + " \"" + OUTPUT1 + "\","// + + " \"io0/InputOutput2\","// + " true"// + " ]"// + " ]"// @@ -86,7 +80,7 @@ public void test() throws Exception { + " {"// + " \"<\": ["// + " {"// - + " \"var\": \"" + SUM_SOC + "\""// + + " \"var\": \"_sum/EssSoc\""// + " },"// + " 40"// + " ]"// @@ -94,24 +88,24 @@ public void test() throws Exception { + " {"// + " \"if\": ["// + " {"// - + " \"var\": \"" + INPUT0 + "\""// + + " \"var\": \"io0/InputOutput0\""// + " },"// + " ["// + " ],"// + " {"// + " \"if\": ["// + " {"// - + " \"var\": \"" + OUTPUT1 + "\""// + + " \"var\": \"io0/InputOutput2\""// + " },"// + " ["// + " ["// - + " \"" + OUTPUT1 + "\","// + + " \"io0/InputOutput2\","// + " false"// + " ]"// + " ],"// + " ["// + " ["// - + " \"" + OUTPUT0 + "\","// + + " \"io0/InputOutput1\","// + " true"// + " ]"// + " ]"// @@ -127,30 +121,30 @@ public void test() throws Exception { + "}") // .build()) .next(new TestCase() // - .input(SUM_PRODUCTION_POWER, 2001) // - .input(SUM_SOC, 71) // - .input(INPUT0, false) // - .input(OUTPUT0, true) // - .output(OUTPUT0, false)) // + .input(PRODUCTION_ACTIVE_POWER, 2001) // + .input(ESS_SOC, 71) // + .input("io0", INPUT_OUTPUT0, false) // + .input("io0", INPUT_OUTPUT1, true) // + .output("io0", INPUT_OUTPUT1, false)) // .next(new TestCase() // - .input(SUM_PRODUCTION_POWER, 2001) // - .input(SUM_SOC, 71) // - .input(INPUT0, false) // - .input(OUTPUT0, false) // - .output(OUTPUT1, true)) // + .input(PRODUCTION_ACTIVE_POWER, 2001) // + .input(ESS_SOC, 71) // + .input("io0", INPUT_OUTPUT0, false) // + .input("io0", INPUT_OUTPUT1, false) // + .output("io0", INPUT_OUTPUT2, true)) // .next(new TestCase() // - .input(SUM_PRODUCTION_POWER, 1999) // - .input(SUM_SOC, 39) // - .input(INPUT0, false) // - .input(OUTPUT1, true) // - .output(OUTPUT1, false)) // + .input(PRODUCTION_ACTIVE_POWER, 1999) // + .input(ESS_SOC, 39) // + .input("io0", INPUT_OUTPUT0, false) // + .input("io0", INPUT_OUTPUT2, true) // + .output("io0", INPUT_OUTPUT2, false)) // .next(new TestCase() // - .input(SUM_PRODUCTION_POWER, 1999) // - .input(SUM_SOC, 39) // - .input(INPUT0, false) // - .input(OUTPUT1, false) // - .output(OUTPUT0, true)) // - ; + .input(PRODUCTION_ACTIVE_POWER, 1999) // + .input(ESS_SOC, 39) // + .input("io0", INPUT_OUTPUT0, false) // + .input("io0", INPUT_OUTPUT2, false) // + .output("io0", INPUT_OUTPUT1, true)) // + .deactivate(); } } diff --git a/io.openems.edge.controller.highloadtimeslot/test/io/openems/edge/controller/highloadtimeslot/ControllerHighLoadTimeslotImplTest.java b/io.openems.edge.controller.highloadtimeslot/test/io/openems/edge/controller/highloadtimeslot/ControllerHighLoadTimeslotImplTest.java index 042f700767e..ad6992ddea2 100644 --- a/io.openems.edge.controller.highloadtimeslot/test/io/openems/edge/controller/highloadtimeslot/ControllerHighLoadTimeslotImplTest.java +++ b/io.openems.edge.controller.highloadtimeslot/test/io/openems/edge/controller/highloadtimeslot/ControllerHighLoadTimeslotImplTest.java @@ -1,5 +1,7 @@ package io.openems.edge.controller.highloadtimeslot; +import static io.openems.edge.controller.highloadtimeslot.WeekdayFilter.EVERDAY; + import org.junit.Test; import io.openems.edge.common.test.DummyComponentManager; @@ -7,24 +9,22 @@ public class ControllerHighLoadTimeslotImplTest { - private static final String CTRL_ID = "ctrl0"; - private static final String ESS_ID = "ess0"; - @Test public void test() throws Exception { new ControllerTest(new ControllerHighLoadTimeslotImpl()) // .addReference("componentManager", new DummyComponentManager()) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEss(ESS_ID).setHysteresisSoc(90) // + .setId("ctrl0") // + .setEss("ess0") // + .setHysteresisSoc(90) // .setChargePower(10000) // .setDischargePower(20000) // .setStartDate("01.01.2019") // .setEndDate("01.01.2020") // .setStartTime("08:00") // .setEndTime("13:00") // - .setWeekdayFilter(WeekdayFilter.EVERDAY) // - .build()); // - ; + .setWeekdayFilter(EVERDAY) // + .build()) // + .deactivate(); } } diff --git a/io.openems.edge.controller.io.alarm/test/io/openems/edge/controller/io/alarm/ControllerIoAlarmImplTest.java b/io.openems.edge.controller.io.alarm/test/io/openems/edge/controller/io/alarm/ControllerIoAlarmImplTest.java index d4adfec3d38..4eb47a82b4b 100644 --- a/io.openems.edge.controller.io.alarm/test/io/openems/edge/controller/io/alarm/ControllerIoAlarmImplTest.java +++ b/io.openems.edge.controller.io.alarm/test/io/openems/edge/controller/io/alarm/ControllerIoAlarmImplTest.java @@ -1,8 +1,11 @@ package io.openems.edge.controller.io.alarm; +import static io.openems.edge.controller.io.alarm.DummyComponent.ChannelId.STATE_0; +import static io.openems.edge.controller.io.alarm.DummyComponent.ChannelId.STATE_1; +import static io.openems.edge.io.test.DummyInputOutput.ChannelId.INPUT_OUTPUT0; + import org.junit.Test; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.controller.test.ControllerTest; @@ -10,44 +13,34 @@ public class ControllerIoAlarmImplTest { - private static final String CTRL_ID = "ctrl0"; - - private static final String DUMMY_ID = "dummy0"; - private static final ChannelAddress DUMMY_STATE0 = new ChannelAddress(DUMMY_ID, "State0"); - private static final ChannelAddress DUMMY_STATE1 = new ChannelAddress(DUMMY_ID, "State1"); - - private static final String IO_ID = "io0"; - private static final ChannelAddress IO_INPUT_OUTPUT0 = new ChannelAddress(IO_ID, "InputOutput0"); - @Test public void test() throws Exception { new ControllerTest(new ControllerIoAlarmImpl()) // .addReference("componentManager", new DummyComponentManager()) // - .addComponent(new DummyComponent(DUMMY_ID)) // - .addComponent(new DummyInputOutput(IO_ID)) // + .addComponent(new DummyComponent("dummy0")) // + .addComponent(new DummyInputOutput("io0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setInputChannelAddresses(// - DUMMY_STATE0.toString(), // - DUMMY_STATE1.toString()) - .setOutputChannelAddress(IO_INPUT_OUTPUT0.toString()) // + .setId("ctrl0") // + .setInputChannelAddresses("dummy0/State0", "dummy0/State1") + .setOutputChannelAddress("io0/InputOutput0") // .build()) .next(new TestCase() // - .input(DUMMY_STATE0, true) // - .input(DUMMY_STATE1, false) // - .output(IO_INPUT_OUTPUT0, true)) // + .input("dummy0", STATE_0, true) // + .input("dummy0", STATE_1, false) // + .output("io0", INPUT_OUTPUT0, true)) // .next(new TestCase() // - .input(DUMMY_STATE0, false) // - .input(DUMMY_STATE1, true) // - .output(IO_INPUT_OUTPUT0, true)) // + .input("dummy0", STATE_0, false) // + .input("dummy0", STATE_1, true) // + .output("io0", INPUT_OUTPUT0, true)) // .next(new TestCase() // - .input(DUMMY_STATE0, true) // - .input(DUMMY_STATE1, true) // - .output(IO_INPUT_OUTPUT0, true)) + .input("dummy0", STATE_0, true) // + .input("dummy0", STATE_1, true) // + .output("io0", INPUT_OUTPUT0, true)) .next(new TestCase() // - .input(DUMMY_STATE0, false) // - .input(DUMMY_STATE1, false) // - .output(IO_INPUT_OUTPUT0, false)); + .input("dummy0", STATE_0, false) // + .input("dummy0", STATE_1, false) // + .output("io0", INPUT_OUTPUT0, false)) // + .deactivate(); } } diff --git a/io.openems.edge.controller.io.analog/test/io/openems/edge/controller/io/analog/MyControllerTest.java b/io.openems.edge.controller.io.analog/test/io/openems/edge/controller/io/analog/MyControllerTest.java index 6c31ef34601..e2ce7b1917c 100644 --- a/io.openems.edge.controller.io.analog/test/io/openems/edge/controller/io/analog/MyControllerTest.java +++ b/io.openems.edge.controller.io.analog/test/io/openems/edge/controller/io/analog/MyControllerTest.java @@ -1,14 +1,14 @@ package io.openems.edge.controller.io.analog; -import java.time.Instant; -import java.time.ZoneOffset; +import static io.openems.edge.common.test.TestUtils.createDummyClock; + import java.time.temporal.ChronoUnit; import org.junit.Test; -import io.openems.common.test.TimeLeapClock; import io.openems.common.types.ChannelAddress; import io.openems.edge.common.sum.DummySum; +import io.openems.edge.common.sum.Sum; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyConfigurationAdmin; import io.openems.edge.controller.test.ControllerTest; @@ -18,139 +18,129 @@ public class MyControllerTest { - private static final String CTRL_ID = "ctrl0"; - private static final String IO_ID = "analogIo0"; - - // Sum channels - private static final ChannelAddress SUM_ESS_DISCHARGE_POWER = new ChannelAddress("_sum", "EssDischargePower"); - private static final ChannelAddress SUM_GRID_ACTIVE_POWER = new ChannelAddress("_sum", "GridActivePower"); - - // AnalogIO channels - private static final ChannelAddress DEBUG_SET_OUTPUT_VOLTAGE = new ChannelAddress(IO_ID, "DebugSetOutputVoltage"); - private static final ChannelAddress DEBUG_SET_OUTPUT_PERCENT = new ChannelAddress(IO_ID, "DebugSetOutputPercent"); + private static final ChannelAddress DEBUG_SET_OUTPUT_VOLTAGE = new ChannelAddress("analogIo0", + "DebugSetOutputVoltage"); + private static final ChannelAddress DEBUG_SET_OUTPUT_PERCENT = new ChannelAddress("analogIo0", + "DebugSetOutputPercent"); @Test public void testOff() throws Exception { - - final var analogOutput = new DummyAnalogVoltageOutput(IO_ID); - final var clock = new TimeLeapClock(Instant.parse("2020-01-01T01:00:00.00Z"), ZoneOffset.UTC); + final var clock = createDummyClock(); new ControllerTest(new ControllerIoAnalogImpl(clock)) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // .addReference("timedata", new DummyTimedata("timedata0")) // - .addReference("analogOutput", analogOutput) // + .addReference("analogOutput", new DummyAnalogVoltageOutput("analogIo0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setAnalogOutputId(IO_ID) // + .setId("ctrl0") // + .setAnalogOutputId("analogIo0") // .setManualTarget(6_000) // .setMaximumPower(10_000) // .setMode(Mode.OFF) // .setPowerBehaviour(PowerBehavior.LINEAR) // .build()) .next(new TestCase() // - .input(SUM_ESS_DISCHARGE_POWER, 2000) // - .input(SUM_GRID_ACTIVE_POWER, -5000)// + .input(Sum.ChannelId.ESS_DISCHARGE_POWER, 2000) // + .input(Sum.ChannelId.GRID_ACTIVE_POWER, -5000)// .output(DEBUG_SET_OUTPUT_PERCENT, 0f) // .output(DEBUG_SET_OUTPUT_VOLTAGE, 0)) // - ; + .deactivate(); } @Test public void testOn() throws Exception { - - final var analogOutput = new DummyAnalogVoltageOutput(IO_ID) // - .setRange(new Range(0, 100, 10000)); - final var clock = new TimeLeapClock(Instant.parse("2020-01-01T01:00:00.00Z"), ZoneOffset.UTC); + final var clock = createDummyClock(); new ControllerTest(new ControllerIoAnalogImpl(clock)) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // .addReference("timedata", new DummyTimedata("timedata0")) // - .addReference("analogOutput", analogOutput) // + .addReference("analogOutput", new DummyAnalogVoltageOutput("analogIo0") // + .setRange(new Range(0, 100, 10000))) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setAnalogOutputId(IO_ID) // + .setId("ctrl0") // + .setAnalogOutputId("analogIo0") // .setManualTarget(6_000) // .setMaximumPower(10_000) // .setMode(Mode.ON) // .setPowerBehaviour(PowerBehavior.LINEAR) // .build()) .next(new TestCase() // - .input(SUM_ESS_DISCHARGE_POWER, 0) // - .input(SUM_GRID_ACTIVE_POWER, -5000)// + .input(Sum.ChannelId.ESS_DISCHARGE_POWER, 0) // + .input(Sum.ChannelId.GRID_ACTIVE_POWER, -5000)// .output(DEBUG_SET_OUTPUT_PERCENT, 60.000004f) // .output(DEBUG_SET_OUTPUT_VOLTAGE, 6000)) // - ; + .deactivate(); new ControllerTest(new ControllerIoAnalogImpl(clock)) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // .addReference("timedata", new DummyTimedata("timedata0")) // - .addReference("analogOutput", analogOutput) // + .addReference("analogOutput", new DummyAnalogVoltageOutput("analogIo0") // + .setRange(new Range(0, 100, 10000))) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setAnalogOutputId(IO_ID) // + .setId("ctrl0") // + .setAnalogOutputId("analogIo0") // .setManualTarget(0) // .setMaximumPower(10_000) // .setMode(Mode.ON) // .setPowerBehaviour(PowerBehavior.LINEAR) // .build()) .next(new TestCase() // - .input(SUM_ESS_DISCHARGE_POWER, 0) // - .input(SUM_GRID_ACTIVE_POWER, -5000)// + .input(Sum.ChannelId.ESS_DISCHARGE_POWER, 0) // + .input(Sum.ChannelId.GRID_ACTIVE_POWER, -5000)// .output(DEBUG_SET_OUTPUT_PERCENT, 0f) // .output(DEBUG_SET_OUTPUT_VOLTAGE, 0)) // - ; + .deactivate(); } @Test public void testAutomatic() throws Exception { - - final var analogOutput = new DummyAnalogVoltageOutput(IO_ID); - final var clock = new TimeLeapClock(Instant.parse("2020-01-01T01:00:00.00Z"), ZoneOffset.UTC); + final var clock = createDummyClock(); new ControllerTest(new ControllerIoAnalogImpl(clock)) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // .addReference("timedata", new DummyTimedata("timedata0")) // - .addReference("analogOutput", analogOutput) // + .addReference("analogOutput", new DummyAnalogVoltageOutput("analogIo0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setAnalogOutputId(IO_ID) // + .setId("ctrl0") // + .setAnalogOutputId("analogIo0") // .setManualTarget(6_000) // .setMaximumPower(10_000) // .setMode(Mode.AUTOMATIC) // .setPowerBehaviour(PowerBehavior.LINEAR) // .build()) .next(new TestCase() // - .input(SUM_ESS_DISCHARGE_POWER, 0) // - .input(SUM_GRID_ACTIVE_POWER, -5000)// + .input(Sum.ChannelId.ESS_DISCHARGE_POWER, 0) // + .input(Sum.ChannelId.GRID_ACTIVE_POWER, -5000)// .output(DEBUG_SET_OUTPUT_PERCENT, 50f) // .output(DEBUG_SET_OUTPUT_VOLTAGE, 5000)) // .next(new TestCase() // - .input(SUM_ESS_DISCHARGE_POWER, 0) // - .input(SUM_GRID_ACTIVE_POWER, -2444)// + .input(Sum.ChannelId.ESS_DISCHARGE_POWER, 0) // + .input(Sum.ChannelId.GRID_ACTIVE_POWER, -2444)// .output(DEBUG_SET_OUTPUT_PERCENT, 50f) // .output(DEBUG_SET_OUTPUT_VOLTAGE, 5000)) // .next(new TestCase() // .timeleap(clock, 4, ChronoUnit.SECONDS) // - .input(SUM_ESS_DISCHARGE_POWER, 0) // - .input(SUM_GRID_ACTIVE_POWER, -2444)// + .input(Sum.ChannelId.ESS_DISCHARGE_POWER, 0) // + .input(Sum.ChannelId.GRID_ACTIVE_POWER, -2444)// .output(DEBUG_SET_OUTPUT_PERCENT, 24.439999f) // .output(DEBUG_SET_OUTPUT_VOLTAGE, 2400)) // 100mV Steps .next(new TestCase() // .timeleap(clock, 4, ChronoUnit.SECONDS) // - .input(SUM_ESS_DISCHARGE_POWER, 0) // - .input(SUM_GRID_ACTIVE_POWER, -12444)// + .input(Sum.ChannelId.ESS_DISCHARGE_POWER, 0) // + .input(Sum.ChannelId.GRID_ACTIVE_POWER, -12444)// .output(DEBUG_SET_OUTPUT_PERCENT, 100f) // .output(DEBUG_SET_OUTPUT_VOLTAGE, 10000)) // .next(new TestCase() // .timeleap(clock, 4, ChronoUnit.SECONDS) // - .input(SUM_ESS_DISCHARGE_POWER, 0) // - .input(SUM_GRID_ACTIVE_POWER, 1000)// + .input(Sum.ChannelId.ESS_DISCHARGE_POWER, 0) // + .input(Sum.ChannelId.GRID_ACTIVE_POWER, 1000)// .output(DEBUG_SET_OUTPUT_PERCENT, 0f) // .output(DEBUG_SET_OUTPUT_VOLTAGE, 0)) // - ; + + .deactivate(); } } diff --git a/io.openems.edge.controller.io.channelsinglethreshold/test/io/openems/edge/controller/io/channelsinglethreshold/ControllerIoChannelSingleThresholdImplTest.java b/io.openems.edge.controller.io.channelsinglethreshold/test/io/openems/edge/controller/io/channelsinglethreshold/ControllerIoChannelSingleThresholdImplTest.java index 7a780ffba36..19494c4a3f3 100644 --- a/io.openems.edge.controller.io.channelsinglethreshold/test/io/openems/edge/controller/io/channelsinglethreshold/ControllerIoChannelSingleThresholdImplTest.java +++ b/io.openems.edge.controller.io.channelsinglethreshold/test/io/openems/edge/controller/io/channelsinglethreshold/ControllerIoChannelSingleThresholdImplTest.java @@ -1,9 +1,11 @@ package io.openems.edge.controller.io.channelsinglethreshold; +import static io.openems.edge.controller.io.channelsinglethreshold.ControllerIoChannelSingleThreshold.ChannelId.AWAITING_HYSTERESIS; +import static io.openems.edge.ess.api.SymmetricEss.ChannelId.SOC; +import static io.openems.edge.io.test.DummyInputOutput.ChannelId.INPUT_OUTPUT0; + import org.junit.Test; -import io.openems.common.test.TimeLeapClock; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.controller.test.ControllerTest; @@ -12,35 +14,26 @@ public class ControllerIoChannelSingleThresholdImplTest { - private static final String CTRL_ID = "ctrl0"; - private static final ChannelAddress CTRL_AWAITING_HYSTERESIS = new ChannelAddress(CTRL_ID, "AwaitingHysteresis"); - - private static final String ESS_ID = "ess0"; - private static final ChannelAddress ESS_SOC = new ChannelAddress(ESS_ID, "Soc"); - - private static final String IO_ID = "io0"; - private static final ChannelAddress IO_INPUT_OUTPUT0 = new ChannelAddress(IO_ID, "InputOutput0"); - @Test public void test() throws Exception { - final var clock = new TimeLeapClock(); new ControllerTest(new ControllerIoChannelSingleThresholdImpl()) // - .addReference("componentManager", new DummyComponentManager(clock)) // - .addComponent(new DummyManagedSymmetricEss(ESS_ID)) // - .addComponent(new DummyInputOutput(IO_ID)) // + .addReference("componentManager", new DummyComponentManager()) // + .addComponent(new DummyManagedSymmetricEss("ess0")) // + .addComponent(new DummyInputOutput("io0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // + .setId("ctrl0") // .setMode(Mode.AUTOMATIC) // - .setInputChannelAddress(ESS_SOC.toString()) // - .setOutputChannelAddress(IO_INPUT_OUTPUT0.toString()) // + .setInputChannelAddress("ess0/Soc") // + .setOutputChannelAddress("io0/InputOutput0") // .setThreshold(70) // .setSwitchedLoadPower(0) // .setMinimumSwitchingTime(60).setInvert(false) // .build()) .next(new TestCase() // - .input(ESS_SOC, 50) // - .output(IO_INPUT_OUTPUT0, false) // - .output(CTRL_AWAITING_HYSTERESIS, false)); // + .input("ess0", SOC, 50) // + .output("io0", INPUT_OUTPUT0, false) // + .output(AWAITING_HYSTERESIS, false)) // + .deactivate(); } } diff --git a/io.openems.edge.controller.io.fixdigitaloutput/test/io/openems/edge/controller/io/fixdigitaloutput/ControllerIoFixDigitalOutputImplTest.java b/io.openems.edge.controller.io.fixdigitaloutput/test/io/openems/edge/controller/io/fixdigitaloutput/ControllerIoFixDigitalOutputImplTest.java index 9a80d917290..87dc6f60fb3 100644 --- a/io.openems.edge.controller.io.fixdigitaloutput/test/io/openems/edge/controller/io/fixdigitaloutput/ControllerIoFixDigitalOutputImplTest.java +++ b/io.openems.edge.controller.io.fixdigitaloutput/test/io/openems/edge/controller/io/fixdigitaloutput/ControllerIoFixDigitalOutputImplTest.java @@ -1,8 +1,9 @@ package io.openems.edge.controller.io.fixdigitaloutput; +import static io.openems.edge.io.test.DummyInputOutput.ChannelId.INPUT_OUTPUT0; + import org.junit.Test; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.controller.test.ControllerTest; @@ -10,11 +11,6 @@ public class ControllerIoFixDigitalOutputImplTest { - private static final String CTRL_ID = "ctrl0"; - - private static final String IO_ID = "io0"; - private static final ChannelAddress IO_INPUT_OUTPUT0 = new ChannelAddress(IO_ID, "InputOutput0"); - @Test public void testOn() throws Exception { this.testSwitch(true); @@ -28,14 +24,14 @@ public void testOff() throws Exception { private void testSwitch(boolean on) throws Exception { new ControllerTest(new ControllerIoFixDigitalOutputImpl()) // .addReference("componentManager", new DummyComponentManager()) // - .addComponent(new DummyInputOutput(IO_ID)) // + .addComponent(new DummyInputOutput("io0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setOutputChannelAddress(IO_INPUT_OUTPUT0.toString()) // + .setId("ctrl0") // + .setOutputChannelAddress("io0/InputOutput0") // .setOn(on) // .build()) .next(new TestCase() // - .output(IO_INPUT_OUTPUT0, on)); + .output("io0", INPUT_OUTPUT0, on)) // + .deactivate(); } - } diff --git a/io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerHeatingElementImplTest4.java b/io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerHeatingElementImplTest4.java index 854d4f90087..6e5db300d23 100644 --- a/io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerHeatingElementImplTest4.java +++ b/io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerHeatingElementImplTest4.java @@ -1,18 +1,18 @@ package io.openems.edge.controller.io.heatingelement; -import java.time.Instant; -import java.time.ZoneOffset; -import java.time.temporal.ChronoUnit; +import static io.openems.edge.common.sum.Sum.ChannelId.ESS_DISCHARGE_POWER; +import static io.openems.edge.common.sum.Sum.ChannelId.GRID_ACTIVE_POWER; +import static io.openems.edge.controller.io.heatingelement.ControllerIoHeatingElement.ChannelId.LEVEL; +import static java.time.temporal.ChronoUnit.SECONDS; import org.junit.Test; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.test.TimeLeapClock; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.sum.DummySum; -import io.openems.edge.common.sum.Sum; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; +import io.openems.edge.common.test.TestUtils; import io.openems.edge.controller.io.heatingelement.enums.Level; import io.openems.edge.controller.io.heatingelement.enums.Mode; import io.openems.edge.controller.io.heatingelement.enums.WorkMode; @@ -20,25 +20,20 @@ import io.openems.edge.io.test.DummyInputOutput; public class ControllerHeatingElementImplTest4 { - private static final String CTRL_ID = "ctrl0"; - private static final String IO_ID = "io0"; - private static final ChannelAddress IO_OUTPUT1 = new ChannelAddress(IO_ID, "InputOutput1"); - private static final ChannelAddress IO_OUTPUT2 = new ChannelAddress(IO_ID, "InputOutput2"); - private static final ChannelAddress IO_OUTPUT3 = new ChannelAddress(IO_ID, "InputOutput3"); - private static final TimeLeapClock clock = new TimeLeapClock( - Instant.ofEpochSecond(1577836800) /* starts at 1. January 2020 00:00:00 */, ZoneOffset.UTC); + private static TimeLeapClock clock; private static ControllerTest prepareTest(Mode mode, Level level) throws OpenemsNamedException, Exception { + clock = TestUtils.createDummyClock(); return new ControllerTest(new ControllerIoHeatingElementImpl()) // .addReference("componentManager", new DummyComponentManager(clock)) // .addReference("sum", new DummySum()) // .addComponent(new DummyInputOutput("io0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setOutputChannelPhaseL1(IO_OUTPUT1.toString()) // - .setOutputChannelPhaseL2(IO_OUTPUT2.toString()) // - .setOutputChannelPhaseL3(IO_OUTPUT3.toString()) // + .setId("ctrl0") // + .setOutputChannelPhaseL1("io0/InputOutput0") // + .setOutputChannelPhaseL2("io0/InputOutput1") // + .setOutputChannelPhaseL3("io0/InputOutput2") // .setEndTime("15:45:00") // .setPowerOfPhase(2000) // .setMode(mode) // @@ -49,13 +44,6 @@ private static ControllerTest prepareTest(Mode mode, Level level) throws Openems .build()); // } - private static final ChannelAddress ESSO_DISCHARGE_POWER = new ChannelAddress("_sum", - Sum.ChannelId.ESS_DISCHARGE_POWER.id()); - private static final ChannelAddress LEVEL = new ChannelAddress(CTRL_ID, - ControllerIoHeatingElement.ChannelId.LEVEL.id()); - private static final ChannelAddress GRID_ACTIVE_POWER = new ChannelAddress("_sum", - Sum.ChannelId.GRID_ACTIVE_POWER.id()); - @Test public void testDischargeTakeIntoAccount() throws OpenemsNamedException, Exception { prepareTest(Mode.AUTOMATIC, Level.LEVEL_3)// @@ -63,20 +51,20 @@ public void testDischargeTakeIntoAccount() throws OpenemsNamedException, Excepti .input(GRID_ACTIVE_POWER, -2500)// .output(LEVEL, Level.LEVEL_1)) // .next(new TestCase() // - .timeleap(clock, 181, ChronoUnit.SECONDS)// + .timeleap(clock, 181, SECONDS)// .input(GRID_ACTIVE_POWER, -2500)// .output(LEVEL, Level.LEVEL_2))// // Grid power reducing because of 2kW heating power .next(new TestCase()// - .timeleap(clock, 181, ChronoUnit.SECONDS)// + .timeleap(clock, 181, SECONDS)// .input(GRID_ACTIVE_POWER, -500) // - .output(LEVEL, Level.LEVEL_2)// - ).next(new TestCase() // - .timeleap(clock, 181, ChronoUnit.SECONDS)// + .output(LEVEL, Level.LEVEL_2)) // + .next(new TestCase() // + .timeleap(clock, 181, SECONDS)// .input(GRID_ACTIVE_POWER, -500) // - .input(ESSO_DISCHARGE_POWER, 2300) // - .output(LEVEL, Level.LEVEL_1)// - ); // ; + .input(ESS_DISCHARGE_POWER, 2300) // + .output(LEVEL, Level.LEVEL_1)) // + .deactivate(); } @Test @@ -87,9 +75,10 @@ public void realDataTest() throws OpenemsNamedException, Exception { .input(GRID_ACTIVE_POWER, -6000)// .output(LEVEL, Level.LEVEL_3)) // .next(new TestCase()// - .timeleap(clock, 181, ChronoUnit.SECONDS)// + .timeleap(clock, 181, SECONDS)// .input(GRID_ACTIVE_POWER, 0)// - .input(ESSO_DISCHARGE_POWER, 2280)// - .output(LEVEL, Level.LEVEL_1)); // ; + .input(ESS_DISCHARGE_POWER, 2280)// + .output(LEVEL, Level.LEVEL_1)) // + .deactivate(); } } diff --git a/io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerIoHeatingElementImplTest.java b/io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerIoHeatingElementImplTest.java index a2c130c4c3a..f874c0994e7 100644 --- a/io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerIoHeatingElementImplTest.java +++ b/io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerIoHeatingElementImplTest.java @@ -1,17 +1,22 @@ package io.openems.edge.controller.io.heatingelement; -import java.time.Instant; -import java.time.ZoneOffset; -import java.time.temporal.ChronoUnit; +import static io.openems.edge.common.sum.Sum.ChannelId.GRID_ACTIVE_POWER; +import static io.openems.edge.common.test.TestUtils.createDummyClock; +import static io.openems.edge.controller.io.heatingelement.ControllerIoHeatingElement.ChannelId.PHASE1_TIME; +import static io.openems.edge.controller.io.heatingelement.ControllerIoHeatingElement.ChannelId.PHASE2_TIME; +import static io.openems.edge.controller.io.heatingelement.ControllerIoHeatingElement.ChannelId.PHASE3_TIME; +import static io.openems.edge.controller.io.heatingelement.enums.Level.LEVEL_3; +import static io.openems.edge.io.test.DummyInputOutput.ChannelId.INPUT_OUTPUT0; +import static io.openems.edge.io.test.DummyInputOutput.ChannelId.INPUT_OUTPUT1; +import static io.openems.edge.io.test.DummyInputOutput.ChannelId.INPUT_OUTPUT2; +import static java.time.temporal.ChronoUnit.HOURS; +import static java.time.temporal.ChronoUnit.MINUTES; import org.junit.Test; -import io.openems.common.test.TimeLeapClock; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.sum.DummySum; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; -import io.openems.edge.controller.io.heatingelement.enums.Level; import io.openems.edge.controller.io.heatingelement.enums.Mode; import io.openems.edge.controller.io.heatingelement.enums.WorkMode; import io.openems.edge.controller.test.ControllerTest; @@ -19,36 +24,22 @@ public class ControllerIoHeatingElementImplTest { - private static final String CTRL_ID = "ctrl0"; - private static final String IO_ID = "io0"; - - private static final ChannelAddress SUM_GRID_ACTIVE_POWER = new ChannelAddress("_sum", "GridActivePower"); - - private static final ChannelAddress IO_OUTPUT1 = new ChannelAddress(IO_ID, "InputOutput1"); - private static final ChannelAddress IO_OUTPUT2 = new ChannelAddress(IO_ID, "InputOutput2"); - private static final ChannelAddress IO_OUTPUT3 = new ChannelAddress(IO_ID, "InputOutput3"); - - private static final ChannelAddress CTRL_PHASE1TIME = new ChannelAddress(CTRL_ID, "Phase1Time"); - private static final ChannelAddress CTRL_PHASE2TIME = new ChannelAddress(CTRL_ID, "Phase2Time"); - private static final ChannelAddress CTRL_PHASE3TIME = new ChannelAddress(CTRL_ID, "Phase3Time"); - @Test public void test() throws Exception { - final var clock = new TimeLeapClock(Instant.ofEpochSecond(1577836800) /* starts at 1. January 2020 00:00:00 */, - ZoneOffset.UTC); + final var clock = createDummyClock(); new ControllerTest(new ControllerIoHeatingElementImpl()) // .addReference("componentManager", new DummyComponentManager(clock)) // .addReference("sum", new DummySum()) // - .addComponent(new DummyInputOutput(IO_ID)) // + .addComponent(new DummyInputOutput("io0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setOutputChannelPhaseL1(IO_OUTPUT1.toString()) // - .setOutputChannelPhaseL2(IO_OUTPUT2.toString()) // - .setOutputChannelPhaseL3(IO_OUTPUT3.toString()) // + .setId("ctrl0") // + .setOutputChannelPhaseL1("io0/InputOutput0") // + .setOutputChannelPhaseL2("io0/InputOutput1") // + .setOutputChannelPhaseL3("io0/InputOutput2") // .setEndTime("15:45:00") // .setPowerOfPhase(2000) // .setMode(Mode.AUTOMATIC) // - .setDefaultLevel(Level.LEVEL_3) // + .setDefaultLevel(LEVEL_3) // .setWorkMode(WorkMode.TIME) // .setMinTime(1) // .setMinimumSwitchingTime(60) // @@ -56,133 +47,134 @@ public void test() throws Exception { .next(new TestCase() // // Grid active power : 0, Excess power : 0, // from -> UNDEFINED --to--> LEVEL_0, no of relais = 0 - .input(SUM_GRID_ACTIVE_POWER, 0) // - .output(IO_OUTPUT1, false) // - .output(IO_OUTPUT2, false) // - .output(IO_OUTPUT3, false) // - .output(CTRL_PHASE1TIME, 0) // - .output(CTRL_PHASE1TIME, 0) // - .output(CTRL_PHASE2TIME, 0)) // + .input(GRID_ACTIVE_POWER, 0) // + .output("io0", INPUT_OUTPUT0, false) // + .output("io0", INPUT_OUTPUT1, false) // + .output("io0", INPUT_OUTPUT2, false) // + .output(PHASE1_TIME, 0) // + .output(PHASE1_TIME, 0) // + .output(PHASE2_TIME, 0)) // .next(new TestCase() // // Grid active power : 0, Excess power : 0, // from -> LEVEL_0 --to--> LEVEL_0, no of relais = 0 - .timeleap(clock, 15, ChronoUnit.MINUTES)// - .input(SUM_GRID_ACTIVE_POWER, 0) // - .output(IO_OUTPUT1, false) // - .output(IO_OUTPUT2, false) // - .output(IO_OUTPUT3, false) // - .output(CTRL_PHASE1TIME, 0) // - .output(CTRL_PHASE2TIME, 0) // - .output(CTRL_PHASE3TIME, 0)) // + .timeleap(clock, 15, MINUTES)// + .input(GRID_ACTIVE_POWER, 0) // + .output("io0", INPUT_OUTPUT0, false) // + .output("io0", INPUT_OUTPUT1, false) // + .output("io0", INPUT_OUTPUT2, false) // + .output(PHASE1_TIME, 0) // + .output(PHASE2_TIME, 0) // + .output(PHASE3_TIME, 0)) // .next(new TestCase() // // Grid active power : -2000, Excess power : 2000, // from -> LEVEL_0 --to--> LEVEL_1, no of relais = 1 - .timeleap(clock, 15, ChronoUnit.MINUTES)// - .input(SUM_GRID_ACTIVE_POWER, -2000) // - .output(IO_OUTPUT1, true) // - .output(IO_OUTPUT2, false) // - .output(IO_OUTPUT3, false) // - .output(CTRL_PHASE1TIME, 0) // - .output(CTRL_PHASE2TIME, 0) // - .output(CTRL_PHASE3TIME, 0)) // + .timeleap(clock, 15, MINUTES)// + .input(GRID_ACTIVE_POWER, -2000) // + .output("io0", INPUT_OUTPUT0, true) // + .output("io0", INPUT_OUTPUT1, false) // + .output("io0", INPUT_OUTPUT2, false) // + .output(PHASE1_TIME, 0) // + .output(PHASE2_TIME, 0) // + .output(PHASE3_TIME, 0)) // .next(new TestCase() // // Grid active power : -4000, Excess power : 6000, // from -> LEVEL_1 --to--> LEVEL_3, no of relais = 3 - .timeleap(clock, 15, ChronoUnit.MINUTES)// - .input(SUM_GRID_ACTIVE_POWER, -4000) // - .output(IO_OUTPUT1, true) // - .output(IO_OUTPUT2, true) // - .output(IO_OUTPUT3, true) // - .output(CTRL_PHASE1TIME, 15 * 60) // - .output(CTRL_PHASE2TIME, 0) // - .output(CTRL_PHASE3TIME, 0)) // + .timeleap(clock, 15, MINUTES)// + .input(GRID_ACTIVE_POWER, -4000) // + .output("io0", INPUT_OUTPUT0, true) // + .output("io0", INPUT_OUTPUT1, true) // + .output("io0", INPUT_OUTPUT2, true) // + .output(PHASE1_TIME, 15 * 60) // + .output(PHASE2_TIME, 0) // + .output(PHASE3_TIME, 0)) // .next(new TestCase() // // Grid active power : -6000, Excess power : 12000, // from -> LEVEL_3 --to--> LEVEL_3, no of relais = 3 - .timeleap(clock, 15, ChronoUnit.MINUTES)// - .input(SUM_GRID_ACTIVE_POWER, -6000) // - .output(IO_OUTPUT1, true) // - .output(IO_OUTPUT2, true) // - .output(IO_OUTPUT3, true) // - .output(CTRL_PHASE1TIME, 30 * 60) // - .output(CTRL_PHASE2TIME, 15 * 60) // - .output(CTRL_PHASE3TIME, 15 * 60)) // + .timeleap(clock, 15, MINUTES)// + .input(GRID_ACTIVE_POWER, -6000) // + .output("io0", INPUT_OUTPUT0, true) // + .output("io0", INPUT_OUTPUT1, true) // + .output("io0", INPUT_OUTPUT2, true) // + .output(PHASE1_TIME, 30 * 60) // + .output(PHASE2_TIME, 15 * 60) // + .output(PHASE3_TIME, 15 * 60)) // .next(new TestCase() // // Grid active power : -7000, Excess power : 13000, // from -> LEVEL_3 --to--> LEVEL_3, no of relais = 3 - .input(SUM_GRID_ACTIVE_POWER, -7000) // - .timeleap(clock, 15, ChronoUnit.MINUTES)// - .output(IO_OUTPUT1, true) // - .output(IO_OUTPUT2, true) // - .output(IO_OUTPUT3, true) // - .output(CTRL_PHASE1TIME, 45 * 60) // - .output(CTRL_PHASE2TIME, 30 * 60) // - .output(CTRL_PHASE3TIME, 30 * 60)) // + .input(GRID_ACTIVE_POWER, -7000) // + .timeleap(clock, 15, MINUTES)// + .output("io0", INPUT_OUTPUT0, true) // + .output("io0", INPUT_OUTPUT1, true) // + .output("io0", INPUT_OUTPUT2, true) // + .output(PHASE1_TIME, 45 * 60) // + .output(PHASE2_TIME, 30 * 60) // + .output(PHASE3_TIME, 30 * 60)) // .next(new TestCase() // // Grid active power : 0, Excess power : 6000, // from -> LEVEL_3 --to--> LEVEL_3, no of relais = 3 - .timeleap(clock, 15, ChronoUnit.MINUTES)// - .input(SUM_GRID_ACTIVE_POWER, 0) // - .output(IO_OUTPUT1, true) // - .output(IO_OUTPUT2, true) // - .output(IO_OUTPUT3, true) // - .output(CTRL_PHASE1TIME, 60 * 60) // - .output(CTRL_PHASE2TIME, 45 * 60) // - .output(CTRL_PHASE3TIME, 45 * 60)) // + .timeleap(clock, 15, MINUTES)// + .input(GRID_ACTIVE_POWER, 0) // + .output("io0", INPUT_OUTPUT0, true) // + .output("io0", INPUT_OUTPUT1, true) // + .output("io0", INPUT_OUTPUT2, true) // + .output(PHASE1_TIME, 60 * 60) // + .output(PHASE2_TIME, 45 * 60) // + .output(PHASE3_TIME, 45 * 60)) // .next(new TestCase() // // Grid active power : 1, Excess power : 0, // from -> LEVEL_3 --to--> LEVEL_0, no of relais = 0 - .timeleap(clock, 15, ChronoUnit.MINUTES)// - .input(SUM_GRID_ACTIVE_POWER, 1) // - .output(IO_OUTPUT1, false) // - .output(IO_OUTPUT2, false) // - .output(IO_OUTPUT3, false) // - .output(CTRL_PHASE1TIME, 75 * 60) // - .output(CTRL_PHASE2TIME, 60 * 60) // - .output(CTRL_PHASE3TIME, 60 * 60)) // + .timeleap(clock, 15, MINUTES)// + .input(GRID_ACTIVE_POWER, 1) // + .output("io0", INPUT_OUTPUT0, false) // + .output("io0", INPUT_OUTPUT1, false) // + .output("io0", INPUT_OUTPUT2, false) // + .output(PHASE1_TIME, 75 * 60) // + .output(PHASE2_TIME, 60 * 60) // + .output(PHASE3_TIME, 60 * 60)) // .next(new TestCase() // // Grid active power : 20000, Excess power : 0, // from -> LEVEL_0 --to--> LEVEL_0, no of relais = 0 - .timeleap(clock, 15, ChronoUnit.MINUTES)// - .input(SUM_GRID_ACTIVE_POWER, 20000) // - .output(IO_OUTPUT1, false) // - .output(IO_OUTPUT2, false) // - .output(IO_OUTPUT3, false) // - .output(CTRL_PHASE1TIME, 75 * 60) // - .output(CTRL_PHASE2TIME, 60 * 60) // - .output(CTRL_PHASE3TIME, 60 * 60)) // + .timeleap(clock, 15, MINUTES)// + .input(GRID_ACTIVE_POWER, 20000) // + .output("io0", INPUT_OUTPUT0, false) // + .output("io0", INPUT_OUTPUT1, false) // + .output("io0", INPUT_OUTPUT2, false) // + .output(PHASE1_TIME, 75 * 60) // + .output(PHASE2_TIME, 60 * 60) // + .output(PHASE3_TIME, 60 * 60)) // .next(new TestCase() // // Grid active power : -4000, Excess power : 10000, // from -> LEVEL_0 --to--> LEVEL_2, no of relais = 2 - .timeleap(clock, 15, ChronoUnit.MINUTES)// - .input(SUM_GRID_ACTIVE_POWER, -4000) // - .output(IO_OUTPUT1, true) // - .output(IO_OUTPUT2, true) // - .output(IO_OUTPUT3, false) // - .output(CTRL_PHASE1TIME, 75 * 60) // - .output(CTRL_PHASE2TIME, 60 * 60) // - .output(CTRL_PHASE3TIME, 60 * 60)) // + .timeleap(clock, 15, MINUTES)// + .input(GRID_ACTIVE_POWER, -4000) // + .output("io0", INPUT_OUTPUT0, true) // + .output("io0", INPUT_OUTPUT1, true) // + .output("io0", INPUT_OUTPUT2, false) // + .output(PHASE1_TIME, 75 * 60) // + .output(PHASE2_TIME, 60 * 60) // + .output(PHASE3_TIME, 60 * 60)) // .next(new TestCase() // // Grid active power : 0, Excess power : 4000, // from -> LEVEL_2 --to--> LEVEL_2, no of relais = 2 - .timeleap(clock, 15, ChronoUnit.MINUTES)// - .input(SUM_GRID_ACTIVE_POWER, 0) // - .output(IO_OUTPUT1, true) // - .output(IO_OUTPUT2, true) // - .output(IO_OUTPUT3, false) // - .output(CTRL_PHASE1TIME, 90 * 60) // - .output(CTRL_PHASE2TIME, 75 * 60) // - .output(CTRL_PHASE3TIME, 60 * 60)) // + .timeleap(clock, 15, MINUTES)// + .input(GRID_ACTIVE_POWER, 0) // + .output("io0", INPUT_OUTPUT0, true) // + .output("io0", INPUT_OUTPUT1, true) // + .output("io0", INPUT_OUTPUT2, false) // + .output(PHASE1_TIME, 90 * 60) // + .output(PHASE2_TIME, 75 * 60) // + .output(PHASE3_TIME, 60 * 60)) // .next(new TestCase() // // Switch to next day - .timeleap(clock, 22, ChronoUnit.HOURS)// - .input(SUM_GRID_ACTIVE_POWER, 0) // - .output(IO_OUTPUT1, true) // - .output(IO_OUTPUT2, true) // - .output(IO_OUTPUT3, false) // - .output(CTRL_PHASE1TIME, 30 * 60) // - .output(CTRL_PHASE2TIME, 30 * 60) // - .output(CTRL_PHASE3TIME, 0)); // + .timeleap(clock, 22, HOURS)// + .input(GRID_ACTIVE_POWER, 0) // + .output("io0", INPUT_OUTPUT0, true) // + .output("io0", INPUT_OUTPUT1, true) // + .output("io0", INPUT_OUTPUT2, false) // + .output(PHASE1_TIME, 30 * 60) // + .output(PHASE2_TIME, 30 * 60) // + .output(PHASE3_TIME, 0)) // + .deactivate(); } } diff --git a/io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerIoHeatingElementImplTest2.java b/io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerIoHeatingElementImplTest2.java index 31ec267cf14..788715d4715 100644 --- a/io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerIoHeatingElementImplTest2.java +++ b/io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerIoHeatingElementImplTest2.java @@ -1,13 +1,20 @@ package io.openems.edge.controller.io.heatingelement; +import static io.openems.edge.common.sum.Sum.ChannelId.GRID_ACTIVE_POWER; +import static io.openems.edge.controller.io.heatingelement.ControllerIoHeatingElement.ChannelId.FORCE_START_AT_SECONDS_OF_DAY; +import static io.openems.edge.controller.io.heatingelement.ControllerIoHeatingElement.ChannelId.STATUS; +import static io.openems.edge.controller.io.heatingelement.ControllerIoHeatingElement.ChannelId.TOTAL_PHASE_TIME; +import static io.openems.edge.io.test.DummyInputOutput.ChannelId.INPUT_OUTPUT0; +import static io.openems.edge.io.test.DummyInputOutput.ChannelId.INPUT_OUTPUT1; +import static io.openems.edge.io.test.DummyInputOutput.ChannelId.INPUT_OUTPUT2; +import static java.time.temporal.ChronoUnit.MINUTES; + import java.time.Instant; import java.time.ZoneOffset; -import java.time.temporal.ChronoUnit; import org.junit.Test; import io.openems.common.test.TimeLeapClock; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.sum.DummySum; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; @@ -20,20 +27,6 @@ public class ControllerIoHeatingElementImplTest2 { - private static final String CTRL_ID = "ctrl0"; - private static final String IO_ID = "io0"; - - private static final ChannelAddress SUM_GRID_ACTIVE_POWER = new ChannelAddress("_sum", "GridActivePower"); - - private static final ChannelAddress IO_OUTPUT1 = new ChannelAddress(IO_ID, "InputOutput1"); - private static final ChannelAddress IO_OUTPUT2 = new ChannelAddress(IO_ID, "InputOutput2"); - private static final ChannelAddress IO_OUTPUT3 = new ChannelAddress(IO_ID, "InputOutput3"); - - private static final ChannelAddress CTRL_FORCE_START_AT_SECONDS_OF_DAY = new ChannelAddress(CTRL_ID, - "ForceStartAtSecondsOfDay"); - private static final ChannelAddress CTRL_TOTAL_PHASE_TIME = new ChannelAddress(CTRL_ID, "TotalPhaseTime"); - private static final ChannelAddress CTRL_STATUS = new ChannelAddress(CTRL_ID, "Status"); - @Test public void minimumTime_lowerLevel_test() throws Exception { final var clock = new TimeLeapClock(Instant.ofEpochSecond(1577836800) /* starts at 1. January 2020 00:00:00 */, @@ -41,12 +34,12 @@ public void minimumTime_lowerLevel_test() throws Exception { new ControllerTest(new ControllerIoHeatingElementImpl()) // .addReference("componentManager", new DummyComponentManager(clock)) // .addReference("sum", new DummySum()) // - .addComponent(new DummyInputOutput(IO_ID)) // + .addComponent(new DummyInputOutput("io0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setOutputChannelPhaseL1(IO_OUTPUT1.toString()) // - .setOutputChannelPhaseL2(IO_OUTPUT2.toString()) // - .setOutputChannelPhaseL3(IO_OUTPUT3.toString()) // + .setId("ctrl0") // + .setOutputChannelPhaseL1("io0/InputOutput0") // + .setOutputChannelPhaseL2("io0/InputOutput1") // + .setOutputChannelPhaseL3("io0/InputOutput2") // .setEndTime("15:45:00") // .setPowerOfPhase(2000) // .setMode(Mode.AUTOMATIC) // @@ -56,20 +49,21 @@ public void minimumTime_lowerLevel_test() throws Exception { .setMinimumSwitchingTime(60) // .build()) // .next(new TestCase() // - .input(SUM_GRID_ACTIVE_POWER, 0) // - .output(IO_OUTPUT1, false))// + .input(GRID_ACTIVE_POWER, 0) // + .output("io0", INPUT_OUTPUT0, false))// .next(new TestCase() // - .timeleap(clock, 6, ChronoUnit.MINUTES)// - .input(SUM_GRID_ACTIVE_POWER, -2000) // - .output(IO_OUTPUT1, true) // - .output(CTRL_TOTAL_PHASE_TIME, 0) // - .output(CTRL_FORCE_START_AT_SECONDS_OF_DAY, 53_100 /* 14:45 */)) // + .timeleap(clock, 6, MINUTES)// + .input(GRID_ACTIVE_POWER, -2000) // + .output("io0", INPUT_OUTPUT0, true) // + .output(TOTAL_PHASE_TIME, 0) // + .output(FORCE_START_AT_SECONDS_OF_DAY, 53_100 /* 14:45 */)) // .next(new TestCase() // - .timeleap(clock, 6, ChronoUnit.MINUTES)// - .input(SUM_GRID_ACTIVE_POWER, 0) // - .output(IO_OUTPUT1, true) // - .output(CTRL_TOTAL_PHASE_TIME, 360 /* 6 minutes, one phase */) // - .output(CTRL_FORCE_START_AT_SECONDS_OF_DAY, 53_220 /* 14:47 - two minutes later */)); // + .timeleap(clock, 6, MINUTES)// + .input(GRID_ACTIVE_POWER, 0) // + .output("io0", INPUT_OUTPUT0, true) // + .output(TOTAL_PHASE_TIME, 360 /* 6 minutes, one phase */) // + .output(FORCE_START_AT_SECONDS_OF_DAY, 53_220 /* 14:47 - two minutes later */)) // + .deactivate(); } @Test @@ -79,12 +73,12 @@ public void minimumTime_sameLevel_test() throws Exception { new ControllerTest(new ControllerIoHeatingElementImpl()) // .addReference("componentManager", new DummyComponentManager(clock)) // .addReference("sum", new DummySum()) // - .addComponent(new DummyInputOutput(IO_ID)) // + .addComponent(new DummyInputOutput("io0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setOutputChannelPhaseL1(IO_OUTPUT1.toString()) // - .setOutputChannelPhaseL2(IO_OUTPUT2.toString()) // - .setOutputChannelPhaseL3(IO_OUTPUT3.toString()) // + .setId("ctrl0") // + .setOutputChannelPhaseL1("io0/InputOutput0") // + .setOutputChannelPhaseL2("io0/InputOutput1") // + .setOutputChannelPhaseL3("io0/InputOutput2") // .setEndTime("15:45:00") // .setPowerOfPhase(2000) // .setMode(Mode.AUTOMATIC) // @@ -94,24 +88,25 @@ public void minimumTime_sameLevel_test() throws Exception { .setMinimumSwitchingTime(60) // .build()) // .next(new TestCase() // - .input(SUM_GRID_ACTIVE_POWER, 0) // - .output(IO_OUTPUT1, false))// + .input(GRID_ACTIVE_POWER, 0) // + .output("io0", INPUT_OUTPUT0, false))// .next(new TestCase() // - .timeleap(clock, 6, ChronoUnit.MINUTES)// - .input(SUM_GRID_ACTIVE_POWER, -6000) // - .output(IO_OUTPUT1, true) // - .output(IO_OUTPUT2, true) // - .output(IO_OUTPUT3, true) // - .output(CTRL_TOTAL_PHASE_TIME, 0) // - .output(CTRL_FORCE_START_AT_SECONDS_OF_DAY, 53_100 /* 14:45 */)) // + .timeleap(clock, 6, MINUTES)// + .input(GRID_ACTIVE_POWER, -6000) // + .output("io0", INPUT_OUTPUT0, true) // + .output("io0", INPUT_OUTPUT1, true) // + .output("io0", INPUT_OUTPUT2, true) // + .output(TOTAL_PHASE_TIME, 0) // + .output(FORCE_START_AT_SECONDS_OF_DAY, 53_100 /* 14:45 */)) // .next(new TestCase() // - .timeleap(clock, 6, ChronoUnit.MINUTES)// - .input(SUM_GRID_ACTIVE_POWER, 0) // - .output(IO_OUTPUT1, true) // - .output(IO_OUTPUT2, true) // - .output(IO_OUTPUT3, true) // - .output(CTRL_TOTAL_PHASE_TIME, 1080 /* 6 minutes, all three phases */) // - .output(CTRL_FORCE_START_AT_SECONDS_OF_DAY, 53_460 /* 14:51 - six minutes later */)); // + .timeleap(clock, 6, MINUTES)// + .input(GRID_ACTIVE_POWER, 0) // + .output("io0", INPUT_OUTPUT0, true) // + .output("io0", INPUT_OUTPUT1, true) // + .output("io0", INPUT_OUTPUT2, true) // + .output(TOTAL_PHASE_TIME, 1080 /* 6 minutes, all three phases */) // + .output(FORCE_START_AT_SECONDS_OF_DAY, 53_460 /* 14:51 - six minutes later */)) // + .deactivate(); } @Test @@ -121,12 +116,12 @@ public void minimumTime_inForceMode_test() throws Exception { new ControllerTest(new ControllerIoHeatingElementImpl()) // .addReference("componentManager", new DummyComponentManager(clock)) // .addReference("sum", new DummySum()) // - .addComponent(new DummyInputOutput(IO_ID)) // + .addComponent(new DummyInputOutput("io0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setOutputChannelPhaseL1(IO_OUTPUT1.toString()) // - .setOutputChannelPhaseL2(IO_OUTPUT2.toString()) // - .setOutputChannelPhaseL3(IO_OUTPUT3.toString()) // + .setId("ctrl0") // + .setOutputChannelPhaseL1("io0/InputOutput0") // + .setOutputChannelPhaseL2("io0/InputOutput1") // + .setOutputChannelPhaseL3("io0/InputOutput2") // .setEndTime("16:00:00") // .setPowerOfPhase(2000) // .setMode(Mode.AUTOMATIC) // @@ -136,35 +131,36 @@ public void minimumTime_inForceMode_test() throws Exception { .setMinimumSwitchingTime(60) // .build()) // .next(new TestCase() // - .input(SUM_GRID_ACTIVE_POWER, 0) // - .output(IO_OUTPUT1, false))// + .input(GRID_ACTIVE_POWER, 0) // + .output("io0", INPUT_OUTPUT0, false))// .next(new TestCase() // - .timeleap(clock, 6, ChronoUnit.MINUTES)// /* 14:57 */ - .input(SUM_GRID_ACTIVE_POWER, 0) // - .output(IO_OUTPUT1, false) // - .output(IO_OUTPUT2, false) // - .output(IO_OUTPUT3, false) // - .output(CTRL_TOTAL_PHASE_TIME, 0) // - .output(CTRL_FORCE_START_AT_SECONDS_OF_DAY, 54_000 /* 15:00 */)) // + .timeleap(clock, 6, MINUTES)// /* 14:57 */ + .input(GRID_ACTIVE_POWER, 0) // + .output("io0", INPUT_OUTPUT0, false) // + .output("io0", INPUT_OUTPUT1, false) // + .output("io0", INPUT_OUTPUT2, false) // + .output(TOTAL_PHASE_TIME, 0) // + .output(FORCE_START_AT_SECONDS_OF_DAY, 54_000 /* 15:00 */)) // .next(new TestCase() // - .timeleap(clock, 4, ChronoUnit.MINUTES)// - .input(SUM_GRID_ACTIVE_POWER, 0) // - .output(IO_OUTPUT1, true) // - .output(IO_OUTPUT2, true) // - .output(IO_OUTPUT3, true) // - .output(CTRL_FORCE_START_AT_SECONDS_OF_DAY, 54_000 /* current time */)) + .timeleap(clock, 4, MINUTES)// + .input(GRID_ACTIVE_POWER, 0) // + .output("io0", INPUT_OUTPUT0, true) // + .output("io0", INPUT_OUTPUT1, true) // + .output("io0", INPUT_OUTPUT2, true) // + .output(FORCE_START_AT_SECONDS_OF_DAY, 54_000 /* current time */)) .next(new TestCase() // - .timeleap(clock, 3, ChronoUnit.MINUTES)// /* 15:03 */ - .input(SUM_GRID_ACTIVE_POWER, 0) // + .timeleap(clock, 3, MINUTES)// /* 15:03 */ + .input(GRID_ACTIVE_POWER, 0) // // Previous duration of each phase cannot be set as input if you want to count // already passed active time // .input(CTRL_PHASE1TIME, 180) // // .input(CTRL_PHASE2TIME, 180) // // .input(CTRL_PHASE3TIME, 180) // - .output(IO_OUTPUT1, true) // - .output(IO_OUTPUT2, true) // - .output(IO_OUTPUT3, true) // - .output(CTRL_STATUS, Status.ACTIVE_FORCED) // - .output(CTRL_FORCE_START_AT_SECONDS_OF_DAY, 54_180 /* current time */)); // + .output("io0", INPUT_OUTPUT0, true) // + .output("io0", INPUT_OUTPUT1, true) // + .output("io0", INPUT_OUTPUT2, true) // + .output(STATUS, Status.ACTIVE_FORCED) // + .output(FORCE_START_AT_SECONDS_OF_DAY, 54_180 /* current time */)) // + .deactivate(); } } diff --git a/io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerIoHeatingElementImplTest3.java b/io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerIoHeatingElementImplTest3.java index f5d21a8d14d..c8d2a90b648 100644 --- a/io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerIoHeatingElementImplTest3.java +++ b/io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerIoHeatingElementImplTest3.java @@ -1,5 +1,9 @@ package io.openems.edge.controller.io.heatingelement; +import static io.openems.edge.io.test.DummyInputOutput.ChannelId.INPUT_OUTPUT0; +import static io.openems.edge.io.test.DummyInputOutput.ChannelId.INPUT_OUTPUT1; +import static io.openems.edge.io.test.DummyInputOutput.ChannelId.INPUT_OUTPUT2; + import java.time.Instant; import java.time.ZoneOffset; @@ -7,7 +11,6 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.test.TimeLeapClock; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.sum.DummySum; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; @@ -19,13 +22,6 @@ public class ControllerIoHeatingElementImplTest3 { - private static final String CTRL_ID = "ctrl0"; - private static final String IO_ID = "io0"; - - private static final ChannelAddress IO_OUTPUT1 = new ChannelAddress(IO_ID, "InputOutput1"); - private static final ChannelAddress IO_OUTPUT2 = new ChannelAddress(IO_ID, "InputOutput2"); - private static final ChannelAddress IO_OUTPUT3 = new ChannelAddress(IO_ID, "InputOutput3"); - private static ControllerTest prepareTest(Mode mode, Level level) throws OpenemsNamedException, Exception { return new ControllerTest(new ControllerIoHeatingElementImpl()) // .addReference("componentManager", @@ -35,10 +31,10 @@ private static ControllerTest prepareTest(Mode mode, Level level) throws Openems .addReference("sum", new DummySum()) // .addComponent(new DummyInputOutput("io0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setOutputChannelPhaseL1(IO_OUTPUT1.toString()) // - .setOutputChannelPhaseL2(IO_OUTPUT2.toString()) // - .setOutputChannelPhaseL3(IO_OUTPUT3.toString()) // + .setId("ctrl0") // + .setOutputChannelPhaseL1("io0/InputOutput0") // + .setOutputChannelPhaseL2("io0/InputOutput1") // + .setOutputChannelPhaseL3("io0/InputOutput2") // .setEndTime("15:45:00") // .setPowerOfPhase(2000) // .setMode(mode) // @@ -53,50 +49,50 @@ private static ControllerTest prepareTest(Mode mode, Level level) throws Openems public void testOff() throws Exception { prepareTest(Mode.MANUAL_OFF, Level.LEVEL_3) // .next(new TestCase() // - .output(IO_OUTPUT1, false) // - .output(IO_OUTPUT2, false) // - .output(IO_OUTPUT3, false) // - ); + .output("io0", INPUT_OUTPUT0, false) // + .output("io0", INPUT_OUTPUT1, false) // + .output("io0", INPUT_OUTPUT2, false)) // + .deactivate(); } @Test public void testOnLevel0() throws Exception { prepareTest(Mode.MANUAL_ON, Level.LEVEL_0) // .next(new TestCase() // - .output(IO_OUTPUT1, false) // - .output(IO_OUTPUT2, false) // - .output(IO_OUTPUT3, false) // - ); + .output("io0", INPUT_OUTPUT0, false) // + .output("io0", INPUT_OUTPUT1, false) // + .output("io0", INPUT_OUTPUT2, false)) // + .deactivate(); } @Test public void testOnLevel1() throws Exception { prepareTest(Mode.MANUAL_ON, Level.LEVEL_1) // .next(new TestCase() // - .output(IO_OUTPUT1, true) // - .output(IO_OUTPUT2, false) // - .output(IO_OUTPUT3, false) // - ); + .output("io0", INPUT_OUTPUT0, true) // + .output("io0", INPUT_OUTPUT1, false) // + .output("io0", INPUT_OUTPUT2, false)) // + .deactivate(); } @Test public void testOnLevel2() throws Exception { prepareTest(Mode.MANUAL_ON, Level.LEVEL_2) // .next(new TestCase() // - .output(IO_OUTPUT1, true) // - .output(IO_OUTPUT2, true) // - .output(IO_OUTPUT3, false) // - ); + .output("io0", INPUT_OUTPUT0, true) // + .output("io0", INPUT_OUTPUT1, true) // + .output("io0", INPUT_OUTPUT2, false)) // + .deactivate(); } @Test public void testOnLevel3() throws Exception { prepareTest(Mode.MANUAL_ON, Level.LEVEL_3) // .next(new TestCase() // - .output(IO_OUTPUT1, true) // - .output(IO_OUTPUT2, true) // - .output(IO_OUTPUT3, true) // - ); + .output("io0", INPUT_OUTPUT0, true) // + .output("io0", INPUT_OUTPUT1, true) // + .output("io0", INPUT_OUTPUT2, true)) // + .deactivate(); } } diff --git a/io.openems.edge.controller.io.heatpump.sgready/test/io/openems/edge/controller/io/heatpump/sgready/ControllerIoHeatPumpSgReadyImplTest.java b/io.openems.edge.controller.io.heatpump.sgready/test/io/openems/edge/controller/io/heatpump/sgready/ControllerIoHeatPumpSgReadyImplTest.java index 25c1389f41a..a1e14ab2de5 100644 --- a/io.openems.edge.controller.io.heatpump.sgready/test/io/openems/edge/controller/io/heatpump/sgready/ControllerIoHeatPumpSgReadyImplTest.java +++ b/io.openems.edge.controller.io.heatpump.sgready/test/io/openems/edge/controller/io/heatpump/sgready/ControllerIoHeatPumpSgReadyImplTest.java @@ -1,13 +1,19 @@ package io.openems.edge.controller.io.heatpump.sgready; -import java.time.Instant; -import java.time.ZoneOffset; +import static io.openems.edge.common.sum.Sum.ChannelId.ESS_DISCHARGE_POWER; +import static io.openems.edge.common.sum.Sum.ChannelId.ESS_SOC; +import static io.openems.edge.common.sum.Sum.ChannelId.GRID_ACTIVE_POWER; +import static io.openems.edge.common.test.TestUtils.createDummyClock; +import static io.openems.edge.controller.io.heatpump.sgready.ControllerIoHeatPumpSgReady.ChannelId.AWAITING_HYSTERESIS; +import static io.openems.edge.controller.io.heatpump.sgready.ControllerIoHeatPumpSgReady.ChannelId.STATUS; +import static io.openems.edge.io.test.DummyInputOutput.ChannelId.INPUT_OUTPUT0; +import static io.openems.edge.io.test.DummyInputOutput.ChannelId.INPUT_OUTPUT1; +import static java.time.temporal.ChronoUnit.SECONDS; + import java.time.temporal.ChronoUnit; import org.junit.Test; -import io.openems.common.test.TimeLeapClock; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.sum.DummySum; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; @@ -16,173 +22,136 @@ public class ControllerIoHeatPumpSgReadyImplTest { - private static final String CTRL_ID = "ctrHeatPump0"; - private static final String IO_ID = "io0"; - - private static final String outputChannel1 = "io0/InputOutput0"; - private static final String outputChannel2 = "io0/InputOutput1"; - - private static final ChannelAddress STATUS = new ChannelAddress(CTRL_ID, "Status"); - private static final ChannelAddress AWAITING_HYSTERESIS = new ChannelAddress(CTRL_ID, "AwaitingHysteresis"); - private static final ChannelAddress IO_OUTPUT_CHANNEL1 = new ChannelAddress(IO_ID, "InputOutput0"); - private static final ChannelAddress IO_OUTPUT_CHANNEL2 = new ChannelAddress(IO_ID, "InputOutput1"); - - private static final ChannelAddress SUM_GRID_ACTIVE_POWER = new ChannelAddress("_sum", "GridActivePower"); - private static final ChannelAddress SUM_ESS_SOC = new ChannelAddress("_sum", "EssSoc"); - private static final ChannelAddress SUM_ESS_DISCHARGE_POWER = new ChannelAddress("_sum", "EssDischargePower"); - @Test public void manual_undefined_test() throws Exception { - - final var clock = new TimeLeapClock(Instant.ofEpochSecond(1577836800) /* starts at 1. January 2020 00:00:00 */, - ZoneOffset.UTC); - new ControllerTest(new ControllerIoHeatPumpSgReadyImpl()) // - .addReference("componentManager", new DummyComponentManager(clock)) // + .addReference("componentManager", new DummyComponentManager()) // .addReference("sum", new DummySum()) // - .addComponent(new DummyInputOutput(IO_ID)) // + .addComponent(new DummyInputOutput("io0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // + .setId("ctrHeatPump0") // .setMode(Mode.MANUAL) // .setManualState(Status.UNDEFINED) // - .setOutputChannel1(outputChannel1) // - .setOutputChannel2(outputChannel2) // + .setOutputChannel1("io0/InputOutput0") // + .setOutputChannel2("io0/InputOutput1") // .build()) .next(new TestCase() // .output(STATUS, Status.REGULAR) // - .output(IO_OUTPUT_CHANNEL1, false) // - .output(IO_OUTPUT_CHANNEL2, false)); + .output("io0", INPUT_OUTPUT0, false) // + .output("io0", INPUT_OUTPUT1, false)) // + .deactivate(); } @Test public void manual_regular_test() throws Exception { - - final var clock = new TimeLeapClock(Instant.ofEpochSecond(1577836800) /* starts at 1. January 2020 00:00:00 */, - ZoneOffset.UTC); - new ControllerTest(new ControllerIoHeatPumpSgReadyImpl()) // - .addReference("componentManager", new DummyComponentManager(clock)) // + .addReference("componentManager", new DummyComponentManager()) // .addReference("sum", new DummySum()) // - .addComponent(new DummyInputOutput(IO_ID)) // + .addComponent(new DummyInputOutput("io0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // + .setId("ctrHeatPump0") // .setMode(Mode.MANUAL) // .setManualState(Status.REGULAR) // - .setOutputChannel1(outputChannel1) // - .setOutputChannel2(outputChannel2) // + .setOutputChannel1("io0/InputOutput0") // + .setOutputChannel2("io0/InputOutput1") // .build()) .next(new TestCase() // .output(STATUS, Status.REGULAR) // - .output(IO_OUTPUT_CHANNEL1, false) // - .output(IO_OUTPUT_CHANNEL2, false)); + .output("io0", INPUT_OUTPUT0, false) // + .output("io0", INPUT_OUTPUT1, false)) // + .deactivate(); } @Test public void manual_recommendation_test() throws Exception { - - final var clock = new TimeLeapClock(Instant.ofEpochSecond(1577836800) /* starts at 1. January 2020 00:00:00 */, - ZoneOffset.UTC); - new ControllerTest(new ControllerIoHeatPumpSgReadyImpl()) // - .addReference("componentManager", new DummyComponentManager(clock)) // + .addReference("componentManager", new DummyComponentManager()) // .addReference("sum", new DummySum()) // - .addComponent(new DummyInputOutput(IO_ID)) // + .addComponent(new DummyInputOutput("io0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // + .setId("ctrHeatPump0") // .setMode(Mode.MANUAL) // .setManualState(Status.RECOMMENDATION) // - .setOutputChannel1(outputChannel1) // - .setOutputChannel2(outputChannel2) // + .setOutputChannel1("io0/InputOutput0") // + .setOutputChannel2("io0/InputOutput1") // .build()) .next(new TestCase() // .output(STATUS, Status.RECOMMENDATION) // - .output(IO_OUTPUT_CHANNEL1, false) // - .output(IO_OUTPUT_CHANNEL2, true)); + .output("io0", INPUT_OUTPUT0, false) // + .output("io0", INPUT_OUTPUT1, true)) // + .deactivate(); } @Test public void manual_force_on_test() throws Exception { - - final var clock = new TimeLeapClock(Instant.ofEpochSecond(1577836800) /* starts at 1. January 2020 00:00:00 */, - ZoneOffset.UTC); - new ControllerTest(new ControllerIoHeatPumpSgReadyImpl()) // - .addReference("componentManager", new DummyComponentManager(clock)) // + .addReference("componentManager", new DummyComponentManager()) // .addReference("sum", new DummySum()) // - .addComponent(new DummyInputOutput(IO_ID)) // + .addComponent(new DummyInputOutput("io0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // + .setId("ctrHeatPump0") // .setMode(Mode.MANUAL) // .setManualState(Status.FORCE_ON) // - .setOutputChannel1(outputChannel1) // - .setOutputChannel2(outputChannel2) // + .setOutputChannel1("io0/InputOutput0") // + .setOutputChannel2("io0/InputOutput1") // .build()) .next(new TestCase() // .output(STATUS, Status.FORCE_ON) // - .output(IO_OUTPUT_CHANNEL1, true) // - .output(IO_OUTPUT_CHANNEL2, true)); + .output("io0", INPUT_OUTPUT0, true) // + .output("io0", INPUT_OUTPUT1, true)) // + .deactivate(); } @Test public void manual_lock_test() throws Exception { - - final var clock = new TimeLeapClock(Instant.ofEpochSecond(1577836800) /* starts at 1. January 2020 00:00:00 */, - ZoneOffset.UTC); - new ControllerTest(new ControllerIoHeatPumpSgReadyImpl()) // - .addReference("componentManager", new DummyComponentManager(clock)) // + .addReference("componentManager", new DummyComponentManager()) // .addReference("sum", new DummySum()) // - .addComponent(new DummyInputOutput(IO_ID)) // + .addComponent(new DummyInputOutput("io0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // + .setId("ctrHeatPump0") // .setMode(Mode.MANUAL) // .setManualState(Status.LOCK) // - .setOutputChannel1(outputChannel1) // - .setOutputChannel2(outputChannel2) // + .setOutputChannel1("io0/InputOutput0") // + .setOutputChannel2("io0/InputOutput1") // .build()) .next(new TestCase() // .output(STATUS, Status.LOCK) // - .output(IO_OUTPUT_CHANNEL1, true) // - .output(IO_OUTPUT_CHANNEL2, false)); + .output("io0", INPUT_OUTPUT0, true) // + .output("io0", INPUT_OUTPUT1, false)) // + .deactivate(); } @Test public void automatic_regular_test() throws Exception { - - final var clock = new TimeLeapClock(Instant.ofEpochSecond(1577836800) /* starts at 1. January 2020 00:00:00 */, - ZoneOffset.UTC); - new ControllerTest(new ControllerIoHeatPumpSgReadyImpl()) // - .addReference("componentManager", new DummyComponentManager(clock)) // + .addReference("componentManager", new DummyComponentManager()) // .addReference("sum", new DummySum()) // - .addComponent(new DummyInputOutput(IO_ID)) // + .addComponent(new DummyInputOutput("io0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // + .setId("ctrHeatPump0") // .setMode(Mode.AUTOMATIC) // .setAutomaticForceOnCtrlEnabled(false) // .setAutomaticRecommendationCtrlEnabled(false) // .setAutomaticLockCtrlEnabled(false) // - .setOutputChannel1(outputChannel1) // - .setOutputChannel2(outputChannel2) // + .setOutputChannel1("io0/InputOutput0") // + .setOutputChannel2("io0/InputOutput1") // .build()) .next(new TestCase() // .output(STATUS, Status.REGULAR) // - .output(IO_OUTPUT_CHANNEL1, false) // - .output(IO_OUTPUT_CHANNEL2, false)); + .output("io0", INPUT_OUTPUT0, false) // + .output("io0", INPUT_OUTPUT1, false)) // + .deactivate(); } @Test public void automatic_normal_config_test() throws Exception { - - final var clock = new TimeLeapClock(Instant.ofEpochSecond(1577836800) /* starts at 1. January 2020 00:00:00 */, - ZoneOffset.UTC); - new ControllerTest(new ControllerIoHeatPumpSgReadyImpl()) // - .addReference("componentManager", new DummyComponentManager(clock)) // + .addReference("componentManager", new DummyComponentManager()) // .addReference("sum", new DummySum()) // - .addComponent(new DummyInputOutput(IO_ID)) // + .addComponent(new DummyInputOutput("io0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // + .setId("ctrHeatPump0") // .setMode(Mode.AUTOMATIC) // .setAutomaticRecommendationCtrlEnabled(true) // .setAutomaticRecommendationSurplusPower(3000) // @@ -192,59 +161,57 @@ public void automatic_normal_config_test() throws Exception { .setAutomaticLockCtrlEnabled(true) // .setAutomaticLockGridBuyPower(5000) // .setAutomaticLockSoc(20) // - .setOutputChannel1(outputChannel1) // - .setOutputChannel2(outputChannel2) // + .setOutputChannel1("io0/InputOutput0") // + .setOutputChannel2("io0/InputOutput1") // .setMinimumSwitchingTime(0) // .build()) .next(new TestCase() // - .input(SUM_GRID_ACTIVE_POWER, -4000) // - .input(SUM_ESS_DISCHARGE_POWER, 0) // - .input(SUM_ESS_SOC, 95) // + .input(GRID_ACTIVE_POWER, -4000) // + .input(ESS_DISCHARGE_POWER, 0) // + .input(ESS_SOC, 95) // .output(STATUS, Status.RECOMMENDATION)) // .next(new TestCase() // - .input(SUM_GRID_ACTIVE_POWER, -3000) // - .input(SUM_ESS_DISCHARGE_POWER, 0) // - .input(SUM_ESS_SOC, 95) // + .input(GRID_ACTIVE_POWER, -3000) // + .input(ESS_DISCHARGE_POWER, 0) // + .input(ESS_SOC, 95) // .output(STATUS, Status.FORCE_ON)) // .next(new TestCase() // - .input(SUM_GRID_ACTIVE_POWER, 500) // - .input(SUM_ESS_DISCHARGE_POWER, 0) // - .input(SUM_ESS_SOC, 95) // + .input(GRID_ACTIVE_POWER, 500) // + .input(ESS_DISCHARGE_POWER, 0) // + .input(ESS_SOC, 95) // .output(STATUS, Status.RECOMMENDATION)) // .next(new TestCase() // - .input(SUM_GRID_ACTIVE_POWER, -2700) // - .input(SUM_ESS_DISCHARGE_POWER, 0) // - .input(SUM_ESS_SOC, 95) // + .input(GRID_ACTIVE_POWER, -2700) // + .input(ESS_DISCHARGE_POWER, 0) // + .input(ESS_SOC, 95) // .output(STATUS, Status.FORCE_ON)) // .next(new TestCase() // - .input(SUM_GRID_ACTIVE_POWER, -150) // - .input(SUM_ESS_DISCHARGE_POWER, 0) // - .input(SUM_ESS_SOC, 88) // + .input(GRID_ACTIVE_POWER, -150) // + .input(ESS_DISCHARGE_POWER, 0) // + .input(ESS_SOC, 88) // .output(STATUS, Status.RECOMMENDATION)) // .next(new TestCase() // - .input(SUM_GRID_ACTIVE_POWER, 500) // - .input(SUM_ESS_DISCHARGE_POWER, 0) // - .input(SUM_ESS_SOC, 88) // + .input(GRID_ACTIVE_POWER, 500) // + .input(ESS_DISCHARGE_POWER, 0) // + .input(ESS_SOC, 88) // .output(STATUS, Status.REGULAR)) .next(new TestCase() // - .input(SUM_GRID_ACTIVE_POWER, 5500) // - .input(SUM_ESS_DISCHARGE_POWER, 0) // - .input(SUM_ESS_SOC, 19) // - .output(STATUS, Status.LOCK)); + .input(GRID_ACTIVE_POWER, 5500) // + .input(ESS_DISCHARGE_POWER, 0) // + .input(ESS_SOC, 19) // + .output(STATUS, Status.LOCK)) // + .deactivate(); } @Test public void automatic_switching_time_test() throws Exception { - - final var clock = new TimeLeapClock(Instant.ofEpochSecond(1577836800) /* starts at 1. January 2020 00:00:00 */, - ZoneOffset.UTC); - + final var clock = createDummyClock(); new ControllerTest(new ControllerIoHeatPumpSgReadyImpl()) // .addReference("componentManager", new DummyComponentManager(clock)) // .addReference("sum", new DummySum()) // - .addComponent(new DummyInputOutput(IO_ID)) // + .addComponent(new DummyInputOutput("io0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // + .setId("ctrHeatPump0") // .setMode(Mode.AUTOMATIC) // .setAutomaticRecommendationCtrlEnabled(true) // .setAutomaticRecommendationSurplusPower(3000) // @@ -254,64 +221,62 @@ public void automatic_switching_time_test() throws Exception { .setAutomaticLockCtrlEnabled(true) // .setAutomaticLockGridBuyPower(5000) // .setAutomaticLockSoc(20) // - .setOutputChannel1(outputChannel1) // - .setOutputChannel2(outputChannel2) // + .setOutputChannel1("io0/InputOutput0") // + .setOutputChannel2("io0/InputOutput1") // .setMinimumSwitchingTime(60) // .build()) .next(new TestCase("Test 1") // - .input(SUM_GRID_ACTIVE_POWER, -4000) // - .input(SUM_ESS_DISCHARGE_POWER, 0) // - .input(SUM_ESS_SOC, 95) // + .input(GRID_ACTIVE_POWER, -4000) // + .input(ESS_DISCHARGE_POWER, 0) // + .input(ESS_SOC, 95) // .output(STATUS, Status.RECOMMENDATION)) // .next(new TestCase("Test 1") // - .timeleap(clock, 18, ChronoUnit.SECONDS) // + .timeleap(clock, 18, SECONDS) // .output(AWAITING_HYSTERESIS, true)) // .next(new TestCase("Test 2") // - .timeleap(clock, 18, ChronoUnit.SECONDS) // + .timeleap(clock, 18, SECONDS) // .output(AWAITING_HYSTERESIS, true)) // .next(new TestCase("Test 3") // - .timeleap(clock, 18, ChronoUnit.SECONDS) // + .timeleap(clock, 18, SECONDS) // .output(AWAITING_HYSTERESIS, true)) // .next(new TestCase("Test 4") // - .timeleap(clock, 18, ChronoUnit.SECONDS) // + .timeleap(clock, 18, SECONDS) // .output(AWAITING_HYSTERESIS, false)) .next(new TestCase("Test 5") // - .input(SUM_GRID_ACTIVE_POWER, -4000) // - .input(SUM_ESS_DISCHARGE_POWER, 0) // - .input(SUM_ESS_SOC, 95) // + .input(GRID_ACTIVE_POWER, -4000) // + .input(ESS_DISCHARGE_POWER, 0) // + .input(ESS_SOC, 95) // .output(STATUS, Status.FORCE_ON)) // .next(new TestCase("Test 6") // - .timeleap(clock, 30, ChronoUnit.SECONDS) // + .timeleap(clock, 30, SECONDS) // .output(STATUS, Status.FORCE_ON) // .output(AWAITING_HYSTERESIS, true)) // .next(new TestCase("Test 7") // - .timeleap(clock, 10, ChronoUnit.SECONDS) // - .input(SUM_GRID_ACTIVE_POWER, -500) // - .input(SUM_ESS_DISCHARGE_POWER, 0) // - .input(SUM_ESS_SOC, 95) // + .timeleap(clock, 10, SECONDS) // + .input(GRID_ACTIVE_POWER, -500) // + .input(ESS_DISCHARGE_POWER, 0) // + .input(ESS_SOC, 95) // .output(STATUS, Status.FORCE_ON) // .output(AWAITING_HYSTERESIS, true)) // .next(new TestCase("Test 8") // - .timeleap(clock, 30, ChronoUnit.SECONDS) // - .input(SUM_GRID_ACTIVE_POWER, 500) // - .input(SUM_ESS_DISCHARGE_POWER, 0) // - .input(SUM_ESS_SOC, 95) // + .timeleap(clock, 30, SECONDS) // + .input(GRID_ACTIVE_POWER, 500) // + .input(ESS_DISCHARGE_POWER, 0) // + .input(ESS_SOC, 95) // .output(AWAITING_HYSTERESIS, false) // - .output(STATUS, Status.RECOMMENDATION) // - ); + .output(STATUS, Status.RECOMMENDATION)) // + .deactivate(); } @Test public void automatic_switching2_time_test() throws Exception { - - final var clock = new TimeLeapClock(Instant.ofEpochSecond(1577836800), ZoneOffset.UTC); - - new ControllerTest(new ControllerIoHeatPumpSgReadyImpl()).addReference("componentManager", // - new DummyComponentManager(clock)) // + final var clock = createDummyClock(); + new ControllerTest(new ControllerIoHeatPumpSgReadyImpl())// + .addReference("componentManager", new DummyComponentManager(clock)) // .addReference("sum", new DummySum()) // - .addComponent(new DummyInputOutput(IO_ID)) // + .addComponent(new DummyInputOutput("io0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // + .setId("ctrHeatPump0") // .setMode(Mode.AUTOMATIC) // .setAutomaticRecommendationCtrlEnabled(true) // .setAutomaticRecommendationSurplusPower(3000) // @@ -321,63 +286,64 @@ public void automatic_switching2_time_test() throws Exception { .setAutomaticLockCtrlEnabled(true) // .setAutomaticLockGridBuyPower(5000) // .setAutomaticLockSoc(20) // - .setOutputChannel1(outputChannel1) // - .setOutputChannel2(outputChannel2) // + .setOutputChannel1("io0/InputOutput0") // + .setOutputChannel2("io0/InputOutput1") // .setMinimumSwitchingTime(60) // .build()) .next(new TestCase("Test 1") // - .input(SUM_GRID_ACTIVE_POWER, -4000) // - .input(SUM_ESS_DISCHARGE_POWER, 0) // - .input(SUM_ESS_SOC, 95) // + .input(GRID_ACTIVE_POWER, -4000) // + .input(ESS_DISCHARGE_POWER, 0) // + .input(ESS_SOC, 95) // .output(STATUS, Status.RECOMMENDATION)) // .next(new TestCase("Test 2") // - .timeleap(clock, 50, ChronoUnit.SECONDS)// - .input(SUM_GRID_ACTIVE_POWER, -3000) // - .input(SUM_ESS_DISCHARGE_POWER, 0) // - .input(SUM_ESS_SOC, 95) // + .timeleap(clock, 50, SECONDS)// + .input(GRID_ACTIVE_POWER, -3000) // + .input(ESS_DISCHARGE_POWER, 0) // + .input(ESS_SOC, 95) // .output(STATUS, Status.RECOMMENDATION) // .output(AWAITING_HYSTERESIS, true)) // .next(new TestCase("Test 3") // - .timeleap(clock, 15, ChronoUnit.SECONDS)// - .input(SUM_GRID_ACTIVE_POWER, -3000) // - .input(SUM_ESS_DISCHARGE_POWER, 0) // - .input(SUM_ESS_SOC, 95) // + .timeleap(clock, 15, SECONDS)// + .input(GRID_ACTIVE_POWER, -3000) // + .input(ESS_DISCHARGE_POWER, 0) // + .input(ESS_SOC, 95) // .output(AWAITING_HYSTERESIS, false)) // .next(new TestCase("Test 3 - Results") // .output(AWAITING_HYSTERESIS, true) // .output(STATUS, Status.FORCE_ON)) // .next(new TestCase("Test 4") // - .timeleap(clock, 65, ChronoUnit.SECONDS)// - .input(SUM_GRID_ACTIVE_POWER, -3000) // - .input(SUM_ESS_DISCHARGE_POWER, 0) // - .input(SUM_ESS_SOC, 95) // + .timeleap(clock, 65, SECONDS)// + .input(GRID_ACTIVE_POWER, -3000) // + .input(ESS_DISCHARGE_POWER, 0) // + .input(ESS_SOC, 95) // .output(AWAITING_HYSTERESIS, false) // .output(STATUS, Status.FORCE_ON)) // .next(new TestCase("Test 5") // - .timeleap(clock, 15, ChronoUnit.SECONDS)// - .input(SUM_GRID_ACTIVE_POWER, 500) // - .input(SUM_ESS_DISCHARGE_POWER, 0) // - .input(SUM_ESS_SOC, 95) // + .timeleap(clock, 15, SECONDS)// + .input(GRID_ACTIVE_POWER, 500) // + .input(ESS_DISCHARGE_POWER, 0) // + .input(ESS_SOC, 95) // .output(AWAITING_HYSTERESIS, false) // .output(STATUS, Status.RECOMMENDATION)) // .next(new TestCase("Test 6") // - .timeleap(clock, 65, ChronoUnit.SECONDS)// - .input(SUM_GRID_ACTIVE_POWER, 15000) // - .input(SUM_ESS_DISCHARGE_POWER, 0) // - .input(SUM_ESS_SOC, 15) // + .timeleap(clock, 65, SECONDS)// + .input(GRID_ACTIVE_POWER, 15000) // + .input(ESS_DISCHARGE_POWER, 0) // + .input(ESS_SOC, 15) // .output(AWAITING_HYSTERESIS, false) // .output(STATUS, Status.LOCK)) // .next(new TestCase("Test 7") // .timeleap(clock, 15, ChronoUnit.MINUTES) // - .input(SUM_GRID_ACTIVE_POWER, -2700) // - .input(SUM_ESS_DISCHARGE_POWER, 0) // - .input(SUM_ESS_SOC, 95) // + .input(GRID_ACTIVE_POWER, -2700) // + .input(ESS_DISCHARGE_POWER, 0) // + .input(ESS_SOC, 95) // .output(STATUS, Status.REGULAR)) // .next(new TestCase("Test 8") // .timeleap(clock, 15, ChronoUnit.MINUTES)// - .input(SUM_GRID_ACTIVE_POWER, -15000) // - .input(SUM_ESS_DISCHARGE_POWER, 0) // - .input(SUM_ESS_SOC, 88) // - .output(STATUS, Status.RECOMMENDATION)); // + .input(GRID_ACTIVE_POWER, -15000) // + .input(ESS_DISCHARGE_POWER, 0) // + .input(ESS_SOC, 88) // + .output(STATUS, Status.RECOMMENDATION)) // + .deactivate(); } } diff --git a/io.openems.edge.controller.pvinverter.fixpowerlimit/test/io/openems/edge/controller/pvinverter/fixpowerlimit/ControllerPvInverterFixPowerLimitImplTest.java b/io.openems.edge.controller.pvinverter.fixpowerlimit/test/io/openems/edge/controller/pvinverter/fixpowerlimit/ControllerPvInverterFixPowerLimitImplTest.java index 03b22d8e4ce..f854cb3e17d 100644 --- a/io.openems.edge.controller.pvinverter.fixpowerlimit/test/io/openems/edge/controller/pvinverter/fixpowerlimit/ControllerPvInverterFixPowerLimitImplTest.java +++ b/io.openems.edge.controller.pvinverter.fixpowerlimit/test/io/openems/edge/controller/pvinverter/fixpowerlimit/ControllerPvInverterFixPowerLimitImplTest.java @@ -7,19 +7,16 @@ public class ControllerPvInverterFixPowerLimitImplTest { - private static final String CTRL_ID = "ctrl0"; - private static final String PV_INVERTER_ID = "pvInverter0"; - @Test public void test() throws Exception { new ControllerTest(new ControllerPvInverterFixPowerLimitImpl()) // .addReference("componentManager", new DummyComponentManager()) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setPvInverterId(PV_INVERTER_ID) // + .setId("ctrl0") // + .setPvInverterId("pvInverter0") // .setPowerLimit(10000) // - .build()); // - ; + .build()) // + .deactivate(); } } diff --git a/io.openems.edge.controller.pvinverter.selltogridlimit/test/io/openems/edge/controller/pvinverter/selltogridlimit/ControllerPvInverterSellToGridLimitImplTest.java b/io.openems.edge.controller.pvinverter.selltogridlimit/test/io/openems/edge/controller/pvinverter/selltogridlimit/ControllerPvInverterSellToGridLimitImplTest.java index f1d89b53e25..ef3bc2313cb 100644 --- a/io.openems.edge.controller.pvinverter.selltogridlimit/test/io/openems/edge/controller/pvinverter/selltogridlimit/ControllerPvInverterSellToGridLimitImplTest.java +++ b/io.openems.edge.controller.pvinverter.selltogridlimit/test/io/openems/edge/controller/pvinverter/selltogridlimit/ControllerPvInverterSellToGridLimitImplTest.java @@ -1,153 +1,148 @@ package io.openems.edge.controller.pvinverter.selltogridlimit; +import static io.openems.common.types.OpenemsType.INTEGER; +import static io.openems.edge.common.type.TypeUtils.getAsType; +import static io.openems.edge.controller.pvinverter.selltogridlimit.ControllerPvInverterSellToGridLimitImpl.DEFAULT_MAX_ADJUSTMENT_RATE; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.ACTIVE_POWER; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.ACTIVE_POWER_L1; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.ACTIVE_POWER_L2; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.ACTIVE_POWER_L3; +import static io.openems.edge.pvinverter.api.ManagedSymmetricPvInverter.ChannelId.ACTIVE_POWER_LIMIT; + import org.junit.Test; -import io.openems.common.types.ChannelAddress; -import io.openems.common.types.OpenemsType; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; -import io.openems.edge.common.type.TypeUtils; import io.openems.edge.controller.test.ControllerTest; import io.openems.edge.meter.test.DummyElectricityMeter; import io.openems.edge.pvinverter.test.DummyManagedSymmetricPvInverter; public class ControllerPvInverterSellToGridLimitImplTest { - private static final String CTRL_ID = "ctrl0"; - - private static final String METER_ID = "meter0"; - private static final ChannelAddress GRID_ACTIVE_POWER = new ChannelAddress(METER_ID, "ActivePower"); - private static final ChannelAddress GRID_ACTIVE_POWER_L1 = new ChannelAddress(METER_ID, "ActivePowerL1"); - private static final ChannelAddress GRID_ACTIVE_POWER_L2 = new ChannelAddress(METER_ID, "ActivePowerL2"); - private static final ChannelAddress GRID_ACTIVE_POWER_L3 = new ChannelAddress(METER_ID, "ActivePowerL3"); - - private static final String PV_INVERTER = "pvInverter0"; - private static final ChannelAddress PV_INVERTER_ACTIVE_POWER = new ChannelAddress(PV_INVERTER, "ActivePower"); - private static final ChannelAddress PV_INVERTER_SET_ACTIVE_POWER_EQUALS = new ChannelAddress(PV_INVERTER, - "ActivePowerLimit"); - - private static final double ADJUST_RATE = ControllerPvInverterSellToGridLimitImpl.DEFAULT_MAX_ADJUSTMENT_RATE; - @Test public void symmetricMeterTest() throws Exception { new ControllerTest(new ControllerPvInverterSellToGridLimitImpl()) // .addReference("componentManager", new DummyComponentManager()) // - .addComponent(new DummyElectricityMeter(METER_ID)) // - .addComponent(new DummyManagedSymmetricPvInverter(PV_INVERTER)).activate(MyConfig.create() // - .setId(CTRL_ID) // - .setMeterId(METER_ID) // + .addComponent(new DummyElectricityMeter("meter0")) // + .addComponent(new DummyManagedSymmetricPvInverter("pvInverter0")) // + .activate(MyConfig.create() // + .setId("ctrl0") // + .setMeterId("meter0") // .setAsymmetricMode(false) // .setMaximumSellToGridPower(10_000) // - .setPvInverterId(PV_INVERTER) // + .setPvInverterId("pvInverter0") // .build()) .next(new TestCase() // - .input(GRID_ACTIVE_POWER, -15000) // - .input(PV_INVERTER_ACTIVE_POWER, 15000) // - .output(PV_INVERTER_SET_ACTIVE_POWER_EQUALS, 10000)) // + .input("meter0", ACTIVE_POWER, -15000) // + .input("pvInverter0", ACTIVE_POWER, 15000) // + .output("pvInverter0", ACTIVE_POWER_LIMIT, 10000)) // .next(new TestCase() // - .input(GRID_ACTIVE_POWER, -15000) // - .input(PV_INVERTER_ACTIVE_POWER, 10000) // - .output(PV_INVERTER_SET_ACTIVE_POWER_EQUALS, - TypeUtils.getAsType(OpenemsType.INTEGER, 10000 - 10000 * ADJUST_RATE))) // 5000 -> 8000 + .input("meter0", ACTIVE_POWER, -15000) // + .input("pvInverter0", ACTIVE_POWER, 10000) // + .output("pvInverter0", ACTIVE_POWER_LIMIT, + getAsType(INTEGER, 10000 - 10000 * DEFAULT_MAX_ADJUSTMENT_RATE))) // 5000 -> 8000 .next(new TestCase() // - .input(GRID_ACTIVE_POWER, -13000) // - .input(PV_INVERTER_ACTIVE_POWER, 8000) // - .output(PV_INVERTER_SET_ACTIVE_POWER_EQUALS, - TypeUtils.getAsType(OpenemsType.INTEGER, 8000 - 8000 * ADJUST_RATE))) // 5000 -> 6400 + .input("meter0", ACTIVE_POWER, -13000) // + .input("pvInverter0", ACTIVE_POWER, 8000) // + .output("pvInverter0", ACTIVE_POWER_LIMIT, + getAsType(INTEGER, 8000 - 8000 * DEFAULT_MAX_ADJUSTMENT_RATE))) // 5000 -> 6400 .next(new TestCase() // - .input(GRID_ACTIVE_POWER, -11400) // - .input(PV_INVERTER_ACTIVE_POWER, 6400) // - .output(PV_INVERTER_SET_ACTIVE_POWER_EQUALS, - TypeUtils.getAsType(OpenemsType.INTEGER, 6400 - 6400 * ADJUST_RATE))) // 5000 -> 5120 + .input("meter0", ACTIVE_POWER, -11400) // + .input("pvInverter0", ACTIVE_POWER, 6400) // + .output("pvInverter0", ACTIVE_POWER_LIMIT, + getAsType(INTEGER, 6400 - 6400 * DEFAULT_MAX_ADJUSTMENT_RATE))) // 5000 -> 5120 .next(new TestCase() // - .input(GRID_ACTIVE_POWER, -10120) // - .input(PV_INVERTER_ACTIVE_POWER, 5120) // - .output(PV_INVERTER_SET_ACTIVE_POWER_EQUALS, 5000)) // + .input("meter0", ACTIVE_POWER, -10120) // + .input("pvInverter0", ACTIVE_POWER, 5120) // + .output("pvInverter0", ACTIVE_POWER_LIMIT, 5000)) // .next(new TestCase() // - .input(GRID_ACTIVE_POWER, -9000) // - .input(PV_INVERTER_ACTIVE_POWER, 5000) // - .output(PV_INVERTER_SET_ACTIVE_POWER_EQUALS, 6000)) // + .input("meter0", ACTIVE_POWER, -9000) // + .input("pvInverter0", ACTIVE_POWER, 5000) // + .output("pvInverter0", ACTIVE_POWER_LIMIT, 6000)) // .next(new TestCase() // - .input(GRID_ACTIVE_POWER, 0) // - .input(PV_INVERTER_ACTIVE_POWER, 6000) // - .output(PV_INVERTER_SET_ACTIVE_POWER_EQUALS, - TypeUtils.getAsType(OpenemsType.INTEGER, 6000 + 6000 * ADJUST_RATE))); // 16000 -> 7200 + .input("meter0", ACTIVE_POWER, 0) // + .input("pvInverter0", ACTIVE_POWER, 6000) // + .output("pvInverter0", ACTIVE_POWER_LIMIT, + getAsType(INTEGER, 6000 + 6000 * DEFAULT_MAX_ADJUSTMENT_RATE))) // 16000 -> 7200 + .deactivate(); } @Test public void asymmetricMeterTest() throws Exception { new ControllerTest(new ControllerPvInverterSellToGridLimitImpl()) // .addReference("componentManager", new DummyComponentManager()) // - .addComponent(new DummyElectricityMeter(METER_ID)) // - .addComponent(new DummyManagedSymmetricPvInverter(PV_INVERTER)).activate(MyConfig.create() // - .setId(CTRL_ID) // - .setMeterId(METER_ID) // + .addComponent(new DummyElectricityMeter("meter0")) // + .addComponent(new DummyManagedSymmetricPvInverter("pvInverter0")) // + .activate(MyConfig.create() // + .setId("ctrl0") // + .setMeterId("meter0") // .setAsymmetricMode(true) // .setMaximumSellToGridPower(4_000) // 12_000 in total - .setPvInverterId(PV_INVERTER) // + .setPvInverterId("pvInverter0") // .build()) .next(new TestCase() // - .input(GRID_ACTIVE_POWER_L1, -2000) // - .input(GRID_ACTIVE_POWER_L2, -4000) // - .input(GRID_ACTIVE_POWER_L3, -3000) // - .input(PV_INVERTER_ACTIVE_POWER, 12000) // - .output(PV_INVERTER_SET_ACTIVE_POWER_EQUALS, 12000)) // + .input("meter0", ACTIVE_POWER_L1, -2000) // + .input("meter0", ACTIVE_POWER_L2, -4000) // + .input("meter0", ACTIVE_POWER_L3, -3000) // + .input("pvInverter0", ACTIVE_POWER, 12000) // + .output("pvInverter0", ACTIVE_POWER_LIMIT, 12000)) // .next(new TestCase() // - .input(GRID_ACTIVE_POWER_L1, -2000) // - .input(GRID_ACTIVE_POWER_L2, -5000) // - .input(GRID_ACTIVE_POWER_L3, -2000) // - .input(PV_INVERTER_ACTIVE_POWER, 12000) // - .output(PV_INVERTER_SET_ACTIVE_POWER_EQUALS, - TypeUtils.getAsType(OpenemsType.INTEGER, 12000 - 12000 * ADJUST_RATE))) // 9000 -> 9600 + .input("meter0", ACTIVE_POWER_L1, -2000) // + .input("meter0", ACTIVE_POWER_L2, -5000) // + .input("meter0", ACTIVE_POWER_L3, -2000) // + .input("pvInverter0", ACTIVE_POWER, 12000) // + .output("pvInverter0", ACTIVE_POWER_LIMIT, + getAsType(INTEGER, 12000 - 12000 * DEFAULT_MAX_ADJUSTMENT_RATE))) // 9000 -> 9600 .next(new TestCase() // - .input(GRID_ACTIVE_POWER_L1, -1200) // - .input(GRID_ACTIVE_POWER_L2, -4200) // - .input(GRID_ACTIVE_POWER_L3, -1200) // - .input(PV_INVERTER_ACTIVE_POWER, 9600) // - .output(PV_INVERTER_SET_ACTIVE_POWER_EQUALS, 9000)) // + .input("meter0", ACTIVE_POWER_L1, -1200) // + .input("meter0", ACTIVE_POWER_L2, -4200) // + .input("meter0", ACTIVE_POWER_L3, -1200) // + .input("pvInverter0", ACTIVE_POWER, 9600) // + .output("pvInverter0", ACTIVE_POWER_LIMIT, 9000)) // .next(new TestCase() // - .input(GRID_ACTIVE_POWER_L1, -1000) // - .input(GRID_ACTIVE_POWER_L2, -4000) // - .input(GRID_ACTIVE_POWER_L3, -1000) // - .input(PV_INVERTER_ACTIVE_POWER, 9000) // - .output(PV_INVERTER_SET_ACTIVE_POWER_EQUALS, 9000)) // + .input("meter0", ACTIVE_POWER_L1, -1000) // + .input("meter0", ACTIVE_POWER_L2, -4000) // + .input("meter0", ACTIVE_POWER_L3, -1000) // + .input("pvInverter0", ACTIVE_POWER, 9000) // + .output("pvInverter0", ACTIVE_POWER_LIMIT, 9000)) // .next(new TestCase() // - .input(GRID_ACTIVE_POWER_L1, -1000) // - .input(GRID_ACTIVE_POWER_L2, -3700) // - .input(GRID_ACTIVE_POWER_L3, -1000) // - .input(PV_INVERTER_ACTIVE_POWER, 9000) // - .output(PV_INVERTER_SET_ACTIVE_POWER_EQUALS, 9900)) // + .input("meter0", ACTIVE_POWER_L1, -1000) // + .input("meter0", ACTIVE_POWER_L2, -3700) // + .input("meter0", ACTIVE_POWER_L3, -1000) // + .input("pvInverter0", ACTIVE_POWER, 9000) // + .output("pvInverter0", ACTIVE_POWER_LIMIT, 9900)) // .next(new TestCase() // - .input(GRID_ACTIVE_POWER_L1, -2000) // - .input(GRID_ACTIVE_POWER_L2, -5000) // - .input(GRID_ACTIVE_POWER_L3, -2000) // - .input(PV_INVERTER_ACTIVE_POWER, 9900) // - .output(PV_INVERTER_SET_ACTIVE_POWER_EQUALS, - TypeUtils.getAsType(OpenemsType.INTEGER, 9900 - 9900 * ADJUST_RATE))) // 6900 -> 7920 + .input("meter0", ACTIVE_POWER_L1, -2000) // + .input("meter0", ACTIVE_POWER_L2, -5000) // + .input("meter0", ACTIVE_POWER_L3, -2000) // + .input("pvInverter0", ACTIVE_POWER, 9900) // + .output("pvInverter0", ACTIVE_POWER_LIMIT, + getAsType(INTEGER, 9900 - 9900 * DEFAULT_MAX_ADJUSTMENT_RATE))) // 6900 -> 7920 .next(new TestCase() // - .input(GRID_ACTIVE_POWER_L1, -2000) // - .input(GRID_ACTIVE_POWER_L2, -5000) // - .input(GRID_ACTIVE_POWER_L3, -2000) // - .input(PV_INVERTER_ACTIVE_POWER, 7920) // - .output(PV_INVERTER_SET_ACTIVE_POWER_EQUALS, - TypeUtils.getAsType(OpenemsType.INTEGER, 7920 - 7920 * ADJUST_RATE))); // 4920 -> 6336 + .input("meter0", ACTIVE_POWER_L1, -2000) // + .input("meter0", ACTIVE_POWER_L2, -5000) // + .input("meter0", ACTIVE_POWER_L3, -2000) // + .input("pvInverter0", ACTIVE_POWER, 7920) // + .output("pvInverter0", ACTIVE_POWER_LIMIT, + getAsType(INTEGER, 7920 - 7920 * DEFAULT_MAX_ADJUSTMENT_RATE))); // 4920 -> 6336 new ControllerTest(new ControllerPvInverterSellToGridLimitImpl()) // .addReference("componentManager", new DummyComponentManager()) // - .addComponent(new DummyElectricityMeter(METER_ID)) // - .addComponent(new DummyManagedSymmetricPvInverter(PV_INVERTER)).activate(MyConfig.create() // - .setId(CTRL_ID) // - .setMeterId(METER_ID) // + .addComponent(new DummyElectricityMeter("meter0")) // + .addComponent(new DummyManagedSymmetricPvInverter("pvInverter0")) // + .activate(MyConfig.create() // + .setId("ctrl0") // + .setMeterId("meter0") // .setAsymmetricMode(true) // .setMaximumSellToGridPower(4_000) // 12_000 in total - .setPvInverterId(PV_INVERTER) // + .setPvInverterId("pvInverter0") // .build()) .next(new TestCase() // - .input(GRID_ACTIVE_POWER_L1, 1000) // - .input(GRID_ACTIVE_POWER_L2, 2000) // - .input(GRID_ACTIVE_POWER_L3, 3000) // - .input(PV_INVERTER_ACTIVE_POWER, 1000) // - .output(PV_INVERTER_SET_ACTIVE_POWER_EQUALS, 16000)) // - ; + .input("meter0", ACTIVE_POWER_L1, 1000) // + .input("meter0", ACTIVE_POWER_L2, 2000) // + .input("meter0", ACTIVE_POWER_L3, 3000) // + .input("pvInverter0", ACTIVE_POWER, 1000) // + .output("pvInverter0", ACTIVE_POWER_LIMIT, 16000)) // + .deactivate(); } } diff --git a/io.openems.edge.controller.symmetric.balancingschedule/test/io/openems/edge/controller/symmetric/balancingschedule/ControllerEssBalancingScheduleImplTest.java b/io.openems.edge.controller.symmetric.balancingschedule/test/io/openems/edge/controller/symmetric/balancingschedule/ControllerEssBalancingScheduleImplTest.java index 7501e1d9d60..ed88ef4c8be 100644 --- a/io.openems.edge.controller.symmetric.balancingschedule/test/io/openems/edge/controller/symmetric/balancingschedule/ControllerEssBalancingScheduleImplTest.java +++ b/io.openems.edge.controller.symmetric.balancingschedule/test/io/openems/edge/controller/symmetric/balancingschedule/ControllerEssBalancingScheduleImplTest.java @@ -1,39 +1,31 @@ package io.openems.edge.controller.symmetric.balancingschedule; +import static io.openems.common.utils.JsonUtils.buildJsonArray; +import static io.openems.common.utils.JsonUtils.buildJsonObject; +import static io.openems.edge.controller.symmetric.balancingschedule.ControllerEssBalancingSchedule.ChannelId.GRID_ACTIVE_POWER_SET_POINT; +import static io.openems.edge.controller.symmetric.balancingschedule.ControllerEssBalancingSchedule.ChannelId.NO_ACTIVE_SETPOINT; +import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_EQUALS_WITH_PID; +import static io.openems.edge.ess.api.SymmetricEss.ChannelId.GRID_MODE; +import static java.time.temporal.ChronoUnit.SECONDS; + import java.time.Instant; import java.time.ZoneOffset; -import java.time.temporal.ChronoUnit; import org.junit.Test; import io.openems.common.test.TimeLeapClock; -import io.openems.common.types.ChannelAddress; -import io.openems.common.utils.JsonUtils; import io.openems.edge.common.sum.GridMode; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.common.test.DummyConfigurationAdmin; import io.openems.edge.controller.test.ControllerTest; +import io.openems.edge.ess.api.SymmetricEss; import io.openems.edge.ess.test.DummyManagedSymmetricEss; +import io.openems.edge.meter.api.ElectricityMeter; import io.openems.edge.meter.test.DummyElectricityMeter; public class ControllerEssBalancingScheduleImplTest { - private static final String CTRL_ID = "ctrl0"; - private static final String ESS_ID = "ess0"; - private static final String METER_ID = "meter0"; - - private static final ChannelAddress CTRL_NO_ACTIVE_SETPOINT = new ChannelAddress(CTRL_ID, "NoActiveSetpoint"); - private static final ChannelAddress CTRL_GRID_ACTIVE_POWER_SET_POINT = new ChannelAddress(CTRL_ID, - "GridActivePowerSetPoint"); - - private static final ChannelAddress ESS_GRID_MODE = new ChannelAddress(ESS_ID, "GridMode"); - private static final ChannelAddress ESS_ACTIVE_POWER = new ChannelAddress(ESS_ID, "ActivePower"); - private static final ChannelAddress SET_ACTIVE_POWER_EQUALS_WITH_PID = new ChannelAddress(ESS_ID, - "SetActivePowerEqualsWithPid"); - - private static final ChannelAddress GRID_ACTIVE_POWER = new ChannelAddress(METER_ID, "ActivePower"); - @Test public void test() throws Exception { final var start = 1577836800L; @@ -42,47 +34,47 @@ public void test() throws Exception { new ControllerTest(new ControllerEssBalancingScheduleImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager(clock)) // - .addReference("ess", new DummyManagedSymmetricEss(ESS_ID)) // - .addReference("meter", new DummyElectricityMeter(METER_ID)) // + .addReference("ess", new DummyManagedSymmetricEss("ess0")) // + .addReference("meter", new DummyElectricityMeter("meter0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // - .setMeterId(METER_ID) // - .setSchedule(JsonUtils.buildJsonArray()// - .add(JsonUtils.buildJsonObject()// + .setId("ctrl0") // + .setEssId("ess0") // + .setMeterId("meter0") // + .setSchedule(buildJsonArray()// + .add(buildJsonObject()// .addProperty("startTimestamp", start + 500) // .addProperty("duration", 900) // .addProperty("activePowerSetPoint", 0) // .build()) // - .add(JsonUtils.buildJsonObject()// + .add(buildJsonObject()// .addProperty("startTimestamp", start + 500 + 800) // .addProperty("duration", 900) // .addProperty("activePowerSetPoint", 3000) // - .build() // - ).build().toString() // - ).build()) // + .build()) // + .build().toString()) // + .build()) // .next(new TestCase("No active setpoint") // - .input(ESS_GRID_MODE, GridMode.ON_GRID) // - .input(GRID_ACTIVE_POWER, 4000) // - .input(ESS_ACTIVE_POWER, 1000) // - .output(CTRL_NO_ACTIVE_SETPOINT, true)) // + .input("ess0", GRID_MODE, GridMode.ON_GRID) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 4000) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 1000) // + .output(NO_ACTIVE_SETPOINT, true)) // .next(new TestCase("Balance to 0") // - .timeleap(clock, 500, ChronoUnit.SECONDS) // - .input(GRID_ACTIVE_POWER, 4000) // - .input(ESS_ACTIVE_POWER, 1000) // - .output(CTRL_NO_ACTIVE_SETPOINT, false) // - .output(SET_ACTIVE_POWER_EQUALS_WITH_PID, 5000)) // + .timeleap(clock, 500, SECONDS) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 4000) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 1000) // + .output(NO_ACTIVE_SETPOINT, false) // + .output("ess0", SET_ACTIVE_POWER_EQUALS_WITH_PID, 5000)) // .next(new TestCase("Balance to -2000 via Channel") // - .input(CTRL_GRID_ACTIVE_POWER_SET_POINT, -2000) // - .input(GRID_ACTIVE_POWER, 4000) // - .input(ESS_ACTIVE_POWER, 1000) // - .output(SET_ACTIVE_POWER_EQUALS_WITH_PID, 7000)) // + .input(GRID_ACTIVE_POWER_SET_POINT, -2000) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 4000) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 1000) // + .output("ess0", SET_ACTIVE_POWER_EQUALS_WITH_PID, 7000)) // .next(new TestCase("Balance to 3000") // - .timeleap(clock, 800, ChronoUnit.SECONDS) // - .input(GRID_ACTIVE_POWER, 4000) // - .input(ESS_ACTIVE_POWER, 1000) // - .output(CTRL_NO_ACTIVE_SETPOINT, false) // - .output(SET_ACTIVE_POWER_EQUALS_WITH_PID, 2000)) // - ; + .timeleap(clock, 800, SECONDS) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 4000) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 1000) // + .output(NO_ACTIVE_SETPOINT, false) // + .output("ess0", SET_ACTIVE_POWER_EQUALS_WITH_PID, 2000)) // + .deactivate(); } } diff --git a/io.openems.edge.controller.symmetric.fixreactivepower/test/io/openems/edge/controller/symmetric/fixreactivepower/ControllerEssFixReactivePowerImplTest.java b/io.openems.edge.controller.symmetric.fixreactivepower/test/io/openems/edge/controller/symmetric/fixreactivepower/ControllerEssFixReactivePowerImplTest.java index 9ffd8bebe22..f576936930b 100644 --- a/io.openems.edge.controller.symmetric.fixreactivepower/test/io/openems/edge/controller/symmetric/fixreactivepower/ControllerEssFixReactivePowerImplTest.java +++ b/io.openems.edge.controller.symmetric.fixreactivepower/test/io/openems/edge/controller/symmetric/fixreactivepower/ControllerEssFixReactivePowerImplTest.java @@ -7,19 +7,16 @@ public class ControllerEssFixReactivePowerImplTest { - private static final String CTRL_ID = "ctrl0"; - private static final String ESS_ID = "ess0"; - @Test public void test() throws Exception { new ControllerTest(new ControllerEssFixReactivePowerImpl()) // .addReference("componentManager", new DummyComponentManager()) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setPower(1000) // - .build()); // - ; + .build()) // + .deactivate(); } } diff --git a/io.openems.edge.controller.symmetric.limitactivepower/test/io/openems/edge/controller/symmetric/limitactivepower/ControllerEssLimitActivePowerImplTest.java b/io.openems.edge.controller.symmetric.limitactivepower/test/io/openems/edge/controller/symmetric/limitactivepower/ControllerEssLimitActivePowerImplTest.java index c9261c90ed3..ace177e6000 100644 --- a/io.openems.edge.controller.symmetric.limitactivepower/test/io/openems/edge/controller/symmetric/limitactivepower/ControllerEssLimitActivePowerImplTest.java +++ b/io.openems.edge.controller.symmetric.limitactivepower/test/io/openems/edge/controller/symmetric/limitactivepower/ControllerEssLimitActivePowerImplTest.java @@ -7,21 +7,18 @@ public class ControllerEssLimitActivePowerImplTest { - private static final String CTRL_ID = "ctrl0"; - private static final String ESS_ID = "ess0"; - @Test public void test() throws Exception { new ControllerTest(new ControllerEssLimitActivePowerImpl()) // .addReference("componentManager", new DummyComponentManager()) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setMaxChargePower(1000) // .setMaxDischargePower(1000) // .setValidatePowerConstraints(false) // - .build()); // - ; + .build()) // + .deactivate(); } } diff --git a/io.openems.edge.controller.symmetric.peakshaving/test/io/openems/edge/controller/symmetric/peakshaving/ControllerEssPeakShavingImplTest.java b/io.openems.edge.controller.symmetric.peakshaving/test/io/openems/edge/controller/symmetric/peakshaving/ControllerEssPeakShavingImplTest.java index b1af67695a4..5249a7598aa 100644 --- a/io.openems.edge.controller.symmetric.peakshaving/test/io/openems/edge/controller/symmetric/peakshaving/ControllerEssPeakShavingImplTest.java +++ b/io.openems.edge.controller.symmetric.peakshaving/test/io/openems/edge/controller/symmetric/peakshaving/ControllerEssPeakShavingImplTest.java @@ -1,97 +1,91 @@ package io.openems.edge.controller.symmetric.peakshaving; +import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_EQUALS; + import org.junit.Test; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.controller.test.ControllerTest; +import io.openems.edge.ess.api.SymmetricEss; import io.openems.edge.ess.test.DummyManagedSymmetricEss; import io.openems.edge.ess.test.DummyPower; +import io.openems.edge.meter.api.ElectricityMeter; import io.openems.edge.meter.test.DummyElectricityMeter; public class ControllerEssPeakShavingImplTest { - private static final String CTRL_ID = "ctrl0"; - - private static final String ESS_ID = "ess0"; - private static final ChannelAddress ESS_ACTIVE_POWER = new ChannelAddress(ESS_ID, "ActivePower"); - private static final ChannelAddress ESS_SET_ACTIVE_POWER_EQUALS = new ChannelAddress(ESS_ID, - "SetActivePowerEquals"); - - private static final String METER_ID = "meter0"; - private static final ChannelAddress METER_ACTIVE_POWER = new ChannelAddress(METER_ID, "ActivePower"); - @Test public void test() throws Exception { new ControllerTest(new ControllerEssPeakShavingImpl()) // .addReference("componentManager", new DummyComponentManager()) // - .addComponent(new DummyManagedSymmetricEss(ESS_ID) // + .addComponent(new DummyManagedSymmetricEss("ess0") // .setPower(new DummyPower(0.3, 0.3, 0.1))) // - .addComponent(new DummyElectricityMeter(METER_ID)) // + .addComponent(new DummyElectricityMeter("meter0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // - .setMeterId(METER_ID) // + .setId("ctrl0") // + .setEssId("ess0") // + .setMeterId("meter0") // .setPeakShavingPower(100_000) // .setRechargePower(50_000) // .build()) .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 0) // - .input(METER_ACTIVE_POWER, 120000) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 6000)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 0) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 120000) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 6000)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 0) // - .input(METER_ACTIVE_POWER, 120000) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 12000)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 0) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 120000) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 12000)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 3793) // - .input(METER_ACTIVE_POWER, 120000 - 3793) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 16483)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 3793) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 120000 - 3793) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 16483)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 8981) // - .input(METER_ACTIVE_POWER, 120000 - 8981) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 19649)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 8981) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 120000 - 8981) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 19649)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 13723) // - .input(METER_ACTIVE_POWER, 120000 - 13723) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 21577)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 13723) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 120000 - 13723) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 21577)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 17469) // - .input(METER_ACTIVE_POWER, 120000 - 17469) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 22436)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 17469) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 120000 - 17469) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 22436)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 20066) // - .input(METER_ACTIVE_POWER, 120000 - 20066) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 22531)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 20066) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 120000 - 20066) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 22531)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 21564) // - .input(METER_ACTIVE_POWER, 120000 - 21564) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 22171)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 21564) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 120000 - 21564) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 22171)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 22175) // - .input(METER_ACTIVE_POWER, 120000 - 22175) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 21608)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 22175) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 120000 - 22175) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 21608)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 22173) // - .input(METER_ACTIVE_POWER, 120000 - 22173) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 21017)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 22173) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 120000 - 22173) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 21017)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 21816) // - .input(METER_ACTIVE_POWER, 120000 - 21816) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 20508)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 21816) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 120000 - 21816) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 20508)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 21311) // - .input(METER_ACTIVE_POWER, 120000 - 21311) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 20129)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 21311) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 120000 - 21311) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 20129)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 20803) // - .input(METER_ACTIVE_POWER, 120000 - 20803) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 19889)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 20803) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 120000 - 20803) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 19889)) // .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 20377) // - .input(METER_ACTIVE_POWER, 120000 - 20377) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 19767)); // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 20377) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 120000 - 20377) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 19767)) // + .deactivate(); } } diff --git a/io.openems.edge.controller.symmetric.randompower/test/io/openems/edge/controller/symmetric/randompower/ControllerEssRandomPowerImplTest.java b/io.openems.edge.controller.symmetric.randompower/test/io/openems/edge/controller/symmetric/randompower/ControllerEssRandomPowerImplTest.java index 94172daab79..ab9b1bfd8f3 100644 --- a/io.openems.edge.controller.symmetric.randompower/test/io/openems/edge/controller/symmetric/randompower/ControllerEssRandomPowerImplTest.java +++ b/io.openems.edge.controller.symmetric.randompower/test/io/openems/edge/controller/symmetric/randompower/ControllerEssRandomPowerImplTest.java @@ -7,19 +7,17 @@ public class ControllerEssRandomPowerImplTest { - private static final String CTRL_ID = "ctrl0"; - private static final String ESS_ID = "ess0"; - @Test public void test() throws Exception { new ControllerTest(new ControllerEssRandomPowerImpl()) // .addReference("componentManager", new DummyComponentManager()) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // + .setId("ctrl0") // + .setEssId("ess0") // .setMinPower(0) // .setMaxPower(1000) // - .build()); // + .build()) // + .deactivate(); } } diff --git a/io.openems.edge.controller.symmetric.timeslotpeakshaving/test/io/openems/edge/controller/timeslotpeakshaving/ControllerEssTimeslotPeakshavingImplTest.java b/io.openems.edge.controller.symmetric.timeslotpeakshaving/test/io/openems/edge/controller/timeslotpeakshaving/ControllerEssTimeslotPeakshavingImplTest.java index f8f7066afcf..fb6cb7828ec 100644 --- a/io.openems.edge.controller.symmetric.timeslotpeakshaving/test/io/openems/edge/controller/timeslotpeakshaving/ControllerEssTimeslotPeakshavingImplTest.java +++ b/io.openems.edge.controller.symmetric.timeslotpeakshaving/test/io/openems/edge/controller/timeslotpeakshaving/ControllerEssTimeslotPeakshavingImplTest.java @@ -1,47 +1,40 @@ package io.openems.edge.controller.timeslotpeakshaving; +import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_EQUALS; +import static io.openems.edge.ess.api.SymmetricEss.ChannelId.SOC; +import static java.time.temporal.ChronoUnit.MINUTES; + import java.time.Instant; import java.time.ZoneOffset; -import java.time.temporal.ChronoUnit; import org.junit.Test; import io.openems.common.test.TimeLeapClock; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.sum.GridMode; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.controller.test.ControllerTest; +import io.openems.edge.ess.api.SymmetricEss; import io.openems.edge.ess.test.DummyManagedSymmetricEss; import io.openems.edge.ess.test.DummyPower; +import io.openems.edge.meter.api.ElectricityMeter; import io.openems.edge.meter.test.DummyElectricityMeter; public class ControllerEssTimeslotPeakshavingImplTest { - private static final String CTRL_ID = "ctrl0"; - - private static final String ESS_ID = "ess0"; - private static final ChannelAddress ESS_SOC = new ChannelAddress(ESS_ID, "Soc"); - private static final ChannelAddress ESS_ACTIVE_POWER = new ChannelAddress(ESS_ID, "ActivePower"); - private static final ChannelAddress ESS_SET_ACTIVE_POWER_EQUALS = new ChannelAddress(ESS_ID, - "SetActivePowerEquals"); - - private static final String METER_ID = "meter0"; - private static final ChannelAddress METER_ACTIVE_POWER = new ChannelAddress(METER_ID, "ActivePower"); - @Test public void test() throws Exception { final var clock = new TimeLeapClock(Instant.parse("2020-02-03T08:30:00.00Z"), ZoneOffset.UTC); new ControllerTest(new ControllerEssTimeslotPeakshavingImpl()) // .addReference("componentManager", new DummyComponentManager(clock)) // - .addComponent(new DummyManagedSymmetricEss(ESS_ID) // + .addComponent(new DummyManagedSymmetricEss("ess0") // .setPower(new DummyPower(0.3, 0.3, 0.1)) // .withGridMode(GridMode.ON_GRID)) // - .addComponent(new DummyElectricityMeter(METER_ID)) // + .addComponent(new DummyElectricityMeter("meter0")) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // - .setMeterId(METER_ID) // + .setId("ctrl0") // + .setEssId("ess0") // + .setMeterId("meter0") // .setPeakShavingPower(100_000) // .setRechargePower(50_000) // .setSlowChargePower(50_000) // @@ -60,34 +53,37 @@ public void test() throws Exception { .setSunday(true) // .build()) .next(new TestCase() // - .input(ESS_ACTIVE_POWER, 0) // - .input(ESS_SOC, 90) // - .input(METER_ACTIVE_POWER, 120000) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, null)) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 0) // + .input("ess0", SOC, 90) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 120000) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, null)) // .next(new TestCase() // - .timeleap(clock, 31, ChronoUnit.MINUTES)/* current time is 09:31, run in slow charge state */ - .input(ESS_SOC, 96) // - .input(ESS_ACTIVE_POWER, 5000) // - .input(METER_ACTIVE_POWER, 120000) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 13500)) // + .timeleap(clock, 31, MINUTES)/* current time is 09:31, run in slow charge state */ + .input("ess0", SOC, 96) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 5000) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 120000) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 13500)) // .next(new TestCase() // - .timeleap(clock, 31, ChronoUnit.MINUTES)/* current time is 09:31, run in hysterisis state */ - .input(ESS_SOC, 100) // - .input(ESS_ACTIVE_POWER, 5000) // - .input(METER_ACTIVE_POWER, 120000)) // nothing set on, Ess's setActivePower + .timeleap(clock, 31, MINUTES)/* current time is 09:31, run in hysterisis state */ + .input("ess0", SOC, 100) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 5000) // + // nothing set on, Ess's setActivePower + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 120000)) .next(new TestCase() // - .input(ESS_SOC, 94) // - .input(ESS_ACTIVE_POWER, 5000) // - .input(METER_ACTIVE_POWER, 120000) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 27000)) // + .input("ess0", SOC, 94) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 5000) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 120000) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 27000)) // .next(new TestCase() // - .timeleap(clock, 75, ChronoUnit.MINUTES)/* current time is 10:47, run in high threshold state */ - .input(ESS_ACTIVE_POWER, 5000) // - .input(METER_ACTIVE_POWER, 120000) // - .output(ESS_SET_ACTIVE_POWER_EQUALS, 33000)) // + .timeleap(clock, 75, MINUTES)/* current time is 10:47, run in high threshold state */ + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 5000) // + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 120000) // + .output("ess0", SET_ACTIVE_POWER_EQUALS, 33000)) // .next(new TestCase() // - .timeleap(clock, 75, ChronoUnit.MINUTES)/* current time is 12:02 run in normal state */ - .input(ESS_ACTIVE_POWER, 5000) // - .input(METER_ACTIVE_POWER, 120000)); // nothing set on, Ess's setActivePower + .timeleap(clock, 75, MINUTES)/* current time is 12:02 run in normal state */ + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 5000) // + // nothing set on, Ess's setActivePower + .input("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 120000)) // + .deactivate(); } } diff --git a/io.openems.edge.core/src/io/openems/edge/app/evcs/EvcsProps.java b/io.openems.edge.core/src/io/openems/edge/app/evcs/EvcsProps.java index 258c66c960f..1904864db00 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/evcs/EvcsProps.java +++ b/io.openems.edge.core/src/io/openems/edge/app/evcs/EvcsProps.java @@ -1,7 +1,9 @@ package io.openems.edge.app.evcs; +import static io.openems.edge.app.common.props.CommonProps.defaultDef; import static io.openems.edge.core.appmanager.formly.enums.InputType.NUMBER; +import java.util.Arrays; import java.util.List; import java.util.stream.IntStream; @@ -11,7 +13,6 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.session.Language; import io.openems.common.utils.JsonUtils; -import io.openems.edge.app.common.props.CommonProps; import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.core.appmanager.AppDef; @@ -28,6 +29,7 @@ import io.openems.edge.core.appmanager.formly.JsonFormlyUtil; import io.openems.edge.core.appmanager.formly.builder.FieldGroupBuilder; import io.openems.edge.core.appmanager.formly.enums.DisplayType; +import io.openems.edge.evcs.api.PhaseRotation; public final class EvcsProps { @@ -45,7 +47,7 @@ private EvcsProps() { public static AppDef numberOfChargePoints(// final int maxValue // ) { - return AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def // + return AppDef.copyOfGeneric(defaultDef(), def -> def // .setTranslatedLabel("App.Evcs.numberOfChargingStations.label") // .setDefaultValue(1) // .setField(JsonFormlyUtil::buildSelectFromNameable, (app, property, l, parameter, field) -> // @@ -103,7 +105,7 @@ private static void field(// */ public static AppDef clusterMaxHardwarePower( Nameable acceptProperty) { - return AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def // + return AppDef.copyOfGeneric(defaultDef(), def -> def // .setTranslatedLabel("App.Evcs.Cluster.maxChargeFromGrid.label") // .setAllowedToSave(false) // .setIsAllowedToSee((app, property, l, parameter, user) -> { @@ -182,4 +184,20 @@ private static final boolean isClusterInstalled(ComponentManager componentManage return false; } + /** + * Creates a {@link AppDef} for a {@link PhaseRotation}. + * + * @return the {@link AppDef} + */ + public static final AppDef phaseRotation() { + return AppDef.copyOfGeneric(defaultDef(), def -> def // + .setTranslatedLabel("App.Evcs.phaseRotation.label") // + .setTranslatedDescription("App.Evcs.phaseRotation.description") // + .setDefaultValue(PhaseRotation.L1_L2_L3) // + .setField(JsonFormlyUtil::buildSelectFromNameable, (app, property, l, parameter, field) -> { + field.setOptions(Arrays.stream(PhaseRotation.values()) // + .map(PhaseRotation::name) // + .toList()); + })); + } } diff --git a/io.openems.edge.core/src/io/openems/edge/app/evcs/HardyBarthEvcs.java b/io.openems.edge.core/src/io/openems/edge/app/evcs/HardyBarthEvcs.java index ed993465b63..59586a5769e 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/evcs/HardyBarthEvcs.java +++ b/io.openems.edge.core/src/io/openems/edge/app/evcs/HardyBarthEvcs.java @@ -73,6 +73,7 @@ "EVCS_ID": "evcs0", "CTRL_EVCS_ID": "ctrlEvcs0", "IP": "192.168.25.30", + "PHASE_ROTATION":"L1_L2_L3", "NUMBER_OF_CHARGING_STATIONS": 1, "EVCS_ID_CP_2": "evcs0", "CTRL_EVCS_ID_CP_2": "ctrlEvcs0", @@ -144,6 +145,7 @@ public static enum Property implements PropertyParent { .collect(Exp.toArrayExpression()) // .every(i -> Exp.currentModelValue(EVCS_ID).notEqual(i)))); }))), // + PHASE_ROTATION(AppDef.copyOfGeneric(EvcsProps.phaseRotation())), // ; private final AppDef def; @@ -317,6 +319,7 @@ OpenemsNamedException> appPropertyConfigurationFactory() { final var alias = this.getString(p, l, SubPropertyFirstChargepoint.ALIAS); final var ip = this.getString(p, l, SubPropertyFirstChargepoint.IP); final var evcsId = this.getId(t, p, Property.EVCS_ID); + final var phaseRotation = this.getString(p, l, Property.PHASE_ROTATION); final var ctrlEvcsId = this.getId(t, p, Property.CTRL_EVCS_ID); schedulerIds.add(new SchedulerComponent(ctrlEvcsId, "Controller.Evcs", this.getAppId())); @@ -324,6 +327,7 @@ OpenemsNamedException> appPropertyConfigurationFactory() { final var components = Lists.newArrayList(// new EdgeConfig.Component(evcsId, alias, factorieId, JsonUtils.buildJsonObject() // .addProperty("ip", ip) // + .addPropertyIfNotNull("phaseRotation", phaseRotation) // .build()), // new EdgeConfig.Component(ctrlEvcsId, controllerAlias, "Controller.Evcs", JsonUtils.buildJsonObject() // .addProperty("evcs.id", evcsId) // @@ -339,6 +343,7 @@ OpenemsNamedException> appPropertyConfigurationFactory() { components.add(new EdgeConfig.Component(evcsIdCp2, aliasCp2, factorieId, JsonUtils.buildJsonObject() // .addProperty("ip", ipCp2) // + .addPropertyIfNotNull("phaseRotation", phaseRotation) // .build())); components.add(new EdgeConfig.Component(ctrlEvcsIdCp2, controllerAlias, "Controller.Evcs", JsonUtils.buildJsonObject() // diff --git a/io.openems.edge.core/src/io/openems/edge/app/evcs/KebaEvcs.java b/io.openems.edge.core/src/io/openems/edge/app/evcs/KebaEvcs.java index e9a680cb831..2ab629b5ae7 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/evcs/KebaEvcs.java +++ b/io.openems.edge.core/src/io/openems/edge/app/evcs/KebaEvcs.java @@ -55,7 +55,8 @@ "properties":{ "EVCS_ID": "evcs0", "CTRL_EVCS_ID": "ctrlEvcs0", - "IP":"192.168.25.11" + "IP":"192.168.25.11", + "PHASE_ROTATION":"L1_L2_L3" }, "appDescriptor": { "websiteUrl": {@link AppDescriptor#getWebsiteUrl()} @@ -80,6 +81,7 @@ public enum Property implements Type def; @@ -120,6 +122,7 @@ protected ThrowingTriFunction, L // values the user enters final var ip = this.getString(p, l, Property.IP); final var alias = this.getString(p, l, Property.ALIAS); + final var phaseRotation = this.getString(p, l, Property.PHASE_ROTATION); // values which are being auto generated by the appmanager final var evcsId = this.getId(t, p, Property.EVCS_ID); @@ -133,6 +136,7 @@ protected ThrowingTriFunction, L var components = Lists.newArrayList(// new EdgeConfig.Component(evcsId, alias, "Evcs.Keba.KeContact", JsonUtils.buildJsonObject() // .addPropertyIfNotNull("ip", ip) // + .addPropertyIfNotNull("phaseRotation", phaseRotation) // .build()), // new EdgeConfig.Component(ctrlEvcsId, controllerAlias, "Controller.Evcs", JsonUtils.buildJsonObject() // .addProperty("evcs.id", evcsId) // diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties index 16414b2d0d5..927b28bf399 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties @@ -123,6 +123,8 @@ App.Evcs.controller.alias = Ladestation Steuerung App.Evcs.ip.description = Die IP-Adresse der Ladestation. App.Evcs.chargingStation.label = Ladepunkt {0} App.Evcs.numberOfChargingStations.label = Anzahl Ladepunkte +App.Evcs.phaseRotation.label = Phasenrotation +App.Evcs.phaseRotation.description = Verkabelung der einzelnen Phasen der Ladestation zu den Phasen im Netz App.Evcs.Cluster.Name = Multiladepunkt Management App.Evcs.Cluster.Name.short = Multiladepunkt Management diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties index 2566a3fa36a..538f2862b93 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties @@ -123,6 +123,8 @@ App.Evcs.controller.alias = Charging station control App.Evcs.ip.description = The IP address of the charging station. App.Evcs.chargingStation.label = Charging point {0} App.Evcs.numberOfChargingStations.label = Number of charging points +App.Evcs.phaseRotation.label = Phase rotation +App.Evcs.phaseRotation.description = Wiring of the individual phases of the charging station to actual phases of the grid App.Evcs.Cluster.Name = Multi-charging point management App.Evcs.Cluster.Name.short = Multi-charging point management diff --git a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/EdgeConfigWorker.java b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/EdgeConfigWorker.java index 9679cfb5a6a..6c90e120dab 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/EdgeConfigWorker.java +++ b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/EdgeConfigWorker.java @@ -595,7 +595,7 @@ private static TreeMap convertProperties(String componentId for (EdgeConfig.Factory.Property property : factory.getProperties()) { var key = property.getId(); - if (EdgeConfig.ignorePropertyKey(key) || EdgeConfig.ignoreComponentPropertyKey(componentId, key)) { + if (EdgeConfig.ignorePropertyKey(key)) { // Ignore this Property continue; } diff --git a/io.openems.edge.core/src/io/openems/edge/core/meta/Config.java b/io.openems.edge.core/src/io/openems/edge/core/meta/Config.java index 41b9dd0f734..7e42538a6c0 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/meta/Config.java +++ b/io.openems.edge.core/src/io/openems/edge/core/meta/Config.java @@ -3,7 +3,7 @@ import org.osgi.service.metatype.annotations.AttributeDefinition; import org.osgi.service.metatype.annotations.ObjectClassDefinition; -import io.openems.edge.common.currency.CurrencyConfig; +import io.openems.common.types.CurrencyConfig; @ObjectClassDefinition(// name = "Core Meta", // diff --git a/io.openems.edge.core/src/io/openems/edge/core/meta/MetaImpl.java b/io.openems.edge.core/src/io/openems/edge/core/meta/MetaImpl.java index 27843503c1e..0d581be7eab 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/meta/MetaImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/meta/MetaImpl.java @@ -22,6 +22,7 @@ import io.openems.edge.common.channel.LongReadChannel; import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.currency.Currency; import io.openems.edge.common.meta.Meta; import io.openems.edge.common.modbusslave.ModbusSlave; import io.openems.edge.common.modbusslave.ModbusSlaveTable; @@ -90,6 +91,6 @@ public ModbusSlaveTable getModbusSlaveTable(AccessMode accessMode) { } private void applyConfig(Config config) { - this._setCurrency(config.currency().toCurrency()); + this._setCurrency(Currency.fromCurrencyConfig(config.currency())); } } diff --git a/io.openems.edge.core/src/io/openems/edge/core/sum/SumImpl.java b/io.openems.edge.core/src/io/openems/edge/core/sum/SumImpl.java index ea45fc4a94a..9ab8803e015 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/sum/SumImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/sum/SumImpl.java @@ -309,13 +309,14 @@ private void calculateChannelValues() { } else if (component instanceof Evcs evcs) { /* * Electric Vehicle Charging Station + * TODO replace with ElectricityMeter.isManagedConsumption() */ if (evcs instanceof MetaEvcs) { // ignore this Evcs continue; } - managedConsumptionActivePower.addValue(evcs.getChargePowerChannel()); + managedConsumptionActivePower.addValue(evcs.getActivePowerChannel()); } else if (component instanceof TimeOfUseTariff tou) { /* diff --git a/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome30DefaultRelays.java b/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome30DefaultRelays.java index 699921aa573..c67423251bc 100644 --- a/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome30DefaultRelays.java +++ b/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome30DefaultRelays.java @@ -18,7 +18,7 @@ import io.openems.edge.core.appmanager.Apps; import io.openems.edge.core.appmanager.DummyPseudoComponentManager; import io.openems.edge.core.appmanager.OpenemsAppInstance; -import io.openems.edge.io.test.DummyInputOutput; +import io.openems.edge.io.test.DummyCustomInputOutput; public class TestFeneconHome30DefaultRelays { @@ -96,10 +96,10 @@ private final OpenemsAppInstance createFullHomeWithDummyIo() throws Exception { final var instance = TestFeneconHome30.createFullHome30(this.appManagerTestBundle, DUMMY_ADMIN); this.appManagerTestBundle.componentManger.handleDeleteComponentConfigRequest(DUMMY_ADMIN, new DeleteComponentConfigRequest("io0")); - final var dummyRelay = new DummyInputOutput("io0", "RELAY", 1, 8); + final var dummyRelay = new DummyCustomInputOutput("io0", "RELAY", 1, 8); this.appManagerTestBundle.cm.getOrCreateEmptyConfiguration(dummyRelay.id()); ((DummyPseudoComponentManager) this.appManagerTestBundle.componentManger).addComponent(dummyRelay); - final var dummyRelay1 = new DummyInputOutput("io1", "RELAY", 1, 8); + final var dummyRelay1 = new DummyCustomInputOutput("io1", "RELAY", 1, 8); this.appManagerTestBundle.cm.getOrCreateEmptyConfiguration(dummyRelay1.id()); ((DummyPseudoComponentManager) this.appManagerTestBundle.componentManger).addComponent(dummyRelay1); return instance; diff --git a/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHomeDefaultRelays.java b/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHomeDefaultRelays.java index 983785d6092..b8cf0b2bd19 100644 --- a/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHomeDefaultRelays.java +++ b/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHomeDefaultRelays.java @@ -18,7 +18,7 @@ import io.openems.edge.core.appmanager.Apps; import io.openems.edge.core.appmanager.DummyPseudoComponentManager; import io.openems.edge.core.appmanager.OpenemsAppInstance; -import io.openems.edge.io.test.DummyInputOutput; +import io.openems.edge.io.test.DummyCustomInputOutput; public class TestFeneconHomeDefaultRelays { @@ -92,10 +92,10 @@ private final OpenemsAppInstance createFullHomeWithDummyIo() throws Exception { final var instance = TestFeneconHome.createFullHome(this.appManagerTestBundle, DUMMY_ADMIN); this.appManagerTestBundle.componentManger.handleDeleteComponentConfigRequest(DUMMY_ADMIN, new DeleteComponentConfigRequest("io0")); - final var dummyRelay = new DummyInputOutput("io0", "RELAY", 1, 4); + final var dummyRelay = new DummyCustomInputOutput("io0", "RELAY", 1, 4); this.appManagerTestBundle.cm.getOrCreateEmptyConfiguration(dummyRelay.id()); ((DummyPseudoComponentManager) this.appManagerTestBundle.componentManger).addComponent(dummyRelay); - final var dummyRelay1 = new DummyInputOutput("io1", "RELAY", 1, 4); + final var dummyRelay1 = new DummyCustomInputOutput("io1", "RELAY", 1, 4); this.appManagerTestBundle.cm.getOrCreateEmptyConfiguration(dummyRelay1.id()); ((DummyPseudoComponentManager) this.appManagerTestBundle.componentManger).addComponent(dummyRelay1); return instance; diff --git a/io.openems.edge.core/test/io/openems/edge/core/meta/MetaImplTest.java b/io.openems.edge.core/test/io/openems/edge/core/meta/MetaImplTest.java index 946dafc96a0..3c6a00657d5 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/meta/MetaImplTest.java +++ b/io.openems.edge.core/test/io/openems/edge/core/meta/MetaImplTest.java @@ -1,6 +1,6 @@ package io.openems.edge.core.meta; -import static io.openems.edge.common.currency.CurrencyConfig.EUR; +import static io.openems.common.types.CurrencyConfig.EUR; import org.junit.Test; diff --git a/io.openems.edge.core/test/io/openems/edge/core/meta/MyConfig.java b/io.openems.edge.core/test/io/openems/edge/core/meta/MyConfig.java index b99b018b74a..c269dc60237 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/meta/MyConfig.java +++ b/io.openems.edge.core/test/io/openems/edge/core/meta/MyConfig.java @@ -1,7 +1,7 @@ package io.openems.edge.core.meta; import io.openems.common.test.AbstractComponentConfig; -import io.openems.edge.common.currency.CurrencyConfig; +import io.openems.common.types.CurrencyConfig; import io.openems.edge.common.meta.Meta; @SuppressWarnings("all") diff --git a/io.openems.edge.core/test/io/openems/edge/core/predictormanager/PredictorManagerImplTest.java b/io.openems.edge.core/test/io/openems/edge/core/predictormanager/PredictorManagerImplTest.java index 934e934489e..3bc99e30cdc 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/predictormanager/PredictorManagerImplTest.java +++ b/io.openems.edge.core/test/io/openems/edge/core/predictormanager/PredictorManagerImplTest.java @@ -1,19 +1,17 @@ package io.openems.edge.core.predictormanager; +import static io.openems.edge.common.test.TestUtils.createDummyClock; import static io.openems.edge.predictor.api.prediction.Prediction.EMPTY_PREDICTION; import static java.time.temporal.ChronoUnit.DAYS; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; -import java.time.Instant; -import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.util.List; import org.junit.Test; import io.openems.common.exceptions.OpenemsException; -import io.openems.common.test.TimeLeapClock; import io.openems.common.types.ChannelAddress; import io.openems.edge.common.sum.DummySum; import io.openems.edge.common.test.ComponentTest; @@ -60,7 +58,7 @@ public class PredictorManagerImplTest { @Test public void test() throws OpenemsException, Exception { - final var clock = new TimeLeapClock(Instant.parse("2020-01-01T00:00:00.00Z"), ZoneOffset.UTC); + final var clock = createDummyClock(); final var cm = new DummyComponentManager(clock); final var sum = new DummySum(); final var midnight = ZonedDateTime.now(clock).truncatedTo(DAYS); diff --git a/io.openems.edge.core/test/io/openems/edge/core/sum/ExtremeEverValuesTest.java b/io.openems.edge.core/test/io/openems/edge/core/sum/ExtremeEverValuesTest.java index 86641c06232..4befb39052f 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/sum/ExtremeEverValuesTest.java +++ b/io.openems.edge.core/test/io/openems/edge/core/sum/ExtremeEverValuesTest.java @@ -1,21 +1,20 @@ package io.openems.edge.core.sum; import static io.openems.edge.common.test.TestUtils.activateNextProcessImage; +import static io.openems.edge.common.test.TestUtils.createDummyClock; import static io.openems.edge.common.test.TestUtils.withValue; import static io.openems.edge.core.sum.ExtremeEverValues.Range.NEGATIVE; import static io.openems.edge.core.sum.ExtremeEverValues.Range.POSTIVE; +import static java.time.temporal.ChronoUnit.HOURS; +import static java.time.temporal.ChronoUnit.SECONDS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import java.io.IOException; -import java.time.Instant; -import java.time.ZoneOffset; -import java.time.temporal.ChronoUnit; import org.junit.Test; import io.openems.common.exceptions.OpenemsException; -import io.openems.common.test.TimeLeapClock; import io.openems.edge.common.sum.Sum; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyComponentManager; @@ -25,12 +24,12 @@ public class ExtremeEverValuesTest { @Test public void test() throws OpenemsException, Exception { - final var clock = new TimeLeapClock(Instant.parse("2020-01-01T20:00:00.00Z"), ZoneOffset.UTC); + final var clock = createDummyClock(); var cm = new DummyConfigurationAdmin(); var sum = new SumImpl(); new ComponentTest(sum) // .addReference("cm", cm) // - .addReference("componentManager", new DummyComponentManager()) // + .addReference("componentManager", new DummyComponentManager(clock)) // .activate(MyConfig.create() // .setGridMinActivePower(0) // .setIgnoreStateComponents() // @@ -63,14 +62,14 @@ public void test() throws OpenemsException, Exception { assertEquals(0, getProperty(cm, "gridMinActivePower")); // Still the same - clock.leap(24, ChronoUnit.HOURS); + clock.leap(24, HOURS); withValue(sum, Sum.ChannelId.GRID_ACTIVE_POWER, -100); sut.update(sum, cm); activateNextProcessImage(sum); assertEquals(0, getProperty(cm, "gridMinActivePower")); // 24 hours passed -> update config - clock.leap(1, ChronoUnit.SECONDS); + clock.leap(1, SECONDS); withValue(sum, Sum.ChannelId.GRID_ACTIVE_POWER, -101); sut.update(sum, cm); activateNextProcessImage(sum); @@ -78,7 +77,7 @@ public void test() throws OpenemsException, Exception { assertEquals(-101, getProperty(cm, "gridMinActivePower")); // Update Channel; not the config - clock.leap(1, ChronoUnit.SECONDS); + clock.leap(1, SECONDS); withValue(sum, Sum.ChannelId.GRID_ACTIVE_POWER, -101); sut.update(sum, cm); activateNextProcessImage(sum); diff --git a/io.openems.edge.core/test/io/openems/edge/core/sum/SumImplTest.java b/io.openems.edge.core/test/io/openems/edge/core/sum/SumImplTest.java index 77a25ef888b..7d8f85f074b 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/sum/SumImplTest.java +++ b/io.openems.edge.core/test/io/openems/edge/core/sum/SumImplTest.java @@ -1,11 +1,14 @@ package io.openems.edge.core.sum; +import static io.openems.edge.common.sum.Sum.ChannelId.CONSUMPTION_MAX_ACTIVE_POWER; +import static io.openems.edge.common.sum.Sum.ChannelId.GRID_MAX_ACTIVE_POWER; +import static io.openems.edge.common.sum.Sum.ChannelId.GRID_MIN_ACTIVE_POWER; +import static io.openems.edge.common.sum.Sum.ChannelId.PRODUCTION_MAX_ACTIVE_POWER; import static io.openems.edge.meter.api.MeterType.GRID; import org.junit.Test; import io.openems.common.exceptions.OpenemsException; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyComponentManager; @@ -15,13 +18,6 @@ public class SumImplTest { - private static final ChannelAddress GRID_MIN_ACTIVE_POWER = new ChannelAddress("_sum", "GridMinActivePower"); - private static final ChannelAddress GRID_MAX_ACTIVE_POWER = new ChannelAddress("_sum", "GridMaxActivePower"); - private static final ChannelAddress PRODUCTION_MAX_ACTIVE_POWER = new ChannelAddress("_sum", - "ProductionMaxActivePower"); - private static final ChannelAddress CONSUMPTION_MAX_ACTIVE_POWER = new ChannelAddress("_sum", - "ConsumptionMaxActivePower"); - @Test public void test() throws OpenemsException, Exception { var sut = new SumImpl(); diff --git a/io.openems.edge.edge2edge/test/io/openems/edge/edge2edge/ess/Edge2EdgeEssImplTest.java b/io.openems.edge.edge2edge/test/io/openems/edge/edge2edge/ess/Edge2EdgeEssImplTest.java index 90317ad9e80..6b200696166 100644 --- a/io.openems.edge.edge2edge/test/io/openems/edge/edge2edge/ess/Edge2EdgeEssImplTest.java +++ b/io.openems.edge.edge2edge/test/io/openems/edge/edge2edge/ess/Edge2EdgeEssImplTest.java @@ -10,19 +10,16 @@ public class Edge2EdgeEssImplTest { - private static final String COMPONENT_ID = "ess0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new Edge2EdgeEssImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // - .setModbusId(MODBUS_ID) // + .setId("ess0") // + .setModbusId("modbus0") // .setRemoteAccessMode(AccessMode.READ_WRITE) // - .setRemoteComponentId(COMPONENT_ID) // + .setRemoteComponentId("ess0") // .build()) .next(new TestCase()); } diff --git a/io.openems.edge.edge2edge/test/io/openems/edge/edge2edge/meter/Edge2EdgeEssMeterImplTest.java b/io.openems.edge.edge2edge/test/io/openems/edge/edge2edge/meter/Edge2EdgeEssMeterImplTest.java index a52aed0a22b..4e0bd762bf9 100644 --- a/io.openems.edge.edge2edge/test/io/openems/edge/edge2edge/meter/Edge2EdgeEssMeterImplTest.java +++ b/io.openems.edge.edge2edge/test/io/openems/edge/edge2edge/meter/Edge2EdgeEssMeterImplTest.java @@ -1,28 +1,26 @@ package io.openems.edge.edge2edge.meter; +import static io.openems.edge.meter.api.MeterType.PRODUCTION; + import org.junit.Test; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.meter.api.MeterType; public class Edge2EdgeEssMeterImplTest { - private static final String COMPONENT_ID = "meter0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new Edge2EdgeMeterImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // - .setModbusId(MODBUS_ID) // - .setRemoteComponentId(COMPONENT_ID) // - .setMeterType(MeterType.PRODUCTION) // + .setId("meter0") // + .setModbusId("modbus0") // + .setRemoteComponentId("meter0") // + .setMeterType(PRODUCTION) // .build()) .next(new TestCase()); } diff --git a/io.openems.edge.energy/test/io/openems/edge/energy/EnergySchedulerImplTest.java b/io.openems.edge.energy/test/io/openems/edge/energy/EnergySchedulerImplTest.java index bacd9a10260..aa2a426c22c 100644 --- a/io.openems.edge.energy/test/io/openems/edge/energy/EnergySchedulerImplTest.java +++ b/io.openems.edge.energy/test/io/openems/edge/energy/EnergySchedulerImplTest.java @@ -37,8 +37,6 @@ public class EnergySchedulerImplTest { public static final Clock CLOCK = new TimeLeapClock(Instant.parse("2020-03-04T14:19:00.00Z"), ZoneOffset.UTC); - private static final String CTRL_ID = "ctrl0"; - @Test public void test() throws Exception { create(CLOCK); @@ -73,7 +71,7 @@ public static EnergySchedulerImpl create(Clock clock) throws Exception { .addReference("schedulables", List.of(ctrl)) // .addReference("sum", sum) // .activate(MyConfig.create() // - .setId(CTRL_ID) // + .setId("ctrl0") // .setEnabled(false) // .setLogVerbosity(TRACE) // .build()) // diff --git a/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/UtilsTest.java b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/UtilsTest.java index a2b82ad90a9..b9b321d8366 100644 --- a/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/UtilsTest.java +++ b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/UtilsTest.java @@ -1,6 +1,7 @@ package io.openems.edge.energy.optimizer; import static io.openems.common.utils.DateUtils.roundDownToQuarter; +import static io.openems.edge.common.test.TestUtils.createDummyClock; import static io.openems.edge.common.test.TestUtils.withValue; import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.BALANCING; import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.DELAY_DISCHARGE; @@ -29,6 +30,8 @@ import static io.openems.edge.energy.optimizer.Utils.toEnergy; import static io.openems.edge.energy.optimizer.Utils.toPower; import static io.openems.edge.energy.optimizer.Utils.updateSchedule; +import static java.time.temporal.ChronoUnit.MINUTES; +import static java.time.temporal.ChronoUnit.SECONDS; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -36,11 +39,8 @@ import static org.junit.Assert.assertTrue; import java.time.Duration; -import java.time.Instant; import java.time.ZoneId; -import java.time.ZoneOffset; import java.time.ZonedDateTime; -import java.time.temporal.ChronoUnit; import java.util.List; import java.util.TreeMap; import java.util.stream.IntStream; @@ -50,7 +50,6 @@ import com.google.common.collect.ImmutableSortedMap; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.test.TimeLeapClock; import io.openems.common.types.ChannelAddress; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.test.AbstractDummyOpenemsComponent; @@ -240,7 +239,7 @@ public void testGetEssMinSocEnergy() { @Test public void testHandleScheduleRequest() throws Exception { - final var clock = new TimeLeapClock(Instant.parse("2020-03-04T14:19:00.00Z"), ZoneOffset.UTC); + final var clock = createDummyClock(); final var energyScheduler = EnergySchedulerImplTest.create(clock); // Simulate historic data @@ -282,16 +281,16 @@ public void testHandleScheduleRequest() throws Exception { @Test public void testCalculateExecutionLimitSeconds() { - final var clock = new TimeLeapClock(Instant.parse("2022-01-01T00:00:00.00Z"), ZoneOffset.UTC); + final var clock = createDummyClock(); assertEquals(Duration.ofMinutes(14).plusSeconds(30).toSeconds(), calculateExecutionLimitSeconds(clock)); - clock.leap(11, ChronoUnit.MINUTES); + clock.leap(11, MINUTES); assertEquals(Duration.ofMinutes(3).plusSeconds(30).toSeconds(), calculateExecutionLimitSeconds(clock)); - clock.leap(150, ChronoUnit.SECONDS); + clock.leap(150, SECONDS); assertEquals(60, calculateExecutionLimitSeconds(clock)); - clock.leap(1, ChronoUnit.SECONDS); + clock.leap(1, SECONDS); assertEquals(Duration.ofMinutes(15).plusSeconds(59).toSeconds(), calculateExecutionLimitSeconds(clock)); } diff --git a/io.openems.edge.ess.byd.container/test/io/openems/edge/ess/byd/container/EssFeneconBydContainerImplTest.java b/io.openems.edge.ess.byd.container/test/io/openems/edge/ess/byd/container/EssFeneconBydContainerImplTest.java index 841489bb5b7..5d1475d92ab 100644 --- a/io.openems.edge.ess.byd.container/test/io/openems/edge/ess/byd/container/EssFeneconBydContainerImplTest.java +++ b/io.openems.edge.ess.byd.container/test/io/openems/edge/ess/byd/container/EssFeneconBydContainerImplTest.java @@ -9,25 +9,20 @@ public class EssFeneconBydContainerImplTest { - private static final String ESS_ID = "ess0"; - private static final String MODBUS0_ID = "modbus0"; - private static final String MODBUS1_ID = "modbus1"; - private static final String MODBUS2_ID = "modbus2"; - @Test public void test() throws Exception { new ManagedSymmetricEssTest(new EssFeneconBydContainerImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("power", new DummyPower()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS0_ID)) // - .addReference("modbus1", new DummyModbusBridge(MODBUS1_ID)) // - .addReference("modbus2", new DummyModbusBridge(MODBUS2_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // + .addReference("modbus1", new DummyModbusBridge("modbus1")) // + .addReference("modbus2", new DummyModbusBridge("modbus2")) // .activate(MyConfig.create() // - .setId(ESS_ID) // + .setId("ess0") // .setReadonly(true) // - .setModbusId0(MODBUS0_ID) // - .setModbusId1(MODBUS1_ID) // - .setModbusId2(MODBUS2_ID) // + .setModbusId0("modbus0") // + .setModbusId1("modbus1") // + .setModbusId2("modbus2") // .build()) // ; } diff --git a/io.openems.edge.ess.byd.container/test/io/openems/edge/ess/byd/container/watchdog/EssFeneconBydContainerWatchdogControllerImplTest.java b/io.openems.edge.ess.byd.container/test/io/openems/edge/ess/byd/container/watchdog/EssFeneconBydContainerWatchdogControllerImplTest.java deleted file mode 100644 index 19d242a4257..00000000000 --- a/io.openems.edge.ess.byd.container/test/io/openems/edge/ess/byd/container/watchdog/EssFeneconBydContainerWatchdogControllerImplTest.java +++ /dev/null @@ -1,81 +0,0 @@ -package io.openems.edge.ess.byd.container.watchdog; - -import io.openems.edge.bridge.modbus.test.DummyModbusBridge; -import io.openems.edge.common.test.ComponentTest; -import io.openems.edge.common.test.DummyComponentManager; -import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.controller.test.ControllerTest; -import io.openems.edge.ess.byd.container.EssFeneconBydContainerImpl; -import io.openems.edge.ess.test.DummyPower; - -public class EssFeneconBydContainerWatchdogControllerImplTest { - - private static final String CTRL_ID = "ctrl0"; - // private final static ChannelAddress CTRL_WATCHDOG = new - // ChannelAddress(CTRL_ID, "Watchdog"); - - private static final String MODBUS0_ID = "modbus0"; - private static final String MODBUS1_ID = "modbus1"; - private static final String MODBUS2_ID = "modbus2"; - - private static final String ESS_ID = "ess0"; - // private final static ChannelAddress ESS_SET_ACTIVE_POWER_EQUALS = new - // ChannelAddress(ESS_ID, - // "SetActivePowerEquals"); - // private final static ChannelAddress ESS_SET_REACTIVE_POWER_EQUALS = new - // ChannelAddress(ESS_ID, - // "SetReactivePowerEquals"); - - // TODO requires fix by Pooran Chandrashekaraiah - // @Test - protected void test() throws Exception { - var ess = new EssFeneconBydContainerImpl(); - new ComponentTest(ess) // - .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("power", new DummyPower()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS0_ID)) // - .addReference("modbus1", new DummyModbusBridge(MODBUS1_ID)) // - .addReference("modbus2", new DummyModbusBridge(MODBUS2_ID)) // - .activate(MyEssConfig.create() // - .setId(ESS_ID) // - .setModbusId0(MODBUS0_ID) // - .setModbusId1(MODBUS1_ID) // - .setModbusId2(MODBUS2_ID) // - .build()); - - new ControllerTest(new EssFeneconBydContainerWatchdogControllerImpl()) // - .addReference("componentManager", new DummyComponentManager()) // - .addReference("cm", new DummyConfigurationAdmin()) // - .addComponent(ess) // - .activate(MyWatchdogConfig.create() // - .setId(CTRL_ID) // - .setEssId(ESS_ID) // - .build()) - // .next(new TestCase()// - // .output(ESS_SET_ACTIVE_POWER_EQUALS, 0)// - // .output(ESS_SET_REACTIVE_POWER_EQUALS, 0))// - // .next(new TestCase() // - // .input(CTRL_WATCHDOG, 0)// - // .output(ESS_SET_ACTIVE_POWER_EQUALS, 0) // - // .output(ESS_SET_REACTIVE_POWER_EQUALS, 0))// - // .next(new TestCase() // - // .input(CTRL_WATCHDOG, 0).// - // output(CTRL_IS_TIMEOUT, 1))// - // .next(new TestCase() // - // .input(CTRL_WATCHDOG, 0)// - // .output(CTRL_IS_TIMEOUT, 1))// - // .next(new TestCase() // - // .input(CTRL_WATCHDOG, 0)// - // .output(CTRL_IS_TIMEOUT, 1)) - // .next(new TestCase() // - // .input(CTRL_WATCHDOG, 1)// - // .output(CTRL_IS_TIMEOUT, 0))// - // .next(new TestCase() // - // .output(CTRL_IS_TIMEOUT, 0)) - // .next(new TestCase() // - // .input(CTRL_WATCHDOG, 0)// - // .output(CTRL_IS_TIMEOUT, 1))// - ; - } - -} diff --git a/io.openems.edge.ess.byd.container/test/io/openems/edge/ess/byd/container/watchdog/MyEssConfig.java b/io.openems.edge.ess.byd.container/test/io/openems/edge/ess/byd/container/watchdog/MyEssConfig.java deleted file mode 100644 index fea2f40e694..00000000000 --- a/io.openems.edge.ess.byd.container/test/io/openems/edge/ess/byd/container/watchdog/MyEssConfig.java +++ /dev/null @@ -1,101 +0,0 @@ -package io.openems.edge.ess.byd.container.watchdog; - -import io.openems.common.test.AbstractComponentConfig; -import io.openems.common.utils.ConfigUtils; -import io.openems.edge.ess.byd.container.Config; - -@SuppressWarnings("all") -public class MyEssConfig extends AbstractComponentConfig implements Config { - - protected static class Builder { - private String id; - private boolean readonly; - private String modbusId0; - private String modbusId1; - private String modbusId2; - - private Builder() { - } - - public Builder setId(String id) { - this.id = id; - return this; - } - - public Builder setModbusId0(String modbusId0) { - this.modbusId0 = modbusId0; - return this; - } - - public Builder setModbusId1(String modbusId1) { - this.modbusId1 = modbusId1; - return this; - } - - public Builder setModbusId2(String modbusId2) { - this.modbusId2 = modbusId2; - return this; - } - - public Builder setReadonly(boolean readonly) { - this.readonly = readonly; - return this; - } - - public MyEssConfig build() { - return new MyEssConfig(this); - } - } - - /** - * Create a Config builder. - * - * @return a {@link Builder} - */ - public static Builder create() { - return new Builder(); - } - - private final Builder builder; - - private MyEssConfig(Builder builder) { - super(Config.class, builder.id); - this.builder = builder; - } - - @Override - public boolean readonly() { - return this.builder.readonly; - } - - @Override - public String modbus_id0() { - return this.builder.modbusId0; - } - - @Override - public String modbus_id1() { - return this.builder.modbusId1; - } - - @Override - public String modbus_id2() { - return this.builder.modbusId2; - } - - @Override - public String Modbus_target() { - return ConfigUtils.generateReferenceTargetFilter(this.id(), this.modbus_id0()); - } - - @Override - public String modbus1_target() { - return ConfigUtils.generateReferenceTargetFilter(this.id(), this.modbus_id1()); - } - - @Override - public String modbus2_target() { - return ConfigUtils.generateReferenceTargetFilter(this.id(), this.modbus_id2()); - } - -} diff --git a/io.openems.edge.ess.byd.container/test/io/openems/edge/ess/byd/container/watchdog/MyWatchdogConfig.java b/io.openems.edge.ess.byd.container/test/io/openems/edge/ess/byd/container/watchdog/MyWatchdogConfig.java deleted file mode 100644 index 90faa50d2fc..00000000000 --- a/io.openems.edge.ess.byd.container/test/io/openems/edge/ess/byd/container/watchdog/MyWatchdogConfig.java +++ /dev/null @@ -1,51 +0,0 @@ -package io.openems.edge.ess.byd.container.watchdog; - -import io.openems.common.test.AbstractComponentConfig; - -@SuppressWarnings("all") -public class MyWatchdogConfig extends AbstractComponentConfig implements Config { - - protected static class Builder { - private String id; - private String essId; - - private Builder() { - } - - public Builder setId(String id) { - this.id = id; - return this; - } - - public Builder setEssId(String essId) { - this.essId = essId; - return this; - } - - public MyWatchdogConfig build() { - return new MyWatchdogConfig(this); - } - } - - /** - * Create a Config builder. - * - * @return a {@link Builder} - */ - public static Builder create() { - return new Builder(); - } - - private final Builder builder; - - private MyWatchdogConfig(Builder builder) { - super(Config.class, builder.id); - this.builder = builder; - } - - @Override - public String ess_id() { - return this.builder.essId; - } - -} \ No newline at end of file diff --git a/io.openems.edge.ess.cluster/test/io/openems/edge/ess/cluster/EssClusterImplTest.java b/io.openems.edge.ess.cluster/test/io/openems/edge/ess/cluster/EssClusterImplTest.java index bc0f208f1af..5a2e9ddf4ab 100644 --- a/io.openems.edge.ess.cluster/test/io/openems/edge/ess/cluster/EssClusterImplTest.java +++ b/io.openems.edge.ess.cluster/test/io/openems/edge/ess/cluster/EssClusterImplTest.java @@ -1,8 +1,17 @@ package io.openems.edge.ess.cluster; +import static io.openems.edge.common.startstop.StartStoppable.ChannelId.START_STOP; +import static io.openems.edge.ess.api.AsymmetricEss.ChannelId.ACTIVE_POWER_L1; +import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.ALLOWED_CHARGE_POWER; +import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.ALLOWED_DISCHARGE_POWER; +import static io.openems.edge.ess.api.SymmetricEss.ChannelId.ACTIVE_CHARGE_ENERGY; +import static io.openems.edge.ess.api.SymmetricEss.ChannelId.ACTIVE_POWER; +import static io.openems.edge.ess.api.SymmetricEss.ChannelId.GRID_MODE; +import static io.openems.edge.ess.api.SymmetricEss.ChannelId.REACTIVE_POWER; +import static io.openems.edge.ess.api.SymmetricEss.ChannelId.SOC; + import org.junit.Test; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.startstop.StartStop; import io.openems.edge.common.startstop.StartStopConfig; import io.openems.edge.common.sum.GridMode; @@ -15,76 +24,39 @@ public class EssClusterImplTest { - private static final String CLUSTER_ID = "ess0"; - private static final String ESS1_ID = "ess1"; - private static final String ESS2_ID = "ess2"; - private static final String ESS3_ID = "ess3"; - private static final ChannelAddress CLUSTER_GRID_MODE = new ChannelAddress(CLUSTER_ID, "GridMode"); - private static final ChannelAddress ESS1_GRID_MODE = new ChannelAddress(ESS1_ID, "GridMode"); - private static final ChannelAddress ESS2_GRID_MODE = new ChannelAddress(ESS2_ID, "GridMode"); - private static final ChannelAddress ESS3_GRID_MODE = new ChannelAddress(ESS3_ID, "GridMode"); - private static final ChannelAddress CLUSTER_SOC = new ChannelAddress(CLUSTER_ID, "Soc"); - private static final ChannelAddress ESS1_SOC = new ChannelAddress(ESS1_ID, "Soc"); - private static final ChannelAddress ESS2_SOC = new ChannelAddress(ESS2_ID, "Soc"); - private static final ChannelAddress CLUSTER_ACTIVE_POWER = new ChannelAddress(CLUSTER_ID, "ActivePower"); - private static final ChannelAddress ESS1_ACTIVE_POWER = new ChannelAddress(ESS1_ID, "ActivePower"); - private static final ChannelAddress ESS2_ACTIVE_POWER = new ChannelAddress(ESS2_ID, "ActivePower"); - private static final ChannelAddress CLUSTER_REACTIVE_POWER = new ChannelAddress(CLUSTER_ID, "ReactivePower"); - private static final ChannelAddress ESS1_REACTIVE_POWER = new ChannelAddress(ESS1_ID, "ReactivePower"); - private static final ChannelAddress ESS2_REACTIVE_POWER = new ChannelAddress(ESS2_ID, "ReactivePower"); - private static final ChannelAddress CLUSTER_ACTIVE_POWER_L1 = new ChannelAddress(CLUSTER_ID, "ActivePowerL1"); - private static final ChannelAddress ESS2_ACTIVE_POWER_L1 = new ChannelAddress(ESS2_ID, "ActivePowerL1"); - private static final ChannelAddress CLUSTER_ACTIVE_CHARGE_ENERGY = new ChannelAddress(CLUSTER_ID, - "ActiveChargeEnergy"); - private static final ChannelAddress ESS1_ACTIVE_CHARGE_ENERGY = new ChannelAddress(ESS1_ID, "ActiveChargeEnergy"); - private static final ChannelAddress ESS2_ACTIVE_CHARGE_ENERGY = new ChannelAddress(ESS2_ID, "ActiveChargeEnergy"); - private static final ChannelAddress CLUSTER_ALLOWED_CHARGE_POWER = new ChannelAddress(CLUSTER_ID, - "AllowedChargePower"); - private static final ChannelAddress ESS1_ALLOWED_CHARGE_POWER = new ChannelAddress(ESS1_ID, "AllowedChargePower"); - private static final ChannelAddress ESS2_ALLOWED_CHARGE_POWER = new ChannelAddress(ESS2_ID, "AllowedChargePower"); - private static final ChannelAddress CLUSTER_ALLOWED_DISCHARGE_POWER = new ChannelAddress(CLUSTER_ID, - "AllowedDischargePower"); - private static final ChannelAddress ESS1_ALLOWED_DISCHARGE_POWER = new ChannelAddress(ESS1_ID, - "AllowedDischargePower"); - private static final ChannelAddress ESS2_ALLOWED_DISCHARGE_POWER = new ChannelAddress(ESS2_ID, - "AllowedDischargePower"); - private static final ChannelAddress CLUSTER_START_STOP = new ChannelAddress(CLUSTER_ID, "StartStop"); - private static final ChannelAddress ESS1_START_STOP = new ChannelAddress(ESS1_ID, "StartStop"); - private static final ChannelAddress ESS2_START_STOP = new ChannelAddress(ESS2_ID, "StartStop"); - @Test public void testCluster() throws Exception { new ComponentTest(new EssClusterImpl()) // .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("addEss", new DummyManagedSymmetricEss(ESS1_ID)) // - .addReference("addEss", new DummyManagedAsymmetricEss(ESS2_ID)) // + .addReference("addEss", new DummyManagedSymmetricEss("ess1")) // + .addReference("addEss", new DummyManagedAsymmetricEss("ess2")) // .activate(MyConfig.create() // - .setId(CLUSTER_ID) // - .setEssIds(ESS1_ID, ESS2_ID) // + .setId("ess0") // + .setEssIds("ess1", "ess2") // .setStartStop(StartStopConfig.START) // .build()) .next(new TestCase() // - .input(ESS1_GRID_MODE, GridMode.ON_GRID) // - .input(ESS2_GRID_MODE, GridMode.ON_GRID) // - .output(CLUSTER_GRID_MODE, GridMode.ON_GRID) // - .input(ESS1_ACTIVE_POWER, 1234) // - .input(ESS2_ACTIVE_POWER, 9876) // - .output(CLUSTER_ACTIVE_POWER, 11110) // - .input(ESS1_REACTIVE_POWER, 1111) // - .input(ESS2_REACTIVE_POWER, 2222) // - .output(CLUSTER_REACTIVE_POWER, 3333) // - .input(ESS1_ACTIVE_CHARGE_ENERGY, 1) // - .input(ESS2_ACTIVE_CHARGE_ENERGY, 2) // - .output(CLUSTER_ACTIVE_CHARGE_ENERGY, 3L) // - .input(ESS2_ACTIVE_POWER_L1, 1111) // - .output(CLUSTER_ACTIVE_POWER_L1, 1234 / 3 + 1111) // - .input(ESS1_ALLOWED_CHARGE_POWER, 11) // - .input(ESS2_ALLOWED_CHARGE_POWER, 22) // - .output(CLUSTER_ALLOWED_CHARGE_POWER, 33) // - .input(ESS1_ALLOWED_DISCHARGE_POWER, 10) // - .input(ESS2_ALLOWED_DISCHARGE_POWER, 20) // - .output(CLUSTER_ALLOWED_DISCHARGE_POWER, 30) // + .input("ess1", GRID_MODE, GridMode.ON_GRID) // + .input("ess2", GRID_MODE, GridMode.ON_GRID) // + .output(GRID_MODE, GridMode.ON_GRID) // + .input("ess1", ACTIVE_POWER, 1234) // + .input("ess2", ACTIVE_POWER, 9876) // + .output(ACTIVE_POWER, 11110) // + .input("ess1", REACTIVE_POWER, 1111) // + .input("ess2", REACTIVE_POWER, 2222) // + .output(REACTIVE_POWER, 3333) // + .input("ess1", ACTIVE_CHARGE_ENERGY, 1) // + .input("ess2", ACTIVE_CHARGE_ENERGY, 2) // + .output(ACTIVE_CHARGE_ENERGY, 3L) // + .input("ess2", ACTIVE_POWER_L1, 1111) // + .output(ACTIVE_POWER_L1, 1234 / 3 + 1111) // + .input("ess1", ALLOWED_CHARGE_POWER, 11) // + .input("ess2", ALLOWED_CHARGE_POWER, 22) // + .output(ALLOWED_CHARGE_POWER, 33) // + .input("ess1", ALLOWED_DISCHARGE_POWER, 10) // + .input("ess2", ALLOWED_DISCHARGE_POWER, 20) // + .output(ALLOWED_DISCHARGE_POWER, 30) // ); } @@ -93,31 +65,31 @@ public void testGridMode() throws Exception { new ComponentTest(new EssClusterImpl()) // .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("addEss", new DummyManagedSymmetricEss(ESS1_ID)) // - .addReference("addEss", new DummyManagedSymmetricEss(ESS2_ID)) // - .addReference("addEss", new DummyManagedSymmetricEss(ESS3_ID)) // + .addReference("addEss", new DummyManagedSymmetricEss("ess1")) // + .addReference("addEss", new DummyManagedSymmetricEss("ess2")) // + .addReference("addEss", new DummyManagedSymmetricEss("ess3")) // .activate(MyConfig.create() // - .setId(CLUSTER_ID) // - .setEssIds(ESS1_ID, ESS2_ID, ESS3_ID) // + .setId("ess0") // + .setEssIds("ess1", "ess2", "ess3") // .setStartStop(StartStopConfig.START) // .build()) .next(new TestCase() // - .input(ESS1_GRID_MODE, GridMode.ON_GRID) // - .input(ESS2_GRID_MODE, GridMode.ON_GRID) // - .input(ESS3_GRID_MODE, GridMode.ON_GRID) // - .output(CLUSTER_GRID_MODE, GridMode.ON_GRID) // + .input("ess1", GRID_MODE, GridMode.ON_GRID) // + .input("ess2", GRID_MODE, GridMode.ON_GRID) // + .input("ess3", GRID_MODE, GridMode.ON_GRID) // + .output(GRID_MODE, GridMode.ON_GRID) // ) // .next(new TestCase() // - .input(ESS1_GRID_MODE, GridMode.OFF_GRID) // - .input(ESS2_GRID_MODE, GridMode.OFF_GRID) // - .input(ESS3_GRID_MODE, GridMode.OFF_GRID) // - .output(CLUSTER_GRID_MODE, GridMode.OFF_GRID) // + .input("ess1", GRID_MODE, GridMode.OFF_GRID) // + .input("ess2", GRID_MODE, GridMode.OFF_GRID) // + .input("ess3", GRID_MODE, GridMode.OFF_GRID) // + .output(GRID_MODE, GridMode.OFF_GRID) // ) // .next(new TestCase() // - .input(ESS1_GRID_MODE, GridMode.OFF_GRID) // - .input(ESS2_GRID_MODE, GridMode.OFF_GRID) // - .input(ESS3_GRID_MODE, GridMode.UNDEFINED) // - .output(CLUSTER_GRID_MODE, GridMode.UNDEFINED) // + .input("ess1", GRID_MODE, GridMode.OFF_GRID) // + .input("ess2", GRID_MODE, GridMode.OFF_GRID) // + .input("ess3", GRID_MODE, GridMode.UNDEFINED) // + .output(GRID_MODE, GridMode.UNDEFINED) // ) // ; } @@ -127,25 +99,25 @@ public void testSoc() throws Exception { new ComponentTest(new EssClusterImpl()) // .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("addEss", new DummyManagedSymmetricEss(ESS1_ID).withCapacity(50000)) // - .addReference("addEss", new DummyManagedSymmetricEss(ESS2_ID).withCapacity(3000)) // + .addReference("addEss", new DummyManagedSymmetricEss("ess1").withCapacity(50000)) // + .addReference("addEss", new DummyManagedSymmetricEss("ess2").withCapacity(3000)) // .activate(MyConfig.create() // - .setId(CLUSTER_ID) // - .setEssIds(ESS1_ID, ESS2_ID) // + .setId("ess0") // + .setEssIds("ess1", "ess2") // .setStartStop(StartStopConfig.START) // .build()) .next(new TestCase() // - .input(ESS1_SOC, 20) // - .input(ESS2_SOC, 90) // - .output(CLUSTER_SOC, 24) // + .input("ess1", SOC, 20) // + .input("ess2", SOC, 90) // + .output(SOC, 24) // ) // .next(new TestCase() // - .input(ESS1_SOC, 21) // - .output(CLUSTER_SOC, 25) // + .input("ess1", SOC, 21) // + .output(SOC, 25) // ) // .next(new TestCase() // - .input(ESS1_SOC, 100) // - .output(CLUSTER_SOC, 99) // + .input("ess1", SOC, 100) // + .output(SOC, 99) // ) // ; } @@ -155,29 +127,29 @@ public void testStartStop() throws Exception { new ComponentTest(new EssClusterImpl()) // .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("addEss", new DummyManagedSymmetricEss(ESS1_ID)) // - .addReference("addEss", new DummyManagedSymmetricEss(ESS2_ID)) // + .addReference("addEss", new DummyManagedSymmetricEss("ess1")) // + .addReference("addEss", new DummyManagedSymmetricEss("ess2")) // .activate(MyConfig.create() // - .setId(CLUSTER_ID) // - .setEssIds(ESS1_ID, ESS2_ID) // + .setId("ess0") // + .setEssIds("ess1", "ess2") // .setStartStop(StartStopConfig.START) // .build()) .next(new TestCase() // - .input(ESS1_START_STOP, StartStop.UNDEFINED) // - .input(ESS2_START_STOP, StartStop.STOP) // - .output(CLUSTER_START_STOP, StartStop.UNDEFINED)) // + .input("ess1", START_STOP, StartStop.UNDEFINED) // + .input("ess2", START_STOP, StartStop.STOP) // + .output(START_STOP, StartStop.UNDEFINED)) // .next(new TestCase() // - .input(ESS1_START_STOP, StartStop.STOP) // - .input(ESS2_START_STOP, StartStop.STOP) // - .output(CLUSTER_START_STOP, StartStop.STOP)) // + .input("ess1", START_STOP, StartStop.STOP) // + .input("ess2", START_STOP, StartStop.STOP) // + .output(START_STOP, StartStop.STOP)) // .next(new TestCase() // - .input(ESS1_START_STOP, StartStop.START) // - .input(ESS2_START_STOP, StartStop.STOP) // - .output(CLUSTER_START_STOP, StartStop.UNDEFINED)) // + .input("ess1", START_STOP, StartStop.START) // + .input("ess2", START_STOP, StartStop.STOP) // + .output(START_STOP, StartStop.UNDEFINED)) // .next(new TestCase() // - .input(ESS1_START_STOP, StartStop.START) // - .input(ESS2_START_STOP, StartStop.START) // - .output(CLUSTER_START_STOP, StartStop.START)) // + .input("ess1", START_STOP, StartStop.START) // + .input("ess2", START_STOP, StartStop.START) // + .output(START_STOP, StartStop.START)) // ; } diff --git a/io.openems.edge.ess.core/test/io/openems/edge/ess/core/power/PowerComponentTest.java b/io.openems.edge.ess.core/test/io/openems/edge/ess/core/power/PowerComponentTest.java index 75baf32bbc0..0e5e0282eaf 100644 --- a/io.openems.edge.ess.core/test/io/openems/edge/ess/core/power/PowerComponentTest.java +++ b/io.openems.edge.ess.core/test/io/openems/edge/ess/core/power/PowerComponentTest.java @@ -1,5 +1,11 @@ package io.openems.edge.ess.core.power; +import static io.openems.edge.ess.power.api.Pwr.ACTIVE; +import static io.openems.edge.ess.power.api.Pwr.REACTIVE; +import static io.openems.edge.ess.power.api.Relationship.EQUALS; +import static io.openems.edge.ess.power.api.Relationship.LESS_OR_EQUALS; +import static io.openems.edge.ess.power.api.SolverStrategy.OPTIMIZE_BY_KEEPING_ALL_EQUAL; +import static io.openems.edge.ess.power.api.SolverStrategy.OPTIMIZE_BY_MOVING_TOWARDS_TARGET; import static org.junit.Assert.assertEquals; import java.util.concurrent.atomic.AtomicInteger; @@ -12,9 +18,6 @@ import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; import io.openems.edge.ess.power.api.Phase; -import io.openems.edge.ess.power.api.Pwr; -import io.openems.edge.ess.power.api.Relationship; -import io.openems.edge.ess.power.api.SolverStrategy; import io.openems.edge.ess.test.DummyManagedAsymmetricEss; import io.openems.edge.ess.test.DummyManagedSymmetricEss; import io.openems.edge.ess.test.DummyMetaEss; @@ -50,15 +53,15 @@ public void testSymmetricEss() throws Exception { .addReference("cm", cm) // .addReference("addEss", ess0) // .activate(MyConfig.create() // - .setStrategy(SolverStrategy.OPTIMIZE_BY_MOVING_TOWARDS_TARGET) // + .setStrategy(OPTIMIZE_BY_MOVING_TOWARDS_TARGET) // .setSymmetricMode(true) // .setDebugMode(false) // .setEnablePid(false) // .build()); // expect("#10", ess0, 5000, 3000); - ess0.addPowerConstraint("", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, 5000); - ess0.addPowerConstraint("", Phase.ALL, Pwr.REACTIVE, Relationship.EQUALS, 3000); + ess0.addPowerConstraint("", Phase.ALL, ACTIVE, EQUALS, 5000); + ess0.addPowerConstraint("", Phase.ALL, REACTIVE, EQUALS, 3000); componentTest.next(new TestCase()); } @@ -79,19 +82,19 @@ public void testAsymmetricEss() throws Exception { .addReference("cm", cm) // .addReference("addEss", ess0) // .activate(MyConfig.create() // - .setStrategy(SolverStrategy.OPTIMIZE_BY_MOVING_TOWARDS_TARGET) // + .setStrategy(OPTIMIZE_BY_MOVING_TOWARDS_TARGET) // .setSymmetricMode(false) // .setDebugMode(false) // .setEnablePid(false) // .build()); // expect("#1", ess0, 5000, 3333, 5000, 3333, 5000, 3334); - ess0.addPowerConstraint("", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, 15000); - ess0.addPowerConstraint("", Phase.ALL, Pwr.REACTIVE, Relationship.EQUALS, 10000); - ess0.addPowerConstraint("", Phase.L1, Pwr.ACTIVE, Relationship.EQUALS, 5000); - ess0.addPowerConstraint("", Phase.L1, Pwr.REACTIVE, Relationship.EQUALS, 3333); - ess0.addPowerConstraint("", Phase.L2, Pwr.ACTIVE, Relationship.EQUALS, 5000); - ess0.addPowerConstraint("", Phase.L2, Pwr.REACTIVE, Relationship.EQUALS, 3333); + ess0.addPowerConstraint("", Phase.ALL, ACTIVE, EQUALS, 15000); + ess0.addPowerConstraint("", Phase.ALL, REACTIVE, EQUALS, 10000); + ess0.addPowerConstraint("", Phase.L1, ACTIVE, EQUALS, 5000); + ess0.addPowerConstraint("", Phase.L1, REACTIVE, EQUALS, 3333); + ess0.addPowerConstraint("", Phase.L2, ACTIVE, EQUALS, 5000); + ess0.addPowerConstraint("", Phase.L2, REACTIVE, EQUALS, 3333); componentTest.next(new TestCase()); } @@ -112,15 +115,15 @@ public void testAsymmetricEssAllEqual() throws Exception { .addReference("cm", cm) // .addReference("addEss", ess0) // .activate(MyConfig.create() // - .setStrategy(SolverStrategy.OPTIMIZE_BY_KEEPING_ALL_EQUAL) // + .setStrategy(OPTIMIZE_BY_KEEPING_ALL_EQUAL) // .setSymmetricMode(false) // .setDebugMode(false) // .setEnablePid(false) // .build()); // expect("#1", ess0, 5000, 3000, 5000, 3000, 5000, 3000); - ess0.addPowerConstraint("", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, 15000); - ess0.addPowerConstraint("", Phase.ALL, Pwr.REACTIVE, Relationship.EQUALS, 9000); + ess0.addPowerConstraint("", Phase.ALL, ACTIVE, EQUALS, 15000); + ess0.addPowerConstraint("", Phase.ALL, REACTIVE, EQUALS, 9000); componentTest.next(new TestCase()); } @@ -151,7 +154,7 @@ public void testCluster() throws Exception { .addReference("addEss", ess1) // .addReference("addEss", ess2) // .activate(MyConfig.create() // - .setStrategy(SolverStrategy.OPTIMIZE_BY_MOVING_TOWARDS_TARGET) // + .setStrategy(OPTIMIZE_BY_MOVING_TOWARDS_TARGET) // .setSymmetricMode(true) // .setDebugMode(false) // .setEnablePid(false) // @@ -160,72 +163,72 @@ public void testCluster() throws Exception { // #1 expect("#1", ess1, -5000, -3000); expect("#1", ess2, -0, 0); - ess0.addPowerConstraint("#1", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, -5000); - ess0.addPowerConstraint("#1", Phase.ALL, Pwr.REACTIVE, Relationship.EQUALS, -3000); + ess0.addPowerConstraint("#1", Phase.ALL, ACTIVE, EQUALS, -5000); + ess0.addPowerConstraint("#1", Phase.ALL, REACTIVE, EQUALS, -3000); ess1.withSoc(80); // this is for test #2 componentTest.next(new TestCase("#1")); // #2 expect("#2", ess1, -4697, -2818); expect("#2", ess2, -302, -181); - ess0.addPowerConstraint("#2", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, -5000); - ess0.addPowerConstraint("#2", Phase.ALL, Pwr.REACTIVE, Relationship.EQUALS, -3000); + ess0.addPowerConstraint("#2", Phase.ALL, ACTIVE, EQUALS, -5000); + ess0.addPowerConstraint("#2", Phase.ALL, REACTIVE, EQUALS, -3000); componentTest.next(new TestCase("#2")); // #3 expect("#3", ess1, -4429, -2657); expect("#3", ess2, -570, -342); - ess0.addPowerConstraint("#3", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, -5000); - ess0.addPowerConstraint("#3", Phase.ALL, Pwr.REACTIVE, Relationship.EQUALS, -3000); + ess0.addPowerConstraint("#3", Phase.ALL, ACTIVE, EQUALS, -5000); + ess0.addPowerConstraint("#3", Phase.ALL, REACTIVE, EQUALS, -3000); componentTest.next(new TestCase("#3")); // #4 expect("#4", ess1, -4190, -2514); expect("#4", ess2, -809, -485); - ess0.addPowerConstraint("#4", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, -5000); - ess0.addPowerConstraint("#4", Phase.ALL, Pwr.REACTIVE, Relationship.EQUALS, -3000); + ess0.addPowerConstraint("#4", Phase.ALL, ACTIVE, EQUALS, -5000); + ess0.addPowerConstraint("#4", Phase.ALL, REACTIVE, EQUALS, -3000); componentTest.next(new TestCase("#4")); // #5 expect("#5", ess1, -3976, -2385); expect("#5", ess2, -1023, -614); - ess0.addPowerConstraint("#5", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, -5000); - ess0.addPowerConstraint("#5", Phase.ALL, Pwr.REACTIVE, Relationship.EQUALS, -3000); + ess0.addPowerConstraint("#5", Phase.ALL, ACTIVE, EQUALS, -5000); + ess0.addPowerConstraint("#5", Phase.ALL, REACTIVE, EQUALS, -3000); componentTest.next(new TestCase("#5")); // #6 expect("#6", ess1, -3782, -2269); expect("#6", ess2, -1217, -730); - ess0.addPowerConstraint("#6", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, -5000); - ess0.addPowerConstraint("#6", Phase.ALL, Pwr.REACTIVE, Relationship.EQUALS, -3000); + ess0.addPowerConstraint("#6", Phase.ALL, ACTIVE, EQUALS, -5000); + ess0.addPowerConstraint("#6", Phase.ALL, REACTIVE, EQUALS, -3000); componentTest.next(new TestCase("#6")); // #7 expect("#7", ess1, -3606, -2164); expect("#7", ess2, -1393, -835); - ess0.addPowerConstraint("#7", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, -5000); - ess0.addPowerConstraint("#7", Phase.ALL, Pwr.REACTIVE, Relationship.EQUALS, -3000); + ess0.addPowerConstraint("#7", Phase.ALL, ACTIVE, EQUALS, -5000); + ess0.addPowerConstraint("#7", Phase.ALL, REACTIVE, EQUALS, -3000); componentTest.next(new TestCase("#7")); // #8 expect("#8", ess1, -3446, -2067); expect("#8", ess2, -1553, -932); - ess0.addPowerConstraint("#8", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, -5000); - ess0.addPowerConstraint("#8", Phase.ALL, Pwr.REACTIVE, Relationship.EQUALS, -3000); + ess0.addPowerConstraint("#8", Phase.ALL, ACTIVE, EQUALS, -5000); + ess0.addPowerConstraint("#8", Phase.ALL, REACTIVE, EQUALS, -3000); componentTest.next(new TestCase("#8")); // #9 expect("#9", ess1, -3300, -1980); expect("#9", ess2, -1699, -1019); - ess0.addPowerConstraint("#9", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, -5000); - ess0.addPowerConstraint("#9", Phase.ALL, Pwr.REACTIVE, Relationship.EQUALS, -3000); + ess0.addPowerConstraint("#9", Phase.ALL, ACTIVE, EQUALS, -5000); + ess0.addPowerConstraint("#9", Phase.ALL, REACTIVE, EQUALS, -3000); componentTest.next(new TestCase("#9")); // #10 expect("#10", ess1, -3165, -1899); expect("#10", ess2, -1834, -1100); - ess0.addPowerConstraint("#10", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, -5000); - ess0.addPowerConstraint("#10", Phase.ALL, Pwr.REACTIVE, Relationship.EQUALS, -3000); + ess0.addPowerConstraint("#10", Phase.ALL, ACTIVE, EQUALS, -5000); + ess0.addPowerConstraint("#10", Phase.ALL, REACTIVE, EQUALS, -3000); componentTest.next(new TestCase("#10")); ess1.withSymmetricApplyPowerCallback(null); @@ -244,8 +247,8 @@ public void testCluster() throws Exception { // #20 expect("#20", ess1, -0, 0); expect("#20", ess2, -5000, -3000); - ess0.addPowerConstraint("#20", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, -5000); - ess0.addPowerConstraint("#20", Phase.ALL, Pwr.REACTIVE, Relationship.EQUALS, -3000); + ess0.addPowerConstraint("#20", Phase.ALL, ACTIVE, EQUALS, -5000); + ess0.addPowerConstraint("#20", Phase.ALL, REACTIVE, EQUALS, -3000); componentTest.next(new TestCase("#20")); } @@ -304,7 +307,7 @@ public void testStrSctr() throws Exception { .addReference("addEss", ess5) // .addReference("addEss", ess6) // .activate(MyConfig.create() // - .setStrategy(SolverStrategy.OPTIMIZE_BY_MOVING_TOWARDS_TARGET) // + .setStrategy(OPTIMIZE_BY_MOVING_TOWARDS_TARGET) // .setSymmetricMode(true) // .setDebugMode(false) // .setEnablePid(false) // @@ -317,8 +320,8 @@ public void testStrSctr() throws Exception { expect("#1", ess4, 0, 0); expect("#1", ess5, 10062, 0); // largest SoC expect("#1", ess6, 9986, 0); // second largest SoC - ess0.addPowerConstraint("#1", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, 30000); - ess0.addPowerConstraint("#1", Phase.ALL, Pwr.REACTIVE, Relationship.EQUALS, 0); + ess0.addPowerConstraint("#1", Phase.ALL, ACTIVE, EQUALS, 30000); + ess0.addPowerConstraint("#1", Phase.ALL, REACTIVE, EQUALS, 0); componentTest.next(new TestCase("#1")); // #2 @@ -328,8 +331,8 @@ public void testStrSctr() throws Exception { expect("#2", ess4, 0, 0); expect("#2", ess5, 8435, 5061); // largest SoC expect("#2", ess6, 8310, 4986); // second largest SoC - ess0.addPowerConstraint("#2", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, 25000); - ess0.addPowerConstraint("#2", Phase.ALL, Pwr.REACTIVE, Relationship.EQUALS, 15000); + ess0.addPowerConstraint("#2", Phase.ALL, ACTIVE, EQUALS, 25000); + ess0.addPowerConstraint("#2", Phase.ALL, REACTIVE, EQUALS, 15000); componentTest.next(new TestCase("#2")); // #3 @@ -339,8 +342,8 @@ public void testStrSctr() throws Exception { expect("#3", ess4, 0, 0); expect("#3", ess5, 1723, 689); // largest SoC expect("#3", ess6, 1644, 658); // second largest SoC - ess0.addPowerConstraint("#3", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, 5000); - ess0.addPowerConstraint("#3", Phase.ALL, Pwr.REACTIVE, Relationship.EQUALS, 2000); + ess0.addPowerConstraint("#3", Phase.ALL, ACTIVE, EQUALS, 5000); + ess0.addPowerConstraint("#3", Phase.ALL, REACTIVE, EQUALS, 2000); componentTest.next(new TestCase("#3")); // #4 not strictly defined force charge @@ -350,18 +353,18 @@ public void testStrSctr() throws Exception { expect("#4", ess4, -2000, -1000); expect("#4", ess5, -2000, -1000); // largest SoC expect("#4", ess6, -2000, -1000); // second largest SoC - ess1.addPowerConstraint("#4", Phase.ALL, Pwr.ACTIVE, Relationship.LESS_OR_EQUALS, -2000); - ess2.addPowerConstraint("#4", Phase.ALL, Pwr.ACTIVE, Relationship.LESS_OR_EQUALS, -2000); - ess3.addPowerConstraint("#4", Phase.ALL, Pwr.ACTIVE, Relationship.LESS_OR_EQUALS, -2000); - ess4.addPowerConstraint("#4", Phase.ALL, Pwr.ACTIVE, Relationship.LESS_OR_EQUALS, -2000); - ess5.addPowerConstraint("#4", Phase.ALL, Pwr.ACTIVE, Relationship.LESS_OR_EQUALS, -2000); - ess6.addPowerConstraint("#4", Phase.ALL, Pwr.ACTIVE, Relationship.LESS_OR_EQUALS, -2000); - ess1.addPowerConstraint("#4", Phase.ALL, Pwr.REACTIVE, Relationship.EQUALS, -1000); - ess2.addPowerConstraint("#4", Phase.ALL, Pwr.REACTIVE, Relationship.EQUALS, -1000); - ess3.addPowerConstraint("#4", Phase.ALL, Pwr.REACTIVE, Relationship.EQUALS, -1000); - ess4.addPowerConstraint("#4", Phase.ALL, Pwr.REACTIVE, Relationship.EQUALS, -1000); - ess5.addPowerConstraint("#4", Phase.ALL, Pwr.REACTIVE, Relationship.EQUALS, -1000); - ess6.addPowerConstraint("#4", Phase.ALL, Pwr.REACTIVE, Relationship.EQUALS, -1000); + ess1.addPowerConstraint("#4", Phase.ALL, ACTIVE, LESS_OR_EQUALS, -2000); + ess2.addPowerConstraint("#4", Phase.ALL, ACTIVE, LESS_OR_EQUALS, -2000); + ess3.addPowerConstraint("#4", Phase.ALL, ACTIVE, LESS_OR_EQUALS, -2000); + ess4.addPowerConstraint("#4", Phase.ALL, ACTIVE, LESS_OR_EQUALS, -2000); + ess5.addPowerConstraint("#4", Phase.ALL, ACTIVE, LESS_OR_EQUALS, -2000); + ess6.addPowerConstraint("#4", Phase.ALL, ACTIVE, LESS_OR_EQUALS, -2000); + ess1.addPowerConstraint("#4", Phase.ALL, REACTIVE, EQUALS, -1000); + ess2.addPowerConstraint("#4", Phase.ALL, REACTIVE, EQUALS, -1000); + ess3.addPowerConstraint("#4", Phase.ALL, REACTIVE, EQUALS, -1000); + ess4.addPowerConstraint("#4", Phase.ALL, REACTIVE, EQUALS, -1000); + ess5.addPowerConstraint("#4", Phase.ALL, REACTIVE, EQUALS, -1000); + ess6.addPowerConstraint("#4", Phase.ALL, REACTIVE, EQUALS, -1000); componentTest.next(new TestCase("#4")); } @@ -390,7 +393,7 @@ public void testCommercial40Cluster() throws Exception { .addReference("addEss", ess1) // .addReference("addEss", ess2) // .activate(MyConfig.create() // - .setStrategy(SolverStrategy.OPTIMIZE_BY_MOVING_TOWARDS_TARGET) // + .setStrategy(OPTIMIZE_BY_MOVING_TOWARDS_TARGET) // .setSymmetricMode(true) // .setDebugMode(false) // .setEnablePid(false) // @@ -399,65 +402,65 @@ public void testCommercial40Cluster() throws Exception { // #1 ess1.withAllowedChargePower(-500).withAllowedDischargePower(500); ess2.withAllowedChargePower(-500).withAllowedDischargePower(500); - assertEquals(1000, ess0.getPower().getMaxPower(ess0, Phase.ALL, Pwr.ACTIVE)); - assertEquals(-1000, ess0.getPower().getMinPower(ess0, Phase.ALL, Pwr.ACTIVE)); + assertEquals(1000, ess0.getPower().getMaxPower(ess0, Phase.ALL, ACTIVE)); + assertEquals(-1000, ess0.getPower().getMinPower(ess0, Phase.ALL, ACTIVE)); expect("#1", ess1, -500, 0); expect("#1", ess2, -500, 0); - ess0.addPowerConstraint("#1", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, -1000); + ess0.addPowerConstraint("#1", Phase.ALL, ACTIVE, EQUALS, -1000); componentTest.next(new TestCase("#1")); // #2 ess1.withAllowedChargePower(-1000); ess2.withAllowedChargePower(-1000); - assertEquals(-2000, ess0.getPower().getMinPower(ess0, Phase.ALL, Pwr.ACTIVE)); + assertEquals(-2000, ess0.getPower().getMinPower(ess0, Phase.ALL, ACTIVE)); expect("#2", ess1, -1000, 0); expect("#2", ess2, -1000, 0); - ess0.addPowerConstraint("#2", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, -2000); + ess0.addPowerConstraint("#2", Phase.ALL, ACTIVE, EQUALS, -2000); componentTest.next(new TestCase("#2")); // #3 ess1.withAllowedChargePower(-2000); ess2.withAllowedChargePower(-2000); - assertEquals(-4000, ess0.getPower().getMinPower(ess0, Phase.ALL, Pwr.ACTIVE)); + assertEquals(-4000, ess0.getPower().getMinPower(ess0, Phase.ALL, ACTIVE)); expect("#3", ess1, -2000, 0); expect("#3", ess2, -2000, 0); - ess0.addPowerConstraint("#3", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, -4000); + ess0.addPowerConstraint("#3", Phase.ALL, ACTIVE, EQUALS, -4000); componentTest.next(new TestCase("#3")); // #4 ess1.withAllowedChargePower(-3000); ess2.withAllowedChargePower(-3000); - assertEquals(-6000, ess0.getPower().getMinPower(ess0, Phase.ALL, Pwr.ACTIVE)); + assertEquals(-6000, ess0.getPower().getMinPower(ess0, Phase.ALL, ACTIVE)); expect("#4", ess1, -2700, 0); // move towards ess1 because it is empty expect("#4", ess2, -2300, 0); - ess0.addPowerConstraint("#4", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, -5000); + ess0.addPowerConstraint("#4", Phase.ALL, ACTIVE, EQUALS, -5000); componentTest.next(new TestCase("#4")); // #5 ess1.withAllowedChargePower(-3500); ess2.withAllowedChargePower(-3500); - assertEquals(-7000, ess0.getPower().getMinPower(ess0, Phase.ALL, Pwr.ACTIVE)); + assertEquals(-7000, ess0.getPower().getMinPower(ess0, Phase.ALL, ACTIVE)); expect("#5", ess1, -2900, 0); expect("#5", ess2, -2100, 0); - ess0.addPowerConstraint("#5", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, -5000); + ess0.addPowerConstraint("#5", Phase.ALL, ACTIVE, EQUALS, -5000); componentTest.next(new TestCase("#5")); // #6 ess1.withAllowedChargePower(-4000); ess2.withAllowedChargePower(-4000); - assertEquals(-8000, ess0.getPower().getMinPower(ess0, Phase.ALL, Pwr.ACTIVE)); + assertEquals(-8000, ess0.getPower().getMinPower(ess0, Phase.ALL, ACTIVE)); expect("#6", ess1, -3100, 0); // move towards ess1 because it is empty expect("#6", ess2, -1900, 0); - ess0.addPowerConstraint("#6", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, -5000); + ess0.addPowerConstraint("#6", Phase.ALL, ACTIVE, EQUALS, -5000); componentTest.next(new TestCase("#6")); // #7 ess1.withAllowedChargePower(-6000); ess2.withAllowedChargePower(-6000); - assertEquals(-12000, ess0.getPower().getMinPower(ess0, Phase.ALL, Pwr.ACTIVE)); + assertEquals(-12000, ess0.getPower().getMinPower(ess0, Phase.ALL, ACTIVE)); expect("#7", ess1, -3300, 0); // move towards ess1 because it is empty expect("#7", ess2, -1700, 0); - ess0.addPowerConstraint("#7", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, -5000); + ess0.addPowerConstraint("#7", Phase.ALL, ACTIVE, EQUALS, -5000); componentTest.next(new TestCase("#7")); } @@ -508,7 +511,7 @@ public void testMultilayerCluster() throws Exception { .addReference("addEss", ess21) // .addReference("addEss", ess22) // .activate(MyConfig.create() // - .setStrategy(SolverStrategy.OPTIMIZE_BY_KEEPING_ALL_EQUAL) // + .setStrategy(OPTIMIZE_BY_KEEPING_ALL_EQUAL) // .setSymmetricMode(true) // .setDebugMode(false) // .setEnablePid(false) // @@ -519,8 +522,8 @@ public void testMultilayerCluster() throws Exception { expect("#1", ess12, 1500, 1500); expect("#1", ess21, 1500, 1500); expect("#1", ess22, 1500, 1500); - ess0.addPowerConstraint("#1", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, 6000); - ess0.addPowerConstraint("#1", Phase.ALL, Pwr.REACTIVE, Relationship.EQUALS, 6000); + ess0.addPowerConstraint("#1", Phase.ALL, ACTIVE, EQUALS, 6000); + ess0.addPowerConstraint("#1", Phase.ALL, REACTIVE, EQUALS, 6000); componentTest.next(new TestCase("#1")); } @@ -571,7 +574,7 @@ public void testNearEqualDistribution() throws Exception { .addReference("addEss", ess3) // .addReference("addEss", ess4) // .activate(MyConfig.create() // - .setStrategy(SolverStrategy.OPTIMIZE_BY_KEEPING_ALL_EQUAL) // + .setStrategy(OPTIMIZE_BY_KEEPING_ALL_EQUAL) // .setSymmetricMode(true) // .setDebugMode(false) // .setEnablePid(false) // @@ -583,7 +586,7 @@ public void testNearEqualDistribution() throws Exception { expect("#1.3", ess3, 2500, 0); expect("#1.4", ess4, 2500, 0); - ess0.addPowerConstraint("SetActivePowerEquals", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, 10000); + ess0.addPowerConstraint("SetActivePowerEquals", Phase.ALL, ACTIVE, EQUALS, 10000); ess0.setActivePowerEquals(10000); componentTest.next(new TestCase("#1")); @@ -593,7 +596,7 @@ public void testNearEqualDistribution() throws Exception { expect("#2.3", ess3, -2500, 0); expect("#2.4", ess4, -2500, 0); - ess0.addPowerConstraint("SetActivePowerEquals", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, -10000); + ess0.addPowerConstraint("SetActivePowerEquals", Phase.ALL, ACTIVE, EQUALS, -10000); ess0.setActivePowerEquals(10000); componentTest.next(new TestCase("#1")); @@ -606,7 +609,7 @@ public void testNearEqualDistribution() throws Exception { expect("#3.3", ess3, 2701, 0); expect("#3.4", ess4, 1897, 0); - ess0.addPowerConstraint("SetActivePowerEquals", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, 10000); + ess0.addPowerConstraint("SetActivePowerEquals", Phase.ALL, ACTIVE, EQUALS, 10000); componentTest.next(new TestCase("#3")); // #4 charging with lower allowed ccharge power @@ -618,7 +621,7 @@ public void testNearEqualDistribution() throws Exception { expect("#4.3", ess3, -9900, 0); expect("#4.4", ess4, -1881, 0); - ess0.addPowerConstraint("SetActivePowerEquals", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, -10000); + ess0.addPowerConstraint("SetActivePowerEquals", Phase.ALL, ACTIVE, EQUALS, -10000); componentTest.next(new TestCase("#4")); // #5 keeping zero @@ -627,7 +630,7 @@ public void testNearEqualDistribution() throws Exception { expect("#5.3", ess3, 0, 0); expect("#5.4", ess4, 0, 0); - ess0.addPowerConstraint("SetActivePowerEquals", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, 0); + ess0.addPowerConstraint("SetActivePowerEquals", Phase.ALL, ACTIVE, EQUALS, 0); componentTest.next(new TestCase("#5")); ess4.withAllowedChargePower(1000); @@ -638,7 +641,7 @@ public void testNearEqualDistribution() throws Exception { expect("#5.3", ess3, 0, 0); expect("#5.4", ess4, 0, 0); - ess0.addPowerConstraint("SetActivePowerEquals", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, 0); + ess0.addPowerConstraint("SetActivePowerEquals", Phase.ALL, ACTIVE, EQUALS, 0); componentTest.next(new TestCase("#5")); } diff --git a/io.openems.edge.ess.core/test/io/openems/edge/ess/core/power/PowerComponentTest2.java b/io.openems.edge.ess.core/test/io/openems/edge/ess/core/power/PowerComponentTest2.java index 7060c6e7393..dd36004444b 100644 --- a/io.openems.edge.ess.core/test/io/openems/edge/ess/core/power/PowerComponentTest2.java +++ b/io.openems.edge.ess.core/test/io/openems/edge/ess/core/power/PowerComponentTest2.java @@ -1,5 +1,8 @@ package io.openems.edge.ess.core.power; +import static io.openems.edge.ess.power.api.Pwr.ACTIVE; +import static io.openems.edge.ess.power.api.Relationship.EQUALS; +import static io.openems.edge.ess.power.api.SolverStrategy.OPTIMIZE_BY_KEEPING_ALL_EQUAL; import static org.junit.Assert.assertEquals; import java.util.concurrent.atomic.AtomicInteger; @@ -12,9 +15,6 @@ import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; import io.openems.edge.ess.power.api.Phase; -import io.openems.edge.ess.power.api.Pwr; -import io.openems.edge.ess.power.api.Relationship; -import io.openems.edge.ess.power.api.SolverStrategy; import io.openems.edge.ess.test.DummyManagedSymmetricEss; import io.openems.edge.ess.test.DummyMetaEss; @@ -55,7 +55,7 @@ public void testOnlyOneEssDistribution() throws Exception { .addReference("addEss", ess1) // .activate(MyConfig.create() // - .setStrategy(SolverStrategy.OPTIMIZE_BY_KEEPING_ALL_EQUAL) // + .setStrategy(OPTIMIZE_BY_KEEPING_ALL_EQUAL) // .setSymmetricMode(true) // .setDebugMode(false) // .setEnablePid(false) // @@ -120,7 +120,7 @@ public void testNearEqualDistribution() throws Exception { .addReference("addEss", ess3) // .addReference("addEss", ess4) // .activate(MyConfig.create() // - .setStrategy(SolverStrategy.OPTIMIZE_BY_KEEPING_ALL_EQUAL) // + .setStrategy(OPTIMIZE_BY_KEEPING_ALL_EQUAL) // .setSymmetricMode(true) // .setDebugMode(false) // .setEnablePid(false) // @@ -132,7 +132,7 @@ public void testNearEqualDistribution() throws Exception { expect("#1.3", ess3, 2500, 0); expect("#1.4", ess4, 2500, 0); - ess0.addPowerConstraint("SetActivePowerEquals1", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, 10000); + ess0.addPowerConstraint("SetActivePowerEquals1", Phase.ALL, ACTIVE, EQUALS, 10000); ess0.setActivePowerEquals(10000); componentTest.next(new TestCase("#1")); @@ -142,7 +142,7 @@ public void testNearEqualDistribution() throws Exception { expect("#2.3", ess3, -2500, 0); expect("#2.4", ess4, -2500, 0); - ess0.addPowerConstraint("SetActivePowerEquals2", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, -10000); + ess0.addPowerConstraint("SetActivePowerEquals2", Phase.ALL, ACTIVE, EQUALS, -10000); ess0.setActivePowerEquals(10000); componentTest.next(new TestCase("#1")); @@ -155,7 +155,7 @@ public void testNearEqualDistribution() throws Exception { expect("#3.3", ess3, 2701, 0); expect("#3.4", ess4, 1897, 0); - ess0.addPowerConstraint("SetActivePowerEquals3", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, 10000); + ess0.addPowerConstraint("SetActivePowerEquals3", Phase.ALL, ACTIVE, EQUALS, 10000); componentTest.next(new TestCase("#3")); // #4 charging with lower allowed charge power @@ -167,7 +167,7 @@ public void testNearEqualDistribution() throws Exception { expect("#4.3", ess3, -2703, 0); expect("#4.4", ess4, -1896, 0); - ess0.addPowerConstraint("SetActivePowerEquals4", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, -10000); + ess0.addPowerConstraint("SetActivePowerEquals4", Phase.ALL, ACTIVE, EQUALS, -10000); componentTest.next(new TestCase("#4")); // #5 keeping zero @@ -176,7 +176,7 @@ public void testNearEqualDistribution() throws Exception { expect("#5.3", ess3, 0, 0); expect("#5.4", ess4, 0, 0); - ess0.addPowerConstraint("SetActivePowerEquals5", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, 0); + ess0.addPowerConstraint("SetActivePowerEquals5", Phase.ALL, ACTIVE, EQUALS, 0); componentTest.next(new TestCase("#5")); ess4.withAllowedChargePower(1000); @@ -187,7 +187,7 @@ public void testNearEqualDistribution() throws Exception { expect("#5.3", ess3, 0, 0); expect("#5.4", ess4, 0, 0); - ess0.addPowerConstraint("ctrl0", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, 0); + ess0.addPowerConstraint("ctrl0", Phase.ALL, ACTIVE, EQUALS, 0); componentTest.next(new TestCase("#5")); } diff --git a/io.openems.edge.ess.fenecon.commercial40/test/io/openems/edge/ess/fenecon/commercial40/EssFeneconCommercial40ImplTest.java b/io.openems.edge.ess.fenecon.commercial40/test/io/openems/edge/ess/fenecon/commercial40/EssFeneconCommercial40ImplTest.java index fdd05793704..f1c7d45a6ff 100644 --- a/io.openems.edge.ess.fenecon.commercial40/test/io/openems/edge/ess/fenecon/commercial40/EssFeneconCommercial40ImplTest.java +++ b/io.openems.edge.ess.fenecon.commercial40/test/io/openems/edge/ess/fenecon/commercial40/EssFeneconCommercial40ImplTest.java @@ -8,17 +8,14 @@ public class EssFeneconCommercial40ImplTest { - private static final String ESS_ID = "ess0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ManagedSymmetricEssTest(new EssFeneconCommercial40Impl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(ESS_ID) // - .setModbusId(MODBUS_ID) // + .setId("ess0") // + .setModbusId("modbus0") // .setSurplusFeedInSocLimit(90) // .setSurplusFeedInAllowedChargePowerLimit(-8000) // .setSurplusFeedInIncreasePowerFactor(1.1) // diff --git a/io.openems.edge.ess.fenecon.commercial40/test/io/openems/edge/ess/fenecon/commercial40/charger/EssFeneconCommercial40Pv1ImplTest.java b/io.openems.edge.ess.fenecon.commercial40/test/io/openems/edge/ess/fenecon/commercial40/charger/EssFeneconCommercial40Pv1ImplTest.java index 317c043debe..91597df6669 100644 --- a/io.openems.edge.ess.fenecon.commercial40/test/io/openems/edge/ess/fenecon/commercial40/charger/EssFeneconCommercial40Pv1ImplTest.java +++ b/io.openems.edge.ess.fenecon.commercial40/test/io/openems/edge/ess/fenecon/commercial40/charger/EssFeneconCommercial40Pv1ImplTest.java @@ -10,19 +10,15 @@ public class EssFeneconCommercial40Pv1ImplTest { - private static final String CHARGER_ID = "charger0"; - private static final String ESS_ID = "ess0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { var ess = new EssFeneconCommercial40Impl(); new ManagedSymmetricEssTest(ess) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(io.openems.edge.ess.fenecon.commercial40.MyConfig.create() // - .setId(ESS_ID) // - .setModbusId(MODBUS_ID) // + .setId("ess0") // + .setModbusId("modbus0") // .setSurplusFeedInSocLimit(90) // .setSurplusFeedInAllowedChargePowerLimit(-8000) // .setSurplusFeedInIncreasePowerFactor(1.1) // @@ -34,11 +30,11 @@ public void test() throws Exception { new ComponentTest(new EssFeneconCommercial40Pv1Impl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("ess", ess) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfigPv1.create() // - .setId(CHARGER_ID) // - .setModbusId(MODBUS_ID) // - .setEssId(ESS_ID) // + .setId("charger0") // + .setModbusId("modbus0") // + .setEssId("ess0") // .setMaxActualPower(0) // .build()) // ; diff --git a/io.openems.edge.ess.fenecon.commercial40/test/io/openems/edge/ess/fenecon/commercial40/charger/EssFeneconCommercial40Pv2ImplTest.java b/io.openems.edge.ess.fenecon.commercial40/test/io/openems/edge/ess/fenecon/commercial40/charger/EssFeneconCommercial40Pv2ImplTest.java index 652b0363b74..80003e5447f 100644 --- a/io.openems.edge.ess.fenecon.commercial40/test/io/openems/edge/ess/fenecon/commercial40/charger/EssFeneconCommercial40Pv2ImplTest.java +++ b/io.openems.edge.ess.fenecon.commercial40/test/io/openems/edge/ess/fenecon/commercial40/charger/EssFeneconCommercial40Pv2ImplTest.java @@ -10,19 +10,15 @@ public class EssFeneconCommercial40Pv2ImplTest { - private static final String CHARGER_ID = "charger1"; - private static final String ESS_ID = "ess0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { var ess = new EssFeneconCommercial40Impl(); new ManagedSymmetricEssTest(ess) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(io.openems.edge.ess.fenecon.commercial40.MyConfig.create() // - .setId(ESS_ID) // - .setModbusId(MODBUS_ID) // + .setId("ess0") // + .setModbusId("modbus0") // .setSurplusFeedInSocLimit(90) // .setSurplusFeedInAllowedChargePowerLimit(-8000) // .setSurplusFeedInIncreasePowerFactor(1.1) // @@ -34,11 +30,11 @@ public void test() throws Exception { new ComponentTest(new EssFeneconCommercial40Pv2Impl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("ess", ess) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfigPv2.create() // - .setId(CHARGER_ID) // - .setModbusId(MODBUS_ID) // - .setEssId(ESS_ID) // + .setId("charger1") // + .setModbusId("modbus0") // + .setEssId("ess0") // .setMaxActualPower(0) // .build()) // ; diff --git a/io.openems.edge.ess.generic/test/io/openems/edge/ess/generic/common/AllowedChargeDischargeHandlerTest.java b/io.openems.edge.ess.generic/test/io/openems/edge/ess/generic/common/AllowedChargeDischargeHandlerTest.java index 8d8c1e1a08d..890f328d8ba 100644 --- a/io.openems.edge.ess.generic/test/io/openems/edge/ess/generic/common/AllowedChargeDischargeHandlerTest.java +++ b/io.openems.edge.ess.generic/test/io/openems/edge/ess/generic/common/AllowedChargeDischargeHandlerTest.java @@ -1,10 +1,11 @@ package io.openems.edge.ess.generic.common; +import static java.time.temporal.ChronoUnit.MILLIS; +import static java.time.temporal.ChronoUnit.SECONDS; import static org.junit.Assert.assertEquals; import java.time.Instant; import java.time.ZoneOffset; -import java.time.temporal.ChronoUnit; import org.junit.Test; @@ -30,60 +31,60 @@ public void testStart() throws Exception { sut.calculateAllowedChargeDischargePower(clockProvider, false, null, null, null); assertEquals(0, sut.lastBatteryAllowedChargePower, 0.001); assertEquals(0, sut.lastBatteryAllowedDischargePower, 0.001); - clock.leap(1, ChronoUnit.SECONDS); + clock.leap(1, SECONDS); sut.calculateAllowedChargeDischargePower(clockProvider, true, null, null, null); assertEquals(0, sut.lastBatteryAllowedChargePower, 0.001); assertEquals(0, sut.lastBatteryAllowedDischargePower, 0.001); - clock.leap(1, ChronoUnit.SECONDS); + clock.leap(1, SECONDS); sut.calculateAllowedChargeDischargePower(clockProvider, true, 9, -1, 500); assertEquals(225, sut.lastBatteryAllowedChargePower, 0.001); assertEquals(-475, sut.lastBatteryAllowedDischargePower, 0.001); - clock.leap(250, ChronoUnit.MILLIS); + clock.leap(250, MILLIS); sut.calculateAllowedChargeDischargePower(clockProvider, true, 9, -1, 500); - clock.leap(250, ChronoUnit.MILLIS); + clock.leap(250, MILLIS); sut.calculateAllowedChargeDischargePower(clockProvider, true, 9, -1, 500); assertEquals(-475, sut.lastBatteryAllowedDischargePower, 0.001); - clock.leap(250, ChronoUnit.MILLIS); + clock.leap(250, MILLIS); sut.calculateAllowedChargeDischargePower(clockProvider, true, 9, 0, 500); - clock.leap(250, ChronoUnit.MILLIS); + clock.leap(250, MILLIS); sut.calculateAllowedChargeDischargePower(clockProvider, true, 9, 0, 500); assertEquals(450, sut.lastBatteryAllowedChargePower, 0.001); assertEquals(0, sut.lastBatteryAllowedDischargePower, 0.001); - clock.leap(1, ChronoUnit.SECONDS); + clock.leap(1, SECONDS); sut.calculateAllowedChargeDischargePower(clockProvider, true, 9, 0, 500); assertEquals(675, sut.lastBatteryAllowedChargePower, 0.001); assertEquals(0, sut.lastBatteryAllowedDischargePower, 0.001); for (var i = 0; i < 15; i++) { - clock.leap(1, ChronoUnit.SECONDS); + clock.leap(1, SECONDS); sut.calculateAllowedChargeDischargePower(clockProvider, true, 9, 1, 500); } - clock.leap(1, ChronoUnit.SECONDS); + clock.leap(1, SECONDS); sut.calculateAllowedChargeDischargePower(clockProvider, true, 9, 1, 500); assertEquals(4275, sut.lastBatteryAllowedChargePower, 0.001); assertEquals(380, sut.lastBatteryAllowedDischargePower, 0.001); - clock.leap(1, ChronoUnit.SECONDS); + clock.leap(1, SECONDS); sut.calculateAllowedChargeDischargePower(clockProvider, true, 9, 1, 500); assertEquals(4500, sut.lastBatteryAllowedChargePower, 0.001); assertEquals(403.75, sut.lastBatteryAllowedDischargePower, 0.001); - clock.leap(1, ChronoUnit.SECONDS); + clock.leap(1, SECONDS); sut.calculateAllowedChargeDischargePower(clockProvider, true, 9, 2, 500); assertEquals(4500, sut.lastBatteryAllowedChargePower, 0.001); assertEquals(451.25, sut.lastBatteryAllowedDischargePower, 0.001); - clock.leap(1, ChronoUnit.SECONDS); + clock.leap(1, SECONDS); sut.calculateAllowedChargeDischargePower(clockProvider, true, 2, 0, 500); assertEquals(1000, sut.lastBatteryAllowedChargePower, 0.001); assertEquals(0, sut.lastBatteryAllowedDischargePower, 0.001); - clock.leap(1, ChronoUnit.SECONDS); + clock.leap(1, SECONDS); sut.calculateAllowedChargeDischargePower(clockProvider, true, 9, 9, 500); assertEquals(1225, sut.lastBatteryAllowedChargePower, 0.001); assertEquals(213.75, sut.lastBatteryAllowedDischargePower, 0.001); diff --git a/io.openems.edge.ess.generic/test/io/openems/edge/ess/generic/offgrid/EssGenericOffGridImplTest.java b/io.openems.edge.ess.generic/test/io/openems/edge/ess/generic/offgrid/EssGenericOffGridImplTest.java index 5fa9e0840b5..8761b50b6ed 100644 --- a/io.openems.edge.ess.generic/test/io/openems/edge/ess/generic/offgrid/EssGenericOffGridImplTest.java +++ b/io.openems.edge.ess.generic/test/io/openems/edge/ess/generic/offgrid/EssGenericOffGridImplTest.java @@ -1,11 +1,7 @@ package io.openems.edge.ess.generic.offgrid; -import java.time.Instant; -import java.time.ZoneOffset; - import org.junit.Test; -import io.openems.common.test.TimeLeapClock; import io.openems.edge.battery.test.DummyBattery; import io.openems.edge.batteryinverter.test.DummyOffGridBatteryInverter; import io.openems.edge.common.startstop.StartStopConfig; @@ -16,26 +12,20 @@ public class EssGenericOffGridImplTest { - private static final String ESS_ID = "ess0"; - private static final String BATTERY_ID = "battery0"; - private static final String BATTERY_INVERTER_ID = "batteryInverter0"; - private static final String OFF_GRID_SWITCH_ID = "offGridSwitch0"; - @Test public void testStart() throws Exception { - final var clock = new TimeLeapClock(Instant.parse("2020-01-01T01:00:00.00Z"), ZoneOffset.UTC); new ComponentTest(new EssGenericOffGridImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("componentManager", new DummyComponentManager(clock)) // - .addReference("batteryInverter", new DummyOffGridBatteryInverter(BATTERY_INVERTER_ID)) // - .addReference("battery", new DummyBattery(BATTERY_ID)) // - .addReference("offGridSwitch", new DummyOffGridSwitch(OFF_GRID_SWITCH_ID)) // + .addReference("componentManager", new DummyComponentManager()) // + .addReference("batteryInverter", new DummyOffGridBatteryInverter("batteryInverter0")) // + .addReference("battery", new DummyBattery("battery0")) // + .addReference("offGridSwitch", new DummyOffGridSwitch("offGridSwitch0")) // .activate(MyConfig.create() // - .setId(ESS_ID) // + .setId("ess0") // .setStartStopConfig(StartStopConfig.START) // - .setBatteryInverterId(BATTERY_INVERTER_ID) // - .setBatteryId(BATTERY_ID) // - .setOffGridSwitchId(OFF_GRID_SWITCH_ID) // + .setBatteryInverterId("batteryInverter0") // + .setBatteryId("battery0") // + .setOffGridSwitchId("offGridSwitch0") // .build()) // ; } diff --git a/io.openems.edge.ess.generic/test/io/openems/edge/ess/generic/symmetric/EssGenericManagedSymmetricImplTest.java b/io.openems.edge.ess.generic/test/io/openems/edge/ess/generic/symmetric/EssGenericManagedSymmetricImplTest.java index 10a90e7e888..431c8e1d3c9 100644 --- a/io.openems.edge.ess.generic/test/io/openems/edge/ess/generic/symmetric/EssGenericManagedSymmetricImplTest.java +++ b/io.openems.edge.ess.generic/test/io/openems/edge/ess/generic/symmetric/EssGenericManagedSymmetricImplTest.java @@ -1,5 +1,12 @@ package io.openems.edge.ess.generic.symmetric; +import static io.openems.edge.battery.api.Battery.ChannelId.CHARGE_MAX_CURRENT; +import static io.openems.edge.battery.api.Battery.ChannelId.DISCHARGE_MAX_CURRENT; +import static io.openems.edge.batteryinverter.api.SymmetricBatteryInverter.ChannelId.ACTIVE_POWER; +import static io.openems.edge.common.startstop.StartStoppable.ChannelId.START_STOP; +import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.ALLOWED_DISCHARGE_POWER; +import static io.openems.edge.ess.generic.common.GenericManagedEss.EFFICIENCY_FACTOR; +import static io.openems.edge.ess.generic.symmetric.EssGenericManagedSymmetric.ChannelId.STATE_MACHINE; import static org.junit.Assert.assertEquals; import java.time.Instant; @@ -9,7 +16,6 @@ import org.junit.Test; import io.openems.common.test.TimeLeapClock; -import io.openems.common.types.ChannelAddress; import io.openems.edge.battery.test.DummyBattery; import io.openems.edge.batteryinverter.test.DummyManagedSymmetricBatteryInverter; import io.openems.edge.common.startstop.StartStop; @@ -18,57 +24,38 @@ import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.ess.generic.common.GenericManagedEss; import io.openems.edge.ess.generic.symmetric.statemachine.StateMachine.State; import io.openems.edge.ess.test.DummyPower; import io.openems.edge.ess.test.ManagedSymmetricEssTest; public class EssGenericManagedSymmetricImplTest { - private static final String ESS_ID = "ess0"; - private static final String BATTERY_ID = "battery0"; - private static final String BATTERY_INVERTER_ID = "batteryInverter0"; - - private static final ChannelAddress ESS_STATE_MACHINE = new ChannelAddress(ESS_ID, "StateMachine"); - private static final ChannelAddress ESS_ALLOWED_DISCHARGE_POWER = new ChannelAddress(ESS_ID, - "AllowedDischargePower"); - - private static final ChannelAddress BATTERY_START_STOP = new ChannelAddress(BATTERY_ID, "StartStop"); - private static final ChannelAddress BATTERY_CHARGE_MAX_CURRENT = new ChannelAddress(BATTERY_ID, "ChargeMaxCurrent"); - private static final ChannelAddress BATTERY_DISCHARGE_MAX_CURRENT = new ChannelAddress(BATTERY_ID, - "DischargeMaxCurrent"); - - private static final ChannelAddress BATTERY_INVERTER_START_STOP = new ChannelAddress(BATTERY_INVERTER_ID, - "StartStop"); - private static final ChannelAddress BATTERY_INVERTER_ACTIVE_POWER = new ChannelAddress(BATTERY_INVERTER_ID, - "ActivePower"); - @Test public void testStart() throws Exception { final var clock = new TimeLeapClock(Instant.parse("2020-01-01T01:00:00.00Z"), ZoneOffset.UTC); new ComponentTest(new EssGenericManagedSymmetricImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager(clock)) // - .addReference("batteryInverter", new DummyManagedSymmetricBatteryInverter(BATTERY_INVERTER_ID)) // - .addReference("battery", new DummyBattery(BATTERY_ID)) // + .addReference("batteryInverter", new DummyManagedSymmetricBatteryInverter("batteryInverter0")) // + .addReference("battery", new DummyBattery("battery0")) // .activate(MyConfig.create() // - .setId(ESS_ID) // + .setId("ess0") // .setStartStopConfig(StartStopConfig.START) // - .setBatteryInverterId(BATTERY_INVERTER_ID) // - .setBatteryId(BATTERY_ID) // + .setBatteryInverterId("batteryInverter0") // + .setBatteryId("battery0") // .build()) // .next(new TestCase() // - .output(ESS_STATE_MACHINE, State.UNDEFINED)) // + .output(STATE_MACHINE, State.UNDEFINED)) // .next(new TestCase() // - .output(ESS_STATE_MACHINE, State.START_BATTERY)) // + .output(STATE_MACHINE, State.START_BATTERY)) // .next(new TestCase("Start the Battery") // - .input(BATTERY_START_STOP, StartStop.START)) // + .input("battery0", START_STOP, StartStop.START)) // .next(new TestCase() // - .output(ESS_STATE_MACHINE, State.START_BATTERY_INVERTER)) // + .output(STATE_MACHINE, State.START_BATTERY_INVERTER)) // .next(new TestCase("Start the Battery-Inverter") // - .input(BATTERY_INVERTER_START_STOP, StartStop.START)) // + .input("batteryInverter0", START_STOP, StartStop.START)) // .next(new TestCase() // - .output(ESS_STATE_MACHINE, State.STARTED)) // + .output(STATE_MACHINE, State.STARTED)) // ; } @@ -78,30 +65,30 @@ public void testForceCharge() throws Exception { .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // - .addReference("batteryInverter", new DummyManagedSymmetricBatteryInverter(BATTERY_INVERTER_ID)) // - .addReference("battery", new DummyBattery(BATTERY_ID) // + .addReference("batteryInverter", new DummyManagedSymmetricBatteryInverter("batteryInverter0")) // + .addReference("battery", new DummyBattery("battery0") // .withVoltage(500) // .withChargeMaxCurrent(50) // .withDischargeMaxCurrent(-5) // ) // .activate(MyConfig.create() // - .setId(ESS_ID) // + .setId("ess0") // .setStartStopConfig(StartStopConfig.START) // - .setBatteryInverterId(BATTERY_INVERTER_ID) // - .setBatteryId(BATTERY_ID) // + .setBatteryInverterId("batteryInverter0") // + .setBatteryId("battery0") // .build()) // .next(new TestCase("Start the Battery") // - .input(BATTERY_START_STOP, StartStop.START) // - .output(ESS_ALLOWED_DISCHARGE_POWER, 0) // - .output(BATTERY_INVERTER_ACTIVE_POWER, 0)) // + .input("battery0", START_STOP, StartStop.START) // + .output(ALLOWED_DISCHARGE_POWER, 0) // + .output(ACTIVE_POWER, 0)) // .next(new TestCase()) // .next(new TestCase("Start the Battery-Inverter") // - .input(BATTERY_INVERTER_START_STOP, StartStop.START)) // + .input("batteryInverter0", START_STOP, StartStop.START)) // .next(new TestCase()) // .next(new TestCase() // - .input(BATTERY_CHARGE_MAX_CURRENT, 50) // - .input(BATTERY_DISCHARGE_MAX_CURRENT, -5) // - .output(ESS_ALLOWED_DISCHARGE_POWER, (int) (-2500 * GenericManagedEss.EFFICIENCY_FACTOR))) // + .input("battery0", CHARGE_MAX_CURRENT, 50) // + .input("battery0", DISCHARGE_MAX_CURRENT, -5) // + .output(ALLOWED_DISCHARGE_POWER, (int) (-2500 * EFFICIENCY_FACTOR))) // ; } @@ -113,20 +100,20 @@ public void testDebugLog() throws Exception { .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager(clock)) // - .addReference("batteryInverter", new DummyManagedSymmetricBatteryInverter(BATTERY_INVERTER_ID) // + .addReference("batteryInverter", new DummyManagedSymmetricBatteryInverter("batteryInverter0") // .withStartStop(StartStop.START) // .withMaxApparentPower(92_000)) // - .addReference("battery", new DummyBattery(BATTERY_ID) // + .addReference("battery", new DummyBattery("battery0") // .withStartStop(StartStop.START) // .withSoc(60) // .withVoltage(700) // .withChargeMaxCurrent(80) // .withDischargeMaxCurrent(70)) // .activate(MyConfig.create() // - .setId(ESS_ID) // + .setId("ess0") // .setStartStopConfig(StartStopConfig.START) // - .setBatteryInverterId(BATTERY_INVERTER_ID) // - .setBatteryId(BATTERY_ID) // + .setBatteryInverterId("batteryInverter0") // + .setBatteryId("battery0") // .build()) // .next(new TestCase() // .onBeforeProcessImage(() -> clock.leap(10, ChronoUnit.SECONDS)), 10); @@ -139,30 +126,29 @@ public void testTimeout() throws Exception { new ComponentTest(new EssGenericManagedSymmetricImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager(clock)) // - .addReference("batteryInverter", new DummyManagedSymmetricBatteryInverter(BATTERY_INVERTER_ID)) // - .addReference("battery", new DummyBattery(BATTERY_ID)) // + .addReference("batteryInverter", new DummyManagedSymmetricBatteryInverter("batteryInverter0")) // + .addReference("battery", new DummyBattery("battery0")) // .activate(MyConfig.create() // - .setId(ESS_ID) // + .setId("ess0") // .setStartStopConfig(StartStopConfig.START) // - .setBatteryInverterId(BATTERY_INVERTER_ID) // - .setBatteryId(BATTERY_ID) // + .setBatteryInverterId("batteryInverter0") // + .setBatteryId("battery0") // .build()) // .next(new TestCase() // - .output(ESS_STATE_MACHINE, State.UNDEFINED)) // + .output(STATE_MACHINE, State.UNDEFINED)) // .next(new TestCase() // - .output(ESS_STATE_MACHINE, State.START_BATTERY)) // + .output(STATE_MACHINE, State.START_BATTERY)) // .next(new TestCase("Start the Battery") // - .input(BATTERY_START_STOP, StartStop.START)) // + .input("battery0", START_STOP, StartStop.START)) // .next(new TestCase() // - .output(ESS_STATE_MACHINE, State.START_BATTERY_INVERTER)) // + .output(STATE_MACHINE, State.START_BATTERY_INVERTER)) // .next(new TestCase()// - .input(BATTERY_INVERTER_START_STOP, StartStop.STOP)// - .timeleap(clock, 350, ChronoUnit.SECONDS)// - )// + .input("batteryInverter0", START_STOP, StartStop.STOP)// + .timeleap(clock, 350, ChronoUnit.SECONDS)) // .next(new TestCase() // - .output(ESS_STATE_MACHINE, State.ERROR)) // + .output(STATE_MACHINE, State.ERROR)) // .next(new TestCase() // - .output(ESS_STATE_MACHINE, State.ERROR)) // + .output(STATE_MACHINE, State.ERROR)) // ; } } diff --git a/io.openems.edge.ess.generic/test/io/openems/edge/ess/generic/symmetric/EssProtectionTest.java b/io.openems.edge.ess.generic/test/io/openems/edge/ess/generic/symmetric/EssProtectionTest.java index 62959e6da20..d355eeee95c 100644 --- a/io.openems.edge.ess.generic/test/io/openems/edge/ess/generic/symmetric/EssProtectionTest.java +++ b/io.openems.edge.ess.generic/test/io/openems/edge/ess/generic/symmetric/EssProtectionTest.java @@ -1,15 +1,23 @@ package io.openems.edge.ess.generic.symmetric; +import static io.openems.edge.battery.api.Battery.ChannelId.CHARGE_MAX_CURRENT; +import static io.openems.edge.battery.api.Battery.ChannelId.CHARGE_MAX_VOLTAGE; +import static io.openems.edge.battery.api.Battery.ChannelId.DISCHARGE_MAX_CURRENT; +import static io.openems.edge.battery.api.Battery.ChannelId.DISCHARGE_MIN_VOLTAGE; +import static io.openems.edge.battery.api.Battery.ChannelId.SOC; +import static io.openems.edge.battery.api.Battery.ChannelId.VOLTAGE; +import static io.openems.edge.ess.generic.symmetric.EssProtection.ChannelId.EP_CHARGE_MAX_CURRENT; +import static io.openems.edge.ess.generic.symmetric.EssProtection.ChannelId.EP_DISCHARGE_MAX_CURRENT; +import static java.time.temporal.ChronoUnit.MINUTES; +import static java.time.temporal.ChronoUnit.SECONDS; import static org.junit.Assert.assertEquals; import java.time.Instant; import java.time.ZoneOffset; -import java.time.temporal.ChronoUnit; import org.junit.Test; import io.openems.common.test.TimeLeapClock; -import io.openems.common.types.ChannelAddress; import io.openems.edge.battery.test.DummyBattery; import io.openems.edge.batteryinverter.test.DummyManagedSymmetricBatteryInverter; import io.openems.edge.common.startstop.StartStop; @@ -22,30 +30,16 @@ public class EssProtectionTest { - private static final String ESS_ID = "ess0"; - private static final String BATTERY_ID = "battery0"; - private static final String BATTERY_INVERTER_ID = "batteryInverter0"; - private static final ChannelAddress BATTERY_SOC = new ChannelAddress(BATTERY_ID, "Soc"); - private static final ChannelAddress BATTERY_VOLTAGE = new ChannelAddress(BATTERY_ID, "Voltage"); - private static final ChannelAddress BATTERY_CHARGE_MAX_VOLTAGE = new ChannelAddress(BATTERY_ID, "ChargeMaxVoltage"); - private static final ChannelAddress BATTERY_DISCHARGE_MIN_VOLTAGE = new ChannelAddress(BATTERY_ID, - "DischargeMinVoltage"); - private static final ChannelAddress BATTERY_CHARGE_MAX_CURRENT = new ChannelAddress(BATTERY_ID, "ChargeMaxCurrent"); - private static final ChannelAddress BATTERY_DISCHARGE_MAX_CURRENT = new ChannelAddress(BATTERY_ID, - "DischargeMaxCurrent"); - private static final ChannelAddress ESS_CHARGE_MAX_CURRENT = new ChannelAddress(ESS_ID, "EpChargeMaxCurrent"); - private static final ChannelAddress ESS_DISCHARGE_MAX_CURRENT = new ChannelAddress(ESS_ID, "EpDischargeMaxCurrent"); - @Test public void testEssProtection() throws Exception { final var ess = new EssGenericManagedSymmetricImpl(); final var clock = new TimeLeapClock(Instant.parse("2020-01-01T01:00:00.00Z"), ZoneOffset.UTC); - final var batteryInverter = new DummyManagedSymmetricBatteryInverter(BATTERY_INVERTER_ID)// + final var batteryInverter = new DummyManagedSymmetricBatteryInverter("batteryInverter0")// .withStartStop(StartStop.START) // .withMaxApparentPower(92000)// .withDcMaxVoltage(1315)// .withDcMinVoltage(650); - final var battery = new DummyBattery(BATTERY_ID)// + final var battery = new DummyBattery("battery0")// .withStartStop(StartStop.START) // .withSoc(80)// .withChargeMaxCurrent(169)// @@ -62,64 +56,64 @@ public void testEssProtection() throws Exception { .addReference("batteryInverter", batteryInverter) // .addReference("battery", battery) // .activate(MyConfig.create() // - .setId(ESS_ID) // + .setId("ess0") // .setStartStopConfig(StartStopConfig.START) // - .setBatteryInverterId(BATTERY_INVERTER_ID) // - .setBatteryId(BATTERY_ID) // + .setBatteryInverterId("batteryInverter0") // + .setBatteryId("battery0") // .build()) // .next(new TestCase() // - .onBeforeProcessImage(() -> clock.leap(1, ChronoUnit.MINUTES)), 10)// - .next(new TestCase()// - .input(BATTERY_VOLTAGE, 700)// - .input(BATTERY_SOC, 80)// - .input(BATTERY_CHARGE_MAX_CURRENT, 169)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594))// + .onBeforeProcessImage(() -> clock.leap(1, MINUTES)), 10)// + .next(new TestCase()// + .input("battery0", VOLTAGE, 700)// + .input("battery0", SOC, 80)// + .input("battery0", CHARGE_MAX_CURRENT, 169)// + .input("battery0", DISCHARGE_MAX_CURRENT, 169)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594))// .next(new TestCase() // - .onBeforeProcessImage(() -> clock.leap(1, ChronoUnit.MINUTES)), 10)// - .next(new TestCase()// - .input(BATTERY_VOLTAGE, 700)// - .input(BATTERY_SOC, 80)// - .input(BATTERY_CHARGE_MAX_CURRENT, 169)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594))// + .onBeforeProcessImage(() -> clock.leap(1, MINUTES)), 10)// + .next(new TestCase()// + .input("battery0", VOLTAGE, 700)// + .input("battery0", SOC, 80)// + .input("battery0", CHARGE_MAX_CURRENT, 169)// + .input("battery0", DISCHARGE_MAX_CURRENT, 169)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594))// .next(new TestCase() // - .onBeforeProcessImage(() -> clock.leap(1, ChronoUnit.MINUTES)), 10)// - .next(new TestCase()// - .input(BATTERY_VOLTAGE, 700)// - .input(BATTERY_SOC, 80)// - .input(BATTERY_CHARGE_MAX_CURRENT, 169)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594))// + .onBeforeProcessImage(() -> clock.leap(1, MINUTES)), 10)// + .next(new TestCase()// + .input("battery0", VOLTAGE, 700)// + .input("battery0", SOC, 80)// + .input("battery0", CHARGE_MAX_CURRENT, 169)// + .input("battery0", DISCHARGE_MAX_CURRENT, 169)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594))// ;// assertEquals("Started|SoC:80 %|L:0 W|Allowed:-92000;92000", ess.debugLog()); sutManaged// .next(new TestCase()// - .timeleap(clock, 1, ChronoUnit.MINUTES))// + .timeleap(clock, 1, MINUTES))// .next(new TestCase()// - .input(BATTERY_VOLTAGE, 700)// - .input(BATTERY_SOC, 60)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 595)// + .input("battery0", VOLTAGE, 700)// + .input("battery0", SOC, 60)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 595)// )// .next(new TestCase()// - .timeleap(clock, 1, ChronoUnit.SECONDS))// + .timeleap(clock, 1, SECONDS))// .next(new TestCase()// - .input(BATTERY_VOLTAGE, 700)// - .input(BATTERY_SOC, 60)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 595)// + .input("battery0", VOLTAGE, 700)// + .input("battery0", SOC, 60)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 595)// )// .next(new TestCase()// - .timeleap(clock, 1, ChronoUnit.SECONDS))// + .timeleap(clock, 1, SECONDS))// .next(new TestCase()// - .input(BATTERY_VOLTAGE, 700)// - .input(BATTERY_SOC, 60)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 595)// + .input("battery0", VOLTAGE, 700)// + .input("battery0", SOC, 60)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 595)// )// ;// assertEquals("Started|SoC:60 %|L:0 W|Allowed:-92000;92000", ess.debugLog()); @@ -127,143 +121,143 @@ public void testEssProtection() throws Exception { // Force charge sutManaged// .next(new TestCase()// - .input(BATTERY_VOLTAGE, 645)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 0)// - .output(ESS_DISCHARGE_MAX_CURRENT, 167)// + .input("battery0", VOLTAGE, 645)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", DISCHARGE_MAX_CURRENT, 0)// + .output(EP_DISCHARGE_MAX_CURRENT, 167)// )// .next(new TestCase()// - .input(BATTERY_VOLTAGE, 645)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_CHARGE_MAX_CURRENT, 169)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 0)// - .output(ESS_DISCHARGE_MAX_CURRENT, 112)// + .input("battery0", VOLTAGE, 645)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", CHARGE_MAX_CURRENT, 169)// + .input("battery0", DISCHARGE_MAX_CURRENT, 0)// + .output(EP_DISCHARGE_MAX_CURRENT, 112)// )// .next(new TestCase()// - .input(BATTERY_VOLTAGE, 645)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_CHARGE_MAX_CURRENT, 169)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 0)// - .output(ESS_DISCHARGE_MAX_CURRENT, 75)// + .input("battery0", VOLTAGE, 645)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", CHARGE_MAX_CURRENT, 169)// + .input("battery0", DISCHARGE_MAX_CURRENT, 0)// + .output(EP_DISCHARGE_MAX_CURRENT, 75)// )// .next(new TestCase()// - .input(BATTERY_VOLTAGE, 645)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_CHARGE_MAX_CURRENT, 169)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 0)// - .output(ESS_DISCHARGE_MAX_CURRENT, 49)// + .input("battery0", VOLTAGE, 645)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", CHARGE_MAX_CURRENT, 169)// + .input("battery0", DISCHARGE_MAX_CURRENT, 0)// + .output(EP_DISCHARGE_MAX_CURRENT, 49)// )// .next(new TestCase()// - .input(BATTERY_VOLTAGE, 645)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_CHARGE_MAX_CURRENT, 169)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 0)// - .output(ESS_DISCHARGE_MAX_CURRENT, 32)// + .input("battery0", VOLTAGE, 645)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", CHARGE_MAX_CURRENT, 169)// + .input("battery0", DISCHARGE_MAX_CURRENT, 0)// + .output(EP_DISCHARGE_MAX_CURRENT, 32)// )// .next(new TestCase()// - .input(BATTERY_VOLTAGE, 645)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_CHARGE_MAX_CURRENT, 169)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 0)// - .output(ESS_DISCHARGE_MAX_CURRENT, 20)// + .input("battery0", VOLTAGE, 645)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", CHARGE_MAX_CURRENT, 169)// + .input("battery0", DISCHARGE_MAX_CURRENT, 0)// + .output(EP_DISCHARGE_MAX_CURRENT, 20)// )// .next(new TestCase()// - .input(BATTERY_VOLTAGE, 645)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_CHARGE_MAX_CURRENT, 169)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 0)// - .output(ESS_DISCHARGE_MAX_CURRENT, 12)// + .input("battery0", VOLTAGE, 645)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", CHARGE_MAX_CURRENT, 169)// + .input("battery0", DISCHARGE_MAX_CURRENT, 0)// + .output(EP_DISCHARGE_MAX_CURRENT, 12)// )// .next(new TestCase()// - .input(BATTERY_VOLTAGE, 645)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_CHARGE_MAX_CURRENT, 169)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 0)// - .output(ESS_DISCHARGE_MAX_CURRENT, 6)// + .input("battery0", VOLTAGE, 645)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", CHARGE_MAX_CURRENT, 169)// + .input("battery0", DISCHARGE_MAX_CURRENT, 0)// + .output(EP_DISCHARGE_MAX_CURRENT, 6)// )// .next(new TestCase()// - .input(BATTERY_VOLTAGE, 645)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_CHARGE_MAX_CURRENT, 169)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 0)// - .output(ESS_DISCHARGE_MAX_CURRENT, 3)// + .input("battery0", VOLTAGE, 645)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", CHARGE_MAX_CURRENT, 169)// + .input("battery0", DISCHARGE_MAX_CURRENT, 0)// + .output(EP_DISCHARGE_MAX_CURRENT, 3)// )// .next(new TestCase()// - .input(BATTERY_VOLTAGE, 645)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_CHARGE_MAX_CURRENT, 169)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 0)// - .output(ESS_DISCHARGE_MAX_CURRENT, 0)// + .input("battery0", VOLTAGE, 645)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", CHARGE_MAX_CURRENT, 169)// + .input("battery0", DISCHARGE_MAX_CURRENT, 0)// + .output(EP_DISCHARGE_MAX_CURRENT, 0)// )// .next(new TestCase()// - .input(BATTERY_VOLTAGE, 645)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 0)// - .output(ESS_DISCHARGE_MAX_CURRENT, 0)// + .input("battery0", VOLTAGE, 645)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", DISCHARGE_MAX_CURRENT, 0)// + .output(EP_DISCHARGE_MAX_CURRENT, 0)// )// .next(new TestCase()// - .input(BATTERY_VOLTAGE, 645)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 0)// - .output(ESS_DISCHARGE_MAX_CURRENT, -1)// + .input("battery0", VOLTAGE, 645)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", DISCHARGE_MAX_CURRENT, 0)// + .output(EP_DISCHARGE_MAX_CURRENT, -1)// )// .next(new TestCase()// - .input(BATTERY_VOLTAGE, 645)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 0)// - .output(ESS_DISCHARGE_MAX_CURRENT, -2)// + .input("battery0", VOLTAGE, 645)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", DISCHARGE_MAX_CURRENT, 0)// + .output(EP_DISCHARGE_MAX_CURRENT, -2)// )// .next(new TestCase()// - .input(BATTERY_VOLTAGE, 650)// - .input(BATTERY_SOC, 0)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .output(ESS_DISCHARGE_MAX_CURRENT, -2)// + .input("battery0", VOLTAGE, 650)// + .input("battery0", SOC, 0)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .output(EP_DISCHARGE_MAX_CURRENT, -2)// )// .next(new TestCase()// - .input(BATTERY_VOLTAGE, 650)// - .input(BATTERY_SOC, 0)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, -2)// - .output(ESS_DISCHARGE_MAX_CURRENT, -1)// + .input("battery0", VOLTAGE, 650)// + .input("battery0", SOC, 0)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", DISCHARGE_MAX_CURRENT, -2)// + .output(EP_DISCHARGE_MAX_CURRENT, -1)// )// .next(new TestCase()// - .input(BATTERY_VOLTAGE, 650)// - .input(BATTERY_SOC, 0)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, -2)// - .output(ESS_DISCHARGE_MAX_CURRENT, -1)// + .input("battery0", VOLTAGE, 650)// + .input("battery0", SOC, 0)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", DISCHARGE_MAX_CURRENT, -2)// + .output(EP_DISCHARGE_MAX_CURRENT, -1)// )// .next(new TestCase()// - .input(BATTERY_VOLTAGE, 650)// - .input(BATTERY_SOC, 0)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, -2)// - .output(ESS_DISCHARGE_MAX_CURRENT, 0)// + .input("battery0", VOLTAGE, 650)// + .input("battery0", SOC, 0)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", DISCHARGE_MAX_CURRENT, -2)// + .output(EP_DISCHARGE_MAX_CURRENT, 0)// )// .next(new TestCase()// - .input(BATTERY_VOLTAGE, 650)// - .input(BATTERY_SOC, 0)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, -2)// - .output(ESS_DISCHARGE_MAX_CURRENT, 0)// + .input("battery0", VOLTAGE, 650)// + .input("battery0", SOC, 0)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", DISCHARGE_MAX_CURRENT, -2)// + .output(EP_DISCHARGE_MAX_CURRENT, 0)// )// ;// assertEquals("Started|SoC:0 %|L:-1235 W|Allowed:-92000;-1235", ess.debugLog()); @@ -271,197 +265,197 @@ public void testEssProtection() throws Exception { // normal condition sutManaged// .next(new TestCase()// - .input(BATTERY_VOLTAGE, 700)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// - .input(BATTERY_CHARGE_MAX_CURRENT, 169)// - .output(ESS_CHARGE_MAX_CURRENT, 654)// + .input("battery0", VOLTAGE, 700)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", DISCHARGE_MAX_CURRENT, 169)// + .input("battery0", CHARGE_MAX_CURRENT, 169)// + .output(EP_CHARGE_MAX_CURRENT, 654)// )// .next(new TestCase()// - .timeleap(clock, 1, ChronoUnit.MINUTES))// + .timeleap(clock, 1, MINUTES))// .next(new TestCase()// - .input(BATTERY_VOLTAGE, 700)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// - .input(BATTERY_CHARGE_MAX_CURRENT, 169)// - .output(ESS_CHARGE_MAX_CURRENT, 599)// + .input("battery0", VOLTAGE, 700)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", DISCHARGE_MAX_CURRENT, 169)// + .input("battery0", CHARGE_MAX_CURRENT, 169)// + .output(EP_CHARGE_MAX_CURRENT, 599)// )// .next(new TestCase()// - .timeleap(clock, 1, ChronoUnit.MINUTES))// + .timeleap(clock, 1, MINUTES))// .next(new TestCase()// - .input(BATTERY_VOLTAGE, 700)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// - .input(BATTERY_CHARGE_MAX_CURRENT, 169)// - .output(ESS_CHARGE_MAX_CURRENT, 561)// + .input("battery0", VOLTAGE, 700)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", DISCHARGE_MAX_CURRENT, 169)// + .input("battery0", CHARGE_MAX_CURRENT, 169)// + .output(EP_CHARGE_MAX_CURRENT, 561)// )// .next(new TestCase()// - .timeleap(clock, 1, ChronoUnit.MINUTES))// + .timeleap(clock, 1, MINUTES))// ;// // Force discharge sutManaged// .next(new TestCase()// - .input(BATTERY_VOLTAGE, 796)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// - .input(BATTERY_CHARGE_MAX_CURRENT, 0)// - .output(ESS_CHARGE_MAX_CURRENT, 383)// + .input("battery0", VOLTAGE, 796)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", DISCHARGE_MAX_CURRENT, 169)// + .input("battery0", CHARGE_MAX_CURRENT, 0)// + .output(EP_CHARGE_MAX_CURRENT, 383)// )// .next(new TestCase()// - .input(BATTERY_VOLTAGE, 796)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// - .input(BATTERY_CHARGE_MAX_CURRENT, 0)// - .output(ESS_CHARGE_MAX_CURRENT, 261)// + .input("battery0", VOLTAGE, 796)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", DISCHARGE_MAX_CURRENT, 169)// + .input("battery0", CHARGE_MAX_CURRENT, 0)// + .output(EP_CHARGE_MAX_CURRENT, 261)// )// .next(new TestCase()// - .input(BATTERY_VOLTAGE, 796)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// - .input(BATTERY_CHARGE_MAX_CURRENT, 0)// - .output(ESS_CHARGE_MAX_CURRENT, 178)// + .input("battery0", VOLTAGE, 796)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", DISCHARGE_MAX_CURRENT, 169)// + .input("battery0", CHARGE_MAX_CURRENT, 0)// + .output(EP_CHARGE_MAX_CURRENT, 178)// )// .next(new TestCase()// - .input(BATTERY_VOLTAGE, 796)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// - .input(BATTERY_CHARGE_MAX_CURRENT, 0)// - .output(ESS_CHARGE_MAX_CURRENT, 122)// + .input("battery0", VOLTAGE, 796)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", DISCHARGE_MAX_CURRENT, 169)// + .input("battery0", CHARGE_MAX_CURRENT, 0)// + .output(EP_CHARGE_MAX_CURRENT, 122)// )// .next(new TestCase()// - .input(BATTERY_VOLTAGE, 796)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// - .input(BATTERY_CHARGE_MAX_CURRENT, 0)// - .output(ESS_CHARGE_MAX_CURRENT, 83)// - )// + .input("battery0", VOLTAGE, 796)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", DISCHARGE_MAX_CURRENT, 169)// + .input("battery0", CHARGE_MAX_CURRENT, 0)// + .output(EP_CHARGE_MAX_CURRENT, 83)// + )// .next(new TestCase()// - .input(BATTERY_VOLTAGE, 796)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// - .input(BATTERY_CHARGE_MAX_CURRENT, 0)// - .output(ESS_CHARGE_MAX_CURRENT, 57)// - )// - .next(new TestCase()// - .input(BATTERY_VOLTAGE, 796)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// - .input(BATTERY_CHARGE_MAX_CURRENT, 0)// - .output(ESS_CHARGE_MAX_CURRENT, 38)// - )// - .next(new TestCase()// - .input(BATTERY_VOLTAGE, 796)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// - .input(BATTERY_CHARGE_MAX_CURRENT, 0)// - .output(ESS_CHARGE_MAX_CURRENT, 26)// - )// - .next(new TestCase()// - .input(BATTERY_VOLTAGE, 796)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// - .input(BATTERY_CHARGE_MAX_CURRENT, 0)// - .output(ESS_CHARGE_MAX_CURRENT, 18)// - )// - .next(new TestCase()// - .input(BATTERY_VOLTAGE, 796)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// - .input(BATTERY_CHARGE_MAX_CURRENT, 0)// - .output(ESS_CHARGE_MAX_CURRENT, 12)// - )// - .next(new TestCase()// - .input(BATTERY_VOLTAGE, 796)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// - .input(BATTERY_CHARGE_MAX_CURRENT, 0)// - .output(ESS_CHARGE_MAX_CURRENT, 8)// - )// - .next(new TestCase()// - .input(BATTERY_VOLTAGE, 796)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// - .input(BATTERY_CHARGE_MAX_CURRENT, 0)// - .output(ESS_CHARGE_MAX_CURRENT, 5)// - )// - .next(new TestCase()// - .input(BATTERY_VOLTAGE, 796)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// - .input(BATTERY_CHARGE_MAX_CURRENT, 0)// - .output(ESS_CHARGE_MAX_CURRENT, 3)// - )// - .next(new TestCase()// - .input(BATTERY_VOLTAGE, 798)// - .input(BATTERY_SOC, 100)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// - .input(BATTERY_CHARGE_MAX_CURRENT, 0)// - .output(ESS_CHARGE_MAX_CURRENT, 1)// - )// - .next(new TestCase()// - .input(BATTERY_VOLTAGE, 798)// - .input(BATTERY_SOC, 100)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// - .input(BATTERY_CHARGE_MAX_CURRENT, 0)// - .output(ESS_CHARGE_MAX_CURRENT, 0)// - )// - .next(new TestCase()// - .input(BATTERY_VOLTAGE, 798)// - .input(BATTERY_SOC, 100)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// - .input(BATTERY_CHARGE_MAX_CURRENT, 0)// - .output(ESS_CHARGE_MAX_CURRENT, -2)// - )// - .next(new TestCase()// - .input(BATTERY_VOLTAGE, 796)// - .input(BATTERY_SOC, 100)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// - .input(BATTERY_CHARGE_MAX_CURRENT, 0)// - .output(ESS_CHARGE_MAX_CURRENT, -1)// - )// - .next(new TestCase()// - .input(BATTERY_VOLTAGE, 796)// - .input(BATTERY_SOC, 100)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// - .input(BATTERY_CHARGE_MAX_CURRENT, 0)// - .output(ESS_CHARGE_MAX_CURRENT, -1)// - )// - .next(new TestCase()// - .input(BATTERY_VOLTAGE, 796)// - .input(BATTERY_SOC, 100)// - .input(BATTERY_CHARGE_MAX_VOLTAGE, 800)// - .input(BATTERY_DISCHARGE_MIN_VOLTAGE, 594)// - .input(BATTERY_DISCHARGE_MAX_CURRENT, 169)// - .input(BATTERY_CHARGE_MAX_CURRENT, 0)// - .output(ESS_CHARGE_MAX_CURRENT, 0)// + .input("battery0", VOLTAGE, 796)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", DISCHARGE_MAX_CURRENT, 169)// + .input("battery0", CHARGE_MAX_CURRENT, 0)// + .output(EP_CHARGE_MAX_CURRENT, 57)// + )// + .next(new TestCase()// + .input("battery0", VOLTAGE, 796)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", DISCHARGE_MAX_CURRENT, 169)// + .input("battery0", CHARGE_MAX_CURRENT, 0)// + .output(EP_CHARGE_MAX_CURRENT, 38)// + )// + .next(new TestCase()// + .input("battery0", VOLTAGE, 796)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", DISCHARGE_MAX_CURRENT, 169)// + .input("battery0", CHARGE_MAX_CURRENT, 0)// + .output(EP_CHARGE_MAX_CURRENT, 26)// + )// + .next(new TestCase()// + .input("battery0", VOLTAGE, 796)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", DISCHARGE_MAX_CURRENT, 169)// + .input("battery0", CHARGE_MAX_CURRENT, 0)// + .output(EP_CHARGE_MAX_CURRENT, 18)// + )// + .next(new TestCase()// + .input("battery0", VOLTAGE, 796)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", DISCHARGE_MAX_CURRENT, 169)// + .input("battery0", CHARGE_MAX_CURRENT, 0)// + .output(EP_CHARGE_MAX_CURRENT, 12)// + )// + .next(new TestCase()// + .input("battery0", VOLTAGE, 796)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", DISCHARGE_MAX_CURRENT, 169)// + .input("battery0", CHARGE_MAX_CURRENT, 0)// + .output(EP_CHARGE_MAX_CURRENT, 8)// + )// + .next(new TestCase()// + .input("battery0", VOLTAGE, 796)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", DISCHARGE_MAX_CURRENT, 169)// + .input("battery0", CHARGE_MAX_CURRENT, 0)// + .output(EP_CHARGE_MAX_CURRENT, 5)// + )// + .next(new TestCase()// + .input("battery0", VOLTAGE, 796)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", DISCHARGE_MAX_CURRENT, 169)// + .input("battery0", CHARGE_MAX_CURRENT, 0)// + .output(EP_CHARGE_MAX_CURRENT, 3)// + )// + .next(new TestCase()// + .input("battery0", VOLTAGE, 798)// + .input("battery0", SOC, 100)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", DISCHARGE_MAX_CURRENT, 169)// + .input("battery0", CHARGE_MAX_CURRENT, 0)// + .output(EP_CHARGE_MAX_CURRENT, 1)// + )// + .next(new TestCase()// + .input("battery0", VOLTAGE, 798)// + .input("battery0", SOC, 100)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", DISCHARGE_MAX_CURRENT, 169)// + .input("battery0", CHARGE_MAX_CURRENT, 0)// + .output(EP_CHARGE_MAX_CURRENT, 0)// + )// + .next(new TestCase()// + .input("battery0", VOLTAGE, 798)// + .input("battery0", SOC, 100)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", DISCHARGE_MAX_CURRENT, 169)// + .input("battery0", CHARGE_MAX_CURRENT, 0)// + .output(EP_CHARGE_MAX_CURRENT, -2)// + )// + .next(new TestCase()// + .input("battery0", VOLTAGE, 796)// + .input("battery0", SOC, 100)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", DISCHARGE_MAX_CURRENT, 169)// + .input("battery0", CHARGE_MAX_CURRENT, 0)// + .output(EP_CHARGE_MAX_CURRENT, -1)// + )// + .next(new TestCase()// + .input("battery0", VOLTAGE, 796)// + .input("battery0", SOC, 100)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", DISCHARGE_MAX_CURRENT, 169)// + .input("battery0", CHARGE_MAX_CURRENT, 0)// + .output(EP_CHARGE_MAX_CURRENT, -1)// + )// + .next(new TestCase()// + .input("battery0", VOLTAGE, 796)// + .input("battery0", SOC, 100)// + .input("battery0", CHARGE_MAX_VOLTAGE, 800)// + .input("battery0", DISCHARGE_MIN_VOLTAGE, 594)// + .input("battery0", DISCHARGE_MAX_CURRENT, 169)// + .input("battery0", CHARGE_MAX_CURRENT, 0)// + .output(EP_CHARGE_MAX_CURRENT, 0)// )// ;// assertEquals("Started|SoC:100 %|L:796 W|Allowed:796;92000", ess.debugLog()); diff --git a/io.openems.edge.ess.sma/test/io/openems/edge/sma/sunnyisland/EssSmaSunnyIslandImplTest.java b/io.openems.edge.ess.sma/test/io/openems/edge/sma/sunnyisland/EssSmaSunnyIslandImplTest.java index fcee18e6c8e..b420b8a95c5 100644 --- a/io.openems.edge.ess.sma/test/io/openems/edge/sma/sunnyisland/EssSmaSunnyIslandImplTest.java +++ b/io.openems.edge.ess.sma/test/io/openems/edge/sma/sunnyisland/EssSmaSunnyIslandImplTest.java @@ -9,17 +9,14 @@ public class EssSmaSunnyIslandImplTest { - private static final String ESS_ID = "ess0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ManagedSymmetricEssTest(new EssSmaSunnyIslandImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(ESS_ID) // - .setModbusId(MODBUS_ID) // + .setId("ess0") // + .setModbusId("modbus0") // .setPhase(Phase.L1) // .build()) // ; diff --git a/io.openems.edge.evcs.alpitronic.hypercharger/bnd.bnd b/io.openems.edge.evcs.alpitronic.hypercharger/bnd.bnd index 865db1aa41d..d1cfcf3a7ad 100644 --- a/io.openems.edge.evcs.alpitronic.hypercharger/bnd.bnd +++ b/io.openems.edge.evcs.alpitronic.hypercharger/bnd.bnd @@ -10,6 +10,7 @@ Bundle-Version: 1.0.0.${tstamp} io.openems.edge.bridge.modbus,\ io.openems.edge.common,\ io.openems.edge.evcs.api,\ + io.openems.edge.meter.api,\ io.openems.edge.timedata.api,\ -testpath: \ diff --git a/io.openems.edge.evcs.alpitronic.hypercharger/src/io/openems/edge/evcs/hypercharger/EvcsAlpitronicHyperchargerImpl.java b/io.openems.edge.evcs.alpitronic.hypercharger/src/io/openems/edge/evcs/hypercharger/EvcsAlpitronicHyperchargerImpl.java index 0dec8b68dad..89347a8e335 100644 --- a/io.openems.edge.evcs.alpitronic.hypercharger/src/io/openems/edge/evcs/hypercharger/EvcsAlpitronicHyperchargerImpl.java +++ b/io.openems.edge.evcs.alpitronic.hypercharger/src/io/openems/edge/evcs/hypercharger/EvcsAlpitronicHyperchargerImpl.java @@ -42,11 +42,13 @@ import io.openems.edge.common.taskmanager.Priority; import io.openems.edge.common.type.TypeUtils; import io.openems.edge.evcs.api.ChargeStateHandler; +import io.openems.edge.evcs.api.DeprecatedEvcs; import io.openems.edge.evcs.api.Evcs; import io.openems.edge.evcs.api.EvcsPower; import io.openems.edge.evcs.api.ManagedEvcs; import io.openems.edge.evcs.api.Status; import io.openems.edge.evcs.api.WriteHandler; +import io.openems.edge.meter.api.ElectricityMeter; import io.openems.edge.timedata.api.Timedata; import io.openems.edge.timedata.api.TimedataProvider; import io.openems.edge.timedata.api.utils.CalculateEnergyFromPower; @@ -61,8 +63,9 @@ EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE, // EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE // }) -public class EvcsAlpitronicHyperchargerImpl extends AbstractOpenemsModbusComponent implements Evcs, ManagedEvcs, - OpenemsComponent, ModbusComponent, EventHandler, EvcsAlpitronicHypercharger, TimedataProvider { +public class EvcsAlpitronicHyperchargerImpl extends AbstractOpenemsModbusComponent + implements Evcs, ManagedEvcs, DeprecatedEvcs, ElectricityMeter, OpenemsComponent, ModbusComponent, EventHandler, + EvcsAlpitronicHypercharger, TimedataProvider { private final Logger log = LoggerFactory.getLogger(EvcsAlpitronicHyperchargerImpl.class); /** Modbus offset for multiple connectors. */ @@ -91,7 +94,8 @@ protected void setModbus(BridgeModbus modbus) { *

      * Accumulates the energy by calling this.calculateTotalEnergy.update(power); */ - private CalculateEnergyFromPower calculateTotalEnergy; + private final CalculateEnergyFromPower calculateTotalEnergy = new CalculateEnergyFromPower(this, + ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY); /** Handles charge states. */ private final ChargeStateHandler chargeStateHandler = new ChargeStateHandler(this); @@ -103,9 +107,16 @@ public EvcsAlpitronicHyperchargerImpl() { super(// OpenemsComponent.ChannelId.values(), // ModbusComponent.ChannelId.values(), // + ElectricityMeter.ChannelId.values(), // Evcs.ChannelId.values(), // ManagedEvcs.ChannelId.values(), // + DeprecatedEvcs.ChannelId.values(), // EvcsAlpitronicHypercharger.ChannelId.values()); + DeprecatedEvcs.copyToDeprecatedEvcsChannels(this); + + // Automatically calculate L1/l2/L3 values from sum + ElectricityMeter.calculatePhasesFromActivePower(this); + // TODO consider CURRENT and VOLTAGE also } @Activate @@ -136,7 +147,6 @@ private void modified(ComponentContext context, Config config) throws OpenemsNam private void applyConfig(ComponentContext context, Config config) { this.config = config; - this.calculateTotalEnergy = new CalculateEnergyFromPower(this, Evcs.ChannelId.ACTIVE_CONSUMPTION_ENERGY); this._setFixedMinimumHardwarePower(config.minHwPower()); this._setFixedMaximumHardwarePower(config.maxHwPower()); this._setPowerPrecision(1); @@ -160,12 +170,10 @@ public void handleEvent(Event event) { return; } switch (event.getTopic()) { - case EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE: - this.calculateTotalEnergy.update(this.getChargePower().get()); - break; - case EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE: - this.writeHandler.run(); - break; + case EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE // + -> this.calculateTotalEnergy.update(this.getActivePower().get()); + case EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE // + -> this.writeHandler.run(); } } @@ -186,8 +194,10 @@ protected ModbusProtocol defineModbusProtocol() { new FC4ReadInputRegistersTask(this.offset.apply(0), Priority.LOW, m(EvcsAlpitronicHypercharger.ChannelId.RAW_STATUS, new UnsignedWordElement(this.offset.apply(0))), + // TODO consider ElectricityMeter VOLTAGE m(EvcsAlpitronicHypercharger.ChannelId.CHARGING_VOLTAGE, new UnsignedDoublewordElement(this.offset.apply(1)), SCALE_FACTOR_MINUS_2), + // TODO consider ElectricityMeter CURRENT m(EvcsAlpitronicHypercharger.ChannelId.CHARGING_CURRENT, new UnsignedWordElement(this.offset.apply(3)), SCALE_FACTOR_MINUS_2), /* @@ -268,7 +278,7 @@ private void addCalculatePowerListeners() { // Calculate power from voltage and current final Consumer> calculatePower = ignore -> { - this._setChargePower(TypeUtils.getAsType(OpenemsType.INTEGER, TypeUtils.multiply(// + this._setActivePower(TypeUtils.getAsType(OpenemsType.INTEGER, TypeUtils.multiply(// this.getChargingVoltageChannel().getNextValue().get(), // this.getChargingCurrentChannel().getNextValue().get() // ))); @@ -283,35 +293,22 @@ private void addStatusListener() { /** * Maps the raw state into a {@link Status}. */ - switch (rawState) { - case AVAILABLE: - this._setStatus(Status.NOT_READY_FOR_CHARGING); - break; - case PREPARING_TAG_ID_READY: - this._setStatus(Status.READY_FOR_CHARGING); - break; - case CHARGING: - case PREPARING_EV_READY: - this._setStatus(Status.CHARGING); - break; - case RESERVED: - case SUSPENDED_EV: - case SUSPENDED_EV_SE: - this._setStatus(Status.CHARGING_REJECTED); - break; - case FINISHING: - this._setStatus(Status.CHARGING_FINISHED); - break; - case FAULTED: - case UNAVAILABLE: - case UNAVAILABLE_CONNECTION_OBJECT: - this._setStatus(Status.ERROR); - break; - case UNAVAILABLE_FW_UPDATE: - case UNDEFINED: - default: - this._setStatus(Status.UNDEFINED); - } + this._setStatus(switch (rawState) { + case AVAILABLE // + -> Status.NOT_READY_FOR_CHARGING; + case PREPARING_TAG_ID_READY // + -> Status.READY_FOR_CHARGING; + case CHARGING, PREPARING_EV_READY // + -> Status.CHARGING; + case RESERVED, SUSPENDED_EV, SUSPENDED_EV_SE // + -> Status.CHARGING_REJECTED; + case FINISHING // + -> Status.CHARGING_FINISHED; + case FAULTED, UNAVAILABLE, UNAVAILABLE_CONNECTION_OBJECT // + -> Status.ERROR; + case UNAVAILABLE_FW_UPDATE, UNDEFINED // + -> Status.UNDEFINED; + }); }); } diff --git a/io.openems.edge.evcs.alpitronic.hypercharger/test/io/openems/edge/evcs/hypercharger/EvcsAlpitronicHyperchargerImplTest.java b/io.openems.edge.evcs.alpitronic.hypercharger/test/io/openems/edge/evcs/hypercharger/EvcsAlpitronicHyperchargerImplTest.java index a2fb6ebfdc2..9e83d535c84 100644 --- a/io.openems.edge.evcs.alpitronic.hypercharger/test/io/openems/edge/evcs/hypercharger/EvcsAlpitronicHyperchargerImplTest.java +++ b/io.openems.edge.evcs.alpitronic.hypercharger/test/io/openems/edge/evcs/hypercharger/EvcsAlpitronicHyperchargerImplTest.java @@ -9,17 +9,14 @@ public class EvcsAlpitronicHyperchargerImplTest { - private static final String EVCS_ID = "evcs0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new EvcsAlpitronicHyperchargerImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setModbusId(MODBUS_ID) // - .setId(EVCS_ID) // + .setModbusId("modbus0") // + .setId("evcs0") // .setModbusUnitId(1) // .setConnector(Connector.SLOT_0) // .setMaxHwPower(70_000) // diff --git a/io.openems.edge.evcs.api/bnd.bnd b/io.openems.edge.evcs.api/bnd.bnd index bd42bcb6773..eb22c030664 100644 --- a/io.openems.edge.evcs.api/bnd.bnd +++ b/io.openems.edge.evcs.api/bnd.bnd @@ -7,7 +7,7 @@ Bundle-Version: 1.0.0.${tstamp} ${buildpath},\ io.openems.common,\ io.openems.edge.common,\ - io.openems.edge.meter.api + io.openems.edge.meter.api,\ -testpath: \ ${testpath} diff --git a/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/AbstractManagedEvcsComponent.java b/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/AbstractManagedEvcsComponent.java index 56afd9dae55..ab88e63294c 100644 --- a/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/AbstractManagedEvcsComponent.java +++ b/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/AbstractManagedEvcsComponent.java @@ -1,6 +1,7 @@ package io.openems.edge.evcs.api; import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Deactivate; import org.osgi.service.event.Event; import org.osgi.service.event.EventHandler; import org.slf4j.Logger; @@ -8,6 +9,7 @@ import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.event.EdgeEventConstants; +import io.openems.edge.meter.api.ElectricityMeter; /** * Abstract Managed EVCS Component. @@ -38,16 +40,17 @@ * */ public abstract class AbstractManagedEvcsComponent extends AbstractOpenemsComponent - implements Evcs, ManagedEvcs, EventHandler { + implements Evcs, ManagedEvcs, ElectricityMeter, EventHandler { private final Logger log = LoggerFactory.getLogger(AbstractManagedEvcsComponent.class); - private final WriteHandler writeHandler = new WriteHandler(this); + protected final WriteHandler writeHandler; private final ChargeStateHandler chargeStateHandler = new ChargeStateHandler(this); protected AbstractManagedEvcsComponent(io.openems.edge.common.channel.ChannelId[] firstInitialChannelIds, io.openems.edge.common.channel.ChannelId[]... furtherInitialChannelIds) { super(firstInitialChannelIds, furtherInitialChannelIds); + this.writeHandler = this.createWriteHandler(); } @Override @@ -57,6 +60,13 @@ protected void activate(ComponentContext context, String id, String alias, boole Evcs.addCalculatePowerLimitListeners(this); } + @Override + @Deactivate + protected void deactivate() { + super.deactivate(); + this.writeHandler.cancelChargePower(); + } + @Override public void handleEvent(Event event) { if (!this.isEnabled()) { @@ -84,6 +94,10 @@ protected void logWarn(Logger log, String message) { super.logWarn(log, message); } + protected WriteHandler createWriteHandler() { + return new WriteHandler(this); + } + @Override protected void logDebug(Logger log, String message) { if (this.getConfiguredDebugMode()) { diff --git a/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/DeprecatedEvcs.java b/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/DeprecatedEvcs.java new file mode 100644 index 00000000000..e5e98c02c74 --- /dev/null +++ b/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/DeprecatedEvcs.java @@ -0,0 +1,58 @@ +package io.openems.edge.evcs.api; + +import static io.openems.common.channel.PersistencePriority.HIGH; +import static io.openems.common.channel.Unit.WATT; +import static io.openems.common.types.OpenemsType.INTEGER; + +import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.channel.IntegerReadChannel; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.meter.api.ElectricityMeter; + +/** + * This interface marks old implementations of {@link Evcs} that did not yet + * inherit {@link ElectricityMeter}. + * + *

      + * It should not be used for new implementations, but serves as a migration path + * for old implementations. + */ +public interface DeprecatedEvcs extends ElectricityMeter, OpenemsComponent { + + /** + * Copies values to Deprecated Channels during migration to + * {@link ElectricityMeter}. + * + *

        + *
      • ACTIVE_POWER -> CHARGE_POWER + *
      • ACTIVE_PRODUCTION_ENERGY -> ACTIVE_CONSUMPTION_ENERGY + *
      + * + * @param meter instance of myself + */ + public static void copyToDeprecatedEvcsChannels(DeprecatedEvcs meter) { + var chargePowerChannel = meter.channel(DeprecatedEvcs.ChannelId.CHARGE_POWER); + meter.getActivePowerChannel().onSetNextValue(v -> chargePowerChannel.setNextValue(v.get())); + meter.getActiveProductionEnergyChannel().onSetNextValue(v -> meter._setActiveConsumptionEnergy(v.get())); + } + + public enum ChannelId implements io.openems.edge.common.channel.ChannelId { + /** + * Copy of {@link ElectricityMeter.ChannelId#ACTIVE_POWER}. + */ + CHARGE_POWER(Doc.of(INTEGER) // + .unit(WATT) // + .persistencePriority(HIGH)); + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } +} diff --git a/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/Evcs.java b/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/Evcs.java index a1405624b2f..b8863a5c15b 100644 --- a/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/Evcs.java +++ b/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/Evcs.java @@ -11,14 +11,15 @@ import io.openems.edge.common.channel.Doc; import io.openems.edge.common.channel.EnumReadChannel; import io.openems.edge.common.channel.IntegerReadChannel; -import io.openems.edge.common.channel.LongReadChannel; import io.openems.edge.common.channel.StateChannel; import io.openems.edge.common.channel.value.Value; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.modbusslave.ModbusSlaveNatureTable; import io.openems.edge.common.modbusslave.ModbusType; +import io.openems.edge.meter.api.ElectricityMeter; +import io.openems.edge.meter.api.MeterType; -public interface Evcs extends OpenemsComponent { +public interface Evcs extends ElectricityMeter, OpenemsComponent { public static final Integer DEFAULT_MAXIMUM_HARDWARE_POWER = 22_080; // W public static final Integer DEFAULT_MINIMUM_HARDWARE_POWER = 4_140; // W @@ -42,21 +43,6 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { * */ STATUS(Doc.of(Status.values()) // - .accessMode(AccessMode.READ_ONLY) // - .persistencePriority(PersistencePriority.HIGH)), // - - /** - * Charge Power. - * - *
        - *
      • Interface: Evcs - *
      • Readable - *
      • Type: Integer - *
      • Unit: W - *
      - */ - CHARGE_POWER(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY) // .persistencePriority(PersistencePriority.HIGH)), // /** @@ -72,7 +58,6 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { * */ CHARGING_TYPE(Doc.of(ChargingType.values()) // - .accessMode(AccessMode.READ_ONLY) // .persistencePriority(PersistencePriority.HIGH)), // /** @@ -91,7 +76,6 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ PHASES(Doc.of(Phases.values()) // .debounce(5) // - .accessMode(AccessMode.READ_ONLY) // .persistencePriority(PersistencePriority.HIGH)), // /** @@ -116,7 +100,6 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ FIXED_MINIMUM_HARDWARE_POWER(Doc.of(OpenemsType.INTEGER) // .unit(Unit.WATT) // - .accessMode(AccessMode.READ_ONLY) // .persistencePriority(PersistencePriority.HIGH)), // /** @@ -140,7 +123,6 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ FIXED_MAXIMUM_HARDWARE_POWER(Doc.of(OpenemsType.INTEGER) // .unit(Unit.WATT) // - .accessMode(AccessMode.READ_ONLY) // .persistencePriority(PersistencePriority.HIGH)), // /** @@ -164,7 +146,6 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ MINIMUM_HARDWARE_POWER(Doc.of(OpenemsType.INTEGER) // .unit(Unit.WATT) // - .accessMode(AccessMode.READ_ONLY) // .persistencePriority(PersistencePriority.HIGH)), // /** @@ -188,7 +169,6 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ MAXIMUM_HARDWARE_POWER(Doc.of(OpenemsType.INTEGER) // .unit(Unit.WATT) // - .accessMode(AccessMode.READ_ONLY) // .persistencePriority(PersistencePriority.HIGH)), // /** @@ -203,7 +183,6 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ MAXIMUM_POWER(Doc.of(OpenemsType.INTEGER) // .unit(Unit.WATT) // - .accessMode(AccessMode.READ_ONLY) // .persistencePriority(PersistencePriority.HIGH)), // /** @@ -218,7 +197,6 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ MINIMUM_POWER(Doc.of(OpenemsType.INTEGER) // .unit(Unit.WATT) // - .accessMode(AccessMode.READ_ONLY) // .persistencePriority(PersistencePriority.HIGH)), // /** @@ -233,21 +211,6 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ ENERGY_SESSION(Doc.of(OpenemsType.INTEGER) // .unit(Unit.WATT_HOURS) // - .accessMode(AccessMode.READ_ONLY) // - .persistencePriority(PersistencePriority.HIGH)), // - - /** - * Active Consumption Energy. - * - *
        - *
      • Interface: Evcs - *
      • Type: Integer - *
      • Unit: Wh - *
      - */ - ACTIVE_CONSUMPTION_ENERGY(Doc.of(OpenemsType.LONG) // - .unit(Unit.CUMULATED_WATT_HOURS) // - .accessMode(AccessMode.READ_ONLY) // .persistencePriority(PersistencePriority.HIGH)), // /** @@ -260,7 +223,6 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { * */ CHARGINGSTATION_COMMUNICATION_FAILED(Doc.of(Level.FAULT) // - .accessMode(AccessMode.READ_ONLY) // .persistencePriority(PersistencePriority.HIGH) // .text("Chargingstation Communication Failed " // + "| Keine Verbindung zur Ladestation " // @@ -278,6 +240,11 @@ public Doc doc() { } } + @Override + public default MeterType getMeterType() { + return MeterType.CONSUMPTION_METERED; + } + /** * Gets the Channel for {@link ChannelId#STATUS}. * @@ -305,44 +272,6 @@ public default void _setStatus(Status value) { this.getStatusChannel().setNextValue(value); } - /** - * Gets the Channel for {@link ChannelId#CHARGE_POWER}. - * - * @return the Channel - */ - public default IntegerReadChannel getChargePowerChannel() { - return this.channel(ChannelId.CHARGE_POWER); - } - - /** - * Gets the Charge Power in [W]. See {@link ChannelId#CHARGE_POWER}. - * - * @return the Channel {@link Value} - */ - public default Value getChargePower() { - return this.getChargePowerChannel().value(); - } - - /** - * Internal method to set the 'nextValue' on {@link ChannelId#CHARGE_POWER} - * Channel. - * - * @param value the next value - */ - public default void _setChargePower(Integer value) { - this.getChargePowerChannel().setNextValue(value); - } - - /** - * Internal method to set the 'nextValue' on {@link ChannelId#CHARGE_POWER} - * Channel. - * - * @param value the next value - */ - public default void _setChargePower(int value) { - this.getChargePowerChannel().setNextValue(value); - } - /** * Gets the Channel for {@link ChannelId#CHARGING_TYPE}. * @@ -666,45 +595,6 @@ public default void _setEnergySession(int value) { this.getEnergySessionChannel().setNextValue(value); } - /** - * Gets the Channel for {@link ChannelId#ACTIVE_CONSUMPTION_ENERGY}. - * - * @return the Channel - */ - public default LongReadChannel getActiveConsumptionEnergyChannel() { - return this.channel(ChannelId.ACTIVE_CONSUMPTION_ENERGY); - } - - /** - * Gets the Active Consumption Energy in [Wh_Σ]. This relates to negative - * ACTIVE_POWER. See {@link ChannelId#ACTIVE_CONSUMPTION_ENERGY}. - * - * @return the Channel {@link Value} - */ - public default Value getActiveConsumptionEnergy() { - return this.getActiveConsumptionEnergyChannel().value(); - } - - /** - * Internal method to set the 'nextValue' on - * {@link ChannelId#ACTIVE_CONSUMPTION_ENERGY} Channel. - * - * @param value the next value - */ - public default void _setActiveConsumptionEnergy(Long value) { - this.getActiveConsumptionEnergyChannel().setNextValue(value); - } - - /** - * Internal method to set the 'nextValue' on - * {@link ChannelId#ACTIVE_CONSUMPTION_ENERGY} Channel. - * - * @param value the next value - */ - public default void _setActiveConsumptionEnergy(long value) { - this.getActiveConsumptionEnergyChannel().setNextValue(value); - } - /** * Gets the Channel for {@link ChannelId#CHARGINGSTATION_COMMUNICATION_FAILED}. * @@ -765,6 +655,37 @@ public static void addCalculatePowerLimitListeners(Evcs evcs) { evcs.getPhasesChannel().onSetNextValue(calculateHardwarePowerLimits); } + /** + * Evaluates the number of Phases from the individual powers per phase. + * + *

      + * The EVCS will pull power from the grid for its own consumption and report + * that on one of the phases. This value is different from EVCS to EVCS but can + * be high. Because of this, this will only register a phase starting with 100W + * because then we definitively know that this load is caused by a car. + * + * @param activePowerL1 active power on L1 + * @param activePowerL2 active power on L2 + * @param activePowerL3 active power on L3 + * @return integer value indicating the number of phases; null if undefined + */ + public static Integer evaluatePhaseCount(Integer activePowerL1, Integer activePowerL2, Integer activePowerL3) { + int phases = 0; + if (activePowerL1 != null && activePowerL1 > 100) { + phases++; + } + if (activePowerL2 != null && activePowerL2 > 100) { + phases++; + } + if (activePowerL3 != null && activePowerL3 > 100) { + phases++; + } + return switch (phases) { + case 1, 2, 3 -> phases; + default -> null; + }; + } + /** * Used for Modbus/TCP Api Controller. Provides a Modbus table for the Channels * of this Component. @@ -775,7 +696,7 @@ public static void addCalculatePowerLimitListeners(Evcs evcs) { public static ModbusSlaveNatureTable getModbusSlaveNatureTable(AccessMode accessMode) { return ModbusSlaveNatureTable.of(Evcs.class, accessMode, 100) // .channel(0, ChannelId.STATUS, ModbusType.UINT16) // - .channel(1, ChannelId.CHARGE_POWER, ModbusType.UINT16) // + .uint16Reserved(1) // .channel(2, ChannelId.CHARGING_TYPE, ModbusType.UINT16) // .channel(3, ChannelId.PHASES, ModbusType.UINT16) // .channel(4, ChannelId.MAXIMUM_HARDWARE_POWER, ModbusType.UINT16) // @@ -786,7 +707,6 @@ public static ModbusSlaveNatureTable getModbusSlaveNatureTable(AccessMode access .channel(9, ChannelId.FIXED_MINIMUM_HARDWARE_POWER, ModbusType.UINT16) // .channel(10, ChannelId.FIXED_MAXIMUM_HARDWARE_POWER, ModbusType.UINT16) // .channel(11, ChannelId.MINIMUM_POWER, ModbusType.UINT16) // - .channel(12, ChannelId.ACTIVE_CONSUMPTION_ENERGY, ModbusType.UINT16) // .build(); } } diff --git a/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/MeasuringEvcs.java b/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/MeasuringEvcs.java index 18f7154f46a..50e680aeb0e 100644 --- a/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/MeasuringEvcs.java +++ b/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/MeasuringEvcs.java @@ -6,6 +6,7 @@ import io.openems.common.types.OpenemsType; import io.openems.edge.common.channel.Doc; +// TODO consider replacing this by ElectricityMeter public interface MeasuringEvcs extends Evcs { public enum ChannelId implements io.openems.edge.common.channel.ChannelId { @@ -240,27 +241,6 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { .persistencePriority(PersistencePriority.HIGH) // .text("Energy.Reactive.Import.Interval")), - /** - * Frequency. - * - *

      - * Instantaneous reading of powerline frequency. NOTE: OCPP 1.6 does not have a - * UnitOfMeasure for frequency, the UnitOfMeasure for any SampledValue with - * measurand: Frequency is Hertz. - * - *

        - *
      • Interface: MeasuringEvcs - *
      • Readable - *
      • Type: String - *
      • Unit: Hz - *
      - */ - FREQUENCY(Doc.of(OpenemsType.STRING) // - .unit(Unit.HERTZ) // - .accessMode(AccessMode.READ_ONLY) // - .persistencePriority(PersistencePriority.HIGH) // - .text("Frequency")), - /** * Active power to grid (export) * @@ -371,23 +351,6 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { .persistencePriority(PersistencePriority.HIGH) // .text("Fan speed")), - /** - * Voltage. - * - *

      - * Instantaneous AC RMS supply voltage. - * - *

        - *
      • Interface: MeasuringEvcs - *
      • Readable - *
      • Type: String - *
      - */ - VOLTAGE(Doc.of(OpenemsType.STRING) // - .accessMode(AccessMode.READ_ONLY) // - .persistencePriority(PersistencePriority.HIGH) // - .text("Voltage")), - /** * Temperature. * diff --git a/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/PhaseRotation.java b/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/PhaseRotation.java new file mode 100644 index 00000000000..e89c312e781 --- /dev/null +++ b/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/PhaseRotation.java @@ -0,0 +1,77 @@ +package io.openems.edge.evcs.api; + +public enum PhaseRotation { + /** + * EVCS uses standard wiring. + * + *
        + *
      • EVCS L1 is connected to Grid L1 + *
      • EVCS L2 is connected to Grid L2 + *
      • EVCS L3 is connected to Grid L3 + *
      + */ + L1_L2_L3, + + /** + * EVCS uses rotated wiring. + * + *
        + *
      • EVCS L1 is connected to Grid L2 + *
      • EVCS L2 is connected to Grid L3 + *
      • EVCS L3 is connected to Grid L1 + *
      + */ + L2_L3_L1, + + /** + * EVCS uses rotated wiring. + * + *
        + *
      • EVCS L1 is connected to Grid L3 + *
      • EVCS L2 is connected to Grid L1 + *
      • EVCS L3 is connected to Grid L2 + *
      + */ + L3_L1_L2; + + public record RotatedPhases(// + Integer voltageL1, int currentL1, Integer activePowerL1, // + Integer voltageL2, int currentL2, Integer activePowerL2, // + Integer voltageL3, int currentL3, Integer activePowerL3) { + + /** + * Rotate phases for voltage, current and active power. + * + * @param phaseRotation the {@link PhaseRotation} + * @param voltageL1 the voltage on L1 + * @param currentL1 the current on L1 + * @param activePowerL1 the active power on L1 + * @param voltageL2 the voltage on L2 + * @param currentL2 the current on L2 + * @param activePowerL2 the active power on L2 + * @param voltageL3 the voltage on L3 + * @param currentL3 the current on L3 + * @param activePowerL3 the active power on L3 + * @return {@link RotatedPhases} + */ + public static RotatedPhases from(PhaseRotation phaseRotation, // + Integer voltageL1, int currentL1, Integer activePowerL1, // + Integer voltageL2, int currentL2, Integer activePowerL2, // + Integer voltageL3, int currentL3, Integer activePowerL3) { + return switch (phaseRotation) { + case L1_L2_L3 -> new RotatedPhases(// + voltageL1, currentL1, activePowerL1, // + voltageL2, currentL2, activePowerL2, // + voltageL3, currentL3, activePowerL3); + case L2_L3_L1 -> new RotatedPhases(// + voltageL3, currentL3, activePowerL3, // + voltageL1, currentL1, activePowerL1, // + voltageL2, currentL2, activePowerL2); + case L3_L1_L2 -> new RotatedPhases(// + voltageL2, currentL2, activePowerL2, // + voltageL3, currentL3, activePowerL3, // + voltageL1, currentL1, activePowerL1); + }; + } + } +} diff --git a/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/WriteHandler.java b/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/WriteHandler.java index 64fcb073b24..a9562639153 100644 --- a/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/WriteHandler.java +++ b/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/WriteHandler.java @@ -75,7 +75,7 @@ private void setPower() { this.parent._setStatus(Status.ENERGY_LIMIT_REACHED); // Apply Charge Power - if (this.lastTarget != 0 || this.parent.getChargePower().orElse(0) != 0) { + if (this.lastTarget != 0 || this.parent.getActivePower().orElse(0) != 0) { this.parent.getChargeStateHandler().applyNewChargeState(ChargeState.DECREASING); this.applyChargePower(0); } @@ -128,7 +128,7 @@ private void setPower() { * * @param power Power that should be applied */ - private void applyChargePower(int power) { + protected void applyChargePower(int power) { try { boolean sent = false; @@ -249,4 +249,11 @@ private void logDebug(String message) { OpenemsComponent.logInfo(this.parent, this.log, message); } } + + /** + * Used for async applyChargePower calls. + * + */ + public void cancelChargePower() { + } } diff --git a/io.openems.edge.evcs.api/src/io/openems/edge/evcs/test/DummyManagedEvcs.java b/io.openems.edge.evcs.api/src/io/openems/edge/evcs/test/DummyManagedEvcs.java index fd28514e222..f64c89c394e 100644 --- a/io.openems.edge.evcs.api/src/io/openems/edge/evcs/test/DummyManagedEvcs.java +++ b/io.openems.edge.evcs.api/src/io/openems/edge/evcs/test/DummyManagedEvcs.java @@ -12,9 +12,10 @@ import io.openems.edge.evcs.api.EvcsPower; import io.openems.edge.evcs.api.ManagedEvcs; import io.openems.edge.evcs.api.Status; +import io.openems.edge.meter.api.ElectricityMeter; public class DummyManagedEvcs extends AbstractManagedEvcsComponent - implements Evcs, ManagedEvcs, OpenemsComponent, EventHandler { + implements Evcs, ManagedEvcs, ElectricityMeter, OpenemsComponent, EventHandler { private final EvcsPower evcsPower; private int minimumHardwarePower = Evcs.DEFAULT_MINIMUM_HARDWARE_POWER; @@ -23,6 +24,7 @@ public class DummyManagedEvcs extends AbstractManagedEvcsComponent public DummyManagedEvcs(String id, EvcsPower evcsPower) { super(// OpenemsComponent.ChannelId.values(), // + ElectricityMeter.ChannelId.values(), // ManagedEvcs.ChannelId.values(), // Evcs.ChannelId.values() // ); @@ -85,14 +87,14 @@ public boolean getConfiguredDebugMode() { @Override public boolean applyChargePowerLimit(int power) throws OpenemsException { - this._setChargePower(power); + this._setActivePower(power); this._setStatus(Status.CHARGING); return true; } @Override public boolean pauseChargeProcess() throws OpenemsException { - this._setChargePower(0); + this._setActivePower(0); return true; } diff --git a/io.openems.edge.evcs.api/test/io/openems/edge/evcs/api/AbstractManagedEvcsTest.java b/io.openems.edge.evcs.api/test/io/openems/edge/evcs/api/AbstractManagedEvcsTest.java index 908cdeb7bfd..a7c39ac36a0 100644 --- a/io.openems.edge.evcs.api/test/io/openems/edge/evcs/api/AbstractManagedEvcsTest.java +++ b/io.openems.edge.evcs.api/test/io/openems/edge/evcs/api/AbstractManagedEvcsTest.java @@ -1,11 +1,17 @@ package io.openems.edge.evcs.api; +import static io.openems.edge.evcs.api.Evcs.ChannelId.ENERGY_SESSION; +import static io.openems.edge.evcs.api.Evcs.ChannelId.STATUS; +import static io.openems.edge.evcs.api.ManagedEvcs.ChannelId.CHARGE_STATE; +import static io.openems.edge.evcs.api.ManagedEvcs.ChannelId.SET_CHARGE_POWER_LIMIT; +import static io.openems.edge.evcs.api.ManagedEvcs.ChannelId.SET_CHARGE_POWER_LIMIT_WITH_FILTER; +import static io.openems.edge.evcs.api.ManagedEvcs.ChannelId.SET_ENERGY_LIMIT; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.ACTIVE_POWER; import static org.junit.Assert.assertEquals; import org.junit.Test; import io.openems.common.function.ThrowingRunnable; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.channel.IntegerReadChannel; import io.openems.edge.common.filter.DisabledRampFilter; import io.openems.edge.common.filter.RampFilter; @@ -16,329 +22,272 @@ public class AbstractManagedEvcsTest { + /** + * Sleep between every TestCase to make sure that the Channel Values are added + * to the pastValues Map. This is required because the Channel Value timestamp + * does not consider the mocked Clock. + * + *

      + * Timeleap is not used, to avoid using a clock in the ChargeSatusHandler and + * therefore a ClockProvider function in every EVCS (.timeleap(clock, 31, + * ChronoUnit.SECONDS)) + */ + private static final ThrowingRunnable SLEEP = () -> Thread.sleep(1010); + private static final DummyEvcsPower EVCS_POWER = new DummyEvcsPower(new DisabledRampFilter()); private static final DummyEvcsPower EVCS_POWER_WITH_FILTER = new DummyEvcsPower(new RampFilter()); private static final DummyManagedEvcs EVCS0 = new DummyManagedEvcs("evcs0", EVCS_POWER); private static final DummyManagedEvcs EVCS1 = new DummyManagedEvcs("evcs1", EVCS_POWER); - private static final DummyManagedEvcs evcs2 = new DummyManagedEvcs("evcs2", EVCS_POWER_WITH_FILTER); + private static final DummyManagedEvcs EVCS2 = new DummyManagedEvcs("evcs2", EVCS_POWER_WITH_FILTER); private static final int MINIMUM = Evcs.DEFAULT_MINIMUM_HARDWARE_POWER; private static final int MAXIMUM = Evcs.DEFAULT_MAXIMUM_HARDWARE_POWER; - // Channel Addresses EVCS0 - private static ChannelAddress evcs0Status = new ChannelAddress("evcs0", "Status"); - private static ChannelAddress evcs0ChargeState = new ChannelAddress("evcs0", "ChargeState"); - private static ChannelAddress evcs0ChargePower = new ChannelAddress("evcs0", "ChargePower"); - private static ChannelAddress evcs0SetChargePowerLimit = new ChannelAddress("evcs0", "SetChargePowerLimit"); - - // Channel Addresses EVCS1 - private static ChannelAddress evcs1Status = new ChannelAddress("evcs1", "Status"); - private static ChannelAddress evcs1ChargeState = new ChannelAddress("evcs1", "ChargeState"); - private static ChannelAddress evcs1ChargePower = new ChannelAddress("evcs1", "ChargePower"); - private static ChannelAddress evcs1SetChargePowerLimit = new ChannelAddress("evcs1", "SetChargePowerLimit"); - private static ChannelAddress evcs1SetEnergyLimit = new ChannelAddress("evcs1", "SetEnergyLimit"); - private static ChannelAddress evcs1EnergySession = new ChannelAddress("evcs1", "EnergySession"); - - // Channel Addresses EVCS 2 - private static ChannelAddress evcs2Status = new ChannelAddress("evcs2", "Status"); - private static ChannelAddress evcs2ChargeState = new ChannelAddress("evcs2", "ChargeState"); - private static ChannelAddress evcs2ChargePower = new ChannelAddress("evcs2", "ChargePower"); - private static ChannelAddress evcs2SetChargePowerLimitWithFilter = new ChannelAddress("evcs2", - "SetChargePowerLimitWithFilter"); - /* * ATTENTION: The test could fail if you run it in Debug mode and e.g. the test * is expecting an output within the "getMinimumTimeTillCharingLimitTaken" time. */ - @Test public void abstractManagedEvcsTest() throws Exception { - // Sleep between every TestCase to make sure that the Channel Values are added - // to the pastValues Map. This is required because the Channel Value timestamp - // does not consider the mocked Clock. - final ThrowingRunnable sleep = () -> Thread.sleep(1010); - - ComponentTest test = new ComponentTest(EVCS0).addComponent(EVCS0); - - // Initial charge - test.next(new TestCase("Initial charge") // - - .input(evcs0SetChargePowerLimit, 15000) // - .input(evcs0ChargePower, 0) // - .input(evcs0Status, Status.READY_FOR_CHARGING) // - - .output(evcs0ChargePower, 15000) // - .output(evcs0ChargeState, ChargeState.INCREASING)); // - - /* - * Cannot check the nextValue of SetChargePowerLimit as output, because the test - * validator checks the write value (.output(evcs0SetChargePowerLimit, 15000)) - */ - // Check set charge limit + var test = new ComponentTest(EVCS0) // + .addComponent(EVCS0) // + + .next(new TestCase("Initial charge") // + .input(SET_CHARGE_POWER_LIMIT, 15000) // + .input(ACTIVE_POWER, 0) // + .input(STATUS, Status.READY_FOR_CHARGING) // + .output(ACTIVE_POWER, 15000) // + .output(CHARGE_STATE, ChargeState.INCREASING)); // + + // Cannot check the nextValue of SetChargePowerLimit as output, because the test + // validator checks the write value + // (.output(ManagedEvcs.ChannelId.SET_CHARGE_POWER_LIMIT, 15000)) assertEquals("Check next value of setChargePowerLimit", 15000, // - ((IntegerReadChannel) EVCS0.channel(ManagedEvcs.ChannelId.SET_CHARGE_POWER_LIMIT)).getNextValue() + (EVCS0.channel(SET_CHARGE_POWER_LIMIT)).getNextValue() .orElse(0).intValue()); - // Wait till charge limit is taken - test.next(new TestCase("Check ChargeState after 'getMinimumTimeTillCharingLimitTaken'") // - /* - * Timeleap is not used, to avoid using a clock in the ChargeSatusHandler and - * therefore a ClockProvider function in every EVCS (.timeleap(clock, 31, - * ChronoUnit.SECONDS)) - */ - .onAfterProcessImage(sleep) // - .input(evcs0ChargePower, 15000) // - .output(evcs0Status, Status.CHARGING) // - .output(evcs0ChargeState, ChargeState.CHARGING)); // - - // Decrease power - test.next(new TestCase("Decrease Power") // - .input(evcs0ChargePower, 15000) // - .input(evcs0SetChargePowerLimit, 8000) // - .output(evcs0ChargePower, 8000) // - .output(evcs0Status, Status.CHARGING) // - .output(evcs0ChargeState, ChargeState.DECREASING)); // - - // Enough power to increase, but 'MinimumTimeTillCharingLimitTaken' is not - // expired - test.next(new TestCase("Stay in decreasing charge state") // - .input(evcs0ChargePower, 8000) // - .input(evcs0SetChargePowerLimit, 20000) // - .output(evcs0ChargePower, 8000) // - .output(evcs0Status, Status.CHARGING) // - .output(evcs0ChargeState, ChargeState.DECREASING)); // - - // MinimumTimeTillCharingLimitTaken passed - test.next(new TestCase("MinimumTimeTillCharginglimitTaken passed") // - .onAfterProcessImage(sleep) // - .input(evcs0ChargePower, 8000) // - .input(evcs0SetChargePowerLimit, 20000) // - .output(evcs0ChargePower, 20000) // - .output(evcs0Status, Status.CHARGING) // - .output(evcs0ChargeState, ChargeState.INCREASING)); // - - // Charge power is increasing but decrease has higher priority than pause - test.next(new TestCase("Decrease has highest priority") // - .input(evcs0ChargePower, 20000) // - .input(evcs0SetChargePowerLimit, 0) // - .output(evcs0ChargePower, 0) // - .output(evcs0Status, Status.CHARGING_REJECTED) // - .output(evcs0ChargeState, ChargeState.DECREASING)); // + test // + .next(new TestCase("Check ChargeState after 'getMinimumTimeTillCharingLimitTaken'") // + .onAfterProcessImage(SLEEP) // + .input(ACTIVE_POWER, 15000) // + .output(STATUS, Status.CHARGING) // + .output(CHARGE_STATE, ChargeState.CHARGING)) + + .next(new TestCase("Decrease Power") // + .input(ACTIVE_POWER, 15000) // + .input(SET_CHARGE_POWER_LIMIT, 8000) // + .output(ACTIVE_POWER, 8000) // + .output(STATUS, Status.CHARGING) // + .output(CHARGE_STATE, ChargeState.DECREASING)) + + // Enough power to increase, but 'MinimumTimeTillCharingLimitTaken' is not + // expired + .next(new TestCase("Stay in decreasing charge state") // + .input(ACTIVE_POWER, 8000) // + .input(SET_CHARGE_POWER_LIMIT, 20000) // + .output(ACTIVE_POWER, 8000) // + .output(STATUS, Status.CHARGING) // + .output(CHARGE_STATE, ChargeState.DECREASING)) + + .next(new TestCase("MinimumTimeTillCharginglimitTaken passed") // + .onAfterProcessImage(SLEEP) // + .input(ACTIVE_POWER, 8000) // + .input(SET_CHARGE_POWER_LIMIT, 20000) // + .output(ACTIVE_POWER, 20000) // + .output(STATUS, Status.CHARGING) // + .output(CHARGE_STATE, ChargeState.INCREASING)) + + // Charge power is increasing but decrease has higher priority than pause + .next(new TestCase("Decrease has highest priority") // + .input(ACTIVE_POWER, 20000) // + .input(SET_CHARGE_POWER_LIMIT, 0) // + .output(ACTIVE_POWER, 0) // + .output(STATUS, Status.CHARGING_REJECTED) // + .output(CHARGE_STATE, ChargeState.DECREASING)); // } @Test public void abstractManagedEvcsStateChangesTest() throws Exception { - // Sleep between every TestCase to make sure that the Channel Values are added - // to the pastValues Map. This is required because the Channel Value timestamp - // does not consider the mocked Clock. - final ThrowingRunnable sleep = () -> Thread.sleep(1010); - - ComponentTest test = new ComponentTest(EVCS1).addComponent(EVCS1); - - // Initial charge - test.next(new TestCase("Initial charge") // - - .input(evcs1SetChargePowerLimit, 15000) // - .input(evcs1ChargePower, 0) // - .input(evcs1Status, Status.READY_FOR_CHARGING) // - .input(evcs1EnergySession, 9999) // - .input(evcs1SetEnergyLimit, 10000) // - .output(evcs1ChargePower, 15000) // - .output(evcs1ChargeState, ChargeState.INCREASING)); // - - // EnergyLimit Reached - test.next(new TestCase("Energy limit reached") // - .input(evcs1ChargePower, 15000) // - .input(evcs1EnergySession, 10000) // - .input(evcs1Status, Status.CHARGING) // - .output(evcs1ChargeState, ChargeState.DECREASING) // - .output(evcs1Status, Status.ENERGY_LIMIT_REACHED) // - .output(evcs1ChargePower, 0)); // - - // EnergyLimit increased - still in pause - test.next(new TestCase("Energy limit increased - still in pause") // - .input(evcs1ChargePower, 0) // - .input(evcs1EnergySession, 10000) // - .input(evcs1SetEnergyLimit, 20000) // - .input(evcs1SetChargePowerLimit, 15000) // - .output(evcs1ChargePower, 0) // - .output(evcs1ChargeState, ChargeState.DECREASING)); // - - // EnergyLimit increased - after pause - test.next(new TestCase("Energy limit increased - after pause") // - .onAfterProcessImage(sleep) // - .input(evcs1ChargePower, 0) // - .input(evcs1EnergySession, 10000) // - .input(evcs1SetEnergyLimit, 20000) // - .input(evcs1SetChargePowerLimit, 15000) // - .output(evcs1ChargePower, 15000) // - .output(evcs1ChargeState, ChargeState.INCREASING)); // - - // Decrease power - test.next(new TestCase("Decrease Power") // - .input(evcs1ChargePower, 15000) // - .input(evcs1SetChargePowerLimit, 8000) // - .output(evcs1ChargePower, 8000) // - .output(evcs1Status, Status.CHARGING) // - .output(evcs1ChargeState, ChargeState.DECREASING)); // - - // Enough power to increase, but 'MinimumTimeTillCharingLimitTaken' is not - // expired - test.next(new TestCase("Stay in decreasing charge state") // - .input(evcs1ChargePower, 8000) // - .input(evcs1SetChargePowerLimit, 20000) // - .output(evcs1ChargePower, 8000) // - .output(evcs1Status, Status.CHARGING) // - .output(evcs1ChargeState, ChargeState.DECREASING)); // - - // MinimumTimeTillCharingLimitTaken passed - test.next(new TestCase("MinimumTimeTillCharginglimitTaken passed") // - .onAfterProcessImage(sleep) // - .input(evcs1ChargePower, 8000) // - .input(evcs1SetChargePowerLimit, 20000) // - .output(evcs1ChargePower, 20000) // - .output(evcs1Status, Status.CHARGING) // - .output(evcs1ChargeState, ChargeState.INCREASING)); // - - // Charge power is increasing but decrease has higher priority than pause - test.next(new TestCase("Decrease has highest priority") // - .input(evcs1ChargePower, 20000) // - .input(evcs1SetChargePowerLimit, 0) // - .output(evcs1ChargePower, 0) // - .output(evcs1Status, Status.CHARGING_REJECTED) // - .output(evcs1ChargeState, ChargeState.DECREASING)); // + new ComponentTest(EVCS1) // + .addComponent(EVCS1) // + + .next(new TestCase("Initial charge") // + .input(SET_CHARGE_POWER_LIMIT, 15000) // + .input(ACTIVE_POWER, 0) // + .input(STATUS, Status.READY_FOR_CHARGING) // + .input(ENERGY_SESSION, 9999) // + .input(SET_ENERGY_LIMIT, 10000) // + .output(ACTIVE_POWER, 15000) // + .output(CHARGE_STATE, ChargeState.INCREASING)) + + .next(new TestCase("Energy limit reached") // + .input(ACTIVE_POWER, 15000) // + .input(ENERGY_SESSION, 10000) // + .input(STATUS, Status.CHARGING) // + .output(CHARGE_STATE, ChargeState.DECREASING) // + .output(STATUS, Status.ENERGY_LIMIT_REACHED) // + .output(ACTIVE_POWER, 0)) + + .next(new TestCase("Energy limit increased - still in pause") // + .input(ACTIVE_POWER, 0) // + .input(ENERGY_SESSION, 10000) // + .input(SET_ENERGY_LIMIT, 20000) // + .input(SET_CHARGE_POWER_LIMIT, 15000) // + .output(ACTIVE_POWER, 0) // + .output(CHARGE_STATE, ChargeState.DECREASING)) + + .next(new TestCase("Energy limit increased - after pause") // + .onAfterProcessImage(SLEEP) // + .input(ACTIVE_POWER, 0) // + .input(ENERGY_SESSION, 10000) // + .input(SET_ENERGY_LIMIT, 20000) // + .input(SET_CHARGE_POWER_LIMIT, 15000) // + .output(ACTIVE_POWER, 15000) // + .output(CHARGE_STATE, ChargeState.INCREASING)) + + .next(new TestCase("Decrease Power") // + .input(ACTIVE_POWER, 15000) // + .input(SET_CHARGE_POWER_LIMIT, 8000) // + .output(ACTIVE_POWER, 8000) // + .output(STATUS, Status.CHARGING) // + .output(CHARGE_STATE, ChargeState.DECREASING)) + + .next(new TestCase("Stay in decreasing charge state; 'MinimumTimeTillCharingLimitTaken' is not expired") // + .input(ACTIVE_POWER, 8000) // + .input(SET_CHARGE_POWER_LIMIT, 20000) // + .output(ACTIVE_POWER, 8000) // + .output(STATUS, Status.CHARGING) // + .output(CHARGE_STATE, ChargeState.DECREASING)) + + .next(new TestCase("MinimumTimeTillCharginglimitTaken passed") // + .onAfterProcessImage(SLEEP) // + .input(ACTIVE_POWER, 8000) // + .input(SET_CHARGE_POWER_LIMIT, 20000) // + .output(ACTIVE_POWER, 20000) // + .output(STATUS, Status.CHARGING) // + .output(CHARGE_STATE, ChargeState.INCREASING)) + + .next(new TestCase("Charge power is increasing, but decrease has highest priority") // + .input(ACTIVE_POWER, 20000) // + .input(SET_CHARGE_POWER_LIMIT, 0) // + .output(ACTIVE_POWER, 0) // + .output(STATUS, Status.CHARGING_REJECTED) // + .output(CHARGE_STATE, ChargeState.DECREASING)); // } @Test public void abstractManagedEvcsWithFilterTest() throws Exception { - // Sleep between every TestCase to make sure that the Channel Values are added - // to the pastValues Map. This is required because the Channel Value timestamp - // does not consider the mocked Clock. - final ThrowingRunnable sleep = () -> Thread.sleep(1010); - - ComponentTest test = new ComponentTest(evcs2).addComponent(evcs2); + ComponentTest test = new ComponentTest(EVCS2) // + .addComponent(EVCS2); // Initial charge - int initialResult = (int) (MINIMUM + MAXIMUM * evcs2.getEvcsPower().getIncreaseRate()); // 5244 - test.next(new TestCase("Initial charge") // - - .input(evcs2SetChargePowerLimitWithFilter, 15000) // - .input(evcs2ChargePower, 0) // - .input(evcs2Status, Status.READY_FOR_CHARGING) // - .output(evcs2ChargePower, initialResult) // - .output(evcs2ChargeState, ChargeState.INCREASING)); // - - /* - * Cannot check the nextValue of SetChargePowerLimit as output, because the test - * validator checks the write value (.output(evcs0SetChargePowerLimit, - * initialResult)) - */ - // Check set charge limit + int initialResult = (int) (MINIMUM + MAXIMUM * EVCS2.getEvcsPower().getIncreaseRate()); // 5244 + + test // + .next(new TestCase("Initial charge") // + .input(SET_CHARGE_POWER_LIMIT_WITH_FILTER, 15000) // + .input(ACTIVE_POWER, 0) // + .input(STATUS, Status.READY_FOR_CHARGING) // + .output(ACTIVE_POWER, initialResult) // + .output(CHARGE_STATE, ChargeState.INCREASING)); // + + // Cannot check the nextValue of SetChargePowerLimit as output, because the test + // validator checks the write value + // (.output(ManagedEvcs.ChannelId.SET_CHARGE_POWER_LIMIT, + // initialResult)) assertEquals("Check next value of setChargePowerLimit", initialResult, // - ((IntegerReadChannel) evcs2.channel(ManagedEvcs.ChannelId.SET_CHARGE_POWER_LIMIT)).getNextValue() + (EVCS2.channel(SET_CHARGE_POWER_LIMIT)).getNextValue() .orElse(0).intValue()); - // Further charge - int increasingValue = (int) (MAXIMUM * evcs2.getEvcsPower().getIncreaseRate()); - test.next(new TestCase("Further charge") // - - .input(evcs2SetChargePowerLimitWithFilter, 15000) // - .input(evcs2ChargePower, 5244) // - .input(evcs2Status, Status.CHARGING) // - .output(evcs2ChargePower, (int) (initialResult + increasingValue)) // 6348 W - .output(evcs2ChargeState, ChargeState.INCREASING)); // - - // Further charge - test.next(new TestCase("Further charge") // - - .input(evcs2SetChargePowerLimitWithFilter, 15000) // - .input(evcs2ChargePower, 6348) // - .input(evcs2Status, Status.CHARGING) // - .output(evcs2ChargePower, initialResult + increasingValue * 2) // 7452 W - .output(evcs2ChargeState, ChargeState.INCREASING)); // - - // Further charge - test.next(new TestCase("Further charge") // - - .input(evcs2SetChargePowerLimitWithFilter, 15000) // - .input(evcs2ChargePower, 6348) // - .input(evcs2Status, Status.CHARGING) // - .output(evcs2ChargePower, initialResult + increasingValue * 3) // 8556 W - .output(evcs2ChargeState, ChargeState.INCREASING)); // - - // Further charge - test.next(new TestCase("Further charge") // - - .input(evcs2SetChargePowerLimitWithFilter, 15000) // - .input(evcs2ChargePower, 6348) // - .input(evcs2Status, Status.CHARGING) // - .output(evcs2ChargePower, initialResult + increasingValue * 4) // 9660 W - .output(evcs2ChargeState, ChargeState.INCREASING)); // - - // Further charge - reached target - test.next(new TestCase("Further charge") // - - .input(evcs2SetChargePowerLimitWithFilter, 10000) // - .input(evcs2ChargePower, 6348) // - .input(evcs2Status, Status.CHARGING) // - .output(evcs2ChargePower, 10_000) // 10000 W - .output(evcs2ChargeState, ChargeState.INCREASING)); // - - // Wait till charge limit is taken - test.next(new TestCase("Check ChargeState after 'getMinimumTimeTillCharingLimitTaken'") // - .onAfterProcessImage(sleep) // - .input(evcs2ChargePower, 10000) // - .output(evcs2Status, Status.CHARGING) // - .output(evcs2ChargeState, ChargeState.CHARGING)); // - - // Decrease power - test.next(new TestCase("Decrease Power") // - .input(evcs2ChargePower, 10000) // - .input(evcs2SetChargePowerLimitWithFilter, 8000) // - .output(evcs2ChargePower, 8000) // - .output(evcs2Status, Status.CHARGING) // - .output(evcs2ChargeState, ChargeState.DECREASING)); // - - // Enough power to increase, but 'MinimumTimeTillCharingLimitTaken' is not - // expired - test.next(new TestCase("Stay in decreasing charge state") // - .input(evcs2ChargePower, 8000) // - .input(evcs2SetChargePowerLimitWithFilter, 20000) // - .output(evcs2ChargePower, 8000) // - .output(evcs2Status, Status.CHARGING) // - .output(evcs2ChargeState, ChargeState.DECREASING)); // - - // MinimumTimeTillCharingLimitTaken passed - test.next(new TestCase("MinimumTimeTillCharginglimitTaken passed") // - .onAfterProcessImage(sleep) // - .input(evcs2ChargePower, 8000) // - .input(evcs2SetChargePowerLimitWithFilter, 20000) // - .output(evcs2ChargePower, 8000 + increasingValue) // 9104 - .output(evcs2Status, Status.CHARGING) // - .output(evcs2ChargeState, ChargeState.INCREASING)); // - - // Charge power is increasing but decrease has higher priority than pause - test.next(new TestCase("Decrease has highest priority") // - .input(evcs2ChargePower, 20000) // - .input(evcs2SetChargePowerLimitWithFilter, 0) // - .output(evcs2ChargePower, 0) // - .output(evcs2Status, Status.CHARGING_REJECTED) // - .output(evcs2ChargeState, ChargeState.DECREASING)); // - - // Charging stopped - still in pause state - test.next(new TestCase("Charging stopped - still in pause state") // - .input(evcs2ChargePower, 0) // - .input(evcs2SetChargePowerLimitWithFilter, 0) // - .output(evcs2ChargePower, 0) // - .output(evcs2Status, Status.CHARGING_REJECTED) // - .output(evcs2ChargeState, ChargeState.DECREASING)); // - - // Charging stopped - test.next(new TestCase("Charging stopped") // - .onAfterProcessImage(sleep) // - .input(evcs2ChargePower, 0) // - .input(evcs2SetChargePowerLimitWithFilter, 0) // - .output(evcs2ChargePower, 0) // - .output(evcs2Status, Status.CHARGING_REJECTED) // - .output(evcs2ChargeState, ChargeState.NOT_CHARGING)); // + int increasingValue = (int) (MAXIMUM * EVCS2.getEvcsPower().getIncreaseRate()); + test // + .next(new TestCase("Further charge") // + .input(SET_CHARGE_POWER_LIMIT_WITH_FILTER, 15000) // + .input(ACTIVE_POWER, 5244) // + .input(STATUS, Status.CHARGING) // + // 6348 W + .output(ACTIVE_POWER, (int) (initialResult + increasingValue)) + .output(CHARGE_STATE, ChargeState.INCREASING)) + + .next(new TestCase("Further charge") // + .input(SET_CHARGE_POWER_LIMIT_WITH_FILTER, 15000) // + .input(ACTIVE_POWER, 6348) // + .input(STATUS, Status.CHARGING) // + .output(ACTIVE_POWER, initialResult + increasingValue * 2) // 7452 W + .output(CHARGE_STATE, ChargeState.INCREASING)) + + .next(new TestCase("Further charge") // + .input(SET_CHARGE_POWER_LIMIT_WITH_FILTER, 15000) // + .input(ACTIVE_POWER, 6348) // + .input(STATUS, Status.CHARGING) // + .output(ACTIVE_POWER, initialResult + increasingValue * 3) // 8556 W + .output(CHARGE_STATE, ChargeState.INCREASING)) + + .next(new TestCase("Further charge") // + .input(SET_CHARGE_POWER_LIMIT_WITH_FILTER, 15000) // + .input(ACTIVE_POWER, 6348) // + .input(STATUS, Status.CHARGING) // + .output(ACTIVE_POWER, initialResult + increasingValue * 4) // 9660 W + .output(CHARGE_STATE, ChargeState.INCREASING)) + + .next(new TestCase("Further charge - reached target") // + .input(SET_CHARGE_POWER_LIMIT_WITH_FILTER, 10000) // + .input(ACTIVE_POWER, 6348) // + .input(STATUS, Status.CHARGING) // + .output(ACTIVE_POWER, 10_000) // 10000 W + .output(CHARGE_STATE, ChargeState.INCREASING)) + + .next(new TestCase( + "Wait till charge limit is taken. Check ChargeState after 'getMinimumTimeTillCharingLimitTaken'") // + .onAfterProcessImage(SLEEP) // + .input(ACTIVE_POWER, 10000) // + .output(STATUS, Status.CHARGING) // + .output(CHARGE_STATE, ChargeState.CHARGING)) + + .next(new TestCase("Decrease Power") // + .input(ACTIVE_POWER, 10000) // + .input(SET_CHARGE_POWER_LIMIT_WITH_FILTER, 8000) // + .output(ACTIVE_POWER, 8000) // + .output(STATUS, Status.CHARGING) // + .output(CHARGE_STATE, ChargeState.DECREASING)) + + // Enough power to increase, but 'MinimumTimeTillCharingLimitTaken' is not + // expired + .next(new TestCase("Stay in decreasing charge state") // + .input(ACTIVE_POWER, 8000) // + .input(SET_CHARGE_POWER_LIMIT_WITH_FILTER, 20000) // + .output(ACTIVE_POWER, 8000) // + .output(STATUS, Status.CHARGING) // + .output(CHARGE_STATE, ChargeState.DECREASING)) + + .next(new TestCase("MinimumTimeTillCharginglimitTaken passed") // + .onAfterProcessImage(SLEEP) // + .input(ACTIVE_POWER, 8000) // + .input(SET_CHARGE_POWER_LIMIT_WITH_FILTER, 20000) // + .output(ACTIVE_POWER, 8000 + increasingValue) // 9104 + .output(STATUS, Status.CHARGING) // + .output(CHARGE_STATE, ChargeState.INCREASING)) + + // Charge power is increasing but decrease has higher priority than pause + .next(new TestCase("Decrease has highest priority") // + .input(ACTIVE_POWER, 20000) // + .input(SET_CHARGE_POWER_LIMIT_WITH_FILTER, 0) // + .output(ACTIVE_POWER, 0) // + .output(STATUS, Status.CHARGING_REJECTED) // + .output(CHARGE_STATE, ChargeState.DECREASING)) + + .next(new TestCase("Charging stopped - still in pause state") // + .input(ACTIVE_POWER, 0) // + .input(SET_CHARGE_POWER_LIMIT_WITH_FILTER, 0) // + .output(ACTIVE_POWER, 0) // + .output(STATUS, Status.CHARGING_REJECTED) // + .output(CHARGE_STATE, ChargeState.DECREASING)) + + .next(new TestCase("Charging stopped") // + .onAfterProcessImage(SLEEP) // + .input(ACTIVE_POWER, 0) // + .input(SET_CHARGE_POWER_LIMIT_WITH_FILTER, 0) // + .output(ACTIVE_POWER, 0) // + .output(STATUS, Status.CHARGING_REJECTED) // + .output(CHARGE_STATE, ChargeState.NOT_CHARGING)); // } } diff --git a/io.openems.edge.evcs.cluster/src/io/openems/edge/evcs/cluster/EvcsClusterPeakShavingImpl.java b/io.openems.edge.evcs.cluster/src/io/openems/edge/evcs/cluster/EvcsClusterPeakShavingImpl.java index 348062f8ecd..ab6eca07d59 100644 --- a/io.openems.edge.evcs.cluster/src/io/openems/edge/evcs/cluster/EvcsClusterPeakShavingImpl.java +++ b/io.openems.edge.evcs.cluster/src/io/openems/edge/evcs/cluster/EvcsClusterPeakShavingImpl.java @@ -1,5 +1,9 @@ package io.openems.edge.evcs.cluster; +import static io.openems.edge.evcs.api.Phases.THREE_PHASE; +import static io.openems.edge.evcs.api.Phases.TWO_PHASE; +import static java.lang.Math.round; + import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -39,7 +43,6 @@ import io.openems.edge.evcs.api.Evcs; import io.openems.edge.evcs.api.ManagedEvcs; import io.openems.edge.evcs.api.MetaEvcs; -import io.openems.edge.evcs.api.Phases; import io.openems.edge.meter.api.ElectricityMeter; @Designate(ocd = Config.class, factory = true) @@ -52,7 +55,7 @@ EdgeEventConstants.TOPIC_CYCLE_AFTER_CONTROLLERS, // }) public class EvcsClusterPeakShavingImpl extends AbstractOpenemsComponent - implements MetaEvcs, OpenemsComponent, Evcs, EventHandler, EvcsClusterPeakShaving, + implements MetaEvcs, OpenemsComponent, Evcs, ElectricityMeter, EventHandler, EvcsClusterPeakShaving, /* * Cluster is not a Controller, but we need to be placed at the correct position * in the Cycle by the Scheduler to be able to read the actually available ESS @@ -107,6 +110,7 @@ public class EvcsClusterPeakShavingImpl extends AbstractOpenemsComponent public EvcsClusterPeakShavingImpl() { super(// OpenemsComponent.ChannelId.values(), // + ElectricityMeter.ChannelId.values(), // Evcs.ChannelId.values(), // EvcsClusterPeakShaving.ChannelId.values(), // Controller.ChannelId.values() // @@ -222,8 +226,8 @@ public void handleEvent(Event event) { */ private void calculateChannelValues() { this.currentEvcsClusterState = EvcsClusterStatus.REGULAR; - final var chargePower = new CalculateIntegerSum(); - final var blockedChargePower = new CalculateIntegerSum(); + final var activePower = new CalculateIntegerSum(); + final var blockedActivePower = new CalculateIntegerSum(); final var minHardwarePower = new CalculateIntegerSum(); final var maxHardwarePowerOfAll = new CalculateIntegerSum(); final var minFixedHardwarePower = new CalculateIntegerSum(); @@ -231,20 +235,16 @@ private void calculateChannelValues() { final var minPower = new CalculateIntegerSum(); final var evcsClusterStatus = new CalculateEvcsClusterStatus(); - for (Evcs evcs : this.getSortedEvcss()) { - chargePower.addValue(evcs.getChargePowerChannel()); - blockedChargePower.addValue(evcs.getChargePowerChannel(), value -> { - + for (var evcs : this.getSortedEvcss()) { + activePower.addValue(evcs.getActivePowerChannel()); + blockedActivePower.addValue(evcs.getActivePowerChannel(), value -> { // Calculate the blocked power using all 3 phases for now if (value != null) { - switch (evcs.getPhases()) { - case ONE_PHASE: - return value * Phases.THREE_PHASE.getValue(); - case TWO_PHASE: - return Math.round(value / Phases.TWO_PHASE.getValue() * Phases.THREE_PHASE.getValue()); - case THREE_PHASE: - return value; - } + return switch (evcs.getPhases()) { + case ONE_PHASE -> value * THREE_PHASE.getValue(); + case TWO_PHASE -> round(value / TWO_PHASE.getValue() * THREE_PHASE.getValue()); + case THREE_PHASE -> value; + }; } return null; }); @@ -258,8 +258,8 @@ private void calculateChannelValues() { } } - this._setChargePower(chargePower.calculate()); - this._setEvcsBlockedChargePower(blockedChargePower.calculate()); + this._setActivePower(activePower.calculate()); + this._setEvcsBlockedChargePower(blockedActivePower.calculate()); this._setFixedMinimumHardwarePower(minFixedHardwarePower.calculate()); this._setFixedMaximumHardwarePower(maxFixedHardwarePower.calculate()); this.channel(Evcs.ChannelId.MINIMUM_HARDWARE_POWER).setNextValue(minHardwarePower.calculate()); @@ -329,7 +329,7 @@ protected void limitEvcss() { * Defines the active charging stations that are charging. */ List activeEvcss = new ArrayList<>(); - for (Evcs evcs : this.getSortedEvcss()) { + for (var evcs : this.getSortedEvcss()) { if (evcs instanceof ManagedEvcs) { var managedEvcs = (ManagedEvcs) evcs; int requestedPower = managedEvcs.getSetChargePowerRequestChannel().getNextWriteValue().orElse(0); @@ -361,8 +361,7 @@ protected void limitEvcss() { case READY_FOR_CHARGING: // Check if there is enough power for an initial charge - // if (totalPowerLimit - this.getChargePower().orElse(0) >= guaranteedPower) { - if (totalPowerLimit - initialChargePower - this.getChargePower().orElse(0) >= guaranteedPower) { + if (totalPowerLimit - initialChargePower - this.getActivePower().orElse(0) >= guaranteedPower) { this.logInfoInDebugmode("Set initial power " + guaranteedPower + " to " + evcs.id()); managedEvcs.setChargePowerLimit(guaranteedPower); @@ -404,7 +403,7 @@ protected void limitEvcss() { /* * Distributes the available Power to the active EVCSs */ - for (ManagedEvcs evcs : activeEvcss) { + for (var evcs : activeEvcss) { // int guaranteedPower = evcs.getMinimumPowerChannel().getNextValue().orElse(0); int guaranteedPower = evcs.getMinimumPowerChannel().getNextValue().orElse(0); @@ -483,8 +482,7 @@ public int getMaximumPowerToDistribute() { // Calculate maximum grid power var gridPower = this.getGridPower(); - var maxAvailableGridPower = (this.config.hardwarePowerLimitPerPhase() * Phases.THREE_PHASE.getValue()) - - gridPower; + var maxAvailableGridPower = (this.config.hardwarePowerLimitPerPhase() * THREE_PHASE.getValue()) - gridPower; this.channel(EvcsClusterPeakShaving.ChannelId.MAXIMUM_AVAILABLE_GRID_POWER).setNextValue(maxAvailableGridPower); // Current charge power blocked by all EVCS's @@ -496,7 +494,7 @@ public int getMaximumPowerToDistribute() { "Calculation of the maximum charge Power: EVCS Charge [" + evcsCharge + "] + Max. available storage power [" + maxAvailableStoragePower + "] + ( Configured Hardware Limit * 3 [" - + this.config.hardwarePowerLimitPerPhase() * Phases.THREE_PHASE.getValue() + + this.config.hardwarePowerLimitPerPhase() * THREE_PHASE.getValue() + "] - Maximum of all three phases * 3 [" + gridPower + "]"); return allowedChargePower > 0 ? allowedChargePower : 0; @@ -531,8 +529,7 @@ private int getGridPower() { public int getAvailableGridPower() { // Calculate maximum grid power int gridPower = this.getGridPower(); - int maxAvailableGridPower = (this.config.hardwarePowerLimitPerPhase() * Phases.THREE_PHASE.getValue()) - - gridPower; + int maxAvailableGridPower = (this.config.hardwarePowerLimitPerPhase() * THREE_PHASE.getValue()) - gridPower; return maxAvailableGridPower; } diff --git a/io.openems.edge.evcs.cluster/test/io/openems/edge/evcs/cluster/EvcsClusterPeakShavingImplTest.java b/io.openems.edge.evcs.cluster/test/io/openems/edge/evcs/cluster/EvcsClusterPeakShavingImplTest.java index 2f6aee35dbf..42c4a4310e9 100644 --- a/io.openems.edge.evcs.cluster/test/io/openems/edge/evcs/cluster/EvcsClusterPeakShavingImplTest.java +++ b/io.openems.edge.evcs.cluster/test/io/openems/edge/evcs/cluster/EvcsClusterPeakShavingImplTest.java @@ -1,8 +1,23 @@ package io.openems.edge.evcs.cluster; +import static io.openems.edge.common.sum.Sum.ChannelId.ESS_ACTIVE_POWER; +import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.ALLOWED_DISCHARGE_POWER; +import static io.openems.edge.evcs.api.Evcs.ChannelId.MAXIMUM_HARDWARE_POWER; +import static io.openems.edge.evcs.api.Evcs.ChannelId.MAXIMUM_POWER; +import static io.openems.edge.evcs.api.Evcs.ChannelId.MINIMUM_HARDWARE_POWER; +import static io.openems.edge.evcs.api.Evcs.ChannelId.STATUS; +import static io.openems.edge.evcs.api.ManagedEvcs.ChannelId.CHARGE_STATE; +import static io.openems.edge.evcs.api.ManagedEvcs.ChannelId.SET_CHARGE_POWER_LIMIT; +import static io.openems.edge.evcs.api.ManagedEvcs.ChannelId.SET_CHARGE_POWER_REQUEST; +import static io.openems.edge.evcs.cluster.EvcsClusterPeakShaving.ChannelId.EVCS_CLUSTER_STATUS; +import static io.openems.edge.evcs.cluster.EvcsClusterPeakShaving.ChannelId.MAXIMUM_POWER_TO_DISTRIBUTE; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.ACTIVE_POWER; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.ACTIVE_POWER_L1; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.ACTIVE_POWER_L2; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.ACTIVE_POWER_L3; + import org.junit.Test; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.filter.DisabledRampFilter; import io.openems.edge.common.filter.RampFilter; import io.openems.edge.common.sum.DummySum; @@ -29,341 +44,256 @@ public class EvcsClusterPeakShavingImplTest { private static final DummyManagedEvcs EVCS2 = new DummyManagedEvcs("evcs2", EVCS_POWER); private static final DummyManagedEvcs EVCS3 = new DummyManagedEvcs("evcs3", EVCS_POWER); private static final DummyManagedEvcs EVCS4 = new DummyManagedEvcs("evcs4", EVCS_POWER); - - private static final DummyEvcsPower EVCS_POWER_WITH_FILTER = new DummyEvcsPower(new RampFilter()); - private static final DummyManagedEvcs EVCS5 = new DummyManagedEvcs("evcs5", EVCS_POWER_WITH_FILTER); + private static final DummyManagedEvcs EVCS5 = new DummyManagedEvcs("evcs5", new DummyEvcsPower(new RampFilter())); private static final int HARDWARE_POWER_LIMIT_PER_PHASE = 7000; - private static final ChannelAddress SUM_ESS_ACTIVE_POWER = new ChannelAddress("_sum", "EssActivePower"); - private static final ChannelAddress METER_GRID_ACTIVE_POWER = new ChannelAddress("meter0", "ActivePower"); - private static final ChannelAddress METER_GRID_ACTIVE_POWER_L1 = new ChannelAddress("meter0", "ActivePowerL1"); - private static final ChannelAddress METER_GRID_ACTIVE_POWER_L2 = new ChannelAddress("meter0", "ActivePowerL2"); - private static final ChannelAddress METER_GRID_ACTIVE_POWER_L3 = new ChannelAddress("meter0", "ActivePowerL3"); - private static final ChannelAddress ESS_ALLOWED_DISCHARGE_POWER = new ChannelAddress("ess0", - "AllowedDischargePower"); - - private static final ChannelAddress EVCS_CLUSTER_MAXIMUM_POWER_TO_DISTRIBUTE = new ChannelAddress("evcsCluster0", - "MaximumPowerToDistribute"); - private static final ChannelAddress EVCS_CLUSTER_STATUS = new ChannelAddress("evcsCluster0", "EvcsClusterStatus"); - - private static final ChannelAddress EVCS0_STATUS = new ChannelAddress("evcs0", "Status"); - private static final ChannelAddress EVCS0_CHARGE_POWER = new ChannelAddress("evcs0", "ChargePower"); - private static final ChannelAddress EVCS0_MAXIMUM_POWER = new ChannelAddress("evcs0", "MaximumPower"); - private static final ChannelAddress EVCS0_SET_POWER_REQUEST = new ChannelAddress("evcs0", "SetChargePowerRequest"); - private static final ChannelAddress EVCS0_SET_CHARGE_POWER_LIMIT = new ChannelAddress("evcs0", - "SetChargePowerLimit"); - private static final ChannelAddress EVCS0_MAXIMUM_HARDWARE_POWER = new ChannelAddress("evcs0", - "MaximumHardwarePower"); - private static final ChannelAddress EVCS0_MINIMUM_HARDWARE_POWER = new ChannelAddress("evcs0", - "MinimumHardwarePower"); - private static final ChannelAddress EVCS0_CHARE_STATE = new ChannelAddress("evcs0", "ChargeState"); - - private static final ChannelAddress EVCS1_STATUS = new ChannelAddress("evcs1", "Status"); - private static final ChannelAddress EVCS1_CHARGE_POWER = new ChannelAddress("evcs1", "ChargePower"); - private static final ChannelAddress EVCS1_MAXIMUM_POWER = new ChannelAddress("evcs1", "MaximumPower"); - private static final ChannelAddress EVCS1_SET_POWER_REQUEST = new ChannelAddress("evcs1", "SetChargePowerRequest"); - private static final ChannelAddress EVCS1_SET_CHARGE_POWER_LIMIT = new ChannelAddress("evcs1", - "SetChargePowerLimit"); - private static final ChannelAddress EVCS1_MAXIMUM_HARDWARE_POWER = new ChannelAddress("evcs1", - "MaximumHardwarePower"); - private static final ChannelAddress EVCS1_MINIMUM_HARDWARE_POWER = new ChannelAddress("evcs1", - "MinimumHardwarePower"); - private static final ChannelAddress EVCS1_CHARGE_STATE = new ChannelAddress("evcs1", "ChargeState"); - - private static final ChannelAddress EVCS2_STATUS = new ChannelAddress("evcs2", "Status"); - private static final ChannelAddress EVCS2_SET_POWER_REQUEST = new ChannelAddress("evcs2", "SetChargePowerRequest"); - private static final ChannelAddress EVCS2_CHARGE_STATE = new ChannelAddress("evcs2", "ChargeState"); - - private static final ChannelAddress EVCS3_STATUS = new ChannelAddress("evcs3", "Status"); - private static final ChannelAddress EVCS3_SET_POWER_REQUEST = new ChannelAddress("evcs3", "SetChargePowerRequest"); - private static final ChannelAddress EVCS3_CHARGE_STATE = new ChannelAddress("evcs3", "ChargeState"); - - private static final ChannelAddress EVCS4_STATUS = new ChannelAddress("evcs4", "Status"); - private static final ChannelAddress EVCS4_SET_POWER_REQUEST = new ChannelAddress("evcs4", "SetChargePowerRequest"); - - private static final ChannelAddress EVCS5_STATUS = new ChannelAddress("evcs5", "Status"); - private static final ChannelAddress EVCS5_CHARGE_POWER = new ChannelAddress("evcs5", "ChargePower"); - private static final ChannelAddress EVCS5_SET_POWER_REQUEST = new ChannelAddress("evcs5", "SetChargePowerRequest"); - private static final ChannelAddress EVCS5_SET_CHARGE_POWER_LIMIT = new ChannelAddress("evcs5", - "SetChargePowerLimit"); - private static final ChannelAddress EVCS5_MAXIMUM_HARDWARE_POWER = new ChannelAddress("evcs5", - "MaximumHardwarePower"); - private static final ChannelAddress EVCS5_CHARGE_STATE = new ChannelAddress("evcs5", "ChargeState"); - @Test public void clusterMaximum_essActivePowerTest() throws Exception { - String[] evcsIds = { "evcs0", "evcs1" }; - new ComponentTest(new EvcsClusterPeakShavingImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // .addReference("sum", new DummySum()) // .addReference("addEvcs", EVCS0) // .addReference("addEvcs", EVCS1) // - .addReference("addEvcs", EVCS2) // - .addReference("addEvcs", EVCS3) // - .addReference("addEvcs", EVCS4) // .addReference("meter", METER) // .addReference("ess", ESS) // .activate(MyConfig.create() // - .setEssId(ESS.id()) // - .setMeterId(METER.id()) // + .setId("evcsCluster0") // + .setEssId("ess0") // + .setMeterId("meter0") // .setHardwarePowerLimit(HARDWARE_POWER_LIMIT_PER_PHASE) // - .setEvcsIds(evcsIds) // + .setEvcsIds("evcs0", "evcs1") // .build()) // .next(new TestCase() // - .input(EVCS0_CHARE_STATE, ChargeState.CHARGING) // - .input(SUM_ESS_ACTIVE_POWER, 0) // - .input(METER_GRID_ACTIVE_POWER, 0) // - .input(METER_GRID_ACTIVE_POWER_L1, 0) // - .input(METER_GRID_ACTIVE_POWER_L2, 0) // - .input(METER_GRID_ACTIVE_POWER_L3, 0) // - .input(ESS_ALLOWED_DISCHARGE_POWER, 0) // - .output(EVCS_CLUSTER_MAXIMUM_POWER_TO_DISTRIBUTE, 21000)) // + .input("evcs0", CHARGE_STATE, ChargeState.CHARGING) // + .input(ESS_ACTIVE_POWER, 0) // + .input("meter0", ACTIVE_POWER, 0) // + .input("meter0", ACTIVE_POWER_L1, 0) // + .input("meter0", ACTIVE_POWER_L2, 0) // + .input("meter0", ACTIVE_POWER_L3, 0) // + .input("ess0", ALLOWED_DISCHARGE_POWER, 0) // + .output("evcsCluster0", MAXIMUM_POWER_TO_DISTRIBUTE, 21000)) // .next(new TestCase() // - .input(SUM_ESS_ACTIVE_POWER, -5000) // - .output(EVCS_CLUSTER_MAXIMUM_POWER_TO_DISTRIBUTE, 26000)) // + .input(ESS_ACTIVE_POWER, -5000) // + .output("evcsCluster0", MAXIMUM_POWER_TO_DISTRIBUTE, 26000)) // .next(new TestCase() // - .input(SUM_ESS_ACTIVE_POWER, 6000) // - .output(EVCS_CLUSTER_MAXIMUM_POWER_TO_DISTRIBUTE, 15000)) // + .input(ESS_ACTIVE_POWER, 6000) // + .output("evcsCluster0", MAXIMUM_POWER_TO_DISTRIBUTE, 15000)) // ; } @Test public void clusterMaximum_symmetricGridPowerTest() throws Exception { - String[] evcsIds = { "evcs0", "evcs1" }; - new ComponentTest(new EvcsClusterPeakShavingImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // .addReference("sum", new DummySum()) // .addReference("addEvcs", EVCS0) // .addReference("addEvcs", EVCS1) // - .addReference("addEvcs", EVCS2) // - .addReference("addEvcs", EVCS3) // - .addReference("addEvcs", EVCS4) // .addReference("meter", METER) // .addReference("ess", ESS) // .activate(MyConfig.create() // - .setEssId(ESS.id()) // - .setMeterId(METER.id()) // + .setId("evcsCluster0") // + .setEssId("ess0") // + .setMeterId("meter0") // .setHardwarePowerLimit(HARDWARE_POWER_LIMIT_PER_PHASE) // - .setEvcsIds(evcsIds) // + .setEvcsIds("evcs0", "evcs1") // .build()) // .next(new TestCase() // - .input(EVCS0_CHARE_STATE, ChargeState.CHARGING) // - .input(METER_GRID_ACTIVE_POWER, -6000) // - .input(METER_GRID_ACTIVE_POWER_L1, -2000) // - .input(METER_GRID_ACTIVE_POWER_L2, -2000) // - .input(METER_GRID_ACTIVE_POWER_L3, -2000) // - .input(ESS_ALLOWED_DISCHARGE_POWER, 0)) // - .next(new TestCase() // - .output(EVCS_CLUSTER_MAXIMUM_POWER_TO_DISTRIBUTE, 27000)) // - .next(new TestCase() // - .input(METER_GRID_ACTIVE_POWER, 4500) // - .input(METER_GRID_ACTIVE_POWER_L1, 1500) // - .input(METER_GRID_ACTIVE_POWER_L2, 1500) // - .input(METER_GRID_ACTIVE_POWER_L3, 1500) // - .input(ESS_ALLOWED_DISCHARGE_POWER, 0) // - .output(EVCS_CLUSTER_MAXIMUM_POWER_TO_DISTRIBUTE, 16500)) // + .input("evcs0", CHARGE_STATE, ChargeState.CHARGING) // + .input("meter0", ACTIVE_POWER, -6000) // + .input("meter0", ACTIVE_POWER_L1, -2000) // + .input("meter0", ACTIVE_POWER_L2, -2000) // + .input("meter0", ACTIVE_POWER_L3, -2000) // + .input("ess0", ALLOWED_DISCHARGE_POWER, 0)) // + .next(new TestCase() // + .output("evcsCluster0", MAXIMUM_POWER_TO_DISTRIBUTE, 27000)) // + .next(new TestCase() // + .input("meter0", ACTIVE_POWER, 4500) // + .input("meter0", ACTIVE_POWER_L1, 1500) // + .input("meter0", ACTIVE_POWER_L2, 1500) // + .input("meter0", ACTIVE_POWER_L3, 1500) // + .input("ess0", ALLOWED_DISCHARGE_POWER, 0) // + .output("evcsCluster0", MAXIMUM_POWER_TO_DISTRIBUTE, 16500)) // ; } @Test public void clusterMaximum_assymmetricGridPowerTest() throws Exception { - String[] evcsIds = { "evcs0", "evcs1" }; - new ComponentTest(new EvcsClusterPeakShavingImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // .addReference("sum", new DummySum()) // .addReference("addEvcs", EVCS0) // .addReference("addEvcs", EVCS1) // - .addReference("addEvcs", EVCS2) // - .addReference("addEvcs", EVCS3) // - .addReference("addEvcs", EVCS4) // .addReference("meter", METER) // .addReference("ess", ESS) // .activate(MyConfig.create() // - .setEssId(ESS.id()) // - .setMeterId(METER.id()) // + .setId("evcsCluster0") // + .setEssId("ess0") // + .setMeterId("meter0") // .setHardwarePowerLimit(HARDWARE_POWER_LIMIT_PER_PHASE) // - .setEvcsIds(evcsIds) // + .setEvcsIds("evcs0", "evcs1") // .build()) // .next(new TestCase() // - .input(EVCS0_CHARE_STATE, ChargeState.CHARGING) // - .input(METER_GRID_ACTIVE_POWER, -4000) // - .input(METER_GRID_ACTIVE_POWER_L1, -2000) // - .input(METER_GRID_ACTIVE_POWER_L2, -1000) // - .input(METER_GRID_ACTIVE_POWER_L3, -1000) // - .input(ESS_ALLOWED_DISCHARGE_POWER, 0) // - .output(EVCS_CLUSTER_MAXIMUM_POWER_TO_DISTRIBUTE, 24000)) // - .next(new TestCase() // - .input(METER_GRID_ACTIVE_POWER, 4500) // - .input(METER_GRID_ACTIVE_POWER_L1, 3000) // - .input(METER_GRID_ACTIVE_POWER_L2, 1500) // - .input(METER_GRID_ACTIVE_POWER_L3, 500) // - .input(ESS_ALLOWED_DISCHARGE_POWER, 0) // - .output(EVCS_CLUSTER_MAXIMUM_POWER_TO_DISTRIBUTE, 12000)) // + .input("evcs0", CHARGE_STATE, ChargeState.CHARGING) // + .input("meter0", ACTIVE_POWER, -4000) // + .input("meter0", ACTIVE_POWER_L1, -2000) // + .input("meter0", ACTIVE_POWER_L2, -1000) // + .input("meter0", ACTIVE_POWER_L3, -1000) // + .input("ess0", ALLOWED_DISCHARGE_POWER, 0) // + .output("evcsCluster0", MAXIMUM_POWER_TO_DISTRIBUTE, 24000)) // + .next(new TestCase() // + .input("meter0", ACTIVE_POWER, 4500) // + .input("meter0", ACTIVE_POWER_L1, 3000) // + .input("meter0", ACTIVE_POWER_L2, 1500) // + .input("meter0", ACTIVE_POWER_L3, 500) // + .input("ess0", ALLOWED_DISCHARGE_POWER, 0) // + .output("evcsCluster0", MAXIMUM_POWER_TO_DISTRIBUTE, 12000)) // ; } @Test public void clusterMaximum_symmetricGridPower_essActivePowerTest() throws Exception { - String[] evcsIds = { "evcs0", "evcs1" }; - new ComponentTest(new EvcsClusterPeakShavingImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // .addReference("sum", new DummySum()) // .addReference("addEvcs", EVCS0) // .addReference("addEvcs", EVCS1) // - .addReference("addEvcs", EVCS2) // - .addReference("addEvcs", EVCS3) // - .addReference("addEvcs", EVCS4) // .addReference("meter", METER) // .addReference("ess", ESS) // .activate(MyConfig.create() // - .setEssId(ESS.id()) // - .setMeterId(METER.id()) // + .setId("evcsCluster0") // + .setEssId("ess0") // + .setMeterId("meter0") // .setHardwarePowerLimit(HARDWARE_POWER_LIMIT_PER_PHASE) // - .setEvcsIds(evcsIds) // + .setEvcsIds("evcs0", "evcs1") // .build()) // .next(new TestCase() // - .input(EVCS0_CHARE_STATE, ChargeState.CHARGING) // - .input(METER_GRID_ACTIVE_POWER, -6000) // - .input(METER_GRID_ACTIVE_POWER_L1, -2000) // - .input(METER_GRID_ACTIVE_POWER_L2, -2000) // - .input(METER_GRID_ACTIVE_POWER_L3, -2000) // - .input(SUM_ESS_ACTIVE_POWER, -6000) // - .input(ESS_ALLOWED_DISCHARGE_POWER, 0) // - .output(EVCS_CLUSTER_MAXIMUM_POWER_TO_DISTRIBUTE, 33000)) // - .next(new TestCase() // - .input(METER_GRID_ACTIVE_POWER, 4500) // - .input(METER_GRID_ACTIVE_POWER_L1, 1500) // - .input(METER_GRID_ACTIVE_POWER_L2, 1500) // - .input(METER_GRID_ACTIVE_POWER_L3, 1500) // - .input(SUM_ESS_ACTIVE_POWER, 3000) // - .input(ESS_ALLOWED_DISCHARGE_POWER, 0) // - .output(EVCS_CLUSTER_MAXIMUM_POWER_TO_DISTRIBUTE, 13500)) // + .input("evcs0", CHARGE_STATE, ChargeState.CHARGING) // + .input("meter0", ACTIVE_POWER, -6000) // + .input("meter0", ACTIVE_POWER_L1, -2000) // + .input("meter0", ACTIVE_POWER_L2, -2000) // + .input("meter0", ACTIVE_POWER_L3, -2000) // + .input(ESS_ACTIVE_POWER, -6000) // + .input("ess0", ALLOWED_DISCHARGE_POWER, 0) // + .output("evcsCluster0", MAXIMUM_POWER_TO_DISTRIBUTE, 33000)) // + .next(new TestCase() // + .input("meter0", ACTIVE_POWER, 4500) // + .input("meter0", ACTIVE_POWER_L1, 1500) // + .input("meter0", ACTIVE_POWER_L2, 1500) // + .input("meter0", ACTIVE_POWER_L3, 1500) // + .input(ESS_ACTIVE_POWER, 3000) // + .input("ess0", ALLOWED_DISCHARGE_POWER, 0) // + .output("evcsCluster0", MAXIMUM_POWER_TO_DISTRIBUTE, 13500)) // ; } @Test public void clusterMaximum_essAllowedDischargePowerTest() throws Exception { - String[] evcsIds = { "evcs0", "evcs1" }; - var sut = new EvcsClusterPeakShavingImpl(); - var test = new ComponentTest(sut) // + new ComponentTest(sut) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // .addReference("sum", new DummySum()) // .addReference("addEvcs", EVCS0) // .addReference("addEvcs", EVCS1) // - .addReference("addEvcs", EVCS2) // - .addReference("addEvcs", EVCS3) // - .addReference("addEvcs", EVCS4) // .addReference("meter", METER) // .addReference("ess", ESS) // .activate(MyConfig.create() // - .setEssId(ESS.id()) // - .setMeterId(METER.id()) // + .setId("evcsCluster0") // + .setEssId("ess0") // + .setMeterId("meter0") // .setHardwarePowerLimit(HARDWARE_POWER_LIMIT_PER_PHASE) // - .setEvcsIds(evcsIds) // - .build()); // - test// - .next(new TestCase() // - .input(EVCS0_CHARE_STATE, ChargeState.CHARGING) // - .input(METER_GRID_ACTIVE_POWER, -6000) // - .input(METER_GRID_ACTIVE_POWER_L1, -2000) // - .input(METER_GRID_ACTIVE_POWER_L2, -2000) // - .input(METER_GRID_ACTIVE_POWER_L3, -2000) // - .input(SUM_ESS_ACTIVE_POWER, -6000) // - .input(ESS_ALLOWED_DISCHARGE_POWER, 10000) // + .setEvcsIds("evcs0", "evcs1") // + .build()) // + .next(new TestCase() // + .input("evcs0", CHARGE_STATE, ChargeState.CHARGING) // + .input("meter0", ACTIVE_POWER, -6000) // + .input("meter0", ACTIVE_POWER_L1, -2000) // + .input("meter0", ACTIVE_POWER_L2, -2000) // + .input("meter0", ACTIVE_POWER_L3, -2000) // + .input(ESS_ACTIVE_POWER, -6000) // + .input("ess0", ALLOWED_DISCHARGE_POWER, 10000) // .onBeforeControllersCallbacks(() -> sut.run()) // - .output(EVCS_CLUSTER_MAXIMUM_POWER_TO_DISTRIBUTE, 63000)) // - .next(new TestCase() // - .input(METER_GRID_ACTIVE_POWER, 4500) // - .input(METER_GRID_ACTIVE_POWER_L1, 1500) // - .input(METER_GRID_ACTIVE_POWER_L2, 1500) // - .input(METER_GRID_ACTIVE_POWER_L3, 1500) // - .input(SUM_ESS_ACTIVE_POWER, 3000) // - .input(ESS_ALLOWED_DISCHARGE_POWER, 20000) // + .output("evcsCluster0", MAXIMUM_POWER_TO_DISTRIBUTE, 63000)) // + .next(new TestCase() // + .input("meter0", ACTIVE_POWER, 4500) // + .input("meter0", ACTIVE_POWER_L1, 1500) // + .input("meter0", ACTIVE_POWER_L2, 1500) // + .input("meter0", ACTIVE_POWER_L3, 1500) // + .input(ESS_ACTIVE_POWER, 3000) // + .input("ess0", ALLOWED_DISCHARGE_POWER, 20000) // .onBeforeControllersCallbacks(() -> sut.run()) // - .output(EVCS_CLUSTER_MAXIMUM_POWER_TO_DISTRIBUTE, 43500)) // + .output("evcsCluster0", MAXIMUM_POWER_TO_DISTRIBUTE, 43500)) // ; } @Test public void clusterDistribution_nothingToChargeTest() throws Exception { - String[] evcsIds = { "evcs0", "evcs1" }; - new ComponentTest(new EvcsClusterPeakShavingImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // .addReference("sum", new DummySum()) // .addReference("addEvcs", EVCS0) // .addReference("addEvcs", EVCS1) // - .addReference("addEvcs", EVCS2) // - .addReference("addEvcs", EVCS3) // - .addReference("addEvcs", EVCS4) // .addReference("meter", METER) // .addReference("ess", ESS) // .activate(MyConfig.create() // - .setEssId(ESS.id()) // - .setMeterId(METER.id()) // + .setId("evcsCluster0") // + .setEssId("ess0") // + .setMeterId("meter0") // .setHardwarePowerLimit(HARDWARE_POWER_LIMIT_PER_PHASE) // - .setEvcsIds(evcsIds) // + .setEvcsIds("evcs0", "evcs1") // .build()) // .next(new TestCase() // - .input(EVCS0_CHARE_STATE, ChargeState.CHARGING)) // - .next(new TestCase() // - .input(SUM_ESS_ACTIVE_POWER, 0) // - .input(METER_GRID_ACTIVE_POWER, 0) // - .input(METER_GRID_ACTIVE_POWER_L1, 0) // - .input(METER_GRID_ACTIVE_POWER_L2, 0) // - .input(METER_GRID_ACTIVE_POWER_L3, 0) // - .input(ESS_ALLOWED_DISCHARGE_POWER, 0) // - .input(EVCS0_SET_POWER_REQUEST, 0) // - .output(EVCS0_SET_CHARGE_POWER_LIMIT, 0)) // - .next(new TestCase() // - .input(SUM_ESS_ACTIVE_POWER, 0) // - .input(METER_GRID_ACTIVE_POWER, 21000) // - .input(METER_GRID_ACTIVE_POWER_L1, 7000) // - .input(METER_GRID_ACTIVE_POWER_L2, 7000) // - .input(METER_GRID_ACTIVE_POWER_L3, 7000) // - .input(EVCS0_SET_POWER_REQUEST, 15000) // - .input(ESS_ALLOWED_DISCHARGE_POWER, 0) // - .output(EVCS_CLUSTER_MAXIMUM_POWER_TO_DISTRIBUTE, 0) // - .output(EVCS0_SET_CHARGE_POWER_LIMIT, 0)) // - .next(new TestCase() // - .input(SUM_ESS_ACTIVE_POWER, 0) // - .input(METER_GRID_ACTIVE_POWER, 15000) // - .input(METER_GRID_ACTIVE_POWER_L1, 5000) // - .input(METER_GRID_ACTIVE_POWER_L2, 5000) // - .input(METER_GRID_ACTIVE_POWER_L3, 5000) // - .input(EVCS0_SET_POWER_REQUEST, 15000) // - .input(EVCS1_SET_POWER_REQUEST, 15000) // - .input(EVCS0_MAXIMUM_POWER, 22000) // - .input(EVCS1_MAXIMUM_POWER, 22000) // - .input(EVCS0_MINIMUM_HARDWARE_POWER, 4500) // - .input(EVCS1_MINIMUM_HARDWARE_POWER, 4500) // - .input(EVCS0_MAXIMUM_HARDWARE_POWER, 22000) // - .input(EVCS1_MAXIMUM_HARDWARE_POWER, 22000) // - .input(EVCS0_STATUS, Status.CHARGING) // - .input(EVCS1_STATUS, Status.CHARGING) // - .input(ESS_ALLOWED_DISCHARGE_POWER, 0) // - .output(EVCS_CLUSTER_MAXIMUM_POWER_TO_DISTRIBUTE, 6000) // - .output(EVCS0_SET_CHARGE_POWER_LIMIT, 6000) // - .output(EVCS1_SET_CHARGE_POWER_LIMIT, 0)) // + .input("evcs0", CHARGE_STATE, ChargeState.CHARGING)) // + .next(new TestCase() // + .input(ESS_ACTIVE_POWER, 0) // + .input("meter0", ACTIVE_POWER, 0) // + .input("meter0", ACTIVE_POWER_L1, 0) // + .input("meter0", ACTIVE_POWER_L2, 0) // + .input("meter0", ACTIVE_POWER_L3, 0) // + .input("ess0", ALLOWED_DISCHARGE_POWER, 0) // + .input("evcs0", SET_CHARGE_POWER_REQUEST, 0) // + .output("evcs0", SET_CHARGE_POWER_LIMIT, 0)) // + .next(new TestCase() // + .input(ESS_ACTIVE_POWER, 0) // + .input("meter0", ACTIVE_POWER, 21000) // + .input("meter0", ACTIVE_POWER_L1, 7000) // + .input("meter0", ACTIVE_POWER_L2, 7000) // + .input("meter0", ACTIVE_POWER_L3, 7000) // + .input("evcs0", SET_CHARGE_POWER_REQUEST, 15000) // + .input("ess0", ALLOWED_DISCHARGE_POWER, 0) // + .output("evcsCluster0", MAXIMUM_POWER_TO_DISTRIBUTE, 0) // + .output("evcs0", SET_CHARGE_POWER_LIMIT, 0)) // + .next(new TestCase() // + .input(ESS_ACTIVE_POWER, 0) // + .input("meter0", ACTIVE_POWER, 15000) // + .input("meter0", ACTIVE_POWER_L1, 5000) // + .input("meter0", ACTIVE_POWER_L2, 5000) // + .input("meter0", ACTIVE_POWER_L3, 5000) // + .input("evcs0", SET_CHARGE_POWER_REQUEST, 15000) // + .input("evcs1", SET_CHARGE_POWER_REQUEST, 15000) // + .input("evcs0", MAXIMUM_POWER, 22000) // + .input("evcs1", MAXIMUM_POWER, 22000) // + .input("evcs0", MINIMUM_HARDWARE_POWER, 4500) // + .input("evcs1", MINIMUM_HARDWARE_POWER, 4500) // + .input("evcs0", MAXIMUM_HARDWARE_POWER, 22000) // + .input("evcs1", MAXIMUM_HARDWARE_POWER, 22000) // + .input("evcs0", STATUS, Status.CHARGING) // + .input("evcs1", STATUS, Status.CHARGING) // + .input("ess0", ALLOWED_DISCHARGE_POWER, 0) // + .output("evcsCluster0", MAXIMUM_POWER_TO_DISTRIBUTE, 6000) // + .output("evcs0", SET_CHARGE_POWER_LIMIT, 6000) // + .output("evcs1", SET_CHARGE_POWER_LIMIT, 0)) // ; } @Test public void clusterDistribution_chargeTest() throws Exception { - String[] evcsIds = { "evcs0", "evcs1", "evcs2", "evcs3", "evcs4" }; - new ComponentTest(new EvcsClusterPeakShavingImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // @@ -376,237 +306,218 @@ public void clusterDistribution_chargeTest() throws Exception { .addReference("meter", METER) // .addReference("ess", ESS) // .activate(MyConfig.create() // - .setEssId(ESS.id()) // - .setMeterId(METER.id()) // + .setId("evcsCluster0") // + .setEssId("ess0") // + .setMeterId("meter0") // .setHardwarePowerLimit(HARDWARE_POWER_LIMIT_PER_PHASE) // - .setEvcsIds(evcsIds) // + .setEvcsIds("evcs0", "evcs1", "evcs2", "evcs3", "evcs4") // .build()) // .next(new TestCase() // - .input(EVCS0_CHARE_STATE, ChargeState.CHARGING) // - .input(SUM_ESS_ACTIVE_POWER, 0) // - .input(METER_GRID_ACTIVE_POWER, 0) // - .input(METER_GRID_ACTIVE_POWER_L1, 0) // - .input(METER_GRID_ACTIVE_POWER_L2, 0) // - .input(METER_GRID_ACTIVE_POWER_L3, 0) // - .input(ESS_ALLOWED_DISCHARGE_POWER, 30000) // - .input(EVCS0_SET_POWER_REQUEST, 15000) // - .input(EVCS1_SET_POWER_REQUEST, 15000) // - .input(EVCS2_SET_POWER_REQUEST, 15000) // - .input(EVCS3_SET_POWER_REQUEST, 15000) // - .input(EVCS4_SET_POWER_REQUEST, 15000) // - .input(EVCS0_STATUS, Status.CHARGING) // - .input(EVCS1_STATUS, Status.CHARGING) // - .input(EVCS2_STATUS, Status.CHARGING) // - .input(EVCS3_STATUS, Status.CHARGING) // - .input(EVCS4_STATUS, Status.CHARGING) // - .input(EVCS0_MAXIMUM_POWER, null) // - .input(EVCS1_MAXIMUM_POWER, null) // - .input(EVCS0_MAXIMUM_HARDWARE_POWER, 22000) // - .input(EVCS1_MAXIMUM_HARDWARE_POWER, 22000) // - .input(EVCS0_CHARGE_POWER, 0) // - .input(EVCS1_CHARGE_POWER, 0)) // + .input("evcs0", CHARGE_STATE, ChargeState.CHARGING) // + .input(ESS_ACTIVE_POWER, 0) // + .input("meter0", ACTIVE_POWER, 0) // + .input("meter0", ACTIVE_POWER_L1, 0) // + .input("meter0", ACTIVE_POWER_L2, 0) // + .input("meter0", ACTIVE_POWER_L3, 0) // + .input("ess0", ALLOWED_DISCHARGE_POWER, 30000) // + .input("evcs0", SET_CHARGE_POWER_REQUEST, 15000) // + .input("evcs1", SET_CHARGE_POWER_REQUEST, 15000) // + .input("evcs2", SET_CHARGE_POWER_REQUEST, 15000) // + .input("evcs3", SET_CHARGE_POWER_REQUEST, 15000) // + .input("evcs4", SET_CHARGE_POWER_REQUEST, 15000) // + .input("evcs0", STATUS, Status.CHARGING) // + .input("evcs1", STATUS, Status.CHARGING) // + .input("evcs2", STATUS, Status.CHARGING) // + .input("evcs3", STATUS, Status.CHARGING) // + .input("evcs4", STATUS, Status.CHARGING) // + .input("evcs0", MAXIMUM_POWER, null) // + .input("evcs1", MAXIMUM_POWER, null) // + .input("evcs0", MAXIMUM_HARDWARE_POWER, 22000) // + .input("evcs1", MAXIMUM_HARDWARE_POWER, 22000) // + .input("evcs0", ACTIVE_POWER, 0) // + .input("evcs1", ACTIVE_POWER, 0)) // ; } @Test public void clusterDistribution_chargeTest2() throws Exception { - String[] evcsIds = { "evcs0", "evcs1" }; - new ComponentTest(new EvcsClusterPeakShavingImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // .addReference("sum", new DummySum()) // .addReference("addEvcs", EVCS0) // .addReference("addEvcs", EVCS1) // - .addReference("addEvcs", EVCS2) // - .addReference("addEvcs", EVCS3) // - .addReference("addEvcs", EVCS4) // .addReference("meter", METER) // .addReference("ess", ESS) // .activate(MyConfig.create() // - .setEssId(ESS.id()) // - .setMeterId(METER.id()) // + .setId("evcsCluster0") // + .setEssId("ess0") // + .setMeterId("meter0") // .setHardwarePowerLimit(HARDWARE_POWER_LIMIT_PER_PHASE) // - .setEvcsIds(evcsIds) // + .setEvcsIds("evcs0", "evcs1") // .build()) // .next(new TestCase() // - .input(EVCS0_CHARE_STATE, ChargeState.CHARGING) // - .input(SUM_ESS_ACTIVE_POWER, 0) // - .input(METER_GRID_ACTIVE_POWER, 0) // - .input(METER_GRID_ACTIVE_POWER_L1, 0) // - .input(METER_GRID_ACTIVE_POWER_L2, 0) // - .input(METER_GRID_ACTIVE_POWER_L3, 0) // - .input(ESS_ALLOWED_DISCHARGE_POWER, 0) // - .input(EVCS0_SET_POWER_REQUEST, 15000) // - .input(EVCS1_SET_POWER_REQUEST, 15000) // + .input("evcs0", CHARGE_STATE, ChargeState.CHARGING) // + .input(ESS_ACTIVE_POWER, 0) // + .input("meter0", ACTIVE_POWER, 0) // + .input("meter0", ACTIVE_POWER_L1, 0) // + .input("meter0", ACTIVE_POWER_L2, 0) // + .input("meter0", ACTIVE_POWER_L3, 0) // + .input("ess0", ALLOWED_DISCHARGE_POWER, 0) // + .input("evcs0", SET_CHARGE_POWER_REQUEST, 15000) // + .input("evcs1", SET_CHARGE_POWER_REQUEST, 15000) // // TODO: The charge power of an EVCS has to be checked if it really charges // this amount) - .input(EVCS0_CHARGE_POWER, 11000) // - .input(EVCS1_CHARGE_POWER, 22000) // - .input(EVCS0_MAXIMUM_POWER, 22000) // - .input(EVCS1_MAXIMUM_POWER, 22000) // - .input(EVCS0_MAXIMUM_HARDWARE_POWER, 22000) // - .input(EVCS1_MAXIMUM_HARDWARE_POWER, 22000) // - .input(EVCS0_STATUS, Status.CHARGING) // - .input(EVCS1_STATUS, Status.CHARGING)) // - .next(new TestCase() // - .output(EVCS_CLUSTER_MAXIMUM_POWER_TO_DISTRIBUTE, 54000) // - .output(EVCS0_SET_CHARGE_POWER_LIMIT, 15000) // - .output(EVCS1_SET_CHARGE_POWER_LIMIT, 15000)) // + .input("evcs0", ACTIVE_POWER, 11000) // + .input("evcs1", ACTIVE_POWER, 22000) // + .input("evcs0", MAXIMUM_POWER, 22000) // + .input("evcs1", MAXIMUM_POWER, 22000) // + .input("evcs0", MAXIMUM_HARDWARE_POWER, 22000) // + .input("evcs1", MAXIMUM_HARDWARE_POWER, 22000) // + .input("evcs0", STATUS, Status.CHARGING) // + .input("evcs1", STATUS, Status.CHARGING)) // + .next(new TestCase() // + .output("evcsCluster0", MAXIMUM_POWER_TO_DISTRIBUTE, 54000) // + .output("evcs0", SET_CHARGE_POWER_LIMIT, 15000) // + .output("evcs1", SET_CHARGE_POWER_LIMIT, 15000)) // ; } @Test public void clusterDistribution_chargeTest_maximumHardwarePowerTest() throws Exception { - String[] evcsIds = { "evcs0", "evcs1" }; - new ComponentTest(new EvcsClusterPeakShavingImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // .addReference("sum", new DummySum()) // .addReference("addEvcs", EVCS0) // .addReference("addEvcs", EVCS1) // - .addReference("addEvcs", EVCS2) // - .addReference("addEvcs", EVCS3) // - .addReference("addEvcs", EVCS4) // .addReference("meter", METER) // .addReference("ess", ESS) // .activate(MyConfig.create() // - .setEssId(ESS.id()) // - .setMeterId(METER.id()) // + .setId("evcsCluster0") // + .setEssId("ess0") // + .setMeterId("meter0") // .setHardwarePowerLimit(HARDWARE_POWER_LIMIT_PER_PHASE) // - .setEvcsIds(evcsIds) // + .setEvcsIds("evcs0", "evcs1") // .build()) // .next(new TestCase() // - .input(EVCS0_CHARE_STATE, ChargeState.CHARGING) // - .input(SUM_ESS_ACTIVE_POWER, 0) // - .input(METER_GRID_ACTIVE_POWER, 0) // - .input(METER_GRID_ACTIVE_POWER_L1, 0) // - .input(METER_GRID_ACTIVE_POWER_L2, 0) // - .input(METER_GRID_ACTIVE_POWER_L3, 0) // - .input(ESS_ALLOWED_DISCHARGE_POWER, 0) // - .input(EVCS0_SET_POWER_REQUEST, 15000) // - .input(EVCS1_SET_POWER_REQUEST, 15000) // - .input(EVCS0_CHARGE_POWER, 11000) // - .input(EVCS1_CHARGE_POWER, 0) // - .input(EVCS0_MAXIMUM_POWER, null) // - .input(EVCS1_MAXIMUM_POWER, null) // - .input(EVCS0_MAXIMUM_HARDWARE_POWER, 11000) // - .input(EVCS1_MAXIMUM_HARDWARE_POWER, 11000) // - .input(EVCS0_STATUS, Status.CHARGING) // - .input(EVCS1_STATUS, Status.CHARGING)) // - .next(new TestCase() // - .output(EVCS_CLUSTER_MAXIMUM_POWER_TO_DISTRIBUTE, 32000) // - .output(EVCS0_SET_CHARGE_POWER_LIMIT, 11000) // - .output(EVCS1_SET_CHARGE_POWER_LIMIT, 11000)) // + .input("evcs0", CHARGE_STATE, ChargeState.CHARGING) // + .input(ESS_ACTIVE_POWER, 0) // + .input("meter0", ACTIVE_POWER, 0) // + .input("meter0", ACTIVE_POWER_L1, 0) // + .input("meter0", ACTIVE_POWER_L2, 0) // + .input("meter0", ACTIVE_POWER_L3, 0) // + .input("ess0", ALLOWED_DISCHARGE_POWER, 0) // + .input("evcs0", SET_CHARGE_POWER_REQUEST, 15000) // + .input("evcs1", SET_CHARGE_POWER_REQUEST, 15000) // + .input("evcs0", ACTIVE_POWER, 11000) // + .input("evcs1", ACTIVE_POWER, 0) // + .input("evcs0", MAXIMUM_POWER, null) // + .input("evcs1", MAXIMUM_POWER, null) // + .input("evcs0", MAXIMUM_HARDWARE_POWER, 11000) // + .input("evcs1", MAXIMUM_HARDWARE_POWER, 11000) // + .input("evcs0", STATUS, Status.CHARGING) // + .input("evcs1", STATUS, Status.CHARGING)) // + .next(new TestCase() // + .output("evcsCluster0", MAXIMUM_POWER_TO_DISTRIBUTE, 32000) // + .output("evcs0", SET_CHARGE_POWER_LIMIT, 11000) // + .output("evcs1", SET_CHARGE_POWER_LIMIT, 11000)) // ; } @Test public void clusterDistribution_chargeTest_maximumPowerTest() throws Exception { - String[] evcsIds = { "evcs0", "evcs1" }; - new ComponentTest(new EvcsClusterPeakShavingImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // .addReference("sum", new DummySum()) // .addReference("addEvcs", EVCS0) // .addReference("addEvcs", EVCS1) // - .addReference("addEvcs", EVCS2) // - .addReference("addEvcs", EVCS3) // - .addReference("addEvcs", EVCS4) // .addReference("meter", METER) // .addReference("ess", ESS) // .activate(MyConfig.create() // - .setEssId(ESS.id()) // - .setMeterId(METER.id()) // + .setId("evcsCluster0") // + .setEssId("ess0") // + .setMeterId("meter0") // .setHardwarePowerLimit(HARDWARE_POWER_LIMIT_PER_PHASE) // - .setEvcsIds(evcsIds) // + .setEvcsIds("evcs0", "evcs1") // .build()) // .next(new TestCase() // - .input(EVCS0_CHARE_STATE, ChargeState.CHARGING) // - .input(SUM_ESS_ACTIVE_POWER, 0) // - .input(METER_GRID_ACTIVE_POWER, 0) // - .input(METER_GRID_ACTIVE_POWER_L1, 0) // - .input(METER_GRID_ACTIVE_POWER_L2, 0) // - .input(METER_GRID_ACTIVE_POWER_L3, 0) // - .input(ESS_ALLOWED_DISCHARGE_POWER, 0) // - .input(EVCS0_SET_POWER_REQUEST, 15000) // - .input(EVCS1_SET_POWER_REQUEST, 15000) // - .input(EVCS0_CHARGE_POWER, 0) // - .input(EVCS1_CHARGE_POWER, 0) // - .input(EVCS0_MAXIMUM_POWER, 5000) // - .input(EVCS1_MAXIMUM_POWER, 9000) // - .input(EVCS0_MAXIMUM_HARDWARE_POWER, 22000) // - .input(EVCS1_MAXIMUM_HARDWARE_POWER, 22000) // - .input(EVCS0_STATUS, Status.CHARGING) // - .input(EVCS1_STATUS, Status.CHARGING)) // - .next(new TestCase() // - .output(EVCS_CLUSTER_MAXIMUM_POWER_TO_DISTRIBUTE, 21000) // - .output(EVCS0_SET_CHARGE_POWER_LIMIT, 15000) // - .output(EVCS1_SET_CHARGE_POWER_LIMIT, 15000)) // + .input("evcs0", CHARGE_STATE, ChargeState.CHARGING) // + .input(ESS_ACTIVE_POWER, 0) // + .input("meter0", ACTIVE_POWER, 0) // + .input("meter0", ACTIVE_POWER_L1, 0) // + .input("meter0", ACTIVE_POWER_L2, 0) // + .input("meter0", ACTIVE_POWER_L3, 0) // + .input("ess0", ALLOWED_DISCHARGE_POWER, 0) // + .input("evcs0", SET_CHARGE_POWER_REQUEST, 15000) // + .input("evcs1", SET_CHARGE_POWER_REQUEST, 15000) // + .input("evcs0", ACTIVE_POWER, 0) // + .input("evcs1", ACTIVE_POWER, 0) // + .input("evcs0", MAXIMUM_POWER, 5000) // + .input("evcs1", MAXIMUM_POWER, 9000) // + .input("evcs0", MAXIMUM_HARDWARE_POWER, 22000) // + .input("evcs1", MAXIMUM_HARDWARE_POWER, 22000) // + .input("evcs0", STATUS, Status.CHARGING) // + .input("evcs1", STATUS, Status.CHARGING)) // + .next(new TestCase() // + .output("evcsCluster0", MAXIMUM_POWER_TO_DISTRIBUTE, 21000) // + .output("evcs0", SET_CHARGE_POWER_LIMIT, 15000) // + .output("evcs1", SET_CHARGE_POWER_LIMIT, 15000)) // ; } @Test public void clusterDistribution_chargeTest_minimumPowerTest() throws Exception { - String[] evcsIds = { "evcs0", "evcs1" }; - new ComponentTest(new EvcsClusterPeakShavingImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // .addReference("sum", new DummySum()) // .addReference("addEvcs", EVCS0) // .addReference("addEvcs", EVCS1) // - .addReference("addEvcs", EVCS2) // - .addReference("addEvcs", EVCS3) // - .addReference("addEvcs", EVCS4) // .addReference("meter", METER) // .addReference("ess", ESS) // .activate(MyConfig.create() // - .setEssId(ESS.id()) // - .setMeterId(METER.id()) // + .setId("evcsCluster0") // + .setEssId("ess0") // + .setMeterId("meter0") // .setHardwarePowerLimit(HARDWARE_POWER_LIMIT_PER_PHASE) // - .setEvcsIds(evcsIds) // + .setEvcsIds("evcs0", "evcs1") // .build()) // .next(new TestCase() // - .input(EVCS0_CHARE_STATE, ChargeState.CHARGING) // - .input(SUM_ESS_ACTIVE_POWER, 0) // - .input(METER_GRID_ACTIVE_POWER, 0) // - .input(METER_GRID_ACTIVE_POWER_L1, 0) // - .input(METER_GRID_ACTIVE_POWER_L2, 0) // - .input(METER_GRID_ACTIVE_POWER_L3, 0) // - .input(ESS_ALLOWED_DISCHARGE_POWER, 0) // - .input(EVCS0_SET_POWER_REQUEST, 15000) // - .input(EVCS1_SET_POWER_REQUEST, 15000) // - .input(EVCS0_CHARGE_POWER, 0) // - .input(EVCS1_CHARGE_POWER, 0) // - .input(EVCS0_MAXIMUM_POWER, 5000) // - .input(EVCS1_MAXIMUM_POWER, 9000) // - .input(EVCS0_MAXIMUM_HARDWARE_POWER, 22000) // - .input(EVCS1_MAXIMUM_HARDWARE_POWER, 22000) // - .input(EVCS0_MINIMUM_HARDWARE_POWER, 4500) // - .input(EVCS1_MINIMUM_HARDWARE_POWER, 4500) // - .input(EVCS0_STATUS, Status.READY_FOR_CHARGING) // - .input(EVCS1_STATUS, Status.READY_FOR_CHARGING)) // - .next(new TestCase() // - .output(EVCS_CLUSTER_MAXIMUM_POWER_TO_DISTRIBUTE, 21000) // - .output(EVCS0_SET_CHARGE_POWER_LIMIT, 4500) // - .output(EVCS1_SET_CHARGE_POWER_LIMIT, 4500)) // - .next(new TestCase() // - .input(EVCS0_MINIMUM_HARDWARE_POWER, 9000) // - .input(EVCS1_MINIMUM_HARDWARE_POWER, 6900) // - .output(EVCS0_SET_CHARGE_POWER_LIMIT, 9000) // - .output(EVCS1_SET_CHARGE_POWER_LIMIT, 6900)) // + .input("evcs0", CHARGE_STATE, ChargeState.CHARGING) // + .input(ESS_ACTIVE_POWER, 0) // + .input("meter0", ACTIVE_POWER, 0) // + .input("meter0", ACTIVE_POWER_L1, 0) // + .input("meter0", ACTIVE_POWER_L2, 0) // + .input("meter0", ACTIVE_POWER_L3, 0) // + .input("ess0", ALLOWED_DISCHARGE_POWER, 0) // + .input("evcs0", SET_CHARGE_POWER_REQUEST, 15000) // + .input("evcs1", SET_CHARGE_POWER_REQUEST, 15000) // + .input("evcs0", ACTIVE_POWER, 0) // + .input("evcs1", ACTIVE_POWER, 0) // + .input("evcs0", MAXIMUM_POWER, 5000) // + .input("evcs1", MAXIMUM_POWER, 9000) // + .input("evcs0", MAXIMUM_HARDWARE_POWER, 22000) // + .input("evcs1", MAXIMUM_HARDWARE_POWER, 22000) // + .input("evcs0", MINIMUM_HARDWARE_POWER, 4500) // + .input("evcs1", MINIMUM_HARDWARE_POWER, 4500) // + .input("evcs0", STATUS, Status.READY_FOR_CHARGING) // + .input("evcs1", STATUS, Status.READY_FOR_CHARGING)) // + .next(new TestCase() // + .output("evcsCluster0", MAXIMUM_POWER_TO_DISTRIBUTE, 21000) // + .output("evcs0", SET_CHARGE_POWER_LIMIT, 4500) // + .output("evcs1", SET_CHARGE_POWER_LIMIT, 4500)) // + .next(new TestCase() // + .input("evcs0", MINIMUM_HARDWARE_POWER, 9000) // + .input("evcs1", MINIMUM_HARDWARE_POWER, 6900) // + .output("evcs0", SET_CHARGE_POWER_LIMIT, 9000) // + .output("evcs1", SET_CHARGE_POWER_LIMIT, 6900)) // ; } @Test public void clusterDistribution_filterTest() throws Exception { - String[] evcsIds = { "evcs5" }; - - int initialPowerFromCluster = 4500; - new ComponentTest(new EvcsClusterPeakShavingImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // @@ -615,24 +526,25 @@ public void clusterDistribution_filterTest() throws Exception { .addReference("meter", METER) // .addReference("ess", ESS) // .activate(MyConfig.create() // - .setEssId(ESS.id()) // - .setMeterId(METER.id()) // + .setId("evcsCluster0") // + .setEssId("ess0") // + .setMeterId("meter0") // .setHardwarePowerLimit(HARDWARE_POWER_LIMIT_PER_PHASE) // - .setEvcsIds(evcsIds) // + .setEvcsIds("evcs5") // .build()) // .next(new TestCase() // - .input(SUM_ESS_ACTIVE_POWER, 0) // - .input(METER_GRID_ACTIVE_POWER, 0) // - .input(METER_GRID_ACTIVE_POWER_L1, 0) // - .input(METER_GRID_ACTIVE_POWER_L2, 0) // - .input(METER_GRID_ACTIVE_POWER_L3, 0) // - .input(ESS_ALLOWED_DISCHARGE_POWER, 0) // - .input(EVCS5_SET_POWER_REQUEST, 22000) // - .input(EVCS5_CHARGE_POWER, 0) // - .input(EVCS5_CHARGE_STATE, ChargeState.NOT_CHARGING) // - .input(EVCS5_MAXIMUM_HARDWARE_POWER, 22080) // - .input(EVCS5_STATUS, Status.READY_FOR_CHARGING) // - .input(EVCS_CLUSTER_STATUS, EvcsClusterStatus.REGULAR)) // + .input(ESS_ACTIVE_POWER, 0) // + .input("meter0", ACTIVE_POWER, 0) // + .input("meter0", ACTIVE_POWER_L1, 0) // + .input("meter0", ACTIVE_POWER_L2, 0) // + .input("meter0", ACTIVE_POWER_L3, 0) // + .input("ess0", ALLOWED_DISCHARGE_POWER, 0) // + .input("evcs5", SET_CHARGE_POWER_REQUEST, 22000) // + .input("evcs5", ACTIVE_POWER, 0) // + .input("evcs5", CHARGE_STATE, ChargeState.NOT_CHARGING) // + .input("evcs5", MAXIMUM_HARDWARE_POWER, 22080) // + .input("evcs5", STATUS, Status.READY_FOR_CHARGING) // + .input("evcsCluster0", EVCS_CLUSTER_STATUS, EvcsClusterStatus.REGULAR)) // .next(new TestCase() // // Cannot test charge states of evcs because the WriteHandler is not triggered // in a Cluster test. @@ -640,15 +552,13 @@ public void clusterDistribution_filterTest() throws Exception { // .output(evcs5ChargeState, ChargeState.INCREASING)) // // .output(evcs5ChargeState, ChargeState.INCREASING) // // .output(evcsClusterStatus, EvcsClusterStatus.INCREASING)) // - .output(EVCS_CLUSTER_MAXIMUM_POWER_TO_DISTRIBUTE, 21000) // - .output(EVCS5_SET_CHARGE_POWER_LIMIT, initialPowerFromCluster) // + .output("evcsCluster0", MAXIMUM_POWER_TO_DISTRIBUTE, 21000) // + .output("evcs5", SET_CHARGE_POWER_LIMIT, 4500) // ); } @Test public void clusterStatusTest() throws Exception { - String[] evcsIds = { "evcs0", "evcs1", "evcs2", "evcs3" }; - new ComponentTest(new EvcsClusterPeakShavingImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // @@ -657,50 +567,50 @@ public void clusterStatusTest() throws Exception { .addReference("addEvcs", EVCS1) // .addReference("addEvcs", EVCS2) // .addReference("addEvcs", EVCS3) // - .addReference("addEvcs", EVCS4) // .addReference("meter", METER) // .addReference("ess", ESS) // .activate(MyConfig.create() // - .setEssId(ESS.id()) // - .setMeterId(METER.id()) // + .setId("evcsCluster0") // + .setEssId("ess0") // + .setMeterId("meter0") // .setHardwarePowerLimit(HARDWARE_POWER_LIMIT_PER_PHASE) // - .setEvcsIds(evcsIds) // + .setEvcsIds("evcs0", "evcs1", "evcs2", "evcs3") // .build()) // .next(new TestCase() // - .input(EVCS0_CHARE_STATE, ChargeState.UNDEFINED) // - .input(EVCS1_CHARGE_STATE, ChargeState.UNDEFINED) // - .input(EVCS2_CHARGE_STATE, ChargeState.UNDEFINED) // - .input(EVCS3_CHARGE_STATE, ChargeState.UNDEFINED)) // + .input("evcs0", CHARGE_STATE, ChargeState.UNDEFINED) // + .input("evcs1", CHARGE_STATE, ChargeState.UNDEFINED) // + .input("evcs2", CHARGE_STATE, ChargeState.UNDEFINED) // + .input("evcs3", CHARGE_STATE, ChargeState.UNDEFINED)) // .next(new TestCase() // - .output(EVCS_CLUSTER_STATUS, EvcsClusterStatus.UNDEFINED)) // + .output("evcsCluster0", EVCS_CLUSTER_STATUS, EvcsClusterStatus.UNDEFINED)) // .next(new TestCase() // - .input(EVCS0_CHARE_STATE, ChargeState.INCREASING) // - .input(EVCS1_CHARGE_STATE, ChargeState.UNDEFINED) // - .input(EVCS2_CHARGE_STATE, ChargeState.UNDEFINED) // - .input(EVCS3_CHARGE_STATE, ChargeState.UNDEFINED)) // + .input("evcs0", CHARGE_STATE, ChargeState.INCREASING) // + .input("evcs1", CHARGE_STATE, ChargeState.UNDEFINED) // + .input("evcs2", CHARGE_STATE, ChargeState.UNDEFINED) // + .input("evcs3", CHARGE_STATE, ChargeState.UNDEFINED)) // .next(new TestCase() // - .output(EVCS_CLUSTER_STATUS, EvcsClusterStatus.INCREASING)) // + .output("evcsCluster0", EVCS_CLUSTER_STATUS, EvcsClusterStatus.INCREASING)) // .next(new TestCase() // - .input(EVCS0_CHARE_STATE, ChargeState.CHARGING) // - .input(EVCS1_CHARGE_STATE, ChargeState.UNDEFINED) // - .input(EVCS2_CHARGE_STATE, ChargeState.UNDEFINED) // - .input(EVCS3_CHARGE_STATE, ChargeState.UNDEFINED)) // + .input("evcs0", CHARGE_STATE, ChargeState.CHARGING) // + .input("evcs1", CHARGE_STATE, ChargeState.UNDEFINED) // + .input("evcs2", CHARGE_STATE, ChargeState.UNDEFINED) // + .input("evcs3", CHARGE_STATE, ChargeState.UNDEFINED)) // .next(new TestCase() // - .output(EVCS_CLUSTER_STATUS, EvcsClusterStatus.REGULAR)) // + .output("evcsCluster0", EVCS_CLUSTER_STATUS, EvcsClusterStatus.REGULAR)) // .next(new TestCase() // - .input(EVCS0_CHARE_STATE, ChargeState.CHARGING) // - .input(EVCS1_CHARGE_STATE, ChargeState.DECREASING) // - .input(EVCS2_CHARGE_STATE, ChargeState.INCREASING) // - .input(EVCS3_CHARGE_STATE, ChargeState.UNDEFINED)) // + .input("evcs0", CHARGE_STATE, ChargeState.CHARGING) // + .input("evcs1", CHARGE_STATE, ChargeState.DECREASING) // + .input("evcs2", CHARGE_STATE, ChargeState.INCREASING) // + .input("evcs3", CHARGE_STATE, ChargeState.UNDEFINED)) // .next(new TestCase() // - .output(EVCS_CLUSTER_STATUS, EvcsClusterStatus.DECREASING)) // + .output("evcsCluster0", EVCS_CLUSTER_STATUS, EvcsClusterStatus.DECREASING)) // .next(new TestCase() // - .input(EVCS0_CHARE_STATE, ChargeState.CHARGING) // - .input(EVCS1_CHARGE_STATE, ChargeState.CHARGING) // - .input(EVCS2_CHARGE_STATE, ChargeState.CHARGING) // - .input(EVCS3_CHARGE_STATE, ChargeState.CHARGING)) // + .input("evcs0", CHARGE_STATE, ChargeState.CHARGING) // + .input("evcs1", CHARGE_STATE, ChargeState.CHARGING) // + .input("evcs2", CHARGE_STATE, ChargeState.CHARGING) // + .input("evcs3", CHARGE_STATE, ChargeState.CHARGING)) // .next(new TestCase() // - .output(EVCS_CLUSTER_STATUS, EvcsClusterStatus.REGULAR)) // + .output("evcsCluster0", EVCS_CLUSTER_STATUS, EvcsClusterStatus.REGULAR)) // ; } } diff --git a/io.openems.edge.evcs.cluster/test/io/openems/edge/evcs/cluster/MyConfig.java b/io.openems.edge.evcs.cluster/test/io/openems/edge/evcs/cluster/MyConfig.java index 8abf3801d3b..3185f98a2ae 100644 --- a/io.openems.edge.evcs.cluster/test/io/openems/edge/evcs/cluster/MyConfig.java +++ b/io.openems.edge.evcs.cluster/test/io/openems/edge/evcs/cluster/MyConfig.java @@ -8,12 +8,12 @@ public class MyConfig extends AbstractComponentConfig implements Config { protected static class Builder { - private String id = "evcsCluster0"; - private boolean debugMode = false; - private int hardwarePowerLimitPerPhase = 7000; - private String[] evcsIds = { "evcs0", "evcs1" }; - private String essId = "ess0"; - private String meterId = "meter0"; + private String id; + private boolean debugMode; + private int hardwarePowerLimitPerPhase; + private String[] evcsIds; + private String essId; + private String meterId; private Builder() { } @@ -33,7 +33,7 @@ public Builder setHardwarePowerLimit(int hardwarePowerLimitPerPhase) { return this; } - public Builder setEvcsIds(String[] evcsIds) { + public Builder setEvcsIds(String... evcsIds) { this.evcsIds = evcsIds; return this; } diff --git a/io.openems.edge.evcs.dezony/bnd.bnd b/io.openems.edge.evcs.dezony/bnd.bnd index a0816a90967..53163b7f5a4 100644 --- a/io.openems.edge.evcs.dezony/bnd.bnd +++ b/io.openems.edge.evcs.dezony/bnd.bnd @@ -7,7 +7,8 @@ Bundle-Version: 1.0.0.${tstamp} ${buildpath},\ io.openems.common,\ io.openems.edge.common,\ - io.openems.edge.evcs.api + io.openems.edge.evcs.api,\ + io.openems.edge.meter.api,\ -testpath: \ ${testpath} diff --git a/io.openems.edge.evcs.dezony/src/io/openems/edge/evcs/dezony/DezonyReadWorker.java b/io.openems.edge.evcs.dezony/src/io/openems/edge/evcs/dezony/DezonyReadWorker.java index e148b80e681..176c289f0a5 100644 --- a/io.openems.edge.evcs.dezony/src/io/openems/edge/evcs/dezony/DezonyReadWorker.java +++ b/io.openems.edge.evcs.dezony/src/io/openems/edge/evcs/dezony/DezonyReadWorker.java @@ -1,5 +1,16 @@ package io.openems.edge.evcs.dezony; +import static io.openems.common.types.OpenemsType.DOUBLE; +import static io.openems.common.types.OpenemsType.STRING; +import static io.openems.common.utils.JsonUtils.getAsDouble; +import static io.openems.common.utils.JsonUtils.getAsFloat; +import static io.openems.common.utils.JsonUtils.getAsInt; +import static io.openems.common.utils.JsonUtils.getAsJsonObject; +import static io.openems.common.utils.JsonUtils.getAsLong; +import static io.openems.common.utils.JsonUtils.getAsShort; +import static io.openems.common.utils.JsonUtils.getAsString; +import static io.openems.edge.evcs.api.Phases.THREE_PHASE; + import java.util.Map; import java.util.function.Function; @@ -13,7 +24,6 @@ import io.openems.edge.common.channel.ChannelId; import io.openems.edge.common.type.TypeUtils; import io.openems.edge.evcs.api.Evcs; -import io.openems.edge.evcs.api.Phases; import io.openems.edge.evcs.api.Status; public class DezonyReadWorker extends AbstractCycleWorker { @@ -54,29 +64,28 @@ protected void forever() throws OpenemsNamedException { * @param json Given raw data in JSON */ private void setEvcsChannelIds(JsonElement json) { - final var activeConsumptionEnergyArray = this.getArrayFromJson(json, "currDataPoint"); + final var energyArray = getArrayFromJson(json, "currDataPoint"); - this.parent._setActiveConsumptionEnergy(this.getValueByKey(activeConsumptionEnergyArray, "etotal")); - this.parent._setChargePower(this.getValueByKey(activeConsumptionEnergyArray, "ptotal")); - this.parent._setSetChargePowerLimit(this.getValueByKey(activeConsumptionEnergyArray, "curlhm") - * Phases.THREE_PHASE.getValue() * Evcs.DEFAULT_VOLTAGE); - this.parent._setPhases(this.calculatePhases(activeConsumptionEnergyArray)); + this.parent._setActiveProductionEnergy(getValueByKey(energyArray, "etotal")); + this.parent._setActivePower(getValueByKey(energyArray, "ptotal")); + this.parent._setSetChargePowerLimit( + getValueByKey(energyArray, "curlhm") * THREE_PHASE.getValue() * Evcs.DEFAULT_VOLTAGE); + this.parent._setPhases(this.calculatePhases(energyArray)); this.parent._setStatus(this.getStatus(json)); } private void setEnergySession(JsonElement json) { - final var energy = (Double) this.getValueFromJson(Evcs.ChannelId.ENERGY_SESSION, OpenemsType.DOUBLE, json, - value -> { - return value; - }, "metric", "energy"); + final var energy = (Double) getValueFromJson(Evcs.ChannelId.ENERGY_SESSION, DOUBLE, json, value -> { + return value; + }, "metric", "energy"); this.parent._setEnergySession(energy == null ? null : (int) Math.round(energy)); } private Status getStatus(JsonElement json) { - final var rawChargeStatus = (String) this.getValueFromJson(EvcsDezony.ChannelId.RAW_CHARGE_STATUS_CHARGEPOINT, - json, value -> { - final String state = TypeUtils.getAsType(OpenemsType.STRING, value); + final var rawChargeStatus = (String) getValueFromJson(EvcsDezony.ChannelId.RAW_CHARGE_STATUS_CHARGEPOINT, json, + value -> { + final String state = TypeUtils.getAsType(STRING, value); return state == null ? "" : state; }, "state"); @@ -104,10 +113,10 @@ private Status getStatus(JsonElement json) { return status; } - private Integer calculatePhases(JsonArray activeConsumptionEnergyArray) { - final var powerL1 = this.getValueByKey(activeConsumptionEnergyArray, "currl1") * Evcs.DEFAULT_VOLTAGE; - final var powerL2 = this.getValueByKey(activeConsumptionEnergyArray, "currl2") * Evcs.DEFAULT_VOLTAGE; - final var powerL3 = this.getValueByKey(activeConsumptionEnergyArray, "currl3") * Evcs.DEFAULT_VOLTAGE; + private Integer calculatePhases(JsonArray energyArray) { + final var powerL1 = getValueByKey(energyArray, "currl1") * Evcs.DEFAULT_VOLTAGE; + final var powerL2 = getValueByKey(energyArray, "currl2") * Evcs.DEFAULT_VOLTAGE; + final var powerL3 = getValueByKey(energyArray, "currl3") * Evcs.DEFAULT_VOLTAGE; final int maxPower = 900; final int minPower = 300; @@ -138,9 +147,9 @@ private Integer calculatePhases(JsonArray activeConsumptionEnergyArray) { return phases; } - private int getValueByKey(JsonArray activeConsumptionEnergyArray, String searchKey) { - for (var i = 0; i < activeConsumptionEnergyArray.size(); ++i) { - final var object = activeConsumptionEnergyArray.get(i).getAsJsonObject(); + private static int getValueByKey(JsonArray energyArray, String searchKey) { + for (var i = 0; i < energyArray.size(); ++i) { + final var object = energyArray.get(i).getAsJsonObject(); final var key = object.get("short"); if (key.getAsString().equals(searchKey)) { @@ -165,9 +174,9 @@ private int getValueByKey(JsonArray activeConsumptionEnergyArray, String searchK * @return Value of the last JsonElement by running through the specified JSON * path. */ - private Object getValueFromJson(ChannelId channelId, JsonElement json, Function converter, + private static Object getValueFromJson(ChannelId channelId, JsonElement json, Function converter, String... jsonPaths) { - return this.getValueFromJson(channelId, null, json, converter, jsonPaths); + return getValueFromJson(channelId, null, json, converter, jsonPaths); } /** @@ -185,7 +194,7 @@ private Object getValueFromJson(ChannelId channelId, JsonElement json, Function< * @return Value of the last JsonElement by running through the specified JSON * path. */ - private Object getValueFromJson(ChannelId channelId, OpenemsType divergentTypeInRawJson, JsonElement json, + private static Object getValueFromJson(ChannelId channelId, OpenemsType divergentTypeInRawJson, JsonElement json, Function converter, String... jsonPaths) { var currentJsonElement = json; // Go through the whole jsonPath of the current channelId @@ -198,13 +207,13 @@ private Object getValueFromJson(ChannelId channelId, OpenemsType divergentTypeIn : divergentTypeInRawJson; // Last path element - var value = this.getJsonElementValue(currentJsonElement, openemsType, jsonPaths[i]); + var value = getJsonElementValue(currentJsonElement, openemsType, jsonPaths[i]); // Return the converted value return converter.apply(value); } // Not last path element - currentJsonElement = JsonUtils.getAsJsonObject(currentJsonElement, currentPathMember); + currentJsonElement = getAsJsonObject(currentJsonElement, currentPathMember); } catch (OpenemsNamedException e) { return null; } @@ -212,7 +221,7 @@ private Object getValueFromJson(ChannelId channelId, OpenemsType divergentTypeIn return null; } - private JsonArray getArrayFromJson(JsonElement json, String... jsonPaths) { + private static JsonArray getArrayFromJson(JsonElement json, String... jsonPaths) { var currentJsonElement = json; // Go through the whole jsonPath of the current channelId for (var i = 0; i < jsonPaths.length; i++) { @@ -222,7 +231,7 @@ private JsonArray getArrayFromJson(JsonElement json, String... jsonPaths) { return JsonUtils.getAsJsonArray(currentJsonElement, jsonPaths[i]); } // Not last path element - currentJsonElement = JsonUtils.getAsJsonObject(currentJsonElement, currentPathMember); + currentJsonElement = getAsJsonObject(currentJsonElement, currentPathMember); } catch (OpenemsNamedException e) { return null; } @@ -239,23 +248,17 @@ private JsonArray getArrayFromJson(JsonElement json, String... jsonPaths) { * @return Value in the required type. * @throws OpenemsNamedException Failed to get the value. */ - private Object getJsonElementValue(JsonElement jsonElement, OpenemsType openemsType, String memberName) + private static Object getJsonElementValue(JsonElement jsonElement, OpenemsType openemsType, String memberName) throws OpenemsNamedException { + // NOTE: could have used JsonUtils.getAsType() return switch (openemsType) { - case BOOLEAN: - yield JsonUtils.getAsInt(jsonElement, memberName) == 1; - case DOUBLE: - yield JsonUtils.getAsDouble(jsonElement, memberName); - case FLOAT: - yield JsonUtils.getAsFloat(jsonElement, memberName); - case INTEGER: - yield JsonUtils.getAsInt(jsonElement, memberName); - case LONG: - yield JsonUtils.getAsLong(jsonElement, memberName); - case SHORT: - yield JsonUtils.getAsShort(jsonElement, memberName); - case STRING: - yield JsonUtils.getAsString(jsonElement, memberName); + case BOOLEAN -> getAsInt(jsonElement, memberName) == 1; + case DOUBLE -> getAsDouble(jsonElement, memberName); + case FLOAT -> getAsFloat(jsonElement, memberName); + case INTEGER -> getAsInt(jsonElement, memberName); + case LONG -> getAsLong(jsonElement, memberName); + case SHORT -> getAsShort(jsonElement, memberName); + case STRING -> getAsString(jsonElement, memberName); }; } } diff --git a/io.openems.edge.evcs.dezony/src/io/openems/edge/evcs/dezony/EvcsDezonyImpl.java b/io.openems.edge.evcs.dezony/src/io/openems/edge/evcs/dezony/EvcsDezonyImpl.java index e26fb8a168d..8aa67bfb7cf 100644 --- a/io.openems.edge.evcs.dezony/src/io/openems/edge/evcs/dezony/EvcsDezonyImpl.java +++ b/io.openems.edge.evcs.dezony/src/io/openems/edge/evcs/dezony/EvcsDezonyImpl.java @@ -1,5 +1,8 @@ package io.openems.edge.evcs.dezony; +import static io.openems.edge.evcs.api.ChargingType.AC; +import static io.openems.edge.evcs.api.Phases.THREE_PHASE; + import org.osgi.service.component.ComponentContext; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; @@ -18,11 +21,10 @@ import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.event.EdgeEventConstants; import io.openems.edge.evcs.api.AbstractManagedEvcsComponent; -import io.openems.edge.evcs.api.ChargingType; import io.openems.edge.evcs.api.Evcs; import io.openems.edge.evcs.api.EvcsPower; import io.openems.edge.evcs.api.ManagedEvcs; -import io.openems.edge.evcs.api.Phases; +import io.openems.edge.meter.api.ElectricityMeter; @Designate(ocd = Config.class, factory = true) @Component(// @@ -35,7 +37,7 @@ EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE, // }) public class EvcsDezonyImpl extends AbstractManagedEvcsComponent - implements OpenemsComponent, EventHandler, EvcsDezony, Evcs, ManagedEvcs { + implements OpenemsComponent, EventHandler, EvcsDezony, Evcs, ManagedEvcs, ElectricityMeter { private final Logger log = LoggerFactory.getLogger(EvcsDezonyImpl.class); private final DezonyReadWorker readWorker = new DezonyReadWorker(this); @@ -48,7 +50,11 @@ public class EvcsDezonyImpl extends AbstractManagedEvcsComponent protected boolean masterEvcs = true; public EvcsDezonyImpl() { - super(OpenemsComponent.ChannelId.values(), Evcs.ChannelId.values(), ManagedEvcs.ChannelId.values(), + super(// + OpenemsComponent.ChannelId.values(), // + ElectricityMeter.ChannelId.values(), // + Evcs.ChannelId.values(), // + ManagedEvcs.ChannelId.values(), // EvcsDezony.ChannelId.values()); } @@ -57,11 +63,9 @@ private void activate(ComponentContext context, Config config) { super.activate(context, config.id(), config.alias(), config.enabled()); this.config = config; - this._setChargingType(ChargingType.AC); - this._setFixedMinimumHardwarePower( - config.minHwCurrent() / 1000 * DEFAULT_VOLTAGE * Phases.THREE_PHASE.getValue()); - this._setFixedMaximumHardwarePower( - config.maxHwCurrent() / 1000 * DEFAULT_VOLTAGE * Phases.THREE_PHASE.getValue()); + this._setChargingType(AC); + this._setFixedMinimumHardwarePower(config.minHwCurrent() / 1000 * DEFAULT_VOLTAGE * THREE_PHASE.getValue()); + this._setFixedMaximumHardwarePower(config.maxHwCurrent() / 1000 * DEFAULT_VOLTAGE * THREE_PHASE.getValue()); this._setPowerPrecision(230); if (config.enabled()) { @@ -158,12 +162,12 @@ public int getMinimumTimeTillChargingLimitTaken() { @Override public int getConfiguredMinimumHardwarePower() { - return Math.round(this.config.minHwCurrent() / 1000f) * DEFAULT_VOLTAGE * Phases.THREE_PHASE.getValue(); + return Math.round(this.config.minHwCurrent() / 1000f) * DEFAULT_VOLTAGE * THREE_PHASE.getValue(); } @Override public int getConfiguredMaximumHardwarePower() { - return Math.round(this.config.maxHwCurrent() / 1000f) * DEFAULT_VOLTAGE * Phases.THREE_PHASE.getValue(); + return Math.round(this.config.maxHwCurrent() / 1000f) * DEFAULT_VOLTAGE * THREE_PHASE.getValue(); } @Override diff --git a/io.openems.edge.evcs.dezony/test/io/openems/edge/evcs/dezony/EvcsDezonyImplTest.java b/io.openems.edge.evcs.dezony/test/io/openems/edge/evcs/dezony/EvcsDezonyImplTest.java index 562d5b84ac9..ec51fd21e79 100644 --- a/io.openems.edge.evcs.dezony/test/io/openems/edge/evcs/dezony/EvcsDezonyImplTest.java +++ b/io.openems.edge.evcs.dezony/test/io/openems/edge/evcs/dezony/EvcsDezonyImplTest.java @@ -7,13 +7,11 @@ public class EvcsDezonyImplTest { - private static final String COMPONENT_ID = "evcs0"; - @Test public void test() throws Exception { new ComponentTest(new EvcsDezonyImpl()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // + .setId("evcs0") // .setIp("192.168.50.88") // .setPort(5000) // .setMaxHwCurrent(32) // diff --git a/io.openems.edge.evcs.goe.chargerhome/bnd.bnd b/io.openems.edge.evcs.goe.chargerhome/bnd.bnd index 80e3fed5106..f78d7569e6f 100644 --- a/io.openems.edge.evcs.goe.chargerhome/bnd.bnd +++ b/io.openems.edge.evcs.goe.chargerhome/bnd.bnd @@ -7,7 +7,8 @@ Bundle-Version: 1.0.0.${tstamp} ${buildpath},\ io.openems.common,\ io.openems.edge.common,\ - io.openems.edge.evcs.api + io.openems.edge.evcs.api,\ + io.openems.edge.meter.api,\ -testpath: \ ${testpath} diff --git a/io.openems.edge.evcs.goe.chargerhome/src/io/openems/edge/evcs/goe/chargerhome/EvcsGoeChargerHome.java b/io.openems.edge.evcs.goe.chargerhome/src/io/openems/edge/evcs/goe/chargerhome/EvcsGoeChargerHome.java index 1b07248a7d4..4bfc3aabe2c 100644 --- a/io.openems.edge.evcs.goe.chargerhome/src/io/openems/edge/evcs/goe/chargerhome/EvcsGoeChargerHome.java +++ b/io.openems.edge.evcs.goe.chargerhome/src/io/openems/edge/evcs/goe/chargerhome/EvcsGoeChargerHome.java @@ -10,8 +10,9 @@ import io.openems.edge.evcs.api.Evcs; import io.openems.edge.evcs.api.ManagedEvcs; import io.openems.edge.evcs.api.Status; +import io.openems.edge.meter.api.ElectricityMeter; -public interface EvcsGoeChargerHome extends ManagedEvcs, Evcs, OpenemsComponent, EventHandler { +public interface EvcsGoeChargerHome extends ManagedEvcs, Evcs, ElectricityMeter, OpenemsComponent, EventHandler { public enum ChannelId implements io.openems.edge.common.channel.ChannelId { ALIAS(Doc.of(OpenemsType.STRING).text("A human-readable name of this Component")), @@ -21,13 +22,6 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { STATUS_GOE(Doc.of(Status.values()).text("Current state of the charging station")), ERROR(Doc.of(Errors.values()).text("")), CURR_USER(Doc.of(OpenemsType.INTEGER).unit(Unit.MILLIAMPERE).text("Current preset value of the user")), - VOLTAGE_L1(Doc.of(OpenemsType.INTEGER).unit(Unit.VOLT).text("Voltage on L1")), - VOLTAGE_L2(Doc.of(OpenemsType.INTEGER).unit(Unit.VOLT).text("Voltage on L2")), - VOLTAGE_L3(Doc.of(OpenemsType.INTEGER).unit(Unit.VOLT).text("Voltage on L3")), - CURRENT_L1(Doc.of(OpenemsType.INTEGER).unit(Unit.MILLIAMPERE).text("Current on L1")), - CURRENT_L2(Doc.of(OpenemsType.INTEGER).unit(Unit.MILLIAMPERE).text("Current on L2")), - CURRENT_L3(Doc.of(OpenemsType.INTEGER).unit(Unit.MILLIAMPERE).text("Current on L3")), - ACTUAL_POWER(Doc.of(OpenemsType.INTEGER).unit(Unit.MILLIWATT).text("Total real power")), ENERGY_TOTAL(Doc.of(OpenemsType.INTEGER).unit(Unit.CUMULATED_WATT_HOURS).text("Total power consumption")), CHARGINGSTATION_STATE_ERROR(Doc.of(Level.WARNING)); diff --git a/io.openems.edge.evcs.goe.chargerhome/src/io/openems/edge/evcs/goe/chargerhome/EvcsGoeChargerHomeImpl.java b/io.openems.edge.evcs.goe.chargerhome/src/io/openems/edge/evcs/goe/chargerhome/EvcsGoeChargerHomeImpl.java index 7e81a9fb3c8..c565c0cf558 100644 --- a/io.openems.edge.evcs.goe.chargerhome/src/io/openems/edge/evcs/goe/chargerhome/EvcsGoeChargerHomeImpl.java +++ b/io.openems.edge.evcs.goe.chargerhome/src/io/openems/edge/evcs/goe/chargerhome/EvcsGoeChargerHomeImpl.java @@ -27,6 +27,7 @@ import io.openems.edge.evcs.api.ManagedEvcs; import io.openems.edge.evcs.api.Phases; import io.openems.edge.evcs.api.Status; +import io.openems.edge.meter.api.ElectricityMeter; @Designate(ocd = Config.class, factory = true) @Component(// @@ -62,6 +63,7 @@ public class EvcsGoeChargerHomeImpl extends AbstractManagedEvcsComponent public EvcsGoeChargerHomeImpl() { super(// OpenemsComponent.ChannelId.values(), // + ElectricityMeter.ChannelId.values(), // ManagedEvcs.ChannelId.values(), // Evcs.ChannelId.values(), // EvcsGoeChargerHome.ChannelId.values() // @@ -128,18 +130,15 @@ public void handleEvent(Event event) { this.channel(EvcsGoeChargerHome.ChannelId.CURR_USER).setNextValue(this.activeCurrent); var nrg = JsonUtils.getAsJsonArray(json, "nrg"); - this.channel(EvcsGoeChargerHome.ChannelId.VOLTAGE_L1).setNextValue(JsonUtils.getAsInt(nrg, 0)); - this.channel(EvcsGoeChargerHome.ChannelId.VOLTAGE_L2).setNextValue(JsonUtils.getAsInt(nrg, 1)); - this.channel(EvcsGoeChargerHome.ChannelId.VOLTAGE_L3).setNextValue(JsonUtils.getAsInt(nrg, 2)); - this.channel(EvcsGoeChargerHome.ChannelId.CURRENT_L1) - .setNextValue(JsonUtils.getAsInt(nrg, 4) * 100); - this.channel(EvcsGoeChargerHome.ChannelId.CURRENT_L2) - .setNextValue(JsonUtils.getAsInt(nrg, 5) * 100); - this.channel(EvcsGoeChargerHome.ChannelId.CURRENT_L3) - .setNextValue(JsonUtils.getAsInt(nrg, 6) * 100); + this._setVoltageL1(JsonUtils.getAsInt(nrg, 0)); + this._setVoltageL2(JsonUtils.getAsInt(nrg, 1)); + this._setVoltageL3(JsonUtils.getAsInt(nrg, 2)); + this._setCurrentL1(JsonUtils.getAsInt(nrg, 4) * 100); + this._setCurrentL2(JsonUtils.getAsInt(nrg, 5) * 100); + this._setCurrentL3(JsonUtils.getAsInt(nrg, 6) * 100); var power = JsonUtils.getAsInt(nrg, 11); - this.channel(EvcsGoeChargerHome.ChannelId.ACTUAL_POWER).setNextValue(power * 10); - this.channel(Evcs.ChannelId.CHARGE_POWER).setNextValue(power * 10); + // TODO set ActivePowerL1/L2/L3 of ElectricityMeter + this._setActivePower(power * 10); // Hardware limits var cableCurrent = JsonUtils.getAsInt(json, "cbl") * 1000; @@ -157,6 +156,7 @@ public void handleEvent(Event event) { this._setPhases(phases); // Energy + // TODO set ActiveProductionEnergy this.channel(EvcsGoeChargerHome.ChannelId.ENERGY_TOTAL) .setNextValue(JsonUtils.getAsInt(json, "eto") * 100); this.channel(Evcs.ChannelId.ENERGY_SESSION) @@ -177,18 +177,13 @@ public void handleEvent(Event event) { } private Status convertGoeStatus(int status) { - switch (status) { - case 1: // ready for charging, car unplugged - return Status.NOT_READY_FOR_CHARGING; - case 2: // charging - return Status.CHARGING; - case 3: // waiting for car - return Status.READY_FOR_CHARGING; - case 4: // charging finished, car plugged - return Status.CHARGING_FINISHED; - default: - return Status.UNDEFINED; - } + return switch (status) { + case 1 -> Status.NOT_READY_FOR_CHARGING; // ready for charging, car unplugged + case 2 -> Status.CHARGING; // charging + case 3 -> Status.READY_FOR_CHARGING; // waiting for car + case 4 -> Status.CHARGING_FINISHED; // charging finished, car plugged + default -> Status.UNDEFINED; + }; } /** @@ -198,17 +193,12 @@ private Status convertGoeStatus(int status) { * @return amount of phases */ private int convertGoePhase(int phase) { - var phasen = (byte) phase & 0b00111000; - switch (phasen) { - case 8: // 0b00001000: Phase 1 is active - return 1; - case 24: // 0b00011000: Phase 1+2 is active - return 2; - case 56: // 0b00111000: Phase1-3 are active - return 3; - default: - return 0; - } + return switch ((byte) phase & 0b00111000) { + case 8 -> 1; // 0b00001000: Phase 1 is active + case 24 -> 2; // 0b00011000: Phase 1+2 is active + case 56 -> 3; // 0b00111000: Phase1-3 are active + default -> 0; // TODO illegal value! + }; } /** diff --git a/io.openems.edge.evcs.goe.chargerhome/test/io/openems/edge/evcs/goe/chargerhome/EvcsGoeChargerHomeImplTest.java b/io.openems.edge.evcs.goe.chargerhome/test/io/openems/edge/evcs/goe/chargerhome/EvcsGoeChargerHomeImplTest.java index ab8cbb6fd48..6ccf8f42662 100644 --- a/io.openems.edge.evcs.goe.chargerhome/test/io/openems/edge/evcs/goe/chargerhome/EvcsGoeChargerHomeImplTest.java +++ b/io.openems.edge.evcs.goe.chargerhome/test/io/openems/edge/evcs/goe/chargerhome/EvcsGoeChargerHomeImplTest.java @@ -6,13 +6,11 @@ public class EvcsGoeChargerHomeImplTest { - private static final String COMPONENT_ID = "evcs0"; - @Test public void test() throws Exception { new ComponentTest(new EvcsGoeChargerHomeImpl()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // + .setId("evcs0") // .setIp("192.168.50.88") // .setMaxHwCurrent(32) // .setMinHwCurrent(6) // diff --git a/io.openems.edge.evcs.hardybarth/bnd.bnd b/io.openems.edge.evcs.hardybarth/bnd.bnd index c7861a683c4..060569c9b40 100644 --- a/io.openems.edge.evcs.hardybarth/bnd.bnd +++ b/io.openems.edge.evcs.hardybarth/bnd.bnd @@ -6,8 +6,10 @@ Bundle-Version: 1.0.0.${tstamp} -buildpath: \ ${buildpath},\ io.openems.common,\ + io.openems.edge.bridge.http,\ io.openems.edge.common,\ - io.openems.edge.evcs.api + io.openems.edge.evcs.api,\ + io.openems.edge.meter.api,\ -testpath: \ ${testpath} diff --git a/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/Config.java b/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/Config.java index 86633930c91..33465046fca 100644 --- a/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/Config.java +++ b/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/Config.java @@ -3,6 +3,8 @@ import org.osgi.service.metatype.annotations.AttributeDefinition; import org.osgi.service.metatype.annotations.ObjectClassDefinition; +import io.openems.edge.evcs.api.PhaseRotation; + @ObjectClassDefinition(// name = "EVCS Hardy Barth", // description = "Implements the Hardy Barth - Salia electric vehicle charging station.") @@ -29,6 +31,9 @@ @AttributeDefinition(name = "Maximum hardware current", description = "Maximum current of the Charger in mA.", required = true) int maxHwCurrent() default 32000; + @AttributeDefinition(name = "Phase Rotation", description = "Apply standard or rotated wiring") + PhaseRotation phaseRotation() default PhaseRotation.L1_L2_L3; + String webconsole_configurationFactory_nameHint() default "EVCS Hardy Barth [{id}]"; } \ No newline at end of file diff --git a/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/EvcsHardyBarth.java b/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/EvcsHardyBarth.java index 60b9b2b7623..ad3cba3b5ac 100644 --- a/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/EvcsHardyBarth.java +++ b/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/EvcsHardyBarth.java @@ -1,31 +1,41 @@ package io.openems.edge.evcs.hardybarth; +import static io.openems.common.channel.Level.WARNING; +import static io.openems.common.channel.Unit.AMPERE; +import static io.openems.common.channel.Unit.CUMULATED_WATT_HOURS; +import static io.openems.common.types.OpenemsType.BOOLEAN; +import static io.openems.common.types.OpenemsType.DOUBLE; +import static io.openems.common.types.OpenemsType.INTEGER; +import static io.openems.common.types.OpenemsType.LONG; +import static io.openems.common.types.OpenemsType.STRING; + import java.util.function.Function; -import io.openems.common.channel.Level; -import io.openems.common.channel.Unit; -import io.openems.common.types.OpenemsType; import io.openems.edge.common.channel.BooleanDoc; import io.openems.edge.common.channel.Doc; -import io.openems.edge.common.type.TypeUtils; public interface EvcsHardyBarth { - public static final double SCALE_FACTOR_MINUS_1 = 0.1; + public static final float SCALE_FACTOR_MINUS_1 = 0.1F; public enum ChannelId implements io.openems.edge.common.channel.ChannelId { // TODO: Correct Type & Unit (Waiting for Manufacturer instructions) // EVSE - RAW_EVSE_GRID_CURRENT_LIMIT(Doc.of(OpenemsType.INTEGER).unit(Unit.AMPERE), "secc", "port0", "ci", "evse", // - "basic", "grid_current_limit", "actual"), // - RAW_PHASE_COUNT(Doc.of(OpenemsType.INTEGER), "secc", "port0", "ci", "evse", "basic", "phase_count"), // + RAW_EVSE_GRID_CURRENT_LIMIT(Doc.of(INTEGER) // + .unit(AMPERE), // + "secc", "port0", "ci", "evse", "basic", "grid_current_limit", "actual"), // + RAW_PHASE_COUNT(Doc.of(INTEGER), // + "secc", "port0", "ci", "evse", "basic", "phase_count"), // // CHARGE - RAW_CHARGE_STATUS_PLUG(Doc.of(OpenemsType.STRING), "secc", "port0", "ci", "charge", "plug", "status"), // - RAW_CHARGE_STATUS_CONTACTOR(Doc.of(OpenemsType.STRING), "secc", "port0", "ci", "charge", "contactor", "status"), // - RAW_CHARGE_STATUS_PWM(Doc.of(OpenemsType.STRING), "secc", "port0", "ci", "charge", "pwm", "status"), // + RAW_CHARGE_STATUS_PLUG(Doc.of(STRING), // + "secc", "port0", "ci", "charge", "plug", "status"), // + RAW_CHARGE_STATUS_CONTACTOR(Doc.of(STRING), // + "secc", "port0", "ci", "charge", "contactor", "status"), // + RAW_CHARGE_STATUS_PWM(Doc.of(STRING), // + "secc", "port0", "ci", "charge", "pwm", "status"), // /** * States of the Hardy Barth. * @@ -39,122 +49,141 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { *

    36. F = Failure * */ - RAW_CHARGE_STATUS_CHARGEPOINT(Doc.of(OpenemsType.STRING), "secc", "port0", "ci", "charge", "cp", "status"), // + RAW_CHARGE_STATUS_CHARGEPOINT(Doc.of(STRING), // + "secc", "port0", "ci", "charge", "cp", "status"), // // SALIA - RAW_SALIA_CHARGE_MODE(Doc.of(OpenemsType.STRING), "secc", "port0", "salia", "chargemode"), // - RAW_SALIA_CHANGE_METER(Doc.of(OpenemsType.STRING), "secc", "port0", "salia", "changemeter"), // - RAW_SALIA_AUTHMODE(Doc.of(OpenemsType.STRING), "secc", "port0", "salia", "authmode"), // - RAW_SALIA_FIRMWARESTATE(Doc.of(OpenemsType.STRING), "secc", "port0", "salia", "firmwarestate"), // - RAW_SALIA_FIRMWAREPROGRESS(Doc.of(OpenemsType.STRING), "secc", "port0", "salia", "firmwareprogress"), // - RAW_SALIA_PUBLISH(Doc.of(OpenemsType.STRING), "secc", "port0", "salia", "publish"), // + RAW_SALIA_CHARGE_MODE(Doc.of(STRING), // + "secc", "port0", "salia", "chargemode"), // + RAW_SALIA_CHANGE_METER(Doc.of(STRING), // + "secc", "port0", "salia", "changemeter"), // + RAW_SALIA_AUTHMODE(Doc.of(STRING), // + "secc", "port0", "salia", "authmode"), // + RAW_SALIA_FIRMWARESTATE(Doc.of(STRING), // + "secc", "port0", "salia", "firmwarestate"), // + RAW_SALIA_FIRMWAREPROGRESS(Doc.of(STRING), // + "secc", "port0", "salia", "firmwareprogress"), // + RAW_SALIA_PUBLISH(Doc.of(STRING), // + "secc", "port0", "salia", "publish"), // // SESSION - RAW_SESSION_STATUS_AUTHORIZATION(Doc.of(OpenemsType.STRING), "secc", "port0", "session", - "authorization_status"), // - RAW_SESSION_SLAC_STARTED(Doc.of(OpenemsType.STRING), "secc", "port0", "session", "slac_started"), // - RAW_SESSION_AUTHORIZATION_METHOD(Doc.of(OpenemsType.STRING), "secc", "port0", "session", - "authorization_method"), // + RAW_SESSION_STATUS_AUTHORIZATION(Doc.of(STRING), // + "secc", "port0", "session", "authorization_status"), // + RAW_SESSION_SLAC_STARTED(Doc.of(STRING), // + "secc", "port0", "session", "slac_started"), // + RAW_SESSION_AUTHORIZATION_METHOD(Doc.of(STRING), // + "secc", "port0", "session", "authorization_method"), // // CONTACTOR - RAW_CONTACTOR_HLC_TARGET(Doc.of(OpenemsType.STRING), "secc", "port0", "contactor", "state", "hlc_target"), // - RAW_CONTACTOR_ACTUAL(Doc.of(OpenemsType.STRING), "secc", "port0", "contactor", "state", "actual"), // - RAW_CONTACTOR_TARGET(Doc.of(OpenemsType.STRING), "secc", "port0", "contactor", "state", "target"), // - RAW_CONTACTOR_ERROR(Doc.of(OpenemsType.STRING), "secc", "port0", "contactor", "error"), // + RAW_CONTACTOR_HLC_TARGET(Doc.of(STRING), // + "secc", "port0", "contactor", "state", "hlc_target"), // + RAW_CONTACTOR_ACTUAL(Doc.of(STRING), // + "secc", "port0", "contactor", "state", "actual"), // + RAW_CONTACTOR_TARGET(Doc.of(STRING), // + "secc", "port0", "contactor", "state", "target"), // + RAW_CONTACTOR_ERROR(Doc.of(STRING), // + "secc", "port0", "contactor", "error"), // // METERING - METER - RAW_METER_SERIALNUMBER(Doc.of(OpenemsType.STRING), "secc", "port0", "metering", "meter", "serialnumber"), // - RAW_METER_TYPE(Doc.of(OpenemsType.STRING), "secc", "port0", "metering", "meter", "type"), // - METER_NOT_AVAILABLE(Doc.of(Level.WARNING) // + RAW_METER_SERIALNUMBER(Doc.of(STRING), // + "secc", "port0", "metering", "meter", "serialnumber"), // + RAW_METER_TYPE(Doc.of(STRING), // + "secc", "port0", "metering", "meter", "type"), // + METER_NOT_AVAILABLE(Doc.of(WARNING) // .translationKey(EvcsHardyBarth.class, "noMeterAvailable")), // RAW_METER_AVAILABLE(new BooleanDoc()// .onChannelSetNextValue((hardyBarth, value) -> { var notAvailable = value.get() == null ? null : !value.get(); hardyBarth.channel(EvcsHardyBarth.ChannelId.METER_NOT_AVAILABLE).setNextValue(notAvailable); - }), "secc", "port0", "metering", "meter", "available"), // - - // METERING - POWER - RAW_ACTIVE_POWER_L1(Doc.of(OpenemsType.LONG).unit(Unit.WATT), value -> { - Double doubleValue = TypeUtils.getAsType(OpenemsType.DOUBLE, value); - return TypeUtils.getAsType(OpenemsType.LONG, TypeUtils.multiply(doubleValue, SCALE_FACTOR_MINUS_1)); - }, "secc", "port0", "metering", "power", "active", "ac", "l1", "actual"), // - - RAW_ACTIVE_POWER_L2(Doc.of(OpenemsType.LONG).unit(Unit.WATT), value -> { - Double doubleValue = TypeUtils.getAsType(OpenemsType.DOUBLE, value); - return TypeUtils.getAsType(OpenemsType.LONG, TypeUtils.multiply(doubleValue, SCALE_FACTOR_MINUS_1)); - }, "secc", "port0", "metering", "power", "active", "ac", "l2", "actual"), // - - RAW_ACTIVE_POWER_L3(Doc.of(OpenemsType.LONG).unit(Unit.WATT), value -> { - Double doubleValue = TypeUtils.getAsType(OpenemsType.DOUBLE, value); - return TypeUtils.getAsType(OpenemsType.LONG, TypeUtils.multiply(doubleValue, SCALE_FACTOR_MINUS_1)); - }, "secc", "port0", "metering", "power", "active", "ac", "l3", "actual"), // - - // METERING - CURRENT - RAW_ACTIVE_CURRENT_L1(Doc.of(OpenemsType.LONG).unit(Unit.MILLIAMPERE), "secc", "port0", "metering", "current", - "ac", "l1", "actual"), // - RAW_ACTIVE_CURRENT_L2(Doc.of(OpenemsType.LONG).unit(Unit.MILLIAMPERE), "secc", "port0", "metering", "current", - "ac", "l2", "actual"), // - RAW_ACTIVE_CURRENT_L3(Doc.of(OpenemsType.LONG).unit(Unit.MILLIAMPERE), "secc", "port0", "metering", "current", - "ac", "l3", "actual"), // + }), // + "secc", "port0", "metering", "meter", "available"), // // METERING - ENERGY - RAW_ACTIVE_ENERGY_TOTAL(Doc.of(OpenemsType.DOUBLE).unit(Unit.CUMULATED_WATT_HOURS), "secc", "port0", "metering", - "energy", "active_total", "actual"), // - RAW_ACTIVE_ENERGY_EXPORT(Doc.of(OpenemsType.DOUBLE).unit(Unit.CUMULATED_WATT_HOURS), "secc", "port0", - "metering", "energy", "active_export", "actual"), // + RAW_ACTIVE_ENERGY_TOTAL(Doc.of(DOUBLE) // + .unit(CUMULATED_WATT_HOURS), // + "secc", "port0", "metering", "energy", "active_total", "actual"), // + RAW_ACTIVE_ENERGY_EXPORT(Doc.of(DOUBLE) // + .unit(CUMULATED_WATT_HOURS), // + "secc", "port0", "metering", "energy", "active_export", "actual"), // // EMERGENCY SHUTDOWN - RAW_EMERGENCY_SHUTDOWN(Doc.of(OpenemsType.STRING), "secc", "port0", "emergency_shutdown"), // + RAW_EMERGENCY_SHUTDOWN(Doc.of(STRING), // + "secc", "port0", "emergency_shutdown"), // // RCD - RAW_RCD_AVAILABLE(Doc.of(OpenemsType.BOOLEAN), "secc", "port0", "rcd", "recloser", "available"), // + RAW_RCD_AVAILABLE(Doc.of(BOOLEAN), // + "secc", "port0", "rcd", "recloser", "available"), // // PLUG LOCK - RAW_PLUG_LOCK_STATE_ACTUAL(Doc.of(OpenemsType.STRING), "secc", "port0", "plug_lock", "state", "actual"), // - RAW_PLUG_LOCK_STATE_TARGET(Doc.of(OpenemsType.STRING), "secc", "port0", "plug_lock", "state", "target"), // - RAW_PLUG_LOCK_ERROR(Doc.of(OpenemsType.STRING), "secc", "port0", "plug_lock", "error"), // + RAW_PLUG_LOCK_STATE_ACTUAL(Doc.of(STRING), // + "secc", "port0", "plug_lock", "state", "actual"), // + RAW_PLUG_LOCK_STATE_TARGET(Doc.of(STRING), // + "secc", "port0", "plug_lock", "state", "target"), // + RAW_PLUG_LOCK_ERROR(Doc.of(STRING), // + "secc", "port0", "plug_lock", "error"), // // CHARGE POINT - RAW_CP_STATE(Doc.of(OpenemsType.STRING), "secc", "port0", "cp", "state"), // + RAW_CP_STATE(Doc.of(STRING), // + "secc", "port0", "cp", "state"), // // DIODE PRESENT - RAW_DIODE_PRESENT(Doc.of(OpenemsType.STRING), "secc", "port0", "diode_present"), // + RAW_DIODE_PRESENT(Doc.of(STRING), // + "secc", "port0", "diode_present"), // // CABLE CURRENT LIMIT - RAW_CABLE_CURRENT_LIMIT(Doc.of(OpenemsType.STRING), "secc", "port0", "cable_current_limit"), // + RAW_CABLE_CURRENT_LIMIT(Doc.of(STRING), // + "secc", "port0", "cable_current_limit"), // // VENTILATION - RAW_VENTILATION_STATE_ACTUAL(Doc.of(OpenemsType.STRING), "secc", "port0", "ventilation", "state", "actual"), // - RAW_VENTILATION_STATE_TARGET(Doc.of(OpenemsType.STRING), "secc", "port0", "ventilation", "state", "target"), // - RAW_VENTILATION_AVAILABLE(Doc.of(OpenemsType.BOOLEAN), "secc", "port0", "ventilation", "available"), // + RAW_VENTILATION_STATE_ACTUAL(Doc.of(STRING), // + "secc", "port0", "ventilation", "state", "actual"), // + RAW_VENTILATION_STATE_TARGET(Doc.of(STRING), // + "secc", "port0", "ventilation", "state", "target"), // + RAW_VENTILATION_AVAILABLE(Doc.of(BOOLEAN), // + "secc", "port0", "ventilation", "available"), // // EV - PRESENT - RAW_EV_PRESENT(Doc.of(OpenemsType.STRING), "secc", "port0", "ev_present"), // + RAW_EV_PRESENT(Doc.of(STRING), // + "secc", "port0", "ev_present"), // // CHARGING - RAW_CHARGING(Doc.of(OpenemsType.STRING), "secc", "port0", "charging"), // + RAW_CHARGING(Doc.of(STRING), // + "secc", "port0", "charging"), // // RFID - RAW_RFID_AUTHORIZEREQ(Doc.of(OpenemsType.STRING), "secc", "port0", "rfid", "authorizereq"), // - RAW_RFID_AVAILABLE(Doc.of(OpenemsType.BOOLEAN), "secc", "port0", "rfid", "available"), // + RAW_RFID_AUTHORIZEREQ(Doc.of(STRING), // + "secc", "port0", "rfid", "authorizereq"), // + RAW_RFID_AVAILABLE(Doc.of(BOOLEAN), // + "secc", "port0", "rfid", "available"), // // GRID CURRENT LIMIT - RAW_GRID_CURRENT_LIMIT(Doc.of(OpenemsType.STRING), "secc", "port0", "grid_current_limit"), // + RAW_GRID_CURRENT_LIMIT(Doc.of(STRING), // + "secc", "port0", "grid_current_limit"), // // SLAC ERROR - RAW_SLAC_ERROR(Doc.of(OpenemsType.STRING), "secc", "port0", "slac_error"), // + RAW_SLAC_ERROR(Doc.of(STRING), // + "secc", "port0", "slac_error"), // // DEVICE - RAW_DEVICE_PRODUCT(Doc.of(OpenemsType.STRING), "device", "product"), // - RAW_DEVICE_MODELNAME(Doc.of(OpenemsType.STRING), "device", "modelname"), // - RAW_DEVICE_HARDWARE_VERSION(Doc.of(OpenemsType.STRING), "device", "hardware_version"), // - RAW_DEVICE_SOFTWARE_VERSION(Doc.of(OpenemsType.STRING), "device", "software_version"), // - RAW_DEVICE_VCS_VERSION(Doc.of(OpenemsType.STRING), "device", "vcs_version"), // - RAW_DEVICE_HOSTNAME(Doc.of(OpenemsType.STRING), "device", "hostname"), // - RAW_DEVICE_MAC_ADDRESS(Doc.of(OpenemsType.STRING), "device", "mac_address"), // - RAW_DEVICE_SERIAL(Doc.of(OpenemsType.LONG), "device", "serial"), // - RAW_DEVICE_UUID(Doc.of(OpenemsType.STRING), "device", "uuid"), // + RAW_DEVICE_PRODUCT(Doc.of(STRING), // + "device", "product"), // + RAW_DEVICE_MODELNAME(Doc.of(STRING), // + "device", "modelname"), // + RAW_DEVICE_HARDWARE_VERSION(Doc.of(STRING), // + "device", "hardware_version"), // + RAW_DEVICE_SOFTWARE_VERSION(Doc.of(STRING), // + "device", "software_version"), // + RAW_DEVICE_VCS_VERSION(Doc.of(STRING), // + "device", "vcs_version"), // + RAW_DEVICE_HOSTNAME(Doc.of(STRING), // + "device", "hostname"), // + RAW_DEVICE_MAC_ADDRESS(Doc.of(STRING), // + "device", "mac_address"), // + RAW_DEVICE_SERIAL(Doc.of(LONG), // + "device", "serial"), // + RAW_DEVICE_UUID(Doc.of(STRING), // + "device", "uuid"), // ; private final Doc doc; 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 3b77f4df677..4afe4696cd6 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 @@ -1,6 +1,17 @@ package io.openems.edge.evcs.hardybarth; +import static io.openems.edge.bridge.http.api.BridgeHttp.DEFAULT_CONNECT_TIMEOUT; +import static io.openems.edge.bridge.http.api.BridgeHttp.DEFAULT_READ_TIMEOUT; +import static io.openems.edge.bridge.http.api.HttpMethod.GET; +import static io.openems.edge.bridge.http.api.HttpMethod.PUT; +import static io.openems.edge.evcs.api.ChargingType.AC; +import static io.openems.edge.evcs.api.Phases.THREE_PHASE; +import static java.lang.Math.round; +import static java.util.Collections.emptyMap; + import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.annotations.Activate; @@ -19,16 +30,22 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; -import io.openems.common.utils.JsonUtils; +import io.openems.common.types.HttpStatus; +import io.openems.edge.bridge.http.api.BridgeHttp; +import io.openems.edge.bridge.http.api.BridgeHttp.Endpoint; +import io.openems.edge.bridge.http.api.BridgeHttpFactory; +import io.openems.edge.bridge.http.api.HttpMethod; +import io.openems.edge.bridge.http.api.HttpResponse; import io.openems.edge.common.channel.StringReadChannel; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.event.EdgeEventConstants; import io.openems.edge.evcs.api.AbstractManagedEvcsComponent; -import io.openems.edge.evcs.api.ChargingType; +import io.openems.edge.evcs.api.DeprecatedEvcs; import io.openems.edge.evcs.api.Evcs; import io.openems.edge.evcs.api.EvcsPower; import io.openems.edge.evcs.api.ManagedEvcs; -import io.openems.edge.evcs.api.Phases; +import io.openems.edge.evcs.api.WriteHandler; +import io.openems.edge.meter.api.ElectricityMeter; @Designate(ocd = Config.class, factory = true) @Component(// @@ -37,82 +54,113 @@ configurationPolicy = ConfigurationPolicy.REQUIRE // ) @EventTopics({ // - EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE, // EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE, // }) public class EvcsHardyBarthImpl extends AbstractManagedEvcsComponent - implements OpenemsComponent, EventHandler, EvcsHardyBarth, Evcs, ManagedEvcs { + implements OpenemsComponent, EventHandler, EvcsHardyBarth, Evcs, ManagedEvcs, DeprecatedEvcs, ElectricityMeter { - protected final Logger log = LoggerFactory.getLogger(EvcsHardyBarthImpl.class); + private final Logger log = LoggerFactory.getLogger(EvcsHardyBarthImpl.class); - @Reference - private EvcsPower evcsPower; + protected final HardyBarthReadUtils readUtils = new HardyBarthReadUtils(this); - /** API for main REST API functions. */ - protected HardyBarthApi api; - /** ReadWorker and WriteHandler: Reading and sending data to the EVCS. */ - private final HardyBarthReadWorker readWorker = new HardyBarthReadWorker(this); /** * Master EVCS is responsible for RFID authentication (Not implemented for now). */ protected boolean masterEvcs = true; - protected Config config; + private BridgeHttp httpBridge; + private Config config; + + @Reference + private EvcsPower evcsPower; + + @Reference + private BridgeHttpFactory httpBridgeFactory; public EvcsHardyBarthImpl() { super(// OpenemsComponent.ChannelId.values(), // + ElectricityMeter.ChannelId.values(), // Evcs.ChannelId.values(), // ManagedEvcs.ChannelId.values(), // - EvcsHardyBarth.ChannelId.values() // + EvcsHardyBarth.ChannelId.values(), // + DeprecatedEvcs.ChannelId.values() // ); + DeprecatedEvcs.copyToDeprecatedEvcsChannels(this); + ElectricityMeter.calculateSumCurrentFromPhases(this); + ElectricityMeter.calculateAverageVoltageFromPhases(this); } @Activate private void activate(ComponentContext context, Config config) { super.activate(context, config.id(), config.alias(), config.enabled()); + // TODO stop here if not enabled this.config = config; - this._setChargingType(ChargingType.AC); + this._setChargingType(AC); 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); + this._setPhases(THREE_PHASE); - // Reading the given values - this.readWorker.activate(config.id()); - this.readWorker.triggerNextRun(); - } + this.httpBridge = this.httpBridgeFactory.get(); + // formerly .setHeartbeat + // The internal heartbeat is currently too fast - it is not enough to write + // every second by default. We have to disable it to run the evcs + // properly. + // TODO: The manufacturer must be asked if it is possible to read the heartbeat + // status so that we can check if the heartbeat is really disabled and if the + // heartbeat time can be increased to be able to use this feature. + this.httpBridge.subscribeCycle(1, // + this.createEndpoint(PUT, "/api/secc", "{\"salia/heartbeat\":\"off\"}"), // + t -> this._setChargingstationCommunicationFailed(false), + t -> this._setChargingstationCommunicationFailed(true)); + this.httpBridge.subscribeCycle(1, // + this.createEndpoint(GET, "/api", null), // + t -> { + this.readUtils.handleGetApiCallResponse(t, config.phaseRotation()); + this._setChargingstationCommunicationFailed(false); + }, // + t -> this._setChargingstationCommunicationFailed(true)); } @Override @Deactivate protected void deactivate() { super.deactivate(); + this.httpBridgeFactory.unget(this.httpBridge); + this.httpBridge = null; + } - if (this.readWorker != null) { - this.readWorker.deactivate(); - } + private Endpoint getTargetEndpoint(int target) { + return this.createEndpoint(PUT, "/api/secc", "{\"salia/pausecharging\":\"" + target + "\"}"); + } + + private Endpoint createEndpoint(HttpMethod httpMethod, String url, String body) { + return createEndpoint(this.config.ip(), httpMethod, url, body); + } + + protected static Endpoint createEndpoint(String ip, HttpMethod httpMethod, String url, String body) { + return new Endpoint(// + new StringBuilder("http://").append(ip).append(url).toString(), // + httpMethod, DEFAULT_CONNECT_TIMEOUT, DEFAULT_READ_TIMEOUT, // + body, // + emptyMap()); } @Override - public void handleEvent(Event event) { + protected WriteHandler createWriteHandler() { + return new HardyBarthWriteHandler(this); + } + @Override + public void handleEvent(Event event) { if (!this.isEnabled()) { return; } super.handleEvent(event); switch (event.getTopic()) { - case EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE: - - this.setManualMode(); - this.setHeartbeat(); - this.readWorker.triggerNextRun(); - - // TODO: intelligent firmware update - break; + case EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE // + -> this.setManualMode(); } } @@ -125,39 +173,14 @@ public void handleEvent(Event event) { private void setManualMode() { StringReadChannel channelChargeMode = this.channel(EvcsHardyBarth.ChannelId.RAW_SALIA_CHARGE_MODE); Optional valueOpt = channelChargeMode.value().asOptional(); - if (valueOpt.isPresent()) { - if (!valueOpt.get().equals("manual")) { - // Set to manual mode - try { - this.debugLog("Setting HardyBarth to manual chargemode"); - JsonElement result = this.api.sendPutRequest("/api/secc", "salia/chargemode", "manual"); - this.debugLog(result.toString()); - } catch (OpenemsNamedException e) { - e.printStackTrace(); - } - } + if (valueOpt.map(t -> !t.equals("manual")).orElse(true)) { + return; } - } - - /** - * Set heartbeat. - * - *

      - * Sets the heartbeat to on or off. - */ - private void setHeartbeat() { - // The internal heartbeat is currently too fast - it is not enough to write - // every second by default. We have to disable it to run the evcs - // properly. - // TODO: The manufacturer must be asked if it is possible to read the heartbeat - // status so that we can check if the heartbeat is really disabled and if the - // heartbeat time can be increased to be able to use this feature. + this.debugLog("Setting HardyBarth to manual chargemode"); + this.httpBridge // + .requestJson(this.createEndpoint(PUT, "/api/secc", "{\"salia/chargemode\":\"manual\"}")) // + .thenAccept(t -> this.debugLog(t.toString())); - try { - this.api.sendPutRequest("/api/secc", "salia/heartbeat", "off"); - } catch (OpenemsNamedException e) { - e.printStackTrace(); - } } /** @@ -219,7 +242,6 @@ public boolean getConfiguredDebugMode() { @Override public boolean applyChargePowerLimit(int power) throws OpenemsNamedException { - // TODO: Use power precision to set valid power if it is used in UI part too // e.g. int precision = TypeUtils.getAsType(OpenemsType.INTEGER, // this.getPowerPrecision().orElse(230d)); @@ -227,7 +249,7 @@ public boolean applyChargePowerLimit(int power) throws OpenemsNamedException { // Convert it to ampere and apply hard limits int phases = this.getPhasesAsInt(); - Integer current = (int) Math.round(power / (double) phases / 230.0); + final var current = round(power / (float) phases / 230.F); return this.setTarget(current); } @@ -244,25 +266,25 @@ public boolean pauseChargeProcess() throws OpenemsNamedException { * @return boolean if the target was set * @throws OpenemsNamedException on error */ - private boolean setTarget(int current) throws OpenemsNamedException { - - JsonElement resultPause; + private boolean setTarget(int current) { + CompletableFuture> resultPause = null; if (current > 0) { // Send stop pause request - resultPause = this.api.sendPutRequest("/api/secc", "salia/pausecharging", "" + 0); + resultPause = this.httpBridge.requestJson(this.getTargetEndpoint(0)); } else { - // Send pause charging request - resultPause = this.api.sendPutRequest("/api/secc", "salia/pausecharging", "" + 1); + resultPause = this.httpBridge.requestJson(this.getTargetEndpoint(1)); this.debugLog("Setting HardyBarth " + this.alias() + " to pause"); } // Send charge power limit - JsonElement resultLimit = this.api.sendPutRequest("/api/secc", "grid_current_limit", "" + current); - - Optional resultLimitVal = JsonUtils.getAsOptionalString(resultLimit, "result"); - Optional resultPauseVal = JsonUtils.getAsOptionalString(resultPause, "result"); - - return resultLimitVal.orElse("").equals("ok") && resultPauseVal.orElse("").equals("ok"); + final var resultLimit = this.httpBridge.requestJson( + this.createEndpoint(PUT, "/api/secc", "{\"" + "grid_current_limit" + "\":\"" + current + "\"}")); + try { + return resultLimit.get().status().equals(HttpStatus.OK) && resultPause.get().status().equals(HttpStatus.OK); + } catch (InterruptedException | ExecutionException e) { + this.log.error("Unable to set EVCS Target"); + return false; + } } @Override @@ -277,12 +299,12 @@ public int getMinimumTimeTillChargingLimitTaken() { @Override public int getConfiguredMinimumHardwarePower() { - return Math.round(this.config.minHwCurrent() / 1000f) * DEFAULT_VOLTAGE * Phases.THREE_PHASE.getValue(); + return round(this.config.minHwCurrent() / 1000f) * DEFAULT_VOLTAGE * THREE_PHASE.getValue(); } @Override public int getConfiguredMaximumHardwarePower() { - return Math.round(this.config.maxHwCurrent() / 1000f) * DEFAULT_VOLTAGE * Phases.THREE_PHASE.getValue(); + return round(this.config.maxHwCurrent() / 1000f) * DEFAULT_VOLTAGE * THREE_PHASE.getValue(); } @Override diff --git a/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/HardyBarthApi.java b/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/HardyBarthApi.java deleted file mode 100644 index 4b088d2d5a3..00000000000 --- a/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/HardyBarthApi.java +++ /dev/null @@ -1,154 +0,0 @@ -package io.openems.edge.evcs.hardybarth; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.net.HttpURLConnection; -import java.net.URL; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; - -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.exceptions.OpenemsException; -import io.openems.common.utils.JsonUtils; - -/** - * Implements the Hardy Barth Api. - */ -public class HardyBarthApi { - - private final String baseUrl; - private final String authorizationHeader; - private final EvcsHardyBarthImpl hardyBarthImpl; - - public HardyBarthApi(String ip, EvcsHardyBarthImpl hardyBarthImpl) { - this.baseUrl = "http://" + ip; - this.authorizationHeader = "Basic "; - this.hardyBarthImpl = hardyBarthImpl; - } - - /** - * Sends a get request to the Hardy Barth. - * - * @param endpoint the REST Api endpoint - * @return a JsonObject or JsonArray - * @throws OpenemsNamedException on error - */ - public JsonElement sendGetRequest(String endpoint) throws OpenemsNamedException { - var putRequestFailed = false; - JsonObject result = null; - - try { - // Create URL like "http://192.168.8.101/api/" - var url = new URL(this.baseUrl + endpoint); - - // Open http url connection - var con = (HttpURLConnection) url.openConnection(); - - // Set general information - con.setRequestProperty("Authorization", this.authorizationHeader); - con.setRequestMethod("GET"); - con.setConnectTimeout(5000); - con.setReadTimeout(5000); - - // Read response - String body; - try (var in = new BufferedReader(new InputStreamReader(con.getInputStream()))) { - - // Read HTTP response - var content = new StringBuilder(); - String line; - while ((line = in.readLine()) != null) { - content.append(line); - content.append(System.lineSeparator()); - } - body = content.toString(); - } - - // Get response code - var status = con.getResponseCode(); - if (status >= 300) { - putRequestFailed = true; - throw new OpenemsException( - "Error while reading from Hardy Barth API. Response code: " + status + ". " + body); - } - putRequestFailed = false; - // Parse response to JSON - result = JsonUtils.parseToJsonObject(body); - } catch (OpenemsNamedException | IOException e) { - putRequestFailed = true; - } - - // Set state and return result - this.hardyBarthImpl._setChargingstationCommunicationFailed(putRequestFailed); - return result; - } - - /** - * Sends a get request to the Hardy Barth. - * - * @param endpoint the REST Api endpoint @return a JsonObject or - * JsonArray @throws OpenemsNamedException on error @throws - * @param key The key in the properties - * @param value The value of the key property - * @return A JsonObject - * @throws OpenemsNamedException on error - */ - public JsonObject sendPutRequest(String endpoint, String key, String value) throws OpenemsNamedException { - var putRequestFailed = false; - JsonObject result = null; - - try { - // Create URL like "http://192.168.8.101/api/" - var url = new URL(this.baseUrl + endpoint); - - // Open http url connection - var connection = (HttpURLConnection) url.openConnection(); - - // Set general information - connection.setRequestProperty("Authorization", this.authorizationHeader); - connection.setRequestMethod("PUT"); - connection.setDoOutput(true); - connection.setConnectTimeout(5000); - connection.setReadTimeout(5000); - - // Write "topic" and "value" on request properties - var osw = new OutputStreamWriter(connection.getOutputStream()); - osw.write("{\"" + key + "\":\"" + value + "\"}"); - osw.flush(); - osw.close(); - - String body; - try (var in = new BufferedReader(new InputStreamReader(connection.getInputStream()))) { - - // Read HTTP response - var content = new StringBuilder(); - String line; - while ((line = in.readLine()) != null) { - content.append(line); - content.append(System.lineSeparator()); - } - body = content.toString(); - } - - // Get response code - var status = connection.getResponseCode(); - if ((status >= 300) && (status >= 0)) { - // Respond error status-code - putRequestFailed = true; - throw new OpenemsException( - "Error while reading from Hardy Barth API. Response code: " + status + ". " + body); - } - // Result OK - result = JsonUtils.parseToJsonObject(body); - } catch (IOException e) { - putRequestFailed = true; - } - - // Set state and return result - this.hardyBarthImpl._setChargingstationCommunicationFailed(putRequestFailed); - return result; - } -} diff --git a/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/HardyBarthReadUtils.java b/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/HardyBarthReadUtils.java new file mode 100644 index 00000000000..d20a8a44d04 --- /dev/null +++ b/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/HardyBarthReadUtils.java @@ -0,0 +1,272 @@ +package io.openems.edge.evcs.hardybarth; + +import static io.openems.common.types.OpenemsType.FLOAT; +import static io.openems.common.types.OpenemsType.INTEGER; +import static io.openems.common.types.OpenemsType.LONG; +import static io.openems.common.types.OpenemsType.STRING; +import static io.openems.common.utils.JsonUtils.parseToJsonObject; +import static io.openems.edge.evcs.api.Evcs.evaluatePhaseCount; +import static io.openems.edge.evcs.hardybarth.EvcsHardyBarth.SCALE_FACTOR_MINUS_1; +import static java.lang.Math.round; + +import java.util.Optional; +import java.util.function.Function; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.types.OpenemsType; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.bridge.http.api.HttpResponse; +import io.openems.edge.common.type.TypeUtils; +import io.openems.edge.evcs.api.PhaseRotation; +import io.openems.edge.evcs.api.PhaseRotation.RotatedPhases; +import io.openems.edge.evcs.api.Status; + +public class HardyBarthReadUtils { + private final EvcsHardyBarthImpl parent; + + private int chargingFinishedCounter = 0; + private int errorCounter = 0; + + public HardyBarthReadUtils(EvcsHardyBarthImpl parent) { + this.parent = parent; + } + + /** + * Set the value for every Evcs.ChannelId. + * + * @param json given raw data in JSON + * @param phaseRotation the configured {@link PhaseRotation} + */ + protected void setEvcsChannelIds(JsonElement json, PhaseRotation phaseRotation) { + final var hb = this.parent; + + // Energy + hb._setEnergySession(getValueFromJson(STRING, json, // + value -> { + if (value == null) { + return null; + } + var chargedata = TypeUtils.getAsType(STRING, value).split("\\|"); + if (chargedata.length == 3) { + return round(TypeUtils.getAsType(FLOAT, chargedata[2]) * 1000); + } + return null; + }, "secc", "port0", "salia", "chargedata")); + hb._setActiveProductionEnergy(getValueFromJson(LONG, json, // + value -> TypeUtils.getAsType(LONG, value), // + "secc", "port0", "metering", "energy", "active_import", "actual")); + + // Current + final var currentL1 = getAsIntOrElse(json, 0, "secc", "port0", "metering", "current", "ac", "l1", "actual"); + final var currentL2 = getAsIntOrElse(json, 0, "secc", "port0", "metering", "current", "ac", "l2", "actual"); + final var currentL3 = getAsIntOrElse(json, 0, "secc", "port0", "metering", "current", "ac", "l3", "actual"); + + // Power + final var activePowerL1 = getAsInteger(json, SCALE_FACTOR_MINUS_1, // + "secc", "port0", "metering", "power", "active", "ac", "l1", "actual"); + final var activePowerL2 = getAsInteger(json, SCALE_FACTOR_MINUS_1, // + "secc", "port0", "metering", "power", "active", "ac", "l2", "actual"); + final var activePowerL3 = getAsInteger(json, SCALE_FACTOR_MINUS_1, // + "secc", "port0", "metering", "power", "active", "ac", "l3", "actual"); + + // Voltage + final var voltageL1 = activePowerL1 == null ? null : round(activePowerL1 * 1_000_000F / currentL1); + final var voltageL2 = activePowerL2 == null ? null : round(activePowerL2 * 1_000_000F / currentL2); + final var voltageL3 = activePowerL3 == null ? null : round(activePowerL3 * 1_000_000F / currentL3); + + var rp = RotatedPhases.from(phaseRotation, // + voltageL1, currentL1, activePowerL1, // + voltageL2, currentL2, activePowerL2, // + voltageL3, currentL3, activePowerL3); + hb._setVoltageL1(rp.voltageL1()); + hb._setVoltageL2(rp.voltageL2()); + hb._setVoltageL3(rp.voltageL3()); + hb._setCurrentL1(rp.currentL1()); + hb._setCurrentL2(rp.currentL2()); + hb._setCurrentL3(rp.currentL3()); + hb._setActivePowerL1(rp.activePowerL1()); + hb._setActivePowerL2(rp.activePowerL2()); + hb._setActivePowerL3(rp.activePowerL3()); + + // Phases: keep last value if no power value was given + var phases = evaluatePhaseCount(rp.activePowerL1(), rp.activePowerL2(), rp.activePowerL3()); + if (phases != null) { + hb._setPhases(phases); + this.parent.debugLog("Used phases: " + phases); + } + + // ACTIVE_POWER + final var activePower = Optional.ofNullable(getAsInteger(json, SCALE_FACTOR_MINUS_1, // + "secc", "port0", "metering", "power", "active_total", "actual")) // + .map(p -> p < 100 ? 0 : p) // Ignore the consumption of the charger itself + .orElse(null); + this.parent._setActivePower(activePower); + + // STATUS + var status = getValueFromJson(STRING, json, value -> { + var stringValue = TypeUtils.getAsType(STRING, value); + if (stringValue == null) { + 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 = switch (stringValue) { + case "A" -> Status.NOT_READY_FOR_CHARGING; + case "B" -> { + var tmpStatus = Status.READY_FOR_CHARGING; + + // Detect if the car is full + if (this.parent.getSetChargePowerLimit().orElse(0) >= this.parent.getMinimumHardwarePower().orElse(0) + && activePower <= 0) { + + if (this.chargingFinishedCounter >= 90) { + tmpStatus = Status.CHARGING_FINISHED; + } else { + this.chargingFinishedCounter++; + } + } else { + this.chargingFinishedCounter = 0; + + // Charging rejected because we are forcing to pause charging + if (this.parent.getSetChargePowerLimit().orElse(0) == 0) { + tmpStatus = Status.CHARGING_REJECTED; + } + } + 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(); + } + 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"); + + this.parent._setStatus(status); + } + + private static Integer getAsInteger(JsonElement json, float scaleFactor, String... jsonPaths) { + return getValueFromJson(INTEGER, json, // + value -> value == null ? null // + : round(TypeUtils.getAsType(INTEGER, value) * scaleFactor), // + jsonPaths); + } + + private static int getAsIntOrElse(JsonElement json, int orElse, String... jsonPaths) { + var result = getValueFromJson(INTEGER, json, // + value -> TypeUtils.getAsType(INTEGER, value), // + jsonPaths); + return result == null // + ? orElse // + : result; + } + + /** + * Get the last JSON element and it's value, by running through the given + * jsonPath. + * + * @param openemsType the {@link OpenemsType}s + * @param json Raw JsonElement. + * @param converter Converter, to convert the raw JSON value into a proper + * Channel. + * @param jsonPaths Whole JSON path, where the JsonElement for the given + * channel is located. + * @param return type + * @return Value of the last JsonElement by running through the specified JSON + * path. + */ + private static T getValueFromJson(OpenemsType openemsType, JsonElement json, Function converter, + String... jsonPaths) { + + var currentJsonElement = json; + // Go through the whole jsonPath of the current channelId + for (var i = 0; i < jsonPaths.length; i++) { + var currentPathMember = jsonPaths[i]; + try { + if (i == jsonPaths.length - 1) { + // Last path element + var value = getJsonElementValue(currentJsonElement, openemsType, jsonPaths[i]); + + // Return the converted value + return converter.apply(value); + } + // Not last path element + currentJsonElement = JsonUtils.getAsJsonObject(currentJsonElement, currentPathMember); + } catch (OpenemsNamedException e) { + return null; + } + } + return null; + } + + /** + * Handles a Response froma http call for the endpoint /api GET. + * + * @param response the {@link HttpResponse} to be handled + * @param phaseRotation the configured {@link PhaseRotation} + * @throws OpenemsNamedException when json can not be parsed + */ + public void handleGetApiCallResponse(HttpResponse response, PhaseRotation phaseRotation) + throws OpenemsNamedException { + final var json = parseToJsonObject(response.data()); + for (var channelId : EvcsHardyBarth.ChannelId.values()) { + var jsonPaths = channelId.getJsonPaths(); + var value = getValueFromJson(channelId.doc().getType(), json, channelId.converter, jsonPaths); + + // Set the channel-value + this.parent.channel(channelId).setNextValue(value); + + if (channelId.equals(EvcsHardyBarth.ChannelId.RAW_SALIA_PUBLISH)) { + this.parent.masterEvcs = false; + } + + } + this.setEvcsChannelIds(json, phaseRotation); + } + + /** + * Get Value of the given JsonElement in the required type. + * + * @param jsonElement Element as JSON. + * @param openemsType Required type. + * @param memberName Member name of the JSON Element. + * @return Value in the required type. + * @throws OpenemsNamedException Failed to get the value. + */ + private static Object getJsonElementValue(JsonElement jsonElement, OpenemsType openemsType, String memberName) + throws OpenemsNamedException { + return switch (openemsType) { + case BOOLEAN -> JsonUtils.getAsInt(jsonElement, memberName) == 1; + case DOUBLE -> JsonUtils.getAsDouble(jsonElement, memberName); + case FLOAT -> JsonUtils.getAsFloat(jsonElement, memberName); + case INTEGER -> JsonUtils.getAsInt(jsonElement, memberName); + case LONG -> JsonUtils.getAsLong(jsonElement, memberName); + case SHORT -> JsonUtils.getAsShort(jsonElement, memberName); + case STRING -> JsonUtils.getAsString(jsonElement, memberName); + }; + } +} \ No newline at end of file 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 deleted file mode 100644 index c24f974ba21..00000000000 --- a/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/HardyBarthReadWorker.java +++ /dev/null @@ -1,318 +0,0 @@ -package io.openems.edge.evcs.hardybarth; - -import java.util.function.Function; - -import com.google.gson.JsonElement; - -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.types.OpenemsType; -import io.openems.common.utils.JsonUtils; -import io.openems.common.worker.AbstractCycleWorker; -import io.openems.edge.common.channel.ChannelId; -import io.openems.edge.common.type.TypeUtils; -import io.openems.edge.evcs.api.Evcs; -import io.openems.edge.evcs.api.Status; - -public class HardyBarthReadWorker extends AbstractCycleWorker { - - private final EvcsHardyBarthImpl parent; - private int chargingFinishedCounter = 0; - private int errorCounter = 0; - - public HardyBarthReadWorker(EvcsHardyBarthImpl parent) { - this.parent = parent; - } - - @Override - protected void forever() throws OpenemsNamedException { - - // TODO: Read separate JSON files - // - separate configuration -> this.api.sendGetRequest("/saliaconf.json"); - // e.g. min & max hardware power - // - customeredit values -> this.api.sendGetRequest("/customer.json"); - // - rfidtags -> this.api.sendGetRequest("/rfidtags.json"); - // - chargelogs -> this.api.sendGetRequest("/chargelogs.json"); - // - Read separate saliaconf.json and set minimum and maximum dynamically - - var json = this.parent.api.sendGetRequest("/api"); - if (json == null) { - return; - } - - // Set value for every HardyBarth.ChannelId - for (EvcsHardyBarth.ChannelId channelId : EvcsHardyBarth.ChannelId.values()) { - var jsonPaths = channelId.getJsonPaths(); - var value = this.getValueFromJson(channelId, json, channelId.converter, jsonPaths); - - // Set the channel-value - this.parent.channel(channelId).setNextValue(value); - - if (channelId.equals(EvcsHardyBarth.ChannelId.RAW_SALIA_PUBLISH)) { - this.parent.masterEvcs = false; - } - } - - // Set value for every Evcs.ChannelId - this.setEvcsChannelIds(json); - } - - /** - * Set the value for every Evcs.ChannelId. - * - * @param json Given raw data in JSON - */ - private void setEvcsChannelIds(JsonElement json) { - - // ENERGY_SESSION - var energy = (Double) this.getValueFromJson(Evcs.ChannelId.ENERGY_SESSION, OpenemsType.STRING, json, value -> { - if (value == null) { - return null; - } - Double rawEnergy = null; - String[] chargedata = value.toString().split("\\|"); - if (chargedata.length == 3) { - Double doubleValue = TypeUtils.getAsType(OpenemsType.DOUBLE, chargedata[2]); - rawEnergy = doubleValue * 1000; - } - return rawEnergy; - - }, "secc", "port0", "salia", "chargedata"); - this.parent._setEnergySession(energy == null ? null : (int) Math.round(energy)); - - // ACTIVE_CONSUMPTION_ENERGY - var activeConsumptionEnergy = (Long) this.getValueFromJson(Evcs.ChannelId.ACTIVE_CONSUMPTION_ENERGY, json, - value -> { - Double doubleValue = TypeUtils.getAsType(OpenemsType.DOUBLE, value); - return TypeUtils.getAsType(OpenemsType.LONG, doubleValue); - - }, "secc", "port0", "metering", "energy", "active_import", "actual"); // - this.parent._setActiveConsumptionEnergy(activeConsumptionEnergy); - - // PHASES - var powerL1 = (Long) this.getValueForChannel(EvcsHardyBarth.ChannelId.RAW_ACTIVE_POWER_L1, 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); - - // 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 > 300) { - phases = 0; - - if (powerL1 >= 100) { - phases += 1; - } - if (powerL2 >= 100) { - phases += 1; - } - if (powerL3 >= 100) { - phases += 1; - } - } - } - this.parent._setPhases(phases); - this.parent.debugLog("Used phases: " + phases); - - // CHARGE_POWER - var chargePowerLong = (Long) this.getValueFromJson(Evcs.ChannelId.CHARGE_POWER, json, value -> { - Integer integerValue = TypeUtils.getAsType(OpenemsType.INTEGER, value); - if (integerValue == null) { - return null; - } - - long activePower = Math.round(integerValue * EvcsHardyBarth.SCALE_FACTOR_MINUS_1); - - // Ignore the consumption of the charger itself - 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) { - 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 = 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(); - if (this.parent.getSetChargePowerLimit().orElse(0) >= this.parent.getMinimumHardwarePower() - .orElse(0) && chargePower <= 0) { - - if (this.chargingFinishedCounter >= 90) { - tmpStatus = Status.CHARGING_FINISHED; - } else { - this.chargingFinishedCounter++; - } - } else { - this.chargingFinishedCounter = 0; - - // Charging rejected because we are forcing to pause charging - if (this.parent.getSetChargePowerLimit().orElse(0) == 0) { - tmpStatus = Status.CHARGING_REJECTED; - } - } - 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(); - } - 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"); - - this.parent._setStatus(status); - } - - /** - * Call the getValueFromJson with the detailed information of the channel. - * - * @param channelId Channel that value will be detect. - * @param json Whole JSON path, where the JsonElement for the given channel - * is located. - * @return Value of the last JsonElement by running through the specified JSON - * path. - */ - private Object getValueForChannel(EvcsHardyBarth.ChannelId channelId, JsonElement json) { - return this.getValueFromJson(channelId, json, channelId.converter, channelId.getJsonPaths()); - } - - /** - * Call the getValueFromJson without a divergent type in the raw json. - * - * @param channelId Channel that value will be detect. - * @param json Raw JsonElement. - * @param converter Converter, to convert the raw JSON value into a proper - * Channel. - * @param jsonPaths Whole JSON path, where the JsonElement for the given channel - * is located. - * @return Value of the last JsonElement by running through the specified JSON - * path. - */ - private Object getValueFromJson(ChannelId channelId, JsonElement json, Function converter, - String... jsonPaths) { - return this.getValueFromJson(channelId, null, json, converter, jsonPaths); - } - - /** - * Get the last JSON element and it's value, by running through the given - * jsonPath. - * - * @param channelId Channel that value will be detect. - * @param divergentTypeInRawJson Divergent type of the value in the depending - * JsonElement. - * @param json Raw JsonElement. - * @param converter Converter, to convert the raw JSON value into a - * proper Channel. - * @param jsonPaths Whole JSON path, where the JsonElement for the - * given channel is located. - * @return Value of the last JsonElement by running through the specified JSON - * path. - */ - private Object getValueFromJson(ChannelId channelId, OpenemsType divergentTypeInRawJson, JsonElement json, - Function converter, String... jsonPaths) { - - var currentJsonElement = json; - // Go through the whole jsonPath of the current channelId - for (var i = 0; i < jsonPaths.length; i++) { - var currentPathMember = jsonPaths[i]; - // System.out.println(currentPathMember); - try { - if (i == jsonPaths.length - 1) { - // - var openemsType = divergentTypeInRawJson == null ? channelId.doc().getType() - : divergentTypeInRawJson; - - // Last path element - var value = this.getJsonElementValue(currentJsonElement, openemsType, jsonPaths[i]); - - // Return the converted value - return converter.apply(value); - } - // Not last path element - currentJsonElement = JsonUtils.getAsJsonObject(currentJsonElement, currentPathMember); - } catch (OpenemsNamedException e) { - return null; - } - } - return null; - } - - /** - * Get Value of the given JsonElement in the required type. - * - * @param jsonElement Element as JSON. - * @param openemsType Required type. - * @param memberName Member name of the JSON Element. - * @return Value in the required type. - * @throws OpenemsNamedException Failed to get the value. - */ - private Object getJsonElementValue(JsonElement jsonElement, OpenemsType openemsType, String memberName) - throws OpenemsNamedException { - final Object value; - - switch (openemsType) { - case BOOLEAN: - value = JsonUtils.getAsInt(jsonElement, memberName) == 1; - break; - case DOUBLE: - value = JsonUtils.getAsDouble(jsonElement, memberName); - break; - case FLOAT: - value = JsonUtils.getAsFloat(jsonElement, memberName); - break; - case INTEGER: - value = JsonUtils.getAsInt(jsonElement, memberName); - break; - case LONG: - value = JsonUtils.getAsLong(jsonElement, memberName); - break; - case SHORT: - value = JsonUtils.getAsShort(jsonElement, memberName); - break; - case STRING: - value = JsonUtils.getAsString(jsonElement, memberName); - break; - default: - value = JsonUtils.getAsString(jsonElement, memberName); - break; - } - return value; - } -} diff --git a/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/HardyBarthWriteHandler.java b/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/HardyBarthWriteHandler.java new file mode 100644 index 00000000000..cde25123e84 --- /dev/null +++ b/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/HardyBarthWriteHandler.java @@ -0,0 +1,31 @@ +package io.openems.edge.evcs.hardybarth; + +import java.util.concurrent.CompletableFuture; + +import io.openems.edge.evcs.api.ManagedEvcs; +import io.openems.edge.evcs.api.WriteHandler; + +public class HardyBarthWriteHandler extends WriteHandler { + + private CompletableFuture applyChargePowerTask = CompletableFuture.completedFuture(null); + + public HardyBarthWriteHandler(ManagedEvcs parent) { + super(parent); + } + + @Override + protected synchronized void applyChargePower(int power) { + if (!this.applyChargePowerTask.isDone()) { + return; + } + this.applyChargePowerTask = CompletableFuture.runAsync(() -> { + super.applyChargePower(power); + }); + } + + @Override + public synchronized void cancelChargePower() { + this.applyChargePowerTask.cancel(true); + } + +} \ No newline at end of file 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 2d44360154f..8ecb6c334bc 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 @@ -1,23 +1,278 @@ package io.openems.edge.evcs.hardybarth; +import static io.openems.common.types.HttpStatus.OK; +import static io.openems.edge.bridge.http.dummy.DummyBridgeHttpFactory.ofDummyBridge; +import static io.openems.edge.evcs.api.PhaseRotation.L2_L3_L1; +import static io.openems.edge.evcs.api.Phases.THREE_PHASE; +import static io.openems.edge.evcs.api.Status.CHARGING; + import org.junit.Test; +import io.openems.edge.bridge.http.api.HttpResponse; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.evcs.api.DeprecatedEvcs; +import io.openems.edge.evcs.api.Evcs; +import io.openems.edge.meter.api.ElectricityMeter; public class EvcsHardyBarthImplTest { - private static final String COMPONENT_ID = "evcs0"; - @Test public void test() throws Exception { - new ComponentTest(new EvcsHardyBarthImpl()) // + final var phaseRotation = L2_L3_L1; + var sut = new EvcsHardyBarthImpl(); + var ru = sut.readUtils; + new ComponentTest(sut) // + .addReference("httpBridgeFactory", ofDummyBridge()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // + .setId("evcs0") // .setIp("192.168.8.101") // .setMaxHwCurrent(32_000) // .setMinHwCurrent(6_000) // - .build()) - .next(new TestCase()); + .setPhaseRotation(phaseRotation).build()) + + .next(new TestCase() // + .onBeforeProcessImage(() -> ru + .handleGetApiCallResponse(new HttpResponse(OK, API_RESPONSE), phaseRotation)) // + .output(EvcsHardyBarth.ChannelId.RAW_EVSE_GRID_CURRENT_LIMIT, 16) // + .output(EvcsHardyBarth.ChannelId.RAW_PHASE_COUNT, 3) // + .output(EvcsHardyBarth.ChannelId.RAW_CHARGE_STATUS_PLUG, "locked") // + .output(EvcsHardyBarth.ChannelId.RAW_CHARGE_STATUS_CONTACTOR, "closed") // + .output(EvcsHardyBarth.ChannelId.RAW_CHARGE_STATUS_PWM, "10.00") // + .output(EvcsHardyBarth.ChannelId.RAW_CHARGE_STATUS_CHARGEPOINT, "C") // + .output(EvcsHardyBarth.ChannelId.RAW_SALIA_CHARGE_MODE, "manual") // + .output(EvcsHardyBarth.ChannelId.RAW_SALIA_CHANGE_METER, null) // + .output(EvcsHardyBarth.ChannelId.RAW_SALIA_AUTHMODE, "free") // + .output(EvcsHardyBarth.ChannelId.RAW_SALIA_FIRMWARESTATE, "idle") // + .output(EvcsHardyBarth.ChannelId.RAW_SALIA_FIRMWAREPROGRESS, "0") // + .output(EvcsHardyBarth.ChannelId.RAW_SALIA_PUBLISH, null) // + .output(EvcsHardyBarth.ChannelId.RAW_SESSION_STATUS_AUTHORIZATION, "") // + .output(EvcsHardyBarth.ChannelId.RAW_SESSION_SLAC_STARTED, null) // + .output(EvcsHardyBarth.ChannelId.RAW_SESSION_AUTHORIZATION_METHOD, null) // + .output(EvcsHardyBarth.ChannelId.RAW_CONTACTOR_HLC_TARGET, "0") // + .output(EvcsHardyBarth.ChannelId.RAW_CONTACTOR_ACTUAL, "1") // + .output(EvcsHardyBarth.ChannelId.RAW_CONTACTOR_TARGET, "1") // + .output(EvcsHardyBarth.ChannelId.RAW_CONTACTOR_ERROR, "0") // + .output(EvcsHardyBarth.ChannelId.RAW_METER_SERIALNUMBER, "21031835") // + .output(EvcsHardyBarth.ChannelId.RAW_METER_TYPE, "klefr") // + .output(EvcsHardyBarth.ChannelId.RAW_METER_AVAILABLE, true) // + .output(EvcsHardyBarth.ChannelId.METER_NOT_AVAILABLE, false) // + .output(EvcsHardyBarth.ChannelId.RAW_ACTIVE_ENERGY_TOTAL, 4658050.0) // + .output(EvcsHardyBarth.ChannelId.RAW_ACTIVE_ENERGY_EXPORT, 0.0) // + .output(EvcsHardyBarth.ChannelId.RAW_EMERGENCY_SHUTDOWN, "0") // + .output(EvcsHardyBarth.ChannelId.RAW_RCD_AVAILABLE, false) // + .output(EvcsHardyBarth.ChannelId.RAW_PLUG_LOCK_STATE_ACTUAL, "1") // + .output(EvcsHardyBarth.ChannelId.RAW_PLUG_LOCK_STATE_TARGET, "1") // + .output(EvcsHardyBarth.ChannelId.RAW_PLUG_LOCK_ERROR, "0") // + .output(EvcsHardyBarth.ChannelId.RAW_CP_STATE, "C") // + .output(EvcsHardyBarth.ChannelId.RAW_DIODE_PRESENT, "1") // + .output(EvcsHardyBarth.ChannelId.RAW_CABLE_CURRENT_LIMIT, "-1") // + .output(EvcsHardyBarth.ChannelId.RAW_VENTILATION_STATE_ACTUAL, "0") // + .output(EvcsHardyBarth.ChannelId.RAW_VENTILATION_STATE_TARGET, null) // + .output(EvcsHardyBarth.ChannelId.RAW_VENTILATION_AVAILABLE, false) // + .output(EvcsHardyBarth.ChannelId.RAW_EV_PRESENT, "1") // + .output(EvcsHardyBarth.ChannelId.RAW_CHARGING, "1") // + .output(EvcsHardyBarth.ChannelId.RAW_RFID_AUTHORIZEREQ, "") // + .output(EvcsHardyBarth.ChannelId.RAW_RFID_AVAILABLE, false) // + .output(EvcsHardyBarth.ChannelId.RAW_GRID_CURRENT_LIMIT, "6") // + .output(EvcsHardyBarth.ChannelId.RAW_SLAC_ERROR, null) // + .output(EvcsHardyBarth.ChannelId.RAW_DEVICE_PRODUCT, "2310007") // + .output(EvcsHardyBarth.ChannelId.RAW_DEVICE_MODELNAME, "Salia PLCC Slave") // + .output(EvcsHardyBarth.ChannelId.RAW_DEVICE_HARDWARE_VERSION, "1.0") // + .output(EvcsHardyBarth.ChannelId.RAW_DEVICE_SOFTWARE_VERSION, "1.50.0") // + .output(EvcsHardyBarth.ChannelId.RAW_DEVICE_VCS_VERSION, "V0R5e") // + .output(EvcsHardyBarth.ChannelId.RAW_DEVICE_HOSTNAME, "salia") // + .output(EvcsHardyBarth.ChannelId.RAW_DEVICE_MAC_ADDRESS, "00:01:87:13:12:34") // + .output(EvcsHardyBarth.ChannelId.RAW_DEVICE_SERIAL, 101249323L) // + .output(EvcsHardyBarth.ChannelId.RAW_DEVICE_UUID, "5491ad62-022a-4356-a32c-00018713102x") // + + .output(Evcs.ChannelId.ENERGY_SESSION, 3460) // + .output(ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY, 4658050L) // + .output(ElectricityMeter.ChannelId.ACTIVE_CONSUMPTION_ENERGY, 4658050L) // + .output(Evcs.ChannelId.PHASES, THREE_PHASE) // + .output(Evcs.ChannelId.STATUS, CHARGING) // + .output(DeprecatedEvcs.ChannelId.CHARGE_POWER, 3192) // + .output(ElectricityMeter.ChannelId.ACTIVE_POWER, 3192) // + .output(ElectricityMeter.ChannelId.ACTIVE_POWER_L1, 1044) // + .output(ElectricityMeter.ChannelId.ACTIVE_POWER_L2, 1075) // + .output(ElectricityMeter.ChannelId.ACTIVE_POWER_L3, 1073) // + .output(ElectricityMeter.ChannelId.CURRENT, 14_770) // + .output(ElectricityMeter.ChannelId.CURRENT_L1, 4_770) // + .output(ElectricityMeter.ChannelId.CURRENT_L2, 5_000) // + .output(ElectricityMeter.ChannelId.CURRENT_L3, 5_000) // + .output(ElectricityMeter.ChannelId.VOLTAGE, 216_156) // + .output(ElectricityMeter.ChannelId.VOLTAGE_L1, 218_868) // + .output(ElectricityMeter.ChannelId.VOLTAGE_L2, 215_000) // + .output(ElectricityMeter.ChannelId.VOLTAGE_L3, 214_600) // + ); } + + private static final String API_RESPONSE = """ + { + "device":{ + "product":"2310007", + "modelname":"Salia PLCC Slave", + "hardware_version":"1.0", + "software_version":"1.50.0", + "vcs_version":"V0R5e", + "hostname":"salia", + "mac_address":"00:01:87:13:12:34", + "serial":"101249323", + "uuid":"5491ad62-022a-4356-a32c-00018713102x", + "internal_id":"412009" + }, + "secc":{ + "port0":{ + "ci":{ + "evse":{ + "basic":{ + "grid_current_limit":{ + "actual":"16" + }, + "phase_count":"3", + "physical_current_limit":"16", + "offered_current_limit":"6.0" + }, + "phase":{ + "actual":"3" + } + }, + "charge":{ + "cp":{ + "status":"C" + }, + "plug":{ + "status":"locked" + }, + "contactor":{ + "status":"closed" + }, + "pwm":{ + "status":"10.00" + } + } + }, + "salia":{ + "chargemode":"manual", + "thermal":"52893", + "mem":"392276", + "uptime":" 1:04", + "load":"0.37", + "chargedata":"3813|3192|3.46|", + "authmode":"free", + "firmwarestate":"idle", + "firmwareprogress":"0", + "heartbeat":"off", + "pausecharging":"0" + }, + "session":{ + "authorization_status":"" + }, + "contactor":{ + "state":{ + "hlc_target":"0", + "actual":"1", + "target":"1" + }, + "error":"0" + }, + "metering":{ + "meter":{ + "serialnumber":"21031835", + "type":"klefr", + "available":"1" + }, + "eichrecht_protocol":"none", + "power":{ + "active":{ + "ac":{ + "l1":{ + "actual":"10750" + }, + "l2":{ + "actual":"10730" + }, + "l3":{ + "actual":"10440" + } + } + }, + "active_total":{ + "actual":"31920" + } + }, + "current":{ + "ac":{ + "l1":{ + "actual":"5000" + }, + "l2":{ + "actual":"5000" + }, + "l3":{ + "actual":"4770" + } + } + }, + "energy":{ + "active_total":{ + "actual":"4658050" + }, + "active_export":{ + "actual":"0" + }, + "active_import":{ + "actual":"4658050" + } + } + }, + "emergency_shutdown":"0", + "rcd":{ + "feedback":{ + "available":"1" + }, + "state":{ + "actual":"1" + }, + "recloser":{ + "available":"0" + } + }, + "plug_lock":{ + "state":{ + "actual":"1", + "target":"1" + }, + "error":"0" + }, + "availability":{ + "actual":"operative" + }, + "cp":{ + "pwm_state":{ + "actual":"1" + }, + "state":"C", + "duty_cycle":"10.00" + }, + "rfid":{ + "available":"0", + "authorizereq":"" + }, + "diode_present":"1", + "cable_current_limit":"-1", + "ready_for_slac":"0", + "ev_present":"1", + "ventilation":{ + "state":{ + "actual":"0" + }, + "available":"0" + }, + "charging":"1", + "grid_current_limit":"6" + } + } + } + """; } diff --git a/io.openems.edge.evcs.hardybarth/test/io/openems/edge/evcs/hardybarth/MyConfig.java b/io.openems.edge.evcs.hardybarth/test/io/openems/edge/evcs/hardybarth/MyConfig.java index 98cc8717cff..d3a6ee1c74a 100644 --- a/io.openems.edge.evcs.hardybarth/test/io/openems/edge/evcs/hardybarth/MyConfig.java +++ b/io.openems.edge.evcs.hardybarth/test/io/openems/edge/evcs/hardybarth/MyConfig.java @@ -1,6 +1,7 @@ package io.openems.edge.evcs.hardybarth; import io.openems.common.test.AbstractComponentConfig; +import io.openems.edge.evcs.api.PhaseRotation; @SuppressWarnings("all") public class MyConfig extends AbstractComponentConfig implements Config { @@ -10,6 +11,7 @@ protected static class Builder { private String ip; private int minHwCurrent; private int maxHwCurrent; + private PhaseRotation phaseRotation; private Builder() { } @@ -34,6 +36,11 @@ public Builder setMaxHwCurrent(int maxHwCurrent) { return this; } + public Builder setPhaseRotation(PhaseRotation phaseRotation) { + this.phaseRotation = phaseRotation; + return this; + } + public MyConfig build() { return new MyConfig(this); } @@ -74,4 +81,9 @@ public int minHwCurrent() { public int maxHwCurrent() { return this.builder.maxHwCurrent; } + + @Override + public PhaseRotation phaseRotation() { + return this.builder.phaseRotation; + } } \ No newline at end of file diff --git a/io.openems.edge.evcs.keba.kecontact/bnd.bnd b/io.openems.edge.evcs.keba.kecontact/bnd.bnd index c1057f1716f..507c805f4d6 100644 --- a/io.openems.edge.evcs.keba.kecontact/bnd.bnd +++ b/io.openems.edge.evcs.keba.kecontact/bnd.bnd @@ -7,7 +7,8 @@ Bundle-Version: 1.0.0.${tstamp} ${buildpath},\ io.openems.common,\ io.openems.edge.common,\ - io.openems.edge.evcs.api + io.openems.edge.evcs.api,\ + io.openems.edge.meter.api,\ -testpath: \ ${testpath} diff --git a/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/Config.java b/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/Config.java index 66e9e587fde..5bed47bdad4 100644 --- a/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/Config.java +++ b/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/Config.java @@ -3,6 +3,8 @@ import org.osgi.service.metatype.annotations.AttributeDefinition; import org.osgi.service.metatype.annotations.ObjectClassDefinition; +import io.openems.edge.evcs.api.PhaseRotation; + @ObjectClassDefinition(name = "EVCS KEBA KeContact", // description = "Implements the KEBA KeContact P20/P30 electric vehicle charging station.") @interface Config { @@ -25,6 +27,9 @@ @AttributeDefinition(name = "Minimum power", description = "Minimum current of the Charger in mA.", required = true) int minHwCurrent() default 6000; + @AttributeDefinition(name = "Phase Rotation", description = "Apply standard or rotated wiring") + PhaseRotation phaseRotation() default PhaseRotation.L1_L2_L3; + @AttributeDefinition(name = "Use display?", description = "Activates the KEBA display to show the current power or states.", required = true) boolean useDisplay() default true; diff --git a/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/EvcsKebaKeContact.java b/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/EvcsKebaKeContact.java index 1b4e637e250..97f8a70c07c 100644 --- a/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/EvcsKebaKeContact.java +++ b/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/EvcsKebaKeContact.java @@ -16,8 +16,10 @@ import io.openems.edge.evcs.api.Evcs; import io.openems.edge.evcs.api.ManagedEvcs; import io.openems.edge.evcs.api.Status; +import io.openems.edge.meter.api.ElectricityMeter; -public interface EvcsKebaKeContact extends ManagedEvcs, Evcs, OpenemsComponent, EventHandler, ModbusSlave { +public interface EvcsKebaKeContact + extends ManagedEvcs, Evcs, ElectricityMeter, OpenemsComponent, EventHandler, ModbusSlave { public static final int UDP_PORT = 7090; @@ -85,34 +87,9 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { /* * Report 3 */ - VOLTAGE_L1(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT) // - .text("Voltage on L1")), // - VOLTAGE_L2(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT) // - .text("Voltage on L2")), // - VOLTAGE_L3(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT) // - .text("Voltage on L3")), // - CURRENT_L1(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.MILLIAMPERE) // - .text("Current on L1")), // - CURRENT_L2(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.MILLIAMPERE) // - .text("Current on L2")), // - CURRENT_L3(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.MILLIAMPERE) // - .text("Current on L3")), // - ACTUAL_POWER(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.MILLIWATT) // - .text("Total real power")), // COS_PHI(Doc.of(OpenemsType.INTEGER) // .unit(Unit.PERCENT) // .text("Power factor")), // - ENERGY_TOTAL(Doc.of(OpenemsType.LONG) // - .unit(Unit.CUMULATED_WATT_HOURS) // - .text("Total power consumption (persistent) without current loading session. " - + "Is summed up after each completed charging session")), // DIP_SWITCH_ERROR_1_3_NOT_SET_FOR_COMM(Doc.of(Level.FAULT) // .debounce(5, Debounce.TRUE_VALUES_IN_A_ROW_TO_SET_TRUE) // .text("Dip-Switch 1.3. for communication must be on")), // @@ -179,19 +156,10 @@ private ModbusSlaveNatureTable getModbusSlaveNatureTable(AccessMode accessMode) .channel(72, EvcsKebaKeContact.ChannelId.CURR_FAILSAFE, ModbusType.UINT16) .channel(73, EvcsKebaKeContact.ChannelId.TIMEOUT_FAILSAFE, ModbusType.UINT16) .channel(74, EvcsKebaKeContact.ChannelId.CURR_TIMER, ModbusType.UINT16) - .channel(75, EvcsKebaKeContact.ChannelId.TIMEOUT_CT, ModbusType.UINT16).uint16Reserved(76) + .channel(75, EvcsKebaKeContact.ChannelId.TIMEOUT_CT, ModbusType.UINT16) // + .uint16Reserved(76) // .channel(77, EvcsKebaKeContact.ChannelId.OUTPUT, ModbusType.UINT16) .channel(78, EvcsKebaKeContact.ChannelId.INPUT, ModbusType.UINT16) - - // Report 3 - .channel(79, EvcsKebaKeContact.ChannelId.VOLTAGE_L1, ModbusType.UINT16) - .channel(80, EvcsKebaKeContact.ChannelId.VOLTAGE_L2, ModbusType.UINT16) - .channel(81, EvcsKebaKeContact.ChannelId.VOLTAGE_L3, ModbusType.UINT16) - .channel(82, EvcsKebaKeContact.ChannelId.CURRENT_L1, ModbusType.UINT16) - .channel(83, EvcsKebaKeContact.ChannelId.CURRENT_L2, ModbusType.UINT16) - .channel(84, EvcsKebaKeContact.ChannelId.CURRENT_L3, ModbusType.UINT16) - .channel(85, EvcsKebaKeContact.ChannelId.ACTUAL_POWER, ModbusType.UINT16) - .channel(86, EvcsKebaKeContact.ChannelId.COS_PHI, ModbusType.UINT16).uint16Reserved(87) - .channel(88, EvcsKebaKeContact.ChannelId.ENERGY_TOTAL, ModbusType.UINT16).build(); + .build(); } } diff --git a/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/EvcsKebaKeContactImpl.java b/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/EvcsKebaKeContactImpl.java index c036301b188..73452b60b4b 100644 --- a/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/EvcsKebaKeContactImpl.java +++ b/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/EvcsKebaKeContactImpl.java @@ -29,11 +29,13 @@ import io.openems.edge.common.modbusslave.ModbusSlave; import io.openems.edge.evcs.api.AbstractManagedEvcsComponent; import io.openems.edge.evcs.api.ChargingType; +import io.openems.edge.evcs.api.DeprecatedEvcs; import io.openems.edge.evcs.api.Evcs; import io.openems.edge.evcs.api.EvcsPower; import io.openems.edge.evcs.api.ManagedEvcs; import io.openems.edge.evcs.api.Phases; import io.openems.edge.evcs.keba.kecontact.core.EvcsKebaKeContactCore; +import io.openems.edge.meter.api.ElectricityMeter; @Designate(ocd = Config.class, factory = true) @Component(// @@ -44,12 +46,13 @@ @EventTopics({ // EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE, // }) -public class EvcsKebaKeContactImpl extends AbstractManagedEvcsComponent - implements EvcsKebaKeContact, ManagedEvcs, Evcs, OpenemsComponent, EventHandler, ModbusSlave { +public class EvcsKebaKeContactImpl extends AbstractManagedEvcsComponent implements EvcsKebaKeContact, ManagedEvcs, Evcs, + DeprecatedEvcs, ElectricityMeter, OpenemsComponent, EventHandler, ModbusSlave { + + protected final ReadHandler readHandler = new ReadHandler(this); private final Logger log = LoggerFactory.getLogger(EvcsKebaKeContactImpl.class); private final ReadWorker readWorker = new ReadWorker(this); - private final ReadHandler readHandler = new ReadHandler(this); @Reference private EvcsPower evcsPower; @@ -65,10 +68,21 @@ public class EvcsKebaKeContactImpl extends AbstractManagedEvcsComponent public EvcsKebaKeContactImpl() { super(// OpenemsComponent.ChannelId.values(), // + ElectricityMeter.ChannelId.values(), // ManagedEvcs.ChannelId.values(), // Evcs.ChannelId.values(), // + DeprecatedEvcs.ChannelId.values(), // EvcsKebaKeContact.ChannelId.values() // ); + DeprecatedEvcs.copyToDeprecatedEvcsChannels(this); + ElectricityMeter.calculateSumCurrentFromPhases(this); + ElectricityMeter.calculateAverageVoltageFromPhases(this); + + // Set ReactivePower defaults + this._setReactivePower(0); + this._setReactivePowerL1(0); + this._setReactivePowerL2(0); + this._setReactivePowerL3(0); } @Activate diff --git a/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/ReadHandler.java b/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/ReadHandler.java index 3fafa14550a..0bcb9a43364 100644 --- a/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/ReadHandler.java +++ b/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/ReadHandler.java @@ -1,19 +1,27 @@ package io.openems.edge.evcs.keba.kecontact; +import static io.openems.common.utils.JsonUtils.getAsOptionalInt; +import static io.openems.common.utils.JsonUtils.getAsOptionalLong; +import static io.openems.common.utils.JsonUtils.getAsOptionalString; +import static io.openems.edge.evcs.api.Evcs.evaluatePhaseCount; +import static io.openems.edge.evcs.api.Phases.THREE_PHASE; +import static io.openems.edge.evcs.api.Status.CHARGING; +import static java.lang.Math.round; + import java.math.BigInteger; import java.util.function.Consumer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.utils.JsonUtils; import io.openems.edge.common.channel.Channel; +import io.openems.edge.common.channel.ChannelId; import io.openems.edge.evcs.api.Evcs; -import io.openems.edge.evcs.api.Phases; +import io.openems.edge.evcs.api.PhaseRotation.RotatedPhases; import io.openems.edge.evcs.api.Status; /** @@ -34,240 +42,258 @@ public ReadHandler(EvcsKebaKeContactImpl parent) { @Override public void accept(String message) { + final var keba = this.parent; if (message.startsWith("TCH-OK")) { this.log.debug("KEBA confirmed reception of command: TCH-OK"); - this.parent.triggerQuery(); + keba.triggerQuery(); + return; + } - } else if (message.startsWith("TCH-ERR")) { + if (message.startsWith("TCH-ERR")) { this.log.warn("KEBA reported command error: TCH-ERR"); - this.parent.triggerQuery(); + keba.triggerQuery(); + return; + } - } else { - JsonElement jsonMessageElement; - try { - jsonMessageElement = JsonUtils.parse(message); - } catch (OpenemsNamedException e) { - this.log.error("Error while parsing KEBA message: " + e.getMessage()); - return; + keba.logInfoInDebugmode(this.log, message); + + // Parse JsonObject + final JsonObject j; + try { + j = JsonUtils.parseToJsonObject(message); + } catch (OpenemsNamedException e) { + this.log.error("Error while parsing KEBA message: " + e.getMessage()); + return; + } + + switch (getAsOptionalString(j, "ID").orElse("")) { + /* + * report 1 + */ + case "1" -> { + this.receiveReport1 = true; + this.setString(EvcsKebaKeContact.ChannelId.SERIAL, j, "Serial"); + this.setString(EvcsKebaKeContact.ChannelId.FIRMWARE, j, "Firmware"); + this.setInt(EvcsKebaKeContact.ChannelId.COM_MODULE, j, "COM-module"); + + // Dip-Switches + var dipSwitch1 = getAsOptionalString(j, "DIP-Sw1"); + var dipSwitch2 = getAsOptionalString(j, "DIP-Sw2"); + + if (dipSwitch1.isPresent() && dipSwitch2.isPresent()) { + this.checkDipSwitchSettings(dipSwitch1.get(), dipSwitch2.get()); } - this.parent.logInfoInDebugmode(this.log, message); - - var jsonMessage = jsonMessageElement.getAsJsonObject(); - // JsonUtils.prettyPrint(jMessage); - var idOpt = JsonUtils.getAsOptionalString(jsonMessage, "ID"); - if (idOpt.isPresent()) { - // message with ID - var id = idOpt.get(); - if (id.equals("1")) { - /* - * Reply to report 1 - */ - this.receiveReport1 = true; - this.setString(EvcsKebaKeContact.ChannelId.SERIAL, jsonMessage, "Serial"); - this.setString(EvcsKebaKeContact.ChannelId.FIRMWARE, jsonMessage, "Firmware"); - this.setInt(EvcsKebaKeContact.ChannelId.COM_MODULE, jsonMessage, "COM-module"); - - // Dip-Switches - var dipSwitch1 = JsonUtils.getAsOptionalString(jsonMessage, "DIP-Sw1"); - var dipSwitch2 = JsonUtils.getAsOptionalString(jsonMessage, "DIP-Sw2"); - - if (dipSwitch1.isPresent() && dipSwitch2.isPresent()) { - this.checkDipSwitchSettings(dipSwitch1.get(), dipSwitch2.get()); - } - // Product information - var product = JsonUtils.getAsOptionalString(jsonMessage, "Product"); - if (product.isPresent()) { - this.parent.channel(EvcsKebaKeContact.ChannelId.PRODUCT).setNextValue(product.get()); - this.checkProductInformation(product.get()); - } + // Product information + var product = getAsOptionalString(j, "Product"); + keba.channel(EvcsKebaKeContact.ChannelId.PRODUCT).setNextValue(product.orElse(null)); + if (product.isPresent()) { + this.checkProductInformation(product.get()); + } + } - } else if (id.equals("2")) { - /* - * Reply to report 2 - */ - this.receiveReport2 = true; - this.setInt(EvcsKebaKeContact.ChannelId.STATUS_KEBA, jsonMessage, "State"); - - // Value "setenergy" not used, because it is reset by the currtime 0 1 command - - // Set Evcs status - Channel stateChannel = this.parent.channel(EvcsKebaKeContact.ChannelId.STATUS_KEBA); - Channel plugChannel = this.parent.channel(EvcsKebaKeContact.ChannelId.PLUG); - - Plug plug = plugChannel.value().asEnum(); - Status status = stateChannel.value().asEnum(); - if (plug.equals(Plug.PLUGGED_ON_EVCS_AND_ON_EV_AND_LOCKED)) { - - // Charging is rejected (by the Software) if the plug is connected but the EVCS - // still not ready for charging. - if (status.equals(Status.NOT_READY_FOR_CHARGING)) { - status = Status.CHARGING_REJECTED; - } - - // Charging is Finished if 'Plug' is connected, State was charging or already - // finished and the EVCS is still ready for charging. - var evcsStatus = this.parent.getStatus(); - switch (evcsStatus) { - case CHARGING_REJECTED: - case ENERGY_LIMIT_REACHED: - case ERROR: - case NOT_READY_FOR_CHARGING: - case STARTING: - case UNDEFINED: - break; - case READY_FOR_CHARGING: - case CHARGING: - case CHARGING_FINISHED: - if (status.equals(Status.READY_FOR_CHARGING) - && this.parent.getSetChargePowerLimit().orElse(0) > 0) { - status = Status.CHARGING_FINISHED; - } - break; - } - - /* - * Check if the maximum energy limit is reached, informs the user and sets the - * status - */ - int limit = this.parent.getSetEnergyLimit().orElse(0); - int energy = this.parent.getEnergySession().orElse(0); - if (energy >= limit && limit != 0) { - status = Status.ENERGY_LIMIT_REACHED; - } - } else { - // Plug not fully connected - status = Status.NOT_READY_FOR_CHARGING; - } + /* + * report 2 + */ + case "2" -> { + this.receiveReport2 = true; + this.setInt(EvcsKebaKeContact.ChannelId.STATUS_KEBA, j, "State"); - this.parent._setStatus(status); - var errorState = status == Status.ERROR == true; - this.parent.channel(EvcsKebaKeContact.ChannelId.CHARGINGSTATION_STATE_ERROR) - .setNextValue(errorState); - - this.setInt(EvcsKebaKeContact.ChannelId.ERROR_1, jsonMessage, "Error1"); - this.setInt(EvcsKebaKeContact.ChannelId.ERROR_2, jsonMessage, "Error2"); - this.setInt(EvcsKebaKeContact.ChannelId.PLUG, jsonMessage, "Plug"); - this.setBoolean(EvcsKebaKeContact.ChannelId.ENABLE_SYS, jsonMessage, "Enable sys"); - this.setBoolean(EvcsKebaKeContact.ChannelId.ENABLE_USER, jsonMessage, "Enable user"); - this.setInt(EvcsKebaKeContact.ChannelId.MAX_CURR_PERCENT, jsonMessage, "Max curr %"); - this.setInt(EvcsKebaKeContact.ChannelId.CURR_FAILSAFE, jsonMessage, "Curr FS"); - this.setInt(EvcsKebaKeContact.ChannelId.TIMEOUT_FAILSAFE, jsonMessage, "Tmo FS"); - this.setInt(EvcsKebaKeContact.ChannelId.CURR_TIMER, jsonMessage, "Curr timer"); - this.setInt(EvcsKebaKeContact.ChannelId.TIMEOUT_CT, jsonMessage, "Tmo CT"); - this.setBoolean(EvcsKebaKeContact.ChannelId.OUTPUT, jsonMessage, "Output"); - this.setBoolean(EvcsKebaKeContact.ChannelId.INPUT, jsonMessage, "Input"); - this.setInt(EvcsKebaKeContact.ChannelId.MAX_CURR, jsonMessage, "Curr HW"); - this.setInt(EvcsKebaKeContact.ChannelId.CURR_USER, jsonMessage, "Curr user"); - - } else if (id.equals("3")) { - /* - * Reply to report 3 - */ - this.receiveReport3 = true; - this.setInt(EvcsKebaKeContact.ChannelId.VOLTAGE_L1, jsonMessage, "U1"); - this.setInt(EvcsKebaKeContact.ChannelId.VOLTAGE_L2, jsonMessage, "U2"); - this.setInt(EvcsKebaKeContact.ChannelId.VOLTAGE_L3, jsonMessage, "U3"); - this.setInt(EvcsKebaKeContact.ChannelId.CURRENT_L1, jsonMessage, "I1"); - this.setInt(EvcsKebaKeContact.ChannelId.CURRENT_L2, jsonMessage, "I2"); - this.setInt(EvcsKebaKeContact.ChannelId.CURRENT_L3, jsonMessage, "I3"); - this.setInt(EvcsKebaKeContact.ChannelId.ACTUAL_POWER, jsonMessage, "P"); - this.setInt(EvcsKebaKeContact.ChannelId.COS_PHI, jsonMessage, "PF"); - - long totalEnergy = Math - .round(JsonUtils.getAsOptionalLong(jsonMessage, "E total").orElse(0L) * 0.1F); - this.parent.channel(EvcsKebaKeContact.ChannelId.ENERGY_TOTAL).setNextValue(totalEnergy); - this.parent._setActiveConsumptionEnergy(totalEnergy); - - // Set the count of the Phases that are currently used - Channel currentL1 = this.parent.channel(EvcsKebaKeContact.ChannelId.CURRENT_L1); - Channel currentL2 = this.parent.channel(EvcsKebaKeContact.ChannelId.CURRENT_L2); - Channel currentL3 = this.parent.channel(EvcsKebaKeContact.ChannelId.CURRENT_L3); - var currentSum = currentL1.getNextValue().orElse(0) + currentL2.getNextValue().orElse(0) - + currentL3.getNextValue().orElse(0); - - if (currentSum > 300) { - - this.parent._setStatus(Status.CHARGING); - var phases = 0; - - if (currentL1.getNextValue().orElse(0) >= 100) { - phases += 1; - } - if (currentL2.getNextValue().orElse(0) >= 100) { - phases += 1; - } - if (currentL3.getNextValue().orElse(0) >= 100) { - phases += 1; - } - this.parent._setPhases(phases); - - this.parent.logInfoInDebugmode(this.log, "Used phases: " + phases); - } + // Value "setenergy" not used, because it is reset by the currtime 0 1 command - /* - * Set FIXED_MAXIMUM_HARDWARE_POWER of Evcs - this is setting internally the - * dynamically calculated MAXIMUM_HARDWARE_POWER including the current used - * phases. - */ - Channel maxDipSwitchLimitChannel = this.parent - .channel(EvcsKebaKeContact.ChannelId.DIP_SWITCH_MAX_HW); - int maxDipSwitchPowerLimit = Math.round( - maxDipSwitchLimitChannel.value().orElse(Evcs.DEFAULT_MAXIMUM_HARDWARE_CURRENT) / 1000f) - * Evcs.DEFAULT_VOLTAGE * Phases.THREE_PHASE.getValue(); - - // Minimum of hardware setting and component configuration will be set. - int maximumHardwareLimit = Math.min(maxDipSwitchPowerLimit, - this.parent.getConfiguredMaximumHardwarePower()); - - this.parent._setFixedMaximumHardwarePower(maximumHardwareLimit); - - /* - * Set FIXED_MINIMUM_HARDWARE_POWER of Evcs - this is setting internally the - * dynamically calculated MINIMUM_HARDWARE_POWER including the current used - * phases. - */ - this.parent._setFixedMinimumHardwarePower(this.parent.getConfiguredMinimumHardwarePower()); - - /* - * Set CHARGE_POWER of Evcs - */ - var powerMw = JsonUtils.getAsOptionalInt(jsonMessage, "P"); // in [mW] - Integer power = null; - if (powerMw.isPresent()) { - power = powerMw.get() / 1000; // convert to [W] - } - this.parent.channel(Evcs.ChannelId.CHARGE_POWER).setNextValue(power); + // Set Evcs status + Channel stateChannel = keba.channel(EvcsKebaKeContact.ChannelId.STATUS_KEBA); + Channel plugChannel = keba.channel(EvcsKebaKeContact.ChannelId.PLUG); + + Plug plug = plugChannel.value().asEnum(); + Status status = stateChannel.value().asEnum(); + if (plug.equals(Plug.PLUGGED_ON_EVCS_AND_ON_EV_AND_LOCKED)) { - /* - * Set ENERGY_SESSION of Evcs - */ - this.parent.channel(Evcs.ChannelId.ENERGY_SESSION) - .setNextValue(JsonUtils.getAsOptionalInt(jsonMessage, "E pres").orElse(0) * 0.1); + // Charging is rejected (by the Software) if the plug is connected but the EVCS + // still not ready for charging. + if (status.equals(Status.NOT_READY_FOR_CHARGING)) { + status = Status.CHARGING_REJECTED; + } + + // Charging is Finished if 'Plug' is connected, State was charging or already + // finished and the EVCS is still ready for charging. + switch (keba.getStatus()) { + case CHARGING_REJECTED: + case ENERGY_LIMIT_REACHED: + case ERROR: + case NOT_READY_FOR_CHARGING: + case STARTING: + case UNDEFINED: + break; + case READY_FOR_CHARGING: + case CHARGING: + case CHARGING_FINISHED: + if (status.equals(Status.READY_FOR_CHARGING) && keba.getSetChargePowerLimit().orElse(0) > 0) { + status = Status.CHARGING_FINISHED; + } + break; } - } else { /* - * message without ID -> UDP broadcast + * Check if the maximum energy limit is reached, informs the user and sets the + * status */ - if (jsonMessage.has("State")) { - this.setInt(EvcsKebaKeContact.ChannelId.STATUS_KEBA, jsonMessage, "State"); - } - if (jsonMessage.has("Plug")) { - this.setInt(EvcsKebaKeContact.ChannelId.PLUG, jsonMessage, "Plug"); - } - if (jsonMessage.has("Input")) { - this.setBoolean(EvcsKebaKeContact.ChannelId.INPUT, jsonMessage, "Input"); - } - if (jsonMessage.has("Enable sys")) { - this.setBoolean(EvcsKebaKeContact.ChannelId.ENABLE_SYS, jsonMessage, "Enable sys"); - } - if (jsonMessage.has("E pres")) { - this.parent.channel(Evcs.ChannelId.ENERGY_SESSION) - .setNextValue(JsonUtils.getAsOptionalInt(jsonMessage, "E pres").orElse(0) * 0.1); + int limit = keba.getSetEnergyLimit().orElse(0); + int energy = keba.getEnergySession().orElse(0); + if (energy >= limit && limit != 0) { + status = Status.ENERGY_LIMIT_REACHED; } + } else { + // Plug not fully connected + status = Status.NOT_READY_FOR_CHARGING; } + + keba._setStatus(status); + var errorState = status == Status.ERROR == true; + keba.channel(EvcsKebaKeContact.ChannelId.CHARGINGSTATION_STATE_ERROR).setNextValue(errorState); + + this.setInt(EvcsKebaKeContact.ChannelId.ERROR_1, j, "Error1"); + this.setInt(EvcsKebaKeContact.ChannelId.ERROR_2, j, "Error2"); + this.setInt(EvcsKebaKeContact.ChannelId.PLUG, j, "Plug"); + this.setBoolean(EvcsKebaKeContact.ChannelId.ENABLE_SYS, j, "Enable sys"); + this.setBoolean(EvcsKebaKeContact.ChannelId.ENABLE_USER, j, "Enable user"); + this.setInt(EvcsKebaKeContact.ChannelId.MAX_CURR_PERCENT, j, "Max curr %"); + this.setInt(EvcsKebaKeContact.ChannelId.CURR_FAILSAFE, j, "Curr FS"); + this.setInt(EvcsKebaKeContact.ChannelId.TIMEOUT_FAILSAFE, j, "Tmo FS"); + this.setInt(EvcsKebaKeContact.ChannelId.CURR_TIMER, j, "Curr timer"); + this.setInt(EvcsKebaKeContact.ChannelId.TIMEOUT_CT, j, "Tmo CT"); + this.setBoolean(EvcsKebaKeContact.ChannelId.OUTPUT, j, "Output"); + this.setBoolean(EvcsKebaKeContact.ChannelId.INPUT, j, "Input"); + this.setInt(EvcsKebaKeContact.ChannelId.MAX_CURR, j, "Curr HW"); + this.setInt(EvcsKebaKeContact.ChannelId.CURR_USER, j, "Curr user"); + } + + /* + * report 3 + */ + case "3" -> { + /* + * Reply to report 3 + */ + this.receiveReport3 = true; + + // Voltage + final var voltageL1 = getAsOptionalInt(j, "U1").map(v -> v != 0 ? v * 1000 : null).orElse(null); + final var voltageL2 = getAsOptionalInt(j, "U2").map(v -> v != 0 ? v * 1000 : null).orElse(null); + final var voltageL3 = getAsOptionalInt(j, "U3").map(v -> v != 0 ? v * 1000 : null).orElse(null); + + // Current + final var currentL1 = getAsOptionalInt(j, "I1").orElse(0).intValue(); + final var currentL2 = getAsOptionalInt(j, "I2").orElse(0).intValue(); + final var currentL3 = getAsOptionalInt(j, "I3").orElse(0).intValue(); + + // Power + final var activePower = getAsOptionalInt(j, "P") // + .map(p -> p / 1000) // convert [mW] to [W] + .orElse(null); + keba._setActivePower(activePower); + + // Round power per phase and apply rotated phases + var appp = ActivePowerPerPhase.from(activePower, // + voltageL1, currentL1, voltageL2, currentL2, voltageL3, currentL3); + var rp = RotatedPhases.from(keba.config.phaseRotation(), // + voltageL1, currentL1, appp.activePowerL1, // + voltageL2, currentL2, appp.activePowerL2, // + voltageL3, currentL3, appp.activePowerL3); + keba._setVoltageL1(rp.voltageL1()); + keba._setVoltageL2(rp.voltageL2()); + keba._setVoltageL3(rp.voltageL3()); + keba._setCurrentL1(rp.currentL1()); + keba._setCurrentL2(rp.currentL2()); + keba._setCurrentL3(rp.currentL3()); + keba._setActivePowerL1(rp.activePowerL1()); + keba._setActivePowerL2(rp.activePowerL2()); + keba._setActivePowerL3(rp.activePowerL3()); + + // Energy + keba._setActiveProductionEnergy(// + getAsOptionalLong(j, "E total") // + .map(e -> round(e * 0.1F)) // + .orElse(null)); + keba._setEnergySession(// + getAsOptionalInt(j, "E pres") // + .map(e -> round(e * 0.1F)) // + .orElse(null)); + + // TODO use COS_PHI to calculate ReactivePower + this.setInt(EvcsKebaKeContact.ChannelId.COS_PHI, j, "PF"); + + final var phases = evaluatePhaseCount(appp.activePowerL1, appp.activePowerL2, appp.activePowerL3); + keba._setPhases(phases); + if (phases != null) { + keba.logInfoInDebugmode(this.log, "Used phases: " + phases); + keba._setStatus(CHARGING); + } + + /* + * Set FIXED_MAXIMUM_HARDWARE_POWER of Evcs - this is setting internally the + * dynamically calculated MAXIMUM_HARDWARE_POWER including the current used + * phases. + */ + Channel maxDipSwitchLimitChannel = keba.channel(EvcsKebaKeContact.ChannelId.DIP_SWITCH_MAX_HW); + int maxDipSwitchPowerLimit = round(maxDipSwitchLimitChannel.value() // + .orElse(Evcs.DEFAULT_MAXIMUM_HARDWARE_CURRENT) / 1000f) * Evcs.DEFAULT_VOLTAGE + * THREE_PHASE.getValue(); + + // Minimum of hardware setting and component configuration will be set. + int maximumHardwareLimit = Math.min(maxDipSwitchPowerLimit, keba.getConfiguredMaximumHardwarePower()); + + keba._setFixedMaximumHardwarePower(maximumHardwareLimit); + + /* + * Set FIXED_MINIMUM_HARDWARE_POWER of Evcs - this is setting internally the + * dynamically calculated MINIMUM_HARDWARE_POWER including the current used + * phases. + */ + keba._setFixedMinimumHardwarePower(keba.getConfiguredMinimumHardwarePower()); + } + + /* + * message without ID -> UDP broadcast + */ + default -> { + if (j.has("State")) { + this.setInt(EvcsKebaKeContact.ChannelId.STATUS_KEBA, j, "State"); + } + if (j.has("Plug")) { + this.setInt(EvcsKebaKeContact.ChannelId.PLUG, j, "Plug"); + } + if (j.has("Input")) { + this.setBoolean(EvcsKebaKeContact.ChannelId.INPUT, j, "Input"); + } + if (j.has("Enable sys")) { + this.setBoolean(EvcsKebaKeContact.ChannelId.ENABLE_SYS, j, "Enable sys"); + } + if (j.has("E pres")) { + keba._setEnergySession(// + getAsOptionalInt(j, "E pres") // + .map(e -> round(e * 0.1F)) // + .orElse(null)); + } + } + } + } + + public record ActivePowerPerPhase(Integer activePowerL1, Integer activePowerL2, Integer activePowerL3) { + protected static ActivePowerPerPhase from(Integer activePowerSum, Integer voltageL1, int currentL1, + Integer voltageL2, int currentL2, Integer voltageL3, int currentL3) { + if (activePowerSum == null) { + return new ActivePowerPerPhase(null, null, null); + } + + var pL1 = voltageL1 != null ? voltageL1 / 1000 * currentL1 : 0; + var pL2 = voltageL2 != null ? voltageL2 / 1000 * currentL2 : 0; + var pL3 = voltageL3 != null ? voltageL3 / 1000 * currentL3 : 0; + var pSum = pL1 + pL2 + pL3; + var factor = activePowerSum / (float) pSum; // distribute power to match sum + + return new ActivePowerPerPhase(round(pL1 * factor), round(pL2 * factor), round(pL3 * factor)); } } @@ -318,29 +344,15 @@ private void checkDipSwitchSettings(String dipSwitch1, String dipSwitch2) { this.setnextStateChannelValue(EvcsKebaKeContact.ChannelId.DIP_SWITCH_INFO_2_8_SET_FOR_INSTALLATION, setState); // Set Channel for the configured maximum limit in mA - Integer hwLimit = null; - var hwLimitDips = dipSwitch1.substring(5); - - switch (hwLimitDips) { - case "000": - hwLimit = 10_000; - break; - case "100": - hwLimit = 13_000; - break; - case "010": - hwLimit = 16_000; - break; - case "110": - hwLimit = 20_000; - break; - case "001": - hwLimit = 25_000; - break; - case "101": - hwLimit = 32_000; - break; - } + var hwLimit = switch (dipSwitch1.substring(5)) { + case "000" -> 10_000; + case "100" -> 13_000; + case "010" -> 16_000; + case "110" -> 20_000; + case "001" -> 25_000; + case "101" -> 32_000; + default -> null; + }; this.parent.channel(EvcsKebaKeContact.ChannelId.DIP_SWITCH_MAX_HW).setNextValue(hwLimit); } @@ -383,20 +395,20 @@ protected static String hexStringToBinaryString(String dipSwitches) { return binaryString; } - private void set(EvcsKebaKeContact.ChannelId channelId, Object value) { + private void set(ChannelId channelId, Object value) { this.parent.channel(channelId).setNextValue(value); } - private void setString(EvcsKebaKeContact.ChannelId channelId, JsonObject jMessage, String name) { - this.set(channelId, JsonUtils.getAsOptionalString(jMessage, name).orElse(null)); + private void setString(ChannelId channelId, JsonObject jMessage, String name) { + this.set(channelId, getAsOptionalString(jMessage, name).orElse(null)); } - private void setInt(EvcsKebaKeContact.ChannelId channelId, JsonObject jMessage, String name) { - this.set(channelId, JsonUtils.getAsOptionalInt(jMessage, name).orElse(null)); + private void setInt(ChannelId channelId, JsonObject jMessage, String name) { + this.set(channelId, getAsOptionalInt(jMessage, name).orElse(null)); } - private void setBoolean(EvcsKebaKeContact.ChannelId channelId, JsonObject jMessage, String name) { - var enableSysOpt = JsonUtils.getAsOptionalInt(jMessage, name); + private void setBoolean(ChannelId channelId, JsonObject jMessage, String name) { + var enableSysOpt = getAsOptionalInt(jMessage, name); if (enableSysOpt.isPresent()) { this.set(channelId, enableSysOpt.get() == 1); } else { diff --git a/io.openems.edge.evcs.keba.kecontact/test/io/openems/edge/evcs/keba/kecontact/EvcsKebaKeContactImplTest.java b/io.openems.edge.evcs.keba.kecontact/test/io/openems/edge/evcs/keba/kecontact/EvcsKebaKeContactImplTest.java index 68b6c75ecd2..db60737ebb8 100644 --- a/io.openems.edge.evcs.keba.kecontact/test/io/openems/edge/evcs/keba/kecontact/EvcsKebaKeContactImplTest.java +++ b/io.openems.edge.evcs.keba.kecontact/test/io/openems/edge/evcs/keba/kecontact/EvcsKebaKeContactImplTest.java @@ -1,27 +1,143 @@ package io.openems.edge.evcs.keba.kecontact; +import static io.openems.edge.evcs.api.PhaseRotation.L2_L3_L1; +import static io.openems.edge.evcs.api.Status.CHARGING_REJECTED; +import static io.openems.edge.evcs.keba.kecontact.Plug.PLUGGED_ON_EVCS_AND_ON_EV_AND_LOCKED; + import org.junit.Test; +import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.evcs.api.Evcs; import io.openems.edge.evcs.keba.kecontact.core.EvcsKebaKeContactCoreImpl; import io.openems.edge.evcs.test.DummyEvcsPower; +import io.openems.edge.meter.api.ElectricityMeter; public class EvcsKebaKeContactImplTest { - private static final String COMPONENT_ID = "evcs0"; - @Test public void test() throws Exception { - new ComponentTest(new EvcsKebaKeContactImpl()) // + var sut = new EvcsKebaKeContactImpl(); + var rh = sut.readHandler; + new ComponentTest(sut) // .addReference("evcsPower", new DummyEvcsPower()) // .addReference("kebaKeContactCore", new EvcsKebaKeContactCoreImpl()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // + .setId("evcs0") // .setDebugMode(false) // .setIp("172.0.0.1") // .setMinHwCurrent(6000) // + .setPhaseRotation(L2_L3_L1) // .setUseDisplay(false) // - .build()); // + .build()) // + + .next(new TestCase() // + .onBeforeProcessImage(() -> rh.accept(REPORT_1)) // + .output(EvcsKebaKeContact.ChannelId.SERIAL, "12345678") // + .output(EvcsKebaKeContact.ChannelId.FIRMWARE, "P30 v 3.10.57 (240521-093236)") // + .output(EvcsKebaKeContact.ChannelId.COM_MODULE, "0") // + .output(EvcsKebaKeContact.ChannelId.DIP_SWITCH_1, "00100101") // + .output(EvcsKebaKeContact.ChannelId.DIP_SWITCH_2, "00000010") // + .output(EvcsKebaKeContact.ChannelId.PRODUCT, "KC-P30-EC240422-E00")) // + + .next(new TestCase() // + .onBeforeProcessImage(() -> rh.accept(REPORT_2)) // + .output(EvcsKebaKeContact.ChannelId.STATUS_KEBA, CHARGING_REJECTED) // + .output(EvcsKebaKeContact.ChannelId.ERROR_1, 0) // + .output(EvcsKebaKeContact.ChannelId.ERROR_2, 0) // + .output(EvcsKebaKeContact.ChannelId.PLUG, PLUGGED_ON_EVCS_AND_ON_EV_AND_LOCKED) // + .output(EvcsKebaKeContact.ChannelId.ENABLE_SYS, false) // + .output(EvcsKebaKeContact.ChannelId.ENABLE_USER, false) // + .output(EvcsKebaKeContact.ChannelId.MAX_CURR_PERCENT, 1_000) // + .output(EvcsKebaKeContact.ChannelId.CURR_FAILSAFE, 0) // + .output(EvcsKebaKeContact.ChannelId.TIMEOUT_FAILSAFE, 0) // + .output(EvcsKebaKeContact.ChannelId.CURR_TIMER, 0) // + .output(EvcsKebaKeContact.ChannelId.TIMEOUT_CT, 0) // + .output(EvcsKebaKeContact.ChannelId.OUTPUT, false) // + .output(EvcsKebaKeContact.ChannelId.INPUT, false) // + .output(EvcsKebaKeContact.ChannelId.MAX_CURR, 32_000) // + .output(EvcsKebaKeContact.ChannelId.CURR_USER, 1_0000)) // + + .next(new TestCase() // + .onBeforeProcessImage(() -> rh.accept(REPORT_3)) // + .output(ElectricityMeter.ChannelId.VOLTAGE, 227_500) // + .output(ElectricityMeter.ChannelId.VOLTAGE_L1, null) // + .output(ElectricityMeter.ChannelId.VOLTAGE_L2, 228_000) // + .output(ElectricityMeter.ChannelId.VOLTAGE_L3, 227_000) // + .output(ElectricityMeter.ChannelId.CURRENT, 9_075) // + .output(ElectricityMeter.ChannelId.CURRENT_L1, 0) // + .output(ElectricityMeter.ChannelId.CURRENT_L2, 9_075) // + .output(ElectricityMeter.ChannelId.CURRENT_L3, 0) // + .output(ElectricityMeter.ChannelId.ACTIVE_POWER, 1_866) // + .output(ElectricityMeter.ChannelId.ACTIVE_POWER_L1, 0) // + .output(ElectricityMeter.ChannelId.ACTIVE_POWER_L2, 1_866) // + .output(ElectricityMeter.ChannelId.ACTIVE_POWER_L3, 0) // + .output(ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY, 7747834L) // + .output(Evcs.ChannelId.ENERGY_SESSION, 6530) // + .output(EvcsKebaKeContact.ChannelId.COS_PHI, 905) // + + ); } + private static final String REPORT_1 = """ + { + "ID": "1", + "Product": "KC-P30-EC240422-E00", + "Serial": "12345678", + "Firmware":"P30 v 3.10.57 (240521-093236)", + "COM-module": 0, + "Backend": 0, + "timeQ": 3, + "setBoot": 0, + "DIP-Sw1": "0x25", + "DIP-Sw2": "0x02", + "Sec": 530786 + } + """; + private static final String REPORT_2 = """ + { + "ID": "2", + "State": 5, + "Error1": 0, + "Error2": 0, + "Plug": 7, + "AuthON": 0, + "Authreq": 0, + "Enable sys": 0, + "Enable user": 0, + "Max curr": 0, + "Max curr %": 1000, + "Curr HW": 32000, + "Curr user": 10000, + "Curr FS": 0, + "Tmo FS": 0, + "Curr timer": 0, + "Tmo CT": 0, + "Setenergy": 0, + "Output": 0, + "Input": 0, + "X2 phaseSwitch source": 0, + "X2 phaseSwitch": 0, + "Serial": "22054282", + "Sec": 530786 + } + """; + private static final String REPORT_3 = """ + { + "ID": "3", + "U1": 228, + "U2": 227, + "U3": 0, + "I1": 9075, + "I2": 0, + "I3": 0, + "P": 1866156, + "PF": 905, + "E pres": 65302, + "E total": 77478335, + "Serial": "22054282", + "Sec": 534926 + } + """; + } diff --git a/io.openems.edge.evcs.keba.kecontact/test/io/openems/edge/evcs/keba/kecontact/MyConfig.java b/io.openems.edge.evcs.keba.kecontact/test/io/openems/edge/evcs/keba/kecontact/MyConfig.java index 005b60b872a..6920b20339f 100644 --- a/io.openems.edge.evcs.keba.kecontact/test/io/openems/edge/evcs/keba/kecontact/MyConfig.java +++ b/io.openems.edge.evcs.keba.kecontact/test/io/openems/edge/evcs/keba/kecontact/MyConfig.java @@ -1,15 +1,17 @@ package io.openems.edge.evcs.keba.kecontact; import io.openems.common.test.AbstractComponentConfig; +import io.openems.edge.evcs.api.PhaseRotation; @SuppressWarnings("all") public class MyConfig extends AbstractComponentConfig implements Config { protected static class Builder { private String id = null; - private int minHwCurrent; private String ip; private boolean debugMode; + private int minHwCurrent; + private PhaseRotation phaseRotation; private boolean useDisplay; private Builder() { @@ -35,6 +37,11 @@ public Builder setDebugMode(boolean debugMode) { return this; } + public Builder setPhaseRotation(PhaseRotation phaseRotation) { + this.phaseRotation = phaseRotation; + return this; + } + public Builder setUseDisplay(boolean useDisplay) { this.useDisplay = useDisplay; return this; @@ -76,6 +83,11 @@ public int minHwCurrent() { return this.builder.minHwCurrent; } + @Override + public PhaseRotation phaseRotation() { + return this.builder.phaseRotation; + } + @Override public boolean useDisplay() { return this.builder.useDisplay; diff --git a/io.openems.edge.evcs.ocpp.abl/src/io/openems/edge/evcs/ocpp/abl/EvcsOcppAbl.java b/io.openems.edge.evcs.ocpp.abl/src/io/openems/edge/evcs/ocpp/abl/EvcsOcppAbl.java index 1cbcf9933a7..d76f92df33b 100644 --- a/io.openems.edge.evcs.ocpp.abl/src/io/openems/edge/evcs/ocpp/abl/EvcsOcppAbl.java +++ b/io.openems.edge.evcs.ocpp.abl/src/io/openems/edge/evcs/ocpp/abl/EvcsOcppAbl.java @@ -7,8 +7,10 @@ import io.openems.edge.evcs.api.Evcs; import io.openems.edge.evcs.api.ManagedEvcs; import io.openems.edge.evcs.api.MeasuringEvcs; +import io.openems.edge.meter.api.ElectricityMeter; -public interface EvcsOcppAbl extends Evcs, MeasuringEvcs, ManagedEvcs, OpenemsComponent, EventHandler { +public interface EvcsOcppAbl + extends Evcs, MeasuringEvcs, ManagedEvcs, ElectricityMeter, OpenemsComponent, EventHandler { public enum ChannelId implements io.openems.edge.common.channel.ChannelId { ; diff --git a/io.openems.edge.evcs.ocpp.abl/src/io/openems/edge/evcs/ocpp/abl/EvcsOcppAblImpl.java b/io.openems.edge.evcs.ocpp.abl/src/io/openems/edge/evcs/ocpp/abl/EvcsOcppAblImpl.java index 30901ec28f0..874de8df500 100644 --- a/io.openems.edge.evcs.ocpp.abl/src/io/openems/edge/evcs/ocpp/abl/EvcsOcppAblImpl.java +++ b/io.openems.edge.evcs.ocpp.abl/src/io/openems/edge/evcs/ocpp/abl/EvcsOcppAblImpl.java @@ -38,6 +38,7 @@ import io.openems.edge.evcs.ocpp.common.OcppInformations; import io.openems.edge.evcs.ocpp.common.OcppProfileType; import io.openems.edge.evcs.ocpp.common.OcppStandardRequests; +import io.openems.edge.meter.api.ElectricityMeter; import io.openems.edge.timedata.api.Timedata; @Designate(ocd = Config.class, factory = true) @@ -51,7 +52,7 @@ EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE // }) public class EvcsOcppAblImpl extends AbstractManagedOcppEvcsComponent - implements EvcsOcppAbl, Evcs, MeasuringEvcs, ManagedEvcs, OpenemsComponent, EventHandler { + implements EvcsOcppAbl, Evcs, MeasuringEvcs, ManagedEvcs, ElectricityMeter, OpenemsComponent, EventHandler { // Default value for the hardware limit private static final Integer DEFAULT_HARDWARE_LIMIT = 22080; @@ -86,8 +87,8 @@ public EvcsOcppAblImpl() { super(// PROFILE_TYPES, // OpenemsComponent.ChannelId.values(), // + ElectricityMeter.ChannelId.values(), // Evcs.ChannelId.values(), // - AbstractManagedOcppEvcsComponent.ChannelId.values(), // ManagedEvcs.ChannelId.values(), // MeasuringEvcs.ChannelId.values(), // EvcsOcppAbl.ChannelId.values() // diff --git a/io.openems.edge.evcs.ocpp.abl/test/io/openems/edge/evcs/ocpp/abl/EvcsOcppAblImplTest.java b/io.openems.edge.evcs.ocpp.abl/test/io/openems/edge/evcs/ocpp/abl/EvcsOcppAblImplTest.java index c3dc9a84329..13123f22149 100644 --- a/io.openems.edge.evcs.ocpp.abl/test/io/openems/edge/evcs/ocpp/abl/EvcsOcppAblImplTest.java +++ b/io.openems.edge.evcs.ocpp.abl/test/io/openems/edge/evcs/ocpp/abl/EvcsOcppAblImplTest.java @@ -8,15 +8,13 @@ public class EvcsOcppAblImplTest { - private static final String COMPONENT_ID = "evcs0"; - @Test public void test() throws Exception { new ComponentTest(new EvcsOcppAblImpl()) // .addReference("componentManager", new DummyComponentManager()) // .addReference("evcsPower", new DummyEvcsPower()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // + .setId("evcs0") // .setConnectorId(0) // .setOcppId("") // .setLogicalId("") // diff --git a/io.openems.edge.evcs.ocpp.common/src/io/openems/edge/evcs/ocpp/common/AbstractManagedOcppEvcsComponent.java b/io.openems.edge.evcs.ocpp.common/src/io/openems/edge/evcs/ocpp/common/AbstractManagedOcppEvcsComponent.java index f4724d48eff..5096e9b3588 100644 --- a/io.openems.edge.evcs.ocpp.common/src/io/openems/edge/evcs/ocpp/common/AbstractManagedOcppEvcsComponent.java +++ b/io.openems.edge.evcs.ocpp.common/src/io/openems/edge/evcs/ocpp/common/AbstractManagedOcppEvcsComponent.java @@ -1,5 +1,7 @@ package io.openems.edge.evcs.ocpp.common; +import static io.openems.edge.common.type.TypeUtils.getAsType; + import java.util.Arrays; import java.util.HashSet; import java.util.List; @@ -20,14 +22,13 @@ import io.openems.common.types.ChannelAddress; import io.openems.common.types.OpenemsType; import io.openems.edge.common.channel.Channel; -import io.openems.edge.common.channel.Doc; import io.openems.edge.common.event.EdgeEventConstants; -import io.openems.edge.common.type.TypeUtils; import io.openems.edge.evcs.api.AbstractManagedEvcsComponent; import io.openems.edge.evcs.api.Evcs; import io.openems.edge.evcs.api.ManagedEvcs; import io.openems.edge.evcs.api.MeasuringEvcs; import io.openems.edge.evcs.api.Status; +import io.openems.edge.meter.api.ElectricityMeter; import io.openems.edge.timedata.api.TimedataProvider; /** @@ -59,7 +60,7 @@ * */ public abstract class AbstractManagedOcppEvcsComponent extends AbstractManagedEvcsComponent - implements Evcs, ManagedEvcs, MeasuringEvcs, EventHandler, TimedataProvider { + implements Evcs, ManagedEvcs, MeasuringEvcs, ElectricityMeter, EventHandler, TimedataProvider { private final Logger log = LoggerFactory.getLogger(AbstractManagedOcppEvcsComponent.class); @@ -83,20 +84,6 @@ protected AbstractManagedOcppEvcsComponent(OcppProfileType[] profileTypes, this.profileTypes = new HashSet<>(Arrays.asList(profileTypes)); } - public enum ChannelId implements io.openems.edge.common.channel.ChannelId { - ; - private final Doc doc; - - private ChannelId(Doc doc) { - this.doc = doc; - } - - @Override - public Doc doc() { - return this.doc; - } - } - @Override protected void activate(ComponentContext context, String id, String alias, boolean enabled) { super.activate(context, id, alias, enabled); @@ -114,11 +101,10 @@ protected void modified(ComponentContext context, String id, String alias, boole private void setInitialSettings() { // Normally the limits are set automatically when the phase channel is set, but // not every OCPP charger provides the information about the number of phases. - int fixedMaximum = this.getFixedMaximumHardwarePower().orElse(DEFAULT_MAXIMUM_HARDWARE_POWER); - int fixedMinimum = this.getFixedMinimumHardwarePower().orElse(DEFAULT_MINIMUM_HARDWARE_POWER); - - this.getMaximumHardwarePowerChannel().setNextValue(fixedMaximum); - this.getMinimumHardwarePowerChannel().setNextValue(fixedMinimum); + this.getMaximumHardwarePowerChannel().setNextValue(// + this.getFixedMaximumHardwarePower().orElse(DEFAULT_MAXIMUM_HARDWARE_POWER)); + this.getMinimumHardwarePowerChannel().setNextValue(// + this.getFixedMinimumHardwarePower().orElse(DEFAULT_MINIMUM_HARDWARE_POWER)); } @Override @@ -157,22 +143,22 @@ private void setInitialTotalEnergyFromTimedata() { if (timedata == null || componentId == null) { return; } else { - timedata.getLatestValue(new ChannelAddress(componentId, Evcs.ChannelId.ACTIVE_CONSUMPTION_ENERGY.id())) + timedata.getLatestValue( + new ChannelAddress(componentId, ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY.id())) .thenAccept(totalEnergyOpt -> { - if (this.getActiveConsumptionEnergy().isDefined()) { + if (this.getActiveProductionEnergy().isDefined()) { // Value has been read from device in the meantime return; } if (totalEnergyOpt.isPresent()) { try { - this._setActiveConsumptionEnergy( - TypeUtils.getAsType(OpenemsType.LONG, totalEnergyOpt.get())); + this._setActiveProductionEnergy(getAsType(OpenemsType.LONG, totalEnergyOpt.get())); } catch (IllegalArgumentException e) { - this._setActiveConsumptionEnergy(TypeUtils.getAsType(OpenemsType.LONG, 0L)); + this._setActiveProductionEnergy(getAsType(OpenemsType.LONG, 0L)); } } else { - this._setActiveConsumptionEnergy(TypeUtils.getAsType(OpenemsType.LONG, 0L)); + this._setActiveConsumptionEnergy(getAsType(OpenemsType.LONG, 0L)); } }); } @@ -284,7 +270,7 @@ private void resetMeasuredChannelValues() { Channel channel = this.channel(c); channel.setNextValue(null); } - this._setChargePower(0); + this._setActivePower(0); } /** @@ -305,7 +291,7 @@ private void checkCurrentState() { case NOT_READY_FOR_CHARGING: case STARTING: case UNDEFINED: - this._setChargePower(0); + this._setActivePower(0); break; } } @@ -338,11 +324,9 @@ protected void logWarn(Logger log, String message) { @Override public String debugLog() { - if (this instanceof ManagedEvcs) { - return "Limit:" + ((ManagedEvcs) this).getSetChargePowerLimit().orElse(null) + "|" - + this.getStatus().getName(); - } - return "Power:" + this.getChargePower().orElse(0) + "|" + this.getStatus().getName(); + return "P:" + this.getActivePower().orElse(null) // + + "|Limit:" + this.getSetChargePowerLimit().orElse(null) // + + "|" + this.getStatus().getName(); } @Override diff --git a/io.openems.edge.evcs.ocpp.common/src/io/openems/edge/evcs/ocpp/common/OcppInformations.java b/io.openems.edge.evcs.ocpp.common/src/io/openems/edge/evcs/ocpp/common/OcppInformations.java index f4f4d7be976..6751117b3fb 100644 --- a/io.openems.edge.evcs.ocpp.common/src/io/openems/edge/evcs/ocpp/common/OcppInformations.java +++ b/io.openems.edge.evcs.ocpp.common/src/io/openems/edge/evcs/ocpp/common/OcppInformations.java @@ -1,9 +1,9 @@ package io.openems.edge.evcs.ocpp.common; import io.openems.edge.common.channel.ChannelId; -import io.openems.edge.evcs.api.Evcs; import io.openems.edge.evcs.api.MeasuringEvcs; import io.openems.edge.evcs.api.SocEvcs; +import io.openems.edge.meter.api.ElectricityMeter; public enum OcppInformations { @@ -95,7 +95,7 @@ public enum OcppInformations { * UnitOfMeasure for frequency, the UnitOfMeasure for any SampledValue with * measurand: Frequency is Hertz. */ - CORE_METER_VALUES_FREQUENCY("Frequency", MeasuringEvcs.ChannelId.FREQUENCY), + CORE_METER_VALUES_FREQUENCY("Frequency", ElectricityMeter.ChannelId.FREQUENCY), /** * Instantaneous active power exported by EV. (W) @@ -105,7 +105,7 @@ public enum OcppInformations { /** * Instantaneous active power imported by EV. (W) */ - CORE_METER_VALUES_POWER_ACTIVE_IMPORT("Power.Active.Import", Evcs.ChannelId.CHARGE_POWER), + CORE_METER_VALUES_POWER_ACTIVE_IMPORT("Power.Active.Import", ElectricityMeter.ChannelId.ACTIVE_POWER), /** * Instantaneous power factor of total energy flow. @@ -146,7 +146,7 @@ public enum OcppInformations { /** * Instantaneous AC RMS supply voltage. */ - CORE_METER_VALUES_VOLTAGE("Voltage", MeasuringEvcs.ChannelId.VOLTAGE); + CORE_METER_VALUES_VOLTAGE("Voltage", ElectricityMeter.ChannelId.VOLTAGE); private final String ocppValue; private final ChannelId channelId; diff --git a/io.openems.edge.evcs.ocpp.ies.keywatt.singleccs/src/io/openems/edge/evcs/ocpp/ies/keywatt/singleccs/EvcsOcppIesKeywattSingle.java b/io.openems.edge.evcs.ocpp.ies.keywatt.singleccs/src/io/openems/edge/evcs/ocpp/ies/keywatt/singleccs/EvcsOcppIesKeywattSingle.java index fed8dedd6f2..4f3ac815d89 100644 --- a/io.openems.edge.evcs.ocpp.ies.keywatt.singleccs/src/io/openems/edge/evcs/ocpp/ies/keywatt/singleccs/EvcsOcppIesKeywattSingle.java +++ b/io.openems.edge.evcs.ocpp.ies.keywatt.singleccs/src/io/openems/edge/evcs/ocpp/ies/keywatt/singleccs/EvcsOcppIesKeywattSingle.java @@ -8,9 +8,10 @@ import io.openems.edge.evcs.api.ManagedEvcs; import io.openems.edge.evcs.api.MeasuringEvcs; import io.openems.edge.evcs.api.SocEvcs; +import io.openems.edge.meter.api.ElectricityMeter; public interface EvcsOcppIesKeywattSingle - extends Evcs, ManagedEvcs, MeasuringEvcs, OpenemsComponent, EventHandler, SocEvcs { + extends Evcs, ManagedEvcs, MeasuringEvcs, ElectricityMeter, OpenemsComponent, EventHandler, SocEvcs { public enum ChannelId implements io.openems.edge.common.channel.ChannelId { ; diff --git a/io.openems.edge.evcs.ocpp.ies.keywatt.singleccs/src/io/openems/edge/evcs/ocpp/ies/keywatt/singleccs/EvcsOcppIesKeywattSingleImpl.java b/io.openems.edge.evcs.ocpp.ies.keywatt.singleccs/src/io/openems/edge/evcs/ocpp/ies/keywatt/singleccs/EvcsOcppIesKeywattSingleImpl.java index b27dde46b05..57eeb4c67b2 100644 --- a/io.openems.edge.evcs.ocpp.ies.keywatt.singleccs/src/io/openems/edge/evcs/ocpp/ies/keywatt/singleccs/EvcsOcppIesKeywattSingleImpl.java +++ b/io.openems.edge.evcs.ocpp.ies.keywatt.singleccs/src/io/openems/edge/evcs/ocpp/ies/keywatt/singleccs/EvcsOcppIesKeywattSingleImpl.java @@ -36,6 +36,7 @@ import io.openems.edge.evcs.ocpp.common.OcppInformations; import io.openems.edge.evcs.ocpp.common.OcppProfileType; import io.openems.edge.evcs.ocpp.common.OcppStandardRequests; +import io.openems.edge.meter.api.ElectricityMeter; import io.openems.edge.timedata.api.Timedata; @Designate(ocd = Config.class, factory = true) @@ -48,8 +49,8 @@ EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE, // EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE // }) -public class EvcsOcppIesKeywattSingleImpl extends AbstractManagedOcppEvcsComponent - implements EvcsOcppIesKeywattSingle, Evcs, ManagedEvcs, MeasuringEvcs, OpenemsComponent, EventHandler, SocEvcs { +public class EvcsOcppIesKeywattSingleImpl extends AbstractManagedOcppEvcsComponent implements EvcsOcppIesKeywattSingle, + Evcs, ManagedEvcs, MeasuringEvcs, ElectricityMeter, OpenemsComponent, EventHandler, SocEvcs { // Profiles that a Ies KeyWatt is supporting private static final OcppProfileType[] PROFILE_TYPES = { // @@ -76,8 +77,8 @@ public EvcsOcppIesKeywattSingleImpl() { super(// PROFILE_TYPES, // OpenemsComponent.ChannelId.values(), // + ElectricityMeter.ChannelId.values(), // Evcs.ChannelId.values(), // - AbstractManagedOcppEvcsComponent.ChannelId.values(), // ManagedEvcs.ChannelId.values(), // MeasuringEvcs.ChannelId.values(), // SocEvcs.ChannelId.values(), // diff --git a/io.openems.edge.evcs.ocpp.ies.keywatt.singleccs/test/io/openems/edge/evcs/ocpp/ies/keywatt/singleccs/EvcsOcppIesKeywattSingleImplTest.java b/io.openems.edge.evcs.ocpp.ies.keywatt.singleccs/test/io/openems/edge/evcs/ocpp/ies/keywatt/singleccs/EvcsOcppIesKeywattSingleImplTest.java index 8d0bea95587..313bd8288ff 100644 --- a/io.openems.edge.evcs.ocpp.ies.keywatt.singleccs/test/io/openems/edge/evcs/ocpp/ies/keywatt/singleccs/EvcsOcppIesKeywattSingleImplTest.java +++ b/io.openems.edge.evcs.ocpp.ies.keywatt.singleccs/test/io/openems/edge/evcs/ocpp/ies/keywatt/singleccs/EvcsOcppIesKeywattSingleImplTest.java @@ -8,15 +8,13 @@ public class EvcsOcppIesKeywattSingleImplTest { - private static final String COMPONENT_ID = "evcs0"; - @Test public void test() throws Exception { new ComponentTest(new EvcsOcppIesKeywattSingleImpl()) // .addReference("componentManager", new DummyComponentManager()) // .addReference("evcsPower", new DummyEvcsPower()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // + .setId("evcs0") // .setConnectorId(0) // .setOcppId("") // .setDebugMode(false) // diff --git a/io.openems.edge.evcs.ocpp.server/bnd.bnd b/io.openems.edge.evcs.ocpp.server/bnd.bnd index 500e91981af..da432b59483 100644 --- a/io.openems.edge.evcs.ocpp.server/bnd.bnd +++ b/io.openems.edge.evcs.ocpp.server/bnd.bnd @@ -10,6 +10,7 @@ Bundle-Version: 1.0.0.${tstamp} io.openems.edge.common,\ io.openems.edge.evcs.api,\ io.openems.edge.evcs.ocpp.common,\ + io.openems.edge.meter.api,\ io.openems.edge.timedata.api,\ io.openems.wrapper.eu.chargetime.ocpp,\ diff --git a/io.openems.edge.evcs.ocpp.server/src/io/openems/edge/evcs/ocpp/server/CoreEventHandlerImpl.java b/io.openems.edge.evcs.ocpp.server/src/io/openems/edge/evcs/ocpp/server/CoreEventHandlerImpl.java index 1342ff71913..5189a6ffe41 100644 --- a/io.openems.edge.evcs.ocpp.server/src/io/openems/edge/evcs/ocpp/server/CoreEventHandlerImpl.java +++ b/io.openems.edge.evcs.ocpp.server/src/io/openems/edge/evcs/ocpp/server/CoreEventHandlerImpl.java @@ -121,7 +121,7 @@ public MeterValuesConfirmation handleMeterValuesRequest(UUID sessionIndex, Meter */ var format = value.getFormat(); if (format.equals(ValueFormat.SignedData)) { - val = this.fromHexToDezString(val); + val = fromHexToDezString(val); } var measurand = OcppInformations @@ -143,14 +143,14 @@ public MeterValuesConfirmation handleMeterValuesRequest(UUID sessionIndex, Meter case CORE_METER_VALUES_ENERGY_ACTIVE_IMPORT_INTERVAL: case CORE_METER_VALUES_ENERGY_ACTIVE_EXPORT_INTERVAL: if (unit.equals(Unit.KWH)) { - val = this.multipliedByThousand(val); + val = multipliedByThousand(val); } correctValue = Double.valueOf(val); break; case CORE_METER_VALUES_ENERGY_ACTIVE_IMPORT_REGISTER: if (unit.equals(Unit.KWH)) { - val = this.multipliedByThousand(val); + val = multipliedByThousand(val); } correctValue = Double.valueOf(val); @@ -165,13 +165,12 @@ public MeterValuesConfirmation handleMeterValuesRequest(UUID sessionIndex, Meter break; } - var sessionEnergy = 0; - var totalEnergy = 0L; - /* * Calculating the energy in this session and in total for the given energy * value. */ + final int sessionEnergy; + final long totalEnergy; if (evcs.returnsSessionEnergy()) { sessionEnergy = (int) energy; totalEnergy = evcs.getSessionStart().getEnergy() + energy; @@ -180,7 +179,7 @@ public MeterValuesConfirmation handleMeterValuesRequest(UUID sessionIndex, Meter totalEnergy = energy; } evcs._setEnergySession(sessionEnergy); - evcs._setActiveConsumptionEnergy(totalEnergy); + evcs._setActiveProductionEnergy(totalEnergy); break; case CORE_METER_VALUES_ENERGY_REACTIVE_EXPORT_REGISTER: @@ -188,7 +187,7 @@ public MeterValuesConfirmation handleMeterValuesRequest(UUID sessionIndex, Meter case CORE_METER_VALUES_ENERGY_REACTIVE_EXPORT_INTERVAL: case CORE_METER_VALUES_ENERGY_REACTIVE_IMPORT_INTERVAL: if (unit.equals(Unit.KVARH)) { - val = this.multipliedByThousand(val); + val = multipliedByThousand(val); } correctValue = Double.valueOf(val); break; @@ -197,7 +196,7 @@ public MeterValuesConfirmation handleMeterValuesRequest(UUID sessionIndex, Meter case CORE_METER_VALUES_POWER_ACTIVE_IMPORT: case CORE_METER_VALUES_POWER_OFFERED: if (unit.equals(Unit.KW)) { - val = this.multipliedByThousand(val); + val = multipliedByThousand(val); } correctValue = (int) Math.round(Double.parseDouble(val)); @@ -226,7 +225,7 @@ public MeterValuesConfirmation handleMeterValuesRequest(UUID sessionIndex, Meter case CORE_METER_VALUES_POWER_REACTIVE_EXPORT: case CORE_METER_VALUES_POWER_REACTIVE_IMPORT: if (unit.equals(Unit.KVAR)) { - val = this.multipliedByThousand(val); + val = multipliedByThousand(val); } correctValue = (int) Math.round(Double.parseDouble(val)); break; @@ -277,8 +276,9 @@ public StatusNotificationConfirmation handleStatusNotificationRequest(UUID sessi evcs.getSessionEnd().resetChargeSessionStampIfPresent(); // Set the start charge session stamp - evcs.getSessionStart().setChargeSessionStampIfNotPresent( - Instant.now(this.parent.componentManager.getClock()), evcs.getActiveConsumptionEnergy().orElse(0L)); + evcs.getSessionStart().setChargeSessionStampIfNotPresent(// + Instant.now(this.parent.componentManager.getClock()), // + evcs.getActiveProductionEnergy().orElse(0L)); break; case Faulted: evcsStatus = Status.ERROR; @@ -289,8 +289,9 @@ public StatusNotificationConfirmation handleStatusNotificationRequest(UUID sessi // Reset the start charge session stamp evcs.getSessionStart().resetChargeSessionStampIfPresent(); - evcs.getSessionEnd().setChargeSessionStampIfNotPresent(Instant.now(this.parent.componentManager.getClock()), - evcs.getActiveConsumptionEnergy().orElse(0L)); + evcs.getSessionEnd().setChargeSessionStampIfNotPresent(// + Instant.now(this.parent.componentManager.getClock()), // + evcs.getActiveProductionEnergy().orElse(0L)); break; case Preparing: evcsStatus = Status.READY_FOR_CHARGING; @@ -403,7 +404,7 @@ private AbstractManagedOcppEvcsComponent getEvcsBySessionIndexAndConnector(UUID * @param hex given value in hex * @return Decimal value as String */ - public String fromHexToDezString(String hex) { + public static String fromHexToDezString(String hex) { var dezValue = Integer.parseInt(hex, 16); return String.valueOf(dezValue); } @@ -414,7 +415,7 @@ public String fromHexToDezString(String hex) { * @param val value * @return Value / 1000 as String */ - private String multipliedByThousand(String val) { + private static String multipliedByThousand(String val) { if (val.isEmpty()) { return val; } @@ -435,8 +436,8 @@ private void setPowerDependingOnEnergy(AbstractManagedOcppEvcsComponent evcs, Do var power = 0; if (lastChargingProperty != null) { - power = this.calculateChargePower(lastChargingProperty, currentEnergy, timestamp); - evcs._setChargePower(power); + power = this.calculateActivePower(lastChargingProperty, currentEnergy, timestamp); + evcs._setActivePower(power); } evcs.setLastChargingProperty(new ChargingProperty(power, currentEnergy, timestamp)); } @@ -449,7 +450,7 @@ private void setPowerDependingOnEnergy(AbstractManagedOcppEvcsComponent evcs, Do * @param timestamp Time when the current Energy was measured. * @return current power */ - private int calculateChargePower(ChargingProperty lastMeterValue, double currentEnergy, ZonedDateTime timestamp) { + private int calculateActivePower(ChargingProperty lastMeterValue, double currentEnergy, ZonedDateTime timestamp) { double diffseconds = Duration.between(timestamp, lastMeterValue.getTimestamp()).getSeconds(); diff --git a/io.openems.edge.evcs.spelsberg/bnd.bnd b/io.openems.edge.evcs.spelsberg/bnd.bnd index 352d8d2c11e..be0c8b9d00b 100644 --- a/io.openems.edge.evcs.spelsberg/bnd.bnd +++ b/io.openems.edge.evcs.spelsberg/bnd.bnd @@ -10,6 +10,7 @@ Bundle-Version: 1.0.0.${tstamp} io.openems.edge.bridge.modbus,\ io.openems.edge.common,\ io.openems.edge.evcs.api,\ + io.openems.edge.meter.api,\ -testpath: \ ${testpath} \ No newline at end of file diff --git a/io.openems.edge.evcs.spelsberg/src/io/openems/edge/evcs/spelsberg/smart/EvcsSpelsbergSmart.java b/io.openems.edge.evcs.spelsberg/src/io/openems/edge/evcs/spelsberg/smart/EvcsSpelsbergSmart.java index 4b05ab4ca21..5e16a5ffacf 100644 --- a/io.openems.edge.evcs.spelsberg/src/io/openems/edge/evcs/spelsberg/smart/EvcsSpelsbergSmart.java +++ b/io.openems.edge.evcs.spelsberg/src/io/openems/edge/evcs/spelsberg/smart/EvcsSpelsbergSmart.java @@ -64,30 +64,6 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { .accessMode(AccessMode.READ_ONLY) // .text("Maximum current signaled to the EV for charging")), - CURRENT_L1(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.MILLIAMPERE).accessMode(AccessMode.READ_ONLY) // - .text("Current on L1")), - - CURRENT_L2(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.MILLIAMPERE).accessMode(AccessMode.READ_ONLY) // - .text("Current on L2")), - - CURRENT_L3(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.MILLIAMPERE).accessMode(AccessMode.READ_ONLY) // - .text("Current on L3")), - - POWER_L1(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY) // - .text("Charging power on L1")), - - POWER_L2(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY) // - .text("Charging power on L2")), - - POWER_L3(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY) // - .text("Charging power on L3")), - POWER_TOTAL(Doc.of(OpenemsType.INTEGER) // .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY) // .text("Sum of active charging power")), @@ -132,60 +108,6 @@ public default void setApplyChargePowerLimit(Integer value) throws OpenemsNamedE this.getApplyChargePowerLimitChannel().setNextWriteValue(value); } - /** - * Gets the Channel for {@link ChannelId#POWER_L1}. - * - * @return the Channel - */ - public default Channel getChargePowerL1Channel() { - return this.channel(ChannelId.POWER_L1); - } - - /** - * Gets the Power on phase L1 in [W]. See {@link ChannelId#POWER_L1}. - * - * @return the Channel {@link Value} - */ - public default Value getChargePowerL1() { - return this.getChargePowerL1Channel().value(); - } - - /** - * Gets the Channel for {@link ChannelId#POWER_L2}. - * - * @return the Channel - */ - public default Channel getChargePowerL2Channel() { - return this.channel(ChannelId.POWER_L2); - } - - /** - * Gets the Power on phase L2 in [W]. See {@link ChannelId#POWER_L2}. - * - * @return the Channel {@link Value} - */ - public default Value getChargePowerL2() { - return this.getChargePowerL2Channel().value(); - } - - /** - * Gets the Channel for {@link ChannelId#POWER_L3}. - * - * @return the Channel - */ - public default Channel getChargePowerL3Channel() { - return this.channel(ChannelId.POWER_L3); - } - - /** - * Gets the Power on phase L3 in [W]. See {@link ChannelId#POWER_L3}. - * - * @return the Channel {@link Value} - */ - public default Value getChargePowerL3() { - return this.getChargePowerL3Channel().value(); - } - /** * Gets the Channel for {@link ChannelId#POWER_TOTAL}. * diff --git a/io.openems.edge.evcs.spelsberg/src/io/openems/edge/evcs/spelsberg/smart/EvcsSpelsbergSmartImpl.java b/io.openems.edge.evcs.spelsberg/src/io/openems/edge/evcs/spelsberg/smart/EvcsSpelsbergSmartImpl.java index 71e6df3342a..cec1e44f812 100644 --- a/io.openems.edge.evcs.spelsberg/src/io/openems/edge/evcs/spelsberg/smart/EvcsSpelsbergSmartImpl.java +++ b/io.openems.edge.evcs.spelsberg/src/io/openems/edge/evcs/spelsberg/smart/EvcsSpelsbergSmartImpl.java @@ -44,6 +44,7 @@ import io.openems.edge.evcs.api.Phases; import io.openems.edge.evcs.api.Status; import io.openems.edge.evcs.api.WriteHandler; +import io.openems.edge.meter.api.ElectricityMeter; @Designate(ocd = Config.class, factory = true) @Component(// @@ -54,8 +55,8 @@ @EventTopics({ // EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE // }) -public class EvcsSpelsbergSmartImpl extends AbstractOpenemsModbusComponent - implements EvcsSpelsbergSmart, Evcs, ManagedEvcs, ModbusComponent, OpenemsComponent, EventHandler { +public class EvcsSpelsbergSmartImpl extends AbstractOpenemsModbusComponent implements EvcsSpelsbergSmart, Evcs, + ManagedEvcs, ModbusComponent, OpenemsComponent, EventHandler, ElectricityMeter { private final Logger log = LoggerFactory.getLogger(EvcsSpelsbergSmartImpl.class); private final ChargeStateHandler chargeStateHandler = new ChargeStateHandler(this); @@ -77,6 +78,7 @@ protected void setModbus(BridgeModbus modbus) { public EvcsSpelsbergSmartImpl() { super(// OpenemsComponent.ChannelId.values(), // + ElectricityMeter.ChannelId.values(), // ModbusComponent.ChannelId.values(), // Evcs.ChannelId.values(), // ManagedEvcs.ChannelId.values(), // @@ -127,23 +129,24 @@ protected ModbusProtocol defineModbusProtocol() { m(EvcsSpelsbergSmart.ChannelId.CABLE_STATE, new UnsignedWordElement(1004))), new FC3ReadRegistersTask(1008, Priority.LOW, - m(EvcsSpelsbergSmart.ChannelId.CURRENT_L1, new UnsignedWordElement(1008)), + m(ElectricityMeter.ChannelId.CURRENT_L1, new UnsignedWordElement(1008)), new DummyRegisterElement(1009), - m(EvcsSpelsbergSmart.ChannelId.CURRENT_L2, new UnsignedWordElement(1010)), + m(ElectricityMeter.ChannelId.CURRENT_L2, new UnsignedWordElement(1010)), new DummyRegisterElement(1011), - m(EvcsSpelsbergSmart.ChannelId.CURRENT_L3, new UnsignedWordElement(1012))), + m(ElectricityMeter.ChannelId.CURRENT_L3, new UnsignedWordElement(1012))), new FC3ReadRegistersTask(1020, Priority.HIGH, - m(Evcs.ChannelId.CHARGE_POWER, new UnsignedDoublewordElement(1020)), + m(ElectricityMeter.ChannelId.ACTIVE_POWER, new UnsignedDoublewordElement(1020)), + // TODO whats the difference between 1020 and 1022? m(EvcsSpelsbergSmart.ChannelId.POWER_TOTAL, new UnsignedDoublewordElement(1022)), - m(EvcsSpelsbergSmart.ChannelId.POWER_L1, new UnsignedDoublewordElement(1024)), + m(ElectricityMeter.ChannelId.ACTIVE_POWER_L1, new UnsignedDoublewordElement(1024)), new DummyRegisterElement(1026, 1027), - m(EvcsSpelsbergSmart.ChannelId.POWER_L2, new UnsignedDoublewordElement(1028)), + m(ElectricityMeter.ChannelId.ACTIVE_POWER_L2, new UnsignedDoublewordElement(1028)), new DummyRegisterElement(1030, 1031), - m(EvcsSpelsbergSmart.ChannelId.POWER_L3, new UnsignedDoublewordElement(1032))), + m(ElectricityMeter.ChannelId.ACTIVE_POWER_L3, new UnsignedDoublewordElement(1032))), new FC3ReadRegistersTask(1036, Priority.LOW, - m(Evcs.ChannelId.ACTIVE_CONSUMPTION_ENERGY, new UnsignedDoublewordElement(1036))), + m(ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY, new UnsignedDoublewordElement(1036))), new FC3ReadRegistersTask(1100, Priority.LOW, m(EvcsSpelsbergSmart.ChannelId.MAX_HARDWARE_CURRENT, new UnsignedWordElement(1100)), @@ -290,21 +293,13 @@ private void addStatusCallback() { */ private void addPhaseDetectionCallback() { final Consumer> setPhasesCallback = ignore -> { - - var phases = 0; - if (this.getChargePowerL1().isDefined() && this.getChargePowerL1().get() > 0) { - phases++; - } - if (this.getChargePowerL2().isDefined() && this.getChargePowerL2().get() > 0) { - phases++; - } - if (this.getChargePowerL3().isDefined() && this.getChargePowerL3().get() > 0) { - phases++; - } - - this._setPhases(phases); + this._setPhases(Evcs.evaluatePhaseCount(// + this.getActivePowerL1().get(), // + this.getActivePowerL2().get(), // + this.getActivePowerL3().get())); }; + // TODO remove this channel this.getChargePowerTotalChannel().onUpdate(setPhasesCallback); } diff --git a/io.openems.edge.evcs.spelsberg/test/io/openems/edge/evcs/spelsberg/smart/EvcsSpelsbergSmartImplTest.java b/io.openems.edge.evcs.spelsberg/test/io/openems/edge/evcs/spelsberg/smart/EvcsSpelsbergSmartImplTest.java index c1b4be1ea43..61854c8a834 100644 --- a/io.openems.edge.evcs.spelsberg/test/io/openems/edge/evcs/spelsberg/smart/EvcsSpelsbergSmartImplTest.java +++ b/io.openems.edge.evcs.spelsberg/test/io/openems/edge/evcs/spelsberg/smart/EvcsSpelsbergSmartImplTest.java @@ -8,17 +8,14 @@ public class EvcsSpelsbergSmartImplTest { - private static final String EVCS_ID = "evcs0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new EvcsSpelsbergSmartImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setModbusId(MODBUS_ID) // - .setId(EVCS_ID) // + .setModbusId("modbus0") // + .setId("evcs0") // .setModbusUnitId(255) // .setMaxHwCurrent(16000) // .setMinHwCurrent(6000) // diff --git a/io.openems.edge.evcs.webasto.next/bnd.bnd b/io.openems.edge.evcs.webasto.next/bnd.bnd index d8f6c880de2..dedafbd9bf3 100644 --- a/io.openems.edge.evcs.webasto.next/bnd.bnd +++ b/io.openems.edge.evcs.webasto.next/bnd.bnd @@ -10,6 +10,7 @@ Bundle-Version: 1.0.0.${tstamp} io.openems.edge.bridge.modbus,\ io.openems.edge.common,\ io.openems.edge.evcs.api,\ + io.openems.edge.meter.api,\ -testpath: \ ${testpath} \ No newline at end of file diff --git a/io.openems.edge.evcs.webasto.next/src/io/openems/edge/evcs/webasto/next/EvcsWebastoNext.java b/io.openems.edge.evcs.webasto.next/src/io/openems/edge/evcs/webasto/next/EvcsWebastoNext.java index fe1dc68577d..06b57a37520 100644 --- a/io.openems.edge.evcs.webasto.next/src/io/openems/edge/evcs/webasto/next/EvcsWebastoNext.java +++ b/io.openems.edge.evcs.webasto.next/src/io/openems/edge/evcs/webasto/next/EvcsWebastoNext.java @@ -5,7 +5,6 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.types.OpenemsType; import io.openems.edge.common.channel.Doc; -import io.openems.edge.common.channel.IntegerReadChannel; import io.openems.edge.common.channel.IntegerWriteChannel; import io.openems.edge.common.channel.value.Value; import io.openems.edge.common.component.OpenemsComponent; @@ -31,26 +30,6 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { EVSE_ERROR_CODE(Doc.of(EvseErrorCode.values())), // - CURRENT_L1(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.MILLIAMPERE) // - .accessMode(AccessMode.READ_ONLY)), // - - CURRENT_L2(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.MILLIAMPERE) // - .accessMode(AccessMode.READ_ONLY)), // - - CURRENT_L3(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.MILLIAMPERE)), // - - POWER_L1(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT)), // - - POWER_L2(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT)), // - - POWER_L3(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT)), // - MAX_HW_CURRENT(Doc.of(OpenemsType.INTEGER) // .unit(Unit.AMPERE)), // @@ -161,58 +140,4 @@ public default Value getEvSetChargePowerLimit() { public default void setEvSetChargePowerLimit(Integer value) throws OpenemsNamedException { this.getEvSetChargePowerLimitChannel().setNextWriteValue(value); } - - /** - * Gets the Channel for {@link ChannelId#POWER_L1}. - * - * @return the Channel - */ - public default IntegerReadChannel getPowerL1Channel() { - return this.channel(ChannelId.POWER_L1); - } - - /** - * Gets the Power on phase 1 in [W]. See {@link ChannelId#POWER_L1}. - * - * @return the Channel {@link Value} - */ - public default Value getPowerL1() { - return this.getPowerL1Channel().value(); - } - - /** - * Gets the Channel for {@link ChannelId#POWER_L2}. - * - * @return the Channel - */ - public default IntegerReadChannel getPowerL2Channel() { - return this.channel(ChannelId.POWER_L2); - } - - /** - * Gets the Power on phase 2 in [W]. See {@link ChannelId#POWER_L2}. - * - * @return the Channel {@link Value} - */ - public default Value getPowerL2() { - return this.getPowerL2Channel().value(); - } - - /** - * Gets the Channel for {@link ChannelId#POWER_L3}. - * - * @return the Channel - */ - public default IntegerReadChannel getPowerL3Channel() { - return this.channel(ChannelId.POWER_L3); - } - - /** - * Gets the Power on phase 3 in [W]. See {@link ChannelId#POWER_L3}. - * - * @return the Channel {@link Value} - */ - public default Value getPowerL3() { - return this.getPowerL3Channel().value(); - } } diff --git a/io.openems.edge.evcs.webasto.next/src/io/openems/edge/evcs/webasto/next/EvcsWebastoNextImpl.java b/io.openems.edge.evcs.webasto.next/src/io/openems/edge/evcs/webasto/next/EvcsWebastoNextImpl.java index d57c72553c9..c1748ed171a 100644 --- a/io.openems.edge.evcs.webasto.next/src/io/openems/edge/evcs/webasto/next/EvcsWebastoNextImpl.java +++ b/io.openems.edge.evcs.webasto.next/src/io/openems/edge/evcs/webasto/next/EvcsWebastoNextImpl.java @@ -45,6 +45,7 @@ import io.openems.edge.evcs.api.Status; import io.openems.edge.evcs.api.WriteHandler; import io.openems.edge.evcs.webasto.next.enums.ChargePointState; +import io.openems.edge.meter.api.ElectricityMeter; @Designate(ocd = Config.class, factory = true) @Component(// @@ -55,11 +56,10 @@ @EventTopics({ // EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE, // }) -public class EvcsWebastoNextImpl extends AbstractOpenemsModbusComponent - implements EvcsWebastoNext, Evcs, ManagedEvcs, ModbusComponent, OpenemsComponent, EventHandler { +public class EvcsWebastoNextImpl extends AbstractOpenemsModbusComponent implements EvcsWebastoNext, Evcs, ManagedEvcs, + ElectricityMeter, ModbusComponent, OpenemsComponent, EventHandler { private static final int DEFAULT_LIFE_BIT = 1; - private static final int DETECT_PHASE_ACTIVITY = 100; // W private final Logger log = LoggerFactory.getLogger(EvcsWebastoNext.class); @@ -84,6 +84,7 @@ protected void setModbus(BridgeModbus modbus) { public EvcsWebastoNextImpl() { super(// OpenemsComponent.ChannelId.values(), // + ElectricityMeter.ChannelId.values(), // ModbusComponent.ChannelId.values(), // Evcs.ChannelId.values(), // ManagedEvcs.ChannelId.values(), // @@ -151,21 +152,21 @@ protected ModbusProtocol defineModbusProtocol() { new FC3ReadRegistersTask(1006, Priority.LOW, m(EvcsWebastoNext.ChannelId.EVSE_ERROR_CODE, new UnsignedWordElement(1006))), new FC3ReadRegistersTask(1008, Priority.LOW, - m(EvcsWebastoNext.ChannelId.CURRENT_L1, new UnsignedWordElement(1008))), + m(ElectricityMeter.ChannelId.CURRENT_L1, new UnsignedWordElement(1008))), new FC3ReadRegistersTask(1010, Priority.LOW, - m(EvcsWebastoNext.ChannelId.CURRENT_L2, new UnsignedWordElement(1010))), + m(ElectricityMeter.ChannelId.CURRENT_L2, new UnsignedWordElement(1010))), new FC3ReadRegistersTask(1012, Priority.LOW, - m(EvcsWebastoNext.ChannelId.CURRENT_L3, new UnsignedWordElement(1012))), + m(ElectricityMeter.ChannelId.CURRENT_L3, new UnsignedWordElement(1012))), new FC3ReadRegistersTask(1020, Priority.HIGH, - m(Evcs.ChannelId.CHARGE_POWER, new UnsignedDoublewordElement(1020))), + m(ElectricityMeter.ChannelId.ACTIVE_POWER, new UnsignedDoublewordElement(1020))), new FC3ReadRegistersTask(1024, Priority.LOW, - m(EvcsWebastoNext.ChannelId.POWER_L1, new UnsignedDoublewordElement(1024))), + m(ElectricityMeter.ChannelId.ACTIVE_POWER_L1, new UnsignedDoublewordElement(1024))), new FC3ReadRegistersTask(1028, Priority.LOW, - m(EvcsWebastoNext.ChannelId.POWER_L2, new UnsignedDoublewordElement(1028))), + m(ElectricityMeter.ChannelId.ACTIVE_POWER_L2, new UnsignedDoublewordElement(1028))), new FC3ReadRegistersTask(1032, Priority.LOW, - m(EvcsWebastoNext.ChannelId.POWER_L3, new UnsignedDoublewordElement(1032))), + m(ElectricityMeter.ChannelId.ACTIVE_POWER_L3, new UnsignedDoublewordElement(1032))), new FC3ReadRegistersTask(1036, Priority.LOW, - m(Evcs.ChannelId.ACTIVE_CONSUMPTION_ENERGY, new UnsignedDoublewordElement(1036))), + m(ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY, new UnsignedDoublewordElement(1036))), new FC3ReadRegistersTask(1100, Priority.LOW, m(EvcsWebastoNext.ChannelId.MAX_HW_CURRENT, new UnsignedWordElement(1100))), new FC3ReadRegistersTask(1102, Priority.LOW, @@ -241,25 +242,15 @@ private void addStatusListener() { } private void addPhasesListener() { - final Consumer> setPhases = ignore -> { - var phases = 0; - if (this.getPowerL1().orElse(0) > DETECT_PHASE_ACTIVITY) { - phases++; - } - if (this.getPowerL2().orElse(0) > DETECT_PHASE_ACTIVITY) { - phases++; - } - if (this.getPowerL3().orElse(0) > DETECT_PHASE_ACTIVITY) { - phases++; - } - if (phases == 0) { - phases = 3; - } - this._setPhases(phases); + final Consumer> setPhasesCallback = ignore -> { + this._setPhases(Evcs.evaluatePhaseCount(// + this.getActivePowerL1().get(), // + this.getActivePowerL2().get(), // + this.getActivePowerL3().get())); }; - this.getPowerL1Channel().onUpdate(setPhases); - this.getPowerL2Channel().onUpdate(setPhases); - this.getPowerL3Channel().onUpdate(setPhases); + this.getActivePowerL1Channel().onUpdate(setPhasesCallback); + this.getActivePowerL2Channel().onUpdate(setPhasesCallback); + this.getActivePowerL3Channel().onUpdate(setPhasesCallback); } @Override diff --git a/io.openems.edge.evcs.webasto.next/test/io/openems/edge/evcs/webasto/next/EvcsWebastoNextImplTest.java b/io.openems.edge.evcs.webasto.next/test/io/openems/edge/evcs/webasto/next/EvcsWebastoNextImplTest.java index b19ec679450..7ffc73c4d6a 100644 --- a/io.openems.edge.evcs.webasto.next/test/io/openems/edge/evcs/webasto/next/EvcsWebastoNextImplTest.java +++ b/io.openems.edge.evcs.webasto.next/test/io/openems/edge/evcs/webasto/next/EvcsWebastoNextImplTest.java @@ -8,17 +8,14 @@ public class EvcsWebastoNextImplTest { - private static final String EVCS_ID = "evcs0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new EvcsWebastoNextImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setModbusId(MODBUS_ID) // - .setId(EVCS_ID) // + .setModbusId("modbus0") // + .setId("evcs0") // .setModbusUnitId(1) // .setMaxHwCurrent(32000) // .setMinHwCurrent(6000) // diff --git a/io.openems.edge.evcs.webasto.unite/bnd.bnd b/io.openems.edge.evcs.webasto.unite/bnd.bnd index 2f4e7fe8a62..a4ed98727d0 100644 --- a/io.openems.edge.evcs.webasto.unite/bnd.bnd +++ b/io.openems.edge.evcs.webasto.unite/bnd.bnd @@ -10,6 +10,7 @@ Bundle-Version: 1.0.0.${tstamp} io.openems.edge.bridge.modbus,\ io.openems.edge.common,\ io.openems.edge.evcs.api,\ + io.openems.edge.meter.api,\ -testpath: \ ${testpath} \ No newline at end of file diff --git a/io.openems.edge.evcs.webasto.unite/src/io/openems/edge/evcs/webasto/unite/EvcsWebastoUnite.java b/io.openems.edge.evcs.webasto.unite/src/io/openems/edge/evcs/webasto/unite/EvcsWebastoUnite.java index a7a8803ec81..1341e62a1c1 100644 --- a/io.openems.edge.evcs.webasto.unite/src/io/openems/edge/evcs/webasto/unite/EvcsWebastoUnite.java +++ b/io.openems.edge.evcs.webasto.unite/src/io/openems/edge/evcs/webasto/unite/EvcsWebastoUnite.java @@ -8,8 +8,10 @@ import io.openems.edge.common.channel.Doc; import io.openems.edge.common.channel.WriteChannel; import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.evcs.api.Evcs; +import io.openems.edge.meter.api.ElectricityMeter; -public interface EvcsWebastoUnite extends OpenemsComponent { +public interface EvcsWebastoUnite extends ElectricityMeter, Evcs, OpenemsComponent { public enum ChannelId implements io.openems.edge.common.channel.ChannelId { SERIAL_NUMBER(Doc.of(OpenemsType.STRING) // @@ -41,36 +43,6 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { .accessMode(AccessMode.READ_ONLY)), // EVSE_FAULT_CODE(Doc.of(OpenemsType.INTEGER) // .accessMode(AccessMode.READ_ONLY)), // - CURRENT_L1(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.MILLIAMPERE) // - .accessMode(AccessMode.READ_ONLY)), // - CURRENT_L2(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.MILLIAMPERE) // - .accessMode(AccessMode.READ_ONLY)), // - CURRENT_L3(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.MILLIAMPERE) // - .accessMode(AccessMode.READ_ONLY)), // - VOLTAGE_L1(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT) // - .accessMode(AccessMode.READ_ONLY)), // - VOLTAGE_L2(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT) // - .accessMode(AccessMode.READ_ONLY)), // - VOLTAGE_L3(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT) // - .accessMode(AccessMode.READ_ONLY)), // - ACTIVE_POWER_TOTAL(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT) // - .accessMode(AccessMode.READ_ONLY)), // - ACTIVE_POWER_L1(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT) // - .accessMode(AccessMode.READ_ONLY)), // - ACTIVE_POWER_L2(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT) // - .accessMode(AccessMode.READ_ONLY)), // - ACTIVE_POWER_L3(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT) // - .accessMode(AccessMode.READ_ONLY)), // METER_READING(Doc.of(OpenemsType.INTEGER) // .accessMode(AccessMode.READ_ONLY)), // SESSION_MAX_CURRENT(Doc.of(OpenemsType.INTEGER) // @@ -133,25 +105,6 @@ default void _setAliveValue(int value) throws OpenemsError.OpenemsNamedException channel.setNextWriteValue(value); } - /** - * Gets the Channel for {@link EvcsWebastoUnite.ChannelId#ACTIVE_POWER_TOTAL}. - * - * @return the Channel - */ - default Channel getActivePowerChannel() { - return this.channel(ChannelId.ACTIVE_POWER_TOTAL); - } - - /** - * Gets the Channel for {@link EvcsWebastoUnite.ChannelId#ACTIVE_POWER_TOTAL}. - * - * @return the Channel - */ - default int getActivePower() { - Channel channel = this.getActivePowerChannel(); - return channel.value().orElse(channel.getNextValue().orElse(0)); - } - /** * Gets the Channel for {@link EvcsWebastoUnite.ChannelId#CHARGE_POINT_STATE}. * @@ -171,63 +124,6 @@ default int getChargePointState() { return channel.value().orElse(channel.getNextValue().orElse(-1)); } - /** - * Gets the Channel for {@link EvcsWebastoUnite.ChannelId#CURRENT_L1}. - * - * @return the Channel - */ - default Channel getActivePowerL1Channel() { - return this.channel(ChannelId.ACTIVE_POWER_L1); - } - - /** - * Gets the Channel for {@link EvcsWebastoUnite.ChannelId#CURRENT_L1}. - * - * @return the Channel - */ - default int getActivePowerL1() { - Channel channel = this.getActivePowerL1Channel(); - return channel.value().orElse(channel.getNextValue().orElse(-1)); - } - - /** - * Gets the Channel for {@link EvcsWebastoUnite.ChannelId#CURRENT_L2}. - * - * @return the Channel - */ - default Channel getActivePowerL2Channel() { - return this.channel(ChannelId.ACTIVE_POWER_L2); - } - - /** - * Gets the Channel for {@link EvcsWebastoUnite.ChannelId#CURRENT_L2}. - * - * @return the Channel - */ - default int getActivePowerL2() { - Channel channel = this.getActivePowerL2Channel(); - return channel.value().orElse(channel.getNextValue().orElse(-1)); - } - - /** - * Gets the Channel for {@link EvcsWebastoUnite.ChannelId#CURRENT_L3}. - * - * @return the Channel - */ - default Channel getActivePowerL3Channel() { - return this.channel(ChannelId.ACTIVE_POWER_L3); - } - - /** - * Gets the Channel for {@link EvcsWebastoUnite.ChannelId#CURRENT_L3}. - * - * @return the Channel - */ - default int getActivePowerL3() { - Channel channel = this.getActivePowerL3Channel(); - return channel.value().orElse(channel.getNextValue().orElse(-1)); - } - /** * Gets the Channel for {@link EvcsWebastoUnite.ChannelId#CHARGING_CURRENT}. * diff --git a/io.openems.edge.evcs.webasto.unite/src/io/openems/edge/evcs/webasto/unite/EvcsWebastoUniteImpl.java b/io.openems.edge.evcs.webasto.unite/src/io/openems/edge/evcs/webasto/unite/EvcsWebastoUniteImpl.java index 8c0d5a821f6..460b3f7ac29 100644 --- a/io.openems.edge.evcs.webasto.unite/src/io/openems/edge/evcs/webasto/unite/EvcsWebastoUniteImpl.java +++ b/io.openems.edge.evcs.webasto.unite/src/io/openems/edge/evcs/webasto/unite/EvcsWebastoUniteImpl.java @@ -41,6 +41,7 @@ import io.openems.edge.evcs.api.ManagedEvcs; import io.openems.edge.evcs.api.Phases; import io.openems.edge.evcs.api.WriteHandler; +import io.openems.edge.meter.api.ElectricityMeter; @Designate(ocd = Config.class, factory = true) @Component(// @@ -53,7 +54,7 @@ EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE // }) public class EvcsWebastoUniteImpl extends AbstractOpenemsModbusComponent - implements EvcsWebastoUnite, Evcs, ManagedEvcs, EventHandler, OpenemsComponent { + implements EvcsWebastoUnite, Evcs, ManagedEvcs, EventHandler, ElectricityMeter, OpenemsComponent { private final Logger log = LoggerFactory.getLogger(EvcsWebastoUniteImpl.class); @@ -74,6 +75,7 @@ public class EvcsWebastoUniteImpl extends AbstractOpenemsModbusComponent public EvcsWebastoUniteImpl() { super(// OpenemsComponent.ChannelId.values(), // + ElectricityMeter.ChannelId.values(), // Evcs.ChannelId.values(), // ManagedEvcs.ChannelId.values(), // ModbusComponent.ChannelId.values(), // @@ -150,25 +152,25 @@ protected ModbusProtocol defineModbusProtocol() { new FC4ReadInputRegistersTask(1006, Priority.LOW, m(EvcsWebastoUnite.ChannelId.EVSE_FAULT_CODE, new UnsignedDoublewordElement(1006))), new FC4ReadInputRegistersTask(1008, Priority.HIGH, - m(EvcsWebastoUnite.ChannelId.CURRENT_L1, new UnsignedWordElement(1008))), + m(ElectricityMeter.ChannelId.CURRENT_L1, new UnsignedWordElement(1008))), new FC4ReadInputRegistersTask(1010, Priority.HIGH, - m(EvcsWebastoUnite.ChannelId.CURRENT_L2, new UnsignedWordElement(1010))), + m(ElectricityMeter.ChannelId.CURRENT_L2, new UnsignedWordElement(1010))), new FC4ReadInputRegistersTask(1012, Priority.HIGH, - m(EvcsWebastoUnite.ChannelId.CURRENT_L3, new UnsignedWordElement(1012))), + m(ElectricityMeter.ChannelId.CURRENT_L3, new UnsignedWordElement(1012))), new FC4ReadInputRegistersTask(1014, Priority.LOW, - m(EvcsWebastoUnite.ChannelId.VOLTAGE_L1, new UnsignedWordElement(1014))), + m(ElectricityMeter.ChannelId.VOLTAGE_L1, new UnsignedWordElement(1014))), new FC4ReadInputRegistersTask(1016, Priority.LOW, - m(EvcsWebastoUnite.ChannelId.VOLTAGE_L2, new UnsignedWordElement(1016))), + m(ElectricityMeter.ChannelId.VOLTAGE_L2, new UnsignedWordElement(1016))), new FC4ReadInputRegistersTask(1018, Priority.LOW, - m(EvcsWebastoUnite.ChannelId.VOLTAGE_L3, new UnsignedWordElement(1018))), + m(ElectricityMeter.ChannelId.VOLTAGE_L3, new UnsignedWordElement(1018))), new FC4ReadInputRegistersTask(1020, Priority.HIGH, - m(EvcsWebastoUnite.ChannelId.ACTIVE_POWER_TOTAL, new UnsignedDoublewordElement(1020))), + m(ElectricityMeter.ChannelId.ACTIVE_POWER, new UnsignedDoublewordElement(1020))), new FC4ReadInputRegistersTask(1024, Priority.HIGH, - m(EvcsWebastoUnite.ChannelId.ACTIVE_POWER_L1, new UnsignedDoublewordElement(1024))), + m(ElectricityMeter.ChannelId.ACTIVE_POWER_L1, new UnsignedDoublewordElement(1024))), new FC4ReadInputRegistersTask(1028, Priority.HIGH, - m(EvcsWebastoUnite.ChannelId.ACTIVE_POWER_L2, new UnsignedDoublewordElement(1028))), + m(ElectricityMeter.ChannelId.ACTIVE_POWER_L2, new UnsignedDoublewordElement(1028))), new FC4ReadInputRegistersTask(1032, Priority.HIGH, - m(EvcsWebastoUnite.ChannelId.ACTIVE_POWER_L3, new UnsignedDoublewordElement(1032))), + m(ElectricityMeter.ChannelId.ACTIVE_POWER_L3, new UnsignedDoublewordElement(1032))), new FC4ReadInputRegistersTask(1036, Priority.LOW, m(EvcsWebastoUnite.ChannelId.METER_READING, new UnsignedDoublewordElement(1036))), new FC4ReadInputRegistersTask(1100, Priority.LOW, diff --git a/io.openems.edge.evcs.webasto.unite/src/io/openems/edge/evcs/webasto/unite/WebastoReadHandler.java b/io.openems.edge.evcs.webasto.unite/src/io/openems/edge/evcs/webasto/unite/WebastoReadHandler.java index 3018446dacc..68a8e7fdbbb 100644 --- a/io.openems.edge.evcs.webasto.unite/src/io/openems/edge/evcs/webasto/unite/WebastoReadHandler.java +++ b/io.openems.edge.evcs.webasto.unite/src/io/openems/edge/evcs/webasto/unite/WebastoReadHandler.java @@ -1,5 +1,7 @@ package io.openems.edge.evcs.webasto.unite; +import static io.openems.edge.evcs.api.Evcs.evaluatePhaseCount; + import io.openems.edge.evcs.api.Status; // TODO: Can also be done by registering onSetNextValue listeners on the depending channel in the WebastoImpl. @@ -14,54 +16,28 @@ protected WebastoReadHandler(EvcsWebastoUniteImpl parent) { protected void run() { this.setPhaseCount(); this.setStatus(); - this.parent._setChargePower((int) this.parent.getActivePower()); } private void setStatus() { - switch (this.parent.getChargePointState()) { - case (0): - this.parent._setStatus(Status.NOT_READY_FOR_CHARGING); - break; - case (1): - this.parent._setStatus(Status.READY_FOR_CHARGING); - break; - case (2): - this.parent._setStatus(Status.CHARGING); - break; - case (3): - case (4): - this.parent._setStatus(Status.CHARGING_REJECTED); - break; - case (5): - // TODO Check if this state is also reached while paused - this.parent._setStatus(Status.CHARGING_FINISHED); - break; - case (7): - case (8): - this.parent._setStatus(Status.ERROR); - } + this.parent._setStatus(switch (this.parent.getChargePointState()) { + case 0 -> Status.NOT_READY_FOR_CHARGING; + case 1 -> Status.READY_FOR_CHARGING; + case 2 -> Status.CHARGING; + case 3, 4 -> Status.CHARGING_REJECTED; + case 5 -> Status.CHARGING_FINISHED; + // TODO Check if this state is also reached while paused + case 7, 8 -> Status.ERROR; + default -> null; + }); } /** * Writes the Amount of Phases in the Phase channel. */ private void setPhaseCount() { - int phases = 0; - /* - * The EVCS will pull power from the grid for its own consumption and report - * that on one of the phases. This value is different from EVCS to EVCS but can - * be high. Because of this, this will only register a Phase starting with 100W - * because then we definitively know that this load is caused by a car. - */ - if (this.parent.getActivePowerL1() >= 100) { - phases += 1; - } - if (this.parent.getActivePowerL2() >= 100) { - phases += 1; - } - if (this.parent.getActivePowerL3() >= 100) { - phases += 1; - } - this.parent._setPhases(phases); + this.parent._setPhases(evaluatePhaseCount(// + this.parent.getActivePowerL1().get(), // + this.parent.getActivePowerL2().get(), // + this.parent.getActivePowerL3().get())); } } diff --git a/io.openems.edge.evcs.webasto.unite/test/io/openems/edge/evcs/webasto/unite/EvcsWebastoUniteImplTest.java b/io.openems.edge.evcs.webasto.unite/test/io/openems/edge/evcs/webasto/unite/EvcsWebastoUniteImplTest.java index 41bc0851964..c5bea2c96cb 100644 --- a/io.openems.edge.evcs.webasto.unite/test/io/openems/edge/evcs/webasto/unite/EvcsWebastoUniteImplTest.java +++ b/io.openems.edge.evcs.webasto.unite/test/io/openems/edge/evcs/webasto/unite/EvcsWebastoUniteImplTest.java @@ -8,17 +8,14 @@ public class EvcsWebastoUniteImplTest { - private static final String EVCS_ID = "evcs0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new EvcsWebastoUniteImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setModbusId(MODBUS_ID) // - .setId(EVCS_ID) // + .setModbusId("modbus0") // + .setId("evcs0") // .setModbusUnitId(255) // .setMaxHwCurrent(32_000) // .setMinHwCurrent(6_000) // diff --git a/io.openems.edge.fenecon.dess/test/io/openems/edge/fenecon/dess/charger/FeneconDessCharger1Test.java b/io.openems.edge.fenecon.dess/test/io/openems/edge/fenecon/dess/charger/FeneconDessCharger1Test.java index 20325ec4cbf..146b7240c85 100644 --- a/io.openems.edge.fenecon.dess/test/io/openems/edge/fenecon/dess/charger/FeneconDessCharger1Test.java +++ b/io.openems.edge.fenecon.dess/test/io/openems/edge/fenecon/dess/charger/FeneconDessCharger1Test.java @@ -10,19 +10,15 @@ public class FeneconDessCharger1Test { - private static final String CHARGER_ID = "charger0"; - private static final String ESS_ID = "ess0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { var ess = new FeneconDessEssImpl(); new ComponentTest(ess) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyEssConfig.create() // - .setId(ESS_ID) // - .setModbusId(MODBUS_ID) // + .setId("ess0") // + .setModbusId("modbus0") // .build()) // ; @@ -30,9 +26,9 @@ public void test() throws Exception { .addReference("cm", new DummyConfigurationAdmin()) // .addReference("ess", ess) // .activate(MyChargerConfig.create() // - .setId(CHARGER_ID) // - .setEssId(ESS_ID) // - .setModbusId(MODBUS_ID) // + .setId("charger0") // + .setEssId("ess0") // + .setModbusId("modbus0") // .build()) // ; } diff --git a/io.openems.edge.fenecon.dess/test/io/openems/edge/fenecon/dess/charger/FeneconDessCharger2Test.java b/io.openems.edge.fenecon.dess/test/io/openems/edge/fenecon/dess/charger/FeneconDessCharger2Test.java index 879abb0d8fe..18f69c54492 100644 --- a/io.openems.edge.fenecon.dess/test/io/openems/edge/fenecon/dess/charger/FeneconDessCharger2Test.java +++ b/io.openems.edge.fenecon.dess/test/io/openems/edge/fenecon/dess/charger/FeneconDessCharger2Test.java @@ -10,19 +10,15 @@ public class FeneconDessCharger2Test { - private static final String CHARGER_ID = "charger1"; - private static final String ESS_ID = "ess0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { var ess = new FeneconDessEssImpl(); new ComponentTest(ess) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyEssConfig.create() // - .setId(ESS_ID) // - .setModbusId(MODBUS_ID) // + .setId("ess0") // + .setModbusId("modbus0") // .build()) // ; @@ -30,9 +26,9 @@ public void test() throws Exception { .addReference("cm", new DummyConfigurationAdmin()) // .addReference("ess", ess) // .activate(MyChargerConfig.create() // - .setId(CHARGER_ID) // - .setEssId(ESS_ID) // - .setModbusId(MODBUS_ID) // + .setId("charger1") // + .setEssId("ess0") // + .setModbusId("modbus0") // .build()) // ; } diff --git a/io.openems.edge.fenecon.dess/test/io/openems/edge/fenecon/dess/ess/FeneconDessEssImplTest.java b/io.openems.edge.fenecon.dess/test/io/openems/edge/fenecon/dess/ess/FeneconDessEssImplTest.java index 9a71817d9c8..8fb795dd74d 100644 --- a/io.openems.edge.fenecon.dess/test/io/openems/edge/fenecon/dess/ess/FeneconDessEssImplTest.java +++ b/io.openems.edge.fenecon.dess/test/io/openems/edge/fenecon/dess/ess/FeneconDessEssImplTest.java @@ -8,17 +8,14 @@ public class FeneconDessEssImplTest { - private static final String ESS_ID = "ess0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new FeneconDessEssImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyEssConfig.create() // - .setId(ESS_ID) // - .setModbusId(MODBUS_ID) // + .setId("ess0") // + .setModbusId("modbus0") // .build()) // ; } diff --git a/io.openems.edge.fenecon.dess/test/io/openems/edge/fenecon/dess/gridmeter/FeneconDessGridMeterImplTest.java b/io.openems.edge.fenecon.dess/test/io/openems/edge/fenecon/dess/gridmeter/FeneconDessGridMeterImplTest.java index fd85f499448..a29b0a99e7c 100644 --- a/io.openems.edge.fenecon.dess/test/io/openems/edge/fenecon/dess/gridmeter/FeneconDessGridMeterImplTest.java +++ b/io.openems.edge.fenecon.dess/test/io/openems/edge/fenecon/dess/gridmeter/FeneconDessGridMeterImplTest.java @@ -8,17 +8,14 @@ public class FeneconDessGridMeterImplTest { - private static final String METER_ID = "meter0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new FeneconDessGridMeterImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setModbusId(MODBUS_ID) // + .setId("meter0") // + .setModbusId("modbus0") // .build()) // ; } diff --git a/io.openems.edge.fenecon.dess/test/io/openems/edge/fenecon/dess/pvmeter/FeneconDessPvMeterImplTest.java b/io.openems.edge.fenecon.dess/test/io/openems/edge/fenecon/dess/pvmeter/FeneconDessPvMeterImplTest.java index c849a026396..4af1a5dfcd3 100644 --- a/io.openems.edge.fenecon.dess/test/io/openems/edge/fenecon/dess/pvmeter/FeneconDessPvMeterImplTest.java +++ b/io.openems.edge.fenecon.dess/test/io/openems/edge/fenecon/dess/pvmeter/FeneconDessPvMeterImplTest.java @@ -8,17 +8,14 @@ public class FeneconDessPvMeterImplTest { - private static final String METER_ID = "meter0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new FeneconDessPvMeterImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setModbusId(MODBUS_ID) // + .setId("meter0") // + .setModbusId("modbus0") // .build()) // ; } diff --git a/io.openems.edge.fenecon.mini/test/io/openems/edge/fenecon/mini/ess/FeneconMiniEssImplTest.java b/io.openems.edge.fenecon.mini/test/io/openems/edge/fenecon/mini/ess/FeneconMiniEssImplTest.java index 7535b25a0c3..b83208448ac 100644 --- a/io.openems.edge.fenecon.mini/test/io/openems/edge/fenecon/mini/ess/FeneconMiniEssImplTest.java +++ b/io.openems.edge.fenecon.mini/test/io/openems/edge/fenecon/mini/ess/FeneconMiniEssImplTest.java @@ -1,8 +1,11 @@ package io.openems.edge.fenecon.mini.ess; +import static io.openems.edge.fenecon.mini.ess.FeneconMiniEss.ChannelId.PCS_MODE; +import static io.openems.edge.fenecon.mini.ess.FeneconMiniEss.ChannelId.SETUP_MODE; +import static io.openems.edge.fenecon.mini.ess.FeneconMiniEss.ChannelId.STATE_MACHINE; + import org.junit.Test; -import io.openems.common.types.ChannelAddress; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyConfigurationAdmin; @@ -13,14 +16,6 @@ public class FeneconMiniEssImplTest { - private static final String MODBUS_ID = "modbus0"; - - private static final String ESS_ID = "ess0"; - - private static final ChannelAddress ESS_STATE_MACHINE = new ChannelAddress(ESS_ID, "StateMachine"); - private static final ChannelAddress ESS_PCS_MODE = new ChannelAddress(ESS_ID, "PcsMode"); - private static final ChannelAddress ESS_SETUP_MODE = new ChannelAddress(ESS_ID, "SetupMode"); - /** * Tests activating write-mode when it was not activated before. * @@ -31,34 +26,34 @@ public void testWriteModeSet() throws Exception { new ManagedSymmetricEssTest(new FeneconMiniEssImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("power", new DummyPower()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(ESS_ID) // - .setModbusId(MODBUS_ID) // + .setId("ess0") // + .setModbusId("modbus0") // .setPhase(SinglePhase.L1) // .setReadonly(false) // .build()) // .next(new TestCase() // - .input(ESS_PCS_MODE, PcsMode.ECONOMIC) // - .input(ESS_SETUP_MODE, SetupMode.OFF) // - .output(ESS_STATE_MACHINE, State.UNDEFINED)) // + .input(PCS_MODE, PcsMode.ECONOMIC) // + .input(SETUP_MODE, SetupMode.OFF) // + .output(STATE_MACHINE, State.UNDEFINED)) // .next(new TestCase() // - .output(ESS_STATE_MACHINE, State.GO_WRITE_MODE)) // + .output(STATE_MACHINE, State.GO_WRITE_MODE)) // .next(new TestCase() // - .output(ESS_STATE_MACHINE, State.ACTIVATE_DEBUG_MODE_1)) // + .output(STATE_MACHINE, State.ACTIVATE_DEBUG_MODE_1)) // .next(new TestCase() // - .input(ESS_SETUP_MODE, SetupMode.ON) // - .output(ESS_STATE_MACHINE, State.ACTIVATE_DEBUG_MODE_2)) // + .input(SETUP_MODE, SetupMode.ON) // + .output(STATE_MACHINE, State.ACTIVATE_DEBUG_MODE_2)) // .next(new TestCase() // - .input(ESS_PCS_MODE, PcsMode.DEBUG) // - .output(ESS_STATE_MACHINE, State.ACTIVATE_DEBUG_MODE_3)) // + .input(PCS_MODE, PcsMode.DEBUG) // + .output(STATE_MACHINE, State.ACTIVATE_DEBUG_MODE_3)) // .next(new TestCase() // - .input(ESS_SETUP_MODE, SetupMode.OFF) // - .output(ESS_STATE_MACHINE, State.ACTIVATE_DEBUG_MODE_4)) // + .input(SETUP_MODE, SetupMode.OFF) // + .output(STATE_MACHINE, State.ACTIVATE_DEBUG_MODE_4)) // .next(new TestCase() // - .output(ESS_STATE_MACHINE, State.GO_WRITE_MODE)) // + .output(STATE_MACHINE, State.GO_WRITE_MODE)) // .next(new TestCase() // - .output(ESS_STATE_MACHINE, State.WRITE_MODE)) // + .output(STATE_MACHINE, State.WRITE_MODE)) // ; } @@ -72,21 +67,21 @@ public void testWriteModeAlreadySet() throws Exception { new ManagedSymmetricEssTest(new FeneconMiniEssImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("power", new DummyPower()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(ESS_ID) // - .setModbusId(MODBUS_ID) // + .setId("ess0") // + .setModbusId("modbus0") // .setPhase(SinglePhase.L1) // .setReadonly(false) // .build()) // .next(new TestCase() // - .input(ESS_PCS_MODE, PcsMode.DEBUG) // - .input(ESS_SETUP_MODE, SetupMode.OFF) // - .output(ESS_STATE_MACHINE, State.UNDEFINED)) // + .input(PCS_MODE, PcsMode.DEBUG) // + .input(SETUP_MODE, SetupMode.OFF) // + .output(STATE_MACHINE, State.UNDEFINED)) // .next(new TestCase() // - .output(ESS_STATE_MACHINE, State.GO_WRITE_MODE)) // + .output(STATE_MACHINE, State.GO_WRITE_MODE)) // .next(new TestCase() // - .output(ESS_STATE_MACHINE, State.WRITE_MODE)) // + .output(STATE_MACHINE, State.WRITE_MODE)) // ; } @@ -100,34 +95,34 @@ public void testReadonlyModeSet() throws Exception { new ManagedSymmetricEssTest(new FeneconMiniEssImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("power", new DummyPower()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(ESS_ID) // - .setModbusId(MODBUS_ID) // + .setId("ess0") // + .setModbusId("modbus0") // .setPhase(SinglePhase.L1) // .setReadonly(true) // .build()) // .next(new TestCase() // - .input(ESS_PCS_MODE, PcsMode.DEBUG) // - .input(ESS_SETUP_MODE, SetupMode.OFF) // - .output(ESS_STATE_MACHINE, State.UNDEFINED)) // + .input(PCS_MODE, PcsMode.DEBUG) // + .input(SETUP_MODE, SetupMode.OFF) // + .output(STATE_MACHINE, State.UNDEFINED)) // .next(new TestCase() // - .output(ESS_STATE_MACHINE, State.GO_READONLY_MODE)) // + .output(STATE_MACHINE, State.GO_READONLY_MODE)) // .next(new TestCase() // - .output(ESS_STATE_MACHINE, State.ACTIVATE_ECONOMIC_MODE_1)) // + .output(STATE_MACHINE, State.ACTIVATE_ECONOMIC_MODE_1)) // .next(new TestCase() // - .input(ESS_SETUP_MODE, SetupMode.ON) // - .output(ESS_STATE_MACHINE, State.ACTIVATE_ECONOMIC_MODE_2)) // + .input(SETUP_MODE, SetupMode.ON) // + .output(STATE_MACHINE, State.ACTIVATE_ECONOMIC_MODE_2)) // .next(new TestCase() // - .input(ESS_PCS_MODE, PcsMode.ECONOMIC) // - .output(ESS_STATE_MACHINE, State.ACTIVATE_ECONOMIC_MODE_3)) // + .input(PCS_MODE, PcsMode.ECONOMIC) // + .output(STATE_MACHINE, State.ACTIVATE_ECONOMIC_MODE_3)) // .next(new TestCase() // - .input(ESS_SETUP_MODE, SetupMode.OFF) // - .output(ESS_STATE_MACHINE, State.ACTIVATE_ECONOMIC_MODE_4)) // + .input(SETUP_MODE, SetupMode.OFF) // + .output(STATE_MACHINE, State.ACTIVATE_ECONOMIC_MODE_4)) // .next(new TestCase() // - .output(ESS_STATE_MACHINE, State.GO_READONLY_MODE)) // + .output(STATE_MACHINE, State.GO_READONLY_MODE)) // .next(new TestCase() // - .output(ESS_STATE_MACHINE, State.READONLY_MODE)) // + .output(STATE_MACHINE, State.READONLY_MODE)) // ; } @@ -141,34 +136,34 @@ public void testReadonlyModeAlreadySet() throws Exception { new ManagedSymmetricEssTest(new FeneconMiniEssImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("power", new DummyPower()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(ESS_ID) // - .setModbusId(MODBUS_ID) // + .setId("ess0") // + .setModbusId("modbus0") // .setPhase(SinglePhase.L1) // .setReadonly(true) // .build()) // .next(new TestCase() // - .input(ESS_PCS_MODE, PcsMode.DEBUG) // - .input(ESS_SETUP_MODE, SetupMode.OFF) // - .output(ESS_STATE_MACHINE, State.UNDEFINED)) // + .input(PCS_MODE, PcsMode.DEBUG) // + .input(SETUP_MODE, SetupMode.OFF) // + .output(STATE_MACHINE, State.UNDEFINED)) // .next(new TestCase() // - .output(ESS_STATE_MACHINE, State.GO_READONLY_MODE)) // + .output(STATE_MACHINE, State.GO_READONLY_MODE)) // .next(new TestCase() // - .output(ESS_STATE_MACHINE, State.ACTIVATE_ECONOMIC_MODE_1)) // + .output(STATE_MACHINE, State.ACTIVATE_ECONOMIC_MODE_1)) // .next(new TestCase() // - .input(ESS_SETUP_MODE, SetupMode.ON) // - .output(ESS_STATE_MACHINE, State.ACTIVATE_ECONOMIC_MODE_2)) // + .input(SETUP_MODE, SetupMode.ON) // + .output(STATE_MACHINE, State.ACTIVATE_ECONOMIC_MODE_2)) // .next(new TestCase() // - .input(ESS_PCS_MODE, PcsMode.ECONOMIC) // - .output(ESS_STATE_MACHINE, State.ACTIVATE_ECONOMIC_MODE_3)) // + .input(PCS_MODE, PcsMode.ECONOMIC) // + .output(STATE_MACHINE, State.ACTIVATE_ECONOMIC_MODE_3)) // .next(new TestCase() // - .input(ESS_SETUP_MODE, SetupMode.OFF) // - .output(ESS_STATE_MACHINE, State.ACTIVATE_ECONOMIC_MODE_4)) // + .input(SETUP_MODE, SetupMode.OFF) // + .output(STATE_MACHINE, State.ACTIVATE_ECONOMIC_MODE_4)) // .next(new TestCase() // - .output(ESS_STATE_MACHINE, State.GO_READONLY_MODE)) // + .output(STATE_MACHINE, State.GO_READONLY_MODE)) // .next(new TestCase() // - .output(ESS_STATE_MACHINE, State.READONLY_MODE)) // + .output(STATE_MACHINE, State.READONLY_MODE)) // ; } } diff --git a/io.openems.edge.fenecon.mini/test/io/openems/edge/fenecon/mini/gridmeter/FeneconMiniGridMeterImplTest.java b/io.openems.edge.fenecon.mini/test/io/openems/edge/fenecon/mini/gridmeter/FeneconMiniGridMeterImplTest.java index 9f22123b8b5..e478c89f29f 100644 --- a/io.openems.edge.fenecon.mini/test/io/openems/edge/fenecon/mini/gridmeter/FeneconMiniGridMeterImplTest.java +++ b/io.openems.edge.fenecon.mini/test/io/openems/edge/fenecon/mini/gridmeter/FeneconMiniGridMeterImplTest.java @@ -8,17 +8,14 @@ public class FeneconMiniGridMeterImplTest { - private static final String METER_ID = "meter0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new FeneconMiniGridMeterImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setModbusId(MODBUS_ID) // + .setId("meter0") // + .setModbusId("modbus0") // .build()) // ; } diff --git a/io.openems.edge.fenecon.mini/test/io/openems/edge/fenecon/mini/pvmeter/FeneconMiniPvMeterImplTest.java b/io.openems.edge.fenecon.mini/test/io/openems/edge/fenecon/mini/pvmeter/FeneconMiniPvMeterImplTest.java index 143b1e2d51a..59e45468495 100644 --- a/io.openems.edge.fenecon.mini/test/io/openems/edge/fenecon/mini/pvmeter/FeneconMiniPvMeterImplTest.java +++ b/io.openems.edge.fenecon.mini/test/io/openems/edge/fenecon/mini/pvmeter/FeneconMiniPvMeterImplTest.java @@ -8,17 +8,14 @@ public class FeneconMiniPvMeterImplTest { - private static final String METER_ID = "meter0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new FeneconMiniPvMeterImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setModbusId(MODBUS_ID) // + .setId("meter0") // + .setModbusId("modbus0") // .build()) // ; } diff --git a/io.openems.edge.fenecon.pro/test/io/openems/edge/fenecon/pro/ess/FeneconProEssImplTest.java b/io.openems.edge.fenecon.pro/test/io/openems/edge/fenecon/pro/ess/FeneconProEssImplTest.java index 05e9ee82109..31a40767aca 100644 --- a/io.openems.edge.fenecon.pro/test/io/openems/edge/fenecon/pro/ess/FeneconProEssImplTest.java +++ b/io.openems.edge.fenecon.pro/test/io/openems/edge/fenecon/pro/ess/FeneconProEssImplTest.java @@ -9,18 +9,15 @@ public class FeneconProEssImplTest { - private static final String ESS_ID = "ess0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new FeneconProEssImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("power", new DummyPower()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(ESS_ID) // - .setModbusId(MODBUS_ID) // + .setId("ess0") // + .setModbusId("modbus0") // .build()) // ; } diff --git a/io.openems.edge.fenecon.pro/test/io/openems/edge/fenecon/pro/pvmeter/FeneconProPvMeterImplTest.java b/io.openems.edge.fenecon.pro/test/io/openems/edge/fenecon/pro/pvmeter/FeneconProPvMeterImplTest.java index d9163f8438f..d46d42f0cc1 100644 --- a/io.openems.edge.fenecon.pro/test/io/openems/edge/fenecon/pro/pvmeter/FeneconProPvMeterImplTest.java +++ b/io.openems.edge.fenecon.pro/test/io/openems/edge/fenecon/pro/pvmeter/FeneconProPvMeterImplTest.java @@ -8,17 +8,14 @@ public class FeneconProPvMeterImplTest { - private static final String METER_ID = "meter0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new FeneconProPvMeterImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setModbusId(MODBUS_ID) // + .setId("meter0") // + .setModbusId("modbus0") // .build()) // ; } diff --git a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverterImplTest.java b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverterImplTest.java index 5473b431528..c8180b66657 100644 --- a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverterImplTest.java +++ b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/batteryinverter/GoodWeBatteryInverterImplTest.java @@ -1,13 +1,45 @@ package io.openems.edge.goodwe.batteryinverter; +import static io.openems.edge.battery.api.Battery.ChannelId.CHARGE_MAX_CURRENT; +import static io.openems.edge.batteryinverter.api.SymmetricBatteryInverter.ChannelId.ACTIVE_POWER; +import static io.openems.edge.batteryinverter.api.SymmetricBatteryInverter.ChannelId.MAX_APPARENT_POWER; +import static io.openems.edge.common.sum.Sum.ChannelId.GRID_ACTIVE_POWER; +import static io.openems.edge.ess.dccharger.api.EssDcCharger.ChannelId.ACTUAL_POWER; +import static io.openems.edge.ess.dccharger.api.EssDcCharger.ChannelId.CURRENT; +import static io.openems.edge.ess.dccharger.api.EssDcCharger.ChannelId.VOLTAGE; +import static io.openems.edge.goodwe.GoodWeConstants.DEFAULT_UNIT_ID; import static io.openems.edge.goodwe.batteryinverter.GoodWeBatteryInverterImpl.doSetBmsVoltage; +import static io.openems.edge.goodwe.common.GoodWe.ChannelId.EMS_POWER_MODE; +import static io.openems.edge.goodwe.common.GoodWe.ChannelId.EMS_POWER_SET; +import static io.openems.edge.goodwe.common.GoodWe.ChannelId.MAX_AC_EXPORT; +import static io.openems.edge.goodwe.common.GoodWe.ChannelId.MAX_AC_IMPORT; +import static io.openems.edge.goodwe.common.GoodWe.ChannelId.METER_COMMUNICATE_STATUS; +import static io.openems.edge.goodwe.common.GoodWe.ChannelId.MPPT1_I; +import static io.openems.edge.goodwe.common.GoodWe.ChannelId.MPPT1_P; +import static io.openems.edge.goodwe.common.GoodWe.ChannelId.MPPT2_I; +import static io.openems.edge.goodwe.common.GoodWe.ChannelId.MPPT2_P; +import static io.openems.edge.goodwe.common.GoodWe.ChannelId.MPPT3_I; +import static io.openems.edge.goodwe.common.GoodWe.ChannelId.MPPT3_P; +import static io.openems.edge.goodwe.common.GoodWe.ChannelId.TWO_S_PV1_I; +import static io.openems.edge.goodwe.common.GoodWe.ChannelId.TWO_S_PV1_V; +import static io.openems.edge.goodwe.common.GoodWe.ChannelId.TWO_S_PV2_I; +import static io.openems.edge.goodwe.common.GoodWe.ChannelId.TWO_S_PV2_V; +import static io.openems.edge.goodwe.common.GoodWe.ChannelId.TWO_S_PV3_I; +import static io.openems.edge.goodwe.common.GoodWe.ChannelId.TWO_S_PV3_V; +import static io.openems.edge.goodwe.common.GoodWe.ChannelId.TWO_S_PV4_I; +import static io.openems.edge.goodwe.common.GoodWe.ChannelId.TWO_S_PV4_V; +import static io.openems.edge.goodwe.common.GoodWe.ChannelId.TWO_S_PV5_I; +import static io.openems.edge.goodwe.common.GoodWe.ChannelId.TWO_S_PV5_V; +import static io.openems.edge.goodwe.common.GoodWe.ChannelId.TWO_S_PV6_I; +import static io.openems.edge.goodwe.common.GoodWe.ChannelId.TWO_S_PV6_V; +import static io.openems.edge.goodwe.common.GoodWe.ChannelId.WBMS_CHARGE_MAX_CURRENT; +import static io.openems.edge.goodwe.common.GoodWe.ChannelId.WBMS_DISCHARGE_MAX_CURRENT; +import static io.openems.edge.goodwe.common.GoodWe.ChannelId.WBMS_VOLTAGE; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Test; -import io.openems.common.types.ChannelAddress; -import io.openems.edge.battery.api.Battery; import io.openems.edge.battery.test.DummyBattery; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.channel.value.Value; @@ -18,7 +50,6 @@ import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.common.test.DummyConfigurationAdmin; import io.openems.edge.ess.test.DummyPower; -import io.openems.edge.goodwe.GoodWeConstants; import io.openems.edge.goodwe.charger.singlestring.GoodWeChargerPv1; import io.openems.edge.goodwe.charger.twostring.GoodWeChargerTwoStringImpl; import io.openems.edge.goodwe.charger.twostring.PvPort; @@ -32,85 +63,17 @@ @SuppressWarnings("deprecation") public class GoodWeBatteryInverterImplTest { - private static final String MODBUS_ID = "modbus0"; - private static final String BATTERY_ID = "battery0"; - private static final String BATTERY_INVERTER_ID = "batteryInverter0"; - private static final String CHARGER_ID = "charger0"; - private static final String CHARGER_2_ID = "charger1"; - private static final String CHARGER_3_ID = "charger2"; - private static final String CHARGER_4_ID = "charger3"; - private static final String CHARGER_5_ID = "charger4"; - private static final String CHARGER_6_ID = "charger5"; - private static final String SUM_ID = "_sum"; - - private static final Battery BATTERY = new DummyBattery(BATTERY_ID); - - private static final ChannelAddress EMS_POWER_MODE = new ChannelAddress(BATTERY_INVERTER_ID, "EmsPowerMode"); - private static final ChannelAddress EMS_POWER_SET = new ChannelAddress(BATTERY_INVERTER_ID, "EmsPowerSet"); - private static final ChannelAddress METER_COMMUNICATE_STATUS = new ChannelAddress(BATTERY_INVERTER_ID, - "MeterCommunicateStatus"); - private static final ChannelAddress MAX_AC_IMPORT = new ChannelAddress(BATTERY_INVERTER_ID, "MaxAcImport"); - private static final ChannelAddress MAX_AC_EXPORT = new ChannelAddress(BATTERY_INVERTER_ID, "MaxAcExport"); - private static final ChannelAddress GRID_ACTIVE_POWER = new ChannelAddress(SUM_ID, "GridActivePower"); - private static final ChannelAddress ACTIVE_POWER = new ChannelAddress(BATTERY_INVERTER_ID, "ActivePower"); - private static final ChannelAddress CHARGE_MAX_CURRENT = new ChannelAddress(BATTERY_ID, "ChargeMaxCurrent"); - private static final ChannelAddress WBMS_CHARGE_MAX_CURRENT = new ChannelAddress(BATTERY_INVERTER_ID, - "WbmsChargeMaxCurrent"); - private static final ChannelAddress WBMS_DISCHARGE_MAX_CURRENT = new ChannelAddress(BATTERY_INVERTER_ID, - "WbmsDischargeMaxCurrent"); - private static final ChannelAddress WBMS_VOLTAGE = new ChannelAddress(BATTERY_INVERTER_ID, "WbmsVoltage"); - private static final ChannelAddress MAX_APPARENT_POWER = new ChannelAddress(BATTERY_INVERTER_ID, - "MaxApparentPower"); - - private static final ChannelAddress CHARGER_ACTUAL_POWER = new ChannelAddress(CHARGER_ID, "ActualPower"); - private static final ChannelAddress CHARGER_VOLTAGE = new ChannelAddress(CHARGER_ID, "Voltage"); - private static final ChannelAddress CHARGER_CURRENT = new ChannelAddress(CHARGER_ID, "Current"); - private static final ChannelAddress CHARGER_2_ACTUAL_POWER = new ChannelAddress(CHARGER_2_ID, "ActualPower"); - private static final ChannelAddress CHARGER_2_VOLTAGE = new ChannelAddress(CHARGER_2_ID, "Voltage"); - private static final ChannelAddress CHARGER_2_CURRENT = new ChannelAddress(CHARGER_2_ID, "Current"); - private static final ChannelAddress CHARGER_3_ACTUAL_POWER = new ChannelAddress(CHARGER_3_ID, "ActualPower"); - private static final ChannelAddress CHARGER_3_VOLTAGE = new ChannelAddress(CHARGER_3_ID, "Voltage"); - private static final ChannelAddress CHARGER_3_CURRENT = new ChannelAddress(CHARGER_3_ID, "Current"); - private static final ChannelAddress CHARGER_4_ACTUAL_POWER = new ChannelAddress(CHARGER_4_ID, "ActualPower"); - private static final ChannelAddress CHARGER_4_VOLTAGE = new ChannelAddress(CHARGER_4_ID, "Voltage"); - private static final ChannelAddress CHARGER_4_CURRENT = new ChannelAddress(CHARGER_4_ID, "Current"); - private static final ChannelAddress CHARGER_5_ACTUAL_POWER = new ChannelAddress(CHARGER_5_ID, "ActualPower"); - private static final ChannelAddress CHARGER_5_VOLTAGE = new ChannelAddress(CHARGER_5_ID, "Voltage"); - private static final ChannelAddress CHARGER_5_CURRENT = new ChannelAddress(CHARGER_5_ID, "Current"); - private static final ChannelAddress CHARGER_6_ACTUAL_POWER = new ChannelAddress(CHARGER_6_ID, "ActualPower"); - private static final ChannelAddress CHARGER_6_VOLTAGE = new ChannelAddress(CHARGER_6_ID, "Voltage"); - private static final ChannelAddress CHARGER_6_CURRENT = new ChannelAddress(CHARGER_6_ID, "Current"); - - private static final ChannelAddress MPPT1_P = new ChannelAddress(BATTERY_INVERTER_ID, "Mppt1P"); - private static final ChannelAddress MPPT1_I = new ChannelAddress(BATTERY_INVERTER_ID, "Mppt1I"); - private static final ChannelAddress MPPT2_P = new ChannelAddress(BATTERY_INVERTER_ID, "Mppt2P"); - private static final ChannelAddress MPPT2_I = new ChannelAddress(BATTERY_INVERTER_ID, "Mppt2I"); - private static final ChannelAddress MPPT3_P = new ChannelAddress(BATTERY_INVERTER_ID, "Mppt3P"); - private static final ChannelAddress MPPT3_I = new ChannelAddress(BATTERY_INVERTER_ID, "Mppt3I"); - private static final ChannelAddress TWO_S_PV1_I = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv1I"); - private static final ChannelAddress TWO_S_PV1_V = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv1V"); - private static final ChannelAddress TWO_S_PV2_I = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv2I"); - private static final ChannelAddress TWO_S_PV2_V = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv2V"); - private static final ChannelAddress TWO_S_PV3_I = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv3I"); - private static final ChannelAddress TWO_S_PV3_V = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv3V"); - private static final ChannelAddress TWO_S_PV4_I = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv4I"); - private static final ChannelAddress TWO_S_PV4_V = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv4V"); - private static final ChannelAddress TWO_S_PV5_I = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv5I"); - private static final ChannelAddress TWO_S_PV5_V = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv5V"); - private static final ChannelAddress TWO_S_PV6_I = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv6I"); - private static final ChannelAddress TWO_S_PV6_V = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv6V"); - @Test public void testEt() throws Exception { var charger = new GoodWeChargerPv1(); new ComponentTest(charger) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(io.openems.edge.goodwe.charger.singlestring.MyConfig.create() // - .setId(CHARGER_ID) // - .setBatteryInverterId(BATTERY_INVERTER_ID) // - .setModbusId(MODBUS_ID) // - .setModbusUnitId(GoodWeConstants.DEFAULT_UNIT_ID) // + .setId("charger0") // + .setBatteryInverterId("batteryInverter0") // + .setModbusId("modbus0") // + .setModbusUnitId(DEFAULT_UNIT_ID) // .build()); var ess = new GoodWeBatteryInverterImpl(); @@ -119,13 +82,13 @@ public void testEt() throws Exception { .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .addReference("sum", new DummySum()) // .addComponent(charger) // .activate(MyConfig.create() // - .setId(BATTERY_INVERTER_ID) // - .setModbusId(MODBUS_ID) // - .setModbusUnitId(GoodWeConstants.DEFAULT_UNIT_ID) // + .setId("batteryInverter0") // + .setModbusId("modbus0") // + .setModbusUnitId(DEFAULT_UNIT_ID) // .setSafetyCountry(SafetyCountry.GERMANY) // .setMpptForShadowEnable(EnableDisable.ENABLE) // .setBackupEnable(EnableDisable.ENABLE) // @@ -140,9 +103,9 @@ public void testEt() throws Exception { .input(ACTIVE_POWER, 0) // .input(MAX_AC_IMPORT, 0) // .input(MAX_AC_EXPORT, 0) // - .input(CHARGER_ACTUAL_POWER, 2000) // + .input("charger0", ACTUAL_POWER, 2000) // .onExecuteWriteCallbacks(() -> { - ess.run(BATTERY, 1000, 0); + ess.run(new DummyBattery("battery0"), 1000, 0); }) // .output(EMS_POWER_MODE, EmsPowerMode.CHARGE_BAT) // .output(EMS_POWER_SET, 1000)); @@ -155,12 +118,12 @@ public void testNegativSetActivePoint() throws Exception { .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .addReference("sum", new DummySum()) // .activate(MyConfig.create() // - .setId(BATTERY_INVERTER_ID) // - .setModbusId(MODBUS_ID) // - .setModbusUnitId(GoodWeConstants.DEFAULT_UNIT_ID) // + .setId("batteryInverter0") // + .setModbusId("modbus0") // + .setModbusUnitId(DEFAULT_UNIT_ID) // .setSafetyCountry(SafetyCountry.GERMANY) // .setMpptForShadowEnable(EnableDisable.ENABLE) // .setBackupEnable(EnableDisable.ENABLE) // @@ -176,7 +139,7 @@ public void testNegativSetActivePoint() throws Exception { .input(MAX_AC_IMPORT, 0) // .input(MAX_AC_EXPORT, 0) // .onExecuteWriteCallbacks(() -> { - ess.run(BATTERY, -1000, 0); + ess.run(new DummyBattery("battery0"), -1000, 0); }) // .output(EMS_POWER_MODE, EmsPowerMode.CHARGE_BAT) // .output(EMS_POWER_SET, 1000)); @@ -189,12 +152,12 @@ public void testDischargeBattery() throws Exception { .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .addReference("sum", new DummySum()) // .activate(MyConfig.create() // - .setId(BATTERY_INVERTER_ID) // - .setModbusId(MODBUS_ID) // - .setModbusUnitId(GoodWeConstants.DEFAULT_UNIT_ID) // + .setId("batteryInverter0") // + .setModbusId("modbus0") // + .setModbusUnitId(DEFAULT_UNIT_ID) // .setSafetyCountry(SafetyCountry.GERMANY) // .setMpptForShadowEnable(EnableDisable.ENABLE) // .setBackupEnable(EnableDisable.ENABLE) // @@ -210,7 +173,7 @@ public void testDischargeBattery() throws Exception { .input(MAX_AC_IMPORT, 0) // .input(MAX_AC_EXPORT, 0) // .onExecuteWriteCallbacks(() -> { - ess.run(BATTERY, 1000, 0); + ess.run(new DummyBattery("battery0"), 1000, 0); }) // .output(EMS_POWER_MODE, EmsPowerMode.DISCHARGE_BAT) // .output(EMS_POWER_SET, 1000)); @@ -223,12 +186,12 @@ public void testEmsPowerModeAutoWithBalancing() throws Exception { .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .addReference("sum", new DummySum()) // .activate(MyConfig.create() // - .setId(BATTERY_INVERTER_ID) // - .setModbusId(MODBUS_ID) // - .setModbusUnitId(GoodWeConstants.DEFAULT_UNIT_ID) // + .setId("batteryInverter0") // + .setModbusId("modbus0") // + .setModbusUnitId(DEFAULT_UNIT_ID) // .setSafetyCountry(SafetyCountry.GERMANY) // .setMpptForShadowEnable(EnableDisable.ENABLE) // .setBackupEnable(EnableDisable.ENABLE) // @@ -243,7 +206,7 @@ public void testEmsPowerModeAutoWithBalancing() throws Exception { .input(GRID_ACTIVE_POWER, 2000) // .input(ACTIVE_POWER, 4000) // .onExecuteWriteCallbacks(() -> { - ess.run(BATTERY, 6000, 0); + ess.run(new DummyBattery("battery0"), 6000, 0); }) // .output(EMS_POWER_MODE, EmsPowerMode.AUTO) // .output(EMS_POWER_SET, 0)); @@ -254,12 +217,12 @@ public void testEmsPowerModeAutoWithSurplus() throws Exception { var charger = new GoodWeChargerPv1(); new ComponentTest(charger) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(io.openems.edge.goodwe.charger.singlestring.MyConfig.create() // - .setId(CHARGER_ID) // - .setBatteryInverterId(BATTERY_INVERTER_ID) // - .setModbusId(MODBUS_ID) // - .setModbusUnitId(GoodWeConstants.DEFAULT_UNIT_ID) // + .setId("charger0") // + .setBatteryInverterId("batteryInverter0") // + .setModbusId("modbus0") // + .setModbusUnitId(DEFAULT_UNIT_ID) // .build()); var ess = new GoodWeBatteryInverterImpl(); @@ -267,15 +230,15 @@ public void testEmsPowerModeAutoWithSurplus() throws Exception { new ComponentTest(ess) // .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .addReference("componentManager", new DummyComponentManager()) // .addReference("sum", new DummySum()) // .addComponent(charger) // - .addComponent(BATTERY) // + .addComponent(new DummyBattery("battery0")) // .activate(MyConfig.create() // - .setId(BATTERY_INVERTER_ID) // - .setModbusId(MODBUS_ID) // - .setModbusUnitId(GoodWeConstants.DEFAULT_UNIT_ID) // + .setId("batteryInverter0") // + .setModbusId("modbus0") // + .setModbusUnitId(DEFAULT_UNIT_ID) // .setSafetyCountry(SafetyCountry.GERMANY) // .setMpptForShadowEnable(EnableDisable.ENABLE) // .setBackupEnable(EnableDisable.ENABLE) // @@ -287,9 +250,9 @@ public void testEmsPowerModeAutoWithSurplus() throws Exception { .build()) // .next(new TestCase() // .input(METER_COMMUNICATE_STATUS, MeterCommunicateStatus.OK) // - .input(CHARGER_ACTUAL_POWER, 10000) // - .input(CHARGE_MAX_CURRENT, 20).onExecuteWriteCallbacks(() -> { - ess.run(BATTERY, 10000, 0); + .input("charger0", ACTUAL_POWER, 10000) // + .input("battery0", CHARGE_MAX_CURRENT, 20).onExecuteWriteCallbacks(() -> { + ess.run(new DummyBattery("battery0"), 10000, 0); }) // .output(EMS_POWER_MODE, EmsPowerMode.AUTO) // .output(EMS_POWER_SET, 0)); @@ -302,12 +265,12 @@ public void testEmsPowerModeAutoWithMaxAcImport() throws Exception { .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .addReference("sum", new DummySum()) // .activate(MyConfig.create() // - .setId(BATTERY_INVERTER_ID) // - .setModbusId(MODBUS_ID) // - .setModbusUnitId(GoodWeConstants.DEFAULT_UNIT_ID) // + .setId("batteryInverter0") // + .setModbusId("modbus0") // + .setModbusUnitId(DEFAULT_UNIT_ID) // .setSafetyCountry(SafetyCountry.GERMANY) // .setMpptForShadowEnable(EnableDisable.ENABLE) // .setBackupEnable(EnableDisable.ENABLE) // @@ -321,7 +284,7 @@ public void testEmsPowerModeAutoWithMaxAcImport() throws Exception { .input(METER_COMMUNICATE_STATUS, MeterCommunicateStatus.OK) // .input(MAX_AC_IMPORT, 3000) // .onExecuteWriteCallbacks(() -> { - ess.run(BATTERY, 3000, 0); + ess.run(new DummyBattery("battery0"), 3000, 0); }) // .output(EMS_POWER_MODE, EmsPowerMode.AUTO) // .output(EMS_POWER_SET, 0)); @@ -334,12 +297,12 @@ public void testEmsPowerModeAutoWithMaxAcExport() throws Exception { .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .addReference("sum", new DummySum()) // .activate(MyConfig.create() // - .setId(BATTERY_INVERTER_ID) // - .setModbusId(MODBUS_ID) // - .setModbusUnitId(GoodWeConstants.DEFAULT_UNIT_ID) // + .setId("batteryInverter0") // + .setModbusId("modbus0") // + .setModbusUnitId(DEFAULT_UNIT_ID) // .setSafetyCountry(SafetyCountry.GERMANY) // .setMpptForShadowEnable(EnableDisable.ENABLE) // .setBackupEnable(EnableDisable.ENABLE) // @@ -353,7 +316,7 @@ public void testEmsPowerModeAutoWithMaxAcExport() throws Exception { .input(METER_COMMUNICATE_STATUS, MeterCommunicateStatus.OK) // .input(MAX_AC_EXPORT, 8000) // .onExecuteWriteCallbacks(() -> { - ess.run(BATTERY, 8000, 0); + ess.run(new DummyBattery("battery0"), 8000, 0); }) // .output(EMS_POWER_MODE, EmsPowerMode.AUTO) // .output(EMS_POWER_SET, 0)); @@ -366,12 +329,12 @@ public void testBatteryIsFull() throws Exception { .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .addReference("sum", new DummySum()) // .activate(MyConfig.create() // - .setId(BATTERY_INVERTER_ID) // - .setModbusId(MODBUS_ID) // - .setModbusUnitId(GoodWeConstants.DEFAULT_UNIT_ID) // + .setId("batteryInverter0") // + .setModbusId("modbus0") // + .setModbusUnitId(DEFAULT_UNIT_ID) // .setSafetyCountry(SafetyCountry.GERMANY) // .setMpptForShadowEnable(EnableDisable.ENABLE) // .setBackupEnable(EnableDisable.ENABLE) // @@ -385,7 +348,7 @@ public void testBatteryIsFull() throws Exception { .input(METER_COMMUNICATE_STATUS, MeterCommunicateStatus.OK) // .input(MAX_AC_IMPORT, 0) // .onExecuteWriteCallbacks(() -> { - ess.run(BATTERY, 0, 0); + ess.run(new DummyBattery("battery0"), 0, 0); }) // .output(EMS_POWER_MODE, EmsPowerMode.AUTO) // .output(EMS_POWER_SET, 0)); @@ -398,12 +361,12 @@ public void testBatteryIsEmpty() throws Exception { .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .addReference("sum", new DummySum()) // .activate(MyConfig.create() // - .setId(BATTERY_INVERTER_ID) // - .setModbusId(MODBUS_ID) // - .setModbusUnitId(GoodWeConstants.DEFAULT_UNIT_ID) // + .setId("batteryInverter0") // + .setModbusId("modbus0") // + .setModbusUnitId(DEFAULT_UNIT_ID) // .setSafetyCountry(SafetyCountry.GERMANY) // .setMpptForShadowEnable(EnableDisable.ENABLE) // .setBackupEnable(EnableDisable.ENABLE) // @@ -417,7 +380,7 @@ public void testBatteryIsEmpty() throws Exception { .input(METER_COMMUNICATE_STATUS, MeterCommunicateStatus.OK) // .input(MAX_AC_EXPORT, 0) // .onExecuteWriteCallbacks(() -> { - ess.run(BATTERY, 0, 0); + ess.run(new DummyBattery("battery0"), 0, 0); }) // .output(EMS_POWER_MODE, EmsPowerMode.AUTO) // .output(EMS_POWER_SET, 0)); @@ -430,12 +393,12 @@ public void testAcCalculation() throws Exception { .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .addReference("sum", new DummySum()) // - .addComponent(BATTERY).activate(MyConfig.create() // - .setId(BATTERY_INVERTER_ID) // - .setModbusId(MODBUS_ID) // - .setModbusUnitId(GoodWeConstants.DEFAULT_UNIT_ID) // + .addComponent(new DummyBattery("battery0")).activate(MyConfig.create() // + .setId("batteryInverter0") // + .setModbusId("modbus0") // + .setModbusUnitId(DEFAULT_UNIT_ID) // .setSafetyCountry(SafetyCountry.GERMANY) // .setMpptForShadowEnable(EnableDisable.ENABLE) // .setBackupEnable(EnableDisable.ENABLE) // @@ -451,7 +414,7 @@ public void testAcCalculation() throws Exception { .input(WBMS_VOLTAGE, 325) // .input(MAX_APPARENT_POWER, 10000) // .onExecuteWriteCallbacks(() -> { - ess.run(BATTERY, 0, 0); + ess.run(new DummyBattery("battery0"), 0, 0); }) // .output(MAX_AC_IMPORT, 0) // .output(MAX_AC_EXPORT, 325)); @@ -471,8 +434,8 @@ public void testTwoStringCharger() throws Exception { .addReference("cm", new DummyConfigurationAdmin()) // .addReference("essOrBatteryInverter", ess) // .activate(io.openems.edge.goodwe.charger.twostring.MyConfig.create() // - .setId(CHARGER_ID) // - .setBatteryInverterId(BATTERY_INVERTER_ID) // + .setId("charger0") // + .setBatteryInverterId("batteryInverter0") // .setPvPort(PvPort.PV_1) // .build()); @@ -480,8 +443,8 @@ public void testTwoStringCharger() throws Exception { .addReference("cm", new DummyConfigurationAdmin()) // .addReference("essOrBatteryInverter", ess) // .activate(io.openems.edge.goodwe.charger.twostring.MyConfig.create() // - .setId(CHARGER_2_ID) // - .setBatteryInverterId(BATTERY_INVERTER_ID) // + .setId("charger1") // + .setBatteryInverterId("batteryInverter0") // .setPvPort(PvPort.PV_2) // .build()); @@ -489,8 +452,8 @@ public void testTwoStringCharger() throws Exception { .addReference("cm", new DummyConfigurationAdmin()) // .addReference("essOrBatteryInverter", ess) // .activate(io.openems.edge.goodwe.charger.twostring.MyConfig.create() // - .setId(CHARGER_3_ID) // - .setBatteryInverterId(BATTERY_INVERTER_ID) // + .setId("charger2") // + .setBatteryInverterId("batteryInverter0") // .setPvPort(PvPort.PV_3) // .build()); @@ -498,8 +461,8 @@ public void testTwoStringCharger() throws Exception { .addReference("cm", new DummyConfigurationAdmin()) // .addReference("essOrBatteryInverter", ess) // .activate(io.openems.edge.goodwe.charger.twostring.MyConfig.create() // - .setId(CHARGER_4_ID) // - .setBatteryInverterId(BATTERY_INVERTER_ID) // + .setId("charger3") // + .setBatteryInverterId("batteryInverter0") // .setPvPort(PvPort.PV_4) // .build()); @@ -507,8 +470,8 @@ public void testTwoStringCharger() throws Exception { .addReference("cm", new DummyConfigurationAdmin()) // .addReference("essOrBatteryInverter", ess) // .activate(io.openems.edge.goodwe.charger.twostring.MyConfig.create() // - .setId(CHARGER_5_ID) // - .setBatteryInverterId(BATTERY_INVERTER_ID) // + .setId("charger4") // + .setBatteryInverterId("batteryInverter0") // .setPvPort(PvPort.PV_5) // .build()); @@ -516,8 +479,8 @@ public void testTwoStringCharger() throws Exception { .addReference("cm", new DummyConfigurationAdmin()) // .addReference("essOrBatteryInverter", ess) // .activate(io.openems.edge.goodwe.charger.twostring.MyConfig.create() // - .setId(CHARGER_6_ID) // - .setBatteryInverterId(BATTERY_INVERTER_ID) // + .setId("charger5") // + .setBatteryInverterId("batteryInverter0") // .setPvPort(PvPort.PV_6) // .build()); @@ -527,15 +490,15 @@ public void testTwoStringCharger() throws Exception { .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .addReference("sum", new DummySum()) // .addComponent(charger1) // .addComponent(charger2) // - .addComponent(BATTERY) // + .addComponent(new DummyBattery("battery0")) // .activate(MyConfig.create() // - .setId(BATTERY_INVERTER_ID) // - .setModbusId(MODBUS_ID) // - .setModbusUnitId(GoodWeConstants.DEFAULT_UNIT_ID) // + .setId("batteryInverter0") // + .setModbusId("modbus0") // + .setModbusUnitId(DEFAULT_UNIT_ID) // .setSafetyCountry(SafetyCountry.GERMANY) // .setMpptForShadowEnable(EnableDisable.ENABLE) // .setBackupEnable(EnableDisable.ENABLE) // @@ -554,19 +517,19 @@ public void testTwoStringCharger() throws Exception { .input(TWO_S_PV2_V, 240) // // Values applied in the next cycle - .output(CHARGER_ACTUAL_POWER, 0) // - .output(CHARGER_2_ACTUAL_POWER, 0) // - .output(CHARGER_CURRENT, null) // - .output(CHARGER_2_CURRENT, null) // - .output(CHARGER_VOLTAGE, null) // - .output(CHARGER_2_VOLTAGE, null)) // + .output("charger0", ACTUAL_POWER, 0) // + .output("charger1", ACTUAL_POWER, 0) // + .output("charger0", CURRENT, null) // + .output("charger1", CURRENT, null) // + .output("charger0", VOLTAGE, null) // + .output("charger1", VOLTAGE, null)) // .next(new TestCase() // - .output(CHARGER_ACTUAL_POWER, 1000) // - .output(CHARGER_2_ACTUAL_POWER, 1000) // - .output(CHARGER_CURRENT, 10) // - .output(CHARGER_2_CURRENT, 10) // - .output(CHARGER_VOLTAGE, 240) // - .output(CHARGER_2_VOLTAGE, 240)) // + .output("charger0", ACTUAL_POWER, 1000) // + .output("charger1", ACTUAL_POWER, 1000) // + .output("charger0", CURRENT, 10) // + .output("charger1", CURRENT, 10) // + .output("charger0", VOLTAGE, 240) // + .output("charger1", VOLTAGE, 240)) // // Chargers with different current values .next(new TestCase() // @@ -574,22 +537,22 @@ public void testTwoStringCharger() throws Exception { .input(MPPT1_P, 2000) // .input(TWO_S_PV1_I, 5) // .input(TWO_S_PV2_I, 15) // - .output(CHARGER_ACTUAL_POWER, 1000) // - .output(CHARGER_2_ACTUAL_POWER, 1000)) // + .output("charger0", ACTUAL_POWER, 1000) // + .output("charger1", ACTUAL_POWER, 1000)) // .next(new TestCase() // - .output(CHARGER_ACTUAL_POWER, 500) // - .output(CHARGER_2_ACTUAL_POWER, 1500)) // + .output("charger0", ACTUAL_POWER, 500) // + .output("charger1", ACTUAL_POWER, 1500)) // .next(new TestCase() // .input(MPPT1_I, 20) // .input(MPPT1_P, 2000) // .input(TWO_S_PV1_I, 20) // .input(TWO_S_PV2_I, 0) // - .output(CHARGER_ACTUAL_POWER, 500) // - .output(CHARGER_2_ACTUAL_POWER, 1500)) // + .output("charger0", ACTUAL_POWER, 500) // + .output("charger1", ACTUAL_POWER, 1500)) // .next(new TestCase() // - .output(CHARGER_ACTUAL_POWER, 2000) // - .output(CHARGER_2_ACTUAL_POWER, 0) // + .output("charger0", ACTUAL_POWER, 2000) // + .output("charger1", ACTUAL_POWER, 0) // ); /* @@ -601,15 +564,15 @@ public void testTwoStringCharger() throws Exception { .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .addReference("sum", new DummySum()) // .addComponent(charger3) // .addComponent(charger4) // - .addComponent(BATTERY) // + .addComponent(new DummyBattery("battery0")) // .activate(MyConfig.create() // - .setId(BATTERY_INVERTER_ID) // - .setModbusId(MODBUS_ID) // - .setModbusUnitId(GoodWeConstants.DEFAULT_UNIT_ID) // + .setId("batteryInverter0") // + .setModbusId("modbus0") // + .setModbusUnitId(DEFAULT_UNIT_ID) // .setSafetyCountry(SafetyCountry.GERMANY) // .setMpptForShadowEnable(EnableDisable.ENABLE) // .setBackupEnable(EnableDisable.ENABLE) // @@ -628,19 +591,19 @@ public void testTwoStringCharger() throws Exception { .input(TWO_S_PV4_V, 240) // // Values applied in the next cycle - .output(CHARGER_3_ACTUAL_POWER, 0) // - .output(CHARGER_4_ACTUAL_POWER, 0) // - .output(CHARGER_3_CURRENT, null) // - .output(CHARGER_4_CURRENT, null) // - .output(CHARGER_3_VOLTAGE, null) // - .output(CHARGER_4_VOLTAGE, null)) // + .output("charger2", ACTUAL_POWER, 0) // + .output("charger3", ACTUAL_POWER, 0) // + .output("charger2", CURRENT, null) // + .output("charger3", CURRENT, null) // + .output("charger2", VOLTAGE, null) // + .output("charger3", VOLTAGE, null)) // .next(new TestCase() // - .output(CHARGER_3_ACTUAL_POWER, 1000) // - .output(CHARGER_4_ACTUAL_POWER, 1000) // - .output(CHARGER_3_CURRENT, 10) // - .output(CHARGER_4_CURRENT, 10) // - .output(CHARGER_3_VOLTAGE, 240) // - .output(CHARGER_4_VOLTAGE, 240)) // + .output("charger2", ACTUAL_POWER, 1000) // + .output("charger3", ACTUAL_POWER, 1000) // + .output("charger2", CURRENT, 10) // + .output("charger3", CURRENT, 10) // + .output("charger2", VOLTAGE, 240) // + .output("charger3", VOLTAGE, 240)) // // Chargers with different current values .next(new TestCase() // @@ -648,22 +611,22 @@ public void testTwoStringCharger() throws Exception { .input(MPPT2_P, 2000) // .input(TWO_S_PV3_I, 5) // .input(TWO_S_PV4_I, 15) // - .output(CHARGER_3_ACTUAL_POWER, 1000) // - .output(CHARGER_4_ACTUAL_POWER, 1000)) // + .output("charger2", ACTUAL_POWER, 1000) // + .output("charger3", ACTUAL_POWER, 1000)) // .next(new TestCase() // - .output(CHARGER_3_ACTUAL_POWER, 500) // - .output(CHARGER_4_ACTUAL_POWER, 1500)) // + .output("charger2", ACTUAL_POWER, 500) // + .output("charger3", ACTUAL_POWER, 1500)) // .next(new TestCase() // .input(MPPT2_I, 20) // .input(MPPT2_P, 2000) // .input(TWO_S_PV3_I, 20) // .input(TWO_S_PV4_I, 0) // - .output(CHARGER_3_ACTUAL_POWER, 500) // - .output(CHARGER_4_ACTUAL_POWER, 1500)) // + .output("charger2", ACTUAL_POWER, 500) // + .output("charger3", ACTUAL_POWER, 1500)) // .next(new TestCase() // - .output(CHARGER_3_ACTUAL_POWER, 2000) // - .output(CHARGER_4_ACTUAL_POWER, 0) // + .output("charger2", ACTUAL_POWER, 2000) // + .output("charger3", ACTUAL_POWER, 0) // ); /* @@ -675,15 +638,15 @@ public void testTwoStringCharger() throws Exception { .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .addReference("sum", new DummySum()) // .addComponent(charger5) // .addComponent(charger6) // - .addComponent(BATTERY) // + .addComponent(new DummyBattery("battery0")) // .activate(MyConfig.create() // - .setId(BATTERY_INVERTER_ID) // - .setModbusId(MODBUS_ID) // - .setModbusUnitId(GoodWeConstants.DEFAULT_UNIT_ID) // + .setId("batteryInverter0") // + .setModbusId("modbus0") // + .setModbusUnitId(DEFAULT_UNIT_ID) // .setSafetyCountry(SafetyCountry.GERMANY) // .setMpptForShadowEnable(EnableDisable.ENABLE) // .setBackupEnable(EnableDisable.ENABLE) // @@ -702,19 +665,19 @@ public void testTwoStringCharger() throws Exception { .input(TWO_S_PV6_V, 240) // // Values applied in the next cycle - .output(CHARGER_5_ACTUAL_POWER, 0) // - .output(CHARGER_6_ACTUAL_POWER, 0) // - .output(CHARGER_5_CURRENT, null) // - .output(CHARGER_6_CURRENT, null) // - .output(CHARGER_5_VOLTAGE, null) // - .output(CHARGER_6_VOLTAGE, null)) // + .output("charger4", ACTUAL_POWER, 0) // + .output("charger5", ACTUAL_POWER, 0) // + .output("charger4", CURRENT, null) // + .output("charger5", CURRENT, null) // + .output("charger4", VOLTAGE, null) // + .output("charger5", VOLTAGE, null)) // .next(new TestCase() // - .output(CHARGER_5_ACTUAL_POWER, 1000) // - .output(CHARGER_6_ACTUAL_POWER, 1000) // - .output(CHARGER_5_CURRENT, 10) // - .output(CHARGER_6_CURRENT, 10) // - .output(CHARGER_5_VOLTAGE, 240) // - .output(CHARGER_6_VOLTAGE, 240)) // + .output("charger4", ACTUAL_POWER, 1000) // + .output("charger5", ACTUAL_POWER, 1000) // + .output("charger4", CURRENT, 10) // + .output("charger5", CURRENT, 10) // + .output("charger4", VOLTAGE, 240) // + .output("charger5", VOLTAGE, 240)) // // Chargers with different current values .next(new TestCase() // @@ -722,22 +685,22 @@ public void testTwoStringCharger() throws Exception { .input(MPPT3_P, 2000) // .input(TWO_S_PV5_I, 5) // .input(TWO_S_PV6_I, 15) // - .output(CHARGER_5_ACTUAL_POWER, 1000) // - .output(CHARGER_6_ACTUAL_POWER, 1000)) // + .output("charger4", ACTUAL_POWER, 1000) // + .output("charger5", ACTUAL_POWER, 1000)) // .next(new TestCase() // - .output(CHARGER_5_ACTUAL_POWER, 500) // - .output(CHARGER_6_ACTUAL_POWER, 1500)) // + .output("charger4", ACTUAL_POWER, 500) // + .output("charger5", ACTUAL_POWER, 1500)) // .next(new TestCase() // .input(MPPT3_I, 20) // .input(MPPT3_P, 2000) // .input(TWO_S_PV5_I, 20) // .input(TWO_S_PV6_I, 0) // - .output(CHARGER_5_ACTUAL_POWER, 500) // - .output(CHARGER_6_ACTUAL_POWER, 1500)) // + .output("charger4", ACTUAL_POWER, 500) // + .output("charger5", ACTUAL_POWER, 1500)) // .next(new TestCase() // - .output(CHARGER_5_ACTUAL_POWER, 2000) // - .output(CHARGER_6_ACTUAL_POWER, 0) // + .output("charger4", ACTUAL_POWER, 2000) // + .output("charger5", ACTUAL_POWER, 0) // ); } diff --git a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/mppt/twostring/GoodWeChargerMpptTwoStringImplTest.java b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/mppt/twostring/GoodWeChargerMpptTwoStringImplTest.java index 591db516cd4..a7ad15707c2 100644 --- a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/mppt/twostring/GoodWeChargerMpptTwoStringImplTest.java +++ b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/mppt/twostring/GoodWeChargerMpptTwoStringImplTest.java @@ -2,8 +2,6 @@ import org.junit.Test; -import io.openems.common.types.ChannelAddress; -import io.openems.edge.battery.api.Battery; import io.openems.edge.battery.test.DummyBattery; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.startstop.StartStopConfig; @@ -12,9 +10,11 @@ import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.common.test.DummyConfigurationAdmin; +import io.openems.edge.ess.dccharger.api.EssDcCharger; import io.openems.edge.ess.test.DummyPower; import io.openems.edge.goodwe.GoodWeConstants; import io.openems.edge.goodwe.batteryinverter.GoodWeBatteryInverterImpl; +import io.openems.edge.goodwe.common.GoodWe; import io.openems.edge.goodwe.common.enums.ControlMode; import io.openems.edge.goodwe.common.enums.EnableDisable; import io.openems.edge.goodwe.common.enums.FeedInPowerSettings; @@ -22,94 +22,57 @@ public class GoodWeChargerMpptTwoStringImplTest { - private static final String MODBUS_ID = "modbus0"; - private static final String BATTERY_ID = "battery0"; - private static final String CHARGER_1_ID = "charger0"; - private static final String CHARGER_2_ID = "charger1"; - private static final String CHARGER_3_ID = "charger2"; - private static final String BATTERY_INVERTER_ID = "batteryInverter0"; - - private static final Battery BATTERY = new DummyBattery(BATTERY_ID); - - private static final ChannelAddress MPPT1_P = new ChannelAddress(BATTERY_INVERTER_ID, "Mppt1P"); - private static final ChannelAddress MPPT1_I = new ChannelAddress(BATTERY_INVERTER_ID, "Mppt1I"); - private static final ChannelAddress MPPT2_P = new ChannelAddress(BATTERY_INVERTER_ID, "Mppt2P"); - private static final ChannelAddress MPPT2_I = new ChannelAddress(BATTERY_INVERTER_ID, "Mppt2I"); - private static final ChannelAddress MPPT3_P = new ChannelAddress(BATTERY_INVERTER_ID, "Mppt3P"); - private static final ChannelAddress MPPT3_I = new ChannelAddress(BATTERY_INVERTER_ID, "Mppt3I"); - private static final ChannelAddress TWO_S_PV1_I = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv1I"); - private static final ChannelAddress TWO_S_PV1_V = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv1V"); - private static final ChannelAddress TWO_S_PV2_I = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv2I"); - private static final ChannelAddress TWO_S_PV2_V = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv2V"); - private static final ChannelAddress TWO_S_PV3_I = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv3I"); - private static final ChannelAddress TWO_S_PV3_V = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv3V"); - private static final ChannelAddress TWO_S_PV4_I = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv4I"); - private static final ChannelAddress TWO_S_PV4_V = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv4V"); - private static final ChannelAddress TWO_S_PV5_I = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv5I"); - private static final ChannelAddress TWO_S_PV5_V = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv5V"); - private static final ChannelAddress TWO_S_PV6_I = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv6I"); - private static final ChannelAddress TWO_S_PV6_V = new ChannelAddress(BATTERY_INVERTER_ID, "TwoSPv6V"); - private static final ChannelAddress CHARGER_1_ACTUAL_POWER = new ChannelAddress(CHARGER_1_ID, "ActualPower"); - private static final ChannelAddress CHARGER_1_VOLTAGE = new ChannelAddress(CHARGER_1_ID, "Voltage"); - private static final ChannelAddress CHARGER_1_CURRENT = new ChannelAddress(CHARGER_1_ID, "Current"); - private static final ChannelAddress CHARGER_2_ACTUAL_POWER = new ChannelAddress(CHARGER_2_ID, "ActualPower"); - private static final ChannelAddress CHARGER_2_VOLTAGE = new ChannelAddress(CHARGER_2_ID, "Voltage"); - private static final ChannelAddress CHARGER_2_CURRENT = new ChannelAddress(CHARGER_2_ID, "Current"); - private static final ChannelAddress CHARGER_3_ACTUAL_POWER = new ChannelAddress(CHARGER_3_ID, "ActualPower"); - private static final ChannelAddress CHARGER_3_VOLTAGE = new ChannelAddress(CHARGER_3_ID, "Voltage"); - private static final ChannelAddress CHARGER_3_CURRENT = new ChannelAddress(CHARGER_3_ID, "Current"); - @Test public void test() throws Exception { - var ess = new GoodWeBatteryInverterImpl(); + var inverter = new GoodWeBatteryInverterImpl(); var charger1 = new GoodWeChargerMpptTwoStringImpl(); var charger2 = new GoodWeChargerMpptTwoStringImpl(); var charger3 = new GoodWeChargerMpptTwoStringImpl(); new ComponentTest(charger1) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("essOrBatteryInverter", ess) // + .addReference("essOrBatteryInverter", inverter) // .activate(MyConfig.create() // - .setId(CHARGER_1_ID) // - .setBatteryInverterId(BATTERY_INVERTER_ID) // + .setId("charger0") // + .setBatteryInverterId("batteryInverter0") // .setMpptPort(MpptPort.MPPT_1) // .build()); new ComponentTest(charger2) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("essOrBatteryInverter", ess) // + .addReference("essOrBatteryInverter", inverter) // .activate(MyConfig.create() // - .setId(CHARGER_2_ID) // - .setBatteryInverterId(BATTERY_INVERTER_ID) // + .setId("charger1") // + .setBatteryInverterId("batteryInverter0") // .setMpptPort(MpptPort.MPPT_2) // .build()); new ComponentTest(charger3) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("essOrBatteryInverter", ess) // + .addReference("essOrBatteryInverter", inverter) // .activate(MyConfig.create() // - .setId(CHARGER_3_ID) // - .setBatteryInverterId(BATTERY_INVERTER_ID) // + .setId("charger2") // + .setBatteryInverterId("batteryInverter0") // .setMpptPort(MpptPort.MPPT_3) // .build()); - ess.addCharger(charger1); - ess.addCharger(charger2); - ess.addCharger(charger3); + inverter.addCharger(charger1); + inverter.addCharger(charger2); + inverter.addCharger(charger3); - new ComponentTest(ess) // + new ComponentTest(inverter) // .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", new DummyComponentManager()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .addReference("sum", new DummySum()) // .addComponent(charger1) // .addComponent(charger2) // .addComponent(charger3) // - .addComponent(BATTERY) // + .addComponent(new DummyBattery("battery0")) // .activate(io.openems.edge.goodwe.batteryinverter.MyConfig.create() // - .setId(BATTERY_INVERTER_ID) // - .setModbusId(MODBUS_ID) // + .setId("batteryInverter0") // + .setModbusId("modbus0") // .setModbusUnitId(GoodWeConstants.DEFAULT_UNIT_ID) // .setSafetyCountry(SafetyCountry.GERMANY) // .setMpptForShadowEnable(EnableDisable.ENABLE) // @@ -121,74 +84,74 @@ public void test() throws Exception { .setStartStop(StartStopConfig.START) // .build()) // .next(new TestCase() // - .input(MPPT1_I, 20) // - .input(MPPT1_P, 2000) // - .input(TWO_S_PV1_I, 10) // - .input(TWO_S_PV2_I, 10) // - .input(TWO_S_PV1_V, 240) // - .input(TWO_S_PV2_V, 240)) // + .input(GoodWe.ChannelId.MPPT1_I, 20) // + .input(GoodWe.ChannelId.MPPT1_P, 2000) // + .input(GoodWe.ChannelId.TWO_S_PV1_I, 10) // + .input(GoodWe.ChannelId.TWO_S_PV2_I, 10) // + .input(GoodWe.ChannelId.TWO_S_PV1_V, 240) // + .input(GoodWe.ChannelId.TWO_S_PV2_V, 240)) // // Values applied in the next cycle .next(new TestCase() // - .output(CHARGER_1_ACTUAL_POWER, 2000) // - .output(CHARGER_1_CURRENT, 20) // - .output(CHARGER_1_VOLTAGE, 240) // - .output(CHARGER_2_ACTUAL_POWER, null) // - .output(CHARGER_2_CURRENT, null) // - .output(CHARGER_2_VOLTAGE, null) // - .output(CHARGER_3_ACTUAL_POWER, null) // - .output(CHARGER_3_CURRENT, null) // - .output(CHARGER_3_VOLTAGE, null) // + .output("charger0", EssDcCharger.ChannelId.ACTUAL_POWER, 2000) // + .output("charger0", EssDcCharger.ChannelId.CURRENT, 20) // + .output("charger0", EssDcCharger.ChannelId.VOLTAGE, 240) // + .output("charger1", EssDcCharger.ChannelId.ACTUAL_POWER, null) // + .output("charger1", EssDcCharger.ChannelId.CURRENT, null) // + .output("charger1", EssDcCharger.ChannelId.VOLTAGE, null) // + .output("charger2", EssDcCharger.ChannelId.ACTUAL_POWER, null) // + .output("charger2", EssDcCharger.ChannelId.CURRENT, null) // + .output("charger2", EssDcCharger.ChannelId.VOLTAGE, null) // ) // // Chargers with different current values .next(new TestCase() // - .input(MPPT1_I, 20) // - .input(MPPT1_P, 3000) // - .input(TWO_S_PV1_I, 5) // - .input(TWO_S_PV2_I, 15) // - .input(TWO_S_PV1_V, 250) // - .input(TWO_S_PV2_V, 250)) // + .input(GoodWe.ChannelId.MPPT1_I, 20) // + .input(GoodWe.ChannelId.MPPT1_P, 3000) // + .input(GoodWe.ChannelId.TWO_S_PV1_I, 5) // + .input(GoodWe.ChannelId.TWO_S_PV2_I, 15) // + .input(GoodWe.ChannelId.TWO_S_PV1_V, 250) // + .input(GoodWe.ChannelId.TWO_S_PV2_V, 250)) // .next(new TestCase() // - .output(CHARGER_1_ACTUAL_POWER, 3000) // - .output(CHARGER_1_CURRENT, 20) // - .output(CHARGER_1_VOLTAGE, 250) // - .output(CHARGER_2_ACTUAL_POWER, null) // - .output(CHARGER_2_CURRENT, null) // - .output(CHARGER_2_VOLTAGE, null). // - output(CHARGER_3_ACTUAL_POWER, null) // - .output(CHARGER_3_CURRENT, null) // - .output(CHARGER_3_VOLTAGE, null) // + .output("charger0", EssDcCharger.ChannelId.ACTUAL_POWER, 3000) // + .output("charger0", EssDcCharger.ChannelId.CURRENT, 20) // + .output("charger0", EssDcCharger.ChannelId.VOLTAGE, 250) // + .output("charger1", EssDcCharger.ChannelId.ACTUAL_POWER, null) // + .output("charger1", EssDcCharger.ChannelId.CURRENT, null) // + .output("charger1", EssDcCharger.ChannelId.VOLTAGE, null) // + .output("charger2", EssDcCharger.ChannelId.ACTUAL_POWER, null) // + .output("charger2", EssDcCharger.ChannelId.CURRENT, null) // + .output("charger2", EssDcCharger.ChannelId.VOLTAGE, null) // ) .next(new TestCase() // - .input(MPPT1_I, 20) // - .input(MPPT1_P, 2000) // - .input(MPPT2_I, 30) // - .input(MPPT2_P, 3000) // - .input(MPPT3_I, 40) // - .input(MPPT3_P, 4000) // - .input(TWO_S_PV1_I, 10) // - .input(TWO_S_PV1_V, 250) // - .input(TWO_S_PV2_I, 10) // - .input(TWO_S_PV2_V, 250) // - .input(TWO_S_PV3_I, 15) // - .input(TWO_S_PV3_V, 280) // - .input(TWO_S_PV4_I, 15) // - .input(TWO_S_PV4_V, 280) // - .input(TWO_S_PV5_I, 20) // - .input(TWO_S_PV5_V, 299) // - .input(TWO_S_PV6_I, 20) // - .input(TWO_S_PV6_V, 299)) // + .input(GoodWe.ChannelId.MPPT1_I, 20) // + .input(GoodWe.ChannelId.MPPT1_P, 2000) // + .input(GoodWe.ChannelId.MPPT2_I, 30) // + .input(GoodWe.ChannelId.MPPT2_P, 3000) // + .input(GoodWe.ChannelId.MPPT3_I, 40) // + .input(GoodWe.ChannelId.MPPT3_P, 4000) // + .input(GoodWe.ChannelId.TWO_S_PV1_I, 10) // + .input(GoodWe.ChannelId.TWO_S_PV1_V, 250) // + .input(GoodWe.ChannelId.TWO_S_PV2_I, 10) // + .input(GoodWe.ChannelId.TWO_S_PV2_V, 250) // + .input(GoodWe.ChannelId.TWO_S_PV3_I, 15) // + .input(GoodWe.ChannelId.TWO_S_PV3_V, 280) // + .input(GoodWe.ChannelId.TWO_S_PV4_I, 15) // + .input(GoodWe.ChannelId.TWO_S_PV4_V, 280) // + .input(GoodWe.ChannelId.TWO_S_PV5_I, 20) // + .input(GoodWe.ChannelId.TWO_S_PV5_V, 299) // + .input(GoodWe.ChannelId.TWO_S_PV6_I, 20) // + .input(GoodWe.ChannelId.TWO_S_PV6_V, 299)) // .next(new TestCase() // - .output(CHARGER_1_ACTUAL_POWER, 2000) // - .output(CHARGER_1_CURRENT, 20) // - .output(CHARGER_1_VOLTAGE, 250) // - .output(CHARGER_2_ACTUAL_POWER, 3000) // - .output(CHARGER_2_CURRENT, 30) // - .output(CHARGER_2_VOLTAGE, 280). // - output(CHARGER_3_ACTUAL_POWER, 4000) // - .output(CHARGER_3_CURRENT, 40) // - .output(CHARGER_3_VOLTAGE, 299) // + .output("charger0", EssDcCharger.ChannelId.ACTUAL_POWER, 2000) // + .output("charger0", EssDcCharger.ChannelId.CURRENT, 20) // + .output("charger0", EssDcCharger.ChannelId.VOLTAGE, 250) // + .output("charger1", EssDcCharger.ChannelId.ACTUAL_POWER, 3000) // + .output("charger1", EssDcCharger.ChannelId.CURRENT, 30) // + .output("charger1", EssDcCharger.ChannelId.VOLTAGE, 280) // + .output("charger2", EssDcCharger.ChannelId.ACTUAL_POWER, 4000) // + .output("charger2", EssDcCharger.ChannelId.CURRENT, 40) // + .output("charger2", EssDcCharger.ChannelId.VOLTAGE, 299) // ); } } diff --git a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/singlestring/GoodWeChargerPv1Test.java b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/singlestring/GoodWeChargerPv1Test.java index 36ec9b90b80..e296380ac59 100644 --- a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/singlestring/GoodWeChargerPv1Test.java +++ b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/singlestring/GoodWeChargerPv1Test.java @@ -8,19 +8,15 @@ public class GoodWeChargerPv1Test { - private static final String MODBUS_ID = "modbus0"; - private static final String ESS_ID = "ess0"; - private static final String CHARGER_ID = "charger0"; - @Test public void test() throws Exception { new ComponentTest(new GoodWeChargerPv1()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(CHARGER_ID) // - .setBatteryInverterId(ESS_ID) // - .setModbusId(MODBUS_ID) // + .setId("charger0") // + .setBatteryInverterId("ess0") // + .setModbusId("modbus0") // .build()); } } diff --git a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/singlestring/GoodWeChargerPv2Test.java b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/singlestring/GoodWeChargerPv2Test.java index 754badab30e..77dd4956860 100644 --- a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/singlestring/GoodWeChargerPv2Test.java +++ b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/singlestring/GoodWeChargerPv2Test.java @@ -8,19 +8,15 @@ public class GoodWeChargerPv2Test { - private static final String MODBUS_ID = "modbus0"; - private static final String ESS_ID = "ess0"; - private static final String CHARGER_ID = "charger0"; - @Test public void test() throws Exception { new ComponentTest(new GoodWeChargerPv2()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(CHARGER_ID) // - .setBatteryInverterId(ESS_ID) // - .setModbusId(MODBUS_ID) // + .setId("charger0") // + .setBatteryInverterId("ess0") // + .setModbusId("modbus0") // .build()); } } diff --git a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/twostring/GoodWeChargerTwoStringImplTest.java b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/twostring/GoodWeChargerTwoStringImplTest.java index 3d2e5340e78..2c678e67e38 100644 --- a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/twostring/GoodWeChargerTwoStringImplTest.java +++ b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/twostring/GoodWeChargerTwoStringImplTest.java @@ -8,9 +8,6 @@ public class GoodWeChargerTwoStringImplTest { - private static final String ESS_ID = "ess0"; - private static final String CHARGER_ID = "charger0"; - @SuppressWarnings("deprecation") @Test public void test() throws Exception { @@ -18,8 +15,8 @@ public void test() throws Exception { .addReference("cm", new DummyConfigurationAdmin()) // .addReference("essOrBatteryInverter", new GoodWeEssImpl()) // .activate(MyConfig.create() // - .setId(CHARGER_ID) // - .setBatteryInverterId(ESS_ID) // + .setId("charger0") // + .setBatteryInverterId("ess0") // .setPvPort(PvPort.PV_1) // .build()); } diff --git a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/emergencypowermeter/GoodWeEmergencyPowerMeterTest.java b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/emergencypowermeter/GoodWeEmergencyPowerMeterTest.java index 6c08cecae9b..463fd4d32f4 100644 --- a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/emergencypowermeter/GoodWeEmergencyPowerMeterTest.java +++ b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/emergencypowermeter/GoodWeEmergencyPowerMeterTest.java @@ -8,18 +8,14 @@ public class GoodWeEmergencyPowerMeterTest { - private static final String MODBUS_ID = "modbus0"; - - private static final String METER_ID = "meter2"; - @Test public void test() throws Exception { new ComponentTest(new GoodWeEmergencyPowerMeterImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setModbusId(MODBUS_ID) // + .setId("meter2") // + .setModbusId("modbus0") // .build()); } } diff --git a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/ess/GoodWeEssImplTest.java b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/ess/GoodWeEssImplTest.java index bfde5088729..f6dec937023 100644 --- a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/ess/GoodWeEssImplTest.java +++ b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/ess/GoodWeEssImplTest.java @@ -1,5 +1,7 @@ package io.openems.edge.goodwe.ess; +import static io.openems.edge.goodwe.GoodWeConstants.DEFAULT_UNIT_ID; + import org.junit.Test; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; @@ -7,27 +9,22 @@ import io.openems.edge.common.test.DummyConfigurationAdmin; import io.openems.edge.ess.test.DummyPower; import io.openems.edge.ess.test.ManagedSymmetricEssTest; -import io.openems.edge.goodwe.GoodWeConstants; import io.openems.edge.goodwe.charger.singlestring.GoodWeChargerPv1; import io.openems.edge.goodwe.common.enums.ControlMode; public class GoodWeEssImplTest { - private static final String ESS_ID = "ess0"; - private static final String MODBUS_ID = "modbus0"; - private static final String CHARGER_ID = "charger0"; - @Test public void testEt() throws Exception { var charger = new GoodWeChargerPv1(); new ComponentTest(charger) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(io.openems.edge.goodwe.charger.singlestring.MyConfig.create() // - .setId(CHARGER_ID) // - .setBatteryInverterId(ESS_ID) // - .setModbusId(MODBUS_ID) // - .setModbusUnitId(GoodWeConstants.DEFAULT_UNIT_ID) // + .setId("charger0") // + .setBatteryInverterId("ess0") // + .setModbusId("modbus0") // + .setModbusUnitId(DEFAULT_UNIT_ID) // .build()); var ess = new GoodWeEssImpl(); @@ -35,12 +32,12 @@ public void testEt() throws Exception { new ManagedSymmetricEssTest(ess) // .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .addComponent(charger) // .activate(MyConfig.create() // - .setId(ESS_ID) // - .setModbusId(MODBUS_ID) // - .setModbusUnitId(GoodWeConstants.DEFAULT_UNIT_ID) // + .setId("ess0") // + .setModbusId("modbus0") // + .setModbusUnitId(DEFAULT_UNIT_ID) // .setCapacity(9_000) // .setMaxBatteryPower(5_200) // .setControlMode(ControlMode.SMART) // @@ -54,11 +51,11 @@ public void testBt() throws Exception { new ManagedSymmetricEssTest(ess) // .addReference("power", new DummyPower()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(ESS_ID) // - .setModbusId(MODBUS_ID) // - .setModbusUnitId(GoodWeConstants.DEFAULT_UNIT_ID) // + .setId("ess0") // + .setModbusId("modbus0") // + .setModbusUnitId(DEFAULT_UNIT_ID) // .setCapacity(9_000) // .setMaxBatteryPower(5_200) // .setControlMode(ControlMode.SMART) // diff --git a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/gridmeter/GoodWeGridMeterImplTest.java b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/gridmeter/GoodWeGridMeterImplTest.java index 47b532280ad..79d1e0cf4d3 100644 --- a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/gridmeter/GoodWeGridMeterImplTest.java +++ b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/gridmeter/GoodWeGridMeterImplTest.java @@ -1,10 +1,17 @@ package io.openems.edge.goodwe.gridmeter; +import static io.openems.edge.goodwe.gridmeter.GoodWeGridMeter.ChannelId.EXTERNAL_METER_RATIO; +import static io.openems.edge.goodwe.gridmeter.GoodWeGridMeter.ChannelId.METER_CON_CORRECTLY_L1; +import static io.openems.edge.goodwe.gridmeter.GoodWeGridMeter.ChannelId.METER_CON_INCORRECTLY_L1; +import static io.openems.edge.goodwe.gridmeter.GoodWeGridMeter.ChannelId.METER_CON_REVERSE_L1; +import static io.openems.edge.goodwe.gridmeter.GoodWeGridMeterCategory.COMMERCIAL_METER; +import static io.openems.edge.goodwe.gridmeter.GoodWeGridMeterCategory.SMART_METER; +import static io.openems.edge.goodwe.gridmeter.GoodWeGridMeterImpl.calculateRatio; +import static io.openems.edge.goodwe.gridmeter.GoodWeGridMeterImpl.getPhaseConnectionValue; import static org.junit.Assert.assertEquals; import org.junit.Test; -import io.openems.common.types.ChannelAddress; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; @@ -13,30 +20,17 @@ public class GoodWeGridMeterImplTest { - private static final String MODBUS_ID = "modbus0"; - - private static final String METER_ID = "meter0"; - - private static final ChannelAddress METER_CON_CORRECTLY_L1 = new ChannelAddress(METER_ID, - GoodWeGridMeter.ChannelId.METER_CON_CORRECTLY_L1.id()); - private static final ChannelAddress METER_CON_INCORRECTLY_L1 = new ChannelAddress(METER_ID, - GoodWeGridMeter.ChannelId.METER_CON_INCORRECTLY_L1.id()); - private static final ChannelAddress METER_CON_REVERSE_L1 = new ChannelAddress(METER_ID, - GoodWeGridMeter.ChannelId.METER_CON_REVERSE_L1.id()); - private static final ChannelAddress EXTERNAL_METER_RATIO = new ChannelAddress(METER_ID, - GoodWeGridMeter.ChannelId.EXTERNAL_METER_RATIO.id()); - @Test public void test() throws Exception { final var sut = new GoodWeGridMeterImpl(); new ComponentTest(sut) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setModbusId(MODBUS_ID) // - .setGoodWeMeterCategory(GoodWeGridMeterCategory.SMART_METER) // + .setId("meter0") // + .setModbusId("modbus0") // + .setGoodWeMeterCategory(SMART_METER) // .setExternalMeterRatioValueA(0) // .setExternalMeterRatioValueB(0) // .build()) // @@ -65,31 +59,31 @@ public void test() throws Exception { @Test public void testMeterConnectStateConverter() throws Exception { - var l1Result = GoodWeGridMeterImpl.getPhaseConnectionValue(Phase.L1, 0x0124); - var l2Result = GoodWeGridMeterImpl.getPhaseConnectionValue(Phase.L2, 0x0124); - var l3Result = GoodWeGridMeterImpl.getPhaseConnectionValue(Phase.L3, 0x0124); + var l1Result = getPhaseConnectionValue(Phase.L1, 0x0124); + var l2Result = getPhaseConnectionValue(Phase.L2, 0x0124); + var l3Result = getPhaseConnectionValue(Phase.L3, 0x0124); assertEquals(4, (int) l1Result); assertEquals(2, (int) l2Result); assertEquals(1, (int) l3Result); - l1Result = GoodWeGridMeterImpl.getPhaseConnectionValue(Phase.L1, 0x0524); - l2Result = GoodWeGridMeterImpl.getPhaseConnectionValue(Phase.L2, 0x0462); - l3Result = GoodWeGridMeterImpl.getPhaseConnectionValue(Phase.L3, 0x1647); + l1Result = getPhaseConnectionValue(Phase.L1, 0x0524); + l2Result = getPhaseConnectionValue(Phase.L2, 0x0462); + l3Result = getPhaseConnectionValue(Phase.L3, 0x1647); assertEquals(4, (int) l1Result); assertEquals(6, (int) l2Result); assertEquals(6, (int) l3Result); - var l1NoResult = GoodWeGridMeterImpl.getPhaseConnectionValue(Phase.L1, 0x000); - var l2NoResult = GoodWeGridMeterImpl.getPhaseConnectionValue(Phase.L2, 0x000); - var l3NoResult = GoodWeGridMeterImpl.getPhaseConnectionValue(Phase.L3, 0x000); + var l1NoResult = getPhaseConnectionValue(Phase.L1, 0x000); + var l2NoResult = getPhaseConnectionValue(Phase.L2, 0x000); + var l3NoResult = getPhaseConnectionValue(Phase.L3, 0x000); assertEquals(0, (int) l1NoResult); assertEquals(0, (int) l2NoResult); assertEquals(0, (int) l3NoResult); - var noResult = GoodWeGridMeterImpl.getPhaseConnectionValue(Phase.L3, 0x000); + var noResult = getPhaseConnectionValue(Phase.L3, 0x000); assert noResult == 0x000; } @@ -98,11 +92,11 @@ public void testMeterConnectStateConverter() throws Exception { public void testExternalMeterRatio() throws Exception { new ComponentTest(new GoodWeGridMeterImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setModbusId(MODBUS_ID) // - .setGoodWeMeterCategory(GoodWeGridMeterCategory.COMMERCIAL_METER) // + .setId("meter0") // + .setModbusId("modbus0") // + .setGoodWeMeterCategory(COMMERCIAL_METER) // .setExternalMeterRatioValueA(3000) // .setExternalMeterRatioValueB(5) // .build()) // @@ -111,11 +105,11 @@ public void testExternalMeterRatio() throws Exception { new ComponentTest(new GoodWeGridMeterImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setModbusId(MODBUS_ID) // - .setGoodWeMeterCategory(GoodWeGridMeterCategory.COMMERCIAL_METER) // + .setId("meter0") // + .setModbusId("modbus0") // + .setGoodWeMeterCategory(COMMERCIAL_METER) // .setExternalMeterRatioValueA(500) // .setExternalMeterRatioValueB(5) // .build()) // @@ -124,11 +118,11 @@ public void testExternalMeterRatio() throws Exception { new ComponentTest(new GoodWeGridMeterImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setModbusId(MODBUS_ID) // - .setGoodWeMeterCategory(GoodWeGridMeterCategory.SMART_METER) // + .setId("meter0") // + .setModbusId("modbus0") // + .setGoodWeMeterCategory(SMART_METER) // .setExternalMeterRatioValueA(3000) // .setExternalMeterRatioValueB(5) // .build()) // @@ -138,12 +132,11 @@ public void testExternalMeterRatio() throws Exception { @Test public void testCalculateRatio() { - - assertEquals(600, (int) GoodWeGridMeterImpl.calculateRatio(3000, 5)); - assertEquals(100, (int) GoodWeGridMeterImpl.calculateRatio(500, 5)); - assertEquals(null, GoodWeGridMeterImpl.calculateRatio(-5, 5)); - assertEquals(null, GoodWeGridMeterImpl.calculateRatio(3000, 0)); - assertEquals(null, GoodWeGridMeterImpl.calculateRatio(500, -5)); + assertEquals(600, calculateRatio(3000, 5).intValue()); + assertEquals(100, calculateRatio(500, 5).intValue()); + assertEquals(null, calculateRatio(-5, 5)); + assertEquals(null, calculateRatio(3000, 0)); + assertEquals(null, calculateRatio(500, -5)); } } diff --git a/io.openems.edge.io.api/src/io/openems/edge/io/test/DummyCustomInputOutput.java b/io.openems.edge.io.api/src/io/openems/edge/io/test/DummyCustomInputOutput.java new file mode 100644 index 00000000000..694f61e0348 --- /dev/null +++ b/io.openems.edge.io.api/src/io/openems/edge/io/test/DummyCustomInputOutput.java @@ -0,0 +1,57 @@ +package io.openems.edge.io.test; + +import io.openems.common.channel.AccessMode; +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.BooleanReadChannel; +import io.openems.edge.common.channel.BooleanWriteChannel; +import io.openems.edge.common.channel.ChannelId.ChannelIdImpl; +import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.test.AbstractDummyOpenemsComponent; +import io.openems.edge.io.api.DigitalInput; +import io.openems.edge.io.api.DigitalOutput; + +/** + * Provides a simple, simulated Digital Input/Output component that can be used + * together with the OpenEMS Component test framework. + */ +public class DummyCustomInputOutput extends AbstractDummyOpenemsComponent + implements DigitalInput, DigitalOutput { + + private final BooleanWriteChannel[] ioChannels; + + public DummyCustomInputOutput(String id) { + this(id, "INPUT_OUTPUT", 0, 10); + } + + public DummyCustomInputOutput(String id, String prefix, int start, int numberOfIOs) { + super(id, // + OpenemsComponent.ChannelId.values(), // + DigitalInput.ChannelId.values(), // + DigitalOutput.ChannelId.values() // + ); + + this.ioChannels = new BooleanWriteChannel[numberOfIOs]; + for (int i = 0; i < numberOfIOs; i++) { + this.ioChannels[i] = (BooleanWriteChannel) this + .addChannel(new ChannelIdImpl(prefix + "_" + (i + start), Doc.of(OpenemsType.BOOLEAN).// + accessMode(AccessMode.READ_WRITE))); + } + } + + @Override + protected DummyCustomInputOutput self() { + return this; + } + + @Override + public BooleanWriteChannel[] digitalOutputChannels() { + return this.ioChannels; + } + + @Override + public BooleanReadChannel[] digitalInputChannels() { + return this.ioChannels; + } + +} diff --git a/io.openems.edge.io.api/src/io/openems/edge/io/test/DummyInputOutput.java b/io.openems.edge.io.api/src/io/openems/edge/io/test/DummyInputOutput.java index f9114bef534..92e6b4a26c1 100644 --- a/io.openems.edge.io.api/src/io/openems/edge/io/test/DummyInputOutput.java +++ b/io.openems.edge.io.api/src/io/openems/edge/io/test/DummyInputOutput.java @@ -1,10 +1,11 @@ package io.openems.edge.io.test; +import java.util.stream.Stream; + import io.openems.common.channel.AccessMode; import io.openems.common.types.OpenemsType; import io.openems.edge.common.channel.BooleanReadChannel; import io.openems.edge.common.channel.BooleanWriteChannel; -import io.openems.edge.common.channel.ChannelId.ChannelIdImpl; import io.openems.edge.common.channel.Doc; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.test.AbstractDummyOpenemsComponent; @@ -18,25 +19,53 @@ public class DummyInputOutput extends AbstractDummyOpenemsComponent implements DigitalInput, DigitalOutput { - private final BooleanWriteChannel[] ioChannels; + public enum ChannelId implements io.openems.edge.common.channel.ChannelId { + INPUT_OUTPUT0(Doc.of(OpenemsType.BOOLEAN) // + .accessMode(AccessMode.READ_WRITE)), // + INPUT_OUTPUT1(Doc.of(OpenemsType.BOOLEAN) // + .accessMode(AccessMode.READ_WRITE)), // + INPUT_OUTPUT2(Doc.of(OpenemsType.BOOLEAN) // + .accessMode(AccessMode.READ_WRITE)), // + INPUT_OUTPUT3(Doc.of(OpenemsType.BOOLEAN) // + .accessMode(AccessMode.READ_WRITE)), // + INPUT_OUTPUT4(Doc.of(OpenemsType.BOOLEAN) // + .accessMode(AccessMode.READ_WRITE)), // + INPUT_OUTPUT5(Doc.of(OpenemsType.BOOLEAN) // + .accessMode(AccessMode.READ_WRITE)), // + INPUT_OUTPUT6(Doc.of(OpenemsType.BOOLEAN) // + .accessMode(AccessMode.READ_WRITE)), // + INPUT_OUTPUT7(Doc.of(OpenemsType.BOOLEAN) // + .accessMode(AccessMode.READ_WRITE)), // + INPUT_OUTPUT8(Doc.of(OpenemsType.BOOLEAN) // + .accessMode(AccessMode.READ_WRITE)), // + INPUT_OUTPUT9(Doc.of(OpenemsType.BOOLEAN) // + .accessMode(AccessMode.READ_WRITE)); - public DummyInputOutput(String id) { - this(id, "INPUT_OUTPUT", 0, 10); + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } } - public DummyInputOutput(String id, String prefix, int start, int numberOfIOs) { + private final BooleanWriteChannel[] digitalOutputChannels; + + public DummyInputOutput(String id) { super(id, // OpenemsComponent.ChannelId.values(), // DigitalInput.ChannelId.values(), // - DigitalOutput.ChannelId.values() // + DigitalOutput.ChannelId.values(), // + ChannelId.values() // ); - - this.ioChannels = new BooleanWriteChannel[numberOfIOs]; - for (int i = 0; i < numberOfIOs; i++) { - this.ioChannels[i] = (BooleanWriteChannel) this - .addChannel(new ChannelIdImpl(prefix + "_" + (i + start), Doc.of(OpenemsType.BOOLEAN).// - accessMode(AccessMode.READ_WRITE))); - } + this.digitalOutputChannels = Stream.of(ChannelId.values()) // + .filter(channelId -> channelId.doc().getAccessMode() == AccessMode.READ_WRITE) // + .map(this::channel) // + .toArray(BooleanWriteChannel[]::new); } @Override @@ -46,12 +75,12 @@ protected DummyInputOutput self() { @Override public BooleanWriteChannel[] digitalOutputChannels() { - return this.ioChannels; + return this.digitalOutputChannels; } @Override public BooleanReadChannel[] digitalInputChannels() { - return this.ioChannels; + return this.digitalOutputChannels; } } diff --git a/io.openems.edge.io.filipowski/test/io/openems/edge/io/filipowski/analog/mr/IoFilipowskiMrAo1ImplTest.java b/io.openems.edge.io.filipowski/test/io/openems/edge/io/filipowski/analog/mr/IoFilipowskiMrAo1ImplTest.java index 11ef8cd64dc..dabd16527a6 100644 --- a/io.openems.edge.io.filipowski/test/io/openems/edge/io/filipowski/analog/mr/IoFilipowskiMrAo1ImplTest.java +++ b/io.openems.edge.io.filipowski/test/io/openems/edge/io/filipowski/analog/mr/IoFilipowskiMrAo1ImplTest.java @@ -9,17 +9,14 @@ public class IoFilipowskiMrAo1ImplTest { - private static final String COMPONENT_ID = "component0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new IoFilipowskiMrAo1Impl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // - .setModbusId(MODBUS_ID) // + .setId("component0") // + .setModbusId("modbus0") // .setRelayContact(AnalogOutput.OUTPUT_1) // .build()) .next(new TestCase()); diff --git a/io.openems.edge.io.gpio/test/io/openems/edge/io/gpio/ModberryCM4Test.java b/io.openems.edge.io.gpio/test/io/openems/edge/io/gpio/ModberryCM4Test.java index 113c39f7c6a..084079c95f0 100644 --- a/io.openems.edge.io.gpio/test/io/openems/edge/io/gpio/ModberryCM4Test.java +++ b/io.openems.edge.io.gpio/test/io/openems/edge/io/gpio/ModberryCM4Test.java @@ -1,5 +1,6 @@ package io.openems.edge.io.gpio; +import static io.openems.edge.io.gpio.hardware.HardwareType.MODBERRY_X500_M40804_W; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -27,14 +28,11 @@ import io.openems.edge.io.gpio.api.AbstractGpioChannel; import io.openems.edge.io.gpio.api.ReadChannelId; import io.openems.edge.io.gpio.api.WriteChannelId; -import io.openems.edge.io.gpio.hardware.HardwareType; public class ModberryCM4Test { private File root; - private static final String ID = "io0"; - private static final List CHANNEL_IDS = List.of(// new ReadChannelId(18, "DigitalInput1"), // new ReadChannelId(19, "DigitalInput2"), // @@ -93,11 +91,11 @@ private void setGpioFile(File root, int gpioNumber, int value) throws IOExceptio @Test public void testChannelIdsAreCorrect() throws Exception { var config = MyConfig.create() // - .setId(ID) // - .setAlias(ID) // + .setId("io0") // + .setAlias("io0") // .setEnabled(true) // .setGpioPath(this.folder.getRoot().getAbsolutePath()) // - .setHardwareType(HardwareType.MODBERRY_X500_M40804_W) // + .setHardwareType(MODBERRY_X500_M40804_W) // .build(); IoGpio modberryComponent = new IoGpioImpl(); new ComponentTest(modberryComponent).activate(config); @@ -107,11 +105,11 @@ public void testChannelIdsAreCorrect() throws Exception { @Test public void testComponentLoadsSucesfully() throws Exception { var config = MyConfig.create() // - .setId(ID) // - .setAlias(ID) // + .setId("io0") // + .setAlias("io0") // .setEnabled(true) // .setGpioPath(this.folder.getRoot().getAbsolutePath()) // - .setHardwareType(HardwareType.MODBERRY_X500_M40804_W) // + .setHardwareType(MODBERRY_X500_M40804_W) // .build(); new ComponentTest(new IoGpioImpl()) // .activate(config); @@ -120,19 +118,19 @@ public void testComponentLoadsSucesfully() throws Exception { @Test public void testInputValuesAreDefault() throws Exception { var config = MyConfig.create() // - .setId(ID) // - .setAlias(ID) // + .setId("io0") // + .setAlias("io0") // .setEnabled(true) // .setGpioPath(this.folder.getRoot().getAbsolutePath()) // - .setHardwareType(HardwareType.MODBERRY_X500_M40804_W) // + .setHardwareType(MODBERRY_X500_M40804_W) // .build(); new ComponentTest(new IoGpioImpl()) // .activate(config) // .next(new TestCase("Default input values are false") // - .output(new ChannelAddress(ID, "DigitalInput1"), false) // - .output(new ChannelAddress(ID, "DigitalInput2"), false) // - .output(new ChannelAddress(ID, "DigitalInput3"), false) // - .output(new ChannelAddress(ID, "DigitalInput4"), false) // + .output(new ChannelAddress("io0", "DigitalInput1"), false) // + .output(new ChannelAddress("io0", "DigitalInput2"), false) // + .output(new ChannelAddress("io0", "DigitalInput3"), false) // + .output(new ChannelAddress("io0", "DigitalInput4"), false) // ); } @@ -143,19 +141,19 @@ public void testChangeOutputWrittenToFs() throws Exception { assertEquals(this.readGpioFile(this.root, 24), "0"); assertEquals(this.readGpioFile(this.root, 25), "0"); var config = MyConfig.create() // - .setId(ID) // - .setAlias(ID) // + .setId("io0") // + .setAlias("io0") // .setEnabled(true) // .setGpioPath(this.folder.getRoot().getAbsolutePath()) // - .setHardwareType(HardwareType.MODBERRY_X500_M40804_W) // + .setHardwareType(MODBERRY_X500_M40804_W) // .build(); new ComponentTest(new IoGpioImpl()) // .activate(config) // .next(new TestCase("Write values are written to fs.") // - .input(new ChannelAddress(ID, "DigitalOutput1"), true) // - .input(new ChannelAddress(ID, "DigitalOutput2"), true) // - .input(new ChannelAddress(ID, "DigitalOutput3"), true) // - .input(new ChannelAddress(ID, "DigitalOutput4"), true) // + .input(new ChannelAddress("io0", "DigitalOutput1"), true) // + .input(new ChannelAddress("io0", "DigitalOutput2"), true) // + .input(new ChannelAddress("io0", "DigitalOutput3"), true) // + .input(new ChannelAddress("io0", "DigitalOutput4"), true) // ); assertEquals(this.readGpioFile(this.root, 22), "1"); assertEquals(this.readGpioFile(this.root, 23), "1"); @@ -171,20 +169,20 @@ public void testChangeInputIsDetected() throws Exception { assertEquals(this.readGpioFile(this.root, 21), "0"); var config = MyConfig.create() // - .setId(ID) // - .setAlias(ID) // + .setId("io0") // + .setAlias("io0") // .setEnabled(true) // .setGpioPath(this.folder.getRoot().getAbsolutePath()) // - .setHardwareType(HardwareType.MODBERRY_X500_M40804_W) // + .setHardwareType(MODBERRY_X500_M40804_W) // .build(); new ComponentTest(new IoGpioImpl()) // .activate(config) // .next(new TestCase("Read values are detected by the component.") // - .output(new ChannelAddress(ID, "DigitalInput1"), false) // - .output(new ChannelAddress(ID, "DigitalInput2"), false) // - .output(new ChannelAddress(ID, "DigitalInput3"), false) // - .output(new ChannelAddress(ID, "DigitalInput4"), false) // + .output(new ChannelAddress("io0", "DigitalInput1"), false) // + .output(new ChannelAddress("io0", "DigitalInput2"), false) // + .output(new ChannelAddress("io0", "DigitalInput3"), false) // + .output(new ChannelAddress("io0", "DigitalInput4"), false) // ); this.setGpioFile(this.root, 18, 1); @@ -200,10 +198,10 @@ public void testChangeInputIsDetected() throws Exception { new ComponentTest(new IoGpioImpl()) // .activate(config) // .next(new TestCase("Read values are detected by the component.") // - .output(new ChannelAddress(ID, "DigitalInput1"), true) // - .output(new ChannelAddress(ID, "DigitalInput2"), true) // - .output(new ChannelAddress(ID, "DigitalInput3"), true) // - .output(new ChannelAddress(ID, "DigitalInput4"), true) // + .output(new ChannelAddress("io0", "DigitalInput1"), true) // + .output(new ChannelAddress("io0", "DigitalInput2"), true) // + .output(new ChannelAddress("io0", "DigitalInput3"), true) // + .output(new ChannelAddress("io0", "DigitalInput4"), true) // ); } @@ -211,18 +209,19 @@ public void testChangeInputIsDetected() throws Exception { public void testJavaApi() throws Exception { this.setGpioFile(this.root, 22, 0); var config = MyConfig.create() // - .setId(ID) // - .setAlias(ID) // + .setId("io0") // + .setAlias("io0") // .setEnabled(true) // .setGpioPath(this.folder.getRoot().getAbsolutePath()) // - .setHardwareType(HardwareType.MODBERRY_X500_M40804_W) // + .setHardwareType(MODBERRY_X500_M40804_W) // .build(); var componentManager = new DummyComponentManager(); - var componentTest = new ComponentTest(new IoGpioImpl()).activate(config); + var componentTest = new ComponentTest(new IoGpioImpl()) // + .activate(config); componentManager.addComponent(componentTest.getSut()); // Get get component channel value as java reference - WriteChannel writeChannel = componentManager.getChannel(new ChannelAddress(ID, "DigitalOutput1")); + WriteChannel writeChannel = componentManager.getChannel(new ChannelAddress("io0", "DigitalOutput1")); assertFalse(writeChannel.value().isDefined()); writeChannel.setNextValue(true); } @@ -231,11 +230,11 @@ public void testJavaApi() throws Exception { public void testInterfaceDigitalOutputChannels() throws Exception { this.setGpioFile(this.root, 22, 0); var config = MyConfig.create() // - .setId(ID) // - .setAlias(ID) // + .setId("io0") // + .setAlias("io0") // .setEnabled(true) // .setGpioPath(this.folder.getRoot().getAbsolutePath()) // - .setHardwareType(HardwareType.MODBERRY_X500_M40804_W) // + .setHardwareType(MODBERRY_X500_M40804_W) // .build(); var componentManager = new DummyComponentManager(); var componentTest = new ComponentTest(new IoGpioImpl()) // @@ -249,11 +248,11 @@ public void testInterfaceDigitalOutputChannels() throws Exception { public void testInterfaceDigitalInputChannels() throws Exception { this.setGpioFile(this.root, 22, 0); var config = MyConfig.create() // - .setId(ID) // - .setAlias(ID) // + .setId("io0") // + .setAlias("io0") // .setEnabled(true) // .setGpioPath(this.folder.getRoot().getAbsolutePath()) // - .setHardwareType(HardwareType.MODBERRY_X500_M40804_W) // + .setHardwareType(MODBERRY_X500_M40804_W) // .build(); var componentManager = new DummyComponentManager(); var componentTest = new ComponentTest(new IoGpioImpl()) // diff --git a/io.openems.edge.io.kmtronic/test/io/openems/edge/io/kmtronic/eight/IoKmtronicRelay8PortImplTest.java b/io.openems.edge.io.kmtronic/test/io/openems/edge/io/kmtronic/eight/IoKmtronicRelay8PortImplTest.java index 67b002d2fae..e27c0302a00 100644 --- a/io.openems.edge.io.kmtronic/test/io/openems/edge/io/kmtronic/eight/IoKmtronicRelay8PortImplTest.java +++ b/io.openems.edge.io.kmtronic/test/io/openems/edge/io/kmtronic/eight/IoKmtronicRelay8PortImplTest.java @@ -8,17 +8,14 @@ public class IoKmtronicRelay8PortImplTest { - private static final String IO_ID = "io0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new IoKmtronicRelay8PortImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(IO_ID) // - .setModbusId(MODBUS_ID) // + .setId("io0") // + .setModbusId("modbus0") // .build()) // ; } diff --git a/io.openems.edge.io.kmtronic/test/io/openems/edge/io/kmtronic/four/IoKmtronicRelay4PortImplTest.java b/io.openems.edge.io.kmtronic/test/io/openems/edge/io/kmtronic/four/IoKmtronicRelay4PortImplTest.java index e7ccd9abf4c..36b4ab28c6f 100644 --- a/io.openems.edge.io.kmtronic/test/io/openems/edge/io/kmtronic/four/IoKmtronicRelay4PortImplTest.java +++ b/io.openems.edge.io.kmtronic/test/io/openems/edge/io/kmtronic/four/IoKmtronicRelay4PortImplTest.java @@ -8,17 +8,14 @@ public class IoKmtronicRelay4PortImplTest { - private static final String IO_ID = "io0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new IoKmtronicRelay4PortImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(IO_ID) // - .setModbusId(MODBUS_ID) // + .setId("io0") // + .setModbusId("modbus0") // .build()) // ; } diff --git a/io.openems.edge.io.offgridswitch/test/io/openems/edge/iooffgridswitch/IoOffGridSwitchImplTest.java b/io.openems.edge.io.offgridswitch/test/io/openems/edge/iooffgridswitch/IoOffGridSwitchImplTest.java index 9d182edd712..0f2944b67f6 100644 --- a/io.openems.edge.io.offgridswitch/test/io/openems/edge/iooffgridswitch/IoOffGridSwitchImplTest.java +++ b/io.openems.edge.io.offgridswitch/test/io/openems/edge/iooffgridswitch/IoOffGridSwitchImplTest.java @@ -2,7 +2,6 @@ import org.junit.Test; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyComponentManager; @@ -10,29 +9,18 @@ public class IoOffGridSwitchImplTest { - private static final String COMPONENT_ID = "ioOffGridSwitch0"; - - private static final String IO_ID = "io0"; - private static final ChannelAddress INPUT_MAIN_CONTACTOR = new ChannelAddress(IO_ID, "InputOutput0"); - private static final ChannelAddress INPUT_GRID_STATUS = new ChannelAddress(IO_ID, "InputOutput1"); - private static final ChannelAddress INPUT_GROUNDING_CONTACTOR = new ChannelAddress(IO_ID, "InputOutput2"); - private static final ChannelAddress OUTPUT_MAIN_CONTACTOR = new ChannelAddress(IO_ID, "InputOutput3"); - private static final ChannelAddress OUTPUT_GROUNDING_CONTACTOR = new ChannelAddress(IO_ID, "InputOutput4"); - @Test public void test() throws Exception { - var io0 = new DummyInputOutput(IO_ID); - new ComponentTest(new IoOffGridSwitchImpl()) // .addReference("componentManager", new DummyComponentManager()) // - .addComponent(io0) // + .addComponent(new DummyInputOutput("io0")) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // - .setInputMainContactor(INPUT_MAIN_CONTACTOR.toString()) // - .setInputGridStatus(INPUT_GRID_STATUS.toString()) // - .setInputGroundingContactor(INPUT_GROUNDING_CONTACTOR.toString()) // - .setOutputMainContactor(OUTPUT_MAIN_CONTACTOR.toString()) // - .setOutputGroundingContactor(OUTPUT_GROUNDING_CONTACTOR.toString()) // + .setId("ioOffGridSwitch0") // + .setInputMainContactor("io0/InputOutput0") // + .setInputGridStatus("io0/InputOutput1") // + .setInputGroundingContactor("io0/InputOutput2") // + .setOutputMainContactor("io0/InputOutput3") // + .setOutputGroundingContactor("io0/InputOutput4") // .build()) .next(new TestCase()); } diff --git a/io.openems.edge.io.revpi/test/io/openems/edge/io/revpi/IoRevolutionPiDigitalIoImplTest.java b/io.openems.edge.io.revpi/test/io/openems/edge/io/revpi/IoRevolutionPiDigitalIoImplTest.java index db1698ef9a2..7f7285b5b65 100644 --- a/io.openems.edge.io.revpi/test/io/openems/edge/io/revpi/IoRevolutionPiDigitalIoImplTest.java +++ b/io.openems.edge.io.revpi/test/io/openems/edge/io/revpi/IoRevolutionPiDigitalIoImplTest.java @@ -6,8 +6,6 @@ public class IoRevolutionPiDigitalIoImplTest { - // private static final String COMPONENT_ID = "io0"; - @Test public void test() throws Exception { new ComponentTest(new IoRevolutionPiDigitalIoImpl()) // diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/IoShellyPro3Em.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/IoShellyPro3Em.java index c5899305afe..e545e5bec63 100644 --- a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/IoShellyPro3Em.java +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/IoShellyPro3Em.java @@ -3,8 +3,8 @@ import io.openems.common.channel.Level; import io.openems.edge.common.channel.Doc; import io.openems.edge.common.channel.StateChannel; -import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.channel.value.Value; +import io.openems.edge.common.component.OpenemsComponent; public interface IoShellyPro3Em extends OpenemsComponent { diff --git a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shelly25/IoShelly25ImplTest.java b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shelly25/IoShelly25ImplTest.java index 06b3f7975cf..679d091a7de 100644 --- a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shelly25/IoShelly25ImplTest.java +++ b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shelly25/IoShelly25ImplTest.java @@ -1,20 +1,19 @@ package io.openems.edge.io.shelly.shelly25; +import static io.openems.edge.bridge.http.dummy.DummyBridgeHttpFactory.ofDummyBridge; + import org.junit.Test; -import io.openems.edge.bridge.http.dummy.DummyBridgeHttpFactory; import io.openems.edge.common.test.ComponentTest; public class IoShelly25ImplTest { - private static final String COMPONENT_ID = "io0"; - @Test public void test() throws Exception { new ComponentTest(new IoShelly25Impl()) // - .addReference("httpBridgeFactory", DummyBridgeHttpFactory.ofDummyBridge()) // + .addReference("httpBridgeFactory", ofDummyBridge()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // + .setId("io0") // .setIp("127.0.0.1") // .build()) // ; diff --git a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shelly3em/IoShelly3EmImplTest.java b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shelly3em/IoShelly3EmImplTest.java index 1c06c65f443..040323c987f 100644 --- a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shelly3em/IoShelly3EmImplTest.java +++ b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shelly3em/IoShelly3EmImplTest.java @@ -1,23 +1,22 @@ package io.openems.edge.io.shelly.shelly3em; +import static io.openems.edge.bridge.http.dummy.DummyBridgeHttpFactory.ofDummyBridge; +import static io.openems.edge.meter.api.MeterType.CONSUMPTION_METERED; + import org.junit.Test; -import io.openems.edge.bridge.http.dummy.DummyBridgeHttpFactory; import io.openems.edge.common.test.ComponentTest; -import io.openems.edge.meter.api.MeterType; public class IoShelly3EmImplTest { - private static final String COMPONENT_ID = "io0"; - @Test public void test() throws Exception { new ComponentTest(new IoShelly3EmImpl()) // - .addReference("httpBridgeFactory", DummyBridgeHttpFactory.ofDummyBridge()) // + .addReference("httpBridgeFactory", ofDummyBridge()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // + .setId("io0") // .setIp("127.0.0.1") // - .setType(MeterType.CONSUMPTION_METERED) // + .setType(CONSUMPTION_METERED) // .build()) // ; } diff --git a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplug/IoShellyPlugImplTest.java b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplug/IoShellyPlugImplTest.java index efef443c6b0..efc52c6e641 100644 --- a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplug/IoShellyPlugImplTest.java +++ b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplug/IoShellyPlugImplTest.java @@ -1,25 +1,24 @@ package io.openems.edge.io.shelly.shellyplug; +import static io.openems.edge.bridge.http.dummy.DummyBridgeHttpFactory.ofDummyBridge; +import static io.openems.edge.meter.api.MeterType.PRODUCTION; + import org.junit.Test; -import io.openems.edge.bridge.http.dummy.DummyBridgeHttpFactory; import io.openems.edge.common.test.ComponentTest; -import io.openems.edge.meter.api.MeterType; import io.openems.edge.meter.api.SinglePhase; public class IoShellyPlugImplTest { - private static final String COMPONENT_ID = "io0"; - @Test public void test() throws Exception { new ComponentTest(new IoShellyPlugImpl()) // - .addReference("httpBridgeFactory", DummyBridgeHttpFactory.ofDummyBridge()) // + .addReference("httpBridgeFactory", ofDummyBridge()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // + .setId("io0") // .setPhase(SinglePhase.L1) // .setIp("127.0.0.1") // - .setType(MeterType.PRODUCTION) // + .setType(PRODUCTION) // .build()) // ; } diff --git a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplus1pm/IoShellyPlus1PmImplTest.java b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplus1pm/IoShellyPlus1PmImplTest.java index e3443f8d6b1..456e5b87ad3 100644 --- a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplus1pm/IoShellyPlus1PmImplTest.java +++ b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplus1pm/IoShellyPlus1PmImplTest.java @@ -1,5 +1,12 @@ package io.openems.edge.io.shelly.shellyplus1pm; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.ACTIVE_CONSUMPTION_ENERGY; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.ACTIVE_POWER; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.ACTIVE_POWER_L1; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.ACTIVE_POWER_L2; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.CURRENT; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.VOLTAGE; import static io.openems.edge.meter.api.MeterType.CONSUMPTION_METERED; import static io.openems.edge.meter.api.SinglePhase.L1; import static org.junit.Assert.assertEquals; @@ -7,7 +14,6 @@ import org.junit.Test; -import io.openems.common.types.ChannelAddress; import io.openems.edge.bridge.http.api.HttpError; import io.openems.edge.bridge.http.api.HttpResponse; import io.openems.edge.bridge.http.dummy.DummyBridgeHttpBundle; @@ -17,17 +23,6 @@ public class IoShellyPlus1PmImplTest { - private static final String COMPONENT_ID = "io0"; - - private static final ChannelAddress ACTIVE_POWER = new ChannelAddress(COMPONENT_ID, "ActivePower"); - private static final ChannelAddress ACTIVE_POWER_L1 = new ChannelAddress(COMPONENT_ID, "ActivePowerL1"); - private static final ChannelAddress ACTIVE_POWER_L2 = new ChannelAddress(COMPONENT_ID, "ActivePowerL2"); - private static final ChannelAddress CURRENT = new ChannelAddress(COMPONENT_ID, "Current"); - private static final ChannelAddress VOLTAGE = new ChannelAddress(COMPONENT_ID, "Voltage"); - private static final ChannelAddress PRODUCTION_ENERGY = new ChannelAddress(COMPONENT_ID, "ActiveProductionEnergy"); - private static final ChannelAddress CONSUMPTION_ENERGY = new ChannelAddress(COMPONENT_ID, - "ActiveConsumptionEnergy"); - @Test public void test() throws Exception { final var httpTestBundle = new DummyBridgeHttpBundle(); @@ -37,7 +32,7 @@ public void test() throws Exception { .addReference("httpBridgeFactory", httpTestBundle.factory()) // .addReference("timedata", new DummyTimedata("timedata0")) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // + .setId("io0") // .setIp("127.0.0.1") // .setType(CONSUMPTION_METERED) // .setPhase(L1) // @@ -122,7 +117,6 @@ public void test() throws Exception { .next(new TestCase("Invalid read response") // .onBeforeControllersCallbacks(() -> assertEquals("Off|123 W", sut.debugLog())) - .onBeforeControllersCallbacks(() -> { httpTestBundle.forceNextFailedResult(HttpError.ResponseError.notFound()); httpTestBundle.triggerNextCycle(); @@ -133,24 +127,19 @@ public void test() throws Exception { .output(CURRENT, null) // .output(VOLTAGE, null) // - .output(PRODUCTION_ENERGY, 0L) // - .output(CONSUMPTION_ENERGY, 0L)) // + .output(ACTIVE_PRODUCTION_ENERGY, 0L) // + .output(ACTIVE_CONSUMPTION_ENERGY, 0L)) // .next(new TestCase("Write") // .onBeforeControllersCallbacks(() -> assertEquals("Unknown|UNDEFINED", sut.debugLog())) - .onBeforeControllersCallbacks(() -> { - sut.setRelay(true); - }) // + .onBeforeControllersCallbacks(() -> sut.setRelay(true)) // .also(testCase -> { final var relayTurnedOn = httpTestBundle.expect("http://127.0.0.1/relay/0?turn=on") .toBeCalled(); - testCase.onBeforeControllersCallbacks(() -> { - httpTestBundle.triggerNextCycle(); - }); - testCase.onAfterWriteCallbacks(() -> { - assertTrue("Failed to turn on relay", relayTurnedOn.get()); - }); + testCase.onBeforeControllersCallbacks(() -> httpTestBundle.triggerNextCycle()); + testCase.onAfterWriteCallbacks( + () -> assertTrue("Failed to turn on relay", relayTurnedOn.get())); })) // .deactivate(); diff --git a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlugImplTest.java b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlugImplTest.java index c91c4c52720..3b4414e7be2 100644 --- a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlugImplTest.java +++ b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlugImplTest.java @@ -1,46 +1,40 @@ package io.openems.edge.io.shelly.shellyplusplugs; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.ACTIVE_CONSUMPTION_ENERGY; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.ACTIVE_POWER; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.ACTIVE_POWER_L1; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.ACTIVE_POWER_L2; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.CURRENT; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.VOLTAGE; +import static io.openems.edge.meter.api.MeterType.PRODUCTION; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import org.junit.Test; -import io.openems.common.types.ChannelAddress; import io.openems.edge.bridge.http.api.HttpError; import io.openems.edge.bridge.http.api.HttpResponse; import io.openems.edge.bridge.http.dummy.DummyBridgeHttpBundle; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; -import io.openems.edge.meter.api.MeterType; import io.openems.edge.meter.api.SinglePhase; import io.openems.edge.timedata.test.DummyTimedata; public class IoShellyPlugImplTest { - private static final String COMPONENT_ID = "io0"; - - private static final ChannelAddress ACTIVE_POWER = new ChannelAddress(COMPONENT_ID, "ActivePower"); - private static final ChannelAddress ACTIVE_POWER_L1 = new ChannelAddress(COMPONENT_ID, "ActivePowerL1"); - private static final ChannelAddress ACTIVE_POWER_L2 = new ChannelAddress(COMPONENT_ID, "ActivePowerL2"); - private static final ChannelAddress CURRENT = new ChannelAddress(COMPONENT_ID, "Current"); - private static final ChannelAddress VOLTAGE = new ChannelAddress(COMPONENT_ID, "Voltage"); - private static final ChannelAddress PRODUCTION_ENERGY = new ChannelAddress(COMPONENT_ID, "ActiveProductionEnergy"); - private static final ChannelAddress CONSUMPTION_ENERGY = new ChannelAddress(COMPONENT_ID, - "ActiveConsumptionEnergy"); - @Test public void test() throws Exception { final var httpTestBundle = new DummyBridgeHttpBundle(); - final var sut = new IoShellyPlusPlugsImpl(); new ComponentTest(sut) // .addReference("httpBridgeFactory", httpTestBundle.factory()) // .addReference("timedata", new DummyTimedata("timedata0")) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // + .setId("io0") // .setPhase(SinglePhase.L1) // .setIp("127.0.0.1") // - .setType(MeterType.PRODUCTION) // + .setType(PRODUCTION) // .build()) // .next(new TestCase("Successful read response") // @@ -81,8 +75,8 @@ public void test() throws Exception { .output(CURRENT, null) // .output(VOLTAGE, null) // - .output(PRODUCTION_ENERGY, 0L) // - .output(CONSUMPTION_ENERGY, 0L)) // + .output(ACTIVE_PRODUCTION_ENERGY, 0L) // + .output(ACTIVE_CONSUMPTION_ENERGY, 0L)) // .next(new TestCase("Write") // .onBeforeControllersCallbacks(() -> assertEquals("Unknown|UNDEFINED", sut.debugLog())) @@ -93,12 +87,9 @@ public void test() throws Exception { final var relayTurnedOn = httpTestBundle.expect("http://127.0.0.1/relay/0?turn=on") .toBeCalled(); - testCase.onBeforeControllersCallbacks(() -> { - httpTestBundle.triggerNextCycle(); - }); - testCase.onAfterWriteCallbacks(() -> { - assertTrue("Failed to turn on relay", relayTurnedOn.get()); - }); + testCase.onBeforeControllersCallbacks(() -> httpTestBundle.triggerNextCycle()); + testCase.onAfterWriteCallbacks( + () -> assertTrue("Failed to turn on relay", relayTurnedOn.get())); })) // .deactivate(); diff --git a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplusplugs/MyConfig.java b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplusplugs/MyConfig.java index 81fe32540f0..c14a9f39c1a 100644 --- a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplusplugs/MyConfig.java +++ b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplusplugs/MyConfig.java @@ -1,7 +1,6 @@ package io.openems.edge.io.shelly.shellyplusplugs; import io.openems.common.test.AbstractComponentConfig; -import io.openems.edge.io.shelly.shellyplusplugs.Config; import io.openems.edge.meter.api.MeterType; import io.openems.edge.meter.api.SinglePhase; diff --git a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3/IoShellyPro3ImplTest.java b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3/IoShellyPro3ImplTest.java index ed4f8d960b6..c7213418efe 100644 --- a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3/IoShellyPro3ImplTest.java +++ b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3/IoShellyPro3ImplTest.java @@ -7,14 +7,12 @@ public class IoShellyPro3ImplTest { - private static final String COMPONENT_ID = "io0"; - @Test public void test() throws Exception { new ComponentTest(new IoShellyPro3Impl()) // .addReference("httpBridgeFactory", DummyBridgeHttpFactory.ofDummyBridge()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // + .setId("io0") // .setIp("127.0.0.1") // .build()) // ; diff --git a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3em/IoShelly3EmImplTest.java b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3em/IoShelly3EmImplTest.java index 29b0136a7a6..f2691bb5e7e 100644 --- a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3em/IoShelly3EmImplTest.java +++ b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3em/IoShelly3EmImplTest.java @@ -8,14 +8,12 @@ public class IoShelly3EmImplTest { - private static final String COMPONENT_ID = "io0"; - @Test public void test() throws Exception { new ComponentTest(new IoShellyPro3EmImpl()) // .addReference("httpBridgeFactory", DummyBridgeHttpFactory.ofDummyBridge()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // + .setId("io0") // .setIp("127.0.0.1") // .setType(MeterType.CONSUMPTION_METERED) // .build()) // diff --git a/io.openems.edge.io.wago/test/io/openems/edge/wago/IoWagoImplTest.java b/io.openems.edge.io.wago/test/io/openems/edge/wago/IoWagoImplTest.java index 012eac53fd3..292deeff3f3 100644 --- a/io.openems.edge.io.wago/test/io/openems/edge/wago/IoWagoImplTest.java +++ b/io.openems.edge.io.wago/test/io/openems/edge/wago/IoWagoImplTest.java @@ -16,9 +16,6 @@ public class IoWagoImplTest { - private static final String IO_ID = "io0"; - private static final String MODBUS_ID = "modbus0"; - /** * This is an example "ea-config.xml" downloaded from a WAGO Fieldbus coupler. */ @@ -56,14 +53,14 @@ public void test() throws Exception { var sut = new IoWagoImpl(); new ComponentTest(sut) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID).withIpAddress("127.0.0.1")) // + .addReference("setModbus", new DummyModbusBridge("modbus0") // + .withIpAddress("127.0.0.1")) // .activate(MyConfig.create() // - .setId(IO_ID) // - .setModbusId(MODBUS_ID) // + .setId("io0") // + .setModbusId("modbus0") // .setUsername("foo") // .setPassword("bar") // - .build()) // - ; + .build()); InputStream dummyXml = new ByteArrayInputStream(EA_CONFIG.getBytes()); var doc = IoWagoImpl.parseXmlToDocument(dummyXml); diff --git a/io.openems.edge.io.weidmueller/test/io/openems/edge/io/weidmueller/IoWeidmuellerUr20ImplTest.java b/io.openems.edge.io.weidmueller/test/io/openems/edge/io/weidmueller/IoWeidmuellerUr20ImplTest.java index 7a8da19e227..eadbf247bb5 100644 --- a/io.openems.edge.io.weidmueller/test/io/openems/edge/io/weidmueller/IoWeidmuellerUr20ImplTest.java +++ b/io.openems.edge.io.weidmueller/test/io/openems/edge/io/weidmueller/IoWeidmuellerUr20ImplTest.java @@ -9,17 +9,14 @@ public class IoWeidmuellerUr20ImplTest { - private static final String COMPONENT_ID = "io0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new IoWeidmuellerUr20Impl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // - .setModbusId(MODBUS_ID) // + .setId("io0") // + .setModbusId("modbus0") // .build()) .next(new TestCase()); } diff --git a/io.openems.edge.kaco.blueplanet.hybrid10/test/io/openems/edge/kaco/blueplanet/hybrid10/core/KacoBlueplanetHybrid10CoreImplTest.java b/io.openems.edge.kaco.blueplanet.hybrid10/test/io/openems/edge/kaco/blueplanet/hybrid10/core/KacoBlueplanetHybrid10CoreImplTest.java index e0d6d9bbb72..bf8f9736926 100644 --- a/io.openems.edge.kaco.blueplanet.hybrid10/test/io/openems/edge/kaco/blueplanet/hybrid10/core/KacoBlueplanetHybrid10CoreImplTest.java +++ b/io.openems.edge.kaco.blueplanet.hybrid10/test/io/openems/edge/kaco/blueplanet/hybrid10/core/KacoBlueplanetHybrid10CoreImplTest.java @@ -6,13 +6,11 @@ public class KacoBlueplanetHybrid10CoreImplTest { - private static final String CORE_ID = "kacoCore0"; - @Test public void test() throws Exception { new ComponentTest(new KacoBlueplanetHybrid10CoreImpl()) // .activate(MyConfig.create() // - .setId(CORE_ID) // + .setId("kacoCore0") // .setIdentkey("") // .setIp("192.168.0.1") // .setSerialnumber("123456") // diff --git a/io.openems.edge.kaco.blueplanet.hybrid10/test/io/openems/edge/kaco/blueplanet/hybrid10/ess/KacoBlueplanetHybrid10EssImplTest.java b/io.openems.edge.kaco.blueplanet.hybrid10/test/io/openems/edge/kaco/blueplanet/hybrid10/ess/KacoBlueplanetHybrid10EssImplTest.java index cb4ec7953a9..f06f0bbafb1 100644 --- a/io.openems.edge.kaco.blueplanet.hybrid10/test/io/openems/edge/kaco/blueplanet/hybrid10/ess/KacoBlueplanetHybrid10EssImplTest.java +++ b/io.openems.edge.kaco.blueplanet.hybrid10/test/io/openems/edge/kaco/blueplanet/hybrid10/ess/KacoBlueplanetHybrid10EssImplTest.java @@ -8,18 +8,14 @@ public class KacoBlueplanetHybrid10EssImplTest { - private static final String ESS_ID = "ess0"; - private static final String CORE_ID = "kacoCore0"; - private static final String TIMEDATA_ID = "timedata0"; - @Test public void test() throws Exception { new ComponentTest(new KacoBlueplanetHybrid10EssImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("timedata", new DummyTimedata(TIMEDATA_ID)) // + .addReference("timedata", new DummyTimedata("timedata0")) // .activate(MyConfig.create() // - .setId(ESS_ID) // - .setCoreId(CORE_ID) // + .setId("ess0") // + .setCoreId("kacoCore0") // .build()) // ; } diff --git a/io.openems.edge.kaco.blueplanet.hybrid10/test/io/openems/edge/kaco/blueplanet/hybrid10/ess/charger/KacoBlueplanetHybrid10ChargerImplTest.java b/io.openems.edge.kaco.blueplanet.hybrid10/test/io/openems/edge/kaco/blueplanet/hybrid10/ess/charger/KacoBlueplanetHybrid10ChargerImplTest.java index 6d9606bb0b6..e5d00f7b9e2 100644 --- a/io.openems.edge.kaco.blueplanet.hybrid10/test/io/openems/edge/kaco/blueplanet/hybrid10/ess/charger/KacoBlueplanetHybrid10ChargerImplTest.java +++ b/io.openems.edge.kaco.blueplanet.hybrid10/test/io/openems/edge/kaco/blueplanet/hybrid10/ess/charger/KacoBlueplanetHybrid10ChargerImplTest.java @@ -7,16 +7,13 @@ public class KacoBlueplanetHybrid10ChargerImplTest { - private static final String CHARGER_ID = "charger0"; - private static final String CORE_ID = "kacoCore0"; - @Test public void test() throws Exception { new ComponentTest(new KacoBlueplanetHybrid10ChargerImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .activate(MyConfig.create() // - .setId(CHARGER_ID) // - .setCoreId(CORE_ID) // + .setId("charger0") // + .setCoreId("kacoCore0") // .build()) // ; } diff --git a/io.openems.edge.kaco.blueplanet.hybrid10/test/io/openems/edge/kaco/blueplanet/hybrid10/pvinverter/KacoBlueplanetHybrid10PvInverterImplTest.java b/io.openems.edge.kaco.blueplanet.hybrid10/test/io/openems/edge/kaco/blueplanet/hybrid10/pvinverter/KacoBlueplanetHybrid10PvInverterImplTest.java index 2a34e01ddaa..a8c9ee17853 100644 --- a/io.openems.edge.kaco.blueplanet.hybrid10/test/io/openems/edge/kaco/blueplanet/hybrid10/pvinverter/KacoBlueplanetHybrid10PvInverterImplTest.java +++ b/io.openems.edge.kaco.blueplanet.hybrid10/test/io/openems/edge/kaco/blueplanet/hybrid10/pvinverter/KacoBlueplanetHybrid10PvInverterImplTest.java @@ -7,16 +7,13 @@ public class KacoBlueplanetHybrid10PvInverterImplTest { - private static final String PV_INVERTER_ID = "pvInverter0"; - private static final String CORE_ID = "kacoCore0"; - @Test public void test() throws Exception { new ComponentTest(new KacoBlueplanetHybrid10PvInverterImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .activate(MyConfig.create() // - .setId(PV_INVERTER_ID) // - .setCoreId(CORE_ID) // + .setId("pvInverter0") // + .setCoreId("kacoCore0") // .build()) // ; } diff --git a/io.openems.edge.kaco.blueplanet.hybrid10/test/io/openems/edge/kaco/blueplanet/hybrid10/vectis/KacoBlueplanetHybrid10GridMeterImplTest.java b/io.openems.edge.kaco.blueplanet.hybrid10/test/io/openems/edge/kaco/blueplanet/hybrid10/vectis/KacoBlueplanetHybrid10GridMeterImplTest.java index c4d71724b33..cc50bb9d0fd 100644 --- a/io.openems.edge.kaco.blueplanet.hybrid10/test/io/openems/edge/kaco/blueplanet/hybrid10/vectis/KacoBlueplanetHybrid10GridMeterImplTest.java +++ b/io.openems.edge.kaco.blueplanet.hybrid10/test/io/openems/edge/kaco/blueplanet/hybrid10/vectis/KacoBlueplanetHybrid10GridMeterImplTest.java @@ -7,16 +7,13 @@ public class KacoBlueplanetHybrid10GridMeterImplTest { - private static final String METER_ID = "meter0"; - private static final String CORE_ID = "kacoCore0"; - @Test public void test() throws Exception { new ComponentTest(new KacoBlueplanetHybrid10GridMeterImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setCoreId(CORE_ID) // + .setId("meter0") // + .setCoreId("kacoCore0") // .build()) // ; } diff --git a/io.openems.edge.kostal.piko/test/io/openems/edge/kostal/piko/charger/KostalPikoChargerImplTest.java b/io.openems.edge.kostal.piko/test/io/openems/edge/kostal/piko/charger/KostalPikoChargerImplTest.java index ed2b7b7d5cc..96cbaf11cdd 100644 --- a/io.openems.edge.kostal.piko/test/io/openems/edge/kostal/piko/charger/KostalPikoChargerImplTest.java +++ b/io.openems.edge.kostal.piko/test/io/openems/edge/kostal/piko/charger/KostalPikoChargerImplTest.java @@ -8,15 +8,13 @@ public class KostalPikoChargerImplTest { - private static final String COMPONENT_ID = "charger0"; - @Test public void test() throws Exception { new ComponentTest(new KostalPikoChargerImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // # .addReference("setCore", new KostalPikoCoreImpl()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // + .setId("charger0") // .setCoreId("core0") // .build()) // ; diff --git a/io.openems.edge.kostal.piko/test/io/openems/edge/kostal/piko/core/impl/KostalPikoCoreImplTest.java b/io.openems.edge.kostal.piko/test/io/openems/edge/kostal/piko/core/impl/KostalPikoCoreImplTest.java index 5dab51e4a65..dff15af4a7e 100644 --- a/io.openems.edge.kostal.piko/test/io/openems/edge/kostal/piko/core/impl/KostalPikoCoreImplTest.java +++ b/io.openems.edge.kostal.piko/test/io/openems/edge/kostal/piko/core/impl/KostalPikoCoreImplTest.java @@ -6,13 +6,11 @@ public class KostalPikoCoreImplTest { - private static final String COMPONENT_ID = "core0"; - @Test public void test() throws Exception { new ComponentTest(new KostalPikoCoreImpl()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // + .setId("core0") // .setIp("127.0.0.1") // .setPort(81) // .setUnitID(0xff) // diff --git a/io.openems.edge.kostal.piko/test/io/openems/edge/kostal/piko/ess/KostalPikoEssImplTest.java b/io.openems.edge.kostal.piko/test/io/openems/edge/kostal/piko/ess/KostalPikoEssImplTest.java index 1c3e78bfc06..aaeaf69fefa 100644 --- a/io.openems.edge.kostal.piko/test/io/openems/edge/kostal/piko/ess/KostalPikoEssImplTest.java +++ b/io.openems.edge.kostal.piko/test/io/openems/edge/kostal/piko/ess/KostalPikoEssImplTest.java @@ -8,15 +8,13 @@ public class KostalPikoEssImplTest { - private static final String COMPONENT_ID = "ess0"; - @Test public void test() throws Exception { new ComponentTest(new KostalPikoEssImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // # .addReference("setCore", new KostalPikoCoreImpl()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // + .setId("ess0") // .setCoreId("core0") // .build()) // ; diff --git a/io.openems.edge.kostal.piko/test/io/openems/edge/kostal/piko/gridmeter/KostalPikoGridMeterImplTest.java b/io.openems.edge.kostal.piko/test/io/openems/edge/kostal/piko/gridmeter/KostalPikoGridMeterImplTest.java index 7895e4c50ed..ee5e9206bcb 100644 --- a/io.openems.edge.kostal.piko/test/io/openems/edge/kostal/piko/gridmeter/KostalPikoGridMeterImplTest.java +++ b/io.openems.edge.kostal.piko/test/io/openems/edge/kostal/piko/gridmeter/KostalPikoGridMeterImplTest.java @@ -8,15 +8,13 @@ public class KostalPikoGridMeterImplTest { - private static final String COMPONENT_ID = "meter0"; - @Test public void test() throws Exception { new ComponentTest(new KostalPikoGridMeterImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // # .addReference("setCore", new KostalPikoCoreImpl()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // + .setId("meter0") // .setCoreId("core0") // .build()) // ; diff --git a/io.openems.edge.meter.artemes.am2/test/io/openems/edge/meter/artemes/am2/MeterArtemesAM2ImplTest.java b/io.openems.edge.meter.artemes.am2/test/io/openems/edge/meter/artemes/am2/MeterArtemesAM2ImplTest.java index cc287731b19..c77fb1b3a1c 100644 --- a/io.openems.edge.meter.artemes.am2/test/io/openems/edge/meter/artemes/am2/MeterArtemesAM2ImplTest.java +++ b/io.openems.edge.meter.artemes.am2/test/io/openems/edge/meter/artemes/am2/MeterArtemesAM2ImplTest.java @@ -1,26 +1,24 @@ package io.openems.edge.meter.artemes.am2; +import static io.openems.edge.meter.api.MeterType.GRID; + import org.junit.Test; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.meter.api.MeterType; public class MeterArtemesAM2ImplTest { - private static final String METER_ID = "meter0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new MeterArtemesAM2Impl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setModbusId(MODBUS_ID) // - .setType(MeterType.GRID) // + .setId("meter0") // + .setModbusId("modbus0") // + .setType(GRID) // .build()) // ; } diff --git a/io.openems.edge.meter.bcontrol.em300/test/io/openems/edge/meter/bcontrol/em300/MeterBControlEM300ImplTest.java b/io.openems.edge.meter.bcontrol.em300/test/io/openems/edge/meter/bcontrol/em300/MeterBControlEM300ImplTest.java index 04513e888fc..090b71d524b 100644 --- a/io.openems.edge.meter.bcontrol.em300/test/io/openems/edge/meter/bcontrol/em300/MeterBControlEM300ImplTest.java +++ b/io.openems.edge.meter.bcontrol.em300/test/io/openems/edge/meter/bcontrol/em300/MeterBControlEM300ImplTest.java @@ -1,26 +1,24 @@ package io.openems.edge.meter.bcontrol.em300; +import static io.openems.edge.meter.api.MeterType.GRID; + import org.junit.Test; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.meter.api.MeterType; public class MeterBControlEM300ImplTest { - private static final String METER_ID = "meter0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new MeterBControlEM300Impl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setModbusId(MODBUS_ID) // - .setType(MeterType.GRID) // + .setId("meter0") // + .setModbusId("modbus0") // + .setType(GRID) // .build()) // ; } diff --git a/io.openems.edge.meter.camillebauer.aplus/test/io/openems/edge/meter/camillebauer/aplus/MeterCamillebauerAplusImplTest.java b/io.openems.edge.meter.camillebauer.aplus/test/io/openems/edge/meter/camillebauer/aplus/MeterCamillebauerAplusImplTest.java index a6ad0bff683..2ee0d121c5d 100644 --- a/io.openems.edge.meter.camillebauer.aplus/test/io/openems/edge/meter/camillebauer/aplus/MeterCamillebauerAplusImplTest.java +++ b/io.openems.edge.meter.camillebauer.aplus/test/io/openems/edge/meter/camillebauer/aplus/MeterCamillebauerAplusImplTest.java @@ -1,27 +1,27 @@ package io.openems.edge.meter.camillebauer.aplus; +import static io.openems.edge.meter.api.MeterType.GRID; + import org.junit.Test; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.meter.api.MeterType; public class MeterCamillebauerAplusImplTest { - private static final String COMPONENT_ID = "component0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new MeterCamillebauerAplusImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // - .setModbusId(MODBUS_ID) // - .setMeterType(MeterType.GRID).setInvert(false).build()) + .setId("component0") // + .setModbusId("modbus0") // + .setMeterType(GRID) // + .setInvert(false) // + .build()) .next(new TestCase()); } diff --git a/io.openems.edge.meter.carlo.gavazzi.em300/test/io/openems/edge/meter/carlo/gavazzi/em300/MeterCarloGavazziEm300ImplTest.java b/io.openems.edge.meter.carlo.gavazzi.em300/test/io/openems/edge/meter/carlo/gavazzi/em300/MeterCarloGavazziEm300ImplTest.java index c628829fba6..529cf4a7a56 100644 --- a/io.openems.edge.meter.carlo.gavazzi.em300/test/io/openems/edge/meter/carlo/gavazzi/em300/MeterCarloGavazziEm300ImplTest.java +++ b/io.openems.edge.meter.carlo.gavazzi.em300/test/io/openems/edge/meter/carlo/gavazzi/em300/MeterCarloGavazziEm300ImplTest.java @@ -1,26 +1,24 @@ package io.openems.edge.meter.carlo.gavazzi.em300; +import static io.openems.edge.meter.api.MeterType.GRID; + import org.junit.Test; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.meter.api.MeterType; public class MeterCarloGavazziEm300ImplTest { - private static final String METER_ID = "meter0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new MeterCarloGavazziEm300Impl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setModbusId(MODBUS_ID) // - .setType(MeterType.GRID) // + .setId("meter0") // + .setModbusId("modbus0") // + .setType(GRID) // .build()) // ; } diff --git a/io.openems.edge.meter.discovergy/test/io/openems/edge/meter/discovergy/MeterDiscovergyImplTest.java b/io.openems.edge.meter.discovergy/test/io/openems/edge/meter/discovergy/MeterDiscovergyImplTest.java index 5ae02ad71c1..4ab716e0283 100644 --- a/io.openems.edge.meter.discovergy/test/io/openems/edge/meter/discovergy/MeterDiscovergyImplTest.java +++ b/io.openems.edge.meter.discovergy/test/io/openems/edge/meter/discovergy/MeterDiscovergyImplTest.java @@ -1,20 +1,19 @@ package io.openems.edge.meter.discovergy; +import static io.openems.edge.meter.api.MeterType.GRID; + import org.junit.Test; import io.openems.edge.common.test.ComponentTest; -import io.openems.edge.meter.api.MeterType; public class MeterDiscovergyImplTest { - private static final String COMPONENT_ID = "meter0"; - @Test public void test() throws Exception { new ComponentTest(new MeterDiscovergyImpl()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // - .setType(MeterType.GRID) // + .setId("meter0") // + .setType(GRID) // .setPassword("xxx") // .setEmail("x@y.z") // .setSerialNumber("12345678") // diff --git a/io.openems.edge.meter.eastron/test/io/openems/edge/meter/eastron/sdm120/MeterEastronSdm120ImplTest.java b/io.openems.edge.meter.eastron/test/io/openems/edge/meter/eastron/sdm120/MeterEastronSdm120ImplTest.java index 169778c8b20..fd67482a7b2 100644 --- a/io.openems.edge.meter.eastron/test/io/openems/edge/meter/eastron/sdm120/MeterEastronSdm120ImplTest.java +++ b/io.openems.edge.meter.eastron/test/io/openems/edge/meter/eastron/sdm120/MeterEastronSdm120ImplTest.java @@ -1,28 +1,26 @@ package io.openems.edge.meter.eastron.sdm120; +import static io.openems.edge.meter.api.MeterType.GRID; +import static io.openems.edge.meter.api.SinglePhase.L1; + import org.junit.Test; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.meter.api.MeterType; -import io.openems.edge.meter.api.SinglePhase; public class MeterEastronSdm120ImplTest { - private static final String METER_ID = "meter0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new MeterEastronSdm120Impl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setModbusId(MODBUS_ID) // - .setType(MeterType.GRID) // - .setPhase(SinglePhase.L1) // + .setId("meter0") // + .setModbusId("modbus0") // + .setType(GRID) // + .setPhase(L1) // .build()) // ; } diff --git a/io.openems.edge.meter.eastron/test/io/openems/edge/meter/eastron/sdm630/MeterEastronSdm630ImplTest.java b/io.openems.edge.meter.eastron/test/io/openems/edge/meter/eastron/sdm630/MeterEastronSdm630ImplTest.java index d79ef87a631..a8eca9a1732 100644 --- a/io.openems.edge.meter.eastron/test/io/openems/edge/meter/eastron/sdm630/MeterEastronSdm630ImplTest.java +++ b/io.openems.edge.meter.eastron/test/io/openems/edge/meter/eastron/sdm630/MeterEastronSdm630ImplTest.java @@ -1,26 +1,24 @@ package io.openems.edge.meter.eastron.sdm630; +import static io.openems.edge.meter.api.MeterType.GRID; + import org.junit.Test; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.meter.api.MeterType; public class MeterEastronSdm630ImplTest { - private static final String METER_ID = "meter0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new MeterEastronSdm630Impl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setModbusId(MODBUS_ID) // - .setType(MeterType.GRID) // + .setId("meter0") // + .setModbusId("modbus0") // + .setType(GRID) // .build()) // ; } diff --git a/io.openems.edge.meter.janitza/test/io/openems/edge/meter/janitza/umg511/MeterJanitzaUmg511ImplTest.java b/io.openems.edge.meter.janitza/test/io/openems/edge/meter/janitza/umg511/MeterJanitzaUmg511ImplTest.java index 852686d87d1..801387613e7 100644 --- a/io.openems.edge.meter.janitza/test/io/openems/edge/meter/janitza/umg511/MeterJanitzaUmg511ImplTest.java +++ b/io.openems.edge.meter.janitza/test/io/openems/edge/meter/janitza/umg511/MeterJanitzaUmg511ImplTest.java @@ -1,26 +1,24 @@ package io.openems.edge.meter.janitza.umg511; +import static io.openems.edge.meter.api.MeterType.GRID; + import org.junit.Test; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.meter.api.MeterType; public class MeterJanitzaUmg511ImplTest { - private static final String METER_ID = "meter0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new MeterJanitzaUmg511Impl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setModbusId(MODBUS_ID) // - .setType(MeterType.GRID) // + .setId("meter0") // + .setModbusId("modbus0") // + .setType(GRID) // .build()) // ; } diff --git a/io.openems.edge.meter.janitza/test/io/openems/edge/meter/janitza/umg604/MeterJanitzaUmg604ImplTest.java b/io.openems.edge.meter.janitza/test/io/openems/edge/meter/janitza/umg604/MeterJanitzaUmg604ImplTest.java index 22fe623eb16..501f7b39ce7 100644 --- a/io.openems.edge.meter.janitza/test/io/openems/edge/meter/janitza/umg604/MeterJanitzaUmg604ImplTest.java +++ b/io.openems.edge.meter.janitza/test/io/openems/edge/meter/janitza/umg604/MeterJanitzaUmg604ImplTest.java @@ -1,26 +1,24 @@ package io.openems.edge.meter.janitza.umg604; +import static io.openems.edge.meter.api.MeterType.GRID; + import org.junit.Test; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.meter.api.MeterType; public class MeterJanitzaUmg604ImplTest { - private static final String METER_ID = "meter0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new MeterJanitzaUmg604Impl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setModbusId(MODBUS_ID) // - .setType(MeterType.GRID) // + .setId("meter0") // + .setModbusId("modbus0") // + .setType(GRID) // .build()) // ; } diff --git a/io.openems.edge.meter.janitza/test/io/openems/edge/meter/janitza/umg96rme/MeterJanitzaUmg96rmeImplTest.java b/io.openems.edge.meter.janitza/test/io/openems/edge/meter/janitza/umg96rme/MeterJanitzaUmg96rmeImplTest.java index ea3f2c9ddc2..d956feeda9d 100644 --- a/io.openems.edge.meter.janitza/test/io/openems/edge/meter/janitza/umg96rme/MeterJanitzaUmg96rmeImplTest.java +++ b/io.openems.edge.meter.janitza/test/io/openems/edge/meter/janitza/umg96rme/MeterJanitzaUmg96rmeImplTest.java @@ -1,26 +1,24 @@ package io.openems.edge.meter.janitza.umg96rme; +import static io.openems.edge.meter.api.MeterType.GRID; + import org.junit.Test; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.meter.api.MeterType; public class MeterJanitzaUmg96rmeImplTest { - private static final String METER_ID = "meter0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new MeterJanitzaUmg96rmeImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setModbusId(MODBUS_ID) // - .setType(MeterType.GRID) // + .setId("meter0") // + .setModbusId("modbus0") // + .setType(GRID) // .build()) // ; } diff --git a/io.openems.edge.meter.kdk/test/io/openems/edge/meter/kdk/puct2/MeterKdk2puctImplTest.java b/io.openems.edge.meter.kdk/test/io/openems/edge/meter/kdk/puct2/MeterKdk2puctImplTest.java index 8cc7f90bdc4..c4602b9fc50 100755 --- a/io.openems.edge.meter.kdk/test/io/openems/edge/meter/kdk/puct2/MeterKdk2puctImplTest.java +++ b/io.openems.edge.meter.kdk/test/io/openems/edge/meter/kdk/puct2/MeterKdk2puctImplTest.java @@ -1,28 +1,26 @@ package io.openems.edge.meter.kdk.puct2; +import static io.openems.edge.meter.api.MeterType.GRID; + import org.junit.Test; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.meter.api.MeterType; public class MeterKdk2puctImplTest { - private static final String COMPONENT_ID = "component0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new MeterKdk2puctImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // - .setModbusId(MODBUS_ID) // + .setId("component0") // + .setModbusId("modbus0") // .setModbusUnitId(1) // - .setMeterType(MeterType.GRID) // + .setMeterType(GRID) // .setInvert(false) // .build()) .next(new TestCase()); diff --git a/io.openems.edge.meter.phoenixcontact/test/io/openems/edge/meter/phoenixcontact/PhoenixContactMeterImplTest.java b/io.openems.edge.meter.phoenixcontact/test/io/openems/edge/meter/phoenixcontact/PhoenixContactMeterImplTest.java index c6801784fb8..be2a80b1460 100644 --- a/io.openems.edge.meter.phoenixcontact/test/io/openems/edge/meter/phoenixcontact/PhoenixContactMeterImplTest.java +++ b/io.openems.edge.meter.phoenixcontact/test/io/openems/edge/meter/phoenixcontact/PhoenixContactMeterImplTest.java @@ -1,27 +1,25 @@ package io.openems.edge.meter.phoenixcontact; +import static io.openems.edge.meter.api.MeterType.PRODUCTION; + import org.junit.Test; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.meter.api.MeterType; public class PhoenixContactMeterImplTest { - private static final String COMPONENT_ID = "meter0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new PhoenixContactMeterImpl()) // .addReference("cm", new DummyConfigurationAdmin()) - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // - .setModbusId(MODBUS_ID) // - .setMeterType(MeterType.PRODUCTION) // + .setId("meter0") // + .setModbusId("modbus0") // + .setMeterType(PRODUCTION) // .build()) .next(new TestCase()); } diff --git a/io.openems.edge.meter.plexlog/test/io/openems/edge/meter/plexlog/MeterPlexlogDataloggerImplTest.java b/io.openems.edge.meter.plexlog/test/io/openems/edge/meter/plexlog/MeterPlexlogDataloggerImplTest.java index b5d53bd93e7..f4d70b3cda4 100644 --- a/io.openems.edge.meter.plexlog/test/io/openems/edge/meter/plexlog/MeterPlexlogDataloggerImplTest.java +++ b/io.openems.edge.meter.plexlog/test/io/openems/edge/meter/plexlog/MeterPlexlogDataloggerImplTest.java @@ -1,27 +1,25 @@ package io.openems.edge.meter.plexlog; +import static io.openems.edge.meter.api.MeterType.PRODUCTION; + import org.junit.Test; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.meter.api.MeterType; public class MeterPlexlogDataloggerImplTest { - private static final String COMPONENT_ID = "meter0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new MeterPlexlogDataloggerImpl()) // .addReference("cm", new DummyConfigurationAdmin()) - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // - .setMeterType(MeterType.PRODUCTION) // - .setModbusId(MODBUS_ID) // + .setId("meter0") // + .setMeterType(PRODUCTION) // + .setModbusId("modbus0") // .build()) .next(new TestCase()); } diff --git a/io.openems.edge.meter.pqplus/test/io/openems/edge/meter/pqplus/umd96/MeterPqplusUmd96ImplTest.java b/io.openems.edge.meter.pqplus/test/io/openems/edge/meter/pqplus/umd96/MeterPqplusUmd96ImplTest.java index 403893ed299..a4ec4ab0e25 100644 --- a/io.openems.edge.meter.pqplus/test/io/openems/edge/meter/pqplus/umd96/MeterPqplusUmd96ImplTest.java +++ b/io.openems.edge.meter.pqplus/test/io/openems/edge/meter/pqplus/umd96/MeterPqplusUmd96ImplTest.java @@ -1,26 +1,24 @@ package io.openems.edge.meter.pqplus.umd96; +import static io.openems.edge.meter.api.MeterType.GRID; + import org.junit.Test; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.meter.api.MeterType; public class MeterPqplusUmd96ImplTest { - private static final String METER_ID = "meter0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new MeterPqplusUmd96Impl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setModbusId(MODBUS_ID) // - .setType(MeterType.GRID) // + .setId("meter0") // + .setModbusId("modbus0") // + .setType(GRID) // .build()) // ; } diff --git a/io.openems.edge.meter.pqplus/test/io/openems/edge/meter/pqplus/umd97/MeterPqplusUmd97ImplTest.java b/io.openems.edge.meter.pqplus/test/io/openems/edge/meter/pqplus/umd97/MeterPqplusUmd97ImplTest.java index 106baa6ae23..a530ebf98a2 100644 --- a/io.openems.edge.meter.pqplus/test/io/openems/edge/meter/pqplus/umd97/MeterPqplusUmd97ImplTest.java +++ b/io.openems.edge.meter.pqplus/test/io/openems/edge/meter/pqplus/umd97/MeterPqplusUmd97ImplTest.java @@ -1,26 +1,24 @@ package io.openems.edge.meter.pqplus.umd97; +import static io.openems.edge.meter.api.MeterType.GRID; + import org.junit.Test; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.meter.api.MeterType; public class MeterPqplusUmd97ImplTest { - private static final String METER_ID = "meter0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new MeterPqplusUmd97Impl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setModbusId(MODBUS_ID) // - .setType(MeterType.GRID) // + .setId("meter0") // + .setModbusId("modbus0") // + .setType(GRID) // .build()) // ; } diff --git a/io.openems.edge.meter.schneider.acti9.smartlink/test/io/openems/edge/meter/schneider/acti9/smartlink/MeterSchneiderActi9SmartlinkImplTest.java b/io.openems.edge.meter.schneider.acti9.smartlink/test/io/openems/edge/meter/schneider/acti9/smartlink/MeterSchneiderActi9SmartlinkImplTest.java index 31b7ac51617..dd79f31f65a 100644 --- a/io.openems.edge.meter.schneider.acti9.smartlink/test/io/openems/edge/meter/schneider/acti9/smartlink/MeterSchneiderActi9SmartlinkImplTest.java +++ b/io.openems.edge.meter.schneider.acti9.smartlink/test/io/openems/edge/meter/schneider/acti9/smartlink/MeterSchneiderActi9SmartlinkImplTest.java @@ -1,26 +1,24 @@ package io.openems.edge.meter.schneider.acti9.smartlink; +import static io.openems.edge.meter.api.MeterType.GRID; + import org.junit.Test; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.meter.api.MeterType; public class MeterSchneiderActi9SmartlinkImplTest { - private static final String METER_ID = "meter0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new MeterSchneiderActi9SmartlinkImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setModbusId(MODBUS_ID) // - .setType(MeterType.GRID) // + .setId("meter0") // + .setModbusId("modbus0") // + .setType(GRID) // .setInvert(false) // .build()) // ; diff --git a/io.openems.edge.meter.siemens/test/io/openems/edge/meter/siemens/pac1600/MeterSiemensPac1600ImplTest.java b/io.openems.edge.meter.siemens/test/io/openems/edge/meter/siemens/pac1600/MeterSiemensPac1600ImplTest.java index 98707507163..bfe5929371c 100644 --- a/io.openems.edge.meter.siemens/test/io/openems/edge/meter/siemens/pac1600/MeterSiemensPac1600ImplTest.java +++ b/io.openems.edge.meter.siemens/test/io/openems/edge/meter/siemens/pac1600/MeterSiemensPac1600ImplTest.java @@ -1,26 +1,24 @@ package io.openems.edge.meter.siemens.pac1600; +import static io.openems.edge.meter.api.MeterType.GRID; + import org.junit.Test; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.meter.api.MeterType; public class MeterSiemensPac1600ImplTest { - private static final String METER_ID = "meter0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new MeterSiemensPac1600Impl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setModbusId(MODBUS_ID) // - .setType(MeterType.GRID) // + .setId("meter0") // + .setModbusId("modbus0") // + .setType(GRID) // .build()) // ; } diff --git a/io.openems.edge.meter.siemens/test/io/openems/edge/meter/siemens/pac2200/MeterSiemensPac2200ImplTest.java b/io.openems.edge.meter.siemens/test/io/openems/edge/meter/siemens/pac2200/MeterSiemensPac2200ImplTest.java index 51a0989cde4..316d770773a 100644 --- a/io.openems.edge.meter.siemens/test/io/openems/edge/meter/siemens/pac2200/MeterSiemensPac2200ImplTest.java +++ b/io.openems.edge.meter.siemens/test/io/openems/edge/meter/siemens/pac2200/MeterSiemensPac2200ImplTest.java @@ -1,26 +1,24 @@ package io.openems.edge.meter.siemens.pac2200; +import static io.openems.edge.meter.api.MeterType.GRID; + import org.junit.Test; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.meter.api.MeterType; public class MeterSiemensPac2200ImplTest { - private static final String METER_ID = "meter0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new MeterSiemensPac2200Impl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setModbusId(MODBUS_ID) // - .setType(MeterType.GRID) // + .setId("meter0") // + .setModbusId("modbus0") // + .setType(GRID) // .setInvert(false) // .build()) // ; diff --git a/io.openems.edge.meter.sma.shm20/test/io/openems/edge/meter/sma/shm20/MeterSmaShm20ImplTest.java b/io.openems.edge.meter.sma.shm20/test/io/openems/edge/meter/sma/shm20/MeterSmaShm20ImplTest.java index 2d72d2aa8ee..17f254ed9a0 100644 --- a/io.openems.edge.meter.sma.shm20/test/io/openems/edge/meter/sma/shm20/MeterSmaShm20ImplTest.java +++ b/io.openems.edge.meter.sma.shm20/test/io/openems/edge/meter/sma/shm20/MeterSmaShm20ImplTest.java @@ -1,26 +1,24 @@ package io.openems.edge.meter.sma.shm20; +import static io.openems.edge.meter.api.MeterType.GRID; + import org.junit.Test; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.meter.api.MeterType; public class MeterSmaShm20ImplTest { - private static final String METER_ID = "meter0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new MeterSmaShm20Impl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setModbusId(MODBUS_ID) // - .setType(MeterType.GRID) // + .setId("meter0") // + .setModbusId("modbus0") // + .setType(GRID) // .build()) // ; } diff --git a/io.openems.edge.meter.socomec/test/io/openems/edge/meter/socomec/singlephase/MeterSocomecSinglephaseImplTest.java b/io.openems.edge.meter.socomec/test/io/openems/edge/meter/socomec/singlephase/MeterSocomecSinglephaseImplTest.java index 7b232645b1f..874f97a5cb9 100644 --- a/io.openems.edge.meter.socomec/test/io/openems/edge/meter/socomec/singlephase/MeterSocomecSinglephaseImplTest.java +++ b/io.openems.edge.meter.socomec/test/io/openems/edge/meter/socomec/singlephase/MeterSocomecSinglephaseImplTest.java @@ -1,19 +1,17 @@ package io.openems.edge.meter.socomec.singlephase; +import static io.openems.edge.meter.api.MeterType.GRID; +import static io.openems.edge.meter.api.SinglePhase.L1; + import org.junit.Before; import org.junit.Test; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.meter.api.MeterType; -import io.openems.edge.meter.api.SinglePhase; public class MeterSocomecSinglephaseImplTest { - private static final String METER_ID = "meter0"; - private static final String MODBUS_ID = "modbus0"; - private static MeterSocomecSinglephaseImpl meter; @Before @@ -21,13 +19,13 @@ public void setup() throws Exception { meter = new MeterSocomecSinglephaseImpl(); new ComponentTest(meter) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setModbusId(MODBUS_ID) // - .setType(MeterType.GRID) // + .setId("meter0") // + .setModbusId("modbus0") // + .setType(GRID) // .setInvert(false) // - .setPhase(SinglePhase.L1) // + .setPhase(L1) // .build()); // } diff --git a/io.openems.edge.meter.socomec/test/io/openems/edge/meter/socomec/threephase/MeterSocomecThreephaseImplTest.java b/io.openems.edge.meter.socomec/test/io/openems/edge/meter/socomec/threephase/MeterSocomecThreephaseImplTest.java index 399894b186f..9447af3edf4 100644 --- a/io.openems.edge.meter.socomec/test/io/openems/edge/meter/socomec/threephase/MeterSocomecThreephaseImplTest.java +++ b/io.openems.edge.meter.socomec/test/io/openems/edge/meter/socomec/threephase/MeterSocomecThreephaseImplTest.java @@ -1,18 +1,16 @@ package io.openems.edge.meter.socomec.threephase; +import static io.openems.edge.meter.api.MeterType.GRID; + import org.junit.Before; import org.junit.Test; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.meter.api.MeterType; public class MeterSocomecThreephaseImplTest { - private static final String METER_ID = "meter0"; - private static final String MODBUS_ID = "modbus0"; - private static MeterSocomecThreephaseImpl meter; @Before @@ -20,11 +18,11 @@ public void setup() throws Exception { meter = new MeterSocomecThreephaseImpl(); new ComponentTest(meter) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setModbusId(MODBUS_ID) // - .setType(MeterType.GRID) // + .setId("meter0") // + .setModbusId("modbus0") // + .setType(GRID) // .setInvert(false) // .build()); // } 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 69dd6d1c616..545eee8e712 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 @@ -1,89 +1,59 @@ package io.openems.edge.meter.virtual.add; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.ACTIVE_POWER; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.ACTIVE_POWER_L1; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.ACTIVE_POWER_L2; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.ACTIVE_POWER_L3; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.FREQUENCY; +import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.VOLTAGE; +import static io.openems.edge.meter.api.MeterType.GRID; + import org.junit.Test; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.meter.api.MeterType; import io.openems.edge.meter.test.DummyElectricityMeter; public class MeterVirtualAddImplTest { - private static final String METER_ID = "meter0"; - private static final ChannelAddress METER_POWER = new ChannelAddress(METER_ID, "ActivePower"); - private static final ChannelAddress METER_VOLTAGE = new ChannelAddress(METER_ID, "Voltage"); - private static final ChannelAddress METER_FREQ = new ChannelAddress(METER_ID, "Frequency"); - - private static final ChannelAddress METER_POWER_L1 = new ChannelAddress(METER_ID, "ActivePowerL1"); - private static final ChannelAddress METER_POWER_L2 = new ChannelAddress(METER_ID, "ActivePowerL2"); - private static final ChannelAddress METER_POWER_L3 = new ChannelAddress(METER_ID, "ActivePowerL3"); - - private static final String METER_ID_1 = "meter1"; - private static final ChannelAddress METER_ID_1_ACTIVEPOWER = new ChannelAddress(METER_ID_1, "ActivePower"); - private static final ChannelAddress METER_ID_1_VOLTAGE = new ChannelAddress(METER_ID_1, "Voltage"); - private static final ChannelAddress METER_ID_1_FREQUENCY = new ChannelAddress(METER_ID_1, "Frequency"); - - private static final ChannelAddress METER_ID_1_ACTIVEPOWER_L1 = new ChannelAddress(METER_ID_1, "ActivePowerL1"); - private static final ChannelAddress METER_ID_1_ACTIVEPOWER_L2 = new ChannelAddress(METER_ID_1, "ActivePowerL2"); - private static final ChannelAddress METER_ID_1_ACTIVEPOWER_L3 = new ChannelAddress(METER_ID_1, "ActivePowerL3"); - - private static final String METER_ID_2 = "meter2"; - private static final ChannelAddress METER_ID_2_ACTIVEPOWER = new ChannelAddress(METER_ID_2, "ActivePower"); - private static final ChannelAddress METER_ID_2_VOLTAGE = new ChannelAddress(METER_ID_2, "Voltage"); - private static final ChannelAddress METER_ID_2_FREQUENCY = new ChannelAddress(METER_ID_2, "Frequency"); - - 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 { new ComponentTest(new MeterVirtualAddImpl()) // .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)) // + .addReference("addMeter", new DummyElectricityMeter("meter1")) + .addReference("addMeter", new DummyElectricityMeter("meter2")) // + .addReference("addMeter", new DummyElectricityMeter("meter3")) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setMeterIds(METER_ID_1, METER_ID_2, METER_ID_3) // - .setType(MeterType.GRID) // + .setId("meter0") // + .setMeterIds("meter1", "meter2", "meter3") // + .setType(GRID) // .build()) .next(new TestCase("one") // - .input(METER_ID_1_ACTIVEPOWER, 6_000) // - .input(METER_ID_1_ACTIVEPOWER_L1, 2_000) // - .input(METER_ID_1_ACTIVEPOWER_L2, 2_000) // - .input(METER_ID_1_ACTIVEPOWER_L3, 2_000) // - .input(METER_ID_2_ACTIVEPOWER, 7_500) // - .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_3_FREQUENCY, 56)) // + .input("meter1", ACTIVE_POWER, 6_000) // + .input("meter1", ACTIVE_POWER_L1, 2_000) // + .input("meter1", ACTIVE_POWER_L2, 2_000) // + .input("meter1", ACTIVE_POWER_L3, 2_000) // + .input("meter2", ACTIVE_POWER, 7_500) // + .input("meter2", ACTIVE_POWER_L1, 2_500) // + .input("meter2", ACTIVE_POWER_L2, 2_500) // + .input("meter2", ACTIVE_POWER_L3, 2_500) // + .input("meter3", ACTIVE_POWER, 9_000) // + .input("meter3", ACTIVE_POWER_L1, 3_000) // + .input("meter3", ACTIVE_POWER_L2, 3_000) // + .input("meter3", ACTIVE_POWER_L3, 3_000) // + .input("meter1", VOLTAGE, 10) // + .input("meter2", VOLTAGE, 20) // + .input("meter3", VOLTAGE, 30) // + .input("meter1", FREQUENCY, 49) // + .input("meter2", FREQUENCY, 51) // + .input("meter3", FREQUENCY, 56)) // .next(new TestCase("two") // - .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)); + .output(ACTIVE_POWER, 22_500) // + .output(ACTIVE_POWER_L1, 7_500) // + .output(ACTIVE_POWER_L2, 7_500) // + .output(ACTIVE_POWER_L3, 7_500) // + .output(VOLTAGE, 20) // + .output(FREQUENCY, 52)); } } diff --git a/io.openems.edge.meter.virtual/test/io/openems/edge/meter/virtual/subtract/VirtualSubtractMeterImplTest.java b/io.openems.edge.meter.virtual/test/io/openems/edge/meter/virtual/subtract/VirtualSubtractMeterImplTest.java index d92470e3068..aa560e8dc04 100644 --- a/io.openems.edge.meter.virtual/test/io/openems/edge/meter/virtual/subtract/VirtualSubtractMeterImplTest.java +++ b/io.openems.edge.meter.virtual/test/io/openems/edge/meter/virtual/subtract/VirtualSubtractMeterImplTest.java @@ -1,60 +1,50 @@ package io.openems.edge.meter.virtual.subtract; -import org.junit.Test; +import static io.openems.edge.meter.api.MeterType.GRID; + +import java.util.List; -import com.google.common.collect.Lists; +import org.junit.Test; -import io.openems.common.types.ChannelAddress; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; +import io.openems.edge.ess.api.SymmetricEss; import io.openems.edge.ess.test.DummyManagedSymmetricEss; -import io.openems.edge.meter.api.MeterType; +import io.openems.edge.meter.api.ElectricityMeter; import io.openems.edge.meter.test.DummyElectricityMeter; public class VirtualSubtractMeterImplTest { - private static final String METER_ID = "meter0"; - private static final ChannelAddress METER_POWER = new ChannelAddress(METER_ID, "ActivePower"); - - private static final String MINUEND_ID = "meter1"; - private static final ChannelAddress MINUEND_POWER = new ChannelAddress(MINUEND_ID, "ActivePower"); - - private static final String SUBTRAHEND1_ID = "meter2"; - private static final ChannelAddress SUBTRAHEND1_POWER = new ChannelAddress(SUBTRAHEND1_ID, "ActivePower"); - - private static final String SUBTRAHEND2_ID = "ess0"; - private static final ChannelAddress SUBTRAHEND2_POWER = new ChannelAddress(SUBTRAHEND2_ID, "ActivePower"); - @Test public void test() throws Exception { new ComponentTest(new VirtualSubtractMeterImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("minuend", new DummyElectricityMeter(MINUEND_ID)) // - .addReference("subtrahends", Lists.newArrayList(// - new DummyElectricityMeter(SUBTRAHEND1_ID), // - new DummyManagedSymmetricEss(SUBTRAHEND2_ID))) // + .addReference("minuend", new DummyElectricityMeter("meter1")) // + .addReference("subtrahends", List.of(// + new DummyElectricityMeter("meter2"), // + new DummyManagedSymmetricEss("ess0"))) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setType(MeterType.GRID) // + .setId("meter0") // + .setType(GRID) // .setAddToSum(true) // - .setMinuendId(MINUEND_ID) // - .setSubtrahendsIds(SUBTRAHEND1_ID, SUBTRAHEND2_ID) // + .setMinuendId("meter1") // + .setSubtrahendsIds("meter2", "ess0") // .build()) // .next(new TestCase() // - .input(MINUEND_POWER, 5_000) // - .input(SUBTRAHEND1_POWER, 2_000) // - .input(SUBTRAHEND2_POWER, 4_000) // - .output(METER_POWER, -1000)) // + .input("meter1", ElectricityMeter.ChannelId.ACTIVE_POWER, 5_000) // + .input("meter2", ElectricityMeter.ChannelId.ACTIVE_POWER, 2_000) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 4_000) // + .output("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, -1000)) // .next(new TestCase() // - .input(MINUEND_POWER, null) // - .input(SUBTRAHEND1_POWER, 2_000) // - .input(SUBTRAHEND2_POWER, 4_000) // - .output(METER_POWER, null)) // + .input("meter1", ElectricityMeter.ChannelId.ACTIVE_POWER, null) // + .input("meter2", ElectricityMeter.ChannelId.ACTIVE_POWER, 2_000) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 4_000) // + .output("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, null)) // .next(new TestCase() // - .input(MINUEND_POWER, 5_000) // - .input(SUBTRAHEND1_POWER, null) // - .input(SUBTRAHEND2_POWER, 4_000) // - .output(METER_POWER, 1000)); + .input("meter1", ElectricityMeter.ChannelId.ACTIVE_POWER, 5_000) // + .input("meter2", ElectricityMeter.ChannelId.ACTIVE_POWER, null) // + .input("ess0", SymmetricEss.ChannelId.ACTIVE_POWER, 4_000) // + .output("meter0", ElectricityMeter.ChannelId.ACTIVE_POWER, 1000)); } } \ No newline at end of file diff --git a/io.openems.edge.meter.weidmueller/test/io/openems/edge/meter/weidmueller/MeterWeidmueller525ImplTest.java b/io.openems.edge.meter.weidmueller/test/io/openems/edge/meter/weidmueller/MeterWeidmueller525ImplTest.java index cb447a0c407..fdcc894d9de 100644 --- a/io.openems.edge.meter.weidmueller/test/io/openems/edge/meter/weidmueller/MeterWeidmueller525ImplTest.java +++ b/io.openems.edge.meter.weidmueller/test/io/openems/edge/meter/weidmueller/MeterWeidmueller525ImplTest.java @@ -1,26 +1,24 @@ package io.openems.edge.meter.weidmueller; +import static io.openems.edge.meter.api.MeterType.GRID; + import org.junit.Test; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.meter.api.MeterType; public class MeterWeidmueller525ImplTest { - private static final String METER_ID = "meter0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new MeterWeidmueller525Impl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setModbusId(MODBUS_ID) // - .setType(MeterType.GRID) // + .setId("meter0") // + .setModbusId("modbus0") // + .setType(GRID) // .build()) // ; } diff --git a/io.openems.edge.meter.ziehl/test/io/openems/edge/meter/ziehl/efr4001ip/MeterZiehlEfr4001IpImplTest.java b/io.openems.edge.meter.ziehl/test/io/openems/edge/meter/ziehl/efr4001ip/MeterZiehlEfr4001IpImplTest.java index 11397a94eee..ac18f9e6332 100644 --- a/io.openems.edge.meter.ziehl/test/io/openems/edge/meter/ziehl/efr4001ip/MeterZiehlEfr4001IpImplTest.java +++ b/io.openems.edge.meter.ziehl/test/io/openems/edge/meter/ziehl/efr4001ip/MeterZiehlEfr4001IpImplTest.java @@ -1,28 +1,26 @@ package io.openems.edge.meter.ziehl.efr4001ip; +import static io.openems.edge.meter.api.MeterType.GRID; + import org.junit.Test; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.meter.api.MeterType; public class MeterZiehlEfr4001IpImplTest { - private static final String COMPONENT_ID = "component0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new MeterZiehlEfr4001IpImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // - .setModbusId(MODBUS_ID) // + .setId("component0") // + .setModbusId("modbus0") // .setModbusUnitId(1) // - .setMeterType(MeterType.GRID) // + .setMeterType(GRID) // .setInvert(false) // .build()) .next(new TestCase()); diff --git a/io.openems.edge.predictor.persistencemodel/test/io/openems/edge/predictor/persistencemodel/PredictorPersistenceModelImplTest.java b/io.openems.edge.predictor.persistencemodel/test/io/openems/edge/predictor/persistencemodel/PredictorPersistenceModelImplTest.java index 4cd7b472cdd..d0d95b109eb 100644 --- a/io.openems.edge.predictor.persistencemodel/test/io/openems/edge/predictor/persistencemodel/PredictorPersistenceModelImplTest.java +++ b/io.openems.edge.predictor.persistencemodel/test/io/openems/edge/predictor/persistencemodel/PredictorPersistenceModelImplTest.java @@ -1,34 +1,28 @@ package io.openems.edge.predictor.persistencemodel; +import static io.openems.edge.common.test.TestUtils.createDummyClock; +import static io.openems.edge.predictor.api.prediction.LogVerbosity.NONE; import static io.openems.edge.predictor.api.prediction.Prediction.EMPTY_PREDICTION; +import static java.time.temporal.ChronoUnit.HOURS; import static org.junit.Assert.assertEquals; -import java.time.Instant; import java.time.ZoneId; -import java.time.ZoneOffset; import java.time.ZonedDateTime; -import java.time.temporal.ChronoUnit; import org.junit.Test; -import io.openems.common.test.TimeLeapClock; import io.openems.common.types.ChannelAddress; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyComponentManager; -import io.openems.edge.predictor.api.prediction.LogVerbosity; import io.openems.edge.timedata.test.DummyTimedata; public class PredictorPersistenceModelImplTest { - private static final String TIMEDATA_ID = "timedata0"; - private static final String PREDICTOR_ID = "predictor0"; - private static final ChannelAddress METER1_ACTIVE_POWER = new ChannelAddress("meter1", "ActivePower"); @Test public void test() throws Exception { - final var clock = new TimeLeapClock(Instant.ofEpochSecond(1577836800) /* starts at 1. January 2020 00:00:00 */, - ZoneOffset.UTC); + final var clock = createDummyClock(); int[] values = { // Day 1 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9, 146, 348, 636, 1192, 2092, 2882, 3181, @@ -43,7 +37,7 @@ public void test() throws Exception { 477, 501, 547, 589, 1067, 13304, 17367, 14825, 13654, 12545, 8371, 10468, 9810, 8537, 6228, 3758, 4131, 3572, 1698, 1017, 569, 188, 14, 2, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - var timedata = new DummyTimedata(TIMEDATA_ID); + var timedata = new DummyTimedata("timedata0"); var start = ZonedDateTime.of(2019, 12, 30, 0, 0, 0, 0, ZoneId.of("UTC")); for (var i = 0; i < values.length; i++) { timedata.add(start.plusMinutes(i * 15), METER1_ACTIVE_POWER, values[i]); @@ -55,9 +49,9 @@ public void test() throws Exception { .addReference("timedata", timedata) // .addReference("componentManager", new DummyComponentManager(clock)) // .activate(MyConfig.create() // - .setId(PREDICTOR_ID) // + .setId("predictor0") // .setChannelAddresses(METER1_ACTIVE_POWER.toString()) // - .setLogVerbosity(LogVerbosity.NONE) // + .setLogVerbosity(NONE) // .build()); var prediction = sut.getPrediction(METER1_ACTIVE_POWER); @@ -74,7 +68,7 @@ public void test() throws Exception { @Test public void test2() throws Exception { var start = ZonedDateTime.of(2019, 12, 30, 0, 0, 0, 0, ZoneId.of("UTC")); - final var clock = new TimeLeapClock(start.toInstant(), ZoneOffset.UTC); + final var clock = createDummyClock(); int[] values = { // Day 1 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 19, 74, 323, @@ -87,7 +81,7 @@ public void test2() throws Exception { 7320, 5950, 5644, 7157, 6847, 6549, 6498, 6296, 6096, 5895, 5658, 5372, 5011, 4603, 4159, 3831, 3400, 2757, 727, 194, 70, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - var timedata = new DummyTimedata(TIMEDATA_ID); + var timedata = new DummyTimedata("timedata0"); for (var i = 0; i < values.length; i++) { timedata.add(start.plusMinutes(i * 15), METER1_ACTIVE_POWER, values[i]); } @@ -98,30 +92,29 @@ public void test2() throws Exception { .addReference("timedata", timedata) // .addReference("componentManager", new DummyComponentManager(clock)) // .activate(MyConfig.create() // - .setId(PREDICTOR_ID) // + .setId("predictor0") // .setChannelAddresses(METER1_ACTIVE_POWER.toString()) // - .setLogVerbosity(LogVerbosity.NONE) // + .setLogVerbosity(NONE) // .build()); - clock.leap(39, ChronoUnit.HOURS); + clock.leap(39, HOURS); sut.getPrediction(METER1_ACTIVE_POWER); } @Test public void testEmpty() throws Exception { - final var clock = new TimeLeapClock(Instant.ofEpochSecond(1577836800) /* starts at 1. January 2020 00:00:00 */, - ZoneOffset.UTC); - var timedata = new DummyTimedata(TIMEDATA_ID); + final var clock = createDummyClock(); + var timedata = new DummyTimedata("timedata0"); var sut = new PredictorPersistenceModelImpl(); new ComponentTest(sut) // .addReference("timedata", timedata) // .addReference("componentManager", new DummyComponentManager(clock)) // .activate(MyConfig.create() // - .setId(PREDICTOR_ID) // + .setId("predictor0") // .setChannelAddresses(METER1_ACTIVE_POWER.toString()) // - .setLogVerbosity(LogVerbosity.NONE) // + .setLogVerbosity(NONE) // .build()); assertEquals(EMPTY_PREDICTION, sut.getPrediction(METER1_ACTIVE_POWER)); diff --git a/io.openems.edge.predictor.similardaymodel/test/io/openems/edge/predictor/similardaymodel/PredictorSimilardayModelImplTest.java b/io.openems.edge.predictor.similardaymodel/test/io/openems/edge/predictor/similardaymodel/PredictorSimilardayModelImplTest.java index 6374c6a2b55..8f9e3d25fd3 100644 --- a/io.openems.edge.predictor.similardaymodel/test/io/openems/edge/predictor/similardaymodel/PredictorSimilardayModelImplTest.java +++ b/io.openems.edge.predictor.similardaymodel/test/io/openems/edge/predictor/similardaymodel/PredictorSimilardayModelImplTest.java @@ -18,9 +18,6 @@ public class PredictorSimilardayModelImplTest { - private static final String TIMEDATA_ID = "timedata0"; - private static final String PREDICTOR_ID = "predictor0"; - private static final ChannelAddress METER1_ACTIVE_POWER = new ChannelAddress("meter1", "ActivePower"); @Test @@ -32,7 +29,7 @@ public void test() throws Exception { var values = Data.data; var predictedValues = Data.predictedData; - var timedata = new DummyTimedata(TIMEDATA_ID); + var timedata = new DummyTimedata("timedata0"); var start = ZonedDateTime.of(2019, 12, 1, 0, 0, 0, 0, ZoneId.of("UTC")); for (var i = 0; i < values.length; i++) { @@ -45,7 +42,7 @@ public void test() throws Exception { .addReference("timedata", timedata) // .addReference("componentManager", new DummyComponentManager(clock)) // .activate(MyConfig.create() // - .setId(PREDICTOR_ID) // + .setId("predictor0") // .setNumOfWeeks(4) // .setChannelAddresses(METER1_ACTIVE_POWER.toString()) // .setLogVerbosity(LogVerbosity.NONE) // diff --git a/io.openems.edge.pvinverter.cluster/test/io/openems/edge/pvinverter/cluster/PvInverterClusterImplTest.java b/io.openems.edge.pvinverter.cluster/test/io/openems/edge/pvinverter/cluster/PvInverterClusterImplTest.java index 8ea8a4efda1..c5d1d1c31a6 100644 --- a/io.openems.edge.pvinverter.cluster/test/io/openems/edge/pvinverter/cluster/PvInverterClusterImplTest.java +++ b/io.openems.edge.pvinverter.cluster/test/io/openems/edge/pvinverter/cluster/PvInverterClusterImplTest.java @@ -8,14 +8,12 @@ public class PvInverterClusterImplTest { - private static final String COMPONENT_ID = "io0"; - @Test public void test() throws Exception { new ComponentTest(new PvInverterClusterImpl()) // .addReference("componentManager", new DummyComponentManager()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // + .setId("io0") // .setPvInverterIds() // .build()) // .next(new TestCase()) // diff --git a/io.openems.edge.pvinverter.fronius/test/io/openems/edge/pvinverter/fronius/PvInverterFroniusImplTest.java b/io.openems.edge.pvinverter.fronius/test/io/openems/edge/pvinverter/fronius/PvInverterFroniusImplTest.java index 04e6f406c5f..db5e7b321d7 100644 --- a/io.openems.edge.pvinverter.fronius/test/io/openems/edge/pvinverter/fronius/PvInverterFroniusImplTest.java +++ b/io.openems.edge.pvinverter.fronius/test/io/openems/edge/pvinverter/fronius/PvInverterFroniusImplTest.java @@ -8,18 +8,15 @@ public class PvInverterFroniusImplTest { - private static final String PV_INVERTER_ID = "pvInverter0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new PvInverterFroniusImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(PV_INVERTER_ID) // + .setId("pvInverter0") // .setReadOnly(true) // - .setModbusId(MODBUS_ID) // + .setModbusId("modbus0") // .setModbusUnitId(1) // .build()) // ; diff --git a/io.openems.edge.pvinverter.kaco.blueplanet/test/io/openems/edge/pvinverter/kaco/blueplanet/PvInverterKacoBlueplanetImplTest.java b/io.openems.edge.pvinverter.kaco.blueplanet/test/io/openems/edge/pvinverter/kaco/blueplanet/PvInverterKacoBlueplanetImplTest.java index 80811823b8e..af619a2deb4 100644 --- a/io.openems.edge.pvinverter.kaco.blueplanet/test/io/openems/edge/pvinverter/kaco/blueplanet/PvInverterKacoBlueplanetImplTest.java +++ b/io.openems.edge.pvinverter.kaco.blueplanet/test/io/openems/edge/pvinverter/kaco/blueplanet/PvInverterKacoBlueplanetImplTest.java @@ -8,18 +8,15 @@ public class PvInverterKacoBlueplanetImplTest { - private static final String PV_INVERTER_ID = "pvInverter0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new PvInverterKacoBlueplanetImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(PV_INVERTER_ID) // + .setId("pvInverter0") // .setReadOnly(true) // - .setModbusId(MODBUS_ID) // + .setModbusId("modbus0") // .setModbusUnitId(1) // .build()) // ; diff --git a/io.openems.edge.pvinverter.kostal/test/io/openems/edge/pvinverter/kostal/PvInverterKostalImplTest.java b/io.openems.edge.pvinverter.kostal/test/io/openems/edge/pvinverter/kostal/PvInverterKostalImplTest.java index d9b74670758..c9f44649eb9 100644 --- a/io.openems.edge.pvinverter.kostal/test/io/openems/edge/pvinverter/kostal/PvInverterKostalImplTest.java +++ b/io.openems.edge.pvinverter.kostal/test/io/openems/edge/pvinverter/kostal/PvInverterKostalImplTest.java @@ -8,18 +8,15 @@ public class PvInverterKostalImplTest { - private static final String PV_INVERTER_ID = "pvInverter0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new PvInverterKostalImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(PV_INVERTER_ID) // + .setId("pvInverter0") // .setReadOnly(true) // - .setModbusId(MODBUS_ID) // + .setModbusId("modbus0") // .setModbusUnitId(1) // .build()) // ; diff --git a/io.openems.edge.pvinverter.sma/test/io/openems/edge/pvinverter/sma/PvInverterSmaSunnyTripowerImplTest.java b/io.openems.edge.pvinverter.sma/test/io/openems/edge/pvinverter/sma/PvInverterSmaSunnyTripowerImplTest.java index 27b7a2d9d03..6e1b94cf7b0 100644 --- a/io.openems.edge.pvinverter.sma/test/io/openems/edge/pvinverter/sma/PvInverterSmaSunnyTripowerImplTest.java +++ b/io.openems.edge.pvinverter.sma/test/io/openems/edge/pvinverter/sma/PvInverterSmaSunnyTripowerImplTest.java @@ -1,28 +1,26 @@ package io.openems.edge.pvinverter.sma; +import static io.openems.edge.pvinverter.sunspec.Phase.ALL; + import org.junit.Test; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.pvinverter.sunspec.Phase; public class PvInverterSmaSunnyTripowerImplTest { - private static final String PV_INVERTER_ID = "pvInverter0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new PvInverterSmaSunnyTripowerImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(PV_INVERTER_ID) // + .setId("pvInverter0") // .setReadOnly(true) // - .setModbusId(MODBUS_ID) // + .setModbusId("modbus0") // .setModbusUnitId(1) // - .setPhase(Phase.ALL) // + .setPhase(ALL) // .build()) // ; } diff --git a/io.openems.edge.pvinverter.solarlog/test/io/openems/edge/pvinverter/solarlog/PvInverterSolarlogImplTest.java b/io.openems.edge.pvinverter.solarlog/test/io/openems/edge/pvinverter/solarlog/PvInverterSolarlogImplTest.java index 7d1f87a7b69..778f9f85f63 100644 --- a/io.openems.edge.pvinverter.solarlog/test/io/openems/edge/pvinverter/solarlog/PvInverterSolarlogImplTest.java +++ b/io.openems.edge.pvinverter.solarlog/test/io/openems/edge/pvinverter/solarlog/PvInverterSolarlogImplTest.java @@ -8,17 +8,14 @@ public class PvInverterSolarlogImplTest { - private static final String METER_ID = "meter0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new PvInverterSolarlogImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setModbusId(MODBUS_ID) // + .setId("meter0") // + .setModbusId("modbus0") // .build()) // ; } diff --git a/io.openems.edge.scheduler.allalphabetically/test/io/openems/edge/scheduler/allalphabetically/SchedulerAllAlphabeticallyImplTest.java b/io.openems.edge.scheduler.allalphabetically/test/io/openems/edge/scheduler/allalphabetically/SchedulerAllAlphabeticallyImplTest.java index 204e4e48109..0b4ca7c84d5 100644 --- a/io.openems.edge.scheduler.allalphabetically/test/io/openems/edge/scheduler/allalphabetically/SchedulerAllAlphabeticallyImplTest.java +++ b/io.openems.edge.scheduler.allalphabetically/test/io/openems/edge/scheduler/allalphabetically/SchedulerAllAlphabeticallyImplTest.java @@ -18,33 +18,25 @@ public class SchedulerAllAlphabeticallyImplTest { - private static final String SCHEDULER_ID = "scheduler0"; - - private static final String CTRL0_ID = "ctrl0"; - private static final String CTRL1_ID = "ctrl1"; - private static final String CTRL2_ID = "ctrl2"; - private static final String CTRL3_ID = "ctrl3"; - private static final String CTRL4_ID = "ctrl4"; - @Test public void testWithFixedPriorities() throws Exception { final SchedulerAllAlphabetically sut = new SchedulerAllAlphabeticallyImpl(); new ComponentTest(sut) // .addReference("componentManager", new DummyComponentManager()) // - .addComponent(new DummyController(CTRL0_ID)) // - .addComponent(new DummyController(CTRL1_ID)) // - .addComponent(new DummyController(CTRL2_ID)) // - .addComponent(new DummyController(CTRL3_ID)) // - .addComponent(new DummyController(CTRL4_ID)) // + .addComponent(new DummyController("ctrl0")) // + .addComponent(new DummyController("ctrl1")) // + .addComponent(new DummyController("ctrl2")) // + .addComponent(new DummyController("ctrl3")) // + .addComponent(new DummyController("ctrl4")) // .activate(MyConfig.create() // - .setId(SCHEDULER_ID) // - .setControllersIds(CTRL2_ID, CTRL1_ID, "") // + .setId("scheduler0") // + .setControllersIds("ctrl2", "ctrl1", "") // .build()) .next(new TestCase()) // .deactivate(); assertEquals(// - Arrays.asList(CTRL2_ID, CTRL1_ID, CTRL0_ID, CTRL3_ID, CTRL4_ID), // + Arrays.asList("ctrl2", "ctrl1", "ctrl0", "ctrl3", "ctrl4"), // getControllerIds(sut)); } @@ -77,7 +69,7 @@ public void testOnlyAlphabeticalOrdering() throws Exception { test // .addReference("componentManager", new DummyComponentManager()) // .activate(MyConfig.create() // - .setId(SCHEDULER_ID) // + .setId("scheduler0") // .setControllersIds() // .build()) // .next(new TestCase()); diff --git a/io.openems.edge.scheduler.daily/test/io/openems/edge/scheduler/daily/SchedulerDailyImplTest.java b/io.openems.edge.scheduler.daily/test/io/openems/edge/scheduler/daily/SchedulerDailyImplTest.java index 9f0d5e94cb1..f992c074e95 100644 --- a/io.openems.edge.scheduler.daily/test/io/openems/edge/scheduler/daily/SchedulerDailyImplTest.java +++ b/io.openems.edge.scheduler.daily/test/io/openems/edge/scheduler/daily/SchedulerDailyImplTest.java @@ -1,18 +1,16 @@ package io.openems.edge.scheduler.daily; +import static io.openems.common.utils.JsonUtils.buildJsonArray; +import static io.openems.common.utils.JsonUtils.buildJsonObject; +import static io.openems.edge.common.test.TestUtils.createDummyClock; +import static java.time.temporal.ChronoUnit.HOURS; import static org.junit.Assert.assertEquals; -import java.time.Instant; -import java.time.ZoneOffset; -import java.time.temporal.ChronoUnit; -import java.util.Arrays; import java.util.List; import org.junit.Test; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.test.TimeLeapClock; -import io.openems.common.utils.JsonUtils; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyComponentManager; @@ -21,56 +19,49 @@ public class SchedulerDailyImplTest { - private static final String SCHEDULER_ID = "scheduler0"; - - private static final String CTRL0_ID = "ctrl0"; - private static final String CTRL1_ID = "ctrl1"; - private static final String CTRL2_ID = "ctrl2"; - private static final String CTRL3_ID = "ctrl3"; - private static final String CTRL4_ID = "ctrl4"; - @Test public void test() throws Exception { - final var clock = new TimeLeapClock(Instant.parse("2020-01-01T00:00:00.00Z"), ZoneOffset.UTC); + final var clock = createDummyClock(); final SchedulerDaily sut = new SchedulerDailyImpl(); new ComponentTest(sut) // .addReference("componentManager", new DummyComponentManager(clock)) // - .addComponent(new DummyController(CTRL0_ID)) // - .addComponent(new DummyController(CTRL1_ID)) // - .addComponent(new DummyController(CTRL2_ID)) // - .addComponent(new DummyController(CTRL3_ID)) // - .addComponent(new DummyController(CTRL4_ID)) // + .addComponent(new DummyController("ctrl0")) // + .addComponent(new DummyController("ctrl1")) // + .addComponent(new DummyController("ctrl2")) // + .addComponent(new DummyController("ctrl3")) // + .addComponent(new DummyController("ctrl4")) // .activate(MyConfig.create() // - .setId(SCHEDULER_ID) // - .setAlwaysRunBeforeControllerIds(CTRL2_ID).setControllerScheduleJson(JsonUtils.buildJsonArray() // - .add(JsonUtils.buildJsonObject() // + .setId("scheduler0") // + .setAlwaysRunBeforeControllerIds("ctrl2") // + .setControllerScheduleJson(buildJsonArray() // + .add(buildJsonObject() // .addProperty("time", "08:00:00") // - .add("controllers", JsonUtils.buildJsonArray() // - .add(CTRL0_ID) // + .add("controllers", buildJsonArray() // + .add("ctrl0") // .build()) // .build()) // - .add(JsonUtils.buildJsonObject() // + .add(buildJsonObject() // .addProperty("time", "13:45:00") // - .add("controllers", JsonUtils.buildJsonArray() // - .add(CTRL4_ID) // + .add("controllers", buildJsonArray() // + .add("ctrl4") // .build()) // .build()) // .build().toString()) - .setAlwaysRunAfterControllerIds(CTRL3_ID, CTRL1_ID) // + .setAlwaysRunAfterControllerIds("ctrl3", "ctrl1") // .build()) // .next(new TestCase("00:00") // .onBeforeControllersCallbacks(() -> assertEquals(// - Arrays.asList(CTRL2_ID, CTRL4_ID, CTRL3_ID, CTRL1_ID), // + List.of("ctrl2", "ctrl4", "ctrl3", "ctrl1"), // getControllerIds(sut)))) // .next(new TestCase("12:00") // - .timeleap(clock, 12, ChronoUnit.HOURS) // + .timeleap(clock, 12, HOURS) // .onBeforeControllersCallbacks(() -> assertEquals(// - Arrays.asList(CTRL2_ID, CTRL0_ID, CTRL3_ID, CTRL1_ID), // + List.of("ctrl2", "ctrl0", "ctrl3", "ctrl1"), // getControllerIds(sut)))) .next(new TestCase("14:00") // - .timeleap(clock, 12, ChronoUnit.HOURS) // + .timeleap(clock, 12, HOURS) // .onBeforeControllersCallbacks(() -> assertEquals(// - Arrays.asList(CTRL2_ID, CTRL4_ID, CTRL3_ID, CTRL1_ID), // + List.of("ctrl2", "ctrl4", "ctrl3", "ctrl1"), // getControllerIds(sut)))); } diff --git a/io.openems.edge.scheduler.fixedorder/test/io/openems/edge/scheduler/fixedorder/SchedulerFixedOrderImplTest.java b/io.openems.edge.scheduler.fixedorder/test/io/openems/edge/scheduler/fixedorder/SchedulerFixedOrderImplTest.java index 47bc0a88a65..710c1adddc0 100644 --- a/io.openems.edge.scheduler.fixedorder/test/io/openems/edge/scheduler/fixedorder/SchedulerFixedOrderImplTest.java +++ b/io.openems.edge.scheduler.fixedorder/test/io/openems/edge/scheduler/fixedorder/SchedulerFixedOrderImplTest.java @@ -2,7 +2,6 @@ import static org.junit.Assert.assertEquals; -import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @@ -40,7 +39,7 @@ public void test() throws Exception { test.next(new TestCase()); // assertEquals(// - Arrays.asList(CTRL3_ID, CTRL1_ID), // + List.of(CTRL3_ID, CTRL1_ID), // getControllerIds(sut)); } diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/datasource/api/DummyDatasource.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/datasource/api/DummyDatasource.java new file mode 100644 index 00000000000..0f1a58189f5 --- /dev/null +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/datasource/api/DummyDatasource.java @@ -0,0 +1,38 @@ +package io.openems.edge.simulator.datasource.api; + +import java.util.List; +import java.util.Set; + +import io.openems.common.types.ChannelAddress; +import io.openems.common.types.OpenemsType; + +public class DummyDatasource implements SimulatorDatasource { + + public final Object value; + + public DummyDatasource(Object value) { + this.value = value; + } + + @Override + public Set getKeys() { + return Set.of(); + } + + @Override + public int getTimeDelta() { + return 0; + } + + @SuppressWarnings("unchecked") + @Override + public List getValues(OpenemsType type, ChannelAddress channelAddress) { + return (List) List.of(this.value); + } + + @SuppressWarnings("unchecked") + @Override + public T getValue(OpenemsType type, ChannelAddress channelAddress) { + return (T) this.value; + } +} diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/evcs/SimulatorEvcs.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/evcs/SimulatorEvcs.java index 59c4acf3eef..bd93a48548f 100644 --- a/io.openems.edge.simulator/src/io/openems/edge/simulator/evcs/SimulatorEvcs.java +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/evcs/SimulatorEvcs.java @@ -5,13 +5,12 @@ import io.openems.common.channel.Unit; import io.openems.common.types.OpenemsType; import io.openems.edge.common.channel.Doc; -import io.openems.edge.common.channel.LongReadChannel; -import io.openems.edge.common.channel.value.Value; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.evcs.api.Evcs; import io.openems.edge.evcs.api.ManagedEvcs; +import io.openems.edge.meter.api.ElectricityMeter; -public interface SimulatorEvcs extends ManagedEvcs, Evcs, OpenemsComponent, EventHandler { +public interface SimulatorEvcs extends ManagedEvcs, Evcs, ElectricityMeter, OpenemsComponent, EventHandler { public enum ChannelId implements io.openems.edge.common.channel.ChannelId { SIMULATED_CHARGE_POWER(Doc.of(OpenemsType.INTEGER).unit(Unit.WATT)); @@ -27,24 +26,4 @@ public Doc doc() { return this.doc; } } - - @Override - public default Value getActiveConsumptionEnergy() { - return this.getActiveConsumptionEnergyChannel().getNextValue(); - } - - @Override - public default void _setActiveConsumptionEnergy(long value) { - this.channel(Evcs.ChannelId.ACTIVE_CONSUMPTION_ENERGY).setNextValue(value); - } - - @Override - public default void _setActiveConsumptionEnergy(Long value) { - this.channel(Evcs.ChannelId.ACTIVE_CONSUMPTION_ENERGY).setNextValue(value); - } - - @Override - public default LongReadChannel getActiveConsumptionEnergyChannel() { - return this.channel(Evcs.ChannelId.ACTIVE_CONSUMPTION_ENERGY); - } } diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/evcs/SimulatorEvcsImpl.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/evcs/SimulatorEvcsImpl.java index 371c2ed8619..96f489d6ce9 100644 --- a/io.openems.edge.simulator/src/io/openems/edge/simulator/evcs/SimulatorEvcsImpl.java +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/evcs/SimulatorEvcsImpl.java @@ -24,6 +24,7 @@ import io.openems.edge.evcs.api.EvcsPower; import io.openems.edge.evcs.api.ManagedEvcs; import io.openems.edge.evcs.api.Status; +import io.openems.edge.meter.api.ElectricityMeter; @Designate(ocd = Config.class, factory = true) @Component(// @@ -36,7 +37,7 @@ EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE, // }) public class SimulatorEvcsImpl extends AbstractManagedEvcsComponent - implements SimulatorEvcs, ManagedEvcs, Evcs, OpenemsComponent, EventHandler { + implements SimulatorEvcs, ManagedEvcs, Evcs, ElectricityMeter, OpenemsComponent, EventHandler { @Reference private EvcsPower evcsPower; @@ -49,6 +50,7 @@ public class SimulatorEvcsImpl extends AbstractManagedEvcsComponent public SimulatorEvcsImpl() { super(// OpenemsComponent.ChannelId.values(), // + ElectricityMeter.ChannelId.values(), // ManagedEvcs.ChannelId.values(), // Evcs.ChannelId.values(), // SimulatorEvcs.ChannelId.values() // @@ -91,18 +93,18 @@ public void handleEvent(Event event) { private void updateChannels() { int chargePowerLimit = this.getSetChargePowerLimit().orElse(0); - this._setChargePower(chargePowerLimit); + this._setActivePower(chargePowerLimit); /* * Set Simulated "meter" Active Power */ - this._setChargePower(chargePowerLimit); + this._setActivePower(chargePowerLimit); /* * Set calculated energy */ var timeDiff = ChronoUnit.MILLIS.between(this.lastUpdate, LocalDateTime.now()); - var energyTransfered = timeDiff / 1000.0 / 60.0 / 60.0 * this.getChargePower().orElse(0); + var energyTransfered = timeDiff / 1000.0 / 60.0 / 60.0 * this.getActivePower().orElse(0); this.exactEnergySession = this.exactEnergySession + energyTransfered; this._setEnergySession((int) this.exactEnergySession); @@ -112,7 +114,7 @@ private void updateChannels() { @Override public String debugLog() { - return this.getChargePower().asString(); + return this.getActivePower().asString(); } @Override @@ -138,7 +140,7 @@ public boolean getConfiguredDebugMode() { @Override public boolean applyChargePowerLimit(int power) throws OpenemsException { this._setSetChargePowerLimit(power); - this._setChargePower(power); + this._setActivePower(power); this._setStatus(power > 0 ? Status.CHARGING : Status.CHARGING_REJECTED); return true; } diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/meter/grid/acting/SimulatorGridMeterActingImpl.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/meter/grid/acting/SimulatorGridMeterActingImpl.java index 215d25ac505..c290e16d03b 100644 --- a/io.openems.edge.simulator/src/io/openems/edge/simulator/meter/grid/acting/SimulatorGridMeterActingImpl.java +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/meter/grid/acting/SimulatorGridMeterActingImpl.java @@ -23,6 +23,8 @@ import org.osgi.service.event.EventHandler; import org.osgi.service.event.propertytypes.EventTopics; import org.osgi.service.metatype.annotations.Designate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import io.openems.common.types.ChannelAddress; import io.openems.common.types.OpenemsType; @@ -39,8 +41,6 @@ import io.openems.edge.timedata.api.Timedata; import io.openems.edge.timedata.api.TimedataProvider; import io.openems.edge.timedata.api.utils.CalculateEnergyFromPower; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; @Designate(ocd = Config.class, factory = true) @Component(// diff --git a/io.openems.edge.simulator/test/io/openems/edge/simulator/battery/SimulatorBatteryImplTest.java b/io.openems.edge.simulator/test/io/openems/edge/simulator/battery/SimulatorBatteryImplTest.java index 0762e332f6d..d2f19787009 100644 --- a/io.openems.edge.simulator/test/io/openems/edge/simulator/battery/SimulatorBatteryImplTest.java +++ b/io.openems.edge.simulator/test/io/openems/edge/simulator/battery/SimulatorBatteryImplTest.java @@ -7,13 +7,11 @@ public class SimulatorBatteryImplTest { - private static final String COMPONENT_ID = "battery0"; - @Test public void test() throws Exception { new ComponentTest(new SimulatorBatteryImpl()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // + .setId("battery0") // .setCapacityKWh(20) // .setChargeMaxCurrent(40) // .setChargeMaxVoltage(700) // diff --git a/io.openems.edge.simulator/test/io/openems/edge/simulator/datasource/csv/predefined/SimulatorDatasourceCsvPredefinedImplTest.java b/io.openems.edge.simulator/test/io/openems/edge/simulator/datasource/csv/predefined/SimulatorDatasourceCsvPredefinedImplTest.java index 1ba5d54f0ca..c10d2e08e70 100644 --- a/io.openems.edge.simulator/test/io/openems/edge/simulator/datasource/csv/predefined/SimulatorDatasourceCsvPredefinedImplTest.java +++ b/io.openems.edge.simulator/test/io/openems/edge/simulator/datasource/csv/predefined/SimulatorDatasourceCsvPredefinedImplTest.java @@ -9,14 +9,12 @@ public class SimulatorDatasourceCsvPredefinedImplTest { - private static final String COMPONENT_ID = "datasource0"; - @Test public void test() throws Exception { new ComponentTest(new SimulatorDatasourceCsvPredefinedImpl()) // .addReference("componentManager", new DummyComponentManager()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // + .setId("datasource0") // .setFactor(1) // .setFormat(CsvFormat.ENGLISH) // .setSource(Source.H0_HOUSEHOLD_SUMMER_WEEKDAY_NON_REGULATED_CONSUMPTION) // diff --git a/io.openems.edge.simulator/test/io/openems/edge/simulator/datasource/single/direct/SimulatorDatasourceSingleDirectImplTest.java b/io.openems.edge.simulator/test/io/openems/edge/simulator/datasource/single/direct/SimulatorDatasourceSingleDirectImplTest.java index 7ac397de8c1..2328e523a45 100644 --- a/io.openems.edge.simulator/test/io/openems/edge/simulator/datasource/single/direct/SimulatorDatasourceSingleDirectImplTest.java +++ b/io.openems.edge.simulator/test/io/openems/edge/simulator/datasource/single/direct/SimulatorDatasourceSingleDirectImplTest.java @@ -8,14 +8,12 @@ public class SimulatorDatasourceSingleDirectImplTest { - private static final String COMPONENT_ID = "datasource0"; - @Test public void test() throws Exception { new ComponentTest(new SimulatorDatasourceSingleDirectImpl()) // .addReference("componentManager", new DummyComponentManager()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // + .setId("datasource0") // .setTimeDelta(0) // .setValues() // .build()) // diff --git a/io.openems.edge.simulator/test/io/openems/edge/simulator/evcs/SimulatorEvcsImplTest.java b/io.openems.edge.simulator/test/io/openems/edge/simulator/evcs/SimulatorEvcsImplTest.java index 5090dd90d7d..4aed1982e28 100644 --- a/io.openems.edge.simulator/test/io/openems/edge/simulator/evcs/SimulatorEvcsImplTest.java +++ b/io.openems.edge.simulator/test/io/openems/edge/simulator/evcs/SimulatorEvcsImplTest.java @@ -10,15 +10,13 @@ public class SimulatorEvcsImplTest { - private static final String ESS_ID = "evcs0"; - @Test public void test() throws OpenemsException, Exception { new ComponentTest(new SimulatorEvcsImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("evcsPower", new DummyEvcsPower()) // .activate(MyConfig.create() // - .setId(ESS_ID) // + .setId("evcs0") // .setMinHwPower(1000) // .setMaxHwPower(10000) // .build()) // diff --git a/io.openems.edge.simulator/test/io/openems/edge/simulator/io/SimulatorIoDigitalInputOutputImplTest.java b/io.openems.edge.simulator/test/io/openems/edge/simulator/io/SimulatorIoDigitalInputOutputImplTest.java index c147bc6a0b1..bd83f9838c9 100644 --- a/io.openems.edge.simulator/test/io/openems/edge/simulator/io/SimulatorIoDigitalInputOutputImplTest.java +++ b/io.openems.edge.simulator/test/io/openems/edge/simulator/io/SimulatorIoDigitalInputOutputImplTest.java @@ -8,13 +8,11 @@ public class SimulatorIoDigitalInputOutputImplTest { - private static final String COMPONENT_ID = "io0"; - @Test public void test() throws OpenemsException, Exception { new ComponentTest(new SimulatorIoDigitalInputOutputImpl()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // + .setId("io0") // .setNumberOfOutputs(3) // .build()) // .next(new TestCase()); // diff --git a/io.openems.edge.simulator/test/io/openems/edge/simulator/meter/grid/acting/SimulatorGridMeterActingImplTest.java b/io.openems.edge.simulator/test/io/openems/edge/simulator/meter/grid/acting/SimulatorGridMeterActingImplTest.java index 59d29433d83..dd2d9614318 100644 --- a/io.openems.edge.simulator/test/io/openems/edge/simulator/meter/grid/acting/SimulatorGridMeterActingImplTest.java +++ b/io.openems.edge.simulator/test/io/openems/edge/simulator/meter/grid/acting/SimulatorGridMeterActingImplTest.java @@ -7,28 +7,27 @@ import io.openems.common.exceptions.OpenemsException; import io.openems.common.test.TimeLeapClock; +import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.simulator.datasource.csv.direct.SimulatorDatasourceCsvDirectImpl; +import io.openems.edge.simulator.datasource.api.DummyDatasource; public class SimulatorGridMeterActingImplTest { - private static final String COMPONENT_ID = "meter0"; - private static final String DATASOURCE_ID = "datasource0"; - @Test public void test() throws OpenemsException, Exception { new ComponentTest(new SimulatorGridMeterActingImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("datasource", new SimulatorDatasourceCsvDirectImpl()) // + .addReference("datasource", new DummyDatasource(123)) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // + .setId("meter0") // .setStartTime("")// .needFrequencyStepResponse(false)// - .setDatasourceId(DATASOURCE_ID) // - .build()); // - // .next(new TestCase()); // TODO requires DummyDatasource + .setDatasourceId("datasource0") // + .build()) // + .next(new TestCase()) // + .deactivate(); } @Test @@ -37,13 +36,13 @@ public void test1() throws OpenemsException, Exception { new ComponentTest(new SimulatorGridMeterActingImpl()) // .addReference("componentManager", new DummyComponentManager(clock)) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("datasource", new SimulatorDatasourceCsvDirectImpl()) // + .addReference("datasource", new DummyDatasource(123)) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // + .setId("meter0") // .setStartTime("")// .needFrequencyStepResponse(true)// - .setDatasourceId(DATASOURCE_ID) // - .build()); // - // .next(new TestCase()); // TODO requires DummyDatasource + .setDatasourceId("datasource0") // + .build()) // + .deactivate(); } } diff --git a/io.openems.edge.simulator/test/io/openems/edge/simulator/meter/grid/reacting/SimulatorGridMeterReactingImplTest.java b/io.openems.edge.simulator/test/io/openems/edge/simulator/meter/grid/reacting/SimulatorGridMeterReactingImplTest.java index 96222001f3e..dedc66db72d 100644 --- a/io.openems.edge.simulator/test/io/openems/edge/simulator/meter/grid/reacting/SimulatorGridMeterReactingImplTest.java +++ b/io.openems.edge.simulator/test/io/openems/edge/simulator/meter/grid/reacting/SimulatorGridMeterReactingImplTest.java @@ -9,14 +9,12 @@ public class SimulatorGridMeterReactingImplTest { - private static final String COMPONENT_ID = "meter0"; - @Test public void test() throws OpenemsException, Exception { new ComponentTest(new SimulatorGridMeterReactingImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // + .setId("meter0") // .build()) // .next(new TestCase()); } diff --git a/io.openems.edge.simulator/test/io/openems/edge/simulator/modbus/SimulatorModbusImplTest.java b/io.openems.edge.simulator/test/io/openems/edge/simulator/modbus/SimulatorModbusImplTest.java index 3a60a20f877..6f059aa6a80 100644 --- a/io.openems.edge.simulator/test/io/openems/edge/simulator/modbus/SimulatorModbusImplTest.java +++ b/io.openems.edge.simulator/test/io/openems/edge/simulator/modbus/SimulatorModbusImplTest.java @@ -8,13 +8,11 @@ public class SimulatorModbusImplTest { - private static final String COMPONENT_ID = "modbus0"; - @Test public void test() throws OpenemsException, Exception { new ComponentTest(new SimulatorModbusImpl()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // + .setId("modbus0") // .build()) // .next(new TestCase()); } diff --git a/io.openems.edge.simulator/test/io/openems/edge/simulator/pvinverter/SimulatorPvInverterImplTest.java b/io.openems.edge.simulator/test/io/openems/edge/simulator/pvinverter/SimulatorPvInverterImplTest.java index 5310e732d61..9294bd195a1 100644 --- a/io.openems.edge.simulator/test/io/openems/edge/simulator/pvinverter/SimulatorPvInverterImplTest.java +++ b/io.openems.edge.simulator/test/io/openems/edge/simulator/pvinverter/SimulatorPvInverterImplTest.java @@ -9,17 +9,14 @@ public class SimulatorPvInverterImplTest { - private static final String COMPONENT_ID = "pvInverter0"; - private static final String DATASOURCE_ID = "datasource0"; - @Test public void test() throws OpenemsException, Exception { new ComponentTest(new SimulatorPvInverterImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("datasource", new SimulatorDatasourceCsvDirectImpl()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // - .setDatasourceId(DATASOURCE_ID) // + .setId("pvInverter0") // + .setDatasourceId("datasource0") // .build()); // // .next(new TestCase()); // TODO requires DummyDatasource } diff --git a/io.openems.edge.simulator/test/io/openems/edge/simulator/thermometer/SimulatorThermometerImplTest.java b/io.openems.edge.simulator/test/io/openems/edge/simulator/thermometer/SimulatorThermometerImplTest.java index c07899add9f..a6620e2fd54 100644 --- a/io.openems.edge.simulator/test/io/openems/edge/simulator/thermometer/SimulatorThermometerImplTest.java +++ b/io.openems.edge.simulator/test/io/openems/edge/simulator/thermometer/SimulatorThermometerImplTest.java @@ -8,13 +8,11 @@ public class SimulatorThermometerImplTest { - private static final String COMPONENT_ID = "thermometer0"; - @Test public void test() throws OpenemsException, Exception { new ComponentTest(new SimulatorThermometerImpl()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // + .setId("thermometer0") // .setTemperature(20) // .build()) // .next(new TestCase()); diff --git a/io.openems.edge.simulator/test/io/openems/edge/simulator/timedata/SimulatorTimedataImplTest.java b/io.openems.edge.simulator/test/io/openems/edge/simulator/timedata/SimulatorTimedataImplTest.java index bd1d9358847..13d83a24d12 100644 --- a/io.openems.edge.simulator/test/io/openems/edge/simulator/timedata/SimulatorTimedataImplTest.java +++ b/io.openems.edge.simulator/test/io/openems/edge/simulator/timedata/SimulatorTimedataImplTest.java @@ -9,13 +9,11 @@ public class SimulatorTimedataImplTest { - private static final String COMPONENT_ID = "thermometer0"; - @Test public void test() throws OpenemsException, Exception { new ComponentTest(new SimulatorTimedataImpl()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // + .setId("thermometer0") // .setFilename("") // .setFormat(CsvFormat.ENGLISH) // .build()) // diff --git a/io.openems.edge.solaredge/test/io/openems/edge/solaredge/gridmeter/SolarEdgeGridMeterImplTest.java b/io.openems.edge.solaredge/test/io/openems/edge/solaredge/gridmeter/SolarEdgeGridMeterImplTest.java index 6c4ccbc5b0d..92b45ac9baa 100644 --- a/io.openems.edge.solaredge/test/io/openems/edge/solaredge/gridmeter/SolarEdgeGridMeterImplTest.java +++ b/io.openems.edge.solaredge/test/io/openems/edge/solaredge/gridmeter/SolarEdgeGridMeterImplTest.java @@ -1,27 +1,25 @@ package io.openems.edge.solaredge.gridmeter; +import static io.openems.edge.meter.api.MeterType.GRID; + import org.junit.Test; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.meter.api.MeterType; public class SolarEdgeGridMeterImplTest { - private static final String METER_ID = "meter0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new SolarEdgeGridMeterImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(METER_ID) // - .setModbusId(MODBUS_ID) // + .setId("meter0") // + .setModbusId("modbus0") // .setModbusUnitId(1) // - .setType(MeterType.GRID) // + .setType(GRID) // .build()) // ; } diff --git a/io.openems.edge.solaredge/test/io/openems/edge/solaredge/pvinverter/SolarEdgePvInverterImplTest.java b/io.openems.edge.solaredge/test/io/openems/edge/solaredge/pvinverter/SolarEdgePvInverterImplTest.java index c90b0a9e978..438399b1243 100644 --- a/io.openems.edge.solaredge/test/io/openems/edge/solaredge/pvinverter/SolarEdgePvInverterImplTest.java +++ b/io.openems.edge.solaredge/test/io/openems/edge/solaredge/pvinverter/SolarEdgePvInverterImplTest.java @@ -1,28 +1,26 @@ package io.openems.edge.solaredge.pvinverter; +import static io.openems.edge.pvinverter.sunspec.Phase.L1; + import org.junit.Test; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.pvinverter.sunspec.Phase; public class SolarEdgePvInverterImplTest { - private static final String PV_INVERTER_ID = "pvInverter0"; - private static final String MODBUS_ID = "modbus0"; - @Test public void test() throws Exception { new ComponentTest(new SolarEdgePvInverterImpl()) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addReference("setModbus", new DummyModbusBridge("modbus0")) // .activate(MyConfig.create() // - .setId(PV_INVERTER_ID) // + .setId("pvInverter0") // .setReadOnly(true) // - .setModbusId(MODBUS_ID) // + .setModbusId("modbus0") // .setModbusUnitId(1) // - .setPhase(Phase.L1) // + .setPhase(L1) // .build()) // ; } diff --git a/io.openems.edge.timedata.influxdb/test/io/openems/edge/timedata/influxdb/TimedataInfluxDbImplTest.java b/io.openems.edge.timedata.influxdb/test/io/openems/edge/timedata/influxdb/TimedataInfluxDbImplTest.java index 4c097c21c69..05890b4b34c 100644 --- a/io.openems.edge.timedata.influxdb/test/io/openems/edge/timedata/influxdb/TimedataInfluxDbImplTest.java +++ b/io.openems.edge.timedata.influxdb/test/io/openems/edge/timedata/influxdb/TimedataInfluxDbImplTest.java @@ -1,19 +1,18 @@ package io.openems.edge.timedata.influxdb; +import static io.openems.common.channel.PersistencePriority.MEDIUM; +import static io.openems.shared.influxdb.QueryLanguageConfig.INFLUX_QL; + import org.junit.Test; -import io.openems.common.channel.PersistencePriority; import io.openems.common.oem.DummyOpenemsEdgeOem; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.common.test.DummyCycle; -import io.openems.shared.influxdb.QueryLanguageConfig; public class TimedataInfluxDbImplTest { - private static final String COMPONENT_ID = "influx0"; - @Test public void test() throws Exception { new ComponentTest(new TimedataInfluxDbImpl()) // @@ -21,8 +20,8 @@ public void test() throws Exception { .addReference("cycle", new DummyCycle(1000)) // .addReference("oem", new DummyOpenemsEdgeOem()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // - .setQueryLanguage(QueryLanguageConfig.INFLUX_QL) // + .setId("influx0") // + .setQueryLanguage(INFLUX_QL) // .setUrl("http://localhost:8086") // .setOrg("-") // .setApiKey("username:password") // @@ -31,7 +30,7 @@ public void test() throws Exception { .setNoOfCycles(1) // .setMaxQueueSize(5000) // .setReadOnly(false) // - .setPersistencePriority(PersistencePriority.MEDIUM) + .setPersistencePriority(MEDIUM) // .build()) // .next(new TestCase()) // ; diff --git a/io.openems.edge.timedata.rrd4j/test/io/openems/edge/timedata/rrd4j/TimedataRrd4jImplTest.java b/io.openems.edge.timedata.rrd4j/test/io/openems/edge/timedata/rrd4j/TimedataRrd4jImplTest.java index 980994dfb48..2b0590abc1b 100644 --- a/io.openems.edge.timedata.rrd4j/test/io/openems/edge/timedata/rrd4j/TimedataRrd4jImplTest.java +++ b/io.openems.edge.timedata.rrd4j/test/io/openems/edge/timedata/rrd4j/TimedataRrd4jImplTest.java @@ -1,5 +1,6 @@ package io.openems.edge.timedata.rrd4j; +import static io.openems.common.channel.PersistencePriority.MEDIUM; import static org.junit.Assert.assertEquals; import java.io.IOException; @@ -15,15 +16,12 @@ import org.rrd4j.core.RrdDef; import org.rrd4j.core.RrdMemoryBackendFactory; -import io.openems.common.channel.PersistencePriority; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyComponentManager; public class TimedataRrd4jImplTest { - private static final String COMPONENT_ID = "rrd4j0"; - @Test public void test() throws Exception { final var componentManager = new DummyComponentManager(); @@ -31,8 +29,8 @@ public void test() throws Exception { .addReference("workerFactory", new DummyRecordWorkerFactory(componentManager)) // .addReference("readHandler", new Rrd4jReadHandler()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // - .setPersistencePriority(PersistencePriority.MEDIUM) // + .setId("rrd4j0") // + .setPersistencePriority(MEDIUM) // .build()) // .next(new TestCase()) // ; diff --git a/io.openems.edge.timeofusetariff.awattar/test/io/openems/edge/timeofusetariff/awattar/TimeOfUseTariffAwattarImplTest.java b/io.openems.edge.timeofusetariff.awattar/test/io/openems/edge/timeofusetariff/awattar/TimeOfUseTariffAwattarImplTest.java index eaef278769f..dd329cfe509 100644 --- a/io.openems.edge.timeofusetariff.awattar/test/io/openems/edge/timeofusetariff/awattar/TimeOfUseTariffAwattarImplTest.java +++ b/io.openems.edge.timeofusetariff.awattar/test/io/openems/edge/timeofusetariff/awattar/TimeOfUseTariffAwattarImplTest.java @@ -1,5 +1,6 @@ package io.openems.edge.timeofusetariff.awattar; +import static io.openems.edge.timeofusetariff.awattar.Zone.GERMANY; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.fail; @@ -11,15 +12,13 @@ public class TimeOfUseTariffAwattarImplTest { - private static final String CTRL_ID = "ctrl0"; - @Test public void test() throws Exception { var awattar = new TimeOfUseTariffAwattarImpl(); new ComponentTest(awattar) // .activate(MyConfig.create() // - .setId(CTRL_ID) // - .setZone(Zone.GERMANY) // + .setId("ctrl0") // + .setZone(GERMANY) // .build()) // ; } diff --git a/io.openems.edge.timeofusetariff.corrently/test/io/openems/edge/timeofusetariff/corrently/TimeOfUseTariffCorrentlyImplTest.java b/io.openems.edge.timeofusetariff.corrently/test/io/openems/edge/timeofusetariff/corrently/TimeOfUseTariffCorrentlyImplTest.java index 3516d5f8378..83c69c1e2eb 100644 --- a/io.openems.edge.timeofusetariff.corrently/test/io/openems/edge/timeofusetariff/corrently/TimeOfUseTariffCorrentlyImplTest.java +++ b/io.openems.edge.timeofusetariff.corrently/test/io/openems/edge/timeofusetariff/corrently/TimeOfUseTariffCorrentlyImplTest.java @@ -12,14 +12,12 @@ public class TimeOfUseTariffCorrentlyImplTest { - private static final String CTRL_ID = "ctrl0"; - @Test public void test() throws Exception { var corrently = new TimeOfUseTariffCorrentlyImpl(); new ComponentTest(corrently) // .activate(MyConfig.create() // - .setId(CTRL_ID) // + .setId("ctrl0") // .setZipcode("94469" /* Deggendorf, Germany */) // .build()) // ; diff --git a/io.openems.edge.timeofusetariff.entsoe/test/io/openems/edge/timeofusetariff/entsoe/TouEntsoeTest.java b/io.openems.edge.timeofusetariff.entsoe/test/io/openems/edge/timeofusetariff/entsoe/TouEntsoeTest.java index 2c3098097d2..8bcea20e8ce 100644 --- a/io.openems.edge.timeofusetariff.entsoe/test/io/openems/edge/timeofusetariff/entsoe/TouEntsoeTest.java +++ b/io.openems.edge.timeofusetariff.entsoe/test/io/openems/edge/timeofusetariff/entsoe/TouEntsoeTest.java @@ -10,8 +10,6 @@ public class TouEntsoeTest { - private static final String COMPONENT_ID = "tou0"; - @Test public void test() throws Exception { var entsoe = new TouEntsoeImpl(); @@ -21,7 +19,7 @@ public void test() throws Exception { .addReference("meta", dummyMeta) // .addReference("oem", new DummyOpenemsEdgeOem()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // + .setId("tou0") // .setSecurityToken("") // .setExchangerateAccesskey("") // .setBiddingZone(BiddingZone.GERMANY) // diff --git a/io.openems.edge.timeofusetariff.groupe/test/io/openems/edge/timeofusetariff/groupe/TimeOfUseTariffGroupeImplTest.java b/io.openems.edge.timeofusetariff.groupe/test/io/openems/edge/timeofusetariff/groupe/TimeOfUseTariffGroupeImplTest.java index 8bdb01e4e1a..76e1e7fda13 100644 --- a/io.openems.edge.timeofusetariff.groupe/test/io/openems/edge/timeofusetariff/groupe/TimeOfUseTariffGroupeImplTest.java +++ b/io.openems.edge.timeofusetariff.groupe/test/io/openems/edge/timeofusetariff/groupe/TimeOfUseTariffGroupeImplTest.java @@ -1,19 +1,16 @@ package io.openems.edge.timeofusetariff.groupe; import static io.openems.edge.common.currency.Currency.CHF; +import static io.openems.edge.common.test.TestUtils.createDummyClock; import static io.openems.edge.timeofusetariff.groupe.TimeOfUseTariffGroupeImpl.parsePrices; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThrows; -import java.time.Instant; -import java.time.ZoneOffset; - import org.junit.Test; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.oem.DummyOpenemsEdgeOem; -import io.openems.common.test.TimeLeapClock; import io.openems.edge.bridge.http.dummy.DummyBridgeHttpFactory; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyComponentManager; @@ -21,7 +18,6 @@ public class TimeOfUseTariffGroupeImplTest { - private static final String CTRL_ID = "ctrl0"; private static final double GROUPE_E_EXCHANGE_RATE = 1; private static final String PRICE_RESULT_STRING = """ @@ -407,8 +403,7 @@ public class TimeOfUseTariffGroupeImplTest { @Test public void test() throws Exception { - final TimeLeapClock clock = new TimeLeapClock(Instant.parse("2020-01-01T01:00:00.00Z"), ZoneOffset.UTC); - final DummyComponentManager cm = new DummyComponentManager(clock); + final var clock = createDummyClock(); var groupe = new TimeOfUseTariffGroupeImpl(); var dummyMeta = new DummyMeta("foo0") // .withCurrency(CHF); @@ -416,9 +411,9 @@ public void test() throws Exception { .addReference("httpBridgeFactory", DummyBridgeHttpFactory.ofDummyBridge()) // .addReference("meta", dummyMeta) // .addReference("oem", new DummyOpenemsEdgeOem()) // - .addReference("componentManager", cm) // + .addReference("componentManager", new DummyComponentManager(clock)) // .activate(MyConfig.create() // - .setId(CTRL_ID) // + .setId("ctrl0") // .setExchangerateAccesskey("") // .build()) // ; diff --git a/io.openems.edge.timeofusetariff.hassfurt/test/io/openems/edge/timeofusetariff/hassfurt/TimeOfUseTariffHassfurtImplTest.java b/io.openems.edge.timeofusetariff.hassfurt/test/io/openems/edge/timeofusetariff/hassfurt/TimeOfUseTariffHassfurtImplTest.java index 2f363b27876..041b9e6ae0e 100644 --- a/io.openems.edge.timeofusetariff.hassfurt/test/io/openems/edge/timeofusetariff/hassfurt/TimeOfUseTariffHassfurtImplTest.java +++ b/io.openems.edge.timeofusetariff.hassfurt/test/io/openems/edge/timeofusetariff/hassfurt/TimeOfUseTariffHassfurtImplTest.java @@ -1,24 +1,20 @@ package io.openems.edge.timeofusetariff.hassfurt; +import static io.openems.edge.common.test.TestUtils.createDummyClock; import static io.openems.edge.timeofusetariff.hassfurt.TimeOfUseTariffHassfurtImpl.parsePrices; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThrows; -import java.time.Instant; -import java.time.ZoneOffset; - import org.junit.Test; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.test.TimeLeapClock; import io.openems.edge.bridge.http.dummy.DummyBridgeHttpFactory; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyComponentManager; public class TimeOfUseTariffHassfurtImplTest { - private static final String CTRL_ID = "ctrl0"; private static final String STROM_FLEX_PRO_STRING = """ { "object": "list", @@ -192,14 +188,12 @@ public class TimeOfUseTariffHassfurtImplTest { @Test public void test() throws Exception { - final TimeLeapClock clock = new TimeLeapClock(Instant.parse("2020-01-01T01:00:00.00Z"), ZoneOffset.UTC); - final DummyComponentManager cm = new DummyComponentManager(clock); - var hassfurt = new TimeOfUseTariffHassfurtImpl(); - new ComponentTest(hassfurt) // + final var clock = createDummyClock(); + new ComponentTest(new TimeOfUseTariffHassfurtImpl()) // .addReference("httpBridgeFactory", DummyBridgeHttpFactory.ofDummyBridge()) // - .addReference("componentManager", cm) // + .addReference("componentManager", new DummyComponentManager(clock)) // .activate(MyConfig.create() // - .setId(CTRL_ID) // + .setId("ctrl0") // .setTariffType(TariffType.STROM_FLEX) // .build()) // ; diff --git a/io.openems.edge.timeofusetariff.rabotcharge/test/io/openems/edge/timeofusetariff/rabotcharge/TimeOfUseTariffRabotChargeImplTest.java b/io.openems.edge.timeofusetariff.rabotcharge/test/io/openems/edge/timeofusetariff/rabotcharge/TimeOfUseTariffRabotChargeImplTest.java index 46c41dec126..4852a20c2d0 100644 --- a/io.openems.edge.timeofusetariff.rabotcharge/test/io/openems/edge/timeofusetariff/rabotcharge/TimeOfUseTariffRabotChargeImplTest.java +++ b/io.openems.edge.timeofusetariff.rabotcharge/test/io/openems/edge/timeofusetariff/rabotcharge/TimeOfUseTariffRabotChargeImplTest.java @@ -1,35 +1,28 @@ package io.openems.edge.timeofusetariff.rabotcharge; +import static io.openems.edge.common.test.TestUtils.createDummyClock; import static io.openems.edge.timeofusetariff.rabotcharge.TimeOfUseTariffRabotChargeImpl.parsePrices; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThrows; -import java.time.Instant; -import java.time.ZoneOffset; - import org.junit.Test; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.test.TimeLeapClock; import io.openems.edge.bridge.http.dummy.DummyBridgeHttpFactory; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyComponentManager; public class TimeOfUseTariffRabotChargeImplTest { - private static final String CTRL_ID = "ctrl0"; - @Test public void test() throws Exception { - final TimeLeapClock clock = new TimeLeapClock(Instant.parse("2020-01-01T01:00:00.00Z"), ZoneOffset.UTC); - final DummyComponentManager cm = new DummyComponentManager(clock); - var rabotCharge = new TimeOfUseTariffRabotChargeImpl(); - new ComponentTest(rabotCharge) // + final var clock = createDummyClock(); + new ComponentTest(new TimeOfUseTariffRabotChargeImpl()) // .addReference("httpBridgeFactory", DummyBridgeHttpFactory.ofDummyBridge()) // - .addReference("componentManager", cm) // + .addReference("componentManager", new DummyComponentManager(clock)) // .activate(MyConfig.create() // - .setId(CTRL_ID) // + .setId("ctrl0") // .setAccessToken("foo-bar") // .build()) // ; diff --git a/io.openems.edge.timeofusetariff.tibber/test/io/openems/edge/timeofusetariff/tibber/TimeOfUseTariffTibberImplTest.java b/io.openems.edge.timeofusetariff.tibber/test/io/openems/edge/timeofusetariff/tibber/TimeOfUseTariffTibberImplTest.java index 59f2b6a3558..7190b8a7795 100644 --- a/io.openems.edge.timeofusetariff.tibber/test/io/openems/edge/timeofusetariff/tibber/TimeOfUseTariffTibberImplTest.java +++ b/io.openems.edge.timeofusetariff.tibber/test/io/openems/edge/timeofusetariff/tibber/TimeOfUseTariffTibberImplTest.java @@ -6,14 +6,11 @@ public class TimeOfUseTariffTibberImplTest { - private static final String CTRL_ID = "ctrl0"; - @Test public void test() throws Exception { - var tibber = new TimeOfUseTariffTibberImpl(); - new ComponentTest(tibber) // + new ComponentTest(new TimeOfUseTariffTibberImpl()) // .activate(MyConfig.create() // - .setId(CTRL_ID) // + .setId("ctrl0") // .setAccessToken("foo-bar") // .setFilter("") // .build()) // diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000000..8196d1ddf2e --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "openems", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/ui/.project b/ui/.project new file mode 100644 index 00000000000..4f185983a47 --- /dev/null +++ b/ui/.project @@ -0,0 +1,11 @@ + + + fems-ui + + + + + + + + diff --git a/ui/README.md b/ui/README.md index 96ef2800acb..e5a4c386f2d 100644 --- a/ui/README.md +++ b/ui/README.md @@ -65,7 +65,9 @@ This project was generated with [angular-cli](https://github.com/angular/angular > [!IMPORTANT] > Crucial information necessary for users to succeed. Only provide /resources/logo-dark.png and logo.png * Move the files from res(except values and xml) to ```/android/app/src/$theme/``` (```/main``` acts as default) -* Build apps: `gradlew bundle{$theme}Release` +* Build apps (execute in order): + - `NODE_ENV="{$theme}" ./node_modules/.bin/ionic cap build android -c "$theme,$theme-backend-deploy-app" --no-open;` + - `THEME="{$theme}" gradlew bundleThemeRelease` Important (if not generated, can be copied and adjusted from existing theme): - `ui\android\app\src\{$theme}\res\xml\file_paths.xml` @@ -77,6 +79,7 @@ Use `gradlew install{$theme}Release to install it on any device` - Available Tasks: `gradlew tasks` - list available devices + emulators: `$npx native-run android --list --json` +- use Android Studio for Debugging: `$ionic cap open android` ## i18n - internationalization diff --git a/ui/src/app/app-routing.module.ts b/ui/src/app/app-routing.module.ts index a6324b0d68b..9aa984ea31d 100644 --- a/ui/src/app/app-routing.module.ts +++ b/ui/src/app/app-routing.module.ts @@ -16,9 +16,9 @@ import { OverviewComponent as GridOptimizedChargeChartOverviewComponent } from " import { OverviewComponent as TimeOfUseTariffOverviewComponent } from "./edge/history/Controller/Ess/TimeOfUseTariff/overview/overview"; import { DetailsOverviewComponent as DigitalOutputDetailsOverviewComponent } from "./edge/history/Controller/Io/DigitalOutput/details/details.overview"; import { OverviewComponent as DigitalOutputChartOverviewComponent } from "./edge/history/Controller/Io/DigitalOutput/overview/overview"; +import { OverviewComponent as HeatingelementChartOverviewComponent } from "./edge/history/Controller/Io/heatingelement/overview/overview"; import { OverviewComponent as ModbusTcpApiOverviewComponent } from "./edge/history/Controller/ModbusTcpApi/overview/overview"; import { DelayedSellToGridChartOverviewComponent } from "./edge/history/delayedselltogrid/symmetricpeakshavingchartoverview/delayedselltogridchartoverview.component"; -import { HeatingelementChartOverviewComponent } from "./edge/history/heatingelement/heatingelementchartoverview/heatingelementchartoverview.component"; import { HeatPumpChartOverviewComponent } from "./edge/history/heatpump/heatpumpchartoverview/heatpumpchartoverview.component"; import { HistoryComponent as EdgeHistoryComponent } from "./edge/history/history.component"; import { HistoryDataService } from "./edge/history/historydataservice"; diff --git a/ui/src/app/app.component.html b/ui/src/app/app.component.html index 80c7aa7d2a0..9b1e3b8fc02 100644 --- a/ui/src/app/app.component.html +++ b/ui/src/app/app.component.html @@ -1,4 +1,46 @@ + + + + + + + + Menu.menu + + + + + + + + + +

      {{ user.name }}

      + +

      {{ user.id }}

      +
      + + + + + + + + Menu.overview + + + + + + + + @@ -35,47 +77,7 @@

      Index.connectionFailed

      - - - - - - - Menu.menu - - - - - - - - -

      {{ user.name }}

      - -

      {{ user.id }}

      -
      -
      -
      - - - - - - Menu.overview - - - - - -
      -
      -
      diff --git a/ui/src/app/changelog/view/view.html b/ui/src/app/changelog/view/view.html index 2746d025db1..10f23e85d60 100644 --- a/ui/src/app/changelog/view/view.html +++ b/ui/src/app/changelog/view/view.html @@ -1,4 +1,3 @@ -
      diff --git a/ui/src/app/edge/history/Controller/Io/Io.module.ts b/ui/src/app/edge/history/Controller/Io/Io.module.ts index caeda2b8417..eae8ce33c7d 100644 --- a/ui/src/app/edge/history/Controller/Io/Io.module.ts +++ b/ui/src/app/edge/history/Controller/Io/Io.module.ts @@ -1,12 +1,15 @@ import { NgModule } from "@angular/core"; import { DigitalOutput } from "./DigitalOutput/digitalOutput.module"; +import { HeatingElement } from "./heatingelement/heatingelement.module"; @NgModule({ imports: [ DigitalOutput, + HeatingElement, ], exports: [ DigitalOutput, + HeatingElement, ], }) export class ControllerIo { } diff --git a/ui/src/app/edge/history/Controller/Io/heatingelement/chart/chart.ts b/ui/src/app/edge/history/Controller/Io/heatingelement/chart/chart.ts new file mode 100644 index 00000000000..4af9f3d9c88 --- /dev/null +++ b/ui/src/app/edge/history/Controller/Io/heatingelement/chart/chart.ts @@ -0,0 +1,82 @@ +// @ts-strict-ignore +import { Component } from "@angular/core"; +import { AbstractHistoryChart } from "src/app/shared/components/chart/abstracthistorychart"; +import { ChartConstants } from "src/app/shared/components/chart/chart.constants"; +import { QueryHistoricTimeseriesEnergyResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse"; +import { ChartAxis, HistoryUtils, Utils, YAxisType } from "src/app/shared/service/utils"; +import { ChannelAddress, EdgeConfig } from "src/app/shared/shared"; + +@Component({ + selector: "controller-io-heatingelement-chart", + templateUrl: "../../../../../../shared/components/chart/abstracthistorychart.html", +}) +export class ChartComponent extends AbstractHistoryChart { + public static getChartData(component: EdgeConfig.Component, phaseColors: string[], chartType: "line" | "bar"): HistoryUtils.ChartData { + + const input: HistoryUtils.InputChannel[] = [ + { name: component.id, powerChannel: new ChannelAddress(component.id, "Level") }, + ]; + + for (const level of [1, 2, 3]) { + input.push({ + name: component.id + level, + powerChannel: new ChannelAddress(component.id, "Level"), + energyChannel: new ChannelAddress(component.id, "Level" + level + "CumulatedTime"), + }); + } + + return { + input: input, + output: (data: HistoryUtils.ChannelData) => { + + const output: HistoryUtils.DisplayValue[] = []; + + if (chartType === "line") { + output.push({ + name: "Level", + converter: () => data[component.id].map(val => Utils.multiplySafely(val, 1000)), + color: ChartConstants.Colors.RED, + stack: 0, + }); + } + + if (chartType === "bar") { + for (const level of [1, 2, 3]) { + output.push({ + name: "Level " + level, + nameSuffix: (energyQueryResponse: QueryHistoricTimeseriesEnergyResponse) => + energyQueryResponse?.result.data[component.id + "/Level" + level + "CumulatedTime"] ?? null, + converter: () => data[component.id + level] + // TODO add logic to not have to adjust non power data manually + .map(val => Utils.multiplySafely(val, 1000)), + color: phaseColors[level % phaseColors.length], + stack: 0, + }); + } + } + + return output; + }, + tooltip: { + formatNumber: ChartConstants.NumberFormat.NO_DECIMALS, + }, + yAxes: [ + chartType === "line" + ? { + unit: YAxisType.LEVEL, + position: "left", + yAxisId: ChartAxis.LEFT, + } + : { + unit: YAxisType.TIME, + position: "left", + yAxisId: ChartAxis.LEFT, + }, + ], + }; + } + + protected override getChartData(): HistoryUtils.ChartData { + return ChartComponent.getChartData(this.component, AbstractHistoryChart.phaseColors, this.chartType); + } +} diff --git a/ui/src/app/edge/history/Controller/Io/heatingelement/flat/flat.html b/ui/src/app/edge/history/Controller/Io/heatingelement/flat/flat.html new file mode 100644 index 00000000000..923a442cb04 --- /dev/null +++ b/ui/src/app/edge/history/Controller/Io/heatingelement/flat/flat.html @@ -0,0 +1,8 @@ + + + + + + diff --git a/ui/src/app/edge/history/Controller/Io/heatingelement/flat/flat.ts b/ui/src/app/edge/history/Controller/Io/heatingelement/flat/flat.ts new file mode 100644 index 00000000000..677d32f0737 --- /dev/null +++ b/ui/src/app/edge/history/Controller/Io/heatingelement/flat/flat.ts @@ -0,0 +1,10 @@ +import { Component } from "@angular/core"; +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; + +@Component({ + selector: "controller-io-heatingelement-widget", + templateUrl: "./flat.html", +}) +export class FlatComponent extends AbstractFlatWidget { + protected FORMAT_SECONDS_TO_DURATION = this.Converter.FORMAT_SECONDS_TO_DURATION(this.translate.currentLang); +} diff --git a/ui/src/app/edge/history/Controller/Io/heatingelement/heatingelement.module.ts b/ui/src/app/edge/history/Controller/Io/heatingelement/heatingelement.module.ts new file mode 100644 index 00000000000..99310facb87 --- /dev/null +++ b/ui/src/app/edge/history/Controller/Io/heatingelement/heatingelement.module.ts @@ -0,0 +1,24 @@ +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"; +import { OverviewComponent } from "./overview/overview"; + +@NgModule({ + imports: [ + BrowserModule, + SharedModule, + ], + declarations: [ + ChartComponent, + FlatComponent, + OverviewComponent, + ], + exports: [ + ChartComponent, + FlatComponent, + OverviewComponent, + ], +}) +export class HeatingElement { } diff --git a/ui/src/app/edge/history/Controller/Io/heatingelement/overview/overview.html b/ui/src/app/edge/history/Controller/Io/heatingelement/overview/overview.html new file mode 100644 index 00000000000..d834e111f28 --- /dev/null +++ b/ui/src/app/edge/history/Controller/Io/heatingelement/overview/overview.html @@ -0,0 +1,4 @@ + + + + diff --git a/ui/src/app/edge/history/Controller/Io/heatingelement/overview/overview.ts b/ui/src/app/edge/history/Controller/Io/heatingelement/overview/overview.ts new file mode 100644 index 00000000000..2e52219327a --- /dev/null +++ b/ui/src/app/edge/history/Controller/Io/heatingelement/overview/overview.ts @@ -0,0 +1,8 @@ +import { Component } from "@angular/core"; +import { AbstractHistoryChartOverview } from "src/app/shared/components/chart/abstractHistoryChartOverview"; + +@Component({ + selector: "controller-io-heatingelement-overview", + templateUrl: "./overview.html", +}) +export class OverviewComponent extends AbstractHistoryChartOverview { } diff --git a/ui/src/app/edge/history/common/consumption/chart/chart.ts b/ui/src/app/edge/history/common/consumption/chart/chart.ts index bc5474bde75..001e004b59e 100644 --- a/ui/src/app/edge/history/common/consumption/chart/chart.ts +++ b/ui/src/app/edge/history/common/consumption/chart/chart.ts @@ -26,9 +26,7 @@ export class ChartComponent extends AbstractHistoryChart { component.factoryId == "Evcs.Cluster.PeakShaving" || component.factoryId == "Evcs.Cluster.SelfConsumption")); - const consumptionMeters: EdgeConfig.Component[] = config.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") - .filter(component => component.isEnabled && config.isTypeConsumptionMetered(component)); - + // TODO Since 2024.11.0 EVCS implements EletricityMeter; use DeprecatedEvcs as filter evcsComponents.forEach(component => { inputChannel.push({ name: component.id + "/ChargePower", @@ -37,6 +35,10 @@ export class ChartComponent extends AbstractHistoryChart { }); }); + const consumptionMeters: EdgeConfig.Component[] = config.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") + .filter(component => component.isEnabled && config.isTypeConsumptionMetered(component) + && !config.getNatureIdsByFactoryId(component.factoryId).includes("io.openems.edge.evcs.api.Evcs")); + consumptionMeters.forEach(meter => { inputChannel.push({ name: meter.id + "/ActivePower", diff --git a/ui/src/app/edge/history/common/consumption/flat/flat.ts b/ui/src/app/edge/history/common/consumption/flat/flat.ts index 149521db911..a862b6ad406 100644 --- a/ui/src/app/edge/history/common/consumption/flat/flat.ts +++ b/ui/src/app/edge/history/common/consumption/flat/flat.ts @@ -14,27 +14,24 @@ export class FlatComponent extends AbstractFlatWidget { protected totalOtherEnergy: number; protected override getChannelAddresses(): ChannelAddress[] { + const channels: ChannelAddress[] = [new ChannelAddress("_sum", "ConsumptionActiveEnergy")]; this.evcsComponents = this.config?.getComponentsImplementingNature("io.openems.edge.evcs.api.Evcs") .filter(component => !(component.factoryId === "Evcs.Cluster.SelfConsumption") && !(component.factoryId === "Evcs.Cluster.PeakShaving") && !component.isEnabled === false); - - this.consumptionMeterComponents = this.config?.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") - .filter(component => component.isEnabled && this.config.isTypeConsumptionMetered(component)); - - const channels: ChannelAddress[] = [new ChannelAddress("_sum", "ConsumptionActiveEnergy")]; - this.evcsComponents.forEach((component) => { channels.push(new ChannelAddress(component.id, "ActiveConsumptionEnergy")); }); + this.consumptionMeterComponents = this.config?.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") + .filter(component => component.isEnabled && this.config.isTypeConsumptionMetered(component) + && !this.config.getNatureIdsByFactoryId(component.factoryId).includes("io.openems.edge.evcs.api.Evcs")); this.consumptionMeterComponents.forEach((component) => { channels.push(new ChannelAddress(component.id, "ActiveProductionEnergy")); }); - return channels; } diff --git a/ui/src/app/edge/history/common/consumption/overview/overview.ts b/ui/src/app/edge/history/common/consumption/overview/overview.ts index cf75130de35..7ba779ea15c 100644 --- a/ui/src/app/edge/history/common/consumption/overview/overview.ts +++ b/ui/src/app/edge/history/common/consumption/overview/overview.ts @@ -34,7 +34,8 @@ export class OverviewComponent extends AbstractHistoryChartOverview { !component.isEnabled === false); this.consumptionMeterComponents = this.config?.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") - .filter(component => component.isEnabled && this.config.isTypeConsumptionMetered(component)); + .filter(component => component.isEnabled && this.config.isTypeConsumptionMetered(component) + && !this.config.getNatureIdsByFactoryId(component.factoryId).includes("io.openems.edge.evcs.api.Evcs")); const sum: EdgeConfig.Component = this.config.getComponent("_sum"); sum.alias = this.translate.instant("General.TOTAL"); 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 fe2dbeb853b..c5c12a0f2fa 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 @@ -8,7 +8,7 @@ import { QueryHistoricTimeseriesEnergyResponse } from "src/app/shared/jsonrpc/re export namespace History { - export const LINE_CHART_OPTIONS = (period: string, chartType: "line" | "bar", options: { [key: string]: { scale: { min: number, max: number; } | null, ticks: { stepSize: number }; }; }): OeChartTester.Dataset.Option => ({ + export const LINE_CHART_OPTIONS = (period: string, chartType: "line" | "bar", options: { [key: string]: { scale: { min: number, max: number; } | null, ticks?: { stepSize: number }; }; }): OeChartTester.Dataset.Option => ({ type: "option", options: { "responsive": true, "maintainAspectRatio": false, "elements": { "point": { "radius": 0, "hitRadius": 0, "hoverRadius": 0 }, "line": { "stepped": false, "fill": true } }, "datasets": { "bar": {}, "line": {} }, @@ -30,11 +30,14 @@ export namespace History { }, "scales": { "x": { "stacked": true, "offset": false, "type": "time", "ticks": { "source": "auto", "maxTicksLimit": 31 }, "bounds": "ticks", "adapters": { "date": { "locale": { "code": "de", "formatLong": {}, "localize": {}, "match": {}, "options": { "weekStartsOn": 1, "firstWeekContainsDate": 4 } } } }, "time": { "unit": period as TimeUnit, "displayFormats": { "datetime": "yyyy-MM-dd HH:mm:ss", "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" } } }, "left": { - ...options["left"]?.scale, ...(chartType === "line" ? { stacked: false } : {}), "beginAtZero": true, "title": { "text": "kW", "display": true, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, + "stacked": false, + ...options["left"]?.scale, ...(chartType === "line" ? { stacked: false } : {}), "beginAtZero": true, + "title": { "text": "kW", "display": false, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, "ticks": { ...options["left"]?.ticks, "color": "", "padding": 5, "maxTicksLimit": ChartConstants.NUMBER_OF_Y_AXIS_TICKS }, }, "right": { - ...options["right"]?.scale, ...(chartType === "line" ? { stacked: false } : {}), "beginAtZero": true, "max": 100, "min": 0, "type": "linear", "title": { "text": "%", "display": true, "font": { "size": 11 }, "padding": 5 }, "position": "right", "grid": { "display": false }, + "stacked": false, + ...options["right"]?.scale, ...(chartType === "line" ? { stacked: false } : {}), "beginAtZero": true, "type": "linear", "title": { "text": "%", "display": false, "font": { "size": 11 }, "padding": 5 }, "position": "right", "grid": { "display": false }, "ticks": { ...options["right"]?.ticks, "color": "", @@ -67,7 +70,8 @@ export namespace History { }, "scales": { "x": { "stacked": true, "offset": true, "type": "time", "ticks": { "source": "auto", "maxTicksLimit": 31 }, "bounds": "ticks", "adapters": { "date": { "locale": { "code": "de", "formatLong": {}, "localize": {}, "match": {}, "options": { "weekStartsOn": 1, "firstWeekContainsDate": 4 } } } }, "time": { "unit": period as TimeUnit, "displayFormats": { "datetime": "yyyy-MM-dd HH:mm:ss", "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" } } }, "left": { - ...options["left"]?.scale, ...(chartType === "line" ? { stacked: false } : {}), "beginAtZero": true, "title": { "text": "kWh", "display": true, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, + "stacked": true, + ...options["left"]?.scale, ...(chartType === "line" ? { stacked: false } : {}), "beginAtZero": true, "title": { "text": "kWh", "display": false, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, "ticks": { ...options["left"]?.ticks, "color": "", 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 cd1695a6c81..ecf8e88a444 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 @@ -34,7 +34,7 @@ describe("History EnergyMonitor", () => { ], labels: LABELS(History.DAY.dataChannelWithValues.result.timestamps), options: History.LINE_CHART_OPTIONS("hour", "line", { - ["right"]: { ticks: { stepSize: 20 }, scale: null }, + ["right"]: { scale: null }, }), }, }); @@ -55,7 +55,7 @@ describe("History EnergyMonitor", () => { DATA("Ladezustand", History.WEEK.dataChannelWithValues.result.data["_sum/EssSoc"]), ], labels: LABELS(History.WEEK.dataChannelWithValues.result.timestamps), - options: History.LINE_CHART_OPTIONS("day", "line", { ["right"]: { ticks: { stepSize: 20 }, scale: null } }), + options: History.LINE_CHART_OPTIONS("day", "line", { ["right"]: { scale: null } }), }, }); } diff --git a/ui/src/app/edge/history/common/grid/chart/chart.spec.ts b/ui/src/app/edge/history/common/grid/chart/chart.spec.ts index 64c0455cdf2..a52ed73cafc 100644 --- a/ui/src/app/edge/history/common/grid/chart/chart.spec.ts +++ b/ui/src/app/edge/history/common/grid/chart/chart.spec.ts @@ -51,9 +51,8 @@ describe("History Grid", () => { DATA("Bezug: 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]), ], labels: LABELS(History.DAY.dataChannelWithValues.result.timestamps), - options: OeTester.ChartOptions.MULTI_LINE_OPTIONS("hour", "line", { - ["right"]: { scale: { max: 1, min: 0 }, ticks: { stepSize: 1 } }, - }), + options: OeTester.ChartOptions.MULTI_LINE_OPTIONS("hour", "line", {}, + ), }, }, false); } @@ -67,9 +66,7 @@ describe("History Grid", () => { DATA("Bezug: 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]), ], labels: LABELS(History.WEEK.dataChannelWithValues.result.timestamps), - options: OeTester.ChartOptions.MULTI_LINE_OPTIONS("day", "line", { - ["right"]: { scale: { max: 1, min: 0 }, ticks: { stepSize: 1 } }, - }), + options: OeTester.ChartOptions.MULTI_LINE_OPTIONS("day", "line", {}), }, }, false); } @@ -83,9 +80,7 @@ describe("History Grid", () => { DATA("Bezug: 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]), ], labels: LABELS(History.MONTH.energyPerPeriodChannelWithValues.result.timestamps), - options: OeTester.ChartOptions.MULTI_BAR_OPTIONS("day", "bar", { - ["right"]: { scale: {}, ticks: { stepSize: 1 } }, - }), + options: OeTester.ChartOptions.MULTI_BAR_OPTIONS("day", "bar", {}), }, }, false); @@ -100,9 +95,7 @@ describe("History Grid", () => { DATA("Bezug: 23.209 kWh", [9829, 4812, 2915, 2036, 2712, 773, 94, null, null, null, null, null]), ], labels: LABELS(History.YEAR.energyPerPeriodChannelWithValues.result.timestamps), - options: OeTester.ChartOptions.MULTI_BAR_OPTIONS("month", "bar", { - ["right"]: { scale: {}, ticks: { stepSize: 1 } }, - }), + options: OeTester.ChartOptions.MULTI_BAR_OPTIONS("month", "bar", {}), }, }, false); } diff --git a/ui/src/app/edge/history/common/production/details/chart/productionMeter.spec.ts b/ui/src/app/edge/history/common/production/details/chart/productionMeter.spec.ts index d3cc8490cc1..6a47313a6ca 100644 --- a/ui/src/app/edge/history/common/production/details/chart/productionMeter.spec.ts +++ b/ui/src/app/edge/history/common/production/details/chart/productionMeter.spec.ts @@ -52,13 +52,6 @@ describe("History Production Details - productionMeters", () => { }); export function expectView(config: EdgeConfig, testContext: TestContext & { route: ActivatedRoute }, chartType: "line" | "bar", channels: OeTester.Types.Channels, view: OeChartTester.View): void { - sessionStorage.setItem("mapping to int", JSON.stringify(History.MONTH.energyPerPeriodChannelWithValues.result.data["meter0/ActiveProductionEnergy"].map(el => el != null ? Math.round(el) : null))); - sessionStorage.setItem("phase", JSON.stringify(OeChartTester - .apply(ProductionMeterChartDetailsComponent - .getChartData( - DummyConfig.convertDummyEdgeConfigToRealEdgeConfig(config), testContext.route, - testContext.translate), chartType, channels, testContext, config))); - expect(removeFunctions(OeChartTester .apply(ProductionMeterChartDetailsComponent .getChartData( diff --git a/ui/src/app/edge/history/heatingelement/chart.component.ts b/ui/src/app/edge/history/heatingelement/chart.component.ts deleted file mode 100644 index 49dd46bf02c..00000000000 --- a/ui/src/app/edge/history/heatingelement/chart.component.ts +++ /dev/null @@ -1,126 +0,0 @@ -// @ts-strict-ignore -import { Component, Input, OnChanges, OnDestroy, OnInit } from "@angular/core"; -import { ActivatedRoute } from "@angular/router"; -import { TranslateService } from "@ngx-translate/core"; - -import type { ChartOptions } from "chart.js"; -import { DefaultTypes } from "src/app/shared/service/defaulttypes"; -import { ChartAxis, YAxisType } from "src/app/shared/service/utils"; - -import { QueryHistoricTimeseriesDataResponse } from "../../../shared/jsonrpc/response/queryHistoricTimeseriesDataResponse"; -import { ChannelAddress, Edge, EdgeConfig, Service } from "../../../shared/shared"; -import { AbstractHistoryChart } from "../abstracthistorychart"; - -@Component({ - selector: "heatingelementChart", - templateUrl: "../abstracthistorychart.html", -}) -export class HeatingelementChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - - @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; - @Input({ required: true }) public component!: EdgeConfig.Component; - - constructor( - protected override service: Service, - protected override translate: TranslateService, - private route: ActivatedRoute, - ) { - super("heatingelement-chart", service, translate); - } - - ngOnChanges() { - this.updateChart(); - } - - ngOnInit() { - this.startSpinner(); - this.setLabel(); - } - - ngOnDestroy() { - this.unsubscribeChartRefresh(); - } - - public getChartHeight(): number { - return window.innerHeight / 1.3; - } - - protected updateChart() { - this.autoSubscribeChartRefresh(); - this.startSpinner(); - this.colors = []; - this.loading = true; - this.queryHistoricTimeseriesData(this.period.from, this.period.to).then(response => { - this.service.getCurrentEdge().then(() => { - const result = (response as QueryHistoricTimeseriesDataResponse).result; - // convert labels - const labels: Date[] = []; - for (const timestamp of result.timestamps) { - labels.push(new Date(timestamp)); - } - this.labels = labels; - - // convert datasets - const datasets = []; - const level = this.component.id + "/Level"; - - if (level in result.data) { - const levelData = result.data[level].map(value => { - if (value == null) { - return null; - } else { - return value; - } - }); - datasets.push({ - label: "Level", - data: levelData, - }); - this.colors.push({ - backgroundColor: "rgba(200,0,0,0.05)", - borderColor: "rgba(200,0,0,1)", - }); - } - this.datasets = datasets; - this.loading = false; - this.stopSpinner(); - - }).catch(reason => { - console.error(reason); // TODO error message - this.initializeChart(); - return; - }); - - }).catch(reason => { - console.error(reason); // TODO error message - this.initializeChart(); - return; - }).finally(async () => { - this.formatNumber = "1.0-1"; - this.unit = YAxisType.NONE; - await this.setOptions(this.options); - this.applyControllerSpecificOptions(this.options); - }); - } - - protected getChannelAddresses(edge: Edge, config: EdgeConfig): Promise { - return new Promise((resolve) => { - const levels = new ChannelAddress(this.component.id, "Level"); - const channeladdresses = [levels]; - resolve(channeladdresses); - }); - } - - protected applyControllerSpecificOptions(options: ChartOptions) { - options.scales[ChartAxis.LEFT]["title"].text = "Level"; - options.scales[ChartAxis.LEFT]["beginAtZero"] = true; - options.scales[ChartAxis.LEFT].max = 3; - options.scales[ChartAxis.LEFT].ticks["stepSize"] = 1; - this.options = options; - } - - protected setLabel() { - this.options = this.createDefaultChartOptions(); - } - -} diff --git a/ui/src/app/edge/history/heatingelement/heatingelementchartoverview/heatingelementchartoverview.component.html b/ui/src/app/edge/history/heatingelement/heatingelementchartoverview/heatingelementchartoverview.component.html deleted file mode 100644 index 9b116e552fb..00000000000 --- a/ui/src/app/edge/history/heatingelement/heatingelementchartoverview/heatingelementchartoverview.component.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - {{ component.alias }} - - - - - - - - - - - - - - - - - - - diff --git a/ui/src/app/edge/history/heatingelement/heatingelementchartoverview/heatingelementchartoverview.component.ts b/ui/src/app/edge/history/heatingelement/heatingelementchartoverview/heatingelementchartoverview.component.ts deleted file mode 100644 index f615818d7c3..00000000000 --- a/ui/src/app/edge/history/heatingelement/heatingelementchartoverview/heatingelementchartoverview.component.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Component, OnInit } from "@angular/core"; -import { ActivatedRoute } from "@angular/router"; -import { Edge, EdgeConfig, Service } from "../../../../shared/shared"; - -@Component({ - selector: HeatingelementChartOverviewComponent.SELECTOR, - templateUrl: "./heatingelementchartoverview.component.html", -}) -export class HeatingelementChartOverviewComponent implements OnInit { - - private static readonly SELECTOR = "heatingelement-chart-overview"; - public edge: Edge | null = null; - public component: EdgeConfig.Component | null = null; - - constructor( - public service: Service, - private route: ActivatedRoute, - ) { } - - ngOnInit() { - this.service.getCurrentEdge().then(edge => { - this.service.getConfig().then(config => { - this.component = config.getComponent(this.route.snapshot.params.componentId); - this.service.getConfig().then(config => { - this.edge = edge; - this.component = config.getComponent(this.route.snapshot.params.componentId); - }); - }); - }); - } -} diff --git a/ui/src/app/edge/history/heatingelement/widget.component.html b/ui/src/app/edge/history/heatingelement/widget.component.html deleted file mode 100644 index 49b50bff319..00000000000 --- a/ui/src/app/edge/history/heatingelement/widget.component.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - {{ component.alias }} - - - - -
    37. + -   {{ displayValue }} + {{displayName ? displayName + ": " + displayValue: '  ' + + displayValue}}
      - {{ name }} + {{ displayName }} + {{ displayValue }}
      - - - - - - - - - - - - -
      - Edge.History.activeDuration Level 1 - - {{ activeTimeOverPeriodLevel1 | formatSecondsToDuration }} -
      - Edge.History.activeDuration Level 2 - - {{ activeTimeOverPeriodLevel2 | formatSecondsToDuration }} -
      - Edge.History.activeDuration Level 3 - {{ activeTimeOverPeriodLevel3 | formatSecondsToDuration }} -
      - -
      -
      - diff --git a/ui/src/app/edge/history/heatingelement/widget.component.ts b/ui/src/app/edge/history/heatingelement/widget.component.ts deleted file mode 100644 index 262c025d23c..00000000000 --- a/ui/src/app/edge/history/heatingelement/widget.component.ts +++ /dev/null @@ -1,77 +0,0 @@ -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"; - -@Component({ - selector: HeatingelementWidgetComponent.SELECTOR, - templateUrl: "./widget.component.html", -}) -export class HeatingelementWidgetComponent extends AbstractHistoryWidget implements OnInit, OnChanges, OnDestroy { - - private static readonly SELECTOR = "heatingelementWidget"; - @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; - @Input({ required: true }) public componentId!: string; - - - public component: EdgeConfig.Component | null = null; - - public activeTimeOverPeriodLevel1: number | null = null; - public activeTimeOverPeriodLevel2: number | null = null; - public activeTimeOverPeriodLevel3: number | null = null; - - public edge: Edge | null = null; - - constructor( - public override service: Service, - private route: ActivatedRoute, - ) { - super(service); - } - - ngOnInit() { - this.service.getCurrentEdge().then(edge => { - this.edge = edge; - this.service.getConfig().then(config => { - this.component = config.getComponent(this.componentId); - }); - }); - } - - ngOnDestroy() { - this.unsubscribeWidgetRefresh(); - } - - ngOnChanges() { - this.updateValues(); - } - - public getCumulativeValue(channeladdress: string, response: QueryHistoricTimeseriesDataResponse) { - const array = response.result.data[channeladdress]; - const firstValue = array.find(el => el != null) ?? 0; - const lastValue = array.slice().reverse().find(el => el != null) ?? 0; - return lastValue - firstValue; - } - - protected updateValues() { - this.queryHistoricTimeseriesData(this.service.historyPeriod.value.from, this.service.historyPeriod.value.to).then(response => { - this.activeTimeOverPeriodLevel1 = this.getCumulativeValue(this.componentId + "/Level1CumulatedTime", response); - this.activeTimeOverPeriodLevel2 = this.getCumulativeValue(this.componentId + "/Level2CumulatedTime", response); - this.activeTimeOverPeriodLevel3 = this.getCumulativeValue(this.componentId + "/Level3CumulatedTime", response); - }); - } - - protected getChannelAddresses(edge: Edge, config: EdgeConfig): Promise { - return new Promise((resolve) => { - const channeladdresses = [ - new ChannelAddress(this.componentId, "Level1CumulatedTime"), - new ChannelAddress(this.componentId, "Level2CumulatedTime"), - new ChannelAddress(this.componentId, "Level3CumulatedTime"), - ]; - resolve(channeladdresses); - }); - } -} diff --git a/ui/src/app/edge/history/history.component.html b/ui/src/app/edge/history/history.component.html index 0b7e40f54f2..45655fbc05e 100644 --- a/ui/src/app/edge/history/history.component.html +++ b/ui/src/app/edge/history/history.component.html @@ -1,4 +1,3 @@ -
      @@ -85,8 +84,8 @@
      - - + + diff --git a/ui/src/app/edge/history/history.component.ts b/ui/src/app/edge/history/history.component.ts index e2349530d0d..1e872a6bca5 100644 --- a/ui/src/app/edge/history/history.component.ts +++ b/ui/src/app/edge/history/history.component.ts @@ -1,9 +1,8 @@ // @ts-strict-ignore -import { Component, OnInit, ViewChild } from "@angular/core"; +import { Component, OnInit } from "@angular/core"; import { ActivatedRoute } from "@angular/router"; import { TranslateService } from "@ngx-translate/core"; import { AppService } from "src/app/app.service"; -import { HeaderComponent } from "src/app/shared/components/header/header.component"; import { JsonrpcResponseError } from "src/app/shared/jsonrpc/base"; import { Edge, EdgeConfig, EdgePermission, Service, Widgets } from "src/app/shared/shared"; import { environment } from "src/environments"; @@ -14,8 +13,6 @@ import { environment } from "src/environments"; }) export class HistoryComponent implements OnInit { - @ViewChild(HeaderComponent, { static: false }) public HeaderComponent: HeaderComponent; - // is a Timedata service available, i.e. can historic data be queried. public isTimedataAvailable: boolean = true; @@ -65,12 +62,6 @@ export class HistoryComponent implements OnInit { }); } - // checks arrows when ChartPage is closed - // double viewchild is used to prevent undefined state of PickDateComponent - ionViewDidEnter() { - this.HeaderComponent.PickDateComponent.checkArrowAutomaticForwarding(); - } - updateOnWindowResize() { const ref = /* fix proportions */ Math.min(window.innerHeight - 150, /* handle grid breakpoints */(window.innerWidth < 768 ? window.innerWidth - 150 : window.innerWidth - 400)); diff --git a/ui/src/app/edge/history/history.module.ts b/ui/src/app/edge/history/history.module.ts index 9d45b5ba2df..0c0fd1d6c06 100644 --- a/ui/src/app/edge/history/history.module.ts +++ b/ui/src/app/edge/history/history.module.ts @@ -1,6 +1,5 @@ import { NgModule } from "@angular/core"; import { HistoryDataErrorModule } from "src/app/shared/components/history-data-error/history-data-error.module"; - import { SharedModule } from "../../shared/shared.module"; import { ChpSocChartComponent } from "./chpsoc/chart.component"; import { ChpSocWidgetComponent } from "./chpsoc/widget.component"; @@ -9,9 +8,6 @@ import { Controller } from "./Controller/controller.module"; import { DelayedSellToGridChartComponent } from "./delayedselltogrid/chart.component"; import { DelayedSellToGridChartOverviewComponent } from "./delayedselltogrid/symmetricpeakshavingchartoverview/delayedselltogridchartoverview.component"; import { DelayedSellToGridWidgetComponent } from "./delayedselltogrid/widget.component"; -import { HeatingelementChartComponent } from "./heatingelement/chart.component"; -import { HeatingelementChartOverviewComponent } from "./heatingelement/heatingelementchartoverview/heatingelementchartoverview.component"; -import { HeatingelementWidgetComponent } from "./heatingelement/widget.component"; import { HeatPumpChartComponent } from "./heatpump/chart.component"; import { HeatPumpChartOverviewComponent } from "./heatpump/heatpumpchartoverview/heatpumpchartoverview.component"; import { HeatpumpWidgetComponent } from "./heatpump/widget.component"; @@ -36,10 +32,10 @@ import { StorageComponent } from "./storage/widget.component"; @NgModule({ imports: [ - SharedModule, Common, Controller, HistoryDataErrorModule, + SharedModule, ], declarations: [ AsymmetricPeakshavingChartComponent, @@ -50,13 +46,11 @@ import { StorageComponent } from "./storage/widget.component"; DelayedSellToGridChartComponent, DelayedSellToGridChartOverviewComponent, DelayedSellToGridWidgetComponent, - HeatingelementChartComponent, - HeatingelementChartOverviewComponent, - HeatingelementWidgetComponent, HeatPumpChartComponent, HeatPumpChartOverviewComponent, HeatpumpWidgetComponent, HistoryComponent, + HistoryParentComponent, SocStorageChartComponent, StorageChargerChartComponent, StorageChartOverviewComponent, @@ -70,7 +64,6 @@ import { StorageComponent } from "./storage/widget.component"; TimeslotPeakshavingChartComponent, TimeslotPeakshavingChartOverviewComponent, TimeslotPeakshavingWidgetComponent, - HistoryParentComponent, ], }) export class HistoryModule { } 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 85b0069083f..58c13f96316 100644 --- a/ui/src/app/edge/live/common/consumption/flat/flat.ts +++ b/ui/src/app/edge/live/common/consumption/flat/flat.ts @@ -50,8 +50,11 @@ export class FlatComponent extends AbstractFlatWidget { // Get EVCSs this.evcss = this.config.getComponentsImplementingNature("io.openems.edge.evcs.api.Evcs") - .filter(component => !(component.factoryId == "Evcs.Cluster.SelfConsumption") && - !(component.factoryId == "Evcs.Cluster.PeakShaving") && !component.isEnabled == false); + .filter(component => + !(component.factoryId == "Evcs.Cluster.SelfConsumption") && + !(component.factoryId == "Evcs.Cluster.PeakShaving") && + !(this.config.factories[component.factoryId].natureIds.includes("io.openems.edge.meter.api.ElectricityMeter")) && + !component.isEnabled == false); for (const component of this.evcss) { channelAddresses.push( diff --git a/ui/src/app/edge/live/common/consumption/modal/modal.ts b/ui/src/app/edge/live/common/consumption/modal/modal.ts index ccdcd9af819..a228215317f 100644 --- a/ui/src/app/edge/live/common/consumption/modal/modal.ts +++ b/ui/src/app/edge/live/common/consumption/modal/modal.ts @@ -16,8 +16,11 @@ export class ModalComponent extends AbstractFormlyComponent { public static generateView(config: EdgeConfig, translate: TranslateService): OeFormlyView { const evcss: EdgeConfig.Component[] | null = config.getComponentsImplementingNature("io.openems.edge.evcs.api.Evcs") - .filter(component => !(component.factoryId == "Evcs.Cluster.SelfConsumption") && - !(component.factoryId == "Evcs.Cluster.PeakShaving") && !component.isEnabled == false); + .filter(component => + !(component.factoryId == "Evcs.Cluster.SelfConsumption") && + !(component.factoryId == "Evcs.Cluster.PeakShaving") && + !(config.factories[component.factoryId].natureIds.includes("io.openems.edge.meter.api.ElectricityMeter")) && + !component.isEnabled == false); const consumptionMeters: EdgeConfig.Component[] | null = config.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") .filter(component => component.isEnabled && config.isTypeConsumptionMetered(component)); diff --git a/ui/src/app/edge/live/live.component.html b/ui/src/app/edge/live/live.component.html index 88a68dd2777..9d4cf55d172 100644 --- a/ui/src/app/edge/live/live.component.html +++ b/ui/src/app/edge/live/live.component.html @@ -1,4 +1,3 @@ -
      diff --git a/ui/src/app/edge/settings/alerting/alerting.component.html b/ui/src/app/edge/settings/alerting/alerting.component.html index 0177269976c..f674bd30749 100644 --- a/ui/src/app/edge/settings/alerting/alerting.component.html +++ b/ui/src/app/edge/settings/alerting/alerting.component.html @@ -6,7 +6,7 @@ vertical-align: middle; } -
      + diff --git a/ui/src/app/edge/settings/app/index.component.html b/ui/src/app/edge/settings/app/index.component.html index 48926c47bdf..fd010aeac6a 100644 --- a/ui/src/app/edge/settings/app/index.component.html +++ b/ui/src/app/edge/settings/app/index.component.html @@ -61,7 +61,7 @@

      -
      + diff --git a/ui/src/app/edge/settings/app/install.component.html b/ui/src/app/edge/settings/app/install.component.html index 2418d652e3a..b9fe99c5215 100644 --- a/ui/src/app/edge/settings/app/install.component.html +++ b/ui/src/app/edge/settings/app/install.component.html @@ -1,4 +1,3 @@ -
      diff --git a/ui/src/app/edge/settings/app/single.component.html b/ui/src/app/edge/settings/app/single.component.html index 465413bd056..3896e3aa39c 100644 --- a/ui/src/app/edge/settings/app/single.component.html +++ b/ui/src/app/edge/settings/app/single.component.html @@ -1,4 +1,3 @@ -
      diff --git a/ui/src/app/edge/settings/app/update.component.html b/ui/src/app/edge/settings/app/update.component.html index 039d79b1826..e336e7124de 100644 --- a/ui/src/app/edge/settings/app/update.component.html +++ b/ui/src/app/edge/settings/app/update.component.html @@ -1,4 +1,3 @@ -
      diff --git a/ui/src/app/edge/settings/channels/channels.component.html b/ui/src/app/edge/settings/channels/channels.component.html index ecef95c38f1..c0931184525 100644 --- a/ui/src/app/edge/settings/channels/channels.component.html +++ b/ui/src/app/edge/settings/channels/channels.component.html @@ -1,4 +1,3 @@ -
      diff --git a/ui/src/app/edge/settings/component/install/index.component.html b/ui/src/app/edge/settings/component/install/index.component.html index c918b508485..bf72bc8faba 100644 --- a/ui/src/app/edge/settings/component/install/index.component.html +++ b/ui/src/app/edge/settings/component/install/index.component.html @@ -1,4 +1,3 @@ -
      diff --git a/ui/src/app/edge/settings/component/install/install.component.html b/ui/src/app/edge/settings/component/install/install.component.html index ae3916b1def..39bd2dfbb1a 100644 --- a/ui/src/app/edge/settings/component/install/install.component.html +++ b/ui/src/app/edge/settings/component/install/install.component.html @@ -1,4 +1,3 @@ -
      diff --git a/ui/src/app/edge/settings/component/update/index.component.html b/ui/src/app/edge/settings/component/update/index.component.html index 30373db23e2..2cd3b5e7223 100644 --- a/ui/src/app/edge/settings/component/update/index.component.html +++ b/ui/src/app/edge/settings/component/update/index.component.html @@ -1,4 +1,3 @@ -
      diff --git a/ui/src/app/edge/settings/component/update/update.component.html b/ui/src/app/edge/settings/component/update/update.component.html index aeaee6f0114..793ad16cfed 100644 --- a/ui/src/app/edge/settings/component/update/update.component.html +++ b/ui/src/app/edge/settings/component/update/update.component.html @@ -1,4 +1,3 @@ -
      diff --git a/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.html b/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.html index 0468ec0c4d5..9359068039c 100644 --- a/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.html +++ b/ui/src/app/edge/settings/jsonrpctest/jsonrpctest.html @@ -31,7 +31,6 @@
      -
      diff --git a/ui/src/app/edge/settings/network/network.component.html b/ui/src/app/edge/settings/network/network.component.html index aaae39ad4ae..1526c04e99c 100644 --- a/ui/src/app/edge/settings/network/network.component.html +++ b/ui/src/app/edge/settings/network/network.component.html @@ -1,4 +1,3 @@ -
      diff --git a/ui/src/app/edge/settings/powerassistant/powerassistant.html b/ui/src/app/edge/settings/powerassistant/powerassistant.html index 8fdb3666116..e428d16d831 100644 --- a/ui/src/app/edge/settings/powerassistant/powerassistant.html +++ b/ui/src/app/edge/settings/powerassistant/powerassistant.html @@ -7,7 +7,7 @@ -
      + diff --git a/ui/src/app/edge/settings/profile/aliasupdate.component.html b/ui/src/app/edge/settings/profile/aliasupdate.component.html index 1e63df550f6..47efa868cca 100644 --- a/ui/src/app/edge/settings/profile/aliasupdate.component.html +++ b/ui/src/app/edge/settings/profile/aliasupdate.component.html @@ -1,4 +1,3 @@ -
      diff --git a/ui/src/app/edge/settings/profile/profile.component.html b/ui/src/app/edge/settings/profile/profile.component.html index a5adddc50c3..2e9b3884104 100644 --- a/ui/src/app/edge/settings/profile/profile.component.html +++ b/ui/src/app/edge/settings/profile/profile.component.html @@ -1,4 +1,3 @@ -
      diff --git a/ui/src/app/edge/settings/settings.component.html b/ui/src/app/edge/settings/settings.component.html index abfdf9a2a04..4c22db2268f 100644 --- a/ui/src/app/edge/settings/settings.component.html +++ b/ui/src/app/edge/settings/settings.component.html @@ -1,4 +1,3 @@ -
      diff --git a/ui/src/app/edge/settings/settings.module.ts b/ui/src/app/edge/settings/settings.module.ts index 3e12f05e109..0f252dc9277 100644 --- a/ui/src/app/edge/settings/settings.module.ts +++ b/ui/src/app/edge/settings/settings.module.ts @@ -1,6 +1,5 @@ import { NgModule } from "@angular/core"; import { ChangelogModule } from "src/app/changelog/changelog.module"; - import { SharedModule } from "./../../shared/shared.module"; import { AlertingComponent } from "./alerting/alerting.component"; import { AppModule } from "./app/app.module"; diff --git a/ui/src/app/edge/settings/system/system.component.html b/ui/src/app/edge/settings/system/system.component.html index fb00b72fee6..154e66467b4 100644 --- a/ui/src/app/edge/settings/system/system.component.html +++ b/ui/src/app/edge/settings/system/system.component.html @@ -1,4 +1,3 @@ -
      diff --git a/ui/src/app/edge/settings/systemexecute/systemexecute.component.html b/ui/src/app/edge/settings/systemexecute/systemexecute.component.html index c22504d89c5..82cf2b8c0f7 100644 --- a/ui/src/app/edge/settings/systemexecute/systemexecute.component.html +++ b/ui/src/app/edge/settings/systemexecute/systemexecute.component.html @@ -1,4 +1,3 @@ -
      diff --git a/ui/src/app/edge/settings/systemlog/systemlog.component.html b/ui/src/app/edge/settings/systemlog/systemlog.component.html index 37919bc7547..9acbac2f1da 100644 --- a/ui/src/app/edge/settings/systemlog/systemlog.component.html +++ b/ui/src/app/edge/settings/systemlog/systemlog.component.html @@ -1,4 +1,3 @@ -
      diff --git a/ui/src/app/index/login.component.ts b/ui/src/app/index/login.component.ts index 7b2f876f623..63b7077c7e7 100644 --- a/ui/src/app/index/login.component.ts +++ b/ui/src/app/index/login.component.ts @@ -3,6 +3,7 @@ import { AfterContentChecked, ChangeDetectorRef, Component, OnDestroy, OnInit } import { FormGroup } from "@angular/forms"; import { ActivatedRoute, Router } from "@angular/router"; import { Capacitor } from "@capacitor/core"; +import { ViewWillEnter } from "@ionic/angular"; import { Subject } from "rxjs"; import { environment } from "src/environments"; @@ -15,7 +16,7 @@ import { Edge, Service, Utils, Websocket } from "../shared/shared"; selector: "login", templateUrl: "./login.component.html", }) -export class LoginComponent implements OnInit, AfterContentChecked, OnDestroy { +export class LoginComponent implements ViewWillEnter, AfterContentChecked, OnDestroy, OnInit { public environment = environment; public form: FormGroup; protected formIsDisabled: boolean = false; @@ -53,18 +54,16 @@ export class LoginComponent implements OnInit, AfterContentChecked, OnDestroy { } ngOnInit() { - - // TODO add websocket status observable const interval = setInterval(() => { - if (this.websocket.status === "online") { + if (this.websocket.status === "online" && !this.router.url.split("/").includes("live")) { this.router.navigate(["/overview"]); clearInterval(interval); } }, 1000); } - async ionViewWillEnter() { + async ionViewWillEnter() { // Execute Login-Request if url path matches 'demo' if (this.route.snapshot.routeConfig.path == "demo") { @@ -107,7 +106,7 @@ export class LoginComponent implements OnInit, AfterContentChecked, OnDestroy { .finally(() => { // Unclean - this.ngOnInit(); + this.ionViewWillEnter(); this.formIsDisabled = false; }); } diff --git a/ui/src/app/index/overview/overview.component.html b/ui/src/app/index/overview/overview.component.html index e1a0fa4e05d..e4c411d6833 100644 --- a/ui/src/app/index/overview/overview.component.html +++ b/ui/src/app/index/overview/overview.component.html @@ -1,4 +1,3 @@ -
      diff --git a/ui/src/app/index/overview/overview.component.ts b/ui/src/app/index/overview/overview.component.ts index f8a129eaa3a..8f885578816 100644 --- a/ui/src/app/index/overview/overview.component.ts +++ b/ui/src/app/index/overview/overview.component.ts @@ -1,8 +1,8 @@ // @ts-strict-ignore -import { Component, OnDestroy, OnInit } from "@angular/core"; +import { Component, OnDestroy } from "@angular/core"; import { FormGroup } from "@angular/forms"; import { ActivatedRoute, Router } from "@angular/router"; -import { InfiniteScrollCustomEvent } from "@ionic/angular"; +import { InfiniteScrollCustomEvent, ViewWillEnter } from "@ionic/angular"; import { TranslateService } from "@ngx-translate/core"; import { Subject } from "rxjs"; import { filter, take } from "rxjs/operators"; @@ -10,14 +10,13 @@ import { Pagination } from "src/app/shared/service/pagination"; import { Edge, Service, Utils, Websocket } from "src/app/shared/shared"; import { Role } from "src/app/shared/type/role"; import { environment } from "src/environments"; - import { ChosenFilter } from "../filter/filter.component"; @Component({ selector: "overview", templateUrl: "./overview.component.html", }) -export class OverViewComponent implements OnInit, OnDestroy { +export class OverViewComponent implements ViewWillEnter, OnDestroy { public environment = environment; /** True, if there is no access to any Edge. */ public noEdges: boolean = false; @@ -50,7 +49,7 @@ export class OverViewComponent implements OnInit, OnDestroy { public pagination: Pagination, ) { } - ngOnInit() { + ionViewWillEnter() { this.page = 0; this.filteredEdges = []; this.limitReached = false; @@ -139,7 +138,6 @@ export class OverViewComponent implements OnInit, OnDestroy { take(1), ) .subscribe(metadata => { - const edgeIds = Object.keys(metadata.edges); this.noEdges = edgeIds.length === 0; this.loggedInUserCanInstall = Role.isAtLeast(metadata.user.globalRole, "installer"); diff --git a/ui/src/app/shared/components/chart/abstracthistorychart.ts b/ui/src/app/shared/components/chart/abstracthistorychart.ts index 3fdc02b231b..b7610c4f5ea 100644 --- a/ui/src/app/shared/components/chart/abstracthistorychart.ts +++ b/ui/src/app/shared/components/chart/abstracthistorychart.ts @@ -405,6 +405,7 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { }; }; + options.plugins.legend.labels.generateLabels = function (chart: Chart.Chart) { const chartLegendLabelItems: Chart.LegendItem[] = []; @@ -467,9 +468,16 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { options.plugins.tooltip.enabled = chartObject.tooltip.enabled ?? true; // Remove duplicates from legend, if legendItem with two or more occurrences in legend, use one legendItem to trigger them both - options.plugins.legend.onClick = function (event: Chart.ChartEvent, legendItem: Chart.LegendItem, legend) { + options.plugins.legend.onClick = function (event: Chart.ChartEvent, legendItem: Chart.LegendItem, legend: Chart.LegendElement) { const chart: Chart.Chart = this.chart; + function rebuildScales(chart: Chart.Chart) { + let options = chart.options; + chartObject.yAxes.forEach((element) => { + options = AbstractHistoryChart.getYAxisOptions(options, element, translate, chartType, locale, _dataSets, showYAxisType); + }); + } + const legendItems = chart.data.datasets.reduce((arr, ds, i) => { if (ds.label == legendItem.text) { arr.push({ label: ds.label, index: i }); @@ -485,10 +493,19 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { meta.hidden = meta.hidden === null ? !chart.data.datasets[item.index].hidden : null; }); - // We hid a dataset ... rerender the chart + /** needs to be set, cause property async set */ + const _dataSets: Chart.ChartDataset[] = datasets.map((v, k) => { + if (k === legendItem.datasetIndex) { + v.hidden = !v.hidden; + } + return v; + }); + + rebuildScales(chart); chart.update(); }; + options.scales.x.ticks["source"] = "auto"; options.scales.x.ticks.maxTicksLimit = 31; options.scales.x["bounds"] = "ticks"; @@ -511,9 +528,7 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { public static getYAxisOptions(options: Chart.ChartOptions, element: HistoryUtils.yAxes, translate: TranslateService, chartType: "line" | "bar", locale: string, datasets: Chart.ChartDataset[], showYAxisType?: boolean): Chart.ChartOptions { const baseConfig = ChartConstants.DEFAULT_Y_SCALE_OPTIONS(element, translate, chartType, datasets, showYAxisType); - switch (element.unit) { - case YAxisType.RELAY: options.scales[element.yAxisId] = { ...baseConfig, @@ -524,7 +539,7 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { ...baseConfig.ticks, stepSize: 1, // Two states are possible - callback: function (value, index, ticks) { + callback: function (value, index, ticks: Chart.Tick[]) { return Converter.ON_OFF(translate)(value); }, padding: 5, @@ -562,6 +577,18 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { }, }; break; + case YAxisType.LEVEL: + options.scales[element.yAxisId] = { + ...baseConfig, + min: 0, + max: 3, + beginAtZero: true, + ticks: { + ...baseConfig.ticks, + stepSize: 1, + }, + }; + break; case YAxisType.VOLTAGE: case YAxisType.CURRENT: options.scales[element.yAxisId] = { diff --git a/ui/src/app/shared/components/chart/chart.constants.spec.ts b/ui/src/app/shared/components/chart/chart.constants.spec.ts index 2e38cb4cbe7..3687e1d71fb 100644 --- a/ui/src/app/shared/components/chart/chart.constants.spec.ts +++ b/ui/src/app/shared/components/chart/chart.constants.spec.ts @@ -7,9 +7,9 @@ import { ChartConstants } from "./chart.constants"; describe("Chart constants", () => { it("#calculateStepSize", () => { - expect(ChartConstants.calculateStepSize(0, 10)).toEqual(2.5); + expect(ChartConstants.calculateStepSize(0, 10)).toEqual(2); expect(ChartConstants.calculateStepSize(0, null)).toEqual(null); - expect(ChartConstants.calculateStepSize(-10, 0)).toEqual(2.5); + expect(ChartConstants.calculateStepSize(-10, 0)).toEqual(2); expect(ChartConstants.calculateStepSize(undefined, 0)).toEqual(null); // min higher than max @@ -26,9 +26,9 @@ describe("Chart constants", () => { }, ]; - expect(ChartConstants.getScaleOptions([], yAxis)).toEqual({ min: null, max: null, stepSize: null }); - expect(ChartConstants.getScaleOptions(datasets, yAxis)).toEqual({ min: 0, max: 1892, stepSize: 473 }); - expect(ChartConstants.getScaleOptions(null, yAxis)).toEqual(null); - expect(ChartConstants.getScaleOptions(null, null)).toEqual(null); + expect(ChartConstants.getScaleOptions([], yAxis, "line")).toEqual({ min: null, max: null, stepSize: null }); + expect(ChartConstants.getScaleOptions(datasets, yAxis, "line")).toEqual({ min: 0, max: 1892, stepSize: 378.4 }); + expect(ChartConstants.getScaleOptions(null, yAxis, "line")).toEqual({ min: null, max: null, stepSize: null }); + expect(ChartConstants.getScaleOptions(null, null, "line")).toEqual({ min: null, max: null, stepSize: null }); }); }); diff --git a/ui/src/app/shared/components/chart/chart.constants.ts b/ui/src/app/shared/components/chart/chart.constants.ts index 2adc960c541..acae3146c98 100644 --- a/ui/src/app/shared/components/chart/chart.constants.ts +++ b/ui/src/app/shared/components/chart/chart.constants.ts @@ -1,16 +1,16 @@ // @ts-strict-ignore - import { formatNumber } from "@angular/common"; import { TranslateService } from "@ngx-translate/core"; import { ChartComponentLike, ChartDataset } from "chart.js"; import ChartDataLabels from "chartjs-plugin-datalabels"; +import { RGBColor } from "../../service/defaulttypes"; import { HistoryUtils, Utils } from "../../service/utils"; import { Language } from "../../type/language"; import { ArrayUtils } from "../../utils/array/array.utils"; import { AbstractHistoryChart } from "./abstracthistorychart"; export class ChartConstants { - public static readonly NUMBER_OF_Y_AXIS_TICKS: number = 6; + public static readonly NUMBER_OF_Y_AXIS_TICKS: number = 7; public static readonly EMPTY_DATASETS: ChartDataset[] = []; public static readonly REQUEST_TIMEOUT = 500; @@ -43,7 +43,7 @@ export class ChartConstants { ...ChartDataLabels, formatter: (value, ctx) => { const locale: string = (Language.getByKey(localStorage.LANGUAGE) ?? Language.DEFAULT).i18nLocaleKey; - return formatNumber(value, locale, "1.0-0") + "\xa0" + unit ?? null; + return formatNumber(value, locale, "1.0-0") + "\xa0" + unit; }, ...{ anchor: "end", offset: -18, align: "start", clip: false, clamp: true, @@ -53,6 +53,14 @@ export class ChartConstants { }); }; + public static Colors = class { + public static RED: string = new RGBColor(200, 0, 0).toString(); + }; + + public static readonly NumberFormat = class { + public static NO_DECIMALS: string = "1.0-0"; + }; + /** * Default yScale CartesianScaleTypeRegistry.linear * @@ -64,25 +72,36 @@ export class ChartConstants { */ public static DEFAULT_Y_SCALE_OPTIONS = (element: HistoryUtils.yAxes, translate: TranslateService, chartType: "line" | "bar", datasets: ChartDataset[], showYAxisTitle?: boolean) => { const beginAtZero: boolean = ChartConstants.isDataSeriesPositive(datasets); + const scaleOptions: ReturnType = this.getScaleOptions(datasets, element, chartType); return { title: { text: element.customTitle ?? AbstractHistoryChart.getYAxisType(element.unit, translate, chartType), - display: showYAxisTitle, + display: false, padding: 5, font: { size: 11, }, }, + stacked: chartType === "line" ? false : true, beginAtZero: beginAtZero, position: element.position, grid: { display: element.displayGrid ?? true, }, + ...(scaleOptions?.min !== null && { min: scaleOptions.min }), + ...(scaleOptions?.max !== null && { max: scaleOptions.max }), ticks: { color: getComputedStyle(document.documentElement).getPropertyValue("--ion-color-text"), padding: 5, maxTicksLimit: ChartConstants.NUMBER_OF_Y_AXIS_TICKS, + ...(scaleOptions?.stepSize && { stepSize: scaleOptions.stepSize }), + callback: function (value, index, ticks) { + if (index == (ticks.length - 1) && showYAxisTitle) { + return element.customTitle ?? AbstractHistoryChart.getYAxisType(element.unit, translate, chartType); + } + return value; + }, }, }; }; @@ -94,10 +113,35 @@ export class ChartConstants { * @param yAxis the yAxis * @returns min, max and stepsize for datasets belonging to this yAxis */ - public static getScaleOptions(datasets: ChartDataset[], yAxis: HistoryUtils.yAxes): { min: number; max: number; stepSize: number; } | null { + public static getScaleOptions(datasets: ChartDataset[], yAxis: HistoryUtils.yAxes, chartType: "line" | "bar"): { min: number; max: number; stepSize: number; } | null { + + const stackMap: { [index: string]: ChartDataset } = {}; + datasets?.filter(el => el["yAxisID"] === yAxis.yAxisId).forEach((dataset, index) => { + const stackId = dataset.stack || "default"; // If no stack is defined, use "default" + + if (dataset.hidden) { + return; + } + + if (chartType === "line") { + stackMap[index] = dataset; + return; + } + + if (!(stackId in stackMap)) { + // If the stack doesn"t exist yet, create an entry + stackMap[stackId] = { ...dataset, data: [...dataset.data] }; + } else { + // If the stack already exists, merge the data arrays + stackMap[stackId].data = stackMap[stackId].data.map((value, index) => { + return Utils.addSafely(value as number, (dataset.data[index] as number || 0)); // Sum data points or handle missing values + }); + } + }); + + return Object.values(stackMap) + .reduce((arr: { min: number, max: number, stepSize: number }, dataset: ChartDataset) => { - return datasets?.filter(el => el["yAxisID"] === yAxis.yAxisId) - .reduce((arr, dataset) => { const min = Math.floor(Math.min(arr.min, ArrayUtils.findSmallestNumber(dataset.data as number[]))) ?? null; const max = Math.ceil(Math.max(arr.max, ArrayUtils.findBiggestNumber(dataset.data as number[]))) ?? null; @@ -108,7 +152,7 @@ export class ChartConstants { arr = { min: min, max: max, - stepSize: Math.max(arr.stepSize, ChartConstants.calculateStepSize(min, max)), + stepSize: Math.max(arr?.stepSize ?? 0, ChartConstants.calculateStepSize(min, max)), }; return arr; diff --git a/ui/src/app/shared/components/edge/edge.ts b/ui/src/app/shared/components/edge/edge.ts index babbb91da9e..64cb0fe962a 100644 --- a/ui/src/app/shared/components/edge/edge.ts +++ b/ui/src/app/shared/components/edge/edge.ts @@ -22,9 +22,9 @@ import { GetChannelResponse } from "../../jsonrpc/response/getChannelResponse"; import { Channel, GetChannelsOfComponentResponse } from "../../jsonrpc/response/getChannelsOfComponentResponse"; import { GetEdgeConfigResponse } from "../../jsonrpc/response/getEdgeConfigResponse"; import { GetPropertiesOfFactoryResponse } from "../../jsonrpc/response/getPropertiesOfFactoryResponse"; -import { ArrayUtils } from "../../service/arrayutils"; import { ChannelAddress, EdgePermission, SystemLog, Websocket } from "../../shared"; import { Role } from "../../type/role"; +import { ArrayUtils } from "../../utils/array/array.utils"; import { CurrentData } from "./currentdata"; import { EdgeConfig } from "./edgeconfig"; diff --git a/ui/src/app/shared/components/edge/edgeconfig.ts b/ui/src/app/shared/components/edge/edgeconfig.ts index 4b12b73aed2..907ebb27fb9 100644 --- a/ui/src/app/shared/components/edge/edgeconfig.ts +++ b/ui/src/app/shared/components/edge/edgeconfig.ts @@ -115,7 +115,7 @@ export class EdgeConfig { category: { title: "Zähler", icon: "speedometer-outline" }, factories: [ EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.meter.api.SymmetricMeter"), // TODO replaced by ElectricityMeter - EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.meter.api.ElectricityMeter"), + EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.meter.api.ElectricityMeter", "io.openems.edge.evcs.api.Evcs"), EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.ess.dccharger.api.EssDcCharger"), ].flat(2), }, @@ -258,13 +258,20 @@ export class EdgeConfig { /** * Get Factories of Nature. * - * @param natureId the given Nature. + * @param factories the given EdgeConfig.Factory + * @param includeNature the name of the Nature to be included + * @param excludeNature an optional name of a Nature to be excluded */ - public static getFactoriesByNature(factories: { [id: string]: EdgeConfig.Factory }, natureId: string): EdgeConfig.Factory[] { + public static getFactoriesByNature(factories: { [id: string]: EdgeConfig.Factory }, includeNature: string, excludeNature?: string): EdgeConfig.Factory[] { const result = []; - const nature = EdgeConfig.getNaturesOfFactories(factories)[natureId]; - if (nature) { - for (const factoryId of nature.factoryIds) { + const natures = EdgeConfig.getNaturesOfFactories(factories); + const include = natures[includeNature]; + const excludes = excludeNature != null && excludeNature in natures ? natures[excludeNature].factoryIds : []; + if (include) { + for (const factoryId of include.factoryIds) { + if (excludes.includes(factoryId)) { + continue; + } if (factoryId in factories) { result.push(factories[factoryId]); } @@ -509,25 +516,19 @@ export class EdgeConfig { if (component.properties["type"] == "PRODUCTION") { return true; } + const natureIds = this.getNatureIdsByFactoryId(component.factoryId); + if (natureIds.includes("io.openems.edge.pvinverter.api.ManagedSymmetricPvInverter") + || natureIds.includes("io.openems.edge.ess.dccharger.api.EssDcCharger")) { + return true; + } // TODO properties in OSGi Component annotations are not transmitted correctly with Apache Felix SCR switch (component.factoryId) { case "Fenecon.Dess.PvMeter": case "Fenecon.Mini.PvMeter": case "Fenecon.Pro.PvMeter": - case "Kaco.BlueplanetHybrid10.PvInverter": - case "Kostal.Piko.Charger": - case "PV-Inverter.Fronius": - case "PV-Inverter.KACO.blueplanet": - case "PV-Inverter.Kostal": - case "PV-Inverter.SMA.SunnyTripower": - case "PV-Inverter.Solarlog": - case "PV-Inverter.SunSpec": case "Simulator.ProductionMeter.Acting": - case "Simulator.PvInverter": - case "SolarEdge.PV-Inverter": return true; } - return false; } @@ -540,11 +541,14 @@ export class EdgeConfig { public isTypeConsumptionMetered(component: EdgeConfig.Component) { if (component.properties["type"] == "CONSUMPTION_METERED") { return true; - } else { - switch (component.factoryId) { - case "GoodWe.EmergencyPowerMeter": - return true; - } + } + switch (component.factoryId) { + case "GoodWe.EmergencyPowerMeter": + return true; + } + const natures = this.getNatureIdsByFactoryId(component.factoryId); + if (natures.includes("io.openems.edge.evcs.api.Evcs") && !natures.includes("io.openems.edge.evcs.api.MetaEvcs")) { + return true; } return false; } diff --git a/ui/src/app/shared/components/flat/flat-widget-percentagebar/flat-widget-percentagebar.ts b/ui/src/app/shared/components/flat/flat-widget-percentagebar/flat-widget-percentagebar.ts index 3faf1948a9f..439c8cbd220 100644 --- a/ui/src/app/shared/components/flat/flat-widget-percentagebar/flat-widget-percentagebar.ts +++ b/ui/src/app/shared/components/flat/flat-widget-percentagebar/flat-widget-percentagebar.ts @@ -6,7 +6,10 @@ import { AbstractFlatWidgetLine } from "../abstract-flat-widget-line"; templateUrl: "./flat-widget-percentagebar.html", }) export class FlatWidgetPercentagebarComponent extends AbstractFlatWidgetLine { - protected get displayPercent(): number { - return Math.round(Number.parseFloat(this.displayValue)); + + protected get displayPercent(): number | null { + return this.displayValue === null + ? null + : Math.round(Number.parseFloat(this.displayValue)); } } diff --git a/ui/src/app/shared/components/header/app-header.ts b/ui/src/app/shared/components/header/app-header.ts new file mode 100644 index 00000000000..1a3a2596fbc --- /dev/null +++ b/ui/src/app/shared/components/header/app-header.ts @@ -0,0 +1,222 @@ +// @ts-strict-ignore +import { AfterViewChecked, ChangeDetectorRef, Component, Input, OnDestroy, OnInit, ViewChild } from "@angular/core"; +import { NavigationEnd, Router } from "@angular/router"; +import { MenuController, ModalController } from "@ionic/angular"; +import { Subject } from "rxjs"; +import { filter, takeUntil } from "rxjs/operators"; +import { environment } from "src/environments"; + +import { Edge, Service, Websocket } from "../../shared"; +import { PickDateComponent } from "../pickdate/pickdate.component"; +import { StatusSingleComponent } from "../status/single/status.component"; + +@Component({ + selector: "app-header", + templateUrl: "./header.component.html", +}) +export class AppHeaderComponent implements OnInit, OnDestroy, AfterViewChecked { + + @ViewChild(PickDateComponent, { static: false }) public PickDateComponent: PickDateComponent; + + public environment = environment; + public backUrl: string | boolean = "/"; + public enableSideMenu: boolean; + public currentPage: "EdgeSettings" | "Other" | "IndexLive" | "IndexHistory" = "Other"; + public isSystemLogEnabled: boolean = false; + + protected isHeaderAllowed: boolean = false; + + private ngUnsubscribe: Subject = new Subject(); + private _customBackUrl: string | null = null; + + constructor( + private cdRef: ChangeDetectorRef, + public menu: MenuController, + public modalCtrl: ModalController, + public router: Router, + public service: Service, + public websocket: Websocket, + ) { } + + @Input() public set customBackUrl(url: string | null) { + if (!url) { + return; + } + this._customBackUrl = url; + this.updateBackUrl(url); + } + + ngOnInit() { + // set inital URL + this.updateUrl(this.router.routerState.snapshot.url); + // update backUrl on navigation events + this.router.events.pipe( + takeUntil(this.ngUnsubscribe), + filter(event => event instanceof NavigationEnd), + ).subscribe(event => { + window.scrollTo(0, 0); + this.updateUrl((event).urlAfterRedirects); + }); + + } + + // used to prevent 'Expression has changed after it was checked' error + ngAfterViewChecked() { + this.cdRef.detectChanges(); + } + + updateUrl(url: string) { + this.updateBackUrl(url); + this.updateEnableSideMenu(url); + this.updateCurrentPage(url); + this.isHeaderAllowed = this.isAllowedForView(url); + } + + updateEnableSideMenu(url: string) { + const urlArray = url.split("/"); + const file = urlArray.pop(); + + if (file == "user" || file == "settings" || file == "changelog" || file == "login" || file == "index" || urlArray.length > 3) { + // disable side-menu; show back-button instead + this.enableSideMenu = false; + } else { + // enable side-menu if back-button is not needed + this.enableSideMenu = true; + } + } + + updateBackUrl(url: string) { + + if (this._customBackUrl) { + this.backUrl = this._customBackUrl; + return; + } + + // disable backUrl & Segment Navigation on initial 'login' page + if (url === "/login" || url === "/overview" || url === "/index") { + this.backUrl = false; + return; + } + + + // set backUrl for user when an Edge had been selected before + const currentEdge: Edge = this.service.currentEdge.value; + if (url === "/user" && currentEdge != null) { + this.backUrl = "/device/" + currentEdge.id + "/live"; + return; + } + + // set backUrl for user if no edge had been selected + if (url === "/user") { + this.backUrl = "/overview"; + return; + } + + if (url === "/changelog" && currentEdge != null) { + // TODO this does not work if Changelog was opened from /user + this.backUrl = "/device/" + currentEdge.id + "/settings/profile"; + return; + } + + const urlArray = url.split("/"); + let backUrl: string | boolean = "/"; + const file = urlArray.pop(); + + // disable backUrl for History & EdgeIndex Component ++ Enable Segment Navigation + if ((file == "history" || file == "live") && urlArray.length == 3) { + this.backUrl = false; + return; + } + + // disable backUrl to first 'index' page from Edge index if there is only one Edge in the system + if (file === "live" && urlArray.length == 3 && this.environment.backend === "OpenEMS Edge") { + this.backUrl = false; + return; + } + + // remove one part of the url for 'index' + if (file === "live") { + urlArray.pop(); + } + + // fix url for App "settings/app/install" and "settings/app/update" + if (urlArray.slice(-3, -1).join("/") === "settings/app") { + urlArray.pop(); + } + + // re-join the url + backUrl = urlArray.join("/") || "/"; + + // correct path for '/device/[edgeId]/index' + if (backUrl === "/device") { + backUrl = "/"; + } + this.backUrl = backUrl; + } + + updateCurrentPage(url: string) { + const urlArray = url.split("/"); + let file = urlArray.pop(); + if (urlArray.length >= 4) { + file = urlArray[3]; + } + // Enable Segment Navigation for Edge-Index-Page + if ((file == "history" || file == "live") && urlArray.length == 3) { + if (file == "history") { + this.currentPage = "IndexHistory"; + } else { + this.currentPage = "IndexLive"; + } + } else if (file == "settings" && urlArray.length > 1) { + this.currentPage = "EdgeSettings"; + } + else { + this.currentPage = "Other"; + } + } + + public segmentChanged(event) { + if (event.detail.value == "IndexLive") { + this.router.navigate(["/device/" + this.service.currentEdge.value.id + "/live"], { replaceUrl: true }); + this.cdRef.detectChanges(); + } + if (event.detail.value == "IndexHistory") { + + /** Creates bug of being infinite forwarded betweeen live and history, if not relatively routed */ + // this.router.navigate(["../history"], { relativeTo: this.route }); + this.router.navigate(["/device/" + this.service.currentEdge.value.id + "/history"]); + this.cdRef.detectChanges(); + } + } + + async presentSingleStatusModal() { + const modal = await this.modalCtrl.create({ + component: StatusSingleComponent, + }); + return await modal.present(); + } + + ngOnDestroy() { + this.ngUnsubscribe.next(); + this.ngUnsubscribe.complete(); + } + + private isAllowedForView(url: string): boolean { + + // Strip queryParams + const cleanUrl = url.split("?")[0]; + + if (url.includes("/history/")) { + return false; + } + + switch (cleanUrl) { + case "/login": + case "/index": + case "/demo": + return false; + default: + return true; + } + } +} diff --git a/ui/src/app/shared/components/header/header.component.html b/ui/src/app/shared/components/header/header.component.html index b1e4714c831..0ef3fa7a05e 100644 --- a/ui/src/app/shared/components/header/header.component.html +++ b/ui/src/app/shared/components/header/header.component.html @@ -1,4 +1,4 @@ - + @@ -36,16 +36,17 @@ - + + [name]="edge.roleIsAtLeast('admin') ? 'information-outline' : 'checkmark-circle-outline'" + size="medium"> diff --git a/ui/src/app/shared/components/header/header.component.ts b/ui/src/app/shared/components/header/header.component.ts index 27c51f4732d..1a4fe4dbf74 100644 --- a/ui/src/app/shared/components/header/header.component.ts +++ b/ui/src/app/shared/components/header/header.component.ts @@ -1,6 +1,6 @@ // @ts-strict-ignore import { AfterViewChecked, ChangeDetectorRef, Component, Input, OnDestroy, OnInit, ViewChild } from "@angular/core"; -import { ActivatedRoute, NavigationEnd, Router } from "@angular/router"; +import { NavigationEnd, Router } from "@angular/router"; import { MenuController, ModalController } from "@ionic/angular"; import { Subject } from "rxjs"; import { filter, takeUntil } from "rxjs/operators"; @@ -23,10 +23,12 @@ export class HeaderComponent implements OnInit, OnDestroy, AfterViewChecked { public enableSideMenu: boolean; public currentPage: "EdgeSettings" | "Other" | "IndexLive" | "IndexHistory" = "Other"; public isSystemLogEnabled: boolean = false; + + protected isHeaderAllowed: boolean = true; + private ngUnsubscribe: Subject = new Subject(); private _customBackUrl: string | null = null; - constructor( private cdRef: ChangeDetectorRef, public menu: MenuController, @@ -34,7 +36,6 @@ export class HeaderComponent implements OnInit, OnDestroy, AfterViewChecked { public router: Router, public service: Service, public websocket: Websocket, - private route: ActivatedRoute, ) { } @Input() public set customBackUrl(url: string | null) { @@ -56,6 +57,7 @@ export class HeaderComponent implements OnInit, OnDestroy, AfterViewChecked { window.scrollTo(0, 0); this.updateUrl((event).urlAfterRedirects); }); + } // used to prevent 'Expression has changed after it was checked' error @@ -180,7 +182,8 @@ export class HeaderComponent implements OnInit, OnDestroy, AfterViewChecked { if (event.detail.value == "IndexHistory") { /** Creates bug of being infinite forwarded betweeen live and history, if not relatively routed */ - this.router.navigate(["../history"], { relativeTo: this.route }); + // this.router.navigate(["../history"], { relativeTo: this.route }); + this.router.navigate(["/device/" + this.service.currentEdge.value.id + "/history"]); this.cdRef.detectChanges(); } } diff --git a/ui/src/app/shared/components/shared/testing/common.ts b/ui/src/app/shared/components/shared/testing/common.ts index 59e22834a1c..ea9af4c8948 100644 --- a/ui/src/app/shared/components/shared/testing/common.ts +++ b/ui/src/app/shared/components/shared/testing/common.ts @@ -22,7 +22,7 @@ export namespace OeTester { } export namespace ChartOptions { - export const LINE_CHART_OPTIONS = (period: string, chartType: "line" | "bar", options: { [key: string]: { scale: { min?: number, max?: number, beginAtZero?: boolean }, ticks?: { stepSize: number; }; }; }, title?: string): OeChartTester.Dataset.Option => ({ + export const LINE_CHART_OPTIONS = (period: string, chartType: "line" | "bar", options: { [key: string]: { scale: { min?: number, max?: number, beginAtZero?: boolean }, ticks?: { stepSize: number; min?: number, max?: number }; }; }, title?: string): OeChartTester.Dataset.Option => ({ type: "option", options: { "responsive": true, "maintainAspectRatio": false, "elements": { "point": { "radius": 0, "hitRadius": 0, "hoverRadius": 0 }, "line": { "stepped": false, "fill": true } }, "datasets": { "bar": {}, "line": {} }, "plugins": { @@ -31,6 +31,7 @@ export namespace OeTester { }, }, "scales": { "x": { "stacked": true, "offset": false, "type": "time", "ticks": { "source": "auto", "maxTicksLimit": 31 }, "bounds": "ticks", "adapters": { "date": { "locale": { "code": "de", "formatLong": {}, "localize": {}, "match": {}, "options": { "weekStartsOn": 1, "firstWeekContainsDate": 4 } } } }, "time": { "unit": period as TimeUnit, "displayFormats": { "datetime": "yyyy-MM-dd HH:mm:ss", "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" } } }, "left": { + "stacked": false, "beginAtZero": false, ...options["left"]?.scale, ...(chartType === "line" ? { stacked: false } : {}), "title": { "text": "kW", "display": false, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, "ticks": { ...options["left"]?.ticks, @@ -52,7 +53,9 @@ export namespace OeTester { }, "scales": { "x": { "stacked": true, "offset": true, "type": "time", "ticks": { "source": "auto", "maxTicksLimit": 31 }, "bounds": "ticks", "adapters": { "date": { "locale": { "code": "de", "formatLong": {}, "localize": {}, "match": {}, "options": { "weekStartsOn": 1, "firstWeekContainsDate": 4 } } } }, "time": { "unit": period as TimeUnit, "displayFormats": { "datetime": "yyyy-MM-dd HH:mm:ss", "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" } } }, "left": { - ...options["left"]?.scale, ...(chartType === "line" ? { stacked: false } : {}), "beginAtZero": true, "title": { "text": "kWh", "display": false, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, + "stacked": true, + ...options["left"]?.scale, + ...(chartType === "line" ? { stacked: false } : {}), "beginAtZero": true, "title": { "text": "kWh", "display": false, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, "ticks": { ...options["left"]?.ticks, "color": "", @@ -85,8 +88,9 @@ export namespace OeTester { }, }, "scales": { "x": { "stacked": true, "offset": false, "type": "time", "ticks": { "source": "auto", "maxTicksLimit": 31 }, "bounds": "ticks", "adapters": { "date": { "locale": { "code": "de", "formatLong": {}, "localize": {}, "match": {}, "options": { "weekStartsOn": 1, "firstWeekContainsDate": 4 } } } }, "time": { "unit": period as TimeUnit, "displayFormats": { "datetime": "yyyy-MM-dd HH:mm:ss", "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" } } }, "left": { + "stacked": false, ...options["left"]?.scale, ...(chartType === "line" ? { stacked: false } : {}), "beginAtZero": true, - "title": { "text": "kW", "display": true, "padding": 5, "font": { "size": 11 } }, + "title": { "text": "kW", "display": false, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, "ticks": { ...options["left"]?.ticks, @@ -96,8 +100,9 @@ export namespace OeTester { }, }, "right": { + "stacked": false, ...options["right"]?.scale, ...(chartType === "line" ? { stacked: false } : {}), "beginAtZero": true, - "title": { "text": "Zustand", "display": true, "padding": 5, "font": { "size": 11 } }, + "title": { "text": "Zustand", "display": false, "padding": 5, "font": { "size": 11 } }, "position": "right", "grid": { "display": false }, "ticks": { ...options["right"]?.ticks, @@ -119,7 +124,8 @@ export namespace OeTester { }, "scales": { "x": { "stacked": true, "offset": true, "type": "time", "ticks": { "source": "auto", "maxTicksLimit": 31 }, "bounds": "ticks", "adapters": { "date": { "locale": { "code": "de", "formatLong": {}, "localize": {}, "match": {}, "options": { "weekStartsOn": 1, "firstWeekContainsDate": 4 } } } }, "time": { "unit": period as TimeUnit, "displayFormats": { "datetime": "yyyy-MM-dd HH:mm:ss", "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" } } }, "left": { - ...options["left"]?.scale, ...(chartType === "line" ? { stacked: false } : {}), "beginAtZero": true, "title": { "text": "kWh", "display": true, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, + "stacked": true, + ...options["left"]?.scale, ...(chartType === "line" ? { stacked: false } : {}), "beginAtZero": true, "title": { "text": "kWh", "display": false, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, "ticks": { ...options["left"]?.ticks, "color": "", @@ -128,8 +134,9 @@ export namespace OeTester { }, }, "right": { - ...options["right"]?.scale, ...(chartType === "line" ? { stacked: false } : { min: 0 }), "beginAtZero": true, - "title": { "text": "Aktive Zeit", "display": true, "padding": 5, "font": { "size": 11 } }, + "stacked": true, + ...options["right"]?.scale, ...(chartType === "line" ? { stacked: false } : {}), "beginAtZero": true, + "title": { "text": "Aktive Zeit", "display": false, "padding": 5, "font": { "size": 11 } }, "position": "right", "grid": { "display": false }, "ticks": { "color": "", diff --git a/ui/src/app/shared/components/shared/testing/tester.ts b/ui/src/app/shared/components/shared/testing/tester.ts index 7b2e9c7c662..9a4084f6bb5 100644 --- a/ui/src/app/shared/components/shared/testing/tester.ts +++ b/ui/src/app/shared/components/shared/testing/tester.ts @@ -6,6 +6,7 @@ import { QueryHistoricTimeseriesEnergyPerPeriodResponse } from "src/app/shared/j import { HistoryUtils } from "src/app/shared/service/utils"; import { CurrentData, EdgeConfig } from "src/app/shared/shared"; +import { ObjectUtils } from "src/app/shared/utils/object/object.utils"; import { AbstractHistoryChart } from "../../chart/abstracthistorychart"; import { XAxisType } from "../../chart/chart.constants"; import { TextIndentation } from "../../modal/modal-line/modal-line"; @@ -307,9 +308,17 @@ export class OeChartTester { legendOptions.push(AbstractHistoryChart.getLegendOptions(label, displayValue)); }); + const options = AbstractHistoryChart.getOptions(chartData, chartType, testContext.service, testContext.translate, legendOptions, channelData.result, locale, config, datasets, xAxisType, labels); + + chartData.yAxes.filter(axis => axis.unit != null).forEach(axis => { + // Remove custom scale calculations from unittest, seperate unittest existing + options.scales[axis.yAxisId] = ObjectUtils.excludeProperties(options.scales[axis.yAxisId], ["min", "max"]) as Chart.ScaleOptionsByType<"radialLinear" | keyof Chart.CartesianScaleTypeRegistry>; + options.scales[axis.yAxisId].ticks = ObjectUtils.excludeProperties(options.scales[axis.yAxisId].ticks as Chart.RadialTickOptions, ["stepSize"]); + }); + return { type: "option", - options: AbstractHistoryChart.getOptions(chartData, chartType, testContext.service, testContext.translate, legendOptions, channelData.result, locale, config, datasets, xAxisType, labels), + options: options, }; } diff --git a/ui/src/app/shared/ngrx-store/states.ts b/ui/src/app/shared/ngrx-store/states.ts index 33d8f0aeb0d..c957daee5e3 100644 --- a/ui/src/app/shared/ngrx-store/states.ts +++ b/ui/src/app/shared/ngrx-store/states.ts @@ -35,7 +35,7 @@ export class AppStateTracker { protected router: Router, protected pagination: Pagination, private websocket: Websocket, - private previousRouteService: PreviousRouteService, + private routeService: PreviousRouteService, ) { if (!localStorage.getItem("AppState")) { console.log(`${AppStateTracker.LOG_PREFIX} Log deactivated`); @@ -55,15 +55,18 @@ export class AppStateTracker { * Handles navigation after authentication */ public navigateAfterAuthentication() { - const segments = this.router.routerState.snapshot.url.split("/"); - const previousUrl: string = this.previousRouteService.getPreviousUrl(); - if ((previousUrl === segments[segments.length - 1]) || previousUrl === "/") { - this.router.navigate(["./overview"]); - return; - } + this.router.navigate(["overview"]); + return; + // const segments = this.router.routerState.snapshot.url.split("/"); + // const previousUrl: string = this.routeService.getPreviousUrl(); + + // if ((previousUrl === segments[segments.length - 1]) || previousUrl === "/") { + // this.router.navigate(["./overview"]); + // return; + // } - this.router.navigate(previousUrl.split("/")); + // this.router.navigate(previousUrl.split("/")); } private startStateHandler(state: States): void { diff --git a/ui/src/app/shared/service/arrayutils.ts b/ui/src/app/shared/service/arrayutils.ts deleted file mode 100644 index 5fc4e31b654..00000000000 --- a/ui/src/app/shared/service/arrayutils.ts +++ /dev/null @@ -1,27 +0,0 @@ -export namespace ArrayUtils { - export function equalsCheck(a: T[], b: T[]) { - return a.length === b.length && - a.every((v, i) => v === b[i]); - } - - /** - * Sort arrays alphabetically, according to the string returned by fn. - * Elements for which fn returns null or undefined are sorted to the end in an undefined order. - * - * @param array to sort - * @param fn to get a string to sort by - * @returns sorted array - */ - export function sortedAlphabetically(array: Type[], fn: (arg: Type) => string): Type[] { - return array.sort((a: Type, b: Type) => { - const aVal = fn(a); - const bVal = fn(b); - if (!aVal) { - return !bVal ? 0 : 1; - } else if (!bVal) { - return -1; - } - return aVal.localeCompare(bVal, undefined, { sensitivity: "accent" }); - }); - } -} diff --git a/ui/src/app/shared/service/defaulttypes.spec.ts b/ui/src/app/shared/service/defaulttypes.spec.ts new file mode 100644 index 00000000000..b5a01f05370 --- /dev/null +++ b/ui/src/app/shared/service/defaulttypes.spec.ts @@ -0,0 +1,17 @@ +// @ts-strict-ignore +import { RGBColor } from "./defaulttypes"; + +describe("Defaulttypes", () => { + + it("#RgbColor.toString()", () => { + const black = new RGBColor(0, 0, 0); + expect(black.toString()).toEqual("rgb(0,0,0)"); + }); + + it("#RgbColor.toString() - invalid values", () => { + const allInvalid = new RGBColor(null, null, null); + expect(() => allInvalid.toString()).toThrow(Error("All values need to be valid")); + const oneInvalid = new RGBColor(0, 0, null); + expect(() => oneInvalid.toString()).toThrow(Error("All values need to be valid")); + }); +}); diff --git a/ui/src/app/shared/service/defaulttypes.ts b/ui/src/app/shared/service/defaulttypes.ts index 08b2419b983..f9652fb6dbe 100644 --- a/ui/src/app/shared/service/defaulttypes.ts +++ b/ui/src/app/shared/service/defaulttypes.ts @@ -256,3 +256,28 @@ export type TKeyValue = { }; /** */ export type PropType = TObj[TProp]; + +type Range = Acc["length"] extends N + ? Acc[number] + : Range; + +export type RGBValue = Range<256>; // 0 to 255 + +export class RGBColor { + private readonly red: T; + private readonly green: T; + private readonly blue: T; + + constructor(red: T, green: T, blue: T) { + this.red = red; + this.green = green; + this.blue = blue; + } + + public toString(): string { + if (this.red == null || this.green == null || this.blue == null) { + throw new Error("All values need to be valid"); + } + return `rgb(${this.red},${this.green},${this.blue})`; + } +} diff --git a/ui/src/app/shared/service/utils.ts b/ui/src/app/shared/service/utils.ts index 0d5f686b21a..837e37acc54 100644 --- a/ui/src/app/shared/service/utils.ts +++ b/ui/src/app/shared/service/utils.ts @@ -4,7 +4,6 @@ import { TranslateService } from "@ngx-translate/core"; import { ChartDataset } from "chart.js"; import { saveAs } from "file-saver-es"; import { DefaultTypes } from "src/app/shared/service/defaulttypes"; - import { JsonrpcResponseSuccess } from "../jsonrpc/base"; import { Base64PayloadResponse } from "../jsonrpc/response/base64PayloadResponse"; import { QueryHistoricTimeseriesEnergyResponse } from "../jsonrpc/response/queryHistoricTimeseriesEnergyResponse"; @@ -626,16 +625,17 @@ export class Utils { } export enum YAxisType { + CURRENCY, + CURRENT, + ENERGY, + LEVEL, NONE, - POWER, PERCENTAGE, - RELAY, - ENERGY, - VOLTAGE, + POWER, REACTIVE, - CURRENT, + RELAY, TIME, - CURRENCY, + VOLTAGE, } export enum ChartAxis { diff --git a/ui/src/app/shared/shared.module.ts b/ui/src/app/shared/shared.module.ts index d85cf25b0e5..75cca829719 100644 --- a/ui/src/app/shared/shared.module.ts +++ b/ui/src/app/shared/shared.module.ts @@ -27,6 +27,7 @@ import { InputTypeComponent } from "./components/formly/input"; import { FormlyInputSerialNumberWrapperComponent as FormlyWrapperInputSerialNumber } from "./components/formly/input-serial-number-wrapper"; import { PanelWrapperComponent } from "./components/formly/panel-wrapper.component"; import { RepeatTypeComponent } from "./components/formly/repeat"; +import { AppHeaderComponent } from "./components/header/app-header"; import { HeaderComponent } from "./components/header/header.component"; import { HistoryDataErrorModule } from "./components/history-data-error/history-data-error.module"; import { PercentageBarComponent } from "./components/percentagebar/percentagebar.component"; @@ -56,20 +57,12 @@ export function SubnetmaskValidatorMessage(err, field: FormlyFieldConfig) { return `"${field.formControl.value}" is not a valid Subnetmask`; } - @NgModule({ imports: [ BrowserAnimationsModule, - NgChartsModule, CommonModule, + ComponentsModule, DirectiveModule, - FormsModule, - IonicModule, - NgxSpinnerModule.forRoot({ - type: "ball-clip-rotate-multiple", - }), - ReactiveFormsModule, - RouterModule, FormlyModule.forRoot({ wrappers: [ { name: "form-field", component: FormlyWrapperFormFieldComponent }, @@ -96,56 +89,61 @@ export function SubnetmaskValidatorMessage(err, field: FormlyFieldConfig) { { name: "subnetmask", message: SubnetmaskValidatorMessage }, ], }), - PipeModule, - ComponentsModule, - TranslateModule, + FormsModule, HistoryDataErrorModule, + IonicModule, MeterModule, + NgChartsModule, + NgxSpinnerModule.forRoot({ + type: "ball-clip-rotate-multiple", + }), + PipeModule, + ReactiveFormsModule, + RouterModule, + TranslateModule, ], declarations: [ - // components + AppHeaderComponent, ChartOptionsComponent, - HeaderComponent, - PercentageBarComponent, - // formly - InputTypeComponent, - FormlyWrapperFormFieldComponent, - RepeatTypeComponent, - FormlyWrapperInputSerialNumber, + FormlyCheckBoxHyperlinkWrapperComponent, + FormlyFieldCheckboxWithImageComponent, + FormlyFieldModalComponent, + FormlyFieldMultiStepComponent, + FormlyFieldRadioWithImageComponent, + FormlyFieldWithLoadingAnimationComponent, FormlySelectFieldExtendedWrapperComponent, FormlySelectFieldModalComponent, - FormlyFieldRadioWithImageComponent, - FormlyCheckBoxHyperlinkWrapperComponent, FormlyWrapperDefaultValueWithCasesComponent, - FormlyFieldModalComponent, + FormlyWrapperFormFieldComponent, + FormlyWrapperInputSerialNumber, + HeaderComponent, + InputTypeComponent, PanelWrapperComponent, - FormlyFieldWithLoadingAnimationComponent, - FormlyFieldCheckboxWithImageComponent, - FormlyFieldMultiStepComponent, + PercentageBarComponent, + RepeatTypeComponent, ], exports: [ - // modules + AppHeaderComponent, BrowserAnimationsModule, - NgChartsModule, + ChartOptionsComponent, CommonModule, + ComponentsModule, DirectiveModule, + FormlyFieldWithLoadingAnimationComponent, FormlyIonicModule, FormlyModule, FormsModule, + HeaderComponent, + HistoryDataErrorModule, IonicModule, + MeterModule, + NgChartsModule, NgxSpinnerModule, + PercentageBarComponent, + PipeModule, ReactiveFormsModule, RouterModule, TranslateModule, - PipeModule, - ComponentsModule, - MeterModule, - HistoryDataErrorModule, - // components - ChartOptionsComponent, - HeaderComponent, - PercentageBarComponent, - FormlyFieldWithLoadingAnimationComponent, ], providers: [ AppStateTracker, diff --git a/ui/src/app/shared/utils/array/array.utils.ts b/ui/src/app/shared/utils/array/array.utils.ts index 6026afa4579..037c4c4c4f6 100644 --- a/ui/src/app/shared/utils/array/array.utils.ts +++ b/ui/src/app/shared/utils/array/array.utils.ts @@ -19,10 +19,10 @@ export namespace ArrayUtils { /** * Finds the biggest number in a array. * null, undefined, NaN, +-Infinity are ignored in this method. - * - * @param arr the arr - * @returns a number if arr not empty, else null - */ + * + * @param arr the arr + * @returns a number if arr not empty, else null + */ export function findBiggestNumber(arr: (number | null | undefined)[]): number | null { const filteredArr = arr.filter((el): el is number => Number.isFinite(el)); return filteredArr.length > 0 ? Math.max(...filteredArr) : null; @@ -48,4 +48,15 @@ export namespace ArrayUtils { return aVal.localeCompare(bVal, undefined, { sensitivity: "accent" }); }); } + + /** + * Checks if array contains at least one of the passed strings + * + * @param strings the strings + * @param arr the array + * @returns true if arr contains at least one of the strings + */ + export function containsStrings(strings: (number | string | null)[], arr: (number | string | null)[]): boolean { + return arr.filter(el => strings.includes(el)).length > 0; + } } diff --git a/ui/src/app/shared/utils/object/object.utils.ts b/ui/src/app/shared/utils/object/object.utils.ts new file mode 100644 index 00000000000..043a0fdb465 --- /dev/null +++ b/ui/src/app/shared/utils/object/object.utils.ts @@ -0,0 +1,8 @@ +export class ObjectUtils { + + public static excludeProperties, K extends keyof T>(obj: T, keys: K[]): Omit { + const result = { ...obj }; + keys.forEach(key => delete result[key]); + return result; + } +} diff --git a/ui/src/app/user/user.component.html b/ui/src/app/user/user.component.html index 08f52cc3ffc..69df7a384f5 100644 --- a/ui/src/app/user/user.component.html +++ b/ui/src/app/user/user.component.html @@ -1,4 +1,3 @@ -
      diff --git a/ui/src/assets/i18n/de.json b/ui/src/assets/i18n/de.json index e105762966d..954c76a43ce 100644 --- a/ui/src/assets/i18n/de.json +++ b/ui/src/assets/i18n/de.json @@ -237,14 +237,14 @@ "CONTROL_MODE_DESCRIPTION": { "CHARGE_CONSUMPTION": "" }, - "CHARGE_FROM_GRID_ACTIVATE": "Aktive Beladung aus dem Netz aktivieren (BETA-Test)", + "CHARGE_FROM_GRID_ACTIVATE": "Aktive Beladung aus dem Netz aktivieren", "PRICE": "Aktueller Bezugsstrompreis", "STATE": { "DELAY_DISCHARGE": "Entladung verzögert", "BALANCING": "Eigenverbrauchsoptimierung", "CHARGE_GRID": "Beladung aus dem Netz freigegeben" }, - "CHART_TITLE": "Aktueller Fahrplan (BETA-Test)", + "CHART_TITLE": "Aktueller Fahrplan", "CHART_WARNING_NOTE": "Die Grafik zeigt die vergangenen drei Stunden, sowie die zukünftig geplante Betriebsweise für den Zeitraum, für den die dynamischen Netzbezugspreise zur Verfügung stehen. Bitte beachten Sie, dass der Fahrplan kontinuierlich neu berechnet wird und sich somit im Tagesverlauf ändern kann.", "POWER_SOC_CHART_TITLE": "Vorhersagen (Nur für Admins)" }, @@ -315,6 +315,7 @@ "nov": "Nov", "dec": "Dez", "activeDuration": "Einschaltdauer", + "ACTIVE_DURATION_WITH_LEVEL": "Einschaltdauer Level {{level}}", "CURRENT": "Strom", "VOLTAGE": "Spannung" }, diff --git a/ui/src/assets/i18n/en.json b/ui/src/assets/i18n/en.json index 58ca563831c..0ce4b7372fb 100644 --- a/ui/src/assets/i18n/en.json +++ b/ui/src/assets/i18n/en.json @@ -238,14 +238,14 @@ "CONTROL_MODE_DESCRIPTION": { "CHARGE_CONSUMPTION": "" }, - "CHARGE_FROM_GRID_ACTIVATE": "Activate charge from the grid (BETA test)", + "CHARGE_FROM_GRID_ACTIVATE": "Activate charge from the grid", "PRICE": "Current price", "STATE": { "DELAY_DISCHARGE": "Delayed discharge", "BALANCING": "Self-Consumption optmization", "CHARGE_GRID": "Charge from grid allowed" }, - "CHART_TITLE": "Planned Schedule (BETA test)", + "CHART_TITLE": "Planned Schedule", "CHART_WARNING_NOTE": "The graphic shows the past three hours as well as the future planned operating mode for the period for which the dynamic grid purchase prices are available. Please note that the planned schedule is subject to continuous recalculation and may change throughout the day.", "POWER_SOC_CHART_TITLE": "Forecasts (Only for Admins)" }, @@ -313,7 +313,8 @@ "oct": "Oxt", "nov": "Nov", "dec": "Dec", - "activeDuration": "active duration", + "activeDuration": "Active duration", + "ACTIVE_DURATION_WITH_LEVEL": "Active duration level {{level}}", "CURRENT_AND_VOLTAGE": "Current & Voltage", "CURRENT": "Current", "VOLTAGE": "Voltage", From 25febfa4dd10d028fc86a4acc83f17e6e430ca5a Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Sat, 19 Oct 2024 23:20:11 +0200 Subject: [PATCH 158/173] Update Checkstyle to 10.18.2 (#2847) - Update checkstyle to 10.18.2 - See https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.18.2 for details. - Unfortunately Checkstyle by default requires no newline after

      in JavaDoc, whereas Eclipse IDE automatically adds one by default. This is PR disables this check. - Change `JavadocParagraph` to `allowNewlineParagraph` - Fix ControllerEssGridOptimizedChargeImplTest - Fixes Checkstyle `Checks that overloaded methods are grouped together. Overloaded methods have the samename but different signatures where the signature can differ by the number ofinput parameters or type of input parameters or both. ` --- build.gradle | 2 +- cnf/checkstyle.xml | 18 +-- ...trollerEssGridOptimizedChargeImplTest.java | 148 +++++++++--------- 3 files changed, 83 insertions(+), 85 deletions(-) diff --git a/build.gradle b/build.gradle index 82249fb14f2..ad224209fd9 100644 --- a/build.gradle +++ b/build.gradle @@ -68,7 +68,7 @@ subprojects { } checkstyle { - toolVersion = '10.11.0' + toolVersion = '10.18.2' configFile = file("${rootDir}/cnf/checkstyle.xml") maxWarnings = 0 ignoreFailures = false diff --git a/cnf/checkstyle.xml b/cnf/checkstyle.xml index ad22318becf..6ed4ad0febb 100644 --- a/cnf/checkstyle.xml +++ b/cnf/checkstyle.xml @@ -23,8 +23,8 @@ - + @@ -47,9 +47,9 @@ + - @@ -107,8 +107,8 @@ - + @@ -144,9 +144,9 @@ + - @@ -179,12 +179,10 @@ - - - + - + @@ -206,15 +204,15 @@ - + - + diff --git a/io.openems.edge.controller.ess.gridoptimizedcharge/test/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedChargeImplTest.java b/io.openems.edge.controller.ess.gridoptimizedcharge/test/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedChargeImplTest.java index 7ac9440a6ba..862b0955d56 100644 --- a/io.openems.edge.controller.ess.gridoptimizedcharge/test/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedChargeImplTest.java +++ b/io.openems.edge.controller.ess.gridoptimizedcharge/test/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedChargeImplTest.java @@ -1444,80 +1444,6 @@ private void testLogic(String description, Integer[] productionPrediction, Integ }); } - private DelayChargeResultState testOneDay(String testDescription, Integer[] productionPrediction, - Integer[] consumptionPrediction, int soc, Optional targetMinuteOpt, int capacity, - int maxApparentPower, int allowedChargePower, DelayChargeRiskLevel riskLevel, Integer[] productionActual, - Integer[] consumptionActual, float resultBuffer) { - DelayChargeResultState resultState; - DelayChargeResult newLogic = ControllerEssGridOptimizedChargeImplTest.testOneDay(testDescription, - productionPrediction, consumptionPrediction, soc, targetMinuteOpt, capacity, maxApparentPower, - allowedChargePower, riskLevel, productionActual, consumptionActual, false); - - DelayChargeResult oldLogic = ControllerEssGridOptimizedChargeImplTest.testOneDay(testDescription, - productionPrediction, consumptionPrediction, soc, targetMinuteOpt, capacity, maxApparentPower, - allowedChargePower, riskLevel, productionActual, consumptionActual, true); - - if (newLogic.getFinalSoc() + resultBuffer < oldLogic.getFinalSoc()) { - resultState = DelayChargeResultState.WARNING; - } else if (newLogic.getFinalSoc() - resultBuffer > oldLogic.getFinalSoc()) { - resultState = DelayChargeResultState.PERFECT; - } else { - resultState = DelayChargeResultState.OK; - } - - float unefficientEnergy = Math - .round(newLogic.getChargedEnergyWithLowPower() / newLogic.getChargedEnergy() * 1000) / 10.0f; - float unefficientEnergyOld = Math - .round(oldLogic.getChargedEnergyWithLowPower() / oldLogic.getChargedEnergy() * 1000) / 10.0f; - System.out.println(resultState.text + "\t" + testDescription + " \t(New: " - + Math.round(newLogic.getFinalSoc() * 100) / 100.0 + " | Old: " - + Math.round(oldLogic.getFinalSoc() * 100) / 100.0 + ") \t Energy: (New: " - + newLogic.getChargedEnergy() + "[" + newLogic.getChargedEnergyWithLowPower() + " -> " - + unefficientEnergy + "%] | Old: " + oldLogic.getChargedEnergy() + "[" - + oldLogic.getChargedEnergyWithLowPower() + " -> " + unefficientEnergyOld + "%])"); - - // fail("New logic results in a lower SoC (New: " + newLogic.getFinalSoc() + " | - // Old: "+ oldLogic.getFinalSoc() + ") - " + testDescription); - return resultState; - } - - private static class DelayChargeResult { - - private float finalSoc; - private float chargedEnergy; - private float chargedEnergyWithLowPower; - - public DelayChargeResult(float finalSoc, float chargedEnergy, float chargedEnergyWithLowPower) { - this.finalSoc = finalSoc; - this.chargedEnergy = chargedEnergy; - this.chargedEnergyWithLowPower = chargedEnergyWithLowPower; - } - - public float getFinalSoc() { - return this.finalSoc; - } - - public float getChargedEnergy() { - return this.chargedEnergy; - } - - public float getChargedEnergyWithLowPower() { - return this.chargedEnergyWithLowPower; - } - } - - private static enum DelayChargeResultState { - OK("OK - SoC as bevore"), // - WARNING("WARNING - Lower SoC"), // - PERFECT("PERFECT - Higher SoC"); - - private String text; - - DelayChargeResultState(String text) { - this.text = text; - } - } - @SuppressWarnings("deprecation") private static DelayChargeResult testOneDay(String testDescription, Integer[] productionPrediction, Integer[] consumptionPrediction, int soc, Optional targetMinuteOpt, int capacity, @@ -1658,6 +1584,80 @@ private static DelayChargeResult testOneDay(String testDescription, Integer[] pr return new DelayChargeResult(socFloat, totoalActivePower * 0.25f, totoalActivePowerLessEfficiency * 0.25f); } + private DelayChargeResultState testOneDay(String testDescription, Integer[] productionPrediction, + Integer[] consumptionPrediction, int soc, Optional targetMinuteOpt, int capacity, + int maxApparentPower, int allowedChargePower, DelayChargeRiskLevel riskLevel, Integer[] productionActual, + Integer[] consumptionActual, float resultBuffer) { + DelayChargeResultState resultState; + DelayChargeResult newLogic = ControllerEssGridOptimizedChargeImplTest.testOneDay(testDescription, + productionPrediction, consumptionPrediction, soc, targetMinuteOpt, capacity, maxApparentPower, + allowedChargePower, riskLevel, productionActual, consumptionActual, false); + + DelayChargeResult oldLogic = ControllerEssGridOptimizedChargeImplTest.testOneDay(testDescription, + productionPrediction, consumptionPrediction, soc, targetMinuteOpt, capacity, maxApparentPower, + allowedChargePower, riskLevel, productionActual, consumptionActual, true); + + if (newLogic.getFinalSoc() + resultBuffer < oldLogic.getFinalSoc()) { + resultState = DelayChargeResultState.WARNING; + } else if (newLogic.getFinalSoc() - resultBuffer > oldLogic.getFinalSoc()) { + resultState = DelayChargeResultState.PERFECT; + } else { + resultState = DelayChargeResultState.OK; + } + + float unefficientEnergy = Math + .round(newLogic.getChargedEnergyWithLowPower() / newLogic.getChargedEnergy() * 1000) / 10.0f; + float unefficientEnergyOld = Math + .round(oldLogic.getChargedEnergyWithLowPower() / oldLogic.getChargedEnergy() * 1000) / 10.0f; + System.out.println(resultState.text + "\t" + testDescription + " \t(New: " + + Math.round(newLogic.getFinalSoc() * 100) / 100.0 + " | Old: " + + Math.round(oldLogic.getFinalSoc() * 100) / 100.0 + ") \t Energy: (New: " + + newLogic.getChargedEnergy() + "[" + newLogic.getChargedEnergyWithLowPower() + " -> " + + unefficientEnergy + "%] | Old: " + oldLogic.getChargedEnergy() + "[" + + oldLogic.getChargedEnergyWithLowPower() + " -> " + unefficientEnergyOld + "%])"); + + // fail("New logic results in a lower SoC (New: " + newLogic.getFinalSoc() + " | + // Old: "+ oldLogic.getFinalSoc() + ") - " + testDescription); + return resultState; + } + + private static class DelayChargeResult { + + private float finalSoc; + private float chargedEnergy; + private float chargedEnergyWithLowPower; + + public DelayChargeResult(float finalSoc, float chargedEnergy, float chargedEnergyWithLowPower) { + this.finalSoc = finalSoc; + this.chargedEnergy = chargedEnergy; + this.chargedEnergyWithLowPower = chargedEnergyWithLowPower; + } + + public float getFinalSoc() { + return this.finalSoc; + } + + public float getChargedEnergy() { + return this.chargedEnergy; + } + + public float getChargedEnergyWithLowPower() { + return this.chargedEnergyWithLowPower; + } + } + + private static enum DelayChargeResultState { + OK("OK - SoC as bevore"), // + WARNING("WARNING - Lower SoC"), // + PERFECT("PERFECT - Higher SoC"); + + private String text; + + DelayChargeResultState(String text) { + this.text = text; + } + } + @Test public void calculateAvailEnergy_test() throws Exception { final var clock = new TimeLeapClock(Instant.parse("2020-01-01T08:00:00.00Z"), ZoneOffset.UTC); From 1949371e6de3d73807fc959edf05e4b69aedb5d8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 19 Oct 2024 23:35:47 +0200 Subject: [PATCH 159/173] Build(deps): Bump org.jetbrains.kotlin:kotlin-osgi-bundle from 2.0.20 to 2.0.21 in /cnf (#2840) * Build(deps): Bump org.jetbrains.kotlin:kotlin-osgi-bundle in /cnf Bumps org.jetbrains.kotlin:kotlin-osgi-bundle from 2.0.20 to 2.0.21. --- updated-dependencies: - dependency-name: org.jetbrains.kotlin:kotlin-osgi-bundle 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 dca7896bc3f..54b6fdc6f82 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -329,7 +329,7 @@ org.jetbrains.kotlin kotlin-osgi-bundle - 2.0.20 + 2.0.21 org.jetbrains.kotlinx diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index e210938f4fd..e02d41046c8 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -115,7 +115,7 @@ org.apache.felix.scr;version='[2.2.12,2.2.13)',\ org.apache.felix.webconsole;version='[5.0.8,5.0.9)',\ org.apache.felix.webconsole.plugins.ds;version='[2.3.0,2.3.1)',\ - org.jetbrains.kotlin.osgi-bundle;version='[2.0.20,2.0.21)',\ + org.jetbrains.kotlin.osgi-bundle;version='[2.0.21,2.0.22)',\ 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 fe957a9b082..3a1158ea4c1 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -418,7 +418,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='[2.0.20,2.0.21)',\ + org.jetbrains.kotlin.osgi-bundle;version='[2.0.21,2.0.22)',\ org.jsoup;version='[1.18.1,1.18.2)',\ org.jsr-305;version='[3.0.2,3.0.3)',\ org.openmuc.jmbus;version='[3.3.0,3.3.1)',\ From 40b3e5d5bc0a30a38bf76a63c2c246b9da629132 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Sun, 20 Oct 2024 00:24:02 +0200 Subject: [PATCH 160/173] Add common dependabot configuration --- .github/dependabot.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index fe2414bdf30..7e89f85d2cc 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -14,6 +14,9 @@ updates: patterns: - "org.dhatim:fastexcel" - "org.dhatim:fastexcel-reader" + bouncycastle: + patterns: + - "org.bouncycastle:*" - package-ecosystem: npm directory: "/ui" From 58cf33d634e87ab56c27abd496f41031dd2970b3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 20 Oct 2024 00:31:59 +0200 Subject: [PATCH 161/173] Build(deps): Bump org.bouncycastle:bcpkix-jdk15to18 from 1.77 to 1.78.1 in /cnf (#2841) * Build(deps): Bump org.bouncycastle:bcpkix-jdk15to18 in /cnf Bumps [org.bouncycastle:bcpkix-jdk15to18](https://github.com/bcgit/bc-java) from 1.77 to 1.78.1. - [Changelog](https://github.com/bcgit/bc-java/blob/main/docs/releasenotes.html) - [Commits](https://github.com/bcgit/bc-java/commits) --- updated-dependencies: - dependency-name: org.bouncycastle:bcpkix-jdk15to18 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Switch dependency to `jdk18on` (where `18` stands for JDK 1.8) * 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 | 12 ++++++++++-- io.openems.edge.application/EdgeApp.bndrun | 6 +++--- io.openems.edge.controller.api.mqtt/bnd.bnd | 4 ++-- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/cnf/pom.xml b/cnf/pom.xml index 54b6fdc6f82..4445a228051 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -281,9 +281,17 @@ + org.bouncycastle - bcpkix-jdk15to18 - 1.77 + bcpkix-jdk18on + 1.78.1 + + + + + org.bouncycastle + bcprov-jdk18on + 1.78.1 org.dhatim diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index 3a1158ea4c1..4dfeab59531 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -194,9 +194,9 @@ -runbundles: \ Java-WebSocket;version='[1.5.4,1.5.5)',\ - bcpkix;version='[1.77.0,1.77.1)',\ - bcprov;version='[1.77.0,1.77.1)',\ - bcutil;version='[1.77.0,1.77.1)',\ + bcpkix;version='[1.78.1,1.78.2)',\ + bcprov;version='[1.78.1,1.78.2)',\ + bcutil;version='[1.78.1,1.78.2)',\ com.fasterxml.aalto-xml;version='[1.3.3,1.3.4)',\ com.fazecast.jSerialComm;version='[2.10.4,2.10.5)',\ com.ghgande.j2mod;version='[3.2.1,3.2.2)',\ diff --git a/io.openems.edge.controller.api.mqtt/bnd.bnd b/io.openems.edge.controller.api.mqtt/bnd.bnd index 816ceaf6133..880e35262f0 100644 --- a/io.openems.edge.controller.api.mqtt/bnd.bnd +++ b/io.openems.edge.controller.api.mqtt/bnd.bnd @@ -5,8 +5,8 @@ Bundle-Version: 1.0.0.${tstamp} -buildpath: \ ${buildpath},\ - bcpkix;version='1.77',\ - bcprov;version='1.77',\ + bcpkix;version='1.78.1',\ + bcprov;version='1.78.1',\ io.openems.common,\ io.openems.edge.common,\ io.openems.edge.controller.api,\ From 34b5e3a9cde6a49b5c9fab2112781062c8e7fd43 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Tue, 22 Oct 2024 09:11:18 +0200 Subject: [PATCH 162/173] Energy Scheduler - next generation of Time-of-Use optimization (#2789) - Introduce generically usable EnergyScheduleHandler (ESH) for executing energy simulations and applying schedules - Provide nice debugLog output and channel "SimulationsPerQuarter" to detect performance issues - Use Cache for cost of Genotypes - **Add config property "Version" to be able to switch between old (only ESS, but fast and well tested) and new (generic ESH but slower) implementation.** - Attention: be sure to set EnergyScheduler (`Core.Energy`) and `Controller.Ess.Time-Of-Use-Tariff` to the same Version! - Introduce new implementation of `EnergyFlow` that uses linear constraint validation and optimization - Implement ESHs for - `Controller.Ess.Time-Of-Use-Tariff`, - `Controller.Ess.EmergencyCapacityReserve`, - `Controller.Ess.LimitTotalDischarge` and - `Controller.Ess.GridOptimizedCharge` (MANUAL only) - Old implementations are moved to `v1` packages and marked @Deprecated and will be removed in one of the next versions of OpenEMS. Unfortunately right now this leads to some mixed code. --- cnf/build.bnd | 1 + .../io/openems/edge/common/sum/DummySum.java | 44 ++ .../openems/edge/common/test/TestUtils.java | 23 + .../openems/edge/common/type/TypeUtils.java | 48 +- .../openems/edge/common/sum/DummySumTest.java | 22 + .../edge/common/type/TypeUtilsTest.java | 72 +- .../bnd.bnd | 1 + ...rollerEssEmergencyCapacityReserveImpl.java | 41 +- .../bnd.bnd | 3 +- .../ControllerEssFixActivePowerImpl.java | 54 +- .../ess/fixactivepower/package-info.java | 3 + .../bnd.bnd | 4 +- .../ControllerEssGridOptimizedChargeImpl.java | 108 ++- .../ess/gridoptimizedcharge/package-info.java | 3 + .../EnergyScheduleHandlerTest.java | 40 ++ .../bnd.bnd | 3 +- .../ControllerEssLimitTotalDischargeImpl.java | 34 +- .../bnd.bnd | 3 + .../ess/timeofusetariff/Config.java | 7 +- .../TimeOfUseTariffController.java | 15 +- .../TimeOfUseTariffControllerImpl.java | 208 +++++- .../controller/ess/timeofusetariff/Utils.java | 154 ++-- .../jsonrpc/GetScheduleRequest.java | 2 +- .../jsonrpc/GetScheduleResponse.java | 230 ++++++ .../timeofusetariff/jsonrpc/package-info.java | 3 + .../v1/EnergyScheduleHandlerV1.java | 88 +++ .../ess/timeofusetariff/v1/UtilsV1.java | 132 ++++ .../ess/timeofusetariff/v1/package-info.java | 3 + .../ess/timeofusetariff/MyConfig.java | 12 + .../TimeOfUseTariffControllerImplTest.java | 37 +- .../ess/timeofusetariff/UtilsTest.java | 109 ++- .../jsonrpc/GetScheduleResponseTest.java | 242 +++++++ .../timeofusetariff/jsonrpc}/TestData.java | 44 +- .../ess/timeofusetariff/v1/UtilsV1Test.java | 101 +++ io.openems.edge.energy.api/bnd.bnd | 1 + .../edge/energy/api/EnergyConstants.java | 15 + .../edge/energy/api/EnergySchedulable.java | 4 +- .../energy/api/EnergyScheduleHandler.java | 489 +++++++++++-- .../edge/energy/api/EnergyScheduler.java | 19 +- .../openems/edge/energy/api/EnergyUtils.java | 125 ++++ .../io/openems/edge/energy/api/Version.java | 20 + .../energy/api/simulation/Coefficient.java | 36 + .../energy/api/simulation/EnergyFlow.java | 657 ++++++++++++++++++ .../simulation/GlobalSimulationsContext.java | 325 +++++++++ .../api/simulation/OneSimulationContext.java | 59 ++ .../energy/api/simulation/package-info.java | 3 + .../test/AbstractDummyEnergySchedulable.java | 16 + .../api/test/DummyEnergySchedulable.java | 37 + .../test/DummyGlobalSimulationsContext.java | 99 +++ .../edge/energy/api/test/package-info.java | 3 + .../edge/energy/api/EnergyUtilsTest.java | 55 ++ .../GlobalSimulationsContextTest.java | 95 +++ io.openems.edge.energy/bnd.bnd | 13 +- .../src/io/openems/edge/energy/Config.java | 5 + .../edge/energy/EnergySchedulerImpl.java | 139 +++- .../io/openems/edge/energy/LogVerbosity.java | 2 +- .../edge/energy/optimizer/Optimizer.java | 279 +++++--- .../edge/energy/optimizer/QuickSchedules.java | 217 ++++++ .../energy/optimizer/SimulationResult.java | 177 +++++ .../edge/energy/optimizer/Simulator.java | 322 ++++++--- .../openems/edge/energy/optimizer/Utils.java | 503 ++------------ .../{ => v1}/jsonrpc/GetScheduleResponse.java | 7 +- .../optimizer/EnergyFlowV1.java} | 35 +- .../optimizer/GlobalContextV1.java} | 27 +- .../optimizer/InitialPopulationV1Utils.java} | 17 +- .../edge/energy/v1/optimizer/OptimizerV1.java | 159 +++++ .../optimizer/ParamsUtilsV1.java} | 17 +- .../optimizer/ParamsV1.java} | 15 +- .../{ => v1}/optimizer/ScheduleDatas.java | 21 +- .../edge/energy/v1/optimizer/SimulatorV1.java | 178 +++++ .../edge/energy/v1/optimizer/UtilsV1.java | 382 ++++++++++ .../edge/energy/EnergySchedulerImplTest.java | 104 +-- .../test/io/openems/edge/energy/MyConfig.java | 14 +- .../energy/api/simulation/EnergyFlowTest.java | 468 +++++++++++++ .../edge/energy/optimizer/OptimizerTest.java | 64 +- .../energy/optimizer/QuickSchedulesTest.java | 65 ++ .../optimizer/SimulationResultTest.java | 56 ++ .../edge/energy/optimizer/SimulatorTest.java | 236 ++----- .../edge/energy/optimizer/TestData.java | 67 ++ .../edge/energy/optimizer/UtilsTest.java | 334 +-------- .../edge/energy/optimizer/app/AppUtils.java | 108 +++ .../app/EnergyPerformanceTestApp.java | 44 ++ .../optimizer/app/RunOptimizerFromLogApp.java | 90 +++ .../energy/v1/EnergySchedulerImplTest.java | 127 ++++ .../jsonrpc/GetScheduleResponseTest.java | 7 +- .../optimizer/EnergyFlowV1Test.java} | 77 +- .../InitialPopulationV1UtilsTest.java} | 38 +- .../optimizer/IntegrationTestsV1.java} | 21 +- .../energy/v1/optimizer/OptimizerV1Test.java | 22 + .../optimizer/ParamsUtilsV1Test.java} | 9 +- .../optimizer/RunOptimizerFromLogV1App.java} | 15 +- .../optimizer/ScheduleDatasV1Test.java} | 31 +- .../energy/v1/optimizer/SimulatorV1Test.java | 208 ++++++ .../edge/energy/v1/optimizer/TestDataV1.java | 40 ++ .../edge/energy/v1/optimizer/UtilsV1Test.java | 304 ++++++++ .../ess/test/DummyManagedSymmetricEss.java | 9 + .../EssGenericManagedSymmetricImpl.java | 8 + .../api/test/AbstractDummyScheduler.java | 15 + .../scheduler/api/test/DummyScheduler.java | 46 ++ .../edge/scheduler/api/test/package-info.java | 3 + 100 files changed, 7502 insertions(+), 1595 deletions(-) create mode 100644 io.openems.edge.common/test/io/openems/edge/common/sum/DummySumTest.java create mode 100644 io.openems.edge.controller.ess.fixactivepower/src/io/openems/edge/controller/ess/fixactivepower/package-info.java create mode 100644 io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/package-info.java create mode 100644 io.openems.edge.controller.ess.gridoptimizedcharge/test/io/openems/edge/controller/ess/gridoptimizedcharge/EnergyScheduleHandlerTest.java rename {io.openems.edge.energy/src/io/openems/edge/energy => io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff}/jsonrpc/GetScheduleRequest.java (94%) create mode 100644 io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/GetScheduleResponse.java create mode 100644 io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/package-info.java create mode 100644 io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/v1/EnergyScheduleHandlerV1.java create mode 100644 io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/v1/UtilsV1.java create mode 100644 io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/v1/package-info.java create mode 100644 io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/GetScheduleResponseTest.java rename {io.openems.edge.energy/test/io/openems/edge/energy => io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/jsonrpc}/TestData.java (61%) create mode 100644 io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/v1/UtilsV1Test.java create mode 100644 io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergyConstants.java create mode 100644 io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergyUtils.java create mode 100644 io.openems.edge.energy.api/src/io/openems/edge/energy/api/Version.java create mode 100644 io.openems.edge.energy.api/src/io/openems/edge/energy/api/simulation/Coefficient.java create mode 100644 io.openems.edge.energy.api/src/io/openems/edge/energy/api/simulation/EnergyFlow.java create mode 100644 io.openems.edge.energy.api/src/io/openems/edge/energy/api/simulation/GlobalSimulationsContext.java create mode 100644 io.openems.edge.energy.api/src/io/openems/edge/energy/api/simulation/OneSimulationContext.java create mode 100644 io.openems.edge.energy.api/src/io/openems/edge/energy/api/simulation/package-info.java create mode 100644 io.openems.edge.energy.api/src/io/openems/edge/energy/api/test/AbstractDummyEnergySchedulable.java create mode 100644 io.openems.edge.energy.api/src/io/openems/edge/energy/api/test/DummyEnergySchedulable.java create mode 100644 io.openems.edge.energy.api/src/io/openems/edge/energy/api/test/DummyGlobalSimulationsContext.java create mode 100644 io.openems.edge.energy.api/src/io/openems/edge/energy/api/test/package-info.java create mode 100644 io.openems.edge.energy.api/test/io/openems/edge/energy/api/EnergyUtilsTest.java create mode 100644 io.openems.edge.energy.api/test/io/openems/edge/energy/api/simulation/GlobalSimulationsContextTest.java create mode 100644 io.openems.edge.energy/src/io/openems/edge/energy/optimizer/QuickSchedules.java create mode 100644 io.openems.edge.energy/src/io/openems/edge/energy/optimizer/SimulationResult.java rename io.openems.edge.energy/src/io/openems/edge/energy/{ => v1}/jsonrpc/GetScheduleResponse.java (90%) rename io.openems.edge.energy/src/io/openems/edge/energy/{optimizer/EnergyFlow.java => v1/optimizer/EnergyFlowV1.java} (76%) rename io.openems.edge.energy/src/io/openems/edge/energy/{optimizer/GlobalContext.java => v1/optimizer/GlobalContextV1.java} (67%) rename io.openems.edge.energy/src/io/openems/edge/energy/{optimizer/InitialPopulationUtils.java => v1/optimizer/InitialPopulationV1Utils.java} (91%) create mode 100644 io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/OptimizerV1.java rename io.openems.edge.energy/src/io/openems/edge/energy/{optimizer/ParamsUtils.java => v1/optimizer/ParamsUtilsV1.java} (88%) rename io.openems.edge.energy/src/io/openems/edge/energy/{optimizer/Params.java => v1/optimizer/ParamsV1.java} (94%) rename io.openems.edge.energy/src/io/openems/edge/energy/{ => v1}/optimizer/ScheduleDatas.java (94%) create mode 100644 io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/SimulatorV1.java create mode 100644 io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/UtilsV1.java create mode 100644 io.openems.edge.energy/test/io/openems/edge/energy/api/simulation/EnergyFlowTest.java create mode 100644 io.openems.edge.energy/test/io/openems/edge/energy/optimizer/QuickSchedulesTest.java create mode 100644 io.openems.edge.energy/test/io/openems/edge/energy/optimizer/SimulationResultTest.java create mode 100644 io.openems.edge.energy/test/io/openems/edge/energy/optimizer/TestData.java create mode 100644 io.openems.edge.energy/test/io/openems/edge/energy/optimizer/app/AppUtils.java create mode 100644 io.openems.edge.energy/test/io/openems/edge/energy/optimizer/app/EnergyPerformanceTestApp.java create mode 100644 io.openems.edge.energy/test/io/openems/edge/energy/optimizer/app/RunOptimizerFromLogApp.java create mode 100644 io.openems.edge.energy/test/io/openems/edge/energy/v1/EnergySchedulerImplTest.java rename io.openems.edge.energy/test/io/openems/edge/energy/{ => v1}/jsonrpc/GetScheduleResponseTest.java (86%) rename io.openems.edge.energy/test/io/openems/edge/energy/{optimizer/EnergyFlowTest.java => v1/optimizer/EnergyFlowV1Test.java} (74%) rename io.openems.edge.energy/test/io/openems/edge/energy/{optimizer/InitialPopulationUtilsTest.java => v1/optimizer/InitialPopulationV1UtilsTest.java} (70%) rename io.openems.edge.energy/test/io/openems/edge/energy/{optimizer/IntegrationTests.java => v1/optimizer/IntegrationTestsV1.java} (80%) create mode 100644 io.openems.edge.energy/test/io/openems/edge/energy/v1/optimizer/OptimizerV1Test.java rename io.openems.edge.energy/test/io/openems/edge/energy/{optimizer/ParamsUtilsTest.java => v1/optimizer/ParamsUtilsV1Test.java} (83%) rename io.openems.edge.energy/test/io/openems/edge/energy/{optimizer/RunOptimizerFromLogApp.java => v1/optimizer/RunOptimizerFromLogV1App.java} (66%) rename io.openems.edge.energy/test/io/openems/edge/energy/{optimizer/ScheduleDatasTest.java => v1/optimizer/ScheduleDatasV1Test.java} (85%) create mode 100644 io.openems.edge.energy/test/io/openems/edge/energy/v1/optimizer/SimulatorV1Test.java create mode 100644 io.openems.edge.energy/test/io/openems/edge/energy/v1/optimizer/TestDataV1.java create mode 100644 io.openems.edge.energy/test/io/openems/edge/energy/v1/optimizer/UtilsV1Test.java create mode 100644 io.openems.edge.scheduler.api/src/io/openems/edge/scheduler/api/test/AbstractDummyScheduler.java create mode 100644 io.openems.edge.scheduler.api/src/io/openems/edge/scheduler/api/test/DummyScheduler.java create mode 100644 io.openems.edge.scheduler.api/src/io/openems/edge/scheduler/api/test/package-info.java diff --git a/cnf/build.bnd b/cnf/build.bnd index 00cba399ba6..dbc9605619d 100644 --- a/cnf/build.bnd +++ b/cnf/build.bnd @@ -41,6 +41,7 @@ buildpath: \ org.osgi.service.metatype.annotations;version='1.4.1',\ org.osgi.util.promise;version='1.2.0',\ com.google.guava;version='33.3.1.jre',\ + com.google.guava.failureaccess;version='1.0.2',\ com.google.gson;version='2.11.0',\ testpath: \ diff --git a/io.openems.edge.common/src/io/openems/edge/common/sum/DummySum.java b/io.openems.edge.common/src/io/openems/edge/common/sum/DummySum.java index 41a246d6b33..2a2b9bd7568 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/sum/DummySum.java +++ b/io.openems.edge.common/src/io/openems/edge/common/sum/DummySum.java @@ -49,4 +49,48 @@ public DummySum withGridActivePower(int value) { return this.self(); } + /** + * Set {@link Sum.ChannelId#ESS_CAPACITY}. + * + * @param value the value + * @return myself + */ + public DummySum withEssCapacity(int value) { + withValue(this, Sum.ChannelId.ESS_CAPACITY, value); + return this.self(); + } + + /** + * Set {@link Sum.ChannelId#ESS_SOC}. + * + * @param value the value + * @return myself + */ + public DummySum withEssSoc(int value) { + withValue(this, Sum.ChannelId.ESS_SOC, value); + return this.self(); + } + + /** + * Set {@link Sum.ChannelId#ESS_MIN_DISCHARGE_POWER}. + * + * @param value the value + * @return myself + */ + public DummySum withEssMinDischargePower(int value) { + withValue(this, Sum.ChannelId.ESS_MIN_DISCHARGE_POWER, value); + return this.self(); + } + + /** + * Set {@link Sum.ChannelId#ESS_MAX_DISCHARGE_POWER}. + * + * @param value the value + * @return myself + */ + public DummySum withEssMaxDischargePower(int value) { + withValue(this, Sum.ChannelId.ESS_MAX_DISCHARGE_POWER, value); + return this.self(); + } + } diff --git a/io.openems.edge.common/src/io/openems/edge/common/test/TestUtils.java b/io.openems.edge.common/src/io/openems/edge/common/test/TestUtils.java index f8f0e2e7a10..4cb54a3f37e 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/test/TestUtils.java +++ b/io.openems.edge.common/src/io/openems/edge/common/test/TestUtils.java @@ -3,10 +3,13 @@ import java.io.IOException; import java.net.ServerSocket; import java.time.Instant; +import java.util.function.BiFunction; +import java.util.function.Function; import io.openems.common.test.TimeLeapClock; import io.openems.edge.common.channel.Channel; import io.openems.edge.common.channel.ChannelId; +import io.openems.edge.common.channel.value.Value; import io.openems.edge.common.component.OpenemsComponent; public class TestUtils { @@ -80,4 +83,24 @@ public static void withValue(Channel channel, Object value) { channel.setNextValue(value); channel.nextProcessImage(); } + + /** + * Helper to test a {@link #withValue(Channel, Object)} method in a JUnit test. + * + * @param the type of the {@link AbstractDummyOpenemsComponent} + * @param sut the actual system-under-test + * @param setter the getChannel getter method + * @param getter the withChannel setter method + */ + public static void testWithValue(T sut, BiFunction setter, Function> getter) { + var before = getter.apply(sut).get(); + if (before != null) { + throw new IllegalArgumentException("TestUtils.testWithValue() expected [null] got [" + before + "]"); + } + setter.apply(sut, 123); + var after = getter.apply(sut).get().intValue(); + if (after != 123) { + throw new IllegalArgumentException("TestUtils.testWithValue() expected [123] got [" + after + "]"); + } + } } 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 babada99a81..d43a8bc6716 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 @@ -364,23 +364,15 @@ public static JsonElement getAsJson(OpenemsType type, Object originalValue) { return JsonNull.INSTANCE; } var value = TypeUtils.getAsType(type, originalValue); - switch (type) { - case BOOLEAN: - return new JsonPrimitive((Boolean) value ? 1 : 0); - case SHORT: - return new JsonPrimitive((Short) value); - case INTEGER: - return new JsonPrimitive((Integer) value); - case LONG: - return new JsonPrimitive((Long) value); - case FLOAT: - return new JsonPrimitive((Float) value); - case DOUBLE: - return new JsonPrimitive((Double) value); - case STRING: - return new JsonPrimitive((String) value); - } - throw new IllegalArgumentException("Converter for value [" + value + "] to JSON is not implemented."); + return switch (type) { + case BOOLEAN -> new JsonPrimitive((Boolean) value ? 1 : 0); + case SHORT -> new JsonPrimitive((Short) value); + case INTEGER -> new JsonPrimitive((Integer) value); + case LONG -> new JsonPrimitive((Long) value); + case FLOAT -> new JsonPrimitive((Float) value); + case DOUBLE -> new JsonPrimitive((Double) value); + case STRING -> new JsonPrimitive((String) value); + }; } /** @@ -427,6 +419,28 @@ public static Integer sum(Integer... values) { return result; } + /** + * Safely add Floats. If one of them is null it is considered '0'. If all of + * them are null, 'null' is returned. + * + * @param values the {@link Float} values + * @return the sum + */ + public static Float sum(Float... values) { + Float result = null; + for (Float value : values) { + if (value == null) { + continue; + } + if (result == null) { + result = value; + } else { + result += value; + } + } + return result; + } + /** * Safely add Longs. If one of them is null it is considered '0'. If all of them * are null, 'null' is returned. diff --git a/io.openems.edge.common/test/io/openems/edge/common/sum/DummySumTest.java b/io.openems.edge.common/test/io/openems/edge/common/sum/DummySumTest.java new file mode 100644 index 00000000000..8cb89d3a6d2 --- /dev/null +++ b/io.openems.edge.common/test/io/openems/edge/common/sum/DummySumTest.java @@ -0,0 +1,22 @@ +package io.openems.edge.common.sum; + +import static io.openems.edge.common.test.TestUtils.testWithValue; + +import org.junit.Test; + +import io.openems.common.exceptions.OpenemsException; + +public class DummySumTest { + + @Test + public void test() throws OpenemsException { + final var sut = new DummySum(); + + testWithValue(sut, DummySum::withProductionAcActivePower, Sum::getProductionAcActivePower); + testWithValue(sut, DummySum::withGridActivePower, Sum::getGridActivePower); + testWithValue(sut, DummySum::withEssCapacity, Sum::getEssCapacity); + testWithValue(sut, DummySum::withEssSoc, Sum::getEssSoc); + testWithValue(sut, DummySum::withEssMinDischargePower, Sum::getEssMinDischargePower); + testWithValue(sut, DummySum::withEssMaxDischargePower, Sum::getEssMaxDischargePower); + } +} diff --git a/io.openems.edge.common/test/io/openems/edge/common/type/TypeUtilsTest.java b/io.openems.edge.common/test/io/openems/edge/common/type/TypeUtilsTest.java index 83c76584a1c..f5ff84b47f3 100644 --- a/io.openems.edge.common/test/io/openems/edge/common/type/TypeUtilsTest.java +++ b/io.openems.edge.common/test/io/openems/edge/common/type/TypeUtilsTest.java @@ -1,5 +1,15 @@ package io.openems.edge.common.type; +import static com.google.gson.JsonNull.INSTANCE; +import static io.openems.common.types.OpenemsType.BOOLEAN; +import static io.openems.common.types.OpenemsType.DOUBLE; +import static io.openems.common.types.OpenemsType.FLOAT; +import static io.openems.common.types.OpenemsType.INTEGER; +import static io.openems.common.types.OpenemsType.LONG; +import static io.openems.common.types.OpenemsType.SHORT; +import static io.openems.common.types.OpenemsType.STRING; +import static io.openems.edge.common.type.TypeUtils.getAsJson; +import static io.openems.edge.common.type.TypeUtils.sum; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; @@ -7,8 +17,9 @@ import org.junit.Test; +import com.google.gson.JsonPrimitive; + import io.openems.common.function.ThrowingRunnable; -import io.openems.common.types.OpenemsType; import io.openems.common.types.OptionsEnum; import io.openems.edge.common.channel.value.Value; @@ -81,8 +92,8 @@ public void testMin() { @Test public void testSumDouble() { - assertNull(TypeUtils.sum((Double) null, null)); - assertEquals(4.0, TypeUtils.sum(1.5, 2.5), 0.1); + assertNull(sum((Double) null, null)); + assertEquals(4.0, sum(1.5, 2.5), 0.1); } @Test @@ -269,6 +280,47 @@ public void testGetAsType() { } } + @Test + public void testGetAsJson() { + assertEquals(INSTANCE, getAsJson(INTEGER, null)); + assertEquals(new JsonPrimitive(0), getAsJson(BOOLEAN, false)); + assertEquals(new JsonPrimitive(1), getAsJson(BOOLEAN, true)); + assertEquals(new JsonPrimitive(123), getAsJson(SHORT, 123)); + assertEquals(new JsonPrimitive(234), getAsJson(INTEGER, 234)); + assertEquals(new JsonPrimitive(345), getAsJson(LONG, 345)); + assertEquals(new JsonPrimitive(45.6F), getAsJson(FLOAT, 45.6F)); + assertEquals(new JsonPrimitive(56.7), getAsJson(DOUBLE, 56.7)); + assertEquals(new JsonPrimitive("678"), getAsJson(STRING, "678")); + } + + @Test + public void sumInteger() { + assertEquals(6, sum(1, 2, 3).intValue()); + assertNull(sum((Integer) null)); + assertEquals(6, sum(1, null, 2, 3).intValue()); + } + + @Test + public void sumFloat() { + assertEquals(6F, sum(1F, 2F, 3F).floatValue(), 0.001F); + assertNull(sum((Float) null)); + assertEquals(6F, sum(1F, null, 2F, 3F).floatValue(), 0.001F); + } + + @Test + public void sumLong() { + assertEquals(6L, sum(1L, 2L, 3L).longValue()); + assertNull(sum((Long) null)); + assertEquals(6L, sum(1L, null, 2L, 3L).longValue()); + } + + @Test + public void sumDouble() { + assertEquals(6., sum(1., 2., 3.).doubleValue(), 0.001); + assertNull(sum((Double) null)); + assertEquals(6., sum(1., null, 2., 3.).doubleValue(), 0.001); + } + private static void assertException(ThrowingRunnable runnable) { try { runnable.run(); @@ -279,31 +331,31 @@ private static void assertException(ThrowingRunnable runnable) { } private static Boolean getAsBoolean(Object value) { - return TypeUtils.getAsType(OpenemsType.BOOLEAN, value); + return TypeUtils.getAsType(BOOLEAN, value); } private static Short getAsShort(Object value) { - return TypeUtils.getAsType(OpenemsType.SHORT, value); + return TypeUtils.getAsType(SHORT, value); } private static Integer getAsInteger(Object value) { - return TypeUtils.getAsType(OpenemsType.INTEGER, value); + return TypeUtils.getAsType(INTEGER, value); } private static Long getAsLong(Object value) { - return TypeUtils.getAsType(OpenemsType.LONG, value); + return TypeUtils.getAsType(LONG, value); } private static Float getAsFloat(Object value) { - return TypeUtils.getAsType(OpenemsType.FLOAT, value); + return TypeUtils.getAsType(FLOAT, value); } private static Double getAsDouble(Object value) { - return TypeUtils.getAsType(OpenemsType.DOUBLE, value); + return TypeUtils.getAsType(DOUBLE, value); } private static String getAsString(Object value) { - return TypeUtils.getAsType(OpenemsType.STRING, value); + return TypeUtils.getAsType(STRING, value); } private static enum MyOptionsEnum implements OptionsEnum { diff --git a/io.openems.edge.controller.ess.emergencycapacityreserve/bnd.bnd b/io.openems.edge.controller.ess.emergencycapacityreserve/bnd.bnd index 3f814d45c0c..0a8bfd62f05 100644 --- a/io.openems.edge.controller.ess.emergencycapacityreserve/bnd.bnd +++ b/io.openems.edge.controller.ess.emergencycapacityreserve/bnd.bnd @@ -8,6 +8,7 @@ Bundle-Version: 1.0.0.${tstamp} io.openems.common,\ io.openems.edge.common,\ io.openems.edge.controller.api,\ + io.openems.edge.energy.api,\ io.openems.edge.ess.api,\ io.openems.edge.ess.generic,\ diff --git a/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/ControllerEssEmergencyCapacityReserveImpl.java b/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/ControllerEssEmergencyCapacityReserveImpl.java index 35ba0a200aa..68e1ad4fc09 100644 --- a/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/ControllerEssEmergencyCapacityReserveImpl.java +++ b/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/ControllerEssEmergencyCapacityReserveImpl.java @@ -1,6 +1,10 @@ package io.openems.edge.controller.ess.emergencycapacityreserve; +import static io.openems.edge.energy.api.EnergyUtils.socToEnergy; +import static java.lang.Math.max; + import java.util.OptionalInt; +import java.util.function.Supplier; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentContext; @@ -25,6 +29,8 @@ import io.openems.edge.controller.ess.emergencycapacityreserve.statemachine.Context; import io.openems.edge.controller.ess.emergencycapacityreserve.statemachine.StateMachine; import io.openems.edge.controller.ess.emergencycapacityreserve.statemachine.StateMachine.State; +import io.openems.edge.energy.api.EnergySchedulable; +import io.openems.edge.energy.api.EnergyScheduleHandler; import io.openems.edge.ess.api.ManagedSymmetricEss; @Designate(ocd = Config.class, factory = true) @@ -34,7 +40,7 @@ configurationPolicy = ConfigurationPolicy.REQUIRE // ) public class ControllerEssEmergencyCapacityReserveImpl extends AbstractOpenemsComponent - implements ControllerEssEmergencyCapacityReserve, Controller, OpenemsComponent { + implements ControllerEssEmergencyCapacityReserve, EnergySchedulable, Controller, OpenemsComponent { /** Minimum reserve SoC value in [%]. */ private static final int reservSocMinValue = 5; @@ -42,6 +48,7 @@ public class ControllerEssEmergencyCapacityReserveImpl extends AbstractOpenemsCo private static final int reservSocMaxValue = 100; private final Logger log = LoggerFactory.getLogger(ControllerEssEmergencyCapacityReserveImpl.class); + private final EnergyScheduleHandler energyScheduleHandler; private final StateMachine stateMachine = new StateMachine(State.NO_LIMIT); private final RampFilter rampFilter = new RampFilter(); @@ -65,6 +72,10 @@ public ControllerEssEmergencyCapacityReserveImpl() { Controller.ChannelId.values(), // ControllerEssEmergencyCapacityReserve.ChannelId.values() // ); + this.energyScheduleHandler = buildEnergyScheduleHandler(// + () -> this.config.isReserveSocEnabled() // + ? this.config.reserveSoc() // + : null); } @Activate @@ -77,6 +88,7 @@ private void activate(ComponentContext context, Config config) { protected void modified(ComponentContext context, String id, String alias, boolean enabled) { super.modified(context, id, alias, enabled); this.updateConfig(this.config); + this.energyScheduleHandler.triggerReschedule(); } @Override @@ -191,4 +203,31 @@ private OptionalInt getLastValidSoc(IntegerReadChannel channel) { .mapToInt(Value::get) // .findFirst(); } + + /** + * Builds the {@link EnergyScheduleHandler}. + * + *

      + * This is public so that it can be used by the EnergyScheduler integration + * test. + * + * @param minSoc supplier for the configured minSoc + * @return a {@link EnergyScheduleHandler} + */ + public static EnergyScheduleHandler buildEnergyScheduleHandler(Supplier minSoc) { + return EnergyScheduleHandler.of(// + simContext -> minSoc.get() == null // + ? null // + : socToEnergy(simContext.ess().totalEnergy(), minSoc.get()), // + (simContext, period, energyFlow, minEnergy) -> { + if (minEnergy != null) { + energyFlow.setEssMaxDischarge(max(0, simContext.getEssInitial() - minEnergy)); + } + }); + } + + @Override + public EnergyScheduleHandler getEnergyScheduleHandler() { + return this.energyScheduleHandler; + } } diff --git a/io.openems.edge.controller.ess.fixactivepower/bnd.bnd b/io.openems.edge.controller.ess.fixactivepower/bnd.bnd index 9b0e7d57001..38c5412d005 100644 --- a/io.openems.edge.controller.ess.fixactivepower/bnd.bnd +++ b/io.openems.edge.controller.ess.fixactivepower/bnd.bnd @@ -8,8 +8,9 @@ Bundle-Version: 1.0.0.${tstamp} io.openems.common,\ io.openems.edge.common,\ io.openems.edge.controller.api,\ + io.openems.edge.energy.api,\ io.openems.edge.ess.api,\ io.openems.edge.timedata.api,\ - + -testpath: \ ${testpath} diff --git a/io.openems.edge.controller.ess.fixactivepower/src/io/openems/edge/controller/ess/fixactivepower/ControllerEssFixActivePowerImpl.java b/io.openems.edge.controller.ess.fixactivepower/src/io/openems/edge/controller/ess/fixactivepower/ControllerEssFixActivePowerImpl.java index ad3f5905e0e..2fe3a64a3e7 100644 --- a/io.openems.edge.controller.ess.fixactivepower/src/io/openems/edge/controller/ess/fixactivepower/ControllerEssFixActivePowerImpl.java +++ b/io.openems.edge.controller.ess.fixactivepower/src/io/openems/edge/controller/ess/fixactivepower/ControllerEssFixActivePowerImpl.java @@ -1,5 +1,9 @@ package io.openems.edge.controller.ess.fixactivepower; +import static io.openems.edge.energy.api.EnergyUtils.toEnergy; + +import java.util.function.Supplier; + import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.annotations.Activate; @@ -17,10 +21,13 @@ import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.controller.api.Controller; +import io.openems.edge.energy.api.EnergySchedulable; +import io.openems.edge.energy.api.EnergyScheduleHandler; import io.openems.edge.ess.api.HybridEss; import io.openems.edge.ess.api.ManagedSymmetricEss; import io.openems.edge.ess.api.PowerConstraint; import io.openems.edge.ess.power.api.Pwr; +import io.openems.edge.ess.power.api.Relationship; import io.openems.edge.timedata.api.Timedata; import io.openems.edge.timedata.api.TimedataProvider; import io.openems.edge.timedata.api.utils.CalculateActiveTime; @@ -32,10 +39,11 @@ configurationPolicy = ConfigurationPolicy.REQUIRE // ) public class ControllerEssFixActivePowerImpl extends AbstractOpenemsComponent - implements ControllerEssFixActivePower, Controller, OpenemsComponent, TimedataProvider { + implements ControllerEssFixActivePower, EnergySchedulable, Controller, OpenemsComponent, TimedataProvider { private final CalculateActiveTime calculateCumulatedActiveTime = new CalculateActiveTime(this, ControllerEssFixActivePower.ChannelId.CUMULATED_ACTIVE_TIME); + private final EnergyScheduleHandler energyScheduleHandler; @Reference private ConfigurationAdmin cm; @@ -54,6 +62,13 @@ public ControllerEssFixActivePowerImpl() { Controller.ChannelId.values(), // ControllerEssFixActivePower.ChannelId.values() // ); + this.energyScheduleHandler = buildEnergyScheduleHandler(() -> new EshContext(// + this.config.mode(), // + toEnergy(switch (this.config.phase()) { + case ALL -> this.config.power(); + case L1, L2, L3 -> this.config.power() * 3; + }), // + this.config.relationship())); } @Activate @@ -70,6 +85,7 @@ private void modified(ComponentContext context, Config config) { if (this.applyConfig(context, config)) { return; } + this.energyScheduleHandler.triggerReschedule(); } private boolean applyConfig(ComponentContext context, Config config) { @@ -137,4 +153,40 @@ protected static Integer getAcPower(ManagedSymmetricEss ess, HybridEssMode hybri public Timedata getTimedata() { return this.timedata; } + + /** + * Builds the {@link EnergyScheduleHandler}. + * + *

      + * This is public so that it can be used by the EnergyScheduler integration + * test. + * + * @param context a supplier for the configured {@link EshContext} + * @return a {@link EnergyScheduleHandler} + */ + public static EnergyScheduleHandler buildEnergyScheduleHandler(Supplier context) { + return EnergyScheduleHandler.of(// + simContext -> context.get(), // + (simContext, period, energyFlow, ctrlContext) -> { + switch (ctrlContext.mode) { + case MANUAL_ON: + switch (ctrlContext.relationship) { + case EQUALS -> energyFlow.setEss(ctrlContext.energy); + case GREATER_OR_EQUALS -> energyFlow.setEssMaxCharge(-ctrlContext.energy); + case LESS_OR_EQUALS -> energyFlow.setEssMaxDischarge(ctrlContext.energy); + } + break; + case MANUAL_OFF: + break; + } + }); + } + + public static record EshContext(Mode mode, int energy, Relationship relationship) { + } + + @Override + public EnergyScheduleHandler getEnergyScheduleHandler() { + return this.energyScheduleHandler; + } } \ No newline at end of file diff --git a/io.openems.edge.controller.ess.fixactivepower/src/io/openems/edge/controller/ess/fixactivepower/package-info.java b/io.openems.edge.controller.ess.fixactivepower/src/io/openems/edge/controller/ess/fixactivepower/package-info.java new file mode 100644 index 00000000000..aab27855be8 --- /dev/null +++ b/io.openems.edge.controller.ess.fixactivepower/src/io/openems/edge/controller/ess/fixactivepower/package-info.java @@ -0,0 +1,3 @@ +@org.osgi.annotation.versioning.Version("1.0.0") +@org.osgi.annotation.bundle.Export +package io.openems.edge.controller.ess.fixactivepower; diff --git a/io.openems.edge.controller.ess.gridoptimizedcharge/bnd.bnd b/io.openems.edge.controller.ess.gridoptimizedcharge/bnd.bnd index ed3817a1757..d00c7cb673d 100644 --- a/io.openems.edge.controller.ess.gridoptimizedcharge/bnd.bnd +++ b/io.openems.edge.controller.ess.gridoptimizedcharge/bnd.bnd @@ -8,10 +8,12 @@ Bundle-Version: 1.0.0.${tstamp} io.openems.common,\ io.openems.edge.common,\ io.openems.edge.controller.api,\ + io.openems.edge.energy.api,\ io.openems.edge.ess.api,\ io.openems.edge.meter.api,\ io.openems.edge.predictor.api,\ io.openems.edge.timedata.api,\ -testpath: \ - ${testpath} + ${testpath},\ + org.apache.commons.math3,\ diff --git a/io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedChargeImpl.java b/io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedChargeImpl.java index cb1ffc764a6..dc05f7914c4 100644 --- a/io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedChargeImpl.java +++ b/io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedChargeImpl.java @@ -1,11 +1,19 @@ package io.openems.edge.controller.ess.gridoptimizedcharge; +import static java.util.stream.Collectors.groupingBy; + +import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; +import java.time.ZonedDateTime; import java.time.temporal.ChronoField; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; +import java.util.Collections; import java.util.OptionalDouble; +import java.util.OptionalInt; +import java.util.function.Supplier; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentContext; @@ -22,6 +30,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.collect.ImmutableSortedMap; + import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; import io.openems.edge.common.channel.IntegerReadChannel; @@ -33,6 +43,8 @@ import io.openems.edge.common.filter.RampFilter; import io.openems.edge.common.sum.Sum; import io.openems.edge.controller.api.Controller; +import io.openems.edge.energy.api.EnergySchedulable; +import io.openems.edge.energy.api.EnergyScheduleHandler; import io.openems.edge.ess.api.ManagedSymmetricEss; import io.openems.edge.meter.api.ElectricityMeter; import io.openems.edge.predictor.api.manager.PredictorManager; @@ -46,8 +58,9 @@ immediate = true, // configurationPolicy = ConfigurationPolicy.REQUIRE // ) -public class ControllerEssGridOptimizedChargeImpl extends AbstractOpenemsComponent implements - ControllerEssGridOptimizedCharge, Controller, OpenemsComponent, TimedataProvider, ComponentManagerProvider { +public class ControllerEssGridOptimizedChargeImpl extends AbstractOpenemsComponent + implements ControllerEssGridOptimizedCharge, EnergySchedulable, Controller, OpenemsComponent, TimedataProvider, + ComponentManagerProvider { /** * Buffer in watt taken into account in the calculation of the first and last @@ -58,6 +71,7 @@ public class ControllerEssGridOptimizedChargeImpl extends AbstractOpenemsCompone protected final RampFilter rampFilter = new RampFilter(); private final Logger log = LoggerFactory.getLogger(ControllerEssGridOptimizedChargeImpl.class); + private final EnergyScheduleHandler energyScheduleHandler; /* * Time counter for the important states @@ -107,6 +121,9 @@ public ControllerEssGridOptimizedChargeImpl() { Controller.ChannelId.values(), // ControllerEssGridOptimizedCharge.ChannelId.values() // ); + this.energyScheduleHandler = buildEnergyScheduleHandler(// + () -> this.config.mode(), // + () -> DelayCharge.parseTime(this.config.manualTargetTime())); } @Activate @@ -442,4 +459,91 @@ public Timedata getTimedata() { return this.timedata; } + /** + * Builds the {@link EnergyScheduleHandler}. + * + *

      + * This is public so that it can be used by the EnergyScheduler integration + * test. + * + * @param mode a supplier for the configured {@link Mode} + * @param manualTargetTime a supplier for the configured manualTargetTime + * @return a {@link EnergyScheduleHandler} + */ + public static EnergyScheduleHandler buildEnergyScheduleHandler(Supplier mode, + Supplier manualTargetTime) { + return EnergyScheduleHandler.of(// + simContext -> { + // TODO try to reuse existing logic for parsing, calculating limits, etc.; for + // now this only works for current day and MANUAL mode + final var limits = ImmutableSortedMap.naturalOrder(); + final var periodsPerDay = simContext.periods().stream() // + .collect(groupingBy(p -> p.time().truncatedTo(ChronoUnit.DAYS))); + if (!periodsPerDay.isEmpty()) { + final var firstDayMignight = Collections.min(periodsPerDay.keySet()); + + for (var entry : periodsPerDay.entrySet()) { + // Find target time for this day + var midnight = entry.getKey(); // beginning of this day + var periods = entry.getValue(); // periods of this day + ZonedDateTime targetTime = switch (mode.get()) { + case OFF -> midnight; // Can not happen + case MANUAL -> midnight // + .withHour(manualTargetTime.get().getHour()) // + .withMinute(manualTargetTime.get().getMinute()); + case AUTOMATIC -> midnight; // TODO + }; + // Find first period with Production > Consumption + var firstExcessEnergyOpt = periods.stream() // + .filter(p -> p.production() > p.consumption()) // + .findFirst(); + if (firstExcessEnergyOpt.isEmpty() + || targetTime.isBefore(firstExcessEnergyOpt.get().time())) { + // Production exceeds Consumption never or too late on this day + // -> set no limit for this day + limits.put(midnight, OptionalInt.empty()); + continue; + } + var firstExcessEnergy = firstExcessEnergyOpt.get().time(); + + // Set no limit for early hours of the day + if (firstExcessEnergy.isAfter(midnight)) { + limits.put(midnight, OptionalInt.empty()); + } + + // Calculate actual charge limit + var noOfQuarters = (int) Duration.between(firstExcessEnergy, targetTime).toMinutes() / 15; + final var totalEnergy = midnight == firstDayMignight // + ? // use actual data for first day + simContext.ess().totalEnergy() - simContext.ess().currentEnergy() + : // assume full charge from second day + simContext.ess().totalEnergy(); + limits.put(firstExcessEnergy, OptionalInt.of(totalEnergy / noOfQuarters)); + + // No limit after targetTime + limits.put(targetTime, OptionalInt.empty()); + } + } + + return new EshContext(limits.build()); + }, // + (simContext, period, energyFlow, ctrlContext) -> { + var limitEntry = ctrlContext.limits.floorEntry(period.time()); + if (limitEntry == null) { + return; + } + var limit = limitEntry.getValue(); + if (limit.isPresent()) { + energyFlow.setEssMaxCharge(limit.getAsInt()); + } + }); + } + + private static record EshContext(ImmutableSortedMap limits) { + } + + @Override + public EnergyScheduleHandler getEnergyScheduleHandler() { + return this.energyScheduleHandler; + } } diff --git a/io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/package-info.java b/io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/package-info.java new file mode 100644 index 00000000000..9736f9da6be --- /dev/null +++ b/io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/package-info.java @@ -0,0 +1,3 @@ +@org.osgi.annotation.versioning.Version("1.0.0") +@org.osgi.annotation.bundle.Export +package io.openems.edge.controller.ess.gridoptimizedcharge; diff --git a/io.openems.edge.controller.ess.gridoptimizedcharge/test/io/openems/edge/controller/ess/gridoptimizedcharge/EnergyScheduleHandlerTest.java b/io.openems.edge.controller.ess.gridoptimizedcharge/test/io/openems/edge/controller/ess/gridoptimizedcharge/EnergyScheduleHandlerTest.java new file mode 100644 index 00000000000..0f33e93c960 --- /dev/null +++ b/io.openems.edge.controller.ess.gridoptimizedcharge/test/io/openems/edge/controller/ess/gridoptimizedcharge/EnergyScheduleHandlerTest.java @@ -0,0 +1,40 @@ +package io.openems.edge.controller.ess.gridoptimizedcharge; + +import static org.junit.Assert.assertEquals; + +import java.time.LocalTime; + +import org.apache.commons.math3.optim.nonlinear.scalar.GoalType; +import org.junit.Test; + +import io.openems.edge.energy.api.EnergyScheduleHandler; +import io.openems.edge.energy.api.EnergyScheduleHandler.AbstractEnergyScheduleHandler; +import io.openems.edge.energy.api.simulation.Coefficient; +import io.openems.edge.energy.api.simulation.EnergyFlow; +import io.openems.edge.energy.api.simulation.GlobalSimulationsContext; +import io.openems.edge.energy.api.simulation.OneSimulationContext; +import io.openems.edge.energy.api.test.DummyGlobalSimulationsContext; + +public class EnergyScheduleHandlerTest { + + @Test + public void testManual() { + var esh = ControllerEssGridOptimizedChargeImpl.buildEnergyScheduleHandler(// + () -> Mode.MANUAL, // + () -> LocalTime.of(10, 00)); + var gsc = DummyGlobalSimulationsContext.fromHandlers(esh); + ((AbstractEnergyScheduleHandler) esh /* this is safe */).initialize(gsc); + + assertEquals(3894, getEssMaxCharge(gsc, esh, 0)); + assertEquals(1214, getEssMaxCharge(gsc, esh, 26)); + assertEquals(4000, getEssMaxCharge(gsc, esh, 40)); + } + + private static int getEssMaxCharge(GlobalSimulationsContext gsc, EnergyScheduleHandler esh, int periodIndex) { + var osc = OneSimulationContext.from(gsc); + var period = gsc.periods().get(periodIndex); + var ef = EnergyFlow.Model.from(osc, period); + ((EnergyScheduleHandler.WithOnlyOneState) esh).simulatePeriod(OneSimulationContext.from(gsc), period, ef); + return ((int) ef.getExtremeCoefficientValue(Coefficient.ESS, GoalType.MINIMIZE)) * -1; + } +} diff --git a/io.openems.edge.controller.ess.limittotaldischarge/bnd.bnd b/io.openems.edge.controller.ess.limittotaldischarge/bnd.bnd index 0f4d0e0a95c..db75c019243 100644 --- a/io.openems.edge.controller.ess.limittotaldischarge/bnd.bnd +++ b/io.openems.edge.controller.ess.limittotaldischarge/bnd.bnd @@ -8,7 +8,8 @@ Bundle-Version: 1.0.0.${tstamp} io.openems.common,\ io.openems.edge.common,\ io.openems.edge.controller.api,\ - io.openems.edge.ess.api + io.openems.edge.energy.api,\ + io.openems.edge.ess.api,\ -testpath: \ ${testpath} diff --git a/io.openems.edge.controller.ess.limittotaldischarge/src/io/openems/edge/controller/ess/limittotaldischarge/ControllerEssLimitTotalDischargeImpl.java b/io.openems.edge.controller.ess.limittotaldischarge/src/io/openems/edge/controller/ess/limittotaldischarge/ControllerEssLimitTotalDischargeImpl.java index a75ecf85f1b..e826546a526 100644 --- a/io.openems.edge.controller.ess.limittotaldischarge/src/io/openems/edge/controller/ess/limittotaldischarge/ControllerEssLimitTotalDischargeImpl.java +++ b/io.openems.edge.controller.ess.limittotaldischarge/src/io/openems/edge/controller/ess/limittotaldischarge/ControllerEssLimitTotalDischargeImpl.java @@ -1,8 +1,12 @@ package io.openems.edge.controller.ess.limittotaldischarge; +import static io.openems.edge.energy.api.EnergyUtils.socToEnergy; +import static java.lang.Math.max; + import java.time.Duration; import java.time.Instant; import java.util.Optional; +import java.util.function.IntSupplier; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.annotations.Activate; @@ -19,6 +23,8 @@ import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.controller.api.Controller; +import io.openems.edge.energy.api.EnergySchedulable; +import io.openems.edge.energy.api.EnergyScheduleHandler; import io.openems.edge.ess.api.ManagedSymmetricEss; import io.openems.edge.ess.power.api.Phase; import io.openems.edge.ess.power.api.Pwr; @@ -30,9 +36,10 @@ configurationPolicy = ConfigurationPolicy.REQUIRE // ) public class ControllerEssLimitTotalDischargeImpl extends AbstractOpenemsComponent - implements ControllerEssLimitTotalDischarge, Controller, OpenemsComponent { + implements ControllerEssLimitTotalDischarge, EnergySchedulable, Controller, OpenemsComponent { private final Logger log = LoggerFactory.getLogger(ControllerEssLimitTotalDischargeImpl.class); + private final EnergyScheduleHandler energyScheduleHandler; @Reference private ComponentManager componentManager; @@ -55,6 +62,8 @@ public ControllerEssLimitTotalDischargeImpl() { Controller.ChannelId.values(), // ControllerEssLimitTotalDischarge.ChannelId.values() // ); + this.energyScheduleHandler = buildEnergyScheduleHandler(// + () -> this.minSoc); } @Activate @@ -211,4 +220,27 @@ private boolean changeState(State nextState) { return false; } } + + /** + * Builds the {@link EnergyScheduleHandler}. + * + *

      + * This is public so that it can be used by the EnergyScheduler integration + * test. + * + * @param minSoc a supplier for the configured minSoc + * @return a {@link EnergyScheduleHandler} + */ + public static EnergyScheduleHandler buildEnergyScheduleHandler(IntSupplier minSoc) { + return EnergyScheduleHandler.of(// + simContext -> socToEnergy(simContext.ess().totalEnergy(), minSoc.getAsInt()), // + (simContext, period, energyFlow, minEnergy) -> { + energyFlow.setEssMaxDischarge(max(0, simContext.getEssInitial() - minEnergy)); + }); + } + + @Override + public EnergyScheduleHandler getEnergyScheduleHandler() { + return this.energyScheduleHandler; + } } diff --git a/io.openems.edge.controller.ess.timeofusetariff/bnd.bnd b/io.openems.edge.controller.ess.timeofusetariff/bnd.bnd index d45bd8553ce..767f72aac39 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/bnd.bnd +++ b/io.openems.edge.controller.ess.timeofusetariff/bnd.bnd @@ -3,6 +3,8 @@ Bundle-Vendor: FENECON GmbH Bundle-License: https://opensource.org/licenses/EPL-2.0 Bundle-Version: 1.0.0.${tstamp} +# TODO remove emergencycapacityreserve and limittotaldischarge after v1 + -buildpath: \ ${buildpath},\ io.openems.common,\ @@ -14,6 +16,7 @@ Bundle-Version: 1.0.0.${tstamp} io.openems.edge.ess.api,\ io.openems.edge.timedata.api,\ io.openems.edge.timeofusetariff.api,\ + org.apache.commons.math3,\ -testpath: \ ${testpath},\ diff --git a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/Config.java b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/Config.java index 99793e89191..bceba3c4d55 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/Config.java +++ b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/Config.java @@ -3,6 +3,8 @@ import org.osgi.service.metatype.annotations.AttributeDefinition; import org.osgi.service.metatype.annotations.ObjectClassDefinition; +import io.openems.edge.energy.api.Version; + @ObjectClassDefinition(// name = "Controller Ess Time-Of-Use Tariff", // description = "Optimize behaviour of an ESS in combination with a Time-Of-Use (ToU) Tariff.") @@ -40,9 +42,12 @@ @AttributeDefinition(name = "Limit Charge Power for §14a EnWG", description = "Always apply §14a EnWG limitation of 4.2 kW") boolean limitChargePowerFor14aEnWG() default false; + @AttributeDefinition(name = "Version", description = "Select version of implementation") + Version version() default Version.V1_ESS_ONLY; + @AttributeDefinition(name = "Ess target filter", description = "This is auto-generated by 'Ess-ID'.") String ess_target() default "(enabled=true)"; String webconsole_configurationFactory_nameHint() default "Controller Ess Time-Of-Use Tariff [{id}]"; -} \ No newline at end of file +} diff --git a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffController.java b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffController.java index 9876f79201e..b241b53977a 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffController.java +++ b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffController.java @@ -8,10 +8,11 @@ import io.openems.edge.common.channel.value.Value; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.controller.api.Controller; +import io.openems.edge.controller.ess.timeofusetariff.v1.EnergyScheduleHandlerV1; +import io.openems.edge.energy.api.EnergySchedulable; -public interface TimeOfUseTariffController extends Controller, OpenemsComponent { - - public static final int PERIODS_PER_HOUR = 4; +@SuppressWarnings("deprecation") +public interface TimeOfUseTariffController extends Controller, EnergySchedulable, OpenemsComponent { public enum ChannelId implements io.openems.edge.common.channel.ChannelId { /** @@ -52,6 +53,14 @@ public Doc doc() { } } + /** + * Get the {@link EnergyScheduleHandlerV1}. + * + * @return {@link EnergyScheduleHandlerV1} + */ + @Deprecated + public EnergyScheduleHandlerV1 getEnergyScheduleHandlerV1(); + /** * Gets the Channel for {@link ChannelId#QUARTERLY_PRICES}. * diff --git a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImpl.java b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImpl.java index 5ae75684899..48b0bc09338 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImpl.java +++ b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImpl.java @@ -1,12 +1,25 @@ package io.openems.edge.controller.ess.timeofusetariff; -import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.BALANCING; import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.CHARGE_GRID; import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.DELAY_DISCHARGE; +import static io.openems.edge.controller.ess.timeofusetariff.Utils.ESS_MAX_SOC; import static io.openems.edge.controller.ess.timeofusetariff.Utils.calculateAutomaticMode; +import static io.openems.edge.controller.ess.timeofusetariff.Utils.calculateChargeEnergyInChargeGrid; +import static io.openems.edge.energy.api.simulation.Coefficient.ESS; +import static io.openems.edge.energy.api.simulation.Coefficient.GRID_TO_CONS; +import static io.openems.edge.energy.api.simulation.Coefficient.GRID_TO_ESS; +import static io.openems.edge.energy.api.simulation.Coefficient.PROD_TO_ESS; +import static io.openems.edge.energy.api.simulation.Coefficient.PROD_TO_GRID; +import static java.lang.Math.min; +import static java.lang.Math.round; +import static org.apache.commons.math3.optim.linear.Relationship.EQ; +import static org.apache.commons.math3.optim.nonlinear.scalar.GoalType.MAXIMIZE; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.BooleanSupplier; +import java.util.function.IntSupplier; +import java.util.function.Supplier; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentContext; @@ -31,11 +44,16 @@ import io.openems.edge.controller.api.Controller; import io.openems.edge.controller.ess.emergencycapacityreserve.ControllerEssEmergencyCapacityReserve; import io.openems.edge.controller.ess.limittotaldischarge.ControllerEssLimitTotalDischarge; -import io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImpl.Context; import io.openems.edge.controller.ess.timeofusetariff.Utils.ApplyState; +import io.openems.edge.controller.ess.timeofusetariff.jsonrpc.GetScheduleRequest; +import io.openems.edge.controller.ess.timeofusetariff.jsonrpc.GetScheduleResponse; +import io.openems.edge.controller.ess.timeofusetariff.v1.EnergyScheduleHandlerV1; +import io.openems.edge.controller.ess.timeofusetariff.v1.EnergyScheduleHandlerV1.ContextV1; +import io.openems.edge.controller.ess.timeofusetariff.v1.UtilsV1; import io.openems.edge.energy.api.EnergySchedulable; import io.openems.edge.energy.api.EnergyScheduleHandler; import io.openems.edge.energy.api.EnergyScheduler; +import io.openems.edge.energy.api.simulation.EnergyFlow; import io.openems.edge.ess.api.ManagedSymmetricEss; import io.openems.edge.ess.power.api.Phase; import io.openems.edge.ess.power.api.Pwr; @@ -50,15 +68,13 @@ immediate = true, // configurationPolicy = ConfigurationPolicy.REQUIRE // ) +@SuppressWarnings("deprecation") public class TimeOfUseTariffControllerImpl extends AbstractOpenemsComponent implements TimeOfUseTariffController, - EnergySchedulable, Controller, OpenemsComponent, TimedataProvider, ComponentJsonApi { + EnergySchedulable, Controller, OpenemsComponent, TimedataProvider, ComponentJsonApi { - public static record Context(List ctrlEmergencyCapacityReserves, - List ctrlLimitTotalDischarges, ManagedSymmetricEss ess, - ControlMode controlMode, int maxChargePowerFromGrid, boolean limitChargePowerFor14aEnWG) { - } - - private final EnergyScheduleHandler energyScheduleHandler; + @Deprecated + private final EnergyScheduleHandlerV1 energyScheduleHandlerV1; + private final EnergyScheduleHandler.WithDifferentStates energyScheduleHandler; private final CalculateActiveTime calculateDelayedTime = new CalculateActiveTime(this, TimeOfUseTariffController.ChannelId.DELAYED_TIME); private final CalculateActiveTime calculateChargedTime = new CalculateActiveTime(this, @@ -80,20 +96,23 @@ public static record Context(List ctrlEme @Reference(policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) private volatile Timedata timedata; + @Deprecated @Reference(policyOption = ReferencePolicyOption.GREEDY, // cardinality = ReferenceCardinality.MULTIPLE, // target = "(&(enabled=true)(isReserveSocEnabled=true))") - private List ctrlEmergencyCapacityReserves = new CopyOnWriteArrayList<>(); + private volatile List ctrlEmergencyCapacityReserves = new CopyOnWriteArrayList<>(); + @Deprecated @Reference(policyOption = ReferencePolicyOption.GREEDY, // cardinality = ReferenceCardinality.MULTIPLE, // target = "(enabled=true)") - private List ctrlLimitTotalDischarges = new CopyOnWriteArrayList<>(); + private volatile List ctrlLimitTotalDischarges = new CopyOnWriteArrayList<>(); @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) private ManagedSymmetricEss ess; @Reference + @Deprecated private EnergyScheduler energyScheduler; private Config config = null; @@ -104,11 +123,18 @@ public TimeOfUseTariffControllerImpl() { Controller.ChannelId.values(), // TimeOfUseTariffController.ChannelId.values() // ); - this.energyScheduleHandler = new EnergyScheduleHandler<>(// + + this.energyScheduleHandlerV1 = new EnergyScheduleHandlerV1(// () -> this.config.controlMode().states, // - () -> new Context(this.ctrlEmergencyCapacityReserves, this.ctrlLimitTotalDischarges, this.ess, + () -> new ContextV1(this.ctrlEmergencyCapacityReserves, this.ctrlLimitTotalDischarges, this.ess, this.config.controlMode(), this.config.maxChargePowerFromGrid(), this.config.limitChargePowerFor14aEnWG())); + + this.energyScheduleHandler = buildEnergyScheduleHandler(// + () -> this.ess, // + () -> this.config.controlMode(), // + () -> this.config.maxChargePowerFromGrid(), // + () -> this.config.limitChargePowerFor14aEnWG()); } @Activate @@ -121,6 +147,7 @@ private void activate(ComponentContext context, Config config) { private void modified(ComponentContext context, Config config) { super.modified(context, config.id(), config.alias(), config.enabled()); this.applyConfig(config); + this.energyScheduleHandler.triggerReschedule(); } private synchronized void applyConfig(Config config) { @@ -138,12 +165,26 @@ protected void deactivate() { @Override public void run() throws OpenemsNamedException { - // Mode given from the configuration. - var as = switch (this.config.mode()) { - case AUTOMATIC -> calculateAutomaticMode(this.sum, this.ess, - this.energyScheduleHandler.getCurrentEssChargeInChargeGrid(), this.config.maxChargePowerFromGrid(), - this.config.limitChargePowerFor14aEnWG(), this.getCurrentPeriodState()); - case OFF -> new ApplyState(StateMachine.BALANCING, null); + // Version and Mode given from the configuration. + final var as = switch (this.config.version()) { + + case V1_ESS_ONLY // + -> switch (this.config.mode()) { + case AUTOMATIC // + -> UtilsV1.calculateAutomaticMode(this.energyScheduleHandlerV1, this.sum, this.ess, + this.config.maxChargePowerFromGrid(), this.config.limitChargePowerFor14aEnWG()); + case OFF // + -> new ApplyState(StateMachine.BALANCING, null); + }; + + case V2_ENERGY_SCHEDULABLE // + -> switch (this.config.mode()) { + case AUTOMATIC // + -> calculateAutomaticMode(this.sum, this.ess, this.config.maxChargePowerFromGrid(), + this.config.limitChargePowerFor14aEnWG(), this.energyScheduleHandler.getCurrentPeriod()); + case OFF // + -> new ApplyState(StateMachine.BALANCING, null); + }; }; // Update Channels @@ -159,14 +200,6 @@ public void run() throws OpenemsNamedException { } } - private StateMachine getCurrentPeriodState() { - var state = this.energyScheduleHandler.getCurrentState(); - if (state != null) { - return state; - } - return BALANCING; // Default Fallback - } - @Override public Timedata getTimedata() { return this.timedata; @@ -174,21 +207,134 @@ public Timedata getTimedata() { @Override public void buildJsonApiRoutes(JsonApiBuilder builder) { - this.energyScheduler.buildJsonApiRoutes(builder); + builder.handleRequest(GetScheduleRequest.METHOD, call -> // + switch (this.config.version()) { + case V1_ESS_ONLY // + -> this.energyScheduler.handleGetScheduleRequestV1(call, this.id()); + + case V2_ENERGY_SCHEDULABLE // + -> GetScheduleResponse.from(call.getRequest().getId(), // + this.id(), this.componentManager.getClock(), this.ess, this.timedata, this.energyScheduleHandler); + }); } @Override public String debugLog() { var b = new StringBuilder() // .append(this.getStateMachine()); // - if (this.getCurrentPeriodState() == null) { - b.append("|No Schedule available"); + + switch (this.config.version()) { + case V1_ESS_ONLY -> { + if (this.energyScheduleHandlerV1 == null || this.energyScheduleHandlerV1.getCurrentState() == null) { + b.append("|No Schedule available"); + } + } + case V2_ENERGY_SCHEDULABLE -> { + if (this.energyScheduleHandler.getCurrentPeriod() == null) { + b.append("|No Schedule available"); + } + } } return b.toString(); } + /** + * Builds the {@link EnergyScheduleHandler}. + * + *

      + * This is public so that it can be used by the EnergyScheduler integration + * test. + * + * @param ess a supplier for the + * {@link ManagedSymmetricEss} + * @param controlMode a supplier for the configured + * {@link ControlMode} + * @param maxChargePowerFromGrid a supplier for the configured + * maxChargePowerFromGrid + * @param limitChargePowerFor14aEnWG a supplier for the configured + * limitChargePowerFor14aEnWG + * @return a typed {@link EnergyScheduleHandler} + */ + public static EnergyScheduleHandler.WithDifferentStates buildEnergyScheduleHandler( + Supplier ess, Supplier controlMode, IntSupplier maxChargePowerFromGrid, + BooleanSupplier limitChargePowerFor14aEnWG) { + return EnergyScheduleHandler.of(// + StateMachine.BALANCING, // + () -> controlMode.get().states, // + simContext -> { + // Maximium-SoC in CHARGE_GRID is 90 % + var maxSocEnergyInChargeGrid = round(simContext.ess().totalEnergy() * (ESS_MAX_SOC / 100)); + var essChargeInChargeGrid = calculateChargeEnergyInChargeGrid(simContext); + return new EshContext(ess.get(), controlMode.get(), maxChargePowerFromGrid.getAsInt(), + limitChargePowerFor14aEnWG.getAsBoolean(), maxSocEnergyInChargeGrid, essChargeInChargeGrid); + }, // + (simContext, period, energyFlow, ctrlContext, state) -> { + switch (state) { + case BALANCING -> applyBalancing(energyFlow); // TODO Move to CtrlBalancing + case DELAY_DISCHARGE -> applyDelayDischarge(energyFlow); + case CHARGE_GRID -> { + energyFlow.setEssMaxCharge(ctrlContext.maxSocEnergyInChargeGrid - simContext.getEssInitial()); + applyChargeGrid(energyFlow, ctrlContext.essChargeInChargeGrid); + } + } + }, // + Utils::postprocessSimulatorState); + } + + /** + * Simulate {@link EnergyFlow} in {@link StateMachine#BALANCING}. + * + * @param model the {@link EnergyFlow.Model} + */ + public static void applyBalancing(EnergyFlow.Model model) { + var target = model.consumption - model.production; + model.setFittingCoefficientValue(ESS, EQ, target); + } + + /** + * Simulate {@link EnergyFlow} in DELAY_DISCHARGE. + * + * @param model the {@link EnergyFlow.Model} + */ + public static void applyDelayDischarge(EnergyFlow.Model model) { + var target = min(0 /* Charge -> apply Balancing */, model.consumption - model.production); + model.setFittingCoefficientValue(ESS, EQ, target); + } + + /** + * Simulate {@link EnergyFlow} in {@link StateMachine#CHARGE_GRID}. + * + * @param model the {@link EnergyFlow.Model} + * @param chargeEnergy the target charge-from-grid energy + */ + public static void applyChargeGrid(EnergyFlow.Model model, int chargeEnergy) { + model.setExtremeCoefficientValue(PROD_TO_ESS, MAXIMIZE); + model.setExtremeCoefficientValue(GRID_TO_CONS, MAXIMIZE); + model.setFittingCoefficientValue(GRID_TO_ESS, EQ, chargeEnergy); + } + + /** + * Simulate {@link EnergyFlow} in a future DISCHARGE_GRID state. + * + * @param model the {@link EnergyFlow.Model} + * @param dischargeEnergy the target discharge-to-grid energy + */ + public static void applyDischargeGrid(EnergyFlow.Model model, int dischargeEnergy) { + model.setExtremeCoefficientValue(PROD_TO_GRID, MAXIMIZE); + model.setFittingCoefficientValue(GRID_TO_ESS, EQ, -dischargeEnergy); + } + + public static record EshContext(ManagedSymmetricEss ess, ControlMode controlMode, int maxChargePowerFromGrid, + boolean limitChargePowerFor14aEnWG, int maxSocEnergyInChargeGrid, int essChargeInChargeGrid) { + } + @Override - public EnergyScheduleHandler getEnergyScheduleHandler() { + public EnergyScheduleHandler.WithDifferentStates getEnergyScheduleHandler() { return this.energyScheduleHandler; } + + @Override + public EnergyScheduleHandlerV1 getEnergyScheduleHandlerV1() { + return this.energyScheduleHandlerV1; + } } diff --git a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/Utils.java b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/Utils.java index 6543f9b24c1..7b21d653571 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/Utils.java +++ b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/Utils.java @@ -1,23 +1,27 @@ package io.openems.edge.controller.ess.timeofusetariff; -import static io.openems.edge.common.type.TypeUtils.multiply; +import static com.google.common.math.Quantiles.percentiles; import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.BALANCING; import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.CHARGE_GRID; import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.DELAY_DISCHARGE; -import static io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffController.PERIODS_PER_HOUR; +import static io.openems.edge.energy.api.EnergyConstants.PERIODS_PER_HOUR; +import static io.openems.edge.energy.api.EnergyUtils.findFirstPeakIndex; +import static io.openems.edge.energy.api.EnergyUtils.findFirstValleyIndex; +import static io.openems.edge.energy.api.EnergyUtils.toPower; import static java.lang.Math.max; import static java.lang.Math.min; import static java.lang.Math.round; -import static java.util.stream.IntStream.concat; +import static java.util.Arrays.stream; -import java.util.List; -import java.util.Objects; +import com.google.common.primitives.ImmutableIntArray; import io.openems.common.types.ChannelAddress; import io.openems.edge.common.sum.Sum; import io.openems.edge.controller.api.Controller; -import io.openems.edge.controller.ess.emergencycapacityreserve.ControllerEssEmergencyCapacityReserve; -import io.openems.edge.controller.ess.limittotaldischarge.ControllerEssLimitTotalDischarge; +import io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImpl.EshContext; +import io.openems.edge.energy.api.EnergyScheduleHandler.WithDifferentStates.Period; +import io.openems.edge.energy.api.simulation.EnergyFlow; +import io.openems.edge.energy.api.simulation.GlobalSimulationsContext; import io.openems.edge.ess.api.HybridEss; import io.openems.edge.ess.api.ManagedSymmetricEss; @@ -52,29 +56,6 @@ private Utils() { public static final ChannelAddress SUM_ESS_DISCHARGE_POWER = new ChannelAddress("_sum", "EssDischargePower"); public static final ChannelAddress SUM_ESS_SOC = new ChannelAddress("_sum", "EssSoc"); - /** - * Returns the configured minimum SoC, or zero. - * - * @param ctrlLimitTotalDischarges the list of - * {@link ControllerEssLimitTotalDischarge} - * @param ctrlEmergencyCapacityReserves the list of - * {@link ControllerEssEmergencyCapacityReserve} - * @return the value in [%] - */ - public static int getEssMinSocPercentage(List ctrlLimitTotalDischarges, - List ctrlEmergencyCapacityReserves) { - return concat(// - ctrlLimitTotalDischarges.stream() // - .map(ctrl -> ctrl.getMinSoc().get()) // - .filter(Objects::nonNull) // - .mapToInt(v -> max(0, v)), // only positives - ctrlEmergencyCapacityReserves.stream() // - .map(ctrl -> ctrl.getActualReserveSoc().get()) // - .filter(Objects::nonNull) // - .mapToInt(v -> max(0, v))) // only positives - .max().orElse(0); - } - public static record ApplyState(StateMachine actualState, Integer setPoint) { } @@ -83,20 +64,19 @@ public static record ApplyState(StateMachine actualState, Integer setPoint) { * * @param sum the {@link Sum} * @param ess the {@link ManagedSymmetricEss} - * @param essChargeInChargeGrid ESS Charge Energy in CHARGE_GRID State [Wh] * @param maxChargePowerFromGrid the configured max charge from grid power * @param limitChargePowerFor14aEnWG Limit Charge Power for §14a EnWG - * @param targetState the scheduled target {@link StateMachine} + * @param period the scheduled {@link Period} * @return {@link ApplyState} */ - public static ApplyState calculateAutomaticMode(Sum sum, ManagedSymmetricEss ess, Integer essChargeInChargeGrid, - int maxChargePowerFromGrid, boolean limitChargePowerFor14aEnWG, StateMachine targetState) { + public static ApplyState calculateAutomaticMode(Sum sum, ManagedSymmetricEss ess, int maxChargePowerFromGrid, + boolean limitChargePowerFor14aEnWG, Period period) { final StateMachine actualState; final Integer setPoint; var gridActivePower = sum.getGridActivePower().get(); // current buy-from/sell-to grid var essActivePower = ess.getActivePower().get(); // current charge/discharge ESS - if (gridActivePower == null || essActivePower == null) { + if (period == null || gridActivePower == null || essActivePower == null) { // undefined state return new ApplyState(BALANCING, null); } @@ -104,9 +84,9 @@ public static ApplyState calculateAutomaticMode(Sum sum, ManagedSymmetricEss ess // Post-process and get actual state final var pwrBalancing = gridActivePower + essActivePower; final var pwrDelayDischarge = calculateDelayDischargePower(ess); - final var pwrChargeGrid = calculateChargeGridPower(essChargeInChargeGrid, ess, essActivePower, gridActivePower, - maxChargePowerFromGrid, limitChargePowerFor14aEnWG); - actualState = postprocessRunState(targetState, pwrBalancing, pwrDelayDischarge, pwrChargeGrid); + final var pwrChargeGrid = calculateChargeGridPower(period.context().essChargeInChargeGrid(), ess, + essActivePower, gridActivePower, maxChargePowerFromGrid, limitChargePowerFor14aEnWG); + actualState = postprocessRunState(period.state(), pwrBalancing, pwrDelayDischarge, pwrChargeGrid); // Get and apply ActivePower Less-or-Equals Set-Point setPoint = switch (actualState) { @@ -156,8 +136,39 @@ public static StateMachine postprocessRunState(StateMachine state, int pwrBalanc return state; } - protected static int calculateEssChargeInChargeGridPowerFromParams(Integer essChargeInChargeGrid, - ManagedSymmetricEss ess) { + /** + * Post-Process a state of a Period during Simulation, i.e. replace with + * 'better' state with the same behaviour. + * + *

      + * NOTE: heavy computation is ok here, because this method is called only at the + * end with the best Schedule. + * + * @param ef the {@link EnergyFlow} for the state + * @param state the initial state + * @return the new state + */ + public static StateMachine postprocessSimulatorState(EnergyFlow ef, StateMachine state) { + if (state == CHARGE_GRID) { + // CHARGE_GRID,... + if (ef.getGridToEss() <= 0) { + // but battery is not charged from grid + state = DELAY_DISCHARGE; + } + } + + if (state == DELAY_DISCHARGE) { + // DELAY_DISCHARGE,... + if (ef.getEss() < 0) { + // but battery gets charged + state = BALANCING; + } + } + + return state; + } + + protected static int calculateEssChargeInChargeGridPower(Integer essChargeInChargeGrid, ManagedSymmetricEss ess) { if (essChargeInChargeGrid != null) { return toPower(essChargeInChargeGrid); } @@ -187,7 +198,7 @@ protected static int calculateEssChargeInChargeGridPowerFromParams(Integer essCh public static int calculateChargeGridPower(Integer essChargeInChargeGrid, ManagedSymmetricEss ess, int essActivePower, int gridActivePower, int maxChargePowerFromGrid, boolean limitChargePowerFor14aEnWG) { var realGridPower = gridActivePower + essActivePower; // 'real', without current ESS charge/discharge - var targetChargePower = calculateEssChargeInChargeGridPowerFromParams(essChargeInChargeGrid, ess) // + var targetChargePower = calculateEssChargeInChargeGridPower(essChargeInChargeGrid, ess) // + min(0, realGridPower) * -1; // add excess production var effectiveGridBuyPower = max(0, realGridPower) + targetChargePower; var chargePower = max(0, targetChargePower - max(0, effectiveGridBuyPower - maxChargePowerFromGrid)); @@ -236,12 +247,63 @@ public static int calculateDelayDischargePower(ManagedSymmetricEss ess) { } /** - * Converts energy [Wh/15 min] to power [W]. + * Calculates the default ESS charge energy per period in + * {@link StateMachine#CHARGE_GRID}. * - * @param energy the energy value - * @return the power value + *

      + * Applies {@link #ESS_CHARGE_C_RATE} with the minimum of usable ESS energy or + * predicted consumption energy that cannot be supplied from production. + * + * @param gsc the {@link GlobalSimulationsContext} + * @return the value in [Wh] */ - private static Integer toPower(Integer energy) { - return multiply(energy, PERIODS_PER_HOUR); + public static int calculateChargeEnergyInChargeGrid(GlobalSimulationsContext gsc) { + var refs = ImmutableIntArray.builder(); + + // Uses the total available energy as reference (= fallback) + var fallback = max(0, round(ESS_MAX_SOC / 100F * gsc.ess().totalEnergy())); + add(refs, fallback); + + // Uses the total excess consumption as reference + add(refs, gsc.periods().stream() // + .mapToInt(p -> p.consumption() - p.production()) // calculates excess Consumption Energy per Period + .sum()); + + add(refs, gsc.periods().stream() // + .takeWhile(p -> p.consumption() >= p.production()) // take only first Periods + .mapToInt(p -> p.consumption() - p.production()) // calculates excess Consumption Energy per Period + .sum()); + + // Uses the excess consumption during high price periods as reference + { + var prices = gsc.periods().stream() // + .mapToDouble(GlobalSimulationsContext.Period::price) // + .toArray(); + var peakIndex = findFirstPeakIndex(findFirstValleyIndex(0, prices), prices); + var firstPrices = stream(prices) // + .limit(peakIndex) // + .toArray(); + if (firstPrices.length > 0) { + var percentilePrice = percentiles().index(95).compute(firstPrices); + add(refs, gsc.periods().stream() // + .limit(peakIndex) // + .filter(p -> p.price() >= percentilePrice) // takes only prices > percentile + .mapToInt(p -> p.consumption() - p.production()) // excess Consumption Energy per Period + .sum()); + } + } + + return (int) round(// + refs.build().stream() // + .average() // + .orElse(fallback) // + * ESS_CHARGE_C_RATE / PERIODS_PER_HOUR); } + + private static void add(ImmutableIntArray.Builder builder, int value) { + if (value > 0) { + builder.add(value); + } + } + } diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/jsonrpc/GetScheduleRequest.java b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/GetScheduleRequest.java similarity index 94% rename from io.openems.edge.energy/src/io/openems/edge/energy/jsonrpc/GetScheduleRequest.java rename to io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/GetScheduleRequest.java index 1dbdb0dc7d8..ff357bfd827 100644 --- a/io.openems.edge.energy/src/io/openems/edge/energy/jsonrpc/GetScheduleRequest.java +++ b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/GetScheduleRequest.java @@ -1,4 +1,4 @@ -package io.openems.edge.energy.jsonrpc; +package io.openems.edge.controller.ess.timeofusetariff.jsonrpc; import com.google.gson.JsonObject; diff --git a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/GetScheduleResponse.java b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/GetScheduleResponse.java new file mode 100644 index 00000000000..d60e3eae6e6 --- /dev/null +++ b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/GetScheduleResponse.java @@ -0,0 +1,230 @@ +package io.openems.edge.controller.ess.timeofusetariff.jsonrpc; + +import static io.openems.common.utils.JsonUtils.buildJsonObject; +import static io.openems.common.utils.JsonUtils.getAsOptionalDouble; +import static io.openems.common.utils.JsonUtils.getAsOptionalInt; +import static io.openems.common.utils.JsonUtils.toJsonArray; +import static io.openems.edge.common.type.TypeUtils.fitWithin; +import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.BALANCING; +import static io.openems.edge.controller.ess.timeofusetariff.Utils.SUM_CONSUMPTION; +import static io.openems.edge.controller.ess.timeofusetariff.Utils.SUM_ESS_DISCHARGE_POWER; +import static io.openems.edge.controller.ess.timeofusetariff.Utils.SUM_ESS_SOC; +import static io.openems.edge.controller.ess.timeofusetariff.Utils.SUM_GRID; +import static io.openems.edge.controller.ess.timeofusetariff.Utils.SUM_PRODUCTION; +import static io.openems.edge.energy.api.EnergyUtils.toPower; +import static java.lang.Math.round; +import static java.util.Optional.ofNullable; + +import java.time.Clock; +import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; +import java.util.Set; +import java.util.SortedMap; +import java.util.UUID; +import java.util.function.Function; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.collect.ImmutableSortedMap; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; +import com.google.gson.JsonObject; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; +import io.openems.common.timedata.Resolution; +import io.openems.common.types.ChannelAddress; +import io.openems.edge.controller.ess.timeofusetariff.StateMachine; +import io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffController; +import io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImpl; +import io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImpl.EshContext; +import io.openems.edge.controller.ess.timeofusetariff.Utils; +import io.openems.edge.energy.api.EnergyScheduleHandler; +import io.openems.edge.energy.api.EnergyScheduleHandler.WithDifferentStates.Period; +import io.openems.edge.ess.api.SymmetricEss; +import io.openems.edge.timedata.api.Timedata; + +/** + * Represents a JSON-RPC Response for 'getSchedule'. + * + *

      + * {
      + *   "jsonrpc": "2.0",
      + *   "id": "UUID",
      + *   "result": {
      + *     'schedule': [{
      + *      'timestamp':...,
      + *      'price':...,
      + *      'state':...,
      + *      'grid':...,
      + *      'production':...,
      + *      'consumption':...,
      + *      'ess':...,
      + *      'soc':...,
      + *     }]
      + *   }
      + * }
      + * 
      + */ +public class GetScheduleResponse extends JsonrpcResponseSuccess { + + private static final Logger LOG = LoggerFactory.getLogger(GetScheduleResponse.class); + + private final JsonObject result; + + public GetScheduleResponse(UUID id, JsonObject result) { + super(id); + this.result = result; + } + + @Override + public JsonObject getResult() { + return this.result; + } + + /** + * Builds a {@link GetScheduleResponse} with last three hours data and current + * Schedule. + * + * @param requestId the JSON-RPC request-id + * @param componentId the Component-ID of the parent + * {@link TimeOfUseTariffController} + * @param clock a {@link Clock} + * @param ess the {@link SymmetricEss} + * @param timedata the {@link Timedata} + * @param energyScheduleHandler the {@link EnergyScheduleHandler} + * @return the {@link GetScheduleResponse} + * @throws OpenemsNamedException on error + */ + public static GetScheduleResponse from(UUID requestId, String componentId, Clock clock, SymmetricEss ess, + Timedata timedata, + EnergyScheduleHandler.WithDifferentStates energyScheduleHandler) { + final var schedule = energyScheduleHandler.getSchedule(); + final JsonArray result; + if (schedule.isEmpty()) { + result = new JsonArray(); + } else { + final var historic = fromHistoricData(componentId, schedule.firstKey(), timedata); + final var future = fromSchedule(ess, schedule); + result = Stream.concat(historic, future) // + .collect(toJsonArray()); + } + + return new GetScheduleResponse(requestId, // + buildJsonObject() // + .add("schedule", result) // + .build()); + } + + /** + * Queries the last three hours' data and converts it to a {@link Stream} of + * {@link JsonObject}s suitable for a {@link GetScheduleResponse}. + * + * @param componentId Component-ID of {@link TimeOfUseTariffControllerImpl} + * @param firstSchedule {@link ZonedDateTime} of the first entry in the Schedule + * (rounded down to 15 minutes) + * @param timedata the {@link Timedata} + * @return {@link Stream} of {@link JsonObject}s + */ + // TODO protected is sufficient after v1 + public static Stream fromHistoricData(String componentId, ZonedDateTime firstSchedule, + Timedata timedata) { + // Process last three hours of historic data + final var fromTime = firstSchedule.minusHours(3); + final var toTime = firstSchedule.minusSeconds(1); + final var channelQuarterlyPrices = new ChannelAddress(componentId, "QuarterlyPrices"); + final var channelStateMachine = new ChannelAddress(componentId, "StateMachine"); + SortedMap> data = null; + try { + data = timedata.queryHistoricData(null, fromTime, toTime, // + Set.of(channelQuarterlyPrices, channelStateMachine, // + Utils.SUM_GRID, SUM_PRODUCTION, SUM_CONSUMPTION, SUM_ESS_DISCHARGE_POWER, SUM_ESS_SOC), + new Resolution(15, ChronoUnit.MINUTES)); + } catch (Exception e) { + LOG.warn("Unable to read historic data: " + e.getMessage()); + } + if (data == null) { + return Stream.of(); + } + + return data.entrySet().stream() // + .map(e -> { + var d = e.getValue(); + Function getter = (c) -> ofNullable(d.get(c)) + .orElse(JsonNull.INSTANCE); + + return buildJsonObject() // + .addProperty("timestamp", e.getKey()) // + .addProperty("price", + getAsOptionalDouble(getter.apply(channelQuarterlyPrices)).orElse(null)) // + .addProperty("state", + getAsOptionalInt(getter.apply(channelStateMachine)).orElse(BALANCING.getValue())) // + .addProperty("grid", getAsOptionalInt(getter.apply(SUM_GRID)).orElse(null)) // + .addProperty("production", getAsOptionalInt(getter.apply(SUM_PRODUCTION)).orElse(null)) // + .addProperty("consumption", getAsOptionalInt(getter.apply(SUM_CONSUMPTION)).orElse(null)) // + .addProperty("ess", getAsOptionalInt(getter.apply(SUM_ESS_DISCHARGE_POWER)).orElse(null)) // + .addProperty("soc", getAsOptionalInt(getter.apply(SUM_ESS_SOC)).orElse(null)) // + .build(); + }); + } + + /** + * Converts the Schedule to a {@link Stream} of {@link JsonObject}s suitable for + * a {@link GetScheduleResponse}. + * + * @param ess the {@link SymmetricEss} + * @param schedule the {@link EnergyScheduleHandler} schedule + * @return {@link Stream} of {@link JsonObject}s + */ + protected static Stream fromSchedule(SymmetricEss ess, + ImmutableSortedMap> schedule) { + final var essTotalEnergy = ess.getCapacity().orElse(0); + return schedule.entrySet().stream() // + .map(e -> { + var p = e.getValue(); + + return buildJsonObject() // + .addProperty("timestamp", e.getKey()) // + .addProperty("price", p.price()) // + .addProperty("state", p.state().getValue()) // + .addProperty("grid", toPower(p.energyFlow().getGrid())) // + .addProperty("production", toPower(p.energyFlow().getProd())) // + .addProperty("consumption", toPower(p.energyFlow().getCons())) // + .addProperty("ess", toPower(p.energyFlow().getEss())) // + .addProperty("soc", round(fitWithin(0F, 100F, // + p.essInitialEnergy() * 100F / essTotalEnergy))) // + .build(); + }); + } + + /** + * Creates an empty default Schedule in case no Schedule is available. + * + * @param clock the {@link Clock} + * @param defaultState the default {@link StateMachine} + * @return {@link Stream} of {@link JsonObject}s + */ + protected static Stream empty(Clock clock, StateMachine defaultState) { + final var now = ZonedDateTime.now(clock); + final var numberOfPeriods = 96; + + return IntStream.range(0, numberOfPeriods) // + .mapToObj(i -> { + return buildJsonObject() // + .addProperty("timestamp", now.plusMinutes(i * 15)) // + .add("price", JsonNull.INSTANCE) // + .addProperty("state", defaultState.getValue()) // + .add("grid", JsonNull.INSTANCE) // + .add("production", JsonNull.INSTANCE) // + .add("consumption", JsonNull.INSTANCE) // + .add("ess", JsonNull.INSTANCE) // + .add("soc", JsonNull.INSTANCE) // + .build(); + }); + } + +} diff --git a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/package-info.java b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/package-info.java new file mode 100644 index 00000000000..c3c8d61c926 --- /dev/null +++ b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/package-info.java @@ -0,0 +1,3 @@ +@org.osgi.annotation.versioning.Version("1.0.0") +@org.osgi.annotation.bundle.Export +package io.openems.edge.controller.ess.timeofusetariff.jsonrpc; diff --git a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/v1/EnergyScheduleHandlerV1.java b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/v1/EnergyScheduleHandlerV1.java new file mode 100644 index 00000000000..305fa7ee007 --- /dev/null +++ b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/v1/EnergyScheduleHandlerV1.java @@ -0,0 +1,88 @@ +package io.openems.edge.controller.ess.timeofusetariff.v1; + +import static io.openems.common.utils.DateUtils.roundDownToQuarter; + +import java.time.ZonedDateTime; +import java.util.List; +import java.util.Optional; +import java.util.function.Supplier; + +import com.google.common.collect.ImmutableSortedMap; + +import io.openems.edge.controller.ess.emergencycapacityreserve.ControllerEssEmergencyCapacityReserve; +import io.openems.edge.controller.ess.limittotaldischarge.ControllerEssLimitTotalDischarge; +import io.openems.edge.controller.ess.timeofusetariff.ControlMode; +import io.openems.edge.controller.ess.timeofusetariff.StateMachine; +import io.openems.edge.ess.api.ManagedSymmetricEss; + +@Deprecated +public class EnergyScheduleHandlerV1 { + + public static record ContextV1(List ctrlEmergencyCapacityReserves, + List ctrlLimitTotalDischarges, ManagedSymmetricEss ess, + ControlMode controlMode, int maxChargePowerFromGrid, boolean limitChargePowerFor14aEnWG) { + } + + private final Supplier availableStates; + private final Supplier context; + + private ImmutableSortedMap> schedule = ImmutableSortedMap.of(); + + public EnergyScheduleHandlerV1(Supplier availableStates, Supplier context) { + this.availableStates = availableStates; + this.context = context; + } + + /** + * Gets the available States. + * + * @return an Array of States + */ + public StateMachine[] getAvailableStates() { + return this.availableStates.get(); + } + + /** + * Gets the Context. + * + * @return the Context + */ + public ContextV1 getContext() { + return this.context.get(); + } + + public static record Period(STATE state, Integer essChargeInChargeGrid) { + } + + /** + * Sets the Schedule. Called by Optimizer. + * + * @param schedule the Schedule + */ + public synchronized void setSchedule(ImmutableSortedMap> schedule) { + this.schedule = schedule; + } + + /** + * Gets the current State or null. + * + * @return the State or null + */ + public synchronized StateMachine getCurrentState() { + return Optional.ofNullable(this.schedule.get(roundDownToQuarter(ZonedDateTime.now()))) // + .map(Period::state) // + .orElse(null); + } + + /** + * Gets the current essChargeInChargeGrid or null. + * + * @return the essChargeInChargeGrid or null + */ + public synchronized Integer getCurrentEssChargeInChargeGrid() { + return Optional.ofNullable(this.schedule.get(roundDownToQuarter(ZonedDateTime.now()))) // + .map(Period::essChargeInChargeGrid) // + .orElse(null); + } + +} diff --git a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/v1/UtilsV1.java b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/v1/UtilsV1.java new file mode 100644 index 00000000000..56db25223e9 --- /dev/null +++ b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/v1/UtilsV1.java @@ -0,0 +1,132 @@ +package io.openems.edge.controller.ess.timeofusetariff.v1; + +import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.BALANCING; +import static io.openems.edge.controller.ess.timeofusetariff.Utils.calculateChargeGridPower; +import static io.openems.edge.controller.ess.timeofusetariff.Utils.calculateDelayDischargePower; +import static io.openems.edge.controller.ess.timeofusetariff.Utils.postprocessRunState; +import static java.lang.Math.max; +import static java.util.stream.IntStream.concat; + +import java.util.List; +import java.util.Objects; + +import io.openems.edge.common.sum.Sum; +import io.openems.edge.controller.ess.emergencycapacityreserve.ControllerEssEmergencyCapacityReserve; +import io.openems.edge.controller.ess.limittotaldischarge.ControllerEssLimitTotalDischarge; +import io.openems.edge.controller.ess.timeofusetariff.StateMachine; +import io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffController; +import io.openems.edge.controller.ess.timeofusetariff.Utils.ApplyState; +import io.openems.edge.ess.api.ManagedSymmetricEss; + +/** + * Utils for {@link TimeOfUseTariffController}. + * + *

      + * All energy values are in [Wh] and positive, unless stated differently. + */ +@Deprecated +public final class UtilsV1 { + + private UtilsV1() { + } + + public static final int PERIODS_PER_HOUR = 4; + + /** + * Returns the configured minimum SoC, or zero. + * + * @param ctrlLimitTotalDischarges the list of + * {@link ControllerEssLimitTotalDischarge} + * @param ctrlEmergencyCapacityReserves the list of + * {@link ControllerEssEmergencyCapacityReserve} + * @return the value in [%] + */ + public static int getEssMinSocPercentage(List ctrlLimitTotalDischarges, + List ctrlEmergencyCapacityReserves) { + return concat(// + ctrlLimitTotalDischarges.stream() // + .map(ctrl -> ctrl.getMinSoc().get()) // + .filter(Objects::nonNull) // + .mapToInt(v -> max(0, v)), // only positives + ctrlEmergencyCapacityReserves.stream() // + .map(ctrl -> ctrl.getActualReserveSoc().get()) // + .filter(Objects::nonNull) // + .mapToInt(v -> max(0, v))) // only positives + .max().orElse(0); + } + + /** + * Calculate Automatic Mode. + * + * @param esh the {@link EnergyScheduleHandlerV1} + * @param sum the {@link Sum} + * @param ess the {@link ManagedSymmetricEss} + * @param maxChargePowerFromGrid the configured max charge from grid power + * @param limitChargePowerFor14aEnWG Limit Charge Power for §14a EnWG + * @return {@link ApplyState} + */ + public static ApplyState calculateAutomaticMode(EnergyScheduleHandlerV1 esh, Sum sum, ManagedSymmetricEss ess, + int maxChargePowerFromGrid, boolean limitChargePowerFor14aEnWG) { + final var targetState = getCurrentPeriodState(esh); + final var essChargeInChargeGrid = esh.getCurrentEssChargeInChargeGrid(); + return calculateAutomaticMode(sum, ess, essChargeInChargeGrid, maxChargePowerFromGrid, + limitChargePowerFor14aEnWG, targetState); + } + + /** + * Calculate Automatic Mode. + * + * @param sum the {@link Sum} + * @param ess the {@link ManagedSymmetricEss} + * @param essChargeInChargeGrid ESS Charge Energy in CHARGE_GRID State [Wh] + * @param maxChargePowerFromGrid the configured max charge from grid power + * @param limitChargePowerFor14aEnWG Limit Charge Power for §14a EnWG + * @param targetState the scheduled target {@link StateMachine} + * @return {@link ApplyState} + */ + protected static ApplyState calculateAutomaticMode(Sum sum, ManagedSymmetricEss ess, Integer essChargeInChargeGrid, + int maxChargePowerFromGrid, boolean limitChargePowerFor14aEnWG, StateMachine targetState) { + final StateMachine actualState; + final Integer setPoint; + + var gridActivePower = sum.getGridActivePower().get(); // current buy-from/sell-to grid + var essActivePower = ess.getActivePower().get(); // current charge/discharge ESS + if (gridActivePower == null || essActivePower == null) { + // undefined state + return new ApplyState(BALANCING, null); + } + + // Post-process and get actual state + final var pwrBalancing = gridActivePower + essActivePower; + final var pwrDelayDischarge = calculateDelayDischargePower(ess); + final var pwrChargeGrid = calculateChargeGridPower(essChargeInChargeGrid, ess, essActivePower, gridActivePower, + maxChargePowerFromGrid, limitChargePowerFor14aEnWG); + actualState = postprocessRunState(targetState, pwrBalancing, pwrDelayDischarge, pwrChargeGrid); + + // Get and apply ActivePower Less-or-Equals Set-Point + setPoint = switch (actualState) { + case BALANCING -> null; // delegate to next priority Controller + case DELAY_DISCHARGE -> pwrDelayDischarge; + case CHARGE_GRID -> pwrChargeGrid; + }; + + return new ApplyState(actualState, setPoint); + } + + /** + * Gets the current period state of the {@link EnergyScheduleHandlerV1} or + * {@link StateMachine#BALANCING}. + * + * @param esh the {@link EnergyScheduleHandlerV1} + * @return the {@link StateMachine} + */ + public static StateMachine getCurrentPeriodState(EnergyScheduleHandlerV1 esh) { + if (esh != null) { + var state = esh.getCurrentState(); + if (state != null) { + return state; + } + } + return BALANCING; // Default Fallback + } +} diff --git a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/v1/package-info.java b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/v1/package-info.java new file mode 100644 index 00000000000..7c842e31832 --- /dev/null +++ b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/v1/package-info.java @@ -0,0 +1,3 @@ +@org.osgi.annotation.versioning.Version("1.0.0") +@org.osgi.annotation.bundle.Export +package io.openems.edge.controller.ess.timeofusetariff.v1; diff --git a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/MyConfig.java b/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/MyConfig.java index bc0c137b4a2..60f8bef585d 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/MyConfig.java +++ b/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/MyConfig.java @@ -2,6 +2,7 @@ import io.openems.common.test.AbstractComponentConfig; import io.openems.common.utils.ConfigUtils; +import io.openems.edge.energy.api.Version; @SuppressWarnings("all") public class MyConfig extends AbstractComponentConfig implements Config { @@ -16,6 +17,7 @@ protected static class Builder { private int maxChargePowerFromGrid; private boolean limitChargePowerFor14aEnWG; private RiskLevel riskLevel; + private Version version; private Builder() { } @@ -65,6 +67,11 @@ public Builder setLimitChargePowerFor14aEnWG(boolean limitChargePowerFor14aEnWG) return this; } + public Builder setVersion(Version version) { + this.version = version; + return this; + } + public MyConfig build() { return new MyConfig(this); } @@ -121,6 +128,11 @@ public RiskLevel riskLevel() { return this.builder.riskLevel; } + @Override + public Version version() { + return this.builder.version; + } + @Override public String ess_target() { return ConfigUtils.generateReferenceTargetFilter(this.id(), this.ess_id()); diff --git a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImplTest.java b/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImplTest.java index a0623215e0f..3750aa110a7 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImplTest.java +++ b/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImplTest.java @@ -13,8 +13,13 @@ import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.common.test.DummyConfigurationAdmin; +import io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImpl.EshContext; import io.openems.edge.controller.test.ControllerTest; +import io.openems.edge.energy.api.EnergyScheduleHandler; +import io.openems.edge.energy.api.Version; +import io.openems.edge.ess.api.SymmetricEss; import io.openems.edge.ess.test.DummyManagedSymmetricEss; +import io.openems.edge.timedata.api.Timedata; import io.openems.edge.timedata.test.DummyTimedata; import io.openems.edge.timeofusetariff.test.DummyTimeOfUseTariffProvider; @@ -23,18 +28,25 @@ public class TimeOfUseTariffControllerImplTest { @Test public void test() throws Exception { final var clock = createDummyClock(); - create(clock) // + create(clock, // + new DummyManagedSymmetricEss("ess0") // + .withSoc(60) // + .withCapacity(10000), // + new DummyTimedata("timedata0")) // .deactivate(); } /** * Creates a {@link TimeOfUseTariffControllerImpl} instance. * - * @param clock a {@link Clock} + * @param clock a {@link Clock} + * @param ess the {@link SymmetricEss} + * @param timedata the {@link Timedata} * @return the object * @throws Exception on error */ - public static TimeOfUseTariffControllerImpl create(Clock clock) throws Exception { + public static TimeOfUseTariffControllerImpl create(Clock clock, SymmetricEss ess, Timedata timedata) + throws Exception { var componentManager = new DummyComponentManager(clock); var sum = new DummySum(); var timeOfUseTariff = DummyTimeOfUseTariffProvider.empty(clock); @@ -43,12 +55,10 @@ public static TimeOfUseTariffControllerImpl create(Clock clock) throws Exception new ControllerTest(sut) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", componentManager) // - .addReference("timedata", new DummyTimedata("timedata0")) // + .addReference("timedata", timedata) // .addReference("timeOfUseTariff", timeOfUseTariff) // .addReference("sum", sum) // - .addReference("ess", new DummyManagedSymmetricEss("ess0") // - .withSoc(60) // - .withCapacity(10000)) // + .addReference("ess", ess) // .activate(MyConfig.create() // .setId("ctrl0") // .setEnabled(false) // @@ -58,9 +68,22 @@ public static TimeOfUseTariffControllerImpl create(Clock clock) throws Exception .setEssMaxChargePower(5000) // .setMaxChargePowerFromGrid(10000) // .setLimitChargePowerFor14aEnWG(false) // + .setVersion(Version.V2_ENERGY_SCHEDULABLE) // .setRiskLevel(MEDIUM) // .build()) // .next(new TestCase()); return sut; } + + /** + * Gets the {@link EnergyScheduleHandler}. + * + * @param ctrl the {@link TimeOfUseTariffControllerImpl} + * @return the object + * @throws Exception on error + */ + public static EnergyScheduleHandler.WithDifferentStates getEnergyScheduleHandler( + TimeOfUseTariffControllerImpl ctrl) throws Exception { + return ctrl.getEnergyScheduleHandler(); + } } diff --git a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/UtilsTest.java b/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/UtilsTest.java index c7a104c3419..ef883691f38 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/UtilsTest.java +++ b/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/UtilsTest.java @@ -5,22 +5,36 @@ import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.CHARGE_GRID; import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.DELAY_DISCHARGE; import static io.openems.edge.controller.ess.timeofusetariff.Utils.calculateAutomaticMode; +import static io.openems.edge.controller.ess.timeofusetariff.Utils.calculateChargeEnergyInChargeGrid; import static io.openems.edge.controller.ess.timeofusetariff.Utils.calculateChargeGridPower; import static io.openems.edge.controller.ess.timeofusetariff.Utils.calculateDelayDischargePower; -import static io.openems.edge.controller.ess.timeofusetariff.Utils.calculateEssChargeInChargeGridPowerFromParams; +import static io.openems.edge.controller.ess.timeofusetariff.Utils.calculateEssChargeInChargeGridPower; import static io.openems.edge.controller.ess.timeofusetariff.Utils.calculateMaxChargeProductionPower; import static org.junit.Assert.assertEquals; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; + import org.junit.Test; +import com.google.common.collect.ImmutableList; + +import io.openems.common.test.TimeLeapClock; import io.openems.edge.common.sum.DummySum; +import io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImpl.EshContext; import io.openems.edge.controller.ess.timeofusetariff.Utils.ApplyState; +import io.openems.edge.energy.api.EnergyScheduleHandler; +import io.openems.edge.energy.api.simulation.GlobalSimulationsContext; import io.openems.edge.ess.api.SymmetricEss; import io.openems.edge.ess.test.DummyHybridEss; import io.openems.edge.ess.test.DummyManagedSymmetricEss; public class UtilsTest { + public static final TimeLeapClock CLOCK = new TimeLeapClock(Instant.ofEpochSecond(946684800), ZoneId.of("UTC")); + public static final ZonedDateTime TIME = ZonedDateTime.now(CLOCK); + @Test public void testCalculateChargeGridPower() { assertEquals(-10000, calculateChargeGridPower(null, // @@ -111,22 +125,28 @@ public void testCalculateDelayDischarge() { } @Test - public void testCalculateMaxChargeGridPowerFromParams() { + public void testCalculateMaxChargeGridPower() { final var ess = new DummyManagedSymmetricEss("ess0"); // No params, initial ESS - assertEquals(0, calculateEssChargeInChargeGridPowerFromParams(null, ess)); + assertEquals(0, calculateEssChargeInChargeGridPower(null, ess)); // No params, ESS with MaxApparentPower withValue(ess, SymmetricEss.ChannelId.MAX_APPARENT_POWER, 1000); - assertEquals(250, calculateEssChargeInChargeGridPowerFromParams(null, ess)); + assertEquals(250, calculateEssChargeInChargeGridPower(null, ess)); // No params, ESS with Capacity withValue(ess, SymmetricEss.ChannelId.CAPACITY, 15000); - assertEquals(7500, calculateEssChargeInChargeGridPowerFromParams(null, ess)); + assertEquals(7500, calculateEssChargeInChargeGridPower(null, ess)); // With params (22 kWh; but few Consumption) - assertEquals(5360, calculateEssChargeInChargeGridPowerFromParams(1340, ess)); + assertEquals(5360, calculateEssChargeInChargeGridPower(1340, ess)); + } + + private static EnergyScheduleHandler.WithDifferentStates.Period mockPeriod( + StateMachine state, int essChargeInChargeGrid) { + return new EnergyScheduleHandler.WithDifferentStates.Period(state, 0, + new EshContext(null, null, 0, false, 0, essChargeInChargeGrid), null, 0); } @Test @@ -135,19 +155,17 @@ public void testCalculateAutomaticMode() { calculateAutomaticMode(// new DummySum(), // new DummyManagedSymmetricEss("ess0"), // - /* essChargeInChargeGrid */ 1000, // /* maxChargePowerFromGrid */ 2000, // /* limitChargePowerFor14aEnWG */ true, // - BALANCING)); + mockPeriod(BALANCING, /* essChargeInChargeGrid */ 1000))); assertEquals("Null-Check", new ApplyState(BALANCING, null), // calculateAutomaticMode(// new DummySum() // .withGridActivePower(100), // new DummyManagedSymmetricEss("ess0"), // - /* essChargeInChargeGrid */ 1000, // /* maxChargePowerFromGrid */ 2000, // /* limitChargePowerFor14aEnWG */ true, // - BALANCING)); + mockPeriod(BALANCING, /* essChargeInChargeGrid */ 1000))); assertEquals("BALANCING", new ApplyState(BALANCING, null), // calculateAutomaticMode(// @@ -155,10 +173,9 @@ public void testCalculateAutomaticMode() { .withGridActivePower(100), // new DummyManagedSymmetricEss("ess0") // .withActivePower(500), // - /* essChargeInChargeGrid */ 1000, // /* maxChargePowerFromGrid */ 2000, // /* limitChargePowerFor14aEnWG */ true, // - BALANCING)); + mockPeriod(BALANCING, /* essChargeInChargeGrid */ 1000))); assertEquals("DELAY_DISCHARGE stays DELAY_DISCHARGE", new ApplyState(DELAY_DISCHARGE, 0), // calculateAutomaticMode(// @@ -166,20 +183,19 @@ public void testCalculateAutomaticMode() { .withGridActivePower(100), // new DummyManagedSymmetricEss("ess0") // .withActivePower(500), // - /* essChargeInChargeGrid */ 1000, // /* maxChargePowerFromGrid */ 2000, // /* limitChargePowerFor14aEnWG */ true, // - DELAY_DISCHARGE)); + mockPeriod(DELAY_DISCHARGE, /* essChargeInChargeGrid */ 1000))); + assertEquals("DELAY_DISCHARGE to BALANCING", new ApplyState(BALANCING, null), // calculateAutomaticMode(// new DummySum() // .withGridActivePower(-500), // new DummyManagedSymmetricEss("ess0") // .withActivePower(500), // - /* essChargeInChargeGrid */ 1000, // /* maxChargePowerFromGrid */ 2000, // /* limitChargePowerFor14aEnWG */ true, // - DELAY_DISCHARGE)); + mockPeriod(DELAY_DISCHARGE, /* essChargeInChargeGrid */ 1000))); assertEquals("CHARGE_GRID stays CHARGE_GRID", new ApplyState(CHARGE_GRID, -1400), // calculateAutomaticMode(// @@ -187,29 +203,78 @@ public void testCalculateAutomaticMode() { .withGridActivePower(100), // new DummyManagedSymmetricEss("ess0") // .withActivePower(500), // - /* essChargeInChargeGrid */ 1000, // /* maxChargePowerFromGrid */ 2000, // /* limitChargePowerFor14aEnWG */ true, // - CHARGE_GRID)); + mockPeriod(CHARGE_GRID, /* essChargeInChargeGrid */ 1000))); + assertEquals("CHARGE_GRID to DELAY_DISCHARGE", new ApplyState(DELAY_DISCHARGE, 0), // calculateAutomaticMode(// new DummySum() // .withGridActivePower(100), // new DummyManagedSymmetricEss("ess0") // .withActivePower(500), // - /* essChargeInChargeGrid */ 1000, // /* maxChargePowerFromGrid */ 400, // /* limitChargePowerFor14aEnWG */ true, // - CHARGE_GRID)); + mockPeriod(CHARGE_GRID, /* essChargeInChargeGrid */ 1000))); + assertEquals("CHARGE_GRID to BALANCING", new ApplyState(BALANCING, null), // calculateAutomaticMode(// new DummySum() // .withGridActivePower(-500), // new DummyManagedSymmetricEss("ess0") // .withActivePower(500), // - /* essChargeInChargeGrid */ 1000, // /* maxChargePowerFromGrid */ 0, // /* limitChargePowerFor14aEnWG */ true, // - CHARGE_GRID)); + mockPeriod(CHARGE_GRID, /* essChargeInChargeGrid */ 1000))); } + + @Test + public void testCalculateChargeEnergyInChargeGrid() { + assertEquals(1375, calculateChargeEnergyInChargeGrid(// + new GlobalSimulationsContext(CLOCK, TIME, ImmutableList.of(), // + new GlobalSimulationsContext.Grid(0, 20000), // + new GlobalSimulationsContext.Ess(0, 12223, 5000, 5000), // + ImmutableList.of()))); + + assertEquals(525, calculateChargeEnergyInChargeGrid(// + new GlobalSimulationsContext(CLOCK, TIME, ImmutableList.of(), // + new GlobalSimulationsContext.Grid(0, 20000), // + new GlobalSimulationsContext.Ess(0, 12223, 5000, 5000), // + ImmutableList.of(// + new GlobalSimulationsContext.Period.Quarter(TIME, 0, 1000, 0), // + new GlobalSimulationsContext.Period.Quarter(TIME, 100, 1100, 0), // + new GlobalSimulationsContext.Period.Quarter(TIME, 200, 0, 0) // + )))); + + assertEquals(538, calculateChargeEnergyInChargeGrid(// + new GlobalSimulationsContext(CLOCK, TIME, ImmutableList.of(), // + new GlobalSimulationsContext.Grid(0, 20000), // + new GlobalSimulationsContext.Ess(0, 12223, 5000, 5000), // + ImmutableList.of(// + new GlobalSimulationsContext.Period.Quarter(TIME, 0, 700, 123), // + new GlobalSimulationsContext.Period.Quarter(TIME, 100, 600, 123), // + new GlobalSimulationsContext.Period.Quarter(TIME, 200, 500, 125), // + new GlobalSimulationsContext.Period.Quarter(TIME, 300, 400, 126), // + new GlobalSimulationsContext.Period.Quarter(TIME, 400, 300, 123), // + new GlobalSimulationsContext.Period.Quarter(TIME, 500, 200, 122), // + new GlobalSimulationsContext.Period.Quarter(TIME, 600, 100, 121), // + new GlobalSimulationsContext.Period.Quarter(TIME, 700, 0, 121) // + )))); + + assertEquals(499, calculateChargeEnergyInChargeGrid(// + new GlobalSimulationsContext(CLOCK, TIME, ImmutableList.of(), // + new GlobalSimulationsContext.Grid(0, 20000), // + new GlobalSimulationsContext.Ess(0, 12223, 5000, 5000), // + ImmutableList.of(// + new GlobalSimulationsContext.Period.Quarter(TIME, 0, 700, 120), // + new GlobalSimulationsContext.Period.Quarter(TIME, 100, 600, 121), // + new GlobalSimulationsContext.Period.Quarter(TIME, 200, 500, 122), // + new GlobalSimulationsContext.Period.Quarter(TIME, 300, 1140, 126), // + new GlobalSimulationsContext.Period.Quarter(TIME, 400, 1150, 125), // + new GlobalSimulationsContext.Period.Quarter(TIME, 500, 200, 122), // + new GlobalSimulationsContext.Period.Quarter(TIME, 600, 100, 121), // + new GlobalSimulationsContext.Period.Quarter(TIME, 700, 0, 121) // + )))); + } + } diff --git a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/GetScheduleResponseTest.java b/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/GetScheduleResponseTest.java new file mode 100644 index 00000000000..4372db782f4 --- /dev/null +++ b/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/GetScheduleResponseTest.java @@ -0,0 +1,242 @@ +package io.openems.edge.controller.ess.timeofusetariff.jsonrpc; + +import static io.openems.common.utils.DateUtils.roundDownToQuarter; +import static io.openems.common.utils.JsonUtils.getAsJsonArray; +import static io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImpl.applyBalancing; +import static io.openems.edge.controller.ess.timeofusetariff.UtilsTest.CLOCK; +import static io.openems.edge.controller.ess.timeofusetariff.jsonrpc.TestData.CONSUMPTION_PREDICTION_QUARTERLY; +import static io.openems.edge.controller.ess.timeofusetariff.jsonrpc.TestData.PAST_HOURLY_PRICES; +import static io.openems.edge.controller.ess.timeofusetariff.jsonrpc.TestData.PAST_SOC; +import static io.openems.edge.controller.ess.timeofusetariff.jsonrpc.TestData.PAST_STATES; +import static io.openems.edge.controller.ess.timeofusetariff.jsonrpc.TestData.PRODUCTION_888_20231106; +import static io.openems.edge.controller.ess.timeofusetariff.jsonrpc.TestData.PRODUCTION_PREDICTION_QUARTERLY; +import static org.junit.Assert.assertEquals; + +import java.time.ZonedDateTime; + +import org.junit.Test; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSortedMap; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.types.ChannelAddress; +import io.openems.common.utils.JsonUtils; +import io.openems.common.utils.UuidUtils; +import io.openems.edge.controller.ess.timeofusetariff.StateMachine; +import io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImplTest; +import io.openems.edge.controller.ess.timeofusetariff.Utils; +import io.openems.edge.energy.api.EnergyScheduleHandler.AbstractEnergyScheduleHandler; +import io.openems.edge.energy.api.EnergyScheduleHandler.WithDifferentStates.Period; +import io.openems.edge.energy.api.simulation.EnergyFlow; +import io.openems.edge.energy.api.simulation.GlobalSimulationsContext; +import io.openems.edge.ess.test.DummyManagedSymmetricEss; +import io.openems.edge.timedata.test.DummyTimedata; + +public class GetScheduleResponseTest { + + @Test + public void test() throws Exception { + final var now = roundDownToQuarter(ZonedDateTime.now(CLOCK)); + final var ess = new DummyManagedSymmetricEss("ess0") // + .withCapacity(10000); + final var model = new EnergyFlow.Model(// + /* production */ 2500, // + /* consumption */ 500, // + /* essMaxCharge */ 5000, // + /* essMaxDischarge */ 0, // + /* gridMaxBuy */ 4000, // + /* gridMaxSell */ 10000); + applyBalancing(model); + final var energyFlow = model.solve(); + + // Simulate historic data + final var timedata = new DummyTimedata("timedata0"); + final var fromDate = now.minusHours(3); + for (var i = 0; i < 12; i++) { + var quarter = fromDate.plusMinutes(i * 15); + timedata.add(quarter, new ChannelAddress("ctrl0", "QuarterlyPrices"), PAST_HOURLY_PRICES[i]); + timedata.add(quarter, new ChannelAddress("ctrl0", "StateMachine"), PAST_STATES[i]); + timedata.add(quarter, Utils.SUM_PRODUCTION, PRODUCTION_PREDICTION_QUARTERLY[i]); + timedata.add(quarter, Utils.SUM_CONSUMPTION, CONSUMPTION_PREDICTION_QUARTERLY[i]); + timedata.add(quarter, Utils.SUM_ESS_SOC, PAST_SOC[i]); + timedata.add(quarter, Utils.SUM_ESS_DISCHARGE_POWER, PRODUCTION_888_20231106[i]); + timedata.add(quarter, Utils.SUM_GRID, PRODUCTION_888_20231106[i]); + } + + // Simulate future Schedule + var ctrl = TimeOfUseTariffControllerImplTest.create(CLOCK, ess, timedata); + var esh = TimeOfUseTariffControllerImplTest.getEnergyScheduleHandler(ctrl); + ((AbstractEnergyScheduleHandler /* this is safe */) esh).initialize(new GlobalSimulationsContext(CLOCK, null, + null, null, new GlobalSimulationsContext.Ess(0, 0, 0, 0), ImmutableList.of())); + esh.applySchedule(ImmutableSortedMap.naturalOrder() // + .put(now.plusMinutes(0), new Period.Transition(1, 0.1, energyFlow, 5000)) // + .put(now.plusMinutes(15), new Period.Transition(0, 0.2, energyFlow, 6000)) // + .put(now.plusMinutes(30), new Period.Transition(0, 0.3, energyFlow, 7000)) // + .build()); + + final var gsr = GetScheduleResponse.from(UuidUtils.getNilUuid(), "ctrl0", CLOCK, ess, timedata, esh); + + var schedule = getAsJsonArray(gsr.getResult(), "schedule"); + + assertEquals(""" + [ + { + "timestamp": "1999-12-31T21:00:00Z", + "price": 158.0, + "state": 1, + "grid": 0, + "production": 0, + "consumption": 1021, + "ess": 0, + "soc": 60 + }, + { + "timestamp": "1999-12-31T21:15:00Z", + "price": 160.0, + "state": 1, + "grid": 0, + "production": 0, + "consumption": 1208, + "ess": 0, + "soc": 62 + }, + { + "timestamp": "1999-12-31T21:30:00Z", + "price": 171.0, + "state": 1, + "grid": 0, + "production": 0, + "consumption": 713, + "ess": 0, + "soc": 64 + }, + { + "timestamp": "1999-12-31T21:45:00Z", + "price": 174.0, + "state": 1, + "grid": 0, + "production": 0, + "consumption": 931, + "ess": 0, + "soc": 66 + }, + { + "timestamp": "1999-12-31T22:00:00Z", + "price": 161.0, + "state": 1, + "grid": 0, + "production": 0, + "consumption": 2847, + "ess": 0, + "soc": 65 + }, + { + "timestamp": "1999-12-31T22:15:00Z", + "price": 152.0, + "state": 3, + "grid": 0, + "production": 0, + "consumption": 2551, + "ess": 0, + "soc": 67 + }, + { + "timestamp": "1999-12-31T22:30:00Z", + "price": 120.0, + "state": 3, + "grid": 0, + "production": 0, + "consumption": 1558, + "ess": 0, + "soc": 70 + }, + { + "timestamp": "1999-12-31T22:45:00Z", + "price": 111.0, + "state": 1, + "grid": 0, + "production": 0, + "consumption": 1234, + "ess": 0, + "soc": 73 + }, + { + "timestamp": "1999-12-31T23:00:00Z", + "price": 105.0, + "state": 2, + "grid": 0, + "production": 0, + "consumption": 433, + "ess": 0, + "soc": 76 + }, + { + "timestamp": "1999-12-31T23:15:00Z", + "price": 105.0, + "state": 1, + "grid": 0, + "production": 0, + "consumption": 633, + "ess": 0, + "soc": 79 + }, + { + "timestamp": "1999-12-31T23:30:00Z", + "price": 74.0, + "state": 2, + "grid": 0, + "production": 0, + "consumption": 1355, + "ess": 0, + "soc": 83 + }, + { + "timestamp": "1999-12-31T23:45:00Z", + "price": 73.0, + "state": 2, + "grid": 0, + "production": 0, + "consumption": 606, + "ess": 0, + "soc": 87 + }, + { + "timestamp": "2000-01-01T00:00:00Z", + "price": 0.1, + "state": 0, + "grid": 0, + "production": 10000, + "consumption": 2000, + "ess": -8000, + "soc": 50 + }, + { + "timestamp": "2000-01-01T00:15:00Z", + "price": 0.2, + "state": 1, + "grid": 0, + "production": 10000, + "consumption": 2000, + "ess": -8000, + "soc": 60 + }, + { + "timestamp": "2000-01-01T00:30:00Z", + "price": 0.3, + "state": 1, + "grid": 0, + "production": 10000, + "consumption": 2000, + "ess": -8000, + "soc": 70 + } + ]""", JsonUtils.prettyToString(schedule)); + } + + @Test + public void testEmpty() throws OpenemsNamedException { + var response = GetScheduleResponse.empty(CLOCK, StateMachine.BALANCING).toList().get(0); + assertEquals(StateMachine.BALANCING.getValue(), JsonUtils.getAsInt(response, "state")); + } +} diff --git a/io.openems.edge.energy/test/io/openems/edge/energy/TestData.java b/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/TestData.java similarity index 61% rename from io.openems.edge.energy/test/io/openems/edge/energy/TestData.java rename to io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/TestData.java index c89873819e7..a56e5a5097d 100644 --- a/io.openems.edge.energy/test/io/openems/edge/energy/TestData.java +++ b/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/jsonrpc/TestData.java @@ -1,31 +1,26 @@ -package io.openems.edge.energy; - -import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.BALANCING; -import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.DELAY_DISCHARGE; - -import io.openems.edge.controller.ess.timeofusetariff.StateMachine; +package io.openems.edge.controller.ess.timeofusetariff.jsonrpc; public class TestData { // Edge 888; 06.11.2023 - public static final Integer[] PRODUCTION_888_20231106 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 12, 19, 24, 92, 301, 441, 653, 741, 1921, 1923, 1649, 2045, 2638, 3399, 4071, 4359, + protected static final Integer[] PRODUCTION_888_20231106 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 12, 19, 24, 92, 301, 441, 653, 741, 1921, 1923, 1649, 2045, 2638, 3399, 4071, 4359, 4516, 5541, 6993, 6292, 3902, 7700, 9098, 9555, 8119, 6868, 6560, 6380, 6193, 5389, 4349, 3743, 5367, 5319, 4383, 2243, 1122, 1315, 1107, 268, 48, 2, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - public static final Integer[] CONSUMPTION_888_20231106 = { 308, 285, 384, 471, 480, 385, 464, 448, 288, 333, 346, + protected static final Integer[] CONSUMPTION_888_20231106 = { 308, 285, 384, 471, 480, 385, 464, 448, 288, 333, 346, 313, 1786, 332, 300, 259, 373, 358, 279, 308, 309, 415, 392, 299, 2913, 3105, 4416, 4442, 497, 5910, 4106, 2171, 3898, 922, 1601, 1088, 303, 2384, 430, 2428, 2899, 371, 613, 1663, 366, 2072, 456, 1589, 2004, 488, 199, 1628, 613, 198, 1796, 202, 1180, 4975, 4493, 5511, 7757, 2926, 2640, 4335, 2630, 2799, 5111, 2979, 3062, 4842, 4194, 4474, 4750, 4876, 1238, 1395, 1425, 1123, 3366, 4088, 418, 436, 3234, 1504, 1092, 1853, 365, 628, 2095, 552, 1113, 1808, 3223, 1629, 1329, 264 }; - public static final Double[] PRICES_888_20231106 = { 155., 152., 152., 152., 157., 172., 238., 266., 266., 241., + protected static final Double[] PRICES_888_20231106 = { 155., 152., 152., 152., 157., 172., 238., 266., 266., 241., 224., 219., 221., 232., 248., 271., 286., 316., 332., 318., 284., 278., 270., 257. }; - public static final Integer[] PRODUCTION_PREDICTION_QUARTERLY = { + protected static final Integer[] PRODUCTION_PREDICTION_QUARTERLY = { /* 00:00-03:45 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // /* 04:00-07:45 */ @@ -52,8 +47,7 @@ public class TestData { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // }; - public static final Integer[] CONSUMPTION_PREDICTION_QUARTERLY = { - + protected static final Integer[] CONSUMPTION_PREDICTION_QUARTERLY = { /* 00:00-03:450 */ 1021, 1208, 713, 931, 2847, 2551, 1558, 1234, 433, 633, 1355, 606, 430, 1432, 1121, 502, // /* 04:00-07:45 */ @@ -80,7 +74,7 @@ public class TestData { 3226, 2358, 1778, 1002, 455, 654, 534, 1587, 1638, 459, 330, 258, 368, 728, 1096, 878 // }; - public static final Double[] HOURLY_PRICES_SUMMER = { // + protected static final Double[] HOURLY_PRICES_SUMMER = { // 70.95, 71.98, 71.95, 74.96, // 78.93, 80., 84.01, 111.03, // 105.04, 105., 74.23, 73.28, // @@ -89,35 +83,19 @@ public class TestData { 149.99, 157.43, 130.9, 120.14 // }; - public static final StateMachine[] STATES = { // - BALANCING, BALANCING, BALANCING, BALANCING, BALANCING, BALANCING, BALANCING, BALANCING, DELAY_DISCHARGE, - BALANCING, DELAY_DISCHARGE, DELAY_DISCHARGE, DELAY_DISCHARGE, DELAY_DISCHARGE, DELAY_DISCHARGE, - DELAY_DISCHARGE, DELAY_DISCHARGE, DELAY_DISCHARGE, DELAY_DISCHARGE, DELAY_DISCHARGE, DELAY_DISCHARGE, - DELAY_DISCHARGE, DELAY_DISCHARGE, DELAY_DISCHARGE, DELAY_DISCHARGE, DELAY_DISCHARGE, DELAY_DISCHARGE, - DELAY_DISCHARGE, DELAY_DISCHARGE, DELAY_DISCHARGE, BALANCING, BALANCING, BALANCING, BALANCING, BALANCING, - BALANCING, BALANCING, BALANCING, BALANCING, BALANCING, BALANCING, BALANCING, BALANCING, BALANCING, - BALANCING, BALANCING, BALANCING, BALANCING, BALANCING, BALANCING, BALANCING, BALANCING, BALANCING, - BALANCING, BALANCING, BALANCING, BALANCING, BALANCING, BALANCING, BALANCING, BALANCING, BALANCING, - BALANCING, BALANCING, BALANCING, BALANCING, BALANCING, BALANCING, BALANCING, BALANCING, BALANCING, - BALANCING, BALANCING, BALANCING, BALANCING, BALANCING, BALANCING, BALANCING, BALANCING, BALANCING, - BALANCING, BALANCING, BALANCING, DELAY_DISCHARGE, DELAY_DISCHARGE, DELAY_DISCHARGE, DELAY_DISCHARGE, - DELAY_DISCHARGE, DELAY_DISCHARGE, DELAY_DISCHARGE, DELAY_DISCHARGE, DELAY_DISCHARGE, DELAY_DISCHARGE, - DELAY_DISCHARGE, DELAY_DISCHARGE, DELAY_DISCHARGE // - }; - - public static final Integer[] PAST_STATES = { // + protected static final Integer[] PAST_STATES = { // 1, 1, 1, 1, // 1, 3, 3, 1, // 2, 1, 2, 2, // }; - public static final Integer[] PAST_SOC = { // + protected static final Integer[] PAST_SOC = { // 60, 62, 64, 66, // 65, 67, 70, 73, // 76, 79, 83, 87, // }; - public static final Integer[] PAST_HOURLY_PRICES = { // + protected static final Integer[] PAST_HOURLY_PRICES = { // 158, 160, 171, 174, // 161, 152, 120, 111, // 105, 105, 74, 73, // diff --git a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/v1/UtilsV1Test.java b/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/v1/UtilsV1Test.java new file mode 100644 index 00000000000..cd5fd7bd569 --- /dev/null +++ b/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/v1/UtilsV1Test.java @@ -0,0 +1,101 @@ +package io.openems.edge.controller.ess.timeofusetariff.v1; + +import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.BALANCING; +import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.CHARGE_GRID; +import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.DELAY_DISCHARGE; +import static io.openems.edge.controller.ess.timeofusetariff.v1.UtilsV1.calculateAutomaticMode; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import io.openems.edge.common.sum.DummySum; +import io.openems.edge.controller.ess.timeofusetariff.Utils.ApplyState; +import io.openems.edge.ess.test.DummyManagedSymmetricEss; + +@SuppressWarnings("deprecation") +public class UtilsV1Test { + + @Test + public void testCalculateAutomaticMode() { + assertEquals("Null-Check", new ApplyState(BALANCING, null), // + calculateAutomaticMode(// + new DummySum(), // + new DummyManagedSymmetricEss("ess0"), // + /* essChargeInChargeGrid */ 1000, // + /* maxChargePowerFromGrid */ 2000, // + /* limitChargePowerFor14aEnWG */ true, // + BALANCING)); + assertEquals("Null-Check", new ApplyState(BALANCING, null), // + calculateAutomaticMode(// + new DummySum() // + .withGridActivePower(100), // + new DummyManagedSymmetricEss("ess0"), // + /* essChargeInChargeGrid */ 1000, // + /* maxChargePowerFromGrid */ 2000, // + /* limitChargePowerFor14aEnWG */ true, // + BALANCING)); + + assertEquals("BALANCING", new ApplyState(BALANCING, null), // + calculateAutomaticMode(// + new DummySum() // + .withGridActivePower(100), // + new DummyManagedSymmetricEss("ess0") // + .withActivePower(500), // + /* essChargeInChargeGrid */ 1000, // + /* maxChargePowerFromGrid */ 2000, // + /* limitChargePowerFor14aEnWG */ true, // + BALANCING)); + + assertEquals("DELAY_DISCHARGE stays DELAY_DISCHARGE", new ApplyState(DELAY_DISCHARGE, 0), // + calculateAutomaticMode(// + new DummySum() // + .withGridActivePower(100), // + new DummyManagedSymmetricEss("ess0") // + .withActivePower(500), // + /* essChargeInChargeGrid */ 1000, // + /* maxChargePowerFromGrid */ 2000, // + /* limitChargePowerFor14aEnWG */ true, // + DELAY_DISCHARGE)); + assertEquals("DELAY_DISCHARGE to BALANCING", new ApplyState(BALANCING, null), // + calculateAutomaticMode(// + new DummySum() // + .withGridActivePower(-500), // + new DummyManagedSymmetricEss("ess0") // + .withActivePower(500), // + /* essChargeInChargeGrid */ 1000, // + /* maxChargePowerFromGrid */ 2000, // + /* limitChargePowerFor14aEnWG */ true, // + DELAY_DISCHARGE)); + + assertEquals("CHARGE_GRID stays CHARGE_GRID", new ApplyState(CHARGE_GRID, -1400), // + calculateAutomaticMode(// + new DummySum() // + .withGridActivePower(100), // + new DummyManagedSymmetricEss("ess0") // + .withActivePower(500), // + /* essChargeInChargeGrid */ 1000, // + /* maxChargePowerFromGrid */ 2000, // + /* limitChargePowerFor14aEnWG */ true, // + CHARGE_GRID)); + assertEquals("CHARGE_GRID to DELAY_DISCHARGE", new ApplyState(DELAY_DISCHARGE, 0), // + calculateAutomaticMode(// + new DummySum() // + .withGridActivePower(100), // + new DummyManagedSymmetricEss("ess0") // + .withActivePower(500), // + /* essChargeInChargeGrid */ 1000, // + /* maxChargePowerFromGrid */ 400, // + /* limitChargePowerFor14aEnWG */ true, // + CHARGE_GRID)); + assertEquals("CHARGE_GRID to BALANCING", new ApplyState(BALANCING, null), // + calculateAutomaticMode(// + new DummySum() // + .withGridActivePower(-500), // + new DummyManagedSymmetricEss("ess0") // + .withActivePower(500), // + /* essChargeInChargeGrid */ 1000, // + /* maxChargePowerFromGrid */ 0, // + /* limitChargePowerFor14aEnWG */ true, // + CHARGE_GRID)); + } +} diff --git a/io.openems.edge.energy.api/bnd.bnd b/io.openems.edge.energy.api/bnd.bnd index 49a30e8f94b..e7874ed1370 100644 --- a/io.openems.edge.energy.api/bnd.bnd +++ b/io.openems.edge.energy.api/bnd.bnd @@ -10,6 +10,7 @@ Bundle-Version: 1.0.0.${tstamp} io.openems.edge.controller.api,\ io.openems.edge.predictor.api,\ io.openems.edge.timeofusetariff.api,\ + org.apache.commons.math3,\ -testpath: \ ${testpath},\ diff --git a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergyConstants.java b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergyConstants.java new file mode 100644 index 00000000000..0cca2cc68df --- /dev/null +++ b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergyConstants.java @@ -0,0 +1,15 @@ +package io.openems.edge.energy.api; + +import io.openems.common.types.ChannelAddress; + +public class EnergyConstants { + + public static final int PERIODS_PER_HOUR = 4; + + public static final ChannelAddress SUM_PRODUCTION = new ChannelAddress("_sum", "ProductionActivePower"); + public static final ChannelAddress SUM_UNMANAGED_CONSUMPTION = new ChannelAddress("_sum", + "UnmanagedConsumptionActivePower"); + + private EnergyConstants() { + } +} diff --git a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergySchedulable.java b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergySchedulable.java index cf2f7e66e0d..601a80179c8 100644 --- a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergySchedulable.java +++ b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergySchedulable.java @@ -2,12 +2,12 @@ import io.openems.edge.controller.api.Controller; -public interface EnergySchedulable extends Controller { +public interface EnergySchedulable extends Controller { /** * Get the {@link EnergyScheduleHandler}. * * @return {@link EnergyScheduleHandler} */ - public EnergyScheduleHandler getEnergyScheduleHandler(); + public EnergyScheduleHandler getEnergyScheduleHandler(); } diff --git a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergyScheduleHandler.java b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergyScheduleHandler.java index ca5ca2ebc45..bad193c7dd6 100644 --- a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergyScheduleHandler.java +++ b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergyScheduleHandler.java @@ -1,76 +1,477 @@ package io.openems.edge.energy.api; +import static com.google.common.base.MoreObjects.toStringHelper; import static io.openems.common.utils.DateUtils.roundDownToQuarter; +import java.time.Clock; import java.time.ZonedDateTime; -import java.util.Optional; +import java.util.Arrays; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.function.Function; +import java.util.function.IntFunction; import java.util.function.Supplier; +import java.util.stream.IntStream; -import com.google.common.collect.ImmutableMap; +import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableSortedMap; -public class EnergyScheduleHandler { +import io.openems.edge.controller.api.Controller; +import io.openems.edge.energy.api.EnergyScheduleHandler.WithDifferentStates.PostProcessor; +import io.openems.edge.energy.api.simulation.EnergyFlow; +import io.openems.edge.energy.api.simulation.GlobalSimulationsContext; +import io.openems.edge.energy.api.simulation.OneSimulationContext; - private final Supplier availableStates; - private final Supplier context; - - private ImmutableMap> schedule = ImmutableMap.of(); - - public EnergyScheduleHandler(Supplier availableStates, Supplier context) { - this.availableStates = availableStates; - this.context = context; - } +public sealed interface EnergyScheduleHandler { /** - * Gets the available States. + * Creates an {@link EnergyScheduleHandler} for a {@link Controller} with + * different states that can be evaluated. * - * @return an Array of States + * @param the type of the State + * @param the type of the Context + * @param defaultState the default State if no other is explicitly scheduled + * @param statesSupplier a {@link Supplier} for available States + * @param contextFunction a {@link Function} to create a Context + * @param simulator a simulator that modifies a given {@link EnergyFlow} + * @return an {@link EnergyScheduleHandler} */ - public STATE[] getAvailableStates() { - return this.availableStates.get(); + public static EnergyScheduleHandler.WithDifferentStates of(// + STATE defaultState, // + Supplier statesSupplier, // + Function contextFunction, // + WithDifferentStates.Simulator simulator) { + return new EnergyScheduleHandler.WithDifferentStates(defaultState, statesSupplier, + contextFunction, simulator, EnergyScheduleHandler.WithDifferentStates.PostProcessor.doNothing()); } /** - * Gets the Context. + * Creates an {@link EnergyScheduleHandler} for a {@link Controller} with + * different states that can be evaluated. * - * @return the Context + * @param the type of the State + * @param the type of the Context + * @param defaultState the default State if no other is explicitly scheduled + * @param statesSupplier a {@link Supplier} for available States + * @param contextFunction a {@link Function} to create a Context + * @param simulator a simulator that modifies a given {@link EnergyFlow} + * @param postProcessor a {@link PostProcessor} + * @return an {@link EnergyScheduleHandler} */ - public CONTEXT getContext() { - return this.context.get(); - } - - public static record Period(STATE state, Integer essChargeInChargeGrid) { + public static EnergyScheduleHandler.WithDifferentStates of(// + STATE defaultState, // + Supplier statesSupplier, // + Function contextFunction, // + WithDifferentStates.Simulator simulator, // + WithDifferentStates.PostProcessor postProcessor) { + return new EnergyScheduleHandler.WithDifferentStates(defaultState, statesSupplier, + contextFunction, simulator, postProcessor); } /** - * Sets the Schedule. Called by Optimizer. + * Creates an {@link EnergyScheduleHandler} for a {@link Controller} with only a + * single state. * - * @param schedule the Schedule + * @param the type of the Context + * @param contextFunction a {@link Function} to create a Context + * @param simulator a simulator that modifies a given {@link EnergyFlow} + * @return an {@link EnergyScheduleHandler} */ - public synchronized void setSchedule(ImmutableMap> schedule) { - this.schedule = schedule; + public static EnergyScheduleHandler.WithOnlyOneState of(// + Function contextFunction, // + WithOnlyOneState.Simulator simulator) { + return new EnergyScheduleHandler.WithOnlyOneState(contextFunction, simulator); } /** - * Gets the current State or null. - * - * @return the State or null + * Triggers Rescheduling by the Energy Scheduler. */ - public synchronized STATE getCurrentState() { - return Optional.ofNullable(this.schedule.get(roundDownToQuarter(ZonedDateTime.now()))) // - .map(Period::state) // - .orElse(null); + public void triggerReschedule(); + + public abstract static sealed class AbstractEnergyScheduleHandler implements EnergyScheduleHandler { + + private final Function contextFunction; + + protected Clock clock; + protected CONTEXT context; + private Runnable onRescheduleCallback; + + public AbstractEnergyScheduleHandler(Function contextFunction) { + this.contextFunction = contextFunction; + } + + /** + * Initialize the {@link EnergyScheduleHandler}. + * + *

      + * This method is called internally before a Simulation is executed. + * + * @param asc the {@link GlobalSimulationsContext} + */ + public void initialize(GlobalSimulationsContext asc) { + this.clock = asc.clock(); + this.context = this.contextFunction.apply(asc); + } + + /** + * This method sets the callback for events that require Rescheduling. + * + * @param callback the {@link Runnable} callback + */ + public synchronized void setOnRescheduleCallback(Runnable callback) { + this.onRescheduleCallback = callback; + } + + /** + * This method removes the callback. + */ + public synchronized void removeOnRescheduleCallback() { + this.onRescheduleCallback = null; + } + + @Override + public void triggerReschedule() { + var onRescheduleCallback = this.onRescheduleCallback; + if (onRescheduleCallback != null) { + onRescheduleCallback.run(); + } + } + + protected ZonedDateTime getNow() { + var clock = this.clock; + if (clock != null) { + return ZonedDateTime.now(clock); + } + return ZonedDateTime.now(); + } + + protected void buildToString(MoreObjects.ToStringHelper toStringHelper) { + var context = this.context; + if (context != null) { + toStringHelper.addValue(context); + } + } } - // TODO hacky... find a better way! - /** - * Gets the current essChargeInChargeGrid or null. - * - * @return the essChargeInChargeGrid or null - */ - public synchronized Integer getCurrentEssChargeInChargeGrid() { - return Optional.ofNullable(this.schedule.get(roundDownToQuarter(ZonedDateTime.now()))) // - .map(Period::essChargeInChargeGrid) // - .orElse(null); + public static final class WithDifferentStates extends AbstractEnergyScheduleHandler { + + public static interface Simulator { + /** + * Simulates a Period. + * + * @param osc the {@link OneSimulationContext} + * @param period the {@link GlobalSimulationsContext.Period} + * @param model the {@link EnergyFlow.Model} + * @param context the Controller Context + * @param state the simulated State + */ + public void simulate(OneSimulationContext osc, GlobalSimulationsContext.Period period, + EnergyFlow.Model model, CONTEXT context, STATE state); + } + + public static interface PostProcessor { + + /** + * A 'do-nothing' {@link PostProcessor}. + * + * @param the type of the State + * @return the same State + */ + public static PostProcessor doNothing() { + return (energyFlow, state) -> state; + } + + /** + * Post-Process a state of a Period during Simulation, i.e. replace with + * 'better' state with the equivalent behaviour. + * + *

      + * NOTE: heavy computation is ok here, because this method is called only at the + * end with the best Schedule. + * + * @param energyFlow the {@link EnergyFlow} + * @param state the initial state + * @return the new state + */ + public STATE postProcess(EnergyFlow energyFlow, STATE state); + } + + private final STATE defaultState; + private final Supplier availableStatesSupplier; + private final Simulator simulator; + private final WithDifferentStates.PostProcessor postProcessor; + private final SortedMap> schedule = new TreeMap<>(); + + private STATE[] availableStates; + + private WithDifferentStates(// + STATE defaultState, // + Supplier availableStatesSupplier, // + Function contextFunction, // + Simulator simulator, // + WithDifferentStates.PostProcessor postProcessor) { + super(contextFunction); + this.defaultState = defaultState; + this.availableStatesSupplier = availableStatesSupplier; + this.simulator = simulator; + this.postProcessor = postProcessor; + } + + @Override + public void initialize(GlobalSimulationsContext asc) { + super.initialize(asc); + this.availableStates = this.availableStatesSupplier.get(); + } + + /** + * Gets the default State. + * + * @return the default State + */ + public STATE getDefaultState() { + return this.defaultState; + } + + /** + * Gets the index of the default State. + * + * @return the index of the default State + */ + public int getDefaultStateIndex() { + var states = this.availableStates; + if (states == null) { + throw new IllegalAccessError( + "EnergySchedulerHandler is uninitialized. `initialize()` must be called first."); + } + return IntStream.range(0, states.length) // + .filter(i -> states[i] == this.defaultState) // + .findFirst() // + .orElse(0 /* fallback */); + } + + /** + * Gets the available States. + * + * @return an Array of States + */ + public STATE[] getAvailableStates() { + return this.availableStates; + } + + /** + * Simulates a Period. + * + * @param osc the {@link OneSimulationContext} + * @param period the simulated {@link GlobalSimulationsContext.Period} + * @param model the {@link EnergyFlow.Model} + * @param stateIndex the index of the simulated state + */ + public void simulatePeriod(OneSimulationContext osc, GlobalSimulationsContext.Period period, + EnergyFlow.Model model, int stateIndex) { + this.simulator.simulate(osc, period, model, this.context, this.availableStates[stateIndex]); + } + + /** + * Post-processes a Period of the best Schedule. + * + *

      + * This method is called internally after the Simulations are executed with the + * found best Schedule. + * + * @param period the {@link GlobalSimulationsContext.Period} + * @param osc the {@link OneSimulationContext} + * @param energyFlow the {@link EnergyFlow} + * @param stateIndex the index of the simulated state + * @return the post-processed state index + */ + public int postProcessPeriod(GlobalSimulationsContext.Period period, OneSimulationContext osc, + EnergyFlow energyFlow, int stateIndex) { + return this.getStateIndex(this.postProcessor.postProcess(energyFlow, this.availableStates[stateIndex])); + } + + public static record Period( + /** STATE of the Period */ + STATE state, + /** Price [1/MWh] */ + double price, // + /** EnergyScheduleHandler Context */ + CONTEXT context, // + /** Simulated EnergyFlow */ + EnergyFlow energyFlow, // + /** the initial ESS energy in the beginning of the period in [Wh] */ + int essInitialEnergy) { + + /** + * This class is only used internally to apply the Schedule. + */ + public static record Transition(int stateIndex, double price, EnergyFlow energyFlow, int essInitialEnergy) { + } + + /** + * Builds a {@link EnergyScheduleHandler.WithDifferentStates.Period} from a + * {@link EnergyScheduleHandler.WithDifferentStates.Period.Transition} record. + * + * @param the type of the State + * @param the type of the Context + * @param t the + * {@link EnergyScheduleHandler.WithDifferentStates.Period.Transition} + * record + * @param getState a method to translate a 'stateIndex' to a STATE + * @param context the CONTEXT used during simulation + * @return a {@link Period} record + */ + public static Period fromTransitionRecord(Period.Transition t, + IntFunction getState, CONTEXT context) { + return new Period<>(getState.apply(t.stateIndex), t.price, context, t.energyFlow, t.essInitialEnergy); + } + } + + /** + * Applies a new Schedule. + * + *

      + * This method is called by the {@link EnergyScheduler}. + * + * @param schedule the new Schedule as Map of ZonedDateTime to State-Index + */ + public void applySchedule(ImmutableSortedMap schedule) { + final var thisQuarter = roundDownToQuarter(this.getNow()); + final var nextQuarter = thisQuarter.plusMinutes(15); + final var currentContext = this.context; + synchronized (this.schedule) { + // Clear outdated entries + this.schedule.headMap(thisQuarter).clear(); + + // Remove future entries + this.schedule.tailMap(nextQuarter).clear(); + + // Update entries from param + var states = this.availableStates; + if (states.length == 0) { + System.err.println("States is empty!"); // TODO proper log + return; + } + schedule.forEach((k, t) -> { + this.schedule.put(k, Period.fromTransitionRecord(t, this::getState, currentContext)); + }); + } + } + + /** + * Gets a copy of the current Schedule. + * + * @return the Schedule + */ + public ImmutableSortedMap> getSchedule() { + synchronized (this.schedule) { + return ImmutableSortedMap.copyOfSorted(this.schedule); + } + } + + /** + * Gets the current {@link Period} record. + * + * @return the record of the currently scheduled Period; possibly null + */ + public Period getCurrentPeriod() { + synchronized (this.schedule) { + final var thisQuarter = roundDownToQuarter(this.getNow()); + return this.schedule.get(thisQuarter); + } + } + + /** + * Gets the string representation for the given stateIndex. + * + * @param stateIndex the index of the state + * @return string representation + */ + public String toStateString(int stateIndex) { + return this.getState(stateIndex).toString(); + } + + /** + * Gets the STATE for the given stateIndex. + * + * @param stateIndex the stateIndex + * @return the STATE + */ + private STATE getState(int stateIndex) { + var states = this.availableStates; + return stateIndex < states.length // + ? states[stateIndex] // + : this.defaultState; + } + + /** + * Gets the stateIndex for the given STATE. + * + * @param state the STATE + * @return the stateIndex; or zero if not found + */ + private int getStateIndex(STATE state) { + var states = this.availableStates; + for (var i = 0; i < states.length; i++) { + if (states[i] == state) { + return i; + } + } + return 0; + } + + @Override + public String toString() { + var toStringHelper = toStringHelper("ESH.WithDifferentStates"); + var availableStates = this.availableStates; + if (availableStates != null) { + toStringHelper.add("availableStates", Arrays.toString(availableStates)); + } + super.buildToString(toStringHelper); + return toStringHelper.toString(); + } } + public static final class WithOnlyOneState extends AbstractEnergyScheduleHandler { + + public static interface Simulator { + /** + * Simulates a Period. + * + * @param osc the {@link OneSimulationContext} + * @param period the {@link GlobalSimulationsContext.Period} + * @param model the {@link EnergyFlow.Model} + * @param context the Controller Context + */ + public void simulate(OneSimulationContext osc, GlobalSimulationsContext.Period period, + EnergyFlow.Model model, CONTEXT context); + } + + private final Simulator simulator; + + private WithOnlyOneState(// + Function contextFunction, // + Simulator simulator) { + super(contextFunction); + this.simulator = simulator; + } + + /** + * Simulates a Period. + * + * @param simContext the {@link OneSimulationContext} + * @param period the {@link GlobalSimulationsContext.Period} + * @param model the {@link EnergyFlow.Model} + */ + public void simulatePeriod(OneSimulationContext simContext, GlobalSimulationsContext.Period period, + EnergyFlow.Model model) { + this.simulator.simulate(simContext, period, model, this.context); + } + + @Override + public String toString() { + var toStringHelper = toStringHelper("ESH.WithOnlyOneState"); + super.buildToString(toStringHelper); + return toStringHelper.toString(); + } + } } diff --git a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergyScheduler.java b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergyScheduler.java index 7d58264b26b..f48c0344a78 100644 --- a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergyScheduler.java +++ b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergyScheduler.java @@ -1,19 +1,22 @@ package io.openems.edge.energy.api; +import io.openems.common.jsonrpc.base.JsonrpcRequest; +import io.openems.common.jsonrpc.base.JsonrpcResponse; +import io.openems.common.types.OpenemsType; import io.openems.edge.common.channel.Doc; import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.common.jsonapi.ComponentJsonApi; +import io.openems.edge.common.jsonapi.Call; /** * The global Energy Schedule optimizer singleton. */ -public interface EnergyScheduler extends OpenemsComponent, ComponentJsonApi { +public interface EnergyScheduler extends OpenemsComponent { public static final String SINGLETON_SERVICE_PID = "Core.Energy"; public static final String SINGLETON_COMPONENT_ID = "_energy"; public enum ChannelId implements io.openems.edge.common.channel.ChannelId { - ; + SIMULATIONS_PER_QUARTER(Doc.of(OpenemsType.INTEGER)); private final Doc doc; @@ -26,4 +29,14 @@ public Doc doc() { return this.doc; } } + + /** + * Handles a GetScheduleRequest. + * + * @param call the JsonApi {@link Call} + * @param id the Component-ID of the Controller + * @return the GetScheduleResponse + */ + @Deprecated + public JsonrpcResponse handleGetScheduleRequestV1(Call call, String id); } diff --git a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergyUtils.java b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergyUtils.java new file mode 100644 index 00000000000..e499135eade --- /dev/null +++ b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergyUtils.java @@ -0,0 +1,125 @@ +package io.openems.edge.energy.api; + +import static io.openems.edge.common.type.TypeUtils.multiply; +import static io.openems.edge.common.type.TypeUtils.orElse; +import static io.openems.edge.energy.api.EnergyConstants.PERIODS_PER_HOUR; +import static java.util.Arrays.stream; + +import java.util.Objects; +import java.util.stream.IntStream; + +public class EnergyUtils { + + private EnergyUtils() { + } + + /** + * Converts a State-of-Charge [%] to Energy [Wh]. + * + * @param totalEnergy the total energy in [Wh] + * @param soc the State-of-Charge in [%] + * @return the energy in [Wh] + */ + public static int socToEnergy(int totalEnergy, int soc) { + return totalEnergy /* [Wh] */ / 100 * soc; + } + + /** + * Finds the first valley in an array of doubles, e.g. prices. + * + * @param fromIndex start searching from this index + * @param values the values array + * @return the index of the valley + */ + public static int findFirstValleyIndex(int fromIndex, double[] values) { + if (values.length <= fromIndex) { + return fromIndex; + } else { + var previous = values[fromIndex]; + for (var i = fromIndex + 1; i < values.length; i++) { + var value = values[i]; + if (value > previous) { + return i - 1; + } + previous = value; + } + } + return values.length - 1; + } + + /** + * Finds the first peak in an array of doubles, e.g. prices. + * + * @param fromIndex start searching from this index + * @param values the values array + * @return the index of the peak + */ + public static int findFirstPeakIndex(int fromIndex, double[] values) { + if (values.length <= fromIndex) { + return fromIndex; + } else { + var previous = values[fromIndex]; + for (var i = fromIndex + 1; i < values.length; i++) { + var value = values[i]; + if (value < previous) { + return i - 1; + } + previous = value; + } + } + return values.length - 1; + } + + /** + * Converts power [W] to energy [Wh/15 min]. + * + * @param power the power value + * @return the energy value + */ + public static int toEnergy(int power) { + return power / PERIODS_PER_HOUR; + } + + /** + * Converts energy [Wh/15 min] to power [W]. + * + * @param energy the energy value + * @return the power value + */ + public static Integer toPower(Integer energy) { + return multiply(energy, PERIODS_PER_HOUR); + } + + /** + * Interpolate an Array of {@link Integer}s. + * + *

      + * Replaces nulls with previous value. If first entry is null, it is set to + * first available value. If all values are null, all are set to 0. + * + * @param values the values + * @return values without nulls + */ + public static int[] interpolateArray(Integer[] values) { + var firstNonNull = stream(values) // + .filter(Objects::nonNull) // + .findFirst(); + var lastNonNullIndex = IntStream.range(0, values.length) // + .filter(i -> values[i] != null) // + .reduce((first, second) -> second); // + if (lastNonNullIndex.isEmpty()) { + return new int[0]; + } + var result = new int[lastNonNullIndex.getAsInt() + 1]; + if (firstNonNull.isEmpty()) { + // all null + return result; + } + int last = firstNonNull.get(); + for (var i = 0; i < result.length; i++) { + int value = orElse(values[i], last); + result[i] = last = value; + } + return result; + } +} diff --git a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/Version.java b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/Version.java new file mode 100644 index 00000000000..41012cf10de --- /dev/null +++ b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/Version.java @@ -0,0 +1,20 @@ +package io.openems.edge.energy.api; + +public enum Version { + /** + * Version 1. + * + *

      + * Well tested and production ready, but applies only to + * "Controller.Ess.Time-Of-Use-Tariff". + */ + V1_ESS_ONLY, // + /** + * Version 1. + * + *

      + * Work-in-progress that uses new EnergySchedulable interface to provide real + * multi-objective optimization. + */ + V2_ENERGY_SCHEDULABLE +} diff --git a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/simulation/Coefficient.java b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/simulation/Coefficient.java new file mode 100644 index 00000000000..14fa453d462 --- /dev/null +++ b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/simulation/Coefficient.java @@ -0,0 +1,36 @@ +package io.openems.edge.energy.api.simulation; + +import static com.google.common.base.CaseFormat.UPPER_CAMEL; +import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE; + +public enum Coefficient { + /* _sum/Production; positive */ + PROD, + /* _sum/Consumption; positive */ + CONS, + /* _sum/EssActivePower; charge negative; discharge positive */ + ESS, + /* _sum/EssActivePower; sell-to-grid negative, buy-from-grid positive */ + GRID, + /* Production -> Consumption, positive */ + PROD_TO_CONS, + /* Production -> Grid, positive */ + PROD_TO_GRID, + /* Production -> ESS, positive */ + PROD_TO_ESS, + /* Grid -> Consumption, positive */ + GRID_TO_CONS, + /* ESS -> Consumption, positive */ + ESS_TO_CONS, + /* Grid -> ESS, discharge-to-grid negative, charge-from-grid positive */ + GRID_TO_ESS; + + /** + * Gets the {@link Coefficient#name()} in CamelCase. + * + * @return name + */ + public String toCamelCase() { + return UPPER_UNDERSCORE.to(UPPER_CAMEL, this.name()); + } +} \ No newline at end of file diff --git a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/simulation/EnergyFlow.java b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/simulation/EnergyFlow.java new file mode 100644 index 00000000000..4984c83a8ae --- /dev/null +++ b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/simulation/EnergyFlow.java @@ -0,0 +1,657 @@ +package io.openems.edge.energy.api.simulation; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static io.openems.edge.energy.api.simulation.Coefficient.CONS; +import static io.openems.edge.energy.api.simulation.Coefficient.ESS; +import static io.openems.edge.energy.api.simulation.Coefficient.ESS_TO_CONS; +import static io.openems.edge.energy.api.simulation.Coefficient.GRID; +import static io.openems.edge.energy.api.simulation.Coefficient.GRID_TO_CONS; +import static io.openems.edge.energy.api.simulation.Coefficient.GRID_TO_ESS; +import static io.openems.edge.energy.api.simulation.Coefficient.PROD; +import static io.openems.edge.energy.api.simulation.Coefficient.PROD_TO_CONS; +import static io.openems.edge.energy.api.simulation.Coefficient.PROD_TO_ESS; +import static io.openems.edge.energy.api.simulation.Coefficient.PROD_TO_GRID; +import static java.lang.Double.NaN; +import static java.lang.Math.min; +import static java.util.Arrays.stream; +import static java.util.stream.Collectors.joining; +import static org.apache.commons.math3.optim.linear.Relationship.EQ; +import static org.apache.commons.math3.optim.linear.Relationship.GEQ; +import static org.apache.commons.math3.optim.linear.Relationship.LEQ; +import static org.apache.commons.math3.optim.nonlinear.scalar.GoalType.MAXIMIZE; +import static org.apache.commons.math3.optim.nonlinear.scalar.GoalType.MINIMIZE; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.function.Function; + +import org.apache.commons.math3.exception.MathIllegalStateException; +import org.apache.commons.math3.optim.PointValuePair; +import org.apache.commons.math3.optim.linear.LinearConstraint; +import org.apache.commons.math3.optim.linear.LinearConstraintSet; +import org.apache.commons.math3.optim.linear.LinearObjectiveFunction; +import org.apache.commons.math3.optim.linear.Relationship; +import org.apache.commons.math3.optim.linear.SimplexSolver; +import org.apache.commons.math3.optim.nonlinear.scalar.GoalType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.openems.edge.energy.api.simulation.GlobalSimulationsContext.Period; + +/** + * Holds the {@link Solution} of an {@link EnergyFlow.Model} and provides helper + * functions to access the individual {@link Coefficient}s. + */ +public class EnergyFlow { + + private static final Logger LOG = LoggerFactory.getLogger(EnergyFlow.class); + + private final double[] point; + + private EnergyFlow(PointValuePair pvp) { + this.point = pvp.getPointRef(); + } + + /** + * Gets {@link Coefficient#PROD}. + * + * @return the value + */ + public int getProd() { + return this.getValue(PROD); + } + + /** + * Gets {@link Coefficient#CONS}. + * + * @return the value + */ + public int getCons() { + return this.getValue(CONS); + } + + /** + * Gets {@link Coefficient#ESS}. + * + * @return the value + */ + public int getEss() { + return this.getValue(ESS); + } + + /** + * Gets {@link Coefficient#GRID}. + * + * @return the value + */ + public int getGrid() { + return this.getValue(GRID); + } + + /** + * Gets {@link Coefficient#PROD_TO_CONS}. + * + * @return the value + */ + public int getProdToCons() { + return this.getValue(PROD_TO_CONS); + } + + /** + * Gets {@link Coefficient#PROD_TO_ESS}. + * + * @return the value + */ + public int getProdToEss() { + return this.getValue(PROD_TO_ESS); + } + + /** + * Gets {@link Coefficient#PROD_TO_GRID}. + * + * @return the value + */ + public int getProdToGrid() { + return this.getValue(PROD_TO_GRID); + } + + /** + * Gets {@link Coefficient#GRID_TO_CONS}. + * + * @return the value + */ + public int getGridToCons() { + return this.getValue(GRID_TO_CONS); + } + + /** + * Gets {@link Coefficient#GRID_TO_ESS}. + * + * @return the value + */ + public int getGridToEss() { + return this.getValue(GRID_TO_ESS); + } + + /** + * Gets {@link Coefficient#ESS_TO_CONS}. + * + * @return the value + */ + public int getEssToCons() { + return this.getValue(ESS_TO_CONS); + } + + private int getValue(Coefficient coefficient) { + return toInt(this.point[coefficient.ordinal()]); + } + + /** + * Prints all {@link Coefficient}s and their values line by line. + */ + public void print() { + for (var c : Coefficient.values()) { + LOG.info(c.toCamelCase() + ": " + this.getValue(c)); + } + } + + @Override + public String toString() { + return toStringHelper(this) // + .addValue(stream(Coefficient.values()) // + .map(c -> new StringBuilder() // + .append(c.toCamelCase()) // + .append("=") // + .append(this.getValue(c)) // + .toString()) // + .collect(joining(", "))) // + .toString(); + } + + /** + * Models an EnergyFlow as a Linear Equation System with defined + * {@link Coefficient}s for GRID, ESS, CONS, etc. + */ + public static class Model { + + /** + * Generates a {@link EnergyFlow.Model} from a {@link OneSimulationContext} and + * a {@link Period}. + * + * @param osc the {@link OneSimulationContext} + * @param period the {@link Period} + * @return a new {@link EnergyFlow.Model} + */ + public static EnergyFlow.Model from(OneSimulationContext osc, Period period) { + final int factor; // TODO replace with switch in Java 21 + if (period instanceof GlobalSimulationsContext.Period.Hour) { + factor = 4; + } else { + factor = 1; + } + final var ess = osc.global.ess(); + final var grid = osc.global.grid(); + return new EnergyFlow.Model(// + /* production */ period.production(), // + /* consumption */ period.consumption(), // + /* essMaxCharge */ min(ess.maxChargeEnergy() * factor, ess.totalEnergy() - osc.getEssInitial()), // + /* essMaxDischarge */ min(ess.maxDischargeEnergy() * factor, osc.getEssInitial()), // + /* gridMaxBuy */ grid.maxBuy() * factor, // + /* gridMaxSell */ grid.maxSell() * factor); + } + + public final int production; + public final int consumption; + public final int essMaxCharge; + public final int essMaxDischarge; + public final int gridMaxBuy; + public final int gridMaxSell; + + private final List constraints = new ArrayList(); + + public Model(int production, int consumption, int essMaxCharge, int essMaxDischarge, int gridMaxBuy, + int gridMaxSell) { + this.production = production; + this.consumption = consumption; + this.essMaxCharge = essMaxCharge; + this.essMaxDischarge = essMaxDischarge; + this.gridMaxBuy = gridMaxBuy; + this.gridMaxSell = gridMaxSell; + + this + // Internal Relationships + .addConstraint(c -> c // Sum + .setCoefficient(PROD, 1) // + .setCoefficient(ESS, 1) // + .setCoefficient(GRID, 1) // + .setCoefficient(CONS, -1) // + .toLinearConstraint(EQ, 0)) // + .addConstraint(c -> c // Distribute Production + .setCoefficient(PROD, -1) // + .setCoefficient(PROD_TO_CONS, 1) // + .setCoefficient(PROD_TO_ESS, 1) // + .setCoefficient(PROD_TO_GRID, 1) // + .toLinearConstraint(EQ, 0)) // + .addConstraint(b -> b // Distribute Consumption + .setCoefficient(CONS, 1) // + .setCoefficient(ESS_TO_CONS, -1) // + .setCoefficient(GRID_TO_CONS, -1) // + .setCoefficient(PROD_TO_CONS, -1) // + .toLinearConstraint(EQ, 0)) // + .addConstraint(b -> b // Distribute Grid + .setCoefficient(GRID, -1) // + .setCoefficient(PROD_TO_GRID, -1) // + .setCoefficient(GRID_TO_CONS, 1) // + .setCoefficient(GRID_TO_ESS, 1) // + .toLinearConstraint(EQ, 0)) // + .addConstraint(b -> b // Distribute ESS + .setCoefficient(ESS, -1) // + .setCoefficient(PROD_TO_ESS, -1) // + .setCoefficient(ESS_TO_CONS, 1) // + .setCoefficient(GRID_TO_ESS, -1) // + .toLinearConstraint(EQ, 0)) // + .addConstraint(b -> b // Only Positive PROD_TO_ESS + .setCoefficient(PROD_TO_ESS, 1) // + .toLinearConstraint(GEQ, 0)) // + .addConstraint(b -> b // Only Positive PROD_TO_GRID + .setCoefficient(PROD_TO_GRID, 1) // + .toLinearConstraint(GEQ, 0)) // + .addConstraint(b -> b // Only Positive ESS_TO_CONS + .setCoefficient(ESS_TO_CONS, 1) // + .toLinearConstraint(GEQ, 0)) // + .addConstraint(b -> b // Only Positive GRID_TO_CONS + .setCoefficient(GRID_TO_CONS, 1) // + .toLinearConstraint(GEQ, 0)) + + // Production & Consumption + .addConstraint(c -> c // + .setCoefficient(PROD, 1) // + .toLinearConstraint(EQ, production)) // + .addConstraint(c -> c // + .setCoefficient(CONS, 1) // + .toLinearConstraint(EQ, consumption)) + .addConstraint(b -> b // PROD_TO_CONS + .setCoefficient(PROD_TO_CONS, 1) // + .toLinearConstraint(EQ, min(production, consumption))) + + // ESS Max Charge/Discharge + .addConstraint(c -> c // + .setCoefficient(ESS, 1) // + .toLinearConstraint(GEQ, -essMaxCharge)) // + .addConstraint(c -> c // + .setCoefficient(ESS, 1) // + .toLinearConstraint(LEQ, essMaxDischarge)) // + // Grid Max Buy/Sell + .addConstraint(c -> c // + .setCoefficient(GRID, 1) // + .toLinearConstraint(LEQ, gridMaxBuy)) // + .addConstraint(c -> c // + .setCoefficient(GRID, 1) // + .toLinearConstraint(GEQ, -gridMaxSell)); + } + + /** + * Sets the {@link Coefficient#ESS} Charge/Discharge Energy to the given value, + * while making sure the value fits in the active constraints. + * + * @param value the value + * @return actually set value; {@link Double#NaN} on error + */ + public double setEss(int value) { + return this.setFittingCoefficientValue(ESS, EQ, value); + } + + /** + * Limits the {@link Coefficient#ESS} Charge Energy to the given value, while + * making sure the value fits in the active constraints. + * + * @param value the value + * @return actually set value; {@link Double#NaN} on error + */ + public double setEssMaxCharge(int value) { + return this.setFittingCoefficientValue(ESS, GEQ, -value); + } + + /** + * Limits the {@link Coefficient#ESS} Discharge Energy to the given value, while + * making sure the value fits in the active constraints. + * + * @param value the value + * @return actually set value; {@link Double#NaN} on error + */ + public double setEssMaxDischarge(int value) { + return this.setFittingCoefficientValue(ESS, LEQ, value); + } + + /** + * Limits the {@link Coefficient#GRID} Buy Energy to the given value, while + * making sure the value fits in the active constraints. + * + * @param value the value + * @return actually set value; {@link Double#NaN} on error + */ + public double setGridMaxBuy(int value) { + return this.setFittingCoefficientValue(ESS, LEQ, value); + } + + /** + * Limits the {@link Coefficient#GRID} Sell Energy to the given value, while + * making sure the value fits in the active constraints. + * + * @param value the value + * @return actually set value; {@link Double#NaN} on error + */ + public double setGridMaxSell(int value) { + return this.setFittingCoefficientValue(ESS, GEQ, -value); + } + + /** + * Prints a table with all constraints. + */ + public void logConstraints() { + { + var b = new StringBuilder(); + for (var coefficient : Coefficient.values()) { + b.append(String.format("%s ", coefficient.toCamelCase())); + } + LOG.info(b.toString()); + } + for (var constraint : this.constraints) { + var b = new StringBuilder(); + var equation = constraint.getCoefficients(); + for (var coefficient : Coefficient.values()) { + b.append(String.format("% " + coefficient.name().length() + ".0f ", + equation.getEntry(coefficient.ordinal()))); + } + b.append(String.format("%2s % 10.0f", constraint.getRelationship(), constraint.getValue())); + LOG.info(b.toString()); + } + } + + /** + * Prints min/max values for a {@link Coefficient}. + * + * @param coefficient the {@link Coefficient} + */ + public void logMinMaxValues(Coefficient coefficient) { + var values = this.calculateMinMaxValues(coefficient); + var min = values[0]; + var max = values[1]; + LOG.info(String.format("%-12s % 5.0f % 5.0f %s", coefficient.toCamelCase(), min, max, + min == max ? "fixed" : "")); + } + + /** + * Prints a table with all constraints. + */ + public void logMinMaxValues() { + LOG.info(String.format("%-12s %5s %5s", "Coefficient", "Min", "Max")); + for (var coefficient : Coefficient.values()) { + this.logMinMaxValues(coefficient); + } + } + + @Override + public String toString() { + return "EnergyFlow.Model[" // + + Arrays.stream(Coefficient.values()) // + .map(coefficient -> { + var values = this.calculateMinMaxValues(coefficient); + var min = values[0]; + var max = values[1]; + var b = new StringBuilder().append(coefficient.toCamelCase()) // + .append("=") // + .append(min); + if (min == max) { + b // + .append("|fixed"); + } else { + b // + .append("|") // + .append(max); // + } + return b.toString(); + }) // + .collect(joining(",")) // + + "]"; + } + + /** + * Calculates the current Min and Max values for a given {@link Coefficient}. + * + * @param coefficient the {@link Coefficient} + * @return result[0] is the Min value; result[1] is the Max value + */ + private double[] calculateMinMaxValues(Coefficient coefficient) { + final double[] result = new double[2]; + try { + result[0] = this.getExtremeCoefficientValue(coefficient, MINIMIZE); + } catch (MathIllegalStateException e) { + result[0] = NaN; + } + try { + result[1] = this.getExtremeCoefficientValue(coefficient, MAXIMIZE); + } catch (MathIllegalStateException e) { + result[1] = NaN; + } + return result; + } + + private EnergyFlow.Model addConstraint(Function coefficients) { + this.constraints.add(coefficients.apply(new Coefficients())); + return this; + } + + /** + * Gets the minimum or maximum allowed value for the given {@link Coefficient}. + * + * @param coefficient the {@link Coefficient} + * @param goalType the {@link GoalType} + * @return the value + * @throws MathIllegalStateException if this {@link EnergyFlow.Model} is + * unsolvable + */ + public double getExtremeCoefficientValue(Coefficient coefficient, GoalType goalType) + throws MathIllegalStateException { + return solve(goalType, this.constraints, Coefficients.create() // + .setCoefficient(coefficient, 1) // + .toLinearObjectiveFunction(0)) // + .getPointRef()[coefficient.ordinal()]; + } + + /** + * Adds a {@link LinearConstraint} that sets the given {@link Coefficient} to + * the minimum or maximum allowed value. + * + * @param coefficient the {@link Coefficient} + * @param goalType the {@link GoalType} + */ + public void setExtremeCoefficientValue(Coefficient coefficient, GoalType goalType) { + try { + var value = this.getExtremeCoefficientValue(coefficient, goalType); + this.setCoefficientValue(coefficient, value); + } catch (MathIllegalStateException e) { + LOG.warn("[setExtremeCoefficientValue] " // + + "Unable to " + goalType + " " + coefficient + ": " + e.getMessage() + " " // + + this.toString()); + } + } + + /** + * Adds a {@link LinearConstraint} that sets the given {@link Coefficient} to + * the given value, while making sure the value fits in the active constraints. + * + * @param coefficient the {@link Coefficient} + * @param relationship the {@link Relationship}l + * @param value the value + * @return actually set value; {@link Double#NaN} on error + */ + public double setFittingCoefficientValue(Coefficient coefficient, Relationship relationship, double value) { + // Fit to MIN value + try { + var min = this.getExtremeCoefficientValue(coefficient, MINIMIZE); + if (value <= min) { + this.setCoefficientValue(coefficient, relationship, min); + return min; + } + } catch (MathIllegalStateException e) { + LOG.warn("[setFittingCoefficientValue] " // + + "Unable to MINIMIZE " + coefficient + ": " + e.getMessage() + " " // + + this.toString()); + return NaN; + } + + // Fit to MAX value + try { + var max = this.getExtremeCoefficientValue(coefficient, MAXIMIZE); + if (value > max) { + this.setCoefficientValue(coefficient, relationship, max); + return max; + } + } catch (MathIllegalStateException e) { + LOG.warn("[setFittingCoefficientValue] " // + + "Unable to MAXIMIZE " + coefficient + ": " + e.getMessage() + " " // + + this.toString()); + return NaN; + } + + // Apply coefficient value + this.setCoefficientValue(coefficient, relationship, value); + return value; + } + + /** + * Adds a {@link LinearConstraint} that sets the given {@link Coefficient} to + * the given value. + * + * @param coefficient the {@link Coefficient} + * @param value the value + */ + private void setCoefficientValue(Coefficient coefficient, double value) { + this.setCoefficientValue(coefficient, Relationship.EQ, value); + } + + /** + * Adds a {@link LinearConstraint} that constrains the given {@link Coefficient} + * to the given value and {@link Relationship}. + * + * @param coefficient the {@link Coefficient} + * @param relationship the {@link Relationship} + * @param value the value + */ + private void setCoefficientValue(Coefficient coefficient, Relationship relationship, double value) { + this.addConstraint(c -> c // + .setCoefficient(coefficient, 1) // + .toLinearConstraint(relationship, value)); + } + + /** + * Solves the {@link EnergyFlow.Model} and returns an {@link EnergyFlow}. + * + * @return the {@link EnergyFlow}; null if this {@link EnergyFlow.Model} is + * unsolvable + */ + public EnergyFlow solve() { + final double ess; + try { + ess = this.getExtremeCoefficientValue(ESS, MAXIMIZE); + } catch (MathIllegalStateException e) { + LOG.warn("[solve] " // + + "Unable to MAXIMIZE ESS: " + e.getMessage() + " " // + + this.toString()); + return null; + } + if (ess <= 0) { + // ESS Charge or Zero; GRID_TO_ESS must be >= 0 + this.setFittingCoefficientValue(GRID_TO_ESS, GEQ, 0); + this.setFittingCoefficientValue(ESS_TO_CONS, EQ, 0); + } + if (ess >= 0) { + // ESS Discharge or Zero + // Maximize ESS_TO_CONS (1st prio: PROD_TO_CONS; 3rd prio: GRID_TO_CONS) + final double essMax; + try { + essMax = this.getExtremeCoefficientValue(ESS_TO_CONS, MAXIMIZE); + } catch (MathIllegalStateException e) { + LOG.warn("[solve] " // + + "Unable to MAXIMIZE ESS_TO_CONS: " + e.getMessage() + " " // + + this.toString()); + return null; + } + this.setCoefficientValue(ESS_TO_CONS, min(essMax, ess)); + } + + var coefficients = initializeCoefficients(); + Arrays.fill(coefficients, 1); + try { + return new EnergyFlow(solve(MINIMIZE, this.constraints, new LinearObjectiveFunction(coefficients, 0))); + } catch (MathIllegalStateException e) { + LOG.warn("[solve] " // + + "Unable to solve EnergyFlow.Model: " + e.getMessage() + " " // + + this.toString()); + return null; + } + } + + /** + * Solves the linear equation system. + * + * @param goalType {@link GoalType#MINIMIZE} or + * {@link GoalType#MAXIMIZE} the objective function + * @param constraints the {@link LinearConstraint}s + * @param objectiveFunction the {@link LinearObjectiveFunction} + * @return the {@link PointValuePair} + * @throws MathIllegalStateException if this {@link EnergyFlow.Model} is + * unsolvable + */ + private static PointValuePair solve(GoalType goalType, Collection constraints, + LinearObjectiveFunction objectiveFunction) throws MathIllegalStateException { + return new SimplexSolver().optimize(// + objectiveFunction, // + new LinearConstraintSet(constraints), // + goalType); + } + } + + /** + * Helper class to provides a Builder-Pattern like way to create a coefficients + * array suitable for a {@link LinearConstraint} or + * {@link LinearObjectiveFunction}. + */ + private static class Coefficients { + + private static Coefficients create() { + return new Coefficients(); + } + + private final double[] coefficients; + + private Coefficients() { + this.coefficients = initializeCoefficients(); + } + + private Coefficients setCoefficient(Coefficient coefficient, int value) { + this.coefficients[coefficient.ordinal()] = value; + return this; + } + + private LinearConstraint toLinearConstraint(Relationship relationship, double value) { + return new LinearConstraint(this.coefficients, relationship, value); + } + + private LinearObjectiveFunction toLinearObjectiveFunction(int constantTerm) { + return new LinearObjectiveFunction(this.coefficients, constantTerm); + } + + } + + private static double[] initializeCoefficients() { + return new double[Coefficient.values().length]; + } + + private static int toInt(double value) { + return (int) Math.round(value); + } +} diff --git a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/simulation/GlobalSimulationsContext.java b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/simulation/GlobalSimulationsContext.java new file mode 100644 index 00000000000..e9bd6d9aa3b --- /dev/null +++ b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/simulation/GlobalSimulationsContext.java @@ -0,0 +1,325 @@ +package io.openems.edge.energy.api.simulation; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.collect.ImmutableList.toImmutableList; +import static io.openems.edge.common.type.TypeUtils.assertNull; +import static io.openems.edge.energy.api.EnergyConstants.SUM_PRODUCTION; +import static io.openems.edge.energy.api.EnergyConstants.SUM_UNMANAGED_CONSUMPTION; +import static io.openems.edge.energy.api.EnergyUtils.socToEnergy; +import static io.openems.edge.energy.api.EnergyUtils.toEnergy; +import static java.lang.Math.abs; +import static java.lang.Math.min; + +import java.time.Clock; +import java.time.ZonedDateTime; +import java.util.function.Function; +import java.util.function.IntFunction; +import java.util.stream.IntStream; + +import com.google.common.collect.ImmutableList; + +import io.openems.common.exceptions.OpenemsException; +import io.openems.common.utils.DateUtils; +import io.openems.edge.common.sum.Sum; +import io.openems.edge.common.type.TypeUtils; +import io.openems.edge.energy.api.EnergySchedulable; +import io.openems.edge.energy.api.EnergyScheduleHandler; +import io.openems.edge.energy.api.simulation.GlobalSimulationsContext.Period.Hour; +import io.openems.edge.energy.api.simulation.GlobalSimulationsContext.Period.Quarter; +import io.openems.edge.predictor.api.manager.PredictorManager; +import io.openems.edge.timeofusetariff.api.TimeOfUseTariff; + +/** + * Holds the simulation context that is used globally for all simulations in one + * optimization run. + * + *

      + * This record is usually created once per quarter. + */ +public record GlobalSimulationsContext(// + Clock clock, // + /** Start-Timestamp */ + ZonedDateTime startTime, // + ImmutableList handlers, // + Grid grid, // + Ess ess, // + /** + * Period is either mixed, with {@link Hour}s and {@link Quarter}s, or + * {@link Quarter}s only. + */ + ImmutableList periods) { + + @Override + public String toString() { + return toStringHelper(this) // + .add("startTime", this.startTime) // + .addValue(this.grid) // + .addValue(this.ess) // + .add("handlers", this.handlers) // + .toString(); + } + + public static record Ess(// + /** ESS Currently Available Energy (SoC in [Wh]) */ + int currentEnergy, // + /** ESS Total Energy (Capacity) [Wh] */ + int totalEnergy, // + /** ESS Max Charge Energy [Wh] */ + int maxChargeEnergy, // + /** ESS Max Discharge Energy [Wh] */ + int maxDischargeEnergy) { + } + + public static record Grid(// + /** Max Buy-From-Grid Energy [Wh] */ + int maxBuy, // + /** Max Sell-To-Grid Energy [Wh] */ + int maxSell) { + } + + public static sealed interface Period { + /** + * Start-Timestamp of the Period. + * + * @return the {@link ZonedDateTime} + */ + public ZonedDateTime time(); + + /** + * Production prediction for the Period in [Wh]. + * + * @return the production prediction + */ + public int production(); + + /** + * Consumption prediction for the Period in [Wh]. + * + * @return the consumption prediction + */ + public int consumption(); + + /** + * (Average) Grid-Buy-Price for the Period in [1/MWh]. + * + * @return the price + */ + public double price(); + + public static record Quarter(// + ZonedDateTime time, // + int production, // + int consumption, // + double price // + ) implements Period { + } + + public static record Hour(// + ZonedDateTime time, // + int production, // + int consumption, // + double price, // + /** Raw Periods, representing one QUARTER. */ + ImmutableList quarterPeriods // + ) implements Period { + } + } + + public static class Builder { + private Clock clock; + private ImmutableList handlers; + private Sum sum; + private PredictorManager predictorManager; + private TimeOfUseTariff timeOfUseTariff; + + /** + * The {@link Clock}. + * + * @param clock the {@link Clock} + * @return myself + */ + public Builder setClock(Clock clock) { + this.clock = clock; + return this; + } + + /** + * The {@link EnergyScheduleHandler}s of the {@link EnergySchedulable}s. + * + *

      + * The list is sorted by Scheduler. + * + * @param handlers the list of {@link EnergyScheduleHandler}s + * @return myself + */ + public Builder setEnergyScheduleHandlers(ImmutableList handlers) { + this.handlers = handlers; + return this; + } + + /** + * The {@link Sum}. + * + * @param sum the {@link Sum} + * @return myself + */ + public Builder setSum(Sum sum) { + this.sum = sum; + return this; + } + + /** + * The {@link PredictorManager}. + * + * @param predictorManager the {@link PredictorManager} + * @return myself + */ + public Builder setPredictorManager(PredictorManager predictorManager) { + this.predictorManager = predictorManager; + return this; + } + + /** + * The {@link TimeOfUseTariff}. + * + * @param timeOfUseTariff the {@link TimeOfUseTariff} + * @return myself + */ + public Builder setTimeOfUseTariff(TimeOfUseTariff timeOfUseTariff) { + this.timeOfUseTariff = timeOfUseTariff; + return this; + } + + /** + * Builds the {@link GlobalSimulationsContext}. + * + * @return the {@link GlobalSimulationsContext} record + */ + public GlobalSimulationsContext build() throws OpenemsException, IllegalArgumentException { + assertNull("Clock is not available", this.clock); + assertNull("EnergyScheduleHandlers are not available", this.handlers); + assertNull("Sum is not available", this.sum); + assertNull("Predictor-Manager is not available", this.predictorManager); + assertNull("TimeOfUseTariff is not available", this.timeOfUseTariff); + + final var startTime = DateUtils.roundDownToQuarter(ZonedDateTime.now(this.clock)); + + // Prediction values + final var consumptions = this.predictorManager.getPrediction(SUM_UNMANAGED_CONSUMPTION).asArray(); + final var productions = generateProductionPrediction(// + this.predictorManager.getPrediction(SUM_PRODUCTION).asArray(), // + consumptions.length); + + // Prices contains the price values and the time it is retrieved. + final var prices = this.timeOfUseTariff.getPrices().asArray(); + + final var numberOfPeriods = min(min(consumptions.length, productions.length), prices.length); + if (numberOfPeriods == 0) { + throw new IllegalArgumentException("No forecast periods available. " // + + "Consumptions[" + consumptions.length + "] " // + + "Productions[" + productions.length + "] " // + + "Prices[" + prices.length + "]"); + } + + // Helpers + final IntFunction toQuarterPeriod = (i) -> new Period.Quarter(// + startTime.plusMinutes(i * 15), // + toEnergy(productions[i]), // + toEnergy(consumptions[i]), // + prices[i]); + final var periodLengthHourFromIndex = calculatePeriodDurationHourFromIndex(startTime); + + var periods = ImmutableList.builder(); + + // Quarters + for (var i = 0; i < min(periodLengthHourFromIndex, numberOfPeriods); i++) { + periods.add(toQuarterPeriod.apply(i)); + } + + // Hours + final Function range = (i) -> IntStream.range(i, min(i + 4, numberOfPeriods)); + for (int i = periodLengthHourFromIndex, hour = periodLengthHourFromIndex / 4; // + i < numberOfPeriods; // + i += 4, hour++) { + periods.add(new Period.Hour(// + startTime.plusHours(hour), // + toEnergy(range.apply(i).map(j -> productions[j]).sum()), // + toEnergy(range.apply(i).map(j -> consumptions[j]).sum()), // + range.apply(i).mapToDouble(j -> prices[j]).average().getAsDouble(), // + range.apply(i) // + .mapToObj(j -> toQuarterPeriod.apply(j)) // + .collect(toImmutableList()))); + } + + final Ess ess; + { + var essTotalEnergy = this.sum.getEssCapacity().getOrError(); + var essInitialEnergy = socToEnergy(essTotalEnergy, this.sum.getEssSoc().getOrError()); + + // Power Values for scheduling battery for individual periods. + var maxDischargePower = TypeUtils.max(1000 /* at least 1000 W */, // + this.sum.getEssMaxDischargePower().get()); + var maxChargePower = TypeUtils.min(-1000 /* at least 1000 W */, // + this.sum.getEssMinDischargePower().get()); + // TODO + // if (context.limitChargePowerFor14aEnWG()) { + // maxChargePower = max(ESS_LIMIT_14A_ENWG, maxChargePower); // Apply §14a EnWG + // limit + // } + + ess = new Ess(essInitialEnergy, essTotalEnergy, toEnergy(abs(maxChargePower)), + toEnergy(maxDischargePower)); + } + final var grid = new Grid(40000 /* TODO */, 20000 /* TODO */); + + return new GlobalSimulationsContext(this.clock, startTime, this.handlers, grid, ess, periods.build()); + } + } + + /** + * Create a {@link GlobalSimulationsContext} {@link Builder}. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new GlobalSimulationsContext.Builder(); + } + + /** + * Postprocesses production prediction; makes sure length is at least the same + * as consumption prediction - filling up with zeroes. + * + * @param prediction the production prediction + * @param minLength the min length (= consumption prediction length) + * @return new production prediction + */ + protected static Integer[] generateProductionPrediction(Integer[] prediction, int minLength) { + if (prediction.length >= minLength) { + return prediction; + } + return IntStream.range(0, minLength) // + .mapToObj(i -> i > prediction.length - 1 ? 0 : prediction[i]) // + .toArray(Integer[]::new); + } + + /** + * Calculates the index when Period duration switches from {@link Hour} to + * {@link Quarter}. + * + *

      + * The index is calculated as "6 hours" plus remaining quarters of the current + * hour. + * + * @param time Start-Timestamp of the Schedule + * @return the index + */ + // TODO this should be set depending on the actual calculation time and + // quality of the best schedule result + protected static int calculatePeriodDurationHourFromIndex(ZonedDateTime time) { + var minute = time.getMinute(); + if (minute == 0) { + minute = 60; + } + return 6 * 4 + (60 - minute) / 15; + } +} diff --git a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/simulation/OneSimulationContext.java b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/simulation/OneSimulationContext.java new file mode 100644 index 00000000000..0e6244a2975 --- /dev/null +++ b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/simulation/OneSimulationContext.java @@ -0,0 +1,59 @@ +package io.openems.edge.energy.api.simulation; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static java.lang.Math.max; + +/** + * Holds the simulation context that is used for one simulation of a full + * schedule with multiple periods. + * + *

      + * This record is usually created multiple times per second. + */ +public class OneSimulationContext { + + /** + * Builds a {@link OneSimulationContext}. + * + * @param asc the {@link GlobalSimulationsContext} + * @return the {@link OneSimulationContext} + */ + public static OneSimulationContext from(GlobalSimulationsContext asc) { + return new OneSimulationContext(asc, asc.ess().currentEnergy()); + } + + public final GlobalSimulationsContext global; + + private int essInitialEnergy; + + private OneSimulationContext(GlobalSimulationsContext gsc, int essInitialEnergy) { + this.global = gsc; + this.essInitialEnergy = essInitialEnergy; + } + + /** + * Calculates the initial SoC-Energy of the next Period. + * + * @param ess the ess charge/discharge energy of the current Period + */ + public synchronized void calculateEssInitial(int ess) { + this.essInitialEnergy = max(0, this.essInitialEnergy - ess); // always at least '0' + } + + /** + * The initial SoC-Energy of the Period. + * + * @return the value + */ + public int getEssInitial() { + return this.essInitialEnergy; + } + + @Override + public String toString() { + return toStringHelper(this) // + .add("essInitialEnergy", this.essInitialEnergy) // + .addValue(this.global) // + .toString(); + } +} diff --git a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/simulation/package-info.java b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/simulation/package-info.java new file mode 100644 index 00000000000..479bc6029cb --- /dev/null +++ b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/simulation/package-info.java @@ -0,0 +1,3 @@ +@org.osgi.annotation.versioning.Version("1.0.0") +@org.osgi.annotation.bundle.Export +package io.openems.edge.energy.api.simulation; diff --git a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/test/AbstractDummyEnergySchedulable.java b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/test/AbstractDummyEnergySchedulable.java new file mode 100644 index 00000000000..0880e69eb33 --- /dev/null +++ b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/test/AbstractDummyEnergySchedulable.java @@ -0,0 +1,16 @@ +package io.openems.edge.energy.api.test; + +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.test.AbstractDummyOpenemsComponent; +import io.openems.edge.energy.api.EnergySchedulable; + +public abstract class AbstractDummyEnergySchedulable> + extends AbstractDummyOpenemsComponent implements EnergySchedulable, OpenemsComponent { + + protected AbstractDummyEnergySchedulable(String id, + io.openems.edge.common.channel.ChannelId[] firstInitialChannelIds, + io.openems.edge.common.channel.ChannelId[]... furtherInitialChannelIds) { + super(id, firstInitialChannelIds, furtherInitialChannelIds); + } + +} diff --git a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/test/DummyEnergySchedulable.java b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/test/DummyEnergySchedulable.java new file mode 100644 index 00000000000..53bac023549 --- /dev/null +++ b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/test/DummyEnergySchedulable.java @@ -0,0 +1,37 @@ +package io.openems.edge.energy.api.test; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.energy.api.EnergySchedulable; +import io.openems.edge.energy.api.EnergyScheduleHandler; + +/** + * Provides a simple, simulated {@link EnergySchedulable} component that can be + * used together with the OpenEMS Component test framework. + */ +public class DummyEnergySchedulable extends AbstractDummyEnergySchedulable + implements EnergySchedulable, OpenemsComponent { + + private final EnergyScheduleHandler esh; + + public DummyEnergySchedulable(String id, EnergyScheduleHandler esh) { + super(id, // + OpenemsComponent.ChannelId.values() // + ); + this.esh = esh; + } + + @Override + protected final DummyEnergySchedulable self() { + return this; + } + + @Override + public void run() throws OpenemsNamedException { + } + + @Override + public EnergyScheduleHandler getEnergyScheduleHandler() { + return this.esh; + } +} diff --git a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/test/DummyGlobalSimulationsContext.java b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/test/DummyGlobalSimulationsContext.java new file mode 100644 index 00000000000..8918dd8f5f1 --- /dev/null +++ b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/test/DummyGlobalSimulationsContext.java @@ -0,0 +1,99 @@ +package io.openems.edge.energy.api.test; + +import static com.google.common.collect.ImmutableList.toImmutableList; + +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.Arrays; + +import com.google.common.collect.ImmutableList; + +import io.openems.common.test.TimeLeapClock; +import io.openems.edge.energy.api.EnergyScheduleHandler; +import io.openems.edge.energy.api.simulation.GlobalSimulationsContext; +import io.openems.edge.energy.api.simulation.GlobalSimulationsContext.Period; + +public class DummyGlobalSimulationsContext { + + private DummyGlobalSimulationsContext() { + } + + public static final TimeLeapClock CLOCK = new TimeLeapClock(Instant.ofEpochSecond(946684800), ZoneId.of("UTC")); + public static final ZonedDateTime TIME = ZonedDateTime.now(CLOCK); + + /** + * Generates a {@link GlobalSimulationsContext} with the given + * {@link EnergyScheduleHandler}s. + * + * @param handlers the {@link EnergyScheduleHandler}s + * @return a {@link GlobalSimulationsContext} + */ + public static GlobalSimulationsContext fromHandlers(EnergyScheduleHandler... handlers) { + return new GlobalSimulationsContext(// + CLOCK, TIME, // + Arrays.stream(handlers).collect(toImmutableList()), // + new GlobalSimulationsContext.Grid(4000, 20000), // + new GlobalSimulationsContext.Ess(5000, 22000, 4000, 4000), // + ImmutableList.of(// + new Period.Quarter(time(0, 0), 0, 106, 293.70), // + new Period.Quarter(time(0, 15), 0, 86, 293.70), // + new Period.Quarter(time(0, 30), 0, 88, 293.70), // + new Period.Quarter(time(0, 45), 0, 81, 293.70), // + new Period.Quarter(time(1, 0), 0, 73, 294.30), // + new Period.Quarter(time(1, 15), 0, 68, 294.30), // + new Period.Quarter(time(1, 30), 0, 76, 294.30), // + new Period.Quarter(time(1, 45), 0, 149, 294.30), // + new Period.Quarter(time(2, 0), 0, 333, 289.30), // + new Period.Quarter(time(2, 15), 0, 61, 289.30), // + new Period.Quarter(time(2, 30), 0, 74, 289.30), // + new Period.Quarter(time(2, 45), 0, 73, 289.30), // + new Period.Quarter(time(3, 0), 0, 68, 288.00), // + new Period.Quarter(time(3, 15), 0, 66, 288.00), // + new Period.Quarter(time(3, 30), 0, 82, 288.00), // + new Period.Quarter(time(3, 45), 0, 99, 288.00), // + new Period.Quarter(time(4, 0), 0, 84, 288.80), // + new Period.Quarter(time(4, 15), 0, 80, 288.80), // + new Period.Quarter(time(4, 30), 0, 97, 288.80), // + new Period.Quarter(time(4, 45), 0, 85, 288.80), // + new Period.Quarter(time(5, 0), 0, 65, 302.90), // + new Period.Quarter(time(5, 15), 0, 69, 302.90), // + new Period.Quarter(time(5, 30), 0, 75, 302.90), // + new Period.Quarter(time(5, 45), 3, 90, 302.90), // + new Period.Quarter(time(6, 0), 6, 394, 331.70), // + new Period.Quarter(time(6, 15), 36, 106, 331.70), // + new Period.Quarter(time(6, 30), 112, 94, 331.70), // + new Period.Quarter(time(6, 45), 205, 74, 331.70), // + new Period.Quarter(time(7, 0), 342, 62, 342.50), // + new Period.Quarter(time(7, 15), 437, 74, 342.50), // + new Period.Quarter(time(7, 30), 518, 72, 342.50), // + new Period.Quarter(time(7, 45), 628, 60, 342.50), // + new Period.Quarter(time(8, 0), 931, 46, 332.70), // + new Period.Quarter(time(8, 15), 1159, 45, 332.70), // + new Period.Quarter(time(8, 30), 1349, 40, 332.70), // + new Period.Quarter(time(8, 45), 1543, 26, 332.70), // + new Period.Quarter(time(9, 0), 1743, 46, 311.80), // + new Period.Quarter(time(9, 15), 1920, 472, 311.80), // + new Period.Quarter(time(9, 30), 2112, 498, 311.80), // + new Period.Quarter(time(9, 45), 2209, 83, 311.80), // + new Period.Quarter(time(10, 0), 2436, 105, 292.10), // + new Period.Quarter(time(10, 15), 2671, 92, 292.10), // + new Period.Quarter(time(10, 30), 2723, 133, 292.10), // + new Period.Quarter(time(10, 45), 2824, 88, 292.10), // + new Period.Hour(time(11, 0), 11610, 716, 282.90, ImmutableList.of(// + new Period.Quarter(time(11, 0), 2878, 86, 282.90), // + new Period.Quarter(time(11, 15), 2871, 245, 282.90), // + new Period.Quarter(time(11, 30), 2883, 308, 282.90), // + new Period.Quarter(time(11, 45), 2978, 77, 282.90))), // + new Period.Hour(time(12, 0), 6118, 241, 260.70, ImmutableList.of(// + new Period.Quarter(time(12, 0), 3044, 54, 260.70), // + new Period.Quarter(time(12, 15), 3022, 64, 260.70), // + new Period.Quarter(time(12, 30), 3036, 64, 260.70), // + new Period.Quarter(time(12, 45), 3045, 59, 260.70))) // + )); + } + + private static ZonedDateTime time(int hours, int minutes) { + return TIME.plusHours(hours).plusMinutes(minutes); + } +} diff --git a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/test/package-info.java b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/test/package-info.java new file mode 100644 index 00000000000..b8f87f83ce3 --- /dev/null +++ b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/test/package-info.java @@ -0,0 +1,3 @@ +@org.osgi.annotation.versioning.Version("1.0.0") +@org.osgi.annotation.bundle.Export +package io.openems.edge.energy.api.test; diff --git a/io.openems.edge.energy.api/test/io/openems/edge/energy/api/EnergyUtilsTest.java b/io.openems.edge.energy.api/test/io/openems/edge/energy/api/EnergyUtilsTest.java new file mode 100644 index 00000000000..b4a6a7f2d69 --- /dev/null +++ b/io.openems.edge.energy.api/test/io/openems/edge/energy/api/EnergyUtilsTest.java @@ -0,0 +1,55 @@ +package io.openems.edge.energy.api; + +import static io.openems.edge.energy.api.EnergyUtils.findFirstPeakIndex; +import static io.openems.edge.energy.api.EnergyUtils.findFirstValleyIndex; +import static io.openems.edge.energy.api.EnergyUtils.interpolateArray; +import static io.openems.edge.energy.api.EnergyUtils.toPower; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import org.junit.Test; + +public class EnergyUtilsTest { + + @Test + public void testFindFirstPeakIndex() { + assertEquals(0, findFirstPeakIndex(0, new double[0])); + assertEquals(0, findFirstPeakIndex(0, new double[] { 1 })); + assertEquals(0, findFirstPeakIndex(0, new double[] { 1, 0 })); + assertEquals(1, findFirstPeakIndex(0, new double[] { 0, 1, 0 })); + assertEquals(1, findFirstPeakIndex(0, new double[] { 0, 1, 0, 1 })); + assertEquals(5, findFirstPeakIndex(5, new double[0])); + } + + @Test + public void testFindFirstValleyIndex() { + assertEquals(0, findFirstValleyIndex(0, new double[0])); + assertEquals(0, findFirstValleyIndex(0, new double[] { 1 })); + assertEquals(1, findFirstValleyIndex(0, new double[] { 1, 0 })); + assertEquals(0, findFirstValleyIndex(0, new double[] { 0, 1, 0 })); + assertEquals(2, findFirstValleyIndex(1, new double[] { 0, 1, 0, 1 })); + assertEquals(5, findFirstValleyIndex(5, new double[0])); + } + + @Test + public void testInterpolateArrayInteger() { + assertArrayEquals(new int[] { 123, 123, 234, 234, 345 }, // + interpolateArray(new Integer[] { null, 123, 234, null, 345, null })); + + assertArrayEquals(new int[] {}, // + interpolateArray(new Integer[] { null })); + + assertArrayEquals(new int[] { 123, 123 }, // + interpolateArray(new Integer[] { null, 123 })); + + assertArrayEquals(new int[] { 123 }, // + interpolateArray(new Integer[] { 123, null })); + } + + @Test + public void testToPower() { + assertEquals(2000, (int) toPower(500)); + assertNull(toPower(null)); + } +} diff --git a/io.openems.edge.energy.api/test/io/openems/edge/energy/api/simulation/GlobalSimulationsContextTest.java b/io.openems.edge.energy.api/test/io/openems/edge/energy/api/simulation/GlobalSimulationsContextTest.java new file mode 100644 index 00000000000..18eb644ba9c --- /dev/null +++ b/io.openems.edge.energy.api/test/io/openems/edge/energy/api/simulation/GlobalSimulationsContextTest.java @@ -0,0 +1,95 @@ +package io.openems.edge.energy.api.simulation; + +import static io.openems.edge.energy.api.simulation.GlobalSimulationsContext.calculatePeriodDurationHourFromIndex; +import static io.openems.edge.energy.api.simulation.GlobalSimulationsContext.generateProductionPrediction; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; + +import org.junit.Test; + +import com.google.common.collect.ImmutableList; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.test.TimeLeapClock; +import io.openems.edge.common.sum.DummySum; +import io.openems.edge.common.test.DummyComponentManager; +import io.openems.edge.energy.api.EnergyConstants; +import io.openems.edge.predictor.api.prediction.Prediction; +import io.openems.edge.predictor.api.test.DummyPredictor; +import io.openems.edge.predictor.api.test.DummyPredictorManager; +import io.openems.edge.timeofusetariff.test.DummyTimeOfUseTariffProvider; + +public class GlobalSimulationsContextTest { + + private static final TimeLeapClock CLOCK = new TimeLeapClock(Instant.ofEpochSecond(946684800), ZoneId.of("UTC")); + + @Test + public void testBuild() throws OpenemsNamedException { + final var cm = new DummyComponentManager(CLOCK); + final var now = ZonedDateTime.now(CLOCK); + final var sum = new DummySum() // + .withEssCapacity(10000) // + .withEssSoc(50) // + .withEssMinDischargePower(-4000) // + .withEssMaxDischargePower(5000); + final var predictorManager = new DummyPredictorManager(// + new DummyPredictor("predictor0", cm, Prediction.from(sum, // + EnergyConstants.SUM_UNMANAGED_CONSUMPTION, now, new Integer[] { // + 4000, 8000, 6000, 2000, 3000, 5000, 7000, 9000, // + 4001, 8001, 6001, 2001, 3001, 5001, 7001, 9001, // + 4002, 8002, 6002, 2002, 3002, 5002, 7002, 9002, // + 4003, 8003, 6003, 2003, 3003, 5003, 7003, 9003, // + 4004, 8004, 6004, 2004, 3004, 5004, 7004, 9004, // + }), EnergyConstants.SUM_UNMANAGED_CONSUMPTION), + new DummyPredictor("predictor1", cm, Prediction.from(sum, // + EnergyConstants.SUM_PRODUCTION, now, + new Integer[] { 8000, 9000, 10000, 11000, 7000, 4000, 3000, 5000, // + 8001, 9001, 10001, 11001, 7001, 4001, 3001, 5001, // + 8002, 9002, 10002, 11002, 7002, 4002, 3002, 5002, // + 8003, 9003, 10003, 11003, 7003, 4003, 3003, 5003, // + 8004, 9004, 10004, 11004, 7004, 4004, 3004, 5004, // + }), EnergyConstants.SUM_PRODUCTION)); + final var prices = DummyTimeOfUseTariffProvider.fromQuarterlyPrices(CLOCK, // + 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, // + 11.1, 12.1, 13.1, 14.1, 15.1, 16.1, 17.1, 18.1, // + 11.2, 12.2, 13.2, 14.2, 15.2, 16.2, 17.2, 18.2, // + 11.3, 12.3, 13.3, 14.3, 15.3, 16.3, 17.3, 18.3, // + 11.4, 12.4, 13.4, 14.4, 15.4, 16.4, 17.4, 18.4 // + ); + + var gsc = GlobalSimulationsContext.create() // + .setClock(CLOCK) // + .setEnergyScheduleHandlers(ImmutableList.of()) // + .setSum(sum) // + .setPredictorManager(predictorManager) // + .setTimeOfUseTariff(prices) // + .build(); + + assertEquals(1000 /* -4000 W */, gsc.ess().maxChargeEnergy()); + assertEquals(1250 /* 5000 W */, gsc.ess().maxDischargeEnergy()); + assertEquals(28, gsc.periods().size()); + var p0 = gsc.periods().get(0); + assertEquals(2000 /* Wh */, p0.production()); + assertEquals(1000 /* Wh */, p0.consumption()); + } + + @Test + public void testGenerateProductionPrediction() { + final var arr = new Integer[] { 1, 2, 3 }; + assertArrayEquals(arr, generateProductionPrediction(arr, 2)); + assertArrayEquals(new Integer[] { 1, 2, 3, 0 }, generateProductionPrediction(arr, 4)); + } + + @Test + public void testCalculatePeriodDurationHourFromIndex() { + assertEquals(24, calculatePeriodDurationHourFromIndex(ZonedDateTime.parse("2020-03-04T14:00:00.00Z"))); + assertEquals(24 + 3, calculatePeriodDurationHourFromIndex(ZonedDateTime.parse("2020-03-04T14:15:00.00Z"))); + assertEquals(24 + 2, calculatePeriodDurationHourFromIndex(ZonedDateTime.parse("2020-03-04T14:30:00.00Z"))); + assertEquals(24 + 1, calculatePeriodDurationHourFromIndex(ZonedDateTime.parse("2020-03-04T14:45:00.00Z"))); + assertEquals(24, calculatePeriodDurationHourFromIndex(ZonedDateTime.parse("2020-03-04T15:00:00.00Z"))); + } +} diff --git a/io.openems.edge.energy/bnd.bnd b/io.openems.edge.energy/bnd.bnd index 7df50f07c5e..2b14c6014a9 100644 --- a/io.openems.edge.energy/bnd.bnd +++ b/io.openems.edge.energy/bnd.bnd @@ -3,20 +3,29 @@ Bundle-Vendor: FENECON GmbH Bundle-License: https://opensource.org/licenses/EPL-2.0 Bundle-Version: 1.0.0.${tstamp} +# TODO remove emergencycapacityreserve and limittotaldischarge from buildpath after v1 + -buildpath: \ ${buildpath},\ io.openems.common,\ io.openems.edge.common,\ io.openems.edge.controller.api,\ io.openems.edge.controller.ess.emergencycapacityreserve,\ + io.openems.edge.controller.ess.fixactivepower,\ io.openems.edge.controller.ess.limittotaldischarge,\ io.openems.edge.controller.ess.timeofusetariff,\ io.openems.edge.energy.api,\ io.openems.edge.ess.api,\ io.openems.edge.predictor.api,\ + io.openems.edge.scheduler.api,\ io.openems.edge.timedata.api,\ io.openems.edge.timeofusetariff.api,\ io.openems.wrapper.jenetics,\ - + -testpath: \ - ${testpath} \ No newline at end of file + ${testpath},\ + io.openems.edge.controller.ess.emergencycapacityreserve,\ + io.openems.edge.controller.ess.gridoptimizedcharge,\ + io.openems.edge.controller.ess.limittotaldischarge,\ + io.openems.edge.controller.ess.timeofusetariff,\ + org.apache.commons.math3,\ diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/Config.java b/io.openems.edge.energy/src/io/openems/edge/energy/Config.java index dad00cde174..1552f7dafa1 100644 --- a/io.openems.edge.energy/src/io/openems/edge/energy/Config.java +++ b/io.openems.edge.energy/src/io/openems/edge/energy/Config.java @@ -3,6 +3,8 @@ import org.osgi.service.metatype.annotations.AttributeDefinition; import org.osgi.service.metatype.annotations.ObjectClassDefinition; +import io.openems.edge.energy.api.Version; + @ObjectClassDefinition(// name = "Core Energy Scheduler", // description = "The global Energy Scheduler.") @@ -14,5 +16,8 @@ @AttributeDefinition(name = "Log-Verbosity", description = "The log verbosity") LogVerbosity logVerbosity() default LogVerbosity.DEBUG_LOG; + @AttributeDefinition(name = "Version", description = "Select version of implementation") + Version version() default Version.V1_ESS_ONLY; + String webconsole_configurationFactory_nameHint() default "Core Energy Scheduler"; } \ No newline at end of file diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/EnergySchedulerImpl.java b/io.openems.edge.energy/src/io/openems/edge/energy/EnergySchedulerImpl.java index 88da0a70170..80d830c61cc 100644 --- a/io.openems.edge.energy/src/io/openems/edge/energy/EnergySchedulerImpl.java +++ b/io.openems.edge.energy/src/io/openems/edge/energy/EnergySchedulerImpl.java @@ -1,10 +1,14 @@ package io.openems.edge.energy; -import static io.openems.edge.energy.optimizer.Utils.handleGetScheduleRequest; +import static com.google.common.collect.ImmutableList.toImmutableList; +import static io.openems.common.utils.ThreadPoolUtils.shutdownAndAwaitTermination; +import static io.openems.edge.energy.optimizer.Utils.sortByScheduler; import java.time.ZonedDateTime; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentContext; @@ -21,18 +25,24 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; +import io.openems.common.jsonrpc.base.JsonrpcRequest; +import io.openems.common.jsonrpc.base.JsonrpcResponse; import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.common.jsonapi.ComponentJsonApi; -import io.openems.edge.common.jsonapi.JsonApiBuilder; +import io.openems.edge.common.jsonapi.Call; import io.openems.edge.common.sum.Sum; -import io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImpl; +import io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffController; import io.openems.edge.energy.api.EnergySchedulable; +import io.openems.edge.energy.api.EnergyScheduleHandler.AbstractEnergyScheduleHandler; import io.openems.edge.energy.api.EnergyScheduler; -import io.openems.edge.energy.jsonrpc.GetScheduleRequest; -import io.openems.edge.energy.optimizer.GlobalContext; +import io.openems.edge.energy.api.Version; +import io.openems.edge.energy.api.simulation.GlobalSimulationsContext; import io.openems.edge.energy.optimizer.Optimizer; +import io.openems.edge.energy.v1.jsonrpc.GetScheduleResponse; +import io.openems.edge.energy.v1.optimizer.GlobalContextV1; +import io.openems.edge.energy.v1.optimizer.OptimizerV1; +import io.openems.edge.energy.v1.optimizer.UtilsV1; import io.openems.edge.predictor.api.manager.PredictorManager; import io.openems.edge.timedata.api.Timedata; import io.openems.edge.timeofusetariff.api.TimeOfUseTariff; @@ -43,11 +53,13 @@ immediate = true, // configurationPolicy = ConfigurationPolicy.OPTIONAL // ) -public class EnergySchedulerImpl extends AbstractOpenemsComponent - implements OpenemsComponent, EnergyScheduler, ComponentJsonApi { +@SuppressWarnings("deprecation") +public class EnergySchedulerImpl extends AbstractOpenemsComponent implements OpenemsComponent, EnergyScheduler { /** The hard working Optimizer. */ + private final OptimizerV1 optimizerV1; private final Optimizer optimizer; + private final ExecutorService executor = Executors.newSingleThreadExecutor(); @Reference private ConfigurationAdmin cm; @@ -61,18 +73,40 @@ public class EnergySchedulerImpl extends AbstractOpenemsComponent @Reference(policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) private volatile TimeOfUseTariff timeOfUseTariff; + @Reference + private io.openems.edge.scheduler.api.Scheduler scheduler; + @Reference private Sum sum; + private final List schedulables = new CopyOnWriteArrayList<>(); + @Reference(policyOption = ReferencePolicyOption.GREEDY, // cardinality = ReferenceCardinality.MULTIPLE, // policy = ReferencePolicy.DYNAMIC, // target = "(enabled=true)") - private volatile List> schedulables = new CopyOnWriteArrayList<>(); + private void addSchedulable(EnergySchedulable schedulable) { + this.schedulables.add(schedulable); + var esh = (AbstractEnergyScheduleHandler) schedulable.getEnergyScheduleHandler(); // this is safe + esh.setOnRescheduleCallback(() -> this.optimizer.triggerReschedule()); + this.resetOptimizer(); + } + + @SuppressWarnings("unused") + private void removeSchedulable(EnergySchedulable schedulable) { + this.schedulables.remove(schedulable); + var esh = (AbstractEnergyScheduleHandler) schedulable.getEnergyScheduleHandler(); // this is safe + esh.removeOnRescheduleCallback(); + this.resetOptimizer(); + } @Reference(policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) private volatile Timedata timedata; + @Deprecated + @Reference(policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL, target = "(enabled=true)") + private volatile TimeOfUseTariffController timeOfUseTariffController; + private Config config; public EnergySchedulerImpl() { @@ -80,57 +114,91 @@ public EnergySchedulerImpl() { OpenemsComponent.ChannelId.values(), // EnergyScheduler.ChannelId.values() // ); - // Prepare Optimizer and Context - this.optimizer = new Optimizer(// + + this.optimizerV1 = new OptimizerV1(// () -> this.config.logVerbosity(), // () -> { if (this.timeOfUseTariff == null) { throw new OpenemsException("TimeOfUseTariff is not available"); } - var ctrl = this.schedulables.stream() // - .filter(TimeOfUseTariffControllerImpl.class::isInstance) // - .map(TimeOfUseTariffControllerImpl.class::cast) // - .findFirst().orElse(null); - if (ctrl == null) { + if (this.timeOfUseTariffController == null) { throw new OpenemsException("TimeOfUseTariffController is not available"); } - var esh = ctrl.getEnergyScheduleHandler(); - // NOTE: This is a workaround while we refactor TimeOfUseTariffController - // This code assumes that the `EnergySchedulable` is a - // `TimeOfUseTariffController` - return GlobalContext.create() // + return GlobalContextV1.create() // .setClock(this.componentManager.getClock()) // - .setEnergyScheduleHandler(esh) // + .setEnergyScheduleHandler(this.timeOfUseTariffController.getEnergyScheduleHandlerV1()) // .setSum(this.sum) // .setPredictorManager(this.predictorManager) // .setTimeOfUseTariff(this.timeOfUseTariff) // .build(); }); + + this.optimizer = new Optimizer(// + () -> this.config.logVerbosity(), // + () -> { + // Sort Schedulables by the order in the Scheduler + var schedulables = sortByScheduler(this.scheduler, this.schedulables); + var eshs = schedulables.stream() // + .map(EnergySchedulable::getEnergyScheduleHandler) // + .collect(toImmutableList()); + + return GlobalSimulationsContext.create() // + .setClock(this.componentManager.getClock()) // + .setEnergyScheduleHandlers(eshs) // + .setSum(this.sum) // + .setPredictorManager(this.predictorManager) // + .setTimeOfUseTariff(this.timeOfUseTariff) // + .build(); + }, // + this.channel(EnergyScheduler.ChannelId.SIMULATIONS_PER_QUARTER)); } @Activate private void activate(ComponentContext context, Config config) throws OpenemsException { super.activate(context, SINGLETON_COMPONENT_ID, SINGLETON_SERVICE_PID, true); + if (this.applyConfig(config)) { - this.optimizer.activate(this.id()); + switch (config.version()) { + case V1_ESS_ONLY -> this.optimizerV1.activate(this.id()); + case V2_ENERGY_SCHEDULABLE -> this.executor.execute(this.optimizer); + } } } @Modified private void modified(ComponentContext context, Config config) throws OpenemsNamedException { super.modified(context, SINGLETON_COMPONENT_ID, SINGLETON_SERVICE_PID, true); - if (this.applyConfig(config)) { - this.optimizer.modified(this.id()); + this.applyConfig(config); + } + + private void resetOptimizer() { + if (this.config == null) { + return; // Wait for @Activate + } + switch (this.config.version()) { + case V1_ESS_ONLY -> this.optimizerV1.activate(this.id()); + case V2_ENERGY_SCHEDULABLE -> this.optimizer.triggerReschedule(); } } + @Override + public String debugLog() { + if (this.config != null && this.config.version() == Version.V2_ENERGY_SCHEDULABLE) { + return this.optimizer.debugLog(); + } + return null; + } + private synchronized boolean applyConfig(Config config) { this.config = config; if (OpenemsComponent.validateSingleton(this.cm, SINGLETON_SERVICE_PID, SINGLETON_COMPONENT_ID)) { return false; } - if (!config.enabled()) { + if (config.enabled()) { + this.resetOptimizer(); + } else { + this.optimizerV1.deactivate(); this.optimizer.deactivate(); return false; } @@ -141,23 +209,18 @@ private synchronized boolean applyConfig(Config config) { @Override @Deactivate protected void deactivate() { + this.optimizerV1.deactivate(); this.optimizer.deactivate(); + shutdownAndAwaitTermination(this.executor, 0); super.deactivate(); } @Override - public String debugLog() { - if (this.config == null || this.config.logVerbosity() == LogVerbosity.NONE) { - return null; + public GetScheduleResponse handleGetScheduleRequestV1(Call call, String id) { + if (this.optimizerV1 != null) { + return UtilsV1.handleGetScheduleRequest(this.optimizerV1, call.getRequest().getId(), this.timedata, + this.timeOfUseTariff, id, ZonedDateTime.now(this.componentManager.getClock())); } - // TODO add debug log - return null; - } - - @Override - public void buildJsonApiRoutes(JsonApiBuilder builder) { - builder.handleRequest(GetScheduleRequest.METHOD, call -> handleGetScheduleRequest(// - this.optimizer, call.getRequest().getId(), this.timedata, this.timeOfUseTariff, - "ctrlEssTimeOfUseTariff0", ZonedDateTime.now(this.componentManager.getClock()))); + throw new IllegalArgumentException("This should have been Version V1"); } } diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/LogVerbosity.java b/io.openems.edge.energy/src/io/openems/edge/energy/LogVerbosity.java index 130bd15e512..27f2d942c3b 100644 --- a/io.openems.edge.energy/src/io/openems/edge/energy/LogVerbosity.java +++ b/io.openems.edge.energy/src/io/openems/edge/energy/LogVerbosity.java @@ -10,4 +10,4 @@ public enum LogVerbosity { * Trace. */ TRACE; -} \ No newline at end of file +} diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Optimizer.java b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Optimizer.java index 3188e15f364..63ca31e3315 100644 --- a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Optimizer.java +++ b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Optimizer.java @@ -1,152 +1,215 @@ package io.openems.edge.energy.optimizer; -import static com.google.common.collect.ImmutableMap.toImmutableMap; -import static com.google.common.collect.ImmutableSortedMap.toImmutableSortedMap; -import static io.openems.edge.energy.optimizer.Simulator.simulate; +import static io.jenetics.engine.Limits.byExecutionTime; +import static io.openems.common.utils.DateUtils.roundDownToQuarter; +import static io.openems.edge.energy.optimizer.QuickSchedules.findBestQuickSchedule; import static io.openems.edge.energy.optimizer.Utils.calculateExecutionLimitSeconds; -import static io.openems.edge.energy.optimizer.Utils.createSimulatorParams; +import static io.openems.edge.energy.optimizer.Utils.createSimulator; import static io.openems.edge.energy.optimizer.Utils.initializeRandomRegistryForProduction; -import static io.openems.edge.energy.optimizer.Utils.logSchedule; -import static io.openems.edge.energy.optimizer.Utils.updateSchedule; -import static java.lang.Thread.sleep; +import static io.openems.edge.energy.optimizer.Utils.logSimulationResult; +import static java.time.Duration.ofSeconds; -import java.time.Duration; -import java.time.Instant; +import java.time.Clock; import java.time.ZonedDateTime; -import java.util.Map.Entry; -import java.util.TreeMap; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Supplier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.collect.ImmutableSortedMap; - import io.openems.common.exceptions.OpenemsException; import io.openems.common.function.ThrowingSupplier; -import io.openems.common.test.TimeLeapClock; import io.openems.common.utils.FunctionUtils; -import io.openems.common.worker.AbstractImmediateWorker; +import io.openems.edge.common.channel.Channel; import io.openems.edge.energy.LogVerbosity; import io.openems.edge.energy.api.EnergyScheduleHandler; -import io.openems.edge.energy.optimizer.Simulator.Period; +import io.openems.edge.energy.api.simulation.GlobalSimulationsContext; /** * This task is executed once in the beginning and afterwards every full 15 * minutes. */ -public class Optimizer extends AbstractImmediateWorker { +public class Optimizer implements Runnable { private final Logger log = LoggerFactory.getLogger(Optimizer.class); private final Supplier logVerbosity; - private final ThrowingSupplier globalContext; - private final TreeMap schedule = new TreeMap<>(); + private final ThrowingSupplier gscSupplier; + private final Channel simulationsPerQuarterChannel; + private final AtomicBoolean interruptFlag = new AtomicBoolean(false); - private Params params = null; + private Simulator simulator = null; + private SimulationResult simulationResult = SimulationResult.EMPTY; public Optimizer(Supplier logVerbosity, - ThrowingSupplier globalContext) { + ThrowingSupplier gscSupplier, // + Channel simulationsPerQuarterChannel) { this.logVerbosity = logVerbosity; - this.globalContext = globalContext; + this.gscSupplier = gscSupplier; + this.simulationsPerQuarterChannel = simulationsPerQuarterChannel; initializeRandomRegistryForProduction(); + } + + /** + * Deactivate the {@link Optimizer}. + */ + public synchronized void deactivate() { + this.interruptFlag.set(true); + } - // Run Optimizer thread in LOW PRIORITY - this.setPriority(Thread.MIN_PRIORITY); + /** + * Triggers Rescheduling. + */ + public void triggerReschedule() { + this.traceLog(() -> "Trigger Reschedule"); + this.interruptFlag.set(true); } @Override - public void forever() throws InterruptedException, OpenemsException { - this.traceLog(() -> "Start next run of Optimizer"); + public void run() { + try { + while (true) { + this.traceLog(() -> "Run..."); + this.interruptFlag.set(false); + + // Create the Simulator with GlobalSimulationsContext + createSimulator(this.gscSupplier, this.interruptFlag, // + simulator -> this.simulator = simulator, // + error -> { + this.traceLog(error); + this.applyEmptySimulationResult(); + }); + this.traceLog(() -> "Simulator is " + this.simulator); + final var simulator = this.simulator; + if (simulator == null) { + continue; + } - this.createParams(); // this possibly takes forever + this.runOnce(simulator); + } + } catch (InterruptedException | ExecutionException e) { + this.log.error("OPTIMIZER execution failed InterruptedException|ExecutionException: " + e.getMessage()); + e.printStackTrace(); + + // ignore + } catch (Exception e) { + this.log.error("OPTIMIZER execution failed: " + e.getMessage()); + e.printStackTrace(); + } + } - final var globalContext = this.globalContext.get(); - final var start = Instant.now(globalContext.clock()); + /** + * Run the optimization once. + * + * @param simulator the {@link Simulator} + * @throws InterruptedException on error + * @throws ExecutionException on error + */ + public void runOnce(Simulator simulator) throws InterruptedException, ExecutionException { + if (this.simulationResult == SimulationResult.EMPTY) { + // No Schedule available yet. Start with a default Schedule with all States + // set to default. + this.traceLog(() -> "No existing schedule available -> apply default"); + this.applyBestQuickSchedule(simulator); + } - long executionLimitSeconds; + this.traceLog(() -> "Run Simulation..."); - // Calculate max execution time till next quarter (with buffer) - executionLimitSeconds = calculateExecutionLimitSeconds(globalContext.clock()); + var simulationResult = this.runSimulation(simulator).get(); + if (simulationResult == null/* no result */ || this.interruptFlag.get() /* was interrupted */) { + this.traceLog(() -> "Simulation gave no result or was interrupted!"); + this.simulationsPerQuarterChannel.setNextValue(null); + this.applyBestQuickSchedule(simulator); + return; + } - // Find best Schedule - var schedule = Simulator.getBestSchedule(this.params, executionLimitSeconds); + this.traceLog(() -> "Calculate metrics"); - // Re-Simulate and keep best Schedule - var newSchedule = simulate(this.params, schedule); + // Calculate metrics + var stats = simulator.cache.stats(); + this.simulationsPerQuarterChannel.setNextValue(stats.loadCount()); - // Debug Log best Schedule - logSchedule(this.params, newSchedule); + // Apply simulation result to EnergyScheduleHandlers + this.applySimulationResult(simulator, simulationResult, false); + } - // Update Schedule from newly simulated Schedule - synchronized (this.schedule) { - updateSchedule(ZonedDateTime.now(globalContext.clock()), this.schedule, newSchedule); - } + private CompletableFuture runSimulation(Simulator simulator) { + this.traceLog(() -> "Run next Simulation"); + return CompletableFuture.supplyAsync(() -> { + this.traceLog(() -> "Executing async Simulation"); - // Send Schedule to Controller - globalContext.energyScheduleHandler().setSchedule(this.schedule.entrySet().stream()// - .collect(toImmutableMap(// - Entry::getKey, // - e -> new EnergyScheduleHandler.Period<>(e.getValue().state(), - e.getValue().op().essChargeInChargeGrid())))); - - // Sleep remaining time - if (!(globalContext.clock() instanceof TimeLeapClock)) { - var remainingExecutionLimit = Duration - .between(Instant.now(globalContext.clock()), start.plusSeconds(executionLimitSeconds)).getSeconds(); - if (remainingExecutionLimit > 0) { - this.traceLog(() -> "Sleep [" + remainingExecutionLimit + "s] till next run of Optimizer"); - sleep(remainingExecutionLimit * 1000); - } - } + final var executionLimit = byExecutionTime(ofSeconds(calculateExecutionLimitSeconds())); + + // Find best Schedule + var bestSchedule = simulator.getBestSchedule(this.simulationResult, null, // + stream -> stream // + // Stop on interruptFlag + .limit(ignore -> !this.interruptFlag.get()) // + // Stop till next quarter + .limit(executionLimit)); + + return bestSchedule; + }); } /** - * Try forever till all data is available (e.g. ESS Capacity) + * Create and apply the best quickly available Schedule. * - * @throws InterruptedException during sleep + * @param simulator the {@link Simulator} */ - private void createParams() throws InterruptedException { - while (true) { - try { - synchronized (this.schedule) { - this.params = createSimulatorParams(this.globalContext.get(), // - this.schedule.entrySet().stream() // - .collect(toImmutableSortedMap(// - ZonedDateTime::compareTo, // - Entry::getKey, e -> e.getValue().state()))); - return; - } - - } catch (OpenemsException e) { - this.traceLog(() -> "Stuck trying to get Params. " + e.getMessage()); - this.params = null; - synchronized (this.schedule) { - this.schedule.clear(); - } - sleep(30_000); - } + protected synchronized void applyBestQuickSchedule(Simulator simulator) { + // Find Genotype with lowest cost + var bestGt = findBestQuickSchedule(simulator, this.simulationResult); + if (bestGt == null) { + this.applyEmptySimulationResult(); + return; } + var simulationResult = SimulationResult.fromQuarters(simulator.gsc, bestGt); + + this.traceLog(() -> "Applying best quick Schedule"); + this.applySimulationResult(simulator, simulationResult, true); } - /** - * Gets the current {@link Params} or null. - * - * @return the {@link Params} or null - */ - public Params getParams() { - return this.params; + private void applyEmptySimulationResult() { + this.traceLog(() -> "Applying empty Schedule"); + this.applySimulationResult(null, SimulationResult.EMPTY, true); } /** - * Gets a copy of the Schedule. - * - * @return {@link ImmutableSortedMap} + * Applies the Schedule to all {@link EnergyScheduleHandler}s and stores the + * {@link SimulationResult} in `this.simulationResult`. + * + * @param simulator the {@link Simulator}, possibly null + * @param simulationResult the {@link SimulationResult} + * @param updateActiveQuarter should the currently active quarter also get + * updated */ - public ImmutableSortedMap getSchedule() { - synchronized (this.schedule) { - return ImmutableSortedMap.copyOf(this.schedule); + private void applySimulationResult(Simulator simulator, SimulationResult simulationResult, + boolean updateActiveQuarter) { + final Clock clock; + if (simulator != null) { + // Debug Log best Schedule + logSimulationResult(simulator, simulationResult); + clock = simulator.gsc.clock(); + } else { + clock = Clock.systemDefaultZone(); } + + final var thisQuarter = roundDownToQuarter(ZonedDateTime.now(clock)); + final var nextQuarter = thisQuarter.plusMinutes(15); + + // Store result + this.simulationResult = simulationResult; + + // Send Schedule to Controllers + simulationResult.schedules().forEach((esh, schedule) -> { + esh.applySchedule(schedule // + .tailMap(updateActiveQuarter // + ? thisQuarter // update also current quarter + : nextQuarter)); // otherwise -> start with next quarter + }); } private void traceLog(Supplier message) { @@ -155,4 +218,34 @@ private void traceLog(Supplier message) { case TRACE -> this.log.info("OPTIMIZER " + message.get()); } } + + /** + * Gets the {@link SimulationResult}. + * + * @return {@link SimulationResult} + */ + public SimulationResult getSimulationResult() { + return this.simulationResult; + } + + /** + * Output for Controller.Debug.Log. + * + * @return the debug log output + */ + public String debugLog() { + var b = new StringBuilder(); + if (this.simulationResult.periods().isEmpty()) { + b.append("No Schedule available"); + } else { + b.append("ScheduledPeriods:" + this.simulationResult.periods().size()); + } + var simulator = this.simulator; + if (simulator != null) { + var stats = simulator.cache.stats(); + b.append("|SimulationCounter:" + stats.loadCount()); + } + b.append("|PerQuarter:" + this.simulationsPerQuarterChannel.value()); + return b.toString(); + } } diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/QuickSchedules.java b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/QuickSchedules.java new file mode 100644 index 00000000000..57dfa9cf80f --- /dev/null +++ b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/QuickSchedules.java @@ -0,0 +1,217 @@ +package io.openems.edge.energy.optimizer; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import com.google.common.collect.ImmutableSortedMap; + +import io.jenetics.Genotype; +import io.jenetics.IntegerChromosome; +import io.jenetics.IntegerGene; +import io.openems.edge.energy.api.EnergyScheduleHandler; +import io.openems.edge.energy.api.simulation.GlobalSimulationsContext; + +/** + * This class helps finding good Schedules that are quickly available. + */ +public class QuickSchedules { + + private QuickSchedules() { + } + + /** + * Finds the best quick Schedule, i.e. the one with the lowest cost. + * + * @param simulator the {@link Simulator} + * @param simulationResult the existing {@link SimulationResult}, or null + * @return the winner {@link Genotype}; or null + */ + public static Genotype findBestQuickSchedule(Simulator simulator, SimulationResult simulationResult) { + double lowestCost = 0.; + Genotype bestGt = null; + for (var gt : generateQuickSchedules(simulator.gsc, simulationResult)) { + var cost = simulator.calculateCost(gt); + if (bestGt == null || cost < lowestCost) { + bestGt = gt; + lowestCost = cost; + } + } + return bestGt; + } + + /** + * Generate quick Schedules. + * + * @param gsc the {@link GlobalSimulationsContext} + * @param simulationResult the existing {@link SimulationResult}, or null + * @return a List of {@link Genotype}s, entries can be null + */ + public static List> generateQuickSchedules(GlobalSimulationsContext gsc, + SimulationResult simulationResult) { + return Stream // + .concat(// + variationsOfAllStatesDefault(gsc), // + variationsFromExistingSimulationResult(gsc, simulationResult)) // + .filter(Objects::nonNull) // + .distinct() // + .toList(); + } + + /** + * Builds {@link Genotype}s with all states default and all possible variations + * for first period. + * + * @param gsc the {@link GlobalSimulationsContext} + * @return a Stream of {@link Genotype}s or nulls + */ + protected static Stream> variationsOfAllStatesDefault(GlobalSimulationsContext gsc) { + return generateAllCombinations(gsc).stream() // + .map(combination -> toGenotypeOrNull(gsc.handlers().stream() // + .filter(EnergyScheduleHandler.WithDifferentStates.class::isInstance) // + .map(EnergyScheduleHandler.WithDifferentStates.class::cast) // + .map(esh -> { + final var defaultState = esh.getDefaultStateIndex(); + final var noOfStates = esh.getAvailableStates().length; + final var firstState = combination.get(esh); + return IntegerChromosome.of(IntStream.range(0, gsc.periods().size()) // + .map(i -> i == 0 // + ? firstState // first period + : defaultState) // remaining periods + .mapToObj(state -> IntegerGene.of(state, 0, noOfStates)) // + .toList()); + }) // + .toList())); + } + + /** + * Builds {@link Genotype}s with all states from an existing + * {@link SimulationResult} and all possible variations for first period. + * + * @param gsc the {@link GlobalSimulationsContext} + * @param simulationResult the {@link SimulationResult} + * @return a Stream of {@link Genotype}s or nulls + */ + protected static Stream> variationsFromExistingSimulationResult(GlobalSimulationsContext gsc, + SimulationResult simulationResult) { + return generateAllCombinations(gsc).stream() // + .map(combination -> toGenotypeOrNull(gsc.handlers().stream() // + .filter(EnergyScheduleHandler.WithDifferentStates.class::isInstance) // + .map(EnergyScheduleHandler.WithDifferentStates.class::cast) // + .map(esh -> { + final var firstState = combination.get(esh); + final var existingSchedule = simulationResult.schedules().getOrDefault(esh, + ImmutableSortedMap.of()); + final var defaultState = esh.getDefaultStateIndex(); + final var noOfStates = esh.getAvailableStates().length; + return IntegerChromosome.of(IntStream.range(0, gsc.periods().size()) // + .map(i -> { + if (i == 0) { // + return firstState; // first period + } + // remaining periods + var period = gsc.periods().get(i); + var previousState = existingSchedule.get(period.time()); + if (previousState != null) { + return previousState.stateIndex(); + } + return defaultState; + }) // + .mapToObj(state -> IntegerGene.of(state, 0, noOfStates)) // + .toList()); + }) // + .toList())); + } + + /** + * Builds a {@link Genotype} of an existing {@link SimulationResult}. + * + * @param gsc the {@link GlobalSimulationsContext} + * @param simulationResult the {@link SimulationResult} + * @return the {@link Genotype} or null + */ + protected static Genotype fromExistingSimulationResult(GlobalSimulationsContext gsc, + SimulationResult simulationResult) { + if (simulationResult == null) { + return null; + } + return toGenotypeOrNull(gsc.handlers().stream() // + .filter(EnergyScheduleHandler.WithDifferentStates.class::isInstance) // + .map(EnergyScheduleHandler.WithDifferentStates.class::cast) // + .map(esh -> { + final var existingSchedule = simulationResult.schedules().getOrDefault(esh, + ImmutableSortedMap.of()); + final var defaultState = esh.getDefaultStateIndex(); + final var noOfStates = esh.getAvailableStates().length; + return IntegerChromosome.of(gsc.periods().stream() // + .map(p -> { + var previousState = existingSchedule.get(p.time()); + var state = previousState == null // + ? defaultState // + : previousState.stateIndex(); + return IntegerGene.of(state, 0, noOfStates); + }) // + .toList()); + }) // + .toList()); + } + + private static Genotype toGenotypeOrNull(List cs) { + if (cs.isEmpty()) { + return null; + } + return Genotype.of(cs); + } + + /** + * Generates all possible combinations of + * {@link EnergyScheduleHandler.WithDifferentStates} and state-index for a + * Period. + * + * @param gsc {@link GlobalSimulationsContext} + * @return combinations + */ + @SuppressWarnings("rawtypes") + private static List> generateAllCombinations( + GlobalSimulationsContext gsc) { + if (gsc == null) { + return List.of(); + } + + var eshs = gsc.handlers().stream() // + .filter(EnergyScheduleHandler.WithDifferentStates.class::isInstance) // + .map(EnergyScheduleHandler.WithDifferentStates.class::cast) // + .toList(); + + List> result = new ArrayList<>(); + generateCombinationsRecursive(eshs, 0, new HashMap<>(), result); + return result; + } + + @SuppressWarnings("rawtypes") + private static void generateCombinationsRecursive(List inputList, + int index, Map currentCombination, + List> result) { + // Base case: If we've added a combination for each input, add the result to the + // list. + if (index == inputList.size()) { + result.add(new HashMap<>(currentCombination)); // Add a copy of the current map + return; + } + + // Get the current input + var currentInput = inputList.get(index); + + // Loop through all possible values for this input, from 0 to maxValue + for (int value = 0; value < currentInput.getAvailableStates().length; value++) { + currentCombination.put(currentInput, value); // Set this value in the map + // Recur to the next input + generateCombinationsRecursive(inputList, index + 1, currentCombination, result); + currentCombination.remove(currentInput); // Backtrack + } + } +} diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/SimulationResult.java b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/SimulationResult.java new file mode 100644 index 00000000000..ae7930cc03a --- /dev/null +++ b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/SimulationResult.java @@ -0,0 +1,177 @@ +package io.openems.edge.energy.optimizer; + +import static com.google.common.collect.ImmutableMap.toImmutableMap; + +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Locale; +import java.util.function.BiConsumer; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSortedMap; + +import io.jenetics.Genotype; +import io.jenetics.IntegerChromosome; +import io.jenetics.IntegerGene; +import io.openems.edge.energy.api.EnergyScheduleHandler; +import io.openems.edge.energy.api.simulation.EnergyFlow; +import io.openems.edge.energy.api.simulation.GlobalSimulationsContext; +import io.openems.edge.energy.api.simulation.GlobalSimulationsContext.Period.Hour; +import io.openems.edge.energy.api.simulation.GlobalSimulationsContext.Period.Quarter; +import io.openems.edge.energy.optimizer.Simulator.EshToState; + +public record SimulationResult(// + double cost, // + ImmutableMap periods, // + ImmutableMap, // + ImmutableSortedMap> schedules) { + + /** + * A Period in a {@link SimulationResult}. Duration of one period is always one + * quarter. + */ + public record Period(// + GlobalSimulationsContext.Period context, // + EnergyFlow energyFlow, // + int essInitialEnergy // + ) { + + /** + * Constructor for {@link Period}. + * + * @param context the {@link GlobalSimulationsContext} + * @param energyFlow the {@link EnergyFlowV1.Solution} + * @param essInitialEnergy the initial ESS energy in the beginning of the period + * in [Wh] + * @return a {@link Period} + */ + public static Period from(GlobalSimulationsContext.Period context, EnergyFlow energyFlow, + int essInitialEnergy) { + return new Period(context, energyFlow, essInitialEnergy); + } + } + + /** + * An empty {@link SimulationResult}. + */ + public static final SimulationResult EMPTY = new SimulationResult(0., ImmutableMap.of(), ImmutableMap.of()); + + /** + * Re-Simulate a {@link Genotype} to create a {@link SimulationResult}. + * + * @param cache the {@link GenotypeCache} + * @param gsc the {@link GlobalSimulationsContext} + * @param gt the {@link Genotype} + * @return the {@link SimulationResult} + */ + private static SimulationResult from(GlobalSimulationsContext gsc, Genotype gt) { + var allPeriods = ImmutableMap.builder(); + var allEshToStates = new ArrayList(); + var cost = Simulator.simulate(gsc, gt, new Simulator.BestScheduleCollector(// + p -> allPeriods.put(p.context().time(), p), // + allEshToStates::add)); + + var schedules = allEshToStates.stream() // + .collect(toImmutableMap(EshToState::esh, // + eshToState -> ImmutableSortedMap.of(eshToState.period().context.time(), + new EnergyScheduleHandler.WithDifferentStates.Period.Transition( + eshToState.postProcessedStateIndex(), eshToState.period().context.price(), + eshToState.period().energyFlow, eshToState.period().essInitialEnergy)), + (a, b) -> ImmutableSortedMap.naturalOrder() + .putAll(a).putAll(b).build())); + + return new SimulationResult(cost, allPeriods.build(), schedules); + } + + /** + * Re-Simulate a {@link Genotype} to create a {@link SimulationResult}. + * + *

      + * This method re-simulates using the {@link Quarter} periods and not (only) the + * {@link Hour} periods. + * + * @param gsc the {@link GlobalSimulationsContext} + * @param gt the {@link Genotype} + * @return the {@link SimulationResult} + */ + public static SimulationResult fromQuarters(GlobalSimulationsContext gsc, Genotype gt) { + if (gsc == null || gt == null) { + return SimulationResult.EMPTY; + } + + // Convert to Quarters + final GlobalSimulationsContext quarterGsc; + final Genotype quarterGt; + { + final var quarterPeriods = ImmutableList.builder(); + final var quarterGenes = gt.stream().map(ignore -> ImmutableList.builder()).toList(); + final BiConsumer add = (j, p) -> { + quarterPeriods.add(p); + for (var i = 0; i < quarterGenes.size(); i++) { + quarterGenes.get(i).add(gt.get(i).get(j)); + } + }; + for (var i = 0; i < gsc.periods().size(); i++) { + var p = gsc.periods().get(i); + if (p instanceof GlobalSimulationsContext.Period.Quarter pq) { + add.accept(i, pq); + } else if (p instanceof GlobalSimulationsContext.Period.Hour ph) { + for (var j = 0; j < ph.quarterPeriods().size(); j++) { + var pq = ph.quarterPeriods().get(j); + add.accept(i, pq); + } + } + } + quarterGsc = new GlobalSimulationsContext(gsc.clock(), gsc.startTime(), gsc.handlers(), gsc.grid(), + gsc.ess(), quarterPeriods.build()); + quarterGt = Genotype.of(quarterGenes.stream() // + .map(gs -> IntegerChromosome.of(gs.build())) // + .toList()); + } + return from(quarterGsc, quarterGt); + } + + private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm"); + + private static void log(StringBuilder b, String format, Object... args) { + b.append(String.format(Locale.ENGLISH, format, args).toString()); + } + + /** + * Builds a log string of this {@link SimulationResult}. + * + * @return log string + */ + public String toLogString(String prefix) { + var b = new StringBuilder(prefix) // + .append("Time Price Production Consumption Ess Grid ProdToCons ProdToGrid ProdToEss GridToCons GridToEss EssToCons EssInitial\n"); + this.periods.entrySet().forEach(e -> { + final var time = e.getKey(); + final var p = e.getValue(); + final var c = p.context; + final var ef = p.energyFlow; + log(b, "%s", prefix); + log(b, "%s ", time.format(TIME_FORMATTER)); + log(b, "%6.2f ", c.price()); + log(b, "%10d ", ef.getProd()); + log(b, "%10d ", ef.getCons()); + log(b, "%6d ", ef.getEss()); + log(b, "%6d ", ef.getGrid()); + log(b, "%10d ", ef.getProdToCons()); + log(b, "%10d ", ef.getProdToGrid()); + log(b, "%9d ", ef.getProdToEss()); + log(b, "%10d ", ef.getGridToCons()); + log(b, "%9d ", ef.getGridToEss()); + log(b, "%9d ", ef.getEssToCons()); + log(b, "%10d ", p.essInitialEnergy); + this.schedules.forEach((esh, schedule) -> { + log(b, "%-15s ", esh.toStateString(schedule.get(time).stateIndex())); + }); + b.append("\n"); + }); + return b.toString(); + } +} diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Simulator.java b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Simulator.java index 0b79a5f6cc2..7c184779768 100644 --- a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Simulator.java +++ b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Simulator.java @@ -1,177 +1,279 @@ package io.openems.edge.energy.optimizer; +import static com.google.common.base.MoreObjects.toStringHelper; import static io.jenetics.engine.EvolutionResult.toBestGenotype; -import static io.jenetics.engine.Limits.byExecutionTime; -import static io.openems.edge.energy.optimizer.InitialPopulationUtils.buildInitialPopulation; -import static io.openems.edge.energy.optimizer.Utils.paramsAreValid; -import static io.openems.edge.energy.optimizer.Utils.postprocessSimulatorState; -import static java.lang.Math.max; -import static java.time.Duration.ofSeconds; - -import java.time.ZonedDateTime; -import java.util.concurrent.atomic.AtomicInteger; +import static io.openems.edge.energy.optimizer.QuickSchedules.fromExistingSimulationResult; +import static java.lang.Thread.currentThread; + +import java.util.List; +import java.util.concurrent.Executor; +import java.util.concurrent.ForkJoinPool; import java.util.function.Consumer; import java.util.function.Function; -import java.util.stream.IntStream; -import java.util.stream.Stream; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSortedMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import io.jenetics.Genotype; import io.jenetics.IntegerChromosome; import io.jenetics.IntegerGene; import io.jenetics.engine.Engine; -import io.jenetics.engine.EvolutionResult; -import io.openems.edge.controller.ess.timeofusetariff.StateMachine; -import io.openems.edge.energy.optimizer.Params.Length; -import io.openems.edge.energy.optimizer.Params.OptimizePeriod; +import io.jenetics.engine.EvolutionStream; +import io.openems.edge.energy.api.EnergyScheduleHandler; +import io.openems.edge.energy.api.EnergyScheduleHandler.AbstractEnergyScheduleHandler; +import io.openems.edge.energy.api.simulation.EnergyFlow; +import io.openems.edge.energy.api.simulation.GlobalSimulationsContext; +import io.openems.edge.energy.api.simulation.OneSimulationContext; public class Simulator { /** Used to incorporate charge/discharge efficiency. */ public static final double EFFICIENCY_FACTOR = 1.17; - public record Period(OptimizePeriod op, StateMachine state, int essInitial, EnergyFlow ef) { + private static final Logger LOG = LoggerFactory.getLogger(Simulator.class); + + public final GlobalSimulationsContext gsc; + + protected final LoadingCache, Double> cache; + + public Simulator(GlobalSimulationsContext gsc) { + this.gsc = gsc; + this.cache = CacheBuilder.newBuilder() // + .recordStats() // + .build(new CacheLoader, Double>() { + + @Override + /** + * Simulates a Schedule and calculates the cost. + * + *

      + * NOTE: do not throw an Exception here, because we use + * {@link LoadingCache#getUnchecked(Object)} below. + * + * @param gt the Schedule as a {@link Genotype} + * @return the cost, lower is better, always positive; {@link Double#NaN} on + * error + */ + public Double load(final Genotype gt) { + return simulate(Simulator.this.gsc, gt, null); + } + }); + + // Initialize the EnergyScheduleHandlers. + for (var esh : gsc.handlers()) { + ((AbstractEnergyScheduleHandler) esh /* this is safe */).initialize(gsc); + } } /** * Simulates a Schedule and calculates the cost. * - * @param p the {@link Params} - * @param schedule the {@link StateMachine} states of the Schedule - * @return the cost, lower is better; always positive + *

      + * This method internally uses a Cache for {@link Genotype}s. + * + * @param gt the Schedule as a {@link Genotype} + * @return the cost, lower is better, always positive; {@link Double#NaN} on + * error */ - protected static double calculateCost(Params p, StateMachine[] schedule) { - final var nextEssInitial = new AtomicInteger(p.essInitialEnergy()); - var sum = 0.; - for (var i = 0; i < p.optimizePeriods().size(); i++) { - sum += simulatePeriod(p, p.optimizePeriods().get(i), schedule[i], nextEssInitial, null); - } - return sum; + public double calculateCost(Genotype gt) { + return this.cache.getUnchecked(gt); } /** - * Simulates a Schedule in quarterly periods. + * Simulates a Schedule and calculates the cost. + * + *

      + * This method does not a Cache for {@link Genotype}s. * - * @param p the {@link Params} - * @param schedule the {@link StateMachine} states of the Schedule - * @return a Map of {@link Period}s + * @param gt the simulated {@link Genotype} + * @param bestScheduleCollector the {@link BestScheduleCollector} + * @return the cost, lower is better, always positive; + * {@link Double#POSITIVE_INFINITY} on error */ - protected static ImmutableSortedMap simulate(Params p, StateMachine[] schedule) { - final var nextEssInitial = new AtomicInteger(p.essInitialEnergy()); - var result = ImmutableSortedMap.naturalOrder(); - for (var i = 0; i < p.optimizePeriods().size(); i++) { - var state = schedule[i]; - var op = p.optimizePeriods().get(i); - var length = op.quarterPeriods().size() == 1 ? Length.QUARTER : Length.HOUR; - // Convert mixed OptimizePeriods to pure quarterly - for (var qp : op.quarterPeriods()) { - var quarterlyOp = new OptimizePeriod(qp.time(), length, qp.essMaxChargeEnergy(), - qp.essMaxDischargeEnergy(), qp.essChargeInChargeGrid(), qp.maxBuyFromGrid(), qp.production(), - qp.consumption(), qp.price(), ImmutableList.of(qp)); - simulatePeriod(p, quarterlyOp, state, nextEssInitial, period -> result.put(period.op().time(), period)); - } + public double simulate(Genotype gt, BestScheduleCollector bestScheduleCollector) { + return simulate(this.gsc, gt, bestScheduleCollector); + } + + protected static double simulate(GlobalSimulationsContext gsc, Genotype gt, + BestScheduleCollector bestScheduleCollector) { + final var osc = OneSimulationContext.from(gsc); + final var noOfPeriods = gsc.periods().size(); + + var sum = 0.; + for (var period = 0; period < noOfPeriods; period++) { + sum += simulatePeriod(osc, gt, period, bestScheduleCollector); } - return result.build(); + return sum; } /** * Calculates the cost of one Period under the given Schedule. * - * @param p the {@link Params} - * @param op the current {@link OptimizePeriod} - * @param state the {@link StateMachine} of the current period - * @param nextEssInitial the initial SoC-Energy; also used as return value - * @param collect a {@link Consumer} to collect the simulation results if - * required. We are not always collecting results to - * reduce workload during simulation. - * @return the cost, lower is better; always positive + * @param simulation the {@link OneSimulationContext} + * @param gt the simulated {@link Genotype} + * @param periodIndex the index of the simulated period + * @param bestScheduleCollector the {@link BestScheduleCollector}; or null + * @return the cost, lower is better, always positive; + * {@link Double#POSITIVE_INFINITY} on error */ - protected static double simulatePeriod(Params p, OptimizePeriod op, StateMachine state, - final AtomicInteger nextEssInitial, Consumer collect) { - // Constants - final var essInitial = max(0, nextEssInitial.get()); // always at least '0' + public static double simulatePeriod(OneSimulationContext simulation, Genotype gt, int periodIndex, + BestScheduleCollector bestScheduleCollector) { + final var period = simulation.global.periods().get(periodIndex); + final var handlers = simulation.global.handlers(); + final var model = EnergyFlow.Model.from(simulation, period); - // Calculate Energy-Flow - final var ef = switch (state) { - case BALANCING -> EnergyFlow.withBalancing(p, op, essInitial); - case DELAY_DISCHARGE -> EnergyFlow.withDelayDischarge(p, op, essInitial); - case CHARGE_GRID -> EnergyFlow.withChargeGrid(p, op, essInitial); - }; + var eshIndex = 0; + for (var esh : handlers) { + if (esh instanceof EnergyScheduleHandler.WithDifferentStates e) { + // Simulate with state given by Genotype + e.simulatePeriod(simulation, period, model, gt.get(eshIndex++).get(periodIndex).intValue()); + } else if (esh instanceof EnergyScheduleHandler.WithOnlyOneState e) { + e.simulatePeriod(simulation, period, model); + } + } - nextEssInitial.set(essInitial - ef.ess()); + final EnergyFlow energyFlow = model.solve(); + + if (energyFlow == null) { + LOG.error("Error while simulating period [" + periodIndex + "]"); + // TODO add configurable debug logging + // LOG.info(simulation.toString()); + // model.logConstraints(); + // model.logMinMaxValues(); + return Double.POSITIVE_INFINITY; + } // Calculate Cost + // TODO should be done also by ESH to enable this use-case: + // https://community.openems.io/t/limitierung-bei-negativen-preisen-und-lastgang-einkauf/2713/2 double cost; - if (ef.grid() > 0) { + if (energyFlow.getGrid() > 0) { // Filter negative prices - var price = max(0, op.price()); + var price = Math.max(0, period.price()); cost = // Cost for direct Consumption - ef.gridToConsumption() * price + energyFlow.getGridToCons() * price // Cost for future Consumption after storage - + ef.gridToEss() * price * EFFICIENCY_FACTOR; + + energyFlow.getGridToEss() * price * EFFICIENCY_FACTOR; } else { // Sell-to-Grid cost = 0.; } - if (collect != null) { - var postprocessedState = postprocessSimulatorState(state, // - EnergyFlow.withBalancing(p, op, essInitial), // - EnergyFlow.withDelayDischarge(p, op, essInitial), // - EnergyFlow.withChargeGrid(p, op, essInitial)); - collect.accept(new Period(op, postprocessedState, essInitial, ef)); + if (bestScheduleCollector != null) { + final var srp = SimulationResult.Period.from(period, energyFlow, simulation.getEssInitial()); + bestScheduleCollector.allPeriods.accept(srp); + eshIndex = 0; + for (var esh : handlers) { + if (esh instanceof EnergyScheduleHandler.WithDifferentStates e) { + bestScheduleCollector.eshStates.accept(new EshToState(e, srp, // + e.postProcessPeriod(period, simulation, energyFlow, + gt.get(eshIndex++).get(periodIndex).intValue()))); + } + } } + + // Prepare for next period + simulation.calculateEssInitial(energyFlow.getEss()); + return cost; } /** - * Runs the optimization with default settings. + * Runs the optimization and returns the "best" simulation result. * - * @param p the {@link Params} - * @param executionLimitSeconds limit.byExecutionTime.ofSeconds - * @return the best schedule + * @param previousResult the {@link SimulationResult} of the + * previous optimization run + * @param engineInterceptor an interceptor for the + * {@link Engine.Builder} + * @param evolutionStreamInterceptor an interceptor for the + * {@link EvolutionStream} + * @return the best Schedule */ - protected static StateMachine[] getBestSchedule(Params p, long executionLimitSeconds) { - return getBestSchedule(p, executionLimitSeconds, null, null); - } + public SimulationResult getBestSchedule(SimulationResult previousResult, + Function, Engine.Builder> engineInterceptor, + Function, EvolutionStream> evolutionStreamInterceptor) { + // Genotype: + // - Separate IntegerChromosome per EnergyScheduleHandler WithDifferentStates + // - Chromosome length = number of periods + // - Integer-Genes represent the state + final var chromosomes = this.gsc.handlers().stream() // + .filter(EnergyScheduleHandler.WithDifferentStates.class::isInstance) // + .map(EnergyScheduleHandler.WithDifferentStates.class::cast) // + .map(esh -> IntegerChromosome.of(0, esh.getAvailableStates().length, this.gsc.periods().size())) // + .toList(); + if (chromosomes.isEmpty()) { + return SimulationResult.EMPTY; + } + final var gtf = Genotype.of(chromosomes); - protected static StateMachine[] getBestSchedule(Params p, long executionLimitSeconds, Integer populationSize, - Integer limit) { - // Return pure BALANCING Schedule if no predictions are available - if (!paramsAreValid(p)) { - return p.optimizePeriods().stream() // - .map(op -> StateMachine.BALANCING) // - .toArray(StateMachine[]::new); + // Decide for single- or multi-threading + final Executor executor; + final var availableCores = Runtime.getRuntime().availableProcessors() - 1; + if (availableCores > 1) { + // Executor is a Thread-Pool with CPU-Cores minus one + executor = new ForkJoinPool(availableCores); + System.out.println("OPTIMIZER Executor runs on " + availableCores + " cores"); + } else { + // Executor is the current thread + executor = Runnable::run; + System.out.println("OPTIMIZER Executor runs on current thread"); } - var gtf = Genotype.of(IntegerChromosome.of(IntegerGene.of(0, p.states().length)), p.optimizePeriods().size()); // - var eval = (Function, Double>) (gt) -> { - var modes = new StateMachine[p.optimizePeriods().size()]; - for (var i = 0; i < modes.length; i++) { - modes[i] = p.states()[gt.get(i).get(0).intValue()]; - } - return calculateCost(p, modes); - }; + // Build the Jenetics Engine var engine = Engine // - .builder(eval, gtf) // - .executor(Runnable::run) // current thread + .builder(this.cache::getUnchecked, gtf) // + .executor(executor) // .minimizing(); - if (populationSize != null) { - engine.populationSize(populationSize); // + if (engineInterceptor != null) { + engine = engineInterceptor.apply(engine); + } + + // Start with previous simulation result as initial population if available + var initialPopulation = fromExistingSimulationResult(this.gsc, previousResult); + EvolutionStream stream; + if (previousResult != null) { + stream = engine.build().stream(List.of(initialPopulation)); + } else { + stream = engine.build().stream(); } - Stream> stream = engine.build() // - .stream(buildInitialPopulation(p)) // - .limit(byExecutionTime(ofSeconds(executionLimitSeconds))); // - if (limit != null) { - stream = stream.limit(limit); // apply optional limit + stream = stream.limit(result -> !currentThread().isInterrupted()); + if (evolutionStreamInterceptor != null) { + stream = evolutionStreamInterceptor.apply(stream); } + + // Start the evaluation var bestGt = stream // .collect(toBestGenotype()); - return IntStream.range(0, p.optimizePeriods().size()) // - .mapToObj(period -> p.states()[bestGt.get(period).get(0).intValue()]) // - .toArray(StateMachine[]::new); + + return SimulationResult.fromQuarters(this.gsc, bestGt); + } + + protected static record BestScheduleCollector(// + Consumer allPeriods, // + Consumer eshStates) { + } + + protected static record EshToState(// + EnergyScheduleHandler.WithDifferentStates esh, // + SimulationResult.Period period, // + int postProcessedStateIndex) { + } + + /** + * Builds a log string of this {@link Simulator}. + * + * @param prefix a line prefix + * @return log string + */ + public String toLogString(String prefix) { + return prefix + toStringHelper(this) // + .addValue(this.gsc) // + .addValue(this.cache.stats()) // + .toString(); } } diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Utils.java b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Utils.java index 4bc3d97858c..e703ab1e0c6 100644 --- a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Utils.java +++ b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Utils.java @@ -1,89 +1,44 @@ package io.openems.edge.energy.optimizer; -import static com.google.common.collect.Streams.concat; import static io.openems.common.utils.DateUtils.roundDownToQuarter; -import static io.openems.edge.common.type.TypeUtils.multiply; -import static io.openems.edge.common.type.TypeUtils.orElse; -import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.BALANCING; -import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.CHARGE_GRID; -import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.DELAY_DISCHARGE; -import static io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffController.PERIODS_PER_HOUR; -import static java.lang.Math.max; -import static java.lang.Math.round; -import static java.util.Arrays.stream; +import static java.lang.Thread.sleep; import java.time.Clock; import java.time.Duration; import java.time.ZonedDateTime; -import java.time.temporal.ChronoUnit; import java.util.List; import java.util.Objects; -import java.util.Set; -import java.util.TreeMap; -import java.util.UUID; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; +import java.util.function.Supplier; import java.util.random.RandomGeneratorFactory; -import java.util.stream.IntStream; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSortedMap; -import com.google.common.collect.Streams; +import com.google.common.collect.Ordering; import io.jenetics.util.RandomRegistry; -import io.openems.common.exceptions.InvalidValueException; -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.timedata.Resolution; +import io.openems.common.exceptions.OpenemsException; +import io.openems.common.function.ThrowingSupplier; import io.openems.common.types.ChannelAddress; -import io.openems.edge.controller.ess.emergencycapacityreserve.ControllerEssEmergencyCapacityReserve; -import io.openems.edge.controller.ess.limittotaldischarge.ControllerEssLimitTotalDischarge; -import io.openems.edge.controller.ess.timeofusetariff.StateMachine; -import io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffController; -import io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImpl; -import io.openems.edge.energy.jsonrpc.GetScheduleResponse; -import io.openems.edge.energy.optimizer.ScheduleDatas.ScheduleData; -import io.openems.edge.energy.optimizer.Simulator.Period; -import io.openems.edge.ess.api.SymmetricEss; -import io.openems.edge.timedata.api.Timedata; -import io.openems.edge.timeofusetariff.api.TimeOfUseTariff; +import io.openems.edge.energy.api.EnergySchedulable; +import io.openems.edge.energy.api.simulation.GlobalSimulationsContext; +import io.openems.edge.scheduler.api.Scheduler; -/** - * Utils for {@link TimeOfUseTariffController}. - * - *

      - * All energy values are in [Wh] and positive, unless stated differently. - */ public final class Utils { private Utils() { } - /** Keep some buffer to avoid scheduling errors because of bad predictions. */ - public static final float ESS_MAX_SOC = 90F; - /** Limit Charge Power for §14a EnWG. */ public static final int ESS_LIMIT_14A_ENWG = -4200; - /** - * C-Rate (capacity divided by time) during {@link StateMachine#CHARGE_GRID}. - * With a C-Rate of 0.5 the battery gets fully charged within 2 hours. - */ - public static final float ESS_CHARGE_C_RATE = 0.5F; - - public static final ChannelAddress SUM_PRODUCTION = new ChannelAddress("_sum", "ProductionActivePower"); - public static final ChannelAddress SUM_CONSUMPTION = new ChannelAddress("_sum", "ConsumptionActivePower"); public static final ChannelAddress SUM_GRID = new ChannelAddress("_sum", "GridActivePower"); - public static final ChannelAddress SUM_UNMANAGED_CONSUMPTION = new ChannelAddress("_sum", - "UnmanagedConsumptionActivePower"); public static final ChannelAddress SUM_ESS_DISCHARGE_POWER = new ChannelAddress("_sum", "EssDischargePower"); public static final ChannelAddress SUM_ESS_SOC = new ChannelAddress("_sum", "EssSoc"); protected static final long EXECUTION_LIMIT_SECONDS_BUFFER = 30; protected static final long EXECUTION_LIMIT_SECONDS_MINIMUM = 60; - private static final Logger LOG = LoggerFactory.getLogger(Utils.class); - /** * Initializes the Jenetics {@link RandomRegistry} for production. */ @@ -121,308 +76,53 @@ private static void initializeRandomRegistry(boolean isUnitTest) { } /** - * Create {@link Params} for {@link Simulator}. + * Creates a {@link Simulator}. * - * @param globalContext the {@link GlobalContext} object - * @param existingSchedule the existing schedule, i.e. result of previous - * optimization - * @return {@link Params} - * @throws InvalidValueException on error - */ - public static Params createSimulatorParams(GlobalContext globalContext, - ImmutableSortedMap existingSchedule) throws InvalidValueException { - final var time = roundDownToQuarter(ZonedDateTime.now()); - - // Prediction values - final var predictionConsumption = joinConsumptionPredictions(4, // - globalContext.predictorManager().getPrediction(SUM_CONSUMPTION).asArray(), // - globalContext.predictorManager().getPrediction(SUM_UNMANAGED_CONSUMPTION).asArray()); - final var predictionProduction = generateProductionPrediction(// - globalContext.predictorManager().getPrediction(SUM_PRODUCTION).asArray(), // - predictionConsumption.length); - - // Prices contains the price values and the time it is retrieved. - final var prices = globalContext.timeOfUseTariff().getPrices(); - - // Ess information. - TimeOfUseTariffControllerImpl.Context context = globalContext.energyScheduleHandler().getContext(); - final var essTotalEnergy = context.ess().getCapacity().getOrError(); - final var essMinSocEnergy = getEssMinSocEnergy(context, essTotalEnergy); - final var essMaxSocEnergy = round(ESS_MAX_SOC / 100F * essTotalEnergy); - final var essSoc = context.ess().getSoc().getOrError(); - final var essSocEnergy = essTotalEnergy /* [Wh] */ / 100 * essSoc; - - // Power Values for scheduling battery for individual periods. - var maxDischargePower = globalContext.sum().getEssMaxDischargePower().orElse(1000 /* at least 1000 */); - var maxChargePower = globalContext.sum().getEssMaxDischargePower().orElse(-1000 /* at least 1000 */); - if (context.limitChargePowerFor14aEnWG()) { - maxChargePower = max(ESS_LIMIT_14A_ENWG, maxChargePower); // Apply §14a EnWG limit - } - - return Params.create() // - .setTime(time) // - .setEssTotalEnergy(essTotalEnergy) // - .setEssMinSocEnergy(essMinSocEnergy) // - .setEssMaxSocEnergy(essMaxSocEnergy) // - .setEssInitialEnergy(essSocEnergy) // - .setEssMaxChargeEnergy(toEnergy(Math.abs(maxChargePower))) // - .setEssMaxDischargeEnergy(toEnergy(maxDischargePower)) // - .seMaxBuyFromGrid(toEnergy(context.maxChargePowerFromGrid())) // - .setProductions(stream(interpolateArray(predictionProduction)).map(v -> toEnergy(v)).toArray()) // - .setConsumptions(stream(interpolateArray(predictionConsumption)).map(v -> toEnergy(v)).toArray()) // - .setPrices(interpolateArray(prices.asArray())) // - .setStates(context.controlMode().states) // - .setExistingSchedule(existingSchedule) // - .build(); - } - - /** - * Postprocesses production prediction; makes sure length is at least the same - * as consumption prediction - filling up with zeroes. - * - * @param prediction the production prediction - * @param minLength the min length (= consumption prediction length) - * @return new production prediction - */ - protected static Integer[] generateProductionPrediction(Integer[] prediction, int minLength) { - if (prediction.length >= minLength) { - return prediction; - } - return IntStream.range(0, minLength) // - .mapToObj(i -> i > prediction.length - 1 ? 0 : prediction[i]) // - .toArray(Integer[]::new); - } - - protected static Integer[] joinConsumptionPredictions(int splitAfterIndex, Integer[] totalConsumption, - Integer[] unmanagedConsumption) { - return Streams.concat(// - stream(totalConsumption) // - .limit(splitAfterIndex), // - stream(unmanagedConsumption) // - .skip(splitAfterIndex)) // - .toArray(Integer[]::new); - } - - protected static boolean paramsAreValid(Params p) { - if (p.optimizePeriods().isEmpty()) { - // No periods are available - LOG.warn("No periods are available"); - return false; - } - if (p.optimizePeriods().stream() // - .allMatch(pp -> pp.production() == 0 && pp.consumption() == 0)) { - // Production and Consumption predictions are all zero - LOG.warn("Production and Consumption predictions are all zero"); - return false; - } - if (p.optimizePeriods().stream() // - .mapToDouble(Params.OptimizePeriod::price) // - .distinct() // - .count() <= 1) { - // Prices are all the same - LOG.info("Prices are all the same"); - return false; - } - - return true; - } - - /** - * Returns the amount of energy that is not available for scheduling because of - * a configured minimum SoC. - * - * @param context the {@link TimeOfUseTariffControllerImpl.Context} - * @param essCapacity net {@link SymmetricEss.ChannelId#CAPACITY} - * @return the value in [Wh] - */ - protected static int getEssMinSocEnergy(TimeOfUseTariffControllerImpl.Context context, int essCapacity) { - return essCapacity /* [Wh] */ / 100 // - * getEssMinSocPercentage(// - context.ctrlLimitTotalDischarges(), // - context.ctrlEmergencyCapacityReserves()); - } + *

      + * This will possibly run forever and call the callbacks multiple times before + * returning. + * + * @param gscSupplier a {@link Supplier} for {@link GlobalSimulationsContext} + * @param interruptFlag a flag to interrupt the threads + * @param simulator a callback for a {@link Simulator}; possibly null + * @param error a callback for a error string + */ + public static synchronized void createSimulator( + ThrowingSupplier gscSupplier, AtomicBoolean interruptFlag, + Consumer simulator, Consumer> error) { + while (!interruptFlag.get()) { + try { + simulator.accept(new Simulator(gscSupplier.get())); + return; - /** - * Returns the configured minimum SoC, or zero. - * - * @param ctrlLimitTotalDischarges the list of - * {@link ControllerEssLimitTotalDischarge} - * @param ctrlEmergencyCapacityReserves the list of - * {@link ControllerEssEmergencyCapacityReserve} - * @return the value in [%] - */ - public static int getEssMinSocPercentage(List ctrlLimitTotalDischarges, - List ctrlEmergencyCapacityReserves) { - return concat(// - ctrlLimitTotalDischarges.stream() // - .map(ctrl -> ctrl.getMinSoc().get()) // - .filter(Objects::nonNull) // - .mapToInt(v -> max(0, v)), // only positives - ctrlEmergencyCapacityReserves.stream() // - .map(ctrl -> ctrl.getActualReserveSoc().get()) // - .filter(Objects::nonNull) // - .mapToInt(v -> max(0, v))) // only positives - .max().orElse(0); - } + } catch (OpenemsException | IllegalArgumentException e) { + e.printStackTrace(); - /** - * Interpolate an Array of {@link Double}s. - * - *

      - * Replaces nulls with previous value. If first entry is null, it is set to - * first available value. If all values are null, all are set to 0. - * - * @param values the values - * @return values without nulls - */ - protected static double[] interpolateArray(Double[] values) { - var firstNonNull = stream(values) // - .filter(Objects::nonNull) // - .findFirst(); - var lastNonNullIndex = IntStream.range(0, values.length) // - .filter(i -> values[i] != null) // - .reduce((first, second) -> second); - if (lastNonNullIndex.isEmpty()) { - return new double[0]; - } - var result = new double[lastNonNullIndex.getAsInt() + 1]; - if (firstNonNull.isEmpty()) { - // all null - return result; - } - double last = firstNonNull.get(); - for (var i = 0; i < result.length; i++) { - double value = orElse(values[i], last); - result[i] = last = value; - } - return result; - } + simulator.accept(null); + error.accept(() -> "Stuck trying to get GlobalSimulationsContext. " + e.getMessage()); - /** - * Interpolate an Array of {@link Integer}s. - * - *

      - * Replaces nulls with previous value. If first entry is null, it is set to - * first available value. If all values are null, all are set to 0. - * - * @param values the values - * @return values without nulls - */ - protected static int[] interpolateArray(Integer[] values) { - var firstNonNull = stream(values) // - .filter(Objects::nonNull) // - .findFirst(); - var lastNonNullIndex = IntStream.range(0, values.length) // - .filter(i -> values[i] != null) // - .reduce((first, second) -> second); // - if (lastNonNullIndex.isEmpty()) { - return new int[0]; - } - var result = new int[lastNonNullIndex.getAsInt() + 1]; - if (firstNonNull.isEmpty()) { - // all null - return result; - } - int last = firstNonNull.get(); - for (var i = 0; i < result.length; i++) { - int value = orElse(values[i], last); - result[i] = last = value; - } - return result; - } + try { + sleep(10_000); + } catch (InterruptedException e1) { + e.printStackTrace(); - protected static int findFirstPeakIndex(int fromIndex, double[] values) { - if (values.length <= fromIndex) { - return fromIndex; - } else { - var previous = values[fromIndex]; - for (var i = fromIndex + 1; i < values.length; i++) { - var value = values[i]; - if (value < previous) { - return i - 1; + simulator.accept(null); + error.accept(() -> "Unable to create global simulations context: " + e1.getMessage()); } - previous = value; } } - return values.length - 1; - } - protected static int findFirstValleyIndex(int fromIndex, double[] values) { - if (values.length <= fromIndex) { - return fromIndex; - } else { - var previous = values[fromIndex]; - for (var i = fromIndex + 1; i < values.length; i++) { - var value = values[i]; - if (value > previous) { - return i - 1; - } - previous = value; - } - } - return values.length - 1; + simulator.accept(null); + error.accept(() -> "Unable to create global simulations context -> abort"); } /** - * Utilizes the previous three hours' data and computes the next 21 hours data - * from the {@link Optimizer} provided, then concatenates them to generate a - * 24-hour {@link GetScheduleResponse}. + * Calculates the ExecutionLimitSeconds for the {@link Optimizer}. * - * @param optimizer the {@link Optimizer} - * @param requestId the JSON-RPC request-id - * @param timedata the{@link Timedata} - * @param timeOfUseTariff the {@link TimeOfUseTariff} - * @param componentId the Component-ID - * @param now the current {@link ZonedDateTime} (will get rounded - * down to 15 minutes) - * @return the {@link GetScheduleResponse} - * @throws OpenemsNamedException on error + * @return execution limit in [s] */ - public static GetScheduleResponse handleGetScheduleRequest(Optimizer optimizer, UUID requestId, Timedata timedata, - TimeOfUseTariff timeOfUseTariff, String componentId, ZonedDateTime now) { - final var b = ImmutableList.builder(); - now = roundDownToQuarter(now); - final var fromTime = now.minusHours(3); - - final var params = optimizer.getParams(); - if (params != null) { - // Process last three hours of historic data - final var channelQuarterlyPrices = new ChannelAddress(componentId, "QuarterlyPrices"); - final var channelStateMachine = new ChannelAddress(componentId, "StateMachine"); - try { - var queryResult = timedata.queryHistoricData(null, fromTime, now, // - Set.of(channelQuarterlyPrices, channelStateMachine, // - SUM_GRID, SUM_PRODUCTION, SUM_CONSUMPTION, SUM_ESS_DISCHARGE_POWER, SUM_ESS_SOC), - new Resolution(15, ChronoUnit.MINUTES)); - ScheduleData.fromHistoricDataQuery(// - params.essTotalEnergy(), channelQuarterlyPrices, channelStateMachine, queryResult) // - .forEach(b::add); - } catch (Exception e) { - LOG.warn("Unable to read historic data: " + e.getMessage()); - } - } - - // Process future schedule - final var schedule = optimizer.getSchedule(); - optimizer.getSchedule().values().stream() // - .flatMap(ScheduleData::fromPeriod) // - .forEach(b::add); - - // Find 'toTime' of result - final ZonedDateTime toTime; - if (!schedule.isEmpty()) { - toTime = schedule.lastKey(); - } else { - var pricesPerQuarter = timeOfUseTariff.getPrices().pricePerQuarter; - if (!pricesPerQuarter.isEmpty()) { - toTime = pricesPerQuarter.lastKey(); - } else { - toTime = fromTime; - } - } - - return new GetScheduleResponse(requestId, fromTime, toTime, - new ScheduleDatas(params.essTotalEnergy(), b.build())); + public static long calculateExecutionLimitSeconds() { + return calculateExecutionLimitSeconds(Clock.systemDefaultZone()); } /** @@ -442,64 +142,6 @@ public static long calculateExecutionLimitSeconds(Clock clock) { return Duration.between(now, nextQuarter.plusMinutes(15)).getSeconds(); } - /** - * Post-Process a state of a Period during Simulation, i.e. replace with - * 'better' state with the same behaviour. - * - *

      - * NOTE: heavy computation is ok here, because this method is called only at the - * end with the best Schedule. - * - * @param state the initial state - * @param efBalancing the {@link EnergyFlow} as it would be in - * {@link StateMachine#BALANCING} - * @param efDelayDischarge the {@link EnergyFlow} as it would be in - * {@link StateMachine#DELAY_DISCHARGE} - * @param efChargeGrid the {@link EnergyFlow} as it would be in - * {@link StateMachine#CHARGE_GRID} - * @return the new state - */ - public static StateMachine postprocessSimulatorState(StateMachine state, EnergyFlow efBalancing, - EnergyFlow efDelayDischarge, EnergyFlow efChargeGrid) { - if (state == CHARGE_GRID) { - // CHARGE_GRID,... - if (efChargeGrid.ess() >= efDelayDischarge.ess()) { - // but battery charge/discharge is the same as DELAY_DISCHARGE - state = DELAY_DISCHARGE; - } - } - - if (state == DELAY_DISCHARGE) { - // DELAY_DISCHARGE,... - if (efDelayDischarge.ess() >= efBalancing.ess()) { - // but battery charge/discharge is the same as BALANCING - state = BALANCING; - } - } - - return state; - } - - /** - * Converts power [W] to energy [Wh/15 min]. - * - * @param power the power value - * @return the energy value - */ - public static int toEnergy(int power) { - return power / PERIODS_PER_HOUR; - } - - /** - * Converts energy [Wh/15 min] to power [W]. - * - * @param energy the energy value - * @return the power value - */ - public static Integer toPower(Integer energy) { - return multiply(energy, PERIODS_PER_HOUR); - } - /** * Prints the Schedule to System.out. * @@ -507,36 +149,45 @@ public static Integer toPower(Integer energy) { * NOTE: The output format is suitable as input for "RunOptimizerFromLogApp". * This is useful to re-run a simulation. * - * @param params the {@link Params} - * @param periods the map of {@link Period}s + * @param simulator the {@link Simulator} + * @param simulationResult the {@link SimulationResult} */ - protected static void logSchedule(Params params, ImmutableSortedMap periods) { - System.out.println("OPTIMIZER " + params.toLogString()); - System.out.println(ScheduleDatas.fromSchedule(params.essTotalEnergy(), periods).toLogString("OPTIMIZER ")); + public static void logSimulationResult(Simulator simulator, SimulationResult simulationResult) { + final var prefix = "OPTIMIZER "; + System.out.println(simulator.toLogString(prefix)); + System.out.println(simulationResult.toLogString(prefix)); } /** - * Updates the active Schedule with a new Schedule. - * - *

      - *

        - *
      • Period of the currently active Quarter is never changed - *
      • Old Periods are removed from the Schedule - *
      • Remaining Schedules are updated from new Schedule - *
      + * Sorts the list of {@link EnergySchedulable}s by the order given by + * {@link Scheduler}. * - * @param now the current {@link ZonedDateTime} - * @param schedule the active Schedule - * @param newSchedule the new Schedule + * @param scheduler the {@link Scheduler} + * @param list the list of {@link EnergySchedulable}s + * @return sorted list of {@link EnergySchedulable}s */ - public static void updateSchedule(ZonedDateTime now, TreeMap schedule, - ImmutableSortedMap newSchedule) { - var thisQuarter = roundDownToQuarter(now); - var current = schedule.get(thisQuarter); - schedule.clear(); - schedule.putAll(newSchedule); - if (current != null) { - schedule.put(thisQuarter, current); - } + public static ImmutableList sortByScheduler(Scheduler scheduler, List list) { + var ref = scheduler.getControllers().stream().toList(); + + final Ordering byScheduler = new Ordering() { + public int compare(String left, String right) { + var leftIdx = ref.indexOf(left); + var rightIdx = ref.indexOf(right); + if (leftIdx < 0 && rightIdx < 0) { // both not found + return Objects.compare(left, right, String::compareTo); + } else if (leftIdx < 0) { // only right is in list + return 1; + } else if (rightIdx < 0) { // only left is in list + return -1; + } else { + return leftIdx - rightIdx; + } + } + }; + + return byScheduler // + .onResultOf(EnergySchedulable::id) // + .immutableSortedCopy(list); } + } diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/jsonrpc/GetScheduleResponse.java b/io.openems.edge.energy/src/io/openems/edge/energy/v1/jsonrpc/GetScheduleResponse.java similarity index 90% rename from io.openems.edge.energy/src/io/openems/edge/energy/jsonrpc/GetScheduleResponse.java rename to io.openems.edge.energy/src/io/openems/edge/energy/v1/jsonrpc/GetScheduleResponse.java index e27461abc45..e20510d8fe3 100644 --- a/io.openems.edge.energy/src/io/openems/edge/energy/jsonrpc/GetScheduleResponse.java +++ b/io.openems.edge.energy/src/io/openems/edge/energy/v1/jsonrpc/GetScheduleResponse.java @@ -1,4 +1,4 @@ -package io.openems.edge.energy.jsonrpc; +package io.openems.edge.energy.v1.jsonrpc; import java.time.ZonedDateTime; import java.util.Map.Entry; @@ -9,8 +9,8 @@ import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; import io.openems.common.utils.JsonUtils; -import io.openems.edge.energy.optimizer.ScheduleDatas; -import io.openems.edge.energy.optimizer.ScheduleDatas.ScheduleData; +import io.openems.edge.energy.v1.optimizer.ScheduleDatas; +import io.openems.edge.energy.v1.optimizer.ScheduleDatas.ScheduleData; /** * Represents a JSON-RPC Response for 'getMeters'. @@ -34,6 +34,7 @@ * } * */ +@Deprecated public class GetScheduleResponse extends JsonrpcResponseSuccess { private final ZonedDateTime fromDate; diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/EnergyFlow.java b/io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/EnergyFlowV1.java similarity index 76% rename from io.openems.edge.energy/src/io/openems/edge/energy/optimizer/EnergyFlow.java rename to io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/EnergyFlowV1.java index bf108379c74..3de095d0913 100644 --- a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/EnergyFlow.java +++ b/io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/EnergyFlowV1.java @@ -1,16 +1,17 @@ -package io.openems.edge.energy.optimizer; +package io.openems.edge.energy.v1.optimizer; import static io.openems.edge.common.type.TypeUtils.fitWithin; import static java.lang.Math.max; import static java.lang.Math.min; import io.openems.edge.controller.ess.timeofusetariff.StateMachine; -import io.openems.edge.energy.optimizer.Params.OptimizePeriod; +import io.openems.edge.energy.v1.optimizer.ParamsV1.OptimizePeriod; /** * Simulates a detailed Energy-Flow. */ -public record EnergyFlow(// +@Deprecated +public record EnergyFlowV1(// int production, /* positive */ int consumption, /* positive */ int ess, /* charge negative, discharge positive */ @@ -24,49 +25,49 @@ public record EnergyFlow(// ) { /** - * Simulate {@link EnergyFlow} in {@link StateMachine#BALANCING}. + * Simulate {@link EnergyFlowV1} in {@link StateMachine#BALANCING}. * - * @param p the {@link Params} + * @param p the {@link ParamsV1} * @param op the {@link OptimizePeriod} * @param essInitial ESS Initially Available Energy (SoC in [Wh]) - * @return the {@link EnergyFlow} + * @return the {@link EnergyFlowV1} */ - public static EnergyFlow withBalancing(Params p, OptimizePeriod op, int essInitial) { + public static EnergyFlowV1 withBalancing(ParamsV1 p, OptimizePeriod op, int essInitial) { return create(p, op, essInitial, // p.essTotalEnergy(), // Allow Balancing till full battery op.consumption() - op.production()); } /** - * Simulate {@link EnergyFlow} in {@link StateMachine#DELAY_DISCHARGE}. + * Simulate {@link EnergyFlowV1} in {@link StateMachine#DELAY_DISCHARGE}. * - * @param p the {@link Params} + * @param p the {@link ParamsV1} * @param op the {@link OptimizePeriod} * @param essInitial ESS Initially Available Energy (SoC in [Wh]) - * @return the {@link EnergyFlow} + * @return the {@link EnergyFlowV1} */ - public static EnergyFlow withDelayDischarge(Params p, OptimizePeriod op, int essInitial) { + public static EnergyFlowV1 withDelayDischarge(ParamsV1 p, OptimizePeriod op, int essInitial) { return create(p, op, essInitial, // p.essTotalEnergy(), // Allow Delay-Discharge with full battery min(0, op.consumption() - op.production())); // Allow charge; no discharge } /** - * Simulate {@link EnergyFlow} in {@link StateMachine#CHARGE_GRID}. + * Simulate {@link EnergyFlowV1} in {@link StateMachine#CHARGE_GRID}. * - * @param p the {@link Params} + * @param p the {@link ParamsV1} * @param op the {@link OptimizePeriod} * @param essInitial ESS Initially Available Energy (SoC in [Wh]) - * @return the {@link EnergyFlow} + * @return the {@link EnergyFlowV1} */ - public static EnergyFlow withChargeGrid(Params p, OptimizePeriod op, int essInitial) { + public static EnergyFlowV1 withChargeGrid(ParamsV1 p, OptimizePeriod op, int essInitial) { return create(p, op, essInitial, // p.essMaxSocEnergy(), // Allow Charge-Grid only till Max-SoC // Same as Delay-Discharge + Charge-From-Grid min(0, op.consumption() - op.production()) - op.essChargeInChargeGrid()); } - protected static EnergyFlow create(Params p, OptimizePeriod op, int essInitial, int essMaxSocEnergy, + protected static EnergyFlowV1 create(ParamsV1 p, OptimizePeriod op, int essInitial, int essMaxSocEnergy, int essTarget) { var essMaxDischarge = max(0, essInitial - p.essMinSocEnergy()); var essMaxCharge = max(0, essMaxSocEnergy - essInitial); @@ -86,7 +87,7 @@ protected static EnergyFlow create(Params p, OptimizePeriod op, int essInitial, var essToConsumption = max(0, min(op.consumption() - productionToConsumption, ess - productionToGrid)); var gridToConsumption = max(0, op.consumption() - essToConsumption - productionToConsumption); var gridToEss = grid - gridToConsumption + productionToGrid; - return new EnergyFlow(// + return new EnergyFlowV1(// op.production(), /* production */ op.consumption(), /* consumption */ ess, /* ess */ diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/GlobalContext.java b/io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/GlobalContextV1.java similarity index 67% rename from io.openems.edge.energy/src/io/openems/edge/energy/optimizer/GlobalContext.java rename to io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/GlobalContextV1.java index c7b889a6eff..3af5e879047 100644 --- a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/GlobalContext.java +++ b/io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/GlobalContextV1.java @@ -1,25 +1,25 @@ -package io.openems.edge.energy.optimizer; +package io.openems.edge.energy.v1.optimizer; import java.time.Clock; import io.openems.edge.common.sum.Sum; -import io.openems.edge.controller.ess.timeofusetariff.StateMachine; import io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffController; -import io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImpl; +import io.openems.edge.controller.ess.timeofusetariff.v1.EnergyScheduleHandlerV1; import io.openems.edge.energy.api.EnergyScheduleHandler; import io.openems.edge.predictor.api.manager.PredictorManager; import io.openems.edge.timeofusetariff.api.TimeOfUseTariff; -public record GlobalContext(// +@Deprecated +public record GlobalContextV1(// Clock clock, // - EnergyScheduleHandler energyScheduleHandler, // + EnergyScheduleHandlerV1 energyScheduleHandler, // Sum sum, // PredictorManager predictorManager, // TimeOfUseTariff timeOfUseTariff) { public static class Builder { private Clock clock; - private EnergyScheduleHandler energyScheduleHandler; + private EnergyScheduleHandlerV1 energyScheduleHandler; private Sum sum; private PredictorManager predictorManager; private TimeOfUseTariff timeOfUseTariff; @@ -41,8 +41,7 @@ public Builder setClock(Clock clock) { * @param energyScheduleHandler the {@link EnergyScheduleHandler} * @return myself */ - public Builder setEnergyScheduleHandler( - EnergyScheduleHandler energyScheduleHandler) { + public Builder setEnergyScheduleHandler(EnergyScheduleHandlerV1 energyScheduleHandler) { this.energyScheduleHandler = energyScheduleHandler; return this; } @@ -81,23 +80,23 @@ public Builder setTimeOfUseTariff(TimeOfUseTariff timeOfUseTariff) { } /** - * Builds the {@link GlobalContext}. + * Builds the {@link GlobalContextV1}. * - * @return the {@link GlobalContext} record + * @return the {@link GlobalContextV1} record */ - public GlobalContext build() { - return new GlobalContext(this.clock, this.energyScheduleHandler, this.sum, this.predictorManager, + public GlobalContextV1 build() { + return new GlobalContextV1(this.clock, this.energyScheduleHandler, this.sum, this.predictorManager, this.timeOfUseTariff); } } /** - * Create a {@link GlobalContext} {@link Builder}. + * Create a {@link GlobalContextV1} {@link Builder}. * * @return a {@link Builder} */ public static Builder create() { - return new GlobalContext.Builder(); + return new GlobalContextV1.Builder(); } } diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/InitialPopulationUtils.java b/io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/InitialPopulationV1Utils.java similarity index 91% rename from io.openems.edge.energy/src/io/openems/edge/energy/optimizer/InitialPopulationUtils.java rename to io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/InitialPopulationV1Utils.java index b09e3e3036c..41b99551fcf 100644 --- a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/InitialPopulationUtils.java +++ b/io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/InitialPopulationV1Utils.java @@ -1,10 +1,10 @@ -package io.openems.edge.energy.optimizer; +package io.openems.edge.energy.v1.optimizer; import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.BALANCING; import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.CHARGE_GRID; import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.DELAY_DISCHARGE; -import static io.openems.edge.energy.optimizer.Utils.findFirstPeakIndex; -import static io.openems.edge.energy.optimizer.Utils.findFirstValleyIndex; +import static io.openems.edge.energy.api.EnergyUtils.findFirstPeakIndex; +import static io.openems.edge.energy.api.EnergyUtils.findFirstValleyIndex; import java.util.Arrays; import java.util.List; @@ -19,11 +19,12 @@ import io.jenetics.IntegerChromosome; import io.jenetics.IntegerGene; import io.openems.edge.controller.ess.timeofusetariff.StateMachine; -import io.openems.edge.energy.optimizer.Params.OptimizePeriod; +import io.openems.edge.energy.v1.optimizer.ParamsV1.OptimizePeriod; -public class InitialPopulationUtils { +@Deprecated +public class InitialPopulationV1Utils { - private InitialPopulationUtils() { + private InitialPopulationV1Utils() { } /** @@ -40,10 +41,10 @@ private InitialPopulationUtils() { * sure, that this one wins in case there are other results with same cost, e.g. * when battery never gets empty anyway. * - * @param p the {@link Params} + * @param p the {@link ParamsV1} * @return the {@link Genotype} */ - public static ImmutableList> buildInitialPopulation(Params p) { + public static ImmutableList> buildInitialPopulation(ParamsV1 p) { var states = List.of(p.states()); if (!states.contains(BALANCING)) { throw new IllegalArgumentException("State option BALANCING is always required!"); diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/OptimizerV1.java b/io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/OptimizerV1.java new file mode 100644 index 00000000000..77fda46f75b --- /dev/null +++ b/io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/OptimizerV1.java @@ -0,0 +1,159 @@ +package io.openems.edge.energy.v1.optimizer; + +import static com.google.common.collect.ImmutableSortedMap.toImmutableSortedMap; +import static io.openems.edge.energy.optimizer.Utils.calculateExecutionLimitSeconds; +import static io.openems.edge.energy.optimizer.Utils.initializeRandomRegistryForProduction; +import static io.openems.edge.energy.v1.optimizer.SimulatorV1.simulate; +import static io.openems.edge.energy.v1.optimizer.UtilsV1.createSimulatorParams; +import static io.openems.edge.energy.v1.optimizer.UtilsV1.logSchedule; +import static io.openems.edge.energy.v1.optimizer.UtilsV1.updateSchedule; +import static java.lang.Thread.sleep; + +import java.time.Duration; +import java.time.Instant; +import java.time.ZonedDateTime; +import java.util.Map.Entry; +import java.util.TreeMap; +import java.util.function.Supplier; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.collect.ImmutableSortedMap; + +import io.openems.common.exceptions.OpenemsException; +import io.openems.common.function.ThrowingSupplier; +import io.openems.common.test.TimeLeapClock; +import io.openems.common.utils.FunctionUtils; +import io.openems.common.worker.AbstractImmediateWorker; +import io.openems.edge.controller.ess.timeofusetariff.v1.EnergyScheduleHandlerV1; +import io.openems.edge.energy.LogVerbosity; +import io.openems.edge.energy.v1.optimizer.SimulatorV1.Period; + +/** + * This task is executed once in the beginning and afterwards every full 15 + * minutes. + */ +@Deprecated +public class OptimizerV1 extends AbstractImmediateWorker { + + private final Logger log = LoggerFactory.getLogger(OptimizerV1.class); + + private final Supplier logVerbosity; + private final ThrowingSupplier globalContext; + private final TreeMap schedule = new TreeMap<>(); + + private ParamsV1 params = null; + + public OptimizerV1(Supplier logVerbosity, // + ThrowingSupplier globalContext) { + this.logVerbosity = logVerbosity; + this.globalContext = globalContext; + initializeRandomRegistryForProduction(); + + // Run Optimizer thread in LOW PRIORITY + this.setPriority(Thread.MIN_PRIORITY); + } + + @Override + public void forever() throws InterruptedException, OpenemsException { + this.traceLog(() -> "Start next run of Optimizer"); + + this.createParams(); // this possibly takes forever + + final var globalContext = this.globalContext.get(); + final var start = Instant.now(globalContext.clock()); + + long executionLimitSeconds; + + // Calculate max execution time till next quarter (with buffer) + executionLimitSeconds = calculateExecutionLimitSeconds(globalContext.clock()); + + // Find best Schedule + var schedule = SimulatorV1.getBestSchedule(this.params, executionLimitSeconds); + + // Re-Simulate and keep best Schedule + var newSchedule = simulate(this.params, schedule); + + // Debug Log best Schedule + logSchedule(this.params, newSchedule); + + // Update Schedule from newly simulated Schedule + synchronized (this.schedule) { + updateSchedule(ZonedDateTime.now(globalContext.clock()), this.schedule, newSchedule); + } + + // Send Schedule to Controller + globalContext.energyScheduleHandler().setSchedule(this.schedule.entrySet().stream()// + .collect(toImmutableSortedMap(// + ZonedDateTime::compareTo, // + Entry::getKey, // + e -> new EnergyScheduleHandlerV1.Period<>(e.getValue().state(), + e.getValue().op().essChargeInChargeGrid())))); + + // Sleep remaining time + if (!(globalContext.clock() instanceof TimeLeapClock)) { + var remainingExecutionLimit = Duration + .between(Instant.now(globalContext.clock()), start.plusSeconds(executionLimitSeconds)).getSeconds(); + if (remainingExecutionLimit > 0) { + this.traceLog(() -> "Sleep [" + remainingExecutionLimit + "s] till next run of Optimizer"); + sleep(remainingExecutionLimit * 1000); + } + } + } + + /** + * Try forever till all data is available (e.g. ESS Capacity) + * + * @throws InterruptedException during sleep + */ + private void createParams() throws InterruptedException { + while (true) { + try { + synchronized (this.schedule) { + this.params = createSimulatorParams(this.globalContext.get(), // + this.schedule.entrySet().stream() // + .collect(toImmutableSortedMap(// + ZonedDateTime::compareTo, // + Entry::getKey, e -> e.getValue().state()))); + return; + } + + } catch (OpenemsException e) { + this.traceLog(() -> "Stuck trying to get Params. " + e.getMessage()); + this.params = null; + synchronized (this.schedule) { + this.schedule.clear(); + } + sleep(30_000); + } + } + } + + /** + * Gets the current {@link ParamsV1} or null. + * + * @return the {@link ParamsV1} or null + */ + public ParamsV1 getParams() { + return this.params; + } + + /** + * Gets a copy of the Schedule. + * + * @return {@link ImmutableSortedMap} + */ + public ImmutableSortedMap getSchedule() { + synchronized (this.schedule) { + return ImmutableSortedMap.copyOf(this.schedule); + } + } + + private void traceLog(Supplier message) { + switch (this.logVerbosity.get()) { + case NONE, DEBUG_LOG -> FunctionUtils.doNothing(); + case TRACE -> this.log.info("OPTIMIZER " + message.get()); + } + } +} diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/ParamsUtils.java b/io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/ParamsUtilsV1.java similarity index 88% rename from io.openems.edge.energy/src/io/openems/edge/energy/optimizer/ParamsUtils.java rename to io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/ParamsUtilsV1.java index cd1e73e75ec..8cca4e3bfdd 100644 --- a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/ParamsUtils.java +++ b/io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/ParamsUtilsV1.java @@ -1,10 +1,10 @@ -package io.openems.edge.energy.optimizer; +package io.openems.edge.energy.v1.optimizer; import static com.google.common.math.Quantiles.percentiles; -import static io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffController.PERIODS_PER_HOUR; -import static io.openems.edge.energy.optimizer.Utils.ESS_CHARGE_C_RATE; -import static io.openems.edge.energy.optimizer.Utils.findFirstPeakIndex; -import static io.openems.edge.energy.optimizer.Utils.findFirstValleyIndex; +import static io.openems.edge.controller.ess.timeofusetariff.Utils.ESS_CHARGE_C_RATE; +import static io.openems.edge.energy.api.EnergyConstants.PERIODS_PER_HOUR; +import static io.openems.edge.energy.api.EnergyUtils.findFirstPeakIndex; +import static io.openems.edge.energy.api.EnergyUtils.findFirstValleyIndex; import static java.lang.Math.max; import static java.lang.Math.min; import static java.lang.Math.round; @@ -16,11 +16,12 @@ import com.google.common.primitives.ImmutableIntArray; import io.openems.edge.controller.ess.timeofusetariff.StateMachine; -import io.openems.edge.energy.optimizer.Simulator.Period; +import io.openems.edge.energy.v1.optimizer.SimulatorV1.Period; -public class ParamsUtils { +@Deprecated +public class ParamsUtilsV1 { - private ParamsUtils() { + private ParamsUtilsV1() { } /** diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Params.java b/io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/ParamsV1.java similarity index 94% rename from io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Params.java rename to io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/ParamsV1.java index f49fe773eb9..92ce404372a 100644 --- a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Params.java +++ b/io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/ParamsV1.java @@ -1,8 +1,8 @@ -package io.openems.edge.energy.optimizer; +package io.openems.edge.energy.v1.optimizer; import static com.google.common.collect.ImmutableList.toImmutableList; -import static io.openems.edge.energy.optimizer.ParamsUtils.calculateChargeEnergyInChargeGrid; -import static io.openems.edge.energy.optimizer.ParamsUtils.calculatePeriodLengthHourFromIndex; +import static io.openems.edge.energy.v1.optimizer.ParamsUtilsV1.calculateChargeEnergyInChargeGrid; +import static io.openems.edge.energy.v1.optimizer.ParamsUtilsV1.calculatePeriodLengthHourFromIndex; import static java.lang.Math.min; import java.time.ZonedDateTime; @@ -16,7 +16,8 @@ import io.openems.edge.controller.ess.timeofusetariff.StateMachine; -public record Params(// +@Deprecated +public record ParamsV1(// /** Start-Timestamp of the Schedule */ ZonedDateTime time, /** ESS Total Energy (Capacity) [Wh] */ @@ -206,15 +207,15 @@ private ImmutableList generatePeriods() { return result.build(); } - public Params build() { - return new Params(this.time, this.essTotalEnergy, this.essMinSocEnergy, this.essMaxSocEnergy, + public ParamsV1 build() { + return new ParamsV1(this.time, this.essTotalEnergy, this.essMinSocEnergy, this.essMaxSocEnergy, this.essInitialEnergy, this.states, // this.existingSchedule, this.generatePeriods()); } } protected static Builder create() { - return new Params.Builder(); + return new ParamsV1.Builder(); } @Override diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/ScheduleDatas.java b/io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/ScheduleDatas.java similarity index 94% rename from io.openems.edge.energy/src/io/openems/edge/energy/optimizer/ScheduleDatas.java rename to io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/ScheduleDatas.java index 053dac39d13..ed0f95c1600 100644 --- a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/ScheduleDatas.java +++ b/io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/ScheduleDatas.java @@ -1,4 +1,4 @@ -package io.openems.edge.energy.optimizer; +package io.openems.edge.energy.v1.optimizer; import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.ImmutableSortedMap.toImmutableSortedMap; @@ -7,13 +7,13 @@ import static io.openems.common.utils.JsonUtils.getAsDouble; import static io.openems.common.utils.JsonUtils.getAsInt; import static io.openems.common.utils.JsonUtils.toJson; -import static io.openems.edge.energy.optimizer.Utils.SUM_CONSUMPTION; +import static io.openems.edge.controller.ess.timeofusetariff.Utils.SUM_PRODUCTION; import static io.openems.edge.energy.optimizer.Utils.SUM_ESS_DISCHARGE_POWER; import static io.openems.edge.energy.optimizer.Utils.SUM_ESS_SOC; import static io.openems.edge.energy.optimizer.Utils.SUM_GRID; -import static io.openems.edge.energy.optimizer.Utils.SUM_PRODUCTION; -import static io.openems.edge.energy.optimizer.Utils.toEnergy; -import static io.openems.edge.energy.optimizer.Utils.toPower; +import static io.openems.edge.energy.v1.optimizer.UtilsV1.SUM_CONSUMPTION; +import static io.openems.edge.energy.v1.optimizer.UtilsV1.toEnergy; +import static io.openems.edge.energy.v1.optimizer.UtilsV1.toPower; import static java.lang.Double.parseDouble; import static java.lang.Integer.parseInt; import static java.lang.Math.round; @@ -43,24 +43,25 @@ import io.openems.common.exceptions.OpenemsException; import io.openems.common.types.ChannelAddress; import io.openems.edge.controller.ess.timeofusetariff.StateMachine; -import io.openems.edge.energy.optimizer.Params.Length; -import io.openems.edge.energy.optimizer.Simulator.Period; +import io.openems.edge.energy.v1.optimizer.ParamsV1.Length; +import io.openems.edge.energy.v1.optimizer.SimulatorV1.Period; /** * Data for JSONRPC-Response. Values are in [W]. */ +@Deprecated public record ScheduleDatas(int essTotalEnergy, ImmutableList entries) { private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("HH:mm"); /** - * Creates {@link ScheduleDatas} from an {@link Optimizer}. + * Creates {@link ScheduleDatas} from an {@link OptimizerV1}. * - * @param optimizer the {@link Optimizer} + * @param optimizer the {@link OptimizerV1} * @return a {@link ScheduleDatas}a * @throws OpenemsException on error */ - public static ScheduleDatas fromSchedule(Optimizer optimizer) throws OpenemsException { + public static ScheduleDatas fromSchedule(OptimizerV1 optimizer) throws OpenemsException { final var schedule = optimizer.getSchedule(); if (schedule == null) { throw new OpenemsException("Has no Schedule"); diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/SimulatorV1.java b/io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/SimulatorV1.java new file mode 100644 index 00000000000..52145544f2e --- /dev/null +++ b/io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/SimulatorV1.java @@ -0,0 +1,178 @@ +package io.openems.edge.energy.v1.optimizer; + +import static io.jenetics.engine.EvolutionResult.toBestGenotype; +import static io.jenetics.engine.Limits.byExecutionTime; +import static io.openems.edge.energy.v1.optimizer.InitialPopulationV1Utils.buildInitialPopulation; +import static io.openems.edge.energy.v1.optimizer.UtilsV1.paramsAreValid; +import static io.openems.edge.energy.v1.optimizer.UtilsV1.postprocessSimulatorState; +import static java.lang.Math.max; +import static java.time.Duration.ofSeconds; + +import java.time.ZonedDateTime; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSortedMap; + +import io.jenetics.Genotype; +import io.jenetics.IntegerChromosome; +import io.jenetics.IntegerGene; +import io.jenetics.engine.Engine; +import io.jenetics.engine.EvolutionResult; +import io.openems.edge.controller.ess.timeofusetariff.StateMachine; +import io.openems.edge.energy.v1.optimizer.ParamsV1.Length; +import io.openems.edge.energy.v1.optimizer.ParamsV1.OptimizePeriod; + +@Deprecated +public class SimulatorV1 { + + /** Used to incorporate charge/discharge efficiency. */ + public static final double EFFICIENCY_FACTOR = 1.17; + + public record Period(OptimizePeriod op, StateMachine state, int essInitial, EnergyFlowV1 ef) { + } + + /** + * Simulates a Schedule and calculates the cost. + * + * @param p the {@link ParamsV1} + * @param schedule the {@link StateMachine} states of the Schedule + * @return the cost, lower is better; always positive + */ + protected static double calculateCost(ParamsV1 p, StateMachine[] schedule) { + final var nextEssInitial = new AtomicInteger(p.essInitialEnergy()); + var sum = 0.; + for (var i = 0; i < p.optimizePeriods().size(); i++) { + sum += simulatePeriod(p, p.optimizePeriods().get(i), schedule[i], nextEssInitial, null); + } + return sum; + } + + /** + * Simulates a Schedule in quarterly periods. + * + * @param p the {@link ParamsV1} + * @param schedule the {@link StateMachine} states of the Schedule + * @return a Map of {@link Period}s + */ + protected static ImmutableSortedMap simulate(ParamsV1 p, StateMachine[] schedule) { + final var nextEssInitial = new AtomicInteger(p.essInitialEnergy()); + var result = ImmutableSortedMap.naturalOrder(); + for (var i = 0; i < p.optimizePeriods().size(); i++) { + var state = schedule[i]; + var op = p.optimizePeriods().get(i); + var length = op.quarterPeriods().size() == 1 ? Length.QUARTER : Length.HOUR; + // Convert mixed OptimizePeriods to pure quarterly + for (var qp : op.quarterPeriods()) { + var quarterlyOp = new OptimizePeriod(qp.time(), length, qp.essMaxChargeEnergy(), + qp.essMaxDischargeEnergy(), qp.essChargeInChargeGrid(), qp.maxBuyFromGrid(), qp.production(), + qp.consumption(), qp.price(), ImmutableList.of(qp)); + simulatePeriod(p, quarterlyOp, state, nextEssInitial, period -> result.put(period.op().time(), period)); + } + } + return result.build(); + } + + /** + * Calculates the cost of one Period under the given Schedule. + * + * @param p the {@link ParamsV1} + * @param op the current {@link OptimizePeriod} + * @param state the {@link StateMachine} of the current period + * @param nextEssInitial the initial SoC-Energy; also used as return value + * @param collect a {@link Consumer} to collect the simulation results if + * required. We are not always collecting results to + * reduce workload during simulation. + * @return the cost, lower is better; always positive + */ + protected static double simulatePeriod(ParamsV1 p, OptimizePeriod op, StateMachine state, + final AtomicInteger nextEssInitial, Consumer collect) { + // Constants + final var essInitial = max(0, nextEssInitial.get()); // always at least '0' + + // Calculate Energy-Flow + final var ef = switch (state) { + case BALANCING -> EnergyFlowV1.withBalancing(p, op, essInitial); + case DELAY_DISCHARGE -> EnergyFlowV1.withDelayDischarge(p, op, essInitial); + case CHARGE_GRID -> EnergyFlowV1.withChargeGrid(p, op, essInitial); + }; + + nextEssInitial.set(essInitial - ef.ess()); + + // Calculate Cost + double cost; + if (ef.grid() > 0) { + // Filter negative prices + var price = max(0, op.price()); + + cost = // Cost for direct Consumption + ef.gridToConsumption() * price + // Cost for future Consumption after storage + + ef.gridToEss() * price * EFFICIENCY_FACTOR; + + } else { + // Sell-to-Grid + cost = 0.; + } + if (collect != null) { + var postprocessedState = postprocessSimulatorState(state, // + EnergyFlowV1.withBalancing(p, op, essInitial), // + EnergyFlowV1.withDelayDischarge(p, op, essInitial), // + EnergyFlowV1.withChargeGrid(p, op, essInitial)); + collect.accept(new Period(op, postprocessedState, essInitial, ef)); + } + return cost; + } + + /** + * Runs the optimization with default settings. + * + * @param p the {@link ParamsV1} + * @param executionLimitSeconds limit.byExecutionTime.ofSeconds + * @return the best schedule + */ + protected static StateMachine[] getBestSchedule(ParamsV1 p, long executionLimitSeconds) { + return getBestSchedule(p, executionLimitSeconds, null, null); + } + + protected static StateMachine[] getBestSchedule(ParamsV1 p, long executionLimitSeconds, Integer populationSize, + Integer limit) { + // Return pure BALANCING Schedule if no predictions are available + if (!paramsAreValid(p)) { + return p.optimizePeriods().stream() // + .map(op -> StateMachine.BALANCING) // + .toArray(StateMachine[]::new); + } + + var gtf = Genotype.of(IntegerChromosome.of(IntegerGene.of(0, p.states().length)), p.optimizePeriods().size()); // + var eval = (Function, Double>) (gt) -> { + var modes = new StateMachine[p.optimizePeriods().size()]; + for (var i = 0; i < modes.length; i++) { + modes[i] = p.states()[gt.get(i).get(0).intValue()]; + } + return calculateCost(p, modes); + }; + var engine = Engine // + .builder(eval, gtf) // + .executor(Runnable::run) // current thread + .minimizing(); + if (populationSize != null) { + engine.populationSize(populationSize); // + } + Stream> stream = engine.build() // + .stream(buildInitialPopulation(p)) // + .limit(byExecutionTime(ofSeconds(executionLimitSeconds))); // + if (limit != null) { + stream = stream.limit(limit); // apply optional limit + } + var bestGt = stream // + .collect(toBestGenotype()); + return IntStream.range(0, p.optimizePeriods().size()) // + .mapToObj(period -> p.states()[bestGt.get(period).get(0).intValue()]) // + .toArray(StateMachine[]::new); + } +} diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/UtilsV1.java b/io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/UtilsV1.java new file mode 100644 index 00000000000..d43f90fcff6 --- /dev/null +++ b/io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/UtilsV1.java @@ -0,0 +1,382 @@ +package io.openems.edge.energy.v1.optimizer; + +import static io.openems.common.utils.DateUtils.roundDownToQuarter; +import static io.openems.edge.common.type.TypeUtils.multiply; +import static io.openems.edge.common.type.TypeUtils.orElse; +import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.BALANCING; +import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.CHARGE_GRID; +import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.DELAY_DISCHARGE; +import static io.openems.edge.controller.ess.timeofusetariff.Utils.ESS_MAX_SOC; +import static io.openems.edge.controller.ess.timeofusetariff.v1.UtilsV1.getEssMinSocPercentage; +import static io.openems.edge.energy.api.EnergyConstants.PERIODS_PER_HOUR; +import static io.openems.edge.energy.api.EnergyUtils.interpolateArray; +import static io.openems.edge.energy.optimizer.Utils.ESS_LIMIT_14A_ENWG; +import static io.openems.edge.energy.optimizer.Utils.SUM_ESS_DISCHARGE_POWER; +import static io.openems.edge.energy.optimizer.Utils.SUM_ESS_SOC; +import static io.openems.edge.energy.optimizer.Utils.SUM_GRID; +import static java.lang.Math.max; +import static java.lang.Math.round; +import static java.util.Arrays.stream; + +import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; +import java.util.Objects; +import java.util.Set; +import java.util.TreeMap; +import java.util.UUID; +import java.util.stream.IntStream; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSortedMap; +import com.google.common.collect.Streams; + +import io.openems.common.exceptions.InvalidValueException; +import io.openems.common.timedata.Resolution; +import io.openems.common.types.ChannelAddress; +import io.openems.edge.controller.ess.emergencycapacityreserve.statemachine.Context; +import io.openems.edge.controller.ess.timeofusetariff.StateMachine; +import io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffController; +import io.openems.edge.controller.ess.timeofusetariff.v1.EnergyScheduleHandlerV1.ContextV1; +import io.openems.edge.energy.v1.jsonrpc.GetScheduleResponse; +import io.openems.edge.energy.v1.optimizer.ScheduleDatas.ScheduleData; +import io.openems.edge.energy.v1.optimizer.SimulatorV1.Period; +import io.openems.edge.ess.api.SymmetricEss; +import io.openems.edge.timedata.api.Timedata; +import io.openems.edge.timeofusetariff.api.TimeOfUseTariff; + +/** + * Utils for {@link TimeOfUseTariffController}. + * + *

      + * All energy values are in [Wh] and positive, unless stated differently. + */ +@Deprecated +public final class UtilsV1 { + + private UtilsV1() { + } + + public static final ChannelAddress SUM_PRODUCTION = new ChannelAddress("_sum", "ProductionActivePower"); + public static final ChannelAddress SUM_CONSUMPTION = new ChannelAddress("_sum", "ConsumptionActivePower"); + public static final ChannelAddress SUM_UNMANAGED_CONSUMPTION = new ChannelAddress("_sum", + "UnmanagedConsumptionActivePower"); + + private static final Logger LOG = LoggerFactory.getLogger(UtilsV1.class); + + /** + * Create {@link ParamsV1} for {@link SimulatorV1}. + * + * @param globalContext the {@link GlobalContextV1} object + * @param existingSchedule the existing schedule, i.e. result of previous + * optimization + * @return {@link ParamsV1} + * @throws InvalidValueException on error + */ + public static ParamsV1 createSimulatorParams(GlobalContextV1 globalContext, + ImmutableSortedMap existingSchedule) throws InvalidValueException { + final var time = roundDownToQuarter(ZonedDateTime.now()); + + // Prediction values + final var predictionConsumption = joinConsumptionPredictions(4, // + globalContext.predictorManager().getPrediction(SUM_CONSUMPTION).asArray(), // + globalContext.predictorManager().getPrediction(SUM_UNMANAGED_CONSUMPTION).asArray()); + final var predictionProduction = generateProductionPrediction(// + globalContext.predictorManager().getPrediction(SUM_PRODUCTION).asArray(), // + predictionConsumption.length); + + // Prices contains the price values and the time it is retrieved. + final var prices = globalContext.timeOfUseTariff().getPrices(); + + // Ess information. + var context = globalContext.energyScheduleHandler().getContext(); + final var essTotalEnergy = context.ess().getCapacity().getOrError(); + final var essMinSocEnergy = getEssMinSocEnergy(context, essTotalEnergy); + final var essMaxSocEnergy = round(ESS_MAX_SOC / 100F * essTotalEnergy); + final var essSoc = context.ess().getSoc().getOrError(); + final var essSocEnergy = essTotalEnergy /* [Wh] */ / 100 * essSoc; + + // Power Values for scheduling battery for individual periods. + var maxDischargePower = globalContext.sum().getEssMaxDischargePower().orElse(1000 /* at least 1000 */); + var maxChargePower = globalContext.sum().getEssMaxDischargePower().orElse(-1000 /* at least 1000 */); + if (context.limitChargePowerFor14aEnWG()) { + maxChargePower = max(ESS_LIMIT_14A_ENWG, maxChargePower); // Apply §14a EnWG limit + } + + return ParamsV1.create() // + .setTime(time) // + .setEssTotalEnergy(essTotalEnergy) // + .setEssMinSocEnergy(essMinSocEnergy) // + .setEssMaxSocEnergy(essMaxSocEnergy) // + .setEssInitialEnergy(essSocEnergy) // + .setEssMaxChargeEnergy(toEnergy(Math.abs(maxChargePower))) // + .setEssMaxDischargeEnergy(toEnergy(maxDischargePower)) // + .seMaxBuyFromGrid(toEnergy(context.maxChargePowerFromGrid())) // + .setProductions(stream(interpolateArray(predictionProduction)).map(v -> toEnergy(v)).toArray()) // + .setConsumptions(stream(interpolateArray(predictionConsumption)).map(v -> toEnergy(v)).toArray()) // + .setPrices(interpolateDoubleArray(prices.asArray())) // + .setStates(context.controlMode().states) // + .setExistingSchedule(existingSchedule) // + .build(); + } + + /** + * Postprocesses production prediction; makes sure length is at least the same + * as consumption prediction - filling up with zeroes. + * + * @param prediction the production prediction + * @param minLength the min length (= consumption prediction length) + * @return new production prediction + */ + protected static Integer[] generateProductionPrediction(Integer[] prediction, int minLength) { + if (prediction.length >= minLength) { + return prediction; + } + return IntStream.range(0, minLength) // + .mapToObj(i -> i > prediction.length - 1 ? 0 : prediction[i]) // + .toArray(Integer[]::new); + } + + protected static Integer[] joinConsumptionPredictions(int splitAfterIndex, Integer[] totalConsumption, + Integer[] unmanagedConsumption) { + return Streams.concat(// + stream(totalConsumption) // + .limit(splitAfterIndex), // + stream(unmanagedConsumption) // + .skip(splitAfterIndex)) // + .toArray(Integer[]::new); + } + + protected static boolean paramsAreValid(ParamsV1 p) { + if (p.optimizePeriods().isEmpty()) { + // No periods are available + LOG.warn("No periods are available"); + return false; + } + if (p.optimizePeriods().stream() // + .allMatch(pp -> pp.production() == 0 && pp.consumption() == 0)) { + // Production and Consumption predictions are all zero + LOG.warn("Production and Consumption predictions are all zero"); + return false; + } + if (p.optimizePeriods().stream() // + .mapToDouble(ParamsV1.OptimizePeriod::price) // + .distinct() // + .count() <= 1) { + // Prices are all the same + LOG.info("Prices are all the same"); + return false; + } + + return true; + } + + /** + * Returns the amount of energy that is not available for scheduling because of + * a configured minimum SoC. + * + * @param context the {@link Context} + * @param essCapacity net {@link SymmetricEss.ChannelId#CAPACITY} + * @return the value in [Wh] + */ + protected static int getEssMinSocEnergy(ContextV1 context, int essCapacity) { + return essCapacity /* [Wh] */ / 100 // + * getEssMinSocPercentage(// + context.ctrlLimitTotalDischarges(), // + context.ctrlEmergencyCapacityReserves()); + } + + /** + * Interpolate an Array of {@link Double}s. + * + *

      + * Replaces nulls with previous value. If first entry is null, it is set to + * first available value. If all values are null, all are set to 0. + * + * @param values the values + * @return values without nulls + */ + protected static double[] interpolateDoubleArray(Double[] values) { + var firstNonNull = stream(values) // + .filter(Objects::nonNull) // + .findFirst(); + var lastNonNullIndex = IntStream.range(0, values.length) // + .filter(i -> values[i] != null) // + .reduce((first, second) -> second); + if (lastNonNullIndex.isEmpty()) { + return new double[0]; + } + var result = new double[lastNonNullIndex.getAsInt() + 1]; + if (firstNonNull.isEmpty()) { + // all null + return result; + } + double last = firstNonNull.get(); + for (var i = 0; i < result.length; i++) { + double value = orElse(values[i], last); + result[i] = last = value; + } + return result; + } + + /** + * Utilizes the previous three hours' data and computes the next 21 hours data + * from the {@link OptimizerV1} provided, then concatenates them to generate a + * 24-hour {@link GetScheduleResponse}. + * + * @param optimizer the {@link OptimizerV1} + * @param requestId the JSON-RPC request-id + * @param timedata the{@link Timedata} + * @param timeOfUseTariff the {@link TimeOfUseTariff} + * @param componentId the Component-ID + * @param now the current {@link ZonedDateTime} (will get rounded + * down to 15 minutes) + * @return the {@link GetScheduleResponse} + */ + public static GetScheduleResponse handleGetScheduleRequest(OptimizerV1 optimizer, UUID requestId, Timedata timedata, + TimeOfUseTariff timeOfUseTariff, String componentId, ZonedDateTime now) { + final var b = ImmutableList.builder(); + now = roundDownToQuarter(now); + final var fromTime = now.minusHours(3); + + final var params = optimizer.getParams(); + if (params != null) { + // Process last three hours of historic data + final var channelQuarterlyPrices = new ChannelAddress(componentId, "QuarterlyPrices"); + final var channelStateMachine = new ChannelAddress(componentId, "StateMachine"); + try { + var queryResult = timedata.queryHistoricData(null, fromTime, now, // + Set.of(channelQuarterlyPrices, channelStateMachine, // + SUM_GRID, SUM_PRODUCTION, SUM_CONSUMPTION, SUM_ESS_DISCHARGE_POWER, SUM_ESS_SOC), + new Resolution(15, ChronoUnit.MINUTES)); + ScheduleData.fromHistoricDataQuery(// + params.essTotalEnergy(), channelQuarterlyPrices, channelStateMachine, queryResult) // + .forEach(b::add); + } catch (Exception e) { + LOG.warn("Unable to read historic data: " + e.getMessage()); + } + } + + // Process future schedule + final var schedule = optimizer.getSchedule(); + optimizer.getSchedule().values().stream() // + .flatMap(ScheduleData::fromPeriod) // + .forEach(b::add); + + // Find 'toTime' of result + final ZonedDateTime toTime; + if (!schedule.isEmpty()) { + toTime = schedule.lastKey(); + } else { + var pricesPerQuarter = timeOfUseTariff.getPrices().pricePerQuarter; + if (!pricesPerQuarter.isEmpty()) { + toTime = pricesPerQuarter.lastKey(); + } else { + toTime = fromTime; + } + } + + return new GetScheduleResponse(requestId, fromTime, toTime, + new ScheduleDatas(params.essTotalEnergy(), b.build())); + } + + /** + * Post-Process a state of a Period during Simulation, i.e. replace with + * 'better' state with the same behaviour. + * + *

      + * NOTE: heavy computation is ok here, because this method is called only at the + * end with the best Schedule. + * + * @param state the initial state + * @param efBalancing the {@link EnergyFlowV1} as it would be in + * {@link StateMachine#BALANCING} + * @param efDelayDischarge the {@link EnergyFlowV1} as it would be in + * {@link StateMachine#DELAY_DISCHARGE} + * @param efChargeGrid the {@link EnergyFlowV1} as it would be in + * {@link StateMachine#CHARGE_GRID} + * @return the new state + */ + public static StateMachine postprocessSimulatorState(StateMachine state, EnergyFlowV1 efBalancing, + EnergyFlowV1 efDelayDischarge, EnergyFlowV1 efChargeGrid) { + if (state == CHARGE_GRID) { + // CHARGE_GRID,... + if (efChargeGrid.ess() >= efDelayDischarge.ess()) { + // but battery charge/discharge is the same as DELAY_DISCHARGE + state = DELAY_DISCHARGE; + } + } + + if (state == DELAY_DISCHARGE) { + // DELAY_DISCHARGE,... + if (efDelayDischarge.ess() >= efBalancing.ess()) { + // but battery charge/discharge is the same as BALANCING + state = BALANCING; + } + } + + return state; + } + + /** + * Converts power [W] to energy [Wh/15 min]. + * + * @param power the power value + * @return the energy value + */ + public static int toEnergy(int power) { + return power / PERIODS_PER_HOUR; + } + + /** + * Converts energy [Wh/15 min] to power [W]. + * + * @param energy the energy value + * @return the power value + */ + public static Integer toPower(Integer energy) { + return multiply(energy, PERIODS_PER_HOUR); + } + + /** + * Prints the Schedule to System.out. + * + *

      + * NOTE: The output format is suitable as input for "RunOptimizerFromLogApp". + * This is useful to re-run a simulation. + * + * @param params the {@link ParamsV1} + * @param periods the map of {@link Period}s + */ + protected static void logSchedule(ParamsV1 params, ImmutableSortedMap periods) { + System.out.println("OPTIMIZER " + params.toLogString()); + System.out.println(ScheduleDatas.fromSchedule(params.essTotalEnergy(), periods).toLogString("OPTIMIZER ")); + } + + /** + * Updates the active Schedule with a new Schedule. + * + *

      + *

        + *
      • Period of the currently active Quarter is never changed + *
      • Old Periods are removed from the Schedule + *
      • Remaining Schedules are updated from new Schedule + *
      + * + * @param now the current {@link ZonedDateTime} + * @param schedule the active Schedule + * @param newSchedule the new Schedule + */ + public static void updateSchedule(ZonedDateTime now, TreeMap schedule, + ImmutableSortedMap newSchedule) { + var thisQuarter = roundDownToQuarter(now); + var current = schedule.get(thisQuarter); + schedule.clear(); + schedule.putAll(newSchedule); + if (current != null) { + schedule.put(thisQuarter, current); + } + } +} diff --git a/io.openems.edge.energy/test/io/openems/edge/energy/EnergySchedulerImplTest.java b/io.openems.edge.energy/test/io/openems/edge/energy/EnergySchedulerImplTest.java index aa2a426c22c..c5598a34647 100644 --- a/io.openems.edge.energy/test/io/openems/edge/energy/EnergySchedulerImplTest.java +++ b/io.openems.edge.energy/test/io/openems/edge/energy/EnergySchedulerImplTest.java @@ -2,19 +2,21 @@ import static io.openems.common.utils.DateUtils.roundDownToQuarter; import static io.openems.edge.energy.LogVerbosity.TRACE; -import static io.openems.edge.energy.TestData.CONSUMPTION_PREDICTION_QUARTERLY; -import static io.openems.edge.energy.TestData.HOURLY_PRICES_SUMMER; -import static io.openems.edge.energy.TestData.PRODUCTION_PREDICTION_QUARTERLY; -import static io.openems.edge.energy.optimizer.Utils.SUM_CONSUMPTION; -import static io.openems.edge.energy.optimizer.Utils.SUM_PRODUCTION; +import static io.openems.edge.energy.api.EnergyConstants.SUM_PRODUCTION; +import static io.openems.edge.energy.api.EnergyConstants.SUM_UNMANAGED_CONSUMPTION; +import static io.openems.edge.energy.api.EnergyUtils.toEnergy; +import static io.openems.edge.energy.api.Version.V2_ENERGY_SCHEDULABLE; +import static io.openems.edge.energy.optimizer.TestData.CONSUMPTION_PREDICTION_QUARTERLY; +import static io.openems.edge.energy.optimizer.TestData.HOURLY_PRICES_SUMMER; +import static io.openems.edge.energy.optimizer.TestData.PRODUCTION_PREDICTION_QUARTERLY; +import static io.openems.edge.ess.power.api.Relationship.GREATER_OR_EQUALS; import static java.time.temporal.ChronoUnit.DAYS; import java.time.Clock; import java.time.Instant; +import java.time.LocalTime; import java.time.ZoneOffset; import java.time.ZonedDateTime; -import java.util.List; -import java.util.function.Supplier; import org.junit.Test; @@ -24,12 +26,19 @@ import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.common.test.DummyConfigurationAdmin; +import io.openems.edge.controller.ess.emergencycapacityreserve.ControllerEssEmergencyCapacityReserveImpl; +import io.openems.edge.controller.ess.fixactivepower.ControllerEssFixActivePowerImpl; +import io.openems.edge.controller.ess.gridoptimizedcharge.ControllerEssGridOptimizedChargeImpl; +import io.openems.edge.controller.ess.limittotaldischarge.ControllerEssLimitTotalDischargeImpl; +import io.openems.edge.controller.ess.timeofusetariff.ControlMode; import io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImpl; -import io.openems.edge.energy.optimizer.GlobalContext; +import io.openems.edge.energy.api.test.DummyEnergySchedulable; import io.openems.edge.energy.optimizer.Optimizer; +import io.openems.edge.ess.test.DummyManagedSymmetricEss; import io.openems.edge.predictor.api.prediction.Prediction; import io.openems.edge.predictor.api.test.DummyPredictor; import io.openems.edge.predictor.api.test.DummyPredictorManager; +import io.openems.edge.scheduler.api.test.DummyScheduler; import io.openems.edge.timedata.test.DummyTimedata; import io.openems.edge.timeofusetariff.test.DummyTimeOfUseTariffProvider; @@ -50,30 +59,60 @@ public void test() throws Exception { * @throws Exception on error */ public static EnergySchedulerImpl create(Clock clock) throws Exception { - var now = roundDownToQuarter(ZonedDateTime.now(clock)); + final var now = roundDownToQuarter(ZonedDateTime.now(clock)); final var midnight = now.truncatedTo(DAYS); - var componentManager = new DummyComponentManager(clock); - var sum = new DummySum(); - var predictor0 = new DummyPredictor("predictor0", componentManager, + final var componentManager = new DummyComponentManager(clock); + final var sum = new DummySum() // + .withEssCapacity(10000) // + .withEssSoc(50); + final var ess = new DummyManagedSymmetricEss("ess0"); + final var predictor0 = new DummyPredictor("predictor0", componentManager, Prediction.from(sum, SUM_PRODUCTION, midnight, PRODUCTION_PREDICTION_QUARTERLY), SUM_PRODUCTION); - var predictor1 = new DummyPredictor("predictor0", componentManager, - Prediction.from(sum, SUM_CONSUMPTION, midnight, CONSUMPTION_PREDICTION_QUARTERLY), SUM_CONSUMPTION); - var timeOfUseTariff = DummyTimeOfUseTariffProvider.fromHourlyPrices(clock, HOURLY_PRICES_SUMMER); - var ctrl = new TimeOfUseTariffControllerImpl(); // this is not fully activated; config is null + final var predictor1 = new DummyPredictor("predictor1", componentManager, + Prediction.from(sum, SUM_UNMANAGED_CONSUMPTION, midnight, CONSUMPTION_PREDICTION_QUARTERLY), + SUM_UNMANAGED_CONSUMPTION); + final var timeOfUseTariff = DummyTimeOfUseTariffProvider.fromHourlyPrices(clock, HOURLY_PRICES_SUMMER); - var sut = new EnergySchedulerImpl(); + final var sut = new EnergySchedulerImpl(); new ComponentTest(sut) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("componentManager", componentManager) // .addReference("predictorManager", new DummyPredictorManager(predictor0, predictor1)) // .addReference("timedata", new DummyTimedata("timedata0")) // .addReference("timeOfUseTariff", timeOfUseTariff) // - .addReference("schedulables", List.of(ctrl)) // + .addReference("scheduler", new DummyScheduler("scheduler0")) // + .addReference("addSchedulable", + new DummyEnergySchedulable("ctrlEmergencyCapacityReserve0", + ControllerEssEmergencyCapacityReserveImpl.buildEnergyScheduleHandler(// + () -> /* reserveSoc */ 10))) // + .addReference("addSchedulable", + new DummyEnergySchedulable("ctrlLimitTotalDischarge0", + ControllerEssLimitTotalDischargeImpl.buildEnergyScheduleHandler(// + () -> /* minSoc */ 12))) // + .addReference("addSchedulable", + new DummyEnergySchedulable("ctrlFixActivePower0", + ControllerEssFixActivePowerImpl.buildEnergyScheduleHandler(// + () -> new ControllerEssFixActivePowerImpl.EshContext( + io.openems.edge.controller.ess.fixactivepower.Mode.MANUAL_ON, // + toEnergy(-1000), GREATER_OR_EQUALS)))) // + .addReference("addSchedulable", + new DummyEnergySchedulable("ctrlGridOptimizedCharge0", + ControllerEssGridOptimizedChargeImpl.buildEnergyScheduleHandler(// + () -> io.openems.edge.controller.ess.gridoptimizedcharge.Mode.MANUAL, // + () -> LocalTime.of(10, 00)))) // + .addReference("addSchedulable", + new DummyEnergySchedulable("ctrlEssTimeOfUseTariff0", + TimeOfUseTariffControllerImpl.buildEnergyScheduleHandler(// + () -> ess, // + () -> ControlMode.CHARGE_CONSUMPTION, // + () -> /* maxChargePowerFromGrid */ 20_000, // + () -> /* limitChargePowerFor14aEnWG */ false))) .addReference("sum", sum) // .activate(MyConfig.create() // - .setId("ctrl0") // + .setId("_energy") // .setEnabled(false) // .setLogVerbosity(TRACE) // + .setVersion(V2_ENERGY_SCHEDULABLE) // .build()) // .next(new TestCase()); return sut; @@ -92,31 +131,4 @@ public static Optimizer getOptimizer(EnergySchedulerImpl energyScheduler) throws return (Optimizer) field.get(energyScheduler); } - /** - * Calls the 'createParams()' method in the {@link Optimizer} via Java - * Reflection. - * - * @param optimizer the {@link Optimizer} - * @throws Exception on error - */ - public static void callCreateParams(Optimizer optimizer) throws Exception { - var method = Optimizer.class.getDeclaredMethod("createParams"); - method.setAccessible(true); - method.invoke(optimizer); - } - - /** - * Gets the {@link GlobalContext} via Java Reflection. - * - * @param energyScheduler the {@link EnergySchedulerImpl} - * @return the object - * @throws Exception on error - */ - @SuppressWarnings("unchecked") - public static GlobalContext getGlobalContext(EnergySchedulerImpl energyScheduler) throws Exception { - var optimizer = getOptimizer(energyScheduler); - var field = Optimizer.class.getDeclaredField("globalContext"); - field.setAccessible(true); - return ((Supplier) field.get(optimizer)).get(); - } } diff --git a/io.openems.edge.energy/test/io/openems/edge/energy/MyConfig.java b/io.openems.edge.energy/test/io/openems/edge/energy/MyConfig.java index 1fbea17e506..e85ab323e37 100644 --- a/io.openems.edge.energy/test/io/openems/edge/energy/MyConfig.java +++ b/io.openems.edge.energy/test/io/openems/edge/energy/MyConfig.java @@ -1,14 +1,16 @@ package io.openems.edge.energy; import io.openems.common.test.AbstractComponentConfig; +import io.openems.edge.energy.api.Version; @SuppressWarnings("all") public class MyConfig extends AbstractComponentConfig implements Config { - protected static class Builder { + public static class Builder { private String id; private boolean enabled; private LogVerbosity logVerbosity; + private Version version; private Builder() { } @@ -28,6 +30,11 @@ public Builder setLogVerbosity(LogVerbosity logVerbosity) { return this; } + public Builder setVersion(Version version) { + this.version = version; + return this; + } + public MyConfig build() { return new MyConfig(this); } @@ -58,4 +65,9 @@ public boolean enabled() { public LogVerbosity logVerbosity() { return this.builder.logVerbosity; } + + @Override + public Version version() { + return this.builder.version; + } } \ No newline at end of file diff --git a/io.openems.edge.energy/test/io/openems/edge/energy/api/simulation/EnergyFlowTest.java b/io.openems.edge.energy/test/io/openems/edge/energy/api/simulation/EnergyFlowTest.java new file mode 100644 index 00000000000..b5eb2f38034 --- /dev/null +++ b/io.openems.edge.energy/test/io/openems/edge/energy/api/simulation/EnergyFlowTest.java @@ -0,0 +1,468 @@ +package io.openems.edge.energy.api.simulation; + +import static io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImpl.applyBalancing; +import static io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImpl.applyChargeGrid; +import static io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImpl.applyDelayDischarge; +import static io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImpl.applyDischargeGrid; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class EnergyFlowTest { + + /* + * BALANCING + */ + + @Test + public void testBalancingAndCharge() { + var m = new EnergyFlow.Model(// + /* production */ 2500, // + /* consumption */ 500, // + /* essMaxCharge */ 5000, // + /* essMaxDischarge */ 0, // + /* gridMaxBuy */ 4000, // + /* gridMaxSell */ 10000); + applyBalancing(m); + var ef = m.solve(); + + assertEquals(500, ef.getCons()); + assertEquals(500, ef.getProdToCons()); + + assertEquals(2500, ef.getProd()); + assertEquals(500, ef.getProdToCons()); + assertEquals(2000, ef.getProdToEss()); + + assertEquals(-2000, ef.getEss()); + assertEquals(2000, ef.getProdToEss()); + + assertEquals(0, ef.getGrid()); + assertEquals(0, ef.getProdToGrid()); + assertEquals(0, ef.getGridToCons()); + assertEquals(0, ef.getEssToCons()); + assertEquals(0, ef.getGridToEss()); + } + + @Test + public void testBalancingAndChargeFull() { + var m = new EnergyFlow.Model(// + /* production */ 3000, // + /* consumption */ 100, // + /* essMaxCharge */ 2400, // + /* essMaxDischarge */ 0, // + /* gridMaxBuy */ 4000, // + /* gridMaxSell */ 10000); + applyBalancing(m); + var ef = m.solve(); + + assertEquals(100, ef.getCons()); + assertEquals(100, ef.getProdToCons()); + + assertEquals(3000, ef.getProd()); + assertEquals(100, ef.getProdToCons()); + assertEquals(2400, ef.getProdToEss()); + assertEquals(500, ef.getProdToGrid()); + + assertEquals(-2400, ef.getEss()); + assertEquals(2400, ef.getProdToEss()); + + assertEquals(-500, ef.getGrid()); + assertEquals(500, ef.getProdToGrid()); + + assertEquals(0, ef.getGridToCons()); + assertEquals(0, ef.getEssToCons()); + assertEquals(0, ef.getGridToEss()); + } + + @Test + public void testBalancingAndDischarge() { + var m = new EnergyFlow.Model(// + /* production */ 500, // + /* consumption */ 2500, // + /* essMaxCharge */ 5000, // + /* essMaxDischarge */ 5000, // + /* gridMaxBuy */ 4000, // + /* gridMaxSell */ 10000); + applyBalancing(m); + var ef = m.solve(); + + assertEquals(2500, ef.getCons()); + assertEquals(2000, ef.getEssToCons()); + assertEquals(500, ef.getProdToCons()); + + assertEquals(500, ef.getProd()); + assertEquals(500, ef.getProdToCons()); + + assertEquals(2000, ef.getEss()); + assertEquals(2000, ef.getEssToCons()); + + assertEquals(0, ef.getGrid()); + assertEquals(0, ef.getProdToGrid()); + assertEquals(0, ef.getProdToEss()); + assertEquals(0, ef.getGridToCons()); + assertEquals(0, ef.getGridToEss()); + } + + @Test + public void testBalancingAndDischargeEmpty() { + var m = new EnergyFlow.Model(// + /* production */ 500, // + /* consumption */ 4500, // + /* essMaxCharge */ 5000, // + /* essMaxDischarge */ 1800, // + /* gridMaxBuy */ 4000, // + /* gridMaxSell */ 10000); + applyBalancing(m); + var ef = m.solve(); + + assertEquals(4500, ef.getCons()); + assertEquals(2200, ef.getGridToCons()); + assertEquals(1800, ef.getEssToCons()); + + assertEquals(500, ef.getProd()); + assertEquals(500, ef.getProdToCons()); + + assertEquals(1800, ef.getEss()); + assertEquals(1800, ef.getEssToCons()); + + assertEquals(2200, ef.getGrid()); + assertEquals(2200, ef.getGridToCons()); + + assertEquals(0, ef.getProdToGrid()); + assertEquals(0, ef.getProdToEss()); + assertEquals(0, ef.getGridToEss()); + } + + @Test + public void testBalancingAndChargeMoreThanEssMaxEnergy() { + var m = new EnergyFlow.Model(// + /* production */ 2500, // + /* consumption */ 500, // + /* essMaxCharge */ 900, // + /* essMaxDischarge */ 900, // + /* gridMaxBuy */ 4000, // + /* gridMaxSell */ 10000); + applyBalancing(m); + var ef = m.solve(); + + assertEquals(500, ef.getCons()); + assertEquals(500, ef.getProdToCons()); + + assertEquals(2500, ef.getProd()); + assertEquals(500, ef.getProdToCons()); + assertEquals(900, ef.getProdToEss()); + assertEquals(1100, ef.getProdToGrid()); + + assertEquals(-900, ef.getEss()); + assertEquals(900, ef.getProdToEss()); + + assertEquals(-1100, ef.getGrid()); + assertEquals(1100, ef.getProdToGrid()); + + assertEquals(0, ef.getGridToCons()); + assertEquals(0, ef.getEssToCons()); + assertEquals(0, ef.getGridToEss()); + } + + @Test + public void testBalancingAndDischargeAboveEssMaxEnergy() { + var m = new EnergyFlow.Model(// + /* production */ 500, // + /* consumption */ 2500, // + /* essMaxCharge */ 900, // + /* essMaxDischarge */ 900, // + /* gridMaxBuy */ 4000, // + /* gridMaxSell */ 10000); + applyBalancing(m); + var ef = m.solve(); + + assertEquals(2500, ef.getCons()); + assertEquals(900, ef.getEssToCons()); + assertEquals(1100, ef.getGridToCons()); + assertEquals(500, ef.getProdToCons()); + + assertEquals(500, ef.getProd()); + assertEquals(500, ef.getProdToCons()); + + assertEquals(900, ef.getEss()); + assertEquals(900, ef.getEssToCons()); + + assertEquals(1100, ef.getGrid()); + assertEquals(1100, ef.getGridToCons()); + + assertEquals(0, ef.getProdToGrid()); + assertEquals(0, ef.getProdToEss()); + assertEquals(0, ef.getGridToEss()); + } + + @Test + public void testBalancingAndAboveGridMaxEnergy() { + var m = new EnergyFlow.Model(// + /* production */ 1000, // + /* consumption */ 4900, // + /* essMaxCharge */ 1600, // + /* essMaxDischarge */ 2000, // + /* gridMaxBuy */ 4000, // + /* gridMaxSell */ 10000); + applyBalancing(m); + var ef = m.solve(); + + assertEquals(4900, ef.getCons()); + assertEquals(2000, ef.getEssToCons()); + assertEquals(1900, ef.getGridToCons()); + assertEquals(1000, ef.getProdToCons()); + + assertEquals(1000, ef.getProd()); + assertEquals(1000, ef.getProdToCons()); + + assertEquals(2000, ef.getEss()); + assertEquals(2000, ef.getEssToCons()); + + assertEquals(1900, ef.getGrid()); + assertEquals(1900, ef.getGridToCons()); + + assertEquals(0, ef.getProdToGrid()); + assertEquals(0, ef.getProdToEss()); + assertEquals(0, ef.getGridToEss()); + } + + /* + * DELAY DISCHARGE + */ + + @Test + public void testDelayDischargeAndCharge() { + var m = new EnergyFlow.Model(// + /* production */ 2500, // + /* consumption */ 500, // + /* essMaxCharge */ 5000, // + /* essMaxDischarge */ 0, // + /* gridMaxBuy */ 4000, // + /* gridMaxSell */ 10000); + applyDelayDischarge(m); + var ef = m.solve(); + + assertEquals(500, ef.getCons()); + assertEquals(500, ef.getProdToCons()); + + assertEquals(2500, ef.getProd()); + assertEquals(2000, ef.getProdToEss()); + assertEquals(500, ef.getProdToCons()); + + assertEquals(-2000, ef.getEss()); + assertEquals(2000, ef.getProdToEss()); + + assertEquals(0, ef.getGrid()); + assertEquals(0, ef.getProdToGrid()); + assertEquals(0, ef.getGridToCons()); + assertEquals(0, ef.getEssToCons()); + assertEquals(0, ef.getGridToEss()); + } + + @Test + public void testDelayDischargeAndChargeFull() { + var m = new EnergyFlow.Model(// + /* production */ 3000, // + /* consumption */ 100, // + /* essMaxCharge */ 2400, // + /* essMaxDischarge */ 5000, // + /* gridMaxBuy */ 4000, // + /* gridMaxSell */ 10000); + applyDelayDischarge(m); + var ef = m.solve(); + + assertEquals(100, ef.getCons()); + assertEquals(100, ef.getProdToCons()); + + assertEquals(3000, ef.getProd()); + assertEquals(100, ef.getProdToCons()); + assertEquals(500, ef.getProdToGrid()); + assertEquals(2400, ef.getProdToEss()); + + assertEquals(-2400, ef.getEss()); + assertEquals(2400, ef.getProdToEss()); + + assertEquals(-500, ef.getGrid()); + assertEquals(500, ef.getProdToGrid()); + + assertEquals(0, ef.getGridToCons()); + assertEquals(0, ef.getEssToCons()); + assertEquals(0, ef.getGridToEss()); + } + + @Test + public void testDelayDischargeAndWouldDischarge() { + var m = new EnergyFlow.Model(// + /* production */ 500, // + /* consumption */ 2500, // + /* essMaxCharge */ 5000, // + /* essMaxDischarge */ 5000, // + /* gridMaxBuy */ 4000, // + /* gridMaxSell */ 10000); + applyDelayDischarge(m); + var ef = m.solve(); + + assertEquals(2500, ef.getCons()); + assertEquals(500, ef.getProdToCons()); + assertEquals(2000, ef.getGridToCons()); + + assertEquals(500, ef.getProd()); + assertEquals(500, ef.getProdToCons()); + + assertEquals(2000, ef.getGrid()); + assertEquals(2000, ef.getGridToCons()); + + assertEquals(0, ef.getEss()); + assertEquals(0, ef.getProdToGrid()); + assertEquals(0, ef.getProdToEss()); + assertEquals(0, ef.getEssToCons()); + assertEquals(0, ef.getGridToEss()); + } + + /* + * CHARGE GRID + */ + + @Test + public void testChargeGridAndCharge() { + var m = new EnergyFlow.Model(// + /* production */ 2500, // + /* consumption */ 500, // + /* essMaxCharge */ 5000, // + /* essMaxDischarge */ 0, // + /* gridMaxBuy */ 4000, // + /* gridMaxSell */ 10000); + applyChargeGrid(m, 2500); + var ef = m.solve(); + + assertEquals(500, ef.getCons()); + assertEquals(500, ef.getProdToCons()); + + assertEquals(2500, ef.getProd()); + assertEquals(2000, ef.getProdToEss()); + assertEquals(500, ef.getProdToCons()); + + assertEquals(-4500, ef.getEss()); + assertEquals(2500, ef.getGridToEss()); + assertEquals(2000, ef.getProdToEss()); + + assertEquals(2500, ef.getGrid()); + assertEquals(2500, ef.getGridToEss()); + + assertEquals(0, ef.getProdToGrid()); + assertEquals(0, ef.getGridToCons()); + assertEquals(0, ef.getEssToCons()); + } + + @Test + public void testChargeGridAndChargeFull() { + var m = new EnergyFlow.Model(// + /* production */ 3000, // + /* consumption */ 100, // + /* essMaxCharge */ 3400, // + /* essMaxDischarge */ 5000, // + /* gridMaxBuy */ 4000, // + /* gridMaxSell */ 10000); + applyChargeGrid(m, 2500); + var ef = m.solve(); + + assertEquals(100, ef.getCons()); + assertEquals(100, ef.getProdToCons()); + + assertEquals(3000, ef.getProd()); + assertEquals(100, ef.getProdToCons()); + assertEquals(2900, ef.getProdToEss()); + + assertEquals(-3400, ef.getEss()); + assertEquals(500, ef.getGridToEss()); + assertEquals(2900, ef.getProdToEss()); + + assertEquals(500, ef.getGrid()); + assertEquals(500, ef.getGridToEss()); + + assertEquals(0, ef.getProdToGrid()); + assertEquals(0, ef.getGridToCons()); + assertEquals(0, ef.getEssToCons()); + } + + @Test + public void testChargeGridAndAboveGridMaxEnergy() { + var m = new EnergyFlow.Model(// + /* production */ 1000, // + /* consumption */ 2000, // + /* essMaxCharge */ 5000, // + /* essMaxDischarge */ 5000, // + /* gridMaxBuy */ 1600, // + /* gridMaxSell */ 10000); + applyChargeGrid(m, 2500); + var ef = m.solve(); + + assertEquals(2000, ef.getCons()); + assertEquals(1000, ef.getProdToCons()); + assertEquals(1000, ef.getGridToCons()); + + assertEquals(1000, ef.getProd()); + assertEquals(1000, ef.getGridToCons()); + + assertEquals(-600, ef.getEss()); + assertEquals(600, ef.getGridToEss()); + + assertEquals(1600, ef.getGrid()); + assertEquals(1000, ef.getGridToCons()); + assertEquals(600, ef.getGridToEss()); + + assertEquals(0, ef.getProdToGrid()); + assertEquals(0, ef.getProdToEss()); + assertEquals(0, ef.getEssToCons()); + } + + /* + * DISCHARGE GRID - just for completeness + */ + + @Test + public void testDischargeGridAndCharge() { + var m = new EnergyFlow.Model(// + /* production */ 2500, // + /* consumption */ 500, // + /* essMaxCharge */ 5000, // + /* essMaxDischarge */ 5000, // + /* gridMaxBuy */ 1600, // + /* gridMaxSell */ 10000); + applyDischargeGrid(m, 2500); + var ef = m.solve(); + + assertEquals(500, ef.getCons()); + assertEquals(500, ef.getProdToCons()); + + assertEquals(2500, ef.getProd()); + assertEquals(500, ef.getProdToCons()); + assertEquals(2000, ef.getProdToGrid()); + + assertEquals(2500, ef.getEss()); + assertEquals(-2500, ef.getGridToEss()); + + assertEquals(-4500, ef.getGrid()); + assertEquals(2000, ef.getProdToGrid()); + assertEquals(-2500, ef.getGridToEss()); + + assertEquals(0, ef.getProdToEss()); + assertEquals(0, ef.getEssToCons()); + assertEquals(0, ef.getGridToCons()); + } + + @Test + public void testLog() { + // No actual test. Would have to mock Logger + var m = new EnergyFlow.Model(// + /* production */ 2500, // + /* consumption */ 500, // + /* essMaxCharge */ 5000, // + /* essMaxDischarge */ 0, // + /* gridMaxBuy */ 4000, // + /* gridMaxSell */ 10000); + applyBalancing(m); + m.logConstraints(); + m.logMinMaxValues(); + } +} diff --git a/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/OptimizerTest.java b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/OptimizerTest.java index 1ab693e4e03..6dc5d0c1c3a 100644 --- a/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/OptimizerTest.java +++ b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/OptimizerTest.java @@ -2,20 +2,74 @@ import static io.openems.edge.energy.EnergySchedulerImplTest.CLOCK; import static io.openems.edge.energy.EnergySchedulerImplTest.getOptimizer; -import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import org.junit.Test; +import io.openems.common.exceptions.OpenemsException; +import io.openems.common.function.ThrowingSupplier; +import io.openems.edge.controller.ess.timeofusetariff.StateMachine; import io.openems.edge.energy.EnergySchedulerImplTest; +import io.openems.edge.energy.LogVerbosity; +import io.openems.edge.energy.api.EnergyScheduleHandler; +import io.openems.edge.energy.api.simulation.GlobalSimulationsContext; public class OptimizerTest { @Test - public void testEmpty() throws Exception { - var sut = getOptimizer(EnergySchedulerImplTest.create(CLOCK)); - assertNull(sut.getParams()); - assertTrue(sut.getSchedule().isEmpty()); + public void test() throws Exception { + var sut = EnergySchedulerImplTest.create(CLOCK); + var optimizer = getOptimizer(sut); + assertEquals("No Schedule available|PerQuarter:UNDEFINED", optimizer.debugLog()); + + var gscSupplier = getGlobalSimulationContextSupplier(optimizer); + var simulator = new Simulator(gscSupplier.get()); + optimizer.runOnce(simulator); + + assertEquals("ScheduledPeriods:96|PerQuarter:UNDEFINED", optimizer.debugLog()); + + var sr = optimizer.getSimulationResult(); + assertEquals(1375977.5150000001, sr.cost(), 0.001); + assertEquals(96, sr.periods().size()); + + var ctrlEssTimeOfUseTariff0 = sr.schedules().entrySet().asList().get(0); + var p = ctrlEssTimeOfUseTariff0.getKey().getCurrentPeriod(); + assertEquals(StateMachine.CHARGE_GRID, p.state()); + } + + @Test + public void test2() { + var simulator = SimulatorTest.DUMMY_SIMULATOR; + var o = new Optimizer(// + () -> LogVerbosity.NONE, // + () -> simulator.gsc, // + null); + o.applyBestQuickSchedule(simulator); + + var schedule = ((EnergyScheduleHandler.WithDifferentStates) simulator.gsc.handlers().get(1)) + .getSchedule(); + + assertEquals(52, schedule.size()); + + assertTrue(schedule.values().stream() // + .allMatch(p -> p.state() == StateMachine.BALANCING)); + } + + /** + * Gets the {@link GlobalSimulationsContext} {@link ThrowingSupplier} via Java + * Reflection. + * + * @param optimizer the {@link Optimizer} + * @return the object + * @throws Exception on error + */ + @SuppressWarnings("unchecked") + public static ThrowingSupplier getGlobalSimulationContextSupplier( + Optimizer optimizer) throws Exception { + var field = Optimizer.class.getDeclaredField("gscSupplier"); + field.setAccessible(true); + return (ThrowingSupplier) field.get(optimizer); } } diff --git a/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/QuickSchedulesTest.java b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/QuickSchedulesTest.java new file mode 100644 index 00000000000..d9ad2be088d --- /dev/null +++ b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/QuickSchedulesTest.java @@ -0,0 +1,65 @@ +package io.openems.edge.energy.optimizer; + +import static io.openems.edge.energy.optimizer.QuickSchedules.fromExistingSimulationResult; +import static io.openems.edge.energy.optimizer.QuickSchedules.variationsFromExistingSimulationResult; +import static io.openems.edge.energy.optimizer.QuickSchedules.variationsOfAllStatesDefault; +import static io.openems.edge.energy.optimizer.SimulatorTest.ESH_TIME_OF_USE_TARIFF_CTRL; +import static org.junit.Assert.assertEquals; + +import java.time.ZoneId; +import java.time.ZonedDateTime; + +import org.junit.Test; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSortedMap; + +import io.openems.edge.energy.api.EnergyScheduleHandler; +import io.openems.edge.energy.api.EnergyScheduleHandler.WithDifferentStates.Period.Transition; + +public class QuickSchedulesTest { + + private static final ZonedDateTime TIME = ZonedDateTime.of(2000, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC")); + + @Test + public void testAllStatesDefault() { + final var simulator = SimulatorTest.DUMMY_SIMULATOR; + var gts = variationsOfAllStatesDefault(simulator.gsc).toList(); + assertEquals(6, gts.size()); + var gt = gts.get(0); + assertEquals(0, gt.get(0).get(1).allele().intValue()); + } + + @Test + public void testFromExistingSimulationResult() { + final var simulator = SimulatorTest.DUMMY_SIMULATOR; + final var previousResult = new SimulationResult(0., ImmutableMap.of(), // + ImmutableMap., ImmutableSortedMap>builder() // + .put(ESH_TIME_OF_USE_TARIFF_CTRL, ImmutableSortedMap.naturalOrder() // + .put(TIME.plusHours(0).plusMinutes(00), state(2)) // + .build()) // + .build()); + var gt = fromExistingSimulationResult(simulator.gsc, previousResult); + assertEquals(2, gt.get(0).get(0).allele().intValue()); + } + + @Test + public void testVariationsFromExistingSimulationResult() { + final var simulator = SimulatorTest.DUMMY_SIMULATOR; + final var previousResult = new SimulationResult(0., ImmutableMap.of(), // + ImmutableMap., ImmutableSortedMap>builder() // + .put(ESH_TIME_OF_USE_TARIFF_CTRL, ImmutableSortedMap.naturalOrder() // + .put(TIME.plusHours(0).plusMinutes(00), state(2)) // + .put(TIME.plusHours(0).plusMinutes(15), state(2)) // + .build()) // + .build()); + var gts = variationsFromExistingSimulationResult(simulator.gsc, previousResult).toList(); + assertEquals(6, gts.size()); + var gt = gts.get(0); + assertEquals(2, gt.get(0).get(1).allele().intValue()); + } + + protected static Transition state(int state) { + return new Transition(state, 0., null, 0); + } +} diff --git a/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/SimulationResultTest.java b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/SimulationResultTest.java new file mode 100644 index 00000000000..bb4f49f9cd3 --- /dev/null +++ b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/SimulationResultTest.java @@ -0,0 +1,56 @@ +package io.openems.edge.energy.optimizer; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; +import java.util.stream.IntStream; + +import org.junit.Test; + +import io.jenetics.Genotype; +import io.jenetics.IntegerChromosome; +import io.jenetics.IntegerGene; + +public class SimulationResultTest { + + @Test + public void test() { + final var simulator = SimulatorTest.DUMMY_SIMULATOR; + + var result = SimulationResult.fromQuarters(simulator.gsc, Genotype.of(// + // ESH1 (BALANCING, DELAY_DISCHARGE, CHARGE_GRID) + integerChromosomeOf(// + 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 1, 2), // + // ESH2 (FOO, BAR) + integerChromosomeOf(// + 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 1, 0))); + + assertEquals(1_126_154.844, result.cost(), 0.001); + } + + /** + * Creates a {@link IntegerChromosome} from the given values. + * + * @param values the int values + * @return the {@link IntegerChromosome} + */ + public static IntegerChromosome integerChromosomeOf(int... values) { + if (values.length == 0) { + return IntegerChromosome.of(); + } + var max = IntStream.of(values).max().getAsInt(); + return IntegerChromosome.of(Arrays.stream(values) // + .mapToObj(value -> IntegerGene.of(value, 0, max)) // + .toList()); + } +} diff --git a/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/SimulatorTest.java b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/SimulatorTest.java index 73cae4f79cb..06e1e98d859 100644 --- a/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/SimulatorTest.java +++ b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/SimulatorTest.java @@ -1,40 +1,56 @@ package io.openems.edge.energy.optimizer; -import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.BALANCING; -import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.CHARGE_GRID; -import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.DELAY_DISCHARGE; -import static io.openems.edge.energy.TestData.CONSUMPTION_888_20231106; -import static io.openems.edge.energy.TestData.PRICES_888_20231106; -import static io.openems.edge.energy.TestData.PRODUCTION_888_20231106; -import static io.openems.edge.energy.optimizer.Simulator.getBestSchedule; -import static io.openems.edge.energy.optimizer.Simulator.simulate; -import static io.openems.edge.energy.optimizer.Utils.interpolateArray; -import static io.openems.edge.energy.optimizer.Utils.toEnergy; -import static java.util.Arrays.stream; -import static org.junit.Assert.assertArrayEquals; +import static io.openems.edge.energy.api.EnergyUtils.socToEnergy; import static org.junit.Assert.assertEquals; -import java.time.ZoneId; -import java.time.ZonedDateTime; -import java.util.Arrays; import java.util.Random; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.DoubleStream; import org.junit.Before; import org.junit.Test; -import com.google.common.collect.ImmutableSortedMap; - +import io.jenetics.engine.Limits; import io.jenetics.util.RandomRegistry; import io.openems.edge.controller.ess.timeofusetariff.ControlMode; -import io.openems.edge.controller.ess.timeofusetariff.StateMachine; -import io.openems.edge.energy.optimizer.Simulator.Period; +import io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImpl; +import io.openems.edge.energy.api.EnergyScheduleHandler; +import io.openems.edge.energy.api.test.DummyGlobalSimulationsContext; +import io.openems.edge.ess.api.ManagedSymmetricEss; +import io.openems.edge.ess.test.DummyManagedSymmetricEss; public class SimulatorTest { - public static final ZonedDateTime TIME = ZonedDateTime.of(2000, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC")); + public static final EnergyScheduleHandler.WithOnlyOneState ESH0 = EnergyScheduleHandler.of(// + simContext -> simContext.ess().totalEnergy(), // + (simContext, period, energyFlow, ctrlContext) -> { + var minEnergy = socToEnergy(simContext.global.ess().totalEnergy(), 10 /* [%] */); + energyFlow.setEssMaxDischarge(Math.max(0, simContext.getEssInitial() - minEnergy)); + }); + + public static final ManagedSymmetricEss ESS = new DummyManagedSymmetricEss("ess0") // + .withMaxApparentPower(10_000) // + .withAllowedChargePower(8_000) // + .withAllowedDischargePower(8_000) // + .withCapacity(22_000); + public static final EnergyScheduleHandler.WithDifferentStates ESH_TIME_OF_USE_TARIFF_CTRL = TimeOfUseTariffControllerImpl + .buildEnergyScheduleHandler(// + () -> ESS, // + () -> ControlMode.CHARGE_CONSUMPTION, // + () -> 20_000 /* maxChargePowerFromGrid */, // + () -> false /* limitChargePowerFor14aEnWG */); + + private static enum Esh2State { + FOO, BAR; + } + + public static final EnergyScheduleHandler.WithDifferentStates ESH2 = EnergyScheduleHandler.of(// + Esh2State.BAR, // + () -> Esh2State.values(), // + simContext -> null, // + (simContext, period, energyFlow, ctrlContext, state) -> { + }); + + public static final Simulator DUMMY_SIMULATOR = new Simulator(// + DummyGlobalSimulationsContext.fromHandlers(ESH0, ESH_TIME_OF_USE_TARIFF_CTRL, ESH2)); @Before public void before() { @@ -43,164 +59,32 @@ public void before() { RandomRegistry.random(new Random(123)); } - private static Period simulatePeriod(StateMachine state, int production, int consumption, double price, - int essInitial) { - var result = new AtomicReference(); - var params = Params.create() // - .setTime(TIME) // - .setEssTotalEnergy(22000) // - .setEssMinSocEnergy(0) // - .setEssMaxSocEnergy(20000) // - .setEssInitialEnergy(essInitial) // - .setEssMaxChargeEnergy(3000 /* [Wh/15 Minutes] */) // - .setEssMaxDischargeEnergy(3000 /* [Wh/15 Minutes] */) // - .seMaxBuyFromGrid(4000 /* [Wh/15 Minutes] */) // - .setProductions(new int[] { production }) // - .setConsumptions(new int[] { consumption }) // - .setPrices(new double[] { price }) // - .setStates(new StateMachine[] { state }) // - .setExistingSchedule(ImmutableSortedMap.of()) // - .build(); - Simulator.simulatePeriod(params, params.optimizePeriods().get(0), state, new AtomicInteger(essInitial), - result::set); - - return result.get(); - } - - private static void assertPeriod(String message, Period period, int essChargeDischarge, int grid, double cost) { - assertEquals(period.state() + "-essChargeDischarge: " + message, essChargeDischarge, period.ef().ess()); - assertEquals(period.state() + "-grid: " + message, grid, period.ef().grid()); - } - - @Test - public void testCalculatePeriodCostBalancing() { - assertPeriod("Consumption > Production; SoC ok", // - simulatePeriod(BALANCING, 200, 300, 0.1, 10000), // - 100, 0, 0); - assertPeriod("Consumption > Production; discharge limited by essMaxEnergyPerPeriod", // - simulatePeriod(BALANCING, 1000, 5000, 0.1, 10000), // - 3000, 1000, 100); - assertPeriod("Consumption > Production; discharge limited by essMinSocEnergy", // - simulatePeriod(BALANCING, 1000, 5000, 0.1, 2500), // - 2500, 1500, 150); - - assertPeriod("Production > Consumption; SoC ok", // - simulatePeriod(BALANCING, 300, 200, 0.1, 10000), // - -100, 0, 0); - assertPeriod("Production > Consumption; charge limited by essMaxEnergyPerPeriod", // - simulatePeriod(BALANCING, 5000, 1000, 0.1, 10000), // - -3000, -1000, 0); - assertPeriod("Production > Consumption; charge limited by essTotalEnergy", // - simulatePeriod(BALANCING, 5000, 1000, 0.1, 19500), // - -2500, -1500, 0); - } - - @Test - public void testCalculatePeriodCostDelayDischarge() { - assertPeriod("Consumption > Production", // - simulatePeriod(DELAY_DISCHARGE, 200, 300, 0.1, 10000), // - 0, 100, 10); - - assertPeriod("Production > Consumption; SoC ok", // - simulatePeriod(DELAY_DISCHARGE, 300, 200, 0.1, 10000), // - -100, 0, 0); - assertPeriod("Production > Consumption; charge limited by essMaxEnergyPerPeriod", // - simulatePeriod(DELAY_DISCHARGE, 5000, 1000, 0.1, 10000), // - -3000, -1000, 0); - assertPeriod("Production > Consumption; charge limited by essTotalEnergy", // - simulatePeriod(DELAY_DISCHARGE, 5000, 1000, 0.1, 19500), // - -2500, -1500, 0); - } - - @Test - public void testCalculatePeriodCostChargeGrid() { - assertPeriod("Consumption > Production", // - simulatePeriod(CHARGE_GRID, 200, 300, 0.1, 10000), // - -842, 942 /* 842 + 100 */, 302.5); - - assertPeriod("Consumption > Production; charge limited by maxBuyFromGrid", // - simulatePeriod(CHARGE_GRID, 0, 4500, 0.1, 10000), // - 500, 4000, 450.12); - - assertPeriod("Production > Consumption", // - simulatePeriod(CHARGE_GRID, 300, 200, 0.1, 10000), // - -2600 /* 2500 + 100 */, 2500, 292.5); - - assertPeriod("Production > Consumption; charge limited by essMaxEnergyPerPeriod", // - simulatePeriod(CHARGE_GRID, 3000, 900, 0.1, 10000), // - -3000, 900, 105.3); - - assertPeriod("Production > Consumption", // - simulatePeriod(CHARGE_GRID, 2000, 1700, 0.1, 10000), // - -2800, 2500, 292.5); - - assertPeriod("Production > Consumption; battery nearly full", // - simulatePeriod(CHARGE_GRID, 3000, 100, 0.1, 19600), // - -400 /* 400 from PV; then full */, -2500 /* sell-to-grid */, 292.5); - } - - @Test - public void testGetFirstSchedule0() { - var existingSchedule = new StateMachine[] { CHARGE_GRID, DELAY_DISCHARGE, CHARGE_GRID, BALANCING }; - - var p = Params.create() // - .setTime(TIME) // - .setEssTotalEnergy(22000) // - .setEssMinSocEnergy(0) // - .setEssMaxSocEnergy(22000) // - .setEssInitialEnergy((int) (22000 * 0.1)) // - .setEssMaxChargeEnergy(toEnergy(10000)) // - .setEssMaxDischargeEnergy(toEnergy(10000)) // - .seMaxBuyFromGrid(toEnergy(24_000)) // - .setProductions(stream(interpolateArray(PRODUCTION_888_20231106)).map(v -> toEnergy(v)).toArray()) // - .setConsumptions(stream(interpolateArray(CONSUMPTION_888_20231106)).map(v -> toEnergy(v)).toArray()) // - .setPrices(hourlyToQuarterly(interpolateArray(PRICES_888_20231106))) // - .setStates(ControlMode.CHARGE_CONSUMPTION.states) // - .setExistingSchedule(UtilsTest.prepareExistingSchedule(TIME, existingSchedule)) // - .build(); - var s = getBestSchedule(p, // - /* executionLimitSeconds */ 30, // - /* populationSize */ 2, // - /* limit */ 1); - - assertArrayEquals(existingSchedule, Arrays.copyOfRange(s, 0, existingSchedule.length)); - } - /** - * Creates dummy {@link Params}. + * Generates a dummy {@link SimulationResult}. * - * @param states the allowed states - * @return {@link Params} + * @return the {@link SimulationResult} */ - public static Params createParams888d20231106(StateMachine... states) { - return Params.create() // - .setTime(TIME) // - .setEssTotalEnergy(22000) // - .setEssMinSocEnergy(0) // - .setEssMaxSocEnergy(22000) // - .setEssMaxChargeEnergy(toEnergy(10000)) // - .setEssMaxDischargeEnergy(toEnergy(10000)) // - .seMaxBuyFromGrid(toEnergy(24_000)) // - .setProductions(stream(interpolateArray(PRODUCTION_888_20231106)).map(v -> toEnergy(v)).toArray()) // - .setConsumptions(stream(interpolateArray(CONSUMPTION_888_20231106)).map(v -> toEnergy(v)).toArray()) // - .setPrices(hourlyToQuarterly(interpolateArray(PRICES_888_20231106))) // - .setStates(states) // - .build(); + public static SimulationResult generateDummySimulationResult() { + final var simulator = DUMMY_SIMULATOR; + + return simulator.getBestSchedule(SimulationResult.EMPTY, // + engine -> engine // + .populationSize(1), // + stream -> stream // + .limit(Limits.byFixedGeneration(1))); } - protected static void logSchedule(Params p, StateMachine[] schedule) { - Utils.logSchedule(p, simulate(p, schedule)); - } + @Test + public void testGetBestSchedule() { + var simulationResult = generateDummySimulationResult(); - /** - * Convert hourly values to quarterly. - * - * @param values hourly values - * @return quarterly values - */ - protected static double[] hourlyToQuarterly(double[] values) { - return DoubleStream.of(values) // - .flatMap(v -> DoubleStream.of(v, v, v, v)) // - .toArray(); + assertEquals(2, simulationResult.schedules().size()); + + simulationResult.schedules().forEach((esh, schedule) -> { + esh.applySchedule(schedule); + }); + + assertEquals("BALANCING", ESH_TIME_OF_USE_TARIFF_CTRL.getCurrentPeriod().state().toString()); + assertEquals("BAR", ESH2.getCurrentPeriod().state().toString()); } } \ No newline at end of file diff --git a/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/TestData.java b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/TestData.java new file mode 100644 index 00000000000..920ff079c13 --- /dev/null +++ b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/TestData.java @@ -0,0 +1,67 @@ +package io.openems.edge.energy.optimizer; + +public class TestData { + + public static final Integer[] PRODUCTION_PREDICTION_QUARTERLY = { + /* 00:00-03:45 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + /* 04:00-07:45 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 74, 297, 610, // + /* 08:00-11:45 */ + 913, 1399, 1838, 2261, 2662, 3052, 3405, 3708, 4011, 4270, 4458, 4630, 4794, 4908, 4963, 4960, // + /* 12:00-15:45 */ + 4973, 4940, 4859, 4807, 4698, 4530, 4348, 4147, 1296, 1399, 1838, 1261, 1662, 1052, 1405, 1402, + /* 16:00-19:45 */ + 1662, 1052, 1405, 1630, 1285, 1520, 1250, 910, 0, 0, 0, 0, 0, 0, 0, 0, // + /* 20:00-23:45 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + /* 00:00-03:45 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + /* 04:00-07:45 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 130, 402, 667, // + /* 08:00-11:45 */ + 1023, 1631, 2020, 2420, 2834, 3237, 3638, 4006, 4338, 4597, 4825, 4965, 5111, 5213, 5268, 5317, // + /* 12:00-15:45 */ + 5321, 5271, 5232, 5193, 5044, 4915, 4738, 4499, 3702, 3226, 3046, 2857, 2649, 2421, 2184, 1933, // + /* 16:00-19:45 */ + 1674, 1364, 1070, 754, 447, 193, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + /* 20:00-23:45 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // + }; + + public static final Integer[] CONSUMPTION_PREDICTION_QUARTERLY = { + /* 00:00-03:450 */ + 1021, 1208, 713, 931, 2847, 2551, 1558, 1234, 433, 633, 1355, 606, 430, 1432, 1121, 502, // + /* 04:00-07:45 */ + 294, 1048, 1194, 914, 1534, 1226, 1235, 977, 578, 1253, 1983, 1417, 513, 929, 1102, 445, // + /* 08:00-11:45 */ + 1208, 2791, 2729, 2609, 2086, 1454, 848, 816, 2610, 3150, 2036, 1180, 359, 1316, 3447, 2104, // + /* 12:00-15:45 */ + 905, 802, 828, 812, 863, 633, 293, 379, 1250, 2296, 2436, 2140, 2135, 1196, 2230, 1725, + /* 16:00-19:45 */ + 2365, 1758, 2325, 2264, 2181, 2167, 2228, 1082, 777, 417, 798, 1268, 409, 830, 1191, 417, // + /* 20:00-23:45 */ + 1087, 2958, 2946, 2235, 1343, 483, 796, 1201, 567, 395, 989, 1066, 370, 989, 1255, 660, // + /* 00:00-03:45 */ + 349, 880, 1186, 580, 327, 911, 1135, 553, 265, 938, 1165, 567, 278, 863, 1239, 658, // + /* 04:00-07:45 */ + 236, 816, 1173, 1131, 498, 550, 1344, 1226, 874, 504, 1733, 1809, 1576, 369, 771, 2583, // + /* 08:00-11:45 */ + 3202, 2174, 1878, 2132, 2109, 1895, 1565, 1477, 1613, 1716, 1867, 1726, 1700, 1787, 1755, 1734, // + /* 12:00-15:45 */ + 1380, 691, 338, 168, 199, 448, 662, 205, 183, 70, 169, 276, 149, 76, 195, 168, // + /* 16:00-19:45 */ + 159, 266, 135, 120, 224, 979, 2965, 1337, 1116, 795, 334, 390, 433, 369, 762, 2908, // + /* 20:00-23:45 */ + 3226, 2358, 1778, 1002, 455, 654, 534, 1587, 1638, 459, 330, 258, 368, 728, 1096, 878 // + }; + + public static final Double[] HOURLY_PRICES_SUMMER = { // + 70.95, 71.98, 71.95, 74.96, // + 78.93, 80., 84.01, 111.03, // + 105.04, 105., 74.23, 73.28, // + 67.97, 72.53, 89.66, 150.01, // + 173.54, 178.4, 158.91, 140.01, // + 149.99, 157.43, 130.9, 120.14 // + }; +} diff --git a/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/UtilsTest.java b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/UtilsTest.java index b9b321d8366..58daf14c3ca 100644 --- a/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/UtilsTest.java +++ b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/UtilsTest.java @@ -1,336 +1,56 @@ package io.openems.edge.energy.optimizer; -import static io.openems.common.utils.DateUtils.roundDownToQuarter; -import static io.openems.edge.common.test.TestUtils.createDummyClock; -import static io.openems.edge.common.test.TestUtils.withValue; -import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.BALANCING; -import static io.openems.edge.controller.ess.timeofusetariff.StateMachine.DELAY_DISCHARGE; -import static io.openems.edge.energy.EnergySchedulerImplTest.getOptimizer; -import static io.openems.edge.energy.TestData.CONSUMPTION_PREDICTION_QUARTERLY; -import static io.openems.edge.energy.TestData.PAST_HOURLY_PRICES; -import static io.openems.edge.energy.TestData.PAST_SOC; -import static io.openems.edge.energy.TestData.PAST_STATES; -import static io.openems.edge.energy.TestData.PRODUCTION_888_20231106; -import static io.openems.edge.energy.TestData.PRODUCTION_PREDICTION_QUARTERLY; -import static io.openems.edge.energy.optimizer.EnergyFlowTest.NO_FLOW; -import static io.openems.edge.energy.optimizer.SimulatorTest.TIME; -import static io.openems.edge.energy.optimizer.Utils.SUM_CONSUMPTION; -import static io.openems.edge.energy.optimizer.Utils.SUM_ESS_DISCHARGE_POWER; -import static io.openems.edge.energy.optimizer.Utils.SUM_ESS_SOC; -import static io.openems.edge.energy.optimizer.Utils.SUM_GRID; -import static io.openems.edge.energy.optimizer.Utils.SUM_PRODUCTION; import static io.openems.edge.energy.optimizer.Utils.calculateExecutionLimitSeconds; -import static io.openems.edge.energy.optimizer.Utils.findFirstPeakIndex; -import static io.openems.edge.energy.optimizer.Utils.findFirstValleyIndex; -import static io.openems.edge.energy.optimizer.Utils.generateProductionPrediction; -import static io.openems.edge.energy.optimizer.Utils.getEssMinSocEnergy; -import static io.openems.edge.energy.optimizer.Utils.interpolateArray; -import static io.openems.edge.energy.optimizer.Utils.joinConsumptionPredictions; -import static io.openems.edge.energy.optimizer.Utils.paramsAreValid; -import static io.openems.edge.energy.optimizer.Utils.toEnergy; -import static io.openems.edge.energy.optimizer.Utils.toPower; -import static io.openems.edge.energy.optimizer.Utils.updateSchedule; -import static java.time.temporal.ChronoUnit.MINUTES; -import static java.time.temporal.ChronoUnit.SECONDS; +import static io.openems.edge.energy.optimizer.Utils.sortByScheduler; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; import java.time.Duration; -import java.time.ZoneId; -import java.time.ZonedDateTime; -import java.util.List; -import java.util.TreeMap; -import java.util.stream.IntStream; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.temporal.ChronoUnit; +import java.util.stream.Stream; import org.junit.Test; -import com.google.common.collect.ImmutableSortedMap; - -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.types.ChannelAddress; -import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.common.test.AbstractDummyOpenemsComponent; -import io.openems.edge.controller.ess.emergencycapacityreserve.ControllerEssEmergencyCapacityReserve; -import io.openems.edge.controller.ess.limittotaldischarge.ControllerEssLimitTotalDischarge; -import io.openems.edge.controller.ess.timeofusetariff.StateMachine; -import io.openems.edge.controller.ess.timeofusetariff.TimeOfUseTariffControllerImpl; -import io.openems.edge.energy.EnergySchedulerImplTest; -import io.openems.edge.energy.optimizer.Simulator.Period; -import io.openems.edge.timedata.test.DummyTimedata; +import io.openems.common.test.TimeLeapClock; +import io.openems.edge.energy.api.EnergySchedulable; +import io.openems.edge.energy.api.test.DummyEnergySchedulable; +import io.openems.edge.scheduler.api.test.DummyScheduler; public class UtilsTest { - protected static ImmutableSortedMap prepareExistingSchedule(ZonedDateTime fromDate, - StateMachine... existingSchedule) { - return IntStream.range(0, existingSchedule.length) // - .mapToObj(Integer::valueOf) // - .collect(ImmutableSortedMap.toImmutableSortedMap( - ZonedDateTime::compareTo, // - i -> fromDate.plusMinutes(i * 15), // - i -> existingSchedule[i])); - } - - @Test - public void testInterpolateArrayFloat() { - assertArrayEquals(new double[] { 123, 123, 234, 234, 345 }, // - interpolateArray(new Double[] { null, 123., 234., null, 345., null }), // - 0.0001F); - - assertArrayEquals(new double[] {}, // - interpolateArray(new Double[] { null }), // - 0.0001F); - } - - @Test - public void testInterpolateArrayInteger() { - assertArrayEquals(new int[] { 123, 123, 234, 234, 345 }, // - interpolateArray(new Integer[] { null, 123, 234, null, 345, null })); - - assertArrayEquals(new int[] {}, // - interpolateArray(new Integer[] { null })); - - assertArrayEquals(new int[] { 123, 123 }, // - interpolateArray(new Integer[] { null, 123 })); - - assertArrayEquals(new int[] { 123 }, // - interpolateArray(new Integer[] { 123, null })); - } - - @Test - public void testToPower() { - assertEquals(2000, (int) toPower(500)); - assertNull(toPower(null)); - } - - @Test - public void testGenerateProductionPrediction() { - final var arr = new Integer[] { 1, 2, 3 }; - assertArrayEquals(arr, generateProductionPrediction(arr, 2)); - assertArrayEquals(new Integer[] { 1, 2, 3, 0 }, generateProductionPrediction(arr, 4)); - } - - @Test - public void testJoinConsumptionPredictions() { - assertArrayEquals(// - new Integer[] { 1, 2, 3, 4, 55, 66, 77, 88, 99 }, // - joinConsumptionPredictions(4, // - new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, // - new Integer[] { 11, 22, 33, 44, 55, 66, 77, 88, 99 })); - } - - @Test - public void testFindFirstPeakIndex() { - assertEquals(0, findFirstPeakIndex(0, new double[0])); - assertEquals(0, findFirstPeakIndex(0, new double[] { 1 })); - assertEquals(0, findFirstPeakIndex(0, new double[] { 1, 0 })); - assertEquals(1, findFirstPeakIndex(0, new double[] { 0, 1, 0 })); - assertEquals(1, findFirstPeakIndex(0, new double[] { 0, 1, 0, 1 })); - assertEquals(5, findFirstPeakIndex(5, new double[0])); - } - - @Test - public void testFindFirstValleyIndex() { - assertEquals(0, findFirstValleyIndex(0, new double[0])); - assertEquals(0, findFirstValleyIndex(0, new double[] { 1 })); - assertEquals(1, findFirstValleyIndex(0, new double[] { 1, 0 })); - assertEquals(0, findFirstValleyIndex(0, new double[] { 0, 1, 0 })); - assertEquals(2, findFirstValleyIndex(1, new double[] { 0, 1, 0, 1 })); - assertEquals(5, findFirstValleyIndex(5, new double[0])); - } - - @Test - public void testParamsAreValid() throws Exception { - var builder = Params.create() // - .setTime(TIME) // - .setEssInitialEnergy(0) // - .setEssTotalEnergy(22000) // - .setEssMinSocEnergy(2_000) // - .setEssMaxSocEnergy(20_000) // - .seMaxBuyFromGrid(toEnergy(24_000)) // - .seMaxBuyFromGrid(0) // - .setStates(new StateMachine[0]); - - // No periods are available - assertFalse(paramsAreValid(builder // - .setProductions() // - .setConsumptions() // - .setPrices() // - .build())); - - // Production and Consumption predictions are all zero - assertFalse(paramsAreValid(builder // - .setProductions(0, 0, 0) // - .setConsumptions(0, 0) // - .setPrices(123F) // - .build())); - - // Prices are all the same - assertFalse(paramsAreValid(builder // - .setProductions(0, 1, 3) // - .setConsumptions(0, 2) // - .setPrices(123F, 123F) // - .build())); - - // Finally got it right... - assertTrue(paramsAreValid(builder // - .setProductions(0, 1, 3) // - .setConsumptions(0, 2) // - .setPrices(123F, 124F) // - .build())); - assertEquals(2, builder.build().optimizePeriods().size()); - } - - private static class MyControllerEssLimitTotalDischarge - extends AbstractDummyOpenemsComponent - implements ControllerEssLimitTotalDischarge { - - protected MyControllerEssLimitTotalDischarge(Integer minSoc) { - super("ctrl0", // - OpenemsComponent.ChannelId.values(), // - ControllerEssLimitTotalDischarge.ChannelId.values() // - ); - withValue(this.getMinSocChannel(), minSoc); - } - - @Override - public void run() throws OpenemsNamedException { - } - - @Override - protected MyControllerEssLimitTotalDischarge self() { - return this; - } - } - - private static class MyControllerEssEmergencyCapacityReserve - extends AbstractDummyOpenemsComponent - implements ControllerEssEmergencyCapacityReserve { - - protected MyControllerEssEmergencyCapacityReserve(Integer reserveSoc) { - super("ctrl0", // - OpenemsComponent.ChannelId.values(), // - ControllerEssEmergencyCapacityReserve.ChannelId.values() // - ); - withValue(this.getActualReserveSocChannel(), reserveSoc); - } - - @Override - public void run() throws OpenemsNamedException { - } - - @Override - protected MyControllerEssEmergencyCapacityReserve self() { - return this; - } - } - - @Test - public void testGetEssMinSocEnergy() { - var t1 = new MyControllerEssLimitTotalDischarge(50); - var t2 = new MyControllerEssLimitTotalDischarge(null); - var t3 = new MyControllerEssEmergencyCapacityReserve(30); - assertEquals(5000, getEssMinSocEnergy( - new TimeOfUseTariffControllerImpl.Context(List.of(t3), List.of(t1, t2), null, null, 10000, false), - 10000)); - } - - @Test - public void testHandleScheduleRequest() throws Exception { - final var clock = createDummyClock(); - final var energyScheduler = EnergySchedulerImplTest.create(clock); - - // Simulate historic data - var now = roundDownToQuarter(ZonedDateTime.now(clock)); - final var fromDate = now.minusHours(3); - var timedata = new DummyTimedata("timedata0"); - for (var i = 0; i < 12; i++) { - var quarter = fromDate.plusMinutes(i * 15); - timedata.add(quarter, new ChannelAddress("ctrl0", "QuarterlyPrices"), PAST_HOURLY_PRICES[i]); - timedata.add(quarter, new ChannelAddress("ctrl0", "StateMachine"), PAST_STATES[i]); - timedata.add(quarter, SUM_PRODUCTION, PRODUCTION_PREDICTION_QUARTERLY[i]); - timedata.add(quarter, SUM_CONSUMPTION, CONSUMPTION_PREDICTION_QUARTERLY[i]); - timedata.add(quarter, SUM_ESS_SOC, PAST_SOC[i]); - timedata.add(quarter, SUM_ESS_DISCHARGE_POWER, PRODUCTION_888_20231106[i]); - timedata.add(quarter, SUM_GRID, PRODUCTION_888_20231106[i]); - } - - var optimizer = getOptimizer(energyScheduler); - System.out.println(optimizer); - // TODO this requires a fully configured TimeOfUseTariffControllerImpl - // callCreateParams(optimizer); - // - // // Testing only past data. For full data, optimizer has to be created as - // well. - // var result = handleGetScheduleRequest(optimizer, getNilUuid(), timedata, - // "ctrl0", clock.now()).getResult(); - // - // // JsonUtils.prettyPrint(result); - // - // var schedule = getAsJsonArray(result, "schedule"); - // assertEquals(11, schedule.size()); - // { - // var period = getAsJsonObject(schedule.get(0)); - // assertEquals(PAST_HOURLY_PRICES[0], getAsFloat(period, "price"), 0.00F); - // assertEquals(PRODUCTION_PREDICTION_QUARTERLY[0] / 4, getAsInt(period, - // "production")); - // } - } - @Test public void testCalculateExecutionLimitSeconds() { - final var clock = createDummyClock(); + final var clock = new TimeLeapClock(Instant.parse("2022-01-01T00:00:00.00Z"), ZoneOffset.UTC); assertEquals(Duration.ofMinutes(14).plusSeconds(30).toSeconds(), calculateExecutionLimitSeconds(clock)); - clock.leap(11, MINUTES); + clock.leap(11, ChronoUnit.MINUTES); assertEquals(Duration.ofMinutes(3).plusSeconds(30).toSeconds(), calculateExecutionLimitSeconds(clock)); - clock.leap(150, SECONDS); + clock.leap(150, ChronoUnit.SECONDS); assertEquals(60, calculateExecutionLimitSeconds(clock)); - clock.leap(1, SECONDS); + clock.leap(1, ChronoUnit.SECONDS); assertEquals(Duration.ofMinutes(15).plusSeconds(59).toSeconds(), calculateExecutionLimitSeconds(clock)); } @Test - public void testUpdateSchedule() { - final ZonedDateTime t = ZonedDateTime.of(2000, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC")); - final Period pOld = new Period(null, DELAY_DISCHARGE, 0, NO_FLOW); - final Period pNew = new Period(null, BALANCING, 0, NO_FLOW); + public void testSortByScheduler() { + final var scheduler = new DummyScheduler("scheduler0") // + .setControllers("d", "f", null, "b"); + final var list = Stream.of("a", "b", "c", "d", "e") // + .map(id -> new DummyEnergySchedulable(id, null)) // + .toList(); - var schedule = new TreeMap(); - schedule.put(t.minusMinutes(15), pOld); // old entry is removed - schedule.put(t, pOld); // current entry stays - schedule.put(t.plusMinutes(15), pOld); // is overridden - schedule.put(t.plusMinutes(30), pOld); // is overridden - schedule.put(t.plusMinutes(45), pOld); // timestamp is missing in new Schedule -> remove + var result = sortByScheduler(scheduler, list).stream() // + .map(EnergySchedulable::id) // + .toArray(); - var newSchedule = ImmutableSortedMap.naturalOrder() // - .put(t, pNew) // - .put(t.plusMinutes(15), pNew) // - .put(t.plusMinutes(30), pNew) // - .build(); - - updateSchedule(t, schedule, newSchedule); - - // One old entry - assertEquals(1, schedule.values().stream().filter(v -> v == pOld).count()); - - // Two new entries - assertEquals(2, schedule.values().stream().filter(v -> v == pNew).count()); - - // No old entry - assertEquals(0, schedule.keySet().stream().filter(tz -> tz.isBefore(t)).count()); - - // Details - assertEquals(pOld, schedule.get(t)); - assertEquals(pNew, schedule.get(t.plusMinutes(15))); - assertEquals(pNew, schedule.get(t.plusMinutes(30))); - - // No current entry -> handle null - schedule.remove(t); - updateSchedule(t, schedule, newSchedule); + assertArrayEquals(// + new String[] { // + "d", "b", // by Scheduler + "a", "c", "e" // remaining alphabetically + }, result); } } diff --git a/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/app/AppUtils.java b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/app/AppUtils.java new file mode 100644 index 00000000000..cbfbbdd1508 --- /dev/null +++ b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/app/AppUtils.java @@ -0,0 +1,108 @@ +package io.openems.edge.energy.optimizer.app; + +import static com.google.common.collect.ImmutableList.toImmutableList; +import static java.lang.Double.parseDouble; +import static java.lang.Integer.parseInt; + +import java.time.LocalTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.concurrent.atomic.AtomicReference; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.google.common.collect.ImmutableList; + +import io.openems.common.test.TimeLeapClock; +import io.openems.edge.energy.api.EnergyScheduleHandler; +import io.openems.edge.energy.api.simulation.GlobalSimulationsContext; +import io.openems.edge.energy.api.simulation.GlobalSimulationsContext.Period; +import io.openems.edge.energy.optimizer.SimulationResult; + +public class AppUtils { + + private AppUtils() { + } + + /** + * Creates {@link GlobalSimulationsContext} from the log output of + * {@link SimulationResult#toLogString()}. + * + * @param log the log output of {@link SimulationResult#toLogString()} + * @param eshs the {@link EnergyScheduleHandler}s + * @return a {@link GlobalSimulationsContext} + */ + public static GlobalSimulationsContext parseGlobalSimulationsContextFromLogString(String log, + ImmutableList eshs) throws IllegalArgumentException { + var headerMatcher = log.lines() // + .filter(l -> l.contains("OPTIMIZER ") && l.contains("GlobalSimulationsContext")) // + .map(l -> applyPattern(HEADER_PATTERN, l)) // + .findFirst().get(); + final var startDateTime = ZonedDateTime.parse(headerMatcher.group("startTime")); + final var clock = new TimeLeapClock(startDateTime.toInstant(), ZoneId.of("UTC")); + + var gridMatcher = applyPattern(GRID_PATTERN, headerMatcher.group("grid")); + final var grid = new GlobalSimulationsContext.Grid(// + parseInt(gridMatcher.group("maxBuy")), // + parseInt(gridMatcher.group("maxSell"))); + + var essMatcher = applyPattern(ESS_PATTERN, headerMatcher.group("ess")); + final var ess = new GlobalSimulationsContext.Ess(// + parseInt(essMatcher.group("currentEnergy")), // + parseInt(essMatcher.group("totalEnergy")), // + parseInt(essMatcher.group("maxChargeEnergy")), // + parseInt(essMatcher.group("maxDischargeEnergy"))); + + var nextTime = new AtomicReference<>(startDateTime); + var periods = log.lines() // + .filter(l -> l.contains("OPTIMIZER ") && !l.contains("GlobalSimulationsContext") && !l.contains("Time")) // + .map(l -> applyPattern(PERIOD_PATTERN, l)) // + .map(m -> { + var time = nextTime.get(); + if (!nextTime.get().toLocalTime().equals(LocalTime.parse(m.group("time"), HOURS_MINUTES))) { + throw new IllegalArgumentException("Times do not match: " + time); + } + nextTime.set(time.plusMinutes(15)); + return (Period) new Period.Quarter(time, // + parseInt(m.group("production")), // + parseInt(m.group("consumption")), // + parseDouble(m.group("price"))); + }) // + .collect(toImmutableList()); + + return new GlobalSimulationsContext(clock, startDateTime, eshs, grid, ess, periods); + } + + private static Matcher applyPattern(Pattern pattern, String line) { + var matcher = pattern.matcher(line); + if (!matcher.find()) { + throw new IllegalArgumentException("Pattern [" + pattern + "] does not match line [" + line + "]"); + } + return matcher; + } + + private static final DateTimeFormatter HOURS_MINUTES = DateTimeFormatter.ofPattern("HH:mm"); + + private static final Pattern HEADER_PATTERN = Pattern.compile("" // + + "startTime=(?\\S*), " // + + "Grid\\[(?.*)\\], " // + + "Ess\\[(?.*)\\]"); + + private static final Pattern GRID_PATTERN = Pattern.compile("" // + + "maxBuy=(?\\d+), " // + + "maxSell=(?\\d+)"); + + private static final Pattern ESS_PATTERN = Pattern.compile("" // + + "currentEnergy=(?\\d+), " // + + "totalEnergy=(?\\d+), " // + + "maxChargeEnergy=(?\\d+), " // + + "maxDischargeEnergy=(?\\d+)"); + + private static final Pattern PERIOD_PATTERN = Pattern.compile("" // + + "(?

      Wh8f913c}syMbca2V09n1=2NL1hPLtB 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"e9+JGJZkXFly*x_YMg)k31*tUv z;w!DgIb95yGPsddgh#=>1ErY_JcOyqu|lWZT`qCadIQtt{FQmx<~r6TnZv`88Ra=k zw&%qL*)Ps5X*Hhb!=FzQnw9qq_#K&<9-ly9k1kIrB(6y8kml#6ru$UTx==8%6hU9q?uaL)-vMOg=jG{rEcRKoen znpvbASaPn!yU_<=$63bA#cKViBVUSaA{7JA-pCya!!*AZ}-8j|^VVuXVeyxZh5mzjEVE zp*Xjn5qUS=hAA|VEh@VhuMa)|pvnn=#BS`3cXg1flIVATAm9prUopsCa)|Kq8*&7g z4;c|5g1io6K}0L5!KWHumm2}(j=%u)azybakubj4XU;qGz-7x^#~=l_F&7`ZFzw$6kSahEzM)Rl5#EDS)1A3 z{=%r(;jR)TfVT)rGTMy{+ci(KD32a{b#J@G=<|am>cB>4WYw0Q^pcg63+4lG?QCs% zTY@d4(M}TfH%VG&{SQq6GrS8DmtT~>o=5i+_N|i-gw-J5Cg7cV!LUq$=WHSDNG@1X zSU)d-q|{mcW&*KdWS^}rg^YpO-hF7dhOp1a7xCb#7qs%ND82A%@DVIA>uam;1Xb~; zrYMM}u8J7MW1G9t0A&vgYazru(i7nQ*h{(D}N+ll2RcM&sHI%dEm?apwyPgbnsjL(sJ@P zFwS|+x3H)(@$^kRK1J(G1Q=9Fj;abjp7K(0OI&is7WT7!M*PF@ z<627Tw&gh1RkZzM7&IG~+5KN>qT)CUq$! zoGS_=xXSb2=k3;4yJJPZz<-e!Ec1CmngWN+3oTdw7Hx!Ny_=g ztlx+37=(qtQ!T;#+^GUrNEZhexX8_nW?>@%AHPIDR^aa*#bxG5E@oILM+vyk44AtJ zmBK>Q>vC<{pbj+*bUvcCXRYl$=+_PJMX!F{`PbQREZ5UxnX$?c_rvLk#Uc!h1$^5j z`9KwV)7Nw9;49jm`0rRnlm2;aedS;v^-jLD3oa(FmhI4qh=99AXczNQ`zMt)#FM}S znk|1vWM^-ztPnc4FXvFV>UIpiZa(zCR5~$D;>Ktp70~K&J1k?REvrHzt-c8Dsq@jJ z>N|zqP2Pw19JlTt#1{pGhE72;uXHF?kV2X_n+m<`Fry}cG>=|$bZF*kYt`~_pSZBUy6Ow6tj`z_79q4lY^oaG1N=ADB^r z#oM(CAhJGU7z98L$GO?<)mkW*!YGFu93>YOAt0J~qHcHSc+E_$@v&8zO za7M1L$+bAVf#SNJS{l%!1r@vmges|cx?lwY|1wZ-AMz0_Oc6I9p zczV;9txR+=ndDdKjylIHS^_Nqxh4ZM)9BfBixuF|hs?F%L1Zw7k2(q}yG-7k3=4E- zY{7x;2pNF7dMip!GY2)+#o@e3mf+boM+P>wZ~lVAN1LLMc&N|^spXn~amF}s!W`F* zja0*Ue^-gE&BPN;8N01`4$BM$R5P6b_w);qI`Bn>6X zthg)Zn|>5#`ab}OKzF}BLtgyp#wfJ*BOt|JxeN@6 zZc?3dDVIi!1X_h$R>dvB-$TTKK*j~c3BjWHyqj;d>l&xs`8{%B=Y9V^G=Fv>cOcMz zFAyc~b)iyn&_k{6K4}9OP_Vsg3x!rtn8++)?=&H`p~8lG>kX?kp(;=- zSAJxJIFf;Z6tCvWiWo3cnZQ7 z$G)q3t@N|usO%XRd!O9&I>R@WcLv2dB*P1&=!liMrq3nbo{d2Md4IWFg85S-`cyHoi6R(p`)Vu+wVVH5<=|p9TN%n6Krl9u$<k6NZ`$4(8m%Uln=RwXPIz-EIz&wykrhFewg9Ef|XD%`(xsFkQ3 zjXccj8Wqy21%G7G`%(4n-Fi^WB^eVzVZli)4f~wJH2lT|8ek_FQiJa=vUTCHCnK29 z4u>}8PP`@)cmzKs;2)tdrJI;Mu!RE02`MW5O+HV8t-3C#QDu3(0uJO+7}#e80<}e% zgkI(4eO%#G^Jg+~X7Q^sM_r8}U72w!VNo%mGG^+j^?!&NMx_MdYGgKBTUo7L2W;^s zMTM6AduQcuq0l!*=PHSY%uZEWf(tyGlU<_27$I{2Y~&{xK{y3e17tYlU}SQ23Ze>F zu$Z_^Y+TgJY<3}1e<-U9K!(&-OdiHmaVzra*h#kKq`Iu}kfmzd)nWWObJK_SdFAWK zeVs+R_J5pGok=$_NtvgIe0|Zpc70QA$@je41=DJmcllc9YbB&j6J5^EI$vZOr zX0sJjx^*c72-AOMB~E6I^R_gl0N~t5IzPgCvww^yM3{fr|L!UjWu56&lXB_Lyn-T5853ujtpfhT-r0!fEXmd}Hl0l#I3; zaNk}wx)gb)MC?-qqdAcpxYyze|Gg3tV)d!<7L-kIp(5979Pt4XxUeYv40a!=R2Fox z)qf*yNvI(7v3*!OJacvDQ_t1c=9rvvt)=<;!k(KhBOmRHj4x{Fcdf1bqDU-iRZ$k) z@1^(XZavP8InT$%3-pz%GfHzxE4f;F=7rf(wz%c6_7$25h~P%RfMznRVc*qkZdg(< zp<;V*2vNRIfi?muf#EMDejI9;4pzF2%XQ47jtoZi;)M$j(6HQ;o(RmH zc(Kk&*A&c!FmJEtgTw_W&tvn!iqVxem<=Zb&#edk!TIvxti-TlQbFKDW6q?$dH+{o z3wf{^Z=woCc?4KbL9p2P`$hLv3lTk%AW2ktgoYYO5;~5D;}E5Z3sLDlG2+GkUVqYy z+gS;@){;yYvRD-g!DCl*)R$#kWzZQfW16-dIP@4^#yP(c%zN**l@o~HD=}5fZlxZzirnb~MRcX}naG&whgM^Tj;Tn0I?wNAT7B!D*JFk`wPKt|wiB^z z%XQS2kEvCT7&r^(!u=#^#pC`alz-{NrQds2`G`OVn{@(HPXPk=G96?qlf{W-V|#CC zq%R?LPu*22f1fM0BacxV8DAJI{nc73r{Y)|O%6$2rQuz=$l7WyKTPv+Ovusd0(Mg4 z;bqLbN*t9J9&I9Hxy#a!Z8g3;3ee8=wPr5JVdb>etXM?IUVVXz_pMSc;6b3aj zc)W>szD(Z;E?gj9yQZ^8uluphx3|2FARp_!jj2jVpz(5G^t)dz^4yro!GRUcX@nLL zJRv|*ES+k>p#=ZP6OL;h>&UCMr@B*_L!eOl+V9DWDe?@(yLfqQKe2eoZZ~+Fq^erL zw01=u^P|hZUCFG>!MHCw$$u&)8fO1F7kvlyUC>oDZ1w8)X8EsUjr!T3##QcLD&Se8_b9~& zhM9_iA^?>PbS#jLyb($qSixpc1kE>Fu^=Ob(q*@*F`bTs;&l%cP=B)n7DSJ;4>b2tbzI!LIOgVv@{F`x71&lEs2Vo@t@JjN_fYiQY5*1bP}pY9}gEjc0)TZkA)5cGQumS;b` zI~@5$;`Vhs-()@nh<}n5W0&j{wJcCgHAwT&qEJ!OXUEWEVd+H->`fd7&5c7#ql|^6 z=rn}~$~)c!Uf#}v=*I|OOnDZ<=!nc}`fmL|KDy0!6;uX1rD`u|EV+;vDN=YF&O=RM zdRuQhQ@1NF-bCG4rg`SN#P+e8=AuE$Y`rAZlS|&LX@D_H%YUUtS$$VB4cVY}>aH_9 zpVvSgJ1s1<)z=$T%^TX_SXpn)nG>$u{d37(uSX{%u!p%k?dJ32v$3r>*v}tfam^SR zaj>Z=aQId!jaiDV@*5CFh>uOc5d)s571LD z?k?UD!qmFi1Aoi<=^^q1Ssnd7ziY;&2y2``8kEecaBa@lESYRHR@gO-VA!3%56)hO zZ)~Y*RdG5(iWh$#TT|fp7I5l}w*|Yn8=Tk3;7RuI>h~R9!lAZykIn2?Fo$=u9qcP_ zUfG`_&kkl11|s4LUd83crtfCqH7HkciB;I&A1khr>3^n=C02I8@#jR{j@G$1Mit+a(fue9;1 z9$04JEpFvC4&(hHvzhC-QA~^glIsX>s6b|Px0TuzvA@EA znBpFUKbP+tXtBp?*PlS9-Gc z3{NIDUg5{sO@l&s7ISN8@HG60x{bVpV|UEJqJD_dJ3lp^&q*ZqE-Ec4B(e9F)#m>k zaLS#Hly-#G+R~+?WKD0cA3`ut4yRkdt+t;-On*#{q#Pa7Z|d66%*w@1(@0CsNJ+u1 zc49+JTCvhjP@S*qoLNjnXaf7+GGME8oQ9F)B>xf%L=^v3J1rkz8AM=4C=9c~Wugy= z=9Z|GgZFfzAondWC3SrhKLQqAh>Mf_8V74Wi}0;g!p7EFSu(9$Z=a(4f;klFee9n< zOMjI@I}$BF35N0-eB94?j3xdm+NY=h?3=8#lH?;4{W7!<5mOX~p%MZLy2~JR zS48M)6kxedO9P3G;GmeD+M-07F3PHL;%PR$6DYwvgx1WyfG_TO{wz;{J2@R~ZMa;1 zevV1Lo6IQtyVA*>2}}S383Hr}q5za6X@5G$oE_~h+!^G)fn-Bs+DoW{A3wnt;WRO6 zF;ndZvcU(z?;h(Db0ogUtwQjdkl+_PTR^Z*6078B=k$gV27zB8j@bSw79GQokN3lJ za2qZD$MBuhox?2d&+zDNUkLQk@L9=Z>UdP^4yjp=pRXs27w|xxwFLBy$hzb=@qYws zFy(H1=gH;C1Zj)Zvs@guDgFT9z2;m;-L`I@`KSyB`sT9(>}3l8^Dv zqb{fC-zgw0CtG@g6sgfOdKKNVy$c>v`Cp;}`Zg~>Kq$ZHwSf^f11nU5|3*98M6;3! z4nt&+GJ%-ab3SN0YGCW3d3H+{n}W^XXO!yE>NJjJ;yum96T^#WMxw#0oPS%PZT>yD z9f=vlNZve8j7@BcET#_2O2u0b8olOoUFT?Wv=G6wKf-I>&~H8$H`^B!;Qo|OYg zbTtKNt1VYmV!kK`{n2>>HETWo;+%QnYe6dV)vIfukW}7F1~- zXtOY&5p)Rv(nc?sCfd_tdGnScEnejpt7i2j?M2Pxt-$`h6xx@v6;hTX_rS8^#C<{6Se()sj(&!)w$VS8NbwDZ)rcX zt~bLT%dw@-5n<_ojFf= zL{m*>@1!z*@y+)(rTAH{O zyG(Xto2Hl-M|>7nx>}}_lQTCQoir|HPz z17j|p-hYSbDL*0&soWl?dms2qo+ik_pYXWG2&;ZN=fb&7Aa_6(A4N^@Zgpz)OK&b% zk~!%!>ykN}MBSk(T68v~dfLWK36B8Ho%paF(&&A7zP+|IT$7qCFL&zUZQM@OOpHI4)Ni~$#iT5)e0^Q;_EbB+lRv9E zDStIu^ap%Tp*amANozR*YM*eVCpqSJef2$ReD>05i!5wB1RVvGTxFBV`3UnH+u{)UM>shljK zaREV+{qifAjk@8dfLHxeKxuEBL3adWO@EUvQLX_pBPRW;vCBAqWeE6%&D@jcjm(9K zXK2ha>S7k}GZ z$E0*ggY9mK&!D=l(VaRG@w%1_rtFX0a7w8fji09!*oSscpifIWwI?fXmEO-;Av78T zgX@=;82a7?Hk%o14W-3Hwavs9ld4Y2X_@T5pS=k=n#!|_uh%b^rx(4etM-P@7T1^L zoRUH=2&;vS+0UETSM-_Y*4z(Zgnwvq`uPj#NF_pS+a);+k7&$dV(|reWkk|ari*BV zv2qOdqZ$DPS_A|GFa$@lR53ug>2P7dGg1=HlGvX~_KFM^r~*J?Bji3E6Zp)9j3_{> zgK;xyx*xN0-WX~hX#hQdQ=brbh9AQ$JGnX|xr%A7eZOL8UL^C`_wxYpF@HI!^&rvQ zZd+cXqlMSVHqDu$X3St2$M*U$@n_t5W5Qwce17_^SY_t3J(jdb+32_e>TEm9^~2RB zkkYY?W;Ms_gVh_Cb>43Na0u$ec6I9;sA3-{tNjZk{OD=3)vxcowbtksnxHEn^NcnF zhUgX8LlOi)RMo|`j&-s+sejSmIqSA1pHS97RMbjV+Ny+aD>|J>z>l5yye&w4+6QHO zD-_hrioc9irIepX7X4O8AQ&!swA|$+Piwx!gCB8JRQ%=>0%mc|{PKz7qp6uesSH$W zCQ|RSJ6(4adjo%R1ktQ>(7t;%as4ihs0R#e_Vx^>Qmq zNkzLeawyJk-&$*Pou0vfXK}~(FZ5xzn(ONFRnNkvmy4RsRZZnd$@udd2MY(74EWjT zB2QZK{>)LAFk?thse5;1B}?L)=uFc~iO$i3;e-M~TZV7sbEKV9?DRl$(pLcv#=(|2 zG<)1nI#5;p<3x?On17jwrlv?Kac?D)PuNZxGJ2}X(pj{Ig9C?X_buf~TFNljgS| z=)9N~ARe4I#gT2PRQI}6gWbyWFN(ukQmAh9DkIy<-w1yu?GbLOllIJ^HExN| z?81g;C4K^a&?8I7)H16H#k#yh=_ufX8Va`-p9I_SN5 z8D!g@ZblX^)yBxZlMs(AfOivJ(($MGhSC=G0DoYSatlgeY~x7R5_w_~DOj6K-R|0^ z#~wAd{1o#FS8ZIJwuZ*{AT+?x%edyfkS26~SAR}uu78XEr2lk@a=KAtcIAtQ_xPdo zJ#Nn%NoP^;?ju-vydq%kL1(fb6zmw^8%`e+up}7dty7y#?vGuWe96#DTiMe=Q?ZAgZ`$etbGSMGVcLPQ{Jq_o&u;_IG4@l)8%P=948FI~%9UmJ z_kUz{?uLcyA3yGA+RGT@B;1_sLjWl8Skxo(!6vs{zg3q%07;v%aOF%o0r)411WfeE zd24m6tCEc*M}X#h*hiG(XoqlEpF{E@AC1o89C{x z+8GSFT30eM&dS9Ak6(VFjmiaV;ixmacz=7Az%zs70ebswyNGwFW1-|lFXQ+;C;hIYU9@H8yZEz<$#!k-<`}#Zjl9nC}J0?6nt8X7UHSM;{Pj zFYJyPID#&M-Teo*<(R458OWa-ulr~2d+K9emfpCA58vS%5a1tb8$^EdBsXVR(0`Od zjSyww_?a5UU#gfu0F9C&Y{i@WL)e6COvn0t;#Tbtg||^;U<*G1M62f%>U$R$ z37QERDkp3nERX;uHm^ny&)E=@Phc7LCy^>E46 zf{XPIT{nf!W^DBW3jk`lH5Uyosu$$@`UnXwo1t-$_>er_! z**p4-o+k4T3%LzyanY#US|0h4D_l|_sAnNBA0@omIX~ootj(Rc&!FS#9cd^b6JRLnEpHSRnxt}@R-3#X@mJOhNq=$WMWpIix z)gK&UMM6}L2F$uF1%Cp06yRPkp`@(u&-BI1A?Y^>(tTSo3yBUE#vL3&#}MnKnfrYA z@s96n&ZJM80HehjeSb-0FI%)~Ut@=_oSncXoXYNk;(=@RmP*3z?q(t?;sp)G^bDQ& z@{^Osf&^&^g@|_2ai2^D3e4;^#e^R7)r7yzQCJTR=M@!bkEwJ$b_$|pbgT!0=GxBg z+OfL{+v*zK_9h|CRbx8JhU1lPL%x^5sdCsqA?O^nsvtIXBY(Y2VC8FjL|Dz4NONF|B0u zqbUZgWTZn=Y{C|ULQC?&B8ZO1Ns2!dVTnNKwBbnDNzU|x`KF{Tz+Q_=?1O*SeJTLV z&My;*8k}MpQh%~f9h?`byOeh-NzC2GdTr&V`?8fbPC6IQBCHa)YE4yBib*yRV;QL` z>&qte({sctqQ$7PKjT{nak?i310>n&xGH+td(xS?>s>wf>zU-(oaif7RAL!6bftxT z>ko4UyEK$qDn_u2v+z6&0 z1OnTlXBbmB6g5f`TPJmYo9H5F%qmio!}Xe07^*9UW=Z9 zwW)ui!aBnKr+mPSwG^?l^zee7G+!~ltnpu|4}Y0Q`?ZLEIi&^MPm9f~>H%N_BqRb5 zZSBQS%W%NDMmc35#gHg6(oz$)KN2T+pgp-+RnSR={x5Z?16 z^nY`|hj49={KcF%!7F@OSKhybwZT>%>%#|)IcI;>btCeZ^vYlyzeMtPrzh>qmh}Mn z#)G}|)vu==P*=UxmG;#>&UHWD{YOO~);|?dR@#p3CMR%>CY$%6`xQ(48Y1O(?>Faa zC3??lQ%fpIGJf(M{56&GR4MMJf6O%bI)4H$`Bq6NlMVUv(yL3%hFjaC`&*Co4@48X zR@o4SZb2sCUdR|>&Zcr2a+P+Ij{zTq>_?5kU-nb6sT0$K~e39-QjO~ z*=}_N><>OYCbD4$V0PFyrPAA>S+I`Dz#Gnx4r9je(j(HdKw$nxLoN^fUKNo@gnt0D zH*G9SV^e~j1i|0eu!y(QGnoy^FBot^_oRCHxTUm!*(^S}n{qa?)s@z*D(z;7x2aN? zrQUs6vGulk(fXkJYdIrX(zxgsQ!tu*g6v|H<@ z-lArt4WXWH4N;-S@MqaQwMiP20}#1}E3|6#x}gZdlES^qOUZCnhS z=0^_@ohiYcdr&hwR^~!Z-hXNJo9TR;(q{uSs$V}gj$&f!F=D($6AylQ!#rtCbNveR6k%^HfLrkIh=#RaBi6D!17Y|I`-2RDK=Gr=Of1^=AqyH-x zVb+!^>DHT0O-B0e@qqWW@a<=w}w+pYzMh@zBfUFP)N&ibScIt)7@> zL3SU-Wd17qOV?DKcD$fcz#3|2UP+h=xa;xjmF?SvLmQNKK|?Y9yvnVgqbd2sERqLz zscOs^9ya>qe5l4Os+mi^qWL=fdJ3H;wFru z2^=Tz;0HO*OWF8`-JTUaY8SV;lASf%(anX)Im6+{5zn~Hc?4;s$*&jpK^&>gK&tJf zMTC*I@TNBj*?$)i0L1cV6uAydjn99E3Pj$o2gON3sl+#37F@kC;_iLd_pl!eZc+1S zBuV@^SQ}9b@8+LC*}My*dsIhG$g@x&ABJ1M2kkVU0EB`Nkb-yHy%xh00L7~Q-KLJ8 zsr1rf@5tOvl4PT*fY>cIj`l3;te!{+b~N}-b(%wi6@Nx-&CeLhGKJCtN#sCCr$2e} z=z$d+6n6LU$EHkmN-Bl%erm!3dnV`LjH%=y$vUt=I@3)kEGA!EqLEcBMA<6#^2%&i#}4gC@_7;y`%yEU85a!&U6L(IDIDfCGBFB9YDDfclR3P7o{u)QwAVAef ze43m4Gh79S)J24dFn) z0n`@Dn*x;&@odhYBTulk3cH$%k_vaFlYF6G7J+N+u7d*x(DrlyH^7swC;YL?@zJpj zhkqdcZj@i8jcS7u^-XoXXayYs)U`YEw-#p8GYmjY$79&!WPyy5O5r%NLS=HHmGLzq&@ zDF^1K4}M&3Vh`o>Pow{Uc8xUhY3R+bhku+w?pkRm&pojL?;{2~s>FcYTWEtGilXWa z`Sc4$kBhTHX)LOJfB`t968Ved5rWVZ3jl#X%Ii$!nXA6ATUIo)xo~*RJiT2zooo(# z7x^zwn1^mUO4DFm@LSm*Ps_mBXoXN7E^9yAgm3SoXR-9jWDDTg_AiCM9wv&nfq#p+ zf#>Czbkm#ou6cEc9XdqH=)HeDNdzxx;=6LwxQb?f^g$vFLBiU_{&f$10j0ERz^gz8 z=2Mr?0E_#V%Y^9`n-#spgV1I<_*^?~-t+ay`<~nII+0gyM9oCImQxzmB!l12TjJkc z^w+>dkpV#u`ERq}dHJta2BW0?#((4S$#4(x4a?vgNuC>~!4sD++97TcX@K0fBX3fE zd>ltEV3|!b`{ESzguy{J8WNaPaSn`5{~(ZEK_mjkc%O-kj=C%vV42d&g3%g^t}K`O zk?=&XG5c3HLN-0&8>Satub}?!m#80g_d8D9l~=1?m7QX@#HN!5A6p58#DB8V6}|D- zK;YymOqH#0>TkmbiJRf8*?Vy@oWtQKjw&JM)99m5v)0zHvWta$G%|BnBSUU64FLFG91>uF0DNmjj~+bt695|We}C~uhHeq*{>$eB z8?`>czLp`0iCf0?3q# z0RVi@$x&%~4C_AaKku;F!ePAG!pK70N%-aI>iTxQ{&B}Snn>VznpRg^)2}0#OH}4pttYgeZ(>}xC+K5KY zd@d?ZF@0G3q^BxllGWo846?-x6V`mN?2>-fDqq>|1+0P>?V*k**Qok16WUvJ=96RW zeYhIV2_g^sgmUbj_L?xh5ozg}l!&Ne?)J>m0}o2{M$UKfDt}|B07_#@IoBCcMV@8v)lNp*WRrO?B<&xlLf_FKe8E=~{GSb1o#(JC>6BP#L zc$4}i$QJU$p??B(yofdymiWc`CHV8On+Cu}{0ps!ifYLjR2iwk|z z^&a7W_Wke4Jn`zG(x?G$aBj;kkT;Pgr<3^K|k-o$iab(Xc)b^Uf(wr_UDb;jO8-O}R8GAlW$As_4<@|s?q zqJQA}M1TD{`I-f$m}9!hQBFB|5TS#_B=Sdz-1+h%` zFZ$nE+XB=9&;a%Tuzx2>9-t3!`^RlVrvg9#K<*nZv4fi600a>^*U6Uk7S{C@x{ucS ztA7a3A=zg)2sdti4mK18d2OJqK5Y8DnbTx+MXB>-s}Fbg!(ly7N%p{L`p=YmY_CvHPU_p?>Y_PeBaKfG7@o(M8z+r4eIwP z;dXf?OOVWsaLZgJ3&E_-kEf9(K4c|)K7ZVO--Mm!z}^Kj5r*;Lr!)GWNr?#Tn<58d zw;2&*Sm!?mbL$42y*r<6YafS`T#7^^C|^WTd9#wz-A$f0D9tx3mSfbZrbHy|svqn6 z$sTCyhI*SH?@!2`Um}j~8`k|n&Hp)-zK{RCyT%XY>6^u9r?Ncql#~_4(mLIquzwlM zR`V4yop9M5&KL8Qa=k!7p)lBtmQ!uN5=*2r8Leizz@k!UwCXLVJ76wklz3$GZJK=MCyg%+PW_$hf{?vt+rL_eYB{fA?X(to7 zuR;A6g^9i0*U4t{qd_Otdb8z?X@7Rz#a6VOV*dS@9f4S+zzCMiVxA<%++650C&*{|tyAupr0) z@W3*dFuStdMiDqX_v2XAXvvg1v)N7{xhjpu%4xYvj(_J(Haze9 zWg>mg``@q|-}kH3-tX6wUSyuYo6!UG^TR>ij8qF_ecOQpP0gfPUB#SQHEqqloZM8X z0uCvrNX34d*rv|~A_S14oxZ+#Fo3U~^YVZG`*x?_o`}MbnAk|~2z(?P2L=ab91I(C zEvtp84STYY!8~9MPP->s6@SMPhvRfU>GDMHYEBNB{jy9V23Ui99$GFEcWOR@6aWAK2owN$1`SO)z76>I zQvd)wQ~&@V034UmJp>_tRa6N80|vTqTc#0wW_5TA009K(0{{R7=mP)%UHoHkF5UA6 z3g5A9+dH;x+vbjK+fH_D+qP{xJ2rOAljrw;-#S%i)m$^vy{xN*006|?j~?L%6YNHa&GO3hOaK7n-p@M49~d|P%J;3Y5)L4W&pip z%h=VK5CDKa{Nd>Q2S!|QSu=Zc8vp=C;D`6~44|&C57J6=L#Lm$u+Bdm*#7|%fMRa# zVfJ(D4*&?1008!Xd2*dM5*8*l?f`%+({f~&=k z@<%uJBNP9C6m}Cn(Za_0zqOYD0I=1MeJu^(%!$@^#y>m-jUPKUf3PE-NKI^G=>B7i z($9AQ2>$~JJ_v!Wp^fQ}PUT1b@eNP|Q30R1y`9sKy~+%KKRUGkc;AKq6MIL~pS8*o zKk~y5PlIzi;?aEruAdPINC6YP?|lbcK?p8W6_nQ+AOL|VM1}X^R)7V3oKX`|o~9XY z8sidU6C)hs6jRyh{$|nRtAz8038VDK4T9Xn6& zHLI;Zd#c|3h*oR-aG`(y#LkofN(f3!=($a^^Cs3%AC`z1bWC1L{udwF!1Q5CMYn=3 z19w`QH~n0iN%=b_b;uzr+hio}vy2auWyG2UGv$Ve@Dx&$L~%Y-83W{`^Z^w!#!Q^H zgv_>d&M9L)m}vt>G!>=kf9^o^CbT$fL+C9H*%%J3rJZr_uV}r;>>sJScV1t8bgqqI z-IoV{MEJ)@_(zPfisHO*EDIvcv`q_Q+`JFSj1-p?4!w?US*JOJoFz!6M49WT2oH)C zCmr+vUBk*}JE9k8W>X zpF#L;(>#$X!D{;KVBWx;VlY#498z~1xUi7q?6O%0~ z%97QYRg{+{VD)*RN!>W#OX2@G0-WHUR)+I{6{j`6q6JZfrX^}!$5SGc>t2zq+;kVAHV2ef)a;NU&1)E(a5UUJ z3Yb?mZa3;E9$tJjgnn~iW^~nm0|V5lp$c)mnsbqQu(X_8?7X?G?>jLfso?ox-WS?6gTbl!#{{ZuhvSzj7W$nW4t<$eU4^Fn5z)Y*_^qyF9>fOIL z0#(T-I~vlc4Q#;l5LE5A@7tkfx2_o1fb{iU01aeVt$o{J#9ZRP@%?Il^d)u<#sTM& zYz?3w@>Z>d@V6K68d&Xr=S|i-usYM@Jxi6_!uA{-zXb(^=qwFrJM;gs_O0b}j+l?l zKZ)qKj(ydAcDmSYGl5ZlFx3&p;rMPbo)||ROA0rNph`hSNfR1ywj~YY{N-p(R*5AV z5?!n{atFM^m;-k&(=yh7xHbZxGi`2)?4~?u;yNMYD@xL6QIP%kFgK}YWJ|0pwzsol zgcanaO(8KQf;CJ^W!NAhlK^WbMb}6gx6YJ>L;6>Y$~+d8LESN(qA;DFM3Zp%SF$&{ zBoYl-l4|0xC6-u-i83wJ*R#1U4b_SyI!;kEZQ>vsm1*Z;oiOx&-PFt-zlfN9ZFK)P z>ecEPrcD1EO~ebUAEDWwyqEtj5TLrd~zg?kOs z;VRUB1%ctz5e!s+N>wSKNe#Vv#B5T0nPfqom#}=Q(u%o!+CVz&~@|Hoz_tOpy15FgANswd{2QDQ}^D<#&;xE5JK5clo z0Y5QcHX209-w-i0SAU.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� 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 delta 177536 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